diff options
Diffstat (limited to 'src/southbridge/intel')
-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 |