[PATCH 03/25] OMAP4: PM: Use custom omap_do_wfi() for suspend and default idle.

Santosh Shilimkar santosh.shilimkar at ti.com
Sun Sep 4 09:54:04 EDT 2011


The omap_do_wfi() incorporates interconnect barriers to meet
OMAP44XX interconnect ordering requirements. Make use of this
hook in default idle, suspend and CPU hot-plug paths.

Without the interconnect barriers, many issues have been observed
leading to system freeze, CPU deadlocks, random crashes with
register accesses, synchronization loss on initiators operating
on both interconnect port simultaneously.

Signed-off-by: Santosh Shilimkar <santosh.shilimkar at ti.com>
Cc: Kevin Hilman <khilman at ti.com>
---
 arch/arm/mach-omap2/include/mach/omap4-common.h |    1 +
 arch/arm/mach-omap2/omap-hotplug.c              |    2 +-
 arch/arm/mach-omap2/pm44xx.c                    |   22 ++++++++++-
 arch/arm/mach-omap2/sleep44xx.S                 |   47 +++++++++++++++++++++++
 4 files changed, 70 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-omap2/include/mach/omap4-common.h b/arch/arm/mach-omap2/include/mach/omap4-common.h
index 26653f6..62d8d07 100644
--- a/arch/arm/mach-omap2/include/mach/omap4-common.h
+++ b/arch/arm/mach-omap2/include/mach/omap4-common.h
@@ -38,6 +38,7 @@ extern void __init gic_init_irq(void);
 extern void omap_smc1(u32 fn, u32 arg);
 extern void omap_bus_sync(void);
 extern unsigned long omap_get_dram_barrier_base(void);
+extern void omap_do_wfi(void);
 
 #ifdef CONFIG_SMP
 /* Needed for secondary core boot */
diff --git a/arch/arm/mach-omap2/omap-hotplug.c b/arch/arm/mach-omap2/omap-hotplug.c
index 4976b93..80167ec 100644
--- a/arch/arm/mach-omap2/omap-hotplug.c
+++ b/arch/arm/mach-omap2/omap-hotplug.c
@@ -45,7 +45,7 @@ void platform_cpu_die(unsigned int cpu)
 		/*
 		 * Execute WFI
 		 */
-		do_wfi();
+		omap_do_wfi();
 
 		if (omap_read_auxcoreboot0() == cpu) {
 			/*
diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
index 59a870b..4bbc6fe 100644
--- a/arch/arm/mach-omap2/pm44xx.c
+++ b/arch/arm/mach-omap2/pm44xx.c
@@ -33,7 +33,7 @@ static LIST_HEAD(pwrst_list);
 #ifdef CONFIG_SUSPEND
 static int omap4_pm_suspend(void)
 {
-	do_wfi();
+	omap_do_wfi();
 	return 0;
 }
 
@@ -91,6 +91,23 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
 }
 
 /**
+ * omap_default_idle -
+ * 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
  *
  * Initializes all powerdomain and clockdomain target states
@@ -115,6 +132,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;
 }
diff --git a/arch/arm/mach-omap2/sleep44xx.S b/arch/arm/mach-omap2/sleep44xx.S
index 5406713..049f426 100644
--- a/arch/arm/mach-omap2/sleep44xx.S
+++ b/arch/arm/mach-omap2/sleep44xx.S
@@ -27,3 +27,50 @@ ENTRY(omap_bus_sync)
 	isb
 	ldmfd	sp!, {pc}
 ENDPROC(omap_bus_sync)
+
+ENTRY(omap_do_wfi)
+	stmfd	sp!, {lr}
+	/* Drain interconnect write buffers. */
+	bl omap_bus_sync
+
+	/*
+	 * Execute an ISB instruction to ensure that all of the
+	 * CP15 register changes have been committed.
+	 */
+	isb
+
+	/*
+	 * Execute a barrier instruction to ensure that all cache,
+	 * TLB and branch predictor maintenance operations issued
+	 * by any CPU in the cluster have completed.
+	 */
+	dsb
+	dmb
+
+	/*
+	 * Execute a WFI instruction and wait until the
+	 * STANDBYWFI output is asserted to indicate that the
+	 * CPU is in idle and low power state. CPU can specualatively
+	 * prefetch the instructions so add NOPs after WFI. Sixteen
+	 * NOPs as per Cortex-A9 pipeline.
+	 */
+	wfi					@ Wait For Interrupt
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+
+	ldmfd	sp!, {pc}
+ENDPROC(omap_do_wfi)
-- 
1.7.4.1




More information about the linux-arm-kernel mailing list