aboutsummaryrefslogtreecommitdiff
path: root/src/southbridge/sis/sis966/sis966_early_smbus.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/southbridge/sis/sis966/sis966_early_smbus.c')
-rw-r--r--src/southbridge/sis/sis966/sis966_early_smbus.c172
1 files changed, 170 insertions, 2 deletions
diff --git a/src/southbridge/sis/sis966/sis966_early_smbus.c b/src/southbridge/sis/sis966/sis966_early_smbus.c
index 3d4954b64f..1c81bf16fd 100644
--- a/src/southbridge/sis/sis966/sis966_early_smbus.c
+++ b/src/southbridge/sis/sis966/sis966_early_smbus.c
@@ -23,6 +23,174 @@
#define SMBUS0_IO_BASE 0x8D0
+static inline void smbus_delay(void)
+{
+ outb(0x80, 0x80);
+}
+
+int smbus_wait_until_ready(unsigned smbus_io_base)
+{
+ unsigned long loops;
+ loops = SMBUS_TIMEOUT;
+ do {
+ unsigned char val;
+ smbus_delay();
+ val = inb(smbus_io_base + SMBHSTSTAT);
+ val &= 0x1f;
+ if (val == 0) {
+ return 0;
+ }
+ outb(val,smbus_io_base + SMBHSTSTAT);
+ } while(--loops);
+ return -2;
+}
+
+int smbus_wait_until_done(unsigned smbus_io_base)
+{
+ unsigned long loops;
+ loops = SMBUS_TIMEOUT;
+ do {
+ unsigned char val;
+ smbus_delay();
+
+ val = inb(smbus_io_base + 0x00);
+ if ( (val & 0xff) != 0x02) {
+ return 0;
+ }
+ } while(--loops);
+ return -3;
+}
+
+int do_smbus_recv_byte(unsigned smbus_io_base, unsigned device)
+{
+ unsigned char global_status_register;
+ unsigned char byte;
+
+ /* set the device I'm talking too */
+ outb(((device & 0x7f) << 1)|1 , smbus_io_base + SMBXMITADD);
+ smbus_delay();
+
+ /* byte data recv */
+ outb(0x05, smbus_io_base + SMBHSTPRTCL);
+ smbus_delay();
+
+ /* poll for transaction completion */
+ if (smbus_wait_until_done(smbus_io_base) < 0) {
+ return -3;
+ }
+
+ global_status_register = inb(smbus_io_base + SMBHSTSTAT) & 0x80; /* lose check */
+
+ /* read results of transaction */
+ byte = inb(smbus_io_base + SMBHSTCMD);
+
+ if (global_status_register != 0x80) { // lose check, otherwise it should be 0
+ return -1;
+ }
+ return byte;
+}
+
+int do_smbus_send_byte(unsigned smbus_io_base, unsigned device, unsigned char val)
+{
+ unsigned global_status_register;
+
+ outb(val, smbus_io_base + SMBHSTDAT0);
+ smbus_delay();
+
+ /* set the command... */
+ outb(val, smbus_io_base + SMBHSTCMD);
+ smbus_delay();
+
+ /* set the device I'm talking too */
+ outb(((device & 0x7f) << 1) | 0, smbus_io_base + SMBXMITADD);
+ smbus_delay();
+
+ /* set up for a byte data write */
+ outb(0x04, smbus_io_base + SMBHSTPRTCL);
+ smbus_delay();
+
+ /* poll for transaction completion */
+ if (smbus_wait_until_done(smbus_io_base) < 0) {
+ return -3;
+ }
+ global_status_register = inb(smbus_io_base + SMBHSTSTAT) & 0x80; /* lose check */;
+
+ if (global_status_register != 0x80) {
+ return -1;
+ }
+ return 0;
+}
+
+static inline int do_smbus_read_byte(unsigned smbus_io_base, unsigned device, unsigned address)
+{
+ unsigned char global_status_register;
+ unsigned char byte;
+
+ outb(0xff, smbus_io_base + 0x00);
+ smbus_delay();
+ outb(0x20, smbus_io_base + 0x03);
+ smbus_delay();
+
+ outb(((device & 0x7f) << 1)|1 , smbus_io_base + 0x04);
+ smbus_delay();
+ outb(address & 0xff, smbus_io_base + 0x05);
+ smbus_delay();
+ outb(0x12, smbus_io_base + 0x03);
+ smbus_delay();
+
+int i,j;
+for(i=0;i<0x1000;i++)
+{
+ if (inb(smbus_io_base + 0x00) != 0x08)
+ { smbus_delay();
+ for(j=0;j<0xFFFF;j++);
+ }
+};
+
+ global_status_register = inb(smbus_io_base + 0x00);
+ byte = inb(smbus_io_base + 0x08);
+
+ if (global_status_register != 0x08) { // lose check, otherwise it should be 0
+ print_debug("Fail");print_debug("\r\t");
+ return -1;
+ }
+ print_debug("Success");print_debug("\r\t");
+ return byte;
+}
+
+
+static inline int do_smbus_write_byte(unsigned smbus_io_base, unsigned device, unsigned address, unsigned char val)
+{
+ unsigned global_status_register;
+
+ outb(val, smbus_io_base + SMBHSTDAT0);
+ smbus_delay();
+
+ /* set the device I'm talking too */
+ outb(((device & 0x7f) << 1) | 0, smbus_io_base + SMBXMITADD);
+ smbus_delay();
+
+ outb(address & 0xff, smbus_io_base + SMBHSTCMD);
+ smbus_delay();
+
+ /* set up for a byte data write */
+ outb(0x06, smbus_io_base + SMBHSTPRTCL);
+ smbus_delay();
+
+ /* poll for transaction completion */
+ if (smbus_wait_until_done(smbus_io_base) < 0) {
+ return -3;
+ }
+ global_status_register = inb(smbus_io_base + SMBHSTSTAT) & 0x80; /* lose check */;
+
+ if (global_status_register != 0x80) {
+ return -1;
+ }
+ return 0;
+}
+
+
+
static const uint8_t SiS_LPC_init[34][3]={
{0x04, 0xF8, 0x07}, //Reg 0x04
{0x45, 0x00, 0x00}, //Reg 0x45 //Enable Rom Flash
@@ -564,11 +732,11 @@ static void enable_smbus(void)
printk(BIOS_DEBUG, "enable_smbus <--------\n");
}
-static int smbus_read_byte(unsigned device, unsigned address)
+int smbus_read_byte(unsigned device, unsigned address)
{
return do_smbus_read_byte(SMBUS0_IO_BASE, device, address);
}
-static int smbus_write_byte(unsigned device, unsigned address, unsigned char val)
+int smbus_write_byte(unsigned device, unsigned address, unsigned char val)
{
return do_smbus_write_byte(SMBUS0_IO_BASE, device, address, val);
}