msm: pm: Support for Krait Retention
Introduce a new low power state for Krait, retention.
This state will lower the voltage to the Krait core to
retention voltage in addition to clock gating. This state
will be in between WFI and Standalone power collapse in
terms of time overhead and power savings.
Change-Id: I6b1f0a0d2e4954a705a047fd4a07f4dd1fb3518a
Signed-off-by: Girish Mahadevan <girishm@codeaurora.org>
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 1e76262..49a63f7 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -27,6 +27,8 @@
#include <linux/irqchip/arm-gic.h>
#include <mach/msm_iomap.h>
#include <mach/socinfo.h>
+#include <mach/scm.h>
+#include <mach/socinfo.h>
#include <asm/cacheflush.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
@@ -66,6 +68,7 @@
module_param_named(
debug_mask, msm_pm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
);
+static int msm_pm_retention_tz_call;
/******************************************************************************
@@ -77,6 +80,9 @@
MSM_PM_MODE_ATTR_NR,
};
+#define SCM_L2_RETENTION (0x2)
+#define SCM_CMD_TERMINATE_PC (0x2)
+
static char *msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_NR] = {
[MSM_PM_MODE_ATTR_SUSPEND] = "suspend_enabled",
[MSM_PM_MODE_ATTR_IDLE] = "idle_enabled",
@@ -331,7 +337,6 @@
*/
static void msm_pm_config_hw_after_power_up(void)
{
- return;
}
/*
@@ -342,6 +347,22 @@
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;
+}
+
/******************************************************************************
* Suspend Max Sleep Time
@@ -408,12 +429,17 @@
{
int ret = 0;
- msm_pm_config_hw_before_swfi();
+ msm_pm_config_hw_before_retention();
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);
+
+ if (msm_pm_retention_tz_call)
+ scm_call_atomic1(SCM_SVC_BOOT, SCM_CMD_TERMINATE_PC,
+ SCM_L2_RETENTION);
+ else
+ msm_arch_idle();
+
+ msm_pm_config_hw_after_retention();
}
#ifdef CONFIG_CACHE_L2X0
@@ -675,6 +701,10 @@
case MSM_PM_SLEEP_MODE_RETENTION:
if (!allow)
break;
+ if (num_online_cpus() > 1) {
+ allow = false;
+ break;
+ }
/* fall through */
case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
@@ -922,6 +952,11 @@
pm_sleep_ops = *ops;
}
+void __init msm_pm_set_tz_retention_flag(unsigned int flag)
+{
+ msm_pm_retention_tz_call = flag;
+}
+
static int __init msm_pm_init(void)
{
pgd_t *pc_pgd;
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
index 1bb6c24..f19c2cd 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -86,6 +86,7 @@
void msm_pm_set_irq_extns(struct msm_pm_irq_calls *irq_calls);
int msm_pm_idle_enter(enum msm_pm_sleep_mode sleep_mode);
void msm_pm_cpu_enter_lowpower(unsigned int cpu);
+void __init msm_pm_set_tz_retention_flag(unsigned int flag);
#ifdef CONFIG_MSM_PM8X60
void msm_pm_set_rpm_wakeup_irq(unsigned int irq);
diff --git a/arch/arm/mach-msm/spm-v2.c b/arch/arm/mach-msm/spm-v2.c
index 23b67c9..3b6cb5b 100644
--- a/arch/arm/mach-msm/spm-v2.c
+++ b/arch/arm/mach-msm/spm-v2.c
@@ -139,6 +139,10 @@
dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_1] &= ~0x3F;
dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_1] |= (vlevel & 0x3F);
+
+ dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_1] &= ~0x3F0000;
+ dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_1] |=
+ ((vlevel & 0x3F) << 16);
}
static inline void msm_spm_drv_set_vctl2(struct msm_spm_driver_data *dev,