[U-Boot] LAN91C96

Yanjun Yang yangyj.ee at gmail.com
Sat Dec 25 08:55:49 CET 2010


Hello all,

I just recently made a LAN91C96 chip work for my hardware. Some changes
to the source code might be useful to whom interested. Any comments and
suggestions are welcome.

1. The device name passed to the eth_device exceed the limit of NAMESIZE

@@ -767,8 +775,8 @@
        {8, "LAN91C100FD"},
        {7, "LAN91C100"},
        {5, "LAN91C95"},
-       {4, "LAN91C94/LAN91C96"},
-       {3, "LAN91C90/LAN91C92"},
+       {4, "LAN91C94/96"},
+       {3, "LAN91C90/92"},
 };
 /* lan91c96_detect_chip
  * See:

2. The lan91c96_detect_chip routine seems wrong, following patch is
just a quick fix.

@@ -780,7 +788,7 @@
        u8 chip_id;
        int r;
        SMC_SELECT_BANK(dev, 3);
-       chip_id = SMC_inw(dev, 0xA) & LAN91C96_REV_REVID;
+       chip_id = (SMC_inw(dev, 0xA) & LAN91C96_REV_CHIPID) >> 4;
        SMC_SELECT_BANK(dev, 0);
        for (r = 0; r < sizeof(supported_chips) / sizeof(struct id_type); r++)
                if (chip_id == supported_chips[r].id)

3. Following lines of code are necessary for my hardware, it seems that the chip
can only be reset into a known state using attribute space.


@@ -216,6 +216,8 @@
 */
 static void smc_reset(struct eth_device *dev)
 {
+       unsigned int tmp;
+
        PRINTK2("%s:smc_reset\n", dev->name);

        /* This resets the registers mostly to defaults, but doesn't
@@ -231,8 +233,13 @@

        /* set the control register */
        SMC_SELECT_BANK(dev, 1);
-       SMC_outw(dev, SMC_inw(dev, LAN91C96_CONTROL) | LAN91C96_CTR_BIT_8,
-                         LAN91C96_CONTROL);
+       tmp = SMC_inw(dev, LAN91C96_CONFIG);
+       tmp |= LAN91C96_CR_SET_SQLCH | LAN91C96_CR_NO_WAIT | LAN91C96_CR_16BIT;
+       tmp &= ~(LAN91C96_CR_DIS_LINK | LAN91C96_CR_AUI_SELECT);
+       SMC_outw(dev, tmp, LAN91C96_CONFIG);
+       SMC_outw(dev, LAN91C96_CTR_TE_ENABLE | LAN91C96_CTR_BIT_8,
LAN91C96_CONTROL);
+//     SMC_outw(dev, SMC_inw(dev, LAN91C96_CONTROL) | LAN91C96_CTR_BIT_8,
+//                       LAN91C96_CONTROL);

        /* Disable all interrupts */
        SMC_outb(dev, 0, LAN91C96_INT_MASK);
@@ -256,7 +263,7 @@
        SMC_outw(dev, LAN91C96_MCR_TRANSMIT_PAGES, LAN91C96_MCR);

        /* Initialize the Transmit Control Register */
-       SMC_outw(dev, LAN91C96_TCR_TXENA, LAN91C96_TCR);
+       SMC_outw(dev, LAN91C96_TCR_TXENA | LAN91C96_TCR_PAD_EN |
LAN91C96_TCR_FDSE, LAN91C96_TCR);
        /* Initialize the Receive Control Register
         * FIXME:
         * The promiscuous bit set because I could not receive ARP reply
@@ -791,6 +799,7 @@
 int lan91c96_initialize(u8 dev_num, int base_addr)
 {
        struct eth_device *dev;
+       volatile unsigned *attaddr = (unsigned *)CONFIG_LAN91C96_ATTR;
        int r = 0;

        dev = malloc(sizeof(*dev));
@@ -799,8 +808,19 @@
        }
        memset(dev, 0, sizeof(*dev));

-       dev->iobase = base_addr;
+       /* first reset, then enable the device. Sequence is critical */
+       attaddr[LAN91C96_ECOR] |= LAN91C96_ECOR_SRESET;
+       udelay( 750 );
+       attaddr[LAN91C96_ECOR] &= ~LAN91C96_ECOR_SRESET;
+       udelay( 750 );
+       attaddr[LAN91C96_ECOR] |= LAN91C96_ECOR_ENABLE;
+       udelay( 750 );
+
+       /* force 16-bit mode */
+       attaddr[LAN91C96_ECSR] &= ~LAN91C96_ECSR_IOIS8;
+       udelay( 750 );

+       dev->iobase = base_addr;
        /* Try to detect chip. Will fail if not present. */
        r = lan91c96_detect_chip(dev);
        if (!r) {


More information about the U-Boot mailing list