blob: 5252d49de9568b33669426f84bb386b6b520c337 [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) {
43 error("%s: Couldn't cofigure MAC!\n", __func__);
44 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) {
93 error("%s: Tx timeout: retried 20 times\n", __func__);
94 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);
106 uint8_t *buf = (uint8_t *)NetRxPackets[0];
107 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)) {
120 error("%s: Wrong Ethernet packet size (%d B), skip!\n",
121 __func__, rcvlen);
122 break;
123 } else {
124 debug("recieved\n");
125
126 /* Forward received packet to uboot network handler */
127 NetReceive(buf, rcvlen);
128
129 if (++i >= PKTBUFSRX)
130 i = 0;
131 buf = NetRxPackets[i];
132 }
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
157 /* Set MAC address from env */
158 if (bcm_sf2_eth_write_hwaddr(dev) != 0) {
159 error("%s: MAC set error when opening !\n", __func__);
160 return -1;
161 }
162
163 eth->enable_mac();
164
165 /* enable tx and rx DMA */
166 dma->enable_dma(dma, MAC_DMA_RX);
167 dma->enable_dma(dma, MAC_DMA_TX);
168
169 /*
170 * Need to start PHY here because link speed can change
171 * before each ethernet operation
172 */
173 for (i = 0; i < eth->port_num; i++) {
174 if (phy_startup(eth->port[i])) {
175 error("%s: PHY %d startup failed!\n", __func__, i);
176 if (i == CONFIG_BCM_SF2_ETH_DEFAULT_PORT) {
177 error("%s: No default port %d!\n", __func__, i);
178 return -1;
179 }
180 }
181 }
182
183 /* Set MAC speed using default port */
184 i = CONFIG_BCM_SF2_ETH_DEFAULT_PORT;
185 debug("PHY %d: speed:%d, duplex:%d, link:%d\n", i,
186 eth->port[i]->speed, eth->port[i]->duplex, eth->port[i]->link);
187 eth->set_mac_speed(eth->port[i]->speed, eth->port[i]->duplex);
188
189 debug("Enable Ethernet Done.\n");
190
191 return 0;
192}
193
194static void bcm_sf2_eth_close(struct eth_device *dev)
195{
196 struct eth_info *eth = (struct eth_info *)(dev->priv);
197 struct eth_dma *dma = &(eth->dma);
198
199 /* disable DMA */
200 dma->disable_dma(dma, MAC_DMA_RX);
201 dma->disable_dma(dma, MAC_DMA_TX);
202
203 eth->disable_mac();
204}
205
206int bcm_sf2_eth_register(bd_t *bis, u8 dev_num)
207{
208 struct eth_device *dev;
209 struct eth_info *eth;
210 int rc;
211
212 dev = (struct eth_device *)malloc(sizeof(struct eth_device));
213 if (dev == NULL) {
214 error("%s: Not enough memory!\n", __func__);
215 return -1;
216 }
217
218 eth = (struct eth_info *)malloc(sizeof(struct eth_info));
219 if (eth == NULL) {
220 error("%s: Not enough memory!\n", __func__);
221 return -1;
222 }
223
224 printf(banner);
225
226 memset(dev, 0, sizeof(*dev));
227 sprintf(dev->name, "%s_%s-%hu", BCM_SF2_ETH_DEV_NAME,
228 BCM_SF2_ETH_MAC_NAME, dev_num);
229
230 dev->priv = (void *)eth;
231 dev->iobase = 0;
232
233 dev->init = bcm_sf2_eth_open;
234 dev->halt = bcm_sf2_eth_close;
235 dev->send = bcm_sf2_eth_send;
236 dev->recv = bcm_sf2_eth_receive;
237 dev->write_hwaddr = bcm_sf2_eth_write_hwaddr;
238
239#ifdef CONFIG_BCM_SF2_ETH_GMAC
240 if (gmac_add(dev)) {
241 free(eth);
242 free(dev);
243 error("%s: Adding GMAC failed!\n", __func__);
244 return -1;
245 }
246#else
247#error "bcm_sf2_eth: NEED to register a MAC!"
248#endif
249
250 eth_register(dev);
251
252#ifdef CONFIG_CMD_MII
253 miiphy_register(dev->name, eth->miiphy_read, eth->miiphy_write);
254#endif
255
256 /* Initialization */
257 debug("Ethernet initialization ...");
258
259 rc = bcm_sf2_eth_init(dev);
260 if (rc != 0) {
261 error("%s: configuration failed!\n", __func__);
262 return -1;
263 }
264
265 printf("Basic ethernet functionality initialized\n");
266
267 return 0;
268}