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 );
+}
