summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDiana Z <dzigterman@chromium.org>2021-02-11 16:56:09 -0700
committerCommit Bot <commit-bot@chromium.org>2021-02-23 20:43:58 +0000
commitd1a52e3f698b79fcae558cde78b3b41f4c0499a6 (patch)
tree60a40238c3f8d4d0862b341fe52318d3d8fc6410
parent26c09d5a67ae4832b7179060a585e065bff020b3 (diff)
downloadchrome-ec-d1a52e3f698b79fcae558cde78b3b41f4c0499a6.tar.gz
TCPMv2: Source out 3.0 A to non-PD ports
When no PD sinks require 3.0 A and no FRS ports require it, offer this current level to non-PD sinking devices. The non-PD devices will be downgraded whenever a higher-priority type of port is connected. BRANCH=None BUG=b:141690755 TEST=on madoo, verify: - plugging in a flash drive, it is offered 3.0 A - plugging in a 3.0 A PD sink, flash drive CC resistor is downgraded - unplugging 3.0 A PD sink, flash drive CC resistor is back to 3.0 A - connect power to 3.0 A PD sink, flash drive CC resistor is back to 3.0 A With FRS config check commented out, verify: - flash drive is downgraded and FRS enabled on powered hub plug in - flash drive is back to 3.0 A on FRS hub detach Signed-off-by: Diana Z <dzigterman@chromium.org> Change-Id: Iaa5c3f0a6a4f41db83978bb1e1d0b54f2519abb2 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2692030 Reviewed-by: Keith Short <keithshort@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2715844 Tested-by: Abe Levkoy <alevkoy@chromium.org> Reviewed-by: Abe Levkoy <alevkoy@chromium.org> Commit-Queue: Abe Levkoy <alevkoy@chromium.org>
-rw-r--r--common/mock/usb_pd_dpm_mock.c4
-rw-r--r--common/usbc/usb_pd_dpm.c66
-rw-r--r--common/usbc/usb_pe_drp_sm.c3
-rw-r--r--include/usb_pd_dpm.h8
-rw-r--r--test/fake_usbc.c4
5 files changed, 80 insertions, 5 deletions
diff --git a/common/mock/usb_pd_dpm_mock.c b/common/mock/usb_pd_dpm_mock.c
index edac099a02..3da96fea2d 100644
--- a/common/mock/usb_pd_dpm_mock.c
+++ b/common/mock/usb_pd_dpm_mock.c
@@ -52,6 +52,10 @@ void dpm_evaluate_sink_fixed_pdo(int port, uint32_t vsafe5v_pdo)
{
}
+void dpm_add_non_pd_sink(int port)
+{
+}
+
void dpm_remove_sink(int port)
{
}
diff --git a/common/usbc/usb_pd_dpm.c b/common/usbc/usb_pd_dpm.c
index 01c01af4e8..9c85011331 100644
--- a/common/usbc/usb_pd_dpm.c
+++ b/common/usbc/usb_pd_dpm.c
@@ -369,6 +369,8 @@ static bool dpm_mutex_initialized;
static uint32_t sink_max_pdo_requested;
/* Ports with FRS source needing > 1.5 A */
static uint32_t source_frs_max_requested;
+/* Ports with non-PD sinks, so current requirements are unknown */
+static uint32_t non_pd_sink_max_requested;
#define LOWEST_PORT(p) __builtin_ctz(p) /* Undefined behavior if p == 0 */
@@ -416,7 +418,8 @@ static void balance_source_ports(void)
/* Remove any ports which no longer require 3.0 A */
removed_ports = max_current_claimed & ~(sink_max_pdo_requested |
- source_frs_max_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 */
@@ -429,8 +432,21 @@ static void balance_source_ports(void)
max_current_claimed |= BIT(new_max_port);
typec_select_src_current_limit_rp(new_max_port,
TYPEC_RP_3A0);
+ } else if (non_pd_sink_max_requested & max_current_claimed) {
+ /* 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,
+ CONFIG_USB_PD_PULLUP);
+ max_current_claimed &= ~BIT(rem_non_pd);
+
+ /* Wait tSinkAdj before using current */
+ deferred_waiting = true;
+ hook_call_deferred(&balance_source_ports_data,
+ PD_T_SINK_ADJ);
+ goto unlock;
} else if (source_frs_max_requested & max_current_claimed) {
- /* Bump lowest FRS port from 3.0 A slot */
+ /* Downgrade lowest FRS port from 3.0 A slot */
int rem_frs = LOWEST_PORT(source_frs_max_requested &
max_current_claimed);
pd_dpm_request(rem_frs, DPM_REQUEST_FRS_DET_DISABLE);
@@ -442,7 +458,7 @@ static void balance_source_ports(void)
20 * MSEC);
goto unlock;
} else {
- /* TODO(b/141690755): Check lower priority claims */
+ /* No lower priority ports to downgrade */
goto unlock;
}
new_ports &= ~BIT(new_max_port);
@@ -458,13 +474,41 @@ static void balance_source_ports(void)
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,
+ CONFIG_USB_PD_PULLUP);
+ max_current_claimed &= ~BIT(rem_non_pd);
+
+ /* Wait tSinkAdj before using current */
+ deferred_waiting = true;
+ hook_call_deferred(&balance_source_ports_data,
+ PD_T_SINK_ADJ);
+ goto unlock;
} else {
- /* TODO(b/141690755): Check lower priority claims */
+ /* No lower priority ports to downgrade */
goto unlock;
}
new_ports &= ~BIT(new_frs_port);
}
+ /* Allocate 3.0 A to any non-PD ports which could need it */
+ new_ports = non_pd_sink_max_requested & ~max_current_claimed;
+ while (new_ports) {
+ int new_max_port = LOWEST_PORT(new_ports);
+
+ if (count_port_bits(max_current_claimed) <
+ CONFIG_USB_PD_3A_PORTS) {
+ max_current_claimed |= BIT(new_max_port);
+ typec_select_src_current_limit_rp(new_max_port,
+ TYPEC_RP_3A0);
+ } else {
+ /* No lower priority ports to downgrade */
+ goto unlock;
+ }
+ new_ports &= ~BIT(new_max_port);
+ }
unlock:
mutex_unlock(&max_current_claimed_lock);
}
@@ -519,15 +563,27 @@ void dpm_evaluate_sink_fixed_pdo(int port, uint32_t vsafe5v_pdo)
balance_source_ports();
}
+void dpm_add_non_pd_sink(int port)
+{
+ if (CONFIG_USB_PD_3A_PORTS == 0)
+ return;
+
+ atomic_or(&non_pd_sink_max_requested, BIT(port));
+
+ balance_source_ports();
+}
+
void dpm_remove_sink(int port)
{
if (CONFIG_USB_PD_3A_PORTS == 0)
return;
- if (!(BIT(port) & sink_max_pdo_requested))
+ if (!(BIT(port) & sink_max_pdo_requested) &&
+ !(BIT(port) & non_pd_sink_max_requested))
return;
atomic_clear_bits(&sink_max_pdo_requested, BIT(port));
+ atomic_clear_bits(&non_pd_sink_max_requested, BIT(port));
balance_source_ports();
}
diff --git a/common/usbc/usb_pe_drp_sm.c b/common/usbc/usb_pe_drp_sm.c
index 8e2581348b..873f7f474d 100644
--- a/common/usbc/usb_pe_drp_sm.c
+++ b/common/usbc/usb_pe_drp_sm.c
@@ -2801,6 +2801,9 @@ static void pe_src_disabled_entry(int port)
tc_ctvpd_detected(port);
}
+ if (pd_get_power_role(port) == PD_ROLE_SOURCE)
+ dpm_add_non_pd_sink(port);
+
/*
* Unresponsive to USB Power Delivery messaging, but not to Hard Reset
* Signaling. See pe_got_hard_reset
diff --git a/include/usb_pd_dpm.h b/include/usb_pd_dpm.h
index aa9608f9b4..0ecb577a1a 100644
--- a/include/usb_pd_dpm.h
+++ b/include/usb_pd_dpm.h
@@ -69,6 +69,14 @@ void dpm_run(int port);
void dpm_evaluate_sink_fixed_pdo(int port, uint32_t vsafe5v_pdo);
/*
+ * Registers port as a non-PD sink, so that can be taken into account when
+ * allocating current.
+ *
+ * @param port USB-C port number
+ */
+void dpm_add_non_pd_sink(int port);
+
+/*
* Remove this port as a sink, and reallocate maximum current as needed.
*
* @param port USB-C port number
diff --git a/test/fake_usbc.c b/test/fake_usbc.c
index 9eb913ea19..b744007a66 100644
--- a/test/fake_usbc.c
+++ b/test/fake_usbc.c
@@ -279,6 +279,10 @@ void dpm_evaluate_sink_fixed_pdo(int port, uint32_t vsafe5v_pdo)
{
}
+void dpm_add_non_pd_sink(int port)
+{
+}
+
void dpm_remove_sink(int port)
{
}