summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorDaisuke Nojiri <dnojiri@chromium.org>2018-11-06 16:33:36 -0800
committerchrome-bot <chrome-bot@chromium.org>2018-11-16 05:01:47 -0800
commit88302ce7f21f16f0902fe5da033dd3d3e4091458 (patch)
treef0a5a612da7bf3f2fafe5cd056f5acd280c6d04c /common
parent70d01fabc76b72fe0f83de4a5a3a3b6958e7a9bf (diff)
downloadchrome-ec-88302ce7f21f16f0902fe5da033dd3d3e4091458.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>
Diffstat (limited to 'common')
-rw-r--r--common/charge_manager.c80
1 files changed, 58 insertions, 22 deletions
diff --git a/common/charge_manager.c b/common/charge_manager.c
index c7620a69dc..46fcb91730 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:
@@ -1041,10 +1047,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);
@@ -1057,14 +1102,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))
@@ -1079,18 +1120,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 */