Added smbus block read/write for amd8111
[coreboot.git] / src / southbridge / amd / amd8111 / amd8111_smbus.h
1 #include <device/smbus_def.h>
2
3 #define SMBGSTATUS 0xe0
4 #define SMBGCTL    0xe2
5 #define SMBHSTADDR 0xe4
6 #define SMBHSTDAT  0xe6
7 #define SMBHSTCMD  0xe8
8 #define SMBHSTFIFO 0xe9
9
10 #define SMBUS_TIMEOUT (100*1000*10)
11 #define SMBUS_STATUS_MASK 0xfbff
12
13 static inline void smbus_delay(void)
14 {
15         outb(0x80, 0x80);
16 }
17
18 static int smbus_wait_until_ready(unsigned smbus_io_base)
19 {
20         unsigned long loops;
21         loops = SMBUS_TIMEOUT;
22         do {
23                 unsigned short val;
24                 smbus_delay();
25                 val = inw(smbus_io_base + SMBGSTATUS);
26                 if ((val & 0x800) == 0) {
27                         break;
28                 }
29                 if(loops == (SMBUS_TIMEOUT / 2)) {
30                         outw(inw(smbus_io_base + SMBGSTATUS),
31                                 smbus_io_base + SMBGSTATUS);
32                 }
33         } while(--loops);
34         return loops?0:SMBUS_WAIT_UNTIL_READY_TIMEOUT;
35 }
36
37 static int smbus_wait_until_done(unsigned smbus_io_base)
38 {
39         unsigned long loops;
40         loops = SMBUS_TIMEOUT;
41         do {
42                 unsigned short val;
43                 smbus_delay();
44
45                 val = inw(smbus_io_base + SMBGSTATUS);
46                 if (((val & 0x8) == 0) | ((val & 0x0037) != 0)) {
47                         break;
48                 }
49         } while(--loops);
50         return loops?0:SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
51 }
52
53 static int do_smbus_recv_byte(unsigned smbus_io_base, unsigned device)
54 {
55         unsigned global_status_register;
56         unsigned byte;
57
58         if (smbus_wait_until_ready(smbus_io_base) < 0) {
59                 return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
60         }
61
62         /* setup transaction */
63         /* disable interrupts */
64         outw(inw(smbus_io_base + SMBGCTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), smbus_io_base + SMBGCTL);
65         /* set the device I'm talking too */
66         outw(((device & 0x7f) << 1) | 1, smbus_io_base + SMBHSTADDR);
67         /* set the command/address... */
68         outb(0, smbus_io_base + SMBHSTCMD);
69         /* set up for a send byte */
70         outw((inw(smbus_io_base + SMBGCTL) & ~7) | (0x1), smbus_io_base + SMBGCTL);
71
72         /* clear any lingering errors, so the transaction will run */
73         /* Do I need to write the bits to a 1 to clear an error? */
74         outw(inw(smbus_io_base + SMBGSTATUS), smbus_io_base + SMBGSTATUS);
75
76         /* set the data word...*/
77         outw(0, smbus_io_base + SMBHSTDAT);
78
79         /* start the command */
80         outw((inw(smbus_io_base + SMBGCTL) | (1 << 3)), smbus_io_base + SMBGCTL);
81
82
83         /* poll for transaction completion */
84         if (smbus_wait_until_done(smbus_io_base) < 0) {
85                 return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
86         }
87
88         global_status_register = inw(smbus_io_base + SMBGSTATUS);
89
90         /* read results of transaction */
91         byte = inw(smbus_io_base + SMBHSTDAT) & 0xff;
92
93         if ((global_status_register & SMBUS_STATUS_MASK) != (1 << 4)) {
94                 return SMBUS_ERROR;
95         }
96         return byte;
97 }
98
99 static int do_smbus_send_byte(unsigned smbus_io_base, unsigned device, unsigned value)
100 {
101         unsigned global_status_register;
102
103         if (smbus_wait_until_ready(smbus_io_base) < 0) {
104                 return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
105         }
106
107         /* setup transaction */
108         /* disable interrupts */
109         outw(inw(smbus_io_base + SMBGCTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), smbus_io_base + SMBGCTL);
110         /* set the device I'm talking too */
111         outw(((device & 0x7f) << 1) | 0, smbus_io_base + SMBHSTADDR);
112         /* set the command/address... */
113         outb(0, smbus_io_base + SMBHSTCMD);
114         /* set up for a send byte */
115         outw((inw(smbus_io_base + SMBGCTL) & ~7) | (0x1), smbus_io_base + SMBGCTL);
116
117         /* clear any lingering errors, so the transaction will run */
118         /* Do I need to write the bits to a 1 to clear an error? */
119         outw(inw(smbus_io_base + SMBGSTATUS), smbus_io_base + SMBGSTATUS);
120
121         /* set the data word...*/
122         outw(value, smbus_io_base + SMBHSTDAT);
123
124         /* start the command */
125         outw((inw(smbus_io_base + SMBGCTL) | (1 << 3)), smbus_io_base + SMBGCTL);
126
127
128         /* poll for transaction completion */
129         if (smbus_wait_until_done(smbus_io_base) < 0) {
130                 return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
131         }
132         global_status_register = inw(smbus_io_base + SMBGSTATUS);
133
134         if ((global_status_register & SMBUS_STATUS_MASK) != (1 << 4)) {
135                 return SMBUS_ERROR;
136         }
137         return 0;
138 }
139
140
141 static int do_smbus_read_byte(unsigned smbus_io_base, unsigned device, unsigned address)
142 {
143         unsigned global_status_register;
144         unsigned byte;
145
146         if (smbus_wait_until_ready(smbus_io_base) < 0) {
147                 return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
148         }
149
150         /* setup transaction */
151         /* disable interrupts */
152         outw(inw(smbus_io_base + SMBGCTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), smbus_io_base + SMBGCTL);
153         /* set the device I'm talking too */
154         outw(((device & 0x7f) << 1) | 1, smbus_io_base + SMBHSTADDR);
155         /* set the command/address... */
156         outb(address & 0xFF, smbus_io_base + SMBHSTCMD);
157         /* set up for a byte data read */
158         outw((inw(smbus_io_base + SMBGCTL) & ~7) | (0x2), smbus_io_base + SMBGCTL);
159
160         /* clear any lingering errors, so the transaction will run */
161         /* Do I need to write the bits to a 1 to clear an error? */
162         outw(inw(smbus_io_base + SMBGSTATUS), smbus_io_base + SMBGSTATUS);
163
164         /* clear the data word...*/
165         outw(0, smbus_io_base + SMBHSTDAT);
166
167         /* start the command */
168         outw((inw(smbus_io_base + SMBGCTL) | (1 << 3)), smbus_io_base + SMBGCTL);
169
170
171         /* poll for transaction completion */
172         if (smbus_wait_until_done(smbus_io_base) < 0) {
173                 return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
174         }
175
176         global_status_register = inw(smbus_io_base + SMBGSTATUS);
177
178         /* read results of transaction */
179         byte = inw(smbus_io_base + SMBHSTDAT) & 0xff;
180
181         if ((global_status_register & SMBUS_STATUS_MASK) != (1 << 4)) {
182                 return SMBUS_ERROR;
183         }
184         return byte;
185 }
186
187 static int do_smbus_write_byte(unsigned smbus_io_base, unsigned device, unsigned address, unsigned char val)
188 {
189         unsigned global_status_register;
190
191         if (smbus_wait_until_ready(smbus_io_base) < 0) {
192                 return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
193         }
194
195         /* setup transaction */
196         /* disable interrupts */
197         outw(inw(smbus_io_base + SMBGCTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), smbus_io_base + SMBGCTL);
198         /* set the device I'm talking too */
199         outw(((device & 0x7f) << 1) | 0, smbus_io_base + SMBHSTADDR);
200         outb(address & 0xFF, smbus_io_base + SMBHSTCMD);
201         /* set up for a byte data write */ /* FIXME */
202         outw((inw(smbus_io_base + SMBGCTL) & ~7) | (0x2), smbus_io_base + SMBGCTL);
203         /* clear any lingering errors, so the transaction will run */
204         /* Do I need to write the bits to a 1 to clear an error? */
205         outw(inw(smbus_io_base + SMBGSTATUS), smbus_io_base + SMBGSTATUS);
206
207         /* write the data word...*/
208         outw(val, smbus_io_base + SMBHSTDAT);
209
210         /* start the command */
211         outw((inw(smbus_io_base + SMBGCTL) | (1 << 3)), smbus_io_base + SMBGCTL);
212
213         /* poll for transaction completion */
214         if (smbus_wait_until_done(smbus_io_base) < 0) {
215                 return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
216         }
217         global_status_register = inw(smbus_io_base + SMBGSTATUS);
218
219         if ((global_status_register & SMBUS_STATUS_MASK) != (1 << 4)) {
220                 return SMBUS_ERROR;
221         }
222         return 0;
223 }
224
225 static int do_smbus_block_read(unsigned smbus_io_base, unsigned device, unsigned cmd, u8 bytes, u8 *buf)
226 {
227         unsigned global_status_register;
228         unsigned i;
229         u8 msglen;
230
231         if (smbus_wait_until_ready(smbus_io_base) < 0) {
232                 return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
233         }
234
235         /* setup transaction */
236         /* disable interrupts */
237         outw(inw(smbus_io_base + SMBGCTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), smbus_io_base + SMBGCTL);
238         /* set the device I'm talking too */
239         outw(((device & 0x7f) << 1) | 1, smbus_io_base + SMBHSTADDR);
240         /* set the command/address... */
241         outb(cmd & 0xFF, smbus_io_base + SMBHSTCMD);
242         /* set up for a block data read */
243         outw((inw(smbus_io_base + SMBGCTL) & ~7) | (0x5), smbus_io_base + SMBGCTL);
244
245         /* clear any lingering errors, so the transaction will run */
246         /* Do I need to write the bits to a 1 to clear an error? */
247         outw(inw(smbus_io_base + SMBGSTATUS), smbus_io_base + SMBGSTATUS);
248
249         /* clear the length word...*/
250         outw(0, smbus_io_base + SMBHSTDAT);
251
252         /* start the command */
253         outw((inw(smbus_io_base + SMBGCTL) | (1 << 3)), smbus_io_base + SMBGCTL);
254
255         /* poll for transaction completion */
256         if (smbus_wait_until_done(smbus_io_base) < 0) {
257                 return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
258         }
259
260         global_status_register = inw(smbus_io_base + SMBGSTATUS);
261
262         /* read results of transaction */
263         msglen = inw(smbus_io_base + SMBHSTDAT) & 0x3f;
264
265         if ((global_status_register & SMBUS_STATUS_MASK) != (1 << 4)) {
266                 return SMBUS_ERROR;
267         }
268
269         /* read data block */
270         for(i=0; i<msglen && i<bytes; i++) {
271                 buf[i] = inw(smbus_io_base + SMBHSTFIFO) & 0xff;
272         }
273         /* empty fifo */
274         while(bytes++<msglen) {
275                 inw(smbus_io_base + SMBHSTFIFO);
276         }
277
278         return i;
279 }
280
281 static int do_smbus_block_write(unsigned smbus_io_base, unsigned device, unsigned cmd, u8 bytes, const u8 *buf)
282 {
283         unsigned global_status_register;
284         unsigned i;
285
286         if (smbus_wait_until_ready(smbus_io_base) < 0) {
287                 return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
288         }
289
290         /* setup transaction */
291         /* disable interrupts */
292         outw(inw(smbus_io_base + SMBGCTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), smbus_io_base + SMBGCTL);
293         /* set the device I'm talking too */
294         outw(((device & 0x7f) << 1) | 0, smbus_io_base + SMBHSTADDR);
295         /* set the command/address... */
296         outb(cmd & 0xFF, smbus_io_base + SMBHSTCMD);
297         /* set up for a block data write */
298         outw((inw(smbus_io_base + SMBGCTL) & ~7) | (0x5), smbus_io_base + SMBGCTL);
299
300         /* clear any lingering errors, so the transaction will run */
301         /* Do I need to write the bits to a 1 to clear an error? */
302         outw(inw(smbus_io_base + SMBGSTATUS), smbus_io_base + SMBGSTATUS);
303
304         /* set the length word...*/
305         outw(bytes, smbus_io_base + SMBHSTDAT);
306
307         /* set the data block */
308         for(i=0; i<bytes; i++) {
309                 outw(buf[i], smbus_io_base + SMBHSTFIFO);
310         }
311
312         /* start the command */
313         outw((inw(smbus_io_base + SMBGCTL) | (1 << 3)), smbus_io_base + SMBGCTL);
314
315         /* poll for transaction completion */
316         if (smbus_wait_until_done(smbus_io_base) < 0) {
317                 return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
318         }
319         global_status_register = inw(smbus_io_base + SMBGSTATUS);
320
321         if ((global_status_register & SMBUS_STATUS_MASK) != (1 << 4)) {
322                 return SMBUS_ERROR;
323         }
324         return 0;
325 }
326
327