diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-07-08 14:01:13 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-07-08 14:01:13 -0400 |
commit | 2a1ccd31420a7b1acd6ca37b2bec2d723aa093e4 (patch) | |
tree | 43946f0c4afc7dce86fc055df48d661f8ed3999c /drivers/irqchip | |
parent | e0e86b111bca6bbf746c03ec5cf3e6a61fa3f8e9 (diff) | |
parent | 3a1d24ca9573fbc74a3d32c972c333b161e0e9dc (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/Kconfig | 32 | ||||
-rw-r--r-- | drivers/irqchip/Makefile | 2 | ||||
-rw-r--r-- | drivers/irqchip/irq-al-fic.c | 278 | ||||
-rw-r--r-- | drivers/irqchip/irq-csky-mpintc.c | 86 | ||||
-rw-r--r-- | drivers/irqchip/irq-gic-v2m.c | 85 | ||||
-rw-r--r-- | drivers/irqchip/irq-gic-v3.c | 3 | ||||
-rw-r--r-- | drivers/irqchip/irq-mbigen.c | 3 | ||||
-rw-r--r-- | drivers/irqchip/irq-meson-gpio.c | 1 | ||||
-rw-r--r-- | drivers/irqchip/irq-renesas-intc-irqpin.c | 3 | ||||
-rw-r--r-- | drivers/irqchip/irq-renesas-irqc.c | 91 | ||||
-rw-r--r-- | drivers/irqchip/irq-renesas-rza1.c | 283 | ||||
-rw-r--r-- | drivers/irqchip/irq-sni-exiu.c | 142 | ||||
-rw-r--r-- | drivers/irqchip/qcom-irq-combiner.c | 5 |
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 | ||
20 | config ARM_GIC_MAX_NR | 19 | config 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 | ||
90 | config 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 | |||
90 | config ATMEL_AIC_IRQ | 98 | config 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 | ||
219 | config RENESAS_INTC_IRQPIN | 227 | config 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 | ||
223 | config RENESAS_IRQC | 234 | config 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 | |||
242 | config 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 | ||
228 | config ST_IRQCHIP | 249 | config ST_IRQCHIP |
229 | bool | 250 | bool |
@@ -299,8 +320,11 @@ config RENESAS_H8300H_INTC | |||
299 | select IRQ_DOMAIN | 320 | select IRQ_DOMAIN |
300 | 321 | ||
301 | config RENESAS_H8S_INTC | 322 | config 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 | ||
305 | config IMX_GPCV2 | 329 | config 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 |
2 | obj-$(CONFIG_IRQCHIP) += irqchip.o | 2 | obj-$(CONFIG_IRQCHIP) += irqchip.o |
3 | 3 | ||
4 | obj-$(CONFIG_AL_FIC) += irq-al-fic.o | ||
4 | obj-$(CONFIG_ALPINE_MSI) += irq-alpine-msi.o | 5 | obj-$(CONFIG_ALPINE_MSI) += irq-alpine-msi.o |
5 | obj-$(CONFIG_ATH79) += irq-ath79-cpu.o | 6 | obj-$(CONFIG_ATH79) += irq-ath79-cpu.o |
6 | obj-$(CONFIG_ATH79) += irq-ath79-misc.o | 7 | obj-$(CONFIG_ATH79) += irq-ath79-misc.o |
@@ -49,6 +50,7 @@ obj-$(CONFIG_JCORE_AIC) += irq-jcore-aic.o | |||
49 | obj-$(CONFIG_RDA_INTC) += irq-rda-intc.o | 50 | obj-$(CONFIG_RDA_INTC) += irq-rda-intc.o |
50 | obj-$(CONFIG_RENESAS_INTC_IRQPIN) += irq-renesas-intc-irqpin.o | 51 | obj-$(CONFIG_RENESAS_INTC_IRQPIN) += irq-renesas-intc-irqpin.o |
51 | obj-$(CONFIG_RENESAS_IRQC) += irq-renesas-irqc.o | 52 | obj-$(CONFIG_RENESAS_IRQC) += irq-renesas-irqc.o |
53 | obj-$(CONFIG_RENESAS_RZA1_IRQC) += irq-renesas-rza1.o | ||
52 | obj-$(CONFIG_VERSATILE_FPGA_IRQ) += irq-versatile-fpga.o | 54 | obj-$(CONFIG_VERSATILE_FPGA_IRQ) += irq-versatile-fpga.o |
53 | obj-$(CONFIG_ARCH_NSPIRE) += irq-zevio.o | 55 | obj-$(CONFIG_ARCH_NSPIRE) += irq-zevio.o |
54 | obj-$(CONFIG_ARCH_VT8500) += irq-vt8500.o | 56 | obj-$(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 | |||
26 | MODULE_AUTHOR("Talel Shenhar"); | ||
27 | MODULE_DESCRIPTION("Amazon's Annapurna Labs Interrupt Controller Driver"); | ||
28 | MODULE_LICENSE("GPL v2"); | ||
29 | |||
30 | enum al_fic_state { | ||
31 | AL_FIC_UNCONFIGURED = 0, | ||
32 | AL_FIC_CONFIGURED_LEVEL, | ||
33 | AL_FIC_CONFIGURED_RISING_EDGE, | ||
34 | }; | ||
35 | |||
36 | struct 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 | |||
44 | static 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 | |||
63 | static 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 | |||
100 | err: | ||
101 | irq_gc_unlock(gc); | ||
102 | |||
103 | return ret; | ||
104 | } | ||
105 | |||
106 | static 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 | |||
129 | static 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 | |||
170 | err_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 | */ | ||
188 | static 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 | |||
224 | err_free: | ||
225 | kfree(fic); | ||
226 | return ERR_PTR(ret); | ||
227 | } | ||
228 | |||
229 | static 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 | |||
270 | err_irq_dispose: | ||
271 | irq_dispose_mapping(parent_irq); | ||
272 | err_unmap: | ||
273 | iounmap(base); | ||
274 | |||
275 | return ret; | ||
276 | } | ||
277 | |||
278 | IRQCHIP_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 | ||
42 | static DEFINE_PER_CPU(void __iomem *, intcl_reg); | 42 | static DEFINE_PER_CPU(void __iomem *, intcl_reg); |
43 | 43 | ||
44 | static 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 | |||
58 | static DEFINE_SPINLOCK(setup_lock); | ||
59 | static 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 | |||
44 | static void csky_mpintc_handler(struct pt_regs *regs) | 73 | static 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 | ||
55 | static void csky_mpintc_enable(struct irq_data *d) | 81 | static 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 | ||
104 | static 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 |
77 | static int csky_irq_set_affinity(struct irq_data *d, | 127 | static 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 | ||
190 | static 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 | |||
139 | static const struct irq_domain_ops csky_irqdomain_ops = { | 207 | static 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 | ||
57 | static LIST_HEAD(v2m_nodes); | 58 | static LIST_HEAD(v2m_nodes); |
58 | static DEFINE_SPINLOCK(v2m_lock); | 59 | static 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 | ||
99 | static 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 | |||
98 | static void gicv2m_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) | 107 | static 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 | ||
305 | static int __init gicv2m_init_one(struct fwnode_handle *fwnode, | 317 | static 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 | ||
475 | static 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 | |||
451 | static int __init | 494 | static int __init |
452 | acpi_parse_madt_msi(union acpi_subtable_headers *header, | 495 | acpi_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 | ||
62 | static void irqc_dbg(struct irqc_irq *i, char *str) | 61 | static 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 | ||
68 | static unsigned char irqc_sense[IRQ_TYPE_SENSE_MASK + 1] = { | 66 | static 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 | ||
126 | static int irqc_probe(struct platform_device *pdev) | 124 | static 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; |
224 | err4: | ||
225 | while (--k >= 0) | ||
226 | free_irq(p->irq[k].requested_irq, &p->irq[k]); | ||
227 | 210 | ||
228 | err3: | 211 | err_remove_domain: |
229 | irq_domain_remove(p->irq_domain); | 212 | irq_domain_remove(p->irq_domain); |
230 | err2: | 213 | err_runtime_pm_disable: |
231 | iounmap(p->iomem); | 214 | pm_runtime_put(dev); |
232 | err1: | 215 | pm_runtime_disable(dev); |
233 | pm_runtime_put(&pdev->dev); | ||
234 | pm_runtime_disable(&pdev->dev); | ||
235 | kfree(p); | ||
236 | err0: | ||
237 | return ret; | 216 | return ret; |
238 | } | 217 | } |
239 | 218 | ||
240 | static int irqc_remove(struct platform_device *pdev) | 219 | static 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 | |||
41 | struct 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 | |||
49 | static struct rza1_irqc_priv *irq_data_to_priv(struct irq_data *data) | ||
50 | { | ||
51 | return data->domain->host_data; | ||
52 | } | ||
53 | |||
54 | static 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 | |||
68 | static 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 | |||
102 | static 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 | |||
125 | static 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 | |||
137 | static const struct irq_domain_ops rza1_irqc_domain_ops = { | ||
138 | .alloc = rza1_irqc_alloc, | ||
139 | .translate = rza1_irqc_translate, | ||
140 | }; | ||
141 | |||
142 | static 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 | |||
190 | static 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 | |||
246 | static 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 | |||
254 | static const struct of_device_id rza1_irqc_dt_ids[] = { | ||
255 | { .compatible = "renesas,rza1-irqc" }, | ||
256 | {}, | ||
257 | }; | ||
258 | MODULE_DEVICE_TABLE(of, rza1_irqc_dt_ids); | ||
259 | |||
260 | static 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 | |||
269 | static int __init rza1_irqc_init(void) | ||
270 | { | ||
271 | return platform_driver_register(&rza1_irqc_device_driver); | ||
272 | } | ||
273 | postcore_initcall(rza1_irqc_init); | ||
274 | |||
275 | static void __exit rza1_irqc_exit(void) | ||
276 | { | ||
277 | platform_driver_unregister(&rza1_irqc_device_driver); | ||
278 | } | ||
279 | module_exit(rza1_irqc_exit); | ||
280 | |||
281 | MODULE_AUTHOR("Geert Uytterhoeven <geert+renesas@glider.be>"); | ||
282 | MODULE_DESCRIPTION("Renesas RZ/A1 IRQC Driver"); | ||
283 | MODULE_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 | ||
139 | static int exiu_domain_alloc(struct irq_domain *dom, unsigned int virq, | 144 | static 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 | ||
167 | static int __init exiu_init(struct device_node *node, | 177 | static 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 | |||
205 | out_free: | ||
206 | kfree(data); | ||
207 | return ERR_PTR(err); | ||
208 | } | ||
209 | |||
210 | static 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 | ||
218 | out_unmap: | 249 | out_unmap: |
219 | iounmap(data->base); | 250 | iounmap(data->base); |
220 | out_free: | ||
221 | kfree(data); | 251 | kfree(data); |
222 | return err; | 252 | return -ENOMEM; |
223 | } | 253 | } |
224 | IRQCHIP_DECLARE(exiu, "socionext,synquacer-exiu", exiu_init); | 254 | IRQCHIP_DECLARE(exiu, "socionext,synquacer-exiu", exiu_dt_init); |
255 | |||
256 | #ifdef CONFIG_ACPI | ||
257 | static 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 | |||
284 | out_unmap: | ||
285 | iounmap(data->base); | ||
286 | kfree(data); | ||
287 | return -ENOMEM; | ||
288 | } | ||
289 | |||
290 | static const struct acpi_device_id exiu_acpi_ids[] = { | ||
291 | { "SCX0008" }, | ||
292 | { /* sentinel */ } | ||
293 | }; | ||
294 | MODULE_DEVICE_TABLE(acpi, exiu_acpi_ids); | ||
295 | |||
296 | static struct platform_driver exiu_driver = { | ||
297 | .driver = { | ||
298 | .name = "exiu", | ||
299 | .acpi_match_table = exiu_acpi_ids, | ||
300 | }, | ||
301 | .probe = exiu_acpi_probe, | ||
302 | }; | ||
303 | builtin_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) | |||
229 | static int __init combiner_probe(struct platform_device *pdev) | 229 | static 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 | ||