blob: 875b479cc154d7ee8348a7bbb9a664bd8ce67f89 [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 Herring050113e2011-10-21 17:14:27 -050027#include <linux/err.h>
Arnd Bergmann4f874102011-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 Cross692c3e252011-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>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070034#include <linux/syscore_ops.h>
Rob Herring0fc0d942011-09-28 21:27:52 -050035#include <linux/of.h>
36#include <linux/of_address.h>
37#include <linux/of_irq.h>
Rob Herringc383e042011-09-28 21:25:31 -050038#include <linux/irqdomain.h>
Trilok Sonieecb28c2011-07-20 16:24:14 +010039#include <linux/interrupt.h>
40#include <linux/percpu.h>
41#include <linux/slab.h>
Russell Kingf27ecac2005-08-18 21:31:00 +010042
43#include <asm/irq.h>
Marc Zyngier181621e2011-09-06 09:56:17 +010044#include <asm/exception.h>
Russell Kingf27ecac2005-08-18 21:31:00 +010045#include <asm/mach/irq.h>
46#include <asm/hardware/gic.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070047#include <asm/system.h>
Trilok Sonieecb28c2011-07-20 16:24:14 +010048#include <asm/localtimer.h>
Russell Kingf27ecac2005-08-18 21:31:00 +010049
Marc Zyngier680392b2011-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 {
56 unsigned int irq_offset;
57 union gic_base dist_base;
58 union gic_base cpu_base;
59 unsigned int max_irq;
60#ifdef CONFIG_PM
61 unsigned int wakeup_irqs[32];
62 unsigned int enabled_irqs[32];
63#endif
64#ifdef CONFIG_CPU_PM
65 u32 saved_spi_enable[DIV_ROUND_UP(1020, 32)];
66 u32 saved_spi_conf[DIV_ROUND_UP(1020, 16)];
67 u32 saved_spi_target[DIV_ROUND_UP(1020, 4)];
Rohit Vaswani26e44862012-01-05 20:26:40 -080068 u32 saved_dist_pri[DIV_ROUND_UP(1020, 4)];
Marc Zyngier680392b2011-11-12 16:09:49 +000069 u32 __percpu *saved_ppi_enable;
70 u32 __percpu *saved_ppi_conf;
71#endif
72#ifdef CONFIG_IRQ_DOMAIN
73 struct irq_domain domain;
74#endif
75 unsigned int gic_irqs;
76#ifdef CONFIG_GIC_NON_BANKED
77 void __iomem *(*get_base)(union gic_base *);
78#endif
79};
80
Thomas Gleixner450ea482009-07-03 08:44:46 -050081static DEFINE_RAW_SPINLOCK(irq_controller_lock);
Russell Kingf27ecac2005-08-18 21:31:00 +010082
Rohit Vaswani26e44862012-01-05 20:26:40 -080083#ifdef CONFIG_CPU_PM
84static unsigned int saved_dist_ctrl, saved_cpu_ctrl;
85#endif
86
Russell Kingff2e27a2010-12-04 16:13:29 +000087/* Address of GIC 0 CPU interface */
Russell Kingbef8f9e2010-12-04 16:50:58 +000088void __iomem *gic_cpu_base_addr __read_mostly;
Russell Kingff2e27a2010-12-04 16:13:29 +000089
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +010090/*
91 * Supported arch specific GIC irq extension.
92 * Default make them NULL.
93 */
94struct irq_chip gic_arch_extn = {
Will Deacon1a017532011-02-09 12:01:12 +000095 .irq_eoi = NULL,
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +010096 .irq_mask = NULL,
97 .irq_unmask = NULL,
98 .irq_retrigger = NULL,
99 .irq_set_type = NULL,
100 .irq_set_wake = NULL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700101 .irq_disable = NULL,
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100102};
103
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100104#ifndef MAX_GIC_NR
105#define MAX_GIC_NR 1
106#endif
107
Russell Kingbef8f9e2010-12-04 16:50:58 +0000108static struct gic_chip_data gic_data[MAX_GIC_NR] __read_mostly;
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100109
Marc Zyngier680392b2011-11-12 16:09:49 +0000110#ifdef CONFIG_GIC_NON_BANKED
111static void __iomem *gic_get_percpu_base(union gic_base *base)
112{
113 return *__this_cpu_ptr(base->percpu_base);
114}
115
116static void __iomem *gic_get_common_base(union gic_base *base)
117{
118 return base->common_base;
119}
120
121static inline void __iomem *gic_data_dist_base(struct gic_chip_data *data)
122{
123 return data->get_base(&data->dist_base);
124}
125
126static inline void __iomem *gic_data_cpu_base(struct gic_chip_data *data)
127{
128 return data->get_base(&data->cpu_base);
129}
130
131static inline void gic_set_base_accessor(struct gic_chip_data *data,
132 void __iomem *(*f)(union gic_base *))
133{
134 data->get_base = f;
135}
136#else
137#define gic_data_dist_base(d) ((d)->dist_base.common_base)
138#define gic_data_cpu_base(d) ((d)->cpu_base.common_base)
139#define gic_set_base_accessor(d,f)
140#endif
141
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100142static inline void __iomem *gic_dist_base(struct irq_data *d)
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100143{
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100144 struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
Marc Zyngier680392b2011-11-12 16:09:49 +0000145 return gic_data_dist_base(gic_data);
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100146}
147
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100148static inline void __iomem *gic_cpu_base(struct irq_data *d)
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100149{
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100150 struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
Marc Zyngier680392b2011-11-12 16:09:49 +0000151 return gic_data_cpu_base(gic_data);
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100152}
153
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100154static inline unsigned int gic_irq(struct irq_data *d)
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100155{
Rob Herringc383e042011-09-28 21:25:31 -0500156 return d->hwirq;
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100157}
158
Taniya Dasb241bd82012-03-19 17:58:06 +0530159#if defined(CONFIG_CPU_V7) && defined(CONFIG_GIC_SECURE)
Rohit Vaswani26e44862012-01-05 20:26:40 -0800160static const inline bool is_cpu_secure(void)
161{
162 unsigned int dscr;
163
164 asm volatile ("mrc p14, 0, %0, c0, c1, 0" : "=r" (dscr));
165
166 /* BIT(18) - NS bit; 1 = NS; 0 = S */
167 if (BIT(18) & dscr)
168 return false;
169 else
170 return true;
171}
172#else
173static const inline bool is_cpu_secure(void)
174{
175 return false;
176}
177#endif
178
Russell Kingf27ecac2005-08-18 21:31:00 +0100179/*
180 * Routines to acknowledge, disable and enable interrupts
Russell Kingf27ecac2005-08-18 21:31:00 +0100181 */
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100182static void gic_mask_irq(struct irq_data *d)
Russell Kingf27ecac2005-08-18 21:31:00 +0100183{
Rob Herringc383e042011-09-28 21:25:31 -0500184 u32 mask = 1 << (gic_irq(d) % 32);
Thomas Gleixnerc4bfa282006-07-01 22:32:14 +0100185
Thomas Gleixner450ea482009-07-03 08:44:46 -0500186 raw_spin_lock(&irq_controller_lock);
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530187 writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_CLEAR + (gic_irq(d) / 32) * 4);
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100188 if (gic_arch_extn.irq_mask)
189 gic_arch_extn.irq_mask(d);
Thomas Gleixner450ea482009-07-03 08:44:46 -0500190 raw_spin_unlock(&irq_controller_lock);
Russell Kingf27ecac2005-08-18 21:31:00 +0100191}
192
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100193static void gic_unmask_irq(struct irq_data *d)
Russell Kingf27ecac2005-08-18 21:31:00 +0100194{
Rob Herringc383e042011-09-28 21:25:31 -0500195 u32 mask = 1 << (gic_irq(d) % 32);
Thomas Gleixnerc4bfa282006-07-01 22:32:14 +0100196
Thomas Gleixner450ea482009-07-03 08:44:46 -0500197 raw_spin_lock(&irq_controller_lock);
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100198 if (gic_arch_extn.irq_unmask)
199 gic_arch_extn.irq_unmask(d);
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530200 writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
Thomas Gleixner450ea482009-07-03 08:44:46 -0500201 raw_spin_unlock(&irq_controller_lock);
Russell Kingf27ecac2005-08-18 21:31:00 +0100202}
203
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700204static void gic_disable_irq(struct irq_data *d)
205{
206 if (gic_arch_extn.irq_disable)
207 gic_arch_extn.irq_disable(d);
208}
209
210#ifdef CONFIG_PM
211static int gic_suspend_one(struct gic_chip_data *gic)
212{
213 unsigned int i;
Marc Zyngier680392b2011-11-12 16:09:49 +0000214 void __iomem *base = gic_data_dist_base(gic);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700215
216 for (i = 0; i * 32 < gic->max_irq; i++) {
Taniya Das66398862012-04-30 12:24:17 +0530217#ifdef CONFIG_ARCH_MSM8625
218 raw_spin_lock(&irq_controller_lock);
219#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700220 gic->enabled_irqs[i]
221 = readl_relaxed(base + GIC_DIST_ENABLE_SET + i * 4);
222 /* disable all of them */
223 writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4);
224 /* enable the wakeup set */
225 writel_relaxed(gic->wakeup_irqs[i],
226 base + GIC_DIST_ENABLE_SET + i * 4);
Taniya Das66398862012-04-30 12:24:17 +0530227#ifdef CONFIG_ARCH_MSM8625
228 raw_spin_unlock(&irq_controller_lock);
229#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700230 }
231 mb();
232 return 0;
233}
234
235static int gic_suspend(void)
236{
237 int i;
238 for (i = 0; i < MAX_GIC_NR; i++)
239 gic_suspend_one(&gic_data[i]);
240 return 0;
241}
242
243extern int msm_show_resume_irq_mask;
244
245static void gic_show_resume_irq(struct gic_chip_data *gic)
246{
247 unsigned int i;
248 u32 enabled;
249 unsigned long pending[32];
Marc Zyngier680392b2011-11-12 16:09:49 +0000250 void __iomem *base = gic_data_dist_base(gic);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700251
252 if (!msm_show_resume_irq_mask)
253 return;
254
Thomas Gleixner450ea482009-07-03 08:44:46 -0500255 raw_spin_lock(&irq_controller_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700256 for (i = 0; i * 32 < gic->max_irq; i++) {
257 enabled = readl_relaxed(base + GIC_DIST_ENABLE_CLEAR + i * 4);
258 pending[i] = readl_relaxed(base + GIC_DIST_PENDING_SET + i * 4);
259 pending[i] &= enabled;
260 }
Thomas Gleixner450ea482009-07-03 08:44:46 -0500261 raw_spin_unlock(&irq_controller_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700262
263 for (i = find_first_bit(pending, gic->max_irq);
264 i < gic->max_irq;
265 i = find_next_bit(pending, gic->max_irq, i+1)) {
266 pr_warning("%s: %d triggered", __func__,
267 i + gic->irq_offset);
268 }
269}
270
271static void gic_resume_one(struct gic_chip_data *gic)
272{
273 unsigned int i;
Marc Zyngier680392b2011-11-12 16:09:49 +0000274 void __iomem *base = gic_data_dist_base(gic);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700275
276 gic_show_resume_irq(gic);
277 for (i = 0; i * 32 < gic->max_irq; i++) {
Taniya Das66398862012-04-30 12:24:17 +0530278#ifdef CONFIG_ARCH_MSM8625
279 raw_spin_lock(&irq_controller_lock);
280#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700281 /* disable all of them */
282 writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4);
283 /* enable the enabled set */
284 writel_relaxed(gic->enabled_irqs[i],
285 base + GIC_DIST_ENABLE_SET + i * 4);
Taniya Das66398862012-04-30 12:24:17 +0530286#ifdef CONFIG_ARCH_MSM8625
287 raw_spin_unlock(&irq_controller_lock);
288#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700289 }
290 mb();
291}
292
293static void gic_resume(void)
294{
295 int i;
296 for (i = 0; i < MAX_GIC_NR; i++)
297 gic_resume_one(&gic_data[i]);
298}
299
300static struct syscore_ops gic_syscore_ops = {
301 .suspend = gic_suspend,
302 .resume = gic_resume,
303};
304
305static int __init gic_init_sys(void)
306{
307 register_syscore_ops(&gic_syscore_ops);
308 return 0;
309}
310arch_initcall(gic_init_sys);
311
312#endif
313
Will Deacon1a017532011-02-09 12:01:12 +0000314static void gic_eoi_irq(struct irq_data *d)
315{
316 if (gic_arch_extn.irq_eoi) {
Thomas Gleixner450ea482009-07-03 08:44:46 -0500317 raw_spin_lock(&irq_controller_lock);
Will Deacon1a017532011-02-09 12:01:12 +0000318 gic_arch_extn.irq_eoi(d);
Thomas Gleixner450ea482009-07-03 08:44:46 -0500319 raw_spin_unlock(&irq_controller_lock);
Will Deacon1a017532011-02-09 12:01:12 +0000320 }
Taniya Das66398862012-04-30 12:24:17 +0530321#ifdef CONFIG_ARCH_MSM8625
322 raw_spin_lock(&irq_controller_lock);
323#endif
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530324 writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
Taniya Das66398862012-04-30 12:24:17 +0530325#ifdef CONFIG_ARCH_MSM8625
326 raw_spin_unlock(&irq_controller_lock);
327#endif
Will Deacon1a017532011-02-09 12:01:12 +0000328}
329
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100330static int gic_set_type(struct irq_data *d, unsigned int type)
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100331{
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100332 void __iomem *base = gic_dist_base(d);
333 unsigned int gicirq = gic_irq(d);
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100334 u32 enablemask = 1 << (gicirq % 32);
335 u32 enableoff = (gicirq / 32) * 4;
336 u32 confmask = 0x2 << ((gicirq % 16) * 2);
337 u32 confoff = (gicirq / 16) * 4;
338 bool enabled = false;
339 u32 val;
340
341 /* Interrupt configuration for SGIs can't be changed */
342 if (gicirq < 16)
343 return -EINVAL;
344
345 if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
346 return -EINVAL;
347
Thomas Gleixner450ea482009-07-03 08:44:46 -0500348 raw_spin_lock(&irq_controller_lock);
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100349
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100350 if (gic_arch_extn.irq_set_type)
351 gic_arch_extn.irq_set_type(d, type);
352
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530353 val = readl_relaxed(base + GIC_DIST_CONFIG + confoff);
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100354 if (type == IRQ_TYPE_LEVEL_HIGH)
355 val &= ~confmask;
356 else if (type == IRQ_TYPE_EDGE_RISING)
357 val |= confmask;
358
359 /*
360 * As recommended by the spec, disable the interrupt before changing
361 * the configuration
362 */
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530363 if (readl_relaxed(base + GIC_DIST_ENABLE_SET + enableoff) & enablemask) {
364 writel_relaxed(enablemask, base + GIC_DIST_ENABLE_CLEAR + enableoff);
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100365 enabled = true;
366 }
367
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530368 writel_relaxed(val, base + GIC_DIST_CONFIG + confoff);
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100369
370 if (enabled)
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530371 writel_relaxed(enablemask, base + GIC_DIST_ENABLE_SET + enableoff);
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100372
Thomas Gleixner450ea482009-07-03 08:44:46 -0500373 raw_spin_unlock(&irq_controller_lock);
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100374
375 return 0;
376}
377
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100378static int gic_retrigger(struct irq_data *d)
379{
380 if (gic_arch_extn.irq_retrigger)
381 return gic_arch_extn.irq_retrigger(d);
382
Abhijeet Dharmapurikar9d44ea02011-10-30 16:47:19 -0700383 /* the retrigger expects 0 for failure */
384 return 0;
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100385}
386
Catalin Marinasa06f5462005-09-30 16:07:05 +0100387#ifdef CONFIG_SMP
Russell Kingc1917892011-01-23 12:12:01 +0000388static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
389 bool force)
Russell Kingf27ecac2005-08-18 21:31:00 +0100390{
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100391 void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) & ~3);
Rob Herringc383e042011-09-28 21:25:31 -0500392 unsigned int shift = (gic_irq(d) % 4) * 8;
Russell Kingf3c52e22011-07-21 15:00:57 +0100393 unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask);
Russell Kingc1917892011-01-23 12:12:01 +0000394 u32 val, mask, bit;
395
Russell Kingf3c52e22011-07-21 15:00:57 +0100396 if (cpu >= 8 || cpu >= nr_cpu_ids)
Russell Kingc1917892011-01-23 12:12:01 +0000397 return -EINVAL;
398
399 mask = 0xff << shift;
Will Deacona803a8d2011-08-23 22:20:03 +0100400 bit = 1 << (cpu_logical_map(cpu) + shift);
Russell Kingf27ecac2005-08-18 21:31:00 +0100401
Thomas Gleixner450ea482009-07-03 08:44:46 -0500402 raw_spin_lock(&irq_controller_lock);
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530403 val = readl_relaxed(reg) & ~mask;
404 writel_relaxed(val | bit, reg);
Thomas Gleixner450ea482009-07-03 08:44:46 -0500405 raw_spin_unlock(&irq_controller_lock);
Yinghai Lud5dedd42009-04-27 17:59:21 -0700406
Russell Kingf3c52e22011-07-21 15:00:57 +0100407 return IRQ_SET_MASK_OK;
Russell Kingf27ecac2005-08-18 21:31:00 +0100408}
Catalin Marinasa06f5462005-09-30 16:07:05 +0100409#endif
Russell Kingf27ecac2005-08-18 21:31:00 +0100410
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100411#ifdef CONFIG_PM
412static int gic_set_wake(struct irq_data *d, unsigned int on)
413{
414 int ret = -ENXIO;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700415 unsigned int reg_offset, bit_offset;
416 unsigned int gicirq = gic_irq(d);
417 struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
418
419 /* per-cpu interrupts cannot be wakeup interrupts */
420 WARN_ON(gicirq < 32);
421
422 reg_offset = gicirq / 32;
423 bit_offset = gicirq % 32;
424
425 if (on)
426 gic_data->wakeup_irqs[reg_offset] |= 1 << bit_offset;
427 else
428 gic_data->wakeup_irqs[reg_offset] &= ~(1 << bit_offset);
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100429
430 if (gic_arch_extn.irq_set_wake)
431 ret = gic_arch_extn.irq_set_wake(d, on);
432
433 return ret;
434}
435
436#else
Rohit Vaswani550aa1a2011-10-06 21:15:37 -0700437static int gic_set_wake(struct irq_data *d, unsigned int on)
438{
439 return 0;
440}
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100441#endif
442
Marc Zyngier181621e2011-09-06 09:56:17 +0100443asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
444{
445 u32 irqstat, irqnr;
446 struct gic_chip_data *gic = &gic_data[0];
447 void __iomem *cpu_base = gic_data_cpu_base(gic);
448
449 do {
Taniya Das66398862012-04-30 12:24:17 +0530450#ifdef CONFIG_ARCH_MSM8625
451 raw_spin_lock(&irq_controller_lock);
452#endif
Marc Zyngier181621e2011-09-06 09:56:17 +0100453 irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
Taniya Das66398862012-04-30 12:24:17 +0530454#ifdef CONFIG_ARCH_MSM8625
455 raw_spin_unlock(&irq_controller_lock);
456#endif
Marc Zyngier181621e2011-09-06 09:56:17 +0100457 irqnr = irqstat & ~0x1c00;
458
459 if (likely(irqnr > 15 && irqnr < 1021)) {
460 irqnr = irq_domain_to_irq(&gic->domain, irqnr);
461 handle_IRQ(irqnr, regs);
462 continue;
463 }
464 if (irqnr < 16) {
Taniya Das66398862012-04-30 12:24:17 +0530465#ifdef CONFIG_ARCH_MSM8625
466 raw_spin_lock(&irq_controller_lock);
467#endif
Marc Zyngier181621e2011-09-06 09:56:17 +0100468 writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
Taniya Das66398862012-04-30 12:24:17 +0530469#ifdef CONFIG_ARCH_MSM8625
470 raw_spin_unlock(&irq_controller_lock);
471#endif
Marc Zyngier181621e2011-09-06 09:56:17 +0100472#ifdef CONFIG_SMP
473 handle_IPI(irqnr, regs);
474#endif
475 continue;
476 }
477 break;
478 } while (1);
479}
480
Russell King0f347bb2007-05-17 10:11:34 +0100481static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100482{
Thomas Gleixner6845664a2011-03-24 13:25:22 +0100483 struct gic_chip_data *chip_data = irq_get_handler_data(irq);
484 struct irq_chip *chip = irq_get_chip(irq);
Russell King0f347bb2007-05-17 10:11:34 +0100485 unsigned int cascade_irq, gic_irq;
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100486 unsigned long status;
487
Will Deacon1a017532011-02-09 12:01:12 +0000488 chained_irq_enter(chip, desc);
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100489
Thomas Gleixner450ea482009-07-03 08:44:46 -0500490 raw_spin_lock(&irq_controller_lock);
Marc Zyngier680392b2011-11-12 16:09:49 +0000491 status = readl_relaxed(gic_data_cpu_base(chip_data) + GIC_CPU_INTACK);
Thomas Gleixner450ea482009-07-03 08:44:46 -0500492 raw_spin_unlock(&irq_controller_lock);
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100493
Russell King0f347bb2007-05-17 10:11:34 +0100494 gic_irq = (status & 0x3ff);
495 if (gic_irq == 1023)
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100496 goto out;
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100497
Rob Herringc383e042011-09-28 21:25:31 -0500498 cascade_irq = irq_domain_to_irq(&chip_data->domain, gic_irq);
Russell King0f347bb2007-05-17 10:11:34 +0100499 if (unlikely(gic_irq < 32 || gic_irq > 1020 || cascade_irq >= NR_IRQS))
500 do_bad_IRQ(cascade_irq, desc);
501 else
502 generic_handle_irq(cascade_irq);
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100503
504 out:
Will Deacon1a017532011-02-09 12:01:12 +0000505 chained_irq_exit(chip, desc);
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100506}
507
David Brownell38c677c2006-08-01 22:26:25 +0100508static struct irq_chip gic_chip = {
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100509 .name = "GIC",
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100510 .irq_mask = gic_mask_irq,
511 .irq_unmask = gic_unmask_irq,
Will Deacon1a017532011-02-09 12:01:12 +0000512 .irq_eoi = gic_eoi_irq,
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100513 .irq_set_type = gic_set_type,
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100514 .irq_retrigger = gic_retrigger,
Russell Kingf27ecac2005-08-18 21:31:00 +0100515#ifdef CONFIG_SMP
Russell Kingc1917892011-01-23 12:12:01 +0000516 .irq_set_affinity = gic_set_affinity,
Russell Kingf27ecac2005-08-18 21:31:00 +0100517#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700518 .irq_disable = gic_disable_irq,
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100519 .irq_set_wake = gic_set_wake,
Russell Kingf27ecac2005-08-18 21:31:00 +0100520};
521
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100522void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
523{
524 if (gic_nr >= MAX_GIC_NR)
525 BUG();
Thomas Gleixner6845664a2011-03-24 13:25:22 +0100526 if (irq_set_handler_data(irq, &gic_data[gic_nr]) != 0)
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100527 BUG();
Thomas Gleixner6845664a2011-03-24 13:25:22 +0100528 irq_set_chained_handler(irq, gic_handle_cascade_irq);
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100529}
530
Rob Herringc383e042011-09-28 21:25:31 -0500531static void __init gic_dist_init(struct gic_chip_data *gic)
Russell Kingf27ecac2005-08-18 21:31:00 +0100532{
Rob Herringc383e042011-09-28 21:25:31 -0500533 unsigned int i, irq;
Will Deacona803a8d2011-08-23 22:20:03 +0100534 u32 cpumask;
Rob Herringc383e042011-09-28 21:25:31 -0500535 unsigned int gic_irqs = gic->gic_irqs;
536 struct irq_domain *domain = &gic->domain;
Marc Zyngier680392b2011-11-12 16:09:49 +0000537 void __iomem *base = gic_data_dist_base(gic);
Will Deacona803a8d2011-08-23 22:20:03 +0100538 u32 cpu = 0;
Russell Kingf27ecac2005-08-18 21:31:00 +0100539
Will Deacona803a8d2011-08-23 22:20:03 +0100540#ifdef CONFIG_SMP
541 cpu = cpu_logical_map(smp_processor_id());
542#endif
543
544 cpumask = 1 << cpu;
Russell Kingf27ecac2005-08-18 21:31:00 +0100545 cpumask |= cpumask << 8;
546 cpumask |= cpumask << 16;
547
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530548 writel_relaxed(0, base + GIC_DIST_CTRL);
Russell Kingf27ecac2005-08-18 21:31:00 +0100549
550 /*
Russell Kingf27ecac2005-08-18 21:31:00 +0100551 * Set all global interrupts to be level triggered, active low.
552 */
Pawel Molle6afec92010-11-26 13:45:43 +0100553 for (i = 32; i < gic_irqs; i += 16)
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530554 writel_relaxed(0, base + GIC_DIST_CONFIG + i * 4 / 16);
Russell Kingf27ecac2005-08-18 21:31:00 +0100555
556 /*
557 * Set all global interrupts to this CPU only.
558 */
Pawel Molle6afec92010-11-26 13:45:43 +0100559 for (i = 32; i < gic_irqs; i += 4)
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530560 writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4 / 4);
Russell Kingf27ecac2005-08-18 21:31:00 +0100561
562 /*
Rohit Vaswani26e44862012-01-05 20:26:40 -0800563 * Set NS/S.
564 */
565 if (is_cpu_secure())
566 for (i = 32; i < gic_irqs; i += 32)
567 writel_relaxed(0xFFFFFFFF,
568 base + GIC_DIST_ISR + i * 4 / 32);
569
570 /*
Russell King9395f6e2010-11-11 23:10:30 +0000571 * Set priority on all global interrupts.
Russell Kingf27ecac2005-08-18 21:31:00 +0100572 */
Pawel Molle6afec92010-11-26 13:45:43 +0100573 for (i = 32; i < gic_irqs; i += 4)
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530574 writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
Russell Kingf27ecac2005-08-18 21:31:00 +0100575
576 /*
Russell King9395f6e2010-11-11 23:10:30 +0000577 * Disable all interrupts. Leave the PPI and SGIs alone
578 * as these enables are banked registers.
Russell Kingf27ecac2005-08-18 21:31:00 +0100579 */
Pawel Molle6afec92010-11-26 13:45:43 +0100580 for (i = 32; i < gic_irqs; i += 32)
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530581 writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
Russell Kingf27ecac2005-08-18 21:31:00 +0100582
583 /*
584 * Setup the Linux IRQ subsystem.
585 */
Rob Herringc383e042011-09-28 21:25:31 -0500586 irq_domain_for_each_irq(domain, i, irq) {
587 if (i < 32) {
588 irq_set_percpu_devid(irq);
589 irq_set_chip_and_handler(irq, &gic_chip,
590 handle_percpu_devid_irq);
591 set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN);
592 } else {
593 irq_set_chip_and_handler(irq, &gic_chip,
594 handle_fasteoi_irq);
595 set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
596 }
597 irq_set_chip_data(irq, gic);
Russell Kingf27ecac2005-08-18 21:31:00 +0100598 }
599
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700600 gic->max_irq = gic_irqs;
601
Rohit Vaswani26e44862012-01-05 20:26:40 -0800602 if (is_cpu_secure())
603 writel_relaxed(3, base + GIC_DIST_CTRL);
604 else
605 writel_relaxed(1, base + GIC_DIST_CTRL);
606
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700607 mb();
Russell Kingf27ecac2005-08-18 21:31:00 +0100608}
609
Russell Kingbef8f9e2010-12-04 16:50:58 +0000610static void __cpuinit gic_cpu_init(struct gic_chip_data *gic)
Russell Kingf27ecac2005-08-18 21:31:00 +0100611{
Marc Zyngier680392b2011-11-12 16:09:49 +0000612 void __iomem *dist_base = gic_data_dist_base(gic);
613 void __iomem *base = gic_data_cpu_base(gic);
Russell King9395f6e2010-11-11 23:10:30 +0000614 int i;
615
Russell King9395f6e2010-11-11 23:10:30 +0000616 /*
617 * Deal with the banked PPI and SGI interrupts - disable all
618 * PPI interrupts, ensure all SGI interrupts are enabled.
619 */
Taniya Das66398862012-04-30 12:24:17 +0530620#ifdef CONFIG_ARCH_MSM8625
621 raw_spin_lock(&irq_controller_lock);
622#endif
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530623 writel_relaxed(0xffff0000, dist_base + GIC_DIST_ENABLE_CLEAR);
624 writel_relaxed(0x0000ffff, dist_base + GIC_DIST_ENABLE_SET);
Russell King9395f6e2010-11-11 23:10:30 +0000625
Rohit Vaswani26e44862012-01-05 20:26:40 -0800626 /* Set NS/S */
627 if (is_cpu_secure())
628 writel_relaxed(0xFFFFFFFF, dist_base + GIC_DIST_ISR);
629
Russell King9395f6e2010-11-11 23:10:30 +0000630 /*
631 * Set priority on PPI and SGI interrupts
632 */
633 for (i = 0; i < 32; i += 4)
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530634 writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
Russell King9395f6e2010-11-11 23:10:30 +0000635
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530636 writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
Rohit Vaswani26e44862012-01-05 20:26:40 -0800637
638 if (is_cpu_secure())
639 writel_relaxed(0xF, base + GIC_CPU_CTRL);
640 else
641 writel_relaxed(1, base + GIC_CPU_CTRL);
Taniya Das66398862012-04-30 12:24:17 +0530642#ifdef CONFIG_ARCH_MSM8625
643 raw_spin_unlock(&irq_controller_lock);
644#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700645 mb();
Russell Kingf27ecac2005-08-18 21:31:00 +0100646}
647
Colin Cross692c3e252011-02-10 12:54:10 -0800648#ifdef CONFIG_CPU_PM
649/*
650 * Saves the GIC distributor registers during suspend or idle. Must be called
651 * with interrupts disabled but before powering down the GIC. After calling
652 * this function, no interrupts will be delivered by the GIC, and another
653 * platform-specific wakeup source must be enabled.
654 */
655static void gic_dist_save(unsigned int gic_nr)
656{
657 unsigned int gic_irqs;
658 void __iomem *dist_base;
659 int i;
660
661 if (gic_nr >= MAX_GIC_NR)
662 BUG();
663
664 gic_irqs = gic_data[gic_nr].gic_irqs;
Marc Zyngier680392b2011-11-12 16:09:49 +0000665 dist_base = gic_data_dist_base(&gic_data[gic_nr]);
Colin Cross692c3e252011-02-10 12:54:10 -0800666
667 if (!dist_base)
668 return;
669
Rohit Vaswani26e44862012-01-05 20:26:40 -0800670 saved_dist_ctrl = readl_relaxed(dist_base + GIC_DIST_CTRL);
671
Colin Cross692c3e252011-02-10 12:54:10 -0800672 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 16); i++)
673 gic_data[gic_nr].saved_spi_conf[i] =
674 readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4);
675
676 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
677 gic_data[gic_nr].saved_spi_target[i] =
678 readl_relaxed(dist_base + GIC_DIST_TARGET + i * 4);
679
Rohit Vaswani26e44862012-01-05 20:26:40 -0800680 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
681 gic_data[gic_nr].saved_dist_pri[i] =
682 readl_relaxed(dist_base + GIC_DIST_PRI + i * 4);
683
Colin Cross692c3e252011-02-10 12:54:10 -0800684 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++)
685 gic_data[gic_nr].saved_spi_enable[i] =
686 readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
687}
688
689/*
690 * Restores the GIC distributor registers during resume or when coming out of
691 * idle. Must be called before enabling interrupts. If a level interrupt
692 * that occured while the GIC was suspended is still present, it will be
693 * handled normally, but any edge interrupts that occured will not be seen by
694 * the GIC and need to be handled by the platform-specific wakeup source.
695 */
696static void gic_dist_restore(unsigned int gic_nr)
697{
698 unsigned int gic_irqs;
699 unsigned int i;
700 void __iomem *dist_base;
701
702 if (gic_nr >= MAX_GIC_NR)
703 BUG();
704
705 gic_irqs = gic_data[gic_nr].gic_irqs;
Marc Zyngier680392b2011-11-12 16:09:49 +0000706 dist_base = gic_data_dist_base(&gic_data[gic_nr]);
Colin Cross692c3e252011-02-10 12:54:10 -0800707
708 if (!dist_base)
709 return;
710
711 writel_relaxed(0, dist_base + GIC_DIST_CTRL);
712
713 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 16); i++)
714 writel_relaxed(gic_data[gic_nr].saved_spi_conf[i],
715 dist_base + GIC_DIST_CONFIG + i * 4);
716
717 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
Rohit Vaswani26e44862012-01-05 20:26:40 -0800718 writel_relaxed(gic_data[gic_nr].saved_dist_pri[i],
Colin Cross692c3e252011-02-10 12:54:10 -0800719 dist_base + GIC_DIST_PRI + i * 4);
720
721 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
722 writel_relaxed(gic_data[gic_nr].saved_spi_target[i],
723 dist_base + GIC_DIST_TARGET + i * 4);
724
725 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++)
726 writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
727 dist_base + GIC_DIST_ENABLE_SET + i * 4);
728
Rohit Vaswani26e44862012-01-05 20:26:40 -0800729 writel_relaxed(saved_dist_ctrl, dist_base + GIC_DIST_CTRL);
Colin Cross692c3e252011-02-10 12:54:10 -0800730}
731
732static void gic_cpu_save(unsigned int gic_nr)
733{
734 int i;
735 u32 *ptr;
736 void __iomem *dist_base;
737 void __iomem *cpu_base;
738
739 if (gic_nr >= MAX_GIC_NR)
740 BUG();
741
Marc Zyngier680392b2011-11-12 16:09:49 +0000742 dist_base = gic_data_dist_base(&gic_data[gic_nr]);
743 cpu_base = gic_data_cpu_base(&gic_data[gic_nr]);
Colin Cross692c3e252011-02-10 12:54:10 -0800744
745 if (!dist_base || !cpu_base)
746 return;
747
Rohit Vaswani26e44862012-01-05 20:26:40 -0800748 saved_cpu_ctrl = readl_relaxed(cpu_base + GIC_CPU_CTRL);
749
750 for (i = 0; i < DIV_ROUND_UP(32, 4); i++)
751 gic_data[gic_nr].saved_dist_pri[i] = readl_relaxed(dist_base +
752 GIC_DIST_PRI + i * 4);
753
Colin Cross692c3e252011-02-10 12:54:10 -0800754 ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_enable);
755 for (i = 0; i < DIV_ROUND_UP(32, 32); i++)
756 ptr[i] = readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
757
758 ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_conf);
759 for (i = 0; i < DIV_ROUND_UP(32, 16); i++)
760 ptr[i] = readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4);
761
762}
763
764static void gic_cpu_restore(unsigned int gic_nr)
765{
766 int i;
767 u32 *ptr;
768 void __iomem *dist_base;
769 void __iomem *cpu_base;
770
771 if (gic_nr >= MAX_GIC_NR)
772 BUG();
773
Marc Zyngier680392b2011-11-12 16:09:49 +0000774 dist_base = gic_data_dist_base(&gic_data[gic_nr]);
775 cpu_base = gic_data_cpu_base(&gic_data[gic_nr]);
Colin Cross692c3e252011-02-10 12:54:10 -0800776
777 if (!dist_base || !cpu_base)
778 return;
779
780 ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_enable);
781 for (i = 0; i < DIV_ROUND_UP(32, 32); i++)
782 writel_relaxed(ptr[i], dist_base + GIC_DIST_ENABLE_SET + i * 4);
783
784 ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_conf);
785 for (i = 0; i < DIV_ROUND_UP(32, 16); i++)
786 writel_relaxed(ptr[i], dist_base + GIC_DIST_CONFIG + i * 4);
787
788 for (i = 0; i < DIV_ROUND_UP(32, 4); i++)
Rohit Vaswani26e44862012-01-05 20:26:40 -0800789 writel_relaxed(gic_data[gic_nr].saved_dist_pri[i],
790 dist_base + GIC_DIST_PRI + i * 4);
Colin Cross692c3e252011-02-10 12:54:10 -0800791
792 writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
Rohit Vaswani26e44862012-01-05 20:26:40 -0800793 writel_relaxed(saved_cpu_ctrl, cpu_base + GIC_CPU_CTRL);
Colin Cross692c3e252011-02-10 12:54:10 -0800794}
795
796static int gic_notifier(struct notifier_block *self, unsigned long cmd, void *v)
797{
798 int i;
799
800 for (i = 0; i < MAX_GIC_NR; i++) {
Marc Zyngier680392b2011-11-12 16:09:49 +0000801#ifdef CONFIG_GIC_NON_BANKED
802 /* Skip over unused GICs */
803 if (!gic_data[i].get_base)
804 continue;
805#endif
Colin Cross692c3e252011-02-10 12:54:10 -0800806 switch (cmd) {
807 case CPU_PM_ENTER:
808 gic_cpu_save(i);
809 break;
810 case CPU_PM_ENTER_FAILED:
811 case CPU_PM_EXIT:
812 gic_cpu_restore(i);
813 break;
814 case CPU_CLUSTER_PM_ENTER:
815 gic_dist_save(i);
816 break;
817 case CPU_CLUSTER_PM_ENTER_FAILED:
818 case CPU_CLUSTER_PM_EXIT:
819 gic_dist_restore(i);
820 break;
821 }
822 }
823
824 return NOTIFY_OK;
825}
826
827static struct notifier_block gic_notifier_block = {
828 .notifier_call = gic_notifier,
829};
830
831static void __init gic_pm_init(struct gic_chip_data *gic)
832{
833 gic->saved_ppi_enable = __alloc_percpu(DIV_ROUND_UP(32, 32) * 4,
834 sizeof(u32));
835 BUG_ON(!gic->saved_ppi_enable);
836
837 gic->saved_ppi_conf = __alloc_percpu(DIV_ROUND_UP(32, 16) * 4,
838 sizeof(u32));
839 BUG_ON(!gic->saved_ppi_conf);
840
841 cpu_pm_register_notifier(&gic_notifier_block);
842}
843#else
844static void __init gic_pm_init(struct gic_chip_data *gic)
845{
846}
847#endif
848
Rob Herring0fc0d942011-09-28 21:27:52 -0500849#ifdef CONFIG_OF
850static int gic_irq_domain_dt_translate(struct irq_domain *d,
851 struct device_node *controller,
852 const u32 *intspec, unsigned int intsize,
853 unsigned long *out_hwirq, unsigned int *out_type)
854{
855 if (d->of_node != controller)
856 return -EINVAL;
857 if (intsize < 3)
858 return -EINVAL;
859
860 /* Get the interrupt number and add 16 to skip over SGIs */
861 *out_hwirq = intspec[1] + 16;
862
863 /* For SPIs, we need to add 16 more to get the GIC irq ID number */
864 if (!intspec[0])
865 *out_hwirq += 16;
866
867 *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK;
868 return 0;
869}
870#endif
871
Rob Herringc383e042011-09-28 21:25:31 -0500872const struct irq_domain_ops gic_irq_domain_ops = {
Rob Herring0fc0d942011-09-28 21:27:52 -0500873#ifdef CONFIG_OF
874 .dt_translate = gic_irq_domain_dt_translate,
875#endif
Rob Herringc383e042011-09-28 21:25:31 -0500876};
877
Marc Zyngier680392b2011-11-12 16:09:49 +0000878void __init gic_init_bases(unsigned int gic_nr, int irq_start,
879 void __iomem *dist_base, void __iomem *cpu_base,
880 u32 percpu_offset)
Russell Kingb580b892010-12-04 15:55:14 +0000881{
Russell Kingbef8f9e2010-12-04 16:50:58 +0000882 struct gic_chip_data *gic;
Rob Herringc383e042011-09-28 21:25:31 -0500883 struct irq_domain *domain;
Michael Bohan33efecf2012-01-12 15:32:21 -0800884 int gic_irqs, rc;
Russell Kingbef8f9e2010-12-04 16:50:58 +0000885
886 BUG_ON(gic_nr >= MAX_GIC_NR);
887
888 gic = &gic_data[gic_nr];
Rob Herringc383e042011-09-28 21:25:31 -0500889 domain = &gic->domain;
Marc Zyngier680392b2011-11-12 16:09:49 +0000890#ifdef CONFIG_GIC_NON_BANKED
891 if (percpu_offset) { /* Frankein-GIC without banked registers... */
892 unsigned int cpu;
893
894 gic->dist_base.percpu_base = alloc_percpu(void __iomem *);
895 gic->cpu_base.percpu_base = alloc_percpu(void __iomem *);
896 if (WARN_ON(!gic->dist_base.percpu_base ||
Michael Bohan33efecf2012-01-12 15:32:21 -0800897 !gic->cpu_base.percpu_base))
898 goto init_bases_err;
Marc Zyngier680392b2011-11-12 16:09:49 +0000899
900 for_each_possible_cpu(cpu) {
901 unsigned long offset = percpu_offset * cpu_logical_map(cpu);
902 *per_cpu_ptr(gic->dist_base.percpu_base, cpu) = dist_base + offset;
903 *per_cpu_ptr(gic->cpu_base.percpu_base, cpu) = cpu_base + offset;
904 }
905
906 gic_set_base_accessor(gic, gic_get_percpu_base);
907 } else
908#endif
909 { /* Normal, sane GIC... */
910 WARN(percpu_offset,
911 "GIC_NON_BANKED not enabled, ignoring %08x offset!",
912 percpu_offset);
913 gic->dist_base.common_base = dist_base;
914 gic->cpu_base.common_base = cpu_base;
915 gic_set_base_accessor(gic, gic_get_common_base);
916 }
Russell Kingbef8f9e2010-12-04 16:50:58 +0000917
Rob Herringc383e042011-09-28 21:25:31 -0500918 /*
919 * For primary GICs, skip over SGIs.
920 * For secondary GICs, skip over PPIs, too.
921 */
922 if (gic_nr == 0) {
Russell Kingff2e27a2010-12-04 16:13:29 +0000923 gic_cpu_base_addr = cpu_base;
Rob Herringc383e042011-09-28 21:25:31 -0500924 domain->hwirq_base = 16;
Rob Herring050113e2011-10-21 17:14:27 -0500925 if (irq_start > 0)
926 irq_start = (irq_start & ~31) + 16;
Rob Herringc383e042011-09-28 21:25:31 -0500927 } else
928 domain->hwirq_base = 32;
929
930 /*
931 * Find out how many interrupts are supported.
932 * The GIC only supports up to 1020 interrupt sources.
933 */
Marc Zyngier680392b2011-11-12 16:09:49 +0000934 gic_irqs = readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_CTR) & 0x1f;
Rob Herringc383e042011-09-28 21:25:31 -0500935 gic_irqs = (gic_irqs + 1) * 32;
936 if (gic_irqs > 1020)
937 gic_irqs = 1020;
938 gic->gic_irqs = gic_irqs;
939
940 domain->nr_irq = gic_irqs - domain->hwirq_base;
Rob Herring050113e2011-10-21 17:14:27 -0500941 domain->irq_base = irq_alloc_descs(irq_start, 16, domain->nr_irq,
Rob Herringc383e042011-09-28 21:25:31 -0500942 numa_node_id());
Rob Herring050113e2011-10-21 17:14:27 -0500943 if (IS_ERR_VALUE(domain->irq_base)) {
944 WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
945 irq_start);
946 domain->irq_base = irq_start;
947 }
Rob Herringc383e042011-09-28 21:25:31 -0500948 domain->priv = gic;
949 domain->ops = &gic_irq_domain_ops;
Michael Bohan33efecf2012-01-12 15:32:21 -0800950 rc = irq_domain_add(domain);
951 if (rc) {
952 WARN(1, "Unable to create irq_domain\n");
953 goto init_bases_err;
954 }
Michael Bohanb8635c32012-01-05 18:32:10 -0800955 irq_domain_register(domain);
Russell Kingbef8f9e2010-12-04 16:50:58 +0000956
Colin Cross692c3e252011-02-10 12:54:10 -0800957 gic_chip.flags |= gic_arch_extn.flags;
Rob Herringc383e042011-09-28 21:25:31 -0500958 gic_dist_init(gic);
Russell Kingbef8f9e2010-12-04 16:50:58 +0000959 gic_cpu_init(gic);
Colin Cross692c3e252011-02-10 12:54:10 -0800960 gic_pm_init(gic);
Michael Bohan33efecf2012-01-12 15:32:21 -0800961
962 return;
963
964init_bases_err:
965 free_percpu(gic->dist_base.percpu_base);
966 free_percpu(gic->cpu_base.percpu_base);
Russell Kingb580b892010-12-04 15:55:14 +0000967}
968
Russell King38489532010-12-04 16:01:03 +0000969void __cpuinit gic_secondary_init(unsigned int gic_nr)
970{
Russell Kingbef8f9e2010-12-04 16:50:58 +0000971 BUG_ON(gic_nr >= MAX_GIC_NR);
972
973 gic_cpu_init(&gic_data[gic_nr]);
Russell King38489532010-12-04 16:01:03 +0000974}
975
Russell Kingf27ecac2005-08-18 21:31:00 +0100976#ifdef CONFIG_SMP
Russell King82668102009-05-17 16:20:18 +0100977void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
Russell Kingf27ecac2005-08-18 21:31:00 +0100978{
Will Deacona803a8d2011-08-23 22:20:03 +0100979 int cpu;
Rohit Vaswani26e44862012-01-05 20:26:40 -0800980 unsigned long sgir;
Will Deacona803a8d2011-08-23 22:20:03 +0100981 unsigned long map = 0;
Taniya Das66398862012-04-30 12:24:17 +0530982#ifdef CONFIG_ARCH_MSM8625
983 unsigned long flags;
984#endif
Will Deacona803a8d2011-08-23 22:20:03 +0100985
986 /* Convert our logical CPU mask into a physical one. */
987 for_each_cpu(cpu, mask)
988 map |= 1 << cpu_logical_map(cpu);
Russell Kingf27ecac2005-08-18 21:31:00 +0100989
Rohit Vaswani26e44862012-01-05 20:26:40 -0800990 sgir = (map << 16) | irq;
991 if (is_cpu_secure())
992 sgir |= (1 << 15);
993
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530994 /*
995 * Ensure that stores to Normal memory are visible to the
996 * other CPUs before issuing the IPI.
997 */
998 dsb();
999
Taniya Das66398862012-04-30 12:24:17 +05301000#ifdef CONFIG_ARCH_MSM8625
1001 raw_spin_lock_irqsave(&irq_controller_lock, flags);
1002#endif
Catalin Marinasb3a1bde2007-02-14 19:14:56 +01001003 /* this always happens on GIC0 */
Rohit Vaswani26e44862012-01-05 20:26:40 -08001004 writel_relaxed(sgir,
1005 gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
Taniya Das66398862012-04-30 12:24:17 +05301006#ifdef CONFIG_ARCH_MSM8625
1007 raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
1008#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001009 mb();
Russell Kingf27ecac2005-08-18 21:31:00 +01001010}
1011#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001012
Rohit Vaswani26e44862012-01-05 20:26:40 -08001013void gic_set_irq_secure(unsigned int irq)
1014{
1015 unsigned int gicd_isr_reg, gicd_pri_reg;
1016 unsigned int mask = 0xFFFFFF00;
1017 struct gic_chip_data *gic_data = &gic_data[0];
1018 struct irq_data *d = irq_get_irq_data(irq);
1019
1020 if (is_cpu_secure()) {
1021 raw_spin_lock(&irq_controller_lock);
1022 gicd_isr_reg = readl_relaxed(gic_dist_base(d) +
1023 GIC_DIST_ISR + gic_irq(d) / 32 * 4);
1024 gicd_isr_reg &= ~BIT(gic_irq(d) % 32);
1025 writel_relaxed(gicd_isr_reg, gic_dist_base(d) +
1026 GIC_DIST_ISR + gic_irq(d) / 32 * 4);
1027 /* Also increase the priority of that irq */
1028 gicd_pri_reg = readl_relaxed(gic_dist_base(d) +
1029 GIC_DIST_PRI + (gic_irq(d) * 4 / 4));
1030 gicd_pri_reg &= mask;
1031 gicd_pri_reg |= 0x80; /* Priority of 0x80 > 0xA0 */
1032 writel_relaxed(gicd_pri_reg, gic_dist_base(d) + GIC_DIST_PRI +
1033 gic_irq(d) * 4 / 4);
1034 mb();
1035 raw_spin_unlock(&irq_controller_lock);
1036 } else {
1037 WARN(1, "Trying to run secure operation from Non-secure mode");
1038 }
1039}
1040
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001041/* before calling this function the interrupts should be disabled
1042 * and the irq must be disabled at gic to avoid spurious interrupts */
1043bool gic_is_spi_pending(unsigned int irq)
1044{
1045 struct irq_data *d = irq_get_irq_data(irq);
1046 struct gic_chip_data *gic_data = &gic_data[0];
1047 u32 mask, val;
1048
1049 WARN_ON(!irqs_disabled());
Thomas Gleixner450ea482009-07-03 08:44:46 -05001050 raw_spin_lock(&irq_controller_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001051 mask = 1 << (gic_irq(d) % 32);
1052 val = readl(gic_dist_base(d) +
1053 GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
1054 /* warn if the interrupt is enabled */
1055 WARN_ON(val & mask);
1056 val = readl(gic_dist_base(d) +
1057 GIC_DIST_PENDING_SET + (gic_irq(d) / 32) * 4);
Thomas Gleixner450ea482009-07-03 08:44:46 -05001058 raw_spin_unlock(&irq_controller_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001059 return (bool) (val & mask);
1060}
1061
1062/* before calling this function the interrupts should be disabled
1063 * and the irq must be disabled at gic to avoid spurious interrupts */
1064void gic_clear_spi_pending(unsigned int irq)
1065{
1066 struct gic_chip_data *gic_data = &gic_data[0];
1067 struct irq_data *d = irq_get_irq_data(irq);
1068
1069 u32 mask, val;
1070 WARN_ON(!irqs_disabled());
Thomas Gleixner450ea482009-07-03 08:44:46 -05001071 raw_spin_lock(&irq_controller_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001072 mask = 1 << (gic_irq(d) % 32);
1073 val = readl(gic_dist_base(d) +
1074 GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
1075 /* warn if the interrupt is enabled */
1076 WARN_ON(val & mask);
1077 writel(mask, gic_dist_base(d) +
1078 GIC_DIST_PENDING_CLEAR + (gic_irq(d) / 32) * 4);
Thomas Gleixner450ea482009-07-03 08:44:46 -05001079 raw_spin_unlock(&irq_controller_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001080}
Rob Herring0fc0d942011-09-28 21:27:52 -05001081#ifdef CONFIG_OF
1082static int gic_cnt __initdata = 0;
1083
1084int __init gic_of_init(struct device_node *node, struct device_node *parent)
1085{
1086 void __iomem *cpu_base;
1087 void __iomem *dist_base;
Marc Zyngier680392b2011-11-12 16:09:49 +00001088 u32 percpu_offset;
Rob Herring0fc0d942011-09-28 21:27:52 -05001089 int irq;
1090 struct irq_domain *domain = &gic_data[gic_cnt].domain;
1091
1092 if (WARN_ON(!node))
1093 return -ENODEV;
1094
1095 dist_base = of_iomap(node, 0);
1096 WARN(!dist_base, "unable to map gic dist registers\n");
1097
1098 cpu_base = of_iomap(node, 1);
1099 WARN(!cpu_base, "unable to map gic cpu registers\n");
1100
Marc Zyngier680392b2011-11-12 16:09:49 +00001101 if (of_property_read_u32(node, "cpu-offset", &percpu_offset))
1102 percpu_offset = 0;
1103
Rob Herring0fc0d942011-09-28 21:27:52 -05001104 domain->of_node = of_node_get(node);
1105
Marc Zyngier680392b2011-11-12 16:09:49 +00001106 gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset);
Rob Herring0fc0d942011-09-28 21:27:52 -05001107
1108 if (parent) {
1109 irq = irq_of_parse_and_map(node, 0);
1110 gic_cascade_irq(gic_cnt, irq);
1111 }
1112 gic_cnt++;
1113 return 0;
1114}
1115#endif
Taniya Dasbc9248a2012-04-30 19:59:11 +05301116#ifdef CONFIG_ARCH_MSM8625
1117 /*
1118 * Check for any interrupts which are enabled are pending
1119 * in the pending set or not.
1120 * Return :
1121 * 0 : No pending interrupts
1122 * 1 : Pending interrupts other than A9_M2A_5
1123 */
1124unsigned int msm_gic_spi_ppi_pending(void)
1125{
1126 unsigned int i, bit = 0;
1127 unsigned int pending_enb = 0, pending = 0;
1128 unsigned long value = 0;
1129 struct gic_chip_data *gic = &gic_data[0];
1130 void __iomem *base = gic_data_dist_base(gic);
1131
1132 raw_spin_lock(&irq_controller_lock);
1133 /*
1134 * PPI and SGI to be included.
1135 * MSM8625_INT_A9_M2A_5 needs to be ignored, as A9_M2A_5
1136 * requesting sleep triggers it
1137 */
1138 for (i = 0; (i * 32) < gic->max_irq; i++) {
1139 pending = readl_relaxed(base +
1140 GIC_DIST_PENDING_SET + i * 4);
1141 pending_enb = readl_relaxed(base +
1142 GIC_DIST_ENABLE_SET + i * 4);
1143 value = pending & pending_enb;
1144
1145 if (value) {
1146 for (bit = 0; bit < 32; bit++) {
1147 bit = find_next_bit(&value, 32, bit);
1148 if ((bit + 32 * i) != MSM8625_INT_A9_M2A_5) {
1149 raw_spin_unlock(&irq_controller_lock);
1150 return 1;
1151 }
1152 }
1153 }
1154 }
1155 raw_spin_unlock(&irq_controller_lock);
1156
1157 return 0;
1158}
1159
1160void msm_gic_save(bool modem_wake, int from_idle)
1161{
1162 unsigned int i;
1163 struct gic_chip_data *gic = &gic_data[0];
1164 void __iomem *base = gic_data_dist_base(gic);
1165
1166 gic_cpu_save(0);
1167 gic_dist_save(0);
1168 /* Disable all the Interrupts, if we enter from idle pc */
1169 if (from_idle) {
1170 for (i = 0; (i * 32) < gic->max_irq; i++) {
1171 raw_spin_lock(&irq_controller_lock);
1172 writel_relaxed(0xffffffff, base
1173 + GIC_DIST_ENABLE_CLEAR + i * 4);
1174 raw_spin_unlock(&irq_controller_lock);
1175 }
1176 }
1177}
1178
1179void msm_gic_restore(void)
1180{
1181 gic_dist_restore(0);
1182 gic_cpu_restore(0);
1183}
1184
1185/*
1186 * Configure the GIC after we come out of power collapse.
1187 * This function will configure some of the GIC registers so as to prepare the
1188 * core1 to receive an SPI(ACSR_MP_CORE_IPC1, (32 + 8)), which will bring
1189 * core1 out of GDFS.
1190 */
1191void core1_gic_configure_and_raise(void)
1192{
1193 struct gic_chip_data *gic = &gic_data[0];
1194 void __iomem *base = gic_data_dist_base(gic);
1195 unsigned int value = 0;
1196
1197 raw_spin_lock(&irq_controller_lock);
1198
1199 value = __raw_readl(base + GIC_DIST_ACTIVE_BIT + 0x4);
1200 value |= BIT(8);
1201 __raw_writel(value, base + GIC_DIST_ACTIVE_BIT + 0x4);
1202 mb();
1203
1204 value = __raw_readl(base + GIC_DIST_TARGET + 0x24);
1205 value |= BIT(13);
1206 __raw_writel(value, base + GIC_DIST_TARGET + 0x24);
1207 mb();
1208
1209 value = __raw_readl(base + GIC_DIST_TARGET + 0x28);
1210 value |= BIT(1);
1211 __raw_writel(value, base + GIC_DIST_TARGET + 0x28);
1212 mb();
1213
1214 value = __raw_readl(base + GIC_DIST_ENABLE_SET + 0x4);
1215 value |= BIT(8);
1216 __raw_writel(value, base + GIC_DIST_ENABLE_SET + 0x4);
1217 mb();
1218
1219 value = __raw_readl(base + GIC_DIST_PENDING_SET + 0x4);
1220 value |= BIT(8);
1221 __raw_writel(value, base + GIC_DIST_PENDING_SET + 0x4);
1222 mb();
1223 raw_spin_unlock(&irq_controller_lock);
1224}
1225#endif