msm: pm-boot: Common API to configure warmboot address

Common API to configure warmboot address during power collapse across
multiple msm platforms.

Change-Id: I64cff7feeca830f75b3873198262bd6f9f818f90
Signed-off-by: Maheshkumar Sivasubramanian <msivasub@codeaurora.org>
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index b7357cd..326abed 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -139,6 +139,7 @@
 	obj-$(CONFIG_ARCH_MSM7X27A) += pm2.o
 	obj-$(CONFIG_ARCH_MSM7X25) += pm.o
 	obj-$(CONFIG_ARCH_MSM7X01A) += pm.o
+	obj-y += pm-boot.o
 else
 	obj-y += no-pm.o
 endif
diff --git a/arch/arm/mach-msm/board-msm7x27.c b/arch/arm/mach-msm/board-msm7x27.c
index 22de352..ef1bf2d 100644
--- a/arch/arm/mach-msm/board-msm7x27.c
+++ b/arch/arm/mach-msm/board-msm7x27.c
@@ -68,6 +68,7 @@
 #include "acpuclock.h"
 #include "msm-keypad-devices.h"
 #include "pm.h"
+#include "pm-boot.h"
 
 #ifdef CONFIG_ARCH_MSM7X25
 #define MSM_PMEM_MDP_SIZE	0xb21000
@@ -1711,6 +1712,9 @@
 	else
 		msm_pm_set_platform_data(msm7x25_pm_data,
 					ARRAY_SIZE(msm7x25_pm_data));
+
+	BUG_ON(msm_pm_boot_init(MSM_PM_BOOT_CONFIG_RESET_VECTOR,
+				ioremap(0, PAGE_SIZE)));
 	msm7x27_wlan_init();
 }
 
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index cd590c3..56c135d 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -53,6 +53,7 @@
 #include "pm.h"
 #include <mach/rpc_server_handset.h>
 #include <mach/socinfo.h>
+#include "pm-boot.h"
 
 #define PMEM_KERNEL_EBI1_SIZE	0x3A000
 #define MSM_PMEM_AUDIO_SIZE	0x5B000
@@ -3199,6 +3200,8 @@
 
 	msm_pm_set_platform_data(msm7x27a_pm_data,
 				ARRAY_SIZE(msm7x27a_pm_data));
+	BUG_ON(msm_pm_boot_init(MSM_PM_BOOT_CONFIG_RESET_VECTOR,
+				ioremap(0, PAGE_SIZE)));
 
 #if defined(CONFIG_I2C) && defined(CONFIG_GPIO_SX150X)
 	register_i2c_devices();
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index b71061a..31754c4 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -80,6 +80,7 @@
 #include <mach/usbdiag.h>
 #endif
 #include "pm.h"
+#include "pm-boot.h"
 #include "spm.h"
 #include "acpuclock.h"
 #include <mach/dal_axi.h>
@@ -7002,6 +7003,8 @@
 
 	msm_fb_add_devices();
 	msm_pm_set_platform_data(msm_pm_data, ARRAY_SIZE(msm_pm_data));
+	BUG_ON(msm_pm_boot_init(MSM_PM_BOOT_CONFIG_RESET_VECTOR,
+				(uint32_t *)PAGE_OFFSET));
 	msm_device_i2c_init();
 	msm_device_i2c_2_init();
 	qup_device_i2c_init();
diff --git a/arch/arm/mach-msm/board-msm8960.c b/arch/arm/mach-msm/board-msm8960.c
index a19cf27..a7cd02f 100644
--- a/arch/arm/mach-msm/board-msm8960.c
+++ b/arch/arm/mach-msm/board-msm8960.c
@@ -88,6 +88,7 @@
 #include "acpuclock.h"
 #include "rpm_log.h"
 #include "smd_private.h"
+#include "pm-boot.h"
 
 static struct platform_device msm_fm_platform_init = {
 	.name = "iris_fm",
@@ -4460,6 +4461,7 @@
 	msm_pm_set_rpm_wakeup_irq(RPM_APCC_CPU0_WAKE_UP_IRQ);
 	msm_cpuidle_set_states(msm_cstates, ARRAY_SIZE(msm_cstates),
 				msm_pm_data);
+	BUG_ON(msm_pm_boot_init(MSM_PM_BOOT_CONFIG_TZ, NULL));
 }
 
 static void __init msm8960_rumi3_init(void)
@@ -4492,6 +4494,7 @@
 	msm_pm_set_rpm_wakeup_irq(RPM_APCC_CPU0_WAKE_UP_IRQ);
 	msm_cpuidle_set_states(msm_cstates, ARRAY_SIZE(msm_cstates),
 				msm_pm_data);
+	BUG_ON(msm_pm_boot_init(MSM_PM_BOOT_CONFIG_TZ, NULL));
 }
 
 static void __init msm8960_cdp_init(void)
@@ -4551,6 +4554,7 @@
 	msm_cpuidle_set_states(msm_cstates, ARRAY_SIZE(msm_cstates),
 				msm_pm_data);
 	change_memory_power = &msm8960_change_memory_power;
+	BUG_ON(msm_pm_boot_init(MSM_PM_BOOT_CONFIG_TZ, NULL));
 }
 
 MACHINE_START(MSM8960_SIM, "QCT MSM8960 SIMULATOR")
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 956387a..7fc06bd 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -108,7 +108,7 @@
 #include <linux/platform_data/qcom_crypto_device.h>
 #include "rpm_resources.h"
 #include "acpuclock.h"
-
+#include "pm-boot.h"
 #define MSM_SHARED_RAM_PHYS 0x40000000
 
 /* Macros assume PMIC GPIOs start at 0 */
@@ -10321,6 +10321,7 @@
 	msm_pm_set_rpm_wakeup_irq(RPM_SCSS_CPU0_WAKE_UP_IRQ);
 	msm_cpuidle_set_states(msm_cstates, ARRAY_SIZE(msm_cstates),
 				msm_pm_data);
+	BUG_ON(msm_pm_boot_init(MSM_PM_BOOT_CONFIG_TZ, NULL));
 
 #ifdef CONFIG_SENSORS_MSM_ADC
 	if (machine_is_msm8x60_fluid()) {
diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c
index b7f6608..0dcd0f4 100644
--- a/arch/arm/mach-msm/board-qsd8x50.c
+++ b/arch/arm/mach-msm/board-qsd8x50.c
@@ -55,6 +55,7 @@
 #include "msm-keypad-devices.h"
 #include "acpuclock.h"
 #include "pm.h"
+#include "pm-boot.h"
 #include "proc_comm.h"
 #ifdef CONFIG_USB_ANDROID
 #include <linux/usb/android_composite.h>
@@ -2436,6 +2437,8 @@
 	spi_register_board_info(msm_spi_board_info,
 				ARRAY_SIZE(msm_spi_board_info));
 	msm_pm_set_platform_data(msm_pm_data, ARRAY_SIZE(msm_pm_data));
+	BUG_ON(msm_pm_boot_init(MSM_PM_BOOT_CONFIG_RESET_VECTOR,
+				(uint32_t *)PAGE_OFFSET));
 
 #ifdef CONFIG_SURF_FFA_GPIO_KEYPAD
 	if (machine_is_qsd8x50_ffa())
diff --git a/arch/arm/mach-msm/idle.h b/arch/arm/mach-msm/idle.h
index 740ef91..138db45 100644
--- a/arch/arm/mach-msm/idle.h
+++ b/arch/arm/mach-msm/idle.h
@@ -17,6 +17,7 @@
 int msm_arch_idle(void);
 int msm_pm_collapse(void);
 void msm_pm_collapse_exit(void);
+void msm_warmboot_entry(void);
 
 #ifdef CONFIG_CPU_V7
 void msm_pm_boot_entry(void);
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 911d546..6a78597 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -48,6 +48,7 @@
 #include "spm.h"
 #include "timer.h"
 #include "qdss.h"
+#include "pm-boot.h"
 
 /******************************************************************************
  * Debug Definitions
@@ -649,7 +650,7 @@
 
 	entry = (!dev->cpu || from_idle) ?
 		msm_pm_collapse_exit : msm_secondary_startup;
-	msm_pm_write_boot_vector(dev->cpu, virt_to_phys(entry));
+	msm_pm_boot_config_before_pc(dev->cpu, virt_to_phys(entry));
 
 	if (MSM_PM_DEBUG_RESET_VECTOR & msm_pm_debug_mask)
 		pr_info("CPU%u: %s: program vector to %p\n",
@@ -661,6 +662,8 @@
 
 	collapsed = msm_pm_collapse();
 
+	msm_pm_boot_config_after_pc(dev->cpu);
+
 	if (collapsed) {
 #ifdef CONFIG_VFP
 		vfp_reinit();
@@ -1179,15 +1182,6 @@
 		init_completion(&dev->cpu_killed);
 #endif
 	}
-#ifdef CONFIG_MSM_SCM
-	ret = scm_set_boot_addr((void *)virt_to_phys(msm_pm_boot_entry),
-			SCM_FLAG_WARMBOOT_CPU0 | SCM_FLAG_WARMBOOT_CPU1);
-	if (ret) {
-		pr_err("%s: failed to set up scm boot addr: %d\n",
-			__func__, ret);
-		return ret;
-	}
-#endif
 
 #ifdef CONFIG_MSM_IDLE_STATS
 	for_each_possible_cpu(cpu) {
diff --git a/arch/arm/mach-msm/pm-boot.c b/arch/arm/mach-msm/pm-boot.c
new file mode 100644
index 0000000..6becc61
--- /dev/null
+++ b/arch/arm/mach-msm/pm-boot.c
@@ -0,0 +1,114 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include "scm-boot.h"
+#include "idle.h"
+#include "pm-boot.h"
+
+static uint32_t *msm_pm_reset_vector;
+static uint32_t saved_vector[2];
+static void (*msm_pm_boot_before_pc)(unsigned int cpu, unsigned long entry);
+static void (*msm_pm_boot_after_pc)(unsigned int cpu);
+
+#ifdef CONFIG_MSM_SCM
+static int __init msm_pm_tz_boot_init(void)
+{
+	int flag = 0;
+	if (num_possible_cpus() == 1)
+		flag = SCM_FLAG_WARMBOOT_CPU0;
+	else if (num_possible_cpus() == 2)
+		flag = SCM_FLAG_WARMBOOT_CPU0 | SCM_FLAG_WARMBOOT_CPU1;
+	else
+		__WARN();
+
+	return scm_set_boot_addr((void *)virt_to_phys(msm_pm_boot_entry), flag);
+}
+
+static void msm_pm_config_tz_before_pc(unsigned int cpu,
+		unsigned long entry)
+{
+	msm_pm_write_boot_vector(cpu, entry);
+}
+#else
+static int __init msm_pm_tz_boot_init(void)
+{
+	return 0;
+};
+
+static inline void msm_pm_config_tz_before_pc(unsigned int cpu,
+		unsigned long entry) {}
+#endif
+
+static int __init msm_pm_boot_reset_vector_init(uint32_t *reset_vector)
+{
+	WARN_ON(!reset_vector);
+	msm_pm_reset_vector = reset_vector;
+	mb();
+
+	return 0;
+}
+
+static void msm_pm_config_rst_vector_before_pc(unsigned int cpu,
+		unsigned long entry)
+{
+	saved_vector[0] = msm_pm_reset_vector[0];
+	saved_vector[1] = msm_pm_reset_vector[1];
+	msm_pm_reset_vector[0] = 0xE51FF004; /* ldr pc, 4 */
+	msm_pm_reset_vector[1] = entry;
+}
+
+static void msm_pm_config_rst_vector_after_pc(unsigned int cpu)
+{
+	msm_pm_reset_vector[0] = saved_vector[0];
+	msm_pm_reset_vector[1] = saved_vector[1];
+}
+
+void msm_pm_boot_config_before_pc(unsigned int cpu, unsigned long entry)
+{
+	if (msm_pm_boot_before_pc)
+		msm_pm_boot_before_pc(cpu, entry);
+}
+
+void msm_pm_boot_config_after_pc(unsigned int cpu)
+{
+	if (msm_pm_boot_after_pc)
+		msm_pm_boot_after_pc(cpu);
+}
+
+int __init msm_pm_boot_init(int tz_available, uint32_t* address)
+{
+	int ret = 0;
+
+	switch (tz_available) {
+	case MSM_PM_BOOT_CONFIG_TZ:
+		ret = msm_pm_tz_boot_init();
+		msm_pm_boot_before_pc = msm_pm_config_tz_before_pc;
+		msm_pm_boot_after_pc = NULL;
+		break;
+	case MSM_PM_BOOT_CONFIG_RESET_VECTOR:
+		ret = msm_pm_boot_reset_vector_init(address);
+		msm_pm_boot_before_pc
+			= msm_pm_config_rst_vector_before_pc;
+		msm_pm_boot_after_pc
+			= msm_pm_config_rst_vector_after_pc;
+		break;
+	default:
+		__WARN();
+	}
+
+	return ret;
+}
diff --git a/arch/arm/mach-msm/pm-boot.h b/arch/arm/mach-msm/pm-boot.h
new file mode 100644
index 0000000..7e1a439
--- /dev/null
+++ b/arch/arm/mach-msm/pm-boot.h
@@ -0,0 +1,25 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef _ARCH_ARM_MACH_MSM_PM_BOOT_H
+#define _ARCH_ARM_MACH_MSM_PM_BOOT_H
+
+enum {
+	MSM_PM_BOOT_CONFIG_TZ		= 0,
+	MSM_PM_BOOT_CONFIG_RESET_VECTOR	= 1,
+};
+
+int __init msm_pm_boot_init(int boot_config, uint32_t* address);
+void msm_pm_boot_config_before_pc(unsigned int cpu, unsigned long entry);
+void msm_pm_boot_config_after_pc(unsigned int cpu);
+
+#endif
diff --git a/arch/arm/mach-msm/pm.c b/arch/arm/mach-msm/pm.c
index 9e19d40..d684a5a 100644
--- a/arch/arm/mach-msm/pm.c
+++ b/arch/arm/mach-msm/pm.c
@@ -45,6 +45,7 @@
 #include "gpio.h"
 #include "timer.h"
 #include "pm.h"
+#include "pm-boot.h"
 
 enum {
 	MSM_PM_DEBUG_SUSPEND = 1U << 0,
@@ -100,7 +101,6 @@
 	struct smsm_interrupt_info_ext *int_info_ext;
 } msm_pm_sma;
 
-static uint32_t *msm_pm_reset_vector;
 static uint32_t msm_pm_max_sleep_time;
 static struct msm_pm_platform_data *msm_pm_modes;
 
@@ -238,7 +238,6 @@
 static int msm_sleep(int sleep_mode, uint32_t sleep_delay,
 	uint32_t sleep_limit, int from_idle)
 {
-	uint32_t saved_vector[2];
 	int collapsed;
 	uint32_t enter_state;
 	uint32_t enter_wait_set = 0;
@@ -344,17 +343,10 @@
 				msm_pm_sma.int_info->aArm_en_mask,
 				msm_pm_sma.int_info->aArm_wakeup_reason,
 				msm_pm_sma.int_info->aArm_interrupts_pending);
-		saved_vector[0] = msm_pm_reset_vector[0];
-		saved_vector[1] = msm_pm_reset_vector[1];
-		msm_pm_reset_vector[0] = 0xE51FF004; /* ldr pc, 4 */
-		msm_pm_reset_vector[1] = virt_to_phys(msm_pm_collapse_exit);
-		if (msm_pm_debug_mask & MSM_PM_DEBUG_RESET_VECTOR)
-			printk(KERN_INFO "msm_sleep(): vector %x %x -> "
-			       "%x %x\n", saved_vector[0], saved_vector[1],
-			       msm_pm_reset_vector[0], msm_pm_reset_vector[1]);
+		msm_pm_boot_config_before_pc(smp_processor_id(),
+				virt_to_phys(msm_pm_collapse_exit));
 		collapsed = msm_pm_collapse();
-		msm_pm_reset_vector[0] = saved_vector[0];
-		msm_pm_reset_vector[1] = saved_vector[1];
+		msm_pm_boot_config_after_pc(smp_processor_id());
 		if (collapsed) {
 			cpu_init();
 			local_fiq_enable();
@@ -871,22 +863,6 @@
 		return -ENODEV;
 	}
 
-#if defined(CONFIG_ARCH_MSM_SCORPION) && !defined(CONFIG_MSM_SMP)
-	/* The bootloader is responsible for initializing many of Scorpion's
-	 * coprocessor registers for things like cache timing. The state of
-	 * these coprocessor registers is lost on reset, so part of the
-	 * bootloader must be re-executed. Do not overwrite the reset vector
-	 * or bootloader area.
-	 */
-	msm_pm_reset_vector = (uint32_t *) PAGE_OFFSET;
-#else
-	msm_pm_reset_vector = ioremap(0, PAGE_SIZE);
-	if (msm_pm_reset_vector == NULL) {
-		printk(KERN_ERR "msm_pm_init: failed to map reset vector\n");
-		return -ENODEV;
-	}
-#endif /* CONFIG_ARCH_MSM_SCORPION */
-
 	ret = msm_timer_init_time_sync(msm_pm_timeout);
 	if (ret)
 		return ret;
diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c
index 6b24a02..4cdd7ae 100644
--- a/arch/arm/mach-msm/pm2.c
+++ b/arch/arm/mach-msm/pm2.c
@@ -61,6 +61,7 @@
 #include "pm.h"
 #include "spm.h"
 #include "sirc.h"
+#include "pm-boot.h"
 
 /******************************************************************************
  * Debug Definitions
@@ -962,7 +963,6 @@
  *
  *****************************************************************************/
 static struct msm_pm_smem_t *msm_pm_smem_data;
-static uint32_t *msm_pm_reset_vector;
 static atomic_t msm_pm_init_done = ATOMIC_INIT(0);
 
 static int msm_pm_modem_busy(void)
@@ -991,7 +991,6 @@
 {
 	struct msm_pm_polled_group state_grps[2];
 	unsigned long saved_acpuclk_rate;
-	uint32_t saved_vector[2];
 	int collapsed = 0;
 	int ret;
 
@@ -1078,15 +1077,8 @@
 		goto power_collapse_early_exit;
 	}
 
-	saved_vector[0] = msm_pm_reset_vector[0];
-	saved_vector[1] = msm_pm_reset_vector[1];
-	msm_pm_reset_vector[0] = 0xE51FF004; /* ldr pc, 4 */
-	msm_pm_reset_vector[1] = virt_to_phys(msm_pm_collapse_exit);
-
-	MSM_PM_DPRINTK(MSM_PM_DEBUG_RESET_VECTOR, KERN_INFO,
-		"%s(): vector %x %x -> %x %x\n", __func__,
-		saved_vector[0], saved_vector[1],
-		msm_pm_reset_vector[0], msm_pm_reset_vector[1]);
+	msm_pm_boot_config_before_pc(smp_processor_id(),
+			virt_to_phys(msm_pm_collapse_exit));
 
 #ifdef CONFIG_VFP
 	if (from_idle)
@@ -1103,8 +1095,7 @@
 	l2x0_resume(collapsed);
 #endif
 
-	msm_pm_reset_vector[0] = saved_vector[0];
-	msm_pm_reset_vector[1] = saved_vector[1];
+	msm_pm_boot_config_after_pc(smp_processor_id());
 
 	if (collapsed) {
 #ifdef CONFIG_VFP
@@ -1283,7 +1274,6 @@
  */
 static int msm_pm_power_collapse_standalone(void)
 {
-	uint32_t saved_vector[2];
 	int collapsed = 0;
 	int ret;
 
@@ -1293,15 +1283,8 @@
 	ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_POWER_COLLAPSE, false);
 	WARN_ON(ret);
 
-	saved_vector[0] = msm_pm_reset_vector[0];
-	saved_vector[1] = msm_pm_reset_vector[1];
-	msm_pm_reset_vector[0] = 0xE51FF004; /* ldr pc, 4 */
-	msm_pm_reset_vector[1] = virt_to_phys(msm_pm_collapse_exit);
-
-	MSM_PM_DPRINTK(MSM_PM_DEBUG_RESET_VECTOR, KERN_INFO,
-		"%s(): vector %x %x -> %x %x\n", __func__,
-		saved_vector[0], saved_vector[1],
-		msm_pm_reset_vector[0], msm_pm_reset_vector[1]);
+	msm_pm_boot_config_before_pc(smp_processor_id(),
+			virt_to_phys(msm_pm_collapse_exit));
 
 #ifdef CONFIG_VFP
 	vfp_flush_context();
@@ -1317,8 +1300,7 @@
 	l2x0_resume(collapsed);
 #endif
 
-	msm_pm_reset_vector[0] = saved_vector[0];
-	msm_pm_reset_vector[1] = saved_vector[1];
+	msm_pm_boot_config_after_pc(smp_processor_id());
 
 	if (collapsed) {
 #ifdef CONFIG_VFP
@@ -1836,21 +1818,6 @@
 		printk(KERN_ERR "%s: failed to get smsm_data\n", __func__);
 		return -ENODEV;
 	}
-#if defined(CONFIG_ARCH_MSM_SCORPION) && !defined(CONFIG_MSM_SMP)
-	/* The bootloader is responsible for initializing many of Scorpion's
-	 * coprocessor registers for things like cache timing. The state of
-	 * these coprocessor registers is lost on reset, so part of the
-	 * bootloader must be re-executed. Do not overwrite the reset vector
-	 * or bootloader area.
-	 */
-	msm_pm_reset_vector = (uint32_t *) PAGE_OFFSET;
-#else
-	msm_pm_reset_vector = ioremap(0, PAGE_SIZE);
-	if (msm_pm_reset_vector == NULL) {
-		printk(KERN_ERR "%s: failed to map reset vector\n", __func__);
-		return -ENODEV;
-	}
-#endif /* CONFIG_ARCH_MSM_SCORPION */
 
 	ret = msm_timer_init_time_sync(msm_pm_timeout);
 	if (ret)