Subject: Patch for cs89x0 and CL7500FE

From: Jason Gunthorpe <[email-masked]>
Date: Mon, 5 Jun 2000 19:36:07 -0600 (MDT)

Hi,

Enclosed is my patch for the ethernet driver. It enables it to support the
Cirrus eval board(s?) and I think tidies up a few related things inside
the driver. 

It does not yet support DMA operation, I will work on that next week I
hope. A note: My board came with a corrupt EEPROM, so even this driver
will not work on such a board. If you have a board like this the driver
will tell you so and refuse to load.

Russell, I think this is the first patch I have that would be suitable for
inclusion in the kernel. If you think it is good I will forward it to
Andrew (the cs89x0 driver guy) and get his thoughts, you might want to put
in your patch set..

I tried for 2 hours today to get head.S to work with very little luck, so
the booting patches will have to wait.

On the plus side, I just got a EP7209 based eval board
(http://www.cirrus.com/design/products/overview/index.cfm?ProductID=109). 
I really need linux working on that so my efforts will be focused there
for the next while. The board comes with a Linux 2.2.1 port from some odd
company (Royal Linux?), but it doesn't seem to work.. :|

Thanks,
Jason

--- linux2/drivers/net/cs89x0.c	Tue May  2 13:40:59 2000
+++ linux/drivers/net/cs89x0.c	Mon Jun  5 10:45:33 2000
@@ -128,10 +128,26 @@
 
 #include "cs89x0.h"
 
-/* First, a few definitions that the brave might change. */
-/* A zero-terminated list of I/O addresses to be probed. */
+/* First, a few definitions that the brave might change.
+   A zero-terminated list of I/O addresses to be probed. Some special flags..
+      Addr & 1 = Read back the address port, look for signature and reset
+                 the page window before probing 
+      Addr & 3 = Reset the page window and probe 
+   The CLPS eval board has the Cirrus chip at 0x80090300, in ARM IO space,
+   but it is possible that a Cirrus board could be plugged into the ISA
+   slots. */
+/* The cs8900 has 4 IRQ pins, software selectable. cs8900_irq_map maps 
+   them to system IRQ numbers. This mapping is card specific and is set to
+   the configuration of the Cirrus Eval board for this chip. */
+#ifdef CONFIG_ARCH_CLPS7500
+static unsigned int netcard_portlist[] __initdata =
+   { 0x80090303, 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0};
+static unsigned int cs8900_irq_map[] = {12,0,0,0};
+#else
 static unsigned int netcard_portlist[] __initdata =
    { 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0};
+static unsigned int cs8900_irq_map[] = {10,11,12,5};
+#endif
 
 #if DEBUGGING
 static unsigned int net_debug = DEBUGGING;
@@ -362,15 +378,17 @@
 
 	/* if they give us an odd I/O address, then do ONE write to
            the address port, to get it back to address zero, where we
-           expect to find the EISA signature word. */
+           expect to find the EISA signature word. An IO with a base of 0x3
+	   will skip the test for the ADD_PORT. */
 	if (ioaddr & 1) {
-		ioaddr &= ~1;
-		if ((inw(ioaddr + ADD_PORT) & ADD_MASK) != ADD_SIG)
-			return ENODEV;
+	        if ((ioaddr & 2) != 2)
+	        	if ((inw((ioaddr & ~3)+ ADD_PORT) & ADD_MASK) != ADD_SIG)
+		        	return ENODEV;
+		ioaddr &= ~3;
 		outw(PP_ChipID, ioaddr + ADD_PORT);
 	}
 
-	if (inw(ioaddr + DATA_PORT) != CHIP_EISA_ID_SIG)
+        if (inw(ioaddr + DATA_PORT) != CHIP_EISA_ID_SIG)
 	{
 		retval = ENODEV;
 		goto out1;
@@ -403,15 +421,77 @@
 	       dev->base_addr);
 
 	reset_chip(dev);
-
-	/* First check to see if an EEPROM is attached*/
+   
+        /* Here we read the current configuration of the chip. If there
+	   is no Extended EEPROM then the idea is to not disturb the chip
+	   configuration, it should have been correctly setup by automatic
+	   EEPROM read on reset. So, if the chip says it read the EEPROM
+	   the driver will always do *something* instead of complain that
+	   adapter_cnf is 0. */
+        if ((readreg(dev, PP_SelfST) & (EEPROM_OK | EEPROM_PRESENT)) == 
+	      (EEPROM_OK|EEPROM_PRESENT)) {
+	        /* Load the MAC. */
+		for (i=0; i < ETH_ALEN/2; i++) {
+	                unsigned int Addr;
+			Addr = readreg(dev, PP_IA+i*2);
+		        dev->dev_addr[i*2] = Addr & 0xFF;
+		        dev->dev_addr[i*2+1] = Addr >> 8;
+		}
+   
+	   	/* Load the Adapter Configuration. 
+		   Note:  Barring any more specific information from some 
+		   other source (ie EEPROM+Schematics), we would not know 
+		   how to operate a 10Base2 interface on the AUI port. 
+		   However, since we  do read the status of HCB1 and use 
+		   settings that always result in calls to control_dc_dc(dev,0) 
+		   a BNC interface should work if the enable pin 
+		   (dc/dc converter) is on HCB1. It will be called AUI 
+		   however. */
+	   
+		lp->adapter_cnf = 0;
+		i = readreg(dev, PP_LineCTL);
+		/* Preserve the setting of the HCB1 pin. */
+		if ((i & (HCB1 | HCB1_ENBL)) ==  (HCB1 | HCB1_ENBL))
+			lp->adapter_cnf |= A_CNF_DC_DC_POLARITY;
+		/* Save the sqelch bit */
+		if ((i & LOW_RX_SQUELCH) == LOW_RX_SQUELCH)
+			lp->adapter_cnf |= A_CNF_EXTND_10B_2 | A_CNF_LOW_RX_SQUELCH;
+		/* Check if the card is in 10Base-t only mode */
+		if ((i & (AUI_ONLY | AUTO_AUI_10BASET)) == 0)
+			lp->adapter_cnf |=  A_CNF_10B_T | A_CNF_MEDIA_10B_T;
+		/* Check if the card is in AUI only mode */
+		if ((i & (AUI_ONLY | AUTO_AUI_10BASET)) == AUI_ONLY)
+			lp->adapter_cnf |=  A_CNF_AUI | A_CNF_MEDIA_AUI;
+		/* Check if the card is in Auto mode. */
+		if ((i & (AUI_ONLY | AUTO_AUI_10BASET)) == AUTO_AUI_10BASET)
+			lp->adapter_cnf |=  A_CNF_AUI | A_CNF_10B_T | 
+			A_CNF_MEDIA_AUI | A_CNF_MEDIA_10B_T | A_CNF_MEDIA_AUTO;
+		
+		/* IRQ. Other chips already probe, see below. */
+		if (lp->chip_type == CS8900) 
+			lp->isa_config = readreg(dev, PP_CS8900_ISAINT) & INT_NO_MASK;
+	   
+		printk( "[Cirrus EEPROM] ");
+	}
+
+        printk("\n");
+   
+	/* First check to see if an EEPROM is attached. */
 	if ((readreg(dev, PP_SelfST) & EEPROM_PRESENT) == 0)
-		printk(KERN_WARNING "\ncs89x0: No EEPROM, relying on command line....\n");
+		printk(KERN_WARNING "cs89x0: No EEPROM, relying on command line....\n");
 	else if (get_eeprom_data(dev, START_EEPROM_DATA,CHKSUM_LEN,eeprom_buff) < 0) {
 		printk(KERN_WARNING "\ncs89x0: EEPROM read failed, relying on command line.\n");
         } else if (get_eeprom_cksum(START_EEPROM_DATA,CHKSUM_LEN,eeprom_buff) < 0) {
-                printk(KERN_WARNING "\ncs89x0: EEPROM checksum bad, relying on command line\n");
+		/* Check if the chip was able to read its own configuration starting
+		   at 0 in the EEPROM*/
+		if ((readreg(dev, PP_SelfST) & (EEPROM_OK | EEPROM_PRESENT)) !=
+		    (EEPROM_OK|EEPROM_PRESENT)) 
+                	printk(KERN_WARNING "cs89x0: Extended EEPROM checksum bad and no Cirrus EEPROM, relying on command line\n");
+		   
         } else {
+		/* This reads an extended EEPROM that is not documented
+		   in the CS8900 datasheet. */
+		
                 /* get transmission control word  but keep the autonegotiation bits */
                 if (!lp->auto_neg_cnf) lp->auto_neg_cnf = eeprom_buff[AUTO_NEG_CNF_OFFSET/2];
                 /* Store adapter configuration */
@@ -464,17 +544,12 @@
 	} else {
 		i = lp->isa_config & INT_NO_MASK;
 		if (lp->chip_type == CS8900) {
-			/* the table that follows is dependent upon how you wired up your cs8900
-			 * in your system.  The table is the same as the cs8900 engineering demo
-			 * board.  irq_map also depends on the contents of the table.  Also see
-			 * write_irq, which is the reverse mapping of the table below. */
-			switch(i) {
-			case 0: i = 10; break;
-			case 1: i = 11; break;
-			case 2: i = 12; break;
-			case 3: i =  5; break;
-			default: printk("\ncs89x0: bug: isa_config is %d\n", i);
-			}
+			/* Translate the IRQ using the IRQ mapping table. */
+			if (i > sizeof(cs8900_irq_map)/sizeof(cs8900_irq_map[0]))
+				printk("\ncs89x0: bug: isa_config is %d\n", i);
+			else
+				i = cs8900_irq_map[i];
+			
 			lp->irq_map = CS8900_IRQ_MAP; /* fixed IRQ map for CS8900 */
 		} else {
 			int irq_map_buff[IRQ_MAP_LEN/2];
@@ -490,7 +565,7 @@
 			dev->irq = i;
 	}
 
-	printk(", IRQ %d", dev->irq);
+	printk(" IRQ %d", dev->irq);
 
 #if ALLOW_DMA
 	if (lp->use_dma)
@@ -741,7 +816,9 @@
 	struct net_local *lp = (struct net_local *)dev->priv;
 	unsigned int selfcontrol;
 	int timenow = jiffies;
-	/* control the DC to DC convertor in the SelfControl register.  */
+	/* control the DC to DC convertor in the SelfControl register.  
+	   Note: This is hooked up to a general purpose pin, might not
+	   always be a DC to DC convertor. */
 
 	selfcontrol = HCB1_ENBL; /* Enable the HCB1 bit as an output */
 	if (((lp->adapter_cnf & A_CNF_DC_DC_POLARITY) != 0) ^ on_not_off)
@@ -916,13 +993,13 @@
 	int i;
 
 	if (chip_type == CS8900) {
-		switch(irq) {
-		case 10: i = 0; break;
-		case 11: i = 1; break;
-		case 12: i = 2; break;
-		case 5: i =  3; break;
-		default: i = 3; break;
-		}
+		/* Search the mapping table for the corrisponding IRQ pin. */
+		for (i = 0; i != sizeof(cs8900_irq_map)/sizeof(cs8900_irq_map[0]); i++)
+			if (cs8900_irq_map[i] == irq)
+				break;
+		/* Not found */
+		if (i == sizeof(cs8900_irq_map)/sizeof(cs8900_irq_map[0]))
+			i = 3;
 		writereg(dev, PP_CS8900_ISAINT, i);
 	} else {
 		writereg(dev, PP_CS8920_ISAINT, irq);

unsubscribe: body of `unsubscribe linux-arm-kernel' to [email-masked]