xref: /openbmc/u-boot/drivers/net/bcm-sf2-eth.c (revision 3ebd892f)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2014 Broadcom Corporation.
4  */
5 
6 #include <common.h>
7 #include <malloc.h>
8 #include <net.h>
9 #include <config.h>
10 
11 #include <phy.h>
12 #include <miiphy.h>
13 
14 #include <asm/io.h>
15 
16 #include <netdev.h>
17 #include "bcm-sf2-eth.h"
18 
19 #if defined(CONFIG_BCM_SF2_ETH_GMAC)
20 #include "bcm-sf2-eth-gmac.h"
21 #else
22 #error "bcm_sf2_eth: NEED to define a MAC!"
23 #endif
24 
25 #define BCM_NET_MODULE_DESCRIPTION	"Broadcom Starfighter2 Ethernet driver"
26 #define BCM_NET_MODULE_VERSION		"0.1"
27 #define BCM_SF2_ETH_DEV_NAME		"bcm_sf2"
28 
29 static const char banner[] =
30 	BCM_NET_MODULE_DESCRIPTION " " BCM_NET_MODULE_VERSION "\n";
31 
32 static int bcm_sf2_eth_init(struct eth_device *dev)
33 {
34 	struct eth_info *eth = (struct eth_info *)(dev->priv);
35 	struct eth_dma *dma = &(eth->dma);
36 	struct phy_device *phydev;
37 	int rc = 0;
38 	int i;
39 
40 	rc = eth->mac_init(dev);
41 	if (rc) {
42 		pr_err("%s: Couldn't cofigure MAC!\n", __func__);
43 		return rc;
44 	}
45 
46 	/* disable DMA */
47 	dma->disable_dma(dma, MAC_DMA_RX);
48 	dma->disable_dma(dma, MAC_DMA_TX);
49 
50 	eth->port_num = 0;
51 	debug("Connecting PHY 0...\n");
52 	phydev = phy_connect(miiphy_get_dev_by_name(dev->name),
53 			     0, dev, eth->phy_interface);
54 	if (phydev != NULL) {
55 		eth->port[0] = phydev;
56 		eth->port_num += 1;
57 	} else {
58 		debug("No PHY found for port 0\n");
59 	}
60 
61 	for (i = 0; i < eth->port_num; i++)
62 		phy_config(eth->port[i]);
63 
64 	return rc;
65 }
66 
67 /*
68  * u-boot net functions
69  */
70 
71 static int bcm_sf2_eth_send(struct eth_device *dev, void *packet, int length)
72 {
73 	struct eth_dma *dma = &(((struct eth_info *)(dev->priv))->dma);
74 	uint8_t *buf = (uint8_t *)packet;
75 	int rc = 0;
76 	int i = 0;
77 
78 	debug("%s enter\n", __func__);
79 
80 	/* load buf and start transmit */
81 	rc = dma->tx_packet(dma, buf, length);
82 	if (rc) {
83 		debug("ERROR - Tx failed\n");
84 		return rc;
85 	}
86 
87 	while (!(dma->check_tx_done(dma))) {
88 		udelay(100);
89 		debug(".");
90 		i++;
91 		if (i > 20) {
92 			pr_err("%s: Tx timeout: retried 20 times\n", __func__);
93 			rc = -1;
94 			break;
95 		}
96 	}
97 
98 	debug("%s exit rc(0x%x)\n", __func__, rc);
99 	return rc;
100 }
101 
102 static int bcm_sf2_eth_receive(struct eth_device *dev)
103 {
104 	struct eth_dma *dma = &(((struct eth_info *)(dev->priv))->dma);
105 	uint8_t *buf = (uint8_t *)net_rx_packets[0];
106 	int rcvlen;
107 	int rc = 0;
108 	int i = 0;
109 
110 	while (1) {
111 		/* Poll Rx queue to get a packet */
112 		rcvlen = dma->check_rx_done(dma, buf);
113 		if (rcvlen < 0) {
114 			/* No packet received */
115 			rc = -1;
116 			debug("\nNO More Rx\n");
117 			break;
118 		} else if ((rcvlen == 0) || (rcvlen > RX_BUF_SIZE)) {
119 			pr_err("%s: Wrong Ethernet packet size (%d B), skip!\n",
120 			      __func__, rcvlen);
121 			break;
122 		} else {
123 			debug("recieved\n");
124 
125 			/* Forward received packet to uboot network handler */
126 			net_process_received_packet(buf, rcvlen);
127 
128 			if (++i >= PKTBUFSRX)
129 				i = 0;
130 			buf = net_rx_packets[i];
131 		}
132 	}
133 
134 	return rc;
135 }
136 
137 static int bcm_sf2_eth_write_hwaddr(struct eth_device *dev)
138 {
139 	struct eth_info *eth = (struct eth_info *)(dev->priv);
140 
141 	printf(" ETH MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
142 	       dev->enetaddr[0], dev->enetaddr[1], dev->enetaddr[2],
143 	       dev->enetaddr[3], dev->enetaddr[4], dev->enetaddr[5]);
144 
145 	return eth->set_mac_addr(dev->enetaddr);
146 }
147 
148 static int bcm_sf2_eth_open(struct eth_device *dev, bd_t *bt)
149 {
150 	struct eth_info *eth = (struct eth_info *)(dev->priv);
151 	struct eth_dma *dma = &(eth->dma);
152 	int i;
153 
154 	debug("Enabling BCM SF2 Ethernet.\n");
155 
156 	eth->enable_mac();
157 
158 	/* enable tx and rx DMA */
159 	dma->enable_dma(dma, MAC_DMA_RX);
160 	dma->enable_dma(dma, MAC_DMA_TX);
161 
162 	/*
163 	 * Need to start PHY here because link speed can change
164 	 * before each ethernet operation
165 	 */
166 	for (i = 0; i < eth->port_num; i++) {
167 		if (phy_startup(eth->port[i])) {
168 			pr_err("%s: PHY %d startup failed!\n", __func__, i);
169 			if (i == CONFIG_BCM_SF2_ETH_DEFAULT_PORT) {
170 				pr_err("%s: No default port %d!\n", __func__, i);
171 				return -1;
172 			}
173 		}
174 	}
175 
176 	/* Set MAC speed using default port */
177 	i = CONFIG_BCM_SF2_ETH_DEFAULT_PORT;
178 	debug("PHY %d: speed:%d, duplex:%d, link:%d\n", i,
179 	      eth->port[i]->speed, eth->port[i]->duplex, eth->port[i]->link);
180 	eth->set_mac_speed(eth->port[i]->speed, eth->port[i]->duplex);
181 
182 	debug("Enable Ethernet Done.\n");
183 
184 	return 0;
185 }
186 
187 static void bcm_sf2_eth_close(struct eth_device *dev)
188 {
189 	struct eth_info *eth = (struct eth_info *)(dev->priv);
190 	struct eth_dma *dma = &(eth->dma);
191 
192 	/* disable DMA */
193 	dma->disable_dma(dma, MAC_DMA_RX);
194 	dma->disable_dma(dma, MAC_DMA_TX);
195 
196 	eth->disable_mac();
197 }
198 
199 int bcm_sf2_eth_register(bd_t *bis, u8 dev_num)
200 {
201 	struct eth_device *dev;
202 	struct eth_info *eth;
203 	int rc;
204 
205 	dev = (struct eth_device *)malloc(sizeof(struct eth_device));
206 	if (dev == NULL) {
207 		pr_err("%s: Not enough memory!\n", __func__);
208 		return -1;
209 	}
210 
211 	eth = (struct eth_info *)malloc(sizeof(struct eth_info));
212 	if (eth == NULL) {
213 		pr_err("%s: Not enough memory!\n", __func__);
214 		return -1;
215 	}
216 
217 	printf(banner);
218 
219 	memset(dev, 0, sizeof(*dev));
220 	sprintf(dev->name, "%s_%s-%hu", BCM_SF2_ETH_DEV_NAME,
221 		BCM_SF2_ETH_MAC_NAME, dev_num);
222 
223 	dev->priv = (void *)eth;
224 	dev->iobase = 0;
225 
226 	dev->init = bcm_sf2_eth_open;
227 	dev->halt = bcm_sf2_eth_close;
228 	dev->send = bcm_sf2_eth_send;
229 	dev->recv = bcm_sf2_eth_receive;
230 	dev->write_hwaddr = bcm_sf2_eth_write_hwaddr;
231 
232 #ifdef CONFIG_BCM_SF2_ETH_GMAC
233 	if (gmac_add(dev)) {
234 		free(eth);
235 		free(dev);
236 		pr_err("%s: Adding GMAC failed!\n", __func__);
237 		return -1;
238 	}
239 #else
240 #error "bcm_sf2_eth: NEED to register a MAC!"
241 #endif
242 
243 	eth_register(dev);
244 
245 #ifdef CONFIG_CMD_MII
246 	int retval;
247 	struct mii_dev *mdiodev = mdio_alloc();
248 
249 	if (!mdiodev)
250 		return -ENOMEM;
251 	strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN);
252 	mdiodev->read = eth->miiphy_read;
253 	mdiodev->write = eth->miiphy_write;
254 
255 	retval = mdio_register(mdiodev);
256 	if (retval < 0)
257 		return retval;
258 #endif
259 
260 	/* Initialization */
261 	debug("Ethernet initialization ...");
262 
263 	rc = bcm_sf2_eth_init(dev);
264 	if (rc != 0) {
265 		pr_err("%s: configuration failed!\n", __func__);
266 		return -1;
267 	}
268 
269 	printf("Basic ethernet functionality initialized\n");
270 
271 	return 0;
272 }
273