[PATCH] arm: exynos4: Add support for dt irq specifier to linux virq conversion

Thomas Abraham thomas.abraham at linaro.org
Thu Jul 28 04:24:28 EST 2011


Exynos4 includes two interrupt controllers - External GIC and External
Interrupt Combiner. External GIC can handle 16 software generated
interrupts (SGI), 16 Private Peripheral Interrupts (PPI) and 128
Shared Peripheral Interrupts (SPI). External Interrupt Combiner manages
32 groups of 8 interrupts each and feeds 32 interrupts as SPI interrupts
to the External GIC controller.

This patch supports conversion of device tree interrupt specifier to
linux virq domain for both the interrupt controllers. The concept of
this patch is derived from Grant's 'simple' irq converter.

This patch is based on Grant's following patchset
[PATCH v3 0/2] Simple irq_domain implementation

Signed-off-by: Thomas Abraham <thomas.abraham at linaro.org>
---
 Documentation/devicetree/bindings/arm/samsung.txt |   72 +++++++++++++
 arch/arm/mach-exynos4/Makefile                    |    1 +
 arch/arm/mach-exynos4/include/mach/irqs.h         |    3 +
 arch/arm/mach-exynos4/irqdomain.c                 |  117 +++++++++++++++++++++
 arch/arm/mach-exynos4/mach-exynos4-dt.c           |    8 +-
 5 files changed, 196 insertions(+), 5 deletions(-)
 create mode 100644 arch/arm/mach-exynos4/irqdomain.c

diff --git a/Documentation/devicetree/bindings/arm/samsung.txt b/Documentation/devicetree/bindings/arm/samsung.txt
index 5676bca..878aa01 100644
--- a/Documentation/devicetree/bindings/arm/samsung.txt
+++ b/Documentation/devicetree/bindings/arm/samsung.txt
@@ -6,3 +6,75 @@ Required root node properties:
   - compatible = "samsung,smdkv310", "samsung,exynos4210'.
       (a) "samsung,smdkv310" - for Samsung's SMDKV310 eval board.
       (b) "samsung,exynos4210" - for boards based on Exynos4210 processor.
+
+
+Exynos4 Interrupt Controllers
+-----------------------------
+
+Samsung's Exynos4 architecture includes two interrupt controllers.
+  - External GIC
+  - External Interrupt Combiner.
+
+The external GIC can manage
+  - 16 Software Generated Interrupts (SGI).
+  - 16 Private Peripheral Interrupts (PPI).
+  - 128 Shared Peripheral Interrupts (SPI).
+
+Out of the 128 Shared Peripheral Interrupts (SPI's), 32 interrupts
+are sourced from a interrupt combiner. The interrupt combiner provides
+32 groups of interrupts with a maximum of 8 interrupts combined per
+group.
+
+External GIC properties:
+  - compatible: should be "samsung,exynos4-ext-gic".
+  - interrupt-cells: should be <2>. The meaning of the cells are
+      * First Cell: Interrupt Number.
+      * Second Cell: Type of Interrupt (0-SPI, 1-SGI, 2-PPI).
+  - reg: The GIC includes a Distributor Interface and CPU Interface and
+    hence requires two base addresses. The property format is
+    <Distributor-Base Distributor-Size>, <CPU-Base CPU Size>
+
+  Example:
+
+	EXT_GIC:interrupt-controller at 10490000 {
+		compatible = "samsung,exynos4-ext-gic";
+		#interrupt-cells = <2>;
+		interrupt-controller;
+		reg = <0x10490000 0x1000>, <0x10480000 0x100>;
+	};
+
+  Devices using External GIC as the interrupt parent should specify two
+  cells for the interrupts property as shown below.
+
+	watchdog at 10060000 {
+		compatible = "samsung,s3c2410-wdt";
+		reg = <0x10060000 0x400>;
+		interrupt-parent = <&EXT_GIC>;
+		interrupts = <43 0>;
+	};
+
+External Interrupt Combiner properties:
+  - compatible: should be "samsung,exynos4-ext-combiner".
+  - interrupt-cells: should be <2>. The meaning of the cells are
+      * First Cell: Combiner Group Number.
+      * Second Cell: Interrupt within the group.
+  - reg: Base address and size of interrupt combiner registers.
+
+  Example:
+
+	EXT_COMBINER:interrupt-controller at 10440000 {
+		compatible = "samsung,exynos4-ext-combiner";
+		#interrupt-cells = <2>;
+		interrupt-controller;
+		reg = <0x10440000 0x200>;
+	};
+
+  Devices using External Interrupt Combiner as the interrupt parent should
+  specify two cells for the interrupts property as shown below.
+
+	watchdog at 10060000 {
+		compatible = "samsung,s3c2410-wdt";
+		reg = <0x10060000 0x400>;
+		interrupt-parent = <&EXT_COMBINER>;
+		interrupts = <4 2>;
+	};
diff --git a/arch/arm/mach-exynos4/Makefile b/arch/arm/mach-exynos4/Makefile
index ac91f4f..fd532c7 100644
--- a/arch/arm/mach-exynos4/Makefile
+++ b/arch/arm/mach-exynos4/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_MACH_ARMLEX4210)		+= mach-armlex4210.o
 obj-$(CONFIG_MACH_UNIVERSAL_C210)	+= mach-universal_c210.o
 obj-$(CONFIG_MACH_NURI)			+= mach-nuri.o
 obj-$(CONFIG_MACH_EXYNOS4_DT)		+= mach-exynos4-dt.o
+obj-$(CONFIG_OF_IRQ)			+= irqdomain.o
 
 # device support
 
diff --git a/arch/arm/mach-exynos4/include/mach/irqs.h b/arch/arm/mach-exynos4/include/mach/irqs.h
index 934d2a4..c120aad 100644
--- a/arch/arm/mach-exynos4/include/mach/irqs.h
+++ b/arch/arm/mach-exynos4/include/mach/irqs.h
@@ -15,6 +15,9 @@
 
 #include <plat/irqs.h>
 
+/* SGI: Software Generated Interrupt */
+#define IRQ_SGI(x)		S5P_IRQ(x)
+
 /* PPI: Private Peripheral Interrupt */
 
 #define IRQ_PPI(x)		S5P_IRQ(x+16)
diff --git a/arch/arm/mach-exynos4/irqdomain.c b/arch/arm/mach-exynos4/irqdomain.c
new file mode 100644
index 0000000..f50fa20
--- /dev/null
+++ b/arch/arm/mach-exynos4/irqdomain.c
@@ -0,0 +1,117 @@
+/*
+ * Exynos4 irq domain conversion from dt irq specifier to linux virq domain
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Exynos4 includes two interrupt controllers - External GIC and External
+ * Interrupt Combiner. This file provides support for converting interrupt
+ * specified in device tree to linux virq domain for both the controllers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+
+#include <mach/irqs.h>
+
+/*
+ * The interrupt specifier for External GIC controller uses to two cells in
+ * the device tree source file. The second cell denotes the type of the
+ * interrupt (SPI/SGI/PPI). The following macros are used to represent
+ * these different types of interrupt.
+ */
+#define	EXT_GIC_SPI	0
+#define	EXT_GIC_SGI	1
+#define	EXT_GIC_PPI	2
+
+/* Translate dt irq specifier to linux virq for external GIC controller */
+static int exynos4_irq_domain_ext_gic_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;
+
+	switch (intspec[1]) {
+	case EXT_GIC_SPI:
+		*out_hwirq = IRQ_SPI(intspec[0]);
+		break;
+	case EXT_GIC_SGI:
+		*out_hwirq = IRQ_SGI(intspec[0]);
+		break;
+	case EXT_GIC_PPI:
+		*out_hwirq = IRQ_PPI(intspec[0]);
+		break;
+	default:
+		pr_info("irq_domain register: invalid ext gic intr type\n");
+		return -EINVAL;
+	}
+
+	*out_type = IRQ_TYPE_NONE;
+	return 0;
+}
+
+/* Translate dt irq specifier to linux virq for external combiner controller */
+static int exynos4_irq_domain_ext_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 = COMBINER_IRQ(intspec[0], intspec[1]);
+	*out_type = IRQ_TYPE_NONE;
+	return 0;
+}
+
+static struct irq_domain_ops exynos4_irq_domain_ext_gic_ops = {
+	.dt_translate = exynos4_irq_domain_ext_gic_dt_translate,
+};
+
+static struct irq_domain_ops exynos4_irq_domain_ext_combiner_ops = {
+	.dt_translate = exynos4_irq_domain_ext_combiner_dt_translate,
+};
+
+static struct of_device_id exynos4_irq_ctrl_of_match[] = {
+	{ .compatible = "samsung,exynos4-ext-gic",
+		.data = &exynos4_irq_domain_ext_gic_ops, },
+	{ .compatible = "samsung,exynos4-ext-combiner",
+		.data = &exynos4_irq_domain_ext_combiner_ops, },
+	{},
+};
+
+void exynos4_register_irq_domain_dt(void)
+{
+	struct device_node *controller;
+	struct irq_domain *domain;
+	const struct of_device_id *match;
+
+	for_each_matching_node(controller, exynos4_irq_ctrl_of_match) {
+		domain = kzalloc(sizeof(*domain), GFP_KERNEL);
+		if (!domain) {
+			WARN_ON(1);
+			return;
+		}
+
+		match = of_match_node(exynos4_irq_ctrl_of_match, controller);
+		domain->of_node = of_node_get(controller);
+		domain->ops = match->data;
+		irq_domain_add(domain);
+	}
+}
+EXPORT_SYMBOL_GPL(exynos4_register_irq_domain_dt);
diff --git a/arch/arm/mach-exynos4/mach-exynos4-dt.c b/arch/arm/mach-exynos4/mach-exynos4-dt.c
index 120665a..450a9ed 100644
--- a/arch/arm/mach-exynos4/mach-exynos4-dt.c
+++ b/arch/arm/mach-exynos4/mach-exynos4-dt.c
@@ -16,6 +16,7 @@
 #include <linux/io.h>
 #include <linux/of_platform.h>
 #include <linux/irq.h>
+#include <linux/irqdomain.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach-types.h>
@@ -85,14 +86,11 @@ static void __init exynos4_dt_map_io(void)
 	s3c24xx_init_uarts(smdkv310_uartcfgs, ARRAY_SIZE(smdkv310_uartcfgs));
 }
 
-static const struct of_device_id intc_of_match[] __initconst = {
-	{ .compatible = "samsung,exynos4-gic", },
-	{}
-};
+extern void exynos4_register_irq_domain_dt(void);
 
 static void __init exynos4_dt_machine_init(void)
 {
-	irq_domain_generate_simple(intc_of_match, EXYNOS4_PA_GIC_DIST, 0);
+	exynos4_register_irq_domain_dt();
 	of_platform_populate(NULL, of_default_bus_match_table,
 				exynos4_auxdata_lookup, NULL);
 }
-- 
1.6.6.rc2



More information about the devicetree-discuss mailing list