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