]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/ns9750_eth.c
G2000 board support added
[karo-tx-uboot.git] / drivers / ns9750_eth.c
1 /***********************************************************************
2  *
3  * Copyright (C) 2004 by FS Forth-Systeme GmbH.
4  * All rights reserved.
5  *
6  * $Id: ns9750_eth.c,v 1.2 2004/02/24 14:09:39 mpietrek Exp $
7  * @Author: Markus Pietrek
8  * @Descr: Ethernet driver for the NS9750. Uses DMA Engine with polling
9  *         interrupt status. But interrupts are not enabled.
10  *         Only one tx buffer descriptor and the RXA buffer descriptor are used
11  *         Currently no transmit lockup handling is included. eth_send has a 5s
12  *         timeout for sending frames. No retransmits are performed when an
13  *         error occurs.
14  * @References: [1] NS9750 Hardware Reference, December 2003
15  *              [2] Intel LXT971 Datasheet #249414 Rev. 02
16  *              [3] NS7520 Linux Ethernet Driver
17  *
18  * This program is free software; you can redistribute it and/or
19  * modify it under the terms of the GNU General Public License as
20  * published by the Free Software Foundation; either version 2 of
21  * the License, or (at your option) any later version.
22  *
23  * This program is distributed in the hope that it will be useful,
24  * but WITHOUT ANY WARRANTY; without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26  * GNU General Public License for more details.
27  *
28  * You should have received a copy of the GNU General Public License
29  * along with this program; if not, write to the Free Software
30  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
31  * MA 02111-1307 USA
32  *
33  ***********************************************************************/
34
35 #include <common.h>
36 #include <net.h>                /* NetSendPacket */
37
38 #include "ns9750_eth.h"         /* for Ethernet and PHY */
39
40 #ifdef CONFIG_DRIVER_NS9750_ETHERNET
41
42 /* some definition to make transistion to linux easier */
43
44 #define NS9750_DRIVER_NAME      "eth"
45 #define KERN_WARNING            "Warning:"
46 #define KERN_ERR                "Error:"
47 #define KERN_INFO               "Info:"
48
49 #if 0
50 # define DEBUG
51 #endif
52
53 #ifdef  DEBUG
54 # define printk                 printf
55
56 # define DEBUG_INIT             0x0001
57 # define DEBUG_MINOR            0x0002
58 # define DEBUG_RX               0x0004
59 # define DEBUG_TX               0x0008
60 # define DEBUG_INT              0x0010
61 # define DEBUG_POLL             0x0020
62 # define DEBUG_LINK             0x0040
63 # define DEBUG_MII              0x0100
64 # define DEBUG_MII_LOW          0x0200
65 # define DEBUG_MEM              0x0400
66 # define DEBUG_ERROR            0x4000
67 # define DEBUG_ERROR_CRIT       0x8000
68
69 static int nDebugLvl = DEBUG_ERROR_CRIT;
70
71 # define DEBUG_ARGS0( FLG, a0 ) if( ( nDebugLvl & (FLG) ) == (FLG) ) \
72                 printf("%s: " a0, __FUNCTION__, 0, 0, 0, 0, 0, 0 )
73 # define DEBUG_ARGS1( FLG, a0, a1 ) if( ( nDebugLvl & (FLG) ) == (FLG)) \
74                 printf("%s: " a0, __FUNCTION__, (int)(a1), 0, 0, 0, 0, 0 )
75 # define DEBUG_ARGS2( FLG, a0, a1, a2 ) if( (nDebugLvl & (FLG)) ==(FLG))\
76                 printf("%s: " a0, __FUNCTION__, (int)(a1), (int)(a2), 0, 0,0,0 )
77 # define DEBUG_ARGS3( FLG, a0, a1, a2, a3 ) if((nDebugLvl &(FLG))==(FLG))\
78                 printf("%s: "a0,__FUNCTION__,(int)(a1),(int)(a2),(int)(a3),0,0,0)
79 # define DEBUG_FN( FLG ) if( (nDebugLvl & (FLG)) == (FLG) ) \
80                 printf("\r%s:line %d\n", (int)__FUNCTION__, __LINE__, 0,0,0,0);
81 # define ASSERT( expr, func ) if( !( expr ) ) { \
82                 printf( "Assertion failed! %s:line %d %s\n", \
83                 (int)__FUNCTION__,__LINE__,(int)(#expr),0,0,0); \
84                 func }
85 #else /* DEBUG */
86 # define printk(...)
87 # define DEBUG_ARGS0( FLG, a0 )
88 # define DEBUG_ARGS1( FLG, a0, a1 )
89 # define DEBUG_ARGS2( FLG, a0, a1, a2 )
90 # define DEBUG_ARGS3( FLG, a0, a1, a2, a3 )
91 # define DEBUG_FN( n )
92 # define ASSERT(expr, func)
93 #endif /* DEBUG */
94
95 #define NS9750_MII_NEG_DELAY            (5*CFG_HZ) /* in s */
96 #define TX_TIMEOUT                      (5*CFG_HZ) /* in s */
97
98 /* @TODO move it to eeprom.h */
99 #define FS_EEPROM_AUTONEG_MASK          0x7
100 #define FS_EEPROM_AUTONEG_SPEED_MASK    0x1
101 #define FS_EEPROM_AUTONEG_SPEED_10      0x0
102 #define FS_EEPROM_AUTONEG_SPEED_100     0x1
103 #define FS_EEPROM_AUTONEG_DUPLEX_MASK   0x2
104 #define FS_EEPROM_AUTONEG_DUPLEX_HALF   0x0
105 #define FS_EEPROM_AUTONEG_DUPLEX_FULL   0x2
106 #define FS_EEPROM_AUTONEG_ENABLE_MASK   0x4
107 #define FS_EEPROM_AUTONEG_DISABLE       0x0
108 #define FS_EEPROM_AUTONEG_ENABLE        0x4
109
110 /* buffer descriptors taken from [1] p.306 */
111 typedef struct
112 {
113         unsigned int* punSrc;
114         unsigned int unLen;     /* 11 bits */
115         unsigned int* punDest;  /* unused */
116         union {
117                 unsigned int unReg;
118                 struct {
119                         unsigned uStatus : 16;
120                         unsigned uRes : 12;
121                         unsigned uFull : 1;
122                         unsigned uEnable : 1;
123                         unsigned uInt : 1;
124                         unsigned uWrap : 1;
125                 } bits;
126         } s;
127 } rx_buffer_desc_t;
128
129 typedef struct
130 {
131         unsigned int* punSrc;
132         unsigned int unLen;     /* 10 bits */
133         unsigned int* punDest;  /* unused */
134         union {
135                 unsigned int unReg; /* only 32bit accesses may done to NS9750
136                                      * eth engine */
137                 struct {
138                         unsigned uStatus : 16;
139                         unsigned uRes : 12;
140                         unsigned uFull : 1;
141                         unsigned uLast : 1;
142                         unsigned uInt : 1;
143                         unsigned uWrap : 1;
144                 } bits;
145         } s;
146 } tx_buffer_desc_t;
147
148 static int ns9750_eth_reset( void );
149
150 static void ns9750_link_force( void );
151 static void ns9750_link_auto_negotiate( void );
152 static void ns9750_link_update_egcr( void );
153 static void ns9750_link_print_changed( void );
154
155 /* the PHY stuff */
156
157 static char ns9750_mii_identify_phy( void );
158 static unsigned short ns9750_mii_read( unsigned short uiRegister );
159 static void ns9750_mii_write( unsigned short uiRegister, unsigned short uiData );
160 static unsigned int ns9750_mii_get_clock_divisor( unsigned int unMaxMDIOClk );
161 static unsigned int ns9750_mii_poll_busy( void );
162
163 static unsigned int nPhyMaxMdioClock = PHY_MDIO_MAX_CLK;
164 static unsigned char ucLinkMode =      FS_EEPROM_AUTONEG_ENABLE;
165 static unsigned int uiLastLinkStatus;
166 static PhyType phyDetected = PHY_NONE;
167
168 /* we use only one tx buffer descriptor */
169 static tx_buffer_desc_t* pTxBufferDesc =
170         (tx_buffer_desc_t*) get_eth_reg_addr( NS9750_ETH_TXBD );
171
172 /* we use only one rx buffer descriptor of the 4 */
173 static rx_buffer_desc_t aRxBufferDesc[ 4 ];
174
175 /***********************************************************************
176  * @Function: eth_init
177  * @Return: -1 on failure otherwise 0
178  * @Descr: Initializes the ethernet engine and uses either FS Forth's default
179  *         MAC addr or the one in environment
180  ***********************************************************************/
181
182 int eth_init (bd_t * pbis)
183 {
184         /* This default MAC Addr is reserved by FS Forth-Systeme for the case of
185            EEPROM failures */
186         unsigned char aucMACAddr[6] = { 0x00, 0x04, 0xf3, 0x00, 0x06, 0x35 };
187         char *pcTmp = getenv ("ethaddr");
188         char *pcEnd;
189         int i;
190
191         DEBUG_FN (DEBUG_INIT);
192
193         /* no need to check for hardware */
194
195         if (!ns9750_eth_reset ())
196                 return -1;
197
198         if (pcTmp != NULL)
199                 for (i = 0; i < 6; i++) {
200                         aucMACAddr[i] =
201                                 pcTmp ? simple_strtoul (pcTmp, &pcEnd,
202                                                         16) : 0;
203                         pcTmp = (*pcTmp) ? pcEnd + 1 : pcEnd;
204                 }
205
206         /* configure ethernet address */
207
208         *get_eth_reg_addr (NS9750_ETH_SA1) =
209                 aucMACAddr[5] << 8 | aucMACAddr[4];
210         *get_eth_reg_addr (NS9750_ETH_SA2) =
211                 aucMACAddr[3] << 8 | aucMACAddr[2];
212         *get_eth_reg_addr (NS9750_ETH_SA3) =
213                 aucMACAddr[1] << 8 | aucMACAddr[0];
214
215         /* enable hardware */
216
217         *get_eth_reg_addr (NS9750_ETH_MAC1) = NS9750_ETH_MAC1_RXEN;
218
219         /* the linux kernel may give packets < 60 bytes, for example arp */
220         *get_eth_reg_addr (NS9750_ETH_MAC2) = NS9750_ETH_MAC2_CRCEN |
221                 NS9750_ETH_MAC2_PADEN | NS9750_ETH_MAC2_HUGE;
222
223         /* enable receive and transmit FIFO, use 10/100 Mbps MII */
224         *get_eth_reg_addr (NS9750_ETH_EGCR1) =
225                 NS9750_ETH_EGCR1_ETXWM |
226                 NS9750_ETH_EGCR1_ERX |
227                 NS9750_ETH_EGCR1_ERXDMA |
228                 NS9750_ETH_EGCR1_ETX |
229                 NS9750_ETH_EGCR1_ETXDMA | NS9750_ETH_EGCR1_ITXA;
230
231         /* prepare DMA descriptors */
232         for (i = 0; i < 4; i++) {
233                 aRxBufferDesc[i].punSrc = 0;
234                 aRxBufferDesc[i].unLen = 0;
235                 aRxBufferDesc[i].s.bits.uWrap = 1;
236                 aRxBufferDesc[i].s.bits.uInt = 1;
237                 aRxBufferDesc[i].s.bits.uEnable = 0;
238                 aRxBufferDesc[i].s.bits.uFull = 0;
239         }
240
241         /* NetRxPackets[ 0 ] is initialized before eth_init is called and never
242            changes. NetRxPackets is 32bit aligned */
243         aRxBufferDesc[0].punSrc = (unsigned int *) NetRxPackets[0];
244         aRxBufferDesc[0].s.bits.uEnable = 1;
245         aRxBufferDesc[0].unLen = 1522;  /* as stated in [1] p.307 */
246
247         *get_eth_reg_addr (NS9750_ETH_RXAPTR) =
248                 (unsigned int) &aRxBufferDesc[0];
249
250         /* [1] Tab. 221 states less than 5us */
251         *get_eth_reg_addr (NS9750_ETH_EGCR1) |= NS9750_ETH_EGCR1_ERXINIT;
252         while (!
253                (*get_eth_reg_addr (NS9750_ETH_EGSR) & NS9750_ETH_EGSR_RXINIT))
254                 /* wait for finish */
255                 udelay (1);
256
257         /* @TODO do we need to clear RXINIT? */
258         *get_eth_reg_addr (NS9750_ETH_EGCR1) &= ~NS9750_ETH_EGCR1_ERXINIT;
259
260         *get_eth_reg_addr (NS9750_ETH_RXFREE) = 0x1;
261
262         return 0;
263 }
264
265 /***********************************************************************
266  * @Function: eth_send
267  * @Return: -1 on timeout otherwise 1
268  * @Descr: sends one frame by DMA
269  ***********************************************************************/
270
271 int eth_send (volatile void *pPacket, int nLen)
272 {
273         ulong ulTimeout;
274
275         DEBUG_FN (DEBUG_TX);
276
277         /* clear old status values */
278         *get_eth_reg_addr (NS9750_ETH_EINTR) &=
279                 *get_eth_reg_addr (NS9750_ETH_EINTR) & NS9750_ETH_EINTR_TX_MA;
280
281         /* prepare Tx Descriptors */
282
283         pTxBufferDesc->punSrc = (unsigned int *) pPacket;       /* pPacket is 32bit
284                                                                  * aligned */
285         pTxBufferDesc->unLen = nLen;
286         /* only 32bit accesses allowed. wrap, full, interrupt and enabled to 1 */
287         pTxBufferDesc->s.unReg = 0xf0000000;
288         /* pTxBufferDesc is the first possible buffer descriptor */
289         *get_eth_reg_addr (NS9750_ETH_TXPTR) = 0x0;
290
291         /* enable processor for next frame */
292
293         *get_eth_reg_addr (NS9750_ETH_EGCR2) &= ~NS9750_ETH_EGCR2_TCLER;
294         *get_eth_reg_addr (NS9750_ETH_EGCR2) |= NS9750_ETH_EGCR2_TCLER;
295
296         ulTimeout = get_timer (0);
297
298         DEBUG_ARGS0 (DEBUG_TX | DEBUG_MINOR,
299                      "Waiting for transmission to finish\n");
300         while (!
301                (*get_eth_reg_addr (NS9750_ETH_EINTR) &
302                 (NS9750_ETH_EINTR_TXDONE | NS9750_ETH_EINTR_TXERR))) {
303                 /* do nothing, wait for completion */
304                 if (get_timer (0) - ulTimeout > TX_TIMEOUT) {
305                         DEBUG_ARGS0 (DEBUG_TX, "Transmit Timed out\n");
306                         return -1;
307                 }
308         }
309         DEBUG_ARGS0 (DEBUG_TX | DEBUG_MINOR, "transmitted...\n");
310
311         return 0;
312 }
313
314 /***********************************************************************
315  * @Function: eth_rx
316  * @Return: size of last frame in bytes or 0 if no frame available
317  * @Descr: gives one frame to U-Boot which has been copied by DMA engine already
318  *         to NetRxPackets[ 0 ].
319  ***********************************************************************/
320
321 int eth_rx (void)
322 {
323         int nLen = 0;
324         unsigned int unStatus;
325
326         unStatus =
327                 *get_eth_reg_addr (NS9750_ETH_EINTR) & NS9750_ETH_EINTR_RX_MA;
328
329         if (!unStatus)
330                 /* no packet available, return immediately */
331                 return 0;
332
333         DEBUG_FN (DEBUG_RX);
334
335         /* unLen always < max(nLen) and discard checksum */
336         nLen = (int) aRxBufferDesc[0].unLen - 4;
337
338         /* acknowledge status register */
339         *get_eth_reg_addr (NS9750_ETH_EINTR) = unStatus;
340
341         aRxBufferDesc[0].unLen = 1522;
342         aRxBufferDesc[0].s.bits.uFull = 0;
343
344         /* Buffer A descriptor available again */
345         *get_eth_reg_addr (NS9750_ETH_RXFREE) |= 0x1;
346
347         /* NetReceive may call eth_send. Due to a possible bug of the NS9750 we
348          * have to acknowledge the received frame before sending a new one */
349         if (unStatus & NS9750_ETH_EINTR_RXDONEA)
350                 NetReceive (NetRxPackets[0], nLen);
351
352         return nLen;
353 }
354
355 /***********************************************************************
356  * @Function: eth_halt
357  * @Return: n/a
358  * @Descr: stops the ethernet engine
359  ***********************************************************************/
360
361 void eth_halt (void)
362 {
363         DEBUG_FN (DEBUG_INIT);
364
365         *get_eth_reg_addr (NS9750_ETH_MAC1) &= ~NS9750_ETH_MAC1_RXEN;
366         *get_eth_reg_addr (NS9750_ETH_EGCR1) &= ~(NS9750_ETH_EGCR1_ERX |
367                                                   NS9750_ETH_EGCR1_ERXDMA |
368                                                   NS9750_ETH_EGCR1_ETX |
369                                                   NS9750_ETH_EGCR1_ETXDMA);
370 }
371
372 /***********************************************************************
373  * @Function: ns9750_eth_reset
374  * @Return: 0 on failure otherwise 1
375  * @Descr: resets the ethernet interface and the PHY,
376  *         performs auto negotiation or fixed modes
377  ***********************************************************************/
378
379 static int ns9750_eth_reset (void)
380 {
381         DEBUG_FN (DEBUG_MINOR);
382
383         /* Reset MAC */
384         *get_eth_reg_addr (NS9750_ETH_EGCR1) |= NS9750_ETH_EGCR1_MAC_HRST;
385         udelay (5);             /* according to [1], p.322 */
386         *get_eth_reg_addr (NS9750_ETH_EGCR1) &= ~NS9750_ETH_EGCR1_MAC_HRST;
387
388         /* reset and initialize PHY */
389
390         *get_eth_reg_addr (NS9750_ETH_MAC1) &= ~NS9750_ETH_MAC1_SRST;
391
392         /* we don't support hot plugging of PHY, therefore we don't reset
393            phyDetected and nPhyMaxMdioClock here. The risk is if the setting is
394            incorrect the first open
395            may detect the PHY correctly but succeding will fail
396            For reseting the PHY and identifying we have to use the standard
397            MDIO CLOCK value 2.5 MHz only after hardware reset
398            After having identified the PHY we will do faster */
399
400         *get_eth_reg_addr (NS9750_ETH_MCFG) =
401                 ns9750_mii_get_clock_divisor (nPhyMaxMdioClock);
402
403         /* reset PHY */
404         ns9750_mii_write (PHY_COMMON_CTRL, PHY_COMMON_CTRL_RESET);
405         ns9750_mii_write (PHY_COMMON_CTRL, 0);
406
407         /* @TODO check time */
408         udelay (3000);          /* [2] p.70 says at least 300us reset recovery time. But
409                                    go sure, it didn't worked stable at higher timer
410                                    frequencies under LxNETES-2.x */
411
412         /* MII clock has been setup to default, ns9750_mii_identify_phy should
413            work for all */
414
415         if (!ns9750_mii_identify_phy ()) {
416                 printk (KERN_ERR NS9750_DRIVER_NAME
417                         ": Unsupported PHY, aborting\n");
418                 return 0;
419         }
420
421         /* now take the highest MDIO clock possible after detection */
422         *get_eth_reg_addr (NS9750_ETH_MCFG) =
423                 ns9750_mii_get_clock_divisor (nPhyMaxMdioClock);
424
425
426         /* PHY has been detected, so there can be no abort reason and we can
427            finish initializing ethernet */
428
429         uiLastLinkStatus = 0xff;        /* undefined */
430
431         if ((ucLinkMode & FS_EEPROM_AUTONEG_ENABLE_MASK) ==
432             FS_EEPROM_AUTONEG_DISABLE)
433                 /* use parameters defined */
434                 ns9750_link_force ();
435         else
436                 ns9750_link_auto_negotiate ();
437
438         if (phyDetected == PHY_LXT971A)
439                 /* set LED2 to link mode */
440                 ns9750_mii_write (PHY_LXT971_LED_CFG,
441                                   PHY_LXT971_LED_CFG_LINK_ACT <<
442                                   PHY_LXT971_LED_CFG_SHIFT_LED2);
443
444         return 1;
445 }
446
447 /***********************************************************************
448  * @Function: ns9750_link_force
449  * @Return: void
450  * @Descr: configures eth and MII to use the link mode defined in
451  *         ucLinkMode
452  ***********************************************************************/
453
454 static void ns9750_link_force (void)
455 {
456         unsigned short uiControl;
457
458         DEBUG_FN (DEBUG_LINK);
459
460         uiControl = ns9750_mii_read (PHY_COMMON_CTRL);
461         uiControl &= ~(PHY_COMMON_CTRL_SPD_MA |
462                        PHY_COMMON_CTRL_AUTO_NEG | PHY_COMMON_CTRL_DUPLEX);
463
464         uiLastLinkStatus = 0;
465
466         if ((ucLinkMode & FS_EEPROM_AUTONEG_SPEED_MASK) ==
467             FS_EEPROM_AUTONEG_SPEED_100) {
468                 uiControl |= PHY_COMMON_CTRL_SPD_100;
469                 uiLastLinkStatus |= PHY_LXT971_STAT2_100BTX;
470         } else
471                 uiControl |= PHY_COMMON_CTRL_SPD_10;
472
473         if ((ucLinkMode & FS_EEPROM_AUTONEG_DUPLEX_MASK) ==
474             FS_EEPROM_AUTONEG_DUPLEX_FULL) {
475                 uiControl |= PHY_COMMON_CTRL_DUPLEX;
476                 uiLastLinkStatus |= PHY_LXT971_STAT2_DUPLEX_MODE;
477         }
478
479         ns9750_mii_write (PHY_COMMON_CTRL, uiControl);
480
481         ns9750_link_print_changed ();
482         ns9750_link_update_egcr ();
483 }
484
485 /***********************************************************************
486  * @Function: ns9750_link_auto_negotiate
487  * @Return: void
488  * @Descr: performs auto-negotation of link.
489  ***********************************************************************/
490
491 static void ns9750_link_auto_negotiate (void)
492 {
493         unsigned long ulStartJiffies;
494         unsigned short uiStatus;
495
496         DEBUG_FN (DEBUG_LINK);
497
498         /* run auto-negotation */
499         /* define what we are capable of */
500         ns9750_mii_write (PHY_COMMON_AUTO_ADV,
501                           PHY_COMMON_AUTO_ADV_100BTXFD |
502                           PHY_COMMON_AUTO_ADV_100BTX |
503                           PHY_COMMON_AUTO_ADV_10BTFD |
504                           PHY_COMMON_AUTO_ADV_10BT |
505                           PHY_COMMON_AUTO_ADV_802_3);
506         /* start auto-negotiation */
507         ns9750_mii_write (PHY_COMMON_CTRL,
508                           PHY_COMMON_CTRL_AUTO_NEG |
509                           PHY_COMMON_CTRL_RES_AUTO);
510
511         /* wait for completion */
512
513         ulStartJiffies = get_ticks ();
514         while (get_ticks () < ulStartJiffies + NS9750_MII_NEG_DELAY) {
515                 uiStatus = ns9750_mii_read (PHY_COMMON_STAT);
516                 if ((uiStatus &
517                      (PHY_COMMON_STAT_AN_COMP | PHY_COMMON_STAT_LNK_STAT)) ==
518                     (PHY_COMMON_STAT_AN_COMP | PHY_COMMON_STAT_LNK_STAT)) {
519                         /* lucky we are, auto-negotiation succeeded */
520                         ns9750_link_print_changed ();
521                         ns9750_link_update_egcr ();
522                         return;
523                 }
524         }
525
526         DEBUG_ARGS0 (DEBUG_LINK, "auto-negotiation timed out\n");
527         /* ignore invalid link settings */
528 }
529
530 /***********************************************************************
531  * @Function: ns9750_link_update_egcr
532  * @Return: void
533  * @Descr: updates the EGCR and MAC2 link status after mode change or
534  *         auto-negotation
535  ***********************************************************************/
536
537 static void ns9750_link_update_egcr (void)
538 {
539         unsigned int unEGCR;
540         unsigned int unMAC2;
541         unsigned int unIPGT;
542
543         DEBUG_FN (DEBUG_LINK);
544
545         unEGCR = *get_eth_reg_addr (NS9750_ETH_EGCR1);
546         unMAC2 = *get_eth_reg_addr (NS9750_ETH_MAC2);
547         unIPGT = *get_eth_reg_addr (NS9750_ETH_IPGT) & ~NS9750_ETH_IPGT_MA;
548
549         unMAC2 &= ~NS9750_ETH_MAC2_FULLD;
550         if ((uiLastLinkStatus & PHY_LXT971_STAT2_DUPLEX_MODE)
551             == PHY_LXT971_STAT2_DUPLEX_MODE) {
552                 unMAC2 |= NS9750_ETH_MAC2_FULLD;
553                 unIPGT |= 0x15; /* see [1] p. 339 */
554         } else
555                 unIPGT |= 0x12; /* see [1] p. 339 */
556
557         *get_eth_reg_addr (NS9750_ETH_MAC2) = unMAC2;
558         *get_eth_reg_addr (NS9750_ETH_EGCR1) = unEGCR;
559         *get_eth_reg_addr (NS9750_ETH_IPGT) = unIPGT;
560 }
561
562 /***********************************************************************
563  * @Function: ns9750_link_print_changed
564  * @Return: void
565  * @Descr: checks whether the link status has changed and if so prints
566  *         the new mode
567  ***********************************************************************/
568
569 static void ns9750_link_print_changed (void)
570 {
571         unsigned short uiStatus;
572         unsigned short uiControl;
573
574         DEBUG_FN (DEBUG_LINK);
575
576         uiControl = ns9750_mii_read (PHY_COMMON_CTRL);
577
578         if ((uiControl & PHY_COMMON_CTRL_AUTO_NEG) ==
579             PHY_COMMON_CTRL_AUTO_NEG) {
580                 /* PHY_COMMON_STAT_LNK_STAT is only set on autonegotiation */
581                 uiStatus = ns9750_mii_read (PHY_COMMON_STAT);
582
583                 if (!(uiStatus & PHY_COMMON_STAT_LNK_STAT)) {
584                         printk (KERN_WARNING NS9750_DRIVER_NAME
585                                 ": link down\n");
586                         /* @TODO Linux: carrier_off */
587                 } else {
588                         /* @TODO Linux: carrier_on */
589                         if (phyDetected == PHY_LXT971A) {
590                                 uiStatus = ns9750_mii_read (PHY_LXT971_STAT2);
591                                 uiStatus &= (PHY_LXT971_STAT2_100BTX |
592                                              PHY_LXT971_STAT2_DUPLEX_MODE |
593                                              PHY_LXT971_STAT2_AUTO_NEG);
594
595                                 /* mask out all uninteresting parts */
596                         }
597                         /* other PHYs must store there link information in
598                            uiStatus as PHY_LXT971 */
599                 }
600         } else {
601                 /* mode has been forced, so uiStatus should be the same as the
602                    last link status, enforce printing */
603                 uiStatus = uiLastLinkStatus;
604                 uiLastLinkStatus = 0xff;
605         }
606
607         if (uiStatus != uiLastLinkStatus) {
608                 /* save current link status */
609                 uiLastLinkStatus = uiStatus;
610
611                 /* print new link status */
612
613                 printk (KERN_INFO NS9750_DRIVER_NAME
614                         ": link mode %i Mbps %s duplex %s\n",
615                         (uiStatus & PHY_LXT971_STAT2_100BTX) ? 100 : 10,
616                         (uiStatus & PHY_LXT971_STAT2_DUPLEX_MODE) ? "full" :
617                         "half",
618                         (uiStatus & PHY_LXT971_STAT2_AUTO_NEG) ? "(auto)" :
619                         "");
620         }
621 }
622
623 /***********************************************************************
624  * the MII low level stuff
625  ***********************************************************************/
626
627 /***********************************************************************
628  * @Function: ns9750_mii_identify_phy
629  * @Return: 1 if supported PHY has been detected otherwise 0
630  * @Descr: checks for supported PHY and prints the IDs.
631  ***********************************************************************/
632
633 static char ns9750_mii_identify_phy (void)
634 {
635         unsigned short uiID1;
636         unsigned short uiID2;
637         unsigned char *szName;
638         char cRes = 0;
639
640         DEBUG_FN (DEBUG_MII);
641
642         phyDetected = (PhyType) uiID1 = ns9750_mii_read (PHY_COMMON_ID1);
643
644         switch (phyDetected) {
645         case PHY_LXT971A:
646                 szName = "LXT971A";
647                 uiID2 = ns9750_mii_read (PHY_COMMON_ID2);
648                 nPhyMaxMdioClock = PHY_LXT971_MDIO_MAX_CLK;
649                 cRes = 1;
650                 break;
651         case PHY_NONE:
652         default:
653                 /* in case uiID1 == 0 && uiID2 == 0 we may have the wrong
654                    address or reset sets the wrong NS9750_ETH_MCFG_CLKS */
655
656                 uiID2 = 0;
657                 szName = "unknown";
658                 nPhyMaxMdioClock = PHY_MDIO_MAX_CLK;
659                 phyDetected = PHY_NONE;
660         }
661
662         printk (KERN_INFO NS9750_DRIVER_NAME
663                 ": PHY (0x%x, 0x%x) = %s detected\n", uiID1, uiID2, szName);
664
665         return cRes;
666 }
667
668 /***********************************************************************
669  * @Function: ns9750_mii_read
670  * @Return: the data read from PHY register uiRegister
671  * @Descr: the data read may be invalid if timed out. If so, a message
672  *         is printed but the invalid data is returned.
673  *         The fixed device address is being used.
674  ***********************************************************************/
675
676 static unsigned short ns9750_mii_read (unsigned short uiRegister)
677 {
678         DEBUG_FN (DEBUG_MII_LOW);
679
680         /* write MII register to be read */
681         *get_eth_reg_addr (NS9750_ETH_MADR) =
682                 NS9750_ETH_PHY_ADDRESS << 8 | uiRegister;
683
684         *get_eth_reg_addr (NS9750_ETH_MCMD) = NS9750_ETH_MCMD_READ;
685
686         if (!ns9750_mii_poll_busy ())
687                 printk (KERN_WARNING NS9750_DRIVER_NAME
688                         ": MII still busy in read\n");
689         /* continue to read */
690
691         *get_eth_reg_addr (NS9750_ETH_MCMD) = 0;
692
693         return (unsigned short) (*get_eth_reg_addr (NS9750_ETH_MRDD));
694 }
695
696
697 /***********************************************************************
698  * @Function: ns9750_mii_write
699  * @Return: nothing
700  * @Descr: writes the data to the PHY register. In case of a timeout,
701  *         no special handling is performed but a message printed
702  *         The fixed device address is being used.
703  ***********************************************************************/
704
705 static void ns9750_mii_write (unsigned short uiRegister,
706                               unsigned short uiData)
707 {
708         DEBUG_FN (DEBUG_MII_LOW);
709
710         /* write MII register to be written */
711         *get_eth_reg_addr (NS9750_ETH_MADR) =
712                 NS9750_ETH_PHY_ADDRESS << 8 | uiRegister;
713
714         *get_eth_reg_addr (NS9750_ETH_MWTD) = uiData;
715
716         if (!ns9750_mii_poll_busy ()) {
717                 printf (KERN_WARNING NS9750_DRIVER_NAME
718                         ": MII still busy in write\n");
719         }
720 }
721
722
723 /***********************************************************************
724  * @Function: ns9750_mii_get_clock_divisor
725  * @Return: the clock divisor that should be used in NS9750_ETH_MCFG_CLKS
726  * @Descr: if no clock divisor can be calculated for the
727  *         current SYSCLK and the maximum MDIO Clock, a warning is printed
728  *         and the greatest divisor is taken
729  ***********************************************************************/
730
731 static unsigned int ns9750_mii_get_clock_divisor (unsigned int unMaxMDIOClk)
732 {
733         struct {
734                 unsigned int unSysClkDivisor;
735                 unsigned int unClks;    /* field for NS9750_ETH_MCFG_CLKS */
736         } PHYClockDivisors[] = {
737                 {
738                 4, NS9750_ETH_MCFG_CLKS_4}, {
739                 6, NS9750_ETH_MCFG_CLKS_6}, {
740                 8, NS9750_ETH_MCFG_CLKS_8}, {
741                 10, NS9750_ETH_MCFG_CLKS_10}, {
742                 20, NS9750_ETH_MCFG_CLKS_20}, {
743                 30, NS9750_ETH_MCFG_CLKS_30}, {
744                 40, NS9750_ETH_MCFG_CLKS_40}
745         };
746
747         int nIndexSysClkDiv;
748         int nArraySize =
749                 sizeof (PHYClockDivisors) / sizeof (PHYClockDivisors[0]);
750         unsigned int unClks = NS9750_ETH_MCFG_CLKS_40;  /* defaults to
751                                                            greatest div */
752
753         DEBUG_FN (DEBUG_INIT);
754
755         for (nIndexSysClkDiv = 0; nIndexSysClkDiv < nArraySize;
756              nIndexSysClkDiv++) {
757                 /* find first sysclock divisor that isn't higher than 2.5 MHz
758                    clock */
759                 if (AHB_CLK_FREQ /
760                     PHYClockDivisors[nIndexSysClkDiv].unSysClkDivisor <=
761                     unMaxMDIOClk) {
762                         unClks = PHYClockDivisors[nIndexSysClkDiv].unClks;
763                         break;
764                 }
765         }
766
767         DEBUG_ARGS2 (DEBUG_INIT,
768                      "Taking MDIO Clock bit mask 0x%0x for max clock %i\n",
769                      unClks, unMaxMDIOClk);
770
771         /* return greatest divisor */
772         return unClks;
773 }
774
775 /***********************************************************************
776  * @Function: ns9750_mii_poll_busy
777  * @Return: 0 if timed out otherwise the remaing timeout
778  * @Descr: waits until the MII has completed a command or it times out
779  *         code may be interrupted by hard interrupts.
780  *         It is not checked what happens on multiple actions when
781  *         the first is still being busy and we timeout.
782  ***********************************************************************/
783
784 static unsigned int ns9750_mii_poll_busy (void)
785 {
786         unsigned int unTimeout = 10000;
787
788         DEBUG_FN (DEBUG_MII_LOW);
789
790         while (((*get_eth_reg_addr (NS9750_ETH_MIND) & NS9750_ETH_MIND_BUSY)
791                 == NS9750_ETH_MIND_BUSY) && unTimeout)
792                 unTimeout--;
793
794         return unTimeout;
795 }
796
797 #endif /* CONFIG_DRIVER_NS9750_ETHERNET */