1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright 2014 Broadcom Corporation. 4 */ 5 6 #include <common.h> 7 #include <malloc.h> 8 #include <net.h> 9 #include <config.h> 10 11 #include <phy.h> 12 #include <miiphy.h> 13 14 #include <asm/io.h> 15 16 #include <netdev.h> 17 #include "bcm-sf2-eth.h" 18 19 #if defined(CONFIG_BCM_SF2_ETH_GMAC) 20 #include "bcm-sf2-eth-gmac.h" 21 #else 22 #error "bcm_sf2_eth: NEED to define a MAC!" 23 #endif 24 25 #define BCM_NET_MODULE_DESCRIPTION "Broadcom Starfighter2 Ethernet driver" 26 #define BCM_NET_MODULE_VERSION "0.1" 27 #define BCM_SF2_ETH_DEV_NAME "bcm_sf2" 28 29 static const char banner[] = 30 BCM_NET_MODULE_DESCRIPTION " " BCM_NET_MODULE_VERSION "\n"; 31 32 static int bcm_sf2_eth_init(struct eth_device *dev) 33 { 34 struct eth_info *eth = (struct eth_info *)(dev->priv); 35 struct eth_dma *dma = &(eth->dma); 36 struct phy_device *phydev; 37 int rc = 0; 38 int i; 39 40 rc = eth->mac_init(dev); 41 if (rc) { 42 pr_err("%s: Couldn't cofigure MAC!\n", __func__); 43 return rc; 44 } 45 46 /* disable DMA */ 47 dma->disable_dma(dma, MAC_DMA_RX); 48 dma->disable_dma(dma, MAC_DMA_TX); 49 50 eth->port_num = 0; 51 debug("Connecting PHY 0...\n"); 52 phydev = phy_connect(miiphy_get_dev_by_name(dev->name), 53 0, dev, eth->phy_interface); 54 if (phydev != NULL) { 55 eth->port[0] = phydev; 56 eth->port_num += 1; 57 } else { 58 debug("No PHY found for port 0\n"); 59 } 60 61 for (i = 0; i < eth->port_num; i++) 62 phy_config(eth->port[i]); 63 64 return rc; 65 } 66 67 /* 68 * u-boot net functions 69 */ 70 71 static int bcm_sf2_eth_send(struct eth_device *dev, void *packet, int length) 72 { 73 struct eth_dma *dma = &(((struct eth_info *)(dev->priv))->dma); 74 uint8_t *buf = (uint8_t *)packet; 75 int rc = 0; 76 int i = 0; 77 78 debug("%s enter\n", __func__); 79 80 /* load buf and start transmit */ 81 rc = dma->tx_packet(dma, buf, length); 82 if (rc) { 83 debug("ERROR - Tx failed\n"); 84 return rc; 85 } 86 87 while (!(dma->check_tx_done(dma))) { 88 udelay(100); 89 debug("."); 90 i++; 91 if (i > 20) { 92 pr_err("%s: Tx timeout: retried 20 times\n", __func__); 93 rc = -1; 94 break; 95 } 96 } 97 98 debug("%s exit rc(0x%x)\n", __func__, rc); 99 return rc; 100 } 101 102 static int bcm_sf2_eth_receive(struct eth_device *dev) 103 { 104 struct eth_dma *dma = &(((struct eth_info *)(dev->priv))->dma); 105 uint8_t *buf = (uint8_t *)net_rx_packets[0]; 106 int rcvlen; 107 int rc = 0; 108 int i = 0; 109 110 while (1) { 111 /* Poll Rx queue to get a packet */ 112 rcvlen = dma->check_rx_done(dma, buf); 113 if (rcvlen < 0) { 114 /* No packet received */ 115 rc = -1; 116 debug("\nNO More Rx\n"); 117 break; 118 } else if ((rcvlen == 0) || (rcvlen > RX_BUF_SIZE)) { 119 pr_err("%s: Wrong Ethernet packet size (%d B), skip!\n", 120 __func__, rcvlen); 121 break; 122 } else { 123 debug("recieved\n"); 124 125 /* Forward received packet to uboot network handler */ 126 net_process_received_packet(buf, rcvlen); 127 128 if (++i >= PKTBUFSRX) 129 i = 0; 130 buf = net_rx_packets[i]; 131 } 132 } 133 134 return rc; 135 } 136 137 static int bcm_sf2_eth_write_hwaddr(struct eth_device *dev) 138 { 139 struct eth_info *eth = (struct eth_info *)(dev->priv); 140 141 printf(" ETH MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", 142 dev->enetaddr[0], dev->enetaddr[1], dev->enetaddr[2], 143 dev->enetaddr[3], dev->enetaddr[4], dev->enetaddr[5]); 144 145 return eth->set_mac_addr(dev->enetaddr); 146 } 147 148 static int bcm_sf2_eth_open(struct eth_device *dev, bd_t *bt) 149 { 150 struct eth_info *eth = (struct eth_info *)(dev->priv); 151 struct eth_dma *dma = &(eth->dma); 152 int i; 153 154 debug("Enabling BCM SF2 Ethernet.\n"); 155 156 eth->enable_mac(); 157 158 /* enable tx and rx DMA */ 159 dma->enable_dma(dma, MAC_DMA_RX); 160 dma->enable_dma(dma, MAC_DMA_TX); 161 162 /* 163 * Need to start PHY here because link speed can change 164 * before each ethernet operation 165 */ 166 for (i = 0; i < eth->port_num; i++) { 167 if (phy_startup(eth->port[i])) { 168 pr_err("%s: PHY %d startup failed!\n", __func__, i); 169 if (i == CONFIG_BCM_SF2_ETH_DEFAULT_PORT) { 170 pr_err("%s: No default port %d!\n", __func__, i); 171 return -1; 172 } 173 } 174 } 175 176 /* Set MAC speed using default port */ 177 i = CONFIG_BCM_SF2_ETH_DEFAULT_PORT; 178 debug("PHY %d: speed:%d, duplex:%d, link:%d\n", i, 179 eth->port[i]->speed, eth->port[i]->duplex, eth->port[i]->link); 180 eth->set_mac_speed(eth->port[i]->speed, eth->port[i]->duplex); 181 182 debug("Enable Ethernet Done.\n"); 183 184 return 0; 185 } 186 187 static void bcm_sf2_eth_close(struct eth_device *dev) 188 { 189 struct eth_info *eth = (struct eth_info *)(dev->priv); 190 struct eth_dma *dma = &(eth->dma); 191 192 /* disable DMA */ 193 dma->disable_dma(dma, MAC_DMA_RX); 194 dma->disable_dma(dma, MAC_DMA_TX); 195 196 eth->disable_mac(); 197 } 198 199 int bcm_sf2_eth_register(bd_t *bis, u8 dev_num) 200 { 201 struct eth_device *dev; 202 struct eth_info *eth; 203 int rc; 204 205 dev = (struct eth_device *)malloc(sizeof(struct eth_device)); 206 if (dev == NULL) { 207 pr_err("%s: Not enough memory!\n", __func__); 208 return -1; 209 } 210 211 eth = (struct eth_info *)malloc(sizeof(struct eth_info)); 212 if (eth == NULL) { 213 pr_err("%s: Not enough memory!\n", __func__); 214 return -1; 215 } 216 217 printf(banner); 218 219 memset(dev, 0, sizeof(*dev)); 220 sprintf(dev->name, "%s_%s-%hu", BCM_SF2_ETH_DEV_NAME, 221 BCM_SF2_ETH_MAC_NAME, dev_num); 222 223 dev->priv = (void *)eth; 224 dev->iobase = 0; 225 226 dev->init = bcm_sf2_eth_open; 227 dev->halt = bcm_sf2_eth_close; 228 dev->send = bcm_sf2_eth_send; 229 dev->recv = bcm_sf2_eth_receive; 230 dev->write_hwaddr = bcm_sf2_eth_write_hwaddr; 231 232 #ifdef CONFIG_BCM_SF2_ETH_GMAC 233 if (gmac_add(dev)) { 234 free(eth); 235 free(dev); 236 pr_err("%s: Adding GMAC failed!\n", __func__); 237 return -1; 238 } 239 #else 240 #error "bcm_sf2_eth: NEED to register a MAC!" 241 #endif 242 243 eth_register(dev); 244 245 #ifdef CONFIG_CMD_MII 246 int retval; 247 struct mii_dev *mdiodev = mdio_alloc(); 248 249 if (!mdiodev) 250 return -ENOMEM; 251 strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN); 252 mdiodev->read = eth->miiphy_read; 253 mdiodev->write = eth->miiphy_write; 254 255 retval = mdio_register(mdiodev); 256 if (retval < 0) 257 return retval; 258 #endif 259 260 /* Initialization */ 261 debug("Ethernet initialization ..."); 262 263 rc = bcm_sf2_eth_init(dev); 264 if (rc != 0) { 265 pr_err("%s: configuration failed!\n", __func__); 266 return -1; 267 } 268 269 printf("Basic ethernet functionality initialized\n"); 270 271 return 0; 272 } 273