1 /***********************************************************************
3 * Copyright (C) 2005 by Videon Central, Inc.
6 * @Author: Arthur Shipkowski
7 * @Descr: Ethernet driver for the NS7520. Uses polled Ethernet, like
8 * the older netarmeth driver. Note that attempting to filter
9 * broadcast and multicast out in the SAFR register will cause
10 * bad things due to released errata.
11 * @References: [1] NS7520 Hardware Reference, December 2003
12 * [2] Intel LXT971 Datasheet #249414 Rev. 02
14 ***********************************************************************/
18 #if defined(CONFIG_DRIVER_NS7520_ETHERNET)
20 #include <net.h> /* NetSendPacket */
21 #include <asm/arch/netarm_registers.h>
22 #include <asm/arch/netarm_dma_module.h>
24 #include "ns7520_eth.h" /* for Ethernet and PHY */
27 * Send an error message to the terminal.
31 char *__foo = strrchr(__FILE__, '/'); \
33 printf("%s: %d: %s(): ", (__foo == NULL ? __FILE__ : (__foo + 1)), \
34 __LINE__, __FUNCTION__); \
35 printf x; printf("\n"); \
38 /* some definition to make transistion to linux easier */
40 #define NS7520_DRIVER_NAME "eth"
41 #define KERN_WARNING "Warning:"
42 #define KERN_ERR "Error:"
43 #define KERN_INFO "Info:"
50 # define printk printf
52 # define DEBUG_INIT 0x0001
53 # define DEBUG_MINOR 0x0002
54 # define DEBUG_RX 0x0004
55 # define DEBUG_TX 0x0008
56 # define DEBUG_INT 0x0010
57 # define DEBUG_POLL 0x0020
58 # define DEBUG_LINK 0x0040
59 # define DEBUG_MII 0x0100
60 # define DEBUG_MII_LOW 0x0200
61 # define DEBUG_MEM 0x0400
62 # define DEBUG_ERROR 0x4000
63 # define DEBUG_ERROR_CRIT 0x8000
65 static int nDebugLvl = DEBUG_ERROR_CRIT;
67 # define DEBUG_ARGS0( FLG, a0 ) if( ( nDebugLvl & (FLG) ) == (FLG) ) \
68 printf("%s: " a0, __FUNCTION__, 0, 0, 0, 0, 0, 0 )
69 # define DEBUG_ARGS1( FLG, a0, a1 ) if( ( nDebugLvl & (FLG) ) == (FLG)) \
70 printf("%s: " a0, __FUNCTION__, (int)(a1), 0, 0, 0, 0, 0 )
71 # define DEBUG_ARGS2( FLG, a0, a1, a2 ) if( (nDebugLvl & (FLG)) ==(FLG))\
72 printf("%s: " a0, __FUNCTION__, (int)(a1), (int)(a2), 0, 0,0,0 )
73 # define DEBUG_ARGS3( FLG, a0, a1, a2, a3 ) if((nDebugLvl &(FLG))==(FLG))\
74 printf("%s: "a0,__FUNCTION__,(int)(a1),(int)(a2),(int)(a3),0,0,0)
75 # define DEBUG_FN( FLG ) if( (nDebugLvl & (FLG)) == (FLG) ) \
76 printf("\r%s:line %d\n", (int)__FUNCTION__, __LINE__, 0,0,0,0);
77 # define ASSERT( expr, func ) if( !( expr ) ) { \
78 printf( "Assertion failed! %s:line %d %s\n", \
79 (int)__FUNCTION__,__LINE__,(int)(#expr),0,0,0); \
83 # define DEBUG_ARGS0( FLG, a0 )
84 # define DEBUG_ARGS1( FLG, a0, a1 )
85 # define DEBUG_ARGS2( FLG, a0, a1, a2 )
86 # define DEBUG_ARGS3( FLG, a0, a1, a2, a3 )
87 # define DEBUG_FN( n )
88 # define ASSERT(expr, func)
91 #define NS7520_MII_NEG_DELAY (5*CFG_HZ) /* in s */
92 #define TX_TIMEOUT (5*CFG_HZ) /* in s */
93 #define RX_STALL_WORKAROUND_CNT 100
95 static int ns7520_eth_reset(void);
97 static void ns7520_link_auto_negotiate(void);
98 static void ns7520_link_update_egcr(void);
99 static void ns7520_link_print_changed(void);
103 static char ns7520_mii_identify_phy(void);
104 static unsigned short ns7520_mii_read(unsigned short uiRegister);
105 static void ns7520_mii_write(unsigned short uiRegister,
106 unsigned short uiData);
107 static unsigned int ns7520_mii_get_clock_divisor(unsigned int
109 static unsigned int ns7520_mii_poll_busy(void);
111 static unsigned int nPhyMaxMdioClock = PHY_MDIO_MAX_CLK;
112 static unsigned int uiLastLinkStatus;
113 static PhyType phyDetected = PHY_NONE;
115 /***********************************************************************
116 * @Function: eth_init
117 * @Return: -1 on failure otherwise 0
118 * @Descr: Initializes the ethernet engine and uses either FS Forth's default
119 * MAC addr or the one in environment
120 ***********************************************************************/
122 int eth_init(bd_t * pbis)
124 unsigned char aucMACAddr[6];
125 char *pcTmp = getenv("ethaddr");
129 DEBUG_FN(DEBUG_INIT);
131 /* no need to check for hardware */
133 if (!ns7520_eth_reset())
139 for (i = 0; i < 6; i++) {
141 pcTmp ? simple_strtoul(pcTmp, &pcEnd, 16) : 0;
142 pcTmp = (*pcTmp) ? pcEnd + 1 : pcEnd;
145 /* configure ethernet address */
147 *get_eth_reg_addr(NS7520_ETH_SA1) =
148 aucMACAddr[5] << 8 | aucMACAddr[4];
149 *get_eth_reg_addr(NS7520_ETH_SA2) =
150 aucMACAddr[3] << 8 | aucMACAddr[2];
151 *get_eth_reg_addr(NS7520_ETH_SA3) =
152 aucMACAddr[1] << 8 | aucMACAddr[0];
154 /* enable hardware */
156 *get_eth_reg_addr(NS7520_ETH_MAC1) = NS7520_ETH_MAC1_RXEN;
157 *get_eth_reg_addr(NS7520_ETH_SUPP) = NS7520_ETH_SUPP_JABBER;
158 *get_eth_reg_addr(NS7520_ETH_MAC1) = NS7520_ETH_MAC1_RXEN;
160 /* the linux kernel may give packets < 60 bytes, for example arp */
161 *get_eth_reg_addr(NS7520_ETH_MAC2) = NS7520_ETH_MAC2_CRCEN |
162 NS7520_ETH_MAC2_PADEN | NS7520_ETH_MAC2_HUGE;
164 /* Broadcast/multicast allowed; if you don't set this even unicast chokes */
165 /* Based on NS7520 errata documentation */
166 *get_eth_reg_addr(NS7520_ETH_SAFR) =
167 NS7520_ETH_SAFR_BROAD | NS7520_ETH_SAFR_PRM;
169 /* enable receive and transmit FIFO, use 10/100 Mbps MII */
170 *get_eth_reg_addr(NS7520_ETH_EGCR) |=
171 NS7520_ETH_EGCR_ETXWM_75 |
172 NS7520_ETH_EGCR_ERX |
173 NS7520_ETH_EGCR_ERXREG |
174 NS7520_ETH_EGCR_ERXBR | NS7520_ETH_EGCR_ETX;
179 /***********************************************************************
180 * @Function: eth_send
181 * @Return: -1 on timeout otherwise 1
182 * @Descr: sends one frame by DMA
183 ***********************************************************************/
185 int eth_send(volatile void *pPacket, int nLen)
187 int i, length32, retval = 1;
189 unsigned int *pa32, lastp = 0, rest;
192 pa = (char *) pPacket;
193 pa32 = (unsigned int *) pPacket;
197 /* make sure there's no garbage in the last word */
200 lastp = pa32[length32 - 1];
204 lastp = pa32[length32] & 0x000000ff;
207 lastp = pa32[length32] & 0x0000ffff;
210 lastp = pa32[length32] & 0x00ffffff;
214 while (((*get_eth_reg_addr(NS7520_ETH_EGSR)) &
215 NS7520_ETH_EGSR_TXREGE)
219 /* write to the fifo */
220 for (i = 0; i < length32; i++)
221 *get_eth_reg_addr(NS7520_ETH_FIFO) = pa32[i];
223 /* the last word is written to an extra register, this
224 starts the transmission */
225 *get_eth_reg_addr(NS7520_ETH_FIFOL) = lastp;
227 /* Wait for it to be done */
228 while ((*get_eth_reg_addr(NS7520_ETH_EGSR) & NS7520_ETH_EGSR_TXBC)
231 status = (*get_eth_reg_addr(NS7520_ETH_ETSR));
232 *get_eth_reg_addr(NS7520_ETH_EGSR) = NS7520_ETH_EGSR_TXBC; /* Clear it now */
234 if (status & NS7520_ETH_ETSR_TXOK) {
235 retval = 0; /* We're OK! */
236 } else if (status & NS7520_ETH_ETSR_TXDEF) {
237 printf("Deferred, we'll see.\n");
239 } else if (status & NS7520_ETH_ETSR_TXAL) {
240 printf("Late collision error, %d collisions.\n",
241 (*get_eth_reg_addr(NS7520_ETH_ETSR)) &
242 NS7520_ETH_ETSR_TXCOLC);
243 } else if (status & NS7520_ETH_ETSR_TXAEC) {
244 printf("Excessive collisions: %d\n",
245 (*get_eth_reg_addr(NS7520_ETH_ETSR)) &
246 NS7520_ETH_ETSR_TXCOLC);
247 } else if (status & NS7520_ETH_ETSR_TXAED) {
248 printf("Excessive deferral on xmit.\n");
249 } else if (status & NS7520_ETH_ETSR_TXAUR) {
250 printf("Packet underrun.\n");
251 } else if (status & NS7520_ETH_ETSR_TXAJ) {
252 printf("Jumbo packet error.\n");
254 printf("Error: Should never get here.\n");
260 /***********************************************************************
262 * @Return: size of last frame in bytes or 0 if no frame available
263 * @Descr: gives one frame to U-Boot which has been copied by DMA engine already
264 * to NetRxPackets[ 0 ].
265 ***********************************************************************/
270 unsigned short rxlen;
271 unsigned short totrxlen = 0;
273 unsigned int rxstatus, lastrxlen;
276 /* If RXBR is 1, data block was received */
277 while (((*get_eth_reg_addr(NS7520_ETH_EGSR)) &
278 NS7520_ETH_EGSR_RXBR) == NS7520_ETH_EGSR_RXBR) {
280 /* get status register and the length of received block */
281 rxstatus = *get_eth_reg_addr(NS7520_ETH_ERSR);
282 rxlen = (rxstatus & NS7520_ETH_ERSR_RXSIZE) >> 16;
284 /* clear RXBR to make fifo available */
285 *get_eth_reg_addr(NS7520_ETH_EGSR) = NS7520_ETH_EGSR_RXBR;
287 if (rxstatus & NS7520_ETH_ERSR_ROVER) {
288 printf("Receive overrun, resetting FIFO.\n");
289 *get_eth_reg_addr(NS7520_ETH_EGCR) &=
290 ~NS7520_ETH_EGCR_ERX;
292 *get_eth_reg_addr(NS7520_ETH_EGCR) |=
296 printf("Nothing.\n");
300 addr = (unsigned int *) NetRxPackets[0];
301 pa = (char *) NetRxPackets[0];
304 for (i = 0; i < rxlen / 4; i++) {
305 *addr = *get_eth_reg_addr(NS7520_ETH_FIFO);
309 if ((*get_eth_reg_addr(NS7520_ETH_EGSR)) &
310 NS7520_ETH_EGSR_RXREGR) {
311 /* RXFDB indicates wether the last word is 1,2,3 or 4 bytes long */
313 ((*get_eth_reg_addr(NS7520_ETH_EGSR)) &
314 NS7520_ETH_EGSR_RXFDB_MA) >> 28;
315 *addr = *get_eth_reg_addr(NS7520_ETH_FIFO);
329 /* Pass the packet up to the protocol layers. */
330 NetReceive(NetRxPackets[0], rxlen - 4);
331 totrxlen += rxlen - 4;
337 /***********************************************************************
338 * @Function: eth_halt
340 * @Descr: stops the ethernet engine
341 ***********************************************************************/
345 DEBUG_FN(DEBUG_INIT);
347 *get_eth_reg_addr(NS7520_ETH_MAC1) &= ~NS7520_ETH_MAC1_RXEN;
348 *get_eth_reg_addr(NS7520_ETH_EGCR) &= ~(NS7520_ETH_EGCR_ERX |
349 NS7520_ETH_EGCR_ERXDMA |
350 NS7520_ETH_EGCR_ERXREG |
351 NS7520_ETH_EGCR_ERXBR |
352 NS7520_ETH_EGCR_ETX |
353 NS7520_ETH_EGCR_ETXDMA);
356 /***********************************************************************
357 * @Function: ns7520_eth_reset
358 * @Return: 0 on failure otherwise 1
359 * @Descr: resets the ethernet interface and the PHY,
360 * performs auto negotiation or fixed modes
361 ***********************************************************************/
363 static int ns7520_eth_reset(void)
365 DEBUG_FN(DEBUG_MINOR);
367 /* Reset important registers */
368 *get_eth_reg_addr(NS7520_ETH_EGCR) = 0; /* Null it out! */
369 *get_eth_reg_addr(NS7520_ETH_MAC1) &= NS7520_ETH_MAC1_SRST;
370 *get_eth_reg_addr(NS7520_ETH_MAC2) = 0;
372 *get_eth_reg_addr(NS7520_ETH_EGCR) |= NS7520_ETH_EGCR_MAC_RES;
374 *get_eth_reg_addr(NS7520_ETH_EGCR) &= ~NS7520_ETH_EGCR_MAC_RES;
376 /* reset and initialize PHY */
378 *get_eth_reg_addr(NS7520_ETH_MAC1) &= ~NS7520_ETH_MAC1_SRST;
380 /* we don't support hot plugging of PHY, therefore we don't reset
381 phyDetected and nPhyMaxMdioClock here. The risk is if the setting is
382 incorrect the first open
383 may detect the PHY correctly but succeding will fail
384 For reseting the PHY and identifying we have to use the standard
385 MDIO CLOCK value 2.5 MHz only after hardware reset
386 After having identified the PHY we will do faster */
388 *get_eth_reg_addr(NS7520_ETH_MCFG) =
389 ns7520_mii_get_clock_divisor(nPhyMaxMdioClock);
392 ns7520_mii_write(PHY_COMMON_CTRL, PHY_COMMON_CTRL_RESET);
393 ns7520_mii_write(PHY_COMMON_CTRL, 0);
395 udelay(3000); /* [2] p.70 says at least 300us reset recovery time. */
397 /* MII clock has been setup to default, ns7520_mii_identify_phy should
400 if (!ns7520_mii_identify_phy()) {
401 printk(KERN_ERR NS7520_DRIVER_NAME
402 ": Unsupported PHY, aborting\n");
406 /* now take the highest MDIO clock possible after detection */
407 *get_eth_reg_addr(NS7520_ETH_MCFG) =
408 ns7520_mii_get_clock_divisor(nPhyMaxMdioClock);
410 /* PHY has been detected, so there can be no abort reason and we can
411 finish initializing ethernet */
413 uiLastLinkStatus = 0xff; /* undefined */
415 ns7520_link_auto_negotiate();
417 if (phyDetected == PHY_LXT971A)
418 /* set LED2 to link mode */
419 ns7520_mii_write(PHY_LXT971_LED_CFG,
420 (PHY_LXT971_LED_CFG_LINK_ACT <<
421 PHY_LXT971_LED_CFG_SHIFT_LED2) |
422 (PHY_LXT971_LED_CFG_TRANSMIT <<
423 PHY_LXT971_LED_CFG_SHIFT_LED1));
428 /***********************************************************************
429 * @Function: ns7520_link_auto_negotiate
431 * @Descr: performs auto-negotation of link.
432 ***********************************************************************/
434 static void ns7520_link_auto_negotiate(void)
436 unsigned long ulStartJiffies;
437 unsigned short uiStatus;
439 DEBUG_FN(DEBUG_LINK);
441 /* run auto-negotation */
442 /* define what we are capable of */
443 ns7520_mii_write(PHY_COMMON_AUTO_ADV,
444 PHY_COMMON_AUTO_ADV_100BTXFD |
445 PHY_COMMON_AUTO_ADV_100BTX |
446 PHY_COMMON_AUTO_ADV_10BTFD |
447 PHY_COMMON_AUTO_ADV_10BT |
448 PHY_COMMON_AUTO_ADV_802_3);
449 /* start auto-negotiation */
450 ns7520_mii_write(PHY_COMMON_CTRL,
451 PHY_COMMON_CTRL_AUTO_NEG |
452 PHY_COMMON_CTRL_RES_AUTO);
454 /* wait for completion */
456 ulStartJiffies = get_timer(0);
457 while (get_timer(0) < ulStartJiffies + NS7520_MII_NEG_DELAY) {
458 uiStatus = ns7520_mii_read(PHY_COMMON_STAT);
460 (PHY_COMMON_STAT_AN_COMP | PHY_COMMON_STAT_LNK_STAT))
462 (PHY_COMMON_STAT_AN_COMP | PHY_COMMON_STAT_LNK_STAT)) {
463 /* lucky we are, auto-negotiation succeeded */
464 ns7520_link_print_changed();
465 ns7520_link_update_egcr();
470 DEBUG_ARGS0(DEBUG_LINK, "auto-negotiation timed out\n");
471 /* ignore invalid link settings */
474 /***********************************************************************
475 * @Function: ns7520_link_update_egcr
477 * @Descr: updates the EGCR and MAC2 link status after mode change or
479 ***********************************************************************/
481 static void ns7520_link_update_egcr(void)
487 DEBUG_FN(DEBUG_LINK);
489 unEGCR = *get_eth_reg_addr(NS7520_ETH_EGCR);
490 unMAC2 = *get_eth_reg_addr(NS7520_ETH_MAC2);
492 *get_eth_reg_addr(NS7520_ETH_IPGT) & ~NS7520_ETH_IPGT_IPGT;
494 unEGCR &= ~NS7520_ETH_EGCR_EFULLD;
495 unMAC2 &= ~NS7520_ETH_MAC2_FULLD;
496 if ((uiLastLinkStatus & PHY_LXT971_STAT2_DUPLEX_MODE)
497 == PHY_LXT971_STAT2_DUPLEX_MODE) {
498 unEGCR |= NS7520_ETH_EGCR_EFULLD;
499 unMAC2 |= NS7520_ETH_MAC2_FULLD;
500 unIPGT |= 0x15; /* see [1] p. 167 */
502 unIPGT |= 0x12; /* see [1] p. 167 */
504 *get_eth_reg_addr(NS7520_ETH_MAC2) = unMAC2;
505 *get_eth_reg_addr(NS7520_ETH_EGCR) = unEGCR;
506 *get_eth_reg_addr(NS7520_ETH_IPGT) = unIPGT;
509 /***********************************************************************
510 * @Function: ns7520_link_print_changed
512 * @Descr: checks whether the link status has changed and if so prints
514 ***********************************************************************/
516 static void ns7520_link_print_changed(void)
518 unsigned short uiStatus;
519 unsigned short uiControl;
521 DEBUG_FN(DEBUG_LINK);
523 uiControl = ns7520_mii_read(PHY_COMMON_CTRL);
525 if ((uiControl & PHY_COMMON_CTRL_AUTO_NEG) ==
526 PHY_COMMON_CTRL_AUTO_NEG) {
527 /* PHY_COMMON_STAT_LNK_STAT is only set on autonegotiation */
528 uiStatus = ns7520_mii_read(PHY_COMMON_STAT);
530 if (!(uiStatus & PHY_COMMON_STAT_LNK_STAT)) {
531 printk(KERN_WARNING NS7520_DRIVER_NAME
533 /* @TODO Linux: carrier_off */
535 /* @TODO Linux: carrier_on */
536 if (phyDetected == PHY_LXT971A) {
538 ns7520_mii_read(PHY_LXT971_STAT2);
540 (PHY_LXT971_STAT2_100BTX |
541 PHY_LXT971_STAT2_DUPLEX_MODE |
542 PHY_LXT971_STAT2_AUTO_NEG);
544 /* mask out all uninteresting parts */
546 /* other PHYs must store there link information in
547 uiStatus as PHY_LXT971 */
550 /* mode has been forced, so uiStatus should be the same as the
551 last link status, enforce printing */
552 uiStatus = uiLastLinkStatus;
553 uiLastLinkStatus = 0xff;
556 if (uiStatus != uiLastLinkStatus) {
557 /* save current link status */
558 uiLastLinkStatus = uiStatus;
560 /* print new link status */
562 printk(KERN_INFO NS7520_DRIVER_NAME
563 ": link mode %i Mbps %s duplex %s\n",
564 (uiStatus & PHY_LXT971_STAT2_100BTX) ? 100 : 10,
565 (uiStatus & PHY_LXT971_STAT2_DUPLEX_MODE) ? "full" :
567 (uiStatus & PHY_LXT971_STAT2_AUTO_NEG) ? "(auto)" :
572 /***********************************************************************
573 * the MII low level stuff
574 ***********************************************************************/
576 /***********************************************************************
577 * @Function: ns7520_mii_identify_phy
578 * @Return: 1 if supported PHY has been detected otherwise 0
579 * @Descr: checks for supported PHY and prints the IDs.
580 ***********************************************************************/
582 static char ns7520_mii_identify_phy(void)
584 unsigned short uiID1;
585 unsigned short uiID2;
586 unsigned char *szName;
591 phyDetected = (PhyType) uiID1 = ns7520_mii_read(PHY_COMMON_ID1);
593 switch (phyDetected) {
596 uiID2 = ns7520_mii_read(PHY_COMMON_ID2);
597 nPhyMaxMdioClock = PHY_LXT971_MDIO_MAX_CLK;
602 /* in case uiID1 == 0 && uiID2 == 0 we may have the wrong
603 address or reset sets the wrong NS7520_ETH_MCFG_CLKS */
607 nPhyMaxMdioClock = PHY_MDIO_MAX_CLK;
608 phyDetected = PHY_NONE;
611 printk(KERN_INFO NS7520_DRIVER_NAME
612 ": PHY (0x%x, 0x%x) = %s detected\n", uiID1, uiID2, szName);
617 /***********************************************************************
618 * @Function: ns7520_mii_read
619 * @Return: the data read from PHY register uiRegister
620 * @Descr: the data read may be invalid if timed out. If so, a message
621 * is printed but the invalid data is returned.
622 * The fixed device address is being used.
623 ***********************************************************************/
625 static unsigned short ns7520_mii_read(unsigned short uiRegister)
627 DEBUG_FN(DEBUG_MII_LOW);
629 /* write MII register to be read */
630 *get_eth_reg_addr(NS7520_ETH_MADR) =
631 CONFIG_PHY_ADDR << 8 | uiRegister;
633 *get_eth_reg_addr(NS7520_ETH_MCMD) = NS7520_ETH_MCMD_READ;
635 if (!ns7520_mii_poll_busy())
636 printk(KERN_WARNING NS7520_DRIVER_NAME
637 ": MII still busy in read\n");
638 /* continue to read */
640 *get_eth_reg_addr(NS7520_ETH_MCMD) = 0;
642 return (unsigned short) (*get_eth_reg_addr(NS7520_ETH_MRDD));
645 /***********************************************************************
646 * @Function: ns7520_mii_write
648 * @Descr: writes the data to the PHY register. In case of a timeout,
649 * no special handling is performed but a message printed
650 * The fixed device address is being used.
651 ***********************************************************************/
653 static void ns7520_mii_write(unsigned short uiRegister,
654 unsigned short uiData)
656 DEBUG_FN(DEBUG_MII_LOW);
658 /* write MII register to be written */
659 *get_eth_reg_addr(NS7520_ETH_MADR) =
660 CONFIG_PHY_ADDR << 8 | uiRegister;
662 *get_eth_reg_addr(NS7520_ETH_MWTD) = uiData;
664 if (!ns7520_mii_poll_busy()) {
665 printf(KERN_WARNING NS7520_DRIVER_NAME
666 ": MII still busy in write\n");
670 /***********************************************************************
671 * @Function: ns7520_mii_get_clock_divisor
672 * @Return: the clock divisor that should be used in NS7520_ETH_MCFG_CLKS
673 * @Descr: if no clock divisor can be calculated for the
674 * current SYSCLK and the maximum MDIO Clock, a warning is printed
675 * and the greatest divisor is taken
676 ***********************************************************************/
678 static unsigned int ns7520_mii_get_clock_divisor(unsigned int unMaxMDIOClk)
681 unsigned int unSysClkDivisor;
682 unsigned int unClks; /* field for NS7520_ETH_MCFG_CLKS */
683 } PHYClockDivisors[] = {
685 4, NS7520_ETH_MCFG_CLKS_4}, {
686 6, NS7520_ETH_MCFG_CLKS_6}, {
687 8, NS7520_ETH_MCFG_CLKS_8}, {
688 10, NS7520_ETH_MCFG_CLKS_10}, {
689 14, NS7520_ETH_MCFG_CLKS_14}, {
690 20, NS7520_ETH_MCFG_CLKS_20}, {
691 28, NS7520_ETH_MCFG_CLKS_28}
696 sizeof(PHYClockDivisors) / sizeof(PHYClockDivisors[0]);
697 unsigned int unClks = NS7520_ETH_MCFG_CLKS_28; /* defaults to
700 DEBUG_FN(DEBUG_INIT);
702 for (nIndexSysClkDiv = 0; nIndexSysClkDiv < nArraySize;
704 /* find first sysclock divisor that isn't higher than 2.5 MHz
706 if (NETARM_XTAL_FREQ /
707 PHYClockDivisors[nIndexSysClkDiv].unSysClkDivisor <=
709 unClks = PHYClockDivisors[nIndexSysClkDiv].unClks;
714 DEBUG_ARGS2(DEBUG_INIT,
715 "Taking MDIO Clock bit mask 0x%0x for max clock %i\n",
716 unClks, unMaxMDIOClk);
718 /* return greatest divisor */
722 /***********************************************************************
723 * @Function: ns7520_mii_poll_busy
724 * @Return: 0 if timed out otherwise the remaing timeout
725 * @Descr: waits until the MII has completed a command or it times out
726 * code may be interrupted by hard interrupts.
727 * It is not checked what happens on multiple actions when
728 * the first is still being busy and we timeout.
729 ***********************************************************************/
731 static unsigned int ns7520_mii_poll_busy(void)
733 unsigned int unTimeout = 1000;
735 DEBUG_FN(DEBUG_MII_LOW);
737 while (((*get_eth_reg_addr(NS7520_ETH_MIND) & NS7520_ETH_MIND_BUSY)
738 == NS7520_ETH_MIND_BUSY) && unTimeout)
744 /* ----------------------------------------------------------------------------
745 * Net+ARM ethernet MII functionality.
747 #if defined(CONFIG_MII)
750 * Maximum MII address we support
752 #define MII_ADDRESS_MAX (31)
755 * Maximum MII register address we support
757 #define MII_REGISTER_MAX (31)
760 * Ethernet MII interface return values for public functions.
763 MII_STATUS_SUCCESS = 0,
764 MII_STATUS_FAILURE = 1,
768 * Read a 16-bit value from an MII register.
770 extern int ns7520_miiphy_read(char *devname, unsigned char const addr,
771 unsigned char const reg, unsigned short *const value)
773 int ret = MII_STATUS_FAILURE;
775 /* Parameter checks */
776 if (addr > MII_ADDRESS_MAX) {
777 ERROR(("invalid addr, 0x%02X", addr));
778 goto miiphy_read_failed_0;
781 if (reg > MII_REGISTER_MAX) {
782 ERROR(("invalid reg, 0x%02X", reg));
783 goto miiphy_read_failed_0;
787 ERROR(("NULL value"));
788 goto miiphy_read_failed_0;
791 DEBUG_FN(DEBUG_MII_LOW);
793 /* write MII register to be read */
794 *get_eth_reg_addr(NS7520_ETH_MADR) = (addr << 8) | reg;
796 *get_eth_reg_addr(NS7520_ETH_MCMD) = NS7520_ETH_MCMD_READ;
798 if (!ns7520_mii_poll_busy())
799 printk(KERN_WARNING NS7520_DRIVER_NAME
800 ": MII still busy in read\n");
801 /* continue to read */
803 *get_eth_reg_addr(NS7520_ETH_MCMD) = 0;
805 *value = (*get_eth_reg_addr(NS7520_ETH_MRDD));
806 ret = MII_STATUS_SUCCESS;
809 miiphy_read_failed_0:
814 * Write a 16-bit value to an MII register.
816 extern int ns7520_miiphy_write(char *devname, unsigned char const addr,
817 unsigned char const reg, unsigned short const value)
819 int ret = MII_STATUS_FAILURE;
821 /* Parameter checks */
822 if (addr > MII_ADDRESS_MAX) {
823 ERROR(("invalid addr, 0x%02X", addr));
824 goto miiphy_write_failed_0;
827 if (reg > MII_REGISTER_MAX) {
828 ERROR(("invalid reg, 0x%02X", reg));
829 goto miiphy_write_failed_0;
832 /* write MII register to be written */
833 *get_eth_reg_addr(NS7520_ETH_MADR) = (addr << 8) | reg;
835 *get_eth_reg_addr(NS7520_ETH_MWTD) = value;
837 if (!ns7520_mii_poll_busy()) {
838 printf(KERN_WARNING NS7520_DRIVER_NAME
839 ": MII still busy in write\n");
842 ret = MII_STATUS_SUCCESS;
845 miiphy_write_failed_0:
848 #endif /* defined(CONFIG_MII) */
849 #endif /* CONFIG_DRIVER_NS7520_ETHERNET */
851 int ns7520_miiphy_initialize(bd_t *bis)
853 #if defined(CONFIG_DRIVER_NS7520_ETHERNET)
854 #if defined(CONFIG_MII)
855 miiphy_register("ns7520phy", ns7520_miiphy_read, ns7520_miiphy_write);