Commit b3dbf4a51f3891c16315b038cd3b7a87f4182e0d
Committed by
Wolfgang Denk
1 parent
3474741c8d
Exists in
master
and in
54 other branches
ftgmac100: support of gigabit eth ftgmac100
Add Faraday's ftgmac100 (gigabit ethernet) MAC controller's driver. Signed-off-by: Macpaul Lin <macpaul@andestech.com>
Showing 5 changed files with 839 additions and 0 deletions Side-by-side Diff
README
... | ... | @@ -861,6 +861,18 @@ |
861 | 861 | Define this to use i/o functions instead of macros |
862 | 862 | (some hardware wont work with macros) |
863 | 863 | |
864 | + CONFIG_FTGMAC100 | |
865 | + Support for Faraday's FTGMAC100 Gigabit SoC Ethernet | |
866 | + | |
867 | + CONFIG_FTGMAC100_EGIGA | |
868 | + Define this to use GE link update with gigabit PHY. | |
869 | + Define this if FTGMAC100 is connected to gigabit PHY. | |
870 | + If your system has 10/100 PHY only, it might not occur | |
871 | + wrong behavior. Because PHY usually return timeout or | |
872 | + useless data when polling gigabit status and gigabit | |
873 | + control registers. This behavior won't affect the | |
874 | + correctnessof 10/100 link speed update. | |
875 | + | |
864 | 876 | CONFIG_SMC911X |
865 | 877 | Support for SMSC's LAN911x and LAN921x chips |
866 | 878 |
drivers/net/Makefile
... | ... | @@ -47,6 +47,7 @@ |
47 | 47 | COBJS-$(CONFIG_ETHOC) += ethoc.o |
48 | 48 | COBJS-$(CONFIG_FEC_MXC) += fec_mxc.o |
49 | 49 | COBJS-$(CONFIG_FSLDMAFEC) += fsl_mcdmafec.o mcfmii.o |
50 | +COBJS-$(CONFIG_FTGMAC100) += ftgmac100.o | |
50 | 51 | COBJS-$(CONFIG_FTMAC100) += ftmac100.o |
51 | 52 | COBJS-$(CONFIG_GRETH) += greth.o |
52 | 53 | COBJS-$(CONFIG_INCA_IP_SWITCH) += inca-ip_sw.o |
drivers/net/ftgmac100.c
1 | +/* | |
2 | + * Faraday FTGMAC100 Ethernet | |
3 | + * | |
4 | + * (C) Copyright 2009 Faraday Technology | |
5 | + * Po-Yu Chuang <ratbert@faraday-tech.com> | |
6 | + * | |
7 | + * (C) Copyright 2010 Andes Technology | |
8 | + * Macpaul Lin <macpaul@andestech.com> | |
9 | + * | |
10 | + * This program is free software; you can redistribute it and/or modify | |
11 | + * it under the terms of the GNU General Public License as published by | |
12 | + * the Free Software Foundation; either version 2 of the License, or | |
13 | + * (at your option) any later version. | |
14 | + * | |
15 | + * This program is distributed in the hope that it will be useful, | |
16 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | + * GNU General Public License for more details. | |
19 | + * | |
20 | + * You should have received a copy of the GNU General Public License | |
21 | + * along with this program; if not, write to the Free Software | |
22 | + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
23 | + */ | |
24 | + | |
25 | +#include <config.h> | |
26 | +#include <common.h> | |
27 | +#include <malloc.h> | |
28 | +#include <net.h> | |
29 | +#include <asm/io.h> | |
30 | +#include <linux/mii.h> | |
31 | + | |
32 | +#include "ftgmac100.h" | |
33 | + | |
34 | +#define ETH_ZLEN 60 | |
35 | + | |
36 | +#define mdelay(n) ({unsigned long msec = (n); while (msec--) udelay(1000); }) | |
37 | + | |
38 | +/* RBSR - hw default init value is also 0x640 */ | |
39 | +#define RBSR_DEFAULT_VALUE 0x640 | |
40 | + | |
41 | +/* PKTBUFSTX/PKTBUFSRX must both be power of 2 */ | |
42 | +#define PKTBUFSTX 4 /* must be power of 2 */ | |
43 | + | |
44 | +struct ftgmac100_data { | |
45 | + struct ftgmac100_txdes txdes[PKTBUFSTX]; | |
46 | + struct ftgmac100_rxdes rxdes[PKTBUFSRX]; | |
47 | + int tx_index; | |
48 | + int rx_index; | |
49 | + int phy_addr; | |
50 | +}; | |
51 | + | |
52 | +/* | |
53 | + * struct mii_bus functions | |
54 | + */ | |
55 | +static int ftgmac100_mdiobus_read(struct eth_device *dev, int phy_addr, | |
56 | + int regnum) | |
57 | +{ | |
58 | + struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase; | |
59 | + int phycr; | |
60 | + int i; | |
61 | + | |
62 | + phycr = readl(&ftgmac100->phycr); | |
63 | + | |
64 | + /* preserve MDC cycle threshold */ | |
65 | + phycr &= FTGMAC100_PHYCR_MDC_CYCTHR_MASK; | |
66 | + | |
67 | + phycr |= FTGMAC100_PHYCR_PHYAD(phy_addr) | |
68 | + | FTGMAC100_PHYCR_REGAD(regnum) | |
69 | + | FTGMAC100_PHYCR_MIIRD; | |
70 | + | |
71 | + writel(phycr, &ftgmac100->phycr); | |
72 | + | |
73 | + for (i = 0; i < 10; i++) { | |
74 | + phycr = readl(&ftgmac100->phycr); | |
75 | + | |
76 | + if ((phycr & FTGMAC100_PHYCR_MIIRD) == 0) { | |
77 | + int data; | |
78 | + | |
79 | + data = readl(&ftgmac100->phydata); | |
80 | + return FTGMAC100_PHYDATA_MIIRDATA(data); | |
81 | + } | |
82 | + | |
83 | + mdelay(10); | |
84 | + } | |
85 | + | |
86 | + debug("mdio read timed out\n"); | |
87 | + return -1; | |
88 | +} | |
89 | + | |
90 | +static int ftgmac100_mdiobus_write(struct eth_device *dev, int phy_addr, | |
91 | + int regnum, u16 value) | |
92 | +{ | |
93 | + struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase; | |
94 | + int phycr; | |
95 | + int data; | |
96 | + int i; | |
97 | + | |
98 | + phycr = readl(&ftgmac100->phycr); | |
99 | + | |
100 | + /* preserve MDC cycle threshold */ | |
101 | + phycr &= FTGMAC100_PHYCR_MDC_CYCTHR_MASK; | |
102 | + | |
103 | + phycr |= FTGMAC100_PHYCR_PHYAD(phy_addr) | |
104 | + | FTGMAC100_PHYCR_REGAD(regnum) | |
105 | + | FTGMAC100_PHYCR_MIIWR; | |
106 | + | |
107 | + data = FTGMAC100_PHYDATA_MIIWDATA(value); | |
108 | + | |
109 | + writel(data, &ftgmac100->phydata); | |
110 | + writel(phycr, &ftgmac100->phycr); | |
111 | + | |
112 | + for (i = 0; i < 10; i++) { | |
113 | + phycr = readl(&ftgmac100->phycr); | |
114 | + | |
115 | + if ((phycr & FTGMAC100_PHYCR_MIIWR) == 0) { | |
116 | + debug("(phycr & FTGMAC100_PHYCR_MIIWR) == 0: " \ | |
117 | + "phy_addr: %x\n", phy_addr); | |
118 | + return 0; | |
119 | + } | |
120 | + | |
121 | + mdelay(1); | |
122 | + } | |
123 | + | |
124 | + debug("mdio write timed out\n"); | |
125 | + return -1; | |
126 | +} | |
127 | + | |
128 | +int ftgmac100_phy_read(struct eth_device *dev, int addr, int reg, u16 *value) | |
129 | +{ | |
130 | + *value = ftgmac100_mdiobus_read(dev , addr, reg); | |
131 | + | |
132 | + if (*value == -1) | |
133 | + return -1; | |
134 | + | |
135 | + return 0; | |
136 | +} | |
137 | + | |
138 | +int ftgmac100_phy_write(struct eth_device *dev, int addr, int reg, u16 value) | |
139 | +{ | |
140 | + if (ftgmac100_mdiobus_write(dev, addr, reg, value) == -1) | |
141 | + return -1; | |
142 | + | |
143 | + return 0; | |
144 | +} | |
145 | + | |
146 | +static int ftgmac100_phy_reset(struct eth_device *dev) | |
147 | +{ | |
148 | + struct ftgmac100_data *priv = dev->priv; | |
149 | + int i; | |
150 | + u16 status, adv; | |
151 | + | |
152 | + adv = ADVERTISE_CSMA | ADVERTISE_ALL; | |
153 | + | |
154 | + ftgmac100_phy_write(dev, priv->phy_addr, MII_ADVERTISE, adv); | |
155 | + | |
156 | + printf("%s: Starting autonegotiation...\n", dev->name); | |
157 | + | |
158 | + ftgmac100_phy_write(dev, priv->phy_addr, | |
159 | + MII_BMCR, (BMCR_ANENABLE | BMCR_ANRESTART)); | |
160 | + | |
161 | + for (i = 0; i < 100000 / 100; i++) { | |
162 | + ftgmac100_phy_read(dev, priv->phy_addr, MII_BMSR, &status); | |
163 | + | |
164 | + if (status & BMSR_ANEGCOMPLETE) | |
165 | + break; | |
166 | + mdelay(1); | |
167 | + } | |
168 | + | |
169 | + if (status & BMSR_ANEGCOMPLETE) { | |
170 | + printf("%s: Autonegotiation complete\n", dev->name); | |
171 | + } else { | |
172 | + printf("%s: Autonegotiation timed out (status=0x%04x)\n", | |
173 | + dev->name, status); | |
174 | + return 0; | |
175 | + } | |
176 | + | |
177 | + return 1; | |
178 | +} | |
179 | + | |
180 | +static int ftgmac100_phy_init(struct eth_device *dev) | |
181 | +{ | |
182 | + struct ftgmac100_data *priv = dev->priv; | |
183 | + | |
184 | + int phy_addr; | |
185 | + u16 phy_id, status, adv, lpa, stat_ge; | |
186 | + int media, speed, duplex; | |
187 | + int i; | |
188 | + | |
189 | + /* Check if the PHY is up to snuff... */ | |
190 | + for (phy_addr = 0; phy_addr < CONFIG_PHY_MAX_ADDR; phy_addr++) { | |
191 | + | |
192 | + ftgmac100_phy_read(dev, phy_addr, MII_PHYSID1, &phy_id); | |
193 | + | |
194 | + /* | |
195 | + * When it is unable to found PHY, | |
196 | + * the interface usually return 0xffff or 0x0000 | |
197 | + */ | |
198 | + if (phy_id != 0xffff && phy_id != 0x0) { | |
199 | + printf("%s: found PHY at 0x%02x\n", | |
200 | + dev->name, phy_addr); | |
201 | + priv->phy_addr = phy_addr; | |
202 | + break; | |
203 | + } | |
204 | + } | |
205 | + | |
206 | + if (phy_id == 0xffff || phy_id == 0x0) { | |
207 | + printf("%s: no PHY present\n", dev->name); | |
208 | + return 0; | |
209 | + } | |
210 | + | |
211 | + ftgmac100_phy_read(dev, priv->phy_addr, MII_BMSR, &status); | |
212 | + | |
213 | + if (!(status & BMSR_LSTATUS)) { | |
214 | + /* Try to re-negotiate if we don't have link already. */ | |
215 | + ftgmac100_phy_reset(dev); | |
216 | + | |
217 | + for (i = 0; i < 100000 / 100; i++) { | |
218 | + ftgmac100_phy_read(dev, priv->phy_addr, | |
219 | + MII_BMSR, &status); | |
220 | + if (status & BMSR_LSTATUS) | |
221 | + break; | |
222 | + udelay(100); | |
223 | + } | |
224 | + } | |
225 | + | |
226 | + if (!(status & BMSR_LSTATUS)) { | |
227 | + printf("%s: link down\n", dev->name); | |
228 | + return 0; | |
229 | + } | |
230 | + | |
231 | +#ifdef CONFIG_FTGMAC100_EGIGA | |
232 | + /* 1000 Base-T Status Register */ | |
233 | + ftgmac100_phy_read(dev, priv->phy_addr, | |
234 | + MII_STAT1000, &stat_ge); | |
235 | + | |
236 | + speed = (stat_ge & (LPA_1000FULL | LPA_1000HALF) | |
237 | + ? 1 : 0); | |
238 | + | |
239 | + duplex = ((stat_ge & LPA_1000FULL) | |
240 | + ? 1 : 0); | |
241 | + | |
242 | + if (speed) { /* Speed is 1000 */ | |
243 | + printf("%s: link up, 1000bps %s-duplex\n", | |
244 | + dev->name, duplex ? "full" : "half"); | |
245 | + return 0; | |
246 | + } | |
247 | +#endif | |
248 | + | |
249 | + ftgmac100_phy_read(dev, priv->phy_addr, MII_ADVERTISE, &adv); | |
250 | + ftgmac100_phy_read(dev, priv->phy_addr, MII_LPA, &lpa); | |
251 | + | |
252 | + media = mii_nway_result(lpa & adv); | |
253 | + speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF) ? 1 : 0); | |
254 | + duplex = (media & ADVERTISE_FULL) ? 1 : 0; | |
255 | + | |
256 | + printf("%s: link up, %sMbps %s-duplex\n", | |
257 | + dev->name, speed ? "100" : "10", duplex ? "full" : "half"); | |
258 | + | |
259 | + return 1; | |
260 | +} | |
261 | + | |
262 | +static int ftgmac100_update_link_speed(struct eth_device *dev) | |
263 | +{ | |
264 | + struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase; | |
265 | + struct ftgmac100_data *priv = dev->priv; | |
266 | + | |
267 | + unsigned short stat_fe; | |
268 | + unsigned short stat_ge; | |
269 | + unsigned int maccr; | |
270 | + | |
271 | +#ifdef CONFIG_FTGMAC100_EGIGA | |
272 | + /* 1000 Base-T Status Register */ | |
273 | + ftgmac100_phy_read(dev, priv->phy_addr, MII_STAT1000, &stat_ge); | |
274 | +#endif | |
275 | + | |
276 | + ftgmac100_phy_read(dev, priv->phy_addr, MII_BMSR, &stat_fe); | |
277 | + | |
278 | + if (!(stat_fe & BMSR_LSTATUS)) /* link status up? */ | |
279 | + return 0; | |
280 | + | |
281 | + /* read MAC control register and clear related bits */ | |
282 | + maccr = readl(&ftgmac100->maccr) & | |
283 | + ~(FTGMAC100_MACCR_GIGA_MODE | | |
284 | + FTGMAC100_MACCR_FAST_MODE | | |
285 | + FTGMAC100_MACCR_FULLDUP); | |
286 | + | |
287 | +#ifdef CONFIG_FTGMAC100_EGIGA | |
288 | + if (stat_ge & LPA_1000FULL) { | |
289 | + /* set gmac for 1000BaseTX and Full Duplex */ | |
290 | + maccr |= FTGMAC100_MACCR_GIGA_MODE | FTGMAC100_MACCR_FULLDUP; | |
291 | + } | |
292 | + | |
293 | + if (stat_ge & LPA_1000HALF) { | |
294 | + /* set gmac for 1000BaseTX and Half Duplex */ | |
295 | + maccr |= FTGMAC100_MACCR_GIGA_MODE; | |
296 | + } | |
297 | +#endif | |
298 | + | |
299 | + if (stat_fe & BMSR_100FULL) { | |
300 | + /* set MII for 100BaseTX and Full Duplex */ | |
301 | + maccr |= FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_FULLDUP; | |
302 | + } | |
303 | + | |
304 | + if (stat_fe & BMSR_10FULL) { | |
305 | + /* set MII for 10BaseT and Full Duplex */ | |
306 | + maccr |= FTGMAC100_MACCR_FULLDUP; | |
307 | + } | |
308 | + | |
309 | + if (stat_fe & BMSR_100HALF) { | |
310 | + /* set MII for 100BaseTX and Half Duplex */ | |
311 | + maccr |= FTGMAC100_MACCR_FAST_MODE; | |
312 | + } | |
313 | + | |
314 | + if (stat_fe & BMSR_10HALF) { | |
315 | + /* set MII for 10BaseT and Half Duplex */ | |
316 | + /* we have already clear these bits, do nothing */ | |
317 | + ; | |
318 | + } | |
319 | + | |
320 | + /* update MII config into maccr */ | |
321 | + writel(maccr, &ftgmac100->maccr); | |
322 | + | |
323 | + return 1; | |
324 | +} | |
325 | + | |
326 | +/* | |
327 | + * Reset MAC | |
328 | + */ | |
329 | +static void ftgmac100_reset(struct eth_device *dev) | |
330 | +{ | |
331 | + struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase; | |
332 | + | |
333 | + debug("%s()\n", __func__); | |
334 | + | |
335 | + writel(FTGMAC100_MACCR_SW_RST, &ftgmac100->maccr); | |
336 | + | |
337 | + while (readl(&ftgmac100->maccr) & FTGMAC100_MACCR_SW_RST) | |
338 | + ; | |
339 | +} | |
340 | + | |
341 | +/* | |
342 | + * Set MAC address | |
343 | + */ | |
344 | +static void ftgmac100_set_mac(struct eth_device *dev, | |
345 | + const unsigned char *mac) | |
346 | +{ | |
347 | + struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase; | |
348 | + unsigned int maddr = mac[0] << 8 | mac[1]; | |
349 | + unsigned int laddr = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5]; | |
350 | + | |
351 | + debug("%s(%x %x)\n", __func__, maddr, laddr); | |
352 | + | |
353 | + writel(maddr, &ftgmac100->mac_madr); | |
354 | + writel(laddr, &ftgmac100->mac_ladr); | |
355 | +} | |
356 | + | |
357 | +static void ftgmac100_set_mac_from_env(struct eth_device *dev) | |
358 | +{ | |
359 | + eth_getenv_enetaddr("ethaddr", dev->enetaddr); | |
360 | + | |
361 | + ftgmac100_set_mac(dev, dev->enetaddr); | |
362 | +} | |
363 | + | |
364 | +/* | |
365 | + * disable transmitter, receiver | |
366 | + */ | |
367 | +static void ftgmac100_halt(struct eth_device *dev) | |
368 | +{ | |
369 | + struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase; | |
370 | + | |
371 | + debug("%s()\n", __func__); | |
372 | + | |
373 | + writel(0, &ftgmac100->maccr); | |
374 | +} | |
375 | + | |
376 | +static int ftgmac100_init(struct eth_device *dev, bd_t *bd) | |
377 | +{ | |
378 | + struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase; | |
379 | + struct ftgmac100_data *priv = dev->priv; | |
380 | + struct ftgmac100_txdes *txdes = priv->txdes; | |
381 | + struct ftgmac100_rxdes *rxdes = priv->rxdes; | |
382 | + unsigned int maccr; | |
383 | + int i; | |
384 | + | |
385 | + debug("%s()\n", __func__); | |
386 | + | |
387 | + ftgmac100_reset(dev); | |
388 | + | |
389 | + /* set the ethernet address */ | |
390 | + ftgmac100_set_mac_from_env(dev); | |
391 | + | |
392 | + /* disable all interrupts */ | |
393 | + writel(0, &ftgmac100->ier); | |
394 | + | |
395 | + /* initialize descriptors */ | |
396 | + priv->tx_index = 0; | |
397 | + priv->rx_index = 0; | |
398 | + | |
399 | + txdes[PKTBUFSTX - 1].txdes0 = FTGMAC100_TXDES0_EDOTR; | |
400 | + rxdes[PKTBUFSRX - 1].rxdes0 = FTGMAC100_RXDES0_EDORR; | |
401 | + | |
402 | + for (i = 0; i < PKTBUFSTX; i++) { | |
403 | + /* TXBUF_BADR */ | |
404 | + txdes[i].txdes3 = 0; | |
405 | + txdes[i].txdes1 = 0; | |
406 | + } | |
407 | + | |
408 | + for (i = 0; i < PKTBUFSRX; i++) { | |
409 | + /* RXBUF_BADR */ | |
410 | + rxdes[i].rxdes3 = (unsigned int)NetRxPackets[i]; | |
411 | + rxdes[i].rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY; | |
412 | + } | |
413 | + | |
414 | + /* transmit ring */ | |
415 | + writel((unsigned int)txdes, &ftgmac100->txr_badr); | |
416 | + | |
417 | + /* receive ring */ | |
418 | + writel((unsigned int)rxdes, &ftgmac100->rxr_badr); | |
419 | + | |
420 | + /* poll receive descriptor automatically */ | |
421 | + writel(FTGMAC100_APTC_RXPOLL_CNT(1), &ftgmac100->aptc); | |
422 | + | |
423 | + /* config receive buffer size register */ | |
424 | + writel(FTGMAC100_RBSR_SIZE(RBSR_DEFAULT_VALUE), &ftgmac100->rbsr); | |
425 | + | |
426 | + /* enable transmitter, receiver */ | |
427 | + maccr = FTGMAC100_MACCR_TXMAC_EN | | |
428 | + FTGMAC100_MACCR_RXMAC_EN | | |
429 | + FTGMAC100_MACCR_TXDMA_EN | | |
430 | + FTGMAC100_MACCR_RXDMA_EN | | |
431 | + FTGMAC100_MACCR_CRC_APD | | |
432 | + FTGMAC100_MACCR_FULLDUP | | |
433 | + FTGMAC100_MACCR_RX_RUNT | | |
434 | + FTGMAC100_MACCR_RX_BROADPKT; | |
435 | + | |
436 | + writel(maccr, &ftgmac100->maccr); | |
437 | + | |
438 | + if (!ftgmac100_phy_init(dev)) { | |
439 | + if (!ftgmac100_update_link_speed(dev)) | |
440 | + return -1; | |
441 | + } | |
442 | + | |
443 | + return 0; | |
444 | +} | |
445 | + | |
446 | +/* | |
447 | + * Get a data block via Ethernet | |
448 | + */ | |
449 | +static int ftgmac100_recv(struct eth_device *dev) | |
450 | +{ | |
451 | + struct ftgmac100_data *priv = dev->priv; | |
452 | + struct ftgmac100_rxdes *curr_des; | |
453 | + unsigned short rxlen; | |
454 | + | |
455 | + curr_des = &priv->rxdes[priv->rx_index]; | |
456 | + | |
457 | + if (!(curr_des->rxdes0 & FTGMAC100_RXDES0_RXPKT_RDY)) | |
458 | + return -1; | |
459 | + | |
460 | + if (curr_des->rxdes0 & (FTGMAC100_RXDES0_RX_ERR | | |
461 | + FTGMAC100_RXDES0_CRC_ERR | | |
462 | + FTGMAC100_RXDES0_FTL | | |
463 | + FTGMAC100_RXDES0_RUNT | | |
464 | + FTGMAC100_RXDES0_RX_ODD_NB)) { | |
465 | + return -1; | |
466 | + } | |
467 | + | |
468 | + rxlen = FTGMAC100_RXDES0_VDBC(curr_des->rxdes0); | |
469 | + | |
470 | + debug("%s(): RX buffer %d, %x received\n", | |
471 | + __func__, priv->rx_index, rxlen); | |
472 | + | |
473 | + /* pass the packet up to the protocol layers. */ | |
474 | + NetReceive((void *)curr_des->rxdes3, rxlen); | |
475 | + | |
476 | + /* release buffer to DMA */ | |
477 | + curr_des->rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY; | |
478 | + | |
479 | + priv->rx_index = (priv->rx_index + 1) % PKTBUFSRX; | |
480 | + | |
481 | + return 0; | |
482 | +} | |
483 | + | |
484 | +/* | |
485 | + * Send a data block via Ethernet | |
486 | + */ | |
487 | +static int | |
488 | +ftgmac100_send(struct eth_device *dev, void *packet, int length) | |
489 | +{ | |
490 | + struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase; | |
491 | + struct ftgmac100_data *priv = dev->priv; | |
492 | + struct ftgmac100_txdes *curr_des = &priv->txdes[priv->tx_index]; | |
493 | + int start; | |
494 | + | |
495 | + if (curr_des->txdes0 & FTGMAC100_TXDES0_TXDMA_OWN) { | |
496 | + debug("%s(): no TX descriptor available\n", __func__); | |
497 | + return -1; | |
498 | + } | |
499 | + | |
500 | + debug("%s(%x, %x)\n", __func__, (int)packet, length); | |
501 | + | |
502 | + length = (length < ETH_ZLEN) ? ETH_ZLEN : length; | |
503 | + | |
504 | + /* initiate a transmit sequence */ | |
505 | + curr_des->txdes3 = (unsigned int)packet; /* TXBUF_BADR */ | |
506 | + | |
507 | + /* only one descriptor on TXBUF */ | |
508 | + curr_des->txdes0 &= FTGMAC100_TXDES0_EDOTR; | |
509 | + curr_des->txdes0 |= FTGMAC100_TXDES0_FTS | | |
510 | + FTGMAC100_TXDES0_LTS | | |
511 | + FTGMAC100_TXDES0_TXBUF_SIZE(length) | | |
512 | + FTGMAC100_TXDES0_TXDMA_OWN ; | |
513 | + | |
514 | + /* start transmit */ | |
515 | + writel(1, &ftgmac100->txpd); | |
516 | + | |
517 | + /* wait for transfer to succeed */ | |
518 | + start = get_timer(0); | |
519 | + while (curr_des->txdes0 & FTGMAC100_TXDES0_TXDMA_OWN) { | |
520 | + if (get_timer(0) >= 5) { | |
521 | + debug("%s(): timed out\n", __func__); | |
522 | + return -1; | |
523 | + } | |
524 | + } | |
525 | + | |
526 | + debug("%s(): packet sent\n", __func__); | |
527 | + | |
528 | + priv->tx_index = (priv->tx_index + 1) % PKTBUFSTX; | |
529 | + | |
530 | + return 0; | |
531 | +} | |
532 | + | |
533 | +int ftgmac100_initialize(bd_t *bd) | |
534 | +{ | |
535 | + struct eth_device *dev; | |
536 | + struct ftgmac100_data *priv; | |
537 | + | |
538 | + dev = malloc(sizeof *dev); | |
539 | + if (!dev) { | |
540 | + printf("%s(): failed to allocate dev\n", __func__); | |
541 | + goto out; | |
542 | + } | |
543 | + | |
544 | + /* Transmit and receive descriptors should align to 16 bytes */ | |
545 | + priv = memalign(16, sizeof(struct ftgmac100_data)); | |
546 | + if (!priv) { | |
547 | + printf("%s(): failed to allocate priv\n", __func__); | |
548 | + goto free_dev; | |
549 | + } | |
550 | + | |
551 | + memset(dev, 0, sizeof(*dev)); | |
552 | + memset(priv, 0, sizeof(*priv)); | |
553 | + | |
554 | + sprintf(dev->name, "FTGMAC100"); | |
555 | + dev->iobase = CONFIG_FTGMAC100_BASE; | |
556 | + dev->init = ftgmac100_init; | |
557 | + dev->halt = ftgmac100_halt; | |
558 | + dev->send = ftgmac100_send; | |
559 | + dev->recv = ftgmac100_recv; | |
560 | + dev->priv = priv; | |
561 | + | |
562 | + eth_register(dev); | |
563 | + | |
564 | + return 1; | |
565 | + | |
566 | +free_dev: | |
567 | + free(dev); | |
568 | +out: | |
569 | + return 0; | |
570 | +} |
drivers/net/ftgmac100.h
1 | +/* | |
2 | + * Faraday FTGMAC100 Ethernet | |
3 | + * | |
4 | + * (C) Copyright 2010 Faraday Technology | |
5 | + * Po-Yu Chuang <ratbert@faraday-tech.com> | |
6 | + * | |
7 | + * (C) Copyright 2010 Andes Technology | |
8 | + * Macpaul Lin <macpaul@andestech.com> | |
9 | + * | |
10 | + * This program is free software; you can redistribute it and/or modify | |
11 | + * it under the terms of the GNU General Public License as published by | |
12 | + * the Free Software Foundation; either version 2 of the License, or | |
13 | + * (at your option) any later version. | |
14 | + * | |
15 | + * This program is distributed in the hope that it will be useful, | |
16 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | + * GNU General Public License for more details. | |
19 | + * | |
20 | + * You should have received a copy of the GNU General Public License | |
21 | + * along with this program; if not, write to the Free Software | |
22 | + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
23 | + */ | |
24 | + | |
25 | +#ifndef __FTGMAC100_H | |
26 | +#define __FTGMAC100_H | |
27 | + | |
28 | +/* The registers offset table of ftgmac100 */ | |
29 | +struct ftgmac100 { | |
30 | + unsigned int isr; /* 0x00 */ | |
31 | + unsigned int ier; /* 0x04 */ | |
32 | + unsigned int mac_madr; /* 0x08 */ | |
33 | + unsigned int mac_ladr; /* 0x0c */ | |
34 | + unsigned int maht0; /* 0x10 */ | |
35 | + unsigned int maht1; /* 0x14 */ | |
36 | + unsigned int txpd; /* 0x18 */ | |
37 | + unsigned int rxpd; /* 0x1c */ | |
38 | + unsigned int txr_badr; /* 0x20 */ | |
39 | + unsigned int rxr_badr; /* 0x24 */ | |
40 | + unsigned int hptxpd; /* 0x28 */ | |
41 | + unsigned int hptxpd_badr; /* 0x2c */ | |
42 | + unsigned int itc; /* 0x30 */ | |
43 | + unsigned int aptc; /* 0x34 */ | |
44 | + unsigned int dblac; /* 0x38 */ | |
45 | + unsigned int dmafifos; /* 0x3c */ | |
46 | + unsigned int revr; /* 0x40 */ | |
47 | + unsigned int fear; /* 0x44 */ | |
48 | + unsigned int tpafcr; /* 0x48 */ | |
49 | + unsigned int rbsr; /* 0x4c */ | |
50 | + unsigned int maccr; /* 0x50 */ | |
51 | + unsigned int macsr; /* 0x54 */ | |
52 | + unsigned int tm; /* 0x58 */ | |
53 | + unsigned int resv1; /* 0x5c */ /* not defined in spec */ | |
54 | + unsigned int phycr; /* 0x60 */ | |
55 | + unsigned int phydata; /* 0x64 */ | |
56 | + unsigned int fcr; /* 0x68 */ | |
57 | + unsigned int bpr; /* 0x6c */ | |
58 | + unsigned int wolcr; /* 0x70 */ | |
59 | + unsigned int wolsr; /* 0x74 */ | |
60 | + unsigned int wfcrc; /* 0x78 */ | |
61 | + unsigned int resv2; /* 0x7c */ /* not defined in spec */ | |
62 | + unsigned int wfbm1; /* 0x80 */ | |
63 | + unsigned int wfbm2; /* 0x84 */ | |
64 | + unsigned int wfbm3; /* 0x88 */ | |
65 | + unsigned int wfbm4; /* 0x8c */ | |
66 | + unsigned int nptxr_ptr; /* 0x90 */ | |
67 | + unsigned int hptxr_ptr; /* 0x94 */ | |
68 | + unsigned int rxr_ptr; /* 0x98 */ | |
69 | + unsigned int resv3; /* 0x9c */ /* not defined in spec */ | |
70 | + unsigned int tx; /* 0xa0 */ | |
71 | + unsigned int tx_mcol_scol; /* 0xa4 */ | |
72 | + unsigned int tx_ecol_fail; /* 0xa8 */ | |
73 | + unsigned int tx_lcol_und; /* 0xac */ | |
74 | + unsigned int rx; /* 0xb0 */ | |
75 | + unsigned int rx_bc; /* 0xb4 */ | |
76 | + unsigned int rx_mc; /* 0xb8 */ | |
77 | + unsigned int rx_pf_aep; /* 0xbc */ | |
78 | + unsigned int rx_runt; /* 0xc0 */ | |
79 | + unsigned int rx_crcer_ftl; /* 0xc4 */ | |
80 | + unsigned int rx_col_lost; /* 0xc8 */ | |
81 | +}; | |
82 | + | |
83 | +/* | |
84 | + * Interrupt status register & interrupt enable register | |
85 | + */ | |
86 | +#define FTGMAC100_INT_RPKT_BUF (1 << 0) | |
87 | +#define FTGMAC100_INT_RPKT_FIFO (1 << 1) | |
88 | +#define FTGMAC100_INT_NO_RXBUF (1 << 2) | |
89 | +#define FTGMAC100_INT_RPKT_LOST (1 << 3) | |
90 | +#define FTGMAC100_INT_XPKT_ETH (1 << 4) | |
91 | +#define FTGMAC100_INT_XPKT_FIFO (1 << 5) | |
92 | +#define FTGMAC100_INT_NO_NPTXBUF (1 << 6) | |
93 | +#define FTGMAC100_INT_XPKT_LOST (1 << 7) | |
94 | +#define FTGMAC100_INT_AHB_ERR (1 << 8) | |
95 | +#define FTGMAC100_INT_PHYSTS_CHG (1 << 9) | |
96 | +#define FTGMAC100_INT_NO_HPTXBUF (1 << 10) | |
97 | + | |
98 | +/* | |
99 | + * Interrupt timer control register | |
100 | + */ | |
101 | +#define FTGMAC100_ITC_RXINT_CNT(x) (((x) & 0xf) << 0) | |
102 | +#define FTGMAC100_ITC_RXINT_THR(x) (((x) & 0x7) << 4) | |
103 | +#define FTGMAC100_ITC_RXINT_TIME_SEL (1 << 7) | |
104 | +#define FTGMAC100_ITC_TXINT_CNT(x) (((x) & 0xf) << 8) | |
105 | +#define FTGMAC100_ITC_TXINT_THR(x) (((x) & 0x7) << 12) | |
106 | +#define FTGMAC100_ITC_TXINT_TIME_SEL (1 << 15) | |
107 | + | |
108 | +/* | |
109 | + * Automatic polling timer control register | |
110 | + */ | |
111 | +#define FTGMAC100_APTC_RXPOLL_CNT(x) (((x) & 0xf) << 0) | |
112 | +#define FTGMAC100_APTC_RXPOLL_TIME_SEL (1 << 4) | |
113 | +#define FTGMAC100_APTC_TXPOLL_CNT(x) (((x) & 0xf) << 8) | |
114 | +#define FTGMAC100_APTC_TXPOLL_TIME_SEL (1 << 12) | |
115 | + | |
116 | +/* | |
117 | + * DMA burst length and arbitration control register | |
118 | + */ | |
119 | +#define FTGMAC100_DBLAC_RXFIFO_LTHR(x) (((x) & 0x7) << 0) | |
120 | +#define FTGMAC100_DBLAC_RXFIFO_HTHR(x) (((x) & 0x7) << 3) | |
121 | +#define FTGMAC100_DBLAC_RX_THR_EN (1 << 6) | |
122 | +#define FTGMAC100_DBLAC_RXBURST_SIZE(x) (((x) & 0x3) << 8) | |
123 | +#define FTGMAC100_DBLAC_TXBURST_SIZE(x) (((x) & 0x3) << 10) | |
124 | +#define FTGMAC100_DBLAC_RXDES_SIZE(x) (((x) & 0xf) << 12) | |
125 | +#define FTGMAC100_DBLAC_TXDES_SIZE(x) (((x) & 0xf) << 16) | |
126 | +#define FTGMAC100_DBLAC_IFG_CNT(x) (((x) & 0x7) << 20) | |
127 | +#define FTGMAC100_DBLAC_IFG_INC (1 << 23) | |
128 | + | |
129 | +/* | |
130 | + * DMA FIFO status register | |
131 | + */ | |
132 | +#define FTGMAC100_DMAFIFOS_RXDMA1_SM(dmafifos) ((dmafifos) & 0xf) | |
133 | +#define FTGMAC100_DMAFIFOS_RXDMA2_SM(dmafifos) (((dmafifos) >> 4) & 0xf) | |
134 | +#define FTGMAC100_DMAFIFOS_RXDMA3_SM(dmafifos) (((dmafifos) >> 8) & 0x7) | |
135 | +#define FTGMAC100_DMAFIFOS_TXDMA1_SM(dmafifos) (((dmafifos) >> 12) & 0xf) | |
136 | +#define FTGMAC100_DMAFIFOS_TXDMA2_SM(dmafifos) (((dmafifos) >> 16) & 0x3) | |
137 | +#define FTGMAC100_DMAFIFOS_TXDMA3_SM(dmafifos) (((dmafifos) >> 18) & 0xf) | |
138 | +#define FTGMAC100_DMAFIFOS_RXFIFO_EMPTY (1 << 26) | |
139 | +#define FTGMAC100_DMAFIFOS_TXFIFO_EMPTY (1 << 27) | |
140 | +#define FTGMAC100_DMAFIFOS_RXDMA_GRANT (1 << 28) | |
141 | +#define FTGMAC100_DMAFIFOS_TXDMA_GRANT (1 << 29) | |
142 | +#define FTGMAC100_DMAFIFOS_RXDMA_REQ (1 << 30) | |
143 | +#define FTGMAC100_DMAFIFOS_TXDMA_REQ (1 << 31) | |
144 | + | |
145 | +/* | |
146 | + * Receive buffer size register | |
147 | + */ | |
148 | +#define FTGMAC100_RBSR_SIZE(x) ((x) & 0x3fff) | |
149 | + | |
150 | +/* | |
151 | + * MAC control register | |
152 | + */ | |
153 | +#define FTGMAC100_MACCR_TXDMA_EN (1 << 0) | |
154 | +#define FTGMAC100_MACCR_RXDMA_EN (1 << 1) | |
155 | +#define FTGMAC100_MACCR_TXMAC_EN (1 << 2) | |
156 | +#define FTGMAC100_MACCR_RXMAC_EN (1 << 3) | |
157 | +#define FTGMAC100_MACCR_RM_VLAN (1 << 4) | |
158 | +#define FTGMAC100_MACCR_HPTXR_EN (1 << 5) | |
159 | +#define FTGMAC100_MACCR_LOOP_EN (1 << 6) | |
160 | +#define FTGMAC100_MACCR_ENRX_IN_HALFTX (1 << 7) | |
161 | +#define FTGMAC100_MACCR_FULLDUP (1 << 8) | |
162 | +#define FTGMAC100_MACCR_GIGA_MODE (1 << 9) | |
163 | +#define FTGMAC100_MACCR_CRC_APD (1 << 10) | |
164 | +#define FTGMAC100_MACCR_RX_RUNT (1 << 12) | |
165 | +#define FTGMAC100_MACCR_JUMBO_LF (1 << 13) | |
166 | +#define FTGMAC100_MACCR_RX_ALL (1 << 14) | |
167 | +#define FTGMAC100_MACCR_HT_MULTI_EN (1 << 15) | |
168 | +#define FTGMAC100_MACCR_RX_MULTIPKT (1 << 16) | |
169 | +#define FTGMAC100_MACCR_RX_BROADPKT (1 << 17) | |
170 | +#define FTGMAC100_MACCR_DISCARD_CRCERR (1 << 18) | |
171 | +#define FTGMAC100_MACCR_FAST_MODE (1 << 19) | |
172 | +#define FTGMAC100_MACCR_SW_RST (1 << 31) | |
173 | + | |
174 | +/* | |
175 | + * PHY control register | |
176 | + */ | |
177 | +#define FTGMAC100_PHYCR_MDC_CYCTHR_MASK 0x3f | |
178 | +#define FTGMAC100_PHYCR_MDC_CYCTHR(x) ((x) & 0x3f) | |
179 | +#define FTGMAC100_PHYCR_PHYAD(x) (((x) & 0x1f) << 16) | |
180 | +#define FTGMAC100_PHYCR_REGAD(x) (((x) & 0x1f) << 21) | |
181 | +#define FTGMAC100_PHYCR_MIIRD (1 << 26) | |
182 | +#define FTGMAC100_PHYCR_MIIWR (1 << 27) | |
183 | + | |
184 | +/* | |
185 | + * PHY data register | |
186 | + */ | |
187 | +#define FTGMAC100_PHYDATA_MIIWDATA(x) ((x) & 0xffff) | |
188 | +#define FTGMAC100_PHYDATA_MIIRDATA(phydata) (((phydata) >> 16) & 0xffff) | |
189 | + | |
190 | +/* | |
191 | + * Transmit descriptor, aligned to 16 bytes | |
192 | + */ | |
193 | +struct ftgmac100_txdes { | |
194 | + unsigned int txdes0; | |
195 | + unsigned int txdes1; | |
196 | + unsigned int txdes2; /* not used by HW */ | |
197 | + unsigned int txdes3; /* TXBUF_BADR */ | |
198 | +} __attribute__ ((aligned(16))); | |
199 | + | |
200 | +#define FTGMAC100_TXDES0_TXBUF_SIZE(x) ((x) & 0x3fff) | |
201 | +#define FTGMAC100_TXDES0_EDOTR (1 << 15) | |
202 | +#define FTGMAC100_TXDES0_CRC_ERR (1 << 19) | |
203 | +#define FTGMAC100_TXDES0_LTS (1 << 28) | |
204 | +#define FTGMAC100_TXDES0_FTS (1 << 29) | |
205 | +#define FTGMAC100_TXDES0_TXDMA_OWN (1 << 31) | |
206 | + | |
207 | +#define FTGMAC100_TXDES1_VLANTAG_CI(x) ((x) & 0xffff) | |
208 | +#define FTGMAC100_TXDES1_INS_VLANTAG (1 << 16) | |
209 | +#define FTGMAC100_TXDES1_TCP_CHKSUM (1 << 17) | |
210 | +#define FTGMAC100_TXDES1_UDP_CHKSUM (1 << 18) | |
211 | +#define FTGMAC100_TXDES1_IP_CHKSUM (1 << 19) | |
212 | +#define FTGMAC100_TXDES1_LLC (1 << 22) | |
213 | +#define FTGMAC100_TXDES1_TX2FIC (1 << 30) | |
214 | +#define FTGMAC100_TXDES1_TXIC (1 << 31) | |
215 | + | |
216 | +/* | |
217 | + * Receive descriptor, aligned to 16 bytes | |
218 | + */ | |
219 | +struct ftgmac100_rxdes { | |
220 | + unsigned int rxdes0; | |
221 | + unsigned int rxdes1; | |
222 | + unsigned int rxdes2; /* not used by HW */ | |
223 | + unsigned int rxdes3; /* RXBUF_BADR */ | |
224 | +} __attribute__ ((aligned(16))); | |
225 | + | |
226 | +#define FTGMAC100_RXDES0_VDBC(x) ((x) & 0x3fff) | |
227 | +#define FTGMAC100_RXDES0_EDORR (1 << 15) | |
228 | +#define FTGMAC100_RXDES0_MULTICAST (1 << 16) | |
229 | +#define FTGMAC100_RXDES0_BROADCAST (1 << 17) | |
230 | +#define FTGMAC100_RXDES0_RX_ERR (1 << 18) | |
231 | +#define FTGMAC100_RXDES0_CRC_ERR (1 << 19) | |
232 | +#define FTGMAC100_RXDES0_FTL (1 << 20) | |
233 | +#define FTGMAC100_RXDES0_RUNT (1 << 21) | |
234 | +#define FTGMAC100_RXDES0_RX_ODD_NB (1 << 22) | |
235 | +#define FTGMAC100_RXDES0_FIFO_FULL (1 << 23) | |
236 | +#define FTGMAC100_RXDES0_PAUSE_OPCODE (1 << 24) | |
237 | +#define FTGMAC100_RXDES0_PAUSE_FRAME (1 << 25) | |
238 | +#define FTGMAC100_RXDES0_LRS (1 << 28) | |
239 | +#define FTGMAC100_RXDES0_FRS (1 << 29) | |
240 | +#define FTGMAC100_RXDES0_RXPKT_RDY (1 << 31) | |
241 | + | |
242 | +#define FTGMAC100_RXDES1_VLANTAG_CI 0xffff | |
243 | +#define FTGMAC100_RXDES1_PROT_MASK (0x3 << 20) | |
244 | +#define FTGMAC100_RXDES1_PROT_NONIP (0x0 << 20) | |
245 | +#define FTGMAC100_RXDES1_PROT_IP (0x1 << 20) | |
246 | +#define FTGMAC100_RXDES1_PROT_TCPIP (0x2 << 20) | |
247 | +#define FTGMAC100_RXDES1_PROT_UDPIP (0x3 << 20) | |
248 | +#define FTGMAC100_RXDES1_LLC (1 << 22) | |
249 | +#define FTGMAC100_RXDES1_DF (1 << 23) | |
250 | +#define FTGMAC100_RXDES1_VLANTAG_AVAIL (1 << 24) | |
251 | +#define FTGMAC100_RXDES1_TCP_CHKSUM_ERR (1 << 25) | |
252 | +#define FTGMAC100_RXDES1_UDP_CHKSUM_ERR (1 << 26) | |
253 | +#define FTGMAC100_RXDES1_IP_CHKSUM_ERR (1 << 27) | |
254 | + | |
255 | +#endif /* __FTGMAC100_H */ |
include/netdev.h
... | ... | @@ -61,6 +61,7 @@ |
61 | 61 | int eth_3com_initialize (bd_t * bis); |
62 | 62 | int fec_initialize (bd_t *bis); |
63 | 63 | int fecmxc_initialize (bd_t *bis); |
64 | +int ftgmac100_initialize(bd_t *bits); | |
64 | 65 | int ftmac100_initialize(bd_t *bits); |
65 | 66 | int greth_initialize(bd_t *bis); |
66 | 67 | void gt6426x_eth_initialize(bd_t *bis); |