msm: pm: warmboot entry/exit counters on IMEM

Add warmboot entry/exit counters for each core on a non-cacheable always
on IMEM memory. This is a useful feature during debug to understand if
the system has correctly warmbooted after a power collapse. The debug
counters start at a memory offset of 0x664 on the IMEM. Each core
reserves 4 words for events, of which 3 are being used to monitor the
following events,
1) power collapse entry
2) warmboot exit
3) failed power collapse when wfi returns with a pending interrupt.

Change-Id: I45aac8e4a4d3421d586790b3b66fd71a8d88ea9d
Signed-off-by: Mahesh Sivasubramanian <msivasub@codeaurora.org>
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 8ddb9e1..dbb23d5 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -24,6 +24,7 @@
 #include <linux/smp.h>
 #include <linux/suspend.h>
 #include <linux/tick.h>
+#include <linux/platform_device.h>
 #include <mach/msm_iomap.h>
 #include <mach/socinfo.h>
 #include <mach/system.h>
@@ -71,7 +72,6 @@
 );
 static int msm_pm_retention_tz_call;
 
-
 /******************************************************************************
  * Sleep Modes and Parameters
  *****************************************************************************/
@@ -491,7 +491,6 @@
 #ifdef CONFIG_VFP
 	vfp_pm_suspend();
 #endif
-
 	collapsed = msm_pm_l2x0_power_collapse();
 
 	msm_pm_boot_config_after_pc(cpu);
@@ -950,6 +949,46 @@
 	msm_pm_retention_tz_call = flag;
 }
 
+static int __devinit msm_pc_debug_probe(struct platform_device *pdev)
+{
+	struct resource *res = NULL;
+	int i ;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		goto fail;
+
+	msm_pc_debug_counters_phys = res->start;
+	WARN_ON(resource_size(res) < SZ_64);
+	msm_pc_debug_counters = devm_ioremap(&pdev->dev, res->start,
+					resource_size(res));
+
+	if (!msm_pc_debug_counters)
+		goto fail;
+
+	for (i = 0; i < resource_size(res)/4; i++)
+		__raw_writel(0, msm_pc_debug_counters + i * 4);
+	return 0;
+fail:
+	msm_pc_debug_counters = 0;
+	msm_pc_debug_counters_phys = 0;
+	return -EFAULT;
+}
+
+static struct of_device_id msm_pc_debug_table[] = {
+	{.compatible = "qcom,pc-cntr"},
+	{},
+};
+
+static struct platform_driver msm_pc_counter_driver = {
+	.probe = msm_pc_debug_probe,
+	.driver = {
+		.name = "pc-cntr",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_pc_debug_table,
+	},
+};
+
 static int __init msm_pm_init(void)
 {
 	pgd_t *pc_pgd;
@@ -965,6 +1004,7 @@
 	unsigned long exit_phys;
 
 	/* Page table for cores to come back up safely. */
+
 	pc_pgd = pgd_alloc(&init_mm);
 	if (!pc_pgd)
 		return -ENOMEM;
@@ -1007,6 +1047,7 @@
 	suspend_set_ops(&msm_pm_ops);
 	msm_pm_qtimer_available();
 	msm_cpuidle_init();
+	platform_driver_register(&msm_pc_counter_driver);
 
 	return 0;
 }