27acca494fedceef705a322fe2db2d622cc8aa1f
[coreboot.git] / src / southbridge / intel / i82801ex / i82801ex_smbus.h
1 #include <device/smbus_def.h>
2
3 #define SMBHSTSTAT 0x0
4 #define SMBHSTCTL  0x2
5 #define SMBHSTCMD  0x3
6 #define SMBXMITADD 0x4
7 #define SMBHSTDAT0 0x5
8 #define SMBHSTDAT1 0x6
9 #define SMBBLKDAT  0x7
10 #define SMBTRNSADD 0x9
11 #define SMBSLVDATA 0xa
12 #define SMLINK_PIN_CTL 0xe
13 #define SMBUS_PIN_CTL  0xf 
14
15 #define SMBUS_TIMEOUT (100*1000*10)
16
17
18 static void smbus_delay(void)
19 {
20         outb(0x80, 0x80);
21 }
22
23 static int smbus_wait_until_ready(unsigned smbus_io_base)
24 {
25         unsigned loops = SMBUS_TIMEOUT;
26         unsigned char byte;
27         do {
28                 smbus_delay();
29                 if (--loops == 0)
30                         break;
31                 byte = inb(smbus_io_base + SMBHSTSTAT);
32         } while(byte & 1);
33         return loops?0:-1;
34 }
35
36 static int smbus_wait_until_done(unsigned smbus_io_base)
37 {
38         unsigned loops = SMBUS_TIMEOUT;
39         unsigned char byte;
40         do {
41                 smbus_delay();
42                 if (--loops == 0)
43                        break;
44                 byte = inb(smbus_io_base + SMBHSTSTAT);
45         } while((byte & 1) || (byte & ~((1<<6)|(1<<0))) == 0);
46         return loops?0:-1;
47 }
48
49 static inline int smbus_wait_until_blk_done(unsigned smbus_io_base)
50 {
51         unsigned loops = SMBUS_TIMEOUT;
52         unsigned char byte;
53         do {
54                 smbus_delay();
55                 if (--loops == 0)
56                        break;
57                 byte = inb(smbus_io_base + SMBHSTSTAT);
58         } while((byte&(1<<7)) == 0);
59         return loops?0:-1;
60 }
61
62 static int do_smbus_read_byte(unsigned smbus_io_base, unsigned device, unsigned address)
63 {
64         unsigned char global_status_register;
65         unsigned char byte;
66
67         if (smbus_wait_until_ready(smbus_io_base) < 0) {
68                 return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
69         }
70         /* setup transaction */
71         /* disable interrupts */
72         outb(inb(smbus_io_base + SMBHSTCTL) & (~1), smbus_io_base + SMBHSTCTL);
73         /* set the device I'm talking too */
74         outb(((device & 0x7f) << 1) | 1, smbus_io_base + SMBXMITADD);
75         /* set the command/address... */
76         outb(address & 0xFF, smbus_io_base + SMBHSTCMD);
77         /* set up for a byte data read */
78         outb((inb(smbus_io_base + SMBHSTCTL) & 0xE3) | (0x2 << 2), smbus_io_base + SMBHSTCTL);
79         /* clear any lingering errors, so the transaction will run */
80         outb(inb(smbus_io_base + SMBHSTSTAT), smbus_io_base + SMBHSTSTAT);
81
82         /* clear the data byte...*/
83         outb(0, smbus_io_base + SMBHSTDAT0);
84
85         /* start the command */
86         outb((inb(smbus_io_base + SMBHSTCTL) | 0x40), smbus_io_base + SMBHSTCTL);
87
88         /* poll for transaction completion */
89         if (smbus_wait_until_done(smbus_io_base) < 0) {
90                 return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
91         }
92
93         global_status_register = inb(smbus_io_base + SMBHSTSTAT);
94
95         /* Ignore the In Use Status... */
96         global_status_register &= ~(3 << 5);
97
98         /* read results of transaction */
99         byte = inb(smbus_io_base + SMBHSTDAT0);
100         if (global_status_register != (1 << 1)) {
101                 return SMBUS_ERROR;
102         }
103         return byte;
104 }
105