diff options
author | Denis Brockus <dbrockus@google.com> | 2020-12-15 16:20:06 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-12-17 00:29:18 +0000 |
commit | 6ab83beef7e4a6230ce583e2a47b38583bc7dc06 (patch) | |
tree | 6b786d3e5ed142b6235272ceb456ddd350e4e34f | |
parent | 4152f3c9cbcadb6215590967453294c8aa286c35 (diff) | |
download | chrome-ec-6ab83beef7e4a6230ce583e2a47b38583bc7dc06.tar.gz |
TCPMv2: Unit Test TD.PD.LL.E3 Soft Reset Usage
BUG=b:175144677
BRANCH=none
TEST=make run-usb_tcpmv2_compliance
Signed-off-by: Denis Brockus <dbrockus@google.com>
Change-Id: I629e2811b2cba5aa9821d8c855e039a6cfaa32ce
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2595816
Tested-by: Denis Brockus <dbrockus@chromium.org>
Auto-Submit: Denis Brockus <dbrockus@chromium.org>
Reviewed-by: Edward Hill <ecgh@chromium.org>
Commit-Queue: Denis Brockus <dbrockus@chromium.org>
-rw-r--r-- | common/mock/tcpci_i2c_mock.c | 459 | ||||
-rw-r--r-- | include/mock/tcpci_i2c_mock.h | 12 | ||||
-rw-r--r-- | test/build.mk | 3 | ||||
-rw-r--r-- | test/test_config.h | 27 | ||||
-rw-r--r-- | test/usb_tcpmv2_compliance.c | 34 | ||||
-rw-r--r-- | test/usb_tcpmv2_compliance.h | 68 | ||||
-rw-r--r-- | test/usb_tcpmv2_compliance.mocklist | 8 | ||||
-rw-r--r-- | test/usb_tcpmv2_compliance.tasklist | 11 | ||||
-rw-r--r-- | test/usb_tcpmv2_compliance_common.c | 289 | ||||
-rw-r--r-- | test/usb_tcpmv2_td_pd_ll_e3.c | 164 |
10 files changed, 1070 insertions, 5 deletions
diff --git a/common/mock/tcpci_i2c_mock.c b/common/mock/tcpci_i2c_mock.c index 30a56ea0dc..4261eb476f 100644 --- a/common/mock/tcpci_i2c_mock.c +++ b/common/mock/tcpci_i2c_mock.c @@ -70,6 +70,7 @@ static struct tcpci_reg tcpci_regs[] = { static uint8_t tx_buffer[BUFFER_SIZE]; static int tx_pos = -1; +static int tx_retry_cnt = -1; static uint8_t rx_buffer[BUFFER_SIZE]; static int rx_pos = -1; @@ -146,11 +147,11 @@ static int verify_transmit(enum tcpm_transmit_type want_tx_type, int want_tx_retry, enum pd_ctrl_msg_type want_ctrl_msg, enum pd_data_msg_type want_data_msg, - int timeout) + int timeout, + uint16_t *old_transmit) { uint64_t end_time = get_time().val + timeout; - TEST_EQ(tcpci_regs[TCPC_REG_TRANSMIT].value, 0, "%d"); while (get_time().val < end_time) { if (tcpci_regs[TCPC_REG_TRANSMIT].value != 0) { int tx_type = TCPC_REG_TRANSMIT_TYPE( @@ -174,6 +175,11 @@ static int verify_transmit(enum tcpm_transmit_type want_tx_type, TEST_EQ(pd_type, want_data_msg, "0x%x"); TEST_GE(pd_cnt, 1, "%d"); } + + if (old_transmit) + *old_transmit = + tcpci_regs[TCPC_REG_TRANSMIT].value; + tcpci_regs[TCPC_REG_TRANSMIT].value = 0; return EC_SUCCESS; } @@ -187,7 +193,31 @@ int verify_tcpci_transmit(enum tcpm_transmit_type tx_type, enum pd_ctrl_msg_type ctrl_msg, enum pd_data_msg_type data_msg) { - return verify_transmit(tx_type, -1, ctrl_msg, data_msg, VERIFY_TIMEOUT); + return verify_transmit(tx_type, -1, + ctrl_msg, data_msg, + VERIFY_TIMEOUT, NULL); +} + +int verify_tcpci_ignore_transmit(enum tcpm_transmit_type tx_type, + enum pd_ctrl_msg_type ctrl_msg, + enum pd_data_msg_type data_msg) +{ + int rv; + uint16_t transmit; + + rv = verify_transmit(tx_type, -1, + ctrl_msg, data_msg, + VERIFY_TIMEOUT, &transmit); + if (rv == EC_SUCCESS) { + if (tx_retry_cnt == -1) + tx_retry_cnt = TCPC_REG_TRANSMIT_RETRY(transmit); + + if (tx_retry_cnt > 0) { + tx_retry_cnt--; + tcpci_regs[TCPC_REG_TRANSMIT].value = transmit; + } + } + return rv; } int verify_tcpci_tx_timeout(enum tcpm_transmit_type tx_type, @@ -195,13 +225,45 @@ int verify_tcpci_tx_timeout(enum tcpm_transmit_type tx_type, enum pd_data_msg_type data_msg, int timeout) { - return verify_transmit(tx_type, -1, ctrl_msg, data_msg, timeout); + return verify_transmit(tx_type, -1, + ctrl_msg, data_msg, + timeout, NULL); } int verify_tcpci_tx_retry_count(enum tcpm_transmit_type tx_type, int retry_count) { - return verify_transmit(tx_type, retry_count, 0, 0, VERIFY_TIMEOUT); + return verify_transmit(tx_type, retry_count, + 0, 0, + VERIFY_TIMEOUT, NULL); +} + +bool mock_rm_if_tx(enum tcpm_transmit_type want_tx_type, + enum pd_ctrl_msg_type want_ctrl_msg, + enum pd_data_msg_type want_data_msg) +{ + if (tcpci_regs[TCPC_REG_TRANSMIT].value != 0) { + int tx_type = TCPC_REG_TRANSMIT_TYPE( + tcpci_regs[TCPC_REG_TRANSMIT].value); + uint16_t header = UINT16_FROM_BYTE_ARRAY_LE( + tx_buffer, 1); + int pd_type = PD_HEADER_TYPE(header); + int pd_cnt = PD_HEADER_CNT(header); + + if (tx_type != want_tx_type) + return false; + if (want_ctrl_msg != 0) + if (pd_type != want_ctrl_msg || + pd_cnt != 0) + return false; + if (want_data_msg != 0) + if (pd_type != want_data_msg || + pd_cnt < 1) + return false; + tcpci_regs[TCPC_REG_TRANSMIT].value = 0; + return true; + } + return false; } void mock_tcpci_receive(enum pd_msg_type sop, uint16_t header, @@ -246,6 +308,26 @@ void mock_tcpci_set_reg(int reg_offset, uint16_t value) ccprints("TCPCI mock set %s = 0x%x", reg->name, reg->value); } +void mock_tcpci_set_reg_bits(int reg_offset, uint16_t mask) +{ + struct tcpci_reg *reg = tcpci_regs + reg_offset; + uint16_t old_value = reg->value; + + reg->value |= mask; + ccprints("TCPCI mock set bits %s (mask=0x%x) = 0x%x -> 0x%x", + reg->name, mask, old_value, reg->value); +} + +void mock_tcpci_clr_reg_bits(int reg_offset, uint16_t mask) +{ + struct tcpci_reg *reg = tcpci_regs + reg_offset; + uint16_t old_value = reg->value; + + reg->value &= ~mask; + ccprints("TCPCI mock clr bits %s (mask=0x%x) = 0x%x -> 0x%x", + reg->name, mask, old_value, reg->value); +} + uint16_t mock_tcpci_get_reg(int reg_offset) { return tcpci_regs[reg_offset].value; @@ -296,6 +378,7 @@ int tcpci_i2c_xfer(int port, uint16_t slave_addr_flags, print_header("TX", UINT16_FROM_BYTE_ARRAY_LE( tx_buffer, 1)); tx_pos = -1; + tx_retry_cnt = -1; } return EC_SUCCESS; } @@ -363,3 +446,369 @@ int tcpci_i2c_xfer(int port, uint16_t slave_addr_flags, return EC_SUCCESS; } DECLARE_TEST_I2C_XFER(tcpci_i2c_xfer); + +void tcpci_register_dump(void) +{ + int reg; + int cc1, cc2; + + ccprints("********* TCPCI Register Dump ***********"); + reg = mock_tcpci_get_reg(TCPC_REG_ALERT); + ccprints("TCPC_REG_ALERT = 0x%08X", reg); + if (reg) { + if (reg & BIT(0)) + ccprints("\t0001: CC Status"); + if (reg & BIT(1)) + ccprints("\t0002: Power Status"); + if (reg & BIT(2)) + ccprints("\t0004: Received SOP* Message Status"); + if (reg & BIT(3)) + ccprints("\t0008: Received Hard Reset"); + if (reg & BIT(4)) + ccprints("\t0010: Transmit SOP* Message Failed"); + if (reg & BIT(5)) + ccprints("\t0020: Transmit SOP* Message Discarded"); + if (reg & BIT(6)) + ccprints("\t0040: Transmit SOP* Message Successful"); + if (reg & BIT(7)) + ccprints("\t0080: Vbus Voltage Alarm Hi"); + if (reg & BIT(8)) + ccprints("\t0100: Vbus Voltage Alarm Lo"); + if (reg & BIT(9)) + ccprints("\t0200: Fault"); + if (reg & BIT(10)) + ccprints("\t0400: Rx Buffer Overflow"); + if (reg & BIT(11)) + ccprints("\t0800: Vbus Sink Disconnect Detected"); + if (reg & BIT(12)) + ccprints("\t1000: Beginning SOP* Message Status"); + if (reg & BIT(13)) + ccprints("\t2000: Extended Status"); + if (reg & BIT(14)) + ccprints("\t4000: Alert Extended"); + if (reg & BIT(15)) + ccprints("\t8000: Vendor Defined Alert"); + } + + reg = mock_tcpci_get_reg(TCPC_REG_TCPC_CTRL); + ccprints("TCPC_REG_TCPC_CTRL = 0x%04X", reg); + if (reg & BIT(0)) + ccprints("\t01: Plug Orientation FLIP"); + if (reg & BIT(1)) + ccprints("\t02: BIST Test Mode"); + if (reg & (BIT(2) | BIT(3))) { + switch ((reg >> 2) & 3) { + case 2: + ccprints("\t08: Enable Clock Stretching"); + break; + case 3: + ccprints("\t0C: Enable Clock Stretching if !Alert"); + break; + } + } + if (reg & BIT(4)) + ccprints("\t10: Debug Accessory controlled by TCPM"); + if (reg & BIT(5)) + ccprints("\t20: Watchdog Timer enabled"); + if (reg & BIT(6)) + ccprints("\t40: Looking4Connection Alert enabled"); + if (reg & BIT(7)) + ccprints("\t80: SMBus PEC enabled"); + + reg = mock_tcpci_get_reg(TCPC_REG_ROLE_CTRL); + ccprints("TCPC_REG_ROLE_CTRL = 0x%04X", reg); + cc1 = (reg >> 0) & 3; + switch (cc1) { + case 0: + ccprints("\t00: CC1 == Ra"); + break; + case 1: + ccprints("\t01: CC1 == Rp"); + break; + case 2: + ccprints("\t02: CC1 == Rd"); + break; + case 3: + ccprints("\t03: CC1 == OPEN"); + break; + } + cc2 = (reg >> 2) & 3; + switch (cc2) { + case 0: + ccprints("\t00: CC2 == Ra"); + break; + case 1: + ccprints("\t04: CC2 == Rp"); + break; + case 2: + ccprints("\t08: CC2 == Rd"); + break; + case 3: + ccprints("\t0C: CC2 == OPEN"); + break; + } + switch ((reg >> 4) & 3) { + case 0: + ccprints("\t00: Rp Value == default"); + break; + case 1: + ccprints("\t10: Rp Value == 1.5A"); + break; + case 2: + ccprints("\t20: Rp Value == 3A"); + break; + } + if (reg & BIT(6)) + ccprints("\t40: DRP"); + + reg = mock_tcpci_get_reg(TCPC_REG_FAULT_CTRL); + ccprints("TCPC_REG_FAULT_CTRL = 0x%04X", reg); + if (reg & BIT(0)) + ccprints("\t01: Vconn Over Current Fault"); + if (reg & BIT(1)) + ccprints("\t02: Vbus OVP Fault"); + if (reg & BIT(2)) + ccprints("\t04: Vbus OCP Fault"); + if (reg & BIT(3)) + ccprints("\t08: Vbus Discharge Fault"); + if (reg & BIT(4)) + ccprints("\t10: Force OFF Vbus"); + + reg = mock_tcpci_get_reg(TCPC_REG_POWER_CTRL); + ccprints("TCPC_REG_POWER_CTRL = 0x%04X", reg); + if (reg & BIT(0)) + ccprints("\t01: Enable Vconn"); + if (reg & BIT(1)) + ccprints("\t02: Vconn Power Supported"); + if (reg & BIT(2)) + ccprints("\t04: Force Discharge"); + if (reg & BIT(3)) + ccprints("\t08: Enable Bleed Discharge"); + if (reg & BIT(4)) + ccprints("\t10: Auto Discharge Disconnect"); + if (reg & BIT(5)) + ccprints("\t20: Disable Voltage Alarms"); + if (reg & BIT(6)) + ccprints("\t40: VBUS_VOLTAGE monitor disabled"); + if (reg & BIT(7)) + ccprints("\t80: Fast Role Swap enabled"); + + reg = mock_tcpci_get_reg(TCPC_REG_CC_STATUS); + ccprints("TCPC_REG_CC_STATUS = 0x%04X", reg); + switch ((reg >> 0) & 3) { + case 0: + switch (cc1) { + case 1: + ccprints("\t00: CC1-Rp SRC.Open"); + break; + case 2: + ccprints("\t00: CC1-Rd SNK.Open"); + break; + } + break; + case 1: + switch (cc1) { + case 1: + ccprints("\t01: CC1-Rp SRC.Ra"); + break; + case 2: + ccprints("\t01: CC1-Rd SNK.Default"); + break; + } + break; + case 2: + switch (cc1) { + case 1: + ccprints("\t02: CC1-Rp SRC.Rd"); + break; + case 2: + ccprints("\t02: CC1-Rd SNK.Power1.5"); + break; + } + break; + case 3: + switch (cc1) { + case 2: + ccprints("\t03: CC1-Rd SNK.Power3.0"); + break; + } + break; + } + switch ((reg >> 2) & 3) { + case 0: + switch (cc2) { + case 1: + ccprints("\t00: CC2-Rp SRC.Open"); + break; + case 2: + ccprints("\t00: CC2-Rd SNK.Open"); + break; + } + break; + case 1: + switch (cc2) { + case 1: + ccprints("\t04: CC2-Rp SRC.Ra"); + break; + case 2: + ccprints("\t04: CC2-Rd SNK.Default"); + break; + } + break; + case 2: + switch (cc2) { + case 1: + ccprints("\t08: CC2-Rp SRC.Rd"); + break; + case 2: + ccprints("\t08: CC2-Rd SNK.Power1.5"); + break; + } + break; + case 3: + switch (cc2) { + case 2: + ccprints("\t0C: CC2-Rd SNK.Power3.0"); + break; + } + break; + } + if (reg & BIT(4)) + ccprints("\t10: Presenting Rd"); + else + ccprints("\t00: Presenting Rp"); + if (reg & BIT(5)) + ccprints("\t20: Looking4Connection"); + + reg = mock_tcpci_get_reg(TCPC_REG_POWER_STATUS); + ccprints("TCPC_REG_POWER_STATUS = 0x%04X", reg); + if (reg & BIT(0)) + ccprints("\t01: Sinking Vbus"); + if (reg & BIT(1)) + ccprints("\t02: Vconn Present"); + if (reg & BIT(2)) + ccprints("\t04: Vbus Present"); + if (reg & BIT(3)) + ccprints("\t08: Vbus Detect enabled"); + if (reg & BIT(4)) + ccprints("\t10: Sourcing Vbus"); + if (reg & BIT(5)) + ccprints("\t20: Sourcing non-default voltage"); + if (reg & BIT(6)) + ccprints("\t40: TCPC Initialization"); + if (reg & BIT(7)) + ccprints("\t80: Debug Accessory Connected"); + + reg = mock_tcpci_get_reg(TCPC_REG_FAULT_STATUS); + ccprints("TCPC_REG_FAULT_STATUS = 0x%04X", reg); + if (reg & BIT(0)) + ccprints("\t01: I2C Interface Error"); + if (reg & BIT(1)) + ccprints("\t02: Vconn Over Current Fault"); + if (reg & BIT(2)) + ccprints("\t04: Vbus OVP Fault"); + if (reg & BIT(3)) + ccprints("\t08: Vbus OCP Fault"); + if (reg & BIT(4)) + ccprints("\t10: Forced Discharge Failed"); + if (reg & BIT(5)) + ccprints("\t20: Auto Discharge Failed"); + if (reg & BIT(6)) + ccprints("\t40: Force OFF Vbus"); + if (reg & BIT(7)) + ccprints("\t80: TCPCI Registers Reset2Default"); + + reg = mock_tcpci_get_reg(TCPC_REG_EXT_STATUS); + ccprints("TCPC_REG_EXT_STATUS = 0x%04X", reg); + if (reg & BIT(0)) + ccprints("\t01: Vbus is at vSafe0V"); + + reg = mock_tcpci_get_reg(TCPC_REG_ALERT_EXT); + ccprints("TCPC_REG_ALERT_EXT = 0x%04X", reg); + if (reg & BIT(0)) + ccprints("\t01: SNK Fast Role Swap"); + if (reg & BIT(1)) + ccprints("\t02: SRC Fast Role Swap"); + if (reg & BIT(2)) + ccprints("\t04: Timer Expired"); + + reg = mock_tcpci_get_reg(TCPC_REG_COMMAND); + ccprints("TCPC_REG_COMMAND = 0x%04X", reg); + switch (reg) { + case 0x11: + ccprints("\t11: WakeI2C"); + break; + case 0x22: + ccprints("\t22: DisableVbusDetect"); + break; + case 0x33: + ccprints("\t33: EnableVbusDetect"); + break; + case 0x44: + ccprints("\t44: DisableSinkVbus"); + break; + case 0x55: + ccprints("\t55: SinkVbus"); + break; + case 0x66: + ccprints("\t66: DisableSourceVbus"); + break; + case 0x77: + ccprints("\t77: SourceVbusDefaultVoltage"); + break; + case 0x88: + ccprints("\t88: SourceVbusNondefaultVoltage"); + break; + case 0x99: + ccprints("\t99: Looking4Connection"); + break; + case 0xAA: + ccprints("\tAA: RxOneMore"); + break; + case 0xCC: + ccprints("\tCC: SendFRSwapSignal"); + break; + case 0xDD: + ccprints("\tDD: ResetTransmitBuffer"); + break; + case 0xEE: + ccprints("\tEE: ResetReceiveBuffer"); + break; + case 0xFF: + ccprints("\tFF: I2C Idle"); + break; + } + + reg = mock_tcpci_get_reg(TCPC_REG_MSG_HDR_INFO); + ccprints("TCPC_REG_MSG_HDR_INFO = 0x%04X", reg); + if (reg & BIT(0)) + ccprints("\t01: Power Role SRC"); + else + ccprints("\t00: Power Role SNK"); + switch ((reg >> 1) & 3) { + case 0: + ccprints("\t00: PD Revision 1.0"); + break; + case 1: + ccprints("\t02: PD Revision 2.0"); + break; + case 2: + ccprints("\t04: PD Revision 3.0"); + break; + } + if (reg & BIT(3)) + ccprints("\t08: Data Role DFP"); + else + ccprints("\t00: Data Role UFP"); + if (reg & BIT(4)) + ccprints("\t10: Message originating from Cable Plug"); + else + ccprints("\t00: Message originating from SRC/SNK/DRP"); + + reg = mock_tcpci_get_reg(TCPC_REG_RX_BUFFER); + ccprints("TCPC_REG_RX_BUFFER = 0x%04X", reg); + + reg = mock_tcpci_get_reg(TCPC_REG_TRANSMIT); + ccprints("TCPC_REG_TRANSMIT = 0x%04X", reg); + ccprints("*****************************************"); +} diff --git a/include/mock/tcpci_i2c_mock.h b/include/mock/tcpci_i2c_mock.h index 4864c7fc96..bac4644c20 100644 --- a/include/mock/tcpci_i2c_mock.h +++ b/include/mock/tcpci_i2c_mock.h @@ -11,6 +11,8 @@ void mock_tcpci_reset(void); void mock_tcpci_set_reg(int reg, uint16_t value); +void mock_tcpci_set_reg_bits(int reg_offset, uint16_t mask); +void mock_tcpci_clr_reg_bits(int reg_offset, uint16_t mask); uint16_t mock_tcpci_get_reg(int reg_offset); @@ -18,6 +20,10 @@ int verify_tcpci_transmit(enum tcpm_transmit_type tx_type, enum pd_ctrl_msg_type ctrl_msg, enum pd_data_msg_type data_msg); +int verify_tcpci_ignore_transmit(enum tcpm_transmit_type tx_type, + enum pd_ctrl_msg_type ctrl_msg, + enum pd_data_msg_type data_msg); + int verify_tcpci_tx_retry_count(enum tcpm_transmit_type tx_type, int retry_count); @@ -28,3 +34,9 @@ int verify_tcpci_tx_timeout(enum tcpm_transmit_type tx_type, void mock_tcpci_receive(enum pd_msg_type sop, uint16_t header, uint32_t *payload); + +bool mock_rm_if_tx(enum tcpm_transmit_type want_tx_type, + enum pd_ctrl_msg_type want_ctrl_msg, + enum pd_data_msg_type want_data_msg); + +void tcpci_register_dump(void); diff --git a/test/build.mk b/test/build.mk index fa0e3500cf..0684f995d1 100644 --- a/test/build.mk +++ b/test/build.mk @@ -93,6 +93,7 @@ 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_tcpmv2_compliance test-list-host += usb_prl test-list-host += usb_prl_noextended test-list-host += usb_pe_drp_old @@ -217,6 +218,8 @@ usb_pe_drp_old_noextended-y=usb_pe_drp_old.o usb_sm_checks.o fake_usbc.o usb_pe_drp-y=usb_pe_drp.o usb_sm_checks.o usb_pe_drp_noextended-y=usb_pe_drp_noextended.o usb_sm_checks.o usb_tcpmv2_tcpci-y=usb_tcpmv2_tcpci.o vpd_api.o usb_sm_checks.o +usb_tcpmv2_compliance-y=usb_tcpmv2_compliance.o vpd_api.o usb_sm_checks.o \ + usb_tcpmv2_compliance_common.o usb_tcpmv2_td_pd_ll_e3.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 00dbcab5c9..fec9fd7084 100644 --- a/test/test_config.h +++ b/test/test_config.h @@ -501,6 +501,33 @@ int ncp15wb_calculate_temp(uint16_t adc); #define CONFIG_USB_PD_DECODE_SOP #endif +#ifdef TEST_USB_TCPMV2_COMPLIANCE +#define CONFIG_USB_DRP_ACC_TRYSRC +#define CONFIG_USB_PD_DUAL_ROLE +#define CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE +#define CONFIG_USB_PD_REV30 +#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_CONTROLLER +#define I2C_PORT_HOST_TCPC 0 +#define CONFIG_USB_PD_DEBUG_LEVEL 3 +#define CONFIG_USB_PD_EXTENDED_MESSAGES +#define CONFIG_USB_PD_DECODE_SOP +#endif + #ifdef TEST_USB_PD_INT #define CONFIG_USB_POWER_DELIVERY #define CONFIG_USB_PD_TCPMV1 diff --git a/test/usb_tcpmv2_compliance.c b/test/usb_tcpmv2_compliance.c new file mode 100644 index 0000000000..2ca08308ca --- /dev/null +++ b/test/usb_tcpmv2_compliance.c @@ -0,0 +1,34 @@ +/* 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 "mock/usb_mux_mock.h" +#include "task.h" +#include "test_util.h" +#include "timer.h" +#include "usb_tcpmv2_compliance.h" + +void before_test(void) +{ + partner_tx_id = 0; + partner_set_pd_rev(PD_REV30); + + 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); + task_wait_event(SECOND); +} + +void run_test(int argc, char **argv) +{ + test_reset(); + + RUN_TEST(test_td_pd_ll_e3_dfp); + RUN_TEST(test_td_pd_ll_e3_ufp); + + test_print_result(); +} diff --git a/test/usb_tcpmv2_compliance.h b/test/usb_tcpmv2_compliance.h new file mode 100644 index 0000000000..fb869a509c --- /dev/null +++ b/test/usb_tcpmv2_compliance.h @@ -0,0 +1,68 @@ +/* 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. + */ + +#ifndef USB_TCPMV2_COMPLIANCE_H +#define USB_TCPMV2_COMPLIANCE_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_DUT_IS_SRC = 0, + MOCK_CC_DUT_IS_SNK = 1, +}; + + +extern int partner_tx_id; + +extern uint32_t rdo; +extern uint32_t pdo; + +extern const struct tcpc_config_t tcpc_config[]; +extern const struct usb_mux usb_muxes[]; + + +void mock_set_cc(enum mock_connect_result cr, + enum mock_cc_state cc1, enum mock_cc_state cc2); +void mock_set_role(int drp, enum tcpc_rp_value rp, + enum tcpc_cc_pull cc1, enum tcpc_cc_pull cc2); +void mock_set_alert(int alert); +uint16_t tcpc_get_alert_status(void); +bool vboot_allow_usb_pd(void); +int pd_check_vconn_swap(int port); +void board_reset_pd_mcu(void); + + +int tcpci_startup(void); + +void partner_set_data_role(enum pd_data_role data_role); +enum pd_data_role partner_get_data_role(void); + +void partner_set_power_role(enum pd_power_role power_role); +enum pd_power_role partner_get_power_role(void); + +void partner_set_pd_rev(enum pd_rev_type pd_rev); +enum pd_rev_type partner_get_pd_rev(void); + +void partner_send_msg(enum pd_msg_type sop, + uint16_t type, + uint16_t cnt, + uint16_t ext, + uint32_t *payload); + +int proc_pd_e1(enum pd_data_role data_role); + +int test_td_pd_ll_e3_dfp(void); +int test_td_pd_ll_e3_ufp(void); + +#endif /* USB_TCPMV2_COMPLIANCE_H */ diff --git a/test/usb_tcpmv2_compliance.mocklist b/test/usb_tcpmv2_compliance.mocklist new file mode 100644 index 0000000000..58a3541412 --- /dev/null +++ b/test/usb_tcpmv2_compliance.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_compliance.tasklist b/test/usb_tcpmv2_compliance.tasklist new file mode 100644 index 0000000000..654e4eca2b --- /dev/null +++ b/test/usb_tcpmv2_compliance.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) diff --git a/test/usb_tcpmv2_compliance_common.c b/test/usb_tcpmv2_compliance_common.c new file mode 100644 index 0000000000..2c3d6e0546 --- /dev/null +++ b/test/usb_tcpmv2_compliance_common.c @@ -0,0 +1,289 @@ +/* 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_tcpmv2_compliance.h" + +int partner_tx_id; + +uint32_t rdo = RDO_FIXED(1, 500, 500, 0); +uint32_t pdo = PDO_FIXED(5000, 3000, + PDO_FIXED_DUAL_ROLE | + PDO_FIXED_DATA_SWAP | + PDO_FIXED_COMM_CAP); + +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, + } +}; + + +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)); +} + +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; +void mock_set_alert(int alert) +{ + mock_tcpci_set_reg_bits(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; +} + +bool vboot_allow_usb_pd(void) +{ + return 1; +} + +int pd_check_vconn_swap(int port) +{ + return 1; +} + +void board_reset_pd_mcu(void) {} + + +/***************************************************************************** + * Partner utility functions + */ +static enum pd_data_role partner_data_role; +void partner_set_data_role(enum pd_data_role data_role) +{ + partner_data_role = data_role; +} +enum pd_data_role partner_get_data_role(void) +{ + return partner_data_role; +} + +static enum pd_power_role partner_power_role; +void partner_set_power_role(enum pd_power_role power_role) +{ + partner_power_role = power_role; +} +enum pd_power_role partner_get_power_role(void) +{ + return partner_power_role; +} + +static enum pd_rev_type partner_pd_rev; +void partner_set_pd_rev(enum pd_rev_type pd_rev) +{ + partner_pd_rev = pd_rev; +} +enum pd_rev_type partner_get_pd_rev(void) +{ + return partner_pd_rev; +} + +void partner_send_msg(enum pd_msg_type sop, + uint16_t type, + uint16_t cnt, + uint16_t ext, + uint32_t *payload) +{ + uint16_t header; + + partner_tx_id &= 7; + header = PD_HEADER(type, + partner_get_power_role(), + partner_get_data_role(), + partner_tx_id, + cnt, + partner_get_pd_rev(), + ext); + + mock_tcpci_receive(sop, header, payload); + partner_tx_id++; + mock_set_alert(TCPC_REG_ALERT_RX_STATUS); +} + + +/***************************************************************************** + * TCPCI clean power up + */ +int tcpci_startup(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; +} + +/***************************************************************************** + * PROC.PD.E1. Bring-up procedure + */ +int proc_pd_e1(enum pd_data_role data_role) +{ + /* + * a) The test starts in a disconnected state. + */ + TEST_EQ(pd_get_data_role(I2C_PORT_HOST_TCPC), + PD_ROLE_DISCONNECTED, "%d"); + + switch (data_role) { + case PD_ROLE_UFP: + /* + * b) The tester applies Rp (3A) and waits for the UUT + * attachment. + */ + mock_set_cc(MOCK_CC_DUT_IS_SNK, + MOCK_CC_SNK_OPEN, + MOCK_CC_SNK_RP_3_0); + mock_set_alert(TCPC_REG_ALERT_CC_STATUS); + task_wait_event(5 * MSEC); + + partner_set_data_role(PD_ROLE_DFP); + partner_set_power_role(PD_ROLE_SOURCE); + + /* + * c) If Ra is detected, the tester applies Vconn. + */ + + /* + * d) The tester applies Vbus and waits 50 ms. + */ + mock_tcpci_set_reg_bits(TCPC_REG_POWER_STATUS, + TCPC_REG_POWER_STATUS_VBUS_PRES); + + mock_tcpci_clr_reg_bits(TCPC_REG_EXT_STATUS, + TCPC_REG_EXT_STATUS_SAFE0V); + mock_set_alert(TCPC_REG_ALERT_EXT_STATUS | + TCPC_REG_ALERT_POWER_STATUS); + + task_wait_event(50 * MSEC); + + /* + * e) The tester transmits Source Capabilities until reception + * of GoodCrc for tNoResponse max (5.5s). The Source + * Capabilities includes Fixed 5V 3A PDO. + */ + partner_send_msg(PD_MSG_SOP, PD_DATA_SOURCE_CAP, 1, 0, &pdo); + + /* + * f) The tester waits for the Request from the UUT for + * tSenderResponse max (30 ms). + */ + TEST_EQ(verify_tcpci_transmit(TCPC_TX_SOP, 0, PD_DATA_REQUEST), + EC_SUCCESS, "%d"); + mock_set_alert(TCPC_REG_ALERT_TX_SUCCESS); + + /* + * g) The tester sends Accept, and when Vbus is stable at the + * target voltage, sends PS_RDY. + */ + partner_send_msg(PD_MSG_SOP, PD_CTRL_ACCEPT, 0, 0, NULL); + task_wait_event(10 * MSEC); + partner_send_msg(PD_MSG_SOP, PD_CTRL_PS_RDY, 0, 0, NULL); + task_wait_event(1 * MSEC); + break; + + case PD_ROLE_DFP: + /* + * b) The tester applies Rd and waits for Vbus for tNoResponse + * max (5.5 s). + */ + mock_set_cc(MOCK_CC_DUT_IS_SRC, + MOCK_CC_SRC_OPEN, + MOCK_CC_SRC_RD); + mock_set_alert(TCPC_REG_ALERT_CC_STATUS); + + partner_set_data_role(PD_ROLE_UFP); + partner_set_power_role(PD_ROLE_SINK); + + /* + * c) The tester waits Source Capabilities for for tNoResponse + * max (5.5 s). + */ + TEST_EQ(verify_tcpci_transmit(TCPC_TX_SOP, + 0, + PD_DATA_SOURCE_CAP), + EC_SUCCESS, "%d"); + + /* + * d) The tester replies GoodCrc on reception of the Source + * Capabilities. + */ + mock_set_alert(TCPC_REG_ALERT_TX_SUCCESS); + task_wait_event(10 * MSEC); + + /* + * e) The tester requests 5V 0.5A. + */ + partner_send_msg(PD_MSG_SOP, PD_DATA_REQUEST, 1, 0, &rdo); + + TEST_EQ(verify_tcpci_transmit(TCPC_TX_SOP, PD_CTRL_ACCEPT, 0), + EC_SUCCESS, "%d"); + mock_set_alert(TCPC_REG_ALERT_TX_SUCCESS); + + /* + * f) The tester waits PS_RDY for tPSSourceOn max (480 ms). + */ + TEST_EQ(verify_tcpci_transmit(TCPC_TX_SOP, PD_CTRL_PS_RDY, 0), + EC_SUCCESS, "%d"); + mock_set_alert(TCPC_REG_ALERT_TX_SUCCESS); + break; + + case PD_ROLE_DISCONNECTED: + break; + } + + TEST_EQ(pd_get_data_role(I2C_PORT_HOST_TCPC), data_role, "%d"); + return EC_SUCCESS; +} diff --git a/test/usb_tcpmv2_td_pd_ll_e3.c b/test/usb_tcpmv2_td_pd_ll_e3.c new file mode 100644 index 0000000000..d2aedf2b9d --- /dev/null +++ b/test/usb_tcpmv2_td_pd_ll_e3.c @@ -0,0 +1,164 @@ +/* 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" +#include "timer.h" +#include "usb_tcpmv2_compliance.h" + +/***************************************************************************** + * TD.PD.LL.E3. Soft Reset Usage + * + * Description: + * Check that the UUT will issue a Soft Reset after unsuccessful retries, + * and that the link can be successfully recovered after that. + */ +static int td_pd_ll_e3(enum pd_data_role data_role) +{ + int retry, retries; + + TEST_EQ(tcpci_startup(), EC_SUCCESS, "%d"); + + /* + * Set Vbus to Safe0V + */ + mock_tcpci_set_reg_bits(TCPC_REG_EXT_STATUS, + TCPC_REG_EXT_STATUS_SAFE0V); + mock_set_alert(TCPC_REG_ALERT_EXT_STATUS); + task_wait_event(10 * SECOND); + + /* + * a) Run PROC.PD.E1 Bring-up according to the UUT role. + */ + TEST_EQ(proc_pd_e1(data_role), EC_SUCCESS, "%d"); + + /* + * Make sure we are idle. Reject everything that is pending + */ + for (;;) { + if (mock_rm_if_tx(TCPC_TX_SOP, + PD_CTRL_DR_SWAP, 0)) { + mock_set_alert(TCPC_REG_ALERT_TX_SUCCESS); + + partner_send_msg(PD_MSG_SOP, + PD_CTRL_REJECT, + 0, 0, NULL); + task_wait_event(1 * MSEC); + continue; + } + if (mock_rm_if_tx(TCPC_TX_SOP, + PD_CTRL_VCONN_SWAP, 0)) { + mock_set_alert(TCPC_REG_ALERT_TX_SUCCESS); + + partner_send_msg(PD_MSG_SOP, + PD_CTRL_REJECT, + 0, 0, NULL); + task_wait_event(1 * MSEC); + continue; + } + if (mock_rm_if_tx(TCPC_TX_SOP, + 0, PD_DATA_VENDOR_DEF)) { + mock_set_alert(TCPC_REG_ALERT_TX_SUCCESS); + + partner_send_msg(PD_MSG_SOP, + PD_CTRL_NOT_SUPPORTED, + 0, 0, NULL); + task_wait_event(1 * MSEC); + continue; + } + if (mock_rm_if_tx(TCPC_TX_SOP, + PD_CTRL_GET_SINK_CAP, 0)) { + mock_set_alert(TCPC_REG_ALERT_TX_SUCCESS); + + partner_send_msg(PD_MSG_SOP, + PD_CTRL_REJECT, + 0, 0, NULL); + task_wait_event(1 * MSEC); + continue; + } + break; + } + + /* + * b) Send a Get_Sink_Cap message to the UUT, wait for a reply + * and do not send GoodCrc for nRetryCount + 1 times + * (nRetryCount equals 3 since PD 2.1). + */ + partner_send_msg(PD_MSG_SOP, + PD_CTRL_GET_SINK_CAP, + 0, 0, NULL); + + retries = (partner_get_pd_rev() == PD_REV30) ? 2 : 3; + for (retry = 0; retry <= retries; retry++) { + TEST_EQ(verify_tcpci_ignore_transmit( + TCPC_TX_SOP, + 0, PD_DATA_SINK_CAP), + EC_SUCCESS, "%d"); + } + + /* + * c) Check that the UUT issues a Soft Reset. + */ + TEST_EQ(verify_tcpci_transmit(TCPC_TX_SOP, PD_CTRL_SOFT_RESET, 0), + EC_SUCCESS, "%d"); + mock_set_alert(TCPC_REG_ALERT_TX_SUCCESS); + task_wait_event(10 * MSEC); + + /* + * d) Handle correctly the Soft Reset procedure. + */ + partner_send_msg(PD_MSG_SOP, PD_CTRL_ACCEPT, 0, 0, NULL); + task_wait_event(1 * MSEC); + + /* + * e) Continue the bring-up procedure and check that the link is + * successfully established. + */ + if (partner_get_power_role() == PD_ROLE_SINK) { + TEST_EQ(verify_tcpci_transmit(TCPC_TX_SOP, + 0, + PD_DATA_SOURCE_CAP), + EC_SUCCESS, "%d"); + + mock_set_alert(TCPC_REG_ALERT_TX_SUCCESS); + task_wait_event(10 * MSEC); + + partner_send_msg(PD_MSG_SOP, PD_DATA_REQUEST, 1, 0, &rdo); + + TEST_EQ(verify_tcpci_transmit(TCPC_TX_SOP, PD_CTRL_ACCEPT, 0), + EC_SUCCESS, "%d"); + mock_set_alert(TCPC_REG_ALERT_TX_SUCCESS); + + TEST_EQ(verify_tcpci_transmit(TCPC_TX_SOP, PD_CTRL_PS_RDY, 0), + EC_SUCCESS, "%d"); + mock_set_alert(TCPC_REG_ALERT_TX_SUCCESS); + task_wait_event(5 * MSEC); + + partner_send_msg(PD_MSG_SOP, PD_CTRL_ACCEPT, 0, 0, NULL); + task_wait_event(1 * MSEC); + } else { + partner_send_msg(PD_MSG_SOP, PD_DATA_SOURCE_CAP, 1, 0, &pdo); + + TEST_EQ(verify_tcpci_transmit(TCPC_TX_SOP, 0, PD_DATA_REQUEST), + EC_SUCCESS, "%d"); + mock_set_alert(TCPC_REG_ALERT_TX_SUCCESS); + + partner_send_msg(PD_MSG_SOP, PD_CTRL_ACCEPT, 0, 0, NULL); + task_wait_event(10 * MSEC); + partner_send_msg(PD_MSG_SOP, PD_CTRL_PS_RDY, 0, 0, NULL); + task_wait_event(1 * MSEC); + } + return EC_SUCCESS; +} +int test_td_pd_ll_e3_dfp(void) +{ + return td_pd_ll_e3(PD_ROLE_DFP); +} +int test_td_pd_ll_e3_ufp(void) +{ + return td_pd_ll_e3(PD_ROLE_UFP); +} |