15b1b1883SVipin KUMAR /* 25b1b1883SVipin KUMAR * (C) Copyright 2010 35b1b1883SVipin KUMAR * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com. 45b1b1883SVipin KUMAR * 51a459660SWolfgang 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); 55*74cb708dSAlexey Brodkin priv->tx_currdescnum = 0; 565b1b1883SVipin KUMAR } 575b1b1883SVipin KUMAR 585b1b1883SVipin KUMAR static void rx_descs_init(struct eth_device *dev) 595b1b1883SVipin KUMAR { 605b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 615b1b1883SVipin KUMAR struct eth_dma_regs *dma_p = priv->dma_regs_p; 625b1b1883SVipin KUMAR struct dmamacdescr *desc_table_p = &priv->rx_mac_descrtable[0]; 635b1b1883SVipin KUMAR char *rxbuffs = &priv->rxbuffs[0]; 645b1b1883SVipin KUMAR struct dmamacdescr *desc_p; 655b1b1883SVipin KUMAR u32 idx; 665b1b1883SVipin KUMAR 675b1b1883SVipin KUMAR for (idx = 0; idx < CONFIG_RX_DESCR_NUM; idx++) { 685b1b1883SVipin KUMAR desc_p = &desc_table_p[idx]; 695b1b1883SVipin KUMAR desc_p->dmamac_addr = &rxbuffs[idx * CONFIG_ETH_BUFSIZE]; 705b1b1883SVipin KUMAR desc_p->dmamac_next = &desc_table_p[idx + 1]; 715b1b1883SVipin KUMAR 725b1b1883SVipin KUMAR desc_p->dmamac_cntl = 735b1b1883SVipin KUMAR (MAC_MAX_FRAME_SZ & DESC_RXCTRL_SIZE1MASK) | \ 745b1b1883SVipin KUMAR DESC_RXCTRL_RXCHAIN; 755b1b1883SVipin KUMAR 765b1b1883SVipin KUMAR desc_p->txrx_status = DESC_RXSTS_OWNBYDMA; 775b1b1883SVipin KUMAR } 785b1b1883SVipin KUMAR 795b1b1883SVipin KUMAR /* Correcting the last pointer of the chain */ 805b1b1883SVipin KUMAR desc_p->dmamac_next = &desc_table_p[0]; 815b1b1883SVipin KUMAR 825b1b1883SVipin KUMAR writel((ulong)&desc_table_p[0], &dma_p->rxdesclistaddr); 83*74cb708dSAlexey Brodkin priv->rx_currdescnum = 0; 845b1b1883SVipin KUMAR } 855b1b1883SVipin KUMAR 865b1b1883SVipin KUMAR static void descs_init(struct eth_device *dev) 875b1b1883SVipin KUMAR { 885b1b1883SVipin KUMAR tx_descs_init(dev); 895b1b1883SVipin KUMAR rx_descs_init(dev); 905b1b1883SVipin KUMAR } 915b1b1883SVipin KUMAR 925b1b1883SVipin KUMAR static int mac_reset(struct eth_device *dev) 935b1b1883SVipin KUMAR { 945b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 955b1b1883SVipin KUMAR struct eth_mac_regs *mac_p = priv->mac_regs_p; 965b1b1883SVipin KUMAR struct eth_dma_regs *dma_p = priv->dma_regs_p; 975b1b1883SVipin KUMAR 98cafabe19SAmit Virdi ulong start; 995b1b1883SVipin KUMAR int timeout = CONFIG_MACRESET_TIMEOUT; 1005b1b1883SVipin KUMAR 101227ad7b2SAlexey Brodkin writel(readl(&dma_p->busmode) | DMAMAC_SRST, &dma_p->busmode); 1027091915aSVipin Kumar 1037091915aSVipin Kumar if (priv->interface != PHY_INTERFACE_MODE_RGMII) 1045b1b1883SVipin KUMAR writel(MII_PORTSELECT, &mac_p->conf); 1055b1b1883SVipin KUMAR 106cafabe19SAmit Virdi start = get_timer(0); 107cafabe19SAmit Virdi while (get_timer(start) < timeout) { 1085b1b1883SVipin KUMAR if (!(readl(&dma_p->busmode) & DMAMAC_SRST)) 1095b1b1883SVipin KUMAR return 0; 110cafabe19SAmit Virdi 111cafabe19SAmit Virdi /* Try again after 10usec */ 112cafabe19SAmit Virdi udelay(10); 113cafabe19SAmit Virdi }; 1145b1b1883SVipin KUMAR 1155b1b1883SVipin KUMAR return -1; 1165b1b1883SVipin KUMAR } 1175b1b1883SVipin KUMAR 1185b1b1883SVipin KUMAR static int dw_write_hwaddr(struct eth_device *dev) 1195b1b1883SVipin KUMAR { 1205b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 1215b1b1883SVipin KUMAR struct eth_mac_regs *mac_p = priv->mac_regs_p; 1225b1b1883SVipin KUMAR u32 macid_lo, macid_hi; 1235b1b1883SVipin KUMAR u8 *mac_id = &dev->enetaddr[0]; 1245b1b1883SVipin KUMAR 1255b1b1883SVipin KUMAR macid_lo = mac_id[0] + (mac_id[1] << 8) + \ 1265b1b1883SVipin KUMAR (mac_id[2] << 16) + (mac_id[3] << 24); 1275b1b1883SVipin KUMAR macid_hi = mac_id[4] + (mac_id[5] << 8); 1285b1b1883SVipin KUMAR 1295b1b1883SVipin KUMAR writel(macid_hi, &mac_p->macaddr0hi); 1305b1b1883SVipin KUMAR writel(macid_lo, &mac_p->macaddr0lo); 1315b1b1883SVipin KUMAR 1325b1b1883SVipin KUMAR return 0; 1335b1b1883SVipin KUMAR } 1345b1b1883SVipin KUMAR 1355b1b1883SVipin KUMAR static int dw_eth_init(struct eth_device *dev, bd_t *bis) 1365b1b1883SVipin KUMAR { 1375b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 1385b1b1883SVipin KUMAR struct eth_mac_regs *mac_p = priv->mac_regs_p; 1395b1b1883SVipin KUMAR struct eth_dma_regs *dma_p = priv->dma_regs_p; 1405b1b1883SVipin KUMAR u32 conf; 1415b1b1883SVipin KUMAR 14213edd170SVipin Kumar if (priv->phy_configured != 1) 14313edd170SVipin Kumar configure_phy(dev); 14413edd170SVipin Kumar 145ef76025aSStefan Roese /* Print link status only once */ 146ef76025aSStefan Roese if (!priv->link_printed) { 147ef76025aSStefan Roese printf("ENET Speed is %d Mbps - %s duplex connection\n", 148ef76025aSStefan Roese priv->speed, (priv->duplex == HALF) ? "HALF" : "FULL"); 149ef76025aSStefan Roese priv->link_printed = 1; 150ef76025aSStefan Roese } 151ef76025aSStefan Roese 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 16266f119e5SDinh Nguyen writel(readl(&dma_p->opmode) | FLUSHTXFIFO | STOREFORWARD | 16366f119e5SDinh Nguyen TXSECONDFRAME, &dma_p->opmode); 1645b1b1883SVipin KUMAR 1655b1b1883SVipin KUMAR conf = FRAMEBURSTENABLE | DISABLERXOWN; 1665b1b1883SVipin KUMAR 167ef76025aSStefan Roese if (priv->speed != 1000) 1685b1b1883SVipin KUMAR conf |= MII_PORTSELECT; 1695b1b1883SVipin KUMAR 1709afc1af0SVipin Kumar if ((priv->interface != PHY_INTERFACE_MODE_MII) && 1719afc1af0SVipin Kumar (priv->interface != PHY_INTERFACE_MODE_GMII)) { 1729afc1af0SVipin Kumar 173ef76025aSStefan Roese if (priv->speed == 100) 1749afc1af0SVipin Kumar conf |= FES_100; 1759afc1af0SVipin Kumar } 1769afc1af0SVipin Kumar 177ef76025aSStefan Roese if (priv->duplex == FULL) 1785b1b1883SVipin KUMAR conf |= FULLDPLXMODE; 1795b1b1883SVipin KUMAR 1805b1b1883SVipin KUMAR writel(conf, &mac_p->conf); 1815b1b1883SVipin KUMAR 1825b1b1883SVipin KUMAR descs_init(dev); 1835b1b1883SVipin KUMAR 1845b1b1883SVipin KUMAR /* 1855b1b1883SVipin KUMAR * Start/Enable xfer at dma as well as mac level 1865b1b1883SVipin KUMAR */ 1875b1b1883SVipin KUMAR writel(readl(&dma_p->opmode) | RXSTART, &dma_p->opmode); 1885b1b1883SVipin KUMAR writel(readl(&dma_p->opmode) | TXSTART, &dma_p->opmode); 1895b1b1883SVipin KUMAR 190aa51005cSArmando Visconti writel(readl(&mac_p->conf) | RXENABLE | TXENABLE, &mac_p->conf); 1915b1b1883SVipin KUMAR 1925b1b1883SVipin KUMAR return 0; 1935b1b1883SVipin KUMAR } 1945b1b1883SVipin KUMAR 19510cbe3b6SJoe Hershberger static int dw_eth_send(struct eth_device *dev, void *packet, int length) 1965b1b1883SVipin KUMAR { 1975b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 1985b1b1883SVipin KUMAR struct eth_dma_regs *dma_p = priv->dma_regs_p; 1995b1b1883SVipin KUMAR u32 desc_num = priv->tx_currdescnum; 2005b1b1883SVipin KUMAR struct dmamacdescr *desc_p = &priv->tx_mac_descrtable[desc_num]; 2015b1b1883SVipin KUMAR 2025b1b1883SVipin KUMAR /* Check if the descriptor is owned by CPU */ 2035b1b1883SVipin KUMAR if (desc_p->txrx_status & DESC_TXSTS_OWNBYDMA) { 2045b1b1883SVipin KUMAR printf("CPU not owner of tx frame\n"); 2055b1b1883SVipin KUMAR return -1; 2065b1b1883SVipin KUMAR } 2075b1b1883SVipin KUMAR 20810cbe3b6SJoe Hershberger memcpy((void *)desc_p->dmamac_addr, packet, length); 2095b1b1883SVipin KUMAR 2105b1b1883SVipin KUMAR #if defined(CONFIG_DW_ALTDESCRIPTOR) 2115b1b1883SVipin KUMAR desc_p->txrx_status |= DESC_TXSTS_TXFIRST | DESC_TXSTS_TXLAST; 2125b1b1883SVipin KUMAR desc_p->dmamac_cntl |= (length << DESC_TXCTRL_SIZE1SHFT) & \ 2135b1b1883SVipin KUMAR DESC_TXCTRL_SIZE1MASK; 2145b1b1883SVipin KUMAR 2155b1b1883SVipin KUMAR desc_p->txrx_status &= ~(DESC_TXSTS_MSK); 2165b1b1883SVipin KUMAR desc_p->txrx_status |= DESC_TXSTS_OWNBYDMA; 2175b1b1883SVipin KUMAR #else 2185b1b1883SVipin KUMAR desc_p->dmamac_cntl |= ((length << DESC_TXCTRL_SIZE1SHFT) & \ 2195b1b1883SVipin KUMAR DESC_TXCTRL_SIZE1MASK) | DESC_TXCTRL_TXLAST | \ 2205b1b1883SVipin KUMAR DESC_TXCTRL_TXFIRST; 2215b1b1883SVipin KUMAR 2225b1b1883SVipin KUMAR desc_p->txrx_status = DESC_TXSTS_OWNBYDMA; 2235b1b1883SVipin KUMAR #endif 2245b1b1883SVipin KUMAR 2255b1b1883SVipin KUMAR /* Test the wrap-around condition. */ 2265b1b1883SVipin KUMAR if (++desc_num >= CONFIG_TX_DESCR_NUM) 2275b1b1883SVipin KUMAR desc_num = 0; 2285b1b1883SVipin KUMAR 2295b1b1883SVipin KUMAR priv->tx_currdescnum = desc_num; 2305b1b1883SVipin KUMAR 2315b1b1883SVipin KUMAR /* Start the transmission */ 2325b1b1883SVipin KUMAR writel(POLL_DATA, &dma_p->txpolldemand); 2335b1b1883SVipin KUMAR 2345b1b1883SVipin KUMAR return 0; 2355b1b1883SVipin KUMAR } 2365b1b1883SVipin KUMAR 2375b1b1883SVipin KUMAR static int dw_eth_recv(struct eth_device *dev) 2385b1b1883SVipin KUMAR { 2395b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 2405b1b1883SVipin KUMAR u32 desc_num = priv->rx_currdescnum; 2415b1b1883SVipin KUMAR struct dmamacdescr *desc_p = &priv->rx_mac_descrtable[desc_num]; 2425b1b1883SVipin KUMAR 2435b1b1883SVipin KUMAR u32 status = desc_p->txrx_status; 2445b1b1883SVipin KUMAR int length = 0; 2455b1b1883SVipin KUMAR 2465b1b1883SVipin KUMAR /* Check if the owner is the CPU */ 2475b1b1883SVipin KUMAR if (!(status & DESC_RXSTS_OWNBYDMA)) { 2485b1b1883SVipin KUMAR 2495b1b1883SVipin KUMAR length = (status & DESC_RXSTS_FRMLENMSK) >> \ 2505b1b1883SVipin KUMAR DESC_RXSTS_FRMLENSHFT; 2515b1b1883SVipin KUMAR 2525b1b1883SVipin KUMAR NetReceive(desc_p->dmamac_addr, length); 2535b1b1883SVipin KUMAR 2545b1b1883SVipin KUMAR /* 2555b1b1883SVipin KUMAR * Make the current descriptor valid again and go to 2565b1b1883SVipin KUMAR * the next one 2575b1b1883SVipin KUMAR */ 2585b1b1883SVipin KUMAR desc_p->txrx_status |= DESC_RXSTS_OWNBYDMA; 2595b1b1883SVipin KUMAR 2605b1b1883SVipin KUMAR /* Test the wrap-around condition. */ 2615b1b1883SVipin KUMAR if (++desc_num >= CONFIG_RX_DESCR_NUM) 2625b1b1883SVipin KUMAR desc_num = 0; 2635b1b1883SVipin KUMAR } 2645b1b1883SVipin KUMAR 2655b1b1883SVipin KUMAR priv->rx_currdescnum = desc_num; 2665b1b1883SVipin KUMAR 2675b1b1883SVipin KUMAR return length; 2685b1b1883SVipin KUMAR } 2695b1b1883SVipin KUMAR 2705b1b1883SVipin KUMAR static void dw_eth_halt(struct eth_device *dev) 2715b1b1883SVipin KUMAR { 2725b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 2735b1b1883SVipin KUMAR 2745b1b1883SVipin KUMAR mac_reset(dev); 2755b1b1883SVipin KUMAR priv->tx_currdescnum = priv->rx_currdescnum = 0; 2765b1b1883SVipin KUMAR } 2775b1b1883SVipin KUMAR 2785b1b1883SVipin KUMAR static int eth_mdio_read(struct eth_device *dev, u8 addr, u8 reg, u16 *val) 2795b1b1883SVipin KUMAR { 2805b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 2815b1b1883SVipin KUMAR struct eth_mac_regs *mac_p = priv->mac_regs_p; 282cafabe19SAmit Virdi ulong start; 2835b1b1883SVipin KUMAR u32 miiaddr; 2845b1b1883SVipin KUMAR int timeout = CONFIG_MDIO_TIMEOUT; 2855b1b1883SVipin KUMAR 2865b1b1883SVipin KUMAR miiaddr = ((addr << MIIADDRSHIFT) & MII_ADDRMSK) | \ 2875b1b1883SVipin KUMAR ((reg << MIIREGSHIFT) & MII_REGMSK); 2885b1b1883SVipin KUMAR 2895b1b1883SVipin KUMAR writel(miiaddr | MII_CLKRANGE_150_250M | MII_BUSY, &mac_p->miiaddr); 2905b1b1883SVipin KUMAR 291cafabe19SAmit Virdi start = get_timer(0); 292cafabe19SAmit Virdi while (get_timer(start) < timeout) { 2935b1b1883SVipin KUMAR if (!(readl(&mac_p->miiaddr) & MII_BUSY)) { 2945b1b1883SVipin KUMAR *val = readl(&mac_p->miidata); 2955b1b1883SVipin KUMAR return 0; 2965b1b1883SVipin KUMAR } 297cafabe19SAmit Virdi 298cafabe19SAmit Virdi /* Try again after 10usec */ 299cafabe19SAmit Virdi udelay(10); 300cafabe19SAmit Virdi }; 3015b1b1883SVipin KUMAR 3025b1b1883SVipin KUMAR return -1; 3035b1b1883SVipin KUMAR } 3045b1b1883SVipin KUMAR 3055b1b1883SVipin KUMAR static int eth_mdio_write(struct eth_device *dev, u8 addr, u8 reg, u16 val) 3065b1b1883SVipin KUMAR { 3075b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 3085b1b1883SVipin KUMAR struct eth_mac_regs *mac_p = priv->mac_regs_p; 309cafabe19SAmit Virdi ulong start; 3105b1b1883SVipin KUMAR u32 miiaddr; 3115b1b1883SVipin KUMAR int ret = -1, timeout = CONFIG_MDIO_TIMEOUT; 3125b1b1883SVipin KUMAR u16 value; 3135b1b1883SVipin KUMAR 3145b1b1883SVipin KUMAR writel(val, &mac_p->miidata); 3155b1b1883SVipin KUMAR miiaddr = ((addr << MIIADDRSHIFT) & MII_ADDRMSK) | \ 3165b1b1883SVipin KUMAR ((reg << MIIREGSHIFT) & MII_REGMSK) | MII_WRITE; 3175b1b1883SVipin KUMAR 3185b1b1883SVipin KUMAR writel(miiaddr | MII_CLKRANGE_150_250M | MII_BUSY, &mac_p->miiaddr); 3195b1b1883SVipin KUMAR 320cafabe19SAmit Virdi start = get_timer(0); 321cafabe19SAmit Virdi while (get_timer(start) < timeout) { 322c7f6dbe7SVipin KUMAR if (!(readl(&mac_p->miiaddr) & MII_BUSY)) { 3235b1b1883SVipin KUMAR ret = 0; 324c7f6dbe7SVipin KUMAR break; 325c7f6dbe7SVipin KUMAR } 326cafabe19SAmit Virdi 327cafabe19SAmit Virdi /* Try again after 10usec */ 328cafabe19SAmit Virdi udelay(10); 329cafabe19SAmit Virdi }; 3305b1b1883SVipin KUMAR 3315b1b1883SVipin KUMAR /* Needed as a fix for ST-Phy */ 3325b1b1883SVipin KUMAR eth_mdio_read(dev, addr, reg, &value); 3335b1b1883SVipin KUMAR 3345b1b1883SVipin KUMAR return ret; 3355b1b1883SVipin KUMAR } 3365b1b1883SVipin KUMAR 3375b1b1883SVipin KUMAR #if defined(CONFIG_DW_SEARCH_PHY) 3385b1b1883SVipin KUMAR static int find_phy(struct eth_device *dev) 3395b1b1883SVipin KUMAR { 3405b1b1883SVipin KUMAR int phy_addr = 0; 3415b1b1883SVipin KUMAR u16 ctrl, oldctrl; 3425b1b1883SVipin KUMAR 3435b1b1883SVipin KUMAR do { 3448ef583a0SMike Frysinger eth_mdio_read(dev, phy_addr, MII_BMCR, &ctrl); 3458ef583a0SMike Frysinger oldctrl = ctrl & BMCR_ANENABLE; 3465b1b1883SVipin KUMAR 3478ef583a0SMike Frysinger ctrl ^= BMCR_ANENABLE; 3488ef583a0SMike Frysinger eth_mdio_write(dev, phy_addr, MII_BMCR, ctrl); 3498ef583a0SMike Frysinger eth_mdio_read(dev, phy_addr, MII_BMCR, &ctrl); 3508ef583a0SMike Frysinger ctrl &= BMCR_ANENABLE; 3515b1b1883SVipin KUMAR 3525b1b1883SVipin KUMAR if (ctrl == oldctrl) { 3535b1b1883SVipin KUMAR phy_addr++; 3545b1b1883SVipin KUMAR } else { 3558ef583a0SMike Frysinger ctrl ^= BMCR_ANENABLE; 3568ef583a0SMike Frysinger eth_mdio_write(dev, phy_addr, MII_BMCR, ctrl); 3575b1b1883SVipin KUMAR 3585b1b1883SVipin KUMAR return phy_addr; 3595b1b1883SVipin KUMAR } 3605b1b1883SVipin KUMAR } while (phy_addr < 32); 3615b1b1883SVipin KUMAR 3625b1b1883SVipin KUMAR return -1; 3635b1b1883SVipin KUMAR } 3645b1b1883SVipin KUMAR #endif 3655b1b1883SVipin KUMAR 3665b1b1883SVipin KUMAR static int dw_reset_phy(struct eth_device *dev) 3675b1b1883SVipin KUMAR { 3685b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 3695b1b1883SVipin KUMAR u16 ctrl; 370cafabe19SAmit Virdi ulong start; 3715b1b1883SVipin KUMAR int timeout = CONFIG_PHYRESET_TIMEOUT; 3725b1b1883SVipin KUMAR u32 phy_addr = priv->address; 3735b1b1883SVipin KUMAR 3748ef583a0SMike Frysinger eth_mdio_write(dev, phy_addr, MII_BMCR, BMCR_RESET); 375cafabe19SAmit Virdi 376cafabe19SAmit Virdi start = get_timer(0); 377cafabe19SAmit Virdi while (get_timer(start) < timeout) { 3788ef583a0SMike Frysinger eth_mdio_read(dev, phy_addr, MII_BMCR, &ctrl); 3798ef583a0SMike Frysinger if (!(ctrl & BMCR_RESET)) 3805b1b1883SVipin KUMAR break; 3815b1b1883SVipin KUMAR 382cafabe19SAmit Virdi /* Try again after 10usec */ 383cafabe19SAmit Virdi udelay(10); 384cafabe19SAmit Virdi }; 385cafabe19SAmit Virdi 386cafabe19SAmit Virdi if (get_timer(start) >= CONFIG_PHYRESET_TIMEOUT) 3875b1b1883SVipin KUMAR return -1; 3885b1b1883SVipin KUMAR 3895b1b1883SVipin KUMAR #ifdef CONFIG_PHY_RESET_DELAY 3905b1b1883SVipin KUMAR udelay(CONFIG_PHY_RESET_DELAY); 3915b1b1883SVipin KUMAR #endif 3925b1b1883SVipin KUMAR return 0; 3935b1b1883SVipin KUMAR } 3945b1b1883SVipin KUMAR 395ef76025aSStefan Roese /* 396ef76025aSStefan Roese * Add weak default function for board specific PHY configuration 397ef76025aSStefan Roese */ 398ef76025aSStefan Roese int __weak designware_board_phy_init(struct eth_device *dev, int phy_addr, 399ef76025aSStefan Roese int (*mii_write)(struct eth_device *, u8, u8, u16), 400ef76025aSStefan Roese int dw_reset_phy(struct eth_device *)) 401ef76025aSStefan Roese { 402ef76025aSStefan Roese return 0; 403ef76025aSStefan Roese } 404ef76025aSStefan Roese 4055b1b1883SVipin KUMAR static int configure_phy(struct eth_device *dev) 4065b1b1883SVipin KUMAR { 4075b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 4085b1b1883SVipin KUMAR int phy_addr; 409ee7f5bfdSMike Frysinger u16 bmcr; 4105b1b1883SVipin KUMAR #if defined(CONFIG_DW_AUTONEG) 4115b1b1883SVipin KUMAR u16 bmsr; 4125b1b1883SVipin KUMAR u32 timeout; 413cafabe19SAmit Virdi ulong start; 4145b1b1883SVipin KUMAR #endif 4155b1b1883SVipin KUMAR 4165b1b1883SVipin KUMAR #if defined(CONFIG_DW_SEARCH_PHY) 4175b1b1883SVipin KUMAR phy_addr = find_phy(dev); 418024333c9SVipin KUMAR if (phy_addr >= 0) 4195b1b1883SVipin KUMAR priv->address = phy_addr; 4205b1b1883SVipin KUMAR else 4215b1b1883SVipin KUMAR return -1; 422f0ece9e9SMike Frysinger #else 423f0ece9e9SMike Frysinger phy_addr = priv->address; 4245b1b1883SVipin KUMAR #endif 425ef76025aSStefan Roese 426ef76025aSStefan Roese /* 427ef76025aSStefan Roese * Some boards need board specific PHY initialization. This is 428ef76025aSStefan Roese * after the main driver init code but before the auto negotiation 429ef76025aSStefan Roese * is run. 430ef76025aSStefan Roese */ 431ef76025aSStefan Roese if (designware_board_phy_init(dev, phy_addr, 432ef76025aSStefan Roese eth_mdio_write, dw_reset_phy) < 0) 433ef76025aSStefan Roese return -1; 434ef76025aSStefan Roese 4355b1b1883SVipin KUMAR if (dw_reset_phy(dev) < 0) 4365b1b1883SVipin KUMAR return -1; 4375b1b1883SVipin KUMAR 4385b1b1883SVipin KUMAR #if defined(CONFIG_DW_AUTONEG) 43920a5dde1SArmando Visconti /* Set Auto-Neg Advertisement capabilities to 10/100 half/full */ 44020a5dde1SArmando Visconti eth_mdio_write(dev, phy_addr, MII_ADVERTISE, 0x1E1); 44120a5dde1SArmando Visconti 442e25c90b4SVikas Manocha bmcr = BMCR_ANENABLE | BMCR_ANRESTART; 4435b1b1883SVipin KUMAR #else 4448ef583a0SMike Frysinger bmcr = BMCR_SPEED100 | BMCR_FULLDPLX; 4455b1b1883SVipin KUMAR 4465b1b1883SVipin KUMAR #if defined(CONFIG_DW_SPEED10M) 4478ef583a0SMike Frysinger bmcr &= ~BMCR_SPEED100; 4485b1b1883SVipin KUMAR #endif 4495b1b1883SVipin KUMAR #if defined(CONFIG_DW_DUPLEXHALF) 4508ef583a0SMike Frysinger bmcr &= ~BMCR_FULLDPLX; 4515b1b1883SVipin KUMAR #endif 4525b1b1883SVipin KUMAR #endif 4538ef583a0SMike Frysinger if (eth_mdio_write(dev, phy_addr, MII_BMCR, bmcr) < 0) 4545b1b1883SVipin KUMAR return -1; 4555b1b1883SVipin KUMAR 4565b1b1883SVipin KUMAR /* Read the phy status register and populate priv structure */ 4575b1b1883SVipin KUMAR #if defined(CONFIG_DW_AUTONEG) 4585b1b1883SVipin KUMAR timeout = CONFIG_AUTONEG_TIMEOUT; 459cafabe19SAmit Virdi start = get_timer(0); 460ef76025aSStefan Roese puts("Waiting for PHY auto negotiation to complete"); 461cafabe19SAmit Virdi while (get_timer(start) < timeout) { 4628ef583a0SMike Frysinger eth_mdio_read(dev, phy_addr, MII_BMSR, &bmsr); 463ef76025aSStefan Roese if (bmsr & BMSR_ANEGCOMPLETE) { 464ef76025aSStefan Roese priv->phy_configured = 1; 4655b1b1883SVipin KUMAR break; 466ef76025aSStefan Roese } 467cafabe19SAmit Virdi 468ef76025aSStefan Roese /* Print dot all 1s to show progress */ 469ef76025aSStefan Roese if ((get_timer(start) % 1000) == 0) 470ef76025aSStefan Roese putc('.'); 471ef76025aSStefan Roese 472ef76025aSStefan Roese /* Try again after 1msec */ 473ef76025aSStefan Roese udelay(1000); 474cafabe19SAmit Virdi }; 4755b1b1883SVipin KUMAR 476ef76025aSStefan Roese if (!(bmsr & BMSR_ANEGCOMPLETE)) 477ef76025aSStefan Roese puts(" TIMEOUT!\n"); 478ef76025aSStefan Roese else 479ef76025aSStefan Roese puts(" done\n"); 4805b1b1883SVipin KUMAR #else 48113edd170SVipin Kumar priv->phy_configured = 1; 482ef76025aSStefan Roese #endif 483ef76025aSStefan Roese 484ef76025aSStefan Roese priv->speed = miiphy_speed(dev->name, phy_addr); 485ef76025aSStefan Roese priv->duplex = miiphy_duplex(dev->name, phy_addr); 48613edd170SVipin Kumar 4875b1b1883SVipin KUMAR return 0; 4885b1b1883SVipin KUMAR } 4895b1b1883SVipin KUMAR 4905b1b1883SVipin KUMAR #if defined(CONFIG_MII) 4915700bb63SMike Frysinger static int dw_mii_read(const char *devname, u8 addr, u8 reg, u16 *val) 4925b1b1883SVipin KUMAR { 4935b1b1883SVipin KUMAR struct eth_device *dev; 4945b1b1883SVipin KUMAR 4955b1b1883SVipin KUMAR dev = eth_get_dev_by_name(devname); 4965b1b1883SVipin KUMAR if (dev) 4975b1b1883SVipin KUMAR eth_mdio_read(dev, addr, reg, val); 4985b1b1883SVipin KUMAR 4995b1b1883SVipin KUMAR return 0; 5005b1b1883SVipin KUMAR } 5015b1b1883SVipin KUMAR 5025700bb63SMike Frysinger static int dw_mii_write(const char *devname, u8 addr, u8 reg, u16 val) 5035b1b1883SVipin KUMAR { 5045b1b1883SVipin KUMAR struct eth_device *dev; 5055b1b1883SVipin KUMAR 5065b1b1883SVipin KUMAR dev = eth_get_dev_by_name(devname); 5075b1b1883SVipin KUMAR if (dev) 5085b1b1883SVipin KUMAR eth_mdio_write(dev, addr, reg, val); 5095b1b1883SVipin KUMAR 5105b1b1883SVipin KUMAR return 0; 5115b1b1883SVipin KUMAR } 5125b1b1883SVipin KUMAR #endif 5135b1b1883SVipin KUMAR 5149afc1af0SVipin Kumar int designware_initialize(u32 id, ulong base_addr, u32 phy_addr, u32 interface) 5155b1b1883SVipin KUMAR { 5165b1b1883SVipin KUMAR struct eth_device *dev; 5175b1b1883SVipin KUMAR struct dw_eth_dev *priv; 5185b1b1883SVipin KUMAR 5195b1b1883SVipin KUMAR dev = (struct eth_device *) malloc(sizeof(struct eth_device)); 5205b1b1883SVipin KUMAR if (!dev) 5215b1b1883SVipin KUMAR return -ENOMEM; 5225b1b1883SVipin KUMAR 5235b1b1883SVipin KUMAR /* 5245b1b1883SVipin KUMAR * Since the priv structure contains the descriptors which need a strict 5255b1b1883SVipin KUMAR * buswidth alignment, memalign is used to allocate memory 5265b1b1883SVipin KUMAR */ 5275b1b1883SVipin KUMAR priv = (struct dw_eth_dev *) memalign(16, sizeof(struct dw_eth_dev)); 5285b1b1883SVipin KUMAR if (!priv) { 5295b1b1883SVipin KUMAR free(dev); 5305b1b1883SVipin KUMAR return -ENOMEM; 5315b1b1883SVipin KUMAR } 5325b1b1883SVipin KUMAR 5335b1b1883SVipin KUMAR memset(dev, 0, sizeof(struct eth_device)); 5345b1b1883SVipin KUMAR memset(priv, 0, sizeof(struct dw_eth_dev)); 5355b1b1883SVipin KUMAR 5365b1b1883SVipin KUMAR sprintf(dev->name, "mii%d", id); 5375b1b1883SVipin KUMAR dev->iobase = (int)base_addr; 5385b1b1883SVipin KUMAR dev->priv = priv; 5395b1b1883SVipin KUMAR 5407616e785SSimon Glass eth_getenv_enetaddr_by_index("eth", id, &dev->enetaddr[0]); 5415b1b1883SVipin KUMAR 5425b1b1883SVipin KUMAR priv->dev = dev; 5435b1b1883SVipin KUMAR priv->mac_regs_p = (struct eth_mac_regs *)base_addr; 5445b1b1883SVipin KUMAR priv->dma_regs_p = (struct eth_dma_regs *)(base_addr + 5455b1b1883SVipin KUMAR DW_DMA_BASE_OFFSET); 5465b1b1883SVipin KUMAR priv->address = phy_addr; 54713edd170SVipin Kumar priv->phy_configured = 0; 5489afc1af0SVipin Kumar priv->interface = interface; 5495b1b1883SVipin KUMAR 5505b1b1883SVipin KUMAR dev->init = dw_eth_init; 5515b1b1883SVipin KUMAR dev->send = dw_eth_send; 5525b1b1883SVipin KUMAR dev->recv = dw_eth_recv; 5535b1b1883SVipin KUMAR dev->halt = dw_eth_halt; 5545b1b1883SVipin KUMAR dev->write_hwaddr = dw_write_hwaddr; 5555b1b1883SVipin KUMAR 5565b1b1883SVipin KUMAR eth_register(dev); 5575b1b1883SVipin KUMAR 5585b1b1883SVipin KUMAR #if defined(CONFIG_MII) 5595b1b1883SVipin KUMAR miiphy_register(dev->name, dw_mii_read, dw_mii_write); 5605b1b1883SVipin KUMAR #endif 5615b1b1883SVipin KUMAR return 1; 5625b1b1883SVipin KUMAR } 563