Commit 74ed7bdc authored by Strashko, Grygorii's avatar Strashko, Grygorii Committed by Olof Johansson

ARM: OMAP4460: cpuidle: Extend PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD on cpuidle

The same workaround as ff999b8a
"ARM: OMAP4460: Workaround for ROM bug because of CA9 r2pX GIC ..."
need to be applied not only when system is booting, but when MPUSS hits
OSWR state through CPUIdle too. Without this WA the same issue is
reproduced now on boards PandaES and Tablet/Blaze with SOM OMAP4460
when CONFIG_CPU_IDLE is enabled.
After MPUSS has enterred OSWR and waken up:
- GIC distributor became disabled forever
- scheduling is not performed any more

Cc: Kevin Hilman <khilman@linaro.org>
Acked-by: default avatarSantosh Shilimkar <santosh.shilimkar@ti.com>
Reported-by: default avatarTaras Kondratiuk <taras.kondratiuk@linaro.org>
Signed-off-by: default avatarGrygorii Strashko <grygorii.strashko@ti.com>
Acked-by: default avatarTony Lindgren <tony@atomide.com>
Signed-off-by: default avatarKevin Hilman <khilman@linaro.org>
Signed-off-by: default avatarOlof Johansson <olof@lixom.net>
parent e7651b81
...@@ -236,6 +236,7 @@ static inline void __iomem *omap4_get_scu_base(void) ...@@ -236,6 +236,7 @@ static inline void __iomem *omap4_get_scu_base(void)
extern void __init gic_init_irq(void); extern void __init gic_init_irq(void);
extern void gic_dist_disable(void); extern void gic_dist_disable(void);
extern void gic_dist_enable(void);
extern bool gic_dist_disabled(void); extern bool gic_dist_disabled(void);
extern void gic_timer_retrigger(void); extern void gic_timer_retrigger(void);
extern void omap_smc1(u32 fn, u32 arg); extern void omap_smc1(u32 fn, u32 arg);
......
...@@ -80,6 +80,7 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev, ...@@ -80,6 +80,7 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev,
int index) int index)
{ {
struct idle_statedata *cx = state_ptr + index; struct idle_statedata *cx = state_ptr + index;
u32 mpuss_can_lose_context = 0;
/* /*
* CPU0 has to wait and stay ON until CPU1 is OFF state. * CPU0 has to wait and stay ON until CPU1 is OFF state.
...@@ -104,6 +105,9 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev, ...@@ -104,6 +105,9 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev,
} }
} }
mpuss_can_lose_context = (cx->mpu_state == PWRDM_POWER_RET) &&
(cx->mpu_logic_state == PWRDM_POWER_OFF);
/* /*
* Call idle CPU PM enter notifier chain so that * Call idle CPU PM enter notifier chain so that
* VFP and per CPU interrupt context is saved. * VFP and per CPU interrupt context is saved.
...@@ -118,8 +122,7 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev, ...@@ -118,8 +122,7 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev,
* Call idle CPU cluster PM enter notifier chain * Call idle CPU cluster PM enter notifier chain
* to save GIC and wakeupgen context. * to save GIC and wakeupgen context.
*/ */
if ((cx->mpu_state == PWRDM_POWER_RET) && if (mpuss_can_lose_context)
(cx->mpu_logic_state == PWRDM_POWER_OFF))
cpu_cluster_pm_enter(); cpu_cluster_pm_enter();
} }
...@@ -128,9 +131,23 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev, ...@@ -128,9 +131,23 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev,
/* Wakeup CPU1 only if it is not offlined */ /* Wakeup CPU1 only if it is not offlined */
if (dev->cpu == 0 && cpumask_test_cpu(1, cpu_online_mask)) { if (dev->cpu == 0 && cpumask_test_cpu(1, cpu_online_mask)) {
if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD) &&
mpuss_can_lose_context)
gic_dist_disable();
clkdm_wakeup(cpu_clkdm[1]); clkdm_wakeup(cpu_clkdm[1]);
omap_set_pwrdm_state(cpu_pd[1], PWRDM_POWER_ON); omap_set_pwrdm_state(cpu_pd[1], PWRDM_POWER_ON);
clkdm_allow_idle(cpu_clkdm[1]); clkdm_allow_idle(cpu_clkdm[1]);
if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD) &&
mpuss_can_lose_context) {
while (gic_dist_disabled()) {
udelay(1);
cpu_relax();
}
gic_timer_retrigger();
}
} }
/* /*
...@@ -143,8 +160,7 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev, ...@@ -143,8 +160,7 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev,
* Call idle CPU cluster PM exit notifier chain * Call idle CPU cluster PM exit notifier chain
* to restore GIC and wakeupgen context. * to restore GIC and wakeupgen context.
*/ */
if (dev->cpu == 0 && (cx->mpu_state == PWRDM_POWER_RET) && if (dev->cpu == 0 && mpuss_can_lose_context)
(cx->mpu_logic_state == PWRDM_POWER_OFF))
cpu_cluster_pm_exit(); cpu_cluster_pm_exit();
fail: fail:
......
...@@ -271,6 +271,9 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) ...@@ -271,6 +271,9 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
else else
omap_pm_ops.finish_suspend(save_state); omap_pm_ops.finish_suspend(save_state);
if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD) && cpu)
gic_dist_enable();
/* /*
* Restore the CPUx power state to ON otherwise CPUx * Restore the CPUx power state to ON otherwise CPUx
* power domain can transitions to programmed low power * power domain can transitions to programmed low power
......
...@@ -127,6 +127,12 @@ void gic_dist_disable(void) ...@@ -127,6 +127,12 @@ void gic_dist_disable(void)
__raw_writel(0x0, gic_dist_base_addr + GIC_DIST_CTRL); __raw_writel(0x0, gic_dist_base_addr + GIC_DIST_CTRL);
} }
void gic_dist_enable(void)
{
if (gic_dist_base_addr)
__raw_writel(0x1, gic_dist_base_addr + GIC_DIST_CTRL);
}
bool gic_dist_disabled(void) bool gic_dist_disabled(void)
{ {
return !(__raw_readl(gic_dist_base_addr + GIC_DIST_CTRL) & 0x1); return !(__raw_readl(gic_dist_base_addr + GIC_DIST_CTRL) & 0x1);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment