diff options
author | Edward Hill <ecgh@chromium.org> | 2020-07-06 16:56:47 -0600 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-07-15 05:03:50 +0000 |
commit | f0d3fff8b1d060d2a90eecebee70e01af017b615 (patch) | |
tree | 792a1b6cd153092ca70a8ea8f3093d04c42c5fca | |
parent | 3d0b1298968922bbb7fa11f8fe9b7cfa4562180c (diff) | |
download | chrome-ec-f0d3fff8b1d060d2a90eecebee70e01af017b615.tar.gz |
tcpmv2: Add usb_tcpmv2_tcpci test
Add a new test that runs a full set of TCPMv2 layers and state
machines, talking to a simulated TCPC via I2C.
Initial test cases:
1) Plug in a non-PD power supply -> we connect as sink.
2) AP S5 > S3 > S0 -> auto-toggle + low power.
BUG=b:161167893
BRANCH=none
TEST=make -j run-usb_tcpmv2_tcpci
Signed-off-by: Edward Hill <ecgh@chromium.org>
Change-Id: If8b8eb2cca722ed01cbe1d6000fb3e4f4b70149c
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2283911
Reviewed-by: Paul Fagerburg <pfagerburg@chromium.org>
Reviewed-by: Denis Brockus <dbrockus@chromium.org>
Reviewed-by: Jett Rink <jettrink@chromium.org>
-rw-r--r-- | board/host/board.c | 2 | ||||
-rw-r--r-- | common/mock/build.mk | 1 | ||||
-rw-r--r-- | common/mock/tcpci_i2c_mock.c | 141 | ||||
-rw-r--r-- | common/usbc/usbc_task.c | 2 | ||||
-rw-r--r-- | include/mock/tcpci_i2c_mock.h | 14 | ||||
-rw-r--r-- | test/build.mk | 2 | ||||
-rw-r--r-- | test/test_config.h | 23 | ||||
-rw-r--r-- | test/usb_tcpmv2_tcpci.c | 157 | ||||
-rw-r--r-- | test/usb_tcpmv2_tcpci.mocklist | 8 | ||||
-rw-r--r-- | test/usb_tcpmv2_tcpci.tasklist | 11 |
10 files changed, 360 insertions, 1 deletions
diff --git a/board/host/board.c b/board/host/board.c index c342ebca8e..2ee7413152 100644 --- a/board/host/board.c +++ b/board/host/board.c @@ -63,6 +63,8 @@ const struct i2c_port_t i2c_ports[] = { {"battery", I2C_PORT_BATTERY, 100, 0, 0}, #elif defined I2C_PORT_LIGHTBAR {"lightbar", I2C_PORT_LIGHTBAR, 100, 0, 0}, +#elif defined I2C_PORT_HOST_TCPC + {"tcpc", I2C_PORT_HOST_TCPC, 100, 0, 0}, #endif }; diff --git a/common/mock/build.mk b/common/mock/build.mk index e5e8511812..1a4a45910d 100644 --- a/common/mock/build.mk +++ b/common/mock/build.mk @@ -11,6 +11,7 @@ mock-$(HAS_MOCK_MKBP_EVENTS) += mkbp_events_mock.o mock-$(HAS_MOCK_ROLLBACK) += rollback_mock.o mock-$(HAS_MOCK_TCPC) += tcpc_mock.o mock-$(HAS_MOCK_TCPM) += tcpm_mock.o +mock-$(HAS_MOCK_TCPCI_I2C) += tcpci_i2c_mock.o mock-$(HAS_MOCK_TIMER) += timer_mock.o mock-$(HAS_MOCK_USB_MUX) += usb_mux_mock.o mock-$(HAS_MOCK_USB_PD) += usb_pd_mock.o diff --git a/common/mock/tcpci_i2c_mock.c b/common/mock/tcpci_i2c_mock.c new file mode 100644 index 0000000000..45ab613917 --- /dev/null +++ b/common/mock/tcpci_i2c_mock.c @@ -0,0 +1,141 @@ +/* Copyright 2020 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "mock/tcpci_i2c_mock.h" +#include "task.h" +#include "tcpci.h" +#include "test_util.h" + +struct tcpci_reg { + const char *name; + uint8_t size; + uint16_t value; +}; + +#define TCPCI_REG(reg_name, reg_size) \ + [reg_name] = { .name = #reg_name, .size = (reg_size) } + +static struct tcpci_reg tcpci_regs[] = { + TCPCI_REG(TCPC_REG_VENDOR_ID, 2), + TCPCI_REG(TCPC_REG_PRODUCT_ID, 2), + TCPCI_REG(TCPC_REG_BCD_DEV, 2), + TCPCI_REG(TCPC_REG_TC_REV, 2), + TCPCI_REG(TCPC_REG_PD_REV, 2), + TCPCI_REG(TCPC_REG_PD_INT_REV, 2), + TCPCI_REG(TCPC_REG_ALERT, 2), + TCPCI_REG(TCPC_REG_ALERT_MASK, 2), + TCPCI_REG(TCPC_REG_POWER_STATUS_MASK, 1), + TCPCI_REG(TCPC_REG_FAULT_STATUS_MASK, 1), + TCPCI_REG(TCPC_REG_EXT_STATUS_MASK, 1), + TCPCI_REG(TCPC_REG_ALERT_EXTENDED_MASK, 1), + TCPCI_REG(TCPC_REG_CONFIG_STD_OUTPUT, 1), + TCPCI_REG(TCPC_REG_TCPC_CTRL, 1), + TCPCI_REG(TCPC_REG_ROLE_CTRL, 1), + TCPCI_REG(TCPC_REG_FAULT_CTRL, 1), + TCPCI_REG(TCPC_REG_POWER_CTRL, 1), + TCPCI_REG(TCPC_REG_CC_STATUS, 1), + TCPCI_REG(TCPC_REG_POWER_STATUS, 1), + TCPCI_REG(TCPC_REG_FAULT_STATUS, 1), + TCPCI_REG(TCPC_REG_ALERT_EXT, 1), + TCPCI_REG(TCPC_REG_DEV_CAP_1, 2), + TCPCI_REG(TCPC_REG_DEV_CAP_2, 2), + TCPCI_REG(TCPC_REG_STD_INPUT_CAP, 1), + TCPCI_REG(TCPC_REG_STD_OUTPUT_CAP, 1), + TCPCI_REG(TCPC_REG_CONFIG_EXT_1, 1), + TCPCI_REG(TCPC_REG_MSG_HDR_INFO, 1), + TCPCI_REG(TCPC_REG_RX_DETECT, 1), + TCPCI_REG(TCPC_REG_RX_BYTE_CNT, 1), + TCPCI_REG(TCPC_REG_RX_BUF_FRAME_TYPE, 1), + TCPCI_REG(TCPC_REG_TRANSMIT, 1), + TCPCI_REG(TCPC_REG_VBUS_VOLTAGE, 2), + TCPCI_REG(TCPC_REG_VBUS_SINK_DISCONNECT_THRESH, 2), + TCPCI_REG(TCPC_REG_VBUS_STOP_DISCHARGE_THRESH, 2), + TCPCI_REG(TCPC_REG_VBUS_VOLTAGE_ALARM_HI_CFG, 2), + TCPCI_REG(TCPC_REG_VBUS_VOLTAGE_ALARM_LO_CFG, 2), + TCPCI_REG(TCPC_REG_COMMAND, 1), +}; + +void mock_tcpci_reset(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(tcpci_regs); i++) + tcpci_regs[i].value = 0; +} + +void mock_tcpci_set_reg(int reg_offset, uint16_t value) +{ + struct tcpci_reg *reg = tcpci_regs + reg_offset; + + reg->value = value; + ccprints("TCPCI mock set %s = 0x%x", reg->name, reg->value); +} + +uint16_t mock_tcpci_get_reg(int reg_offset) +{ + return tcpci_regs[reg_offset].value; +} + +int tcpci_i2c_xfer(int port, uint16_t slave_addr_flags, + const uint8_t *out, int out_size, + uint8_t *in, int in_size, int flags) +{ + struct tcpci_reg *reg; + + if (port != I2C_PORT_HOST_TCPC) { + ccprints("ERROR: wrong I2C port %d", port); + return EC_ERROR_UNKNOWN; + } + if (slave_addr_flags != MOCK_TCPCI_I2C_ADDR_FLAGS) { + ccprints("ERROR: wrong I2C address 0x%x", slave_addr_flags); + return EC_ERROR_UNKNOWN; + } + + if (out_size == 0) { + ccprints("ERROR: out_size == 0"); + return EC_ERROR_UNKNOWN; + } + reg = tcpci_regs + *out; + if (*out >= ARRAY_SIZE(tcpci_regs) || reg->size == 0) { + ccprints("ERROR: unknown reg 0x%x", *out); + return EC_ERROR_UNKNOWN; + } + if (out_size == 1) { + if (in_size != reg->size) { + ccprints("ERROR: in_size != %d", reg->size); + return EC_ERROR_UNKNOWN; + } + ccprints("%s TCPCI read %s = 0x%x", + task_get_name(task_get_current()), + reg->name, reg->value); + if (reg->size == 1) + in[0] = reg->value; + else if (reg->size == 2) { + in[0] = reg->value; + in[1] = reg->value >> 8; + } + } else { + uint16_t value = 0; + + if (in_size != 0) { + ccprints("ERROR: in_size != 0"); + return EC_ERROR_UNKNOWN; + } + if (out_size != reg->size + 1) { + ccprints("ERROR: out_size != %d", reg->size + 1); + return EC_ERROR_UNKNOWN; + } + if (reg->size == 1) + value = out[1]; + else if (reg->size == 2) + value = out[1] + (out[2] << 8); + ccprints("%s TCPCI write %s = 0x%x", + task_get_name(task_get_current()), + reg->name, value); + reg->value = value; + } + return EC_SUCCESS; +} +DECLARE_TEST_I2C_XFER(tcpci_i2c_xfer); diff --git a/common/usbc/usbc_task.c b/common/usbc/usbc_task.c index 3367e2fd32..9b5382160b 100644 --- a/common/usbc/usbc_task.c +++ b/common/usbc/usbc_task.c @@ -89,7 +89,7 @@ void schedule_deferred_pd_interrupt(const int port) */ void pd_interrupt_handler_task(void *p) { - const int port = (int) p; + const int port = (int) ((intptr_t) p); const int port_mask = (PD_STATUS_TCPC_ALERT_0 << port); struct { int count; diff --git a/include/mock/tcpci_i2c_mock.h b/include/mock/tcpci_i2c_mock.h new file mode 100644 index 0000000000..87f163836c --- /dev/null +++ b/include/mock/tcpci_i2c_mock.h @@ -0,0 +1,14 @@ +/* Copyright 2020 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "common.h" + +#define MOCK_TCPCI_I2C_ADDR_FLAGS 0x99 + +void mock_tcpci_reset(void); + +void mock_tcpci_set_reg(int reg, uint16_t value); + +uint16_t mock_tcpci_get_reg(int reg_offset); diff --git a/test/build.mk b/test/build.mk index 294048077e..9ce5ef8b94 100644 --- a/test/build.mk +++ b/test/build.mk @@ -87,6 +87,7 @@ test-list-host += usb_typec_vpd test-list-host += usb_typec_ctvpd test-list-host += usb_typec_drp_acc_trysrc test-list-host += usb_prl_old +test-list-host += usb_tcpmv2_tcpci test-list-host += usb_prl test-list-host += usb_pe_drp test-list-host += utils @@ -198,6 +199,7 @@ usb_prl_old-y=usb_prl_old.o usb_sm_checks.o fake_usbc.o usb_prl-y=usb_prl.o usb_sm_checks.o usb_pe_drp-y=usb_pe_drp.o usb_sm_checks.o \ fake_battery.o fake_prl.o fake_usbc.o +usb_tcpmv2_tcpci-y=usb_tcpmv2_tcpci.o vpd_api.o usb_sm_checks.o utils-y=utils.o utils_str-y=utils_str.o vboot-y=vboot.o diff --git a/test/test_config.h b/test/test_config.h index 4c53ff0bdf..85c7d29f81 100644 --- a/test/test_config.h +++ b/test/test_config.h @@ -409,6 +409,29 @@ int ncp15wb_calculate_temp(uint16_t adc); #undef CONFIG_USB_PD_HOST_CMD #endif +#ifdef TEST_USB_TCPMV2_TCPCI +#define CONFIG_USB_DRP_ACC_TRYSRC +#define CONFIG_USB_PD_DUAL_ROLE +#define CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE +#define CONFIG_USB_PD_TCPC_LOW_POWER +#define CONFIG_USB_PD_TRY_SRC +#define CONFIG_USB_PD_TCPMV2 +#define CONFIG_USB_PD_PORT_MAX_COUNT 1 +#define CONFIG_USBC_SS_MUX +#define CONFIG_USB_PD_VBUS_DETECT_TCPC +#define CONFIG_USB_POWER_DELIVERY +#define CONFIG_TEST_USB_PE_SM +#define CONFIG_USB_PD_ALT_MODE_DFP +#define CONFIG_USBC_VCONN +#define CONFIG_USBC_VCONN_SWAP +#define CONFIG_USB_PID 0x5036 +#define PD_VCONN_SWAP_DELAY 5000 /* us */ +#define CONFIG_USB_PD_TCPM_TCPCI +#define CONFIG_I2C +#define CONFIG_I2C_MASTER +#define I2C_PORT_HOST_TCPC 0 +#endif + #ifdef TEST_USB_PD_INT #define CONFIG_USB_POWER_DELIVERY #define CONFIG_USB_PD_TCPMV1 diff --git a/test/usb_tcpmv2_tcpci.c b/test/usb_tcpmv2_tcpci.c new file mode 100644 index 0000000000..cc8bf3026a --- /dev/null +++ b/test/usb_tcpmv2_tcpci.c @@ -0,0 +1,157 @@ +/* Copyright 2020 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "hooks.h" +#include "mock/tcpci_i2c_mock.h" +#include "mock/usb_mux_mock.h" +#include "task.h" +#include "tcpci.h" +#include "test_util.h" +#include "timer.h" +#include "usb_mux.h" +#include "usb_tc_sm.h" + +#define PORT0 0 + +enum mock_cc_state { + MOCK_CC_SRC_OPEN = 0, + MOCK_CC_SNK_OPEN = 0, + MOCK_CC_SRC_RA = 1, + MOCK_CC_SNK_RP_DEF = 1, + MOCK_CC_SRC_RD = 2, + MOCK_CC_SNK_RP_1_5 = 2, + MOCK_CC_SNK_RP_3_0 = 3, +}; +enum mock_connect_result { + MOCK_CC_WE_ARE_SRC = 0, + MOCK_CC_WE_ARE_SNK = 1, +}; + +__maybe_unused static void mock_set_cc(enum mock_connect_result cr, + enum mock_cc_state cc1, enum mock_cc_state cc2) +{ + mock_tcpci_set_reg(TCPC_REG_CC_STATUS, + TCPC_REG_CC_STATUS_SET(cr, cc1, cc2)); +} + +__maybe_unused static void mock_set_role(int drp, enum tcpc_rp_value rp, + enum tcpc_cc_pull cc1, enum tcpc_cc_pull cc2) +{ + mock_tcpci_set_reg(TCPC_REG_ROLE_CTRL, + TCPC_REG_ROLE_CTRL_SET(drp, rp, cc1, cc2)); +} + +static int mock_alert_count; + +__maybe_unused static void mock_set_alert(int alert) +{ + mock_tcpci_set_reg(TCPC_REG_ALERT, alert); + mock_alert_count = 1; + schedule_deferred_pd_interrupt(PORT0); +} + +uint16_t tcpc_get_alert_status(void) +{ + ccprints("mock_alert_count %d", mock_alert_count); + if (mock_alert_count > 0) { + mock_alert_count--; + return PD_STATUS_TCPC_ALERT_0; + } + return 0; +} + +const struct svdm_response svdm_rsp = { + .identity = NULL, + .svids = NULL, + .modes = NULL, +}; + +int pd_check_vconn_swap(int port) +{ + return 1; +} + +void board_reset_pd_mcu(void) {} + +const struct tcpc_config_t tcpc_config[CONFIG_USB_PD_PORT_MAX_COUNT] = { + { + .bus_type = EC_BUS_TYPE_I2C, + .i2c_info = { + .port = I2C_PORT_HOST_TCPC, + .addr_flags = MOCK_TCPCI_I2C_ADDR_FLAGS, + }, + .drv = &tcpci_tcpm_drv, + .flags = TCPC_FLAGS_TCPCI_REV2_0, + }, +}; + +const struct usb_mux usb_muxes[CONFIG_USB_PD_PORT_MAX_COUNT] = { + { + .driver = &mock_usb_mux_driver, + } +}; + +__maybe_unused static int test_connect_as_sink(void) +{ + task_wait_event(10 * SECOND); + + /* Simulate a non-PD power supply being plugged in. */ + mock_set_cc(MOCK_CC_WE_ARE_SNK, MOCK_CC_SNK_OPEN, MOCK_CC_SNK_RP_3_0); + mock_set_alert(TCPC_REG_ALERT_CC_STATUS); + + task_wait_event(50 * MSEC); + + mock_tcpci_set_reg(TCPC_REG_POWER_STATUS, + TCPC_REG_POWER_STATUS_VBUS_PRES); + mock_set_alert(TCPC_REG_ALERT_POWER_STATUS); + + task_wait_event(10 * SECOND); + TEST_EQ(tc_is_attached_snk(PORT0), true, "%d"); + + return EC_SUCCESS; +} + +__maybe_unused static int test_startup_and_resume(void) +{ + /* Should be in low power mode before AP boots. */ + TEST_EQ(mock_tcpci_get_reg(TCPC_REG_COMMAND), + TCPC_REG_COMMAND_I2CIDLE, "%d"); + task_wait_event(10 * SECOND); + + hook_notify(HOOK_CHIPSET_STARTUP); + task_wait_event(5 * MSEC); + hook_notify(HOOK_CHIPSET_RESUME); + + task_wait_event(10 * SECOND); + /* Should be in low power mode and DRP auto-toggling with AP in S0. */ + TEST_EQ((mock_tcpci_get_reg(TCPC_REG_ROLE_CTRL) + & TCPC_REG_ROLE_CTRL_DRP_MASK), + TCPC_REG_ROLE_CTRL_DRP_MASK, "%d"); + /* TODO: check previous command was TCPC_REG_COMMAND_LOOK4CONNECTION */ + TEST_EQ(mock_tcpci_get_reg(TCPC_REG_COMMAND), + TCPC_REG_COMMAND_I2CIDLE, "%d"); + + return EC_SUCCESS; +} + +void before_test(void) +{ + mock_usb_mux_reset(); + mock_tcpci_reset(); + + /* Restart the PD task and let it settle */ + task_set_event(TASK_ID_PD_C0, TASK_EVENT_RESET_DONE, 0); + task_wait_event(SECOND); +} + +void run_test(int argc, char **argv) +{ + test_reset(); + + RUN_TEST(test_connect_as_sink); + RUN_TEST(test_startup_and_resume); + + test_print_result(); +} diff --git a/test/usb_tcpmv2_tcpci.mocklist b/test/usb_tcpmv2_tcpci.mocklist new file mode 100644 index 0000000000..58a3541412 --- /dev/null +++ b/test/usb_tcpmv2_tcpci.mocklist @@ -0,0 +1,8 @@ +/* Copyright 2020 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + #define CONFIG_TEST_MOCK_LIST \ + MOCK(USB_MUX) \ + MOCK(TCPCI_I2C) diff --git a/test/usb_tcpmv2_tcpci.tasklist b/test/usb_tcpmv2_tcpci.tasklist new file mode 100644 index 0000000000..654e4eca2b --- /dev/null +++ b/test/usb_tcpmv2_tcpci.tasklist @@ -0,0 +1,11 @@ +/* Copyright 2020 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/** + * See CONFIG_TEST_TASK_LIST in config.h for details. + */ +#define CONFIG_TEST_TASK_LIST \ + TASK_TEST(PD_C0, pd_task, NULL, LARGER_TASK_STACK_SIZE) \ + TASK_TEST(PD_INT_C0, pd_interrupt_handler_task, 0, LARGER_TASK_STACK_SIZE) |