public inbox for linux-arm-kernel@lists.infradead.org
 help / color / mirror / Atom feed
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

  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