xref: /rk3399_rockchip-uboot/drivers/net/designware.c (revision ee7f5bfd124c61370a2fa417ca6d21d587d23a3f)
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