Vladimir Serbinenko (phcoder@gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/4774
-gerrit
commit 2a4aff72571df8e7c029f1ce67bbd92ecfc671af Author: Vladimir Serbinenko phcoder@gmail.com Date: Tue Jan 21 23:13:13 2014 +0100
lenovo: Handle EEPROM/RFID chip.
Change-Id: Ia3e766d90a094f63c8c854cd37e165221ccd8acd Signed-off-by: Vladimir Serbinenko phcoder@gmail.com --- src/drivers/i2c/lenovo/eeprom.c | 118 +++++++++++++++++++++++++++++++++ src/drivers/i2c/lenovo/eeprom.h | 6 ++ src/mainboard/lenovo/t60/Makefile.inc | 1 + src/mainboard/lenovo/t60/mainboard.c | 2 + src/mainboard/lenovo/x201/Makefile.inc | 1 + src/mainboard/lenovo/x201/mainboard.c | 79 +--------------------- src/mainboard/lenovo/x230/Makefile.inc | 1 + src/mainboard/lenovo/x230/mainboard.c | 80 +--------------------- src/mainboard/lenovo/x60/Makefile.inc | 1 + src/mainboard/lenovo/x60/mainboard.c | 4 ++ src/southbridge/intel/bd82x6x/smbus.h | 43 ++++++++++++ src/southbridge/intel/ibexpeak/smbus.h | 4 +- util/inteltool/gpio.c | 5 ++ 13 files changed, 190 insertions(+), 155 deletions(-)
diff --git a/src/drivers/i2c/lenovo/eeprom.c b/src/drivers/i2c/lenovo/eeprom.c new file mode 100644 index 0000000..299d641 --- /dev/null +++ b/src/drivers/i2c/lenovo/eeprom.c @@ -0,0 +1,118 @@ +/* + * 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> +#if IS_ENABLED(CONFIG_SOUTHBRIDGE_INTEL_IBEXPEAK) +#include <southbridge/intel/ibexpeak/smbus.h> +#elif IS_ENABLED(CONFIG_SOUTHBRIDGE_INTEL_C216) +#include <southbridge/intel/bd82x6x/smbus.h> +#elif IS_ENABLED(CONFIG_SOUTHBRIDGE_INTEL_I82801GX) +#include <southbridge/intel/i82801gx/smbus.h> +#else +#error "Complete this!" +#endif +#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 = do_smbus_read_byte(SMBUS_IO_BASE, 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 = do_smbus_read_byte(SMBUS_IO_BASE, 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++) + do_smbus_write_byte(SMBUS_IO_BASE, 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/mainboard/lenovo/t60/Makefile.inc b/src/mainboard/lenovo/t60/Makefile.inc index 5e09e99..187e2b3 100644 --- a/src/mainboard/lenovo/t60/Makefile.inc +++ b/src/mainboard/lenovo/t60/Makefile.inc @@ -19,3 +19,4 @@
smm-$(CONFIG_HAVE_SMI_HANDLER) += dock.c romstage-y += dock.c +ramstage-y += ../../../drivers/i2c/lenovo/eeprom.c diff --git a/src/mainboard/lenovo/t60/mainboard.c b/src/mainboard/lenovo/t60/mainboard.c index 52f5dcf..246c4eb 100644 --- a/src/mainboard/lenovo/t60/mainboard.c +++ b/src/mainboard/lenovo/t60/mainboard.c @@ -52,6 +52,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/Makefile.inc b/src/mainboard/lenovo/x201/Makefile.inc index 285e0d0..fae825d 100644 --- a/src/mainboard/lenovo/x201/Makefile.inc +++ b/src/mainboard/lenovo/x201/Makefile.inc @@ -22,4 +22,5 @@ smm-$(CONFIG_HAVE_SMI_HANDLER) += smihandler.c romstage-y += dock.c ramstage-y += dock.c ramstage-y += gma.c +ramstage-y += ../../../drivers/i2c/lenovo/eeprom.c
diff --git a/src/mainboard/lenovo/x201/mainboard.c b/src/mainboard/lenovo/x201/mainboard.c index 7562e36..63557b6 100644 --- a/src/mainboard/lenovo/x201/mainboard.c +++ b/src/mainboard/lenovo/x201/mainboard.c @@ -48,6 +48,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}}, @@ -96,87 +97,13 @@ const char *smbios_mainboard_version(void) return "Lenovo X201"; }
-static void smbus_read_string(u8 addr, u8 start, u8 len, char *result) -{ - int i; - - for (i = 0; i < len; i++) { - int t = do_smbus_read_byte(SMBUS_IO_BASE, 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 = do_smbus_read_byte(SMBUS_IO_BASE, 0x56, 0x12 + i); - if (t < 0) { - memset (result, 0, sizeof (result)); - break; - } - result[remap[i]] = t; - } - - already_read = 1; - - memcpy (uuid, result, 16); -} - 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/Makefile.inc b/src/mainboard/lenovo/x230/Makefile.inc index d514d4b..84b9835 100644 --- a/src/mainboard/lenovo/x230/Makefile.inc +++ b/src/mainboard/lenovo/x230/Makefile.inc @@ -18,3 +18,4 @@ ##
smm-$(CONFIG_HAVE_SMI_HANDLER) += smihandler.c +ramstage-y += ../../../drivers/i2c/lenovo/eeprom.c diff --git a/src/mainboard/lenovo/x230/mainboard.c b/src/mainboard/lenovo/x230/mainboard.c index 22afce4..d32a75d 100644 --- a/src/mainboard/lenovo/x230/mainboard.c +++ b/src/mainboard/lenovo/x230/mainboard.c @@ -34,11 +34,11 @@ #include <boot/coreboot_tables.h> #include "hda_verb.h" #include <southbridge/intel/bd82x6x/pch.h> -#include <southbridge/intel/bd82x6x/smbus.h> #include <smbios.h> #include <device/pci.h> #include <cbfs.h> #include <pc80/keyboard.h> +#include "drivers/i2c/lenovo/eeprom.h"
void mainboard_suspend_resume(void) { @@ -138,82 +138,6 @@ const char *smbios_mainboard_version(void) return "ThinkPad X230"; }
-static void smbus_read_string(u8 addr, u8 start, u8 len, char *result) -{ - int i; - - for (i = 0; i < len; i++) { - int t = do_smbus_read_byte(SMBUS_IO_BASE, 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 = do_smbus_read_byte(SMBUS_IO_BASE, 0x56, 0x12 + i); - if (t < 0) { - memset (result, 0, sizeof (result)); - break; - } - result[remap[i]] = t; - } - - already_read = 1; - - memcpy (uuid, result, 16); -} - /* Audio Setup */
extern const u32 *cim_verb_data; @@ -232,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/Makefile.inc b/src/mainboard/lenovo/x60/Makefile.inc index ecb7ce5..7147af2 100644 --- a/src/mainboard/lenovo/x60/Makefile.inc +++ b/src/mainboard/lenovo/x60/Makefile.inc @@ -23,3 +23,4 @@ ramstage-y += dock.c ramstage-$(CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT) += i915.c ramstage-$(CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT) += i915io.c ramstage-$(CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT) += intel_dp.c +ramstage-y += ../../../drivers/i2c/lenovo/eeprom.c 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.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/ibexpeak/smbus.h b/src/southbridge/intel/ibexpeak/smbus.h index 6858e7d..cf57685 100644 --- a/src/southbridge/intel/ibexpeak/smbus.h +++ b/src/southbridge/intel/ibexpeak/smbus.h @@ -99,8 +99,6 @@ 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) { 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)