uboot/drivers/net/designware.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2010
   3 * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
   4 *
   5 * SPDX-License-Identifier:     GPL-2.0+
   6 */
   7
   8/*
   9 * Designware ethernet IP driver for u-boot
  10 */
  11
  12#include <common.h>
  13#include <miiphy.h>
  14#include <malloc.h>
  15#include <linux/compiler.h>
  16#include <linux/err.h>
  17#include <asm/io.h>
  18#include "designware.h"
  19
  20static int configure_phy(struct eth_device *dev);
  21
  22static void tx_descs_init(struct eth_device *dev)
  23{
  24        struct dw_eth_dev *priv = dev->priv;
  25        struct eth_dma_regs *dma_p = priv->dma_regs_p;
  26        struct dmamacdescr *desc_table_p = &priv->tx_mac_descrtable[0];
  27        char *txbuffs = &priv->txbuffs[0];
  28        struct dmamacdescr *desc_p;
  29        u32 idx;
  30
  31        for (idx = 0; idx < CONFIG_TX_DESCR_NUM; idx++) {
  32                desc_p = &desc_table_p[idx];
  33                desc_p->dmamac_addr = &txbuffs[idx * CONFIG_ETH_BUFSIZE];
  34                desc_p->dmamac_next = &desc_table_p[idx + 1];
  35
  36#if defined(CONFIG_DW_ALTDESCRIPTOR)
  37                desc_p->txrx_status &= ~(DESC_TXSTS_TXINT | DESC_TXSTS_TXLAST |
  38                                DESC_TXSTS_TXFIRST | DESC_TXSTS_TXCRCDIS | \
  39                                DESC_TXSTS_TXCHECKINSCTRL | \
  40                                DESC_TXSTS_TXRINGEND | DESC_TXSTS_TXPADDIS);
  41
  42                desc_p->txrx_status |= DESC_TXSTS_TXCHAIN;
  43                desc_p->dmamac_cntl = 0;
  44                desc_p->txrx_status &= ~(DESC_TXSTS_MSK | DESC_TXSTS_OWNBYDMA);
  45#else
  46                desc_p->dmamac_cntl = DESC_TXCTRL_TXCHAIN;
  47                desc_p->txrx_status = 0;
  48#endif
  49        }
  50
  51        /* Correcting the last pointer of the chain */
  52        desc_p->dmamac_next = &desc_table_p[0];
  53
  54        writel((ulong)&desc_table_p[0], &dma_p->txdesclistaddr);
  55}
  56
  57static void rx_descs_init(struct eth_device *dev)
  58{
  59        struct dw_eth_dev *priv = dev->priv;
  60        struct eth_dma_regs *dma_p = priv->dma_regs_p;
  61        struct dmamacdescr *desc_table_p = &priv->rx_mac_descrtable[0];
  62        char *rxbuffs = &priv->rxbuffs[0];
  63        struct dmamacdescr *desc_p;
  64        u32 idx;
  65
  66        for (idx = 0; idx < CONFIG_RX_DESCR_NUM; idx++) {
  67                desc_p = &desc_table_p[idx];
  68                desc_p->dmamac_addr = &rxbuffs[idx * CONFIG_ETH_BUFSIZE];
  69                desc_p->dmamac_next = &desc_table_p[idx + 1];
  70
  71                desc_p->dmamac_cntl =
  72                        (MAC_MAX_FRAME_SZ & DESC_RXCTRL_SIZE1MASK) | \
  73                                      DESC_RXCTRL_RXCHAIN;
  74
  75                desc_p->txrx_status = DESC_RXSTS_OWNBYDMA;
  76        }
  77
  78        /* Correcting the last pointer of the chain */
  79        desc_p->dmamac_next = &desc_table_p[0];
  80
  81        writel((ulong)&desc_table_p[0], &dma_p->rxdesclistaddr);
  82}
  83
  84static void descs_init(struct eth_device *dev)
  85{
  86        tx_descs_init(dev);
  87        rx_descs_init(dev);
  88}
  89
  90static int mac_reset(struct eth_device *dev)
  91{
  92        struct dw_eth_dev *priv = dev->priv;
  93        struct eth_mac_regs *mac_p = priv->mac_regs_p;
  94        struct eth_dma_regs *dma_p = priv->dma_regs_p;
  95
  96        ulong start;
  97        int timeout = CONFIG_MACRESET_TIMEOUT;
  98
  99        writel(DMAMAC_SRST, &dma_p->busmode);
 100
 101        if (priv->interface != PHY_INTERFACE_MODE_RGMII)
 102                writel(MII_PORTSELECT, &mac_p->conf);
 103
 104        start = get_timer(0);
 105        while (get_timer(start) < timeout) {
 106                if (!(readl(&dma_p->busmode) & DMAMAC_SRST))
 107                        return 0;
 108
 109                /* Try again after 10usec */
 110                udelay(10);
 111        };
 112
 113        return -1;
 114}
 115
 116static int dw_write_hwaddr(struct eth_device *dev)
 117{
 118        struct dw_eth_dev *priv = dev->priv;
 119        struct eth_mac_regs *mac_p = priv->mac_regs_p;
 120        u32 macid_lo, macid_hi;
 121        u8 *mac_id = &dev->enetaddr[0];
 122
 123        macid_lo = mac_id[0] + (mac_id[1] << 8) + \
 124                   (mac_id[2] << 16) + (mac_id[3] << 24);
 125        macid_hi = mac_id[4] + (mac_id[5] << 8);
 126
 127        writel(macid_hi, &mac_p->macaddr0hi);
 128        writel(macid_lo, &mac_p->macaddr0lo);
 129
 130        return 0;
 131}
 132
 133static int dw_eth_init(struct eth_device *dev, bd_t *bis)
 134{
 135        struct dw_eth_dev *priv = dev->priv;
 136        struct eth_mac_regs *mac_p = priv->mac_regs_p;
 137        struct eth_dma_regs *dma_p = priv->dma_regs_p;
 138        u32 conf;
 139
 140        if (priv->phy_configured != 1)
 141                configure_phy(dev);
 142
 143        /* Print link status only once */
 144        if (!priv->link_printed) {
 145                printf("ENET Speed is %d Mbps - %s duplex connection\n",
 146                       priv->speed, (priv->duplex == HALF) ? "HALF" : "FULL");
 147                priv->link_printed = 1;
 148        }
 149
 150        /* Reset ethernet hardware */
 151        if (mac_reset(dev) < 0)
 152                return -1;
 153
 154        /* Resore the HW MAC address as it has been lost during MAC reset */
 155        dw_write_hwaddr(dev);
 156
 157        writel(FIXEDBURST | PRIORXTX_41 | BURST_16,
 158                        &dma_p->busmode);
 159
 160        writel(readl(&dma_p->opmode) | FLUSHTXFIFO | STOREFORWARD |
 161                TXSECONDFRAME, &dma_p->opmode);
 162
 163        conf = FRAMEBURSTENABLE | DISABLERXOWN;
 164
 165        if (priv->speed != 1000)
 166                conf |= MII_PORTSELECT;
 167
 168        if ((priv->interface != PHY_INTERFACE_MODE_MII) &&
 169                (priv->interface != PHY_INTERFACE_MODE_GMII)) {
 170
 171                if (priv->speed == 100)
 172                        conf |= FES_100;
 173        }
 174
 175        if (priv->duplex == FULL)
 176                conf |= FULLDPLXMODE;
 177
 178        writel(conf, &mac_p->conf);
 179
 180        descs_init(dev);
 181
 182        /*
 183         * Start/Enable xfer at dma as well as mac level
 184         */
 185        writel(readl(&dma_p->opmode) | RXSTART, &dma_p->opmode);
 186        writel(readl(&dma_p->opmode) | TXSTART, &dma_p->opmode);
 187
 188        writel(readl(&mac_p->conf) | RXENABLE | TXENABLE, &mac_p->conf);
 189
 190        return 0;
 191}
 192
 193static int dw_eth_send(struct eth_device *dev, void *packet, int length)
 194{
 195        struct dw_eth_dev *priv = dev->priv;
 196        struct eth_dma_regs *dma_p = priv->dma_regs_p;
 197        u32 desc_num = priv->tx_currdescnum;
 198        struct dmamacdescr *desc_p = &priv->tx_mac_descrtable[desc_num];
 199
 200        /* Check if the descriptor is owned by CPU */
 201        if (desc_p->txrx_status & DESC_TXSTS_OWNBYDMA) {
 202                printf("CPU not owner of tx frame\n");
 203                return -1;
 204        }
 205
 206        memcpy((void *)desc_p->dmamac_addr, packet, length);
 207
 208#if defined(CONFIG_DW_ALTDESCRIPTOR)
 209        desc_p->txrx_status |= DESC_TXSTS_TXFIRST | DESC_TXSTS_TXLAST;
 210        desc_p->dmamac_cntl |= (length << DESC_TXCTRL_SIZE1SHFT) & \
 211                               DESC_TXCTRL_SIZE1MASK;
 212
 213        desc_p->txrx_status &= ~(DESC_TXSTS_MSK);
 214        desc_p->txrx_status |= DESC_TXSTS_OWNBYDMA;
 215#else
 216        desc_p->dmamac_cntl |= ((length << DESC_TXCTRL_SIZE1SHFT) & \
 217                               DESC_TXCTRL_SIZE1MASK) | DESC_TXCTRL_TXLAST | \
 218                               DESC_TXCTRL_TXFIRST;
 219
 220        desc_p->txrx_status = DESC_TXSTS_OWNBYDMA;
 221#endif
 222
 223        /* Test the wrap-around condition. */
 224        if (++desc_num >= CONFIG_TX_DESCR_NUM)
 225                desc_num = 0;
 226
 227        priv->tx_currdescnum = desc_num;
 228
 229        /* Start the transmission */
 230        writel(POLL_DATA, &dma_p->txpolldemand);
 231
 232        return 0;
 233}
 234
 235static int dw_eth_recv(struct eth_device *dev)
 236{
 237        struct dw_eth_dev *priv = dev->priv;
 238        u32 desc_num = priv->rx_currdescnum;
 239        struct dmamacdescr *desc_p = &priv->rx_mac_descrtable[desc_num];
 240
 241        u32 status = desc_p->txrx_status;
 242        int length = 0;
 243
 244        /* Check  if the owner is the CPU */
 245        if (!(status & DESC_RXSTS_OWNBYDMA)) {
 246
 247                length = (status & DESC_RXSTS_FRMLENMSK) >> \
 248                         DESC_RXSTS_FRMLENSHFT;
 249
 250                NetReceive(desc_p->dmamac_addr, length);
 251
 252                /*
 253                 * Make the current descriptor valid again and go to
 254                 * the next one
 255                 */
 256                desc_p->txrx_status |= DESC_RXSTS_OWNBYDMA;
 257
 258                /* Test the wrap-around condition. */
 259                if (++desc_num >= CONFIG_RX_DESCR_NUM)
 260                        desc_num = 0;
 261        }
 262
 263        priv->rx_currdescnum = desc_num;
 264
 265        return length;
 266}
 267
 268static void dw_eth_halt(struct eth_device *dev)
 269{
 270        struct dw_eth_dev *priv = dev->priv;
 271
 272        mac_reset(dev);
 273        priv->tx_currdescnum = priv->rx_currdescnum = 0;
 274}
 275
 276static int eth_mdio_read(struct eth_device *dev, u8 addr, u8 reg, u16 *val)
 277{
 278        struct dw_eth_dev *priv = dev->priv;
 279        struct eth_mac_regs *mac_p = priv->mac_regs_p;
 280        ulong start;
 281        u32 miiaddr;
 282        int timeout = CONFIG_MDIO_TIMEOUT;
 283
 284        miiaddr = ((addr << MIIADDRSHIFT) & MII_ADDRMSK) | \
 285                  ((reg << MIIREGSHIFT) & MII_REGMSK);
 286
 287        writel(miiaddr | MII_CLKRANGE_150_250M | MII_BUSY, &mac_p->miiaddr);
 288
 289        start = get_timer(0);
 290        while (get_timer(start) < timeout) {
 291                if (!(readl(&mac_p->miiaddr) & MII_BUSY)) {
 292                        *val = readl(&mac_p->miidata);
 293                        return 0;
 294                }
 295
 296                /* Try again after 10usec */
 297                udelay(10);
 298        };
 299
 300        return -1;
 301}
 302
 303static int eth_mdio_write(struct eth_device *dev, u8 addr, u8 reg, u16 val)
 304{
 305        struct dw_eth_dev *priv = dev->priv;
 306        struct eth_mac_regs *mac_p = priv->mac_regs_p;
 307        ulong start;
 308        u32 miiaddr;
 309        int ret = -1, timeout = CONFIG_MDIO_TIMEOUT;
 310        u16 value;
 311
 312        writel(val, &mac_p->miidata);
 313        miiaddr = ((addr << MIIADDRSHIFT) & MII_ADDRMSK) | \
 314                  ((reg << MIIREGSHIFT) & MII_REGMSK) | MII_WRITE;
 315
 316        writel(miiaddr | MII_CLKRANGE_150_250M | MII_BUSY, &mac_p->miiaddr);
 317
 318        start = get_timer(0);
 319        while (get_timer(start) < timeout) {
 320                if (!(readl(&mac_p->miiaddr) & MII_BUSY)) {
 321                        ret = 0;
 322                        break;
 323                }
 324
 325                /* Try again after 10usec */
 326                udelay(10);
 327        };
 328
 329        /* Needed as a fix for ST-Phy */
 330        eth_mdio_read(dev, addr, reg, &value);
 331
 332        return ret;
 333}
 334
 335#if defined(CONFIG_DW_SEARCH_PHY)
 336static int find_phy(struct eth_device *dev)
 337{
 338        int phy_addr = 0;
 339        u16 ctrl, oldctrl;
 340
 341        do {
 342                eth_mdio_read(dev, phy_addr, MII_BMCR, &ctrl);
 343                oldctrl = ctrl & BMCR_ANENABLE;
 344
 345                ctrl ^= BMCR_ANENABLE;
 346                eth_mdio_write(dev, phy_addr, MII_BMCR, ctrl);
 347                eth_mdio_read(dev, phy_addr, MII_BMCR, &ctrl);
 348                ctrl &= BMCR_ANENABLE;
 349
 350                if (ctrl == oldctrl) {
 351                        phy_addr++;
 352                } else {
 353                        ctrl ^= BMCR_ANENABLE;
 354                        eth_mdio_write(dev, phy_addr, MII_BMCR, ctrl);
 355
 356                        return phy_addr;
 357                }
 358        } while (phy_addr < 32);
 359
 360        return -1;
 361}
 362#endif
 363
 364static int dw_reset_phy(struct eth_device *dev)
 365{
 366        struct dw_eth_dev *priv = dev->priv;
 367        u16 ctrl;
 368        ulong start;
 369        int timeout = CONFIG_PHYRESET_TIMEOUT;
 370        u32 phy_addr = priv->address;
 371
 372        eth_mdio_write(dev, phy_addr, MII_BMCR, BMCR_RESET);
 373
 374        start = get_timer(0);
 375        while (get_timer(start) < timeout) {
 376                eth_mdio_read(dev, phy_addr, MII_BMCR, &ctrl);
 377                if (!(ctrl & BMCR_RESET))
 378                        break;
 379
 380                /* Try again after 10usec */
 381                udelay(10);
 382        };
 383
 384        if (get_timer(start) >= CONFIG_PHYRESET_TIMEOUT)
 385                return -1;
 386
 387#ifdef CONFIG_PHY_RESET_DELAY
 388        udelay(CONFIG_PHY_RESET_DELAY);
 389#endif
 390        return 0;
 391}
 392
 393/*
 394 * Add weak default function for board specific PHY configuration
 395 */
 396int __weak designware_board_phy_init(struct eth_device *dev, int phy_addr,
 397                int (*mii_write)(struct eth_device *, u8, u8, u16),
 398                int dw_reset_phy(struct eth_device *))
 399{
 400        return 0;
 401}
 402
 403static int configure_phy(struct eth_device *dev)
 404{
 405        struct dw_eth_dev *priv = dev->priv;
 406        int phy_addr;
 407        u16 bmcr;
 408#if defined(CONFIG_DW_AUTONEG)
 409        u16 bmsr;
 410        u32 timeout;
 411        ulong start;
 412#endif
 413
 414#if defined(CONFIG_DW_SEARCH_PHY)
 415        phy_addr = find_phy(dev);
 416        if (phy_addr >= 0)
 417                priv->address = phy_addr;
 418        else
 419                return -1;
 420#else
 421        phy_addr = priv->address;
 422#endif
 423
 424        /*
 425         * Some boards need board specific PHY initialization. This is
 426         * after the main driver init code but before the auto negotiation
 427         * is run.
 428         */
 429        if (designware_board_phy_init(dev, phy_addr,
 430                                      eth_mdio_write, dw_reset_phy) < 0)
 431                return -1;
 432
 433        if (dw_reset_phy(dev) < 0)
 434                return -1;
 435
 436#if defined(CONFIG_DW_AUTONEG)
 437        /* Set Auto-Neg Advertisement capabilities to 10/100 half/full */
 438        eth_mdio_write(dev, phy_addr, MII_ADVERTISE, 0x1E1);
 439
 440        bmcr = BMCR_ANENABLE | BMCR_ANRESTART;
 441#else
 442        bmcr = BMCR_SPEED100 | BMCR_FULLDPLX;
 443
 444#if defined(CONFIG_DW_SPEED10M)
 445        bmcr &= ~BMCR_SPEED100;
 446#endif
 447#if defined(CONFIG_DW_DUPLEXHALF)
 448        bmcr &= ~BMCR_FULLDPLX;
 449#endif
 450#endif
 451        if (eth_mdio_write(dev, phy_addr, MII_BMCR, bmcr) < 0)
 452                return -1;
 453
 454        /* Read the phy status register and populate priv structure */
 455#if defined(CONFIG_DW_AUTONEG)
 456        timeout = CONFIG_AUTONEG_TIMEOUT;
 457        start = get_timer(0);
 458        puts("Waiting for PHY auto negotiation to complete");
 459        while (get_timer(start) < timeout) {
 460                eth_mdio_read(dev, phy_addr, MII_BMSR, &bmsr);
 461                if (bmsr & BMSR_ANEGCOMPLETE) {
 462                        priv->phy_configured = 1;
 463                        break;
 464                }
 465
 466                /* Print dot all 1s to show progress */
 467                if ((get_timer(start) % 1000) == 0)
 468                        putc('.');
 469
 470                /* Try again after 1msec */
 471                udelay(1000);
 472        };
 473
 474        if (!(bmsr & BMSR_ANEGCOMPLETE))
 475                puts(" TIMEOUT!\n");
 476        else
 477                puts(" done\n");
 478#else
 479        priv->phy_configured = 1;
 480#endif
 481
 482        priv->speed = miiphy_speed(dev->name, phy_addr);
 483        priv->duplex = miiphy_duplex(dev->name, phy_addr);
 484
 485        return 0;
 486}
 487
 488#if defined(CONFIG_MII)
 489static int dw_mii_read(const char *devname, u8 addr, u8 reg, u16 *val)
 490{
 491        struct eth_device *dev;
 492
 493        dev = eth_get_dev_by_name(devname);
 494        if (dev)
 495                eth_mdio_read(dev, addr, reg, val);
 496
 497        return 0;
 498}
 499
 500static int dw_mii_write(const char *devname, u8 addr, u8 reg, u16 val)
 501{
 502        struct eth_device *dev;
 503
 504        dev = eth_get_dev_by_name(devname);
 505        if (dev)
 506                eth_mdio_write(dev, addr, reg, val);
 507
 508        return 0;
 509}
 510#endif
 511
 512int designware_initialize(u32 id, ulong base_addr, u32 phy_addr, u32 interface)
 513{
 514        struct eth_device *dev;
 515        struct dw_eth_dev *priv;
 516
 517        dev = (struct eth_device *) malloc(sizeof(struct eth_device));
 518        if (!dev)
 519                return -ENOMEM;
 520
 521        /*
 522         * Since the priv structure contains the descriptors which need a strict
 523         * buswidth alignment, memalign is used to allocate memory
 524         */
 525        priv = (struct dw_eth_dev *) memalign(16, sizeof(struct dw_eth_dev));
 526        if (!priv) {
 527                free(dev);
 528                return -ENOMEM;
 529        }
 530
 531        memset(dev, 0, sizeof(struct eth_device));
 532        memset(priv, 0, sizeof(struct dw_eth_dev));
 533
 534        sprintf(dev->name, "mii%d", id);
 535        dev->iobase = (int)base_addr;
 536        dev->priv = priv;
 537
 538        eth_getenv_enetaddr_by_index("eth", id, &dev->enetaddr[0]);
 539
 540        priv->dev = dev;
 541        priv->mac_regs_p = (struct eth_mac_regs *)base_addr;
 542        priv->dma_regs_p = (struct eth_dma_regs *)(base_addr +
 543                        DW_DMA_BASE_OFFSET);
 544        priv->address = phy_addr;
 545        priv->phy_configured = 0;
 546        priv->interface = interface;
 547
 548        dev->init = dw_eth_init;
 549        dev->send = dw_eth_send;
 550        dev->recv = dw_eth_recv;
 551        dev->halt = dw_eth_halt;
 552        dev->write_hwaddr = dw_write_hwaddr;
 553
 554        eth_register(dev);
 555
 556#if defined(CONFIG_MII)
 557        miiphy_register(dev->name, dw_mii_read, dw_mii_write);
 558#endif
 559        return 1;
 560}
 561