1*5b1b1883SVipin KUMAR /* 2*5b1b1883SVipin KUMAR * (C) Copyright 2010 3*5b1b1883SVipin KUMAR * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com. 4*5b1b1883SVipin KUMAR * 5*5b1b1883SVipin KUMAR * See file CREDITS for list of people who contributed to this 6*5b1b1883SVipin KUMAR * project. 7*5b1b1883SVipin KUMAR * 8*5b1b1883SVipin KUMAR * This program is free software; you can redistribute it and/or 9*5b1b1883SVipin KUMAR * modify it under the terms of the GNU General Public License as 10*5b1b1883SVipin KUMAR * published by the Free Software Foundation; either version 2 of 11*5b1b1883SVipin KUMAR * the License, or (at your option) any later version. 12*5b1b1883SVipin KUMAR * 13*5b1b1883SVipin KUMAR * This program is distributed in the hope that it will be useful, 14*5b1b1883SVipin KUMAR * but WITHOUT ANY WARRANTY; without even the implied warranty of 15*5b1b1883SVipin KUMAR * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16*5b1b1883SVipin KUMAR * GNU General Public License for more details. 17*5b1b1883SVipin KUMAR * 18*5b1b1883SVipin KUMAR * You should have received a copy of the GNU General Public License 19*5b1b1883SVipin KUMAR * along with this program; if not, write to the Free Software 20*5b1b1883SVipin KUMAR * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 21*5b1b1883SVipin KUMAR * MA 02111-1307 USA 22*5b1b1883SVipin KUMAR */ 23*5b1b1883SVipin KUMAR 24*5b1b1883SVipin KUMAR /* 25*5b1b1883SVipin KUMAR * Designware ethernet IP driver for u-boot 26*5b1b1883SVipin KUMAR */ 27*5b1b1883SVipin KUMAR 28*5b1b1883SVipin KUMAR #include <common.h> 29*5b1b1883SVipin KUMAR #include <miiphy.h> 30*5b1b1883SVipin KUMAR #include <malloc.h> 31*5b1b1883SVipin KUMAR #include <linux/err.h> 32*5b1b1883SVipin KUMAR #include <asm/io.h> 33*5b1b1883SVipin KUMAR #include "designware.h" 34*5b1b1883SVipin KUMAR 35*5b1b1883SVipin KUMAR static void tx_descs_init(struct eth_device *dev) 36*5b1b1883SVipin KUMAR { 37*5b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 38*5b1b1883SVipin KUMAR struct eth_dma_regs *dma_p = priv->dma_regs_p; 39*5b1b1883SVipin KUMAR struct dmamacdescr *desc_table_p = &priv->tx_mac_descrtable[0]; 40*5b1b1883SVipin KUMAR char *txbuffs = &priv->txbuffs[0]; 41*5b1b1883SVipin KUMAR struct dmamacdescr *desc_p; 42*5b1b1883SVipin KUMAR u32 idx; 43*5b1b1883SVipin KUMAR 44*5b1b1883SVipin KUMAR for (idx = 0; idx < CONFIG_TX_DESCR_NUM; idx++) { 45*5b1b1883SVipin KUMAR desc_p = &desc_table_p[idx]; 46*5b1b1883SVipin KUMAR desc_p->dmamac_addr = &txbuffs[idx * CONFIG_ETH_BUFSIZE]; 47*5b1b1883SVipin KUMAR desc_p->dmamac_next = &desc_table_p[idx + 1]; 48*5b1b1883SVipin KUMAR 49*5b1b1883SVipin KUMAR #if defined(CONFIG_DW_ALTDESCRIPTOR) 50*5b1b1883SVipin KUMAR desc_p->txrx_status &= ~(DESC_TXSTS_TXINT | DESC_TXSTS_TXLAST | 51*5b1b1883SVipin KUMAR DESC_TXSTS_TXFIRST | DESC_TXSTS_TXCRCDIS | \ 52*5b1b1883SVipin KUMAR DESC_TXSTS_TXCHECKINSCTRL | \ 53*5b1b1883SVipin KUMAR DESC_TXSTS_TXRINGEND | DESC_TXSTS_TXPADDIS); 54*5b1b1883SVipin KUMAR 55*5b1b1883SVipin KUMAR desc_p->txrx_status |= DESC_TXSTS_TXCHAIN; 56*5b1b1883SVipin KUMAR desc_p->dmamac_cntl = 0; 57*5b1b1883SVipin KUMAR desc_p->txrx_status &= ~(DESC_TXSTS_MSK | DESC_TXSTS_OWNBYDMA); 58*5b1b1883SVipin KUMAR #else 59*5b1b1883SVipin KUMAR desc_p->dmamac_cntl = DESC_TXCTRL_TXCHAIN; 60*5b1b1883SVipin KUMAR desc_p->txrx_status = 0; 61*5b1b1883SVipin KUMAR #endif 62*5b1b1883SVipin KUMAR } 63*5b1b1883SVipin KUMAR 64*5b1b1883SVipin KUMAR /* Correcting the last pointer of the chain */ 65*5b1b1883SVipin KUMAR desc_p->dmamac_next = &desc_table_p[0]; 66*5b1b1883SVipin KUMAR 67*5b1b1883SVipin KUMAR writel((ulong)&desc_table_p[0], &dma_p->txdesclistaddr); 68*5b1b1883SVipin KUMAR } 69*5b1b1883SVipin KUMAR 70*5b1b1883SVipin KUMAR static void rx_descs_init(struct eth_device *dev) 71*5b1b1883SVipin KUMAR { 72*5b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 73*5b1b1883SVipin KUMAR struct eth_dma_regs *dma_p = priv->dma_regs_p; 74*5b1b1883SVipin KUMAR struct dmamacdescr *desc_table_p = &priv->rx_mac_descrtable[0]; 75*5b1b1883SVipin KUMAR char *rxbuffs = &priv->rxbuffs[0]; 76*5b1b1883SVipin KUMAR struct dmamacdescr *desc_p; 77*5b1b1883SVipin KUMAR u32 idx; 78*5b1b1883SVipin KUMAR 79*5b1b1883SVipin KUMAR for (idx = 0; idx < CONFIG_RX_DESCR_NUM; idx++) { 80*5b1b1883SVipin KUMAR desc_p = &desc_table_p[idx]; 81*5b1b1883SVipin KUMAR desc_p->dmamac_addr = &rxbuffs[idx * CONFIG_ETH_BUFSIZE]; 82*5b1b1883SVipin KUMAR desc_p->dmamac_next = &desc_table_p[idx + 1]; 83*5b1b1883SVipin KUMAR 84*5b1b1883SVipin KUMAR desc_p->dmamac_cntl = 85*5b1b1883SVipin KUMAR (MAC_MAX_FRAME_SZ & DESC_RXCTRL_SIZE1MASK) | \ 86*5b1b1883SVipin KUMAR DESC_RXCTRL_RXCHAIN; 87*5b1b1883SVipin KUMAR 88*5b1b1883SVipin KUMAR desc_p->txrx_status = DESC_RXSTS_OWNBYDMA; 89*5b1b1883SVipin KUMAR } 90*5b1b1883SVipin KUMAR 91*5b1b1883SVipin KUMAR /* Correcting the last pointer of the chain */ 92*5b1b1883SVipin KUMAR desc_p->dmamac_next = &desc_table_p[0]; 93*5b1b1883SVipin KUMAR 94*5b1b1883SVipin KUMAR writel((ulong)&desc_table_p[0], &dma_p->rxdesclistaddr); 95*5b1b1883SVipin KUMAR } 96*5b1b1883SVipin KUMAR 97*5b1b1883SVipin KUMAR static void descs_init(struct eth_device *dev) 98*5b1b1883SVipin KUMAR { 99*5b1b1883SVipin KUMAR tx_descs_init(dev); 100*5b1b1883SVipin KUMAR rx_descs_init(dev); 101*5b1b1883SVipin KUMAR } 102*5b1b1883SVipin KUMAR 103*5b1b1883SVipin KUMAR static int mac_reset(struct eth_device *dev) 104*5b1b1883SVipin KUMAR { 105*5b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 106*5b1b1883SVipin KUMAR struct eth_mac_regs *mac_p = priv->mac_regs_p; 107*5b1b1883SVipin KUMAR struct eth_dma_regs *dma_p = priv->dma_regs_p; 108*5b1b1883SVipin KUMAR 109*5b1b1883SVipin KUMAR int timeout = CONFIG_MACRESET_TIMEOUT; 110*5b1b1883SVipin KUMAR 111*5b1b1883SVipin KUMAR writel(DMAMAC_SRST, &dma_p->busmode); 112*5b1b1883SVipin KUMAR writel(MII_PORTSELECT, &mac_p->conf); 113*5b1b1883SVipin KUMAR 114*5b1b1883SVipin KUMAR do { 115*5b1b1883SVipin KUMAR if (!(readl(&dma_p->busmode) & DMAMAC_SRST)) 116*5b1b1883SVipin KUMAR return 0; 117*5b1b1883SVipin KUMAR udelay(1000); 118*5b1b1883SVipin KUMAR } while (timeout--); 119*5b1b1883SVipin KUMAR 120*5b1b1883SVipin KUMAR return -1; 121*5b1b1883SVipin KUMAR } 122*5b1b1883SVipin KUMAR 123*5b1b1883SVipin KUMAR static int dw_write_hwaddr(struct eth_device *dev) 124*5b1b1883SVipin KUMAR { 125*5b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 126*5b1b1883SVipin KUMAR struct eth_mac_regs *mac_p = priv->mac_regs_p; 127*5b1b1883SVipin KUMAR u32 macid_lo, macid_hi; 128*5b1b1883SVipin KUMAR u8 *mac_id = &dev->enetaddr[0]; 129*5b1b1883SVipin KUMAR 130*5b1b1883SVipin KUMAR macid_lo = mac_id[0] + (mac_id[1] << 8) + \ 131*5b1b1883SVipin KUMAR (mac_id[2] << 16) + (mac_id[3] << 24); 132*5b1b1883SVipin KUMAR macid_hi = mac_id[4] + (mac_id[5] << 8); 133*5b1b1883SVipin KUMAR 134*5b1b1883SVipin KUMAR writel(macid_hi, &mac_p->macaddr0hi); 135*5b1b1883SVipin KUMAR writel(macid_lo, &mac_p->macaddr0lo); 136*5b1b1883SVipin KUMAR 137*5b1b1883SVipin KUMAR return 0; 138*5b1b1883SVipin KUMAR } 139*5b1b1883SVipin KUMAR 140*5b1b1883SVipin KUMAR static int dw_eth_init(struct eth_device *dev, bd_t *bis) 141*5b1b1883SVipin KUMAR { 142*5b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 143*5b1b1883SVipin KUMAR struct eth_mac_regs *mac_p = priv->mac_regs_p; 144*5b1b1883SVipin KUMAR struct eth_dma_regs *dma_p = priv->dma_regs_p; 145*5b1b1883SVipin KUMAR u32 conf; 146*5b1b1883SVipin KUMAR 147*5b1b1883SVipin KUMAR /* Reset ethernet hardware */ 148*5b1b1883SVipin KUMAR if (mac_reset(dev) < 0) 149*5b1b1883SVipin KUMAR return -1; 150*5b1b1883SVipin KUMAR 151*5b1b1883SVipin KUMAR writel(FIXEDBURST | PRIORXTX_41 | BURST_16, 152*5b1b1883SVipin KUMAR &dma_p->busmode); 153*5b1b1883SVipin KUMAR 154*5b1b1883SVipin KUMAR writel(FLUSHTXFIFO | readl(&dma_p->opmode), &dma_p->opmode); 155*5b1b1883SVipin KUMAR writel(STOREFORWARD | TXSECONDFRAME, &dma_p->opmode); 156*5b1b1883SVipin KUMAR 157*5b1b1883SVipin KUMAR conf = FRAMEBURSTENABLE | DISABLERXOWN; 158*5b1b1883SVipin KUMAR 159*5b1b1883SVipin KUMAR if (priv->speed != SPEED_1000M) 160*5b1b1883SVipin KUMAR conf |= MII_PORTSELECT; 161*5b1b1883SVipin KUMAR 162*5b1b1883SVipin KUMAR if (priv->duplex == FULL_DUPLEX) 163*5b1b1883SVipin KUMAR conf |= FULLDPLXMODE; 164*5b1b1883SVipin KUMAR 165*5b1b1883SVipin KUMAR writel(conf, &mac_p->conf); 166*5b1b1883SVipin KUMAR 167*5b1b1883SVipin KUMAR descs_init(dev); 168*5b1b1883SVipin KUMAR 169*5b1b1883SVipin KUMAR /* 170*5b1b1883SVipin KUMAR * Start/Enable xfer at dma as well as mac level 171*5b1b1883SVipin KUMAR */ 172*5b1b1883SVipin KUMAR writel(readl(&dma_p->opmode) | RXSTART, &dma_p->opmode); 173*5b1b1883SVipin KUMAR writel(readl(&dma_p->opmode) | TXSTART, &dma_p->opmode); 174*5b1b1883SVipin KUMAR 175*5b1b1883SVipin KUMAR writel(readl(&mac_p->conf) | RXENABLE, &mac_p->conf); 176*5b1b1883SVipin KUMAR writel(readl(&mac_p->conf) | TXENABLE, &mac_p->conf); 177*5b1b1883SVipin KUMAR 178*5b1b1883SVipin KUMAR return 0; 179*5b1b1883SVipin KUMAR } 180*5b1b1883SVipin KUMAR 181*5b1b1883SVipin KUMAR static int dw_eth_send(struct eth_device *dev, volatile void *packet, 182*5b1b1883SVipin KUMAR int length) 183*5b1b1883SVipin KUMAR { 184*5b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 185*5b1b1883SVipin KUMAR struct eth_dma_regs *dma_p = priv->dma_regs_p; 186*5b1b1883SVipin KUMAR u32 desc_num = priv->tx_currdescnum; 187*5b1b1883SVipin KUMAR struct dmamacdescr *desc_p = &priv->tx_mac_descrtable[desc_num]; 188*5b1b1883SVipin KUMAR 189*5b1b1883SVipin KUMAR /* Check if the descriptor is owned by CPU */ 190*5b1b1883SVipin KUMAR if (desc_p->txrx_status & DESC_TXSTS_OWNBYDMA) { 191*5b1b1883SVipin KUMAR printf("CPU not owner of tx frame\n"); 192*5b1b1883SVipin KUMAR return -1; 193*5b1b1883SVipin KUMAR } 194*5b1b1883SVipin KUMAR 195*5b1b1883SVipin KUMAR memcpy((void *)desc_p->dmamac_addr, (void *)packet, length); 196*5b1b1883SVipin KUMAR 197*5b1b1883SVipin KUMAR #if defined(CONFIG_DW_ALTDESCRIPTOR) 198*5b1b1883SVipin KUMAR desc_p->txrx_status |= DESC_TXSTS_TXFIRST | DESC_TXSTS_TXLAST; 199*5b1b1883SVipin KUMAR desc_p->dmamac_cntl |= (length << DESC_TXCTRL_SIZE1SHFT) & \ 200*5b1b1883SVipin KUMAR DESC_TXCTRL_SIZE1MASK; 201*5b1b1883SVipin KUMAR 202*5b1b1883SVipin KUMAR desc_p->txrx_status &= ~(DESC_TXSTS_MSK); 203*5b1b1883SVipin KUMAR desc_p->txrx_status |= DESC_TXSTS_OWNBYDMA; 204*5b1b1883SVipin KUMAR #else 205*5b1b1883SVipin KUMAR desc_p->dmamac_cntl |= ((length << DESC_TXCTRL_SIZE1SHFT) & \ 206*5b1b1883SVipin KUMAR DESC_TXCTRL_SIZE1MASK) | DESC_TXCTRL_TXLAST | \ 207*5b1b1883SVipin KUMAR DESC_TXCTRL_TXFIRST; 208*5b1b1883SVipin KUMAR 209*5b1b1883SVipin KUMAR desc_p->txrx_status = DESC_TXSTS_OWNBYDMA; 210*5b1b1883SVipin KUMAR #endif 211*5b1b1883SVipin KUMAR 212*5b1b1883SVipin KUMAR /* Test the wrap-around condition. */ 213*5b1b1883SVipin KUMAR if (++desc_num >= CONFIG_TX_DESCR_NUM) 214*5b1b1883SVipin KUMAR desc_num = 0; 215*5b1b1883SVipin KUMAR 216*5b1b1883SVipin KUMAR priv->tx_currdescnum = desc_num; 217*5b1b1883SVipin KUMAR 218*5b1b1883SVipin KUMAR /* Start the transmission */ 219*5b1b1883SVipin KUMAR writel(POLL_DATA, &dma_p->txpolldemand); 220*5b1b1883SVipin KUMAR 221*5b1b1883SVipin KUMAR return 0; 222*5b1b1883SVipin KUMAR } 223*5b1b1883SVipin KUMAR 224*5b1b1883SVipin KUMAR static int dw_eth_recv(struct eth_device *dev) 225*5b1b1883SVipin KUMAR { 226*5b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 227*5b1b1883SVipin KUMAR u32 desc_num = priv->rx_currdescnum; 228*5b1b1883SVipin KUMAR struct dmamacdescr *desc_p = &priv->rx_mac_descrtable[desc_num]; 229*5b1b1883SVipin KUMAR 230*5b1b1883SVipin KUMAR u32 status = desc_p->txrx_status; 231*5b1b1883SVipin KUMAR int length = 0; 232*5b1b1883SVipin KUMAR 233*5b1b1883SVipin KUMAR /* Check if the owner is the CPU */ 234*5b1b1883SVipin KUMAR if (!(status & DESC_RXSTS_OWNBYDMA)) { 235*5b1b1883SVipin KUMAR 236*5b1b1883SVipin KUMAR length = (status & DESC_RXSTS_FRMLENMSK) >> \ 237*5b1b1883SVipin KUMAR DESC_RXSTS_FRMLENSHFT; 238*5b1b1883SVipin KUMAR 239*5b1b1883SVipin KUMAR NetReceive(desc_p->dmamac_addr, length); 240*5b1b1883SVipin KUMAR 241*5b1b1883SVipin KUMAR /* 242*5b1b1883SVipin KUMAR * Make the current descriptor valid again and go to 243*5b1b1883SVipin KUMAR * the next one 244*5b1b1883SVipin KUMAR */ 245*5b1b1883SVipin KUMAR desc_p->txrx_status |= DESC_RXSTS_OWNBYDMA; 246*5b1b1883SVipin KUMAR 247*5b1b1883SVipin KUMAR /* Test the wrap-around condition. */ 248*5b1b1883SVipin KUMAR if (++desc_num >= CONFIG_RX_DESCR_NUM) 249*5b1b1883SVipin KUMAR desc_num = 0; 250*5b1b1883SVipin KUMAR } 251*5b1b1883SVipin KUMAR 252*5b1b1883SVipin KUMAR priv->rx_currdescnum = desc_num; 253*5b1b1883SVipin KUMAR 254*5b1b1883SVipin KUMAR return length; 255*5b1b1883SVipin KUMAR } 256*5b1b1883SVipin KUMAR 257*5b1b1883SVipin KUMAR static void dw_eth_halt(struct eth_device *dev) 258*5b1b1883SVipin KUMAR { 259*5b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 260*5b1b1883SVipin KUMAR 261*5b1b1883SVipin KUMAR mac_reset(dev); 262*5b1b1883SVipin KUMAR priv->tx_currdescnum = priv->rx_currdescnum = 0; 263*5b1b1883SVipin KUMAR } 264*5b1b1883SVipin KUMAR 265*5b1b1883SVipin KUMAR static int eth_mdio_read(struct eth_device *dev, u8 addr, u8 reg, u16 *val) 266*5b1b1883SVipin KUMAR { 267*5b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 268*5b1b1883SVipin KUMAR struct eth_mac_regs *mac_p = priv->mac_regs_p; 269*5b1b1883SVipin KUMAR u32 miiaddr; 270*5b1b1883SVipin KUMAR int timeout = CONFIG_MDIO_TIMEOUT; 271*5b1b1883SVipin KUMAR 272*5b1b1883SVipin KUMAR miiaddr = ((addr << MIIADDRSHIFT) & MII_ADDRMSK) | \ 273*5b1b1883SVipin KUMAR ((reg << MIIREGSHIFT) & MII_REGMSK); 274*5b1b1883SVipin KUMAR 275*5b1b1883SVipin KUMAR writel(miiaddr | MII_CLKRANGE_150_250M | MII_BUSY, &mac_p->miiaddr); 276*5b1b1883SVipin KUMAR 277*5b1b1883SVipin KUMAR do { 278*5b1b1883SVipin KUMAR if (!(readl(&mac_p->miiaddr) & MII_BUSY)) { 279*5b1b1883SVipin KUMAR *val = readl(&mac_p->miidata); 280*5b1b1883SVipin KUMAR return 0; 281*5b1b1883SVipin KUMAR } 282*5b1b1883SVipin KUMAR udelay(1000); 283*5b1b1883SVipin KUMAR } while (timeout--); 284*5b1b1883SVipin KUMAR 285*5b1b1883SVipin KUMAR return -1; 286*5b1b1883SVipin KUMAR } 287*5b1b1883SVipin KUMAR 288*5b1b1883SVipin KUMAR static int eth_mdio_write(struct eth_device *dev, u8 addr, u8 reg, u16 val) 289*5b1b1883SVipin KUMAR { 290*5b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 291*5b1b1883SVipin KUMAR struct eth_mac_regs *mac_p = priv->mac_regs_p; 292*5b1b1883SVipin KUMAR u32 miiaddr; 293*5b1b1883SVipin KUMAR int ret = -1, timeout = CONFIG_MDIO_TIMEOUT; 294*5b1b1883SVipin KUMAR u16 value; 295*5b1b1883SVipin KUMAR 296*5b1b1883SVipin KUMAR writel(val, &mac_p->miidata); 297*5b1b1883SVipin KUMAR miiaddr = ((addr << MIIADDRSHIFT) & MII_ADDRMSK) | \ 298*5b1b1883SVipin KUMAR ((reg << MIIREGSHIFT) & MII_REGMSK) | MII_WRITE; 299*5b1b1883SVipin KUMAR 300*5b1b1883SVipin KUMAR writel(miiaddr | MII_CLKRANGE_150_250M | MII_BUSY, &mac_p->miiaddr); 301*5b1b1883SVipin KUMAR 302*5b1b1883SVipin KUMAR do { 303*5b1b1883SVipin KUMAR if (!(readl(&mac_p->miiaddr) & MII_BUSY)) 304*5b1b1883SVipin KUMAR ret = 0; 305*5b1b1883SVipin KUMAR udelay(1000); 306*5b1b1883SVipin KUMAR } while (timeout--); 307*5b1b1883SVipin KUMAR 308*5b1b1883SVipin KUMAR /* Needed as a fix for ST-Phy */ 309*5b1b1883SVipin KUMAR eth_mdio_read(dev, addr, reg, &value); 310*5b1b1883SVipin KUMAR 311*5b1b1883SVipin KUMAR return ret; 312*5b1b1883SVipin KUMAR } 313*5b1b1883SVipin KUMAR 314*5b1b1883SVipin KUMAR #if defined(CONFIG_DW_SEARCH_PHY) 315*5b1b1883SVipin KUMAR static int find_phy(struct eth_device *dev) 316*5b1b1883SVipin KUMAR { 317*5b1b1883SVipin KUMAR int phy_addr = 0; 318*5b1b1883SVipin KUMAR u16 ctrl, oldctrl; 319*5b1b1883SVipin KUMAR 320*5b1b1883SVipin KUMAR do { 321*5b1b1883SVipin KUMAR eth_mdio_read(dev, phy_addr, PHY_BMCR, &ctrl); 322*5b1b1883SVipin KUMAR oldctrl = ctrl & PHY_BMCR_AUTON; 323*5b1b1883SVipin KUMAR 324*5b1b1883SVipin KUMAR ctrl ^= PHY_BMCR_AUTON; 325*5b1b1883SVipin KUMAR eth_mdio_write(dev, phy_addr, PHY_BMCR, ctrl); 326*5b1b1883SVipin KUMAR eth_mdio_read(dev, phy_addr, PHY_BMCR, &ctrl); 327*5b1b1883SVipin KUMAR ctrl &= PHY_BMCR_AUTON; 328*5b1b1883SVipin KUMAR 329*5b1b1883SVipin KUMAR if (ctrl == oldctrl) { 330*5b1b1883SVipin KUMAR phy_addr++; 331*5b1b1883SVipin KUMAR } else { 332*5b1b1883SVipin KUMAR ctrl ^= PHY_BMCR_AUTON; 333*5b1b1883SVipin KUMAR eth_mdio_write(dev, phy_addr, PHY_BMCR, ctrl); 334*5b1b1883SVipin KUMAR 335*5b1b1883SVipin KUMAR return phy_addr; 336*5b1b1883SVipin KUMAR } 337*5b1b1883SVipin KUMAR } while (phy_addr < 32); 338*5b1b1883SVipin KUMAR 339*5b1b1883SVipin KUMAR return -1; 340*5b1b1883SVipin KUMAR } 341*5b1b1883SVipin KUMAR #endif 342*5b1b1883SVipin KUMAR 343*5b1b1883SVipin KUMAR static int dw_reset_phy(struct eth_device *dev) 344*5b1b1883SVipin KUMAR { 345*5b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 346*5b1b1883SVipin KUMAR u16 ctrl; 347*5b1b1883SVipin KUMAR int timeout = CONFIG_PHYRESET_TIMEOUT; 348*5b1b1883SVipin KUMAR u32 phy_addr = priv->address; 349*5b1b1883SVipin KUMAR 350*5b1b1883SVipin KUMAR eth_mdio_write(dev, phy_addr, PHY_BMCR, PHY_BMCR_RESET); 351*5b1b1883SVipin KUMAR do { 352*5b1b1883SVipin KUMAR eth_mdio_read(dev, phy_addr, PHY_BMCR, &ctrl); 353*5b1b1883SVipin KUMAR if (!(ctrl & PHY_BMCR_RESET)) 354*5b1b1883SVipin KUMAR break; 355*5b1b1883SVipin KUMAR udelay(1000); 356*5b1b1883SVipin KUMAR } while (timeout--); 357*5b1b1883SVipin KUMAR 358*5b1b1883SVipin KUMAR if (timeout < 0) 359*5b1b1883SVipin KUMAR return -1; 360*5b1b1883SVipin KUMAR 361*5b1b1883SVipin KUMAR #ifdef CONFIG_PHY_RESET_DELAY 362*5b1b1883SVipin KUMAR udelay(CONFIG_PHY_RESET_DELAY); 363*5b1b1883SVipin KUMAR #endif 364*5b1b1883SVipin KUMAR return 0; 365*5b1b1883SVipin KUMAR } 366*5b1b1883SVipin KUMAR 367*5b1b1883SVipin KUMAR static int configure_phy(struct eth_device *dev) 368*5b1b1883SVipin KUMAR { 369*5b1b1883SVipin KUMAR struct dw_eth_dev *priv = dev->priv; 370*5b1b1883SVipin KUMAR int phy_addr; 371*5b1b1883SVipin KUMAR u16 bmcr, ctrl; 372*5b1b1883SVipin KUMAR #if defined(CONFIG_DW_AUTONEG) 373*5b1b1883SVipin KUMAR u16 bmsr; 374*5b1b1883SVipin KUMAR u32 timeout; 375*5b1b1883SVipin KUMAR u16 anlpar, btsr; 376*5b1b1883SVipin KUMAR #endif 377*5b1b1883SVipin KUMAR 378*5b1b1883SVipin KUMAR #if defined(CONFIG_DW_SEARCH_PHY) 379*5b1b1883SVipin KUMAR phy_addr = find_phy(dev); 380*5b1b1883SVipin KUMAR if (phy_addr > 0) 381*5b1b1883SVipin KUMAR priv->address = phy_addr; 382*5b1b1883SVipin KUMAR else 383*5b1b1883SVipin KUMAR return -1; 384*5b1b1883SVipin KUMAR #endif 385*5b1b1883SVipin KUMAR if (dw_reset_phy(dev) < 0) 386*5b1b1883SVipin KUMAR return -1; 387*5b1b1883SVipin KUMAR 388*5b1b1883SVipin KUMAR #if defined(CONFIG_DW_AUTONEG) 389*5b1b1883SVipin KUMAR bmcr = PHY_BMCR_AUTON | PHY_BMCR_RST_NEG | PHY_BMCR_100MB | \ 390*5b1b1883SVipin KUMAR PHY_BMCR_DPLX | PHY_BMCR_1000_MBPS; 391*5b1b1883SVipin KUMAR #else 392*5b1b1883SVipin KUMAR bmcr = PHY_BMCR_100MB | PHY_BMCR_DPLX; 393*5b1b1883SVipin KUMAR 394*5b1b1883SVipin KUMAR #if defined(CONFIG_DW_SPEED10M) 395*5b1b1883SVipin KUMAR bmcr &= ~PHY_BMCR_100MB; 396*5b1b1883SVipin KUMAR #endif 397*5b1b1883SVipin KUMAR #if defined(CONFIG_DW_DUPLEXHALF) 398*5b1b1883SVipin KUMAR bmcr &= ~PHY_BMCR_DPLX; 399*5b1b1883SVipin KUMAR #endif 400*5b1b1883SVipin KUMAR #endif 401*5b1b1883SVipin KUMAR if (eth_mdio_write(dev, phy_addr, PHY_BMCR, bmcr) < 0) 402*5b1b1883SVipin KUMAR return -1; 403*5b1b1883SVipin KUMAR 404*5b1b1883SVipin KUMAR /* Read the phy status register and populate priv structure */ 405*5b1b1883SVipin KUMAR #if defined(CONFIG_DW_AUTONEG) 406*5b1b1883SVipin KUMAR timeout = CONFIG_AUTONEG_TIMEOUT; 407*5b1b1883SVipin KUMAR do { 408*5b1b1883SVipin KUMAR eth_mdio_read(dev, phy_addr, PHY_BMSR, &bmsr); 409*5b1b1883SVipin KUMAR if (bmsr & PHY_BMSR_AUTN_COMP) 410*5b1b1883SVipin KUMAR break; 411*5b1b1883SVipin KUMAR udelay(1000); 412*5b1b1883SVipin KUMAR } while (timeout--); 413*5b1b1883SVipin KUMAR 414*5b1b1883SVipin KUMAR eth_mdio_read(dev, phy_addr, PHY_ANLPAR, &anlpar); 415*5b1b1883SVipin KUMAR eth_mdio_read(dev, phy_addr, PHY_1000BTSR, &btsr); 416*5b1b1883SVipin KUMAR 417*5b1b1883SVipin KUMAR if (btsr & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD)) { 418*5b1b1883SVipin KUMAR priv->speed = SPEED_1000M; 419*5b1b1883SVipin KUMAR if (btsr & PHY_1000BTSR_1000FD) 420*5b1b1883SVipin KUMAR priv->duplex = FULL_DUPLEX; 421*5b1b1883SVipin KUMAR else 422*5b1b1883SVipin KUMAR priv->duplex = HALF_DUPLEX; 423*5b1b1883SVipin KUMAR } else { 424*5b1b1883SVipin KUMAR if (anlpar & PHY_ANLPAR_100) 425*5b1b1883SVipin KUMAR priv->speed = SPEED_100M; 426*5b1b1883SVipin KUMAR else 427*5b1b1883SVipin KUMAR priv->speed = SPEED_10M; 428*5b1b1883SVipin KUMAR 429*5b1b1883SVipin KUMAR if (anlpar & (PHY_ANLPAR_10FD | PHY_ANLPAR_TXFD)) 430*5b1b1883SVipin KUMAR priv->duplex = FULL_DUPLEX; 431*5b1b1883SVipin KUMAR else 432*5b1b1883SVipin KUMAR priv->duplex = HALF_DUPLEX; 433*5b1b1883SVipin KUMAR } 434*5b1b1883SVipin KUMAR #else 435*5b1b1883SVipin KUMAR if (eth_mdio_read(dev, phy_addr, PHY_BMCR, &ctrl) < 0) 436*5b1b1883SVipin KUMAR return -1; 437*5b1b1883SVipin KUMAR 438*5b1b1883SVipin KUMAR if (ctrl & PHY_BMCR_DPLX) 439*5b1b1883SVipin KUMAR priv->duplex = FULL_DUPLEX; 440*5b1b1883SVipin KUMAR else 441*5b1b1883SVipin KUMAR priv->duplex = HALF_DUPLEX; 442*5b1b1883SVipin KUMAR 443*5b1b1883SVipin KUMAR if (ctrl & PHY_BMCR_1000_MBPS) 444*5b1b1883SVipin KUMAR priv->speed = SPEED_1000M; 445*5b1b1883SVipin KUMAR else if (ctrl & PHY_BMCR_100_MBPS) 446*5b1b1883SVipin KUMAR priv->speed = SPEED_100M; 447*5b1b1883SVipin KUMAR else 448*5b1b1883SVipin KUMAR priv->speed = SPEED_10M; 449*5b1b1883SVipin KUMAR #endif 450*5b1b1883SVipin KUMAR return 0; 451*5b1b1883SVipin KUMAR } 452*5b1b1883SVipin KUMAR 453*5b1b1883SVipin KUMAR #if defined(CONFIG_MII) 454*5b1b1883SVipin KUMAR static int dw_mii_read(char *devname, u8 addr, u8 reg, u16 *val) 455*5b1b1883SVipin KUMAR { 456*5b1b1883SVipin KUMAR struct eth_device *dev; 457*5b1b1883SVipin KUMAR 458*5b1b1883SVipin KUMAR dev = eth_get_dev_by_name(devname); 459*5b1b1883SVipin KUMAR if (dev) 460*5b1b1883SVipin KUMAR eth_mdio_read(dev, addr, reg, val); 461*5b1b1883SVipin KUMAR 462*5b1b1883SVipin KUMAR return 0; 463*5b1b1883SVipin KUMAR } 464*5b1b1883SVipin KUMAR 465*5b1b1883SVipin KUMAR static int dw_mii_write(char *devname, u8 addr, u8 reg, u16 val) 466*5b1b1883SVipin KUMAR { 467*5b1b1883SVipin KUMAR struct eth_device *dev; 468*5b1b1883SVipin KUMAR 469*5b1b1883SVipin KUMAR dev = eth_get_dev_by_name(devname); 470*5b1b1883SVipin KUMAR if (dev) 471*5b1b1883SVipin KUMAR eth_mdio_write(dev, addr, reg, val); 472*5b1b1883SVipin KUMAR 473*5b1b1883SVipin KUMAR return 0; 474*5b1b1883SVipin KUMAR } 475*5b1b1883SVipin KUMAR #endif 476*5b1b1883SVipin KUMAR 477*5b1b1883SVipin KUMAR int designware_initialize(u32 id, ulong base_addr, u32 phy_addr) 478*5b1b1883SVipin KUMAR { 479*5b1b1883SVipin KUMAR struct eth_device *dev; 480*5b1b1883SVipin KUMAR struct dw_eth_dev *priv; 481*5b1b1883SVipin KUMAR 482*5b1b1883SVipin KUMAR dev = (struct eth_device *) malloc(sizeof(struct eth_device)); 483*5b1b1883SVipin KUMAR if (!dev) 484*5b1b1883SVipin KUMAR return -ENOMEM; 485*5b1b1883SVipin KUMAR 486*5b1b1883SVipin KUMAR /* 487*5b1b1883SVipin KUMAR * Since the priv structure contains the descriptors which need a strict 488*5b1b1883SVipin KUMAR * buswidth alignment, memalign is used to allocate memory 489*5b1b1883SVipin KUMAR */ 490*5b1b1883SVipin KUMAR priv = (struct dw_eth_dev *) memalign(16, sizeof(struct dw_eth_dev)); 491*5b1b1883SVipin KUMAR if (!priv) { 492*5b1b1883SVipin KUMAR free(dev); 493*5b1b1883SVipin KUMAR return -ENOMEM; 494*5b1b1883SVipin KUMAR } 495*5b1b1883SVipin KUMAR 496*5b1b1883SVipin KUMAR memset(dev, 0, sizeof(struct eth_device)); 497*5b1b1883SVipin KUMAR memset(priv, 0, sizeof(struct dw_eth_dev)); 498*5b1b1883SVipin KUMAR 499*5b1b1883SVipin KUMAR sprintf(dev->name, "mii%d", id); 500*5b1b1883SVipin KUMAR dev->iobase = (int)base_addr; 501*5b1b1883SVipin KUMAR dev->priv = priv; 502*5b1b1883SVipin KUMAR 503*5b1b1883SVipin KUMAR eth_getenv_enetaddr_by_index(id, &dev->enetaddr[0]); 504*5b1b1883SVipin KUMAR 505*5b1b1883SVipin KUMAR priv->dev = dev; 506*5b1b1883SVipin KUMAR priv->mac_regs_p = (struct eth_mac_regs *)base_addr; 507*5b1b1883SVipin KUMAR priv->dma_regs_p = (struct eth_dma_regs *)(base_addr + 508*5b1b1883SVipin KUMAR DW_DMA_BASE_OFFSET); 509*5b1b1883SVipin KUMAR priv->address = phy_addr; 510*5b1b1883SVipin KUMAR 511*5b1b1883SVipin KUMAR if (mac_reset(dev) < 0) 512*5b1b1883SVipin KUMAR return -1; 513*5b1b1883SVipin KUMAR 514*5b1b1883SVipin KUMAR if (configure_phy(dev) < 0) { 515*5b1b1883SVipin KUMAR printf("Phy could not be configured\n"); 516*5b1b1883SVipin KUMAR return -1; 517*5b1b1883SVipin KUMAR } 518*5b1b1883SVipin KUMAR 519*5b1b1883SVipin KUMAR dev->init = dw_eth_init; 520*5b1b1883SVipin KUMAR dev->send = dw_eth_send; 521*5b1b1883SVipin KUMAR dev->recv = dw_eth_recv; 522*5b1b1883SVipin KUMAR dev->halt = dw_eth_halt; 523*5b1b1883SVipin KUMAR dev->write_hwaddr = dw_write_hwaddr; 524*5b1b1883SVipin KUMAR 525*5b1b1883SVipin KUMAR eth_register(dev); 526*5b1b1883SVipin KUMAR 527*5b1b1883SVipin KUMAR #if defined(CONFIG_MII) 528*5b1b1883SVipin KUMAR miiphy_register(dev->name, dw_mii_read, dw_mii_write); 529*5b1b1883SVipin KUMAR #endif 530*5b1b1883SVipin KUMAR return 1; 531*5b1b1883SVipin KUMAR } 532