aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2016-09-22 16:49:52 -0400
committerThomas Gleixner <tglx@linutronix.de>2016-09-22 16:49:52 -0400
commit474aa3dd3e1f3ae410115fe6624ba48fc9791bc5 (patch)
treefcc7de41f698eb7eb018e992d60494bb60833a24
parent5a79d596378b65e773d93d00edcb57a33f87ea94 (diff)
parentf61f86068cdf7e59de64d430fd3cc907a8e102f2 (diff)
Merge tag 'irqchip-core-4.9' of git://git.infradead.org/users/jcooper/linux into irq/core
Pull irqchip core changes for v4.9 from Jason Cooper - jcore: Add AIC driver - mips-gic: Use for_each_set_bit - mvebu: Add PIC driver
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/jcore,aic.txt26
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/marvell,armada-8k-pic.txt25
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/marvell,odmi-controller.txt2
-rw-r--r--arch/arm64/Kconfig.platforms1
-rw-r--r--drivers/irqchip/Kconfig10
-rw-r--r--drivers/irqchip/Makefile2
-rw-r--r--drivers/irqchip/irq-jcore-aic.c95
-rw-r--r--drivers/irqchip/irq-keystone.c2
-rw-r--r--drivers/irqchip/irq-mips-gic.c7
-rw-r--r--drivers/irqchip/irq-mvebu-pic.c197
10 files changed, 359 insertions, 8 deletions
diff --git a/Documentation/devicetree/bindings/interrupt-controller/jcore,aic.txt b/Documentation/devicetree/bindings/interrupt-controller/jcore,aic.txt
new file mode 100644
index 000000000000..ee2ad36f8df8
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/jcore,aic.txt
@@ -0,0 +1,26 @@
1J-Core Advanced Interrupt Controller
2
3Required properties:
4
5- compatible: Should be "jcore,aic1" for the (obsolete) first-generation aic
6 with 8 interrupt lines with programmable priorities, or "jcore,aic2" for
7 the "aic2" core with 64 interrupts.
8
9- reg: Memory region(s) for configuration. For SMP, there should be one
10 region per cpu, indexed by the sequential, zero-based hardware cpu
11 number.
12
13- interrupt-controller: Identifies the node as an interrupt controller
14
15- #interrupt-cells: Specifies the number of cells needed to encode an
16 interrupt source. The value shall be 1.
17
18
19Example:
20
21aic: interrupt-controller@200 {
22 compatible = "jcore,aic2";
23 reg = < 0x200 0x30 0x500 0x30 >;
24 interrupt-controller;
25 #interrupt-cells = <1>;
26};
diff --git a/Documentation/devicetree/bindings/interrupt-controller/marvell,armada-8k-pic.txt b/Documentation/devicetree/bindings/interrupt-controller/marvell,armada-8k-pic.txt
new file mode 100644
index 000000000000..86a7b4cd03f5
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/marvell,armada-8k-pic.txt
@@ -0,0 +1,25 @@
1Marvell Armada 7K/8K PIC Interrupt controller
2---------------------------------------------
3
4This is the Device Tree binding for the PIC, a secondary interrupt
5controller available on the Marvell Armada 7K/8K ARM64 SoCs, and
6typically connected to the GIC as the primary interrupt controller.
7
8Required properties:
9- compatible: should be "marvell,armada-8k-pic"
10- interrupt-controller: identifies the node as an interrupt controller
11- #interrupt-cells: the number of cells to define interrupts on this
12 controller. Should be 1
13- reg: the register area for the PIC interrupt controller
14- interrupts: the interrupt to the primary interrupt controller,
15 typically the GIC
16
17Example:
18
19 pic: interrupt-controller@3f0100 {
20 compatible = "marvell,armada-8k-pic";
21 reg = <0x3f0100 0x10>;
22 #interrupt-cells = <1>;
23 interrupt-controller;
24 interrupts = <GIC_PPI 15 IRQ_TYPE_LEVEL_HIGH>;
25 };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/marvell,odmi-controller.txt b/Documentation/devicetree/bindings/interrupt-controller/marvell,odmi-controller.txt
index 8af0a8e613ab..3f6442c7f867 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/marvell,odmi-controller.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/marvell,odmi-controller.txt
@@ -31,7 +31,7 @@ Required properties:
31Example: 31Example:
32 32
33 odmi: odmi@300000 { 33 odmi: odmi@300000 {
34 compatible = "marvell,ap806-odm-controller", 34 compatible = "marvell,ap806-odmi-controller",
35 "marvell,odmi-controller"; 35 "marvell,odmi-controller";
36 interrupt-controller; 36 interrupt-controller;
37 msi-controller; 37 msi-controller;
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index be5d824ebdba..169c40a51cef 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -93,6 +93,7 @@ config ARCH_MVEBU
93 select ARMADA_CP110_SYSCON 93 select ARMADA_CP110_SYSCON
94 select ARMADA_37XX_CLK 94 select ARMADA_37XX_CLK
95 select MVEBU_ODMI 95 select MVEBU_ODMI
96 select MVEBU_PIC
96 help 97 help
97 This enables support for Marvell EBU familly, including: 98 This enables support for Marvell EBU familly, including:
98 - Armada 3700 SoC Family 99 - Armada 3700 SoC Family
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 329c941e46b5..82b0b5daf3f5 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -157,6 +157,13 @@ config PIC32_EVIC
157 select GENERIC_IRQ_CHIP 157 select GENERIC_IRQ_CHIP
158 select IRQ_DOMAIN 158 select IRQ_DOMAIN
159 159
160config JCORE_AIC
161 bool "J-Core integrated AIC"
162 depends on OF && (SUPERH || COMPILE_TEST)
163 select IRQ_DOMAIN
164 help
165 Support for the J-Core integrated AIC.
166
160config RENESAS_INTC_IRQPIN 167config RENESAS_INTC_IRQPIN
161 bool 168 bool
162 select IRQ_DOMAIN 169 select IRQ_DOMAIN
@@ -252,6 +259,9 @@ config IRQ_MXS
252config MVEBU_ODMI 259config MVEBU_ODMI
253 bool 260 bool
254 261
262config MVEBU_PIC
263 bool
264
255config LS_SCFG_MSI 265config LS_SCFG_MSI
256 def_bool y if SOC_LS1021A || ARCH_LAYERSCAPE 266 def_bool y if SOC_LS1021A || ARCH_LAYERSCAPE
257 depends on PCI && PCI_MSI 267 depends on PCI && PCI_MSI
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 96383b22cffe..b372e792adc2 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_I8259) += irq-i8259.o
40obj-$(CONFIG_IMGPDC_IRQ) += irq-imgpdc.o 40obj-$(CONFIG_IMGPDC_IRQ) += irq-imgpdc.o
41obj-$(CONFIG_IRQ_MIPS_CPU) += irq-mips-cpu.o 41obj-$(CONFIG_IRQ_MIPS_CPU) += irq-mips-cpu.o
42obj-$(CONFIG_SIRF_IRQ) += irq-sirfsoc.o 42obj-$(CONFIG_SIRF_IRQ) += irq-sirfsoc.o
43obj-$(CONFIG_JCORE_AIC) += irq-jcore-aic.o
43obj-$(CONFIG_RENESAS_INTC_IRQPIN) += irq-renesas-intc-irqpin.o 44obj-$(CONFIG_RENESAS_INTC_IRQPIN) += irq-renesas-intc-irqpin.o
44obj-$(CONFIG_RENESAS_IRQC) += irq-renesas-irqc.o 45obj-$(CONFIG_RENESAS_IRQC) += irq-renesas-irqc.o
45obj-$(CONFIG_VERSATILE_FPGA_IRQ) += irq-versatile-fpga.o 46obj-$(CONFIG_VERSATILE_FPGA_IRQ) += irq-versatile-fpga.o
@@ -68,6 +69,7 @@ obj-$(CONFIG_INGENIC_IRQ) += irq-ingenic.o
68obj-$(CONFIG_IMX_GPCV2) += irq-imx-gpcv2.o 69obj-$(CONFIG_IMX_GPCV2) += irq-imx-gpcv2.o
69obj-$(CONFIG_PIC32_EVIC) += irq-pic32-evic.o 70obj-$(CONFIG_PIC32_EVIC) += irq-pic32-evic.o
70obj-$(CONFIG_MVEBU_ODMI) += irq-mvebu-odmi.o 71obj-$(CONFIG_MVEBU_ODMI) += irq-mvebu-odmi.o
72obj-$(CONFIG_MVEBU_PIC) += irq-mvebu-pic.o
71obj-$(CONFIG_LS_SCFG_MSI) += irq-ls-scfg-msi.o 73obj-$(CONFIG_LS_SCFG_MSI) += irq-ls-scfg-msi.o
72obj-$(CONFIG_EZNPS_GIC) += irq-eznps.o 74obj-$(CONFIG_EZNPS_GIC) += irq-eznps.o
73obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o 75obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o
diff --git a/drivers/irqchip/irq-jcore-aic.c b/drivers/irqchip/irq-jcore-aic.c
new file mode 100644
index 000000000000..84b01dec277d
--- /dev/null
+++ b/drivers/irqchip/irq-jcore-aic.c
@@ -0,0 +1,95 @@
1/*
2 * J-Core SoC AIC driver
3 *
4 * Copyright (C) 2015-2016 Smart Energy Instruments, Inc.
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10
11#include <linux/irq.h>
12#include <linux/io.h>
13#include <linux/irqchip.h>
14#include <linux/irqdomain.h>
15#include <linux/cpu.h>
16#include <linux/of.h>
17#include <linux/of_address.h>
18#include <linux/of_irq.h>
19
20#define JCORE_AIC_MAX_HWIRQ 127
21#define JCORE_AIC1_MIN_HWIRQ 16
22#define JCORE_AIC2_MIN_HWIRQ 64
23
24#define JCORE_AIC1_INTPRI_REG 8
25
26static struct irq_chip jcore_aic;
27
28static int jcore_aic_irqdomain_map(struct irq_domain *d, unsigned int irq,
29 irq_hw_number_t hwirq)
30{
31 struct irq_chip *aic = d->host_data;
32
33 irq_set_chip_and_handler(irq, aic, handle_simple_irq);
34
35 return 0;
36}
37
38static const struct irq_domain_ops jcore_aic_irqdomain_ops = {
39 .map = jcore_aic_irqdomain_map,
40 .xlate = irq_domain_xlate_onecell,
41};
42
43static void noop(struct irq_data *data)
44{
45}
46
47static int __init aic_irq_of_init(struct device_node *node,
48 struct device_node *parent)
49{
50 unsigned min_irq = JCORE_AIC2_MIN_HWIRQ;
51 unsigned dom_sz = JCORE_AIC_MAX_HWIRQ+1;
52 struct irq_domain *domain;
53
54 pr_info("Initializing J-Core AIC\n");
55
56 /* AIC1 needs priority initialization to receive interrupts. */
57 if (of_device_is_compatible(node, "jcore,aic1")) {
58 unsigned cpu;
59
60 for_each_present_cpu(cpu) {
61 void __iomem *base = of_iomap(node, cpu);
62
63 if (!base) {
64 pr_err("Unable to map AIC for cpu %u\n", cpu);
65 return -ENOMEM;
66 }
67 __raw_writel(0xffffffff, base + JCORE_AIC1_INTPRI_REG);
68 iounmap(base);
69 }
70 min_irq = JCORE_AIC1_MIN_HWIRQ;
71 }
72
73 /*
74 * The irq chip framework requires either mask/unmask or enable/disable
75 * function pointers to be provided, but the hardware does not have any
76 * such mechanism; the only interrupt masking is at the cpu level and
77 * it affects all interrupts. We provide dummy mask/unmask. The hardware
78 * handles all interrupt control and clears pending status when the cpu
79 * accepts the interrupt.
80 */
81 jcore_aic.irq_mask = noop;
82 jcore_aic.irq_unmask = noop;
83 jcore_aic.name = "AIC";
84
85 domain = irq_domain_add_linear(node, dom_sz, &jcore_aic_irqdomain_ops,
86 &jcore_aic);
87 if (!domain)
88 return -ENOMEM;
89 irq_create_strict_mappings(domain, min_irq, min_irq, dom_sz - min_irq);
90
91 return 0;
92}
93
94IRQCHIP_DECLARE(jcore_aic2, "jcore,aic2", aic_irq_of_init);
95IRQCHIP_DECLARE(jcore_aic1, "jcore,aic1", aic_irq_of_init);
diff --git a/drivers/irqchip/irq-keystone.c b/drivers/irqchip/irq-keystone.c
index deb89d63a728..54a5e870a8f5 100644
--- a/drivers/irqchip/irq-keystone.c
+++ b/drivers/irqchip/irq-keystone.c
@@ -109,7 +109,7 @@ static void keystone_irq_handler(struct irq_desc *desc)
109 dev_dbg(kirq->dev, "dispatch bit %d, virq %d\n", 109 dev_dbg(kirq->dev, "dispatch bit %d, virq %d\n",
110 src, virq); 110 src, virq);
111 if (!virq) 111 if (!virq)
112 dev_warn(kirq->dev, "sporious irq detected hwirq %d, virq %d\n", 112 dev_warn(kirq->dev, "spurious irq detected hwirq %d, virq %d\n",
113 src, virq); 113 src, virq);
114 generic_handle_irq(virq); 114 generic_handle_irq(virq);
115 } 115 }
diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c
index 8f7d38ba24c6..c0178a122940 100644
--- a/drivers/irqchip/irq-mips-gic.c
+++ b/drivers/irqchip/irq-mips-gic.c
@@ -371,18 +371,13 @@ static void gic_handle_shared_int(bool chained)
371 bitmap_and(pending, pending, intrmask, gic_shared_intrs); 371 bitmap_and(pending, pending, intrmask, gic_shared_intrs);
372 bitmap_and(pending, pending, pcpu_mask, gic_shared_intrs); 372 bitmap_and(pending, pending, pcpu_mask, gic_shared_intrs);
373 373
374 intr = find_first_bit(pending, gic_shared_intrs); 374 for_each_set_bit(intr, pending, gic_shared_intrs) {
375 while (intr != gic_shared_intrs) {
376 virq = irq_linear_revmap(gic_irq_domain, 375 virq = irq_linear_revmap(gic_irq_domain,
377 GIC_SHARED_TO_HWIRQ(intr)); 376 GIC_SHARED_TO_HWIRQ(intr));
378 if (chained) 377 if (chained)
379 generic_handle_irq(virq); 378 generic_handle_irq(virq);
380 else 379 else
381 do_IRQ(virq); 380 do_IRQ(virq);
382
383 /* go to next pending bit */
384 bitmap_clear(pending, intr, 1);
385 intr = find_first_bit(pending, gic_shared_intrs);
386 } 381 }
387} 382}
388 383
diff --git a/drivers/irqchip/irq-mvebu-pic.c b/drivers/irqchip/irq-mvebu-pic.c
new file mode 100644
index 000000000000..eec63951129a
--- /dev/null
+++ b/drivers/irqchip/irq-mvebu-pic.c
@@ -0,0 +1,197 @@
1/*
2 * Copyright (C) 2016 Marvell
3 *
4 * Yehuda Yitschak <yehuday@marvell.com>
5 * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
6 *
7 * This file is licensed under the terms of the GNU General Public
8 * License version 2. This program is licensed "as is" without any
9 * warranty of any kind, whether express or implied.
10 */
11
12#include <linux/interrupt.h>
13#include <linux/io.h>
14#include <linux/irq.h>
15#include <linux/irqchip.h>
16#include <linux/irqchip/chained_irq.h>
17#include <linux/irqdomain.h>
18#include <linux/module.h>
19#include <linux/of_irq.h>
20#include <linux/platform_device.h>
21
22#define PIC_CAUSE 0x0
23#define PIC_MASK 0x4
24
25#define PIC_MAX_IRQS 32
26#define PIC_MAX_IRQ_MASK ((1UL << PIC_MAX_IRQS) - 1)
27
28struct mvebu_pic {
29 void __iomem *base;
30 u32 parent_irq;
31 struct irq_domain *domain;
32 struct irq_chip irq_chip;
33};
34
35static void mvebu_pic_reset(struct mvebu_pic *pic)
36{
37 /* ACK and mask all interrupts */
38 writel(0, pic->base + PIC_MASK);
39 writel(PIC_MAX_IRQ_MASK, pic->base + PIC_CAUSE);
40}
41
42static void mvebu_pic_eoi_irq(struct irq_data *d)
43{
44 struct mvebu_pic *pic = irq_data_get_irq_chip_data(d);
45
46 writel(1 << d->hwirq, pic->base + PIC_CAUSE);
47}
48
49static void mvebu_pic_mask_irq(struct irq_data *d)
50{
51 struct mvebu_pic *pic = irq_data_get_irq_chip_data(d);
52 u32 reg;
53
54 reg = readl(pic->base + PIC_MASK);
55 reg |= (1 << d->hwirq);
56 writel(reg, pic->base + PIC_MASK);
57}
58
59static void mvebu_pic_unmask_irq(struct irq_data *d)
60{
61 struct mvebu_pic *pic = irq_data_get_irq_chip_data(d);
62 u32 reg;
63
64 reg = readl(pic->base + PIC_MASK);
65 reg &= ~(1 << d->hwirq);
66 writel(reg, pic->base + PIC_MASK);
67}
68
69static int mvebu_pic_irq_map(struct irq_domain *domain, unsigned int virq,
70 irq_hw_number_t hwirq)
71{
72 struct mvebu_pic *pic = domain->host_data;
73
74 irq_set_percpu_devid(virq);
75 irq_set_chip_data(virq, pic);
76 irq_set_chip_and_handler(virq, &pic->irq_chip,
77 handle_percpu_devid_irq);
78 irq_set_status_flags(virq, IRQ_LEVEL);
79 irq_set_probe(virq);
80
81 return 0;
82}
83
84static const struct irq_domain_ops mvebu_pic_domain_ops = {
85 .map = mvebu_pic_irq_map,
86 .xlate = irq_domain_xlate_onecell,
87};
88
89static void mvebu_pic_handle_cascade_irq(struct irq_desc *desc)
90{
91 struct mvebu_pic *pic = irq_desc_get_handler_data(desc);
92 struct irq_chip *chip = irq_desc_get_chip(desc);
93 unsigned long irqmap, irqn;
94 unsigned int cascade_irq;
95
96 irqmap = readl_relaxed(pic->base + PIC_CAUSE);
97 chained_irq_enter(chip, desc);
98
99 for_each_set_bit(irqn, &irqmap, BITS_PER_LONG) {
100 cascade_irq = irq_find_mapping(pic->domain, irqn);
101 generic_handle_irq(cascade_irq);
102 }
103
104 chained_irq_exit(chip, desc);
105}
106
107static void mvebu_pic_enable_percpu_irq(void *data)
108{
109 struct mvebu_pic *pic = data;
110
111 mvebu_pic_reset(pic);
112 enable_percpu_irq(pic->parent_irq, IRQ_TYPE_NONE);
113}
114
115static void mvebu_pic_disable_percpu_irq(void *data)
116{
117 struct mvebu_pic *pic = data;
118
119 disable_percpu_irq(pic->parent_irq);
120}
121
122static int mvebu_pic_probe(struct platform_device *pdev)
123{
124 struct device_node *node = pdev->dev.of_node;
125 struct mvebu_pic *pic;
126 struct irq_chip *irq_chip;
127 struct resource *res;
128
129 pic = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_pic), GFP_KERNEL);
130 if (!pic)
131 return -ENOMEM;
132
133 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
134 pic->base = devm_ioremap_resource(&pdev->dev, res);
135 if (IS_ERR(pic->base))
136 return PTR_ERR(pic->base);
137
138 irq_chip = &pic->irq_chip;
139 irq_chip->name = dev_name(&pdev->dev);
140 irq_chip->irq_mask = mvebu_pic_mask_irq;
141 irq_chip->irq_unmask = mvebu_pic_unmask_irq;
142 irq_chip->irq_eoi = mvebu_pic_eoi_irq;
143
144 pic->parent_irq = irq_of_parse_and_map(node, 0);
145 if (pic->parent_irq <= 0) {
146 dev_err(&pdev->dev, "Failed to parse parent interrupt\n");
147 return -EINVAL;
148 }
149
150 pic->domain = irq_domain_add_linear(node, PIC_MAX_IRQS,
151 &mvebu_pic_domain_ops, pic);
152 if (!pic->domain) {
153 dev_err(&pdev->dev, "Failed to allocate irq domain\n");
154 return -ENOMEM;
155 }
156
157 irq_set_chained_handler(pic->parent_irq, mvebu_pic_handle_cascade_irq);
158 irq_set_handler_data(pic->parent_irq, pic);
159
160 on_each_cpu(mvebu_pic_enable_percpu_irq, pic, 1);
161
162 platform_set_drvdata(pdev, pic);
163
164 return 0;
165}
166
167static int mvebu_pic_remove(struct platform_device *pdev)
168{
169 struct mvebu_pic *pic = platform_get_drvdata(pdev);
170
171 on_each_cpu(mvebu_pic_disable_percpu_irq, pic, 1);
172 irq_domain_remove(pic->domain);
173
174 return 0;
175}
176
177static const struct of_device_id mvebu_pic_of_match[] = {
178 { .compatible = "marvell,armada-8k-pic", },
179 {},
180};
181MODULE_DEVICE_TABLE(of, mvebu_pic_of_match);
182
183static struct platform_driver mvebu_pic_driver = {
184 .probe = mvebu_pic_probe,
185 .remove = mvebu_pic_remove,
186 .driver = {
187 .name = "mvebu-pic",
188 .of_match_table = mvebu_pic_of_match,
189 },
190};
191module_platform_driver(mvebu_pic_driver);
192
193MODULE_AUTHOR("Yehuda Yitschak <yehuday@marvell.com>");
194MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>");
195MODULE_LICENSE("GPL v2");
196MODULE_ALIAS("platform:mvebu_pic");
197