diff options
author | Dino Li <Dino.Li@ite.com.tw> | 2021-07-07 15:55:04 +0800 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2021-07-22 19:54:04 +0000 |
commit | 154f661f50d08adc3a546360be020a7e0321fe2e (patch) | |
tree | 0a85a77f8aa5215595a91cf9c5d3c39972387c27 | |
parent | 506a1ee872aad4ef21d7c90717f1917963dec6b1 (diff) | |
download | chrome-ec-154f661f50d08adc3a546360be020a7e0321fe2e.tar.gz |
zephyr: i2c: protect physical port
If i2c devices are connected to the same port, they should
use the same mutex_lock() index. So the new transaction won't
break the ongoing transaction.
BRANCH=none
BUG=b:189855648
TEST=Enable CONFIG_SMBUS_PEC and voltage regulator function on asurada.
No i2c transaction is broken.
Change-Id: Ib848e3c2e60b99ce66ad5fd2fc7095f90820a15d
Signed-off-by: Dino Li <Dino.Li@ite.com.tw>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3010920
Reviewed-by: Jack Rosenthal <jrosenth@chromium.org>
Reviewed-by: Denis Brockus <dbrockus@chromium.org>
Commit-Queue: Denis Brockus <dbrockus@chromium.org>
-rw-r--r-- | common/i2c_controller.c | 20 | ||||
-rw-r--r-- | include/i2c.h | 14 | ||||
-rw-r--r-- | zephyr/boards/riscv/asurada/asurada.dts | 12 | ||||
-rw-r--r-- | zephyr/dts/bindings/i2c/cros-ec-i2c-port-base.yaml | 8 | ||||
-rw-r--r-- | zephyr/shim/src/i2c.c | 17 |
5 files changed, 71 insertions, 0 deletions
diff --git a/common/i2c_controller.c b/common/i2c_controller.c index 10ea4081cd..0596ddc422 100644 --- a/common/i2c_controller.c +++ b/common/i2c_controller.c @@ -83,6 +83,16 @@ static int i2c_port_is_locked(int port) if (port < 0) return 0; + if (IS_ENABLED(CONFIG_ZEPHYR)) { + /* + * For Zephyr: to convert an i2c port enum value to a port + * number in mutex_lock(), this number should be soc's i2c port + * where the i2 device is connected to. + */ + if (i2c_get_physical_port(port) >= 0) + port = i2c_get_physical_port(port); + } + return (i2c_port_active_list >> port) & 1; } @@ -287,6 +297,16 @@ void i2c_lock(int port, int lock) if (port < 0 || port >= ARRAY_SIZE(port_mutex)) return; + if (IS_ENABLED(CONFIG_ZEPHYR)) { + /* + * For Zephyr: to convert an i2c port enum value to a port + * number in mutex_lock(), this number should be soc's i2c port + * where the i2 device is connected to. + */ + if (i2c_get_physical_port(port) >= 0) + port = i2c_get_physical_port(port); + } + if (lock) { uint32_t irq_lock_key; diff --git a/include/i2c.h b/include/i2c.h index 231561caea..4d49ec96e8 100644 --- a/include/i2c.h +++ b/include/i2c.h @@ -590,4 +590,18 @@ enum i2c_freq i2c_get_freq(int port); /* Find the matching port in i2c_ports[] table. */ const struct i2c_port_t *get_i2c_port(const int port); +/** + * @brief Get soc's i2c port number where i2c device is connected to. + * + * This function translate a i2c port enum value (enum-name property listed in + * named-i2c-ports) to soc's i2c port. Devices which are connected to the + * same port of soc should have the same number. + * + * @param enum_port i2c port enum value. + * @return i2c port of soc used in mutex_lock(). + * -1 if physical port is not defined or i2c port number is out of + * port_mutex space. + */ +int i2c_get_physical_port(int enum_port); + #endif /* __CROS_EC_I2C_H */ diff --git a/zephyr/boards/riscv/asurada/asurada.dts b/zephyr/boards/riscv/asurada/asurada.dts index f5c4cc3cfe..e759080996 100644 --- a/zephyr/boards/riscv/asurada/asurada.dts +++ b/zephyr/boards/riscv/asurada/asurada.dts @@ -72,62 +72,74 @@ i2c-port = <&i2c0>; enum-name = "I2C_PORT_POWER"; label = "POWER"; + physical-port = <0>; }; battery { i2c-port = <&i2c0>; remote-port = <0>; enum-name = "I2C_PORT_BATTERY"; label = "BATTERY"; + physical-port = <0>; }; eeprom { i2c-port = <&i2c0>; enum-name = "I2C_PORT_EEPROM"; label = "EEPROM"; + physical-port = <0>; }; charger { i2c-port = <&i2c0>; enum-name = "I2C_PORT_CHARGER"; label = "CHARGER"; + physical-port = <0>; }; i2c_sensor: sensor { i2c-port = <&i2c1>; enum-name = "I2C_PORT_SENSOR"; label = "SENSOR"; + physical-port = <1>; }; i2c-accel { i2c-port = <&i2c1>; enum-name = "I2C_PORT_ACCEL"; label = "ACCEL"; + physical-port = <1>; }; ppc0 { i2c-port = <&i2c2>; enum-name = "I2C_PORT_PPC0"; label = "PPC0"; + physical-port = <2>; }; ppc1 { i2c-port = <&i2c4>; enum-name = "I2C_PORT_PPC1"; label = "PPC1"; + physical-port = <4>; }; usb-c0 { i2c-port = <&i2c2>; enum-name = "I2C_PORT_USB_C0"; label = "USB_C0"; + physical-port = <2>; }; usb-c1 { i2c-port = <&i2c4>; enum-name = "I2C_PORT_USB_C1"; label = "USB_C1"; + physical-port = <4>; }; usb-mux0 { i2c-port = <&i2c2>; enum-name = "I2C_PORT_USB_MUX0"; label = "USB_MUX0"; + physical-port = <2>; }; usb-mux1 { i2c-port = <&i2c4>; enum-name = "I2C_PORT_USB_MUX1"; label = "USB_MUX1"; + physical-port = <4>; }; }; diff --git a/zephyr/dts/bindings/i2c/cros-ec-i2c-port-base.yaml b/zephyr/dts/bindings/i2c/cros-ec-i2c-port-base.yaml index 3838ca6fc9..a7d5232599 100644 --- a/zephyr/dts/bindings/i2c/cros-ec-i2c-port-base.yaml +++ b/zephyr/dts/bindings/i2c/cros-ec-i2c-port-base.yaml @@ -51,3 +51,11 @@ properties: description: Human readable string describing the device (used as device_get_binding() argument). + physical-port: + type: int + # TODO: Change the field to true once all boards' named-i2c-ports support + # this property. + required: false + description: + In the named-i2c-ports, it's a number indicated an i2c device + (eg. battery, charger, etc.) connected to which soc's i2c port. diff --git a/zephyr/shim/src/i2c.c b/zephyr/shim/src/i2c.c index cc4af85021..ae82db1a0a 100644 --- a/zephyr/shim/src/i2c.c +++ b/zephyr/shim/src/i2c.c @@ -18,6 +18,9 @@ #define INIT_REMOTE_PORTS(id) \ i2c_remote_ports[I2C_PORT(id)] = DT_PROP_OR(id, remote_port, -1); +#define INIT_PHYSICAL_PORTS(id) \ + i2c_physical_ports[I2C_PORT(id)] = DT_PROP_OR(id, physical_port, -1); + #define I2C_CONFIG_GPIO(id, type) \ DT_ENUM_UPPER_TOKEN(DT_CHILD(DT_CHILD(id, config), type), enum_name) @@ -41,6 +44,7 @@ const struct i2c_port_t i2c_ports[] = { }; const unsigned int i2c_ports_used = ARRAY_SIZE(i2c_ports); static int i2c_remote_ports[I2C_PORT_COUNT]; +static int i2c_physical_ports[I2C_PORT_COUNT]; int i2c_get_line_levels(int port) { @@ -54,6 +58,7 @@ static int init_device_bindings(const struct device *device) ARG_UNUSED(device); DT_FOREACH_CHILD(DT_PATH(named_i2c_ports), INIT_DEV_BINDING) DT_FOREACH_CHILD(DT_PATH(named_i2c_ports), INIT_REMOTE_PORTS) + DT_FOREACH_CHILD(DT_PATH(named_i2c_ports), INIT_PHYSICAL_PORTS) return 0; } SYS_INIT(init_device_bindings, POST_KERNEL, 51); @@ -75,3 +80,15 @@ int i2c_get_port_from_remote_port(int remote_port) /* Remote port is not defined, return -1 to signal the problem */ return -1; } + +int i2c_get_physical_port(int enum_port) +{ + int i2c_port = i2c_physical_ports[enum_port]; + + /* + * Return -1 for caller if physical port is not defined or the + * port number is out of port_mutex space. + * Please ensure the caller won't change anything if -1 received. + */ + return (i2c_port < I2C_PORT_COUNT) ? i2c_port : -1; +} |