Revision: linuxbios@linuxbios.org--devel/freebios--devel--2.0--patch-51
[coreboot.git] / src / southbridge / intel / i82801er / i82801er_early_smbus.c
1
2 //#define SMBUS_IO_BASE 0x1000
3 #define SMBUS_IO_BASE 0x0f00
4
5 #define SMBHSTSTAT 0x0
6 #define SMBHSTCTL  0x2
7 #define SMBHSTCMD  0x3
8 #define SMBXMITADD 0x4
9 #define SMBHSTDAT0 0x5
10 #define SMBHSTDAT1 0x6
11 #define SMBBLKDAT  0x7
12 #define SMBTRNSADD 0x9
13 #define SMBSLVDATA 0xa
14 #define SMLINK_PIN_CTL 0xe
15 #define SMBUS_PIN_CTL  0xf 
16
17 /* Between 1-10 seconds, We should never timeout normally 
18  * Longer than this is just painful when a timeout condition occurs.
19  */
20 #define SMBUS_TIMEOUT (100*1000*10)
21
22 static void enable_smbus(void)
23 {
24         device_t dev;
25         dev = pci_locate_device(PCI_ID(0x8086, 0x24d3), 0);
26         if (dev == PCI_DEV_INVALID) {
27                 die("SMBUS controller not found\r\n");
28         }
29         
30         print_debug("SMBus controller enabled\r\n");
31         /* set smbus iobase */
32         pci_write_config32(dev, 0x20, SMBUS_IO_BASE | 1);
33         /* Set smbus enable */
34         pci_write_config8(dev, 0x40, 0x01);
35         /* Set smbus iospace enable */ 
36         pci_write_config16(dev, 0x4, 0x01);
37         /* Disable interrupt generation */ 
38         outb(0, SMBUS_IO_BASE + SMBHSTCTL);
39         /* clear any lingering errors, so the transaction will run */
40         outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
41 }
42
43
44 static inline void smbus_delay(void)
45 {
46         outb(0x80, 0x80);
47 }
48
49 static int smbus_wait_until_active(void)
50 {                       
51         unsigned long loops;
52         loops = SMBUS_TIMEOUT;
53         do {
54                 unsigned char val;
55                 smbus_delay();
56                 val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
57                 if ((val & 1)) {
58                         break;
59                 }
60         } while(--loops);
61         return loops?0:-4;
62 }
63
64 static int smbus_wait_until_ready(void)
65 {
66         unsigned long loops;
67         loops = SMBUS_TIMEOUT;
68         do {
69                 unsigned char val;
70                 smbus_delay();
71                 val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
72                 if ((val & 1) == 0) {
73                         break;
74                 }
75                 if(loops == (SMBUS_TIMEOUT / 2)) {
76                         outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), 
77                                 SMBUS_IO_BASE + SMBHSTSTAT);
78                 }
79         } while(--loops);
80         return loops?0:-2;
81 }
82
83 static int smbus_wait_until_done(void)
84 {
85         unsigned long loops;
86         loops = SMBUS_TIMEOUT;
87         do {
88                 unsigned char val;
89                 smbus_delay();
90                 
91                 val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
92                 if ( (val & 1) == 0) {
93                         break;
94                 }
95                 if ((val & ~((1<<6)|(1<<0)) ) != 0 ) {
96                         break;
97                 }
98         } while(--loops);
99         return loops?0:-3;
100 }
101
102 static int smbus_read_byte(unsigned device, unsigned address)
103 {
104         unsigned char global_control_register;
105         unsigned char global_status_register;
106         unsigned char byte;
107
108         if (smbus_wait_until_ready() < 0) {
109                 return -2;
110         }
111         
112         /* setup transaction */
113         /* disable interrupts */
114         outb(inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xfe, SMBUS_IO_BASE + SMBHSTCTL);
115         /* set the device I'm talking too */
116         outb(((device & 0x7f) << 1) | 1, SMBUS_IO_BASE + SMBXMITADD);
117         /* set the command/address... */
118         outb(address & 0xFF, SMBUS_IO_BASE + SMBHSTCMD);
119         /* set up for a byte data read */
120         outb((inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xe3) | (0x2<<2), SMBUS_IO_BASE + SMBHSTCTL);
121
122         /* clear any lingering errors, so the transaction will run */
123         outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
124
125         /* clear the data byte...*/
126         outb(0, SMBUS_IO_BASE + SMBHSTDAT0);
127
128         /* start a byte read, with interrupts disabled */
129         outb((inb(SMBUS_IO_BASE + SMBHSTCTL) | 0x40), SMBUS_IO_BASE + SMBHSTCTL);
130
131         /* poll for it to start */
132         if (smbus_wait_until_active() < 0) {
133                 return -4;
134         }
135
136         /* poll for transaction completion */
137         if (smbus_wait_until_done() < 0) {
138                 return -3;
139         }
140
141         global_status_register = inb(SMBUS_IO_BASE + SMBHSTSTAT) & ~(1<<6); /* Ignore the In Use Status... */
142
143         /* read results of transaction */
144         byte = inb(SMBUS_IO_BASE + SMBHSTDAT0);
145
146         if (global_status_register != 2) {
147                 return -1;
148         }
149         return byte;
150 }
151 #if 0
152 static void smbus_write_byte(unsigned device, unsigned address, unsigned char val)
153 {
154         if (smbus_wait_until_ready() < 0) {
155                 return;
156         }
157
158         /* by LYH */
159         outb(0x37,SMBUS_IO_BASE + SMBHSTSTAT);
160         /* set the device I'm talking too */
161         outw(((device & 0x7f) << 1) | 0, SMBUS_IO_BASE + SMBHSTADDR);
162
163         /* data to send */
164         outb(val, SMBUS_IO_BASE + SMBHSTDAT);
165
166         outb(address & 0xFF, SMBUS_IO_BASE + SMBHSTCMD);
167
168         /* start the command */
169         outb(0xa, SMBUS_IO_BASE + SMBHSTCTL);
170
171         /* poll for transaction completion */
172         smbus_wait_until_done();
173         return;
174 }
175 #endif