aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-exynos/common.c
diff options
context:
space:
mode:
authorThomas Abraham <thomas.abraham@linaro.org>2012-05-15 03:25:23 -0400
committerKukjin Kim <kgene.kim@samsung.com>2012-05-15 18:03:44 -0400
commite873a47c4ef3fbb2e439a6b674e73b0c40dd8248 (patch)
tree245b58e5d007f998ca6e9be39d25bec80818c12f /arch/arm/mach-exynos/common.c
parent1e60bc0b5f488c8acde22adeb62118ccfdb49062 (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/arm/mach-exynos/common.c')
-rw-r--r--arch/arm/mach-exynos/common.c71
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
495static 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
513static 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
493static int combiner_irq_domain_map(struct irq_domain *d, unsigned int irq, 523static 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
503static struct irq_domain_ops combiner_irq_domain_ops = { 533static 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
507void __init combiner_init(void __iomem *combiner_base, struct device_node *np) 538void __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
577int __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
536static const struct of_device_id exynos4_dt_irq_match[] = { 592static 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