tegra: i2c: Add a timeout to I2C bit clear recovery mechanism
Our tests with the I2C bit clear mechanism (recovering from "lost arbitration" errors) show that the bit clear hardware does not work correctly in some situations. When a wedged slave device tries to send more than one 0-to-1-to-0 transition to the host (e.g. leftover bits from an aborted read), the controller never transitions the BC_ENABLE bit back to zero. This patch adds a long timeout to the bit clear code that waits for register transitions as a safeguard. This way, We will still eventually exit the function (probably followed by a reboot). Our tests show that this will recover from all conditions after at most a few reboots. BRANCH=nyan BUG=chrome-os-partner:28323 TEST=Ran wedge_ack and wedge_read tests with software_i2c patch, system recovered as expected in all cases. Change-Id: I6c37119130e1240e1ef3a5944582abbcd2e39ff0 Signed-off-by: Julius Werner <jwerner@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/200265 Reviewed-by: Tom Warren <twarren@nvidia.com> Reviewed-by: Gabe Black <gabeblack@chromium.org>
This commit is contained in:
parent
8f71503dbb
commit
4c8d0af25c
1 changed files with 10 additions and 4 deletions
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include <arch/io.h>
|
||||
#include <console/console.h>
|
||||
#include <delay.h>
|
||||
#include <device/i2c.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
|
@ -30,6 +31,7 @@ static void do_bus_clear(int bus)
|
|||
struct tegra_i2c_bus_info *info = &tegra_i2c_info[bus];
|
||||
struct tegra_i2c_regs * const regs = info->base;
|
||||
uint32_t bc;
|
||||
int i, timeout_ms = 10;
|
||||
|
||||
// BUS CLEAR regs (from TRM):
|
||||
// 1. Reset the I2C controller (already done)
|
||||
|
|
@ -41,16 +43,20 @@ static void do_bus_clear(int bus)
|
|||
write32(bc, ®s->bus_clear_config);
|
||||
// 4.1 Set MSTR_CONFIG_LOAD and wait for clear
|
||||
write32(I2C_CONFIG_LOAD_MSTR_CONFIG_LOAD_ENABLE, ®s->config_load);
|
||||
do {
|
||||
for (i = 0; i < timeout_ms * 10 && (read32(®s->config_load) &
|
||||
I2C_CONFIG_LOAD_MSTR_CONFIG_LOAD_ENABLE); i++) {
|
||||
printk(BIOS_DEBUG, "%s: wait for MSTR_CONFIG_LOAD to clear\n",
|
||||
__func__);
|
||||
} while (read32(®s->config_load) & I2C_CONFIG_LOAD_MSTR_CONFIG_LOAD_ENABLE);
|
||||
udelay(100);
|
||||
}
|
||||
// 5. Set ENABLE to start the bus clear op
|
||||
write32(bc | I2C_BUS_CLEAR_CONFIG_BC_ENABLE, ®s->bus_clear_config);
|
||||
do {
|
||||
for (i = 0; i < timeout_ms * 10 && (read32(®s->bus_clear_config) &
|
||||
I2C_BUS_CLEAR_CONFIG_BC_ENABLE); i++) {
|
||||
printk(BIOS_DEBUG, "%s: wait for bus clear completion\n",
|
||||
__func__);
|
||||
} while (read32(®s->bus_clear_config) & I2C_BUS_CLEAR_CONFIG_BC_ENABLE);
|
||||
udelay(100);
|
||||
}
|
||||
}
|
||||
|
||||
static int tegra_i2c_send_recv(int bus, int read,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue