diff --git a/drivers/input/misc/qpnp-power-on.c b/drivers/input/misc/qpnp-power-on.c index 56918e9ef768..7c9cb4836442 100644 --- a/drivers/input/misc/qpnp-power-on.c +++ b/drivers/input/misc/qpnp-power-on.c @@ -86,6 +86,8 @@ #define QPNP_PON_S3_DBC_CTL(pon) ((pon)->base + 0x75) #define QPNP_PON_SMPL_CTL(pon) ((pon)->base + 0x7F) #define QPNP_PON_TRIGGER_EN(pon) ((pon)->base + 0x80) +#define QPNP_PON_PERPH_RB_SPARE(pon) ((pon)->base + 0x8C) +#define QPNP_PON_DVDD_RB_SPARE(pon) ((pon)->base + 0x8D) #define QPNP_PON_XVDD_RB_SPARE(pon) ((pon)->base + 0x8E) #define QPNP_PON_SOFT_RB_SPARE(pon) ((pon)->base + 0x8F) #define QPNP_PON_SEC_ACCESS(pon) ((pon)->base + 0xD0) @@ -383,6 +385,50 @@ int qpnp_pon_set_restart_reason(enum pon_restart_reason reason) } EXPORT_SYMBOL(qpnp_pon_set_restart_reason); +/** + * qpnp_pon_store_extra_reset_info - Store extra reset info in PMIC register. + * + * Returns = 0 if PMIC feature is not available or store restart reason + * successfully. + * Returns > 0 for errors + * + * This function is used to store extra reset info in PMIC spare register + * which can be preserved during reset. + */ +int qpnp_pon_store_extra_reset_info(u16 mask, u16 val) +{ + int rc = 0; + struct qpnp_pon *pon = sys_reset_dev; + + if (!pon) + return 0; + + if (mask & 0xFF) { + rc = qpnp_pon_masked_write(pon, QPNP_PON_DVDD_RB_SPARE(pon), + (mask & 0xFF), (val & 0xFF)); + if (rc) { + dev_err(pon->dev, + "Failed to store extra reset info to 0x%x\n", + QPNP_PON_DVDD_RB_SPARE(pon)); + return rc; + } + } + + if (mask & 0xFF00) { + rc = qpnp_pon_masked_write(pon, QPNP_PON_XVDD_RB_SPARE(pon), + ((mask >> 8) & 0xFF), ((val >> 8) & 0xFF)); + if (rc) { + dev_err(pon->dev, + "Failed to store extra reset info to 0x%x\n", + QPNP_PON_XVDD_RB_SPARE(pon)); + return rc; + } + } + + return rc; +} +EXPORT_SYMBOL(qpnp_pon_store_extra_reset_info); + /* * qpnp_pon_check_hard_reset_stored() - Checks if the PMIC need to * store hard reset reason. diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c index c1b0799963e6..696381f14dd2 100644 --- a/drivers/power/reset/msm-poweroff.c +++ b/drivers/power/reset/msm-poweroff.c @@ -490,7 +490,7 @@ static void msm_restart_prepare(const char *cmd) pr_info("Forcing a warm reset of the system\n"); /* Hard reset the PMIC unless memory contents must be maintained. */ - if (force_warm_reboot || need_warm_reset) + if (force_warm_reboot || in_panic) qpnp_pon_system_pwr_off(PON_POWER_OFF_WARM_RESET); else qpnp_pon_system_pwr_off(PON_POWER_OFF_HARD_RESET); @@ -500,6 +500,14 @@ static void msm_restart_prepare(const char *cmd) qpnp_pon_set_restart_reason( PON_RESTART_REASON_BOOTLOADER); __raw_writel(0x77665500, restart_reason); + /* set reboot_bl flag in PMIC for cold reset */ + qpnp_pon_store_extra_reset_info(RESET_EXTRA_REBOOT_BL_REASON, + RESET_EXTRA_REBOOT_BL_REASON); + /* + * force cold reboot here to avoid unexpected + * warm boot from bootloader. + */ + qpnp_pon_system_pwr_off(PON_POWER_OFF_HARD_RESET); } else if (!strncmp(cmd, "recovery", 8)) { qpnp_pon_set_restart_reason( PON_RESTART_REASON_RECOVERY); @@ -530,9 +538,33 @@ static void msm_restart_prepare(const char *cmd) restart_reason); } else if (!strncmp(cmd, "edl", 3)) { enable_emergency_dload_mode(); + } else if (!strncmp(cmd, "post-wdt", 8)) { + /* set flag in PMIC to nofity BL post watchdog reboot */ + qpnp_pon_store_extra_reset_info(RESET_EXTRA_POST_REBOOT_MASK, + RESET_EXTRA_POST_WDT_REASON); + /* force cold reboot */ + qpnp_pon_system_pwr_off(PON_POWER_OFF_HARD_RESET); + } else if (!strncmp(cmd, "post-pmicwdt", 12)) { + /* set flag in PMIC to nofity BL post pmic watchdog reboot */ + qpnp_pon_store_extra_reset_info(RESET_EXTRA_POST_REBOOT_MASK, + RESET_EXTRA_POST_PMICWDT_REASON); + /* force cold reboot */ + qpnp_pon_system_pwr_off(PON_POWER_OFF_HARD_RESET); + } else if (!strncmp(cmd, "post-panic", 10)) { + /* set flag in PMIC to nofity BL post panic reboot */ + qpnp_pon_store_extra_reset_info(RESET_EXTRA_POST_REBOOT_MASK, + RESET_EXTRA_POST_PANIC_REASON); + /* force cold reboot */ + qpnp_pon_system_pwr_off(PON_POWER_OFF_HARD_RESET); } else { __raw_writel(0x77665501, restart_reason); } + } else if (in_panic == 1) { + __raw_writel(0x77665505, restart_reason); + qpnp_pon_store_extra_reset_info(RESET_EXTRA_PANIC_REASON, + RESET_EXTRA_PANIC_REASON); + } else { + __raw_writel(0x77665501, restart_reason); } flush_cache_all(); diff --git a/include/linux/input/qpnp-power-on.h b/include/linux/input/qpnp-power-on.h index d80ab2b31d43..8f275086ece1 100644 --- a/include/linux/input/qpnp-power-on.h +++ b/include/linux/input/qpnp-power-on.h @@ -56,6 +56,13 @@ enum pon_restart_reason { PON_RESTART_REASON_KEYS_CLEAR = 0x06, }; +#define RESET_EXTRA_POST_PANIC_REASON (BIT(4) | BIT(5)) +#define RESET_EXTRA_POST_PMICWDT_REASON BIT(5) +#define RESET_EXTRA_POST_WDT_REASON BIT(4) +#define RESET_EXTRA_POST_REBOOT_MASK (BIT(4) | BIT(5) | BIT(6)) +#define RESET_EXTRA_PANIC_REASON BIT(3) +#define RESET_EXTRA_REBOOT_BL_REASON BIT(2) + #ifdef CONFIG_INPUT_QPNP_POWER_ON int qpnp_pon_system_pwr_off(enum pon_power_off_type type); int qpnp_pon_is_warm_reset(void); @@ -64,6 +71,7 @@ int qpnp_pon_wd_config(bool enable); int qpnp_pon_set_restart_reason(enum pon_restart_reason reason); bool qpnp_pon_check_hard_reset_stored(void); int qpnp_pon_modem_pwr_off(enum pon_power_off_type type); +int qpnp_pon_store_extra_reset_info(u16 mask, u16 val); #else @@ -103,6 +111,10 @@ static inline int qpnp_pon_modem_pwr_off(enum pon_power_off_type type) return -ENODEV; } +static inline int qpnp_pon_store_extra_reset_info(u16 mask, u16 val) +{ + return -ENODEV; +} #endif #endif