msm: pm: Rearchitect power management code

The existing PM code relies on a levels table to determine the various
sleep modes including the system sleep states. Splitting them into cpu
and system/cluster specific levels is a more appropriate representation
of the existing system. As a part of this rearchitecture, the decision
to enter a low power mode is made within lpm_levels module. Unlike
earlier, the decision was split between pm-8x60 and lpm_levels.

To this effect, the lpm_levels directly registers with the cpuidle
driver instead of relying on a glue msm-cpuidle driver. The
functionality of the cpuidle driver was limited to calling into a PM
driver and without providing any additional functionality.

While at it, also remove any references to unused enums and
functionality.

Change-Id: I474cc85c6220473fdaa87e14e3b0a199e95d7eb7
Signed-off-by: Mahesh Sivasubramanian <msivasub@codeaurora.org>
diff --git a/arch/arm/mach-msm/msm-pm.c b/arch/arm/mach-msm/msm-pm.c
index aebd61f..5f8657e 100644
--- a/arch/arm/mach-msm/msm-pm.c
+++ b/arch/arm/mach-msm/msm-pm.c
@@ -11,61 +11,37 @@
  *
  */
 
-#include <linux/dma-mapping.h>
 #include <linux/debugfs.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/clk.h>
 #include <linux/clkdev.h>
-#include <linux/completion.h>
-#include <linux/cpuidle.h>
-#include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/ktime.h>
-#include <linux/pm.h>
-#include <linux/pm_qos.h>
 #include <linux/smp.h>
-#include <linux/suspend.h>
 #include <linux/tick.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/of_platform.h>
-#include <linux/regulator/krait-regulator.h>
-#include <linux/cpu.h>
-#include <mach/msm_iomap.h>
-#include <mach/socinfo.h>
-#include <mach/system.h>
-#include <mach/scm.h>
-#include <mach/socinfo.h>
-#define CREATE_TRACE_POINTS
-#include <mach/trace_msm_low_power.h>
-#include <mach/msm-krait-l2-accessors.h>
-#include <mach/msm_bus.h>
-#include <mach/mpm.h>
-#include <mach/jtag.h>
+#include <linux/cpu_pm.h>
+#include <asm/uaccess.h>
 #include <asm/suspend.h>
 #include <asm/cacheflush.h>
-#include <asm/hardware/gic.h>
-#include <asm/pgtable.h>
-#include <asm/pgalloc.h>
-#include <asm/barrier.h>
 #include <asm/outercache.h>
-#ifdef CONFIG_VFP
-#include <asm/vfp.h>
-#endif
+#include <mach/scm.h>
+#include <mach/msm_bus.h>
+#include <mach/jtag.h>
 #include "acpuclock.h"
-#include "clock.h"
 #include "avs.h"
-#include <mach/cpuidle.h>
 #include "idle.h"
 #include "pm.h"
 #include "scm-boot.h"
 #include "spm.h"
-#include "timer.h"
 #include "pm-boot.h"
-#include <mach/event_timer.h>
-#include <linux/cpu_pm.h>
+
+#define CREATE_TRACE_POINTS
+#include <mach/trace_msm_low_power.h>
 
 #define SCM_CMD_TERMINATE_PC	(0x2)
 #define SCM_CMD_CORE_HOTPLUGGED (0x10)
@@ -82,10 +58,6 @@
 	debug_mask, msm_pm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
 );
 
-static int msm_pm_sleep_time_override;
-module_param_named(sleep_time_override,
-	msm_pm_sleep_time_override, int, S_IRUGO | S_IWUSR | S_IWGRP);
-
 static bool use_acpuclk_apis;
 
 enum {
@@ -138,15 +110,9 @@
 		"standalone_power_collapse",
 };
 
-static struct hrtimer pm_hrtimer;
-static struct msm_pm_sleep_ops pm_sleep_ops;
 static bool msm_pm_ldo_retention_enabled = true;
-static bool msm_pm_use_sync_timer;
-static struct msm_pm_cp15_save_data cp15_data;
-static bool msm_pm_retention_calls_tz;
 static bool msm_no_ramp_down_pc;
 static struct msm_pm_sleep_status_data *msm_pm_slp_sts;
-static bool msm_pm_pc_reset_timer;
 DEFINE_PER_CPU(struct clk *, cpu_clks);
 static struct clk *l2_clk;
 
@@ -172,6 +138,9 @@
 	return msm_pm_flush_l2_flag;
 }
 
+static cpumask_t retention_cpus;
+static DEFINE_SPINLOCK(retention_lock);
+
 static int msm_pm_get_pc_mode(struct device_node *node,
 		const char *key, uint32_t *pc_mode_val)
 {
@@ -186,13 +155,10 @@
 				{MSM_PM_PC_TZ_L2_EXT , "tz_l2_ext"} };
 	int ret;
 	const char *pc_mode_str;
+	*pc_mode_val = MSM_PM_PC_TZ_L2_INT;
 
 	ret = of_property_read_string(node, key, &pc_mode_str);
-	if (ret) {
-		pr_debug("%s: Cannot read %s,defaulting to 0", __func__, key);
-		pc_mode_val = MSM_PM_PC_TZ_L2_INT;
-		ret = 0;
-	} else {
+	if (!ret) {
 		ret = -EINVAL;
 		for (i = 0; i < ARRAY_SIZE(pc_modes); i++) {
 			if (!strncmp(pc_mode_str, pc_modes[i].mode_name,
@@ -202,6 +168,9 @@
 				break;
 			}
 		}
+	} else {
+		pr_debug("%s: Cannot read %s,defaulting to 0", __func__, key);
+		ret = 0;
 	}
 	return ret;
 }
@@ -288,7 +257,7 @@
 	return ret ? ret : count;
 }
 
-static int __devinit msm_pm_mode_sysfs_add_cpu(
+static int msm_pm_mode_sysfs_add_cpu(
 	unsigned int cpu, struct kobject *modes_kobj)
 {
 	char cpu_name[8];
@@ -371,7 +340,7 @@
 	return ret;
 }
 
-int __devinit msm_pm_mode_sysfs_add(void)
+int msm_pm_mode_sysfs_add(void)
 {
 	struct kobject *module_kobj;
 	struct kobject *modes_kobj;
@@ -405,44 +374,10 @@
 	return ret;
 }
 
-/*
- * Configure hardware registers in preparation for Apps power down.
- */
-static void msm_pm_config_hw_before_power_down(void)
+static inline void msm_arch_idle(void)
 {
-	return;
-}
-
-/*
- * Clear hardware registers after Apps powers up.
- */
-static void msm_pm_config_hw_after_power_up(void)
-{
-}
-
-/*
- * Configure hardware registers in preparation for SWFI.
- */
-static void msm_pm_config_hw_before_swfi(void)
-{
-	return;
-}
-
-/*
- * Configure/Restore hardware registers in preparation for Retention.
- */
-
-static void msm_pm_config_hw_after_retention(void)
-{
-	int ret;
-
-	ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
-	WARN_ON(ret);
-}
-
-static void msm_pm_config_hw_before_retention(void)
-{
-	return;
+	mb();
+	wfi();
 }
 
 static bool msm_pm_is_L1_writeback(void)
@@ -458,76 +393,38 @@
 	return cache_id & BIT(31);
 }
 
-static void msm_pm_save_cpu_reg(void)
+static enum msm_pm_time_stats_id msm_pm_swfi(bool from_idle)
 {
-	int i;
-
-	/* Only on core0 */
-	if (smp_processor_id())
-		return;
-
-	/**
-	 * On some targets, L2 PC will turn off may reset the core
-	 * configuration for the mux and the default may not make the core
-	 * happy when it resumes.
-	 * Save the active vdd, and set the core vdd to QSB max vdd, so that
-	 * when the core resumes, it is capable of supporting the current QSB
-	 * rate. Then restore the active vdd before switching the acpuclk rate.
-	 */
-	if (msm_pm_get_l2_flush_flag() == MSM_SCM_L2_OFF) {
-		cp15_data.active_vdd = msm_spm_get_vdd(0);
-		for (i = 0; i < cp15_data.reg_saved_state_size; i++)
-			cp15_data.reg_val[i] =
-				get_l2_indirect_reg(
-					cp15_data.reg_data[i]);
-		msm_spm_set_vdd(0, cp15_data.qsb_pc_vdd);
-	}
-}
-
-static void msm_pm_restore_cpu_reg(void)
-{
-	int i;
-
-	/* Only on core0 */
-	if (smp_processor_id())
-		return;
-
-	if (msm_pm_get_l2_flush_flag() == MSM_SCM_L2_OFF) {
-		for (i = 0; i < cp15_data.reg_saved_state_size; i++)
-			set_l2_indirect_reg(
-					cp15_data.reg_data[i],
-					cp15_data.reg_val[i]);
-		msm_spm_set_vdd(0, cp15_data.active_vdd);
-	}
-}
-
-static inline void msm_arch_idle(void)
-{
-	mb();
-	wfi();
-}
-
-static void msm_pm_swfi(void)
-{
-	msm_pm_config_hw_before_swfi();
 	msm_arch_idle();
+	return MSM_PM_STAT_IDLE_WFI;
 }
 
-static void msm_pm_retention(void)
+static enum msm_pm_time_stats_id msm_pm_retention(bool from_idle)
 {
 	int ret = 0;
+	int cpu = smp_processor_id();
 
-	msm_pm_config_hw_before_retention();
+	spin_lock(&retention_lock);
+
+	if (!msm_pm_ldo_retention_enabled)
+		goto bailout;
+
+	cpumask_set_cpu(cpu, &retention_cpus);
+	spin_unlock(&retention_lock);
+
 	ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_POWER_RETENTION, false);
 	WARN_ON(ret);
 
-	if (msm_pm_retention_calls_tz)
-		scm_call_atomic1(SCM_SVC_BOOT, SCM_CMD_TERMINATE_PC,
-					MSM_SCM_L2_RET);
-	else
-		msm_arch_idle();
+	msm_arch_idle();
+	spin_lock(&retention_lock);
+	cpumask_clear_cpu(cpu, &retention_cpus);
+bailout:
+	spin_unlock(&retention_lock);
 
-	msm_pm_config_hw_after_retention();
+	ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
+	WARN_ON(ret);
+
+	return MSM_PM_STAT_RETENTION;
 }
 
 static inline void msm_pc_inc_debug_count(uint32_t cpu,
@@ -594,16 +491,12 @@
 	bool collapsed = 0;
 	int ret;
 	bool save_cpu_regs = !cpu || from_idle;
-	unsigned int saved_gic_cpu_ctrl;
-
-	saved_gic_cpu_ctrl = readl_relaxed(MSM_QGIC_CPU_BASE + GIC_CPU_CTRL);
-	mb();
 
 	if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
 		pr_info("CPU%u: %s: notify_rpm %d\n",
 			cpu, __func__, (int) notify_rpm);
 
-	if (from_idle == true)
+	if (from_idle)
 		cpu_pm_enter();
 
 	ret = msm_spm_set_low_power_mode(
@@ -617,30 +510,23 @@
 	if (MSM_PM_DEBUG_RESET_VECTOR & msm_pm_debug_mask)
 		pr_info("CPU%u: %s: program vector to %p\n",
 			cpu, __func__, entry);
-	if (from_idle && msm_pm_pc_reset_timer)
-		clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu);
 
 	msm_jtag_save_state();
+
 	collapsed = save_cpu_regs ?
 		!cpu_suspend(0, msm_pm_collapse) : msm_pm_pc_hotplug();
+
 	msm_jtag_restore_state();
 
-	if (from_idle && msm_pm_pc_reset_timer)
-		clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu);
+	if (collapsed) {
+		cpu_init();
+		local_fiq_enable();
+	}
 
 	msm_pm_boot_config_after_pc(cpu);
 
-	if (collapsed) {
-#ifdef CONFIG_VFP
-		vfp_pm_resume();
-#endif
-		cpu_init();
-		writel(0xF0, MSM_QGIC_CPU_BASE + GIC_CPU_PRIMASK);
-		writel_relaxed(saved_gic_cpu_ctrl,
-				MSM_QGIC_CPU_BASE + GIC_CPU_CTRL);
-		mb();
-		local_fiq_enable();
-	}
+	if (from_idle)
+		cpu_pm_exit();
 
 	if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
 		pr_info("CPU%u: %s: msm_pm_collapse returned, collapsed %d\n",
@@ -648,14 +534,11 @@
 
 	ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
 	WARN_ON(ret);
-
-	if (from_idle == true)
-		cpu_pm_exit();
-
 	return collapsed;
 }
 
-static bool msm_pm_power_collapse_standalone(bool from_idle)
+static enum msm_pm_time_stats_id msm_pm_power_collapse_standalone(
+		bool from_idle)
 {
 	unsigned int cpu = smp_processor_id();
 	unsigned int avsdscr;
@@ -670,7 +553,8 @@
 
 	avs_set_avsdscr(avsdscr);
 	avs_set_avscsr(avscsr);
-	return collapsed;
+	return collapsed ? MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE :
+			MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE;
 }
 
 static int ramp_down_last_cpu(int cpu)
@@ -725,7 +609,7 @@
 	return rc;
 }
 
-static bool msm_pm_power_collapse(bool from_idle)
+static enum msm_pm_time_stats_id msm_pm_power_collapse(bool from_idle)
 {
 	unsigned int cpu = smp_processor_id();
 	unsigned long saved_acpuclk_rate = 0;
@@ -737,7 +621,6 @@
 		pr_info("CPU%u: %s: idle %d\n",
 			cpu, __func__, (int)from_idle);
 
-	msm_pm_config_hw_before_power_down();
 	if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
 		pr_info("CPU%u: %s: pre power down\n", cpu, __func__);
 
@@ -748,120 +631,22 @@
 	if (cpu_online(cpu) && !msm_no_ramp_down_pc)
 		saved_acpuclk_rate = ramp_down_last_cpu(cpu);
 
-	if (cp15_data.save_cp15)
-		msm_pm_save_cpu_reg();
-
 	collapsed = msm_pm_spm_power_collapse(cpu, from_idle, true);
 
-	if (cp15_data.save_cp15)
-		msm_pm_restore_cpu_reg();
-
-	if (cpu_online(cpu) && !msm_no_ramp_down_pc) {
+	if (cpu_online(cpu) && !msm_no_ramp_down_pc)
 		ramp_up_first_cpu(cpu, saved_acpuclk_rate);
-	} else {
-		unsigned int gic_dist_enabled;
-		unsigned int gic_dist_pending;
-		gic_dist_enabled = readl_relaxed(
-				MSM_QGIC_DIST_BASE + GIC_DIST_ENABLE_CLEAR);
-		gic_dist_pending = readl_relaxed(
-				MSM_QGIC_DIST_BASE + GIC_DIST_PENDING_SET);
-		mb();
-		gic_dist_pending &= gic_dist_enabled;
-
-		if (gic_dist_pending)
-			pr_err("CPU %d interrupted during hotplug.Pending int 0x%x\n",
-					cpu, gic_dist_pending);
-	}
-
 
 	avs_set_avsdscr(avsdscr);
 	avs_set_avscsr(avscsr);
-	msm_pm_config_hw_after_power_up();
+
 	if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
 		pr_info("CPU%u: %s: post power up\n", cpu, __func__);
 
 	if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
 		pr_info("CPU%u: %s: return\n", cpu, __func__);
-	return collapsed;
+	return collapsed ? MSM_PM_STAT_IDLE_POWER_COLLAPSE :
+			MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE;
 }
-
-static int64_t msm_pm_timer_enter_idle(void)
-{
-	if (msm_pm_use_sync_timer)
-		return ktime_to_ns(tick_nohz_get_sleep_length());
-
-	return msm_timer_enter_idle();
-}
-
-static void msm_pm_timer_exit_idle(bool timer_halted)
-{
-	if (msm_pm_use_sync_timer)
-		return;
-
-	msm_timer_exit_idle((int) timer_halted);
-}
-
-static int64_t msm_pm_timer_enter_suspend(int64_t *period)
-{
-	int64_t time = 0;
-
-	if (msm_pm_use_sync_timer) {
-		struct timespec ts;
-		getnstimeofday(&ts);
-		return timespec_to_ns(&ts);
-	}
-
-	time = msm_timer_get_sclk_time(period);
-	if (!time)
-		pr_err("%s: Unable to read sclk.\n", __func__);
-
-	return time;
-}
-
-static int64_t msm_pm_timer_exit_suspend(int64_t time, int64_t period)
-{
-	if (msm_pm_use_sync_timer) {
-		struct timespec ts;
-		getnstimeofday(&ts);
-
-		return timespec_to_ns(&ts) - time;
-	}
-
-	if (time != 0) {
-		int64_t end_time = msm_timer_get_sclk_time(NULL);
-		if (end_time != 0) {
-			time = end_time - time;
-			if (time < 0)
-				time += period;
-		} else
-			time = 0;
-	}
-
-	return time;
-}
-
-/**
- * pm_hrtimer_cb() : Callback function for hrtimer created if the
- *                   core needs to be awake to handle an event.
- * @hrtimer : Pointer to hrtimer
- */
-static enum hrtimer_restart pm_hrtimer_cb(struct hrtimer *hrtimer)
-{
-	return HRTIMER_NORESTART;
-}
-
-/**
- * msm_pm_set_timer() : Set an hrtimer to wakeup the core in time
- *                      to handle an event.
- */
-static void msm_pm_set_timer(uint32_t modified_time_us)
-{
-	u64 modified_time_ns = modified_time_us * NSEC_PER_USEC;
-	ktime_t modified_ktime = ns_to_ktime(modified_time_ns);
-	pm_hrtimer.function = pm_hrtimer_cb;
-	hrtimer_start(&pm_hrtimer, modified_ktime, HRTIMER_MODE_REL);
-}
-
 /******************************************************************************
  * External Idle/Suspend Functions
  *****************************************************************************/
@@ -916,221 +701,66 @@
 	}
 }
 
-static int msm_pm_idle_prepare(struct cpuidle_device *dev,
-		struct cpuidle_driver *drv, int index,
-		void **msm_pm_idle_rs_limits)
+static enum msm_pm_time_stats_id (*execute[MSM_PM_SLEEP_MODE_NR])(bool idle) = {
+	[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT] = msm_pm_swfi,
+	[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE] =
+		msm_pm_power_collapse_standalone,
+	[MSM_PM_SLEEP_MODE_RETENTION] = msm_pm_retention,
+	[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = msm_pm_power_collapse,
+};
+
+bool msm_cpu_pm_check_mode(unsigned int cpu, enum msm_pm_sleep_mode mode,
+		bool from_idle)
 {
-	int i;
-	unsigned int power_usage = -1;
-	int ret = MSM_PM_SLEEP_MODE_NOT_SELECTED;
-	uint32_t modified_time_us = 0;
-	struct msm_pm_time_params time_param;
+	int idx = MSM_PM_MODE(cpu, mode);
+	struct msm_pm_platform_data *d = &msm_pm_sleep_modes[idx];
 
-	time_param.latency_us =
-		(uint32_t) pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
-	time_param.sleep_us =
-		(uint32_t) (ktime_to_us(tick_nohz_get_sleep_length())
-								& UINT_MAX);
-	time_param.modified_time_us = 0;
+	if ((mode == MSM_PM_SLEEP_MODE_RETENTION)
+			&& !msm_pm_ldo_retention_enabled)
+		return false;
 
-	if (!dev->cpu)
-		time_param.next_event_us =
-			(uint32_t) (ktime_to_us(get_next_event_time())
-								& UINT_MAX);
+	if (from_idle)
+		return d->idle_enabled && d->idle_supported;
 	else
-		time_param.next_event_us = 0;
-
-	for (i = 0; i < dev->state_count; i++) {
-		struct cpuidle_state *state = &drv->states[i];
-		struct cpuidle_state_usage *st_usage = &dev->states_usage[i];
-		enum msm_pm_sleep_mode mode;
-		bool allow;
-		uint32_t power;
-		int idx;
-		void *rs_limits = NULL;
-
-		mode = (enum msm_pm_sleep_mode) cpuidle_get_statedata(st_usage);
-		idx = MSM_PM_MODE(dev->cpu, mode);
-
-		allow = msm_pm_sleep_modes[idx].idle_enabled &&
-				msm_pm_sleep_modes[idx].idle_supported;
-
-		switch (mode) {
-		case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
-			if (num_online_cpus() > 1)
-				allow = false;
-			break;
-		case MSM_PM_SLEEP_MODE_RETENTION:
-			/*
-			 * The Krait BHS regulator doesn't have enough head
-			 * room to drive the retention voltage on LDO and so
-			 * has disabled retention
-			 */
-			if (!msm_pm_ldo_retention_enabled)
-				allow = false;
-
-			if (msm_pm_retention_calls_tz && num_online_cpus() > 1)
-				allow = false;
-			break;
-		case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
-		case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
-			break;
-		default:
-			allow = false;
-			break;
-		}
-
-		if (!allow)
-			continue;
-
-		if (pm_sleep_ops.lowest_limits)
-			rs_limits = pm_sleep_ops.lowest_limits(true,
-					mode, &time_param, &power);
-
-		if (MSM_PM_DEBUG_IDLE & msm_pm_debug_mask)
-			pr_info("CPU%u:%s:%s, latency %uus, slp %uus, lim %p\n",
-					dev->cpu, __func__, state->desc,
-					time_param.latency_us,
-					time_param.sleep_us, rs_limits);
-		if (!rs_limits)
-			continue;
-
-		if (power < power_usage) {
-			power_usage = power;
-			modified_time_us = time_param.modified_time_us;
-			ret = mode;
-			*msm_pm_idle_rs_limits = rs_limits;
-		}
-
-	}
-
-	if (modified_time_us && !dev->cpu)
-		msm_pm_set_timer(modified_time_us);
-
-	msm_pm_ftrace_lpm_enter(dev->cpu, time_param.latency_us,
-			time_param.sleep_us, time_param.next_event_us,
-			ret);
-
-	return ret;
+		return d->suspend_enabled && d->suspend_supported;
 }
 
-enum msm_pm_sleep_mode msm_pm_idle_enter(struct cpuidle_device *dev,
-	struct cpuidle_driver *drv, int index)
+int msm_cpu_pm_enter_sleep(enum msm_pm_sleep_mode mode, bool from_idle)
 {
 	int64_t time;
 	bool collapsed = 1;
 	int exit_stat = -1;
-	enum msm_pm_sleep_mode sleep_mode;
-	void *msm_pm_idle_rs_limits = NULL;
-	uint32_t sleep_delay = 1;
-	int ret = -ENODEV;
-	int notify_rpm = false;
-	bool timer_halted = false;
-
-	sleep_mode = msm_pm_idle_prepare(dev, drv, index,
-		&msm_pm_idle_rs_limits);
-
-	if (!msm_pm_idle_rs_limits) {
-		sleep_mode = MSM_PM_SLEEP_MODE_NOT_SELECTED;
-		goto cpuidle_enter_bail;
-	}
 
 	if (MSM_PM_DEBUG_IDLE & msm_pm_debug_mask)
 		pr_info("CPU%u: %s: mode %d\n",
-			smp_processor_id(), __func__, sleep_mode);
+			smp_processor_id(), __func__, mode);
+	if (!from_idle)
+		pr_info("CPU%u: %s mode:%d\n",
+			smp_processor_id(), __func__, mode);
 
-	time = ktime_to_ns(ktime_get());
-
-	if (sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) {
-		int64_t ns = msm_pm_timer_enter_idle();
-		notify_rpm = true;
-		do_div(ns, NSEC_PER_SEC / SCLK_HZ);
-		sleep_delay = (uint32_t)ns;
-
-		if (sleep_delay == 0) /* 0 would mean infinite time */
-			sleep_delay = 1;
-	}
-
-	if (pm_sleep_ops.enter_sleep)
-		ret = pm_sleep_ops.enter_sleep(sleep_delay,
-			msm_pm_idle_rs_limits, true, notify_rpm);
-	if (ret)
-		goto cpuidle_enter_bail;
-
-	switch (sleep_mode) {
-	case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
-		msm_pm_swfi();
-		exit_stat = MSM_PM_STAT_IDLE_WFI;
-		break;
-
-	case MSM_PM_SLEEP_MODE_RETENTION:
-		msm_pm_retention();
-		exit_stat = MSM_PM_STAT_RETENTION;
-		break;
-
-	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
-		collapsed = msm_pm_power_collapse_standalone(true);
-		if (collapsed)
-			exit_stat = MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE;
-		else
-			exit_stat
-			    = MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE;
-		break;
-
-	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
-		if (MSM_PM_DEBUG_IDLE_CLK & msm_pm_debug_mask)
-			clock_debug_print_enabled();
-
-		collapsed = msm_pm_power_collapse(true);
-		timer_halted = true;
-
-		if (collapsed)
-			exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
-		else
-			exit_stat = MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE;
-
-		msm_pm_timer_exit_idle(timer_halted);
-		break;
-
-	case MSM_PM_SLEEP_MODE_NOT_SELECTED:
-		goto cpuidle_enter_bail;
-		break;
-
-	default:
-		__WARN();
-		goto cpuidle_enter_bail;
-		break;
-	}
-
-	if (pm_sleep_ops.exit_sleep)
-		pm_sleep_ops.exit_sleep(msm_pm_idle_rs_limits, true,
-				notify_rpm, collapsed);
-
-	time = ktime_to_ns(ktime_get()) - time;
-	msm_pm_ftrace_lpm_exit(smp_processor_id(), sleep_mode, collapsed);
+	time = sched_clock();
+	if (execute[mode])
+		exit_stat = execute[mode](from_idle);
+	time = sched_clock() - time;
+	if (from_idle)
+		msm_pm_ftrace_lpm_exit(smp_processor_id(), mode, collapsed);
+	else
+		exit_stat = MSM_PM_STAT_SUSPEND;
 	if (exit_stat >= 0)
 		msm_pm_add_stat(exit_stat, time);
 	do_div(time, 1000);
-	dev->last_residency = (int) time;
-	return sleep_mode;
-
-cpuidle_enter_bail:
-	dev->last_residency = 0;
-	if (sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE)
-		msm_pm_timer_exit_idle(timer_halted);
-	sleep_mode = MSM_PM_SLEEP_MODE_NOT_SELECTED;
-	return sleep_mode;
+	return collapsed;
 }
 
 int msm_pm_wait_cpu_shutdown(unsigned int cpu)
 {
-	int timeout = 0;
+	int timeout = 10;
 
 	if (!msm_pm_slp_sts)
 		return 0;
 	if (!msm_pm_slp_sts[cpu].base_addr)
 		return 0;
-	while (1) {
+	while (timeout--) {
 		/*
 		 * Check for the SPM of the core being hotplugged to set
 		 * its sleep state.The SPM sleep state indicates that the
@@ -1141,10 +771,10 @@
 		if (acc_sts & msm_pm_slp_sts[cpu].mask)
 			return 0;
 		udelay(100);
-		WARN(++timeout == 20, "CPU%u didn't collape within 2ms\n",
-					cpu);
 	}
 
+	pr_info("%s(): Timed out waiting for CPU %u SPM to enter sleep state",
+		__func__, cpu);
 	return -EBUSY;
 }
 
@@ -1168,9 +798,9 @@
 	else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE])
 		msm_pm_power_collapse_standalone(false);
 	else if (allow[MSM_PM_SLEEP_MODE_RETENTION])
-		msm_pm_retention();
+		msm_pm_retention(false);
 	else
-		msm_pm_swfi();
+		msm_pm_swfi(false);
 }
 
 static void msm_pm_ack_retention_disable(void *data)
@@ -1191,6 +821,7 @@
 		return;
 
 	msm_pm_ldo_retention_enabled = enable;
+
 	/*
 	 * If retention is being disabled, wakeup all online core to ensure
 	 * that it isn't executing retention. Offlined cores need not be woken
@@ -1199,142 +830,15 @@
 	 */
 	if (!enable) {
 		preempt_disable();
-		smp_call_function_many(cpu_online_mask,
+		smp_call_function_many(&retention_cpus,
 				msm_pm_ack_retention_disable,
 				NULL, true);
 		preempt_enable();
-
-
 	}
 }
 EXPORT_SYMBOL(msm_pm_enable_retention);
 
-static int64_t suspend_time, suspend_period;
-static int collapsed;
-static int suspend_power_collapsed;
-
-static int msm_pm_enter(suspend_state_t state)
-{
-	bool allow[MSM_PM_SLEEP_MODE_NR];
-	int i;
-	struct msm_pm_time_params time_param;
-
-	time_param.latency_us = -1;
-	time_param.sleep_us = -1;
-	time_param.next_event_us = 0;
-
-	if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
-		pr_info("%s\n", __func__);
-
-	if (smp_processor_id()) {
-		__WARN();
-		goto enter_exit;
-	}
-
-
-	for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
-		struct msm_pm_platform_data *mode;
-
-		mode = &msm_pm_sleep_modes[MSM_PM_MODE(0, i)];
-		allow[i] = mode->suspend_supported && mode->suspend_enabled;
-	}
-
-	if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE]) {
-		void *rs_limits = NULL;
-		int ret = -ENODEV;
-		uint32_t power;
-		uint32_t msm_pm_max_sleep_time = 0;
-
-		if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
-			pr_info("%s: power collapse\n", __func__);
-
-		clock_debug_print_enabled();
-
-		if (msm_pm_sleep_time_override > 0) {
-			int64_t ns = NSEC_PER_SEC *
-				(int64_t) msm_pm_sleep_time_override;
-			do_div(ns, NSEC_PER_SEC / SCLK_HZ);
-			msm_pm_max_sleep_time = (uint32_t) ns;
-		}
-
-		if (pm_sleep_ops.lowest_limits)
-			rs_limits = pm_sleep_ops.lowest_limits(false,
-		MSM_PM_SLEEP_MODE_POWER_COLLAPSE, &time_param, &power);
-
-		if (rs_limits) {
-			if (pm_sleep_ops.enter_sleep)
-				ret = pm_sleep_ops.enter_sleep(
-						msm_pm_max_sleep_time,
-						rs_limits, false, true);
-			if (!ret) {
-				collapsed = msm_pm_power_collapse(false);
-				if (pm_sleep_ops.exit_sleep) {
-					pm_sleep_ops.exit_sleep(rs_limits,
-						false, true, collapsed);
-				}
-			}
-		} else {
-			pr_err("%s: cannot find the lowest power limit\n",
-				__func__);
-		}
-		suspend_power_collapsed = true;
-	} else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
-		if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
-			pr_info("%s: standalone power collapse\n", __func__);
-		msm_pm_power_collapse_standalone(false);
-	} else if (allow[MSM_PM_SLEEP_MODE_RETENTION]) {
-		if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
-			pr_info("%s: retention\n", __func__);
-		msm_pm_retention();
-	} else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT]) {
-		if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
-			pr_info("%s: swfi\n", __func__);
-		msm_pm_swfi();
-	}
-
-enter_exit:
-	if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
-		pr_info("%s: return\n", __func__);
-
-	return 0;
-}
-
-void msm_pm_set_sleep_ops(struct msm_pm_sleep_ops *ops)
-{
-	if (ops)
-		pm_sleep_ops = *ops;
-}
-
-static int msm_suspend_prepare(void)
-{
-	suspend_time = msm_pm_timer_enter_suspend(&suspend_period);
-	msm_mpm_suspend_prepare();
-	return 0;
-}
-
-static void msm_suspend_wake(void)
-{
-	msm_mpm_suspend_wake();
-	if (suspend_power_collapsed) {
-		suspend_time = msm_pm_timer_exit_suspend(suspend_time,
-				suspend_period);
-		if (collapsed)
-			msm_pm_add_stat(MSM_PM_STAT_SUSPEND, suspend_time);
-		else
-			msm_pm_add_stat(MSM_PM_STAT_FAILED_SUSPEND,
-					suspend_time);
-		suspend_power_collapsed = false;
-	}
-}
-
-static const struct platform_suspend_ops msm_pm_ops = {
-	.enter = msm_pm_enter,
-	.valid = suspend_valid_only_mem,
-	.prepare_late = msm_suspend_prepare,
-	.wake = msm_suspend_wake,
-};
-
-static int __devinit msm_pm_snoc_client_probe(struct platform_device *pdev)
+static int msm_pm_snoc_client_probe(struct platform_device *pdev)
 {
 	int rc = 0;
 	static struct msm_bus_scale_pdata *msm_pm_bus_pdata;
@@ -1347,8 +851,7 @@
 			msm_bus_scale_register_client(msm_pm_bus_pdata);
 
 		if (!msm_pm_bus_client) {
-			pr_err("%s: Failed to register SNOC client",
-							__func__);
+			pr_err("%s: Failed to register SNOC client", __func__);
 			rc = -ENXIO;
 			goto snoc_cl_probe_done;
 		}
@@ -1363,7 +866,7 @@
 	return rc;
 }
 
-static int __devinit msm_cpu_status_probe(struct platform_device *pdev)
+static int msm_cpu_status_probe(struct platform_device *pdev)
 {
 	struct msm_pm_sleep_status_data *pdata;
 	char *key;
@@ -1372,9 +875,9 @@
 	if (!pdev)
 		return -EFAULT;
 
-	msm_pm_slp_sts =
-		kzalloc(sizeof(*msm_pm_slp_sts) * num_possible_cpus(),
-				GFP_KERNEL);
+	msm_pm_slp_sts = devm_kzalloc(&pdev->dev,
+			sizeof(*msm_pm_slp_sts) * num_possible_cpus(),
+			GFP_KERNEL);
 
 	if (!msm_pm_slp_sts)
 		return -ENOMEM;
@@ -1387,34 +890,34 @@
 
 		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 		if (!res)
-			goto fail_free_mem;
+			return -ENODEV;
 
 		key = "qcom,cpu-alias-addr";
 		rc = of_property_read_u32(pdev->dev.of_node, key, &offset);
 
 		if (rc)
-			goto fail_free_mem;
+			return -ENODEV;
 
 		key = "qcom,sleep-status-mask";
-		rc = of_property_read_u32(pdev->dev.of_node, key,
-					&mask);
+		rc = of_property_read_u32(pdev->dev.of_node, key, &mask);
+
 		if (rc)
-			goto fail_free_mem;
+			return -ENODEV;
 
 		for_each_possible_cpu(cpu) {
+			phys_addr_t base_c = res->start + cpu * offset;
 			msm_pm_slp_sts[cpu].base_addr =
-				ioremap(res->start + cpu * offset,
-					resource_size(res));
+				devm_ioremap(&pdev->dev, base_c,
+						resource_size(res));
 			msm_pm_slp_sts[cpu].mask = mask;
 
 			if (!msm_pm_slp_sts[cpu].base_addr)
-				goto failed_of_node;
+				return -ENOMEM;
 		}
-
 	} else {
 		pdata = pdev->dev.platform_data;
 		if (!pdev->dev.platform_data)
-			goto fail_free_mem;
+			return -EINVAL;
 
 		for_each_possible_cpu(cpu) {
 			msm_pm_slp_sts[cpu].base_addr =
@@ -1424,17 +927,6 @@
 	}
 
 	return 0;
-
-failed_of_node:
-	pr_info("%s(): Failed to key=%s\n", __func__, key);
-	for_each_possible_cpu(cpu) {
-		if (msm_pm_slp_sts[cpu].base_addr)
-			iounmap(msm_pm_slp_sts[cpu].base_addr);
-	}
-fail_free_mem:
-	kfree(msm_pm_slp_sts);
-	return -EINVAL;
-
 };
 
 static struct of_device_id msm_slp_sts_match_tbl[] = {
@@ -1465,55 +957,24 @@
 	},
 };
 
-static void setup_broadcast_timer(void *arg)
-{
-	int cpu = smp_processor_id();
-
-	clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &cpu);
-}
-
-static int setup_broadcast_cpuhp_notify(struct notifier_block *n,
-		unsigned long action, void *hcpu)
-{
-	int cpu = (unsigned long)hcpu;
-
-	switch (action & ~CPU_TASKS_FROZEN) {
-	case CPU_ONLINE:
-		smp_call_function_single(cpu, setup_broadcast_timer, NULL, 1);
-		break;
-	}
-
-	return NOTIFY_OK;
-}
-
-static struct notifier_block setup_broadcast_notifier = {
-	.notifier_call = setup_broadcast_cpuhp_notify,
-};
-
-static int __init msm_pm_init(void)
+static int msm_pm_init(void)
 {
 	enum msm_pm_time_stats_id enable_stats[] = {
 		MSM_PM_STAT_IDLE_WFI,
 		MSM_PM_STAT_RETENTION,
 		MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE,
+		MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE,
 		MSM_PM_STAT_IDLE_POWER_COLLAPSE,
+		MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE,
 		MSM_PM_STAT_SUSPEND,
 	};
 	msm_pm_mode_sysfs_add();
 	msm_pm_add_stats(enable_stats, ARRAY_SIZE(enable_stats));
-	suspend_set_ops(&msm_pm_ops);
-	hrtimer_init(&pm_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-	msm_cpuidle_init();
-
-	if (msm_pm_pc_reset_timer) {
-		on_each_cpu(setup_broadcast_timer, NULL, 1);
-		register_cpu_notifier(&setup_broadcast_notifier);
-	}
 
 	return 0;
 }
 
-static void __devinit msm_pm_set_flush_fn(uint32_t pc_mode)
+static void msm_pm_set_flush_fn(uint32_t pc_mode)
 {
 	msm_pm_disable_l2_fn = NULL;
 	msm_pm_enable_l2_fn = NULL;
@@ -1555,10 +1016,10 @@
 				sizeof(data->buf)-data->len,
 				"CPU%d\n", cpu);
 
-			for (j = 0; j < MSM_PC_NUM_COUNTERS; j++) {
-				stat = msm_pc_debug_counters_read_register(
-						data->reg, cpu, j);
-				data->len += scnprintf(data->buf + data->len,
+		for (j = 0; j < MSM_PC_NUM_COUNTERS; j++) {
+			stat = msm_pc_debug_counters_read_register(
+					data->reg, cpu, j);
+			data->len += scnprintf(data->buf + data->len,
 					sizeof(data->buf)-data->len,
 					"\t%s : %d\n", counter_name[j],
 					stat);
@@ -1579,7 +1040,7 @@
 	if (!data)
 		return -EINVAL;
 
-	if (!bufu)
+	if (!bufu || count < 0)
 		return -EINVAL;
 
 	if (!access_ok(VERIFY_WRITE, bufu, count))
@@ -1673,50 +1134,42 @@
 	return PTR_RET(l2_clk);
 }
 
-static int __devinit msm_pm_8x60_probe(struct platform_device *pdev)
+static int msm_cpu_pm_probe(struct platform_device *pdev)
 {
 	char *key = NULL;
 	struct dentry *dent = NULL;
 	struct resource *res = NULL;
-	int i ;
+	int i;
 	struct msm_pm_init_data_type pdata_local;
 	int ret = 0;
 
 	memset(&pdata_local, 0, sizeof(struct msm_pm_init_data_type));
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (res) {
-		msm_pc_debug_counters_phys = res->start;
-		WARN_ON(resource_size(res) < SZ_64);
-		msm_pc_debug_counters = devm_ioremap(&pdev->dev, res->start,
+	if (!res)
+		return  0;
+	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)
-			for (i = 0; i < resource_size(res)/4; i++)
-				__raw_writel(0, msm_pc_debug_counters + i * 4);
+	if (msm_pc_debug_counters) {
+		for (i = 0; i < resource_size(res)/4; i++)
+			__raw_writel(0, msm_pc_debug_counters + i * 4);
 
-	}
-
-	if (!msm_pc_debug_counters) {
-		msm_pc_debug_counters = 0;
-		msm_pc_debug_counters_phys = 0;
-	} else {
 		dent = debugfs_create_file("pc_debug_counter", S_IRUGO, NULL,
 				msm_pc_debug_counters,
 				&msm_pc_debug_counters_fops);
 		if (!dent)
 			pr_err("%s: ERROR debugfs_create_file failed\n",
 					__func__);
+	} else {
+		msm_pc_debug_counters = 0;
+		msm_pc_debug_counters_phys = 0;
 	}
 
-	if (!pdev->dev.of_node) {
-		struct msm_pm_init_data_type *d = pdev->dev.platform_data;
+	if (pdev->dev.of_node) {
+		enum msm_pm_pc_mode_type pc_mode;
 
-		if (!d)
-			goto pm_8x60_probe_done;
-
-		memcpy(&pdata_local, d, sizeof(struct msm_pm_init_data_type));
-
-	} else {
 		ret = msm_pm_clk_init(pdev);
 		if (ret) {
 			pr_info("msm_pm_clk_init returned error\n");
@@ -1724,52 +1177,14 @@
 		}
 
 		key = "qcom,pc-mode";
-		ret = msm_pm_get_pc_mode(pdev->dev.of_node,
-				key,
-				&pdata_local.pc_mode);
+		ret = msm_pm_get_pc_mode(pdev->dev.of_node, key, &pc_mode);
 		if (ret) {
-			pr_debug("%s: Error reading key %s",
-					__func__, key);
+			pr_debug("%s: Error reading key %s", __func__, key);
 			return -EINVAL;
 		}
-
-		key = "qcom,use-sync-timer";
-		pdata_local.use_sync_timer =
-			of_property_read_bool(pdev->dev.of_node, key);
-
-		key = "qcom,saw-turns-off-pll";
-		msm_no_ramp_down_pc = of_property_read_bool(pdev->dev.of_node,
-					key);
-
-		key = "qcom,pc-resets-timer";
-		msm_pm_pc_reset_timer = of_property_read_bool(
-				pdev->dev.of_node, key);
+		msm_pm_set_flush_fn(pc_mode);
 	}
 
-	if (pdata_local.cp15_data.reg_data &&
-		pdata_local.cp15_data.reg_saved_state_size > 0) {
-		cp15_data.reg_data = kzalloc(sizeof(uint32_t) *
-				pdata_local.cp15_data.reg_saved_state_size,
-				GFP_KERNEL);
-		if (!cp15_data.reg_data)
-			return -ENOMEM;
-
-		cp15_data.reg_val = kzalloc(sizeof(uint32_t) *
-				pdata_local.cp15_data.reg_saved_state_size,
-				GFP_KERNEL);
-		if (cp15_data.reg_val)
-			return -ENOMEM;
-
-		memcpy(cp15_data.reg_data, pdata_local.cp15_data.reg_data,
-			pdata_local.cp15_data.reg_saved_state_size *
-			sizeof(uint32_t));
-	}
-
-	msm_pm_set_flush_fn(pdata_local.pc_mode);
-	msm_pm_use_sync_timer = pdata_local.use_sync_timer;
-	msm_pm_retention_calls_tz = pdata_local.retention_calls_tz;
-
-pm_8x60_probe_done:
 	msm_pm_init();
 	if (pdev->dev.of_node)
 		of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
@@ -1777,24 +1192,26 @@
 	return ret;
 }
 
-static struct of_device_id msm_pm_8x60_table[] = {
-		{.compatible = "qcom,pm-8x60"},
-		{},
+static struct of_device_id msm_cpu_pm_table[] = {
+	{.compatible = "qcom,pm-8x60"},
+	{},
 };
 
-static struct platform_driver msm_pm_8x60_driver = {
-		.probe = msm_pm_8x60_probe,
-		.driver = {
-			.name = "pm-8x60",
-			.owner = THIS_MODULE,
-			.of_match_table = msm_pm_8x60_table,
-		},
+static struct platform_driver msm_cpu_pm_driver = {
+	.probe = msm_cpu_pm_probe,
+	.driver = {
+		.name = "pm-8x60",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_cpu_pm_table,
+	},
 };
 
-static int __init msm_pm_8x60_init(void)
+static int __init msm_cpu_pm_init(void)
 {
 	int rc;
 
+	cpumask_clear(&retention_cpus);
+
 	rc = platform_driver_register(&msm_cpu_pm_snoc_client_driver);
 
 	if (rc) {
@@ -1803,9 +1220,9 @@
 		return rc;
 	}
 
-	return platform_driver_register(&msm_pm_8x60_driver);
+	return platform_driver_register(&msm_cpu_pm_driver);
 }
-device_initcall(msm_pm_8x60_init);
+device_initcall(msm_cpu_pm_init);
 
 void __init msm_pm_sleep_status_init(void)
 {