@@ -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 */
@@ -45,7 +45,7 @@ void platform_cpu_die(unsigned int cpu)
/*
* Execute WFI
*/
- do_wfi();
+ omap_do_wfi();
if (omap_read_auxcoreboot0() == cpu) {
/*
@@ -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;
}
@@ -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)
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@ti.com> Cc: Kevin Hilman <khilman@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(-)