[coreboot-gerrit] Patch set updated for coreboot: 93f67af lenovo: Handle EEPROM/RFID chip.
Vladimir Serbinenko (phcoder@gmail.com)
gerrit at coreboot.org
Wed Jan 22 00:46:26 CET 2014
Vladimir Serbinenko (phcoder at gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/4774
-gerrit
commit 93f67af71547c6cb814b1bc9235acdccac4a91ec
Author: Vladimir Serbinenko <phcoder at gmail.com>
Date: Tue Jan 21 11:19:45 2014 +0100
lenovo: Handle EEPROM/RFID chip.
EEPROM/RFID chip present in thinkpad should be locked in a way to avoid
any potential RFID access.
Read serial number, UUID and P/N from EEPROM.
This info is stored on AT24RF08 chip acessible through SMBUS.
Change-Id: Ia3e766d90a094f63c8c854cd37e165221ccd8acd
Signed-off-by: Vladimir Serbinenko <phcoder at gmail.com>
---
src/drivers/i2c/Makefile.inc | 1 +
src/drivers/i2c/lenovo/eeprom.c | 110 +++++++++++++++++++++++++++++++++
src/drivers/i2c/lenovo/eeprom.h | 6 ++
src/include/device/smbus.h | 2 +
src/mainboard/lenovo/t60/mainboard.c | 3 +
src/mainboard/lenovo/x201/mainboard.c | 6 ++
src/mainboard/lenovo/x230/mainboard.c | 5 ++
src/mainboard/lenovo/x60/mainboard.c | 4 ++
src/southbridge/intel/bd82x6x/smbus.c | 16 +++++
src/southbridge/intel/bd82x6x/smbus.h | 43 +++++++++++++
src/southbridge/intel/i82801gx/smbus.c | 57 +++++------------
src/southbridge/intel/i82801gx/smbus.h | 41 ++++++++++++
src/southbridge/intel/ibexpeak/smbus.c | 16 +++++
src/southbridge/intel/ibexpeak/smbus.h | 6 +-
util/inteltool/gpio.c | 5 ++
15 files changed, 276 insertions(+), 45 deletions(-)
diff --git a/src/drivers/i2c/Makefile.inc b/src/drivers/i2c/Makefile.inc
index ef7ac4b..2cd1db0 100644
--- a/src/drivers/i2c/Makefile.inc
+++ b/src/drivers/i2c/Makefile.inc
@@ -7,3 +7,4 @@ subdirs-y += lm63
subdirs-y += rtd2132
subdirs-y += w83795
subdirs-y += w83793
+subdirs-y += lenovo
diff --git a/src/drivers/i2c/lenovo/eeprom.c b/src/drivers/i2c/lenovo/eeprom.c
new file mode 100644
index 0000000..ebaab27
--- /dev/null
+++ b/src/drivers/i2c/lenovo/eeprom.c
@@ -0,0 +1,110 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <types.h>
+#include <string.h>
+#include <arch/io.h>
+#include <device/device.h>
+#include <device/smbus.h>
+#include <smbios.h>
+#include "eeprom.h"
+
+static void smbus_read_string(u8 addr, u8 start, u8 len, char *result)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ int t = smbus_read_byte_main(addr, start + i);
+ if (t < 0x20 || t > 0x7f) {
+ memcpy(result, "*INVALID*", sizeof ("*INVALID*"));
+ return;
+ }
+ result[i] = t;
+ }
+}
+
+const char *smbios_mainboard_serial_number(void)
+{
+ static char result[12];
+ static int already_read;
+
+ if (already_read)
+ return result;
+
+ memset(result, 0, sizeof (result));
+
+ smbus_read_string(0x54, 0x2e, 7, result);
+ already_read = 1;
+ return result;
+}
+
+const char *smbios_mainboard_product_name(void)
+{
+ static char result[12];
+ static int already_read;
+
+ if (already_read)
+ return result;
+ memset (result, 0, sizeof (result));
+
+ smbus_read_string(0x54, 0x27, 7, result);
+
+ already_read = 1;
+ return result;
+}
+
+void smbios_mainboard_set_uuid(u8 *uuid)
+{
+ static char result[16];
+ unsigned i;
+ static int already_read;
+ const int remap[16] = {
+ /* UUID byteswap. */
+ 3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15
+ };
+
+
+ if (already_read) {
+ memcpy (uuid, result, 16);
+ return;
+ }
+
+ memset (result, 0, sizeof (result));
+
+ for (i = 0; i < 16; i++) {
+ int t = smbus_read_byte_main(0x56, 0x12 + i);
+ if (t < 0) {
+ memset (result, 0, sizeof (result));
+ break;
+ }
+ result[remap[i]] = t;
+ }
+
+ already_read = 1;
+
+ memcpy (uuid, result, 16);
+}
+
+/* Ensure that EEPROM/RFID chip is not accessible through RFID. */
+void lenovo_eeprom_lock(void)
+{
+ int i;
+ for (i = 0; i < 8; i++)
+ smbus_write_byte_main(0x5c, i, 0x0f);
+}
diff --git a/src/drivers/i2c/lenovo/eeprom.h b/src/drivers/i2c/lenovo/eeprom.h
new file mode 100644
index 0000000..7fabac0
--- /dev/null
+++ b/src/drivers/i2c/lenovo/eeprom.h
@@ -0,0 +1,6 @@
+#ifndef LENOVO_EEPROM_H
+#define LENOVO_EEPROM_H
+
+void lenovo_eeprom_lock(void);
+
+#endif
diff --git a/src/include/device/smbus.h b/src/include/device/smbus.h
index 073d7e2..f7fba22 100644
--- a/src/include/device/smbus.h
+++ b/src/include/device/smbus.h
@@ -46,5 +46,7 @@ int smbus_write_word(device_t dev, u8 addr, u16 val);
int smbus_process_call(device_t dev, u8 cmd, u16 data);
int smbus_block_read(device_t dev, u8 cmd, u8 bytes, u8 *buffer);
int smbus_block_write(device_t dev, u8 cmd, u8 bytes, const u8 *buffer);
+int smbus_read_byte_main(u8 dev, u8 addr);
+int smbus_write_byte_main(u8 dev, u8 addr, u8 val);
#endif /* DEVICE_SMBUS_H */
diff --git a/src/mainboard/lenovo/t60/mainboard.c b/src/mainboard/lenovo/t60/mainboard.c
index 52f5dcf..66c3764 100644
--- a/src/mainboard/lenovo/t60/mainboard.c
+++ b/src/mainboard/lenovo/t60/mainboard.c
@@ -33,6 +33,7 @@
#include <northbridge/intel/i945/i945.h>
#include <pc80/mc146818rtc.h>
#include <arch/x86/include/arch/acpigen.h>
+#include "drivers/i2c/lenovo/eeprom.h"
static acpi_cstate_t cst_entries[] = {
{ 1, 1, 1000, { 0x7f, 1, 2, { 0 }, 1, 0 } },
@@ -52,6 +53,8 @@ static void mainboard_enable(device_t dev)
device_t dev0, idedev;
u8 defaults_loaded = 0;
+ lenovo_eeprom_lock();
+
/* If we're resuming from suspend, blink suspend LED */
dev0 = dev_find_slot(0, PCI_DEVFN(0,0));
if (dev0 && pci_read_config32(dev0, SKPAD) == SKPAD_ACPI_S3_MAGIC)
diff --git a/src/mainboard/lenovo/x201/mainboard.c b/src/mainboard/lenovo/x201/mainboard.c
index 6321777..1395b06 100644
--- a/src/mainboard/lenovo/x201/mainboard.c
+++ b/src/mainboard/lenovo/x201/mainboard.c
@@ -34,6 +34,7 @@
#include <ec/lenovo/h8/h8.h>
#include <northbridge/intel/nehalem/nehalem.h>
#include <southbridge/intel/bd82x6x/pch.h>
+#include <string.h>
#include <pc80/mc146818rtc.h>
#include "dock.h"
@@ -46,6 +47,7 @@
#include <cpu/x86/lapic.h>
#include <device/pci.h>
#include <smbios.h>
+#include "drivers/i2c/lenovo/eeprom.h"
static acpi_cstate_t cst_entries[] = {
{1, 1, 1000, {0x7f, 1, 2, {0}, 1, 0}},
@@ -89,6 +91,8 @@ static int int15_handler(void)
const char *smbios_mainboard_version(void)
{
+ /* Is available from SMBUS as well but why read it if we know
+ what we'll find? */
return "Lenovo X201";
}
@@ -97,6 +101,8 @@ static void mainboard_enable(device_t dev)
device_t dev0;
u16 pmbase;
+ lenovo_eeprom_lock();
+
printk(BIOS_SPEW, "starting SPI configuration\n");
/* Configure SPI. */
diff --git a/src/mainboard/lenovo/x230/mainboard.c b/src/mainboard/lenovo/x230/mainboard.c
index 91965b6..d32a75d 100644
--- a/src/mainboard/lenovo/x230/mainboard.c
+++ b/src/mainboard/lenovo/x230/mainboard.c
@@ -38,6 +38,7 @@
#include <device/pci.h>
#include <cbfs.h>
#include <pc80/keyboard.h>
+#include "drivers/i2c/lenovo/eeprom.h"
void mainboard_suspend_resume(void)
{
@@ -132,6 +133,8 @@ static int int15_handler(void)
const char *smbios_mainboard_version(void)
{
+ /* Is available from SMBUS as well but why read it if we know
+ what we'll find? */
return "ThinkPad X230";
}
@@ -153,6 +156,8 @@ static void verb_setup(void)
static void mainboard_init(device_t dev)
{
+ lenovo_eeprom_lock();
+
RCBA32(0x38c8) = 0x00002005;
RCBA32(0x38c4) = 0x00802005;
RCBA32(0x38c0) = 0x00000007;
diff --git a/src/mainboard/lenovo/x60/mainboard.c b/src/mainboard/lenovo/x60/mainboard.c
index d1fcb7b..0342580 100644
--- a/src/mainboard/lenovo/x60/mainboard.c
+++ b/src/mainboard/lenovo/x60/mainboard.c
@@ -38,6 +38,8 @@
#include <arch/x86/include/arch/acpigen.h>
#include <smbios.h>
#include <x86emu/x86emu.h>
+#include "drivers/i2c/lenovo/eeprom.h"
+
#define PANEL INT15_5F35_CL_DISPLAY_DEFAULT
int i915lightup(unsigned int physbase, unsigned int iobase, unsigned int mmio,
@@ -90,6 +92,8 @@ static void mainboard_init(device_t dev)
{
device_t dev0, idedev, sdhci_dev;
+ lenovo_eeprom_lock();
+
ec_clr_bit(0x03, 2);
if (inb(0x164c) & 0x08) {
diff --git a/src/southbridge/intel/bd82x6x/smbus.c b/src/southbridge/intel/bd82x6x/smbus.c
index 4786d8b..057160d 100644
--- a/src/southbridge/intel/bd82x6x/smbus.c
+++ b/src/southbridge/intel/bd82x6x/smbus.c
@@ -58,6 +58,22 @@ static int lsmbus_read_byte(device_t dev, u8 address)
return do_smbus_read_byte(res->base, device, address);
}
+int smbus_read_byte_main(u8 dev, u8 addr)
+{
+ device_t controller = dev_find_slot(0, PCI_DEVFN(0x1f, 3));
+ struct resource *res = find_resource(controller, 0x20);
+
+ return do_smbus_read_byte(res->base, dev, addr);
+}
+
+int smbus_write_byte_main(u8 dev, u8 addr, u8 val)
+{
+ device_t controller = dev_find_slot(0, PCI_DEVFN(0x1f, 3));
+ struct resource *res = find_resource(controller, 0x20);
+
+ return do_smbus_write_byte(res->base, dev, addr, val);
+}
+
static struct smbus_bus_operations lops_smbus_bus = {
.read_byte = lsmbus_read_byte,
};
diff --git a/src/southbridge/intel/bd82x6x/smbus.h b/src/southbridge/intel/bd82x6x/smbus.h
index 81e5949..9ea088d 100644
--- a/src/southbridge/intel/bd82x6x/smbus.h
+++ b/src/southbridge/intel/bd82x6x/smbus.h
@@ -98,3 +98,46 @@ static int do_smbus_read_byte(unsigned smbus_base, unsigned device, unsigned add
return byte;
}
+static inline 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/i82801gx/smbus.c b/src/southbridge/intel/i82801gx/smbus.c
index 750da51..790959c 100644
--- a/src/southbridge/intel/i82801gx/smbus.c
+++ b/src/southbridge/intel/i82801gx/smbus.c
@@ -42,48 +42,6 @@ static int lsmbus_read_byte(device_t dev, u8 address)
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 data)
{
u16 device;
@@ -221,6 +179,21 @@ static int lsmbus_block_read(device_t dev, u8 cmd, u8 bytes, u8 *buf)
return do_smbus_block_read(res->base, device, cmd, bytes, buf);
}
+int smbus_read_byte_main(u8 dev, u8 addr)
+{
+ device_t controller = dev_find_slot(0, PCI_DEVFN(0x1f, 3));
+ struct resource *res = find_resource(controller, 0x20);
+
+ return do_smbus_read_byte(res->base, dev, addr);
+}
+
+int smbus_write_byte_main(u8 dev, u8 addr, u8 val)
+{
+ device_t controller = dev_find_slot(0, PCI_DEVFN(0x1f, 3));
+ struct resource *res = find_resource(controller, 0x20);
+
+ return do_smbus_write_byte(res->base, dev, addr, val);
+}
static struct smbus_bus_operations lops_smbus_bus = {
.read_byte = lsmbus_read_byte,
diff --git a/src/southbridge/intel/i82801gx/smbus.h b/src/southbridge/intel/i82801gx/smbus.h
index 23b46ce..197727e 100644
--- a/src/southbridge/intel/i82801gx/smbus.h
+++ b/src/southbridge/intel/i82801gx/smbus.h
@@ -98,3 +98,44 @@ static int do_smbus_read_byte(unsigned smbus_base, unsigned device, unsigned add
return byte;
}
+static inline 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/ibexpeak/smbus.c b/src/southbridge/intel/ibexpeak/smbus.c
index ad7c8f9..01cdd7f 100644
--- a/src/southbridge/intel/ibexpeak/smbus.c
+++ b/src/southbridge/intel/ibexpeak/smbus.c
@@ -62,6 +62,22 @@ static struct smbus_bus_operations lops_smbus_bus = {
.read_byte = lsmbus_read_byte,
};
+int smbus_read_byte_main(u8 dev, u8 addr)
+{
+ device_t controller = dev_find_slot(0, PCI_DEVFN(0x1f, 3));
+ struct resource *res = find_resource(controller, 0x20);
+
+ return do_smbus_read_byte(res->base, dev, addr);
+}
+
+int smbus_write_byte_main(u8 dev, u8 addr, u8 val)
+{
+ device_t controller = dev_find_slot(0, PCI_DEVFN(0x1f, 3));
+ struct resource *res = find_resource(controller, 0x20);
+
+ return do_smbus_write_byte(res->base, dev, addr, val);
+}
+
static void smbus_set_subsystem(device_t dev, unsigned vendor, unsigned device)
{
if (!vendor || !device) {
diff --git a/src/southbridge/intel/ibexpeak/smbus.h b/src/southbridge/intel/ibexpeak/smbus.h
index 6858e7d..5e03ada 100644
--- a/src/southbridge/intel/ibexpeak/smbus.h
+++ b/src/southbridge/intel/ibexpeak/smbus.h
@@ -99,9 +99,7 @@ static int do_smbus_read_byte(unsigned smbus_base, unsigned device, unsigned add
return byte;
}
-#ifdef __PRE_RAM__
-
-static int do_smbus_write_byte(unsigned smbus_base, unsigned device, unsigned address, unsigned data)
+static inline int do_smbus_write_byte(unsigned smbus_base, unsigned device, unsigned address, unsigned data)
{
unsigned char global_status_register;
@@ -144,6 +142,8 @@ static int do_smbus_write_byte(unsigned smbus_base, unsigned device, unsigned a
return 0;
}
+#ifdef __PRE_RAM__
+
static int do_smbus_block_write(unsigned smbus_base, unsigned device,
unsigned cmd, unsigned bytes, const u8 *buf)
{
diff --git a/util/inteltool/gpio.c b/util/inteltool/gpio.c
index 42e7272..15019ab 100644
--- a/util/inteltool/gpio.c
+++ b/util/inteltool/gpio.c
@@ -558,6 +558,11 @@ int print_gpios(struct pci_dev *sb, int show_all, int show_diffs)
printf("GPIOBASE = 0x%04x (IO)\n\n", gpiobase);
+ outw(inw (gpiobase +0x30) | 0x400, gpiobase + 0x30);
+ outw(inw (gpiobase +0x34) & ~0x400, gpiobase + 0x34);
+
+ outw(inw (gpiobase +0x38) | 0x400, gpiobase + 0x38);
+
j = 0;
for (i = 0; i < size; i++) {
if (show_all)
More information about the coreboot-gerrit
mailing list