bd34dc3aa5d6d6928e7c969c8c7cac983d5e1977
[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 #if 0
27 /* Not needed, upon write to PRTCL, the status will be auto-cleared. */
28 static int smbus_wait_until_ready(unsigned smbus_io_base)
29 {
30         unsigned long loops;
31         loops = SMBUS_TIMEOUT;
32         do {
33                 unsigned char val;
34                 smbus_delay();
35                 val = inb(smbus_io_base + SMBHSTSTAT);
36                 val &= 0x1f;
37                 if (val == 0)
38                         return 0;
39                 outb(val, smbus_io_base + SMBHSTSTAT);
40         } while (--loops);
41         return -2;
42 }
43 #endif
44
45 static int smbus_wait_until_done(unsigned smbus_io_base)
46 {
47         unsigned long loops;
48         loops = SMBUS_TIMEOUT;
49         do {
50                 unsigned char val;
51                 smbus_delay();
52                 val = inb(smbus_io_base + SMBHSTSTAT);
53                 if ((val & 0xff) != 0)
54                         return 0;
55         } while (--loops);
56         return -3;
57 }
58
59 #ifndef __PRE_RAM__
60 static int do_smbus_recv_byte(unsigned smbus_io_base, unsigned device)
61 {
62         unsigned char global_status_register, byte;
63
64 #if 0
65         /* Not needed, upon write to PRTCL, the status will be auto-cleared. */
66         if (smbus_wait_until_ready(smbus_io_base) < 0)
67                 return -2;
68 #endif
69
70         /* Set the device I'm talking to. */
71         outb(((device & 0x7f) << 1) | 1, smbus_io_base + SMBXMITADD);
72         smbus_delay();
73
74         /* Set the command/address. */
75         outb(0, smbus_io_base + SMBHSTCMD);
76         smbus_delay();
77
78         /* Byte data recv */
79         outb(0x05, smbus_io_base + SMBHSTPRTCL);
80         smbus_delay();
81
82         /* Poll for transaction completion. */
83         if (smbus_wait_until_done(smbus_io_base) < 0)
84                 return -3;
85
86         /* Lose check */
87         global_status_register = inb(smbus_io_base + SMBHSTSTAT) & 0x80;
88
89         /* Read results of transaction. */
90         byte = inb(smbus_io_base + SMBHSTDAT0);
91
92         /* Lose check, otherwise it should be 0. */
93         if (global_status_register != 0x80)
94                 return -1;
95
96         return byte;
97 }
98
99 static int do_smbus_send_byte(unsigned smbus_io_base, unsigned device,
100                               unsigned char val)
101 {
102         unsigned global_status_register;
103
104 #if 0
105         /* Not needed, upon write to PRTCL, the status will be auto-cleared. */
106         if (smbus_wait_until_ready(smbus_io_base) < 0)
107                 return -2;
108 #endif
109
110         outb(val, smbus_io_base + SMBHSTDAT0);
111         smbus_delay();
112
113         /* Set the device I'm talking to. */
114         outb(((device & 0x7f) << 1) | 0, smbus_io_base + SMBXMITADD);
115         smbus_delay();
116
117         outb(0, smbus_io_base + SMBHSTCMD);
118         smbus_delay();
119
120         /* Set up for a byte data write. */
121         outb(0x04, smbus_io_base + SMBHSTPRTCL);
122         smbus_delay();
123
124         /* Poll for transaction completion. */
125         if (smbus_wait_until_done(smbus_io_base) < 0)
126                 return -3;
127
128         /* Lose check */
129         global_status_register = inb(smbus_io_base + SMBHSTSTAT) & 0x80;
130
131         if (global_status_register != 0x80)
132                 return -1;
133
134         return 0;
135 }
136 #endif
137
138 static int do_smbus_read_byte(unsigned smbus_io_base, unsigned device,
139                               unsigned address)
140 {
141         unsigned char global_status_register, byte;
142
143 #if 0
144         /* Not needed, upon write to PRTCL, the status will be auto-cleared. */
145         if (smbus_wait_until_ready(smbus_io_base) < 0)
146                 return -2;
147 #endif
148
149         /* Set the device I'm talking to. */
150         outb(((device & 0x7f) << 1) | 1, smbus_io_base + SMBXMITADD);
151         smbus_delay();
152
153         /* Set the command/address. */
154         outb(address & 0xff, smbus_io_base + SMBHSTCMD);
155         smbus_delay();
156
157         /* Byte data read */
158         outb(0x07, smbus_io_base + SMBHSTPRTCL);
159         smbus_delay();
160
161         /* Poll for transaction completion. */
162         if (smbus_wait_until_done(smbus_io_base) < 0)
163                 return -3;
164
165         /* Lose check */
166         global_status_register = inb(smbus_io_base + SMBHSTSTAT) & 0x80;
167
168         /* Read results of transaction. */
169         byte = inb(smbus_io_base + SMBHSTDAT0);
170
171         /* Lose check, otherwise it should be 0. */
172         if (global_status_register != 0x80)
173                 return -1;
174
175         return byte;
176 }
177
178 static int do_smbus_write_byte(unsigned smbus_io_base, unsigned device,
179                                unsigned address, unsigned char val)
180 {
181         unsigned global_status_register;
182
183 #if 0
184         /* Not needed, upon write to PRTCL, the status will be auto-cleared. */
185         if (smbus_wait_until_ready(smbus_io_base) < 0)
186                 return -2;
187 #endif
188
189         outb(val, smbus_io_base + SMBHSTDAT0);
190         smbus_delay();
191
192         /* Set the device I'm talking to. */
193         outb(((device & 0x7f) << 1) | 0, smbus_io_base + SMBXMITADD);
194         smbus_delay();
195
196         outb(address & 0xff, smbus_io_base + SMBHSTCMD);
197         smbus_delay();
198
199         /* Set up for a byte data write. */
200         outb(0x06, smbus_io_base + SMBHSTPRTCL);
201         smbus_delay();
202
203         /* Poll for transaction completion. */
204         if (smbus_wait_until_done(smbus_io_base) < 0)
205                 return -3;
206
207         /* Lose check */
208         global_status_register = inb(smbus_io_base + SMBHSTSTAT) & 0x80;
209
210         if (global_status_register != 0x80)
211                 return -1;
212
213         return 0;
214 }