1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2014 Broadcom Corporation.
4 */
5
6#include <common.h>
7#include <log.h>
8#include <malloc.h>
9#include <net.h>
10#include <config.h>
11#include <linux/delay.h>
12#include <linux/printk.h>
13
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) {
45		pr_err("%s: Couldn't cofigure MAC!\n", __func__);
46		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),
56			     -1, dev, eth->phy_interface);
57	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) {
95			pr_err("%s: Tx timeout: retried 20 times\n", __func__);
96			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);
108	uint8_t *buf = (uint8_t *)net_rx_packets[0];
109	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)) {
122			pr_err("%s: Wrong Ethernet packet size (%d B), skip!\n",
123			      __func__, rcvlen);
124			break;
125		} else {
126			debug("recieved\n");
127
128			/* Forward received packet to uboot network handler */
129			net_process_received_packet(buf, rcvlen);
130
131			if (++i >= PKTBUFSRX)
132				i = 0;
133			buf = net_rx_packets[i];
134		}
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
151static int bcm_sf2_eth_open(struct eth_device *dev, struct bd_info *bt)
152{
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
159	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])) {
171			pr_err("%s: PHY %d startup failed!\n", __func__, i);
172			if (i == CONFIG_BCM_SF2_ETH_DEFAULT_PORT) {
173				pr_err("%s: No default port %d!\n", __func__, i);
174				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
202int bcm_sf2_eth_register(struct bd_info *bis, u8 dev_num)
203{
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) {
210		pr_err("%s: Not enough memory!\n", __func__);
211		return -1;
212	}
213
214	eth = (struct eth_info *)malloc(sizeof(struct eth_info));
215	if (eth == NULL) {
216		pr_err("%s: Not enough memory!\n", __func__);
217		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);
239		pr_err("%s: Adding GMAC failed!\n", __func__);
240		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
249	int retval;
250	struct mii_dev *mdiodev = mdio_alloc();
251
252	if (!mdiodev)
253		return -ENOMEM;
254	strlcpy(mdiodev->name, dev->name, MDIO_NAME_LEN);
255	mdiodev->read = eth->miiphy_read;
256	mdiodev->write = eth->miiphy_write;
257
258	retval = mdio_register(mdiodev);
259	if (retval < 0)
260		return retval;
261#endif
262
263	/* Initialization */
264	debug("Ethernet initialization ...");
265
266	rc = bcm_sf2_eth_init(dev);
267	if (rc != 0) {
268		pr_err("%s: configuration failed!\n", __func__);
269		return -1;
270	}
271
272	printf("Basic ethernet functionality initialized\n");
273
274	return 0;
275}
276