blob: b2a78c9fc1fb6729508c4ff5c08c68f39a5e6fad [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>
Kyösti Mälkkib5d998b2017-08-20 21:36:08 +030019#include <console/console.h>
Arthur Heymans16fe7902017-04-12 17:01:31 +020020#include <device/smbus_def.h>
Arthur Heymans1b04aa22017-08-04 14:28:50 +020021#include <stdlib.h>
Arthur Heymans16fe7902017-04-12 17:01:31 +020022#include "smbus.h"
23
24
Kyösti Mälkkib5d998b2017-08-20 21:36:08 +030025#if IS_ENABLED(CONFIG_DEBUG_SMBUS)
26#define dprintk(args...) printk(BIOS_DEBUG, ##args)
27#else
28#define dprintk(args...) do {} while (0)
29#endif
30
Arthur Heymans16fe7902017-04-12 17:01:31 +020031/* I801 command constants */
32#define I801_QUICK (0 << 2)
33#define I801_BYTE (1 << 2)
34#define I801_BYTE_DATA (2 << 2)
35#define I801_WORD_DATA (3 << 2)
36#define I801_BLOCK_DATA (5 << 2)
37#define I801_I2C_BLOCK_DATA (6 << 2) /* ICH5 and later */
38
39/* I801 Host Control register bits */
40#define SMBHSTCNT_INTREN (1 << 0)
41#define SMBHSTCNT_KILL (1 << 1)
42#define SMBHSTCNT_LAST_BYTE (1 << 5)
43#define SMBHSTCNT_START (1 << 6)
44#define SMBHSTCNT_PEC_EN (1 << 7) /* ICH3 and later */
45
46/* I801 Hosts Status register bits */
47#define SMBHSTSTS_BYTE_DONE (1 << 7)
48#define SMBHSTSTS_INUSE_STS (1 << 6)
49#define SMBHSTSTS_SMBALERT_STS (1 << 5)
50#define SMBHSTSTS_FAILED (1 << 4)
51#define SMBHSTSTS_BUS_ERR (1 << 3)
52#define SMBHSTSTS_DEV_ERR (1 << 2)
53#define SMBHSTSTS_INTR (1 << 1)
54#define SMBHSTSTS_HOST_BUSY (1 << 0)
55
Kyösti Mälkki957511c2017-08-20 21:36:11 +030056/* For SMBXMITADD register. */
57#define XMIT_WRITE(dev) (((dev) << 1) | 0)
58#define XMIT_READ(dev) (((dev) << 1) | 1)
59
Arthur Heymans16fe7902017-04-12 17:01:31 +020060#define SMBUS_TIMEOUT (10 * 1000 * 100)
Elyes HAOUASb0f19882018-06-09 11:59:00 +020061#define SMBUS_BLOCK_MAXLEN 32
Arthur Heymans16fe7902017-04-12 17:01:31 +020062
63static void smbus_delay(void)
64{
65 inb(0x80);
66}
67
Kyösti Mälkki957511c2017-08-20 21:36:11 +030068static int recover_master(int smbus_base, int ret)
Arthur Heymans16fe7902017-04-12 17:01:31 +020069{
Kyösti Mälkki957511c2017-08-20 21:36:11 +030070 /* TODO: Depending of the failure, drive KILL transaction
71 * or force soft reset on SMBus master controller.
72 */
73 printk(BIOS_ERR, "SMBus: Fatal master timeout (%d)\n", ret);
74 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +020075}
76
Kyösti Mälkki957511c2017-08-20 21:36:11 +030077static int setup_command(unsigned int smbus_base, u8 ctrl, u8 xmitadd)
Arthur Heymans16fe7902017-04-12 17:01:31 +020078{
79 unsigned int loops = SMBUS_TIMEOUT;
Kyösti Mälkki957511c2017-08-20 21:36:11 +030080 u8 host_busy;
81
Arthur Heymans16fe7902017-04-12 17:01:31 +020082 do {
83 smbus_delay();
Kyösti Mälkki957511c2017-08-20 21:36:11 +030084 host_busy = inb(smbus_base + SMBHSTSTAT) & SMBHSTSTS_HOST_BUSY;
85 } while (--loops && host_busy);
86
87 if (loops == 0)
88 return recover_master(smbus_base,
89 SMBUS_WAIT_UNTIL_READY_TIMEOUT);
90
91 /* Clear any lingering errors, so the transaction will run. */
92 outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
93
94 /* Set up transaction */
95 /* Disable interrupts */
96 outb(ctrl, (smbus_base + SMBHSTCTL));
97
98 /* Set the device I'm talking to. */
99 outb(xmitadd, smbus_base + SMBXMITADD);
100
101 return 0;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200102}
103
104static int smbus_wait_until_active(u16 smbus_base)
105{
106 unsigned long loops;
107 loops = SMBUS_TIMEOUT;
108 do {
109 unsigned char val;
110 smbus_delay();
111 val = inb(smbus_base + SMBHSTSTAT);
112 if ((val & SMBHSTSTS_HOST_BUSY)) {
113 break;
114 }
115 } while (--loops);
116 return loops ? 0 : -1;
117}
118
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300119static int smbus_wait_until_done(u16 smbus_base)
120{
121 unsigned int loops = SMBUS_TIMEOUT;
122 unsigned char byte;
123 do {
124 smbus_delay();
125 if (--loops == 0)
126 break;
127 byte = inb(smbus_base + SMBHSTSTAT);
128 } while ((byte & SMBHSTSTS_HOST_BUSY)
129 || (byte & ~(SMBHSTSTS_INUSE_STS | SMBHSTSTS_HOST_BUSY)) == 0);
130 return loops ? 0 : -1;
131}
132
Arthur Heymans16fe7902017-04-12 17:01:31 +0200133int do_smbus_read_byte(unsigned int smbus_base, u8 device,
134 unsigned int address)
135{
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300136 int ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200137 unsigned char status;
138 unsigned char byte;
139
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300140 /* Set up for a byte data read. */
141 ret = setup_command(smbus_base, I801_BYTE_DATA, XMIT_READ(device));
142 if (ret < 0)
143 return ret;
144
Arthur Heymans16fe7902017-04-12 17:01:31 +0200145 /* Set the command/address... */
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300146 outb(address, smbus_base + SMBHSTCMD);
Arthur Heymans16fe7902017-04-12 17:01:31 +0200147
148 /* Clear the data byte... */
149 outb(0, smbus_base + SMBHSTDAT0);
150
151 /* Start the command */
152 outb((inb(smbus_base + SMBHSTCTL) | SMBHSTCNT_START),
153 smbus_base + SMBHSTCTL);
154
155 /* poll for it to start */
156 if (smbus_wait_until_active(smbus_base) < 0)
157 return SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT;
158
159 /* Poll for transaction completion */
160 if (smbus_wait_until_done(smbus_base) < 0)
161 return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
162
163 status = inb(smbus_base + SMBHSTSTAT);
164
165 /* Ignore the "In Use" status... */
166 status &= ~(SMBHSTSTS_SMBALERT_STS | SMBHSTSTS_INUSE_STS);
167
168 /* Read results of transaction */
169 byte = inb(smbus_base + SMBHSTDAT0);
170 if (status != SMBHSTSTS_INTR)
171 return SMBUS_ERROR;
172 return byte;
173}
174
175int do_smbus_write_byte(unsigned int smbus_base, u8 device,
176 unsigned int address, unsigned int data)
177{
178 unsigned char status;
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300179 int ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200180
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300181 /* Set up for a byte data write. */
182 ret = setup_command(smbus_base, I801_BYTE_DATA, XMIT_WRITE(device));
183 if (ret < 0)
184 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200185
Arthur Heymans16fe7902017-04-12 17:01:31 +0200186 /* Set the command/address... */
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300187 outb(address, smbus_base + SMBHSTCMD);
Arthur Heymans16fe7902017-04-12 17:01:31 +0200188
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300189 /* Set the data byte... */
Arthur Heymans16fe7902017-04-12 17:01:31 +0200190 outb(data, smbus_base + SMBHSTDAT0);
191
192 /* Start the command */
193 outb((inb(smbus_base + SMBHSTCTL) | SMBHSTCNT_START),
194 smbus_base + SMBHSTCTL);
195
196 /* poll for it to start */
197 if (smbus_wait_until_active(smbus_base) < 0)
198 return SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT;
199
200 /* Poll for transaction completion */
201 if (smbus_wait_until_done(smbus_base) < 0)
202 return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
203
204 status = inb(smbus_base + SMBHSTSTAT);
205
206 /* Ignore the "In Use" status... */
207 status &= ~(SMBHSTSTS_SMBALERT_STS | SMBHSTSTS_INUSE_STS);
208
209 /* Read results of transaction */
210 if (status != SMBHSTSTS_INTR)
211 return SMBUS_ERROR;
212
213 return 0;
214}
215
216int do_smbus_block_read(unsigned int smbus_base, u8 device, u8 cmd,
Arthur Heymans1b04aa22017-08-04 14:28:50 +0200217 unsigned int max_bytes, u8 *buf)
Arthur Heymans16fe7902017-04-12 17:01:31 +0200218{
219 u8 status;
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300220 int ret, slave_bytes;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200221 int bytes_read = 0;
222 unsigned int loops = SMBUS_TIMEOUT;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200223
Kyösti Mälkkic17e8552017-08-20 23:48:23 +0300224 max_bytes = MIN(SMBUS_BLOCK_MAXLEN, max_bytes);
Arthur Heymans1b04aa22017-08-04 14:28:50 +0200225
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300226 /* Set up for a block data read. */
227 ret = setup_command(smbus_base, I801_BLOCK_DATA, XMIT_READ(device));
228 if (ret < 0)
229 return ret;
230
Arthur Heymans16fe7902017-04-12 17:01:31 +0200231 /* Set the command/address... */
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300232 outb(cmd, smbus_base + SMBHSTCMD);
Arthur Heymans16fe7902017-04-12 17:01:31 +0200233
Arthur Heymans1b04aa22017-08-04 14:28:50 +0200234 /* Reset number of bytes to transfer so we notice later it
235 * was really updated with the transaction. */
236 outb(0, smbus_base + SMBHSTDAT0);
237
Arthur Heymans16fe7902017-04-12 17:01:31 +0200238 /* Start the command */
239 outb((inb(smbus_base + SMBHSTCTL) | SMBHSTCNT_START),
240 smbus_base + SMBHSTCTL);
241
242 /* poll for it to start */
243 if (smbus_wait_until_active(smbus_base) < 0)
244 return SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT;
245
246 /* Poll for transaction completion */
247 do {
248 loops--;
249 status = inb(smbus_base + SMBHSTSTAT);
250 if (status & (SMBHSTSTS_FAILED | /* FAILED */
251 SMBHSTSTS_BUS_ERR | /* BUS ERR */
252 SMBHSTSTS_DEV_ERR)) /* DEV ERR */
253 return SMBUS_ERROR;
254
255 if (status & SMBHSTSTS_BYTE_DONE) { /* Byte done */
Arthur Heymans1b04aa22017-08-04 14:28:50 +0200256
257 if (bytes_read < max_bytes) {
Kyösti Mälkkic17e8552017-08-20 23:48:23 +0300258 *buf++ = inb(smbus_base + SMBBLKDAT);
Arthur Heymans1b04aa22017-08-04 14:28:50 +0200259 bytes_read++;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200260 }
Arthur Heymans1b04aa22017-08-04 14:28:50 +0200261
262 /* Engine internally completes the transaction
263 * and clears HOST_BUSY flag once the byte count
264 * from slave is reached.
265 */
Arthur Heymans16fe7902017-04-12 17:01:31 +0200266 outb(status, smbus_base + SMBHSTSTAT);
267 }
268 } while ((status & SMBHSTSTS_HOST_BUSY) && loops);
269
Kyösti Mälkkif51c5fd2017-09-09 20:45:47 +0300270 /* Post-check we received complete message. */
271 slave_bytes = inb(smbus_base + SMBHSTDAT0);
272
Kyösti Mälkkib5d998b2017-08-20 21:36:08 +0300273 dprintk("%s: status = %02x, len = %d / %d, loops = %d\n",
274 __func__, status, bytes_read, slave_bytes, loops);
275
Arthur Heymans1b04aa22017-08-04 14:28:50 +0200276 if (bytes_read < slave_bytes)
277 return SMBUS_ERROR;
278
Arthur Heymans16fe7902017-04-12 17:01:31 +0200279 return bytes_read;
280}
281
282int do_smbus_block_write(unsigned int smbus_base, u8 device, u8 cmd,
Arthur Heymans1b04aa22017-08-04 14:28:50 +0200283 const unsigned int bytes, const u8 *buf)
Arthur Heymans16fe7902017-04-12 17:01:31 +0200284{
285 u8 status;
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300286 int ret, bytes_sent = 0;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200287 unsigned int loops = SMBUS_TIMEOUT;
288
Kyösti Mälkkic17e8552017-08-20 23:48:23 +0300289 if (bytes > SMBUS_BLOCK_MAXLEN)
Arthur Heymans1b04aa22017-08-04 14:28:50 +0200290 return SMBUS_ERROR;
291
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300292 /* Set up for a block data write. */
293 ret = setup_command(smbus_base, I801_BLOCK_DATA, XMIT_WRITE(device));
294 if (ret < 0)
295 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200296
Arthur Heymans16fe7902017-04-12 17:01:31 +0200297 /* Set the command/address... */
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300298 outb(cmd, smbus_base + SMBHSTCMD);
Arthur Heymans16fe7902017-04-12 17:01:31 +0200299
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300300 /* Set number of bytes to transfer. */
Arthur Heymans16fe7902017-04-12 17:01:31 +0200301 outb(bytes, smbus_base + SMBHSTDAT0);
302
Arthur Heymans1b04aa22017-08-04 14:28:50 +0200303 /* Send first byte from buffer, bytes_sent increments after
304 * hardware acknowledges it.
305 */
Arthur Heymans16fe7902017-04-12 17:01:31 +0200306 outb(*buf++, smbus_base + SMBBLKDAT);
Arthur Heymans16fe7902017-04-12 17:01:31 +0200307
308 /* Start the command */
309 outb((inb(smbus_base + SMBHSTCTL) | SMBHSTCNT_START),
310 smbus_base + SMBHSTCTL);
311
312 /* poll for it to start */
313 if (smbus_wait_until_active(smbus_base) < 0)
314 return SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT;
315
316 /* Poll for transaction completion */
317 do {
318 loops--;
319 status = inb(smbus_base + SMBHSTSTAT);
320 if (status & (SMBHSTSTS_FAILED | /* FAILED */
321 SMBHSTSTS_BUS_ERR | /* BUS ERR */
322 SMBHSTSTS_DEV_ERR)) /* DEV ERR */
323 return SMBUS_ERROR;
324
325 if (status & SMBHSTSTS_BYTE_DONE) {
Arthur Heymans1b04aa22017-08-04 14:28:50 +0200326 bytes_sent++;
327 if (bytes_sent < bytes)
328 outb(*buf++, smbus_base + SMBBLKDAT);
329
330 /* Engine internally completes the transaction
331 * and clears HOST_BUSY flag once the byte count
332 * has been reached.
333 */
Arthur Heymans16fe7902017-04-12 17:01:31 +0200334 outb(status, smbus_base + SMBHSTSTAT);
335 }
336 } while ((status & SMBHSTSTS_HOST_BUSY) && loops);
337
Kyösti Mälkkib5d998b2017-08-20 21:36:08 +0300338 dprintk("%s: status = %02x, len = %d / %d, loops = %d\n",
339 __func__, status, bytes_sent, bytes, loops);
340
Kyösti Mälkkic17e8552017-08-20 23:48:23 +0300341 if (bytes_sent < bytes)
342 return SMBUS_ERROR;
343
Arthur Heymans1b04aa22017-08-04 14:28:50 +0200344 return bytes_sent;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200345}
346
347/* Only since ICH5 */
348int do_i2c_block_read(unsigned int smbus_base, u8 device,
Kyösti Mälkki1e392362017-08-20 21:36:03 +0300349 unsigned int offset, const unsigned int bytes, u8 *buf)
Arthur Heymans16fe7902017-04-12 17:01:31 +0200350{
351 u8 status;
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300352 int ret, bytes_read = 0;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200353 unsigned int loops = SMBUS_TIMEOUT;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200354
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300355 /* Set up for a i2c block data read.
356 *
357 * FIXME: Address parameter changes to XMIT_READ(device) with
358 * some revision of PCH. Presumably hardware revisions that
359 * do not have i2c block write support internally set LSB.
360 */
361 ret = setup_command(smbus_base, I801_I2C_BLOCK_DATA,
362 XMIT_WRITE(device));
363 if (ret < 0)
364 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200365
366 /* device offset */
367 outb(offset, smbus_base + SMBHSTDAT1);
368
Arthur Heymans16fe7902017-04-12 17:01:31 +0200369 /* Start the command */
370 outb((inb(smbus_base + SMBHSTCTL) | SMBHSTCNT_START),
371 smbus_base + SMBHSTCTL);
372
373 /* poll for it to start */
374 if (smbus_wait_until_active(smbus_base) < 0)
375 return SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT;
376
377 /* Poll for transaction completion */
378 do {
379 loops--;
380 status = inb(smbus_base + SMBHSTSTAT);
381 if (status & (SMBHSTSTS_FAILED | /* FAILED */
382 SMBHSTSTS_BUS_ERR | /* BUS ERR */
383 SMBHSTSTS_DEV_ERR)) /* DEV ERR */
384 return SMBUS_ERROR;
385
386 if (status & SMBHSTSTS_BYTE_DONE) {
Kyösti Mälkki1e392362017-08-20 21:36:03 +0300387
388 if (bytes_read < bytes) {
389 *buf++ = inb(smbus_base + SMBBLKDAT);
390 bytes_read++;
391 }
392
393 if (bytes_read + 1 >= bytes) {
Arthur Heymans16fe7902017-04-12 17:01:31 +0200394 /* indicate that next byte is the last one */
395 outb(inb(smbus_base + SMBHSTCTL)
396 | SMBHSTCNT_LAST_BYTE,
397 smbus_base + SMBHSTCTL);
398 }
Kyösti Mälkki1e392362017-08-20 21:36:03 +0300399
Arthur Heymans16fe7902017-04-12 17:01:31 +0200400 outb(status, smbus_base + SMBHSTSTAT);
401 }
402 } while ((status & SMBHSTSTS_HOST_BUSY) && loops);
403
Kyösti Mälkkib5d998b2017-08-20 21:36:08 +0300404 dprintk("%s: status = %02x, len = %d / %d, loops = %d\n",
405 __func__, status, bytes_read, bytes, loops);
406
Kyösti Mälkki1e392362017-08-20 21:36:03 +0300407 if (bytes_read < bytes)
408 return SMBUS_ERROR;
409
Arthur Heymans16fe7902017-04-12 17:01:31 +0200410 return bytes_read;
411}