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