summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2012-11-26 16:43:57 -0800
committerRandall Spangler <rspangler@chromium.org>2012-11-28 11:00:00 -0800
commit9444f1edb88d2ed3e9d185f14e32401c6eebc5dd (patch)
treecac9b02b4aec089edcf801e1fd486db9d30048aa
parent4e930ad1c16d43977103aa533eef74ea3dfae6b2 (diff)
downloadchrome-ec-9444f1edb88d2ed3e9d185f14e32401c6eebc5dd.tar.gz
Handle arbitration lost on I2C ports
This seems to happen when the I2C signals come up so that the EC sees a start condition from the remote end. In this case, the EC refuses to talk on the I2C port until the EC's I2C state machine is reset. Also, don't fail on bus-busy, since that's true during a multi-part transaction such as an I2C string read. BUG=chrome-os-partner:16262 BRANCH=link TEST=boot system; 'battery' and 'temps' should give good info Then run snanda's suspend_stress_test for a while and repeat. Or a better test is to open 2 crosh shells, sudo bash in each, and 1) while true; do ectool temps all; sleep 0.5; done 2) suspend_stress_test Then watch the EC console for "I2C5 bad status" errors. These happen rarely, only on some systems. With this fix, they'll be reported when they occur, but should not cause errors to be reported by 'ectool temps all', since the I2C module will clear the arbitration-lost status before retrying. Original-Change-Id: Idfaf9cd7e8ef2abcc0130332890329dd5d2ca052 Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/38686 Reviewed-by: Yung-Chieh Lo <yjlou@chromium.org> (cherry picked from commit d619cdd58f473efe7b8c67e817080fc16751b4a5) Change-Id: I44d339e4d9f6ad1763895caca11a350818fe4e02 Reviewed-on: https://gerrit.chromium.org/gerrit/38825 Reviewed-by: Randall Spangler <rspangler@chromium.org> Tested-by: Randall Spangler <rspangler@chromium.org>
-rw-r--r--chip/lm4/i2c.c30
-rw-r--r--chip/lm4/registers.h1
2 files changed, 22 insertions, 9 deletions
diff --git a/chip/lm4/i2c.c b/chip/lm4/i2c.c
index 7ca195f587..a789478e4b 100644
--- a/chip/lm4/i2c.c
+++ b/chip/lm4/i2c.c
@@ -85,7 +85,7 @@ static int wait_idle(int port)
task_set_event(task_get_current(), event, 0);
/* Check for errors */
- if (i & LM4_I2C_MCS_ERROR)
+ if (i & (LM4_I2C_MCS_CLKTO | LM4_I2C_MCS_ARBLST | LM4_I2C_MCS_ERROR))
return EC_ERROR_UNKNOWN;
return EC_SUCCESS;
@@ -108,15 +108,27 @@ static int i2c_transmit_receive(int port, int slave_addr,
if (transmit_size == 0 && receive_size == 0)
return EC_SUCCESS;
- if (!started && (LM4_I2C_MCS(port) &
- (LM4_I2C_MCS_CLKTO | LM4_I2C_MCS_BUSBSY))) {
+ reg_mcs = LM4_I2C_MCS(port);
+ if (!started && (reg_mcs & (LM4_I2C_MCS_CLKTO | LM4_I2C_MCS_ARBLST))) {
+ uint32_t tpr = LM4_I2C_MTPR(port);
+
+ CPRINTF("[%T I2C%d bad status 0x%02x]\n", port, reg_mcs);
+
+ /* Clock timeout or arbitration lost. Reset port to clear. */
+ LM4_SYSTEM_SRI2C |= (1 << port);
+ clock_wait_cycles(3);
+ LM4_SYSTEM_SRI2C &= ~(1 << port);
+ clock_wait_cycles(3);
+
+ /* Restore settings */
+ LM4_I2C_MCR(port) = 0x10;
+ LM4_I2C_MTPR(port) = tpr;
+
/*
- * Previous clock timeout or bus-busy. Bounce the master to
- * clear these error states.
+ * We don't know what edges the slave saw, so sleep long enough
+ * that the slave will see the new start condition below.
*/
- LM4_I2C_MCR(port) = 0;
- usleep(100000);
- LM4_I2C_MCR(port) = 0x10;
+ usleep(1000);
}
if (transmit_data) {
@@ -184,7 +196,7 @@ static int i2c_transmit_receive(int port, int slave_addr,
}
/* Check for error conditions */
- if (LM4_I2C_MCS(port) & (LM4_I2C_MCS_CLKTO | LM4_I2C_MCS_BUSBSY |
+ if (LM4_I2C_MCS(port) & (LM4_I2C_MCS_CLKTO | LM4_I2C_MCS_ARBLST |
LM4_I2C_MCS_ERROR))
return EC_ERROR_UNKNOWN;
diff --git a/chip/lm4/registers.h b/chip/lm4/registers.h
index f351bb2814..1818c73a1d 100644
--- a/chip/lm4/registers.h
+++ b/chip/lm4/registers.h
@@ -254,6 +254,7 @@ static inline int lm4_fan_addr(int ch, int offset)
/* Note: USER_REG3 is used to hold pre-programming process data and should not
* be modified by EC code. See crosbug.com/p/8889. */
#define LM4_SYSTEM_USER_REG3 LM4REG(0x400fe1ec)
+#define LM4_SYSTEM_SRI2C LM4REG(0x400fe520)
#define LM4_SYSTEM_SREEPROM LM4REG(0x400fe558)
#define LM4_SYSTEM_RCGCWD LM4REG(0x400fe600)
#define LM4_SYSTEM_RCGCTIMER LM4REG(0x400fe604)