Add functionality to detect and handle reboot-to-bootloader requests by reading PMIC PON (Power On) registers. When the device is rebooted with the bootloader flag set, U-Boot will automatically enter fastboot mode.
This implementation supports multiple PMIC generations: - Gen 4 PMICs: Uses PON_SOFT_RB_SPARE register (0x88F) - Newer PMICs: Uses SDAM-based PON_REBOOT_REASON register (0x7148) The PMIC model is automatically detected via revision ID registers to determine the correct register addresses. After detecting a fastboot reboot reason, the register is cleared and fastboot mode is entered via the "run fastboot" command. Signed-off-by: Aswin Murugan <[email protected]> --- arch/arm/mach-snapdragon/board.c | 146 +++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) diff --git a/arch/arm/mach-snapdragon/board.c b/arch/arm/mach-snapdragon/board.c index 5fb3240acc5..02b84297e05 100644 --- a/arch/arm/mach-snapdragon/board.c +++ b/arch/arm/mach-snapdragon/board.c @@ -19,6 +19,7 @@ #include <dm/uclass-internal.h> #include <dm/read.h> #include <power/regulator.h> +#include <power/pmic.h> #include <env.h> #include <fdt_support.h> #include <init.h> @@ -32,9 +33,32 @@ #include <usb.h> #include <sort.h> #include <time.h> +#include <command.h> #include "qcom-priv.h" +/* Reboot mode definitions */ +#define QCOM_REBOOT_MODE_FASTBOOT 0x2 +#define QCOM_REBOOT_MODE_MASK 0xFE + +/* PON (Power On) register addresses - Gen 4 PMICs */ +#define QCOM_PON_BASE_ADDR 0x800 +#define QCOM_PON_PERPH_SUBTYPE (QCOM_PON_BASE_ADDR + 0x5) +#define QCOM_PON_SOFT_RB_SPARE (QCOM_PON_BASE_ADDR + 0x8F) + +/* PON register addresses - Newer PMICs (SDAM-based) */ +#define QCOM_PON_REBOOT_REASON_SDAM 0x7148 + +/* PMIC Revision ID registers */ +#define QCOM_PMIC_REVID_BASE 0x0100 +#define QCOM_PMIC_METAL_REV (QCOM_PMIC_REVID_BASE + 0x02) + +/* PMIC identification values */ +#define QCOM_PMIC_TYPE_QC 0x51 +#define QCOM_PMIC_SUBTYPE_GEN4 0x4 +#define QCOM_PMIC_MODEL_PM855 30 +#define QCOM_PMIC_MODEL_INVALID 0x00 + DECLARE_GLOBAL_DATA_PTR; enum qcom_boot_source qcom_boot_source __section(".data") = 0; @@ -489,6 +513,125 @@ static void configure_env(void) qcom_set_serialno(); } +/** + * detect_pmic_model() - Detect PMIC model from revision ID registers + * @dev: PMIC device + * + * Reads the PMIC revision ID registers to identify the PMIC model. + * This is used to determine which register addresses to use for + * reading the reboot reason. + * + * Return: PMIC model number or QCOM_PMIC_MODEL_INVALID on error + */ +static int detect_pmic_model(struct udevice *dev) +{ + u8 rev_id[4] = {0}; + int ret, i; + u8 pmic_model; + + /* Read 4 bytes from PMIC REVID registers */ + for (i = 0; i < 4; i++) { + ret = pmic_reg_read(dev, QCOM_PMIC_METAL_REV + i); + if (ret < 0) { + log_debug("Failed to read PMIC REVID reg 0x%X: %d\n", + QCOM_PMIC_METAL_REV + i, ret); + return QCOM_PMIC_MODEL_INVALID; + } + rev_id[i] = (u8)ret; + } + + /* Verify this is a Qualcomm PMIC device */ + if (rev_id[2] != QCOM_PMIC_TYPE_QC) { + log_debug("Not a Qualcomm PMIC (type=0x%02X)\n", + rev_id[2]); + return QCOM_PMIC_MODEL_INVALID; + } + + pmic_model = rev_id[3]; + log_debug("PMIC Model: 0x%02X (Metal=0x%02X, Layer=0x%02X)\n", + pmic_model, rev_id[0], rev_id[1]); + + return pmic_model; +} + +/** + * check_fastboot_mode() - Check if device should enter fastboot mode + * + * Reads the PMIC PON (Power On) register to check if the reboot reason + * indicates that fastboot mode should be entered. The register address + * varies depending on the PMIC generation. + * + * For Gen 4 PMICs: Uses PON_SOFT_RB_SPARE register + * For newer PMICs: Uses SDAM-based PON_REBOOT_REASON register + * + * If fastboot mode is detected, clears the reboot reason and enters + * fastboot mode via the "run fastboot" command. + * + * Return: 0 on success, negative error code on failure + */ +static int check_fastboot_mode(void) +{ + struct udevice *dev; + int ret, reboot_reason, reg_val; + u32 pon_reset_addr; + u8 peripheral_subtype; + int pmic_model; + + if (!IS_ENABLED(CONFIG_DM_PMIC)) + return 0; + + ret = pmic_get("pmic@0", &dev); + if (ret) + return ret; + + /* Detect PMIC model for address resolution */ + pmic_model = detect_pmic_model(dev); + if (pmic_model == QCOM_PMIC_MODEL_INVALID) + return -1; + + peripheral_subtype = pmic_reg_read(dev, QCOM_PON_PERPH_SUBTYPE); + + /* Select register address based on PMIC generation */ + if (peripheral_subtype == QCOM_PMIC_SUBTYPE_GEN4) + pon_reset_addr = QCOM_PON_SOFT_RB_SPARE; + else + pon_reset_addr = QCOM_PON_REBOOT_REASON_SDAM; + + log_debug("PON reg: 0x%X (subtype=0x%X, model=0x%X)\n", + pon_reset_addr, peripheral_subtype, pmic_model); + + /* Read reboot reason */ + reg_val = pmic_reg_read(dev, pon_reset_addr); + if (reg_val < 0) { + log_debug("Failed to read reboot reason: %d\n", reg_val); + return reg_val; + } + + reboot_reason = (reg_val & QCOM_REBOOT_MODE_MASK) >> 1; + log_debug("Reboot reason: 0x%02X (raw=0x%02X)\n", + reboot_reason, reg_val); + + if (reboot_reason == QCOM_REBOOT_MODE_FASTBOOT) { + log_info("Fastboot mode detected, entering fastboot...\n"); + + /* Clear reboot reason */ + reg_val &= (~QCOM_REBOOT_MODE_MASK); + + if (pmic_model == QCOM_PMIC_MODEL_PM855) + pon_reset_addr = QCOM_PON_SOFT_RB_SPARE; + + ret = pmic_reg_write(dev, pon_reset_addr, reg_val); + if (ret != 0) + log_warning("Failed to clear reboot reason (%d)\n", + ret); + + /* Enter fastboot mode */ + ret = run_command("run fastboot", 0); + } + + return ret; +} + void qcom_show_boot_source(void) { const char *name = "UNKNOWN"; @@ -573,6 +716,9 @@ int board_late_init(void) /* Configure the dfu_string for capsule updates */ qcom_configure_capsule_updates(); + /* Check reboot reason for fastboot */ + check_fastboot_mode(); + return 0; } -- 2.34.1

