diff options
author | Arthur Heymans <arthur@aheymans.xyz> | 2017-04-12 17:01:31 +0200 |
---|---|---|
committer | Martin Roth <martinroth@google.com> | 2017-08-06 23:26:15 +0000 |
commit | 16fe79048f5254661ff2342aa481cbb44657b7ff (patch) | |
tree | 5ad72bc5c5a97ca9a7a47f5ab24bbe622f12e9e9 | |
parent | 12d010306b3892b01350e96d83275206215d9f31 (diff) |
sb/intel/*: Use common SMBus functions
All Intel southbridges implement the same SMBus functions.
This patch replaces all these similar and mostly identical
implementations with a common file.
This also makes i2c block read available to all those southbridges.
If the northbridge has to read a lot of SPD bytes sequentially, using
this function can reduce the time being spent to read SPD five-fold.
Change-Id: I93bb186e04e8c32dff04fc1abe4b5ecbc4c9c962
Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
Reviewed-on: https://review.coreboot.org/19258
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
68 files changed, 471 insertions, 2162 deletions
diff --git a/src/include/device/smbus_def.h b/src/include/device/smbus_def.h index 971e9756a9..0b07400b37 100644 --- a/src/include/device/smbus_def.h +++ b/src/include/device/smbus_def.h @@ -5,5 +5,6 @@ #define SMBUS_ERROR -1 #define SMBUS_WAIT_UNTIL_READY_TIMEOUT -2 #define SMBUS_WAIT_UNTIL_DONE_TIMEOUT -3 +#define SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT -4 #endif /* DEVICE_SMBUS_DEF_H */ diff --git a/src/northbridge/intel/sandybridge/raminit.c b/src/northbridge/intel/sandybridge/raminit.c index b50555646d..2854a2b0d7 100644 --- a/src/northbridge/intel/sandybridge/raminit.c +++ b/src/northbridge/intel/sandybridge/raminit.c @@ -25,7 +25,7 @@ #include <timestamp.h> #include <northbridge/intel/common/mrc_cache.h> #include <southbridge/intel/bd82x6x/me.h> -#include <southbridge/intel/bd82x6x/smbus.h> +#include <southbridge/intel/common/smbus.h> #include <cpu/x86/msr.h> #include <delay.h> #include <smbios.h> diff --git a/src/southbridge/intel/bd82x6x/Kconfig b/src/southbridge/intel/bd82x6x/Kconfig index 6522cce848..c24c71c30f 100644 --- a/src/southbridge/intel/bd82x6x/Kconfig +++ b/src/southbridge/intel/bd82x6x/Kconfig @@ -25,6 +25,7 @@ config SOUTH_BRIDGE_OPTIONS # dummy def_bool y select ACPI_INTEL_HARDWARE_SLEEP_VALUES select SOUTHBRIDGE_INTEL_COMMON + select SOUTHBRIDGE_INTEL_COMMON_SMBUS select IOAPIC select HAVE_HARD_RESET select HAVE_USBDEBUG_OPTIONS diff --git a/src/southbridge/intel/bd82x6x/early_smbus.c b/src/southbridge/intel/bd82x6x/early_smbus.c index 9f74fdd45f..4c67aea29c 100644 --- a/src/southbridge/intel/bd82x6x/early_smbus.c +++ b/src/southbridge/intel/bd82x6x/early_smbus.c @@ -18,8 +18,8 @@ #include <console/console.h> #include <device/pci_ids.h> #include <device/pci_def.h> +#include <southbridge/intel/common/smbus.h> #include "pch.h" -#include "smbus.h" void enable_smbus(void) { diff --git a/src/southbridge/intel/bd82x6x/pch.h b/src/southbridge/intel/bd82x6x/pch.h index 0ae9826989..dcd7b2e130 100644 --- a/src/southbridge/intel/bd82x6x/pch.h +++ b/src/southbridge/intel/bd82x6x/pch.h @@ -265,22 +265,6 @@ early_usb_init (const struct southbridge_usb_port *portmap); #define SMB_SMI_EN (1 << 1) #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) - - /* Southbridge IO BARs */ #define GPIOBASE 0x48 diff --git a/src/southbridge/intel/bd82x6x/smbus.c b/src/southbridge/intel/bd82x6x/smbus.c index c450d9b555..6cbdef987e 100644 --- a/src/southbridge/intel/bd82x6x/smbus.c +++ b/src/southbridge/intel/bd82x6x/smbus.c @@ -22,8 +22,8 @@ #include <device/pci_ids.h> #include <device/pci_ops.h> #include <arch/io.h> +#include <southbridge/intel/common/smbus.h> #include "pch.h" -#include "smbus.h" static void pch_smbus_init(device_t dev) { @@ -54,49 +54,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 val) { u16 device; diff --git a/src/southbridge/intel/bd82x6x/smbus.h b/src/southbridge/intel/bd82x6x/smbus.h deleted file mode 100644 index 0978963723..0000000000 --- a/src/southbridge/intel/bd82x6x/smbus.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com> - * Copyright (C) 2009 coresystems GmbH - * - * 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 <device/smbus_def.h> -#include "pch.h" - -static void smbus_delay(void) -{ - inb(0x80); -} - -static int smbus_wait_until_ready(u16 smbus_base) -{ - unsigned loops = SMBUS_TIMEOUT; - unsigned char byte; - do { - smbus_delay(); - if (--loops == 0) - break; - byte = inb(smbus_base + SMBHSTSTAT); - } while (byte & 1); - return loops ? 0 : -1; -} - -static int smbus_wait_until_done(u16 smbus_base) -{ - unsigned loops = SMBUS_TIMEOUT; - unsigned char byte; - do { - smbus_delay(); - if (--loops == 0) - break; - byte = inb(smbus_base + SMBHSTSTAT); - } while ((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0); - return loops ? 0 : -1; -} - -static int do_smbus_read_byte(unsigned smbus_base, unsigned device, unsigned address) -{ - unsigned char global_status_register; - unsigned char byte; - - 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) | 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_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 */ - byte = inb(smbus_base + SMBHSTDAT0); - if (global_status_register != (1 << 1)) { - return SMBUS_ERROR; - } - return byte; -} diff --git a/src/southbridge/intel/common/Kconfig b/src/southbridge/intel/common/Kconfig index 7bc686defa..23fb8cea5b 100644 --- a/src/southbridge/intel/common/Kconfig +++ b/src/southbridge/intel/common/Kconfig @@ -2,3 +2,5 @@ config SOUTHBRIDGE_INTEL_COMMON def_bool n config SOUTHBRIDGE_INTEL_COMMON_GPIO def_bool n +config SOUTHBRIDGE_INTEL_COMMON_SMBUS + def_bool n diff --git a/src/southbridge/intel/common/Makefile.inc b/src/southbridge/intel/common/Makefile.inc index 56ba56fc01..5810394bcb 100644 --- a/src/southbridge/intel/common/Makefile.inc +++ b/src/southbridge/intel/common/Makefile.inc @@ -24,4 +24,8 @@ ramstage-$(CONFIG_USBDEBUG) += usb_debug.c romstage-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON_GPIO) += gpio.c ramstage-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON_GPIO) += gpio.c smm-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON_GPIO) += gpio.c + +romstage-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON_SMBUS) += smbus.c +ramstage-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON_SMBUS) += smbus.c + endif diff --git a/src/southbridge/intel/common/smbus.c b/src/southbridge/intel/common/smbus.c new file mode 100644 index 0000000000..cac9ba7943 --- /dev/null +++ b/src/southbridge/intel/common/smbus.c @@ -0,0 +1,365 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com> + * Copyright (C) 2009 coresystems GmbH + * 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. + */ + +#include <arch/io.h> +#include <device/smbus_def.h> +#include "smbus.h" + + +/* I801 command constants */ +#define I801_QUICK (0 << 2) +#define I801_BYTE (1 << 2) +#define I801_BYTE_DATA (2 << 2) +#define I801_WORD_DATA (3 << 2) +#define I801_BLOCK_DATA (5 << 2) +#define I801_I2C_BLOCK_DATA (6 << 2) /* ICH5 and later */ + +/* I801 Host Control register bits */ +#define SMBHSTCNT_INTREN (1 << 0) +#define SMBHSTCNT_KILL (1 << 1) +#define SMBHSTCNT_LAST_BYTE (1 << 5) +#define SMBHSTCNT_START (1 << 6) +#define SMBHSTCNT_PEC_EN (1 << 7) /* ICH3 and later */ + +/* I801 Hosts Status register bits */ +#define SMBHSTSTS_BYTE_DONE (1 << 7) +#define SMBHSTSTS_INUSE_STS (1 << 6) +#define SMBHSTSTS_SMBALERT_STS (1 << 5) +#define SMBHSTSTS_FAILED (1 << 4) +#define SMBHSTSTS_BUS_ERR (1 << 3) +#define SMBHSTSTS_DEV_ERR (1 << 2) +#define SMBHSTSTS_INTR (1 << 1) +#define SMBHSTSTS_HOST_BUSY (1 << 0) + +#define SMBUS_TIMEOUT (10 * 1000 * 100) + +static void smbus_delay(void) +{ + inb(0x80); +} + +static int smbus_wait_until_ready(u16 smbus_base) +{ + unsigned int loops = SMBUS_TIMEOUT; + unsigned char byte; + do { + smbus_delay(); + if (--loops == 0) + break; + byte = inb(smbus_base + SMBHSTSTAT); + } while (byte & SMBHSTSTS_HOST_BUSY); + return loops ? 0 : -1; +} + +static int smbus_wait_until_done(u16 smbus_base) +{ + unsigned int loops = SMBUS_TIMEOUT; + unsigned char byte; + do { + smbus_delay(); + if (--loops == 0) + break; + byte = inb(smbus_base + SMBHSTSTAT); + } while ((byte & SMBHSTSTS_HOST_BUSY) + || (byte & ~(SMBHSTSTS_INUSE_STS | SMBHSTSTS_HOST_BUSY)) == 0); + return loops ? 0 : -1; +} + +static int smbus_wait_until_active(u16 smbus_base) +{ + unsigned long loops; + loops = SMBUS_TIMEOUT; + do { + unsigned char val; + smbus_delay(); + val = inb(smbus_base + SMBHSTSTAT); + if ((val & SMBHSTSTS_HOST_BUSY)) { + break; + } + } while (--loops); + return loops ? 0 : -1; +} + +int do_smbus_read_byte(unsigned int smbus_base, u8 device, + unsigned int address) +{ + unsigned char status; + unsigned char byte; + + if (smbus_wait_until_ready(smbus_base) < 0) + return SMBUS_WAIT_UNTIL_READY_TIMEOUT; + /* Set up transaction */ + /* Disable interrupts */ + outb(inb(smbus_base + SMBHSTCTL) & ~SMBHSTCNT_INTREN, + 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) | I801_BYTE_DATA, + (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) | SMBHSTCNT_START), + smbus_base + SMBHSTCTL); + + /* poll for it to start */ + if (smbus_wait_until_active(smbus_base) < 0) + return SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT; + + /* Poll for transaction completion */ + if (smbus_wait_until_done(smbus_base) < 0) + return SMBUS_WAIT_UNTIL_DONE_TIMEOUT; + + status = inb(smbus_base + SMBHSTSTAT); + + /* Ignore the "In Use" status... */ + status &= ~(SMBHSTSTS_SMBALERT_STS | SMBHSTSTS_INUSE_STS); + + /* Read results of transaction */ + byte = inb(smbus_base + SMBHSTDAT0); + if (status != SMBHSTSTS_INTR) + return SMBUS_ERROR; + return byte; +} + +int do_smbus_write_byte(unsigned int smbus_base, u8 device, + unsigned int address, unsigned int data) +{ + unsigned char status; + + if (smbus_wait_until_ready(smbus_base) < 0) + return SMBUS_WAIT_UNTIL_READY_TIMEOUT; + + /* Set up transaction */ + /* Disable interrupts */ + outb(inb(smbus_base + SMBHSTCTL) & ~SMBHSTCNT_INTREN, + 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) | I801_BYTE_DATA, + (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) | SMBHSTCNT_START), + smbus_base + SMBHSTCTL); + + /* poll for it to start */ + if (smbus_wait_until_active(smbus_base) < 0) + return SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT; + + /* Poll for transaction completion */ + if (smbus_wait_until_done(smbus_base) < 0) + return SMBUS_WAIT_UNTIL_DONE_TIMEOUT; + + status = inb(smbus_base + SMBHSTSTAT); + + /* Ignore the "In Use" status... */ + status &= ~(SMBHSTSTS_SMBALERT_STS | SMBHSTSTS_INUSE_STS); + + /* Read results of transaction */ + if (status != SMBHSTSTS_INTR) + return SMBUS_ERROR; + + return 0; +} + +int do_smbus_block_read(unsigned int smbus_base, u8 device, u8 cmd, + unsigned int bytes, u8 *buf) +{ + u8 status; + int bytes_read = 0; + unsigned int loops = SMBUS_TIMEOUT; + if (smbus_wait_until_ready(smbus_base) < 0) + return SMBUS_WAIT_UNTIL_READY_TIMEOUT; + + /* Set up transaction */ + /* Disable interrupts */ + outb(inb(smbus_base + SMBHSTCTL) & ~SMBHSTCNT_INTREN, + smbus_base + SMBHSTCTL); + /* Set the device I'm talking too */ + outb(((device & 0x7f) << 1) | 1, smbus_base + SMBXMITADD); + /* Set the command/address... */ + outb(cmd & 0xff, smbus_base + SMBHSTCMD); + /* Set up for a block data read */ + outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | I801_BLOCK_DATA, + (smbus_base + SMBHSTCTL)); + /* Clear any lingering errors, so the transaction will run */ + outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT); + + /* Start the command */ + outb((inb(smbus_base + SMBHSTCTL) | SMBHSTCNT_START), + smbus_base + SMBHSTCTL); + + /* poll for it to start */ + if (smbus_wait_until_active(smbus_base) < 0) + return SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT; + + /* Poll for transaction completion */ + do { + loops--; + status = inb(smbus_base + SMBHSTSTAT); + if (status & (SMBHSTSTS_FAILED | /* FAILED */ + SMBHSTSTS_BUS_ERR | /* BUS ERR */ + SMBHSTSTS_DEV_ERR)) /* DEV ERR */ + return SMBUS_ERROR; + + if (status & SMBHSTSTS_BYTE_DONE) { /* Byte done */ + *buf = inb(smbus_base + SMBBLKDAT); + buf++; + bytes_read++; + if (--bytes == 1) { + /* indicate that next byte is the last one */ + outb(inb(smbus_base + SMBHSTCTL) + | SMBHSTCNT_LAST_BYTE, + smbus_base + SMBHSTCTL); + } + outb(status, smbus_base + SMBHSTSTAT); + } + } while ((status & SMBHSTSTS_HOST_BUSY) && loops); + + return bytes_read; +} + +int do_smbus_block_write(unsigned int smbus_base, u8 device, u8 cmd, + unsigned int bytes, const u8 *buf) +{ + u8 status; + unsigned int loops = SMBUS_TIMEOUT; + + if (smbus_wait_until_ready(smbus_base) < 0) + return SMBUS_WAIT_UNTIL_READY_TIMEOUT; + + /* Set up transaction */ + /* Disable interrupts */ + outb(inb(smbus_base + SMBHSTCTL) & ~SMBHSTCNT_INTREN, + smbus_base + SMBHSTCTL); + /* Set the device I'm talking too */ + outb(((device & 0x7f) << 1) & ~0x01, smbus_base + SMBXMITADD); + /* Set the command/address... */ + outb(cmd & 0xff, smbus_base + SMBHSTCMD); + /* Set up for a block data write */ + outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | I801_BLOCK_DATA, + (smbus_base + SMBHSTCTL)); + /* Clear any lingering errors, so the transaction will run */ + outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT); + + /* set number of bytes to transfer */ + outb(bytes, smbus_base + SMBHSTDAT0); + + outb(*buf++, smbus_base + SMBBLKDAT); + bytes--; + + /* Start the command */ + outb((inb(smbus_base + SMBHSTCTL) | SMBHSTCNT_START), + smbus_base + SMBHSTCTL); + + /* poll for it to start */ + if (smbus_wait_until_active(smbus_base) < 0) + return SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT; + + /* Poll for transaction completion */ + do { + loops--; + status = inb(smbus_base + SMBHSTSTAT); + if (status & (SMBHSTSTS_FAILED | /* FAILED */ + SMBHSTSTS_BUS_ERR | /* BUS ERR */ + SMBHSTSTS_DEV_ERR)) /* DEV ERR */ + return SMBUS_ERROR; + + if (status & SMBHSTSTS_BYTE_DONE) { + outb(*buf++, smbus_base + SMBBLKDAT); + outb(status, smbus_base + SMBHSTSTAT); + } + } while ((status & SMBHSTSTS_HOST_BUSY) && loops); + + return 0; +} + +/* Only since ICH5 */ +int do_i2c_block_read(unsigned int smbus_base, u8 device, + unsigned int offset, u32 bytes, u8 *buf) +{ + u8 status; + int bytes_read = 0; + unsigned int loops = SMBUS_TIMEOUT; + if (smbus_wait_until_ready(smbus_base) < 0) + return SMBUS_WAIT_UNTIL_READY_TIMEOUT; + + /* Set upp transaction */ + /* Disable interrupts */ + outb(inb(smbus_base + SMBHSTCTL) & SMBHSTCNT_INTREN, + smbus_base + SMBHSTCTL); + /* Set the device I'm talking to */ + outb((device & 0x7f) << 1, smbus_base + SMBXMITADD); + + /* device offset */ + outb(offset, smbus_base + SMBHSTDAT1); + + /* Set up for a i2c block data read */ + outb((inb(smbus_base + SMBHSTCTL) & 0xc3) | I801_I2C_BLOCK_DATA, + (smbus_base + SMBHSTCTL)); + + /* Clear any lingering errors, so the transaction will run */ + outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT); + /* Start the command */ + outb((inb(smbus_base + SMBHSTCTL) | SMBHSTCNT_START), + smbus_base + SMBHSTCTL); + + /* poll for it to start */ + if (smbus_wait_until_active(smbus_base) < 0) + return SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT; + + /* Poll for transaction completion */ + do { + loops--; + status = inb(smbus_base + SMBHSTSTAT); + if (status & (SMBHSTSTS_FAILED | /* FAILED */ + SMBHSTSTS_BUS_ERR | /* BUS ERR */ + SMBHSTSTS_DEV_ERR)) /* DEV ERR */ + return SMBUS_ERROR; + + if (status & SMBHSTSTS_BYTE_DONE) { + *buf = inb(smbus_base + SMBBLKDAT); + buf++; + bytes_read++; + if (--bytes == 1) { + /* indicate that next byte is the last one */ + outb(inb(smbus_base + SMBHSTCTL) + | SMBHSTCNT_LAST_BYTE, + smbus_base + SMBHSTCTL); + } + outb(status, smbus_base + SMBHSTSTAT); + } + } while ((status & SMBHSTSTS_HOST_BUSY) && loops); + + return bytes_read; +} diff --git a/src/southbridge/intel/common/smbus.h b/src/southbridge/intel/common/smbus.h new file mode 100644 index 0000000000..f2e903c82b --- /dev/null +++ b/src/southbridge/intel/common/smbus.h @@ -0,0 +1,46 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com> + * Copyright (C) 2009 coresystems GmbH + * 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. + */ + +#ifndef INTEL_COMMON_SMBUS_H +#define INTEL_COMMON_SMBUS_H + +/* SMBus register offsets. */ +#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 SMBSLVCMD 0x11 + +int do_smbus_read_byte(unsigned int smbus_base, u8 device, + unsigned int address); +int do_smbus_write_byte(unsigned int smbus_base, u8 device, + unsigned int address, unsigned int data); +int do_smbus_block_read(unsigned int smbus_base, u8 device, + u8 cmd, unsigned int bytes, u8 *buf); +int do_smbus_block_write(unsigned int smbus_base, u8 device, + u8 cmd, unsigned int bytes, const u8 *buf); +/* Only since ICH5 */ +int do_i2c_block_read(unsigned int smbus_base, u8 device, + unsigned int offset, u32 bytes, u8 *buf); +#endif diff --git a/src/southbridge/intel/fsp_bd82x6x/Kconfig b/src/southbridge/intel/fsp_bd82x6x/Kconfig index 516362c773..cebd96d69a 100644 --- a/src/southbridge/intel/fsp_bd82x6x/Kconfig +++ b/src/southbridge/intel/fsp_bd82x6x/Kconfig @@ -31,6 +31,8 @@ config SOUTH_BRIDGE_OPTIONS # dummy select SPI_FLASH select COMMON_FADT select HAVE_INTEL_FIRMWARE + select SOUTHBRIDGE_INTEL_COMMON + select SOUTHBRIDGE_INTEL_COMMON_SMBUS config EHCI_BAR hex diff --git a/src/southbridge/intel/fsp_i89xx/Kconfig b/src/southbridge/intel/fsp_i89xx/Kconfig index 9dfbbf7169..67c2665e66 100644 --- a/src/southbridge/intel/fsp_i89xx/Kconfig +++ b/src/southbridge/intel/fsp_i89xx/Kconfig @@ -32,6 +32,8 @@ config SOUTH_BRIDGE_OPTIONS # dummy select COMMON_FADT select HAVE_INTEL_FIRMWARE select NO_EARLY_BOOTBLOCK_POSTCODES + select SOUTHBRIDGE_INTEL_COMMON + select SOUTHBRIDGE_INTEL_COMMON_SMBUS config EHCI_BAR hex diff --git a/src/southbridge/intel/fsp_i89xx/early_smbus.c b/src/southbridge/intel/fsp_i89xx/early_smbus.c index 0d41d5eaf2..1451179915 100644 --- a/src/southbridge/intel/fsp_i89xx/early_smbus.c +++ b/src/southbridge/intel/fsp_i89xx/early_smbus.c @@ -19,8 +19,8 @@ #include <console/console.h> #include <device/pci_ids.h> #include <device/pci_def.h> +#include <southbridge/intel/common/smbus.h> #include "pch.h" -#include "smbus.h" void enable_smbus(void) { diff --git a/src/southbridge/intel/fsp_i89xx/pch.h b/src/southbridge/intel/fsp_i89xx/pch.h index 9ae9467a7a..447178865c 100644 --- a/src/southbridge/intel/fsp_i89xx/pch.h +++ b/src/southbridge/intel/fsp_i89xx/pch.h @@ -174,22 +174,6 @@ void early_pch_init(void); #define SMB_SMI_EN (1 << 1) #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) - - /* Southbridge IO BARs */ #define GPIOBASE 0x48 diff --git a/src/southbridge/intel/fsp_i89xx/smbus.h b/src/southbridge/intel/fsp_i89xx/smbus.h deleted file mode 100644 index 92b05b78c2..0000000000 --- a/src/southbridge/intel/fsp_i89xx/smbus.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com> - * Copyright (C) 2009 coresystems GmbH - * - * 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 <device/smbus_def.h> -#include "pch.h" -#include <delay.h> - -static int smbus_wait_until_ready(u16 smbus_base) -{ - unsigned loops = SMBUS_TIMEOUT; - unsigned char byte; - do { - udelay(1); - if (--loops == 0) - break; - byte = inb(smbus_base + SMBHSTSTAT); - } while (byte & 1); - return loops ? 0 : -1; -} - -static int smbus_wait_until_done(u16 smbus_base) -{ - unsigned loops = SMBUS_TIMEOUT; - unsigned char byte; - do { - udelay(1); - if (--loops == 0) - break; - byte = inb(smbus_base + SMBHSTSTAT); - } while ((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0); - return loops ? 0 : -1; -} - -static int do_smbus_read_byte(unsigned smbus_base, unsigned device, unsigned address) -{ - unsigned char global_status_register; - unsigned char byte; - - 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) | 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_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 */ - byte = inb(smbus_base + SMBHSTDAT0); - if (global_status_register != (1 << 1)) { - return SMBUS_ERROR; - } - return byte; -} diff --git a/src/southbridge/intel/fsp_rangeley/Kconfig b/src/southbridge/intel/fsp_rangeley/Kconfig index 092cf1dd63..4d2e89f316 100644 --- a/src/southbridge/intel/fsp_rangeley/Kconfig +++ b/src/southbridge/intel/fsp_rangeley/Kconfig @@ -30,6 +30,8 @@ config SOUTH_BRIDGE_OPTIONS # dummy select PCIEXP_COMMON_CLOCK select SPI_FLASH select HAVE_INTEL_FIRMWARE + select SOUTHBRIDGE_INTEL_COMMON + select SOUTHBRIDGE_INTEL_COMMON_SMBUS config EHCI_BAR hex diff --git a/src/southbridge/intel/fsp_rangeley/early_smbus.c b/src/southbridge/intel/fsp_rangeley/early_smbus.c index f27fa87d38..84b750e228 100644 --- a/src/southbridge/intel/fsp_rangeley/early_smbus.c +++ b/src/southbridge/intel/fsp_rangeley/early_smbus.c @@ -18,8 +18,8 @@ #include <console/console.h> #include <device/pci_ids.h> #include <device/pci_def.h> +#include <southbridge/intel/common/smbus.h> #include "soc.h" -#include "smbus.h" void enable_smbus(void) { diff --git a/src/southbridge/intel/fsp_rangeley/smbus.c b/src/southbridge/intel/fsp_rangeley/smbus.c index 9a4d86708c..9ea8126222 100644 --- a/src/southbridge/intel/fsp_rangeley/smbus.c +++ b/src/southbridge/intel/fsp_rangeley/smbus.c @@ -22,8 +22,8 @@ #include <device/pci_ids.h> #include <device/pci_ops.h> #include <arch/io.h> +#include <southbridge/intel/common/smbus.h> #include "soc.h" -#include "smbus.h" static int lsmbus_read_byte(device_t dev, u8 address) { diff --git a/src/southbridge/intel/fsp_rangeley/smbus.h b/src/southbridge/intel/fsp_rangeley/smbus.h deleted file mode 100644 index 39ba6dce16..0000000000 --- a/src/southbridge/intel/fsp_rangeley/smbus.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com> - * Copyright (C) 2009 coresystems GmbH - * - * 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 <device/smbus_def.h> -#include "soc.h" - -static void smbus_delay(void) -{ - inb(0x80); -} - -static int smbus_wait_until_ready(u16 smbus_base) -{ - unsigned loops = SMBUS_TIMEOUT; - unsigned char byte; - do { - smbus_delay(); - if (--loops == 0) - break; - byte = inb(smbus_base + SMBHSTSTAT); - } while (byte & 1); - return loops ? 0 : -1; -} - -static int smbus_wait_until_done(u16 smbus_base) -{ - unsigned loops = SMBUS_TIMEOUT; - unsigned char byte; - do { - smbus_delay(); - if (--loops == 0) - break; - byte = inb(smbus_base + SMBHSTSTAT); - } while ((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0); - return loops ? 0 : -1; -} - -static int do_smbus_read_byte(unsigned smbus_base, unsigned device, unsigned address) -{ - unsigned char global_status_register; - unsigned char byte; - - 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) | 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_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 */ - byte = inb(smbus_base + SMBHSTDAT0); - if (global_status_register != (1 << 1)) { - return SMBUS_ERROR; - } - return byte; -} diff --git a/src/southbridge/intel/fsp_rangeley/soc.h b/src/southbridge/intel/fsp_rangeley/soc.h index 4409f1e5f2..764bf97ca4 100644 --- a/src/southbridge/intel/fsp_rangeley/soc.h +++ b/src/southbridge/intel/fsp_rangeley/soc.h @@ -176,21 +176,6 @@ void rangeley_sb_early_initialization(void); #define SMB_SMI_EN (1 << 1) #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) - /* Root Complex Register Block */ #define RCBA 0xf0 #define RCBA_ENABLE 0x01 diff --git a/src/southbridge/intel/i3100/Kconfig b/src/southbridge/intel/i3100/Kconfig index 1dd0931779..20990ba289 100644 --- a/src/southbridge/intel/i3100/Kconfig +++ b/src/southbridge/intel/i3100/Kconfig @@ -2,6 +2,8 @@ config SOUTHBRIDGE_INTEL_I3100 bool select IOAPIC select HAVE_HARD_RESET + select SOUTHBRIDGE_INTEL_COMMON + select SOUTHBRIDGE_INTEL_COMMON_SMBUS if SOUTHBRIDGE_INTEL_I3100 diff --git a/src/southbridge/intel/i3100/early_smbus.c b/src/southbridge/intel/i3100/early_smbus.c index 35c32a41c1..35fe614d8e 100644 --- a/src/southbridge/intel/i3100/early_smbus.c +++ b/src/southbridge/intel/i3100/early_smbus.c @@ -14,7 +14,7 @@ * */ -#include "smbus.h" +#include <southbridge/intel/common/smbus.h> #define SMBUS_IO_BASE 0x0f00 diff --git a/src/southbridge/intel/i3100/smbus.c b/src/southbridge/intel/i3100/smbus.c index 32cf709b0c..850982adc5 100644 --- a/src/southbridge/intel/i3100/smbus.c +++ b/src/southbridge/intel/i3100/smbus.c @@ -21,8 +21,8 @@ #include <device/pci_ops.h> #include <device/smbus.h> #include <arch/io.h> +#include <southbridge/intel/common/smbus.h> #include "i3100.h" -#include "smbus.h" static int lsmbus_read_byte(device_t dev, u8 address) { diff --git a/src/southbridge/intel/i3100/smbus.h b/src/southbridge/intel/i3100/smbus.h deleted file mode 100644 index 0b2f0601f1..0000000000 --- a/src/southbridge/intel/i3100/smbus.h +++ /dev/null @@ -1,151 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2008 Arastra, Inc. - * - * 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. - */ - -/* This code is based on src/southbridge/intel/esb6300/esb6300_smbus.h */ - -#include <device/smbus_def.h> - -#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 SMBSLVCMD 0x11 - -#define SMBUS_TIMEOUT (100*1000*10) - -static void smbus_delay(void) -{ - outb(0x80, 0x80); -} - -static int smbus_wait_until_ready(u32 smbus_io_base) -{ - u32 loops = SMBUS_TIMEOUT; - u8 byte; - do { - smbus_delay(); - if (--loops == 0) - break; - byte = inb(smbus_io_base + SMBHSTSTAT); - } while (byte & 1); - return loops ? 0 : -1; -} - -static int smbus_wait_until_done(u32 smbus_io_base) -{ - u32 loops = SMBUS_TIMEOUT; - u8 byte; - do { - smbus_delay(); - if (--loops == 0) - break; - byte = inb(smbus_io_base + SMBHSTSTAT); - } while ((byte & 1) || (byte & ~((1 << 6)|(1 << 0))) == 0); - return loops ? 0 : -1; -} - -static int do_smbus_read_byte(u32 smbus_io_base, u16 device, u8 address) -{ - u8 global_status_register; - u8 byte; - - if (smbus_wait_until_ready(smbus_io_base) < 0) { - return SMBUS_WAIT_UNTIL_READY_TIMEOUT; - } - /* setup transaction */ - /* disable interrupts */ - outb(inb(smbus_io_base + SMBHSTCTL) & (~1), smbus_io_base + SMBHSTCTL); - /* set the device I'm talking too */ - outb(((device & 0x7f) << 1) | 1, smbus_io_base + SMBXMITADD); - /* set the command/address... */ - outb(address & 0xFF, smbus_io_base + SMBHSTCMD); - /* set up for a byte data read */ - outb((inb(smbus_io_base + SMBHSTCTL) & 0xE3) | (0x2 << 2), smbus_io_base + SMBHSTCTL); - /* clear any lingering errors, so the transaction will run */ - outb(inb(smbus_io_base + SMBHSTSTAT), smbus_io_base + SMBHSTSTAT); - - /* clear the data byte...*/ - outb(0, smbus_io_base + SMBHSTDAT0); - - /* start the command */ - outb((inb(smbus_io_base + SMBHSTCTL) | 0x40), smbus_io_base + SMBHSTCTL); - - /* poll for transaction completion */ - if (smbus_wait_until_done(smbus_io_base) < 0) { - return SMBUS_WAIT_UNTIL_DONE_TIMEOUT; - } - - global_status_register = inb(smbus_io_base + SMBHSTSTAT); - - /* Ignore the In Use Status... */ - global_status_register &= ~(3 << 5); - - /* read results of transaction */ - byte = inb(smbus_io_base + SMBHSTDAT0); - if (global_status_register != (1 << 1)) { - return SMBUS_ERROR; - } - return byte; -} - -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; -} diff --git a/src/southbridge/intel/i82371eb/Kconfig b/src/southbridge/intel/i82371eb/Kconfig index 5466b12d50..f22c6e90fc 100644 --- a/src/southbridge/intel/i82371eb/Kconfig +++ b/src/southbridge/intel/i82371eb/Kconfig @@ -1,4 +1,6 @@ config SOUTHBRIDGE_INTEL_I82371EB + select SOUTHBRIDGE_INTEL_COMMON + select SOUTHBRIDGE_INTEL_COMMON_SMBUS bool config BOOTBLOCK_SOUTHBRIDGE_INIT diff --git a/src/southbridge/intel/i82371eb/early_smbus.c b/src/southbridge/intel/i82371eb/early_smbus.c index af6b14b643..89ed9c8e57 100644 --- a/src/southbridge/intel/i82371eb/early_smbus.c +++ b/src/southbridge/intel/i82371eb/early_smbus.c @@ -19,8 +19,8 @@ #include <console/console.h> #include <device/pci_ids.h> #include <device/pci_def.h> +#include <southbridge/intel/common/smbus.h> #include "i82371eb.h" -#include "smbus.h" void enable_smbus(void) { @@ -46,7 +46,7 @@ void enable_smbus(void) pci_write_config16(dev, PCI_COMMAND, reg16); /* Clear any lingering errors, so the transaction will run. */ - outb(inb(SMBUS_IO_BASE + SMBHST_STATUS), SMBUS_IO_BASE + SMBHST_STATUS); + outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT); } int smbus_read_byte(u8 device, u8 address) diff --git a/src/southbridge/intel/i82371eb/smbus.c b/src/southbridge/intel/i82371eb/smbus.c index 9231402cd0..3477c52c32 100644 --- a/src/southbridge/intel/i82371eb/smbus.c +++ b/src/southbridge/intel/i82371eb/smbus.c @@ -24,8 +24,8 @@ #include <device/pci.h> #include <device/pci_ids.h> #include <device/smbus.h> +#include <southbridge/intel/common/smbus.h> #include "i82371eb.h" -#include "smbus.h" static void pwrmgt_enable(struct device *dev) { diff --git a/src/southbridge/intel/i82371eb/smbus.h b/src/southbridge/intel/i82371eb/smbus.h deleted file mode 100644 index de34504aff..0000000000 --- a/src/southbridge/intel/i82371eb/smbus.h +++ /dev/null @@ -1,112 +0,0 @@ -#include <device/smbus_def.h> -#include "i82371eb.h" - -#define SMBHST_STATUS 0x0 -#define SMBHST_CTL 0x2 -#define SMBHST_CMD 0x3 -#define SMBHST_ADDR 0x4 -#define SMBHST_DAT 0x5 - -#define SMBUS_TIMEOUT (100*1000*10) -#define SMBUS_STATUS_MASK 0x1e -#define SMBUS_ERROR_FLAG (1<<2) - -int do_smbus_read_byte(unsigned smbus_io_base, unsigned device, unsigned address); - -static inline void smbus_delay(void) -{ - outb(0x80, 0x80); - outb(0x80, 0x80); - outb(0x80, 0x80); - outb(0x80, 0x80); - outb(0x80, 0x80); - outb(0x80, 0x80); -} - -static int smbus_wait_until_ready(unsigned smbus_io_base) -{ - unsigned long loops; - loops = SMBUS_TIMEOUT; - do { - unsigned char val; - smbus_delay(); - val = inb(smbus_io_base + SMBHST_STATUS); - if ((val & 0x1) == 0) { - break; - } -#if 0 - if (loops == (SMBUS_TIMEOUT / 2)) { - outw(inw(smbus_io_base + SMBHST_STATUS), - smbus_io_base + SMBHST_STATUS); - } -#endif - } while (--loops); - return loops?0:SMBUS_WAIT_UNTIL_READY_TIMEOUT; -} - -static int smbus_wait_until_done(unsigned smbus_io_base) -{ - unsigned long loops; - loops = SMBUS_TIMEOUT; - do { - unsigned short val; - smbus_delay(); - - val = inb(smbus_io_base + SMBHST_STATUS); - // Make sure the command is done - if ((val & 0x1) != 0) { - continue; - } - // Don't break out until one of the interrupt - // flags is set. - if (val & 0xfe) { - break; - } - } while (--loops); - return loops?0:SMBUS_WAIT_UNTIL_DONE_TIMEOUT; -} - -int do_smbus_read_byte(unsigned smbus_io_base, unsigned device, unsigned address) -{ - unsigned status_register; - unsigned byte; - - if (smbus_wait_until_ready(smbus_io_base) < 0) { - return SMBUS_WAIT_UNTIL_READY_TIMEOUT; - } - - /* setup transaction */ - - /* clear any lingering errors, so the transaction will run */ - outb(0x1e, smbus_io_base + SMBHST_STATUS); - - /* set the device I'm talking too */ - outb(((device & 0x7f) << 1) | 1, smbus_io_base + SMBHST_ADDR); - - /* set the command/address... */ - outb(address & 0xff, smbus_io_base + SMBHST_CMD); - - /* clear the data word...*/ - outb(0, smbus_io_base + SMBHST_DAT); - - /* start a byte read with interrupts disabled */ - outb( (0x02 << 2)|(1<<6), smbus_io_base + SMBHST_CTL); - - /* poll for transaction completion */ - if (smbus_wait_until_done(smbus_io_base) < 0) { - return SMBUS_WAIT_UNTIL_DONE_TIMEOUT; - } - - status_register = inw(smbus_io_base + SMBHST_STATUS); - - /* read results of transaction */ - byte = inw(smbus_io_base + SMBHST_DAT) & 0xff; - - if (status_register & 0x04) { -#if 0 - printk(BIOS_DEBUG, "Read fail %04x\n", status_register); -#endif - return SMBUS_ERROR; - } - return byte; -} diff --git a/src/southbridge/intel/i82801ax/Kconfig b/src/southbridge/intel/i82801ax/Kconfig index 740c69dd00..cade3f5f82 100644 --- a/src/southbridge/intel/i82801ax/Kconfig +++ b/src/southbridge/intel/i82801ax/Kconfig @@ -18,3 +18,5 @@ config SOUTHBRIDGE_INTEL_I82801AX select IOAPIC select HAVE_HARD_RESET select USE_WATCHDOG_ON_BOOT + select SOUTHBRIDGE_INTEL_COMMON + select SOUTHBRIDGE_INTEL_COMMON_SMBUS diff --git a/src/southbridge/intel/i82801ax/early_smbus.c b/src/southbridge/intel/i82801ax/early_smbus.c index 2a224bffd6..836721b6a8 100644 --- a/src/southbridge/intel/i82801ax/early_smbus.c +++ b/src/southbridge/intel/i82801ax/early_smbus.c @@ -20,8 +20,8 @@ #include <console/console.h> #include <device/pci_ids.h> #include <device/pci_def.h> +#include <southbridge/intel/common/smbus.h> #include "i82801ax.h" -#include "smbus.h" void enable_smbus(void) { diff --git a/src/southbridge/intel/i82801ax/i82801ax.h b/src/southbridge/intel/i82801ax/i82801ax.h index c6e505d25b..879c25a835 100644 --- a/src/southbridge/intel/i82801ax/i82801ax.h +++ b/src/southbridge/intel/i82801ax/i82801ax.h @@ -90,15 +90,4 @@ int smbus_read_byte(u8 device, u8 address); #define SMB_SMI_EN (1 << 1) #define HST_EN (1 << 0) -/* SMBus I/O registers. */ -#define SMBHSTSTAT 0x0 -#define SMBHSTCTL 0x2 -#define SMBHSTCMD 0x3 -#define SMBXMITADD 0x4 -#define SMBHSTDAT0 0x5 -#define SMBHSTDAT1 0x6 -#define SMBBLKDAT 0x7 - -#define SMBUS_TIMEOUT (10 * 1000 * 100) - #endif diff --git a/src/southbridge/intel/i82801ax/smbus.c b/src/southbridge/intel/i82801ax/smbus.c index 54fa34f5a2..1e71a984a8 100644 --- a/src/southbridge/intel/i82801ax/smbus.c +++ b/src/southbridge/intel/i82801ax/smbus.c @@ -19,8 +19,8 @@ #include <device/pci.h> #include <device/pci_ids.h> #include <arch/io.h> +#include <southbridge/intel/common/smbus.h> #include "i82801ax.h" -#include "smbus.h" static int lsmbus_read_byte(device_t dev, u8 address) { diff --git a/src/southbridge/intel/i82801ax/smbus.h b/src/southbridge/intel/i82801ax/smbus.h deleted file mode 100644 index 0ca7d8e282..0000000000 --- a/src/southbridge/intel/i82801ax/smbus.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com> - * - * 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; either version 2 of the License, or - * (at your option) any later version. - * - * 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 <device/smbus_def.h> -#include "i82801ax.h" - -int do_smbus_read_byte(u16 smbus_io_base, u8 device, u8 address); - -static void smbus_delay(void) -{ - inb(0x80); -} - -static int smbus_wait_until_ready(u16 smbus_io_base) -{ - unsigned loops = SMBUS_TIMEOUT; - unsigned char byte; - do { - smbus_delay(); - if (--loops == 0) - break; - byte = inb(smbus_io_base + SMBHSTSTAT); - } while (byte & 1); - return loops ? 0 : -1; -} - -static int smbus_wait_until_done(u16 smbus_io_base) -{ - unsigned loops = SMBUS_TIMEOUT; - unsigned char byte; - do { - smbus_delay(); - if (--loops == 0) - break; - byte = inb(smbus_io_base + SMBHSTSTAT); - } while ((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0); - return loops ? 0 : -1; -} - -int do_smbus_read_byte(u16 smbus_io_base, u8 device, u8 address) -{ - unsigned char global_status_register; - unsigned char byte; - - if (smbus_wait_until_ready(smbus_io_base) < 0) { - return SMBUS_WAIT_UNTIL_READY_TIMEOUT; - } - /* Setup transaction */ - /* Disable interrupts */ - outb(inb(smbus_io_base + SMBHSTCTL) & (~1), smbus_io_base + SMBHSTCTL); - /* Set the device I'm talking too */ - outb(((device & 0x7f) << 1) | 1, smbus_io_base + SMBXMITADD); - /* Set the command/address... */ - outb(address & 0xff, smbus_io_base + SMBHSTCMD); - /* Set up for a byte data read */ - outb((inb(smbus_io_base + SMBHSTCTL) & 0xe3) | (0x2 << 2), - (smbus_io_base + SMBHSTCTL)); - /* Clear any lingering errors, so the transaction will run */ - outb(inb(smbus_io_base + SMBHSTSTAT), smbus_io_base + SMBHSTSTAT); - - /* Clear the data byte... */ - outb(0, smbus_io_base + SMBHSTDAT0); - - /* Start the command */ - outb((inb(smbus_io_base + SMBHSTCTL) | 0x40), - smbus_io_base + SMBHSTCTL); - - /* Poll for transaction completion */ - if (smbus_wait_until_done(smbus_io_base) < 0) { - return SMBUS_WAIT_UNTIL_DONE_TIMEOUT; - } - - global_status_register = inb(smbus_io_base + SMBHSTSTAT); - - /* Ignore the "In Use" status... */ - global_status_register &= ~(3 << 5); - - /* Read results of transaction */ - byte = inb(smbus_io_base + SMBHSTDAT0); - if (global_status_register != (1 << 1)) { - return SMBUS_ERROR; - } - return byte; -} diff --git a/src/southbridge/intel/i82801bx/Kconfig b/src/southbridge/intel/i82801bx/Kconfig index f1423001b9..9d25cbf5da 100644 --- a/src/southbridge/intel/i82801bx/Kconfig +++ b/src/southbridge/intel/i82801bx/Kconfig @@ -18,3 +18,5 @@ config SOUTHBRIDGE_INTEL_I82801BX select IOAPIC select HAVE_HARD_RESET select USE_WATCHDOG_ON_BOOT + select SOUTHBRIDGE_INTEL_COMMON + select SOUTHBRIDGE_INTEL_COMMON_SMBUS diff --git a/src/southbridge/intel/i82801bx/early_smbus.c b/src/southbridge/intel/i82801bx/early_smbus.c index c038e0aba8..103e1a35d4 100644 --- a/src/southbridge/intel/i82801bx/early_smbus.c +++ b/src/southbridge/intel/i82801bx/early_smbus.c @@ -20,8 +20,8 @@ #include <console/console.h> #include <device/pci_ids.h> #include <device/pci_def.h> +#include <southbridge/intel/common/smbus.h> #include "i82801bx.h" -#include "smbus.h" void enable_smbus(void) { diff --git a/src/southbridge/intel/i82801bx/i82801bx.h b/src/southbridge/intel/i82801bx/i82801bx.h index 27888b881f..3ecfe72947 100644 --- a/src/southbridge/intel/i82801bx/i82801bx.h +++ b/src/southbridge/intel/i82801bx/i82801bx.h @@ -99,19 +99,4 @@ int smbus_read_byte(u8 device, u8 address); #define SMB_SMI_EN (1 << 1) #define HST_EN (1 << 0) -/* SMBus I/O registers. */ -#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) - #endif /* SOUTHBRIDGE_INTEL_I82801BX_I82801BX_H */ diff --git a/src/southbridge/intel/i82801bx/smbus.c b/src/southbridge/intel/i82801bx/smbus.c index 6cc05ca5c4..01e8c373e6 100644 --- a/src/southbridge/intel/i82801bx/smbus.c +++ b/src/southbridge/intel/i82801bx/smbus.c @@ -19,8 +19,8 @@ #include <device/pci.h> #include <device/pci_ids.h> #include <arch/io.h> +#include <southbridge/intel/common/smbus.h> #include "i82801bx.h" -#include "smbus.h" static int lsmbus_read_byte(device_t dev, u8 address) { diff --git a/src/southbridge/intel/i82801bx/smbus.h b/src/southbridge/intel/i82801bx/smbus.h deleted file mode 100644 index ffb983ea04..0000000000 --- a/src/southbridge/intel/i82801bx/smbus.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com> - * - * 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; either version 2 of the License, or - * (at your option) any later version. - * - * 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 <device/smbus_def.h> - -static void smbus_delay(void) -{ - inb(0x80); -} - -static int smbus_wait_until_ready(u16 smbus_io_base) -{ - unsigned loops = SMBUS_TIMEOUT; - unsigned char byte; - do { - smbus_delay(); - if (--loops == 0) - break; - byte = inb(smbus_io_base + SMBHSTSTAT); - } while (byte & 1); - return loops ? 0 : -1; -} - -static int smbus_wait_until_done(u16 smbus_io_base) -{ - unsigned loops = SMBUS_TIMEOUT; - unsigned char byte; - do { - smbus_delay(); - if (--loops == 0) - break; - byte = inb(smbus_io_base + SMBHSTSTAT); - } while ((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0); - return loops ? 0 : -1; -} - -static int do_smbus_read_byte(u16 smbus_io_base, u8 device, u8 address) -{ - unsigned char global_status_register; - unsigned char byte; - - if (smbus_wait_until_ready(smbus_io_base) < 0) { - return SMBUS_WAIT_UNTIL_READY_TIMEOUT; - } - /* Setup transaction */ - /* Disable interrupts */ - outb(inb(smbus_io_base + SMBHSTCTL) & (~1), SMBUS_IO_BASE + SMBHSTCTL); - /* Set the device I'm talking too */ - outb(((device & 0x7f) << 1) | 1, smbus_io_base + SMBXMITADD); - /* Set the command/address... */ - outb(address & 0xff, smbus_io_base + SMBHSTCMD); - /* Set up for a byte data read */ - outb((inb(smbus_io_base + SMBHSTCTL) & 0xe3) | (0x2 << 2), - (smbus_io_base + SMBHSTCTL)); - /* Clear any lingering errors, so the transaction will run */ - outb(inb(smbus_io_base + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT); - - /* Clear the data byte... */ - outb(0, smbus_io_base + SMBHSTDAT0); - - /* Start the command */ - outb((inb(smbus_io_base + SMBHSTCTL) | 0x40), - smbus_io_base + SMBHSTCTL); - - /* Poll for transaction completion */ - if (smbus_wait_until_done(smbus_io_base) < 0) { - return SMBUS_WAIT_UNTIL_DONE_TIMEOUT; - } - - global_status_register = inb(smbus_io_base + SMBHSTSTAT); - - /* Ignore the "In Use" status... */ - global_status_register &= ~(3 << 5); - - /* Read results of transaction */ - byte = inb(smbus_io_base + SMBHSTDAT0); - if (global_status_register != (1 << 1)) { - return SMBUS_ERROR; - } - return byte; -} diff --git a/src/southbridge/intel/i82801dx/Kconfig b/src/southbridge/intel/i82801dx/Kconfig index 82db1c3752..35e597acbf 100644 --- a/src/southbridge/intel/i82801dx/Kconfig +++ b/src/southbridge/intel/i82801dx/Kconfig @@ -22,6 +22,8 @@ config SOUTHBRIDGE_INTEL_I82801DX select HAVE_HARD_RESET select HAVE_SMI_HANDLER select HAVE_USBDEBUG + select SOUTHBRIDGE_INTEL_COMMON + select SOUTHBRIDGE_INTEL_COMMON_SMBUS if SOUTHBRIDGE_INTEL_I82801DX diff --git a/src/southbridge/intel/i82801dx/early_smbus.c b/src/southbridge/intel/i82801dx/early_smbus.c index 5bf87d8e91..fabb58b55b 100644 --- a/src/southbridge/intel/i82801dx/early_smbus.c +++ b/src/southbridge/intel/i82801dx/early_smbus.c @@ -17,6 +17,7 @@ #include <arch/io.h> #include <device/pci_def.h> #include <console/console.h> +#include <southbridge/intel/common/smbus.h> #include "i82801dx.h" @@ -37,143 +38,7 @@ void enable_smbus(void) outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT); } -static inline void smbus_delay(void) +int smbus_read_byte(unsigned int device, unsigned int address) { - outb(0x80, 0x80); + return do_smbus_read_byte(SMBUS_IO_BASE, device, address); } - -static int smbus_wait_until_active(void) -{ - unsigned long loops; - loops = SMBUS_TIMEOUT; - do { - unsigned char val; - smbus_delay(); - val = inb(SMBUS_IO_BASE + SMBHSTSTAT); - if ((val & 1)) { - break; - } - } while (--loops); - return loops ? 0 : -4; -} - -static int smbus_wait_until_ready(void) -{ - unsigned long loops; - loops = SMBUS_TIMEOUT; - do { - unsigned char val; - smbus_delay(); - val = inb(SMBUS_IO_BASE + SMBHSTSTAT); - if ((val & 1) == 0) { - break; - } - if (loops == (SMBUS_TIMEOUT / 2)) { - outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), - SMBUS_IO_BASE + SMBHSTSTAT); - } - } while (--loops); - return loops ? 0 : -2; -} - -static int smbus_wait_until_done(void) -{ - unsigned long loops; - loops = SMBUS_TIMEOUT; - do { - unsigned char val; - smbus_delay(); - - val = inb(SMBUS_IO_BASE + SMBHSTSTAT); - if ((val & 1) == 0) { - break; - } - if ((val & ~((1 << 6) | (1 << 0))) != 0) { - break; - } - } while (--loops); - return loops ? 0 : -3; -} - -int smbus_read_byte(unsigned device, unsigned address) -{ - unsigned char global_status_register; - unsigned char byte; - - /* printk(BIOS_ERR, "smbus_read_byte\n"); */ - if (smbus_wait_until_ready() < 0) { - printk(BIOS_ERR, "SMBUS not ready (-2)\n"); - return -2; - } - - /* setup transaction */ - /* disable interrupts */ - outb(inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xfe, SMBUS_IO_BASE + SMBHSTCTL); - /* set the device I'm talking too */ - outb(((device & 0x7f) << 1) | 1, SMBUS_IO_BASE + SMBXMITADD); - /* set the command/address... */ - outb(address & 0xFF, SMBUS_IO_BASE + SMBHSTCMD); - /* set up for a byte data read */ - outb((inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xe3) | (0x2 << 2), - SMBUS_IO_BASE + SMBHSTCTL); - - /* clear any lingering errors, so the transaction will run */ - outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT); - - /* clear the data byte... */ - outb(0, SMBUS_IO_BASE + SMBHSTDAT0); - - /* start a byte read, with interrupts disabled */ - outb((inb(SMBUS_IO_BASE + SMBHSTCTL) | 0x40), - SMBUS_IO_BASE + SMBHSTCTL); - /* poll for it to start */ - if (smbus_wait_until_active() < 0) { - printk(BIOS_ERR, "SMBUS not active (-4)\n"); - return -4; - } - - /* poll for transaction completion */ - if (smbus_wait_until_done() < 0) { - printk(BIOS_ERR, "SMBUS not completed (-3)\n"); - return -3; - } - - global_status_register = inb(SMBUS_IO_BASE + SMBHSTSTAT) & ~(1 << 6); /* Ignore the In Use Status... */ - - /* read results of transaction */ - byte = inb(SMBUS_IO_BASE + SMBHSTDAT0); - - if (global_status_register != 2) { - //printk(BIOS_SPEW, "%s: no device (%02x, %02x)\n", __func__, device, address); - return -1; - } - //printk(BIOS_DEBUG, "%s: %02x@%02x = %02x\n", __func__, device, address, byte); - return byte; -} - -#if 0 -static void smbus_write_byte(unsigned device, unsigned address, - unsigned char val) -{ - if (smbus_wait_until_ready() < 0) { - return; - } - - /* by LYH */ - outb(0x37, SMBUS_IO_BASE + SMBHSTSTAT); - /* set the device I'm talking too */ - outw(((device & 0x7f) << 1) | 0, SMBUS_IO_BASE + SMBHSTADDR); - - /* data to send */ - outb(val, SMBUS_IO_BASE + SMBHSTDAT); - - outb(address & 0xFF, SMBUS_IO_BASE + SMBHSTCMD); - - /* start the command */ - outb(0xa, SMBUS_IO_BASE + SMBHSTCTL); - - /* poll for transaction completion */ - smbus_wait_until_done(); - return; -} -#endif diff --git a/src/southbridge/intel/i82801dx/i82801dx.h b/src/southbridge/intel/i82801dx/i82801dx.h index 3ab0fda8b2..14ca28f9aa 100644 --- a/src/southbridge/intel/i82801dx/i82801dx.h +++ b/src/southbridge/intel/i82801dx/i82801dx.h @@ -116,23 +116,6 @@ int smbus_read_byte(unsigned device, unsigned address); #define SMBUS_IO_BASE 0x1000 -#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 - -/* Between 1-10 seconds, We should never timeout normally - * Longer than this is just painful when a timeout condition occurs. - */ -#define SMBUS_TIMEOUT (100*1000) - #define PM1_STS 0x00 #define WAK_STS (1 << 15) #define PCIEXPWAK_STS (1 << 14) diff --git a/src/southbridge/intel/i82801dx/smbus.c b/src/southbridge/intel/i82801dx/smbus.c deleted file mode 100644 index 441b45a98d..0000000000 --- a/src/southbridge/intel/i82801dx/smbus.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2004 Ronald G. Minnich - * - * 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 "i82801dx.h" -#include <smbus.h> -#include <pci.h> -#include <arch/io.h> - -#define PM_BUS 0 -#define PM_DEVFN PCI_DEVFN(0x1f,3) - -void smbus_enable(void) -{ - unsigned char byte; - /* iobase addr */ - pcibios_write_config_dword(PM_BUS, PM_DEVFN, 0x20, SMBUS_IO_BASE | 1); - /* smbus enable */ - pcibios_write_config_byte(PM_BUS, PM_DEVFN, 0x40, 1); - /* iospace enable */ - pcibios_write_config_word(PM_BUS, PM_DEVFN, 0x4, 1); - - /* Disable interrupt generation */ - outb(0, SMBUS_IO_BASE + SMBHSTCTL); - -} - -void smbus_setup(void) -{ - outb(0, SMBUS_IO_BASE + SMBHSTSTAT); -} - -static void smbus_wait_until_ready(void) -{ - while ((inb(SMBUS_IO_BASE + SMBHSTSTAT) & 1) == 1) { - /* nop */ - } -} - -static void smbus_wait_until_done(void) -{ - unsigned char byte; - do { - byte = inb(SMBUS_IO_BASE + SMBHSTSTAT); - } - while ((byte & 1) == 1); - while ((byte & ~1) == 0) { - byte = inb(SMBUS_IO_BASE + SMBHSTSTAT); - } -} - -int smbus_read_byte(unsigned device, unsigned address, unsigned char *result) -{ - unsigned char host_status_register; - unsigned char byte; - - smbus_wait_until_ready(); - - /* setup transaction */ - /* disable interrupts */ - outb(inb(SMBUS_IO_BASE + SMBHSTCTL) & (~1), SMBUS_IO_BASE + SMBHSTCTL); - /* set the device I'm talking too */ - outb(((device & 0x7f) << 1) | 1, SMBUS_IO_BASE + SMBHSTADD); - /* set the command/address... */ - outb(address & 0xFF, SMBUS_IO_BASE + SMBHSTCMD); - /* set up for a byte data read */ - outb((inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xE3) | (0x2 << 2), - SMBUS_IO_BASE + SMBHSTCTL); - - /* clear any lingering errors, so the transaction will run */ - outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT); - - /* clear the data byte... */ - outb(0, SMBUS_IO_BASE + SMBHSTDAT0); - - /* start the command */ - outb((inb(SMBUS_IO_BASE + SMBHSTCTL) | 0x40), - SMBUS_IO_BASE + SMBHSTCTL); - - /* poll for transaction completion */ - smbus_wait_until_done(); - - host_status_register = inb(SMBUS_IO_BASE + SMBHSTSTAT); - - /* read results of transaction */ - byte = inb(SMBUS_IO_BASE + SMBHSTDAT0); - - *result = byte; - return host_status_register != 0x02; -} diff --git a/src/southbridge/intel/i82801gx/Kconfig b/src/southbridge/intel/i82801gx/Kconfig index b2265c4902..68c236299e 100644 --- a/src/southbridge/intel/i82801gx/Kconfig +++ b/src/southbridge/intel/i82801gx/Kconfig @@ -24,6 +24,7 @@ config SOUTHBRIDGE_INTEL_I82801GX select HAVE_SMI_HANDLER select COMMON_FADT select SOUTHBRIDGE_INTEL_COMMON_GPIO + select SOUTHBRIDGE_INTEL_COMMON_SMBUS if SOUTHBRIDGE_INTEL_I82801GX diff --git a/src/southbridge/intel/i82801gx/early_smbus.c b/src/southbridge/intel/i82801gx/early_smbus.c index b8852e91ab..5d204e9527 100644 --- a/src/southbridge/intel/i82801gx/early_smbus.c +++ b/src/southbridge/intel/i82801gx/early_smbus.c @@ -18,8 +18,8 @@ #include <console/console.h> #include <device/pci_ids.h> #include <device/pci_def.h> +#include <southbridge/intel/common/smbus.h> #include "i82801gx.h" -#include "smbus.h" void enable_smbus(void) { @@ -57,52 +57,5 @@ int smbus_read_byte(unsigned int device, unsigned int address) int i2c_block_read(unsigned int device, unsigned int offset, u32 bytes, u8 *buf) { - u8 status; - int bytes_read = 0; - if (smbus_wait_until_ready(SMBUS_IO_BASE) < 0) - return SMBUS_WAIT_UNTIL_READY_TIMEOUT; - - /* Setup transaction */ - /* Disable interrupts */ - outb(inb(SMBUS_IO_BASE + SMBHSTCTL) & (~1), SMBUS_IO_BASE + SMBHSTCTL); - /* Set the device I'm talking to */ - outb((device & 0x7f) << 1, SMBUS_IO_BASE + SMBXMITADD); - - /* SPD offset */ - outb(offset, SMBUS_IO_BASE + SMBHSTDAT1); - - /* Set up for a i2c block data read */ - outb((inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xc3) | (0x6 << 2), - (SMBUS_IO_BASE + SMBHSTCTL)); - - /* Clear any lingering errors, so the transaction will run */ - outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT); - /* Start the command */ - outb((inb(SMBUS_IO_BASE + SMBHSTCTL) | 0x40), - SMBUS_IO_BASE + SMBHSTCTL); - - while (!(inb(SMBUS_IO_BASE + SMBHSTSTAT) & 1)) - ; - /* Poll for transaction completion */ - do { - status = inb(SMBUS_IO_BASE + SMBHSTSTAT); - if (status & ((1 << 4) | /* FAILED */ - (1 << 3) | /* BUS ERR */ - (1 << 2))) /* DEV ERR */ - return SMBUS_ERROR; - - if (status & 0x80) { /* Byte done */ - *buf = inb(SMBUS_IO_BASE + SMBBLKDAT); - buf++; - bytes_read++; - if (--bytes == 1) { - /* indicate that next byte is the last one */ - outb(inb(SMBUS_IO_BASE + SMBHSTCTL) | 0x20, - SMBUS_IO_BASE + SMBHSTCTL); - } - outb(status, SMBUS_IO_BASE + SMBHSTSTAT); - } - } while (status & 0x01); - - return bytes_read; + return do_i2c_block_read(SMBUS_IO_BASE, device, offset, bytes, buf); } diff --git a/src/southbridge/intel/i82801gx/i82801gx.h b/src/southbridge/intel/i82801gx/i82801gx.h index 0dc4c0b9fd..d1c861ddeb 100644 --- a/src/southbridge/intel/i82801gx/i82801gx.h +++ b/src/southbridge/intel/i82801gx/i82801gx.h @@ -177,22 +177,6 @@ int southbridge_detect_s3_resume(void); #define SMB_SMI_EN (1 << 1) #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) - - /* Southbridge IO BARs */ #define GPIOBASE 0x48 diff --git a/src/southbridge/intel/i82801gx/smbus.c b/src/southbridge/intel/i82801gx/smbus.c index d028f73367..fdf76a03e5 100644 --- a/src/southbridge/intel/i82801gx/smbus.c +++ b/src/southbridge/intel/i82801gx/smbus.c @@ -22,8 +22,8 @@ #include <device/pci_ids.h> #include <device/pci_ops.h> #include <arch/io.h> +#include <southbridge/intel/common/smbus.h> #include "i82801gx.h" -#include "smbus.h" static int lsmbus_read_byte(device_t dev, u8 address) { @@ -38,49 +38,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 int smbus_base, unsigned int device, - unsigned int address, unsigned int 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; @@ -93,58 +50,6 @@ static int lsmbus_write_byte(device_t dev, u8 address, u8 data) return do_smbus_write_byte(res->base, device, address, data); } -static int do_smbus_block_write(unsigned int smbus_base, unsigned int device, - unsigned int cmd, unsigned int bytes, const u8 *buf) -{ - u8 status; - - 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(cmd & 0xff, smbus_base + SMBHSTCMD); - /* Set up for a block data write */ - outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x5 << 2), - (smbus_base + SMBHSTCTL)); - /* Clear any lingering errors, so the transaction will run */ - outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT); - - /* set number of bytes to transfer */ - outb(bytes, smbus_base + SMBHSTDAT0); - - outb(*buf++, smbus_base + SMBBLKDAT); - bytes--; - - /* Start the command */ - outb((inb(smbus_base + SMBHSTCTL) | 0x40), - smbus_base + SMBHSTCTL); - - while (!(inb(smbus_base + SMBHSTSTAT) & 1)) - ; - /* Poll for transaction completion */ - do { - status = inb(smbus_base + SMBHSTSTAT); - if (status & ((1 << 4) | /* FAILED */ - (1 << 3) | /* BUS ERR */ - (1 << 2))) /* DEV ERR */ - return SMBUS_ERROR; - - if (status & 0x80) { /* Byte done */ - outb(*buf++, smbus_base + SMBBLKDAT); - outb(status, smbus_base + SMBHSTSTAT); - } - } while (status & 0x01); - - return 0; -} - - - static int lsmbus_block_write(device_t dev, u8 cmd, u8 bytes, const u8 *buf) { u16 device; @@ -157,57 +62,6 @@ static int lsmbus_block_write(device_t dev, u8 cmd, u8 bytes, const u8 *buf) return do_smbus_block_write(res->base, device, cmd, bytes, buf); } -static int do_smbus_block_read(unsigned int smbus_base, unsigned int device, - unsigned int cmd, unsigned int bytes, u8 *buf) -{ - u8 status; - int bytes_read = 0; - 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) | 1, smbus_base + SMBXMITADD); - /* Set the command/address... */ - outb(cmd & 0xff, smbus_base + SMBHSTCMD); - /* Set up for a block data read */ - outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x5 << 2), - (smbus_base + SMBHSTCTL)); - /* Clear any lingering errors, so the transaction will run */ - outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT); - - /* Start the command */ - outb((inb(smbus_base + SMBHSTCTL) | 0x40), - smbus_base + SMBHSTCTL); - - while (!(inb(smbus_base + SMBHSTSTAT) & 1)) - ; - /* Poll for transaction completion */ - do { - status = inb(smbus_base + SMBHSTSTAT); - if (status & ((1 << 4) | /* FAILED */ - (1 << 3) | /* BUS ERR */ - (1 << 2))) /* DEV ERR */ - return SMBUS_ERROR; - - if (status & 0x80) { /* Byte done */ - *buf = inb(smbus_base + SMBBLKDAT); - buf++; - bytes_read++; - outb(status, smbus_base + SMBHSTSTAT); - if (--bytes == 1) { - /* indicate that next byte is the last one */ - outb(inb(smbus_base + SMBHSTCTL) | 0x20, - smbus_base + SMBHSTCTL); - } - } - } while (status & 0x01); - - return bytes_read; -} - static int lsmbus_block_read(device_t dev, u8 cmd, u8 bytes, u8 *buf) { u16 device; diff --git a/src/southbridge/intel/i82801gx/smbus.h b/src/southbridge/intel/i82801gx/smbus.h deleted file mode 100644 index ff8e1fb112..0000000000 --- a/src/southbridge/intel/i82801gx/smbus.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com> - * Copyright (C) 2009 coresystems GmbH - * - * 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 <device/smbus_def.h> -#include "i82801gx.h" - -static void smbus_delay(void) -{ - inb(0x80); -} - -static int smbus_wait_until_ready(u16 smbus_base) -{ - unsigned int loops = SMBUS_TIMEOUT; - unsigned char byte; - do { - smbus_delay(); - if (--loops == 0) - break; - byte = inb(smbus_base + SMBHSTSTAT); - } while (byte & 1); - return loops ? 0 : -1; -} - -static int smbus_wait_until_done(u16 smbus_base) -{ - unsigned int loops = SMBUS_TIMEOUT; - unsigned char byte; - do { - smbus_delay(); - if (--loops == 0) - break; - byte = inb(smbus_base + SMBHSTSTAT); - } while ((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0); - return loops ? 0 : -1; -} - -static 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_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) | 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_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 */ - byte = inb(smbus_base + SMBHSTDAT0); - if (global_status_register != (1 << 1)) - return SMBUS_ERROR; - return byte; -} diff --git a/src/southbridge/intel/i82801ix/Kconfig b/src/southbridge/intel/i82801ix/Kconfig index e4d1f916f1..6879bce803 100644 --- a/src/southbridge/intel/i82801ix/Kconfig +++ b/src/southbridge/intel/i82801ix/Kconfig @@ -17,6 +17,7 @@ config SOUTHBRIDGE_INTEL_I82801IX bool select SOUTHBRIDGE_INTEL_COMMON + select SOUTHBRIDGE_INTEL_COMMON_SMBUS select IOAPIC select HAVE_USBDEBUG select HAVE_HARD_RESET diff --git a/src/southbridge/intel/i82801ix/early_smbus.c b/src/southbridge/intel/i82801ix/early_smbus.c index 31b33e92d9..0e4195c198 100644 --- a/src/southbridge/intel/i82801ix/early_smbus.c +++ b/src/southbridge/intel/i82801ix/early_smbus.c @@ -19,8 +19,8 @@ #include <console/console.h> #include <device/pci_ids.h> #include <device/pci_def.h> +#include <southbridge/intel/common/smbus.h> #include "i82801ix.h" -#include "smbus.h" void enable_smbus(void) { diff --git a/src/southbridge/intel/i82801ix/i82801ix.h b/src/southbridge/intel/i82801ix/i82801ix.h index af4efcdb30..38dfa385ad 100644 --- a/src/southbridge/intel/i82801ix/i82801ix.h +++ b/src/southbridge/intel/i82801ix/i82801ix.h @@ -154,22 +154,6 @@ #define SMB_SMI_EN (1 << 1) #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) - - #define RCBA8(x) *((volatile u8 *)(DEFAULT_RCBA + x)) #define RCBA16(x) *((volatile u16 *)(DEFAULT_RCBA + x)) #define RCBA32(x) *((volatile u32 *)(DEFAULT_RCBA + x)) diff --git a/src/southbridge/intel/i82801ix/smbus.c b/src/southbridge/intel/i82801ix/smbus.c index 211372237f..ccfcddbec2 100644 --- a/src/southbridge/intel/i82801ix/smbus.c +++ b/src/southbridge/intel/i82801ix/smbus.c @@ -22,7 +22,8 @@ #include <device/pci_ids.h> #include <device/pci_ops.h> #include <arch/io.h> -#include "smbus.h" +#include <southbridge/intel/common/smbus.h> +#include "i82801ix.h" static void pch_smbus_init(device_t dev) { diff --git a/src/southbridge/intel/i82801ix/smbus.h b/src/southbridge/intel/i82801ix/smbus.h deleted file mode 100644 index bcc758700d..0000000000 --- a/src/southbridge/intel/i82801ix/smbus.h +++ /dev/null @@ -1,140 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com> - * Copyright (C) 2009 coresystems GmbH - * - * 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 <device/smbus_def.h> -#include "i82801ix.h" - -static void smbus_delay(void) -{ - inb(0x80); -} - -static int smbus_wait_until_ready(u16 smbus_base) -{ - unsigned loops = SMBUS_TIMEOUT; - unsigned char byte; - do { - smbus_delay(); - if (--loops == 0) - break; - byte = inb(smbus_base + SMBHSTSTAT); - } while (byte & 1); - return loops ? 0 : -1; -} - -static int smbus_wait_until_done(u16 smbus_base) -{ - unsigned loops = SMBUS_TIMEOUT; - unsigned char byte; - do { - smbus_delay(); - if (--loops == 0) - break; - byte = inb(smbus_base + SMBHSTSTAT); - } while ((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0); - return loops ? 0 : -1; -} - -static int do_smbus_read_byte(unsigned smbus_base, unsigned device, unsigned address) -{ - unsigned char global_status_register; - unsigned char byte; - - 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) | 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_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 */ - byte = inb(smbus_base + SMBHSTDAT0); - if (global_status_register != (1 << 1)) { - return SMBUS_ERROR; - } - return byte; -} - -#ifndef __PRE_RAM__ -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; -} -#endif diff --git a/src/southbridge/intel/i82801jx/Kconfig b/src/southbridge/intel/i82801jx/Kconfig index 3f0e5692a0..5edaf1a3ce 100644 --- a/src/southbridge/intel/i82801jx/Kconfig +++ b/src/southbridge/intel/i82801jx/Kconfig @@ -17,6 +17,7 @@ config SOUTHBRIDGE_INTEL_I82801JX bool select SOUTHBRIDGE_INTEL_COMMON + select SOUTHBRIDGE_INTEL_COMMON_SMBUS select IOAPIC select HAVE_USBDEBUG select HAVE_HARD_RESET diff --git a/src/southbridge/intel/i82801jx/early_smbus.c b/src/southbridge/intel/i82801jx/early_smbus.c index fb6c252d39..a95099298f 100644 --- a/src/southbridge/intel/i82801jx/early_smbus.c +++ b/src/southbridge/intel/i82801jx/early_smbus.c @@ -19,8 +19,8 @@ #include <console/console.h> #include <device/pci_ids.h> #include <device/pci_def.h> +#include <southbridge/intel/common/smbus.h> #include "i82801jx.h" -#include "smbus.h" void enable_smbus(void) { diff --git a/src/southbridge/intel/i82801jx/i82801jx.h b/src/southbridge/intel/i82801jx/i82801jx.h index be92a8b58e..fd74d2a02f 100644 --- a/src/southbridge/intel/i82801jx/i82801jx.h +++ b/src/southbridge/intel/i82801jx/i82801jx.h @@ -147,22 +147,6 @@ #define SMB_SMI_EN (1 << 1) #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) - - #define RCBA8(x) *((volatile u8 *)(DEFAULT_RCBA + x)) #define RCBA16(x) *((volatile u16 *)(DEFAULT_RCBA + x)) #define RCBA32(x) *((volatile u32 *)(DEFAULT_RCBA + x)) diff --git a/src/southbridge/intel/i82801jx/smbus.c b/src/southbridge/intel/i82801jx/smbus.c index 00894cf82a..bc735a35b2 100644 --- a/src/southbridge/intel/i82801jx/smbus.c +++ b/src/southbridge/intel/i82801jx/smbus.c @@ -22,7 +22,8 @@ #include <device/pci_ids.h> #include <device/pci_ops.h> #include <arch/io.h> -#include "smbus.h" +#include <southbridge/intel/common/smbus.h> +#include "i82801jx.h" static void pch_smbus_init(device_t dev) { diff --git a/src/southbridge/intel/i82801jx/smbus.h b/src/southbridge/intel/i82801jx/smbus.h deleted file mode 100644 index 61402f77b2..0000000000 --- a/src/southbridge/intel/i82801jx/smbus.h +++ /dev/null @@ -1,140 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com> - * Copyright (C) 2009 coresystems GmbH - * - * 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 <device/smbus_def.h> -#include "i82801jx.h" - -static void smbus_delay(void) -{ - inb(0x80); -} - -static int smbus_wait_until_ready(u16 smbus_base) -{ - unsigned loops = SMBUS_TIMEOUT; - unsigned char byte; - do { - smbus_delay(); - if (--loops == 0) - break; - byte = inb(smbus_base + SMBHSTSTAT); - } while (byte & 1); - return loops ? 0 : -1; -} - -static int smbus_wait_until_done(u16 smbus_base) -{ - unsigned loops = SMBUS_TIMEOUT; - unsigned char byte; - do { - smbus_delay(); - if (--loops == 0) - break; - byte = inb(smbus_base + SMBHSTSTAT); - } while ((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0); - return loops ? 0 : -1; -} - -static int do_smbus_read_byte(unsigned smbus_base, unsigned device, unsigned address) -{ - unsigned char global_status_register; - unsigned char byte; - - 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) | 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_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 */ - byte = inb(smbus_base + SMBHSTDAT0); - if (global_status_register != (1 << 1)) { - return SMBUS_ERROR; - } - return byte; -} - -#ifndef __PRE_RAM__ -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; -} -#endif diff --git a/src/southbridge/intel/ibexpeak/Kconfig b/src/southbridge/intel/ibexpeak/Kconfig index ad32a9bde0..41ace46f7f 100644 --- a/src/southbridge/intel/ibexpeak/Kconfig +++ b/src/southbridge/intel/ibexpeak/Kconfig @@ -30,6 +30,7 @@ config SOUTH_BRIDGE_OPTIONS # dummy select PCIEXP_COMMON_CLOCK select SPI_FLASH select SOUTHBRIDGE_INTEL_COMMON + select SOUTHBRIDGE_INTEL_COMMON_SMBUS select HAVE_USBDEBUG_OPTIONS select COMMON_FADT select ACPI_SATA_GENERATOR diff --git a/src/southbridge/intel/ibexpeak/early_smbus.c b/src/southbridge/intel/ibexpeak/early_smbus.c index f3dab8d00f..b7823ebf59 100644 --- a/src/southbridge/intel/ibexpeak/early_smbus.c +++ b/src/southbridge/intel/ibexpeak/early_smbus.c @@ -18,8 +18,8 @@ #include <console/console.h> #include <device/pci_ids.h> #include <device/pci_def.h> +#include <southbridge/intel/common/smbus.h> #include "pch.h" -#include "smbus.h" void enable_smbus(void) { diff --git a/src/southbridge/intel/ibexpeak/pch.h b/src/southbridge/intel/ibexpeak/pch.h index 63307d9368..1898ae3dba 100644 --- a/src/southbridge/intel/ibexpeak/pch.h +++ b/src/southbridge/intel/ibexpeak/pch.h @@ -233,22 +233,6 @@ void southbridge_configure_default_intmap(void); #define SMB_SMI_EN (1 << 1) #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) - - /* Southbridge IO BARs */ #define GPIOBASE 0x48 diff --git a/src/southbridge/intel/ibexpeak/smbus.c b/src/southbridge/intel/ibexpeak/smbus.c index 3b2f18c08e..aea52de7b5 100644 --- a/src/southbridge/intel/ibexpeak/smbus.c +++ b/src/southbridge/intel/ibexpeak/smbus.c @@ -22,8 +22,8 @@ #include <device/pci_ids.h> #include <device/pci_ops.h> #include <arch/io.h> +#include <southbridge/intel/common/smbus.h> #include "pch.h" -#include "smbus.h" static void pch_smbus_init(device_t dev) { diff --git a/src/southbridge/intel/ibexpeak/smbus.h b/src/southbridge/intel/ibexpeak/smbus.h deleted file mode 100644 index 0815bf4f14..0000000000 --- a/src/southbridge/intel/ibexpeak/smbus.h +++ /dev/null @@ -1,241 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com> - * Copyright (C) 2009 coresystems GmbH - * 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. - */ - -#include <device/smbus_def.h> -#include "pch.h" - -static void smbus_delay(void) -{ - inb(0x80); -} - -static int smbus_wait_until_ready(u16 smbus_base) -{ - unsigned loops = SMBUS_TIMEOUT; - unsigned char byte; - do { - smbus_delay(); - if (--loops == 0) - break; - byte = inb(smbus_base + SMBHSTSTAT); - } while (byte & 1); - return loops ? 0 : -1; -} - -static int smbus_wait_until_done(u16 smbus_base) -{ - unsigned loops = SMBUS_TIMEOUT; - unsigned char byte; - do { - smbus_delay(); - if (--loops == 0) - break; - byte = inb(smbus_base + SMBHSTSTAT); - } while ((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0); - return loops ? 0 : -1; -} - -static int do_smbus_read_byte(unsigned smbus_base, unsigned device, unsigned address) -{ - unsigned char global_status_register; - unsigned char byte; - - 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) | 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_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 */ - byte = inb(smbus_base + SMBHSTDAT0); - if (global_status_register != (1 << 1)) { - return SMBUS_ERROR; - } - return byte; -} - -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; -} - -#ifdef __PRE_RAM__ - -static int do_smbus_block_write(unsigned smbus_base, unsigned device, - unsigned cmd, unsigned bytes, const u8 *buf) -{ - u8 status; - - 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(cmd & 0xff, smbus_base + SMBHSTCMD); - /* Set up for a block data write */ - outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x5 << 2), - (smbus_base + SMBHSTCTL)); - /* Clear any lingering errors, so the transaction will run */ - outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT); - - /* set number of bytes to transfer */ - outb(bytes, smbus_base + SMBHSTDAT0); - - outb(*buf++, smbus_base + SMBBLKDAT); - bytes--; - - /* Start the command */ - outb((inb(smbus_base + SMBHSTCTL) | 0x40), - smbus_base + SMBHSTCTL); - - while (!(inb(smbus_base + SMBHSTSTAT) & 1)); - /* Poll for transaction completion */ - do { - status = inb(smbus_base + SMBHSTSTAT); - if (status & ((1 << 4) | /* FAILED */ - (1 << 3) | /* BUS ERR */ - (1 << 2))) /* DEV ERR */ - return SMBUS_ERROR; - - if (status & 0x80) { /* Byte done */ - outb(*buf++, smbus_base + SMBBLKDAT); - outb(status, smbus_base + SMBHSTSTAT); - } - } while (status & 0x01); - - return 0; -} - -static int do_smbus_block_read(unsigned smbus_base, unsigned device, - unsigned cmd, unsigned bytes, u8 *buf) -{ - u8 status; - int bytes_read = 0; - 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) | 1, smbus_base + SMBXMITADD); - /* Set the command/address... */ - outb(cmd & 0xff, smbus_base + SMBHSTCMD); - /* Set up for a block data read */ - outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x5 << 2), - (smbus_base + SMBHSTCTL)); - /* Clear any lingering errors, so the transaction will run */ - outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT); - - /* Start the command */ - outb((inb(smbus_base + SMBHSTCTL) | 0x40), - smbus_base + SMBHSTCTL); - - while (!(inb(smbus_base + SMBHSTSTAT) & 1)); - /* Poll for transaction completion */ - do { - status = inb(smbus_base + SMBHSTSTAT); - if (status & ((1 << 4) | /* FAILED */ - (1 << 3) | /* BUS ERR */ - (1 << 2))) /* DEV ERR */ - return SMBUS_ERROR; - - if (status & 0x80) { /* Byte done */ - *buf = inb(smbus_base + SMBBLKDAT); - buf++; - bytes_read++; - outb(status, smbus_base + SMBHSTSTAT); - if (--bytes == 1) { - /* indicate that next byte is the last one */ - outb(inb(smbus_base + SMBHSTCTL) | 0x20, - smbus_base + SMBHSTCTL); - } - } - } while (status & 0x01); - - return bytes_read; -} -#endif diff --git a/src/southbridge/intel/lynxpoint/Kconfig b/src/southbridge/intel/lynxpoint/Kconfig index 742f95cbd2..c65e5d7c32 100644 --- a/src/southbridge/intel/lynxpoint/Kconfig +++ b/src/southbridge/intel/lynxpoint/Kconfig @@ -22,6 +22,7 @@ config SOUTH_BRIDGE_OPTIONS # dummy def_bool y select ACPI_INTEL_HARDWARE_SLEEP_VALUES select SOUTHBRIDGE_INTEL_COMMON + select SOUTHBRIDGE_INTEL_COMMON_SMBUS select IOAPIC select HAVE_HARD_RESET select HAVE_USBDEBUG_OPTIONS diff --git a/src/southbridge/intel/lynxpoint/early_smbus.c b/src/southbridge/intel/lynxpoint/early_smbus.c index 2b174c787a..cf3a34c9e5 100644 --- a/src/southbridge/intel/lynxpoint/early_smbus.c +++ b/src/southbridge/intel/lynxpoint/early_smbus.c @@ -18,8 +18,8 @@ #include <console/console.h> #include <device/pci_ids.h> #include <device/pci_def.h> +#include <southbridge/intel/common/smbus.h> #include "pch.h" -#include "smbus.h" void enable_smbus(void) { diff --git a/src/southbridge/intel/lynxpoint/pch.h b/src/southbridge/intel/lynxpoint/pch.h index c9c9c32acd..000f5460ef 100644 --- a/src/southbridge/intel/lynxpoint/pch.h +++ b/src/southbridge/intel/lynxpoint/pch.h @@ -473,22 +473,6 @@ void pch_enable_lpc(void); #define SMB_SMI_EN (1 << 1) #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) - - /* Southbridge IO BARs */ #define GPIOBASE 0x48 diff --git a/src/southbridge/intel/lynxpoint/smbus.c b/src/southbridge/intel/lynxpoint/smbus.c index d81a097fef..ccb5ea08f6 100644 --- a/src/southbridge/intel/lynxpoint/smbus.c +++ b/src/southbridge/intel/lynxpoint/smbus.c @@ -22,8 +22,8 @@ #include <device/pci_ids.h> #include <device/pci_ops.h> #include <arch/io.h> +#include <southbridge/intel/common/smbus.h> #include "pch.h" -#include "smbus.h" static void pch_smbus_init(device_t dev) { @@ -54,54 +54,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) { - printk(BIOS_ERR, "SMBUS transaction timeout\n"); - 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)) { - printk(BIOS_ERR, "SMBUS transaction error\n"); - return SMBUS_ERROR; - } - - return 0; -} - static int lsmbus_write_byte(device_t dev, u8 address, u8 data) { u16 device; diff --git a/src/southbridge/intel/lynxpoint/smbus.h b/src/southbridge/intel/lynxpoint/smbus.h deleted file mode 100644 index 0978963723..0000000000 --- a/src/southbridge/intel/lynxpoint/smbus.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com> - * Copyright (C) 2009 coresystems GmbH - * - * 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 <device/smbus_def.h> -#include "pch.h" - -static void smbus_delay(void) -{ - inb(0x80); -} - -static int smbus_wait_until_ready(u16 smbus_base) -{ - unsigned loops = SMBUS_TIMEOUT; - unsigned char byte; - do { - smbus_delay(); - if (--loops == 0) - break; - byte = inb(smbus_base + SMBHSTSTAT); - } while (byte & 1); - return loops ? 0 : -1; -} - -static int smbus_wait_until_done(u16 smbus_base) -{ - unsigned loops = SMBUS_TIMEOUT; - unsigned char byte; - do { - smbus_delay(); - if (--loops == 0) - break; - byte = inb(smbus_base + SMBHSTSTAT); - } while ((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0); - return loops ? 0 : -1; -} - -static int do_smbus_read_byte(unsigned smbus_base, unsigned device, unsigned address) -{ - unsigned char global_status_register; - unsigned char byte; - - 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) | 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_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 */ - byte = inb(smbus_base + SMBHSTDAT0); - if (global_status_register != (1 << 1)) { - return SMBUS_ERROR; - } - return byte; -} |