324f82f2863097c2f47157b6d3499842b554f175
[coreboot.git] / src / southbridge / intel / i82801cx / i82801cx_smbus.c
1 #include <smbus.h>
2 #include <pci.h>
3 #include <arch/io.h>
4 #include "i82801cx.h"
5
6 #define PM_BUS 0
7 #define PM_DEVFN PCI_DEVFN(0x1f,3)
8
9 void smbus_enable(void)
10 {
11         /* iobase addr */
12         pcibios_write_config_dword(PM_BUS, PM_DEVFN, SMB_BASE,
13                                                            SMBUS_IO_BASE | PCI_BASE_ADDRESS_SPACE_IO);
14         /* smbus enable */
15         pcibios_write_config_byte(PM_BUS, PM_DEVFN, HOSTC, HST_EN);
16         /* iospace enable */
17         pcibios_write_config_word(PM_BUS, PM_DEVFN, PCI_COMMAND, PCI_COMMAND_IO);
18
19     /* Disable interrupt generation */
20     outb(0, SMBUS_IO_BASE + SMBHSTCTL);
21 }
22
23 static void smbus_wait_until_ready(void)
24 {
25         // Loop while HOST_BUSY
26         while((inb(SMBUS_IO_BASE + SMBHSTSTAT) & 1) == 1) {
27                 /* nop */
28         }
29 }
30
31 static void smbus_wait_until_done(void)
32 {
33         unsigned char byte;
34
35         // Loop while HOST_BUSY
36         do {
37                 byte = inb(SMBUS_IO_BASE + SMBHSTSTAT);
38         }
39         while((byte &1) == 1);
40
41         // Wait for SUCCESS or error or BYTE_DONE
42         while( (byte & ~1) == 0) {
43                 byte = inb(SMBUS_IO_BASE + SMBHSTSTAT);
44         }
45 }
46
47 int smbus_read_byte(unsigned device, unsigned address, unsigned char *result)
48 {
49         unsigned char host_status_register;
50         unsigned char byte;
51
52         smbus_wait_until_ready();
53
54         /* setup transaction */
55         /* disable interrupts */
56         outb(inb(SMBUS_IO_BASE + SMBHSTCTL) & (~1), SMBUS_IO_BASE + SMBHSTCTL);
57         /* set to read from the specified device  */
58         outb(((device & 0x7f) << 1) | 1, SMBUS_IO_BASE + SMBHSTADD);
59         /* set the command/address... */
60         outb(address & 0xFF, SMBUS_IO_BASE + SMBHSTCMD);
61         /* set up for a byte data read */
62         outb((inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xE3) | (0x2 << 2), SMBUS_IO_BASE + SMBHSTCTL);
63
64         /* clear any lingering errors, so the transaction will run */
65         outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
66
67         /* clear the data byte...*/
68         outb(0, SMBUS_IO_BASE + SMBHSTDAT0);
69
70         /* start the command */
71         outb((inb(SMBUS_IO_BASE + SMBHSTCTL) | 0x40), SMBUS_IO_BASE + SMBHSTCTL);
72
73         /* poll for transaction completion */
74         smbus_wait_until_done();
75
76         host_status_register = inb(SMBUS_IO_BASE + SMBHSTSTAT);
77
78         /* read results of transaction */
79         byte = inb(SMBUS_IO_BASE + SMBHSTDAT0);
80
81         *result = byte;
82         return host_status_register != 0x02;            // return true if !SUCCESS
83 }