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