diff options
-rw-r--r-- | common/i2c_bitbang.c | 13 | ||||
-rw-r--r-- | common/i2c_controller.c | 19 | ||||
-rw-r--r-- | common/main.c | 18 | ||||
-rw-r--r-- | include/i2c_bitbang.h | 8 |
4 files changed, 54 insertions, 4 deletions
diff --git a/common/i2c_bitbang.c b/common/i2c_bitbang.c index 86d76a8b47..9e961d730e 100644 --- a/common/i2c_bitbang.c +++ b/common/i2c_bitbang.c @@ -11,6 +11,7 @@ #include "util.h" #define CPUTS(str) cputs(CC_I2C, str) +#define CPRINTS(format, args...) cprints(CC_I2C, format, ## args) static int started; @@ -336,6 +337,18 @@ exit: return err; } +void enable_i2c_raw_mode(bool enable) +{ + int i; + + for (i = 0; i < i2c_bitbang_ports_used; i++) { + if (i2c_raw_mode(i2c_bitbang_ports[i].port, enable)) + CPRINTS("I2C p%d: Failed to %s raw mode", + i2c_bitbang_ports[i].port, + enable ? "enable" : "disable"); + } +} + const struct i2c_drv bitbang_drv = { .xfer = &i2c_bitbang_xfer }; diff --git a/common/i2c_controller.c b/common/i2c_controller.c index f2d1cf4a5f..92234bc600 100644 --- a/common/i2c_controller.c +++ b/common/i2c_controller.c @@ -100,13 +100,23 @@ const struct i2c_port_t *get_i2c_port(const int port) { int i; - /* Find the matching port in i2c_ports[] table. */ - for (i = 0; i < i2c_ports_used; i++) { - if (i2c_ports[i].port == port) - return &i2c_ports[i]; + /* + * If the EC's I2C driver implementation is task event based and the + * I2C is accessed before the task is initialized, it causes the system + * panic hence these I2C will fall back to bitbang mode if enabled at + * board level and will again switch back to event based I2C upon task + * initialization. + */ + if (task_start_called()) { + /* Find the matching port in i2c_ports[] table. */ + for (i = 0; i < i2c_ports_used; i++) { + if (i2c_ports[i].port == port) + return &i2c_ports[i]; + } } if (IS_ENABLED(CONFIG_I2C_BITBANG)) { + /* Find the matching port in i2c_bitbang_ports[] table. */ for (i = 0; i < i2c_bitbang_ports_used; i++) { if (i2c_bitbang_ports[i].port == port) return &i2c_bitbang_ports[i]; @@ -137,6 +147,7 @@ __maybe_unused static int chip_i2c_xfer_with_notify( * remove the flag so it won't confuse chip driver. */ no_pec_af &= ~I2C_FLAG_PEC; + if (i2c_port->drv) ret = i2c_port->drv->xfer(i2c_port, no_pec_af, out, out_size, in, in_size, flags); diff --git a/common/main.c b/common/main.c index d9fbe94a1e..0e18580373 100644 --- a/common/main.c +++ b/common/main.c @@ -19,6 +19,7 @@ #include "gpio.h" #include "hooks.h" #include "i2c.h" +#include "i2c_bitbang.h" #include "keyboard_scan.h" #include "link_defs.h" #include "lpc.h" @@ -193,7 +194,15 @@ test_mockable __keep int main(void) * pretty early, so let's initialize the controller now. */ i2c_init(); + + /* + * Enable I2C raw mode for the ports which need pre-task i2c + * transactions. + */ + if (IS_ENABLED(CONFIG_I2C_BITBANG)) + enable_i2c_raw_mode(true); } + #ifdef HAS_TASK_KEYSCAN keyboard_scan_init(); #endif @@ -247,6 +256,15 @@ test_mockable __keep int main(void) #endif /* !CONFIG_VBOOT_EFS && CONFIG_RWSIG && !HAS_TASK_RWSIG */ /* + * Disable I2C raw mode for the ports which needed pre-task i2c + * transactions as the task is about to start and the I2C can resume + * to event based transactions. + */ + if (IS_ENABLED(CONFIG_I2C_BITBANG) && + IS_ENABLED(CONFIG_I2C_CONTROLLER)) + enable_i2c_raw_mode(false); + + /* * Print the init time. Not completely accurate because it can't take * into account the time before timer_init(), but it'll at least catch * the majority of the time. diff --git a/include/i2c_bitbang.h b/include/i2c_bitbang.h index f3c07baf76..d550f1a582 100644 --- a/include/i2c_bitbang.h +++ b/include/i2c_bitbang.h @@ -12,6 +12,14 @@ extern const struct i2c_drv bitbang_drv; extern const struct i2c_port_t i2c_bitbang_ports[]; extern const unsigned int i2c_bitbang_ports_used; +/** + * Enable I2C raw mode for the ports which need pre-task + * I2C transactions in bitbang mode. + * + * @param enable Enable/disable the I2C raw mode + */ +void enable_i2c_raw_mode(bool enable); + /* expose static functions for testing */ #ifdef TEST_BUILD int bitbang_start_cond(const struct i2c_port_t *i2c_port); |