[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