[coreboot-gerrit] Change in coreboot[master]: soc/intel/common/block: [WIP]Add Intel common smbus code

Aamir Bohra (Code Review) gerrit at coreboot.org
Wed Apr 19 19:14:42 CEST 2017


Aamir Bohra has uploaded a new change for review. ( https://review.coreboot.org/19372 )

Change subject: soc/intel/common/block: [WIP]Add Intel common smbus code
......................................................................

soc/intel/common/block: [WIP]Add Intel common smbus code

Add below code support under intel/common/block:

*Smbus read/write byte APIs
*Common smbus initialization code

Change-Id: I936143a334c31937d557c6828e5876d35b133567
Signed-off-by: Aamir Bohra <aamir.bohra at intel.com>
---
A src/soc/intel/common/block/include/intelblocks/smbus.h
A src/soc/intel/common/block/smbus/Kconfig
A src/soc/intel/common/block/smbus/Makefile.inc
A src/soc/intel/common/block/smbus/smbus.c
4 files changed, 230 insertions(+), 0 deletions(-)


  git pull ssh://review.coreboot.org:29418/coreboot refs/changes/72/19372/1

diff --git a/src/soc/intel/common/block/include/intelblocks/smbus.h b/src/soc/intel/common/block/include/intelblocks/smbus.h
new file mode 100644
index 0000000..5464338
--- /dev/null
+++ b/src/soc/intel/common/block/include/intelblocks/smbus.h
@@ -0,0 +1,25 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2017 Intel Corporation.
+ *
+ * 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 SOC_INTEL_COMMON_BLOCK_SMBUS_H
+#define SOC_INTEL_COMMON_BLOCK_SMBUS_H
+
+void enable_smbus(void);
+int do_smbus_read_byte(unsigned int smbus_base, unsigned int device,
+		       unsigned int address);
+int do_smbus_write_byte(unsigned int smbus_base, unsigned int device,
+			unsigned int address, unsigned int data);
+
+#endif	/* SOC_INTEL_COMMON_BLOCK_SMBUS_H */
diff --git a/src/soc/intel/common/block/smbus/Kconfig b/src/soc/intel/common/block/smbus/Kconfig
new file mode 100644
index 0000000..be68025
--- /dev/null
+++ b/src/soc/intel/common/block/smbus/Kconfig
@@ -0,0 +1,4 @@
+config SOC_INTEL_COMMON_BLOCK_SMBUS
+	bool
+	help
+	  Intel Processor common SMBUS support
diff --git a/src/soc/intel/common/block/smbus/Makefile.inc b/src/soc/intel/common/block/smbus/Makefile.inc
new file mode 100644
index 0000000..9a7bec4
--- /dev/null
+++ b/src/soc/intel/common/block/smbus/Makefile.inc
@@ -0,0 +1,3 @@
+bootblock-$(CONFIG_SOC_INTEL_COMMON_BLOCK_SMBUS) += smbus.c
+ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_SMBUS) += smbus.c
+romstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_SMBUS) += smbus.c
diff --git a/src/soc/intel/common/block/smbus/smbus.c b/src/soc/intel/common/block/smbus/smbus.c
new file mode 100644
index 0000000..44ad1f9
--- /dev/null
+++ b/src/soc/intel/common/block/smbus/smbus.c
@@ -0,0 +1,198 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2017 Intel Corporation.
+ *
+ * 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 <device/pci_def.h>
+#include <device/early_smbus.h>
+#include <intelblocks/smbus.h>
+#include <reg_script.h>
+#include <soc/pci_devs.h>
+
+/* SMBUS IO Base */
+#define SMBUS_IO_BASE	0xefa0
+
+/* PCI Configuration Space : SMBus */
+#define SMB_BASE	0x20
+#define HOSTC	0x40
+#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)
+
+static const struct reg_script smbus_init_script[] = {
+	/* Set SMBUS I/O base address */
+	REG_PCI_WRITE32(SMB_BASE, SMBUS_IO_BASE | 1),
+	/* Set SMBUS enable */
+	REG_PCI_WRITE8(HOSTC, HST_EN),
+	/* Enable I/O access */
+	REG_PCI_WRITE16(PCI_COMMAND, PCI_COMMAND_IO),
+	/* Disable interrupts */
+	REG_IO_WRITE8(SMBUS_IO_BASE + SMBHSTCTL, 0),
+	/* Clear errors */
+	REG_IO_WRITE8(SMBUS_IO_BASE + SMBHSTSTAT, 0xff),
+	/* Indicate the end of this array by REG_SCRIPT_END */
+	REG_SCRIPT_END,
+};
+
+static void delay_smbus(void)
+{
+	inb(0x80);
+}
+
+static int smbus_wait_till_ready(u16 smbus_base)
+{
+	unsigned int loops = SMBUS_TIMEOUT;
+	unsigned char byte;
+	do {
+		delay_smbus();
+		if (--loops == 0)
+			break;
+		byte = inb(smbus_base + SMBHSTSTAT);
+	} while (byte & 1);
+	return loops ? 0 : -1;
+}
+
+static int smbus_wait_till_done(u16 smbus_base)
+{
+	unsigned int loops = SMBUS_TIMEOUT;
+	unsigned char byte;
+	do {
+		delay_smbus();
+		if (--loops == 0)
+			break;
+		byte = inb(smbus_base + SMBHSTSTAT);
+	} while ((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0);
+	return loops ? 0 : -1;
+}
+
+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_till_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_till_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;
+}
+
+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_till_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_till_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;
+}
+
+void enable_smbus(void)
+{
+	reg_script_run_on_dev(PCH_DEV_SMBUS, smbus_init_script);
+}
+
+#if !ENV_RAMSTAGE
+
+u8 smbus_read_byte(u32 smbus_dev, u8 addr, u8 offset)
+{
+	return do_smbus_read_byte(SMBUS_IO_BASE, addr, offset);
+}
+
+u8 smbus_write_byte(u32 smbus_dev, u8 addr, u8 offset, u8 value)
+{
+	return do_smbus_write_byte(SMBUS_IO_BASE, addr, offset, value);
+}
+#endif

-- 
To view, visit https://review.coreboot.org/19372
To unsubscribe, visit https://review.coreboot.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I936143a334c31937d557c6828e5876d35b133567
Gerrit-PatchSet: 1
Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Owner: Aamir Bohra <aamir.bohra at intel.com>



More information about the coreboot-gerrit mailing list