aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Konovalov <andrey.konovalov@linaro.org>2013-10-18 20:43:01 +0400
committerAndrey Konovalov <andrey.konovalov@linaro.org>2013-10-18 20:43:01 +0400
commitb8c7f006b57591f1bb8b79f924a33fb935b3c072 (patch)
tree40d31b2f6fbf01bbabfe0ee04ab97bc97ac45fff
parent773644a260a289e3f65c6028bdde414e7d7897fb (diff)
parentcd2944d615cdf345d874e82fd966d1af891e63e1 (diff)
Merge branch 'tracking-ll-misc-fixes' into merge-linux-linaroll-20131018.0ll_20131018.0
-rw-r--r--arch/arm/mach-omap2/common.h6
-rw-r--r--arch/arm/mach-omap2/cpuidle44xx.c35
-rw-r--r--arch/arm/mach-omap2/omap-mpuss-lowpower.c14
-rw-r--r--arch/arm/mach-omap2/omap4-common.c6
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);