msm: restart: call secure code to disable arbiter

The other masters in the MSM could be accessing the pmic while
pmic has raised the reset interrupt. This might cause pmic
lockups.

Disable the pmic arbiter by calling secure code when we handle
the reset interrupt from pmic. This will disable all the ssbi
transactions to the pmic avoiding a possible lockup.

Also since we wont be lowering ps_hold for pmic initiated startups
piggy back on lower_pshold to return from the power off function
so that we can call in the secure manager as the last step.

Additionally, since we will be busy looping until the pmic resets
us, pet the watchdog.

CRs-Fixed: 306410
Signed-off-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org>
diff --git a/arch/arm/mach-msm/restart.c b/arch/arm/mach-msm/restart.c
index dba575c..7ddcde7 100644
--- a/arch/arm/mach-msm/restart.c
+++ b/arch/arm/mach-msm/restart.c
@@ -31,6 +31,8 @@
 #include <mach/restart.h>
 #include <mach/socinfo.h>
 #include <mach/irqs.h>
+#include <mach/scm.h>
+#include "msm_watchdog.h"
 
 #define WDT0_RST       (MSM_TMR0_BASE + 0x38)
 #define WDT0_EN        (MSM_TMR0_BASE + 0x40)
@@ -42,6 +44,8 @@
 #define RESTART_REASON_ADDR 0x65C
 #define DLOAD_MODE_ADDR     0x0
 
+#define SCM_IO_DISABLE_PMIC_ARBITER	1
+
 static int restart_mode;
 void *restart_reason;
 
@@ -119,10 +123,11 @@
 		pm8901_reset_pwr_off(0);
 	}
 	pm8xxx_reset_pwr_off(0);
-	if (lower_pshold)
+	if (lower_pshold) {
 		__raw_writel(0, PSHOLD_CTL_SU);
-	mdelay(10000);
-	printk(KERN_ERR "Powering off has failed\n");
+		mdelay(10000);
+		printk(KERN_ERR "Powering off has failed\n");
+	}
 	return;
 }
 
@@ -134,15 +139,27 @@
 
 static void cpu_power_off(void *data)
 {
+	int rc;
+
 	pr_err("PMIC Initiated shutdown %s cpu=%d\n", __func__,
 						smp_processor_id());
-	if (smp_processor_id() == 0)
+	if (smp_processor_id() == 0) {
 		/*
 		 * PMIC initiated power off, do not lower ps_hold, pmic will
 		 * shut msm down
 		 */
 		__msm_power_off(0);
 
+		pet_watchdog();
+		pr_err("Calling scm to disable arbiter\n");
+		/* call secure manager to disable arbiter and never return */
+		rc = scm_call_atomic1(SCM_SVC_PWR,
+						SCM_IO_DISABLE_PMIC_ARBITER, 1);
+
+		pr_err("SCM returned even when asked to busy loop rc=%d\n", rc);
+		pr_err("waiting on pmic to shut msm down\n");
+	}
+
 	preempt_disable();
 	while (1)
 		;