blob: 2998d57c72f799705483b294fe53c62b284f7283 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Jiandong Zhengc36e42e2014-08-01 20:37:16 -07002/*
3 * Copyright 2014 Broadcom Corporation.
Jiandong Zhengc36e42e2014-08-01 20:37:16 -07004 */
5
6#include <common.h>
Simon Glass0f2af882020-05-10 11:40:05 -06007#include <log.h>
Jiandong Zhengc36e42e2014-08-01 20:37:16 -07008#include <malloc.h>
9#include <net.h>
10#include <config.h>
Simon Glassdbd79542020-05-10 11:40:11 -060011#include <linux/delay.h>
Jiandong Zhengc36e42e2014-08-01 20:37:16 -070012
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
31static const char banner[] =
32 BCM_NET_MODULE_DESCRIPTION " " BCM_NET_MODULE_VERSION "\n";
33
34static 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) {
Masahiro Yamada81e10422017-09-16 14:10:41 +090044 pr_err("%s: Couldn't cofigure MAC!\n", __func__);
Jiandong Zhengc36e42e2014-08-01 20:37:16 -070045 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),
Alex Margineane1a25da2019-12-19 14:35:37 +020055 -1, dev, eth->phy_interface);
Jiandong Zhengc36e42e2014-08-01 20:37:16 -070056 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
73static 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) {
Masahiro Yamada81e10422017-09-16 14:10:41 +090094 pr_err("%s: Tx timeout: retried 20 times\n", __func__);
Jiandong Zhengc36e42e2014-08-01 20:37:16 -070095 rc = -1;
96 break;
97 }
98 }
99
100 debug("%s exit rc(0x%x)\n", __func__, rc);
101 return rc;
102}
103
104static int bcm_sf2_eth_receive(struct eth_device *dev)
105{
106 struct eth_dma *dma = &(((struct eth_info *)(dev->priv))->dma);
Joe Hershberger9f09a362015-04-08 01:41:06 -0500107 uint8_t *buf = (uint8_t *)net_rx_packets[0];
Jiandong Zhengc36e42e2014-08-01 20:37:16 -0700108 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)) {
Masahiro Yamada81e10422017-09-16 14:10:41 +0900121 pr_err("%s: Wrong Ethernet packet size (%d B), skip!\n",
Jiandong Zhengc36e42e2014-08-01 20:37:16 -0700122 __func__, rcvlen);
123 break;
124 } else {
125 debug("recieved\n");
126
127 /* Forward received packet to uboot network handler */
Joe Hershberger9f09a362015-04-08 01:41:06 -0500128 net_process_received_packet(buf, rcvlen);
Jiandong Zhengc36e42e2014-08-01 20:37:16 -0700129
130 if (++i >= PKTBUFSRX)
131 i = 0;
Joe Hershberger9f09a362015-04-08 01:41:06 -0500132 buf = net_rx_packets[i];
Jiandong Zhengc36e42e2014-08-01 20:37:16 -0700133 }
134 }
135
136 return rc;
137}
138
139static 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
150static int bcm_sf2_eth_open(struct eth_device *dev, bd_t *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
Jiandong Zhengc36e42e2014-08-01 20:37:16 -0700158 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])) {
Masahiro Yamada81e10422017-09-16 14:10:41 +0900170 pr_err("%s: PHY %d startup failed!\n", __func__, i);
Jiandong Zhengc36e42e2014-08-01 20:37:16 -0700171 if (i == CONFIG_BCM_SF2_ETH_DEFAULT_PORT) {
Masahiro Yamada81e10422017-09-16 14:10:41 +0900172 pr_err("%s: No default port %d!\n", __func__, i);
Jiandong Zhengc36e42e2014-08-01 20:37:16 -0700173 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
189static 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
201int bcm_sf2_eth_register(bd_t *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) {
Masahiro Yamada81e10422017-09-16 14:10:41 +0900209 pr_err("%s: Not enough memory!\n", __func__);
Jiandong Zhengc36e42e2014-08-01 20:37:16 -0700210 return -1;
211 }
212
213 eth = (struct eth_info *)malloc(sizeof(struct eth_info));
214 if (eth == NULL) {
Masahiro Yamada81e10422017-09-16 14:10:41 +0900215 pr_err("%s: Not enough memory!\n", __func__);
Jiandong Zhengc36e42e2014-08-01 20:37:16 -0700216 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);
Masahiro Yamada81e10422017-09-16 14:10:41 +0900238 pr_err("%s: Adding GMAC failed!\n", __func__);
Jiandong Zhengc36e42e2014-08-01 20:37:16 -0700239 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
Joe Hershberger0c333192016-08-08 11:28:39 -0500248 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;
Jiandong Zhengc36e42e2014-08-01 20:37:16 -0700260#endif
261
262 /* Initialization */
263 debug("Ethernet initialization ...");
264
265 rc = bcm_sf2_eth_init(dev);
266 if (rc != 0) {
Masahiro Yamada81e10422017-09-16 14:10:41 +0900267 pr_err("%s: configuration failed!\n", __func__);
Jiandong Zhengc36e42e2014-08-01 20:37:16 -0700268 return -1;
269 }
270
271 printf("Basic ethernet functionality initialized\n");
272
273 return 0;
274}