8067ffb9a5666dd428590ff2d3c39e5b1909c0c8
[coreboot.git] / src / southbridge / nvidia / ck804 / ck804_smbus.h
1 /*
2  * Copyright 2004 Tyan Computer
3  *  by yhlu@tyan.com
4  */
5
6 #include <device/smbus_def.h>
7
8 #define SMBHSTSTAT  0x1
9 #define SMBHSTPRTCL 0x0
10 #define SMBHSTCMD   0x3
11 #define SMBXMITADD  0x2
12 #define SMBHSTDAT0  0x4
13 #define SMBHSTDAT1  0x5
14
15 /*
16  * Between 1-10 seconds, We should never timeout normally.
17  * Longer than this is just painful when a timeout condition occurs.
18  */
19 #define SMBUS_TIMEOUT (100 * 1000 * 10)
20
21 static inline void smbus_delay(void)
22 {
23         outb(0x80, 0x80);
24 }
25
26 static int smbus_wait_until_ready(unsigned smbus_io_base)
27 {
28         unsigned long loops;
29         loops = SMBUS_TIMEOUT;
30         do {
31                 unsigned char val;
32                 smbus_delay();
33                 val = inb(smbus_io_base + SMBHSTSTAT);
34                 val &= 0x1f;
35                 if (val == 0)
36                         return 0;
37                 outb(val, smbus_io_base + SMBHSTSTAT);
38         } while (--loops);
39         return -2;
40 }
41
42 static int smbus_wait_until_done(unsigned smbus_io_base)
43 {
44         unsigned long loops;
45         loops = SMBUS_TIMEOUT;
46         do {
47                 unsigned char val;
48                 smbus_delay();
49                 val = inb(smbus_io_base + SMBHSTSTAT);
50                 if ((val & 0xff) != 0)
51                         return 0;
52         } while (--loops);
53         return -3;
54 }
55
56 static int do_smbus_recv_byte(unsigned smbus_io_base, unsigned device)
57 {
58         unsigned char global_status_register, byte;
59
60 #if 0
61         /* Not needed, upon write to PRTCL, the status will be auto-cleared. */
62         if (smbus_wait_until_ready(smbus_io_base) < 0)
63                 return -2;
64 #endif
65
66         /* Set the device I'm talking to. */
67         outb(((device & 0x7f) << 1) | 1, smbus_io_base + SMBXMITADD);
68         smbus_delay();
69
70         /* Set the command/address. */
71         outb(0, smbus_io_base + SMBHSTCMD);
72         smbus_delay();
73
74         /* Byte data recv */
75         outb(0x05, smbus_io_base + SMBHSTPRTCL);
76         smbus_delay();
77
78         /* Poll for transaction completion. */
79         if (smbus_wait_until_done(smbus_io_base) < 0)
80                 return -3;
81
82         /* Lose check */
83         global_status_register = inb(smbus_io_base + SMBHSTSTAT) & 0x80;
84
85         /* Read results of transaction. */
86         byte = inb(smbus_io_base + SMBHSTDAT0);
87
88         /* Lose check, otherwise it should be 0. */
89         if (global_status_register != 0x80)
90                 return -1;
91
92         return byte;
93 }
94
95 static int do_smbus_send_byte(unsigned smbus_io_base, unsigned device,
96                               unsigned char val)
97 {
98         unsigned global_status_register;
99
100 #if 0
101         /* Not needed, upon write to PRTCL, the status will be auto-cleared. */
102         if (smbus_wait_until_ready(smbus_io_base) < 0)
103                 return -2;
104 #endif
105
106         outb(val, smbus_io_base + SMBHSTDAT0);
107         smbus_delay();
108
109         /* Set the device I'm talking to. */
110         outb(((device & 0x7f) << 1) | 0, smbus_io_base + SMBXMITADD);
111         smbus_delay();
112
113         outb(0, smbus_io_base + SMBHSTCMD);
114         smbus_delay();
115
116         /* Set up for a byte data write. */
117         outb(0x04, smbus_io_base + SMBHSTPRTCL);
118         smbus_delay();
119
120         /* Poll for transaction completion. */
121         if (smbus_wait_until_done(smbus_io_base) < 0)
122                 return -3;
123
124         /* Lose check */
125         global_status_register = inb(smbus_io_base + SMBHSTSTAT) & 0x80;
126
127         if (global_status_register != 0x80)
128                 return -1;
129
130         return 0;
131 }
132
133 static int do_smbus_read_byte(unsigned smbus_io_base, unsigned device,
134                               unsigned address)
135 {
136         unsigned char global_status_register, byte;
137
138 #if 0
139         /* Not needed, upon write to PRTCL, the status will be auto-cleared. */
140         if (smbus_wait_until_ready(smbus_io_base) < 0)
141                 return -2;
142 #endif
143
144         /* Set the device I'm talking to. */
145         outb(((device & 0x7f) << 1) | 1, smbus_io_base + SMBXMITADD);
146         smbus_delay();
147
148         /* Set the command/address. */
149         outb(address & 0xff, smbus_io_base + SMBHSTCMD);
150         smbus_delay();
151
152         /* Byte data read */
153         outb(0x07, smbus_io_base + SMBHSTPRTCL);
154         smbus_delay();
155
156         /* Poll for transaction completion. */
157         if (smbus_wait_until_done(smbus_io_base) < 0)
158                 return -3;
159
160         /* Lose check */
161         global_status_register = inb(smbus_io_base + SMBHSTSTAT) & 0x80;
162
163         /* Read results of transaction. */
164         byte = inb(smbus_io_base + SMBHSTDAT0);
165
166         /* Lose check, otherwise it should be 0. */
167         if (global_status_register != 0x80)
168                 return -1;
169
170         return byte;
171 }
172
173 static int do_smbus_write_byte(unsigned smbus_io_base, unsigned device,
174                                unsigned address, unsigned char val)
175 {
176         unsigned global_status_register;
177
178 #if 0
179         /* Not needed, upon write to PRTCL, the status will be auto-cleared. */
180         if (smbus_wait_until_ready(smbus_io_base) < 0)
181                 return -2;
182 #endif
183
184         outb(val, smbus_io_base + SMBHSTDAT0);
185         smbus_delay();
186
187         /* Set the device I'm talking to. */
188         outb(((device & 0x7f) << 1) | 0, smbus_io_base + SMBXMITADD);
189         smbus_delay();
190
191         outb(address & 0xff, smbus_io_base + SMBHSTCMD);
192         smbus_delay();
193
194         /* Set up for a byte data write. */
195         outb(0x06, smbus_io_base + SMBHSTPRTCL);
196         smbus_delay();
197
198         /* Poll for transaction completion. */
199         if (smbus_wait_until_done(smbus_io_base) < 0)
200                 return -3;
201
202         /* Lose check */
203         global_status_register = inb(smbus_io_base + SMBHSTSTAT) & 0x80;
204
205         if (global_status_register != 0x80)
206                 return -1;
207
208         return 0;
209 }