pm2: Power Management driver changes for 8x25

Current pm2.c driver supports low power mode functionality
only for single APPS processor targets. This patch adds extra
functionality to pm2.c driver to support multicore APPS
processor targets where MODEM is a master.

These changes makes pm2.c driver backward compatible to
older targets(eg: 7x27a & 7x30 etc) & multicore APPS
processors like 8x25.

Change-Id: I79b23b2a2052aa55f9a169886dea17180614dedb
Signed-off-by: Murali Nalajala <mnalajal@codeaurora.org>
diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c
index 7977d22..ff7a930 100644
--- a/arch/arm/mach-msm/pm2.c
+++ b/arch/arm/mach-msm/pm2.c
@@ -48,6 +48,7 @@
 #ifdef CONFIG_MSM_MEMORY_LOW_POWER_MODE_SUSPEND_DEEP_POWER_DOWN
 #include <mach/msm_migrate_pages.h>
 #endif
+#include <mach/socinfo.h>
 
 #include "smd_private.h"
 #include "smd_rpcrouter.h"
@@ -142,7 +143,6 @@
 static char *msm_pm_sleep_mode_labels[MSM_PM_SLEEP_MODE_NR] = {
 	[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND] = " ",
 	[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = "power_collapse",
-	[MSM_PM_SLEEP_MODE_APPS_SLEEP] = "apps_sleep",
 	[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT] =
 		"ramp_down_and_wfi",
 	[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT] = "wfi",
@@ -682,8 +682,6 @@
 	MSM_PM_STAT_IDLE_WFI,
 	MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE,
 	MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE,
-	MSM_PM_STAT_IDLE_SLEEP,
-	MSM_PM_STAT_IDLE_FAILED_SLEEP,
 	MSM_PM_STAT_IDLE_POWER_COLLAPSE,
 	MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE,
 	MSM_PM_STAT_SUSPEND,
@@ -1008,6 +1006,13 @@
 
 	memset(msm_pm_smem_data, 0, sizeof(*msm_pm_smem_data));
 
+	if (cpu_is_msm8625()) {
+		/* Program the SPM */
+		ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_POWER_COLLAPSE,
+									false);
+		WARN_ON(ret);
+	}
+
 	msm_irq_enter_sleep1(true, from_idle, &msm_pm_smem_data->irq_mask);
 	msm_sirc_enter_sleep();
 	msm_gpio_enter_sleep(from_idle);
@@ -1210,6 +1215,13 @@
 	MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): RUN");
 
 	smd_sleep_exit();
+
+	if (cpu_is_msm8625()) {
+		ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING,
+									false);
+		WARN_ON(ret);
+	}
+
 	return 0;
 
 power_collapse_early_exit:
@@ -1263,6 +1275,12 @@
 		smd_sleep_exit();
 
 power_collapse_bail:
+	if (cpu_is_msm8625()) {
+		ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING,
+									false);
+		WARN_ON(ret);
+	}
+
 	return ret;
 }
 
@@ -1272,10 +1290,11 @@
  * Return value:
  *      0: success
  */
-static int msm_pm_power_collapse_standalone(void)
+static int msm_pm_power_collapse_standalone(bool from_idle)
 {
 	int collapsed = 0;
 	int ret;
+	void *entry;
 
 	MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
 		KERN_INFO, "%s()\n", __func__);
@@ -1283,21 +1302,26 @@
 	ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_POWER_COLLAPSE, false);
 	WARN_ON(ret);
 
+	entry = (!smp_processor_id() || from_idle) ?
+			msm_pm_collapse_exit : msm_secondary_startup;
+
 	msm_pm_boot_config_before_pc(smp_processor_id(),
-			virt_to_phys(msm_pm_collapse_exit));
+						virt_to_phys(entry));
 
 #ifdef CONFIG_VFP
 	vfp_flush_context();
 #endif
 
 #ifdef CONFIG_CACHE_L2X0
-	l2x0_suspend();
+	if (!cpu_is_msm8625())
+		l2x0_suspend();
 #endif
 
 	collapsed = msm_pm_collapse();
 
 #ifdef CONFIG_CACHE_L2X0
-	l2x0_resume(collapsed);
+	if (!cpu_is_msm8625())
+		l2x0_resume(collapsed);
 #endif
 
 	msm_pm_boot_config_after_pc(smp_processor_id());
@@ -1321,18 +1345,6 @@
 }
 
 /*
- * Apps-sleep the Apps processor.  This function execute the handshake
- * protocol with Modem.
- *
- * Return value:
- *      -ENOSYS: function not implemented yet
- */
-static int msm_pm_apps_sleep(uint32_t sleep_delay, uint32_t sleep_limit)
-{
-	return -ENOSYS;
-}
-
-/*
  * Bring the Apps processor to SWFI.
  *
  * Return value:
@@ -1353,7 +1365,9 @@
 			return -EIO;
 	}
 
-	msm_pm_config_hw_before_swfi();
+	if (!cpu_is_msm8625())
+		msm_pm_config_hw_before_swfi();
+
 	msm_arch_idle();
 
 	if (ramp_acpu) {
@@ -1395,7 +1409,7 @@
 	int64_t t1;
 	static int64_t t2;
 	int exit_stat;
- #endif /* CONFIG_MSM_IDLE_STATS */
+ #endif
 
 	if (!atomic_read(&msm_pm_init_done))
 		return;
@@ -1412,19 +1426,19 @@
 
 	exit_stat = MSM_PM_STAT_IDLE_SPIN;
 	low_power = 0;
-#endif /* CONFIG_MSM_IDLE_STATS */
+#endif
 
 	for (i = 0; i < ARRAY_SIZE(allow); i++)
 		allow[i] = true;
 
-	if ((timer_expiration < msm_pm_idle_sleep_min_time) ||
+	if (num_online_cpus() > 1 ||
+		(timer_expiration < msm_pm_idle_sleep_min_time) ||
 #ifdef CONFIG_HAS_WAKELOCK
 		has_wake_lock(WAKE_LOCK_IDLE) ||
 #endif
 		!msm_irq_idle_sleep_allowed()) {
 		allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = false;
 		allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN] = false;
-		allow[MSM_PM_SLEEP_MODE_APPS_SLEEP] = false;
 	}
 
 	for (i = 0; i < ARRAY_SIZE(allow); i++) {
@@ -1493,32 +1507,15 @@
 			exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
 			msm_pm_sleep_limit = sleep_limit;
 		}
-#endif /* CONFIG_MSM_IDLE_STATS */
-	} else if (allow[MSM_PM_SLEEP_MODE_APPS_SLEEP]) {
-		uint32_t sleep_delay;
-
-		sleep_delay = (uint32_t) msm_pm_convert_and_cap_time(
-			timer_expiration, MSM_PM_SLEEP_TICK_LIMIT);
-		if (sleep_delay == 0) /* 0 would mean infinite time */
-			sleep_delay = 1;
-
-		ret = msm_pm_apps_sleep(sleep_delay, sleep_limit);
-		low_power = 0;
-
-#ifdef CONFIG_MSM_IDLE_STATS
-		if (ret)
-			exit_stat = MSM_PM_STAT_IDLE_FAILED_SLEEP;
-		else
-			exit_stat = MSM_PM_STAT_IDLE_SLEEP;
-#endif /* CONFIG_MSM_IDLE_STATS */
+#endif
 	} else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
-		ret = msm_pm_power_collapse_standalone();
+		ret = msm_pm_power_collapse_standalone(true);
 		low_power = 0;
 #ifdef CONFIG_MSM_IDLE_STATS
 		exit_stat = ret ?
 			MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE :
 			MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE;
-#endif /* CONFIG_MSM_IDLE_STATS */
+#endif
 	} else if (allow[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT]) {
 		ret = msm_pm_swfi(true);
 		if (ret)
@@ -1527,20 +1524,20 @@
 		low_power = 0;
 #ifdef CONFIG_MSM_IDLE_STATS
 		exit_stat = ret ? MSM_PM_STAT_IDLE_SPIN : MSM_PM_STAT_IDLE_WFI;
-#endif /* CONFIG_MSM_IDLE_STATS */
+#endif
 	} else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT]) {
 		msm_pm_swfi(false);
 		low_power = 0;
 #ifdef CONFIG_MSM_IDLE_STATS
 		exit_stat = MSM_PM_STAT_IDLE_WFI;
-#endif /* CONFIG_MSM_IDLE_STATS */
+#endif
 	} else {
 		while (!msm_irq_pending())
 			udelay(1);
 		low_power = 0;
 #ifdef CONFIG_MSM_IDLE_STATS
 		exit_stat = MSM_PM_STAT_IDLE_SPIN;
-#endif /* CONFIG_MSM_IDLE_STATS */
+#endif
 	}
 
 	msm_timer_exit_idle(low_power);
@@ -1548,13 +1545,14 @@
 #ifdef CONFIG_MSM_IDLE_STATS
 	t2 = ktime_to_ns(ktime_get());
 	msm_pm_add_stat(exit_stat, t2 - t1);
-#endif /* CONFIG_MSM_IDLE_STATS */
+#endif
 }
 
 /*
  * Suspend the Apps processor.
  *
  * Return value:
+ *	-EPERM: Suspend happened by a not permitted core
  *      -EAGAIN: modem reset occurred or early exit from suspend
  *      -EBUSY: modem not ready for our suspend
  *      -EINVAL: invalid sleep mode
@@ -1566,13 +1564,20 @@
 {
 	bool allow[MSM_PM_SLEEP_MODE_NR];
 	uint32_t sleep_limit = SLEEP_LIMIT_NONE;
-	int ret;
+	int ret = -EPERM;
 	int i;
-
 #ifdef CONFIG_MSM_IDLE_STATS
 	int64_t period = 0;
 	int64_t time = 0;
+#endif
 
+	/* Must executed by CORE0 */
+	if (smp_processor_id()) {
+		__WARN();
+		goto suspend_exit;
+	}
+
+#ifdef CONFIG_MSM_IDLE_STATS
 	time = msm_timer_get_sclk_time(&period);
 #endif
 
@@ -1589,8 +1594,6 @@
 			allow[i] = false;
 	}
 
-	ret = 0;
-
 	if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] ||
 		allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN]) {
 #ifdef CONFIG_MSM_IDLE_STATS
@@ -1647,7 +1650,7 @@
 		msm_pm_add_stat(id, time);
 #endif
 	} else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
-		ret = msm_pm_power_collapse_standalone();
+		ret = msm_pm_power_collapse_standalone(false);
 	} else if (allow[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT]) {
 		ret = msm_pm_swfi(true);
 		if (ret)
@@ -1657,6 +1660,7 @@
 		msm_pm_swfi(false);
 	}
 
+suspend_exit:
 	MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND, KERN_INFO,
 		"%s(): return %d\n", __func__, ret);
 
@@ -1725,10 +1729,6 @@
 };
 
 
-/******************************************************************************
- *
- *****************************************************************************/
-
 /*
  * Initialize the power management subsystem.
  *
@@ -1837,15 +1837,6 @@
 			first_bucket_time =
 			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
 
-		stats[MSM_PM_STAT_IDLE_SLEEP].name = "idle-sleep";
-		stats[MSM_PM_STAT_IDLE_SLEEP].first_bucket_time =
-			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
-		stats[MSM_PM_STAT_IDLE_FAILED_SLEEP].name =
-			"idle-failed-sleep";
-		stats[MSM_PM_STAT_IDLE_FAILED_SLEEP].first_bucket_time =
-			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
 		stats[MSM_PM_STAT_IDLE_POWER_COLLAPSE].name =
 			"idle-power-collapse";
 		stats[MSM_PM_STAT_IDLE_POWER_COLLAPSE].first_bucket_time =