blob: 1594e684a6d9e2c8cf6f9fe1c7e77d1e24bbe645 [file] [log] [blame]
Angel Pons182dbde2020-04-02 23:49:05 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Arthur Heymans16fe7902017-04-12 17:01:31 +02002
3#include <arch/io.h>
Kyösti Mälkkib5d998b2017-08-20 21:36:08 +03004#include <console/console.h>
Arthur Heymans16fe7902017-04-12 17:01:31 +02005#include <device/smbus_def.h>
Kyösti Mälkki1cae4542020-01-06 12:31:34 +02006#include <device/smbus_host.h>
Elyes HAOUASab89edb2019-05-15 21:10:44 +02007#include <types.h>
8
Julius Wernercd49cce2019-03-05 16:53:33 -08009#if CONFIG(DEBUG_SMBUS)
Kyösti Mälkkib5d998b2017-08-20 21:36:08 +030010#define dprintk(args...) printk(BIOS_DEBUG, ##args)
11#else
12#define dprintk(args...) do {} while (0)
13#endif
14
Kyösti Mälkki7f40bd62020-01-06 19:00:31 +020015/* SMBus register offsets. */
16#define SMBHSTSTAT 0x0
17#define SMBHSTCTL 0x2
18#define SMBHSTCMD 0x3
19#define SMBXMITADD 0x4
20#define SMBHSTDAT0 0x5
21#define SMBHSTDAT1 0x6
22#define SMBBLKDAT 0x7
23#define SMBTRNSADD 0x9
24#define SMBSLVDATA 0xa
25#define SMLINK_PIN_CTL 0xe
26#define SMBUS_PIN_CTL 0xf
27#define SMBSLVCMD 0x11
28
29#define SMB_RCV_SLVA SMBTRNSADD
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)
Christian Walter04953eb2020-03-27 11:59:43 +010036#define I801_PROCESS_CALL (4 << 2)
Arthur Heymans16fe7902017-04-12 17:01:31 +020037#define I801_BLOCK_DATA (5 << 2)
38#define I801_I2C_BLOCK_DATA (6 << 2) /* ICH5 and later */
39
40/* I801 Host Control register bits */
41#define SMBHSTCNT_INTREN (1 << 0)
42#define SMBHSTCNT_KILL (1 << 1)
43#define SMBHSTCNT_LAST_BYTE (1 << 5)
44#define SMBHSTCNT_START (1 << 6)
45#define SMBHSTCNT_PEC_EN (1 << 7) /* ICH3 and later */
46
47/* I801 Hosts Status register bits */
48#define SMBHSTSTS_BYTE_DONE (1 << 7)
49#define SMBHSTSTS_INUSE_STS (1 << 6)
50#define SMBHSTSTS_SMBALERT_STS (1 << 5)
51#define SMBHSTSTS_FAILED (1 << 4)
52#define SMBHSTSTS_BUS_ERR (1 << 3)
53#define SMBHSTSTS_DEV_ERR (1 << 2)
54#define SMBHSTSTS_INTR (1 << 1)
55#define SMBHSTSTS_HOST_BUSY (1 << 0)
56
Kyösti Mälkki957511c2017-08-20 21:36:11 +030057/* For SMBXMITADD register. */
58#define XMIT_WRITE(dev) (((dev) << 1) | 0)
59#define XMIT_READ(dev) (((dev) << 1) | 1)
60
Arthur Heymans16fe7902017-04-12 17:01:31 +020061#define SMBUS_TIMEOUT (10 * 1000 * 100)
Elyes HAOUASb0f19882018-06-09 11:59:00 +020062#define SMBUS_BLOCK_MAXLEN 32
Arthur Heymans16fe7902017-04-12 17:01:31 +020063
Kyösti Mälkki893edee2017-08-20 21:36:24 +030064/* block_cmd_loop flags */
65#define BLOCK_READ 0
66#define BLOCK_WRITE (1 << 0)
67#define BLOCK_I2C (1 << 1)
68
Arthur Heymans16fe7902017-04-12 17:01:31 +020069static void smbus_delay(void)
70{
71 inb(0x80);
72}
73
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +020074static void host_outb(uintptr_t base, u8 reg, u8 value)
Kyösti Mälkkib49638d2020-01-02 16:36:56 +020075{
76 outb(value, base + reg);
77}
78
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +020079static u8 host_inb(uintptr_t base, u8 reg)
Kyösti Mälkkib49638d2020-01-02 16:36:56 +020080{
81 return inb(base + reg);
82}
83
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +020084static void host_and_or(uintptr_t base, u8 reg, u8 mask, u8 or)
Kyösti Mälkki65f5de22020-01-02 16:36:56 +020085{
86 u8 value;
87 value = host_inb(base, reg);
88 value &= mask;
89 value |= or;
90 host_outb(base, reg, value);
91}
92
Kyösti Mälkki7cdcc382020-01-06 19:00:31 +020093void smbus_host_reset(uintptr_t base)
94{
95 /* Disable interrupt generation. */
96 host_outb(base, SMBHSTCTL, 0);
97
98 /* Clear any lingering errors, so transactions can run. */
99 host_and_or(base, SMBHSTSTAT, 0xff, 0);
100}
101
Kyösti Mälkki73451fd2020-01-06 19:00:31 +0200102void smbus_set_slave_addr(uintptr_t base, u8 slave_address)
103{
104 host_outb(base, SMB_RCV_SLVA, slave_address);
105}
106
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300107static int host_completed(u8 status)
108{
109 if (status & SMBHSTSTS_HOST_BUSY)
110 return 0;
Kyösti Mälkki44206e32019-02-26 17:17:24 +0200111
112 /* These status bits do not imply completion of transaction. */
113 status &= ~(SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INUSE_STS |
114 SMBHSTSTS_SMBALERT_STS);
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300115 return status != 0;
116}
117
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200118static int recover_master(uintptr_t base, int ret)
Arthur Heymans16fe7902017-04-12 17:01:31 +0200119{
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300120 /* TODO: Depending of the failure, drive KILL transaction
121 * or force soft reset on SMBus master controller.
122 */
123 printk(BIOS_ERR, "SMBus: Fatal master timeout (%d)\n", ret);
124 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200125}
126
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300127static int cb_err_from_stat(u8 status)
128{
Kyösti Mälkki44206e32019-02-26 17:17:24 +0200129 /* These status bits do not imply errors. */
130 status &= ~(SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INUSE_STS |
131 SMBHSTSTS_SMBALERT_STS);
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300132
133 if (status == SMBHSTSTS_INTR)
134 return 0;
135
136 return SMBUS_ERROR;
137}
138
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200139static int setup_command(uintptr_t base, u8 ctrl, u8 xmitadd)
Arthur Heymans16fe7902017-04-12 17:01:31 +0200140{
141 unsigned int loops = SMBUS_TIMEOUT;
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300142 u8 host_busy;
143
Arthur Heymans16fe7902017-04-12 17:01:31 +0200144 do {
145 smbus_delay();
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200146 host_busy = host_inb(base, SMBHSTSTAT) & SMBHSTSTS_HOST_BUSY;
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300147 } while (--loops && host_busy);
148
149 if (loops == 0)
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200150 return recover_master(base, SMBUS_WAIT_UNTIL_READY_TIMEOUT);
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300151
152 /* Clear any lingering errors, so the transaction will run. */
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200153 host_and_or(base, SMBHSTSTAT, 0xff, 0);
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300154
155 /* Set up transaction */
156 /* Disable interrupts */
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200157 host_outb(base, SMBHSTCTL, ctrl);
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300158
159 /* Set the device I'm talking to. */
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200160 host_outb(base, SMBXMITADD, xmitadd);
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300161
162 return 0;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200163}
164
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200165static int execute_command(uintptr_t base)
Arthur Heymans16fe7902017-04-12 17:01:31 +0200166{
Kyösti Mälkkia2dcf732017-08-20 21:36:15 +0300167 unsigned int loops = SMBUS_TIMEOUT;
168 u8 status;
169
170 /* Start the command. */
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200171 host_and_or(base, SMBHSTCTL, 0xff, SMBHSTCNT_START);
Kyösti Mälkkia2dcf732017-08-20 21:36:15 +0300172
173 /* Poll for it to start. */
Arthur Heymans16fe7902017-04-12 17:01:31 +0200174 do {
Arthur Heymans16fe7902017-04-12 17:01:31 +0200175 smbus_delay();
Kyösti Mälkkia2dcf732017-08-20 21:36:15 +0300176
177 /* If we poll too slow, we could miss HOST_BUSY flag
178 * set and detect INTR or x_ERR flags instead here.
179 */
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200180 status = host_inb(base, SMBHSTSTAT);
Kyösti Mälkkia2dcf732017-08-20 21:36:15 +0300181 status &= ~(SMBHSTSTS_SMBALERT_STS | SMBHSTSTS_INUSE_STS);
182 } while (--loops && status == 0);
183
184 if (loops == 0)
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200185 return recover_master(base,
Kyösti Mälkkia2dcf732017-08-20 21:36:15 +0300186 SMBUS_WAIT_UNTIL_ACTIVE_TIMEOUT);
187
188 return 0;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200189}
190
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200191static int complete_command(uintptr_t base)
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300192{
193 unsigned int loops = SMBUS_TIMEOUT;
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300194 u8 status;
195
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300196 do {
197 smbus_delay();
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200198 status = host_inb(base, SMBHSTSTAT);
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300199 } while (--loops && !host_completed(status));
200
201 if (loops == 0)
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200202 return recover_master(base,
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300203 SMBUS_WAIT_UNTIL_DONE_TIMEOUT);
204
205 return cb_err_from_stat(status);
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300206}
207
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200208static int smbus_read_cmd(uintptr_t base, u8 ctrl, u8 device, u8 address)
Arthur Heymans16fe7902017-04-12 17:01:31 +0200209{
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300210 int ret;
Kyösti Mälkki7ca19b22020-01-02 17:02:54 +0200211 u16 word;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200212
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300213 /* Set up for a byte data read. */
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200214 ret = setup_command(base, ctrl, XMIT_READ(device));
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300215 if (ret < 0)
216 return ret;
217
Arthur Heymans16fe7902017-04-12 17:01:31 +0200218 /* Set the command/address... */
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200219 host_outb(base, SMBHSTCMD, address);
Arthur Heymans16fe7902017-04-12 17:01:31 +0200220
Kyösti Mälkki7ca19b22020-01-02 17:02:54 +0200221 /* Clear the data bytes... */
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200222 host_outb(base, SMBHSTDAT0, 0);
223 host_outb(base, SMBHSTDAT1, 0);
Arthur Heymans16fe7902017-04-12 17:01:31 +0200224
225 /* Start the command */
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200226 ret = execute_command(base);
Kyösti Mälkkia2dcf732017-08-20 21:36:15 +0300227 if (ret < 0)
228 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200229
230 /* Poll for transaction completion */
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200231 ret = complete_command(base);
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300232 if (ret < 0)
233 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200234
235 /* Read results of transaction */
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200236 word = host_inb(base, SMBHSTDAT0);
Kyösti Mälkki7ca19b22020-01-02 17:02:54 +0200237 if (ctrl == I801_WORD_DATA)
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200238 word |= host_inb(base, SMBHSTDAT1) << 8;
Kyösti Mälkki7ca19b22020-01-02 17:02:54 +0200239
240 return word;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200241}
242
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200243static int smbus_write_cmd(uintptr_t base, u8 ctrl, u8 device, u8 address, u16 data)
Arthur Heymans16fe7902017-04-12 17:01:31 +0200244{
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300245 int ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200246
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300247 /* Set up for a byte data write. */
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200248 ret = setup_command(base, ctrl, XMIT_WRITE(device));
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300249 if (ret < 0)
250 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200251
Arthur Heymans16fe7902017-04-12 17:01:31 +0200252 /* Set the command/address... */
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200253 host_outb(base, SMBHSTCMD, address);
Arthur Heymans16fe7902017-04-12 17:01:31 +0200254
Kyösti Mälkki7ca19b22020-01-02 17:02:54 +0200255 /* Set the data bytes... */
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200256 host_outb(base, SMBHSTDAT0, data & 0xff);
Kyösti Mälkki7ca19b22020-01-02 17:02:54 +0200257 if (ctrl == I801_WORD_DATA)
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200258 host_outb(base, SMBHSTDAT1, data >> 8);
Arthur Heymans16fe7902017-04-12 17:01:31 +0200259
260 /* Start the command */
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200261 ret = execute_command(base);
Kyösti Mälkkia2dcf732017-08-20 21:36:15 +0300262 if (ret < 0)
263 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200264
265 /* Poll for transaction completion */
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200266 return complete_command(base);
Arthur Heymans16fe7902017-04-12 17:01:31 +0200267}
268
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200269static int block_cmd_loop(uintptr_t base, u8 *buf, size_t max_bytes, int flags)
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300270{
271 u8 status;
272 unsigned int loops = SMBUS_TIMEOUT;
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200273 int ret;
274 size_t bytes = 0;
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300275 int is_write_cmd = flags & BLOCK_WRITE;
276 int sw_drives_nak = flags & BLOCK_I2C;
277
278 /* Hardware limitations. */
279 if (flags == (BLOCK_WRITE | BLOCK_I2C))
280 return SMBUS_ERROR;
281
Kyösti Mälkkid6c15d02017-08-20 21:36:24 +0300282 /* Set number of bytes to transfer. */
283 /* Reset number of bytes to transfer so we notice later it
284 * was really updated with the transaction. */
285 if (!sw_drives_nak) {
286 if (is_write_cmd)
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200287 host_outb(base, SMBHSTDAT0, max_bytes);
Kyösti Mälkkid6c15d02017-08-20 21:36:24 +0300288 else
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200289 host_outb(base, SMBHSTDAT0, 0);
Kyösti Mälkkid6c15d02017-08-20 21:36:24 +0300290 }
291
292 /* Send first byte from buffer, bytes_sent increments after
293 * hardware acknowledges it.
294 */
295 if (is_write_cmd)
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200296 host_outb(base, SMBBLKDAT, *buf++);
Kyösti Mälkkid6c15d02017-08-20 21:36:24 +0300297
298 /* Start the command */
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200299 ret = execute_command(base);
Kyösti Mälkkid6c15d02017-08-20 21:36:24 +0300300 if (ret < 0)
301 return ret;
302
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300303 /* Poll for transaction completion */
304 do {
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200305 status = host_inb(base, SMBHSTSTAT);
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300306
307 if (status & SMBHSTSTS_BYTE_DONE) { /* Byte done */
308
309 if (is_write_cmd) {
310 bytes++;
311 if (bytes < max_bytes)
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200312 host_outb(base, SMBBLKDAT, *buf++);
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300313 } else {
314 if (bytes < max_bytes)
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200315 *buf++ = host_inb(base, SMBBLKDAT);
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300316 bytes++;
317
318 /* Indicate that next byte is the last one. */
319 if (sw_drives_nak && (bytes + 1 >= max_bytes)) {
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200320 host_and_or(base, SMBHSTCTL, 0xff,
321 SMBHSTCNT_LAST_BYTE);
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300322 }
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300323 }
324
325 /* Engine internally completes the transaction
326 * and clears HOST_BUSY flag once the byte count
327 * has been reached or LAST_BYTE was set.
328 */
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200329 host_outb(base, SMBHSTSTAT, SMBHSTSTS_BYTE_DONE);
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300330 }
331
332 } while (--loops && !host_completed(status));
333
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200334 dprintk("%s: status = %02x, len = %zd / %zd, loops = %d\n",
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300335 __func__, status, bytes, max_bytes, SMBUS_TIMEOUT - loops);
336
337 if (loops == 0)
Kyösti Mälkki5e9ae0c2020-01-06 13:35:59 +0200338 return recover_master(base, SMBUS_WAIT_UNTIL_DONE_TIMEOUT);
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300339
340 ret = cb_err_from_stat(status);
341 if (ret < 0)
342 return ret;
343
344 return bytes;
345}
346
Kyösti Mälkkic5284262020-01-06 12:31:34 +0200347int do_smbus_read_byte(uintptr_t base, u8 device, u8 address)
Kyösti Mälkki7ca19b22020-01-02 17:02:54 +0200348{
Kyösti Mälkkic5284262020-01-06 12:31:34 +0200349 return smbus_read_cmd(base, I801_BYTE_DATA, device, address);
Kyösti Mälkki7ca19b22020-01-02 17:02:54 +0200350}
351
Kyösti Mälkkic5284262020-01-06 12:31:34 +0200352int do_smbus_read_word(uintptr_t base, u8 device, u8 address)
Kyösti Mälkki7ca19b22020-01-02 17:02:54 +0200353{
Kyösti Mälkkic5284262020-01-06 12:31:34 +0200354 return smbus_read_cmd(base, I801_WORD_DATA, device, address);
Kyösti Mälkki7ca19b22020-01-02 17:02:54 +0200355}
356
Kyösti Mälkkic5284262020-01-06 12:31:34 +0200357int do_smbus_write_byte(uintptr_t base, u8 device, u8 address, u8 data)
Kyösti Mälkki7ca19b22020-01-02 17:02:54 +0200358{
Kyösti Mälkkic5284262020-01-06 12:31:34 +0200359 return smbus_write_cmd(base, I801_BYTE_DATA, device, address, data);
Kyösti Mälkki7ca19b22020-01-02 17:02:54 +0200360}
361
Kyösti Mälkkic5284262020-01-06 12:31:34 +0200362int do_smbus_write_word(uintptr_t base, u8 device, u8 address, u16 data)
Kyösti Mälkki7ca19b22020-01-02 17:02:54 +0200363{
Kyösti Mälkkic5284262020-01-06 12:31:34 +0200364 return smbus_write_cmd(base, I801_WORD_DATA, device, address, data);
Kyösti Mälkki7ca19b22020-01-02 17:02:54 +0200365}
366
Kyösti Mälkkic5284262020-01-06 12:31:34 +0200367int do_smbus_block_read(uintptr_t base, u8 device, u8 cmd, size_t max_bytes, u8 *buf)
Arthur Heymans16fe7902017-04-12 17:01:31 +0200368{
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300369 int ret, slave_bytes;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200370
Kyösti Mälkkic17e8552017-08-20 23:48:23 +0300371 max_bytes = MIN(SMBUS_BLOCK_MAXLEN, max_bytes);
Arthur Heymans1b04aa22017-08-04 14:28:50 +0200372
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300373 /* Set up for a block data read. */
Kyösti Mälkkic5284262020-01-06 12:31:34 +0200374 ret = setup_command(base, I801_BLOCK_DATA, XMIT_READ(device));
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300375 if (ret < 0)
376 return ret;
377
Arthur Heymans16fe7902017-04-12 17:01:31 +0200378 /* Set the command/address... */
Kyösti Mälkkic5284262020-01-06 12:31:34 +0200379 host_outb(base, SMBHSTCMD, cmd);
Arthur Heymans16fe7902017-04-12 17:01:31 +0200380
Kyösti Mälkkid6c15d02017-08-20 21:36:24 +0300381 /* Execute block transaction. */
Kyösti Mälkkic5284262020-01-06 12:31:34 +0200382 ret = block_cmd_loop(base, buf, max_bytes, BLOCK_READ);
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300383 if (ret < 0)
384 return ret;
385
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300386 /* Post-check we received complete message. */
Kyösti Mälkkic5284262020-01-06 12:31:34 +0200387 slave_bytes = host_inb(base, SMBHSTDAT0);
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300388 if (ret < slave_bytes)
Arthur Heymans1b04aa22017-08-04 14:28:50 +0200389 return SMBUS_ERROR;
390
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300391 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200392}
393
Christian Walter04953eb2020-03-27 11:59:43 +0100394/*
395 * The caller is responsible of settings HOSTC I2C_EN bit prior to making this
396 * call!
397 */
398int do_smbus_process_call(uintptr_t base, u8 device, u8 cmd, u16 data, u16 *buf)
399{
400 int ret;
401
402 /* Set up for process call */
403 ret = setup_command(base, I801_PROCESS_CALL, XMIT_WRITE(device));
404 if (ret < 0)
405 return ret;
406
407 /* cmd will only be send if I2C_EN is zero */
408 host_outb(base, SMBHSTCMD, cmd);
409
410 host_outb(base, SMBHSTDAT0, data & 0x00ff);
411 host_outb(base, SMBHSTDAT1, (data & 0xff00) >> 8);
412
413 /* Start the command */
414 ret = execute_command(base);
415 if (ret < 0)
416 return ret;
417
418 /* Poll for transaction completion */
419 ret = complete_command(base);
420 if (ret < 0)
421 return ret;
422
423 /* Read results of transaction */
424 *buf = host_inb(base, SMBHSTDAT0);
425 *buf |= (host_inb(base, SMBHSTDAT1) << 8);
426
427 return ret;
428}
429
Kyösti Mälkkic5284262020-01-06 12:31:34 +0200430int do_smbus_block_write(uintptr_t base, u8 device, u8 cmd, const size_t bytes, const u8 *buf)
Arthur Heymans16fe7902017-04-12 17:01:31 +0200431{
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300432 int ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200433
Kyösti Mälkkic17e8552017-08-20 23:48:23 +0300434 if (bytes > SMBUS_BLOCK_MAXLEN)
Arthur Heymans1b04aa22017-08-04 14:28:50 +0200435 return SMBUS_ERROR;
436
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300437 /* Set up for a block data write. */
Kyösti Mälkkic5284262020-01-06 12:31:34 +0200438 ret = setup_command(base, I801_BLOCK_DATA, XMIT_WRITE(device));
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300439 if (ret < 0)
440 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200441
Arthur Heymans16fe7902017-04-12 17:01:31 +0200442 /* Set the command/address... */
Kyösti Mälkkic5284262020-01-06 12:31:34 +0200443 host_outb(base, SMBHSTCMD, cmd);
Arthur Heymans16fe7902017-04-12 17:01:31 +0200444
Kyösti Mälkkid6c15d02017-08-20 21:36:24 +0300445 /* Execute block transaction. */
Kyösti Mälkkic5284262020-01-06 12:31:34 +0200446 ret = block_cmd_loop(base, (u8 *)buf, bytes, BLOCK_WRITE);
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300447 if (ret < 0)
448 return ret;
449
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300450 if (ret < bytes)
Kyösti Mälkkic17e8552017-08-20 23:48:23 +0300451 return SMBUS_ERROR;
452
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300453 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200454}
455
456/* Only since ICH5 */
Kyösti Mälkkic01a5052019-01-30 09:39:23 +0200457static int has_i2c_read_command(void)
458{
Kyösti Mälkki7b73e8522022-11-08 04:43:41 +0000459 if (CONFIG(SOUTHBRIDGE_INTEL_I82371EB) ||
460 CONFIG(SOUTHBRIDGE_INTEL_I82801DX))
Kyösti Mälkkic01a5052019-01-30 09:39:23 +0200461 return 0;
462 return 1;
463}
464
Kyösti Mälkkic5284262020-01-06 12:31:34 +0200465int do_i2c_eeprom_read(uintptr_t base, u8 device, u8 offset, const size_t bytes, u8 *buf)
Arthur Heymans16fe7902017-04-12 17:01:31 +0200466{
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300467 int ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200468
Kyösti Mälkkic01a5052019-01-30 09:39:23 +0200469 if (!has_i2c_read_command())
470 return SMBUS_ERROR;
471
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300472 /* Set up for a i2c block data read.
473 *
474 * FIXME: Address parameter changes to XMIT_READ(device) with
475 * some revision of PCH. Presumably hardware revisions that
476 * do not have i2c block write support internally set LSB.
477 */
Kyösti Mälkkic5284262020-01-06 12:31:34 +0200478 ret = setup_command(base, I801_I2C_BLOCK_DATA,
Kyösti Mälkki957511c2017-08-20 21:36:11 +0300479 XMIT_WRITE(device));
480 if (ret < 0)
481 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200482
483 /* device offset */
Kyösti Mälkkic5284262020-01-06 12:31:34 +0200484 host_outb(base, SMBHSTDAT1, offset);
Arthur Heymans16fe7902017-04-12 17:01:31 +0200485
Kyösti Mälkkid6c15d02017-08-20 21:36:24 +0300486 /* Execute block transaction. */
Kyösti Mälkkic5284262020-01-06 12:31:34 +0200487 ret = block_cmd_loop(base, buf, bytes, BLOCK_READ | BLOCK_I2C);
Kyösti Mälkkic38d5432017-08-20 21:36:18 +0300488 if (ret < 0)
489 return ret;
490
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300491 /* Post-check we received complete message. */
492 if (ret < bytes)
Kyösti Mälkki1e392362017-08-20 21:36:03 +0300493 return SMBUS_ERROR;
494
Kyösti Mälkki893edee2017-08-20 21:36:24 +0300495 return ret;
Arthur Heymans16fe7902017-04-12 17:01:31 +0200496}
Frans Hendrikse48be352019-06-19 11:01:27 +0200497
498/*
499 * The caller is responsible of settings HOSTC I2C_EN bit prior to making this
500 * call!
501 */
Kyösti Mälkkic5284262020-01-06 12:31:34 +0200502int do_i2c_block_write(uintptr_t base, u8 device, size_t bytes, u8 *buf)
Frans Hendrikse48be352019-06-19 11:01:27 +0200503{
504 u8 cmd;
505 int ret;
506
507 if (!CONFIG(SOC_INTEL_BRASWELL))
508 return SMBUS_ERROR;
509
510 if (!bytes || (bytes > SMBUS_BLOCK_MAXLEN))
511 return SMBUS_ERROR;
512
513 /* Set up for a block data write. */
Kyösti Mälkkic5284262020-01-06 12:31:34 +0200514 ret = setup_command(base, I801_BLOCK_DATA, XMIT_WRITE(device));
Frans Hendrikse48be352019-06-19 11:01:27 +0200515 if (ret < 0)
516 return ret;
517
518 /*
519 * In i2c mode SMBus controller sequence on bus will be:
520 * <SMBXINTADD> <SMBHSTDAT1> <SMBBLKDAT> .. <SMBBLKDAT>
521 * The SMBHSTCMD must be written also to ensure the SMBUs controller
522 * will generate the i2c sequence.
523 */
524 cmd = *buf++;
525 bytes--;
Kyösti Mälkkic5284262020-01-06 12:31:34 +0200526 host_outb(base, SMBHSTCMD, cmd);
527 host_outb(base, SMBHSTDAT1, cmd);
Frans Hendrikse48be352019-06-19 11:01:27 +0200528
529 /* Execute block transaction. */
Kyösti Mälkkic5284262020-01-06 12:31:34 +0200530 ret = block_cmd_loop(base, buf, bytes, BLOCK_WRITE);
Frans Hendrikse48be352019-06-19 11:01:27 +0200531 if (ret < 0)
532 return ret;
533
534 if (ret < bytes)
535 return SMBUS_ERROR;
536
537 ret++; /* 1st byte has been written using SMBHSTDAT1 */
538 return ret;
539}