#define RESET_SEQUENCER_CONFIGURATION (0x0500)
#define PS_HOLD_CONTROL (0x330C)
#define EXYNOS_PMU_SYSIP_DAT0 (0x0810)
-#define LAST_POWERUP_REASON_REG (0x0854) /*EXYNOS9610_POWER_INFORM9*/
+#define EXYNOS_PMU_SYSIP_DAT3 (0x081C)
/* defines for BIG reset */
#define PEND_BIG (1 << 0)
#define PEND_LITTLE (1 << 1)
| RESET_DISABLE_PRESET_DBG \
| RESET_DISABLE_L2RESET)
+static int in_panic = 0;
+static int panic_prep_restart(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ in_panic = 1;
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block panic_blk = {
+ .notifier_call = panic_prep_restart,
+};
+
static void dfd_set_dump_gpr(int en)
{
u32 reg_val;
/* Reboot into recovery */
#define REBOOT_MODE_FACTORY 0xFD
-#define RESET_EXTRA_RESET_KUNPOW_REASON BIT(9)
-#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)
-#define RESET_EXTRA_HW_RESET_REASON BIT(1)
-
#if !defined(CONFIG_SEC_REBOOT)
#ifdef CONFIG_OF
static void exynos_power_off(void)
#endif
#endif
+#define PON_RESTART_REASON_OEM_MIN 0x20
+
static void exynos_reboot(enum reboot_mode mode, const char *cmd)
{
u32 soc_id, revision;
void __iomem *addr;
- void __iomem *addr_extra;
+ void __iomem *restart_reason;
if (!exynos_pmu_base)
return;
#ifdef CONFIG_EXYNOS_ACPM
printk("[%s] reboot cmd: %s\n", __func__, cmd);
addr = exynos_pmu_base + EXYNOS_PMU_SYSIP_DAT0;
- addr_extra = exynos_pmu_base + LAST_POWERUP_REASON_REG;
- /*Clear the last power up reason first*/
- __raw_writel(0, addr_extra);
+ restart_reason = exynos_pmu_base + EXYNOS_PMU_SYSIP_DAT3;
+
if (cmd) {
if (!strcmp((char *)cmd, "charge")) {
__raw_writel(REBOOT_MODE_CHARGE, addr);
__raw_writel(REBOOT_MODE_RECOVERY, addr);
} else if (!strcmp(cmd, "sfactory")) {
__raw_writel(REBOOT_MODE_FACTORY, addr);
- } else if (!strncmp(cmd, "post-wdt",8)) {
- __raw_writel(RESET_EXTRA_POST_WDT_REASON, addr_extra);
- } else if (!strncmp(cmd, "post-pmicwdt",12)) {
- __raw_writel(RESET_EXTRA_POST_PMICWDT_REASON, addr_extra);
- } else if (!strncmp(cmd, "post-panic",10)) {
- __raw_writel(RESET_EXTRA_POST_PANIC_REASON, addr_extra);
}
}
+ if (cmd != NULL) {
+ if (!strncmp(cmd, "bootloader", 10)) {
+ __raw_writel(0x77665500, restart_reason);
+ } else if (!strncmp(cmd, "recovery", 8)) {
+ __raw_writel(0x77665502, restart_reason);
+ } else if (!strcmp(cmd, "rtc")) {
+ __raw_writel(0x77665503, restart_reason);
+ } else if (!strcmp(cmd, "dm-verity device corrupted")) {
+ __raw_writel(0x77665508, restart_reason);
+ } else if (!strcmp(cmd, "dm-verity enforcing")) {
+ __raw_writel(0x77665509, restart_reason);
+ } else if (!strcmp(cmd, "keys clear")) {
+ __raw_writel(0x7766550a, restart_reason);
+ } else if (!strncmp(cmd, "oem-", 4)) {
+ unsigned long code;
+ unsigned long reset_reason;
+ int ret;
+
+ ret = kstrtoul(cmd + 4, 16, &code);
+ if (!ret) {
+ /* Bit-2 to bit-7 of SOFT_RB_SPARE for hard
+ * reset reason:
+ * Value 0 to 31 for common defined features
+ * Value 32 to 63 for oem specific features
+ */
+ reset_reason = code +
+ PON_RESTART_REASON_OEM_MIN;
+ __raw_writel(0x6f656d00 | (code & 0xff),
+ restart_reason);
+ }
+ } else if (!strncmp(cmd, "post-wdt", 8)) {
+ __raw_writel(0x77665508, restart_reason);
+ } else if (!strncmp(cmd, "post-pmicwdt", 12)) {
+ __raw_writel(0x77665507, restart_reason);
+ } else if (!strncmp(cmd, "post-panic", 10)) {
+ __raw_writel(0x77665506, restart_reason);
+ } else {
+ __raw_writel(0x77665501, restart_reason);
+ }
+ } else if (in_panic == 1) {
+ __raw_writel(0x77665505, restart_reason);
+ } else {
+ __raw_writel(0x77665501, restart_reason);
+ }
+
/* Check by each SoC */
soc_id = exynos_soc_info.product_id;
revision = exynos_soc_info.revision;
if (!np)
return -ENODEV;
+ atomic_notifier_chain_register(&panic_notifier_list, &panic_blk);
arm_pm_restart = exynos_reboot;
#if !defined(CONFIG_SEC_REBOOT)
pm_power_off = exynos_power_off;