summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/mock/tcpci_i2c_mock.c214
-rw-r--r--common/usbc/usbc_task.c1
-rw-r--r--include/mock/tcpci_i2c_mock.h8
-rw-r--r--test/test_config.h3
-rw-r--r--test/usb_tcpmv2_tcpci.c101
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();
}