summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Palatin <vpalatin@chromium.org>2016-08-22 17:11:27 +0200
committerchrome-bot <chrome-bot@chromium.org>2016-09-01 19:52:35 -0700
commit02b80c49f473b872360a782f6a95c607c6734717 (patch)
tree4c4e9b53f264b81d57206a0035a3ce8adbf323a2
parentf4863ef03d76fc3923c49bccdfaf28b47ddc80f9 (diff)
downloadchrome-ec-02b80c49f473b872360a782f6a95c607c6734717.tar.gz
pd: manage total source current available
Add a policy to handle the case where the device can source the `CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT` over one of its type-C port if there is no sink connected on the other ones. Signed-off-by: Vincent Palatin <vpalatin@chromium.org> BRANCH=none BUG=chrome-os-partner:56110 TEST=manual: on Kevin, plug and unplug various devices on the 2 ports, while measuring the type-C pull-up with Twinkie. Change-Id: Id5961f04d0a1b1073f5ab340068efd9079918209 Reviewed-on: https://chromium-review.googlesource.com/373818 Commit-Ready: Vincent Palatin <vpalatin@chromium.org> Tested-by: Vincent Palatin <vpalatin@chromium.org> Reviewed-by: Shawn N <shawnn@chromium.org>
-rw-r--r--board/plankton/usb_pd_policy.c2
-rw-r--r--common/charge_manager.c53
-rw-r--r--common/usb_pd_protocol.c26
-rw-r--r--include/charge_manager.h11
-rw-r--r--include/config.h8
-rw-r--r--include/usb_pd.h22
6 files changed, 110 insertions, 12 deletions
diff --git a/board/plankton/usb_pd_policy.c b/board/plankton/usb_pd_policy.c
index 8a916e65aa..1b5e0271df 100644
--- a/board/plankton/usb_pd_policy.c
+++ b/board/plankton/usb_pd_policy.c
@@ -55,7 +55,7 @@ void board_set_source_cap(enum board_src_cap cap)
pd_src_pdo_idx = cap;
}
-int pd_get_source_pdo(const uint32_t **src_pdo)
+int charge_manager_get_source_pdo(const uint32_t **src_pdo)
{
*src_pdo = pd_src_pdo;
return pd_src_pdo_cnts[pd_src_pdo_idx];
diff --git a/common/charge_manager.c b/common/charge_manager.c
index 13f85e38d0..becb6cc91d 100644
--- a/common/charge_manager.c
+++ b/common/charge_manager.c
@@ -4,6 +4,7 @@
*/
#include "adc.h"
+#include "atomic.h"
#include "battery.h"
#include "charge_manager.h"
#include "charge_ramp.h"
@@ -13,8 +14,10 @@
#include "hooks.h"
#include "host_command.h"
#include "system.h"
+#include "tcpm.h"
#include "timer.h"
#include "usb_pd.h"
+#include "usb_pd_tcpm.h"
#include "util.h"
#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args)
@@ -72,6 +75,10 @@ static int override_port = OVERRIDE_OFF;
static int delayed_override_port = OVERRIDE_OFF;
static timestamp_t delayed_override_deadline;
+/* Bitmap of ports used as power source */
+static volatile uint32_t source_port_bitmap;
+BUILD_ASSERT(sizeof(source_port_bitmap)*8 >= CONFIG_USB_PD_PORT_COUNT);
+
enum charge_manager_change_type {
CHANGE_CHARGE,
CHANGE_DUALROLE,
@@ -885,6 +892,52 @@ int charge_manager_get_power_limit_uw(void)
return current_ma * voltage_mv;
}
+#ifdef CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT
+void charge_manager_source_port(int port, int enable)
+{
+ uint32_t prev_bitmap = source_port_bitmap;
+ int p;
+
+ if (enable)
+ atomic_or(&source_port_bitmap, 1 << port);
+ else
+ atomic_clear(&source_port_bitmap, 1 << port);
+
+ /* No change, exit early. */
+ if (prev_bitmap == source_port_bitmap)
+ return;
+
+ /* 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;
+
+ tcpm_select_rp_value(p, rp);
+ pd_update_contract(p);
+ }
+}
+
+int charge_manager_get_source_pdo(const uint32_t **src_pdo)
+{
+ int p;
+ int count = 0;
+
+ /* count the number of connected sinks */
+ for (p = 0; p < CONFIG_USB_PD_PORT_COUNT; p++)
+ if (source_port_bitmap & (1 << p))
+ count++;
+
+ /* send the maximum current if we are sourcing only on one port */
+ *src_pdo = count <= 1 ? pd_src_pdo_max : pd_src_pdo;
+
+ return count <= 1 ? pd_src_pdo_cnt : pd_src_pdo_max_cnt;
+}
+#endif /* CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT */
+
#ifndef TEST_BUILD
static int hc_pd_power_info(struct host_cmd_handler_args *args)
{
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c
index c2eafb7fa3..e5850a8554 100644
--- a/common/usb_pd_protocol.c
+++ b/common/usb_pd_protocol.c
@@ -421,9 +421,10 @@ static int send_control(int port, int type)
static int send_source_cap(int port)
{
int bit_len;
-#ifdef CONFIG_USB_PD_DYNAMIC_SRC_CAP
+#if defined(CONFIG_USB_PD_DYNAMIC_SRC_CAP) || \
+ defined(CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT)
const uint32_t *src_pdo;
- const int src_pdo_cnt = pd_get_source_pdo(&src_pdo);
+ const int src_pdo_cnt = charge_manager_get_source_pdo(&src_pdo);
#else
const uint32_t *src_pdo = pd_src_pdo;
const int src_pdo_cnt = pd_src_pdo_cnt;
@@ -1887,6 +1888,18 @@ void pd_task(void)
(pd[port].vdm_state == VDM_STATE_BUSY))
break;
+ /* Send updated source capabilities to our partner */
+ if (pd[port].flags & PD_FLAGS_UPDATE_SRC_CAPS) {
+ res = send_source_cap(port);
+ if (res >= 0) {
+ set_state(port,
+ PD_STATE_SRC_NEGOCIATE);
+ pd[port].flags &=
+ ~PD_FLAGS_UPDATE_SRC_CAPS;
+ }
+ break;
+ }
+
/* Send get sink cap if haven't received it yet */
if (pd[port].last_state != pd[port].task_state &&
!(pd[port].flags & PD_FLAGS_SNK_CAP_RECVD)) {
@@ -2955,6 +2968,15 @@ void pd_set_external_voltage_limit(int port, int mv)
}
}
+void pd_update_contract(int port)
+{
+ if ((pd[port].task_state >= PD_STATE_SRC_NEGOCIATE) &&
+ (pd[port].task_state <= PD_STATE_SRC_GET_SINK_CAP)) {
+ pd[port].flags |= PD_FLAGS_UPDATE_SRC_CAPS;
+ task_wake(PD_PORT_TO_TASK_ID(port));
+ }
+}
+
#endif /* CONFIG_USB_PD_DUAL_ROLE */
static int command_pd(int argc, char **argv)
diff --git a/include/charge_manager.h b/include/charge_manager.h
index 28546e22a1..7427d12aca 100644
--- a/include/charge_manager.h
+++ b/include/charge_manager.h
@@ -91,6 +91,17 @@ int charge_manager_get_charger_current(void);
void charge_manager_save_log(int port);
#endif
+/* Update whether a given port is sourcing current. */
+void charge_manager_source_port(int port, int enable);
+
+/*
+ * Get PD source power data objects.
+ *
+ * @param src_pdo pointer to the data to return.
+ * @return number of PDOs returned.
+ */
+int charge_manager_get_source_pdo(const uint32_t **src_pdo);
+
/* Board-level callback functions */
/*
diff --git a/include/config.h b/include/config.h
index 0228dd439b..56c0088990 100644
--- a/include/config.h
+++ b/include/config.h
@@ -2165,6 +2165,14 @@
/* Default pull-up value on the USB-C ports when they are used as source. */
#define CONFIG_USB_PD_PULLUP TYPEC_RP_1A5
+/*
+ * Override the pull-up value when only zero or one port is actively sourcing
+ * current and we can advertise more current than what is defined by
+ * `CONFIG_USB_PD_PULLUP`.
+ * Should be defined with one of the tcpc_rp_value.
+ */
+#undef CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT
+
/******************************************************************************/
/* USB port switch */
diff --git a/include/usb_pd.h b/include/usb_pd.h
index 00b149475b..28a94efdb3 100644
--- a/include/usb_pd.h
+++ b/include/usb_pd.h
@@ -701,6 +701,7 @@ enum pd_states {
#define PD_FLAGS_VCONN_ON (1 << 12)/* vconn is being sourced */
#define PD_FLAGS_TRY_SRC (1 << 13)/* Try.SRC states are active */
#define PD_FLAGS_PARTNER_USB_COMM (1 << 14)/* port partner is USB comms */
+#define PD_FLAGS_UPDATE_SRC_CAPS (1 << 15)/* send new source capabilities */
/* Flags to clear on a disconnect */
#define PD_FLAGS_RESET_ON_DISCONNECT_MASK (PD_FLAGS_PARTNER_DR_POWER | \
PD_FLAGS_PARTNER_DR_DATA | \
@@ -713,7 +714,8 @@ enum pd_states {
PD_FLAGS_PARTNER_EXTPOWER | \
PD_FLAGS_VCONN_ON | \
PD_FLAGS_TRY_SRC | \
- PD_FLAGS_PARTNER_USB_COMM)
+ PD_FLAGS_PARTNER_USB_COMM | \
+ PD_FLAGS_UPDATE_SRC_CAPS)
enum pd_cc_states {
@@ -970,6 +972,14 @@ void pd_set_external_voltage_limit(int port, int mv);
void pd_set_input_current_limit(int port, uint32_t max_ma,
uint32_t supply_voltage);
+
+/**
+ * Update the power contract if it exists.
+ *
+ * @param port USB-C port number.
+ */
+void pd_update_contract(int port);
+
/**
* Set the type-C input current limit.
*
@@ -1201,18 +1211,12 @@ void pd_send_vdm(int port, uint32_t vid, int cmd, const uint32_t *data,
/* Power Data Objects for the source and the sink */
extern const uint32_t pd_src_pdo[];
extern const int pd_src_pdo_cnt;
+extern const uint32_t pd_src_pdo_max[];
+extern const int pd_src_pdo_max_cnt;
extern const uint32_t pd_snk_pdo[];
extern const int pd_snk_pdo_cnt;
/**
- * Get PD source power data objects.
- *
- * @param src_pdo pointer to the data to return.
- * @return number of PDOs returned.
- */
-int pd_get_source_pdo(const uint32_t **src_pdo);
-
-/**
* Request that a host event be sent to notify the AP of a PD power event.
*
* @param mask host event mask.