diff options
author | Sam Hurst <shurst@google.com> | 2018-09-13 09:27:08 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2019-04-08 22:30:19 -0700 |
commit | 0fe6147a9d8d9feef5049aa6c6c4a6ad30d12b26 (patch) | |
tree | 05d4509bcfe68a248ec3fa58168f3de2536c2d9c /test/usb_typec_ctvpd.c | |
parent | e097feb8b2db20cd2435a483517356defa222db1 (diff) | |
download | chrome-ec-0fe6147a9d8d9feef5049aa6c6c4a6ad30d12b26.tar.gz |
chocodile_vpdmcu: Firmware for chocodile mcu
Implement Chocodile Charge-Through Vconn Powered firmware for mcu
using new Type-C/PD State machine stack.
BUG=b:115626873
BRANCH=none
TEST=manual
Charge-Through was tested on an Atlas running a DRP USB-C/PD state
machine with CTUnattached.SNK and CTAttached.SNK states.
Signed-off-by: Sam Hurst <shurst@chromium.org>
Change-Id: I847f1bcd2fc3ce41e66edd133a10c943d5e8c819
Reviewed-on: https://chromium-review.googlesource.com/1225250
Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com>
Tested-by: Sam Hurst <shurst@google.com>
Reviewed-by: Stefan Reinauer <reinauer@google.com>
Diffstat (limited to 'test/usb_typec_ctvpd.c')
-rw-r--r-- | test/usb_typec_ctvpd.c | 1488 |
1 files changed, 1488 insertions, 0 deletions
diff --git a/test/usb_typec_ctvpd.c b/test/usb_typec_ctvpd.c new file mode 100644 index 0000000000..19fbfa1b8a --- /dev/null +++ b/test/usb_typec_ctvpd.c @@ -0,0 +1,1488 @@ +/* Copyright 2019 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. + * + * Test USB Type-C VPD and CTVPD module. + */ +#include "common.h" +#include "crc.h" +#include "task.h" +#include "test_util.h" +#include "timer.h" +#include "usb_pd.h" +#include "usb_sm.h" +#include "usb_tc_sm.h" +#include "util.h" +#include "usb_pd_tcpm.h" +#include "usb_pd_test_util.h" +#include "vpd_api.h" + +#define PORT0 0 + +enum cc_type {CC1, CC2}; +enum vbus_type {VBUS_0 = 0, VBUS_5 = 5000}; +enum vconn_type {VCONN_0 = 0, VCONN_3 = 3000, VCONN_5 = 5000}; +enum snk_con_voltage_type {SRC_CON_DEF, SRC_CON_1_5, SRC_CON_3_0}; + +struct pd_port_t { + int host_mode; + int has_vbus; + int msg_tx_id; + int msg_rx_id; + int polarity; + int partner_role; /* -1 for none */ + int partner_polarity; + int rev; +} pd_port[CONFIG_USB_PD_PORT_COUNT]; + +uint64_t wait_for_state_change(int port, uint64_t timeout) +{ + uint64_t start; + uint64_t wait; + uint32_t state = get_typec_state_id(port); + + task_wake(PD_PORT_TO_TASK_ID(port)); + + wait = get_time().val + timeout; + start = get_time().val; + while (get_typec_state_id(port) == state && get_time().val < wait) + task_wait_event(5 * MSEC); + + return get_time().val - start; +} + +#if defined(TEST_USB_TYPEC_CTVPD) +static int ct_connect_sink(enum cc_type cc, enum snk_con_voltage_type v) +{ + int ret; + + switch (v) { + case SRC_CON_DEF: + ret = (cc) ? mock_set_cc2_rp3a0_rd_l(PD_SRC_DEF_RD_THRESH_MV) : + mock_set_cc1_rp3a0_rd_l(PD_SRC_DEF_RD_THRESH_MV); + break; + case SRC_CON_1_5: + ret = (cc) ? mock_set_cc2_rp3a0_rd_l(PD_SRC_1_5_RD_THRESH_MV) : + mock_set_cc1_rp3a0_rd_l(PD_SRC_1_5_RD_THRESH_MV); + break; + case SRC_CON_3_0: + ret = (cc) ? mock_set_cc2_rp3a0_rd_l(PD_SRC_3_0_RD_THRESH_MV) : + mock_set_cc1_rp3a0_rd_l(PD_SRC_3_0_RD_THRESH_MV); + break; + default: + ret = 0; + } + + return ret; +} + +static int ct_disconnect_sink(void) +{ + int r1; + int r2; + + r1 = mock_set_cc1_rp3a0_rd_l(PD_SRC_DEF_VNC_MV); + r2 = mock_set_cc2_rp3a0_rd_l(PD_SRC_DEF_VNC_MV); + + return r1 & r2; +} + +static int ct_connect_source(enum cc_type cc, enum vbus_type vbus) +{ + mock_set_ct_vbus(vbus); + return (cc) ? mock_set_cc2_rpusb_odh(PD_SNK_VA_MV) : + mock_set_cc1_rpusb_odh(PD_SNK_VA_MV); +} + +static int ct_disconnect_source(void) +{ + int r1; + int r2; + + mock_set_ct_vbus(VBUS_0); + r1 = mock_set_cc1_rpusb_odh(0); + r2 = mock_set_cc2_rpusb_odh(0); + + return r1 & r2; +} +#endif + +static void host_disconnect_source(void) +{ + mock_set_host_vbus(VBUS_0); + mock_set_host_cc_source_voltage(0); + mock_set_host_cc_sink_voltage(0); +} + +static void host_connect_source(enum vbus_type vbus) +{ + mock_set_host_vbus(vbus); + mock_set_host_cc_source_voltage(PD_SNK_VA_MV); +} + +#if defined(TEST_USB_TYPEC_CTVPD) +static void host_connect_sink(enum snk_con_voltage_type v) +{ + switch (v) { + case SRC_CON_DEF: + mock_set_host_cc_sink_voltage(PD_SRC_DEF_RD_THRESH_MV); + break; + case SRC_CON_1_5: + mock_set_host_cc_sink_voltage(PD_SRC_1_5_RD_THRESH_MV); + break; + case SRC_CON_3_0: + mock_set_host_cc_sink_voltage(PD_SRC_3_0_RD_THRESH_MV); + break; + } +} +#endif + +static void init_port(int port) +{ + pd_port[port].polarity = 0; + pd_port[port].rev = PD_REV30; + pd_port[port].msg_tx_id = 0; + pd_port[port].msg_rx_id = 0; +} + +static int check_host_ra_rd(void) +{ + /* Make sure CC_RP3A0_RD_L is configured as GPO */ + if (mock_get_cfg_cc_rp3a0_rd_l() != PIN_GPO) + return 0; + + /* Make sure CC_RP3A0_RD_L is asserted low */ + if (mock_get_cc_rp3a0_rd_l() != 0) + return 0; + + /* Make sure VPDMCU_CC_EN is enabled */ + if (mock_get_mcu_cc_en() != 1) + return 0; + + /* Make sure CC_VPDMCU is configured as ADC */ + if (mock_get_cfg_cc_vpdmcu() != PIN_ADC) + return 0; + + /* Make sure CC_DB_EN_OD is HZ */ + if (mock_get_cc_db_en_od() != GPO_HZ) + return 0; + + return 1; +} + +static int check_host_rd(void) +{ + /* Make sure CC_RP3A0_RD_L is configured as GPO */ + if (mock_get_cfg_cc_rp3a0_rd_l() != PIN_GPO) + return 0; + + /* Make sure CC_RP3A0_RD_L is asserted low */ + if (mock_get_cc_rp3a0_rd_l() != 0) + return 0; + + /* Make sure VPDMCU_CC_EN is enabled */ + if (mock_get_mcu_cc_en() != 1) + return 0; + + /* Make sure CC_VPDMCU is configured as ADC */ + if (mock_get_cfg_cc_vpdmcu() != PIN_ADC) + return 0; + + /* Make sure CC_DB_EN_OD is LOW */ + if (mock_get_cc_db_en_od() != GPO_LOW) + return 0; + + return 1; +} + +#if defined(TEST_USB_TYPEC_CTVPD) +static int check_host_rp3a0(void) +{ + /* Make sure CC_RP3A0_RD_L is asserted high */ + if (mock_get_cc_rp3a0_rd_l() != 1) + return 0; + + return 1; +} + +static int check_host_rpusb(void) +{ + /* Make sure CC_RPUSB_ODH is asserted high */ + if (mock_get_cc_rpusb_odh() != 1) + return 0; + + /* Make sure CC_RP3A0_RD_L is configured as comparator */ + if (mock_get_cfg_cc_rp3a0_rd_l() != PIN_CMP) + return 0; + + return 1; +} + +static int check_host_cc_open(void) +{ + /* Make sure CC_RPUSB_ODH is hi-z */ + if (mock_get_cc_rpusb_odh() != GPO_HZ) + return 0; + + /* Make sure CC_RP3A0_RD_L is set to comparitor */ + if (mock_get_cfg_cc_rp3a0_rd_l() != PIN_CMP) + return 0; + + /* Make sure cc_db_en_od is set low */ + if (mock_get_cc_db_en_od() != GPO_LOW) + return 0; + + return 1; +} + +static int check_ct_ccs_hz(void) +{ + return (mock_get_ct_rd() == GPO_HIGH); +} + +static int check_ct_ccs_rd(void) +{ + return (mock_get_ct_rd() == GPO_LOW); +} + +static int check_ct_ccs_cc1_rpusb(void) +{ + return (mock_get_ct_cc1_rpusb() == 1); +} +#endif + +void inc_tx_id(int port) +{ + pd_port[port].msg_tx_id = (pd_port[port].msg_tx_id + 1) % 7; +} + +void inc_rx_id(int port) +{ + pd_port[port].msg_rx_id = (pd_port[port].msg_rx_id + 1) % 7; +} + +static int verify_goodcrc(int port, int role, int id) +{ + return pd_test_tx_msg_verify_sop_prime(port) && + pd_test_tx_msg_verify_short(port, PD_HEADER(PD_CTRL_GOOD_CRC, + role, role, id, 0, 0, 0)) && + pd_test_tx_msg_verify_crc(port) && + pd_test_tx_msg_verify_eop(port); +} + +static void simulate_rx_msg(int port, uint16_t header, int cnt, + const uint32_t *data) +{ + int i; + + pd_test_rx_set_preamble(port, 1); + pd_test_rx_msg_append_sop_prime(port); + pd_test_rx_msg_append_short(port, header); + + crc32_init(); + crc32_hash16(header); + + for (i = 0; i < cnt; ++i) { + pd_test_rx_msg_append_word(port, data[i]); + crc32_hash32(data[i]); + } + + pd_test_rx_msg_append_word(port, crc32_result()); + + pd_test_rx_msg_append_eop(port); + pd_test_rx_msg_append_last_edge(port); + + pd_simulate_rx(port); +} + +static void simulate_goodcrc(int port, int role, int id) +{ + simulate_rx_msg(port, PD_HEADER(PD_CTRL_GOOD_CRC, role, role, id, 0, + pd_port[port].rev, 0), 0, NULL); +} + +static void simulate_discovery_identity(int port) +{ + uint16_t header = PD_HEADER(PD_DATA_VENDOR_DEF, PD_ROLE_SOURCE, + 0, pd_port[port].msg_rx_id, + 1, pd_port[port].rev, 0); + uint32_t msg = VDO(USB_SID_PD, + 1, /* Structured VDM */ + VDO_SVDM_VERS(1) | + VDO_CMDT(CMDT_INIT) | + CMD_DISCOVER_IDENT); + + simulate_rx_msg(port, header, 1, (const uint32_t *)&msg); +} + +static int test_vpd_host_src_detection(void) +{ + int port = PORT0; + + mock_set_vconn(VCONN_0); + host_disconnect_source(); + + task_wake(PD_PORT_TO_TASK_ID(port)); + task_wait_event(40 * MSEC); + + /* + * TEST: + * Host is configured properly and start state is UNATTACHED_SNK + */ + TEST_ASSERT(check_host_ra_rd()); + TEST_ASSERT(get_typec_state_id(port) == UNATTACHED_SNK); + + /* + * TEST: + * Host PORT Source Connection Detected + */ + + host_connect_source(VBUS_0); + mock_set_vconn(VCONN_0); + + wait_for_state_change(port, 40 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == ATTACH_WAIT_SNK); + + /* + * TEST: + * Host CC debounce in ATTACH_WAIT_SNK state + */ + + host_disconnect_source(); + + task_wake(PD_PORT_TO_TASK_ID(port)); + task_wait_event(5 * MSEC); + + /* + * TEST: + * Host CC debounce in ATTACH_WAIT_SNK state + */ + + host_connect_source(VBUS_0); + mock_set_vconn(VCONN_0); + + task_wake(PD_PORT_TO_TASK_ID(port)); + task_wait_event(50 * MSEC); + + /* + * TEST: + * Host Port Connection Removed + */ + host_disconnect_source(); + + wait_for_state_change(port, 40 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == UNATTACHED_SNK); + + return EC_SUCCESS; +} + +static int test_vpd_host_src_detection_vbus(void) +{ + int port = PORT0; + + mock_set_vconn(VCONN_0); + host_disconnect_source(); + + task_wake(PD_PORT_TO_TASK_ID(port)); + task_wait_event(40 * MSEC); + + /* + * TEST: + * Host is configured properly and start state is UNATTACHED_SNK + */ + + TEST_ASSERT(check_host_ra_rd()); + TEST_ASSERT(get_typec_state_id(port) == UNATTACHED_SNK); + + /* + * TEST: + * Host Port Source Connection Detected + */ + + host_connect_source(VBUS_0); + mock_set_vconn(VCONN_0); + + wait_for_state_change(port, 40 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == ATTACH_WAIT_SNK); + + /* + * TEST: + * Host Port Source Detected for tCCDebounce and Host Port VBUS + * Detected. + */ + + host_connect_source(VBUS_5); + + wait_for_state_change(port, PD_T_CC_DEBOUNCE + 10 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == ATTACHED_SNK); + + /* + * TEST: + * Host Port VBUS Removed + */ + + host_connect_source(VBUS_0); + + wait_for_state_change(port, 10 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == UNATTACHED_SNK); + + return EC_SUCCESS; +} + +static int test_vpd_host_src_detection_vconn(void) +{ + int port = PORT0; + + mock_set_vconn(VCONN_0); + host_disconnect_source(); + + task_wake(PD_PORT_TO_TASK_ID(port)); + task_wait_event(40 * MSEC); + + /* + * TEST: + * Host is configured properly and start state is UNATTACHED_SNK + */ + + TEST_ASSERT(check_host_ra_rd()); + TEST_ASSERT(get_typec_state_id(port) == UNATTACHED_SNK); + + /* + * TEST: + * Host Source Connection Detected + */ + + host_connect_source(VBUS_0); + mock_set_vconn(VCONN_0); + + wait_for_state_change(port, 40 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == ATTACH_WAIT_SNK); + + /* + * TEST: + * Host Port Source Detected for tCCDebounce and VCONN Detected + */ + + host_connect_source(VBUS_0); + mock_set_vconn(VCONN_3); + + wait_for_state_change(port, PD_T_CC_DEBOUNCE + 10 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == ATTACHED_SNK); + + /* VCONN was detected. Make sure RA is removed */ + task_wake(PD_PORT_TO_TASK_ID(port)); + task_wait_event(40 * MSEC); + TEST_ASSERT(check_host_rd()); + + /* + * TEST: + * Host Port VCONN Removed + */ + + mock_set_vconn(VCONN_0); + + wait_for_state_change(port, 10 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == UNATTACHED_SNK); + + host_disconnect_source(); + + return EC_SUCCESS; +} + +static int test_vpd_host_src_detection_message_reception(void) +{ + int port = PORT0; + uint32_t expected_vdm_header = VDO(USB_VID_GOOGLE, + 1, /* Structured VDM */ + VDO_SVDM_VERS(1) | + VDO_CMDT(CMDT_RSP_ACK) | + CMD_DISCOVER_IDENT); + uint32_t expected_vdo_id_header = VDO_IDH( + 0, /* Not a USB Host */ + 1, /* Capable of being enumerated as USB Device */ + IDH_PTYPE_VPD, + 0, /* Modal Operation Not Supported */ + USB_VID_GOOGLE); + uint32_t expected_vdo_cert = 0; + uint32_t expected_vdo_product = VDO_PRODUCT( + CONFIG_USB_PID, + USB_BCD_DEVICE); + uint32_t expected_vdo_vpd = VDO_VPD( + VPD_HW_VERSION, + VPD_FW_VERSION, + VPD_MAX_VBUS_20V, + VPD_VBUS_IMP(VPD_VBUS_IMPEDANCE), + VPD_GND_IMP(VPD_GND_IMPEDANCE), +#ifdef CONFIG_USB_TYPEC_CTVPD + VPD_CTS_SUPPORTED +#else + VPD_CTS_NOT_SUPPORTED +#endif + ); + + mock_set_vconn(VCONN_0); + host_disconnect_source(); + + task_wake(PD_PORT_TO_TASK_ID(port)); + task_wait_event(40 * MSEC); + + /* + * TEST: + * Host is configured properly and start state is UNATTACHED_SNK + */ + + TEST_ASSERT(check_host_ra_rd()); + TEST_ASSERT(get_typec_state_id(port) == UNATTACHED_SNK); + + /* + * Transition to ATTACHED_SNK + */ + + host_connect_source(VBUS_5); + + wait_for_state_change(port, 10 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == ATTACH_WAIT_SNK); + + wait_for_state_change(port, PD_T_CC_DEBOUNCE + 20 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == ATTACHED_SNK); + + /* Run state machines to enable rx monitoring */ + task_wake(PD_PORT_TO_TASK_ID(port)); + task_wait_event(30 * MSEC); + + /* + * TEST: + * Reception of Discovery Identity message + */ + + simulate_discovery_identity(port); + task_wait_event(30 * MSEC); + + TEST_ASSERT(verify_goodcrc(port, + PD_ROLE_SINK, pd_port[port].msg_rx_id)); + + task_wake(PD_PORT_TO_TASK_ID(port)); + task_wait_event(30 * MSEC); + inc_rx_id(port); + + /* Test Discover Identity Ack */ + TEST_ASSERT(pd_test_tx_msg_verify_sop_prime(port)); + TEST_ASSERT(pd_test_tx_msg_verify_short(port, + PD_HEADER(PD_DATA_VENDOR_DEF, PD_PLUG_CABLE_VPD, 0, + pd_port[port].msg_tx_id, 5, pd_port[port].rev, 0))); + TEST_ASSERT(pd_test_tx_msg_verify_word(port, expected_vdm_header)); + TEST_ASSERT(pd_test_tx_msg_verify_word(port, expected_vdo_id_header)); + TEST_ASSERT(pd_test_tx_msg_verify_word(port, expected_vdo_cert)); + TEST_ASSERT(pd_test_tx_msg_verify_word(port, expected_vdo_product)); + TEST_ASSERT(pd_test_tx_msg_verify_word(port, expected_vdo_vpd)); + TEST_ASSERT(pd_test_tx_msg_verify_crc(port)); + TEST_ASSERT(pd_test_tx_msg_verify_eop(port)); + + task_wake(PD_PORT_TO_TASK_ID(port)); + task_wait_event(30 * MSEC); + + /* Ack was good. Send GoodCRC */ + simulate_goodcrc(port, PD_ROLE_SOURCE, pd_port[port].msg_tx_id); + task_wake(PD_PORT_TO_TASK_ID(port)); + task_wait_event(30 * MSEC); + inc_tx_id(port); + + /* + * TEST: + * Host Port VBUS Removed + */ + + host_connect_source(VBUS_0); + + wait_for_state_change(port, 10 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == UNATTACHED_SNK); + + host_disconnect_source(); + + return EC_SUCCESS; +} + +#if defined(TEST_USB_TYPEC_CTVPD) +static int test_ctvpd_behavior_case1(void) +{ + int port = PORT0; + + mock_set_vconn(VCONN_0); + host_disconnect_source(); + TEST_ASSERT(ct_disconnect_source()); + TEST_ASSERT(ct_disconnect_sink()); + + task_wake(PD_PORT_TO_TASK_ID(port)); + task_wait_event(40 * MSEC); + + /* + * CASE 1: The following tests the behavior when a DRP is connected to a + * Charge-Through VCONN-Powered USB Device (abbreviated CTVPD), + * with no Power Source attached to the ChargeThrough port on + * the CTVPD. + */ + + /* 1. DRP and CTVPD are both in the unattached state */ + TEST_ASSERT(get_typec_state_id(port) == UNATTACHED_SNK); + + /* + * a. DRP alternates between Unattached.SRC and Unattached.SNK + * + * b. CTVPD has applied Rd on its Charge-Through port’s CC1 and CC2 + * pins and Rd on the Host-side port’s CC pin + */ + TEST_ASSERT(check_host_ra_rd()); + TEST_ASSERT(check_ct_ccs_rd()); + + /* + * 2. DRP transitions from Unattached.SRC to AttachWait.SRC to + * Attached.SRC + * + * a. DRP in Unattached.SRC detects the CC pull-down of CTVPD which + * is in Unattached.SNK and DRP enters AttachWait.SRC + * b. DRP in AttachWait.SRC detects that pull down on CC persists for + * tCCDebounce, enters Attached.SRC and turns on VBUS and VCONN + */ + host_connect_source(VBUS_5); + mock_set_vconn(VCONN_3); + + /* + * 3. CTVPD transitions from Unattached.SNK to Attached.SNK through + * AttachWait.SNK. + * + * a. CTVPD detects the host-side CC pull-up of the DRP and CTVPD + * enters AttachWait.SNK + * b. CTVPD in AttachWait.SNK detects that pull up on the Host-side + * port’s CC persists for tCCDebounce, VCONN present and enters + * Attached.SNK + * c. CTVPD present a high-impedance to ground (above zOPEN) on its + * Charge-Through port’s CC1 and CC2 pins + */ + wait_for_state_change(port, 40 * MSEC); + TEST_ASSERT(get_typec_state_id(port) == ATTACH_WAIT_SNK); + + wait_for_state_change(port, PD_T_CC_DEBOUNCE + 40 * MSEC); + TEST_ASSERT(get_typec_state_id(port) == ATTACHED_SNK); + TEST_ASSERT(check_ct_ccs_hz()); + + /* + * 4. While DRP and CTVPD are in their respective attached states, DRP + * discovers the ChargeThrough CTVPD and transitions to + * CTUnattached.SNK + * + * a. DRP (as Source) queries the device identity via USB PD + * (Device Identity Command) on SOP’. + * b. CTVPD responds on SOP’, advertising that it is a + * Charge-Through VCONN-Powered USB Device + * c. DRP (as Source) removes VBUS + * d. DRP (as Source) changes its Rp to a Rd + * e. DRP (as Sink) continues to provide VCONN and enters + * CTUnattached.SNK + */ + host_disconnect_source(); + + /* + * 5. CTVPD transitions to CTUnattached.VPD + * + * a. CTVPD detects VBUS removal, VCONN presence, the low Host-side + * CC pin and enters CTUnattached.VPD + * b. CTVPD changes its host-side Rd to a Rp advertising 3.0 A + * c. CTVPD isolates itself from VBUS + * d. CTVPD apply Rd on its Charge-Through port’s CC1 and CC2 pins + */ + wait_for_state_change(port, 40 * MSEC); + TEST_ASSERT(get_typec_state_id(port) == CTUNATTACHED_VPD); + + /* + * 6. While the CTVPD in CTUnattached.VPD state and the DRP in + * CTUnattached.SNK state: + * + * a. CTVPD monitors Charge-Though CC pins for a source or sink; + * when a Power Source attach is detected, enters + * CTAttachWait.VPD; when a sink is detected, enters + * CTAttachWait.Unsupported + * b. CTVPD monitors VCONN for Host detach and when detected, enters + * Unattached.SNK + * c. DRP monitors VBUS and CC for CTVPD detach for tVPDDetach and + * when detected, enters Unattached.SNK + * d. DRP monitors VBUS for Power Source attach and when detected, + * enters CTAttached.SNK + */ + /* Attach Power Source */ + TEST_ASSERT(ct_connect_source(CC2, VBUS_0)); + + wait_for_state_change(port, 40 * MSEC); + TEST_ASSERT(get_typec_state_id(port) == CTATTACH_WAIT_VPD); + + /* Remove Power Source */ + TEST_ASSERT(ct_disconnect_source()); + + wait_for_state_change(port, 40 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == CTUNATTACHED_VPD); + + /* Attach Sink */ + TEST_ASSERT(ct_connect_sink(CC1, SRC_CON_DEF)); + + wait_for_state_change(port, PD_T_DRP_SNK); + + TEST_ASSERT(get_typec_state_id(port) == CTUNATTACHED_UNSUPPORTED); + + wait_for_state_change(port, 40 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == CTATTACH_WAIT_UNSUPPORTED); + + /* Remove VCONN (Host detach) */ + mock_set_vconn(VCONN_0); + + wait_for_state_change(port, 40 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == UNATTACHED_SNK); + + return EC_SUCCESS; +} + +static int test_ctvpd_behavior_case2(void) +{ + int port = PORT0; + + mock_set_vconn(VCONN_0); + host_disconnect_source(); + TEST_ASSERT(ct_disconnect_source()); + TEST_ASSERT(ct_disconnect_sink()); + + task_wake(PD_PORT_TO_TASK_ID(port)); + task_wait_event(40 * MSEC); + + /* + * CASE 2: The following tests the behavior when a Power Source is + * connected to a Charge-Through VCONN-Powered USB Device + * (abbreviated CTVPD), with a Host already attached to the + * Host-Side port on the CTVPD. + */ + + /* + * 1. DRP is in CTUnattached.SNK state, CTVPD in CTUnattached.VPD, and + * Power Source in the unattached state + * + * a. CTVPD has applied Rd on the Charge-Through port’s CC1 and CC2 + * pins and Rp termination advertising 3.0 A on the Host-side + * port’s CC pin + */ + TEST_ASSERT(get_typec_state_id(port) == UNATTACHED_SNK); + + host_connect_source(VBUS_5); + mock_set_vconn(VCONN_3); + + wait_for_state_change(port, 40 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == ATTACH_WAIT_SNK); + + wait_for_state_change(port, PD_T_CC_DEBOUNCE + 40 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == ATTACHED_SNK); + + /* Remove Host CC */ + mock_set_host_cc_source_voltage(0); + + wait_for_state_change(port, 40 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == CTUNATTACHED_VPD); + TEST_ASSERT(check_ct_ccs_rd()); + TEST_ASSERT(check_host_rp3a0()); + + /* + * 2. Power Source transitions from Unattached.SRC to Attached.SRC + * through AttachWait.SRC. + * + * a. Power Source detects the CC pull-down of the CTVPD and enters + * AttachWait.SRC + * b. Power Source in AttachWait.SRC detects that pull down on CC + * persists for tCCDebounce, enters Attached.SRC and turns on + * VBUS + */ + TEST_ASSERT(ct_connect_source(CC2, VBUS_5)); + + /* + * 3. CTVPD transitions from CTUnattached.VPD through CTAttachWait.VPD + * to CTAttached.VPD + * + * a. CTVPD detects the Source’s Rp on one of its Charge-Through CC + * pins, and transitions to CTAttachWait.VPD + * b. CTVPD finishes any active USB PD communication on SOP’ and + * ceases to respond to SOP’ queries + * c. CTVPD in CTAttachWait.VPD detects that the pull up on + * Charge-Through CC pin persists for tCCDebounce, detects VBUS + * and enters CTAttached.VPD + * d. CTVPD connects the active Charge-Through CC pin to the + * Host-side port’s CC pin + * e. CTVPD disables its Rp termination advertising 3.0 A on the + * Host-side port’s CC pin + * f. CTVPD disables its Rd on the Charge-Through CC pins + * g. CTVPD connects VBUS from the Charge-Through side to the Host + * side + */ + + wait_for_state_change(port, 40 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == CTATTACH_WAIT_VPD); + + wait_for_state_change(port, PD_T_CC_DEBOUNCE + 40 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == CTATTACHED_VPD); + TEST_ASSERT(moch_get_ct_cl_sel() == CT_CC2); + TEST_ASSERT(check_host_cc_open()); + TEST_ASSERT(check_ct_ccs_hz()); + TEST_ASSERT(mock_get_vbus_pass_en()); + + /* + * 4. DRP (as Sink) transitions to CTAttached.SNK + * a. DRP (as Sink) detects VBUS, monitors vRd for available current + * and enter CTAttached.SNK + */ + + /* + * 5. While the devices are all in their respective attached states: + * a. CTVPD monitors VCONN for DRP detach and when detected, + * enters CTDisabled.VPD + * b. CTVPD monitors VBUS and CC for Power Source detach and when + * detected, enters CTUnattached.VPD within tVPDCTDD + * c. DRP (as Sink) monitors VBUS for Charge-Through Power Source + * detach and when detected, enters CTUnattached.SNK + * d. DRP (as Sink) monitors VBUS and CC for CTVPD detach and when + * detected, enters Unattached.SNK (and resumes toggling between + * Unattached.SNK and Unattached.SRC) + * e. Power Source monitors CC for CTVPD detach and when detected, + * enters Unattached.SRC + */ + mock_set_vconn(VCONN_0); + + wait_for_state_change(port, 40 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == CTDISABLED_VPD); + + return EC_SUCCESS; +} + +static int test_ctvpd_behavior_case3(void) +{ + int port = PORT0; + + mock_set_vconn(VCONN_0); + host_disconnect_source(); + TEST_ASSERT(ct_disconnect_source()); + TEST_ASSERT(ct_disconnect_sink()); + + task_wake(PD_PORT_TO_TASK_ID(port)); + task_wait_event(40 * MSEC); + + /* + * CASE 3: The following describes the behavior when a Power Source is + * connected to a ChargeThrough VCONN-Powered USB Device + * (abbreviated CTVPD), with no Host attached to the Host-side + * port on the CTVPD. + */ + + /* + * 1. CTVPD and Power Source are both in the unattached state + * a. CTVPD has applied Rd on the Charge-Through port’s CC1 and CC2 + * pins and Rd on the Host-side port’s CC pin + */ + TEST_ASSERT(get_typec_state_id(port) == UNATTACHED_SNK); + + TEST_ASSERT(check_ct_ccs_rd()); + TEST_ASSERT(check_host_ra_rd()); + TEST_ASSERT(ct_connect_source(CC2, VBUS_5)); + + /* + * 2. Power Source transitions from Unattached.SRC to Attached.SRC + * through AttachWait.SRC. + * + * a. Power Source detects the CC pull-down of the CTVPD and enters + * AttachWait.SRC + * b. Power Source in AttachWait.SRC detects that pull down on CC + * persists for tCCDebounce, enters Attached.SRC and turns on + * VBUS + */ + + /* 3. CTVPD alternates between Unattached.SNk and Unattached.SRC + * + * a. CTVPD detects the Source’s Rp on one of its Charge-Through CC + * pins, detects VBUS for tCCDebounce and starts alternating + * between Unattached.SRC and Unattached.SNK + */ + wait_for_state_change(port, PD_T_CC_DEBOUNCE + 40 * MSEC); + TEST_ASSERT(get_typec_state_id(port) == UNATTACHED_SRC); + + /* + * 4. While the CTVPD alternates between Unattached.SRC and + * Unattached.SNK state and the Power Source in Attached.SRC state: + * + * a. CTVPD monitors the Host-side port’s CC pin for device attach + * and when detected, enters AttachWait.SRC + * b. CTVPD monitors VBUS for Power Source detach and when detected, + * enters Unattached.SNK + * c. Power Source monitors CC for CTVPD detach and when detected, + * enters Unattached.SRC + */ + + /* Attached host side device */ + host_connect_sink(SRC_CON_DEF); + + wait_for_state_change(port, 40 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == ATTACH_WAIT_SRC); + + /* Remove VBUS */ + TEST_ASSERT(ct_disconnect_source()); + + wait_for_state_change(port, 40 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == UNATTACHED_SNK); + + return EC_SUCCESS; +} + +static int test_ctvpd_behavior_case4(void) +{ + int port = PORT0; + uint32_t expected_vdm_header = VDO(USB_VID_GOOGLE, + 1, /* Structured VDM */ + VDO_SVDM_VERS(1) | + VDO_CMDT(CMDT_RSP_ACK) | + CMD_DISCOVER_IDENT); + uint32_t expected_vdo_id_header = VDO_IDH( + 0, /* Not a USB Host */ + 1, /* Capable of being enumerated as USB Device */ + IDH_PTYPE_VPD, + 0, /* Modal Operation Not Supported */ + USB_VID_GOOGLE); + uint32_t expected_vdo_cert = 0; + uint32_t expected_vdo_product = VDO_PRODUCT( + CONFIG_USB_PID, + USB_BCD_DEVICE); + uint32_t expected_vdo_vpd = VDO_VPD( + VPD_HW_VERSION, + VPD_FW_VERSION, + VPD_MAX_VBUS_20V, + VPD_VBUS_IMP(VPD_VBUS_IMPEDANCE), + VPD_GND_IMP(VPD_GND_IMPEDANCE), + VPD_CTS_SUPPORTED + ); + + init_port(port); + mock_set_vconn(VCONN_0); + host_disconnect_source(); + TEST_ASSERT(ct_disconnect_source()); + TEST_ASSERT(ct_disconnect_sink()); + + task_wake(PD_PORT_TO_TASK_ID(port)); + task_wait_event(40 * MSEC); + + /* + * CASE 4: The following describes the behavior when a DRP is connected + * to a Charge-Through VCONN-Powered USB Device + * (abbreviated CTVPD), with a Power Source already attached to + * the Charge-Through side on the CTVPD. + */ + + /* + * 1. DRP, CTVPD and Sink are all in the unattached state + * + * a. DRP alternates between Unattached.SRC and Unattached.SNK + * b. CTVPD has applied Rd on its Charge-Through port’s CC1 and CC2 + * pins and Rd on the Host-side port’s CC pin + */ + TEST_ASSERT(get_typec_state_id(port) == UNATTACHED_SNK); + + TEST_ASSERT(check_ct_ccs_rd()); + TEST_ASSERT(check_host_ra_rd()); + + /* + * 2. DRP transitions from Unattached.SRC to AttachWait.SRC to + * Attached.SRC + * + * a. DRP in Unattached.SRC detects the CC pull-down of CTVPD which + * is in Unattached.SNK and DRP enters AttachWait.SRC + * b. DRP in AttachWait.SRC detects that pull down on CC persists + * for tCCDebounce, enters Attached.SRC and turns on VBUS and + * VCONN + */ + + host_connect_source(VBUS_5); + mock_set_vconn(VCONN_3); + + /* + * 3. CTVPD transitions from Unattached.SNK to Attached.SNK through + * AttachWait.SNK. + * + * a. CTVPD detects the host-side CC pull-up of the DRP and CTVPD + * enters AttachWait.SNK + * b. CTVPD in AttachWait.SNK detects that pull up on the + * Host-side port’s CC persists for tCCDebounce, VCONN present + * and enters Attached.SNK + * c. CTVPD present a high-impedance to ground (above zOPEN) on its + * Charge-Through port’s CC1 and CC2 pins + */ + + wait_for_state_change(port, 40 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == ATTACH_WAIT_SNK); + + wait_for_state_change(port, PD_T_CC_DEBOUNCE + 40 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == ATTACHED_SNK); + TEST_ASSERT(check_ct_ccs_hz()); + + /* + * 4. While DRP and CTVPD are in their respective attached states, DRP + * discovers the ChargeThrough CTVPD and transitions to + * CTUnattached.SNK + * + * a. DRP (as Source) queries the device identity via USB PD + * (Discover Identity Command) on SOP’. + * b. CTVPD responds on SOP’, advertising that it is a + * Charge-Through VCONN-Powered USB Device + * c. DRP (as Source) removes VBUS + * d. DRP (as Source) changes its Rp to a Rd + * e. DRP (as Sink) continues to provide VCONN and enters + * CTUnattached.SNK + */ + + task_wake(PD_PORT_TO_TASK_ID(port)); + task_wait_event(40 * MSEC); + + simulate_discovery_identity(port); + task_wait_event(40 * MSEC); + + TEST_ASSERT(verify_goodcrc(port, + PD_ROLE_SINK, pd_port[port].msg_rx_id)); + + task_wake(PD_PORT_TO_TASK_ID(port)); + task_wait_event(40 * MSEC); + inc_rx_id(port); + + /* Test Discover Identity Ack */ + TEST_ASSERT(pd_test_tx_msg_verify_sop_prime(port)); + TEST_ASSERT(pd_test_tx_msg_verify_short(port, + PD_HEADER(PD_DATA_VENDOR_DEF, PD_PLUG_CABLE_VPD, 0, + pd_port[port].msg_tx_id, 5, pd_port[port].rev, 0))); + TEST_ASSERT(pd_test_tx_msg_verify_word(port, expected_vdm_header)); + TEST_ASSERT(pd_test_tx_msg_verify_word(port, expected_vdo_id_header)); + TEST_ASSERT(pd_test_tx_msg_verify_word(port, expected_vdo_cert)); + TEST_ASSERT(pd_test_tx_msg_verify_word(port, expected_vdo_product)); + TEST_ASSERT(pd_test_tx_msg_verify_word(port, expected_vdo_vpd)); + TEST_ASSERT(pd_test_tx_msg_verify_crc(port)); + TEST_ASSERT(pd_test_tx_msg_verify_eop(port)); + + task_wake(PD_PORT_TO_TASK_ID(port)); + task_wait_event(40 * MSEC); + + /* Ack was good. Send GoodCRC */ + simulate_goodcrc(port, PD_ROLE_SOURCE, pd_port[port].msg_tx_id); + task_wake(PD_PORT_TO_TASK_ID(port)); + task_wait_event(40 * MSEC); + inc_tx_id(port); + + /* + * 5. CTVPD transitions to CTUnattached.VPD + * + * a. CTVPD detects VBUS removal, VCONN presence, the low Host-side + * CC pin and enters CTUnattached.VPD + * b. CTVPD changes its host-side Rd to a Rp termination advertising + * 3.0 A + * c. CTVPD isolates itself from VBUS + * d. CTVPD apply Rd on its Charge-Through port’s CC1 and CC2 pins + */ + host_disconnect_source(); + + wait_for_state_change(port, 40 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == CTUNATTACHED_VPD); + TEST_ASSERT(check_ct_ccs_rd()); + TEST_ASSERT(check_host_rp3a0()); + + /* + * 6. CTVPD alternates between CTUnattached.VPD and + * CTUnattached.Unsupported + */ + wait_for_state_change(port, PD_T_DRP_SRC + 10 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == CTUNATTACHED_UNSUPPORTED); + + wait_for_state_change(port, PD_T_DRP_SRC + 10 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == CTUNATTACHED_VPD); + TEST_ASSERT(ct_connect_source(CC2, VBUS_5)); + + wait_for_state_change(port, 40 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == CTATTACH_WAIT_VPD); + + return EC_SUCCESS; +} + +static int test_ctvpd_behavior_case5(void) +{ + int port = PORT0; + + mock_set_vconn(VCONN_0); + host_disconnect_source(); + TEST_ASSERT(ct_disconnect_source()); + TEST_ASSERT(ct_disconnect_sink()); + + task_wake(PD_PORT_TO_TASK_ID(port)); + task_wait_event(40 * MSEC); + + /* + * CASE 5: The following describes the behavior when a Power Source is + * connected to a ChargeThrough VCONN-Powered USB Device + * (abbreviated CTVPD), with a DRP (with dead battery) attached + * to the Host-side port on the CTVPD. + */ + + /* + * 1. DRP, CTVPD and Power Source are all in the unattached state + * + * a. DRP apply dead battery Rd + * b. CTVPD apply Rd on the Charge-Through port’s CC1 and CC2 pins + * and Rd on the Host-side port’s CC pin + */ + TEST_ASSERT(get_typec_state_id(port) == UNATTACHED_SNK); + + TEST_ASSERT(check_ct_ccs_rd()); + TEST_ASSERT(check_host_ra_rd()); + + /* + * 2. Power Source transitions from Unattached.SRC to Attached.SRC + * through AttachWait.SRC. + * + * a. Power Source detects the CC pull-down of the CTVPD and enters + * AttachWait.SRC + * b. Power Source in AttachWait.SRC detects that pull down on CC + * persists for tCCDebounce, enters Attached.SRC and enable VBUS + */ + TEST_ASSERT(ct_connect_source(CC2, VBUS_5)); + + /* + * 3. CTVPD alternates between Unattached.SNK and Unattached.SRC + * + * a. CTVPD detects the Source’s Rp on one of its Charge-Through CC + * pins, detects VBUS for tCCDebounce and starts alternating + * between Unattached.SRC and Unattached.SNK + */ + + wait_for_state_change(port, PD_T_CC_DEBOUNCE + 40 * MSEC); + TEST_ASSERT(get_typec_state_id(port) == UNATTACHED_SRC); + + /* Connect Host With Dead Battery */ + host_connect_sink(SRC_CON_DEF); + + /* + * 4. CTVPD transitions from Unattached.SRC to Try.SNK through + * AttachWait.SRC + * + * a. CTVPD in Unattached.SRC detects the CC pull-down of DRP which + * is in Unattached.SNK and CTVPD enters AttachWait.SRC + * b. CTVPD in AttachWait.SRC detects that pull down on CC persists + * for tCCDebounce and enters Try.SNK + * c. CTVPD disables Rp termination advertising Default USB Power on + * the Host-side port’s CC + * d. CTVPD enables Rd on the Host-side port’s CC + */ + + wait_for_state_change(port, 40 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == ATTACH_WAIT_SRC); + + wait_for_state_change(port, PD_T_CC_DEBOUNCE + 10 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == TRY_SNK); + TEST_ASSERT(check_host_ra_rd()); + + /* 5. DRP in dead battery condition remains in Unattached.SNK */ + + /* + * 6. CTVPD transitions from Try.SNK to Attached.SRC through + * TryWait.SRC + * + * a. CTVPD didn’t detect the CC pull-up of the DRP for + * tTryDebounce after tDRPTry and enters TryWait.SRC + * b. CTVPD disables Rd on the Host-side port’s CC + * c. CTVPD enables Rp termination advertising Default USB Power on + * the Host-side port’s CC + * d. CTVPD detects the CC pull-down of the DRP for tTryCCDebounce + * and enters Attached.SRC + * e. CTVPD connects VBUS from the Charge-Through side to the Host + * side + */ + wait_for_state_change(port, PD_T_TRY_CC_DEBOUNCE + + PD_T_DRP_TRY + 40 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == TRY_WAIT_SRC); + TEST_ASSERT(check_host_rpusb()); + + wait_for_state_change(port, 40 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == ATTACHED_SRC); + TEST_ASSERT(mock_get_vbus_pass_en()); + + /* + * 7. DRP transitions from Unattached.SNK to Attached.SNK through + * AttachWait.SNK + * + * a. DRP in Unattached.SNK detects the CC pull-up of CTVPD which is + * in Attached.SRC and DRP enters AttachWait.SNK + * b. DRP in AttachWait.SNK detects that pull up on CC persists for + * tCCDebounce, VBUS present and enters Attached.SNK + */ + + /* + * 8. While the devices are all in their respective attached states: + * a. CTVPD monitors the Host-side port’s CC pin for device attach + * and when detected, enters Unattached.SNK + * b. CTVPD monitors VBUS for Power Source detach and when detected, + * enters Unattached.SNK + * c. Power Source monitors CC for CTVPD detach and when detected, + * enters Unattached.SRC + * d. DRP monitors VBUS for CTVPD detach and when detected, enters + * Unattached.SNK + * e. Additionally, the DRP may query the identity of the cable via + * USB PD on SOP’ when it has sufficient battery power and when + * a Charge-Through VPD is identified enters TryWait.SRC if + * implemented, or enters Unattached.SRC if TryWait.SRC is not + * supported + */ + TEST_ASSERT(ct_connect_source(CC2, VBUS_0)); + + wait_for_state_change(port, 40 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == UNATTACHED_SNK); + + return EC_SUCCESS; +} + +static int test_ctvpd_behavior_case6(void) +{ + int port = PORT0; + + mock_set_vconn(VCONN_0); + host_disconnect_source(); + TEST_ASSERT(ct_disconnect_source()); + TEST_ASSERT(ct_disconnect_sink()); + + task_wake(PD_PORT_TO_TASK_ID(port)); + task_wait_event(40 * MSEC); + + /* + * CASE 6: The following describes the behavior when a DRP is connected + * to a Charge-Through VCONN-Powered USB Device + * (abbreviated CTVPD) and a Sink is attached to the + * Charge-Through port on the CTVPD. + */ + + /* + * 1. DRP, CTVPD and Sink are all in the unattached state + * + * a. DRP alternates between Unattached.SRC and Unattached.SNK + * b. CTVPD has applied Rd on its Charge-Through port’s CC1 and CC2 + * pins and Rd on the Host-side port’s CC pin + */ + TEST_ASSERT(get_typec_state_id(port) == UNATTACHED_SNK); + TEST_ASSERT(check_ct_ccs_rd()); + TEST_ASSERT(check_host_ra_rd()); + + /* + * 2. DRP transitions from Unattached.SRC to AttachWait.SRC to + * Attached.SRC + * + * a. DRP in Unattached.SRC detects the CC pull-down of CTVPD which + * is in Unattached.SNK and DRP enters AttachWait.SRC + * b. DRP in AttachWait.SRC detects that pull down on CC persists + * for tCCDebounce, enters Attached.SRC and turns on VBUS and + * VCONN + */ + host_connect_source(VBUS_5); + mock_set_vconn(VCONN_3); + + /* + * 3. CTVPD transitions from Unattached.SNK to Attached.SNK through + * AttachWait.SNK. + * + * a. CTVPD detects the host-side CC pull-up of the DRP and CTVPD + * enters AttachWait.SNK + * b. CTVPD in AttachWait.SNK detects that pull up on the Host-side + * port’s CC persists for tCCDebounce, VCONN present and enters + * Attached.SNK + * c. CTVPD present a high-impedance to ground (above zOPEN) on its + * Charge-Through port’s CC1 and CC2 pins + */ + wait_for_state_change(port, 40 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == ATTACH_WAIT_SNK); + + wait_for_state_change(port, PD_T_CC_DEBOUNCE + 40 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == ATTACHED_SNK); + TEST_ASSERT(check_ct_ccs_hz()); + + /* + * 4. While DRP and CTVPD are in their respective attached states, DRP + * discovers the ChargeThrough CTVPD and transitions to + * CTUnattached.SNK + * + * a. DRP (as Source) queries the device identity via USB PD + * (Discover Identity Command) on SOP’. + * b. CTVPD responds on SOP’, advertising that it is a + * Charge-Through VCONN-Powered USB Device + * c. DRP (as Source) removes VBUS + * d. DRP (as Source) changes its Rp to a Rd + * e. DRP (as Sink) continues to provide VCONN and enters + * CTUnattached.SNK + */ + + host_disconnect_source(); + host_connect_sink(SRC_CON_DEF); + + /* + * 5. CTVPD transitions to CTUnattached.VPD + * + * a. CTVPD detects VBUS removal, VCONN presence, the low Host-side + * CC pin and enters CTUnattached.VPD + * b. CTVPD changes its host-side Rd to a Rp termination advertising + * 3.0 A + * c. CTVPD isolates itself from VBUS + * d. CTVPD apply Rd on its Charge-Through port’s CC1 and CC2 pins + */ + wait_for_state_change(port, 40 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == CTUNATTACHED_VPD); + TEST_ASSERT(check_host_rp3a0()); + TEST_ASSERT(mock_get_vbus_pass_en() == 0); + TEST_ASSERT(check_ct_ccs_rd()); + + /* + * 6. CTVPD alternates between CTUnattached.VPD and + * CTUnattached.Unsupported + * + * a. CTVPD detects SRC.open on its Charge-Through CC pins and + * starts alternating between CTUnattached.VPD and + * CTUnattached.Unsupported + */ + wait_for_state_change(port, PD_T_DRP_SNK + 40 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == CTUNATTACHED_UNSUPPORTED); + + wait_for_state_change(port, PD_T_DRP_SNK + 40 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == CTUNATTACHED_VPD); + + wait_for_state_change(port, PD_T_DRP_SNK + 40 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == CTUNATTACHED_UNSUPPORTED); + + /* + * 7. CTVPD transitions from CTUnattached.Unsupported to CTTry.SNK + * through CTAttachWait.Unsupported + * + * a. CTVPD in CTUnattached.Unsupported detects the CC pull-down of + * the Sink which is in Unattached.SNK and CTVPD enters + * CTAttachWait.Unsupported + * b. CTVPD in CTAttachWait.Unsupported detects that pull down on CC + * persists for tCCDebounce and enters CTTry.SNK + * c. CTVPD disables Rp termination advertising Default USB Power on + * the ChargeThrough port’s CC pins + * d. CTVPD enables Rd on the Charge-Through port’s CC pins + */ + TEST_ASSERT(ct_connect_sink(CC1, SRC_CON_DEF)); + + wait_for_state_change(port, 40 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == CTATTACH_WAIT_UNSUPPORTED); + + wait_for_state_change(port, PD_T_CC_DEBOUNCE + 40 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == CTTRY_SNK); + TEST_ASSERT(check_ct_ccs_rd()); + + /* + * 8. CTVPD transitions from CTTry.SNK to CTAttached.Unsupported + * + * a. CTVPD didn’t detect the CC pull-up of the potential Source + * for tDRPTryWait after tDRPTry and enters + * CTAttached.Unsupported + */ + + wait_for_state_change(port, PD_T_DRP_TRY + PD_T_TRY_WAIT + 40 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == CTATTACHED_UNSUPPORTED); + + /* + * 9. While the CTVPD in CTAttached.Unsupported state, the DRP in + * CTUnattached.SNK state and the Sink in Unattached.SNK state: + * + * a. CTVPD disables the Rd termination on the Charge-Through + * port’s CC pins and applies Rp termination advertising + * Default USB Power + * b. CTVPD exposes a USB Billboard Device Class to the DRP + * indicating that it is connected to an unsupported device on + * its Charge Through port + * c. CTVPD monitors Charge-Though CC pins for Sink detach and when + * detected, enters CTUnattached.VPD + * d. CTVPD monitors VCONN for Host detach and when detected, enters + * Unattached.SNK + * e. DRP monitors CC for CTVPD detach for tVPDDetach and when + * detected, enters Unattached.SNK + * f. DRP monitors VBUS for CTVPD Charge-Through source attach and, + * when detected, enters CTAttached.SNK + */ + + TEST_ASSERT(check_ct_ccs_cc1_rpusb()); + TEST_ASSERT(mock_get_present_billboard() == BB_SNK); + + TEST_ASSERT(ct_disconnect_sink()); + + wait_for_state_change(port, 40 * MSEC); + + TEST_ASSERT(get_typec_state_id(port) == CTUNATTACHED_VPD); + + return EC_SUCCESS; +} +#endif + +void run_test(void) +{ + test_reset(); + + init_port(PORT0); + + /* VPD and CTVPD tests */ + RUN_TEST(test_vpd_host_src_detection); + RUN_TEST(test_vpd_host_src_detection_vbus); + RUN_TEST(test_vpd_host_src_detection_vconn); + RUN_TEST(test_vpd_host_src_detection_message_reception); + + /* CTVPD only tests */ +#if defined(TEST_USB_TYPEC_CTVPD) + /* DRP to VCONN-Powered USB Device (CTVPD) Behavior Tests */ + RUN_TEST(test_ctvpd_behavior_case1); + RUN_TEST(test_ctvpd_behavior_case2); + RUN_TEST(test_ctvpd_behavior_case3); + RUN_TEST(test_ctvpd_behavior_case4); + RUN_TEST(test_ctvpd_behavior_case5); + RUN_TEST(test_ctvpd_behavior_case6); +#endif + test_print_result(); +} + |