diff options
author | Thomas Abraham <thomas.abraham@linaro.org> | 2012-05-15 03:25:23 -0400 |
---|---|---|
committer | Kukjin Kim <kgene.kim@samsung.com> | 2012-05-15 18:03:44 -0400 |
commit | e873a47c4ef3fbb2e439a6b674e73b0c40dd8248 (patch) | |
tree | 245b58e5d007f998ca6e9be39d25bec80818c12f /arch | |
parent | 1e60bc0b5f488c8acde22adeb62118ccfdb49062 (diff) |
ARM: EXYNOS: Add device tree support for interrupt combiner
Add device tree based instantiation of the interrupt combiner controller.
Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
Acked-by: Rob Herring <rob.herring@calxeda.com>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/mach-exynos/common.c | 71 |
1 files changed, 64 insertions, 7 deletions
diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c index a688c17bc869..9900158f026a 100644 --- a/arch/arm/mach-exynos/common.c +++ b/arch/arm/mach-exynos/common.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/of_irq.h> | 21 | #include <linux/of_irq.h> |
22 | #include <linux/export.h> | 22 | #include <linux/export.h> |
23 | #include <linux/irqdomain.h> | 23 | #include <linux/irqdomain.h> |
24 | #include <linux/of_address.h> | ||
24 | 25 | ||
25 | #include <asm/proc-fns.h> | 26 | #include <asm/proc-fns.h> |
26 | #include <asm/exception.h> | 27 | #include <asm/exception.h> |
@@ -490,6 +491,35 @@ static void __init combiner_init_one(unsigned int combiner_nr, | |||
490 | base + COMBINER_ENABLE_CLEAR); | 491 | base + COMBINER_ENABLE_CLEAR); |
491 | } | 492 | } |
492 | 493 | ||
494 | #ifdef CONFIG_OF | ||
495 | static int combiner_irq_domain_xlate(struct irq_domain *d, | ||
496 | struct device_node *controller, | ||
497 | const u32 *intspec, unsigned int intsize, | ||
498 | unsigned long *out_hwirq, | ||
499 | unsigned int *out_type) | ||
500 | { | ||
501 | if (d->of_node != controller) | ||
502 | return -EINVAL; | ||
503 | |||
504 | if (intsize < 2) | ||
505 | return -EINVAL; | ||
506 | |||
507 | *out_hwirq = intspec[0] * MAX_IRQ_IN_COMBINER + intspec[1]; | ||
508 | *out_type = 0; | ||
509 | |||
510 | return 0; | ||
511 | } | ||
512 | #else | ||
513 | static int combiner_irq_domain_xlate(struct irq_domain *d, | ||
514 | struct device_node *controller, | ||
515 | const u32 *intspec, unsigned int intsize, | ||
516 | unsigned long *out_hwirq, | ||
517 | unsigned int *out_type) | ||
518 | { | ||
519 | return -EINVAL; | ||
520 | } | ||
521 | #endif | ||
522 | |||
493 | static int combiner_irq_domain_map(struct irq_domain *d, unsigned int irq, | 523 | static int combiner_irq_domain_map(struct irq_domain *d, unsigned int irq, |
494 | irq_hw_number_t hw) | 524 | irq_hw_number_t hw) |
495 | { | 525 | { |
@@ -501,16 +531,26 @@ static int combiner_irq_domain_map(struct irq_domain *d, unsigned int irq, | |||
501 | } | 531 | } |
502 | 532 | ||
503 | static struct irq_domain_ops combiner_irq_domain_ops = { | 533 | static struct irq_domain_ops combiner_irq_domain_ops = { |
534 | .xlate = combiner_irq_domain_xlate, | ||
504 | .map = combiner_irq_domain_map, | 535 | .map = combiner_irq_domain_map, |
505 | }; | 536 | }; |
506 | 537 | ||
507 | void __init combiner_init(void __iomem *combiner_base, struct device_node *np) | 538 | void __init combiner_init(void __iomem *combiner_base, struct device_node *np) |
508 | { | 539 | { |
509 | int i, irq_base; | 540 | int i, irq, irq_base; |
510 | unsigned int max_nr, nr_irq; | 541 | unsigned int max_nr, nr_irq; |
511 | 542 | ||
512 | max_nr = soc_is_exynos5250() ? EXYNOS5_MAX_COMBINER_NR : | 543 | if (np) { |
513 | EXYNOS4_MAX_COMBINER_NR; | 544 | if (of_property_read_u32(np, "samsung,combiner-nr", &max_nr)) { |
545 | pr_warning("%s: number of combiners not specified, " | ||
546 | "setting default as %d.\n", | ||
547 | __func__, EXYNOS4_MAX_COMBINER_NR); | ||
548 | max_nr = EXYNOS4_MAX_COMBINER_NR; | ||
549 | } | ||
550 | } else { | ||
551 | max_nr = soc_is_exynos5250() ? EXYNOS5_MAX_COMBINER_NR : | ||
552 | EXYNOS4_MAX_COMBINER_NR; | ||
553 | } | ||
514 | nr_irq = max_nr * MAX_IRQ_IN_COMBINER; | 554 | nr_irq = max_nr * MAX_IRQ_IN_COMBINER; |
515 | 555 | ||
516 | irq_base = irq_alloc_descs(COMBINER_IRQ(0, 0), 1, nr_irq, 0); | 556 | irq_base = irq_alloc_descs(COMBINER_IRQ(0, 0), 1, nr_irq, 0); |
@@ -528,13 +568,31 @@ void __init combiner_init(void __iomem *combiner_base, struct device_node *np) | |||
528 | 568 | ||
529 | for (i = 0; i < max_nr; i++) { | 569 | for (i = 0; i < max_nr; i++) { |
530 | combiner_init_one(i, combiner_base + (i >> 2) * 0x10); | 570 | combiner_init_one(i, combiner_base + (i >> 2) * 0x10); |
531 | combiner_cascade_irq(i, IRQ_SPI(i)); | 571 | irq = np ? irq_of_parse_and_map(np, i) : IRQ_SPI(i); |
572 | combiner_cascade_irq(i, irq); | ||
532 | } | 573 | } |
533 | } | 574 | } |
534 | 575 | ||
535 | #ifdef CONFIG_OF | 576 | #ifdef CONFIG_OF |
577 | int __init combiner_of_init(struct device_node *np, struct device_node *parent) | ||
578 | { | ||
579 | void __iomem *combiner_base; | ||
580 | |||
581 | combiner_base = of_iomap(np, 0); | ||
582 | if (!combiner_base) { | ||
583 | pr_err("%s: failed to map combiner registers\n", __func__); | ||
584 | return -ENXIO; | ||
585 | } | ||
586 | |||
587 | combiner_init(combiner_base, np); | ||
588 | |||
589 | return 0; | ||
590 | } | ||
591 | |||
536 | static const struct of_device_id exynos4_dt_irq_match[] = { | 592 | static const struct of_device_id exynos4_dt_irq_match[] = { |
537 | { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, }, | 593 | { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, }, |
594 | { .compatible = "samsung,exynos4210-combiner", | ||
595 | .data = combiner_of_init, }, | ||
538 | {}, | 596 | {}, |
539 | }; | 597 | }; |
540 | #endif | 598 | #endif |
@@ -552,7 +610,8 @@ void __init exynos4_init_irq(void) | |||
552 | of_irq_init(exynos4_dt_irq_match); | 610 | of_irq_init(exynos4_dt_irq_match); |
553 | #endif | 611 | #endif |
554 | 612 | ||
555 | combiner_init(S5P_VA_COMBINER_BASE, NULL); | 613 | if (!of_have_populated_dt()) |
614 | combiner_init(S5P_VA_COMBINER_BASE, NULL); | ||
556 | 615 | ||
557 | /* | 616 | /* |
558 | * The parameters of s5p_init_irq() are for VIC init. | 617 | * The parameters of s5p_init_irq() are for VIC init. |
@@ -567,8 +626,6 @@ void __init exynos5_init_irq(void) | |||
567 | #ifdef CONFIG_OF | 626 | #ifdef CONFIG_OF |
568 | of_irq_init(exynos4_dt_irq_match); | 627 | of_irq_init(exynos4_dt_irq_match); |
569 | #endif | 628 | #endif |
570 | combiner_init(S5P_VA_COMBINER_BASE, NULL); | ||
571 | |||
572 | /* | 629 | /* |
573 | * The parameters of s5p_init_irq() are for VIC init. | 630 | * The parameters of s5p_init_irq() are for VIC init. |
574 | * Theses parameters should be NULL and 0 because EXYNOS4 | 631 | * Theses parameters should be NULL and 0 because EXYNOS4 |