summaryrefslogtreecommitdiff
path: root/arch/arm/mach-omap2/pm44xx.c
diff options
context:
space:
mode:
authorSantosh Shilimkar <santosh.shilimkar@ti.com>2010-06-16 22:19:49 +0530
committerKevin Hilman <khilman@ti.com>2011-12-08 11:29:01 -0800
commite44f9a7744de8e39eda0f544171efc6e4b1ed91c (patch)
tree6650a4f61f9df92620470533ae0cd83ba7f0a3fb /arch/arm/mach-omap2/pm44xx.c
parent72826b9f8892957156e3d390b74d8bd5e0835d51 (diff)
ARM: OMAP4: suspend: Add MPUSS power domain RETENTION support
This patch adds MPUSS(MPU Sub System) power domain CSWR(Close Switch Retention) support to system wide suspend. For MPUSS power domain to hit retention(CSWR or OSWR), both CPU0 and CPU1 power domains need to be in OFF or DORMANT state, since CPU power domain CSWR is not supported by hardware Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com> Acked-by: Jean Pihet <j-pihet@ti.com> Reviewed-by: Kevin Hilman <khilman@ti.com> Tested-by: Vishwanath BS <vishwanath.bs@ti.com> Signed-off-by: Kevin Hilman <khilman@ti.com>
Diffstat (limited to 'arch/arm/mach-omap2/pm44xx.c')
-rw-r--r--arch/arm/mach-omap2/pm44xx.c66
1 files changed, 62 insertions, 4 deletions
diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
index 72c745047514..6dc9bbe0a4a8 100644
--- a/arch/arm/mach-omap2/pm44xx.c
+++ b/arch/arm/mach-omap2/pm44xx.c
@@ -1,8 +1,9 @@
/*
* OMAP4 Power Management Routines
*
- * Copyright (C) 2010 Texas Instruments, Inc.
+ * Copyright (C) 2010-2011 Texas Instruments, Inc.
* Rajendra Nayak <rnayak@ti.com>
+ * Santosh Shilimkar <santosh.shilimkar@ti.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -19,6 +20,7 @@
#include "common.h"
#include "clockdomain.h"
#include "powerdomain.h"
+#include "pm.h"
struct power_state {
struct powerdomain *pwrdm;
@@ -34,7 +36,47 @@ static LIST_HEAD(pwrst_list);
#ifdef CONFIG_SUSPEND
static int omap4_pm_suspend(void)
{
- do_wfi();
+ struct power_state *pwrst;
+ int state, ret = 0;
+ u32 cpu_id = smp_processor_id();
+
+ /* Save current powerdomain state */
+ list_for_each_entry(pwrst, &pwrst_list, node) {
+ pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm);
+ }
+
+ /* Set targeted power domain states by suspend */
+ list_for_each_entry(pwrst, &pwrst_list, node) {
+ omap_set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
+ }
+
+ /*
+ * For MPUSS to hit power domain retention(CSWR or OSWR),
+ * CPU0 and CPU1 power domains need to be in OFF or DORMANT state,
+ * since CPU power domain CSWR is not supported by hardware
+ * Only master CPU follows suspend path. All other CPUs follow
+ * CPU hotplug path in system wide suspend. On OMAP4, CPU power
+ * domain CSWR is not supported by hardware.
+ * More details can be found in OMAP4430 TRM section 4.3.4.2.
+ */
+ omap4_enter_lowpower(cpu_id, PWRDM_POWER_OFF);
+
+ /* Restore next powerdomain state */
+ list_for_each_entry(pwrst, &pwrst_list, node) {
+ state = pwrdm_read_prev_pwrst(pwrst->pwrdm);
+ if (state > pwrst->next_state) {
+ pr_info("Powerdomain (%s) didn't enter "
+ "target state %d\n",
+ pwrst->pwrdm->name, pwrst->next_state);
+ ret = -1;
+ }
+ omap_set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state);
+ }
+ if (ret)
+ pr_crit("Could not enter target state in pm_suspend\n");
+ else
+ pr_info("Successfully put all powerdomains to target state\n");
+
return 0;
}
@@ -97,14 +139,30 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
if (!pwrdm->pwrsts)
return 0;
+ /*
+ * Skip CPU0 and CPU1 power domains. CPU1 is programmed
+ * through hotplug path and CPU0 explicitly programmed
+ * further down in the code path
+ */
+ if (!strncmp(pwrdm->name, "cpu", 3))
+ return 0;
+
+ /*
+ * FIXME: Remove this check when core retention is supported
+ * Only MPUSS power domain is added in the list.
+ */
+ if (strcmp(pwrdm->name, "mpu_pwrdm"))
+ return 0;
+
pwrst = kmalloc(sizeof(struct power_state), GFP_ATOMIC);
if (!pwrst)
return -ENOMEM;
+
pwrst->pwrdm = pwrdm;
- pwrst->next_state = PWRDM_POWER_ON;
+ pwrst->next_state = PWRDM_POWER_RET;
list_add(&pwrst->node, &pwrst_list);
- return pwrdm_set_next_pwrst(pwrst->pwrdm, pwrst->next_state);
+ return omap_set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
}
/**