diff options
author | Vadim Bendebury <vbendeb@chromium.org> | 2017-06-29 17:59:44 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2017-08-17 20:41:57 -0700 |
commit | 430d55879dc0ce9567b4ee2eefed200e604091ee (patch) | |
tree | 5b87eb9e7c63db7c8fbe51d712cabe5441dc739c /common/i2cs_tpm.c | |
parent | a0c2fa80cd5e3c8dec89189d5c40075d6d210259 (diff) | |
download | chrome-ec-430d55879dc0ce9567b4ee2eefed200e604091ee.tar.gz |
g: add 'recover hosed slave' i2cs capability
A common failure condition on the i2c bus is when the master
unexpectedly stops clocking the bus while the slave is driving the SDA
line low. In this case the master is not able to issue Stop or Start
sequences, which makes the bus unusable.
Good slave controllers are able to detect this condition and recover
from it by removing the pull down from the SDA line. This patch adds
this capability to the g chip i2c slave controller.
A new timer function is created which samples the SDA line twice a
second. If it detects that SDA is low in two consecutive invocations
and the number of i2cs read interrupts has not advanced, it decides
that the "hosed slave" condition is happening and reinitializes the
i2c driver, which removes the hold from the SDA line.
Even though the state of the SDA line is supposed to be accessible
through the I2CS_READVAL register, it in fact is not, reads always
return zero in the SDA bit. To work around this a GPIO (port 0, bit
14) is being allocated to allow to monitor the state of the line, it
is multiplexed to the same pin the SDA line uses.
When the AP is in low power modes the SDA line is held low, this state
should not trigger i2c reinitializations.
CQ-DEPEND=CL:616300
BRANCH=none
BUG=b:35648537
TEST=connected H1 on the test board to an I2c master capable of
stopping clocking mid byte. Observed that the existing code would
just sit in the "hosed" state indefinitely. The code with the fix
recovers from the condition (drives the SDA line high) 500ms to
1s after the failure condition is created.
Change-Id: Iafc7433bbae9e49975a72ef032a923274f8aab3b
Signed-off-by: Vadim Bendebury <vbendeb@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/614391
Reviewed-by: Aseda Aboagye <aaboagye@chromium.org>
Diffstat (limited to 'common/i2cs_tpm.c')
-rw-r--r-- | common/i2cs_tpm.c | 8 |
1 files changed, 8 insertions, 0 deletions
diff --git a/common/i2cs_tpm.c b/common/i2cs_tpm.c index e649be1675..42089681dd 100644 --- a/common/i2cs_tpm.c +++ b/common/i2cs_tpm.c @@ -229,14 +229,22 @@ DECLARE_HOOK(HOOK_INIT, i2cs_if_register, HOOK_PRIO_LAST); static int command_i2cs(int argc, char **argv) { + static uint16_t base_read_recovery_count; + struct i2cs_status status; + + i2cs_get_status(&status); + ccprintf("rd fifo adjust cnt = %d\n", i2cs_fifo_adjust_count); ccprintf("wr mismatch cnt = %d\n", i2cs_write_error_count); + ccprintf("read recovered cnt = %d\n", status.read_recovery_count + - base_read_recovery_count); if (argc < 2) return EC_SUCCESS; if (!strcasecmp(argv[1], "reset")) { i2cs_fifo_adjust_count = 0; i2cs_write_error_count = 0; + base_read_recovery_count = status.read_recovery_count; ccprintf("i2cs error counts reset\n"); } else return EC_ERROR_PARAM1; |