summaryrefslogtreecommitdiff
path: root/baseboard/guybrush/baseboard.c
diff options
context:
space:
mode:
Diffstat (limited to 'baseboard/guybrush/baseboard.c')
-rw-r--r--baseboard/guybrush/baseboard.c109
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);
}