uboot/drivers/usb/eth/lan75xx.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (c) 2017 Microchip Technology Inc. All rights reserved.
   4 */
   5
   6#include <dm.h>
   7#include <log.h>
   8#include <usb.h>
   9#include <linux/bitops.h>
  10#include <linux/mii.h>
  11#include "usb_ether.h"
  12#include "lan7x.h"
  13
  14/* LAN75xx specific register/bit defines */
  15#define LAN75XX_HW_CFG_BIR              BIT(7)
  16
  17#define LAN75XX_BURST_CAP               0x034
  18
  19#define LAN75XX_BULK_IN_DLY             0x03C
  20
  21#define LAN75XX_RFE_CTL                 0x060
  22
  23#define LAN75XX_FCT_RX_CTL              0x090
  24
  25#define LAN75XX_FCT_TX_CTL              0x094
  26
  27#define LAN75XX_FCT_RX_FIFO_END         0x098
  28
  29#define LAN75XX_FCT_TX_FIFO_END         0x09C
  30
  31#define LAN75XX_FCT_FLOW                0x0A0
  32
  33/* MAC ADDRESS PERFECT FILTER For LAN75xx */
  34#define LAN75XX_ADDR_FILTX              0x300
  35#define LAN75XX_ADDR_FILTX_FB_VALID     BIT(31)
  36
  37/*
  38 * Lan75xx infrastructure commands
  39 */
  40static int lan75xx_phy_gig_workaround(struct usb_device *udev,
  41                                      struct ueth_data *dev)
  42{
  43        int ret = 0;
  44
  45        /* Only internal phy */
  46        /* Set the phy in Gig loopback */
  47        lan7x_mdio_write(udev, dev->phy_id, MII_BMCR,
  48                         (BMCR_LOOPBACK | BMCR_SPEED1000));
  49
  50        /* Wait for the link up */
  51        ret = lan7x_mdio_wait_for_bit(udev, "BMSR_LSTATUS",
  52                                      dev->phy_id, MII_BMSR, BMSR_LSTATUS,
  53                                      true, PHY_CONNECT_TIMEOUT_MS, 1);
  54        if (ret)
  55                return ret;
  56
  57        /* phy reset */
  58        return lan7x_pmt_phy_reset(udev, dev);
  59}
  60
  61static int lan75xx_update_flowcontrol(struct usb_device *udev,
  62                                      struct ueth_data *dev)
  63{
  64        uint32_t flow = 0, fct_flow = 0;
  65        int ret;
  66
  67        ret = lan7x_update_flowcontrol(udev, dev, &flow, &fct_flow);
  68        if (ret)
  69                return ret;
  70
  71        ret = lan7x_write_reg(udev, LAN75XX_FCT_FLOW, fct_flow);
  72        if (ret)
  73                return ret;
  74        return lan7x_write_reg(udev, FLOW, flow);
  75}
  76
  77static int lan75xx_set_receive_filter(struct usb_device *udev)
  78{
  79        /* No multicast in u-boot */
  80        return lan7x_write_reg(udev, LAN75XX_RFE_CTL,
  81                               RFE_CTL_BCAST_EN | RFE_CTL_DA_PERFECT);
  82}
  83
  84/* starts the TX path */
  85static void lan75xx_start_tx_path(struct usb_device *udev)
  86{
  87        /* Enable Tx at MAC */
  88        lan7x_write_reg(udev, MAC_TX, MAC_TX_TXEN);
  89
  90        /* Enable Tx at SCSRs */
  91        lan7x_write_reg(udev, LAN75XX_FCT_TX_CTL, FCT_TX_CTL_EN);
  92}
  93
  94/* Starts the Receive path */
  95static void lan75xx_start_rx_path(struct usb_device *udev)
  96{
  97        /* Enable Rx at MAC */
  98        lan7x_write_reg(udev, MAC_RX,
  99                        LAN7X_MAC_RX_MAX_SIZE_DEFAULT |
 100                        MAC_RX_FCS_STRIP | MAC_RX_RXEN);
 101
 102        /* Enable Rx at SCSRs */
 103        lan7x_write_reg(udev, LAN75XX_FCT_RX_CTL, FCT_RX_CTL_EN);
 104}
 105
 106static int lan75xx_basic_reset(struct usb_device *udev,
 107                               struct ueth_data *dev,
 108                               struct lan7x_private *priv)
 109{
 110        int ret;
 111        u32 val;
 112
 113        ret = lan7x_basic_reset(udev, dev);
 114        if (ret)
 115                return ret;
 116
 117        /* Keep the chip ID */
 118        ret = lan7x_read_reg(udev, ID_REV, &val);
 119        if (ret)
 120                return ret;
 121        debug("LAN75xx ID_REV = 0x%08x\n", val);
 122
 123        priv->chipid = (val & ID_REV_CHIP_ID_MASK) >> 16;
 124
 125        /* Respond to the IN token with a NAK */
 126        ret = lan7x_read_reg(udev, HW_CFG, &val);
 127        if (ret)
 128                return ret;
 129        val |= LAN75XX_HW_CFG_BIR;
 130        return lan7x_write_reg(udev, HW_CFG, val);
 131}
 132
 133int lan75xx_write_hwaddr(struct udevice *dev)
 134{
 135        struct usb_device *udev = dev_get_parent_priv(dev);
 136        struct eth_pdata *pdata = dev_get_plat(dev);
 137        unsigned char *enetaddr = pdata->enetaddr;
 138        u32 addr_lo = get_unaligned_le32(&enetaddr[0]);
 139        u32 addr_hi = (u32)get_unaligned_le16(&enetaddr[4]);
 140        int ret;
 141
 142        /* set hardware address */
 143        ret = lan7x_write_reg(udev, RX_ADDRL, addr_lo);
 144        if (ret)
 145                return ret;
 146
 147        ret = lan7x_write_reg(udev, RX_ADDRH, addr_hi);
 148        if (ret)
 149                return ret;
 150
 151        ret = lan7x_write_reg(udev, LAN75XX_ADDR_FILTX + 4, addr_lo);
 152        if (ret)
 153                return ret;
 154
 155        addr_hi |= LAN75XX_ADDR_FILTX_FB_VALID;
 156        ret = lan7x_write_reg(udev, LAN75XX_ADDR_FILTX, addr_hi);
 157        if (ret)
 158                return ret;
 159
 160        debug("MAC addr %pM written\n", enetaddr);
 161
 162        return 0;
 163}
 164
 165static int lan75xx_eth_start(struct udevice *dev)
 166{
 167        struct usb_device *udev = dev_get_parent_priv(dev);
 168        struct lan7x_private *priv = dev_get_priv(dev);
 169        struct ueth_data *ueth = &priv->ueth;
 170        int ret;
 171        u32 write_buf;
 172
 173        /* Reset and read Mac addr were done in probe() */
 174        ret = lan75xx_write_hwaddr(dev);
 175        if (ret)
 176                return ret;
 177
 178        ret = lan7x_write_reg(udev, INT_STS, 0xFFFFFFFF);
 179        if (ret)
 180                return ret;
 181
 182        ret = lan7x_write_reg(udev, LAN75XX_BURST_CAP, 0);
 183        if (ret)
 184                return ret;
 185
 186        ret = lan7x_write_reg(udev, LAN75XX_BULK_IN_DLY, DEFAULT_BULK_IN_DELAY);
 187        if (ret)
 188                return ret;
 189
 190        /* set FIFO sizes */
 191        write_buf = (MAX_RX_FIFO_SIZE - 512) / 512;
 192        ret = lan7x_write_reg(udev, LAN75XX_FCT_RX_FIFO_END, write_buf);
 193        if (ret)
 194                return ret;
 195
 196        write_buf = (MAX_TX_FIFO_SIZE - 512) / 512;
 197        ret = lan7x_write_reg(udev, LAN75XX_FCT_TX_FIFO_END, write_buf);
 198        if (ret)
 199                return ret;
 200
 201        /* Init Tx */
 202        ret = lan7x_write_reg(udev, FLOW, 0);
 203        if (ret)
 204                return ret;
 205
 206        /* Init Rx. Set Vlan, keep default for VLAN on 75xx */
 207        ret = lan75xx_set_receive_filter(udev);
 208        if (ret)
 209                return ret;
 210
 211        /* phy workaround for gig link */
 212        ret = lan75xx_phy_gig_workaround(udev, ueth);
 213        if (ret)
 214                return ret;
 215
 216        /* Init PHY, autonego, and link */
 217        ret = lan7x_eth_phylib_connect(dev, &priv->ueth);
 218        if (ret)
 219                return ret;
 220        ret = lan7x_eth_phylib_config_start(dev);
 221        if (ret)
 222                return ret;
 223
 224        /*
 225         * MAC_CR has to be set after PHY init.
 226         * MAC will auto detect the PHY speed.
 227         */
 228        ret = lan7x_read_reg(udev, MAC_CR, &write_buf);
 229        if (ret)
 230                return ret;
 231        write_buf |= MAC_CR_AUTO_DUPLEX | MAC_CR_AUTO_SPEED | MAC_CR_ADP;
 232        ret = lan7x_write_reg(udev, MAC_CR, write_buf);
 233        if (ret)
 234                return ret;
 235
 236        lan75xx_start_tx_path(udev);
 237        lan75xx_start_rx_path(udev);
 238
 239        return lan75xx_update_flowcontrol(udev, ueth);
 240}
 241
 242int lan75xx_read_rom_hwaddr(struct udevice *dev)
 243{
 244        struct usb_device *udev = dev_get_parent_priv(dev);
 245        struct eth_pdata *pdata = dev_get_plat(dev);
 246        int ret;
 247
 248        /*
 249         * Refer to the doc/README.enetaddr and doc/README.usb for
 250         * the U-Boot MAC address policy
 251         */
 252        ret = lan7x_read_eeprom_mac(pdata->enetaddr, udev);
 253        if (ret)
 254                memset(pdata->enetaddr, 0, 6);
 255
 256        return 0;
 257}
 258
 259static int lan75xx_eth_probe(struct udevice *dev)
 260{
 261        struct usb_device *udev = dev_get_parent_priv(dev);
 262        struct lan7x_private *priv = dev_get_priv(dev);
 263        struct ueth_data *ueth = &priv->ueth;
 264        struct eth_pdata *pdata = dev_get_plat(dev);
 265        int ret;
 266
 267        /* Do a reset in order to get the MAC address from HW */
 268        if (lan75xx_basic_reset(udev, ueth, priv))
 269                return 0;
 270
 271        /* Get the MAC address */
 272        /*
 273         * We must set the eth->enetaddr from HW because the upper layer
 274         * will force to use the environmental var (usbethaddr) or random if
 275         * there is no valid MAC address in eth->enetaddr.
 276         *
 277         * Refer to the doc/README.enetaddr and doc/README.usb for
 278         * the U-Boot MAC address policy
 279         */
 280        lan7x_read_eeprom_mac(pdata->enetaddr, udev);
 281        /* Do not return 0 for not finding MAC addr in HW */
 282
 283        ret = usb_ether_register(dev, ueth, RX_URB_SIZE);
 284        if (ret)
 285                return ret;
 286
 287        /* Register phylib */
 288        return lan7x_phylib_register(dev);
 289}
 290
 291static const struct eth_ops lan75xx_eth_ops = {
 292        .start  = lan75xx_eth_start,
 293        .send   = lan7x_eth_send,
 294        .recv   = lan7x_eth_recv,
 295        .free_pkt = lan7x_free_pkt,
 296        .stop   = lan7x_eth_stop,
 297        .write_hwaddr = lan75xx_write_hwaddr,
 298        .read_rom_hwaddr = lan75xx_read_rom_hwaddr,
 299};
 300
 301U_BOOT_DRIVER(lan75xx_eth) = {
 302        .name   = "lan75xx_eth",
 303        .id     = UCLASS_ETH,
 304        .probe  = lan75xx_eth_probe,
 305        .remove = lan7x_eth_remove,
 306        .ops    = &lan75xx_eth_ops,
 307        .priv_auto      = sizeof(struct lan7x_private),
 308        .plat_auto      = sizeof(struct eth_pdata),
 309};
 310
 311static const struct usb_device_id lan75xx_eth_id_table[] = {
 312        { USB_DEVICE(0x0424, 0x7500) }, /* LAN7500 USB Ethernet */
 313        { }             /* Terminating entry */
 314};
 315
 316U_BOOT_USB_DEVICE(lan75xx_eth, lan75xx_eth_id_table);
 317