diff options
author | Haojian Zhuang <haojian.zhuang@gmail.com> | 2013-04-21 04:53:02 -0400 |
---|---|---|
committer | Haojian Zhuang <haojian.zhuang@gmail.com> | 2013-08-24 05:42:09 -0400 |
commit | 0f374561b50df8f29e3427717b35dd57c7ac4ca4 (patch) | |
tree | d5b5275b3c77e80d6c9c01aacc8fb47e06e33489 | |
parent | c052d13c08b793a13cf0158feca324417bf9ca4b (diff) |
irqchip: mmp: support irqchip
Support IRQCHIP & CONFIG_MULTI_IRQ_HANDLER in irq-mmp driver.
Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
Reviewed-by: Daniel Drake <dsd@laptop.org>
-rw-r--r-- | arch/arm/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm/mach-mmp/include/mach/entry-macro.S | 26 | ||||
-rw-r--r-- | arch/arm/mach-mmp/mmp-dt.c | 8 | ||||
-rw-r--r-- | arch/arm/mach-mmp/mmp2-dt.c | 8 | ||||
-rw-r--r-- | drivers/irqchip/irq-mmp.c | 280 |
5 files changed, 168 insertions, 155 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index ba412e02ec0c..76793a633bee 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -557,6 +557,7 @@ config ARCH_MMP | |||
557 | select GENERIC_CLOCKEVENTS | 557 | select GENERIC_CLOCKEVENTS |
558 | select GPIO_PXA | 558 | select GPIO_PXA |
559 | select IRQ_DOMAIN | 559 | select IRQ_DOMAIN |
560 | select MULTI_IRQ_HANDLER | ||
560 | select NEED_MACH_GPIO_H | 561 | select NEED_MACH_GPIO_H |
561 | select PINCTRL | 562 | select PINCTRL |
562 | select PLAT_PXA | 563 | select PLAT_PXA |
diff --git a/arch/arm/mach-mmp/include/mach/entry-macro.S b/arch/arm/mach-mmp/include/mach/entry-macro.S deleted file mode 100644 index bd152e24e6d7..000000000000 --- a/arch/arm/mach-mmp/include/mach/entry-macro.S +++ /dev/null | |||
@@ -1,26 +0,0 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-mmp/include/mach/entry-macro.S | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <asm/irq.h> | ||
10 | #include <mach/regs-icu.h> | ||
11 | |||
12 | .macro get_irqnr_preamble, base, tmp | ||
13 | mrc p15, 0, \tmp, c0, c0, 0 @ CPUID | ||
14 | and \tmp, \tmp, #0xff00 | ||
15 | cmp \tmp, #0x5800 | ||
16 | ldr \base, =mmp_icu_base | ||
17 | ldr \base, [\base, #0] | ||
18 | addne \base, \base, #0x10c @ PJ1 AP INT SEL register | ||
19 | addeq \base, \base, #0x104 @ PJ4 IRQ SEL register | ||
20 | .endm | ||
21 | |||
22 | .macro get_irqnr_and_base, irqnr, irqstat, base, tmp | ||
23 | ldr \tmp, [\base, #0] | ||
24 | and \irqnr, \tmp, #0x3f | ||
25 | tst \tmp, #(1 << 6) | ||
26 | .endm | ||
diff --git a/arch/arm/mach-mmp/mmp-dt.c b/arch/arm/mach-mmp/mmp-dt.c index b37915dc4470..cca529ceecb7 100644 --- a/arch/arm/mach-mmp/mmp-dt.c +++ b/arch/arm/mach-mmp/mmp-dt.c | |||
@@ -9,17 +9,13 @@ | |||
9 | * publishhed by the Free Software Foundation. | 9 | * publishhed by the Free Software Foundation. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/irq.h> | 12 | #include <linux/irqchip.h> |
13 | #include <linux/irqdomain.h> | ||
14 | #include <linux/of_irq.h> | ||
15 | #include <linux/of_platform.h> | 13 | #include <linux/of_platform.h> |
16 | #include <asm/mach/arch.h> | 14 | #include <asm/mach/arch.h> |
17 | #include <asm/mach/time.h> | 15 | #include <asm/mach/time.h> |
18 | #include <mach/irqs.h> | ||
19 | 16 | ||
20 | #include "common.h" | 17 | #include "common.h" |
21 | 18 | ||
22 | extern void __init mmp_dt_irq_init(void); | ||
23 | extern void __init mmp_dt_init_timer(void); | 19 | extern void __init mmp_dt_init_timer(void); |
24 | 20 | ||
25 | static const struct of_dev_auxdata pxa168_auxdata_lookup[] __initconst = { | 21 | static const struct of_dev_auxdata pxa168_auxdata_lookup[] __initconst = { |
@@ -64,7 +60,6 @@ static const char *mmp_dt_board_compat[] __initdata = { | |||
64 | 60 | ||
65 | DT_MACHINE_START(PXA168_DT, "Marvell PXA168 (Device Tree Support)") | 61 | DT_MACHINE_START(PXA168_DT, "Marvell PXA168 (Device Tree Support)") |
66 | .map_io = mmp_map_io, | 62 | .map_io = mmp_map_io, |
67 | .init_irq = mmp_dt_irq_init, | ||
68 | .init_time = mmp_dt_init_timer, | 63 | .init_time = mmp_dt_init_timer, |
69 | .init_machine = pxa168_dt_init, | 64 | .init_machine = pxa168_dt_init, |
70 | .dt_compat = mmp_dt_board_compat, | 65 | .dt_compat = mmp_dt_board_compat, |
@@ -72,7 +67,6 @@ MACHINE_END | |||
72 | 67 | ||
73 | DT_MACHINE_START(PXA910_DT, "Marvell PXA910 (Device Tree Support)") | 68 | DT_MACHINE_START(PXA910_DT, "Marvell PXA910 (Device Tree Support)") |
74 | .map_io = mmp_map_io, | 69 | .map_io = mmp_map_io, |
75 | .init_irq = mmp_dt_irq_init, | ||
76 | .init_time = mmp_dt_init_timer, | 70 | .init_time = mmp_dt_init_timer, |
77 | .init_machine = pxa910_dt_init, | 71 | .init_machine = pxa910_dt_init, |
78 | .dt_compat = mmp_dt_board_compat, | 72 | .dt_compat = mmp_dt_board_compat, |
diff --git a/arch/arm/mach-mmp/mmp2-dt.c b/arch/arm/mach-mmp/mmp2-dt.c index 4ac256720f7d..023cb453f157 100644 --- a/arch/arm/mach-mmp/mmp2-dt.c +++ b/arch/arm/mach-mmp/mmp2-dt.c | |||
@@ -10,18 +10,13 @@ | |||
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/io.h> | 12 | #include <linux/io.h> |
13 | #include <linux/irq.h> | 13 | #include <linux/irqchip.h> |
14 | #include <linux/irqdomain.h> | ||
15 | #include <linux/of_irq.h> | ||
16 | #include <linux/of_platform.h> | 14 | #include <linux/of_platform.h> |
17 | #include <asm/mach/arch.h> | 15 | #include <asm/mach/arch.h> |
18 | #include <asm/mach/time.h> | 16 | #include <asm/mach/time.h> |
19 | #include <mach/irqs.h> | ||
20 | #include <mach/regs-apbc.h> | ||
21 | 17 | ||
22 | #include "common.h" | 18 | #include "common.h" |
23 | 19 | ||
24 | extern void __init mmp_dt_irq_init(void); | ||
25 | extern void __init mmp_dt_init_timer(void); | 20 | extern void __init mmp_dt_init_timer(void); |
26 | 21 | ||
27 | static const struct of_dev_auxdata mmp2_auxdata_lookup[] __initconst = { | 22 | static const struct of_dev_auxdata mmp2_auxdata_lookup[] __initconst = { |
@@ -49,7 +44,6 @@ static const char *mmp2_dt_board_compat[] __initdata = { | |||
49 | 44 | ||
50 | DT_MACHINE_START(MMP2_DT, "Marvell MMP2 (Device Tree Support)") | 45 | DT_MACHINE_START(MMP2_DT, "Marvell MMP2 (Device Tree Support)") |
51 | .map_io = mmp_map_io, | 46 | .map_io = mmp_map_io, |
52 | .init_irq = mmp_dt_irq_init, | ||
53 | .init_time = mmp_dt_init_timer, | 47 | .init_time = mmp_dt_init_timer, |
54 | .init_machine = mmp2_dt_init, | 48 | .init_machine = mmp2_dt_init, |
55 | .dt_compat = mmp2_dt_board_compat, | 49 | .dt_compat = mmp2_dt_board_compat, |
diff --git a/drivers/irqchip/irq-mmp.c b/drivers/irqchip/irq-mmp.c index dab6def93190..84d51ff836ee 100644 --- a/drivers/irqchip/irq-mmp.c +++ b/drivers/irqchip/irq-mmp.c | |||
@@ -21,6 +21,9 @@ | |||
21 | #include <linux/of_address.h> | 21 | #include <linux/of_address.h> |
22 | #include <linux/of_irq.h> | 22 | #include <linux/of_irq.h> |
23 | 23 | ||
24 | #include <asm/exception.h> | ||
25 | #include <asm/mach/irq.h> | ||
26 | |||
24 | #include <mach/irqs.h> | 27 | #include <mach/irqs.h> |
25 | 28 | ||
26 | #ifdef CONFIG_CPU_MMP2 | 29 | #ifdef CONFIG_CPU_MMP2 |
@@ -30,8 +33,17 @@ | |||
30 | #include <mach/pm-pxa910.h> | 33 | #include <mach/pm-pxa910.h> |
31 | #endif | 34 | #endif |
32 | 35 | ||
36 | #include "irqchip.h" | ||
37 | |||
33 | #define MAX_ICU_NR 16 | 38 | #define MAX_ICU_NR 16 |
34 | 39 | ||
40 | #define PJ1_INT_SEL 0x10c | ||
41 | #define PJ4_INT_SEL 0x104 | ||
42 | |||
43 | /* bit fields in PJ1_INT_SEL and PJ4_INT_SEL */ | ||
44 | #define SEL_INT_PENDING (1 << 6) | ||
45 | #define SEL_INT_NUM_MASK 0x3f | ||
46 | |||
35 | struct icu_chip_data { | 47 | struct icu_chip_data { |
36 | int nr_irqs; | 48 | int nr_irqs; |
37 | unsigned int virq_base; | 49 | unsigned int virq_base; |
@@ -52,7 +64,7 @@ struct mmp_intc_conf { | |||
52 | unsigned int conf_mask; | 64 | unsigned int conf_mask; |
53 | }; | 65 | }; |
54 | 66 | ||
55 | void __iomem *mmp_icu_base; | 67 | static void __iomem *mmp_icu_base; |
56 | static struct icu_chip_data icu_data[MAX_ICU_NR]; | 68 | static struct icu_chip_data icu_data[MAX_ICU_NR]; |
57 | static int max_icu_nr; | 69 | static int max_icu_nr; |
58 | 70 | ||
@@ -191,6 +203,32 @@ static struct mmp_intc_conf mmp2_conf = { | |||
191 | .conf_mask = 0x7f, | 203 | .conf_mask = 0x7f, |
192 | }; | 204 | }; |
193 | 205 | ||
206 | static asmlinkage void __exception_irq_entry | ||
207 | mmp_handle_irq(struct pt_regs *regs) | ||
208 | { | ||
209 | int irq, hwirq; | ||
210 | |||
211 | hwirq = readl_relaxed(mmp_icu_base + PJ1_INT_SEL); | ||
212 | if (!(hwirq & SEL_INT_PENDING)) | ||
213 | return; | ||
214 | hwirq &= SEL_INT_NUM_MASK; | ||
215 | irq = irq_find_mapping(icu_data[0].domain, hwirq); | ||
216 | handle_IRQ(irq, regs); | ||
217 | } | ||
218 | |||
219 | static asmlinkage void __exception_irq_entry | ||
220 | mmp2_handle_irq(struct pt_regs *regs) | ||
221 | { | ||
222 | int irq, hwirq; | ||
223 | |||
224 | hwirq = readl_relaxed(mmp_icu_base + PJ4_INT_SEL); | ||
225 | if (!(hwirq & SEL_INT_PENDING)) | ||
226 | return; | ||
227 | hwirq &= SEL_INT_NUM_MASK; | ||
228 | irq = irq_find_mapping(icu_data[0].domain, hwirq); | ||
229 | handle_IRQ(irq, regs); | ||
230 | } | ||
231 | |||
194 | /* MMP (ARMv5) */ | 232 | /* MMP (ARMv5) */ |
195 | void __init icu_init_irq(void) | 233 | void __init icu_init_irq(void) |
196 | { | 234 | { |
@@ -212,6 +250,7 @@ void __init icu_init_irq(void) | |||
212 | set_irq_flags(irq, IRQF_VALID); | 250 | set_irq_flags(irq, IRQF_VALID); |
213 | } | 251 | } |
214 | irq_set_default_host(icu_data[0].domain); | 252 | irq_set_default_host(icu_data[0].domain); |
253 | set_handle_irq(mmp_handle_irq); | ||
215 | #ifdef CONFIG_CPU_PXA910 | 254 | #ifdef CONFIG_CPU_PXA910 |
216 | icu_irq_chip.irq_set_wake = pxa910_set_wake; | 255 | icu_irq_chip.irq_set_wake = pxa910_set_wake; |
217 | #endif | 256 | #endif |
@@ -318,144 +357,155 @@ void __init mmp2_init_icu(void) | |||
318 | set_irq_flags(irq, IRQF_VALID); | 357 | set_irq_flags(irq, IRQF_VALID); |
319 | } | 358 | } |
320 | irq_set_default_host(icu_data[0].domain); | 359 | irq_set_default_host(icu_data[0].domain); |
360 | set_handle_irq(mmp2_handle_irq); | ||
321 | #ifdef CONFIG_CPU_MMP2 | 361 | #ifdef CONFIG_CPU_MMP2 |
322 | icu_irq_chip.irq_set_wake = mmp2_set_wake; | 362 | icu_irq_chip.irq_set_wake = mmp2_set_wake; |
323 | #endif | 363 | #endif |
324 | } | 364 | } |
325 | 365 | ||
326 | #ifdef CONFIG_OF | 366 | #ifdef CONFIG_OF |
327 | static const struct of_device_id intc_ids[] __initconst = { | 367 | static int __init mmp_init_bases(struct device_node *node) |
328 | { .compatible = "mrvl,mmp-intc", .data = &mmp_conf }, | ||
329 | { .compatible = "mrvl,mmp2-intc", .data = &mmp2_conf }, | ||
330 | {} | ||
331 | }; | ||
332 | |||
333 | static const struct of_device_id mmp_mux_irq_match[] __initconst = { | ||
334 | { .compatible = "mrvl,mmp2-mux-intc" }, | ||
335 | {} | ||
336 | }; | ||
337 | |||
338 | int __init mmp2_mux_init(struct device_node *parent) | ||
339 | { | 368 | { |
340 | struct device_node *node; | 369 | int ret, nr_irqs, irq, i = 0; |
341 | const struct of_device_id *of_id; | ||
342 | struct resource res; | ||
343 | int i, irq_base, ret, irq; | ||
344 | u32 nr_irqs, mfp_irq; | ||
345 | 370 | ||
346 | node = parent; | 371 | ret = of_property_read_u32(node, "mrvl,intc-nr-irqs", &nr_irqs); |
347 | max_icu_nr = 1; | 372 | if (ret) { |
348 | for (i = 1; i < MAX_ICU_NR; i++) { | 373 | pr_err("Not found mrvl,intc-nr-irqs property\n"); |
349 | node = of_find_matching_node(node, mmp_mux_irq_match); | 374 | return ret; |
350 | if (!node) | 375 | } |
351 | break; | ||
352 | of_id = of_match_node(&mmp_mux_irq_match[0], node); | ||
353 | ret = of_property_read_u32(node, "mrvl,intc-nr-irqs", | ||
354 | &nr_irqs); | ||
355 | if (ret) { | ||
356 | pr_err("Not found mrvl,intc-nr-irqs property\n"); | ||
357 | ret = -EINVAL; | ||
358 | goto err; | ||
359 | } | ||
360 | ret = of_address_to_resource(node, 0, &res); | ||
361 | if (ret < 0) { | ||
362 | pr_err("Not found reg property\n"); | ||
363 | ret = -EINVAL; | ||
364 | goto err; | ||
365 | } | ||
366 | icu_data[i].reg_status = mmp_icu_base + res.start; | ||
367 | ret = of_address_to_resource(node, 1, &res); | ||
368 | if (ret < 0) { | ||
369 | pr_err("Not found reg property\n"); | ||
370 | ret = -EINVAL; | ||
371 | goto err; | ||
372 | } | ||
373 | icu_data[i].reg_mask = mmp_icu_base + res.start; | ||
374 | icu_data[i].cascade_irq = irq_of_parse_and_map(node, 0); | ||
375 | if (!icu_data[i].cascade_irq) { | ||
376 | ret = -EINVAL; | ||
377 | goto err; | ||
378 | } | ||
379 | 376 | ||
380 | irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0); | 377 | mmp_icu_base = of_iomap(node, 0); |
381 | if (irq_base < 0) { | 378 | if (!mmp_icu_base) { |
382 | pr_err("Failed to allocate IRQ numbers for mux intc\n"); | 379 | pr_err("Failed to get interrupt controller register\n"); |
383 | ret = irq_base; | 380 | return -ENOMEM; |
381 | } | ||
382 | |||
383 | icu_data[0].virq_base = 0; | ||
384 | icu_data[0].domain = irq_domain_add_linear(node, nr_irqs, | ||
385 | &mmp_irq_domain_ops, | ||
386 | &icu_data[0]); | ||
387 | for (irq = 0; irq < nr_irqs; irq++) { | ||
388 | ret = irq_create_mapping(icu_data[0].domain, irq); | ||
389 | if (!ret) { | ||
390 | pr_err("Failed to mapping hwirq\n"); | ||
384 | goto err; | 391 | goto err; |
385 | } | 392 | } |
386 | if (!of_property_read_u32(node, "mrvl,clr-mfp-irq", | 393 | if (!irq) |
387 | &mfp_irq)) { | 394 | icu_data[0].virq_base = ret; |
388 | icu_data[i].clr_mfp_irq_base = irq_base; | ||
389 | icu_data[i].clr_mfp_hwirq = mfp_irq; | ||
390 | } | ||
391 | irq_set_chained_handler(icu_data[i].cascade_irq, | ||
392 | icu_mux_irq_demux); | ||
393 | icu_data[i].nr_irqs = nr_irqs; | ||
394 | icu_data[i].virq_base = irq_base; | ||
395 | icu_data[i].domain = irq_domain_add_legacy(node, nr_irqs, | ||
396 | irq_base, 0, | ||
397 | &mmp_irq_domain_ops, | ||
398 | &icu_data[i]); | ||
399 | for (irq = irq_base; irq < irq_base + nr_irqs; irq++) | ||
400 | icu_mask_irq(irq_get_irq_data(irq)); | ||
401 | } | 395 | } |
402 | max_icu_nr = i; | 396 | icu_data[0].nr_irqs = nr_irqs; |
403 | return 0; | 397 | return 0; |
404 | err: | 398 | err: |
405 | of_node_put(node); | 399 | if (icu_data[0].virq_base) { |
406 | max_icu_nr = i; | 400 | for (i = 0; i < irq; i++) |
407 | return ret; | 401 | irq_dispose_mapping(icu_data[0].virq_base + i); |
402 | } | ||
403 | irq_domain_remove(icu_data[0].domain); | ||
404 | iounmap(mmp_icu_base); | ||
405 | return -EINVAL; | ||
408 | } | 406 | } |
409 | 407 | ||
410 | void __init mmp_dt_irq_init(void) | 408 | static int __init mmp_of_init(struct device_node *node, |
409 | struct device_node *parent) | ||
411 | { | 410 | { |
412 | struct device_node *node; | 411 | int ret; |
413 | const struct of_device_id *of_id; | ||
414 | struct mmp_intc_conf *conf; | ||
415 | int nr_irqs, irq_base, ret, irq; | ||
416 | |||
417 | node = of_find_matching_node(NULL, intc_ids); | ||
418 | if (!node) { | ||
419 | pr_err("Failed to find interrupt controller in arch-mmp\n"); | ||
420 | return; | ||
421 | } | ||
422 | of_id = of_match_node(intc_ids, node); | ||
423 | conf = of_id->data; | ||
424 | 412 | ||
425 | ret = of_property_read_u32(node, "mrvl,intc-nr-irqs", &nr_irqs); | 413 | ret = mmp_init_bases(node); |
414 | if (ret < 0) | ||
415 | return ret; | ||
416 | |||
417 | icu_data[0].conf_enable = mmp_conf.conf_enable; | ||
418 | icu_data[0].conf_disable = mmp_conf.conf_disable; | ||
419 | icu_data[0].conf_mask = mmp_conf.conf_mask; | ||
420 | irq_set_default_host(icu_data[0].domain); | ||
421 | set_handle_irq(mmp_handle_irq); | ||
422 | max_icu_nr = 1; | ||
423 | return 0; | ||
424 | } | ||
425 | IRQCHIP_DECLARE(mmp_intc, "mrvl,mmp-intc", mmp_of_init); | ||
426 | |||
427 | static int __init mmp2_of_init(struct device_node *node, | ||
428 | struct device_node *parent) | ||
429 | { | ||
430 | int ret; | ||
431 | |||
432 | ret = mmp_init_bases(node); | ||
433 | if (ret < 0) | ||
434 | return ret; | ||
435 | |||
436 | icu_data[0].conf_enable = mmp2_conf.conf_enable; | ||
437 | icu_data[0].conf_disable = mmp2_conf.conf_disable; | ||
438 | icu_data[0].conf_mask = mmp2_conf.conf_mask; | ||
439 | irq_set_default_host(icu_data[0].domain); | ||
440 | set_handle_irq(mmp2_handle_irq); | ||
441 | max_icu_nr = 1; | ||
442 | return 0; | ||
443 | } | ||
444 | IRQCHIP_DECLARE(mmp2_intc, "mrvl,mmp2-intc", mmp2_of_init); | ||
445 | |||
446 | static int __init mmp2_mux_of_init(struct device_node *node, | ||
447 | struct device_node *parent) | ||
448 | { | ||
449 | struct resource res; | ||
450 | int i, ret, irq, j = 0; | ||
451 | u32 nr_irqs, mfp_irq; | ||
452 | |||
453 | if (!parent) | ||
454 | return -ENODEV; | ||
455 | |||
456 | i = max_icu_nr; | ||
457 | ret = of_property_read_u32(node, "mrvl,intc-nr-irqs", | ||
458 | &nr_irqs); | ||
426 | if (ret) { | 459 | if (ret) { |
427 | pr_err("Not found mrvl,intc-nr-irqs property\n"); | 460 | pr_err("Not found mrvl,intc-nr-irqs property\n"); |
428 | return; | 461 | return -EINVAL; |
429 | } | 462 | } |
430 | 463 | ret = of_address_to_resource(node, 0, &res); | |
431 | mmp_icu_base = of_iomap(node, 0); | 464 | if (ret < 0) { |
432 | if (!mmp_icu_base) { | 465 | pr_err("Not found reg property\n"); |
433 | pr_err("Failed to get interrupt controller register\n"); | 466 | return -EINVAL; |
434 | return; | ||
435 | } | 467 | } |
436 | 468 | icu_data[i].reg_status = mmp_icu_base + res.start; | |
437 | irq_base = irq_alloc_descs(-1, 0, nr_irqs - NR_IRQS_LEGACY, 0); | 469 | ret = of_address_to_resource(node, 1, &res); |
438 | if (irq_base < 0) { | 470 | if (ret < 0) { |
439 | pr_err("Failed to allocate IRQ numbers\n"); | 471 | pr_err("Not found reg property\n"); |
440 | goto err; | 472 | return -EINVAL; |
441 | } else if (irq_base != NR_IRQS_LEGACY) { | ||
442 | pr_err("ICU's irqbase should be started from 0\n"); | ||
443 | goto err; | ||
444 | } | 473 | } |
445 | icu_data[0].conf_enable = conf->conf_enable; | 474 | icu_data[i].reg_mask = mmp_icu_base + res.start; |
446 | icu_data[0].conf_disable = conf->conf_disable; | 475 | icu_data[i].cascade_irq = irq_of_parse_and_map(node, 0); |
447 | icu_data[0].conf_mask = conf->conf_mask; | 476 | if (!icu_data[i].cascade_irq) |
448 | icu_data[0].nr_irqs = nr_irqs; | 477 | return -EINVAL; |
449 | icu_data[0].virq_base = 0; | 478 | |
450 | icu_data[0].domain = irq_domain_add_legacy(node, nr_irqs, 0, 0, | 479 | icu_data[i].virq_base = 0; |
480 | icu_data[i].domain = irq_domain_add_linear(node, nr_irqs, | ||
451 | &mmp_irq_domain_ops, | 481 | &mmp_irq_domain_ops, |
452 | &icu_data[0]); | 482 | &icu_data[i]); |
453 | irq_set_default_host(icu_data[0].domain); | 483 | for (irq = 0; irq < nr_irqs; irq++) { |
454 | for (irq = 0; irq < nr_irqs; irq++) | 484 | ret = irq_create_mapping(icu_data[i].domain, irq); |
455 | icu_mask_irq(irq_get_irq_data(irq)); | 485 | if (!ret) { |
456 | mmp2_mux_init(node); | 486 | pr_err("Failed to mapping hwirq\n"); |
457 | return; | 487 | goto err; |
488 | } | ||
489 | if (!irq) | ||
490 | icu_data[i].virq_base = ret; | ||
491 | } | ||
492 | icu_data[i].nr_irqs = nr_irqs; | ||
493 | if (!of_property_read_u32(node, "mrvl,clr-mfp-irq", | ||
494 | &mfp_irq)) { | ||
495 | icu_data[i].clr_mfp_irq_base = icu_data[i].virq_base; | ||
496 | icu_data[i].clr_mfp_hwirq = mfp_irq; | ||
497 | } | ||
498 | irq_set_chained_handler(icu_data[i].cascade_irq, | ||
499 | icu_mux_irq_demux); | ||
500 | max_icu_nr++; | ||
501 | return 0; | ||
458 | err: | 502 | err: |
459 | iounmap(mmp_icu_base); | 503 | if (icu_data[i].virq_base) { |
504 | for (j = 0; j < irq; j++) | ||
505 | irq_dispose_mapping(icu_data[i].virq_base + j); | ||
506 | } | ||
507 | irq_domain_remove(icu_data[i].domain); | ||
508 | return -EINVAL; | ||
460 | } | 509 | } |
510 | IRQCHIP_DECLARE(mmp2_mux_intc, "mrvl,mmp2-mux-intc", mmp2_mux_of_init); | ||
461 | #endif | 511 | #endif |