summaryrefslogtreecommitdiffstats
path: root/src/southbridge/intel/i82801gx/early_smbus.c
diff options
context:
space:
mode:
authorArthur Heymans <arthur@aheymans.xyz>2017-03-20 22:32:02 +0100
committerArthur Heymans <arthur@aheymans.xyz>2017-04-11 11:51:04 +0200
commit2a7c519c89fc05c3640ee457883829b1d7221f0e (patch)
tree80e152ae5d2d73b53e2b30430f52add42d378d18 /src/southbridge/intel/i82801gx/early_smbus.c
parent4f4410dcbc56b14d1a078f078baab754046a5c69 (diff)
downloadcoreboot-2a7c519c89fc05c3640ee457883829b1d7221f0e.tar.gz
coreboot-2a7c519c89fc05c3640ee457883829b1d7221f0e.tar.bz2
coreboot-2a7c519c89fc05c3640ee457883829b1d7221f0e.zip
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>
Diffstat (limited to 'src/southbridge/intel/i82801gx/early_smbus.c')
-rw-r--r--src/southbridge/intel/i82801gx/early_smbus.c52
1 files changed, 52 insertions, 0 deletions
diff --git a/src/southbridge/intel/i82801gx/early_smbus.c b/src/southbridge/intel/i82801gx/early_smbus.c
index 93e9d6a6b5af..b8852e91ab1b 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;
+}