summaryrefslogtreecommitdiff
path: root/common/usbc/usb_pd_dpm.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/usbc/usb_pd_dpm.c')
-rw-r--r--common/usbc/usb_pd_dpm.c65
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;
/*