1 /* 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 30 static const char banner[] = 31 BCM_NET_MODULE_DESCRIPTION " " BCM_NET_MODULE_VERSION "\n"; 32 33 static 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 72 static 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 103 static 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 *)net_rx_packets[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 net_process_received_packet(buf, rcvlen); 128 129 if (++i >= PKTBUFSRX) 130 i = 0; 131 buf = net_rx_packets[i]; 132 } 133 } 134 135 return rc; 136 } 137 138 static 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 149 static 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 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])) { 169 error("%s: PHY %d startup failed!\n", __func__, i); 170 if (i == CONFIG_BCM_SF2_ETH_DEFAULT_PORT) { 171 error("%s: No default port %d!\n", __func__, i); 172 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 188 static 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 200 int 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) { 208 error("%s: Not enough memory!\n", __func__); 209 return -1; 210 } 211 212 eth = (struct eth_info *)malloc(sizeof(struct eth_info)); 213 if (eth == NULL) { 214 error("%s: Not enough memory!\n", __func__); 215 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); 237 error("%s: Adding GMAC failed!\n", __func__); 238 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 247 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; 259 #endif 260 261 /* Initialization */ 262 debug("Ethernet initialization ..."); 263 264 rc = bcm_sf2_eth_init(dev); 265 if (rc != 0) { 266 error("%s: configuration failed!\n", __func__); 267 return -1; 268 } 269 270 printf("Basic ethernet functionality initialized\n"); 271 272 return 0; 273 } 274