summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMark Wilkinson <mark.wilkinson@2pmtech.co.uk>2004-12-01 16:57:37 +0000
committerMark Wilkinson <mark.wilkinson@2pmtech.co.uk>2004-12-01 16:57:37 +0000
commite1bc97b07837bc0663d56c9f62b919316f3ddac4 (patch)
treefb32f07d4b596e55a893705f86b40a1fcc5d9132 /src
parent284c27f29971326bd786e89c1ceb3f51a53203db (diff)
Updated version of vt8231_early_smbus.c
smbus_read_byte routine updated as per suggestion by rgm addition reset & wait_until_ready to allow correct reading of first byte on epia systems. git-svn-id: svn://svn.coreboot.org/coreboot/trunk@1807 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'src')
-rw-r--r--src/southbridge/via/vt8231/vt8231_early_smbus.c150
1 files changed, 109 insertions, 41 deletions
diff --git a/src/southbridge/via/vt8231/vt8231_early_smbus.c b/src/southbridge/via/vt8231/vt8231_early_smbus.c
index 1888176144..056c4b5b11 100644
--- a/src/southbridge/via/vt8231/vt8231_early_smbus.c
+++ b/src/southbridge/via/vt8231/vt8231_early_smbus.c
@@ -59,25 +59,54 @@ static inline void smbus_delay(void)
outb(0x80, 0x80);
}
+static int smbus_wait_until_active(void)
+{
+ unsigned long loops;
+ loops = SMBUS_TIMEOUT;
+ do {
+ unsigned char val;
+ smbus_delay();
+ val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
+ if ((val & 1)) {
+ break;
+ }
+ } while(--loops);
+ return loops?0:-4;
+}
+
static int smbus_wait_until_ready(void)
{
- unsigned char c;
- unsigned long loops;
- loops = SMBUS_TIMEOUT;
- do {
- unsigned char val;
- smbus_delay();
- c = inb(SMBUS_IO_BASE + SMBHSTSTAT);
- while((c & 1) == 1) {
- print_debug("c is ");
- print_debug_hex8(c);
- print_debug("\r\n");
- c = inb(SMBUS_IO_BASE + SMBHSTSTAT);
- /* nop */
- }
-
- } while(--loops);
- return loops?0:-1;
+ unsigned long loops;
+ loops = SMBUS_TIMEOUT;
+ do {
+ unsigned char val;
+ smbus_delay();
+ val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
+ if ((val & 1) == 0) {
+ break;
+ }
+ if(loops == (SMBUS_TIMEOUT / 2)) {
+ outb(inb(SMBUS_IO_BASE + SMBHSTSTAT),
+ SMBUS_IO_BASE + SMBHSTSTAT);
+ }
+ } while(--loops);
+ return loops?0:-2;
+}
+
+static int smbus_wait_until_done(void)
+{
+ unsigned long loops;
+ loops = SMBUS_TIMEOUT;
+ do {
+ unsigned char val;
+ smbus_delay();
+
+ val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
+ if ( (val & 1) == 0) {
+ break;
+ }
+ } while(--loops);
+ return loops?0:-3;
}
void smbus_reset(void)
@@ -93,25 +122,6 @@ void smbus_reset(void)
print_debug("\r\n");
}
-
-
-static int smbus_wait_until_done(void)
-{
- unsigned long loops;
- unsigned char byte;
- loops = SMBUS_TIMEOUT;
- do {
- unsigned char val;
- smbus_delay();
-
- byte = inb(SMBUS_IO_BASE + SMBHSTSTAT);
- if (byte & 1)
- break;
-
- } while(--loops);
- return loops?0:-1;
-}
-
static void smbus_print_error(unsigned char host_status_register)
{
@@ -135,13 +145,71 @@ static void smbus_print_error(unsigned char host_status_register)
}
}
+/*
+ * Copied from intel/i82801dbm early smbus code - suggested by rgm.
+ * Modifications/check against i2c-viapro driver code from linux-2.4.22
+ * and VT8231 Reference Docs - mw.
+ */
+static int smbus_read_byte(unsigned device, unsigned address)
+{
+ unsigned char global_control_register;
+ unsigned char global_status_register;
+ unsigned char byte;
+
+ if (smbus_wait_until_ready() < 0) {
+ outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
+ if ( smbus_wait_until_ready() < 0 ) {
+ return -2;
+ }
+ }
+
+ /* setup transaction */
+ /* disable interrupts */
+ outb(inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xfe, SMBUS_IO_BASE + SMBHSTCTL);
+ /* set the device I'm talking too */
+ outb(((device & 0x7f) << 1) | 1, SMBUS_IO_BASE + SMBXMITADD);
+ /* set the command/address... */
+ outb(address & 0xFF, SMBUS_IO_BASE + SMBHSTCMD);
+ /* set up for a byte data read */
+ outb((inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xe3) | (0x2<<2), SMBUS_IO_BASE + SMBHSTCTL);
+
+ /* clear any lingering errors, so the transaction will run */
+ outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
+
+ /* clear the data byte...*/
+ outb(0, SMBUS_IO_BASE + SMBHSTDAT0);
+
+ /* start a byte read, with interrupts disabled */
+ outb((inb(SMBUS_IO_BASE + SMBHSTCTL) | 0x40), SMBUS_IO_BASE + SMBHSTCTL);
+ /* poll for it to start */
+ if (smbus_wait_until_active() < 0) {
+ return -4;
+ }
+
+ /* poll for transaction completion */
+ if (smbus_wait_until_done() < 0) {
+ return -3;
+ }
+ /* Ignore the Host Busy & Command Complete ? */
+ global_status_register = inb(SMBUS_IO_BASE + SMBHSTSTAT) & ~((1<<1)|(1<<0));
+
+ /* read results of transaction */
+ byte = inb(SMBUS_IO_BASE + SMBHSTDAT0);
+
+ if (global_status_register != 0) {
+ return -1;
+ }
+ return byte;
+}
+
+#if 0
/* SMBus routines borrowed from VIA's Trident Driver */
/* this works, so I am not going to touch it for now -- rgm */
static unsigned char smbus_read_byte(unsigned char devAdr,
unsigned char bIndex)
{
- unsigned short i;
+ unsigned int i;
unsigned char bData;
unsigned char sts = 0;
@@ -149,10 +217,10 @@ static unsigned char smbus_read_byte(unsigned char devAdr,
outb(0xff, SMBUS_IO_BASE);
/* check SMBUS ready */
- for ( i = 0; i < 0xFFFF; i++ )
+ for ( i = 0; i < SMBUS_TIMEOUT; i++ )
if ( (inb(SMBUS_IO_BASE) & 0x01) == 0 )
break;
-
+
/* set host command */
outb(bIndex, SMBUS_IO_BASE+3);
@@ -163,7 +231,7 @@ static unsigned char smbus_read_byte(unsigned char devAdr,
outb(0x48, SMBUS_IO_BASE+2);
/* SMBUS Wait Ready */
- for ( i = 0; i < 0xFFFF; i++ )
+ for ( i = 0; i < SMBUS_TIMEOUT; i++ )
if ( ((sts = inb(SMBUS_IO_BASE)) & 0x01) == 0 )
break;
if ((sts & ~3) != 0) {
@@ -175,7 +243,7 @@ static unsigned char smbus_read_byte(unsigned char devAdr,
return bData;
}
-
+#endif
/* for reference, here is the fancier version which we will use at some
* point
*/