Oskar Enoksson (enok@lysator.liu.se) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/281
-gerrit
commit ca2c760ba546f6c16f0468ca989898d992bc230d Author: Oskar Enoksson enok@lysator.liu.se Date: Fri Oct 14 02:16:48 2011 +0200
Added smbus block operations for amd8111
Also fixed bug in one function prototype: smbus_block_read should pass pointer to block length, not value. At least it makes no sense to me to pass a value(?)
Signed-off-by: Oskar Enoksson enok@lysator.liu.se Change-Id: I86c80a27fd13c9a2be4034fdfb63be4ab2fadbfc --- src/devices/smbus_ops.c | 2 +- src/include/device/smbus.h | 4 +- src/southbridge/amd/amd8111/acpi.c | 25 +++++++ src/southbridge/amd/amd8111/amd8111_smbus.h | 98 +++++++++++++++++++++++++++ src/southbridge/amd/amd8111/early_smbus.c | 9 +++ 5 files changed, 135 insertions(+), 3 deletions(-)
diff --git a/src/devices/smbus_ops.c b/src/devices/smbus_ops.c index 75ca42b..d0e226f 100644 --- a/src/devices/smbus_ops.c +++ b/src/devices/smbus_ops.c @@ -124,7 +124,7 @@ int smbus_process_call(device_t dev, u8 cmd, u16 data) return ops_smbus_bus(get_pbus_smbus(dev))->process_call(dev, cmd, data); }
-int smbus_block_read(device_t dev, u8 cmd, u8 bytes, u8 *buffer) +int smbus_block_read(device_t dev, u8 cmd, u8 *bytes, u8 *buffer) { return ops_smbus_bus(get_pbus_smbus(dev))->block_read(dev, cmd, bytes, buffer); diff --git a/src/include/device/smbus.h b/src/include/device/smbus.h index 073d7e2..bd8f8ce 100644 --- a/src/include/device/smbus.h +++ b/src/include/device/smbus.h @@ -17,7 +17,7 @@ struct smbus_bus_operations { int (*read_word) (device_t dev, u8 addr); int (*write_word) (device_t dev, u8 addr, u16 value); int (*process_call)(device_t dev, u8 cmd, u16 data); - int (*block_read) (device_t dev, u8 cmd, u8 bytes, u8 *buffer); + int (*block_read) (device_t dev, u8 cmd, u8 *bytes, u8 *buffer); int (*block_write) (device_t dev, u8 cmd, u8 bytes, const u8 *buffer); };
@@ -44,7 +44,7 @@ int smbus_write_byte(device_t dev, u8 addr, u8 val); int smbus_read_word(device_t dev, u8 addr); int smbus_write_word(device_t dev, u8 addr, u16 val); int smbus_process_call(device_t dev, u8 cmd, u16 data); -int smbus_block_read(device_t dev, u8 cmd, u8 bytes, u8 *buffer); +int smbus_block_read(device_t dev, u8 cmd, u8 *bytes, u8 *buffer); int smbus_block_write(device_t dev, u8 cmd, u8 bytes, const u8 *buffer);
#endif /* DEVICE_SMBUS_H */ diff --git a/src/southbridge/amd/amd8111/acpi.c b/src/southbridge/amd/amd8111/acpi.c index 2ad54b7..0c78b91 100644 --- a/src/southbridge/amd/amd8111/acpi.c +++ b/src/southbridge/amd/amd8111/acpi.c @@ -66,6 +66,29 @@ static int lsmbus_write_byte(device_t dev, uint8_t address, uint8_t val) return do_smbus_write_byte(res->base, device, address, val); }
+static int lsmbus_block_read(device_t dev, uint8_t cmd, u8 *bytes, u8 *buffer) +{ + unsigned device; + struct resource *res; + + device = dev->path.i2c.device; + res = find_resource(get_pbus_smbus(dev)->dev, 0x58); + + return do_smbus_block_read(res->base, device, cmd, bytes, buffer); +} + +static int lsmbus_block_write(device_t dev, uint8_t cmd, u8 bytes, const u8 *buffer) +{ + unsigned device; + struct resource *res; + + device = dev->path.i2c.device; + res = find_resource(get_pbus_smbus(dev)->dev, 0x58); + + return do_smbus_block_write(res->base, device, cmd, bytes, buffer); +} + + #if CONFIG_GENERATE_ACPI_TABLES == 1 unsigned pm_base; #endif @@ -191,6 +214,8 @@ static struct smbus_bus_operations lops_smbus_bus = { .send_byte = lsmbus_send_byte, .read_byte = lsmbus_read_byte, .write_byte = lsmbus_write_byte, + .block_read = lsmbus_block_read, + .block_write= lsmbus_block_write, };
static struct pci_operations lops_pci = { diff --git a/src/southbridge/amd/amd8111/amd8111_smbus.h b/src/southbridge/amd/amd8111/amd8111_smbus.h index fe9b3bf..f07893d 100644 --- a/src/southbridge/amd/amd8111/amd8111_smbus.h +++ b/src/southbridge/amd/amd8111/amd8111_smbus.h @@ -222,3 +222,101 @@ static int do_smbus_write_byte(unsigned smbus_io_base, unsigned device, unsigned return 0; }
+static int do_smbus_block_read(unsigned smbus_io_base, unsigned device, unsigned cmd, u8 *bytes, u8 *buf) +{ + unsigned global_status_register; + unsigned i; + + if (smbus_wait_until_ready(smbus_io_base) < 0) { + return SMBUS_WAIT_UNTIL_READY_TIMEOUT; + } + + /* setup transaction */ + /* disable interrupts */ + outw(inw(smbus_io_base + SMBGCTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), smbus_io_base + SMBGCTL); + /* set the device I'm talking too */ + outw(((device & 0x7f) << 1) | 1, smbus_io_base + SMBHSTADDR); + /* set the command/address... */ + outb(cmd & 0xFF, smbus_io_base + SMBHSTCMD); + /* set up for a block data read */ + outw((inw(smbus_io_base + SMBGCTL) & ~7) | (0x5), smbus_io_base + SMBGCTL); + + /* clear any lingering errors, so the transaction will run */ + /* Do I need to write the bits to a 1 to clear an error? */ + outw(inw(smbus_io_base + SMBGSTATUS), smbus_io_base + SMBGSTATUS); + + /* clear the length word...*/ + outw(0, smbus_io_base + SMBHSTDAT); + + /* start the command */ + outw((inw(smbus_io_base + SMBGCTL) | (1 << 3)), smbus_io_base + SMBGCTL); + + /* poll for transaction completion */ + if (smbus_wait_until_done(smbus_io_base) < 0) { + return SMBUS_WAIT_UNTIL_DONE_TIMEOUT; + } + + global_status_register = inw(smbus_io_base + SMBGSTATUS); + + /* read results of transaction */ + *bytes = inw(smbus_io_base + SMBHSTDAT) & 0x3f; + + if ((global_status_register & SMBUS_STATUS_MASK) != (1 << 4)) { + return SMBUS_ERROR; + } + + /* read data block */ + for(i=0; i<*bytes; i++) { + buf[i] = inw(smbus_io_base + SMBHSTFIFO) & 0xff; + } + + return 0; +} + +static int do_smbus_block_write(unsigned smbus_io_base, unsigned device, unsigned cmd, u8 bytes, const u8 *buf) +{ + unsigned global_status_register; + unsigned i; + + if (smbus_wait_until_ready(smbus_io_base) < 0) { + return SMBUS_WAIT_UNTIL_READY_TIMEOUT; + } + + /* setup transaction */ + /* disable interrupts */ + outw(inw(smbus_io_base + SMBGCTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), smbus_io_base + SMBGCTL); + /* set the device I'm talking too */ + outw(((device & 0x7f) << 1) | 0, smbus_io_base + SMBHSTADDR); + /* set the command/address... */ + outb(cmd & 0xFF, smbus_io_base + SMBHSTCMD); + /* set up for a block data write */ + outw((inw(smbus_io_base + SMBGCTL) & ~7) | (0x5), smbus_io_base + SMBGCTL); + + /* clear any lingering errors, so the transaction will run */ + /* Do I need to write the bits to a 1 to clear an error? */ + outw(inw(smbus_io_base + SMBGSTATUS), smbus_io_base + SMBGSTATUS); + + /* set the length word...*/ + outw(bytes, smbus_io_base + SMBHSTDAT); + + /* set the data block */ + for(i=0; i<bytes; i++) { + outw(buf[i], smbus_io_base + SMBHSTFIFO); + } + + /* start the command */ + outw((inw(smbus_io_base + SMBGCTL) | (1 << 3)), smbus_io_base + SMBGCTL); + + /* poll for transaction completion */ + if (smbus_wait_until_done(smbus_io_base) < 0) { + return SMBUS_WAIT_UNTIL_DONE_TIMEOUT; + } + global_status_register = inw(smbus_io_base + SMBGSTATUS); + + if ((global_status_register & SMBUS_STATUS_MASK) != (1 << 4)) { + return SMBUS_ERROR; + } + return 0; +} + + diff --git a/src/southbridge/amd/amd8111/early_smbus.c b/src/southbridge/amd/amd8111/early_smbus.c index e6d7084..9a58a99 100644 --- a/src/southbridge/amd/amd8111/early_smbus.c +++ b/src/southbridge/amd/amd8111/early_smbus.c @@ -46,3 +46,12 @@ static inline int smbus_write_byte(unsigned device, unsigned address, unsigned c return do_smbus_write_byte(SMBUS_IO_BASE, device, address, val); }
+static inline int smbus_block_read(unsigned device, unsigned cmd, u8 *bytes, u8 *buf) +{ + return do_smbus_block_read(SMBUS_IO_BASE, device, cmd, bytes, buf); +} + +static inline int smbus_block_write(unsigned device, unsigned cmd, u8 bytes, const u8 *buf) +{ + return do_smbus_block_write(SMBUS_IO_BASE, device, cmd, bytes, buf); +}