blob: 7dbf2961da38fb0d0c1a1a0d5ab541d586f86c75 [file] [log] [blame]
Russell Kingf27ecac2005-08-18 21:31:00 +01001/*
2 * linux/arch/arm/common/gic.c
3 *
4 * Copyright (C) 2002 ARM Limited, All Rights Reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * Interrupt architecture for the GIC:
11 *
12 * o There is one Interrupt Distributor, which receives interrupts
13 * from system devices and sends them to the Interrupt Controllers.
14 *
15 * o There is one CPU Interface per CPU, which sends interrupts sent
16 * by the Distributor, and interrupts generated locally, to the
Catalin Marinasb3a1bde2007-02-14 19:14:56 +010017 * associated CPU. The base address of the CPU interface is usually
18 * aliased so that the same address points to different chips depending
19 * on the CPU it is accessed from.
Russell Kingf27ecac2005-08-18 21:31:00 +010020 *
21 * Note that IRQs 0-31 are special - they are local to each CPU.
22 * As such, the enable set/clear, pending set/clear and active bit
23 * registers are banked per-cpu for these sources.
24 */
25#include <linux/init.h>
26#include <linux/kernel.h>
Rob Herringc383e042011-09-28 21:25:31 -050027#include <linux/export.h>
Russell Kingf27ecac2005-08-18 21:31:00 +010028#include <linux/list.h>
29#include <linux/smp.h>
Colin Cross692c3e252011-02-10 12:54:10 -080030#include <linux/cpu_pm.h>
Catalin Marinasdcb86e82005-08-31 21:45:14 +010031#include <linux/cpumask.h>
Russell Kingfced80c2008-09-06 12:10:45 +010032#include <linux/io.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070033#include <linux/syscore_ops.h>
Rob Herringc383e042011-09-28 21:25:31 -050034#include <linux/irqdomain.h>
Trilok Sonieecb28c2011-07-20 16:24:14 +010035#include <linux/interrupt.h>
36#include <linux/percpu.h>
37#include <linux/slab.h>
Russell Kingf27ecac2005-08-18 21:31:00 +010038
39#include <asm/irq.h>
Russell Kingf27ecac2005-08-18 21:31:00 +010040#include <asm/mach/irq.h>
41#include <asm/hardware/gic.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070042#include <asm/system.h>
Trilok Sonieecb28c2011-07-20 16:24:14 +010043#include <asm/localtimer.h>
Russell Kingf27ecac2005-08-18 21:31:00 +010044
Thomas Gleixner450ea482009-07-03 08:44:46 -050045static DEFINE_RAW_SPINLOCK(irq_controller_lock);
Russell Kingf27ecac2005-08-18 21:31:00 +010046
Russell Kingff2e27a2010-12-04 16:13:29 +000047/* Address of GIC 0 CPU interface */
Russell Kingbef8f9e2010-12-04 16:50:58 +000048void __iomem *gic_cpu_base_addr __read_mostly;
Russell Kingff2e27a2010-12-04 16:13:29 +000049
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +010050/*
51 * Supported arch specific GIC irq extension.
52 * Default make them NULL.
53 */
54struct irq_chip gic_arch_extn = {
Will Deacon1a017532011-02-09 12:01:12 +000055 .irq_eoi = NULL,
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +010056 .irq_mask = NULL,
57 .irq_unmask = NULL,
58 .irq_retrigger = NULL,
59 .irq_set_type = NULL,
60 .irq_set_wake = NULL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070061 .irq_disable = NULL,
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +010062};
63
Catalin Marinasb3a1bde2007-02-14 19:14:56 +010064#ifndef MAX_GIC_NR
65#define MAX_GIC_NR 1
66#endif
67
Russell Kingbef8f9e2010-12-04 16:50:58 +000068static struct gic_chip_data gic_data[MAX_GIC_NR] __read_mostly;
Catalin Marinasb3a1bde2007-02-14 19:14:56 +010069
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +010070static inline void __iomem *gic_dist_base(struct irq_data *d)
Catalin Marinasb3a1bde2007-02-14 19:14:56 +010071{
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +010072 struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
Catalin Marinasb3a1bde2007-02-14 19:14:56 +010073 return gic_data->dist_base;
74}
75
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +010076static inline void __iomem *gic_cpu_base(struct irq_data *d)
Catalin Marinasb3a1bde2007-02-14 19:14:56 +010077{
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +010078 struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
Catalin Marinasb3a1bde2007-02-14 19:14:56 +010079 return gic_data->cpu_base;
80}
81
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +010082static inline unsigned int gic_irq(struct irq_data *d)
Catalin Marinasb3a1bde2007-02-14 19:14:56 +010083{
Rob Herringc383e042011-09-28 21:25:31 -050084 return d->hwirq;
Catalin Marinasb3a1bde2007-02-14 19:14:56 +010085}
86
Russell Kingf27ecac2005-08-18 21:31:00 +010087/*
88 * Routines to acknowledge, disable and enable interrupts
Russell Kingf27ecac2005-08-18 21:31:00 +010089 */
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +010090static void gic_mask_irq(struct irq_data *d)
Russell Kingf27ecac2005-08-18 21:31:00 +010091{
Rob Herringc383e042011-09-28 21:25:31 -050092 u32 mask = 1 << (gic_irq(d) % 32);
Thomas Gleixnerc4bfa282006-07-01 22:32:14 +010093
Thomas Gleixner450ea482009-07-03 08:44:46 -050094 raw_spin_lock(&irq_controller_lock);
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +053095 writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_CLEAR + (gic_irq(d) / 32) * 4);
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +010096 if (gic_arch_extn.irq_mask)
97 gic_arch_extn.irq_mask(d);
Thomas Gleixner450ea482009-07-03 08:44:46 -050098 raw_spin_unlock(&irq_controller_lock);
Russell Kingf27ecac2005-08-18 21:31:00 +010099}
100
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100101static void gic_unmask_irq(struct irq_data *d)
Russell Kingf27ecac2005-08-18 21:31:00 +0100102{
Rob Herringc383e042011-09-28 21:25:31 -0500103 u32 mask = 1 << (gic_irq(d) % 32);
Thomas Gleixnerc4bfa282006-07-01 22:32:14 +0100104
Thomas Gleixner450ea482009-07-03 08:44:46 -0500105 raw_spin_lock(&irq_controller_lock);
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100106 if (gic_arch_extn.irq_unmask)
107 gic_arch_extn.irq_unmask(d);
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530108 writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
Thomas Gleixner450ea482009-07-03 08:44:46 -0500109 raw_spin_unlock(&irq_controller_lock);
Russell Kingf27ecac2005-08-18 21:31:00 +0100110}
111
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700112static void gic_disable_irq(struct irq_data *d)
113{
114 if (gic_arch_extn.irq_disable)
115 gic_arch_extn.irq_disable(d);
116}
117
118#ifdef CONFIG_PM
119static int gic_suspend_one(struct gic_chip_data *gic)
120{
121 unsigned int i;
122 void __iomem *base = gic->dist_base;
123
124 for (i = 0; i * 32 < gic->max_irq; i++) {
125 gic->enabled_irqs[i]
126 = readl_relaxed(base + GIC_DIST_ENABLE_SET + i * 4);
127 /* disable all of them */
128 writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4);
129 /* enable the wakeup set */
130 writel_relaxed(gic->wakeup_irqs[i],
131 base + GIC_DIST_ENABLE_SET + i * 4);
132 }
133 mb();
134 return 0;
135}
136
137static int gic_suspend(void)
138{
139 int i;
140 for (i = 0; i < MAX_GIC_NR; i++)
141 gic_suspend_one(&gic_data[i]);
142 return 0;
143}
144
145extern int msm_show_resume_irq_mask;
146
147static void gic_show_resume_irq(struct gic_chip_data *gic)
148{
149 unsigned int i;
150 u32 enabled;
151 unsigned long pending[32];
152 void __iomem *base = gic->dist_base;
153
154 if (!msm_show_resume_irq_mask)
155 return;
156
Thomas Gleixner450ea482009-07-03 08:44:46 -0500157 raw_spin_lock(&irq_controller_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700158 for (i = 0; i * 32 < gic->max_irq; i++) {
159 enabled = readl_relaxed(base + GIC_DIST_ENABLE_CLEAR + i * 4);
160 pending[i] = readl_relaxed(base + GIC_DIST_PENDING_SET + i * 4);
161 pending[i] &= enabled;
162 }
Thomas Gleixner450ea482009-07-03 08:44:46 -0500163 raw_spin_unlock(&irq_controller_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700164
165 for (i = find_first_bit(pending, gic->max_irq);
166 i < gic->max_irq;
167 i = find_next_bit(pending, gic->max_irq, i+1)) {
168 pr_warning("%s: %d triggered", __func__,
169 i + gic->irq_offset);
170 }
171}
172
173static void gic_resume_one(struct gic_chip_data *gic)
174{
175 unsigned int i;
176 void __iomem *base = gic->dist_base;
177
178 gic_show_resume_irq(gic);
179 for (i = 0; i * 32 < gic->max_irq; i++) {
180 /* disable all of them */
181 writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4);
182 /* enable the enabled set */
183 writel_relaxed(gic->enabled_irqs[i],
184 base + GIC_DIST_ENABLE_SET + i * 4);
185 }
186 mb();
187}
188
189static void gic_resume(void)
190{
191 int i;
192 for (i = 0; i < MAX_GIC_NR; i++)
193 gic_resume_one(&gic_data[i]);
194}
195
196static struct syscore_ops gic_syscore_ops = {
197 .suspend = gic_suspend,
198 .resume = gic_resume,
199};
200
201static int __init gic_init_sys(void)
202{
203 register_syscore_ops(&gic_syscore_ops);
204 return 0;
205}
206arch_initcall(gic_init_sys);
207
208#endif
209
Will Deacon1a017532011-02-09 12:01:12 +0000210static void gic_eoi_irq(struct irq_data *d)
211{
212 if (gic_arch_extn.irq_eoi) {
Thomas Gleixner450ea482009-07-03 08:44:46 -0500213 raw_spin_lock(&irq_controller_lock);
Will Deacon1a017532011-02-09 12:01:12 +0000214 gic_arch_extn.irq_eoi(d);
Thomas Gleixner450ea482009-07-03 08:44:46 -0500215 raw_spin_unlock(&irq_controller_lock);
Will Deacon1a017532011-02-09 12:01:12 +0000216 }
217
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530218 writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
Will Deacon1a017532011-02-09 12:01:12 +0000219}
220
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100221static int gic_set_type(struct irq_data *d, unsigned int type)
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100222{
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100223 void __iomem *base = gic_dist_base(d);
224 unsigned int gicirq = gic_irq(d);
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100225 u32 enablemask = 1 << (gicirq % 32);
226 u32 enableoff = (gicirq / 32) * 4;
227 u32 confmask = 0x2 << ((gicirq % 16) * 2);
228 u32 confoff = (gicirq / 16) * 4;
229 bool enabled = false;
230 u32 val;
231
232 /* Interrupt configuration for SGIs can't be changed */
233 if (gicirq < 16)
234 return -EINVAL;
235
236 if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
237 return -EINVAL;
238
Thomas Gleixner450ea482009-07-03 08:44:46 -0500239 raw_spin_lock(&irq_controller_lock);
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100240
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100241 if (gic_arch_extn.irq_set_type)
242 gic_arch_extn.irq_set_type(d, type);
243
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530244 val = readl_relaxed(base + GIC_DIST_CONFIG + confoff);
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100245 if (type == IRQ_TYPE_LEVEL_HIGH)
246 val &= ~confmask;
247 else if (type == IRQ_TYPE_EDGE_RISING)
248 val |= confmask;
249
250 /*
251 * As recommended by the spec, disable the interrupt before changing
252 * the configuration
253 */
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530254 if (readl_relaxed(base + GIC_DIST_ENABLE_SET + enableoff) & enablemask) {
255 writel_relaxed(enablemask, base + GIC_DIST_ENABLE_CLEAR + enableoff);
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100256 enabled = true;
257 }
258
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530259 writel_relaxed(val, base + GIC_DIST_CONFIG + confoff);
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100260
261 if (enabled)
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530262 writel_relaxed(enablemask, base + GIC_DIST_ENABLE_SET + enableoff);
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100263
Thomas Gleixner450ea482009-07-03 08:44:46 -0500264 raw_spin_unlock(&irq_controller_lock);
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100265
266 return 0;
267}
268
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100269static int gic_retrigger(struct irq_data *d)
270{
271 if (gic_arch_extn.irq_retrigger)
272 return gic_arch_extn.irq_retrigger(d);
273
Abhijeet Dharmapurikar9d44ea02011-10-30 16:47:19 -0700274 /* the retrigger expects 0 for failure */
275 return 0;
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100276}
277
Catalin Marinasa06f5462005-09-30 16:07:05 +0100278#ifdef CONFIG_SMP
Russell Kingc1917892011-01-23 12:12:01 +0000279static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
280 bool force)
Russell Kingf27ecac2005-08-18 21:31:00 +0100281{
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100282 void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) & ~3);
Rob Herringc383e042011-09-28 21:25:31 -0500283 unsigned int shift = (gic_irq(d) % 4) * 8;
Russell Kingf3c52e22011-07-21 15:00:57 +0100284 unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask);
Russell Kingc1917892011-01-23 12:12:01 +0000285 u32 val, mask, bit;
286
Russell Kingf3c52e22011-07-21 15:00:57 +0100287 if (cpu >= 8 || cpu >= nr_cpu_ids)
Russell Kingc1917892011-01-23 12:12:01 +0000288 return -EINVAL;
289
290 mask = 0xff << shift;
Will Deacona803a8d2011-08-23 22:20:03 +0100291 bit = 1 << (cpu_logical_map(cpu) + shift);
Russell Kingf27ecac2005-08-18 21:31:00 +0100292
Thomas Gleixner450ea482009-07-03 08:44:46 -0500293 raw_spin_lock(&irq_controller_lock);
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530294 val = readl_relaxed(reg) & ~mask;
295 writel_relaxed(val | bit, reg);
Thomas Gleixner450ea482009-07-03 08:44:46 -0500296 raw_spin_unlock(&irq_controller_lock);
Yinghai Lud5dedd42009-04-27 17:59:21 -0700297
Russell Kingf3c52e22011-07-21 15:00:57 +0100298 return IRQ_SET_MASK_OK;
Russell Kingf27ecac2005-08-18 21:31:00 +0100299}
Catalin Marinasa06f5462005-09-30 16:07:05 +0100300#endif
Russell Kingf27ecac2005-08-18 21:31:00 +0100301
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100302#ifdef CONFIG_PM
303static int gic_set_wake(struct irq_data *d, unsigned int on)
304{
305 int ret = -ENXIO;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700306 unsigned int reg_offset, bit_offset;
307 unsigned int gicirq = gic_irq(d);
308 struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
309
310 /* per-cpu interrupts cannot be wakeup interrupts */
311 WARN_ON(gicirq < 32);
312
313 reg_offset = gicirq / 32;
314 bit_offset = gicirq % 32;
315
316 if (on)
317 gic_data->wakeup_irqs[reg_offset] |= 1 << bit_offset;
318 else
319 gic_data->wakeup_irqs[reg_offset] &= ~(1 << bit_offset);
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100320
321 if (gic_arch_extn.irq_set_wake)
322 ret = gic_arch_extn.irq_set_wake(d, on);
323
324 return ret;
325}
326
327#else
Rohit Vaswani550aa1a2011-10-06 21:15:37 -0700328static int gic_set_wake(struct irq_data *d, unsigned int on)
329{
330 return 0;
331}
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100332#endif
333
Russell King0f347bb2007-05-17 10:11:34 +0100334static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100335{
Thomas Gleixner6845664a2011-03-24 13:25:22 +0100336 struct gic_chip_data *chip_data = irq_get_handler_data(irq);
337 struct irq_chip *chip = irq_get_chip(irq);
Russell King0f347bb2007-05-17 10:11:34 +0100338 unsigned int cascade_irq, gic_irq;
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100339 unsigned long status;
340
Will Deacon1a017532011-02-09 12:01:12 +0000341 chained_irq_enter(chip, desc);
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100342
Thomas Gleixner450ea482009-07-03 08:44:46 -0500343 raw_spin_lock(&irq_controller_lock);
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530344 status = readl_relaxed(chip_data->cpu_base + GIC_CPU_INTACK);
Thomas Gleixner450ea482009-07-03 08:44:46 -0500345 raw_spin_unlock(&irq_controller_lock);
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100346
Russell King0f347bb2007-05-17 10:11:34 +0100347 gic_irq = (status & 0x3ff);
348 if (gic_irq == 1023)
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100349 goto out;
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100350
Rob Herringc383e042011-09-28 21:25:31 -0500351 cascade_irq = irq_domain_to_irq(&chip_data->domain, gic_irq);
Russell King0f347bb2007-05-17 10:11:34 +0100352 if (unlikely(gic_irq < 32 || gic_irq > 1020 || cascade_irq >= NR_IRQS))
353 do_bad_IRQ(cascade_irq, desc);
354 else
355 generic_handle_irq(cascade_irq);
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100356
357 out:
Will Deacon1a017532011-02-09 12:01:12 +0000358 chained_irq_exit(chip, desc);
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100359}
360
David Brownell38c677c2006-08-01 22:26:25 +0100361static struct irq_chip gic_chip = {
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100362 .name = "GIC",
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100363 .irq_mask = gic_mask_irq,
364 .irq_unmask = gic_unmask_irq,
Will Deacon1a017532011-02-09 12:01:12 +0000365 .irq_eoi = gic_eoi_irq,
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100366 .irq_set_type = gic_set_type,
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100367 .irq_retrigger = gic_retrigger,
Russell Kingf27ecac2005-08-18 21:31:00 +0100368#ifdef CONFIG_SMP
Russell Kingc1917892011-01-23 12:12:01 +0000369 .irq_set_affinity = gic_set_affinity,
Russell Kingf27ecac2005-08-18 21:31:00 +0100370#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700371 .irq_disable = gic_disable_irq,
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100372 .irq_set_wake = gic_set_wake,
Russell Kingf27ecac2005-08-18 21:31:00 +0100373};
374
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100375void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
376{
377 if (gic_nr >= MAX_GIC_NR)
378 BUG();
Thomas Gleixner6845664a2011-03-24 13:25:22 +0100379 if (irq_set_handler_data(irq, &gic_data[gic_nr]) != 0)
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100380 BUG();
Thomas Gleixner6845664a2011-03-24 13:25:22 +0100381 irq_set_chained_handler(irq, gic_handle_cascade_irq);
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100382}
383
Rob Herringc383e042011-09-28 21:25:31 -0500384static void __init gic_dist_init(struct gic_chip_data *gic)
Russell Kingf27ecac2005-08-18 21:31:00 +0100385{
Rob Herringc383e042011-09-28 21:25:31 -0500386 unsigned int i, irq;
Will Deacona803a8d2011-08-23 22:20:03 +0100387 u32 cpumask;
Rob Herringc383e042011-09-28 21:25:31 -0500388 unsigned int gic_irqs = gic->gic_irqs;
389 struct irq_domain *domain = &gic->domain;
Russell Kingbef8f9e2010-12-04 16:50:58 +0000390 void __iomem *base = gic->dist_base;
Will Deacona803a8d2011-08-23 22:20:03 +0100391 u32 cpu = 0;
Russell Kingf27ecac2005-08-18 21:31:00 +0100392
Will Deacona803a8d2011-08-23 22:20:03 +0100393#ifdef CONFIG_SMP
394 cpu = cpu_logical_map(smp_processor_id());
395#endif
396
397 cpumask = 1 << cpu;
Russell Kingf27ecac2005-08-18 21:31:00 +0100398 cpumask |= cpumask << 8;
399 cpumask |= cpumask << 16;
400
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530401 writel_relaxed(0, base + GIC_DIST_CTRL);
Russell Kingf27ecac2005-08-18 21:31:00 +0100402
403 /*
Russell Kingf27ecac2005-08-18 21:31:00 +0100404 * Set all global interrupts to be level triggered, active low.
405 */
Pawel Molle6afec92010-11-26 13:45:43 +0100406 for (i = 32; i < gic_irqs; i += 16)
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530407 writel_relaxed(0, base + GIC_DIST_CONFIG + i * 4 / 16);
Russell Kingf27ecac2005-08-18 21:31:00 +0100408
409 /*
410 * Set all global interrupts to this CPU only.
411 */
Pawel Molle6afec92010-11-26 13:45:43 +0100412 for (i = 32; i < gic_irqs; i += 4)
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530413 writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4 / 4);
Russell Kingf27ecac2005-08-18 21:31:00 +0100414
415 /*
Russell King9395f6e2010-11-11 23:10:30 +0000416 * Set priority on all global interrupts.
Russell Kingf27ecac2005-08-18 21:31:00 +0100417 */
Pawel Molle6afec92010-11-26 13:45:43 +0100418 for (i = 32; i < gic_irqs; i += 4)
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530419 writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
Russell Kingf27ecac2005-08-18 21:31:00 +0100420
421 /*
Russell King9395f6e2010-11-11 23:10:30 +0000422 * Disable all interrupts. Leave the PPI and SGIs alone
423 * as these enables are banked registers.
Russell Kingf27ecac2005-08-18 21:31:00 +0100424 */
Pawel Molle6afec92010-11-26 13:45:43 +0100425 for (i = 32; i < gic_irqs; i += 32)
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530426 writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
Russell Kingf27ecac2005-08-18 21:31:00 +0100427
428 /*
429 * Setup the Linux IRQ subsystem.
430 */
Rob Herringc383e042011-09-28 21:25:31 -0500431 irq_domain_for_each_irq(domain, i, irq) {
432 if (i < 32) {
433 irq_set_percpu_devid(irq);
434 irq_set_chip_and_handler(irq, &gic_chip,
435 handle_percpu_devid_irq);
436 set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN);
437 } else {
438 irq_set_chip_and_handler(irq, &gic_chip,
439 handle_fasteoi_irq);
440 set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
441 }
442 irq_set_chip_data(irq, gic);
Russell Kingf27ecac2005-08-18 21:31:00 +0100443 }
444
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700445 gic->max_irq = gic_irqs;
446
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530447 writel_relaxed(1, base + GIC_DIST_CTRL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700448 mb();
Russell Kingf27ecac2005-08-18 21:31:00 +0100449}
450
Russell Kingbef8f9e2010-12-04 16:50:58 +0000451static void __cpuinit gic_cpu_init(struct gic_chip_data *gic)
Russell Kingf27ecac2005-08-18 21:31:00 +0100452{
Russell Kingbef8f9e2010-12-04 16:50:58 +0000453 void __iomem *dist_base = gic->dist_base;
454 void __iomem *base = gic->cpu_base;
Russell King9395f6e2010-11-11 23:10:30 +0000455 int i;
456
Russell King9395f6e2010-11-11 23:10:30 +0000457 /*
458 * Deal with the banked PPI and SGI interrupts - disable all
459 * PPI interrupts, ensure all SGI interrupts are enabled.
460 */
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530461 writel_relaxed(0xffff0000, dist_base + GIC_DIST_ENABLE_CLEAR);
462 writel_relaxed(0x0000ffff, dist_base + GIC_DIST_ENABLE_SET);
Russell King9395f6e2010-11-11 23:10:30 +0000463
464 /*
465 * Set priority on PPI and SGI interrupts
466 */
467 for (i = 0; i < 32; i += 4)
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530468 writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
Russell King9395f6e2010-11-11 23:10:30 +0000469
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530470 writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
471 writel_relaxed(1, base + GIC_CPU_CTRL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700472 mb();
Russell Kingf27ecac2005-08-18 21:31:00 +0100473}
474
Colin Cross692c3e252011-02-10 12:54:10 -0800475#ifdef CONFIG_CPU_PM
476/*
477 * Saves the GIC distributor registers during suspend or idle. Must be called
478 * with interrupts disabled but before powering down the GIC. After calling
479 * this function, no interrupts will be delivered by the GIC, and another
480 * platform-specific wakeup source must be enabled.
481 */
482static void gic_dist_save(unsigned int gic_nr)
483{
484 unsigned int gic_irqs;
485 void __iomem *dist_base;
486 int i;
487
488 if (gic_nr >= MAX_GIC_NR)
489 BUG();
490
491 gic_irqs = gic_data[gic_nr].gic_irqs;
492 dist_base = gic_data[gic_nr].dist_base;
493
494 if (!dist_base)
495 return;
496
497 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 16); i++)
498 gic_data[gic_nr].saved_spi_conf[i] =
499 readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4);
500
501 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
502 gic_data[gic_nr].saved_spi_target[i] =
503 readl_relaxed(dist_base + GIC_DIST_TARGET + i * 4);
504
505 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++)
506 gic_data[gic_nr].saved_spi_enable[i] =
507 readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
508}
509
510/*
511 * Restores the GIC distributor registers during resume or when coming out of
512 * idle. Must be called before enabling interrupts. If a level interrupt
513 * that occured while the GIC was suspended is still present, it will be
514 * handled normally, but any edge interrupts that occured will not be seen by
515 * the GIC and need to be handled by the platform-specific wakeup source.
516 */
517static void gic_dist_restore(unsigned int gic_nr)
518{
519 unsigned int gic_irqs;
520 unsigned int i;
521 void __iomem *dist_base;
522
523 if (gic_nr >= MAX_GIC_NR)
524 BUG();
525
526 gic_irqs = gic_data[gic_nr].gic_irqs;
527 dist_base = gic_data[gic_nr].dist_base;
528
529 if (!dist_base)
530 return;
531
532 writel_relaxed(0, dist_base + GIC_DIST_CTRL);
533
534 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 16); i++)
535 writel_relaxed(gic_data[gic_nr].saved_spi_conf[i],
536 dist_base + GIC_DIST_CONFIG + i * 4);
537
538 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
539 writel_relaxed(0xa0a0a0a0,
540 dist_base + GIC_DIST_PRI + i * 4);
541
542 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
543 writel_relaxed(gic_data[gic_nr].saved_spi_target[i],
544 dist_base + GIC_DIST_TARGET + i * 4);
545
546 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++)
547 writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
548 dist_base + GIC_DIST_ENABLE_SET + i * 4);
549
550 writel_relaxed(1, dist_base + GIC_DIST_CTRL);
551}
552
553static void gic_cpu_save(unsigned int gic_nr)
554{
555 int i;
556 u32 *ptr;
557 void __iomem *dist_base;
558 void __iomem *cpu_base;
559
560 if (gic_nr >= MAX_GIC_NR)
561 BUG();
562
563 dist_base = gic_data[gic_nr].dist_base;
564 cpu_base = gic_data[gic_nr].cpu_base;
565
566 if (!dist_base || !cpu_base)
567 return;
568
569 ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_enable);
570 for (i = 0; i < DIV_ROUND_UP(32, 32); i++)
571 ptr[i] = readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
572
573 ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_conf);
574 for (i = 0; i < DIV_ROUND_UP(32, 16); i++)
575 ptr[i] = readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4);
576
577}
578
579static void gic_cpu_restore(unsigned int gic_nr)
580{
581 int i;
582 u32 *ptr;
583 void __iomem *dist_base;
584 void __iomem *cpu_base;
585
586 if (gic_nr >= MAX_GIC_NR)
587 BUG();
588
589 dist_base = gic_data[gic_nr].dist_base;
590 cpu_base = gic_data[gic_nr].cpu_base;
591
592 if (!dist_base || !cpu_base)
593 return;
594
595 ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_enable);
596 for (i = 0; i < DIV_ROUND_UP(32, 32); i++)
597 writel_relaxed(ptr[i], dist_base + GIC_DIST_ENABLE_SET + i * 4);
598
599 ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_conf);
600 for (i = 0; i < DIV_ROUND_UP(32, 16); i++)
601 writel_relaxed(ptr[i], dist_base + GIC_DIST_CONFIG + i * 4);
602
603 for (i = 0; i < DIV_ROUND_UP(32, 4); i++)
604 writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
605
606 writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
607 writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
608}
609
610static int gic_notifier(struct notifier_block *self, unsigned long cmd, void *v)
611{
612 int i;
613
614 for (i = 0; i < MAX_GIC_NR; i++) {
615 switch (cmd) {
616 case CPU_PM_ENTER:
617 gic_cpu_save(i);
618 break;
619 case CPU_PM_ENTER_FAILED:
620 case CPU_PM_EXIT:
621 gic_cpu_restore(i);
622 break;
623 case CPU_CLUSTER_PM_ENTER:
624 gic_dist_save(i);
625 break;
626 case CPU_CLUSTER_PM_ENTER_FAILED:
627 case CPU_CLUSTER_PM_EXIT:
628 gic_dist_restore(i);
629 break;
630 }
631 }
632
633 return NOTIFY_OK;
634}
635
636static struct notifier_block gic_notifier_block = {
637 .notifier_call = gic_notifier,
638};
639
640static void __init gic_pm_init(struct gic_chip_data *gic)
641{
642 gic->saved_ppi_enable = __alloc_percpu(DIV_ROUND_UP(32, 32) * 4,
643 sizeof(u32));
644 BUG_ON(!gic->saved_ppi_enable);
645
646 gic->saved_ppi_conf = __alloc_percpu(DIV_ROUND_UP(32, 16) * 4,
647 sizeof(u32));
648 BUG_ON(!gic->saved_ppi_conf);
649
650 cpu_pm_register_notifier(&gic_notifier_block);
651}
652#else
653static void __init gic_pm_init(struct gic_chip_data *gic)
654{
655}
656#endif
657
Rob Herringc383e042011-09-28 21:25:31 -0500658const struct irq_domain_ops gic_irq_domain_ops = {
659};
660
Russell Kingb580b892010-12-04 15:55:14 +0000661void __init gic_init(unsigned int gic_nr, unsigned int irq_start,
662 void __iomem *dist_base, void __iomem *cpu_base)
663{
Russell Kingbef8f9e2010-12-04 16:50:58 +0000664 struct gic_chip_data *gic;
Rob Herringc383e042011-09-28 21:25:31 -0500665 struct irq_domain *domain;
666 int gic_irqs;
Russell Kingbef8f9e2010-12-04 16:50:58 +0000667
668 BUG_ON(gic_nr >= MAX_GIC_NR);
669
670 gic = &gic_data[gic_nr];
Rob Herringc383e042011-09-28 21:25:31 -0500671 domain = &gic->domain;
Russell Kingbef8f9e2010-12-04 16:50:58 +0000672 gic->dist_base = dist_base;
673 gic->cpu_base = cpu_base;
Russell Kingbef8f9e2010-12-04 16:50:58 +0000674
Rob Herringc383e042011-09-28 21:25:31 -0500675 /*
676 * For primary GICs, skip over SGIs.
677 * For secondary GICs, skip over PPIs, too.
678 */
679 if (gic_nr == 0) {
Russell Kingff2e27a2010-12-04 16:13:29 +0000680 gic_cpu_base_addr = cpu_base;
Rob Herringc383e042011-09-28 21:25:31 -0500681 domain->hwirq_base = 16;
682 irq_start = (irq_start & ~31) + 16;
683 } else
684 domain->hwirq_base = 32;
685
686 /*
687 * Find out how many interrupts are supported.
688 * The GIC only supports up to 1020 interrupt sources.
689 */
690 gic_irqs = readl_relaxed(dist_base + GIC_DIST_CTR) & 0x1f;
691 gic_irqs = (gic_irqs + 1) * 32;
692 if (gic_irqs > 1020)
693 gic_irqs = 1020;
694 gic->gic_irqs = gic_irqs;
695
696 domain->nr_irq = gic_irqs - domain->hwirq_base;
697 domain->irq_base = irq_alloc_descs(-1, irq_start, domain->nr_irq,
698 numa_node_id());
699 domain->priv = gic;
700 domain->ops = &gic_irq_domain_ops;
701 irq_domain_add(domain);
Russell Kingbef8f9e2010-12-04 16:50:58 +0000702
Colin Cross692c3e252011-02-10 12:54:10 -0800703 gic_chip.flags |= gic_arch_extn.flags;
Rob Herringc383e042011-09-28 21:25:31 -0500704 gic_dist_init(gic);
Russell Kingbef8f9e2010-12-04 16:50:58 +0000705 gic_cpu_init(gic);
Colin Cross692c3e252011-02-10 12:54:10 -0800706 gic_pm_init(gic);
Russell Kingb580b892010-12-04 15:55:14 +0000707}
708
Russell King38489532010-12-04 16:01:03 +0000709void __cpuinit gic_secondary_init(unsigned int gic_nr)
710{
Russell Kingbef8f9e2010-12-04 16:50:58 +0000711 BUG_ON(gic_nr >= MAX_GIC_NR);
712
713 gic_cpu_init(&gic_data[gic_nr]);
Russell King38489532010-12-04 16:01:03 +0000714}
715
Russell Kingf27ecac2005-08-18 21:31:00 +0100716#ifdef CONFIG_SMP
Russell King82668102009-05-17 16:20:18 +0100717void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
Russell Kingf27ecac2005-08-18 21:31:00 +0100718{
Will Deacona803a8d2011-08-23 22:20:03 +0100719 int cpu;
720 unsigned long map = 0;
721
722 /* Convert our logical CPU mask into a physical one. */
723 for_each_cpu(cpu, mask)
724 map |= 1 << cpu_logical_map(cpu);
Russell Kingf27ecac2005-08-18 21:31:00 +0100725
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530726 /*
727 * Ensure that stores to Normal memory are visible to the
728 * other CPUs before issuing the IPI.
729 */
730 dsb();
731
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100732 /* this always happens on GIC0 */
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530733 writel_relaxed(map << 16 | irq, gic_data[0].dist_base + GIC_DIST_SOFTINT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700734 mb();
Russell Kingf27ecac2005-08-18 21:31:00 +0100735}
736#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700737
738/* before calling this function the interrupts should be disabled
739 * and the irq must be disabled at gic to avoid spurious interrupts */
740bool gic_is_spi_pending(unsigned int irq)
741{
742 struct irq_data *d = irq_get_irq_data(irq);
743 struct gic_chip_data *gic_data = &gic_data[0];
744 u32 mask, val;
745
746 WARN_ON(!irqs_disabled());
Thomas Gleixner450ea482009-07-03 08:44:46 -0500747 raw_spin_lock(&irq_controller_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700748 mask = 1 << (gic_irq(d) % 32);
749 val = readl(gic_dist_base(d) +
750 GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
751 /* warn if the interrupt is enabled */
752 WARN_ON(val & mask);
753 val = readl(gic_dist_base(d) +
754 GIC_DIST_PENDING_SET + (gic_irq(d) / 32) * 4);
Thomas Gleixner450ea482009-07-03 08:44:46 -0500755 raw_spin_unlock(&irq_controller_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700756 return (bool) (val & mask);
757}
758
759/* before calling this function the interrupts should be disabled
760 * and the irq must be disabled at gic to avoid spurious interrupts */
761void gic_clear_spi_pending(unsigned int irq)
762{
763 struct gic_chip_data *gic_data = &gic_data[0];
764 struct irq_data *d = irq_get_irq_data(irq);
765
766 u32 mask, val;
767 WARN_ON(!irqs_disabled());
Thomas Gleixner450ea482009-07-03 08:44:46 -0500768 raw_spin_lock(&irq_controller_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700769 mask = 1 << (gic_irq(d) % 32);
770 val = readl(gic_dist_base(d) +
771 GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
772 /* warn if the interrupt is enabled */
773 WARN_ON(val & mask);
774 writel(mask, gic_dist_base(d) +
775 GIC_DIST_PENDING_CLEAR + (gic_irq(d) / 32) * 4);
Thomas Gleixner450ea482009-07-03 08:44:46 -0500776 raw_spin_unlock(&irq_controller_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700777}