xref: /OK3568_Linux_fs/u-boot/drivers/net/ftgmac100.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Faraday FTGMAC100 Ethernet
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * (C) Copyright 2009 Faraday Technology
5*4882a593Smuzhiyun  * Po-Yu Chuang <ratbert@faraday-tech.com>
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * (C) Copyright 2010 Andes Technology
8*4882a593Smuzhiyun  * Macpaul Lin <macpaul@andestech.com>
9*4882a593Smuzhiyun  *
10*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
11*4882a593Smuzhiyun  */
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #include <config.h>
14*4882a593Smuzhiyun #include <common.h>
15*4882a593Smuzhiyun #include <malloc.h>
16*4882a593Smuzhiyun #include <net.h>
17*4882a593Smuzhiyun #include <asm/io.h>
18*4882a593Smuzhiyun #include <asm/dma-mapping.h>
19*4882a593Smuzhiyun #include <linux/mii.h>
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun #include "ftgmac100.h"
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun #define ETH_ZLEN	60
24*4882a593Smuzhiyun #define CFG_XBUF_SIZE	1536
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun /* RBSR - hw default init value is also 0x640 */
27*4882a593Smuzhiyun #define RBSR_DEFAULT_VALUE	0x640
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun /* PKTBUFSTX/PKTBUFSRX must both be power of 2 */
30*4882a593Smuzhiyun #define PKTBUFSTX	4	/* must be power of 2 */
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun struct ftgmac100_data {
33*4882a593Smuzhiyun 	ulong txdes_dma;
34*4882a593Smuzhiyun 	struct ftgmac100_txdes *txdes;
35*4882a593Smuzhiyun 	ulong rxdes_dma;
36*4882a593Smuzhiyun 	struct ftgmac100_rxdes *rxdes;
37*4882a593Smuzhiyun 	int tx_index;
38*4882a593Smuzhiyun 	int rx_index;
39*4882a593Smuzhiyun 	int phy_addr;
40*4882a593Smuzhiyun };
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun /*
43*4882a593Smuzhiyun  * struct mii_bus functions
44*4882a593Smuzhiyun  */
ftgmac100_mdiobus_read(struct eth_device * dev,int phy_addr,int regnum)45*4882a593Smuzhiyun static int ftgmac100_mdiobus_read(struct eth_device *dev, int phy_addr,
46*4882a593Smuzhiyun 	int regnum)
47*4882a593Smuzhiyun {
48*4882a593Smuzhiyun 	struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
49*4882a593Smuzhiyun 	int phycr;
50*4882a593Smuzhiyun 	int i;
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 	phycr = readl(&ftgmac100->phycr);
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 	/* preserve MDC cycle threshold */
55*4882a593Smuzhiyun 	phycr &= FTGMAC100_PHYCR_MDC_CYCTHR_MASK;
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun 	phycr |= FTGMAC100_PHYCR_PHYAD(phy_addr)
58*4882a593Smuzhiyun 	      |  FTGMAC100_PHYCR_REGAD(regnum)
59*4882a593Smuzhiyun 	      |  FTGMAC100_PHYCR_MIIRD;
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun 	writel(phycr, &ftgmac100->phycr);
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 	for (i = 0; i < 10; i++) {
64*4882a593Smuzhiyun 		phycr = readl(&ftgmac100->phycr);
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 		if ((phycr & FTGMAC100_PHYCR_MIIRD) == 0) {
67*4882a593Smuzhiyun 			int data;
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 			data = readl(&ftgmac100->phydata);
70*4882a593Smuzhiyun 			return FTGMAC100_PHYDATA_MIIRDATA(data);
71*4882a593Smuzhiyun 		}
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 		mdelay(10);
74*4882a593Smuzhiyun 	}
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	debug("mdio read timed out\n");
77*4882a593Smuzhiyun 	return -1;
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun 
ftgmac100_mdiobus_write(struct eth_device * dev,int phy_addr,int regnum,u16 value)80*4882a593Smuzhiyun static int ftgmac100_mdiobus_write(struct eth_device *dev, int phy_addr,
81*4882a593Smuzhiyun 	int regnum, u16 value)
82*4882a593Smuzhiyun {
83*4882a593Smuzhiyun 	struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
84*4882a593Smuzhiyun 	int phycr;
85*4882a593Smuzhiyun 	int data;
86*4882a593Smuzhiyun 	int i;
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 	phycr = readl(&ftgmac100->phycr);
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	/* preserve MDC cycle threshold */
91*4882a593Smuzhiyun 	phycr &= FTGMAC100_PHYCR_MDC_CYCTHR_MASK;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	phycr |= FTGMAC100_PHYCR_PHYAD(phy_addr)
94*4882a593Smuzhiyun 	      |  FTGMAC100_PHYCR_REGAD(regnum)
95*4882a593Smuzhiyun 	      |  FTGMAC100_PHYCR_MIIWR;
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	data = FTGMAC100_PHYDATA_MIIWDATA(value);
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	writel(data, &ftgmac100->phydata);
100*4882a593Smuzhiyun 	writel(phycr, &ftgmac100->phycr);
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	for (i = 0; i < 10; i++) {
103*4882a593Smuzhiyun 		phycr = readl(&ftgmac100->phycr);
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 		if ((phycr & FTGMAC100_PHYCR_MIIWR) == 0) {
106*4882a593Smuzhiyun 			debug("(phycr & FTGMAC100_PHYCR_MIIWR) == 0: " \
107*4882a593Smuzhiyun 				"phy_addr: %x\n", phy_addr);
108*4882a593Smuzhiyun 			return 0;
109*4882a593Smuzhiyun 		}
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 		mdelay(1);
112*4882a593Smuzhiyun 	}
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	debug("mdio write timed out\n");
115*4882a593Smuzhiyun 	return -1;
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun 
ftgmac100_phy_read(struct eth_device * dev,int addr,int reg,u16 * value)118*4882a593Smuzhiyun int ftgmac100_phy_read(struct eth_device *dev, int addr, int reg, u16 *value)
119*4882a593Smuzhiyun {
120*4882a593Smuzhiyun 	*value = ftgmac100_mdiobus_read(dev , addr, reg);
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	if (*value == -1)
123*4882a593Smuzhiyun 		return -1;
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	return 0;
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun 
ftgmac100_phy_write(struct eth_device * dev,int addr,int reg,u16 value)128*4882a593Smuzhiyun int  ftgmac100_phy_write(struct eth_device *dev, int addr, int reg, u16 value)
129*4882a593Smuzhiyun {
130*4882a593Smuzhiyun 	if (ftgmac100_mdiobus_write(dev, addr, reg, value) == -1)
131*4882a593Smuzhiyun 		return -1;
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	return 0;
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun 
ftgmac100_phy_reset(struct eth_device * dev)136*4882a593Smuzhiyun static int ftgmac100_phy_reset(struct eth_device *dev)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun 	struct ftgmac100_data *priv = dev->priv;
139*4882a593Smuzhiyun 	int i;
140*4882a593Smuzhiyun 	u16 status, adv;
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	adv = ADVERTISE_CSMA | ADVERTISE_ALL;
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	ftgmac100_phy_write(dev, priv->phy_addr, MII_ADVERTISE, adv);
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 	printf("%s: Starting autonegotiation...\n", dev->name);
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	ftgmac100_phy_write(dev, priv->phy_addr,
149*4882a593Smuzhiyun 		MII_BMCR, (BMCR_ANENABLE | BMCR_ANRESTART));
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	for (i = 0; i < 100000 / 100; i++) {
152*4882a593Smuzhiyun 		ftgmac100_phy_read(dev, priv->phy_addr, MII_BMSR, &status);
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 		if (status & BMSR_ANEGCOMPLETE)
155*4882a593Smuzhiyun 			break;
156*4882a593Smuzhiyun 		mdelay(1);
157*4882a593Smuzhiyun 	}
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	if (status & BMSR_ANEGCOMPLETE) {
160*4882a593Smuzhiyun 		printf("%s: Autonegotiation complete\n", dev->name);
161*4882a593Smuzhiyun 	} else {
162*4882a593Smuzhiyun 		printf("%s: Autonegotiation timed out (status=0x%04x)\n",
163*4882a593Smuzhiyun 		       dev->name, status);
164*4882a593Smuzhiyun 		return 0;
165*4882a593Smuzhiyun 	}
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	return 1;
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun 
ftgmac100_phy_init(struct eth_device * dev)170*4882a593Smuzhiyun static int ftgmac100_phy_init(struct eth_device *dev)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun 	struct ftgmac100_data *priv = dev->priv;
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	int phy_addr;
175*4882a593Smuzhiyun 	u16 phy_id, status, adv, lpa, stat_ge;
176*4882a593Smuzhiyun 	int media, speed, duplex;
177*4882a593Smuzhiyun 	int i;
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun 	/* Check if the PHY is up to snuff... */
180*4882a593Smuzhiyun 	for (phy_addr = 0; phy_addr < CONFIG_PHY_MAX_ADDR; phy_addr++) {
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 		ftgmac100_phy_read(dev, phy_addr, MII_PHYSID1, &phy_id);
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 		/*
185*4882a593Smuzhiyun 		 * When it is unable to found PHY,
186*4882a593Smuzhiyun 		 * the interface usually return 0xffff or 0x0000
187*4882a593Smuzhiyun 		 */
188*4882a593Smuzhiyun 		if (phy_id != 0xffff && phy_id != 0x0) {
189*4882a593Smuzhiyun 			printf("%s: found PHY at 0x%02x\n",
190*4882a593Smuzhiyun 				dev->name, phy_addr);
191*4882a593Smuzhiyun 			priv->phy_addr = phy_addr;
192*4882a593Smuzhiyun 			break;
193*4882a593Smuzhiyun 		}
194*4882a593Smuzhiyun 	}
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	if (phy_id == 0xffff || phy_id == 0x0) {
197*4882a593Smuzhiyun 		printf("%s: no PHY present\n", dev->name);
198*4882a593Smuzhiyun 		return 0;
199*4882a593Smuzhiyun 	}
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	ftgmac100_phy_read(dev, priv->phy_addr, MII_BMSR, &status);
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	if (!(status & BMSR_LSTATUS)) {
204*4882a593Smuzhiyun 		/* Try to re-negotiate if we don't have link already. */
205*4882a593Smuzhiyun 		ftgmac100_phy_reset(dev);
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 		for (i = 0; i < 100000 / 100; i++) {
208*4882a593Smuzhiyun 			ftgmac100_phy_read(dev, priv->phy_addr,
209*4882a593Smuzhiyun 				MII_BMSR, &status);
210*4882a593Smuzhiyun 			if (status & BMSR_LSTATUS)
211*4882a593Smuzhiyun 				break;
212*4882a593Smuzhiyun 			udelay(100);
213*4882a593Smuzhiyun 		}
214*4882a593Smuzhiyun 	}
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	if (!(status & BMSR_LSTATUS)) {
217*4882a593Smuzhiyun 		printf("%s: link down\n", dev->name);
218*4882a593Smuzhiyun 		return 0;
219*4882a593Smuzhiyun 	}
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun #ifdef CONFIG_FTGMAC100_EGIGA
222*4882a593Smuzhiyun 	/* 1000 Base-T Status Register */
223*4882a593Smuzhiyun 	ftgmac100_phy_read(dev, priv->phy_addr,
224*4882a593Smuzhiyun 		MII_STAT1000, &stat_ge);
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	speed = (stat_ge & (LPA_1000FULL | LPA_1000HALF)
227*4882a593Smuzhiyun 		 ? 1 : 0);
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	duplex = ((stat_ge & LPA_1000FULL)
230*4882a593Smuzhiyun 		 ? 1 : 0);
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	if (speed) { /* Speed is 1000 */
233*4882a593Smuzhiyun 		printf("%s: link up, 1000bps %s-duplex\n",
234*4882a593Smuzhiyun 			dev->name, duplex ? "full" : "half");
235*4882a593Smuzhiyun 		return 0;
236*4882a593Smuzhiyun 	}
237*4882a593Smuzhiyun #endif
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	ftgmac100_phy_read(dev, priv->phy_addr, MII_ADVERTISE, &adv);
240*4882a593Smuzhiyun 	ftgmac100_phy_read(dev, priv->phy_addr, MII_LPA, &lpa);
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	media = mii_nway_result(lpa & adv);
243*4882a593Smuzhiyun 	speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF) ? 1 : 0);
244*4882a593Smuzhiyun 	duplex = (media & ADVERTISE_FULL) ? 1 : 0;
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	printf("%s: link up, %sMbps %s-duplex\n",
247*4882a593Smuzhiyun 	       dev->name, speed ? "100" : "10", duplex ? "full" : "half");
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	return 1;
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun 
ftgmac100_update_link_speed(struct eth_device * dev)252*4882a593Smuzhiyun static int ftgmac100_update_link_speed(struct eth_device *dev)
253*4882a593Smuzhiyun {
254*4882a593Smuzhiyun 	struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
255*4882a593Smuzhiyun 	struct ftgmac100_data *priv = dev->priv;
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	unsigned short stat_fe;
258*4882a593Smuzhiyun 	unsigned short stat_ge;
259*4882a593Smuzhiyun 	unsigned int maccr;
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun #ifdef CONFIG_FTGMAC100_EGIGA
262*4882a593Smuzhiyun 	/* 1000 Base-T Status Register */
263*4882a593Smuzhiyun 	ftgmac100_phy_read(dev, priv->phy_addr, MII_STAT1000, &stat_ge);
264*4882a593Smuzhiyun #endif
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 	ftgmac100_phy_read(dev, priv->phy_addr, MII_BMSR, &stat_fe);
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 	if (!(stat_fe & BMSR_LSTATUS))	/* link status up? */
269*4882a593Smuzhiyun 		return 0;
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	/* read MAC control register and clear related bits */
272*4882a593Smuzhiyun 	maccr = readl(&ftgmac100->maccr) &
273*4882a593Smuzhiyun 		~(FTGMAC100_MACCR_GIGA_MODE |
274*4882a593Smuzhiyun 		  FTGMAC100_MACCR_FAST_MODE |
275*4882a593Smuzhiyun 		  FTGMAC100_MACCR_FULLDUP);
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun #ifdef CONFIG_FTGMAC100_EGIGA
278*4882a593Smuzhiyun 	if (stat_ge & LPA_1000FULL) {
279*4882a593Smuzhiyun 		/* set gmac for 1000BaseTX and Full Duplex */
280*4882a593Smuzhiyun 		maccr |= FTGMAC100_MACCR_GIGA_MODE | FTGMAC100_MACCR_FULLDUP;
281*4882a593Smuzhiyun 	}
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	if (stat_ge & LPA_1000HALF) {
284*4882a593Smuzhiyun 		/* set gmac for 1000BaseTX and Half Duplex */
285*4882a593Smuzhiyun 		maccr |= FTGMAC100_MACCR_GIGA_MODE;
286*4882a593Smuzhiyun 	}
287*4882a593Smuzhiyun #endif
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 	if (stat_fe & BMSR_100FULL) {
290*4882a593Smuzhiyun 		/* set MII for 100BaseTX and Full Duplex */
291*4882a593Smuzhiyun 		maccr |= FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_FULLDUP;
292*4882a593Smuzhiyun 	}
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	if (stat_fe & BMSR_10FULL) {
295*4882a593Smuzhiyun 		/* set MII for 10BaseT and Full Duplex */
296*4882a593Smuzhiyun 		maccr |= FTGMAC100_MACCR_FULLDUP;
297*4882a593Smuzhiyun 	}
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 	if (stat_fe & BMSR_100HALF) {
300*4882a593Smuzhiyun 		/* set MII for 100BaseTX and Half Duplex */
301*4882a593Smuzhiyun 		maccr |= FTGMAC100_MACCR_FAST_MODE;
302*4882a593Smuzhiyun 	}
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	if (stat_fe & BMSR_10HALF) {
305*4882a593Smuzhiyun 		/* set MII for 10BaseT and Half Duplex */
306*4882a593Smuzhiyun 		/* we have already clear these bits, do nothing */
307*4882a593Smuzhiyun 		;
308*4882a593Smuzhiyun 	}
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 	/* update MII config into maccr */
311*4882a593Smuzhiyun 	writel(maccr, &ftgmac100->maccr);
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 	return 1;
314*4882a593Smuzhiyun }
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun /*
317*4882a593Smuzhiyun  * Reset MAC
318*4882a593Smuzhiyun  */
ftgmac100_reset(struct eth_device * dev)319*4882a593Smuzhiyun static void ftgmac100_reset(struct eth_device *dev)
320*4882a593Smuzhiyun {
321*4882a593Smuzhiyun 	struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 	debug("%s()\n", __func__);
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun 	writel(FTGMAC100_MACCR_SW_RST, &ftgmac100->maccr);
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	while (readl(&ftgmac100->maccr) & FTGMAC100_MACCR_SW_RST)
328*4882a593Smuzhiyun 		;
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun /*
332*4882a593Smuzhiyun  * Set MAC address
333*4882a593Smuzhiyun  */
ftgmac100_set_mac(struct eth_device * dev,const unsigned char * mac)334*4882a593Smuzhiyun static void ftgmac100_set_mac(struct eth_device *dev,
335*4882a593Smuzhiyun 	const unsigned char *mac)
336*4882a593Smuzhiyun {
337*4882a593Smuzhiyun 	struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
338*4882a593Smuzhiyun 	unsigned int maddr = mac[0] << 8 | mac[1];
339*4882a593Smuzhiyun 	unsigned int laddr = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5];
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 	debug("%s(%x %x)\n", __func__, maddr, laddr);
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 	writel(maddr, &ftgmac100->mac_madr);
344*4882a593Smuzhiyun 	writel(laddr, &ftgmac100->mac_ladr);
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun 
ftgmac100_set_mac_from_env(struct eth_device * dev)347*4882a593Smuzhiyun static void ftgmac100_set_mac_from_env(struct eth_device *dev)
348*4882a593Smuzhiyun {
349*4882a593Smuzhiyun 	eth_env_get_enetaddr("ethaddr", dev->enetaddr);
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 	ftgmac100_set_mac(dev, dev->enetaddr);
352*4882a593Smuzhiyun }
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun /*
355*4882a593Smuzhiyun  * disable transmitter, receiver
356*4882a593Smuzhiyun  */
ftgmac100_halt(struct eth_device * dev)357*4882a593Smuzhiyun static void ftgmac100_halt(struct eth_device *dev)
358*4882a593Smuzhiyun {
359*4882a593Smuzhiyun 	struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 	debug("%s()\n", __func__);
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun 	writel(0, &ftgmac100->maccr);
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun 
ftgmac100_init(struct eth_device * dev,bd_t * bd)366*4882a593Smuzhiyun static int ftgmac100_init(struct eth_device *dev, bd_t *bd)
367*4882a593Smuzhiyun {
368*4882a593Smuzhiyun 	struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
369*4882a593Smuzhiyun 	struct ftgmac100_data *priv = dev->priv;
370*4882a593Smuzhiyun 	struct ftgmac100_txdes *txdes;
371*4882a593Smuzhiyun 	struct ftgmac100_rxdes *rxdes;
372*4882a593Smuzhiyun 	unsigned int maccr;
373*4882a593Smuzhiyun 	void *buf;
374*4882a593Smuzhiyun 	int i;
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun 	debug("%s()\n", __func__);
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	if (!priv->txdes) {
379*4882a593Smuzhiyun 		txdes = dma_alloc_coherent(
380*4882a593Smuzhiyun 			sizeof(*txdes) * PKTBUFSTX, &priv->txdes_dma);
381*4882a593Smuzhiyun 		if (!txdes)
382*4882a593Smuzhiyun 			panic("ftgmac100: out of memory\n");
383*4882a593Smuzhiyun 		memset(txdes, 0, sizeof(*txdes) * PKTBUFSTX);
384*4882a593Smuzhiyun 		priv->txdes = txdes;
385*4882a593Smuzhiyun 	}
386*4882a593Smuzhiyun 	txdes = priv->txdes;
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 	if (!priv->rxdes) {
389*4882a593Smuzhiyun 		rxdes = dma_alloc_coherent(
390*4882a593Smuzhiyun 			sizeof(*rxdes) * PKTBUFSRX, &priv->rxdes_dma);
391*4882a593Smuzhiyun 		if (!rxdes)
392*4882a593Smuzhiyun 			panic("ftgmac100: out of memory\n");
393*4882a593Smuzhiyun 		memset(rxdes, 0, sizeof(*rxdes) * PKTBUFSRX);
394*4882a593Smuzhiyun 		priv->rxdes = rxdes;
395*4882a593Smuzhiyun 	}
396*4882a593Smuzhiyun 	rxdes = priv->rxdes;
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun 	/* set the ethernet address */
399*4882a593Smuzhiyun 	ftgmac100_set_mac_from_env(dev);
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	/* disable all interrupts */
402*4882a593Smuzhiyun 	writel(0, &ftgmac100->ier);
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 	/* initialize descriptors */
405*4882a593Smuzhiyun 	priv->tx_index = 0;
406*4882a593Smuzhiyun 	priv->rx_index = 0;
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun 	txdes[PKTBUFSTX - 1].txdes0	= FTGMAC100_TXDES0_EDOTR;
409*4882a593Smuzhiyun 	rxdes[PKTBUFSRX - 1].rxdes0	= FTGMAC100_RXDES0_EDORR;
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun 	for (i = 0; i < PKTBUFSTX; i++) {
412*4882a593Smuzhiyun 		/* TXBUF_BADR */
413*4882a593Smuzhiyun 		if (!txdes[i].txdes2) {
414*4882a593Smuzhiyun 			buf = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE);
415*4882a593Smuzhiyun 			if (!buf)
416*4882a593Smuzhiyun 				panic("ftgmac100: out of memory\n");
417*4882a593Smuzhiyun 			txdes[i].txdes3 = virt_to_phys(buf);
418*4882a593Smuzhiyun 			txdes[i].txdes2 = (uint)buf;
419*4882a593Smuzhiyun 		}
420*4882a593Smuzhiyun 		txdes[i].txdes1 = 0;
421*4882a593Smuzhiyun 	}
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 	for (i = 0; i < PKTBUFSRX; i++) {
424*4882a593Smuzhiyun 		/* RXBUF_BADR */
425*4882a593Smuzhiyun 		if (!rxdes[i].rxdes2) {
426*4882a593Smuzhiyun 			buf = net_rx_packets[i];
427*4882a593Smuzhiyun 			rxdes[i].rxdes3 = virt_to_phys(buf);
428*4882a593Smuzhiyun 			rxdes[i].rxdes2 = (uint)buf;
429*4882a593Smuzhiyun 		}
430*4882a593Smuzhiyun 		rxdes[i].rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY;
431*4882a593Smuzhiyun 	}
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun 	/* transmit ring */
434*4882a593Smuzhiyun 	writel(priv->txdes_dma, &ftgmac100->txr_badr);
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun 	/* receive ring */
437*4882a593Smuzhiyun 	writel(priv->rxdes_dma, &ftgmac100->rxr_badr);
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun 	/* poll receive descriptor automatically */
440*4882a593Smuzhiyun 	writel(FTGMAC100_APTC_RXPOLL_CNT(1), &ftgmac100->aptc);
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun 	/* config receive buffer size register */
443*4882a593Smuzhiyun 	writel(FTGMAC100_RBSR_SIZE(RBSR_DEFAULT_VALUE), &ftgmac100->rbsr);
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun 	/* enable transmitter, receiver */
446*4882a593Smuzhiyun 	maccr = FTGMAC100_MACCR_TXMAC_EN |
447*4882a593Smuzhiyun 		FTGMAC100_MACCR_RXMAC_EN |
448*4882a593Smuzhiyun 		FTGMAC100_MACCR_TXDMA_EN |
449*4882a593Smuzhiyun 		FTGMAC100_MACCR_RXDMA_EN |
450*4882a593Smuzhiyun 		FTGMAC100_MACCR_CRC_APD |
451*4882a593Smuzhiyun 		FTGMAC100_MACCR_FULLDUP |
452*4882a593Smuzhiyun 		FTGMAC100_MACCR_RX_RUNT |
453*4882a593Smuzhiyun 		FTGMAC100_MACCR_RX_BROADPKT;
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun 	writel(maccr, &ftgmac100->maccr);
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun 	if (!ftgmac100_phy_init(dev)) {
458*4882a593Smuzhiyun 		if (!ftgmac100_update_link_speed(dev))
459*4882a593Smuzhiyun 			return -1;
460*4882a593Smuzhiyun 	}
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun 	return 0;
463*4882a593Smuzhiyun }
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun /*
466*4882a593Smuzhiyun  * Get a data block via Ethernet
467*4882a593Smuzhiyun  */
ftgmac100_recv(struct eth_device * dev)468*4882a593Smuzhiyun static int ftgmac100_recv(struct eth_device *dev)
469*4882a593Smuzhiyun {
470*4882a593Smuzhiyun 	struct ftgmac100_data *priv = dev->priv;
471*4882a593Smuzhiyun 	struct ftgmac100_rxdes *curr_des;
472*4882a593Smuzhiyun 	unsigned short rxlen;
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun 	curr_des = &priv->rxdes[priv->rx_index];
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun 	if (!(curr_des->rxdes0 & FTGMAC100_RXDES0_RXPKT_RDY))
477*4882a593Smuzhiyun 		return -1;
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun 	if (curr_des->rxdes0 & (FTGMAC100_RXDES0_RX_ERR |
480*4882a593Smuzhiyun 				FTGMAC100_RXDES0_CRC_ERR |
481*4882a593Smuzhiyun 				FTGMAC100_RXDES0_FTL |
482*4882a593Smuzhiyun 				FTGMAC100_RXDES0_RUNT |
483*4882a593Smuzhiyun 				FTGMAC100_RXDES0_RX_ODD_NB)) {
484*4882a593Smuzhiyun 		return -1;
485*4882a593Smuzhiyun 	}
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun 	rxlen = FTGMAC100_RXDES0_VDBC(curr_des->rxdes0);
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun 	debug("%s(): RX buffer %d, %x received\n",
490*4882a593Smuzhiyun 	       __func__, priv->rx_index, rxlen);
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun 	/* invalidate d-cache */
493*4882a593Smuzhiyun 	dma_map_single((void *)curr_des->rxdes2, rxlen, DMA_FROM_DEVICE);
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun 	/* pass the packet up to the protocol layers. */
496*4882a593Smuzhiyun 	net_process_received_packet((void *)curr_des->rxdes2, rxlen);
497*4882a593Smuzhiyun 
498*4882a593Smuzhiyun 	/* release buffer to DMA */
499*4882a593Smuzhiyun 	curr_des->rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY;
500*4882a593Smuzhiyun 
501*4882a593Smuzhiyun 	priv->rx_index = (priv->rx_index + 1) % PKTBUFSRX;
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun 	return 0;
504*4882a593Smuzhiyun }
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun /*
507*4882a593Smuzhiyun  * Send a data block via Ethernet
508*4882a593Smuzhiyun  */
ftgmac100_send(struct eth_device * dev,void * packet,int length)509*4882a593Smuzhiyun static int ftgmac100_send(struct eth_device *dev, void *packet, int length)
510*4882a593Smuzhiyun {
511*4882a593Smuzhiyun 	struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
512*4882a593Smuzhiyun 	struct ftgmac100_data *priv = dev->priv;
513*4882a593Smuzhiyun 	struct ftgmac100_txdes *curr_des = &priv->txdes[priv->tx_index];
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun 	if (curr_des->txdes0 & FTGMAC100_TXDES0_TXDMA_OWN) {
516*4882a593Smuzhiyun 		debug("%s(): no TX descriptor available\n", __func__);
517*4882a593Smuzhiyun 		return -1;
518*4882a593Smuzhiyun 	}
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun 	debug("%s(%x, %x)\n", __func__, (int)packet, length);
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun 	length = (length < ETH_ZLEN) ? ETH_ZLEN : length;
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun 	memcpy((void *)curr_des->txdes2, (void *)packet, length);
525*4882a593Smuzhiyun 	dma_map_single((void *)curr_des->txdes2, length, DMA_TO_DEVICE);
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun 	/* only one descriptor on TXBUF */
528*4882a593Smuzhiyun 	curr_des->txdes0 &= FTGMAC100_TXDES0_EDOTR;
529*4882a593Smuzhiyun 	curr_des->txdes0 |= FTGMAC100_TXDES0_FTS |
530*4882a593Smuzhiyun 			    FTGMAC100_TXDES0_LTS |
531*4882a593Smuzhiyun 			    FTGMAC100_TXDES0_TXBUF_SIZE(length) |
532*4882a593Smuzhiyun 			    FTGMAC100_TXDES0_TXDMA_OWN ;
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun 	/* start transmit */
535*4882a593Smuzhiyun 	writel(1, &ftgmac100->txpd);
536*4882a593Smuzhiyun 
537*4882a593Smuzhiyun 	debug("%s(): packet sent\n", __func__);
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun 	priv->tx_index = (priv->tx_index + 1) % PKTBUFSTX;
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun 	return 0;
542*4882a593Smuzhiyun }
543*4882a593Smuzhiyun 
ftgmac100_initialize(bd_t * bd)544*4882a593Smuzhiyun int ftgmac100_initialize(bd_t *bd)
545*4882a593Smuzhiyun {
546*4882a593Smuzhiyun 	struct eth_device *dev;
547*4882a593Smuzhiyun 	struct ftgmac100_data *priv;
548*4882a593Smuzhiyun 
549*4882a593Smuzhiyun 	dev = malloc(sizeof *dev);
550*4882a593Smuzhiyun 	if (!dev) {
551*4882a593Smuzhiyun 		printf("%s(): failed to allocate dev\n", __func__);
552*4882a593Smuzhiyun 		goto out;
553*4882a593Smuzhiyun 	}
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun 	/* Transmit and receive descriptors should align to 16 bytes */
556*4882a593Smuzhiyun 	priv = memalign(16, sizeof(struct ftgmac100_data));
557*4882a593Smuzhiyun 	if (!priv) {
558*4882a593Smuzhiyun 		printf("%s(): failed to allocate priv\n", __func__);
559*4882a593Smuzhiyun 		goto free_dev;
560*4882a593Smuzhiyun 	}
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun 	memset(dev, 0, sizeof(*dev));
563*4882a593Smuzhiyun 	memset(priv, 0, sizeof(*priv));
564*4882a593Smuzhiyun 
565*4882a593Smuzhiyun 	strcpy(dev->name, "FTGMAC100");
566*4882a593Smuzhiyun 	dev->iobase	= CONFIG_FTGMAC100_BASE;
567*4882a593Smuzhiyun 	dev->init	= ftgmac100_init;
568*4882a593Smuzhiyun 	dev->halt	= ftgmac100_halt;
569*4882a593Smuzhiyun 	dev->send	= ftgmac100_send;
570*4882a593Smuzhiyun 	dev->recv	= ftgmac100_recv;
571*4882a593Smuzhiyun 	dev->priv	= priv;
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun 	eth_register(dev);
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun 	ftgmac100_reset(dev);
576*4882a593Smuzhiyun 
577*4882a593Smuzhiyun 	return 1;
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun free_dev:
580*4882a593Smuzhiyun 	free(dev);
581*4882a593Smuzhiyun out:
582*4882a593Smuzhiyun 	return 0;
583*4882a593Smuzhiyun }
584