diff options
-rw-r--r-- | common/usb_pd_dual_role.c | 45 | ||||
-rw-r--r-- | common/usb_pd_protocol.c | 52 | ||||
-rw-r--r-- | common/usbc/usb_pe_drp_sm.c | 106 | ||||
-rw-r--r-- | common/usbc/usb_tc_drp_acc_trysrc_sm.c | 81 | ||||
-rw-r--r-- | include/system.h | 3 | ||||
-rw-r--r-- | include/usb_common.h | 18 | ||||
-rw-r--r-- | include/usb_pd.h | 1 | ||||
-rw-r--r-- | include/usb_pe_sm.h | 12 | ||||
-rw-r--r-- | test/fake_usbc.c | 4 |
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) { |