diff options
-rw-r--r-- | common/mock/tcpci_i2c_mock.c | 214 | ||||
-rw-r--r-- | common/usbc/usbc_task.c | 1 | ||||
-rw-r--r-- | include/mock/tcpci_i2c_mock.h | 8 | ||||
-rw-r--r-- | test/test_config.h | 3 | ||||
-rw-r--r-- | test/usb_tcpmv2_tcpci.c | 101 |
5 files changed, 314 insertions, 13 deletions
diff --git a/common/mock/tcpci_i2c_mock.c b/common/mock/tcpci_i2c_mock.c index 45ab613917..a0aa40dba4 100644 --- a/common/mock/tcpci_i2c_mock.c +++ b/common/mock/tcpci_i2c_mock.c @@ -7,15 +7,20 @@ #include "task.h" #include "tcpci.h" #include "test_util.h" +#include "timer.h" + +#define BUFFER_SIZE 100 struct tcpci_reg { - const char *name; + uint8_t offset; uint8_t size; uint16_t value; + const char *name; }; -#define TCPCI_REG(reg_name, reg_size) \ - [reg_name] = { .name = #reg_name, .size = (reg_size) } +#define TCPCI_REG(reg_name, reg_size) \ + [reg_name] = { .offset = (reg_name), .size = (reg_size), \ + .value = 0, .name = #reg_name, } static struct tcpci_reg tcpci_regs[] = { TCPCI_REG(TCPC_REG_VENDOR_ID, 2), @@ -38,6 +43,7 @@ static struct tcpci_reg tcpci_regs[] = { 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_EXT_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), @@ -46,9 +52,9 @@ static struct tcpci_reg tcpci_regs[] = { 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_RX_BUFFER, BUFFER_SIZE), TCPCI_REG(TCPC_REG_TRANSMIT, 1), + TCPCI_REG(TCPC_REG_TX_BUFFER, BUFFER_SIZE), 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), @@ -57,6 +63,141 @@ static struct tcpci_reg tcpci_regs[] = { TCPCI_REG(TCPC_REG_COMMAND, 1), }; +static uint8_t tx_buffer[BUFFER_SIZE]; +static int tx_pos = -1; +static uint8_t rx_buffer[BUFFER_SIZE]; +static int rx_pos = -1; + +static const char * const ctrl_msg_name[] = { + [0] = "RSVD-C0", + [PD_CTRL_GOOD_CRC] = "GOODCRC", + [PD_CTRL_GOTO_MIN] = "GOTOMIN", + [PD_CTRL_ACCEPT] = "ACCEPT", + [PD_CTRL_REJECT] = "REJECT", + [PD_CTRL_PING] = "PING", + [PD_CTRL_PS_RDY] = "PSRDY", + [PD_CTRL_GET_SOURCE_CAP] = "GSRCCAP", + [PD_CTRL_GET_SINK_CAP] = "GSNKCAP", + [PD_CTRL_DR_SWAP] = "DRSWAP", + [PD_CTRL_PR_SWAP] = "PRSWAP", + [PD_CTRL_VCONN_SWAP] = "VCONNSW", + [PD_CTRL_WAIT] = "WAIT", + [PD_CTRL_SOFT_RESET] = "SFT-RST", + [14] = "RSVD-C14", + [15] = "RSVD-C15", + [PD_CTRL_NOT_SUPPORTED] = "NOT-SUPPORTED", + [PD_CTRL_GET_SOURCE_CAP_EXT] = "GSRCCAP-EXT", + [PD_CTRL_GET_STATUS] = "GET-STATUS", + [PD_CTRL_FR_SWAP] = "FRSWAP", + [PD_CTRL_GET_PPS_STATUS] = "GET-PPS-STATUS", + [PD_CTRL_GET_COUNTRY_CODES] = "GET-COUNTRY-CODES", +}; + +static const char * const data_msg_name[] = { + [0] = "RSVD-D0", + [PD_DATA_SOURCE_CAP] = "SRCCAP", + [PD_DATA_REQUEST] = "REQUEST", + [PD_DATA_BIST] = "BIST", + [PD_DATA_SINK_CAP] = "SNKCAP", + /* 5-14 Reserved */ + [PD_DATA_VENDOR_DEF] = "VDM", +}; + +static const char * const rev_name[] = { + [PD_REV10] = "1.0", + [PD_REV20] = "2.0", + [PD_REV30] = "3.0", + [3] = "RSVD", +}; + +static const char * const drole_name[] = { + [PD_ROLE_UFP] = "UFP", + [PD_ROLE_DFP] = "DFP", +}; + +static const char * const prole_name[] = { + [PD_ROLE_SINK] = "SNK", + [PD_ROLE_SOURCE] = "SRC", +}; + +static void print_header(const char *prefix, uint16_t header) +{ + int type = PD_HEADER_TYPE(header); + int drole = PD_HEADER_DROLE(header); + int rev = PD_HEADER_REV(header); + int prole = PD_HEADER_PROLE(header); + int id = PD_HEADER_ID(header); + int cnt = PD_HEADER_CNT(header); + int ext = PD_HEADER_EXT(header); + const char *name = cnt ? data_msg_name[type] : ctrl_msg_name[type]; + + ccprints("%s header=0x%x [%s %s %s %s id=%d cnt=%d ext=%d]", + prefix, header, + name, drole_name[drole], rev_name[rev], prole_name[prole], + id, cnt, ext); +} + +int mock_tcpci_wait_for_transmit(enum tcpm_transmit_type tx_type, + enum pd_ctrl_msg_type ctrl_msg, + enum pd_data_msg_type data_msg) +{ + int want_tx_reg = (tx_type == TCPC_TX_SOP_PRIME) ? + TCPC_REG_TRANSMIT_SET_WITHOUT_RETRY(tx_type) : + TCPC_REG_TRANSMIT_SET_WITH_RETRY(tx_type); + uint64_t timeout = get_time().val + 5 * SECOND; + + TEST_EQ(tcpci_regs[TCPC_REG_TRANSMIT].value, 0, "%d"); + while (get_time().val < timeout) { + if (tcpci_regs[TCPC_REG_TRANSMIT].value != 0) { + uint16_t header = UINT16_FROM_BYTE_ARRAY_LE( + tx_buffer, 1); + int type = PD_HEADER_TYPE(header); + int cnt = PD_HEADER_CNT(header); + + TEST_EQ(tcpci_regs[TCPC_REG_TRANSMIT].value, + want_tx_reg, "%d"); + if (ctrl_msg != 0) { + TEST_EQ(ctrl_msg, type, "%d"); + TEST_EQ(cnt, 0, "%d"); + } else { + TEST_EQ(data_msg, type, "%d"); + TEST_GE(cnt, 1, "%d"); + } + tcpci_regs[TCPC_REG_TRANSMIT].value = 0; + return EC_SUCCESS; + } + task_wait_event(5 * MSEC); + } + TEST_ASSERT(0); + return EC_ERROR_UNKNOWN; +} + +void mock_tcpci_receive(enum pd_msg_type sop, uint16_t header, + uint32_t *payload) +{ + int i; + + rx_buffer[0] = 3 + (PD_HEADER_CNT(header) * 4); + rx_buffer[1] = sop; + rx_buffer[2] = header & 0xFF; + rx_buffer[3] = (header >> 8) & 0xFF; + + if (rx_buffer[0] >= BUFFER_SIZE) { + ccprints("ERROR: rx too large"); + return; + } + + for (i = 4; i < rx_buffer[0]; i += 4) { + rx_buffer[i] = *payload & 0xFF; + rx_buffer[i+1] = (*payload >> 8) & 0xFF; + rx_buffer[i+2] = (*payload >> 16) & 0xFF; + rx_buffer[i+3] = (*payload >> 24) & 0xFF; + payload++; + } + + rx_pos = 0; +} + void mock_tcpci_reset(void) { int i; @@ -93,23 +234,71 @@ int tcpci_i2c_xfer(int port, uint16_t slave_addr_flags, return EC_ERROR_UNKNOWN; } + if (rx_pos > 0) { + if (rx_pos + in_size > rx_buffer[0] + 1) { + ccprints("ERROR: rx in_size"); + return EC_ERROR_UNKNOWN; + } + memcpy(in, rx_buffer + rx_pos, in_size); + rx_pos += in_size; + if (rx_pos == rx_buffer[0] + 1) { + print_header("RX", UINT16_FROM_BYTE_ARRAY_LE( + rx_buffer, 2)); + rx_pos = -1; + } + return EC_SUCCESS; + } + if (out_size == 0) { ccprints("ERROR: out_size == 0"); return EC_ERROR_UNKNOWN; } + if (tx_pos != -1) { + if (tx_pos + out_size > BUFFER_SIZE) { + ccprints("ERROR: tx out_size"); + return EC_ERROR_UNKNOWN; + } + memcpy(tx_buffer + tx_pos, out, out_size); + tx_pos += out_size; + if (tx_pos > 0 && tx_pos == tx_buffer[0] + 1) { + print_header("TX", UINT16_FROM_BYTE_ARRAY_LE( + tx_buffer, 1)); + tx_pos = -1; + } + return EC_SUCCESS; + } 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 (reg->offset == TCPC_REG_TX_BUFFER) { + if (tx_pos != -1) { + ccprints("ERROR: TCPC_REG_TX_BUFFER not ready"); + return EC_ERROR_UNKNOWN; + } + tx_pos = 0; + if (out_size != 1) { + ccprints("ERROR: TCPC_REG_TX_BUFFER out_size != 1"); + return EC_ERROR_UNKNOWN; + } + } else if (reg->offset == TCPC_REG_RX_BUFFER) { + if (rx_pos != 0) { + ccprints("ERROR: TCPC_REG_RX_BUFFER not ready"); + return EC_ERROR_UNKNOWN; + } + if (in_size > BUFFER_SIZE || in_size > rx_buffer[0]) { + ccprints("ERROR: TCPC_REG_RX_BUFFER in_size"); + return EC_ERROR_UNKNOWN; + } + memcpy(in, rx_buffer, in_size); + rx_pos += in_size; + } else if (out_size == 1) { if (in_size != reg->size) { - ccprints("ERROR: in_size != %d", reg->size); + ccprints("ERROR: %s in_size %d != %d", reg->name, + in_size, 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) { @@ -134,7 +323,10 @@ int tcpci_i2c_xfer(int port, uint16_t slave_addr_flags, ccprints("%s TCPCI write %s = 0x%x", task_get_name(task_get_current()), reg->name, value); - reg->value = value; + if (reg->offset == TCPC_REG_ALERT) + reg->value &= ~value; + else + reg->value = value; } return EC_SUCCESS; } diff --git a/common/usbc/usbc_task.c b/common/usbc/usbc_task.c index be7182f3b7..54a1f601ba 100644 --- a/common/usbc/usbc_task.c +++ b/common/usbc/usbc_task.c @@ -159,6 +159,7 @@ static void pd_task_init(int port) { if (IS_ENABLED(CONFIG_USB_TYPEC_SM)) tc_state_init(port); + paused[port] = 0; /* * Since most boards configure the TCPC interrupt as edge diff --git a/include/mock/tcpci_i2c_mock.h b/include/mock/tcpci_i2c_mock.h index 87f163836c..06cb0ca5f4 100644 --- a/include/mock/tcpci_i2c_mock.h +++ b/include/mock/tcpci_i2c_mock.h @@ -4,6 +4,7 @@ */ #include "common.h" +#include "usb_pd.h" #define MOCK_TCPCI_I2C_ADDR_FLAGS 0x99 @@ -12,3 +13,10 @@ void mock_tcpci_reset(void); void mock_tcpci_set_reg(int reg, uint16_t value); uint16_t mock_tcpci_get_reg(int reg_offset); + +int mock_tcpci_wait_for_transmit(enum tcpm_transmit_type tx_type, + enum pd_ctrl_msg_type ctrl_msg, + enum pd_data_msg_type data_msg); + +void mock_tcpci_receive(enum pd_msg_type sop, uint16_t header, + uint32_t *payload); diff --git a/test/test_config.h b/test/test_config.h index 00cf881e4c..5f52e45952 100644 --- a/test/test_config.h +++ b/test/test_config.h @@ -425,6 +425,7 @@ int ncp15wb_calculate_temp(uint16_t adc); #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 @@ -442,6 +443,8 @@ int ncp15wb_calculate_temp(uint16_t adc); #define CONFIG_I2C #define CONFIG_I2C_MASTER #define I2C_PORT_HOST_TCPC 0 +#define CONFIG_USB_PD_DEBUG_LEVEL 3 +#define CONFIG_USB_PD_EXTENDED_MESSAGES #endif #ifdef TEST_USB_PD_INT diff --git a/test/usb_tcpmv2_tcpci.c b/test/usb_tcpmv2_tcpci.c index cc8bf3026a..84bedd3e66 100644 --- a/test/usb_tcpmv2_tcpci.c +++ b/test/usb_tcpmv2_tcpci.c @@ -68,6 +68,11 @@ const struct svdm_response svdm_rsp = { .modes = NULL, }; +bool vboot_allow_usb_pd(void) +{ + return 1; +} + int pd_check_vconn_swap(int port) { return 1; @@ -93,7 +98,7 @@ const struct usb_mux usb_muxes[CONFIG_USB_PD_PORT_MAX_COUNT] = { } }; -__maybe_unused static int test_connect_as_sink(void) +__maybe_unused static int test_connect_as_nonpd_sink(void) { task_wait_event(10 * SECOND); @@ -136,6 +141,97 @@ __maybe_unused static int test_startup_and_resume(void) return EC_SUCCESS; } + +__maybe_unused static int test_connect_as_pd3_source(void) +{ + int rx_id = 0; + uint32_t rdo = RDO_FIXED(1, 500, 500, 0); + + /* DRP auto-toggling with AP in S0, source enabled. */ + TEST_EQ(test_startup_and_resume(), EC_SUCCESS, "%d"); + + /* + * PROC.PD.E1. Bring-up procedure for DFP(Source) UUT: + * a) The test starts in a disconnected state. + */ + mock_tcpci_set_reg(TCPC_REG_EXT_STATUS, TCPC_REG_EXT_STATUS_SAFE0V); + mock_set_alert(TCPC_REG_ALERT_EXT_STATUS); + task_wait_event(10 * SECOND); + + /* + * b) The Tester applies Rd and waits for Vbus for tNoResponse max. + */ + mock_set_cc(MOCK_CC_WE_ARE_SRC, MOCK_CC_SRC_OPEN, MOCK_CC_SRC_RD); + mock_set_alert(TCPC_REG_ALERT_CC_STATUS); + + /* + * c) The Tester waits for Source_Capabilities for tNoResponse max. + */ + TEST_EQ(mock_tcpci_wait_for_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. + */ + mock_tcpci_receive(PD_MSG_SOP, + PD_HEADER(PD_DATA_REQUEST, PD_ROLE_SINK, + PD_ROLE_UFP, rx_id, + 1, PD_REV30, 0), + &rdo); + mock_set_alert(TCPC_REG_ALERT_RX_STATUS); + TEST_EQ(mock_tcpci_wait_for_transmit( + TCPC_TX_SOP, PD_CTRL_ACCEPT, 0), EC_SUCCESS, "%d"); + mock_set_alert(TCPC_REG_ALERT_TX_SUCCESS); + /* + * f) The Tester waits for PS_RDY for tPSSourceOn max. + */ + TEST_EQ(mock_tcpci_wait_for_transmit( + TCPC_TX_SOP, PD_CTRL_PS_RDY, 0), EC_SUCCESS, "%d"); + mock_set_alert(TCPC_REG_ALERT_TX_SUCCESS); + + /* + * PROC.PD.E3. Wait to Start AMS for DFP(Source) UUT: + * a) The Tester keeps monitoring the Rp value and if the UUT doesn't + * set the value to SinkTXOK if it doesn't have anything to send in 1s, + * the test fails. During this period, the Tester replies any message + * sent from the UUT with a proper response. + */ + TEST_EQ(mock_tcpci_wait_for_transmit( + TCPC_TX_SOP_PRIME, 0, PD_DATA_VENDOR_DEF), EC_SUCCESS, "%d"); + mock_set_alert(TCPC_REG_ALERT_TX_SUCCESS); + task_wait_event(10 * MSEC); + mock_tcpci_receive(PD_MSG_SOP_PRIME, + PD_HEADER(PD_CTRL_NOT_SUPPORTED, PD_PLUG_FROM_CABLE, + PD_ROLE_UFP, 1, + 0, PD_REV30, 0), + NULL); + mock_set_alert(TCPC_REG_ALERT_RX_STATUS); + + TEST_EQ(mock_tcpci_wait_for_transmit( + TCPC_TX_SOP, 0, PD_DATA_VENDOR_DEF), EC_SUCCESS, "%d"); + mock_set_alert(TCPC_REG_ALERT_TX_SUCCESS); + task_wait_event(10 * MSEC); + mock_tcpci_receive(PD_MSG_SOP, + PD_HEADER(PD_CTRL_NOT_SUPPORTED, PD_ROLE_SINK, + PD_ROLE_UFP, 2, + 0, PD_REV30, 0), + NULL); + mock_set_alert(TCPC_REG_ALERT_RX_STATUS); + + task_wait_event(1 * SECOND); + TEST_EQ(tc_is_attached_src(PORT0), true, "%d"); + TEST_EQ(TCPC_REG_ROLE_CTRL_RP(mock_tcpci_get_reg(TCPC_REG_ROLE_CTRL)), + SINK_TX_OK, "%d"); + + task_wait_event(10 * SECOND); + return EC_SUCCESS; +} + void before_test(void) { mock_usb_mux_reset(); @@ -150,8 +246,9 @@ void run_test(int argc, char **argv) { test_reset(); - RUN_TEST(test_connect_as_sink); + RUN_TEST(test_connect_as_nonpd_sink); RUN_TEST(test_startup_and_resume); + RUN_TEST(test_connect_as_pd3_source); test_print_result(); } |