aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/arm/samsung/interrupt-combiner.txt52
-rw-r--r--arch/arm/mach-exynos/common.c71
2 files changed, 116 insertions, 7 deletions
diff --git a/Documentation/devicetree/bindings/arm/samsung/interrupt-combiner.txt b/Documentation/devicetree/bindings/arm/samsung/interrupt-combiner.txt
new file mode 100644
index 000000000000..f2f2171e530e
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/samsung/interrupt-combiner.txt
@@ -0,0 +1,52 @@
1* Samsung Exynos Interrupt Combiner Controller
2
3Samsung's Exynos4 architecture includes a interrupt combiner controller which
4can combine interrupt sources as a group and provide a single interrupt request
5for the group. The interrupt request from each group are connected to a parent
6interrupt controller, such as GIC in case of Exynos4210.
7
8The interrupt combiner controller consists of multiple combiners. Upto eight
9interrupt sources can be connected to a combiner. The combiner outputs one
10combined interrupt for its eight interrupt sources. The combined interrupt
11is usually connected to a parent interrupt controller.
12
13A single node in the device tree is used to describe the interrupt combiner
14controller module (which includes multiple combiners). A combiner in the
15interrupt controller module shares config/control registers with other
16combiners. For example, a 32-bit interrupt enable/disable config register
17can accommodate upto 4 interrupt combiners (with each combiner supporting
18upto 8 interrupt sources).
19
20Required properties:
21- compatible: should be "samsung,exynos4210-combiner".
22- interrupt-controller: Identifies the node as an interrupt controller.
23- #interrupt-cells: should be <2>. The meaning of the cells are
24 * First Cell: Combiner Group Number.
25 * Second Cell: Interrupt number within the group.
26- reg: Base address and size of interrupt combiner registers.
27- interrupts: The list of interrupts generated by the combiners which are then
28 connected to a parent interrupt controller. The format of the interrupt
29 specifier depends in the interrupt parent controller.
30
31Optional properties:
32- samsung,combiner-nr: The number of interrupt combiners supported. If this
33 property is not specified, the default number of combiners is assumed
34 to be 16.
35- interrupt-parent: pHandle of the parent interrupt controller, if not
36 inherited from the parent node.
37
38
39Example:
40
41 The following is a an example from the Exynos4210 SoC dtsi file.
42
43 combiner:interrupt-controller@10440000 {
44 compatible = "samsung,exynos4210-combiner";
45 interrupt-controller;
46 #interrupt-cells = <2>;
47 reg = <0x10440000 0x1000>;
48 interrupts = <0 0 0>, <0 1 0>, <0 2 0>, <0 3 0>,
49 <0 4 0>, <0 5 0>, <0 6 0>, <0 7 0>,
50 <0 8 0>, <0 9 0>, <0 10 0>, <0 11 0>,
51 <0 12 0>, <0 13 0>, <0 14 0>, <0 15 0>;
52 };
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