From 12f27826bdaf56b01cbdfc8bdeb577ebc106dee3 Mon Sep 17 00:00:00 2001 From: Santosh Shilimkar Date: Tue, 8 Mar 2011 18:24:30 +0530 Subject: ARM: OMAP4: PM: Keep static dep between MPUSS-EMIF and MPUSS-L3/L4 and DUCATI-L3 As per OMAP4430 TRM, the dynamic dependency between MPUSS -> EMIF and MPUSS -> L4PER/L3_* and DUCATI -> L3_* clockdomains is enable by default. Refer register CM_MPU_DYNAMICDEP description for details. But these dynamic dependencies doesn't work as expected. The hardware recommendation is to enable static dependencies for above clockdomains. Without this, system locks up or randomly crashes. Signed-off-by: Rajendra Nayak Signed-off-by: Santosh Shilimkar Acked-by: Paul Walmsley Acked-by: Jean Pihet Reviewed-by: Kevin Hilman Tested-by: Vishwanath BS Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/pm44xx.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'arch/arm/mach-omap2/pm44xx.c') diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c index 8edb015f5618..715035d0512a 100644 --- a/arch/arm/mach-omap2/pm44xx.c +++ b/arch/arm/mach-omap2/pm44xx.c @@ -99,6 +99,8 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused) static int __init omap4_pm_init(void) { int ret; + struct clockdomain *emif_clkdm, *mpuss_clkdm, *l3_1_clkdm; + struct clockdomain *ducati_clkdm, *l3_2_clkdm, *l4_per_clkdm; if (!cpu_is_omap44xx()) return -ENODEV; @@ -111,6 +113,34 @@ static int __init omap4_pm_init(void) goto err2; } + /* + * The dynamic dependency between MPUSS -> MEMIF and + * MPUSS -> L4_PER/L3_* and DUCATI -> L3_* doesn't work as + * expected. The hardware recommendation is to enable static + * dependencies for these to avoid system lock ups or random crashes. + */ + mpuss_clkdm = clkdm_lookup("mpuss_clkdm"); + emif_clkdm = clkdm_lookup("l3_emif_clkdm"); + l3_1_clkdm = clkdm_lookup("l3_1_clkdm"); + l3_2_clkdm = clkdm_lookup("l3_2_clkdm"); + l4_per_clkdm = clkdm_lookup("l4_per_clkdm"); + ducati_clkdm = clkdm_lookup("ducati_clkdm"); + if ((!mpuss_clkdm) || (!emif_clkdm) || (!l3_1_clkdm) || + (!l3_2_clkdm) || (!ducati_clkdm) || (!l4_per_clkdm)) + goto err2; + + ret = clkdm_add_wkdep(mpuss_clkdm, emif_clkdm); + ret |= clkdm_add_wkdep(mpuss_clkdm, l3_1_clkdm); + ret |= clkdm_add_wkdep(mpuss_clkdm, l3_2_clkdm); + ret |= clkdm_add_wkdep(mpuss_clkdm, l4_per_clkdm); + ret |= clkdm_add_wkdep(ducati_clkdm, l3_1_clkdm); + ret |= clkdm_add_wkdep(ducati_clkdm, l3_2_clkdm); + if (ret) { + pr_err("Failed to add MPUSS -> L3/EMIF/L4PER, DUCATI -> L3 " + "wakeup dependency\n"); + goto err2; + } + #ifdef CONFIG_SUSPEND suspend_set_ops(&omap_pm_ops); #endif /* CONFIG_SUSPEND */ -- cgit v1.2.1 From 361b02f3538bc5603a426ed3bb04129a8d7b9a67 Mon Sep 17 00:00:00 2001 From: Santosh Shilimkar Date: Fri, 11 Mar 2011 16:13:09 +0530 Subject: ARM: OMAP4: PM: Avoid omap4_pm_init() on OMAP4430 ES1.0 On OMAP4430 ES1.0, Power Management features are not supported. Avoid omap4_pm_init() on ES1.0 silicon so that we can continue to use same kernel binary to boot on all OMAP4 silicons. The ES1.0 boot failure with OMAP4 PM series was because of the clockdomain initialisation code. Hardware supervised clockdomain mode isn't functional for all clockdomains on OMAP4430 ES1.0 silicon so avoid the same. Signed-off-by: Santosh Shilimkar Reported-by: Kevin Hilman Acked-by: Jean Pihet Reviewed-by: Kevin Hilman Tested-by: Vishwanath BS Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/pm44xx.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'arch/arm/mach-omap2/pm44xx.c') diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c index 715035d0512a..35d392abcaa4 100644 --- a/arch/arm/mach-omap2/pm44xx.c +++ b/arch/arm/mach-omap2/pm44xx.c @@ -105,6 +105,11 @@ static int __init omap4_pm_init(void) if (!cpu_is_omap44xx()) return -ENODEV; + if (omap_rev() == OMAP4430_REV_ES1_0) { + WARN(1, "Power Management not supported on OMAP4430 ES1.0\n"); + return -ENODEV; + } + pr_err("Power Management for TI OMAP4.\n"); ret = pwrdm_for_each(pwrdms_setup, NULL); -- cgit v1.2.1 From 3c50729b3fa1cd8ca1f347e6caf1081204cf1a7c Mon Sep 17 00:00:00 2001 From: Santosh Shilimkar Date: Wed, 5 Jan 2011 22:03:17 +0530 Subject: ARM: OMAP4: PM: Initialise all the clockdomains to supported states Initialise hardware supervised mode for all clockdomains if it's supported. Initiate sleep transition for other clockdomains, if they are not being used. Signed-off-by: Santosh Shilimkar Signed-off-by: Rajendra Nayak Acked-by: Jean Pihet Reviewed-by: Kevin Hilman Tested-by: Vishwanath BS Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/pm44xx.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'arch/arm/mach-omap2/pm44xx.c') diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c index 35d392abcaa4..c34139dc8d8c 100644 --- a/arch/arm/mach-omap2/pm44xx.c +++ b/arch/arm/mach-omap2/pm44xx.c @@ -17,6 +17,7 @@ #include #include "common.h" +#include "clockdomain.h" #include "powerdomain.h" struct power_state { @@ -73,6 +74,22 @@ static const struct platform_suspend_ops omap_pm_ops = { }; #endif /* CONFIG_SUSPEND */ +/* + * Enable hardware supervised mode for all clockdomains if it's + * supported. Initiate sleep transition for other clockdomains, if + * they are not used + */ +static int __init clkdms_setup(struct clockdomain *clkdm, void *unused) +{ + if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO) + clkdm_allow_idle(clkdm); + else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP && + atomic_read(&clkdm->usecount) == 0) + clkdm_sleep(clkdm); + return 0; +} + + static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused) { struct power_state *pwrst; @@ -146,6 +163,8 @@ static int __init omap4_pm_init(void) goto err2; } + (void) clkdm_for_each(clkdms_setup, NULL); + #ifdef CONFIG_SUSPEND suspend_set_ops(&omap_pm_ops); #endif /* CONFIG_SUSPEND */ -- cgit v1.2.1 From b2b9762f76981c16a8768255284efeae7f27e4f1 Mon Sep 17 00:00:00 2001 From: Santosh Shilimkar Date: Wed, 16 Jun 2010 22:19:48 +0530 Subject: ARM: OMAP4: PM: Add CPUX OFF mode support This patch adds the CPU0 and CPU1 off mode support. CPUX close switch retention (CSWR) is not supported by hardware design. The CPUx OFF mode isn't supported on OMAP4430 ES1.0 CPUx sleep code is common for hotplug, suspend and CPUilde. Signed-off-by: Santosh Shilimkar Acked-by: Jean Pihet Reviewed-by: Kevin Hilman Tested-by: Vishwanath BS Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/pm44xx.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'arch/arm/mach-omap2/pm44xx.c') diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c index c34139dc8d8c..781aadf98e32 100644 --- a/arch/arm/mach-omap2/pm44xx.c +++ b/arch/arm/mach-omap2/pm44xx.c @@ -163,6 +163,12 @@ static int __init omap4_pm_init(void) goto err2; } + ret = omap4_mpuss_init(); + if (ret) { + pr_err("Failed to initialise OMAP4 MPUSS\n"); + goto err2; + } + (void) clkdm_for_each(clkdms_setup, NULL); #ifdef CONFIG_SUSPEND -- cgit v1.2.1 From 72826b9f8892957156e3d390b74d8bd5e0835d51 Mon Sep 17 00:00:00 2001 From: Santosh Shilimkar Date: Mon, 18 Jul 2011 12:25:10 +0530 Subject: ARM: OMAP4: PM: Use custom omap_do_wfi() for default idle. Default arch_idle() isn't good enough for OMAP4 because of aync bridge errata and necessity of NOPs post WFI to avoid speculative prefetch aborts. Hence Use OMAP4 custom omap_do_wfi() hook for default idle. Later in the series, async bridge errata work-around patch updates the omap_do_wfi() with necessary interconnects barriers. Signed-off-by: Santosh Shilimkar Acked-by: Jean Pihet Reviewed-by: Kevin Hilman Tested-by: Vishwanath BS Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/pm44xx.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'arch/arm/mach-omap2/pm44xx.c') diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c index 781aadf98e32..72c745047514 100644 --- a/arch/arm/mach-omap2/pm44xx.c +++ b/arch/arm/mach-omap2/pm44xx.c @@ -107,6 +107,24 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused) return pwrdm_set_next_pwrst(pwrst->pwrdm, pwrst->next_state); } +/** + * omap_default_idle - OMAP4 default ilde routine.' + * + * Implements OMAP4 memory, IO ordering requirements which can't be addressed + * with default arch_idle() hook. Used by all CPUs with !CONFIG_CPUIDLE and + * by secondary CPU with CONFIG_CPUIDLE. + */ +static void omap_default_idle(void) +{ + local_irq_disable(); + local_fiq_disable(); + + omap_do_wfi(); + + local_fiq_enable(); + local_irq_enable(); +} + /** * omap4_pm_init - Init routine for OMAP4 PM * @@ -175,6 +193,9 @@ static int __init omap4_pm_init(void) suspend_set_ops(&omap_pm_ops); #endif /* CONFIG_SUSPEND */ + /* Overwrite the default arch_idle() */ + pm_idle = omap_default_idle; + err2: return ret; } -- cgit v1.2.1 From e44f9a7744de8e39eda0f544171efc6e4b1ed91c Mon Sep 17 00:00:00 2001 From: Santosh Shilimkar Date: Wed, 16 Jun 2010 22:19:49 +0530 Subject: 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 Acked-by: Jean Pihet Reviewed-by: Kevin Hilman Tested-by: Vishwanath BS Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/pm44xx.c | 66 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 62 insertions(+), 4 deletions(-) (limited to 'arch/arm/mach-omap2/pm44xx.c') 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 + * Santosh Shilimkar * * 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); } /** -- cgit v1.2.1 From 3ba2a7393e6be48ad7f545a743cd6f46325ba8fd Mon Sep 17 00:00:00 2001 From: Santosh Shilimkar Date: Mon, 6 Jun 2011 14:33:29 +0530 Subject: ARM: OMAP4: PM: Add MPUSS power domain OSWR support This patch adds the MPUSS OSWR (Open Switch Retention) support. The MPUSS OSWR configuration is as below. - CPUx L1 and logic lost, MPUSS logic lost, L2 memory is retained OMAP4460 onwards, MPUSS power domain doesn't support OFF state any more anymore just like CORE power domain. The deepest state supported is OSWR. On OMAP4430 secure devices too, MPUSS off mode can't be used because of a bug which alters Ducati and Tesla states. Hence MPUSS off mode as an independent state isn't supported on OMAP44XX devices. Ofcourse when MPUSS power domain transitions to OSWR along with device off mode, it eventually hits off state since memory contents are lost. Hence the MPUSS off mode independent state is not attempted without device off mode. All the necessary infrastructure code for MPUSS off mode is in place as part of this series. Signed-off-by: Santosh Shilimkar Acked-by: Jean Pihet Reviewed-by: Kevin Hilman Tested-by: Vishwanath BS Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/pm44xx.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'arch/arm/mach-omap2/pm44xx.c') diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c index 6dc9bbe0a4a8..92daae07d634 100644 --- a/arch/arm/mach-omap2/pm44xx.c +++ b/arch/arm/mach-omap2/pm44xx.c @@ -27,6 +27,7 @@ struct power_state { u32 next_state; #ifdef CONFIG_SUSPEND u32 saved_state; + u32 saved_logic_state; #endif struct list_head node; }; @@ -43,11 +44,13 @@ static int omap4_pm_suspend(void) /* Save current powerdomain state */ list_for_each_entry(pwrst, &pwrst_list, node) { pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm); + pwrst->saved_logic_state = pwrdm_read_logic_retst(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); + pwrdm_set_logic_retst(pwrst->pwrdm, PWRDM_POWER_OFF); } /* @@ -71,6 +74,7 @@ static int omap4_pm_suspend(void) ret = -1; } omap_set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state); + pwrdm_set_logic_retst(pwrst->pwrdm, pwrst->saved_logic_state); } if (ret) pr_crit("Could not enter target state in pm_suspend\n"); -- cgit v1.2.1 From 98272660970a71e21ad1992f695f75b780de833c Mon Sep 17 00:00:00 2001 From: Santosh Shilimkar Date: Tue, 16 Aug 2011 17:31:40 +0530 Subject: ARM: OMAP4: PM: Add CPUidle support Add OMAP4 CPUIDLE support. CPU1 is left with defualt idle and the low power state for it is managed via cpu-hotplug. This patch adds MPUSS low power states in cpuidle. C1 - CPU0 ON + CPU1 ON + MPU ON C2 - CPU0 OFF + CPU1 OFF + MPU CSWR C3 - CPU0 OFF + CPU1 OFF + MPU OSWR OMAP4460 onwards, MPUSS power domain doesn't support OFF state any more anymore just like CORE power domain. The deepest state supported is OSWr. Ofcourse when MPUSS and CORE PD transitions to OSWR along with device off mode, even the memory contemts are lost which is as good as the PD off state. On OMAP4 because of hardware constraints, no low power states are targeted when both CPUs are online and in SMP mode. The low power states are attempted only when secondary CPU gets offline to OFF through hotplug infrastructure. Thanks to Nicole Chalhoub for doing exhaustive C-state latency profiling. Signed-off-by: Rajendra Nayak Signed-off-by: Santosh Shilimkar Acked-by: Jean Pihet Reviewed-by: Kevin Hilman Tested-by: Vishwanath BS Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/pm44xx.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/arm/mach-omap2/pm44xx.c') diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c index 92daae07d634..c264ef7219c1 100644 --- a/arch/arm/mach-omap2/pm44xx.c +++ b/arch/arm/mach-omap2/pm44xx.c @@ -258,6 +258,8 @@ static int __init omap4_pm_init(void) /* Overwrite the default arch_idle() */ pm_idle = omap_default_idle; + omap4_idle_init(); + err2: return ret; } -- cgit v1.2.1