diff options
author | Diana Z <dzigterman@chromium.org> | 2021-02-11 16:56:09 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2021-02-23 20:43:58 +0000 |
commit | d1a52e3f698b79fcae558cde78b3b41f4c0499a6 (patch) | |
tree | 60a40238c3f8d4d0862b341fe52318d3d8fc6410 | |
parent | 26c09d5a67ae4832b7179060a585e065bff020b3 (diff) | |
download | chrome-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.c | 4 | ||||
-rw-r--r-- | common/usbc/usb_pd_dpm.c | 66 | ||||
-rw-r--r-- | common/usbc/usb_pe_drp_sm.c | 3 | ||||
-rw-r--r-- | include/usb_pd_dpm.h | 8 | ||||
-rw-r--r-- | test/fake_usbc.c | 4 |
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) { } |