<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>