uboot/drivers/net/bcm-sf2-eth.c
<<
>>
Prefs
   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
  29static const char banner[] =
  30        BCM_NET_MODULE_DESCRIPTION " " BCM_NET_MODULE_VERSION "\n";
  31
  32static 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                             -1, 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
  71static 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
 102static 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
 137static 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
 148static 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
 187static 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
 199int 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