Rename almost all occurences of LinuxBIOS to coreboot.
[coreboot.git] / src / southbridge / intel / i82801ca / i82801ca_early_smbus.c
1 #include <device/pci_ids.h>
2 #include "i82801ca.h"
3
4 static void enable_smbus(void)
5 {
6         device_t dev;
7         dev = pci_locate_device(PCI_ID(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_SMB), 0);
8         if (dev == PCI_DEV_INVALID) {
9                 die("SMBUS controller not found\r\n");
10         }
11         
12         print_debug("SMBus controller enabled\r\n");
13         /* set smbus iobase */
14         pci_write_config32(dev, SMB_BASE, SMBUS_IO_BASE | PCI_BASE_ADDRESS_SPACE_IO);
15         /* Set smbus enable */
16         pci_write_config8(dev, HOSTC, HST_EN);
17         /* Set smbus iospace enable */ 
18         pci_write_config16(dev, PCI_COMMAND, PCI_COMMAND_IO);
19         /* Disable interrupt generation */ 
20         outb(0, SMBUS_IO_BASE + SMBHSTCTL);
21         /* clear any lingering errors, so the transaction will run */
22         outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
23 }
24
25
26 static inline void smbus_delay(void)
27 {
28         outb(0x80, 0x80);
29 }
30
31 // See http://www.coreboot.org/pipermail/linuxbios/2004-September/009077.html
32 // for a description of this function.
33 static int smbus_wait_until_active(void)
34 {
35         unsigned long loops;
36         loops = SMBUS_TIMEOUT;
37         do {
38                 unsigned char val;
39                 smbus_delay();
40                 val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
41                 if ((val & 1)) {
42                         break;
43                 }
44         } while (--loops);
45         return loops ? 0 : -4;
46 }
47
48 static int smbus_wait_until_ready(void)
49 {
50         unsigned long loops;
51         loops = SMBUS_TIMEOUT;
52         do {
53                 unsigned char val;
54                 smbus_delay();
55                 val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
56                 // !HOST_BUSY?
57                 if ((val & 1) == 0) {
58                         break;
59                 }
60                 if(loops == (SMBUS_TIMEOUT / 2)) {
61                         // Clear status flags
62                         outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), 
63                                 SMBUS_IO_BASE + SMBHSTSTAT);
64                 }
65         } while(--loops);
66         return loops?0:-2;
67 }
68
69 static int smbus_wait_until_done(void)
70 {
71         unsigned long loops;
72         loops = SMBUS_TIMEOUT;
73         do {
74                 unsigned char val;
75                 smbus_delay();
76                 
77                 val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
78                 // !HOST_BUSY?
79                 if ( (val & 1) == 0) {
80                         break;
81                 }
82                 // BYTE_DONE or SUCCESS or error?
83                 if ((val & ~((1<<6)|(1<<0)) ) != 0 ) {
84                         break;
85                 }
86         } while(--loops);
87         return loops?0:-3;
88 }
89
90 static int smbus_read_byte(unsigned device, unsigned address)
91 {
92         unsigned char global_control_register;
93         unsigned char global_status_register;
94         unsigned char byte;
95
96         if (smbus_wait_until_ready() < 0) {
97                 return -2;
98         }
99         
100         /* setup transaction */
101         /* disable interrupts */
102         outb(inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xfe, SMBUS_IO_BASE + SMBHSTCTL);
103         /* set to read from the specified device  */
104         outb(((device & 0x7f) << 1) | 1, SMBUS_IO_BASE + SMBXMITADD);
105         /* set the command/address... */
106         outb(address & 0xFF, SMBUS_IO_BASE + SMBHSTCMD);
107         /* set up for a byte data read */
108         outb((inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xe3) | (0x2<<2), SMBUS_IO_BASE + SMBHSTCTL);
109
110         /* clear any lingering errors, so the transaction will run */
111         outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
112
113         /* clear the data byte...*/
114         outb(0, SMBUS_IO_BASE + SMBHSTDAT0);
115
116         /* start a byte read, with interrupts disabled */
117         outb((inb(SMBUS_IO_BASE + SMBHSTCTL) | 0x40), SMBUS_IO_BASE + SMBHSTCTL);
118         /* poll for it to start */
119         if (smbus_wait_until_active() < 0) {
120                 return -4;
121         }
122
123         /* poll for transaction completion */
124         if (smbus_wait_until_done() < 0) {
125                 return -3;
126         }
127
128         global_status_register = inb(SMBUS_IO_BASE + SMBHSTSTAT) & ~(1<<6); /* Ignore the In Use Status... */
129
130         /* read results of transaction */
131         byte = inb(SMBUS_IO_BASE + SMBHSTDAT0);
132
133         // SUCCESS?
134         if (global_status_register != 2) {
135                 return -1;
136         }
137         return byte;
138 }