diff options
Diffstat (limited to 'common/usbc/usb_pd_dpm.c')
-rw-r--r-- | common/usbc/usb_pd_dpm.c | 65 |
1 files changed, 49 insertions, 16 deletions
diff --git a/common/usbc/usb_pd_dpm.c b/common/usbc/usb_pd_dpm.c index eb2dfc52c0..36cfdf0f75 100644 --- a/common/usbc/usb_pd_dpm.c +++ b/common/usbc/usb_pd_dpm.c @@ -18,9 +18,11 @@ #include "tcpm/tcpm.h" #include "usb_dp_alt_mode.h" #include "usb_mode.h" +#include "usb_mux.h" #include "usb_pd.h" #include "usb_pd_dpm.h" #include "usb_pd_tcpm.h" +#include "usb_pd_pdo.h" #include "usb_tbt_alt_mode.h" #ifdef CONFIG_COMMON_RUNTIME @@ -234,6 +236,7 @@ static void dpm_attempt_mode_entry(int port) enum tcpci_msg_type tx_type = TCPCI_MSG_SOP; bool enter_mode_requested = IS_ENABLED(CONFIG_USB_PD_REQUIRE_AP_MODE_ENTRY) ? false : true; + enum dpm_msg_setup_status status = MSG_SETUP_UNSUPPORTED; if (pd_get_data_role(port) != PD_ROLE_DFP) { if (DPM_CHK_FLAG(port, DPM_FLAG_ENTER_DP | @@ -276,6 +279,14 @@ static void dpm_attempt_mode_entry(int port) return; } + /* + * If muxes are still settling, then wait on our next VDM. We must + * ensure we correctly sequence actions such as USB safe state with TBT + * entry or DP configuration. + */ + if (IS_ENABLED(CONFIG_USBC_SS_MUX) && !usb_mux_set_completed(port)) + return; + /* Check if port, port partner and cable support USB4. */ if (IS_ENABLED(CONFIG_USB_PD_USB4) && board_is_tbt_usb4_port(port) && @@ -287,8 +298,9 @@ static void dpm_attempt_mode_entry(int port) * cable and USB4 mode with the port partner. */ if (tbt_cable_entry_required_for_usb4(port)) { - vdo_count = tbt_setup_next_vdm(port, - ARRAY_SIZE(vdm), vdm, &tx_type); + vdo_count = ARRAY_SIZE(vdm); + status = tbt_setup_next_vdm(port, &vdo_count, vdm, + &tx_type); } else { pd_dpm_request(port, DPM_REQUEST_ENTER_USB); return; @@ -302,24 +314,32 @@ static void dpm_attempt_mode_entry(int port) USB_VID_INTEL) && dpm_mode_entry_requested(port, TYPEC_MODE_TBT)) { enter_mode_requested = true; - vdo_count = tbt_setup_next_vdm(port, - ARRAY_SIZE(vdm), vdm, &tx_type); + vdo_count = ARRAY_SIZE(vdm); + status = tbt_setup_next_vdm(port, &vdo_count, vdm, + &tx_type); } /* If not, check if they support DisplayPort alt mode. */ - if (vdo_count == 0 && !DPM_CHK_FLAG(port, DPM_FLAG_MODE_ENTRY_DONE) && + if (status == MSG_SETUP_UNSUPPORTED && + !DPM_CHK_FLAG(port, DPM_FLAG_MODE_ENTRY_DONE) && pd_is_mode_discovered_for_svid(port, TCPCI_MSG_SOP, - USB_SID_DISPLAYPORT) && + USB_SID_DISPLAYPORT) && dpm_mode_entry_requested(port, TYPEC_MODE_DP)) { enter_mode_requested = true; - vdo_count = dp_setup_next_vdm(port, ARRAY_SIZE(vdm), vdm); + vdo_count = ARRAY_SIZE(vdm); + status = dp_setup_next_vdm(port, &vdo_count, vdm); } + /* Not ready to send a VDM, check again next cycle */ + if (status == MSG_SETUP_MUX_WAIT) + return; + /* * If the PE didn't discover any supported (requested) alternate mode, * just mark setup done and get out of here. */ - if (vdo_count == 0 && !DPM_CHK_FLAG(port, DPM_FLAG_MODE_ENTRY_DONE)) { + if (status != MSG_SETUP_SUCCESS && + !DPM_CHK_FLAG(port, DPM_FLAG_MODE_ENTRY_DONE)) { if (enter_mode_requested) { /* * TODO(b/168030639): Notify the AP that mode entry @@ -335,7 +355,7 @@ static void dpm_attempt_mode_entry(int port) return; } - if (vdo_count < 0) { + if (status != MSG_SETUP_SUCCESS) { dpm_set_mode_entry_done(port); CPRINTS("C%d: Couldn't construct alt mode VDM", port); return; @@ -355,8 +375,9 @@ static void dpm_attempt_mode_entry(int port) static void dpm_attempt_mode_exit(int port) { - uint32_t vdm = 0; - int vdo_count = 0; + uint32_t vdm[VDO_MAX_SIZE]; + int vdo_count = ARRAY_SIZE(vdm); + enum dpm_msg_setup_status status = MSG_SETUP_ERROR; enum tcpci_msg_type tx_type = TCPCI_MSG_SOP; if (IS_ENABLED(CONFIG_USB_PD_USB4) && @@ -364,6 +385,15 @@ static void dpm_attempt_mode_exit(int port) CPRINTS("C%d: USB4 teardown", port); usb4_exit_mode_request(port); } + + /* + * If muxes are still settling, then wait on our next VDM. We must + * ensure we correctly sequence actions such as USB safe state with TBT + * or DP mode exit. + */ + if (IS_ENABLED(CONFIG_USBC_SS_MUX) && !usb_mux_set_completed(port)) + return; + if (IS_ENABLED(CONFIG_USB_PD_TBT_COMPAT_MODE) && tbt_is_active(port)) { /* @@ -373,18 +403,21 @@ static void dpm_attempt_mode_exit(int port) */ CPRINTS("C%d: TBT teardown", port); tbt_exit_mode_request(port); - vdo_count = tbt_setup_next_vdm(port, VDO_MAX_SIZE, &vdm, - &tx_type); + status = tbt_setup_next_vdm(port, &vdo_count, vdm, &tx_type); } else if (dp_is_active(port)) { CPRINTS("C%d: DP teardown", port); - vdo_count = dp_setup_next_vdm(port, VDO_MAX_SIZE, &vdm); + status = dp_setup_next_vdm(port, &vdo_count, vdm); } else { /* Clear exit mode request */ dpm_clear_mode_exit_request(port); return; } - if (!pd_setup_vdm_request(port, tx_type, &vdm, vdo_count)) { + /* This covers error, wait mux, and unsupported cases */ + if (status != MSG_SETUP_SUCCESS) + return; + + if (!pd_setup_vdm_request(port, tx_type, vdm, vdo_count)) { dpm_clear_mode_exit_request(port); return; } @@ -467,7 +500,7 @@ static void balance_source_ports(void) uint32_t removed_ports, new_ports; static bool deferred_waiting; - if (task_get_current() == TASK_ID_HOOKS) + if (in_deferred_context()) deferred_waiting = false; /* |