mb/google/bluey: Add support for off-mode charging

Implement full support for the LB_BOOT_MODE_OFFMODE_CHARGING
state. This mode is detected when the system powers on due to an
external charging event (cable insertion) while the system was
previously fully powered off.

This boot mode is critical for systems that need to maintain a light
footprint to quickly start charging without performing a full boot.
It combines with the existing low-battery mode to define a unified
"low power boot" state.

In romstage, the boot mode is detected using is_off_mode() and
the EC's low battery status, and the result is saved to CBMEM. In
ramstage, this mode is read to determine if heavy, resource-intensive
initializations should be skipped to conserve time and power.

Key changes:
- In romstage.c, implement set_boot_mode() to determine the
  mode (NORMAL, OFFMODE_CHARGING, or LOW_BATTERY) and save it to
  CBMEM_ID_BOOT_MODE.
- In mainboard.c, introduce get_boot_mode() and
  is_low_power_boot() to retrieve and check the CBMEM value.
- Skip heavy ramstage initializations (mainboard_init and
  mainboard_needs_pcie_init) when in a low-power boot mode.
- Update lb_add_boot_mode to report the mode stored in CBMEM
  to the coreboot table.

BUG=b:439819922
TEST=Verify off-mode charging behavior on Google/Quenbi.

Change-Id: I57d25deb6b2b1f9ff199cea5ca2953f10ffb4746
Signed-off-by: Kapil Porwal <kapilporwal@google.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/90176
Reviewed-by: Subrata Banik <subratabanik@google.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
Kapil Porwal 2025-11-24 13:18:05 +05:30 committed by Matt DeVillier
commit 567186a000
2 changed files with 56 additions and 24 deletions

View file

@ -2,6 +2,9 @@
#include <boot/coreboot_tables.h>
#include <bootmode.h>
#include <cbmem.h>
#include <commonlib/bsd/cbmem_id.h>
#include <commonlib/coreboot_tables.h>
#include <console/console.h>
#include <device/device.h>
#include <ec/google/chromeec/ec.h>
@ -13,27 +16,30 @@
#include <soc/usb/usb.h>
/*
* Check if the system is in low battery boot mode.
*
* This function calls the underlying EC function only once during the
* This function calls the underlying PMIC/EC function only once during the
* first execution and caches the result for all subsequent calls.
*
* Return `true` if system battery is below critical threshold, `false` otherwise.
*/
static inline bool is_low_battery_mode(void)
static enum boot_mode_t get_boot_mode(void)
{
if (!CONFIG(EC_GOOGLE_CHROMEEC))
return false;
static bool low_battery_mode_cached = false;
static bool cached_low_battery_result = false;
if (!low_battery_mode_cached) {
cached_low_battery_result = google_chromeec_is_below_critical_threshold();
low_battery_mode_cached = true;
static bool initialized = false;
static enum boot_mode_t boot_mode = LB_BOOT_MODE_NORMAL;
if (!initialized) {
enum boot_mode_t *boot_mode_ptr = cbmem_find(CBMEM_ID_BOOT_MODE);
if (boot_mode_ptr)
boot_mode = *boot_mode_ptr;
printk(BIOS_INFO, "Boot mode is %d\n", boot_mode);
initialized = true;
}
return boot_mode;
}
return cached_low_battery_result;
static bool is_low_power_boot(void)
{
enum boot_mode_t boot_mode = get_boot_mode();
if ((boot_mode == LB_BOOT_MODE_LOW_BATTERY) ||
(boot_mode == LB_BOOT_MODE_OFFMODE_CHARGING))
return true;
return false;
}
static void setup_usb(void)
@ -51,20 +57,17 @@ void lb_add_boot_mode(struct lb_header *header)
mode->tag = LB_TAG_BOOT_MODE;
mode->size = sizeof(*mode);
mode->boot_mode = LB_BOOT_MODE_NORMAL;
mode->boot_mode = get_boot_mode();
if (is_low_battery_mode())
mode->boot_mode = LB_BOOT_MODE_LOW_BATTERY;
/* Enable charging only during low-battery mode */
if (mode->boot_mode == LB_BOOT_MODE_LOW_BATTERY)
/* Enable charging only during off-mode or low-battery mode */
if (is_low_power_boot())
enable_slow_battery_charging();
}
bool mainboard_needs_pcie_init(void)
{
/* Skip PCIe initialization if boot mode is "low-battery" or "off-mode charging"*/
if (is_low_battery_mode())
if (is_low_power_boot())
return false;
return true;
@ -83,7 +86,7 @@ static void display_startup(void)
static void mainboard_init(struct device *dev)
{
/* Skip mainboard initialization if boot mode is "low-battery" or "off-mode charging"*/
if (is_low_battery_mode())
if (is_low_power_boot())
return;
gpi_firmware_load(QUP_0_GSI_BASE);

View file

@ -2,12 +2,29 @@
#include <arch/stages.h>
#include "board.h"
#include <cbmem.h>
#include <commonlib/bsd/cbmem_id.h>
#include <commonlib/coreboot_tables.h>
#include <ec/google/chromeec/ec.h>
#include <gpio.h>
#include <soc/aop_common.h>
#include <soc/qclib_common.h>
#include <soc/shrm.h>
#include <soc/watchdog.h>
static enum boot_mode_t boot_mode = LB_BOOT_MODE_NORMAL;
static void set_boot_mode(void)
{
if (!CONFIG(EC_GOOGLE_CHROMEEC))
return;
if (is_off_mode())
boot_mode = LB_BOOT_MODE_OFFMODE_CHARGING;
else if (google_chromeec_is_below_critical_threshold())
boot_mode = LB_BOOT_MODE_LOW_BATTERY;
}
void platform_romstage_main(void)
{
/* Watchdog must be checked first to avoid erasing watchdog info later. */
@ -18,6 +35,9 @@ void platform_romstage_main(void)
/* QCLib: DDR init & train */
qclib_load_and_run();
/* Underlying PMIC registers are accessible only at this point */
set_boot_mode();
aop_fw_load_reset();
qclib_rerun();
@ -31,3 +51,12 @@ void platform_romstage_main(void)
if (CONFIG(MAINBOARD_HAS_FINGERPRINT_VIA_SPI))
gpio_output(GPIO_EN_FP_RAILS, 1);
}
void platform_romstage_postram(void)
{
enum boot_mode_t *boot_mode_ptr = cbmem_add(CBMEM_ID_BOOT_MODE, sizeof(*boot_mode_ptr));
if (boot_mode_ptr) {
*boot_mode_ptr = boot_mode;
printk(BIOS_INFO, "Boot mode is %d\n", *boot_mode_ptr);
}
}