summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Brockus <dbrockus@chromium.org>2019-09-25 11:33:53 -0600
committerCommit Bot <commit-bot@chromium.org>2019-10-07 23:33:24 +0000
commit0783b019fc880443a768acdc1286499a49594baa (patch)
tree68751a4d70cb7c97af0421f5cef2c98e73b52b24
parent87d1b1904dc58fbadd21cd5c7c6b03da2e42d077 (diff)
downloadchrome-ec-0783b019fc880443a768acdc1286499a49594baa.tar.gz
pd: FRS enable/disable and interrupt handling
BUG=b:138599955 BRANCH=none TEST=make buildall -j Change-Id: I0c639aae18e8c2c2d1b457e2e209f8484a834f6b Signed-off-by: Denis Brockus <dbrockus@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1825507 Reviewed-by: Edward Hill <ecgh@chromium.org>
-rw-r--r--common/usbc/usb_pe_drp_sm.c208
-rw-r--r--common/usbc/usb_tc_drp_acc_trysrc_sm.c5
-rw-r--r--driver/tcpm/tcpci.h3
-rw-r--r--driver/tcpm/tcpm.h19
-rw-r--r--include/config.h3
-rw-r--r--include/usb_pd.h12
-rw-r--r--include/usb_pd_tcpm.h8
-rw-r--r--include/usb_pe_sm.h7
8 files changed, 244 insertions, 21 deletions
diff --git a/common/usbc/usb_pe_drp_sm.c b/common/usbc/usb_pe_drp_sm.c
index 70c7a32eb7..ac9e4883e1 100644
--- a/common/usbc/usb_pe_drp_sm.c
+++ b/common/usbc/usb_pe_drp_sm.c
@@ -71,7 +71,9 @@
#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)
+#define PE_FLAGS_FAST_ROLE_SWAP_PATH BIT(22)/* FRS/PRS Exec Path */
+#define PE_FLAGS_FAST_ROLE_SWAP_ENABLED BIT(23)/* FRS Listening State */
+#define PE_FLAGS_FAST_ROLE_SWAP_SIGNALED BIT(24)/* FRS PPC/TCPC Signal */
/* 6.7.3 Hard Reset Counter */
#define N_HARD_RESET_COUNT 2
@@ -146,6 +148,7 @@ enum usb_pe_state {
PE_HANDLE_CUSTOM_VDM_REQUEST,
PE_WAIT_FOR_ERROR_RECOVERY,
PE_BIST,
+ PE_DR_SNK_GET_SINK_CAP,
/* Super States */
PE_PRS_FRS_SHARED,
@@ -212,6 +215,7 @@ static const char * const pe_state_names[] = {
[PE_HANDLE_CUSTOM_VDM_REQUEST] = "PE_Handle_Custom_Vdm_Request",
[PE_WAIT_FOR_ERROR_RECOVERY] = "PE_Wait_For_Error_Recovery",
[PE_BIST] = "PE_Bist",
+ [PE_DR_SNK_GET_SINK_CAP] = "PE_DR_SNK_Get_Sink_Cap",
};
#endif
@@ -476,6 +480,18 @@ void pe_run(int port, int evt, int en)
break;
}
+ /*
+ * Check for Fast Role Swap signal
+ * This is not a typical pattern for adding state changes.
+ * I added this here because FRS SIGNALED can happen at any
+ * state once we are listening for the signal and we want to
+ * make sure to handle it immediately.
+ */
+ if (PE_CHK_FLAG(port, PE_FLAGS_FAST_ROLE_SWAP_SIGNALED)) {
+ PE_CLR_FLAG(port, PE_FLAGS_FAST_ROLE_SWAP_SIGNALED);
+ set_state_pe(port, PE_FRS_SNK_SRC_START_AMS);
+ }
+
/* Run state machine */
exe_state(port, &pe[port].ctx);
break;
@@ -521,6 +537,58 @@ void pe_got_hard_reset(int port)
set_state_pe(port, PE_SNK_TRANSITION_TO_DEFAULT);
}
+/*
+ * pe_got_frs_signal
+ *
+ * Called by the handler that detects the FRS signal in order to
+ * switch PE states to complete the FRS that the hardware has
+ * started.
+ */
+void pe_got_frs_signal(int port)
+{
+ PE_SET_FLAG(port, PE_FLAGS_FAST_ROLE_SWAP_SIGNALED);
+}
+
+/*
+ * PE_Set_FRS_Enable
+ *
+ * This function should be called every time an explicit contract
+ * is disabled, to disable FRS.
+ *
+ * Enabling an explicit contract is not enough to enable FRS, it
+ * also requires a Sink Capability power requirement from a Source
+ * that supports FRS so we can determine if this is something we
+ * can handle.
+ */
+static void pe_set_frs_enable(int port, int enable)
+{
+ /* This should only be called from the PD task */
+ assert(port == TASK_ID_TO_PD_PORT(task_get_current()));
+
+ if (IS_ENABLED(CONFIG_USB_TYPEC_PD_FAST_ROLE_SWAP)) {
+ int current = PE_CHK_FLAG(port,
+ PE_FLAGS_FAST_ROLE_SWAP_ENABLED);
+
+ /* Request an FRS change, only if the state has changed */
+ if (!!current != !!enable) {
+ tcpm_set_frs_enable(port, enable);
+
+ if (enable)
+ PE_SET_FLAG(port,
+ PE_FLAGS_FAST_ROLE_SWAP_ENABLED);
+ else
+ PE_CLR_FLAG(port,
+ PE_FLAGS_FAST_ROLE_SWAP_ENABLED);
+ }
+ }
+}
+
+static void pe_invalidate_explicit_contract(int port)
+{
+ pe_set_frs_enable(port, 0);
+ PE_CLR_FLAG(port, PE_FLAGS_EXPLICIT_CONTRACT);
+}
+
void pe_report_error(int port, enum pe_error e)
{
/* This should only be called from the PD task */
@@ -681,7 +749,7 @@ static void print_current_state(const int port)
{
const char *mode = "";
- if (PE_CHK_FLAG(port, PE_FLAGS_FAST_ROLE_SWAP))
+ if (PE_CHK_FLAG(port, PE_FLAGS_FAST_ROLE_SWAP_PATH))
mode = " FRS-MODE";
CPRINTS("C%d: %s%s", port, pe_state_names[get_state_pe(port)], mode);
@@ -848,7 +916,7 @@ static void pe_src_startup_entry(int port)
pe[port].power_role = PD_ROLE_SOURCE;
/* Clear explicit contract. */
- PE_CLR_FLAG(port, PE_FLAGS_EXPLICIT_CONTRACT);
+ pe_invalidate_explicit_contract(port);
pe[port].cable_discover_identity_count = 0;
pe[port].port_discover_identity_count = 0;
@@ -1614,7 +1682,7 @@ static void pe_snk_startup_entry(int port)
pe[port].power_role = PD_ROLE_SINK;
/* Clear explicit contract */
- PE_CLR_FLAG(port, PE_FLAGS_EXPLICIT_CONTRACT);
+ pe_invalidate_explicit_contract(port);
}
static void pe_snk_startup_run(int port)
@@ -1789,6 +1857,12 @@ static void pe_snk_select_capability_run(int port)
/* explicit contract is now in place */
PE_SET_FLAG(port, PE_FLAGS_EXPLICIT_CONTRACT);
set_state_pe(port, PE_SNK_TRANSITION_SINK);
+
+ /*
+ * Setup to get Device Policy Manager to
+ * request Sink Capabilities for possible FRS
+ */
+ pe_dpm_request(port, DPM_REQUEST_GET_SNK_CAPS);
return;
}
/*
@@ -1967,12 +2041,10 @@ static void pe_snk_ready_run(int port)
* Ignore source specific requests:
* DPM_REQUEST_GOTO_MIN
* DPM_REQUEST_SRC_CAP_CHANGE,
- * DPM_REQUEST_GET_SNK_CAPS,
* DPM_REQUEST_SEND_PING
*/
PE_CLR_DPM_REQUEST(port, DPM_REQUEST_GOTO_MIN |
DPM_REQUEST_SRC_CAP_CHANGE |
- DPM_REQUEST_GET_SNK_CAPS |
DPM_REQUEST_SEND_PING);
if (pe[port].dpm_request) {
@@ -1997,7 +2069,8 @@ static void pe_snk_ready_run(int port)
set_state_pe(port, PE_SNK_SELECT_CAPABILITY);
} else if (PE_CHK_DPM_REQUEST(port,
DPM_REQUEST_DISCOVER_IDENTITY)) {
- PE_CLR_DPM_REQUEST(port, DPM_REQUEST_DISCOVER_IDENTITY);
+ PE_CLR_DPM_REQUEST(port,
+ DPM_REQUEST_DISCOVER_IDENTITY);
pe[port].partner_type = CABLE;
pe[port].vdm_cmd = DISCOVER_IDENTITY;
@@ -2008,6 +2081,10 @@ static void pe_snk_ready_run(int port)
pe[port].vdm_cnt = 1;
set_state_pe(port, PE_VDM_REQUEST);
+ } else if (PE_CHK_DPM_REQUEST(port,
+ DPM_REQUEST_GET_SNK_CAPS)) {
+ PE_CLR_DPM_REQUEST(port, DPM_REQUEST_GET_SNK_CAPS);
+ set_state_pe(port, PE_DR_SNK_GET_SINK_CAP);
}
return;
}
@@ -2743,7 +2820,7 @@ static void pe_prs_src_snk_transition_to_off_run(int port)
/* Wait until Rd is asserted */
if (tc_is_attached_snk(port)) {
/* Contract is invalid */
- PE_CLR_FLAG(port, PE_FLAGS_EXPLICIT_CONTRACT);
+ pe_invalidate_explicit_contract(port);
set_state_pe(port, PE_PRS_SRC_SNK_WAIT_SOURCE_ON);
}
}
@@ -2916,7 +2993,7 @@ static void pe_prs_snk_src_transition_to_off_entry(int port)
{
print_current_state(port);
- if (!PE_CHK_FLAG(port, PE_FLAGS_FAST_ROLE_SWAP))
+ if (!PE_CHK_FLAG(port, PE_FLAGS_FAST_ROLE_SWAP_PATH))
tc_snk_power_off(port);
pe[port].ps_source_timer = get_time().val + PD_T_PS_SOURCE_OFF;
@@ -2978,9 +3055,10 @@ 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)) {
- if (!PE_CHK_FLAG(port, PE_FLAGS_FAST_ROLE_SWAP))
+ if (!PE_CHK_FLAG(port, PE_FLAGS_FAST_ROLE_SWAP_PATH)) {
/* Contract is invalid now */
- PE_CLR_FLAG(port, PE_FLAGS_EXPLICIT_CONTRACT);
+ pe_invalidate_explicit_contract(port);
+ }
set_state_pe(port, PE_PRS_SNK_SRC_SOURCE_ON);
}
@@ -3058,7 +3136,7 @@ static void pe_prs_snk_src_send_swap_entry(int port)
*/
prl_send_ctrl_msg(port,
TCPC_TX_SOP,
- PE_CHK_FLAG(port, PE_FLAGS_FAST_ROLE_SWAP)
+ PE_CHK_FLAG(port, PE_FLAGS_FAST_ROLE_SWAP_PATH)
? PD_CTRL_FR_SWAP
: PD_CTRL_PR_SWAP);
@@ -3080,7 +3158,7 @@ static void pe_prs_snk_src_send_swap_run(int port)
*/
if (get_time().val > pe[port].sender_response_timer)
set_state_pe(port,
- PE_CHK_FLAG(port, PE_FLAGS_FAST_ROLE_SWAP)
+ PE_CHK_FLAG(port, PE_FLAGS_FAST_ROLE_SWAP_PATH)
? PE_WAIT_FOR_ERROR_RECOVERY
: PE_SNK_READY);
@@ -3108,7 +3186,7 @@ static void pe_prs_snk_src_send_swap_run(int port)
(type == PD_CTRL_WAIT))
set_state_pe(port,
PE_CHK_FLAG(port,
- PE_FLAGS_FAST_ROLE_SWAP)
+ PE_FLAGS_FAST_ROLE_SWAP_PATH)
? PE_WAIT_FOR_ERROR_RECOVERY
: PE_SNK_READY);
}
@@ -3129,14 +3207,13 @@ 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);
+ pe_invalidate_explicit_contract(port);
/* 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);
+ PE_SET_FLAG(port, PE_FLAGS_FAST_ROLE_SWAP_PATH);
set_state_pe(port, PE_PRS_SNK_SRC_SEND_SWAP);
}
@@ -3153,7 +3230,7 @@ static void pe_prs_frs_shared_entry(int port)
* 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);
+ PE_CLR_FLAG(port, PE_FLAGS_FAST_ROLE_SWAP_PATH);
}
static void pe_prs_frs_shared_exit(int port)
@@ -3162,7 +3239,7 @@ 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);
+ PE_CLR_FLAG(port, PE_FLAGS_FAST_ROLE_SWAP_PATH);
}
/**
@@ -4140,6 +4217,95 @@ static void pe_vcs_send_ps_rdy_swap_run(int port)
}
}
+/*
+ * PE_DR_SNK_Get_Sink_Cap
+ */
+static void pe_dr_snk_get_sink_cap_entry(int port)
+{
+ print_current_state(port);
+
+ /* Send a Get Sink Cap Message */
+ prl_send_ctrl_msg(port, TCPC_TX_SOP, PD_CTRL_GET_SINK_CAP);
+
+ /* Don't start the timer until message sent */
+ pe[port].sender_response_timer = 0;
+}
+
+static void pe_dr_snk_get_sink_cap_run(int port)
+{
+ int type;
+ int cnt;
+ int ext;
+ uint32_t payload;
+
+ /* Wait until message is sent */
+ if (pe[port].sender_response_timer == 0) {
+ if (PE_CHK_FLAG(port, PE_FLAGS_TX_COMPLETE)) {
+ PE_CLR_FLAG(port, PE_FLAGS_TX_COMPLETE);
+ /* start the SenderResponseTimer */
+ pe[port].sender_response_timer =
+ get_time().val + PD_T_SENDER_RESPONSE;
+ } else {
+ return;
+ }
+ }
+
+ /*
+ * Determine if FRS is possible based on the returned Sink Caps
+ * and transition to PE_SNK_Ready when:
+ * 1) An Accept Message is received.
+ *
+ * Transition to PE_SNK_Ready state when:
+ * 1) A Reject Message is received.
+ * 2) Or a Wait Message is received.
+ */
+ 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);
+ payload = *(uint32_t *)emsg[port].buf;
+
+ if ((ext == 0) && (cnt == 0)) {
+ if (type == PD_CTRL_ACCEPT) {
+ /*
+ * Check message to see if we can handle
+ * FRS for this connection.
+ *
+ * TODO(b/14191267): Make sure we can handle
+ * the required current before we enable FRS.
+ */
+ if (payload & PDO_FIXED_DUAL_ROLE) {
+ switch (payload &
+ PDO_FIXED_FRS_CURR_MASK) {
+ case PDO_FIXED_FRS_CURR_NOT_SUPPORTED:
+ break;
+ case PDO_FIXED_FRS_CURR_DFLT_USB_POWER:
+ case PDO_FIXED_FRS_CURR_1A5_AT_5V:
+ case PDO_FIXED_FRS_CURR_3A0_AT_5V:
+ pe_set_frs_enable(port, 1);
+ return;
+ }
+ }
+ set_state_pe(port, PE_SNK_READY);
+ return;
+ } else if ((type == PD_CTRL_REJECT) ||
+ (type == PD_CTRL_WAIT)) {
+ set_state_pe(port, PE_SNK_READY);
+ return;
+ }
+ }
+ }
+
+ /*
+ * Transition to PE_SNK_Ready state when:
+ * 1) SenderResponseTimer times out.
+ */
+ if (get_time().val > pe[port].sender_response_timer)
+ set_state_pe(port, PE_SNK_READY);
+}
+
/* Policy Engine utility functions */
int pd_check_requested_voltage(uint32_t rdo, const int port)
{
@@ -4980,6 +5146,10 @@ static const struct usb_state pe_states[] = {
.entry = pe_bist_entry,
.run = pe_bist_run,
},
+ [PE_DR_SNK_GET_SINK_CAP] = {
+ .entry = pe_dr_snk_get_sink_cap_entry,
+ .run = pe_dr_snk_get_sink_cap_run,
+ },
};
#ifdef TEST_BUILD
diff --git a/common/usbc/usb_tc_drp_acc_trysrc_sm.c b/common/usbc/usb_tc_drp_acc_trysrc_sm.c
index 60c6fa6ad0..08abf619a2 100644
--- a/common/usbc/usb_tc_drp_acc_trysrc_sm.c
+++ b/common/usbc/usb_tc_drp_acc_trysrc_sm.c
@@ -402,6 +402,11 @@ int pd_dev_store_rw_hash(int port, uint16_t dev_id, uint32_t *rw_hash,
return 0;
}
+void pd_got_frs_signal(int port)
+{
+ pe_got_frs_signal(port);
+}
+
int tc_is_attached_src(int port)
{
return get_state_tc(port) == TC_ATTACHED_SRC;
diff --git a/driver/tcpm/tcpci.h b/driver/tcpm/tcpci.h
index d2950b7b1a..491fe195ed 100644
--- a/driver/tcpm/tcpci.h
+++ b/driver/tcpm/tcpci.h
@@ -20,7 +20,7 @@
#define TCPC_REG_PD_INT_REV 0xa
#define TCPC_REG_ALERT 0x10
-#define TCPC_REG_ALERT_MASK_ALL 0xfff
+#define TCPC_REG_ALERT_MASK_ALL 0xffff
#define TCPC_REG_ALERT_VENDOR_DEF (1<<15)
#define TCPC_REG_ALERT_VBUS_DISCNCT (1<<11)
#define TCPC_REG_ALERT_RX_BUF_OVF (1<<10)
@@ -42,7 +42,6 @@
#define TCPC_REG_POWER_STATUS_MASK 0x14
#define TCPC_REG_FAULT_STATUS_MASK 0x15
#define TCPC_REG_CONFIG_STD_OUTPUT 0x18
-
#define TCPC_REG_CONFIG_STD_OUTPUT_MUX_MASK (3 << 2)
#define TCPC_REG_CONFIG_STD_OUTPUT_MUX_NONE (0 << 2)
#define TCPC_REG_CONFIG_STD_OUTPUT_MUX_USB BIT(2)
diff --git a/driver/tcpm/tcpm.h b/driver/tcpm/tcpm.h
index a5b029d700..51b315fb77 100644
--- a/driver/tcpm/tcpm.h
+++ b/driver/tcpm/tcpm.h
@@ -396,4 +396,23 @@ int tcpm_has_pending_message(int port);
*/
void tcpm_clear_pending_messages(int port);
+/**
+ * Enable/Disable TCPC Fast Role Swap detection
+ *
+ * @param port Type-C port number
+ * @param enable FRS enable (true) disable (false)
+ */
+static inline void tcpm_set_frs_enable(int port, int enable)
+{
+ const struct tcpm_drv *tcpc;
+
+ /*
+ * set_frs_enable will be set to tcpci_tcp_fast_role_swap_enable
+ * if it is handled by the tcpci for the tcpc chipset
+ */
+ tcpc = tcpc_config[port].drv;
+ if (tcpc->set_frs_enable)
+ tcpc->set_frs_enable(port, enable);
+}
+
#endif
diff --git a/include/config.h b/include/config.h
index 5c3385e97c..0c738e8a3c 100644
--- a/include/config.h
+++ b/include/config.h
@@ -3858,6 +3858,9 @@
/* Type-C DRP with Accessory and Try.SRC */
#undef CONFIG_USB_TYPEC_DRP_ACC_TRYSRC
+/* Type-C Fast Role Swap */
+#undef CONFIG_USB_TYPEC_PD_FAST_ROLE_SWAP
+
/* USB Product ID. */
#undef CONFIG_USB_PID
diff --git a/include/usb_pd.h b/include/usb_pd.h
index cf18a325d1..ca8b8e04ad 100644
--- a/include/usb_pd.h
+++ b/include/usb_pd.h
@@ -98,6 +98,11 @@ enum pd_rx_errors {
#define PDO_FIXED_EXTERNAL BIT(27) /* Externally powered */
#define PDO_FIXED_COMM_CAP BIT(26) /* USB Communications Capable */
#define PDO_FIXED_DATA_SWAP BIT(25) /* Data role swap command supported */
+#define PDO_FIXED_FRS_CURR_MASK (3 << 23) /* [23..24] FRS current */
+#define PDO_FIXED_FRS_CURR_NOT_SUPPORTED (0 << 23)
+#define PDO_FIXED_FRS_CURR_DFLT_USB_POWER (1 << 23)
+#define PDO_FIXED_FRS_CURR_1A5_AT_5V (2 << 23)
+#define PDO_FIXED_FRS_CURR_3A0_AT_5V (3 << 23)
#define PDO_FIXED_PEAK_CURR () /* [21..20] Peak current */
#define PDO_FIXED_VOLT(mv) (((mv)/50) << 10) /* Voltage in 50mV units */
#define PDO_FIXED_CURR(ma) (((ma)/10) << 0) /* Max current in 10mA units */
@@ -1788,6 +1793,13 @@ int pd_dev_store_rw_hash(int port, uint16_t dev_id, uint32_t *rw_hash,
uint32_t ec_current_image);
/**
+ * Fast Role Swap was detected
+ *
+ * @param port USB-C port number
+ */
+void pd_got_frs_signal(int port);
+
+/**
* Try to fetch one PD log entry from accessory
*
* @param port USB-C accessory port number
diff --git a/include/usb_pd_tcpm.h b/include/usb_pd_tcpm.h
index 18effd0661..67c230b79b 100644
--- a/include/usb_pd_tcpm.h
+++ b/include/usb_pd_tcpm.h
@@ -324,6 +324,14 @@ struct tcpm_drv {
*/
int (*enter_low_power_mode)(int port);
#endif
+
+ /**
+ * Enable/Disable TCPC FRS detection
+ *
+ * @param port Type-C port number
+ * @param enable FRS enable (true) disable (false)
+ */
+ void (*set_frs_enable)(int port, int enable);
};
/*
diff --git a/include/usb_pe_sm.h b/include/usb_pe_sm.h
index 21226cbe9c..0a51ce5fa3 100644
--- a/include/usb_pe_sm.h
+++ b/include/usb_pe_sm.h
@@ -98,6 +98,13 @@ void pe_got_soft_reset(int port);
void pe_hard_reset_sent(int port);
/**
+ * Informs the Policy Engine that a Fast Role Swap signal was detected
+ *
+ * @param port USB-C port number
+ */
+void pe_got_frs_signal(int port);
+
+/**
* Exit DP mode
*
* @param port USB-C port number