summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/usbc/usb_pe_drp_sm.c175
1 files changed, 145 insertions, 30 deletions
diff --git a/common/usbc/usb_pe_drp_sm.c b/common/usbc/usb_pe_drp_sm.c
index 45d7050e37..b2aa88902f 100644
--- a/common/usbc/usb_pe_drp_sm.c
+++ b/common/usbc/usb_pe_drp_sm.c
@@ -71,6 +71,7 @@
#define PE_FLAGS_RUN_SOURCE_START_TIMER BIT(19)
#define PE_FLAGS_VDM_REQUEST_BUSY BIT(20)
#define PE_FLAGS_VDM_REQUEST_NAKED BIT(21)
+#define PE_FLAGS_FAST_ROLE_SWAP BIT(22)
/* 6.7.3 Hard Reset Counter */
#define N_HARD_RESET_COUNT 2
@@ -131,6 +132,7 @@ enum usb_pe_state {
PE_PRS_SNK_SRC_ASSERT_RP,
PE_PRS_SNK_SRC_SOURCE_ON,
PE_PRS_SNK_SRC_SEND_SWAP,
+ PE_FRS_SNK_SRC_START_AMS,
PE_VCS_EVALUATE_SWAP,
PE_VCS_SEND_SWAP,
PE_VCS_WAIT_FOR_VCONN_SWAP,
@@ -144,6 +146,9 @@ enum usb_pe_state {
PE_HANDLE_CUSTOM_VDM_REQUEST,
PE_WAIT_FOR_ERROR_RECOVERY,
PE_BIST,
+
+ /* Super States */
+ PE_PRS_FRS_SHARED,
};
/* Forward declare the full list of states. This is indexed by usb_pe_state */
@@ -188,11 +193,12 @@ static const char * const pe_state_names[] = {
[PE_PRS_SRC_SNK_TRANSITION_TO_OFF] = "PE_PRS_SRC_SNK_Transition_To_Off",
[PE_PRS_SRC_SNK_WAIT_SOURCE_ON] = "PE_PRS_SRC_SNK_Wait_Source_On",
[PE_PRS_SRC_SNK_SEND_SWAP] = "PE_PRS_SRC_SNK_Send_Swap",
- [PE_PRS_SNK_SRC_EVALUATE_SWAP] = "PE_SNK_SRC_Evaluate_Swap",
- [PE_PRS_SNK_SRC_TRANSITION_TO_OFF] = "PE_SNK_SRC_Transition_To_Off",
- [PE_PRS_SNK_SRC_ASSERT_RP] = "PE_SNK_SRC_Assert_Rp",
- [PE_PRS_SNK_SRC_SOURCE_ON] = "PE_SNK_SRC_Source_On",
- [PE_PRS_SNK_SRC_SEND_SWAP] = "PE_SNK_SRC_Send_Swap",
+ [PE_PRS_SNK_SRC_EVALUATE_SWAP] = "PE_PRS_SNK_SRC_Evaluate_Swap",
+ [PE_PRS_SNK_SRC_TRANSITION_TO_OFF] = "PE_PRS_SNK_SRC_Transition_To_Off",
+ [PE_PRS_SNK_SRC_ASSERT_RP] = "PE_PRS_SNK_SRC_Assert_Rp",
+ [PE_PRS_SNK_SRC_SOURCE_ON] = "PE_PRS_SNK_SRC_Source_On",
+ [PE_PRS_SNK_SRC_SEND_SWAP] = "PE_PRS_SNK_SRC_Send_Swap",
+ [PE_FRS_SNK_SRC_START_AMS] = "PE_FRS_SNK_SRC_Start_Ams",
[PE_VCS_EVALUATE_SWAP] = "PE_VCS_Evaluate_Swap",
[PE_VCS_SEND_SWAP] = "PE_VCS_Send_Swap",
[PE_VCS_WAIT_FOR_VCONN_SWAP] = "PE_VCS_Wait_For_Vconn_Swap",
@@ -673,7 +679,12 @@ static enum usb_pe_state get_last_state_pe(const int port)
static void print_current_state(const int port)
{
- CPRINTS("C%d: %s", port, pe_state_names[get_state_pe(port)]);
+ const char *mode = "";
+
+ if (PE_CHK_FLAG(port, PE_FLAGS_FAST_ROLE_SWAP))
+ mode = " FRS-MODE";
+
+ CPRINTS("C%d: %s%s", port, pe_state_names[get_state_pe(port)], mode);
}
static void send_source_cap(int port)
@@ -2897,11 +2908,17 @@ static void pe_prs_snk_src_evaluate_swap_run(int port)
/**
* PE_PRS_SNK_SRC_Transition_To_Off
+ * PE_FRS_SNK_SRC_Transition_To_Off
+ *
+ * NOTE: Shared action code used for Power Role Swap and Fast Role Swap
*/
static void pe_prs_snk_src_transition_to_off_entry(int port)
{
print_current_state(port);
- tc_snk_power_off(port);
+
+ if (!PE_CHK_FLAG(port, PE_FLAGS_FAST_ROLE_SWAP))
+ tc_snk_power_off(port);
+
pe[port].ps_source_timer = get_time().val + PD_T_PS_SOURCE_OFF;
}
@@ -2915,36 +2932,43 @@ static void pe_prs_snk_src_transition_to_off_run(int port)
* Transition to ErrorRecovery state when:
* 1) The PSSourceOffTimer times out.
*/
- if (get_time().val > pe[port].ps_source_timer) {
+ if (get_time().val > pe[port].ps_source_timer)
set_state_pe(port, PE_WAIT_FOR_ERROR_RECOVERY);
- return;
- }
/*
* Transition to PE_PRS_SNK_SRC_Assert_Rp when:
* 1) An PS_RDY Message is received.
*/
- if (PE_CHK_FLAG(port, PE_FLAGS_MSG_RECEIVED)) {
+ else if (PE_CHK_FLAG(port, PE_FLAGS_MSG_RECEIVED)) {
PE_CLR_FLAG(port, PE_FLAGS_MSG_RECEIVED);
type = PD_HEADER_TYPE(emsg[port].header);
cnt = PD_HEADER_CNT(emsg[port].header);
ext = PD_HEADER_EXT(emsg[port].header);
- if ((ext == 0) && (cnt == 0) && (type == PD_CTRL_PS_RDY))
+ if ((ext == 0) && (cnt == 0) && (type == PD_CTRL_PS_RDY)) {
+ /*
+ * FRS: We are always ready to drive vSafe5v, so just
+ * skip PE_FRS_SNK_SRC_Vbus_Applied and go direct to
+ * PE_FRS_SNK_SRC_Assert_Rp
+ */
set_state_pe(port, PE_PRS_SNK_SRC_ASSERT_RP);
+ }
}
}
/**
* PE_PRS_SNK_SRC_Assert_Rp
+ * PE_FRS_SNK_SRC_Assert_Rp
+ *
+ * NOTE: Shared action code used for Power Role Swap and Fast Role Swap
*/
static void pe_prs_snk_src_assert_rp_entry(int port)
{
print_current_state(port);
/*
- * Tell TypeC to Power Role Swap (PRS) from
+ * Tell TypeC to Power/Fast Role Swap (PRS/FRS) from
* Attached.SNK to Attached.SRC
*/
tc_prs_snk_src_assert_rp(port);
@@ -2954,14 +2978,19 @@ static void pe_prs_snk_src_assert_rp_run(int port)
{
/* Wait until TypeC is in the Attached.SRC state */
if (tc_is_attached_src(port)) {
- /* Contract is invalid now */
- PE_CLR_FLAG(port, PE_FLAGS_EXPLICIT_CONTRACT);
+ if (!PE_CHK_FLAG(port, PE_FLAGS_FAST_ROLE_SWAP))
+ /* Contract is invalid now */
+ PE_CLR_FLAG(port, PE_FLAGS_EXPLICIT_CONTRACT);
+
set_state_pe(port, PE_PRS_SNK_SRC_SOURCE_ON);
}
}
/**
* PE_PRS_SNK_SRC_Source_On
+ * PE_FRS_SNK_SRC_Source_On
+ *
+ * NOTE: Shared action code used for Power Role Swap and Fast Role Swap
*/
static void pe_prs_snk_src_source_on_entry(int port)
{
@@ -2987,20 +3016,18 @@ static void pe_prs_snk_src_source_on_run(int port)
prl_send_ctrl_msg(port, TCPC_TX_SOP, PD_CTRL_PS_RDY);
/* reset timer so PD_CTRL_PS_RDY isn't sent again */
pe[port].ps_source_timer = 0;
- return;
}
/*
* Transition to ErrorRecovery state when:
* 1) On protocol error
*/
- if (PE_CHK_FLAG(port, PE_FLAGS_PROTOCOL_ERROR)) {
+ else if (PE_CHK_FLAG(port, PE_FLAGS_PROTOCOL_ERROR)) {
PE_CLR_FLAG(port, PE_FLAGS_PROTOCOL_ERROR);
set_state_pe(port, PE_WAIT_FOR_ERROR_RECOVERY);
- return;
}
- if (PE_CHK_FLAG(port, PE_FLAGS_TX_COMPLETE)) {
+ else if (PE_CHK_FLAG(port, PE_FLAGS_TX_COMPLETE)) {
PE_CLR_FLAG(port, PE_FLAGS_TX_COMPLETE);
/* Run swap source timer on entry to pe_src_startup */
@@ -3012,13 +3039,28 @@ static void pe_prs_snk_src_source_on_run(int port)
/**
* PE_PRS_SNK_SRC_Send_Swap
+ * PE_FRS_SNK_SRC_Send_Swap
+ *
+ * NOTE: Shared action code used for Power Role Swap and Fast Role Swap
*/
static void pe_prs_snk_src_send_swap_entry(int port)
{
print_current_state(port);
- /* Request the Protocol Layer to send a PR_Swap Message. */
- prl_send_ctrl_msg(port, TCPC_TX_SOP, PD_CTRL_PR_SWAP);
+ /*
+ * PRS_SNK_SRC_SEND_SWAP
+ * Request the Protocol Layer to send a PR_Swap Message.
+ *
+ * FRS_SNK_SRC_SEND_SWAP
+ * Hardware should have turned off sink power and started
+ * bringing Vbus to vSafe5.
+ * Request the Protocol Layer to send a FR_Swap Message.
+ */
+ prl_send_ctrl_msg(port,
+ TCPC_TX_SOP,
+ PE_CHK_FLAG(port, PE_FLAGS_FAST_ROLE_SWAP)
+ ? PD_CTRL_FR_SWAP
+ : PD_CTRL_PR_SWAP);
/* Start the SenderResponseTimer */
pe[port].sender_response_timer =
@@ -3032,23 +3074,26 @@ static void pe_prs_snk_src_send_swap_run(int port)
int ext;
/*
- * Transition to PE_SNK_Ready state when:
+ * PRS: Transition to PE_SNK_Ready state when:
+ * FRS: Transition to ErrorRecovery state when:
* 1) The SenderResponseTimer times out.
*/
- if (get_time().val > pe[port].sender_response_timer) {
- set_state_pe(port, PE_SNK_READY);
- return;
- }
+ if (get_time().val > pe[port].sender_response_timer)
+ set_state_pe(port,
+ PE_CHK_FLAG(port, PE_FLAGS_FAST_ROLE_SWAP)
+ ? PE_WAIT_FOR_ERROR_RECOVERY
+ : PE_SNK_READY);
/*
* Transition to PE_PRS_SNK_SRC_Transition_to_off when:
* 1) An Accept Message is received.
*
- * Transition to PE_SNK_Ready state when:
+ * PRS: Transition to PE_SNK_Ready state when:
+ * FRS: Transition to ErrorRecovery state when:
* 1) A Reject Message is received.
* 2) Or a Wait Message is received.
*/
- if (PE_CHK_FLAG(port, PE_FLAGS_MSG_RECEIVED)) {
+ else if (PE_CHK_FLAG(port, PE_FLAGS_MSG_RECEIVED)) {
PE_CLR_FLAG(port, PE_FLAGS_MSG_RECEIVED);
type = PD_HEADER_TYPE(emsg[port].header);
@@ -3058,10 +3103,14 @@ static void pe_prs_snk_src_send_swap_run(int port)
if ((ext == 0) && (cnt == 0)) {
if (type == PD_CTRL_ACCEPT)
set_state_pe(port,
- PE_PRS_SNK_SRC_TRANSITION_TO_OFF);
+ PE_PRS_SNK_SRC_TRANSITION_TO_OFF);
else if ((type == PD_CTRL_REJECT) ||
(type == PD_CTRL_WAIT))
- set_state_pe(port, PE_SNK_READY);
+ set_state_pe(port,
+ PE_CHK_FLAG(port,
+ PE_FLAGS_FAST_ROLE_SWAP)
+ ? PE_WAIT_FOR_ERROR_RECOVERY
+ : PE_SNK_READY);
}
}
}
@@ -3073,6 +3122,50 @@ static void pe_prs_snk_src_send_swap_exit(int port)
}
/**
+ * PE_FRS_SNK_SRC_Start_AMS
+ */
+static void pe_frs_snk_src_start_ams_entry(int port)
+{
+ print_current_state(port);
+
+ /* Contract is invalid now */
+ PE_CLR_FLAG(port, PE_FLAGS_EXPLICIT_CONTRACT);
+
+ /* Inform Protocol Layer this is start of AMS */
+ prl_start_ams(port);
+ tc_set_timeout(port, 2 * MSEC);
+
+ /* Shared PRS/FRS code, indicate FRS path */
+ PE_SET_FLAG(port, PE_FLAGS_FAST_ROLE_SWAP);
+ set_state_pe(port, PE_PRS_SNK_SRC_SEND_SWAP);
+}
+
+/**
+ * PE_PRS_FRS_SHARED
+ */
+static void pe_prs_frs_shared_entry(int port)
+{
+ /*
+ * Shared PRS/FRS code, assume PRS path
+ *
+ * This is the super state entry. It will be called before
+ * the first entry state to get into the PRS/FRS path.
+ * For FRS, PE_FRS_SNK_SRC_START_AMS entry will be called
+ * after this and that will set for the FRS path.
+ */
+ PE_CLR_FLAG(port, PE_FLAGS_FAST_ROLE_SWAP);
+}
+
+static void pe_prs_frs_shared_exit(int port)
+{
+ /*
+ * Shared PRS/FRS code, when not in shared path
+ * indicate PRS path
+ */
+ PE_CLR_FLAG(port, PE_FLAGS_FAST_ROLE_SWAP);
+}
+
+/**
* BIST
*/
static void pe_bist_entry(int port)
@@ -4645,6 +4738,12 @@ DECLARE_HOST_COMMAND(EC_CMD_USB_PD_GET_AMODE,
#endif /* CONFIG_USB_PD_ALT_MODE_DFP */
static const struct usb_state pe_states[] = {
+ /* Super States */
+ [PE_PRS_FRS_SHARED] = {
+ .entry = pe_prs_frs_shared_entry,
+ .exit = pe_prs_frs_shared_exit,
+ },
+
/* Normal States */
[PE_SRC_STARTUP] = {
.entry = pe_src_startup_entry,
@@ -4796,22 +4895,38 @@ static const struct usb_state pe_states[] = {
.entry = pe_prs_snk_src_evaluate_swap_entry,
.run = pe_prs_snk_src_evaluate_swap_run,
},
+ /*
+ * Some of the Power Role Swap actions are shared with the very
+ * similar actions of Fast Role Swap.
+ */
+ /* State actions are shared with PE_FRS_SNK_SRC_TRANSITION_TO_OFF */
[PE_PRS_SNK_SRC_TRANSITION_TO_OFF] = {
.entry = pe_prs_snk_src_transition_to_off_entry,
.run = pe_prs_snk_src_transition_to_off_run,
+ .parent = &pe_states[PE_PRS_FRS_SHARED],
},
+ /* State actions are shared with PE_FRS_SNK_SRC_ASSERT_RP */
[PE_PRS_SNK_SRC_ASSERT_RP] = {
.entry = pe_prs_snk_src_assert_rp_entry,
.run = pe_prs_snk_src_assert_rp_run,
+ .parent = &pe_states[PE_PRS_FRS_SHARED],
},
+ /* State actions are shared with PE_FRS_SNK_SRC_SOURCE_ON */
[PE_PRS_SNK_SRC_SOURCE_ON] = {
.entry = pe_prs_snk_src_source_on_entry,
.run = pe_prs_snk_src_source_on_run,
+ .parent = &pe_states[PE_PRS_FRS_SHARED],
},
+ /* State actions are shared with PE_FRS_SNK_SRC_SEND_SWAP */
[PE_PRS_SNK_SRC_SEND_SWAP] = {
.entry = pe_prs_snk_src_send_swap_entry,
.run = pe_prs_snk_src_send_swap_run,
.exit = pe_prs_snk_src_send_swap_exit,
+ .parent = &pe_states[PE_PRS_FRS_SHARED],
+ },
+ [PE_FRS_SNK_SRC_START_AMS] = {
+ .entry = pe_frs_snk_src_start_ams_entry,
+ .parent = &pe_states[PE_PRS_FRS_SHARED],
},
[PE_VCS_EVALUATE_SWAP] = {
.entry = pe_vcs_evaluate_swap_entry,