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