Since some people disapprove of white space cleanups mixed in regular commits
[coreboot.git] / src / southbridge / intel / i82371eb / i82371eb_smbus.h
1 #include <device/smbus_def.h>
2
3 #define SMBHST_STATUS   0x0
4 #define SMBHST_CTL      0x2
5 #define SMBHST_CMD      0x3
6 #define SMBHST_ADDR     0x4
7 #define SMBHST_DAT      0x5
8
9 #define SMBUS_TIMEOUT (100*1000*10)
10 #define SMBUS_STATUS_MASK 0x1e
11 #define SMBUS_ERROR_FLAG (1<<2)
12
13 static inline void smbus_delay(void)
14 {
15         outb(0x80, 0x80);
16         outb(0x80, 0x80);
17         outb(0x80, 0x80);
18         outb(0x80, 0x80);
19         outb(0x80, 0x80);
20         outb(0x80, 0x80);
21 }
22
23 static int smbus_wait_until_ready(unsigned smbus_io_base)
24 {
25         unsigned long loops;
26         loops = SMBUS_TIMEOUT;
27         do {
28                 unsigned char val;
29                 smbus_delay();
30                 val = inb(smbus_io_base + SMBHST_STATUS);
31                 if ((val & 0x1) == 0) {
32                         break;
33                 }
34 #if 0
35                 if(loops == (SMBUS_TIMEOUT / 2)) {
36                         outw(inw(smbus_io_base + SMBHST_STATUS),
37                                 smbus_io_base + SMBHST_STATUS);
38                 }
39 #endif
40         } while(--loops);
41         return loops?0:SMBUS_WAIT_UNTIL_READY_TIMEOUT;
42 }
43
44 static int smbus_wait_until_done(unsigned smbus_io_base)
45 {
46         unsigned long loops;
47         loops = SMBUS_TIMEOUT;
48         do {
49                 unsigned short val;
50                 smbus_delay();
51
52                 val = inb(smbus_io_base + SMBHST_STATUS);
53                 // Make sure the command is done
54                 if ((val & 0x1) != 0) {
55                         continue;
56                 }
57                 // Don't break out until one of the interrupt
58                 // flags is set.
59                 if (val & 0xfe) {
60                         break;
61                 }
62         } while(--loops);
63         return loops?0:SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
64 }
65
66 static int do_smbus_recv_byte(unsigned smbus_io_base, unsigned device)
67 {
68         unsigned global_status_register;
69         unsigned byte;
70
71         if (smbus_wait_until_ready(smbus_io_base) < 0) {
72                 return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
73         }
74
75         /* setup transaction */
76         /* disable interrupts */
77         outw(inw(smbus_io_base + SMBHST_CTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), smbus_io_base + SMBHST_CTL);
78         /* set the device I'm talking too */
79         outw(((device & 0x7f) << 1) | 1, smbus_io_base + SMBHST_ADDR);
80         /* set the command/address... */
81         outb(0, smbus_io_base + SMBHST_CMD);
82         /* set up for a send byte */
83         outw((inw(smbus_io_base + SMBHST_CTL) & ~7) | (0x1), smbus_io_base + SMBHST_CTL);
84
85         /* clear any lingering errors, so the transaction will run */
86         /* Do I need to write the bits to a 1 to clear an error? */
87         outw(inw(smbus_io_base + SMBHST_STATUS), smbus_io_base + SMBHST_STATUS);
88
89         /* set the data word...*/
90         outw(0, smbus_io_base + SMBHST_DAT);
91
92         /* start the command */
93         outw((inw(smbus_io_base + SMBHST_CTL) | (1 << 3)), smbus_io_base + SMBHST_CTL);
94
95
96         /* poll for transaction completion */
97         if (smbus_wait_until_done(smbus_io_base) < 0) {
98                 return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
99         }
100
101         global_status_register = inw(smbus_io_base + SMBHST_STATUS);
102
103         /* read results of transaction */
104         byte = inb(smbus_io_base + SMBHST_DAT) & 0xff;
105
106         // Check for any result other than a command completion
107         if ((global_status_register & SMBUS_STATUS_MASK) != (1 << 1)) {
108                 return SMBUS_ERROR;
109         }
110         return byte;
111 }
112
113 static int do_smbus_send_byte(unsigned smbus_io_base, unsigned device, unsigned value)
114 {
115         unsigned global_status_register;
116
117         if (smbus_wait_until_ready(smbus_io_base) < 0) {
118                 return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
119         }
120
121         /* setup transaction */
122         /* disable interrupts */
123         outw(inw(smbus_io_base + SMBHST_CTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), smbus_io_base + SMBHST_CTL);
124         /* set the device I'm talking too */
125         outw(((device & 0x7f) << 1) | 0, smbus_io_base + SMBHST_ADDR);
126         /* set the command/address... */
127         outb(0, smbus_io_base + SMBHST_CMD);
128         /* set up for a send byte */
129         outw((inw(smbus_io_base + SMBHST_CTL) & ~7) | (0x1), smbus_io_base + SMBHST_CTL);
130
131         /* clear any lingering errors, so the transaction will run */
132         /* Do I need to write the bits to a 1 to clear an error? */
133         outw(inw(smbus_io_base + SMBHST_STATUS), smbus_io_base + SMBHST_STATUS);
134
135         /* set the data word...*/
136         outw(value, smbus_io_base + SMBHST_DAT);
137
138         /* start the command */
139         outw((inw(smbus_io_base + SMBHST_CTL) | (1 << 3)), smbus_io_base + SMBHST_CTL);
140
141
142         /* poll for transaction completion */
143         if (smbus_wait_until_done(smbus_io_base) < 0) {
144                 return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
145         }
146         global_status_register = inw(smbus_io_base + SMBHST_STATUS);
147
148         if ((global_status_register & SMBUS_STATUS_MASK) != (1 << 4)) {
149                 return SMBUS_ERROR;
150         }
151         return 0;
152 }
153
154
155 static int do_smbus_read_byte(unsigned smbus_io_base, unsigned device, unsigned address)
156 {
157         unsigned status_register;
158         unsigned byte;
159
160         if (smbus_wait_until_ready(smbus_io_base) < 0) {
161                 return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
162         }
163
164         /* setup transaction */
165
166         /* clear any lingering errors, so the transaction will run */
167         outb(0x1e, smbus_io_base + SMBHST_STATUS);
168
169         /* set the device I'm talking too */
170         outb(((device & 0x7f) << 1) | 1, smbus_io_base + SMBHST_ADDR);
171
172         /* set the command/address... */
173         outb(address & 0xff, smbus_io_base + SMBHST_CMD);
174
175         /* clear the data word...*/
176         outb(0, smbus_io_base + SMBHST_DAT);
177
178         /* start a byte read with interrupts disabled */
179         outb( (0x02 << 2)|(1<<6), smbus_io_base + SMBHST_CTL);
180
181         /* poll for transaction completion */
182         if (smbus_wait_until_done(smbus_io_base) < 0) {
183                 return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
184         }
185
186         status_register = inw(smbus_io_base + SMBHST_STATUS);
187
188         /* read results of transaction */
189         byte = inw(smbus_io_base + SMBHST_DAT) & 0xff;
190
191         if (status_register & 0x04) {
192 #if 0
193                 print_debug("Read fail ");
194                 print_debug_hex16(status_register);
195                 print_debug("\n");
196 #endif
197                 return SMBUS_ERROR;
198         }
199         return byte;
200 }
201
202 static int do_smbus_write_byte(unsigned smbus_io_base, unsigned device, unsigned address, unsigned char val)
203 {
204         unsigned global_status_register;
205
206         if (smbus_wait_until_ready(smbus_io_base) < 0) {
207                 return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
208         }
209
210         /* setup transaction */
211         /* disable interrupts */
212         outw(inw(smbus_io_base + SMBHST_CTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), smbus_io_base + SMBHST_CTL);
213         /* set the device I'm talking too */
214         outw(((device & 0x7f) << 1) | 0, smbus_io_base + SMBHST_ADDR);
215         outb(address & 0xFF, smbus_io_base + SMBHST_CMD);
216         /* set up for a byte data write */ /* FIXME */
217         outw((inw(smbus_io_base + SMBHST_CTL) & ~7) | (0x2), smbus_io_base + SMBHST_CTL);
218         /* clear any lingering errors, so the transaction will run */
219         /* Do I need to write the bits to a 1 to clear an error? */
220         outw(inw(smbus_io_base + SMBHST_STATUS), smbus_io_base + SMBHST_STATUS);
221
222         /* write the data word...*/
223         outw(val, smbus_io_base + SMBHST_DAT);
224
225         /* start the command */
226         outw((inw(smbus_io_base + SMBHST_CTL) | (1 << 3)), smbus_io_base + SMBHST_CTL);
227
228         /* poll for transaction completion */
229         if (smbus_wait_until_done(smbus_io_base) < 0) {
230                 return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
231         }
232         global_status_register = inw(smbus_io_base + SMBHST_STATUS);
233
234         if ((global_status_register & SMBUS_STATUS_MASK) != (1 << 1)) {
235                 return SMBUS_ERROR;
236         }
237         return 0;
238 }
239