summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/usb_pd_dual_role.c45
-rw-r--r--common/usb_pd_protocol.c52
-rw-r--r--common/usbc/usb_pe_drp_sm.c106
-rw-r--r--common/usbc/usb_tc_drp_acc_trysrc_sm.c81
-rw-r--r--include/system.h3
-rw-r--r--include/usb_common.h18
-rw-r--r--include/usb_pd.h1
-rw-r--r--include/usb_pe_sm.h12
-rw-r--r--test/fake_usbc.c4
9 files changed, 226 insertions, 96 deletions
diff --git a/common/usb_pd_dual_role.c b/common/usb_pd_dual_role.c
index 73e56f30eb..a424555b26 100644
--- a/common/usb_pd_dual_role.c
+++ b/common/usb_pd_dual_role.c
@@ -7,6 +7,7 @@
#include "charge_manager.h"
#include "charge_state.h"
+#include "system.h"
#include "usb_common.h"
#include "usb_pd.h"
#include "util.h"
@@ -391,3 +392,47 @@ bool pd_is_try_source_capable(void)
return new_try_src;
}
#endif /* CONFIG_USB_PD_TRY_SRC */
+
+static int get_bbram_idx(uint8_t port)
+{
+ if (port < MAX_SYSTEM_BBRAM_IDX_PD_PORTS)
+ return (port + SYSTEM_BBRAM_IDX_PD0);
+
+ return -1;
+}
+
+int pd_get_saved_port_flags(int port, uint8_t *flags)
+{
+ if (system_get_bbram(get_bbram_idx(port), flags) != EC_SUCCESS) {
+#ifndef CHIP_HOST
+ ccprintf("PD NVRAM FAIL");
+#endif
+ return EC_ERROR_UNKNOWN;
+ }
+
+ return EC_SUCCESS;
+}
+
+static void pd_set_saved_port_flags(int port, uint8_t flags)
+{
+ if (system_set_bbram(get_bbram_idx(port), flags) != EC_SUCCESS) {
+#ifndef CHIP_HOST
+ ccprintf("PD NVRAM FAIL");
+#endif
+ }
+}
+
+void pd_update_saved_port_flags(int port, uint8_t flag, uint8_t do_set)
+{
+ uint8_t saved_flags;
+
+ if (pd_get_saved_port_flags(port, &saved_flags) != EC_SUCCESS)
+ return;
+
+ if (do_set)
+ saved_flags |= flag;
+ else
+ saved_flags &= ~flag;
+
+ pd_set_saved_port_flags(port, saved_flags);
+}
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c
index 82e0a1e0e4..80e89017e1 100644
--- a/common/usb_pd_protocol.c
+++ b/common/usb_pd_protocol.c
@@ -575,58 +575,6 @@ static int reset_device_and_notify(int port)
#endif /* CONFIG_USB_PD_TCPC_LOW_POWER */
-#ifdef CONFIG_USB_PD_DUAL_ROLE
-static int get_bbram_idx(int port)
-{
- switch (port) {
- case 2:
- return SYSTEM_BBRAM_IDX_PD2;
- case 1:
- return SYSTEM_BBRAM_IDX_PD1;
- case 0:
- return SYSTEM_BBRAM_IDX_PD0;
- default:
- return -1;
- }
-}
-
-static int pd_get_saved_port_flags(int port, uint8_t *flags)
-{
- if (system_get_bbram(get_bbram_idx(port), flags) != EC_SUCCESS) {
-#ifndef CHIP_HOST
- CPRINTS("PD NVRAM FAIL");
-#endif
- return EC_ERROR_UNKNOWN;
- }
-
- return EC_SUCCESS;
-}
-
-static void pd_set_saved_port_flags(int port, uint8_t flags)
-{
- if (system_set_bbram(get_bbram_idx(port), flags) != EC_SUCCESS) {
-#ifndef CHIP_HOST
- CPRINTS("PD NVRAM FAIL");
-#endif
- }
-}
-
-static void pd_update_saved_port_flags(int port, uint8_t flag, uint8_t val)
-{
- uint8_t saved_flags;
-
- if (pd_get_saved_port_flags(port, &saved_flags) != EC_SUCCESS)
- return;
-
- if (val)
- saved_flags |= flag;
- else
- saved_flags &= ~flag;
-
- pd_set_saved_port_flags(port, saved_flags);
-}
-#endif /* defined(CONFIG_USB_PD_DUAL_ROLE) */
-
/**
* Invalidate last message received at the port when the port gets disconnected
* or reset(soft/hard). This is used to identify and handle the duplicate
diff --git a/common/usbc/usb_pe_drp_sm.c b/common/usbc/usb_pe_drp_sm.c
index e570e27ce2..f16e4d3958 100644
--- a/common/usbc/usb_pe_drp_sm.c
+++ b/common/usbc/usb_pe_drp_sm.c
@@ -153,6 +153,9 @@
*/
typedef int (*svdm_rsp_func)(int port, uint32_t *payload);
+/* This is true only if a sysjump has occurred */
+static bool sysjump_occurred;
+
/* List of all Policy Engine level states */
enum usb_pe_state {
/* Normal States */
@@ -587,6 +590,11 @@ void pe_run(int port, int evt, int en)
}
}
+void pe_set_sysjump(void)
+{
+ sysjump_occurred = true;
+}
+
int pe_is_explicit_contract(int port)
{
return PE_CHK_FLAG(port, PE_FLAGS_EXPLICIT_CONTRACT);
@@ -672,10 +680,11 @@ static void pe_set_frs_enable(int port, int enable)
}
}
-static void pe_invalidate_explicit_contract(int port)
+void pe_invalidate_explicit_contract(int port)
{
pe_set_frs_enable(port, 0);
PE_CLR_FLAG(port, PE_FLAGS_EXPLICIT_CONTRACT);
+ pd_update_saved_port_flags(port, PD_BBRMFLG_EXPLICIT_CONTRACT, 0);
}
/*
@@ -833,9 +842,6 @@ void pe_send_vdm(int port, uint32_t vid, int cmd, const uint32_t *data,
void pe_exit_dp_mode(int port)
{
- /* This should only be called from the PD task */
- assert(port == TASK_ID_TO_PD_PORT(task_get_current()));
-
if (IS_ENABLED(CONFIG_USB_PD_ALT_MODE_DFP)) {
int opos = pd_alt_mode(port, USB_SID_DISPLAYPORT);
@@ -1544,6 +1550,8 @@ static void pe_src_transition_supply_run(int port)
/* NOTE: Second pass through this code block */
/* Explicit Contract is now in place */
PE_SET_FLAG(port, PE_FLAGS_EXPLICIT_CONTRACT);
+ pd_update_saved_port_flags(port,
+ PD_BBRMFLG_EXPLICIT_CONTRACT, 1);
/*
* Set first message flag to trigger a wait and add
* jitter delay when operating in PD2.0 mode.
@@ -1986,8 +1994,14 @@ static void pe_snk_startup_entry(int port)
/* Set initial power role */
pe[port].power_role = PD_ROLE_SINK;
- /* Clear explicit contract */
- pe_invalidate_explicit_contract(port);
+ /*
+ * An explicit contract must be maintained across sysjumps,
+ * so do not invalidate it if a sysjump has occurred
+ */
+ if (!sysjump_occurred) {
+ /* Invalidate explicit contract */
+ pe_invalidate_explicit_contract(port);
+ }
if (PE_CHK_FLAG(port, PE_FLAGS_PR_SWAP_COMPLETE)) {
PE_CLR_FLAG(port, PE_FLAGS_PR_SWAP_COMPLETE);
@@ -2008,11 +2022,22 @@ static void pe_snk_startup_run(int port)
if (!prl_is_running(port))
return;
- /*
- * Once the reset process completes, the Policy Engine Shall
- * transition to the PE_SNK_Discovery state
- */
- set_state_pe(port, PE_SNK_DISCOVERY);
+ /* Soft reset the charger on sysjump */
+ if (sysjump_occurred) {
+ /*
+ * The sysjump flag is no longer needed, so clear it.
+ * After Soft Reset is sent, PE_ATTACHED_SNK state
+ * is entered.
+ */
+ sysjump_occurred = false;
+ set_state_pe(port, PE_SEND_SOFT_RESET);
+ } else {
+ /*
+ * Once the reset process completes, the Policy Engine Shall
+ * transition to the PE_SNK_Discovery state
+ */
+ set_state_pe(port, PE_SNK_DISCOVERY);
+ }
}
/**
@@ -2110,10 +2135,6 @@ static void pe_snk_evaluate_capability_entry(int port)
/* Evaluate the options based on supplied capabilities */
pd_process_source_cap(port, pe[port].src_cap_cnt, pe[port].src_caps);
- /* We are PD Connected */
- PE_SET_FLAG(port, PE_FLAGS_PD_CONNECTION);
- tc_pd_connection(port, 1);
-
/* Device Policy Response Received */
set_state_pe(port, PE_SNK_SELECT_CAPABILITY);
}
@@ -2125,9 +2146,13 @@ static void pe_snk_select_capability_entry(int port)
{
print_current_state(port);
- pe[port].sender_response_timer = TIMER_DISABLED;
/* Send Request */
pe_send_request_msg(port);
+
+ /* We are PD Connected */
+ PE_SET_FLAG(port, PE_FLAGS_PD_CONNECTION);
+ tc_pd_connection(port, 1);
+ pe[port].sender_response_timer = TIMER_DISABLED;
}
static void pe_snk_select_capability_run(int port)
@@ -2178,6 +2203,9 @@ static void pe_snk_select_capability_run(int port)
if (type == PD_CTRL_ACCEPT) {
/* explicit contract is now in place */
PE_SET_FLAG(port, PE_FLAGS_EXPLICIT_CONTRACT);
+ pd_update_saved_port_flags(port,
+ PD_BBRMFLG_EXPLICIT_CONTRACT, 1);
+
set_state_pe(port, PE_SNK_TRANSITION_SINK);
/*
@@ -2316,14 +2344,14 @@ static void pe_snk_ready_entry(int port)
prl_end_ams(port);
/*
- * On entry to the PE_SNK_Ready state as the result of a wait, then do
- * the following:
+ * On entry to the PE_SNK_Ready state as the result of a wait,
+ * then do the following:
* 1) Initialize and run the SinkRequestTimer
*/
if (PE_CHK_FLAG(port, PE_FLAGS_WAIT)) {
PE_CLR_FLAG(port, PE_FLAGS_WAIT);
pe[port].sink_request_timer =
- get_time().val + PD_T_SINK_REQUEST;
+ get_time().val + PD_T_SINK_REQUEST;
} else {
pe[port].sink_request_timer = TIMER_DISABLED;
}
@@ -2331,14 +2359,15 @@ static void pe_snk_ready_entry(int port)
/*
* Do port partner discovery
*
- * This function modifies state variables that are used in the run
- * part of this state. See pe_attempt_port_discovery for details.
+ * This function modifies state variables that are used in
+ * the run part of this state. See pe_attempt_port_discovery
+ * for details.
*/
pe_attempt_port_discovery(port);
/*
- * Wait and add jitter if we are operating in PD2.0 mode and no messages
- * have been sent since enter this state.
+ * Wait and add jitter if we are operating in PD2.0 mode and no
+ * messages have been sent since enter this state.
*/
pe_update_wait_and_add_jitter_timer(port);
}
@@ -2677,21 +2706,6 @@ static void pe_send_soft_reset_run(int port)
}
/*
- * Transition to PE_SNK_Hard_Reset or PE_SRC_Hard_Reset on Sender
- * Response Timer Timeout or Protocol Layer or Protocol Error
- */
- if (get_time().val > pe[port].sender_response_timer ||
- PE_CHK_FLAG(port, PE_FLAGS_PROTOCOL_ERROR)) {
- PE_CLR_FLAG(port, PE_FLAGS_PROTOCOL_ERROR);
-
- if (pe[port].power_role == PD_ROLE_SINK)
- set_state_pe(port, PE_SRC_HARD_RESET);
- else
- set_state_pe(port, PE_SRC_HARD_RESET);
- return;
- }
-
- /*
* Transition to the PE_SNK_Send_Capabilities or
* PE_SRC_Send_Capabilities state when:
* 1) An Accept Message has been received.
@@ -2713,6 +2727,22 @@ static void pe_send_soft_reset_run(int port)
return;
}
}
+
+ /*
+ * Transition to PE_SNK_Hard_Reset or PE_SRC_Hard_Reset on Sender
+ * Response Timer Timeout or Protocol Layer or Protocol Error
+ */
+ if (get_time().val > pe[port].sender_response_timer ||
+ PE_CHK_FLAG(port, PE_FLAGS_PROTOCOL_ERROR)) {
+ PE_CLR_FLAG(port, PE_FLAGS_PROTOCOL_ERROR);
+
+ if (pe[port].power_role == PD_ROLE_SINK)
+ set_state_pe(port, PE_SRC_HARD_RESET);
+ else
+ set_state_pe(port, PE_SRC_HARD_RESET);
+ return;
+ }
+
}
static void pe_send_soft_reset_exit(int port)
diff --git a/common/usbc/usb_tc_drp_acc_trysrc_sm.c b/common/usbc/usb_tc_drp_acc_trysrc_sm.c
index c18eff6219..b8ceb5b7da 100644
--- a/common/usbc/usb_tc_drp_acc_trysrc_sm.c
+++ b/common/usbc/usb_tc_drp_acc_trysrc_sm.c
@@ -262,6 +262,8 @@ enum pd_dual_role_states drp_state[CONFIG_USB_PD_PORT_MAX_COUNT] = {
[0 ... (CONFIG_USB_PD_PORT_MAX_COUNT - 1)] =
CONFIG_USB_PD_INITIAL_DRP_STATE};
+static uint8_t saved_flgs[CONFIG_USB_PD_PORT_MAX_COUNT];
+
#ifdef CONFIG_USBC_VCONN
static void set_vconn(int port, int enable);
#endif
@@ -1022,8 +1024,54 @@ static void restart_tc_sm(int port, enum usb_tc_state start_state)
void tc_state_init(int port)
{
- /* Unattached.SNK is the default starting state. */
- restart_tc_sm(port, TC_UNATTACHED_SNK);
+ /*
+ * If there's an explicit contract in place, let's restore the data and
+ * power roles such that any messages we send to the port partner will
+ * still be valid.
+ */
+ if (pd_comm_is_enabled(port) &&
+ (pd_get_saved_port_flags(port, &saved_flgs[port]) ==
+ EC_SUCCESS) &&
+ (saved_flgs[port] & PD_BBRMFLG_EXPLICIT_CONTRACT)) {
+ /* Only attempt to maintain previous sink contracts */
+ if ((saved_flgs[port] & PD_BBRMFLG_POWER_ROLE) ==
+ PD_ROLE_SINK) {
+ tc_set_power_role(port,
+ (saved_flgs[port] & PD_BBRMFLG_POWER_ROLE) ?
+ PD_ROLE_SOURCE : PD_ROLE_SINK);
+ tc_set_data_role(port,
+ (saved_flgs[port] & PD_BBRMFLG_DATA_ROLE) ?
+ PD_ROLE_DFP : PD_ROLE_UFP);
+#ifdef CONFIG_USBC_VCONN
+ set_vconn(port,
+ (saved_flgs[port] & PD_BBRMFLG_VCONN_ROLE) ?
+ PD_ROLE_VCONN_ON : PD_ROLE_VCONN_OFF);
+#endif /* CONFIG_USBC_VCONN */
+ if (IS_ENABLED(CONFIG_USB_PE_SM))
+ pe_set_sysjump();
+
+ set_state_tc(port, TC_ATTACHED_SNK);
+ } else {
+ restart_tc_sm(port, TC_UNATTACHED_SNK);
+ /*
+ * Vbus was turned off during the power supply reset
+ * earlier, so clear the contract flag and re-start as
+ * default role
+ */
+ pd_update_saved_port_flags(port,
+ PD_BBRMFLG_EXPLICIT_CONTRACT, 0);
+ }
+ /*
+ * Set the TCPC reset event such that we can set our CC
+ * terminations, determine polarity, and enable RX so we
+ * can hear back from our port partner if maintaining our old
+ * connection.
+ */
+ task_set_event(task_get_current(), PD_EVENT_TCPC_RESET, 0);
+ } else {
+ /* Unattached.SNK is the default starting state. */
+ restart_tc_sm(port, TC_UNATTACHED_SNK);
+ }
/*
* If the TCPC isn't accessed, it will enter low power mode
@@ -1076,6 +1124,7 @@ uint8_t tc_get_pd_enabled(int port)
void tc_set_power_role(int port, enum pd_power_role role)
{
tc[port].power_role = role;
+ pd_update_saved_port_flags(port, PD_BBRMFLG_POWER_ROLE, role);
}
/*
@@ -1133,10 +1182,19 @@ void tc_event_check(int port, int evt)
}
#endif /* CONFIG_POWER_COMMON */
#ifdef CONFIG_USB_PD_ALT_MODE_DFP
- if (IS_ENABLED(CONFIG_USB_PD_ALT_MODE_DFP)) {
- if (evt & PD_EVENT_SYSJUMP) {
- pe_exit_dp_mode(port);
- notify_sysjump_ready(&sysjump_task_waiting);
+ {
+ int i;
+
+ if (IS_ENABLED(CONFIG_USB_PD_ALT_MODE_DFP)) {
+ /*
+ * Notify all ports of sysjump
+ */
+ if (evt & PD_EVENT_SYSJUMP) {
+ for (i = 0; i <
+ CONFIG_USB_PD_PORT_MAX_COUNT; i++)
+ pe_exit_dp_mode(i);
+ notify_sysjump_ready(&sysjump_task_waiting);
+ }
}
}
#endif
@@ -1163,6 +1221,8 @@ void tc_set_data_role(int port, enum pd_data_role role)
{
tc[port].data_role = role;
+ pd_update_saved_port_flags(port, PD_BBRMFLG_DATA_ROLE, role);
+
if (IS_ENABLED(CONFIG_USBC_SS_MUX))
set_usb_mux_with_current_data_role(port);
@@ -1210,6 +1270,8 @@ static void set_vconn(int port, int enable)
else
TC_CLR_FLAG(port, TC_FLAGS_VCONN_ON);
+ pd_update_saved_port_flags(port, PD_BBRMFLG_VCONN_ROLE, enable);
+
/*
* TODO(chromium:951681): When we are sourcing VCONN, we should make
* sure to remove our termination on that CC line first.
@@ -1647,6 +1709,13 @@ static void tc_unattached_snk_entry(const int port)
print_current_state(port);
}
+ /*
+ * Tell Policy Engine to invalidate the explicit contract.
+ * This mainly used to clear the BB Ram Explicit Contract
+ * value.
+ */
+ pe_invalidate_explicit_contract(port);
+
tc[port].data_role = PD_ROLE_DISCONNECTED;
/*
diff --git a/include/system.h b/include/system.h
index ced5446eee..03a2c15238 100644
--- a/include/system.h
+++ b/include/system.h
@@ -355,6 +355,9 @@ enum system_bbram_idx {
SYSTEM_BBRAM_IDX_TRY_SLOT,
};
+/* Maximum number of bbram indexes allotted for PD port state data */
+#define MAX_SYSTEM_BBRAM_IDX_PD_PORTS 3
+
/**
* Get/Set byte in battery-backed storage.
*
diff --git a/include/usb_common.h b/include/usb_common.h
index 5078ff071e..be7ead8055 100644
--- a/include/usb_common.h
+++ b/include/usb_common.h
@@ -159,4 +159,22 @@ void notify_sysjump_ready(volatile const task_id_t * const
* @param port USB-C port number
*/
void set_usb_mux_with_current_data_role(int port);
+
+/**
+ * Get the PD flags stored in BB Ram
+ *
+ * @param port USB-C port number
+ * @param flags pointer where flags are written to
+ * @return EC_SUCCESS on success
+ */
+int pd_get_saved_port_flags(int port, uint8_t *flags);
+
+/**
+ * Update the flag in BB Ram with the give value
+ *
+ * @param port USB-C port number
+ * @param flag BB Ram flag to update
+ * @param do_set value written to the BB Ram flag
+ */
+void pd_update_saved_port_flags(int port, uint8_t flag, uint8_t do_set);
#endif /* __CROS_EC_USB_COMMON_H */
diff --git a/include/usb_pd.h b/include/usb_pd.h
index 319d3471fe..1d32b86da0 100644
--- a/include/usb_pd.h
+++ b/include/usb_pd.h
@@ -228,6 +228,7 @@ enum pd_rx_errors {
#define PD_T_SRC_DISCONNECT (15*MSEC) /* 15ms */
#define PD_T_VCONN_STABLE (50*MSEC) /* 50ms */
#define PD_T_DISCOVER_IDENTITY (45*MSEC) /* between 40ms and 50ms */
+#define PD_T_SYSJUMP (1000*MSEC) /* 1s */
/* number of edges and time window to detect CC line is not idle */
#define PD_RX_TRANSITION_COUNT 3
diff --git a/include/usb_pe_sm.h b/include/usb_pe_sm.h
index c22103efa4..2a9d466b2e 100644
--- a/include/usb_pe_sm.h
+++ b/include/usb_pe_sm.h
@@ -177,5 +177,17 @@ void pe_dpm_request(int port, enum pe_dpm_request req);
*/
int pd_is_port_partner_dualrole(int port);
+/*
+ * Informs the Policy Engine that a sysjump has occurred
+ */
+void pe_set_sysjump(void);
+
+/*
+ * Informs the Policy Engine that it should invalidate the
+ * explicit contract.
+ *
+ * @param port USB-C port number
+ */
+void pe_invalidate_explicit_contract(int port);
#endif /* __CROS_EC_USB_PE_H */
diff --git a/test/fake_usbc.c b/test/fake_usbc.c
index 73c992676b..a096652020 100644
--- a/test/fake_usbc.c
+++ b/test/fake_usbc.c
@@ -126,6 +126,10 @@ __overridable void tc_start_error_recovery(int port)
__overridable void tc_snk_power_off(int port)
{}
+__overridable void pe_invalidate_explicit_contract(int port)
+{
+}
+
int pd_dev_store_rw_hash(int port, uint16_t dev_id, uint32_t *rw_hash,
uint32_t ec_image)
{