xref: /rk3399_rockchip-uboot/drivers/net/designware.c (revision 13edd1706c56371dc6a67f7bef874f6d8b7af8eb)
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 
35*13edd170SVipin Kumar static int configure_phy(struct eth_device *dev);
36*13edd170SVipin Kumar 
375b1b1883SVipin KUMAR static void tx_descs_init(struct eth_device *dev)
385b1b1883SVipin KUMAR {
395b1b1883SVipin KUMAR 	struct dw_eth_dev *priv = dev->priv;
405b1b1883SVipin KUMAR 	struct eth_dma_regs *dma_p = priv->dma_regs_p;
415b1b1883SVipin KUMAR 	struct dmamacdescr *desc_table_p = &priv->tx_mac_descrtable[0];
425b1b1883SVipin KUMAR 	char *txbuffs = &priv->txbuffs[0];
435b1b1883SVipin KUMAR 	struct dmamacdescr *desc_p;
445b1b1883SVipin KUMAR 	u32 idx;
455b1b1883SVipin KUMAR 
465b1b1883SVipin KUMAR 	for (idx = 0; idx < CONFIG_TX_DESCR_NUM; idx++) {
475b1b1883SVipin KUMAR 		desc_p = &desc_table_p[idx];
485b1b1883SVipin KUMAR 		desc_p->dmamac_addr = &txbuffs[idx * CONFIG_ETH_BUFSIZE];
495b1b1883SVipin KUMAR 		desc_p->dmamac_next = &desc_table_p[idx + 1];
505b1b1883SVipin KUMAR 
515b1b1883SVipin KUMAR #if defined(CONFIG_DW_ALTDESCRIPTOR)
525b1b1883SVipin KUMAR 		desc_p->txrx_status &= ~(DESC_TXSTS_TXINT | DESC_TXSTS_TXLAST |
535b1b1883SVipin KUMAR 				DESC_TXSTS_TXFIRST | DESC_TXSTS_TXCRCDIS | \
545b1b1883SVipin KUMAR 				DESC_TXSTS_TXCHECKINSCTRL | \
555b1b1883SVipin KUMAR 				DESC_TXSTS_TXRINGEND | DESC_TXSTS_TXPADDIS);
565b1b1883SVipin KUMAR 
575b1b1883SVipin KUMAR 		desc_p->txrx_status |= DESC_TXSTS_TXCHAIN;
585b1b1883SVipin KUMAR 		desc_p->dmamac_cntl = 0;
595b1b1883SVipin KUMAR 		desc_p->txrx_status &= ~(DESC_TXSTS_MSK | DESC_TXSTS_OWNBYDMA);
605b1b1883SVipin KUMAR #else
615b1b1883SVipin KUMAR 		desc_p->dmamac_cntl = DESC_TXCTRL_TXCHAIN;
625b1b1883SVipin KUMAR 		desc_p->txrx_status = 0;
635b1b1883SVipin KUMAR #endif
645b1b1883SVipin KUMAR 	}
655b1b1883SVipin KUMAR 
665b1b1883SVipin KUMAR 	/* Correcting the last pointer of the chain */
675b1b1883SVipin KUMAR 	desc_p->dmamac_next = &desc_table_p[0];
685b1b1883SVipin KUMAR 
695b1b1883SVipin KUMAR 	writel((ulong)&desc_table_p[0], &dma_p->txdesclistaddr);
705b1b1883SVipin KUMAR }
715b1b1883SVipin KUMAR 
725b1b1883SVipin KUMAR static void rx_descs_init(struct eth_device *dev)
735b1b1883SVipin KUMAR {
745b1b1883SVipin KUMAR 	struct dw_eth_dev *priv = dev->priv;
755b1b1883SVipin KUMAR 	struct eth_dma_regs *dma_p = priv->dma_regs_p;
765b1b1883SVipin KUMAR 	struct dmamacdescr *desc_table_p = &priv->rx_mac_descrtable[0];
775b1b1883SVipin KUMAR 	char *rxbuffs = &priv->rxbuffs[0];
785b1b1883SVipin KUMAR 	struct dmamacdescr *desc_p;
795b1b1883SVipin KUMAR 	u32 idx;
805b1b1883SVipin KUMAR 
815b1b1883SVipin KUMAR 	for (idx = 0; idx < CONFIG_RX_DESCR_NUM; idx++) {
825b1b1883SVipin KUMAR 		desc_p = &desc_table_p[idx];
835b1b1883SVipin KUMAR 		desc_p->dmamac_addr = &rxbuffs[idx * CONFIG_ETH_BUFSIZE];
845b1b1883SVipin KUMAR 		desc_p->dmamac_next = &desc_table_p[idx + 1];
855b1b1883SVipin KUMAR 
865b1b1883SVipin KUMAR 		desc_p->dmamac_cntl =
875b1b1883SVipin KUMAR 			(MAC_MAX_FRAME_SZ & DESC_RXCTRL_SIZE1MASK) | \
885b1b1883SVipin KUMAR 				      DESC_RXCTRL_RXCHAIN;
895b1b1883SVipin KUMAR 
905b1b1883SVipin KUMAR 		desc_p->txrx_status = DESC_RXSTS_OWNBYDMA;
915b1b1883SVipin KUMAR 	}
925b1b1883SVipin KUMAR 
935b1b1883SVipin KUMAR 	/* Correcting the last pointer of the chain */
945b1b1883SVipin KUMAR 	desc_p->dmamac_next = &desc_table_p[0];
955b1b1883SVipin KUMAR 
965b1b1883SVipin KUMAR 	writel((ulong)&desc_table_p[0], &dma_p->rxdesclistaddr);
975b1b1883SVipin KUMAR }
985b1b1883SVipin KUMAR 
995b1b1883SVipin KUMAR static void descs_init(struct eth_device *dev)
1005b1b1883SVipin KUMAR {
1015b1b1883SVipin KUMAR 	tx_descs_init(dev);
1025b1b1883SVipin KUMAR 	rx_descs_init(dev);
1035b1b1883SVipin KUMAR }
1045b1b1883SVipin KUMAR 
1055b1b1883SVipin KUMAR static int mac_reset(struct eth_device *dev)
1065b1b1883SVipin KUMAR {
1075b1b1883SVipin KUMAR 	struct dw_eth_dev *priv = dev->priv;
1085b1b1883SVipin KUMAR 	struct eth_mac_regs *mac_p = priv->mac_regs_p;
1095b1b1883SVipin KUMAR 	struct eth_dma_regs *dma_p = priv->dma_regs_p;
1105b1b1883SVipin KUMAR 
1115b1b1883SVipin KUMAR 	int timeout = CONFIG_MACRESET_TIMEOUT;
1125b1b1883SVipin KUMAR 
1135b1b1883SVipin KUMAR 	writel(DMAMAC_SRST, &dma_p->busmode);
1145b1b1883SVipin KUMAR 	writel(MII_PORTSELECT, &mac_p->conf);
1155b1b1883SVipin KUMAR 
1165b1b1883SVipin KUMAR 	do {
1175b1b1883SVipin KUMAR 		if (!(readl(&dma_p->busmode) & DMAMAC_SRST))
1185b1b1883SVipin KUMAR 			return 0;
1195b1b1883SVipin KUMAR 		udelay(1000);
1205b1b1883SVipin KUMAR 	} while (timeout--);
1215b1b1883SVipin KUMAR 
1225b1b1883SVipin KUMAR 	return -1;
1235b1b1883SVipin KUMAR }
1245b1b1883SVipin KUMAR 
1255b1b1883SVipin KUMAR static int dw_write_hwaddr(struct eth_device *dev)
1265b1b1883SVipin KUMAR {
1275b1b1883SVipin KUMAR 	struct dw_eth_dev *priv = dev->priv;
1285b1b1883SVipin KUMAR 	struct eth_mac_regs *mac_p = priv->mac_regs_p;
1295b1b1883SVipin KUMAR 	u32 macid_lo, macid_hi;
1305b1b1883SVipin KUMAR 	u8 *mac_id = &dev->enetaddr[0];
1315b1b1883SVipin KUMAR 
1325b1b1883SVipin KUMAR 	macid_lo = mac_id[0] + (mac_id[1] << 8) + \
1335b1b1883SVipin KUMAR 		   (mac_id[2] << 16) + (mac_id[3] << 24);
1345b1b1883SVipin KUMAR 	macid_hi = mac_id[4] + (mac_id[5] << 8);
1355b1b1883SVipin KUMAR 
1365b1b1883SVipin KUMAR 	writel(macid_hi, &mac_p->macaddr0hi);
1375b1b1883SVipin KUMAR 	writel(macid_lo, &mac_p->macaddr0lo);
1385b1b1883SVipin KUMAR 
1395b1b1883SVipin KUMAR 	return 0;
1405b1b1883SVipin KUMAR }
1415b1b1883SVipin KUMAR 
1425b1b1883SVipin KUMAR static int dw_eth_init(struct eth_device *dev, bd_t *bis)
1435b1b1883SVipin KUMAR {
1445b1b1883SVipin KUMAR 	struct dw_eth_dev *priv = dev->priv;
1455b1b1883SVipin KUMAR 	struct eth_mac_regs *mac_p = priv->mac_regs_p;
1465b1b1883SVipin KUMAR 	struct eth_dma_regs *dma_p = priv->dma_regs_p;
1475b1b1883SVipin KUMAR 	u32 conf;
1485b1b1883SVipin KUMAR 
149*13edd170SVipin Kumar 	if (priv->phy_configured != 1)
150*13edd170SVipin Kumar 		configure_phy(dev);
151*13edd170SVipin Kumar 
1525b1b1883SVipin KUMAR 	/* Reset ethernet hardware */
1535b1b1883SVipin KUMAR 	if (mac_reset(dev) < 0)
1545b1b1883SVipin KUMAR 		return -1;
1555b1b1883SVipin KUMAR 
156c7f6dbe7SVipin KUMAR 	/* Resore the HW MAC address as it has been lost during MAC reset */
157c7f6dbe7SVipin KUMAR 	dw_write_hwaddr(dev);
158c7f6dbe7SVipin KUMAR 
1595b1b1883SVipin KUMAR 	writel(FIXEDBURST | PRIORXTX_41 | BURST_16,
1605b1b1883SVipin KUMAR 			&dma_p->busmode);
1615b1b1883SVipin KUMAR 
1625b1b1883SVipin KUMAR 	writel(FLUSHTXFIFO | readl(&dma_p->opmode), &dma_p->opmode);
1635b1b1883SVipin KUMAR 	writel(STOREFORWARD | TXSECONDFRAME, &dma_p->opmode);
1645b1b1883SVipin KUMAR 
1655b1b1883SVipin KUMAR 	conf = FRAMEBURSTENABLE | DISABLERXOWN;
1665b1b1883SVipin KUMAR 
1675b1b1883SVipin KUMAR 	if (priv->speed != SPEED_1000M)
1685b1b1883SVipin KUMAR 		conf |= MII_PORTSELECT;
1695b1b1883SVipin KUMAR 
1705b1b1883SVipin KUMAR 	if (priv->duplex == FULL_DUPLEX)
1715b1b1883SVipin KUMAR 		conf |= FULLDPLXMODE;
1725b1b1883SVipin KUMAR 
1735b1b1883SVipin KUMAR 	writel(conf, &mac_p->conf);
1745b1b1883SVipin KUMAR 
1755b1b1883SVipin KUMAR 	descs_init(dev);
1765b1b1883SVipin KUMAR 
1775b1b1883SVipin KUMAR 	/*
1785b1b1883SVipin KUMAR 	 * Start/Enable xfer at dma as well as mac level
1795b1b1883SVipin KUMAR 	 */
1805b1b1883SVipin KUMAR 	writel(readl(&dma_p->opmode) | RXSTART, &dma_p->opmode);
1815b1b1883SVipin KUMAR 	writel(readl(&dma_p->opmode) | TXSTART, &dma_p->opmode);
1825b1b1883SVipin KUMAR 
183aa51005cSArmando Visconti 	writel(readl(&mac_p->conf) | RXENABLE | TXENABLE, &mac_p->conf);
1845b1b1883SVipin KUMAR 
1855b1b1883SVipin KUMAR 	return 0;
1865b1b1883SVipin KUMAR }
1875b1b1883SVipin KUMAR 
1885b1b1883SVipin KUMAR static int dw_eth_send(struct eth_device *dev, volatile void *packet,
1895b1b1883SVipin KUMAR 		int length)
1905b1b1883SVipin KUMAR {
1915b1b1883SVipin KUMAR 	struct dw_eth_dev *priv = dev->priv;
1925b1b1883SVipin KUMAR 	struct eth_dma_regs *dma_p = priv->dma_regs_p;
1935b1b1883SVipin KUMAR 	u32 desc_num = priv->tx_currdescnum;
1945b1b1883SVipin KUMAR 	struct dmamacdescr *desc_p = &priv->tx_mac_descrtable[desc_num];
1955b1b1883SVipin KUMAR 
1965b1b1883SVipin KUMAR 	/* Check if the descriptor is owned by CPU */
1975b1b1883SVipin KUMAR 	if (desc_p->txrx_status & DESC_TXSTS_OWNBYDMA) {
1985b1b1883SVipin KUMAR 		printf("CPU not owner of tx frame\n");
1995b1b1883SVipin KUMAR 		return -1;
2005b1b1883SVipin KUMAR 	}
2015b1b1883SVipin KUMAR 
2025b1b1883SVipin KUMAR 	memcpy((void *)desc_p->dmamac_addr, (void *)packet, length);
2035b1b1883SVipin KUMAR 
2045b1b1883SVipin KUMAR #if defined(CONFIG_DW_ALTDESCRIPTOR)
2055b1b1883SVipin KUMAR 	desc_p->txrx_status |= DESC_TXSTS_TXFIRST | DESC_TXSTS_TXLAST;
2065b1b1883SVipin KUMAR 	desc_p->dmamac_cntl |= (length << DESC_TXCTRL_SIZE1SHFT) & \
2075b1b1883SVipin KUMAR 			       DESC_TXCTRL_SIZE1MASK;
2085b1b1883SVipin KUMAR 
2095b1b1883SVipin KUMAR 	desc_p->txrx_status &= ~(DESC_TXSTS_MSK);
2105b1b1883SVipin KUMAR 	desc_p->txrx_status |= DESC_TXSTS_OWNBYDMA;
2115b1b1883SVipin KUMAR #else
2125b1b1883SVipin KUMAR 	desc_p->dmamac_cntl |= ((length << DESC_TXCTRL_SIZE1SHFT) & \
2135b1b1883SVipin KUMAR 			       DESC_TXCTRL_SIZE1MASK) | DESC_TXCTRL_TXLAST | \
2145b1b1883SVipin KUMAR 			       DESC_TXCTRL_TXFIRST;
2155b1b1883SVipin KUMAR 
2165b1b1883SVipin KUMAR 	desc_p->txrx_status = DESC_TXSTS_OWNBYDMA;
2175b1b1883SVipin KUMAR #endif
2185b1b1883SVipin KUMAR 
2195b1b1883SVipin KUMAR 	/* Test the wrap-around condition. */
2205b1b1883SVipin KUMAR 	if (++desc_num >= CONFIG_TX_DESCR_NUM)
2215b1b1883SVipin KUMAR 		desc_num = 0;
2225b1b1883SVipin KUMAR 
2235b1b1883SVipin KUMAR 	priv->tx_currdescnum = desc_num;
2245b1b1883SVipin KUMAR 
2255b1b1883SVipin KUMAR 	/* Start the transmission */
2265b1b1883SVipin KUMAR 	writel(POLL_DATA, &dma_p->txpolldemand);
2275b1b1883SVipin KUMAR 
2285b1b1883SVipin KUMAR 	return 0;
2295b1b1883SVipin KUMAR }
2305b1b1883SVipin KUMAR 
2315b1b1883SVipin KUMAR static int dw_eth_recv(struct eth_device *dev)
2325b1b1883SVipin KUMAR {
2335b1b1883SVipin KUMAR 	struct dw_eth_dev *priv = dev->priv;
2345b1b1883SVipin KUMAR 	u32 desc_num = priv->rx_currdescnum;
2355b1b1883SVipin KUMAR 	struct dmamacdescr *desc_p = &priv->rx_mac_descrtable[desc_num];
2365b1b1883SVipin KUMAR 
2375b1b1883SVipin KUMAR 	u32 status = desc_p->txrx_status;
2385b1b1883SVipin KUMAR 	int length = 0;
2395b1b1883SVipin KUMAR 
2405b1b1883SVipin KUMAR 	/* Check  if the owner is the CPU */
2415b1b1883SVipin KUMAR 	if (!(status & DESC_RXSTS_OWNBYDMA)) {
2425b1b1883SVipin KUMAR 
2435b1b1883SVipin KUMAR 		length = (status & DESC_RXSTS_FRMLENMSK) >> \
2445b1b1883SVipin KUMAR 			 DESC_RXSTS_FRMLENSHFT;
2455b1b1883SVipin KUMAR 
2465b1b1883SVipin KUMAR 		NetReceive(desc_p->dmamac_addr, length);
2475b1b1883SVipin KUMAR 
2485b1b1883SVipin KUMAR 		/*
2495b1b1883SVipin KUMAR 		 * Make the current descriptor valid again and go to
2505b1b1883SVipin KUMAR 		 * the next one
2515b1b1883SVipin KUMAR 		 */
2525b1b1883SVipin KUMAR 		desc_p->txrx_status |= DESC_RXSTS_OWNBYDMA;
2535b1b1883SVipin KUMAR 
2545b1b1883SVipin KUMAR 		/* Test the wrap-around condition. */
2555b1b1883SVipin KUMAR 		if (++desc_num >= CONFIG_RX_DESCR_NUM)
2565b1b1883SVipin KUMAR 			desc_num = 0;
2575b1b1883SVipin KUMAR 	}
2585b1b1883SVipin KUMAR 
2595b1b1883SVipin KUMAR 	priv->rx_currdescnum = desc_num;
2605b1b1883SVipin KUMAR 
2615b1b1883SVipin KUMAR 	return length;
2625b1b1883SVipin KUMAR }
2635b1b1883SVipin KUMAR 
2645b1b1883SVipin KUMAR static void dw_eth_halt(struct eth_device *dev)
2655b1b1883SVipin KUMAR {
2665b1b1883SVipin KUMAR 	struct dw_eth_dev *priv = dev->priv;
2675b1b1883SVipin KUMAR 
2685b1b1883SVipin KUMAR 	mac_reset(dev);
2695b1b1883SVipin KUMAR 	priv->tx_currdescnum = priv->rx_currdescnum = 0;
2705b1b1883SVipin KUMAR }
2715b1b1883SVipin KUMAR 
2725b1b1883SVipin KUMAR static int eth_mdio_read(struct eth_device *dev, u8 addr, u8 reg, u16 *val)
2735b1b1883SVipin KUMAR {
2745b1b1883SVipin KUMAR 	struct dw_eth_dev *priv = dev->priv;
2755b1b1883SVipin KUMAR 	struct eth_mac_regs *mac_p = priv->mac_regs_p;
2765b1b1883SVipin KUMAR 	u32 miiaddr;
2775b1b1883SVipin KUMAR 	int timeout = CONFIG_MDIO_TIMEOUT;
2785b1b1883SVipin KUMAR 
2795b1b1883SVipin KUMAR 	miiaddr = ((addr << MIIADDRSHIFT) & MII_ADDRMSK) | \
2805b1b1883SVipin KUMAR 		  ((reg << MIIREGSHIFT) & MII_REGMSK);
2815b1b1883SVipin KUMAR 
2825b1b1883SVipin KUMAR 	writel(miiaddr | MII_CLKRANGE_150_250M | MII_BUSY, &mac_p->miiaddr);
2835b1b1883SVipin KUMAR 
2845b1b1883SVipin KUMAR 	do {
2855b1b1883SVipin KUMAR 		if (!(readl(&mac_p->miiaddr) & MII_BUSY)) {
2865b1b1883SVipin KUMAR 			*val = readl(&mac_p->miidata);
2875b1b1883SVipin KUMAR 			return 0;
2885b1b1883SVipin KUMAR 		}
2895b1b1883SVipin KUMAR 		udelay(1000);
2905b1b1883SVipin KUMAR 	} while (timeout--);
2915b1b1883SVipin KUMAR 
2925b1b1883SVipin KUMAR 	return -1;
2935b1b1883SVipin KUMAR }
2945b1b1883SVipin KUMAR 
2955b1b1883SVipin KUMAR static int eth_mdio_write(struct eth_device *dev, u8 addr, u8 reg, u16 val)
2965b1b1883SVipin KUMAR {
2975b1b1883SVipin KUMAR 	struct dw_eth_dev *priv = dev->priv;
2985b1b1883SVipin KUMAR 	struct eth_mac_regs *mac_p = priv->mac_regs_p;
2995b1b1883SVipin KUMAR 	u32 miiaddr;
3005b1b1883SVipin KUMAR 	int ret = -1, timeout = CONFIG_MDIO_TIMEOUT;
3015b1b1883SVipin KUMAR 	u16 value;
3025b1b1883SVipin KUMAR 
3035b1b1883SVipin KUMAR 	writel(val, &mac_p->miidata);
3045b1b1883SVipin KUMAR 	miiaddr = ((addr << MIIADDRSHIFT) & MII_ADDRMSK) | \
3055b1b1883SVipin KUMAR 		  ((reg << MIIREGSHIFT) & MII_REGMSK) | MII_WRITE;
3065b1b1883SVipin KUMAR 
3075b1b1883SVipin KUMAR 	writel(miiaddr | MII_CLKRANGE_150_250M | MII_BUSY, &mac_p->miiaddr);
3085b1b1883SVipin KUMAR 
3095b1b1883SVipin KUMAR 	do {
310c7f6dbe7SVipin KUMAR 		if (!(readl(&mac_p->miiaddr) & MII_BUSY)) {
3115b1b1883SVipin KUMAR 			ret = 0;
312c7f6dbe7SVipin KUMAR 			break;
313c7f6dbe7SVipin KUMAR 		}
3145b1b1883SVipin KUMAR 		udelay(1000);
3155b1b1883SVipin KUMAR 	} while (timeout--);
3165b1b1883SVipin KUMAR 
3175b1b1883SVipin KUMAR 	/* Needed as a fix for ST-Phy */
3185b1b1883SVipin KUMAR 	eth_mdio_read(dev, addr, reg, &value);
3195b1b1883SVipin KUMAR 
3205b1b1883SVipin KUMAR 	return ret;
3215b1b1883SVipin KUMAR }
3225b1b1883SVipin KUMAR 
3235b1b1883SVipin KUMAR #if defined(CONFIG_DW_SEARCH_PHY)
3245b1b1883SVipin KUMAR static int find_phy(struct eth_device *dev)
3255b1b1883SVipin KUMAR {
3265b1b1883SVipin KUMAR 	int phy_addr = 0;
3275b1b1883SVipin KUMAR 	u16 ctrl, oldctrl;
3285b1b1883SVipin KUMAR 
3295b1b1883SVipin KUMAR 	do {
3308ef583a0SMike Frysinger 		eth_mdio_read(dev, phy_addr, MII_BMCR, &ctrl);
3318ef583a0SMike Frysinger 		oldctrl = ctrl & BMCR_ANENABLE;
3325b1b1883SVipin KUMAR 
3338ef583a0SMike Frysinger 		ctrl ^= BMCR_ANENABLE;
3348ef583a0SMike Frysinger 		eth_mdio_write(dev, phy_addr, MII_BMCR, ctrl);
3358ef583a0SMike Frysinger 		eth_mdio_read(dev, phy_addr, MII_BMCR, &ctrl);
3368ef583a0SMike Frysinger 		ctrl &= BMCR_ANENABLE;
3375b1b1883SVipin KUMAR 
3385b1b1883SVipin KUMAR 		if (ctrl == oldctrl) {
3395b1b1883SVipin KUMAR 			phy_addr++;
3405b1b1883SVipin KUMAR 		} else {
3418ef583a0SMike Frysinger 			ctrl ^= BMCR_ANENABLE;
3428ef583a0SMike Frysinger 			eth_mdio_write(dev, phy_addr, MII_BMCR, ctrl);
3435b1b1883SVipin KUMAR 
3445b1b1883SVipin KUMAR 			return phy_addr;
3455b1b1883SVipin KUMAR 		}
3465b1b1883SVipin KUMAR 	} while (phy_addr < 32);
3475b1b1883SVipin KUMAR 
3485b1b1883SVipin KUMAR 	return -1;
3495b1b1883SVipin KUMAR }
3505b1b1883SVipin KUMAR #endif
3515b1b1883SVipin KUMAR 
3525b1b1883SVipin KUMAR static int dw_reset_phy(struct eth_device *dev)
3535b1b1883SVipin KUMAR {
3545b1b1883SVipin KUMAR 	struct dw_eth_dev *priv = dev->priv;
3555b1b1883SVipin KUMAR 	u16 ctrl;
3565b1b1883SVipin KUMAR 	int timeout = CONFIG_PHYRESET_TIMEOUT;
3575b1b1883SVipin KUMAR 	u32 phy_addr = priv->address;
3585b1b1883SVipin KUMAR 
3598ef583a0SMike Frysinger 	eth_mdio_write(dev, phy_addr, MII_BMCR, BMCR_RESET);
3605b1b1883SVipin KUMAR 	do {
3618ef583a0SMike Frysinger 		eth_mdio_read(dev, phy_addr, MII_BMCR, &ctrl);
3628ef583a0SMike Frysinger 		if (!(ctrl & BMCR_RESET))
3635b1b1883SVipin KUMAR 			break;
3645b1b1883SVipin KUMAR 		udelay(1000);
3655b1b1883SVipin KUMAR 	} while (timeout--);
3665b1b1883SVipin KUMAR 
3675b1b1883SVipin KUMAR 	if (timeout < 0)
3685b1b1883SVipin KUMAR 		return -1;
3695b1b1883SVipin KUMAR 
3705b1b1883SVipin KUMAR #ifdef CONFIG_PHY_RESET_DELAY
3715b1b1883SVipin KUMAR 	udelay(CONFIG_PHY_RESET_DELAY);
3725b1b1883SVipin KUMAR #endif
3735b1b1883SVipin KUMAR 	return 0;
3745b1b1883SVipin KUMAR }
3755b1b1883SVipin KUMAR 
3765b1b1883SVipin KUMAR static int configure_phy(struct eth_device *dev)
3775b1b1883SVipin KUMAR {
3785b1b1883SVipin KUMAR 	struct dw_eth_dev *priv = dev->priv;
3795b1b1883SVipin KUMAR 	int phy_addr;
380ee7f5bfdSMike Frysinger 	u16 bmcr;
3815b1b1883SVipin KUMAR #if defined(CONFIG_DW_AUTONEG)
3825b1b1883SVipin KUMAR 	u16 bmsr;
3835b1b1883SVipin KUMAR 	u32 timeout;
3845b1b1883SVipin KUMAR 	u16 anlpar, btsr;
385ee7f5bfdSMike Frysinger #else
386ee7f5bfdSMike Frysinger 	u16 ctrl;
3875b1b1883SVipin KUMAR #endif
3885b1b1883SVipin KUMAR 
3895b1b1883SVipin KUMAR #if defined(CONFIG_DW_SEARCH_PHY)
3905b1b1883SVipin KUMAR 	phy_addr = find_phy(dev);
391024333c9SVipin KUMAR 	if (phy_addr >= 0)
3925b1b1883SVipin KUMAR 		priv->address = phy_addr;
3935b1b1883SVipin KUMAR 	else
3945b1b1883SVipin KUMAR 		return -1;
395f0ece9e9SMike Frysinger #else
396f0ece9e9SMike Frysinger 	phy_addr = priv->address;
3975b1b1883SVipin KUMAR #endif
3985b1b1883SVipin KUMAR 	if (dw_reset_phy(dev) < 0)
3995b1b1883SVipin KUMAR 		return -1;
4005b1b1883SVipin KUMAR 
4015b1b1883SVipin KUMAR #if defined(CONFIG_DW_AUTONEG)
4028ef583a0SMike Frysinger 	bmcr = BMCR_ANENABLE | BMCR_ANRESTART | BMCR_SPEED100 | \
4038ef583a0SMike Frysinger 	       BMCR_FULLDPLX | BMCR_SPEED1000;
4045b1b1883SVipin KUMAR #else
4058ef583a0SMike Frysinger 	bmcr = BMCR_SPEED100 | BMCR_FULLDPLX;
4065b1b1883SVipin KUMAR 
4075b1b1883SVipin KUMAR #if defined(CONFIG_DW_SPEED10M)
4088ef583a0SMike Frysinger 	bmcr &= ~BMCR_SPEED100;
4095b1b1883SVipin KUMAR #endif
4105b1b1883SVipin KUMAR #if defined(CONFIG_DW_DUPLEXHALF)
4118ef583a0SMike Frysinger 	bmcr &= ~BMCR_FULLDPLX;
4125b1b1883SVipin KUMAR #endif
4135b1b1883SVipin KUMAR #endif
4148ef583a0SMike Frysinger 	if (eth_mdio_write(dev, phy_addr, MII_BMCR, bmcr) < 0)
4155b1b1883SVipin KUMAR 		return -1;
4165b1b1883SVipin KUMAR 
4175b1b1883SVipin KUMAR 	/* Read the phy status register and populate priv structure */
4185b1b1883SVipin KUMAR #if defined(CONFIG_DW_AUTONEG)
4195b1b1883SVipin KUMAR 	timeout = CONFIG_AUTONEG_TIMEOUT;
4205b1b1883SVipin KUMAR 	do {
4218ef583a0SMike Frysinger 		eth_mdio_read(dev, phy_addr, MII_BMSR, &bmsr);
4228ef583a0SMike Frysinger 		if (bmsr & BMSR_ANEGCOMPLETE)
4235b1b1883SVipin KUMAR 			break;
4245b1b1883SVipin KUMAR 		udelay(1000);
4255b1b1883SVipin KUMAR 	} while (timeout--);
4265b1b1883SVipin KUMAR 
4278ef583a0SMike Frysinger 	eth_mdio_read(dev, phy_addr, MII_LPA, &anlpar);
4288ef583a0SMike Frysinger 	eth_mdio_read(dev, phy_addr, MII_STAT1000, &btsr);
4295b1b1883SVipin KUMAR 
430*13edd170SVipin Kumar 	if (bmsr & BMSR_ANEGCOMPLETE) {
4315b1b1883SVipin KUMAR 		if (btsr & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD)) {
4325b1b1883SVipin KUMAR 			priv->speed = SPEED_1000M;
4335b1b1883SVipin KUMAR 			if (btsr & PHY_1000BTSR_1000FD)
4345b1b1883SVipin KUMAR 				priv->duplex = FULL_DUPLEX;
4355b1b1883SVipin KUMAR 			else
4365b1b1883SVipin KUMAR 				priv->duplex = HALF_DUPLEX;
4375b1b1883SVipin KUMAR 		} else {
4388ef583a0SMike Frysinger 			if (anlpar & LPA_100)
4395b1b1883SVipin KUMAR 				priv->speed = SPEED_100M;
4405b1b1883SVipin KUMAR 			else
4415b1b1883SVipin KUMAR 				priv->speed = SPEED_10M;
4425b1b1883SVipin KUMAR 
4438ef583a0SMike Frysinger 			if (anlpar & (LPA_10FULL | LPA_100FULL))
4445b1b1883SVipin KUMAR 				priv->duplex = FULL_DUPLEX;
4455b1b1883SVipin KUMAR 			else
4465b1b1883SVipin KUMAR 				priv->duplex = HALF_DUPLEX;
4475b1b1883SVipin KUMAR 		}
448*13edd170SVipin Kumar 	} else
449*13edd170SVipin Kumar 		return -1;
4505b1b1883SVipin KUMAR #else
4518ef583a0SMike Frysinger 	if (eth_mdio_read(dev, phy_addr, MII_BMCR, &ctrl) < 0)
4525b1b1883SVipin KUMAR 		return -1;
4535b1b1883SVipin KUMAR 
4548ef583a0SMike Frysinger 	if (ctrl & BMCR_FULLDPLX)
4555b1b1883SVipin KUMAR 		priv->duplex = FULL_DUPLEX;
4565b1b1883SVipin KUMAR 	else
4575b1b1883SVipin KUMAR 		priv->duplex = HALF_DUPLEX;
4585b1b1883SVipin KUMAR 
4598ef583a0SMike Frysinger 	if (ctrl & BMCR_SPEED1000)
4605b1b1883SVipin KUMAR 		priv->speed = SPEED_1000M;
4618ef583a0SMike Frysinger 	else if (ctrl & BMCR_SPEED100)
4625b1b1883SVipin KUMAR 		priv->speed = SPEED_100M;
4635b1b1883SVipin KUMAR 	else
4645b1b1883SVipin KUMAR 		priv->speed = SPEED_10M;
4655b1b1883SVipin KUMAR #endif
466*13edd170SVipin Kumar 	priv->phy_configured = 1;
467*13edd170SVipin Kumar 
4685b1b1883SVipin KUMAR 	return 0;
4695b1b1883SVipin KUMAR }
4705b1b1883SVipin KUMAR 
4715b1b1883SVipin KUMAR #if defined(CONFIG_MII)
4725700bb63SMike Frysinger static int dw_mii_read(const char *devname, u8 addr, u8 reg, u16 *val)
4735b1b1883SVipin KUMAR {
4745b1b1883SVipin KUMAR 	struct eth_device *dev;
4755b1b1883SVipin KUMAR 
4765b1b1883SVipin KUMAR 	dev = eth_get_dev_by_name(devname);
4775b1b1883SVipin KUMAR 	if (dev)
4785b1b1883SVipin KUMAR 		eth_mdio_read(dev, addr, reg, val);
4795b1b1883SVipin KUMAR 
4805b1b1883SVipin KUMAR 	return 0;
4815b1b1883SVipin KUMAR }
4825b1b1883SVipin KUMAR 
4835700bb63SMike Frysinger static int dw_mii_write(const char *devname, u8 addr, u8 reg, u16 val)
4845b1b1883SVipin KUMAR {
4855b1b1883SVipin KUMAR 	struct eth_device *dev;
4865b1b1883SVipin KUMAR 
4875b1b1883SVipin KUMAR 	dev = eth_get_dev_by_name(devname);
4885b1b1883SVipin KUMAR 	if (dev)
4895b1b1883SVipin KUMAR 		eth_mdio_write(dev, addr, reg, val);
4905b1b1883SVipin KUMAR 
4915b1b1883SVipin KUMAR 	return 0;
4925b1b1883SVipin KUMAR }
4935b1b1883SVipin KUMAR #endif
4945b1b1883SVipin KUMAR 
4955b1b1883SVipin KUMAR int designware_initialize(u32 id, ulong base_addr, u32 phy_addr)
4965b1b1883SVipin KUMAR {
4975b1b1883SVipin KUMAR 	struct eth_device *dev;
4985b1b1883SVipin KUMAR 	struct dw_eth_dev *priv;
4995b1b1883SVipin KUMAR 
5005b1b1883SVipin KUMAR 	dev = (struct eth_device *) malloc(sizeof(struct eth_device));
5015b1b1883SVipin KUMAR 	if (!dev)
5025b1b1883SVipin KUMAR 		return -ENOMEM;
5035b1b1883SVipin KUMAR 
5045b1b1883SVipin KUMAR 	/*
5055b1b1883SVipin KUMAR 	 * Since the priv structure contains the descriptors which need a strict
5065b1b1883SVipin KUMAR 	 * buswidth alignment, memalign is used to allocate memory
5075b1b1883SVipin KUMAR 	 */
5085b1b1883SVipin KUMAR 	priv = (struct dw_eth_dev *) memalign(16, sizeof(struct dw_eth_dev));
5095b1b1883SVipin KUMAR 	if (!priv) {
5105b1b1883SVipin KUMAR 		free(dev);
5115b1b1883SVipin KUMAR 		return -ENOMEM;
5125b1b1883SVipin KUMAR 	}
5135b1b1883SVipin KUMAR 
5145b1b1883SVipin KUMAR 	memset(dev, 0, sizeof(struct eth_device));
5155b1b1883SVipin KUMAR 	memset(priv, 0, sizeof(struct dw_eth_dev));
5165b1b1883SVipin KUMAR 
5175b1b1883SVipin KUMAR 	sprintf(dev->name, "mii%d", id);
5185b1b1883SVipin KUMAR 	dev->iobase = (int)base_addr;
5195b1b1883SVipin KUMAR 	dev->priv = priv;
5205b1b1883SVipin KUMAR 
5217616e785SSimon Glass 	eth_getenv_enetaddr_by_index("eth", id, &dev->enetaddr[0]);
5225b1b1883SVipin KUMAR 
5235b1b1883SVipin KUMAR 	priv->dev = dev;
5245b1b1883SVipin KUMAR 	priv->mac_regs_p = (struct eth_mac_regs *)base_addr;
5255b1b1883SVipin KUMAR 	priv->dma_regs_p = (struct eth_dma_regs *)(base_addr +
5265b1b1883SVipin KUMAR 			DW_DMA_BASE_OFFSET);
5275b1b1883SVipin KUMAR 	priv->address = phy_addr;
528*13edd170SVipin Kumar 	priv->phy_configured = 0;
5295b1b1883SVipin KUMAR 
5305b1b1883SVipin KUMAR 	if (mac_reset(dev) < 0)
5315b1b1883SVipin KUMAR 		return -1;
5325b1b1883SVipin KUMAR 
533*13edd170SVipin Kumar 	configure_phy(dev);
5345b1b1883SVipin KUMAR 
5355b1b1883SVipin KUMAR 	dev->init = dw_eth_init;
5365b1b1883SVipin KUMAR 	dev->send = dw_eth_send;
5375b1b1883SVipin KUMAR 	dev->recv = dw_eth_recv;
5385b1b1883SVipin KUMAR 	dev->halt = dw_eth_halt;
5395b1b1883SVipin KUMAR 	dev->write_hwaddr = dw_write_hwaddr;
5405b1b1883SVipin KUMAR 
5415b1b1883SVipin KUMAR 	eth_register(dev);
5425b1b1883SVipin KUMAR 
5435b1b1883SVipin KUMAR #if defined(CONFIG_MII)
5445b1b1883SVipin KUMAR 	miiphy_register(dev->name, dw_mii_read, dw_mii_write);
5455b1b1883SVipin KUMAR #endif
5465b1b1883SVipin KUMAR 	return 1;
5475b1b1883SVipin KUMAR }
548