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