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