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