Skip to contentSkip to conversation

arm: exynos4: add irq domain and device tree support for wakeup interrupts

PATCH New Thomas Abraham 2 participants 9 messages Dec 7, 2011

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

cover arm: exynos4: add irq domain and device tree support for wakeup interrupts

Samsung Exynos4 includes 32 external wakeup interrupt sources. This patchset adds irq domain and device tree support for these interrupts.

This patchset is based on the following tree.
http://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung.git for-next

This patchset depends on the following patch from Jamie Iles.
irqdomain: export irq_domain._simple_op.s for !CONFIG_OF

Thomas Abraham (4):
arm: exynos4: simplify EINT number to GIC irq number translation
arm: exynos4: add irq_domain support for wakeup interrupts
arm: exynos4: remove arch_initcall for wakeup interrupt source initialization
arm: exynos4: add device tree support for external wakeup interrupt controller

 .../bindings/arm/samsung/wakeup-eint.txt           |   14 +++
 arch/arm/mach-exynos/cpu.c                         |    4 +
 arch/arm/mach-exynos/include/mach/regs-gpio.h      |    4 +-
 arch/arm/mach-exynos/irq-eint.c                    |  101 +++++++++++---------
 arch/arm/plat-samsung/include/plat/exynos4.h       |    1 +
 5 files changed, 75 insertions(+), 49 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/samsung/wakeup-eint.txt
#1 lore raw

PATCH 1/4 arm: exynos4: simplify EINT number to linux irq number translation

The exynos4_get_irq_nr function that converts a given wakeup interrupt source number to a linux irq number is simplified and replaced with the new macro exynos4_irq_eint_to_gic_irq.

---
 arch/arm/mach-exynos/irq-eint.c |   25 +++----------------------
 1 files changed, 3 insertions(+), 22 deletions(-)
arch/arm/mach-exynos/irq-eint.c +3 -22
index badb8c6..5e89412 100644
@@ -29,26 +29,7 @@ static DEFINE_SPINLOCK(eint_lock);
 
 static unsigned int eint0_15_data[16];
 
-static unsigned int exynos4_get_irq_nr(unsigned int number)
-{
-	u32 ret = 0;
-
-	switch (number) {
-	case 0 ... 3:
-		ret = (number + IRQ_EINT0);
-		break;
-	case 4 ... 7:
-		ret = (number + (IRQ_EINT4 - 4));
-		break;
-	case 8 ... 15:
-		ret = (number + (IRQ_EINT8 - 8));
-		break;
-	default:
-		printk(KERN_ERR "number available : %d\n", number);
-	}
-
-	return ret;
-}
+#define exynos4_irq_eint_to_gic_irq(number) (IRQ_EINT0 + number)
 
 static inline void exynos4_irq_eint_mask(struct irq_data *data)
 {
@@ -225,9 +206,9 @@ int __init exynos4_init_irq_eint(void)
 	for (irq = 0 ; irq <= 15 ; irq++) {
 		eint0_15_data[irq] = IRQ_EINT(irq);
 
-		irq_set_handler_data(exynos4_get_irq_nr(irq),
+		irq_set_handler_data(exynos4_irq_eint_to_gic_irq(irq),
 				     &eint0_15_data[irq]);
-		irq_set_chained_handler(exynos4_get_irq_nr(irq),
+		irq_set_chained_handler(exynos4_irq_eint_to_gic_irq(irq),
 					exynos4_irq_eint0_15);
 	}
 
Signature · 1 line
1.6.6.rc2
#2 lore raw

PATCH 2/4 arm: exynos4: add irq_domain support for wakeup interrupts

Add irq_domain support for the 32 wakeup interrupt sources.

---
 arch/arm/mach-exynos/include/mach/regs-gpio.h |    4 +-
 arch/arm/mach-exynos/irq-eint.c               |   69 ++++++++++++++++---------
 2 files changed, 46 insertions(+), 27 deletions(-)
arch/arm/mach-exynos/include/mach/regs-gpio.h +2 -2
index 1401b21..2e6ec6b 100644
@@ -28,9 +28,9 @@
 #define EXYNOS4_EINT40PEND		(S5P_VA_GPIO2 + 0xF40)
 #define S5P_EINT_PEND(x)		(EXYNOS4_EINT40PEND + ((x) * 0x4))
 
-#define EINT_REG_NR(x)			(EINT_OFFSET(x) >> 3)
+#define EINT_REG_NR(x)			((x) >> 3)
 
-#define eint_irq_to_bit(irq)		(1 << (EINT_OFFSET(irq) & 0x7))
+#define eint_irq_to_bit(irq)		(1 << ((irq) & 0x7))
 
 #define EINT_MODE			S3C_GPIO_SFN(0xf)
 
arch/arm/mach-exynos/irq-eint.c +44 -25

150 lines not on this page · raw message

Signature · 1 line
1.6.6.rc2
#3 lore raw

PATCH 3/4 arm: exynos4: remove arch_initcall for wakeup interrupt source initialization

The of_irq_init function would be setup to invoke the exynos4_init_irq_eint function when booting using device tree. The arch_initcall for exynos4_init_irq_eint would duplicate its invocation in that case. Hence, arch_initcall for exynos4_init_irq_eint is removed and this function is invoked from the exynos4_init_irq for non-dt case.

Moreover, with single kernel image build, the exynos4_init_irq_eint has no checks to ensure that it is running on a exynos4 platform. So it would be appropriate to invoke it from exynos4_init_irq.

---
 arch/arm/mach-exynos/cpu.c                   |    1 +
 arch/arm/mach-exynos/irq-eint.c              |    2 --
 arch/arm/plat-samsung/include/plat/exynos4.h |    1 +
 3 files changed, 2 insertions(+), 2 deletions(-)
arch/arm/mach-exynos/cpu.c +1 -0
index 8e09f34..6d27c36 100644
@@ -278,6 +278,7 @@ void __init exynos4_init_irq(void)
 	 * uses GIC instead of VIC.
 	 */
 	s5p_init_irq(NULL, 0);
+	exynos4_init_irq_eint();
 }
 
 struct sysdev_class exynos4_sysclass = {
arch/arm/mach-exynos/irq-eint.c +0 -2
index a65da64..771b156 100644
@@ -233,5 +233,3 @@ int __init exynos4_init_irq_eint(void)
 
 	return 0;
 }
-
-arch_initcall(exynos4_init_irq_eint);
arch/arm/plat-samsung/include/plat/exynos4.h +1 -0
index f546e88..a501461 100644
@@ -24,6 +24,7 @@ extern void exynos4_init_irq(void);
 extern void exynos4_map_io(void);
 extern void exynos4_init_clocks(int xtal);
 extern struct sys_timer exynos4_timer;
+extern int exynos4_init_irq_eint(void);
 
 #define exynos4_init_uarts exynos4_common_init_uarts
 
Signature · 1 line
1.6.6.rc2
#4 lore raw

PATCH 4/4 arm: exynos4: add device tree support for external wakeup interrupt controller

Add device tree support for external wakeup source interrupt controller on Exynos4.

Cc Rob Herring <[email protected]>
Cc Grant Likely <[email protected]>
---
 .../bindings/arm/samsung/wakeup-eint.txt           |   14 ++++++++++++++
 arch/arm/mach-exynos/cpu.c                         |    5 ++++-
 arch/arm/mach-exynos/irq-eint.c                    |    9 +++++++++
 3 files changed, 27 insertions(+), 1 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/samsung/wakeup-eint.txt
Documentation/devicetree/bindings/arm/samsung/wakeup-eint.txt new file +14 -0
new file mode 100644
index 0000000..0ca5782
@@ -0,0 +1,14 @@
+* Samsung Exynos4 External Wakeup Interrupt Source Controller
+
+Samsung Exynos4 processor supports 32 external wakeup interrupt sources. First
+16 of these interrupts are directly connected to GIC and the rest 16 of the
+interrupts are grouped together to deliver a single interrupt to GIC.
+
+Required properties:
+
+- compatible: should be "samsung,exynos4210-wakeup-eint".
+- interrupt-controller: Identifies the node as an interrupt controller.
+- interrupt-cells: Specifies the number of cells required to specify the
+    interrupt source number. The value of should be <2>. The first cell
+    represents the wakeup interrupt source number and the second cell
+    should be zero (currently unused).
arch/arm/mach-exynos/cpu.c +4 -1
index 6d27c36..306c13c 100644
@@ -245,6 +245,8 @@ static void exynos4_gic_irq_fix_base(struct irq_data *d)
 #ifdef CONFIG_OF
 static const struct of_device_id exynos4_dt_irq_match[] = {
 	{ .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
+	{ .compatible = "samsung,exynos4210-wakeup-eint",
+		.data = exynos4_init_irq_eint, },
 	{},
 };
 #endif
@@ -278,7 +280,8 @@ void __init exynos4_init_irq(void)
 	 * uses GIC instead of VIC.
 	 */
 	s5p_init_irq(NULL, 0);
-	exynos4_init_irq_eint();
+	if (!of_have_populated_dt())
+		exynos4_init_irq_eint();
 }
 
 struct sysdev_class exynos4_sysclass = {
arch/arm/mach-exynos/irq-eint.c +9 -0
index 771b156..e78fdfa 100644
@@ -18,6 +18,7 @@
 #include <linux/gpio.h>
 #include <linux/irqdomain.h>
 #include <linux/export.h>
+#include <linux/of.h>
 
 #include <plat/pm.h>
 #include <plat/cpu.h>
@@ -210,6 +211,14 @@ int __init exynos4_init_irq_eint(void)
 	}
 	domain->nr_irq = EXYNOS4_EINT_NR;
 	domain->ops = &irq_domain_simple_ops;
+#ifdef CONFIG_OF
+	if (of_have_populated_dt()) {
+		domain->of_node = of_find_compatible_node(NULL, NULL,
+					"samsung,exynos4210-wakeup-eint");
+		if (!domain->of_node)
+			pr_info("exynos4_init_irq_eint: of_node not found\n");
+	}
+#endif
 	irq_domain_add(domain);
 
 	irq_domain_for_each_irq(domain, hwirq, irq) {
Signature · 1 line
1.6.6.rc2
#5 lore raw

PATCH 4/4 arm: exynos4: add device tree support for external wakeup interrupt controller

Quoted 23 lines · Thomas Abraham

Add device tree support for external wakeup source interrupt controller on Exynos4.

Cc Rob Herring <[email protected]>
Cc Grant Likely <[email protected]>
---
 .../bindings/arm/samsung/wakeup-eint.txt           |   14 ++++++++++++++
 arch/arm/mach-exynos/cpu.c                         |    5 ++++-
 arch/arm/mach-exynos/irq-eint.c                    |    9 +++++++++
 3 files changed, 27 insertions(+), 1 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/samsung/wakeup-eint.txt
Documentation/devicetree/bindings/arm/samsung/wakeup-eint.txt new file +4 -0
new file mode 100644
index 0000000..0ca5782
@@ -0,0 +1,14 @@
+* Samsung Exynos4 External Wakeup Interrupt Source Controller
+
+Samsung Exynos4 processor supports 32 external wakeup interrupt sources. First
+16 of these interrupts are directly connected to GIC and the rest 16 of the

Documentation/devicetree/bindings/arm/samsung/wakeup-eint.txt line 14

Quoted 10 lines
Documentation/devicetree/bindings/arm/samsung/wakeup-eint.txt new file +10 -0
+interrupts are grouped together to deliver a single interrupt to GIC.
+
+Required properties:
+
+- compatible: should be "samsung,exynos4210-wakeup-eint".
+- interrupt-controller: Identifies the node as an interrupt controller.
+- interrupt-cells: Specifies the number of cells required to specify the
+    interrupt source number. The value of should be <2>. The first cell
+    represents the wakeup interrupt source number and the second cell
+    should be zero (currently unused).

interrupt-parent needs to be set to the gic?

Quoted 37 lines
arch/arm/mach-exynos/cpu.c +4 -1
index 6d27c36..306c13c 100644
@@ -245,6 +245,8 @@ static void exynos4_gic_irq_fix_base(struct irq_data *d)
 #ifdef CONFIG_OF
 static const struct of_device_id exynos4_dt_irq_match[] = {
 	{ .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
+	{ .compatible = "samsung,exynos4210-wakeup-eint",
+		.data = exynos4_init_irq_eint, },
 	{},
 };
 #endif
@@ -278,7 +280,8 @@ void __init exynos4_init_irq(void)
 	 * uses GIC instead of VIC.
 	 */
 	s5p_init_irq(NULL, 0);
-	exynos4_init_irq_eint();
+	if (!of_have_populated_dt())
+		exynos4_init_irq_eint();
 }
 
 struct sysdev_class exynos4_sysclass = {
arch/arm/mach-exynos/irq-eint.c +1 -0
index 771b156..e78fdfa 100644
@@ -18,6 +18,7 @@
 #include <linux/gpio.h>
 #include <linux/irqdomain.h>
 #include <linux/export.h>
+#include <linux/of.h>
 
 #include <plat/pm.h>
 #include <plat/cpu.h>
@@ -210,6 +211,14 @@ int __init exynos4_init_irq_eint(void)
 	}

arch/arm/mach-exynos/irq-eint.c int __init exynos4_init_irq_eint(void) · line 221

Quoted 10 lines
arch/arm/mach-exynos/irq-eint.c +8 -0
 	domain->nr_irq = EXYNOS4_EINT_NR;
 	domain->ops = &irq_domain_simple_ops;
+#ifdef CONFIG_OF
+	if (of_have_populated_dt()) {
+		domain->of_node = of_find_compatible_node(NULL, NULL,
+					"samsung,exynos4210-wakeup-eint");
+		if (!domain->of_node)
+			pr_info("exynos4_init_irq_eint: of_node not found\n");
+	}
+#endif

Your function prototype is wrong for of_irq_init as it provides you the node ptr.

Otherwise, the series looks pretty good.

Rob

#6 lore raw

PATCH 4/4 arm: exynos4: add device tree support for external wakeup interrupt controller

Hi Rob,

Quoted 8 lines · Rob Herring
Quoted 7 lines · Thomas Abraham

Add device tree support for external wakeup source interrupt controller on Exynos4.

Cc Rob Herring <[email protected]>
Cc Grant Likely <[email protected]>

---

[...]

Quoted 14 lines
Quoted 14 lines
Documentation/devicetree/bindings/arm/samsung/wakeup-eint.txt new file +8 -0
new file mode 100644
index 0000000..0ca5782
@@ -0,0 +1,14 @@
+* Samsung Exynos4 External Wakeup Interrupt Source Controller
+
+Samsung Exynos4 processor supports 32 external wakeup interrupt sources. First
+16 of these interrupts are directly connected to GIC and the rest 16 of the
+interrupts are grouped together to deliver a single interrupt to GIC.
+
+Required properties:
+
Quoted 8 lines

Documentation/devicetree/bindings/arm/samsung/wakeup-eint.txt

Quoted 6 lines
Documentation/devicetree/bindings/arm/samsung/wakeup-eint.txt new file +6 -0
+- compatible: should be "samsung,exynos4210-wakeup-eint".
+- interrupt-controller: Identifies the node as an interrupt controller.
+- interrupt-cells: Specifies the number of cells required to specify the
+ ? ?interrupt source number. The value of should be <2>. The first cell
+ ? ?represents the wakeup interrupt source number and the second cell
+ ? ?should be zero (currently unused).

interrupt-parent needs to be set to the gic?

Yes, I missed that. gic is set as the interrupt parent in the root node and all child nodes inherit it. I will add interrupt-parent as the required property as list gic as the parent.

Quoted 2 lines
Quoted 2 lines
arch/arm/mach-exynos/cpu.c +0 -0

[...]

Quoted 11 lines

arch/arm/mach-exynos/cpu.c

Quoted 8 lines
arch/arm/mach-exynos/cpu.c +8 -0
+#ifdef CONFIG_OF
+ ? ? if (of_have_populated_dt()) {
+ ? ? ? ? ? ? domain->of_node = of_find_compatible_node(NULL, NULL,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "samsung,exynos4210-wakeup-eint");
+ ? ? ? ? ? ? if (!domain->of_node)
+ ? ? ? ? ? ? ? ? ? ? pr_info("exynos4_init_irq_eint: of_node not found\n");
+ ? ? }
+#endif

Your function prototype is wrong for of_irq_init as it provides you the node ptr.

Thanks. I got this wrong. That would make the code above much simpler. I will fix this.

Quoted 4 lines

Otherwise, the series looks pretty good.

Rob

Thanks for your review and comments.

Regards,
Thomas.

#7 lore raw

PATCH 2/4 arm: exynos4: add irq_domain support for wakeup interrupts

In reply to Thomas Abraham

Thomas,

Quoted 9 lines · Thomas Abraham

Add irq_domain support for the 32 wakeup interrupt sources.

---
 arch/arm/mach-exynos/include/mach/regs-gpio.h |    4 +-
 arch/arm/mach-exynos/irq-eint.c               |   69 ++++++++++++++++---------
 2 files changed, 46 insertions(+), 27 deletions(-)

[snip]

arch/arm/mach-exynos/irq-eint.c static void exynos4_irq_eint0_15(unsigned int irq, struct irq_desc *desc) · line 205

Quoted 9 lines
arch/arm/mach-exynos/irq-eint.c +4 -1
@@ -193,22 +199,35 @@ static void exynos4_irq_eint0_15(unsigned int irq, struct irq_desc *desc)
 
 int __init exynos4_init_irq_eint(void)
 {
-	int irq;
+	int irq, hwirq;
+	struct irq_domain *domain = &exynos4_eint_irq_domain;
+
+	domain->irq_base = irq_alloc_descs(IRQ_EINT(0), IRQ_EINT(0),

Can this be dynamic and remove any compile time knowledge of the irq base?

arch/arm/mach-exynos/irq-eint.c static void exynos4_irq_eint0_15(unsigned int irq, struct irq_desc *desc) · line 209

Quoted 4 lines
arch/arm/mach-exynos/irq-eint.c +4 -0
+						EXYNOS4_EINT_NR, 0);
+	if (domain->irq_base < 0) {
+		pr_err("exynos4_init_irq_eint: Failed to alloc irq descs\n");
+		return -EBUSY;

You will hit this error with sparse irq unless you set nr_irq in mach desc to NR_IRQ_LEGACY (16).

Quoted 31 lines
arch/arm/mach-exynos/irq-eint.c +13 -7
+	}
+	domain->nr_irq = EXYNOS4_EINT_NR;
+	domain->ops = &irq_domain_simple_ops;
+	irq_domain_add(domain);
 
-	for (irq = 0 ; irq <= 31 ; irq++) {
-		irq_set_chip_and_handler(IRQ_EINT(irq), &exynos4_irq_eint,
+	irq_domain_for_each_irq(domain, hwirq, irq) {
+		irq_set_chip_and_handler(irq, &exynos4_irq_eint,
 					 handle_level_irq);
-		set_irq_flags(IRQ_EINT(irq), IRQF_VALID);
+		set_irq_flags(irq, IRQF_VALID);
 	}
 
 	irq_set_chained_handler(IRQ_EINT16_31, exynos4_irq_demux_eint16_31);
+	irq_set_handler_data(IRQ_EINT16_31, &domain->irq_base);
 
-	for (irq = 0 ; irq <= 15 ; irq++) {
-		eint0_15_data[irq] = IRQ_EINT(irq);
+	for (hwirq = 0 ; hwirq <= 15 ; hwirq++) {
+		irq = irq_domain_to_irq(domain, hwirq);
+		eint0_15_data[irq] = irq;
 
-		irq_set_handler_data(exynos4_irq_eint_to_gic_irq(irq),
+		irq_set_handler_data(exynos4_irq_eint_to_gic_irq(hwirq),
 				     &eint0_15_data[irq]);
-		irq_set_chained_handler(exynos4_irq_eint_to_gic_irq(irq),
+		irq_set_chained_handler(exynos4_irq_eint_to_gic_irq(hwirq),
 					exynos4_irq_eint0_15);
 	}
 
#8 lore raw

PATCH 2/4 arm: exynos4: add irq_domain support for wakeup interrupts

Hi Rob,

Quoted 17 lines · Rob Herring

Thomas,

Quoted 9 lines · Thomas Abraham

Add irq_domain support for the 32 wakeup interrupt sources.

---
?arch/arm/mach-exynos/include/mach/regs-gpio.h | ? ?4 +- ?arch/arm/mach-exynos/irq-eint.c ? ? ? ? ? ? ? | ? 69 ++++++++++++++++--------- ?2 files changed, 46 insertions(+), 27 deletions(-)

[snip]

Quoted 2 lines
(quoted diff) +0 -0
@@ -193,22 +199,35 @@ static void exynos4_irq_eint0_15(unsigned int irq, struct irq_desc *desc)
 
Quoted 9 lines

Review static void exynos4_irq_eint0_15(unsigned int irq, struct irq_desc *desc) · line 205

Quoted 7 lines
(quoted diff) +4 -1
 ?int __init exynos4_init_irq_eint(void)
 ?{
- ? ? int irq;
+ ? ? int irq, hwirq;
+ ? ? struct irq_domain *domain = &exynos4_eint_irq_domain;
+
+ ? ? domain->irq_base = irq_alloc_descs(IRQ_EINT(0), IRQ_EINT(0),

Can this be dynamic and remove any compile time knowledge of the irq base?

There are macros in the mach-exynos code that define linux irq numbers for specific uses. For instance, linux interrupt number for wakeup interrupt 0 is defined as IRQ_EINT(0) and maps to one of the linux irq number. Consumer using this interrupt would use IRQ_EINT(0) in request_irq or setup_irq.

Since the linux irq numbers are currently assigned to specific uses like this, I am not sure how to make irq_alloc_descs dynamic and still be able to use the dynamic irq base in the rest of the mach-exynos code with no other code changes. Is there any way to handle this case?

Thanks,
Thomas.

Quoted 8 lines

Review static void exynos4_irq_eint0_15(unsigned int irq, struct irq_desc *desc) · line 209

Quoted 5 lines
(quoted diff) +4 -0
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? EXYNOS4_EINT_NR, 0);
+ ? ? if (domain->irq_base < 0) {
+ ? ? ? ? ? ? pr_err("exynos4_init_irq_eint: Failed to alloc irq descs\n");
+ ? ? ? ? ? ? return -EBUSY;

You will hit this error with sparse irq unless you set nr_irq in mach desc to NR_IRQ_LEGACY (16).

[...]