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
