diff options
-rw-r--r-- | driver/retimer/ps8811.h | 5 | ||||
-rw-r--r-- | zephyr/Kconfig.retimer | 17 | ||||
-rw-r--r-- | zephyr/Kconfig.usbc | 7 | ||||
-rw-r--r-- | zephyr/dts/bindings/emul/cros,ps8811-emul.yaml | 9 | ||||
-rw-r--r-- | zephyr/emul/CMakeLists.txt | 1 | ||||
-rw-r--r-- | zephyr/emul/Kconfig | 1 | ||||
-rw-r--r-- | zephyr/emul/retimer/CMakeLists.txt | 5 | ||||
-rw-r--r-- | zephyr/emul/retimer/Kconfig | 14 | ||||
-rw-r--r-- | zephyr/emul/retimer/emul_ps8811.c | 271 | ||||
-rw-r--r-- | zephyr/include/emul/retimer/emul_ps8811.h | 64 | ||||
-rw-r--r-- | zephyr/test/drivers/CMakeLists.txt | 1 | ||||
-rw-r--r-- | zephyr/test/drivers/Kconfig | 5 | ||||
-rw-r--r-- | zephyr/test/drivers/boards/native_posix.overlay | 5 | ||||
-rw-r--r-- | zephyr/test/drivers/testcase.yaml | 4 | ||||
-rw-r--r-- | zephyr/test/drivers/usbc_retimer/CMakeLists.txt | 5 | ||||
-rw-r--r-- | zephyr/test/drivers/usbc_retimer/i2c.dts | 46 | ||||
-rw-r--r-- | zephyr/test/drivers/usbc_retimer/prj.conf | 3 | ||||
-rw-r--r-- | zephyr/test/drivers/usbc_retimer/src/ps8811.c | 344 |
18 files changed, 799 insertions, 8 deletions
diff --git a/driver/retimer/ps8811.h b/driver/retimer/ps8811.h index b834635215..5f196de870 100644 --- a/driver/retimer/ps8811.h +++ b/driver/retimer/ps8811.h @@ -26,6 +26,11 @@ #define PS8811_I2C_ADDR_FLAGS3 0x72 /* + * PAGE 0 Register Definitions + */ +#define PS8811_REG_PAGE0 0x00 + +/* * PAGE 1 Register Definitions */ #define PS8811_REG_PAGE1 0x01 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 ®ister_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); +} |