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