diff options
author | Abe Levkoy <alevkoy@chromium.org> | 2020-02-14 17:59:47 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-03-11 17:48:45 +0000 |
commit | 49c0bcf54db9c9702637549b1425e6bfb78a3d96 (patch) | |
tree | 8a6ec1a55e64724ab8266355379071fe3dc7790d /common/usb_pd_host_cmd.c | |
parent | c6b8f8a00149a75395f14aaaff5889b2c4eb5f99 (diff) | |
download | chrome-ec-49c0bcf54db9c9702637549b1425e6bfb78a3d96.tar.gz |
usb: Move pdcontrol host command to common code
Support pdcontrol in TCPMv2 in order to support TCPC firmware update.
BUG=chromium:1021417
TEST=ectool pdcontrol suspend, resume with charger attached
TEST=ectool pdcontrol suspend, resume with sink device attached
TEST=ectool pdcontrol reset (effectively suspend on Volteer), resume
TEST=ectool pdcontrol on (unsupported on Volteer)
TEST=ectool pdcontrol disable
TEST=Compare above to behavior on TCPMv1
BRANCH=none
Change-Id: I6a72ca708f499689e1d7e8bae6f5ca8a61f72c16
Signed-off-by: Abe Levkoy <alevkoy@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2057982
Commit-Queue: Keith Short <keithshort@chromium.org>
Reviewed-by: Keith Short <keithshort@chromium.org>
Diffstat (limited to 'common/usb_pd_host_cmd.c')
-rw-r--r-- | common/usb_pd_host_cmd.c | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/common/usb_pd_host_cmd.c b/common/usb_pd_host_cmd.c index bb8a1532a7..1de3944502 100644 --- a/common/usb_pd_host_cmd.c +++ b/common/usb_pd_host_cmd.c @@ -7,6 +7,7 @@ #include <string.h> +#include "battery.h" #include "console.h" #include "ec_commands.h" #include "host_command.h" @@ -16,6 +17,14 @@ #include "usb_pd_tcpm.h" #ifdef CONFIG_COMMON_RUNTIME +/* + * If we are trying to upgrade the TCPC port that is supplying power, then we + * need to ensure that the battery has enough charge for the upgrade. 100mAh + * is about 5% of most batteries, and it should be enough charge to get us + * through the EC jump to RW and PD upgrade. + */ +#define MIN_BATTERY_FOR_TCPC_UPGRADE_MAH 100 /* mAH */ + struct ec_params_usb_pd_rw_hash_entry rw_hash_table[RW_HASH_ENTRIES]; #define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) @@ -413,4 +422,83 @@ DECLARE_HOST_COMMAND(EC_CMD_GET_PD_PORT_CAPS, hc_get_pd_port_caps, EC_VER_MASK(0)); +#ifdef CONFIG_CMD_PD_CONTROL +static enum ec_status pd_control(struct host_cmd_handler_args *args) +{ + static int pd_control_disabled[CONFIG_USB_PD_PORT_MAX_COUNT]; + const struct ec_params_pd_control *cmd = args->params; + int enable = 0; + + if (cmd->chip >= board_get_usb_pd_port_count()) + return EC_RES_INVALID_PARAM; + + /* Always allow disable command */ + if (cmd->subcmd == PD_CONTROL_DISABLE) { + pd_control_disabled[cmd->chip] = 1; + return EC_RES_SUCCESS; + } + + if (pd_control_disabled[cmd->chip]) + return EC_RES_ACCESS_DENIED; + + if (cmd->subcmd == PD_SUSPEND) { + /* + * The AP is requesting to suspend PD traffic on the EC so it + * can perform a firmware upgrade. If Vbus is present on the + * connector (it is either a source or sink), then we will + * prevent the upgrade if there is not enough battery to finish + * the upgrade. We cannot rely on the EC's active charger data + * as the EC just rebooted into RW and has not necessarily + * picked the active charger yet. + */ +#ifdef HAS_TASK_CHARGER + if (pd_is_vbus_present(cmd->chip)) { + struct batt_params batt = { 0 }; + /* + * The charger task has not re-initialized, so we need + * to ask the battery directly. + */ + battery_get_params(&batt); + if (batt.remaining_capacity < + MIN_BATTERY_FOR_TCPC_UPGRADE_MAH || + batt.flags & BATT_FLAG_BAD_REMAINING_CAPACITY) { + CPRINTS("C%d: Cannot suspend for upgrade, not " + "enough battery (%dmAh)!", + cmd->chip, batt.remaining_capacity); + return EC_RES_BUSY; + } + } +#else + if (pd_is_vbus_present(cmd->chip)) { + CPRINTS("C%d: Cannot suspend for upgrade, Vbus " + "present!", + cmd->chip); + return EC_RES_BUSY; + } +#endif + enable = 0; + } else if (cmd->subcmd == PD_RESUME) { + enable = 1; + } else if (cmd->subcmd == PD_RESET) { +#ifdef HAS_TASK_PDCMD + board_reset_pd_mcu(); +#else + return EC_RES_INVALID_COMMAND; +#endif + } else if (cmd->subcmd == PD_CHIP_ON && board_set_tcpc_power_mode) { + board_set_tcpc_power_mode(cmd->chip, 1); + return EC_RES_SUCCESS; + } else { + return EC_RES_INVALID_COMMAND; + } + + pd_comm_enable(cmd->chip, enable); + pd_set_suspend(cmd->chip, !enable); + + return EC_RES_SUCCESS; +} + +DECLARE_HOST_COMMAND(EC_CMD_PD_CONTROL, pd_control, EC_VER_MASK(0)); +#endif /* CONFIG_CMD_PD_CONTROL */ + #endif /* HAS_TASK_HOSTCMD */ |