linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] ARM: Exynos: Add irq domain and device tree support for interrupt combiner
@ 2012-01-12  7:32 Thomas Abraham
  0 siblings, 0 replies; 4+ messages in thread
From: Thomas Abraham @ 2012-01-12  7:32 UTC (permalink / raw)
  To: linux-arm-kernel

A common irq domain for the interrupts managed by the interrupt combiners is
setup. All the instances of irq combiner reference the common irq domain for
translating hardware interrupts to linux irq number.

In case of device tree based boot, a interrupt specifier translator is setup
that can translate interrupt specifiers for device nodes which use combiner
as their interrupt parent.

Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
---
Changes since v1:
- Includes all changes suggested by Rob Herring.
- Tested with SPARSE_IRQ enabled.

 .../bindings/arm/samsung/interrupt-combiner.txt    |   27 +++++++++
 arch/arm/mach-exynos/cpu.c                         |   29 ++++++---
 arch/arm/mach-exynos/irq-combiner.c                |   62 +++++++++++++++++---
 3 files changed, 100 insertions(+), 18 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/samsung/interrupt-combiner.txt

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 0000000..dbc474b
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/samsung/interrupt-combiner.txt
@@ -0,0 +1,27 @@
+* Samsung Exynos Interrupt Combiner Controller
+
+Samsung's Exynos4 architecture includes a interrupt combiner which can combine
+interrupt sources as a group and provide a single interrupt request for the
+group. The interrupt request from each group are connected to a parent interrupt
+controller, such as GIC in case of Exynos4210.
+
+Required properties:
+- compatible: should be "samsung,exynos4210-combiner".
+- #interrupt-cells: should be <2>. The meaning of the cells are
+	* First Cell: Combiner Group Number.
+	* Second Cell: Interrupt number within the group.
+- reg: Base address and size of interrupt combiner registers.
+- interrupt-controller: Identifies the node as an interrupt controller.
+
+Optional properties:
+- interrupt-parent: pHandle of the parent interrupt controller, if not
+  inherited from the parent node.
+
+Example:
+
+	combiner:interrupt-controller at 10440000 {
+		compatible = "samsung,exynos4120-combiner";
+		#interrupt-cells = <2>;
+		interrupt-controller;
+		reg = <0x10440000 0x1000>;
+	};
diff --git a/arch/arm/mach-exynos/cpu.c b/arch/arm/mach-exynos/cpu.c
index 4c5001f..063e86c 100644
--- a/arch/arm/mach-exynos/cpu.c
+++ b/arch/arm/mach-exynos/cpu.c
@@ -38,9 +38,10 @@
 
 unsigned int gic_bank_offset __read_mostly;
 
-extern int combiner_init(unsigned int combiner_nr, void __iomem *base,
-			 unsigned int irq_start);
+extern int combiner_init(unsigned int combiner_nr, void __iomem *base);
 extern void combiner_cascade_irq(unsigned int combiner_nr, unsigned int irq);
+extern int combiner_init_irq_domain(int irq_base, unsigned int nr_irq,
+					struct device_node *np);
 
 /* Initial IO mappings */
 static struct map_desc exynos_iodesc[] __initdata = {
@@ -223,16 +224,30 @@ static void exynos4_gic_irq_fix_base(struct irq_data *d)
 			    (gic_bank_offset * smp_processor_id());
 }
 
+void __init combiner_of_init(struct device_node *np, struct device_node *parent)
+{
+	int irq;
+
+	if (combiner_init_irq_domain(COMBINER_IRQ(0, 0), MAX_COMBINER_NR *
+					MAX_IRQ_IN_COMBINER, np))
+		BUG();
+	for (irq = 0; irq < MAX_COMBINER_NR; irq++) {
+		combiner_init(irq, (void __iomem *)S5P_VA_COMBINER(irq));
+		combiner_cascade_irq(irq, IRQ_SPI(irq));
+	}
+}
+
 #ifdef CONFIG_OF
 static const struct of_device_id exynos4_dt_irq_match[] = {
 	{ .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
+	{ .compatible = "samsung,exynos4120-combiner",
+			.data = combiner_of_init, },
 	{},
 };
 #endif
 
 void __init exynos4_init_irq(void)
 {
-	int irq;
 
 	gic_bank_offset = soc_is_exynos4412() ? 0x4000 : 0x8000;
 
@@ -247,12 +262,8 @@ void __init exynos4_init_irq(void)
 	gic_arch_extn.irq_unmask = exynos4_gic_irq_fix_base;
 	gic_arch_extn.irq_mask = exynos4_gic_irq_fix_base;
 
-	for (irq = 0; irq < MAX_COMBINER_NR; irq++) {
-
-		combiner_init(irq, (void __iomem *)S5P_VA_COMBINER(irq),
-				COMBINER_IRQ(irq, 0));
-		combiner_cascade_irq(irq, IRQ_SPI(irq));
-	}
+	if (!of_have_populated_dt())
+		combiner_of_init(NULL, NULL);
 
 	/* The parameters of s5p_init_irq() are for VIC init.
 	 * Theses parameters should be NULL and 0 because EXYNOS4
diff --git a/arch/arm/mach-exynos/irq-combiner.c b/arch/arm/mach-exynos/irq-combiner.c
index 5a2758a..9dca53b 100644
--- a/arch/arm/mach-exynos/irq-combiner.c
+++ b/arch/arm/mach-exynos/irq-combiner.c
@@ -13,6 +13,8 @@
 */
 
 #include <linux/io.h>
+#include <linux/export.h>
+#include <linux/irqdomain.h>
 
 #include <asm/mach/irq.h>
 
@@ -26,8 +28,10 @@ struct combiner_chip_data {
 	unsigned int irq_offset;
 	unsigned int irq_mask;
 	void __iomem *base;
+	struct irq_domain *domain;
 };
 
+static struct irq_domain combiner_irq_domain;
 static struct combiner_chip_data combiner_data[MAX_COMBINER_NR];
 
 static inline void __iomem *combiner_base(struct irq_data *data)
@@ -40,14 +44,14 @@ static inline void __iomem *combiner_base(struct irq_data *data)
 
 static void combiner_mask_irq(struct irq_data *data)
 {
-	u32 mask = 1 << (data->irq % 32);
+	u32 mask = 1 << (data->hwirq % 32);
 
 	__raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_CLEAR);
 }
 
 static void combiner_unmask_irq(struct irq_data *data)
 {
-	u32 mask = 1 << (data->irq % 32);
+	u32 mask = 1 << (data->hwirq % 32);
 
 	__raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_SET);
 }
@@ -96,17 +100,18 @@ void __init combiner_cascade_irq(unsigned int combiner_nr, unsigned int irq)
 	irq_set_chained_handler(irq, combiner_handle_cascade_irq);
 }
 
-void __init combiner_init(unsigned int combiner_nr, void __iomem *base,
-			  unsigned int irq_start)
+void __init combiner_init(unsigned int combiner_nr, void __iomem *base)
 {
-	unsigned int i;
+	unsigned int i, hwirq;
 
 	if (combiner_nr >= MAX_COMBINER_NR)
 		BUG();
 
 	combiner_data[combiner_nr].base = base;
-	combiner_data[combiner_nr].irq_offset = irq_start;
+	combiner_data[combiner_nr].irq_offset =	irq_domain_to_irq(
+		&combiner_irq_domain, combiner_nr * MAX_IRQ_IN_COMBINER);
 	combiner_data[combiner_nr].irq_mask = 0xff << ((combiner_nr % 4) << 3);
+	combiner_data[combiner_nr].domain = &combiner_irq_domain;
 
 	/* Disable all interrupts */
 
@@ -114,11 +119,50 @@ void __init combiner_init(unsigned int combiner_nr, void __iomem *base,
 		     base + COMBINER_ENABLE_CLEAR);
 
 	/* Setup the Linux IRQ subsystem */
-
-	for (i = irq_start; i < combiner_data[combiner_nr].irq_offset
-				+ MAX_IRQ_IN_COMBINER; i++) {
+	for (hwirq = 0; hwirq < MAX_IRQ_IN_COMBINER; hwirq++) {
+		i = combiner_data[combiner_nr].irq_offset + hwirq;
 		irq_set_chip_and_handler(i, &combiner_chip, handle_level_irq);
 		irq_set_chip_data(i, &combiner_data[combiner_nr]);
 		set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
 	}
 }
+
+#ifdef CONFIG_OF
+static int combiner_dt_translate(struct irq_domain *d,
+		struct device_node *controller, const u32 *intspec,
+		unsigned int intsize, unsigned long *out_hwirq,
+		unsigned int *out_type)
+{
+	if (d->of_node != controller)
+		return -EINVAL;
+	if (intsize < 2)
+		return -EINVAL;
+
+	*out_hwirq = intspec[0] * MAX_IRQ_IN_COMBINER + intspec[1];
+	*out_type = 0;
+	return 0;
+}
+#endif
+
+static struct irq_domain_ops combiner_irq_domain_ops = {
+#ifdef CONFIG_OF
+	.dt_translate = combiner_dt_translate,
+#endif
+};
+
+int __init combiner_init_irq_domain(int irq_base, unsigned int nr_irq,
+					struct device_node *np)
+{
+	struct irq_domain *domain = &combiner_irq_domain;
+
+	domain->irq_base = irq_alloc_descs(irq_base, 1, nr_irq, 0);
+	if (domain->irq_base < 0) {
+		pr_warning("combiner_init_irq_domain: irq desc alloc failed\n");
+		domain->irq_base = irq_base;
+	}
+	domain->nr_irq = nr_irq;
+	domain->ops = &combiner_irq_domain_ops;
+	domain->of_node = np;
+	irq_domain_add(domain);
+	return 0;
+}
-- 
1.6.6.rc2

^ permalink raw reply related	[flat|nested] 4+ messages in thread
* [PATCH] ARM: Exynos: Add irq domain and device tree support for interrupt combiner
@ 2012-02-08 18:10 Thomas Abraham
  2012-02-08 19:47 ` Rob Herring
  0 siblings, 1 reply; 4+ messages in thread
From: Thomas Abraham @ 2012-02-08 18:10 UTC (permalink / raw)
  To: linux-arm-kernel

A common irq domain for the interrupts managed by the interrupt combiners is
setup. All the instances of irq combiner reference the common irq domain for
translating hardware interrupts to linux irq number.

In case of device tree based boot, a interrupt specifier translator is setup
that can translate interrupt specifiers for device nodes which use combiner
as their interrupt parent.

Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: Rob Herring <rob.herring@calxeda.com>
Cc: Kukjin Kim <kgene.kim@samsung.com>
Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
---
Changes since v2:
- Rebased to Grant's irqdomain/next branch.

Changes since v1:
- Includes all changes suggested by Rob Herring.
- Tested with SPARSE_IRQ enabled.

 arch/arm/mach-exynos/common.c |  100 ++++++++++++++++++++++++++++++++--------
 1 files changed, 80 insertions(+), 20 deletions(-)

diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c
index 6de298c..24693f0 100644
--- a/arch/arm/mach-exynos/common.c
+++ b/arch/arm/mach-exynos/common.c
@@ -19,6 +19,8 @@
 #include <linux/serial_core.h>
 #include <linux/of.h>
 #include <linux/of_irq.h>
+#include <linux/export.h>
+#include <linux/irqdomain.h>
 
 #include <asm/proc-fns.h>
 #include <asm/exception.h>
@@ -292,6 +294,7 @@ struct combiner_chip_data {
 	void __iomem *base;
 };
 
+static struct irq_domain *combiner_irq_domain;
 static struct combiner_chip_data combiner_data[MAX_COMBINER_NR];
 
 static inline void __iomem *combiner_base(struct irq_data *data)
@@ -304,14 +307,14 @@ static inline void __iomem *combiner_base(struct irq_data *data)
 
 static void combiner_mask_irq(struct irq_data *data)
 {
-	u32 mask = 1 << (data->irq % 32);
+	u32 mask = 1 << (data->hwirq % 32);
 
 	__raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_CLEAR);
 }
 
 static void combiner_unmask_irq(struct irq_data *data)
 {
-	u32 mask = 1 << (data->irq % 32);
+	u32 mask = 1 << (data->hwirq % 32);
 
 	__raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_SET);
 }
@@ -360,43 +363,104 @@ static void __init combiner_cascade_irq(unsigned int combiner_nr, unsigned int i
 	irq_set_chained_handler(irq, combiner_handle_cascade_irq);
 }
 
-static void __init combiner_init(unsigned int combiner_nr, void __iomem *base,
-			  unsigned int irq_start)
+static void __init combiner_init(unsigned int combiner_nr, void __iomem *base)
 {
-	unsigned int i;
-
 	if (combiner_nr >= MAX_COMBINER_NR)
 		BUG();
 
 	combiner_data[combiner_nr].base = base;
-	combiner_data[combiner_nr].irq_offset = irq_start;
+	combiner_data[combiner_nr].irq_offset = irq_find_mapping(
+		combiner_irq_domain, combiner_nr * MAX_IRQ_IN_COMBINER);
 	combiner_data[combiner_nr].irq_mask = 0xff << ((combiner_nr % 4) << 3);
 
 	/* Disable all interrupts */
 
 	__raw_writel(combiner_data[combiner_nr].irq_mask,
 		     base + COMBINER_ENABLE_CLEAR);
+}
+
+#ifdef CONFIG_OF
+static int combiner_irq_domain_xlate(struct irq_domain *d,
+		struct device_node *controller, const u32 *intspec,
+		unsigned int intsize, unsigned long *out_hwirq,
+		unsigned int *out_type)
+{
+	if (d->of_node != controller)
+		return -EINVAL;
+	if (intsize < 2)
+		return -EINVAL;
+	*out_hwirq = intspec[0] * MAX_IRQ_IN_COMBINER + intspec[1];
+	*out_type = 0;
+	return 0;
+}
+#else
+static int combiner_irq_domain_xlate(struct irq_domain *d,
+		struct device_node *controller, const u32 *intspec,
+		unsigned int intsize, unsigned long *out_hwirq,
+		unsigned int *out_type)
+{
+	return 0;
+}
+#endif
+
+static int combiner_irq_domain_map(struct irq_domain *d, unsigned int irq,
+					irq_hw_number_t hw)
+{
+	irq_set_chip_and_handler(irq, &combiner_chip, handle_level_irq);
+	irq_set_chip_data(irq, &combiner_data[hw >> 3]);
+	set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+	return 0;
+}
+
+static struct irq_domain_ops combiner_irq_domain_ops = {
+	.xlate = combiner_irq_domain_xlate,
+	.map = combiner_irq_domain_map,
+};
+
+int __init combiner_init_irq_domain(int virq_base, unsigned int nr_irq,
+					struct device_node *np)
+{
+	int irq_base;
+
+	irq_base = irq_alloc_descs(virq_base, 1, nr_irq, 0);
+	if (IS_ERR_VALUE(irq_base)) {
+		pr_warning("combiner_init_irq_domain: irq desc alloc failed\n");
+		irq_base = virq_base;
+	}
+
+	combiner_irq_domain = irq_domain_add_legacy(np, nr_irq, irq_base, 0,
+				&combiner_irq_domain_ops, &combiner_data);
+	if (WARN_ON(!combiner_irq_domain))
+		return -EINVAL;
 
-	/* Setup the Linux IRQ subsystem */
+	return 0;
+}
+
+void __init combiner_of_init(struct device_node *np, struct device_node *parent)
+{
+	int irq;
 
-	for (i = irq_start; i < combiner_data[combiner_nr].irq_offset
-				+ MAX_IRQ_IN_COMBINER; i++) {
-		irq_set_chip_and_handler(i, &combiner_chip, handle_level_irq);
-		irq_set_chip_data(i, &combiner_data[combiner_nr]);
-		set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
+	if (combiner_init_irq_domain(COMBINER_IRQ(0, 0), MAX_COMBINER_NR *
+					MAX_IRQ_IN_COMBINER, np))
+		BUG();
+	for (irq = 0; irq < MAX_COMBINER_NR; irq++) {
+		combiner_init(irq, (void __iomem *)S5P_VA_COMBINER(irq));
+		combiner_cascade_irq(irq, IRQ_SPI(irq));
 	}
 }
 
+
 #ifdef CONFIG_OF
 static const struct of_device_id exynos4_dt_irq_match[] = {
 	{ .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
+	{ .compatible = "samsung,exynos4120-combiner",
+			.data = combiner_of_init, },
 	{},
 };
 #endif
 
 void __init exynos4_init_irq(void)
 {
-	int irq;
 	unsigned int gic_bank_offset;
 
 	gic_bank_offset = soc_is_exynos4412() ? 0x4000 : 0x8000;
@@ -408,12 +472,8 @@ void __init exynos4_init_irq(void)
 		of_irq_init(exynos4_dt_irq_match);
 #endif
 
-	for (irq = 0; irq < MAX_COMBINER_NR; irq++) {
-
-		combiner_init(irq, (void __iomem *)S5P_VA_COMBINER(irq),
-				COMBINER_IRQ(irq, 0));
-		combiner_cascade_irq(irq, IRQ_SPI(irq));
-	}
+	if (!of_have_populated_dt())
+		combiner_of_init(NULL, NULL);
 
 	/*
 	 * The parameters of s5p_init_irq() are for VIC init.
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 4+ messages in thread
* [PATCH] ARM: Exynos: Add irq domain and device tree support for interrupt combiner
@ 2011-12-10 17:17 Thomas Abraham
  0 siblings, 0 replies; 4+ messages in thread
From: Thomas Abraham @ 2011-12-10 17:17 UTC (permalink / raw)
  To: linux-arm-kernel

A common irq domain for the interrupts managed by the interrupt combiners is
setup. All the instances of irq combiner reference the common irq domain for
translating hardware interrupts to linux irq number.

In case of device tree based boot, a interrupt specifier translator is setup
that can translate interrupt specifiers for device nodes which use combiner
as their interrupt parent.

Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
---
This patch is based on the following tree.
http://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung.git for-next

 .../bindings/arm/samsung/interrupt-combiner.txt    |   18 ++++++
 arch/arm/mach-exynos/cpu.c                         |   29 +++++++---
 arch/arm/mach-exynos/irq-combiner.c                |   58 +++++++++++++++++---
 3 files changed, 87 insertions(+), 18 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/samsung/interrupt-combiner.txt

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 0000000..6ca30d9
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/samsung/interrupt-combiner.txt
@@ -0,0 +1,18 @@
+* Samsung Exynos Interrupt Combiner Controller
+
+Samsung's Exynos4 architecture includes a interrupt combiner which can combine
+interrupt sources as a group and provide a single interrupt request for the
+group. The interrupt request from each group are connected to a parent interrupt
+controller, such as GIC in case of Exynos4210.
+
+Required properties:
+- compatible: should be "samsung,exynos4210-combiner".
+- #interrupt-cells: should be <2>. The meaning of the cells are
+	* First Cell: Combiner Group Number.
+	* Second Cell: Interrupt number within the group.
+- reg: Base address and size of interrupt combiner registers.
+- interrupt-controller: Identifies the node as an interrupt controller.
+
+Optional properties:
+- interrupt-parent: pHandle of the parent interrupt controller, if not
+  inherited from the parent node.
diff --git a/arch/arm/mach-exynos/cpu.c b/arch/arm/mach-exynos/cpu.c
index 8e09f34..14f86ba 100644
--- a/arch/arm/mach-exynos/cpu.c
+++ b/arch/arm/mach-exynos/cpu.c
@@ -37,9 +37,10 @@
 
 unsigned int gic_bank_offset __read_mostly;
 
-extern int combiner_init(unsigned int combiner_nr, void __iomem *base,
-			 unsigned int irq_start);
+extern int combiner_init(unsigned int combiner_nr, void __iomem *base);
 extern void combiner_cascade_irq(unsigned int combiner_nr, unsigned int irq);
+extern int combiner_init_irq_domain(unsigned int irq_base, unsigned int nr_irq,
+					struct device_node *np);
 
 /* Initial IO mappings */
 static struct map_desc exynos_iodesc[] __initdata = {
@@ -242,16 +243,30 @@ static void exynos4_gic_irq_fix_base(struct irq_data *d)
 			    (gic_bank_offset * smp_processor_id());
 }
 
+void __init combiner_of_init(struct device_node *np, struct device_node *parent)
+{
+	int irq;
+
+	if (combiner_init_irq_domain(COMBINER_IRQ(0, 0), MAX_COMBINER_NR *
+					MAX_IRQ_IN_COMBINER, np))
+		BUG();
+	for (irq = 0; irq < MAX_COMBINER_NR; irq++) {
+		combiner_init(irq, (void __iomem *)S5P_VA_COMBINER(irq));
+		combiner_cascade_irq(irq, IRQ_SPI(irq));
+	}
+}
+
 #ifdef CONFIG_OF
 static const struct of_device_id exynos4_dt_irq_match[] = {
 	{ .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
+	{ .compatible = "samsung,exynos4120-combiner",
+			.data = combiner_of_init, },
 	{},
 };
 #endif
 
 void __init exynos4_init_irq(void)
 {
-	int irq;
 
 	gic_bank_offset = soc_is_exynos4412() ? 0x4000 : 0x8000;
 
@@ -266,12 +281,8 @@ void __init exynos4_init_irq(void)
 	gic_arch_extn.irq_unmask = exynos4_gic_irq_fix_base;
 	gic_arch_extn.irq_mask = exynos4_gic_irq_fix_base;
 
-	for (irq = 0; irq < MAX_COMBINER_NR; irq++) {
-
-		combiner_init(irq, (void __iomem *)S5P_VA_COMBINER(irq),
-				COMBINER_IRQ(irq, 0));
-		combiner_cascade_irq(irq, IRQ_SPI(irq));
-	}
+	if (!of_have_populated_dt())
+		combiner_of_init(NULL, NULL);
 
 	/* The parameters of s5p_init_irq() are for VIC init.
 	 * Theses parameters should be NULL and 0 because EXYNOS4
diff --git a/arch/arm/mach-exynos/irq-combiner.c b/arch/arm/mach-exynos/irq-combiner.c
index 5a2758a..84f24c9 100644
--- a/arch/arm/mach-exynos/irq-combiner.c
+++ b/arch/arm/mach-exynos/irq-combiner.c
@@ -13,6 +13,8 @@
 */
 
 #include <linux/io.h>
+#include <linux/export.h>
+#include <linux/irqdomain.h>
 
 #include <asm/mach/irq.h>
 
@@ -26,8 +28,10 @@ struct combiner_chip_data {
 	unsigned int irq_offset;
 	unsigned int irq_mask;
 	void __iomem *base;
+	struct irq_domain *domain;
 };
 
+static struct irq_domain combiner_irq_domain;
 static struct combiner_chip_data combiner_data[MAX_COMBINER_NR];
 
 static inline void __iomem *combiner_base(struct irq_data *data)
@@ -40,14 +44,14 @@ static inline void __iomem *combiner_base(struct irq_data *data)
 
 static void combiner_mask_irq(struct irq_data *data)
 {
-	u32 mask = 1 << (data->irq % 32);
+	u32 mask = 1 << (data->hwirq % 32);
 
 	__raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_CLEAR);
 }
 
 static void combiner_unmask_irq(struct irq_data *data)
 {
-	u32 mask = 1 << (data->irq % 32);
+	u32 mask = 1 << (data->hwirq % 32);
 
 	__raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_SET);
 }
@@ -96,17 +100,18 @@ void __init combiner_cascade_irq(unsigned int combiner_nr, unsigned int irq)
 	irq_set_chained_handler(irq, combiner_handle_cascade_irq);
 }
 
-void __init combiner_init(unsigned int combiner_nr, void __iomem *base,
-			  unsigned int irq_start)
+void __init combiner_init(unsigned int combiner_nr, void __iomem *base)
 {
-	unsigned int i;
+	unsigned int i, hwirq;
 
 	if (combiner_nr >= MAX_COMBINER_NR)
 		BUG();
 
 	combiner_data[combiner_nr].base = base;
-	combiner_data[combiner_nr].irq_offset = irq_start;
+	combiner_data[combiner_nr].irq_offset =	irq_domain_to_irq(
+		&combiner_irq_domain, combiner_nr * MAX_IRQ_IN_COMBINER);
 	combiner_data[combiner_nr].irq_mask = 0xff << ((combiner_nr % 4) << 3);
+	combiner_data[combiner_nr].domain = &combiner_irq_domain;
 
 	/* Disable all interrupts */
 
@@ -114,11 +119,46 @@ void __init combiner_init(unsigned int combiner_nr, void __iomem *base,
 		     base + COMBINER_ENABLE_CLEAR);
 
 	/* Setup the Linux IRQ subsystem */
-
-	for (i = irq_start; i < combiner_data[combiner_nr].irq_offset
-				+ MAX_IRQ_IN_COMBINER; i++) {
+	for (hwirq = 0; hwirq < MAX_IRQ_IN_COMBINER; hwirq++) {
+		i = combiner_data[combiner_nr].irq_offset + hwirq;
 		irq_set_chip_and_handler(i, &combiner_chip, handle_level_irq);
 		irq_set_chip_data(i, &combiner_data[combiner_nr]);
 		set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
 	}
 }
+
+static int combiner_dt_translate(struct irq_domain *d,
+		struct device_node *controller, const u32 *intspec,
+		unsigned int intsize, unsigned long *out_hwirq,
+		unsigned int *out_type)
+{
+	if (d->of_node != controller)
+		return -EINVAL;
+	if (intsize < 2)
+		return -EINVAL;
+
+	*out_hwirq = intspec[0] * MAX_IRQ_IN_COMBINER + intspec[1];
+	*out_type = 0;
+	return 0;
+}
+
+static struct irq_domain_ops combiner_irq_domain_ops = {
+	.dt_translate = combiner_dt_translate,
+};
+
+int __init combiner_init_irq_domain(unsigned int irq_base, unsigned int nr_irq,
+					struct device_node *np)
+{
+	struct irq_domain *domain = &combiner_irq_domain;
+
+	domain->irq_base = irq_alloc_descs(irq_base, irq_base, nr_irq, 0);
+	if (domain->irq_base < 0) {
+		pr_err("failed to alloc irq descs, combiner init failed\n");
+		return -EBUSY;
+	}
+	domain->nr_irq = nr_irq;
+	domain->ops = &combiner_irq_domain_ops;
+	domain->of_node = np;
+	irq_domain_add(domain);
+	return 0;
+}
-- 
1.6.6.rc2

^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2012-02-08 19:47 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-01-12  7:32 [PATCH] ARM: Exynos: Add irq domain and device tree support for interrupt combiner Thomas Abraham
  -- strict thread matches above, loose matches on Subject: below --
2012-02-08 18:10 Thomas Abraham
2012-02-08 19:47 ` Rob Herring
2011-12-10 17:17 Thomas Abraham

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).