diff options
Diffstat (limited to 'common/usbc/usb_pd_dpm.c')
-rw-r--r-- | common/usbc/usb_pd_dpm.c | 344 |
1 files changed, 276 insertions, 68 deletions
diff --git a/common/usbc/usb_pd_dpm.c b/common/usbc/usb_pd_dpm.c index 159331171e..8141e92fd7 100644 --- a/common/usbc/usb_pd_dpm.c +++ b/common/usbc/usb_pd_dpm.c @@ -1,4 +1,4 @@ -/* Copyright 2020 The Chromium OS Authors. All rights reserved. +/* Copyright 2020 The ChromiumOS Authors * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ @@ -8,12 +8,15 @@ * Refer to USB PD 3.0 spec, version 2.0, sections 8.2 and 8.3 */ +#include "builtin/assert.h" #include "charge_state.h" +#include "chipset.h" #include "compile_time_macros.h" #include "console.h" #include "ec_commands.h" #include "hooks.h" #include "power.h" +#include "power_button.h" #include "system.h" #include "task.h" #include "tcpm/tcpm.h" @@ -23,8 +26,9 @@ #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_pd_tcpm.h" +#include "usb_pd_timer.h" #include "usb_pe_sm.h" #include "usb_tbt_alt_mode.h" @@ -33,8 +37,8 @@ #endif #ifdef CONFIG_COMMON_RUNTIME -#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) -#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) +#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ##args) +#define CPRINTS(format, args...) cprints(CC_USBPD, format, ##args) #else #define CPRINTF(format, args...) #define CPRINTS(format, args...) @@ -48,6 +52,7 @@ static struct { uint32_t vdm_attention[DPM_ATTENION_MAX_VDO]; int vdm_cnt; mutex_t vdm_attention_mutex; + enum dpm_pd_button_state pd_button_state; } dpm[CONFIG_USB_PD_PORT_MAX_COUNT]; #define DPM_SET_FLAG(port, flag) atomic_or(&dpm[(port)].flags, (flag)) @@ -55,16 +60,18 @@ static struct { #define DPM_CHK_FLAG(port, flag) (dpm[(port)].flags & (flag)) /* Flags for internal DPM state */ -#define DPM_FLAG_MODE_ENTRY_DONE BIT(0) -#define DPM_FLAG_EXIT_REQUEST BIT(1) -#define DPM_FLAG_ENTER_DP BIT(2) -#define DPM_FLAG_ENTER_TBT BIT(3) -#define DPM_FLAG_ENTER_USB4 BIT(4) -#define DPM_FLAG_ENTER_ANY (DPM_FLAG_ENTER_DP | DPM_FLAG_ENTER_TBT \ - | DPM_FLAG_ENTER_USB4) -#define DPM_FLAG_SEND_ATTENTION BIT(5) +#define DPM_FLAG_MODE_ENTRY_DONE BIT(0) +#define DPM_FLAG_EXIT_REQUEST BIT(1) +#define DPM_FLAG_ENTER_DP BIT(2) +#define DPM_FLAG_ENTER_TBT BIT(3) +#define DPM_FLAG_ENTER_USB4 BIT(4) +#define DPM_FLAG_ENTER_ANY \ + (DPM_FLAG_ENTER_DP | DPM_FLAG_ENTER_TBT | DPM_FLAG_ENTER_USB4) +#define DPM_FLAG_SEND_ATTENTION BIT(5) #define DPM_FLAG_DATA_RESET_REQUESTED BIT(6) -#define DPM_FLAG_DATA_RESET_DONE BIT(7) +#define DPM_FLAG_DATA_RESET_DONE BIT(7) +#define DPM_FLAG_PD_BUTTON_PRESSED BIT(8) +#define DPM_FLAG_PD_BUTTON_RELEASED BIT(9) #ifdef CONFIG_ZEPHYR static int init_vdm_attention_mutex(const struct device *dev) @@ -81,6 +88,11 @@ static int init_vdm_attention_mutex(const struct device *dev) SYS_INIT(init_vdm_attention_mutex, POST_KERNEL, 50); #endif /* CONFIG_ZEPHYR */ +__overridable bool board_is_tbt_usb4_port(int port) +{ + return true; +} + enum ec_status pd_request_vdm_attention(int port, const uint32_t *data, int vdo_count) { @@ -120,17 +132,22 @@ enum ec_status pd_request_enter_mode(int port, enum typec_mode mode) return EC_RES_INVALID_PARAM; /* Only one enter request may be active at a time. */ - if (DPM_CHK_FLAG(port, DPM_FLAG_ENTER_DP | - DPM_FLAG_ENTER_TBT | - DPM_FLAG_ENTER_USB4)) + if (DPM_CHK_FLAG(port, DPM_FLAG_ENTER_DP | DPM_FLAG_ENTER_TBT | + DPM_FLAG_ENTER_USB4)) return EC_RES_BUSY; switch (mode) { case TYPEC_MODE_DP: + if (dp_is_idle(port)) + dp_init(port); DPM_SET_FLAG(port, DPM_FLAG_ENTER_DP); break; #ifdef CONFIG_USB_PD_TBT_COMPAT_MODE case TYPEC_MODE_TBT: + /* TODO(b/235984702#comment21): Refactor alt mode modules + * to better support mode reentry. */ + if (dp_is_idle(port)) + dp_init(port); DPM_SET_FLAG(port, DPM_FLAG_ENTER_TBT); break; #endif /* CONFIG_USB_PD_TBT_COMPAT_MODE */ @@ -153,19 +170,20 @@ enum ec_status pd_request_enter_mode(int port, enum typec_mode mode) void dpm_init(int port) { dpm[port].flags = 0; + dpm[port].pd_button_state = DPM_PD_BUTTON_IDLE; } void dpm_mode_exit_complete(int port) { DPM_CLR_FLAG(port, DPM_FLAG_MODE_ENTRY_DONE | DPM_FLAG_EXIT_REQUEST | - DPM_FLAG_SEND_ATTENTION); + DPM_FLAG_SEND_ATTENTION); } static void dpm_set_mode_entry_done(int port) { DPM_SET_FLAG(port, DPM_FLAG_MODE_ENTRY_DONE); DPM_CLR_FLAG(port, DPM_FLAG_ENTER_DP | DPM_FLAG_ENTER_TBT | - DPM_FLAG_ENTER_USB4); + DPM_FLAG_ENTER_USB4); } void dpm_set_mode_exit_request(int port) @@ -210,7 +228,7 @@ static bool dpm_mode_entry_requested(int port, enum typec_mode mode) } void dpm_vdm_acked(int port, enum tcpci_msg_type type, int vdo_count, - uint32_t *vdm) + uint32_t *vdm) { const uint16_t svid = PD_VDO_VID(vdm[0]); @@ -227,12 +245,12 @@ void dpm_vdm_acked(int port, enum tcpci_msg_type type, int vdo_count, } default: CPRINTS("C%d: Received unexpected VDM ACK for SVID %d", port, - svid); + svid); } } void dpm_vdm_naked(int port, enum tcpci_msg_type type, uint16_t svid, - uint8_t vdm_cmd) + uint8_t vdm_cmd) { switch (svid) { case USB_SID_DISPLAYPORT: @@ -245,7 +263,7 @@ void dpm_vdm_naked(int port, enum tcpci_msg_type type, uint16_t svid, } default: CPRINTS("C%d: Received unexpected VDM NAK for SVID %d", port, - svid); + svid); } } @@ -261,16 +279,15 @@ static void dpm_attempt_mode_entry(int port) uint32_t vdm[VDO_MAX_SIZE]; enum tcpci_msg_type tx_type = TCPCI_MSG_SOP; bool enter_mode_requested = - IS_ENABLED(CONFIG_USB_PD_REQUIRE_AP_MODE_ENTRY) ? false : true; + 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 | - DPM_FLAG_ENTER_TBT | - DPM_FLAG_ENTER_USB4)) + if (DPM_CHK_FLAG(port, DPM_FLAG_ENTER_DP | DPM_FLAG_ENTER_TBT | + DPM_FLAG_ENTER_USB4)) DPM_CLR_FLAG(port, DPM_FLAG_ENTER_DP | - DPM_FLAG_ENTER_TBT | - DPM_FLAG_ENTER_USB4); + DPM_FLAG_ENTER_TBT | + DPM_FLAG_ENTER_USB4); /* * TODO(b/168030639): Notify the AP that the enter mode request * failed. @@ -298,9 +315,9 @@ static void dpm_attempt_mode_entry(int port) return; if (dp_entry_is_done(port) || - (IS_ENABLED(CONFIG_USB_PD_TBT_COMPAT_MODE) && - tbt_entry_is_done(port)) || - (IS_ENABLED(CONFIG_USB_PD_USB4) && enter_usb_entry_is_done(port))) { + (IS_ENABLED(CONFIG_USB_PD_TBT_COMPAT_MODE) && + tbt_entry_is_done(port)) || + (IS_ENABLED(CONFIG_USB_PD_USB4) && enter_usb_entry_is_done(port))) { dpm_set_mode_entry_done(port); return; } @@ -314,24 +331,23 @@ static void dpm_attempt_mode_entry(int port) return; if (IS_ENABLED(CONFIG_USB_PD_REQUIRE_AP_MODE_ENTRY) && - IS_ENABLED(CONFIG_USB_PD_DATA_RESET_MSG) && - DPM_CHK_FLAG(port, DPM_FLAG_ENTER_ANY) && - !DPM_CHK_FLAG(port, DPM_FLAG_DATA_RESET_REQUESTED) && - !DPM_CHK_FLAG(port, DPM_FLAG_DATA_RESET_DONE)) { + IS_ENABLED(CONFIG_USB_PD_DATA_RESET_MSG) && + DPM_CHK_FLAG(port, DPM_FLAG_ENTER_ANY) && + !DPM_CHK_FLAG(port, DPM_FLAG_DATA_RESET_REQUESTED) && + !DPM_CHK_FLAG(port, DPM_FLAG_DATA_RESET_DONE)) { pd_dpm_request(port, DPM_REQUEST_DATA_RESET); DPM_SET_FLAG(port, DPM_FLAG_DATA_RESET_REQUESTED); return; } if (IS_ENABLED(CONFIG_USB_PD_REQUIRE_AP_MODE_ENTRY) && - IS_ENABLED(CONFIG_USB_PD_DATA_RESET_MSG) && - !DPM_CHK_FLAG(port, DPM_FLAG_DATA_RESET_DONE)) { + IS_ENABLED(CONFIG_USB_PD_DATA_RESET_MSG) && + !DPM_CHK_FLAG(port, DPM_FLAG_DATA_RESET_DONE)) { return; } /* Check if port, port partner and cable support USB4. */ - if (IS_ENABLED(CONFIG_USB_PD_USB4) && - board_is_tbt_usb4_port(port) && + if (IS_ENABLED(CONFIG_USB_PD_USB4) && board_is_tbt_usb4_port(port) && enter_usb_port_partner_is_capable(port) && enter_usb_cable_is_capable(port) && dpm_mode_entry_requested(port, TYPEC_MODE_USB4)) { @@ -351,14 +367,13 @@ static void dpm_attempt_mode_entry(int port) /* If not, check if they support Thunderbolt alt mode. */ if (IS_ENABLED(CONFIG_USB_PD_TBT_COMPAT_MODE) && - board_is_tbt_usb4_port(port) && - pd_is_mode_discovered_for_svid(port, TCPCI_MSG_SOP, - USB_VID_INTEL) && - dpm_mode_entry_requested(port, TYPEC_MODE_TBT)) { + board_is_tbt_usb4_port(port) && + pd_is_mode_discovered_for_svid(port, TCPCI_MSG_SOP, + USB_VID_INTEL) && + dpm_mode_entry_requested(port, TYPEC_MODE_TBT)) { enter_mode_requested = true; vdo_count = ARRAY_SIZE(vdm); - status = tbt_setup_next_vdm(port, &vdo_count, vdm, - &tx_type); + status = tbt_setup_next_vdm(port, &vdo_count, vdm, &tx_type); } /* If not, check if they support DisplayPort alt mode. */ @@ -381,7 +396,7 @@ static void dpm_attempt_mode_entry(int port) * just mark setup done and get out of here. */ if (status != MSG_SETUP_SUCCESS && - !DPM_CHK_FLAG(port, DPM_FLAG_MODE_ENTRY_DONE)) { + !DPM_CHK_FLAG(port, DPM_FLAG_MODE_ENTRY_DONE)) { if (enter_mode_requested) { /* * TODO(b/168030639): Notify the AP that mode entry @@ -427,9 +442,8 @@ static void dpm_attempt_mode_exit(int port) * is not supported, exit active modes individually. */ if (IS_ENABLED(CONFIG_USB_PD_DATA_RESET_MSG)) { - if (!DPM_CHK_FLAG(port, DPM_FLAG_DATA_RESET_REQUESTED) - && !DPM_CHK_FLAG(port, - DPM_FLAG_DATA_RESET_DONE)) { + if (!DPM_CHK_FLAG(port, DPM_FLAG_DATA_RESET_REQUESTED) && + !DPM_CHK_FLAG(port, DPM_FLAG_DATA_RESET_DONE)) { pd_dpm_request(port, DPM_REQUEST_DATA_RESET); DPM_SET_FLAG(port, DPM_FLAG_DATA_RESET_REQUESTED); return; @@ -495,6 +509,118 @@ static void dpm_send_attention_vdm(int port) DPM_CLR_FLAG(port, DPM_FLAG_SEND_ATTENTION); } +void dpm_handle_alert(int port, uint32_t ado) +{ + if (ado & ADO_EXTENDED_ALERT_EVENT) { + /* Extended Alert */ + if (pd_get_data_role(port) == PD_ROLE_DFP && + (ADO_EXTENDED_ALERT_EVENT_TYPE & ado) == + ADO_POWER_BUTTON_PRESS) { + DPM_SET_FLAG(port, DPM_FLAG_PD_BUTTON_PRESSED); + } else if (pd_get_data_role(port) == PD_ROLE_DFP && + (ADO_EXTENDED_ALERT_EVENT_TYPE & ado) == + ADO_POWER_BUTTON_RELEASE) { + DPM_SET_FLAG(port, DPM_FLAG_PD_BUTTON_RELEASED); + } + } +} + +static void dpm_run_pd_button_sm(int port) +{ +#ifdef CONFIG_AP_POWER_CONTROL + if (!IS_ENABLED(CONFIG_POWER_BUTTON_X86) && + !IS_ENABLED(CONFIG_CHIPSET_SC7180) && + !IS_ENABLED(CONFIG_CHIPSET_SC7280)) { + /* Insufficient chipset API support for USB PD power button. */ + DPM_CLR_FLAG(port, DPM_FLAG_PD_BUTTON_PRESSED); + DPM_CLR_FLAG(port, DPM_FLAG_PD_BUTTON_RELEASED); + return; + } + + /* + * Check for invalid flag combination. Alerts can only send a press or + * release event at once and only one flag should be set. If press and + * release flags are both set, we cannot know the order they were + * received. Clear the flags, disable the timer and return to an idle + * state. + */ + if (DPM_CHK_FLAG(port, DPM_FLAG_PD_BUTTON_PRESSED) && + DPM_CHK_FLAG(port, DPM_FLAG_PD_BUTTON_RELEASED)) { + DPM_CLR_FLAG(port, DPM_FLAG_PD_BUTTON_PRESSED | + DPM_FLAG_PD_BUTTON_RELEASED); + pd_timer_disable(port, DPM_TIMER_PD_BUTTON_SHORT_PRESS); + pd_timer_disable(port, DPM_TIMER_PD_BUTTON_LONG_PRESS); + dpm[port].pd_button_state = DPM_PD_BUTTON_IDLE; + return; + } + + switch (dpm[port].pd_button_state) { + case DPM_PD_BUTTON_IDLE: + if (DPM_CHK_FLAG(port, DPM_FLAG_PD_BUTTON_PRESSED)) { + pd_timer_enable(port, DPM_TIMER_PD_BUTTON_SHORT_PRESS, + CONFIG_USB_PD_SHORT_PRESS_MAX_MS * + MSEC); + pd_timer_enable(port, DPM_TIMER_PD_BUTTON_LONG_PRESS, + CONFIG_USB_PD_LONG_PRESS_MAX_MS * MSEC); + dpm[port].pd_button_state = DPM_PD_BUTTON_PRESSED; + } + break; + case DPM_PD_BUTTON_PRESSED: + if (DPM_CHK_FLAG(port, DPM_FLAG_PD_BUTTON_PRESSED)) { + pd_timer_enable(port, DPM_TIMER_PD_BUTTON_SHORT_PRESS, + CONFIG_USB_PD_SHORT_PRESS_MAX_MS * + MSEC); + pd_timer_enable(port, DPM_TIMER_PD_BUTTON_LONG_PRESS, + CONFIG_USB_PD_LONG_PRESS_MAX_MS * MSEC); + } else if (pd_timer_is_expired( + port, DPM_TIMER_PD_BUTTON_LONG_PRESS)) { + pd_timer_disable(port, DPM_TIMER_PD_BUTTON_SHORT_PRESS); + pd_timer_disable(port, DPM_TIMER_PD_BUTTON_LONG_PRESS); + dpm[port].pd_button_state = DPM_PD_BUTTON_IDLE; + } else if (DPM_CHK_FLAG(port, DPM_FLAG_PD_BUTTON_RELEASED)) { + if (chipset_in_state(CHIPSET_STATE_ANY_OFF)) { + /* + * Wake chipset on any button press when the + * system is off. + */ + chipset_power_on(); + } else if (chipset_in_state( + CHIPSET_STATE_ANY_SUSPEND) || + chipset_in_state(CHIPSET_STATE_ON)) { + if (pd_timer_is_expired( + port, + DPM_TIMER_PD_BUTTON_SHORT_PRESS)) { + /* + * Shutdown chipset on long USB PD power + * button press. + */ + chipset_force_shutdown( + CHIPSET_SHUTDOWN_BUTTON); + } else { + /* + * Simulate a short power button press + * on short USB PD power button press. + * This will wake the system from + * suspend, or bring up the power UI + * when the system is on. + */ + power_button_simulate_press( + USB_PD_SHORT_BUTTON_PRESS_MS); + } + } + pd_timer_disable(port, DPM_TIMER_PD_BUTTON_SHORT_PRESS); + pd_timer_disable(port, DPM_TIMER_PD_BUTTON_LONG_PRESS); + dpm[port].pd_button_state = DPM_PD_BUTTON_IDLE; + } + break; + } +#endif /* CONFIG_AP_POWER_CONTROL */ + + /* After checking flags, clear them. */ + DPM_CLR_FLAG(port, DPM_FLAG_PD_BUTTON_PRESSED); + DPM_CLR_FLAG(port, DPM_FLAG_PD_BUTTON_RELEASED); +} + void dpm_run(int port) { if (pd_get_data_role(port) == PD_ROLE_DFP) { @@ -503,6 +629,9 @@ void dpm_run(int port) dpm_attempt_mode_exit(port); else if (!DPM_CHK_FLAG(port, DPM_FLAG_MODE_ENTRY_DONE)) dpm_attempt_mode_entry(port); + + /* Run USB PD Power button state machine */ + dpm_run_pd_button_sm(port); } else { /* Run UFP related DPM requests */ if (DPM_CHK_FLAG(port, DPM_FLAG_SEND_ATTENTION)) @@ -523,7 +652,7 @@ void dpm_run(int port) * Note: request bitmasks should be accessed atomically as other ports may alter * them */ -static uint32_t max_current_claimed; +static uint32_t max_current_claimed; K_MUTEX_DEFINE(max_current_claimed_lock); /* Ports with PD sink needing > 1.5 A */ @@ -533,7 +662,10 @@ static atomic_t source_frs_max_requested; /* Ports with non-PD sinks, so current requirements are unknown */ static atomic_t non_pd_sink_max_requested; -#define LOWEST_PORT(p) __builtin_ctz(p) /* Undefined behavior if p == 0 */ +/* BIST shared test mode */ +static bool bist_shared_mode_enabled; + +#define LOWEST_PORT(p) __builtin_ctz(p) /* Undefined behavior if p == 0 */ static int count_port_bits(uint32_t bitmask) { @@ -568,12 +700,19 @@ static void balance_source_ports(void) if (deferred_waiting) return; + /* + * Turn off all shared power logic while BIST shared test mode is active + * on the system. + */ + if (bist_shared_mode_enabled) + return; + mutex_lock(&max_current_claimed_lock); /* Remove any ports which no longer require 3.0 A */ - removed_ports = max_current_claimed & ~(sink_max_pdo_requested | - source_frs_max_requested | - non_pd_sink_max_requested); + removed_ports = max_current_claimed & + ~(sink_max_pdo_requested | source_frs_max_requested | + non_pd_sink_max_requested); max_current_claimed &= ~removed_ports; /* Allocate 3.0 A to new PD sink ports that need it */ @@ -582,7 +721,7 @@ static void balance_source_ports(void) int new_max_port = LOWEST_PORT(new_ports); if (count_port_bits(max_current_claimed) < - CONFIG_USB_PD_3A_PORTS) { + CONFIG_USB_PD_3A_PORTS) { max_current_claimed |= BIT(new_max_port); typec_select_src_current_limit_rp(new_max_port, TYPEC_RP_3A0); @@ -590,7 +729,8 @@ static void balance_source_ports(void) /* Always downgrade non-PD ports first */ int rem_non_pd = LOWEST_PORT(non_pd_sink_max_requested & max_current_claimed); - typec_select_src_current_limit_rp(rem_non_pd, + typec_select_src_current_limit_rp( + rem_non_pd, typec_get_default_current_limit_rp(rem_non_pd)); max_current_claimed &= ~BIT(rem_non_pd); @@ -602,7 +742,7 @@ static void balance_source_ports(void) } else if (source_frs_max_requested & max_current_claimed) { /* Downgrade lowest FRS port from 3.0 A slot */ int rem_frs = LOWEST_PORT(source_frs_max_requested & - max_current_claimed); + max_current_claimed); pd_dpm_request(rem_frs, DPM_REQUEST_FRS_DET_DISABLE); max_current_claimed &= ~BIT(rem_frs); @@ -624,14 +764,15 @@ static void balance_source_ports(void) int new_frs_port = LOWEST_PORT(new_ports); if (count_port_bits(max_current_claimed) < - CONFIG_USB_PD_3A_PORTS) { + CONFIG_USB_PD_3A_PORTS) { max_current_claimed |= BIT(new_frs_port); pd_dpm_request(new_frs_port, DPM_REQUEST_FRS_DET_ENABLE); } else if (non_pd_sink_max_requested & max_current_claimed) { int rem_non_pd = LOWEST_PORT(non_pd_sink_max_requested & max_current_claimed); - typec_select_src_current_limit_rp(rem_non_pd, + typec_select_src_current_limit_rp( + rem_non_pd, typec_get_default_current_limit_rp(rem_non_pd)); max_current_claimed &= ~BIT(rem_non_pd); @@ -653,7 +794,7 @@ static void balance_source_ports(void) int new_max_port = LOWEST_PORT(new_ports); if (count_port_bits(max_current_claimed) < - CONFIG_USB_PD_3A_PORTS) { + CONFIG_USB_PD_3A_PORTS) { max_current_claimed |= BIT(new_max_port); typec_select_src_current_limit_rp(new_max_port, TYPEC_RP_3A0); @@ -741,7 +882,7 @@ void dpm_evaluate_request_rdo(int port, uint32_t rdo) return; op_ma = (rdo >> 10) & 0x3FF; - if ((BIT(port) && sink_max_pdo_requested) && (op_ma <= 150)) { + if ((BIT(port) & sink_max_pdo_requested) && (op_ma <= 150)) { /* * sink_max_pdo_requested will be set when we get 5V/3A sink * capability from port partner. If port partner only request @@ -766,8 +907,8 @@ void dpm_remove_sink(int port) atomic_clear_bits(&non_pd_sink_max_requested, BIT(port)); /* Restore selected default Rp on the port */ - typec_select_src_current_limit_rp(port, - typec_get_default_current_limit_rp(port)); + typec_select_src_current_limit_rp( + port, typec_get_default_current_limit_rp(port)); balance_source_ports(); } @@ -788,16 +929,83 @@ void dpm_remove_source(int port) balance_source_ports(); } +void dpm_bist_shared_mode_enter(int port) +{ + /* + * From 6.4.3.3.1 BIST Shared Test Mode Entry: + * + * "When any Master Port in a shared capacity group receives a BIST + * Message with a BIST Shared Test Mode Entry BIST Data Object, while + * in the PE_SRC_Ready State, the UUT Shall enter a compliance test + * mode where the maximum source capability is always offered on every + * port, regardless of the availability of shared power i.e. all shared + * power management is disabled. + * . . . + * On entering this mode, the UUT Shall send a new Source_Capabilities + * Message from each Port in the shared capacity group within + * tBISTSharedTestMode. The Tester will not exceed the shared capacity + * during this mode." + */ + + /* Shared mode is unnecessary without at least one 3.0 A port */ + if (CONFIG_USB_PD_3A_PORTS == 0) + return; + + /* Enter mode only if this port had been in PE_SRC_Ready */ + if (pd_get_power_role(port) != PD_ROLE_SOURCE) + return; + + bist_shared_mode_enabled = true; + + /* Trigger new source caps on all source ports */ + for (int i = 0; i < board_get_usb_pd_port_count(); i++) { + if (pd_get_power_role(i) == PD_ROLE_SOURCE) + typec_select_src_current_limit_rp(i, TYPEC_RP_3A0); + } +} + +void dpm_bist_shared_mode_exit(int port) +{ + /* + * From 6.4.3.3.2 BIST Shared Test Mode Exit: + * + * "Upon receipt of a BIST Message, with a BIST Shared Test Mode Exit + * BIST Data Object, the UUT Shall return a GoodCRC Message and Shall + * exit the BIST Shared Capacity Test Mode. + * . . . + * On exiting the mode, the UUT May send a new Source_Capabilities + * Message to each port in the shared capacity group or the UUT May + * perform ErrorRecovery on each port." + */ + + /* Shared mode is unnecessary without at least one 3.0 A port */ + if (CONFIG_USB_PD_3A_PORTS == 0) + return; + + /* Do nothing if Exit was received with no Entry */ + if (!bist_shared_mode_enabled) + return; + + bist_shared_mode_enabled = false; + + /* Declare error recovery bankruptcy */ + for (int i = 0; i < board_get_usb_pd_port_count(); i++) { + pd_set_error_recovery(i); + } +} + /* * Note: all ports receive the 1.5 A source offering until they are found to * match a criteria on the 3.0 A priority list (ex. through sink capability * probing), at which point they will be offered a new 3.0 A source capability. + * + * All ports must be offered our full capability while in BIST shared test mode. */ __overridable int dpm_get_source_pdo(const uint32_t **src_pdo, const int port) { /* Max PDO may not exist on boards which don't offer 3 A */ #if CONFIG_USB_PD_3A_PORTS > 0 - if (max_current_claimed & BIT(port)) { + if (max_current_claimed & BIT(port) || bist_shared_mode_enabled) { *src_pdo = pd_src_pdo_max; return pd_src_pdo_max_cnt; } @@ -812,7 +1020,7 @@ int dpm_get_source_current(const int port) if (pd_get_power_role(port) == PD_ROLE_SINK) return 0; - if (max_current_claimed & BIT(port)) + if (max_current_claimed & BIT(port) || bist_shared_mode_enabled) return 3000; else if (typec_get_default_current_limit_rp(port) == TYPEC_RP_1A5) return 1500; @@ -820,8 +1028,8 @@ int dpm_get_source_current(const int port) return 500; } -__overridable enum pd_sdb_power_indicator board_get_pd_sdb_power_indicator( -enum pd_sdb_power_state power_state) +__overridable enum pd_sdb_power_indicator +board_get_pd_sdb_power_indicator(enum pd_sdb_power_state power_state) { /* * LED on for S0 and blinking for S0ix/S3. @@ -856,7 +1064,7 @@ static uint8_t get_status_internal_temp(void) else if (temp_c < 2) temp_c = 1; - return (uint8_t) temp_c; + return (uint8_t)temp_c; #else return 0; #endif |