blob: 11f937032f3c434c32033e4eca36e630a94816fb [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Jiandong Zheng799e1252014-08-01 20:37:16 -07002/*
3 * Copyright 2014 Broadcom Corporation.
Jiandong Zheng799e1252014-08-01 20:37:16 -07004 */
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
29static const char banner[] =
30 BCM_NET_MODULE_DESCRIPTION " " BCM_NET_MODULE_VERSION "\n";
31
32static 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) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +090042 pr_err("%s: Couldn't cofigure MAC!\n", __func__);
Jiandong Zheng799e1252014-08-01 20:37:16 -070043 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),
Alex Marginean1785d8c2019-12-19 14:35:37 +020053 -1, dev, eth->phy_interface);
Jiandong Zheng799e1252014-08-01 20:37:16 -070054 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
71static 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) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +090092 pr_err("%s: Tx timeout: retried 20 times\n", __func__);
Jiandong Zheng799e1252014-08-01 20:37:16 -070093 rc = -1;
94 break;
95 }
96 }
97
98 debug("%s exit rc(0x%x)\n", __func__, rc);
99 return rc;
100}
101
102static int bcm_sf2_eth_receive(struct eth_device *dev)
103{
104 struct eth_dma *dma = &(((struct eth_info *)(dev->priv))->dma);
Joe Hershberger1fd92db2015-04-08 01:41:06 -0500105 uint8_t *buf = (uint8_t *)net_rx_packets[0];
Jiandong Zheng799e1252014-08-01 20:37:16 -0700106 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)) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900119 pr_err("%s: Wrong Ethernet packet size (%d B), skip!\n",
Jiandong Zheng799e1252014-08-01 20:37:16 -0700120 __func__, rcvlen);
121 break;
122 } else {
123 debug("recieved\n");
124
125 /* Forward received packet to uboot network handler */
Joe Hershberger1fd92db2015-04-08 01:41:06 -0500126 net_process_received_packet(buf, rcvlen);
Jiandong Zheng799e1252014-08-01 20:37:16 -0700127
128 if (++i >= PKTBUFSRX)
129 i = 0;
Joe Hershberger1fd92db2015-04-08 01:41:06 -0500130 buf = net_rx_packets[i];
Jiandong Zheng799e1252014-08-01 20:37:16 -0700131 }
132 }
133
134 return rc;
135}
136
137static 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
148static 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
Jiandong Zheng799e1252014-08-01 20:37:16 -0700156 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])) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900168 pr_err("%s: PHY %d startup failed!\n", __func__, i);
Jiandong Zheng799e1252014-08-01 20:37:16 -0700169 if (i == CONFIG_BCM_SF2_ETH_DEFAULT_PORT) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900170 pr_err("%s: No default port %d!\n", __func__, i);
Jiandong Zheng799e1252014-08-01 20:37:16 -0700171 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
187static 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
199int 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) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900207 pr_err("%s: Not enough memory!\n", __func__);
Jiandong Zheng799e1252014-08-01 20:37:16 -0700208 return -1;
209 }
210
211 eth = (struct eth_info *)malloc(sizeof(struct eth_info));
212 if (eth == NULL) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900213 pr_err("%s: Not enough memory!\n", __func__);
Jiandong Zheng799e1252014-08-01 20:37:16 -0700214 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);
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900236 pr_err("%s: Adding GMAC failed!\n", __func__);
Jiandong Zheng799e1252014-08-01 20:37:16 -0700237 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
Joe Hershbergerdfcc4962016-08-08 11:28:39 -0500246 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;
Jiandong Zheng799e1252014-08-01 20:37:16 -0700258#endif
259
260 /* Initialization */
261 debug("Ethernet initialization ...");
262
263 rc = bcm_sf2_eth_init(dev);
264 if (rc != 0) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900265 pr_err("%s: configuration failed!\n", __func__);
Jiandong Zheng799e1252014-08-01 20:37:16 -0700266 return -1;
267 }
268
269 printf("Basic ethernet functionality initialized\n");
270
271 return 0;
272}