From: nm@ti.com (Nishanth Menon)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH 08/15] ARM: OMAP5: PM: Add CPU power off mode support
Date: Fri, 1 Mar 2013 15:36:01 -0600 [thread overview]
Message-ID: <20130301213601.GA23458@kahuna> (raw)
In-Reply-To: <1362139864-9233-9-git-send-email-santosh.shilimkar@ti.com>
On 17:40-20130301, Santosh Shilimkar wrote:
> Add power management code to handle the CPU off mode. Separate
> suspend finisher is used for OMAP5(Cortex-A15) because it doesn't
> use SCU power status register and external PL310 L2 cache which makes
> code flow bit different.
>
> Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
> ---
> arch/arm/mach-omap2/omap-mpuss-lowpower.c | 31 +++++++----
> arch/arm/mach-omap2/omap-secure.h | 1 +
> arch/arm/mach-omap2/omap4-sar-layout.h | 2 +
> arch/arm/mach-omap2/sleep_omap4plus.S | 80 +++++++++++++++++++++++++++++
> 4 files changed, 104 insertions(+), 10 deletions(-)
>
> diff --git a/arch/arm/mach-omap2/omap-mpuss-lowpower.c b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
> index 9fda96b..275f9a4 100644
> --- a/arch/arm/mach-omap2/omap-mpuss-lowpower.c
> +++ b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
> @@ -76,10 +76,12 @@ struct cpu_pm_ops {
> int (*finish_suspend)(unsigned long cpu_state);
> void (*resume)(void);
> void (*scu_prepare)(unsigned int cpu_id, unsigned int cpu_state);
> + void (*hotplug_restart)(void);
> };
>
> extern int omap4_finish_suspend(unsigned long cpu_state);
> extern void omap4_cpu_resume(void);
> +extern int omap5_finish_suspend(unsigned long cpu_state);
>
> static DEFINE_PER_CPU(struct omap4_cpu_pm_info, omap4_pm_info);
> static struct powerdomain *mpuss_pd;
> @@ -102,6 +104,7 @@ struct cpu_pm_ops omap_pm_ops = {
> .finish_suspend = default_finish_suspend,
> .resume = dummy_cpu_resume,
> .scu_prepare = dummy_scu_prepare,
> + .hotplug_restart = dummy_cpu_resume,
> };
>
> /*
> @@ -334,7 +337,6 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
> int __cpuinit omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state)
> {
> unsigned int cpu_state = 0;
> - struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu);
>
> if (omap_rev() == OMAP4430_REV_ES1_0)
> return -ENXIO;
> @@ -344,7 +346,7 @@ int __cpuinit omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state)
>
> clear_cpu_prev_pwrst(cpu);
> set_cpu_next_pwrst(cpu, power_state);
> - set_cpu_wakeup_addr(cpu, virt_to_phys(pm_info->secondary_startup));
> + set_cpu_wakeup_addr(cpu, virt_to_phys(omap_pm_ops.hotplug_restart));
> omap_pm_ops.scu_prepare(cpu, power_state);
>
> /*
> @@ -379,6 +381,7 @@ static void enable_mercury_retention_mode(void)
> int __init omap4_mpuss_init(void)
> {
> struct omap4_cpu_pm_info *pm_info;
> + u32 cpu_wakeup_addr = 0;
>
> if (omap_rev() == OMAP4430_REV_ES1_0) {
> WARN(1, "Power Management not supported on OMAP4430 ES1.0\n");
> @@ -388,9 +391,13 @@ int __init omap4_mpuss_init(void)
> sar_base = omap4_get_sar_ram_base();
>
> /* Initilaise per CPU PM information */
> + if (cpu_is_omap44xx())
> + cpu_wakeup_addr = CPU0_WAKEUP_NS_PA_ADDR_OFFSET;
> + else if (soc_is_omap54xx())
> + cpu_wakeup_addr = OMAP5_CPU0_WAKEUP_NS_PA_ADDR_OFFSET;
> pm_info = &per_cpu(omap4_pm_info, 0x0);
> pm_info->scu_sar_addr = sar_base + SCU_OFFSET0;
> - pm_info->wkup_sar_addr = sar_base + CPU0_WAKEUP_NS_PA_ADDR_OFFSET;
> + pm_info->wkup_sar_addr = sar_base + cpu_wakeup_addr;
> pm_info->l2x0_sar_addr = sar_base + L2X0_SAVE_OFFSET0;
> pm_info->pwrdm = pwrdm_lookup("cpu0_pwrdm");
> if (!pm_info->pwrdm) {
> @@ -405,14 +412,14 @@ int __init omap4_mpuss_init(void)
> /* Initialise CPU0 power domain state to ON */
> pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON);
>
> + if (cpu_is_omap44xx())
> + cpu_wakeup_addr = CPU1_WAKEUP_NS_PA_ADDR_OFFSET;
> + else if (soc_is_omap54xx())
> + cpu_wakeup_addr = OMAP5_CPU1_WAKEUP_NS_PA_ADDR_OFFSET;
> pm_info = &per_cpu(omap4_pm_info, 0x1);
> pm_info->scu_sar_addr = sar_base + SCU_OFFSET1;
> - pm_info->wkup_sar_addr = sar_base + CPU1_WAKEUP_NS_PA_ADDR_OFFSET;
> + pm_info->wkup_sar_addr = sar_base + cpu_wakeup_addr;
> pm_info->l2x0_sar_addr = sar_base + L2X0_SAVE_OFFSET1;
> - if (cpu_is_omap446x())
> - pm_info->secondary_startup = omap_secondary_startup_4460;
> - else
> - pm_info->secondary_startup = omap_secondary_startup;
>
> pm_info->pwrdm = pwrdm_lookup("cpu1_pwrdm");
> if (!pm_info->pwrdm) {
> @@ -445,15 +452,19 @@ int __init omap4_mpuss_init(void)
>
> if (cpu_is_omap44xx()) {
> omap_pm_ops.finish_suspend = omap4_finish_suspend;
> + omap_pm_ops.hotplug_restart = omap_secondary_startup;
could we handle omap_pm_ops.hotplug_restart = omap_secondary_startup_4460
here as well with the interest of keeping all function inits
in consecutive source location?
> omap_pm_ops.resume = omap4_cpu_resume;
> omap_pm_ops.scu_prepare = scu_pwrst_prepare;
> cpu_context_offset = OMAP4_RM_CPU0_CPU0_CONTEXT_OFFSET;
> } else if (soc_is_omap54xx()) {
> + omap_pm_ops.finish_suspend = omap5_finish_suspend;
> + omap_pm_ops.hotplug_restart = omap5_secondary_startup;
> cpu_context_offset = OMAP54XX_RM_CPU0_CPU0_CONTEXT_OFFSET;
> + enable_mercury_retention_mode();
> }
>
> - if (soc_is_omap54xx())
> - enable_mercury_retention_mode();
> + if (cpu_is_omap446x())
> + omap_pm_ops.hotplug_restart = omap_secondary_startup_4460;
>
> return 0;
> }
> diff --git a/arch/arm/mach-omap2/omap-secure.h b/arch/arm/mach-omap2/omap-secure.h
> index 82b3c4c..6f4dbee 100644
> --- a/arch/arm/mach-omap2/omap-secure.h
> +++ b/arch/arm/mach-omap2/omap-secure.h
> @@ -41,6 +41,7 @@
> #define OMAP4_MON_L2X0_CTRL_INDEX 0x102
> #define OMAP4_MON_L2X0_AUXCTRL_INDEX 0x109
> #define OMAP4_MON_L2X0_PREFETCH_INDEX 0x113
> +#define OMAP5_MON_CACHES_CLEAN_INDEX 0x103
>
> #define OMAP5_MON_AMBA_IF_INDEX 0x108
>
> diff --git a/arch/arm/mach-omap2/omap4-sar-layout.h b/arch/arm/mach-omap2/omap4-sar-layout.h
> index 6822d0a..ee8215b 100644
> --- a/arch/arm/mach-omap2/omap4-sar-layout.h
> +++ b/arch/arm/mach-omap2/omap4-sar-layout.h
> @@ -31,6 +31,8 @@
> /* CPUx Wakeup Non-Secure Physical Address offsets in SAR_BANK3 */
> #define CPU0_WAKEUP_NS_PA_ADDR_OFFSET 0xa04
> #define CPU1_WAKEUP_NS_PA_ADDR_OFFSET 0xa08
> +#define OMAP5_CPU0_WAKEUP_NS_PA_ADDR_OFFSET 0xe00
> +#define OMAP5_CPU1_WAKEUP_NS_PA_ADDR_OFFSET 0xe04
>
> #define SAR_BACKUP_STATUS_OFFSET (SAR_BANK3_OFFSET + 0x500)
> #define SAR_SECURE_RAM_SIZE_OFFSET (SAR_BANK3_OFFSET + 0x504)
> diff --git a/arch/arm/mach-omap2/sleep_omap4plus.S b/arch/arm/mach-omap2/sleep_omap4plus.S
> index 88ff83a..3322fc8 100644
> --- a/arch/arm/mach-omap2/sleep_omap4plus.S
> +++ b/arch/arm/mach-omap2/sleep_omap4plus.S
> @@ -326,6 +326,86 @@ skip_l2en:
>
> b cpu_resume @ Jump to generic resume
> ENDPROC(omap4_cpu_resume)
> +
> +/*
> + * ================================
> + * == OMAP5 CPU suspend finisher ==
> + * ================================
> + *
> + * OMAP5 MPUSS states for the context save:
> + * save_state =
> + * 0 - Nothing lost and no need to save: MPUSS INA/CSWR
> + * 1 - CPUx L1 and logic lost: CPU OFF, MPUSS INA/CSWR
> + * 2 - CPUx L1 and logic lost + GIC lost: MPUSS OSWR
> + * 3 - CPUx L1 and logic lost + GIC + L2 lost: DEVICE OFF
> + */
> +ENTRY(omap5_finish_suspend)
> + stmfd sp!, {r4-r12, lr}
> + cmp r0, #0x0
> + beq do_wfi @ No lowpower state, jump to WFI
> +
> + /*
> + * Flush all data from the L1 data cache before disabling
> + * SCTLR.C bit.
> + */
> + bl omap4_get_sar_ram_base
> + ldr r9, [r0, #OMAP_TYPE_OFFSET]
> + cmp r9, #0x1 @ Check for HS device
> + bne skip_secure_l1_clean_op
> + mov r0, #0 @ Clean secure L1
> + stmfd r13!, {r4-r12, r14}
> + ldr r12, =OMAP5_MON_CACHES_CLEAN_INDEX
> + DO_SMC
> + ldmfd r13!, {r4-r12, r14}
> +skip_secure_l1_clean_op:
> + bl v7_flush_dcache_louis
> +
> + /*
> + * Clear the SCTLR.C bit to prevent further data cache
> + * allocation. Clearing SCTLR.C would make all the data accesses
> + * strongly ordered and would not hit the cache.
> + */
> + mrc p15, 0, r0, c1, c0, 0
> + bic r0, r0, #(1 << 2) @ Disable the C bit
> + mcr p15, 0, r0, c1, c0, 0
> + isb
> +
> + /* Clean and Invalidate L1 data cache. */
> + bl v7_flush_dcache_louis
Curious question - once we have flushed and invalidated L1 on
skip_secure_l1_clean_op:, we disable SCTLR.C to make all accesses SO,
what is the need to go through clean and invalidate again? is'nt it an
un-necessary cycle consuming NOP? What kind of data are we cleaning out
here?
> +
> + /*
> + * Take CPU out of Symmetric Multiprocessing (SMP) mode and thus
> + * preventing the CPU from receiving cache, TLB, or BTB
> + * maintenance operations broadcast by other CPUs in the cluster.
> + */
> + mrc p15, 0, r0, c1, c1, 2 @ Read NSACR data
> + tst r0, #(1 << 18)
> + mrcne p15, 0, r0, c1, c0, 1
> + bicne r0, r0, #(1 << 6) @ Disable SMP bit
> + mcrne p15, 0, r0, c1, c0, 1
> + isb
> + dsb
> +
when save_state=3, as per the function comment:
3 - CPUx L1 and logic lost + GIC + L2 lost: DEVICE OFF
But we dont flush L2 nonsecure OR secure at this point. results wont be
pretty.
If we dont want to deal with "3", then should'nt we add an adequate
handler on entry and remove the code comment claiming we support
it?
is'nt it better to squash in "[PATCH 11/15] ARM: OMAP5: PM: Add L2
memory power down support" here?
> +do_wfi:
> + bl omap_do_wfi
> +
> + /*
> + * CPU is here when it failed to enter OFF/DORMANT or
> + * no low power state was attempted.
This might need a bit more clarity IMHO. successful WFI (which is
arguably an power state if we consider ARM internal clock gating takes
place), will reach here as well. So would OMAP CPU INA state. The
comment is probably valid for the defined save_states in code comments
for CPU OFF which is un-successful.
> + */
> + mrc p15, 0, r0, c1, c0, 0
> + tst r0, #(1 << 2) @ Check C bit enabled?
> + orreq r0, r0, #(1 << 2) @ Enable the C bit
> + mcreq p15, 0, r0, c1, c0, 0
> + isb
> + mrc p15, 0, r0, c1, c0, 1
> + tst r0, #(1 << 6) @ Check SMP bit enabled?
> + orreq r0, r0, #(1 << 6)
> + mcreq p15, 0, r0, c1, c0, 1
> + isb
> + dsb
> + ldmfd sp!, {r4-r12, pc}
> +ENDPROC(omap5_finish_suspend)
> #endif
>
> #ifndef CONFIG_OMAP4_ERRATA_I688
I was curious at this point -> given that we added documentation that
we will be able to go to CPU OFF here, but I did not see an resume
handler registered. Untill I looked down in the series to see:
[PATCH 10/15] ARM: OMAP5: PM: Add MPU Open Switch Retention support
Might be better to squash things up? or maybe remove the
"documentation"? for example:
patch 10 introduces OSWR support, but part of the required support for
it is suspend code - which is introduced here! There is no point IMHO
introducing code to enter OFF mode in one patch and exit off mode in
another patch - just my 2 cents. if we wanted to organize it as per
feature, then maybe:
patch 9 supports just WFI. patch 10 brings in additional suspend and
resume handler for OSWR, patch 11 for device OFF,
in each stage adding documentation for save_state - so that it is
appropriate and in context.
--
Regards,
Nishanth Menon
next prev parent reply other threads:[~2013-03-01 21:36 UTC|newest]
Thread overview: 50+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-03-01 12:10 [PATCH 00/15] ARM: OMAP5: PM: Add MPUSS suspend and CPUidle support Santosh Shilimkar
2013-03-01 12:10 ` [PATCH 01/15] ARM: OMAP4+: PM: Consolidate MPU subsystem PM code for re-use Santosh Shilimkar
2013-03-01 13:50 ` Nishanth Menon
2013-03-01 12:10 ` [PATCH 02/15] ARM: OMAP5: PM: Update CPU context register offset Santosh Shilimkar
2013-03-01 17:34 ` Nishanth Menon
2013-03-01 12:10 ` [PATCH 03/15] ARM: OMAP4+: PM: Consolidate and use OMAP4 PM code for OMAP5 Santosh Shilimkar
2013-03-01 17:43 ` Nishanth Menon
2013-03-02 5:43 ` Santosh Shilimkar
2013-03-04 18:21 ` Nishanth Menon
2013-03-01 12:10 ` [PATCH 04/15] ARM: OMAP5: PM: Set MPUSS-EMIF clock-domain static dependency Santosh Shilimkar
2013-03-01 12:10 ` [PATCH 05/15] ARM: OMAP5: PM: Enables ES2 PM mode by default Santosh Shilimkar
2013-03-01 19:37 ` Nishanth Menon
2013-03-02 5:47 ` Santosh Shilimkar
2013-03-04 18:29 ` Nishanth Menon
2013-03-10 18:07 ` Santosh Shilimkar
2013-03-01 12:10 ` [PATCH 06/15] ARM: OMAP5: PM: Enable Mercury retention mode on CPUx powerdomains Santosh Shilimkar
2013-03-01 19:42 ` Nishanth Menon
2013-03-02 5:52 ` Santosh Shilimkar
2013-03-04 18:33 ` Nishanth Menon
2013-03-01 12:10 ` [PATCH 07/15] ARM: OMAP5: Add init_late() hook to enable pm initialization Santosh Shilimkar
2013-03-01 20:12 ` Nishanth Menon
2013-03-02 6:00 ` Santosh Shilimkar
2013-03-04 18:35 ` Nishanth Menon
2013-03-01 12:10 ` [PATCH 08/15] ARM: OMAP5: PM: Add CPU power off mode support Santosh Shilimkar
2013-03-01 21:36 ` Nishanth Menon [this message]
2013-03-02 6:14 ` Santosh Shilimkar
2013-03-04 18:38 ` Nishanth Menon
2013-03-01 12:10 ` [PATCH 09/15] ARM: OMAP4+: PM: Restore CPU power state to ON with clockdomain force wakeup method Santosh Shilimkar
2013-03-01 21:53 ` Nishanth Menon
2013-03-02 6:16 ` Santosh Shilimkar
2013-03-01 12:10 ` [PATCH 10/15] ARM: OMAP5: PM: Add MPU Open Switch Retention support Santosh Shilimkar
2013-03-01 22:05 ` Nishanth Menon
2013-03-01 12:11 ` [PATCH 11/15] ARM: OMAP5: PM: Add L2 memory power down support Santosh Shilimkar
2013-03-01 23:43 ` Nishanth Menon
2013-03-02 6:24 ` Santosh Shilimkar
2013-03-04 18:41 ` Nishanth Menon
2013-03-01 12:11 ` [PATCH 12/15] ARM: OMAP4+: CPUidle: Cleanup idle driver for OMAP5 support Santosh Shilimkar
2013-03-01 23:56 ` Nishanth Menon
2013-03-02 6:25 ` Santosh Shilimkar
2013-03-01 12:11 ` [PATCH 13/15] ARM: OMAP4+: CPUidle: Deprecate use of omap4_mpuss_read_prev_context_state() Santosh Shilimkar
2013-03-02 0:03 ` Nishanth Menon
2013-03-01 12:11 ` [PATCH 14/15] ARM: OMAP4+: CPUidle: Add OMAP5 idle driver support Santosh Shilimkar
2013-03-02 0:25 ` Nishanth Menon
2013-03-02 6:47 ` Santosh Shilimkar
2013-03-04 18:48 ` Nishanth Menon
2013-03-01 12:11 ` [PATCH 15/15] ARM: OMAP5: PM: handle device instance for for coldreset Santosh Shilimkar
2013-03-01 13:04 ` Nishanth Menon
2013-03-01 13:09 ` Santosh Shilimkar
2013-03-01 13:13 ` Nishanth Menon
2013-03-01 13:16 ` Santosh Shilimkar
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20130301213601.GA23458@kahuna \
--to=nm@ti.com \
--cc=linux-arm-kernel@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox