summaryrefslogtreecommitdiff
path: root/src/southbridge/intel
diff options
context:
space:
mode:
Diffstat (limited to 'src/southbridge/intel')
-rw-r--r--src/southbridge/intel/i82801gx/early_smbus.c52
-rw-r--r--src/southbridge/intel/i82801gx/i82801gx.h2
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