diff options
Diffstat (limited to 'arch/arm/mach-omap2/omap-wakeupgen.c')
| -rw-r--r-- | arch/arm/mach-omap2/omap-wakeupgen.c | 233 |
1 files changed, 151 insertions, 82 deletions
diff --git a/arch/arm/mach-omap2/omap-wakeupgen.c b/arch/arm/mach-omap2/omap-wakeupgen.c index d3d8971d7f3..37843a7d363 100644 --- a/arch/arm/mach-omap2/omap-wakeupgen.c +++ b/arch/arm/mach-omap2/omap-wakeupgen.c @@ -24,55 +24,55 @@ #include <linux/cpu.h> #include <linux/notifier.h> #include <linux/cpu_pm.h> +#include <linux/irqchip/arm-gic.h> -#include <asm/hardware/gic.h> - -#include <mach/omap-wakeupgen.h> -#include <mach/omap-secure.h> +#include "omap-wakeupgen.h" +#include "omap-secure.h" +#include "soc.h" #include "omap4-sar-layout.h" #include "common.h" -#define NR_REG_BANKS 4 -#define MAX_IRQS 128 +#define AM43XX_NR_REG_BANKS 7 +#define AM43XX_IRQS 224 +#define MAX_NR_REG_BANKS AM43XX_NR_REG_BANKS +#define MAX_IRQS AM43XX_IRQS +#define DEFAULT_NR_REG_BANKS 5 +#define DEFAULT_IRQS 160 #define WKG_MASK_ALL 0x00000000 #define WKG_UNMASK_ALL 0xffffffff #define CPU_ENA_OFFSET 0x400 #define CPU0_ID 0x0 #define CPU1_ID 0x1 +#define OMAP4_NR_BANKS 4 +#define OMAP4_NR_IRQS 128 static void __iomem *wakeupgen_base; static void __iomem *sar_base; -static DEFINE_PER_CPU(u32 [NR_REG_BANKS], irqmasks); -static DEFINE_SPINLOCK(wakeupgen_lock); -static unsigned int irq_target_cpu[NR_IRQS]; +static DEFINE_RAW_SPINLOCK(wakeupgen_lock); +static unsigned int irq_target_cpu[MAX_IRQS]; +static unsigned int irq_banks = DEFAULT_NR_REG_BANKS; +static unsigned int max_irqs = DEFAULT_IRQS; +static unsigned int omap_secure_apis; /* * Static helper functions. */ static inline u32 wakeupgen_readl(u8 idx, u32 cpu) { - return __raw_readl(wakeupgen_base + OMAP_WKG_ENB_A_0 + + return readl_relaxed(wakeupgen_base + OMAP_WKG_ENB_A_0 + (cpu * CPU_ENA_OFFSET) + (idx * 4)); } static inline void wakeupgen_writel(u32 val, u8 idx, u32 cpu) { - __raw_writel(val, wakeupgen_base + OMAP_WKG_ENB_A_0 + + writel_relaxed(val, wakeupgen_base + OMAP_WKG_ENB_A_0 + (cpu * CPU_ENA_OFFSET) + (idx * 4)); } static inline void sar_writel(u32 val, u32 offset, u8 idx) { - __raw_writel(val, sar_base + offset + (idx * 4)); -} - -static void _wakeupgen_set_all(unsigned int cpu, unsigned int reg) -{ - u8 i; - - for (i = 0; i < NR_REG_BANKS; i++) - wakeupgen_writel(reg, i, cpu); + writel_relaxed(val, sar_base + offset + (idx * 4)); } static inline int _wakeupgen_get_irq_info(u32 irq, u32 *bit_posn, u8 *reg_index) @@ -130,22 +130,6 @@ static void _wakeupgen_set(unsigned int irq, unsigned int cpu) wakeupgen_writel(val, i, cpu); } -static void _wakeupgen_save_masks(unsigned int cpu) -{ - u8 i; - - for (i = 0; i < NR_REG_BANKS; i++) - per_cpu(irqmasks, cpu)[i] = wakeupgen_readl(i, cpu); -} - -static void _wakeupgen_restore_masks(unsigned int cpu) -{ - u8 i; - - for (i = 0; i < NR_REG_BANKS; i++) - wakeupgen_writel(per_cpu(irqmasks, cpu)[i], i, cpu); -} - /* * Architecture specific Mask extension */ @@ -153,9 +137,9 @@ static void wakeupgen_mask(struct irq_data *d) { unsigned long flags; - spin_lock_irqsave(&wakeupgen_lock, flags); - _wakeupgen_clear(d->irq, irq_target_cpu[d->irq]); - spin_unlock_irqrestore(&wakeupgen_lock, flags); + raw_spin_lock_irqsave(&wakeupgen_lock, flags); + _wakeupgen_clear(d->hwirq, irq_target_cpu[d->hwirq]); + raw_spin_unlock_irqrestore(&wakeupgen_lock, flags); } /* @@ -165,9 +149,36 @@ static void wakeupgen_unmask(struct irq_data *d) { unsigned long flags; - spin_lock_irqsave(&wakeupgen_lock, flags); - _wakeupgen_set(d->irq, irq_target_cpu[d->irq]); - spin_unlock_irqrestore(&wakeupgen_lock, flags); + raw_spin_lock_irqsave(&wakeupgen_lock, flags); + _wakeupgen_set(d->hwirq, irq_target_cpu[d->hwirq]); + raw_spin_unlock_irqrestore(&wakeupgen_lock, flags); +} + +#ifdef CONFIG_HOTPLUG_CPU +static DEFINE_PER_CPU(u32 [MAX_NR_REG_BANKS], irqmasks); + +static void _wakeupgen_save_masks(unsigned int cpu) +{ + u8 i; + + for (i = 0; i < irq_banks; i++) + per_cpu(irqmasks, cpu)[i] = wakeupgen_readl(i, cpu); +} + +static void _wakeupgen_restore_masks(unsigned int cpu) +{ + u8 i; + + for (i = 0; i < irq_banks; i++) + wakeupgen_writel(per_cpu(irqmasks, cpu)[i], i, cpu); +} + +static void _wakeupgen_set_all(unsigned int cpu, unsigned int reg) +{ + u8 i; + + for (i = 0; i < irq_banks; i++) + wakeupgen_writel(reg, i, cpu); } /* @@ -181,7 +192,7 @@ static void wakeupgen_irqmask_all(unsigned int cpu, unsigned int set) { unsigned long flags; - spin_lock_irqsave(&wakeupgen_lock, flags); + raw_spin_lock_irqsave(&wakeupgen_lock, flags); if (set) { _wakeupgen_save_masks(cpu); _wakeupgen_set_all(cpu, WKG_MASK_ALL); @@ -189,29 +200,19 @@ static void wakeupgen_irqmask_all(unsigned int cpu, unsigned int set) _wakeupgen_set_all(cpu, WKG_UNMASK_ALL); _wakeupgen_restore_masks(cpu); } - spin_unlock_irqrestore(&wakeupgen_lock, flags); + raw_spin_unlock_irqrestore(&wakeupgen_lock, flags); } +#endif #ifdef CONFIG_CPU_PM -/* - * Save WakeupGen interrupt context in SAR BANK3. Restore is done by - * ROM code. WakeupGen IP is integrated along with GIC to manage the - * interrupt wakeups from CPU low power states. It manages - * masking/unmasking of Shared peripheral interrupts(SPI). So the - * interrupt enable/disable control should be in sync and consistent - * at WakeupGen and GIC so that interrupts are not lost. - */ -static void irq_save_context(void) +static inline void omap4_irq_save_context(void) { u32 i, val; if (omap_rev() == OMAP4430_REV_ES1_0) return; - if (!sar_base) - sar_base = omap4_get_sar_ram_base(); - - for (i = 0; i < NR_REG_BANKS; i++) { + for (i = 0; i < irq_banks; i++) { /* Save the CPUx interrupt mask for IRQ 0 to 127 */ val = wakeupgen_readl(i, 0); sar_writel(val, WAKEUPGENENB_OFFSET_CPU0, i); @@ -230,38 +231,84 @@ static void irq_save_context(void) } /* Save AuxBoot* registers */ - val = __raw_readl(wakeupgen_base + OMAP_AUX_CORE_BOOT_0); - __raw_writel(val, sar_base + AUXCOREBOOT0_OFFSET); - val = __raw_readl(wakeupgen_base + OMAP_AUX_CORE_BOOT_0); - __raw_writel(val, sar_base + AUXCOREBOOT1_OFFSET); + val = readl_relaxed(wakeupgen_base + OMAP_AUX_CORE_BOOT_0); + writel_relaxed(val, sar_base + AUXCOREBOOT0_OFFSET); + val = readl_relaxed(wakeupgen_base + OMAP_AUX_CORE_BOOT_1); + writel_relaxed(val, sar_base + AUXCOREBOOT1_OFFSET); /* Save SyncReq generation logic */ - val = __raw_readl(wakeupgen_base + OMAP_AUX_CORE_BOOT_0); - __raw_writel(val, sar_base + AUXCOREBOOT0_OFFSET); - val = __raw_readl(wakeupgen_base + OMAP_AUX_CORE_BOOT_0); - __raw_writel(val, sar_base + AUXCOREBOOT1_OFFSET); + val = readl_relaxed(wakeupgen_base + OMAP_PTMSYNCREQ_MASK); + writel_relaxed(val, sar_base + PTMSYNCREQ_MASK_OFFSET); + val = readl_relaxed(wakeupgen_base + OMAP_PTMSYNCREQ_EN); + writel_relaxed(val, sar_base + PTMSYNCREQ_EN_OFFSET); - /* Save SyncReq generation logic */ - val = __raw_readl(wakeupgen_base + OMAP_PTMSYNCREQ_MASK); - __raw_writel(val, sar_base + PTMSYNCREQ_MASK_OFFSET); - val = __raw_readl(wakeupgen_base + OMAP_PTMSYNCREQ_EN); - __raw_writel(val, sar_base + PTMSYNCREQ_EN_OFFSET); + /* Set the Backup Bit Mask status */ + val = readl_relaxed(sar_base + SAR_BACKUP_STATUS_OFFSET); + val |= SAR_BACKUP_STATUS_WAKEUPGEN; + writel_relaxed(val, sar_base + SAR_BACKUP_STATUS_OFFSET); + +} + +static inline void omap5_irq_save_context(void) +{ + u32 i, val; + + for (i = 0; i < irq_banks; i++) { + /* Save the CPUx interrupt mask for IRQ 0 to 159 */ + val = wakeupgen_readl(i, 0); + sar_writel(val, OMAP5_WAKEUPGENENB_OFFSET_CPU0, i); + val = wakeupgen_readl(i, 1); + sar_writel(val, OMAP5_WAKEUPGENENB_OFFSET_CPU1, i); + sar_writel(0x0, OMAP5_WAKEUPGENENB_SECURE_OFFSET_CPU0, i); + sar_writel(0x0, OMAP5_WAKEUPGENENB_SECURE_OFFSET_CPU1, i); + } + + /* Save AuxBoot* registers */ + val = readl_relaxed(wakeupgen_base + OMAP_AUX_CORE_BOOT_0); + writel_relaxed(val, sar_base + OMAP5_AUXCOREBOOT0_OFFSET); + val = readl_relaxed(wakeupgen_base + OMAP_AUX_CORE_BOOT_0); + writel_relaxed(val, sar_base + OMAP5_AUXCOREBOOT1_OFFSET); /* Set the Backup Bit Mask status */ - val = __raw_readl(sar_base + SAR_BACKUP_STATUS_OFFSET); + val = readl_relaxed(sar_base + OMAP5_SAR_BACKUP_STATUS_OFFSET); val |= SAR_BACKUP_STATUS_WAKEUPGEN; - __raw_writel(val, sar_base + SAR_BACKUP_STATUS_OFFSET); + writel_relaxed(val, sar_base + OMAP5_SAR_BACKUP_STATUS_OFFSET); + +} + +/* + * Save WakeupGen interrupt context in SAR BANK3. Restore is done by + * ROM code. WakeupGen IP is integrated along with GIC to manage the + * interrupt wakeups from CPU low power states. It manages + * masking/unmasking of Shared peripheral interrupts(SPI). So the + * interrupt enable/disable control should be in sync and consistent + * at WakeupGen and GIC so that interrupts are not lost. + */ +static void irq_save_context(void) +{ + if (!sar_base) + sar_base = omap4_get_sar_ram_base(); + + if (soc_is_omap54xx()) + omap5_irq_save_context(); + else + omap4_irq_save_context(); } /* * Clear WakeupGen SAR backup status. */ -void irq_sar_clear(void) +static void irq_sar_clear(void) { u32 val; - val = __raw_readl(sar_base + SAR_BACKUP_STATUS_OFFSET); + u32 offset = SAR_BACKUP_STATUS_OFFSET; + + if (soc_is_omap54xx()) + offset = OMAP5_SAR_BACKUP_STATUS_OFFSET; + + val = readl_relaxed(sar_base + offset); val &= ~SAR_BACKUP_STATUS_WAKEUPGEN; - __raw_writel(val, sar_base + SAR_BACKUP_STATUS_OFFSET); + writel_relaxed(val, sar_base + offset); } /* @@ -280,8 +327,8 @@ static void irq_save_secure_context(void) #endif #ifdef CONFIG_HOTPLUG_CPU -static int __cpuinit irq_cpu_hotplug_notify(struct notifier_block *self, - unsigned long action, void *hcpu) +static int irq_cpu_hotplug_notify(struct notifier_block *self, + unsigned long action, void *hcpu) { unsigned int cpu = (unsigned int)hcpu; @@ -333,13 +380,25 @@ static struct notifier_block irq_notifier_block = { static void __init irq_pm_init(void) { - cpu_pm_register_notifier(&irq_notifier_block); + /* FIXME: Remove this when MPU OSWR support is added */ + if (!soc_is_omap54xx()) + cpu_pm_register_notifier(&irq_notifier_block); } #else static void __init irq_pm_init(void) {} #endif +void __iomem *omap_get_wakeupgen_base(void) +{ + return wakeupgen_base; +} + +int omap_secure_apis_support(void) +{ + return omap_secure_apis; +} + /* * Initialise the wakeupgen module. */ @@ -355,14 +414,24 @@ int __init omap_wakeupgen_init(void) } /* Static mapping, never released */ - wakeupgen_base = ioremap(OMAP44XX_WKUPGEN_BASE, SZ_4K); + wakeupgen_base = ioremap(OMAP_WKUPGEN_BASE, SZ_4K); if (WARN_ON(!wakeupgen_base)) return -ENOMEM; + if (cpu_is_omap44xx()) { + irq_banks = OMAP4_NR_BANKS; + max_irqs = OMAP4_NR_IRQS; + omap_secure_apis = 1; + } else if (soc_is_am43xx()) { + irq_banks = AM43XX_NR_REG_BANKS; + max_irqs = AM43XX_IRQS; + } + /* Clear all IRQ bitmasks at wakeupGen level */ - for (i = 0; i < NR_REG_BANKS; i++) { + for (i = 0; i < irq_banks; i++) { wakeupgen_writel(0, i, CPU0_ID); - wakeupgen_writel(0, i, CPU1_ID); + if (!soc_is_am43xx()) + wakeupgen_writel(0, i, CPU1_ID); } /* @@ -379,7 +448,7 @@ int __init omap_wakeupgen_init(void) */ /* Associate all the IRQs to boot CPU like GIC init does. */ - for (i = 0; i < NR_IRQS; i++) + for (i = 0; i < max_irqs; i++) irq_target_cpu[i] = boot_cpu; irq_hotplug_init(); |
