summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaisuke Nojiri <dnojiri@chromium.org>2018-11-06 16:33:36 -0800
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2018-11-16 16:28:37 +0000
commit90d8f1f9c0a670281418a4c1b8d165d95edd533f (patch)
treecde46585cc714d17799b1a132ce687161fc8212e
parent98da1db95df8ebd31e77c7f61e1f3123930bb7f1 (diff)
downloadchrome-ec-90d8f1f9c0a670281418a4c1b8d165d95edd533f.tar.gz
USB-PD: Supply power up to 3A + 1.5A
Currently, USB PD ports supply 3A only if there is no other active supplier. We enforce this rule even if the port is actively supplying power. That is, we drop the max current of an active port to 1.5A if a sink device is plugged to another port. This change makes USB PD ports supply 3A if the other ports are not supplying 3A. (P0, P1) and '*' indicates a sink device is plugged. Unplug both: (3A, 3A) Plug P0: (*3A, 1.5A) Plug P1: (*3A, *1.5A) Unplug P0: (1.5A, *3A) Unplug P1: (3A, 3A) Plug P1: (1.5A, *3A) Plug P0: (*1.5A, *3A) Unplug P0: (1.5A, *3A) Unplug P1: (3A, 3A) Signed-off-by: Daisuke Nojiri <dnojiri@chromium.org> BUG=b:115291657 BRANCH=none TEST=Performed as shown above and verify current of active port is not affected by the other port. Change-Id: I08fb04da7e0177d5e71f823fb1e47e6945ae12fc Reviewed-on: https://chromium-review.googlesource.com/1322069 Commit-Ready: Daisuke Nojiri <dnojiri@chromium.org> Tested-by: Raymond Chou <raymond_chou@compal.corp-partner.google.com> Reviewed-by: Jett Rink <jettrink@chromium.org> (cherry picked from commit 88302ce7f21f16f0902fe5da033dd3d3e4091458) Reviewed-on: https://chromium-review.googlesource.com/c/1340539 Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org> Commit-Queue: Daisuke Nojiri <dnojiri@chromium.org> Tested-by: Daisuke Nojiri <dnojiri@chromium.org>
-rw-r--r--common/charge_manager.c80
-rw-r--r--include/config.h9
2 files changed, 67 insertions, 22 deletions
diff --git a/common/charge_manager.c b/common/charge_manager.c
index 2abb770667..2dc6db4a6d 100644
--- a/common/charge_manager.c
+++ b/common/charge_manager.c
@@ -86,7 +86,13 @@ static timestamp_t delayed_override_deadline;
static volatile uint32_t source_port_bitmap;
BUILD_ASSERT(sizeof(source_port_bitmap)*8 >= CONFIG_USB_PD_PORT_COUNT);
#endif
-static uint8_t source_port_last_rp[CONFIG_USB_PD_PORT_COUNT];
+static uint8_t source_port_rp[CONFIG_USB_PD_PORT_COUNT];
+
+#ifdef CONFIG_USB_PD_MAX_TOTAL_SOURCE_CURRENT
+/* 3A on one port and 1.5A on the rest */
+BUILD_ASSERT(CONFIG_USB_PD_PORT_COUNT * 1500 + 1500 <=
+ CONFIG_USB_PD_MAX_TOTAL_SOURCE_CURRENT);
+#endif
/*
* charge_manager initially operates in safe mode until asked to leave (through
@@ -178,7 +184,7 @@ static void charge_manager_init(void)
if (!is_pd_port(i))
dualrole_capability[i] = CAP_DEDICATED;
if (is_pd_port(i))
- source_port_last_rp[i] = CONFIG_USB_PD_PULLUP;
+ source_port_rp[i] = CONFIG_USB_PD_PULLUP;
}
}
DECLARE_HOOK(HOOK_INIT, charge_manager_init, HOOK_PRIO_CHARGE_MANAGER_INIT);
@@ -222,7 +228,7 @@ static int charge_manager_get_source_current(int port)
if (!is_pd_port(port))
return 0;
- switch (source_port_last_rp[port]) {
+ switch (source_port_rp[port]) {
case TYPEC_RP_3A0:
return 3000;
case TYPEC_RP_1A5:
@@ -1018,10 +1024,49 @@ int charge_manager_get_power_limit_uw(void)
}
#ifdef CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT
+
+static inline int has_other_active_source(int port)
+{
+ return source_port_bitmap & ~(1 << port);
+}
+
+static inline int is_active_source(int port)
+{
+ return source_port_bitmap & (1 << port);
+}
+
+static int can_supply_max_current(int port)
+{
+#ifdef CONFIG_USB_PD_MAX_TOTAL_SOURCE_CURRENT
+ /*
+ * This guarantees active 3A source continues to supply 3A.
+ *
+ * Since redistribution occurs sequentially, younger ports get
+ * priority. Priority surfaces only when 3A source is released.
+ * That is, when 3A source is released, the youngest active
+ * port gets 3A.
+ */
+ int p;
+ if (!is_active_source(port) && has_other_active_source(port))
+ /* Another port will get 3A */
+ return 0;
+ for (p = 0; p < CONFIG_USB_PD_PORT_COUNT; p++) {
+ if (p == port)
+ continue;
+ if (is_active_source(p) && source_port_rp[p] ==
+ CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT)
+ return 0;
+ }
+ return 1;
+#else
+ return !has_other_active_source(port);
+#endif /* CONFIG_USB_PD_MAX_TOTAL_SOURCE_CURRENT */
+}
+
void charge_manager_source_port(int port, int enable)
{
uint32_t prev_bitmap = source_port_bitmap;
- int p;
+ int p, rp;
if (enable)
atomic_or(&source_port_bitmap, 1 << port);
@@ -1034,14 +1079,10 @@ void charge_manager_source_port(int port, int enable)
/* Set port limit according to policy */
for (p = 0; p < CONFIG_USB_PD_PORT_COUNT; p++) {
- /*
- * if we are the only active source port or there is none,
- * advertise all the available power.
- */
- int rp = (source_port_bitmap & ~(1 << p)) ? CONFIG_USB_PD_PULLUP
- : CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT;
-
- source_port_last_rp[p] = rp;
+ rp = can_supply_max_current(p) ?
+ CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT :
+ CONFIG_USB_PD_PULLUP;
+ source_port_rp[p] = rp;
#ifdef CONFIG_USB_PD_LOGGING
if (is_connected(p) && !is_sink(p))
@@ -1056,18 +1097,13 @@ void charge_manager_source_port(int port, int enable)
int charge_manager_get_source_pdo(const uint32_t **src_pdo, const int port)
{
- /* Are there any other connected sinks? */
- if (source_port_bitmap & ~(1 << port)) {
- *src_pdo = pd_src_pdo;
- return pd_src_pdo_cnt;
+ if (can_supply_max_current(port)) {
+ *src_pdo = pd_src_pdo_max;
+ return pd_src_pdo_max_cnt;
}
- /*
- * If not, send the maximum current since we're sourcing on only one
- * port.
- */
- *src_pdo = pd_src_pdo_max;
- return pd_src_pdo_max_cnt;
+ *src_pdo = pd_src_pdo;
+ return pd_src_pdo_cnt;
}
#endif /* CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT */
diff --git a/include/config.h b/include/config.h
index 3be92868a8..7c040de845 100644
--- a/include/config.h
+++ b/include/config.h
@@ -3354,6 +3354,15 @@
*/
#undef CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT
+/*
+ * Total current in mA the board can supply to external devices through
+ * USB-C ports
+ *
+ * When a sink device is plugged or unplugged, source current redistribution
+ * occurs. If this macro is defined, redistribution occurs in such a way
+ * that there is no current drop (e.g. 3A -> 1.5A) on active source ports.
+ */
+#undef CONFIG_USB_PD_MAX_TOTAL_SOURCE_CURRENT
/******************************************************************************/
/* stm32f4 dwc usb configs. */