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 3513edd170SVipin Kumar static int configure_phy(struct eth_device *dev); 3613edd170SVipin 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 14913edd170SVipin Kumar if (priv->phy_configured != 1) 15013edd170SVipin Kumar configure_phy(dev); 15113edd170SVipin 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) 402*20a5dde1SArmando Visconti /* Set Auto-Neg Advertisement capabilities to 10/100 half/full */ 403*20a5dde1SArmando Visconti eth_mdio_write(dev, phy_addr, MII_ADVERTISE, 0x1E1); 404*20a5dde1SArmando Visconti 405e25c90b4SVikas Manocha bmcr = BMCR_ANENABLE | BMCR_ANRESTART; 4065b1b1883SVipin KUMAR #else 4078ef583a0SMike Frysinger bmcr = BMCR_SPEED100 | BMCR_FULLDPLX; 4085b1b1883SVipin KUMAR 4095b1b1883SVipin KUMAR #if defined(CONFIG_DW_SPEED10M) 4108ef583a0SMike Frysinger bmcr &= ~BMCR_SPEED100; 4115b1b1883SVipin KUMAR #endif 4125b1b1883SVipin KUMAR #if defined(CONFIG_DW_DUPLEXHALF) 4138ef583a0SMike Frysinger bmcr &= ~BMCR_FULLDPLX; 4145b1b1883SVipin KUMAR #endif 4155b1b1883SVipin KUMAR #endif 4168ef583a0SMike Frysinger if (eth_mdio_write(dev, phy_addr, MII_BMCR, bmcr) < 0) 4175b1b1883SVipin KUMAR return -1; 4185b1b1883SVipin KUMAR 4195b1b1883SVipin KUMAR /* Read the phy status register and populate priv structure */ 4205b1b1883SVipin KUMAR #if defined(CONFIG_DW_AUTONEG) 4215b1b1883SVipin KUMAR timeout = CONFIG_AUTONEG_TIMEOUT; 4225b1b1883SVipin KUMAR do { 4238ef583a0SMike Frysinger eth_mdio_read(dev, phy_addr, MII_BMSR, &bmsr); 4248ef583a0SMike Frysinger if (bmsr & BMSR_ANEGCOMPLETE) 4255b1b1883SVipin KUMAR break; 4265b1b1883SVipin KUMAR udelay(1000); 4275b1b1883SVipin KUMAR } while (timeout--); 4285b1b1883SVipin KUMAR 4298ef583a0SMike Frysinger eth_mdio_read(dev, phy_addr, MII_LPA, &anlpar); 4308ef583a0SMike Frysinger eth_mdio_read(dev, phy_addr, MII_STAT1000, &btsr); 4315b1b1883SVipin KUMAR 43213edd170SVipin Kumar if (bmsr & BMSR_ANEGCOMPLETE) { 433e25c90b4SVikas Manocha if (btsr & PHY_1000BTSR_1000FD) { 4345b1b1883SVipin KUMAR priv->speed = SPEED_1000M; 435e25c90b4SVikas Manocha bmcr |= BMCR_SPEED1000; 4365b1b1883SVipin KUMAR priv->duplex = FULL_DUPLEX; 437e25c90b4SVikas Manocha bmcr |= BMCR_FULLDPLX; 438e25c90b4SVikas Manocha } else if (btsr & PHY_1000BTSR_1000HD) { 439e25c90b4SVikas Manocha priv->speed = SPEED_1000M; 440e25c90b4SVikas Manocha bmcr |= BMCR_SPEED1000; 4415b1b1883SVipin KUMAR priv->duplex = HALF_DUPLEX; 442e25c90b4SVikas Manocha bmcr &= ~BMCR_FULLDPLX; 443e25c90b4SVikas Manocha } else if (anlpar & LPA_100FULL) { 4445b1b1883SVipin KUMAR priv->speed = SPEED_100M; 445e25c90b4SVikas Manocha bmcr |= BMCR_SPEED100; 4465b1b1883SVipin KUMAR priv->duplex = FULL_DUPLEX; 447e25c90b4SVikas Manocha bmcr |= BMCR_FULLDPLX; 448e25c90b4SVikas Manocha } else if (anlpar & LPA_100HALF) { 449e25c90b4SVikas Manocha priv->speed = SPEED_100M; 450e25c90b4SVikas Manocha bmcr |= BMCR_SPEED100; 4515b1b1883SVipin KUMAR priv->duplex = HALF_DUPLEX; 452e25c90b4SVikas Manocha bmcr &= ~BMCR_FULLDPLX; 453e25c90b4SVikas Manocha } else if (anlpar & LPA_10FULL) { 454e25c90b4SVikas Manocha priv->speed = SPEED_10M; 455e25c90b4SVikas Manocha bmcr &= ~BMCR_SPEED100; 456e25c90b4SVikas Manocha priv->duplex = FULL_DUPLEX; 457e25c90b4SVikas Manocha bmcr |= BMCR_FULLDPLX; 458e25c90b4SVikas Manocha } else { 459e25c90b4SVikas Manocha priv->speed = SPEED_10M; 460e25c90b4SVikas Manocha bmcr &= ~BMCR_SPEED100; 461e25c90b4SVikas Manocha priv->duplex = HALF_DUPLEX; 462e25c90b4SVikas Manocha bmcr &= ~BMCR_FULLDPLX; 4635b1b1883SVipin KUMAR } 464e25c90b4SVikas Manocha if (eth_mdio_write(dev, phy_addr, MII_BMCR, bmcr) < 0) 465e25c90b4SVikas Manocha return -1; 46613edd170SVipin Kumar } else 46713edd170SVipin Kumar return -1; 4685b1b1883SVipin KUMAR #else 4698ef583a0SMike Frysinger if (eth_mdio_read(dev, phy_addr, MII_BMCR, &ctrl) < 0) 4705b1b1883SVipin KUMAR return -1; 4715b1b1883SVipin KUMAR 4728ef583a0SMike Frysinger if (ctrl & BMCR_FULLDPLX) 4735b1b1883SVipin KUMAR priv->duplex = FULL_DUPLEX; 4745b1b1883SVipin KUMAR else 4755b1b1883SVipin KUMAR priv->duplex = HALF_DUPLEX; 4765b1b1883SVipin KUMAR 4778ef583a0SMike Frysinger if (ctrl & BMCR_SPEED1000) 4785b1b1883SVipin KUMAR priv->speed = SPEED_1000M; 4798ef583a0SMike Frysinger else if (ctrl & BMCR_SPEED100) 4805b1b1883SVipin KUMAR priv->speed = SPEED_100M; 4815b1b1883SVipin KUMAR else 4825b1b1883SVipin KUMAR priv->speed = SPEED_10M; 4835b1b1883SVipin KUMAR #endif 48413edd170SVipin Kumar priv->phy_configured = 1; 48513edd170SVipin Kumar 4865b1b1883SVipin KUMAR return 0; 4875b1b1883SVipin KUMAR } 4885b1b1883SVipin KUMAR 4895b1b1883SVipin KUMAR #if defined(CONFIG_MII) 4905700bb63SMike Frysinger static int dw_mii_read(const char *devname, u8 addr, u8 reg, u16 *val) 4915b1b1883SVipin KUMAR { 4925b1b1883SVipin KUMAR struct eth_device *dev; 4935b1b1883SVipin KUMAR 4945b1b1883SVipin KUMAR dev = eth_get_dev_by_name(devname); 4955b1b1883SVipin KUMAR if (dev) 4965b1b1883SVipin KUMAR eth_mdio_read(dev, addr, reg, val); 4975b1b1883SVipin KUMAR 4985b1b1883SVipin KUMAR return 0; 4995b1b1883SVipin KUMAR } 5005b1b1883SVipin KUMAR 5015700bb63SMike Frysinger static int dw_mii_write(const char *devname, u8 addr, u8 reg, u16 val) 5025b1b1883SVipin KUMAR { 5035b1b1883SVipin KUMAR struct eth_device *dev; 5045b1b1883SVipin KUMAR 5055b1b1883SVipin KUMAR dev = eth_get_dev_by_name(devname); 5065b1b1883SVipin KUMAR if (dev) 5075b1b1883SVipin KUMAR eth_mdio_write(dev, addr, reg, val); 5085b1b1883SVipin KUMAR 5095b1b1883SVipin KUMAR return 0; 5105b1b1883SVipin KUMAR } 5115b1b1883SVipin KUMAR #endif 5125b1b1883SVipin KUMAR 5135b1b1883SVipin KUMAR int designware_initialize(u32 id, ulong base_addr, u32 phy_addr) 5145b1b1883SVipin KUMAR { 5155b1b1883SVipin KUMAR struct eth_device *dev; 5165b1b1883SVipin KUMAR struct dw_eth_dev *priv; 5175b1b1883SVipin KUMAR 5185b1b1883SVipin KUMAR dev = (struct eth_device *) malloc(sizeof(struct eth_device)); 5195b1b1883SVipin KUMAR if (!dev) 5205b1b1883SVipin KUMAR return -ENOMEM; 5215b1b1883SVipin KUMAR 5225b1b1883SVipin KUMAR /* 5235b1b1883SVipin KUMAR * Since the priv structure contains the descriptors which need a strict 5245b1b1883SVipin KUMAR * buswidth alignment, memalign is used to allocate memory 5255b1b1883SVipin KUMAR */ 5265b1b1883SVipin KUMAR priv = (struct dw_eth_dev *) memalign(16, sizeof(struct dw_eth_dev)); 5275b1b1883SVipin KUMAR if (!priv) { 5285b1b1883SVipin KUMAR free(dev); 5295b1b1883SVipin KUMAR return -ENOMEM; 5305b1b1883SVipin KUMAR } 5315b1b1883SVipin KUMAR 5325b1b1883SVipin KUMAR memset(dev, 0, sizeof(struct eth_device)); 5335b1b1883SVipin KUMAR memset(priv, 0, sizeof(struct dw_eth_dev)); 5345b1b1883SVipin KUMAR 5355b1b1883SVipin KUMAR sprintf(dev->name, "mii%d", id); 5365b1b1883SVipin KUMAR dev->iobase = (int)base_addr; 5375b1b1883SVipin KUMAR dev->priv = priv; 5385b1b1883SVipin KUMAR 5397616e785SSimon Glass eth_getenv_enetaddr_by_index("eth", id, &dev->enetaddr[0]); 5405b1b1883SVipin KUMAR 5415b1b1883SVipin KUMAR priv->dev = dev; 5425b1b1883SVipin KUMAR priv->mac_regs_p = (struct eth_mac_regs *)base_addr; 5435b1b1883SVipin KUMAR priv->dma_regs_p = (struct eth_dma_regs *)(base_addr + 5445b1b1883SVipin KUMAR DW_DMA_BASE_OFFSET); 5455b1b1883SVipin KUMAR priv->address = phy_addr; 54613edd170SVipin Kumar priv->phy_configured = 0; 5475b1b1883SVipin KUMAR 5485b1b1883SVipin KUMAR if (mac_reset(dev) < 0) 5495b1b1883SVipin KUMAR return -1; 5505b1b1883SVipin KUMAR 55113edd170SVipin Kumar configure_phy(dev); 5525b1b1883SVipin KUMAR 5535b1b1883SVipin KUMAR dev->init = dw_eth_init; 5545b1b1883SVipin KUMAR dev->send = dw_eth_send; 5555b1b1883SVipin KUMAR dev->recv = dw_eth_recv; 5565b1b1883SVipin KUMAR dev->halt = dw_eth_halt; 5575b1b1883SVipin KUMAR dev->write_hwaddr = dw_write_hwaddr; 5585b1b1883SVipin KUMAR 5595b1b1883SVipin KUMAR eth_register(dev); 5605b1b1883SVipin KUMAR 5615b1b1883SVipin KUMAR #if defined(CONFIG_MII) 5625b1b1883SVipin KUMAR miiphy_register(dev->name, dw_mii_read, dw_mii_write); 5635b1b1883SVipin KUMAR #endif 5645b1b1883SVipin KUMAR return 1; 5655b1b1883SVipin KUMAR } 566