msm: pm-8x60: Warmboot support for 9615

During warmboot, the boot remap register in the A5 core allows for a 64K
aligned warmboot handler to be remapped to the boot address. Use the
reserve callback in the machine_descriptor to allocate a memory block
that is aligned to 64K using memblock_alloc API.  The boot remapper
address is programmed so as to remap the allocated memory to boot
address. The power management code programs into this memory to jump to
the warmboot resume path during power collapse.

Change-Id: I2cf9e5ca346ac0632c9e21152dc25f5541166077
Signed-off-by: Maheshkumar Sivasubramanian <msivasub@codeaurora.org>
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 5cf6c78..180c54f 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -1806,6 +1806,10 @@
 	},
 };
 
+static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
+	.mode = MSM_PM_BOOT_CONFIG_TZ,
+};
+
 #ifdef CONFIG_I2C
 #define I2C_SURF 1
 #define I2C_FFA  (1 << 1)
@@ -2006,7 +2010,7 @@
 	msm_cpuidle_set_states(msm_cstates, ARRAY_SIZE(msm_cstates),
 				msm_pm_data);
 	change_memory_power = &msm8930_change_memory_power;
-	BUG_ON(msm_pm_boot_init(MSM_PM_BOOT_CONFIG_TZ, NULL));
+	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
 
 	if (PLATFORM_IS_CHARM25())
 		platform_add_devices(mdm_devices, ARRAY_SIZE(mdm_devices));
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index d92a3b2..ab6439a 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -1922,6 +1922,10 @@
 	},
 };
 
+static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
+	.mode = MSM_PM_BOOT_CONFIG_TZ,
+};
+
 #ifdef CONFIG_I2C
 #define I2C_SURF 1
 #define I2C_FFA  (1 << 1)
@@ -2139,7 +2143,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));
+	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
 }
 
 static void __init msm8960_rumi3_init(void)
@@ -2170,7 +2174,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));
+	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
 }
 
 static void __init msm8960_cdp_init(void)
@@ -2245,8 +2249,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));
-
+	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
 	if (PLATFORM_IS_CHARM25())
 		platform_add_devices(mdm_devices, ARRAY_SIZE(mdm_devices));
 }
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index cd51a16..f5bd44d 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -14,6 +14,7 @@
 #include <linux/platform_device.h>
 #include <linux/i2c.h>
 #include <linux/msm_ssbi.h>
+#include <linux/memblock.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/mmc.h>
@@ -35,6 +36,7 @@
 #include "pm.h"
 #include "acpuclock.h"
 #include <linux/power/ltc4088-charger.h>
+#include "pm-boot.h"
 
 static struct pm8xxx_adc_amux pm8018_adc_channels_data[] = {
 	{"vcoin", CHANNEL_VCOIN, CHAN_PATH_SCALING2, AMUX_RSV1,
@@ -627,6 +629,11 @@
 	},
 };
 
+static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
+	.mode = MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR,
+	.v_addr = MSM_APCS_GLB_BASE +  0x24,
+};
+
 static int __init gpiomux_init(void)
 {
 	int rc;
@@ -850,6 +857,11 @@
 					&msm9615_i2c_qup_gsbi5_pdata;
 }
 
+static void __init msm9615_reserve(void)
+{
+	msm_pm_boot_pdata.p_addr = memblock_alloc(SZ_8, SZ_64K);
+}
+
 static void __init msm9615_common_init(void)
 {
 	msm9615_device_init();
@@ -880,6 +892,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_pdata));
 }
 
 static void __init msm9615_cdp_init(void)
@@ -897,6 +910,7 @@
 	.init_irq = msm9615_init_irq,
 	.timer = &msm_timer,
 	.init_machine = msm9615_cdp_init,
+	.reserve = msm9615_reserve,
 MACHINE_END
 
 MACHINE_START(MSM9615_MTP, "QCT MSM9615 MTP")
@@ -904,4 +918,5 @@
 	.init_irq = msm9615_init_irq,
 	.timer = &msm_timer,
 	.init_machine = msm9615_mtp_init,
+	.reserve = msm9615_reserve,
 MACHINE_END
diff --git a/arch/arm/mach-msm/board-msm7x27.c b/arch/arm/mach-msm/board-msm7x27.c
index 15705ec..d8efcfe 100644
--- a/arch/arm/mach-msm/board-msm7x27.c
+++ b/arch/arm/mach-msm/board-msm7x27.c
@@ -1625,6 +1625,11 @@
 	},
 };
 
+static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
+	.mode = MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT,
+	.v_addr = (uint32_t *)PAGE_OFFSET,
+};
+
 static void
 msm_i2c_gpio_config(int iface, int config_type)
 {
@@ -1818,8 +1823,8 @@
 		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)));
+	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+
 	msm7x27_wlan_init();
 }
 
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index f9beced..33a8d42 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -1720,6 +1720,11 @@
 	},
 };
 
+static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
+	.mode = MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT,
+	.v_addr = (uint32_t *)PAGE_OFFSET,
+};
+
 static struct android_pmem_platform_data android_pmem_adsp_pdata = {
 	.name = "pmem_adsp",
 	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
@@ -3303,8 +3308,7 @@
 
 	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)));
+	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
 
 #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 9ba92ed..857c88a 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -2948,6 +2948,11 @@
 	},
 };
 
+static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
+	.mode = MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT,
+	.v_addr = (uint32_t *)PAGE_OFFSET,
+};
+
 static struct resource qsd_spi_resources[] = {
 	{
 		.name   = "spi_irq_in",
@@ -6710,8 +6715,7 @@
 	hdmi_init_regs();
 	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));
+	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
 	msm_device_i2c_init();
 	msm_device_i2c_2_init();
 	qup_device_i2c_init();
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 0a539c5..75c1b80 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -915,6 +915,10 @@
 	},
 };
 
+static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
+	.mode = MSM_PM_BOOT_CONFIG_TZ,
+};
+
 #if defined(CONFIG_USB_PEHCI_HCD) || defined(CONFIG_USB_PEHCI_HCD_MODULE)
 
 #define ISP1763_INT_GPIO		117
@@ -10175,7 +10179,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));
+	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
 
 	pm8058_gpios_init();
 
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index 537251a..48cdeda 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -1606,6 +1606,11 @@
 	},
 };
 
+static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
+	.mode = MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT,
+	.v_addr = (uint32_t *)PAGE_OFFSET,
+};
+
 static struct android_pmem_platform_data android_pmem_adsp_pdata = {
 	.name = "pmem_adsp",
 	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
@@ -2565,8 +2570,7 @@
 #endif
 	msm_pm_set_platform_data(msm7627a_pm_data,
 				ARRAY_SIZE(msm7627a_pm_data));
-	BUG_ON(msm_pm_boot_init(MSM_PM_BOOT_CONFIG_RESET_VECTOR,
-				ioremap(0, PAGE_SIZE)));
+	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
 
 	msm_fb_add_devices();
 
diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c
index 0dcd0f4..10432a0 100644
--- a/arch/arm/mach-msm/board-qsd8x50.c
+++ b/arch/arm/mach-msm/board-qsd8x50.c
@@ -2297,6 +2297,11 @@
 	},
 };
 
+static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
+	.mode = MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT,
+	.v_addr = (unsigned int *)PAGE_OFFSET,
+};
+
 static void
 msm_i2c_gpio_config(int iface, int config_type)
 {
@@ -2437,8 +2442,7 @@
 	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));
+	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
 
 #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 753a47c..830e36b 100644
--- a/arch/arm/mach-msm/idle.h
+++ b/arch/arm/mach-msm/idle.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2009, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2007-2009,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
@@ -17,7 +17,6 @@
 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);
@@ -31,5 +30,4 @@
 }
 #endif
 
-
 #endif
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 8db21f9..f479daf 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -33,6 +33,7 @@
 #include <asm/hardware/gic.h>
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
+#include <asm/hardware/cache-l2x0.h>
 #ifdef CONFIG_VFP
 #include <asm/vfp.h>
 #endif
@@ -636,6 +637,24 @@
 	msm_arch_idle();
 }
 
+#ifdef CONFIG_CACHE_L2X0
+static inline bool msm_pm_l2x0_power_collapse(void)
+{
+	bool collapsed = 0;
+
+	l2x0_suspend();
+	collapsed = msm_pm_collapse();
+	l2x0_resume(collapsed);
+
+	return collapsed;
+}
+#else
+static inline bool msm_pm_l2x0_power_collapse(void)
+{
+	return msm_pm_collapse();
+}
+#endif
+
 static bool msm_pm_spm_power_collapse(
 	struct msm_pm_device *dev, bool from_idle, bool notify_rpm)
 {
@@ -663,7 +682,7 @@
 	vfp_flush_context();
 #endif
 
-	collapsed = msm_pm_collapse();
+	collapsed = msm_pm_l2x0_power_collapse();
 
 	msm_pm_boot_config_after_pc(dev->cpu);
 
diff --git a/arch/arm/mach-msm/pm-boot.c b/arch/arm/mach-msm/pm-boot.c
index bcc4c64..6b92d1e 100644
--- a/arch/arm/mach-msm/pm-boot.c
+++ b/arch/arm/mach-msm/pm-boot.c
@@ -15,6 +15,10 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <mach/msm_iomap.h>
+#include <mach/socinfo.h>
+#include <asm/mach-types.h>
+#include <asm/sizes.h>
 #include "scm-boot.h"
 #include "idle.h"
 #include "pm-boot.h"
@@ -55,7 +59,8 @@
 
 static int __init msm_pm_boot_reset_vector_init(uint32_t *reset_vector)
 {
-	WARN_ON(!reset_vector);
+	if (!reset_vector)
+		return -ENODEV;
 	msm_pm_reset_vector = reset_vector;
 	mb();
 
@@ -88,19 +93,47 @@
 	if (msm_pm_boot_after_pc)
 		msm_pm_boot_after_pc(cpu);
 }
+#define BOOT_REMAP_ENABLE  BIT(0)
 
-int __init msm_pm_boot_init(int tz_available, uint32_t* address)
+int __init msm_pm_boot_init(struct msm_pm_boot_platform_data *pdata)
 {
 	int ret = 0;
 
-	switch (tz_available) {
+	switch (pdata->mode) {
 	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);
+	case MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS:
+		if (!pdata->p_addr)
+			return -ENODEV;
+		pdata->v_addr = ioremap(pdata->p_addr, PAGE_SIZE);
+		/* Fall through */
+	case MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT:
+
+		if (!pdata->v_addr)
+			return -ENODEV;
+
+		ret = msm_pm_boot_reset_vector_init(pdata->v_addr);
+		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;
+	case MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR:
+		/*
+		 * Set the boot remap address and enable remapping of
+		 * reset vector
+		 */
+		if (!pdata->p_addr || !pdata->v_addr)
+			return -ENODEV;
+
+		__raw_writel((pdata->p_addr | BOOT_REMAP_ENABLE),
+				pdata->v_addr);
+
+		ret = msm_pm_boot_reset_vector_init(__va(pdata->p_addr));
+
 		msm_pm_boot_before_pc
 			= msm_pm_config_rst_vector_before_pc;
 		msm_pm_boot_after_pc
diff --git a/arch/arm/mach-msm/pm-boot.h b/arch/arm/mach-msm/pm-boot.h
index 2234192..8a7238a 100644
--- a/arch/arm/mach-msm/pm-boot.h
+++ b/arch/arm/mach-msm/pm-boot.h
@@ -14,18 +14,28 @@
 #define _ARCH_ARM_MACH_MSM_PM_BOOT_H
 
 enum {
-	MSM_PM_BOOT_CONFIG_TZ		= 0,
-	MSM_PM_BOOT_CONFIG_RESET_VECTOR	= 1,
+	MSM_PM_BOOT_CONFIG_TZ		     = 0,
+	MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS = 1,
+	MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT = 2,
+	MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR   = 3,
+};
+
+struct msm_pm_boot_platform_data {
+	int mode;
+	phys_addr_t  p_addr;
+	void __iomem *v_addr;
 };
 
 #ifdef CONFIG_PM
-int __init msm_pm_boot_init(int boot_config, uint32_t* address);
+int __init msm_pm_boot_init(struct msm_pm_boot_platform_data *pdata);
 #else
-static inline int __init msm_pm_boot_init(int boot_config, uint32_t* address)
+static inline int __init msm_pm_boot_init(
+		struct msm_pm_boot_platform_data *pdata);
 {
 	return 0;
 }
 #endif
+
 void msm_pm_boot_config_before_pc(unsigned int cpu, unsigned long entry);
 void msm_pm_boot_config_after_pc(unsigned int cpu);