diff options
Diffstat (limited to 'common/usb_pd_protocol.c')
-rw-r--r-- | common/usb_pd_protocol.c | 42 |
1 files changed, 42 insertions, 0 deletions
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c index e9525cb547..aba957c77f 100644 --- a/common/usb_pd_protocol.c +++ b/common/usb_pd_protocol.c @@ -36,6 +36,14 @@ BUILD_ASSERT(CONFIG_USB_PD_PORT_COUNT <= EC_USB_PD_MAX_PORTS); /* + * 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 */ + +/* * Debug log level - higher number == more log * Level 0: Log state transitions * Level 1: Level 0, plus state name @@ -4455,6 +4463,40 @@ static int pd_control(struct host_cmd_handler_args *args) 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; |