diff options
Diffstat (limited to 'baseboard/guybrush/baseboard.c')
-rw-r--r-- | baseboard/guybrush/baseboard.c | 109 |
1 files changed, 80 insertions, 29 deletions
diff --git a/baseboard/guybrush/baseboard.c b/baseboard/guybrush/baseboard.c index 344ea459de..26f212e986 100644 --- a/baseboard/guybrush/baseboard.c +++ b/baseboard/guybrush/baseboard.c @@ -43,6 +43,8 @@ #define CPRINTSUSB(format, args...) cprints(CC_USBCHARGE, format, ## args) #define CPRINTFUSB(format, args...) cprintf(CC_USBCHARGE, format, ## args) +#define CPRINTSCHIP(format, args...) cprints(CC_CHIPSET, format ## args) + static void reset_nct38xx_port(int port); /* Wake Sources */ @@ -431,7 +433,7 @@ int board_set_active_charge_port(int port) int is_valid_port = (port >= 0 && port < CONFIG_USB_PD_PORT_MAX_COUNT); int i; - int cur_port = charge_manager_get_active_charge_port(); + int rv; if (port == CHARGE_PORT_NONE) { CPRINTSUSB("Disabling all charger ports"); @@ -444,7 +446,7 @@ int board_set_active_charge_port(int port) */ if (nct38xx_get_boot_type(i) == NCT38XX_BOOT_DEAD_BATTERY) { - reset_nct38xx_port(cur_port); + reset_nct38xx_port(i); pd_set_error_recovery(i); } @@ -461,36 +463,56 @@ int board_set_active_charge_port(int port) return EC_ERROR_INVAL; } - - /* Check if the port is sourcing VBUS. */ - if (tcpm_get_src_ctrl(port)) { - CPRINTSUSB("Skip enable C%d", port); - return EC_ERROR_INVAL; - } - /* - * Disallow changing ports if we booted in dead battery mode and don't - * have sufficient power to withstand Vbus loss. The NCT3807 may - * continue to keep EN_SNK low on the original port and allow a - * dangerous level of voltage to pass through to the initial charge - * port (see b/183660105) + * Check if we can reset any ports in dead battery mode * - * If we do have sufficient power, then reset the dead battery port and - * set up Type-C error recovery on its connection. + * The NCT3807 may continue to keep EN_SNK low on the dead battery port + * and allow a dangerous level of voltage to pass through to the initial + * charge port (see b/183660105). We must reset the ports if we have + * sufficient battery to do so, which will bring EN_SNK back under + * normal control. */ - if (cur_port != CHARGE_PORT_NONE && - port != cur_port && - nct38xx_get_boot_type(cur_port) == + rv = EC_SUCCESS; + for (i = 0; i < board_get_usb_pd_port_count(); i++) { + if (nct38xx_get_boot_type(i) == NCT38XX_BOOT_DEAD_BATTERY) { + CPRINTSUSB("Found dead battery on %d", i); + /* + * If we have battery, get this port reset ASAP. + * This means temporarily rejecting charge manager + * sets to it. + */ + if (pd_is_battery_capable()) { + reset_nct38xx_port(i); + pd_set_error_recovery(i); + + if (port == i) + rv = EC_ERROR_INVAL; + } else if (port != i) { + /* + * If other port is selected and in dead battery + * mode, reset this port. Otherwise, reject + * change because we'll brown out. + */ + if (nct38xx_get_boot_type(port) == NCT38XX_BOOT_DEAD_BATTERY) { - if (pd_is_battery_capable()) { - reset_nct38xx_port(cur_port); - pd_set_error_recovery(cur_port); - } else { - CPRINTSUSB("Battery too low for charge port change"); - return EC_ERROR_INVAL; + reset_nct38xx_port(i); + pd_set_error_recovery(i); + } else { + rv = EC_ERROR_INVAL; + } + } } } + if (rv != EC_SUCCESS) + return rv; + + /* Check if the port is sourcing VBUS. */ + if (tcpm_get_src_ctrl(port)) { + CPRINTSUSB("Skip enable C%d", port); + return EC_ERROR_INVAL; + } + CPRINTSUSB("New charge port: C%d", port); /* @@ -872,14 +894,32 @@ void board_overcurrent_event(int port, int is_overcurrented) } } -void baseboard_en_pwr_pcore_s0(enum gpio_signal signal) +static void baseboard_set_en_pwr_pcore(void) { - - /* EC must AND signals PG_LPDDR4X_S3_OD and PG_GROUPC_S0_OD */ + /* + * EC must AND signals PG_LPDDR4X_S3_OD, PG_GROUPC_S0_OD, and + * EN_PWR_S0_R. + */ gpio_set_level(GPIO_EN_PWR_PCORE_S0_R, gpio_get_level(GPIO_PG_LPDDR4X_S3_OD) && - gpio_get_level(GPIO_PG_GROUPC_S0_OD)); + gpio_get_level(GPIO_PG_GROUPC_S0_OD) && + gpio_get_level(GPIO_EN_PWR_S0_R)); +} + +void baseboard_en_pwr_pcore_signal(enum gpio_signal signal) +{ + baseboard_set_en_pwr_pcore(); +} + +static void baseboard_check_groupc_low(void) +{ + /* Warn if we see unexpected sequencing here */ + if (!gpio_get_level(GPIO_EN_PWR_S0_R) && + gpio_get_level(GPIO_PG_GROUPC_S0_OD)) + CPRINTSCHIP("WARN: PG_GROUPC_S0_OD high while EN_PWR_S0_R low"); + } +DECLARE_DEFERRED(baseboard_check_groupc_low); void baseboard_en_pwr_s0(enum gpio_signal signal) { @@ -889,6 +929,17 @@ void baseboard_en_pwr_s0(enum gpio_signal signal) gpio_get_level(GPIO_SLP_S3_L) && gpio_get_level(GPIO_PG_PWR_S5)); + /* + * If we set EN_PWR_S0_R low, then check PG_GROUPC_S0_OD went low as + * well some reasonable time later + */ + if (!gpio_get_level(GPIO_EN_PWR_S0_R)) + hook_call_deferred(&baseboard_check_groupc_low_data, + 100 * MSEC); + + /* Change EN_PWR_PCORE_S0_R if needed */ + baseboard_set_en_pwr_pcore(); + /* Now chain off to the normal power signal interrupt handler. */ power_signal_interrupt(signal); } |