blob: cac9ba7943501988ed140ddd6c87288f4a4b050b [file] [log] [blame]
Arthur Heymans16fe7902017-04-12 17:01:31 +02001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com>
5 * Copyright (C) 2009 coresystems GmbH
6 * Copyright (C) 2013 Vladimir Serbinenko
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 */
17
18#include <arch/io.h>
19#include <device/smbus_def.h>
20#include "smbus.h"
21
22
23/* I801 command constants */
24#define I801_QUICK (0 << 2)
25#define I801_BYTE (1 << 2)
26#define I801_BYTE_DATA (2 << 2)
27#define I801_WORD_DATA (3 << 2)
28#define I801_BLOCK_DATA (5 << 2)
29#define I801_I2C_BLOCK_DATA (6 << 2) /* ICH5 and later */
30
31/* I801 Host Control register bits */
32#define SMBHSTCNT_INTREN (1 << 0)
33#define SMBHSTCNT_KILL (1 << 1)
34#define SMBHSTCNT_LAST_BYTE (1 << 5)
35#define SMBHSTCNT_START (1 << 6)
36#define SMBHSTCNT_PEC_EN (1 << 7) /* ICH3 and later */
37
38/* I801 Hosts Status register bits */
39#define SMBHSTSTS_BYTE_DONE (1 << 7)
40#define SMBHSTSTS_INUSE_STS (1 << 6)
41#define SMBHSTSTS_SMBALERT_STS (1 << 5)
42#define SMBHSTSTS_FAILED (1 << 4)
43#define SMBHSTSTS_BUS_ERR (1 << 3)
44#define SMBHSTSTS_DEV_ERR (1 << 2)
45#define SMBHSTSTS_INTR (1 << 1)
46#define SMBHSTSTS_HOST_BUSY (1 << 0)
47
48#define SMBUS_TIMEOUT (10 * 1000 * 100)
49
50static void smbus_delay(void)
51{
52 inb(0x80);
53}
54
55static int smbus_wait_until_ready(u16 smbus_base)
56{
57 unsigned int loops = SMBUS_TIMEOUT;
58 unsigned char byte;
59 do {
60 smbus_delay();
61 if (--loops == 0)
62 break;
63 byte = inb(smbus_base + SMBHSTSTAT);
64 } while (byte & SMBHSTSTS_HOST_BUSY);
65 return loops ? 0 : -1;
66}
67
68static int smbus_wait_until_done(u16 smbus_base)
69{
70 unsigned int loops = SMBUS_TIMEOUT;
71 unsigned char byte;
72 do {
73 smbus_delay();
74 if (--loops == 0)
75 break;
76 byte = inb(smbus_base + SMBHSTSTAT);
77 } while ((byte & SMBHSTSTS_HOST_BUSY)
78 || (byte & ~(SMBHSTSTS_INUSE_STS | SMBHSTSTS_HOST_BUSY)) == 0);
79 return loops ? 0 : -1;
80}
81
82static int smbus_wait_until_active(u16 smbus_base)
83{
84 unsigned long loops;
85 loops = SMBUS_TIMEOUT;
86 do {
87 unsigned char val;
88 smbus_delay();
89 val = inb(smbus_base + SMBHSTSTAT);
90 if ((val & SMBHSTSTS_HOST_BUSY)) {
91 break;
92 }
93 } while (--loops);
94 return loops ? 0 : -1;
95}
96
97int do_smbus_read_byte(unsigned int smbus_base, u8 device,
98 unsigned int address)
99{
100 unsigned char status;
101 unsigned char byte;
102
103 if (smbus_wait_until_ready(smbus_base) < 0)
104 return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
105 /* Set up transaction */
106 /* Disable interrupts */
107 outb(inb(smbus_base + SMBHSTCTL) & ~SMBHSTCNT_INTREN,
108 smbus_base + SMBHSTCTL);
109 /* Set the device I'm talking too */
110 outb(((device & 0x7f) << 1) | 1, smbus_base + SMBXMITADD);
111 /* Set the command/address... */
112 outb(address & 0xff, smbus_base + SMBHSTCMD);
113 /* Set up for a byte data read */
114 outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | I801_BYTE_DATA,
115 (smbus_base + SMBHSTCTL));
116 /* Clear any lingering errors, so the transaction will run */
117 outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
118
119 /* Clear the data byte... */
120 outb(0, smbus_base + SMBHSTDAT0);
121
122 /* Start the command */
123 outb((inb(smbus_base + SMBHSTCTL) | SMBHSTCNT_START),
124 smbus_base + SMBHSTCTL);
125
126 /* poll for it to start */
127 if (smbus_wait_until_active(smbus_base) < 0)
128 return SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT;
129
130 /* Poll for transaction completion */
131 if (smbus_wait_until_done(smbus_base) < 0)
132 return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
133
134 status = inb(smbus_base + SMBHSTSTAT);
135
136 /* Ignore the "In Use" status... */
137 status &= ~(SMBHSTSTS_SMBALERT_STS | SMBHSTSTS_INUSE_STS);
138
139 /* Read results of transaction */
140 byte = inb(smbus_base + SMBHSTDAT0);
141 if (status != SMBHSTSTS_INTR)
142 return SMBUS_ERROR;
143 return byte;
144}
145
146int do_smbus_write_byte(unsigned int smbus_base, u8 device,
147 unsigned int address, unsigned int data)
148{
149 unsigned char status;
150
151 if (smbus_wait_until_ready(smbus_base) < 0)
152 return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
153
154 /* Set up transaction */
155 /* Disable interrupts */
156 outb(inb(smbus_base + SMBHSTCTL) & ~SMBHSTCNT_INTREN,
157 smbus_base + SMBHSTCTL);
158 /* Set the device I'm talking too */
159 outb(((device & 0x7f) << 1) & ~0x01, smbus_base + SMBXMITADD);
160 /* Set the command/address... */
161 outb(address & 0xff, smbus_base + SMBHSTCMD);
162 /* Set up for a byte data read */
163 outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | I801_BYTE_DATA,
164 (smbus_base + SMBHSTCTL));
165 /* Clear any lingering errors, so the transaction will run */
166 outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
167
168 /* Clear the data byte... */
169 outb(data, smbus_base + SMBHSTDAT0);
170
171 /* Start the command */
172 outb((inb(smbus_base + SMBHSTCTL) | SMBHSTCNT_START),
173 smbus_base + SMBHSTCTL);
174
175 /* poll for it to start */
176 if (smbus_wait_until_active(smbus_base) < 0)
177 return SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT;
178
179 /* Poll for transaction completion */
180 if (smbus_wait_until_done(smbus_base) < 0)
181 return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
182
183 status = inb(smbus_base + SMBHSTSTAT);
184
185 /* Ignore the "In Use" status... */
186 status &= ~(SMBHSTSTS_SMBALERT_STS | SMBHSTSTS_INUSE_STS);
187
188 /* Read results of transaction */
189 if (status != SMBHSTSTS_INTR)
190 return SMBUS_ERROR;
191
192 return 0;
193}
194
195int do_smbus_block_read(unsigned int smbus_base, u8 device, u8 cmd,
196 unsigned int bytes, u8 *buf)
197{
198 u8 status;
199 int bytes_read = 0;
200 unsigned int loops = SMBUS_TIMEOUT;
201 if (smbus_wait_until_ready(smbus_base) < 0)
202 return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
203
204 /* Set up transaction */
205 /* Disable interrupts */
206 outb(inb(smbus_base + SMBHSTCTL) & ~SMBHSTCNT_INTREN,
207 smbus_base + SMBHSTCTL);
208 /* Set the device I'm talking too */
209 outb(((device & 0x7f) << 1) | 1, smbus_base + SMBXMITADD);
210 /* Set the command/address... */
211 outb(cmd & 0xff, smbus_base + SMBHSTCMD);
212 /* Set up for a block data read */
213 outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | I801_BLOCK_DATA,
214 (smbus_base + SMBHSTCTL));
215 /* Clear any lingering errors, so the transaction will run */
216 outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
217
218 /* Start the command */
219 outb((inb(smbus_base + SMBHSTCTL) | SMBHSTCNT_START),
220 smbus_base + SMBHSTCTL);
221
222 /* poll for it to start */
223 if (smbus_wait_until_active(smbus_base) < 0)
224 return SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT;
225
226 /* Poll for transaction completion */
227 do {
228 loops--;
229 status = inb(smbus_base + SMBHSTSTAT);
230 if (status & (SMBHSTSTS_FAILED | /* FAILED */
231 SMBHSTSTS_BUS_ERR | /* BUS ERR */
232 SMBHSTSTS_DEV_ERR)) /* DEV ERR */
233 return SMBUS_ERROR;
234
235 if (status & SMBHSTSTS_BYTE_DONE) { /* Byte done */
236 *buf = inb(smbus_base + SMBBLKDAT);
237 buf++;
238 bytes_read++;
239 if (--bytes == 1) {
240 /* indicate that next byte is the last one */
241 outb(inb(smbus_base + SMBHSTCTL)
242 | SMBHSTCNT_LAST_BYTE,
243 smbus_base + SMBHSTCTL);
244 }
245 outb(status, smbus_base + SMBHSTSTAT);
246 }
247 } while ((status & SMBHSTSTS_HOST_BUSY) && loops);
248
249 return bytes_read;
250}
251
252int do_smbus_block_write(unsigned int smbus_base, u8 device, u8 cmd,
253 unsigned int bytes, const u8 *buf)
254{
255 u8 status;
256 unsigned int loops = SMBUS_TIMEOUT;
257
258 if (smbus_wait_until_ready(smbus_base) < 0)
259 return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
260
261 /* Set up transaction */
262 /* Disable interrupts */
263 outb(inb(smbus_base + SMBHSTCTL) & ~SMBHSTCNT_INTREN,
264 smbus_base + SMBHSTCTL);
265 /* Set the device I'm talking too */
266 outb(((device & 0x7f) << 1) & ~0x01, smbus_base + SMBXMITADD);
267 /* Set the command/address... */
268 outb(cmd & 0xff, smbus_base + SMBHSTCMD);
269 /* Set up for a block data write */
270 outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | I801_BLOCK_DATA,
271 (smbus_base + SMBHSTCTL));
272 /* Clear any lingering errors, so the transaction will run */
273 outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
274
275 /* set number of bytes to transfer */
276 outb(bytes, smbus_base + SMBHSTDAT0);
277
278 outb(*buf++, smbus_base + SMBBLKDAT);
279 bytes--;
280
281 /* Start the command */
282 outb((inb(smbus_base + SMBHSTCTL) | SMBHSTCNT_START),
283 smbus_base + SMBHSTCTL);
284
285 /* poll for it to start */
286 if (smbus_wait_until_active(smbus_base) < 0)
287 return SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT;
288
289 /* Poll for transaction completion */
290 do {
291 loops--;
292 status = inb(smbus_base + SMBHSTSTAT);
293 if (status & (SMBHSTSTS_FAILED | /* FAILED */
294 SMBHSTSTS_BUS_ERR | /* BUS ERR */
295 SMBHSTSTS_DEV_ERR)) /* DEV ERR */
296 return SMBUS_ERROR;
297
298 if (status & SMBHSTSTS_BYTE_DONE) {
299 outb(*buf++, smbus_base + SMBBLKDAT);
300 outb(status, smbus_base + SMBHSTSTAT);
301 }
302 } while ((status & SMBHSTSTS_HOST_BUSY) && loops);
303
304 return 0;
305}
306
307/* Only since ICH5 */
308int do_i2c_block_read(unsigned int smbus_base, u8 device,
309 unsigned int offset, u32 bytes, u8 *buf)
310{
311 u8 status;
312 int bytes_read = 0;
313 unsigned int loops = SMBUS_TIMEOUT;
314 if (smbus_wait_until_ready(smbus_base) < 0)
315 return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
316
317 /* Set upp transaction */
318 /* Disable interrupts */
319 outb(inb(smbus_base + SMBHSTCTL) & SMBHSTCNT_INTREN,
320 smbus_base + SMBHSTCTL);
321 /* Set the device I'm talking to */
322 outb((device & 0x7f) << 1, smbus_base + SMBXMITADD);
323
324 /* device offset */
325 outb(offset, smbus_base + SMBHSTDAT1);
326
327 /* Set up for a i2c block data read */
328 outb((inb(smbus_base + SMBHSTCTL) & 0xc3) | I801_I2C_BLOCK_DATA,
329 (smbus_base + SMBHSTCTL));
330
331 /* Clear any lingering errors, so the transaction will run */
332 outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
333 /* Start the command */
334 outb((inb(smbus_base + SMBHSTCTL) | SMBHSTCNT_START),
335 smbus_base + SMBHSTCTL);
336
337 /* poll for it to start */
338 if (smbus_wait_until_active(smbus_base) < 0)
339 return SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT;
340
341 /* Poll for transaction completion */
342 do {
343 loops--;
344 status = inb(smbus_base + SMBHSTSTAT);
345 if (status & (SMBHSTSTS_FAILED | /* FAILED */
346 SMBHSTSTS_BUS_ERR | /* BUS ERR */
347 SMBHSTSTS_DEV_ERR)) /* DEV ERR */
348 return SMBUS_ERROR;
349
350 if (status & SMBHSTSTS_BYTE_DONE) {
351 *buf = inb(smbus_base + SMBBLKDAT);
352 buf++;
353 bytes_read++;
354 if (--bytes == 1) {
355 /* indicate that next byte is the last one */
356 outb(inb(smbus_base + SMBHSTCTL)
357 | SMBHSTCNT_LAST_BYTE,
358 smbus_base + SMBHSTCTL);
359 }
360 outb(status, smbus_base + SMBHSTSTAT);
361 }
362 } while ((status & SMBHSTSTS_HOST_BUSY) && loops);
363
364 return bytes_read;
365}