[PATCH v1] mach-snapdragon:: Add support for fastboot reboot reason detection
Aswin Murugan
aswin.murugan at oss.qualcomm.com
Thu Jan 8 07:55:33 CET 2026
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 <aswin.murugan at oss.qualcomm.com>
---
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 at 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
More information about the U-Boot
mailing list