uboot/drivers/net/bcm-sf2-eth.c
<<
>>
Prefs
   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
  30static const char banner[] =
  31        BCM_NET_MODULE_DESCRIPTION " " BCM_NET_MODULE_VERSION "\n";
  32
  33static 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
  72static 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
 103static 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
 138static 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
 149static 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
 188static 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
 200int 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