Hi all,

Signed-off:    Marc Bertens <[email protected]>
Tested-by:    Marc Bertens<[email protected]> 

I made some new patches for the Nokia IP530, therefore my last patch
submission can be discarded.

1.    21143PD driver; I removed the not needed stuff from there and
tested without and all worked fine.

2.    Patched the devicetree.cb; added some comments and commented out
the setting of the GPIO lines, this was unnecessary.    

3.    nokia/Kconfig; added a description in de help about which board
revisions are supported.

4.    ip530/Kconfig; added the CPU model, removed the PIRQ_ROUTE and set
the IRQ_SLOT_COUNT to 1, this last is needed by the
        header files, because those structures are still used by the
code, see pirq_table.c

5.    ip530/mainboard.c; Now the identification of the physical system
is show in the boot up of the machine, like;
        * System type, should be IP530, otherwise a warning is given. 
        * Board number 
        * Mfg. P/N
        * Mfg. rev.
        * Serial number
        All these read from the SPI eeprom behind the SuperIO

6.    The sourcecode files for the superIO-SPI interface in the
Nokia-IP530.  

Stefan: please drop that last patch submission of mine. 

Thats all folks....


Marc 

Index: src/drivers/dec/21143/21143.c
===================================================================
--- src/drivers/dec/21143/21143.c	(revision 6292)
+++ src/drivers/dec/21143/21143.c	(working copy)
@@ -27,20 +27,6 @@
 static void dec_21143_enable(device_t dev)
 {
 	printk(BIOS_DEBUG, "Initializing DECchip 21143\n");
-
-	// The resource allocator should do this. If not, it needs to be fixed
-	// differently.
-#if 0 
-	/* Command and status configuration (offset 0x04) */
-	pci_write_config32(dev, 0x04, 0x02800107);
-	printk(BIOS_DEBUG, "0x04 = %08x (07 01 80 02)\n",
-	       pci_read_config32(dev, 0x04));
-
-	/* Cache line size (offset 0x0C) */
-	pci_write_config8(dev, 0x0C, 0x00);
-	printk(BIOS_DEBUG, "0x0c = %08x (00)\n",
-	       pci_read_config8(dev, 0x0C));
-#endif
 }
 
 static struct device_operations dec_21143_ops = {
Index: src/mainboard/nokia/ip530/devicetree.cb
===================================================================
--- src/mainboard/nokia/ip530/devicetree.cb	(revision 6292)
+++ src/mainboard/nokia/ip530/devicetree.cb	(working copy)
@@ -51,13 +51,14 @@
             irq 0xB2 = 0x0C		# Soft power status 1
             irq 0xB3 = 0x05		# Soft power status 2
             irq 0xC0 = 0x03		# IRQ MUX control
-
+            # setting up the PINs to there function, ie. GPIO, IRQ or other function
             irq 0xC8 = 0x10		# GP50 = (I/O) output = Flashrom enable
             irq 0xCA = 0x09		# GP52 = IRQ8 (output)
             irq 0xCB = 0x01		# GP53 = nROMCS (output)
             irq 0xCC = 0x11		# GP54 = (I/O) input
-            irq 0xF9 = 0x00             # read/write GP5x lines (0x1C)
-
+## This line can go !!!!
+#           irq 0xF9 = 0x00             # read/write GP5x lines (0x1C)
+            # setting up the PINs to there function, ie. GPIO, IRQ or other function
             irq 0xD0 = 0x08		# GP60 = IRQ1
             irq 0xD1 = 0x08		# GP61 = IRQ3
             irq 0xD2 = 0x08		# GP62 = IRQ4
@@ -66,17 +67,19 @@
             irq 0xD5 = 0x11		# GP65 = (I/O) input
             irq 0xD6 = 0x08		# GP66 = IRQ8
             irq 0xD7 = 0x11		# GP67 = (I/O) input
-            irq 0xFA = 0x00		# read/write GP6x lines (0x88)
-
-            irq 0xE0 = 0x00		# GP10 (I/O) = output
-            irq 0xE1 = 0x01		# GP11 (I/O) = input
+## This line can go !!!!
+#           irq 0xFA = 0x00		# read/write GP6x lines (0x88)
+            # setting up the PINs to there function, ie. GPIO, IRQ or other function
+            irq 0xE0 = 0x00		# GP10 (I/O) = output   to DI of 93LC46 (1024 bits of EEPROM)
+            irq 0xE1 = 0x01		# GP11 (I/O) = input  from DO of 93LC46
+            irq 0xE4 = 0x00		# GP14 (I/O) = output   to SK of 93LC46
+            irq 0xE5 = 0x00		# GP15 (I/O) = output   to CS of 93LC46
             irq 0xE2 = 0x08		# GP12 = P17
             irq 0xE3 = 0x00		# GP13 (I/O) = output = LED fault on front, active low
-            irq 0xE4 = 0x00		# GP14 (I/O) = output
-            irq 0xE5 = 0x00		# GP15 (I/O) = output
             irq 0xE6 = 0x01		# GP16 (I/O) = input = JP900 on board, low on short, high on open
             irq 0xE7 = 0x00 		# GP17 (I/O) = output = LED alert on front, active low
-            irq 0xF6 = 0xFF		# read/write GP1x lines (0xCA)
+            # Make sure that the LEDs are off and set all EEPROM lines HIGH  
+            irq 0xF6 = 0xAC		# read/write GP1x lines (0xCA)
 
             irq 0xEF = 0x00		# GP_INT2 disable
             irq 0xF0 = 0x00		# GP_INT1 disable
Index: src/mainboard/nokia/ip530/Kconfig
===================================================================
--- src/mainboard/nokia/ip530/Kconfig	(revision 6292)
+++ src/mainboard/nokia/ip530/Kconfig	(working copy)
@@ -22,13 +22,13 @@
 	def_bool y
 	select ARCH_X86
 	select CPU_INTEL_SOCKET_PGA370
+	select CPU_INTEL_MODEL_68X
 	select NORTHBRIDGE_INTEL_I440BX
 	select SOUTHBRIDGE_INTEL_I82371EB
 	select SUPERIO_SMSC_SMSCSUPERIO
 	select SOUTHBRIDGE_TI_PCI1X2X
 	select DRIVERS_DEC_21143
 	select BOARD_ROMSIZE_KB_512
-	select PIRQ_ROUTE
 	select HAVE_PIRQ_TABLE
 	select UDELAY_TSC
 	select SDRAMPWR_4DIMM
@@ -43,7 +43,7 @@
 
 config IRQ_SLOT_COUNT
 	int
-	default 22
+	default 1
 
 ## Configuration for the PCMCIA-Cardbus controller.
 config TI_PCMCIA_CARDBUS_CMDR
Index: src/mainboard/nokia/ip530/mainboard.c
===================================================================
--- src/mainboard/nokia/ip530/mainboard.c	(revision 6292)
+++ src/mainboard/nokia/ip530/mainboard.c	(working copy)
@@ -21,6 +21,48 @@
 #include <device/device.h>
 #include "chip.h"
 
+#include <console/console.h>
+#include <stdlib.h>               // get some memory
+#include <delay.h>                // mdelay()
+#include <string.h>               // memcmp() coreboots version
+#define CONFIG_USES_93LC46_16BIT
+#include "microchip93lc46b_spi.c"
+#include "superio.c"
+#include "superio_spi.c"
+
+static void enable_nokia( struct device *dev )
+{
+  uint8_t i;
+  uint8_t* szString = malloc( 0x10 );
+  spi_93LC46B_read( 0, szString, 6 );
+  if ( memcmp( szString, "IP530\0", 6 ) != 0 )
+  {
+    printk( BIOS_CRIT, "This is not a NOKIA - IP530, but a %s\n", szString );
+    return;
+  }
+  /* Ok its a NOKIA-IP530 */
+  printk( BIOS_INFO,   "NOKIA         : %s", szString );
+  /* Board number, sticker close to the PIII cpu */
+  spi_93LC46B_read( 0x24, szString, 6 );
+  printk( BIOS_INFO, "\nBoard number  : " );
+  for ( i = 0; i < 6; i++ )
+  {
+    printk( BIOS_INFO, "%02X", szString[ i ] & 0xFF );
+  }
+  /* Mfg. P/n (on the bottom side of the unit), filled out with spaces */
+  spi_93LC46B_read( 0x2A, szString, 14 );
+  printk( BIOS_INFO, "\nMfg. P/N      : %s", szString );
+  /* Mfg. rev. (on the bottom side of the unit), 0xYY = is the revision letter, where A = 0x41, B = 0x42  */
+  spi_93LC46B_read( 0x3E, szString, 2 );
+  printk( BIOS_INFO, "\nMfg. rev.     : %s", szString );
+  /* 	Serial number (on the bottom side of the unit)  */
+  spi_93LC46B_read( 0x52, szString, 12 );
+  printk( BIOS_INFO, "\nSerial number : %s\n", szString );
+  free( szString );
+  return;
+}
+
 struct chip_operations mainboard_ops = {
 	CHIP_NAME("Nokia IP530 Mainboard")
+	.enable_dev = enable_nokia,
 };
Index: src/mainboard/nokia/ip530/irq_tables.c
===================================================================
--- src/mainboard/nokia/ip530/irq_tables.c	(revision 6292)
+++ src/mainboard/nokia/ip530/irq_tables.c	(working copy)
@@ -17,80 +17,249 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
  */
-
 #include <arch/pirq_routing.h>
+#include <console/console.h>
+#define CONFIG_USES_93LC46_16BIT
+#include "microchip93lc46b_spi.h"
+#include <stdint.h>
+#include <string.h>               // memcmp() coreboots version
+/*
+ *  This IRQ mask enables the following lines 5, 6, 10, 11
+ *	IRQ-lines FEDCBA9876543210
+ *  0x1E20 =  0001111000100000
+ *	0x0C60 =  0000110001100000 (current)
+ */
+#define         PIRQ_IRQ_MASK	        0x0C60
+static uint8_t  BoardRevision[ 2 ];
 
-#define PIRQ_IRQ_MASK 0x0c60
+static struct irq_routing_table* build_pirq_table( unsigned long addr, uint16_t router_bus, uint16_t dev,
+                                            uint16_t sub_dev, uint16_t router_dev )
+{
+	struct irq_routing_table *pirq;
+	/* Align the table to be 16 byte aligned. */
+	addr += 15;
+	addr &= ~15;
+	printk( BIOS_INFO, "Address correction on dynamic IRQ routing tables to 0x%lx\n", addr );
+	pirq = (void *)(addr);
+	/* u32 signature */
+	pirq->signature				= PIRQ_SIGNATURE;
+	/* u16 version */
+	pirq->version					= PIRQ_VERSION;
+	/* Interrupt router bus */
+	pirq->rtr_bus					= router_bus;
+	/* Interrupt router device. */
+	pirq->rtr_devfn 			= router_dev;
+	/* IRQs devoted exclusively to PCI usage */
+	pirq->exclusive_irqs 	= 0;
+	/* Vendor */
+	pirq->rtr_vendor 			= dev;
+	/* Device */
+	pirq->rtr_device 			= sub_dev;
+	/* Miniport */
+	pirq->miniport_data 	= 0;
+	/* u8 rfu[11] */
+	memset( pirq->rfu, 0, sizeof( pirq->rfu ) );
+	pirq->checksum				= 0;
+	return ( pirq );
+}
 
-const struct irq_routing_table intel_irq_routing_table = {
-	PIRQ_SIGNATURE,		/* u32 signature */
-	PIRQ_VERSION,		/* u16 version */
-	32 + 16 * CONFIG_IRQ_SLOT_COUNT,/* Max. number of devices on the bus */
-	0x00,			/* Interrupt router bus */
-	(0x07 << 3) | 0x0,	/* Interrupt router dev */
-	0,			/* IRQs devoted exclusively to PCI usage */
-	0x8086,			/* Vendor */
-	0x122e,			/* Device */
-	0,			/* Miniport */
-	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* u8 rfu[11] */
-	0xD7,			/* Checksum */
+static void finish_pirw_table( struct irq_routing_table* pirq, uint8_t slots )
+{
+	uint16_t i;
+	uint8_t	sum	= 0;
+	uint8_t* v	= (uint8_t *)(pirq);
+	printk( BIOS_SPEW, "PIRQ slots %i\n", slots & 0xFF );
+	pirq->size = 32 + 16 * slots;
+	printk( BIOS_SPEW, "PIRQ table size %i\n", pirq->size );
+	for ( i = 0; i < pirq->size; i++ )
 	{
-		/**
-		 * Rebuild of the PIRQ table, to fix the non-working on-board NIC and PCMCIA controller.
-		 *          FEDCBA9876543210
-		 * 0x1E20 = 0001111000100000
-		 * 0x0C60 = 0000110001100000
-		 */
-		// Southbridge 82371EB, INTD = 0x63
-		{ 0x00, (0x07 << 3) | 0x0, {{0x00, PIRQ_IRQ_MASK}, {0x00, PIRQ_IRQ_MASK}, {0x00, PIRQ_IRQ_MASK}, {0x00, PIRQ_IRQ_MASK}}, 0x0, 0x0 },
-		// On-board PCI-to-PCI bridge
-		{ 0x01, (0x00 << 3) | 0x0, {{0x60, PIRQ_IRQ_MASK}, {0x61, PIRQ_IRQ_MASK}, {0x62, PIRQ_IRQ_MASK}, {0x63, PIRQ_IRQ_MASK}}, 0x0, 0x0 },
-		// ETH1 on front panel, INTA = 0x62 = ok
-		{ 0x00, (0x0d << 3) | 0x0, {{0x62, PIRQ_IRQ_MASK}, {0x00, PIRQ_IRQ_MASK}, {0x00, PIRQ_IRQ_MASK}, {0x00, PIRQ_IRQ_MASK}}, 0x0, 0x0 },
-
-		// ETH2 on front panel, 0x63
-		{ 0x00, (0x0e << 3) | 0x0, {{0x63, PIRQ_IRQ_MASK}, {0x00, PIRQ_IRQ_MASK}, {0x00, PIRQ_IRQ_MASK}, {0x00, PIRQ_IRQ_MASK}}, 0x0, 0x0 },
-		// ETH3 on front panel = 0x60
-		{ 0x02, (0x04 << 3) | 0x0, {{0x60, PIRQ_IRQ_MASK}, {0x00, PIRQ_IRQ_MASK}, {0x00, PIRQ_IRQ_MASK}, {0x00, PIRQ_IRQ_MASK}}, 0x0, 0x0 },
-
-		// ETH4 on front panel, INTA = 0x61 = ok
-		{ 0x02, (0x05 << 3) | 0x0, {{0x61, PIRQ_IRQ_MASK}, {0x00, PIRQ_IRQ_MASK}, {0x00, PIRQ_IRQ_MASK}, {0x00, PIRQ_IRQ_MASK}}, 0x0, 0x0 },
-		// PCMCIA/Cardbus controller, INTA = 0x60 = ok, INTB = 0x61 = ok
-		{ 0x00, (0x0f << 3) | 0x0, {{0x60, PIRQ_IRQ_MASK}, {0x61, PIRQ_IRQ_MASK}, {0x00, PIRQ_IRQ_MASK}, {0x00, PIRQ_IRQ_MASK}}, 0x0, 0x0 },
-		// Bridge for slot 1 (top)
-		{ 0x02, (0x07 << 3) | 0x0, {{0x61, PIRQ_IRQ_MASK}, {0x62, PIRQ_IRQ_MASK}, {0x63, PIRQ_IRQ_MASK}, {0x64, PIRQ_IRQ_MASK}}, 0x0, 0x0 },
-		// PCI compact slots 1 (top)
-		{ 0x03, (0x04 << 3) | 0x0, {{0x61, PIRQ_IRQ_MASK}, {0x62, PIRQ_IRQ_MASK}, {0x63, PIRQ_IRQ_MASK}, {0x60, PIRQ_IRQ_MASK}}, 0x1, 0x0 },
-		{ 0x03, (0x05 << 3) | 0x0, {{0x62, PIRQ_IRQ_MASK}, {0x63, PIRQ_IRQ_MASK}, {0x60, PIRQ_IRQ_MASK}, {0x61, PIRQ_IRQ_MASK}}, 0x2, 0x0 },
-		{ 0x03, (0x06 << 3) | 0x0, {{0x63, PIRQ_IRQ_MASK}, {0x60, PIRQ_IRQ_MASK}, {0x61, PIRQ_IRQ_MASK}, {0x62, PIRQ_IRQ_MASK}}, 0x3, 0x0 },
-		{ 0x03, (0x07 << 3) | 0x0, {{0x60, PIRQ_IRQ_MASK}, {0x61, PIRQ_IRQ_MASK}, {0x62, PIRQ_IRQ_MASK}, {0x63, PIRQ_IRQ_MASK}}, 0x4, 0x0 },
-		// Bridge for slot 2 (middle)
-		{ 0x02, (0x06 << 3) | 0x0, {{0x61, PIRQ_IRQ_MASK}, {0x62, PIRQ_IRQ_MASK}, {0x63, PIRQ_IRQ_MASK}, {0x60, PIRQ_IRQ_MASK}}, 0x0, 0x0 },
-		// PCI compact slots 2 (middle)
-		{ 0x04, (0x04 << 3) | 0x0, {{0x61, PIRQ_IRQ_MASK}, {0x62, PIRQ_IRQ_MASK}, {0x63, PIRQ_IRQ_MASK}, {0x60, PIRQ_IRQ_MASK}}, 0x5, 0x0 },
-		{ 0x04, (0x05 << 3) | 0x0, {{0x62, PIRQ_IRQ_MASK}, {0x63, PIRQ_IRQ_MASK}, {0x60, PIRQ_IRQ_MASK}, {0x61, PIRQ_IRQ_MASK}}, 0x6, 0x0 },
-		{ 0x04, (0x06 << 3) | 0x0, {{0x63, PIRQ_IRQ_MASK}, {0x60, PIRQ_IRQ_MASK}, {0x61, PIRQ_IRQ_MASK}, {0x62, PIRQ_IRQ_MASK}}, 0x7, 0x0 },
-		{ 0x04, (0x07 << 3) | 0x0, {{0x60, PIRQ_IRQ_MASK}, {0x61, PIRQ_IRQ_MASK}, {0x62, PIRQ_IRQ_MASK}, {0x63, PIRQ_IRQ_MASK}}, 0x8, 0x0 },
-		// Bridge for slot 3 (bottom)
-		{ 0x00, (0x10 << 3) | 0x0, {{0x61, PIRQ_IRQ_MASK}, {0x62, PIRQ_IRQ_MASK}, {0x63, PIRQ_IRQ_MASK}, {0x60, PIRQ_IRQ_MASK}}, 0x0, 0x0 },
-		// PCI compact slots 3 (bottom)
-		{ 0x05, (0x04 << 3) | 0x0, {{0x61, PIRQ_IRQ_MASK}, {0x62, PIRQ_IRQ_MASK}, {0x63, PIRQ_IRQ_MASK}, {0x60, PIRQ_IRQ_MASK}}, 0x9, 0x0 },
-		{ 0x05, (0x05 << 3) | 0x0, {{0x62, PIRQ_IRQ_MASK}, {0x63, PIRQ_IRQ_MASK}, {0x60, PIRQ_IRQ_MASK}, {0x61, PIRQ_IRQ_MASK}}, 0xA, 0x0 },
-		{ 0x05, (0x06 << 3) | 0x0, {{0x63, PIRQ_IRQ_MASK}, {0x60, PIRQ_IRQ_MASK}, {0x61, PIRQ_IRQ_MASK}, {0x62, PIRQ_IRQ_MASK}}, 0xB, 0x0 },
-		{ 0x05, (0x07 << 3) | 0x0, {{0x60, PIRQ_IRQ_MASK}, {0x61, PIRQ_IRQ_MASK}, {0x62, PIRQ_IRQ_MASK}, {0x63, PIRQ_IRQ_MASK}}, 0xC, 0x0 },
+		sum += v[ i ];
 	}
-};
+	pirq->checksum = pirq->checksum - sum;
+	printk( BIOS_SPEW, "PIRQ checksum %02X\n", pirq->checksum & 0xFF );
+	return;
+}
 
-unsigned long write_pirq_routing_table(unsigned long addr)
+static void write_pirq_info_ex( struct irq_info *pirq_info, uint8_t bus, uint8_t devfn, uint8_t link0, uint16_t bitmap0,
+		uint8_t link1, uint16_t bitmap1, uint8_t link2, uint16_t bitmap2,uint8_t link3, uint16_t bitmap3,
+		uint8_t slot, uint8_t rfu)
 {
-	return copy_pirq_routing_table(addr);
+	pirq_info->bus							= bus;
+	pirq_info->devfn						= devfn;
+	pirq_info->irq[ 0 ].link		= link0;
+	pirq_info->irq[ 0 ].bitmap	= (link0 ? bitmap0 : 0x0000 );
+	pirq_info->irq[ 1 ].link		= link1;
+	pirq_info->irq[ 1 ].bitmap	= (link1 ? bitmap1 : 0x0000 );
+	pirq_info->irq[ 2 ].link		= link2;
+	pirq_info->irq[ 2 ].bitmap	= (link2 ? bitmap2 : 0x0000 );
+	pirq_info->irq[ 3 ].link		= link3;
+	pirq_info->irq[ 3 ].bitmap	= (link3 ? bitmap3 : 0x0000 );
+	pirq_info->slot							= slot;
+	pirq_info->rfu							= rfu;
+	return;
 }
 
-/**
- * TODO: This stub function is here until the point is solved in the
- * main code of coreboot. See also arch/x86/boot/pirq_tables.c.
- */
-void pirq_assign_irqs(const unsigned char pIntAtoD[4])
+static void write_pirq_info( struct irq_info* pirq_info, uint8_t bus, uint8_t devfn,
+                            uint16_t bitmap, uint8_t link0, uint8_t link1, uint8_t link2, uint8_t link3,
+                            uint8_t slot )
 {
+	write_pirq_info_ex( pirq_info, bus, devfn, link0, bitmap, link1, bitmap, link2, bitmap, link3, bitmap, slot, 0 );
 	return;
 }
+
+#if CONFIG_MAXIMUM_CONSOLE_LOGLEVEL >= BIOS_SPEW
+static void HexDump( const char* pszCaption, const void* ptr, uint16_t size )
+{
+  int   address = 0;
+	int   j;
+  char  Ascii[ 17 ];
+  const uint8_t* bytes = (const uint8_t*)ptr;
+  for ( address = 0, j = 0; address < size; address++ )
+  {
+    if ( j == 0 )
+		{
+			printk( BIOS_INFO, "\n%s:%p:%04X : ", pszCaption, (void*)(bytes + address), address );
+		}
+		if ( bytes[ address ] >= 0x20 && bytes[ address ] < 0x7E )
+		{
+		  Ascii[ j ] = bytes[ address ];
+		}
+		else
+		{
+		  Ascii[ j ] = '.';
+		}
+		printk( BIOS_INFO, "%02X ", bytes[ address ] & 0xFF );
+		if ( ++j == 16 )
+		{
+		  Ascii[ j ] = 0;
+		  printk( BIOS_INFO, "%s", Ascii );
+			j = 0;
+		}
+  }
+  if ( j != 0 )
+  {
+    Ascii[ j ] = 0;
+    for ( ; j < 16; j++ )
+    {
+      printk( BIOS_INFO, "   " );
+    }
+    printk( BIOS_INFO, "%s", Ascii );
+  }
+	printk( BIOS_INFO, "\n" );
+  return;
+}
+#endif
+unsigned long write_pirq_routing_table( unsigned long addr )
+{
+	struct irq_routing_table *pirq;
+	struct irq_info *pirq_info;
+	unsigned slot_num	= 0;
+	unsigned link;
+	unsigned domain;
+  /* Mfg. rev. (on the bottom side of the unit), 0xYY = is the revision letter, where A = 0x41, B = 0x42  */
+  spi_93LC46B_read( 0x3E, BoardRevision, 2 );
+	/* This table must be betweeen 0xf0000 & 0x100000 */
+	printk( BIOS_INFO, "Writing dynamic IRQ routing tables to 0x%lx...\n", addr );
+  /* For which board are we doing this */
+  printk( BIOS_INFO, "Nokia IP530 Mfg. rev. : %c\n", BoardRevision[ 0 ] );
+	/*                     memory, bus,  device, sub-dev, interrupt router */
+	pirq = build_pirq_table( addr, 0x00, 0x8086, 0x122e, (0x07 << 3) | 0x0 );
+	pirq_info = (void *)( &pirq->checksum + 1);
+	printk( BIOS_SPEW, "Table Address : %p\n", pirq );
+	/* Southbridge 82371, INTD = 0x63 */
+	write_pirq_info( pirq_info, 0x00, (0x07<<3) | 0x0, PIRQ_IRQ_MASK, 0x00, 0x00, 0x00, 0x63, 0x00 );
+	pirq_info++; slot_num++;
+		// On-board PCI-to-PCI bridge */
+	write_pirq_info( pirq_info, 0x01, (0x00<<3) | 0x0, PIRQ_IRQ_MASK, 0x60, 0x61, 0x62, 0x63, 0x00 );
+	pirq_info++; slot_num++;
+		// ETH1 on front panel */
+	write_pirq_info( pirq_info, 0x00, (0x0d<<3) | 0x0, PIRQ_IRQ_MASK, 0x62, 0x00, 0x00, 0x00, 0x00 );
+	pirq_info++; slot_num++;
+		// ETH2 on front panel */
+	write_pirq_info( pirq_info, 0x00, (0x0e<<3) | 0x0, PIRQ_IRQ_MASK, 0x63, 0x00, 0x00, 0x00, 0x00 );
+	pirq_info++; slot_num++;
+		// ETH3 on front panel */
+	write_pirq_info( pirq_info, 0x02, (0x04<<3) | 0x0, PIRQ_IRQ_MASK, 0x60, 0x00, 0x00, 0x00, 0x00 );
+	pirq_info++; slot_num++;
+		// ETH4 on front panel */
+	write_pirq_info( pirq_info, 0x02, (0x05<<3) | 0x0, PIRQ_IRQ_MASK, 0x61, 0x00, 0x00, 0x00, 0x00 );
+	pirq_info++; slot_num++;
+  if ( BoardRevision[ 0 ] >= 'B' && BoardRevision[ 0 ] <= 'Z' )
+  {
+    if ( BoardRevision[ 0 ] > 'B' )
+    {
+      printk( BIOS_CRIT, "The %c revision of the Nokia IP530 are untested.\n", BoardRevision[ 0 ] );
+    }
+		/* PCMCIA/Cardbus controller, board revision B and higher */
+		write_pirq_info( pirq_info, 0x00, (0x0f<<3) | 0x0, PIRQ_IRQ_MASK, 0x60, 0x00, 0x00, 0x00, 0x00 );
+  }
+  else
+  {
+    /* PCMCIA/Cardbus controller, board revision A */
+		write_pirq_info( pirq_info, 0x00, (0x0f<<3) | 0x0, PIRQ_IRQ_MASK, 0x60, 0x61, 0x00, 0x00, 0x00 );
+  }
+  pirq_info++; slot_num++;
+  /* Bridge for slot 1 (top) */
+	write_pirq_info( pirq_info, 0x02, (0x07<<3) | 0x0, PIRQ_IRQ_MASK, 0x60, 0x61, 0x62, 0x63, 0x00 );
+	pirq_info++; slot_num++;
+	/* Bridge for slot 2 (middle) */
+	write_pirq_info( pirq_info, 0x02, (0x06<<3) | 0x0, PIRQ_IRQ_MASK, 0x60, 0x61, 0x62, 0x63, 0x00 );
+	pirq_info++; slot_num++;
+	/* Bridge for slot 3 (bottom) */
+	write_pirq_info( pirq_info, 0x00, (0x10<<3) | 0x0, PIRQ_IRQ_MASK, 0x60, 0x61, 0x62, 0x63, 0x00 );
+	pirq_info++; slot_num++;
+
+	for ( domain = 3; domain < 6; domain++ )
+	{
+    /* PCI compact slots 1 (top) = domain 3, 2 (middle) = domain 4, 3 (bottom) = domain 5 */
+    for ( link = 0; link < 4; link++ )
+    {
+      write_pirq_info( pirq_info, domain, ( ( 0x04 + link ) <<3 ) | 0x0, PIRQ_IRQ_MASK,
+                          ( ( 0x61 + link ) & 0x63 ),
+                          ( ( 0x62 + link ) & 0x63 ),
+                          ( ( 0x63 + link ) & 0x63 ),
+                          ( ( 0x60 + link ) & 0x63 ), 0x01 );
+      pirq_info++; slot_num++;
+    }
+	}
+	/* Fix the checksum of the table and set length */
+  finish_pirw_table( pirq, slot_num );
+  printk( BIOS_INFO, "Done dynamic IRQ routing tables.\n" );
+#if ( CONFIG_MAXIMUM_CONSOLE_LOGLEVEL >= BIOS_DEBUG )
+    printk( BIOS_INFO, "Signature              : %08X\n", pirq->signature );
+    printk( BIOS_INFO, "Version                : %04X\n", pirq->version );
+    printk( BIOS_INFO, "Sizeof PIRQ table      : %u\n", pirq->size );
+    printk( BIOS_INFO, "Router bus             : %02X\n", pirq->rtr_bus & 0xFF );
+    printk( BIOS_INFO, "Router device function : %02X\n", pirq->rtr_devfn & 0xFF );
+    printk( BIOS_INFO, "PCI IRQ's              : %04x\n", pirq->exclusive_irqs & 0xFFFF );
+    printk( BIOS_INFO, "Router vendor id.      : %04x\n", pirq->rtr_vendor );
+    printk( BIOS_INFO, "Router device id.      : %04x\n", pirq->rtr_device );
+    printk( BIOS_INFO, "Miniport data          : %04x\n", pirq->miniport_data );
+    printk( BIOS_INFO, "RFU bytes              : " );
+    for ( slot_num = 0; slot_num < 10; slot_num++ )
+    {
+      printk( BIOS_INFO, "%02X ", pirq->rfu[ slot_num ] & 0xFF );
+    }
+    printk( BIOS_INFO, "\nChecksum               : %02X\n", ( pirq->checksum & 0xFF ) );
+    for ( slot_num = 0; slot_num < (( pirq->size - 32 ) / 16); slot_num++ )
+    {
+      printk( BIOS_INFO, "\t{ %02X, %02X, { ",  pirq->slots[ slot_num ].bus & 0xFF,
+                                                pirq->slots[ slot_num ].devfn & 0xFF );
+      for ( link = 0; link < 4; link++ )
+      {
+        printk( BIOS_INFO, "{ %02X, %04X }%c",  pirq->slots[ slot_num ].irq[ link ].link,
+                                                pirq->slots[ slot_num ].irq[ link ].bitmap,
+                                                ( link < 3 ? ',' : ' ' ) );
+      }
+      printk( BIOS_INFO, "}, %02X, %02X }\n",   pirq->slots[ slot_num ].slot & 0xFF,
+                                                pirq->slots[ slot_num ].rfu & 0xFF );
+    }
+    printk( BIOS_SPEW, "Table Address : %p\n", pirq );
+    if ( CONFIG_MAXIMUM_CONSOLE_LOGLEVEL >= BIOS_SPEW )
+    {
+      HexDump( "PIRQ", (uint8_t*)pirq, (uint16_t)((uint8_t*)pirq_info - (uint8_t*)pirq) );
+    }
+#endif
+  /* return the end of the table */
+	return ( (unsigned long)pirq_info );
+}
Index: src/mainboard/nokia/Kconfig
===================================================================
--- src/mainboard/nokia/Kconfig	(revision 6292)
+++ src/mainboard/nokia/Kconfig	(working copy)
@@ -23,6 +23,10 @@
 
 config BOARD_NOKIA_IP530
 	bool "IP530"
+  help
+    The current coreboot release supports board manufacturer revision A and B. 
+    Of the higher revisions is not known if all hardware is supported. We know
+    of revision F is running under a revision B coreboot bios.
 
 endchoice
Index: src/mainboard/nokia/ip530/microchip93lc46b_spi.c
===================================================================
--- src/mainboard/nokia/ip530/microchip93lc46b_spi.c	(revision 0)
+++ src/mainboard/nokia/ip530/microchip93lc46b_spi.c	(revision 0)
@@ -0,0 +1,173 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2009-2010 Marc Bertens
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+#define CONFIG_USES_93LC46_16BIT
+#include "spi_interface.h"
+#include "microchip93lc46b_spi.h"
+/****************************************************************************
+ * This is written for usage within Coreboot, but can be used outside
+ * Coreboot as well.
+ *
+ ********/
+
+/**==========================================================================
+ *  The defintion of the command table; opcode, address, direction and bit
+ *  widths. This can easily adapted for other SPI eeproms. Currently the
+ *  93LC46 A/B/C types are supported. When using the C type depending on
+ *  8 or 16 modes (see ORG line in datasheet) use the A or B commands.
+ *
+ *  When the 'address' contains 0xFFFF this means that the address is taken
+ *  from the caller.
+ */
+static struct tag_spi_93LC46_eeprom_commands
+{
+  uint16_t  opcode;
+  uint8_t   opcode_width;
+  uint16_t  address;
+  uint8_t   address_width;
+  uint8_t   data_width;
+  uint8_t   direction;
+} COMMANDS[ SPI_93LC46_MAX_COMMANDS ] = {
+  { 0x0000, 0, 0x0000, 0,  0, 0 },  // SPI_CHIP_NULL_PLACEHOLDER
+#ifdef CONFIG_USES_93LC46_8BIT
+  { 0x0004, 3, 0x0000, 7,  0, 0 },  // SPI_EEPROM_WRITE_DISABLE
+  { 0x0004, 3, 0x0010, 7,  8, 0 },  // SPI_EEPROM_WRITE_ALL
+  { 0x0004, 3, 0x0020, 7,  0, 0 },  // SPI_EEPROM_ERASE_ALL
+  { 0x0004, 3, 0x0030, 7,  0, 0 },  // SPI_EEPROM_WRITE_ENABLE
+  { 0x0005, 3, 0xFFFF, 7,  8, 0 },  // SPI_EEPROM_WRITE
+  { 0x0006, 3, 0xFFFF, 7,  8, 1 },  // SPI_EEPROM_READ
+  { 0x0007, 3, 0xFFFF, 7,  0, 0 },  // SPI_EEPROM_ERASE
+#endif
+#ifdef CONFIG_USES_93LC46_16BIT
+  { 0x0004, 3, 0x0000, 6,  0, 0 },  // SPI_EEPROM_WRITE_DISABLE
+  { 0x0004, 3, 0x0010, 6, 16, 0 },  // SPI_EEPROM_WRITE_ALL
+  { 0x0004, 3, 0x0020, 6,  0, 0 },  // SPI_EEPROM_ERASE_ALL
+  { 0x0004, 3, 0x0030, 6,  0, 0 },  // SPI_EEPROM_WRITE_ENABLE
+  { 0x0005, 3, 0xFFFF, 6, 16, 0 },  // SPI_EEPROM_WRITE
+  { 0x0006, 3, 0xFFFF, 6, 16, 1 },  // SPI_EEPROM_READ
+  { 0x0007, 3, 0xFFFF, 6,  0, 0 },  // SPI_EEPROM_ERASE
+#endif
+};
+/**--------------------------------------------------------------------------
+ *
+ */
+uint16_t spi_93LC46_action( SPI_93LC46_CMDS eCmd, uint16_t addr, uint8_t* data )
+{
+  uint16_t  address = addr;
+  SpiInterface.spi_start();
+  SpiInterface.spi_write( COMMANDS[ eCmd ].opcode_width, COMMANDS[ eCmd ].opcode );
+  if ( COMMANDS[ eCmd ].address != 0xFFFF )
+  {
+    address = COMMANDS[ eCmd ].address;
+  }
+  SpiInterface.spi_write( COMMANDS[ eCmd ].address_width, address );
+  if ( COMMANDS[ eCmd ].data_width > 0 )
+  {
+    uint8_t len = COMMANDS[ eCmd ].data_width;
+    uint8_t off = 0;
+    if ( COMMANDS[ eCmd ].direction == 0 )
+    {
+      while ( len )
+      {
+        // Write the data to the device
+        SpiInterface.spi_write( 8, data[ off++ ] );
+        len -= 8;
+      }
+      SpiInterface.spi_wait_for_ready();
+    }
+    else
+    {
+      while ( len )
+      {
+        // Read the data from the device
+        data[ off ] = SpiInterface.spi_read( 8 );
+        off++;
+        len -= 8;
+      }
+    }
+  }
+  SpiInterface.spi_stop();
+  return ( COMMANDS[ eCmd ].data_width );
+}
+#ifdef CONFIG_USES_93LC46_8BIT
+/**--------------------------------------------------------------------------
+ *
+ */
+void spi_93LC46A_read( int address, uint8_t *bytes, uint16_t size )	// the length of 'bytes' must be divideble by 2 !!!
+{
+  uint16_t i;
+  for ( i = 0; i < size; i++ )
+  {
+    spi_93LC46_action( SPI_93LC46A_READ, address + i, bytes + i );
+  }
+	return;
+}
+/**--------------------------------------------------------------------------
+ *
+ */
+void spi_93LC46A_write( int address, uint8_t *bytes, uint16_t size )	// the length of 'bytes' must be divideble by 2 !!!
+{
+  uint16_t i;
+  spi_93LC46A_enable_wr();
+	for ( i = 0; i < size; i++ )
+	{
+    spi_93LC46_action( SPI_93LC46A_WRITE, address + i, bytes + i )
+	}
+  spi_93LC46A_disable_wr();
+	return;
+}
+#endif
+#ifdef CONFIG_USES_93LC46_16BIT
+/**--------------------------------------------------------------------------
+ *
+ */
+void spi_93LC46B_read( int address, uint8_t *bytes, uint16_t size )	// the length of 'bytes' must be divideble by 2 !!!
+{
+  uint16_t i;
+  address /= 2;
+  for ( i = 0; i < size; i++ )
+  {
+    if ( spi_93LC46_action( SPI_93LC46B_READ, address + (i / 2), bytes + i ) == 16 )
+    {
+      i++;
+    }
+  }
+	return;
+}
+/**--------------------------------------------------------------------------
+ *
+ */
+void spi_93LC46B_write( int address, uint8_t *bytes, uint16_t size )	// the length of 'bytes' must be divideble by 2 !!!
+{
+  uint16_t i;
+  spi_93LC46B_enable_wr();
+  address /= 2;
+	for ( i = 0; i < size; i++ )
+	{
+    if ( spi_93LC46_action( SPI_93LC46B_WRITE, address + (i / 2), bytes + i ) == 16 )
+    {
+      i++;
+    }
+	}
+  spi_93LC46B_disable_wr();
+	return;
+}
+#endif
+/**--------------------------------------------------------------------------
+ * END
+ */
Index: src/mainboard/nokia/ip530/spi_interface.h
===================================================================
--- src/mainboard/nokia/ip530/spi_interface.h	(revision 0)
+++ src/mainboard/nokia/ip530/spi_interface.h	(revision 0)
@@ -0,0 +1,26 @@
+#ifndef __SPI_INTERFACE_H__
+#define __SPI_INTERFACE_H__
+#include <stdint.h>
+
+typedef struct tag_spi_bitfunctions
+{
+  int     (*spi_init)( uint16_t port, int spi_delay );
+  /*  This function generates a START condition on the SPI bus */
+  void    (*spi_start)( void );
+  /*  This function generates a STOP condition on the SPI bus */
+  void    (*spi_stop)( void );
+  /*  This function creates a STOP condition and waits on the SPI slave to
+   *  release the SPI bus. */
+  void    (*spi_wait_for_ready)( void );
+  /*  This function takes care of the writing of the specified number of bits */
+  void    (*spi_write)( int8_t bits, int command );
+  /*  This function takes care of the reading of the specified number of bits */
+  int     (*spi_read)( int8_t bits );
+} SPI_INTF_FUNCTIONS;
+
+/*
+ * This must be defined by the user, with its own SPI routines
+ */
+extern SPI_INTF_FUNCTIONS    SpiInterface;
+
+#endif
Index: src/mainboard/nokia/ip530/superio_spi.c
===================================================================
--- src/mainboard/nokia/ip530/superio_spi.c	(revision 0)
+++ src/mainboard/nokia/ip530/superio_spi.c	(revision 0)
@@ -0,0 +1,249 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2009-2010 Marc Bertens
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+//#include <errno.h>
+//#include <stdlib.h>
+//#include <string.h>	        // for strcmp()
+#include <stdint.h>
+#include "superio.h"
+#ifndef CONFIG_BOARD_NOKIA_IP530
+#include "superio_spi.h"
+#endif
+#include "spi_interface.h"
+
+/****************************************************************************
+ * This is written for usage within Coreboot, but can be used outside
+ * Coreboot as well. It accesses the SPI eeprom behind the SuperIO chip.
+ * It uses the bitbang mechanism to control the SPI bus.
+ *
+ ********/
+
+/**--------------------------------------------------------------------------
+ *  Cached value of last GPIO state.
+ */
+static uint8_t 	bGpioState  = 0;
+#ifdef CONFIG_BOARD_NOKIA_IP530
+/* When compiling into Coreboot for the Nokia IP530 don't bother having those
+ * values configurable */
+# define  iSuperIoPort        0x3F0
+# define  iSpiHalfPeriod      0
+/* Use Coreboots delay function */
+# define  spi_delay( d )      mdelay( d )
+#else
+/* Address of Super I/O chip */
+uint16_t  iSuperIoPort      = 0x3F0;
+/* Half a period delay */
+int       iSpiHalfPeriod    = 0;
+
+/**--------------------------------------------------------------------------
+ *  loops per microsecond
+ */
+static void spi_delay( int usecs )
+{
+  static unsigned long micro = 1;
+	unsigned long i;
+	for (i = 0; i < usecs * micro; i++) {
+		/* Make sure the compiler doesn't optimize the loop away. */
+		asm volatile ("" : : "rm" (i) );
+	}
+	return;
+}
+#endif
+/**--------------------------------------------------------------------------
+ *  This function sets the SuperIO into config mode, selects Logical Device
+ *  eight (8 = GPIO Device) and reads the GPIO line register.
+ */
+static void superio_access_spibus( void )
+{
+  superio_acquire_configmode( iSuperIoPort );
+	/* select the Logical Device Number <ldn> */
+	superio_write_reg( iSuperIoPort, SUPERIO_LDN_REG, SUPERIO_LDN_GPIO );
+	/* Update the cache. */
+	bGpioState = superio_read_reg( iSuperIoPort, SUPERIO_GPIO_SPI_REG );
+	return;
+}
+/**--------------------------------------------------------------------------
+ *  This function takes care of the reading of the specified number of bits
+ *
+ *    +-----+
+ *    |     |     |
+ *  --+     +-----+
+ *    1  2  3  4
+ *   A  B  C  D
+ */
+static int superio_spi_read( int8_t bits )
+{
+	int ret = 0;
+	int i;
+	superio_access_spibus();
+	for ( i = bits-1; i >= 0; i-- )
+	{
+    /* Wait A */
+		spi_delay( iSpiHalfPeriod );
+	  /* Step 1: pullup SCK line */
+	  bGpioState	|= SPI_SCK;
+	  superio_write_reg( iSuperIoPort, SUPERIO_GPIO_SPI_REG, bGpioState );
+		/* Wait B */
+		spi_delay( iSpiHalfPeriod );
+		ret <<= 1;
+		/* Step 2: Get the MISO line state */
+		bGpioState = superio_read_reg( iSuperIoPort, SUPERIO_GPIO_SPI_REG );
+		ret |= (((bGpioState & SPI_MISO) == SPI_MISO)& 0x01);
+		/* Wait C */
+		spi_delay( iSpiHalfPeriod );
+		/* pulldown SCK line */
+		bGpioState	&= ~SPI_SCK;
+		superio_write_reg( iSuperIoPort, SUPERIO_GPIO_SPI_REG, bGpioState );
+		/* Wait D */
+		spi_delay( iSpiHalfPeriod );
+	}
+	superio_release_configmode( iSuperIoPort );
+	return ( ret );
+}
+/**--------------------------------------------------------------------------
+ *  This function takes care of the writing of the specified number of bits
+ *
+ *    +-----+
+ *    |     |     |
+ *  --+     +-----+
+ *  1 2     3
+ *   A  B C  D
+ */
+static void superio_spi_write( int8_t bits, int data )
+{
+	int i;
+	superio_access_spibus();
+	for ( i = bits-1; i >= 0; i-- )
+	{
+	  /* Step 1: Set the MOSI line state */
+	  if ( (data >> i) & 0x01 )
+      bGpioState	|= SPI_MOSI;
+    else
+      bGpioState	&= ~SPI_MOSI;
+		superio_write_reg( iSuperIoPort, SUPERIO_GPIO_SPI_REG, bGpioState );
+    /* Wait A */
+		spi_delay( iSpiHalfPeriod );
+		/* Step 2: pullup SCK line */
+		bGpioState	|= SPI_SCK;
+	  superio_write_reg( iSuperIoPort, SUPERIO_GPIO_SPI_REG, bGpioState );
+	  /* Wait B */
+		spi_delay( iSpiHalfPeriod );
+		/* Wait C */
+		spi_delay( iSpiHalfPeriod );
+		/* Step 3: pulldown SCK line */
+		bGpioState	&= ~SPI_SCK;
+		superio_write_reg( iSuperIoPort, SUPERIO_GPIO_SPI_REG, bGpioState );
+		/* Wait D */
+		spi_delay( iSpiHalfPeriod );
+  }
+  superio_release_configmode( iSuperIoPort );
+	return;
+}
+/**--------------------------------------------------------------------------
+ *  This function creates a STOP condition and waits on the SPI slave to
+ *  release the SPI bus.
+ */
+static void superio_spi_wait_for_ready( void )
+{
+  uint16_t  j;
+  superio_access_spibus();
+  /* Generate a COMMIT condition.
+   * pulldown CS line */
+  bGpioState	&= ~SPI_CS;
+  /* pullup SCK line */
+  bGpioState  |= SPI_SCK;
+  superio_write_reg( iSuperIoPort, SUPERIO_GPIO_SPI_REG, bGpioState );
+  spi_delay( iSpiHalfPeriod );
+  /* pullup CS line */
+  bGpioState	|= SPI_CS;
+  /* pulldown SCK line */
+  bGpioState  &= ~SPI_SCK;
+  superio_write_reg( iSuperIoPort, SUPERIO_GPIO_SPI_REG, bGpioState );
+  spi_delay( iSpiHalfPeriod );
+  /* Wait for the SLAVE */
+  do
+  {
+    /* pullup SCK line */
+    bGpioState  |= SPI_SCK;
+    superio_write_reg( iSuperIoPort, SUPERIO_GPIO_SPI_REG, bGpioState );
+		spi_delay( iSpiHalfPeriod );
+		/* Update the cache. */
+    bGpioState = superio_read_reg( iSuperIoPort, SUPERIO_GPIO_SPI_REG );
+		j = ((bGpioState & SPI_MISO) == SPI_MISO);
+		spi_delay( iSpiHalfPeriod );
+		/* pulldown SCK line */
+		bGpioState  &= ~SPI_SCK;
+    superio_write_reg( iSuperIoPort, SUPERIO_GPIO_SPI_REG, bGpioState );
+    spi_delay( iSpiHalfPeriod );
+  }
+  while ( !j );
+  superio_release_configmode( iSuperIoPort );
+  return;
+}
+/**--------------------------------------------------------------------------
+ *  This function generates a START condition on the SPI bus
+ */
+static void superio_spi_start( void )
+{
+  superio_access_spibus();
+  /* Check of the MISO and SCK lines are NOT down */
+  if ( bGpioState & ( SPI_MISO | SPI_SCK ) )
+  {
+    /* SPI bus is wrong state
+     * Pull down the CS, SCK and MOSI lines */
+    bGpioState &= ~SPI_CS_SCK_MOSI;
+    superio_write_reg( iSuperIoPort, SUPERIO_GPIO_SPI_REG, bGpioState );
+    spi_delay( iSpiHalfPeriod );
+  }
+  /* Generate the START condition on the SPI bus
+   * pullup CS line */
+  bGpioState  |= SPI_CS;
+  superio_write_reg( iSuperIoPort, SUPERIO_GPIO_SPI_REG, bGpioState );
+  superio_release_configmode( iSuperIoPort );
+  return;
+}
+/**--------------------------------------------------------------------------
+ *  This function generates a STOP condition on the SPI bus
+ */
+static void superio_spi_stop( void )
+{
+  superio_access_spibus();
+  /* Pull down the CS, SCK and MOSI lines */
+  bGpioState &= ~SPI_CS_SCK_MOSI;
+  superio_write_reg( iSuperIoPort, SUPERIO_GPIO_SPI_REG, bGpioState );
+  superio_release_configmode( iSuperIoPort );
+  return;
+}
+/**--------------------------------------------------------------------------
+ *  This publish the functions of the SPI bus.
+ */
+SPI_INTF_FUNCTIONS    SpiInterface = {
+#ifndef CONFIG_BOARD_NOKIA_IP530
+    .spi_init           = superio_spi_init,
+#else
+    .spi_init           = 0,
+#endif
+    .spi_start          = superio_spi_start,
+    .spi_stop           = superio_spi_stop,
+    .spi_wait_for_ready = superio_spi_wait_for_ready,
+    .spi_write          = superio_spi_write,
+    .spi_read           = superio_spi_read
+};
+/**--------------------------------------------------------------------------
+ * END
+ */
Index: src/mainboard/nokia/ip530/microchip93lc46b_spi.h
===================================================================
--- src/mainboard/nokia/ip530/microchip93lc46b_spi.h	(revision 0)
+++ src/mainboard/nokia/ip530/microchip93lc46b_spi.h	(revision 0)
@@ -0,0 +1,57 @@
+#ifndef __MICROCHIP_93LC46B_SPI_H__
+# define __MICROCHIP_93LC46B_SPI_H__
+# include <stdint.h>
+
+typedef enum
+{
+  SPI_CHIP_NULL_PLACEHOLDER = 0,
+# ifdef CONFIG_USES_93LC46_8BIT
+  SPI_93LC46A_WRITE_DISABLE,
+  SPI_93LC46A_WRITE_ALL,
+  SPI_93LC46A_ERASE_ALL,
+  SPI_93LC46A_WRITE_ENABLE,
+  SPI_93LC46A_WRITE,
+  SPI_93LC46A_READ,
+  SPI_93LC46A_ERASE,
+# endif
+# ifdef CONFIG_USES_93LC46_16BIT
+  SPI_93LC46B_WRITE_DISABLE,
+  SPI_93LC46B_WRITE_ALL,
+  SPI_93LC46B_ERASE_ALL,
+  SPI_93LC46B_WRITE_ENABLE,
+  SPI_93LC46B_WRITE,
+  SPI_93LC46B_READ,
+  SPI_93LC46B_ERASE,
+# endif
+  SPI_93LC46_MAX_COMMANDS,
+} SPI_93LC46_CMDS;
+
+/*  Core function for the 93LC46B chip */
+uint16_t  spi_93LC46_action( SPI_93LC46_CMDS eCmd, uint16_t addr, uint8_t* data );
+
+# ifdef CONFIG_USES_93LC46_8BIT
+#  define   spi_93LC46A_erase( addr )            spi_93LC46_action( SPI_93LC46A_ERASE, addr, '\0' )
+#  define   spi_93LC46A_erase_all()              spi_93LC46_action( SPI_93LC46A_ERASE_ALL, 0, 0xFF )
+#  define   spi_93LC46A_enable_wr()              spi_93LC46_action( SPI_93LC46A_WRITE_ENABLE, 0, '\0' )
+#  define   spi_93LC46A_disable_wr()             spi_93LC46_action( SPI_93LC46A_WRITE_DISABLE, 0, '\0' )
+#  define   spi_93LC46A_write_word( addr, data ) spi_93LC46_action( SPI_93LC46A_WRITE, addr, data )
+#  define   spi_93LC46A_write_all( data )        spi_93LC46_action( SPI_93LC46A_WRITE_ALL, 0, data )
+#  define   spi_93LC46A_read_word( addr, data )  spi_93LC46_action( SPI_93LC46A_READ, addr, data )
+
+void      spi_93LC46A_read( int address, uint8_t *bytes, uint16_t size );
+void      spi_93LC46A_write( int address, uint8_t *bytes, uint16_t size );
+# endif
+
+# ifdef CONFIG_USES_93LC46_16BIT
+#  define   spi_93LC46B_erase( addr )            spi_93LC46_action( SPI_93LC46B_ERASE, addr, '\0' )
+#  define   spi_93LC46B_erase_all()              spi_93LC46_action( SPI_93LC46B_ERASE_ALL, 0, (uint8_t*)"\xFF\xFF" )
+#  define   spi_93LC46B_enable_wr()              spi_93LC46_action( SPI_93LC46B_WRITE_ENABLE, 0, '\0' )
+#  define   spi_93LC46B_disable_wr()             spi_93LC46_action( SPI_93LC46B_WRITE_DISABLE, 0, '\0' )
+#  define   spi_93LC46B_write_word( addr, data ) spi_93LC46_action( SPI_93LC46B_WRITE, addr, data )
+#  define   spi_93LC46B_write_all( data )        spi_93LC46_action( SPI_93LC46B_WRITE_ALL, 0, data )
+#  define   spi_93LC46B_read_word( addr, data )  spi_93LC46_action( SPI_93LC46B_READ, addr, data )
+
+void      spi_93LC46B_read( int address, uint8_t *bytes, uint16_t size );
+void      spi_93LC46B_write( int address, uint8_t *bytes, uint16_t size );
+# endif
+#endif
Index: src/mainboard/nokia/ip530/superio.c
===================================================================
--- src/mainboard/nokia/ip530/superio.c	(revision 0)
+++ src/mainboard/nokia/ip530/superio.c	(revision 0)
@@ -0,0 +1,75 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2009-2010 Marc Bertens
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+#ifdef CONFIG_BOARD_NOKIA_IP530
+/* Take the coreboot definition */
+# include <arch/io.h> // for outb(), outw(), outl(), inb(), inw() and inl()
+#else
+/* Take the Linux defintion */
+# include <sys/io.h>  // for outb(), outw(), outl(), inb(), inw() and inl()
+#endif
+#include "superio.h"  // For prototype check
+/****************************************************************************
+ * This is written for usage within Coreboot, but can be used outside
+ * Coreboot as well. It accesses the SPI eeprom behind the SuperIO chip.
+ * It uses the bitbang mechanism to control the SPI bus.
+ *
+ ********/
+//===========================================================================
+// Puts the superio into config mode
+//
+void superio_acquire_configmode( uint16_t port )
+{
+	/* enter_config_mode */
+	outb( 0x55, port );
+	/* In the superiotool does two writes to the port to get it in config mode */
+	outb( 0x55, port );
+	return;
+}
+//---------------------------------------------------------------------------
+// Exits the superio from config mode into normal mode.
+//
+void superio_release_configmode( uint16_t port )
+{
+	/* Exit config mode of the FDC37B878 */
+	outb( 0xAA, port );
+	return;
+}
+//---------------------------------------------------------------------------
+// Writes the data to a specific register on a specific device port address
+//
+void superio_write_reg( uint16_t port, uint8_t reg, uint8_t value )
+{
+  // Write on the control port the register to write to
+	outb( reg, port );
+	// Write on the data port the data to the register
+	outb( value, port + 1 );
+	return;
+}
+//---------------------------------------------------------------------------
+// Reads the data from a specific register on a specific device port address
+//
+uint8_t superio_read_reg( uint16_t port, uint8_t reg )
+{
+  // Write on the control port the register to read from
+	outb( reg, port );
+	// Read from the data port the data from the register
+	return ( inb( port + 1 ) );
+}
+//---------------------------------------------------------------------------
+
Index: src/mainboard/nokia/ip530/superio_spi.h
===================================================================
--- src/mainboard/nokia/ip530/superio_spi.h	(revision 0)
+++ src/mainboard/nokia/ip530/superio_spi.h	(revision 0)
@@ -0,0 +1,30 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2009-2010 Marc Bertens
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+#ifndef __SUPERIO_SPI_H__
+#define __SUPERIO_SPI_H__
+#include <stdint.h>
+#include <stdio.h>  // for NULL
+
+/* For outside Coreboot */
+extern int      iSpiHalfPeriod;
+extern uint16_t iSuperIoPort;
+
+int             superio_spi_init( uint16_t port, int spi_delay );
+
+#endif
Index: src/mainboard/nokia/ip530/superio.h
===================================================================
--- src/mainboard/nokia/ip530/superio.h	(revision 0)
+++ src/mainboard/nokia/ip530/superio.h	(revision 0)
@@ -0,0 +1,36 @@
+#ifndef __SUPERIO_H__
+#define __SUPERIO_H__
+#include <stdint.h>
+
+#define SUPERIO_FDC37B787_ID      0x44
+#define SUPERIO_FDC37B787_REV     0x03
+
+#define SUPERIO_LDN_REG           0x07
+#define SUPERIO_LDN_GPIO          0x08
+
+#define SUPERIO_DEVICE_ID         0x20
+#define SUPERIO_DEVICE_REV        0x21
+
+#define SUPERIO_GPIO_CFG_MOSI     0xE0
+#define SUPERIO_GPIO_CFG_MISO     0xE1
+#define SUPERIO_GPIO_CFG_SCK      0xE4
+#define SUPERIO_GPIO_CFG_CS       0xE5
+#define SUPERIO_GPIO_SPI_REG      0xF6
+
+#define SUPERIO_GPIO_OUTPUT_LINE  0x00
+#define SUPERIO_GPIO_INPUT_LINE   0x01
+
+#define SPI_MOSI                  0x01
+#define SPI_MISO                  0x02
+#define SPI_SCK                   0x10
+#define SPI_CS                    0x20
+
+#define SPI_CS_SCK_MOSI           0x31
+
+void    superio_acquire_configmode( uint16_t port );
+void    superio_release_configmode( uint16_t port );
+
+void    superio_write_reg( uint16_t port, uint8_t reg, uint8_t value );
+uint8_t superio_read_reg( uint16_t port, uint8_t reg );
+
+#endif
-- 
coreboot mailing list: [email protected]
http://www.coreboot.org/mailman/listinfo/coreboot

Reply via email to