diff options
author | Arthur Heymans <arthur@aheymans.xyz> | 2017-03-20 22:32:02 +0100 |
---|---|---|
committer | Arthur Heymans <arthur@aheymans.xyz> | 2017-04-11 11:51:04 +0200 |
commit | 2a7c519c89fc05c3640ee457883829b1d7221f0e (patch) | |
tree | 80e152ae5d2d73b53e2b30430f52add42d378d18 | |
parent | 4f4410dcbc56b14d1a078f078baab754046a5c69 (diff) | |
download | coreboot-2a7c519c89fc05c3640ee457883829b1d7221f0e.tar.xz |
sb/intel/i82801gx: Add i2c_block_read to smbus.h
Using i2c_block_read speeds up reading SPD four to fivefold compared
to sequential byte read.
TESTED on Intel D945GCLF.
Change-Id: I6d768a2ba128329168f26445a4fca6921c0c8642
Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
Reviewed-on: https://review.coreboot.org/18927
Tested-by: build bot (Jenkins)
Reviewed-by: Patrick Rudolph <siro@das-labor.org>
Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
Reviewed-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
-rw-r--r-- | src/southbridge/intel/i82801gx/early_smbus.c | 52 | ||||
-rw-r--r-- | src/southbridge/intel/i82801gx/i82801gx.h | 2 |
2 files changed, 54 insertions, 0 deletions
diff --git a/src/southbridge/intel/i82801gx/early_smbus.c b/src/southbridge/intel/i82801gx/early_smbus.c index 93e9d6a6b5..b8852e91ab 100644 --- a/src/southbridge/intel/i82801gx/early_smbus.c +++ b/src/southbridge/intel/i82801gx/early_smbus.c @@ -54,3 +54,55 @@ int smbus_read_byte(unsigned int device, unsigned int address) { return do_smbus_read_byte(SMBUS_IO_BASE, device, 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; +} diff --git a/src/southbridge/intel/i82801gx/i82801gx.h b/src/southbridge/intel/i82801gx/i82801gx.h index 85cf6dbd53..0dc4c0b9fd 100644 --- a/src/southbridge/intel/i82801gx/i82801gx.h +++ b/src/southbridge/intel/i82801gx/i82801gx.h @@ -50,6 +50,8 @@ void gpi_route_interrupt(u8 gpi, u8 mode); #else void enable_smbus(void); int smbus_read_byte(unsigned int device, unsigned int address); +int i2c_block_read(unsigned int device, unsigned int cmd, unsigned int bytes, + u8 *buf); int southbridge_detect_s3_resume(void); #endif #endif |