summaryrefslogtreecommitdiff
path: root/zephyr
diff options
context:
space:
mode:
authorRobert Zieba <robertzieba@google.com>2023-03-06 23:12:25 +0000
committerChromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com>2023-03-16 21:14:23 +0000
commitc92120e39891f34ab485adc99ecf51e15940e13e (patch)
treecc60a59a2824ef1c6042d50bc93df0aac81294fa /zephyr
parentab4c6d2c3ad1ce62f85755bf87c7380c09733102 (diff)
downloadchrome-ec-c92120e39891f34ab485adc99ecf51e15940e13e.tar.gz
zephyr/emul: Add PS8811 emulator
Add emulator for the PS8811 retimer and associated tests. BRANCH=none BUG=b:247151116 TEST=Ran tests Change-Id: I65153b9c7cd2b597c1ebcc0371a96d34740c8a81 Signed-off-by: Robert Zieba <robertzieba@google.com> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/4313466 Reviewed-by: Diana Z <dzigterman@chromium.org>
Diffstat (limited to 'zephyr')
-rw-r--r--zephyr/Kconfig.retimer17
-rw-r--r--zephyr/Kconfig.usbc7
-rw-r--r--zephyr/dts/bindings/emul/cros,ps8811-emul.yaml9
-rw-r--r--zephyr/emul/CMakeLists.txt1
-rw-r--r--zephyr/emul/Kconfig1
-rw-r--r--zephyr/emul/retimer/CMakeLists.txt5
-rw-r--r--zephyr/emul/retimer/Kconfig14
-rw-r--r--zephyr/emul/retimer/emul_ps8811.c271
-rw-r--r--zephyr/include/emul/retimer/emul_ps8811.h64
-rw-r--r--zephyr/test/drivers/CMakeLists.txt1
-rw-r--r--zephyr/test/drivers/Kconfig5
-rw-r--r--zephyr/test/drivers/boards/native_posix.overlay5
-rw-r--r--zephyr/test/drivers/testcase.yaml4
-rw-r--r--zephyr/test/drivers/usbc_retimer/CMakeLists.txt5
-rw-r--r--zephyr/test/drivers/usbc_retimer/i2c.dts46
-rw-r--r--zephyr/test/drivers/usbc_retimer/prj.conf3
-rw-r--r--zephyr/test/drivers/usbc_retimer/src/ps8811.c344
17 files changed, 794 insertions, 8 deletions
diff --git a/zephyr/Kconfig.retimer b/zephyr/Kconfig.retimer
index 8c5390eb31..245964711d 100644
--- a/zephyr/Kconfig.retimer
+++ b/zephyr/Kconfig.retimer
@@ -97,14 +97,6 @@ config PLATFORM_EC_USBC_RETIMER_ANX7483
USB3.2 Gen 2 10Gbps signals to support type-C (USB-C) ports with
DisplayPort Alternate Mode.
-config PLATFORM_EC_USBC_RETIMER_PS8811
- bool "Support Parade PS8811 Single Port USB 3.1 Gen 2 10G Retimer"
- help
- The PS8811 is a one-port bidirectional USB 3.1 Gen 2 retimer that
- integrates the UniEye equalizer and a retimer to re-condition USB 3.1
- signals for long media link applications. It supports USB 3.1 Gen 2
- with operation speed up to 10Gbps as well as Gen 1 operation at 5Gbps.
-
config PLATFORM_EC_USBC_RETIMER_PS8818
bool "Parade PS8818 USB Type-C Retimer for USB and DP Alternate Mode"
default y
@@ -133,3 +125,12 @@ config PLATFORM_EC_KB800X_CUSTOM_XBAR
lanes.
endif # PLATFORM_EC_USBC
+
+config PLATFORM_EC_USBC_RETIMER_PS8811
+ bool "Support Parade PS8811 Single Port USB 3.1 Gen 2 10G Retimer"
+ depends on PLATFORM_EC_USBC || TEST_DISABLE_PLATFORM_EC_USBC
+ help
+ The PS8811 is a one-port bidirectional USB 3.1 Gen 2 retimer that
+ integrates the UniEye equalizer and a retimer to re-condition USB 3.1
+ signals for long media link applications. It supports USB 3.1 Gen 2
+ with operation speed up to 10Gbps as well as Gen 1 operation at 5Gbps. \ No newline at end of file
diff --git a/zephyr/Kconfig.usbc b/zephyr/Kconfig.usbc
index 13fc8c653e..6dcf03335c 100644
--- a/zephyr/Kconfig.usbc
+++ b/zephyr/Kconfig.usbc
@@ -14,6 +14,13 @@ menuconfig PLATFORM_EC_USBC
of attached USB-C partners and enabling alternate operational modes,
including Display Port, Thunderbolt, and USB4.
+config TEST_DISABLE_PLATFORM_EC_USBC
+ bool "Test disable USB type-C"
+ depends on ZTEST && !PLATFORM_EC_USBC
+ help
+ Use this config to allow tests for code that doesn't actually rely on
+ USBC.
+
rsource "Kconfig.retimer"
rsource "Kconfig.pd_int_shared"
rsource "Kconfig.pd_meas_vbus"
diff --git a/zephyr/dts/bindings/emul/cros,ps8811-emul.yaml b/zephyr/dts/bindings/emul/cros,ps8811-emul.yaml
new file mode 100644
index 0000000000..1c46f0bfd2
--- /dev/null
+++ b/zephyr/dts/bindings/emul/cros,ps8811-emul.yaml
@@ -0,0 +1,9 @@
+# Copyright 2023 The ChromiumOS Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+description: Zephyr PS8811 emulator
+
+compatible: "cros,ps8811-emul"
+
+include: base.yaml
diff --git a/zephyr/emul/CMakeLists.txt b/zephyr/emul/CMakeLists.txt
index e94b7e7d37..44ff30ce7f 100644
--- a/zephyr/emul/CMakeLists.txt
+++ b/zephyr/emul/CMakeLists.txt
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+add_subdirectory("retimer")
add_subdirectory("tcpc")
cros_ec_library_include_directories(include)
diff --git a/zephyr/emul/Kconfig b/zephyr/emul/Kconfig
index a7a0591c09..9154144d39 100644
--- a/zephyr/emul/Kconfig
+++ b/zephyr/emul/Kconfig
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+rsource "retimer/Kconfig"
rsource "tcpc/Kconfig"
config EMUL_COMMON_I2C
diff --git a/zephyr/emul/retimer/CMakeLists.txt b/zephyr/emul/retimer/CMakeLists.txt
new file mode 100644
index 0000000000..52c6741ac3
--- /dev/null
+++ b/zephyr/emul/retimer/CMakeLists.txt
@@ -0,0 +1,5 @@
+# Copyright 2023 The ChromiumOS Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+zephyr_library_sources_ifdef(CONFIG_EMUL_PS8811 emul_ps8811.c)
diff --git a/zephyr/emul/retimer/Kconfig b/zephyr/emul/retimer/Kconfig
new file mode 100644
index 0000000000..1f4c84f34e
--- /dev/null
+++ b/zephyr/emul/retimer/Kconfig
@@ -0,0 +1,14 @@
+# Copyright 2023 The ChromiumOS Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+config EMUL_PS8811
+ bool "Parade PS8811 Emulator"
+ depends on DT_HAS_CROS_PS8811_EMUL_ENABLED
+ default y
+ help
+ Enable emulator for PS8811 retimer.
+
+config RETIMER_EMUL_LOG_LEVEL
+ int "Retimer emulator log level"
+ default 3 # Log level info \ No newline at end of file
diff --git a/zephyr/emul/retimer/emul_ps8811.c b/zephyr/emul/retimer/emul_ps8811.c
new file mode 100644
index 0000000000..cebb256f66
--- /dev/null
+++ b/zephyr/emul/retimer/emul_ps8811.c
@@ -0,0 +1,271 @@
+/* Copyright 2023 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "driver/retimer/ps8811.h"
+#include "emul/emul_common_i2c.h"
+#include "emul/emul_stub_device.h"
+#include "emul/retimer/emul_ps8811.h"
+
+#include <zephyr/logging/log.h>
+#include <zephyr/ztest.h>
+
+LOG_MODULE_REGISTER(ps8811_emul, CONFIG_RETIMER_EMUL_LOG_LEVEL);
+
+#define DT_DRV_COMPAT cros_ps8811_emul
+
+struct register_config {
+ uint8_t reg;
+ uint8_t def;
+ uint8_t reserved;
+};
+
+static const struct register_config register_configs[] = {
+ {
+ .reg = PS8811_REG1_USB_AEQ_LEVEL,
+ .def = PS8811_REG1_USB_AEQ_LEVEL_DEFAULT,
+ },
+ {
+ .reg = PS8811_REG1_USB_ADE_CONFIG,
+ .def = PS8811_REG1_USB_ADE_CONFIG_DEFAULT,
+ },
+ {
+ .reg = PS8811_REG1_USB_BEQ_LEVEL,
+ .def = PS8811_REG1_USB_BEQ_LEVEL_DEFAULT,
+ },
+ {
+ .reg = PS8811_REG1_USB_BDE_CONFIG,
+ .def = PS8811_REG1_USB_BDE_CONFIG_DEFAULT,
+ },
+ {
+ .reg = PS8811_REG1_USB_CHAN_A_SWING,
+ .def = PS8811_REG1_USB_CHAN_A_SWING_DEFAULT,
+ .reserved = PS8811_REG1_USB_CHAN_A_SWING_RESERVED_MASK,
+ },
+ {
+ .reg = PS8811_REG1_50OHM_ADJUST_CHAN_B,
+ .def = PS8811_REG1_50OHM_ADJUST_CHAN_B_DEFAULT,
+ .reserved = PS8811_REG1_50OHM_ADJUST_CHAN_B_RESERVED_MASK,
+ },
+ {
+ .reg = PS8811_REG1_USB_CHAN_B_SWING,
+ .def = PS8811_REG1_USB_CHAN_B_SWING_DEFAULT,
+ .reserved = PS8811_REG1_USB_CHAN_B_SWING_RESERVED_MASK,
+ },
+ {
+ .reg = PS8811_REG1_USB_CHAN_B_DE_PS_LSB,
+ .def = PS8811_REG1_USB_CHAN_B_DE_PS_LSB_DEFAULT,
+ .reserved = PS8811_REG1_USB_CHAN_B_DE_PS_LSB_RESERVED_MASK,
+ },
+ {
+ .reg = PS8811_REG1_USB_CHAN_B_DE_PS_MSB,
+ .def = PS8811_REG1_USB_CHAN_B_DE_PS_MSB_DEFAULT,
+ .reserved = PS8811_REG1_USB_CHAN_B_DE_PS_MSB_RESERVED_MASK,
+ },
+};
+
+static int ps8811_emul_p1_read_byte(const struct emul *emul, int reg,
+ uint8_t *val, int byte)
+{
+ /* register_configs are all one byte. */
+ if (byte != 0)
+ return -EIO;
+
+ return (ps8811_emul_get_reg1(emul, reg, val) == 0) ? 0 : -EIO;
+}
+
+static int ps8811_emul_p1_write_byte(const struct emul *emul, int reg,
+ uint8_t val, int bytes)
+{
+ /* register_configs are all one byte. */
+ if (bytes != 1)
+ return -EIO;
+
+ return (ps8811_emul_set_reg1(emul, reg, val) == 0) ? 0 : -EIO;
+}
+
+static int ps8811_emul_p0_read_byte(const struct emul *emul, int reg,
+ uint8_t *val, int byte)
+{
+ return (ps8811_emul_get_reg0(emul, reg, val) == 0) ? 0 : -EIO;
+}
+
+static int ps8811_emul_p0_write_byte(const struct emul *emul, int reg,
+ uint8_t val, int bytes)
+{
+ return (ps8811_emul_set_reg0(emul, reg, val) == 0) ? 0 : -EIO;
+}
+
+static int i2c_ps8811_emul_transfer(const struct emul *target,
+ struct i2c_msg *msgs, int num_msgs,
+ int addr)
+{
+ struct ps8811_emul_data *data = target->data;
+ const struct ps8811_emul_cfg *cfg = target->cfg;
+
+ if (addr == target->bus.i2c->addr) {
+ return i2c_common_emul_transfer_workhorse(target, target->data,
+ target->cfg, msgs,
+ num_msgs, addr);
+ } else if (addr == data->p1_data.emul.addr) {
+ return i2c_common_emul_transfer_workhorse(target,
+ &data->p1_data,
+ &cfg->p1_cfg, msgs,
+ num_msgs, addr);
+ }
+
+ LOG_ERR("Cannot map address %02x", addr);
+ return -EIO;
+}
+
+struct i2c_emul_api i2c_ps8811_emul_api = {
+ .transfer = i2c_ps8811_emul_transfer,
+};
+
+static int ps8811_emul_init(const struct emul *emul,
+ const struct device *parent)
+{
+ struct ps8811_emul_data *data = emul->data;
+ const struct ps8811_emul_cfg *cfg = emul->cfg;
+ int rv = 0;
+
+ ps8811_emul_reset(emul);
+
+ i2c_common_emul_init(&data->p0_data);
+
+ data->p1_data.emul.api = &i2c_ps8811_emul_api;
+ data->p1_data.emul.addr = cfg->p1_cfg.addr;
+ data->p1_data.emul.target = emul;
+ data->p1_data.i2c = parent;
+ data->p1_data.cfg = &cfg->p1_cfg;
+ i2c_common_emul_init(&data->p1_data);
+
+ rv = i2c_emul_register(parent, &data->p1_data.emul);
+ if (rv) {
+ LOG_ERR("Failed to register page 1 register emulator");
+ return rv;
+ }
+
+ return 0;
+}
+
+/*
+ * Page 0 contains hardware revision and similar info. No code currently
+ * accesses these register_configs so just stub them out for future use.
+ */
+int ps8811_emul_get_reg0(const struct emul *emulator, int reg, uint8_t *val)
+{
+ return -EINVAL;
+}
+
+int ps8811_emul_set_reg0(const struct emul *emulator, int reg, uint8_t val)
+{
+ return -EINVAL;
+}
+
+static const struct register_config *get_reg1_config(int reg)
+{
+ for (size_t i = 0; i < ARRAY_SIZE(register_configs); i++) {
+ if (register_configs[i].reg == reg)
+ return &register_configs[i];
+ }
+
+ return NULL;
+}
+
+int ps8811_emul_get_reg1(const struct emul *emulator, int reg, uint8_t *val)
+{
+ struct ps8811_emul_data *ps8811 = emulator->data;
+
+ if (reg >= ARRAY_SIZE(ps8811->p1_regs)) {
+ LOG_DBG("Register %x is out of bounds");
+ return -EINVAL;
+ }
+
+ if (!get_reg1_config(reg)) {
+ LOG_DBG("Unknown register %x", reg);
+ return -EINVAL;
+ }
+
+ *val = ps8811->p1_regs[reg];
+ return 0;
+}
+
+int ps8811_emul_set_reg1(const struct emul *emulator, int reg, uint8_t val)
+{
+ struct ps8811_emul_data *ps8811 = emulator->data;
+ const struct register_config *config = get_reg1_config(reg);
+
+ if (reg >= ARRAY_SIZE(ps8811->p1_regs)) {
+ LOG_DBG("Register %x is out of bounds");
+ return -EINVAL;
+ }
+
+ if (!config) {
+ LOG_DBG("Unknown register %x", reg);
+ return -EINVAL;
+ }
+
+ /* Validate that we're not touching reserved bits. */
+ if ((val & config->reserved) != (config->def & config->reserved)) {
+ LOG_DBG("Reserved bits modified for reg %02x, val: %02x, \
+ default: %02x, reserved: %02x",
+ reg, val, config->def, config->reserved);
+ return -EINVAL;
+ }
+
+ ps8811->p1_regs[reg] = val;
+ return 0;
+}
+
+void ps8811_emul_reset(const struct emul *emul)
+{
+ /* Use the setter helps catch any default misconfigs. */
+ for (size_t i = 0; i < ARRAY_SIZE(register_configs); i++)
+ ps8811_emul_set_reg1(emul, register_configs[i].reg,
+ register_configs[i].def);
+}
+
+#define PS8811_EMUL_RESET_RULE_AFTER(n) \
+ ps8811_emul_reset(EMUL_DT_GET(DT_DRV_INST(n)));
+
+static void ps8811_emul_test_reset(const struct ztest_unit_test *test,
+ void *data)
+{
+ ARG_UNUSED(test);
+ ARG_UNUSED(data);
+
+ DT_INST_FOREACH_STATUS_OKAY(PS8811_EMUL_RESET_RULE_AFTER)
+}
+
+ZTEST_RULE(emul_ps8811_reset, NULL, ps8811_emul_test_reset);
+
+#define PS8811_EMUL(n) \
+ static struct ps8811_emul_data ps8811_emul_data_##n = { \
+ .p0_data = { \
+ .read_byte = ps8811_emul_p0_read_byte, \
+ .write_byte = ps8811_emul_p0_write_byte, \
+ }, \
+ .p1_data = { \
+ .read_byte = ps8811_emul_p1_read_byte, \
+ .write_byte = ps8811_emul_p1_write_byte, \
+ }, \
+ }; \
+ static const struct ps8811_emul_cfg ps8811_emul_cfg_##n = { \
+ .p0_cfg = { \
+ .dev_label = DT_NODE_FULL_NAME(DT_DRV_INST(n)), \
+ .data = &ps8811_emul_data_##n.p0_data, \
+ .addr = DT_INST_REG_ADDR(n), \
+ }, \
+ .p1_cfg = { \
+ .dev_label = DT_NODE_FULL_NAME(DT_DRV_INST(n)), \
+ .data = &ps8811_emul_data_##n.p1_data, \
+ .addr = DT_INST_REG_ADDR(n) + 1, \
+ }, \
+ }; \
+ EMUL_DT_INST_DEFINE(n, ps8811_emul_init, &ps8811_emul_data_##n, \
+ &ps8811_emul_cfg_##n, &i2c_ps8811_emul_api, NULL)
+
+DT_INST_FOREACH_STATUS_OKAY(PS8811_EMUL);
+DT_INST_FOREACH_STATUS_OKAY(EMUL_STUB_DEVICE)
diff --git a/zephyr/include/emul/retimer/emul_ps8811.h b/zephyr/include/emul/retimer/emul_ps8811.h
new file mode 100644
index 0000000000..f26c4b5e84
--- /dev/null
+++ b/zephyr/include/emul/retimer/emul_ps8811.h
@@ -0,0 +1,64 @@
+/* Copyright 2023 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef __EMUL_PS8811_H
+#define __EMUL_PS8811_H
+
+#include "driver/retimer/ps8811.h"
+#include "emul/emul_common_i2c.h"
+
+#include <zephyr/device.h>
+#include <zephyr/drivers/emul.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/drivers/i2c_emul.h>
+
+#define PS811_REG1_MAX (PS8811_REG1_USB_CHAN_B_DE_PS_MSB + 1)
+
+#define PS8811_REG1_USB_CHAN_A_SWING_RESERVED_MASK \
+ (GENMASK(7, 7) | GENMASK(3, 0))
+#define PS8811_REG1_50OHM_ADJUST_CHAN_B_RESERVED_MASK GENMASK(7, 4)
+#define PS8811_REG1_USB_CHAN_B_SWING_RESERVED_MASK GENMASK(7, 3)
+#define PS8811_REG1_USB_CHAN_B_DE_PS_LSB_RESERVED_MASK GENMASK(7, 3)
+#define PS8811_REG1_USB_CHAN_B_DE_PS_MSB_RESERVED_MASK GENMASK(7, 5)
+
+#define PS8811_REG1_USB_AEQ_LEVEL_DEFAULT 0x37
+#define PS8811_REG1_USB_ADE_CONFIG_DEFAULT 0x80
+#define PS8811_REG1_USB_BEQ_LEVEL_DEFAULT 0x26
+#define PS8811_REG1_USB_BDE_CONFIG_DEFAULT 0x80
+#define PS8811_REG1_USB_CHAN_A_SWING_DEFAULT 0x00
+#define PS8811_REG1_50OHM_ADJUST_CHAN_B_DEFAULT 0x00
+#define PS8811_REG1_USB_CHAN_B_SWING_DEFAULT 0x02
+#define PS8811_REG1_USB_CHAN_B_DE_PS_LSB_DEFAULT 0x82
+#define PS8811_REG1_USB_CHAN_B_DE_PS_MSB_DEFAULT 0x13
+
+/* Constant configuration of the emulator */
+struct ps8811_emul_cfg {
+ /*
+ * Each page of the PS8811's register map is located at a different I2C
+ * address.
+ */
+ const struct i2c_common_emul_cfg p0_cfg;
+ const struct i2c_common_emul_cfg p1_cfg;
+};
+
+/* Run-time data used by the emulator */
+struct ps8811_emul_data {
+ /* I2C data for each page of the register map. */
+ struct i2c_common_emul_data p0_data;
+ struct i2c_common_emul_data p1_data;
+
+ /* Page 1 registers */
+ uint8_t p1_regs[PS811_REG1_MAX];
+};
+
+int ps8811_emul_get_reg0(const struct emul *emulator, int reg, uint8_t *val);
+int ps8811_emul_set_reg0(const struct emul *emulator, int reg, uint8_t val);
+
+int ps8811_emul_get_reg1(const struct emul *emulator, int reg, uint8_t *val);
+int ps8811_emul_set_reg1(const struct emul *emulator, int reg, uint8_t val);
+
+void ps8811_emul_reset(const struct emul *emul);
+
+#endif /* __EMUL_PS8811_H */
diff --git a/zephyr/test/drivers/CMakeLists.txt b/zephyr/test/drivers/CMakeLists.txt
index b91b1295d9..1284ef446b 100644
--- a/zephyr/test/drivers/CMakeLists.txt
+++ b/zephyr/test/drivers/CMakeLists.txt
@@ -50,6 +50,7 @@ add_subdirectory_ifdef(CONFIG_LINK_TEST_SUITE_USBC_CTVPD usbc_ctvpd)
add_subdirectory_ifdef(CONFIG_LINK_TEST_SUITE_USBC_FRS usbc_frs)
add_subdirectory_ifdef(CONFIG_LINK_TEST_SUITE_USBC_SVDM_DFP_ONLY usbc_svdm_dfp_only)
add_subdirectory_ifdef(CONFIG_LINK_TEST_SUITE_USBC_TBT_MODE usbc_tbt_mode)
+add_subdirectory_ifdef(CONFIG_LINK_TEST_SUITE_USBC_RETIMER usbc_retimer)
add_subdirectory_ifdef(CONFIG_LINK_TEST_SUITE_USBC_USB4_MODE usbc_usb4_mode)
add_subdirectory_ifdef(CONFIG_LINK_TEST_SUITE_USBC_VCONN_SWAP usbc_vconn_swap)
add_subdirectory_ifdef(CONFIG_LINK_TEST_SUITE_USBC_OCP usbc_ocp)
diff --git a/zephyr/test/drivers/Kconfig b/zephyr/test/drivers/Kconfig
index 670746d505..cf24966beb 100644
--- a/zephyr/test/drivers/Kconfig
+++ b/zephyr/test/drivers/Kconfig
@@ -161,6 +161,11 @@ config LINK_TEST_SUITE_USBC_PPC
config LINK_TEST_SUITE_USBC_SVDM_DFP_ONLY
bool "Link and test the usbc_svdm_dfp_only tests"
+config LINK_TEST_SUITE_USBC_RETIMER
+ bool "Link and test the usbc_retimer tests"
+ help
+ Include the usbc_retimer test suite in the binary.
+
config LINK_TEST_SUITE_USBC_TBT_MODE
bool "Link and test the usbc_tbt_mode tests"
diff --git a/zephyr/test/drivers/boards/native_posix.overlay b/zephyr/test/drivers/boards/native_posix.overlay
index 27b888439d..561f2cd311 100644
--- a/zephyr/test/drivers/boards/native_posix.overlay
+++ b/zephyr/test/drivers/boards/native_posix.overlay
@@ -897,6 +897,11 @@
ls-en-pin = <&usb_c1_ls_en>;
};
+ ps8811_emul: ps8811_emul@72 {
+ compatible = "cros,ps8811-emul";
+ reg = <0x72>;
+ };
+
ps8xxx_emul: ps8xxx_emul@b {
compatible = "cros,ps8xxx-emul";
reg = <0xb>;
diff --git a/zephyr/test/drivers/testcase.yaml b/zephyr/test/drivers/testcase.yaml
index c3dc0d13c8..164ca61801 100644
--- a/zephyr/test/drivers/testcase.yaml
+++ b/zephyr/test/drivers/testcase.yaml
@@ -320,6 +320,10 @@ tests:
drivers.usbc_ppc:
extra_configs:
- CONFIG_LINK_TEST_SUITE_USBC_PPC=y
+ drivers.usbc_retimer.ps8811:
+ extra_configs:
+ - CONFIG_LINK_TEST_SUITE_USBC_RETIMER=y
+ - CONFIG_PLATFORM_EC_USBC_RETIMER_PS8811=y
drivers.usbc_svdm_dfp_only:
extra_args: CONF_FILE="prj.conf;usbc_svdm_dfp_only/prj.conf"
DTC_OVERLAY_FILE="usbc_svdm_dfp_only/boards/native_posix.overlay"
diff --git a/zephyr/test/drivers/usbc_retimer/CMakeLists.txt b/zephyr/test/drivers/usbc_retimer/CMakeLists.txt
new file mode 100644
index 0000000000..b67b309400
--- /dev/null
+++ b/zephyr/test/drivers/usbc_retimer/CMakeLists.txt
@@ -0,0 +1,5 @@
+# Copyright 2023 The ChromiumOS Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+target_sources_ifdef(CONFIG_EMUL_PS8811 app PRIVATE src/ps8811.c)
diff --git a/zephyr/test/drivers/usbc_retimer/i2c.dts b/zephyr/test/drivers/usbc_retimer/i2c.dts
new file mode 100644
index 0000000000..5bdf9b1696
--- /dev/null
+++ b/zephyr/test/drivers/usbc_retimer/i2c.dts
@@ -0,0 +1,46 @@
+/* Copyright 2023 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <dt-bindings/usb_pd_tcpm.h>
+
+/ {
+ usbc {
+ port0@0 {
+ compatible = "named-usbc-port";
+ tcpc = <&ps8xxx_emul0>;
+ };
+ port1@1 {
+ compatible = "named-usbc-port";
+ tcpc = <&ps8xxx_emul1>;
+ };
+ };
+};
+
+&i2c2 {
+ status="okay";
+
+ ps8xxx_emul0: ps8xxx_emul@c {
+ compatible = "cros,ps8xxx-emul";
+ reg = <0xc>;
+ p0-i2c-addr = <0x10>;
+ p1-i2c-addr = <0x11>;
+ gpio-i2c-addr = <0x1b>;
+ };
+};
+
+&i2c3 {
+ status="okay";
+
+ /delete-node/ ps8xxx_emul@b;
+
+ ps8xxx_emul1: ps8xxx_emul@b {
+ compatible = "cros,ps8xxx-emul";
+ reg = <0xb>;
+ p0-i2c-addr = <0x8>;
+ p1-i2c-addr = <0x9>;
+ gpio-i2c-addr = <0x1a>;
+ };
+
+};
diff --git a/zephyr/test/drivers/usbc_retimer/prj.conf b/zephyr/test/drivers/usbc_retimer/prj.conf
new file mode 100644
index 0000000000..96bb372274
--- /dev/null
+++ b/zephyr/test/drivers/usbc_retimer/prj.conf
@@ -0,0 +1,3 @@
+# Copyright 2023 The ChromiumOS Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
diff --git a/zephyr/test/drivers/usbc_retimer/src/ps8811.c b/zephyr/test/drivers/usbc_retimer/src/ps8811.c
new file mode 100644
index 0000000000..5c76f49964
--- /dev/null
+++ b/zephyr/test/drivers/usbc_retimer/src/ps8811.c
@@ -0,0 +1,344 @@
+/* Copyright 2023 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "driver/retimer/ps8811.h"
+#include "emul/retimer/emul_ps8811.h"
+#include "i2c.h"
+#include "usb_mux.h"
+
+#include <zephyr/drivers/emul.h>
+#include <zephyr/ztest.h>
+
+#define PS811_EMUL EMUL_DT_GET(DT_NODELABEL(ps8811_emul))
+
+static struct usb_mux mux = {
+ .i2c_port = I2C_PORT_NODELABEL(i2c3),
+ .i2c_addr_flags = PS8811_I2C_ADDR_FLAGS3,
+};
+
+ZTEST_SUITE(ps8811, NULL, NULL, NULL, NULL, NULL);
+
+/* Helper functions to make tests clearer. */
+static int ps8811_emul_test_read0(int reg, int *val)
+{
+ return ps8811_i2c_read(&mux, PS8811_REG_PAGE0, reg, val);
+}
+
+static int ps8811_emul_test_write0(int reg, int val)
+{
+ return ps8811_i2c_write(&mux, PS8811_REG_PAGE0, reg, val);
+}
+
+static int ps8811_emul_test_update0(int reg, uint8_t mask, uint8_t val)
+{
+ return ps8811_i2c_field_update(&mux, PS8811_REG_PAGE0, reg, mask, val);
+}
+
+static int ps8811_emul_test_read1(int reg, int *val)
+{
+ return ps8811_i2c_read(&mux, PS8811_REG_PAGE1, reg, val);
+}
+
+static int ps8811_emul_test_write1(int reg, int val)
+{
+ return ps8811_i2c_write(&mux, PS8811_REG_PAGE1, reg, val);
+}
+
+static int ps8811_emul_test_update1(int reg, uint8_t mask, uint8_t val)
+{
+ return ps8811_i2c_field_update(&mux, PS8811_REG_PAGE1, reg, mask, val);
+}
+
+static int ps8811_emul_test_get_reg1(int reg, uint8_t *val)
+{
+ return ps8811_emul_get_reg1(PS811_EMUL, reg, val);
+}
+
+static int ps8811_emul_test_set_reg1(int reg, uint8_t val)
+{
+ return ps8811_emul_set_reg1(PS811_EMUL, reg, val);
+}
+
+/* Verify that the reset values for all registers are correct. */
+ZTEST(ps8811, test_emul_reset)
+{
+ uint8_t val;
+ int rv;
+
+ rv = ps8811_emul_test_get_reg1(PS8811_REG1_USB_AEQ_LEVEL, &val);
+ zexpect_ok(rv);
+ zexpect_equal(val, PS8811_REG1_USB_AEQ_LEVEL_DEFAULT);
+
+ rv = ps8811_emul_test_get_reg1(PS8811_REG1_USB_ADE_CONFIG, &val);
+ zexpect_ok(rv);
+ zexpect_equal(val, PS8811_REG1_USB_ADE_CONFIG_DEFAULT);
+
+ rv = ps8811_emul_test_get_reg1(PS8811_REG1_USB_BEQ_LEVEL, &val);
+ zexpect_ok(rv);
+ zexpect_equal(val, PS8811_REG1_USB_BEQ_LEVEL_DEFAULT);
+
+ rv = ps8811_emul_test_get_reg1(PS8811_REG1_USB_BDE_CONFIG, &val);
+ zexpect_ok(rv);
+ zexpect_equal(val, PS8811_REG1_USB_BDE_CONFIG_DEFAULT);
+
+ rv = ps8811_emul_test_get_reg1(PS8811_REG1_USB_CHAN_A_SWING, &val);
+ zexpect_ok(rv);
+ zexpect_equal(val, PS8811_REG1_USB_CHAN_A_SWING_DEFAULT);
+
+ rv = ps8811_emul_test_get_reg1(PS8811_REG1_50OHM_ADJUST_CHAN_B, &val);
+ zexpect_ok(rv);
+ zexpect_equal(val, PS8811_REG1_50OHM_ADJUST_CHAN_B_DEFAULT);
+
+ rv = ps8811_emul_test_get_reg1(PS8811_REG1_USB_CHAN_B_SWING, &val);
+ zexpect_ok(rv);
+ zexpect_equal(val, PS8811_REG1_USB_CHAN_B_SWING_DEFAULT);
+
+ rv = ps8811_emul_test_get_reg1(PS8811_REG1_USB_CHAN_B_DE_PS_LSB, &val);
+ zexpect_ok(rv);
+ zexpect_equal(val, PS8811_REG1_USB_CHAN_B_DE_PS_LSB_DEFAULT);
+
+ ps8811_emul_test_get_reg1(PS8811_REG1_USB_CHAN_B_DE_PS_MSB, &val);
+ zexpect_ok(rv);
+ zexpect_equal(val, PS8811_REG1_USB_CHAN_B_DE_PS_MSB_DEFAULT);
+}
+
+/*
+ * P0 registers aren't currently implemented,
+ * ensure access results in an error.
+ */
+ZTEST(ps8811, test_emul_page0_registers)
+{
+ int rv;
+ int val;
+
+ rv = ps8811_emul_test_write0(0, 0);
+ zexpect_not_equal(rv, EC_SUCCESS);
+ rv = ps8811_emul_test_read0(0, &val);
+ zexpect_not_equal(rv, EC_SUCCESS);
+ rv = ps8811_emul_test_update0(0, 0xff, 0xff);
+ zexpect_not_equal(rv, EC_SUCCESS);
+}
+
+/*
+ * Verify that writing/reading all our registers through I2C works. But
+ * don't attempt to verify errors when writing reserved bits.
+ */
+ZTEST(ps8811, test_emul_page1_registers_rw)
+{
+ int val;
+ int rv;
+ uint8_t expected;
+
+ expected = 0xff;
+ rv = ps8811_emul_test_write1(PS8811_REG1_USB_AEQ_LEVEL, expected);
+ zexpect_ok(rv, EC_SUCCESS);
+ rv = ps8811_emul_test_read1(PS8811_REG1_USB_AEQ_LEVEL, &val);
+ zexpect_ok(rv);
+ zexpect_equal(val, expected);
+
+ expected = 0xff;
+ rv = ps8811_emul_test_write1(PS8811_REG1_USB_ADE_CONFIG, expected);
+ zexpect_ok(rv);
+ rv = ps8811_emul_test_read1(PS8811_REG1_USB_ADE_CONFIG, &val);
+ zexpect_ok(rv);
+ zexpect_equal(val, expected);
+
+ expected = 0xff;
+ rv = ps8811_emul_test_write1(PS8811_REG1_USB_BEQ_LEVEL, expected);
+ zexpect_ok(rv);
+ rv = ps8811_emul_test_read1(PS8811_REG1_USB_BEQ_LEVEL, &val);
+ zexpect_ok(rv);
+ zexpect_equal(val, expected);
+
+ expected = 0xff;
+ rv = ps8811_emul_test_write1(PS8811_REG1_USB_BDE_CONFIG, expected);
+ zexpect_ok(rv);
+ rv = ps8811_emul_test_read1(PS8811_REG1_USB_BDE_CONFIG, &val);
+ zexpect_ok(rv);
+ zexpect_equal(val, expected);
+
+ expected = (uint8_t)(PS8811_REG1_USB_CHAN_A_SWING_RESERVED_MASK &
+ PS8811_REG1_USB_CHAN_A_SWING_DEFAULT);
+ expected |= (uint8_t)(~PS8811_REG1_USB_CHAN_A_SWING_RESERVED_MASK);
+ rv = ps8811_emul_test_write1(PS8811_REG1_USB_CHAN_A_SWING, expected);
+ zexpect_ok(rv);
+ rv = ps8811_emul_test_read1(PS8811_REG1_USB_CHAN_A_SWING, &val);
+ zexpect_ok(rv);
+ zexpect_equal(val, expected);
+
+ expected = (uint8_t)(PS8811_REG1_50OHM_ADJUST_CHAN_B_RESERVED_MASK &
+ PS8811_REG1_50OHM_ADJUST_CHAN_B_DEFAULT);
+ expected |= (uint8_t)(~PS8811_REG1_50OHM_ADJUST_CHAN_B_RESERVED_MASK);
+ rv = ps8811_emul_test_write1(PS8811_REG1_50OHM_ADJUST_CHAN_B, expected);
+ zexpect_ok(rv);
+ rv = ps8811_emul_test_read1(PS8811_REG1_50OHM_ADJUST_CHAN_B, &val);
+ zexpect_ok(rv);
+ zexpect_equal(val, expected);
+
+ expected = (uint8_t)(PS8811_REG1_USB_CHAN_B_SWING_RESERVED_MASK &
+ PS8811_REG1_USB_CHAN_B_SWING_DEFAULT);
+ expected |= (uint8_t)(~PS8811_REG1_USB_CHAN_B_SWING_RESERVED_MASK);
+ rv = ps8811_emul_test_write1(PS8811_REG1_USB_CHAN_B_SWING, expected);
+ zexpect_ok(rv);
+ rv = ps8811_emul_test_read1(PS8811_REG1_USB_CHAN_B_SWING, &val);
+ zexpect_ok(rv);
+ zexpect_equal(val, expected);
+
+ expected = (uint8_t)(PS8811_REG1_USB_CHAN_B_DE_PS_LSB_RESERVED_MASK &
+ PS8811_REG1_USB_CHAN_B_DE_PS_LSB_DEFAULT);
+ expected |= (uint8_t)(~PS8811_REG1_USB_CHAN_B_DE_PS_LSB_RESERVED_MASK);
+ rv = ps8811_emul_test_write1(PS8811_REG1_USB_CHAN_B_DE_PS_LSB,
+ expected);
+ zexpect_ok(rv);
+ rv = ps8811_emul_test_read1(PS8811_REG1_USB_CHAN_B_DE_PS_LSB, &val);
+ zexpect_ok(rv);
+ zexpect_equal(val, expected);
+
+ expected = (uint8_t)(PS8811_REG1_USB_CHAN_B_DE_PS_MSB_RESERVED_MASK &
+ PS8811_REG1_USB_CHAN_B_DE_PS_MSB_DEFAULT);
+ expected |= (uint8_t)(~PS8811_REG1_USB_CHAN_B_DE_PS_MSB_RESERVED_MASK);
+ rv = ps8811_emul_test_write1(PS8811_REG1_USB_CHAN_B_DE_PS_MSB,
+ expected);
+ zexpect_ok(rv);
+ rv = ps8811_emul_test_read1(PS8811_REG1_USB_CHAN_B_DE_PS_MSB, &val);
+ zexpect_ok(rv);
+ zexpect_equal(val, expected);
+
+ /* Verify that accessing a non-existent register fails. */
+ rv = ps8811_emul_test_write1(0xff, 0xff);
+ zexpect_not_equal(rv, EC_SUCCESS);
+ rv = ps8811_emul_test_read1(0xff, &val);
+ zexpect_not_equal(rv, EC_SUCCESS);
+}
+
+/* Verify that I2C register updates work. */
+ZTEST(ps8811, test_emul_page1_registers_update)
+{
+ int rv;
+ uint8_t val;
+
+ rv = ps8811_emul_test_set_reg1(PS8811_REG1_USB_AEQ_LEVEL, 0xff);
+ zexpect_ok(rv);
+ rv = ps8811_emul_test_update1(PS8811_REG1_USB_AEQ_LEVEL, 0x0f, 0x00);
+ zexpect_ok(rv);
+ rv = ps8811_emul_test_get_reg1(PS8811_REG1_USB_AEQ_LEVEL, &val);
+ zexpect_ok(rv);
+ zexpect_equal(val, 0xf0);
+
+ rv = ps8811_emul_test_set_reg1(PS8811_REG1_USB_ADE_CONFIG, 0xff);
+ zexpect_ok(rv);
+ rv = ps8811_emul_test_update1(PS8811_REG1_USB_ADE_CONFIG, 0x0f, 0x00);
+ zexpect_ok(rv);
+ rv = ps8811_emul_test_get_reg1(PS8811_REG1_USB_ADE_CONFIG, &val);
+ zexpect_ok(rv);
+ zexpect_equal(val, 0xf0);
+
+ rv = ps8811_emul_test_set_reg1(PS8811_REG1_USB_BEQ_LEVEL, 0xff);
+ zexpect_ok(rv);
+ rv = ps8811_emul_test_update1(PS8811_REG1_USB_BEQ_LEVEL, 0x0f, 0x00);
+ zexpect_ok(rv);
+ rv = ps8811_emul_test_get_reg1(PS8811_REG1_USB_BEQ_LEVEL, &val);
+ zexpect_ok(rv);
+ zexpect_equal(val, 0xf0);
+
+ rv = ps8811_emul_test_set_reg1(PS8811_REG1_USB_BDE_CONFIG, 0xff);
+ zexpect_ok(rv);
+ rv = ps8811_emul_test_update1(PS8811_REG1_USB_BDE_CONFIG, 0x0f, 0x0);
+ zexpect_ok(rv);
+ rv = ps8811_emul_test_get_reg1(PS8811_REG1_USB_BDE_CONFIG, &val);
+ zexpect_equal(val, 0xf0);
+
+ const uint8_t a_swing_mask =
+ (uint8_t)(~PS8811_REG1_USB_CHAN_A_SWING_RESERVED_MASK);
+ rv = ps8811_emul_test_set_reg1(PS8811_REG1_USB_CHAN_A_SWING,
+ a_swing_mask);
+ zexpect_ok(rv);
+ rv = ps8811_emul_test_update1(PS8811_REG1_USB_CHAN_A_SWING,
+ a_swing_mask, 0x0);
+ zexpect_ok(rv);
+ rv = ps8811_emul_test_get_reg1(PS8811_REG1_USB_CHAN_A_SWING, &val);
+ zexpect_equal(val, 0x00);
+
+ const uint8_t adjust_b_50ohm_mask =
+ (uint8_t)(~PS8811_REG1_50OHM_ADJUST_CHAN_B_RESERVED_MASK);
+ rv = ps8811_emul_test_set_reg1(PS8811_REG1_50OHM_ADJUST_CHAN_B,
+ adjust_b_50ohm_mask);
+ zexpect_ok(rv);
+ rv = ps8811_emul_test_update1(PS8811_REG1_50OHM_ADJUST_CHAN_B,
+ adjust_b_50ohm_mask, 0x0);
+ zexpect_ok(rv);
+ rv = ps8811_emul_test_get_reg1(PS8811_REG1_50OHM_ADJUST_CHAN_B, &val);
+ zexpect_equal(val, 0x00);
+
+ const uint8_t b_swing_mask =
+ (uint8_t)(~PS8811_REG1_USB_CHAN_B_SWING_RESERVED_MASK);
+ rv = ps8811_emul_test_set_reg1(PS8811_REG1_USB_CHAN_B_SWING,
+ b_swing_mask);
+ zexpect_ok(rv);
+ rv = ps8811_emul_test_update1(PS8811_REG1_USB_CHAN_B_SWING,
+ b_swing_mask, 0x0);
+ zexpect_ok(rv);
+ rv = ps8811_emul_test_get_reg1(PS8811_REG1_USB_CHAN_B_SWING, &val);
+ zexpect_equal(val, 0x00);
+
+ /* This register has its highest reserved bit set by default. */
+ const uint8_t b_de_ps_lsb_mask =
+ (uint8_t)(~PS8811_REG1_USB_CHAN_B_DE_PS_LSB_RESERVED_MASK) |
+ 0x80;
+ rv = ps8811_emul_test_set_reg1(PS8811_REG1_USB_CHAN_B_DE_PS_LSB,
+ b_de_ps_lsb_mask);
+ zexpect_ok(rv);
+ rv = ps8811_emul_test_update1(PS8811_REG1_USB_CHAN_B_DE_PS_LSB,
+ b_de_ps_lsb_mask, 0x80);
+ zexpect_ok(rv);
+ rv = ps8811_emul_test_get_reg1(PS8811_REG1_USB_CHAN_B_DE_PS_LSB, &val);
+ zexpect_equal(val, 0x80);
+
+ const uint8_t b_de_ps_msb_mask =
+ (uint8_t)(~PS8811_REG1_USB_CHAN_B_DE_PS_MSB_RESERVED_MASK);
+ rv = ps8811_emul_test_set_reg1(PS8811_REG1_USB_CHAN_B_DE_PS_MSB,
+ b_de_ps_msb_mask);
+ zexpect_ok(rv);
+ rv = ps8811_emul_test_update1(PS8811_REG1_USB_CHAN_B_DE_PS_MSB,
+ b_de_ps_msb_mask, 0x0);
+ zexpect_ok(rv);
+ rv = ps8811_emul_test_get_reg1(PS8811_REG1_USB_CHAN_B_DE_PS_MSB, &val);
+ zexpect_equal(val, 0x00);
+
+ /* Verify that updating a non-existent register fails. */
+ rv = ps8811_emul_test_update1(0xff, 0xff, 0xff);
+ zexpect_not_equal(rv, EC_SUCCESS);
+}
+
+/* Verify that writing to reserved bits results in an error. */
+ZTEST(ps8811, test_emul_reserved)
+{
+ int rv;
+
+ rv = ps8811_emul_test_write1(
+ PS8811_REG1_USB_CHAN_A_SWING,
+ PS8811_REG1_USB_CHAN_A_SWING_RESERVED_MASK);
+ zexpect_not_equal(rv, EC_SUCCESS);
+
+ rv = ps8811_emul_test_write1(
+ PS8811_REG1_50OHM_ADJUST_CHAN_B,
+ PS8811_REG1_50OHM_ADJUST_CHAN_B_RESERVED_MASK);
+ zexpect_not_equal(rv, EC_SUCCESS);
+
+ rv = ps8811_emul_test_write1(
+ PS8811_REG1_USB_CHAN_B_SWING,
+ PS8811_REG1_USB_CHAN_B_SWING_RESERVED_MASK);
+ zexpect_not_equal(rv, EC_SUCCESS);
+
+ rv = ps8811_emul_test_write1(
+ PS8811_REG1_USB_CHAN_B_DE_PS_LSB,
+ PS8811_REG1_USB_CHAN_B_DE_PS_LSB_RESERVED_MASK);
+ zexpect_not_equal(rv, EC_SUCCESS);
+
+ rv = ps8811_emul_test_write1(
+ PS8811_REG1_USB_CHAN_B_DE_PS_MSB,
+ PS8811_REG1_USB_CHAN_B_DE_PS_MSB_RESERVED_MASK);
+ zexpect_not_equal(rv, EC_SUCCESS);
+}