From ad8ce3f806961e2c4548c2f552b7f94adf0fd4b5 Mon Sep 17 00:00:00 2001 From: Shawn Nematbakhsh Date: Mon, 17 Aug 2015 13:55:47 -0700 Subject: usb_pd: Add host command to limit external charger voltage / current PD charger voltage + current can now be limited with EC_CMD_EXTERNAL_POWER_LIMIT. The limit is automatically cleared when the AP transitions out of S0 into S3 / suspend. BUG=chrome-os-partner:43285 TEST=Manual on Samus w/ zinger. - Plug zinger, verify charging at 20V/3A. - `ectool extpwrlimit 3000 12000 --dev=1`, verify charging at 12V/3A - `ectool extpwrlimit 1000 5000 --dev=1`, verify charging at 5V/1A - Plug zinger into other port, verify still charging at 5V/1A - `powerd_dbus_suspend`, verify charging at 20V/3A - `chglim 2000 12000`, verify charging at 12V/2A - `ectool extpwrlimit 0xffff 0xffff --dev=1`, verify charging at 20V/3A - `chglim 1000 20000`, verify charging at 20V/1A - `chglim`, verify charging at 20V/3A BRANCH=ryu Signed-off-by: Shawn Nematbakhsh Change-Id: I6cd5377be91b3df75f99cb414fd3fa5a463b56cb Reviewed-on: https://chromium-review.googlesource.com/293954 Reviewed-by: Todd Broch Reviewed-by: Alec Berg --- board/ryu/board.h | 1 + common/charge_manager.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++ common/usb_pd_policy.c | 8 ++---- common/usb_pd_protocol.c | 13 +++++++++ include/config.h | 3 ++ include/ec_commands.h | 12 +++++--- include/usb_pd.h | 9 ++++++ util/ectool.c | 34 +++++++++++++--------- 8 files changed, 130 insertions(+), 23 deletions(-) diff --git a/board/ryu/board.h b/board/ryu/board.h index 4d8111b79c..3a22f811c9 100644 --- a/board/ryu/board.h +++ b/board/ryu/board.h @@ -22,6 +22,7 @@ /* Optional features */ #undef CONFIG_CMD_HASH #define CONFIG_CHARGE_MANAGER +#define CONFIG_CHARGE_MANAGER_EXTERNAL_POWER_LIMIT #define CONFIG_CHARGE_RAMP_HW #define CONFIG_FORCE_CONSOLE_RESUME #define CONFIG_STM_HWTIMER32 diff --git a/common/charge_manager.c b/common/charge_manager.c index 4e21bdf2bd..ef74438368 100644 --- a/common/charge_manager.c +++ b/common/charge_manager.c @@ -855,3 +855,76 @@ DECLARE_CONSOLE_COMMAND(chgoverride, command_charge_port_override, "[port | -1 | -2]", "Force charging from a given port (-1 = off, -2 = disable charging)", NULL); + +#ifdef CONFIG_CHARGE_MANAGER_EXTERNAL_POWER_LIMIT +static void charge_manager_set_external_power_limit(int current_lim, + int voltage_lim) +{ + int port; + + if (current_lim == EC_POWER_LIMIT_NONE) + current_lim = CHARGE_CEIL_NONE; + if (voltage_lim == EC_POWER_LIMIT_NONE) + voltage_lim = PD_MAX_VOLTAGE_MV; + + for (port = 0; port < CONFIG_USB_PD_PORT_COUNT; ++port) { + charge_manager_set_ceil(port, CEIL_REQUESTOR_HOST, current_lim); + pd_set_external_voltage_limit(port, voltage_lim); + } +} + +/* + * On transition out of S0, disable all external power limits, in case AP + * failed to clear them. + */ +static void charge_manager_external_power_limit_off(void) +{ + charge_manager_set_external_power_limit(EC_POWER_LIMIT_NONE, + EC_POWER_LIMIT_NONE); +} +DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, charge_manager_external_power_limit_off, + HOOK_PRIO_DEFAULT); + +static int hc_external_power_limit(struct host_cmd_handler_args *args) +{ + const struct ec_params_external_power_limit_v1 *p = args->params; + + charge_manager_set_external_power_limit(p->current_lim, + p->voltage_lim); + + return EC_SUCCESS; +} +DECLARE_HOST_COMMAND(EC_CMD_EXTERNAL_POWER_LIMIT, + hc_external_power_limit, + EC_VER_MASK(1)); + +static int command_external_power_limit(int argc, char **argv) +{ + int max_current; + int max_voltage; + char *e; + + if (argc >= 2) { + max_current = strtoi(argv[1], &e, 10); + if (*e) + return EC_ERROR_PARAM1; + } else + max_current = EC_POWER_LIMIT_NONE; + + if (argc >= 3) { + max_voltage = strtoi(argv[2], &e, 10); + if (*e) + return EC_ERROR_PARAM1; + } else + max_voltage = EC_POWER_LIMIT_NONE; + + charge_manager_set_external_power_limit(max_current, max_voltage); + ccprintf("max req: %dmA %dmV\n", max_current, max_voltage); + + return EC_SUCCESS; +} +DECLARE_CONSOLE_COMMAND(chglim, command_external_power_limit, + "[max_current (mA)] [max_voltage (mV)]", + "Set max charger current / voltage", + NULL); +#endif /* CONFIG_CHARGE_MANAGER_EXTERNAL_POWER_LIMIT */ diff --git a/common/usb_pd_policy.c b/common/usb_pd_policy.c index 16a9fefa7a..91bbdb15e4 100644 --- a/common/usb_pd_policy.c +++ b/common/usb_pd_policy.c @@ -34,7 +34,7 @@ static int rw_flash_changed = 1; #ifdef CONFIG_USB_PD_DUAL_ROLE /* Cap on the max voltage requested as a sink (in millivolts) */ -static unsigned max_request_mv = -1; /* no cap */ +static unsigned max_request_mv = PD_MAX_VOLTAGE_MV; /* no cap */ /** * Find PDO index that offers the most amount of power and stays within @@ -53,10 +53,6 @@ static int pd_find_pdo_index(int cnt, uint32_t *src_caps, int max_mv) int cur_mv; #endif - /* max_mv of -1 represents max limit */ - if (max_mv == -1) - max_mv = PD_MAX_VOLTAGE_MV; - /* max voltage is always limited by this boards max request */ max_mv = MIN(max_mv, PD_MAX_VOLTAGE_MV); @@ -155,7 +151,7 @@ void pd_process_source_cap(int port, int cnt, uint32_t *src_caps) int pdo_index; /* Get max power info that we could request */ - pdo_index = pd_find_pdo_index(cnt, src_caps, -1); + pdo_index = pd_find_pdo_index(cnt, src_caps, PD_MAX_VOLTAGE_MV); if (pdo_index < 0) pdo_index = 0; pd_extract_pdo_power(src_caps[pdo_index], &ma, &mv); diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c index b124ad0245..b6507baa5c 100644 --- a/common/usb_pd_protocol.c +++ b/common/usb_pd_protocol.c @@ -2725,6 +2725,19 @@ void pd_request_source_voltage(int port, int mv) task_wake(PD_PORT_TO_TASK_ID(port)); } + +void pd_set_external_voltage_limit(int port, int mv) +{ + pd_set_max_voltage(mv); + + if (pd[port].task_state == PD_STATE_SNK_READY || + pd[port].task_state == PD_STATE_SNK_TRANSITION) { + /* Set flag to send new power request in pd_task */ + pd[port].new_power_request = 1; + 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/config.h b/include/config.h index b718941a12..4685c89f59 100644 --- a/include/config.h +++ b/include/config.h @@ -247,6 +247,9 @@ /* Compile charge manager */ #undef CONFIG_CHARGE_MANAGER +/* Handle the external power limit host command in charge manager */ +#undef CONFIG_CHARGE_MANAGER_EXTERNAL_POWER_LIMIT + /* Compile input current ramping support */ #undef CONFIG_CHARGE_RAMP diff --git a/include/ec_commands.h b/include/ec_commands.h index f64ffd6eac..fa820b7ebb 100644 --- a/include/ec_commands.h +++ b/include/ec_commands.h @@ -2842,14 +2842,18 @@ struct ec_params_current_limit { } __packed; /* - * Set maximum external power current. + * Set maximum external voltage / current. */ -#define EC_CMD_EXT_POWER_CURRENT_LIMIT 0xa2 +#define EC_CMD_EXTERNAL_POWER_LIMIT 0xa2 -struct ec_params_ext_power_current_limit { - uint32_t limit; /* in mA */ +/* Command v0 is used only on Spring and is obsolete + unsupported */ +struct ec_params_external_power_limit_v1 { + uint16_t current_lim; /* in mA, or EC_POWER_LIMIT_NONE to clear limit */ + uint16_t voltage_lim; /* in mV, or EC_POWER_LIMIT_NONE to clear limit */ } __packed; +#define EC_POWER_LIMIT_NONE 0xffff + /*****************************************************************************/ /* Smart battery pass-through */ diff --git a/include/usb_pd.h b/include/usb_pd.h index 5b42b687e0..6ca88bb55a 100644 --- a/include/usb_pd.h +++ b/include/usb_pd.h @@ -946,6 +946,15 @@ int pd_set_power_supply_ready(int port); */ void pd_request_source_voltage(int port, int mv); +/** + * Set a voltage limit from the PD source. + * + * If the source is currently active, it triggers a new negotiation. + * @param port USB-C port number + * @param mv limit voltage in millivolts. + */ +void pd_set_external_voltage_limit(int port, int mv); + /** * Set the PD input current limit. * diff --git a/util/ectool.c b/util/ectool.c index 8fa08b4b10..c6a40f4b34 100644 --- a/util/ectool.c +++ b/util/ectool.c @@ -43,8 +43,6 @@ static struct option long_opts[] = { const char help_str[] = "Commands:\n" - " extpwrcurrentlimit\n" - " Set the maximum external power current\n" " autofanctrl \n" " Turn on automatic fan speed control.\n" " backlight \n" @@ -93,6 +91,8 @@ const char help_str[] = " Sets the SMI mask for EC host events\n" " eventsetwakemask \n" " Sets the wake mask for EC host events\n" + " extpwrlimit\n" + " Set the maximum external power limit\n" " fanduty \n" " Forces the fan PWM to a constant duty cycle\n" " flasherase \n" @@ -4829,26 +4829,34 @@ int cmd_lcd_backlight(int argc, char *argv[]) } -int cmd_ext_power_current_limit(int argc, char *argv[]) +int cmd_ext_power_limit(int argc, char *argv[]) { - struct ec_params_ext_power_current_limit p; - int rv; + /* Version 1 is used, no support for obsolete version 0 */ + struct ec_params_external_power_limit_v1 p; char *e; - if (argc != 2) { - fprintf(stderr, "Usage: %s \n", argv[0]); + if (argc != 3) { + fprintf(stderr, + "Usage: %s \n", + argv[0]); return -1; } - p.limit = strtol(argv[1], &e, 0); + p.current_lim = strtol(argv[1], &e, 0); if (e && *e) { - fprintf(stderr, "Bad value.\n"); + fprintf(stderr, "Bad param1.\n"); return -1; } - rv = ec_command(EC_CMD_EXT_POWER_CURRENT_LIMIT, 0, &p, sizeof(p), - NULL, 0); - return rv; + p.voltage_lim = strtol(argv[2], &e, 0); + if (e && *e) { + fprintf(stderr, "Bad param2.\n"); + return -1; + } + + /* Send version 1 of command */ + return ec_command(EC_CMD_EXTERNAL_POWER_LIMIT, 1, &p, sizeof(p), + NULL, 0); } @@ -6315,7 +6323,6 @@ int cmd_pd_write_log(int argc, char *argv[]) /* NULL-terminated list of commands */ const struct command commands[] = { - {"extpwrcurrentlimit", cmd_ext_power_current_limit}, {"autofanctrl", cmd_thermal_auto_fan_ctrl}, {"backlight", cmd_lcd_backlight}, {"battery", cmd_battery}, @@ -6340,6 +6347,7 @@ const struct command commands[] = { {"eventsetscimask", cmd_host_event_set_sci_mask}, {"eventsetsmimask", cmd_host_event_set_smi_mask}, {"eventsetwakemask", cmd_host_event_set_wake_mask}, + {"extpwrlimit", cmd_ext_power_limit}, {"fanduty", cmd_fanduty}, {"flasherase", cmd_flash_erase}, {"flashprotect", cmd_flash_protect}, -- cgit v1.2.1