blob: 1302798e06e7945273cc4fb0e7645268bb1438ac [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älkkic38d5432017-08-20 21:36:18 +030068static int host_completed(u8 status)
69{
70 if (status & SMBHSTSTS_HOST_BUSY)
71 return 0;
72 status &= ~(SMBHSTSTS_SMBALERT_STS | SMBHSTSTS_INUSE_STS);
73 return status != 0;
74}
75
Kyösti Mälkki957511c2017-08-20 21:36:11 +030076static int recover_master(int smbus_base, int ret)
Arthur Heymans16fe7902017-04-12 17:01:31 +020077{
Kyösti Mälkki957511c2017-08-20 21:36:11 +030078 /* TODO: Depending of the failure, drive KILL transaction
79 * or force soft reset on SMBus master controller.
80 */
81 printk(BIOS_ERR, "SMBus: Fatal master timeout (%d)\n", ret);
82 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +020083}
84
Kyösti Mälkkic38d5432017-08-20 21:36:18 +030085static int cb_err_from_stat(u8 status)
86{
87 /* Ignore the "In Use" status... */
88 status &= ~(SMBHSTSTS_SMBALERT_STS | SMBHSTSTS_INUSE_STS);
89
90 if (status == SMBHSTSTS_INTR)
91 return 0;
92
93 return SMBUS_ERROR;
94}
95
Kyösti Mälkki957511c2017-08-20 21:36:11 +030096static int setup_command(unsigned int smbus_base, u8 ctrl, u8 xmitadd)
Arthur Heymans16fe7902017-04-12 17:01:31 +020097{
98 unsigned int loops = SMBUS_TIMEOUT;
Kyösti Mälkki957511c2017-08-20 21:36:11 +030099 u8 host_busy;
100
Arthur Heymans16fe7902017-04-12 17:01:31 +0200101 do {
102 smbus_delay();
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300103 host_busy = inb(smbus_base + SMBHSTSTAT) & SMBHSTSTS_HOST_BUSY;
104 } while (--loops && host_busy);
105
106 if (loops == 0)
107 return recover_master(smbus_base,
108 SMBUS_WAIT_UNTIL_READY_TIMEOUT);
109
110 /* Clear any lingering errors, so the transaction will run. */
111 outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
112
113 /* Set up transaction */
114 /* Disable interrupts */
115 outb(ctrl, (smbus_base + SMBHSTCTL));
116
117 /* Set the device I'm talking to. */
118 outb(xmitadd, smbus_base + SMBXMITADD);
119
120 return 0;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200121}
122
Kyösti Mälkkia2dcf732017-08-20 21:36:15 +0300123static int execute_command(unsigned int smbus_base)
Arthur Heymans16fe7902017-04-12 17:01:31 +0200124{
Kyösti Mälkkia2dcf732017-08-20 21:36:15 +0300125 unsigned int loops = SMBUS_TIMEOUT;
126 u8 status;
127
128 /* Start the command. */
129 outb((inb(smbus_base + SMBHSTCTL) | SMBHSTCNT_START),
130 smbus_base + SMBHSTCTL);
131
132 /* Poll for it to start. */
Arthur Heymans16fe7902017-04-12 17:01:31 +0200133 do {
Arthur Heymans16fe7902017-04-12 17:01:31 +0200134 smbus_delay();
Kyösti Mälkkia2dcf732017-08-20 21:36:15 +0300135
136 /* If we poll too slow, we could miss HOST_BUSY flag
137 * set and detect INTR or x_ERR flags instead here.
138 */
139 status = inb(smbus_base + SMBHSTSTAT);
140 status &= ~(SMBHSTSTS_SMBALERT_STS | SMBHSTSTS_INUSE_STS);
141 } while (--loops && status == 0);
142
143 if (loops == 0)
144 return recover_master(smbus_base,
145 SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT);
146
147 return 0;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200148}
149
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300150static int complete_command(unsigned int smbus_base)
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300151{
152 unsigned int loops = SMBUS_TIMEOUT;
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300153 u8 status;
154
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300155 do {
156 smbus_delay();
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300157 status = inb(smbus_base + SMBHSTSTAT);
158 } while (--loops && !host_completed(status));
159
160 if (loops == 0)
161 return recover_master(smbus_base,
162 SMBUS_WAIT_UNTIL_DONE_TIMEOUT);
163
164 return cb_err_from_stat(status);
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300165}
166
Arthur Heymans16fe7902017-04-12 17:01:31 +0200167int do_smbus_read_byte(unsigned int smbus_base, u8 device,
168 unsigned int address)
169{
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300170 int ret;
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300171 u8 byte;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200172
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300173 /* Set up for a byte data read. */
174 ret = setup_command(smbus_base, I801_BYTE_DATA, XMIT_READ(device));
175 if (ret < 0)
176 return ret;
177
Arthur Heymans16fe7902017-04-12 17:01:31 +0200178 /* Set the command/address... */
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300179 outb(address, smbus_base + SMBHSTCMD);
Arthur Heymans16fe7902017-04-12 17:01:31 +0200180
181 /* Clear the data byte... */
182 outb(0, smbus_base + SMBHSTDAT0);
183
184 /* Start the command */
Kyösti Mälkkia2dcf732017-08-20 21:36:15 +0300185 ret = execute_command(smbus_base);
186 if (ret < 0)
187 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200188
189 /* Poll for transaction completion */
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300190 ret = complete_command(smbus_base);
191 if (ret < 0)
192 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200193
194 /* Read results of transaction */
195 byte = inb(smbus_base + SMBHSTDAT0);
Arthur Heymans16fe7902017-04-12 17:01:31 +0200196 return byte;
197}
198
199int do_smbus_write_byte(unsigned int smbus_base, u8 device,
200 unsigned int address, unsigned int data)
201{
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300202 int ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200203
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300204 /* Set up for a byte data write. */
205 ret = setup_command(smbus_base, I801_BYTE_DATA, XMIT_WRITE(device));
206 if (ret < 0)
207 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200208
Arthur Heymans16fe7902017-04-12 17:01:31 +0200209 /* Set the command/address... */
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300210 outb(address, smbus_base + SMBHSTCMD);
Arthur Heymans16fe7902017-04-12 17:01:31 +0200211
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300212 /* Set the data byte... */
Arthur Heymans16fe7902017-04-12 17:01:31 +0200213 outb(data, smbus_base + SMBHSTDAT0);
214
215 /* Start the command */
Kyösti Mälkkia2dcf732017-08-20 21:36:15 +0300216 ret = execute_command(smbus_base);
217 if (ret < 0)
218 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200219
220 /* Poll for transaction completion */
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300221 return complete_command(smbus_base);
Arthur Heymans16fe7902017-04-12 17:01:31 +0200222}
223
224int do_smbus_block_read(unsigned int smbus_base, u8 device, u8 cmd,
Arthur Heymans1b04aa22017-08-04 14:28:50 +0200225 unsigned int max_bytes, u8 *buf)
Arthur Heymans16fe7902017-04-12 17:01:31 +0200226{
227 u8 status;
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300228 int ret, slave_bytes;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200229 int bytes_read = 0;
230 unsigned int loops = SMBUS_TIMEOUT;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200231
Kyösti Mälkkic17e8552017-08-20 23:48:23 +0300232 max_bytes = MIN(SMBUS_BLOCK_MAXLEN, max_bytes);
Arthur Heymans1b04aa22017-08-04 14:28:50 +0200233
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300234 /* Set up for a block data read. */
235 ret = setup_command(smbus_base, I801_BLOCK_DATA, XMIT_READ(device));
236 if (ret < 0)
237 return ret;
238
Arthur Heymans16fe7902017-04-12 17:01:31 +0200239 /* Set the command/address... */
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300240 outb(cmd, smbus_base + SMBHSTCMD);
Arthur Heymans16fe7902017-04-12 17:01:31 +0200241
Arthur Heymans1b04aa22017-08-04 14:28:50 +0200242 /* Reset number of bytes to transfer so we notice later it
243 * was really updated with the transaction. */
244 outb(0, smbus_base + SMBHSTDAT0);
245
Arthur Heymans16fe7902017-04-12 17:01:31 +0200246 /* Start the command */
Kyösti Mälkkia2dcf732017-08-20 21:36:15 +0300247 ret = execute_command(smbus_base);
248 if (ret < 0)
249 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200250
251 /* Poll for transaction completion */
252 do {
Arthur Heymans16fe7902017-04-12 17:01:31 +0200253 status = inb(smbus_base + SMBHSTSTAT);
Arthur Heymans16fe7902017-04-12 17:01:31 +0200254
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 */
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300266 outb(SMBHSTSTS_BYTE_DONE, smbus_base + SMBHSTSTAT);
Arthur Heymans16fe7902017-04-12 17:01:31 +0200267 }
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300268 } while (--loops && !host_completed(status));
Arthur Heymans16fe7902017-04-12 17:01:31 +0200269
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
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300276 if (loops == 0)
277 return recover_master(smbus_base,
278 SMBUS_WAIT_UNTIL_DONE_TIMEOUT);
279
280 ret = cb_err_from_stat(status);
281 if (ret < 0)
282 return ret;
283
Arthur Heymans1b04aa22017-08-04 14:28:50 +0200284 if (bytes_read < slave_bytes)
285 return SMBUS_ERROR;
286
Arthur Heymans16fe7902017-04-12 17:01:31 +0200287 return bytes_read;
288}
289
290int do_smbus_block_write(unsigned int smbus_base, u8 device, u8 cmd,
Arthur Heymans1b04aa22017-08-04 14:28:50 +0200291 const unsigned int bytes, const u8 *buf)
Arthur Heymans16fe7902017-04-12 17:01:31 +0200292{
293 u8 status;
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300294 int ret, bytes_sent = 0;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200295 unsigned int loops = SMBUS_TIMEOUT;
296
Kyösti Mälkkic17e8552017-08-20 23:48:23 +0300297 if (bytes > SMBUS_BLOCK_MAXLEN)
Arthur Heymans1b04aa22017-08-04 14:28:50 +0200298 return SMBUS_ERROR;
299
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300300 /* Set up for a block data write. */
301 ret = setup_command(smbus_base, I801_BLOCK_DATA, XMIT_WRITE(device));
302 if (ret < 0)
303 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200304
Arthur Heymans16fe7902017-04-12 17:01:31 +0200305 /* Set the command/address... */
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300306 outb(cmd, smbus_base + SMBHSTCMD);
Arthur Heymans16fe7902017-04-12 17:01:31 +0200307
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300308 /* Set number of bytes to transfer. */
Arthur Heymans16fe7902017-04-12 17:01:31 +0200309 outb(bytes, smbus_base + SMBHSTDAT0);
310
Arthur Heymans1b04aa22017-08-04 14:28:50 +0200311 /* Send first byte from buffer, bytes_sent increments after
312 * hardware acknowledges it.
313 */
Arthur Heymans16fe7902017-04-12 17:01:31 +0200314 outb(*buf++, smbus_base + SMBBLKDAT);
Arthur Heymans16fe7902017-04-12 17:01:31 +0200315
316 /* Start the command */
Kyösti Mälkkia2dcf732017-08-20 21:36:15 +0300317 ret = execute_command(smbus_base);
318 if (ret < 0)
319 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200320
321 /* Poll for transaction completion */
322 do {
Arthur Heymans16fe7902017-04-12 17:01:31 +0200323 status = inb(smbus_base + SMBHSTSTAT);
Arthur Heymans16fe7902017-04-12 17:01:31 +0200324
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 */
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300334 outb(SMBHSTSTS_BYTE_DONE, smbus_base + SMBHSTSTAT);
Arthur Heymans16fe7902017-04-12 17:01:31 +0200335 }
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300336 } while (--loops && !host_completed(status));
Arthur Heymans16fe7902017-04-12 17:01:31 +0200337
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älkkic38d5432017-08-20 21:36:18 +0300341 if (loops == 0)
342 return recover_master(smbus_base,
343 SMBUS_WAIT_UNTIL_DONE_TIMEOUT);
344
345 ret = cb_err_from_stat(status);
346 if (ret < 0)
347 return ret;
348
Kyösti Mälkkic17e8552017-08-20 23:48:23 +0300349 if (bytes_sent < bytes)
350 return SMBUS_ERROR;
351
Arthur Heymans1b04aa22017-08-04 14:28:50 +0200352 return bytes_sent;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200353}
354
355/* Only since ICH5 */
356int do_i2c_block_read(unsigned int smbus_base, u8 device,
Kyösti Mälkki1e392362017-08-20 21:36:03 +0300357 unsigned int offset, const unsigned int bytes, u8 *buf)
Arthur Heymans16fe7902017-04-12 17:01:31 +0200358{
359 u8 status;
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300360 int ret, bytes_read = 0;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200361 unsigned int loops = SMBUS_TIMEOUT;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200362
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300363 /* Set up for a i2c block data read.
364 *
365 * FIXME: Address parameter changes to XMIT_READ(device) with
366 * some revision of PCH. Presumably hardware revisions that
367 * do not have i2c block write support internally set LSB.
368 */
369 ret = setup_command(smbus_base, I801_I2C_BLOCK_DATA,
370 XMIT_WRITE(device));
371 if (ret < 0)
372 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200373
374 /* device offset */
375 outb(offset, smbus_base + SMBHSTDAT1);
376
Arthur Heymans16fe7902017-04-12 17:01:31 +0200377 /* Start the command */
Kyösti Mälkkia2dcf732017-08-20 21:36:15 +0300378 ret = execute_command(smbus_base);
379 if (ret < 0)
380 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200381
382 /* Poll for transaction completion */
383 do {
Arthur Heymans16fe7902017-04-12 17:01:31 +0200384 status = inb(smbus_base + SMBHSTSTAT);
Arthur Heymans16fe7902017-04-12 17:01:31 +0200385
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
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300400 outb(SMBHSTSTS_BYTE_DONE, smbus_base + SMBHSTSTAT);
Arthur Heymans16fe7902017-04-12 17:01:31 +0200401 }
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300402 } while (--loops && !host_completed(status));
Arthur Heymans16fe7902017-04-12 17:01:31 +0200403
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älkkic38d5432017-08-20 21:36:18 +0300407 if (loops == 0)
408 return recover_master(smbus_base,
409 SMBUS_WAIT_UNTIL_DONE_TIMEOUT);
410
411 ret = cb_err_from_stat(status);
412 if (ret < 0)
413 return ret;
414
Kyösti Mälkki1e392362017-08-20 21:36:03 +0300415 if (bytes_read < bytes)
416 return SMBUS_ERROR;
417
Arthur Heymans16fe7902017-04-12 17:01:31 +0200418 return bytes_read;
419}