blob: 88c4862e72e905099e8d85d9d98255ed7877cbe3 [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 Herringf37a53c2011-10-21 17:14:27 -050027#include <linux/err.h>
Arnd Bergmann7e1efcf2011-11-01 00:28:37 +010028#include <linux/module.h>
Russell Kingf27ecac2005-08-18 21:31:00 +010029#include <linux/list.h>
30#include <linux/smp.h>
Colin Cross254056f2011-02-10 12:54:10 -080031#include <linux/cpu_pm.h>
Catalin Marinasdcb86e82005-08-31 21:45:14 +010032#include <linux/cpumask.h>
Russell Kingfced80c2008-09-06 12:10:45 +010033#include <linux/io.h>
Rob Herringb3f7ed02011-09-28 21:27:52 -050034#include <linux/of.h>
35#include <linux/of_address.h>
36#include <linux/of_irq.h>
Rob Herring4294f8b2011-09-28 21:25:31 -050037#include <linux/irqdomain.h>
Marc Zyngier292b2932011-07-20 16:24:14 +010038#include <linux/interrupt.h>
39#include <linux/percpu.h>
40#include <linux/slab.h>
Steve Mucklef132c6c2012-06-06 18:30:57 -070041#include <linux/syscore_ops.h>
Russell Kingf27ecac2005-08-18 21:31:00 +010042
43#include <asm/irq.h>
Marc Zyngier562e0022011-09-06 09:56:17 +010044#include <asm/exception.h>
Will Deaconeb504392012-01-20 12:01:12 +010045#include <asm/smp_plat.h>
Russell Kingf27ecac2005-08-18 21:31:00 +010046#include <asm/mach/irq.h>
47#include <asm/hardware/gic.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070048#include <asm/system.h>
Russell Kingf27ecac2005-08-18 21:31:00 +010049
Marc Zyngierdb0d4db2011-11-12 16:09:49 +000050union gic_base {
51 void __iomem *common_base;
52 void __percpu __iomem **percpu_base;
53};
54
55struct gic_chip_data {
Marc Zyngier680392b2011-11-12 16:09:49 +000056 unsigned int irq_offset;
Marc Zyngierdb0d4db2011-11-12 16:09:49 +000057 union gic_base dist_base;
58 union gic_base cpu_base;
59#ifdef CONFIG_CPU_PM
60 u32 saved_spi_enable[DIV_ROUND_UP(1020, 32)];
61 u32 saved_spi_conf[DIV_ROUND_UP(1020, 16)];
62 u32 saved_spi_target[DIV_ROUND_UP(1020, 4)];
Rohit Vaswani26e44862012-01-05 20:26:40 -080063 u32 saved_dist_pri[DIV_ROUND_UP(1020, 4)];
Marc Zyngierdb0d4db2011-11-12 16:09:49 +000064 u32 __percpu *saved_ppi_enable;
65 u32 __percpu *saved_ppi_conf;
66#endif
Michael Bohanbb6b30f2012-06-01 13:33:51 -070067 struct irq_domain *domain;
Marc Zyngierdb0d4db2011-11-12 16:09:49 +000068 unsigned int gic_irqs;
69#ifdef CONFIG_GIC_NON_BANKED
70 void __iomem *(*get_base)(union gic_base *);
71#endif
Steve Mucklef132c6c2012-06-06 18:30:57 -070072 unsigned int max_irq;
73#ifdef CONFIG_PM
74 unsigned int wakeup_irqs[32];
75 unsigned int enabled_irqs[32];
76#endif
Marc Zyngierdb0d4db2011-11-12 16:09:49 +000077};
78
Thomas Gleixnerbd31b852009-07-03 08:44:46 -050079static DEFINE_RAW_SPINLOCK(irq_controller_lock);
Russell Kingf27ecac2005-08-18 21:31:00 +010080
Rohit Vaswani26e44862012-01-05 20:26:40 -080081#ifdef CONFIG_CPU_PM
82static unsigned int saved_dist_ctrl, saved_cpu_ctrl;
83#endif
84
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +010085/*
86 * Supported arch specific GIC irq extension.
87 * Default make them NULL.
88 */
89struct irq_chip gic_arch_extn = {
Will Deacon1a017532011-02-09 12:01:12 +000090 .irq_eoi = NULL,
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +010091 .irq_mask = NULL,
92 .irq_unmask = NULL,
93 .irq_retrigger = NULL,
94 .irq_set_type = NULL,
95 .irq_set_wake = NULL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070096 .irq_disable = NULL,
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +010097};
98
Catalin Marinasb3a1bde2007-02-14 19:14:56 +010099#ifndef MAX_GIC_NR
100#define MAX_GIC_NR 1
101#endif
102
Russell Kingbef8f9e2010-12-04 16:50:58 +0000103static struct gic_chip_data gic_data[MAX_GIC_NR] __read_mostly;
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100104
Marc Zyngierdb0d4db2011-11-12 16:09:49 +0000105#ifdef CONFIG_GIC_NON_BANKED
106static void __iomem *gic_get_percpu_base(union gic_base *base)
107{
108 return *__this_cpu_ptr(base->percpu_base);
109}
110
111static void __iomem *gic_get_common_base(union gic_base *base)
112{
113 return base->common_base;
114}
115
116static inline void __iomem *gic_data_dist_base(struct gic_chip_data *data)
117{
118 return data->get_base(&data->dist_base);
119}
120
121static inline void __iomem *gic_data_cpu_base(struct gic_chip_data *data)
122{
123 return data->get_base(&data->cpu_base);
124}
125
126static inline void gic_set_base_accessor(struct gic_chip_data *data,
127 void __iomem *(*f)(union gic_base *))
128{
129 data->get_base = f;
130}
131#else
132#define gic_data_dist_base(d) ((d)->dist_base.common_base)
133#define gic_data_cpu_base(d) ((d)->cpu_base.common_base)
134#define gic_set_base_accessor(d,f)
135#endif
136
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100137static inline void __iomem *gic_dist_base(struct irq_data *d)
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100138{
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100139 struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
Marc Zyngierdb0d4db2011-11-12 16:09:49 +0000140 return gic_data_dist_base(gic_data);
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100141}
142
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100143static inline void __iomem *gic_cpu_base(struct irq_data *d)
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100144{
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100145 struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
Marc Zyngierdb0d4db2011-11-12 16:09:49 +0000146 return gic_data_cpu_base(gic_data);
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100147}
148
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100149static inline unsigned int gic_irq(struct irq_data *d)
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100150{
Rob Herring4294f8b2011-09-28 21:25:31 -0500151 return d->hwirq;
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100152}
153
Taniya Dasb241bd82012-03-19 17:58:06 +0530154#if defined(CONFIG_CPU_V7) && defined(CONFIG_GIC_SECURE)
Rohit Vaswani26e44862012-01-05 20:26:40 -0800155static const inline bool is_cpu_secure(void)
156{
157 unsigned int dscr;
158
159 asm volatile ("mrc p14, 0, %0, c0, c1, 0" : "=r" (dscr));
160
161 /* BIT(18) - NS bit; 1 = NS; 0 = S */
162 if (BIT(18) & dscr)
163 return false;
164 else
165 return true;
166}
167#else
168static const inline bool is_cpu_secure(void)
169{
170 return false;
171}
172#endif
173
Russell Kingf27ecac2005-08-18 21:31:00 +0100174/*
175 * Routines to acknowledge, disable and enable interrupts
Russell Kingf27ecac2005-08-18 21:31:00 +0100176 */
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100177static void gic_mask_irq(struct irq_data *d)
Russell Kingf27ecac2005-08-18 21:31:00 +0100178{
Rob Herring4294f8b2011-09-28 21:25:31 -0500179 u32 mask = 1 << (gic_irq(d) % 32);
Thomas Gleixnerc4bfa282006-07-01 22:32:14 +0100180
Thomas Gleixnerbd31b852009-07-03 08:44:46 -0500181 raw_spin_lock(&irq_controller_lock);
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530182 writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_CLEAR + (gic_irq(d) / 32) * 4);
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100183 if (gic_arch_extn.irq_mask)
184 gic_arch_extn.irq_mask(d);
Thomas Gleixnerbd31b852009-07-03 08:44:46 -0500185 raw_spin_unlock(&irq_controller_lock);
Russell Kingf27ecac2005-08-18 21:31:00 +0100186}
187
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100188static void gic_unmask_irq(struct irq_data *d)
Russell Kingf27ecac2005-08-18 21:31:00 +0100189{
Rob Herring4294f8b2011-09-28 21:25:31 -0500190 u32 mask = 1 << (gic_irq(d) % 32);
Thomas Gleixnerc4bfa282006-07-01 22:32:14 +0100191
Thomas Gleixnerbd31b852009-07-03 08:44:46 -0500192 raw_spin_lock(&irq_controller_lock);
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100193 if (gic_arch_extn.irq_unmask)
194 gic_arch_extn.irq_unmask(d);
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530195 writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
Thomas Gleixnerbd31b852009-07-03 08:44:46 -0500196 raw_spin_unlock(&irq_controller_lock);
Russell Kingf27ecac2005-08-18 21:31:00 +0100197}
198
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700199static void gic_disable_irq(struct irq_data *d)
200{
201 if (gic_arch_extn.irq_disable)
202 gic_arch_extn.irq_disable(d);
203}
204
205#ifdef CONFIG_PM
206static int gic_suspend_one(struct gic_chip_data *gic)
207{
208 unsigned int i;
Marc Zyngier680392b2011-11-12 16:09:49 +0000209 void __iomem *base = gic_data_dist_base(gic);
Trilok Soni6278db02012-05-20 01:29:52 +0530210#ifdef CONFIG_ARCH_MSM8625
211 unsigned long flags;
212#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700213
214 for (i = 0; i * 32 < gic->max_irq; i++) {
Taniya Das66398862012-04-30 12:24:17 +0530215#ifdef CONFIG_ARCH_MSM8625
Trilok Soni6278db02012-05-20 01:29:52 +0530216 raw_spin_lock_irqsave(&irq_controller_lock, flags);
Taniya Das66398862012-04-30 12:24:17 +0530217#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700218 gic->enabled_irqs[i]
219 = readl_relaxed(base + GIC_DIST_ENABLE_SET + i * 4);
220 /* disable all of them */
221 writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4);
222 /* enable the wakeup set */
223 writel_relaxed(gic->wakeup_irqs[i],
224 base + GIC_DIST_ENABLE_SET + i * 4);
Taniya Das66398862012-04-30 12:24:17 +0530225#ifdef CONFIG_ARCH_MSM8625
Trilok Soni6278db02012-05-20 01:29:52 +0530226 raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
Taniya Das66398862012-04-30 12:24:17 +0530227#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700228 }
229 mb();
230 return 0;
231}
232
233static int gic_suspend(void)
234{
235 int i;
236 for (i = 0; i < MAX_GIC_NR; i++)
237 gic_suspend_one(&gic_data[i]);
238 return 0;
239}
240
241extern int msm_show_resume_irq_mask;
242
243static void gic_show_resume_irq(struct gic_chip_data *gic)
244{
245 unsigned int i;
246 u32 enabled;
247 unsigned long pending[32];
Marc Zyngier680392b2011-11-12 16:09:49 +0000248 void __iomem *base = gic_data_dist_base(gic);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700249
250 if (!msm_show_resume_irq_mask)
251 return;
252
Thomas Gleixner450ea482009-07-03 08:44:46 -0500253 raw_spin_lock(&irq_controller_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700254 for (i = 0; i * 32 < gic->max_irq; i++) {
255 enabled = readl_relaxed(base + GIC_DIST_ENABLE_CLEAR + i * 4);
256 pending[i] = readl_relaxed(base + GIC_DIST_PENDING_SET + i * 4);
257 pending[i] &= enabled;
258 }
Trilok Soni1bf3f2d2012-05-26 11:58:59 +0530259 raw_spin_unlock(&irq_controller_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700260
261 for (i = find_first_bit(pending, gic->max_irq);
262 i < gic->max_irq;
263 i = find_next_bit(pending, gic->max_irq, i+1)) {
264 pr_warning("%s: %d triggered", __func__,
265 i + gic->irq_offset);
266 }
267}
268
269static void gic_resume_one(struct gic_chip_data *gic)
270{
271 unsigned int i;
Marc Zyngier680392b2011-11-12 16:09:49 +0000272 void __iomem *base = gic_data_dist_base(gic);
Trilok Soni1bf3f2d2012-05-26 11:58:59 +0530273
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700274 gic_show_resume_irq(gic);
275 for (i = 0; i * 32 < gic->max_irq; i++) {
276 /* disable all of them */
277 writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4);
278 /* enable the enabled set */
279 writel_relaxed(gic->enabled_irqs[i],
280 base + GIC_DIST_ENABLE_SET + i * 4);
281 }
282 mb();
283}
284
285static void gic_resume(void)
286{
287 int i;
288 for (i = 0; i < MAX_GIC_NR; i++)
289 gic_resume_one(&gic_data[i]);
290}
291
292static struct syscore_ops gic_syscore_ops = {
293 .suspend = gic_suspend,
294 .resume = gic_resume,
295};
296
297static int __init gic_init_sys(void)
298{
299 register_syscore_ops(&gic_syscore_ops);
300 return 0;
301}
302arch_initcall(gic_init_sys);
303
304#endif
305
Will Deacon1a017532011-02-09 12:01:12 +0000306static void gic_eoi_irq(struct irq_data *d)
307{
308 if (gic_arch_extn.irq_eoi) {
Thomas Gleixnerbd31b852009-07-03 08:44:46 -0500309 raw_spin_lock(&irq_controller_lock);
Will Deacon1a017532011-02-09 12:01:12 +0000310 gic_arch_extn.irq_eoi(d);
Thomas Gleixnerbd31b852009-07-03 08:44:46 -0500311 raw_spin_unlock(&irq_controller_lock);
Will Deacon1a017532011-02-09 12:01:12 +0000312 }
Taniya Das66398862012-04-30 12:24:17 +0530313#ifdef CONFIG_ARCH_MSM8625
314 raw_spin_lock(&irq_controller_lock);
315#endif
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530316 writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
Taniya Das66398862012-04-30 12:24:17 +0530317#ifdef CONFIG_ARCH_MSM8625
318 raw_spin_unlock(&irq_controller_lock);
319#endif
Will Deacon1a017532011-02-09 12:01:12 +0000320}
321
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100322static int gic_set_type(struct irq_data *d, unsigned int type)
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100323{
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100324 void __iomem *base = gic_dist_base(d);
325 unsigned int gicirq = gic_irq(d);
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100326 u32 enablemask = 1 << (gicirq % 32);
327 u32 enableoff = (gicirq / 32) * 4;
328 u32 confmask = 0x2 << ((gicirq % 16) * 2);
329 u32 confoff = (gicirq / 16) * 4;
330 bool enabled = false;
331 u32 val;
332
333 /* Interrupt configuration for SGIs can't be changed */
334 if (gicirq < 16)
335 return -EINVAL;
336
337 if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
338 return -EINVAL;
339
Thomas Gleixnerbd31b852009-07-03 08:44:46 -0500340 raw_spin_lock(&irq_controller_lock);
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100341
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100342 if (gic_arch_extn.irq_set_type)
343 gic_arch_extn.irq_set_type(d, type);
344
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530345 val = readl_relaxed(base + GIC_DIST_CONFIG + confoff);
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100346 if (type == IRQ_TYPE_LEVEL_HIGH)
347 val &= ~confmask;
348 else if (type == IRQ_TYPE_EDGE_RISING)
349 val |= confmask;
350
351 /*
352 * As recommended by the spec, disable the interrupt before changing
353 * the configuration
354 */
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530355 if (readl_relaxed(base + GIC_DIST_ENABLE_SET + enableoff) & enablemask) {
356 writel_relaxed(enablemask, base + GIC_DIST_ENABLE_CLEAR + enableoff);
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100357 enabled = true;
358 }
359
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530360 writel_relaxed(val, base + GIC_DIST_CONFIG + confoff);
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100361
362 if (enabled)
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530363 writel_relaxed(enablemask, base + GIC_DIST_ENABLE_SET + enableoff);
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100364
Thomas Gleixnerbd31b852009-07-03 08:44:46 -0500365 raw_spin_unlock(&irq_controller_lock);
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100366
367 return 0;
368}
369
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100370static int gic_retrigger(struct irq_data *d)
371{
372 if (gic_arch_extn.irq_retrigger)
373 return gic_arch_extn.irq_retrigger(d);
374
375 return -ENXIO;
376}
377
Catalin Marinasa06f5462005-09-30 16:07:05 +0100378#ifdef CONFIG_SMP
Russell Kingc1917892011-01-23 12:12:01 +0000379static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
380 bool force)
Russell Kingf27ecac2005-08-18 21:31:00 +0100381{
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100382 void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) & ~3);
Rob Herring4294f8b2011-09-28 21:25:31 -0500383 unsigned int shift = (gic_irq(d) % 4) * 8;
Russell King5dfc54e2011-07-21 15:00:57 +0100384 unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask);
Russell Kingc1917892011-01-23 12:12:01 +0000385 u32 val, mask, bit;
386
Russell King5dfc54e2011-07-21 15:00:57 +0100387 if (cpu >= 8 || cpu >= nr_cpu_ids)
Russell Kingc1917892011-01-23 12:12:01 +0000388 return -EINVAL;
389
390 mask = 0xff << shift;
Will Deacon267840f2011-08-23 22:20:03 +0100391 bit = 1 << (cpu_logical_map(cpu) + shift);
Russell Kingf27ecac2005-08-18 21:31:00 +0100392
Thomas Gleixnerbd31b852009-07-03 08:44:46 -0500393 raw_spin_lock(&irq_controller_lock);
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530394 val = readl_relaxed(reg) & ~mask;
395 writel_relaxed(val | bit, reg);
Thomas Gleixnerbd31b852009-07-03 08:44:46 -0500396 raw_spin_unlock(&irq_controller_lock);
Yinghai Lud5dedd42009-04-27 17:59:21 -0700397
Russell King5dfc54e2011-07-21 15:00:57 +0100398 return IRQ_SET_MASK_OK;
Russell Kingf27ecac2005-08-18 21:31:00 +0100399}
Catalin Marinasa06f5462005-09-30 16:07:05 +0100400#endif
Russell Kingf27ecac2005-08-18 21:31:00 +0100401
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100402#ifdef CONFIG_PM
403static int gic_set_wake(struct irq_data *d, unsigned int on)
404{
405 int ret = -ENXIO;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700406 unsigned int reg_offset, bit_offset;
407 unsigned int gicirq = gic_irq(d);
408 struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
409
410 /* per-cpu interrupts cannot be wakeup interrupts */
411 WARN_ON(gicirq < 32);
412
413 reg_offset = gicirq / 32;
414 bit_offset = gicirq % 32;
415
416 if (on)
417 gic_data->wakeup_irqs[reg_offset] |= 1 << bit_offset;
418 else
419 gic_data->wakeup_irqs[reg_offset] &= ~(1 << bit_offset);
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100420
421 if (gic_arch_extn.irq_set_wake)
422 ret = gic_arch_extn.irq_set_wake(d, on);
423
424 return ret;
425}
426
427#else
428#define gic_set_wake NULL
429#endif
430
Marc Zyngier562e0022011-09-06 09:56:17 +0100431asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
432{
433 u32 irqstat, irqnr;
434 struct gic_chip_data *gic = &gic_data[0];
435 void __iomem *cpu_base = gic_data_cpu_base(gic);
436
437 do {
Taniya Das66398862012-04-30 12:24:17 +0530438#ifdef CONFIG_ARCH_MSM8625
439 raw_spin_lock(&irq_controller_lock);
440#endif
Marc Zyngier562e0022011-09-06 09:56:17 +0100441 irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
Taniya Das66398862012-04-30 12:24:17 +0530442#ifdef CONFIG_ARCH_MSM8625
443 raw_spin_unlock(&irq_controller_lock);
444#endif
Marc Zyngier562e0022011-09-06 09:56:17 +0100445 irqnr = irqstat & ~0x1c00;
446
447 if (likely(irqnr > 15 && irqnr < 1021)) {
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700448 irqnr = irq_find_mapping(gic->domain, irqnr);
Marc Zyngier562e0022011-09-06 09:56:17 +0100449 handle_IRQ(irqnr, regs);
450 continue;
451 }
452 if (irqnr < 16) {
Taniya Das66398862012-04-30 12:24:17 +0530453#ifdef CONFIG_ARCH_MSM8625
454 raw_spin_lock(&irq_controller_lock);
455#endif
Marc Zyngier562e0022011-09-06 09:56:17 +0100456 writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
Taniya Das66398862012-04-30 12:24:17 +0530457#ifdef CONFIG_ARCH_MSM8625
458 raw_spin_unlock(&irq_controller_lock);
459#endif
Marc Zyngier562e0022011-09-06 09:56:17 +0100460#ifdef CONFIG_SMP
461 handle_IPI(irqnr, regs);
462#endif
463 continue;
464 }
465 break;
466 } while (1);
467}
468
Russell King0f347bb2007-05-17 10:11:34 +0100469static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100470{
Thomas Gleixner6845664a2011-03-24 13:25:22 +0100471 struct gic_chip_data *chip_data = irq_get_handler_data(irq);
472 struct irq_chip *chip = irq_get_chip(irq);
Russell King0f347bb2007-05-17 10:11:34 +0100473 unsigned int cascade_irq, gic_irq;
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100474 unsigned long status;
475
Will Deacon1a017532011-02-09 12:01:12 +0000476 chained_irq_enter(chip, desc);
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100477
Thomas Gleixnerbd31b852009-07-03 08:44:46 -0500478 raw_spin_lock(&irq_controller_lock);
Marc Zyngierdb0d4db2011-11-12 16:09:49 +0000479 status = readl_relaxed(gic_data_cpu_base(chip_data) + GIC_CPU_INTACK);
Thomas Gleixnerbd31b852009-07-03 08:44:46 -0500480 raw_spin_unlock(&irq_controller_lock);
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100481
Russell King0f347bb2007-05-17 10:11:34 +0100482 gic_irq = (status & 0x3ff);
483 if (gic_irq == 1023)
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100484 goto out;
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100485
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700486 cascade_irq = irq_find_mapping(chip_data->domain, gic_irq);
487 if (unlikely(gic_irq < 32 || gic_irq > 1020))
Russell King0f347bb2007-05-17 10:11:34 +0100488 do_bad_IRQ(cascade_irq, desc);
489 else
490 generic_handle_irq(cascade_irq);
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100491
492 out:
Will Deacon1a017532011-02-09 12:01:12 +0000493 chained_irq_exit(chip, desc);
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100494}
495
David Brownell38c677c2006-08-01 22:26:25 +0100496static struct irq_chip gic_chip = {
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100497 .name = "GIC",
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100498 .irq_mask = gic_mask_irq,
499 .irq_unmask = gic_unmask_irq,
Will Deacon1a017532011-02-09 12:01:12 +0000500 .irq_eoi = gic_eoi_irq,
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100501 .irq_set_type = gic_set_type,
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100502 .irq_retrigger = gic_retrigger,
Russell Kingf27ecac2005-08-18 21:31:00 +0100503#ifdef CONFIG_SMP
Russell Kingc1917892011-01-23 12:12:01 +0000504 .irq_set_affinity = gic_set_affinity,
Russell Kingf27ecac2005-08-18 21:31:00 +0100505#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700506 .irq_disable = gic_disable_irq,
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100507 .irq_set_wake = gic_set_wake,
Russell Kingf27ecac2005-08-18 21:31:00 +0100508};
509
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100510void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
511{
512 if (gic_nr >= MAX_GIC_NR)
513 BUG();
Thomas Gleixner6845664a2011-03-24 13:25:22 +0100514 if (irq_set_handler_data(irq, &gic_data[gic_nr]) != 0)
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100515 BUG();
Thomas Gleixner6845664a2011-03-24 13:25:22 +0100516 irq_set_chained_handler(irq, gic_handle_cascade_irq);
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100517}
518
Rob Herring4294f8b2011-09-28 21:25:31 -0500519static void __init gic_dist_init(struct gic_chip_data *gic)
Russell Kingf27ecac2005-08-18 21:31:00 +0100520{
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700521 unsigned int i;
Will Deacon267840f2011-08-23 22:20:03 +0100522 u32 cpumask;
Rob Herring4294f8b2011-09-28 21:25:31 -0500523 unsigned int gic_irqs = gic->gic_irqs;
Marc Zyngierdb0d4db2011-11-12 16:09:49 +0000524 void __iomem *base = gic_data_dist_base(gic);
Will Deaconeb504392012-01-20 12:01:12 +0100525 u32 cpu = cpu_logical_map(smp_processor_id());
Will Deacon267840f2011-08-23 22:20:03 +0100526
527 cpumask = 1 << cpu;
Russell Kingf27ecac2005-08-18 21:31:00 +0100528 cpumask |= cpumask << 8;
529 cpumask |= cpumask << 16;
530
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530531 writel_relaxed(0, base + GIC_DIST_CTRL);
Russell Kingf27ecac2005-08-18 21:31:00 +0100532
533 /*
Russell Kingf27ecac2005-08-18 21:31:00 +0100534 * Set all global interrupts to be level triggered, active low.
535 */
Pawel Molle6afec92010-11-26 13:45:43 +0100536 for (i = 32; i < gic_irqs; i += 16)
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530537 writel_relaxed(0, base + GIC_DIST_CONFIG + i * 4 / 16);
Russell Kingf27ecac2005-08-18 21:31:00 +0100538
539 /*
540 * Set all global interrupts to this CPU only.
541 */
Pawel Molle6afec92010-11-26 13:45:43 +0100542 for (i = 32; i < gic_irqs; i += 4)
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530543 writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4 / 4);
Russell Kingf27ecac2005-08-18 21:31:00 +0100544
545 /*
Rohit Vaswani26e44862012-01-05 20:26:40 -0800546 * Set NS/S.
547 */
548 if (is_cpu_secure())
549 for (i = 32; i < gic_irqs; i += 32)
550 writel_relaxed(0xFFFFFFFF,
551 base + GIC_DIST_ISR + i * 4 / 32);
552
553 /*
Russell King9395f6e2010-11-11 23:10:30 +0000554 * Set priority on all global interrupts.
Russell Kingf27ecac2005-08-18 21:31:00 +0100555 */
Pawel Molle6afec92010-11-26 13:45:43 +0100556 for (i = 32; i < gic_irqs; i += 4)
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530557 writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
Russell Kingf27ecac2005-08-18 21:31:00 +0100558
559 /*
Russell King9395f6e2010-11-11 23:10:30 +0000560 * Disable all interrupts. Leave the PPI and SGIs alone
561 * as these enables are banked registers.
Russell Kingf27ecac2005-08-18 21:31:00 +0100562 */
Pawel Molle6afec92010-11-26 13:45:43 +0100563 for (i = 32; i < gic_irqs; i += 32)
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530564 writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
Russell Kingf27ecac2005-08-18 21:31:00 +0100565
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700566 gic->max_irq = gic_irqs;
567
Rohit Vaswani26e44862012-01-05 20:26:40 -0800568 if (is_cpu_secure())
569 writel_relaxed(3, base + GIC_DIST_CTRL);
570 else
571 writel_relaxed(1, base + GIC_DIST_CTRL);
572
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700573 mb();
Russell Kingf27ecac2005-08-18 21:31:00 +0100574}
575
Russell Kingbef8f9e2010-12-04 16:50:58 +0000576static void __cpuinit gic_cpu_init(struct gic_chip_data *gic)
Russell Kingf27ecac2005-08-18 21:31:00 +0100577{
Marc Zyngierdb0d4db2011-11-12 16:09:49 +0000578 void __iomem *dist_base = gic_data_dist_base(gic);
579 void __iomem *base = gic_data_cpu_base(gic);
Russell King9395f6e2010-11-11 23:10:30 +0000580 int i;
581
Russell King9395f6e2010-11-11 23:10:30 +0000582 /*
583 * Deal with the banked PPI and SGI interrupts - disable all
584 * PPI interrupts, ensure all SGI interrupts are enabled.
585 */
Taniya Das66398862012-04-30 12:24:17 +0530586#ifdef CONFIG_ARCH_MSM8625
587 raw_spin_lock(&irq_controller_lock);
588#endif
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530589 writel_relaxed(0xffff0000, dist_base + GIC_DIST_ENABLE_CLEAR);
590 writel_relaxed(0x0000ffff, dist_base + GIC_DIST_ENABLE_SET);
Russell King9395f6e2010-11-11 23:10:30 +0000591
Rohit Vaswani26e44862012-01-05 20:26:40 -0800592 /* Set NS/S */
593 if (is_cpu_secure())
594 writel_relaxed(0xFFFFFFFF, dist_base + GIC_DIST_ISR);
595
Russell King9395f6e2010-11-11 23:10:30 +0000596 /*
597 * Set priority on PPI and SGI interrupts
598 */
599 for (i = 0; i < 32; i += 4)
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530600 writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
Russell King9395f6e2010-11-11 23:10:30 +0000601
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530602 writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
Rohit Vaswani26e44862012-01-05 20:26:40 -0800603
604 if (is_cpu_secure())
605 writel_relaxed(0xF, base + GIC_CPU_CTRL);
606 else
607 writel_relaxed(1, base + GIC_CPU_CTRL);
Taniya Das66398862012-04-30 12:24:17 +0530608#ifdef CONFIG_ARCH_MSM8625
609 raw_spin_unlock(&irq_controller_lock);
610#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700611 mb();
Russell Kingf27ecac2005-08-18 21:31:00 +0100612}
613
Colin Cross254056f2011-02-10 12:54:10 -0800614#ifdef CONFIG_CPU_PM
615/*
616 * Saves the GIC distributor registers during suspend or idle. Must be called
617 * with interrupts disabled but before powering down the GIC. After calling
618 * this function, no interrupts will be delivered by the GIC, and another
619 * platform-specific wakeup source must be enabled.
620 */
621static void gic_dist_save(unsigned int gic_nr)
622{
623 unsigned int gic_irqs;
624 void __iomem *dist_base;
625 int i;
626
627 if (gic_nr >= MAX_GIC_NR)
628 BUG();
629
630 gic_irqs = gic_data[gic_nr].gic_irqs;
Marc Zyngierdb0d4db2011-11-12 16:09:49 +0000631 dist_base = gic_data_dist_base(&gic_data[gic_nr]);
Colin Cross254056f2011-02-10 12:54:10 -0800632
633 if (!dist_base)
634 return;
635
Rohit Vaswani26e44862012-01-05 20:26:40 -0800636 saved_dist_ctrl = readl_relaxed(dist_base + GIC_DIST_CTRL);
637
Colin Cross254056f2011-02-10 12:54:10 -0800638 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 16); i++)
639 gic_data[gic_nr].saved_spi_conf[i] =
640 readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4);
641
642 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
643 gic_data[gic_nr].saved_spi_target[i] =
644 readl_relaxed(dist_base + GIC_DIST_TARGET + i * 4);
645
Rohit Vaswani26e44862012-01-05 20:26:40 -0800646 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
647 gic_data[gic_nr].saved_dist_pri[i] =
648 readl_relaxed(dist_base + GIC_DIST_PRI + i * 4);
649
Colin Cross254056f2011-02-10 12:54:10 -0800650 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++)
651 gic_data[gic_nr].saved_spi_enable[i] =
652 readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
653}
654
655/*
656 * Restores the GIC distributor registers during resume or when coming out of
657 * idle. Must be called before enabling interrupts. If a level interrupt
658 * that occured while the GIC was suspended is still present, it will be
659 * handled normally, but any edge interrupts that occured will not be seen by
660 * the GIC and need to be handled by the platform-specific wakeup source.
661 */
662static void gic_dist_restore(unsigned int gic_nr)
663{
664 unsigned int gic_irqs;
665 unsigned int i;
666 void __iomem *dist_base;
667
668 if (gic_nr >= MAX_GIC_NR)
669 BUG();
670
671 gic_irqs = gic_data[gic_nr].gic_irqs;
Marc Zyngierdb0d4db2011-11-12 16:09:49 +0000672 dist_base = gic_data_dist_base(&gic_data[gic_nr]);
Colin Cross254056f2011-02-10 12:54:10 -0800673
674 if (!dist_base)
675 return;
676
677 writel_relaxed(0, dist_base + GIC_DIST_CTRL);
678
679 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 16); i++)
680 writel_relaxed(gic_data[gic_nr].saved_spi_conf[i],
681 dist_base + GIC_DIST_CONFIG + i * 4);
682
683 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
Rohit Vaswani26e44862012-01-05 20:26:40 -0800684 writel_relaxed(gic_data[gic_nr].saved_dist_pri[i],
Colin Cross254056f2011-02-10 12:54:10 -0800685 dist_base + GIC_DIST_PRI + i * 4);
686
687 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
688 writel_relaxed(gic_data[gic_nr].saved_spi_target[i],
689 dist_base + GIC_DIST_TARGET + i * 4);
690
691 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++)
692 writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
693 dist_base + GIC_DIST_ENABLE_SET + i * 4);
694
Rohit Vaswani26e44862012-01-05 20:26:40 -0800695 writel_relaxed(saved_dist_ctrl, dist_base + GIC_DIST_CTRL);
Colin Cross254056f2011-02-10 12:54:10 -0800696}
697
698static void gic_cpu_save(unsigned int gic_nr)
699{
700 int i;
701 u32 *ptr;
702 void __iomem *dist_base;
703 void __iomem *cpu_base;
704
705 if (gic_nr >= MAX_GIC_NR)
706 BUG();
707
Marc Zyngierdb0d4db2011-11-12 16:09:49 +0000708 dist_base = gic_data_dist_base(&gic_data[gic_nr]);
709 cpu_base = gic_data_cpu_base(&gic_data[gic_nr]);
Colin Cross254056f2011-02-10 12:54:10 -0800710
711 if (!dist_base || !cpu_base)
712 return;
713
Rohit Vaswani26e44862012-01-05 20:26:40 -0800714 saved_cpu_ctrl = readl_relaxed(cpu_base + GIC_CPU_CTRL);
715
716 for (i = 0; i < DIV_ROUND_UP(32, 4); i++)
717 gic_data[gic_nr].saved_dist_pri[i] = readl_relaxed(dist_base +
718 GIC_DIST_PRI + i * 4);
719
Colin Cross254056f2011-02-10 12:54:10 -0800720 ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_enable);
721 for (i = 0; i < DIV_ROUND_UP(32, 32); i++)
722 ptr[i] = readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
723
724 ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_conf);
725 for (i = 0; i < DIV_ROUND_UP(32, 16); i++)
726 ptr[i] = readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4);
727
728}
729
730static void gic_cpu_restore(unsigned int gic_nr)
731{
732 int i;
733 u32 *ptr;
734 void __iomem *dist_base;
735 void __iomem *cpu_base;
736
737 if (gic_nr >= MAX_GIC_NR)
738 BUG();
739
Marc Zyngierdb0d4db2011-11-12 16:09:49 +0000740 dist_base = gic_data_dist_base(&gic_data[gic_nr]);
741 cpu_base = gic_data_cpu_base(&gic_data[gic_nr]);
Colin Cross254056f2011-02-10 12:54:10 -0800742
743 if (!dist_base || !cpu_base)
744 return;
745
746 ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_enable);
747 for (i = 0; i < DIV_ROUND_UP(32, 32); i++)
748 writel_relaxed(ptr[i], dist_base + GIC_DIST_ENABLE_SET + i * 4);
749
750 ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_conf);
751 for (i = 0; i < DIV_ROUND_UP(32, 16); i++)
752 writel_relaxed(ptr[i], dist_base + GIC_DIST_CONFIG + i * 4);
753
754 for (i = 0; i < DIV_ROUND_UP(32, 4); i++)
Rohit Vaswani26e44862012-01-05 20:26:40 -0800755 writel_relaxed(gic_data[gic_nr].saved_dist_pri[i],
756 dist_base + GIC_DIST_PRI + i * 4);
Colin Cross254056f2011-02-10 12:54:10 -0800757
758 writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
Rohit Vaswani26e44862012-01-05 20:26:40 -0800759 writel_relaxed(saved_cpu_ctrl, cpu_base + GIC_CPU_CTRL);
Colin Cross254056f2011-02-10 12:54:10 -0800760}
761
762static int gic_notifier(struct notifier_block *self, unsigned long cmd, void *v)
763{
764 int i;
765
766 for (i = 0; i < MAX_GIC_NR; i++) {
Marc Zyngierdb0d4db2011-11-12 16:09:49 +0000767#ifdef CONFIG_GIC_NON_BANKED
768 /* Skip over unused GICs */
769 if (!gic_data[i].get_base)
770 continue;
771#endif
Colin Cross254056f2011-02-10 12:54:10 -0800772 switch (cmd) {
773 case CPU_PM_ENTER:
774 gic_cpu_save(i);
775 break;
776 case CPU_PM_ENTER_FAILED:
777 case CPU_PM_EXIT:
778 gic_cpu_restore(i);
779 break;
780 case CPU_CLUSTER_PM_ENTER:
781 gic_dist_save(i);
782 break;
783 case CPU_CLUSTER_PM_ENTER_FAILED:
784 case CPU_CLUSTER_PM_EXIT:
785 gic_dist_restore(i);
786 break;
787 }
788 }
789
790 return NOTIFY_OK;
791}
792
793static struct notifier_block gic_notifier_block = {
794 .notifier_call = gic_notifier,
795};
796
797static void __init gic_pm_init(struct gic_chip_data *gic)
798{
799 gic->saved_ppi_enable = __alloc_percpu(DIV_ROUND_UP(32, 32) * 4,
800 sizeof(u32));
801 BUG_ON(!gic->saved_ppi_enable);
802
803 gic->saved_ppi_conf = __alloc_percpu(DIV_ROUND_UP(32, 16) * 4,
804 sizeof(u32));
805 BUG_ON(!gic->saved_ppi_conf);
806
Marc Zyngierabdd7b92011-11-25 17:58:19 +0100807 if (gic == &gic_data[0])
808 cpu_pm_register_notifier(&gic_notifier_block);
Colin Cross254056f2011-02-10 12:54:10 -0800809}
810#else
811static void __init gic_pm_init(struct gic_chip_data *gic)
812{
813}
Trilok Soni38501052012-06-07 18:55:37 +0530814
815static void gic_cpu_restore(unsigned int gic_nr)
816{
817}
818
819static void gic_cpu_save(unsigned int gic_nr)
820{
821}
822
823static void gic_dist_restore(unsigned int gic_nr)
824{
825}
826
827static void gic_dist_save(unsigned int gic_nr)
828{
829}
Colin Cross254056f2011-02-10 12:54:10 -0800830#endif
831
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700832static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
833 irq_hw_number_t hw)
834{
835 if (hw < 32) {
836 irq_set_percpu_devid(irq);
837 irq_set_chip_and_handler(irq, &gic_chip,
838 handle_percpu_devid_irq);
839 set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN);
840 } else {
841 irq_set_chip_and_handler(irq, &gic_chip,
842 handle_fasteoi_irq);
843 set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
844 }
845 irq_set_chip_data(irq, d->host_data);
846 return 0;
847}
848
849static int gic_irq_domain_xlate(struct irq_domain *d,
850 struct device_node *controller,
851 const u32 *intspec, unsigned int intsize,
852 unsigned long *out_hwirq, unsigned int *out_type)
Rob Herringb3f7ed02011-09-28 21:27:52 -0500853{
854 if (d->of_node != controller)
855 return -EINVAL;
856 if (intsize < 3)
857 return -EINVAL;
858
859 /* Get the interrupt number and add 16 to skip over SGIs */
860 *out_hwirq = intspec[1] + 16;
861
862 /* For SPIs, we need to add 16 more to get the GIC irq ID number */
863 if (!intspec[0])
864 *out_hwirq += 16;
865
866 *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK;
867 return 0;
868}
Rob Herringb3f7ed02011-09-28 21:27:52 -0500869
Grant Likely15a25982012-01-26 12:25:18 -0700870const struct irq_domain_ops gic_irq_domain_ops = {
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700871 .map = gic_irq_domain_map,
872 .xlate = gic_irq_domain_xlate,
Rob Herring4294f8b2011-09-28 21:25:31 -0500873};
874
Marc Zyngierdb0d4db2011-11-12 16:09:49 +0000875void __init gic_init_bases(unsigned int gic_nr, int irq_start,
876 void __iomem *dist_base, void __iomem *cpu_base,
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700877 u32 percpu_offset, struct device_node *node)
Russell Kingb580b892010-12-04 15:55:14 +0000878{
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700879 irq_hw_number_t hwirq_base;
Russell Kingbef8f9e2010-12-04 16:50:58 +0000880 struct gic_chip_data *gic;
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700881 int gic_irqs, irq_base;
Russell Kingbef8f9e2010-12-04 16:50:58 +0000882
883 BUG_ON(gic_nr >= MAX_GIC_NR);
884
885 gic = &gic_data[gic_nr];
Marc Zyngierdb0d4db2011-11-12 16:09:49 +0000886#ifdef CONFIG_GIC_NON_BANKED
887 if (percpu_offset) { /* Frankein-GIC without banked registers... */
888 unsigned int cpu;
889
890 gic->dist_base.percpu_base = alloc_percpu(void __iomem *);
891 gic->cpu_base.percpu_base = alloc_percpu(void __iomem *);
892 if (WARN_ON(!gic->dist_base.percpu_base ||
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700893 !gic->cpu_base.percpu_base)) {
894 free_percpu(gic->dist_base.percpu_base);
895 free_percpu(gic->cpu_base.percpu_base);
896 return;
897 }
Marc Zyngierdb0d4db2011-11-12 16:09:49 +0000898
899 for_each_possible_cpu(cpu) {
900 unsigned long offset = percpu_offset * cpu_logical_map(cpu);
901 *per_cpu_ptr(gic->dist_base.percpu_base, cpu) = dist_base + offset;
902 *per_cpu_ptr(gic->cpu_base.percpu_base, cpu) = cpu_base + offset;
903 }
904
905 gic_set_base_accessor(gic, gic_get_percpu_base);
906 } else
907#endif
908 { /* Normal, sane GIC... */
909 WARN(percpu_offset,
910 "GIC_NON_BANKED not enabled, ignoring %08x offset!",
911 percpu_offset);
912 gic->dist_base.common_base = dist_base;
913 gic->cpu_base.common_base = cpu_base;
914 gic_set_base_accessor(gic, gic_get_common_base);
915 }
Russell Kingbef8f9e2010-12-04 16:50:58 +0000916
Rob Herring4294f8b2011-09-28 21:25:31 -0500917 /*
918 * For primary GICs, skip over SGIs.
919 * For secondary GICs, skip over PPIs, too.
920 */
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700921 if (gic_nr == 0 && (irq_start & 31) > 0) {
922 hwirq_base = 16;
923 if (irq_start != -1)
924 irq_start = (irq_start & ~31) + 16;
925 } else {
926 hwirq_base = 32;
Will Deaconfe41db72011-11-25 19:23:36 +0100927 }
Rob Herring4294f8b2011-09-28 21:25:31 -0500928
929 /*
930 * Find out how many interrupts are supported.
931 * The GIC only supports up to 1020 interrupt sources.
932 */
Marc Zyngierdb0d4db2011-11-12 16:09:49 +0000933 gic_irqs = readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_CTR) & 0x1f;
Rob Herring4294f8b2011-09-28 21:25:31 -0500934 gic_irqs = (gic_irqs + 1) * 32;
935 if (gic_irqs > 1020)
936 gic_irqs = 1020;
937 gic->gic_irqs = gic_irqs;
938
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700939 gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */
940 irq_base = irq_alloc_descs(irq_start, 16, gic_irqs, numa_node_id());
941 if (IS_ERR_VALUE(irq_base)) {
Rob Herringf37a53c2011-10-21 17:14:27 -0500942 WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
943 irq_start);
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700944 irq_base = irq_start;
Rob Herringf37a53c2011-10-21 17:14:27 -0500945 }
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700946 gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base,
947 hwirq_base, &gic_irq_domain_ops, gic);
948 if (WARN_ON(!gic->domain))
949 return;
Russell Kingbef8f9e2010-12-04 16:50:58 +0000950
Colin Cross9c128452011-06-13 00:45:59 +0000951 gic_chip.flags |= gic_arch_extn.flags;
Rob Herring4294f8b2011-09-28 21:25:31 -0500952 gic_dist_init(gic);
Russell Kingbef8f9e2010-12-04 16:50:58 +0000953 gic_cpu_init(gic);
Colin Cross254056f2011-02-10 12:54:10 -0800954 gic_pm_init(gic);
Russell Kingb580b892010-12-04 15:55:14 +0000955}
956
Russell King38489532010-12-04 16:01:03 +0000957void __cpuinit gic_secondary_init(unsigned int gic_nr)
958{
Russell Kingbef8f9e2010-12-04 16:50:58 +0000959 BUG_ON(gic_nr >= MAX_GIC_NR);
960
961 gic_cpu_init(&gic_data[gic_nr]);
Russell King38489532010-12-04 16:01:03 +0000962}
963
Russell Kingf27ecac2005-08-18 21:31:00 +0100964#ifdef CONFIG_SMP
Russell King82668102009-05-17 16:20:18 +0100965void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
Russell Kingf27ecac2005-08-18 21:31:00 +0100966{
Will Deacon267840f2011-08-23 22:20:03 +0100967 int cpu;
Rohit Vaswani26e44862012-01-05 20:26:40 -0800968 unsigned long sgir;
Will Deacon267840f2011-08-23 22:20:03 +0100969 unsigned long map = 0;
Taniya Das66398862012-04-30 12:24:17 +0530970#ifdef CONFIG_ARCH_MSM8625
971 unsigned long flags;
972#endif
Will Deacon267840f2011-08-23 22:20:03 +0100973
974 /* Convert our logical CPU mask into a physical one. */
975 for_each_cpu(cpu, mask)
976 map |= 1 << cpu_logical_map(cpu);
Russell Kingf27ecac2005-08-18 21:31:00 +0100977
Rohit Vaswani26e44862012-01-05 20:26:40 -0800978 sgir = (map << 16) | irq;
979 if (is_cpu_secure())
980 sgir |= (1 << 15);
981
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530982 /*
983 * Ensure that stores to Normal memory are visible to the
984 * other CPUs before issuing the IPI.
985 */
986 dsb();
987
Taniya Das66398862012-04-30 12:24:17 +0530988#ifdef CONFIG_ARCH_MSM8625
989 raw_spin_lock_irqsave(&irq_controller_lock, flags);
990#endif
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100991 /* this always happens on GIC0 */
Steve Mucklef132c6c2012-06-06 18:30:57 -0700992
Rohit Vaswani26e44862012-01-05 20:26:40 -0800993 writel_relaxed(sgir,
994 gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
Taniya Das66398862012-04-30 12:24:17 +0530995#ifdef CONFIG_ARCH_MSM8625
996 raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
997#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700998 mb();
Russell Kingf27ecac2005-08-18 21:31:00 +0100999}
1000#endif
Rob Herringb3f7ed02011-09-28 21:27:52 -05001001
Rohit Vaswani26e44862012-01-05 20:26:40 -08001002void gic_set_irq_secure(unsigned int irq)
1003{
1004 unsigned int gicd_isr_reg, gicd_pri_reg;
1005 unsigned int mask = 0xFFFFFF00;
1006 struct gic_chip_data *gic_data = &gic_data[0];
1007 struct irq_data *d = irq_get_irq_data(irq);
1008
1009 if (is_cpu_secure()) {
1010 raw_spin_lock(&irq_controller_lock);
1011 gicd_isr_reg = readl_relaxed(gic_dist_base(d) +
1012 GIC_DIST_ISR + gic_irq(d) / 32 * 4);
1013 gicd_isr_reg &= ~BIT(gic_irq(d) % 32);
1014 writel_relaxed(gicd_isr_reg, gic_dist_base(d) +
1015 GIC_DIST_ISR + gic_irq(d) / 32 * 4);
1016 /* Also increase the priority of that irq */
1017 gicd_pri_reg = readl_relaxed(gic_dist_base(d) +
1018 GIC_DIST_PRI + (gic_irq(d) * 4 / 4));
1019 gicd_pri_reg &= mask;
1020 gicd_pri_reg |= 0x80; /* Priority of 0x80 > 0xA0 */
1021 writel_relaxed(gicd_pri_reg, gic_dist_base(d) + GIC_DIST_PRI +
1022 gic_irq(d) * 4 / 4);
1023 mb();
1024 raw_spin_unlock(&irq_controller_lock);
1025 } else {
1026 WARN(1, "Trying to run secure operation from Non-secure mode");
1027 }
1028}
1029
Rob Herringb3f7ed02011-09-28 21:27:52 -05001030#ifdef CONFIG_OF
1031static int gic_cnt __initdata = 0;
1032
1033int __init gic_of_init(struct device_node *node, struct device_node *parent)
1034{
1035 void __iomem *cpu_base;
1036 void __iomem *dist_base;
Marc Zyngierdb0d4db2011-11-12 16:09:49 +00001037 u32 percpu_offset;
Rob Herringb3f7ed02011-09-28 21:27:52 -05001038 int irq;
Rob Herringb3f7ed02011-09-28 21:27:52 -05001039
1040 if (WARN_ON(!node))
1041 return -ENODEV;
1042
1043 dist_base = of_iomap(node, 0);
1044 WARN(!dist_base, "unable to map gic dist registers\n");
1045
1046 cpu_base = of_iomap(node, 1);
1047 WARN(!cpu_base, "unable to map gic cpu registers\n");
1048
Marc Zyngierdb0d4db2011-11-12 16:09:49 +00001049 if (of_property_read_u32(node, "cpu-offset", &percpu_offset))
1050 percpu_offset = 0;
1051
Michael Bohanbb6b30f2012-06-01 13:33:51 -07001052 gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset, node);
Rob Herringb3f7ed02011-09-28 21:27:52 -05001053
1054 if (parent) {
1055 irq = irq_of_parse_and_map(node, 0);
1056 gic_cascade_irq(gic_cnt, irq);
1057 }
1058 gic_cnt++;
1059 return 0;
1060}
1061#endif
Trilok Soni01dbb612012-05-28 19:23:53 +05301062/*
1063 * Before calling this function the interrupts should be disabled
1064 * and the irq must be disabled at gic to avoid spurious interrupts
1065 */
1066bool gic_is_irq_pending(unsigned int irq)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001067{
1068 struct irq_data *d = irq_get_irq_data(irq);
1069 struct gic_chip_data *gic_data = &gic_data[0];
1070 u32 mask, val;
1071
1072 WARN_ON(!irqs_disabled());
Thomas Gleixner450ea482009-07-03 08:44:46 -05001073 raw_spin_lock(&irq_controller_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001074 mask = 1 << (gic_irq(d) % 32);
1075 val = readl(gic_dist_base(d) +
1076 GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
1077 /* warn if the interrupt is enabled */
1078 WARN_ON(val & mask);
1079 val = readl(gic_dist_base(d) +
1080 GIC_DIST_PENDING_SET + (gic_irq(d) / 32) * 4);
Thomas Gleixner450ea482009-07-03 08:44:46 -05001081 raw_spin_unlock(&irq_controller_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001082 return (bool) (val & mask);
1083}
1084
Trilok Soni01dbb612012-05-28 19:23:53 +05301085/*
1086 * Before calling this function the interrupts should be disabled
1087 * and the irq must be disabled at gic to avoid spurious interrupts
1088 */
1089void gic_clear_irq_pending(unsigned int irq)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001090{
1091 struct gic_chip_data *gic_data = &gic_data[0];
1092 struct irq_data *d = irq_get_irq_data(irq);
1093
1094 u32 mask, val;
1095 WARN_ON(!irqs_disabled());
Thomas Gleixner450ea482009-07-03 08:44:46 -05001096 raw_spin_lock(&irq_controller_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001097 mask = 1 << (gic_irq(d) % 32);
1098 val = readl(gic_dist_base(d) +
1099 GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
1100 /* warn if the interrupt is enabled */
1101 WARN_ON(val & mask);
1102 writel(mask, gic_dist_base(d) +
1103 GIC_DIST_PENDING_CLEAR + (gic_irq(d) / 32) * 4);
Thomas Gleixner450ea482009-07-03 08:44:46 -05001104 raw_spin_unlock(&irq_controller_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001105}
Rob Herring0fc0d942011-09-28 21:27:52 -05001106
Taniya Dasbc9248a2012-04-30 19:59:11 +05301107#ifdef CONFIG_ARCH_MSM8625
1108 /*
1109 * Check for any interrupts which are enabled are pending
1110 * in the pending set or not.
1111 * Return :
1112 * 0 : No pending interrupts
1113 * 1 : Pending interrupts other than A9_M2A_5
1114 */
1115unsigned int msm_gic_spi_ppi_pending(void)
1116{
1117 unsigned int i, bit = 0;
1118 unsigned int pending_enb = 0, pending = 0;
1119 unsigned long value = 0;
1120 struct gic_chip_data *gic = &gic_data[0];
1121 void __iomem *base = gic_data_dist_base(gic);
Trilok Soni6278db02012-05-20 01:29:52 +05301122 unsigned long flags;
Taniya Dasbc9248a2012-04-30 19:59:11 +05301123
Trilok Soni6278db02012-05-20 01:29:52 +05301124 raw_spin_lock_irqsave(&irq_controller_lock, flags);
Taniya Dasbc9248a2012-04-30 19:59:11 +05301125 /*
1126 * PPI and SGI to be included.
1127 * MSM8625_INT_A9_M2A_5 needs to be ignored, as A9_M2A_5
1128 * requesting sleep triggers it
1129 */
1130 for (i = 0; (i * 32) < gic->max_irq; i++) {
1131 pending = readl_relaxed(base +
1132 GIC_DIST_PENDING_SET + i * 4);
1133 pending_enb = readl_relaxed(base +
1134 GIC_DIST_ENABLE_SET + i * 4);
1135 value = pending & pending_enb;
1136
1137 if (value) {
1138 for (bit = 0; bit < 32; bit++) {
1139 bit = find_next_bit(&value, 32, bit);
1140 if ((bit + 32 * i) != MSM8625_INT_A9_M2A_5) {
Trilok Soni6278db02012-05-20 01:29:52 +05301141 raw_spin_unlock_irqrestore(
1142 &irq_controller_lock, flags);
Taniya Dasbc9248a2012-04-30 19:59:11 +05301143 return 1;
1144 }
1145 }
1146 }
1147 }
Trilok Soni6278db02012-05-20 01:29:52 +05301148 raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
Taniya Dasbc9248a2012-04-30 19:59:11 +05301149
1150 return 0;
1151}
Trilok Soni38501052012-06-07 18:55:37 +05301152#endif
Taniya Dasbc9248a2012-04-30 19:59:11 +05301153
1154void msm_gic_save(bool modem_wake, int from_idle)
1155{
1156 unsigned int i;
1157 struct gic_chip_data *gic = &gic_data[0];
1158 void __iomem *base = gic_data_dist_base(gic);
1159
1160 gic_cpu_save(0);
1161 gic_dist_save(0);
Taniya Das8862d7d2012-05-21 20:11:37 +05301162
1163 /* Disable all the Interrupts, before we enter pc */
1164 for (i = 0; (i * 32) < gic->max_irq; i++) {
1165 raw_spin_lock(&irq_controller_lock);
1166 writel_relaxed(0xffffffff, base
1167 + GIC_DIST_ENABLE_CLEAR + i * 4);
1168 raw_spin_unlock(&irq_controller_lock);
Taniya Dasbc9248a2012-04-30 19:59:11 +05301169 }
1170}
1171
1172void msm_gic_restore(void)
1173{
1174 gic_dist_restore(0);
1175 gic_cpu_restore(0);
1176}
1177
1178/*
1179 * Configure the GIC after we come out of power collapse.
1180 * This function will configure some of the GIC registers so as to prepare the
1181 * core1 to receive an SPI(ACSR_MP_CORE_IPC1, (32 + 8)), which will bring
1182 * core1 out of GDFS.
1183 */
1184void core1_gic_configure_and_raise(void)
1185{
1186 struct gic_chip_data *gic = &gic_data[0];
1187 void __iomem *base = gic_data_dist_base(gic);
1188 unsigned int value = 0;
Trilok Soni6278db02012-05-20 01:29:52 +05301189 unsigned long flags;
Taniya Dasbc9248a2012-04-30 19:59:11 +05301190
Trilok Soni6278db02012-05-20 01:29:52 +05301191 raw_spin_lock_irqsave(&irq_controller_lock, flags);
Taniya Dasbc9248a2012-04-30 19:59:11 +05301192
1193 value = __raw_readl(base + GIC_DIST_ACTIVE_BIT + 0x4);
1194 value |= BIT(8);
1195 __raw_writel(value, base + GIC_DIST_ACTIVE_BIT + 0x4);
1196 mb();
1197
1198 value = __raw_readl(base + GIC_DIST_TARGET + 0x24);
1199 value |= BIT(13);
1200 __raw_writel(value, base + GIC_DIST_TARGET + 0x24);
1201 mb();
1202
1203 value = __raw_readl(base + GIC_DIST_TARGET + 0x28);
1204 value |= BIT(1);
1205 __raw_writel(value, base + GIC_DIST_TARGET + 0x28);
1206 mb();
1207
1208 value = __raw_readl(base + GIC_DIST_ENABLE_SET + 0x4);
1209 value |= BIT(8);
1210 __raw_writel(value, base + GIC_DIST_ENABLE_SET + 0x4);
1211 mb();
1212
1213 value = __raw_readl(base + GIC_DIST_PENDING_SET + 0x4);
1214 value |= BIT(8);
1215 __raw_writel(value, base + GIC_DIST_PENDING_SET + 0x4);
1216 mb();
Trilok Soni6278db02012-05-20 01:29:52 +05301217 raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
Taniya Dasbc9248a2012-04-30 19:59:11 +05301218}