From 9a0ac7c1c0a826a53cb20028d4adc74aedcef0bf Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Thu, 18 Oct 2012 12:20:08 +0300 Subject: [PATCH] --- yaml --- r: 339587 b: refs/heads/master c: cd8ce159031813eb870a5f3d5b27c3be36cd6e3a h: refs/heads/master i: 339585: afc33e22c330d129a0f11cbc91262546cdfbd60d 339583: b3c3d7f46ae8ac116f0e478cd37f6a2b87d87e06 v: v3 --- [refs] | 2 +- trunk/arch/arm/mach-omap2/common.h | 2 ++ trunk/arch/arm/mach-omap2/omap-smp.c | 13 ++++++++- trunk/arch/arm/mach-omap2/omap4-common.c | 34 ++++++++++++++++++++++++ 4 files changed, 49 insertions(+), 2 deletions(-) diff --git a/[refs] b/[refs] index a2a5e354b03a..135c8087d46a 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: ff999b8a0983ee15668394ed49e38d3568fc6859 +refs/heads/master: cd8ce159031813eb870a5f3d5b27c3be36cd6e3a diff --git a/trunk/arch/arm/mach-omap2/common.h b/trunk/arch/arm/mach-omap2/common.h index 70993a9fcb50..d29dbaa29621 100644 --- a/trunk/arch/arm/mach-omap2/common.h +++ b/trunk/arch/arm/mach-omap2/common.h @@ -276,6 +276,8 @@ static inline void __iomem *omap4_get_scu_base(void) extern void __init gic_init_irq(void); extern void gic_dist_disable(void); +extern bool gic_dist_disabled(void); +extern void gic_timer_retrigger(void); extern void omap_smc1(u32 fn, u32 arg); extern void __iomem *omap4_get_sar_ram_base(void); extern void omap_do_wfi(void); diff --git a/trunk/arch/arm/mach-omap2/omap-smp.c b/trunk/arch/arm/mach-omap2/omap-smp.c index 7d9c0e3fedc4..49a08dfe8d88 100644 --- a/trunk/arch/arm/mach-omap2/omap-smp.c +++ b/trunk/arch/arm/mach-omap2/omap-smp.c @@ -134,11 +134,22 @@ static int __cpuinit omap4_boot_secondary(unsigned int cpu, struct task_struct * * 2) CPU1 must re-enable the GIC distributor on * it's wakeup path. */ - if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD)) + if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD)) { + local_irq_disable(); gic_dist_disable(); + } clkdm_wakeup(cpu1_clkdm); clkdm_allow_idle(cpu1_clkdm); + + if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD)) { + while (gic_dist_disabled()) { + udelay(1); + cpu_relax(); + } + gic_timer_retrigger(); + local_irq_enable(); + } } else { dsb_sev(); booted = true; diff --git a/trunk/arch/arm/mach-omap2/omap4-common.c b/trunk/arch/arm/mach-omap2/omap4-common.c index 72cf396a0fc2..6f94b4e7b18d 100644 --- a/trunk/arch/arm/mach-omap2/omap4-common.c +++ b/trunk/arch/arm/mach-omap2/omap4-common.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -24,6 +25,7 @@ #include #include #include +#include #include #include @@ -42,6 +44,9 @@ static void __iomem *l2cache_base; static void __iomem *sar_ram_base; static void __iomem *gic_dist_base_addr; +static void __iomem *twd_base; + +#define IRQ_LOCALTIMER 29 #ifdef CONFIG_OMAP4_ERRATA_I688 /* Used to implement memory barrier on DRAM path */ @@ -101,6 +106,9 @@ void __init gic_init_irq(void) gic_dist_base_addr = ioremap(OMAP44XX_GIC_DIST_BASE, SZ_4K); BUG_ON(!gic_dist_base_addr); + twd_base = ioremap(OMAP44XX_LOCAL_TWD_BASE, SZ_4K); + BUG_ON(!twd_base); + /* Static mapping, never released */ omap_irq_base = ioremap(OMAP44XX_GIC_CPU_BASE, SZ_512); BUG_ON(!omap_irq_base); @@ -116,6 +124,32 @@ void gic_dist_disable(void) __raw_writel(0x0, gic_dist_base_addr + GIC_DIST_CTRL); } +bool gic_dist_disabled(void) +{ + return !(__raw_readl(gic_dist_base_addr + GIC_DIST_CTRL) & 0x1); +} + +void gic_timer_retrigger(void) +{ + u32 twd_int = __raw_readl(twd_base + TWD_TIMER_INTSTAT); + u32 gic_int = __raw_readl(gic_dist_base_addr + GIC_DIST_PENDING_SET); + u32 twd_ctrl = __raw_readl(twd_base + TWD_TIMER_CONTROL); + + if (twd_int && !(gic_int & BIT(IRQ_LOCALTIMER))) { + /* + * The local timer interrupt got lost while the distributor was + * disabled. Ack the pending interrupt, and retrigger it. + */ + pr_warn("%s: lost localtimer interrupt\n", __func__); + __raw_writel(1, twd_base + TWD_TIMER_INTSTAT); + if (!(twd_ctrl & TWD_TIMER_CONTROL_PERIODIC)) { + __raw_writel(1, twd_base + TWD_TIMER_COUNTER); + twd_ctrl |= TWD_TIMER_CONTROL_ENABLE; + __raw_writel(twd_ctrl, twd_base + TWD_TIMER_CONTROL); + } + } +} + #ifdef CONFIG_CACHE_L2X0 void __iomem *omap4_get_l2cache_base(void)