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 53static int num_ictlrs; 54 55static 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 64static u32 cop_ier[TEGRA_MAX_NUM_ICTLRS]; 65static u32 cop_iep[TEGRA_MAX_NUM_ICTLRS]; 66static u32 cpu_ier[TEGRA_MAX_NUM_ICTLRS]; 67static u32 cpu_iep[TEGRA_MAX_NUM_ICTLRS]; 68 69static u32 ictlr_wake_mask[TEGRA_MAX_NUM_ICTLRS]; 70static void __iomem *tegra_gic_cpu_base; 71#endif 72 73bool 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 86static 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 100static void tegra_mask(struct irq_data *d) 101{ 102 if (d->hwirq < FIRST_LEGACY_IRQ) 103 return; 104 105 tegra_irq_write_mask(d->hwirq, ICTLR_CPU_IER_CLR); 106} 107 108static void tegra_unmask(struct irq_data *d) 109{ 110 if (d->hwirq < FIRST_LEGACY_IRQ) 111 return; 112 113 tegra_irq_write_mask(d->hwirq, ICTLR_CPU_IER_SET); 114} 115 116static void tegra_ack(struct irq_data *d) 117{ 118 if (d->hwirq < FIRST_LEGACY_IRQ) 119 return; 120 121 tegra_irq_write_mask(d->hwirq, ICTLR_CPU_IEP_FIR_CLR); 122} 123 124static void tegra_eoi(struct irq_data *d) 125{ 126 if (d->hwirq < FIRST_LEGACY_IRQ) 127 return; 128 129 tegra_irq_write_mask(d->hwirq, ICTLR_CPU_IEP_FIR_CLR); 130} 131 132static int tegra_retrigger(struct irq_data *d) 133{ 134 if (d->hwirq < FIRST_LEGACY_IRQ) 135 return 0; 136 137 tegra_irq_write_mask(d->hwirq, ICTLR_CPU_IEP_FIR_SET); 138 139 return 1; 140} 141 142#ifdef CONFIG_PM_SLEEP 143static int tegra_set_wake(struct irq_data *d, unsigned int enable) 144{ 145 u32 irq = d->hwirq; 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 162static 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 190static 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 208static struct syscore_ops tegra_legacy_irq_syscore_ops = { 209 .suspend = tegra_legacy_irq_suspend, 210 .resume = tegra_legacy_irq_resume, 211}; 212 213int tegra_legacy_irq_syscore_init(void) 214{ 215 register_syscore_ops(&tegra_legacy_irq_syscore_ops); 216 217 return 0; 218} 219 220static 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 232static struct notifier_block tegra_gic_notifier_block = { 233 .notifier_call = tegra_gic_notifier, 234}; 235 236static const struct of_device_id tegra114_dt_gic_match[] __initconst = { 237 { .compatible = "arm,cortex-a15-gic" }, 238 { } 239}; 240 241static 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 255static void tegra114_gic_cpu_pm_registration(void) { } 256#endif 257 258void __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