15b1b1883SVipin KUMAR /* 25b1b1883SVipin KUMAR * (C) Copyright 2010 35b1b1883SVipin KUMAR * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com. 45b1b1883SVipin KUMAR * 5*1a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 65b1b1883SVipin KUMAR */ 75b1b1883SVipin KUMAR 85b1b1883SVipin KUMAR /* 95b1b1883SVipin KUMAR * Designware ethernet IP driver for u-boot 105b1b1883SVipin KUMAR */ 115b1b1883SVipin KUMAR 125b1b1883SVipin KUMAR #include <common.h> 135b1b1883SVipin KUMAR #include <miiphy.h> 145b1b1883SVipin KUMAR #include <malloc.h> 15ef76025aSStefan Roese #include <linux/compiler.h> 165b1b1883SVipin KUMAR #include <linux/err.h> 175b1b1883SVipin KUMAR #include <asm/io.h> 185b1b1883SVipin KUMAR #include "designware.h" 195b1b1883SVipin KUMAR 2013edd170SVipin Kumar static int configure_phy(struct eth_device *dev); 2113edd170SVipin Kumar 225b1b1883SVipin KUMAR static void tx_descs_init(struct eth_device *dev) 235b1b1883SVipin KUMAR { 245b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 255b1b1883SVipin KUMAR struct eth_dma_regs *dma_p = priv->dma_regs_p; 265b1b1883SVipin KUMAR struct dmamacdescr *desc_table_p = &priv->tx_mac_descrtable[0]; 275b1b1883SVipin KUMAR char *txbuffs = &priv->txbuffs[0]; 285b1b1883SVipin KUMAR struct dmamacdescr *desc_p; 295b1b1883SVipin KUMAR u32 idx; 305b1b1883SVipin KUMAR 315b1b1883SVipin KUMAR for (idx = 0; idx < CONFIG_TX_DESCR_NUM; idx++) { 325b1b1883SVipin KUMAR desc_p = &desc_table_p[idx]; 335b1b1883SVipin KUMAR desc_p->dmamac_addr = &txbuffs[idx * CONFIG_ETH_BUFSIZE]; 345b1b1883SVipin KUMAR desc_p->dmamac_next = &desc_table_p[idx + 1]; 355b1b1883SVipin KUMAR 365b1b1883SVipin KUMAR #if defined(CONFIG_DW_ALTDESCRIPTOR) 375b1b1883SVipin KUMAR desc_p->txrx_status &= ~(DESC_TXSTS_TXINT | DESC_TXSTS_TXLAST | 385b1b1883SVipin KUMAR DESC_TXSTS_TXFIRST | DESC_TXSTS_TXCRCDIS | \ 395b1b1883SVipin KUMAR DESC_TXSTS_TXCHECKINSCTRL | \ 405b1b1883SVipin KUMAR DESC_TXSTS_TXRINGEND | DESC_TXSTS_TXPADDIS); 415b1b1883SVipin KUMAR 425b1b1883SVipin KUMAR desc_p->txrx_status |= DESC_TXSTS_TXCHAIN; 435b1b1883SVipin KUMAR desc_p->dmamac_cntl = 0; 445b1b1883SVipin KUMAR desc_p->txrx_status &= ~(DESC_TXSTS_MSK | DESC_TXSTS_OWNBYDMA); 455b1b1883SVipin KUMAR #else 465b1b1883SVipin KUMAR desc_p->dmamac_cntl = DESC_TXCTRL_TXCHAIN; 475b1b1883SVipin KUMAR desc_p->txrx_status = 0; 485b1b1883SVipin KUMAR #endif 495b1b1883SVipin KUMAR } 505b1b1883SVipin KUMAR 515b1b1883SVipin KUMAR /* Correcting the last pointer of the chain */ 525b1b1883SVipin KUMAR desc_p->dmamac_next = &desc_table_p[0]; 535b1b1883SVipin KUMAR 545b1b1883SVipin KUMAR writel((ulong)&desc_table_p[0], &dma_p->txdesclistaddr); 555b1b1883SVipin KUMAR } 565b1b1883SVipin KUMAR 575b1b1883SVipin KUMAR static void rx_descs_init(struct eth_device *dev) 585b1b1883SVipin KUMAR { 595b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 605b1b1883SVipin KUMAR struct eth_dma_regs *dma_p = priv->dma_regs_p; 615b1b1883SVipin KUMAR struct dmamacdescr *desc_table_p = &priv->rx_mac_descrtable[0]; 625b1b1883SVipin KUMAR char *rxbuffs = &priv->rxbuffs[0]; 635b1b1883SVipin KUMAR struct dmamacdescr *desc_p; 645b1b1883SVipin KUMAR u32 idx; 655b1b1883SVipin KUMAR 665b1b1883SVipin KUMAR for (idx = 0; idx < CONFIG_RX_DESCR_NUM; idx++) { 675b1b1883SVipin KUMAR desc_p = &desc_table_p[idx]; 685b1b1883SVipin KUMAR desc_p->dmamac_addr = &rxbuffs[idx * CONFIG_ETH_BUFSIZE]; 695b1b1883SVipin KUMAR desc_p->dmamac_next = &desc_table_p[idx + 1]; 705b1b1883SVipin KUMAR 715b1b1883SVipin KUMAR desc_p->dmamac_cntl = 725b1b1883SVipin KUMAR (MAC_MAX_FRAME_SZ & DESC_RXCTRL_SIZE1MASK) | \ 735b1b1883SVipin KUMAR DESC_RXCTRL_RXCHAIN; 745b1b1883SVipin KUMAR 755b1b1883SVipin KUMAR desc_p->txrx_status = DESC_RXSTS_OWNBYDMA; 765b1b1883SVipin KUMAR } 775b1b1883SVipin KUMAR 785b1b1883SVipin KUMAR /* Correcting the last pointer of the chain */ 795b1b1883SVipin KUMAR desc_p->dmamac_next = &desc_table_p[0]; 805b1b1883SVipin KUMAR 815b1b1883SVipin KUMAR writel((ulong)&desc_table_p[0], &dma_p->rxdesclistaddr); 825b1b1883SVipin KUMAR } 835b1b1883SVipin KUMAR 845b1b1883SVipin KUMAR static void descs_init(struct eth_device *dev) 855b1b1883SVipin KUMAR { 865b1b1883SVipin KUMAR tx_descs_init(dev); 875b1b1883SVipin KUMAR rx_descs_init(dev); 885b1b1883SVipin KUMAR } 895b1b1883SVipin KUMAR 905b1b1883SVipin KUMAR static int mac_reset(struct eth_device *dev) 915b1b1883SVipin KUMAR { 925b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 935b1b1883SVipin KUMAR struct eth_mac_regs *mac_p = priv->mac_regs_p; 945b1b1883SVipin KUMAR struct eth_dma_regs *dma_p = priv->dma_regs_p; 955b1b1883SVipin KUMAR 96cafabe19SAmit Virdi ulong start; 975b1b1883SVipin KUMAR int timeout = CONFIG_MACRESET_TIMEOUT; 985b1b1883SVipin KUMAR 995b1b1883SVipin KUMAR writel(DMAMAC_SRST, &dma_p->busmode); 1007091915aSVipin Kumar 1017091915aSVipin Kumar if (priv->interface != PHY_INTERFACE_MODE_RGMII) 1025b1b1883SVipin KUMAR writel(MII_PORTSELECT, &mac_p->conf); 1035b1b1883SVipin KUMAR 104cafabe19SAmit Virdi start = get_timer(0); 105cafabe19SAmit Virdi while (get_timer(start) < timeout) { 1065b1b1883SVipin KUMAR if (!(readl(&dma_p->busmode) & DMAMAC_SRST)) 1075b1b1883SVipin KUMAR return 0; 108cafabe19SAmit Virdi 109cafabe19SAmit Virdi /* Try again after 10usec */ 110cafabe19SAmit Virdi udelay(10); 111cafabe19SAmit Virdi }; 1125b1b1883SVipin KUMAR 1135b1b1883SVipin KUMAR return -1; 1145b1b1883SVipin KUMAR } 1155b1b1883SVipin KUMAR 1165b1b1883SVipin KUMAR static int dw_write_hwaddr(struct eth_device *dev) 1175b1b1883SVipin KUMAR { 1185b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 1195b1b1883SVipin KUMAR struct eth_mac_regs *mac_p = priv->mac_regs_p; 1205b1b1883SVipin KUMAR u32 macid_lo, macid_hi; 1215b1b1883SVipin KUMAR u8 *mac_id = &dev->enetaddr[0]; 1225b1b1883SVipin KUMAR 1235b1b1883SVipin KUMAR macid_lo = mac_id[0] + (mac_id[1] << 8) + \ 1245b1b1883SVipin KUMAR (mac_id[2] << 16) + (mac_id[3] << 24); 1255b1b1883SVipin KUMAR macid_hi = mac_id[4] + (mac_id[5] << 8); 1265b1b1883SVipin KUMAR 1275b1b1883SVipin KUMAR writel(macid_hi, &mac_p->macaddr0hi); 1285b1b1883SVipin KUMAR writel(macid_lo, &mac_p->macaddr0lo); 1295b1b1883SVipin KUMAR 1305b1b1883SVipin KUMAR return 0; 1315b1b1883SVipin KUMAR } 1325b1b1883SVipin KUMAR 1335b1b1883SVipin KUMAR static int dw_eth_init(struct eth_device *dev, bd_t *bis) 1345b1b1883SVipin KUMAR { 1355b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 1365b1b1883SVipin KUMAR struct eth_mac_regs *mac_p = priv->mac_regs_p; 1375b1b1883SVipin KUMAR struct eth_dma_regs *dma_p = priv->dma_regs_p; 1385b1b1883SVipin KUMAR u32 conf; 1395b1b1883SVipin KUMAR 14013edd170SVipin Kumar if (priv->phy_configured != 1) 14113edd170SVipin Kumar configure_phy(dev); 14213edd170SVipin Kumar 143ef76025aSStefan Roese /* Print link status only once */ 144ef76025aSStefan Roese if (!priv->link_printed) { 145ef76025aSStefan Roese printf("ENET Speed is %d Mbps - %s duplex connection\n", 146ef76025aSStefan Roese priv->speed, (priv->duplex == HALF) ? "HALF" : "FULL"); 147ef76025aSStefan Roese priv->link_printed = 1; 148ef76025aSStefan Roese } 149ef76025aSStefan Roese 1505b1b1883SVipin KUMAR /* Reset ethernet hardware */ 1515b1b1883SVipin KUMAR if (mac_reset(dev) < 0) 1525b1b1883SVipin KUMAR return -1; 1535b1b1883SVipin KUMAR 154c7f6dbe7SVipin KUMAR /* Resore the HW MAC address as it has been lost during MAC reset */ 155c7f6dbe7SVipin KUMAR dw_write_hwaddr(dev); 156c7f6dbe7SVipin KUMAR 1575b1b1883SVipin KUMAR writel(FIXEDBURST | PRIORXTX_41 | BURST_16, 1585b1b1883SVipin KUMAR &dma_p->busmode); 1595b1b1883SVipin KUMAR 16066f119e5SDinh Nguyen writel(readl(&dma_p->opmode) | FLUSHTXFIFO | STOREFORWARD | 16166f119e5SDinh Nguyen TXSECONDFRAME, &dma_p->opmode); 1625b1b1883SVipin KUMAR 1635b1b1883SVipin KUMAR conf = FRAMEBURSTENABLE | DISABLERXOWN; 1645b1b1883SVipin KUMAR 165ef76025aSStefan Roese if (priv->speed != 1000) 1665b1b1883SVipin KUMAR conf |= MII_PORTSELECT; 1675b1b1883SVipin KUMAR 1689afc1af0SVipin Kumar if ((priv->interface != PHY_INTERFACE_MODE_MII) && 1699afc1af0SVipin Kumar (priv->interface != PHY_INTERFACE_MODE_GMII)) { 1709afc1af0SVipin Kumar 171ef76025aSStefan Roese if (priv->speed == 100) 1729afc1af0SVipin Kumar conf |= FES_100; 1739afc1af0SVipin Kumar } 1749afc1af0SVipin Kumar 175ef76025aSStefan Roese if (priv->duplex == FULL) 1765b1b1883SVipin KUMAR conf |= FULLDPLXMODE; 1775b1b1883SVipin KUMAR 1785b1b1883SVipin KUMAR writel(conf, &mac_p->conf); 1795b1b1883SVipin KUMAR 1805b1b1883SVipin KUMAR descs_init(dev); 1815b1b1883SVipin KUMAR 1825b1b1883SVipin KUMAR /* 1835b1b1883SVipin KUMAR * Start/Enable xfer at dma as well as mac level 1845b1b1883SVipin KUMAR */ 1855b1b1883SVipin KUMAR writel(readl(&dma_p->opmode) | RXSTART, &dma_p->opmode); 1865b1b1883SVipin KUMAR writel(readl(&dma_p->opmode) | TXSTART, &dma_p->opmode); 1875b1b1883SVipin KUMAR 188aa51005cSArmando Visconti writel(readl(&mac_p->conf) | RXENABLE | TXENABLE, &mac_p->conf); 1895b1b1883SVipin KUMAR 1905b1b1883SVipin KUMAR return 0; 1915b1b1883SVipin KUMAR } 1925b1b1883SVipin KUMAR 19310cbe3b6SJoe Hershberger static int dw_eth_send(struct eth_device *dev, void *packet, int length) 1945b1b1883SVipin KUMAR { 1955b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 1965b1b1883SVipin KUMAR struct eth_dma_regs *dma_p = priv->dma_regs_p; 1975b1b1883SVipin KUMAR u32 desc_num = priv->tx_currdescnum; 1985b1b1883SVipin KUMAR struct dmamacdescr *desc_p = &priv->tx_mac_descrtable[desc_num]; 1995b1b1883SVipin KUMAR 2005b1b1883SVipin KUMAR /* Check if the descriptor is owned by CPU */ 2015b1b1883SVipin KUMAR if (desc_p->txrx_status & DESC_TXSTS_OWNBYDMA) { 2025b1b1883SVipin KUMAR printf("CPU not owner of tx frame\n"); 2035b1b1883SVipin KUMAR return -1; 2045b1b1883SVipin KUMAR } 2055b1b1883SVipin KUMAR 20610cbe3b6SJoe Hershberger memcpy((void *)desc_p->dmamac_addr, packet, length); 2075b1b1883SVipin KUMAR 2085b1b1883SVipin KUMAR #if defined(CONFIG_DW_ALTDESCRIPTOR) 2095b1b1883SVipin KUMAR desc_p->txrx_status |= DESC_TXSTS_TXFIRST | DESC_TXSTS_TXLAST; 2105b1b1883SVipin KUMAR desc_p->dmamac_cntl |= (length << DESC_TXCTRL_SIZE1SHFT) & \ 2115b1b1883SVipin KUMAR DESC_TXCTRL_SIZE1MASK; 2125b1b1883SVipin KUMAR 2135b1b1883SVipin KUMAR desc_p->txrx_status &= ~(DESC_TXSTS_MSK); 2145b1b1883SVipin KUMAR desc_p->txrx_status |= DESC_TXSTS_OWNBYDMA; 2155b1b1883SVipin KUMAR #else 2165b1b1883SVipin KUMAR desc_p->dmamac_cntl |= ((length << DESC_TXCTRL_SIZE1SHFT) & \ 2175b1b1883SVipin KUMAR DESC_TXCTRL_SIZE1MASK) | DESC_TXCTRL_TXLAST | \ 2185b1b1883SVipin KUMAR DESC_TXCTRL_TXFIRST; 2195b1b1883SVipin KUMAR 2205b1b1883SVipin KUMAR desc_p->txrx_status = DESC_TXSTS_OWNBYDMA; 2215b1b1883SVipin KUMAR #endif 2225b1b1883SVipin KUMAR 2235b1b1883SVipin KUMAR /* Test the wrap-around condition. */ 2245b1b1883SVipin KUMAR if (++desc_num >= CONFIG_TX_DESCR_NUM) 2255b1b1883SVipin KUMAR desc_num = 0; 2265b1b1883SVipin KUMAR 2275b1b1883SVipin KUMAR priv->tx_currdescnum = desc_num; 2285b1b1883SVipin KUMAR 2295b1b1883SVipin KUMAR /* Start the transmission */ 2305b1b1883SVipin KUMAR writel(POLL_DATA, &dma_p->txpolldemand); 2315b1b1883SVipin KUMAR 2325b1b1883SVipin KUMAR return 0; 2335b1b1883SVipin KUMAR } 2345b1b1883SVipin KUMAR 2355b1b1883SVipin KUMAR static int dw_eth_recv(struct eth_device *dev) 2365b1b1883SVipin KUMAR { 2375b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 2385b1b1883SVipin KUMAR u32 desc_num = priv->rx_currdescnum; 2395b1b1883SVipin KUMAR struct dmamacdescr *desc_p = &priv->rx_mac_descrtable[desc_num]; 2405b1b1883SVipin KUMAR 2415b1b1883SVipin KUMAR u32 status = desc_p->txrx_status; 2425b1b1883SVipin KUMAR int length = 0; 2435b1b1883SVipin KUMAR 2445b1b1883SVipin KUMAR /* Check if the owner is the CPU */ 2455b1b1883SVipin KUMAR if (!(status & DESC_RXSTS_OWNBYDMA)) { 2465b1b1883SVipin KUMAR 2475b1b1883SVipin KUMAR length = (status & DESC_RXSTS_FRMLENMSK) >> \ 2485b1b1883SVipin KUMAR DESC_RXSTS_FRMLENSHFT; 2495b1b1883SVipin KUMAR 2505b1b1883SVipin KUMAR NetReceive(desc_p->dmamac_addr, length); 2515b1b1883SVipin KUMAR 2525b1b1883SVipin KUMAR /* 2535b1b1883SVipin KUMAR * Make the current descriptor valid again and go to 2545b1b1883SVipin KUMAR * the next one 2555b1b1883SVipin KUMAR */ 2565b1b1883SVipin KUMAR desc_p->txrx_status |= DESC_RXSTS_OWNBYDMA; 2575b1b1883SVipin KUMAR 2585b1b1883SVipin KUMAR /* Test the wrap-around condition. */ 2595b1b1883SVipin KUMAR if (++desc_num >= CONFIG_RX_DESCR_NUM) 2605b1b1883SVipin KUMAR desc_num = 0; 2615b1b1883SVipin KUMAR } 2625b1b1883SVipin KUMAR 2635b1b1883SVipin KUMAR priv->rx_currdescnum = desc_num; 2645b1b1883SVipin KUMAR 2655b1b1883SVipin KUMAR return length; 2665b1b1883SVipin KUMAR } 2675b1b1883SVipin KUMAR 2685b1b1883SVipin KUMAR static void dw_eth_halt(struct eth_device *dev) 2695b1b1883SVipin KUMAR { 2705b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 2715b1b1883SVipin KUMAR 2725b1b1883SVipin KUMAR mac_reset(dev); 2735b1b1883SVipin KUMAR priv->tx_currdescnum = priv->rx_currdescnum = 0; 2745b1b1883SVipin KUMAR } 2755b1b1883SVipin KUMAR 2765b1b1883SVipin KUMAR static int eth_mdio_read(struct eth_device *dev, u8 addr, u8 reg, u16 *val) 2775b1b1883SVipin KUMAR { 2785b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 2795b1b1883SVipin KUMAR struct eth_mac_regs *mac_p = priv->mac_regs_p; 280cafabe19SAmit Virdi ulong start; 2815b1b1883SVipin KUMAR u32 miiaddr; 2825b1b1883SVipin KUMAR int timeout = CONFIG_MDIO_TIMEOUT; 2835b1b1883SVipin KUMAR 2845b1b1883SVipin KUMAR miiaddr = ((addr << MIIADDRSHIFT) & MII_ADDRMSK) | \ 2855b1b1883SVipin KUMAR ((reg << MIIREGSHIFT) & MII_REGMSK); 2865b1b1883SVipin KUMAR 2875b1b1883SVipin KUMAR writel(miiaddr | MII_CLKRANGE_150_250M | MII_BUSY, &mac_p->miiaddr); 2885b1b1883SVipin KUMAR 289cafabe19SAmit Virdi start = get_timer(0); 290cafabe19SAmit Virdi while (get_timer(start) < timeout) { 2915b1b1883SVipin KUMAR if (!(readl(&mac_p->miiaddr) & MII_BUSY)) { 2925b1b1883SVipin KUMAR *val = readl(&mac_p->miidata); 2935b1b1883SVipin KUMAR return 0; 2945b1b1883SVipin KUMAR } 295cafabe19SAmit Virdi 296cafabe19SAmit Virdi /* Try again after 10usec */ 297cafabe19SAmit Virdi udelay(10); 298cafabe19SAmit Virdi }; 2995b1b1883SVipin KUMAR 3005b1b1883SVipin KUMAR return -1; 3015b1b1883SVipin KUMAR } 3025b1b1883SVipin KUMAR 3035b1b1883SVipin KUMAR static int eth_mdio_write(struct eth_device *dev, u8 addr, u8 reg, u16 val) 3045b1b1883SVipin KUMAR { 3055b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 3065b1b1883SVipin KUMAR struct eth_mac_regs *mac_p = priv->mac_regs_p; 307cafabe19SAmit Virdi ulong start; 3085b1b1883SVipin KUMAR u32 miiaddr; 3095b1b1883SVipin KUMAR int ret = -1, timeout = CONFIG_MDIO_TIMEOUT; 3105b1b1883SVipin KUMAR u16 value; 3115b1b1883SVipin KUMAR 3125b1b1883SVipin KUMAR writel(val, &mac_p->miidata); 3135b1b1883SVipin KUMAR miiaddr = ((addr << MIIADDRSHIFT) & MII_ADDRMSK) | \ 3145b1b1883SVipin KUMAR ((reg << MIIREGSHIFT) & MII_REGMSK) | MII_WRITE; 3155b1b1883SVipin KUMAR 3165b1b1883SVipin KUMAR writel(miiaddr | MII_CLKRANGE_150_250M | MII_BUSY, &mac_p->miiaddr); 3175b1b1883SVipin KUMAR 318cafabe19SAmit Virdi start = get_timer(0); 319cafabe19SAmit Virdi while (get_timer(start) < timeout) { 320c7f6dbe7SVipin KUMAR if (!(readl(&mac_p->miiaddr) & MII_BUSY)) { 3215b1b1883SVipin KUMAR ret = 0; 322c7f6dbe7SVipin KUMAR break; 323c7f6dbe7SVipin KUMAR } 324cafabe19SAmit Virdi 325cafabe19SAmit Virdi /* Try again after 10usec */ 326cafabe19SAmit Virdi udelay(10); 327cafabe19SAmit Virdi }; 3285b1b1883SVipin KUMAR 3295b1b1883SVipin KUMAR /* Needed as a fix for ST-Phy */ 3305b1b1883SVipin KUMAR eth_mdio_read(dev, addr, reg, &value); 3315b1b1883SVipin KUMAR 3325b1b1883SVipin KUMAR return ret; 3335b1b1883SVipin KUMAR } 3345b1b1883SVipin KUMAR 3355b1b1883SVipin KUMAR #if defined(CONFIG_DW_SEARCH_PHY) 3365b1b1883SVipin KUMAR static int find_phy(struct eth_device *dev) 3375b1b1883SVipin KUMAR { 3385b1b1883SVipin KUMAR int phy_addr = 0; 3395b1b1883SVipin KUMAR u16 ctrl, oldctrl; 3405b1b1883SVipin KUMAR 3415b1b1883SVipin KUMAR do { 3428ef583a0SMike Frysinger eth_mdio_read(dev, phy_addr, MII_BMCR, &ctrl); 3438ef583a0SMike Frysinger oldctrl = ctrl & BMCR_ANENABLE; 3445b1b1883SVipin KUMAR 3458ef583a0SMike Frysinger ctrl ^= BMCR_ANENABLE; 3468ef583a0SMike Frysinger eth_mdio_write(dev, phy_addr, MII_BMCR, ctrl); 3478ef583a0SMike Frysinger eth_mdio_read(dev, phy_addr, MII_BMCR, &ctrl); 3488ef583a0SMike Frysinger ctrl &= BMCR_ANENABLE; 3495b1b1883SVipin KUMAR 3505b1b1883SVipin KUMAR if (ctrl == oldctrl) { 3515b1b1883SVipin KUMAR phy_addr++; 3525b1b1883SVipin KUMAR } else { 3538ef583a0SMike Frysinger ctrl ^= BMCR_ANENABLE; 3548ef583a0SMike Frysinger eth_mdio_write(dev, phy_addr, MII_BMCR, ctrl); 3555b1b1883SVipin KUMAR 3565b1b1883SVipin KUMAR return phy_addr; 3575b1b1883SVipin KUMAR } 3585b1b1883SVipin KUMAR } while (phy_addr < 32); 3595b1b1883SVipin KUMAR 3605b1b1883SVipin KUMAR return -1; 3615b1b1883SVipin KUMAR } 3625b1b1883SVipin KUMAR #endif 3635b1b1883SVipin KUMAR 3645b1b1883SVipin KUMAR static int dw_reset_phy(struct eth_device *dev) 3655b1b1883SVipin KUMAR { 3665b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 3675b1b1883SVipin KUMAR u16 ctrl; 368cafabe19SAmit Virdi ulong start; 3695b1b1883SVipin KUMAR int timeout = CONFIG_PHYRESET_TIMEOUT; 3705b1b1883SVipin KUMAR u32 phy_addr = priv->address; 3715b1b1883SVipin KUMAR 3728ef583a0SMike Frysinger eth_mdio_write(dev, phy_addr, MII_BMCR, BMCR_RESET); 373cafabe19SAmit Virdi 374cafabe19SAmit Virdi start = get_timer(0); 375cafabe19SAmit Virdi while (get_timer(start) < timeout) { 3768ef583a0SMike Frysinger eth_mdio_read(dev, phy_addr, MII_BMCR, &ctrl); 3778ef583a0SMike Frysinger if (!(ctrl & BMCR_RESET)) 3785b1b1883SVipin KUMAR break; 3795b1b1883SVipin KUMAR 380cafabe19SAmit Virdi /* Try again after 10usec */ 381cafabe19SAmit Virdi udelay(10); 382cafabe19SAmit Virdi }; 383cafabe19SAmit Virdi 384cafabe19SAmit Virdi if (get_timer(start) >= CONFIG_PHYRESET_TIMEOUT) 3855b1b1883SVipin KUMAR return -1; 3865b1b1883SVipin KUMAR 3875b1b1883SVipin KUMAR #ifdef CONFIG_PHY_RESET_DELAY 3885b1b1883SVipin KUMAR udelay(CONFIG_PHY_RESET_DELAY); 3895b1b1883SVipin KUMAR #endif 3905b1b1883SVipin KUMAR return 0; 3915b1b1883SVipin KUMAR } 3925b1b1883SVipin KUMAR 393ef76025aSStefan Roese /* 394ef76025aSStefan Roese * Add weak default function for board specific PHY configuration 395ef76025aSStefan Roese */ 396ef76025aSStefan Roese int __weak designware_board_phy_init(struct eth_device *dev, int phy_addr, 397ef76025aSStefan Roese int (*mii_write)(struct eth_device *, u8, u8, u16), 398ef76025aSStefan Roese int dw_reset_phy(struct eth_device *)) 399ef76025aSStefan Roese { 400ef76025aSStefan Roese return 0; 401ef76025aSStefan Roese } 402ef76025aSStefan Roese 4035b1b1883SVipin KUMAR static int configure_phy(struct eth_device *dev) 4045b1b1883SVipin KUMAR { 4055b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 4065b1b1883SVipin KUMAR int phy_addr; 407ee7f5bfdSMike Frysinger u16 bmcr; 4085b1b1883SVipin KUMAR #if defined(CONFIG_DW_AUTONEG) 4095b1b1883SVipin KUMAR u16 bmsr; 4105b1b1883SVipin KUMAR u32 timeout; 411cafabe19SAmit Virdi ulong start; 4125b1b1883SVipin KUMAR #endif 4135b1b1883SVipin KUMAR 4145b1b1883SVipin KUMAR #if defined(CONFIG_DW_SEARCH_PHY) 4155b1b1883SVipin KUMAR phy_addr = find_phy(dev); 416024333c9SVipin KUMAR if (phy_addr >= 0) 4175b1b1883SVipin KUMAR priv->address = phy_addr; 4185b1b1883SVipin KUMAR else 4195b1b1883SVipin KUMAR return -1; 420f0ece9e9SMike Frysinger #else 421f0ece9e9SMike Frysinger phy_addr = priv->address; 4225b1b1883SVipin KUMAR #endif 423ef76025aSStefan Roese 424ef76025aSStefan Roese /* 425ef76025aSStefan Roese * Some boards need board specific PHY initialization. This is 426ef76025aSStefan Roese * after the main driver init code but before the auto negotiation 427ef76025aSStefan Roese * is run. 428ef76025aSStefan Roese */ 429ef76025aSStefan Roese if (designware_board_phy_init(dev, phy_addr, 430ef76025aSStefan Roese eth_mdio_write, dw_reset_phy) < 0) 431ef76025aSStefan Roese return -1; 432ef76025aSStefan Roese 4335b1b1883SVipin KUMAR if (dw_reset_phy(dev) < 0) 4345b1b1883SVipin KUMAR return -1; 4355b1b1883SVipin KUMAR 4365b1b1883SVipin KUMAR #if defined(CONFIG_DW_AUTONEG) 43720a5dde1SArmando Visconti /* Set Auto-Neg Advertisement capabilities to 10/100 half/full */ 43820a5dde1SArmando Visconti eth_mdio_write(dev, phy_addr, MII_ADVERTISE, 0x1E1); 43920a5dde1SArmando Visconti 440e25c90b4SVikas Manocha bmcr = BMCR_ANENABLE | BMCR_ANRESTART; 4415b1b1883SVipin KUMAR #else 4428ef583a0SMike Frysinger bmcr = BMCR_SPEED100 | BMCR_FULLDPLX; 4435b1b1883SVipin KUMAR 4445b1b1883SVipin KUMAR #if defined(CONFIG_DW_SPEED10M) 4458ef583a0SMike Frysinger bmcr &= ~BMCR_SPEED100; 4465b1b1883SVipin KUMAR #endif 4475b1b1883SVipin KUMAR #if defined(CONFIG_DW_DUPLEXHALF) 4488ef583a0SMike Frysinger bmcr &= ~BMCR_FULLDPLX; 4495b1b1883SVipin KUMAR #endif 4505b1b1883SVipin KUMAR #endif 4518ef583a0SMike Frysinger if (eth_mdio_write(dev, phy_addr, MII_BMCR, bmcr) < 0) 4525b1b1883SVipin KUMAR return -1; 4535b1b1883SVipin KUMAR 4545b1b1883SVipin KUMAR /* Read the phy status register and populate priv structure */ 4555b1b1883SVipin KUMAR #if defined(CONFIG_DW_AUTONEG) 4565b1b1883SVipin KUMAR timeout = CONFIG_AUTONEG_TIMEOUT; 457cafabe19SAmit Virdi start = get_timer(0); 458ef76025aSStefan Roese puts("Waiting for PHY auto negotiation to complete"); 459cafabe19SAmit Virdi while (get_timer(start) < timeout) { 4608ef583a0SMike Frysinger eth_mdio_read(dev, phy_addr, MII_BMSR, &bmsr); 461ef76025aSStefan Roese if (bmsr & BMSR_ANEGCOMPLETE) { 462ef76025aSStefan Roese priv->phy_configured = 1; 4635b1b1883SVipin KUMAR break; 464ef76025aSStefan Roese } 465cafabe19SAmit Virdi 466ef76025aSStefan Roese /* Print dot all 1s to show progress */ 467ef76025aSStefan Roese if ((get_timer(start) % 1000) == 0) 468ef76025aSStefan Roese putc('.'); 469ef76025aSStefan Roese 470ef76025aSStefan Roese /* Try again after 1msec */ 471ef76025aSStefan Roese udelay(1000); 472cafabe19SAmit Virdi }; 4735b1b1883SVipin KUMAR 474ef76025aSStefan Roese if (!(bmsr & BMSR_ANEGCOMPLETE)) 475ef76025aSStefan Roese puts(" TIMEOUT!\n"); 476ef76025aSStefan Roese else 477ef76025aSStefan Roese puts(" done\n"); 4785b1b1883SVipin KUMAR #else 47913edd170SVipin Kumar priv->phy_configured = 1; 480ef76025aSStefan Roese #endif 481ef76025aSStefan Roese 482ef76025aSStefan Roese priv->speed = miiphy_speed(dev->name, phy_addr); 483ef76025aSStefan Roese priv->duplex = miiphy_duplex(dev->name, phy_addr); 48413edd170SVipin Kumar 4855b1b1883SVipin KUMAR return 0; 4865b1b1883SVipin KUMAR } 4875b1b1883SVipin KUMAR 4885b1b1883SVipin KUMAR #if defined(CONFIG_MII) 4895700bb63SMike Frysinger static int dw_mii_read(const char *devname, u8 addr, u8 reg, u16 *val) 4905b1b1883SVipin KUMAR { 4915b1b1883SVipin KUMAR struct eth_device *dev; 4925b1b1883SVipin KUMAR 4935b1b1883SVipin KUMAR dev = eth_get_dev_by_name(devname); 4945b1b1883SVipin KUMAR if (dev) 4955b1b1883SVipin KUMAR eth_mdio_read(dev, addr, reg, val); 4965b1b1883SVipin KUMAR 4975b1b1883SVipin KUMAR return 0; 4985b1b1883SVipin KUMAR } 4995b1b1883SVipin KUMAR 5005700bb63SMike Frysinger static int dw_mii_write(const char *devname, u8 addr, u8 reg, u16 val) 5015b1b1883SVipin KUMAR { 5025b1b1883SVipin KUMAR struct eth_device *dev; 5035b1b1883SVipin KUMAR 5045b1b1883SVipin KUMAR dev = eth_get_dev_by_name(devname); 5055b1b1883SVipin KUMAR if (dev) 5065b1b1883SVipin KUMAR eth_mdio_write(dev, addr, reg, val); 5075b1b1883SVipin KUMAR 5085b1b1883SVipin KUMAR return 0; 5095b1b1883SVipin KUMAR } 5105b1b1883SVipin KUMAR #endif 5115b1b1883SVipin KUMAR 5129afc1af0SVipin Kumar int designware_initialize(u32 id, ulong base_addr, u32 phy_addr, u32 interface) 5135b1b1883SVipin KUMAR { 5145b1b1883SVipin KUMAR struct eth_device *dev; 5155b1b1883SVipin KUMAR struct dw_eth_dev *priv; 5165b1b1883SVipin KUMAR 5175b1b1883SVipin KUMAR dev = (struct eth_device *) malloc(sizeof(struct eth_device)); 5185b1b1883SVipin KUMAR if (!dev) 5195b1b1883SVipin KUMAR return -ENOMEM; 5205b1b1883SVipin KUMAR 5215b1b1883SVipin KUMAR /* 5225b1b1883SVipin KUMAR * Since the priv structure contains the descriptors which need a strict 5235b1b1883SVipin KUMAR * buswidth alignment, memalign is used to allocate memory 5245b1b1883SVipin KUMAR */ 5255b1b1883SVipin KUMAR priv = (struct dw_eth_dev *) memalign(16, sizeof(struct dw_eth_dev)); 5265b1b1883SVipin KUMAR if (!priv) { 5275b1b1883SVipin KUMAR free(dev); 5285b1b1883SVipin KUMAR return -ENOMEM; 5295b1b1883SVipin KUMAR } 5305b1b1883SVipin KUMAR 5315b1b1883SVipin KUMAR memset(dev, 0, sizeof(struct eth_device)); 5325b1b1883SVipin KUMAR memset(priv, 0, sizeof(struct dw_eth_dev)); 5335b1b1883SVipin KUMAR 5345b1b1883SVipin KUMAR sprintf(dev->name, "mii%d", id); 5355b1b1883SVipin KUMAR dev->iobase = (int)base_addr; 5365b1b1883SVipin KUMAR dev->priv = priv; 5375b1b1883SVipin KUMAR 5387616e785SSimon Glass eth_getenv_enetaddr_by_index("eth", id, &dev->enetaddr[0]); 5395b1b1883SVipin KUMAR 5405b1b1883SVipin KUMAR priv->dev = dev; 5415b1b1883SVipin KUMAR priv->mac_regs_p = (struct eth_mac_regs *)base_addr; 5425b1b1883SVipin KUMAR priv->dma_regs_p = (struct eth_dma_regs *)(base_addr + 5435b1b1883SVipin KUMAR DW_DMA_BASE_OFFSET); 5445b1b1883SVipin KUMAR priv->address = phy_addr; 54513edd170SVipin Kumar priv->phy_configured = 0; 5469afc1af0SVipin Kumar priv->interface = interface; 5475b1b1883SVipin KUMAR 5485b1b1883SVipin KUMAR dev->init = dw_eth_init; 5495b1b1883SVipin KUMAR dev->send = dw_eth_send; 5505b1b1883SVipin KUMAR dev->recv = dw_eth_recv; 5515b1b1883SVipin KUMAR dev->halt = dw_eth_halt; 5525b1b1883SVipin KUMAR dev->write_hwaddr = dw_write_hwaddr; 5535b1b1883SVipin KUMAR 5545b1b1883SVipin KUMAR eth_register(dev); 5555b1b1883SVipin KUMAR 5565b1b1883SVipin KUMAR #if defined(CONFIG_MII) 5575b1b1883SVipin KUMAR miiphy_register(dev->name, dw_mii_read, dw_mii_write); 5585b1b1883SVipin KUMAR #endif 5595b1b1883SVipin KUMAR return 1; 5605b1b1883SVipin KUMAR } 561