blob: 29d01f305c4b78dfdb41499f10c12eb0386e2f72 [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}
814#endif
815
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700816static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
817 irq_hw_number_t hw)
818{
819 if (hw < 32) {
820 irq_set_percpu_devid(irq);
821 irq_set_chip_and_handler(irq, &gic_chip,
822 handle_percpu_devid_irq);
823 set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN);
824 } else {
825 irq_set_chip_and_handler(irq, &gic_chip,
826 handle_fasteoi_irq);
827 set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
828 }
829 irq_set_chip_data(irq, d->host_data);
830 return 0;
831}
832
833static int gic_irq_domain_xlate(struct irq_domain *d,
834 struct device_node *controller,
835 const u32 *intspec, unsigned int intsize,
836 unsigned long *out_hwirq, unsigned int *out_type)
Rob Herringb3f7ed02011-09-28 21:27:52 -0500837{
838 if (d->of_node != controller)
839 return -EINVAL;
840 if (intsize < 3)
841 return -EINVAL;
842
843 /* Get the interrupt number and add 16 to skip over SGIs */
844 *out_hwirq = intspec[1] + 16;
845
846 /* For SPIs, we need to add 16 more to get the GIC irq ID number */
847 if (!intspec[0])
848 *out_hwirq += 16;
849
850 *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK;
851 return 0;
852}
Rob Herringb3f7ed02011-09-28 21:27:52 -0500853
Grant Likely15a25982012-01-26 12:25:18 -0700854const struct irq_domain_ops gic_irq_domain_ops = {
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700855 .map = gic_irq_domain_map,
856 .xlate = gic_irq_domain_xlate,
Rob Herring4294f8b2011-09-28 21:25:31 -0500857};
858
Marc Zyngierdb0d4db2011-11-12 16:09:49 +0000859void __init gic_init_bases(unsigned int gic_nr, int irq_start,
860 void __iomem *dist_base, void __iomem *cpu_base,
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700861 u32 percpu_offset, struct device_node *node)
Russell Kingb580b892010-12-04 15:55:14 +0000862{
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700863 irq_hw_number_t hwirq_base;
Russell Kingbef8f9e2010-12-04 16:50:58 +0000864 struct gic_chip_data *gic;
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700865 int gic_irqs, irq_base;
Russell Kingbef8f9e2010-12-04 16:50:58 +0000866
867 BUG_ON(gic_nr >= MAX_GIC_NR);
868
869 gic = &gic_data[gic_nr];
Marc Zyngierdb0d4db2011-11-12 16:09:49 +0000870#ifdef CONFIG_GIC_NON_BANKED
871 if (percpu_offset) { /* Frankein-GIC without banked registers... */
872 unsigned int cpu;
873
874 gic->dist_base.percpu_base = alloc_percpu(void __iomem *);
875 gic->cpu_base.percpu_base = alloc_percpu(void __iomem *);
876 if (WARN_ON(!gic->dist_base.percpu_base ||
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700877 !gic->cpu_base.percpu_base)) {
878 free_percpu(gic->dist_base.percpu_base);
879 free_percpu(gic->cpu_base.percpu_base);
880 return;
881 }
Marc Zyngierdb0d4db2011-11-12 16:09:49 +0000882
883 for_each_possible_cpu(cpu) {
884 unsigned long offset = percpu_offset * cpu_logical_map(cpu);
885 *per_cpu_ptr(gic->dist_base.percpu_base, cpu) = dist_base + offset;
886 *per_cpu_ptr(gic->cpu_base.percpu_base, cpu) = cpu_base + offset;
887 }
888
889 gic_set_base_accessor(gic, gic_get_percpu_base);
890 } else
891#endif
892 { /* Normal, sane GIC... */
893 WARN(percpu_offset,
894 "GIC_NON_BANKED not enabled, ignoring %08x offset!",
895 percpu_offset);
896 gic->dist_base.common_base = dist_base;
897 gic->cpu_base.common_base = cpu_base;
898 gic_set_base_accessor(gic, gic_get_common_base);
899 }
Russell Kingbef8f9e2010-12-04 16:50:58 +0000900
Rob Herring4294f8b2011-09-28 21:25:31 -0500901 /*
902 * For primary GICs, skip over SGIs.
903 * For secondary GICs, skip over PPIs, too.
904 */
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700905 if (gic_nr == 0 && (irq_start & 31) > 0) {
906 hwirq_base = 16;
907 if (irq_start != -1)
908 irq_start = (irq_start & ~31) + 16;
909 } else {
910 hwirq_base = 32;
Will Deaconfe41db72011-11-25 19:23:36 +0100911 }
Rob Herring4294f8b2011-09-28 21:25:31 -0500912
913 /*
914 * Find out how many interrupts are supported.
915 * The GIC only supports up to 1020 interrupt sources.
916 */
Marc Zyngierdb0d4db2011-11-12 16:09:49 +0000917 gic_irqs = readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_CTR) & 0x1f;
Rob Herring4294f8b2011-09-28 21:25:31 -0500918 gic_irqs = (gic_irqs + 1) * 32;
919 if (gic_irqs > 1020)
920 gic_irqs = 1020;
921 gic->gic_irqs = gic_irqs;
922
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700923 gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */
924 irq_base = irq_alloc_descs(irq_start, 16, gic_irqs, numa_node_id());
925 if (IS_ERR_VALUE(irq_base)) {
Rob Herringf37a53c2011-10-21 17:14:27 -0500926 WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
927 irq_start);
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700928 irq_base = irq_start;
Rob Herringf37a53c2011-10-21 17:14:27 -0500929 }
Michael Bohanbb6b30f2012-06-01 13:33:51 -0700930 gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base,
931 hwirq_base, &gic_irq_domain_ops, gic);
932 if (WARN_ON(!gic->domain))
933 return;
Russell Kingbef8f9e2010-12-04 16:50:58 +0000934
Colin Cross9c128452011-06-13 00:45:59 +0000935 gic_chip.flags |= gic_arch_extn.flags;
Rob Herring4294f8b2011-09-28 21:25:31 -0500936 gic_dist_init(gic);
Russell Kingbef8f9e2010-12-04 16:50:58 +0000937 gic_cpu_init(gic);
Colin Cross254056f2011-02-10 12:54:10 -0800938 gic_pm_init(gic);
Russell Kingb580b892010-12-04 15:55:14 +0000939}
940
Russell King38489532010-12-04 16:01:03 +0000941void __cpuinit gic_secondary_init(unsigned int gic_nr)
942{
Russell Kingbef8f9e2010-12-04 16:50:58 +0000943 BUG_ON(gic_nr >= MAX_GIC_NR);
944
945 gic_cpu_init(&gic_data[gic_nr]);
Russell King38489532010-12-04 16:01:03 +0000946}
947
Russell Kingf27ecac2005-08-18 21:31:00 +0100948#ifdef CONFIG_SMP
Russell King82668102009-05-17 16:20:18 +0100949void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
Russell Kingf27ecac2005-08-18 21:31:00 +0100950{
Will Deacon267840f2011-08-23 22:20:03 +0100951 int cpu;
Rohit Vaswani26e44862012-01-05 20:26:40 -0800952 unsigned long sgir;
Will Deacon267840f2011-08-23 22:20:03 +0100953 unsigned long map = 0;
Taniya Das66398862012-04-30 12:24:17 +0530954#ifdef CONFIG_ARCH_MSM8625
955 unsigned long flags;
956#endif
Will Deacon267840f2011-08-23 22:20:03 +0100957
958 /* Convert our logical CPU mask into a physical one. */
959 for_each_cpu(cpu, mask)
960 map |= 1 << cpu_logical_map(cpu);
Russell Kingf27ecac2005-08-18 21:31:00 +0100961
Rohit Vaswani26e44862012-01-05 20:26:40 -0800962 sgir = (map << 16) | irq;
963 if (is_cpu_secure())
964 sgir |= (1 << 15);
965
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530966 /*
967 * Ensure that stores to Normal memory are visible to the
968 * other CPUs before issuing the IPI.
969 */
970 dsb();
971
Taniya Das66398862012-04-30 12:24:17 +0530972#ifdef CONFIG_ARCH_MSM8625
973 raw_spin_lock_irqsave(&irq_controller_lock, flags);
974#endif
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100975 /* this always happens on GIC0 */
Steve Mucklef132c6c2012-06-06 18:30:57 -0700976
Rohit Vaswani26e44862012-01-05 20:26:40 -0800977 writel_relaxed(sgir,
978 gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
Taniya Das66398862012-04-30 12:24:17 +0530979#ifdef CONFIG_ARCH_MSM8625
980 raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
981#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700982 mb();
Russell Kingf27ecac2005-08-18 21:31:00 +0100983}
984#endif
Rob Herringb3f7ed02011-09-28 21:27:52 -0500985
Rohit Vaswani26e44862012-01-05 20:26:40 -0800986void gic_set_irq_secure(unsigned int irq)
987{
988 unsigned int gicd_isr_reg, gicd_pri_reg;
989 unsigned int mask = 0xFFFFFF00;
990 struct gic_chip_data *gic_data = &gic_data[0];
991 struct irq_data *d = irq_get_irq_data(irq);
992
993 if (is_cpu_secure()) {
994 raw_spin_lock(&irq_controller_lock);
995 gicd_isr_reg = readl_relaxed(gic_dist_base(d) +
996 GIC_DIST_ISR + gic_irq(d) / 32 * 4);
997 gicd_isr_reg &= ~BIT(gic_irq(d) % 32);
998 writel_relaxed(gicd_isr_reg, gic_dist_base(d) +
999 GIC_DIST_ISR + gic_irq(d) / 32 * 4);
1000 /* Also increase the priority of that irq */
1001 gicd_pri_reg = readl_relaxed(gic_dist_base(d) +
1002 GIC_DIST_PRI + (gic_irq(d) * 4 / 4));
1003 gicd_pri_reg &= mask;
1004 gicd_pri_reg |= 0x80; /* Priority of 0x80 > 0xA0 */
1005 writel_relaxed(gicd_pri_reg, gic_dist_base(d) + GIC_DIST_PRI +
1006 gic_irq(d) * 4 / 4);
1007 mb();
1008 raw_spin_unlock(&irq_controller_lock);
1009 } else {
1010 WARN(1, "Trying to run secure operation from Non-secure mode");
1011 }
1012}
1013
Rob Herringb3f7ed02011-09-28 21:27:52 -05001014#ifdef CONFIG_OF
1015static int gic_cnt __initdata = 0;
1016
1017int __init gic_of_init(struct device_node *node, struct device_node *parent)
1018{
1019 void __iomem *cpu_base;
1020 void __iomem *dist_base;
Marc Zyngierdb0d4db2011-11-12 16:09:49 +00001021 u32 percpu_offset;
Rob Herringb3f7ed02011-09-28 21:27:52 -05001022 int irq;
Rob Herringb3f7ed02011-09-28 21:27:52 -05001023
1024 if (WARN_ON(!node))
1025 return -ENODEV;
1026
1027 dist_base = of_iomap(node, 0);
1028 WARN(!dist_base, "unable to map gic dist registers\n");
1029
1030 cpu_base = of_iomap(node, 1);
1031 WARN(!cpu_base, "unable to map gic cpu registers\n");
1032
Marc Zyngierdb0d4db2011-11-12 16:09:49 +00001033 if (of_property_read_u32(node, "cpu-offset", &percpu_offset))
1034 percpu_offset = 0;
1035
Michael Bohanbb6b30f2012-06-01 13:33:51 -07001036 gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset, node);
Rob Herringb3f7ed02011-09-28 21:27:52 -05001037
1038 if (parent) {
1039 irq = irq_of_parse_and_map(node, 0);
1040 gic_cascade_irq(gic_cnt, irq);
1041 }
1042 gic_cnt++;
1043 return 0;
1044}
1045#endif
Trilok Soni01dbb612012-05-28 19:23:53 +05301046/*
1047 * Before calling this function the interrupts should be disabled
1048 * and the irq must be disabled at gic to avoid spurious interrupts
1049 */
1050bool gic_is_irq_pending(unsigned int irq)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001051{
1052 struct irq_data *d = irq_get_irq_data(irq);
1053 struct gic_chip_data *gic_data = &gic_data[0];
1054 u32 mask, val;
1055
1056 WARN_ON(!irqs_disabled());
Thomas Gleixner450ea482009-07-03 08:44:46 -05001057 raw_spin_lock(&irq_controller_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001058 mask = 1 << (gic_irq(d) % 32);
1059 val = readl(gic_dist_base(d) +
1060 GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
1061 /* warn if the interrupt is enabled */
1062 WARN_ON(val & mask);
1063 val = readl(gic_dist_base(d) +
1064 GIC_DIST_PENDING_SET + (gic_irq(d) / 32) * 4);
Thomas Gleixner450ea482009-07-03 08:44:46 -05001065 raw_spin_unlock(&irq_controller_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001066 return (bool) (val & mask);
1067}
1068
Trilok Soni01dbb612012-05-28 19:23:53 +05301069/*
1070 * Before calling this function the interrupts should be disabled
1071 * and the irq must be disabled at gic to avoid spurious interrupts
1072 */
1073void gic_clear_irq_pending(unsigned int irq)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001074{
1075 struct gic_chip_data *gic_data = &gic_data[0];
1076 struct irq_data *d = irq_get_irq_data(irq);
1077
1078 u32 mask, val;
1079 WARN_ON(!irqs_disabled());
Thomas Gleixner450ea482009-07-03 08:44:46 -05001080 raw_spin_lock(&irq_controller_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001081 mask = 1 << (gic_irq(d) % 32);
1082 val = readl(gic_dist_base(d) +
1083 GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
1084 /* warn if the interrupt is enabled */
1085 WARN_ON(val & mask);
1086 writel(mask, gic_dist_base(d) +
1087 GIC_DIST_PENDING_CLEAR + (gic_irq(d) / 32) * 4);
Thomas Gleixner450ea482009-07-03 08:44:46 -05001088 raw_spin_unlock(&irq_controller_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001089}
Rob Herring0fc0d942011-09-28 21:27:52 -05001090
Taniya Dasbc9248a2012-04-30 19:59:11 +05301091#ifdef CONFIG_ARCH_MSM8625
1092 /*
1093 * Check for any interrupts which are enabled are pending
1094 * in the pending set or not.
1095 * Return :
1096 * 0 : No pending interrupts
1097 * 1 : Pending interrupts other than A9_M2A_5
1098 */
1099unsigned int msm_gic_spi_ppi_pending(void)
1100{
1101 unsigned int i, bit = 0;
1102 unsigned int pending_enb = 0, pending = 0;
1103 unsigned long value = 0;
1104 struct gic_chip_data *gic = &gic_data[0];
1105 void __iomem *base = gic_data_dist_base(gic);
Trilok Soni6278db02012-05-20 01:29:52 +05301106 unsigned long flags;
Taniya Dasbc9248a2012-04-30 19:59:11 +05301107
Trilok Soni6278db02012-05-20 01:29:52 +05301108 raw_spin_lock_irqsave(&irq_controller_lock, flags);
Taniya Dasbc9248a2012-04-30 19:59:11 +05301109 /*
1110 * PPI and SGI to be included.
1111 * MSM8625_INT_A9_M2A_5 needs to be ignored, as A9_M2A_5
1112 * requesting sleep triggers it
1113 */
1114 for (i = 0; (i * 32) < gic->max_irq; i++) {
1115 pending = readl_relaxed(base +
1116 GIC_DIST_PENDING_SET + i * 4);
1117 pending_enb = readl_relaxed(base +
1118 GIC_DIST_ENABLE_SET + i * 4);
1119 value = pending & pending_enb;
1120
1121 if (value) {
1122 for (bit = 0; bit < 32; bit++) {
1123 bit = find_next_bit(&value, 32, bit);
1124 if ((bit + 32 * i) != MSM8625_INT_A9_M2A_5) {
Trilok Soni6278db02012-05-20 01:29:52 +05301125 raw_spin_unlock_irqrestore(
1126 &irq_controller_lock, flags);
Taniya Dasbc9248a2012-04-30 19:59:11 +05301127 return 1;
1128 }
1129 }
1130 }
1131 }
Trilok Soni6278db02012-05-20 01:29:52 +05301132 raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
Taniya Dasbc9248a2012-04-30 19:59:11 +05301133
1134 return 0;
1135}
1136
1137void msm_gic_save(bool modem_wake, int from_idle)
1138{
1139 unsigned int i;
1140 struct gic_chip_data *gic = &gic_data[0];
1141 void __iomem *base = gic_data_dist_base(gic);
1142
1143 gic_cpu_save(0);
1144 gic_dist_save(0);
Taniya Das8862d7d2012-05-21 20:11:37 +05301145
1146 /* Disable all the Interrupts, before we enter pc */
1147 for (i = 0; (i * 32) < gic->max_irq; i++) {
1148 raw_spin_lock(&irq_controller_lock);
1149 writel_relaxed(0xffffffff, base
1150 + GIC_DIST_ENABLE_CLEAR + i * 4);
1151 raw_spin_unlock(&irq_controller_lock);
Taniya Dasbc9248a2012-04-30 19:59:11 +05301152 }
1153}
1154
1155void msm_gic_restore(void)
1156{
1157 gic_dist_restore(0);
1158 gic_cpu_restore(0);
1159}
1160
1161/*
1162 * Configure the GIC after we come out of power collapse.
1163 * This function will configure some of the GIC registers so as to prepare the
1164 * core1 to receive an SPI(ACSR_MP_CORE_IPC1, (32 + 8)), which will bring
1165 * core1 out of GDFS.
1166 */
1167void core1_gic_configure_and_raise(void)
1168{
1169 struct gic_chip_data *gic = &gic_data[0];
1170 void __iomem *base = gic_data_dist_base(gic);
1171 unsigned int value = 0;
Trilok Soni6278db02012-05-20 01:29:52 +05301172 unsigned long flags;
Taniya Dasbc9248a2012-04-30 19:59:11 +05301173
Trilok Soni6278db02012-05-20 01:29:52 +05301174 raw_spin_lock_irqsave(&irq_controller_lock, flags);
Taniya Dasbc9248a2012-04-30 19:59:11 +05301175
1176 value = __raw_readl(base + GIC_DIST_ACTIVE_BIT + 0x4);
1177 value |= BIT(8);
1178 __raw_writel(value, base + GIC_DIST_ACTIVE_BIT + 0x4);
1179 mb();
1180
1181 value = __raw_readl(base + GIC_DIST_TARGET + 0x24);
1182 value |= BIT(13);
1183 __raw_writel(value, base + GIC_DIST_TARGET + 0x24);
1184 mb();
1185
1186 value = __raw_readl(base + GIC_DIST_TARGET + 0x28);
1187 value |= BIT(1);
1188 __raw_writel(value, base + GIC_DIST_TARGET + 0x28);
1189 mb();
1190
1191 value = __raw_readl(base + GIC_DIST_ENABLE_SET + 0x4);
1192 value |= BIT(8);
1193 __raw_writel(value, base + GIC_DIST_ENABLE_SET + 0x4);
1194 mb();
1195
1196 value = __raw_readl(base + GIC_DIST_PENDING_SET + 0x4);
1197 value |= BIT(8);
1198 __raw_writel(value, base + GIC_DIST_PENDING_SET + 0x4);
1199 mb();
Trilok Soni6278db02012-05-20 01:29:52 +05301200 raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
Taniya Dasbc9248a2012-04-30 19:59:11 +05301201}
1202#endif