From ff999b8a0983ee15668394ed49e38d3568fc6859 Mon Sep 17 00:00:00 2001 From: Santosh Shilimkar Date: Thu, 18 Oct 2012 12:20:05 +0300 Subject: ARM: OMAP4460: Workaround for ROM bug because of CA9 r2pX GIC control register change. On OMAP4+ devices, GIC register context is lost when MPUSS hits the OSWR(Open Switch Retention). On the CPU wakeup path, ROM code gets executed and one of the steps in it is to restore the saved context of the GIC. The ROM Code GIC distributor restoration is split in two parts: CPU specific register done by each CPU and common register done by only one CPU. Below is the abstract flow. ............................................................... - MPUSS in OSWR state. - CPU0 wakes up on the event(interrupt) and start executing ROM code. [..] - CPU0 executes "GIC Restoration:" [...] - CPU0 swicthes to non-secure mode and jumps to OS resume code. [...] - CPU0 is online in OS - CPU0 enables the GIC distributor. GICD.Enable Non-secure = 1 - CPU0 wakes up CPU1 with clock-domain force wakeup method. - CPU0 continues it's execution. [..] - CPU1 wakes up and start executing ROM code. [..] - CPU1 executes "GIC Restoration:" [..] - CPU1 swicthes to non-secure mode and jumps to OS resume code. [...] - CPU1 is online in OS and start executing. [...] - GIC Restoration: /* Common routine for HS and GP devices */ { if (GICD != 1) { /* This will be true in OSWR state */ if (GIC_SAR_BACKUP_STATE == SAVED) - CPU restores GIC distributor else - reconfigure GIC distributor to boot values. GICD.Enable secure = 1 } if (GIC_SAR_BACKUP_STATE == SAVED) - CPU restore its GIC CPU interface registers if saved. else - reconfigure its GIC CPU interface registers to boot values. } ............................................................... So as mentioned in the flow, GICD != 1 condition decides how the GIC registers are handled in ROM code wakeup path from OSWR. As evident from the flow, ROM code relies on the entire GICD register value and not specific register bits. The assumption was valid till CortexA9 r1pX version since there was only one banked bit to control secure and non-secure GICD. Secure view which ROM code sees: bit 0 == Enable Non-secure Non-secure view which HLOS sees: bit 0 == Enable secure But GICD register has changed between CortexA9 r1pX and r2pX. On r2pX GICD register is composed of 2 bits. Secure view which ROM code sees: bit 1 == Enable Non-secure bit 0 == Enable secure Non-secure view which HLOS sees: bit 0 == Enable Non-secure Hence on OMAP4460(r2pX) devices, if you go through the above flow again during CPU1 wakeup, GICD == 3 and hence ROM code fails to understand the real wakeup power state and reconfigures GIC distributor to boot values. This is nasty since you loose the entire interrupt controller context in a live system. The ROM code fix done on next OMAP4 device (OMAP4470 - r2px) is to check "GICD.Enable secure != 1" for GIC restoration in OSWR wakeup path. Since ROM code can't be fixed on OMAP4460 devices, a work around needs to be implemented. As evident from the flow, as long as CPU1 sees GICD == 1 in it's wakeup path from OSWR, the issue won't happen. Below is the flow with the work-around. ............................................................... - MPUSS in OSWR state. - CPU0 wakes up on the event(interrupt) and start executing ROM code. [..] - CPU0 executes "GIC Restoration:" [..] - CPU0 swicthes to non-secure mode and jumps to OS resume code. [..] - CPU0 is online in OS. - CPU0 does GICD.Enable Non-secure = 0 - CPU0 wakes up CPU1 with clock domain force wakeup method. - CPU0 waits for GICD.Enable Non-secure = 1 - CPU0 coninues it's execution. [..] - CPU1 wakes up and start executing ROM code. [..] - CPU1 executes "GIC Restoration:" [..] - CPU1 swicthes to non-secure mode and jumps to OS resume code. [..] - CPU1 is online in OS - CPU1 does GICD.Enable Non-secure = 1 - CPU1 start executing [...] ............................................................... With this procedure, the GIC configuration done between the CPU0 wakeup and CPU1 wakeup will not be lost but during this short windows, the CPU0 will not receive interrupts. The BUG is applicable to only OMAP4460(r2pX) devices. OMAP4470 (also r2pX) is not affected by this bug because ROM code has been fixed. Signed-off-by: Santosh Shilimkar Signed-off-by: Tero Kristo Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/common.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/arm/mach-omap2/common.h') diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h index 7045e4d61ac3..70993a9fcb50 100644 --- a/arch/arm/mach-omap2/common.h +++ b/arch/arm/mach-omap2/common.h @@ -275,6 +275,7 @@ static inline void __iomem *omap4_get_scu_base(void) #endif extern void __init gic_init_irq(void); +extern void gic_dist_disable(void); extern void omap_smc1(u32 fn, u32 arg); extern void __iomem *omap4_get_sar_ram_base(void); extern void omap_do_wfi(void); @@ -282,6 +283,7 @@ extern void omap_do_wfi(void); #ifdef CONFIG_SMP /* Needed for secondary core boot */ extern void omap_secondary_startup(void); +extern void omap_secondary_startup_4460(void); extern u32 omap_modify_auxcoreboot0(u32 set_mask, u32 clear_mask); extern void omap_auxcoreboot_addr(u32 cpu_addr); extern u32 omap_read_auxcoreboot0(void); -- cgit v1.2.1