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 *)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 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 /* 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 194 static 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 206 int 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 } 269