diff options
author | Andrey Konovalov <andrey.konovalov@linaro.org> | 2013-10-18 20:43:01 +0400 |
---|---|---|
committer | Andrey Konovalov <andrey.konovalov@linaro.org> | 2013-10-18 20:43:01 +0400 |
commit | b8c7f006b57591f1bb8b79f924a33fb935b3c072 (patch) | |
tree | 40d31b2f6fbf01bbabfe0ee04ab97bc97ac45fff | |
parent | 773644a260a289e3f65c6028bdde414e7d7897fb (diff) | |
parent | cd2944d615cdf345d874e82fd966d1af891e63e1 (diff) |
Merge branch 'tracking-ll-misc-fixes' into merge-linux-linaroll-20131018.0
-rw-r--r-- | arch/arm/mach-omap2/common.h | 6 | ||||
-rw-r--r-- | arch/arm/mach-omap2/cpuidle44xx.c | 35 | ||||
-rw-r--r-- | arch/arm/mach-omap2/omap-mpuss-lowpower.c | 14 | ||||
-rw-r--r-- | arch/arm/mach-omap2/omap4-common.c | 6 |
4 files changed, 59 insertions, 2 deletions
diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h index 4a5684b96492..795711010eb6 100644 --- a/arch/arm/mach-omap2/common.h +++ b/arch/arm/mach-omap2/common.h @@ -232,6 +232,7 @@ static inline void __iomem *omap4_get_scu_base(void) extern void __init gic_init_irq(void); extern void gic_dist_disable(void); +extern void gic_dist_enable(void); extern bool gic_dist_disabled(void); extern void gic_timer_retrigger(void); extern void omap_smc1(u32 fn, u32 arg); @@ -259,6 +260,7 @@ extern int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state); extern int omap4_finish_suspend(unsigned long cpu_state); extern void omap4_cpu_resume(void); extern int omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state); +extern u32 omap4_mpuss_read_prev_context_state(void); #else static inline int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) @@ -286,6 +288,10 @@ static inline int omap4_finish_suspend(unsigned long cpu_state) static inline void omap4_cpu_resume(void) {} +static inline u32 omap4_mpuss_read_prev_context_state(void) +{ + return 0; +} #endif struct omap_sdrc_params; diff --git a/arch/arm/mach-omap2/cpuidle44xx.c b/arch/arm/mach-omap2/cpuidle44xx.c index 4c8982ae9529..528638bf195a 100644 --- a/arch/arm/mach-omap2/cpuidle44xx.c +++ b/arch/arm/mach-omap2/cpuidle44xx.c @@ -80,6 +80,7 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev, int index) { struct idle_statedata *cx = state_ptr + index; + u32 mpuss_context_lost = 0; /* * CPU0 has to wait and stay ON until CPU1 is OFF state. @@ -126,13 +127,44 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev, omap4_enter_lowpower(dev->cpu, cx->cpu_state); cpu_done[dev->cpu] = true; + mpuss_context_lost = omap4_mpuss_read_prev_context_state(); + /* Wakeup CPU1 only if it is not offlined */ if (dev->cpu == 0 && cpumask_test_cpu(1, cpu_online_mask)) { + /* + * GIC distributor control register has changed between + * CortexA9 r1pX and r2pX. The Control Register secure + * banked version is now composed of 2 bits: + * bit 0 == Secure Enable + * bit 1 == Non-Secure Enable + * The Non-Secure banked register has not changed + * Because the ROM Code is based on the r1pX GIC, the CPU1 + * GIC restoration will cause a problem to CPU0 Non-Secure SW. + * The workaround must be: + * 1) Before doing the CPU1 wakeup, CPU0 must disable + * the GIC distributor and wait until it will be enabled by CPU1 + * 2) CPU1 must re-enable the GIC distributor on + * it's wakeup path. + */ + if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD) && + mpuss_context_lost) + gic_dist_disable(); + clkdm_wakeup(cpu_clkdm[1]); omap_set_pwrdm_state(cpu_pd[1], PWRDM_POWER_ON); clkdm_allow_idle(cpu_clkdm[1]); + + if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD) && + mpuss_context_lost) + while (gic_dist_disabled()) { + udelay(1); + cpu_relax(); + } } + if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD) && dev->cpu) + gic_dist_enable(); + /* * Call idle CPU PM exit notifier chain to restore * VFP and per CPU IRQ context. @@ -143,8 +175,7 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev, * Call idle CPU cluster PM exit notifier chain * to restore GIC and wakeupgen context. */ - if (dev->cpu == 0 && (cx->mpu_state == PWRDM_POWER_RET) && - (cx->mpu_logic_state == PWRDM_POWER_OFF)) + if (dev->cpu == 0 && mpuss_context_lost) cpu_cluster_pm_exit(); fail: diff --git a/arch/arm/mach-omap2/omap-mpuss-lowpower.c b/arch/arm/mach-omap2/omap-mpuss-lowpower.c index 63582577205a..16c00c2c707c 100644 --- a/arch/arm/mach-omap2/omap-mpuss-lowpower.c +++ b/arch/arm/mach-omap2/omap-mpuss-lowpower.c @@ -172,6 +172,20 @@ static inline void cpu_clear_prev_logic_pwrst(unsigned int cpu_id) } } +/** + * omap4_mpuss_read_prev_context_state: + * Function returns the MPUSS previous context state + */ +u32 omap4_mpuss_read_prev_context_state(void) +{ + u32 reg; + + reg = omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION, + OMAP4430_PRM_MPU_INST, OMAP4_RM_MPU_MPU_CONTEXT_OFFSET); + reg &= OMAP4430_LOSTCONTEXT_DFF_MASK; + return reg; +} + /* * Store the CPU cluster state for L2X0 low power operations. */ diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c index 2840d1e67a09..9ee15d7c8aab 100644 --- a/arch/arm/mach-omap2/omap4-common.c +++ b/arch/arm/mach-omap2/omap4-common.c @@ -128,6 +128,12 @@ void gic_dist_disable(void) writel_relaxed(0x0, gic_dist_base_addr + GIC_DIST_CTRL); } +void gic_dist_enable(void) +{ + if (gic_dist_base_addr) + writel_relaxed(0x1, gic_dist_base_addr + GIC_DIST_CTRL); +} + bool gic_dist_disabled(void) { return !(readl_relaxed(gic_dist_base_addr + GIC_DIST_CTRL) & 0x1); |