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 355b1b1883SVipin KUMAR static void tx_descs_init(struct eth_device *dev) 365b1b1883SVipin KUMAR { 375b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 385b1b1883SVipin KUMAR struct eth_dma_regs *dma_p = priv->dma_regs_p; 395b1b1883SVipin KUMAR struct dmamacdescr *desc_table_p = &priv->tx_mac_descrtable[0]; 405b1b1883SVipin KUMAR char *txbuffs = &priv->txbuffs[0]; 415b1b1883SVipin KUMAR struct dmamacdescr *desc_p; 425b1b1883SVipin KUMAR u32 idx; 435b1b1883SVipin KUMAR 445b1b1883SVipin KUMAR for (idx = 0; idx < CONFIG_TX_DESCR_NUM; idx++) { 455b1b1883SVipin KUMAR desc_p = &desc_table_p[idx]; 465b1b1883SVipin KUMAR desc_p->dmamac_addr = &txbuffs[idx * CONFIG_ETH_BUFSIZE]; 475b1b1883SVipin KUMAR desc_p->dmamac_next = &desc_table_p[idx + 1]; 485b1b1883SVipin KUMAR 495b1b1883SVipin KUMAR #if defined(CONFIG_DW_ALTDESCRIPTOR) 505b1b1883SVipin KUMAR desc_p->txrx_status &= ~(DESC_TXSTS_TXINT | DESC_TXSTS_TXLAST | 515b1b1883SVipin KUMAR DESC_TXSTS_TXFIRST | DESC_TXSTS_TXCRCDIS | \ 525b1b1883SVipin KUMAR DESC_TXSTS_TXCHECKINSCTRL | \ 535b1b1883SVipin KUMAR DESC_TXSTS_TXRINGEND | DESC_TXSTS_TXPADDIS); 545b1b1883SVipin KUMAR 555b1b1883SVipin KUMAR desc_p->txrx_status |= DESC_TXSTS_TXCHAIN; 565b1b1883SVipin KUMAR desc_p->dmamac_cntl = 0; 575b1b1883SVipin KUMAR desc_p->txrx_status &= ~(DESC_TXSTS_MSK | DESC_TXSTS_OWNBYDMA); 585b1b1883SVipin KUMAR #else 595b1b1883SVipin KUMAR desc_p->dmamac_cntl = DESC_TXCTRL_TXCHAIN; 605b1b1883SVipin KUMAR desc_p->txrx_status = 0; 615b1b1883SVipin KUMAR #endif 625b1b1883SVipin KUMAR } 635b1b1883SVipin KUMAR 645b1b1883SVipin KUMAR /* Correcting the last pointer of the chain */ 655b1b1883SVipin KUMAR desc_p->dmamac_next = &desc_table_p[0]; 665b1b1883SVipin KUMAR 675b1b1883SVipin KUMAR writel((ulong)&desc_table_p[0], &dma_p->txdesclistaddr); 685b1b1883SVipin KUMAR } 695b1b1883SVipin KUMAR 705b1b1883SVipin KUMAR static void rx_descs_init(struct eth_device *dev) 715b1b1883SVipin KUMAR { 725b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 735b1b1883SVipin KUMAR struct eth_dma_regs *dma_p = priv->dma_regs_p; 745b1b1883SVipin KUMAR struct dmamacdescr *desc_table_p = &priv->rx_mac_descrtable[0]; 755b1b1883SVipin KUMAR char *rxbuffs = &priv->rxbuffs[0]; 765b1b1883SVipin KUMAR struct dmamacdescr *desc_p; 775b1b1883SVipin KUMAR u32 idx; 785b1b1883SVipin KUMAR 795b1b1883SVipin KUMAR for (idx = 0; idx < CONFIG_RX_DESCR_NUM; idx++) { 805b1b1883SVipin KUMAR desc_p = &desc_table_p[idx]; 815b1b1883SVipin KUMAR desc_p->dmamac_addr = &rxbuffs[idx * CONFIG_ETH_BUFSIZE]; 825b1b1883SVipin KUMAR desc_p->dmamac_next = &desc_table_p[idx + 1]; 835b1b1883SVipin KUMAR 845b1b1883SVipin KUMAR desc_p->dmamac_cntl = 855b1b1883SVipin KUMAR (MAC_MAX_FRAME_SZ & DESC_RXCTRL_SIZE1MASK) | \ 865b1b1883SVipin KUMAR DESC_RXCTRL_RXCHAIN; 875b1b1883SVipin KUMAR 885b1b1883SVipin KUMAR desc_p->txrx_status = DESC_RXSTS_OWNBYDMA; 895b1b1883SVipin KUMAR } 905b1b1883SVipin KUMAR 915b1b1883SVipin KUMAR /* Correcting the last pointer of the chain */ 925b1b1883SVipin KUMAR desc_p->dmamac_next = &desc_table_p[0]; 935b1b1883SVipin KUMAR 945b1b1883SVipin KUMAR writel((ulong)&desc_table_p[0], &dma_p->rxdesclistaddr); 955b1b1883SVipin KUMAR } 965b1b1883SVipin KUMAR 975b1b1883SVipin KUMAR static void descs_init(struct eth_device *dev) 985b1b1883SVipin KUMAR { 995b1b1883SVipin KUMAR tx_descs_init(dev); 1005b1b1883SVipin KUMAR rx_descs_init(dev); 1015b1b1883SVipin KUMAR } 1025b1b1883SVipin KUMAR 1035b1b1883SVipin KUMAR static int mac_reset(struct eth_device *dev) 1045b1b1883SVipin KUMAR { 1055b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 1065b1b1883SVipin KUMAR struct eth_mac_regs *mac_p = priv->mac_regs_p; 1075b1b1883SVipin KUMAR struct eth_dma_regs *dma_p = priv->dma_regs_p; 1085b1b1883SVipin KUMAR 1095b1b1883SVipin KUMAR int timeout = CONFIG_MACRESET_TIMEOUT; 1105b1b1883SVipin KUMAR 1115b1b1883SVipin KUMAR writel(DMAMAC_SRST, &dma_p->busmode); 1125b1b1883SVipin KUMAR writel(MII_PORTSELECT, &mac_p->conf); 1135b1b1883SVipin KUMAR 1145b1b1883SVipin KUMAR do { 1155b1b1883SVipin KUMAR if (!(readl(&dma_p->busmode) & DMAMAC_SRST)) 1165b1b1883SVipin KUMAR return 0; 1175b1b1883SVipin KUMAR udelay(1000); 1185b1b1883SVipin KUMAR } while (timeout--); 1195b1b1883SVipin KUMAR 1205b1b1883SVipin KUMAR return -1; 1215b1b1883SVipin KUMAR } 1225b1b1883SVipin KUMAR 1235b1b1883SVipin KUMAR static int dw_write_hwaddr(struct eth_device *dev) 1245b1b1883SVipin KUMAR { 1255b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 1265b1b1883SVipin KUMAR struct eth_mac_regs *mac_p = priv->mac_regs_p; 1275b1b1883SVipin KUMAR u32 macid_lo, macid_hi; 1285b1b1883SVipin KUMAR u8 *mac_id = &dev->enetaddr[0]; 1295b1b1883SVipin KUMAR 1305b1b1883SVipin KUMAR macid_lo = mac_id[0] + (mac_id[1] << 8) + \ 1315b1b1883SVipin KUMAR (mac_id[2] << 16) + (mac_id[3] << 24); 1325b1b1883SVipin KUMAR macid_hi = mac_id[4] + (mac_id[5] << 8); 1335b1b1883SVipin KUMAR 1345b1b1883SVipin KUMAR writel(macid_hi, &mac_p->macaddr0hi); 1355b1b1883SVipin KUMAR writel(macid_lo, &mac_p->macaddr0lo); 1365b1b1883SVipin KUMAR 1375b1b1883SVipin KUMAR return 0; 1385b1b1883SVipin KUMAR } 1395b1b1883SVipin KUMAR 1405b1b1883SVipin KUMAR static int dw_eth_init(struct eth_device *dev, bd_t *bis) 1415b1b1883SVipin KUMAR { 1425b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 1435b1b1883SVipin KUMAR struct eth_mac_regs *mac_p = priv->mac_regs_p; 1445b1b1883SVipin KUMAR struct eth_dma_regs *dma_p = priv->dma_regs_p; 1455b1b1883SVipin KUMAR u32 conf; 1465b1b1883SVipin KUMAR 1475b1b1883SVipin KUMAR /* Reset ethernet hardware */ 1485b1b1883SVipin KUMAR if (mac_reset(dev) < 0) 1495b1b1883SVipin KUMAR return -1; 1505b1b1883SVipin KUMAR 1515b1b1883SVipin KUMAR writel(FIXEDBURST | PRIORXTX_41 | BURST_16, 1525b1b1883SVipin KUMAR &dma_p->busmode); 1535b1b1883SVipin KUMAR 1545b1b1883SVipin KUMAR writel(FLUSHTXFIFO | readl(&dma_p->opmode), &dma_p->opmode); 1555b1b1883SVipin KUMAR writel(STOREFORWARD | TXSECONDFRAME, &dma_p->opmode); 1565b1b1883SVipin KUMAR 1575b1b1883SVipin KUMAR conf = FRAMEBURSTENABLE | DISABLERXOWN; 1585b1b1883SVipin KUMAR 1595b1b1883SVipin KUMAR if (priv->speed != SPEED_1000M) 1605b1b1883SVipin KUMAR conf |= MII_PORTSELECT; 1615b1b1883SVipin KUMAR 1625b1b1883SVipin KUMAR if (priv->duplex == FULL_DUPLEX) 1635b1b1883SVipin KUMAR conf |= FULLDPLXMODE; 1645b1b1883SVipin KUMAR 1655b1b1883SVipin KUMAR writel(conf, &mac_p->conf); 1665b1b1883SVipin KUMAR 1675b1b1883SVipin KUMAR descs_init(dev); 1685b1b1883SVipin KUMAR 1695b1b1883SVipin KUMAR /* 1705b1b1883SVipin KUMAR * Start/Enable xfer at dma as well as mac level 1715b1b1883SVipin KUMAR */ 1725b1b1883SVipin KUMAR writel(readl(&dma_p->opmode) | RXSTART, &dma_p->opmode); 1735b1b1883SVipin KUMAR writel(readl(&dma_p->opmode) | TXSTART, &dma_p->opmode); 1745b1b1883SVipin KUMAR 1755b1b1883SVipin KUMAR writel(readl(&mac_p->conf) | RXENABLE, &mac_p->conf); 1765b1b1883SVipin KUMAR writel(readl(&mac_p->conf) | TXENABLE, &mac_p->conf); 1775b1b1883SVipin KUMAR 1785b1b1883SVipin KUMAR return 0; 1795b1b1883SVipin KUMAR } 1805b1b1883SVipin KUMAR 1815b1b1883SVipin KUMAR static int dw_eth_send(struct eth_device *dev, volatile void *packet, 1825b1b1883SVipin KUMAR int length) 1835b1b1883SVipin KUMAR { 1845b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 1855b1b1883SVipin KUMAR struct eth_dma_regs *dma_p = priv->dma_regs_p; 1865b1b1883SVipin KUMAR u32 desc_num = priv->tx_currdescnum; 1875b1b1883SVipin KUMAR struct dmamacdescr *desc_p = &priv->tx_mac_descrtable[desc_num]; 1885b1b1883SVipin KUMAR 1895b1b1883SVipin KUMAR /* Check if the descriptor is owned by CPU */ 1905b1b1883SVipin KUMAR if (desc_p->txrx_status & DESC_TXSTS_OWNBYDMA) { 1915b1b1883SVipin KUMAR printf("CPU not owner of tx frame\n"); 1925b1b1883SVipin KUMAR return -1; 1935b1b1883SVipin KUMAR } 1945b1b1883SVipin KUMAR 1955b1b1883SVipin KUMAR memcpy((void *)desc_p->dmamac_addr, (void *)packet, length); 1965b1b1883SVipin KUMAR 1975b1b1883SVipin KUMAR #if defined(CONFIG_DW_ALTDESCRIPTOR) 1985b1b1883SVipin KUMAR desc_p->txrx_status |= DESC_TXSTS_TXFIRST | DESC_TXSTS_TXLAST; 1995b1b1883SVipin KUMAR desc_p->dmamac_cntl |= (length << DESC_TXCTRL_SIZE1SHFT) & \ 2005b1b1883SVipin KUMAR DESC_TXCTRL_SIZE1MASK; 2015b1b1883SVipin KUMAR 2025b1b1883SVipin KUMAR desc_p->txrx_status &= ~(DESC_TXSTS_MSK); 2035b1b1883SVipin KUMAR desc_p->txrx_status |= DESC_TXSTS_OWNBYDMA; 2045b1b1883SVipin KUMAR #else 2055b1b1883SVipin KUMAR desc_p->dmamac_cntl |= ((length << DESC_TXCTRL_SIZE1SHFT) & \ 2065b1b1883SVipin KUMAR DESC_TXCTRL_SIZE1MASK) | DESC_TXCTRL_TXLAST | \ 2075b1b1883SVipin KUMAR DESC_TXCTRL_TXFIRST; 2085b1b1883SVipin KUMAR 2095b1b1883SVipin KUMAR desc_p->txrx_status = DESC_TXSTS_OWNBYDMA; 2105b1b1883SVipin KUMAR #endif 2115b1b1883SVipin KUMAR 2125b1b1883SVipin KUMAR /* Test the wrap-around condition. */ 2135b1b1883SVipin KUMAR if (++desc_num >= CONFIG_TX_DESCR_NUM) 2145b1b1883SVipin KUMAR desc_num = 0; 2155b1b1883SVipin KUMAR 2165b1b1883SVipin KUMAR priv->tx_currdescnum = desc_num; 2175b1b1883SVipin KUMAR 2185b1b1883SVipin KUMAR /* Start the transmission */ 2195b1b1883SVipin KUMAR writel(POLL_DATA, &dma_p->txpolldemand); 2205b1b1883SVipin KUMAR 2215b1b1883SVipin KUMAR return 0; 2225b1b1883SVipin KUMAR } 2235b1b1883SVipin KUMAR 2245b1b1883SVipin KUMAR static int dw_eth_recv(struct eth_device *dev) 2255b1b1883SVipin KUMAR { 2265b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 2275b1b1883SVipin KUMAR u32 desc_num = priv->rx_currdescnum; 2285b1b1883SVipin KUMAR struct dmamacdescr *desc_p = &priv->rx_mac_descrtable[desc_num]; 2295b1b1883SVipin KUMAR 2305b1b1883SVipin KUMAR u32 status = desc_p->txrx_status; 2315b1b1883SVipin KUMAR int length = 0; 2325b1b1883SVipin KUMAR 2335b1b1883SVipin KUMAR /* Check if the owner is the CPU */ 2345b1b1883SVipin KUMAR if (!(status & DESC_RXSTS_OWNBYDMA)) { 2355b1b1883SVipin KUMAR 2365b1b1883SVipin KUMAR length = (status & DESC_RXSTS_FRMLENMSK) >> \ 2375b1b1883SVipin KUMAR DESC_RXSTS_FRMLENSHFT; 2385b1b1883SVipin KUMAR 2395b1b1883SVipin KUMAR NetReceive(desc_p->dmamac_addr, length); 2405b1b1883SVipin KUMAR 2415b1b1883SVipin KUMAR /* 2425b1b1883SVipin KUMAR * Make the current descriptor valid again and go to 2435b1b1883SVipin KUMAR * the next one 2445b1b1883SVipin KUMAR */ 2455b1b1883SVipin KUMAR desc_p->txrx_status |= DESC_RXSTS_OWNBYDMA; 2465b1b1883SVipin KUMAR 2475b1b1883SVipin KUMAR /* Test the wrap-around condition. */ 2485b1b1883SVipin KUMAR if (++desc_num >= CONFIG_RX_DESCR_NUM) 2495b1b1883SVipin KUMAR desc_num = 0; 2505b1b1883SVipin KUMAR } 2515b1b1883SVipin KUMAR 2525b1b1883SVipin KUMAR priv->rx_currdescnum = desc_num; 2535b1b1883SVipin KUMAR 2545b1b1883SVipin KUMAR return length; 2555b1b1883SVipin KUMAR } 2565b1b1883SVipin KUMAR 2575b1b1883SVipin KUMAR static void dw_eth_halt(struct eth_device *dev) 2585b1b1883SVipin KUMAR { 2595b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 2605b1b1883SVipin KUMAR 2615b1b1883SVipin KUMAR mac_reset(dev); 2625b1b1883SVipin KUMAR priv->tx_currdescnum = priv->rx_currdescnum = 0; 2635b1b1883SVipin KUMAR } 2645b1b1883SVipin KUMAR 2655b1b1883SVipin KUMAR static int eth_mdio_read(struct eth_device *dev, u8 addr, u8 reg, u16 *val) 2665b1b1883SVipin KUMAR { 2675b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 2685b1b1883SVipin KUMAR struct eth_mac_regs *mac_p = priv->mac_regs_p; 2695b1b1883SVipin KUMAR u32 miiaddr; 2705b1b1883SVipin KUMAR int timeout = CONFIG_MDIO_TIMEOUT; 2715b1b1883SVipin KUMAR 2725b1b1883SVipin KUMAR miiaddr = ((addr << MIIADDRSHIFT) & MII_ADDRMSK) | \ 2735b1b1883SVipin KUMAR ((reg << MIIREGSHIFT) & MII_REGMSK); 2745b1b1883SVipin KUMAR 2755b1b1883SVipin KUMAR writel(miiaddr | MII_CLKRANGE_150_250M | MII_BUSY, &mac_p->miiaddr); 2765b1b1883SVipin KUMAR 2775b1b1883SVipin KUMAR do { 2785b1b1883SVipin KUMAR if (!(readl(&mac_p->miiaddr) & MII_BUSY)) { 2795b1b1883SVipin KUMAR *val = readl(&mac_p->miidata); 2805b1b1883SVipin KUMAR return 0; 2815b1b1883SVipin KUMAR } 2825b1b1883SVipin KUMAR udelay(1000); 2835b1b1883SVipin KUMAR } while (timeout--); 2845b1b1883SVipin KUMAR 2855b1b1883SVipin KUMAR return -1; 2865b1b1883SVipin KUMAR } 2875b1b1883SVipin KUMAR 2885b1b1883SVipin KUMAR static int eth_mdio_write(struct eth_device *dev, u8 addr, u8 reg, u16 val) 2895b1b1883SVipin KUMAR { 2905b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 2915b1b1883SVipin KUMAR struct eth_mac_regs *mac_p = priv->mac_regs_p; 2925b1b1883SVipin KUMAR u32 miiaddr; 2935b1b1883SVipin KUMAR int ret = -1, timeout = CONFIG_MDIO_TIMEOUT; 2945b1b1883SVipin KUMAR u16 value; 2955b1b1883SVipin KUMAR 2965b1b1883SVipin KUMAR writel(val, &mac_p->miidata); 2975b1b1883SVipin KUMAR miiaddr = ((addr << MIIADDRSHIFT) & MII_ADDRMSK) | \ 2985b1b1883SVipin KUMAR ((reg << MIIREGSHIFT) & MII_REGMSK) | MII_WRITE; 2995b1b1883SVipin KUMAR 3005b1b1883SVipin KUMAR writel(miiaddr | MII_CLKRANGE_150_250M | MII_BUSY, &mac_p->miiaddr); 3015b1b1883SVipin KUMAR 3025b1b1883SVipin KUMAR do { 3035b1b1883SVipin KUMAR if (!(readl(&mac_p->miiaddr) & MII_BUSY)) 3045b1b1883SVipin KUMAR ret = 0; 3055b1b1883SVipin KUMAR udelay(1000); 3065b1b1883SVipin KUMAR } while (timeout--); 3075b1b1883SVipin KUMAR 3085b1b1883SVipin KUMAR /* Needed as a fix for ST-Phy */ 3095b1b1883SVipin KUMAR eth_mdio_read(dev, addr, reg, &value); 3105b1b1883SVipin KUMAR 3115b1b1883SVipin KUMAR return ret; 3125b1b1883SVipin KUMAR } 3135b1b1883SVipin KUMAR 3145b1b1883SVipin KUMAR #if defined(CONFIG_DW_SEARCH_PHY) 3155b1b1883SVipin KUMAR static int find_phy(struct eth_device *dev) 3165b1b1883SVipin KUMAR { 3175b1b1883SVipin KUMAR int phy_addr = 0; 3185b1b1883SVipin KUMAR u16 ctrl, oldctrl; 3195b1b1883SVipin KUMAR 3205b1b1883SVipin KUMAR do { 3218ef583a0SMike Frysinger eth_mdio_read(dev, phy_addr, MII_BMCR, &ctrl); 3228ef583a0SMike Frysinger oldctrl = ctrl & BMCR_ANENABLE; 3235b1b1883SVipin KUMAR 3248ef583a0SMike Frysinger ctrl ^= BMCR_ANENABLE; 3258ef583a0SMike Frysinger eth_mdio_write(dev, phy_addr, MII_BMCR, ctrl); 3268ef583a0SMike Frysinger eth_mdio_read(dev, phy_addr, MII_BMCR, &ctrl); 3278ef583a0SMike Frysinger ctrl &= BMCR_ANENABLE; 3285b1b1883SVipin KUMAR 3295b1b1883SVipin KUMAR if (ctrl == oldctrl) { 3305b1b1883SVipin KUMAR phy_addr++; 3315b1b1883SVipin KUMAR } else { 3328ef583a0SMike Frysinger ctrl ^= BMCR_ANENABLE; 3338ef583a0SMike Frysinger eth_mdio_write(dev, phy_addr, MII_BMCR, ctrl); 3345b1b1883SVipin KUMAR 3355b1b1883SVipin KUMAR return phy_addr; 3365b1b1883SVipin KUMAR } 3375b1b1883SVipin KUMAR } while (phy_addr < 32); 3385b1b1883SVipin KUMAR 3395b1b1883SVipin KUMAR return -1; 3405b1b1883SVipin KUMAR } 3415b1b1883SVipin KUMAR #endif 3425b1b1883SVipin KUMAR 3435b1b1883SVipin KUMAR static int dw_reset_phy(struct eth_device *dev) 3445b1b1883SVipin KUMAR { 3455b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 3465b1b1883SVipin KUMAR u16 ctrl; 3475b1b1883SVipin KUMAR int timeout = CONFIG_PHYRESET_TIMEOUT; 3485b1b1883SVipin KUMAR u32 phy_addr = priv->address; 3495b1b1883SVipin KUMAR 3508ef583a0SMike Frysinger eth_mdio_write(dev, phy_addr, MII_BMCR, BMCR_RESET); 3515b1b1883SVipin KUMAR do { 3528ef583a0SMike Frysinger eth_mdio_read(dev, phy_addr, MII_BMCR, &ctrl); 3538ef583a0SMike Frysinger if (!(ctrl & BMCR_RESET)) 3545b1b1883SVipin KUMAR break; 3555b1b1883SVipin KUMAR udelay(1000); 3565b1b1883SVipin KUMAR } while (timeout--); 3575b1b1883SVipin KUMAR 3585b1b1883SVipin KUMAR if (timeout < 0) 3595b1b1883SVipin KUMAR return -1; 3605b1b1883SVipin KUMAR 3615b1b1883SVipin KUMAR #ifdef CONFIG_PHY_RESET_DELAY 3625b1b1883SVipin KUMAR udelay(CONFIG_PHY_RESET_DELAY); 3635b1b1883SVipin KUMAR #endif 3645b1b1883SVipin KUMAR return 0; 3655b1b1883SVipin KUMAR } 3665b1b1883SVipin KUMAR 3675b1b1883SVipin KUMAR static int configure_phy(struct eth_device *dev) 3685b1b1883SVipin KUMAR { 3695b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 3705b1b1883SVipin KUMAR int phy_addr; 371*ee7f5bfdSMike Frysinger u16 bmcr; 3725b1b1883SVipin KUMAR #if defined(CONFIG_DW_AUTONEG) 3735b1b1883SVipin KUMAR u16 bmsr; 3745b1b1883SVipin KUMAR u32 timeout; 3755b1b1883SVipin KUMAR u16 anlpar, btsr; 376*ee7f5bfdSMike Frysinger #else 377*ee7f5bfdSMike Frysinger u16 ctrl; 3785b1b1883SVipin KUMAR #endif 3795b1b1883SVipin KUMAR 3805b1b1883SVipin KUMAR #if defined(CONFIG_DW_SEARCH_PHY) 3815b1b1883SVipin KUMAR phy_addr = find_phy(dev); 3825b1b1883SVipin KUMAR if (phy_addr > 0) 3835b1b1883SVipin KUMAR priv->address = phy_addr; 3845b1b1883SVipin KUMAR else 3855b1b1883SVipin KUMAR return -1; 3865b1b1883SVipin KUMAR #endif 3875b1b1883SVipin KUMAR if (dw_reset_phy(dev) < 0) 3885b1b1883SVipin KUMAR return -1; 3895b1b1883SVipin KUMAR 3905b1b1883SVipin KUMAR #if defined(CONFIG_DW_AUTONEG) 3918ef583a0SMike Frysinger bmcr = BMCR_ANENABLE | BMCR_ANRESTART | BMCR_SPEED100 | \ 3928ef583a0SMike Frysinger BMCR_FULLDPLX | BMCR_SPEED1000; 3935b1b1883SVipin KUMAR #else 3948ef583a0SMike Frysinger bmcr = BMCR_SPEED100 | BMCR_FULLDPLX; 3955b1b1883SVipin KUMAR 3965b1b1883SVipin KUMAR #if defined(CONFIG_DW_SPEED10M) 3978ef583a0SMike Frysinger bmcr &= ~BMCR_SPEED100; 3985b1b1883SVipin KUMAR #endif 3995b1b1883SVipin KUMAR #if defined(CONFIG_DW_DUPLEXHALF) 4008ef583a0SMike Frysinger bmcr &= ~BMCR_FULLDPLX; 4015b1b1883SVipin KUMAR #endif 4025b1b1883SVipin KUMAR #endif 4038ef583a0SMike Frysinger if (eth_mdio_write(dev, phy_addr, MII_BMCR, bmcr) < 0) 4045b1b1883SVipin KUMAR return -1; 4055b1b1883SVipin KUMAR 4065b1b1883SVipin KUMAR /* Read the phy status register and populate priv structure */ 4075b1b1883SVipin KUMAR #if defined(CONFIG_DW_AUTONEG) 4085b1b1883SVipin KUMAR timeout = CONFIG_AUTONEG_TIMEOUT; 4095b1b1883SVipin KUMAR do { 4108ef583a0SMike Frysinger eth_mdio_read(dev, phy_addr, MII_BMSR, &bmsr); 4118ef583a0SMike Frysinger if (bmsr & BMSR_ANEGCOMPLETE) 4125b1b1883SVipin KUMAR break; 4135b1b1883SVipin KUMAR udelay(1000); 4145b1b1883SVipin KUMAR } while (timeout--); 4155b1b1883SVipin KUMAR 4168ef583a0SMike Frysinger eth_mdio_read(dev, phy_addr, MII_LPA, &anlpar); 4178ef583a0SMike Frysinger eth_mdio_read(dev, phy_addr, MII_STAT1000, &btsr); 4185b1b1883SVipin KUMAR 4195b1b1883SVipin KUMAR if (btsr & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD)) { 4205b1b1883SVipin KUMAR priv->speed = SPEED_1000M; 4215b1b1883SVipin KUMAR if (btsr & PHY_1000BTSR_1000FD) 4225b1b1883SVipin KUMAR priv->duplex = FULL_DUPLEX; 4235b1b1883SVipin KUMAR else 4245b1b1883SVipin KUMAR priv->duplex = HALF_DUPLEX; 4255b1b1883SVipin KUMAR } else { 4268ef583a0SMike Frysinger if (anlpar & LPA_100) 4275b1b1883SVipin KUMAR priv->speed = SPEED_100M; 4285b1b1883SVipin KUMAR else 4295b1b1883SVipin KUMAR priv->speed = SPEED_10M; 4305b1b1883SVipin KUMAR 4318ef583a0SMike Frysinger if (anlpar & (LPA_10FULL | LPA_100FULL)) 4325b1b1883SVipin KUMAR priv->duplex = FULL_DUPLEX; 4335b1b1883SVipin KUMAR else 4345b1b1883SVipin KUMAR priv->duplex = HALF_DUPLEX; 4355b1b1883SVipin KUMAR } 4365b1b1883SVipin KUMAR #else 4378ef583a0SMike Frysinger if (eth_mdio_read(dev, phy_addr, MII_BMCR, &ctrl) < 0) 4385b1b1883SVipin KUMAR return -1; 4395b1b1883SVipin KUMAR 4408ef583a0SMike Frysinger if (ctrl & BMCR_FULLDPLX) 4415b1b1883SVipin KUMAR priv->duplex = FULL_DUPLEX; 4425b1b1883SVipin KUMAR else 4435b1b1883SVipin KUMAR priv->duplex = HALF_DUPLEX; 4445b1b1883SVipin KUMAR 4458ef583a0SMike Frysinger if (ctrl & BMCR_SPEED1000) 4465b1b1883SVipin KUMAR priv->speed = SPEED_1000M; 4478ef583a0SMike Frysinger else if (ctrl & BMCR_SPEED100) 4485b1b1883SVipin KUMAR priv->speed = SPEED_100M; 4495b1b1883SVipin KUMAR else 4505b1b1883SVipin KUMAR priv->speed = SPEED_10M; 4515b1b1883SVipin KUMAR #endif 4525b1b1883SVipin KUMAR return 0; 4535b1b1883SVipin KUMAR } 4545b1b1883SVipin KUMAR 4555b1b1883SVipin KUMAR #if defined(CONFIG_MII) 4565700bb63SMike Frysinger static int dw_mii_read(const char *devname, u8 addr, u8 reg, u16 *val) 4575b1b1883SVipin KUMAR { 4585b1b1883SVipin KUMAR struct eth_device *dev; 4595b1b1883SVipin KUMAR 4605b1b1883SVipin KUMAR dev = eth_get_dev_by_name(devname); 4615b1b1883SVipin KUMAR if (dev) 4625b1b1883SVipin KUMAR eth_mdio_read(dev, addr, reg, val); 4635b1b1883SVipin KUMAR 4645b1b1883SVipin KUMAR return 0; 4655b1b1883SVipin KUMAR } 4665b1b1883SVipin KUMAR 4675700bb63SMike Frysinger static int dw_mii_write(const char *devname, u8 addr, u8 reg, u16 val) 4685b1b1883SVipin KUMAR { 4695b1b1883SVipin KUMAR struct eth_device *dev; 4705b1b1883SVipin KUMAR 4715b1b1883SVipin KUMAR dev = eth_get_dev_by_name(devname); 4725b1b1883SVipin KUMAR if (dev) 4735b1b1883SVipin KUMAR eth_mdio_write(dev, addr, reg, val); 4745b1b1883SVipin KUMAR 4755b1b1883SVipin KUMAR return 0; 4765b1b1883SVipin KUMAR } 4775b1b1883SVipin KUMAR #endif 4785b1b1883SVipin KUMAR 4795b1b1883SVipin KUMAR int designware_initialize(u32 id, ulong base_addr, u32 phy_addr) 4805b1b1883SVipin KUMAR { 4815b1b1883SVipin KUMAR struct eth_device *dev; 4825b1b1883SVipin KUMAR struct dw_eth_dev *priv; 4835b1b1883SVipin KUMAR 4845b1b1883SVipin KUMAR dev = (struct eth_device *) malloc(sizeof(struct eth_device)); 4855b1b1883SVipin KUMAR if (!dev) 4865b1b1883SVipin KUMAR return -ENOMEM; 4875b1b1883SVipin KUMAR 4885b1b1883SVipin KUMAR /* 4895b1b1883SVipin KUMAR * Since the priv structure contains the descriptors which need a strict 4905b1b1883SVipin KUMAR * buswidth alignment, memalign is used to allocate memory 4915b1b1883SVipin KUMAR */ 4925b1b1883SVipin KUMAR priv = (struct dw_eth_dev *) memalign(16, sizeof(struct dw_eth_dev)); 4935b1b1883SVipin KUMAR if (!priv) { 4945b1b1883SVipin KUMAR free(dev); 4955b1b1883SVipin KUMAR return -ENOMEM; 4965b1b1883SVipin KUMAR } 4975b1b1883SVipin KUMAR 4985b1b1883SVipin KUMAR memset(dev, 0, sizeof(struct eth_device)); 4995b1b1883SVipin KUMAR memset(priv, 0, sizeof(struct dw_eth_dev)); 5005b1b1883SVipin KUMAR 5015b1b1883SVipin KUMAR sprintf(dev->name, "mii%d", id); 5025b1b1883SVipin KUMAR dev->iobase = (int)base_addr; 5035b1b1883SVipin KUMAR dev->priv = priv; 5045b1b1883SVipin KUMAR 5055b1b1883SVipin KUMAR eth_getenv_enetaddr_by_index(id, &dev->enetaddr[0]); 5065b1b1883SVipin KUMAR 5075b1b1883SVipin KUMAR priv->dev = dev; 5085b1b1883SVipin KUMAR priv->mac_regs_p = (struct eth_mac_regs *)base_addr; 5095b1b1883SVipin KUMAR priv->dma_regs_p = (struct eth_dma_regs *)(base_addr + 5105b1b1883SVipin KUMAR DW_DMA_BASE_OFFSET); 5115b1b1883SVipin KUMAR priv->address = phy_addr; 5125b1b1883SVipin KUMAR 5135b1b1883SVipin KUMAR if (mac_reset(dev) < 0) 5145b1b1883SVipin KUMAR return -1; 5155b1b1883SVipin KUMAR 5165b1b1883SVipin KUMAR if (configure_phy(dev) < 0) { 5175b1b1883SVipin KUMAR printf("Phy could not be configured\n"); 5185b1b1883SVipin KUMAR return -1; 5195b1b1883SVipin KUMAR } 5205b1b1883SVipin KUMAR 5215b1b1883SVipin KUMAR dev->init = dw_eth_init; 5225b1b1883SVipin KUMAR dev->send = dw_eth_send; 5235b1b1883SVipin KUMAR dev->recv = dw_eth_recv; 5245b1b1883SVipin KUMAR dev->halt = dw_eth_halt; 5255b1b1883SVipin KUMAR dev->write_hwaddr = dw_write_hwaddr; 5265b1b1883SVipin KUMAR 5275b1b1883SVipin KUMAR eth_register(dev); 5285b1b1883SVipin KUMAR 5295b1b1883SVipin KUMAR #if defined(CONFIG_MII) 5305b1b1883SVipin KUMAR miiphy_register(dev->name, dw_mii_read, dw_mii_write); 5315b1b1883SVipin KUMAR #endif 5325b1b1883SVipin KUMAR return 1; 5335b1b1883SVipin KUMAR } 534