diff mbox

[v2,08/18] ARM: OMAP5: PM: Add CPU power off in hotplug path

Message ID 1364205910-32392-9-git-send-email-santosh.shilimkar@ti.com (mailing list archive)
State New, archived
Headers show

Commit Message

Santosh Shilimkar March 25, 2013, 10:05 a.m. UTC
Add power management code to handle the CPU off mode to enable CPUP hotplug
mode for OMAP5 devices. 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.

Acked-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
---
 arch/arm/mach-omap2/omap-mpuss-lowpower.c |   30 ++++++++---
 arch/arm/mach-omap2/omap-secure.h         |    1 +
 arch/arm/mach-omap2/omap4-sar-layout.h    |    2 +
 arch/arm/mach-omap2/sleep_omap4plus.S     |   84 +++++++++++++++++++++++++++++
 4 files changed, 110 insertions(+), 7 deletions(-)

Comments

Kevin Hilman April 3, 2013, 8:49 p.m. UTC | #1
Santosh Shilimkar <santosh.shilimkar@ti.com> writes:

> Add power management code to handle the CPU off mode to enable CPUP hotplug
> mode for OMAP5 devices. 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.
>
> Acked-by: Nishanth Menon <nm@ti.com>
> Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>

[...]

> @@ -436,14 +445,21 @@ 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;
>  		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();
>  	}
>  
> +	/* Over-write the OMAP4 hook to take care of ROM BUG */
> +	if (cpu_is_omap446x())
> +		omap_pm_ops.hotplug_restart = omap_secondary_startup_4460;

A couple nits...

I think this would go better at the end of the 'if omap44xx' block
above.

Also, while you're hear, maybe it's time to rename the current secondary 
startup functions to match the new one.  IOW omap4_..., omap4460_... and omap5_...

Kevin
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Santosh Shilimkar April 4, 2013, 1:23 p.m. UTC | #2
On Thursday 04 April 2013 02:19 AM, Kevin Hilman wrote:
> Santosh Shilimkar <santosh.shilimkar@ti.com> writes:
> 
>> Add power management code to handle the CPU off mode to enable CPUP hotplug
>> mode for OMAP5 devices. 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.
>>
>> Acked-by: Nishanth Menon <nm@ti.com>
>> Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
> 
> [...]
> 
>> @@ -436,14 +445,21 @@ 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;
>>  		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();
>>  	}
>>  
>> +	/* Over-write the OMAP4 hook to take care of ROM BUG */
>> +	if (cpu_is_omap446x())
>> +		omap_pm_ops.hotplug_restart = omap_secondary_startup_4460;
> 
> A couple nits...
> 
> I think this would go better at the end of the 'if omap44xx' block
> above.
> 
Nishant commented on this as well. The indentation was looking ugly
and I thought its better to have this BUG hunk separate. I prefer
it this way though if you really insist, i have to change it.

> Also, while you're hear, maybe it's time to rename the current secondary 
> startup functions to match the new one.  IOW omap4_..., omap4460_... and omap5_...
> 
Good idea. Will do it in a separate patch since these have been there in few
files.

Regards,
Santosh

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Kevin Hilman April 4, 2013, 5:31 p.m. UTC | #3
Santosh Shilimkar <santosh.shilimkar@ti.com> writes:

> On Thursday 04 April 2013 02:19 AM, Kevin Hilman wrote:
>> Santosh Shilimkar <santosh.shilimkar@ti.com> writes:
>> 
>>> Add power management code to handle the CPU off mode to enable CPUP hotplug
>>> mode for OMAP5 devices. 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.
>>>
>>> Acked-by: Nishanth Menon <nm@ti.com>
>>> Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
>> 
>> [...]
>> 
>>> @@ -436,14 +445,21 @@ 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;
>>>  		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();
>>>  	}
>>>  
>>> +	/* Over-write the OMAP4 hook to take care of ROM BUG */
>>> +	if (cpu_is_omap446x())
>>> +		omap_pm_ops.hotplug_restart = omap_secondary_startup_4460;
>> 
>> A couple nits...
>> 
>> I think this would go better at the end of the 'if omap44xx' block
>> above.
>> 
> Nishant commented on this as well. The indentation was looking ugly
> and I thought its better to have this BUG hunk separate. I prefer
> it this way though if you really insist, i have to change it.

I insist.

>> Also, while you're hear, maybe it's time to rename the current secondary 
>> startup functions to match the new one.  IOW omap4_..., omap4460_... and omap5_...
>> 
> Good idea. Will do it in a separate patch since these have been there in few
> files.

OK.

Thanks,

Kevin
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Santosh Shilimkar April 5, 2013, 9:04 a.m. UTC | #4
On Thursday 04 April 2013 11:01 PM, Kevin Hilman wrote:
> Santosh Shilimkar <santosh.shilimkar@ti.com> writes:
> 
>> On Thursday 04 April 2013 02:19 AM, Kevin Hilman wrote:
>>> Santosh Shilimkar <santosh.shilimkar@ti.com> writes:
>>>
>>>> Add power management code to handle the CPU off mode to enable CPUP hotplug
>>>> mode for OMAP5 devices. 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.
>>>>
>>>> Acked-by: Nishanth Menon <nm@ti.com>
>>>> Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
>>>
>>> [...]
>>>
>>>> @@ -436,14 +445,21 @@ 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;
>>>>  		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();
>>>>  	}
>>>>  
>>>> +	/* Over-write the OMAP4 hook to take care of ROM BUG */
>>>> +	if (cpu_is_omap446x())
>>>> +		omap_pm_ops.hotplug_restart = omap_secondary_startup_4460;
>>>
>>> A couple nits...
>>>
>>> I think this would go better at the end of the 'if omap44xx' block
>>> above.
>>>
>> Nishant commented on this as well. The indentation was looking ugly
>> and I thought its better to have this BUG hunk separate. I prefer
>> it this way though if you really insist, i have to change it.
> 
> I insist.
> 
Will update the patch accordingly then.

Regards,
Santosh

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/arch/arm/mach-omap2/omap-mpuss-lowpower.c b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
index d390d18..096f489 100644
--- a/arch/arm/mach-omap2/omap-mpuss-lowpower.c
+++ b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
@@ -81,6 +81,7 @@  struct omap4_cpu_pm_info {
  * @finish_suspend:	CPU suspend finisher function pointer
  * @resume:		CPU resume function pointer
  * @scu_prepare:	CPU Snoop Control program function pointer
+ * @hotplug_restart:	CPU hotplug restart kernel hook pointer
  *
  * Structure holds functions pointer for CPU low power operations like
  * suspend, resume and scu programming.
@@ -89,10 +90,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;
@@ -115,6 +118,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,
 };
 
 /*
@@ -327,7 +331,7 @@  int __cpuinit omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state)
 
 	pwrdm_clear_all_prev_pwrst(pm_info->pwrdm);
 	pwrdm_set_next_pwrst(pm_info->pwrdm, 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);
 
 	/*
@@ -370,6 +374,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");
@@ -379,9 +384,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) {
@@ -396,14 +405,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) {
@@ -436,14 +445,21 @@  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;
 		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();
 	}
 
+	/* Over-write the OMAP4 hook to take care of ROM BUG */
+	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 792b106..5b2966a 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..5a372a6 100644
--- a/arch/arm/mach-omap2/sleep_omap4plus.S
+++ b/arch/arm/mach-omap2/sleep_omap4plus.S
@@ -326,6 +326,90 @@  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
+ */
+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. Since we modify stack here, we must clean and
+	 * invalidate the local cache here to avoid stack corruption.
+	 */
+	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.
+	 */
+	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 all data from the L1 data cache. The L2
+	 * duplicate snoop tag RAM for this processor is now empty. This
+	 * prevents any new data cache snoops or data cache maintenance
+	 * operations from other processors in the MPCore device being
+	 * issued to this processor.
+	 */
+	bl	v7_flush_dcache_louis
+
+	/*
+	 * 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
+
+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
+	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