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