From 2a7c519c89fc05c3640ee457883829b1d7221f0e Mon Sep 17 00:00:00 2001 From: Arthur Heymans Date: Mon, 20 Mar 2017 22:32:02 +0100 Subject: sb/intel/i82801gx: Add i2c_block_read to smbus.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Reviewed-on: https://review.coreboot.org/18927 Tested-by: build bot (Jenkins) Reviewed-by: Patrick Rudolph Reviewed-by: Paul Menzel Reviewed-by: Kyösti Mälkki --- src/southbridge/intel/i82801gx/early_smbus.c | 52 ++++++++++++++++++++++++++++ src/southbridge/intel/i82801gx/i82801gx.h | 2 ++ 2 files changed, 54 insertions(+) (limited to 'src/southbridge/intel') 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 -- cgit v1.2.3