msm: restart: Handle reset interrupt from pmic
The reset interrupt in the pmic indicates the pmic will shutdown
the msm in few seconds - it does so by lowering the reset_n line
to the msm.
When this interrupt is triggered it is required that no more ssbi
transactions are initiated and the msm should cleanup and prepare
for the impending shutdown. There is no need to lower ps_hold in
this case as the pmic will shutdown the msm regardless.
Also since we don't want any ssbi transactions, force shutdown
nonboot cpus. This will prevent ssbi transactions to the pmic for
lower/raising nonboot cpu's voltages as they enter/exit idle states.
Signed-off-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org>
diff --git a/arch/arm/mach-msm/board-msm8960.c b/arch/arm/mach-msm/board-msm8960.c
index 892cba0..a460ca7 100644
--- a/arch/arm/mach-msm/board-msm8960.c
+++ b/arch/arm/mach-msm/board-msm8960.c
@@ -62,6 +62,7 @@
#include <mach/dma.h>
#include <mach/msm_dsps.h>
#include <mach/msm_xo.h>
+#include <mach/restart.h>
#ifdef CONFIG_WCD9310_CODEC
#include <linux/slimbus/slimbus.h>
@@ -4082,6 +4083,8 @@
BUG_ON(msm_rpm_init(&msm_rpm_data));
BUG_ON(msm_rpmrs_levels_init(msm_rpmrs_levels,
ARRAY_SIZE(msm_rpmrs_levels)));
+
+ pmic_reset_irq = PM8921_IRQ_BASE + PM8921_RESOUT_IRQ;
regulator_suppress_info_printing();
if (msm_xo_init())
pr_err("Failed to initialize XO votes\n");
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 29c6ceb..88d8a4a 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -88,6 +88,7 @@
#include <mach/sdio_al.h>
#include <mach/rpm.h>
#include <mach/rpm-regulator.h>
+#include <mach/restart.h>
#include "devices.h"
#include "devices-msm8x60.h"
@@ -9986,6 +9987,8 @@
{
uint32_t soc_platform_version;
+ pmic_reset_irq = PM8058_RESOUT_IRQ(PM8058_IRQ_BASE);
+
/*
* Initialize RPM first as other drivers and devices may need
* it for their initialization.
diff --git a/arch/arm/mach-msm/include/mach/restart.h b/arch/arm/mach-msm/include/mach/restart.h
index 72ce29b..3deeeaf 100644
--- a/arch/arm/mach-msm/include/mach/restart.h
+++ b/arch/arm/mach-msm/include/mach/restart.h
@@ -23,5 +23,7 @@
#define msm_set_restart_mode(mode)
#endif
+extern int pmic_reset_irq;
+
#endif
diff --git a/arch/arm/mach-msm/restart.c b/arch/arm/mach-msm/restart.c
index 2b82bf1..dba575c 100644
--- a/arch/arm/mach-msm/restart.c
+++ b/arch/arm/mach-msm/restart.c
@@ -19,6 +19,8 @@
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/pm.h>
+#include <linux/cpu.h>
+#include <linux/interrupt.h>
#include <linux/mfd/pmic8058.h>
#include <linux/mfd/pmic8901.h>
#include <linux/mfd/pm8xxx/misc.h>
@@ -28,6 +30,7 @@
#include <mach/msm_iomap.h>
#include <mach/restart.h>
#include <mach/socinfo.h>
+#include <mach/irqs.h>
#define WDT0_RST (MSM_TMR0_BASE + 0x38)
#define WDT0_EN (MSM_TMR0_BASE + 0x40)
@@ -42,6 +45,8 @@
static int restart_mode;
void *restart_reason;
+int pmic_reset_irq;
+
#ifdef CONFIG_MSM_DLOAD_MODE
static int in_panic;
static void *dload_mode_addr;
@@ -103,9 +108,9 @@
}
EXPORT_SYMBOL(msm_set_restart_mode);
-static void msm_power_off(void)
+static void __msm_power_off(int lower_pshold)
{
- printk(KERN_NOTICE "Powering off the SoC\n");
+ printk(KERN_CRIT "Powering off the SoC\n");
#ifdef CONFIG_MSM_DLOAD_MODE
set_dload_mode(0);
#endif
@@ -114,12 +119,48 @@
pm8901_reset_pwr_off(0);
}
pm8xxx_reset_pwr_off(0);
- __raw_writel(0, PSHOLD_CTL_SU);
+ if (lower_pshold)
+ __raw_writel(0, PSHOLD_CTL_SU);
mdelay(10000);
printk(KERN_ERR "Powering off has failed\n");
return;
}
+static void msm_power_off(void)
+{
+ /* MSM initiated power off, lower ps_hold */
+ __msm_power_off(1);
+}
+
+static void cpu_power_off(void *data)
+{
+ pr_err("PMIC Initiated shutdown %s cpu=%d\n", __func__,
+ smp_processor_id());
+ if (smp_processor_id() == 0)
+ /*
+ * PMIC initiated power off, do not lower ps_hold, pmic will
+ * shut msm down
+ */
+ __msm_power_off(0);
+
+ preempt_disable();
+ while (1)
+ ;
+}
+
+static irqreturn_t resout_irq_handler(int irq, void *dev_id)
+{
+ pr_warn("%s PMIC Initiated shutdown\n", __func__);
+ oops_in_progress = 1;
+ smp_call_function_many(cpu_online_mask, cpu_power_off, NULL, 0);
+ if (smp_processor_id() == 0)
+ cpu_power_off(NULL);
+ preempt_disable();
+ while (1)
+ ;
+ return IRQ_HANDLED;
+}
+
void arch_reset(char mode, const char *cmd)
{
@@ -179,6 +220,8 @@
static int __init msm_restart_init(void)
{
+ int rc;
+
#ifdef CONFIG_MSM_DLOAD_MODE
atomic_notifier_chain_register(&panic_notifier_list, &panic_blk);
dload_mode_addr = MSM_IMEM_BASE + DLOAD_MODE_ADDR;
@@ -189,6 +232,16 @@
restart_reason = MSM_IMEM_BASE + RESTART_REASON_ADDR;
pm_power_off = msm_power_off;
+ if (pmic_reset_irq != 0) {
+ rc = request_any_context_irq(pmic_reset_irq,
+ resout_irq_handler, IRQF_TRIGGER_HIGH,
+ "restart_from_pmic", NULL);
+ if (rc < 0)
+ pr_err("pmic restart irq fail rc = %d\n", rc);
+ } else {
+ pr_warn("no pmic restart interrupt specified\n");
+ }
+
return 0;
}