diff options
author | Vincent Palatin <vpalatin@chromium.org> | 2016-08-22 17:11:27 +0200 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2016-09-01 19:52:35 -0700 |
commit | 02b80c49f473b872360a782f6a95c607c6734717 (patch) | |
tree | 4c4e9b53f264b81d57206a0035a3ce8adbf323a2 | |
parent | f4863ef03d76fc3923c49bccdfaf28b47ddc80f9 (diff) | |
download | chrome-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.c | 2 | ||||
-rw-r--r-- | common/charge_manager.c | 53 | ||||
-rw-r--r-- | common/usb_pd_protocol.c | 26 | ||||
-rw-r--r-- | include/charge_manager.h | 11 | ||||
-rw-r--r-- | include/config.h | 8 | ||||
-rw-r--r-- | include/usb_pd.h | 22 |
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. |