|
@@ -140,3 +140,188 @@ static void wakeupgen_mask(struct irq_data *d)
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
+ * Architecture specific Unmask extension
|
|
|
+ */
|
|
|
+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);
|
|
|
+}
|
|
|
+
|
|
|
+#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);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Mask or unmask all interrupts on given CPU.
|
|
|
+ * 0 = Mask all interrupts on the 'cpu'
|
|
|
+ * 1 = Unmask all interrupts on the 'cpu'
|
|
|
+ * Ensure that the initial mask is maintained. This is faster than
|
|
|
+ * iterating through GIC registers to arrive at the correct masks.
|
|
|
+ */
|
|
|
+static void wakeupgen_irqmask_all(unsigned int cpu, unsigned int set)
|
|
|
+{
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
+ spin_lock_irqsave(&wakeupgen_lock, flags);
|
|
|
+ if (set) {
|
|
|
+ _wakeupgen_save_masks(cpu);
|
|
|
+ _wakeupgen_set_all(cpu, WKG_MASK_ALL);
|
|
|
+ } else {
|
|
|
+ _wakeupgen_set_all(cpu, WKG_UNMASK_ALL);
|
|
|
+ _wakeupgen_restore_masks(cpu);
|
|
|
+ }
|
|
|
+ spin_unlock_irqrestore(&wakeupgen_lock, flags);
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifdef CONFIG_CPU_PM
|
|
|
+static inline void omap4_irq_save_context(void)
|
|
|
+{
|
|
|
+ u32 i, val;
|
|
|
+
|
|
|
+ if (omap_rev() == OMAP4430_REV_ES1_0)
|
|
|
+ return;
|
|
|
+
|
|
|
+ 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);
|
|
|
+ val = wakeupgen_readl(i, 1);
|
|
|
+ sar_writel(val, WAKEUPGENENB_OFFSET_CPU1, i);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Disable the secure interrupts for CPUx. The restore
|
|
|
+ * code blindly restores secure and non-secure interrupt
|
|
|
+ * masks from SAR RAM. Secure interrupts are not suppose
|
|
|
+ * to be enabled from HLOS. So overwrite the SAR location
|
|
|
+ * so that the secure interrupt remains disabled.
|
|
|
+ */
|
|
|
+ sar_writel(0x0, WAKEUPGENENB_SECURE_OFFSET_CPU0, i);
|
|
|
+ sar_writel(0x0, WAKEUPGENENB_SECURE_OFFSET_CPU1, i);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 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_1);
|
|
|
+ __raw_writel(val, sar_base + AUXCOREBOOT1_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 = __raw_readl(sar_base + SAR_BACKUP_STATUS_OFFSET);
|
|
|
+ val |= SAR_BACKUP_STATUS_WAKEUPGEN;
|
|
|
+ __raw_writel(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 = __raw_readl(wakeupgen_base + OMAP_AUX_CORE_BOOT_0);
|
|
|
+ __raw_writel(val, sar_base + OMAP5_AUXCOREBOOT0_OFFSET);
|
|
|
+ val = __raw_readl(wakeupgen_base + OMAP_AUX_CORE_BOOT_0);
|
|
|
+ __raw_writel(val, sar_base + OMAP5_AUXCOREBOOT1_OFFSET);
|
|
|
+
|
|
|
+ /* Set the Backup Bit Mask status */
|
|
|
+ val = __raw_readl(sar_base + OMAP5_SAR_BACKUP_STATUS_OFFSET);
|
|
|
+ val |= SAR_BACKUP_STATUS_WAKEUPGEN;
|
|
|
+ __raw_writel(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.
|
|
|
+ */
|
|
|
+static void irq_sar_clear(void)
|
|
|
+{
|
|
|
+ u32 val;
|
|
|
+ u32 offset = SAR_BACKUP_STATUS_OFFSET;
|
|
|
+
|
|
|
+ if (soc_is_omap54xx())
|
|
|
+ offset = OMAP5_SAR_BACKUP_STATUS_OFFSET;
|
|
|
+
|
|
|
+ val = __raw_readl(sar_base + offset);
|
|
|
+ val &= ~SAR_BACKUP_STATUS_WAKEUPGEN;
|
|
|
+ __raw_writel(val, sar_base + offset);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Save GIC and Wakeupgen interrupt context using secure API
|
|
|
+ * for HS/EMU devices.
|
|
|
+ */
|
|
|
+static void irq_save_secure_context(void)
|
|
|
+{
|
|
|
+ u32 ret;
|
|
|
+ ret = omap_secure_dispatcher(OMAP4_HAL_SAVEGIC_INDEX,
|
|
|
+ FLAG_START_CRITICAL,
|
|
|
+ 0, 0, 0, 0, 0);
|
|
|
+ if (ret != API_HAL_RET_VALUE_OK)
|
|
|
+ pr_err("GIC and Wakeupgen context save failed\n");
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifdef CONFIG_HOTPLUG_CPU
|
|
|
+static int __cpuinit irq_cpu_hotplug_notify(struct notifier_block *self,
|