From: Petr Hodina <[email protected]>

Show in the boot menu header the PMIC Power-On Notification trigger
from the QPNP-PON block of a PMIC, distinguishing cold vs. warm reset
and its cause.

Signed-off-by: Petr Hodina <[email protected]>
---
 cmd/phonemenu.c      | 10 +++++++
 cmd/phonemenu_qcom.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/phonemenu.h  |  3 ++
 3 files changed, 97 insertions(+)

diff --git a/cmd/phonemenu.c b/cmd/phonemenu.c
index 8f29d8d704b..f031b891641 100644
--- a/cmd/phonemenu.c
+++ b/cmd/phonemenu.c
@@ -458,6 +458,12 @@ __weak int phonemenu_ab_slot(void)
        return ab_select_slot(desc, &misc, false);
 }
 
+/* PMIC power-on trigger for the header, NULL if unknown */
+__weak const char *phonemenu_pon_status(void)
+{
+       return NULL;
+}
+
 static const char *pm_slot(void)
 {
        int slot;
@@ -510,6 +516,7 @@ static int do_phonemenu(struct cmd_tbl *cmdtp, int flag, 
int argc,
        static char slot_line[96];
        const char *slot = pm_slot();
        const char *reason = pm_reason();
+       const char *pon = phonemenu_pon_status();
        const char *sub = (argc > 1) ? argv[1] : "main";
        int n = 0;
 
@@ -519,6 +526,9 @@ static int do_phonemenu(struct cmd_tbl *cmdtp, int flag, 
int argc,
        if (reason)
                n += snprintf(slot_line + n, sizeof(slot_line) - n,
                              "%s%s", n ? "  -  " : "", reason);
+       if (pon)
+               n += snprintf(slot_line + n, sizeof(slot_line) - n,
+                             "%s%s", n ? "  -  " : "", pon);
 
        if (!strcmp(sub, "advanced"))
                return pm_run(pm_advanced, ARRAY_SIZE(pm_advanced),
diff --git a/cmd/phonemenu_qcom.c b/cmd/phonemenu_qcom.c
index d8a295c10dc..20a1cced8d9 100644
--- a/cmd/phonemenu_qcom.c
+++ b/cmd/phonemenu_qcom.c
@@ -5,8 +5,12 @@
 
 #include <android_ab.h>
 #include <blk.h>
+#include <dm.h>
+#include <dm/ofnode.h>
+#include <dm/uclass.h>
 #include <part.h>
 #include <phonemenu.h>
+#include <power/pmic.h>
 #include <linux/errno.h>
 
 #if IS_ENABLED(CONFIG_ARCH_SNAPDRAGON)
@@ -25,4 +29,84 @@ int phonemenu_ab_slot(void)
        return ab_select_slot(desc, &unused, false);
 }
 
+/*
+ * PMIC PON ("Power-On Notification") boot trigger from the QPNP-PON block
+ * in the primary PMIC. Two registers are interesting:
+ *
+ *   PON_REASON1 (PON base + 0x0c) - cold-reset trigger:
+ *     0x80 KPDPWR   = power button press
+ *     0x40 CBLPWR   = cable inserted while off
+ *     0x20 PON1     = generic PON
+ *     0x10 USB_CHG  = USB charger inserted
+ *     0x08 DC_CHG   = DC charger inserted
+ *     0x04 RTC      = RTC alarm
+ *     0x02 SMPL     = sudden mains power loss / auto-restart
+ *     0x01 HARDRST  = hard reset requested
+ *
+ *   WARM_RESET_REASON1 (PON base + 0x0a) - warm-reset trigger:
+ *     0x80 KPDPWR        = power-button reset
+ *     0x40 RESIN         = volume-down (or assigned) reset
+ *     0x20 KPDPWR_RESIN  = power + vol-down combo (force reset)
+ *     0x04 PMIC_WD       = PMIC watchdog
+ *     0x02 PS_HOLD       = SoC pulled PS_HOLD low (normal reboot)
+ *     0x01 SOFT          = soft reset request
+ *
+ * If WARM_RESET_REASON1 is non-zero this was a warm reboot and we use it;
+ * otherwise PON_REASON1 wins. Returned strings are short for the menu
+ * subtitle. NULL if we can't find a PM660-class PMIC at all.
+ */
+const char *phonemenu_pon_status(void)
+{
+       struct udevice *pmic;
+       int r;
+
+       for (uclass_first_device(UCLASS_PMIC, &pmic);
+            pmic;
+            uclass_next_device(&pmic)) {
+               if (ofnode_device_is_compatible(dev_ofnode(pmic),
+                                               "qcom,pm660"))
+                       break;
+       }
+       if (!pmic)
+               return NULL;
+
+       r = pmic_reg_read(pmic, 0x80a);
+       if (r > 0) {
+               if (r & 0x20)
+                       return "warm: pwr+vol-";
+               if (r & 0x80)
+                       return "warm: pwr";
+               if (r & 0x40)
+                       return "warm: vol-";
+               if (r & 0x04)
+                       return "warm: wdog";
+               if (r & 0x02)
+                       return "warm: reboot";
+               if (r & 0x01)
+                       return "warm: soft";
+               return "warm";
+       }
+
+       r = pmic_reg_read(pmic, 0x80c);
+       if (r > 0) {
+               if (r & 0x80)
+                       return "cold: pwr";
+               if (r & 0x40)
+                       return "cold: cable";
+               if (r & 0x10)
+                       return "cold: usb";
+               if (r & 0x08)
+                       return "cold: dc";
+               if (r & 0x04)
+                       return "cold: rtc";
+               if (r & 0x02)
+                       return "cold: smpl";
+               if (r & 0x01)
+                       return "cold: hardrst";
+               if (r & 0x20)
+                       return "cold";
+       }
+       return NULL;
+}
+
 #endif /* CONFIG_ARCH_SNAPDRAGON */
diff --git a/include/phonemenu.h b/include/phonemenu.h
index 5d6ded84197..ad33e9511c1 100644
--- a/include/phonemenu.h
+++ b/include/phonemenu.h
@@ -11,4 +11,7 @@ struct blk_desc *phonemenu_storage_desc(void);
 /* Active A/B slot (0 = a, 1 = b) or a negative errno */
 int phonemenu_ab_slot(void);
 
+/* Short PMIC power-on trigger string, or NULL if unknown */
+const char *phonemenu_pon_status(void);
+
 #endif

-- 
2.55.0


Reply via email to