blob: 4b08c48f270de87583e032f8d2609114e9c82e76 [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
Julius Wernercd49cce2019-03-05 16:53:33 -080025#if CONFIG(DEBUG_SMBUS)
Kyösti Mälkkib5d998b2017-08-20 21:36:08 +030026#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;
Kyösti Mälkki44206e32019-02-26 17:17:24 +020077
78 /* These status bits do not imply completion of transaction. */
79 status &= ~(SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INUSE_STS |
80 SMBHSTSTS_SMBALERT_STS);
Kyösti Mälkkic38d5432017-08-20 21:36:18 +030081 return status != 0;
82}
83
Kyösti Mälkki957511c2017-08-20 21:36:11 +030084static int recover_master(int smbus_base, int ret)
Arthur Heymans16fe7902017-04-12 17:01:31 +020085{
Kyösti Mälkki957511c2017-08-20 21:36:11 +030086 /* TODO: Depending of the failure, drive KILL transaction
87 * or force soft reset on SMBus master controller.
88 */
89 printk(BIOS_ERR, "SMBus: Fatal master timeout (%d)\n", ret);
90 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +020091}
92
Kyösti Mälkkic38d5432017-08-20 21:36:18 +030093static int cb_err_from_stat(u8 status)
94{
Kyösti Mälkki44206e32019-02-26 17:17:24 +020095 /* These status bits do not imply errors. */
96 status &= ~(SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INUSE_STS |
97 SMBHSTSTS_SMBALERT_STS);
Kyösti Mälkkic38d5432017-08-20 21:36:18 +030098
99 if (status == SMBHSTSTS_INTR)
100 return 0;
101
102 return SMBUS_ERROR;
103}
104
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300105static int setup_command(unsigned int smbus_base, u8 ctrl, u8 xmitadd)
Arthur Heymans16fe7902017-04-12 17:01:31 +0200106{
107 unsigned int loops = SMBUS_TIMEOUT;
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300108 u8 host_busy;
109
Arthur Heymans16fe7902017-04-12 17:01:31 +0200110 do {
111 smbus_delay();
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300112 host_busy = inb(smbus_base + SMBHSTSTAT) & SMBHSTSTS_HOST_BUSY;
113 } while (--loops && host_busy);
114
115 if (loops == 0)
116 return recover_master(smbus_base,
117 SMBUS_WAIT_UNTIL_READY_TIMEOUT);
118
119 /* Clear any lingering errors, so the transaction will run. */
120 outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);
121
122 /* Set up transaction */
123 /* Disable interrupts */
124 outb(ctrl, (smbus_base + SMBHSTCTL));
125
126 /* Set the device I'm talking to. */
127 outb(xmitadd, smbus_base + SMBXMITADD);
128
129 return 0;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200130}
131
Kyösti Mälkkia2dcf732017-08-20 21:36:15 +0300132static int execute_command(unsigned int smbus_base)
Arthur Heymans16fe7902017-04-12 17:01:31 +0200133{
Kyösti Mälkkia2dcf732017-08-20 21:36:15 +0300134 unsigned int loops = SMBUS_TIMEOUT;
135 u8 status;
136
137 /* Start the command. */
138 outb((inb(smbus_base + SMBHSTCTL) | SMBHSTCNT_START),
139 smbus_base + SMBHSTCTL);
140
141 /* Poll for it to start. */
Arthur Heymans16fe7902017-04-12 17:01:31 +0200142 do {
Arthur Heymans16fe7902017-04-12 17:01:31 +0200143 smbus_delay();
Kyösti Mälkkia2dcf732017-08-20 21:36:15 +0300144
145 /* If we poll too slow, we could miss HOST_BUSY flag
146 * set and detect INTR or x_ERR flags instead here.
147 */
148 status = inb(smbus_base + SMBHSTSTAT);
149 status &= ~(SMBHSTSTS_SMBALERT_STS | SMBHSTSTS_INUSE_STS);
150 } while (--loops && status == 0);
151
152 if (loops == 0)
153 return recover_master(smbus_base,
154 SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT);
155
156 return 0;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200157}
158
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300159static int complete_command(unsigned int smbus_base)
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300160{
161 unsigned int loops = SMBUS_TIMEOUT;
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300162 u8 status;
163
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300164 do {
165 smbus_delay();
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300166 status = inb(smbus_base + SMBHSTSTAT);
167 } while (--loops && !host_completed(status));
168
169 if (loops == 0)
170 return recover_master(smbus_base,
171 SMBUS_WAIT_UNTIL_DONE_TIMEOUT);
172
173 return cb_err_from_stat(status);
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300174}
175
Arthur Heymans16fe7902017-04-12 17:01:31 +0200176int do_smbus_read_byte(unsigned int smbus_base, u8 device,
177 unsigned int address)
178{
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300179 int ret;
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300180 u8 byte;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200181
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300182 /* Set up for a byte data read. */
183 ret = setup_command(smbus_base, I801_BYTE_DATA, XMIT_READ(device));
184 if (ret < 0)
185 return ret;
186
Arthur Heymans16fe7902017-04-12 17:01:31 +0200187 /* Set the command/address... */
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300188 outb(address, smbus_base + SMBHSTCMD);
Arthur Heymans16fe7902017-04-12 17:01:31 +0200189
190 /* Clear the data byte... */
191 outb(0, smbus_base + SMBHSTDAT0);
192
193 /* Start the command */
Kyösti Mälkkia2dcf732017-08-20 21:36:15 +0300194 ret = execute_command(smbus_base);
195 if (ret < 0)
196 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200197
198 /* Poll for transaction completion */
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300199 ret = complete_command(smbus_base);
200 if (ret < 0)
201 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200202
203 /* Read results of transaction */
204 byte = inb(smbus_base + SMBHSTDAT0);
Arthur Heymans16fe7902017-04-12 17:01:31 +0200205 return byte;
206}
207
208int do_smbus_write_byte(unsigned int smbus_base, u8 device,
209 unsigned int address, unsigned int data)
210{
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300211 int ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200212
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300213 /* Set up for a byte data write. */
214 ret = setup_command(smbus_base, I801_BYTE_DATA, XMIT_WRITE(device));
215 if (ret < 0)
216 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200217
Arthur Heymans16fe7902017-04-12 17:01:31 +0200218 /* Set the command/address... */
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300219 outb(address, smbus_base + SMBHSTCMD);
Arthur Heymans16fe7902017-04-12 17:01:31 +0200220
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300221 /* Set the data byte... */
Arthur Heymans16fe7902017-04-12 17:01:31 +0200222 outb(data, smbus_base + SMBHSTDAT0);
223
224 /* Start the command */
Kyösti Mälkkia2dcf732017-08-20 21:36:15 +0300225 ret = execute_command(smbus_base);
226 if (ret < 0)
227 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200228
229 /* Poll for transaction completion */
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300230 return complete_command(smbus_base);
Arthur Heymans16fe7902017-04-12 17:01:31 +0200231}
232
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300233static int block_cmd_loop(unsigned int smbus_base,
234 u8 *buf, const unsigned int max_bytes, int flags)
235{
236 u8 status;
237 unsigned int loops = SMBUS_TIMEOUT;
238 int ret, bytes = 0;
239 int is_write_cmd = flags & BLOCK_WRITE;
240 int sw_drives_nak = flags & BLOCK_I2C;
241
242 /* Hardware limitations. */
243 if (flags == (BLOCK_WRITE | BLOCK_I2C))
244 return SMBUS_ERROR;
245
Kyösti Mälkkid6c15d02017-08-20 21:36:24 +0300246 /* Set number of bytes to transfer. */
247 /* Reset number of bytes to transfer so we notice later it
248 * was really updated with the transaction. */
249 if (!sw_drives_nak) {
250 if (is_write_cmd)
251 outb(max_bytes, smbus_base + SMBHSTDAT0);
252 else
253 outb(0, smbus_base + SMBHSTDAT0);
254 }
255
256 /* Send first byte from buffer, bytes_sent increments after
257 * hardware acknowledges it.
258 */
259 if (is_write_cmd)
260 outb(*buf++, smbus_base + SMBBLKDAT);
261
262 /* Start the command */
263 ret = execute_command(smbus_base);
264 if (ret < 0)
265 return ret;
266
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300267 /* Poll for transaction completion */
268 do {
269 status = inb(smbus_base + SMBHSTSTAT);
270
271 if (status & SMBHSTSTS_BYTE_DONE) { /* Byte done */
272
273 if (is_write_cmd) {
274 bytes++;
275 if (bytes < max_bytes)
276 outb(*buf++, smbus_base + SMBBLKDAT);
277 } else {
278 if (bytes < max_bytes)
279 *buf++ = inb(smbus_base + SMBBLKDAT);
280 bytes++;
281
282 /* Indicate that next byte is the last one. */
283 if (sw_drives_nak && (bytes + 1 >= max_bytes)) {
284 outb(inb(smbus_base + SMBHSTCTL)
285 | SMBHSTCNT_LAST_BYTE,
286 smbus_base + SMBHSTCTL);
287 }
288
289 }
290
291 /* Engine internally completes the transaction
292 * and clears HOST_BUSY flag once the byte count
293 * has been reached or LAST_BYTE was set.
294 */
295 outb(SMBHSTSTS_BYTE_DONE, smbus_base + SMBHSTSTAT);
296 }
297
298 } while (--loops && !host_completed(status));
299
300 dprintk("%s: status = %02x, len = %d / %d, loops = %d\n",
301 __func__, status, bytes, max_bytes, SMBUS_TIMEOUT - loops);
302
303 if (loops == 0)
304 return recover_master(smbus_base,
305 SMBUS_WAIT_UNTIL_DONE_TIMEOUT);
306
307 ret = cb_err_from_stat(status);
308 if (ret < 0)
309 return ret;
310
311 return bytes;
312}
313
Arthur Heymans16fe7902017-04-12 17:01:31 +0200314int do_smbus_block_read(unsigned int smbus_base, u8 device, u8 cmd,
Arthur Heymans1b04aa22017-08-04 14:28:50 +0200315 unsigned int max_bytes, u8 *buf)
Arthur Heymans16fe7902017-04-12 17:01:31 +0200316{
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300317 int ret, slave_bytes;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200318
Kyösti Mälkkic17e8552017-08-20 23:48:23 +0300319 max_bytes = MIN(SMBUS_BLOCK_MAXLEN, max_bytes);
Arthur Heymans1b04aa22017-08-04 14:28:50 +0200320
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300321 /* Set up for a block data read. */
322 ret = setup_command(smbus_base, I801_BLOCK_DATA, XMIT_READ(device));
323 if (ret < 0)
324 return ret;
325
Arthur Heymans16fe7902017-04-12 17:01:31 +0200326 /* Set the command/address... */
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300327 outb(cmd, smbus_base + SMBHSTCMD);
Arthur Heymans16fe7902017-04-12 17:01:31 +0200328
Kyösti Mälkkid6c15d02017-08-20 21:36:24 +0300329 /* Execute block transaction. */
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300330 ret = block_cmd_loop(smbus_base, buf, max_bytes, BLOCK_READ);
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300331 if (ret < 0)
332 return ret;
333
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300334 /* Post-check we received complete message. */
335 slave_bytes = inb(smbus_base + SMBHSTDAT0);
336 if (ret < slave_bytes)
Arthur Heymans1b04aa22017-08-04 14:28:50 +0200337 return SMBUS_ERROR;
338
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300339 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200340}
341
342int do_smbus_block_write(unsigned int smbus_base, u8 device, u8 cmd,
Arthur Heymans1b04aa22017-08-04 14:28:50 +0200343 const unsigned int bytes, const u8 *buf)
Arthur Heymans16fe7902017-04-12 17:01:31 +0200344{
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300345 int ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200346
Kyösti Mälkkic17e8552017-08-20 23:48:23 +0300347 if (bytes > SMBUS_BLOCK_MAXLEN)
Arthur Heymans1b04aa22017-08-04 14:28:50 +0200348 return SMBUS_ERROR;
349
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300350 /* Set up for a block data write. */
351 ret = setup_command(smbus_base, I801_BLOCK_DATA, XMIT_WRITE(device));
352 if (ret < 0)
353 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200354
Arthur Heymans16fe7902017-04-12 17:01:31 +0200355 /* Set the command/address... */
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300356 outb(cmd, smbus_base + SMBHSTCMD);
Arthur Heymans16fe7902017-04-12 17:01:31 +0200357
Kyösti Mälkkid6c15d02017-08-20 21:36:24 +0300358 /* Execute block transaction. */
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300359 ret = block_cmd_loop(smbus_base, (u8 *)buf, bytes, BLOCK_WRITE);
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300360 if (ret < 0)
361 return ret;
362
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300363 if (ret < bytes)
Kyösti Mälkkic17e8552017-08-20 23:48:23 +0300364 return SMBUS_ERROR;
365
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300366 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200367}
368
369/* Only since ICH5 */
Kyösti Mälkkic01a5052019-01-30 09:39:23 +0200370static int has_i2c_read_command(void)
371{
Julius Wernercd49cce2019-03-05 16:53:33 -0800372 if (CONFIG(SOUTHBRIDGE_INTEL_I82371EB) ||
373 CONFIG(SOUTHBRIDGE_INTEL_I82801DX))
Kyösti Mälkkic01a5052019-01-30 09:39:23 +0200374 return 0;
375 return 1;
376}
377
378int do_i2c_eeprom_read(unsigned int smbus_base, u8 device,
Kyösti Mälkki1e392362017-08-20 21:36:03 +0300379 unsigned int offset, const unsigned int bytes, u8 *buf)
Arthur Heymans16fe7902017-04-12 17:01:31 +0200380{
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300381 int ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200382
Kyösti Mälkkic01a5052019-01-30 09:39:23 +0200383 if (!has_i2c_read_command())
384 return SMBUS_ERROR;
385
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300386 /* Set up for a i2c block data read.
387 *
388 * FIXME: Address parameter changes to XMIT_READ(device) with
389 * some revision of PCH. Presumably hardware revisions that
390 * do not have i2c block write support internally set LSB.
391 */
392 ret = setup_command(smbus_base, I801_I2C_BLOCK_DATA,
393 XMIT_WRITE(device));
394 if (ret < 0)
395 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200396
397 /* device offset */
398 outb(offset, smbus_base + SMBHSTDAT1);
399
Kyösti Mälkkid6c15d02017-08-20 21:36:24 +0300400 /* Execute block transaction. */
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300401 ret = block_cmd_loop(smbus_base, buf, bytes, BLOCK_READ | BLOCK_I2C);
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300402 if (ret < 0)
403 return ret;
404
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300405 /* Post-check we received complete message. */
406 if (ret < bytes)
Kyösti Mälkki1e392362017-08-20 21:36:03 +0300407 return SMBUS_ERROR;
408
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300409 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200410}