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