msm: pm-8x60: Add retention mode for processor cores
Application processors can do retention mode (apps sleep) in which
the processor reduces the voltage and gates the clock and when an
interrupt occurs will bail out of the low power mode and resume from the
command after WFI.
In retention mode, processor core is not reset and so will not do a warm
boot from TZ.
Change-Id: Id035602dfc53edde88a17ea194dcc85df877e9ea
Signed-off-by: Praveen Chidambaram <pchidamb@codeaurora.org>
diff --git a/arch/arm/mach-msm/cpuidle.c b/arch/arm/mach-msm/cpuidle.c
index 4ba3f95..b68fdc1 100644
--- a/arch/arm/mach-msm/cpuidle.c
+++ b/arch/arm/mach-msm/cpuidle.c
@@ -30,28 +30,40 @@
{0, 0, "C0", "WFI",
MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT},
- {0, 1, "C1", "STANDALONE_POWER_COLLAPSE",
+ {0, 1, "C1", "RETENTION",
+ MSM_PM_SLEEP_MODE_RETENTION},
+
+ {0, 2, "C2", "STANDALONE_POWER_COLLAPSE",
MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE},
- {0, 2, "C2", "POWER_COLLAPSE",
+ {0, 3, "C3", "POWER_COLLAPSE",
MSM_PM_SLEEP_MODE_POWER_COLLAPSE},
{1, 0, "C0", "WFI",
MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT},
- {1, 1, "C1", "STANDALONE_POWER_COLLAPSE",
+ {1, 1, "C1", "RETENTION",
+ MSM_PM_SLEEP_MODE_RETENTION},
+
+ {1, 2, "C2", "STANDALONE_POWER_COLLAPSE",
MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE},
{2, 0, "C0", "WFI",
MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT},
- {2, 1, "C1", "STANDALONE_POWER_COLLAPSE",
+ {2, 1, "C1", "RETENTION",
+ MSM_PM_SLEEP_MODE_RETENTION},
+
+ {2, 2, "C2", "STANDALONE_POWER_COLLAPSE",
MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE},
{3, 0, "C0", "WFI",
MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT},
- {3, 1, "C1", "STANDALONE_POWER_COLLAPSE",
+ {3, 1, "C1", "RETENTION",
+ MSM_PM_SLEEP_MODE_RETENTION},
+
+ {3, 2, "C2", "STANDALONE_POWER_COLLAPSE",
MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE},
};
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 2b0cc18..43e7032 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -105,6 +105,7 @@
static char *msm_pm_sleep_mode_labels[MSM_PM_SLEEP_MODE_NR] = {
[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = "power_collapse",
[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT] = "wfi",
+ [MSM_PM_SLEEP_MODE_RETENTION] = "retention",
[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE] =
"standalone_power_collapse",
};
@@ -324,6 +325,7 @@
enum msm_pm_time_stats_id {
MSM_PM_STAT_REQUESTED_IDLE,
MSM_PM_STAT_IDLE_WFI,
+ MSM_PM_STAT_RETENTION,
MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE,
MSM_PM_STAT_IDLE_POWER_COLLAPSE,
MSM_PM_STAT_SUSPEND,
@@ -617,6 +619,19 @@
msm_arch_idle();
}
+
+static void msm_pm_retention(void)
+{
+ int ret = 0;
+
+ msm_pm_config_hw_before_swfi();
+ ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_POWER_RETENTION, false);
+ WARN_ON(ret);
+ msm_arch_idle();
+ ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
+ WARN_ON(ret);
+}
+
#ifdef CONFIG_CACHE_L2X0
static inline bool msm_pm_l2x0_power_collapse(void)
{
@@ -810,6 +825,11 @@
}
/* fall through */
+ case MSM_PM_SLEEP_MODE_RETENTION:
+ if (!allow)
+ break;
+ /* fall through */
+
case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
if (!allow)
break;
@@ -884,6 +904,13 @@
#endif
break;
+ case MSM_PM_SLEEP_MODE_RETENTION:
+ msm_pm_retention();
+#ifdef CONFIG_MSM_IDLE_STATS
+ exit_stat = MSM_PM_STAT_RETENTION;
+#endif
+ break;
+
case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
msm_pm_power_collapse_standalone(true);
#ifdef CONFIG_MSM_IDLE_STATS
@@ -982,6 +1009,10 @@
per_cpu(msm_pm_last_slp_mode, cpu)
= MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE;
msm_pm_power_collapse_standalone(false);
+ } else if (allow[MSM_PM_SLEEP_MODE_RETENTION]) {
+ per_cpu(msm_pm_last_slp_mode, cpu)
+ = MSM_PM_SLEEP_MODE_RETENTION;
+ msm_pm_retention();
} else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT]) {
per_cpu(msm_pm_last_slp_mode, cpu)
= MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE;
@@ -1108,6 +1139,10 @@
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__);
@@ -1195,6 +1230,10 @@
stats[MSM_PM_STAT_IDLE_WFI].first_bucket_time =
CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+ stats[MSM_PM_STAT_RETENTION].name = "retention";
+ stats[MSM_PM_STAT_RETENTION].first_bucket_time =
+ CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
stats[MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE].name =
"idle-standalone-power-collapse";
stats[MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE].
diff --git a/arch/arm/mach-msm/pm-data.c b/arch/arm/mach-msm/pm-data.c
index d7001d7..6f4743f 100644
--- a/arch/arm/mach-msm/pm-data.c
+++ b/arch/arm/mach-msm/pm-data.c
@@ -28,6 +28,13 @@
.suspend_enabled = 0,
},
+ [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_RETENTION)] = {
+ .idle_supported = 1,
+ .suspend_supported = 1,
+ .idle_enabled = 0,
+ .suspend_enabled = 0,
+ },
+
[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
.idle_supported = 1,
.suspend_supported = 1,
@@ -49,6 +56,13 @@
.suspend_enabled = 0,
},
+ [MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_RETENTION)] = {
+ .idle_supported = 1,
+ .suspend_supported = 1,
+ .idle_enabled = 0,
+ .suspend_enabled = 0,
+ },
+
[MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
.idle_supported = 1,
.suspend_supported = 0,
@@ -70,6 +84,13 @@
.suspend_enabled = 0,
},
+ [MSM_PM_MODE(2, MSM_PM_SLEEP_MODE_RETENTION)] = {
+ .idle_supported = 1,
+ .suspend_supported = 1,
+ .idle_enabled = 0,
+ .suspend_enabled = 0,
+ },
+
[MSM_PM_MODE(2, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
.idle_supported = 1,
.suspend_supported = 0,
@@ -91,6 +112,13 @@
.suspend_enabled = 0,
},
+ [MSM_PM_MODE(3, MSM_PM_SLEEP_MODE_RETENTION)] = {
+ .idle_supported = 1,
+ .suspend_supported = 1,
+ .idle_enabled = 0,
+ .suspend_enabled = 0,
+ },
+
[MSM_PM_MODE(3, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
.idle_supported = 1,
.suspend_supported = 0,
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
index 7ef3c34..09494a0 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -44,13 +44,14 @@
};
enum msm_pm_sleep_mode {
- MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND,
- MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
- MSM_PM_SLEEP_MODE_APPS_SLEEP,
- MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT,
- MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT,
- MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN,
- MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE,
+ MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT = 0,
+ MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT = 1,
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE = 2,
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE = 3,
+ MSM_PM_SLEEP_MODE_APPS_SLEEP = 4,
+ MSM_PM_SLEEP_MODE_RETENTION = MSM_PM_SLEEP_MODE_APPS_SLEEP,
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND = 5,
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN = 6,
MSM_PM_SLEEP_MODE_NR
};