aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2014-06-30 11:01:30 -0400
committerJason Cooper <jason@lakedaemon.net>2014-07-08 17:49:14 -0400
commitd51d0af43b30dcae1ca13ea67fd717e03b37f153 (patch)
tree3c5b91f4ee3428130fe7276daf2a606f44182292
parent7171511eaec5bf23fb06078f59784a3a0626b38f (diff)
irqchip: gic: Move some bits of GICv2 to a library-type file
A few GICv2 low-level function are actually very useful to GICv3, and it makes some sense to share them across the two drivers. They end-up in their own file, with an additional parameter used to ensure an optional synchronization (unused on GICv2). Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Jason Cooper <jason@lakedaemon.net> Acked-by: Christoffer Dall <christoffer.dall@linaro.org> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> Link: https://lkml.kernel.org/r/1404140510-5382-2-git-send-email-marc.zyngier@arm.com Signed-off-by: Jason Cooper <jason@lakedaemon.net>
-rw-r--r--drivers/irqchip/Makefile2
-rw-r--r--drivers/irqchip/irq-gic-common.c115
-rw-r--r--drivers/irqchip/irq-gic-common.h29
-rw-r--r--drivers/irqchip/irq-gic.c59
4 files changed, 149 insertions, 56 deletions
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 62a13e5ef98f..9b9505c8e774 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -15,7 +15,7 @@ obj-$(CONFIG_ORION_IRQCHIP) += irq-orion.o
15obj-$(CONFIG_ARCH_SUNXI) += irq-sun4i.o 15obj-$(CONFIG_ARCH_SUNXI) += irq-sun4i.o
16obj-$(CONFIG_ARCH_SUNXI) += irq-sunxi-nmi.o 16obj-$(CONFIG_ARCH_SUNXI) += irq-sunxi-nmi.o
17obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o 17obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o
18obj-$(CONFIG_ARM_GIC) += irq-gic.o 18obj-$(CONFIG_ARM_GIC) += irq-gic.o irq-gic-common.o
19obj-$(CONFIG_ARM_NVIC) += irq-nvic.o 19obj-$(CONFIG_ARM_NVIC) += irq-nvic.o
20obj-$(CONFIG_ARM_VIC) += irq-vic.o 20obj-$(CONFIG_ARM_VIC) += irq-vic.o
21obj-$(CONFIG_IMGPDC_IRQ) += irq-imgpdc.o 21obj-$(CONFIG_IMGPDC_IRQ) += irq-imgpdc.o
diff --git a/drivers/irqchip/irq-gic-common.c b/drivers/irqchip/irq-gic-common.c
new file mode 100644
index 000000000000..60ac704d2090
--- /dev/null
+++ b/drivers/irqchip/irq-gic-common.c
@@ -0,0 +1,115 @@
1/*
2 * Copyright (C) 2002 ARM Limited, All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include <linux/interrupt.h>
18#include <linux/io.h>
19#include <linux/irq.h>
20#include <linux/irqchip/arm-gic.h>
21
22#include "irq-gic-common.h"
23
24void gic_configure_irq(unsigned int irq, unsigned int type,
25 void __iomem *base, void (*sync_access)(void))
26{
27 u32 enablemask = 1 << (irq % 32);
28 u32 enableoff = (irq / 32) * 4;
29 u32 confmask = 0x2 << ((irq % 16) * 2);
30 u32 confoff = (irq / 16) * 4;
31 bool enabled = false;
32 u32 val;
33
34 /*
35 * Read current configuration register, and insert the config
36 * for "irq", depending on "type".
37 */
38 val = readl_relaxed(base + GIC_DIST_CONFIG + confoff);
39 if (type == IRQ_TYPE_LEVEL_HIGH)
40 val &= ~confmask;
41 else if (type == IRQ_TYPE_EDGE_RISING)
42 val |= confmask;
43
44 /*
45 * As recommended by the spec, disable the interrupt before changing
46 * the configuration
47 */
48 if (readl_relaxed(base + GIC_DIST_ENABLE_SET + enableoff) & enablemask) {
49 writel_relaxed(enablemask, base + GIC_DIST_ENABLE_CLEAR + enableoff);
50 if (sync_access)
51 sync_access();
52 enabled = true;
53 }
54
55 /*
56 * Write back the new configuration, and possibly re-enable
57 * the interrupt.
58 */
59 writel_relaxed(val, base + GIC_DIST_CONFIG + confoff);
60
61 if (enabled)
62 writel_relaxed(enablemask, base + GIC_DIST_ENABLE_SET + enableoff);
63
64 if (sync_access)
65 sync_access();
66}
67
68void __init gic_dist_config(void __iomem *base, int gic_irqs,
69 void (*sync_access)(void))
70{
71 unsigned int i;
72
73 /*
74 * Set all global interrupts to be level triggered, active low.
75 */
76 for (i = 32; i < gic_irqs; i += 16)
77 writel_relaxed(0, base + GIC_DIST_CONFIG + i / 4);
78
79 /*
80 * Set priority on all global interrupts.
81 */
82 for (i = 32; i < gic_irqs; i += 4)
83 writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i);
84
85 /*
86 * Disable all interrupts. Leave the PPI and SGIs alone
87 * as they are enabled by redistributor registers.
88 */
89 for (i = 32; i < gic_irqs; i += 32)
90 writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i / 8);
91
92 if (sync_access)
93 sync_access();
94}
95
96void gic_cpu_config(void __iomem *base, void (*sync_access)(void))
97{
98 int i;
99
100 /*
101 * Deal with the banked PPI and SGI interrupts - disable all
102 * PPI interrupts, ensure all SGI interrupts are enabled.
103 */
104 writel_relaxed(0xffff0000, base + GIC_DIST_ENABLE_CLEAR);
105 writel_relaxed(0x0000ffff, base + GIC_DIST_ENABLE_SET);
106
107 /*
108 * Set priority on PPI and SGI interrupts
109 */
110 for (i = 0; i < 32; i += 4)
111 writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
112
113 if (sync_access)
114 sync_access();
115}
diff --git a/drivers/irqchip/irq-gic-common.h b/drivers/irqchip/irq-gic-common.h
new file mode 100644
index 000000000000..b41f02481c3a
--- /dev/null
+++ b/drivers/irqchip/irq-gic-common.h
@@ -0,0 +1,29 @@
1/*
2 * Copyright (C) 2002 ARM Limited, All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef _IRQ_GIC_COMMON_H
18#define _IRQ_GIC_COMMON_H
19
20#include <linux/of.h>
21#include <linux/irqdomain.h>
22
23void gic_configure_irq(unsigned int irq, unsigned int type,
24 void __iomem *base, void (*sync_access)(void));
25void gic_dist_config(void __iomem *base, int gic_irqs,
26 void (*sync_access)(void));
27void gic_cpu_config(void __iomem *base, void (*sync_access)(void));
28
29#endif /* _IRQ_GIC_COMMON_H */
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 7e11c9d6ae8c..508b81536b8a 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -46,6 +46,7 @@
46#include <asm/exception.h> 46#include <asm/exception.h>
47#include <asm/smp_plat.h> 47#include <asm/smp_plat.h>
48 48
49#include "irq-gic-common.h"
49#include "irqchip.h" 50#include "irqchip.h"
50 51
51union gic_base { 52union gic_base {
@@ -188,12 +189,6 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
188{ 189{
189 void __iomem *base = gic_dist_base(d); 190 void __iomem *base = gic_dist_base(d);
190 unsigned int gicirq = gic_irq(d); 191 unsigned int gicirq = gic_irq(d);
191 u32 enablemask = 1 << (gicirq % 32);
192 u32 enableoff = (gicirq / 32) * 4;
193 u32 confmask = 0x2 << ((gicirq % 16) * 2);
194 u32 confoff = (gicirq / 16) * 4;
195 bool enabled = false;
196 u32 val;
197 192
198 /* Interrupt configuration for SGIs can't be changed */ 193 /* Interrupt configuration for SGIs can't be changed */
199 if (gicirq < 16) 194 if (gicirq < 16)
@@ -207,25 +202,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
207 if (gic_arch_extn.irq_set_type) 202 if (gic_arch_extn.irq_set_type)
208 gic_arch_extn.irq_set_type(d, type); 203 gic_arch_extn.irq_set_type(d, type);
209 204
210 val = readl_relaxed(base + GIC_DIST_CONFIG + confoff); 205 gic_configure_irq(gicirq, type, base, NULL);
211 if (type == IRQ_TYPE_LEVEL_HIGH)
212 val &= ~confmask;
213 else if (type == IRQ_TYPE_EDGE_RISING)
214 val |= confmask;
215
216 /*
217 * As recommended by the spec, disable the interrupt before changing
218 * the configuration
219 */
220 if (readl_relaxed(base + GIC_DIST_ENABLE_SET + enableoff) & enablemask) {
221 writel_relaxed(enablemask, base + GIC_DIST_ENABLE_CLEAR + enableoff);
222 enabled = true;
223 }
224
225 writel_relaxed(val, base + GIC_DIST_CONFIG + confoff);
226
227 if (enabled)
228 writel_relaxed(enablemask, base + GIC_DIST_ENABLE_SET + enableoff);
229 206
230 raw_spin_unlock(&irq_controller_lock); 207 raw_spin_unlock(&irq_controller_lock);
231 208
@@ -387,12 +364,6 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
387 writel_relaxed(0, base + GIC_DIST_CTRL); 364 writel_relaxed(0, base + GIC_DIST_CTRL);
388 365
389 /* 366 /*
390 * Set all global interrupts to be level triggered, active low.
391 */
392 for (i = 32; i < gic_irqs; i += 16)
393 writel_relaxed(0, base + GIC_DIST_CONFIG + i * 4 / 16);
394
395 /*
396 * Set all global interrupts to this CPU only. 367 * Set all global interrupts to this CPU only.
397 */ 368 */
398 cpumask = gic_get_cpumask(gic); 369 cpumask = gic_get_cpumask(gic);
@@ -401,18 +372,7 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
401 for (i = 32; i < gic_irqs; i += 4) 372 for (i = 32; i < gic_irqs; i += 4)
402 writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4 / 4); 373 writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4 / 4);
403 374
404 /* 375 gic_dist_config(base, gic_irqs, NULL);
405 * Set priority on all global interrupts.
406 */
407 for (i = 32; i < gic_irqs; i += 4)
408 writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
409
410 /*
411 * Disable all interrupts. Leave the PPI and SGIs alone
412 * as these enables are banked registers.
413 */
414 for (i = 32; i < gic_irqs; i += 32)
415 writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
416 376
417 writel_relaxed(1, base + GIC_DIST_CTRL); 377 writel_relaxed(1, base + GIC_DIST_CTRL);
418} 378}
@@ -439,18 +399,7 @@ static void gic_cpu_init(struct gic_chip_data *gic)
439 if (i != cpu) 399 if (i != cpu)
440 gic_cpu_map[i] &= ~cpu_mask; 400 gic_cpu_map[i] &= ~cpu_mask;
441 401
442 /* 402 gic_cpu_config(dist_base, NULL);
443 * Deal with the banked PPI and SGI interrupts - disable all
444 * PPI interrupts, ensure all SGI interrupts are enabled.
445 */
446 writel_relaxed(0xffff0000, dist_base + GIC_DIST_ENABLE_CLEAR);
447 writel_relaxed(0x0000ffff, dist_base + GIC_DIST_ENABLE_SET);
448
449 /*
450 * Set priority on PPI and SGI interrupts
451 */
452 for (i = 0; i < 32; i += 4)
453 writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
454 403
455 writel_relaxed(0xf0, base + GIC_CPU_PRIMASK); 404 writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
456 writel_relaxed(1, base + GIC_CPU_CTRL); 405 writel_relaxed(1, base + GIC_CPU_CTRL);