c8393c5f50158c7865889a863f81b63d1fa5ff9d
[oweals/u-boot.git] / drivers / net / bcm-sf2-eth.c
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
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                              -1, 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 }