blob: fd8b6aa8dd0e6c284f7e32ca95419b1dbfe3874c [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
Kyösti Mälkki893edee2017-08-20 21:36:24 +030063/* block_cmd_loop flags */
64#define BLOCK_READ 0
65#define BLOCK_WRITE (1 << 0)
66#define BLOCK_I2C (1 << 1)
67
Arthur Heymans16fe7902017-04-12 17:01:31 +020068static void smbus_delay(void)
69{
70 inb(0x80);
71}
72
Kyösti Mälkkic38d5432017-08-20 21:36:18 +030073static int host_completed(u8 status)
74{
75 if (status & SMBHSTSTS_HOST_BUSY)
76 return 0;
77 status &= ~(SMBHSTSTS_SMBALERT_STS | SMBHSTSTS_INUSE_STS);
78 return status != 0;
79}
80
Kyösti Mälkki957511c2017-08-20 21:36:11 +030081static int recover_master(int smbus_base, int ret)
Arthur Heymans16fe7902017-04-12 17:01:31 +020082{
Kyösti Mälkki957511c2017-08-20 21:36:11 +030083 /* TODO: Depending of the failure, drive KILL transaction
84 * or force soft reset on SMBus master controller.
85 */
86 printk(BIOS_ERR, "SMBus: Fatal master timeout (%d)\n", ret);
87 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +020088}
89
Kyösti Mälkkic38d5432017-08-20 21:36:18 +030090static int cb_err_from_stat(u8 status)
91{
92 /* Ignore the "In Use" status... */
93 status &= ~(SMBHSTSTS_SMBALERT_STS | SMBHSTSTS_INUSE_STS);
94
95 if (status == SMBHSTSTS_INTR)
96 return 0;
97
98 return SMBUS_ERROR;
99}
100
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300101static int setup_command(unsigned int smbus_base, u8 ctrl, u8 xmitadd)
Arthur Heymans16fe7902017-04-12 17:01:31 +0200102{
103 unsigned int loops = SMBUS_TIMEOUT;
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300104 u8 host_busy;
105
Arthur Heymans16fe7902017-04-12 17:01:31 +0200106 do {
107 smbus_delay();
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300108 host_busy = inb(smbus_base + SMBHSTSTAT) & SMBHSTSTS_HOST_BUSY;
109 } while (--loops && host_busy);
110
111 if (loops == 0)
112 return recover_master(smbus_base,
113 SMBUS_WAIT_UNTIL_READY_TIMEOUT);
114
115 /* Clear any lingering errors, so the transaction will run. */
116 outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
117
118 /* Set up transaction */
119 /* Disable interrupts */
120 outb(ctrl, (smbus_base + SMBHSTCTL));
121
122 /* Set the device I'm talking to. */
123 outb(xmitadd, smbus_base + SMBXMITADD);
124
125 return 0;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200126}
127
Kyösti Mälkkia2dcf732017-08-20 21:36:15 +0300128static int execute_command(unsigned int smbus_base)
Arthur Heymans16fe7902017-04-12 17:01:31 +0200129{
Kyösti Mälkkia2dcf732017-08-20 21:36:15 +0300130 unsigned int loops = SMBUS_TIMEOUT;
131 u8 status;
132
133 /* Start the command. */
134 outb((inb(smbus_base + SMBHSTCTL) | SMBHSTCNT_START),
135 smbus_base + SMBHSTCTL);
136
137 /* Poll for it to start. */
Arthur Heymans16fe7902017-04-12 17:01:31 +0200138 do {
Arthur Heymans16fe7902017-04-12 17:01:31 +0200139 smbus_delay();
Kyösti Mälkkia2dcf732017-08-20 21:36:15 +0300140
141 /* If we poll too slow, we could miss HOST_BUSY flag
142 * set and detect INTR or x_ERR flags instead here.
143 */
144 status = inb(smbus_base + SMBHSTSTAT);
145 status &= ~(SMBHSTSTS_SMBALERT_STS | SMBHSTSTS_INUSE_STS);
146 } while (--loops && status == 0);
147
148 if (loops == 0)
149 return recover_master(smbus_base,
150 SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT);
151
152 return 0;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200153}
154
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300155static int complete_command(unsigned int smbus_base)
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300156{
157 unsigned int loops = SMBUS_TIMEOUT;
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300158 u8 status;
159
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300160 do {
161 smbus_delay();
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300162 status = inb(smbus_base + SMBHSTSTAT);
163 } while (--loops && !host_completed(status));
164
165 if (loops == 0)
166 return recover_master(smbus_base,
167 SMBUS_WAIT_UNTIL_DONE_TIMEOUT);
168
169 return cb_err_from_stat(status);
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300170}
171
Arthur Heymans16fe7902017-04-12 17:01:31 +0200172int do_smbus_read_byte(unsigned int smbus_base, u8 device,
173 unsigned int address)
174{
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300175 int ret;
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300176 u8 byte;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200177
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300178 /* Set up for a byte data read. */
179 ret = setup_command(smbus_base, I801_BYTE_DATA, XMIT_READ(device));
180 if (ret < 0)
181 return ret;
182
Arthur Heymans16fe7902017-04-12 17:01:31 +0200183 /* Set the command/address... */
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300184 outb(address, smbus_base + SMBHSTCMD);
Arthur Heymans16fe7902017-04-12 17:01:31 +0200185
186 /* Clear the data byte... */
187 outb(0, smbus_base + SMBHSTDAT0);
188
189 /* Start the command */
Kyösti Mälkkia2dcf732017-08-20 21:36:15 +0300190 ret = execute_command(smbus_base);
191 if (ret < 0)
192 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200193
194 /* Poll for transaction completion */
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300195 ret = complete_command(smbus_base);
196 if (ret < 0)
197 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200198
199 /* Read results of transaction */
200 byte = inb(smbus_base + SMBHSTDAT0);
Arthur Heymans16fe7902017-04-12 17:01:31 +0200201 return byte;
202}
203
204int do_smbus_write_byte(unsigned int smbus_base, u8 device,
205 unsigned int address, unsigned int data)
206{
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300207 int ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200208
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300209 /* Set up for a byte data write. */
210 ret = setup_command(smbus_base, I801_BYTE_DATA, XMIT_WRITE(device));
211 if (ret < 0)
212 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200213
Arthur Heymans16fe7902017-04-12 17:01:31 +0200214 /* Set the command/address... */
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300215 outb(address, smbus_base + SMBHSTCMD);
Arthur Heymans16fe7902017-04-12 17:01:31 +0200216
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300217 /* Set the data byte... */
Arthur Heymans16fe7902017-04-12 17:01:31 +0200218 outb(data, smbus_base + SMBHSTDAT0);
219
220 /* Start the command */
Kyösti Mälkkia2dcf732017-08-20 21:36:15 +0300221 ret = execute_command(smbus_base);
222 if (ret < 0)
223 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200224
225 /* Poll for transaction completion */
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300226 return complete_command(smbus_base);
Arthur Heymans16fe7902017-04-12 17:01:31 +0200227}
228
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300229static int block_cmd_loop(unsigned int smbus_base,
230 u8 *buf, const unsigned int max_bytes, int flags)
231{
232 u8 status;
233 unsigned int loops = SMBUS_TIMEOUT;
234 int ret, bytes = 0;
235 int is_write_cmd = flags & BLOCK_WRITE;
236 int sw_drives_nak = flags & BLOCK_I2C;
237
238 /* Hardware limitations. */
239 if (flags == (BLOCK_WRITE | BLOCK_I2C))
240 return SMBUS_ERROR;
241
Kyösti Mälkkid6c15d02017-08-20 21:36:24 +0300242 /* Set number of bytes to transfer. */
243 /* Reset number of bytes to transfer so we notice later it
244 * was really updated with the transaction. */
245 if (!sw_drives_nak) {
246 if (is_write_cmd)
247 outb(max_bytes, smbus_base + SMBHSTDAT0);
248 else
249 outb(0, smbus_base + SMBHSTDAT0);
250 }
251
252 /* Send first byte from buffer, bytes_sent increments after
253 * hardware acknowledges it.
254 */
255 if (is_write_cmd)
256 outb(*buf++, smbus_base + SMBBLKDAT);
257
258 /* Start the command */
259 ret = execute_command(smbus_base);
260 if (ret < 0)
261 return ret;
262
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300263 /* Poll for transaction completion */
264 do {
265 status = inb(smbus_base + SMBHSTSTAT);
266
267 if (status & SMBHSTSTS_BYTE_DONE) { /* Byte done */
268
269 if (is_write_cmd) {
270 bytes++;
271 if (bytes < max_bytes)
272 outb(*buf++, smbus_base + SMBBLKDAT);
273 } else {
274 if (bytes < max_bytes)
275 *buf++ = inb(smbus_base + SMBBLKDAT);
276 bytes++;
277
278 /* Indicate that next byte is the last one. */
279 if (sw_drives_nak && (bytes + 1 >= max_bytes)) {
280 outb(inb(smbus_base + SMBHSTCTL)
281 | SMBHSTCNT_LAST_BYTE,
282 smbus_base + SMBHSTCTL);
283 }
284
285 }
286
287 /* Engine internally completes the transaction
288 * and clears HOST_BUSY flag once the byte count
289 * has been reached or LAST_BYTE was set.
290 */
291 outb(SMBHSTSTS_BYTE_DONE, smbus_base + SMBHSTSTAT);
292 }
293
294 } while (--loops && !host_completed(status));
295
296 dprintk("%s: status = %02x, len = %d / %d, loops = %d\n",
297 __func__, status, bytes, max_bytes, SMBUS_TIMEOUT - loops);
298
299 if (loops == 0)
300 return recover_master(smbus_base,
301 SMBUS_WAIT_UNTIL_DONE_TIMEOUT);
302
303 ret = cb_err_from_stat(status);
304 if (ret < 0)
305 return ret;
306
307 return bytes;
308}
309
Arthur Heymans16fe7902017-04-12 17:01:31 +0200310int do_smbus_block_read(unsigned int smbus_base, u8 device, u8 cmd,
Arthur Heymans1b04aa22017-08-04 14:28:50 +0200311 unsigned int max_bytes, u8 *buf)
Arthur Heymans16fe7902017-04-12 17:01:31 +0200312{
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300313 int ret, slave_bytes;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200314
Kyösti Mälkkic17e8552017-08-20 23:48:23 +0300315 max_bytes = MIN(SMBUS_BLOCK_MAXLEN, max_bytes);
Arthur Heymans1b04aa22017-08-04 14:28:50 +0200316
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300317 /* Set up for a block data read. */
318 ret = setup_command(smbus_base, I801_BLOCK_DATA, XMIT_READ(device));
319 if (ret < 0)
320 return ret;
321
Arthur Heymans16fe7902017-04-12 17:01:31 +0200322 /* Set the command/address... */
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300323 outb(cmd, smbus_base + SMBHSTCMD);
Arthur Heymans16fe7902017-04-12 17:01:31 +0200324
Kyösti Mälkkid6c15d02017-08-20 21:36:24 +0300325 /* Execute block transaction. */
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300326 ret = block_cmd_loop(smbus_base, buf, max_bytes, BLOCK_READ);
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300327 if (ret < 0)
328 return ret;
329
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300330 /* Post-check we received complete message. */
331 slave_bytes = inb(smbus_base + SMBHSTDAT0);
332 if (ret < slave_bytes)
Arthur Heymans1b04aa22017-08-04 14:28:50 +0200333 return SMBUS_ERROR;
334
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300335 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200336}
337
338int do_smbus_block_write(unsigned int smbus_base, u8 device, u8 cmd,
Arthur Heymans1b04aa22017-08-04 14:28:50 +0200339 const unsigned int bytes, const u8 *buf)
Arthur Heymans16fe7902017-04-12 17:01:31 +0200340{
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300341 int ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200342
Kyösti Mälkkic17e8552017-08-20 23:48:23 +0300343 if (bytes > SMBUS_BLOCK_MAXLEN)
Arthur Heymans1b04aa22017-08-04 14:28:50 +0200344 return SMBUS_ERROR;
345
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300346 /* Set up for a block data write. */
347 ret = setup_command(smbus_base, I801_BLOCK_DATA, XMIT_WRITE(device));
348 if (ret < 0)
349 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200350
Arthur Heymans16fe7902017-04-12 17:01:31 +0200351 /* Set the command/address... */
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300352 outb(cmd, smbus_base + SMBHSTCMD);
Arthur Heymans16fe7902017-04-12 17:01:31 +0200353
Kyösti Mälkkid6c15d02017-08-20 21:36:24 +0300354 /* Execute block transaction. */
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300355 ret = block_cmd_loop(smbus_base, (u8 *)buf, bytes, BLOCK_WRITE);
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300356 if (ret < 0)
357 return ret;
358
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300359 if (ret < bytes)
Kyösti Mälkkic17e8552017-08-20 23:48:23 +0300360 return SMBUS_ERROR;
361
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300362 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200363}
364
365/* Only since ICH5 */
366int do_i2c_block_read(unsigned int smbus_base, u8 device,
Kyösti Mälkki1e392362017-08-20 21:36:03 +0300367 unsigned int offset, const unsigned int bytes, u8 *buf)
Arthur Heymans16fe7902017-04-12 17:01:31 +0200368{
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300369 int ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200370
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300371 /* Set up for a i2c block data read.
372 *
373 * FIXME: Address parameter changes to XMIT_READ(device) with
374 * some revision of PCH. Presumably hardware revisions that
375 * do not have i2c block write support internally set LSB.
376 */
377 ret = setup_command(smbus_base, I801_I2C_BLOCK_DATA,
378 XMIT_WRITE(device));
379 if (ret < 0)
380 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200381
382 /* device offset */
383 outb(offset, smbus_base + SMBHSTDAT1);
384
Kyösti Mälkkid6c15d02017-08-20 21:36:24 +0300385 /* Execute block transaction. */
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300386 ret = block_cmd_loop(smbus_base, buf, bytes, BLOCK_READ | BLOCK_I2C);
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300387 if (ret < 0)
388 return ret;
389
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300390 /* Post-check we received complete message. */
391 if (ret < bytes)
Kyösti Mälkki1e392362017-08-20 21:36:03 +0300392 return SMBUS_ERROR;
393
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300394 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200395}