[coreboot-gerrit] Change in coreboot[master]: soc/amd/stoneyridge/gpio.c: Create I2C slave reset code
Richard Spiegel (Code Review)
gerrit at coreboot.org
Tue Sep 11 20:38:38 CEST 2018
Richard Spiegel has uploaded this change for review. ( https://review.coreboot.org/28574
Change subject: soc/amd/stoneyridge/gpio.c: Create I2C slave reset code
......................................................................
soc/amd/stoneyridge/gpio.c: Create I2C slave reset code
AMD soc does not wait for I2C transaction to complete before executing a
reset. Because of this, it's possible for the reset to happen in the middle
of a transaction, resulting on a slave hang. There are 2 possible solutions:
If the slave has a reset pin connected to a GPIO pin, it can be used to
reset the slave, else the only solution is to bang SCL 9 times. Create code
that makes it easy to implement either solution.
BUG=b:114479395
TEST=Build and boot grunt.
Change-Id: I7f74b7e45c509044825355874753969f074e2382
Signed-off-by: Richard Spiegel <richard.spiegel at silverbackltd.com>
---
M src/soc/amd/stoneyridge/gpio.c
M src/soc/amd/stoneyridge/include/soc/gpio.h
2 files changed, 108 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/74/28574/1
diff --git a/src/soc/amd/stoneyridge/gpio.c b/src/soc/amd/stoneyridge/gpio.c
index 88e7d3b..1da7ab4 100644
--- a/src/soc/amd/stoneyridge/gpio.c
+++ b/src/soc/amd/stoneyridge/gpio.c
@@ -22,6 +22,7 @@
#include <soc/southbridge.h>
#include <assert.h>
#include <compiler.h>
+#include <delay.h>
static const struct soc_amd_event gpio_event_table[] = {
{ GPIO_1, GEVENT_19 },
@@ -297,6 +298,85 @@
edge_level, mask);
}
+static const struct soc_amd_gpio gpo_i2c_2_gpo[] = {
+ PAD_GPO(GPIO_19, HIGH),
+ PAD_GPI(GPIO_20, PULL_UP),
+ PAD_GPO(GPIO_113, HIGH),
+ PAD_GPI(GPIO_114, PULL_UP),
+ PAD_GPO(GPIO_145, HIGH),
+ PAD_GPI(GPIO_146, PULL_UP),
+ PAD_GPO(GPIO_147, HIGH),
+ PAD_GPI(GPIO_148, PULL_UP),
+};
+
+static void save_i2c_pin_registers(uint8_t gpio,
+ struct soc_amd_i2c_save *save_table)
+{
+ uint32_t *gpio_ptr;
+ uint8_t *mux_ptr;
+
+ mux_ptr = (uint8_t *)(uintptr_t)(gpio + AMD_GPIO_MUX);
+ gpio_ptr = (uint32_t *)gpio_get_address(gpio);
+ save_table->mux_pointer = mux_ptr;
+ save_table->mux_value = read8(mux_ptr);
+ save_table->control_pointer = gpio_ptr;
+ save_table->control_value = read32(gpio_ptr);
+}
+
+void sb_reset_i2c_slaves(const struct soc_amd_force_toggle *pin_table,
+ size_t size)
+{
+ struct soc_amd_i2c_save save_table[8];
+ struct soc_and_pointer_count control_table[8];
+ uint32_t reg32, *reg_ptr;
+ uint8_t i, j, remain;
+
+ for (i = 0; i < 8; i++) {
+ save_i2c_pin_registers(gpo_i2c_2_gpo[i].gpio, &save_table[i]);
+ control_table[i].ptr = NULL;
+ }
+ sb_program_gpios(gpo_i2c_2_gpo, ARRAY_SIZE(gpo_i2c_2_gpo));
+
+ if (size > 8) {
+ printk(BIOS_WARNING, "Maximum reset size is 8 elements\n");
+ j = 8;
+ } else
+ j = size;
+ for (i = 0; i < j; i++) {
+ reg_ptr = (uint32_t *)gpio_get_address(pin_table[i].gpio);
+ control_table[i].ptr = reg_ptr;
+ control_table[i].count = pin_table[i].count;
+ }
+
+ remain = 1; /* at least 1 pin needs to be toggled */
+ while (remain) {
+ for (i = 0; i < j; i++) {
+ if (control_table[i].count) {
+ reg32 = read32(control_table[i].ptr);
+ reg32 ^= GPIO_OUTPUT_VALUE;
+ write32(control_table[i].ptr, reg32);
+ }
+ }
+ udelay(5);
+ remain = 0;
+ for (i = 0; i < j; i++) {
+ if (control_table[i].count) {
+ reg32 = read32(control_table[i].ptr);
+ reg32 ^= GPIO_OUTPUT_VALUE;
+ write32(control_table[i].ptr, reg32);
+ control_table[i].count--;
+ }
+ remain += control_table[i].count;
+ }
+ udelay(5);
+ }
+
+ for (i = 0; i < 8; i++) {
+ write8(save_table->mux_pointer, save_table->mux_value);
+ write32(save_table->control_pointer, save_table->control_value);
+ }
+}
+
int gpio_interrupt_status(gpio_t gpio)
{
uintptr_t gpio_address = gpio_get_address(gpio);
diff --git a/src/soc/amd/stoneyridge/include/soc/gpio.h b/src/soc/amd/stoneyridge/include/soc/gpio.h
index 6e72293..d4383f8 100644
--- a/src/soc/amd/stoneyridge/include/soc/gpio.h
+++ b/src/soc/amd/stoneyridge/include/soc/gpio.h
@@ -36,6 +36,23 @@
uint8_t event;
};
+struct soc_amd_i2c_save {
+ uint32_t *control_pointer;
+ uint32_t control_value;
+ uint8_t *mux_pointer;
+ uint8_t mux_value;
+};
+
+struct soc_and_pointer_count {
+ uint32_t *ptr;
+ uint8_t count;
+};
+
+struct soc_amd_force_toggle {
+ uint8_t gpio;
+ uint8_t count;
+};
+
#define GPIO_TOTAL_PINS 149
#define GPIO_PIN_IN (1 << 0) /* for byte access */
#define GPIO_PIN_OUT (1 << 6) /* for byte access */
@@ -558,6 +575,15 @@
.control = (GPIO_IN ## _ ## type | GPIO_IN ## _ ## time), \
.flags = GPIO_FLAG_DEBOUNCE }
+/* Use these to define GPIO to be toggled, to solve I2C reset issues */
+#define PAD_RESET_I2C_SLAVE(pin) \
+ { .gpio = (pin), \
+ .count = 9 }
+
+#define PAD_RESET_DEVICE(pin) \
+ { .gpio = (pin), \
+ .count = 1 }
+
typedef uint32_t gpio_t;
/* Get the address of the control register of a particular pin */
uintptr_t gpio_get_address(gpio_t gpio_num);
@@ -571,6 +597,8 @@
* @return none
*/
void sb_program_gpios(const struct soc_amd_gpio *gpio_list_ptr, size_t size);
+void sb_reset_i2c_slaves(const struct soc_amd_force_toggle *pin_table,
+ size_t size);
/* Return the interrupt status and clear if set. */
int gpio_interrupt_status(gpio_t gpio);
--
To view, visit https://review.coreboot.org/28574
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: I7f74b7e45c509044825355874753969f074e2382
Gerrit-Change-Number: 28574
Gerrit-PatchSet: 1
Gerrit-Owner: Richard Spiegel <richard.spiegel at silverbackltd.com>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.coreboot.org/pipermail/coreboot-gerrit/attachments/20180911/6cdc15f4/attachment-0001.html>
More information about the coreboot-gerrit
mailing list