irq-ixp4xx.c (1136fa0c07de570dc17858745af8be169d1440ba) irq-ixp4xx.c (c83227a5d05ed77b634ce4c2fc5f143ae2a4d6f5)
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * irqchip for the IXP4xx interrupt controller
4 * Copyright (C) 2019 Linus Walleij <linus.walleij@linaro.org>
5 *
6 * Based on arch/arm/mach-ixp4xx/common.c
7 * Copyright 2002 (C) Intel Corporation
8 * Copyright 2003-2004 (C) MontaVista, Software, Inc.
9 * Copyright (C) Deepak Saxena <dsaxena@plexity.net>
10 */
11#include <linux/bitops.h>
12#include <linux/gpio/driver.h>
13#include <linux/irq.h>
14#include <linux/io.h>
15#include <linux/irqchip.h>
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * irqchip for the IXP4xx interrupt controller
4 * Copyright (C) 2019 Linus Walleij <linus.walleij@linaro.org>
5 *
6 * Based on arch/arm/mach-ixp4xx/common.c
7 * Copyright 2002 (C) Intel Corporation
8 * Copyright 2003-2004 (C) MontaVista, Software, Inc.
9 * Copyright (C) Deepak Saxena <dsaxena@plexity.net>
10 */
11#include <linux/bitops.h>
12#include <linux/gpio/driver.h>
13#include <linux/irq.h>
14#include <linux/io.h>
15#include <linux/irqchip.h>
16#include <linux/irqchip/irq-ixp4xx.h>
17#include <linux/irqdomain.h>
18#include <linux/of.h>
19#include <linux/of_address.h>
20#include <linux/of_irq.h>
21#include <linux/platform_device.h>
22#include <linux/cpu.h>
23
24#include <asm/exception.h>

--- 76 unchanged lines hidden (view full) ---

101 __raw_writel(val, ixi->irqbase + IXP4XX_ICMR2);
102 } else {
103 val = __raw_readl(ixi->irqbase + IXP4XX_ICMR);
104 val |= BIT(d->hwirq);
105 __raw_writel(val, ixi->irqbase + IXP4XX_ICMR);
106 }
107}
108
16#include <linux/irqdomain.h>
17#include <linux/of.h>
18#include <linux/of_address.h>
19#include <linux/of_irq.h>
20#include <linux/platform_device.h>
21#include <linux/cpu.h>
22
23#include <asm/exception.h>

--- 76 unchanged lines hidden (view full) ---

100 __raw_writel(val, ixi->irqbase + IXP4XX_ICMR2);
101 } else {
102 val = __raw_readl(ixi->irqbase + IXP4XX_ICMR);
103 val |= BIT(d->hwirq);
104 __raw_writel(val, ixi->irqbase + IXP4XX_ICMR);
105 }
106}
107
109asmlinkage void __exception_irq_entry ixp4xx_handle_irq(struct pt_regs *regs)
108static asmlinkage void __exception_irq_entry
109ixp4xx_handle_irq(struct pt_regs *regs)
110{
111 struct ixp4xx_irq *ixi = &ixirq;
112 unsigned long status;
113 int i;
114
115 status = __raw_readl(ixi->irqbase + IXP4XX_ICIP);
116 for_each_set_bit(i, &status, 32)
117 generic_handle_domain_irq(ixi->domain, i);

--- 73 unchanged lines hidden (view full) ---

191 */
192static const struct irq_domain_ops ixp4xx_irqdomain_ops = {
193 .translate = ixp4xx_irq_domain_translate,
194 .alloc = ixp4xx_irq_domain_alloc,
195 .free = irq_domain_free_irqs_common,
196};
197
198/**
110{
111 struct ixp4xx_irq *ixi = &ixirq;
112 unsigned long status;
113 int i;
114
115 status = __raw_readl(ixi->irqbase + IXP4XX_ICIP);
116 for_each_set_bit(i, &status, 32)
117 generic_handle_domain_irq(ixi->domain, i);

--- 73 unchanged lines hidden (view full) ---

191 */
192static const struct irq_domain_ops ixp4xx_irqdomain_ops = {
193 .translate = ixp4xx_irq_domain_translate,
194 .alloc = ixp4xx_irq_domain_alloc,
195 .free = irq_domain_free_irqs_common,
196};
197
198/**
199 * ixp4xx_get_irq_domain() - retrieve the ixp4xx irq domain
200 *
201 * This function will go away when we transition to DT probing.
202 */
203struct irq_domain *ixp4xx_get_irq_domain(void)
204{
205 struct ixp4xx_irq *ixi = &ixirq;
206
207 return ixi->domain;
208}
209EXPORT_SYMBOL_GPL(ixp4xx_get_irq_domain);
210
211/*
212 * This is the Linux IRQ to hwirq mapping table. This goes away when
213 * we have DT support as all IRQ resources are defined in the device
214 * tree. It will register all the IRQs that are not used by the hierarchical
215 * GPIO IRQ chip. The "holes" inbetween these IRQs will be requested by
216 * the GPIO driver using . This is a step-gap solution.
217 */
218struct ixp4xx_irq_chunk {
219 int irq;
220 int hwirq;
221 int nr_irqs;
222};
223
224static const struct ixp4xx_irq_chunk ixp4xx_irq_chunks[] = {
225 {
226 .irq = 16,
227 .hwirq = 0,
228 .nr_irqs = 6,
229 },
230 {
231 .irq = 24,
232 .hwirq = 8,
233 .nr_irqs = 11,
234 },
235 {
236 .irq = 46,
237 .hwirq = 30,
238 .nr_irqs = 2,
239 },
240 /* Only on the 436 variants */
241 {
242 .irq = 48,
243 .hwirq = 32,
244 .nr_irqs = 10,
245 },
246};
247
248/**
249 * ixp4x_irq_setup() - Common setup code for the IXP4xx interrupt controller
250 * @ixi: State container
251 * @irqbase: Virtual memory base for the interrupt controller
252 * @fwnode: Corresponding fwnode abstraction for this controller
253 * @is_356: if this is an IXP43x, IXP45x or IXP46x SoC variant
254 */
255static int __init ixp4xx_irq_setup(struct ixp4xx_irq *ixi,
256 void __iomem *irqbase,

--- 36 unchanged lines hidden (view full) ---

293 return -ENODEV;
294 }
295
296 set_handle_irq(ixp4xx_handle_irq);
297
298 return 0;
299}
300
199 * ixp4x_irq_setup() - Common setup code for the IXP4xx interrupt controller
200 * @ixi: State container
201 * @irqbase: Virtual memory base for the interrupt controller
202 * @fwnode: Corresponding fwnode abstraction for this controller
203 * @is_356: if this is an IXP43x, IXP45x or IXP46x SoC variant
204 */
205static int __init ixp4xx_irq_setup(struct ixp4xx_irq *ixi,
206 void __iomem *irqbase,

--- 36 unchanged lines hidden (view full) ---

243 return -ENODEV;
244 }
245
246 set_handle_irq(ixp4xx_handle_irq);
247
248 return 0;
249}
250
301/**
302 * ixp4xx_irq_init() - Function to initialize the irqchip from boardfiles
303 * @irqbase: physical base for the irq controller
304 * @is_356: if this is an IXP43x, IXP45x or IXP46x SoC variant
305 */
306void __init ixp4xx_irq_init(resource_size_t irqbase,
307 bool is_356)
251static int __init ixp4xx_of_init_irq(struct device_node *np,
252 struct device_node *parent)
308{
309 struct ixp4xx_irq *ixi = &ixirq;
310 void __iomem *base;
311 struct fwnode_handle *fwnode;
253{
254 struct ixp4xx_irq *ixi = &ixirq;
255 void __iomem *base;
256 struct fwnode_handle *fwnode;
312 struct irq_fwspec fwspec;
313 int nr_chunks;
314 int ret;
315 int i;
316
317 base = ioremap(irqbase, 0x100);
318 if (!base) {
319 pr_crit("IXP4XX: could not ioremap interrupt controller\n");
320 return;
321 }
322 fwnode = irq_domain_alloc_fwnode(&irqbase);
323 if (!fwnode) {
324 pr_crit("IXP4XX: no domain handle\n");
325 return;
326 }
327 ret = ixp4xx_irq_setup(ixi, base, fwnode, is_356);
328 if (ret) {
329 pr_crit("IXP4XX: failed to set up irqchip\n");
330 irq_domain_free_fwnode(fwnode);
331 }
332
333 nr_chunks = ARRAY_SIZE(ixp4xx_irq_chunks);
334 if (!is_356)
335 nr_chunks--;
336
337 /*
338 * After adding OF support, this is no longer needed: irqs
339 * will be allocated for the respective fwnodes.
340 */
341 for (i = 0; i < nr_chunks; i++) {
342 const struct ixp4xx_irq_chunk *chunk = &ixp4xx_irq_chunks[i];
343
344 pr_info("Allocate Linux IRQs %d..%d HW IRQs %d..%d\n",
345 chunk->irq, chunk->irq + chunk->nr_irqs - 1,
346 chunk->hwirq, chunk->hwirq + chunk->nr_irqs - 1);
347 fwspec.fwnode = fwnode;
348 fwspec.param[0] = chunk->hwirq;
349 fwspec.param[1] = IRQ_TYPE_LEVEL_HIGH;
350 fwspec.param_count = 2;
351 ret = __irq_domain_alloc_irqs(ixi->domain,
352 chunk->irq,
353 chunk->nr_irqs,
354 NUMA_NO_NODE,
355 &fwspec,
356 false,
357 NULL);
358 if (ret < 0) {
359 pr_crit("IXP4XX: can not allocate irqs in hierarchy %d\n",
360 ret);
361 return;
362 }
363 }
364}
365EXPORT_SYMBOL_GPL(ixp4xx_irq_init);
366
367#ifdef CONFIG_OF
368int __init ixp4xx_of_init_irq(struct device_node *np,
369 struct device_node *parent)
370{
371 struct ixp4xx_irq *ixi = &ixirq;
372 void __iomem *base;
373 struct fwnode_handle *fwnode;
374 bool is_356;
375 int ret;
376
377 base = of_iomap(np, 0);
378 if (!base) {
379 pr_crit("IXP4XX: could not ioremap interrupt controller\n");
380 return -ENODEV;
381 }

--- 13 unchanged lines hidden (view full) ---

395IRQCHIP_DECLARE(ixp42x, "intel,ixp42x-interrupt",
396 ixp4xx_of_init_irq);
397IRQCHIP_DECLARE(ixp43x, "intel,ixp43x-interrupt",
398 ixp4xx_of_init_irq);
399IRQCHIP_DECLARE(ixp45x, "intel,ixp45x-interrupt",
400 ixp4xx_of_init_irq);
401IRQCHIP_DECLARE(ixp46x, "intel,ixp46x-interrupt",
402 ixp4xx_of_init_irq);
257 bool is_356;
258 int ret;
259
260 base = of_iomap(np, 0);
261 if (!base) {
262 pr_crit("IXP4XX: could not ioremap interrupt controller\n");
263 return -ENODEV;
264 }

--- 13 unchanged lines hidden (view full) ---

278IRQCHIP_DECLARE(ixp42x, "intel,ixp42x-interrupt",
279 ixp4xx_of_init_irq);
280IRQCHIP_DECLARE(ixp43x, "intel,ixp43x-interrupt",
281 ixp4xx_of_init_irq);
282IRQCHIP_DECLARE(ixp45x, "intel,ixp45x-interrupt",
283 ixp4xx_of_init_irq);
284IRQCHIP_DECLARE(ixp46x, "intel,ixp46x-interrupt",
285 ixp4xx_of_init_irq);
403#endif