arm: exynos4: add irq domain and device tree support for wakeup interrupts
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
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
@@ -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
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
@@ -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
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
@@ -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
@@ -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
@@ -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
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.
--- .../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
@@ -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
@@ -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
@@ -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
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]>Signed-off-by Thomas Abraham <[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.txtDocumentation/devicetree/bindings/arm/samsung/wakeup-eint.txt new file +4
-0@@ -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@@ -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@@ -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
-0domain->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
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]>Signed-off-by Thomas Abraham <[email protected]>---
[...]
Quoted 14 lines
Quoted 14 lines
Documentation/devicetree/bindings/arm/samsung/wakeup-eint.txt new file +8
-0@@ -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_initas 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.
PATCH 2/4 arm: exynos4: add irq_domain support for wakeup interrupts
In reply to Thomas AbrahamThomas,
Quoted 9 lines · Thomas Abraham
Add
irq_domainsupport for the 32 wakeup interrupt sources.Cc Grant Likely <[email protected]>Signed-off-by Thomas Abraham <[email protected]>--- 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); }
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_domainsupport for the 32 wakeup interrupt sources.Cc Grant Likely <[email protected]>Signed-off-by Thomas Abraham <[email protected]>---
?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_irqin mach desc toNR_IRQ_LEGACY(16).
[...]