summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDino Li <Dino.Li@ite.com.tw>2021-07-07 15:55:04 +0800
committerCommit Bot <commit-bot@chromium.org>2021-07-22 19:54:04 +0000
commit154f661f50d08adc3a546360be020a7e0321fe2e (patch)
tree0a85a77f8aa5215595a91cf9c5d3c39972387c27
parent506a1ee872aad4ef21d7c90717f1917963dec6b1 (diff)
downloadchrome-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.c20
-rw-r--r--include/i2c.h14
-rw-r--r--zephyr/boards/riscv/asurada/asurada.dts12
-rw-r--r--zephyr/dts/bindings/i2c/cros-ec-i2c-port-base.yaml8
-rw-r--r--zephyr/shim/src/i2c.c17
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;
+}