uboot/drivers/net/smc911x.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * SMSC LAN9[12]1[567] Network driver
   4 *
   5 * (c) 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
   6 */
   7
   8#include <common.h>
   9#include <command.h>
  10#include <malloc.h>
  11#include <net.h>
  12#include <miiphy.h>
  13#include <linux/io.h>
  14#include <linux/delay.h>
  15#include <linux/types.h>
  16
  17#include "smc911x.h"
  18
  19struct chip_id {
  20        u16 id;
  21        char *name;
  22};
  23
  24struct smc911x_priv {
  25#ifndef CONFIG_DM_ETH
  26        struct eth_device       dev;
  27#endif
  28        phys_addr_t             iobase;
  29        const struct chip_id    *chipid;
  30        unsigned char           enetaddr[6];
  31        bool                    use_32_bit_io;
  32};
  33
  34static const struct chip_id chip_ids[] =  {
  35        { CHIP_89218, "LAN89218" },
  36        { CHIP_9115, "LAN9115" },
  37        { CHIP_9116, "LAN9116" },
  38        { CHIP_9117, "LAN9117" },
  39        { CHIP_9118, "LAN9118" },
  40        { CHIP_9211, "LAN9211" },
  41        { CHIP_9215, "LAN9215" },
  42        { CHIP_9216, "LAN9216" },
  43        { CHIP_9217, "LAN9217" },
  44        { CHIP_9218, "LAN9218" },
  45        { CHIP_9220, "LAN9220" },
  46        { CHIP_9221, "LAN9221" },
  47        { 0, NULL },
  48};
  49
  50#define DRIVERNAME "smc911x"
  51
  52static u32 smc911x_reg_read(struct smc911x_priv *priv, u32 offset)
  53{
  54        if (priv->use_32_bit_io)
  55                return readl(priv->iobase + offset);
  56
  57        return (readw(priv->iobase + offset) & 0xffff) |
  58               (readw(priv->iobase + offset + 2) << 16);
  59}
  60
  61static void smc911x_reg_write(struct smc911x_priv *priv, u32 offset, u32 val)
  62{
  63        if (priv->use_32_bit_io) {
  64                writel(val, priv->iobase + offset);
  65        } else {
  66                writew(val & 0xffff, priv->iobase + offset);
  67                writew(val >> 16, priv->iobase + offset + 2);
  68        }
  69}
  70
  71static u32 smc911x_get_mac_csr(struct smc911x_priv *priv, u8 reg)
  72{
  73        while (smc911x_reg_read(priv, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
  74                ;
  75        smc911x_reg_write(priv, MAC_CSR_CMD,
  76                        MAC_CSR_CMD_CSR_BUSY | MAC_CSR_CMD_R_NOT_W | reg);
  77        while (smc911x_reg_read(priv, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
  78                ;
  79
  80        return smc911x_reg_read(priv, MAC_CSR_DATA);
  81}
  82
  83static void smc911x_set_mac_csr(struct smc911x_priv *priv, u8 reg, u32 data)
  84{
  85        while (smc911x_reg_read(priv, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
  86                ;
  87        smc911x_reg_write(priv, MAC_CSR_DATA, data);
  88        smc911x_reg_write(priv, MAC_CSR_CMD, MAC_CSR_CMD_CSR_BUSY | reg);
  89        while (smc911x_reg_read(priv, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
  90                ;
  91}
  92
  93static int smc911x_detect_chip(struct smc911x_priv *priv)
  94{
  95        unsigned long val, i;
  96
  97        val = smc911x_reg_read(priv, BYTE_TEST);
  98        if (val == 0xffffffff) {
  99                /* Special case -- no chip present */
 100                return -1;
 101        } else if (val != 0x87654321) {
 102                printf(DRIVERNAME ": Invalid chip endian 0x%08lx\n", val);
 103                return -1;
 104        }
 105
 106        val = smc911x_reg_read(priv, ID_REV) >> 16;
 107        for (i = 0; chip_ids[i].id != 0; i++) {
 108                if (chip_ids[i].id == val) break;
 109        }
 110        if (!chip_ids[i].id) {
 111                printf(DRIVERNAME ": Unknown chip ID %04lx\n", val);
 112                return -1;
 113        }
 114
 115        priv->chipid = &chip_ids[i];
 116
 117        return 0;
 118}
 119
 120static void smc911x_reset(struct smc911x_priv *priv)
 121{
 122        int timeout;
 123
 124        /*
 125         *  Take out of PM setting first
 126         *  Device is already wake up if PMT_CTRL_READY bit is set
 127         */
 128        if ((smc911x_reg_read(priv, PMT_CTRL) & PMT_CTRL_READY) == 0) {
 129                /* Write to the bytetest will take out of powerdown */
 130                smc911x_reg_write(priv, BYTE_TEST, 0x0);
 131
 132                timeout = 10;
 133
 134                while (timeout-- &&
 135                        !(smc911x_reg_read(priv, PMT_CTRL) & PMT_CTRL_READY))
 136                        udelay(10);
 137                if (timeout < 0) {
 138                        printf(DRIVERNAME
 139                                ": timeout waiting for PM restore\n");
 140                        return;
 141                }
 142        }
 143
 144        /* Disable interrupts */
 145        smc911x_reg_write(priv, INT_EN, 0);
 146
 147        smc911x_reg_write(priv, HW_CFG, HW_CFG_SRST);
 148
 149        timeout = 1000;
 150        while (timeout-- && smc911x_reg_read(priv, E2P_CMD) & E2P_CMD_EPC_BUSY)
 151                udelay(10);
 152
 153        if (timeout < 0) {
 154                printf(DRIVERNAME ": reset timeout\n");
 155                return;
 156        }
 157
 158        /* Reset the FIFO level and flow control settings */
 159        smc911x_set_mac_csr(priv, FLOW, FLOW_FCPT | FLOW_FCEN);
 160        smc911x_reg_write(priv, AFC_CFG, 0x0050287F);
 161
 162        /* Set to LED outputs */
 163        smc911x_reg_write(priv, GPIO_CFG, 0x70070000);
 164}
 165
 166static void smc911x_handle_mac_address(struct smc911x_priv *priv)
 167{
 168        unsigned long addrh, addrl;
 169        unsigned char *m = priv->enetaddr;
 170
 171        addrl = m[0] | (m[1] << 8) | (m[2] << 16) | (m[3] << 24);
 172        addrh = m[4] | (m[5] << 8);
 173        smc911x_set_mac_csr(priv, ADDRL, addrl);
 174        smc911x_set_mac_csr(priv, ADDRH, addrh);
 175
 176        printf(DRIVERNAME ": MAC %pM\n", m);
 177}
 178
 179static bool smc911x_read_mac_address(struct smc911x_priv *priv)
 180{
 181        u32 addrh, addrl;
 182
 183        /* address is obtained from optional eeprom */
 184        addrh = smc911x_get_mac_csr(priv, ADDRH);
 185        addrl = smc911x_get_mac_csr(priv, ADDRL);
 186        if (addrl == 0xffffffff && addrh == 0x0000ffff)
 187                return false;
 188
 189        priv->enetaddr[0] = addrl;
 190        priv->enetaddr[1] = addrl >>  8;
 191        priv->enetaddr[2] = addrl >> 16;
 192        priv->enetaddr[3] = addrl >> 24;
 193        priv->enetaddr[4] = addrh;
 194        priv->enetaddr[5] = addrh >> 8;
 195
 196        return true;
 197}
 198
 199static int smc911x_eth_phy_read(struct smc911x_priv *priv,
 200                                u8 phy, u8 reg, u16 *val)
 201{
 202        while (smc911x_get_mac_csr(priv, MII_ACC) & MII_ACC_MII_BUSY)
 203                ;
 204
 205        smc911x_set_mac_csr(priv, MII_ACC, phy << 11 | reg << 6 |
 206                                MII_ACC_MII_BUSY);
 207
 208        while (smc911x_get_mac_csr(priv, MII_ACC) & MII_ACC_MII_BUSY)
 209                ;
 210
 211        *val = smc911x_get_mac_csr(priv, MII_DATA);
 212
 213        return 0;
 214}
 215
 216static int smc911x_eth_phy_write(struct smc911x_priv *priv,
 217                                u8 phy, u8 reg, u16  val)
 218{
 219        while (smc911x_get_mac_csr(priv, MII_ACC) & MII_ACC_MII_BUSY)
 220                ;
 221
 222        smc911x_set_mac_csr(priv, MII_DATA, val);
 223        smc911x_set_mac_csr(priv, MII_ACC,
 224                phy << 11 | reg << 6 | MII_ACC_MII_BUSY | MII_ACC_MII_WRITE);
 225
 226        while (smc911x_get_mac_csr(priv, MII_ACC) & MII_ACC_MII_BUSY)
 227                ;
 228        return 0;
 229}
 230
 231static int smc911x_phy_reset(struct smc911x_priv *priv)
 232{
 233        u32 reg;
 234
 235        reg = smc911x_reg_read(priv, PMT_CTRL);
 236        reg &= ~0xfffff030;
 237        reg |= PMT_CTRL_PHY_RST;
 238        smc911x_reg_write(priv, PMT_CTRL, reg);
 239
 240        mdelay(100);
 241
 242        return 0;
 243}
 244
 245static void smc911x_phy_configure(struct smc911x_priv *priv)
 246{
 247        int timeout;
 248        u16 status;
 249
 250        smc911x_phy_reset(priv);
 251
 252        smc911x_eth_phy_write(priv, 1, MII_BMCR, BMCR_RESET);
 253        mdelay(1);
 254        smc911x_eth_phy_write(priv, 1, MII_ADVERTISE, 0x01e1);
 255        smc911x_eth_phy_write(priv, 1, MII_BMCR, BMCR_ANENABLE |
 256                                BMCR_ANRESTART);
 257
 258        timeout = 5000;
 259        do {
 260                mdelay(1);
 261                if ((timeout--) == 0)
 262                        goto err_out;
 263
 264                if (smc911x_eth_phy_read(priv, 1, MII_BMSR, &status) != 0)
 265                        goto err_out;
 266        } while (!(status & BMSR_LSTATUS));
 267
 268        printf(DRIVERNAME ": phy initialized\n");
 269
 270        return;
 271
 272err_out:
 273        printf(DRIVERNAME ": autonegotiation timed out\n");
 274}
 275
 276static void smc911x_enable(struct smc911x_priv *priv)
 277{
 278        /* Enable TX */
 279        smc911x_reg_write(priv, HW_CFG, 8 << 16 | HW_CFG_SF);
 280
 281        smc911x_reg_write(priv, GPT_CFG, GPT_CFG_TIMER_EN | 10000);
 282
 283        smc911x_reg_write(priv, TX_CFG, TX_CFG_TX_ON);
 284
 285        /* no padding to start of packets */
 286        smc911x_reg_write(priv, RX_CFG, 0);
 287
 288        smc911x_set_mac_csr(priv, MAC_CR, MAC_CR_TXEN | MAC_CR_RXEN |
 289                                MAC_CR_HBDIS);
 290}
 291
 292static int smc911x_init_common(struct smc911x_priv *priv)
 293{
 294        const struct chip_id *id = priv->chipid;
 295
 296        printf(DRIVERNAME ": detected %s controller\n", id->name);
 297
 298        smc911x_reset(priv);
 299
 300        /* Configure the PHY, initialize the link state */
 301        smc911x_phy_configure(priv);
 302
 303        smc911x_handle_mac_address(priv);
 304
 305        /* Turn on Tx + Rx */
 306        smc911x_enable(priv);
 307
 308        return 0;
 309}
 310
 311static int smc911x_send_common(struct smc911x_priv *priv,
 312                               void *packet, int length)
 313{
 314        u32 *data = (u32*)packet;
 315        u32 tmplen;
 316        u32 status;
 317
 318        smc911x_reg_write(priv, TX_DATA_FIFO, TX_CMD_A_INT_FIRST_SEG |
 319                                TX_CMD_A_INT_LAST_SEG | length);
 320        smc911x_reg_write(priv, TX_DATA_FIFO, length);
 321
 322        tmplen = (length + 3) / 4;
 323
 324        while (tmplen--)
 325                smc911x_reg_write(priv, TX_DATA_FIFO, *data++);
 326
 327        /* wait for transmission */
 328        while (!((smc911x_reg_read(priv, TX_FIFO_INF) &
 329                                        TX_FIFO_INF_TSUSED) >> 16));
 330
 331        /* get status. Ignore 'no carrier' error, it has no meaning for
 332         * full duplex operation
 333         */
 334        status = smc911x_reg_read(priv, TX_STATUS_FIFO) &
 335                        (TX_STS_LOC | TX_STS_LATE_COLL | TX_STS_MANY_COLL |
 336                        TX_STS_MANY_DEFER | TX_STS_UNDERRUN);
 337
 338        if (!status)
 339                return 0;
 340
 341        printf(DRIVERNAME ": failed to send packet: %s%s%s%s%s\n",
 342                status & TX_STS_LOC ? "TX_STS_LOC " : "",
 343                status & TX_STS_LATE_COLL ? "TX_STS_LATE_COLL " : "",
 344                status & TX_STS_MANY_COLL ? "TX_STS_MANY_COLL " : "",
 345                status & TX_STS_MANY_DEFER ? "TX_STS_MANY_DEFER " : "",
 346                status & TX_STS_UNDERRUN ? "TX_STS_UNDERRUN" : "");
 347
 348        return -1;
 349}
 350
 351static void smc911x_halt_common(struct smc911x_priv *priv)
 352{
 353        smc911x_reset(priv);
 354        smc911x_handle_mac_address(priv);
 355}
 356
 357static int smc911x_recv_common(struct smc911x_priv *priv, u32 *data)
 358{
 359        u32 pktlen, tmplen;
 360        u32 status;
 361
 362        status = smc911x_reg_read(priv, RX_FIFO_INF);
 363        if (!(status & RX_FIFO_INF_RXSUSED))
 364                return 0;
 365
 366        status = smc911x_reg_read(priv, RX_STATUS_FIFO);
 367        pktlen = (status & RX_STS_PKT_LEN) >> 16;
 368
 369        smc911x_reg_write(priv, RX_CFG, 0);
 370
 371        tmplen = (pktlen + 3) / 4;
 372        while (tmplen--)
 373                *data++ = smc911x_reg_read(priv, RX_DATA_FIFO);
 374
 375        if (status & RX_STS_ES) {
 376                printf(DRIVERNAME
 377                        ": dropped bad packet. Status: 0x%08x\n",
 378                        status);
 379                return 0;
 380        }
 381
 382        return pktlen;
 383}
 384
 385#ifndef CONFIG_DM_ETH
 386
 387#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
 388/* wrapper for smc911x_eth_phy_read */
 389static int smc911x_miiphy_read(struct mii_dev *bus, int phy, int devad,
 390                               int reg)
 391{
 392        struct eth_device *dev = eth_get_dev_by_name(bus->name);
 393        struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev);
 394        u16 val = 0;
 395        int ret;
 396
 397        if (!dev || !priv)
 398                return -ENODEV;
 399
 400        ret = smc911x_eth_phy_read(priv, phy, reg, &val);
 401        if (ret < 0)
 402                return ret;
 403
 404        return val;
 405}
 406
 407/* wrapper for smc911x_eth_phy_write */
 408static int smc911x_miiphy_write(struct mii_dev *bus, int phy, int devad,
 409                                int reg, u16 val)
 410{
 411        struct eth_device *dev = eth_get_dev_by_name(bus->name);
 412        struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev);
 413
 414        if (!dev || !priv)
 415                return -ENODEV;
 416
 417        return smc911x_eth_phy_write(priv, phy, reg, val);
 418}
 419
 420static int smc911x_initialize_mii(struct smc911x_priv *priv)
 421{
 422        struct mii_dev *mdiodev = mdio_alloc();
 423        int ret;
 424
 425        if (!mdiodev)
 426                return -ENOMEM;
 427
 428        strlcpy(mdiodev->name, priv->dev.name, MDIO_NAME_LEN);
 429        mdiodev->read = smc911x_miiphy_read;
 430        mdiodev->write = smc911x_miiphy_write;
 431
 432        ret = mdio_register(mdiodev);
 433        if (ret < 0) {
 434                mdio_free(mdiodev);
 435                return ret;
 436        }
 437
 438        return 0;
 439}
 440#else
 441static int smc911x_initialize_mii(struct smc911x_priv *priv)
 442{
 443        return 0;
 444}
 445#endif
 446
 447static int smc911x_init(struct eth_device *dev, struct bd_info *bd)
 448{
 449        struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev);
 450
 451        return smc911x_init_common(priv);
 452}
 453
 454static void smc911x_halt(struct eth_device *dev)
 455{
 456        struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev);
 457
 458        smc911x_halt_common(priv);
 459}
 460
 461static int smc911x_send(struct eth_device *dev, void *packet, int length)
 462{
 463        struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev);
 464
 465        return smc911x_send_common(priv, packet, length);
 466}
 467
 468static int smc911x_recv(struct eth_device *dev)
 469{
 470        struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev);
 471        u32 *data = (u32 *)net_rx_packets[0];
 472        int ret;
 473
 474        ret = smc911x_recv_common(priv, data);
 475        if (ret)
 476                net_process_received_packet(net_rx_packets[0], ret);
 477
 478        return ret;
 479}
 480
 481int smc911x_initialize(u8 dev_num, phys_addr_t base_addr)
 482{
 483        struct smc911x_priv *priv;
 484        int ret;
 485
 486        priv = calloc(1, sizeof(*priv));
 487        if (!priv)
 488                return -ENOMEM;
 489
 490        priv->iobase = base_addr;
 491        priv->dev.iobase = base_addr;
 492
 493        priv->use_32_bit_io = CONFIG_IS_ENABLED(SMC911X_32_BIT);
 494
 495        /* Try to detect chip. Will fail if not present. */
 496        ret = smc911x_detect_chip(priv);
 497        if (ret) {
 498                ret = 0;        /* Card not detected is not an error */
 499                goto err_detect;
 500        }
 501
 502        if (smc911x_read_mac_address(priv))
 503                memcpy(priv->dev.enetaddr, priv->enetaddr, 6);
 504
 505        priv->dev.init = smc911x_init;
 506        priv->dev.halt = smc911x_halt;
 507        priv->dev.send = smc911x_send;
 508        priv->dev.recv = smc911x_recv;
 509        sprintf(priv->dev.name, "%s-%hu", DRIVERNAME, dev_num);
 510
 511        eth_register(&priv->dev);
 512
 513        ret = smc911x_initialize_mii(priv);
 514        if (ret)
 515                goto err_mii;
 516
 517        return 1;
 518
 519err_mii:
 520        eth_unregister(&priv->dev);
 521err_detect:
 522        free(priv);
 523        return ret;
 524}
 525
 526#else   /* ifdef CONFIG_DM_ETH */
 527
 528static int smc911x_start(struct udevice *dev)
 529{
 530        struct eth_pdata *plat = dev_get_plat(dev);
 531        struct smc911x_priv *priv = dev_get_priv(dev);
 532
 533        memcpy(priv->enetaddr, plat->enetaddr, sizeof(plat->enetaddr));
 534
 535        return smc911x_init_common(priv);
 536}
 537
 538static void smc911x_stop(struct udevice *dev)
 539{
 540        struct smc911x_priv *priv = dev_get_priv(dev);
 541
 542        smc911x_halt_common(priv);
 543}
 544
 545static int smc911x_send(struct udevice *dev, void *packet, int length)
 546{
 547        struct smc911x_priv *priv = dev_get_priv(dev);
 548        int ret;
 549
 550        ret = smc911x_send_common(priv, packet, length);
 551
 552        return ret ? 0 : -ETIMEDOUT;
 553}
 554
 555static int smc911x_recv(struct udevice *dev, int flags, uchar **packetp)
 556{
 557        struct smc911x_priv *priv = dev_get_priv(dev);
 558        u32 *data = (u32 *)net_rx_packets[0];
 559        int ret;
 560
 561        ret = smc911x_recv_common(priv, data);
 562        if (ret)
 563                *packetp = (void *)data;
 564
 565        return ret ? ret : -EAGAIN;
 566}
 567
 568static int smc911x_read_rom_hwaddr(struct udevice *dev)
 569{
 570        struct smc911x_priv *priv = dev_get_priv(dev);
 571        struct eth_pdata *pdata = dev_get_plat(dev);
 572
 573        if (!smc911x_read_mac_address(priv))
 574                return -ENODEV;
 575
 576        memcpy(pdata->enetaddr, priv->enetaddr, sizeof(pdata->enetaddr));
 577
 578        return 0;
 579}
 580
 581static int smc911x_bind(struct udevice *dev)
 582{
 583        return device_set_name(dev, dev->name);
 584}
 585
 586static int smc911x_probe(struct udevice *dev)
 587{
 588        struct smc911x_priv *priv = dev_get_priv(dev);
 589        int ret;
 590
 591        /* Try to detect chip. Will fail if not present. */
 592        ret = smc911x_detect_chip(priv);
 593        if (ret)
 594                return ret;
 595
 596        smc911x_read_rom_hwaddr(dev);
 597
 598        return 0;
 599}
 600
 601static int smc911x_of_to_plat(struct udevice *dev)
 602{
 603        struct smc911x_priv *priv = dev_get_priv(dev);
 604        struct eth_pdata *pdata = dev_get_plat(dev);
 605        u32 io_width;
 606        int ret;
 607
 608        pdata->iobase = dev_read_addr(dev);
 609        priv->iobase = pdata->iobase;
 610
 611        ret = dev_read_u32(dev, "reg-io-width", &io_width);
 612        if (!ret)
 613                priv->use_32_bit_io = (io_width == 4);
 614        else
 615                priv->use_32_bit_io = CONFIG_IS_ENABLED(SMC911X_32_BIT);
 616
 617        return 0;
 618}
 619
 620static const struct eth_ops smc911x_ops = {
 621        .start  = smc911x_start,
 622        .send   = smc911x_send,
 623        .recv   = smc911x_recv,
 624        .stop   = smc911x_stop,
 625        .read_rom_hwaddr = smc911x_read_rom_hwaddr,
 626};
 627
 628static const struct udevice_id smc911x_ids[] = {
 629        { .compatible = "smsc,lan9115" },
 630        { }
 631};
 632
 633U_BOOT_DRIVER(smc911x) = {
 634        .name           = "eth_smc911x",
 635        .id             = UCLASS_ETH,
 636        .of_match       = smc911x_ids,
 637        .bind           = smc911x_bind,
 638        .of_to_plat = smc911x_of_to_plat,
 639        .probe          = smc911x_probe,
 640        .ops            = &smc911x_ops,
 641        .priv_auto      = sizeof(struct smc911x_priv),
 642        .plat_auto      = sizeof(struct eth_pdata),
 643        .flags          = DM_FLAG_ALLOC_PRIV_DMA,
 644};
 645#endif
 646