soc/amd/stoneyridge: Access SMBUS through MMIO

Currently SMBUS registers are accessed through IO, but with stoneyridge
they can be accessed through MMIO. This reduces the time of execution by
a tiny amount (MMIO write is faster than IO write, though MMIO read is about
as fast as IO read) as most of the time consumed is actually transaction
time. Convert code to MMIO access.

BUG=b:117754784
TEST=Used IO to write and MMIO to read, to confirm a one to one relationship
between IO and MMIO. Then build and boot grunt.

Change-Id: Ibe1471d1d578611e7d666f70bc97de4c3b74d7f8
Signed-off-by: Richard Spiegel <richard.spiegel@silverbackltd.com>
Reviewed-on: https://review.coreboot.org/c/29258
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Martin Roth <martinroth@google.com>
diff --git a/src/soc/amd/stoneyridge/include/soc/iomap.h b/src/soc/amd/stoneyridge/include/soc/iomap.h
index 78e8e09..b101014 100644
--- a/src/soc/amd/stoneyridge/include/soc/iomap.h
+++ b/src/soc/amd/stoneyridge/include/soc/iomap.h
@@ -38,6 +38,8 @@
 #define PM_MMIO_BASE			0xfed80300
 #define BIOSRAM_MMIO_BASE		0xfed80500
 #define ACPI_REG_MMIO_BASE		0xfed80800
+#define ASF_MMIO_BASE			0xfed80900
+#define SMBUS_MMIO_BASE			0xfed80a00
 #define GPIO_IOMUX_MMIO_BASE		0xfed80d00
 #define MISC_MMIO_BASE			0xfed80e00
 #define XHCI_ACPI_PM_MMIO_BASE		0xfed81c00
diff --git a/src/soc/amd/stoneyridge/include/soc/smbus.h b/src/soc/amd/stoneyridge/include/soc/smbus.h
index 1bb4346..71f7faf 100644
--- a/src/soc/amd/stoneyridge/include/soc/smbus.h
+++ b/src/soc/amd/stoneyridge/include/soc/smbus.h
@@ -19,50 +19,6 @@
 #include <stdint.h>
 #include <soc/iomap.h>
 
-#define SMBHSTSTAT			0x0
-#define   SMBHST_STAT_FAILED		0x10
-#define   SMBHST_STAT_COLLISION		0x08
-#define   SMBHST_STAT_ERROR		0x04
-#define   SMBHST_STAT_INTERRUPT		0x02
-#define   SMBHST_STAT_BUSY		0x01
-#define   SMBHST_STAT_CLEAR		0xff
-#define   SMBHST_STAT_NOERROR		0x02
-#define   SMBHST_STAT_VAL_BITS		0x1f
-#define   SMBHST_STAT_ERROR_BITS	0x1c
-
-#define SMBSLVSTAT			0x1
-#define   SMBSLV_STAT_ALERT		0x20
-#define   SMBSLV_STAT_SHADOW2		0x10
-#define   SMBSLV_STAT_SHADOW1		0x08
-#define   SMBSLV_STAT_SLV_STS		0x04
-#define   SMBSLV_STAT_SLV_INIT		0x02
-#define   SMBSLV_STAT_SLV_BUSY		0x01
-#define   SMBSLV_STAT_CLEAR		0x1f
-
-#define SMBHSTCTRL			0x2
-#define   SMBHST_CTRL_RST		0x80
-#define   SMBHST_CTRL_STRT		0x40
-#define   SMBHST_CTRL_QCK_RW		0x00
-#define   SMBHST_CTRL_BTE_RW		0x04
-#define   SMBHST_CTRL_BDT_RW		0x08
-#define   SMBHST_CTRL_WDT_RW		0x0c
-#define   SMBHST_CTRL_BLK_RW		0x14
-#define   SMBHST_CTRL_MODE_BITS		0x1c
-#define   SMBHST_CTRL_KILL		0x02
-#define   SMBHST_CTRL_IEN		0x01
-
-#define SMBHSTCMD			0x3
-#define SMBHSTADDR			0x4
-#define SMBHSTDAT0			0x5
-#define SMBHSTDAT1			0x6
-#define SMBHSTBLKDAT			0x7
-#define SMBSLVCTRL			0x8
-#define SMBSLVCMD_SHADOW		0x9
-#define SMBSLVEVT			0xa
-#define SMBSLVDAT			0xc
-#define SMBTIMING			0xe
-
-#define SMB_ASF_IO_BASE			0x01
 #define SMB_SPEED_400KHZ		(66000000 / (400000 * 4))
 
 #define AX_INDXC			0
@@ -91,10 +47,10 @@
 #define rcindxp_reg(reg, port, mask, val)	\
 	alink_rc_indx((RC_INDXP), (reg), (port), (mask), (val))
 
-int do_smbus_read_byte(u16 smbus_io_base, u8 device, u8 address);
-int do_smbus_write_byte(u16 smbus_io_base, u8 device, u8 address, u8 val);
-int do_smbus_recv_byte(u16 smbus_io_base, u8 device);
-int do_smbus_send_byte(u16 smbus_io_base, u8 device, u8 val);
+int do_smbus_read_byte(u32 mmio, u8 device, u8 address);
+int do_smbus_write_byte(u32 mmio, u8 device, u8 address, u8 val);
+int do_smbus_recv_byte(u32 mmio, u8 device);
+int do_smbus_send_byte(u32 mmio, u8 device, u8 val);
 void alink_rc_indx(u32 reg_space, u32 reg_addr, u32 port, u32 mask, u32 val);
 void alink_ab_indx(u32 reg_space, u32 reg_addr, u32 mask, u32 val);
 void alink_ax_indx(u32 space /*c or p? */, u32 axindc, u32 mask, u32 val);
diff --git a/src/soc/amd/stoneyridge/include/soc/southbridge.h b/src/soc/amd/stoneyridge/include/soc/southbridge.h
index adf3af2..1652bbc 100644
--- a/src/soc/amd/stoneyridge/include/soc/southbridge.h
+++ b/src/soc/amd/stoneyridge/include/soc/southbridge.h
@@ -39,6 +39,8 @@
 #define   FORCE_SLPSTATE_RETRY		BIT(25)
 #define   FORCE_STPCLK_RETRY		BIT(24)
 
+#define SMB_ASF_IO_BASE			0x01 /* part of PM_DECODE_EN */
+
 #define PWR_RESET_CFG			0x10
 #define   TOGGLE_ALL_PWR_GOOD		BIT(1)
 
@@ -111,6 +113,50 @@
 #define MMIO_ACPI_GPE0_EN		0x18
 #define MMIO_ACPI_PM_TMR_BLK		0x08
 
+/* SMBUS MMIO offsets 0xfed80a00 */
+#define SMBHSTSTAT			0x0
+#define   SMBHST_STAT_FAILED		0x10
+#define   SMBHST_STAT_COLLISION		0x08
+#define   SMBHST_STAT_ERROR		0x04
+#define   SMBHST_STAT_INTERRUPT		0x02
+#define   SMBHST_STAT_BUSY		0x01
+#define   SMBHST_STAT_CLEAR		0xff
+#define   SMBHST_STAT_NOERROR		0x02
+#define   SMBHST_STAT_VAL_BITS		0x1f
+#define   SMBHST_STAT_ERROR_BITS	0x1c
+
+#define SMBSLVSTAT			0x1
+#define   SMBSLV_STAT_ALERT		0x20
+#define   SMBSLV_STAT_SHADOW2		0x10
+#define   SMBSLV_STAT_SHADOW1		0x08
+#define   SMBSLV_STAT_SLV_STS		0x04
+#define   SMBSLV_STAT_SLV_INIT		0x02
+#define   SMBSLV_STAT_SLV_BUSY		0x01
+#define   SMBSLV_STAT_CLEAR		0x1f
+
+#define SMBHSTCTRL			0x2
+#define   SMBHST_CTRL_RST		0x80
+#define   SMBHST_CTRL_STRT		0x40
+#define   SMBHST_CTRL_QCK_RW		0x00
+#define   SMBHST_CTRL_BTE_RW		0x04
+#define   SMBHST_CTRL_BDT_RW		0x08
+#define   SMBHST_CTRL_WDT_RW		0x0c
+#define   SMBHST_CTRL_BLK_RW		0x14
+#define   SMBHST_CTRL_MODE_BITS		0x1c
+#define   SMBHST_CTRL_KILL		0x02
+#define   SMBHST_CTRL_IEN		0x01
+
+#define SMBHSTCMD			0x3
+#define SMBHSTADDR			0x4
+#define SMBHSTDAT0			0x5
+#define SMBHSTDAT1			0x6
+#define SMBHSTBLKDAT			0x7
+#define SMBSLVCTRL			0x8
+#define SMBSLVCMD_SHADOW		0x9
+#define SMBSLVEVT			0xa
+#define SMBSLVDAT			0xc
+#define SMBTIMING			0xe
+
 /* FCH MISC Registers 0xfed80e00 */
 #define GPP_CLK_CNTRL			0x00
 #define   GPP_CLK2_REQ_MAP_SHIFT	8
@@ -480,6 +526,8 @@
 uint16_t xhci_pm_read16(uint8_t reg);
 void xhci_pm_write32(uint8_t reg, uint32_t value);
 uint32_t xhci_pm_read32(uint8_t reg);
+void smbus_write8(uint32_t mmio, uint8_t reg, uint8_t value);
+uint8_t smbus_read8(uint32_t mmio, uint8_t reg);
 void bootblock_fch_early_init(void);
 void bootblock_fch_init(void);
 /**
diff --git a/src/soc/amd/stoneyridge/sb_util.c b/src/soc/amd/stoneyridge/sb_util.c
index ccbde7e..eeb550c 100644
--- a/src/soc/amd/stoneyridge/sb_util.c
+++ b/src/soc/amd/stoneyridge/sb_util.c
@@ -200,6 +200,16 @@
 	return read32((void *)(XHCI_ACPI_PM_MMIO_BASE + reg));
 }
 
+void smbus_write8(uint32_t mmio, uint8_t reg, uint8_t value)
+{
+	write8((void *)(mmio + reg), value);
+}
+
+uint8_t smbus_read8(uint32_t mmio, uint8_t reg)
+{
+	return read8((void *)(mmio + reg));
+}
+
 int acpi_get_sleep_type(void)
 {
 	return acpi_sleep_from_pm1(inw(pm_acpi_pm_cnt_blk()));
diff --git a/src/soc/amd/stoneyridge/sm.c b/src/soc/amd/stoneyridge/sm.c
index 22cbde8..82c265e 100644
--- a/src/soc/amd/stoneyridge/sm.c
+++ b/src/soc/amd/stoneyridge/sm.c
@@ -35,60 +35,49 @@
 	setup_ioapic(VIO_APIC_VADDR, CONFIG_MAX_CPUS);
 }
 
-static int lsmbus_recv_byte(struct device *dev)
+static u32 get_sm_mmio(struct device *dev)
 {
-	u8 device;
 	struct resource *res;
 	struct bus *pbus;
 
-	device = dev->path.i2c.device;
 	pbus = get_pbus_smbus(dev);
-
 	res = find_resource(pbus->dev, 0x90);
+	if (res->base == SMB_BASE_ADDR)
+		return SMBUS_MMIO_BASE;
 
-	return do_smbus_recv_byte(res->base, device);
+	return ASF_MMIO_BASE;
+}
+
+static int lsmbus_recv_byte(struct device *dev)
+{
+	u8 device;
+
+	device = dev->path.i2c.device;
+	return do_smbus_recv_byte(get_sm_mmio(dev), device);
 }
 
 static int lsmbus_send_byte(struct device *dev, u8 val)
 {
 	u8 device;
-	struct resource *res;
-	struct bus *pbus;
 
 	device = dev->path.i2c.device;
-	pbus = get_pbus_smbus(dev);
-
-	res = find_resource(pbus->dev, 0x90);
-
-	return do_smbus_send_byte(res->base, device, val);
+	return do_smbus_send_byte(get_sm_mmio(dev), device, val);
 }
 
 static int lsmbus_read_byte(struct device *dev, u8 address)
 {
 	u8 device;
-	struct resource *res;
-	struct bus *pbus;
 
 	device = dev->path.i2c.device;
-	pbus = get_pbus_smbus(dev);
-
-	res = find_resource(pbus->dev, 0x90);
-
-	return do_smbus_read_byte(res->base, device, address);
+	return do_smbus_read_byte(get_sm_mmio(dev), device, address);
 }
 
 static int lsmbus_write_byte(struct device *dev, u8 address, u8 val)
 {
 	u8 device;
-	struct resource *res;
-	struct bus *pbus;
 
 	device = dev->path.i2c.device;
-	pbus = get_pbus_smbus(dev);
-
-	res = find_resource(pbus->dev, 0x90);
-
-	return do_smbus_write_byte(res->base, device, address, val);
+	return do_smbus_write_byte(get_sm_mmio(dev), device, address, val);
 }
 static struct smbus_bus_operations lops_smbus_bus = {
 	.recv_byte = lsmbus_recv_byte,
diff --git a/src/soc/amd/stoneyridge/smbus.c b/src/soc/amd/stoneyridge/smbus.c
index 919a52e..21750d8 100644
--- a/src/soc/amd/stoneyridge/smbus.c
+++ b/src/soc/amd/stoneyridge/smbus.c
@@ -16,143 +16,144 @@
 #include <io.h>
 #include <stdint.h>
 #include <soc/smbus.h>
+#include <soc/southbridge.h>
 
-static int smbus_wait_until_ready(u16 smbus_io_base)
+static int smbus_wait_until_ready(u32 mmio)
 {
 	u32 loops;
 	loops = SMBUS_TIMEOUT;
 	do {
 		u8 val;
-		val = inb(smbus_io_base + SMBHSTSTAT);
+		val = smbus_read8(mmio, SMBHSTSTAT);
 		val &= SMBHST_STAT_VAL_BITS;
 		if (val == 0) {	/* ready now */
 			return 0;
 		}
-		outb(val, smbus_io_base + SMBHSTSTAT);
+		smbus_write8(mmio, SMBHSTSTAT, val);
 	} while (--loops);
 	return -2;		/* time out */
 }
 
-static int smbus_wait_until_done(u16 smbus_io_base)
+static int smbus_wait_until_done(u32 mmio)
 {
 	u32 loops;
 	loops = SMBUS_TIMEOUT;
 	do {
 		u8 val;
 
-		val = inb(smbus_io_base + SMBHSTSTAT);
+		val = smbus_read8(mmio, SMBHSTSTAT);
 		val &= SMBHST_STAT_VAL_BITS;	/* mask off reserved bits */
 		if (val & SMBHST_STAT_ERROR_BITS)
 			return -5;	/* error */
 		if (val == SMBHST_STAT_NOERROR) {
-			outb(val, smbus_io_base + SMBHSTSTAT); /* clear sts */
+			smbus_write8(mmio, SMBHSTSTAT, val); /* clear sts */
 			return 0;
 		}
 	} while (--loops);
 	return -3;		/* timeout */
 }
 
-int do_smbus_recv_byte(u16 smbus_io_base, u8 device)
+int do_smbus_recv_byte(u32 mmio, u8 device)
 {
 	u8 byte;
 
-	if (smbus_wait_until_ready(smbus_io_base) < 0)
+	if (smbus_wait_until_ready(mmio) < 0)
 		return -2;	/* not ready */
 
 	/* set the device I'm talking to */
-	outb(((device & 0x7f) << 1) | 1, smbus_io_base + SMBHSTADDR);
+	smbus_write8(mmio, SMBHSTADDR, ((device & 0x7f) << 1) | 1);
 
-	byte = inb(smbus_io_base + SMBHSTCTRL);
+	byte = smbus_read8(mmio, SMBHSTCTRL);
 	byte &= ~SMBHST_CTRL_MODE_BITS;			/* Clear [4:2] */
 	byte |= SMBHST_CTRL_STRT | SMBHST_CTRL_BTE_RW;	/* set mode, start */
-	outb(byte, smbus_io_base + SMBHSTCTRL);
+	smbus_write8(mmio, SMBHSTCTRL, byte);
 
 	/* poll for transaction completion */
-	if (smbus_wait_until_done(smbus_io_base) < 0)
+	if (smbus_wait_until_done(mmio) < 0)
 		return -3;	/* timeout or error */
 
 	/* read results of transaction */
-	byte = inb(smbus_io_base + SMBHSTDAT0);
+	byte = smbus_read8(mmio, SMBHSTDAT0);
 
 	return byte;
 }
 
-int do_smbus_send_byte(u16 smbus_io_base, u8 device, u8 val)
+int do_smbus_send_byte(u32 mmio, u8 device, u8 val)
 {
 	u8 byte;
 
-	if (smbus_wait_until_ready(smbus_io_base) < 0)
+	if (smbus_wait_until_ready(mmio) < 0)
 		return -2;	/* not ready */
 
 	/* set the command... */
-	outb(val, smbus_io_base + SMBHSTDAT0);
+	smbus_write8(mmio, SMBHSTDAT0, val);
 
 	/* set the device I'm talking to */
-	outb(((device & 0x7f) << 1) | 0, smbus_io_base + SMBHSTADDR);
+	smbus_write8(mmio, SMBHSTADDR, ((device & 0x7f) << 1) | 0);
 
-	byte = inb(smbus_io_base + SMBHSTCTRL);
+	byte = smbus_read8(mmio, SMBHSTCTRL);
 	byte &= ~SMBHST_CTRL_MODE_BITS;			/* Clear [4:2] */
 	byte |= SMBHST_CTRL_STRT | SMBHST_CTRL_BTE_RW;	/* set mode, start */
-	outb(byte, smbus_io_base + SMBHSTCTRL);
+	smbus_write8(mmio, SMBHSTCTRL, byte);
 
 	/* poll for transaction completion */
-	if (smbus_wait_until_done(smbus_io_base) < 0)
+	if (smbus_wait_until_done(mmio) < 0)
 		return -3;	/* timeout or error */
 
 	return 0;
 }
 
-int do_smbus_read_byte(u16 smbus_io_base, u8 device, u8 address)
+int do_smbus_read_byte(u32 mmio, u8 device, u8 address)
 {
 	u8 byte;
 
-	if (smbus_wait_until_ready(smbus_io_base) < 0)
+	if (smbus_wait_until_ready(mmio) < 0)
 		return -2;	/* not ready */
 
 	/* set the command/address... */
-	outb(address & 0xff, smbus_io_base + SMBHSTCMD);
+	smbus_write8(mmio, SMBHSTCMD, address & 0xff);
 
 	/* set the device I'm talking to */
-	outb(((device & 0x7f) << 1) | 1, smbus_io_base + SMBHSTADDR);
+	smbus_write8(mmio, SMBHSTADDR, ((device & 0x7f) << 1) | 1);
 
-	byte = inb(smbus_io_base + SMBHSTCTRL);
+	byte = smbus_read8(mmio, SMBHSTCTRL);
 	byte &= ~SMBHST_CTRL_MODE_BITS;			/* Clear [4:2] */
 	byte |= SMBHST_CTRL_STRT | SMBHST_CTRL_BDT_RW;	/* set mode, start */
-	outb(byte, smbus_io_base + SMBHSTCTRL);
+	smbus_write8(mmio, SMBHSTCTRL, byte);
 
 	/* poll for transaction completion */
-	if (smbus_wait_until_done(smbus_io_base) < 0)
+	if (smbus_wait_until_done(mmio) < 0)
 		return -3;	/* timeout or error */
 
 	/* read results of transaction */
-	byte = inb(smbus_io_base + SMBHSTDAT0);
+	byte = smbus_read8(mmio, SMBHSTDAT0);
 
 	return byte;
 }
 
-int do_smbus_write_byte(u16 smbus_io_base, u8 device, u8 address, u8 val)
+int do_smbus_write_byte(u32 mmio, u8 device, u8 address, u8 val)
 {
 	u8 byte;
 
-	if (smbus_wait_until_ready(smbus_io_base) < 0)
+	if (smbus_wait_until_ready(mmio) < 0)
 		return -2;	/* not ready */
 
 	/* set the command/address... */
-	outb(address & 0xff, smbus_io_base + SMBHSTCMD);
+	smbus_write8(mmio, SMBHSTCMD, address & 0xff);
 
 	/* set the device I'm talking to */
-	outb(((device & 0x7f) << 1) | 0, smbus_io_base + SMBHSTADDR);
+	smbus_write8(mmio, SMBHSTADDR, ((device & 0x7f) << 1) | 0);
 
 	/* output value */
-	outb(val, smbus_io_base + SMBHSTDAT0);
+	smbus_write8(mmio, SMBHSTDAT0, val);
 
-	byte = inb(smbus_io_base + SMBHSTCTRL);
+	byte = smbus_read8(mmio, SMBHSTCTRL);
 	byte &= ~SMBHST_CTRL_MODE_BITS;			/* Clear [4:2] */
 	byte |= SMBHST_CTRL_STRT | SMBHST_CTRL_BDT_RW;	/* set mode, start */
-	outb(byte, smbus_io_base + SMBHSTCTRL);
+	smbus_write8(mmio, SMBHSTCTRL, byte);
 
 	/* poll for transaction completion */
-	if (smbus_wait_until_done(smbus_io_base) < 0)
+	if (smbus_wait_until_done(mmio) < 0)
 		return -3;	/* timeout or error */
 
 	return 0;
diff --git a/src/soc/amd/stoneyridge/smbus_spd.c b/src/soc/amd/stoneyridge/smbus_spd.c
index 384bc8a..63b457c 100644
--- a/src/soc/amd/stoneyridge/smbus_spd.c
+++ b/src/soc/amd/stoneyridge/smbus_spd.c
@@ -27,8 +27,7 @@
  *           sending offset for every byte.
  *          Reads 128 bytes in 7-8 ms at 400 KHz.
  */
-static int readspd(uint16_t iobase, uint8_t SmbusSlaveAddress,
-			char *buffer, size_t count)
+static int readspd(uint8_t SmbusSlaveAddress, char *buffer, size_t count)
 {
 	uint8_t dev_addr;
 	size_t index;
@@ -36,8 +35,8 @@
 	char *pbuf = buffer;
 
 	printk(BIOS_SPEW, "-------------READING SPD-----------\n");
-	printk(BIOS_SPEW, "iobase: 0x%08X, SmbusSlave: 0x%08X, count: %d\n",
-					iobase, SmbusSlaveAddress, (int)count);
+	printk(BIOS_SPEW, "SmbusSlave: 0x%08X, count: %zd\n",
+					SmbusSlaveAddress, count);
 
 	/*
 	 * Convert received device address to the format accepted by
@@ -46,7 +45,7 @@
 	dev_addr = (SmbusSlaveAddress >> 1);
 
 	/* Read the first SPD byte */
-	error = do_smbus_read_byte(iobase, dev_addr, 0);
+	error = do_smbus_read_byte(SMBUS_MMIO_BASE, dev_addr, 0);
 	if (error < 0) {
 		printk(BIOS_ERR, "-------------SPD READ ERROR-----------\n");
 		return error;
@@ -56,7 +55,7 @@
 
 	/* Read the remaining SPD bytes using do_smbus_recv_byte for speed */
 	for (index = 1 ; index < count ; index++) {
-		error = do_smbus_recv_byte(iobase, dev_addr);
+		error = do_smbus_recv_byte(SMBUS_MMIO_BASE, dev_addr);
 		if (error < 0) {
 			printk(BIOS_ERR, "-------------SPD READ ERROR-----------\n");
 			return error;
@@ -70,24 +69,7 @@
 	return 0;
 }
 
-static void write_pm_reg(int reg, int data)
-{
-	outb(reg, PM_INDEX);
-	outb(data, PM_DATA);
-}
-
-static void setup_fch(uint16_t ioBase)
-{
-	write_pm_reg(SMB_ASF_IO_BASE, ioBase >> 8);
-	outb(SMB_SPEED_400KHZ, ioBase + SMBTIMING);
-	/* Clear all SMBUS status bits */
-	outb(SMBHST_STAT_CLEAR, ioBase + SMBHSTSTAT);
-	outb(SMBSLV_STAT_CLEAR, ioBase + SMBSLVSTAT);
-}
-
 int sb_read_spd(uint8_t spdAddress, char *buf, size_t len)
 {
-	uint16_t ioBase = SMB_BASE_ADDR;
-	setup_fch(ioBase);
-	return readspd(ioBase, spdAddress, buf, len);
+	return readspd(spdAddress, buf, len);
 }
diff --git a/src/soc/amd/stoneyridge/southbridge.c b/src/soc/amd/stoneyridge/southbridge.c
index eb41882..c8d66ac 100644
--- a/src/soc/amd/stoneyridge/southbridge.c
+++ b/src/soc/amd/stoneyridge/southbridge.c
@@ -28,6 +28,7 @@
 #include <amdblocks/agesawrapper.h>
 #include <amdblocks/reset.h>
 #include <soc/southbridge.h>
+#include <soc/smbus.h>
 #include <soc/smi.h>
 #include <soc/amd_pci_int_defs.h>
 #include <delay.h>
@@ -619,6 +620,17 @@
 	}
 }
 
+static void fch_smbus_init(void)
+{
+	pm_write8(SMB_ASF_IO_BASE, SMB_BASE_ADDR >> 8);
+	smbus_write8(SMBUS_MMIO_BASE, SMBTIMING, SMB_SPEED_400KHZ);
+	/* Clear all SMBUS status bits */
+	smbus_write8(SMBUS_MMIO_BASE, SMBHSTSTAT, SMBHST_STAT_CLEAR);
+	smbus_write8(SMBUS_MMIO_BASE, SMBSLVSTAT, SMBSLV_STAT_CLEAR);
+	smbus_write8(ASF_MMIO_BASE, SMBHSTSTAT, SMBHST_STAT_CLEAR);
+	smbus_write8(ASF_MMIO_BASE, SMBSLVSTAT, SMBSLV_STAT_CLEAR);
+}
+
 /* Before console init */
 void bootblock_fch_early_init(void)
 {
@@ -631,6 +643,7 @@
 	sb_spibase();
 	sb_disable_4dw_burst(); /* Must be disabled on CZ(ST) */
 	sb_acpi_mmio_decode();
+	fch_smbus_init();
 	sb_enable_cf9_io();
 	setup_spread_spectrum(&reboot);
 	setup_misc(&reboot);