[PATCH 14/25] OMAP4: PM: Add CPUX OFF mode support

Shawn Guo shawn.guo at freescale.com
Fri Sep 9 11:27:30 EDT 2011


On Fri, Sep 09, 2011 at 07:41:08PM +0530, Shilimkar, Santosh wrote:
> On Fri, Sep 9, 2011 at 7:43 PM, Shawn Guo <shawn.guo at freescale.com> wrote:
> > On Fri, Sep 09, 2011 at 01:39:51PM +0530, Santosh wrote:
> >> On Friday 09 September 2011 01:34 PM, Shawn Guo wrote:
> >> >Hi Santosh,
> >> >
> >> >On Sun, Sep 04, 2011 at 07:24:15PM +0530, Santosh Shilimkar wrote:
> >> >>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<santosh.shilimkar at ti.com>
> >> >>Cc: Kevin Hilman<khilman at ti.com>
> >> >>---
> >> >>  arch/arm/mach-omap2/Makefile                    |    3 +-
> >> >>  arch/arm/mach-omap2/include/mach/omap-secure.h  |    8 +
> >> >>  arch/arm/mach-omap2/include/mach/omap4-common.h |   25 +++
> >> >>  arch/arm/mach-omap2/omap-mpuss-lowpower.c       |  249 +++++++++++++++++++++++
> >> >>  arch/arm/mach-omap2/omap-smp.c                  |    6 +
> >> >>  arch/arm/mach-omap2/omap4-sar-layout.h          |    9 +
> >> >>  arch/arm/mach-omap2/pm44xx.c                    |    6 +
> >> >>  arch/arm/mach-omap2/sleep44xx.S                 |  213 +++++++++++++++++++
> >> >>  8 files changed, 518 insertions(+), 1 deletions(-)
> >> >>  create mode 100644 arch/arm/mach-omap2/omap-mpuss-lowpower.c
> >> >>
> >> >
> >> >[...]
> >> >
> >> >>diff --git a/arch/arm/mach-omap2/sleep44xx.S b/arch/arm/mach-omap2/sleep44xx.S
> >> >>index 049f426..230ab8c 100644
> >> >>--- a/arch/arm/mach-omap2/sleep44xx.S
> >> >>+++ b/arch/arm/mach-omap2/sleep44xx.S
> >> >>@@ -11,8 +11,221 @@
> >> >>
> >> >>  #include<linux/linkage.h>
> >> >>  #include<asm/system.h>
> >> >>+#include<asm/smp_scu.h>
> >> >>+#include<asm/memory.h>
> >> >>+#include<asm/hardware/cache-l2x0.h>
> >> >>
> >> >>+#include<plat/omap44xx.h>
> >> >>  #include<mach/omap4-common.h>
> >> >>+#include<mach/omap-secure.h>
> >> >>+
> >> >>+#include "omap4-sar-layout.h"
> >> >>+
> >> >>+#ifdef CONFIG_SMP
> >> >>+
> >> >>+.macro     DO_SMC
> >> >>+   dsb
> >> >>+   smc     #0
> >> >>+   dsb
> >> >>+.endm
> >> >>+
> >> >>+ppa_zero_params:
> >> >>+   .word           0x0
> >> >>+
> >> >>+/*
> >> >>+ * =============================
> >> >>+ * == CPU suspend finisher ==
> >> >>+ * =============================
> >> >>+ *
> >> >>+ * void omap4_finish_suspend(unsigned long cpu_state)
> >> >>+ *
> >> >>+ * This function code saves the CPU context and performs the CPU
> >> >>+ * power down sequence. Calling WFI effectively changes the CPU
> >> >>+ * power domains states to the desired target power state.
> >> >>+ *
> >> >>+ * @cpu_state : contains context save state (r0)
> >> >>+ * 0 - No context lost
> >> >>+ *         1 - CPUx L1 and logic lost: MPUSS CSWR
> >> >>+ *         2 - CPUx L1 and logic lost + GIC lost: MPUSS OSWR
> >> >>+ * 3 - CPUx L1 and logic lost + GIC + L2 lost: MPUSS OFF
> >> >
> >> >I was told by rmk that same as imx6q, omap44xx will retain L2 content
> >> >across suspen/resume cycle.  Then what does "L2 lost" mean here?  Or
> >> >what rmk meant is the case cpu_state == 2?
> >> >
> >> Yes.
> >>
> >> The last case is entire SOC OFF. We call Device OFF in OMAP.
> >> All voltages will scale to 0 V. This isn't supported by this
> >> series.
> >>
> > Then the second question would be what the following patch in this
> > series is for.
> >
> >    [PATCH 20/25] OMAP4: PM: Add L2X0 cache lowpower support
> >
> > I could have read the patch incorrectly, but it seems l2x_clean_inv
> > will also be called for "MPUSS OSWR" in which case L2 is retained?
> > Shouldn't L2 for this case have been handled by rmk's patch (ARM: pm:
> > add L2 cache cleaning for suspend)?
> >
> Yes you did read it wrongly :)
> It won't be called for OSWR
> 
Come on, man.  It's really hard for me who is still at entry level of
assembly to understand that.  So please help me out.

The following is a copy from arch/arm/mach-omap2/sleep44xx.S after I
apply this patch series on v3.1-rc4.

> /*
>  * =============================
>  * == CPU suspend finisher ==
>  * =============================
>  *
>  * void omap4_finish_suspend(unsigned long cpu_state)
>  *
>  * This function code saves the CPU context and performs the CPU
>  * power down sequence. Calling WFI effectively changes the CPU
>  * power domains states to the desired target power state.
>  *
>  * @cpu_state : contains context save state (r0)

So cpu_state is passed in r0.

>  *	0 - No context lost
>  * 	1 - CPUx L1 and logic lost: MPUSS CSWR
>  * 	2 - CPUx L1 and logic lost + GIC lost: MPUSS OSWR
>  *	3 - CPUx L1 and logic lost + GIC + L2 lost: MPUSS OFF
>  * @return: This function never returns for CPU OFF and DORMANT power states.
>  * Post WFI, CPU transitions to DORMANT or OFF power state and on wake-up
>  * from this follows a full CPU reset path via ROM code to CPU restore code.
>  * It returns to the caller for CPU INACTIVE and ON power states or in case
>  * CPU failed to transition to targeted OFF/DORMANT state.
>  */
> ENTRY(omap4_finish_suspend)
> 	stmfd	sp!, {lr}
> 	cmp	r0, #0x0
> 	beq	do_WFI				@ No lowpower state, jump to WFI

The case "0" is handled here.

> 
> 	/*
> 	 * Flush all data from the L1 data cache before disabling
> 	 * SCTLR.C bit.
> 	 */
> 	bl	omap4_get_sar_ram_base

Isn't r0 lost here?

> 	ldr	r9, [r0, #OMAP_TYPE_OFFSET]
> 	cmp	r9, #0x1			@ Check for HS device
> 	bne	skip_secure_l1_clean
> 	mov	r0, #SCU_PM_NORMAL
> 	mov	r1, #0xFF			@ clean seucre L1
> 	stmfd   r13!, {r4-r12, r14}
> 	ldr	r12, =OMAP4_MON_SCU_PWR_INDEX
> 	DO_SMC
> 	ldmfd   r13!, {r4-r12, r14}
> skip_secure_l1_clean:
> 
> 	/*
> 	 * 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
> 
> 	/*
> 	 * Invalidate L1 data cache. Even though only invalidate is
> 	 * necessary exported flush API is used here. Doing clean
> 	 * on already clean cache would be almost NOP.
> 	 */
> 	bl	v7_flush_dcache_all
> 
> 	/*
> 	 * Switch the CPU from Symmetric Multiprocessing (SMP) mode
> 	 * to AsymmetricMultiprocessing (AMP) mode by programming
> 	 * the SCU power status to DORMANT or OFF mode.
> 	 * This enables the CPU to be taken out of coherency by
> 	 * preventing the CPU from receiving cache, TLB, or BTB
> 	 * maintenance operations broadcast by other CPUs in the cluster.
> 	 */
> 	bl	omap4_get_sar_ram_base
> 	mov	r8, r0
> 	ldr	r9, [r8, #OMAP_TYPE_OFFSET]
> 	cmp	r9, #0x1			@ Check for HS device
> 	bne	scu_gp_set
> 	mrc	p15, 0, r0, c0, c0, 5		@ Read MPIDR
> 	ands	r0, r0, #0x0f
> 	ldreq	r0, [r8, #SCU_OFFSET0]
> 	ldrne	r0, [r8, #SCU_OFFSET1]
> 	mov	r1, #0x00
> 	stmfd   r13!, {r4-r12, r14}
> 	ldr	r12, =OMAP4_MON_SCU_PWR_INDEX
> 	DO_SMC
> 	ldmfd   r13!, {r4-r12, r14}
> 	b	skip_scu_gp_set
> scu_gp_set:
> 	mrc	p15, 0, r0, c0, c0, 5		@ Read MPIDR
> 	ands	r0, r0, #0x0f
> 	ldreq	r1, [r8, #SCU_OFFSET0]
> 	ldrne	r1, [r8, #SCU_OFFSET1]
> 	bl	omap4_get_scu_base
> 	bl	scu_power_mode
> skip_scu_gp_set:
> 	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
> #ifdef CONFIG_CACHE_L2X0
> 	/*
> 	 * Clean and invalidate the L2 cache.
> 	 * Common cache-l2x0.c functions can't be used here since it
> 	 * uses spinlocks. We are out of coherency here with data cache
> 	 * disabled. The spinlock implementation uses exclusive load/store
> 	 * instruction which can fail without data cache being enabled.
> 	 * OMAP4 hardware doesn't support exclusive monitor which can
> 	 * overcome exclusive access issue. Because of this, CPU can
> 	 * lead to deadlock.
> 	 */
> l2x_clean_inv:
> 	bl	omap4_get_sar_ram_base
> 	mov	r8, r0
> 	mrc	p15, 0, r5, c0, c0, 5		@ Read MPIDR
> 	ands	r5, r5, #0x0f
> 	ldreq	r0, [r8, #L2X0_SAVE_OFFSET0]
> 	ldrne	r0, [r8, #L2X0_SAVE_OFFSET1]
> 	cmp	r0, #3
> 	bne	do_WFI

It looks like you are bypassing L2 clean and invalidate for cases
"1" and "2" here.  But I really do not understand how you get r0
back here.

Regards,
Shawn

> #ifdef CONFIG_PL310_ERRATA_727915
> 	mov	r0, #0x03
> 	mov	r12, #OMAP4_MON_L2X0_DBG_CTRL_INDEX
> 	DO_SMC
> #endif
> 	bl	omap4_get_l2cache_base
> 	mov	r2, r0
> 	ldr	r0, =0xffff
> 	str	r0, [r2, #L2X0_CLEAN_INV_WAY]
> wait:
> 	ldr	r0, [r2, #L2X0_CLEAN_INV_WAY]
> 	ldr	r1, =0xffff
> 	ands	r0, r0, r1
> 	bne	wait
> #ifdef CONFIG_PL310_ERRATA_727915
> 	mov	r0, #0x00
> 	mov	r12, #OMAP4_MON_L2X0_DBG_CTRL_INDEX
> 	DO_SMC
> #endif
> l2x_sync:
> 	bl	omap4_get_l2cache_base
> 	mov	r2, r0
> 	mov	r0, #0x0
> 	str	r0, [r2, #L2X0_CACHE_SYNC]
> sync:
> 	ldr	r0, [r2, #L2X0_CACHE_SYNC]
> 	ands	r0, r0, #0x1
> 	bne	sync
> #endif
> 
> do_WFI:
> 	bl	omap_do_wfi
> 
> 	/*
> 	 * CPU is here when it failed to enter OFF/DORMANT or
> 	 * no low power state was attempted.
> 	 */
> 	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
> 
> 	/*
> 	 * Ensure the CPU power state is set to NORMAL in
> 	 * SCU power state so that CPU is back in coherency.
> 	 * In non-coherent mode CPU can lock-up and lead to
> 	 * system deadlock.
> 	 */
> 	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
> 	bl	omap4_get_sar_ram_base
> 	mov	r8, r0
> 	ldr	r9, [r8, #OMAP_TYPE_OFFSET]
> 	cmp	r9, #0x1			@ Check for HS device
> 	bne	scu_gp_clear
> 	mov	r0, #SCU_PM_NORMAL
> 	mov	r1, #0x00
> 	stmfd   r13!, {r4-r12, r14}
> 	ldr	r12, =OMAP4_MON_SCU_PWR_INDEX
> 	DO_SMC
> 	ldmfd   r13!, {r4-r12, r14}
> 	b	skip_scu_gp_clear
> scu_gp_clear:
> 	bl	omap4_get_scu_base
> 	mov	r1, #SCU_PM_NORMAL
> 	bl	scu_power_mode
> skip_scu_gp_clear:
> 	isb
> 	dsb
> 	ldmfd	sp!, {pc}
> ENDPROC(omap4_finish_suspend)




More information about the linux-arm-kernel mailing list