Browse Source

Patch by Mathijs Haarman, 08 May 2003:
Add lan91c96 driver (tested on Lubbock and custom PXA250 board only)

wdenk 22 năm trước cách đây
mục cha
commit
45219c4660
11 tập tin đã thay đổi với 1544 bổ sung12 xóa
  1. 3 0
      CHANGELOG
  2. 1 1
      MAKEALL
  3. 12 0
      README
  4. 17 7
      doc/README.Purple
  5. 1 1
      drivers/Makefile
  6. 858 0
      drivers/lan91c96.c
  7. 635 0
      drivers/lan91c96.h
  8. 3 1
      include/configs/lubbock.h
  9. 10 0
      lib_arm/board.c
  10. 2 2
      post/sysmon.c
  11. 2 0
      post/uart.c

+ 3 - 0
CHANGELOG

@@ -2,6 +2,9 @@
 Changes since U-Boot 0.3.1:
 ======================================================================
 
+* Patch by Mathijs Haarman, 08 May 2003:
+  Add lan91c96 driver (tested on Lubbock and custom PXA250 board only)
+
 * Fix problem with usage of "true" (undefined in current versions of bfd.h)
 
 * Add support for Promess ATC board

+ 1 - 1
MAKEALL

@@ -67,7 +67,7 @@ LIST_824x="	\
 #########################################################################
 
 LIST_8260="	\
-	ATC		cogent_mpc8260	CPU86		ep8260		\
+	atc		cogent_mpc8260	CPU86		ep8260		\
 	gw8260		hymod		IPHASE4539	MPC8260ADS	\
 	MPC8266ADS	PM826		ppmc8260	RPXsuper	\
 	rsdproto	sacsng		sbc8260		SCM		\

+ 12 - 0
README

@@ -695,6 +695,18 @@ The following options need to be configured:
 		CONFIG_NS8382X
 		Support for National dp8382[01] gigabit chips.
 
+- NETWORK Support (other):
+
+		CONFIG_DRIVER_LAN91C96
+		Support for SMSC's LAN91C96 chips.
+
+			CONFIG_LAN91C96_BASE
+			Define this to hold the physical address
+			of the LAN91C96's I/O space
+
+			CONFIG_LAN91C96_USE_32_BIT
+			Define this to enable 32 bit addressing
+
 - USB Support:
 		At the moment only the UHCI host controller is
 		supported (PIP405, MIP405); define

+ 17 - 7
doc/README.Purple

@@ -7,22 +7,32 @@ Installation Instructions:
 	------
 	|x   |
 	|   x|
-	|x   |	
-	|   X|	
+	|x   |
+	|   X|
 	------
 
    Put the s3 switch into the following position:
 
-	1   0
+	 1  0
+	------
+	| x  |
+	| x  |
+	|   x|
+	|   x|
+	------
+
+   Put the s4 switch into the following position:
+
+	 1  0
 	------
 	|x   |
 	|x   |
-	|x   |	
+	|x   |
 	|x   |
 	|x   |
 	|   x|
 	|   x|
-	|x   |	
+	|x   |
 	------
 
 2. Connect to the serial console and to the BDI. Power on. On the
@@ -54,8 +64,8 @@ Installation Instructions:
 	------
 	|   x|
 	|   x|
-	|x   |	
-	|   X|	
+	|x   |
+	|   X|
 	------
 
    Power on.  U-Boot should come up.

+ 1 - 1
drivers/Makefile

@@ -30,7 +30,7 @@ LIB	= libdrivers.a
 OBJS	= 3c589.o 5701rls.o at91rm9200_ether.o \
 	  bcm570x.o bcm570x_autoneg.o \
 	  cfb_console.o cs8900.o ct69000.o dc2114x.o \
-	  eepro100.o i8042.o inca-ip_sw.o \
+	  eepro100.o i8042.o inca-ip_sw.o lan91c96.o\
 	  natsemi.o ns16550.o ns8382x.o ns87308.o \
 	  pci.o pci_auto.o pci_indirect.o \
 	  pcnet.o plb2800_eth.o \

+ 858 - 0
drivers/lan91c96.c

@@ -0,0 +1,858 @@
+/*------------------------------------------------------------------------
+ * lan91c96.c
+ * This is a driver for SMSC's LAN91C96 single-chip Ethernet device, based
+ * on the SMC91111 driver from U-boot.
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Rolf Offermanns <rof@sysgo.de>
+ *
+ * Copyright (C) 2001 Standard Microsystems Corporation (SMSC)
+ *       Developed by Simple Network Magic Corporation (SNMC)
+ * Copyright (C) 1996 by Erik Stahlman (ES)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Information contained in this file was obtained from the LAN91C96
+ * manual from SMC.  To get a copy, if you really want one, you can find
+ * information under www.smsc.com.
+ *
+ *
+ * "Features" of the SMC chip:
+ *   6144 byte packet memory. ( for the 91C96 )
+ *   EEPROM for configuration
+ *   AUI/TP selection  ( mine has 10Base2/10BaseT select )
+ *
+ * Arguments:
+ * 	io	= for the base address
+ *	irq	= for the IRQ
+ *
+ * author:
+ * 	Erik Stahlman				( erik@vt.edu )
+ * 	Daris A Nevil				( dnevil@snmc.com )
+ *
+ *
+ * Hardware multicast code from Peter Cammaert ( pc@denkart.be )
+ *
+ * Sources:
+ *    o   SMSC LAN91C96 databook (www.smsc.com)
+ *    o   smc91111.c (u-boot driver)
+ *    o   smc9194.c (linux kernel driver)
+ *    o   lan91c96.c (Intel Diagnostic Manager driver)
+ *
+ * History:
+ * 	04/30/03  Mathijs Haarman	Modified smc91111.c (u-boot version)
+ *					for lan91c96
+ *---------------------------------------------------------------------------
+ */
+
+#include <common.h>
+#include <command.h>
+#include "lan91c96.h"
+#include <net.h>
+
+#ifdef CONFIG_DRIVER_LAN91C96
+
+#if (CONFIG_COMMANDS & CFG_CMD_NET)
+
+/*------------------------------------------------------------------------
+ *
+ * Configuration options, for the experienced user to change.
+ *
+ -------------------------------------------------------------------------*/
+
+/* Use power-down feature of the chip */
+#define POWER_DOWN	0
+
+/*
+ * Wait time for memory to be free.  This probably shouldn't be
+ * tuned that much, as waiting for this means nothing else happens
+ * in the system
+*/
+#define MEMORY_WAIT_TIME 16
+
+#define SMC_DEBUG 0
+
+#if (SMC_DEBUG > 2 )
+#define PRINTK3(args...) printf(args)
+#else
+#define PRINTK3(args...)
+#endif
+
+#if SMC_DEBUG > 1
+#define PRINTK2(args...) printf(args)
+#else
+#define PRINTK2(args...)
+#endif
+
+#ifdef SMC_DEBUG
+#define PRINTK(args...) printf(args)
+#else
+#define PRINTK(args...)
+#endif
+
+
+/*------------------------------------------------------------------------
+ *
+ * The internal workings of the driver.  If you are changing anything
+ * here with the SMC stuff, you should have the datasheet and know
+ * what you are doing.
+ *
+ *------------------------------------------------------------------------
+ */
+#define CARDNAME "LAN91C96"
+
+#define SMC_BASE_ADDRESS CONFIG_LAN91C96_BASE
+
+#define SMC_DEV_NAME "LAN91C96"
+#define SMC_ALLOC_MAX_TRY 5
+#define SMC_TX_TIMEOUT 30
+
+#define ETH_ZLEN 60
+
+#ifdef  CONFIG_LAN91C96_USE_32_BIT
+#define USE_32_BIT  1
+#else
+#undef USE_32_BIT
+#endif
+
+/*-----------------------------------------------------------------
+ *
+ *  The driver can be entered at any of the following entry points.
+ *
+ *-----------------------------------------------------------------
+ */
+
+extern int eth_init (bd_t * bd);
+extern void eth_halt (void);
+extern int eth_rx (void);
+extern int eth_send (volatile void *packet, int length);
+static int smc_hw_init (void);
+
+/*
+ * This is called by  register_netdev().  It is responsible for
+ * checking the portlist for the SMC9000 series chipset.  If it finds
+ * one, then it will initialize the device, find the hardware information,
+ * and sets up the appropriate device parameters.
+ * NOTE: Interrupts are *OFF* when this procedure is called.
+ *
+ * NB:This shouldn't be static since it is referred to externally.
+ */
+int smc_init (void);
+
+/*
+ * This is called by  unregister_netdev().  It is responsible for
+ * cleaning up before the driver is finally unregistered and discarded.
+ */
+void smc_destructor (void);
+
+/*
+ * The kernel calls this function when someone wants to use the device,
+ * typically 'ifconfig ethX up'.
+ */
+static int smc_open (void);
+
+
+/*
+ * This is called by the kernel in response to 'ifconfig ethX down'.  It
+ * is responsible for cleaning up everything that the open routine
+ * does, and maybe putting the card into a powerdown state.
+ */
+static int smc_close (void);
+
+/*
+ * This is a separate procedure to handle the receipt of a packet, to
+ * leave the interrupt code looking slightly cleaner
+ */
+static int smc_rcv (void);
+
+
+
+/* ------------------------------------------------------------
+ * Internal routines
+ * ------------------------------------------------------------
+ */
+
+static char smc_mac_addr[] = { 0xc0, 0x00, 0x00, 0x1b, 0x62, 0x9c };
+
+/*
+ * This function must be called before smc_open() if you want to override
+ * the default mac address.
+ */
+
+void smc_set_mac_addr (const char *addr)
+{
+	int i;
+
+	for (i = 0; i < sizeof (smc_mac_addr); i++) {
+		smc_mac_addr[i] = addr[i];
+	}
+}
+
+/*
+ * smc_get_macaddr is no longer used. If you want to override the default
+ * mac address, call smc_get_mac_addr as a part of the board initialisation.
+ */
+
+#if 0
+void smc_get_macaddr (byte * addr)
+{
+	/* MAC ADDRESS AT FLASHBLOCK 1 / OFFSET 0x10 */
+	unsigned char *dnp1110_mac = (unsigned char *) (0xE8000000 + 0x20010);
+	int i;
+
+
+	for (i = 0; i < 6; i++) {
+		addr[0] = *(dnp1110_mac + 0);
+		addr[1] = *(dnp1110_mac + 1);
+		addr[2] = *(dnp1110_mac + 2);
+		addr[3] = *(dnp1110_mac + 3);
+		addr[4] = *(dnp1110_mac + 4);
+		addr[5] = *(dnp1110_mac + 5);
+	}
+}
+#endif /* 0 */
+
+/***********************************************
+ * Show available memory                       *
+ ***********************************************/
+void dump_memory_info (void)
+{
+	word mem_info;
+	word old_bank;
+
+	old_bank = SMC_inw (LAN91C96_BANK_SELECT) & 0xF;
+
+	SMC_SELECT_BANK (0);
+	mem_info = SMC_inw (LAN91C96_MIR);
+	PRINTK2 ("Memory: %4d available\n", (mem_info >> 8) * 2048);
+
+	SMC_SELECT_BANK (old_bank);
+}
+
+/*
+ * A rather simple routine to print out a packet for debugging purposes.
+ */
+#if SMC_DEBUG > 2
+static void print_packet (byte *, int);
+#endif
+
+/* #define tx_done(dev) 1 */
+
+
+
+/* this does a soft reset on the device */
+static void smc_reset (void);
+
+/* Enable Interrupts, Receive, and Transmit */
+static void smc_enable (void);
+
+/* this puts the device in an inactive state */
+static void smc_shutdown (void);
+
+
+static int poll4int (byte mask, int timeout)
+{
+	int tmo = get_timer (0) + timeout * CFG_HZ;
+	int is_timeout = 0;
+	word old_bank = SMC_inw (LAN91C96_BANK_SELECT);
+
+	PRINTK2 ("Polling...\n");
+	SMC_SELECT_BANK (2);
+	while ((SMC_inw (LAN91C96_INT_STATS) & mask) == 0) {
+		if (get_timer (0) >= tmo) {
+			is_timeout = 1;
+			break;
+		}
+	}
+
+	/* restore old bank selection */
+	SMC_SELECT_BANK (old_bank);
+
+	if (is_timeout)
+		return 1;
+	else
+		return 0;
+}
+
+/*
+ * Function: smc_reset( void )
+ * Purpose:
+ *  	This sets the SMC91111 chip to its normal state, hopefully from whatever
+ * 	mess that any other DOS driver has put it in.
+ *
+ * Maybe I should reset more registers to defaults in here?  SOFTRST  should
+ * do that for me.
+ *
+ * Method:
+ *	1.  send a SOFT RESET
+ *	2.  wait for it to finish
+ *	3.  enable autorelease mode
+ *	4.  reset the memory management unit
+ *	5.  clear all interrupts
+ *
+*/
+static void smc_reset (void)
+{
+	PRINTK2 ("%s:smc_reset\n", SMC_DEV_NAME);
+
+	/* This resets the registers mostly to defaults, but doesn't
+	   affect EEPROM.  That seems unnecessary */
+	SMC_SELECT_BANK (0);
+	SMC_outw (LAN91C96_RCR_SOFT_RST, LAN91C96_RCR);
+
+	udelay (10);
+
+	/* Disable transmit and receive functionality */
+	SMC_outw (0, LAN91C96_RCR);
+	SMC_outw (0, LAN91C96_TCR);
+
+	/* set the control register */
+	SMC_SELECT_BANK (1);
+	SMC_outw (SMC_inw (LAN91C96_CONTROL) | LAN91C96_CTR_BIT_8,
+			  LAN91C96_CONTROL);
+
+	/* Disable all interrupts */
+	SMC_outb (0, LAN91C96_INT_MASK);
+}
+
+/*
+ * Function: smc_enable
+ * Purpose: let the chip talk to the outside work
+ * Method:
+ *	1.  Initialize the Memory Configuration Register
+ *	2.  Enable the transmitter
+ *	3.  Enable the receiver
+*/
+static void smc_enable ()
+{
+	PRINTK2 ("%s:smc_enable\n", SMC_DEV_NAME);
+	SMC_SELECT_BANK (0);
+
+	/* Initialize the Memory Configuration Register. See page
+	   49 of the LAN91C96 data sheet for details. */
+	SMC_outw (LAN91C96_MCR_TRANSMIT_PAGES, LAN91C96_MCR);
+
+	/* Initialize the Transmit Control Register */
+	SMC_outw (LAN91C96_TCR_TXENA, LAN91C96_TCR);
+	/* Initialize the Receive Control Register
+	 * FIXME:
+	 * The promiscuous bit set because I could not receive ARP reply
+	 * packets from the server when I send a ARP request. It only works
+	 * when I set the promiscuous bit
+	 */
+	SMC_outw (LAN91C96_RCR_RXEN | LAN91C96_RCR_PRMS, LAN91C96_RCR);
+}
+
+/*
+ * Function: smc_shutdown
+ * Purpose:  closes down the SMC91xxx chip.
+ * Method:
+ *	1. zero the interrupt mask
+ *	2. clear the enable receive flag
+ *	3. clear the enable xmit flags
+ *
+ * TODO:
+ *   (1) maybe utilize power down mode.
+ *	Why not yet?  Because while the chip will go into power down mode,
+ *	the manual says that it will wake up in response to any I/O requests
+ *	in the register space.   Empirical results do not show this working.
+ */
+static void smc_shutdown ()
+{
+	PRINTK2 (CARDNAME ":smc_shutdown\n");
+
+	/* no more interrupts for me */
+	SMC_SELECT_BANK (2);
+	SMC_outb (0, LAN91C96_INT_MASK);
+
+	/* and tell the card to stay away from that nasty outside world */
+	SMC_SELECT_BANK (0);
+	SMC_outb (0, LAN91C96_RCR);
+	SMC_outb (0, LAN91C96_TCR);
+}
+
+
+/*
+ * Function:  smc_hardware_send_packet(struct net_device * )
+ * Purpose:
+ *	This sends the actual packet to the SMC9xxx chip.
+ *
+ * Algorithm:
+ * 	First, see if a saved_skb is available.
+ *		( this should NOT be called if there is no 'saved_skb'
+ *	Now, find the packet number that the chip allocated
+ *	Point the data pointers at it in memory
+ *	Set the length word in the chip's memory
+ *	Dump the packet to chip memory
+ *	Check if a last byte is needed ( odd length packet )
+ *		if so, set the control flag right
+ * 	Tell the card to send it
+ *	Enable the transmit interrupt, so I know if it failed
+ * 	Free the kernel data if I actually sent it.
+ */
+static int smc_send_packet (volatile void *packet, int packet_length)
+{
+	byte packet_no;
+	unsigned long ioaddr;
+	byte *buf;
+	int length;
+	int numPages;
+	int try = 0;
+	int time_out;
+	byte status;
+
+
+	PRINTK3 ("%s:smc_hardware_send_packet\n", SMC_DEV_NAME);
+
+	length = ETH_ZLEN < packet_length ? packet_length : ETH_ZLEN;
+
+	/* allocate memory
+	 ** The MMU wants the number of pages to be the number of 256 bytes
+	 ** 'pages', minus 1 ( since a packet can't ever have 0 pages :) )
+	 **
+	 ** The 91C111 ignores the size bits, but the code is left intact
+	 ** for backwards and future compatibility.
+	 **
+	 ** Pkt size for allocating is data length +6 (for additional status
+	 ** words, length and ctl!)
+	 **
+	 ** If odd size then last byte is included in this header.
+	 */
+	numPages = ((length & 0xfffe) + 6);
+	numPages >>= 8;				/* Divide by 256 */
+
+	if (numPages > 7) {
+		printf ("%s: Far too big packet error. \n", SMC_DEV_NAME);
+		return 0;
+	}
+
+	/* now, try to allocate the memory */
+
+	SMC_SELECT_BANK (2);
+	SMC_outw (LAN91C96_MMUCR_ALLOC_TX | numPages, LAN91C96_MMU);
+
+  again:
+	try++;
+	time_out = MEMORY_WAIT_TIME;
+	do {
+		status = SMC_inb (LAN91C96_INT_STATS);
+		if (status & LAN91C96_IST_ALLOC_INT) {
+
+			SMC_outb (LAN91C96_IST_ALLOC_INT, LAN91C96_INT_STATS);
+			break;
+		}
+	} while (--time_out);
+
+	if (!time_out) {
+		PRINTK2 ("%s: memory allocation, try %d failed ...\n",
+				 SMC_DEV_NAME, try);
+		if (try < SMC_ALLOC_MAX_TRY)
+			goto again;
+		else
+			return 0;
+	}
+
+	PRINTK2 ("%s: memory allocation, try %d succeeded ...\n",
+			 SMC_DEV_NAME, try);
+
+	/* I can send the packet now.. */
+
+	ioaddr = SMC_BASE_ADDRESS;
+
+	buf = (byte *) packet;
+
+	/* If I get here, I _know_ there is a packet slot waiting for me */
+	packet_no = SMC_inb (LAN91C96_ARR);
+	if (packet_no & LAN91C96_ARR_FAILED) {
+		/* or isn't there?  BAD CHIP! */
+		printf ("%s: Memory allocation failed. \n", SMC_DEV_NAME);
+		return 0;
+	}
+
+	/* we have a packet address, so tell the card to use it */
+	SMC_outb (packet_no, LAN91C96_PNR);
+
+	/* point to the beginning of the packet */
+	SMC_outw (LAN91C96_PTR_AUTO_INCR, LAN91C96_POINTER);
+
+	PRINTK3 ("%s: Trying to xmit packet of length %x\n",
+			 SMC_DEV_NAME, length);
+
+#if SMC_DEBUG > 2
+	printf ("Transmitting Packet\n");
+	print_packet (buf, length);
+#endif
+
+	/* send the packet length ( +6 for status, length and ctl byte )
+	   and the status word ( set to zeros ) */
+#ifdef USE_32_BIT
+	SMC_outl ((length + 6) << 16, LAN91C96_DATA_HIGH);
+#else
+	SMC_outw (0, LAN91C96_DATA_HIGH);
+	/* send the packet length ( +6 for status words, length, and ctl */
+	SMC_outw ((length + 6), LAN91C96_DATA_HIGH);
+#endif /* USE_32_BIT */
+
+	/* send the actual data
+	 * I _think_ it's faster to send the longs first, and then
+	 * mop up by sending the last word.  It depends heavily
+	 * on alignment, at least on the 486.  Maybe it would be
+	 * a good idea to check which is optimal?  But that could take
+	 * almost as much time as is saved?
+	 */
+#ifdef USE_32_BIT
+	SMC_outsl (LAN91C96_DATA_HIGH, buf, length >> 2);
+	if (length & 0x2)
+		SMC_outw (*((word *) (buf + (length & 0xFFFFFFFC))),
+				  LAN91C96_DATA_HIGH);
+#else
+	SMC_outsw (LAN91C96_DATA_HIGH, buf, (length) >> 1);
+#endif /* USE_32_BIT */
+
+	/* Send the last byte, if there is one.   */
+	if ((length & 1) == 0) {
+		SMC_outw (0, LAN91C96_DATA_HIGH);
+	} else {
+		SMC_outw (buf[length - 1] | 0x2000, LAN91C96_DATA_HIGH);
+	}
+
+	/* and let the chipset deal with it */
+	SMC_outw (LAN91C96_MMUCR_ENQUEUE, LAN91C96_MMU);
+
+	/* poll for TX INT */
+	if (poll4int (LAN91C96_MSK_TX_INT, SMC_TX_TIMEOUT)) {
+		/* sending failed */
+		PRINTK2 ("%s: TX timeout, sending failed...\n", SMC_DEV_NAME);
+
+		/* release packet */
+		SMC_outw (LAN91C96_MMUCR_RELEASE_TX, LAN91C96_MMU);
+
+		/* wait for MMU getting ready (low) */
+		while (SMC_inw (LAN91C96_MMU) & LAN91C96_MMUCR_NO_BUSY) {
+			udelay (10);
+		}
+
+		PRINTK2 ("MMU ready\n");
+
+
+		return 0;
+	} else {
+		/* ack. int */
+		SMC_outw (LAN91C96_IST_TX_INT, LAN91C96_INT_STATS);
+
+		PRINTK2 ("%s: Sent packet of length %d \n", SMC_DEV_NAME, length);
+
+		/* release packet */
+		SMC_outw (LAN91C96_MMUCR_RELEASE_TX, LAN91C96_MMU);
+
+		/* wait for MMU getting ready (low) */
+		while (SMC_inw (LAN91C96_MMU) & LAN91C96_MMUCR_NO_BUSY) {
+			udelay (10);
+		}
+
+		PRINTK2 ("MMU ready\n");
+	}
+
+	return length;
+}
+
+/*-------------------------------------------------------------------------
+ * smc_destructor( struct net_device * dev )
+ *   Input parameters:
+ *	dev, pointer to the device structure
+ *
+ *   Output:
+ *	None.
+ *--------------------------------------------------------------------------
+ */
+void smc_destructor ()
+{
+	PRINTK2 (CARDNAME ":smc_destructor\n");
+}
+
+
+/*
+ * Open and Initialize the board
+ *
+ * Set up everything, reset the card, etc ..
+ *
+ */
+static int smc_open ()
+{
+	int i;			/* used to set hw ethernet address */
+
+	PRINTK2 ("%s:smc_open\n", SMC_DEV_NAME);
+
+	/* reset the hardware */
+
+	smc_reset ();
+	smc_enable ();
+
+	SMC_SELECT_BANK (1);
+
+	for (i = 0; i < 6; i += 2) {
+		word address;
+
+		address = smc_mac_addr[i + 1] << 8;
+		address |= smc_mac_addr[i];
+		SMC_outw (address, LAN91C96_IA0 + i);
+	}
+	return 0;
+}
+
+/*-------------------------------------------------------------
+ *
+ * smc_rcv -  receive a packet from the card
+ *
+ * There is ( at least ) a packet waiting to be read from
+ * chip-memory.
+ *
+ * o Read the status
+ * o If an error, record it
+ * o otherwise, read in the packet
+ *-------------------------------------------------------------
+ */
+static int smc_rcv ()
+{
+	int packet_number;
+	word status;
+	word packet_length;
+	int is_error = 0;
+
+#ifdef USE_32_BIT
+	dword stat_len;
+#endif
+
+
+	SMC_SELECT_BANK (2);
+	packet_number = SMC_inw (LAN91C96_FIFO);
+
+	if (packet_number & LAN91C96_FIFO_RXEMPTY) {
+		return 0;
+	}
+
+	PRINTK3 ("%s:smc_rcv\n", SMC_DEV_NAME);
+	/*  start reading from the start of the packet */
+	SMC_outw (LAN91C96_PTR_READ | LAN91C96_PTR_RCV |
+			  LAN91C96_PTR_AUTO_INCR, LAN91C96_POINTER);
+
+	/* First two words are status and packet_length */
+#ifdef USE_32_BIT
+	stat_len = SMC_inl (LAN91C96_DATA_HIGH);
+	status = stat_len & 0xffff;
+	packet_length = stat_len >> 16;
+#else
+	status = SMC_inw (LAN91C96_DATA_HIGH);
+	packet_length = SMC_inw (LAN91C96_DATA_HIGH);
+#endif
+
+	packet_length &= 0x07ff;	/* mask off top bits */
+
+	PRINTK2 ("RCV: STATUS %4x LENGTH %4x\n", status, packet_length);
+
+	if (!(status & FRAME_FILTER)) {
+		/* Adjust for having already read the first two words */
+		packet_length -= 4;		/*4; */
+
+
+
+		/* set odd length for bug in LAN91C111, */
+		/* which never sets RS_ODDFRAME */
+		/* TODO ? */
+
+
+#ifdef USE_32_BIT
+		PRINTK3 (" Reading %d dwords (and %d bytes) \n",
+			 packet_length >> 2, packet_length & 3);
+		/* QUESTION:  Like in the TX routine, do I want
+		   to send the DWORDs or the bytes first, or some
+		   mixture.  A mixture might improve already slow PIO
+		   performance  */
+		SMC_insl (LAN91C96_DATA_HIGH, NetRxPackets[0], packet_length >> 2);
+		/* read the left over bytes */
+		if (packet_length & 3) {
+			int i;
+
+			byte *tail = (byte *) (NetRxPackets[0] + (packet_length & ~3));
+			dword leftover = SMC_inl (LAN91C96_DATA_HIGH);
+
+			for (i = 0; i < (packet_length & 3); i++)
+				*tail++ = (byte) (leftover >> (8 * i)) & 0xff;
+		}
+#else
+		PRINTK3 (" Reading %d words and %d byte(s) \n",
+				 (packet_length >> 1), packet_length & 1);
+		SMC_insw (LAN91C96_DATA_HIGH, NetRxPackets[0], packet_length >> 1);
+
+#endif /* USE_32_BIT */
+
+#if	SMC_DEBUG > 2
+		printf ("Receiving Packet\n");
+		print_packet (NetRxPackets[0], packet_length);
+#endif
+	} else {
+		/* error ... */
+		/* TODO ? */
+		is_error = 1;
+	}
+
+	while (SMC_inw (LAN91C96_MMU) & LAN91C96_MMUCR_NO_BUSY)
+		udelay (1);		/* Wait until not busy */
+
+	/*  error or good, tell the card to get rid of this packet */
+	SMC_outw (LAN91C96_MMUCR_RELEASE_RX, LAN91C96_MMU);
+
+	while (SMC_inw (LAN91C96_MMU) & LAN91C96_MMUCR_NO_BUSY)
+		udelay (1);		/* Wait until not busy */
+
+	if (!is_error) {
+		/* Pass the packet up to the protocol layers. */
+		NetReceive (NetRxPackets[0], packet_length);
+		return packet_length;
+	} else {
+		return 0;
+	}
+
+}
+
+/*----------------------------------------------------
+ * smc_close
+ *
+ * this makes the board clean up everything that it can
+ * and not talk to the outside world.   Caused by
+ * an 'ifconfig ethX down'
+ *
+ -----------------------------------------------------*/
+static int smc_close ()
+{
+	PRINTK2 ("%s:smc_close\n", SMC_DEV_NAME);
+
+	/* clear everything */
+	smc_shutdown ();
+
+	return 0;
+}
+
+#if SMC_DEBUG > 2
+static void print_packet (byte * buf, int length)
+{
+#if 0
+	int i;
+	int remainder;
+	int lines;
+
+	printf ("Packet of length %d \n", length);
+
+	lines = length / 16;
+	remainder = length % 16;
+
+	for (i = 0; i < lines; i++) {
+		int cur;
+
+		for (cur = 0; cur < 8; cur++) {
+			byte a, b;
+
+			a = *(buf++);
+			b = *(buf++);
+			printf ("%02x%02x ", a, b);
+		}
+		printf ("\n");
+	}
+	for (i = 0; i < remainder / 2; i++) {
+		byte a, b;
+
+		a = *(buf++);
+		b = *(buf++);
+		printf ("%02x%02x ", a, b);
+	}
+	printf ("\n");
+#endif /* 0 */
+}
+#endif /* SMC_DEBUG > 2 */
+
+int eth_init (bd_t * bd)
+{
+	smc_open ();
+	return 0;
+}
+
+void eth_halt ()
+{
+	smc_close ();
+}
+
+int eth_rx ()
+{
+	return smc_rcv ();
+}
+
+int eth_send (volatile void *packet, int length)
+{
+	return smc_send_packet (packet, length);
+}
+
+int eth_hw_init ()
+{
+	return smc_hw_init ();
+}
+
+/*-------------------------------------------------------------------------
+ * smc_hw_init()
+ *
+ *   Function:
+ *      Reset and enable the device, check if the I/O space location
+ *      is correct
+ *
+ *   Input parameters:
+ *      None
+ *
+ *   Output:
+ *	0 --> success
+ *	1 --> error
+ *--------------------------------------------------------------------------
+ */
+static int smc_hw_init ()
+{
+	unsigned short status_test;
+
+	/* The attribute register of the LAN91C96 is located at address
+	   0x0e000000 on the lubbock platform */
+	volatile unsigned *attaddr = (unsigned *) (0x0e000000);
+
+	/* first reset, then enable the device. Sequence is critical */
+	attaddr[LAN91C96_ECOR] |= LAN91C96_ECOR_SRESET;
+	udelay (100);
+	attaddr[LAN91C96_ECOR] &= ~LAN91C96_ECOR_SRESET;
+	attaddr[LAN91C96_ECOR] |= LAN91C96_ECOR_ENABLE;
+
+	/* force 16-bit mode */
+	attaddr[LAN91C96_ECSR] &= ~LAN91C96_ECSR_IOIS8;
+	udelay (100);
+
+	/* check if the I/O address is correct, the upper byte of the
+	   bank select register should read 0x33 */
+
+	status_test = SMC_inw (LAN91C96_BANK_SELECT);
+	if ((status_test & 0xFF00) != 0x3300) {
+		printf ("Failed to initialize ethernetchip\n");
+		return 1;
+	}
+	return 0;
+}
+
+#endif /* COMMANDS & CFG_NET */
+
+#endif /* CONFIG_DRIVER_LAN91C96 */

+ 635 - 0
drivers/lan91c96.h

@@ -0,0 +1,635 @@
+/*------------------------------------------------------------------------
+ * lan91c96.h
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Rolf Offermanns <rof@sysgo.de>
+ * Copyright (C) 2001 Standard Microsystems Corporation (SMSC)
+ *       Developed by Simple Network Magic Corporation (SNMC)
+ * Copyright (C) 1996 by Erik Stahlman (ES)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * This file contains register information and access macros for
+ * the LAN91C96 single chip ethernet controller.  It is a modified
+ * version of the smc9111.h file.
+ *
+ * Information contained in this file was obtained from the LAN91C96
+ * manual from SMC. To get a copy, if you really want one, you can find
+ * information under www.smsc.com.
+ *
+ * Authors
+ * 	Erik Stahlman				( erik@vt.edu )
+ *	Daris A Nevil				( dnevil@snmc.com )
+ *
+ * History
+ * 04/30/03	Mathijs Haarman		Modified smc91111.h (u-boot version)
+ *		                        for lan91c96
+ *-------------------------------------------------------------------------
+ */
+#ifndef _LAN91C96_H_
+#define _LAN91C96_H_
+
+#include <asm/types.h>
+#include <asm/io.h>
+#include <config.h>
+
+/*
+ * This function may be called by the board specific initialisation code
+ * in order to override the default mac address.
+ */
+
+void smc_set_mac_addr(const char *addr);
+int eth_hw_init(void);
+
+
+/* I want some simple types */
+
+typedef unsigned char			byte;
+typedef unsigned short			word;
+typedef unsigned long int 		dword;
+
+/*
+ * DEBUGGING LEVELS
+ *
+ * 0 for normal operation
+ * 1 for slightly more details
+ * >2 for various levels of increasingly useless information
+ *    2 for interrupt tracking, status flags
+ *    3 for packet info
+ *    4 for complete packet dumps
+ */
+/*#define SMC_DEBUG 0 */
+
+/* Because of bank switching, the LAN91xxx uses only 16 I/O ports */
+
+#define	SMC_IO_EXTENT	16
+
+#ifdef CONFIG_PXA250
+
+#define	SMC_inl(r) 	(*((volatile dword *)(SMC_BASE_ADDRESS+( r * 4 ))))
+#define	SMC_inw(r) 	(*((volatile word *)(SMC_BASE_ADDRESS+( r * 4 ))))
+#define SMC_inb(p)	({ \
+	unsigned int __p = (unsigned int)(SMC_BASE_ADDRESS + (p * 4)); \
+	unsigned int __v = *(volatile unsigned short *)((__p) & ~1); \
+	if (__p & 1) __v >>= 8; \
+	else __v &= 0xff; \
+	__v; })
+
+#define	SMC_outl(d,r)	(*((volatile dword *)(SMC_BASE_ADDRESS+(r * 4))) = d)
+#define	SMC_outw(d,r)	(*((volatile word *)(SMC_BASE_ADDRESS+(r * 4))) = d)
+#define	SMC_outb(d,r)	({	word __d = (byte)(d);  \
+				word __w = SMC_inw((r)&~1);  \
+				__w &= ((r)&1) ? 0x00FF : 0xFF00;  \
+				__w |= ((r)&1) ? __d<<8 : __d;  \
+				SMC_outw(__w,(r)&~1);  \
+			})
+
+#define SMC_outsl(r,b,l)	({	int __i; \
+					dword *__b2; \
+					__b2 = (dword *) b; \
+					for (__i = 0; __i < l; __i++) { \
+					    SMC_outl( *(__b2 + __i), r ); \
+					} \
+				})
+
+#define SMC_outsw(r,b,l)	({	int __i; \
+					word *__b2; \
+					__b2 = (word *) b; \
+					for (__i = 0; __i < l; __i++) { \
+					    SMC_outw( *(__b2 + __i), r ); \
+					} \
+				})
+
+#define SMC_insl(r,b,l) 	({	int __i ;  \
+					dword *__b2;  \
+			    		__b2 = (dword *) b;  \
+			    		for (__i = 0; __i < l; __i++) {  \
+					  *(__b2 + __i) = SMC_inl(r);  \
+					  SMC_inl(0);  \
+					};  \
+				})
+
+#define SMC_insw(r,b,l) 	({	int __i ;  \
+					word *__b2;  \
+			    		__b2 = (word *) b;  \
+			    		for (__i = 0; __i < l; __i++) {  \
+					  *(__b2 + __i) = SMC_inw(r);  \
+					  SMC_inw(0);  \
+					};  \
+				})
+
+#define SMC_insb(r,b,l) 	({	int __i ;  \
+					byte *__b2;  \
+			    		__b2 = (byte *) b;  \
+			    		for (__i = 0; __i < l; __i++) {  \
+					  *(__b2 + __i) = SMC_inb(r);  \
+					  SMC_inb(0);  \
+					};  \
+				})
+
+#else /* if not CONFIG_PXA250 */
+
+/*
+ * We have only 16 Bit PCMCIA access on Socket 0
+ */
+
+#define	SMC_inw(r) 	(*((volatile word *)(SMC_BASE_ADDRESS+(r))))
+#define  SMC_inb(r)	(((r)&1) ? SMC_inw((r)&~1)>>8 : SMC_inw(r)&0xFF)
+
+#define	SMC_outw(d,r)	(*((volatile word *)(SMC_BASE_ADDRESS+(r))) = d)
+#define	SMC_outb(d,r)	({	word __d = (byte)(d);  \
+				word __w = SMC_inw((r)&~1);  \
+				__w &= ((r)&1) ? 0x00FF : 0xFF00;  \
+				__w |= ((r)&1) ? __d<<8 : __d;  \
+				SMC_outw(__w,(r)&~1);  \
+			})
+#if 0
+#define	SMC_outsw(r,b,l)	outsw(SMC_BASE_ADDRESS+(r), (b), (l))
+#else
+#define SMC_outsw(r,b,l)	({	int __i; \
+					word *__b2; \
+					__b2 = (word *) b; \
+					for (__i = 0; __i < l; __i++) { \
+					    SMC_outw( *(__b2 + __i), r); \
+					} \
+				})
+#endif
+
+#if 0
+#define	SMC_insw(r,b,l) 	insw(SMC_BASE_ADDRESS+(r), (b), (l))
+#else
+#define SMC_insw(r,b,l) 	({	int __i ;  \
+					word *__b2;  \
+			    		__b2 = (word *) b;  \
+			    		for (__i = 0; __i < l; __i++) {  \
+					  *(__b2 + __i) = SMC_inw(r);  \
+					  SMC_inw(0);  \
+					};  \
+				})
+#endif
+
+#endif
+
+/*
+ ****************************************************************************
+ *	Bank Select Field
+ ****************************************************************************
+ */
+#define LAN91C96_BANK_SELECT  14       // Bank Select Register
+#define LAN91C96_BANKSELECT (0x3UC << 0)
+#define BANK0               0x00
+#define BANK1               0x01
+#define BANK2               0x02
+#define BANK3               0x03
+#define BANK4               0x04
+
+/*
+ ****************************************************************************
+ *	EEPROM Addresses.
+ ****************************************************************************
+ */
+#define EEPROM_MAC_OFFSET_1    0x6020
+#define EEPROM_MAC_OFFSET_2    0x6021
+#define EEPROM_MAC_OFFSET_3    0x6022
+
+/*
+ ****************************************************************************
+ *	Bank 0 Register Map in I/O Space
+ ****************************************************************************
+ */
+#define LAN91C96_TCR          0        // Transmit Control Register
+#define LAN91C96_EPH_STATUS   2        // EPH Status Register
+#define LAN91C96_RCR          4        // Receive Control Register
+#define LAN91C96_COUNTER      6        // Counter Register
+#define LAN91C96_MIR          8        // Memory Information Register
+#define LAN91C96_MCR          10       // Memory Configuration Register
+
+/*
+ ****************************************************************************
+ *	Transmit Control Register - Bank 0 - Offset 0
+ ****************************************************************************
+ */
+#define LAN91C96_TCR_TXENA        (0x1U << 0)
+#define LAN91C96_TCR_LOOP         (0x1U << 1)
+#define LAN91C96_TCR_FORCOL       (0x1U << 2)
+#define LAN91C96_TCR_TXP_EN       (0x1U << 3)
+#define LAN91C96_TCR_PAD_EN       (0x1U << 7)
+#define LAN91C96_TCR_NOCRC        (0x1U << 8)
+#define LAN91C96_TCR_MON_CSN      (0x1U << 10)
+#define LAN91C96_TCR_FDUPLX       (0x1U << 11)
+#define LAN91C96_TCR_STP_SQET     (0x1U << 12)
+#define LAN91C96_TCR_EPH_LOOP     (0x1U << 13)
+#define LAN91C96_TCR_ETEN_TYPE    (0x1U << 14)
+#define LAN91C96_TCR_FDSE         (0x1U << 15)
+
+/*
+ ****************************************************************************
+ *	EPH Status Register - Bank 0 - Offset 2
+ ****************************************************************************
+ */
+#define LAN91C96_EPHSR_TX_SUC     (0x1U << 0)
+#define LAN91C96_EPHSR_SNGL_COL   (0x1U << 1)
+#define LAN91C96_EPHSR_MUL_COL    (0x1U << 2)
+#define LAN91C96_EPHSR_LTX_MULT   (0x1U << 3)
+#define LAN91C96_EPHSR_16COL      (0x1U << 4)
+#define LAN91C96_EPHSR_SQET       (0x1U << 5)
+#define LAN91C96_EPHSR_LTX_BRD    (0x1U << 6)
+#define LAN91C96_EPHSR_TX_DEFR    (0x1U << 7)
+#define LAN91C96_EPHSR_WAKEUP     (0x1U << 8)
+#define LAN91C96_EPHSR_LATCOL     (0x1U << 9)
+#define LAN91C96_EPHSR_LOST_CARR  (0x1U << 10)
+#define LAN91C96_EPHSR_EXC_DEF    (0x1U << 11)
+#define LAN91C96_EPHSR_CTR_ROL    (0x1U << 12)
+
+#define LAN91C96_EPHSR_LINK_OK    (0x1U << 14)
+#define LAN91C96_EPHSR_TX_UNRN    (0x1U << 15)
+
+#define LAN91C96_EPHSR_ERRORS     (LAN91C96_EPHSR_SNGL_COL  |    \
+                                   LAN91C96_EPHSR_MUL_COL   |    \
+                                   LAN91C96_EPHSR_16COL     |    \
+                                   LAN91C96_EPHSR_SQET      |    \
+                                   LAN91C96_EPHSR_TX_DEFR   |    \
+                                   LAN91C96_EPHSR_LATCOL    |    \
+                                   LAN91C96_EPHSR_LOST_CARR |    \
+                                   LAN91C96_EPHSR_EXC_DEF   |    \
+                                   LAN91C96_EPHSR_LINK_OK   |    \
+                                   LAN91C96_EPHSR_TX_UNRN)
+
+/*
+ ****************************************************************************
+ *	Receive Control Register - Bank 0 - Offset 4
+ ****************************************************************************
+ */
+#define LAN91C96_RCR_RX_ABORT     (0x1U << 0)
+#define LAN91C96_RCR_PRMS         (0x1U << 1)
+#define LAN91C96_RCR_ALMUL        (0x1U << 2)
+#define LAN91C96_RCR_RXEN         (0x1U << 8)
+#define LAN91C96_RCR_STRIP_CRC    (0x1U << 9)
+#define LAN91C96_RCR_FILT_CAR     (0x1U << 14)
+#define LAN91C96_RCR_SOFT_RST     (0x1U << 15)
+
+/*
+ ****************************************************************************
+ *	Counter Register - Bank 0 - Offset 6
+ ****************************************************************************
+ */
+#define LAN91C96_ECR_SNGL_COL     (0xFU << 0)
+#define LAN91C96_ECR_MULT_COL     (0xFU << 5)
+#define LAN91C96_ECR_DEF_TX       (0xFU << 8)
+#define LAN91C96_ECR_EXC_DEF_TX   (0xFU << 12)
+
+/*
+ ****************************************************************************
+ *	Memory Information Register - Bank 0 - OFfset 8
+ ****************************************************************************
+ */
+#define LAN91C96_MIR_SIZE        (0x18 << 0)    // 6144 bytes
+
+/*
+ ****************************************************************************
+ *	Memory Configuration Register - Bank 0 - Offset 10
+ ****************************************************************************
+ */
+#define LAN91C96_MCR_MEM_RES      (0xFFU << 0)
+#define LAN91C96_MCR_MEM_MULT     (0x3U << 9)
+#define LAN91C96_MCR_HIGH_ID      (0x3U << 12)
+
+#define LAN91C96_MCR_TRANSMIT_PAGES 0x6
+
+/*
+ ****************************************************************************
+ *	Bank 1 Register Map in I/O Space
+ ****************************************************************************
+ */
+#define LAN91C96_CONFIG       0        // Configuration Register
+#define LAN91C96_BASE         2        // Base Address Register
+#define LAN91C96_IA0          4        // Individual Address Register - 0
+#define LAN91C96_IA1          5        // Individual Address Register - 1
+#define LAN91C96_IA2          6        // Individual Address Register - 2
+#define LAN91C96_IA3          7        // Individual Address Register - 3
+#define LAN91C96_IA4          8        // Individual Address Register - 4
+#define LAN91C96_IA5          9        // Individual Address Register - 5
+#define LAN91C96_GEN_PURPOSE  10       // General Address Registers
+#define LAN91C96_CONTROL      12       // Control Register
+
+/*
+ ****************************************************************************
+ *	Configuration Register - Bank 1 - Offset 0
+ ****************************************************************************
+ */
+#define LAN91C96_CR_INT_SEL0      (0x1U << 1)
+#define LAN91C96_CR_INT_SEL1      (0x1U << 2)
+#define LAN91C96_CR_RES           (0x3U << 3)
+#define LAN91C96_CR_DIS_LINK      (0x1U << 6)
+#define LAN91C96_CR_16BIT         (0x1U << 7)
+#define LAN91C96_CR_AUI_SELECT    (0x1U << 8)
+#define LAN91C96_CR_SET_SQLCH     (0x1U << 9)
+#define LAN91C96_CR_FULL_STEP     (0x1U << 10)
+#define LAN91C96_CR_NO_WAIT       (0x1U << 12)
+
+/*
+ ****************************************************************************
+ *	Base Address Register - Bank 1 - Offset 2
+ ****************************************************************************
+ */
+#define LAN91C96_BAR_RA_BITS      (0x27U << 0)
+#define LAN91C96_BAR_ROM_SIZE     (0x1U << 6)
+#define LAN91C96_BAR_A_BITS       (0xFFU << 8)
+
+/*
+ ****************************************************************************
+ *	Control Register - Bank 1 - Offset 12
+ ****************************************************************************
+ */
+#define LAN91C96_CTR_STORE        (0x1U << 0)
+#define LAN91C96_CTR_RELOAD       (0x1U << 1)
+#define LAN91C96_CTR_EEPROM       (0x1U << 2)
+#define LAN91C96_CTR_TE_ENABLE    (0x1U << 5)
+#define LAN91C96_CTR_CR_ENABLE    (0x1U << 6)
+#define LAN91C96_CTR_LE_ENABLE    (0x1U << 7)
+#define LAN91C96_CTR_BIT_8        (0x1U << 8)
+#define LAN91C96_CTR_AUTO_RELEASE (0x1U << 11)
+#define LAN91C96_CTR_WAKEUP_EN    (0x1U << 12)
+#define LAN91C96_CTR_PWRDN        (0x1U << 13)
+#define LAN91C96_CTR_RCV_BAD      (0x1U << 14)
+
+/*
+ ****************************************************************************
+ *	Bank 2 Register Map in I/O Space
+ ****************************************************************************
+ */
+#define LAN91C96_MMU            0      // MMU Command Register
+#define LAN91C96_AUTO_TX_START  1      // Auto Tx Start Register
+#define LAN91C96_PNR            2      // Packet Number Register
+#define LAN91C96_ARR            3      // Allocation Result Register
+#define LAN91C96_FIFO           4      // FIFO Ports Register
+#define LAN91C96_POINTER        6      // Pointer Register
+#define LAN91C96_DATA_HIGH      8      // Data High Register
+#define LAN91C96_DATA_LOW       10     // Data Low Register
+#define LAN91C96_INT_STATS      12     // Interrupt Status Register - RO
+#define LAN91C96_INT_ACK        12     // Interrupt Acknowledge Register -WO
+#define LAN91C96_INT_MASK       13     // Interrupt Mask Register
+
+/*
+ ****************************************************************************
+ *	MMU Command Register - Bank 2 - Offset 0
+ ****************************************************************************
+ */
+#define LAN91C96_MMUCR_NO_BUSY    (0x1U << 0)
+#define LAN91C96_MMUCR_N1         (0x1U << 1)
+#define LAN91C96_MMUCR_N2         (0x1U << 2)
+#define LAN91C96_MMUCR_COMMAND    (0xFU << 4)
+#define LAN91C96_MMUCR_ALLOC_TX   (0x2U << 4)    // WXYZ = 0010
+#define LAN91C96_MMUCR_RESET_MMU  (0x4U << 4)    // WXYZ = 0100
+#define LAN91C96_MMUCR_REMOVE_RX  (0x6U << 4)    // WXYZ = 0110
+#define LAN91C96_MMUCR_REMOVE_TX  (0x7U << 4)    // WXYZ = 0111
+#define LAN91C96_MMUCR_RELEASE_RX (0x8U << 4)    // WXYZ = 1000
+#define LAN91C96_MMUCR_RELEASE_TX (0xAU << 4)    // WXYZ = 1010
+#define LAN91C96_MMUCR_ENQUEUE    (0xCU << 4)    // WXYZ = 1100
+#define LAN91C96_MMUCR_RESET_TX   (0xEU << 4)    // WXYZ = 1110
+
+/*
+ ****************************************************************************
+ *	Auto Tx Start Register - Bank 2 - Offset 1
+ ****************************************************************************
+ */
+#define LAN91C96_AUTOTX           (0xFFU << 0)
+
+/*
+ ****************************************************************************
+ *	Packet Number Register - Bank 2 - Offset 2
+ ****************************************************************************
+ */
+#define LAN91C96_PNR_TX           (0x1FU << 0)
+
+/*
+ ****************************************************************************
+ *	Allocation Result Register - Bank 2 - Offset 3
+ ****************************************************************************
+ */
+#define LAN91C96_ARR_ALLOC_PN     (0x7FU << 0)
+#define LAN91C96_ARR_FAILED       (0x1U << 7)
+
+/*
+ ****************************************************************************
+ *	FIFO Ports Register - Bank 2 - Offset 4
+ ****************************************************************************
+ */
+#define LAN91C96_FIFO_TX_DONE_PN  (0x1FU << 0)
+#define LAN91C96_FIFO_TEMPTY      (0x1U << 7)
+#define LAN91C96_FIFO_RX_DONE_PN  (0x1FU << 8)
+#define LAN91C96_FIFO_RXEMPTY     (0x1U << 15)
+
+/*
+ ****************************************************************************
+ *	Pointer Register - Bank 2 - Offset 6
+ ****************************************************************************
+ */
+#define LAN91C96_PTR_LOW          (0xFFU << 0)
+#define LAN91C96_PTR_HIGH         (0x7U << 8)
+#define LAN91C96_PTR_AUTO_TX      (0x1U << 11)
+#define LAN91C96_PTR_ETEN         (0x1U << 12)
+#define LAN91C96_PTR_READ         (0x1U << 13)
+#define LAN91C96_PTR_AUTO_INCR    (0x1U << 14)
+#define LAN91C96_PTR_RCV          (0x1U << 15)
+
+#define LAN91C96_PTR_RX_FRAME     (LAN91C96_PTR_RCV       |    \
+                                   LAN91C96_PTR_AUTO_INCR |    \
+                                   LAN91C96_PTR_READ)
+
+/*
+ ****************************************************************************
+ *	Data Register - Bank 2 - Offset 8
+ ****************************************************************************
+ */
+#define LAN91C96_CONTROL_CRC      (0x1U << 4)    // CRC bit
+#define LAN91C96_CONTROL_ODD      (0x1U << 5)    // ODD bit
+
+/*
+ ****************************************************************************
+ *	Interrupt Status Register - Bank 2 - Offset 12
+ ****************************************************************************
+ */
+#define LAN91C96_IST_RCV_INT      (0x1U << 0)
+#define LAN91C96_IST_TX_INT       (0x1U << 1)
+#define LAN91C96_IST_TX_EMPTY_INT (0x1U << 2)
+#define LAN91C96_IST_ALLOC_INT    (0x1U << 3)
+#define LAN91C96_IST_RX_OVRN_INT  (0x1U << 4)
+#define LAN91C96_IST_EPH_INT      (0x1U << 5)
+#define LAN91C96_IST_ERCV_INT     (0x1U << 6)
+#define LAN91C96_IST_RX_IDLE_INT  (0x1U << 7)
+
+/*
+ ****************************************************************************
+ *	Interrupt Acknowledge Register - Bank 2 - Offset 12
+ ****************************************************************************
+ */
+#define LAN91C96_ACK_TX_INT       (0x1U << 1)
+#define LAN91C96_ACK_TX_EMPTY_INT (0x1U << 2)
+#define LAN91C96_ACK_RX_OVRN_INT  (0x1U << 4)
+#define LAN91C96_ACK_ERCV_INT     (0x1U << 6)
+
+/*
+ ****************************************************************************
+ *	Interrupt Mask Register - Bank 2 - Offset 13
+ ****************************************************************************
+ */
+#define LAN91C96_MSK_RCV_INT      (0x1U << 0)
+#define LAN91C96_MSK_TX_INT       (0x1U << 1)
+#define LAN91C96_MSK_TX_EMPTY_INT (0x1U << 2)
+#define LAN91C96_MSK_ALLOC_INT    (0x1U << 3)
+#define LAN91C96_MSK_RX_OVRN_INT  (0x1U << 4)
+#define LAN91C96_MSK_EPH_INT      (0x1U << 5)
+#define LAN91C96_MSK_ERCV_INT     (0x1U << 6)
+#define LAN91C96_MSK_TX_IDLE_INT  (0x1U << 7)
+
+/*
+ ****************************************************************************
+ *	Bank 3 Register Map in I/O Space
+ **************************************************************************
+ */
+#define LAN91C96_MGMT_MDO         (0x1U << 0)
+#define LAN91C96_MGMT_MDI         (0x1U << 1)
+#define LAN91C96_MGMT_MCLK        (0x1U << 2)
+#define LAN91C96_MGMT_MDOE        (0x1U << 3)
+#define LAN91C96_MGMT_LOW_ID      (0x3U << 4)
+#define LAN91C96_MGMT_IOS0        (0x1U << 8)
+#define LAN91C96_MGMT_IOS1        (0x1U << 9)
+#define LAN91C96_MGMT_IOS2        (0x1U << 10)
+#define LAN91C96_MGMT_nXNDEC      (0x1U << 11)
+#define LAN91C96_MGMT_HIGH_ID     (0x3U << 12)
+
+/*
+ ****************************************************************************
+ *	Revision Register - Bank 3 - Offset 10
+ ****************************************************************************
+ */
+#define LAN91C96_REV_REVID        (0xFU << 0)
+#define LAN91C96_REV_CHIPID       (0xFU << 4)
+
+/*
+ ****************************************************************************
+ *	Early RCV Register - Bank 3 - Offset 12
+ ****************************************************************************
+ */
+#define LAN91C96_ERCV_THRESHOLD   (0x1FU << 0)
+#define LAN91C96_ERCV_RCV_DISCRD  (0x1U << 7)
+
+/*
+ ****************************************************************************
+ *	PCMCIA Configuration Registers
+ ****************************************************************************
+ */
+#define LAN91C96_ECOR    0x8000        // Ethernet Configuration Register
+#define LAN91C96_ECSR    0x8002        // Ethernet Configuration and Status
+
+/*
+ ****************************************************************************
+ *	PCMCIA Ethernet Configuration Option Register (ECOR)
+ ****************************************************************************
+ */
+#define LAN91C96_ECOR_ENABLE       (0x1U << 0)
+#define LAN91C96_ECOR_WR_ATTRIB    (0x1U << 2)
+#define LAN91C96_ECOR_LEVEL_REQ    (0x1U << 6)
+#define LAN91C96_ECOR_SRESET       (0x1U << 7)
+
+/*
+ ****************************************************************************
+ *	PCMCIA Ethernet Configuration and Status Register (ECSR)
+ ****************************************************************************
+ */
+#define LAN91C96_ECSR_INTR        (0x1U << 1)
+#define LAN91C96_ECSR_PWRDWN      (0x1U << 2)
+#define LAN91C96_ECSR_IOIS8       (0x1U << 5)
+
+/*
+ ****************************************************************************
+ *	Receive Frame Status Word - See page 38 of the LAN91C96 specification.
+ ****************************************************************************
+ */
+#define LAN91C96_TOO_SHORT        (0x1U << 10)
+#define LAN91C96_TOO_LONG         (0x1U << 11)
+#define LAN91C96_ODD_FRM          (0x1U << 12)
+#define LAN91C96_BAD_CRC          (0x1U << 13)
+#define LAN91C96_BROD_CAST        (0x1U << 14)
+#define LAN91C96_ALGN_ERR         (0x1U << 15)
+
+#define FRAME_FILTER              (LAN91C96_TOO_SHORT | LAN91C96_TOO_LONG  | LAN91C96_BAD_CRC   | LAN91C96_ALGN_ERR)
+
+/*
+ ****************************************************************************
+ *	Default MAC Address
+ ****************************************************************************
+ */
+#define MAC_DEF_HI  0x0800
+#define MAC_DEF_MED 0x3333
+#define MAC_DEF_LO  0x0100
+
+/*
+ ****************************************************************************
+ *	Default I/O Signature - 0x33
+ ****************************************************************************
+ */
+#define LAN91C96_LOW_SIGNATURE        (0x33U << 0)
+#define LAN91C96_HIGH_SIGNATURE       (0x33U << 8)
+#define LAN91C96_SIGNATURE (LAN91C96_HIGH_SIGNATURE | LAN91C96_LOW_SIGNATURE)
+
+#define LAN91C96_MAX_PAGES     6        // Maximum number of 256 pages.
+#define ETHERNET_MAX_LENGTH 1514
+
+
+
+/*-------------------------------------------------------------------------
+ *  I define some macros to make it easier to do somewhat common
+ * or slightly complicated, repeated tasks.
+ *-------------------------------------------------------------------------
+ */
+
+/* select a register bank, 0 to 3  */
+
+#define SMC_SELECT_BANK(x)  { SMC_outw( x, LAN91C96_BANK_SELECT ); }
+
+/* this enables an interrupt in the interrupt mask register */
+#define SMC_ENABLE_INT(x) {\
+		unsigned char mask;\
+		SMC_SELECT_BANK(2);\
+		mask = SMC_inb( LAN91C96_INT_MASK );\
+		mask |= (x);\
+		SMC_outb( mask, LAN91C96_INT_MASK ); \
+}
+
+/* this disables an interrupt from the interrupt mask register */
+
+#define SMC_DISABLE_INT(x) {\
+		unsigned char mask;\
+		SMC_SELECT_BANK(2);\
+		mask = SMC_inb( LAN91C96_INT_MASK );\
+		mask &= ~(x);\
+		SMC_outb( mask, LAN91C96_INT_MASK ); \
+}
+
+/*----------------------------------------------------------------------
+ * Define the interrupts that I want to receive from the card
+ *
+ * I want:
+ *  LAN91C96_IST_EPH_INT, for nasty errors
+ *  LAN91C96_IST_RCV_INT, for happy received packets
+ *  LAN91C96_IST_RX_OVRN_INT, because I have to kick the receiver
+ *-------------------------------------------------------------------------
+ */
+#define SMC_INTERRUPT_MASK   (LAN91C96_IST_EPH_INT | LAN91C96_IST_RX_OVRN_INT | LAN91C96_IST_RCV_INT)
+
+#endif  /* _LAN91C96_H_ */

+ 3 - 1
include/configs/lubbock.h

@@ -53,6 +53,8 @@
 /*
  * Hardware drivers
  */
+#define CONFIG_DRIVER_LAN91C96
+#define CONFIG_LAN91C96_BASE 0x0C000000
 
 /*
  * select serial console configuration
@@ -64,7 +66,7 @@
 
 #define CONFIG_BAUDRATE         115200
 
-#define CONFIG_COMMANDS         (CONFIG_CMD_DFL & ~CFG_CMD_NET)
+#define CONFIG_COMMANDS         (CONFIG_CMD_DFL)
 
 /* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */
 #include <cmd_confdefs.h>

+ 10 - 0
lib_arm/board.c

@@ -42,6 +42,9 @@ const char version_string[] =
 extern void cs8900_get_enetaddr (uchar * addr);
 #endif
 
+#ifdef CONFIG_DRIVER_LAN91C96
+#include "../drivers/lan91c96.h"
+#endif
 /*
  * Begin and End of memory area for malloc(), and current "brk"
  */
@@ -275,6 +278,13 @@ void start_armboot (void)
 	cs8900_get_enetaddr (gd->bd->bi_enetaddr);
 #endif
 
+#ifdef CONFIG_DRIVER_LAN91C96
+	if (getenv ("ethaddr")) {
+		smc_set_mac_addr(gd->bd->bi_enetaddr);
+	}
+	/* eth_hw_init(); */
+#endif /* CONFIG_DRIVER_LAN91C96 */
+
 	/* Initialize from environment */
 	if ((s = getenv ("loadaddr")) != NULL) {
 		load_addr = simple_strtoul (s, NULL, 16);

+ 2 - 2
post/sysmon.c

@@ -50,10 +50,10 @@
 #include <watchdog.h>
 #include <i2c.h>
 
-static int sysmon_temp_invalid = 0;
-
 #if CONFIG_POST & CFG_POST_SYSMON
 
+static int sysmon_temp_invalid = 0;
+
 /* #define DEBUG */
 
 #define	RELOC(x) if (x != NULL) x = (void *) ((ulong) (x) + gd->reloc_off)

+ 2 - 0
post/uart.c

@@ -73,7 +73,9 @@ static struct {
 static char *ctlr_name[2] = { "SMC", "SCC" };
 
 static int used_by_uart[2] = { -1, -1 };
+#if defined(SCC_ENET)
 static int used_by_ether[2] = { -1, -1 };
+#endif
 
 static int proff_smc[] = { PROFF_SMC1, PROFF_SMC2 };
 static int proff_scc[] =