cb4a1e731dbed1f6029f0ae4970fe47730b5e775
[coreboot.git] / src / southbridge / amd / cs5536 / cs5536_smbus2.h
1 //#include <device/smbus_def.h>
2 #define SMBUS_ERROR -1
3 #define SMBUS_WAIT_UNTIL_READY_TIMEOUT -2
4 #define SMBUS_WAIT_UNTIL_DONE_TIMEOUT  -3
5
6 #define SMB_SDA         0x00
7 #define SMB_STS         0x01
8 #define SMB_CTRL_STS    0x02
9 #define SMB_CTRL1       0x03
10 #define SMB_ADD         0x04
11 #define SMB_CTRL2       0x05
12 #define SMB_CTRL3       0x06
13
14 #define SMB_STS_SLVSTP  (0x01 << 7)
15 #define SMB_STS_SDAST   (0x01 << 6)
16 #define SMB_STS_BER     (0x01 << 5)
17 #define SMB_STS_NEGACK  (0x01 << 4)
18 #define SMB_STS_STASTR  (0x01 << 3)
19 #define SMB_STS_NMATCH  (0x01 << 2)
20 #define SMB_STS_MASTER  (0x01 << 1)
21 #define SMB_STS_XMIT    (0x01 << 0)
22
23 #define SMB_CSTS_TGSCL  (0x01 << 5)
24 #define SMB_CSTS_TSDA   (0x01 << 4)
25 #define SMB_CSTS_GCMTCH (0x01 << 3)
26 #define SMB_CSTS_MATCH  (0x01 << 2)
27 #define SMB_CSTS_BB     (0x01 << 1)
28 #define SMB_CSTS_BUSY   (0x01 << 0)
29
30 #define SMB_CTRL1_STASTRE (0x01 << 7)
31 #define SMB_CTRL1_NMINTE  (0x01 << 6)
32 #define SMB_CTRL1_GCMEN   (0x01 << 5)
33 #define SMB_CTRL1_ACK     (0x01 << 4)
34 #define SMB_CTRL1_RSVD    (0x01 << 3)
35 #define SMB_CTRL1_INTEN   (0x01 << 2)
36 #define SMB_CTRL1_STOP    (0x01 << 1)
37 #define SMB_CTRL1_START   (0x01 << 0)
38
39 #define SMB_ADD_SAEN      (0x01 << 7)
40
41 #define SMB_CTRL2_ENABLE  0x01
42
43 #define SMBUS_TIMEOUT (100*1000*10)
44 #define SMBUS_STATUS_MASK 0xfbff
45
46
47 static void smbus_delay(void)
48 {
49         inb(0x80);
50 }
51
52 static int smbus_wait(unsigned smbus_io_base) {
53         unsigned long loops = SMBUS_TIMEOUT;
54         unsigned char val;
55
56         do {
57                 smbus_delay();
58                 val = inb(smbus_io_base + SMB_STS);
59                 if ((val & SMB_STS_SDAST) != 0)
60                         break;
61                 if (val & (SMB_STS_BER | SMB_STS_NEGACK)) {
62                         printk_debug("SMBUS WAIT ERROR %x\n", val);
63                         return SMBUS_ERROR;
64                 }
65         } while(--loops);
66
67         outb(0, smbus_io_base + SMB_STS);
68         return loops ? 0 : SMBUS_WAIT_UNTIL_READY_TIMEOUT;
69 }
70
71 static int smbus_write(unsigned smbus_io_base, unsigned char byte) {
72
73         outb(byte, smbus_io_base + SMB_SDA);
74         return smbus_wait(smbus_io_base);
75 }
76
77 /* generate a smbus start condition */
78 static int smbus_start_condition(unsigned smbus_io_base)
79 {
80         unsigned char val;
81
82         /* issue a START condition */
83         val = inb(smbus_io_base + SMB_CTRL1);
84         outb(val | SMB_CTRL1_START, smbus_io_base + SMB_CTRL1);
85
86         /* check for bus conflict */
87         val = inb(smbus_io_base + SMB_STS);
88         if ((val & SMB_STS_BER) != 0)
89                 return SMBUS_ERROR;
90
91         return smbus_wait(smbus_io_base);
92 }
93
94 static int smbus_check_stop_condition(unsigned smbus_io_base)
95 {
96         unsigned char val;
97         unsigned long loops;
98         loops = SMBUS_TIMEOUT;
99         /* check for SDA status */
100         do {
101                 smbus_delay();
102                 val = inb(smbus_io_base + SMB_CTRL1);
103                 if ((val & SMB_CTRL1_STOP) == 0) {
104                         break;
105                 }
106         } while(--loops);
107         return loops?0:SMBUS_WAIT_UNTIL_READY_TIMEOUT;
108
109         /* Make sure everything is cleared and ready to go */
110
111         val = inb(smbus_io_base + SMB_CTRL1);
112         outb(val & ~(SMB_CTRL1_STASTRE | SMB_CTRL1_NMINTE),
113                         smbus_io_base + SMB_CTRL1);
114
115         outb(SMB_STS_BER | SMB_STS_NEGACK | SMB_STS_STASTR,
116                         smbus_io_base + SMB_STS);
117
118         val = inb(smbus_io_base + SMB_CTRL_STS);
119         outb(val | SMB_CSTS_BB, smbus_io_base + SMB_CTRL_STS);
120 }
121
122 static int smbus_stop_condition(unsigned smbus_io_base)
123 {
124         unsigned char val;
125         val = inb(smbus_io_base + SMB_CTRL1);
126         outb(SMB_CTRL1_STOP, smbus_io_base + SMB_CTRL1);
127
128         return 0;
129 }
130
131 static int smbus_ack(unsigned smbus_io_base, int state)
132 {
133         unsigned char val = inb(smbus_io_base + SMB_CTRL1);
134
135         if (state)
136                 outb(val | SMB_CTRL1_ACK, smbus_io_base + SMB_CTRL1);
137         else
138                 outb(val & ~SMB_CTRL1_ACK, smbus_io_base + SMB_CTRL1);
139
140         return 0;
141 }
142
143 static int smbus_send_slave_address(unsigned smbus_io_base, unsigned char device)
144 {
145         unsigned char val;
146
147         /* send the slave address */
148         outb(device, smbus_io_base + SMB_SDA);
149
150         /* check for bus conflict and NACK */
151         val = inb(smbus_io_base + SMB_STS);
152         if (((val & SMB_STS_BER)    != 0) ||
153             ((val & SMB_STS_NEGACK) != 0)) {
154                 printk_debug("SEND SLAVE ERROR (%x)\n", val);
155                 return SMBUS_ERROR;
156         }
157         return smbus_wait(smbus_io_base);
158 }
159
160 static int smbus_send_command(unsigned smbus_io_base, unsigned char command)
161 {
162         unsigned char val;
163
164         /* send the command */
165         outb(command, smbus_io_base + SMB_SDA);
166
167         /* check for bus conflict and NACK */
168         val = inb(smbus_io_base + SMB_STS);
169         if (((val & SMB_STS_BER)    != 0) ||
170             ((val & SMB_STS_NEGACK) != 0))
171                 return SMBUS_ERROR;
172
173         return smbus_wait(smbus_io_base);
174 }
175
176 static void _doread(unsigned smbus_io_base, unsigned char device,
177                 unsigned char address, unsigned char *data, int count)
178 {
179         int ret;
180         int index = 0;
181         unsigned char val;
182
183         if ((ret = smbus_check_stop_condition(smbus_io_base)))
184                 goto err;
185
186         index++;
187
188         if ((ret = smbus_start_condition(smbus_io_base)))
189                 goto err;
190
191         index++; /* 2 */
192         if ((ret = smbus_send_slave_address(smbus_io_base, device)))
193                 goto err;
194
195         index++;
196         if ((ret = smbus_send_command(smbus_io_base, address)))
197                 goto err;
198
199         index++;
200         if ((ret = smbus_start_condition(smbus_io_base)))
201                 goto err;
202
203         /* Clear the ack for multiple byte reads */
204         smbus_ack(smbus_io_base, (count == 1) ? 1 : 0);
205
206         index++;
207         if ((ret = smbus_send_slave_address(smbus_io_base, device | 0x01)))
208                 goto err;
209
210         while(count) {
211                 /* Set the ACK if this is the next to last byte */
212                 smbus_ack(smbus_io_base, (count == 2) ? 1 : 0);
213
214                 /* Set the stop bit if this is the last byte to read */
215
216                 if (count == 1)
217                         smbus_stop_condition(smbus_io_base);
218
219                 val = inb(smbus_io_base + SMB_SDA);
220                 *data++ = val;
221
222                 if (count > 1) {
223                         int ret = smbus_wait(smbus_io_base);
224                         if (ret)
225                                 return ret;
226                 }
227
228                 count--;
229         }
230
231         return;
232
233  err:
234         printk_debug("SMBUS READ ERROR (%d): %d\n", index, ret);
235 }
236
237 static unsigned char do_smbus_read_byte(unsigned smbus_io_base,
238                 unsigned char device,
239                                         unsigned char address)
240 {
241         unsigned char val = 0;
242         _doread(smbus_io_base, device, address, &val, sizeof(val));
243         return val;
244 }
245
246 static unsigned short do_smbus_read_word(unsigned smbus_io_base,
247                 unsigned char device, unsigned char address)
248 {
249         unsigned short val = 0;
250         _doread(smbus_io_base, device, address, (unsigned char *) &val,
251                         sizeof(val));
252         return val;
253 }
254
255 static int _dowrite(unsigned smbus_io_base, unsigned char device,
256                 unsigned char address, unsigned char *data, int count) {
257
258         int ret;
259
260         if ((ret = smbus_check_stop_condition(smbus_io_base)))
261                 goto err;
262
263         if ((ret = smbus_start_condition(smbus_io_base)))
264                 goto err;
265
266         if ((ret = smbus_send_slave_address(smbus_io_base, device)))
267                 goto err;
268
269         if ((ret = smbus_send_command(smbus_io_base, address)))
270                 goto err;
271
272         while(count) {
273                 if ((ret = smbus_write(smbus_io_base, *data++)))
274                         goto err;
275                 count--;
276         }
277
278         smbus_stop_condition(smbus_io_base);
279         return 0;
280
281  err:
282         printk_debug("SMBUS WRITE ERROR: %d\n", ret);
283         return -1;
284 }
285
286
287 static int do_smbus_write_byte(unsigned smbus_io_base, unsigned char device,
288                 unsigned char address, unsigned char data)
289 {
290         return _dowrite(smbus_io_base, device, address,
291                         (unsigned char *) &data, 1);
292 }
293
294 static int do_smbus_write_word(unsigned smbus_io_base, unsigned char device, unsigned char address,
295                                unsigned short data)
296 {
297         return _dowrite(smbus_io_base, device ,address, (unsigned char *) &data, 2);
298 }