xref: /rk3399_rockchip-uboot/drivers/net/bcm-sf2-eth.c (revision 90aa625c9a9e1fb7a2f001fd8e50099bacaf92b8)
1799e125cSJiandong Zheng /*
2799e125cSJiandong Zheng  * Copyright 2014 Broadcom Corporation.
3799e125cSJiandong Zheng  *
4799e125cSJiandong Zheng  * SPDX-License-Identifier:	GPL-2.0+
5799e125cSJiandong Zheng  */
6799e125cSJiandong Zheng 
7799e125cSJiandong Zheng #include <common.h>
8799e125cSJiandong Zheng #include <malloc.h>
9799e125cSJiandong Zheng #include <net.h>
10799e125cSJiandong Zheng #include <config.h>
11799e125cSJiandong Zheng 
12799e125cSJiandong Zheng #include <phy.h>
13799e125cSJiandong Zheng #include <miiphy.h>
14799e125cSJiandong Zheng 
15799e125cSJiandong Zheng #include <asm/io.h>
16799e125cSJiandong Zheng 
17799e125cSJiandong Zheng #include <netdev.h>
18799e125cSJiandong Zheng #include "bcm-sf2-eth.h"
19799e125cSJiandong Zheng 
20799e125cSJiandong Zheng #if defined(CONFIG_BCM_SF2_ETH_GMAC)
21799e125cSJiandong Zheng #include "bcm-sf2-eth-gmac.h"
22799e125cSJiandong Zheng #else
23799e125cSJiandong Zheng #error "bcm_sf2_eth: NEED to define a MAC!"
24799e125cSJiandong Zheng #endif
25799e125cSJiandong Zheng 
26799e125cSJiandong Zheng #define BCM_NET_MODULE_DESCRIPTION	"Broadcom Starfighter2 Ethernet driver"
27799e125cSJiandong Zheng #define BCM_NET_MODULE_VERSION		"0.1"
28799e125cSJiandong Zheng #define BCM_SF2_ETH_DEV_NAME		"bcm_sf2"
29799e125cSJiandong Zheng 
30799e125cSJiandong Zheng static const char banner[] =
31799e125cSJiandong Zheng 	BCM_NET_MODULE_DESCRIPTION " " BCM_NET_MODULE_VERSION "\n";
32799e125cSJiandong Zheng 
bcm_sf2_eth_init(struct eth_device * dev)33799e125cSJiandong Zheng static int bcm_sf2_eth_init(struct eth_device *dev)
34799e125cSJiandong Zheng {
35799e125cSJiandong Zheng 	struct eth_info *eth = (struct eth_info *)(dev->priv);
36799e125cSJiandong Zheng 	struct eth_dma *dma = &(eth->dma);
37799e125cSJiandong Zheng 	struct phy_device *phydev;
38799e125cSJiandong Zheng 	int rc = 0;
39799e125cSJiandong Zheng 	int i;
40799e125cSJiandong Zheng 
41799e125cSJiandong Zheng 	rc = eth->mac_init(dev);
42799e125cSJiandong Zheng 	if (rc) {
43*90aa625cSMasahiro Yamada 		pr_err("%s: Couldn't cofigure MAC!\n", __func__);
44799e125cSJiandong Zheng 		return rc;
45799e125cSJiandong Zheng 	}
46799e125cSJiandong Zheng 
47799e125cSJiandong Zheng 	/* disable DMA */
48799e125cSJiandong Zheng 	dma->disable_dma(dma, MAC_DMA_RX);
49799e125cSJiandong Zheng 	dma->disable_dma(dma, MAC_DMA_TX);
50799e125cSJiandong Zheng 
51799e125cSJiandong Zheng 	eth->port_num = 0;
52799e125cSJiandong Zheng 	debug("Connecting PHY 0...\n");
53799e125cSJiandong Zheng 	phydev = phy_connect(miiphy_get_dev_by_name(dev->name),
54799e125cSJiandong Zheng 			     0, dev, eth->phy_interface);
55799e125cSJiandong Zheng 	if (phydev != NULL) {
56799e125cSJiandong Zheng 		eth->port[0] = phydev;
57799e125cSJiandong Zheng 		eth->port_num += 1;
58799e125cSJiandong Zheng 	} else {
59799e125cSJiandong Zheng 		debug("No PHY found for port 0\n");
60799e125cSJiandong Zheng 	}
61799e125cSJiandong Zheng 
62799e125cSJiandong Zheng 	for (i = 0; i < eth->port_num; i++)
63799e125cSJiandong Zheng 		phy_config(eth->port[i]);
64799e125cSJiandong Zheng 
65799e125cSJiandong Zheng 	return rc;
66799e125cSJiandong Zheng }
67799e125cSJiandong Zheng 
68799e125cSJiandong Zheng /*
69799e125cSJiandong Zheng  * u-boot net functions
70799e125cSJiandong Zheng  */
71799e125cSJiandong Zheng 
bcm_sf2_eth_send(struct eth_device * dev,void * packet,int length)72799e125cSJiandong Zheng static int bcm_sf2_eth_send(struct eth_device *dev, void *packet, int length)
73799e125cSJiandong Zheng {
74799e125cSJiandong Zheng 	struct eth_dma *dma = &(((struct eth_info *)(dev->priv))->dma);
75799e125cSJiandong Zheng 	uint8_t *buf = (uint8_t *)packet;
76799e125cSJiandong Zheng 	int rc = 0;
77799e125cSJiandong Zheng 	int i = 0;
78799e125cSJiandong Zheng 
79799e125cSJiandong Zheng 	debug("%s enter\n", __func__);
80799e125cSJiandong Zheng 
81799e125cSJiandong Zheng 	/* load buf and start transmit */
82799e125cSJiandong Zheng 	rc = dma->tx_packet(dma, buf, length);
83799e125cSJiandong Zheng 	if (rc) {
84799e125cSJiandong Zheng 		debug("ERROR - Tx failed\n");
85799e125cSJiandong Zheng 		return rc;
86799e125cSJiandong Zheng 	}
87799e125cSJiandong Zheng 
88799e125cSJiandong Zheng 	while (!(dma->check_tx_done(dma))) {
89799e125cSJiandong Zheng 		udelay(100);
90799e125cSJiandong Zheng 		debug(".");
91799e125cSJiandong Zheng 		i++;
92799e125cSJiandong Zheng 		if (i > 20) {
93*90aa625cSMasahiro Yamada 			pr_err("%s: Tx timeout: retried 20 times\n", __func__);
94799e125cSJiandong Zheng 			rc = -1;
95799e125cSJiandong Zheng 			break;
96799e125cSJiandong Zheng 		}
97799e125cSJiandong Zheng 	}
98799e125cSJiandong Zheng 
99799e125cSJiandong Zheng 	debug("%s exit rc(0x%x)\n", __func__, rc);
100799e125cSJiandong Zheng 	return rc;
101799e125cSJiandong Zheng }
102799e125cSJiandong Zheng 
bcm_sf2_eth_receive(struct eth_device * dev)103799e125cSJiandong Zheng static int bcm_sf2_eth_receive(struct eth_device *dev)
104799e125cSJiandong Zheng {
105799e125cSJiandong Zheng 	struct eth_dma *dma = &(((struct eth_info *)(dev->priv))->dma);
1061fd92db8SJoe Hershberger 	uint8_t *buf = (uint8_t *)net_rx_packets[0];
107799e125cSJiandong Zheng 	int rcvlen;
108799e125cSJiandong Zheng 	int rc = 0;
109799e125cSJiandong Zheng 	int i = 0;
110799e125cSJiandong Zheng 
111799e125cSJiandong Zheng 	while (1) {
112799e125cSJiandong Zheng 		/* Poll Rx queue to get a packet */
113799e125cSJiandong Zheng 		rcvlen = dma->check_rx_done(dma, buf);
114799e125cSJiandong Zheng 		if (rcvlen < 0) {
115799e125cSJiandong Zheng 			/* No packet received */
116799e125cSJiandong Zheng 			rc = -1;
117799e125cSJiandong Zheng 			debug("\nNO More Rx\n");
118799e125cSJiandong Zheng 			break;
119799e125cSJiandong Zheng 		} else if ((rcvlen == 0) || (rcvlen > RX_BUF_SIZE)) {
120*90aa625cSMasahiro Yamada 			pr_err("%s: Wrong Ethernet packet size (%d B), skip!\n",
121799e125cSJiandong Zheng 			      __func__, rcvlen);
122799e125cSJiandong Zheng 			break;
123799e125cSJiandong Zheng 		} else {
124799e125cSJiandong Zheng 			debug("recieved\n");
125799e125cSJiandong Zheng 
126799e125cSJiandong Zheng 			/* Forward received packet to uboot network handler */
1271fd92db8SJoe Hershberger 			net_process_received_packet(buf, rcvlen);
128799e125cSJiandong Zheng 
129799e125cSJiandong Zheng 			if (++i >= PKTBUFSRX)
130799e125cSJiandong Zheng 				i = 0;
1311fd92db8SJoe Hershberger 			buf = net_rx_packets[i];
132799e125cSJiandong Zheng 		}
133799e125cSJiandong Zheng 	}
134799e125cSJiandong Zheng 
135799e125cSJiandong Zheng 	return rc;
136799e125cSJiandong Zheng }
137799e125cSJiandong Zheng 
bcm_sf2_eth_write_hwaddr(struct eth_device * dev)138799e125cSJiandong Zheng static int bcm_sf2_eth_write_hwaddr(struct eth_device *dev)
139799e125cSJiandong Zheng {
140799e125cSJiandong Zheng 	struct eth_info *eth = (struct eth_info *)(dev->priv);
141799e125cSJiandong Zheng 
142799e125cSJiandong Zheng 	printf(" ETH MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
143799e125cSJiandong Zheng 	       dev->enetaddr[0], dev->enetaddr[1], dev->enetaddr[2],
144799e125cSJiandong Zheng 	       dev->enetaddr[3], dev->enetaddr[4], dev->enetaddr[5]);
145799e125cSJiandong Zheng 
146799e125cSJiandong Zheng 	return eth->set_mac_addr(dev->enetaddr);
147799e125cSJiandong Zheng }
148799e125cSJiandong Zheng 
bcm_sf2_eth_open(struct eth_device * dev,bd_t * bt)149799e125cSJiandong Zheng static int bcm_sf2_eth_open(struct eth_device *dev, bd_t *bt)
150799e125cSJiandong Zheng {
151799e125cSJiandong Zheng 	struct eth_info *eth = (struct eth_info *)(dev->priv);
152799e125cSJiandong Zheng 	struct eth_dma *dma = &(eth->dma);
153799e125cSJiandong Zheng 	int i;
154799e125cSJiandong Zheng 
155799e125cSJiandong Zheng 	debug("Enabling BCM SF2 Ethernet.\n");
156799e125cSJiandong Zheng 
157799e125cSJiandong Zheng 	eth->enable_mac();
158799e125cSJiandong Zheng 
159799e125cSJiandong Zheng 	/* enable tx and rx DMA */
160799e125cSJiandong Zheng 	dma->enable_dma(dma, MAC_DMA_RX);
161799e125cSJiandong Zheng 	dma->enable_dma(dma, MAC_DMA_TX);
162799e125cSJiandong Zheng 
163799e125cSJiandong Zheng 	/*
164799e125cSJiandong Zheng 	 * Need to start PHY here because link speed can change
165799e125cSJiandong Zheng 	 * before each ethernet operation
166799e125cSJiandong Zheng 	 */
167799e125cSJiandong Zheng 	for (i = 0; i < eth->port_num; i++) {
168799e125cSJiandong Zheng 		if (phy_startup(eth->port[i])) {
169*90aa625cSMasahiro Yamada 			pr_err("%s: PHY %d startup failed!\n", __func__, i);
170799e125cSJiandong Zheng 			if (i == CONFIG_BCM_SF2_ETH_DEFAULT_PORT) {
171*90aa625cSMasahiro Yamada 				pr_err("%s: No default port %d!\n", __func__, i);
172799e125cSJiandong Zheng 				return -1;
173799e125cSJiandong Zheng 			}
174799e125cSJiandong Zheng 		}
175799e125cSJiandong Zheng 	}
176799e125cSJiandong Zheng 
177799e125cSJiandong Zheng 	/* Set MAC speed using default port */
178799e125cSJiandong Zheng 	i = CONFIG_BCM_SF2_ETH_DEFAULT_PORT;
179799e125cSJiandong Zheng 	debug("PHY %d: speed:%d, duplex:%d, link:%d\n", i,
180799e125cSJiandong Zheng 	      eth->port[i]->speed, eth->port[i]->duplex, eth->port[i]->link);
181799e125cSJiandong Zheng 	eth->set_mac_speed(eth->port[i]->speed, eth->port[i]->duplex);
182799e125cSJiandong Zheng 
183799e125cSJiandong Zheng 	debug("Enable Ethernet Done.\n");
184799e125cSJiandong Zheng 
185799e125cSJiandong Zheng 	return 0;
186799e125cSJiandong Zheng }
187799e125cSJiandong Zheng 
bcm_sf2_eth_close(struct eth_device * dev)188799e125cSJiandong Zheng static void bcm_sf2_eth_close(struct eth_device *dev)
189799e125cSJiandong Zheng {
190799e125cSJiandong Zheng 	struct eth_info *eth = (struct eth_info *)(dev->priv);
191799e125cSJiandong Zheng 	struct eth_dma *dma = &(eth->dma);
192799e125cSJiandong Zheng 
193799e125cSJiandong Zheng 	/* disable DMA */
194799e125cSJiandong Zheng 	dma->disable_dma(dma, MAC_DMA_RX);
195799e125cSJiandong Zheng 	dma->disable_dma(dma, MAC_DMA_TX);
196799e125cSJiandong Zheng 
197799e125cSJiandong Zheng 	eth->disable_mac();
198799e125cSJiandong Zheng }
199799e125cSJiandong Zheng 
bcm_sf2_eth_register(bd_t * bis,u8 dev_num)200799e125cSJiandong Zheng int bcm_sf2_eth_register(bd_t *bis, u8 dev_num)
201799e125cSJiandong Zheng {
202799e125cSJiandong Zheng 	struct eth_device *dev;
203799e125cSJiandong Zheng 	struct eth_info *eth;
204799e125cSJiandong Zheng 	int rc;
205799e125cSJiandong Zheng 
206799e125cSJiandong Zheng 	dev = (struct eth_device *)malloc(sizeof(struct eth_device));
207799e125cSJiandong Zheng 	if (dev == NULL) {
208*90aa625cSMasahiro Yamada 		pr_err("%s: Not enough memory!\n", __func__);
209799e125cSJiandong Zheng 		return -1;
210799e125cSJiandong Zheng 	}
211799e125cSJiandong Zheng 
212799e125cSJiandong Zheng 	eth = (struct eth_info *)malloc(sizeof(struct eth_info));
213799e125cSJiandong Zheng 	if (eth == NULL) {
214*90aa625cSMasahiro Yamada 		pr_err("%s: Not enough memory!\n", __func__);
215799e125cSJiandong Zheng 		return -1;
216799e125cSJiandong Zheng 	}
217799e125cSJiandong Zheng 
218799e125cSJiandong Zheng 	printf(banner);
219799e125cSJiandong Zheng 
220799e125cSJiandong Zheng 	memset(dev, 0, sizeof(*dev));
221799e125cSJiandong Zheng 	sprintf(dev->name, "%s_%s-%hu", BCM_SF2_ETH_DEV_NAME,
222799e125cSJiandong Zheng 		BCM_SF2_ETH_MAC_NAME, dev_num);
223799e125cSJiandong Zheng 
224799e125cSJiandong Zheng 	dev->priv = (void *)eth;
225799e125cSJiandong Zheng 	dev->iobase = 0;
226799e125cSJiandong Zheng 
227799e125cSJiandong Zheng 	dev->init = bcm_sf2_eth_open;
228799e125cSJiandong Zheng 	dev->halt = bcm_sf2_eth_close;
229799e125cSJiandong Zheng 	dev->send = bcm_sf2_eth_send;
230799e125cSJiandong Zheng 	dev->recv = bcm_sf2_eth_receive;
231799e125cSJiandong Zheng 	dev->write_hwaddr = bcm_sf2_eth_write_hwaddr;
232799e125cSJiandong Zheng 
233799e125cSJiandong Zheng #ifdef CONFIG_BCM_SF2_ETH_GMAC
234799e125cSJiandong Zheng 	if (gmac_add(dev)) {
235799e125cSJiandong Zheng 		free(eth);
236799e125cSJiandong Zheng 		free(dev);
237*90aa625cSMasahiro Yamada 		pr_err("%s: Adding GMAC failed!\n", __func__);
238799e125cSJiandong Zheng 		return -1;
239799e125cSJiandong Zheng 	}
240799e125cSJiandong Zheng #else
241799e125cSJiandong Zheng #error "bcm_sf2_eth: NEED to register a MAC!"
242799e125cSJiandong Zheng #endif
243799e125cSJiandong Zheng 
244799e125cSJiandong Zheng 	eth_register(dev);
245799e125cSJiandong Zheng 
246799e125cSJiandong Zheng #ifdef CONFIG_CMD_MII
247dfcc496eSJoe Hershberger 	int retval;
248dfcc496eSJoe Hershberger 	struct mii_dev *mdiodev = mdio_alloc();
249dfcc496eSJoe Hershberger 
250dfcc496eSJoe Hershberger 	if (!mdiodev)
251dfcc496eSJoe Hershberger 		return -ENOMEM;
252dfcc496eSJoe Hershberger 	strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN);
253dfcc496eSJoe Hershberger 	mdiodev->read = eth->miiphy_read;
254dfcc496eSJoe Hershberger 	mdiodev->write = eth->miiphy_write;
255dfcc496eSJoe Hershberger 
256dfcc496eSJoe Hershberger 	retval = mdio_register(mdiodev);
257dfcc496eSJoe Hershberger 	if (retval < 0)
258dfcc496eSJoe Hershberger 		return retval;
259799e125cSJiandong Zheng #endif
260799e125cSJiandong Zheng 
261799e125cSJiandong Zheng 	/* Initialization */
262799e125cSJiandong Zheng 	debug("Ethernet initialization ...");
263799e125cSJiandong Zheng 
264799e125cSJiandong Zheng 	rc = bcm_sf2_eth_init(dev);
265799e125cSJiandong Zheng 	if (rc != 0) {
266*90aa625cSMasahiro Yamada 		pr_err("%s: configuration failed!\n", __func__);
267799e125cSJiandong Zheng 		return -1;
268799e125cSJiandong Zheng 	}
269799e125cSJiandong Zheng 
270799e125cSJiandong Zheng 	printf("Basic ethernet functionality initialized\n");
271799e125cSJiandong Zheng 
272799e125cSJiandong Zheng 	return 0;
273799e125cSJiandong Zheng }
274