summaryrefslogtreecommitdiffstats
path: root/drivers/irqchip
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-07-08 14:01:13 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2019-07-08 14:01:13 -0400
commit2a1ccd31420a7b1acd6ca37b2bec2d723aa093e4 (patch)
tree43946f0c4afc7dce86fc055df48d661f8ed3999c /drivers/irqchip
parente0e86b111bca6bbf746c03ec5cf3e6a61fa3f8e9 (diff)
parent3a1d24ca9573fbc74a3d32c972c333b161e0e9dc (diff)
Merge branch 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull irq updates from Thomas Gleixner: "The irq departement provides the usual mixed bag: Core: - Further improvements to the irq timings code which aims to predict the next interrupt for power state selection to achieve better latency/power balance - Add interrupt statistics to the core NMI handlers - The usual small fixes and cleanups Drivers: - Support for Renesas RZ/A1, Annapurna Labs FIC, Meson-G12A SoC and Amazon Gravition AMR/GIC interrupt controllers. - Rework of the Renesas INTC controller driver - ACPI support for Socionext SoCs - Enhancements to the CSKY interrupt controller - The usual small fixes and cleanups" * 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (39 commits) irq/irqdomain: Fix comment typo genirq: Update irq stats from NMI handlers irqchip/gic-pm: Remove PM_CLK dependency irqchip/al-fic: Introduce Amazon's Annapurna Labs Fabric Interrupt Controller Driver dt-bindings: interrupt-controller: Add Amazon's Annapurna Labs FIC softirq: Use __this_cpu_write() in takeover_tasklets() irqchip/mbigen: Stop printing kernel addresses irqchip/gic: Add dependency for ARM_GIC_MAX_NR genirq/affinity: Remove unused argument from [__]irq_build_affinity_masks() genirq/timings: Add selftest for next event computation genirq/timings: Add selftest for irqs circular buffer genirq/timings: Add selftest for circular array genirq/timings: Encapsulate storing function genirq/timings: Encapsulate timings push genirq/timings: Optimize the period detection speed genirq/timings: Fix timings buffer inspection genirq/timings: Fix next event index function irqchip/qcom: Use struct_size() in devm_kzalloc() irqchip/irq-csky-mpintc: Remove unnecessary loop in interrupt handler dt-bindings: interrupt-controller: Update csky mpintc ...
Diffstat (limited to 'drivers/irqchip')
-rw-r--r--drivers/irqchip/Kconfig32
-rw-r--r--drivers/irqchip/Makefile2
-rw-r--r--drivers/irqchip/irq-al-fic.c278
-rw-r--r--drivers/irqchip/irq-csky-mpintc.c86
-rw-r--r--drivers/irqchip/irq-gic-v2m.c85
-rw-r--r--drivers/irqchip/irq-gic-v3.c3
-rw-r--r--drivers/irqchip/irq-mbigen.c3
-rw-r--r--drivers/irqchip/irq-meson-gpio.c1
-rw-r--r--drivers/irqchip/irq-renesas-intc-irqpin.c3
-rw-r--r--drivers/irqchip/irq-renesas-irqc.c91
-rw-r--r--drivers/irqchip/irq-renesas-rza1.c283
-rw-r--r--drivers/irqchip/irq-sni-exiu.c142
-rw-r--r--drivers/irqchip/qcom-irq-combiner.c5
13 files changed, 890 insertions, 124 deletions
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 659c5e0fb835..80e10f4e213a 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -15,10 +15,10 @@ config ARM_GIC_PM
15 bool 15 bool
16 depends on PM 16 depends on PM
17 select ARM_GIC 17 select ARM_GIC
18 select PM_CLK
19 18
20config ARM_GIC_MAX_NR 19config ARM_GIC_MAX_NR
21 int 20 int
21 depends on ARM_GIC
22 default 2 if ARCH_REALVIEW 22 default 2 if ARCH_REALVIEW
23 default 1 23 default 1
24 24
@@ -87,6 +87,14 @@ config ALPINE_MSI
87 select PCI_MSI 87 select PCI_MSI
88 select GENERIC_IRQ_CHIP 88 select GENERIC_IRQ_CHIP
89 89
90config AL_FIC
91 bool "Amazon's Annapurna Labs Fabric Interrupt Controller"
92 depends on OF || COMPILE_TEST
93 select GENERIC_IRQ_CHIP
94 select IRQ_DOMAIN
95 help
96 Support Amazon's Annapurna Labs Fabric Interrupt Controller.
97
90config ATMEL_AIC_IRQ 98config ATMEL_AIC_IRQ
91 bool 99 bool
92 select GENERIC_IRQ_CHIP 100 select GENERIC_IRQ_CHIP
@@ -217,13 +225,26 @@ config RDA_INTC
217 select IRQ_DOMAIN 225 select IRQ_DOMAIN
218 226
219config RENESAS_INTC_IRQPIN 227config RENESAS_INTC_IRQPIN
220 bool 228 bool "Renesas INTC External IRQ Pin Support" if COMPILE_TEST
221 select IRQ_DOMAIN 229 select IRQ_DOMAIN
230 help
231 Enable support for the Renesas Interrupt Controller for external
232 interrupt pins, as found on SH/R-Mobile and R-Car Gen1 SoCs.
222 233
223config RENESAS_IRQC 234config RENESAS_IRQC
224 bool 235 bool "Renesas R-Mobile APE6 and R-Car IRQC support" if COMPILE_TEST
225 select GENERIC_IRQ_CHIP 236 select GENERIC_IRQ_CHIP
226 select IRQ_DOMAIN 237 select IRQ_DOMAIN
238 help
239 Enable support for the Renesas Interrupt Controller for external
240 devices, as found on R-Mobile APE6, R-Car Gen2, and R-Car Gen3 SoCs.
241
242config RENESAS_RZA1_IRQC
243 bool "Renesas RZ/A1 IRQC support" if COMPILE_TEST
244 select IRQ_DOMAIN_HIERARCHY
245 help
246 Enable support for the Renesas RZ/A1 Interrupt Controller, to use up
247 to 8 external interrupts with configurable sense select.
227 248
228config ST_IRQCHIP 249config ST_IRQCHIP
229 bool 250 bool
@@ -299,8 +320,11 @@ config RENESAS_H8300H_INTC
299 select IRQ_DOMAIN 320 select IRQ_DOMAIN
300 321
301config RENESAS_H8S_INTC 322config RENESAS_H8S_INTC
302 bool 323 bool "Renesas H8S Interrupt Controller Support" if COMPILE_TEST
303 select IRQ_DOMAIN 324 select IRQ_DOMAIN
325 help
326 Enable support for the Renesas H8/300 Interrupt Controller, as found
327 on Renesas H8S SoCs.
304 328
305config IMX_GPCV2 329config IMX_GPCV2
306 bool 330 bool
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 606a003a0000..8d0fcec6ab23 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -1,6 +1,7 @@
1# SPDX-License-Identifier: GPL-2.0 1# SPDX-License-Identifier: GPL-2.0
2obj-$(CONFIG_IRQCHIP) += irqchip.o 2obj-$(CONFIG_IRQCHIP) += irqchip.o
3 3
4obj-$(CONFIG_AL_FIC) += irq-al-fic.o
4obj-$(CONFIG_ALPINE_MSI) += irq-alpine-msi.o 5obj-$(CONFIG_ALPINE_MSI) += irq-alpine-msi.o
5obj-$(CONFIG_ATH79) += irq-ath79-cpu.o 6obj-$(CONFIG_ATH79) += irq-ath79-cpu.o
6obj-$(CONFIG_ATH79) += irq-ath79-misc.o 7obj-$(CONFIG_ATH79) += irq-ath79-misc.o
@@ -49,6 +50,7 @@ obj-$(CONFIG_JCORE_AIC) += irq-jcore-aic.o
49obj-$(CONFIG_RDA_INTC) += irq-rda-intc.o 50obj-$(CONFIG_RDA_INTC) += irq-rda-intc.o
50obj-$(CONFIG_RENESAS_INTC_IRQPIN) += irq-renesas-intc-irqpin.o 51obj-$(CONFIG_RENESAS_INTC_IRQPIN) += irq-renesas-intc-irqpin.o
51obj-$(CONFIG_RENESAS_IRQC) += irq-renesas-irqc.o 52obj-$(CONFIG_RENESAS_IRQC) += irq-renesas-irqc.o
53obj-$(CONFIG_RENESAS_RZA1_IRQC) += irq-renesas-rza1.o
52obj-$(CONFIG_VERSATILE_FPGA_IRQ) += irq-versatile-fpga.o 54obj-$(CONFIG_VERSATILE_FPGA_IRQ) += irq-versatile-fpga.o
53obj-$(CONFIG_ARCH_NSPIRE) += irq-zevio.o 55obj-$(CONFIG_ARCH_NSPIRE) += irq-zevio.o
54obj-$(CONFIG_ARCH_VT8500) += irq-vt8500.o 56obj-$(CONFIG_ARCH_VT8500) += irq-vt8500.o
diff --git a/drivers/irqchip/irq-al-fic.c b/drivers/irqchip/irq-al-fic.c
new file mode 100644
index 000000000000..1a57cee3efab
--- /dev/null
+++ b/drivers/irqchip/irq-al-fic.c
@@ -0,0 +1,278 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 */
5
6#include <linux/bitfield.h>
7#include <linux/irq.h>
8#include <linux/irqchip.h>
9#include <linux/irqchip/chained_irq.h>
10#include <linux/irqdomain.h>
11#include <linux/module.h>
12#include <linux/of.h>
13#include <linux/of_address.h>
14#include <linux/of_irq.h>
15
16/* FIC Registers */
17#define AL_FIC_CAUSE 0x00
18#define AL_FIC_MASK 0x10
19#define AL_FIC_CONTROL 0x28
20
21#define CONTROL_TRIGGER_RISING BIT(3)
22#define CONTROL_MASK_MSI_X BIT(5)
23
24#define NR_FIC_IRQS 32
25
26MODULE_AUTHOR("Talel Shenhar");
27MODULE_DESCRIPTION("Amazon's Annapurna Labs Interrupt Controller Driver");
28MODULE_LICENSE("GPL v2");
29
30enum al_fic_state {
31 AL_FIC_UNCONFIGURED = 0,
32 AL_FIC_CONFIGURED_LEVEL,
33 AL_FIC_CONFIGURED_RISING_EDGE,
34};
35
36struct al_fic {
37 void __iomem *base;
38 struct irq_domain *domain;
39 const char *name;
40 unsigned int parent_irq;
41 enum al_fic_state state;
42};
43
44static void al_fic_set_trigger(struct al_fic *fic,
45 struct irq_chip_generic *gc,
46 enum al_fic_state new_state)
47{
48 irq_flow_handler_t handler;
49 u32 control = readl_relaxed(fic->base + AL_FIC_CONTROL);
50
51 if (new_state == AL_FIC_CONFIGURED_LEVEL) {
52 handler = handle_level_irq;
53 control &= ~CONTROL_TRIGGER_RISING;
54 } else {
55 handler = handle_edge_irq;
56 control |= CONTROL_TRIGGER_RISING;
57 }
58 gc->chip_types->handler = handler;
59 fic->state = new_state;
60 writel_relaxed(control, fic->base + AL_FIC_CONTROL);
61}
62
63static int al_fic_irq_set_type(struct irq_data *data, unsigned int flow_type)
64{
65 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
66 struct al_fic *fic = gc->private;
67 enum al_fic_state new_state;
68 int ret = 0;
69
70 irq_gc_lock(gc);
71
72 if (((flow_type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_LEVEL_HIGH) &&
73 ((flow_type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_EDGE_RISING)) {
74 pr_debug("fic doesn't support flow type %d\n", flow_type);
75 ret = -EINVAL;
76 goto err;
77 }
78
79 new_state = (flow_type & IRQ_TYPE_LEVEL_HIGH) ?
80 AL_FIC_CONFIGURED_LEVEL : AL_FIC_CONFIGURED_RISING_EDGE;
81
82 /*
83 * A given FIC instance can be either all level or all edge triggered.
84 * This is generally fixed depending on what pieces of HW it's wired up
85 * to.
86 *
87 * We configure it based on the sensitivity of the first source
88 * being setup, and reject any subsequent attempt at configuring it in a
89 * different way.
90 */
91 if (fic->state == AL_FIC_UNCONFIGURED) {
92 al_fic_set_trigger(fic, gc, new_state);
93 } else if (fic->state != new_state) {
94 pr_debug("fic %s state already configured to %d\n",
95 fic->name, fic->state);
96 ret = -EINVAL;
97 goto err;
98 }
99
100err:
101 irq_gc_unlock(gc);
102
103 return ret;
104}
105
106static void al_fic_irq_handler(struct irq_desc *desc)
107{
108 struct al_fic *fic = irq_desc_get_handler_data(desc);
109 struct irq_domain *domain = fic->domain;
110 struct irq_chip *irqchip = irq_desc_get_chip(desc);
111 struct irq_chip_generic *gc = irq_get_domain_generic_chip(domain, 0);
112 unsigned long pending;
113 unsigned int irq;
114 u32 hwirq;
115
116 chained_irq_enter(irqchip, desc);
117
118 pending = readl_relaxed(fic->base + AL_FIC_CAUSE);
119 pending &= ~gc->mask_cache;
120
121 for_each_set_bit(hwirq, &pending, NR_FIC_IRQS) {
122 irq = irq_find_mapping(domain, hwirq);
123 generic_handle_irq(irq);
124 }
125
126 chained_irq_exit(irqchip, desc);
127}
128
129static int al_fic_register(struct device_node *node,
130 struct al_fic *fic)
131{
132 struct irq_chip_generic *gc;
133 int ret;
134
135 fic->domain = irq_domain_add_linear(node,
136 NR_FIC_IRQS,
137 &irq_generic_chip_ops,
138 fic);
139 if (!fic->domain) {
140 pr_err("fail to add irq domain\n");
141 return -ENOMEM;
142 }
143
144 ret = irq_alloc_domain_generic_chips(fic->domain,
145 NR_FIC_IRQS,
146 1, fic->name,
147 handle_level_irq,
148 0, 0, IRQ_GC_INIT_MASK_CACHE);
149 if (ret) {
150 pr_err("fail to allocate generic chip (%d)\n", ret);
151 goto err_domain_remove;
152 }
153
154 gc = irq_get_domain_generic_chip(fic->domain, 0);
155 gc->reg_base = fic->base;
156 gc->chip_types->regs.mask = AL_FIC_MASK;
157 gc->chip_types->regs.ack = AL_FIC_CAUSE;
158 gc->chip_types->chip.irq_mask = irq_gc_mask_set_bit;
159 gc->chip_types->chip.irq_unmask = irq_gc_mask_clr_bit;
160 gc->chip_types->chip.irq_ack = irq_gc_ack_clr_bit;
161 gc->chip_types->chip.irq_set_type = al_fic_irq_set_type;
162 gc->chip_types->chip.flags = IRQCHIP_SKIP_SET_WAKE;
163 gc->private = fic;
164
165 irq_set_chained_handler_and_data(fic->parent_irq,
166 al_fic_irq_handler,
167 fic);
168 return 0;
169
170err_domain_remove:
171 irq_domain_remove(fic->domain);
172
173 return ret;
174}
175
176/*
177 * al_fic_wire_init() - initialize and configure fic in wire mode
178 * @of_node: optional pointer to interrupt controller's device tree node.
179 * @base: mmio to fic register
180 * @name: name of the fic
181 * @parent_irq: interrupt of parent
182 *
183 * This API will configure the fic hardware to to work in wire mode.
184 * In wire mode, fic hardware is generating a wire ("wired") interrupt.
185 * Interrupt can be generated based on positive edge or level - configuration is
186 * to be determined based on connected hardware to this fic.
187 */
188static struct al_fic *al_fic_wire_init(struct device_node *node,
189 void __iomem *base,
190 const char *name,
191 unsigned int parent_irq)
192{
193 struct al_fic *fic;
194 int ret;
195 u32 control = CONTROL_MASK_MSI_X;
196
197 fic = kzalloc(sizeof(*fic), GFP_KERNEL);
198 if (!fic)
199 return ERR_PTR(-ENOMEM);
200
201 fic->base = base;
202 fic->parent_irq = parent_irq;
203 fic->name = name;
204
205 /* mask out all interrupts */
206 writel_relaxed(0xFFFFFFFF, fic->base + AL_FIC_MASK);
207
208 /* clear any pending interrupt */
209 writel_relaxed(0, fic->base + AL_FIC_CAUSE);
210
211 writel_relaxed(control, fic->base + AL_FIC_CONTROL);
212
213 ret = al_fic_register(node, fic);
214 if (ret) {
215 pr_err("fail to register irqchip\n");
216 goto err_free;
217 }
218
219 pr_debug("%s initialized successfully in Legacy mode (parent-irq=%u)\n",
220 fic->name, parent_irq);
221
222 return fic;
223
224err_free:
225 kfree(fic);
226 return ERR_PTR(ret);
227}
228
229static int __init al_fic_init_dt(struct device_node *node,
230 struct device_node *parent)
231{
232 int ret;
233 void __iomem *base;
234 unsigned int parent_irq;
235 struct al_fic *fic;
236
237 if (!parent) {
238 pr_err("%s: unsupported - device require a parent\n",
239 node->name);
240 return -EINVAL;
241 }
242
243 base = of_iomap(node, 0);
244 if (!base) {
245 pr_err("%s: fail to map memory\n", node->name);
246 return -ENOMEM;
247 }
248
249 parent_irq = irq_of_parse_and_map(node, 0);
250 if (!parent_irq) {
251 pr_err("%s: fail to map irq\n", node->name);
252 ret = -EINVAL;
253 goto err_unmap;
254 }
255
256 fic = al_fic_wire_init(node,
257 base,
258 node->name,
259 parent_irq);
260 if (IS_ERR(fic)) {
261 pr_err("%s: fail to initialize irqchip (%lu)\n",
262 node->name,
263 PTR_ERR(fic));
264 ret = PTR_ERR(fic);
265 goto err_irq_dispose;
266 }
267
268 return 0;
269
270err_irq_dispose:
271 irq_dispose_mapping(parent_irq);
272err_unmap:
273 iounmap(base);
274
275 return ret;
276}
277
278IRQCHIP_DECLARE(al_fic, "amazon,al-fic", al_fic_init_dt);
diff --git a/drivers/irqchip/irq-csky-mpintc.c b/drivers/irqchip/irq-csky-mpintc.c
index a4c1aacba1ff..a1534edef7fa 100644
--- a/drivers/irqchip/irq-csky-mpintc.c
+++ b/drivers/irqchip/irq-csky-mpintc.c
@@ -32,8 +32,8 @@ static void __iomem *INTCL_base;
32#define INTCG_CIDSTR 0x1000 32#define INTCG_CIDSTR 0x1000
33 33
34#define INTCL_PICTLR 0x0 34#define INTCL_PICTLR 0x0
35#define INTCL_CFGR 0x14
35#define INTCL_SIGR 0x60 36#define INTCL_SIGR 0x60
36#define INTCL_HPPIR 0x68
37#define INTCL_RDYIR 0x6c 37#define INTCL_RDYIR 0x6c
38#define INTCL_SENR 0xa0 38#define INTCL_SENR 0xa0
39#define INTCL_CENR 0xa4 39#define INTCL_CENR 0xa4
@@ -41,21 +41,49 @@ static void __iomem *INTCL_base;
41 41
42static DEFINE_PER_CPU(void __iomem *, intcl_reg); 42static DEFINE_PER_CPU(void __iomem *, intcl_reg);
43 43
44static unsigned long *__trigger;
45
46#define IRQ_OFFSET(irq) ((irq < COMM_IRQ_BASE) ? irq : (irq - COMM_IRQ_BASE))
47
48#define TRIG_BYTE_OFFSET(i) ((((i) * 2) / 32) * 4)
49#define TRIG_BIT_OFFSET(i) (((i) * 2) % 32)
50
51#define TRIG_VAL(trigger, irq) (trigger << TRIG_BIT_OFFSET(IRQ_OFFSET(irq)))
52#define TRIG_VAL_MSK(irq) (~(3 << TRIG_BIT_OFFSET(IRQ_OFFSET(irq))))
53
54#define TRIG_BASE(irq) \
55 (TRIG_BYTE_OFFSET(IRQ_OFFSET(irq)) + ((irq < COMM_IRQ_BASE) ? \
56 (this_cpu_read(intcl_reg) + INTCL_CFGR) : (INTCG_base + INTCG_CICFGR)))
57
58static DEFINE_SPINLOCK(setup_lock);
59static void setup_trigger(unsigned long irq, unsigned long trigger)
60{
61 unsigned int tmp;
62
63 spin_lock(&setup_lock);
64
65 /* setup trigger */
66 tmp = readl_relaxed(TRIG_BASE(irq)) & TRIG_VAL_MSK(irq);
67
68 writel_relaxed(tmp | TRIG_VAL(trigger, irq), TRIG_BASE(irq));
69
70 spin_unlock(&setup_lock);
71}
72
44static void csky_mpintc_handler(struct pt_regs *regs) 73static void csky_mpintc_handler(struct pt_regs *regs)
45{ 74{
46 void __iomem *reg_base = this_cpu_read(intcl_reg); 75 void __iomem *reg_base = this_cpu_read(intcl_reg);
47 76
48 do { 77 handle_domain_irq(root_domain,
49 handle_domain_irq(root_domain, 78 readl_relaxed(reg_base + INTCL_RDYIR), regs);
50 readl_relaxed(reg_base + INTCL_RDYIR),
51 regs);
52 } while (readl_relaxed(reg_base + INTCL_HPPIR) & BIT(31));
53} 79}
54 80
55static void csky_mpintc_enable(struct irq_data *d) 81static void csky_mpintc_enable(struct irq_data *d)
56{ 82{
57 void __iomem *reg_base = this_cpu_read(intcl_reg); 83 void __iomem *reg_base = this_cpu_read(intcl_reg);
58 84
85 setup_trigger(d->hwirq, __trigger[d->hwirq]);
86
59 writel_relaxed(d->hwirq, reg_base + INTCL_SENR); 87 writel_relaxed(d->hwirq, reg_base + INTCL_SENR);
60} 88}
61 89
@@ -73,6 +101,28 @@ static void csky_mpintc_eoi(struct irq_data *d)
73 writel_relaxed(d->hwirq, reg_base + INTCL_CACR); 101 writel_relaxed(d->hwirq, reg_base + INTCL_CACR);
74} 102}
75 103
104static int csky_mpintc_set_type(struct irq_data *d, unsigned int type)
105{
106 switch (type & IRQ_TYPE_SENSE_MASK) {
107 case IRQ_TYPE_LEVEL_HIGH:
108 __trigger[d->hwirq] = 0;
109 break;
110 case IRQ_TYPE_LEVEL_LOW:
111 __trigger[d->hwirq] = 1;
112 break;
113 case IRQ_TYPE_EDGE_RISING:
114 __trigger[d->hwirq] = 2;
115 break;
116 case IRQ_TYPE_EDGE_FALLING:
117 __trigger[d->hwirq] = 3;
118 break;
119 default:
120 return -EINVAL;
121 }
122
123 return 0;
124}
125
76#ifdef CONFIG_SMP 126#ifdef CONFIG_SMP
77static int csky_irq_set_affinity(struct irq_data *d, 127static int csky_irq_set_affinity(struct irq_data *d,
78 const struct cpumask *mask_val, 128 const struct cpumask *mask_val,
@@ -116,6 +166,7 @@ static struct irq_chip csky_irq_chip = {
116 .irq_eoi = csky_mpintc_eoi, 166 .irq_eoi = csky_mpintc_eoi,
117 .irq_enable = csky_mpintc_enable, 167 .irq_enable = csky_mpintc_enable,
118 .irq_disable = csky_mpintc_disable, 168 .irq_disable = csky_mpintc_disable,
169 .irq_set_type = csky_mpintc_set_type,
119#ifdef CONFIG_SMP 170#ifdef CONFIG_SMP
120 .irq_set_affinity = csky_irq_set_affinity, 171 .irq_set_affinity = csky_irq_set_affinity,
121#endif 172#endif
@@ -136,9 +187,26 @@ static int csky_irqdomain_map(struct irq_domain *d, unsigned int irq,
136 return 0; 187 return 0;
137} 188}
138 189
190static int csky_irq_domain_xlate_cells(struct irq_domain *d,
191 struct device_node *ctrlr, const u32 *intspec,
192 unsigned int intsize, unsigned long *out_hwirq,
193 unsigned int *out_type)
194{
195 if (WARN_ON(intsize < 1))
196 return -EINVAL;
197
198 *out_hwirq = intspec[0];
199 if (intsize > 1)
200 *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
201 else
202 *out_type = IRQ_TYPE_LEVEL_HIGH;
203
204 return 0;
205}
206
139static const struct irq_domain_ops csky_irqdomain_ops = { 207static const struct irq_domain_ops csky_irqdomain_ops = {
140 .map = csky_irqdomain_map, 208 .map = csky_irqdomain_map,
141 .xlate = irq_domain_xlate_onecell, 209 .xlate = csky_irq_domain_xlate_cells,
142}; 210};
143 211
144#ifdef CONFIG_SMP 212#ifdef CONFIG_SMP
@@ -172,6 +240,10 @@ csky_mpintc_init(struct device_node *node, struct device_node *parent)
172 if (ret < 0) 240 if (ret < 0)
173 nr_irq = INTC_IRQS; 241 nr_irq = INTC_IRQS;
174 242
243 __trigger = kcalloc(nr_irq, sizeof(unsigned long), GFP_KERNEL);
244 if (__trigger == NULL)
245 return -ENXIO;
246
175 if (INTCG_base == NULL) { 247 if (INTCG_base == NULL) {
176 INTCG_base = ioremap(mfcr("cr<31, 14>"), 248 INTCG_base = ioremap(mfcr("cr<31, 14>"),
177 INTCL_SIZE*nr_cpu_ids + INTCG_SIZE); 249 INTCL_SIZE*nr_cpu_ids + INTCG_SIZE);
diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c
index 875ac80f690b..7338f90b2f9e 100644
--- a/drivers/irqchip/irq-gic-v2m.c
+++ b/drivers/irqchip/irq-gic-v2m.c
@@ -53,6 +53,7 @@
53 53
54/* List of flags for specific v2m implementation */ 54/* List of flags for specific v2m implementation */
55#define GICV2M_NEEDS_SPI_OFFSET 0x00000001 55#define GICV2M_NEEDS_SPI_OFFSET 0x00000001
56#define GICV2M_GRAVITON_ADDRESS_ONLY 0x00000002
56 57
57static LIST_HEAD(v2m_nodes); 58static LIST_HEAD(v2m_nodes);
58static DEFINE_SPINLOCK(v2m_lock); 59static DEFINE_SPINLOCK(v2m_lock);
@@ -95,15 +96,26 @@ static struct msi_domain_info gicv2m_msi_domain_info = {
95 .chip = &gicv2m_msi_irq_chip, 96 .chip = &gicv2m_msi_irq_chip,
96}; 97};
97 98
99static phys_addr_t gicv2m_get_msi_addr(struct v2m_data *v2m, int hwirq)
100{
101 if (v2m->flags & GICV2M_GRAVITON_ADDRESS_ONLY)
102 return v2m->res.start | ((hwirq - 32) << 3);
103 else
104 return v2m->res.start + V2M_MSI_SETSPI_NS;
105}
106
98static void gicv2m_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) 107static void gicv2m_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
99{ 108{
100 struct v2m_data *v2m = irq_data_get_irq_chip_data(data); 109 struct v2m_data *v2m = irq_data_get_irq_chip_data(data);
101 phys_addr_t addr = v2m->res.start + V2M_MSI_SETSPI_NS; 110 phys_addr_t addr = gicv2m_get_msi_addr(v2m, data->hwirq);
102 111
103 msg->address_hi = upper_32_bits(addr); 112 msg->address_hi = upper_32_bits(addr);
104 msg->address_lo = lower_32_bits(addr); 113 msg->address_lo = lower_32_bits(addr);
105 msg->data = data->hwirq;
106 114
115 if (v2m->flags & GICV2M_GRAVITON_ADDRESS_ONLY)
116 msg->data = 0;
117 else
118 msg->data = data->hwirq;
107 if (v2m->flags & GICV2M_NEEDS_SPI_OFFSET) 119 if (v2m->flags & GICV2M_NEEDS_SPI_OFFSET)
108 msg->data -= v2m->spi_offset; 120 msg->data -= v2m->spi_offset;
109 121
@@ -185,7 +197,7 @@ static int gicv2m_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
185 hwirq = v2m->spi_start + offset; 197 hwirq = v2m->spi_start + offset;
186 198
187 err = iommu_dma_prepare_msi(info->desc, 199 err = iommu_dma_prepare_msi(info->desc,
188 v2m->res.start + V2M_MSI_SETSPI_NS); 200 gicv2m_get_msi_addr(v2m, hwirq));
189 if (err) 201 if (err)
190 return err; 202 return err;
191 203
@@ -304,7 +316,7 @@ static int gicv2m_allocate_domains(struct irq_domain *parent)
304 316
305static int __init gicv2m_init_one(struct fwnode_handle *fwnode, 317static int __init gicv2m_init_one(struct fwnode_handle *fwnode,
306 u32 spi_start, u32 nr_spis, 318 u32 spi_start, u32 nr_spis,
307 struct resource *res) 319 struct resource *res, u32 flags)
308{ 320{
309 int ret; 321 int ret;
310 struct v2m_data *v2m; 322 struct v2m_data *v2m;
@@ -317,6 +329,7 @@ static int __init gicv2m_init_one(struct fwnode_handle *fwnode,
317 329
318 INIT_LIST_HEAD(&v2m->entry); 330 INIT_LIST_HEAD(&v2m->entry);
319 v2m->fwnode = fwnode; 331 v2m->fwnode = fwnode;
332 v2m->flags = flags;
320 333
321 memcpy(&v2m->res, res, sizeof(struct resource)); 334 memcpy(&v2m->res, res, sizeof(struct resource));
322 335
@@ -331,7 +344,14 @@ static int __init gicv2m_init_one(struct fwnode_handle *fwnode,
331 v2m->spi_start = spi_start; 344 v2m->spi_start = spi_start;
332 v2m->nr_spis = nr_spis; 345 v2m->nr_spis = nr_spis;
333 } else { 346 } else {
334 u32 typer = readl_relaxed(v2m->base + V2M_MSI_TYPER); 347 u32 typer;
348
349 /* Graviton should always have explicit spi_start/nr_spis */
350 if (v2m->flags & GICV2M_GRAVITON_ADDRESS_ONLY) {
351 ret = -EINVAL;
352 goto err_iounmap;
353 }
354 typer = readl_relaxed(v2m->base + V2M_MSI_TYPER);
335 355
336 v2m->spi_start = V2M_MSI_TYPER_BASE_SPI(typer); 356 v2m->spi_start = V2M_MSI_TYPER_BASE_SPI(typer);
337 v2m->nr_spis = V2M_MSI_TYPER_NUM_SPI(typer); 357 v2m->nr_spis = V2M_MSI_TYPER_NUM_SPI(typer);
@@ -352,18 +372,21 @@ static int __init gicv2m_init_one(struct fwnode_handle *fwnode,
352 * 372 *
353 * Broadom NS2 GICv2m implementation has an erratum where the MSI data 373 * Broadom NS2 GICv2m implementation has an erratum where the MSI data
354 * is 'spi_number - 32' 374 * is 'spi_number - 32'
375 *
376 * Reading that register fails on the Graviton implementation
355 */ 377 */
356 switch (readl_relaxed(v2m->base + V2M_MSI_IIDR)) { 378 if (!(v2m->flags & GICV2M_GRAVITON_ADDRESS_ONLY)) {
357 case XGENE_GICV2M_MSI_IIDR: 379 switch (readl_relaxed(v2m->base + V2M_MSI_IIDR)) {
358 v2m->flags |= GICV2M_NEEDS_SPI_OFFSET; 380 case XGENE_GICV2M_MSI_IIDR:
359 v2m->spi_offset = v2m->spi_start; 381 v2m->flags |= GICV2M_NEEDS_SPI_OFFSET;
360 break; 382 v2m->spi_offset = v2m->spi_start;
361 case BCM_NS2_GICV2M_MSI_IIDR: 383 break;
362 v2m->flags |= GICV2M_NEEDS_SPI_OFFSET; 384 case BCM_NS2_GICV2M_MSI_IIDR:
363 v2m->spi_offset = 32; 385 v2m->flags |= GICV2M_NEEDS_SPI_OFFSET;
364 break; 386 v2m->spi_offset = 32;
387 break;
388 }
365 } 389 }
366
367 v2m->bm = kcalloc(BITS_TO_LONGS(v2m->nr_spis), sizeof(long), 390 v2m->bm = kcalloc(BITS_TO_LONGS(v2m->nr_spis), sizeof(long),
368 GFP_KERNEL); 391 GFP_KERNEL);
369 if (!v2m->bm) { 392 if (!v2m->bm) {
@@ -416,7 +439,8 @@ static int __init gicv2m_of_init(struct fwnode_handle *parent_handle,
416 pr_info("DT overriding V2M MSI_TYPER (base:%u, num:%u)\n", 439 pr_info("DT overriding V2M MSI_TYPER (base:%u, num:%u)\n",
417 spi_start, nr_spis); 440 spi_start, nr_spis);
418 441
419 ret = gicv2m_init_one(&child->fwnode, spi_start, nr_spis, &res); 442 ret = gicv2m_init_one(&child->fwnode, spi_start, nr_spis,
443 &res, 0);
420 if (ret) { 444 if (ret) {
421 of_node_put(child); 445 of_node_put(child);
422 break; 446 break;
@@ -448,6 +472,25 @@ static struct fwnode_handle *gicv2m_get_fwnode(struct device *dev)
448 return data->fwnode; 472 return data->fwnode;
449} 473}
450 474
475static bool acpi_check_amazon_graviton_quirks(void)
476{
477 static struct acpi_table_madt *madt;
478 acpi_status status;
479 bool rc = false;
480
481#define ACPI_AMZN_OEM_ID "AMAZON"
482
483 status = acpi_get_table(ACPI_SIG_MADT, 0,
484 (struct acpi_table_header **)&madt);
485
486 if (ACPI_FAILURE(status) || !madt)
487 return rc;
488 rc = !memcmp(madt->header.oem_id, ACPI_AMZN_OEM_ID, ACPI_OEM_ID_SIZE);
489 acpi_put_table((struct acpi_table_header *)madt);
490
491 return rc;
492}
493
451static int __init 494static int __init
452acpi_parse_madt_msi(union acpi_subtable_headers *header, 495acpi_parse_madt_msi(union acpi_subtable_headers *header,
453 const unsigned long end) 496 const unsigned long end)
@@ -457,6 +500,7 @@ acpi_parse_madt_msi(union acpi_subtable_headers *header,
457 u32 spi_start = 0, nr_spis = 0; 500 u32 spi_start = 0, nr_spis = 0;
458 struct acpi_madt_generic_msi_frame *m; 501 struct acpi_madt_generic_msi_frame *m;
459 struct fwnode_handle *fwnode; 502 struct fwnode_handle *fwnode;
503 u32 flags = 0;
460 504
461 m = (struct acpi_madt_generic_msi_frame *)header; 505 m = (struct acpi_madt_generic_msi_frame *)header;
462 if (BAD_MADT_ENTRY(m, end)) 506 if (BAD_MADT_ENTRY(m, end))
@@ -466,6 +510,13 @@ acpi_parse_madt_msi(union acpi_subtable_headers *header,
466 res.end = m->base_address + SZ_4K - 1; 510 res.end = m->base_address + SZ_4K - 1;
467 res.flags = IORESOURCE_MEM; 511 res.flags = IORESOURCE_MEM;
468 512
513 if (acpi_check_amazon_graviton_quirks()) {
514 pr_info("applying Amazon Graviton quirk\n");
515 res.end = res.start + SZ_8K - 1;
516 flags |= GICV2M_GRAVITON_ADDRESS_ONLY;
517 gicv2m_msi_domain_info.flags &= ~MSI_FLAG_MULTI_PCI_MSI;
518 }
519
469 if (m->flags & ACPI_MADT_OVERRIDE_SPI_VALUES) { 520 if (m->flags & ACPI_MADT_OVERRIDE_SPI_VALUES) {
470 spi_start = m->spi_base; 521 spi_start = m->spi_base;
471 nr_spis = m->spi_count; 522 nr_spis = m->spi_count;
@@ -480,7 +531,7 @@ acpi_parse_madt_msi(union acpi_subtable_headers *header,
480 return -EINVAL; 531 return -EINVAL;
481 } 532 }
482 533
483 ret = gicv2m_init_one(fwnode, spi_start, nr_spis, &res); 534 ret = gicv2m_init_one(fwnode, spi_start, nr_spis, &res, flags);
484 if (ret) 535 if (ret)
485 irq_domain_free_fwnode(fwnode); 536 irq_domain_free_fwnode(fwnode);
486 537
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index f3e44d6d9255..9bca4896fa6f 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -1339,6 +1339,9 @@ static int __init gic_init_bases(void __iomem *dist_base,
1339 if (gic_dist_supports_lpis()) { 1339 if (gic_dist_supports_lpis()) {
1340 its_init(handle, &gic_data.rdists, gic_data.domain); 1340 its_init(handle, &gic_data.rdists, gic_data.domain);
1341 its_cpu_init(); 1341 its_cpu_init();
1342 } else {
1343 if (IS_ENABLED(CONFIG_ARM_GIC_V2M))
1344 gicv2m_init(handle, gic_data.domain);
1342 } 1345 }
1343 1346
1344 if (gic_prio_masking_enabled()) { 1347 if (gic_prio_masking_enabled()) {
diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
index a89c693d5b90..3dd28382d5f5 100644
--- a/drivers/irqchip/irq-mbigen.c
+++ b/drivers/irqchip/irq-mbigen.c
@@ -344,8 +344,7 @@ static int mbigen_device_probe(struct platform_device *pdev)
344 err = -EINVAL; 344 err = -EINVAL;
345 345
346 if (err) { 346 if (err) {
347 dev_err(&pdev->dev, "Failed to create mbi-gen@%p irqdomain", 347 dev_err(&pdev->dev, "Failed to create mbi-gen irqdomain\n");
348 mgn_chip->base);
349 return err; 348 return err;
350 } 349 }
351 350
diff --git a/drivers/irqchip/irq-meson-gpio.c b/drivers/irqchip/irq-meson-gpio.c
index 8eb92eb98f54..dcdc23b9dce6 100644
--- a/drivers/irqchip/irq-meson-gpio.c
+++ b/drivers/irqchip/irq-meson-gpio.c
@@ -60,6 +60,7 @@ static const struct of_device_id meson_irq_gpio_matches[] = {
60 { .compatible = "amlogic,meson-gxbb-gpio-intc", .data = &gxbb_params }, 60 { .compatible = "amlogic,meson-gxbb-gpio-intc", .data = &gxbb_params },
61 { .compatible = "amlogic,meson-gxl-gpio-intc", .data = &gxl_params }, 61 { .compatible = "amlogic,meson-gxl-gpio-intc", .data = &gxl_params },
62 { .compatible = "amlogic,meson-axg-gpio-intc", .data = &axg_params }, 62 { .compatible = "amlogic,meson-axg-gpio-intc", .data = &axg_params },
63 { .compatible = "amlogic,meson-g12a-gpio-intc", .data = &axg_params },
63 { } 64 { }
64}; 65};
65 66
diff --git a/drivers/irqchip/irq-renesas-intc-irqpin.c b/drivers/irqchip/irq-renesas-intc-irqpin.c
index 04c05a18600c..f82bc60a6793 100644
--- a/drivers/irqchip/irq-renesas-intc-irqpin.c
+++ b/drivers/irqchip/irq-renesas-intc-irqpin.c
@@ -508,7 +508,8 @@ static int intc_irqpin_probe(struct platform_device *pdev)
508 } 508 }
509 509
510 irq_chip = &p->irq_chip; 510 irq_chip = &p->irq_chip;
511 irq_chip->name = name; 511 irq_chip->name = "intc-irqpin";
512 irq_chip->parent_device = dev;
512 irq_chip->irq_mask = disable_fn; 513 irq_chip->irq_mask = disable_fn;
513 irq_chip->irq_unmask = enable_fn; 514 irq_chip->irq_unmask = enable_fn;
514 irq_chip->irq_set_type = intc_irqpin_irq_set_type; 515 irq_chip->irq_set_type = intc_irqpin_irq_set_type;
diff --git a/drivers/irqchip/irq-renesas-irqc.c b/drivers/irqchip/irq-renesas-irqc.c
index a449a7c839b3..11abc09ef76c 100644
--- a/drivers/irqchip/irq-renesas-irqc.c
+++ b/drivers/irqchip/irq-renesas-irqc.c
@@ -7,7 +7,6 @@
7 7
8#include <linux/init.h> 8#include <linux/init.h>
9#include <linux/platform_device.h> 9#include <linux/platform_device.h>
10#include <linux/spinlock.h>
11#include <linux/interrupt.h> 10#include <linux/interrupt.h>
12#include <linux/ioport.h> 11#include <linux/ioport.h>
13#include <linux/io.h> 12#include <linux/io.h>
@@ -48,7 +47,7 @@ struct irqc_priv {
48 void __iomem *cpu_int_base; 47 void __iomem *cpu_int_base;
49 struct irqc_irq irq[IRQC_IRQ_MAX]; 48 struct irqc_irq irq[IRQC_IRQ_MAX];
50 unsigned int number_of_irqs; 49 unsigned int number_of_irqs;
51 struct platform_device *pdev; 50 struct device *dev;
52 struct irq_chip_generic *gc; 51 struct irq_chip_generic *gc;
53 struct irq_domain *irq_domain; 52 struct irq_domain *irq_domain;
54 atomic_t wakeup_path; 53 atomic_t wakeup_path;
@@ -61,8 +60,7 @@ static struct irqc_priv *irq_data_to_priv(struct irq_data *data)
61 60
62static void irqc_dbg(struct irqc_irq *i, char *str) 61static void irqc_dbg(struct irqc_irq *i, char *str)
63{ 62{
64 dev_dbg(&i->p->pdev->dev, "%s (%d:%d)\n", 63 dev_dbg(i->p->dev, "%s (%d:%d)\n", str, i->requested_irq, i->hw_irq);
65 str, i->requested_irq, i->hw_irq);
66} 64}
67 65
68static unsigned char irqc_sense[IRQ_TYPE_SENSE_MASK + 1] = { 66static unsigned char irqc_sense[IRQ_TYPE_SENSE_MASK + 1] = {
@@ -125,33 +123,22 @@ static irqreturn_t irqc_irq_handler(int irq, void *dev_id)
125 123
126static int irqc_probe(struct platform_device *pdev) 124static int irqc_probe(struct platform_device *pdev)
127{ 125{
126 struct device *dev = &pdev->dev;
127 const char *name = dev_name(dev);
128 struct irqc_priv *p; 128 struct irqc_priv *p;
129 struct resource *io;
130 struct resource *irq; 129 struct resource *irq;
131 const char *name = dev_name(&pdev->dev);
132 int ret; 130 int ret;
133 int k; 131 int k;
134 132
135 p = kzalloc(sizeof(*p), GFP_KERNEL); 133 p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL);
136 if (!p) { 134 if (!p)
137 dev_err(&pdev->dev, "failed to allocate driver data\n"); 135 return -ENOMEM;
138 ret = -ENOMEM;
139 goto err0;
140 }
141 136
142 p->pdev = pdev; 137 p->dev = dev;
143 platform_set_drvdata(pdev, p); 138 platform_set_drvdata(pdev, p);
144 139
145 pm_runtime_enable(&pdev->dev); 140 pm_runtime_enable(dev);
146 pm_runtime_get_sync(&pdev->dev); 141 pm_runtime_get_sync(dev);
147
148 /* get hold of manadatory IOMEM */
149 io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
150 if (!io) {
151 dev_err(&pdev->dev, "not enough IOMEM resources\n");
152 ret = -EINVAL;
153 goto err1;
154 }
155 142
156 /* allow any number of IRQs between 1 and IRQC_IRQ_MAX */ 143 /* allow any number of IRQs between 1 and IRQC_IRQ_MAX */
157 for (k = 0; k < IRQC_IRQ_MAX; k++) { 144 for (k = 0; k < IRQC_IRQ_MAX; k++) {
@@ -166,42 +153,41 @@ static int irqc_probe(struct platform_device *pdev)
166 153
167 p->number_of_irqs = k; 154 p->number_of_irqs = k;
168 if (p->number_of_irqs < 1) { 155 if (p->number_of_irqs < 1) {
169 dev_err(&pdev->dev, "not enough IRQ resources\n"); 156 dev_err(dev, "not enough IRQ resources\n");
170 ret = -EINVAL; 157 ret = -EINVAL;
171 goto err1; 158 goto err_runtime_pm_disable;
172 } 159 }
173 160
174 /* ioremap IOMEM and setup read/write callbacks */ 161 /* ioremap IOMEM and setup read/write callbacks */
175 p->iomem = ioremap_nocache(io->start, resource_size(io)); 162 p->iomem = devm_platform_ioremap_resource(pdev, 0);
176 if (!p->iomem) { 163 if (IS_ERR(p->iomem)) {
177 dev_err(&pdev->dev, "failed to remap IOMEM\n"); 164 ret = PTR_ERR(p->iomem);
178 ret = -ENXIO; 165 goto err_runtime_pm_disable;
179 goto err2;
180 } 166 }
181 167
182 p->cpu_int_base = p->iomem + IRQC_INT_CPU_BASE(0); /* SYS-SPI */ 168 p->cpu_int_base = p->iomem + IRQC_INT_CPU_BASE(0); /* SYS-SPI */
183 169
184 p->irq_domain = irq_domain_add_linear(pdev->dev.of_node, 170 p->irq_domain = irq_domain_add_linear(dev->of_node, p->number_of_irqs,
185 p->number_of_irqs,
186 &irq_generic_chip_ops, p); 171 &irq_generic_chip_ops, p);
187 if (!p->irq_domain) { 172 if (!p->irq_domain) {
188 ret = -ENXIO; 173 ret = -ENXIO;
189 dev_err(&pdev->dev, "cannot initialize irq domain\n"); 174 dev_err(dev, "cannot initialize irq domain\n");
190 goto err2; 175 goto err_runtime_pm_disable;
191 } 176 }
192 177
193 ret = irq_alloc_domain_generic_chips(p->irq_domain, p->number_of_irqs, 178 ret = irq_alloc_domain_generic_chips(p->irq_domain, p->number_of_irqs,
194 1, name, handle_level_irq, 179 1, "irqc", handle_level_irq,
195 0, 0, IRQ_GC_INIT_NESTED_LOCK); 180 0, 0, IRQ_GC_INIT_NESTED_LOCK);
196 if (ret) { 181 if (ret) {
197 dev_err(&pdev->dev, "cannot allocate generic chip\n"); 182 dev_err(dev, "cannot allocate generic chip\n");
198 goto err3; 183 goto err_remove_domain;
199 } 184 }
200 185
201 p->gc = irq_get_domain_generic_chip(p->irq_domain, 0); 186 p->gc = irq_get_domain_generic_chip(p->irq_domain, 0);
202 p->gc->reg_base = p->cpu_int_base; 187 p->gc->reg_base = p->cpu_int_base;
203 p->gc->chip_types[0].regs.enable = IRQC_EN_SET; 188 p->gc->chip_types[0].regs.enable = IRQC_EN_SET;
204 p->gc->chip_types[0].regs.disable = IRQC_EN_STS; 189 p->gc->chip_types[0].regs.disable = IRQC_EN_STS;
190 p->gc->chip_types[0].chip.parent_device = dev;
205 p->gc->chip_types[0].chip.irq_mask = irq_gc_mask_disable_reg; 191 p->gc->chip_types[0].chip.irq_mask = irq_gc_mask_disable_reg;
206 p->gc->chip_types[0].chip.irq_unmask = irq_gc_unmask_enable_reg; 192 p->gc->chip_types[0].chip.irq_unmask = irq_gc_unmask_enable_reg;
207 p->gc->chip_types[0].chip.irq_set_type = irqc_irq_set_type; 193 p->gc->chip_types[0].chip.irq_set_type = irqc_irq_set_type;
@@ -210,46 +196,33 @@ static int irqc_probe(struct platform_device *pdev)
210 196
211 /* request interrupts one by one */ 197 /* request interrupts one by one */
212 for (k = 0; k < p->number_of_irqs; k++) { 198 for (k = 0; k < p->number_of_irqs; k++) {
213 if (request_irq(p->irq[k].requested_irq, irqc_irq_handler, 199 if (devm_request_irq(dev, p->irq[k].requested_irq,
214 0, name, &p->irq[k])) { 200 irqc_irq_handler, 0, name, &p->irq[k])) {
215 dev_err(&pdev->dev, "failed to request IRQ\n"); 201 dev_err(dev, "failed to request IRQ\n");
216 ret = -ENOENT; 202 ret = -ENOENT;
217 goto err4; 203 goto err_remove_domain;
218 } 204 }
219 } 205 }
220 206
221 dev_info(&pdev->dev, "driving %d irqs\n", p->number_of_irqs); 207 dev_info(dev, "driving %d irqs\n", p->number_of_irqs);
222 208
223 return 0; 209 return 0;
224err4:
225 while (--k >= 0)
226 free_irq(p->irq[k].requested_irq, &p->irq[k]);
227 210
228err3: 211err_remove_domain:
229 irq_domain_remove(p->irq_domain); 212 irq_domain_remove(p->irq_domain);
230err2: 213err_runtime_pm_disable:
231 iounmap(p->iomem); 214 pm_runtime_put(dev);
232err1: 215 pm_runtime_disable(dev);
233 pm_runtime_put(&pdev->dev);
234 pm_runtime_disable(&pdev->dev);
235 kfree(p);
236err0:
237 return ret; 216 return ret;
238} 217}
239 218
240static int irqc_remove(struct platform_device *pdev) 219static int irqc_remove(struct platform_device *pdev)
241{ 220{
242 struct irqc_priv *p = platform_get_drvdata(pdev); 221 struct irqc_priv *p = platform_get_drvdata(pdev);
243 int k;
244
245 for (k = 0; k < p->number_of_irqs; k++)
246 free_irq(p->irq[k].requested_irq, &p->irq[k]);
247 222
248 irq_domain_remove(p->irq_domain); 223 irq_domain_remove(p->irq_domain);
249 iounmap(p->iomem);
250 pm_runtime_put(&pdev->dev); 224 pm_runtime_put(&pdev->dev);
251 pm_runtime_disable(&pdev->dev); 225 pm_runtime_disable(&pdev->dev);
252 kfree(p);
253 return 0; 226 return 0;
254} 227}
255 228
diff --git a/drivers/irqchip/irq-renesas-rza1.c b/drivers/irqchip/irq-renesas-rza1.c
new file mode 100644
index 000000000000..b1f19b210190
--- /dev/null
+++ b/drivers/irqchip/irq-renesas-rza1.c
@@ -0,0 +1,283 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Renesas RZ/A1 IRQC Driver
4 *
5 * Copyright (C) 2019 Glider bvba
6 */
7
8#include <linux/err.h>
9#include <linux/init.h>
10#include <linux/interrupt.h>
11#include <linux/io.h>
12#include <linux/irqdomain.h>
13#include <linux/irq.h>
14#include <linux/module.h>
15#include <linux/of_irq.h>
16#include <linux/platform_device.h>
17#include <linux/slab.h>
18
19#include <dt-bindings/interrupt-controller/arm-gic.h>
20
21#define IRQC_NUM_IRQ 8
22
23#define ICR0 0 /* Interrupt Control Register 0 */
24
25#define ICR0_NMIL BIT(15) /* NMI Input Level (0=low, 1=high) */
26#define ICR0_NMIE BIT(8) /* Edge Select (0=falling, 1=rising) */
27#define ICR0_NMIF BIT(1) /* NMI Interrupt Request */
28
29#define ICR1 2 /* Interrupt Control Register 1 */
30
31#define ICR1_IRQS(n, sense) ((sense) << ((n) * 2)) /* IRQ Sense Select */
32#define ICR1_IRQS_LEVEL_LOW 0
33#define ICR1_IRQS_EDGE_FALLING 1
34#define ICR1_IRQS_EDGE_RISING 2
35#define ICR1_IRQS_EDGE_BOTH 3
36#define ICR1_IRQS_MASK(n) ICR1_IRQS((n), 3)
37
38#define IRQRR 4 /* IRQ Interrupt Request Register */
39
40
41struct rza1_irqc_priv {
42 struct device *dev;
43 void __iomem *base;
44 struct irq_chip chip;
45 struct irq_domain *irq_domain;
46 struct of_phandle_args map[IRQC_NUM_IRQ];
47};
48
49static struct rza1_irqc_priv *irq_data_to_priv(struct irq_data *data)
50{
51 return data->domain->host_data;
52}
53
54static void rza1_irqc_eoi(struct irq_data *d)
55{
56 struct rza1_irqc_priv *priv = irq_data_to_priv(d);
57 u16 bit = BIT(irqd_to_hwirq(d));
58 u16 tmp;
59
60 tmp = readw_relaxed(priv->base + IRQRR);
61 if (tmp & bit)
62 writew_relaxed(GENMASK(IRQC_NUM_IRQ - 1, 0) & ~bit,
63 priv->base + IRQRR);
64
65 irq_chip_eoi_parent(d);
66}
67
68static int rza1_irqc_set_type(struct irq_data *d, unsigned int type)
69{
70 struct rza1_irqc_priv *priv = irq_data_to_priv(d);
71 unsigned int hw_irq = irqd_to_hwirq(d);
72 u16 sense, tmp;
73
74 switch (type & IRQ_TYPE_SENSE_MASK) {
75 case IRQ_TYPE_LEVEL_LOW:
76 sense = ICR1_IRQS_LEVEL_LOW;
77 break;
78
79 case IRQ_TYPE_EDGE_FALLING:
80 sense = ICR1_IRQS_EDGE_FALLING;
81 break;
82
83 case IRQ_TYPE_EDGE_RISING:
84 sense = ICR1_IRQS_EDGE_RISING;
85 break;
86
87 case IRQ_TYPE_EDGE_BOTH:
88 sense = ICR1_IRQS_EDGE_BOTH;
89 break;
90
91 default:
92 return -EINVAL;
93 }
94
95 tmp = readw_relaxed(priv->base + ICR1);
96 tmp &= ~ICR1_IRQS_MASK(hw_irq);
97 tmp |= ICR1_IRQS(hw_irq, sense);
98 writew_relaxed(tmp, priv->base + ICR1);
99 return 0;
100}
101
102static int rza1_irqc_alloc(struct irq_domain *domain, unsigned int virq,
103 unsigned int nr_irqs, void *arg)
104{
105 struct rza1_irqc_priv *priv = domain->host_data;
106 struct irq_fwspec *fwspec = arg;
107 unsigned int hwirq = fwspec->param[0];
108 struct irq_fwspec spec;
109 unsigned int i;
110 int ret;
111
112 ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq, &priv->chip,
113 priv);
114 if (ret)
115 return ret;
116
117 spec.fwnode = &priv->dev->of_node->fwnode;
118 spec.param_count = priv->map[hwirq].args_count;
119 for (i = 0; i < spec.param_count; i++)
120 spec.param[i] = priv->map[hwirq].args[i];
121
122 return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &spec);
123}
124
125static int rza1_irqc_translate(struct irq_domain *domain,
126 struct irq_fwspec *fwspec, unsigned long *hwirq,
127 unsigned int *type)
128{
129 if (fwspec->param_count != 2 || fwspec->param[0] >= IRQC_NUM_IRQ)
130 return -EINVAL;
131
132 *hwirq = fwspec->param[0];
133 *type = fwspec->param[1];
134 return 0;
135}
136
137static const struct irq_domain_ops rza1_irqc_domain_ops = {
138 .alloc = rza1_irqc_alloc,
139 .translate = rza1_irqc_translate,
140};
141
142static int rza1_irqc_parse_map(struct rza1_irqc_priv *priv,
143 struct device_node *gic_node)
144{
145 unsigned int imaplen, i, j, ret;
146 struct device *dev = priv->dev;
147 struct device_node *ipar;
148 const __be32 *imap;
149 u32 intsize;
150
151 imap = of_get_property(dev->of_node, "interrupt-map", &imaplen);
152 if (!imap)
153 return -EINVAL;
154
155 for (i = 0; i < IRQC_NUM_IRQ; i++) {
156 if (imaplen < 3)
157 return -EINVAL;
158
159 /* Check interrupt number, ignore sense */
160 if (be32_to_cpup(imap) != i)
161 return -EINVAL;
162
163 ipar = of_find_node_by_phandle(be32_to_cpup(imap + 2));
164 if (ipar != gic_node) {
165 of_node_put(ipar);
166 return -EINVAL;
167 }
168
169 imap += 3;
170 imaplen -= 3;
171
172 ret = of_property_read_u32(ipar, "#interrupt-cells", &intsize);
173 of_node_put(ipar);
174 if (ret)
175 return ret;
176
177 if (imaplen < intsize)
178 return -EINVAL;
179
180 priv->map[i].args_count = intsize;
181 for (j = 0; j < intsize; j++)
182 priv->map[i].args[j] = be32_to_cpup(imap++);
183
184 imaplen -= intsize;
185 }
186
187 return 0;
188}
189
190static int rza1_irqc_probe(struct platform_device *pdev)
191{
192 struct device *dev = &pdev->dev;
193 struct device_node *np = dev->of_node;
194 struct irq_domain *parent = NULL;
195 struct device_node *gic_node;
196 struct rza1_irqc_priv *priv;
197 int ret;
198
199 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
200 if (!priv)
201 return -ENOMEM;
202
203 platform_set_drvdata(pdev, priv);
204 priv->dev = dev;
205
206 priv->base = devm_platform_ioremap_resource(pdev, 0);
207 if (IS_ERR(priv->base))
208 return PTR_ERR(priv->base);
209
210 gic_node = of_irq_find_parent(np);
211 if (gic_node) {
212 parent = irq_find_host(gic_node);
213 of_node_put(gic_node);
214 }
215
216 if (!parent) {
217 dev_err(dev, "cannot find parent domain\n");
218 return -ENODEV;
219 }
220
221 ret = rza1_irqc_parse_map(priv, gic_node);
222 if (ret) {
223 dev_err(dev, "cannot parse %s: %d\n", "interrupt-map", ret);
224 return ret;
225 }
226
227 priv->chip.name = "rza1-irqc",
228 priv->chip.irq_mask = irq_chip_mask_parent,
229 priv->chip.irq_unmask = irq_chip_unmask_parent,
230 priv->chip.irq_eoi = rza1_irqc_eoi,
231 priv->chip.irq_retrigger = irq_chip_retrigger_hierarchy,
232 priv->chip.irq_set_type = rza1_irqc_set_type,
233 priv->chip.flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE;
234
235 priv->irq_domain = irq_domain_add_hierarchy(parent, 0, IRQC_NUM_IRQ,
236 np, &rza1_irqc_domain_ops,
237 priv);
238 if (!priv->irq_domain) {
239 dev_err(dev, "cannot initialize irq domain\n");
240 return -ENOMEM;
241 }
242
243 return 0;
244}
245
246static int rza1_irqc_remove(struct platform_device *pdev)
247{
248 struct rza1_irqc_priv *priv = platform_get_drvdata(pdev);
249
250 irq_domain_remove(priv->irq_domain);
251 return 0;
252}
253
254static const struct of_device_id rza1_irqc_dt_ids[] = {
255 { .compatible = "renesas,rza1-irqc" },
256 {},
257};
258MODULE_DEVICE_TABLE(of, rza1_irqc_dt_ids);
259
260static struct platform_driver rza1_irqc_device_driver = {
261 .probe = rza1_irqc_probe,
262 .remove = rza1_irqc_remove,
263 .driver = {
264 .name = "renesas_rza1_irqc",
265 .of_match_table = rza1_irqc_dt_ids,
266 }
267};
268
269static int __init rza1_irqc_init(void)
270{
271 return platform_driver_register(&rza1_irqc_device_driver);
272}
273postcore_initcall(rza1_irqc_init);
274
275static void __exit rza1_irqc_exit(void)
276{
277 platform_driver_unregister(&rza1_irqc_device_driver);
278}
279module_exit(rza1_irqc_exit);
280
281MODULE_AUTHOR("Geert Uytterhoeven <geert+renesas@glider.be>");
282MODULE_DESCRIPTION("Renesas RZ/A1 IRQC Driver");
283MODULE_LICENSE("GPL v2");
diff --git a/drivers/irqchip/irq-sni-exiu.c b/drivers/irqchip/irq-sni-exiu.c
index 4e983bc6cf93..1d027623c776 100644
--- a/drivers/irqchip/irq-sni-exiu.c
+++ b/drivers/irqchip/irq-sni-exiu.c
@@ -2,7 +2,7 @@
2/* 2/*
3 * Driver for Socionext External Interrupt Unit (EXIU) 3 * Driver for Socionext External Interrupt Unit (EXIU)
4 * 4 *
5 * Copyright (c) 2017 Linaro, Ltd. <ard.biesheuvel@linaro.org> 5 * Copyright (c) 2017-2019 Linaro, Ltd. <ard.biesheuvel@linaro.org>
6 * 6 *
7 * Based on irq-tegra.c: 7 * Based on irq-tegra.c:
8 * Copyright (C) 2011 Google, Inc. 8 * Copyright (C) 2011 Google, Inc.
@@ -17,6 +17,7 @@
17#include <linux/of.h> 17#include <linux/of.h>
18#include <linux/of_address.h> 18#include <linux/of_address.h>
19#include <linux/of_irq.h> 19#include <linux/of_irq.h>
20#include <linux/platform_device.h>
20 21
21#include <dt-bindings/interrupt-controller/arm-gic.h> 22#include <dt-bindings/interrupt-controller/arm-gic.h>
22 23
@@ -131,9 +132,13 @@ static int exiu_domain_translate(struct irq_domain *domain,
131 132
132 *hwirq = fwspec->param[1] - info->spi_base; 133 *hwirq = fwspec->param[1] - info->spi_base;
133 *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK; 134 *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
134 return 0; 135 } else {
136 if (fwspec->param_count != 2)
137 return -EINVAL;
138 *hwirq = fwspec->param[0];
139 *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
135 } 140 }
136 return -EINVAL; 141 return 0;
137} 142}
138 143
139static int exiu_domain_alloc(struct irq_domain *dom, unsigned int virq, 144static int exiu_domain_alloc(struct irq_domain *dom, unsigned int virq,
@@ -144,16 +149,21 @@ static int exiu_domain_alloc(struct irq_domain *dom, unsigned int virq,
144 struct exiu_irq_data *info = dom->host_data; 149 struct exiu_irq_data *info = dom->host_data;
145 irq_hw_number_t hwirq; 150 irq_hw_number_t hwirq;
146 151
147 if (fwspec->param_count != 3) 152 parent_fwspec = *fwspec;
148 return -EINVAL; /* Not GIC compliant */ 153 if (is_of_node(dom->parent->fwnode)) {
149 if (fwspec->param[0] != GIC_SPI) 154 if (fwspec->param_count != 3)
150 return -EINVAL; /* No PPI should point to this domain */ 155 return -EINVAL; /* Not GIC compliant */
156 if (fwspec->param[0] != GIC_SPI)
157 return -EINVAL; /* No PPI should point to this domain */
151 158
159 hwirq = fwspec->param[1] - info->spi_base;
160 } else {
161 hwirq = fwspec->param[0];
162 parent_fwspec.param[0] = hwirq + info->spi_base + 32;
163 }
152 WARN_ON(nr_irqs != 1); 164 WARN_ON(nr_irqs != 1);
153 hwirq = fwspec->param[1] - info->spi_base;
154 irq_domain_set_hwirq_and_chip(dom, virq, hwirq, &exiu_irq_chip, info); 165 irq_domain_set_hwirq_and_chip(dom, virq, hwirq, &exiu_irq_chip, info);
155 166
156 parent_fwspec = *fwspec;
157 parent_fwspec.fwnode = dom->parent->fwnode; 167 parent_fwspec.fwnode = dom->parent->fwnode;
158 return irq_domain_alloc_irqs_parent(dom, virq, nr_irqs, &parent_fwspec); 168 return irq_domain_alloc_irqs_parent(dom, virq, nr_irqs, &parent_fwspec);
159} 169}
@@ -164,35 +174,23 @@ static const struct irq_domain_ops exiu_domain_ops = {
164 .free = irq_domain_free_irqs_common, 174 .free = irq_domain_free_irqs_common,
165}; 175};
166 176
167static int __init exiu_init(struct device_node *node, 177static struct exiu_irq_data *exiu_init(const struct fwnode_handle *fwnode,
168 struct device_node *parent) 178 struct resource *res)
169{ 179{
170 struct irq_domain *parent_domain, *domain;
171 struct exiu_irq_data *data; 180 struct exiu_irq_data *data;
172 int err; 181 int err;
173 182
174 if (!parent) {
175 pr_err("%pOF: no parent, giving up\n", node);
176 return -ENODEV;
177 }
178
179 parent_domain = irq_find_host(parent);
180 if (!parent_domain) {
181 pr_err("%pOF: unable to obtain parent domain\n", node);
182 return -ENXIO;
183 }
184
185 data = kzalloc(sizeof(*data), GFP_KERNEL); 183 data = kzalloc(sizeof(*data), GFP_KERNEL);
186 if (!data) 184 if (!data)
187 return -ENOMEM; 185 return ERR_PTR(-ENOMEM);
188 186
189 if (of_property_read_u32(node, "socionext,spi-base", &data->spi_base)) { 187 if (fwnode_property_read_u32_array(fwnode, "socionext,spi-base",
190 pr_err("%pOF: failed to parse 'spi-base' property\n", node); 188 &data->spi_base, 1)) {
191 err = -ENODEV; 189 err = -ENODEV;
192 goto out_free; 190 goto out_free;
193 } 191 }
194 192
195 data->base = of_iomap(node, 0); 193 data->base = ioremap(res->start, resource_size(res));
196 if (!data->base) { 194 if (!data->base) {
197 err = -ENODEV; 195 err = -ENODEV;
198 goto out_free; 196 goto out_free;
@@ -202,11 +200,44 @@ static int __init exiu_init(struct device_node *node,
202 writel_relaxed(0xFFFFFFFF, data->base + EIREQCLR); 200 writel_relaxed(0xFFFFFFFF, data->base + EIREQCLR);
203 writel_relaxed(0xFFFFFFFF, data->base + EIMASK); 201 writel_relaxed(0xFFFFFFFF, data->base + EIMASK);
204 202
203 return data;
204
205out_free:
206 kfree(data);
207 return ERR_PTR(err);
208}
209
210static int __init exiu_dt_init(struct device_node *node,
211 struct device_node *parent)
212{
213 struct irq_domain *parent_domain, *domain;
214 struct exiu_irq_data *data;
215 struct resource res;
216
217 if (!parent) {
218 pr_err("%pOF: no parent, giving up\n", node);
219 return -ENODEV;
220 }
221
222 parent_domain = irq_find_host(parent);
223 if (!parent_domain) {
224 pr_err("%pOF: unable to obtain parent domain\n", node);
225 return -ENXIO;
226 }
227
228 if (of_address_to_resource(node, 0, &res)) {
229 pr_err("%pOF: failed to parse memory resource\n", node);
230 return -ENXIO;
231 }
232
233 data = exiu_init(of_node_to_fwnode(node), &res);
234 if (IS_ERR(data))
235 return PTR_ERR(data);
236
205 domain = irq_domain_add_hierarchy(parent_domain, 0, NUM_IRQS, node, 237 domain = irq_domain_add_hierarchy(parent_domain, 0, NUM_IRQS, node,
206 &exiu_domain_ops, data); 238 &exiu_domain_ops, data);
207 if (!domain) { 239 if (!domain) {
208 pr_err("%pOF: failed to allocate domain\n", node); 240 pr_err("%pOF: failed to allocate domain\n", node);
209 err = -ENOMEM;
210 goto out_unmap; 241 goto out_unmap;
211 } 242 }
212 243
@@ -217,8 +248,57 @@ static int __init exiu_init(struct device_node *node,
217 248
218out_unmap: 249out_unmap:
219 iounmap(data->base); 250 iounmap(data->base);
220out_free:
221 kfree(data); 251 kfree(data);
222 return err; 252 return -ENOMEM;
223} 253}
224IRQCHIP_DECLARE(exiu, "socionext,synquacer-exiu", exiu_init); 254IRQCHIP_DECLARE(exiu, "socionext,synquacer-exiu", exiu_dt_init);
255
256#ifdef CONFIG_ACPI
257static int exiu_acpi_probe(struct platform_device *pdev)
258{
259 struct irq_domain *domain;
260 struct exiu_irq_data *data;
261 struct resource *res;
262
263 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
264 if (!res) {
265 dev_err(&pdev->dev, "failed to parse memory resource\n");
266 return -ENXIO;
267 }
268
269 data = exiu_init(dev_fwnode(&pdev->dev), res);
270 if (IS_ERR(data))
271 return PTR_ERR(data);
272
273 domain = acpi_irq_create_hierarchy(0, NUM_IRQS, dev_fwnode(&pdev->dev),
274 &exiu_domain_ops, data);
275 if (!domain) {
276 dev_err(&pdev->dev, "failed to create IRQ domain\n");
277 goto out_unmap;
278 }
279
280 dev_info(&pdev->dev, "%d interrupts forwarded\n", NUM_IRQS);
281
282 return 0;
283
284out_unmap:
285 iounmap(data->base);
286 kfree(data);
287 return -ENOMEM;
288}
289
290static const struct acpi_device_id exiu_acpi_ids[] = {
291 { "SCX0008" },
292 { /* sentinel */ }
293};
294MODULE_DEVICE_TABLE(acpi, exiu_acpi_ids);
295
296static struct platform_driver exiu_driver = {
297 .driver = {
298 .name = "exiu",
299 .acpi_match_table = exiu_acpi_ids,
300 },
301 .probe = exiu_acpi_probe,
302};
303builtin_platform_driver(exiu_driver);
304#endif
diff --git a/drivers/irqchip/qcom-irq-combiner.c b/drivers/irqchip/qcom-irq-combiner.c
index 067337ab3f20..d88e993aa66d 100644
--- a/drivers/irqchip/qcom-irq-combiner.c
+++ b/drivers/irqchip/qcom-irq-combiner.c
@@ -229,7 +229,6 @@ static int get_registers(struct platform_device *pdev, struct combiner *comb)
229static int __init combiner_probe(struct platform_device *pdev) 229static int __init combiner_probe(struct platform_device *pdev)
230{ 230{
231 struct combiner *combiner; 231 struct combiner *combiner;
232 size_t alloc_sz;
233 int nregs; 232 int nregs;
234 int err; 233 int err;
235 234
@@ -239,8 +238,8 @@ static int __init combiner_probe(struct platform_device *pdev)
239 return -EINVAL; 238 return -EINVAL;
240 } 239 }
241 240
242 alloc_sz = sizeof(*combiner) + sizeof(struct combiner_reg) * nregs; 241 combiner = devm_kzalloc(&pdev->dev, struct_size(combiner, regs, nregs),
243 combiner = devm_kzalloc(&pdev->dev, alloc_sz, GFP_KERNEL); 242 GFP_KERNEL);
244 if (!combiner) 243 if (!combiner)
245 return -ENOMEM; 244 return -ENOMEM;
246 245