diff options
author | Denis Brockus <dbrockus@google.com> | 2020-08-27 15:34:03 -0600 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-09-02 21:50:25 +0000 |
commit | bc7b14284465675c69cfa186da6a3389debfde16 (patch) | |
tree | a0e3705a72ba983e7cfca0fe5bf75e73a8e31c0c | |
parent | 44302acb01290bea42acf35bd15a390a36a6688d (diff) | |
download | chrome-ec-bc7b14284465675c69cfa186da6a3389debfde16.tar.gz |
TCPMv2: Add DPM_REQUEST_GET_SRC_CAP
As a SRC that runs on battery it can be handy to determine
if the connected partner has unconstrained power available
so we can try to PR_Swap to let them power us. This only
requests the information, if it is not already available,
and leaves it to other code to determine if the swap is
a good idea.
BUG=b:166446426
BRANCH=none
TEST=connect a sink device and determine it performed the action
Signed-off-by: Denis Brockus <dbrockus@google.com>
Change-Id: If45801a33df8b75e541989d7ee8f36ed316ffcc6
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2381408
Tested-by: Denis Brockus <dbrockus@chromium.org>
Reviewed-by: Jett Rink <jettrink@chromium.org>
Commit-Queue: Jett Rink <jettrink@chromium.org>
Auto-Submit: Denis Brockus <dbrockus@chromium.org>
-rw-r--r-- | common/usbc/usb_pe_drp_sm.c | 96 | ||||
-rw-r--r-- | common/usbc/usb_tc_drp_acc_trysrc_sm.c | 10 | ||||
-rw-r--r-- | include/usb_pe_sm.h | 1 | ||||
-rw-r--r-- | test/usb_pe.h | 1 | ||||
-rw-r--r-- | test/usb_tcpmv2_tcpci.c | 31 |
5 files changed, 130 insertions, 9 deletions
diff --git a/common/usbc/usb_pe_drp_sm.c b/common/usbc/usb_pe_drp_sm.c index 60924579b4..9c489fccf8 100644 --- a/common/usbc/usb_pe_drp_sm.c +++ b/common/usbc/usb_pe_drp_sm.c @@ -276,6 +276,7 @@ enum usb_pe_state { PE_DEU_SEND_ENTER_USB, PE_DR_SNK_GET_SINK_CAP, PE_DR_SNK_GIVE_SOURCE_CAP, + PE_DR_SRC_GET_SOURCE_CAP, /* PD3.0 only states below here*/ PE_FRS_SNK_SRC_START_AMS, @@ -397,6 +398,7 @@ static const char * const pe_state_names[] = { [PE_DR_SNK_GET_SINK_CAP] = "PE_DR_SNK_Get_Sink_Cap", #endif [PE_DR_SNK_GIVE_SOURCE_CAP] = "PE_DR_SNK_Give_Source_Cap", + [PE_DR_SRC_GET_SOURCE_CAP] = "PE_DR_SRC_Get_Source_Cap", /* PD3.0 only states below here*/ #ifdef CONFIG_USB_PD_REV30 @@ -2068,6 +2070,14 @@ static void pe_src_transition_supply_run(int port) */ PE_SET_FLAG(port, PE_FLAGS_FIRST_MSG); + /* + * Setup to get Device Policy Manager to request + * Source Capabilities, if needed, for possible + * PR_Swap + */ + if (pd_get_src_cap_cnt(port) == 0) + pe_dpm_request(port, DPM_REQUEST_GET_SRC_CAPS); + set_state_pe(port, PE_SRC_READY); } else { /* NOTE: First pass through this code block */ @@ -2326,6 +2336,11 @@ static void pe_src_ready_run(int port) DPM_REQUEST_SRC_CAP_CHANGE); set_state_pe(port, PE_SRC_SEND_CAPABILITIES); } else if (PE_CHK_DPM_REQUEST(port, + DPM_REQUEST_GET_SRC_CAPS)) { + pe_set_dpm_curr_request(port, + DPM_REQUEST_GET_SRC_CAPS); + set_state_pe(port, PE_DR_SRC_GET_SOURCE_CAP); + } else if (PE_CHK_DPM_REQUEST(port, DPM_REQUEST_SEND_PING)) { pe_set_dpm_curr_request(port, DPM_REQUEST_SEND_PING); @@ -2641,7 +2656,6 @@ static void pe_snk_evaluate_capability_entry(int port) { uint32_t *pdo = (uint32_t *)rx_emsg[port].buf; uint32_t num = rx_emsg[port].len >> 2; - int i; print_current_state(port); @@ -2659,10 +2673,7 @@ static void pe_snk_evaluate_capability_entry(int port) if (prl_get_rev(port, TCPC_TX_SOP) == PD_REV20) prl_set_rev(port, TCPC_TX_SOP_PRIME, PD_REV20); - pe[port].src_cap_cnt = num; - - for (i = 0; i < num; i++) - pe[port].src_caps[i] = pdo[i]; + pd_set_src_caps(port, num, pdo); /* src cap 0 should be fixed PDO */ pe_update_pdo_flags(port, pdo[0]); @@ -5850,6 +5861,77 @@ static void pe_dr_snk_give_source_cap_run(int port) } } +/* + * PE_DR_SRC_Get_Source_Cap + */ +static void pe_dr_src_get_source_cap_entry(int port) +{ + print_current_state(port); + + /* Send a Get_Source_Cap Message */ + tx_emsg[port].len = 0; + send_ctrl_msg(port, TCPC_TX_SOP, PD_CTRL_GET_SOURCE_CAP); + pe_sender_response_msg_entry(port); +} + +static void pe_dr_src_get_source_cap_run(int port) +{ + int type; + int cnt; + int ext; + enum pe_msg_check msg_check; + + /* + * Check the state of the message sent + */ + msg_check = pe_sender_response_msg_run(port); + + /* + * Transition to PE_SRC_Ready when: + * 1) A Source Capabilities Message is received. + * 2) A Reject Message is received. + */ + if ((msg_check & PE_MSG_SENT) && + PE_CHK_FLAG(port, PE_FLAGS_MSG_RECEIVED)) { + PE_CLR_FLAG(port, PE_FLAGS_MSG_RECEIVED); + + type = PD_HEADER_TYPE(rx_emsg[port].header); + cnt = PD_HEADER_CNT(rx_emsg[port].header); + ext = PD_HEADER_EXT(rx_emsg[port].header); + + if (ext == 0) { + if ((cnt > 0) && (type == PD_DATA_SOURCE_CAP)) { + uint32_t *payload = + (uint32_t *)rx_emsg[port].buf; + + /* + * src_caps[0] & PDO_FIXED_UNCONSTRAINED + * has useful information to help guide us + * to possibly perform a PR_Swap if that is + * desired + */ + pd_set_src_caps(port, cnt, payload); + set_state_pe(port, PE_SRC_READY); + } else if (type == PD_CTRL_REJECT || + type == PD_CTRL_NOT_SUPPORTED) { + set_state_pe(port, PE_SRC_READY); + } else { + set_state_pe(port, PE_SEND_SOFT_RESET); + } + return; + } + } + + /* + * Transition to PE_SRC_Ready state when: + * 1) the SenderResponseTimer times out. + * 2) Message was discarded. + */ + if ((msg_check & PE_MSG_DISCARDED) || + get_time().val > pe[port].sender_response_timer) + set_state_pe(port, PE_SRC_READY); +} + const uint32_t * const pd_get_src_caps(int port) { return pe[port].src_caps; @@ -6212,6 +6294,10 @@ static const struct usb_state pe_states[] = { .entry = pe_dr_snk_give_source_cap_entry, .run = pe_dr_snk_give_source_cap_run, }, + [PE_DR_SRC_GET_SOURCE_CAP] = { + .entry = pe_dr_src_get_source_cap_entry, + .run = pe_dr_src_get_source_cap_run, + }, #ifdef CONFIG_USB_PD_REV30 [PE_FRS_SNK_SRC_START_AMS] = { .entry = pe_frs_snk_src_start_ams_entry, diff --git a/common/usbc/usb_tc_drp_acc_trysrc_sm.c b/common/usbc/usb_tc_drp_acc_trysrc_sm.c index c2a9ef0985..2dbcb294f9 100644 --- a/common/usbc/usb_tc_drp_acc_trysrc_sm.c +++ b/common/usbc/usb_tc_drp_acc_trysrc_sm.c @@ -1927,6 +1927,11 @@ static void tc_unattached_snk_entry(const int port) tc[port].data_role = PD_ROLE_DISCONNECTED; /* + * Saved SRC_Capabilities are no longer valid on disconnect + */ + pd_set_src_caps(port, 0, NULL); + + /* * When data role set events are used to enable BC1.2, then CC * detach events are used to notify BC1.2 that it can be powered * down. @@ -2404,6 +2409,11 @@ static void tc_unattached_src_entry(const int port) tc[port].data_role = PD_ROLE_DISCONNECTED; /* + * Saved SRC_Capabilities are no longer valid on disconnect + */ + pd_set_src_caps(port, 0, NULL); + + /* * When data role set events are used to enable BC1.2, then CC * detach events are used to notify BC1.2 that it can be powered * down. diff --git a/include/usb_pe_sm.h b/include/usb_pe_sm.h index 511bf263b5..340c0b486b 100644 --- a/include/usb_pe_sm.h +++ b/include/usb_pe_sm.h @@ -43,6 +43,7 @@ enum pe_dpm_request { DPM_REQUEST_PORT_DISCOVERY = BIT(16), DPM_REQUEST_SEND_ALERT = BIT(17), DPM_REQUEST_ENTER_USB = BIT(18), + DPM_REQUEST_GET_SRC_CAPS = BIT(19), }; /** diff --git a/test/usb_pe.h b/test/usb_pe.h index 3a4479d534..fb5ac10f88 100644 --- a/test/usb_pe.h +++ b/test/usb_pe.h @@ -133,6 +133,7 @@ enum usb_pe_state { PE_DEU_SEND_ENTER_USB, PE_DR_SNK_GET_SINK_CAP, PE_DR_SNK_GIVE_SOURCE_CAP, + PE_DR_SRC_GET_SOURCE_CAP, /* PD3.0 only states below here*/ PE_FRS_SNK_SRC_START_AMS, diff --git a/test/usb_tcpmv2_tcpci.c b/test/usb_tcpmv2_tcpci.c index 1ab0ec7f66..960cb9ff0f 100644 --- a/test/usb_tcpmv2_tcpci.c +++ b/test/usb_tcpmv2_tcpci.c @@ -63,6 +63,8 @@ uint16_t tcpc_get_alert_status(void) return 0; } +static int rx_id; + const struct svdm_response svdm_rsp = { .identity = NULL, .svids = NULL, @@ -145,8 +147,11 @@ __maybe_unused static int test_startup_and_resume(void) __maybe_unused static int test_connect_as_pd3_source(void) { - int rx_id = 0; uint32_t rdo = RDO_FIXED(1, 500, 500, 0); + uint32_t pdo = PDO_FIXED(5000, 500, + PDO_FIXED_DUAL_ROLE | + PDO_FIXED_DATA_SWAP | + PDO_FIXED_COMM_CAP); /* DRP auto-toggling with AP in S0, source enabled. */ TEST_EQ(test_startup_and_resume(), EC_SUCCESS, "%d"); @@ -184,6 +189,7 @@ __maybe_unused static int test_connect_as_pd3_source(void) PD_ROLE_UFP, rx_id, 1, PD_REV30, 0), &rdo); + rx_id++; mock_set_alert(TCPC_REG_ALERT_RX_STATUS); TEST_EQ(verify_tcpci_transmit(TCPC_TX_SOP, PD_CTRL_ACCEPT, 0), EC_SUCCESS, "%d"); @@ -208,9 +214,10 @@ __maybe_unused static int test_connect_as_pd3_source(void) 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, + PD_ROLE_UFP, rx_id, 0, PD_REV30, 0), NULL); + rx_id++; mock_set_alert(TCPC_REG_ALERT_RX_STATUS); TEST_EQ(verify_tcpci_transmit(TCPC_TX_SOP, 0, PD_DATA_VENDOR_DEF), @@ -219,9 +226,22 @@ __maybe_unused static int test_connect_as_pd3_source(void) task_wait_event(10 * MSEC); mock_tcpci_receive(PD_MSG_SOP, PD_HEADER(PD_CTRL_NOT_SUPPORTED, PD_ROLE_SINK, - PD_ROLE_UFP, 2, + PD_ROLE_UFP, rx_id, 0, PD_REV30, 0), NULL); + rx_id++; + mock_set_alert(TCPC_REG_ALERT_RX_STATUS); + + TEST_EQ(verify_tcpci_transmit(TCPC_TX_SOP, PD_CTRL_GET_SOURCE_CAP, 0), + 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_DATA_SOURCE_CAP, PD_ROLE_SINK, + PD_ROLE_UFP, rx_id, + 1, PD_REV30, 0), + &pdo); + rx_id++; mock_set_alert(TCPC_REG_ALERT_RX_STATUS); task_wait_event(1 * SECOND); @@ -319,9 +339,10 @@ __maybe_unused static int test_pd3_source_send_soft_reset(void) */ mock_tcpci_receive(PD_MSG_SOP, PD_HEADER(PD_CTRL_GET_SOURCE_CAP, PD_ROLE_SINK, - PD_ROLE_UFP, 3, + PD_ROLE_UFP, rx_id, 0, PD_REV30, 0), NULL); + rx_id++; mock_set_alert(TCPC_REG_ALERT_RX_STATUS); /* @@ -346,6 +367,8 @@ __maybe_unused static int test_pd3_source_send_soft_reset(void) void before_test(void) { + rx_id = 0; + mock_usb_mux_reset(); mock_tcpci_reset(); |