aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2012-10-18 05:20:08 -0400
committerKevin Hilman <khilman@ti.com>2012-11-05 17:26:43 -0500
commitcd8ce159031813eb870a5f3d5b27c3be36cd6e3a (patch)
treedeaa9a4ccac205b288aff709f39c0b622d0b91b7 /arch/arm/mach-omap2
parentff999b8a0983ee15668394ed49e38d3568fc6859 (diff)
ARM: OMAP4: retrigger localtimers after re-enabling gic
'Workaround for ROM bug because of CA9 r2pX gic control' register change disables the gic distributor while the secondary cpu is being booted. If a localtimer interrupt on the primary cpu occurs when the distributor is turned off, the interrupt is lost, and the localtimer never fires again. Make the primary cpu wait for the secondary cpu to reenable the gic distributor (with interrupts off for safety), and then check if the pending bit is set in the localtimer but not the gic. If so, ack it in the localtimer, and reset the timer with the minimum timeout to trigger a new timer interrupt. Signed-off-by: Colin Cross <ccross@android.com> [s-jan@ti.com: adapted to k3.4 + validated functionality] Signed-off-by: Sebastien Jan <s-jan@ti.com> [t-kristo@ti.com: dropped generic ARM kernel exports from the code, rebased to mainline] Signed-off-by: Tero Kristo <t-kristo@ti.com> Signed-off-by: Kevin Hilman <khilman@ti.com>
Diffstat (limited to 'arch/arm/mach-omap2')
-rw-r--r--arch/arm/mach-omap2/common.h2
-rw-r--r--arch/arm/mach-omap2/omap-smp.c13
-rw-r--r--arch/arm/mach-omap2/omap4-common.c34
3 files changed, 48 insertions, 1 deletions
diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h
index 70993a9fcb50..d29dbaa29621 100644
--- a/arch/arm/mach-omap2/common.h
+++ b/arch/arm/mach-omap2/common.h
@@ -276,6 +276,8 @@ static inline void __iomem *omap4_get_scu_base(void)
276 276
277extern void __init gic_init_irq(void); 277extern void __init gic_init_irq(void);
278extern void gic_dist_disable(void); 278extern void gic_dist_disable(void);
279extern bool gic_dist_disabled(void);
280extern void gic_timer_retrigger(void);
279extern void omap_smc1(u32 fn, u32 arg); 281extern void omap_smc1(u32 fn, u32 arg);
280extern void __iomem *omap4_get_sar_ram_base(void); 282extern void __iomem *omap4_get_sar_ram_base(void);
281extern void omap_do_wfi(void); 283extern void omap_do_wfi(void);
diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c
index 7d9c0e3fedc4..49a08dfe8d88 100644
--- a/arch/arm/mach-omap2/omap-smp.c
+++ b/arch/arm/mach-omap2/omap-smp.c
@@ -134,11 +134,22 @@ static int __cpuinit omap4_boot_secondary(unsigned int cpu, struct task_struct *
134 * 2) CPU1 must re-enable the GIC distributor on 134 * 2) CPU1 must re-enable the GIC distributor on
135 * it's wakeup path. 135 * it's wakeup path.
136 */ 136 */
137 if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD)) 137 if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD)) {
138 local_irq_disable();
138 gic_dist_disable(); 139 gic_dist_disable();
140 }
139 141
140 clkdm_wakeup(cpu1_clkdm); 142 clkdm_wakeup(cpu1_clkdm);
141 clkdm_allow_idle(cpu1_clkdm); 143 clkdm_allow_idle(cpu1_clkdm);
144
145 if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD)) {
146 while (gic_dist_disabled()) {
147 udelay(1);
148 cpu_relax();
149 }
150 gic_timer_retrigger();
151 local_irq_enable();
152 }
142 } else { 153 } else {
143 dsb_sev(); 154 dsb_sev();
144 booted = true; 155 booted = true;
diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c
index 72cf396a0fc2..6f94b4e7b18d 100644
--- a/arch/arm/mach-omap2/omap4-common.c
+++ b/arch/arm/mach-omap2/omap4-common.c
@@ -14,6 +14,7 @@
14#include <linux/kernel.h> 14#include <linux/kernel.h>
15#include <linux/init.h> 15#include <linux/init.h>
16#include <linux/io.h> 16#include <linux/io.h>
17#include <linux/irq.h>
17#include <linux/platform_device.h> 18#include <linux/platform_device.h>
18#include <linux/memblock.h> 19#include <linux/memblock.h>
19#include <linux/of_irq.h> 20#include <linux/of_irq.h>
@@ -24,6 +25,7 @@
24#include <asm/hardware/cache-l2x0.h> 25#include <asm/hardware/cache-l2x0.h>
25#include <asm/mach/map.h> 26#include <asm/mach/map.h>
26#include <asm/memblock.h> 27#include <asm/memblock.h>
28#include <asm/smp_twd.h>
27 29
28#include <plat/sram.h> 30#include <plat/sram.h>
29#include <plat/omap-secure.h> 31#include <plat/omap-secure.h>
@@ -42,6 +44,9 @@ static void __iomem *l2cache_base;
42 44
43static void __iomem *sar_ram_base; 45static void __iomem *sar_ram_base;
44static void __iomem *gic_dist_base_addr; 46static void __iomem *gic_dist_base_addr;
47static void __iomem *twd_base;
48
49#define IRQ_LOCALTIMER 29
45 50
46#ifdef CONFIG_OMAP4_ERRATA_I688 51#ifdef CONFIG_OMAP4_ERRATA_I688
47/* Used to implement memory barrier on DRAM path */ 52/* Used to implement memory barrier on DRAM path */
@@ -101,6 +106,9 @@ void __init gic_init_irq(void)
101 gic_dist_base_addr = ioremap(OMAP44XX_GIC_DIST_BASE, SZ_4K); 106 gic_dist_base_addr = ioremap(OMAP44XX_GIC_DIST_BASE, SZ_4K);
102 BUG_ON(!gic_dist_base_addr); 107 BUG_ON(!gic_dist_base_addr);
103 108
109 twd_base = ioremap(OMAP44XX_LOCAL_TWD_BASE, SZ_4K);
110 BUG_ON(!twd_base);
111
104 /* Static mapping, never released */ 112 /* Static mapping, never released */
105 omap_irq_base = ioremap(OMAP44XX_GIC_CPU_BASE, SZ_512); 113 omap_irq_base = ioremap(OMAP44XX_GIC_CPU_BASE, SZ_512);
106 BUG_ON(!omap_irq_base); 114 BUG_ON(!omap_irq_base);
@@ -116,6 +124,32 @@ void gic_dist_disable(void)
116 __raw_writel(0x0, gic_dist_base_addr + GIC_DIST_CTRL); 124 __raw_writel(0x0, gic_dist_base_addr + GIC_DIST_CTRL);
117} 125}
118 126
127bool gic_dist_disabled(void)
128{
129 return !(__raw_readl(gic_dist_base_addr + GIC_DIST_CTRL) & 0x1);
130}
131
132void gic_timer_retrigger(void)
133{
134 u32 twd_int = __raw_readl(twd_base + TWD_TIMER_INTSTAT);
135 u32 gic_int = __raw_readl(gic_dist_base_addr + GIC_DIST_PENDING_SET);
136 u32 twd_ctrl = __raw_readl(twd_base + TWD_TIMER_CONTROL);
137
138 if (twd_int && !(gic_int & BIT(IRQ_LOCALTIMER))) {
139 /*
140 * The local timer interrupt got lost while the distributor was
141 * disabled. Ack the pending interrupt, and retrigger it.
142 */
143 pr_warn("%s: lost localtimer interrupt\n", __func__);
144 __raw_writel(1, twd_base + TWD_TIMER_INTSTAT);
145 if (!(twd_ctrl & TWD_TIMER_CONTROL_PERIODIC)) {
146 __raw_writel(1, twd_base + TWD_TIMER_COUNTER);
147 twd_ctrl |= TWD_TIMER_CONTROL_ENABLE;
148 __raw_writel(twd_ctrl, twd_base + TWD_TIMER_CONTROL);
149 }
150 }
151}
152
119#ifdef CONFIG_CACHE_L2X0 153#ifdef CONFIG_CACHE_L2X0
120 154
121void __iomem *omap4_get_l2cache_base(void) 155void __iomem *omap4_get_l2cache_base(void)