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>
This commit is contained in:
Arthur Heymans 2017-03-20 22:32:02 +01:00
parent 4f4410dcbc
commit 2a7c519c89
2 changed files with 54 additions and 0 deletions

View File

@ -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;
}

View File

@ -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