15b1b1883SVipin KUMAR /* 25b1b1883SVipin KUMAR * (C) Copyright 2010 35b1b1883SVipin KUMAR * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com. 45b1b1883SVipin KUMAR * 55b1b1883SVipin KUMAR * See file CREDITS for list of people who contributed to this 65b1b1883SVipin KUMAR * project. 75b1b1883SVipin KUMAR * 85b1b1883SVipin KUMAR * This program is free software; you can redistribute it and/or 95b1b1883SVipin KUMAR * modify it under the terms of the GNU General Public License as 105b1b1883SVipin KUMAR * published by the Free Software Foundation; either version 2 of 115b1b1883SVipin KUMAR * the License, or (at your option) any later version. 125b1b1883SVipin KUMAR * 135b1b1883SVipin KUMAR * This program is distributed in the hope that it will be useful, 145b1b1883SVipin KUMAR * but WITHOUT ANY WARRANTY; without even the implied warranty of 155b1b1883SVipin KUMAR * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 165b1b1883SVipin KUMAR * GNU General Public License for more details. 175b1b1883SVipin KUMAR * 185b1b1883SVipin KUMAR * You should have received a copy of the GNU General Public License 195b1b1883SVipin KUMAR * along with this program; if not, write to the Free Software 205b1b1883SVipin KUMAR * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 215b1b1883SVipin KUMAR * MA 02111-1307 USA 225b1b1883SVipin KUMAR */ 235b1b1883SVipin KUMAR 245b1b1883SVipin KUMAR /* 255b1b1883SVipin KUMAR * Designware ethernet IP driver for u-boot 265b1b1883SVipin KUMAR */ 275b1b1883SVipin KUMAR 285b1b1883SVipin KUMAR #include <common.h> 295b1b1883SVipin KUMAR #include <miiphy.h> 305b1b1883SVipin KUMAR #include <malloc.h> 315b1b1883SVipin KUMAR #include <linux/err.h> 325b1b1883SVipin KUMAR #include <asm/io.h> 335b1b1883SVipin KUMAR #include "designware.h" 345b1b1883SVipin KUMAR 35*13edd170SVipin Kumar static int configure_phy(struct eth_device *dev); 36*13edd170SVipin Kumar 375b1b1883SVipin KUMAR static void tx_descs_init(struct eth_device *dev) 385b1b1883SVipin KUMAR { 395b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 405b1b1883SVipin KUMAR struct eth_dma_regs *dma_p = priv->dma_regs_p; 415b1b1883SVipin KUMAR struct dmamacdescr *desc_table_p = &priv->tx_mac_descrtable[0]; 425b1b1883SVipin KUMAR char *txbuffs = &priv->txbuffs[0]; 435b1b1883SVipin KUMAR struct dmamacdescr *desc_p; 445b1b1883SVipin KUMAR u32 idx; 455b1b1883SVipin KUMAR 465b1b1883SVipin KUMAR for (idx = 0; idx < CONFIG_TX_DESCR_NUM; idx++) { 475b1b1883SVipin KUMAR desc_p = &desc_table_p[idx]; 485b1b1883SVipin KUMAR desc_p->dmamac_addr = &txbuffs[idx * CONFIG_ETH_BUFSIZE]; 495b1b1883SVipin KUMAR desc_p->dmamac_next = &desc_table_p[idx + 1]; 505b1b1883SVipin KUMAR 515b1b1883SVipin KUMAR #if defined(CONFIG_DW_ALTDESCRIPTOR) 525b1b1883SVipin KUMAR desc_p->txrx_status &= ~(DESC_TXSTS_TXINT | DESC_TXSTS_TXLAST | 535b1b1883SVipin KUMAR DESC_TXSTS_TXFIRST | DESC_TXSTS_TXCRCDIS | \ 545b1b1883SVipin KUMAR DESC_TXSTS_TXCHECKINSCTRL | \ 555b1b1883SVipin KUMAR DESC_TXSTS_TXRINGEND | DESC_TXSTS_TXPADDIS); 565b1b1883SVipin KUMAR 575b1b1883SVipin KUMAR desc_p->txrx_status |= DESC_TXSTS_TXCHAIN; 585b1b1883SVipin KUMAR desc_p->dmamac_cntl = 0; 595b1b1883SVipin KUMAR desc_p->txrx_status &= ~(DESC_TXSTS_MSK | DESC_TXSTS_OWNBYDMA); 605b1b1883SVipin KUMAR #else 615b1b1883SVipin KUMAR desc_p->dmamac_cntl = DESC_TXCTRL_TXCHAIN; 625b1b1883SVipin KUMAR desc_p->txrx_status = 0; 635b1b1883SVipin KUMAR #endif 645b1b1883SVipin KUMAR } 655b1b1883SVipin KUMAR 665b1b1883SVipin KUMAR /* Correcting the last pointer of the chain */ 675b1b1883SVipin KUMAR desc_p->dmamac_next = &desc_table_p[0]; 685b1b1883SVipin KUMAR 695b1b1883SVipin KUMAR writel((ulong)&desc_table_p[0], &dma_p->txdesclistaddr); 705b1b1883SVipin KUMAR } 715b1b1883SVipin KUMAR 725b1b1883SVipin KUMAR static void rx_descs_init(struct eth_device *dev) 735b1b1883SVipin KUMAR { 745b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 755b1b1883SVipin KUMAR struct eth_dma_regs *dma_p = priv->dma_regs_p; 765b1b1883SVipin KUMAR struct dmamacdescr *desc_table_p = &priv->rx_mac_descrtable[0]; 775b1b1883SVipin KUMAR char *rxbuffs = &priv->rxbuffs[0]; 785b1b1883SVipin KUMAR struct dmamacdescr *desc_p; 795b1b1883SVipin KUMAR u32 idx; 805b1b1883SVipin KUMAR 815b1b1883SVipin KUMAR for (idx = 0; idx < CONFIG_RX_DESCR_NUM; idx++) { 825b1b1883SVipin KUMAR desc_p = &desc_table_p[idx]; 835b1b1883SVipin KUMAR desc_p->dmamac_addr = &rxbuffs[idx * CONFIG_ETH_BUFSIZE]; 845b1b1883SVipin KUMAR desc_p->dmamac_next = &desc_table_p[idx + 1]; 855b1b1883SVipin KUMAR 865b1b1883SVipin KUMAR desc_p->dmamac_cntl = 875b1b1883SVipin KUMAR (MAC_MAX_FRAME_SZ & DESC_RXCTRL_SIZE1MASK) | \ 885b1b1883SVipin KUMAR DESC_RXCTRL_RXCHAIN; 895b1b1883SVipin KUMAR 905b1b1883SVipin KUMAR desc_p->txrx_status = DESC_RXSTS_OWNBYDMA; 915b1b1883SVipin KUMAR } 925b1b1883SVipin KUMAR 935b1b1883SVipin KUMAR /* Correcting the last pointer of the chain */ 945b1b1883SVipin KUMAR desc_p->dmamac_next = &desc_table_p[0]; 955b1b1883SVipin KUMAR 965b1b1883SVipin KUMAR writel((ulong)&desc_table_p[0], &dma_p->rxdesclistaddr); 975b1b1883SVipin KUMAR } 985b1b1883SVipin KUMAR 995b1b1883SVipin KUMAR static void descs_init(struct eth_device *dev) 1005b1b1883SVipin KUMAR { 1015b1b1883SVipin KUMAR tx_descs_init(dev); 1025b1b1883SVipin KUMAR rx_descs_init(dev); 1035b1b1883SVipin KUMAR } 1045b1b1883SVipin KUMAR 1055b1b1883SVipin KUMAR static int mac_reset(struct eth_device *dev) 1065b1b1883SVipin KUMAR { 1075b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 1085b1b1883SVipin KUMAR struct eth_mac_regs *mac_p = priv->mac_regs_p; 1095b1b1883SVipin KUMAR struct eth_dma_regs *dma_p = priv->dma_regs_p; 1105b1b1883SVipin KUMAR 1115b1b1883SVipin KUMAR int timeout = CONFIG_MACRESET_TIMEOUT; 1125b1b1883SVipin KUMAR 1135b1b1883SVipin KUMAR writel(DMAMAC_SRST, &dma_p->busmode); 1145b1b1883SVipin KUMAR writel(MII_PORTSELECT, &mac_p->conf); 1155b1b1883SVipin KUMAR 1165b1b1883SVipin KUMAR do { 1175b1b1883SVipin KUMAR if (!(readl(&dma_p->busmode) & DMAMAC_SRST)) 1185b1b1883SVipin KUMAR return 0; 1195b1b1883SVipin KUMAR udelay(1000); 1205b1b1883SVipin KUMAR } while (timeout--); 1215b1b1883SVipin KUMAR 1225b1b1883SVipin KUMAR return -1; 1235b1b1883SVipin KUMAR } 1245b1b1883SVipin KUMAR 1255b1b1883SVipin KUMAR static int dw_write_hwaddr(struct eth_device *dev) 1265b1b1883SVipin KUMAR { 1275b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 1285b1b1883SVipin KUMAR struct eth_mac_regs *mac_p = priv->mac_regs_p; 1295b1b1883SVipin KUMAR u32 macid_lo, macid_hi; 1305b1b1883SVipin KUMAR u8 *mac_id = &dev->enetaddr[0]; 1315b1b1883SVipin KUMAR 1325b1b1883SVipin KUMAR macid_lo = mac_id[0] + (mac_id[1] << 8) + \ 1335b1b1883SVipin KUMAR (mac_id[2] << 16) + (mac_id[3] << 24); 1345b1b1883SVipin KUMAR macid_hi = mac_id[4] + (mac_id[5] << 8); 1355b1b1883SVipin KUMAR 1365b1b1883SVipin KUMAR writel(macid_hi, &mac_p->macaddr0hi); 1375b1b1883SVipin KUMAR writel(macid_lo, &mac_p->macaddr0lo); 1385b1b1883SVipin KUMAR 1395b1b1883SVipin KUMAR return 0; 1405b1b1883SVipin KUMAR } 1415b1b1883SVipin KUMAR 1425b1b1883SVipin KUMAR static int dw_eth_init(struct eth_device *dev, bd_t *bis) 1435b1b1883SVipin KUMAR { 1445b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 1455b1b1883SVipin KUMAR struct eth_mac_regs *mac_p = priv->mac_regs_p; 1465b1b1883SVipin KUMAR struct eth_dma_regs *dma_p = priv->dma_regs_p; 1475b1b1883SVipin KUMAR u32 conf; 1485b1b1883SVipin KUMAR 149*13edd170SVipin Kumar if (priv->phy_configured != 1) 150*13edd170SVipin Kumar configure_phy(dev); 151*13edd170SVipin Kumar 1525b1b1883SVipin KUMAR /* Reset ethernet hardware */ 1535b1b1883SVipin KUMAR if (mac_reset(dev) < 0) 1545b1b1883SVipin KUMAR return -1; 1555b1b1883SVipin KUMAR 156c7f6dbe7SVipin KUMAR /* Resore the HW MAC address as it has been lost during MAC reset */ 157c7f6dbe7SVipin KUMAR dw_write_hwaddr(dev); 158c7f6dbe7SVipin KUMAR 1595b1b1883SVipin KUMAR writel(FIXEDBURST | PRIORXTX_41 | BURST_16, 1605b1b1883SVipin KUMAR &dma_p->busmode); 1615b1b1883SVipin KUMAR 1625b1b1883SVipin KUMAR writel(FLUSHTXFIFO | readl(&dma_p->opmode), &dma_p->opmode); 1635b1b1883SVipin KUMAR writel(STOREFORWARD | TXSECONDFRAME, &dma_p->opmode); 1645b1b1883SVipin KUMAR 1655b1b1883SVipin KUMAR conf = FRAMEBURSTENABLE | DISABLERXOWN; 1665b1b1883SVipin KUMAR 1675b1b1883SVipin KUMAR if (priv->speed != SPEED_1000M) 1685b1b1883SVipin KUMAR conf |= MII_PORTSELECT; 1695b1b1883SVipin KUMAR 1705b1b1883SVipin KUMAR if (priv->duplex == FULL_DUPLEX) 1715b1b1883SVipin KUMAR conf |= FULLDPLXMODE; 1725b1b1883SVipin KUMAR 1735b1b1883SVipin KUMAR writel(conf, &mac_p->conf); 1745b1b1883SVipin KUMAR 1755b1b1883SVipin KUMAR descs_init(dev); 1765b1b1883SVipin KUMAR 1775b1b1883SVipin KUMAR /* 1785b1b1883SVipin KUMAR * Start/Enable xfer at dma as well as mac level 1795b1b1883SVipin KUMAR */ 1805b1b1883SVipin KUMAR writel(readl(&dma_p->opmode) | RXSTART, &dma_p->opmode); 1815b1b1883SVipin KUMAR writel(readl(&dma_p->opmode) | TXSTART, &dma_p->opmode); 1825b1b1883SVipin KUMAR 183aa51005cSArmando Visconti writel(readl(&mac_p->conf) | RXENABLE | TXENABLE, &mac_p->conf); 1845b1b1883SVipin KUMAR 1855b1b1883SVipin KUMAR return 0; 1865b1b1883SVipin KUMAR } 1875b1b1883SVipin KUMAR 1885b1b1883SVipin KUMAR static int dw_eth_send(struct eth_device *dev, volatile void *packet, 1895b1b1883SVipin KUMAR int length) 1905b1b1883SVipin KUMAR { 1915b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 1925b1b1883SVipin KUMAR struct eth_dma_regs *dma_p = priv->dma_regs_p; 1935b1b1883SVipin KUMAR u32 desc_num = priv->tx_currdescnum; 1945b1b1883SVipin KUMAR struct dmamacdescr *desc_p = &priv->tx_mac_descrtable[desc_num]; 1955b1b1883SVipin KUMAR 1965b1b1883SVipin KUMAR /* Check if the descriptor is owned by CPU */ 1975b1b1883SVipin KUMAR if (desc_p->txrx_status & DESC_TXSTS_OWNBYDMA) { 1985b1b1883SVipin KUMAR printf("CPU not owner of tx frame\n"); 1995b1b1883SVipin KUMAR return -1; 2005b1b1883SVipin KUMAR } 2015b1b1883SVipin KUMAR 2025b1b1883SVipin KUMAR memcpy((void *)desc_p->dmamac_addr, (void *)packet, length); 2035b1b1883SVipin KUMAR 2045b1b1883SVipin KUMAR #if defined(CONFIG_DW_ALTDESCRIPTOR) 2055b1b1883SVipin KUMAR desc_p->txrx_status |= DESC_TXSTS_TXFIRST | DESC_TXSTS_TXLAST; 2065b1b1883SVipin KUMAR desc_p->dmamac_cntl |= (length << DESC_TXCTRL_SIZE1SHFT) & \ 2075b1b1883SVipin KUMAR DESC_TXCTRL_SIZE1MASK; 2085b1b1883SVipin KUMAR 2095b1b1883SVipin KUMAR desc_p->txrx_status &= ~(DESC_TXSTS_MSK); 2105b1b1883SVipin KUMAR desc_p->txrx_status |= DESC_TXSTS_OWNBYDMA; 2115b1b1883SVipin KUMAR #else 2125b1b1883SVipin KUMAR desc_p->dmamac_cntl |= ((length << DESC_TXCTRL_SIZE1SHFT) & \ 2135b1b1883SVipin KUMAR DESC_TXCTRL_SIZE1MASK) | DESC_TXCTRL_TXLAST | \ 2145b1b1883SVipin KUMAR DESC_TXCTRL_TXFIRST; 2155b1b1883SVipin KUMAR 2165b1b1883SVipin KUMAR desc_p->txrx_status = DESC_TXSTS_OWNBYDMA; 2175b1b1883SVipin KUMAR #endif 2185b1b1883SVipin KUMAR 2195b1b1883SVipin KUMAR /* Test the wrap-around condition. */ 2205b1b1883SVipin KUMAR if (++desc_num >= CONFIG_TX_DESCR_NUM) 2215b1b1883SVipin KUMAR desc_num = 0; 2225b1b1883SVipin KUMAR 2235b1b1883SVipin KUMAR priv->tx_currdescnum = desc_num; 2245b1b1883SVipin KUMAR 2255b1b1883SVipin KUMAR /* Start the transmission */ 2265b1b1883SVipin KUMAR writel(POLL_DATA, &dma_p->txpolldemand); 2275b1b1883SVipin KUMAR 2285b1b1883SVipin KUMAR return 0; 2295b1b1883SVipin KUMAR } 2305b1b1883SVipin KUMAR 2315b1b1883SVipin KUMAR static int dw_eth_recv(struct eth_device *dev) 2325b1b1883SVipin KUMAR { 2335b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 2345b1b1883SVipin KUMAR u32 desc_num = priv->rx_currdescnum; 2355b1b1883SVipin KUMAR struct dmamacdescr *desc_p = &priv->rx_mac_descrtable[desc_num]; 2365b1b1883SVipin KUMAR 2375b1b1883SVipin KUMAR u32 status = desc_p->txrx_status; 2385b1b1883SVipin KUMAR int length = 0; 2395b1b1883SVipin KUMAR 2405b1b1883SVipin KUMAR /* Check if the owner is the CPU */ 2415b1b1883SVipin KUMAR if (!(status & DESC_RXSTS_OWNBYDMA)) { 2425b1b1883SVipin KUMAR 2435b1b1883SVipin KUMAR length = (status & DESC_RXSTS_FRMLENMSK) >> \ 2445b1b1883SVipin KUMAR DESC_RXSTS_FRMLENSHFT; 2455b1b1883SVipin KUMAR 2465b1b1883SVipin KUMAR NetReceive(desc_p->dmamac_addr, length); 2475b1b1883SVipin KUMAR 2485b1b1883SVipin KUMAR /* 2495b1b1883SVipin KUMAR * Make the current descriptor valid again and go to 2505b1b1883SVipin KUMAR * the next one 2515b1b1883SVipin KUMAR */ 2525b1b1883SVipin KUMAR desc_p->txrx_status |= DESC_RXSTS_OWNBYDMA; 2535b1b1883SVipin KUMAR 2545b1b1883SVipin KUMAR /* Test the wrap-around condition. */ 2555b1b1883SVipin KUMAR if (++desc_num >= CONFIG_RX_DESCR_NUM) 2565b1b1883SVipin KUMAR desc_num = 0; 2575b1b1883SVipin KUMAR } 2585b1b1883SVipin KUMAR 2595b1b1883SVipin KUMAR priv->rx_currdescnum = desc_num; 2605b1b1883SVipin KUMAR 2615b1b1883SVipin KUMAR return length; 2625b1b1883SVipin KUMAR } 2635b1b1883SVipin KUMAR 2645b1b1883SVipin KUMAR static void dw_eth_halt(struct eth_device *dev) 2655b1b1883SVipin KUMAR { 2665b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 2675b1b1883SVipin KUMAR 2685b1b1883SVipin KUMAR mac_reset(dev); 2695b1b1883SVipin KUMAR priv->tx_currdescnum = priv->rx_currdescnum = 0; 2705b1b1883SVipin KUMAR } 2715b1b1883SVipin KUMAR 2725b1b1883SVipin KUMAR static int eth_mdio_read(struct eth_device *dev, u8 addr, u8 reg, u16 *val) 2735b1b1883SVipin KUMAR { 2745b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 2755b1b1883SVipin KUMAR struct eth_mac_regs *mac_p = priv->mac_regs_p; 2765b1b1883SVipin KUMAR u32 miiaddr; 2775b1b1883SVipin KUMAR int timeout = CONFIG_MDIO_TIMEOUT; 2785b1b1883SVipin KUMAR 2795b1b1883SVipin KUMAR miiaddr = ((addr << MIIADDRSHIFT) & MII_ADDRMSK) | \ 2805b1b1883SVipin KUMAR ((reg << MIIREGSHIFT) & MII_REGMSK); 2815b1b1883SVipin KUMAR 2825b1b1883SVipin KUMAR writel(miiaddr | MII_CLKRANGE_150_250M | MII_BUSY, &mac_p->miiaddr); 2835b1b1883SVipin KUMAR 2845b1b1883SVipin KUMAR do { 2855b1b1883SVipin KUMAR if (!(readl(&mac_p->miiaddr) & MII_BUSY)) { 2865b1b1883SVipin KUMAR *val = readl(&mac_p->miidata); 2875b1b1883SVipin KUMAR return 0; 2885b1b1883SVipin KUMAR } 2895b1b1883SVipin KUMAR udelay(1000); 2905b1b1883SVipin KUMAR } while (timeout--); 2915b1b1883SVipin KUMAR 2925b1b1883SVipin KUMAR return -1; 2935b1b1883SVipin KUMAR } 2945b1b1883SVipin KUMAR 2955b1b1883SVipin KUMAR static int eth_mdio_write(struct eth_device *dev, u8 addr, u8 reg, u16 val) 2965b1b1883SVipin KUMAR { 2975b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 2985b1b1883SVipin KUMAR struct eth_mac_regs *mac_p = priv->mac_regs_p; 2995b1b1883SVipin KUMAR u32 miiaddr; 3005b1b1883SVipin KUMAR int ret = -1, timeout = CONFIG_MDIO_TIMEOUT; 3015b1b1883SVipin KUMAR u16 value; 3025b1b1883SVipin KUMAR 3035b1b1883SVipin KUMAR writel(val, &mac_p->miidata); 3045b1b1883SVipin KUMAR miiaddr = ((addr << MIIADDRSHIFT) & MII_ADDRMSK) | \ 3055b1b1883SVipin KUMAR ((reg << MIIREGSHIFT) & MII_REGMSK) | MII_WRITE; 3065b1b1883SVipin KUMAR 3075b1b1883SVipin KUMAR writel(miiaddr | MII_CLKRANGE_150_250M | MII_BUSY, &mac_p->miiaddr); 3085b1b1883SVipin KUMAR 3095b1b1883SVipin KUMAR do { 310c7f6dbe7SVipin KUMAR if (!(readl(&mac_p->miiaddr) & MII_BUSY)) { 3115b1b1883SVipin KUMAR ret = 0; 312c7f6dbe7SVipin KUMAR break; 313c7f6dbe7SVipin KUMAR } 3145b1b1883SVipin KUMAR udelay(1000); 3155b1b1883SVipin KUMAR } while (timeout--); 3165b1b1883SVipin KUMAR 3175b1b1883SVipin KUMAR /* Needed as a fix for ST-Phy */ 3185b1b1883SVipin KUMAR eth_mdio_read(dev, addr, reg, &value); 3195b1b1883SVipin KUMAR 3205b1b1883SVipin KUMAR return ret; 3215b1b1883SVipin KUMAR } 3225b1b1883SVipin KUMAR 3235b1b1883SVipin KUMAR #if defined(CONFIG_DW_SEARCH_PHY) 3245b1b1883SVipin KUMAR static int find_phy(struct eth_device *dev) 3255b1b1883SVipin KUMAR { 3265b1b1883SVipin KUMAR int phy_addr = 0; 3275b1b1883SVipin KUMAR u16 ctrl, oldctrl; 3285b1b1883SVipin KUMAR 3295b1b1883SVipin KUMAR do { 3308ef583a0SMike Frysinger eth_mdio_read(dev, phy_addr, MII_BMCR, &ctrl); 3318ef583a0SMike Frysinger oldctrl = ctrl & BMCR_ANENABLE; 3325b1b1883SVipin KUMAR 3338ef583a0SMike Frysinger ctrl ^= BMCR_ANENABLE; 3348ef583a0SMike Frysinger eth_mdio_write(dev, phy_addr, MII_BMCR, ctrl); 3358ef583a0SMike Frysinger eth_mdio_read(dev, phy_addr, MII_BMCR, &ctrl); 3368ef583a0SMike Frysinger ctrl &= BMCR_ANENABLE; 3375b1b1883SVipin KUMAR 3385b1b1883SVipin KUMAR if (ctrl == oldctrl) { 3395b1b1883SVipin KUMAR phy_addr++; 3405b1b1883SVipin KUMAR } else { 3418ef583a0SMike Frysinger ctrl ^= BMCR_ANENABLE; 3428ef583a0SMike Frysinger eth_mdio_write(dev, phy_addr, MII_BMCR, ctrl); 3435b1b1883SVipin KUMAR 3445b1b1883SVipin KUMAR return phy_addr; 3455b1b1883SVipin KUMAR } 3465b1b1883SVipin KUMAR } while (phy_addr < 32); 3475b1b1883SVipin KUMAR 3485b1b1883SVipin KUMAR return -1; 3495b1b1883SVipin KUMAR } 3505b1b1883SVipin KUMAR #endif 3515b1b1883SVipin KUMAR 3525b1b1883SVipin KUMAR static int dw_reset_phy(struct eth_device *dev) 3535b1b1883SVipin KUMAR { 3545b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 3555b1b1883SVipin KUMAR u16 ctrl; 3565b1b1883SVipin KUMAR int timeout = CONFIG_PHYRESET_TIMEOUT; 3575b1b1883SVipin KUMAR u32 phy_addr = priv->address; 3585b1b1883SVipin KUMAR 3598ef583a0SMike Frysinger eth_mdio_write(dev, phy_addr, MII_BMCR, BMCR_RESET); 3605b1b1883SVipin KUMAR do { 3618ef583a0SMike Frysinger eth_mdio_read(dev, phy_addr, MII_BMCR, &ctrl); 3628ef583a0SMike Frysinger if (!(ctrl & BMCR_RESET)) 3635b1b1883SVipin KUMAR break; 3645b1b1883SVipin KUMAR udelay(1000); 3655b1b1883SVipin KUMAR } while (timeout--); 3665b1b1883SVipin KUMAR 3675b1b1883SVipin KUMAR if (timeout < 0) 3685b1b1883SVipin KUMAR return -1; 3695b1b1883SVipin KUMAR 3705b1b1883SVipin KUMAR #ifdef CONFIG_PHY_RESET_DELAY 3715b1b1883SVipin KUMAR udelay(CONFIG_PHY_RESET_DELAY); 3725b1b1883SVipin KUMAR #endif 3735b1b1883SVipin KUMAR return 0; 3745b1b1883SVipin KUMAR } 3755b1b1883SVipin KUMAR 3765b1b1883SVipin KUMAR static int configure_phy(struct eth_device *dev) 3775b1b1883SVipin KUMAR { 3785b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 3795b1b1883SVipin KUMAR int phy_addr; 380ee7f5bfdSMike Frysinger u16 bmcr; 3815b1b1883SVipin KUMAR #if defined(CONFIG_DW_AUTONEG) 3825b1b1883SVipin KUMAR u16 bmsr; 3835b1b1883SVipin KUMAR u32 timeout; 3845b1b1883SVipin KUMAR u16 anlpar, btsr; 385ee7f5bfdSMike Frysinger #else 386ee7f5bfdSMike Frysinger u16 ctrl; 3875b1b1883SVipin KUMAR #endif 3885b1b1883SVipin KUMAR 3895b1b1883SVipin KUMAR #if defined(CONFIG_DW_SEARCH_PHY) 3905b1b1883SVipin KUMAR phy_addr = find_phy(dev); 391024333c9SVipin KUMAR if (phy_addr >= 0) 3925b1b1883SVipin KUMAR priv->address = phy_addr; 3935b1b1883SVipin KUMAR else 3945b1b1883SVipin KUMAR return -1; 395f0ece9e9SMike Frysinger #else 396f0ece9e9SMike Frysinger phy_addr = priv->address; 3975b1b1883SVipin KUMAR #endif 3985b1b1883SVipin KUMAR if (dw_reset_phy(dev) < 0) 3995b1b1883SVipin KUMAR return -1; 4005b1b1883SVipin KUMAR 4015b1b1883SVipin KUMAR #if defined(CONFIG_DW_AUTONEG) 4028ef583a0SMike Frysinger bmcr = BMCR_ANENABLE | BMCR_ANRESTART | BMCR_SPEED100 | \ 4038ef583a0SMike Frysinger BMCR_FULLDPLX | BMCR_SPEED1000; 4045b1b1883SVipin KUMAR #else 4058ef583a0SMike Frysinger bmcr = BMCR_SPEED100 | BMCR_FULLDPLX; 4065b1b1883SVipin KUMAR 4075b1b1883SVipin KUMAR #if defined(CONFIG_DW_SPEED10M) 4088ef583a0SMike Frysinger bmcr &= ~BMCR_SPEED100; 4095b1b1883SVipin KUMAR #endif 4105b1b1883SVipin KUMAR #if defined(CONFIG_DW_DUPLEXHALF) 4118ef583a0SMike Frysinger bmcr &= ~BMCR_FULLDPLX; 4125b1b1883SVipin KUMAR #endif 4135b1b1883SVipin KUMAR #endif 4148ef583a0SMike Frysinger if (eth_mdio_write(dev, phy_addr, MII_BMCR, bmcr) < 0) 4155b1b1883SVipin KUMAR return -1; 4165b1b1883SVipin KUMAR 4175b1b1883SVipin KUMAR /* Read the phy status register and populate priv structure */ 4185b1b1883SVipin KUMAR #if defined(CONFIG_DW_AUTONEG) 4195b1b1883SVipin KUMAR timeout = CONFIG_AUTONEG_TIMEOUT; 4205b1b1883SVipin KUMAR do { 4218ef583a0SMike Frysinger eth_mdio_read(dev, phy_addr, MII_BMSR, &bmsr); 4228ef583a0SMike Frysinger if (bmsr & BMSR_ANEGCOMPLETE) 4235b1b1883SVipin KUMAR break; 4245b1b1883SVipin KUMAR udelay(1000); 4255b1b1883SVipin KUMAR } while (timeout--); 4265b1b1883SVipin KUMAR 4278ef583a0SMike Frysinger eth_mdio_read(dev, phy_addr, MII_LPA, &anlpar); 4288ef583a0SMike Frysinger eth_mdio_read(dev, phy_addr, MII_STAT1000, &btsr); 4295b1b1883SVipin KUMAR 430*13edd170SVipin Kumar if (bmsr & BMSR_ANEGCOMPLETE) { 4315b1b1883SVipin KUMAR if (btsr & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD)) { 4325b1b1883SVipin KUMAR priv->speed = SPEED_1000M; 4335b1b1883SVipin KUMAR if (btsr & PHY_1000BTSR_1000FD) 4345b1b1883SVipin KUMAR priv->duplex = FULL_DUPLEX; 4355b1b1883SVipin KUMAR else 4365b1b1883SVipin KUMAR priv->duplex = HALF_DUPLEX; 4375b1b1883SVipin KUMAR } else { 4388ef583a0SMike Frysinger if (anlpar & LPA_100) 4395b1b1883SVipin KUMAR priv->speed = SPEED_100M; 4405b1b1883SVipin KUMAR else 4415b1b1883SVipin KUMAR priv->speed = SPEED_10M; 4425b1b1883SVipin KUMAR 4438ef583a0SMike Frysinger if (anlpar & (LPA_10FULL | LPA_100FULL)) 4445b1b1883SVipin KUMAR priv->duplex = FULL_DUPLEX; 4455b1b1883SVipin KUMAR else 4465b1b1883SVipin KUMAR priv->duplex = HALF_DUPLEX; 4475b1b1883SVipin KUMAR } 448*13edd170SVipin Kumar } else 449*13edd170SVipin Kumar return -1; 4505b1b1883SVipin KUMAR #else 4518ef583a0SMike Frysinger if (eth_mdio_read(dev, phy_addr, MII_BMCR, &ctrl) < 0) 4525b1b1883SVipin KUMAR return -1; 4535b1b1883SVipin KUMAR 4548ef583a0SMike Frysinger if (ctrl & BMCR_FULLDPLX) 4555b1b1883SVipin KUMAR priv->duplex = FULL_DUPLEX; 4565b1b1883SVipin KUMAR else 4575b1b1883SVipin KUMAR priv->duplex = HALF_DUPLEX; 4585b1b1883SVipin KUMAR 4598ef583a0SMike Frysinger if (ctrl & BMCR_SPEED1000) 4605b1b1883SVipin KUMAR priv->speed = SPEED_1000M; 4618ef583a0SMike Frysinger else if (ctrl & BMCR_SPEED100) 4625b1b1883SVipin KUMAR priv->speed = SPEED_100M; 4635b1b1883SVipin KUMAR else 4645b1b1883SVipin KUMAR priv->speed = SPEED_10M; 4655b1b1883SVipin KUMAR #endif 466*13edd170SVipin Kumar priv->phy_configured = 1; 467*13edd170SVipin Kumar 4685b1b1883SVipin KUMAR return 0; 4695b1b1883SVipin KUMAR } 4705b1b1883SVipin KUMAR 4715b1b1883SVipin KUMAR #if defined(CONFIG_MII) 4725700bb63SMike Frysinger static int dw_mii_read(const char *devname, u8 addr, u8 reg, u16 *val) 4735b1b1883SVipin KUMAR { 4745b1b1883SVipin KUMAR struct eth_device *dev; 4755b1b1883SVipin KUMAR 4765b1b1883SVipin KUMAR dev = eth_get_dev_by_name(devname); 4775b1b1883SVipin KUMAR if (dev) 4785b1b1883SVipin KUMAR eth_mdio_read(dev, addr, reg, val); 4795b1b1883SVipin KUMAR 4805b1b1883SVipin KUMAR return 0; 4815b1b1883SVipin KUMAR } 4825b1b1883SVipin KUMAR 4835700bb63SMike Frysinger static int dw_mii_write(const char *devname, u8 addr, u8 reg, u16 val) 4845b1b1883SVipin KUMAR { 4855b1b1883SVipin KUMAR struct eth_device *dev; 4865b1b1883SVipin KUMAR 4875b1b1883SVipin KUMAR dev = eth_get_dev_by_name(devname); 4885b1b1883SVipin KUMAR if (dev) 4895b1b1883SVipin KUMAR eth_mdio_write(dev, addr, reg, val); 4905b1b1883SVipin KUMAR 4915b1b1883SVipin KUMAR return 0; 4925b1b1883SVipin KUMAR } 4935b1b1883SVipin KUMAR #endif 4945b1b1883SVipin KUMAR 4955b1b1883SVipin KUMAR int designware_initialize(u32 id, ulong base_addr, u32 phy_addr) 4965b1b1883SVipin KUMAR { 4975b1b1883SVipin KUMAR struct eth_device *dev; 4985b1b1883SVipin KUMAR struct dw_eth_dev *priv; 4995b1b1883SVipin KUMAR 5005b1b1883SVipin KUMAR dev = (struct eth_device *) malloc(sizeof(struct eth_device)); 5015b1b1883SVipin KUMAR if (!dev) 5025b1b1883SVipin KUMAR return -ENOMEM; 5035b1b1883SVipin KUMAR 5045b1b1883SVipin KUMAR /* 5055b1b1883SVipin KUMAR * Since the priv structure contains the descriptors which need a strict 5065b1b1883SVipin KUMAR * buswidth alignment, memalign is used to allocate memory 5075b1b1883SVipin KUMAR */ 5085b1b1883SVipin KUMAR priv = (struct dw_eth_dev *) memalign(16, sizeof(struct dw_eth_dev)); 5095b1b1883SVipin KUMAR if (!priv) { 5105b1b1883SVipin KUMAR free(dev); 5115b1b1883SVipin KUMAR return -ENOMEM; 5125b1b1883SVipin KUMAR } 5135b1b1883SVipin KUMAR 5145b1b1883SVipin KUMAR memset(dev, 0, sizeof(struct eth_device)); 5155b1b1883SVipin KUMAR memset(priv, 0, sizeof(struct dw_eth_dev)); 5165b1b1883SVipin KUMAR 5175b1b1883SVipin KUMAR sprintf(dev->name, "mii%d", id); 5185b1b1883SVipin KUMAR dev->iobase = (int)base_addr; 5195b1b1883SVipin KUMAR dev->priv = priv; 5205b1b1883SVipin KUMAR 5217616e785SSimon Glass eth_getenv_enetaddr_by_index("eth", id, &dev->enetaddr[0]); 5225b1b1883SVipin KUMAR 5235b1b1883SVipin KUMAR priv->dev = dev; 5245b1b1883SVipin KUMAR priv->mac_regs_p = (struct eth_mac_regs *)base_addr; 5255b1b1883SVipin KUMAR priv->dma_regs_p = (struct eth_dma_regs *)(base_addr + 5265b1b1883SVipin KUMAR DW_DMA_BASE_OFFSET); 5275b1b1883SVipin KUMAR priv->address = phy_addr; 528*13edd170SVipin Kumar priv->phy_configured = 0; 5295b1b1883SVipin KUMAR 5305b1b1883SVipin KUMAR if (mac_reset(dev) < 0) 5315b1b1883SVipin KUMAR return -1; 5325b1b1883SVipin KUMAR 533*13edd170SVipin Kumar configure_phy(dev); 5345b1b1883SVipin KUMAR 5355b1b1883SVipin KUMAR dev->init = dw_eth_init; 5365b1b1883SVipin KUMAR dev->send = dw_eth_send; 5375b1b1883SVipin KUMAR dev->recv = dw_eth_recv; 5385b1b1883SVipin KUMAR dev->halt = dw_eth_halt; 5395b1b1883SVipin KUMAR dev->write_hwaddr = dw_write_hwaddr; 5405b1b1883SVipin KUMAR 5415b1b1883SVipin KUMAR eth_register(dev); 5425b1b1883SVipin KUMAR 5435b1b1883SVipin KUMAR #if defined(CONFIG_MII) 5445b1b1883SVipin KUMAR miiphy_register(dev->name, dw_mii_read, dw_mii_write); 5455b1b1883SVipin KUMAR #endif 5465b1b1883SVipin KUMAR return 1; 5475b1b1883SVipin KUMAR } 548