<p>Richard Spiegel has uploaded this change for <strong>review</strong>.</p><p><a href="https://review.coreboot.org/28571">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">soc/amd/stoneyridge/gpio.c: Create I2C slave reset code<br><br>AMD soc does not wait for I2C transaction to complete before executing a<br>reset. Because of this, it's possible for the reset to happen in the middle<br>of a transaction, resulting on a slave hang. There are 2 possible solutions:<br>If the slave has a reset pin connected to a GPIO pin, it can be used to<br>reset the slave, else the only solution is to bang SCL 9 times. Create code<br>that makes it easy to implement either solution.<br><br>BUG=b:114479395<br>TEST=Build and boot grunt.<br><br>Change-Id: I825b6380fb658c3ea5fc669117ae04d2dc181819<br>Signed-off-by: Richard Spiegel <richard.spiegel@silverbackltd.com><br>---<br>M src/soc/amd/stoneyridge/gpio.c<br>M src/soc/amd/stoneyridge/include/soc/gpio.h<br>2 files changed, 108 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://review.coreboot.org:29418/coreboot refs/changes/71/28571/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/src/soc/amd/stoneyridge/gpio.c b/src/soc/amd/stoneyridge/gpio.c</span><br><span>index 88e7d3b..d846315 100644</span><br><span>--- a/src/soc/amd/stoneyridge/gpio.c</span><br><span>+++ b/src/soc/amd/stoneyridge/gpio.c</span><br><span>@@ -22,6 +22,7 @@</span><br><span> #include <soc/southbridge.h></span><br><span> #include <assert.h></span><br><span> #include <compiler.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <delay.h></span><br><span> </span><br><span> static const struct soc_amd_event gpio_event_table[] = {</span><br><span> { GPIO_1, GEVENT_19 },</span><br><span>@@ -297,6 +298,85 @@</span><br><span> edge_level, mask);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static const struct soc_amd_gpio gpo_i2c_2_gpo[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ PAD_GPO(GPIO_19, HIGH),</span><br><span style="color: hsl(120, 100%, 40%);">+ PAD_GPI(GPIO_20, PULL_UP),</span><br><span style="color: hsl(120, 100%, 40%);">+ PAD_GPO(GPIO_113, HIGH),</span><br><span style="color: hsl(120, 100%, 40%);">+ PAD_GPI(GPIO_114, PULL_UP),</span><br><span style="color: hsl(120, 100%, 40%);">+ PAD_GPO(GPIO_145, HIGH),</span><br><span style="color: hsl(120, 100%, 40%);">+ PAD_GPI(GPIO_146, PULL_UP),</span><br><span style="color: hsl(120, 100%, 40%);">+ PAD_GPO(GPIO_147, HIGH),</span><br><span style="color: hsl(120, 100%, 40%);">+ PAD_GPI(GPIO_148, PULL_UP),</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%);">+static void save_i2c_pin_registers(uint8_t gpio,</span><br><span style="color: hsl(120, 100%, 40%);">+ struct soc_amd_i2c_save *save_table)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t *gpio_ptr;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t *mux_ptr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ mux_ptr = (uint8_t *)(uintptr_t)(gpio + AMD_GPIO_MUX);</span><br><span style="color: hsl(120, 100%, 40%);">+ gpio_ptr = (uint32_t *)gpio_get_address(gpio);</span><br><span style="color: hsl(120, 100%, 40%);">+ save_table->mux_pointer = mux_ptr;</span><br><span style="color: hsl(120, 100%, 40%);">+ save_table->mux_value = read8(mux_ptr);</span><br><span style="color: hsl(120, 100%, 40%);">+ save_table->control_pointer = gpio_ptr;</span><br><span style="color: hsl(120, 100%, 40%);">+ save_table->control_value = read32(gpio_ptr);</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%);">+void sb_reset_i2c_slaves(const struct soc_amd_force_toggle *pin_table,</span><br><span style="color: hsl(120, 100%, 40%);">+ size_t size)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct soc_amd_i2c_save save_table[8];</span><br><span style="color: hsl(120, 100%, 40%);">+ struct soc_and_pointer_count control_table[8];</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t reg32, *reg_ptr;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t i, j, remain;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < 8; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+ save_i2c_pin_registers(gpo_i2c_2_gpo[i].gpio, &save_table[i]);</span><br><span style="color: hsl(120, 100%, 40%);">+ control_table[i].ptr = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ sb_program_gpios(gpo_i2c_2_gpo, ARRAY_SIZE(gpo_i2c_2_gpo));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (size > 8) {</span><br><span style="color: hsl(120, 100%, 40%);">+ printk(BIOS_WARNING, "Maximum reset size is 8 elements\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ j = 8;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else</span><br><span style="color: hsl(120, 100%, 40%);">+ j = size;</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < j; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+ reg_ptr = (uint32_t *)gpio_get_address(pin_table[i].gpio);</span><br><span style="color: hsl(120, 100%, 40%);">+ control_table[i].ptr = reg_ptr;</span><br><span style="color: hsl(120, 100%, 40%);">+ control_table[i].count = pin_table[i].count;</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%);">+ remain = 1; /* at least 1 pin needs to be toggled */</span><br><span style="color: hsl(120, 100%, 40%);">+ while(remain) {</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < j; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (control_table[i].count) {</span><br><span style="color: hsl(120, 100%, 40%);">+ reg32 = read32(control_table[i].ptr);</span><br><span style="color: hsl(120, 100%, 40%);">+ reg32 ^= GPIO_OUTPUT_VALUE;</span><br><span style="color: hsl(120, 100%, 40%);">+ write32(control_table[i].ptr, reg32);</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%);">+ udelay(5);</span><br><span style="color: hsl(120, 100%, 40%);">+ remain = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < j; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (control_table[i].count) {</span><br><span style="color: hsl(120, 100%, 40%);">+ reg32 = read32(control_table[i].ptr);</span><br><span style="color: hsl(120, 100%, 40%);">+ reg32 ^= GPIO_OUTPUT_VALUE;</span><br><span style="color: hsl(120, 100%, 40%);">+ write32(control_table[i].ptr, reg32);</span><br><span style="color: hsl(120, 100%, 40%);">+ control_table[i].count--;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ remain += control_table[i].count;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ udelay(5);</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%);">+ for (i = 0; i < 8; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+ write8(save_table->mux_pointer, save_table->mux_value);</span><br><span style="color: hsl(120, 100%, 40%);">+ write32(save_table->control_pointer, save_table->control_value);</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%);">+</span><br><span> int gpio_interrupt_status(gpio_t gpio)</span><br><span> {</span><br><span> uintptr_t gpio_address = gpio_get_address(gpio);</span><br><span>diff --git a/src/soc/amd/stoneyridge/include/soc/gpio.h b/src/soc/amd/stoneyridge/include/soc/gpio.h</span><br><span>index 6e72293..e49db6f 100644</span><br><span>--- a/src/soc/amd/stoneyridge/include/soc/gpio.h</span><br><span>+++ b/src/soc/amd/stoneyridge/include/soc/gpio.h</span><br><span>@@ -36,6 +36,23 @@</span><br><span> uint8_t event;</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct soc_amd_i2c_save{</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t *control_pointer;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t control_value;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t *mux_pointer;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t mux_value;</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%);">+struct soc_and_pointer_count {</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t *ptr;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t count;</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%);">+struct soc_amd_force_toggle {</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t gpio;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t count;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #define GPIO_TOTAL_PINS 149</span><br><span> #define GPIO_PIN_IN (1 << 0) /* for byte access */</span><br><span> #define GPIO_PIN_OUT (1 << 6) /* for byte access */</span><br><span>@@ -558,6 +575,15 @@</span><br><span> .control = (GPIO_IN ## _ ## type | GPIO_IN ## _ ## time), \</span><br><span> .flags = GPIO_FLAG_DEBOUNCE }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* Use these to define GPIO to be toggled, to solve I2C reset issues */</span><br><span style="color: hsl(120, 100%, 40%);">+#define PAD_RESET_I2C_SLAVE(pin) \</span><br><span style="color: hsl(120, 100%, 40%);">+ { .gpio = (pin), \</span><br><span style="color: hsl(120, 100%, 40%);">+ .count = 9 }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define PAD_RESET_DEVICE(pin) \</span><br><span style="color: hsl(120, 100%, 40%);">+ { .gpio = (pin), \</span><br><span style="color: hsl(120, 100%, 40%);">+ .count = 1 }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> typedef uint32_t gpio_t;</span><br><span> /* Get the address of the control register of a particular pin */</span><br><span> uintptr_t gpio_get_address(gpio_t gpio_num);</span><br><span>@@ -571,6 +597,8 @@</span><br><span> * @return none</span><br><span> */</span><br><span> void sb_program_gpios(const struct soc_amd_gpio *gpio_list_ptr, size_t size);</span><br><span style="color: hsl(120, 100%, 40%);">+void sb_reset_i2c_slaves(const struct soc_amd_force_toggle *pin_table,</span><br><span style="color: hsl(120, 100%, 40%);">+ size_t size);</span><br><span> </span><br><span> /* Return the interrupt status and clear if set. */</span><br><span> int gpio_interrupt_status(gpio_t gpio);</span><br><span></span><br></pre><p>To view, visit <a href="https://review.coreboot.org/28571">change 28571</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/28571"/><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: I825b6380fb658c3ea5fc669117ae04d2dc181819 </div>
<div style="display:none"> Gerrit-Change-Number: 28571 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Richard Spiegel <richard.spiegel@silverbackltd.com> </div>