^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * OMAP WakeupGen Source file
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * OMAP WakeupGen is the interrupt controller extension used along
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * with ARM GIC to wake the CPU out from low power states on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * external interrupts. It is responsible for generating wakeup
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * event from the incoming interrupts and enable bits. It is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * implemented in MPU always ON power domain. During normal operation,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * WakeupGen delivers external interrupts directly to the GIC.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * Copyright (C) 2011 Texas Instruments, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * Santosh Shilimkar <santosh.shilimkar@ti.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/irqchip.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/irqdomain.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/of_address.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/cpu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/notifier.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/cpu_pm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include "omap-wakeupgen.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include "omap-secure.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include "soc.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include "omap4-sar-layout.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include "common.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include "pm.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define AM43XX_NR_REG_BANKS 7
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define AM43XX_IRQS 224
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define MAX_NR_REG_BANKS AM43XX_NR_REG_BANKS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define MAX_IRQS AM43XX_IRQS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define DEFAULT_NR_REG_BANKS 5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define DEFAULT_IRQS 160
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define WKG_MASK_ALL 0x00000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define WKG_UNMASK_ALL 0xffffffff
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define CPU_ENA_OFFSET 0x400
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define CPU0_ID 0x0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define CPU1_ID 0x1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #define OMAP4_NR_BANKS 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #define OMAP4_NR_IRQS 128
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #define SYS_NIRQ1_EXT_SYS_IRQ_1 7
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #define SYS_NIRQ2_EXT_SYS_IRQ_2 119
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) static void __iomem *wakeupgen_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) static void __iomem *sar_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) static DEFINE_RAW_SPINLOCK(wakeupgen_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) static unsigned int irq_target_cpu[MAX_IRQS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) static unsigned int irq_banks = DEFAULT_NR_REG_BANKS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) static unsigned int max_irqs = DEFAULT_IRQS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) static unsigned int omap_secure_apis;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #ifdef CONFIG_CPU_PM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) static unsigned int wakeupgen_context[MAX_NR_REG_BANKS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) struct omap_wakeupgen_ops {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) void (*save_context)(void);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) void (*restore_context)(void);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) static struct omap_wakeupgen_ops *wakeupgen_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) * Static helper functions.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) static inline u32 wakeupgen_readl(u8 idx, u32 cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) return readl_relaxed(wakeupgen_base + OMAP_WKG_ENB_A_0 +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) (cpu * CPU_ENA_OFFSET) + (idx * 4));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) static inline void wakeupgen_writel(u32 val, u8 idx, u32 cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) writel_relaxed(val, wakeupgen_base + OMAP_WKG_ENB_A_0 +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) (cpu * CPU_ENA_OFFSET) + (idx * 4));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) static inline void sar_writel(u32 val, u32 offset, u8 idx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) writel_relaxed(val, sar_base + offset + (idx * 4));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) static inline int _wakeupgen_get_irq_info(u32 irq, u32 *bit_posn, u8 *reg_index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) * Each WakeupGen register controls 32 interrupt.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) * i.e. 1 bit per SPI IRQ
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) *reg_index = irq >> 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) *bit_posn = irq %= 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) static void _wakeupgen_clear(unsigned int irq, unsigned int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) u32 val, bit_number;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) u8 i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) if (_wakeupgen_get_irq_info(irq, &bit_number, &i))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) val = wakeupgen_readl(i, cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) val &= ~BIT(bit_number);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) wakeupgen_writel(val, i, cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) static void _wakeupgen_set(unsigned int irq, unsigned int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) u32 val, bit_number;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) u8 i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) if (_wakeupgen_get_irq_info(irq, &bit_number, &i))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) val = wakeupgen_readl(i, cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) val |= BIT(bit_number);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) wakeupgen_writel(val, i, cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) * Architecture specific Mask extension
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) static void wakeupgen_mask(struct irq_data *d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) raw_spin_lock_irqsave(&wakeupgen_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) _wakeupgen_clear(d->hwirq, irq_target_cpu[d->hwirq]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) raw_spin_unlock_irqrestore(&wakeupgen_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) irq_chip_mask_parent(d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) * Architecture specific Unmask extension
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) static void wakeupgen_unmask(struct irq_data *d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) raw_spin_lock_irqsave(&wakeupgen_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) _wakeupgen_set(d->hwirq, irq_target_cpu[d->hwirq]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) raw_spin_unlock_irqrestore(&wakeupgen_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) irq_chip_unmask_parent(d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) * The sys_nirq pins bypass peripheral modules and are wired directly
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) * to MPUSS wakeupgen. They get automatically inverted for GIC.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) static int wakeupgen_irq_set_type(struct irq_data *d, unsigned int type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) bool inverted = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) switch (type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) case IRQ_TYPE_LEVEL_LOW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) type &= ~IRQ_TYPE_LEVEL_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) type |= IRQ_TYPE_LEVEL_HIGH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) inverted = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) case IRQ_TYPE_EDGE_FALLING:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) type &= ~IRQ_TYPE_EDGE_BOTH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) type |= IRQ_TYPE_EDGE_RISING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) inverted = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) if (inverted && d->hwirq != SYS_NIRQ1_EXT_SYS_IRQ_1 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) d->hwirq != SYS_NIRQ2_EXT_SYS_IRQ_2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) pr_warn("wakeupgen: irq%li polarity inverted in dts\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) d->hwirq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) return irq_chip_set_type_parent(d, type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) #ifdef CONFIG_HOTPLUG_CPU
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) static DEFINE_PER_CPU(u32 [MAX_NR_REG_BANKS], irqmasks);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) static void _wakeupgen_save_masks(unsigned int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) u8 i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) for (i = 0; i < irq_banks; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) per_cpu(irqmasks, cpu)[i] = wakeupgen_readl(i, cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) static void _wakeupgen_restore_masks(unsigned int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) u8 i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) for (i = 0; i < irq_banks; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) wakeupgen_writel(per_cpu(irqmasks, cpu)[i], i, cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) static void _wakeupgen_set_all(unsigned int cpu, unsigned int reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) u8 i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) for (i = 0; i < irq_banks; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) wakeupgen_writel(reg, i, cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) * Mask or unmask all interrupts on given CPU.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) * 0 = Mask all interrupts on the 'cpu'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) * 1 = Unmask all interrupts on the 'cpu'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) * Ensure that the initial mask is maintained. This is faster than
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) * iterating through GIC registers to arrive at the correct masks.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) static void wakeupgen_irqmask_all(unsigned int cpu, unsigned int set)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) raw_spin_lock_irqsave(&wakeupgen_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) if (set) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) _wakeupgen_save_masks(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) _wakeupgen_set_all(cpu, WKG_MASK_ALL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) _wakeupgen_set_all(cpu, WKG_UNMASK_ALL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) _wakeupgen_restore_masks(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) raw_spin_unlock_irqrestore(&wakeupgen_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) #ifdef CONFIG_CPU_PM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) static inline void omap4_irq_save_context(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) u32 i, val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) if (omap_rev() == OMAP4430_REV_ES1_0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) for (i = 0; i < irq_banks; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) /* Save the CPUx interrupt mask for IRQ 0 to 127 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) val = wakeupgen_readl(i, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) sar_writel(val, WAKEUPGENENB_OFFSET_CPU0, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) val = wakeupgen_readl(i, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) sar_writel(val, WAKEUPGENENB_OFFSET_CPU1, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) * Disable the secure interrupts for CPUx. The restore
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) * code blindly restores secure and non-secure interrupt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) * masks from SAR RAM. Secure interrupts are not suppose
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) * to be enabled from HLOS. So overwrite the SAR location
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) * so that the secure interrupt remains disabled.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) sar_writel(0x0, WAKEUPGENENB_SECURE_OFFSET_CPU0, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) sar_writel(0x0, WAKEUPGENENB_SECURE_OFFSET_CPU1, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) /* Save AuxBoot* registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) val = readl_relaxed(wakeupgen_base + OMAP_AUX_CORE_BOOT_0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) writel_relaxed(val, sar_base + AUXCOREBOOT0_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) val = readl_relaxed(wakeupgen_base + OMAP_AUX_CORE_BOOT_1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) writel_relaxed(val, sar_base + AUXCOREBOOT1_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) /* Save SyncReq generation logic */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) val = readl_relaxed(wakeupgen_base + OMAP_PTMSYNCREQ_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) writel_relaxed(val, sar_base + PTMSYNCREQ_MASK_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) val = readl_relaxed(wakeupgen_base + OMAP_PTMSYNCREQ_EN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) writel_relaxed(val, sar_base + PTMSYNCREQ_EN_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) /* Set the Backup Bit Mask status */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) val = readl_relaxed(sar_base + SAR_BACKUP_STATUS_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) val |= SAR_BACKUP_STATUS_WAKEUPGEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) writel_relaxed(val, sar_base + SAR_BACKUP_STATUS_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) static inline void omap5_irq_save_context(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) u32 i, val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) for (i = 0; i < irq_banks; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) /* Save the CPUx interrupt mask for IRQ 0 to 159 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) val = wakeupgen_readl(i, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) sar_writel(val, OMAP5_WAKEUPGENENB_OFFSET_CPU0, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) val = wakeupgen_readl(i, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) sar_writel(val, OMAP5_WAKEUPGENENB_OFFSET_CPU1, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) sar_writel(0x0, OMAP5_WAKEUPGENENB_SECURE_OFFSET_CPU0, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) sar_writel(0x0, OMAP5_WAKEUPGENENB_SECURE_OFFSET_CPU1, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) /* Save AuxBoot* registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) val = readl_relaxed(wakeupgen_base + OMAP_AUX_CORE_BOOT_0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) writel_relaxed(val, sar_base + OMAP5_AUXCOREBOOT0_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) val = readl_relaxed(wakeupgen_base + OMAP_AUX_CORE_BOOT_0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) writel_relaxed(val, sar_base + OMAP5_AUXCOREBOOT1_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) /* Set the Backup Bit Mask status */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) val = readl_relaxed(sar_base + OMAP5_SAR_BACKUP_STATUS_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) val |= SAR_BACKUP_STATUS_WAKEUPGEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) writel_relaxed(val, sar_base + OMAP5_SAR_BACKUP_STATUS_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) static inline void am43xx_irq_save_context(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) u32 i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) for (i = 0; i < irq_banks; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) wakeupgen_context[i] = wakeupgen_readl(i, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) wakeupgen_writel(0, i, CPU0_ID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) * Save WakeupGen interrupt context in SAR BANK3. Restore is done by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) * ROM code. WakeupGen IP is integrated along with GIC to manage the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) * interrupt wakeups from CPU low power states. It manages
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) * masking/unmasking of Shared peripheral interrupts(SPI). So the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) * interrupt enable/disable control should be in sync and consistent
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) * at WakeupGen and GIC so that interrupts are not lost.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) static void irq_save_context(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) /* DRA7 has no SAR to save */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) if (soc_is_dra7xx())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) if (wakeupgen_ops && wakeupgen_ops->save_context)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) wakeupgen_ops->save_context();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) * Clear WakeupGen SAR backup status.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) static void irq_sar_clear(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) u32 offset = SAR_BACKUP_STATUS_OFFSET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) /* DRA7 has no SAR to save */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) if (soc_is_dra7xx())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) if (soc_is_omap54xx())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) offset = OMAP5_SAR_BACKUP_STATUS_OFFSET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) val = readl_relaxed(sar_base + offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) val &= ~SAR_BACKUP_STATUS_WAKEUPGEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) writel_relaxed(val, sar_base + offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) static void am43xx_irq_restore_context(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) u32 i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) for (i = 0; i < irq_banks; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) wakeupgen_writel(wakeupgen_context[i], i, CPU0_ID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) static void irq_restore_context(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) if (wakeupgen_ops && wakeupgen_ops->restore_context)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) wakeupgen_ops->restore_context();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) * Save GIC and Wakeupgen interrupt context using secure API
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) * for HS/EMU devices.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) static void irq_save_secure_context(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) u32 ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) ret = omap_secure_dispatcher(OMAP4_HAL_SAVEGIC_INDEX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) FLAG_START_CRITICAL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) 0, 0, 0, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) if (ret != API_HAL_RET_VALUE_OK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) pr_err("GIC and Wakeupgen context save failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) /* Define ops for context save and restore for each SoC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) static struct omap_wakeupgen_ops omap4_wakeupgen_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) .save_context = omap4_irq_save_context,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) .restore_context = irq_sar_clear,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) static struct omap_wakeupgen_ops omap5_wakeupgen_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) .save_context = omap5_irq_save_context,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) .restore_context = irq_sar_clear,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) static struct omap_wakeupgen_ops am43xx_wakeupgen_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) .save_context = am43xx_irq_save_context,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) .restore_context = am43xx_irq_restore_context,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) static struct omap_wakeupgen_ops omap4_wakeupgen_ops = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) static struct omap_wakeupgen_ops omap5_wakeupgen_ops = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) static struct omap_wakeupgen_ops am43xx_wakeupgen_ops = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) #ifdef CONFIG_HOTPLUG_CPU
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) static int omap_wakeupgen_cpu_online(unsigned int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) wakeupgen_irqmask_all(cpu, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) static int omap_wakeupgen_cpu_dead(unsigned int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) wakeupgen_irqmask_all(cpu, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) static void __init irq_hotplug_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "arm/omap-wake:online",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) omap_wakeupgen_cpu_online, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) cpuhp_setup_state_nocalls(CPUHP_ARM_OMAP_WAKE_DEAD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) "arm/omap-wake:dead", NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) omap_wakeupgen_cpu_dead);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) static void __init irq_hotplug_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) #ifdef CONFIG_CPU_PM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) static int irq_notifier(struct notifier_block *self, unsigned long cmd, void *v)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) switch (cmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) case CPU_CLUSTER_PM_ENTER:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) if (omap_type() == OMAP2_DEVICE_TYPE_GP || soc_is_am43xx())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) irq_save_context();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) irq_save_secure_context();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) case CPU_CLUSTER_PM_EXIT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) if (omap_type() == OMAP2_DEVICE_TYPE_GP || soc_is_am43xx())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) irq_restore_context();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) return NOTIFY_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) static struct notifier_block irq_notifier_block = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) .notifier_call = irq_notifier,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) static void __init irq_pm_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) /* FIXME: Remove this when MPU OSWR support is added */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) if (!IS_PM44XX_ERRATUM(PM_OMAP4_CPU_OSWR_DISABLE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) cpu_pm_register_notifier(&irq_notifier_block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) static void __init irq_pm_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) void __iomem *omap_get_wakeupgen_base(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) return wakeupgen_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) int omap_secure_apis_support(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) return omap_secure_apis;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) static struct irq_chip wakeupgen_chip = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) .name = "WUGEN",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) .irq_eoi = irq_chip_eoi_parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) .irq_mask = wakeupgen_mask,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) .irq_unmask = wakeupgen_unmask,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) .irq_retrigger = irq_chip_retrigger_hierarchy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) .irq_set_type = wakeupgen_irq_set_type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) .flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) #ifdef CONFIG_SMP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) .irq_set_affinity = irq_chip_set_affinity_parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) static int wakeupgen_domain_translate(struct irq_domain *d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) struct irq_fwspec *fwspec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) unsigned long *hwirq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) unsigned int *type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) if (is_of_node(fwspec->fwnode)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) if (fwspec->param_count != 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) /* No PPI should point to this domain */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) if (fwspec->param[0] != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) *hwirq = fwspec->param[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) *type = fwspec->param[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) static int wakeupgen_domain_alloc(struct irq_domain *domain,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) unsigned int virq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) unsigned int nr_irqs, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) struct irq_fwspec *fwspec = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) struct irq_fwspec parent_fwspec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) irq_hw_number_t hwirq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) if (fwspec->param_count != 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) return -EINVAL; /* Not GIC compliant */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) if (fwspec->param[0] != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) return -EINVAL; /* No PPI should point to this domain */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) hwirq = fwspec->param[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) if (hwirq >= MAX_IRQS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) return -EINVAL; /* Can't deal with this */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) for (i = 0; i < nr_irqs; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) &wakeupgen_chip, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) parent_fwspec = *fwspec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) parent_fwspec.fwnode = domain->parent->fwnode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) &parent_fwspec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) static const struct irq_domain_ops wakeupgen_domain_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) .translate = wakeupgen_domain_translate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) .alloc = wakeupgen_domain_alloc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) .free = irq_domain_free_irqs_common,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) * Initialise the wakeupgen module.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) static int __init wakeupgen_init(struct device_node *node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) struct device_node *parent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) struct irq_domain *parent_domain, *domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) unsigned int boot_cpu = smp_processor_id();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) if (!parent) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) pr_err("%pOF: no parent, giving up\n", node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) parent_domain = irq_find_host(parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) if (!parent_domain) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) pr_err("%pOF: unable to obtain parent domain\n", node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) /* Not supported on OMAP4 ES1.0 silicon */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) if (omap_rev() == OMAP4430_REV_ES1_0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) WARN(1, "WakeupGen: Not supported on OMAP4430 ES1.0\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) return -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) /* Static mapping, never released */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) wakeupgen_base = of_iomap(node, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) if (WARN_ON(!wakeupgen_base))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) if (cpu_is_omap44xx()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) irq_banks = OMAP4_NR_BANKS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) max_irqs = OMAP4_NR_IRQS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) omap_secure_apis = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) wakeupgen_ops = &omap4_wakeupgen_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) } else if (soc_is_omap54xx()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) wakeupgen_ops = &omap5_wakeupgen_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) } else if (soc_is_am43xx()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) irq_banks = AM43XX_NR_REG_BANKS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) max_irqs = AM43XX_IRQS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) wakeupgen_ops = &am43xx_wakeupgen_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) domain = irq_domain_add_hierarchy(parent_domain, 0, max_irqs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) node, &wakeupgen_domain_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) if (!domain) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) iounmap(wakeupgen_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) /* Clear all IRQ bitmasks at wakeupGen level */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) for (i = 0; i < irq_banks; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) wakeupgen_writel(0, i, CPU0_ID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) if (!soc_is_am43xx())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) wakeupgen_writel(0, i, CPU1_ID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) * FIXME: Add support to set_smp_affinity() once the core
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) * GIC code has necessary hooks in place.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) /* Associate all the IRQs to boot CPU like GIC init does. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) for (i = 0; i < max_irqs; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) irq_target_cpu[i] = boot_cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) * Enables OMAP5 ES2 PM Mode using ES2_PM_MODE in AMBA_IF_MODE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) * 0x0: ES1 behavior, CPU cores would enter and exit OFF mode together.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) * 0x1: ES2 behavior, CPU cores are allowed to enter/exit OFF mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) * independently.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) * This needs to be set one time thanks to always ON domain.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) * We do not support ES1 behavior anymore. OMAP5 is assumed to be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) * ES2.0, and the same is applicable for DRA7.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) if (soc_is_omap54xx() || soc_is_dra7xx()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) val = __raw_readl(wakeupgen_base + OMAP_AMBA_IF_MODE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) val |= BIT(5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) omap_smc1(OMAP5_MON_AMBA_IF_INDEX, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) irq_hotplug_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) irq_pm_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) sar_base = omap4_get_sar_ram_base();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) IRQCHIP_DECLARE(ti_wakeupgen, "ti,omap4-wugen-mpu", wakeupgen_init);