1 /* 2 * Copyright (C) 2011 Google, Inc. 3 * 4 * Author: 5 * Colin Cross <ccross@android.com> 6 * 7 * Copyright (C) 2010,2013, NVIDIA Corporation 8 * 9 * This software is licensed under the terms of the GNU General Public 10 * License version 2, as published by the Free Software Foundation, and 11 * may be copied, distributed, and modified under those terms. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 */ 19 20 #include <linux/cpu_pm.h> 21 #include <linux/interrupt.h> 22 #include <linux/io.h> 23 #include <linux/irqchip/arm-gic.h> 24 #include <linux/irq.h> 25 #include <linux/kernel.h> 26 #include <linux/of_address.h> 27 #include <linux/of.h> 28 #include <linux/syscore_ops.h> 29 30 #include "board.h" 31 #include "iomap.h" 32 33 #define ICTLR_CPU_IEP_VFIQ 0x08 34 #define ICTLR_CPU_IEP_FIR 0x14 35 #define ICTLR_CPU_IEP_FIR_SET 0x18 36 #define ICTLR_CPU_IEP_FIR_CLR 0x1c 37 38 #define ICTLR_CPU_IER 0x20 39 #define ICTLR_CPU_IER_SET 0x24 40 #define ICTLR_CPU_IER_CLR 0x28 41 #define ICTLR_CPU_IEP_CLASS 0x2C 42 43 #define ICTLR_COP_IER 0x30 44 #define ICTLR_COP_IER_SET 0x34 45 #define ICTLR_COP_IER_CLR 0x38 46 #define ICTLR_COP_IEP_CLASS 0x3c 47 48 #define FIRST_LEGACY_IRQ 32 49 #define TEGRA_MAX_NUM_ICTLRS 5 50 51 #define SGI_MASK 0xFFFF 52 53 static int num_ictlrs; 54 55 static void __iomem *ictlr_reg_base[] = { 56 IO_ADDRESS(TEGRA_PRIMARY_ICTLR_BASE), 57 IO_ADDRESS(TEGRA_SECONDARY_ICTLR_BASE), 58 IO_ADDRESS(TEGRA_TERTIARY_ICTLR_BASE), 59 IO_ADDRESS(TEGRA_QUATERNARY_ICTLR_BASE), 60 IO_ADDRESS(TEGRA_QUINARY_ICTLR_BASE), 61 }; 62 63 #ifdef CONFIG_PM_SLEEP 64 static u32 cop_ier[TEGRA_MAX_NUM_ICTLRS]; 65 static u32 cop_iep[TEGRA_MAX_NUM_ICTLRS]; 66 static u32 cpu_ier[TEGRA_MAX_NUM_ICTLRS]; 67 static u32 cpu_iep[TEGRA_MAX_NUM_ICTLRS]; 68 69 static u32 ictlr_wake_mask[TEGRA_MAX_NUM_ICTLRS]; 70 static void __iomem *tegra_gic_cpu_base; 71 #endif 72 73 bool tegra_pending_sgi(void) 74 { 75 u32 pending_set; 76 void __iomem *distbase = IO_ADDRESS(TEGRA_ARM_INT_DIST_BASE); 77 78 pending_set = readl_relaxed(distbase + GIC_DIST_PENDING_SET); 79 80 if (pending_set & SGI_MASK) 81 return true; 82 83 return false; 84 } 85 86 static inline void tegra_irq_write_mask(unsigned int irq, unsigned long reg) 87 { 88 void __iomem *base; 89 u32 mask; 90 91 BUG_ON(irq < FIRST_LEGACY_IRQ || 92 irq >= FIRST_LEGACY_IRQ + num_ictlrs * 32); 93 94 base = ictlr_reg_base[(irq - FIRST_LEGACY_IRQ) / 32]; 95 mask = BIT((irq - FIRST_LEGACY_IRQ) % 32); 96 97 __raw_writel(mask, base + reg); 98 } 99 100 static void tegra_mask(struct irq_data *d) 101 { 102 if (d->irq < FIRST_LEGACY_IRQ) 103 return; 104 105 tegra_irq_write_mask(d->irq, ICTLR_CPU_IER_CLR); 106 } 107 108 static void tegra_unmask(struct irq_data *d) 109 { 110 if (d->irq < FIRST_LEGACY_IRQ) 111 return; 112 113 tegra_irq_write_mask(d->irq, ICTLR_CPU_IER_SET); 114 } 115 116 static void tegra_ack(struct irq_data *d) 117 { 118 if (d->irq < FIRST_LEGACY_IRQ) 119 return; 120 121 tegra_irq_write_mask(d->irq, ICTLR_CPU_IEP_FIR_CLR); 122 } 123 124 static void tegra_eoi(struct irq_data *d) 125 { 126 if (d->irq < FIRST_LEGACY_IRQ) 127 return; 128 129 tegra_irq_write_mask(d->irq, ICTLR_CPU_IEP_FIR_CLR); 130 } 131 132 static int tegra_retrigger(struct irq_data *d) 133 { 134 if (d->irq < FIRST_LEGACY_IRQ) 135 return 0; 136 137 tegra_irq_write_mask(d->irq, ICTLR_CPU_IEP_FIR_SET); 138 139 return 1; 140 } 141 142 #ifdef CONFIG_PM_SLEEP 143 static int tegra_set_wake(struct irq_data *d, unsigned int enable) 144 { 145 u32 irq = d->irq; 146 u32 index, mask; 147 148 if (irq < FIRST_LEGACY_IRQ || 149 irq >= FIRST_LEGACY_IRQ + num_ictlrs * 32) 150 return -EINVAL; 151 152 index = ((irq - FIRST_LEGACY_IRQ) / 32); 153 mask = BIT((irq - FIRST_LEGACY_IRQ) % 32); 154 if (enable) 155 ictlr_wake_mask[index] |= mask; 156 else 157 ictlr_wake_mask[index] &= ~mask; 158 159 return 0; 160 } 161 162 static int tegra_legacy_irq_suspend(void) 163 { 164 unsigned long flags; 165 int i; 166 167 local_irq_save(flags); 168 for (i = 0; i < num_ictlrs; i++) { 169 void __iomem *ictlr = ictlr_reg_base[i]; 170 /* Save interrupt state */ 171 cpu_ier[i] = readl_relaxed(ictlr + ICTLR_CPU_IER); 172 cpu_iep[i] = readl_relaxed(ictlr + ICTLR_CPU_IEP_CLASS); 173 cop_ier[i] = readl_relaxed(ictlr + ICTLR_COP_IER); 174 cop_iep[i] = readl_relaxed(ictlr + ICTLR_COP_IEP_CLASS); 175 176 /* Disable COP interrupts */ 177 writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR); 178 179 /* Disable CPU interrupts */ 180 writel_relaxed(~0ul, ictlr + ICTLR_CPU_IER_CLR); 181 182 /* Enable the wakeup sources of ictlr */ 183 writel_relaxed(ictlr_wake_mask[i], ictlr + ICTLR_CPU_IER_SET); 184 } 185 local_irq_restore(flags); 186 187 return 0; 188 } 189 190 static void tegra_legacy_irq_resume(void) 191 { 192 unsigned long flags; 193 int i; 194 195 local_irq_save(flags); 196 for (i = 0; i < num_ictlrs; i++) { 197 void __iomem *ictlr = ictlr_reg_base[i]; 198 writel_relaxed(cpu_iep[i], ictlr + ICTLR_CPU_IEP_CLASS); 199 writel_relaxed(~0ul, ictlr + ICTLR_CPU_IER_CLR); 200 writel_relaxed(cpu_ier[i], ictlr + ICTLR_CPU_IER_SET); 201 writel_relaxed(cop_iep[i], ictlr + ICTLR_COP_IEP_CLASS); 202 writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR); 203 writel_relaxed(cop_ier[i], ictlr + ICTLR_COP_IER_SET); 204 } 205 local_irq_restore(flags); 206 } 207 208 static struct syscore_ops tegra_legacy_irq_syscore_ops = { 209 .suspend = tegra_legacy_irq_suspend, 210 .resume = tegra_legacy_irq_resume, 211 }; 212 213 int tegra_legacy_irq_syscore_init(void) 214 { 215 register_syscore_ops(&tegra_legacy_irq_syscore_ops); 216 217 return 0; 218 } 219 220 static int tegra_gic_notifier(struct notifier_block *self, 221 unsigned long cmd, void *v) 222 { 223 switch (cmd) { 224 case CPU_PM_ENTER: 225 writel_relaxed(0x1E0, tegra_gic_cpu_base + GIC_CPU_CTRL); 226 break; 227 } 228 229 return NOTIFY_OK; 230 } 231 232 static struct notifier_block tegra_gic_notifier_block = { 233 .notifier_call = tegra_gic_notifier, 234 }; 235 236 static const struct of_device_id tegra114_dt_gic_match[] __initconst = { 237 { .compatible = "arm,cortex-a15-gic" }, 238 { } 239 }; 240 241 static void tegra114_gic_cpu_pm_registration(void) 242 { 243 struct device_node *dn; 244 245 dn = of_find_matching_node(NULL, tegra114_dt_gic_match); 246 if (!dn) 247 return; 248 249 tegra_gic_cpu_base = of_iomap(dn, 1); 250 251 cpu_pm_register_notifier(&tegra_gic_notifier_block); 252 } 253 #else 254 #define tegra_set_wake NULL 255 static void tegra114_gic_cpu_pm_registration(void) { } 256 #endif 257 258 void __init tegra_init_irq(void) 259 { 260 int i; 261 void __iomem *distbase; 262 263 distbase = IO_ADDRESS(TEGRA_ARM_INT_DIST_BASE); 264 num_ictlrs = readl_relaxed(distbase + GIC_DIST_CTR) & 0x1f; 265 266 if (num_ictlrs > ARRAY_SIZE(ictlr_reg_base)) { 267 WARN(1, "Too many (%d) interrupt controllers found. Maximum is %d.", 268 num_ictlrs, ARRAY_SIZE(ictlr_reg_base)); 269 num_ictlrs = ARRAY_SIZE(ictlr_reg_base); 270 } 271 272 for (i = 0; i < num_ictlrs; i++) { 273 void __iomem *ictlr = ictlr_reg_base[i]; 274 writel(~0, ictlr + ICTLR_CPU_IER_CLR); 275 writel(0, ictlr + ICTLR_CPU_IEP_CLASS); 276 } 277 278 gic_arch_extn.irq_ack = tegra_ack; 279 gic_arch_extn.irq_eoi = tegra_eoi; 280 gic_arch_extn.irq_mask = tegra_mask; 281 gic_arch_extn.irq_unmask = tegra_unmask; 282 gic_arch_extn.irq_retrigger = tegra_retrigger; 283 gic_arch_extn.irq_set_wake = tegra_set_wake; 284 gic_arch_extn.flags = IRQCHIP_MASK_ON_SUSPEND; 285 286 /* 287 * Check if there is a devicetree present, since the GIC will be 288 * initialized elsewhere under DT. 289 */ 290 if (!of_have_populated_dt()) 291 gic_init(0, 29, distbase, 292 IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x100)); 293 294 tegra114_gic_cpu_pm_registration(); 295 } 296