sb/intel/*: Use common SMBus functions

All Intel southbridges implement the same SMBus functions.
This patch replaces all these similar and mostly identical
implementations with a common file.

This also makes i2c block read available to all those southbridges.
If the northbridge has to read a lot of SPD bytes sequentially, using
this function can reduce the time being spent to read SPD five-fold.

Change-Id: I93bb186e04e8c32dff04fc1abe4b5ecbc4c9c962
Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
Reviewed-on: https://review.coreboot.org/19258
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
diff --git a/src/include/device/smbus_def.h b/src/include/device/smbus_def.h
index 971e975..0b07400 100644
--- a/src/include/device/smbus_def.h
+++ b/src/include/device/smbus_def.h
@@ -5,5 +5,6 @@
 #define SMBUS_ERROR -1
 #define SMBUS_WAIT_UNTIL_READY_TIMEOUT -2
 #define SMBUS_WAIT_UNTIL_DONE_TIMEOUT  -3
+#define SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT -4
 
 #endif /* DEVICE_SMBUS_DEF_H */
diff --git a/src/northbridge/intel/sandybridge/raminit.c b/src/northbridge/intel/sandybridge/raminit.c
index b505556..2854a2b 100644
--- a/src/northbridge/intel/sandybridge/raminit.c
+++ b/src/northbridge/intel/sandybridge/raminit.c
@@ -25,7 +25,7 @@
 #include <timestamp.h>
 #include <northbridge/intel/common/mrc_cache.h>
 #include <southbridge/intel/bd82x6x/me.h>
-#include <southbridge/intel/bd82x6x/smbus.h>
+#include <southbridge/intel/common/smbus.h>
 #include <cpu/x86/msr.h>
 #include <delay.h>
 #include <smbios.h>
diff --git a/src/southbridge/intel/bd82x6x/Kconfig b/src/southbridge/intel/bd82x6x/Kconfig
index 6522cce..c24c71c 100644
--- a/src/southbridge/intel/bd82x6x/Kconfig
+++ b/src/southbridge/intel/bd82x6x/Kconfig
@@ -25,6 +25,7 @@
 	def_bool y
 	select ACPI_INTEL_HARDWARE_SLEEP_VALUES
 	select SOUTHBRIDGE_INTEL_COMMON
+	select SOUTHBRIDGE_INTEL_COMMON_SMBUS
 	select IOAPIC
 	select HAVE_HARD_RESET
 	select HAVE_USBDEBUG_OPTIONS
diff --git a/src/southbridge/intel/bd82x6x/early_smbus.c b/src/southbridge/intel/bd82x6x/early_smbus.c
index 9f74fdd..4c67aea 100644
--- a/src/southbridge/intel/bd82x6x/early_smbus.c
+++ b/src/southbridge/intel/bd82x6x/early_smbus.c
@@ -18,8 +18,8 @@
 #include <console/console.h>
 #include <device/pci_ids.h>
 #include <device/pci_def.h>
+#include <southbridge/intel/common/smbus.h>
 #include "pch.h"
-#include "smbus.h"
 
 void enable_smbus(void)
 {
diff --git a/src/southbridge/intel/bd82x6x/pch.h b/src/southbridge/intel/bd82x6x/pch.h
index 0ae9826..dcd7b2e 100644
--- a/src/southbridge/intel/bd82x6x/pch.h
+++ b/src/southbridge/intel/bd82x6x/pch.h
@@ -265,22 +265,6 @@
 #define SMB_SMI_EN		(1 << 1)
 #define HST_EN			(1 << 0)
 
-/* SMBus I/O bits. */
-#define SMBHSTSTAT		0x0
-#define SMBHSTCTL		0x2
-#define SMBHSTCMD		0x3
-#define SMBXMITADD		0x4
-#define SMBHSTDAT0		0x5
-#define SMBHSTDAT1		0x6
-#define SMBBLKDAT		0x7
-#define SMBTRNSADD		0x9
-#define SMBSLVDATA		0xa
-#define SMLINK_PIN_CTL		0xe
-#define SMBUS_PIN_CTL		0xf
-
-#define SMBUS_TIMEOUT		(10 * 1000 * 100)
-
-
 /* Southbridge IO BARs */
 
 #define GPIOBASE		0x48
diff --git a/src/southbridge/intel/bd82x6x/smbus.c b/src/southbridge/intel/bd82x6x/smbus.c
index c450d9b..6cbdef9 100644
--- a/src/southbridge/intel/bd82x6x/smbus.c
+++ b/src/southbridge/intel/bd82x6x/smbus.c
@@ -22,8 +22,8 @@
 #include <device/pci_ids.h>
 #include <device/pci_ops.h>
 #include <arch/io.h>
+#include <southbridge/intel/common/smbus.h>
 #include "pch.h"
-#include "smbus.h"
 
 static void pch_smbus_init(device_t dev)
 {
@@ -54,49 +54,6 @@
 	return do_smbus_read_byte(res->base, device, address);
 }
 
-static  int do_smbus_write_byte(unsigned smbus_base, unsigned device, unsigned address, unsigned data)
-{
-	unsigned char global_status_register;
-
-	if (smbus_wait_until_ready(smbus_base) < 0)
-		return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
-
-	/* Setup transaction */
-	/* Disable interrupts */
-	outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
-	/* Set the device I'm talking too */
-	outb(((device & 0x7f) << 1) & ~0x01, smbus_base + SMBXMITADD);
-	/* Set the command/address... */
-	outb(address & 0xff, smbus_base + SMBHSTCMD);
-	/* Set up for a byte data read */
-	outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x2 << 2),
-	     (smbus_base + SMBHSTCTL));
-	/* Clear any lingering errors, so the transaction will run */
-	outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
-
-	/* Clear the data byte... */
-	outb(data, smbus_base + SMBHSTDAT0);
-
-	/* Start the command */
-	outb((inb(smbus_base + SMBHSTCTL) | 0x40),
-	     smbus_base + SMBHSTCTL);
-
-	/* Poll for transaction completion */
-	if (smbus_wait_until_done(smbus_base) < 0)
-		return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
-
-	global_status_register = inb(smbus_base + SMBHSTSTAT);
-
-	/* Ignore the "In Use" status... */
-	global_status_register &= ~(3 << 5);
-
-	/* Read results of transaction */
-	if (global_status_register != (1 << 1))
-		return SMBUS_ERROR;
-
-	return 0;
-}
-
 static int lsmbus_write_byte(device_t dev, u8 address, u8 val)
 {
 	u16 device;
diff --git a/src/southbridge/intel/bd82x6x/smbus.h b/src/southbridge/intel/bd82x6x/smbus.h
deleted file mode 100644
index 0978963..0000000
--- a/src/southbridge/intel/bd82x6x/smbus.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * This file is part of the coreboot project.
- *
- * Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com>
- * Copyright (C) 2009 coresystems GmbH
- *
- * 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.
- */
-
-#include <device/smbus_def.h>
-#include "pch.h"
-
-static void smbus_delay(void)
-{
-	inb(0x80);
-}
-
-static int smbus_wait_until_ready(u16 smbus_base)
-{
-	unsigned loops = SMBUS_TIMEOUT;
-	unsigned char byte;
-	do {
-		smbus_delay();
-		if (--loops == 0)
-			break;
-		byte = inb(smbus_base + SMBHSTSTAT);
-	} while (byte & 1);
-	return loops ? 0 : -1;
-}
-
-static int smbus_wait_until_done(u16 smbus_base)
-{
-	unsigned loops = SMBUS_TIMEOUT;
-	unsigned char byte;
-	do {
-		smbus_delay();
-		if (--loops == 0)
-			break;
-		byte = inb(smbus_base + SMBHSTSTAT);
-	} while ((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0);
-	return loops ? 0 : -1;
-}
-
-static int do_smbus_read_byte(unsigned smbus_base, unsigned device, unsigned address)
-{
-	unsigned char global_status_register;
-	unsigned char byte;
-
-	if (smbus_wait_until_ready(smbus_base) < 0) {
-		return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
-	}
-	/* Setup transaction */
-	/* Disable interrupts */
-	outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
-	/* Set the device I'm talking too */
-	outb(((device & 0x7f) << 1) | 1, smbus_base + SMBXMITADD);
-	/* Set the command/address... */
-	outb(address & 0xff, smbus_base + SMBHSTCMD);
-	/* Set up for a byte data read */
-	outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x2 << 2),
-	     (smbus_base + SMBHSTCTL));
-	/* Clear any lingering errors, so the transaction will run */
-	outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
-
-	/* Clear the data byte... */
-	outb(0, smbus_base + SMBHSTDAT0);
-
-	/* Start the command */
-	outb((inb(smbus_base + SMBHSTCTL) | 0x40),
-	     smbus_base + SMBHSTCTL);
-
-	/* Poll for transaction completion */
-	if (smbus_wait_until_done(smbus_base) < 0) {
-		return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
-	}
-
-	global_status_register = inb(smbus_base + SMBHSTSTAT);
-
-	/* Ignore the "In Use" status... */
-	global_status_register &= ~(3 << 5);
-
-	/* Read results of transaction */
-	byte = inb(smbus_base + SMBHSTDAT0);
-	if (global_status_register != (1 << 1)) {
-		return SMBUS_ERROR;
-	}
-	return byte;
-}
diff --git a/src/southbridge/intel/common/Kconfig b/src/southbridge/intel/common/Kconfig
index 7bc686d..23fb8ce 100644
--- a/src/southbridge/intel/common/Kconfig
+++ b/src/southbridge/intel/common/Kconfig
@@ -2,3 +2,5 @@
 	def_bool n
 config SOUTHBRIDGE_INTEL_COMMON_GPIO
 	def_bool n
+config SOUTHBRIDGE_INTEL_COMMON_SMBUS
+	def_bool n
diff --git a/src/southbridge/intel/common/Makefile.inc b/src/southbridge/intel/common/Makefile.inc
index 56ba56f..5810394 100644
--- a/src/southbridge/intel/common/Makefile.inc
+++ b/src/southbridge/intel/common/Makefile.inc
@@ -24,4 +24,8 @@
 romstage-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON_GPIO) += gpio.c
 ramstage-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON_GPIO) += gpio.c
 smm-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON_GPIO) += gpio.c
+
+romstage-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON_SMBUS) += smbus.c
+ramstage-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON_SMBUS) += smbus.c
+
 endif
diff --git a/src/southbridge/intel/common/smbus.c b/src/southbridge/intel/common/smbus.c
new file mode 100644
index 0000000..cac9ba7
--- /dev/null
+++ b/src/southbridge/intel/common/smbus.c
@@ -0,0 +1,365 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com>
+ * Copyright (C) 2009 coresystems GmbH
+ * Copyright (C) 2013 Vladimir Serbinenko
+ *
+ * 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.
+ */
+
+#include <arch/io.h>
+#include <device/smbus_def.h>
+#include "smbus.h"
+
+
+/* I801 command constants */
+#define I801_QUICK		(0 << 2)
+#define I801_BYTE		(1 << 2)
+#define I801_BYTE_DATA		(2 << 2)
+#define I801_WORD_DATA		(3 << 2)
+#define I801_BLOCK_DATA		(5 << 2)
+#define I801_I2C_BLOCK_DATA	(6 << 2) /* ICH5 and later */
+
+/* I801 Host Control register bits */
+#define SMBHSTCNT_INTREN	(1 << 0)
+#define SMBHSTCNT_KILL		(1 << 1)
+#define SMBHSTCNT_LAST_BYTE	(1 << 5)
+#define SMBHSTCNT_START		(1 << 6)
+#define SMBHSTCNT_PEC_EN	(1 << 7) /* ICH3 and later */
+
+/* I801 Hosts Status register bits */
+#define SMBHSTSTS_BYTE_DONE	(1 << 7)
+#define SMBHSTSTS_INUSE_STS	(1 << 6)
+#define SMBHSTSTS_SMBALERT_STS	(1 << 5)
+#define SMBHSTSTS_FAILED	(1 << 4)
+#define SMBHSTSTS_BUS_ERR	(1 << 3)
+#define SMBHSTSTS_DEV_ERR	(1 << 2)
+#define SMBHSTSTS_INTR		(1 << 1)
+#define SMBHSTSTS_HOST_BUSY	(1 << 0)
+
+#define SMBUS_TIMEOUT		(10 * 1000 * 100)
+
+static void smbus_delay(void)
+{
+	inb(0x80);
+}
+
+static int smbus_wait_until_ready(u16 smbus_base)
+{
+	unsigned int loops = SMBUS_TIMEOUT;
+	unsigned char byte;
+	do {
+		smbus_delay();
+		if (--loops == 0)
+			break;
+		byte = inb(smbus_base + SMBHSTSTAT);
+	} while (byte & SMBHSTSTS_HOST_BUSY);
+	return loops ? 0 : -1;
+}
+
+static int smbus_wait_until_done(u16 smbus_base)
+{
+	unsigned int loops = SMBUS_TIMEOUT;
+	unsigned char byte;
+	do {
+		smbus_delay();
+		if (--loops == 0)
+			break;
+		byte = inb(smbus_base + SMBHSTSTAT);
+	} while ((byte & SMBHSTSTS_HOST_BUSY)
+		|| (byte & ~(SMBHSTSTS_INUSE_STS | SMBHSTSTS_HOST_BUSY)) == 0);
+	return loops ? 0 : -1;
+}
+
+static int smbus_wait_until_active(u16 smbus_base)
+{
+	unsigned long loops;
+	loops = SMBUS_TIMEOUT;
+	do {
+		unsigned char val;
+		smbus_delay();
+		val = inb(smbus_base + SMBHSTSTAT);
+		if ((val & SMBHSTSTS_HOST_BUSY)) {
+			break;
+		}
+	} while (--loops);
+	return loops ? 0 : -1;
+}
+
+int do_smbus_read_byte(unsigned int smbus_base, u8 device,
+		unsigned int address)
+{
+	unsigned char status;
+	unsigned char byte;
+
+	if (smbus_wait_until_ready(smbus_base) < 0)
+		return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
+	/* Set up transaction */
+	/* Disable interrupts */
+	outb(inb(smbus_base + SMBHSTCTL) & ~SMBHSTCNT_INTREN,
+		smbus_base + SMBHSTCTL);
+	/* Set the device I'm talking too */
+	outb(((device & 0x7f) << 1) | 1, smbus_base + SMBXMITADD);
+	/* Set the command/address... */
+	outb(address & 0xff, smbus_base + SMBHSTCMD);
+	/* Set up for a byte data read */
+	outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | I801_BYTE_DATA,
+	     (smbus_base + SMBHSTCTL));
+	/* Clear any lingering errors, so the transaction will run */
+	outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
+
+	/* Clear the data byte... */
+	outb(0, smbus_base + SMBHSTDAT0);
+
+	/* Start the command */
+	outb((inb(smbus_base + SMBHSTCTL) | SMBHSTCNT_START),
+	     smbus_base + SMBHSTCTL);
+
+	/* poll for it to start */
+	if (smbus_wait_until_active(smbus_base) < 0)
+		return SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT;
+
+	/* Poll for transaction completion */
+	if (smbus_wait_until_done(smbus_base) < 0)
+		return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
+
+	status = inb(smbus_base + SMBHSTSTAT);
+
+	/* Ignore the "In Use" status... */
+	status &= ~(SMBHSTSTS_SMBALERT_STS | SMBHSTSTS_INUSE_STS);
+
+	/* Read results of transaction */
+	byte = inb(smbus_base + SMBHSTDAT0);
+	if (status != SMBHSTSTS_INTR)
+		return SMBUS_ERROR;
+	return byte;
+}
+
+int do_smbus_write_byte(unsigned int smbus_base, u8 device,
+			unsigned int address, unsigned int data)
+{
+	unsigned char status;
+
+	if (smbus_wait_until_ready(smbus_base) < 0)
+		return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
+
+	/* Set up transaction */
+	/* Disable interrupts */
+	outb(inb(smbus_base + SMBHSTCTL) & ~SMBHSTCNT_INTREN,
+		smbus_base + SMBHSTCTL);
+	/* Set the device I'm talking too */
+	outb(((device & 0x7f) << 1) & ~0x01, smbus_base + SMBXMITADD);
+	/* Set the command/address... */
+	outb(address & 0xff, smbus_base + SMBHSTCMD);
+	/* Set up for a byte data read */
+	outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | I801_BYTE_DATA,
+	     (smbus_base + SMBHSTCTL));
+	/* Clear any lingering errors, so the transaction will run */
+	outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
+
+	/* Clear the data byte... */
+	outb(data, smbus_base + SMBHSTDAT0);
+
+	/* Start the command */
+	outb((inb(smbus_base + SMBHSTCTL) | SMBHSTCNT_START),
+	     smbus_base + SMBHSTCTL);
+
+	/* poll for it to start */
+	if (smbus_wait_until_active(smbus_base) < 0)
+		return SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT;
+
+	/* Poll for transaction completion */
+	if (smbus_wait_until_done(smbus_base) < 0)
+		return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
+
+	status = inb(smbus_base + SMBHSTSTAT);
+
+	/* Ignore the "In Use" status... */
+	status &= ~(SMBHSTSTS_SMBALERT_STS | SMBHSTSTS_INUSE_STS);
+
+	/* Read results of transaction */
+	if (status != SMBHSTSTS_INTR)
+		return SMBUS_ERROR;
+
+	return 0;
+}
+
+int do_smbus_block_read(unsigned int smbus_base, u8 device, u8 cmd,
+			unsigned int bytes, u8 *buf)
+{
+	u8 status;
+	int bytes_read = 0;
+	unsigned int loops = SMBUS_TIMEOUT;
+	if (smbus_wait_until_ready(smbus_base) < 0)
+		return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
+
+	/* Set up transaction */
+	/* Disable interrupts */
+	outb(inb(smbus_base + SMBHSTCTL) & ~SMBHSTCNT_INTREN,
+		smbus_base + SMBHSTCTL);
+	/* Set the device I'm talking too */
+	outb(((device & 0x7f) << 1) | 1, smbus_base + SMBXMITADD);
+	/* Set the command/address... */
+	outb(cmd & 0xff, smbus_base + SMBHSTCMD);
+	/* Set up for a block data read */
+	outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | I801_BLOCK_DATA,
+	     (smbus_base + SMBHSTCTL));
+	/* Clear any lingering errors, so the transaction will run */
+	outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
+
+	/* Start the command */
+	outb((inb(smbus_base + SMBHSTCTL) | SMBHSTCNT_START),
+	     smbus_base + SMBHSTCTL);
+
+	/* poll for it to start */
+	if (smbus_wait_until_active(smbus_base) < 0)
+		return SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT;
+
+	/* Poll for transaction completion */
+	do {
+		loops--;
+		status = inb(smbus_base + SMBHSTSTAT);
+		if (status & (SMBHSTSTS_FAILED | /* FAILED */
+				SMBHSTSTS_BUS_ERR | /* BUS ERR */
+				SMBHSTSTS_DEV_ERR)) /* DEV ERR */
+			return SMBUS_ERROR;
+
+		if (status & SMBHSTSTS_BYTE_DONE) { /* Byte done */
+			*buf = inb(smbus_base + SMBBLKDAT);
+			buf++;
+			bytes_read++;
+			if (--bytes == 1) {
+				/* indicate that next byte is the last one */
+				outb(inb(smbus_base + SMBHSTCTL)
+					| SMBHSTCNT_LAST_BYTE,
+					smbus_base + SMBHSTCTL);
+			}
+			outb(status, smbus_base + SMBHSTSTAT);
+		}
+	} while ((status & SMBHSTSTS_HOST_BUSY) && loops);
+
+	return bytes_read;
+}
+
+int do_smbus_block_write(unsigned int smbus_base, u8 device, u8 cmd,
+			unsigned int bytes, const u8 *buf)
+{
+	u8 status;
+	unsigned int loops = SMBUS_TIMEOUT;
+
+	if (smbus_wait_until_ready(smbus_base) < 0)
+		return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
+
+	/* Set up transaction */
+	/* Disable interrupts */
+	outb(inb(smbus_base + SMBHSTCTL) & ~SMBHSTCNT_INTREN,
+		smbus_base + SMBHSTCTL);
+	/* Set the device I'm talking too */
+	outb(((device & 0x7f) << 1) & ~0x01, smbus_base + SMBXMITADD);
+	/* Set the command/address... */
+	outb(cmd & 0xff, smbus_base + SMBHSTCMD);
+	/* Set up for a block data write */
+	outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | I801_BLOCK_DATA,
+	     (smbus_base + SMBHSTCTL));
+	/* Clear any lingering errors, so the transaction will run */
+	outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
+
+	/* set number of bytes to transfer */
+	outb(bytes, smbus_base + SMBHSTDAT0);
+
+	outb(*buf++, smbus_base + SMBBLKDAT);
+	bytes--;
+
+	/* Start the command */
+	outb((inb(smbus_base + SMBHSTCTL) | SMBHSTCNT_START),
+	     smbus_base + SMBHSTCTL);
+
+	/* poll for it to start */
+	if (smbus_wait_until_active(smbus_base) < 0)
+		return SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT;
+
+	/* Poll for transaction completion */
+	do {
+		loops--;
+		status = inb(smbus_base + SMBHSTSTAT);
+		if (status & (SMBHSTSTS_FAILED | /* FAILED */
+				SMBHSTSTS_BUS_ERR | /* BUS ERR */
+				SMBHSTSTS_DEV_ERR)) /* DEV ERR */
+			return SMBUS_ERROR;
+
+		if (status & SMBHSTSTS_BYTE_DONE) {
+			outb(*buf++, smbus_base + SMBBLKDAT);
+			outb(status, smbus_base + SMBHSTSTAT);
+		}
+	} while ((status & SMBHSTSTS_HOST_BUSY) && loops);
+
+	return 0;
+}
+
+/* Only since ICH5 */
+int do_i2c_block_read(unsigned int smbus_base, u8 device,
+		unsigned int offset, u32 bytes, u8 *buf)
+{
+	u8 status;
+	int bytes_read = 0;
+	unsigned int loops = SMBUS_TIMEOUT;
+	if (smbus_wait_until_ready(smbus_base) < 0)
+		return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
+
+	/* Set upp transaction */
+	/* Disable interrupts */
+	outb(inb(smbus_base + SMBHSTCTL) & SMBHSTCNT_INTREN,
+		smbus_base + SMBHSTCTL);
+	/* Set the device I'm talking to */
+	outb((device & 0x7f) << 1, smbus_base + SMBXMITADD);
+
+	/* device offset */
+	outb(offset, smbus_base + SMBHSTDAT1);
+
+	/* Set up for a i2c block data read */
+	outb((inb(smbus_base + SMBHSTCTL) & 0xc3) | I801_I2C_BLOCK_DATA,
+		(smbus_base + SMBHSTCTL));
+
+	/* Clear any lingering errors, so the transaction will run */
+	outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
+	/* Start the command */
+	outb((inb(smbus_base + SMBHSTCTL) | SMBHSTCNT_START),
+	     smbus_base + SMBHSTCTL);
+
+	/* poll for it to start */
+	if (smbus_wait_until_active(smbus_base) < 0)
+		return SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT;
+
+	/* Poll for transaction completion */
+	do {
+		loops--;
+		status = inb(smbus_base + SMBHSTSTAT);
+		if (status & (SMBHSTSTS_FAILED | /* FAILED */
+				SMBHSTSTS_BUS_ERR | /* BUS ERR */
+				SMBHSTSTS_DEV_ERR)) /* DEV ERR */
+			return SMBUS_ERROR;
+
+		if (status & SMBHSTSTS_BYTE_DONE) {
+			*buf = inb(smbus_base + SMBBLKDAT);
+			buf++;
+			bytes_read++;
+			if (--bytes == 1) {
+				/* indicate that next byte is the last one */
+				outb(inb(smbus_base + SMBHSTCTL)
+					| SMBHSTCNT_LAST_BYTE,
+					smbus_base + SMBHSTCTL);
+			}
+			outb(status, smbus_base + SMBHSTSTAT);
+		}
+	} while ((status & SMBHSTSTS_HOST_BUSY) && loops);
+
+	return bytes_read;
+}
diff --git a/src/southbridge/intel/common/smbus.h b/src/southbridge/intel/common/smbus.h
new file mode 100644
index 0000000..f2e903c
--- /dev/null
+++ b/src/southbridge/intel/common/smbus.h
@@ -0,0 +1,46 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com>
+ * Copyright (C) 2009 coresystems GmbH
+ * Copyright (C) 2013 Vladimir Serbinenko
+ *
+ * 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.
+ */
+
+#ifndef INTEL_COMMON_SMBUS_H
+#define INTEL_COMMON_SMBUS_H
+
+/* SMBus register offsets. */
+#define SMBHSTSTAT		0x0
+#define SMBHSTCTL		0x2
+#define SMBHSTCMD		0x3
+#define SMBXMITADD		0x4
+#define SMBHSTDAT0		0x5
+#define SMBHSTDAT1		0x6
+#define SMBBLKDAT		0x7
+#define SMBTRNSADD		0x9
+#define SMBSLVDATA		0xa
+#define SMLINK_PIN_CTL		0xe
+#define SMBUS_PIN_CTL		0xf
+#define SMBSLVCMD		0x11
+
+int do_smbus_read_byte(unsigned int smbus_base, u8 device,
+		unsigned int address);
+int do_smbus_write_byte(unsigned int smbus_base, u8 device,
+			unsigned int address, unsigned int data);
+int do_smbus_block_read(unsigned int smbus_base, u8 device,
+			u8 cmd, unsigned int bytes, u8 *buf);
+int do_smbus_block_write(unsigned int smbus_base, u8 device,
+			u8 cmd, unsigned int bytes, const u8 *buf);
+/* Only since ICH5 */
+int do_i2c_block_read(unsigned int smbus_base, u8 device,
+		unsigned int offset, u32 bytes, u8 *buf);
+#endif
diff --git a/src/southbridge/intel/fsp_bd82x6x/Kconfig b/src/southbridge/intel/fsp_bd82x6x/Kconfig
index 516362c..cebd96d 100644
--- a/src/southbridge/intel/fsp_bd82x6x/Kconfig
+++ b/src/southbridge/intel/fsp_bd82x6x/Kconfig
@@ -31,6 +31,8 @@
 	select SPI_FLASH
 	select COMMON_FADT
 	select HAVE_INTEL_FIRMWARE
+	select SOUTHBRIDGE_INTEL_COMMON
+	select SOUTHBRIDGE_INTEL_COMMON_SMBUS
 
 config EHCI_BAR
 	hex
diff --git a/src/southbridge/intel/fsp_i89xx/Kconfig b/src/southbridge/intel/fsp_i89xx/Kconfig
index 9dfbbf7..67c2665 100644
--- a/src/southbridge/intel/fsp_i89xx/Kconfig
+++ b/src/southbridge/intel/fsp_i89xx/Kconfig
@@ -32,6 +32,8 @@
 	select COMMON_FADT
 	select HAVE_INTEL_FIRMWARE
 	select NO_EARLY_BOOTBLOCK_POSTCODES
+	select SOUTHBRIDGE_INTEL_COMMON
+	select SOUTHBRIDGE_INTEL_COMMON_SMBUS
 
 config EHCI_BAR
 	hex
diff --git a/src/southbridge/intel/fsp_i89xx/early_smbus.c b/src/southbridge/intel/fsp_i89xx/early_smbus.c
index 0d41d5e..1451179 100644
--- a/src/southbridge/intel/fsp_i89xx/early_smbus.c
+++ b/src/southbridge/intel/fsp_i89xx/early_smbus.c
@@ -19,8 +19,8 @@
 #include <console/console.h>
 #include <device/pci_ids.h>
 #include <device/pci_def.h>
+#include <southbridge/intel/common/smbus.h>
 #include "pch.h"
-#include "smbus.h"
 
 void enable_smbus(void)
 {
diff --git a/src/southbridge/intel/fsp_i89xx/pch.h b/src/southbridge/intel/fsp_i89xx/pch.h
index 9ae9467..4471788 100644
--- a/src/southbridge/intel/fsp_i89xx/pch.h
+++ b/src/southbridge/intel/fsp_i89xx/pch.h
@@ -174,22 +174,6 @@
 #define SMB_SMI_EN		(1 << 1)
 #define HST_EN			(1 << 0)
 
-/* SMBus I/O bits. */
-#define SMBHSTSTAT		0x0
-#define SMBHSTCTL		0x2
-#define SMBHSTCMD		0x3
-#define SMBXMITADD		0x4
-#define SMBHSTDAT0		0x5
-#define SMBHSTDAT1		0x6
-#define SMBBLKDAT		0x7
-#define SMBTRNSADD		0x9
-#define SMBSLVDATA		0xa
-#define SMLINK_PIN_CTL		0xe
-#define SMBUS_PIN_CTL		0xf
-
-#define SMBUS_TIMEOUT		(10 * 1000 * 100)
-
-
 /* Southbridge IO BARs */
 
 #define GPIOBASE		0x48
diff --git a/src/southbridge/intel/fsp_i89xx/smbus.h b/src/southbridge/intel/fsp_i89xx/smbus.h
deleted file mode 100644
index 92b05b7..0000000
--- a/src/southbridge/intel/fsp_i89xx/smbus.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * This file is part of the coreboot project.
- *
- * Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com>
- * Copyright (C) 2009 coresystems GmbH
- *
- * 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.
- */
-
-#include <device/smbus_def.h>
-#include "pch.h"
-#include <delay.h>
-
-static int smbus_wait_until_ready(u16 smbus_base)
-{
-	unsigned loops = SMBUS_TIMEOUT;
-	unsigned char byte;
-	do {
-		udelay(1);
-		if (--loops == 0)
-			break;
-		byte = inb(smbus_base + SMBHSTSTAT);
-	} while (byte & 1);
-	return loops ? 0 : -1;
-}
-
-static int smbus_wait_until_done(u16 smbus_base)
-{
-	unsigned loops = SMBUS_TIMEOUT;
-	unsigned char byte;
-	do {
-		udelay(1);
-		if (--loops == 0)
-			break;
-		byte = inb(smbus_base + SMBHSTSTAT);
-	} while ((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0);
-	return loops ? 0 : -1;
-}
-
-static int do_smbus_read_byte(unsigned smbus_base, unsigned device, unsigned address)
-{
-	unsigned char global_status_register;
-	unsigned char byte;
-
-	if (smbus_wait_until_ready(smbus_base) < 0) {
-		return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
-	}
-	/* Setup transaction */
-	/* Disable interrupts */
-	outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
-	/* Set the device I'm talking too */
-	outb(((device & 0x7f) << 1) | 1, smbus_base + SMBXMITADD);
-	/* Set the command/address... */
-	outb(address & 0xff, smbus_base + SMBHSTCMD);
-	/* Set up for a byte data read */
-	outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x2 << 2),
-	     (smbus_base + SMBHSTCTL));
-	/* Clear any lingering errors, so the transaction will run */
-	outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
-
-	/* Clear the data byte... */
-	outb(0, smbus_base + SMBHSTDAT0);
-
-	/* Start the command */
-	outb((inb(smbus_base + SMBHSTCTL) | 0x40),
-	     smbus_base + SMBHSTCTL);
-
-	/* Poll for transaction completion */
-	if (smbus_wait_until_done(smbus_base) < 0) {
-		return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
-	}
-
-	global_status_register = inb(smbus_base + SMBHSTSTAT);
-
-	/* Ignore the "In Use" status... */
-	global_status_register &= ~(3 << 5);
-
-	/* Read results of transaction */
-	byte = inb(smbus_base + SMBHSTDAT0);
-	if (global_status_register != (1 << 1)) {
-		return SMBUS_ERROR;
-	}
-	return byte;
-}
diff --git a/src/southbridge/intel/fsp_rangeley/Kconfig b/src/southbridge/intel/fsp_rangeley/Kconfig
index 092cf1d..4d2e89f 100644
--- a/src/southbridge/intel/fsp_rangeley/Kconfig
+++ b/src/southbridge/intel/fsp_rangeley/Kconfig
@@ -30,6 +30,8 @@
 	select PCIEXP_COMMON_CLOCK
 	select SPI_FLASH
 	select HAVE_INTEL_FIRMWARE
+	select SOUTHBRIDGE_INTEL_COMMON
+	select SOUTHBRIDGE_INTEL_COMMON_SMBUS
 
 config EHCI_BAR
 	hex
diff --git a/src/southbridge/intel/fsp_rangeley/early_smbus.c b/src/southbridge/intel/fsp_rangeley/early_smbus.c
index f27fa87..84b750e 100644
--- a/src/southbridge/intel/fsp_rangeley/early_smbus.c
+++ b/src/southbridge/intel/fsp_rangeley/early_smbus.c
@@ -18,8 +18,8 @@
 #include <console/console.h>
 #include <device/pci_ids.h>
 #include <device/pci_def.h>
+#include <southbridge/intel/common/smbus.h>
 #include "soc.h"
-#include "smbus.h"
 
 void enable_smbus(void)
 {
diff --git a/src/southbridge/intel/fsp_rangeley/smbus.c b/src/southbridge/intel/fsp_rangeley/smbus.c
index 9a4d867..9ea8126 100644
--- a/src/southbridge/intel/fsp_rangeley/smbus.c
+++ b/src/southbridge/intel/fsp_rangeley/smbus.c
@@ -22,8 +22,8 @@
 #include <device/pci_ids.h>
 #include <device/pci_ops.h>
 #include <arch/io.h>
+#include <southbridge/intel/common/smbus.h>
 #include "soc.h"
-#include "smbus.h"
 
 static int lsmbus_read_byte(device_t dev, u8 address)
 {
diff --git a/src/southbridge/intel/fsp_rangeley/smbus.h b/src/southbridge/intel/fsp_rangeley/smbus.h
deleted file mode 100644
index 39ba6dc..0000000
--- a/src/southbridge/intel/fsp_rangeley/smbus.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * This file is part of the coreboot project.
- *
- * Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com>
- * Copyright (C) 2009 coresystems GmbH
- *
- * 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.
- */
-
-#include <device/smbus_def.h>
-#include "soc.h"
-
-static void smbus_delay(void)
-{
-	inb(0x80);
-}
-
-static int smbus_wait_until_ready(u16 smbus_base)
-{
-	unsigned loops = SMBUS_TIMEOUT;
-	unsigned char byte;
-	do {
-		smbus_delay();
-		if (--loops == 0)
-			break;
-		byte = inb(smbus_base + SMBHSTSTAT);
-	} while (byte & 1);
-	return loops ? 0 : -1;
-}
-
-static int smbus_wait_until_done(u16 smbus_base)
-{
-	unsigned loops = SMBUS_TIMEOUT;
-	unsigned char byte;
-	do {
-		smbus_delay();
-		if (--loops == 0)
-			break;
-		byte = inb(smbus_base + SMBHSTSTAT);
-	} while ((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0);
-	return loops ? 0 : -1;
-}
-
-static int do_smbus_read_byte(unsigned smbus_base, unsigned device, unsigned address)
-{
-	unsigned char global_status_register;
-	unsigned char byte;
-
-	if (smbus_wait_until_ready(smbus_base) < 0) {
-		return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
-	}
-	/* Setup transaction */
-	/* Disable interrupts */
-	outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
-	/* Set the device I'm talking too */
-	outb(((device & 0x7f) << 1) | 1, smbus_base + SMBXMITADD);
-	/* Set the command/address... */
-	outb(address & 0xff, smbus_base + SMBHSTCMD);
-	/* Set up for a byte data read */
-	outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x2 << 2),
-	     (smbus_base + SMBHSTCTL));
-	/* Clear any lingering errors, so the transaction will run */
-	outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
-
-	/* Clear the data byte... */
-	outb(0, smbus_base + SMBHSTDAT0);
-
-	/* Start the command */
-	outb((inb(smbus_base + SMBHSTCTL) | 0x40),
-	     smbus_base + SMBHSTCTL);
-
-	/* Poll for transaction completion */
-	if (smbus_wait_until_done(smbus_base) < 0) {
-		return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
-	}
-
-	global_status_register = inb(smbus_base + SMBHSTSTAT);
-
-	/* Ignore the "In Use" status... */
-	global_status_register &= ~(3 << 5);
-
-	/* Read results of transaction */
-	byte = inb(smbus_base + SMBHSTDAT0);
-	if (global_status_register != (1 << 1)) {
-		return SMBUS_ERROR;
-	}
-	return byte;
-}
diff --git a/src/southbridge/intel/fsp_rangeley/soc.h b/src/southbridge/intel/fsp_rangeley/soc.h
index 4409f1e..764bf97 100644
--- a/src/southbridge/intel/fsp_rangeley/soc.h
+++ b/src/southbridge/intel/fsp_rangeley/soc.h
@@ -176,21 +176,6 @@
 #define SMB_SMI_EN		(1 << 1)
 #define HST_EN			(1 << 0)
 
-/* SMBus I/O bits. */
-#define SMBHSTSTAT		0x0
-#define SMBHSTCTL		0x2
-#define SMBHSTCMD		0x3
-#define SMBXMITADD		0x4
-#define SMBHSTDAT0		0x5
-#define SMBHSTDAT1		0x6
-#define SMBBLKDAT		0x7
-#define SMBTRNSADD		0x9
-#define SMBSLVDATA		0xa
-#define SMLINK_PIN_CTL		0xe
-#define SMBUS_PIN_CTL		0xf
-
-#define SMBUS_TIMEOUT		(10 * 1000 * 100)
-
 /* Root Complex Register Block */
 #define RCBA		0xf0
 #define  RCBA_ENABLE 0x01
diff --git a/src/southbridge/intel/i3100/Kconfig b/src/southbridge/intel/i3100/Kconfig
index 1dd0931..20990ba 100644
--- a/src/southbridge/intel/i3100/Kconfig
+++ b/src/southbridge/intel/i3100/Kconfig
@@ -2,6 +2,8 @@
 	bool
 	select IOAPIC
 	select HAVE_HARD_RESET
+	select SOUTHBRIDGE_INTEL_COMMON
+	select SOUTHBRIDGE_INTEL_COMMON_SMBUS
 
 if SOUTHBRIDGE_INTEL_I3100
 
diff --git a/src/southbridge/intel/i3100/early_smbus.c b/src/southbridge/intel/i3100/early_smbus.c
index 35c32a4..35fe614 100644
--- a/src/southbridge/intel/i3100/early_smbus.c
+++ b/src/southbridge/intel/i3100/early_smbus.c
@@ -14,7 +14,7 @@
  *
  */
 
-#include "smbus.h"
+#include <southbridge/intel/common/smbus.h>
 
 #define SMBUS_IO_BASE 0x0f00
 
diff --git a/src/southbridge/intel/i3100/smbus.c b/src/southbridge/intel/i3100/smbus.c
index 32cf709..850982a 100644
--- a/src/southbridge/intel/i3100/smbus.c
+++ b/src/southbridge/intel/i3100/smbus.c
@@ -21,8 +21,8 @@
 #include <device/pci_ops.h>
 #include <device/smbus.h>
 #include <arch/io.h>
+#include <southbridge/intel/common/smbus.h>
 #include "i3100.h"
-#include "smbus.h"
 
 static int lsmbus_read_byte(device_t dev, u8 address)
 {
diff --git a/src/southbridge/intel/i3100/smbus.h b/src/southbridge/intel/i3100/smbus.h
deleted file mode 100644
index 0b2f060..0000000
--- a/src/southbridge/intel/i3100/smbus.h
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * This file is part of the coreboot project.
- *
- * Copyright (C) 2008 Arastra, Inc.
- *
- * 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.
- */
-
-/* This code is based on src/southbridge/intel/esb6300/esb6300_smbus.h */
-
-#include <device/smbus_def.h>
-
-#define SMBHSTSTAT 0x0
-#define SMBHSTCTL  0x2
-#define SMBHSTCMD  0x3
-#define SMBXMITADD 0x4
-#define SMBHSTDAT0 0x5
-#define SMBHSTDAT1 0x6
-#define SMBBLKDAT  0x7
-#define SMBTRNSADD 0x9
-#define SMBSLVDATA 0xa
-#define SMLINK_PIN_CTL 0xe
-#define SMBUS_PIN_CTL  0xf
-#define SMBSLVCMD  0x11
-
-#define SMBUS_TIMEOUT (100*1000*10)
-
-static void smbus_delay(void)
-{
-	outb(0x80, 0x80);
-}
-
-static int smbus_wait_until_ready(u32 smbus_io_base)
-{
-	u32 loops = SMBUS_TIMEOUT;
-	u8 byte;
-	do {
-		smbus_delay();
-		if (--loops == 0)
-			break;
-		byte = inb(smbus_io_base + SMBHSTSTAT);
-	} while (byte & 1);
-	return loops ? 0 : -1;
-}
-
-static int smbus_wait_until_done(u32 smbus_io_base)
-{
-	u32 loops = SMBUS_TIMEOUT;
-	u8 byte;
-	do {
-		smbus_delay();
-		if (--loops == 0)
-			break;
-		byte = inb(smbus_io_base + SMBHSTSTAT);
-	} while ((byte & 1) || (byte & ~((1 << 6)|(1 << 0))) == 0);
-	return loops ? 0 : -1;
-}
-
-static int do_smbus_read_byte(u32 smbus_io_base, u16 device, u8 address)
-{
-	u8 global_status_register;
-	u8 byte;
-
-	if (smbus_wait_until_ready(smbus_io_base) < 0) {
-		return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
-	}
-	/* setup transaction */
-	/* disable interrupts */
-	outb(inb(smbus_io_base + SMBHSTCTL) & (~1), smbus_io_base + SMBHSTCTL);
-	/* set the device I'm talking too */
-	outb(((device & 0x7f) << 1) | 1, smbus_io_base + SMBXMITADD);
-	/* set the command/address... */
-	outb(address & 0xFF, smbus_io_base + SMBHSTCMD);
-	/* set up for a byte data read */
-	outb((inb(smbus_io_base + SMBHSTCTL) & 0xE3) | (0x2 << 2), smbus_io_base + SMBHSTCTL);
-	/* clear any lingering errors, so the transaction will run */
-	outb(inb(smbus_io_base + SMBHSTSTAT), smbus_io_base + SMBHSTSTAT);
-
-	/* clear the data byte...*/
-	outb(0, smbus_io_base + SMBHSTDAT0);
-
-	/* start the command */
-	outb((inb(smbus_io_base + SMBHSTCTL) | 0x40), smbus_io_base + SMBHSTCTL);
-
-	/* poll for transaction completion */
-	if (smbus_wait_until_done(smbus_io_base) < 0) {
-		return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
-	}
-
-	global_status_register = inb(smbus_io_base + SMBHSTSTAT);
-
-	/* Ignore the In Use Status... */
-	global_status_register &= ~(3 << 5);
-
-	/* read results of transaction */
-	byte = inb(smbus_io_base + SMBHSTDAT0);
-	if (global_status_register != (1 << 1)) {
-		return SMBUS_ERROR;
-	}
-	return byte;
-}
-
-static  int do_smbus_write_byte(unsigned smbus_base, unsigned device, unsigned address, unsigned data)
-{
-	unsigned char global_status_register;
-
-	if (smbus_wait_until_ready(smbus_base) < 0)
-		return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
-
-	/* Setup transaction */
-	/* Disable interrupts */
-	outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
-	/* Set the device I'm talking too */
-	outb(((device & 0x7f) << 1) & ~0x01, smbus_base + SMBXMITADD);
-	/* Set the command/address... */
-	outb(address & 0xff, smbus_base + SMBHSTCMD);
-	/* Set up for a byte data read */
-	outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x2 << 2),
-	     (smbus_base + SMBHSTCTL));
-	/* Clear any lingering errors, so the transaction will run */
-	outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
-
-	/* Clear the data byte... */
-	outb(data, smbus_base + SMBHSTDAT0);
-
-	/* Start the command */
-	outb((inb(smbus_base + SMBHSTCTL) | 0x40),
-	     smbus_base + SMBHSTCTL);
-
-	/* Poll for transaction completion */
-	if (smbus_wait_until_done(smbus_base) < 0)
-		return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
-
-	global_status_register = inb(smbus_base + SMBHSTSTAT);
-
-	/* Ignore the "In Use" status... */
-	global_status_register &= ~(3 << 5);
-
-	/* Read results of transaction */
-	if (global_status_register != (1 << 1))
-		return SMBUS_ERROR;
-
-	return 0;
-}
diff --git a/src/southbridge/intel/i82371eb/Kconfig b/src/southbridge/intel/i82371eb/Kconfig
index 5466b12..f22c6e9 100644
--- a/src/southbridge/intel/i82371eb/Kconfig
+++ b/src/southbridge/intel/i82371eb/Kconfig
@@ -1,4 +1,6 @@
 config SOUTHBRIDGE_INTEL_I82371EB
+	select SOUTHBRIDGE_INTEL_COMMON
+	select SOUTHBRIDGE_INTEL_COMMON_SMBUS
 	bool
 
 config BOOTBLOCK_SOUTHBRIDGE_INIT
diff --git a/src/southbridge/intel/i82371eb/early_smbus.c b/src/southbridge/intel/i82371eb/early_smbus.c
index af6b14b..89ed9c8 100644
--- a/src/southbridge/intel/i82371eb/early_smbus.c
+++ b/src/southbridge/intel/i82371eb/early_smbus.c
@@ -19,8 +19,8 @@
 #include <console/console.h>
 #include <device/pci_ids.h>
 #include <device/pci_def.h>
+#include <southbridge/intel/common/smbus.h>
 #include "i82371eb.h"
-#include "smbus.h"
 
 void enable_smbus(void)
 {
@@ -46,7 +46,7 @@
 	pci_write_config16(dev, PCI_COMMAND, reg16);
 
 	/* Clear any lingering errors, so the transaction will run. */
-	outb(inb(SMBUS_IO_BASE + SMBHST_STATUS), SMBUS_IO_BASE + SMBHST_STATUS);
+	outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
 }
 
 int smbus_read_byte(u8 device, u8 address)
diff --git a/src/southbridge/intel/i82371eb/smbus.c b/src/southbridge/intel/i82371eb/smbus.c
index 9231402..3477c52 100644
--- a/src/southbridge/intel/i82371eb/smbus.c
+++ b/src/southbridge/intel/i82371eb/smbus.c
@@ -24,8 +24,8 @@
 #include <device/pci.h>
 #include <device/pci_ids.h>
 #include <device/smbus.h>
+#include <southbridge/intel/common/smbus.h>
 #include "i82371eb.h"
-#include "smbus.h"
 
 static void pwrmgt_enable(struct device *dev)
 {
diff --git a/src/southbridge/intel/i82371eb/smbus.h b/src/southbridge/intel/i82371eb/smbus.h
deleted file mode 100644
index de34504..0000000
--- a/src/southbridge/intel/i82371eb/smbus.h
+++ /dev/null
@@ -1,112 +0,0 @@
-#include <device/smbus_def.h>
-#include "i82371eb.h"
-
-#define SMBHST_STATUS 	0x0
-#define SMBHST_CTL    	0x2
-#define SMBHST_CMD  	0x3
-#define SMBHST_ADDR 	0x4
-#define SMBHST_DAT  	0x5
-
-#define SMBUS_TIMEOUT (100*1000*10)
-#define SMBUS_STATUS_MASK 0x1e
-#define SMBUS_ERROR_FLAG (1<<2)
-
-int do_smbus_read_byte(unsigned smbus_io_base, unsigned device, unsigned address);
-
-static inline void smbus_delay(void)
-{
-	outb(0x80, 0x80);
-	outb(0x80, 0x80);
-	outb(0x80, 0x80);
-	outb(0x80, 0x80);
-	outb(0x80, 0x80);
-	outb(0x80, 0x80);
-}
-
-static int smbus_wait_until_ready(unsigned smbus_io_base)
-{
-	unsigned long loops;
-	loops = SMBUS_TIMEOUT;
-	do {
-		unsigned char val;
-		smbus_delay();
-		val = inb(smbus_io_base + SMBHST_STATUS);
-		if ((val & 0x1) == 0) {
-			break;
-		}
-#if 0
-		if (loops == (SMBUS_TIMEOUT / 2)) {
-			outw(inw(smbus_io_base + SMBHST_STATUS),
-				smbus_io_base + SMBHST_STATUS);
-		}
-#endif
-	} while (--loops);
-	return loops?0:SMBUS_WAIT_UNTIL_READY_TIMEOUT;
-}
-
-static int smbus_wait_until_done(unsigned smbus_io_base)
-{
-	unsigned long loops;
-	loops = SMBUS_TIMEOUT;
-	do {
-		unsigned short val;
-		smbus_delay();
-
-		val = inb(smbus_io_base + SMBHST_STATUS);
-		// Make sure the command is done
-		if ((val & 0x1) != 0) {
-			continue;
-		}
-		// Don't break out until one of the interrupt
-		// flags is set.
-		if (val & 0xfe) {
-			break;
-		}
-	} while (--loops);
-	return loops?0:SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
-}
-
-int do_smbus_read_byte(unsigned smbus_io_base, unsigned device, unsigned address)
-{
-	unsigned status_register;
-	unsigned byte;
-
-	if (smbus_wait_until_ready(smbus_io_base) < 0) {
-		return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
-	}
-
-	/* setup transaction */
-
-	/* clear any lingering errors, so the transaction will run */
-	outb(0x1e, smbus_io_base + SMBHST_STATUS);
-
-	/* set the device I'm talking too */
-	outb(((device & 0x7f) << 1) | 1, smbus_io_base + SMBHST_ADDR);
-
-	/* set the command/address... */
-	outb(address & 0xff, smbus_io_base + SMBHST_CMD);
-
-	/* clear the data word...*/
-	outb(0, smbus_io_base + SMBHST_DAT);
-
-	/* start a byte read with interrupts disabled */
-	outb( (0x02 << 2)|(1<<6), smbus_io_base + SMBHST_CTL);
-
-	/* poll for transaction completion */
-	if (smbus_wait_until_done(smbus_io_base) < 0) {
-		return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
-	}
-
-	status_register = inw(smbus_io_base + SMBHST_STATUS);
-
-	/* read results of transaction */
-	byte = inw(smbus_io_base + SMBHST_DAT) & 0xff;
-
-	if (status_register & 0x04) {
-#if 0
- 		printk(BIOS_DEBUG, "Read fail %04x\n", status_register);
-#endif
-		return SMBUS_ERROR;
-	}
-	return byte;
-}
diff --git a/src/southbridge/intel/i82801ax/Kconfig b/src/southbridge/intel/i82801ax/Kconfig
index 740c69d..cade3f5 100644
--- a/src/southbridge/intel/i82801ax/Kconfig
+++ b/src/southbridge/intel/i82801ax/Kconfig
@@ -18,3 +18,5 @@
 	select IOAPIC
 	select HAVE_HARD_RESET
 	select USE_WATCHDOG_ON_BOOT
+	select SOUTHBRIDGE_INTEL_COMMON
+	select SOUTHBRIDGE_INTEL_COMMON_SMBUS
diff --git a/src/southbridge/intel/i82801ax/early_smbus.c b/src/southbridge/intel/i82801ax/early_smbus.c
index 2a224bf..836721b 100644
--- a/src/southbridge/intel/i82801ax/early_smbus.c
+++ b/src/southbridge/intel/i82801ax/early_smbus.c
@@ -20,8 +20,8 @@
 #include <console/console.h>
 #include <device/pci_ids.h>
 #include <device/pci_def.h>
+#include <southbridge/intel/common/smbus.h>
 #include "i82801ax.h"
-#include "smbus.h"
 
 void enable_smbus(void)
 {
diff --git a/src/southbridge/intel/i82801ax/i82801ax.h b/src/southbridge/intel/i82801ax/i82801ax.h
index c6e505d..879c25a 100644
--- a/src/southbridge/intel/i82801ax/i82801ax.h
+++ b/src/southbridge/intel/i82801ax/i82801ax.h
@@ -90,15 +90,4 @@
 #define SMB_SMI_EN		(1 << 1)
 #define HST_EN			(1 << 0)
 
-/* SMBus I/O registers. */
-#define SMBHSTSTAT		0x0
-#define SMBHSTCTL		0x2
-#define SMBHSTCMD		0x3
-#define SMBXMITADD		0x4
-#define SMBHSTDAT0		0x5
-#define SMBHSTDAT1		0x6
-#define SMBBLKDAT		0x7
-
-#define SMBUS_TIMEOUT		(10 * 1000 * 100)
-
 #endif
diff --git a/src/southbridge/intel/i82801ax/smbus.c b/src/southbridge/intel/i82801ax/smbus.c
index 54fa34f..1e71a98 100644
--- a/src/southbridge/intel/i82801ax/smbus.c
+++ b/src/southbridge/intel/i82801ax/smbus.c
@@ -19,8 +19,8 @@
 #include <device/pci.h>
 #include <device/pci_ids.h>
 #include <arch/io.h>
+#include <southbridge/intel/common/smbus.h>
 #include "i82801ax.h"
-#include "smbus.h"
 
 static int lsmbus_read_byte(device_t dev, u8 address)
 {
diff --git a/src/southbridge/intel/i82801ax/smbus.h b/src/southbridge/intel/i82801ax/smbus.h
deleted file mode 100644
index 0ca7d8e..0000000
--- a/src/southbridge/intel/i82801ax/smbus.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * This file is part of the coreboot project.
- *
- * Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <device/smbus_def.h>
-#include "i82801ax.h"
-
-int do_smbus_read_byte(u16 smbus_io_base, u8 device, u8 address);
-
-static void smbus_delay(void)
-{
-	inb(0x80);
-}
-
-static int smbus_wait_until_ready(u16 smbus_io_base)
-{
-	unsigned loops = SMBUS_TIMEOUT;
-	unsigned char byte;
-	do {
-		smbus_delay();
-		if (--loops == 0)
-			break;
-		byte = inb(smbus_io_base + SMBHSTSTAT);
-	} while (byte & 1);
-	return loops ? 0 : -1;
-}
-
-static int smbus_wait_until_done(u16 smbus_io_base)
-{
-	unsigned loops = SMBUS_TIMEOUT;
-	unsigned char byte;
-	do {
-		smbus_delay();
-		if (--loops == 0)
-			break;
-		byte = inb(smbus_io_base + SMBHSTSTAT);
-	} while ((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0);
-	return loops ? 0 : -1;
-}
-
-int do_smbus_read_byte(u16 smbus_io_base, u8 device, u8 address)
-{
-	unsigned char global_status_register;
-	unsigned char byte;
-
-	if (smbus_wait_until_ready(smbus_io_base) < 0) {
-		return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
-	}
-	/* Setup transaction */
-	/* Disable interrupts */
-	outb(inb(smbus_io_base + SMBHSTCTL) & (~1), smbus_io_base + SMBHSTCTL);
-	/* Set the device I'm talking too */
-	outb(((device & 0x7f) << 1) | 1, smbus_io_base + SMBXMITADD);
-	/* Set the command/address... */
-	outb(address & 0xff, smbus_io_base + SMBHSTCMD);
-	/* Set up for a byte data read */
-	outb((inb(smbus_io_base + SMBHSTCTL) & 0xe3) | (0x2 << 2),
-	     (smbus_io_base + SMBHSTCTL));
-	/* Clear any lingering errors, so the transaction will run */
-	outb(inb(smbus_io_base + SMBHSTSTAT), smbus_io_base + SMBHSTSTAT);
-
-	/* Clear the data byte... */
-	outb(0, smbus_io_base + SMBHSTDAT0);
-
-	/* Start the command */
-	outb((inb(smbus_io_base + SMBHSTCTL) | 0x40),
-	     smbus_io_base + SMBHSTCTL);
-
-	/* Poll for transaction completion */
-	if (smbus_wait_until_done(smbus_io_base) < 0) {
-		return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
-	}
-
-	global_status_register = inb(smbus_io_base + SMBHSTSTAT);
-
-	/* Ignore the "In Use" status... */
-	global_status_register &= ~(3 << 5);
-
-	/* Read results of transaction */
-	byte = inb(smbus_io_base + SMBHSTDAT0);
-	if (global_status_register != (1 << 1)) {
-		return SMBUS_ERROR;
-	}
-	return byte;
-}
diff --git a/src/southbridge/intel/i82801bx/Kconfig b/src/southbridge/intel/i82801bx/Kconfig
index f142300..9d25cbf 100644
--- a/src/southbridge/intel/i82801bx/Kconfig
+++ b/src/southbridge/intel/i82801bx/Kconfig
@@ -18,3 +18,5 @@
 	select IOAPIC
 	select HAVE_HARD_RESET
 	select USE_WATCHDOG_ON_BOOT
+	select SOUTHBRIDGE_INTEL_COMMON
+	select SOUTHBRIDGE_INTEL_COMMON_SMBUS
diff --git a/src/southbridge/intel/i82801bx/early_smbus.c b/src/southbridge/intel/i82801bx/early_smbus.c
index c038e0a..103e1a3 100644
--- a/src/southbridge/intel/i82801bx/early_smbus.c
+++ b/src/southbridge/intel/i82801bx/early_smbus.c
@@ -20,8 +20,8 @@
 #include <console/console.h>
 #include <device/pci_ids.h>
 #include <device/pci_def.h>
+#include <southbridge/intel/common/smbus.h>
 #include "i82801bx.h"
-#include "smbus.h"
 
 void enable_smbus(void)
 {
diff --git a/src/southbridge/intel/i82801bx/i82801bx.h b/src/southbridge/intel/i82801bx/i82801bx.h
index 27888b8..3ecfe72 100644
--- a/src/southbridge/intel/i82801bx/i82801bx.h
+++ b/src/southbridge/intel/i82801bx/i82801bx.h
@@ -99,19 +99,4 @@
 #define SMB_SMI_EN		(1 << 1)
 #define HST_EN			(1 << 0)
 
-/* SMBus I/O registers. */
-#define SMBHSTSTAT		0x0
-#define SMBHSTCTL		0x2
-#define SMBHSTCMD		0x3
-#define SMBXMITADD		0x4
-#define SMBHSTDAT0		0x5
-#define SMBHSTDAT1		0x6
-#define SMBBLKDAT		0x7
-#define SMBTRNSADD		0x9
-#define SMBSLVDATA		0xa
-#define SMLINK_PIN_CTL		0xe
-#define SMBUS_PIN_CTL		0xf
-
-#define SMBUS_TIMEOUT		(10 * 1000 * 100)
-
 #endif				/* SOUTHBRIDGE_INTEL_I82801BX_I82801BX_H */
diff --git a/src/southbridge/intel/i82801bx/smbus.c b/src/southbridge/intel/i82801bx/smbus.c
index 6cc05ca..01e8c37 100644
--- a/src/southbridge/intel/i82801bx/smbus.c
+++ b/src/southbridge/intel/i82801bx/smbus.c
@@ -19,8 +19,8 @@
 #include <device/pci.h>
 #include <device/pci_ids.h>
 #include <arch/io.h>
+#include <southbridge/intel/common/smbus.h>
 #include "i82801bx.h"
-#include "smbus.h"
 
 static int lsmbus_read_byte(device_t dev, u8 address)
 {
diff --git a/src/southbridge/intel/i82801bx/smbus.h b/src/southbridge/intel/i82801bx/smbus.h
deleted file mode 100644
index ffb983e..0000000
--- a/src/southbridge/intel/i82801bx/smbus.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * This file is part of the coreboot project.
- *
- * Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <device/smbus_def.h>
-
-static void smbus_delay(void)
-{
-	inb(0x80);
-}
-
-static int smbus_wait_until_ready(u16 smbus_io_base)
-{
-	unsigned loops = SMBUS_TIMEOUT;
-	unsigned char byte;
-	do {
-		smbus_delay();
-		if (--loops == 0)
-			break;
-		byte = inb(smbus_io_base + SMBHSTSTAT);
-	} while (byte & 1);
-	return loops ? 0 : -1;
-}
-
-static int smbus_wait_until_done(u16 smbus_io_base)
-{
-	unsigned loops = SMBUS_TIMEOUT;
-	unsigned char byte;
-	do {
-		smbus_delay();
-		if (--loops == 0)
-			break;
-		byte = inb(smbus_io_base + SMBHSTSTAT);
-	} while ((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0);
-	return loops ? 0 : -1;
-}
-
-static int do_smbus_read_byte(u16 smbus_io_base, u8 device, u8 address)
-{
-	unsigned char global_status_register;
-	unsigned char byte;
-
-	if (smbus_wait_until_ready(smbus_io_base) < 0) {
-		return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
-	}
-	/* Setup transaction */
-	/* Disable interrupts */
-	outb(inb(smbus_io_base + SMBHSTCTL) & (~1), SMBUS_IO_BASE + SMBHSTCTL);
-	/* Set the device I'm talking too */
-	outb(((device & 0x7f) << 1) | 1, smbus_io_base + SMBXMITADD);
-	/* Set the command/address... */
-	outb(address & 0xff, smbus_io_base + SMBHSTCMD);
-	/* Set up for a byte data read */
-	outb((inb(smbus_io_base + SMBHSTCTL) & 0xe3) | (0x2 << 2),
-	     (smbus_io_base + SMBHSTCTL));
-	/* Clear any lingering errors, so the transaction will run */
-	outb(inb(smbus_io_base + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
-
-	/* Clear the data byte... */
-	outb(0, smbus_io_base + SMBHSTDAT0);
-
-	/* Start the command */
-	outb((inb(smbus_io_base + SMBHSTCTL) | 0x40),
-	     smbus_io_base + SMBHSTCTL);
-
-	/* Poll for transaction completion */
-	if (smbus_wait_until_done(smbus_io_base) < 0) {
-		return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
-	}
-
-	global_status_register = inb(smbus_io_base + SMBHSTSTAT);
-
-	/* Ignore the "In Use" status... */
-	global_status_register &= ~(3 << 5);
-
-	/* Read results of transaction */
-	byte = inb(smbus_io_base + SMBHSTDAT0);
-	if (global_status_register != (1 << 1)) {
-		return SMBUS_ERROR;
-	}
-	return byte;
-}
diff --git a/src/southbridge/intel/i82801dx/Kconfig b/src/southbridge/intel/i82801dx/Kconfig
index 82db1c3..35e597a 100644
--- a/src/southbridge/intel/i82801dx/Kconfig
+++ b/src/southbridge/intel/i82801dx/Kconfig
@@ -22,6 +22,8 @@
 	select HAVE_HARD_RESET
 	select HAVE_SMI_HANDLER
 	select HAVE_USBDEBUG
+	select SOUTHBRIDGE_INTEL_COMMON
+	select SOUTHBRIDGE_INTEL_COMMON_SMBUS
 
 if SOUTHBRIDGE_INTEL_I82801DX
 
diff --git a/src/southbridge/intel/i82801dx/early_smbus.c b/src/southbridge/intel/i82801dx/early_smbus.c
index 5bf87d8..fabb58b 100644
--- a/src/southbridge/intel/i82801dx/early_smbus.c
+++ b/src/southbridge/intel/i82801dx/early_smbus.c
@@ -17,6 +17,7 @@
 #include <arch/io.h>
 #include <device/pci_def.h>
 #include <console/console.h>
+#include <southbridge/intel/common/smbus.h>
 
 #include "i82801dx.h"
 
@@ -37,143 +38,7 @@
 	outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
 }
 
-static inline void smbus_delay(void)
+int smbus_read_byte(unsigned int device, unsigned int address)
 {
-	outb(0x80, 0x80);
+	return do_smbus_read_byte(SMBUS_IO_BASE, device, address);
 }
-
-static int smbus_wait_until_active(void)
-{
-	unsigned long loops;
-	loops = SMBUS_TIMEOUT;
-	do {
-		unsigned char val;
-		smbus_delay();
-		val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
-		if ((val & 1)) {
-			break;
-		}
-	} while (--loops);
-	return loops ? 0 : -4;
-}
-
-static int smbus_wait_until_ready(void)
-{
-	unsigned long loops;
-	loops = SMBUS_TIMEOUT;
-	do {
-		unsigned char val;
-		smbus_delay();
-		val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
-		if ((val & 1) == 0) {
-			break;
-		}
-		if (loops == (SMBUS_TIMEOUT / 2)) {
-			outb(inb(SMBUS_IO_BASE + SMBHSTSTAT),
-			     SMBUS_IO_BASE + SMBHSTSTAT);
-		}
-	} while (--loops);
-	return loops ? 0 : -2;
-}
-
-static int smbus_wait_until_done(void)
-{
-	unsigned long loops;
-	loops = SMBUS_TIMEOUT;
-	do {
-		unsigned char val;
-		smbus_delay();
-
-		val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
-		if ((val & 1) == 0) {
-			break;
-		}
-		if ((val & ~((1 << 6) | (1 << 0))) != 0) {
-			break;
-		}
-	} while (--loops);
-	return loops ? 0 : -3;
-}
-
-int smbus_read_byte(unsigned device, unsigned address)
-{
-	unsigned char global_status_register;
-	unsigned char byte;
-
-	/* printk(BIOS_ERR, "smbus_read_byte\n"); */
-	if (smbus_wait_until_ready() < 0) {
-		printk(BIOS_ERR, "SMBUS not ready (-2)\n");
-		return -2;
-	}
-
-	/* setup transaction */
-	/* disable interrupts */
-	outb(inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xfe, SMBUS_IO_BASE + SMBHSTCTL);
-	/* set the device I'm talking too */
-	outb(((device & 0x7f) << 1) | 1, SMBUS_IO_BASE + SMBXMITADD);
-	/* set the command/address... */
-	outb(address & 0xFF, SMBUS_IO_BASE + SMBHSTCMD);
-	/* set up for a byte data read */
-	outb((inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xe3) | (0x2 << 2),
-	     SMBUS_IO_BASE + SMBHSTCTL);
-
-	/* clear any lingering errors, so the transaction will run */
-	outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
-
-	/* clear the data byte... */
-	outb(0, SMBUS_IO_BASE + SMBHSTDAT0);
-
-	/* start a byte read, with interrupts disabled */
-	outb((inb(SMBUS_IO_BASE + SMBHSTCTL) | 0x40),
-	     SMBUS_IO_BASE + SMBHSTCTL);
-	/* poll for it to start */
-	if (smbus_wait_until_active() < 0) {
-		printk(BIOS_ERR, "SMBUS not active (-4)\n");
-		return -4;
-	}
-
-	/* poll for transaction completion */
-	if (smbus_wait_until_done() < 0) {
-		printk(BIOS_ERR, "SMBUS not completed (-3)\n");
-		return -3;
-	}
-
-	global_status_register = inb(SMBUS_IO_BASE + SMBHSTSTAT) & ~(1 << 6);	/* Ignore the In Use Status... */
-
-	/* read results of transaction */
-	byte = inb(SMBUS_IO_BASE + SMBHSTDAT0);
-
-	if (global_status_register != 2) {
-		//printk(BIOS_SPEW, "%s: no device (%02x, %02x)\n", __func__, device, address);
-		return -1;
-	}
-	//printk(BIOS_DEBUG, "%s: %02x@%02x = %02x\n", __func__, device, address, byte);
-	return byte;
-}
-
-#if 0
-static void smbus_write_byte(unsigned device, unsigned address,
-			     unsigned char val)
-{
-	if (smbus_wait_until_ready() < 0) {
-		return;
-	}
-
-	/* by LYH */
-	outb(0x37, SMBUS_IO_BASE + SMBHSTSTAT);
-	/* set the device I'm talking too */
-	outw(((device & 0x7f) << 1) | 0, SMBUS_IO_BASE + SMBHSTADDR);
-
-	/* data to send */
-	outb(val, SMBUS_IO_BASE + SMBHSTDAT);
-
-	outb(address & 0xFF, SMBUS_IO_BASE + SMBHSTCMD);
-
-	/* start the command */
-	outb(0xa, SMBUS_IO_BASE + SMBHSTCTL);
-
-	/* poll for transaction completion */
-	smbus_wait_until_done();
-	return;
-}
-#endif
diff --git a/src/southbridge/intel/i82801dx/i82801dx.h b/src/southbridge/intel/i82801dx/i82801dx.h
index 3ab0fda..14ca28f 100644
--- a/src/southbridge/intel/i82801dx/i82801dx.h
+++ b/src/southbridge/intel/i82801dx/i82801dx.h
@@ -116,23 +116,6 @@
 
 #define SMBUS_IO_BASE 0x1000
 
-#define SMBHSTSTAT 0x0
-#define SMBHSTCTL  0x2
-#define SMBHSTCMD  0x3
-#define SMBXMITADD 0x4
-#define SMBHSTDAT0 0x5
-#define SMBHSTDAT1 0x6
-#define SMBBLKDAT  0x7
-#define SMBTRNSADD 0x9
-#define SMBSLVDATA 0xa
-#define SMLINK_PIN_CTL 0xe
-#define SMBUS_PIN_CTL  0xf
-
-/* Between 1-10 seconds, We should never timeout normally
- * Longer than this is just painful when a timeout condition occurs.
- */
-#define SMBUS_TIMEOUT (100*1000)
-
 #define PM1_STS		0x00
 #define   WAK_STS	(1 << 15)
 #define   PCIEXPWAK_STS	(1 << 14)
diff --git a/src/southbridge/intel/i82801dx/smbus.c b/src/southbridge/intel/i82801dx/smbus.c
deleted file mode 100644
index 441b45a..0000000
--- a/src/southbridge/intel/i82801dx/smbus.c
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * This file is part of the coreboot project.
- *
- * Copyright (C) 2004 Ronald G. Minnich
- *
- * 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.
- */
-
-#include "i82801dx.h"
-#include <smbus.h>
-#include <pci.h>
-#include <arch/io.h>
-
-#define PM_BUS 0
-#define PM_DEVFN PCI_DEVFN(0x1f,3)
-
-void smbus_enable(void)
-{
-	unsigned char byte;
-	/* iobase addr */
-	pcibios_write_config_dword(PM_BUS, PM_DEVFN, 0x20, SMBUS_IO_BASE | 1);
-	/* smbus enable */
-	pcibios_write_config_byte(PM_BUS, PM_DEVFN, 0x40, 1);
-	/* iospace enable */
-	pcibios_write_config_word(PM_BUS, PM_DEVFN, 0x4, 1);
-
-	/* Disable interrupt generation */
-	outb(0, SMBUS_IO_BASE + SMBHSTCTL);
-
-}
-
-void smbus_setup(void)
-{
-	outb(0, SMBUS_IO_BASE + SMBHSTSTAT);
-}
-
-static void smbus_wait_until_ready(void)
-{
-	while ((inb(SMBUS_IO_BASE + SMBHSTSTAT) & 1) == 1) {
-		/* nop */
-	}
-}
-
-static void smbus_wait_until_done(void)
-{
-	unsigned char byte;
-	do {
-		byte = inb(SMBUS_IO_BASE + SMBHSTSTAT);
-	}
-	while ((byte & 1) == 1);
-	while ((byte & ~1) == 0) {
-		byte = inb(SMBUS_IO_BASE + SMBHSTSTAT);
-	}
-}
-
-int smbus_read_byte(unsigned device, unsigned address, unsigned char *result)
-{
-	unsigned char host_status_register;
-	unsigned char byte;
-
-	smbus_wait_until_ready();
-
-	/* setup transaction */
-	/* disable interrupts */
-	outb(inb(SMBUS_IO_BASE + SMBHSTCTL) & (~1), SMBUS_IO_BASE + SMBHSTCTL);
-	/* set the device I'm talking too */
-	outb(((device & 0x7f) << 1) | 1, SMBUS_IO_BASE + SMBHSTADD);
-	/* set the command/address... */
-	outb(address & 0xFF, SMBUS_IO_BASE + SMBHSTCMD);
-	/* set up for a byte data read */
-	outb((inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xE3) | (0x2 << 2),
-	     SMBUS_IO_BASE + SMBHSTCTL);
-
-	/* clear any lingering errors, so the transaction will run */
-	outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
-
-	/* clear the data byte... */
-	outb(0, SMBUS_IO_BASE + SMBHSTDAT0);
-
-	/* start the command */
-	outb((inb(SMBUS_IO_BASE + SMBHSTCTL) | 0x40),
-	     SMBUS_IO_BASE + SMBHSTCTL);
-
-	/* poll for transaction completion */
-	smbus_wait_until_done();
-
-	host_status_register = inb(SMBUS_IO_BASE + SMBHSTSTAT);
-
-	/* read results of transaction */
-	byte = inb(SMBUS_IO_BASE + SMBHSTDAT0);
-
-	*result = byte;
-	return host_status_register != 0x02;
-}
diff --git a/src/southbridge/intel/i82801gx/Kconfig b/src/southbridge/intel/i82801gx/Kconfig
index b2265c4..68c2362 100644
--- a/src/southbridge/intel/i82801gx/Kconfig
+++ b/src/southbridge/intel/i82801gx/Kconfig
@@ -24,6 +24,7 @@
 	select HAVE_SMI_HANDLER
 	select COMMON_FADT
 	select SOUTHBRIDGE_INTEL_COMMON_GPIO
+	select SOUTHBRIDGE_INTEL_COMMON_SMBUS
 
 if SOUTHBRIDGE_INTEL_I82801GX
 
diff --git a/src/southbridge/intel/i82801gx/early_smbus.c b/src/southbridge/intel/i82801gx/early_smbus.c
index b8852e9..5d204e9 100644
--- a/src/southbridge/intel/i82801gx/early_smbus.c
+++ b/src/southbridge/intel/i82801gx/early_smbus.c
@@ -18,8 +18,8 @@
 #include <console/console.h>
 #include <device/pci_ids.h>
 #include <device/pci_def.h>
+#include <southbridge/intel/common/smbus.h>
 #include "i82801gx.h"
-#include "smbus.h"
 
 void enable_smbus(void)
 {
@@ -57,52 +57,5 @@
 
 int i2c_block_read(unsigned int device, unsigned int offset, u32 bytes, u8 *buf)
 {
-	u8 status;
-	int bytes_read = 0;
-	if (smbus_wait_until_ready(SMBUS_IO_BASE) < 0)
-		return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
-
-	/* Setup transaction */
-	/* Disable interrupts */
-	outb(inb(SMBUS_IO_BASE + SMBHSTCTL) & (~1), SMBUS_IO_BASE + SMBHSTCTL);
-	/* Set the device I'm talking to */
-	outb((device & 0x7f) << 1, SMBUS_IO_BASE + SMBXMITADD);
-
-	/* SPD offset */
-	outb(offset, SMBUS_IO_BASE + SMBHSTDAT1);
-
-	/* Set up for a i2c block data read */
-	outb((inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xc3) | (0x6 << 2),
-		(SMBUS_IO_BASE + SMBHSTCTL));
-
-	/* Clear any lingering errors, so the transaction will run */
-	outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
-	/* Start the command */
-	outb((inb(SMBUS_IO_BASE + SMBHSTCTL) | 0x40),
-	     SMBUS_IO_BASE + SMBHSTCTL);
-
-	while (!(inb(SMBUS_IO_BASE + SMBHSTSTAT) & 1))
-		;
-	/* Poll for transaction completion */
-	do {
-		status = inb(SMBUS_IO_BASE + SMBHSTSTAT);
-		if (status & ((1 << 4) | /* FAILED */
-			      (1 << 3) | /* BUS ERR */
-			      (1 << 2))) /* DEV ERR */
-			return SMBUS_ERROR;
-
-		if (status & 0x80) { /* Byte done */
-			*buf = inb(SMBUS_IO_BASE + SMBBLKDAT);
-			buf++;
-			bytes_read++;
-			if (--bytes == 1) {
-				/* indicate that next byte is the last one */
-				outb(inb(SMBUS_IO_BASE + SMBHSTCTL) | 0x20,
-					 SMBUS_IO_BASE + SMBHSTCTL);
-			}
-			outb(status, SMBUS_IO_BASE + SMBHSTSTAT);
-		}
-	} while (status & 0x01);
-
-	return bytes_read;
+	return do_i2c_block_read(SMBUS_IO_BASE, device, offset, bytes, buf);
 }
diff --git a/src/southbridge/intel/i82801gx/i82801gx.h b/src/southbridge/intel/i82801gx/i82801gx.h
index 0dc4c0b..d1c861d 100644
--- a/src/southbridge/intel/i82801gx/i82801gx.h
+++ b/src/southbridge/intel/i82801gx/i82801gx.h
@@ -177,22 +177,6 @@
 #define SMB_SMI_EN		(1 << 1)
 #define HST_EN			(1 << 0)
 
-/* SMBus I/O bits. */
-#define SMBHSTSTAT		0x0
-#define SMBHSTCTL		0x2
-#define SMBHSTCMD		0x3
-#define SMBXMITADD		0x4
-#define SMBHSTDAT0		0x5
-#define SMBHSTDAT1		0x6
-#define SMBBLKDAT		0x7
-#define SMBTRNSADD		0x9
-#define SMBSLVDATA		0xa
-#define SMLINK_PIN_CTL		0xe
-#define SMBUS_PIN_CTL		0xf
-
-#define SMBUS_TIMEOUT		(10 * 1000 * 100)
-
-
 /* Southbridge IO BARs */
 
 #define GPIOBASE		0x48
diff --git a/src/southbridge/intel/i82801gx/smbus.c b/src/southbridge/intel/i82801gx/smbus.c
index d028f73..fdf76a0 100644
--- a/src/southbridge/intel/i82801gx/smbus.c
+++ b/src/southbridge/intel/i82801gx/smbus.c
@@ -22,8 +22,8 @@
 #include <device/pci_ids.h>
 #include <device/pci_ops.h>
 #include <arch/io.h>
+#include <southbridge/intel/common/smbus.h>
 #include "i82801gx.h"
-#include "smbus.h"
 
 static int lsmbus_read_byte(device_t dev, u8 address)
 {
@@ -38,49 +38,6 @@
 	return do_smbus_read_byte(res->base, device, address);
 }
 
-static int do_smbus_write_byte(unsigned int smbus_base, unsigned int device,
-			unsigned int address, unsigned int data)
-{
-	unsigned char global_status_register;
-
-	if (smbus_wait_until_ready(smbus_base) < 0)
-		return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
-
-	/* Setup transaction */
-	/* Disable interrupts */
-	outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
-	/* Set the device I'm talking too */
-	outb(((device & 0x7f) << 1) & ~0x01, smbus_base + SMBXMITADD);
-	/* Set the command/address... */
-	outb(address & 0xff, smbus_base + SMBHSTCMD);
-	/* Set up for a byte data read */
-	outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x2 << 2),
-	     (smbus_base + SMBHSTCTL));
-	/* Clear any lingering errors, so the transaction will run */
-	outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
-
-	/* Clear the data byte... */
-	outb(data, smbus_base + SMBHSTDAT0);
-
-	/* Start the command */
-	outb((inb(smbus_base + SMBHSTCTL) | 0x40),
-	     smbus_base + SMBHSTCTL);
-
-	/* Poll for transaction completion */
-	if (smbus_wait_until_done(smbus_base) < 0)
-		return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
-
-	global_status_register = inb(smbus_base + SMBHSTSTAT);
-
-	/* Ignore the "In Use" status... */
-	global_status_register &= ~(3 << 5);
-
-	/* Read results of transaction */
-	if (global_status_register != (1 << 1))
-		return SMBUS_ERROR;
-	return 0;
-}
-
 static int lsmbus_write_byte(device_t dev, u8 address, u8 data)
 {
 	u16 device;
@@ -93,58 +50,6 @@
 	return do_smbus_write_byte(res->base, device, address, data);
 }
 
-static int do_smbus_block_write(unsigned int smbus_base, unsigned int device,
-			      unsigned int cmd, unsigned int bytes, const u8 *buf)
-{
-	u8 status;
-
-	if (smbus_wait_until_ready(smbus_base) < 0)
-		return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
-
-	/* Setup transaction */
-	/* Disable interrupts */
-	outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
-	/* Set the device I'm talking too */
-	outb(((device & 0x7f) << 1) & ~0x01, smbus_base + SMBXMITADD);
-	/* Set the command/address... */
-	outb(cmd & 0xff, smbus_base + SMBHSTCMD);
-	/* Set up for a block data write */
-	outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x5 << 2),
-	     (smbus_base + SMBHSTCTL));
-	/* Clear any lingering errors, so the transaction will run */
-	outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
-
-	/* set number of bytes to transfer */
-	outb(bytes, smbus_base + SMBHSTDAT0);
-
-	outb(*buf++, smbus_base + SMBBLKDAT);
-	bytes--;
-
-	/* Start the command */
-	outb((inb(smbus_base + SMBHSTCTL) | 0x40),
-	     smbus_base + SMBHSTCTL);
-
-	while (!(inb(smbus_base + SMBHSTSTAT) & 1))
-		;
-	/* Poll for transaction completion */
-	do {
-		status = inb(smbus_base + SMBHSTSTAT);
-		if (status & ((1 << 4) | /* FAILED */
-			      (1 << 3) | /* BUS ERR */
-			      (1 << 2))) /* DEV ERR */
-			return SMBUS_ERROR;
-
-		if (status & 0x80) { /* Byte done */
-			outb(*buf++, smbus_base + SMBBLKDAT);
-			outb(status, smbus_base + SMBHSTSTAT);
-		}
-	} while (status & 0x01);
-
-	return 0;
-}
-
-
-
 static int lsmbus_block_write(device_t dev, u8 cmd, u8 bytes, const u8 *buf)
 {
 	u16 device;
@@ -157,57 +62,6 @@
 	return do_smbus_block_write(res->base, device, cmd, bytes, buf);
 }
 
-static int do_smbus_block_read(unsigned int smbus_base, unsigned int device,
-			      unsigned int cmd, unsigned int bytes, u8 *buf)
-{
-	u8 status;
-	int bytes_read = 0;
-	if (smbus_wait_until_ready(smbus_base) < 0)
-		return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
-
-	/* Setup transaction */
-	/* Disable interrupts */
-	outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
-	/* Set the device I'm talking too */
-	outb(((device & 0x7f) << 1) | 1, smbus_base + SMBXMITADD);
-	/* Set the command/address... */
-	outb(cmd & 0xff, smbus_base + SMBHSTCMD);
-	/* Set up for a block data read */
-	outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x5 << 2),
-	     (smbus_base + SMBHSTCTL));
-	/* Clear any lingering errors, so the transaction will run */
-	outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
-
-	/* Start the command */
-	outb((inb(smbus_base + SMBHSTCTL) | 0x40),
-	     smbus_base + SMBHSTCTL);
-
-	while (!(inb(smbus_base + SMBHSTSTAT) & 1))
-		;
-	/* Poll for transaction completion */
-	do {
-		status = inb(smbus_base + SMBHSTSTAT);
-		if (status & ((1 << 4) | /* FAILED */
-			      (1 << 3) | /* BUS ERR */
-			      (1 << 2))) /* DEV ERR */
-			return SMBUS_ERROR;
-
-		if (status & 0x80) { /* Byte done */
-			*buf = inb(smbus_base + SMBBLKDAT);
-			buf++;
-			bytes_read++;
-			outb(status, smbus_base + SMBHSTSTAT);
-			if (--bytes == 1) {
-				/* indicate that next byte is the last one */
-				outb(inb(smbus_base + SMBHSTCTL) | 0x20,
-					 smbus_base + SMBHSTCTL);
-			}
-		}
-	} while (status & 0x01);
-
-	return bytes_read;
-}
-
 static int lsmbus_block_read(device_t dev, u8 cmd, u8 bytes, u8 *buf)
 {
 	u16 device;
diff --git a/src/southbridge/intel/i82801gx/smbus.h b/src/southbridge/intel/i82801gx/smbus.h
deleted file mode 100644
index ff8e1fb..0000000
--- a/src/southbridge/intel/i82801gx/smbus.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * This file is part of the coreboot project.
- *
- * Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com>
- * Copyright (C) 2009 coresystems GmbH
- *
- * 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.
- */
-
-#include <device/smbus_def.h>
-#include "i82801gx.h"
-
-static void smbus_delay(void)
-{
-	inb(0x80);
-}
-
-static int smbus_wait_until_ready(u16 smbus_base)
-{
-	unsigned int loops = SMBUS_TIMEOUT;
-	unsigned char byte;
-	do {
-		smbus_delay();
-		if (--loops == 0)
-			break;
-		byte = inb(smbus_base + SMBHSTSTAT);
-	} while (byte & 1);
-	return loops ? 0 : -1;
-}
-
-static int smbus_wait_until_done(u16 smbus_base)
-{
-	unsigned int loops = SMBUS_TIMEOUT;
-	unsigned char byte;
-	do {
-		smbus_delay();
-		if (--loops == 0)
-			break;
-		byte = inb(smbus_base + SMBHSTSTAT);
-	} while ((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0);
-	return loops ? 0 : -1;
-}
-
-static int do_smbus_read_byte(unsigned int smbus_base, unsigned int device, unsigned int address)
-{
-	unsigned char global_status_register;
-	unsigned char byte;
-
-	if (smbus_wait_until_ready(smbus_base) < 0)
-		return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
-	/* Setup transaction */
-	/* Disable interrupts */
-	outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
-	/* Set the device I'm talking too */
-	outb(((device & 0x7f) << 1) | 1, smbus_base + SMBXMITADD);
-	/* Set the command/address... */
-	outb(address & 0xff, smbus_base + SMBHSTCMD);
-	/* Set up for a byte data read */
-	outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x2 << 2),
-	     (smbus_base + SMBHSTCTL));
-	/* Clear any lingering errors, so the transaction will run */
-	outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
-
-	/* Clear the data byte... */
-	outb(0, smbus_base + SMBHSTDAT0);
-
-	/* Start the command */
-	outb((inb(smbus_base + SMBHSTCTL) | 0x40),
-	     smbus_base + SMBHSTCTL);
-
-	/* Poll for transaction completion */
-	if (smbus_wait_until_done(smbus_base) < 0)
-		return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
-
-	global_status_register = inb(smbus_base + SMBHSTSTAT);
-
-	/* Ignore the "In Use" status... */
-	global_status_register &= ~(3 << 5);
-
-	/* Read results of transaction */
-	byte = inb(smbus_base + SMBHSTDAT0);
-	if (global_status_register != (1 << 1))
-		return SMBUS_ERROR;
-	return byte;
-}
diff --git a/src/southbridge/intel/i82801ix/Kconfig b/src/southbridge/intel/i82801ix/Kconfig
index e4d1f91..6879bce 100644
--- a/src/southbridge/intel/i82801ix/Kconfig
+++ b/src/southbridge/intel/i82801ix/Kconfig
@@ -17,6 +17,7 @@
 config SOUTHBRIDGE_INTEL_I82801IX
 	bool
 	select SOUTHBRIDGE_INTEL_COMMON
+	select SOUTHBRIDGE_INTEL_COMMON_SMBUS
 	select IOAPIC
 	select HAVE_USBDEBUG
 	select HAVE_HARD_RESET
diff --git a/src/southbridge/intel/i82801ix/early_smbus.c b/src/southbridge/intel/i82801ix/early_smbus.c
index 31b33e9..0e4195c 100644
--- a/src/southbridge/intel/i82801ix/early_smbus.c
+++ b/src/southbridge/intel/i82801ix/early_smbus.c
@@ -19,8 +19,8 @@
 #include <console/console.h>
 #include <device/pci_ids.h>
 #include <device/pci_def.h>
+#include <southbridge/intel/common/smbus.h>
 #include "i82801ix.h"
-#include "smbus.h"
 
 void enable_smbus(void)
 {
diff --git a/src/southbridge/intel/i82801ix/i82801ix.h b/src/southbridge/intel/i82801ix/i82801ix.h
index af4efcd..38dfa38 100644
--- a/src/southbridge/intel/i82801ix/i82801ix.h
+++ b/src/southbridge/intel/i82801ix/i82801ix.h
@@ -154,22 +154,6 @@
 #define SMB_SMI_EN		(1 << 1)
 #define HST_EN			(1 << 0)
 
-/* SMBus I/O bits. */
-#define SMBHSTSTAT		0x0
-#define SMBHSTCTL		0x2
-#define SMBHSTCMD		0x3
-#define SMBXMITADD		0x4
-#define SMBHSTDAT0		0x5
-#define SMBHSTDAT1		0x6
-#define SMBBLKDAT		0x7
-#define SMBTRNSADD		0x9
-#define SMBSLVDATA		0xa
-#define SMLINK_PIN_CTL		0xe
-#define SMBUS_PIN_CTL		0xf
-
-#define SMBUS_TIMEOUT		(10 * 1000 * 100)
-
-
 #define RCBA8(x) *((volatile u8 *)(DEFAULT_RCBA + x))
 #define RCBA16(x) *((volatile u16 *)(DEFAULT_RCBA + x))
 #define RCBA32(x) *((volatile u32 *)(DEFAULT_RCBA + x))
diff --git a/src/southbridge/intel/i82801ix/smbus.c b/src/southbridge/intel/i82801ix/smbus.c
index 2113722..ccfcddb 100644
--- a/src/southbridge/intel/i82801ix/smbus.c
+++ b/src/southbridge/intel/i82801ix/smbus.c
@@ -22,7 +22,8 @@
 #include <device/pci_ids.h>
 #include <device/pci_ops.h>
 #include <arch/io.h>
-#include "smbus.h"
+#include <southbridge/intel/common/smbus.h>
+#include "i82801ix.h"
 
 static void pch_smbus_init(device_t dev)
 {
diff --git a/src/southbridge/intel/i82801ix/smbus.h b/src/southbridge/intel/i82801ix/smbus.h
deleted file mode 100644
index bcc7587..0000000
--- a/src/southbridge/intel/i82801ix/smbus.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * This file is part of the coreboot project.
- *
- * Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com>
- * Copyright (C) 2009 coresystems GmbH
- *
- * 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.
- */
-
-#include <device/smbus_def.h>
-#include "i82801ix.h"
-
-static void smbus_delay(void)
-{
-	inb(0x80);
-}
-
-static int smbus_wait_until_ready(u16 smbus_base)
-{
-	unsigned loops = SMBUS_TIMEOUT;
-	unsigned char byte;
-	do {
-		smbus_delay();
-		if (--loops == 0)
-			break;
-		byte = inb(smbus_base + SMBHSTSTAT);
-	} while (byte & 1);
-	return loops ? 0 : -1;
-}
-
-static int smbus_wait_until_done(u16 smbus_base)
-{
-	unsigned loops = SMBUS_TIMEOUT;
-	unsigned char byte;
-	do {
-		smbus_delay();
-		if (--loops == 0)
-			break;
-		byte = inb(smbus_base + SMBHSTSTAT);
-	} while ((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0);
-	return loops ? 0 : -1;
-}
-
-static int do_smbus_read_byte(unsigned smbus_base, unsigned device, unsigned address)
-{
-	unsigned char global_status_register;
-	unsigned char byte;
-
-	if (smbus_wait_until_ready(smbus_base) < 0) {
-		return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
-	}
-	/* Setup transaction */
-	/* Disable interrupts */
-	outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
-	/* Set the device I'm talking too */
-	outb(((device & 0x7f) << 1) | 1, smbus_base + SMBXMITADD);
-	/* Set the command/address... */
-	outb(address & 0xff, smbus_base + SMBHSTCMD);
-	/* Set up for a byte data read */
-	outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x2 << 2),
-	     (smbus_base + SMBHSTCTL));
-	/* Clear any lingering errors, so the transaction will run */
-	outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
-
-	/* Clear the data byte... */
-	outb(0, smbus_base + SMBHSTDAT0);
-
-	/* Start the command */
-	outb((inb(smbus_base + SMBHSTCTL) | 0x40),
-	     smbus_base + SMBHSTCTL);
-
-	/* Poll for transaction completion */
-	if (smbus_wait_until_done(smbus_base) < 0) {
-		return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
-	}
-
-	global_status_register = inb(smbus_base + SMBHSTSTAT);
-
-	/* Ignore the "In Use" status... */
-	global_status_register &= ~(3 << 5);
-
-	/* Read results of transaction */
-	byte = inb(smbus_base + SMBHSTDAT0);
-	if (global_status_register != (1 << 1)) {
-		return SMBUS_ERROR;
-	}
-	return byte;
-}
-
-#ifndef __PRE_RAM__
-static  int do_smbus_write_byte(unsigned smbus_base, unsigned device, unsigned address, unsigned data)
-{
-	unsigned char global_status_register;
-
-	if (smbus_wait_until_ready(smbus_base) < 0)
-		return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
-
-	/* Setup transaction */
-	/* Disable interrupts */
-	outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
-	/* Set the device I'm talking too */
-	outb(((device & 0x7f) << 1) & ~0x01, smbus_base + SMBXMITADD);
-	/* Set the command/address... */
-	outb(address & 0xff, smbus_base + SMBHSTCMD);
-	/* Set up for a byte data read */
-	outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x2 << 2),
-	     (smbus_base + SMBHSTCTL));
-	/* Clear any lingering errors, so the transaction will run */
-	outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
-
-	/* Clear the data byte... */
-	outb(data, smbus_base + SMBHSTDAT0);
-
-	/* Start the command */
-	outb((inb(smbus_base + SMBHSTCTL) | 0x40),
-	     smbus_base + SMBHSTCTL);
-
-	/* Poll for transaction completion */
-	if (smbus_wait_until_done(smbus_base) < 0)
-		return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
-
-	global_status_register = inb(smbus_base + SMBHSTSTAT);
-
-	/* Ignore the "In Use" status... */
-	global_status_register &= ~(3 << 5);
-
-	/* Read results of transaction */
-	if (global_status_register != (1 << 1))
-		return SMBUS_ERROR;
-
-	return 0;
-}
-#endif
diff --git a/src/southbridge/intel/i82801jx/Kconfig b/src/southbridge/intel/i82801jx/Kconfig
index 3f0e569..5edaf1a 100644
--- a/src/southbridge/intel/i82801jx/Kconfig
+++ b/src/southbridge/intel/i82801jx/Kconfig
@@ -17,6 +17,7 @@
 config SOUTHBRIDGE_INTEL_I82801JX
 	bool
 	select SOUTHBRIDGE_INTEL_COMMON
+	select SOUTHBRIDGE_INTEL_COMMON_SMBUS
 	select IOAPIC
 	select HAVE_USBDEBUG
 	select HAVE_HARD_RESET
diff --git a/src/southbridge/intel/i82801jx/early_smbus.c b/src/southbridge/intel/i82801jx/early_smbus.c
index fb6c252..a950992 100644
--- a/src/southbridge/intel/i82801jx/early_smbus.c
+++ b/src/southbridge/intel/i82801jx/early_smbus.c
@@ -19,8 +19,8 @@
 #include <console/console.h>
 #include <device/pci_ids.h>
 #include <device/pci_def.h>
+#include <southbridge/intel/common/smbus.h>
 #include "i82801jx.h"
-#include "smbus.h"
 
 void enable_smbus(void)
 {
diff --git a/src/southbridge/intel/i82801jx/i82801jx.h b/src/southbridge/intel/i82801jx/i82801jx.h
index be92a8b..fd74d2a 100644
--- a/src/southbridge/intel/i82801jx/i82801jx.h
+++ b/src/southbridge/intel/i82801jx/i82801jx.h
@@ -147,22 +147,6 @@
 #define SMB_SMI_EN		(1 << 1)
 #define HST_EN			(1 << 0)
 
-/* SMBus I/O bits. */
-#define SMBHSTSTAT		0x0
-#define SMBHSTCTL		0x2
-#define SMBHSTCMD		0x3
-#define SMBXMITADD		0x4
-#define SMBHSTDAT0		0x5
-#define SMBHSTDAT1		0x6
-#define SMBBLKDAT		0x7
-#define SMBTRNSADD		0x9
-#define SMBSLVDATA		0xa
-#define SMLINK_PIN_CTL		0xe
-#define SMBUS_PIN_CTL		0xf
-
-#define SMBUS_TIMEOUT		(10 * 1000 * 100)
-
-
 #define RCBA8(x) *((volatile u8 *)(DEFAULT_RCBA + x))
 #define RCBA16(x) *((volatile u16 *)(DEFAULT_RCBA + x))
 #define RCBA32(x) *((volatile u32 *)(DEFAULT_RCBA + x))
diff --git a/src/southbridge/intel/i82801jx/smbus.c b/src/southbridge/intel/i82801jx/smbus.c
index 00894cf..bc735a3 100644
--- a/src/southbridge/intel/i82801jx/smbus.c
+++ b/src/southbridge/intel/i82801jx/smbus.c
@@ -22,7 +22,8 @@
 #include <device/pci_ids.h>
 #include <device/pci_ops.h>
 #include <arch/io.h>
-#include "smbus.h"
+#include <southbridge/intel/common/smbus.h>
+#include "i82801jx.h"
 
 static void pch_smbus_init(device_t dev)
 {
diff --git a/src/southbridge/intel/i82801jx/smbus.h b/src/southbridge/intel/i82801jx/smbus.h
deleted file mode 100644
index 61402f7..0000000
--- a/src/southbridge/intel/i82801jx/smbus.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * This file is part of the coreboot project.
- *
- * Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com>
- * Copyright (C) 2009 coresystems GmbH
- *
- * 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.
- */
-
-#include <device/smbus_def.h>
-#include "i82801jx.h"
-
-static void smbus_delay(void)
-{
-	inb(0x80);
-}
-
-static int smbus_wait_until_ready(u16 smbus_base)
-{
-	unsigned loops = SMBUS_TIMEOUT;
-	unsigned char byte;
-	do {
-		smbus_delay();
-		if (--loops == 0)
-			break;
-		byte = inb(smbus_base + SMBHSTSTAT);
-	} while (byte & 1);
-	return loops ? 0 : -1;
-}
-
-static int smbus_wait_until_done(u16 smbus_base)
-{
-	unsigned loops = SMBUS_TIMEOUT;
-	unsigned char byte;
-	do {
-		smbus_delay();
-		if (--loops == 0)
-			break;
-		byte = inb(smbus_base + SMBHSTSTAT);
-	} while ((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0);
-	return loops ? 0 : -1;
-}
-
-static int do_smbus_read_byte(unsigned smbus_base, unsigned device, unsigned address)
-{
-	unsigned char global_status_register;
-	unsigned char byte;
-
-	if (smbus_wait_until_ready(smbus_base) < 0) {
-		return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
-	}
-	/* Setup transaction */
-	/* Disable interrupts */
-	outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
-	/* Set the device I'm talking too */
-	outb(((device & 0x7f) << 1) | 1, smbus_base + SMBXMITADD);
-	/* Set the command/address... */
-	outb(address & 0xff, smbus_base + SMBHSTCMD);
-	/* Set up for a byte data read */
-	outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x2 << 2),
-	     (smbus_base + SMBHSTCTL));
-	/* Clear any lingering errors, so the transaction will run */
-	outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
-
-	/* Clear the data byte... */
-	outb(0, smbus_base + SMBHSTDAT0);
-
-	/* Start the command */
-	outb((inb(smbus_base + SMBHSTCTL) | 0x40),
-	     smbus_base + SMBHSTCTL);
-
-	/* Poll for transaction completion */
-	if (smbus_wait_until_done(smbus_base) < 0) {
-		return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
-	}
-
-	global_status_register = inb(smbus_base + SMBHSTSTAT);
-
-	/* Ignore the "In Use" status... */
-	global_status_register &= ~(3 << 5);
-
-	/* Read results of transaction */
-	byte = inb(smbus_base + SMBHSTDAT0);
-	if (global_status_register != (1 << 1)) {
-		return SMBUS_ERROR;
-	}
-	return byte;
-}
-
-#ifndef __PRE_RAM__
-static  int do_smbus_write_byte(unsigned smbus_base, unsigned device, unsigned address, unsigned data)
-{
-	unsigned char global_status_register;
-
-	if (smbus_wait_until_ready(smbus_base) < 0)
-		return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
-
-	/* Setup transaction */
-	/* Disable interrupts */
-	outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
-	/* Set the device I'm talking too */
-	outb(((device & 0x7f) << 1) & ~0x01, smbus_base + SMBXMITADD);
-	/* Set the command/address... */
-	outb(address & 0xff, smbus_base + SMBHSTCMD);
-	/* Set up for a byte data read */
-	outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x2 << 2),
-	     (smbus_base + SMBHSTCTL));
-	/* Clear any lingering errors, so the transaction will run */
-	outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
-
-	/* Clear the data byte... */
-	outb(data, smbus_base + SMBHSTDAT0);
-
-	/* Start the command */
-	outb((inb(smbus_base + SMBHSTCTL) | 0x40),
-	     smbus_base + SMBHSTCTL);
-
-	/* Poll for transaction completion */
-	if (smbus_wait_until_done(smbus_base) < 0)
-		return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
-
-	global_status_register = inb(smbus_base + SMBHSTSTAT);
-
-	/* Ignore the "In Use" status... */
-	global_status_register &= ~(3 << 5);
-
-	/* Read results of transaction */
-	if (global_status_register != (1 << 1))
-		return SMBUS_ERROR;
-
-	return 0;
-}
-#endif
diff --git a/src/southbridge/intel/ibexpeak/Kconfig b/src/southbridge/intel/ibexpeak/Kconfig
index ad32a9b..41ace46f 100644
--- a/src/southbridge/intel/ibexpeak/Kconfig
+++ b/src/southbridge/intel/ibexpeak/Kconfig
@@ -30,6 +30,7 @@
 	select PCIEXP_COMMON_CLOCK
 	select SPI_FLASH
 	select SOUTHBRIDGE_INTEL_COMMON
+	select SOUTHBRIDGE_INTEL_COMMON_SMBUS
 	select HAVE_USBDEBUG_OPTIONS
 	select COMMON_FADT
 	select ACPI_SATA_GENERATOR
diff --git a/src/southbridge/intel/ibexpeak/early_smbus.c b/src/southbridge/intel/ibexpeak/early_smbus.c
index f3dab8d..b7823eb 100644
--- a/src/southbridge/intel/ibexpeak/early_smbus.c
+++ b/src/southbridge/intel/ibexpeak/early_smbus.c
@@ -18,8 +18,8 @@
 #include <console/console.h>
 #include <device/pci_ids.h>
 #include <device/pci_def.h>
+#include <southbridge/intel/common/smbus.h>
 #include "pch.h"
-#include "smbus.h"
 
 void enable_smbus(void)
 {
diff --git a/src/southbridge/intel/ibexpeak/pch.h b/src/southbridge/intel/ibexpeak/pch.h
index 63307d9..1898ae3 100644
--- a/src/southbridge/intel/ibexpeak/pch.h
+++ b/src/southbridge/intel/ibexpeak/pch.h
@@ -233,22 +233,6 @@
 #define SMB_SMI_EN		(1 << 1)
 #define HST_EN			(1 << 0)
 
-/* SMBus I/O bits. */
-#define SMBHSTSTAT		0x0
-#define SMBHSTCTL		0x2
-#define SMBHSTCMD		0x3
-#define SMBXMITADD		0x4
-#define SMBHSTDAT0		0x5
-#define SMBHSTDAT1		0x6
-#define SMBBLKDAT		0x7
-#define SMBTRNSADD		0x9
-#define SMBSLVDATA		0xa
-#define SMLINK_PIN_CTL		0xe
-#define SMBUS_PIN_CTL		0xf
-
-#define SMBUS_TIMEOUT		(10 * 1000 * 100)
-
-
 /* Southbridge IO BARs */
 
 #define GPIOBASE		0x48
diff --git a/src/southbridge/intel/ibexpeak/smbus.c b/src/southbridge/intel/ibexpeak/smbus.c
index 3b2f18c..aea52de 100644
--- a/src/southbridge/intel/ibexpeak/smbus.c
+++ b/src/southbridge/intel/ibexpeak/smbus.c
@@ -22,8 +22,8 @@
 #include <device/pci_ids.h>
 #include <device/pci_ops.h>
 #include <arch/io.h>
+#include <southbridge/intel/common/smbus.h>
 #include "pch.h"
-#include "smbus.h"
 
 static void pch_smbus_init(device_t dev)
 {
diff --git a/src/southbridge/intel/ibexpeak/smbus.h b/src/southbridge/intel/ibexpeak/smbus.h
deleted file mode 100644
index 0815bf4..0000000
--- a/src/southbridge/intel/ibexpeak/smbus.h
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * This file is part of the coreboot project.
- *
- * Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com>
- * Copyright (C) 2009 coresystems GmbH
- * Copyright (C) 2013 Vladimir Serbinenko
- *
- * 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.
- */
-
-#include <device/smbus_def.h>
-#include "pch.h"
-
-static void smbus_delay(void)
-{
-	inb(0x80);
-}
-
-static int smbus_wait_until_ready(u16 smbus_base)
-{
-	unsigned loops = SMBUS_TIMEOUT;
-	unsigned char byte;
-	do {
-		smbus_delay();
-		if (--loops == 0)
-			break;
-		byte = inb(smbus_base + SMBHSTSTAT);
-	} while (byte & 1);
-	return loops ? 0 : -1;
-}
-
-static int smbus_wait_until_done(u16 smbus_base)
-{
-	unsigned loops = SMBUS_TIMEOUT;
-	unsigned char byte;
-	do {
-		smbus_delay();
-		if (--loops == 0)
-			break;
-		byte = inb(smbus_base + SMBHSTSTAT);
-	} while ((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0);
-	return loops ? 0 : -1;
-}
-
-static int do_smbus_read_byte(unsigned smbus_base, unsigned device, unsigned address)
-{
-	unsigned char global_status_register;
-	unsigned char byte;
-
-	if (smbus_wait_until_ready(smbus_base) < 0) {
-		return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
-	}
-	/* Setup transaction */
-	/* Disable interrupts */
-	outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
-	/* Set the device I'm talking too */
-	outb(((device & 0x7f) << 1) | 1, smbus_base + SMBXMITADD);
-	/* Set the command/address... */
-	outb(address & 0xff, smbus_base + SMBHSTCMD);
-	/* Set up for a byte data read */
-	outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x2 << 2),
-	     (smbus_base + SMBHSTCTL));
-	/* Clear any lingering errors, so the transaction will run */
-	outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
-
-	/* Clear the data byte... */
-	outb(0, smbus_base + SMBHSTDAT0);
-
-	/* Start the command */
-	outb((inb(smbus_base + SMBHSTCTL) | 0x40),
-	     smbus_base + SMBHSTCTL);
-
-	/* Poll for transaction completion */
-	if (smbus_wait_until_done(smbus_base) < 0) {
-		return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
-	}
-
-	global_status_register = inb(smbus_base + SMBHSTSTAT);
-
-	/* Ignore the "In Use" status... */
-	global_status_register &= ~(3 << 5);
-
-	/* Read results of transaction */
-	byte = inb(smbus_base + SMBHSTDAT0);
-	if (global_status_register != (1 << 1)) {
-		return SMBUS_ERROR;
-	}
-	return byte;
-}
-
-static  int do_smbus_write_byte(unsigned smbus_base, unsigned device, unsigned address, unsigned data)
-{
-	unsigned char global_status_register;
-
-	if (smbus_wait_until_ready(smbus_base) < 0)
-		return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
-
-	/* Setup transaction */
-	/* Disable interrupts */
-	outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
-	/* Set the device I'm talking too */
-	outb(((device & 0x7f) << 1) & ~0x01, smbus_base + SMBXMITADD);
-	/* Set the command/address... */
-	outb(address & 0xff, smbus_base + SMBHSTCMD);
-	/* Set up for a byte data read */
-	outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x2 << 2),
-	     (smbus_base + SMBHSTCTL));
-	/* Clear any lingering errors, so the transaction will run */
-	outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
-
-	/* Clear the data byte... */
-	outb(data, smbus_base + SMBHSTDAT0);
-
-	/* Start the command */
-	outb((inb(smbus_base + SMBHSTCTL) | 0x40),
-	     smbus_base + SMBHSTCTL);
-
-	/* Poll for transaction completion */
-	if (smbus_wait_until_done(smbus_base) < 0)
-		return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
-
-	global_status_register = inb(smbus_base + SMBHSTSTAT);
-
-	/* Ignore the "In Use" status... */
-	global_status_register &= ~(3 << 5);
-
-	/* Read results of transaction */
-	if (global_status_register != (1 << 1))
-		return SMBUS_ERROR;
-
-	return 0;
-}
-
-#ifdef __PRE_RAM__
-
-static int do_smbus_block_write(unsigned smbus_base, unsigned device,
-			      unsigned cmd, unsigned bytes, const u8 *buf)
-{
-	u8 status;
-
-	if (smbus_wait_until_ready(smbus_base) < 0)
-		return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
-
-	/* Setup transaction */
-	/* Disable interrupts */
-	outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
-	/* Set the device I'm talking too */
-	outb(((device & 0x7f) << 1) & ~0x01, smbus_base + SMBXMITADD);
-	/* Set the command/address... */
-	outb(cmd & 0xff, smbus_base + SMBHSTCMD);
-	/* Set up for a block data write */
-	outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x5 << 2),
-	     (smbus_base + SMBHSTCTL));
-	/* Clear any lingering errors, so the transaction will run */
-	outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
-
-	/* set number of bytes to transfer */
-	outb(bytes, smbus_base + SMBHSTDAT0);
-
-	outb(*buf++, smbus_base + SMBBLKDAT);
-	bytes--;
-
-	/* Start the command */
-	outb((inb(smbus_base + SMBHSTCTL) | 0x40),
-	     smbus_base + SMBHSTCTL);
-
-	while (!(inb(smbus_base + SMBHSTSTAT) & 1));
-	/* Poll for transaction completion */
-	do {
-		status = inb(smbus_base + SMBHSTSTAT);
-		if (status & ((1 << 4) | /* FAILED */
-			      (1 << 3) | /* BUS ERR */
-			      (1 << 2))) /* DEV ERR */
-			return SMBUS_ERROR;
-
-		if (status & 0x80) { /* Byte done */
-			outb(*buf++, smbus_base + SMBBLKDAT);
-			outb(status, smbus_base + SMBHSTSTAT);
-		}
-	} while (status & 0x01);
-
-	return 0;
-}
-
-static int do_smbus_block_read(unsigned smbus_base, unsigned device,
-			      unsigned cmd, unsigned bytes, u8 *buf)
-{
-	u8 status;
-	int bytes_read = 0;
-	if (smbus_wait_until_ready(smbus_base) < 0)
-		return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
-
-	/* Setup transaction */
-	/* Disable interrupts */
-	outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
-	/* Set the device I'm talking too */
-	outb(((device & 0x7f) << 1) | 1, smbus_base + SMBXMITADD);
-	/* Set the command/address... */
-	outb(cmd & 0xff, smbus_base + SMBHSTCMD);
-	/* Set up for a block data read */
-	outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x5 << 2),
-	     (smbus_base + SMBHSTCTL));
-	/* Clear any lingering errors, so the transaction will run */
-	outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
-
-	/* Start the command */
-	outb((inb(smbus_base + SMBHSTCTL) | 0x40),
-	     smbus_base + SMBHSTCTL);
-
-	while (!(inb(smbus_base + SMBHSTSTAT) & 1));
-	/* Poll for transaction completion */
-	do {
-		status = inb(smbus_base + SMBHSTSTAT);
-		if (status & ((1 << 4) | /* FAILED */
-			      (1 << 3) | /* BUS ERR */
-			      (1 << 2))) /* DEV ERR */
-			return SMBUS_ERROR;
-
-		if (status & 0x80) { /* Byte done */
-			*buf = inb(smbus_base + SMBBLKDAT);
-			buf++;
-			bytes_read++;
-			outb(status, smbus_base + SMBHSTSTAT);
-			if (--bytes == 1) {
-				/* indicate that next byte is the last one */
-				outb(inb(smbus_base + SMBHSTCTL) | 0x20,
-					 smbus_base + SMBHSTCTL);
-			}
-		}
-	} while (status & 0x01);
-
-	return bytes_read;
-}
-#endif
diff --git a/src/southbridge/intel/lynxpoint/Kconfig b/src/southbridge/intel/lynxpoint/Kconfig
index 742f95c..c65e5d7 100644
--- a/src/southbridge/intel/lynxpoint/Kconfig
+++ b/src/southbridge/intel/lynxpoint/Kconfig
@@ -22,6 +22,7 @@
 	def_bool y
 	select ACPI_INTEL_HARDWARE_SLEEP_VALUES
 	select SOUTHBRIDGE_INTEL_COMMON
+	select SOUTHBRIDGE_INTEL_COMMON_SMBUS
 	select IOAPIC
 	select HAVE_HARD_RESET
 	select HAVE_USBDEBUG_OPTIONS
diff --git a/src/southbridge/intel/lynxpoint/early_smbus.c b/src/southbridge/intel/lynxpoint/early_smbus.c
index 2b174c7..cf3a34c 100644
--- a/src/southbridge/intel/lynxpoint/early_smbus.c
+++ b/src/southbridge/intel/lynxpoint/early_smbus.c
@@ -18,8 +18,8 @@
 #include <console/console.h>
 #include <device/pci_ids.h>
 #include <device/pci_def.h>
+#include <southbridge/intel/common/smbus.h>
 #include "pch.h"
-#include "smbus.h"
 
 void enable_smbus(void)
 {
diff --git a/src/southbridge/intel/lynxpoint/pch.h b/src/southbridge/intel/lynxpoint/pch.h
index c9c9c32..000f546 100644
--- a/src/southbridge/intel/lynxpoint/pch.h
+++ b/src/southbridge/intel/lynxpoint/pch.h
@@ -473,22 +473,6 @@
 #define SMB_SMI_EN		(1 << 1)
 #define HST_EN			(1 << 0)
 
-/* SMBus I/O bits. */
-#define SMBHSTSTAT		0x0
-#define SMBHSTCTL		0x2
-#define SMBHSTCMD		0x3
-#define SMBXMITADD		0x4
-#define SMBHSTDAT0		0x5
-#define SMBHSTDAT1		0x6
-#define SMBBLKDAT		0x7
-#define SMBTRNSADD		0x9
-#define SMBSLVDATA		0xa
-#define SMLINK_PIN_CTL		0xe
-#define SMBUS_PIN_CTL		0xf
-
-#define SMBUS_TIMEOUT		(10 * 1000 * 100)
-
-
 /* Southbridge IO BARs */
 
 #define GPIOBASE		0x48
diff --git a/src/southbridge/intel/lynxpoint/smbus.c b/src/southbridge/intel/lynxpoint/smbus.c
index d81a097..ccb5ea0 100644
--- a/src/southbridge/intel/lynxpoint/smbus.c
+++ b/src/southbridge/intel/lynxpoint/smbus.c
@@ -22,8 +22,8 @@
 #include <device/pci_ids.h>
 #include <device/pci_ops.h>
 #include <arch/io.h>
+#include <southbridge/intel/common/smbus.h>
 #include "pch.h"
-#include "smbus.h"
 
 static void pch_smbus_init(device_t dev)
 {
@@ -54,54 +54,6 @@
 	return do_smbus_read_byte(res->base, device, address);
 }
 
-static int do_smbus_write_byte(unsigned smbus_base, unsigned device,
-			       unsigned address, unsigned data)
-{
-	unsigned char global_status_register;
-
-	if (smbus_wait_until_ready(smbus_base) < 0)
-		return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
-
-	/* Setup transaction */
-	/* Disable interrupts */
-	outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
-	/* Set the device I'm talking too */
-	outb(((device & 0x7f) << 1) & ~0x01, smbus_base + SMBXMITADD);
-	/* Set the command/address... */
-	outb(address & 0xff, smbus_base + SMBHSTCMD);
-	/* Set up for a byte data read */
-	outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x2 << 2),
-	     (smbus_base + SMBHSTCTL));
-	/* Clear any lingering errors, so the transaction will run */
-	outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
-
-	/* Clear the data byte... */
-	outb(data, smbus_base + SMBHSTDAT0);
-
-	/* Start the command */
-	outb((inb(smbus_base + SMBHSTCTL) | 0x40),
-	     smbus_base + SMBHSTCTL);
-
-	/* Poll for transaction completion */
-	if (smbus_wait_until_done(smbus_base) < 0) {
-		printk(BIOS_ERR, "SMBUS transaction timeout\n");
-		return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
-	}
-
-	global_status_register = inb(smbus_base + SMBHSTSTAT);
-
-	/* Ignore the "In Use" status... */
-	global_status_register &= ~(3 << 5);
-
-	/* Read results of transaction */
-	if (global_status_register != (1 << 1)) {
-		printk(BIOS_ERR, "SMBUS transaction error\n");
-		return SMBUS_ERROR;
-	}
-
-	return 0;
-}
-
 static int lsmbus_write_byte(device_t dev, u8 address, u8 data)
 {
 	u16 device;
diff --git a/src/southbridge/intel/lynxpoint/smbus.h b/src/southbridge/intel/lynxpoint/smbus.h
deleted file mode 100644
index 0978963..0000000
--- a/src/southbridge/intel/lynxpoint/smbus.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * This file is part of the coreboot project.
- *
- * Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com>
- * Copyright (C) 2009 coresystems GmbH
- *
- * 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.
- */
-
-#include <device/smbus_def.h>
-#include "pch.h"
-
-static void smbus_delay(void)
-{
-	inb(0x80);
-}
-
-static int smbus_wait_until_ready(u16 smbus_base)
-{
-	unsigned loops = SMBUS_TIMEOUT;
-	unsigned char byte;
-	do {
-		smbus_delay();
-		if (--loops == 0)
-			break;
-		byte = inb(smbus_base + SMBHSTSTAT);
-	} while (byte & 1);
-	return loops ? 0 : -1;
-}
-
-static int smbus_wait_until_done(u16 smbus_base)
-{
-	unsigned loops = SMBUS_TIMEOUT;
-	unsigned char byte;
-	do {
-		smbus_delay();
-		if (--loops == 0)
-			break;
-		byte = inb(smbus_base + SMBHSTSTAT);
-	} while ((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0);
-	return loops ? 0 : -1;
-}
-
-static int do_smbus_read_byte(unsigned smbus_base, unsigned device, unsigned address)
-{
-	unsigned char global_status_register;
-	unsigned char byte;
-
-	if (smbus_wait_until_ready(smbus_base) < 0) {
-		return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
-	}
-	/* Setup transaction */
-	/* Disable interrupts */
-	outb(inb(smbus_base + SMBHSTCTL) & (~1), smbus_base + SMBHSTCTL);
-	/* Set the device I'm talking too */
-	outb(((device & 0x7f) << 1) | 1, smbus_base + SMBXMITADD);
-	/* Set the command/address... */
-	outb(address & 0xff, smbus_base + SMBHSTCMD);
-	/* Set up for a byte data read */
-	outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x2 << 2),
-	     (smbus_base + SMBHSTCTL));
-	/* Clear any lingering errors, so the transaction will run */
-	outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
-
-	/* Clear the data byte... */
-	outb(0, smbus_base + SMBHSTDAT0);
-
-	/* Start the command */
-	outb((inb(smbus_base + SMBHSTCTL) | 0x40),
-	     smbus_base + SMBHSTCTL);
-
-	/* Poll for transaction completion */
-	if (smbus_wait_until_done(smbus_base) < 0) {
-		return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
-	}
-
-	global_status_register = inb(smbus_base + SMBHSTSTAT);
-
-	/* Ignore the "In Use" status... */
-	global_status_register &= ~(3 << 5);
-
-	/* Read results of transaction */
-	byte = inb(smbus_base + SMBHSTDAT0);
-	if (global_status_register != (1 << 1)) {
-		return SMBUS_ERROR;
-	}
-	return byte;
-}