<p>Youness Alaoui has uploaded this change for <strong>review</strong>.</p><p><a href="https://review.coreboot.org/22967">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">intel/common/smbus: Add support for reading SPD by block<br><br>This change adds support for reading from the SMBus using the Block Read<br>command, which speeds up the transfer of data significantly (~75%) when<br>compared to Byte Read or Word Read commands.<br><br>There are two methods for reading block data, either with the E32B option<br>or without it. When enabling E32B, a 32 Byte array is used to return<br>up to 32 bytes of block data. Otherwise, each byte needs to be read<br>from a single byte register whenever it becomes available.<br><br>When testing on Purism Librem 13 v2, the E32B option did not work, as<br>it would return mangled data every time and at the wrong offsets from<br>what was requested. Doing a byte-by-byte read works correctly however.<br><br>Unfortunately, there is a quirk in the SMBus controller where the first<br>byte of data is returned in the DAT0 register and the rest is returned<br>in the HBD register (as expected). The datasheet says that the DAT0<br>register should instead contain the number of bytes being returned.<br><br>This change adds three new options, one for using the Block Read to read<br>the SPD data, one to specify whether to use the E32B feature or not, and<br>one for the DAT0 quirk mentioned above.<br><br>Note that the E32B implementation was not tested on compatible hardware<br>but it was written to follow the specification and should work if the<br>hardware supports E32B and has no additional quirks.<br><br>Speed improvements :<br>- With Byte Read : 218 ms to dump DDR4 SPD data (512 bytes)<br>- With Word Read : 134 ms to dump DDR4 SPD data (512 bytes)<br>- With Block Read : 62 ms to dump DDR4 SPD data (512 bytes)<br>- With Byte Read : 108 ms to dump DDR3 SPD data (256 bytes)<br>- With Word Read : 66 ms to dump DDR3 SPD data (256 bytes)<br>- With Block Read : 34 ms to dump DDR3 SPD data (256 bytes)<br><br>Tested on Purism Librem 13 v2 and Librem 15 v3 with the DAT0<br>Quirk option enabled.<br><br>Change-Id: I14882b646e7c0fa96cf38a698562cc20bbd41095<br>Signed-off-by: Youness Alaoui <youness.alaoui@puri.sm><br>---<br>M src/Kconfig<br>M src/include/device/early_smbus.h<br>M src/lib/spd_bin.c<br>M src/soc/intel/common/block/smbus/smbus_early.c<br>M src/soc/intel/common/block/smbus/smbuslib.c<br>M src/soc/intel/common/block/smbus/smbuslib.h<br>6 files changed, 195 insertions(+), 8 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://review.coreboot.org:29418/coreboot refs/changes/67/22967/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/src/Kconfig b/src/Kconfig</span><br><span>index 6896d0e..8c524a5 100644</span><br><span>--- a/src/Kconfig</span><br><span>+++ b/src/Kconfig</span><br><span>@@ -1200,6 +1200,34 @@</span><br><span> </span><br><span> config SPD_READ_BY_WORD</span><br><span> bool</span><br><span style="color: hsl(120, 100%, 40%);">+ help</span><br><span style="color: hsl(120, 100%, 40%);">+ Use the Read Word command to the SMBus to read the SPD data.</span><br><span style="color: hsl(120, 100%, 40%);">+ This option can speed up boot time by ~80 to ~90ms</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+config SPD_READ_BY_BLOCK</span><br><span style="color: hsl(120, 100%, 40%);">+ bool</span><br><span style="color: hsl(120, 100%, 40%);">+ default n</span><br><span style="color: hsl(120, 100%, 40%);">+ help</span><br><span style="color: hsl(120, 100%, 40%);">+ Use the Read Block command to the SMBus to read the SPD data.</span><br><span style="color: hsl(120, 100%, 40%);">+ This option can speed up boot time by ~150ms</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+config SMBUS_BLOCK_READ_SUPPORTS_E32B</span><br><span style="color: hsl(120, 100%, 40%);">+ bool</span><br><span style="color: hsl(120, 100%, 40%);">+ default n</span><br><span style="color: hsl(120, 100%, 40%);">+ help</span><br><span style="color: hsl(120, 100%, 40%);">+ Enable if the SMBus supports the E32B option to use a 32-byte array</span><br><span style="color: hsl(120, 100%, 40%);">+ for the Read Block command. Some interfaces may not support this</span><br><span style="color: hsl(120, 100%, 40%);">+ feature, and it can cause invalid data to be returned.</span><br><span style="color: hsl(120, 100%, 40%);">+ When in doubt, keep disabled, and the Read Block command will use a</span><br><span style="color: hsl(120, 100%, 40%);">+ single byte register to read data from the controller instead.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+config SMBUS_BLOCK_READ_DAT0_QUIRK</span><br><span style="color: hsl(120, 100%, 40%);">+ bool</span><br><span style="color: hsl(120, 100%, 40%);">+ default n</span><br><span style="color: hsl(120, 100%, 40%);">+ help</span><br><span style="color: hsl(120, 100%, 40%);">+ This quirk was experienced on Skylake (Purism Librem) machines where the</span><br><span style="color: hsl(120, 100%, 40%);">+ DAT0 register contains the first byte of the block instead of containing</span><br><span style="color: hsl(120, 100%, 40%);">+ the number of bytes returned.</span><br><span> </span><br><span> config BOOTBLOCK_CUSTOM</span><br><span> # To be selected by arch, SoC or mainboard if it does not want use the normal</span><br><span>diff --git a/src/include/device/early_smbus.h b/src/include/device/early_smbus.h</span><br><span>index c907396..84baddb 100644</span><br><span>--- a/src/include/device/early_smbus.h</span><br><span>+++ b/src/include/device/early_smbus.h</span><br><span>@@ -66,6 +66,7 @@</span><br><span> u16 smbus_read_word(u32 smbus_dev, u8 addr, u8 offset);</span><br><span> u8 smbus_read_byte(u32 smbus_dev, u8 addr, u8 offset);</span><br><span> u8 smbus_write_byte(u32 smbus_dev, u8 addr, u8 offset, u8 value);</span><br><span style="color: hsl(120, 100%, 40%);">+u16 smbus_read_block(u32 smbus_dev, u8 addr, u8 offset, u8 *data, u16 max_size);</span><br><span> void smbus_delay(void);</span><br><span> </span><br><span> #endif /* DEVICE_EARLY_SMBUS_H */</span><br><span>diff --git a/src/lib/spd_bin.c b/src/lib/spd_bin.c</span><br><span>index 79bda1e..37c8032 100644</span><br><span>--- a/src/lib/spd_bin.c</span><br><span>+++ b/src/lib/spd_bin.c</span><br><span>@@ -15,6 +15,7 @@</span><br><span> </span><br><span> #include <arch/byteorder.h></span><br><span> #include <cbfs.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <lib.h></span><br><span> #include <console/console.h></span><br><span> #include <spd_bin.h></span><br><span> #include <string.h></span><br><span>@@ -128,18 +129,32 @@</span><br><span> static void smbus_read_spd(u8 *spd, u8 addr)</span><br><span> {</span><br><span> u16 i;</span><br><span style="color: hsl(0, 100%, 40%);">- u8 step = 1;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- if (IS_ENABLED(CONFIG_SPD_READ_BY_WORD))</span><br><span style="color: hsl(0, 100%, 40%);">- step = sizeof(uint16_t);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (IS_ENABLED(CONFIG_SPD_READ_BY_BLOCK)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ u16 read_size;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- for (i = 0; i < SPD_PAGE_LEN; i += step) {</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < SPD_PAGE_LEN;) {</span><br><span style="color: hsl(120, 100%, 40%);">+ read_size = smbus_read_block(0, addr, i, &spd[i],</span><br><span style="color: hsl(120, 100%, 40%);">+ SPD_PAGE_LEN - i);</span><br><span style="color: hsl(120, 100%, 40%);">+ i += read_size;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (read_size == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ u8 step = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> if (IS_ENABLED(CONFIG_SPD_READ_BY_WORD))</span><br><span style="color: hsl(0, 100%, 40%);">- ((u16*)spd)[i / sizeof(uint16_t)] =</span><br><span style="color: hsl(0, 100%, 40%);">- smbus_read_word(0, addr, i);</span><br><span style="color: hsl(0, 100%, 40%);">- else</span><br><span style="color: hsl(0, 100%, 40%);">- spd[i] = smbus_read_byte(0, addr, i);</span><br><span style="color: hsl(120, 100%, 40%);">+ step = sizeof(uint16_t);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < SPD_PAGE_LEN; i += step) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (IS_ENABLED(CONFIG_SPD_READ_BY_WORD))</span><br><span style="color: hsl(120, 100%, 40%);">+ ((u16 *)spd)[i / sizeof(uint16_t)] =</span><br><span style="color: hsl(120, 100%, 40%);">+ smbus_read_word(0, addr, i);</span><br><span style="color: hsl(120, 100%, 40%);">+ else</span><br><span style="color: hsl(120, 100%, 40%);">+ spd[i] = smbus_read_byte(0, addr, i);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> }</span><br><span> </span><br><span> static void get_spd(u8 *spd, u8 addr)</span><br><span>diff --git a/src/soc/intel/common/block/smbus/smbus_early.c b/src/soc/intel/common/block/smbus/smbus_early.c</span><br><span>index 9e6afc4..c244eeb 100644</span><br><span>--- a/src/soc/intel/common/block/smbus/smbus_early.c</span><br><span>+++ b/src/soc/intel/common/block/smbus/smbus_early.c</span><br><span>@@ -46,6 +46,15 @@</span><br><span> return smbus_read8(SMBUS_IO_BASE, addr, offset);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+u16 smbus_read_block(u32 smbus_dev, u8 addr, u8 offset, u8 *data, u16 max_size)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int read_size = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (smbus_read_block_data(SMBUS_IO_BASE, addr, offset, data,</span><br><span style="color: hsl(120, 100%, 40%);">+ max_size, &read_size) != 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ return read_size;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> u8 smbus_write_byte(u32 smbus_dev, u8 addr, u8 offset, u8 value)</span><br><span> {</span><br><span> return smbus_write8(SMBUS_IO_BASE, addr, offset, value);</span><br><span>diff --git a/src/soc/intel/common/block/smbus/smbuslib.c b/src/soc/intel/common/block/smbus/smbuslib.c</span><br><span>index 0d3901f..e1a57af 100644</span><br><span>--- a/src/soc/intel/common/block/smbus/smbuslib.c</span><br><span>+++ b/src/soc/intel/common/block/smbus/smbuslib.c</span><br><span>@@ -46,6 +46,21 @@</span><br><span> return -1;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static int smbus_wait_till_byte_done(u16 smbus_base)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct stopwatch sw;</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned char byte;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ stopwatch_init_msecs_expire(&sw, SMBUS_TIMEOUT);</span><br><span style="color: hsl(120, 100%, 40%);">+ do {</span><br><span style="color: hsl(120, 100%, 40%);">+ byte = inb(smbus_base + SMBHSTSTAT);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!((byte & 1) || (byte & ~((1 << 6) | (1 << 0))) == 0) ||</span><br><span style="color: hsl(120, 100%, 40%);">+ (byte & (1 << 7)))</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ } while (!stopwatch_expired(&sw));</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> int smbus_read8(unsigned int smbus_base, unsigned int device,</span><br><span> unsigned int address)</span><br><span> {</span><br><span>@@ -176,3 +191,116 @@</span><br><span> </span><br><span> return data;</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * Read from SMBus using the Block Data command.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Data is stored in the @data variable up to @max_size bytes.</span><br><span style="color: hsl(120, 100%, 40%);">+ * The number of bytes read will be returned in @read_size argument.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Returns 0 if successful.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int smbus_read_block_data(unsigned int smbus_base, unsigned int device,</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int address, unsigned char *data, unsigned int max_size,</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int *read_size)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned char global_status_register;</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned char count;</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (smbus_wait_till_ready(smbus_base) < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ return SMBUS_WAIT_UNTIL_READY_TIMEOUT;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Set up transaction */</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Disable interrupts */</span><br><span style="color: hsl(120, 100%, 40%);">+ outb(inb(smbus_base + SMBHSTCTL) & ~1, smbus_base + SMBHSTCTL);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Set the device I'm talking to */</span><br><span style="color: hsl(120, 100%, 40%);">+ outb(((device & 0x7f) << 1) | 1, smbus_base + SMBXMITADD);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Set the command/address... */</span><br><span style="color: hsl(120, 100%, 40%);">+ outb(address & 0xff, smbus_base + SMBHSTCMD);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (IS_ENABLED(CONFIG_SMBUS_BLOCK_READ_SUPPORTS_E32B)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Enable E32B */</span><br><span style="color: hsl(120, 100%, 40%);">+ outb(inb(smbus_base + SMBHSTAUXC) | (1 << 1),</span><br><span style="color: hsl(120, 100%, 40%);">+ smbus_base + SMBHSTAUXC);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Disable E32B */</span><br><span style="color: hsl(120, 100%, 40%);">+ outb(inb(smbus_base + SMBHSTAUXC) & ~(1 << 1),</span><br><span style="color: hsl(120, 100%, 40%);">+ smbus_base + SMBHSTAUXC);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Set up for a block data read */</span><br><span style="color: hsl(120, 100%, 40%);">+ outb((inb(smbus_base + SMBHSTCTL) & 0xe3) | (0x5 << 2),</span><br><span style="color: hsl(120, 100%, 40%);">+ (smbus_base + SMBHSTCTL));</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Clear any lingering errors, so the transaction will run */</span><br><span style="color: hsl(120, 100%, 40%);">+ outb(inb(smbus_base + SMBHSTSTAT), smbus_base + SMBHSTSTAT);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Start the command */</span><br><span style="color: hsl(120, 100%, 40%);">+ outb((inb(smbus_base + SMBHSTCTL) | 0x40),</span><br><span style="color: hsl(120, 100%, 40%);">+ smbus_base + SMBHSTCTL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Read results of transaction */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (IS_ENABLED(CONFIG_SMBUS_BLOCK_READ_SUPPORTS_E32B)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Poll for transaction completion */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (smbus_wait_till_done(smbus_base) < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ global_status_register = inb(smbus_base + SMBHSTSTAT);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Ignore the "In Use" status... */</span><br><span style="color: hsl(120, 100%, 40%);">+ if ((global_status_register & ~(3 << 5)) != (1 << 1))</span><br><span style="color: hsl(120, 100%, 40%);">+ return SMBUS_ERROR;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ count = inb(smbus_base + SMBHSTDAT0);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (count < 1 || count > 32)</span><br><span style="color: hsl(120, 100%, 40%);">+ return SMBUS_ERROR;</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < count && i < max_size; i++)</span><br><span style="color: hsl(120, 100%, 40%);">+ data[i] = inb(smbus_base + SMBHSTHBD);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ *read_size = i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Disable E32B */</span><br><span style="color: hsl(120, 100%, 40%);">+ outb(inb(smbus_base + SMBHSTAUXC) & ~(1 << 1),</span><br><span style="color: hsl(120, 100%, 40%);">+ smbus_base + SMBHSTAUXC);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ i = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ while (i < max_size) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Poll for transaction completion */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (smbus_wait_till_byte_done(smbus_base) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Recover idle status of controller */</span><br><span style="color: hsl(120, 100%, 40%);">+ while (inb(smbus_base + SMBHSTSTAT) & 1)</span><br><span style="color: hsl(120, 100%, 40%);">+ outb(1 << 7, smbus_base + SMBHSTSTAT);</span><br><span style="color: hsl(120, 100%, 40%);">+ return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Check if we're done and no more bytes are returned */</span><br><span style="color: hsl(120, 100%, 40%);">+ global_status_register = inb(smbus_base + SMBHSTSTAT);</span><br><span style="color: hsl(120, 100%, 40%);">+ if ((global_status_register & (1 << 7 | 1 << 0)) == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (i == 0 &&</span><br><span style="color: hsl(120, 100%, 40%);">+ IS_ENABLED(CONFIG_SMBUS_BLOCK_READ_DAT0_QUIRK)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Contrary to what the datasheet says, the DAT0</span><br><span style="color: hsl(120, 100%, 40%);">+ register contains the first byte of data</span><br><span style="color: hsl(120, 100%, 40%);">+ instead of containing the number of bytes</span><br><span style="color: hsl(120, 100%, 40%);">+ being returned */</span><br><span style="color: hsl(120, 100%, 40%);">+ data[i++] = inb(smbus_base + SMBHSTDAT0);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (i >= max_size)</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ data[i++] = inb(smbus_base + SMBHSTHBD);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Clear the Byte Done bit */</span><br><span style="color: hsl(120, 100%, 40%);">+ outb(1 << 7, smbus_base + SMBHSTSTAT);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* In case more bytes are available, ignore the rest and</span><br><span style="color: hsl(120, 100%, 40%);">+ recover idle status of the controller */</span><br><span style="color: hsl(120, 100%, 40%);">+ while (inb(smbus_base + SMBHSTSTAT) & 1)</span><br><span style="color: hsl(120, 100%, 40%);">+ outb(1 << 7, smbus_base + SMBHSTSTAT);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Ignore the "In Use" status... */</span><br><span style="color: hsl(120, 100%, 40%);">+ global_status_register = inb(smbus_base + SMBHSTSTAT);</span><br><span style="color: hsl(120, 100%, 40%);">+ if ((global_status_register & ~(3 << 5)) != (1 << 1))</span><br><span style="color: hsl(120, 100%, 40%);">+ return SMBUS_ERROR;</span><br><span style="color: hsl(120, 100%, 40%);">+ *read_size = i;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/soc/intel/common/block/smbus/smbuslib.h b/src/soc/intel/common/block/smbus/smbuslib.h</span><br><span>index 05dafe9..1ec99fd 100644</span><br><span>--- a/src/soc/intel/common/block/smbus/smbuslib.h</span><br><span>+++ b/src/soc/intel/common/block/smbus/smbuslib.h</span><br><span>@@ -27,6 +27,9 @@</span><br><span> #define SMBHSTCMD 0x3</span><br><span> #define SMBXMITADD 0x4</span><br><span> #define SMBHSTDAT0 0x5</span><br><span style="color: hsl(120, 100%, 40%);">+#define SMBHSTDAT1 0x6</span><br><span style="color: hsl(120, 100%, 40%);">+#define SMBHSTHBD 0x7</span><br><span style="color: hsl(120, 100%, 40%);">+#define SMBHSTAUXC 0xD</span><br><span> </span><br><span> #define SMBUS_TIMEOUT 15 /* 15ms */</span><br><span> </span><br><span>@@ -36,5 +39,8 @@</span><br><span> unsigned int address, unsigned int data);</span><br><span> int smbus_read16(unsigned int smbus_base, unsigned int device,</span><br><span> unsigned int address);</span><br><span style="color: hsl(120, 100%, 40%);">+int smbus_read_block_data(unsigned int smbus_base, unsigned int device,</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int address, unsigned char *data,</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int max_size, unsigned int *read_size);</span><br><span> </span><br><span> #endif /* SOC_INTEL_COMMON_BLOCK_SMBUS__LIB_H */</span><br><span></span><br></pre><p>To view, visit <a href="https://review.coreboot.org/22967">change 22967</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://review.coreboot.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://review.coreboot.org/22967"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: coreboot </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: I14882b646e7c0fa96cf38a698562cc20bbd41095 </div>
<div style="display:none"> Gerrit-Change-Number: 22967 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Youness Alaoui <snifikino@gmail.com> </div>