summaryrefslogtreecommitdiff
path: root/common/usbc/usb_pd_dpm.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/usbc/usb_pd_dpm.c')
-rw-r--r--common/usbc/usb_pd_dpm.c344
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