blob: 6e788a06410c2f09b85bc761126d5e34edf118e5 [file] [log] [blame]
Louis Su8dcca362008-07-09 11:01:37 +08001/*
2 * ax88180: ASIX AX88180 Non-PCI Gigabit Ethernet u-boot driver
3 *
4 * This program is free software; you can distribute it and/or modify
5 * it under the terms of the GNU General Public License (Version 2) as
6 * published by the Free Software Foundation.
7 * This program is distributed in the hope it will be useful, but
8 * WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 * See the GNU General Public License for more details.
11 * You should have received a copy of the GNU General Public License
12 * along with this program; if not, write to the Free Software
13 * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
14 * USA.
15 */
16
17/*
18 * ========================================================================
19 * ASIX AX88180 Non-PCI 16/32-bit Gigabit Ethernet Linux Driver
20 *
21 * The AX88180 Ethernet controller is a high performance and highly
22 * integrated local CPU bus Ethernet controller with embedded 40K bytes
23 * SRAM and supports both 16-bit and 32-bit SRAM-Like interfaces for any
24 * embedded systems.
25 * The AX88180 is a single chip 10/100/1000Mbps Gigabit Ethernet
26 * controller that supports both MII and RGMII interfaces and is
27 * compliant to IEEE 802.3, IEEE 802.3u and IEEE 802.3z standards.
28 *
29 * Please visit ASIX's web site (http://www.asix.com.tw) for more
30 * details.
31 *
32 * Module Name : ax88180.c
33 * Date : 2008-07-07
34 * History
35 * 09/06/2006 : New release for AX88180 US2 chip.
36 * 07/07/2008 : Fix up the coding style and using inline functions
37 * instead of macros
38 * ========================================================================
39 */
40#include <common.h>
41#include <command.h>
42#include <net.h>
43#include <malloc.h>
44#include "ax88180.h"
45
46/*
47 * ===========================================================================
48 * Local SubProgram Declaration
49 * ===========================================================================
50 */
51static void ax88180_rx_handler (struct eth_device *dev);
52static int ax88180_phy_initial (struct eth_device *dev);
Hoan Hoang0b8c3552010-05-10 16:09:35 -040053static void ax88180_media_config (struct eth_device *dev);
54static unsigned long get_CicadaPHY_media_mode (struct eth_device *dev);
55static unsigned long get_MarvellPHY_media_mode (struct eth_device *dev);
Louis Su8dcca362008-07-09 11:01:37 +080056static unsigned short ax88180_mdio_read (struct eth_device *dev,
57 unsigned long regaddr);
58static void ax88180_mdio_write (struct eth_device *dev,
59 unsigned long regaddr, unsigned short regdata);
60
61/*
62 * ===========================================================================
63 * Local SubProgram Bodies
64 * ===========================================================================
65 */
66static int ax88180_mdio_check_complete (struct eth_device *dev)
67{
68 int us_cnt = 10000;
69 unsigned short tmpval;
70
71 /* MDIO read/write should not take more than 10 ms */
72 while (--us_cnt) {
73 tmpval = INW (dev, MDIOCTRL);
74 if (((tmpval & READ_PHY) == 0) && ((tmpval & WRITE_PHY) == 0))
75 break;
76 }
77
78 return us_cnt;
79}
80
81static unsigned short
82ax88180_mdio_read (struct eth_device *dev, unsigned long regaddr)
83{
84 struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
85 unsigned long tmpval = 0;
86
87 OUTW (dev, (READ_PHY | (regaddr << 8) | priv->PhyAddr), MDIOCTRL);
88
89 if (ax88180_mdio_check_complete (dev))
90 tmpval = INW (dev, MDIODP);
91 else
92 printf ("Failed to read PHY register!\n");
93
94 return (unsigned short)(tmpval & 0xFFFF);
95}
96
97static void
98ax88180_mdio_write (struct eth_device *dev, unsigned long regaddr,
99 unsigned short regdata)
100{
101 struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
102
103 OUTW (dev, regdata, MDIODP);
104
105 OUTW (dev, (WRITE_PHY | (regaddr << 8) | priv->PhyAddr), MDIOCTRL);
106
107 if (!ax88180_mdio_check_complete (dev))
108 printf ("Failed to write PHY register!\n");
109}
110
111static int ax88180_phy_reset (struct eth_device *dev)
112{
113 unsigned short delay_cnt = 500;
114
115 ax88180_mdio_write (dev, BMCR, (PHY_RESET | AUTONEG_EN));
116
117 /* Wait for the reset to complete, or time out (500 ms) */
118 while (ax88180_mdio_read (dev, BMCR) & PHY_RESET) {
119 udelay (1000);
120 if (--delay_cnt == 0) {
121 printf ("Failed to reset PHY!\n");
122 return -1;
123 }
124 }
125
126 return 0;
127}
128
129static void ax88180_mac_reset (struct eth_device *dev)
130{
131 unsigned long tmpval;
132 unsigned char i;
133
134 struct {
135 unsigned short offset, value;
136 } program_seq[] = {
137 {
138 MISC, MISC_NORMAL}, {
139 RXINDICATOR, DEFAULT_RXINDICATOR}, {
140 TXCMD, DEFAULT_TXCMD}, {
141 TXBS, DEFAULT_TXBS}, {
142 TXDES0, DEFAULT_TXDES0}, {
143 TXDES1, DEFAULT_TXDES1}, {
144 TXDES2, DEFAULT_TXDES2}, {
145 TXDES3, DEFAULT_TXDES3}, {
146 TXCFG, DEFAULT_TXCFG}, {
147 MACCFG2, DEFAULT_MACCFG2}, {
148 MACCFG3, DEFAULT_MACCFG3}, {
149 TXLEN, DEFAULT_TXLEN}, {
150 RXBTHD0, DEFAULT_RXBTHD0}, {
151 RXBTHD1, DEFAULT_RXBTHD1}, {
152 RXFULTHD, DEFAULT_RXFULTHD}, {
153 DOGTHD0, DEFAULT_DOGTHD0}, {
154 DOGTHD1, DEFAULT_DOGTHD1},};
155
156 OUTW (dev, MISC_RESET_MAC, MISC);
157 tmpval = INW (dev, MISC);
158
159 for (i = 0; i < (sizeof (program_seq) / sizeof (program_seq[0])); i++)
160 OUTW (dev, program_seq[i].value, program_seq[i].offset);
161}
162
163static int ax88180_poll_tx_complete (struct eth_device *dev)
164{
165 struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
166 unsigned long tmpval, txbs_txdp;
167 int TimeOutCnt = 10000;
168
169 txbs_txdp = 1 << priv->NextTxDesc;
170
171 while (TimeOutCnt--) {
172
173 tmpval = INW (dev, TXBS);
174
175 if ((tmpval & txbs_txdp) == 0)
176 break;
177
178 udelay (100);
179 }
180
181 if (TimeOutCnt)
182 return 0;
183 else
184 return -TimeOutCnt;
185}
186
187static void ax88180_rx_handler (struct eth_device *dev)
188{
189 struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
190 unsigned long data_size;
191 unsigned short rxcurt_ptr, rxbound_ptr, next_ptr;
192 int i;
193#if defined (CONFIG_DRIVER_AX88180_16BIT)
194 unsigned short *rxdata = (unsigned short *)NetRxPackets[0];
195#else
196 unsigned long *rxdata = (unsigned long *)NetRxPackets[0];
197#endif
198 unsigned short count;
199
200 rxcurt_ptr = INW (dev, RXCURT);
201 rxbound_ptr = INW (dev, RXBOUND);
202 next_ptr = (rxbound_ptr + 1) & RX_PAGE_NUM_MASK;
203
204 debug ("ax88180: RX original RXBOUND=0x%04x,"
205 " RXCURT=0x%04x\n", rxbound_ptr, rxcurt_ptr);
206
207 while (next_ptr != rxcurt_ptr) {
208
209 OUTW (dev, RX_START_READ, RXINDICATOR);
210
211 data_size = READ_RXBUF (dev) & 0xFFFF;
212
213 if ((data_size == 0) || (data_size > MAX_RX_SIZE)) {
214
215 OUTW (dev, RX_STOP_READ, RXINDICATOR);
216
217 ax88180_mac_reset (dev);
218 printf ("ax88180: Invalid Rx packet length!"
219 " (len=0x%04lx)\n", data_size);
220
221 debug ("ax88180: RX RXBOUND=0x%04x,"
222 "RXCURT=0x%04x\n", rxbound_ptr, rxcurt_ptr);
223 return;
224 }
225
226 rxbound_ptr += (((data_size + 0xF) & 0xFFF0) >> 4) + 1;
227 rxbound_ptr &= RX_PAGE_NUM_MASK;
228
229 /* Comput access times */
230 count = (data_size + priv->PadSize) >> priv->BusWidth;
231
232 for (i = 0; i < count; i++) {
233 *(rxdata + i) = READ_RXBUF (dev);
234 }
235
236 OUTW (dev, RX_STOP_READ, RXINDICATOR);
237
238 /* Pass the packet up to the protocol layers. */
239 NetReceive (NetRxPackets[0], data_size);
240
241 OUTW (dev, rxbound_ptr, RXBOUND);
242
243 rxcurt_ptr = INW (dev, RXCURT);
244 rxbound_ptr = INW (dev, RXBOUND);
245 next_ptr = (rxbound_ptr + 1) & RX_PAGE_NUM_MASK;
246
247 debug ("ax88180: RX updated RXBOUND=0x%04x,"
248 "RXCURT=0x%04x\n", rxbound_ptr, rxcurt_ptr);
249 }
250
251 return;
252}
253
254static int ax88180_phy_initial (struct eth_device *dev)
255{
256 struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
257 unsigned long tmp_regval;
Mike Frysinger762c9322010-05-10 16:10:00 -0400258 unsigned short phyaddr;
Louis Su8dcca362008-07-09 11:01:37 +0800259
Mike Frysinger762c9322010-05-10 16:10:00 -0400260 /* Search for first avaliable PHY chipset */
261#ifdef CONFIG_PHY_ADDR
262 phyaddr = CONFIG_PHY_ADDR;
263#else
264 for (phyaddr = 0; phyaddr < 32; ++phyaddr)
265#endif
266 {
267 priv->PhyAddr = phyaddr;
268 priv->PhyID0 = ax88180_mdio_read(dev, PHYIDR0);
Louis Su8dcca362008-07-09 11:01:37 +0800269
Mike Frysinger762c9322010-05-10 16:10:00 -0400270 switch (priv->PhyID0) {
271 case MARVELL_88E1111_PHYIDR0:
272 debug("ax88180: Found Marvell 88E1111 PHY."
273 " (PHY Addr=0x%x)\n", priv->PhyAddr);
Louis Su8dcca362008-07-09 11:01:37 +0800274
Mike Frysinger762c9322010-05-10 16:10:00 -0400275 tmp_regval = ax88180_mdio_read(dev, M88_EXT_SSR);
276 if ((tmp_regval & HWCFG_MODE_MASK) != RGMII_COPPER_MODE) {
277 ax88180_mdio_write(dev, M88_EXT_SCR, DEFAULT_EXT_SCR);
278 if (ax88180_phy_reset(dev) < 0)
279 return 0;
280 ax88180_mdio_write(dev, M88_IER, LINK_CHANGE_INT);
281 }
Louis Su8dcca362008-07-09 11:01:37 +0800282
Mike Frysinger762c9322010-05-10 16:10:00 -0400283 return 1;
Louis Su8dcca362008-07-09 11:01:37 +0800284
Mike Frysinger762c9322010-05-10 16:10:00 -0400285 case CICADA_CIS8201_PHYIDR0:
286 debug("ax88180: Found CICADA CIS8201 PHY"
287 " chipset. (PHY Addr=0x%x)\n", priv->PhyAddr);
Louis Su8dcca362008-07-09 11:01:37 +0800288
Mike Frysinger762c9322010-05-10 16:10:00 -0400289 ax88180_mdio_write(dev, CIS_IMR,
Louis Su8dcca362008-07-09 11:01:37 +0800290 (CIS_INT_ENABLE | LINK_CHANGE_INT));
291
292 /* Set CIS_SMI_PRIORITY bit before force the media mode */
Mike Frysinger762c9322010-05-10 16:10:00 -0400293 tmp_regval = ax88180_mdio_read(dev, CIS_AUX_CTRL_STATUS);
Louis Su8dcca362008-07-09 11:01:37 +0800294 tmp_regval &= ~CIS_SMI_PRIORITY;
Mike Frysinger762c9322010-05-10 16:10:00 -0400295 ax88180_mdio_write(dev, CIS_AUX_CTRL_STATUS, tmp_regval);
296
297 return 1;
298
299 case 0xffff:
300 /* No PHY at this addr */
301 break;
302
303 default:
304 printf("ax88180: Unknown PHY chipset %#x at addr %#x\n",
305 priv->PhyID0, priv->PhyAddr);
306 break;
Louis Su8dcca362008-07-09 11:01:37 +0800307 }
308 }
309
Mike Frysinger762c9322010-05-10 16:10:00 -0400310 printf("ax88180: Unknown PHY chipset!!\n");
311 return 0;
Louis Su8dcca362008-07-09 11:01:37 +0800312}
313
Hoan Hoang0b8c3552010-05-10 16:09:35 -0400314static void ax88180_media_config (struct eth_device *dev)
Louis Su8dcca362008-07-09 11:01:37 +0800315{
316 struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
317 unsigned long bmcr_val, bmsr_val;
318 unsigned long rxcfg_val, maccfg0_val, maccfg1_val;
319 unsigned long RealMediaMode;
320 int i;
321
322 /* Waiting 2 seconds for PHY link stable */
323 for (i = 0; i < 20000; i++) {
324 bmsr_val = ax88180_mdio_read (dev, BMSR);
325 if (bmsr_val & LINKOK) {
326 break;
327 }
328 udelay (100);
329 }
330
331 bmsr_val = ax88180_mdio_read (dev, BMSR);
332 debug ("ax88180: BMSR=0x%04x\n", (unsigned int)bmsr_val);
333
334 if (bmsr_val & LINKOK) {
335 bmcr_val = ax88180_mdio_read (dev, BMCR);
336
337 if (bmcr_val & AUTONEG_EN) {
338
339 /*
340 * Waiting for Auto-negotiation completion, this may
341 * take up to 5 seconds.
342 */
343 debug ("ax88180: Auto-negotiation is "
344 "enabled. Waiting for NWay completion..\n");
345 for (i = 0; i < 50000; i++) {
346 bmsr_val = ax88180_mdio_read (dev, BMSR);
347 if (bmsr_val & AUTONEG_COMPLETE) {
348 break;
349 }
350 udelay (100);
351 }
352 } else
353 debug ("ax88180: Auto-negotiation is disabled.\n");
354
355 debug ("ax88180: BMCR=0x%04x, BMSR=0x%04x\n",
356 (unsigned int)bmcr_val, (unsigned int)bmsr_val);
357
358 /* Get real media mode here */
Mike Frysinger762c9322010-05-10 16:10:00 -0400359 switch (priv->PhyID0) {
360 case MARVELL_88E1111_PHYIDR0:
361 RealMediaMode = get_MarvellPHY_media_mode(dev);
362 break;
363 case CICADA_CIS8201_PHYIDR0:
364 RealMediaMode = get_CicadaPHY_media_mode(dev);
365 break;
366 default:
Louis Su8dcca362008-07-09 11:01:37 +0800367 RealMediaMode = MEDIA_1000FULL;
Mike Frysinger762c9322010-05-10 16:10:00 -0400368 break;
Louis Su8dcca362008-07-09 11:01:37 +0800369 }
370
371 priv->LinkState = INS_LINK_UP;
372
373 switch (RealMediaMode) {
374 case MEDIA_1000FULL:
375 debug ("ax88180: 1000Mbps Full-duplex mode.\n");
376 rxcfg_val = RXFLOW_ENABLE | DEFAULT_RXCFG;
377 maccfg0_val = TXFLOW_ENABLE | DEFAULT_MACCFG0;
378 maccfg1_val = GIGA_MODE_EN | RXFLOW_EN |
379 FULLDUPLEX | DEFAULT_MACCFG1;
380 break;
381
382 case MEDIA_1000HALF:
383 debug ("ax88180: 1000Mbps Half-duplex mode.\n");
384 rxcfg_val = DEFAULT_RXCFG;
385 maccfg0_val = DEFAULT_MACCFG0;
386 maccfg1_val = GIGA_MODE_EN | DEFAULT_MACCFG1;
387 break;
388
389 case MEDIA_100FULL:
390 debug ("ax88180: 100Mbps Full-duplex mode.\n");
391 rxcfg_val = RXFLOW_ENABLE | DEFAULT_RXCFG;
392 maccfg0_val = SPEED100 | TXFLOW_ENABLE
393 | DEFAULT_MACCFG0;
394 maccfg1_val = RXFLOW_EN | FULLDUPLEX | DEFAULT_MACCFG1;
395 break;
396
397 case MEDIA_100HALF:
398 debug ("ax88180: 100Mbps Half-duplex mode.\n");
399 rxcfg_val = DEFAULT_RXCFG;
400 maccfg0_val = SPEED100 | DEFAULT_MACCFG0;
401 maccfg1_val = DEFAULT_MACCFG1;
402 break;
403
404 case MEDIA_10FULL:
405 debug ("ax88180: 10Mbps Full-duplex mode.\n");
406 rxcfg_val = RXFLOW_ENABLE | DEFAULT_RXCFG;
407 maccfg0_val = TXFLOW_ENABLE | DEFAULT_MACCFG0;
408 maccfg1_val = RXFLOW_EN | FULLDUPLEX | DEFAULT_MACCFG1;
409 break;
410
411 case MEDIA_10HALF:
412 debug ("ax88180: 10Mbps Half-duplex mode.\n");
413 rxcfg_val = DEFAULT_RXCFG;
414 maccfg0_val = DEFAULT_MACCFG0;
415 maccfg1_val = DEFAULT_MACCFG1;
416 break;
417 default:
418 debug ("ax88180: Unknow media mode.\n");
419 rxcfg_val = DEFAULT_RXCFG;
420 maccfg0_val = DEFAULT_MACCFG0;
421 maccfg1_val = DEFAULT_MACCFG1;
422
423 priv->LinkState = INS_LINK_DOWN;
424 break;
425 }
426
427 } else {
428 rxcfg_val = DEFAULT_RXCFG;
429 maccfg0_val = DEFAULT_MACCFG0;
430 maccfg1_val = DEFAULT_MACCFG1;
431
432 priv->LinkState = INS_LINK_DOWN;
433 }
434
435 OUTW (dev, rxcfg_val, RXCFG);
436 OUTW (dev, maccfg0_val, MACCFG0);
437 OUTW (dev, maccfg1_val, MACCFG1);
438
439 return;
440}
441
Hoan Hoang0b8c3552010-05-10 16:09:35 -0400442static unsigned long get_MarvellPHY_media_mode (struct eth_device *dev)
Louis Su8dcca362008-07-09 11:01:37 +0800443{
444 unsigned long m88_ssr;
445 unsigned long MediaMode;
446
447 m88_ssr = ax88180_mdio_read (dev, M88_SSR);
448 switch (m88_ssr & SSR_MEDIA_MASK) {
449 case SSR_1000FULL:
450 MediaMode = MEDIA_1000FULL;
451 break;
452 case SSR_1000HALF:
453 MediaMode = MEDIA_1000HALF;
454 break;
455 case SSR_100FULL:
456 MediaMode = MEDIA_100FULL;
457 break;
458 case SSR_100HALF:
459 MediaMode = MEDIA_100HALF;
460 break;
461 case SSR_10FULL:
462 MediaMode = MEDIA_10FULL;
463 break;
464 case SSR_10HALF:
465 MediaMode = MEDIA_10HALF;
466 break;
467 default:
468 MediaMode = MEDIA_UNKNOWN;
469 break;
470 }
471
472 return MediaMode;
473}
474
Hoan Hoang0b8c3552010-05-10 16:09:35 -0400475static unsigned long get_CicadaPHY_media_mode (struct eth_device *dev)
Louis Su8dcca362008-07-09 11:01:37 +0800476{
477 unsigned long tmp_regval;
478 unsigned long MediaMode;
479
480 tmp_regval = ax88180_mdio_read (dev, CIS_AUX_CTRL_STATUS);
481 switch (tmp_regval & CIS_MEDIA_MASK) {
482 case CIS_1000FULL:
483 MediaMode = MEDIA_1000FULL;
484 break;
485 case CIS_1000HALF:
486 MediaMode = MEDIA_1000HALF;
487 break;
488 case CIS_100FULL:
489 MediaMode = MEDIA_100FULL;
490 break;
491 case CIS_100HALF:
492 MediaMode = MEDIA_100HALF;
493 break;
494 case CIS_10FULL:
495 MediaMode = MEDIA_10FULL;
496 break;
497 case CIS_10HALF:
498 MediaMode = MEDIA_10HALF;
499 break;
500 default:
501 MediaMode = MEDIA_UNKNOWN;
502 break;
503 }
504
505 return MediaMode;
506}
507
508static void ax88180_halt (struct eth_device *dev)
509{
510 /* Disable AX88180 TX/RX functions */
511 OUTW (dev, WAKEMOD, CMD);
512}
513
514static int ax88180_init (struct eth_device *dev, bd_t * bd)
515{
516 struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
517 unsigned short tmp_regval;
518
519 ax88180_mac_reset (dev);
520
521 /* Disable interrupt */
522 OUTW (dev, CLEAR_IMR, IMR);
523
524 /* Disable AX88180 TX/RX functions */
525 OUTW (dev, WAKEMOD, CMD);
526
527 /* Fill the MAC address */
528 tmp_regval =
529 dev->enetaddr[0] | (((unsigned short)dev->enetaddr[1]) << 8);
530 OUTW (dev, tmp_regval, MACID0);
531
532 tmp_regval =
533 dev->enetaddr[2] | (((unsigned short)dev->enetaddr[3]) << 8);
534 OUTW (dev, tmp_regval, MACID1);
535
536 tmp_regval =
537 dev->enetaddr[4] | (((unsigned short)dev->enetaddr[5]) << 8);
538 OUTW (dev, tmp_regval, MACID2);
539
Hoan Hoang0b8c3552010-05-10 16:09:35 -0400540 ax88180_media_config (dev);
Louis Su8dcca362008-07-09 11:01:37 +0800541
542 OUTW (dev, DEFAULT_RXFILTER, RXFILTER);
543
544 /* Initial variables here */
545 priv->FirstTxDesc = TXDP0;
546 priv->NextTxDesc = TXDP0;
547
548 /* Check if there is any invalid interrupt status and clear it. */
549 OUTW (dev, INW (dev, ISR), ISR);
550
551 /* Start AX88180 TX/RX functions */
552 OUTW (dev, (RXEN | TXEN | WAKEMOD), CMD);
553
554 return 0;
555}
556
557/* Get a data block via Ethernet */
558static int ax88180_recv (struct eth_device *dev)
559{
560 unsigned short ISR_Status;
561 unsigned short tmp_regval;
562
563 /* Read and check interrupt status here. */
564 ISR_Status = INW (dev, ISR);
565
566 while (ISR_Status) {
567 /* Clear the interrupt status */
568 OUTW (dev, ISR_Status, ISR);
569
570 debug ("\nax88180: The interrupt status = 0x%04x\n",
571 ISR_Status);
572
573 if (ISR_Status & ISR_PHY) {
574 /* Read ISR register once to clear PHY interrupt bit */
575 tmp_regval = ax88180_mdio_read (dev, M88_ISR);
Hoan Hoang0b8c3552010-05-10 16:09:35 -0400576 ax88180_media_config (dev);
Louis Su8dcca362008-07-09 11:01:37 +0800577 }
578
579 if ((ISR_Status & ISR_RX) || (ISR_Status & ISR_RXBUFFOVR)) {
580 ax88180_rx_handler (dev);
581 }
582
583 /* Read and check interrupt status again */
584 ISR_Status = INW (dev, ISR);
585 }
586
587 return 0;
588}
589
590/* Send a data block via Ethernet. */
591static int
592ax88180_send (struct eth_device *dev, volatile void *packet, int length)
593{
594 struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
595 unsigned short TXDES_addr;
596 unsigned short txcmd_txdp, txbs_txdp;
597 unsigned short tmp_data;
598 int i;
599#if defined (CONFIG_DRIVER_AX88180_16BIT)
600 volatile unsigned short *txdata = (volatile unsigned short *)packet;
601#else
602 volatile unsigned long *txdata = (volatile unsigned long *)packet;
603#endif
604 unsigned short count;
605
606 if (priv->LinkState != INS_LINK_UP) {
607 return 0;
608 }
609
610 priv->FirstTxDesc = priv->NextTxDesc;
611 txbs_txdp = 1 << priv->FirstTxDesc;
612
613 debug ("ax88180: TXDP%d is available\n", priv->FirstTxDesc);
614
615 txcmd_txdp = priv->FirstTxDesc << 13;
616 TXDES_addr = TXDES0 + (priv->FirstTxDesc << 2);
617
618 OUTW (dev, (txcmd_txdp | length | TX_START_WRITE), TXCMD);
619
620 /* Comput access times */
621 count = (length + priv->PadSize) >> priv->BusWidth;
622
623 for (i = 0; i < count; i++) {
624 WRITE_TXBUF (dev, *(txdata + i));
625 }
626
627 OUTW (dev, txcmd_txdp | length, TXCMD);
628 OUTW (dev, txbs_txdp, TXBS);
629 OUTW (dev, (TXDPx_ENABLE | length), TXDES_addr);
630
631 priv->NextTxDesc = (priv->NextTxDesc + 1) & TXDP_MASK;
632
633 /*
634 * Check the available transmit descriptor, if we had exhausted all
635 * transmit descriptor ,then we have to wait for at least one free
636 * descriptor
637 */
638 txbs_txdp = 1 << priv->NextTxDesc;
639 tmp_data = INW (dev, TXBS);
640
641 if (tmp_data & txbs_txdp) {
642 if (ax88180_poll_tx_complete (dev) < 0) {
643 ax88180_mac_reset (dev);
644 priv->FirstTxDesc = TXDP0;
645 priv->NextTxDesc = TXDP0;
646 printf ("ax88180: Transmit time out occurred!\n");
647 }
648 }
649
650 return 0;
651}
652
653static void ax88180_read_mac_addr (struct eth_device *dev)
654{
655 unsigned short macid0_val, macid1_val, macid2_val;
656 unsigned short tmp_regval;
657 unsigned short i;
658
659 /* Reload MAC address from EEPROM */
660 OUTW (dev, RELOAD_EEPROM, PROMCTRL);
661
662 /* Waiting for reload eeprom completion */
663 for (i = 0; i < 500; i++) {
664 tmp_regval = INW (dev, PROMCTRL);
665 if ((tmp_regval & RELOAD_EEPROM) == 0)
666 break;
667 udelay (1000);
668 }
669
670 /* Get MAC addresses */
671 macid0_val = INW (dev, MACID0);
672 macid1_val = INW (dev, MACID1);
673 macid2_val = INW (dev, MACID2);
674
675 if (((macid0_val | macid1_val | macid2_val) != 0) &&
676 ((macid0_val & 0x01) == 0)) {
677 dev->enetaddr[0] = (unsigned char)macid0_val;
678 dev->enetaddr[1] = (unsigned char)(macid0_val >> 8);
679 dev->enetaddr[2] = (unsigned char)macid1_val;
680 dev->enetaddr[3] = (unsigned char)(macid1_val >> 8);
681 dev->enetaddr[4] = (unsigned char)macid2_val;
682 dev->enetaddr[5] = (unsigned char)(macid2_val >> 8);
683 }
684}
685
686/*
687===========================================================================
688<<<<<< Exported SubProgram Bodies >>>>>>
689===========================================================================
690*/
691int ax88180_initialize (bd_t * bis)
692{
693 struct eth_device *dev;
694 struct ax88180_private *priv;
695
696 dev = (struct eth_device *)malloc (sizeof *dev);
697
698 if (NULL == dev)
699 return 0;
700
701 memset (dev, 0, sizeof *dev);
702
703 priv = (struct ax88180_private *)malloc (sizeof (*priv));
704
705 if (NULL == priv)
706 return 0;
707
708 memset (priv, 0, sizeof *priv);
709
710 sprintf (dev->name, "ax88180");
711 dev->iobase = AX88180_BASE;
712 dev->priv = priv;
713 dev->init = ax88180_init;
714 dev->halt = ax88180_halt;
715 dev->send = ax88180_send;
716 dev->recv = ax88180_recv;
717
718 priv->BusWidth = BUS_WIDTH_32;
719 priv->PadSize = 3;
720#if defined (CONFIG_DRIVER_AX88180_16BIT)
721 OUTW (dev, (START_BASE >> 8), BASE);
722 OUTW (dev, DECODE_EN, DECODE);
723
724 priv->BusWidth = BUS_WIDTH_16;
725 priv->PadSize = 1;
726#endif
727
728 ax88180_mac_reset (dev);
729
730 /* Disable interrupt */
731 OUTW (dev, CLEAR_IMR, IMR);
732
733 /* Disable AX88180 TX/RX functions */
734 OUTW (dev, WAKEMOD, CMD);
735
736 ax88180_read_mac_addr (dev);
737
738 eth_register (dev);
739
740 return ax88180_phy_initial (dev);
741
742}