blob: 9056f71b9aceb3732dd4a8fe9da1243d23779d21 [file] [log] [blame]
Jiandong Zheng799e1252014-08-01 20:37:16 -07001/*
2 * Copyright 2014 Broadcom Corporation.
3 *
4 * SPDX-License-Identifier: GPL-2.0+
5 */
6
7#include <common.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
30static const char banner[] =
31 BCM_NET_MODULE_DESCRIPTION " " BCM_NET_MODULE_VERSION "\n";
32
33static 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) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +090043 pr_err("%s: Couldn't cofigure MAC!\n", __func__);
Jiandong Zheng799e1252014-08-01 20:37:16 -070044 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 0, 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
72static 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) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +090093 pr_err("%s: Tx timeout: retried 20 times\n", __func__);
Jiandong Zheng799e1252014-08-01 20:37:16 -070094 rc = -1;
95 break;
96 }
97 }
98
99 debug("%s exit rc(0x%x)\n", __func__, rc);
100 return rc;
101}
102
103static int bcm_sf2_eth_receive(struct eth_device *dev)
104{
105 struct eth_dma *dma = &(((struct eth_info *)(dev->priv))->dma);
Joe Hershberger1fd92db2015-04-08 01:41:06 -0500106 uint8_t *buf = (uint8_t *)net_rx_packets[0];
Jiandong Zheng799e1252014-08-01 20:37:16 -0700107 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)) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900120 pr_err("%s: Wrong Ethernet packet size (%d B), skip!\n",
Jiandong Zheng799e1252014-08-01 20:37:16 -0700121 __func__, rcvlen);
122 break;
123 } else {
124 debug("recieved\n");
125
126 /* Forward received packet to uboot network handler */
Joe Hershberger1fd92db2015-04-08 01:41:06 -0500127 net_process_received_packet(buf, rcvlen);
Jiandong Zheng799e1252014-08-01 20:37:16 -0700128
129 if (++i >= PKTBUFSRX)
130 i = 0;
Joe Hershberger1fd92db2015-04-08 01:41:06 -0500131 buf = net_rx_packets[i];
Jiandong Zheng799e1252014-08-01 20:37:16 -0700132 }
133 }
134
135 return rc;
136}
137
138static 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
149static 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
Jiandong Zheng799e1252014-08-01 20:37:16 -0700157 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])) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900169 pr_err("%s: PHY %d startup failed!\n", __func__, i);
Jiandong Zheng799e1252014-08-01 20:37:16 -0700170 if (i == CONFIG_BCM_SF2_ETH_DEFAULT_PORT) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900171 pr_err("%s: No default port %d!\n", __func__, i);
Jiandong Zheng799e1252014-08-01 20:37:16 -0700172 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
188static 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
200int 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) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900208 pr_err("%s: Not enough memory!\n", __func__);
Jiandong Zheng799e1252014-08-01 20:37:16 -0700209 return -1;
210 }
211
212 eth = (struct eth_info *)malloc(sizeof(struct eth_info));
213 if (eth == NULL) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900214 pr_err("%s: Not enough memory!\n", __func__);
Jiandong Zheng799e1252014-08-01 20:37:16 -0700215 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);
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900237 pr_err("%s: Adding GMAC failed!\n", __func__);
Jiandong Zheng799e1252014-08-01 20:37:16 -0700238 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
Joe Hershbergerdfcc4962016-08-08 11:28:39 -0500247 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;
Jiandong Zheng799e1252014-08-01 20:37:16 -0700259#endif
260
261 /* Initialization */
262 debug("Ethernet initialization ...");
263
264 rc = bcm_sf2_eth_init(dev);
265 if (rc != 0) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900266 pr_err("%s: configuration failed!\n", __func__);
Jiandong Zheng799e1252014-08-01 20:37:16 -0700267 return -1;
268 }
269
270 printf("Basic ethernet functionality initialized\n");
271
272 return 0;
273}