blob: 54a839265d854bbfcf459dc7bdda677d725418e5 [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
Marc Zyngier680392b2011-11-12 16:09:49 +000067#ifdef CONFIG_IRQ_DOMAIN
68 struct irq_domain domain;
69#endif
Marc Zyngierdb0d4db2011-11-12 16:09:49 +000070 unsigned int gic_irqs;
71#ifdef CONFIG_GIC_NON_BANKED
72 void __iomem *(*get_base)(union gic_base *);
73#endif
Steve Mucklef132c6c2012-06-06 18:30:57 -070074 unsigned int max_irq;
75#ifdef CONFIG_PM
76 unsigned int wakeup_irqs[32];
77 unsigned int enabled_irqs[32];
78#endif
Marc Zyngierdb0d4db2011-11-12 16:09:49 +000079};
80
Thomas Gleixnerbd31b852009-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
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +010087/*
88 * Supported arch specific GIC irq extension.
89 * Default make them NULL.
90 */
91struct irq_chip gic_arch_extn = {
Will Deacon1a017532011-02-09 12:01:12 +000092 .irq_eoi = NULL,
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +010093 .irq_mask = NULL,
94 .irq_unmask = NULL,
95 .irq_retrigger = NULL,
96 .irq_set_type = NULL,
97 .irq_set_wake = NULL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070098 .irq_disable = NULL,
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +010099};
100
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100101#ifndef MAX_GIC_NR
102#define MAX_GIC_NR 1
103#endif
104
Russell Kingbef8f9e2010-12-04 16:50:58 +0000105static struct gic_chip_data gic_data[MAX_GIC_NR] __read_mostly;
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100106
Marc Zyngierdb0d4db2011-11-12 16:09:49 +0000107#ifdef CONFIG_GIC_NON_BANKED
108static void __iomem *gic_get_percpu_base(union gic_base *base)
109{
110 return *__this_cpu_ptr(base->percpu_base);
111}
112
113static void __iomem *gic_get_common_base(union gic_base *base)
114{
115 return base->common_base;
116}
117
118static inline void __iomem *gic_data_dist_base(struct gic_chip_data *data)
119{
120 return data->get_base(&data->dist_base);
121}
122
123static inline void __iomem *gic_data_cpu_base(struct gic_chip_data *data)
124{
125 return data->get_base(&data->cpu_base);
126}
127
128static inline void gic_set_base_accessor(struct gic_chip_data *data,
129 void __iomem *(*f)(union gic_base *))
130{
131 data->get_base = f;
132}
133#else
134#define gic_data_dist_base(d) ((d)->dist_base.common_base)
135#define gic_data_cpu_base(d) ((d)->cpu_base.common_base)
136#define gic_set_base_accessor(d,f)
137#endif
138
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100139static inline void __iomem *gic_dist_base(struct irq_data *d)
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100140{
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100141 struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
Marc Zyngierdb0d4db2011-11-12 16:09:49 +0000142 return gic_data_dist_base(gic_data);
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100143}
144
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100145static inline void __iomem *gic_cpu_base(struct irq_data *d)
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100146{
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100147 struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
Marc Zyngierdb0d4db2011-11-12 16:09:49 +0000148 return gic_data_cpu_base(gic_data);
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100149}
150
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100151static inline unsigned int gic_irq(struct irq_data *d)
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100152{
Rob Herring4294f8b2011-09-28 21:25:31 -0500153 return d->hwirq;
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100154}
155
Taniya Dasb241bd82012-03-19 17:58:06 +0530156#if defined(CONFIG_CPU_V7) && defined(CONFIG_GIC_SECURE)
Rohit Vaswani26e44862012-01-05 20:26:40 -0800157static const inline bool is_cpu_secure(void)
158{
159 unsigned int dscr;
160
161 asm volatile ("mrc p14, 0, %0, c0, c1, 0" : "=r" (dscr));
162
163 /* BIT(18) - NS bit; 1 = NS; 0 = S */
164 if (BIT(18) & dscr)
165 return false;
166 else
167 return true;
168}
169#else
170static const inline bool is_cpu_secure(void)
171{
172 return false;
173}
174#endif
175
Russell Kingf27ecac2005-08-18 21:31:00 +0100176/*
177 * Routines to acknowledge, disable and enable interrupts
Russell Kingf27ecac2005-08-18 21:31:00 +0100178 */
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100179static void gic_mask_irq(struct irq_data *d)
Russell Kingf27ecac2005-08-18 21:31:00 +0100180{
Rob Herring4294f8b2011-09-28 21:25:31 -0500181 u32 mask = 1 << (gic_irq(d) % 32);
Thomas Gleixnerc4bfa282006-07-01 22:32:14 +0100182
Thomas Gleixnerbd31b852009-07-03 08:44:46 -0500183 raw_spin_lock(&irq_controller_lock);
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530184 writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_CLEAR + (gic_irq(d) / 32) * 4);
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100185 if (gic_arch_extn.irq_mask)
186 gic_arch_extn.irq_mask(d);
Thomas Gleixnerbd31b852009-07-03 08:44:46 -0500187 raw_spin_unlock(&irq_controller_lock);
Russell Kingf27ecac2005-08-18 21:31:00 +0100188}
189
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100190static void gic_unmask_irq(struct irq_data *d)
Russell Kingf27ecac2005-08-18 21:31:00 +0100191{
Rob Herring4294f8b2011-09-28 21:25:31 -0500192 u32 mask = 1 << (gic_irq(d) % 32);
Thomas Gleixnerc4bfa282006-07-01 22:32:14 +0100193
Thomas Gleixnerbd31b852009-07-03 08:44:46 -0500194 raw_spin_lock(&irq_controller_lock);
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100195 if (gic_arch_extn.irq_unmask)
196 gic_arch_extn.irq_unmask(d);
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530197 writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
Thomas Gleixnerbd31b852009-07-03 08:44:46 -0500198 raw_spin_unlock(&irq_controller_lock);
Russell Kingf27ecac2005-08-18 21:31:00 +0100199}
200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700201static void gic_disable_irq(struct irq_data *d)
202{
203 if (gic_arch_extn.irq_disable)
204 gic_arch_extn.irq_disable(d);
205}
206
207#ifdef CONFIG_PM
208static int gic_suspend_one(struct gic_chip_data *gic)
209{
210 unsigned int i;
Marc Zyngier680392b2011-11-12 16:09:49 +0000211 void __iomem *base = gic_data_dist_base(gic);
Trilok Soni6278db02012-05-20 01:29:52 +0530212#ifdef CONFIG_ARCH_MSM8625
213 unsigned long flags;
214#endif
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
Trilok Soni6278db02012-05-20 01:29:52 +0530218 raw_spin_lock_irqsave(&irq_controller_lock, flags);
Taniya Das66398862012-04-30 12:24:17 +0530219#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
Trilok Soni6278db02012-05-20 01:29:52 +0530228 raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
Taniya Das66398862012-04-30 12:24:17 +0530229#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);
Trilok Soni6278db02012-05-20 01:29:52 +0530251#ifdef CONFIG_ARCH_MSM8625
252 unsigned long flags;
253#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700254
255 if (!msm_show_resume_irq_mask)
256 return;
257
Trilok Soni6278db02012-05-20 01:29:52 +0530258#ifdef CONFIG_ARCH_MSM8625
259 raw_spin_lock_irqsave(&irq_controller_lock, flags);
260#else
Thomas Gleixner450ea482009-07-03 08:44:46 -0500261 raw_spin_lock(&irq_controller_lock);
Trilok Soni6278db02012-05-20 01:29:52 +0530262#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700263 for (i = 0; i * 32 < gic->max_irq; i++) {
264 enabled = readl_relaxed(base + GIC_DIST_ENABLE_CLEAR + i * 4);
265 pending[i] = readl_relaxed(base + GIC_DIST_PENDING_SET + i * 4);
266 pending[i] &= enabled;
267 }
Trilok Soni6278db02012-05-20 01:29:52 +0530268#ifdef CONFIG_ARCH_MSM8625
269 raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
270#else
271 raw_spin_lock(&irq_controller_lock);
272#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700273
274 for (i = find_first_bit(pending, gic->max_irq);
275 i < gic->max_irq;
276 i = find_next_bit(pending, gic->max_irq, i+1)) {
277 pr_warning("%s: %d triggered", __func__,
278 i + gic->irq_offset);
279 }
280}
281
282static void gic_resume_one(struct gic_chip_data *gic)
283{
284 unsigned int i;
Marc Zyngier680392b2011-11-12 16:09:49 +0000285 void __iomem *base = gic_data_dist_base(gic);
Trilok Soni6278db02012-05-20 01:29:52 +0530286#ifdef CONFIG_ARCH_MSM8625
287 unsigned long flags;
288#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700289 gic_show_resume_irq(gic);
290 for (i = 0; i * 32 < gic->max_irq; i++) {
Taniya Das66398862012-04-30 12:24:17 +0530291#ifdef CONFIG_ARCH_MSM8625
Trilok Soni6278db02012-05-20 01:29:52 +0530292 raw_spin_lock_irqsave(&irq_controller_lock, flags);
Taniya Das66398862012-04-30 12:24:17 +0530293#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700294 /* disable all of them */
295 writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4);
296 /* enable the enabled set */
297 writel_relaxed(gic->enabled_irqs[i],
298 base + GIC_DIST_ENABLE_SET + i * 4);
Taniya Das66398862012-04-30 12:24:17 +0530299#ifdef CONFIG_ARCH_MSM8625
Trilok Soni6278db02012-05-20 01:29:52 +0530300 raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
Taniya Das66398862012-04-30 12:24:17 +0530301#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700302 }
303 mb();
304}
305
306static void gic_resume(void)
307{
308 int i;
309 for (i = 0; i < MAX_GIC_NR; i++)
310 gic_resume_one(&gic_data[i]);
311}
312
313static struct syscore_ops gic_syscore_ops = {
314 .suspend = gic_suspend,
315 .resume = gic_resume,
316};
317
318static int __init gic_init_sys(void)
319{
320 register_syscore_ops(&gic_syscore_ops);
321 return 0;
322}
323arch_initcall(gic_init_sys);
324
325#endif
326
Will Deacon1a017532011-02-09 12:01:12 +0000327static void gic_eoi_irq(struct irq_data *d)
328{
329 if (gic_arch_extn.irq_eoi) {
Thomas Gleixnerbd31b852009-07-03 08:44:46 -0500330 raw_spin_lock(&irq_controller_lock);
Will Deacon1a017532011-02-09 12:01:12 +0000331 gic_arch_extn.irq_eoi(d);
Thomas Gleixnerbd31b852009-07-03 08:44:46 -0500332 raw_spin_unlock(&irq_controller_lock);
Will Deacon1a017532011-02-09 12:01:12 +0000333 }
Taniya Das66398862012-04-30 12:24:17 +0530334#ifdef CONFIG_ARCH_MSM8625
335 raw_spin_lock(&irq_controller_lock);
336#endif
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530337 writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
Taniya Das66398862012-04-30 12:24:17 +0530338#ifdef CONFIG_ARCH_MSM8625
339 raw_spin_unlock(&irq_controller_lock);
340#endif
Will Deacon1a017532011-02-09 12:01:12 +0000341}
342
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100343static int gic_set_type(struct irq_data *d, unsigned int type)
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100344{
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100345 void __iomem *base = gic_dist_base(d);
346 unsigned int gicirq = gic_irq(d);
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100347 u32 enablemask = 1 << (gicirq % 32);
348 u32 enableoff = (gicirq / 32) * 4;
349 u32 confmask = 0x2 << ((gicirq % 16) * 2);
350 u32 confoff = (gicirq / 16) * 4;
351 bool enabled = false;
352 u32 val;
353
354 /* Interrupt configuration for SGIs can't be changed */
355 if (gicirq < 16)
356 return -EINVAL;
357
358 if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
359 return -EINVAL;
360
Thomas Gleixnerbd31b852009-07-03 08:44:46 -0500361 raw_spin_lock(&irq_controller_lock);
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100362
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100363 if (gic_arch_extn.irq_set_type)
364 gic_arch_extn.irq_set_type(d, type);
365
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530366 val = readl_relaxed(base + GIC_DIST_CONFIG + confoff);
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100367 if (type == IRQ_TYPE_LEVEL_HIGH)
368 val &= ~confmask;
369 else if (type == IRQ_TYPE_EDGE_RISING)
370 val |= confmask;
371
372 /*
373 * As recommended by the spec, disable the interrupt before changing
374 * the configuration
375 */
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530376 if (readl_relaxed(base + GIC_DIST_ENABLE_SET + enableoff) & enablemask) {
377 writel_relaxed(enablemask, base + GIC_DIST_ENABLE_CLEAR + enableoff);
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100378 enabled = true;
379 }
380
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530381 writel_relaxed(val, base + GIC_DIST_CONFIG + confoff);
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100382
383 if (enabled)
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530384 writel_relaxed(enablemask, base + GIC_DIST_ENABLE_SET + enableoff);
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100385
Thomas Gleixnerbd31b852009-07-03 08:44:46 -0500386 raw_spin_unlock(&irq_controller_lock);
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100387
388 return 0;
389}
390
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100391static int gic_retrigger(struct irq_data *d)
392{
393 if (gic_arch_extn.irq_retrigger)
394 return gic_arch_extn.irq_retrigger(d);
395
396 return -ENXIO;
397}
398
Catalin Marinasa06f5462005-09-30 16:07:05 +0100399#ifdef CONFIG_SMP
Russell Kingc1917892011-01-23 12:12:01 +0000400static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
401 bool force)
Russell Kingf27ecac2005-08-18 21:31:00 +0100402{
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100403 void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) & ~3);
Rob Herring4294f8b2011-09-28 21:25:31 -0500404 unsigned int shift = (gic_irq(d) % 4) * 8;
Russell King5dfc54e2011-07-21 15:00:57 +0100405 unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask);
Russell Kingc1917892011-01-23 12:12:01 +0000406 u32 val, mask, bit;
407
Russell King5dfc54e2011-07-21 15:00:57 +0100408 if (cpu >= 8 || cpu >= nr_cpu_ids)
Russell Kingc1917892011-01-23 12:12:01 +0000409 return -EINVAL;
410
411 mask = 0xff << shift;
Will Deacon267840f2011-08-23 22:20:03 +0100412 bit = 1 << (cpu_logical_map(cpu) + shift);
Russell Kingf27ecac2005-08-18 21:31:00 +0100413
Thomas Gleixnerbd31b852009-07-03 08:44:46 -0500414 raw_spin_lock(&irq_controller_lock);
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530415 val = readl_relaxed(reg) & ~mask;
416 writel_relaxed(val | bit, reg);
Thomas Gleixnerbd31b852009-07-03 08:44:46 -0500417 raw_spin_unlock(&irq_controller_lock);
Yinghai Lud5dedd42009-04-27 17:59:21 -0700418
Russell King5dfc54e2011-07-21 15:00:57 +0100419 return IRQ_SET_MASK_OK;
Russell Kingf27ecac2005-08-18 21:31:00 +0100420}
Catalin Marinasa06f5462005-09-30 16:07:05 +0100421#endif
Russell Kingf27ecac2005-08-18 21:31:00 +0100422
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100423#ifdef CONFIG_PM
424static int gic_set_wake(struct irq_data *d, unsigned int on)
425{
426 int ret = -ENXIO;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700427 unsigned int reg_offset, bit_offset;
428 unsigned int gicirq = gic_irq(d);
429 struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
430
431 /* per-cpu interrupts cannot be wakeup interrupts */
432 WARN_ON(gicirq < 32);
433
434 reg_offset = gicirq / 32;
435 bit_offset = gicirq % 32;
436
437 if (on)
438 gic_data->wakeup_irqs[reg_offset] |= 1 << bit_offset;
439 else
440 gic_data->wakeup_irqs[reg_offset] &= ~(1 << bit_offset);
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100441
442 if (gic_arch_extn.irq_set_wake)
443 ret = gic_arch_extn.irq_set_wake(d, on);
444
445 return ret;
446}
447
448#else
449#define gic_set_wake NULL
450#endif
451
Marc Zyngier562e0022011-09-06 09:56:17 +0100452asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
453{
454 u32 irqstat, irqnr;
455 struct gic_chip_data *gic = &gic_data[0];
456 void __iomem *cpu_base = gic_data_cpu_base(gic);
457
458 do {
Taniya Das66398862012-04-30 12:24:17 +0530459#ifdef CONFIG_ARCH_MSM8625
460 raw_spin_lock(&irq_controller_lock);
461#endif
Marc Zyngier562e0022011-09-06 09:56:17 +0100462 irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
Taniya Das66398862012-04-30 12:24:17 +0530463#ifdef CONFIG_ARCH_MSM8625
464 raw_spin_unlock(&irq_controller_lock);
465#endif
Marc Zyngier562e0022011-09-06 09:56:17 +0100466 irqnr = irqstat & ~0x1c00;
467
468 if (likely(irqnr > 15 && irqnr < 1021)) {
Marc Zyngier181621e2011-09-06 09:56:17 +0100469 irqnr = irq_domain_to_irq(&gic->domain, irqnr);
Marc Zyngier562e0022011-09-06 09:56:17 +0100470 handle_IRQ(irqnr, regs);
471 continue;
472 }
473 if (irqnr < 16) {
Taniya Das66398862012-04-30 12:24:17 +0530474#ifdef CONFIG_ARCH_MSM8625
475 raw_spin_lock(&irq_controller_lock);
476#endif
Marc Zyngier562e0022011-09-06 09:56:17 +0100477 writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
Taniya Das66398862012-04-30 12:24:17 +0530478#ifdef CONFIG_ARCH_MSM8625
479 raw_spin_unlock(&irq_controller_lock);
480#endif
Marc Zyngier562e0022011-09-06 09:56:17 +0100481#ifdef CONFIG_SMP
482 handle_IPI(irqnr, regs);
483#endif
484 continue;
485 }
486 break;
487 } while (1);
488}
489
Russell King0f347bb2007-05-17 10:11:34 +0100490static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100491{
Thomas Gleixner6845664a2011-03-24 13:25:22 +0100492 struct gic_chip_data *chip_data = irq_get_handler_data(irq);
493 struct irq_chip *chip = irq_get_chip(irq);
Russell King0f347bb2007-05-17 10:11:34 +0100494 unsigned int cascade_irq, gic_irq;
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100495 unsigned long status;
496
Will Deacon1a017532011-02-09 12:01:12 +0000497 chained_irq_enter(chip, desc);
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100498
Thomas Gleixnerbd31b852009-07-03 08:44:46 -0500499 raw_spin_lock(&irq_controller_lock);
Marc Zyngierdb0d4db2011-11-12 16:09:49 +0000500 status = readl_relaxed(gic_data_cpu_base(chip_data) + GIC_CPU_INTACK);
Thomas Gleixnerbd31b852009-07-03 08:44:46 -0500501 raw_spin_unlock(&irq_controller_lock);
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100502
Russell King0f347bb2007-05-17 10:11:34 +0100503 gic_irq = (status & 0x3ff);
504 if (gic_irq == 1023)
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100505 goto out;
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100506
Rob Herringc383e042011-09-28 21:25:31 -0500507 cascade_irq = irq_domain_to_irq(&chip_data->domain, gic_irq);
Russell King0f347bb2007-05-17 10:11:34 +0100508 if (unlikely(gic_irq < 32 || gic_irq > 1020 || cascade_irq >= NR_IRQS))
509 do_bad_IRQ(cascade_irq, desc);
510 else
511 generic_handle_irq(cascade_irq);
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100512
513 out:
Will Deacon1a017532011-02-09 12:01:12 +0000514 chained_irq_exit(chip, desc);
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100515}
516
David Brownell38c677c2006-08-01 22:26:25 +0100517static struct irq_chip gic_chip = {
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100518 .name = "GIC",
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100519 .irq_mask = gic_mask_irq,
520 .irq_unmask = gic_unmask_irq,
Will Deacon1a017532011-02-09 12:01:12 +0000521 .irq_eoi = gic_eoi_irq,
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100522 .irq_set_type = gic_set_type,
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100523 .irq_retrigger = gic_retrigger,
Russell Kingf27ecac2005-08-18 21:31:00 +0100524#ifdef CONFIG_SMP
Russell Kingc1917892011-01-23 12:12:01 +0000525 .irq_set_affinity = gic_set_affinity,
Russell Kingf27ecac2005-08-18 21:31:00 +0100526#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700527 .irq_disable = gic_disable_irq,
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100528 .irq_set_wake = gic_set_wake,
Russell Kingf27ecac2005-08-18 21:31:00 +0100529};
530
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100531void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
532{
533 if (gic_nr >= MAX_GIC_NR)
534 BUG();
Thomas Gleixner6845664a2011-03-24 13:25:22 +0100535 if (irq_set_handler_data(irq, &gic_data[gic_nr]) != 0)
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100536 BUG();
Thomas Gleixner6845664a2011-03-24 13:25:22 +0100537 irq_set_chained_handler(irq, gic_handle_cascade_irq);
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100538}
539
Rob Herring4294f8b2011-09-28 21:25:31 -0500540static void __init gic_dist_init(struct gic_chip_data *gic)
Russell Kingf27ecac2005-08-18 21:31:00 +0100541{
Rob Herringc383e042011-09-28 21:25:31 -0500542 unsigned int i, irq;
Will Deacon267840f2011-08-23 22:20:03 +0100543 u32 cpumask;
Rob Herring4294f8b2011-09-28 21:25:31 -0500544 unsigned int gic_irqs = gic->gic_irqs;
Rob Herringc383e042011-09-28 21:25:31 -0500545 struct irq_domain *domain = &gic->domain;
Marc Zyngierdb0d4db2011-11-12 16:09:49 +0000546 void __iomem *base = gic_data_dist_base(gic);
Will Deaconeb504392012-01-20 12:01:12 +0100547 u32 cpu = cpu_logical_map(smp_processor_id());
Will Deacon267840f2011-08-23 22:20:03 +0100548
549 cpumask = 1 << cpu;
Russell Kingf27ecac2005-08-18 21:31:00 +0100550 cpumask |= cpumask << 8;
551 cpumask |= cpumask << 16;
552
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530553 writel_relaxed(0, base + GIC_DIST_CTRL);
Russell Kingf27ecac2005-08-18 21:31:00 +0100554
555 /*
Russell Kingf27ecac2005-08-18 21:31:00 +0100556 * Set all global interrupts to be level triggered, active low.
557 */
Pawel Molle6afec92010-11-26 13:45:43 +0100558 for (i = 32; i < gic_irqs; i += 16)
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530559 writel_relaxed(0, base + GIC_DIST_CONFIG + i * 4 / 16);
Russell Kingf27ecac2005-08-18 21:31:00 +0100560
561 /*
562 * Set all global interrupts to this CPU only.
563 */
Pawel Molle6afec92010-11-26 13:45:43 +0100564 for (i = 32; i < gic_irqs; i += 4)
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530565 writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4 / 4);
Russell Kingf27ecac2005-08-18 21:31:00 +0100566
567 /*
Rohit Vaswani26e44862012-01-05 20:26:40 -0800568 * Set NS/S.
569 */
570 if (is_cpu_secure())
571 for (i = 32; i < gic_irqs; i += 32)
572 writel_relaxed(0xFFFFFFFF,
573 base + GIC_DIST_ISR + i * 4 / 32);
574
575 /*
Russell King9395f6e2010-11-11 23:10:30 +0000576 * Set priority on all global interrupts.
Russell Kingf27ecac2005-08-18 21:31:00 +0100577 */
Pawel Molle6afec92010-11-26 13:45:43 +0100578 for (i = 32; i < gic_irqs; i += 4)
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530579 writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
Russell Kingf27ecac2005-08-18 21:31:00 +0100580
581 /*
Russell King9395f6e2010-11-11 23:10:30 +0000582 * Disable all interrupts. Leave the PPI and SGIs alone
583 * as these enables are banked registers.
Russell Kingf27ecac2005-08-18 21:31:00 +0100584 */
Pawel Molle6afec92010-11-26 13:45:43 +0100585 for (i = 32; i < gic_irqs; i += 32)
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530586 writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
Russell Kingf27ecac2005-08-18 21:31:00 +0100587
588 /*
589 * Setup the Linux IRQ subsystem.
590 */
Rob Herringc383e042011-09-28 21:25:31 -0500591 irq_domain_for_each_irq(domain, i, irq) {
592 if (i < 32) {
593 irq_set_percpu_devid(irq);
594 irq_set_chip_and_handler(irq, &gic_chip,
595 handle_percpu_devid_irq);
596 set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN);
597 } else {
598 irq_set_chip_and_handler(irq, &gic_chip,
599 handle_fasteoi_irq);
600 set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
601 }
602 irq_set_chip_data(irq, gic);
Russell Kingf27ecac2005-08-18 21:31:00 +0100603 }
604
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700605 gic->max_irq = gic_irqs;
606
Rohit Vaswani26e44862012-01-05 20:26:40 -0800607 if (is_cpu_secure())
608 writel_relaxed(3, base + GIC_DIST_CTRL);
609 else
610 writel_relaxed(1, base + GIC_DIST_CTRL);
611
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700612 mb();
Russell Kingf27ecac2005-08-18 21:31:00 +0100613}
614
Russell Kingbef8f9e2010-12-04 16:50:58 +0000615static void __cpuinit gic_cpu_init(struct gic_chip_data *gic)
Russell Kingf27ecac2005-08-18 21:31:00 +0100616{
Marc Zyngierdb0d4db2011-11-12 16:09:49 +0000617 void __iomem *dist_base = gic_data_dist_base(gic);
618 void __iomem *base = gic_data_cpu_base(gic);
Russell King9395f6e2010-11-11 23:10:30 +0000619 int i;
620
Russell King9395f6e2010-11-11 23:10:30 +0000621 /*
622 * Deal with the banked PPI and SGI interrupts - disable all
623 * PPI interrupts, ensure all SGI interrupts are enabled.
624 */
Taniya Das66398862012-04-30 12:24:17 +0530625#ifdef CONFIG_ARCH_MSM8625
626 raw_spin_lock(&irq_controller_lock);
627#endif
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530628 writel_relaxed(0xffff0000, dist_base + GIC_DIST_ENABLE_CLEAR);
629 writel_relaxed(0x0000ffff, dist_base + GIC_DIST_ENABLE_SET);
Russell King9395f6e2010-11-11 23:10:30 +0000630
Rohit Vaswani26e44862012-01-05 20:26:40 -0800631 /* Set NS/S */
632 if (is_cpu_secure())
633 writel_relaxed(0xFFFFFFFF, dist_base + GIC_DIST_ISR);
634
Russell King9395f6e2010-11-11 23:10:30 +0000635 /*
636 * Set priority on PPI and SGI interrupts
637 */
638 for (i = 0; i < 32; i += 4)
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530639 writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
Russell King9395f6e2010-11-11 23:10:30 +0000640
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530641 writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
Rohit Vaswani26e44862012-01-05 20:26:40 -0800642
643 if (is_cpu_secure())
644 writel_relaxed(0xF, base + GIC_CPU_CTRL);
645 else
646 writel_relaxed(1, base + GIC_CPU_CTRL);
Taniya Das66398862012-04-30 12:24:17 +0530647#ifdef CONFIG_ARCH_MSM8625
648 raw_spin_unlock(&irq_controller_lock);
649#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700650 mb();
Russell Kingf27ecac2005-08-18 21:31:00 +0100651}
652
Colin Cross254056f2011-02-10 12:54:10 -0800653#ifdef CONFIG_CPU_PM
654/*
655 * Saves the GIC distributor registers during suspend or idle. Must be called
656 * with interrupts disabled but before powering down the GIC. After calling
657 * this function, no interrupts will be delivered by the GIC, and another
658 * platform-specific wakeup source must be enabled.
659 */
660static void gic_dist_save(unsigned int gic_nr)
661{
662 unsigned int gic_irqs;
663 void __iomem *dist_base;
664 int i;
665
666 if (gic_nr >= MAX_GIC_NR)
667 BUG();
668
669 gic_irqs = gic_data[gic_nr].gic_irqs;
Marc Zyngierdb0d4db2011-11-12 16:09:49 +0000670 dist_base = gic_data_dist_base(&gic_data[gic_nr]);
Colin Cross254056f2011-02-10 12:54:10 -0800671
672 if (!dist_base)
673 return;
674
Rohit Vaswani26e44862012-01-05 20:26:40 -0800675 saved_dist_ctrl = readl_relaxed(dist_base + GIC_DIST_CTRL);
676
Colin Cross254056f2011-02-10 12:54:10 -0800677 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 16); i++)
678 gic_data[gic_nr].saved_spi_conf[i] =
679 readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4);
680
681 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
682 gic_data[gic_nr].saved_spi_target[i] =
683 readl_relaxed(dist_base + GIC_DIST_TARGET + i * 4);
684
Rohit Vaswani26e44862012-01-05 20:26:40 -0800685 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
686 gic_data[gic_nr].saved_dist_pri[i] =
687 readl_relaxed(dist_base + GIC_DIST_PRI + i * 4);
688
Colin Cross254056f2011-02-10 12:54:10 -0800689 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++)
690 gic_data[gic_nr].saved_spi_enable[i] =
691 readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
692}
693
694/*
695 * Restores the GIC distributor registers during resume or when coming out of
696 * idle. Must be called before enabling interrupts. If a level interrupt
697 * that occured while the GIC was suspended is still present, it will be
698 * handled normally, but any edge interrupts that occured will not be seen by
699 * the GIC and need to be handled by the platform-specific wakeup source.
700 */
701static void gic_dist_restore(unsigned int gic_nr)
702{
703 unsigned int gic_irqs;
704 unsigned int i;
705 void __iomem *dist_base;
706
707 if (gic_nr >= MAX_GIC_NR)
708 BUG();
709
710 gic_irqs = gic_data[gic_nr].gic_irqs;
Marc Zyngierdb0d4db2011-11-12 16:09:49 +0000711 dist_base = gic_data_dist_base(&gic_data[gic_nr]);
Colin Cross254056f2011-02-10 12:54:10 -0800712
713 if (!dist_base)
714 return;
715
716 writel_relaxed(0, dist_base + GIC_DIST_CTRL);
717
718 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 16); i++)
719 writel_relaxed(gic_data[gic_nr].saved_spi_conf[i],
720 dist_base + GIC_DIST_CONFIG + i * 4);
721
722 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
Rohit Vaswani26e44862012-01-05 20:26:40 -0800723 writel_relaxed(gic_data[gic_nr].saved_dist_pri[i],
Colin Cross254056f2011-02-10 12:54:10 -0800724 dist_base + GIC_DIST_PRI + i * 4);
725
726 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
727 writel_relaxed(gic_data[gic_nr].saved_spi_target[i],
728 dist_base + GIC_DIST_TARGET + i * 4);
729
730 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++)
731 writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
732 dist_base + GIC_DIST_ENABLE_SET + i * 4);
733
Rohit Vaswani26e44862012-01-05 20:26:40 -0800734 writel_relaxed(saved_dist_ctrl, dist_base + GIC_DIST_CTRL);
Colin Cross254056f2011-02-10 12:54:10 -0800735}
736
737static void gic_cpu_save(unsigned int gic_nr)
738{
739 int i;
740 u32 *ptr;
741 void __iomem *dist_base;
742 void __iomem *cpu_base;
743
744 if (gic_nr >= MAX_GIC_NR)
745 BUG();
746
Marc Zyngierdb0d4db2011-11-12 16:09:49 +0000747 dist_base = gic_data_dist_base(&gic_data[gic_nr]);
748 cpu_base = gic_data_cpu_base(&gic_data[gic_nr]);
Colin Cross254056f2011-02-10 12:54:10 -0800749
750 if (!dist_base || !cpu_base)
751 return;
752
Rohit Vaswani26e44862012-01-05 20:26:40 -0800753 saved_cpu_ctrl = readl_relaxed(cpu_base + GIC_CPU_CTRL);
754
755 for (i = 0; i < DIV_ROUND_UP(32, 4); i++)
756 gic_data[gic_nr].saved_dist_pri[i] = readl_relaxed(dist_base +
757 GIC_DIST_PRI + i * 4);
758
Colin Cross254056f2011-02-10 12:54:10 -0800759 ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_enable);
760 for (i = 0; i < DIV_ROUND_UP(32, 32); i++)
761 ptr[i] = readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
762
763 ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_conf);
764 for (i = 0; i < DIV_ROUND_UP(32, 16); i++)
765 ptr[i] = readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4);
766
767}
768
769static void gic_cpu_restore(unsigned int gic_nr)
770{
771 int i;
772 u32 *ptr;
773 void __iomem *dist_base;
774 void __iomem *cpu_base;
775
776 if (gic_nr >= MAX_GIC_NR)
777 BUG();
778
Marc Zyngierdb0d4db2011-11-12 16:09:49 +0000779 dist_base = gic_data_dist_base(&gic_data[gic_nr]);
780 cpu_base = gic_data_cpu_base(&gic_data[gic_nr]);
Colin Cross254056f2011-02-10 12:54:10 -0800781
782 if (!dist_base || !cpu_base)
783 return;
784
785 ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_enable);
786 for (i = 0; i < DIV_ROUND_UP(32, 32); i++)
787 writel_relaxed(ptr[i], dist_base + GIC_DIST_ENABLE_SET + i * 4);
788
789 ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_conf);
790 for (i = 0; i < DIV_ROUND_UP(32, 16); i++)
791 writel_relaxed(ptr[i], dist_base + GIC_DIST_CONFIG + i * 4);
792
793 for (i = 0; i < DIV_ROUND_UP(32, 4); i++)
Rohit Vaswani26e44862012-01-05 20:26:40 -0800794 writel_relaxed(gic_data[gic_nr].saved_dist_pri[i],
795 dist_base + GIC_DIST_PRI + i * 4);
Colin Cross254056f2011-02-10 12:54:10 -0800796
797 writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
Rohit Vaswani26e44862012-01-05 20:26:40 -0800798 writel_relaxed(saved_cpu_ctrl, cpu_base + GIC_CPU_CTRL);
Colin Cross254056f2011-02-10 12:54:10 -0800799}
800
801static int gic_notifier(struct notifier_block *self, unsigned long cmd, void *v)
802{
803 int i;
804
805 for (i = 0; i < MAX_GIC_NR; i++) {
Marc Zyngierdb0d4db2011-11-12 16:09:49 +0000806#ifdef CONFIG_GIC_NON_BANKED
807 /* Skip over unused GICs */
808 if (!gic_data[i].get_base)
809 continue;
810#endif
Colin Cross254056f2011-02-10 12:54:10 -0800811 switch (cmd) {
812 case CPU_PM_ENTER:
813 gic_cpu_save(i);
814 break;
815 case CPU_PM_ENTER_FAILED:
816 case CPU_PM_EXIT:
817 gic_cpu_restore(i);
818 break;
819 case CPU_CLUSTER_PM_ENTER:
820 gic_dist_save(i);
821 break;
822 case CPU_CLUSTER_PM_ENTER_FAILED:
823 case CPU_CLUSTER_PM_EXIT:
824 gic_dist_restore(i);
825 break;
826 }
827 }
828
829 return NOTIFY_OK;
830}
831
832static struct notifier_block gic_notifier_block = {
833 .notifier_call = gic_notifier,
834};
835
836static void __init gic_pm_init(struct gic_chip_data *gic)
837{
838 gic->saved_ppi_enable = __alloc_percpu(DIV_ROUND_UP(32, 32) * 4,
839 sizeof(u32));
840 BUG_ON(!gic->saved_ppi_enable);
841
842 gic->saved_ppi_conf = __alloc_percpu(DIV_ROUND_UP(32, 16) * 4,
843 sizeof(u32));
844 BUG_ON(!gic->saved_ppi_conf);
845
Marc Zyngierabdd7b92011-11-25 17:58:19 +0100846 if (gic == &gic_data[0])
847 cpu_pm_register_notifier(&gic_notifier_block);
Colin Cross254056f2011-02-10 12:54:10 -0800848}
849#else
850static void __init gic_pm_init(struct gic_chip_data *gic)
851{
852}
853#endif
854
Rob Herring0fc0d942011-09-28 21:27:52 -0500855#ifdef CONFIG_OF
856static int gic_irq_domain_dt_translate(struct irq_domain *d,
857 struct device_node *controller,
858 const u32 *intspec, unsigned int intsize,
859 unsigned long *out_hwirq, unsigned int *out_type)
Rob Herringb3f7ed02011-09-28 21:27:52 -0500860{
861 if (d->of_node != controller)
862 return -EINVAL;
863 if (intsize < 3)
864 return -EINVAL;
865
866 /* Get the interrupt number and add 16 to skip over SGIs */
867 *out_hwirq = intspec[1] + 16;
868
869 /* For SPIs, we need to add 16 more to get the GIC irq ID number */
870 if (!intspec[0])
871 *out_hwirq += 16;
872
873 *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK;
874 return 0;
875}
Rob Herring0fc0d942011-09-28 21:27:52 -0500876#endif
Rob Herringb3f7ed02011-09-28 21:27:52 -0500877
Grant Likely15a25982012-01-26 12:25:18 -0700878const struct irq_domain_ops gic_irq_domain_ops = {
Rob Herring0fc0d942011-09-28 21:27:52 -0500879#ifdef CONFIG_OF
880 .dt_translate = gic_irq_domain_dt_translate,
881#endif
Rob Herring4294f8b2011-09-28 21:25:31 -0500882};
883
Marc Zyngierdb0d4db2011-11-12 16:09:49 +0000884void __init gic_init_bases(unsigned int gic_nr, int irq_start,
885 void __iomem *dist_base, void __iomem *cpu_base,
Marc Zyngier680392b2011-11-12 16:09:49 +0000886 u32 percpu_offset)
Russell Kingb580b892010-12-04 15:55:14 +0000887{
Russell Kingbef8f9e2010-12-04 16:50:58 +0000888 struct gic_chip_data *gic;
Rob Herringc383e042011-09-28 21:25:31 -0500889 struct irq_domain *domain;
Michael Bohan33efecf2012-01-12 15:32:21 -0800890 int gic_irqs, rc;
Russell Kingbef8f9e2010-12-04 16:50:58 +0000891
892 BUG_ON(gic_nr >= MAX_GIC_NR);
893
894 gic = &gic_data[gic_nr];
Rob Herringc383e042011-09-28 21:25:31 -0500895 domain = &gic->domain;
Marc Zyngierdb0d4db2011-11-12 16:09:49 +0000896#ifdef CONFIG_GIC_NON_BANKED
897 if (percpu_offset) { /* Frankein-GIC without banked registers... */
898 unsigned int cpu;
899
900 gic->dist_base.percpu_base = alloc_percpu(void __iomem *);
901 gic->cpu_base.percpu_base = alloc_percpu(void __iomem *);
902 if (WARN_ON(!gic->dist_base.percpu_base ||
Michael Bohan33efecf2012-01-12 15:32:21 -0800903 !gic->cpu_base.percpu_base))
904 goto init_bases_err;
Marc Zyngierdb0d4db2011-11-12 16:09:49 +0000905
906 for_each_possible_cpu(cpu) {
907 unsigned long offset = percpu_offset * cpu_logical_map(cpu);
908 *per_cpu_ptr(gic->dist_base.percpu_base, cpu) = dist_base + offset;
909 *per_cpu_ptr(gic->cpu_base.percpu_base, cpu) = cpu_base + offset;
910 }
911
912 gic_set_base_accessor(gic, gic_get_percpu_base);
913 } else
914#endif
915 { /* Normal, sane GIC... */
916 WARN(percpu_offset,
917 "GIC_NON_BANKED not enabled, ignoring %08x offset!",
918 percpu_offset);
919 gic->dist_base.common_base = dist_base;
920 gic->cpu_base.common_base = cpu_base;
921 gic_set_base_accessor(gic, gic_get_common_base);
922 }
Russell Kingbef8f9e2010-12-04 16:50:58 +0000923
Rob Herring4294f8b2011-09-28 21:25:31 -0500924 /*
925 * For primary GICs, skip over SGIs.
926 * For secondary GICs, skip over PPIs, too.
927 */
Steve Mucklef132c6c2012-06-06 18:30:57 -0700928 domain->hwirq_base = 32;
Rob Herringc383e042011-09-28 21:25:31 -0500929 if (gic_nr == 0) {
Steve Mucklef132c6c2012-06-06 18:30:57 -0700930 if ((irq_start & 31) > 0) {
931 domain->hwirq_base = 16;
932 if (irq_start != -1)
933 irq_start = (irq_start & ~31) + 16;
934 }
Will Deaconfe41db72011-11-25 19:23:36 +0100935 }
Rob Herring4294f8b2011-09-28 21:25:31 -0500936
937 /*
938 * Find out how many interrupts are supported.
939 * The GIC only supports up to 1020 interrupt sources.
940 */
Marc Zyngierdb0d4db2011-11-12 16:09:49 +0000941 gic_irqs = readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_CTR) & 0x1f;
Rob Herring4294f8b2011-09-28 21:25:31 -0500942 gic_irqs = (gic_irqs + 1) * 32;
943 if (gic_irqs > 1020)
944 gic_irqs = 1020;
945 gic->gic_irqs = gic_irqs;
946
Rob Herringc383e042011-09-28 21:25:31 -0500947 domain->nr_irq = gic_irqs - domain->hwirq_base;
Rob Herring050113e2011-10-21 17:14:27 -0500948 domain->irq_base = irq_alloc_descs(irq_start, 16, domain->nr_irq,
Rob Herringc383e042011-09-28 21:25:31 -0500949 numa_node_id());
Rob Herring050113e2011-10-21 17:14:27 -0500950 if (IS_ERR_VALUE(domain->irq_base)) {
Rob Herringf37a53c2011-10-21 17:14:27 -0500951 WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
952 irq_start);
Rob Herring050113e2011-10-21 17:14:27 -0500953 domain->irq_base = irq_start;
Rob Herringf37a53c2011-10-21 17:14:27 -0500954 }
Rob Herringc383e042011-09-28 21:25:31 -0500955 domain->priv = gic;
956 domain->ops = &gic_irq_domain_ops;
Michael Bohan33efecf2012-01-12 15:32:21 -0800957 rc = irq_domain_add(domain);
958 if (rc) {
959 WARN(1, "Unable to create irq_domain\n");
960 goto init_bases_err;
961 }
Michael Bohanb8635c32012-01-05 18:32:10 -0800962 irq_domain_register(domain);
Russell Kingbef8f9e2010-12-04 16:50:58 +0000963
Colin Cross9c128452011-06-13 00:45:59 +0000964 gic_chip.flags |= gic_arch_extn.flags;
Rob Herring4294f8b2011-09-28 21:25:31 -0500965 gic_dist_init(gic);
Russell Kingbef8f9e2010-12-04 16:50:58 +0000966 gic_cpu_init(gic);
Colin Cross254056f2011-02-10 12:54:10 -0800967 gic_pm_init(gic);
Michael Bohan33efecf2012-01-12 15:32:21 -0800968
969 return;
970
971init_bases_err:
972 free_percpu(gic->dist_base.percpu_base);
973 free_percpu(gic->cpu_base.percpu_base);
Russell Kingb580b892010-12-04 15:55:14 +0000974}
975
Russell King38489532010-12-04 16:01:03 +0000976void __cpuinit gic_secondary_init(unsigned int gic_nr)
977{
Russell Kingbef8f9e2010-12-04 16:50:58 +0000978 BUG_ON(gic_nr >= MAX_GIC_NR);
979
980 gic_cpu_init(&gic_data[gic_nr]);
Russell King38489532010-12-04 16:01:03 +0000981}
982
Russell Kingf27ecac2005-08-18 21:31:00 +0100983#ifdef CONFIG_SMP
Russell King82668102009-05-17 16:20:18 +0100984void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
Russell Kingf27ecac2005-08-18 21:31:00 +0100985{
Will Deacon267840f2011-08-23 22:20:03 +0100986 int cpu;
Rohit Vaswani26e44862012-01-05 20:26:40 -0800987 unsigned long sgir;
Will Deacon267840f2011-08-23 22:20:03 +0100988 unsigned long map = 0;
Taniya Das66398862012-04-30 12:24:17 +0530989#ifdef CONFIG_ARCH_MSM8625
990 unsigned long flags;
991#endif
Will Deacon267840f2011-08-23 22:20:03 +0100992
993 /* Convert our logical CPU mask into a physical one. */
994 for_each_cpu(cpu, mask)
995 map |= 1 << cpu_logical_map(cpu);
Russell Kingf27ecac2005-08-18 21:31:00 +0100996
Rohit Vaswani26e44862012-01-05 20:26:40 -0800997 sgir = (map << 16) | irq;
998 if (is_cpu_secure())
999 sgir |= (1 << 15);
1000
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +05301001 /*
1002 * Ensure that stores to Normal memory are visible to the
1003 * other CPUs before issuing the IPI.
1004 */
1005 dsb();
1006
Taniya Das66398862012-04-30 12:24:17 +05301007#ifdef CONFIG_ARCH_MSM8625
1008 raw_spin_lock_irqsave(&irq_controller_lock, flags);
1009#endif
Catalin Marinasb3a1bde2007-02-14 19:14:56 +01001010 /* this always happens on GIC0 */
Steve Mucklef132c6c2012-06-06 18:30:57 -07001011
Rohit Vaswani26e44862012-01-05 20:26:40 -08001012 writel_relaxed(sgir,
1013 gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
Taniya Das66398862012-04-30 12:24:17 +05301014#ifdef CONFIG_ARCH_MSM8625
1015 raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
1016#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001017 mb();
Russell Kingf27ecac2005-08-18 21:31:00 +01001018}
1019#endif
Rob Herringb3f7ed02011-09-28 21:27:52 -05001020
Rohit Vaswani26e44862012-01-05 20:26:40 -08001021void gic_set_irq_secure(unsigned int irq)
1022{
1023 unsigned int gicd_isr_reg, gicd_pri_reg;
1024 unsigned int mask = 0xFFFFFF00;
1025 struct gic_chip_data *gic_data = &gic_data[0];
1026 struct irq_data *d = irq_get_irq_data(irq);
1027
1028 if (is_cpu_secure()) {
1029 raw_spin_lock(&irq_controller_lock);
1030 gicd_isr_reg = readl_relaxed(gic_dist_base(d) +
1031 GIC_DIST_ISR + gic_irq(d) / 32 * 4);
1032 gicd_isr_reg &= ~BIT(gic_irq(d) % 32);
1033 writel_relaxed(gicd_isr_reg, gic_dist_base(d) +
1034 GIC_DIST_ISR + gic_irq(d) / 32 * 4);
1035 /* Also increase the priority of that irq */
1036 gicd_pri_reg = readl_relaxed(gic_dist_base(d) +
1037 GIC_DIST_PRI + (gic_irq(d) * 4 / 4));
1038 gicd_pri_reg &= mask;
1039 gicd_pri_reg |= 0x80; /* Priority of 0x80 > 0xA0 */
1040 writel_relaxed(gicd_pri_reg, gic_dist_base(d) + GIC_DIST_PRI +
1041 gic_irq(d) * 4 / 4);
1042 mb();
1043 raw_spin_unlock(&irq_controller_lock);
1044 } else {
1045 WARN(1, "Trying to run secure operation from Non-secure mode");
1046 }
1047}
1048
Rob Herringb3f7ed02011-09-28 21:27:52 -05001049#ifdef CONFIG_OF
1050static int gic_cnt __initdata = 0;
1051
1052int __init gic_of_init(struct device_node *node, struct device_node *parent)
1053{
1054 void __iomem *cpu_base;
1055 void __iomem *dist_base;
Marc Zyngierdb0d4db2011-11-12 16:09:49 +00001056 u32 percpu_offset;
Rob Herringb3f7ed02011-09-28 21:27:52 -05001057 int irq;
Steve Mucklef132c6c2012-06-06 18:30:57 -07001058 struct irq_domain *domain = &gic_data[gic_cnt].domain;
Rob Herringb3f7ed02011-09-28 21:27:52 -05001059
1060 if (WARN_ON(!node))
1061 return -ENODEV;
1062
1063 dist_base = of_iomap(node, 0);
1064 WARN(!dist_base, "unable to map gic dist registers\n");
1065
1066 cpu_base = of_iomap(node, 1);
1067 WARN(!cpu_base, "unable to map gic cpu registers\n");
1068
Marc Zyngierdb0d4db2011-11-12 16:09:49 +00001069 if (of_property_read_u32(node, "cpu-offset", &percpu_offset))
1070 percpu_offset = 0;
1071
Steve Mucklef132c6c2012-06-06 18:30:57 -07001072 domain->of_node = of_node_get(node);
1073
1074 gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset);
Rob Herringb3f7ed02011-09-28 21:27:52 -05001075
1076 if (parent) {
1077 irq = irq_of_parse_and_map(node, 0);
1078 gic_cascade_irq(gic_cnt, irq);
1079 }
1080 gic_cnt++;
1081 return 0;
1082}
1083#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001084/* before calling this function the interrupts should be disabled
1085 * and the irq must be disabled at gic to avoid spurious interrupts */
1086bool gic_is_spi_pending(unsigned int irq)
1087{
1088 struct irq_data *d = irq_get_irq_data(irq);
1089 struct gic_chip_data *gic_data = &gic_data[0];
1090 u32 mask, val;
1091
1092 WARN_ON(!irqs_disabled());
Thomas Gleixner450ea482009-07-03 08:44:46 -05001093 raw_spin_lock(&irq_controller_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001094 mask = 1 << (gic_irq(d) % 32);
1095 val = readl(gic_dist_base(d) +
1096 GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
1097 /* warn if the interrupt is enabled */
1098 WARN_ON(val & mask);
1099 val = readl(gic_dist_base(d) +
1100 GIC_DIST_PENDING_SET + (gic_irq(d) / 32) * 4);
Thomas Gleixner450ea482009-07-03 08:44:46 -05001101 raw_spin_unlock(&irq_controller_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001102 return (bool) (val & mask);
1103}
1104
1105/* before calling this function the interrupts should be disabled
1106 * and the irq must be disabled at gic to avoid spurious interrupts */
1107void gic_clear_spi_pending(unsigned int irq)
1108{
1109 struct gic_chip_data *gic_data = &gic_data[0];
1110 struct irq_data *d = irq_get_irq_data(irq);
1111
1112 u32 mask, val;
1113 WARN_ON(!irqs_disabled());
Thomas Gleixner450ea482009-07-03 08:44:46 -05001114 raw_spin_lock(&irq_controller_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001115 mask = 1 << (gic_irq(d) % 32);
1116 val = readl(gic_dist_base(d) +
1117 GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
1118 /* warn if the interrupt is enabled */
1119 WARN_ON(val & mask);
1120 writel(mask, gic_dist_base(d) +
1121 GIC_DIST_PENDING_CLEAR + (gic_irq(d) / 32) * 4);
Thomas Gleixner450ea482009-07-03 08:44:46 -05001122 raw_spin_unlock(&irq_controller_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001123}
Rob Herring0fc0d942011-09-28 21:27:52 -05001124
Taniya Dasbc9248a2012-04-30 19:59:11 +05301125#ifdef CONFIG_ARCH_MSM8625
1126 /*
1127 * Check for any interrupts which are enabled are pending
1128 * in the pending set or not.
1129 * Return :
1130 * 0 : No pending interrupts
1131 * 1 : Pending interrupts other than A9_M2A_5
1132 */
1133unsigned int msm_gic_spi_ppi_pending(void)
1134{
1135 unsigned int i, bit = 0;
1136 unsigned int pending_enb = 0, pending = 0;
1137 unsigned long value = 0;
1138 struct gic_chip_data *gic = &gic_data[0];
1139 void __iomem *base = gic_data_dist_base(gic);
Trilok Soni6278db02012-05-20 01:29:52 +05301140 unsigned long flags;
Taniya Dasbc9248a2012-04-30 19:59:11 +05301141
Trilok Soni6278db02012-05-20 01:29:52 +05301142 raw_spin_lock_irqsave(&irq_controller_lock, flags);
Taniya Dasbc9248a2012-04-30 19:59:11 +05301143 /*
1144 * PPI and SGI to be included.
1145 * MSM8625_INT_A9_M2A_5 needs to be ignored, as A9_M2A_5
1146 * requesting sleep triggers it
1147 */
1148 for (i = 0; (i * 32) < gic->max_irq; i++) {
1149 pending = readl_relaxed(base +
1150 GIC_DIST_PENDING_SET + i * 4);
1151 pending_enb = readl_relaxed(base +
1152 GIC_DIST_ENABLE_SET + i * 4);
1153 value = pending & pending_enb;
1154
1155 if (value) {
1156 for (bit = 0; bit < 32; bit++) {
1157 bit = find_next_bit(&value, 32, bit);
1158 if ((bit + 32 * i) != MSM8625_INT_A9_M2A_5) {
Trilok Soni6278db02012-05-20 01:29:52 +05301159 raw_spin_unlock_irqrestore(
1160 &irq_controller_lock, flags);
Taniya Dasbc9248a2012-04-30 19:59:11 +05301161 return 1;
1162 }
1163 }
1164 }
1165 }
Trilok Soni6278db02012-05-20 01:29:52 +05301166 raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
Taniya Dasbc9248a2012-04-30 19:59:11 +05301167
1168 return 0;
1169}
1170
1171void msm_gic_save(bool modem_wake, int from_idle)
1172{
1173 unsigned int i;
1174 struct gic_chip_data *gic = &gic_data[0];
1175 void __iomem *base = gic_data_dist_base(gic);
1176
1177 gic_cpu_save(0);
1178 gic_dist_save(0);
Taniya Das8862d7d2012-05-21 20:11:37 +05301179
1180 /* Disable all the Interrupts, before we enter pc */
1181 for (i = 0; (i * 32) < gic->max_irq; i++) {
1182 raw_spin_lock(&irq_controller_lock);
1183 writel_relaxed(0xffffffff, base
1184 + GIC_DIST_ENABLE_CLEAR + i * 4);
1185 raw_spin_unlock(&irq_controller_lock);
Taniya Dasbc9248a2012-04-30 19:59:11 +05301186 }
1187}
1188
1189void msm_gic_restore(void)
1190{
1191 gic_dist_restore(0);
1192 gic_cpu_restore(0);
1193}
1194
1195/*
1196 * Configure the GIC after we come out of power collapse.
1197 * This function will configure some of the GIC registers so as to prepare the
1198 * core1 to receive an SPI(ACSR_MP_CORE_IPC1, (32 + 8)), which will bring
1199 * core1 out of GDFS.
1200 */
1201void core1_gic_configure_and_raise(void)
1202{
1203 struct gic_chip_data *gic = &gic_data[0];
1204 void __iomem *base = gic_data_dist_base(gic);
1205 unsigned int value = 0;
Trilok Soni6278db02012-05-20 01:29:52 +05301206 unsigned long flags;
Taniya Dasbc9248a2012-04-30 19:59:11 +05301207
Trilok Soni6278db02012-05-20 01:29:52 +05301208 raw_spin_lock_irqsave(&irq_controller_lock, flags);
Taniya Dasbc9248a2012-04-30 19:59:11 +05301209
1210 value = __raw_readl(base + GIC_DIST_ACTIVE_BIT + 0x4);
1211 value |= BIT(8);
1212 __raw_writel(value, base + GIC_DIST_ACTIVE_BIT + 0x4);
1213 mb();
1214
1215 value = __raw_readl(base + GIC_DIST_TARGET + 0x24);
1216 value |= BIT(13);
1217 __raw_writel(value, base + GIC_DIST_TARGET + 0x24);
1218 mb();
1219
1220 value = __raw_readl(base + GIC_DIST_TARGET + 0x28);
1221 value |= BIT(1);
1222 __raw_writel(value, base + GIC_DIST_TARGET + 0x28);
1223 mb();
1224
1225 value = __raw_readl(base + GIC_DIST_ENABLE_SET + 0x4);
1226 value |= BIT(8);
1227 __raw_writel(value, base + GIC_DIST_ENABLE_SET + 0x4);
1228 mb();
1229
1230 value = __raw_readl(base + GIC_DIST_PENDING_SET + 0x4);
1231 value |= BIT(8);
1232 __raw_writel(value, base + GIC_DIST_PENDING_SET + 0x4);
1233 mb();
Trilok Soni6278db02012-05-20 01:29:52 +05301234 raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
Taniya Dasbc9248a2012-04-30 19:59:11 +05301235}
1236#endif