diff mbox

[RFC,1/2] ARM: S3C24XX: add devicetree support for interrupts

Message ID 201211250147.42164.heiko@sntech.de (mailing list archive)
State New, archived
Headers show

Commit Message

Heiko Stuebner Nov. 25, 2012, 12:47 a.m. UTC
This adds devicetree parsing of the controller-data for the
interrupt controllers on S3C24XX architectures.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 .../interrupt-controller/samsung,s3c24xx-irq.txt   |   57 ++++++
 arch/arm/mach-s3c24xx/common.h                     |    1 +
 arch/arm/plat-s3c24xx/irq.c                        |  197 ++++++++++++++++++++
 3 files changed, 255 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24xx-irq.txt

Comments

Thomas Abraham Nov. 26, 2012, 11:03 a.m. UTC | #1
Hi Heiko,

On 25 November 2012 06:17, Heiko Stübner <heiko@sntech.de> wrote:
> This adds devicetree parsing of the controller-data for the
> interrupt controllers on S3C24XX architectures.
>
> Signed-off-by: Heiko Stuebner <heiko@sntech.de>
> ---
>  .../interrupt-controller/samsung,s3c24xx-irq.txt   |   57 ++++++
>  arch/arm/mach-s3c24xx/common.h                     |    1 +
>  arch/arm/plat-s3c24xx/irq.c                        |  197 ++++++++++++++++++++
>  3 files changed, 255 insertions(+), 0 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24xx-irq.txt
>
> diff --git a/Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24xx-irq.txt b/Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24xx-irq.txt
> new file mode 100644
> index 0000000..c637637
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24xx-irq.txt
> @@ -0,0 +1,57 @@
> +Samsung S3C24XX Interrupt Controllers
> +
> +The S3C24XX SoCs contain custom set of interrupt controllers providing a
> +varying number of interrupt sources.
> +
> +The set consists of a main- and a sub-controller as well as a controller
> +for the external interrupts and on newer SoCs even a second main controller.
> +
> +The bit-to-interrupt and parent mapping of the controllers is not fixed
> +over all SoCs and therefore must be defined in the controller description.
> +
> +Required properties:
> +- compatible: Compatible property value should be "samsung,s3c24xx-irq".
> +
> +- reg: Physical base address of the controller and length of memory mapped
> +  region.
> +
> +- interrupt-controller : Identifies the node as an interrupt controller
> +- #interrupt-cells : Specifies the number of cells needed to encode an
> +  interrupt source. The value shall be 2.
> +
> +- s3c24xx,irqlist : List of irqtypes found on this controller as
> +  two-value pairs consisting of irqtype and parent-irq
> +
> +  parent-irq is always the list position of the irq in the irqlist
> +  of the parent controller (0..31)
> +
> +  irqtypes are:
> +  - 0 .. none
> +  - 1 .. external interrupts in the main register (GPF0 .. GPF3)
> +  - 2 .. edge irq in the main register
> +  - 3 .. for parent-irqs, that have sub-irqs in child controllers
> +  - 4 .. level irqs in the sub-register
> +  - 5 .. edge irqs in the sub-register
> +  - 6 .. external irqs in the external irq register (starting with GPF4)
> +  - 7 .. irq in the second base irq controller of S3C2416/S3C2450 SoCs

Instead of defining the type of interrupt controller as above, is it
possible to create multiple device nodes, with each node representing
a type of interrupt controller with a unique compatible string and
corresponding properties. There will be a init function for each type
of interrupt controller. There should be a irq-domain for each of
these different types of interrupt controller. And then, in the device
tree source file, a proper tree like hierarchy of interrupt
controllers can defined (using the interrupt-parent property for each
controller node). The client nodes that generate the interrupt can
specify the parent node and the interrupt number within the parent to
which they generate the interrupt.

Thanks,
Thomas.

> +
> +Optional properties:
> +- interrupt_parent : The parent interrupt controller
> +
> +Example:
> +
> +       intc2:interrupt-controller@4a000040 {
> +               compatible = "samsung,s3c24xx-irq";
> +               reg = <0x4a000040 0x18>;
> +               interrupt-controller;
> +               #interrupt-cells = <2>;
> +
> +               s3c24xx,irqlist = <7 0 /* 2D */
> +                                  7 0 /* IIC1 */
> +                                  0 0 /* reserved */
> +                                  0 0 /* reserved */
> +                                  7 0 /* PCM0 */
> +                                  7 0 /* PCM1 */
> +                                  7 0 /* I2S0 */
> +                                  7 0>; /* I2S1 */
> +       };
> diff --git a/arch/arm/mach-s3c24xx/common.h b/arch/arm/mach-s3c24xx/common.h
> index ed6276f..7a7b770 100644
> --- a/arch/arm/mach-s3c24xx/common.h
> +++ b/arch/arm/mach-s3c24xx/common.h
> @@ -16,5 +16,6 @@ void s3c2410_restart(char mode, const char *cmd);
>  void s3c244x_restart(char mode, const char *cmd);
>
>  extern struct syscore_ops s3c24xx_irq_syscore_ops;
> +extern void s3c24xx_init_irq_of(void);
>
>  #endif /* __ARCH_ARM_MACH_S3C24XX_COMMON_H */
> diff --git a/arch/arm/plat-s3c24xx/irq.c b/arch/arm/plat-s3c24xx/irq.c
> index 0510627..4f8fe4a 100644
> --- a/arch/arm/plat-s3c24xx/irq.c
> +++ b/arch/arm/plat-s3c24xx/irq.c
> @@ -25,6 +25,9 @@
>  #include <linux/slab.h>
>
>  #include <linux/irqdomain.h>
> +#include <linux/of.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_address.h>
>
>  #include <asm/irq.h>
>  #include <asm/mach/irq.h>
> @@ -956,3 +959,197 @@ void __init s3c2443_init_irq(void)
>         s3c24xx_init_irq();
>  }
>  #endif
> +
> +#ifdef CONFIG_OF
> +static int __init s3c24xx_init_intc_of(struct device_node *np,
> +                                      struct device_node *interrupt_parent)
> +{
> +       struct s3c_irq_intc *intc;
> +       struct s3c_irq_intc *parent;
> +       struct s3c_irq_data *irq_data;
> +       struct property *intc_prop;
> +       int irq_num = 0, irq_start = 0, irq_offset = 0;
> +       int ret, i, cnt;
> +       const __be32 *p;
> +       u32 val;
> +
> +       intc = kzalloc(sizeof(struct s3c_irq_intc), GFP_KERNEL);
> +       if (!intc)
> +               return -ENOMEM;
> +
> +       p = of_get_address(np, 0, NULL, NULL);
> +       if (!p) {
> +               pr_err("irq: register address missing\n");
> +               ret = -EINVAL;
> +               goto err_addr;
> +       }
> +
> +       /* select the correct data for the controller.
> +        * Need to hard code the irq num start and offset
> +        * to preserve the static mapping for now
> +        */
> +       switch (of_translate_address(np, p)) {
> +       case 0x4a000000:
> +               pr_debug("irq: found main intc\n");
> +               intc->reg_pending = S3C2410_SRCPND;
> +               intc->reg_intpnd = S3C2410_INTPND;
> +               intc->reg_mask = S3C2410_INTMSK;
> +               irq_num = 32;
> +               irq_start = S3C2410_IRQ(0);
> +               irq_offset = 0;
> +               break;
> +       case 0x560000a4:
> +               pr_debug("irq: found extintc\n");
> +               intc->reg_pending = S3C2410_EINTPEND;
> +               intc->reg_mask = S3C2410_EINTMASK;
> +               irq_num = 20;
> +               irq_start = S3C2410_IRQ(32);
> +               irq_offset = 4;
> +               break;
> +       case 0x4a000018:
> +               pr_debug("irq: found subintc\n");
> +               intc->reg_pending = S3C2410_SUBSRCPND;
> +               intc->reg_mask = S3C2410_INTSUBMSK;
> +               irq_num = 29;
> +               irq_start = S3C2410_IRQSUB(0);
> +               irq_offset = 0;
> +               break;
> +       case 0x4a000040:
> +               pr_debug("irq: found intc2\n");
> +               intc->reg_pending = S3C2416_SRCPND2;
> +               intc->reg_intpnd = S3C2416_INTPND2;
> +               intc->reg_mask = S3C2416_INTMSK2;
> +               irq_num = 8;
> +               irq_start = S3C2416_IRQ(0);
> +               irq_offset = 0;
> +               break;
> +       case 0:
> +               pr_err("irq: couldn't translate address\n");
> +               ret = -EINVAL;
> +               goto err_addr;
> +       default:
> +               pr_err("irq: unsupported controller address\n");
> +               ret = -EINVAL;
> +               goto err_addr;
> +       }
> +
> +       irq_data = kzalloc(sizeof(struct s3c_irq_data) * 32, GFP_KERNEL);
> +       if (!irq_data) {
> +               ret = -ENOMEM;
> +               goto err_addr;
> +       }
> +
> +       cnt = 0;
> +       intc_prop = of_find_property(np, "s3c24xx,irqlist", NULL);
> +       if (!intc_prop) {
> +               pr_err("irq: irqlist not found\n");
> +               ret = -EINVAL;
> +               goto err_data;
> +       }
> +
> +       /* build the irq_data list */
> +       p = NULL;
> +       for (i = 0; i < 32; i++) {
> +               p = of_prop_next_u32(intc_prop, p, &val);
> +
> +               /* when we hit the first non-valid element, assume it's
> +                * the end of the list. The rest of the fields are
> +                * already of type S3C_IRQTYPE_NONE (value 0)
> +                */
> +               if (!p)
> +                       break;
> +
> +               irq_data[i].type = val;
> +
> +               p = of_prop_next_u32(intc_prop, p, &val);
> +               if (!p) {
> +                       pr_warn("irq: uneven number of elements in irqlist, last value will be dropped\n");
> +                       irq_data[i].type = 0;
> +                       break;
> +               }
> +
> +               irq_data[i].parent_irq = val;
> +
> +               pr_debug("irq: found hwirq %d with type %d and parent %lu\n",
> +                        i, irq_data[i].type, irq_data[i].parent_irq);
> +               cnt++;
> +       }
> +
> +       /* if we haven't found any irq definition at all,
> +        * something is very wrong.
> +        */
> +       if (!cnt) {
> +               pr_err("irq: empty irq definition\n");
> +               ret = -EINVAL;
> +               goto err_data;
> +       }
> +
> +       intc->irqs = irq_data;
> +
> +       /* put the intc into the dt as property, so we can access it from
> +        * as the interrupt_parent later
> +        */
> +
> +       intc_prop = kzalloc(sizeof(struct property), GFP_KERNEL);
> +       if (!intc_prop) {
> +               ret = -ENOMEM;
> +               goto err_data;
> +       }
> +
> +       intc_prop->name = kstrdup("s3c-irq-intc", GFP_KERNEL);
> +       intc_prop->value = intc;
> +       intc_prop->length = sizeof(struct s3c_irq_intc);
> +
> +       ret = prom_add_property(np, intc_prop);
> +       if (ret) {
> +               pr_err("irq: failed to add dt property\n");
> +               goto err_prop;
> +       }
> +
> +       /* set the parent relationship */
> +       if (interrupt_parent) {
> +               parent = (struct s3c_irq_intc *)of_get_property(
> +                                     interrupt_parent, "s3c-irq-intc", NULL);
> +               if (!parent) {
> +                       pr_err("irq: no parent for non-root controller found\n");
> +                       goto err_domain;
> +               }
> +
> +               intc->parent = parent;
> +       }
> +
> +       /* now that all the data is complete, init the irq-domain */
> +       s3c24xx_clear_intc(intc);
> +       intc->domain = irq_domain_add_legacy(np, irq_num, irq_start,
> +                                            irq_offset, &s3c24xx_irq_ops,
> +                                            intc);
> +       if (!intc->domain) {
> +               pr_err("irq: could not create irq-domain\n");
> +               ret = -EINVAL;
> +               goto err_domain;
> +       }
> +
> +       return 0;
> +
> +err_domain:
> +       prom_remove_property(np, intc_prop);
> +err_prop:
> +       kfree(intc_prop);
> +err_data:
> +       kfree(irq_data);
> +err_addr:
> +       kfree(intc);
> +
> +       return ret;
> +}
> +
> +static const struct of_device_id s3c24xx_irq_match[] __initconst = {
> +       { .compatible = "samsung,s3c24xx-irq", .data = s3c24xx_init_intc_of, },
> +       { /* sentinel */ }
> +};
> +
> +void __init s3c24xx_init_irq_of(void)
> +{
> +       of_irq_init(s3c24xx_irq_match);
> +}
> +#endif
> --
> 1.7.2.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
Heiko Stuebner Nov. 26, 2012, 12:13 p.m. UTC | #2
Hi Thomas,

Am Montag, 26. November 2012, 12:03:22 schrieb Thomas Abraham:
> Hi Heiko,
> 
> On 25 November 2012 06:17, Heiko Stübner <heiko@sntech.de> wrote:
> > This adds devicetree parsing of the controller-data for the
> > interrupt controllers on S3C24XX architectures.
> > 
> > Signed-off-by: Heiko Stuebner <heiko@sntech.de>
> > ---
> > 
> >  .../interrupt-controller/samsung,s3c24xx-irq.txt   |   57 ++++++
> >  arch/arm/mach-s3c24xx/common.h                     |    1 +
> >  arch/arm/plat-s3c24xx/irq.c                        |  197
> >  ++++++++++++++++++++ 3 files changed, 255 insertions(+), 0 deletions(-)
> >  create mode 100644
> >  Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24xx-
> >  irq.txt
> > 
> > diff --git
> > a/Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24xx
> > -irq.txt
> > b/Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24xx
> > -irq.txt new file mode 100644
> > index 0000000..c637637
> > --- /dev/null
> > +++
> > b/Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24xx
> > -irq.txt @@ -0,0 +1,57 @@
> > +Samsung S3C24XX Interrupt Controllers
> > +
> > +The S3C24XX SoCs contain custom set of interrupt controllers providing a
> > +varying number of interrupt sources.
> > +
> > +The set consists of a main- and a sub-controller as well as a controller
> > +for the external interrupts and on newer SoCs even a second main
> > controller. +
> > +The bit-to-interrupt and parent mapping of the controllers is not fixed
> > +over all SoCs and therefore must be defined in the controller
> > description. +
> > +Required properties:
> > +- compatible: Compatible property value should be "samsung,s3c24xx-irq".
> > +
> > +- reg: Physical base address of the controller and length of memory
> > mapped +  region.
> > +
> > +- interrupt-controller : Identifies the node as an interrupt controller
> > +- #interrupt-cells : Specifies the number of cells needed to encode an
> > +  interrupt source. The value shall be 2.
> > +
> > +- s3c24xx,irqlist : List of irqtypes found on this controller as
> > +  two-value pairs consisting of irqtype and parent-irq
> > +
> > +  parent-irq is always the list position of the irq in the irqlist
> > +  of the parent controller (0..31)
> > +
> > +  irqtypes are:
> > +  - 0 .. none
> > +  - 1 .. external interrupts in the main register (GPF0 .. GPF3)
> > +  - 2 .. edge irq in the main register
> > +  - 3 .. for parent-irqs, that have sub-irqs in child controllers
> > +  - 4 .. level irqs in the sub-register
> > +  - 5 .. edge irqs in the sub-register
> > +  - 6 .. external irqs in the external irq register (starting with GPF4)
> > +  - 7 .. irq in the second base irq controller of S3C2416/S3C2450 SoCs
> 
> Instead of defining the type of interrupt controller as above, is it
> possible to create multiple device nodes, with each node representing
> a type of interrupt controller with a unique compatible string and
> corresponding properties. There will be a init function for each type
> of interrupt controller. There should be a irq-domain for each of
> these different types of interrupt controller. And then, in the device
> tree source file, a proper tree like hierarchy of interrupt
> controllers can defined (using the interrupt-parent property for each
> controller node). The client nodes that generate the interrupt can
> specify the parent node and the interrupt number within the parent to
> which they generate the interrupt.

I'm not sure I understand yet :-). The list describes the types of interrupts 
inside the individual controllers.

On all the s3c24xx we have three register sets denoting the main (SRCPND, 
INTPND, INTMSK), sub (SUBSRCPEND, INTSUBMASK) and extint (EINTPEND, EINTMASK) 
controllers. The bits of these registers are used for quite different irqs. 
For example is bit 17 of the main register set used as DMA0 on earlier socs 
while the dma interrupts moved to the subint registers for s3c2443 and later.

So the entries in the irqlist describe the needed handlers for the hwirq bits 
of the indidual controllers. So in this scheme you set for dt-devices the 
interrupt parent to the correct register set and the interrupts field then 
matches the bit of the register, according to the datasheet.


When I changed the basic interrupt handling in the previous set, the changed 
irq.c can for exmaple be found on [0], I created these lists in the code and 
soc specific routines to init them for the still valid non-dt case.

But as dt is about describing the hardware, I found the current solution nice, 
because will I only need exactly one dt-init-function for all s3c24xx-socs, 
instead of representing all the slight variances in code.


I'm definitly not sure if all the different types of individual irq handlers 
are strictly necessary yet, but they represent all the variants that were in 
use in the original code.


Heiko


[0] https://github.com/mmind/linux-es600/blob/topic/es600-devel/arch/arm/plat-
s3c24xx/irq.c

> > +
> > +Optional properties:
> > +- interrupt_parent : The parent interrupt controller
> > +
> > +Example:
> > +
> > +       intc2:interrupt-controller@4a000040 {
> > +               compatible = "samsung,s3c24xx-irq";
> > +               reg = <0x4a000040 0x18>;
> > +               interrupt-controller;
> > +               #interrupt-cells = <2>;
> > +
> > +               s3c24xx,irqlist = <7 0 /* 2D */
> > +                                  7 0 /* IIC1 */
> > +                                  0 0 /* reserved */
> > +                                  0 0 /* reserved */
> > +                                  7 0 /* PCM0 */
> > +                                  7 0 /* PCM1 */
> > +                                  7 0 /* I2S0 */
> > +                                  7 0>; /* I2S1 */
> > +       };
> > diff --git a/arch/arm/mach-s3c24xx/common.h
> > b/arch/arm/mach-s3c24xx/common.h index ed6276f..7a7b770 100644
> > --- a/arch/arm/mach-s3c24xx/common.h
> > +++ b/arch/arm/mach-s3c24xx/common.h
> > @@ -16,5 +16,6 @@ void s3c2410_restart(char mode, const char *cmd);
> > 
> >  void s3c244x_restart(char mode, const char *cmd);
> >  
> >  extern struct syscore_ops s3c24xx_irq_syscore_ops;
> > 
> > +extern void s3c24xx_init_irq_of(void);
> > 
> >  #endif /* __ARCH_ARM_MACH_S3C24XX_COMMON_H */
> > 
> > diff --git a/arch/arm/plat-s3c24xx/irq.c b/arch/arm/plat-s3c24xx/irq.c
> > index 0510627..4f8fe4a 100644
> > --- a/arch/arm/plat-s3c24xx/irq.c
> > +++ b/arch/arm/plat-s3c24xx/irq.c
> > @@ -25,6 +25,9 @@
> > 
> >  #include <linux/slab.h>
> >  
> >  #include <linux/irqdomain.h>
> > 
> > +#include <linux/of.h>
> > +#include <linux/of_irq.h>
> > +#include <linux/of_address.h>
> > 
> >  #include <asm/irq.h>
> >  #include <asm/mach/irq.h>
> > 
> > @@ -956,3 +959,197 @@ void __init s3c2443_init_irq(void)
> > 
> >         s3c24xx_init_irq();
> >  
> >  }
> >  #endif
> > 
> > +
> > +#ifdef CONFIG_OF
> > +static int __init s3c24xx_init_intc_of(struct device_node *np,
> > +                                      struct device_node
> > *interrupt_parent) +{
> > +       struct s3c_irq_intc *intc;
> > +       struct s3c_irq_intc *parent;
> > +       struct s3c_irq_data *irq_data;
> > +       struct property *intc_prop;
> > +       int irq_num = 0, irq_start = 0, irq_offset = 0;
> > +       int ret, i, cnt;
> > +       const __be32 *p;
> > +       u32 val;
> > +
> > +       intc = kzalloc(sizeof(struct s3c_irq_intc), GFP_KERNEL);
> > +       if (!intc)
> > +               return -ENOMEM;
> > +
> > +       p = of_get_address(np, 0, NULL, NULL);
> > +       if (!p) {
> > +               pr_err("irq: register address missing\n");
> > +               ret = -EINVAL;
> > +               goto err_addr;
> > +       }
> > +
> > +       /* select the correct data for the controller.
> > +        * Need to hard code the irq num start and offset
> > +        * to preserve the static mapping for now
> > +        */
> > +       switch (of_translate_address(np, p)) {
> > +       case 0x4a000000:
> > +               pr_debug("irq: found main intc\n");
> > +               intc->reg_pending = S3C2410_SRCPND;
> > +               intc->reg_intpnd = S3C2410_INTPND;
> > +               intc->reg_mask = S3C2410_INTMSK;
> > +               irq_num = 32;
> > +               irq_start = S3C2410_IRQ(0);
> > +               irq_offset = 0;
> > +               break;
> > +       case 0x560000a4:
> > +               pr_debug("irq: found extintc\n");
> > +               intc->reg_pending = S3C2410_EINTPEND;
> > +               intc->reg_mask = S3C2410_EINTMASK;
> > +               irq_num = 20;
> > +               irq_start = S3C2410_IRQ(32);
> > +               irq_offset = 4;
> > +               break;
> > +       case 0x4a000018:
> > +               pr_debug("irq: found subintc\n");
> > +               intc->reg_pending = S3C2410_SUBSRCPND;
> > +               intc->reg_mask = S3C2410_INTSUBMSK;
> > +               irq_num = 29;
> > +               irq_start = S3C2410_IRQSUB(0);
> > +               irq_offset = 0;
> > +               break;
> > +       case 0x4a000040:
> > +               pr_debug("irq: found intc2\n");
> > +               intc->reg_pending = S3C2416_SRCPND2;
> > +               intc->reg_intpnd = S3C2416_INTPND2;
> > +               intc->reg_mask = S3C2416_INTMSK2;
> > +               irq_num = 8;
> > +               irq_start = S3C2416_IRQ(0);
> > +               irq_offset = 0;
> > +               break;
> > +       case 0:
> > +               pr_err("irq: couldn't translate address\n");
> > +               ret = -EINVAL;
> > +               goto err_addr;
> > +       default:
> > +               pr_err("irq: unsupported controller address\n");
> > +               ret = -EINVAL;
> > +               goto err_addr;
> > +       }
> > +
> > +       irq_data = kzalloc(sizeof(struct s3c_irq_data) * 32, GFP_KERNEL);
> > +       if (!irq_data) {
> > +               ret = -ENOMEM;
> > +               goto err_addr;
> > +       }
> > +
> > +       cnt = 0;
> > +       intc_prop = of_find_property(np, "s3c24xx,irqlist", NULL);
> > +       if (!intc_prop) {
> > +               pr_err("irq: irqlist not found\n");
> > +               ret = -EINVAL;
> > +               goto err_data;
> > +       }
> > +
> > +       /* build the irq_data list */
> > +       p = NULL;
> > +       for (i = 0; i < 32; i++) {
> > +               p = of_prop_next_u32(intc_prop, p, &val);
> > +
> > +               /* when we hit the first non-valid element, assume it's
> > +                * the end of the list. The rest of the fields are
> > +                * already of type S3C_IRQTYPE_NONE (value 0)
> > +                */
> > +               if (!p)
> > +                       break;
> > +
> > +               irq_data[i].type = val;
> > +
> > +               p = of_prop_next_u32(intc_prop, p, &val);
> > +               if (!p) {
> > +                       pr_warn("irq: uneven number of elements in
> > irqlist, last value will be dropped\n"); +                      
> > irq_data[i].type = 0;
> > +                       break;
> > +               }
> > +
> > +               irq_data[i].parent_irq = val;
> > +
> > +               pr_debug("irq: found hwirq %d with type %d and parent
> > %lu\n", +                        i, irq_data[i].type,
> > irq_data[i].parent_irq); +               cnt++;
> > +       }
> > +
> > +       /* if we haven't found any irq definition at all,
> > +        * something is very wrong.
> > +        */
> > +       if (!cnt) {
> > +               pr_err("irq: empty irq definition\n");
> > +               ret = -EINVAL;
> > +               goto err_data;
> > +       }
> > +
> > +       intc->irqs = irq_data;
> > +
> > +       /* put the intc into the dt as property, so we can access it from
> > +        * as the interrupt_parent later
> > +        */
> > +
> > +       intc_prop = kzalloc(sizeof(struct property), GFP_KERNEL);
> > +       if (!intc_prop) {
> > +               ret = -ENOMEM;
> > +               goto err_data;
> > +       }
> > +
> > +       intc_prop->name = kstrdup("s3c-irq-intc", GFP_KERNEL);
> > +       intc_prop->value = intc;
> > +       intc_prop->length = sizeof(struct s3c_irq_intc);
> > +
> > +       ret = prom_add_property(np, intc_prop);
> > +       if (ret) {
> > +               pr_err("irq: failed to add dt property\n");
> > +               goto err_prop;
> > +       }
> > +
> > +       /* set the parent relationship */
> > +       if (interrupt_parent) {
> > +               parent = (struct s3c_irq_intc *)of_get_property(
> > +                                     interrupt_parent, "s3c-irq-intc",
> > NULL); +               if (!parent) {
> > +                       pr_err("irq: no parent for non-root controller
> > found\n"); +                       goto err_domain;
> > +               }
> > +
> > +               intc->parent = parent;
> > +       }
> > +
> > +       /* now that all the data is complete, init the irq-domain */
> > +       s3c24xx_clear_intc(intc);
> > +       intc->domain = irq_domain_add_legacy(np, irq_num, irq_start,
> > +                                            irq_offset,
> > &s3c24xx_irq_ops, +                                            intc);
> > +       if (!intc->domain) {
> > +               pr_err("irq: could not create irq-domain\n");
> > +               ret = -EINVAL;
> > +               goto err_domain;
> > +       }
> > +
> > +       return 0;
> > +
> > +err_domain:
> > +       prom_remove_property(np, intc_prop);
> > +err_prop:
> > +       kfree(intc_prop);
> > +err_data:
> > +       kfree(irq_data);
> > +err_addr:
> > +       kfree(intc);
> > +
> > +       return ret;
> > +}
> > +
> > +static const struct of_device_id s3c24xx_irq_match[] __initconst = {
> > +       { .compatible = "samsung,s3c24xx-irq", .data =
> > s3c24xx_init_intc_of, }, +       { /* sentinel */ }
> > +};
> > +
> > +void __init s3c24xx_init_irq_of(void)
> > +{
> > +       of_irq_init(s3c24xx_irq_match);
> > +}
> > +#endif
> > --
> > 1.7.2.3
> > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe
> > linux-samsung-soc" in the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
Thomas Abraham Nov. 26, 2012, 3:23 p.m. UTC | #3
On 26 November 2012 17:43, Heiko Stübner <heiko@sntech.de> wrote:
> Hi Thomas,
>
> Am Montag, 26. November 2012, 12:03:22 schrieb Thomas Abraham:
>> Hi Heiko,
>>
>> On 25 November 2012 06:17, Heiko Stübner <heiko@sntech.de> wrote:
>> > This adds devicetree parsing of the controller-data for the
>> > interrupt controllers on S3C24XX architectures.
>> >
>> > Signed-off-by: Heiko Stuebner <heiko@sntech.de>
>> > ---
>> >
>> >  .../interrupt-controller/samsung,s3c24xx-irq.txt   |   57 ++++++
>> >  arch/arm/mach-s3c24xx/common.h                     |    1 +
>> >  arch/arm/plat-s3c24xx/irq.c                        |  197
>> >  ++++++++++++++++++++ 3 files changed, 255 insertions(+), 0 deletions(-)
>> >  create mode 100644
>> >  Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24xx-
>> >  irq.txt
>> >
>> > diff --git
>> > a/Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24xx
>> > -irq.txt
>> > b/Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24xx
>> > -irq.txt new file mode 100644
>> > index 0000000..c637637
>> > --- /dev/null
>> > +++
>> > b/Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24xx
>> > -irq.txt @@ -0,0 +1,57 @@
>> > +Samsung S3C24XX Interrupt Controllers
>> > +
>> > +The S3C24XX SoCs contain custom set of interrupt controllers providing a
>> > +varying number of interrupt sources.
>> > +
>> > +The set consists of a main- and a sub-controller as well as a controller
>> > +for the external interrupts and on newer SoCs even a second main
>> > controller. +
>> > +The bit-to-interrupt and parent mapping of the controllers is not fixed
>> > +over all SoCs and therefore must be defined in the controller
>> > description. +
>> > +Required properties:
>> > +- compatible: Compatible property value should be "samsung,s3c24xx-irq".
>> > +
>> > +- reg: Physical base address of the controller and length of memory
>> > mapped +  region.
>> > +
>> > +- interrupt-controller : Identifies the node as an interrupt controller
>> > +- #interrupt-cells : Specifies the number of cells needed to encode an
>> > +  interrupt source. The value shall be 2.
>> > +
>> > +- s3c24xx,irqlist : List of irqtypes found on this controller as
>> > +  two-value pairs consisting of irqtype and parent-irq
>> > +
>> > +  parent-irq is always the list position of the irq in the irqlist
>> > +  of the parent controller (0..31)
>> > +
>> > +  irqtypes are:
>> > +  - 0 .. none
>> > +  - 1 .. external interrupts in the main register (GPF0 .. GPF3)
>> > +  - 2 .. edge irq in the main register
>> > +  - 3 .. for parent-irqs, that have sub-irqs in child controllers
>> > +  - 4 .. level irqs in the sub-register
>> > +  - 5 .. edge irqs in the sub-register
>> > +  - 6 .. external irqs in the external irq register (starting with GPF4)
>> > +  - 7 .. irq in the second base irq controller of S3C2416/S3C2450 SoCs
>>
>> Instead of defining the type of interrupt controller as above, is it
>> possible to create multiple device nodes, with each node representing
>> a type of interrupt controller with a unique compatible string and
>> corresponding properties. There will be a init function for each type
>> of interrupt controller. There should be a irq-domain for each of
>> these different types of interrupt controller. And then, in the device
>> tree source file, a proper tree like hierarchy of interrupt
>> controllers can defined (using the interrupt-parent property for each
>> controller node). The client nodes that generate the interrupt can
>> specify the parent node and the interrupt number within the parent to
>> which they generate the interrupt.
>
> I'm not sure I understand yet :-). The list describes the types of interrupts
> inside the individual controllers.
>
> On all the s3c24xx we have three register sets denoting the main (SRCPND,
> INTPND, INTMSK), sub (SUBSRCPEND, INTSUBMASK) and extint (EINTPEND, EINTMASK)
> controllers. The bits of these registers are used for quite different irqs.

We could consider main, sub and extint as three separate interrupt
controllers and thus three different nodes in device tree. So the
interrupt nodes could be something like (referring to 2416 manual).

     main@0x4a000000 {
            compatible = "samsung,s3c2410-main";
            reg = <0x4a000000 0x100>;
            interrupt-controller;
            #interrupt-cells = <2>;
     };

     sub@0x4a001000 {
            compatible = "samsung,s3c2410-sub";
            reg = <0x4a001000 0x100>;
            interrupt-controller;
            #interrupt-cells = <2>;
            interrupt-parent = <&main>;
            interrupts = <28 0>, <23 0>, <.....  /*uart0/uart1/..*/
     };

     eint@0x4a002000 {
            compatible = "samsung,s3c2410-eint";
            reg = <0x4a002000 0x100>;
            interrupt-controller;
            #interrupt-cells = <2>;
            interrupt-parent = <&main>;
            interrupts = <0 0>, <1 0>,
                              <2 0>, <3 0>,
                              <4 0>, <5 0>;
     };

There should be a corresponding irqchip driver code to handle each of
these types of controllers. They should have their own irq-domain
supported.

Then the client nodes can specify the interrupt parent and interrupt
number. For example, the uart node would be

       uart@50000000 {
            compatible = "samsung,s3c2410-uart";
            reg = <0x50000000 0x100>;
            interrupt-parent = <&sub>;
            interrupts = <0 0>, <1 0>, <2 0>; /*tx/rx/err*/
       };

> For example is bit 17 of the main register set used as DMA0 on earlier socs
> while the dma interrupts moved to the subint registers for s3c2443 and later.

Writing the nodes with the correct interrupt parent and the interrupt
number should take care of this.

>
> So the entries in the irqlist describe the needed handlers for the hwirq bits
> of the indidual controllers. So in this scheme you set for dt-devices the
> interrupt parent to the correct register set and the interrupts field then
> matches the bit of the register, according to the datasheet.
>
> When I changed the basic interrupt handling in the previous set, the changed
> irq.c can for exmaple be found on [0], I created these lists in the code and
> soc specific routines to init them for the still valid non-dt case.
>
> But as dt is about describing the hardware, I found the current solution nice,
> because will I only need exactly one dt-init-function for all s3c24xx-socs,
> instead of representing all the slight variances in code.
>
> I'm definitly not sure if all the different types of individual irq handlers
> are strictly necessary yet, but they represent all the variants that were in
> use in the original code.

I have brought up this point just for discussion. You could choose the
implementation that you prefer. I understand that implementing with
different interrupt controller nodes might require lot of code
changes.

Thanks,
Thomas.
Heiko Stuebner Nov. 26, 2012, 4:04 p.m. UTC | #4
Hi Thomas,

Am Montag, 26. November 2012, 16:23:00 schrieb Thomas Abraham:
> On 26 November 2012 17:43, Heiko Stübner <heiko@sntech.de> wrote:
> > Hi Thomas,
> > 
> > Am Montag, 26. November 2012, 12:03:22 schrieb Thomas Abraham:
> >> Hi Heiko,
> >> 
> >> On 25 November 2012 06:17, Heiko Stübner <heiko@sntech.de> wrote:
> >> > This adds devicetree parsing of the controller-data for the
> >> > interrupt controllers on S3C24XX architectures.
> >> > 
> >> > Signed-off-by: Heiko Stuebner <heiko@sntech.de>
> >> > ---
> >> > 
> >> >  .../interrupt-controller/samsung,s3c24xx-irq.txt   |   57 ++++++
> >> >  arch/arm/mach-s3c24xx/common.h                     |    1 +
> >> >  arch/arm/plat-s3c24xx/irq.c                        |  197
> >> >  ++++++++++++++++++++ 3 files changed, 255 insertions(+), 0
> >> >  deletions(-) create mode 100644
> >> >  Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24x
> >> >  x- irq.txt
> >> > 
> >> > diff --git
> >> > a/Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24
> >> > xx -irq.txt
> >> > b/Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24
> >> > xx -irq.txt new file mode 100644
> >> > index 0000000..c637637
> >> > --- /dev/null
> >> > +++
> >> > b/Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24
> >> > xx -irq.txt @@ -0,0 +1,57 @@
> >> > +Samsung S3C24XX Interrupt Controllers
> >> > +
> >> > +The S3C24XX SoCs contain custom set of interrupt controllers
> >> > providing a +varying number of interrupt sources.
> >> > +
> >> > +The set consists of a main- and a sub-controller as well as a
> >> > controller +for the external interrupts and on newer SoCs even a
> >> > second main controller. +
> >> > +The bit-to-interrupt and parent mapping of the controllers is not
> >> > fixed +over all SoCs and therefore must be defined in the controller
> >> > description. +
> >> > +Required properties:
> >> > +- compatible: Compatible property value should be
> >> > "samsung,s3c24xx-irq". +
> >> > +- reg: Physical base address of the controller and length of memory
> >> > mapped +  region.
> >> > +
> >> > +- interrupt-controller : Identifies the node as an interrupt
> >> > controller +- #interrupt-cells : Specifies the number of cells needed
> >> > to encode an +  interrupt source. The value shall be 2.
> >> > +
> >> > +- s3c24xx,irqlist : List of irqtypes found on this controller as
> >> > +  two-value pairs consisting of irqtype and parent-irq
> >> > +
> >> > +  parent-irq is always the list position of the irq in the irqlist
> >> > +  of the parent controller (0..31)
> >> > +
> >> > +  irqtypes are:
> >> > +  - 0 .. none
> >> > +  - 1 .. external interrupts in the main register (GPF0 .. GPF3)
> >> > +  - 2 .. edge irq in the main register
> >> > +  - 3 .. for parent-irqs, that have sub-irqs in child controllers
> >> > +  - 4 .. level irqs in the sub-register
> >> > +  - 5 .. edge irqs in the sub-register
> >> > +  - 6 .. external irqs in the external irq register (starting with
> >> > GPF4) +  - 7 .. irq in the second base irq controller of
> >> > S3C2416/S3C2450 SoCs
> >> 
> >> Instead of defining the type of interrupt controller as above, is it
> >> possible to create multiple device nodes, with each node representing
> >> a type of interrupt controller with a unique compatible string and
> >> corresponding properties. There will be a init function for each type
> >> of interrupt controller. There should be a irq-domain for each of
> >> these different types of interrupt controller. And then, in the device
> >> tree source file, a proper tree like hierarchy of interrupt
> >> controllers can defined (using the interrupt-parent property for each
> >> controller node). The client nodes that generate the interrupt can
> >> specify the parent node and the interrupt number within the parent to
> >> which they generate the interrupt.
> > 
> > I'm not sure I understand yet :-). The list describes the types of
> > interrupts inside the individual controllers.
> > 
> > On all the s3c24xx we have three register sets denoting the main (SRCPND,
> > INTPND, INTMSK), sub (SUBSRCPEND, INTSUBMASK) and extint (EINTPEND,
> > EINTMASK) controllers. The bits of these registers are used for quite
> > different irqs.
> 
> We could consider main, sub and extint as three separate interrupt
> controllers and thus three different nodes in device tree. So the
> interrupt nodes could be something like (referring to 2416 manual).
> 
>      main@0x4a000000 {
>             compatible = "samsung,s3c2410-main";
>             reg = <0x4a000000 0x100>;
>             interrupt-controller;
>             #interrupt-cells = <2>;
>      };
> 
>      sub@0x4a001000 {
>             compatible = "samsung,s3c2410-sub";
>             reg = <0x4a001000 0x100>;
>             interrupt-controller;
>             #interrupt-cells = <2>;
>             interrupt-parent = <&main>;
>             interrupts = <28 0>, <23 0>, <.....  /*uart0/uart1/..*/
>      };
> 
>      eint@0x4a002000 {
>             compatible = "samsung,s3c2410-eint";
>             reg = <0x4a002000 0x100>;
>             interrupt-controller;
>             #interrupt-cells = <2>;
>             interrupt-parent = <&main>;
>             interrupts = <0 0>, <1 0>,
>                               <2 0>, <3 0>,
>                               <4 0>, <5 0>;
>      };
> 
> There should be a corresponding irqchip driver code to handle each of
> these types of controllers. They should have their own irq-domain
> supported.
> 
> Then the client nodes can specify the interrupt parent and interrupt
> number. For example, the uart node would be
> 
>        uart@50000000 {
>             compatible = "samsung,s3c2410-uart";
>             reg = <0x50000000 0x100>;
>             interrupt-parent = <&sub>;
>             interrupts = <0 0>, <1 0>, <2 0>; /*tx/rx/err*/
>        };
> 
> > For example is bit 17 of the main register set used as DMA0 on earlier
> > socs while the dma interrupts moved to the subint registers for s3c2443
> > and later.
> 
> Writing the nodes with the correct interrupt parent and the interrupt
> number should take care of this.
> 
> > So the entries in the irqlist describe the needed handlers for the hwirq
> > bits of the indidual controllers. So in this scheme you set for
> > dt-devices the interrupt parent to the correct register set and the
> > interrupts field then matches the bit of the register, according to the
> > datasheet.
> > 
> > When I changed the basic interrupt handling in the previous set, the
> > changed irq.c can for exmaple be found on [0], I created these lists in
> > the code and soc specific routines to init them for the still valid
> > non-dt case.
> > 
> > But as dt is about describing the hardware, I found the current solution
> > nice, because will I only need exactly one dt-init-function for all
> > s3c24xx-socs, instead of representing all the slight variances in code.
> > 
> > I'm definitly not sure if all the different types of individual irq
> > handlers are strictly necessary yet, but they represent all the variants
> > that were in use in the original code.
> 
> I have brought up this point just for discussion. You could choose the
> implementation that you prefer. I understand that implementing with
> different interrupt controller nodes might require lot of code
> changes.

first of all, thanks for the feedback. Working on this is like moving in a fog 
where I don't really see where I'm going - so I don't claim to be right.


But somehow I have the feeling we're talking about similar things here :-)

If you look in the second patch, you'll see that there are already the three 
(or 4 in the case of the s3c2416) interrupt controllers defined [intc, 
subintc, extintc]. But as they contain the data of their individual interrupts 
inside the devicetree definitions, they don't need individual init functions 
but only one which constructs the interrupt data out of the list provided.

The real list for a platform in the second patch might also help in showing 
why this list was necessary.

The basic problem is, that each individual interrupt inside one of the 
controllers might need a different handler and access a specific parent 
interrupt. For example the uart0-rx,tx,err interrupts in the subintc must 
ack/mask the uart0 interrupt in the main intc; similar for a lot of other 
interrupts. And the s3c24xx,irqlist provides this mapping to handler and 
parent, so it does not need to be codified.

And of course the second problem this approach should solve is, that the 
interrupts in the controllers differ and also move between most of the s3c24xx 
sub-architectures.


Thanks
Heiko
Thomas Abraham Nov. 27, 2012, 6:12 a.m. UTC | #5
On 26 November 2012 21:34, Heiko Stübner <heiko@sntech.de> wrote:
> Hi Thomas,
>
> Am Montag, 26. November 2012, 16:23:00 schrieb Thomas Abraham:
>> On 26 November 2012 17:43, Heiko Stübner <heiko@sntech.de> wrote:
>> > Hi Thomas,
>> >
>> > Am Montag, 26. November 2012, 12:03:22 schrieb Thomas Abraham:
>> >> Hi Heiko,
>> >>
>> >> On 25 November 2012 06:17, Heiko Stübner <heiko@sntech.de> wrote:
>> >> > This adds devicetree parsing of the controller-data for the
>> >> > interrupt controllers on S3C24XX architectures.
>> >> >
>> >> > Signed-off-by: Heiko Stuebner <heiko@sntech.de>
>> >> > ---
>> >> >
>> >> >  .../interrupt-controller/samsung,s3c24xx-irq.txt   |   57 ++++++
>> >> >  arch/arm/mach-s3c24xx/common.h                     |    1 +
>> >> >  arch/arm/plat-s3c24xx/irq.c                        |  197
>> >> >  ++++++++++++++++++++ 3 files changed, 255 insertions(+), 0
>> >> >  deletions(-) create mode 100644
>> >> >  Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24x
>> >> >  x- irq.txt
>> >> >
>> >> > diff --git
>> >> > a/Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24
>> >> > xx -irq.txt
>> >> > b/Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24
>> >> > xx -irq.txt new file mode 100644
>> >> > index 0000000..c637637
>> >> > --- /dev/null
>> >> > +++
>> >> > b/Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24
>> >> > xx -irq.txt @@ -0,0 +1,57 @@
>> >> > +Samsung S3C24XX Interrupt Controllers
>> >> > +
>> >> > +The S3C24XX SoCs contain custom set of interrupt controllers
>> >> > providing a +varying number of interrupt sources.
>> >> > +
>> >> > +The set consists of a main- and a sub-controller as well as a
>> >> > controller +for the external interrupts and on newer SoCs even a
>> >> > second main controller. +
>> >> > +The bit-to-interrupt and parent mapping of the controllers is not
>> >> > fixed +over all SoCs and therefore must be defined in the controller
>> >> > description. +
>> >> > +Required properties:
>> >> > +- compatible: Compatible property value should be
>> >> > "samsung,s3c24xx-irq". +
>> >> > +- reg: Physical base address of the controller and length of memory
>> >> > mapped +  region.
>> >> > +
>> >> > +- interrupt-controller : Identifies the node as an interrupt
>> >> > controller +- #interrupt-cells : Specifies the number of cells needed
>> >> > to encode an +  interrupt source. The value shall be 2.
>> >> > +
>> >> > +- s3c24xx,irqlist : List of irqtypes found on this controller as
>> >> > +  two-value pairs consisting of irqtype and parent-irq
>> >> > +
>> >> > +  parent-irq is always the list position of the irq in the irqlist
>> >> > +  of the parent controller (0..31)
>> >> > +
>> >> > +  irqtypes are:
>> >> > +  - 0 .. none
>> >> > +  - 1 .. external interrupts in the main register (GPF0 .. GPF3)
>> >> > +  - 2 .. edge irq in the main register
>> >> > +  - 3 .. for parent-irqs, that have sub-irqs in child controllers
>> >> > +  - 4 .. level irqs in the sub-register
>> >> > +  - 5 .. edge irqs in the sub-register
>> >> > +  - 6 .. external irqs in the external irq register (starting with
>> >> > GPF4) +  - 7 .. irq in the second base irq controller of
>> >> > S3C2416/S3C2450 SoCs
>> >>
>> >> Instead of defining the type of interrupt controller as above, is it
>> >> possible to create multiple device nodes, with each node representing
>> >> a type of interrupt controller with a unique compatible string and
>> >> corresponding properties. There will be a init function for each type
>> >> of interrupt controller. There should be a irq-domain for each of
>> >> these different types of interrupt controller. And then, in the device
>> >> tree source file, a proper tree like hierarchy of interrupt
>> >> controllers can defined (using the interrupt-parent property for each
>> >> controller node). The client nodes that generate the interrupt can
>> >> specify the parent node and the interrupt number within the parent to
>> >> which they generate the interrupt.
>> >
>> > I'm not sure I understand yet :-). The list describes the types of
>> > interrupts inside the individual controllers.
>> >
>> > On all the s3c24xx we have three register sets denoting the main (SRCPND,
>> > INTPND, INTMSK), sub (SUBSRCPEND, INTSUBMASK) and extint (EINTPEND,
>> > EINTMASK) controllers. The bits of these registers are used for quite
>> > different irqs.
>>
>> We could consider main, sub and extint as three separate interrupt
>> controllers and thus three different nodes in device tree. So the
>> interrupt nodes could be something like (referring to 2416 manual).
>>
>>      main@0x4a000000 {
>>             compatible = "samsung,s3c2410-main";
>>             reg = <0x4a000000 0x100>;
>>             interrupt-controller;
>>             #interrupt-cells = <2>;
>>      };
>>
>>      sub@0x4a001000 {
>>             compatible = "samsung,s3c2410-sub";
>>             reg = <0x4a001000 0x100>;
>>             interrupt-controller;
>>             #interrupt-cells = <2>;
>>             interrupt-parent = <&main>;
>>             interrupts = <28 0>, <23 0>, <.....  /*uart0/uart1/..*/
>>      };
>>
>>      eint@0x4a002000 {
>>             compatible = "samsung,s3c2410-eint";
>>             reg = <0x4a002000 0x100>;
>>             interrupt-controller;
>>             #interrupt-cells = <2>;
>>             interrupt-parent = <&main>;
>>             interrupts = <0 0>, <1 0>,
>>                               <2 0>, <3 0>,
>>                               <4 0>, <5 0>;
>>      };
>>
>> There should be a corresponding irqchip driver code to handle each of
>> these types of controllers. They should have their own irq-domain
>> supported.
>>
>> Then the client nodes can specify the interrupt parent and interrupt
>> number. For example, the uart node would be
>>
>>        uart@50000000 {
>>             compatible = "samsung,s3c2410-uart";
>>             reg = <0x50000000 0x100>;
>>             interrupt-parent = <&sub>;
>>             interrupts = <0 0>, <1 0>, <2 0>; /*tx/rx/err*/
>>        };
>>
>> > For example is bit 17 of the main register set used as DMA0 on earlier
>> > socs while the dma interrupts moved to the subint registers for s3c2443
>> > and later.
>>
>> Writing the nodes with the correct interrupt parent and the interrupt
>> number should take care of this.
>>
>> > So the entries in the irqlist describe the needed handlers for the hwirq
>> > bits of the indidual controllers. So in this scheme you set for
>> > dt-devices the interrupt parent to the correct register set and the
>> > interrupts field then matches the bit of the register, according to the
>> > datasheet.
>> >
>> > When I changed the basic interrupt handling in the previous set, the
>> > changed irq.c can for exmaple be found on [0], I created these lists in
>> > the code and soc specific routines to init them for the still valid
>> > non-dt case.
>> >
>> > But as dt is about describing the hardware, I found the current solution
>> > nice, because will I only need exactly one dt-init-function for all
>> > s3c24xx-socs, instead of representing all the slight variances in code.
>> >
>> > I'm definitly not sure if all the different types of individual irq
>> > handlers are strictly necessary yet, but they represent all the variants
>> > that were in use in the original code.
>>
>> I have brought up this point just for discussion. You could choose the
>> implementation that you prefer. I understand that implementing with
>> different interrupt controller nodes might require lot of code
>> changes.
>
> first of all, thanks for the feedback. Working on this is like moving in a fog
> where I don't really see where I'm going - so I don't claim to be right.

>
>
> But somehow I have the feeling we're talking about similar things here :-)
>
> If you look in the second patch, you'll see that there are already the three
> (or 4 in the case of the s3c2416) interrupt controllers defined [intc,
> subintc, extintc]. But as they contain the data of their individual interrupts
> inside the devicetree definitions, they don't need individual init functions
> but only one which constructs the interrupt data out of the list provided.
>
> The real list for a platform in the second patch might also help in showing
> why this list was necessary.

Ok, I had not looked at the second patch carefully enough. There are
four interrupt controller nodes but I am still not sure if the
bindings for those nodes are correct. The question here is, did we
design the binding to suit a specific linux implementation of the
interrupt controller. Ideally, the bindings should just be enough to
explain the interconnection between the interrupt controller and the
client devices. And should be OS agnostic as much as possible. The
seven irqtypes in the binding definition seems to suggest that we are
encoding a software defined abstraction into the binding, which does
not seem right.

>
> The basic problem is, that each individual interrupt inside one of the
> controllers might need a different handler and access a specific parent
> interrupt. For example the uart0-rx,tx,err interrupts in the subintc must
> ack/mask the uart0 interrupt in the main intc; similar for a lot of other
> interrupts. And the s3c24xx,irqlist provides this mapping to handler and
> parent, so it does not need to be codified.

I believe the three node example that I listed above should be able to
handle this, but yes, it might require additional code to support it.
For example, the uart device node has listed three interrupts. The
uart controller drivers can register three separate interrupt handlers
for these interrupts. As far as the interrupt handling for 'main'
controller, I see that this is very similar to the way interrupt
combiner module has been coded for exynos soc's. So the combiner
interrupt controller code in mach-exynos/common.c file can be used a
reference on how this can be handled.

>
> And of course the second problem this approach should solve is, that the
> interrupts in the controllers differ and also move between most of the s3c24xx
> sub-architectures.

Yes, I understand how difficult it can get while writing a generalized
code for all soc's in s3c24xx family.

Thanks,
Thomas.
Heiko Stuebner Nov. 27, 2012, 4:24 p.m. UTC | #6
Am Dienstag, 27. November 2012, 07:12:52 schrieb Thomas Abraham:
> On 26 November 2012 21:34, Heiko Stübner <heiko@sntech.de> wrote:
> > Hi Thomas,
> > 
> > Am Montag, 26. November 2012, 16:23:00 schrieb Thomas Abraham:
> >> On 26 November 2012 17:43, Heiko Stübner <heiko@sntech.de> wrote:
> >> > Hi Thomas,
> >> > 
> >> > Am Montag, 26. November 2012, 12:03:22 schrieb Thomas Abraham:
> >> >> Hi Heiko,
> >> >> 
> >> >> On 25 November 2012 06:17, Heiko Stübner <heiko@sntech.de> wrote:
> >> >> > This adds devicetree parsing of the controller-data for the
> >> >> > interrupt controllers on S3C24XX architectures.
> >> >> > 
> >> >> > Signed-off-by: Heiko Stuebner <heiko@sntech.de>
> >> >> > ---
> >> >> > 
> >> >> >  .../interrupt-controller/samsung,s3c24xx-irq.txt   |   57 ++++++
> >> >> >  arch/arm/mach-s3c24xx/common.h                     |    1 +
> >> >> >  arch/arm/plat-s3c24xx/irq.c                        |  197
> >> >> >  ++++++++++++++++++++ 3 files changed, 255 insertions(+), 0
> >> >> >  deletions(-) create mode 100644
> >> >> >  Documentation/devicetree/bindings/interrupt-controller/samsung,s3c
> >> >> >  24x x- irq.txt
> >> >> > 
> >> >> > diff --git
> >> >> > a/Documentation/devicetree/bindings/interrupt-controller/samsung,s3
> >> >> > c24 xx -irq.txt
> >> >> > b/Documentation/devicetree/bindings/interrupt-controller/samsung,s3
> >> >> > c24 xx -irq.txt new file mode 100644
> >> >> > index 0000000..c637637
> >> >> > --- /dev/null
> >> >> > +++
> >> >> > b/Documentation/devicetree/bindings/interrupt-controller/samsung,s3
> >> >> > c24 xx -irq.txt @@ -0,0 +1,57 @@
> >> >> > +Samsung S3C24XX Interrupt Controllers
> >> >> > +
> >> >> > +The S3C24XX SoCs contain custom set of interrupt controllers
> >> >> > providing a +varying number of interrupt sources.
> >> >> > +
> >> >> > +The set consists of a main- and a sub-controller as well as a
> >> >> > controller +for the external interrupts and on newer SoCs even a
> >> >> > second main controller. +
> >> >> > +The bit-to-interrupt and parent mapping of the controllers is not
> >> >> > fixed +over all SoCs and therefore must be defined in the
> >> >> > controller description. +
> >> >> > +Required properties:
> >> >> > +- compatible: Compatible property value should be
> >> >> > "samsung,s3c24xx-irq". +
> >> >> > +- reg: Physical base address of the controller and length of
> >> >> > memory mapped +  region.
> >> >> > +
> >> >> > +- interrupt-controller : Identifies the node as an interrupt
> >> >> > controller +- #interrupt-cells : Specifies the number of cells
> >> >> > needed to encode an +  interrupt source. The value shall be 2.
> >> >> > +
> >> >> > +- s3c24xx,irqlist : List of irqtypes found on this controller as
> >> >> > +  two-value pairs consisting of irqtype and parent-irq
> >> >> > +
> >> >> > +  parent-irq is always the list position of the irq in the irqlist
> >> >> > +  of the parent controller (0..31)
> >> >> > +
> >> >> > +  irqtypes are:
> >> >> > +  - 0 .. none
> >> >> > +  - 1 .. external interrupts in the main register (GPF0 .. GPF3)
> >> >> > +  - 2 .. edge irq in the main register
> >> >> > +  - 3 .. for parent-irqs, that have sub-irqs in child controllers
> >> >> > +  - 4 .. level irqs in the sub-register
> >> >> > +  - 5 .. edge irqs in the sub-register
> >> >> > +  - 6 .. external irqs in the external irq register (starting with
> >> >> > GPF4) +  - 7 .. irq in the second base irq controller of
> >> >> > S3C2416/S3C2450 SoCs
> >> >> 
> >> >> Instead of defining the type of interrupt controller as above, is it
> >> >> possible to create multiple device nodes, with each node representing
> >> >> a type of interrupt controller with a unique compatible string and
> >> >> corresponding properties. There will be a init function for each type
> >> >> of interrupt controller. There should be a irq-domain for each of
> >> >> these different types of interrupt controller. And then, in the
> >> >> device tree source file, a proper tree like hierarchy of interrupt
> >> >> controllers can defined (using the interrupt-parent property for each
> >> >> controller node). The client nodes that generate the interrupt can
> >> >> specify the parent node and the interrupt number within the parent to
> >> >> which they generate the interrupt.
> >> > 
> >> > I'm not sure I understand yet :-). The list describes the types of
> >> > interrupts inside the individual controllers.
> >> > 
> >> > On all the s3c24xx we have three register sets denoting the main
> >> > (SRCPND, INTPND, INTMSK), sub (SUBSRCPEND, INTSUBMASK) and extint
> >> > (EINTPEND, EINTMASK) controllers. The bits of these registers are
> >> > used for quite different irqs.
> >> 
> >> We could consider main, sub and extint as three separate interrupt
> >> controllers and thus three different nodes in device tree. So the
> >> interrupt nodes could be something like (referring to 2416 manual).
> >> 
> >>      main@0x4a000000 {
> >>      
> >>             compatible = "samsung,s3c2410-main";
> >>             reg = <0x4a000000 0x100>;
> >>             interrupt-controller;
> >>             #interrupt-cells = <2>;
> >>      
> >>      };
> >>      
> >>      sub@0x4a001000 {
> >>      
> >>             compatible = "samsung,s3c2410-sub";
> >>             reg = <0x4a001000 0x100>;
> >>             interrupt-controller;
> >>             #interrupt-cells = <2>;
> >>             interrupt-parent = <&main>;
> >>             interrupts = <28 0>, <23 0>, <.....  /*uart0/uart1/..*/
> >>      
> >>      };
> >>      
> >>      eint@0x4a002000 {
> >>      
> >>             compatible = "samsung,s3c2410-eint";
> >>             reg = <0x4a002000 0x100>;
> >>             interrupt-controller;
> >>             #interrupt-cells = <2>;
> >>             interrupt-parent = <&main>;
> >>             interrupts = <0 0>, <1 0>,
> >>             
> >>                               <2 0>, <3 0>,
> >>                               <4 0>, <5 0>;
> >>      
> >>      };
> >> 
> >> There should be a corresponding irqchip driver code to handle each of
> >> these types of controllers. They should have their own irq-domain
> >> supported.
> >> 
> >> Then the client nodes can specify the interrupt parent and interrupt
> >> number. For example, the uart node would be
> >> 
> >>        uart@50000000 {
> >>        
> >>             compatible = "samsung,s3c2410-uart";
> >>             reg = <0x50000000 0x100>;
> >>             interrupt-parent = <&sub>;
> >>             interrupts = <0 0>, <1 0>, <2 0>; /*tx/rx/err*/
> >>        
> >>        };
> >> > 
> >> > For example is bit 17 of the main register set used as DMA0 on earlier
> >> > socs while the dma interrupts moved to the subint registers for
> >> > s3c2443 and later.
> >> 
> >> Writing the nodes with the correct interrupt parent and the interrupt
> >> number should take care of this.
> >> 
> >> > So the entries in the irqlist describe the needed handlers for the
> >> > hwirq bits of the indidual controllers. So in this scheme you set for
> >> > dt-devices the interrupt parent to the correct register set and the
> >> > interrupts field then matches the bit of the register, according to
> >> > the datasheet.
> >> > 
> >> > When I changed the basic interrupt handling in the previous set, the
> >> > changed irq.c can for exmaple be found on [0], I created these lists
> >> > in the code and soc specific routines to init them for the still
> >> > valid non-dt case.
> >> > 
> >> > But as dt is about describing the hardware, I found the current
> >> > solution nice, because will I only need exactly one dt-init-function
> >> > for all s3c24xx-socs, instead of representing all the slight
> >> > variances in code.
> >> > 
> >> > I'm definitly not sure if all the different types of individual irq
> >> > handlers are strictly necessary yet, but they represent all the
> >> > variants that were in use in the original code.
> >> 
> >> I have brought up this point just for discussion. You could choose the
> >> implementation that you prefer. I understand that implementing with
> >> different interrupt controller nodes might require lot of code
> >> changes.
> > 
> > first of all, thanks for the feedback. Working on this is like moving in
> > a fog where I don't really see where I'm going - so I don't claim to be
> > right.
> > 
> > 
> > 
> > But somehow I have the feeling we're talking about similar things here
> > :-)
> > 
> > If you look in the second patch, you'll see that there are already the
> > three (or 4 in the case of the s3c2416) interrupt controllers defined
> > [intc, subintc, extintc]. But as they contain the data of their
> > individual interrupts inside the devicetree definitions, they don't need
> > individual init functions but only one which constructs the interrupt
> > data out of the list provided.
> > 
> > The real list for a platform in the second patch might also help in
> > showing why this list was necessary.
> 
> Ok, I had not looked at the second patch carefully enough. There are
> four interrupt controller nodes but I am still not sure if the
> bindings for those nodes are correct. The question here is, did we
> design the binding to suit a specific linux implementation of the
> interrupt controller. Ideally, the bindings should just be enough to
> explain the interconnection between the interrupt controller and the
> client devices. And should be OS agnostic as much as possible. The
> seven irqtypes in the binding definition seems to suggest that we are
> encoding a software defined abstraction into the binding, which does
> not seem right.


Because of the mails from yesterday I took another look at my code, after 
letting it sit for the previous days and I found more optimization 
possiblities.

It should be possible to trim the irqtypes down to level,edge and eint types 
and do the gathering of the other informations in the code. This would make 
the list more os-agnostic.
The list itself does describe the interconnections between the controllers, so 
I think it's not false per se, just the multitude of probably redundant types 
used should probably go down.


The other option could be to really change to individual initializers for the 
different implementations and have all the data in the code instead of the dt. 
For this I've compared all the different implementations and it seems this 
would lead to at least handlers for s3c2410, s3c2440, s3c2442, s3c2412 and 
s3c2443. For the time being they will be in the code in any case, because of 
all the non-dt boards 

If anyone is interested, the comparison can be found on [0].


Btw. do you know if it would have bad effects to register (but not use) for 
example the cam interrupt-handler on a machine that does not have it. (The 
additional cam, cf and spi1 interrupts are the only things differing between 
the s3c2443 and s3c2416 SoCs).


> > The basic problem is, that each individual interrupt inside one of the
> > controllers might need a different handler and access a specific parent
> > interrupt. For example the uart0-rx,tx,err interrupts in the subintc must
> > ack/mask the uart0 interrupt in the main intc; similar for a lot of other
> > interrupts. And the s3c24xx,irqlist provides this mapping to handler and
> > parent, so it does not need to be codified.
> 
> I believe the three node example that I listed above should be able to
> handle this, but yes, it might require additional code to support it.
> For example, the uart device node has listed three interrupts. The
> uart controller drivers can register three separate interrupt handlers
> for these interrupts. As far as the interrupt handling for 'main'
> controller, I see that this is very similar to the way interrupt
> combiner module has been coded for exynos soc's. So the combiner
> interrupt controller code in mach-exynos/common.c file can be used a
> reference on how this can be handled.

I'v seen the combiner code as well, but from the code itself I've not managed 
to understand the combiner this well yet. And Exynos datasheets, to get a 
textual description of the combiner, are not this easy to come by ;-) .


> > And of course the second problem this approach should solve is, that the
> > interrupts in the controllers differ and also move between most of the
> > s3c24xx sub-architectures.
> 
> Yes, I understand how difficult it can get while writing a generalized
> code for all soc's in s3c24xx family.

again, thanks for taking the time to read and answer all these mails :-)


Thanks
Heiko


[0] 
https://docs.google.com/spreadsheet/pub?key=0Am5FJAmTa7wydENkdkwwRVA5eEVTb09fb0RtcGhnTlE&output=html
Thomas Abraham Nov. 28, 2012, 2:10 p.m. UTC | #7
Hi Heiko,

On 27 November 2012 21:54, Heiko Stübner <heiko@sntech.de> wrote:

[...]

>
>
> Because of the mails from yesterday I took another look at my code, after
> letting it sit for the previous days and I found more optimization
> possiblities.
>
> It should be possible to trim the irqtypes down to level,edge and eint types
> and do the gathering of the other informations in the code. This would make
> the list more os-agnostic.
> The list itself does describe the interconnections between the controllers, so
> I think it's not false per se, just the multitude of probably redundant types
> used should probably go down.

Ok.

>
> The other option could be to really change to individual initializers for the
> different implementations and have all the data in the code instead of the dt.
> For this I've compared all the different implementations and it seems this
> would lead to at least handlers for s3c2410, s3c2440, s3c2442, s3c2412 and
> s3c2443. For the time being they will be in the code in any case, because of
> all the non-dt boards

I did feel that it this could have been handled with dt + some kernel
code for all s3c24xx soc's but probably I am under estimating the
effort here. If it helps, the dt code need not be intermixed with
non-dt code and there can be runtime check on whether to take dt and
non-dt path.

>
> If anyone is interested, the comparison can be found on [0].
>
>
> Btw. do you know if it would have bad effects to register (but not use) for
> example the cam interrupt-handler on a machine that does not have it. (The
> additional cam, cf and spi1 interrupts are the only things differing between
> the s3c2443 and s3c2416 SoCs).

I am not aware of any bad effects of this (if those interrupts are
never enabled). But logically, it might be better not to do this. Is
this something that cannot be handled by checking the machine
compatible value.

>
>

[...]

>
> I'v seen the combiner code as well, but from the code itself I've not managed
> to understand the combiner this well yet. And Exynos datasheets, to get a
> textual description of the combiner, are not this easy to come by ;-) .

Yes, I understand. Basically interrupt combiner combines upto 8
interrupts into one interrupt that is delivered to combiner's
interrupt parent, which is the gic interrupt controller in case of
exynos. There are 16 to 32 interrupt combiners in a soc. Combiner has
the basic mask, pend and unmask registers.

Thanks,
Thomas.

[...]
diff mbox

Patch

diff --git a/Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24xx-irq.txt b/Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24xx-irq.txt
new file mode 100644
index 0000000..c637637
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24xx-irq.txt
@@ -0,0 +1,57 @@ 
+Samsung S3C24XX Interrupt Controllers
+
+The S3C24XX SoCs contain custom set of interrupt controllers providing a
+varying number of interrupt sources.
+
+The set consists of a main- and a sub-controller as well as a controller
+for the external interrupts and on newer SoCs even a second main controller.
+
+The bit-to-interrupt and parent mapping of the controllers is not fixed
+over all SoCs and therefore must be defined in the controller description.
+
+Required properties:
+- compatible: Compatible property value should be "samsung,s3c24xx-irq".
+
+- reg: Physical base address of the controller and length of memory mapped
+  region.
+
+- interrupt-controller : Identifies the node as an interrupt controller
+- #interrupt-cells : Specifies the number of cells needed to encode an
+  interrupt source. The value shall be 2.
+
+- s3c24xx,irqlist : List of irqtypes found on this controller as
+  two-value pairs consisting of irqtype and parent-irq
+
+  parent-irq is always the list position of the irq in the irqlist
+  of the parent controller (0..31)
+
+  irqtypes are:
+  - 0 .. none
+  - 1 .. external interrupts in the main register (GPF0 .. GPF3)
+  - 2 .. edge irq in the main register
+  - 3 .. for parent-irqs, that have sub-irqs in child controllers
+  - 4 .. level irqs in the sub-register
+  - 5 .. edge irqs in the sub-register
+  - 6 .. external irqs in the external irq register (starting with GPF4)
+  - 7 .. irq in the second base irq controller of S3C2416/S3C2450 SoCs
+
+Optional properties:
+- interrupt_parent : The parent interrupt controller
+
+Example:
+
+	intc2:interrupt-controller@4a000040 {
+		compatible = "samsung,s3c24xx-irq";
+		reg = <0x4a000040 0x18>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+
+		s3c24xx,irqlist = <7 0 /* 2D */
+				   7 0 /* IIC1 */
+				   0 0 /* reserved */
+				   0 0 /* reserved */
+				   7 0 /* PCM0 */
+				   7 0 /* PCM1 */
+				   7 0 /* I2S0 */
+				   7 0>; /* I2S1 */
+	};
diff --git a/arch/arm/mach-s3c24xx/common.h b/arch/arm/mach-s3c24xx/common.h
index ed6276f..7a7b770 100644
--- a/arch/arm/mach-s3c24xx/common.h
+++ b/arch/arm/mach-s3c24xx/common.h
@@ -16,5 +16,6 @@  void s3c2410_restart(char mode, const char *cmd);
 void s3c244x_restart(char mode, const char *cmd);
 
 extern struct syscore_ops s3c24xx_irq_syscore_ops;
+extern void s3c24xx_init_irq_of(void);
 
 #endif /* __ARCH_ARM_MACH_S3C24XX_COMMON_H */
diff --git a/arch/arm/plat-s3c24xx/irq.c b/arch/arm/plat-s3c24xx/irq.c
index 0510627..4f8fe4a 100644
--- a/arch/arm/plat-s3c24xx/irq.c
+++ b/arch/arm/plat-s3c24xx/irq.c
@@ -25,6 +25,9 @@ 
 #include <linux/slab.h>
 
 #include <linux/irqdomain.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
 
 #include <asm/irq.h>
 #include <asm/mach/irq.h>
@@ -956,3 +959,197 @@  void __init s3c2443_init_irq(void)
 	s3c24xx_init_irq();
 }
 #endif
+
+#ifdef CONFIG_OF
+static int __init s3c24xx_init_intc_of(struct device_node *np,
+				       struct device_node *interrupt_parent)
+{
+	struct s3c_irq_intc *intc;
+	struct s3c_irq_intc *parent;
+	struct s3c_irq_data *irq_data;
+	struct property *intc_prop;
+	int irq_num = 0, irq_start = 0, irq_offset = 0;
+	int ret, i, cnt;
+	const __be32 *p;
+	u32 val;
+
+	intc = kzalloc(sizeof(struct s3c_irq_intc), GFP_KERNEL);
+	if (!intc)
+		return -ENOMEM;
+
+	p = of_get_address(np, 0, NULL, NULL);
+	if (!p) {
+		pr_err("irq: register address missing\n");
+		ret = -EINVAL;
+		goto err_addr;
+	}
+
+	/* select the correct data for the controller.
+	 * Need to hard code the irq num start and offset
+	 * to preserve the static mapping for now
+	 */
+	switch (of_translate_address(np, p)) {
+	case 0x4a000000:
+		pr_debug("irq: found main intc\n");
+		intc->reg_pending = S3C2410_SRCPND;
+		intc->reg_intpnd = S3C2410_INTPND;
+		intc->reg_mask = S3C2410_INTMSK;
+		irq_num = 32;
+		irq_start = S3C2410_IRQ(0);
+		irq_offset = 0;
+		break;
+	case 0x560000a4:
+		pr_debug("irq: found extintc\n");
+		intc->reg_pending = S3C2410_EINTPEND;
+		intc->reg_mask = S3C2410_EINTMASK;
+		irq_num = 20;
+		irq_start = S3C2410_IRQ(32);
+		irq_offset = 4;
+		break;
+	case 0x4a000018:
+		pr_debug("irq: found subintc\n");
+		intc->reg_pending = S3C2410_SUBSRCPND;
+		intc->reg_mask = S3C2410_INTSUBMSK;
+		irq_num = 29;
+		irq_start = S3C2410_IRQSUB(0);
+		irq_offset = 0;
+		break;
+	case 0x4a000040:
+		pr_debug("irq: found intc2\n");
+		intc->reg_pending = S3C2416_SRCPND2;
+		intc->reg_intpnd = S3C2416_INTPND2;
+		intc->reg_mask = S3C2416_INTMSK2;
+		irq_num = 8;
+		irq_start = S3C2416_IRQ(0);
+		irq_offset = 0;
+		break;
+	case 0:
+		pr_err("irq: couldn't translate address\n");
+		ret = -EINVAL;
+		goto err_addr;
+	default:
+		pr_err("irq: unsupported controller address\n");
+		ret = -EINVAL;
+		goto err_addr;
+	}
+
+	irq_data = kzalloc(sizeof(struct s3c_irq_data) * 32, GFP_KERNEL);
+	if (!irq_data) {
+		ret = -ENOMEM;
+		goto err_addr;
+	}
+
+	cnt = 0;
+	intc_prop = of_find_property(np, "s3c24xx,irqlist", NULL);
+	if (!intc_prop) {
+		pr_err("irq: irqlist not found\n");
+		ret = -EINVAL;
+		goto err_data;
+	}
+
+	/* build the irq_data list */
+	p = NULL;
+	for (i = 0; i < 32; i++) {
+		p = of_prop_next_u32(intc_prop, p, &val);
+
+		/* when we hit the first non-valid element, assume it's
+		 * the end of the list. The rest of the fields are
+		 * already of type S3C_IRQTYPE_NONE (value 0)
+		 */
+		if (!p)
+			break;
+
+		irq_data[i].type = val;
+
+		p = of_prop_next_u32(intc_prop, p, &val);
+		if (!p) {
+			pr_warn("irq: uneven number of elements in irqlist, last value will be dropped\n");
+			irq_data[i].type = 0;
+			break;
+		}
+
+		irq_data[i].parent_irq = val;
+
+		pr_debug("irq: found hwirq %d with type %d and parent %lu\n",
+			 i, irq_data[i].type, irq_data[i].parent_irq);
+		cnt++;
+	}
+
+	/* if we haven't found any irq definition at all,
+	 * something is very wrong.
+	 */
+	if (!cnt) {
+		pr_err("irq: empty irq definition\n");
+		ret = -EINVAL;
+		goto err_data;
+	}
+
+	intc->irqs = irq_data;
+
+	/* put the intc into the dt as property, so we can access it from
+	 * as the interrupt_parent later
+	 */
+
+	intc_prop = kzalloc(sizeof(struct property), GFP_KERNEL);
+	if (!intc_prop) {
+		ret = -ENOMEM;
+		goto err_data;
+	}
+
+	intc_prop->name = kstrdup("s3c-irq-intc", GFP_KERNEL);
+	intc_prop->value = intc;
+	intc_prop->length = sizeof(struct s3c_irq_intc);
+
+	ret = prom_add_property(np, intc_prop);
+	if (ret) {
+		pr_err("irq: failed to add dt property\n");
+		goto err_prop;
+	}
+
+	/* set the parent relationship */
+	if (interrupt_parent) {
+		parent = (struct s3c_irq_intc *)of_get_property(
+				      interrupt_parent, "s3c-irq-intc", NULL);
+		if (!parent) {
+			pr_err("irq: no parent for non-root controller found\n");
+			goto err_domain;
+		}
+
+		intc->parent = parent;
+	}
+
+	/* now that all the data is complete, init the irq-domain */
+	s3c24xx_clear_intc(intc);
+	intc->domain = irq_domain_add_legacy(np, irq_num, irq_start,
+					     irq_offset, &s3c24xx_irq_ops,
+					     intc);
+	if (!intc->domain) {
+		pr_err("irq: could not create irq-domain\n");
+		ret = -EINVAL;
+		goto err_domain;
+	}
+
+	return 0;
+
+err_domain:
+	prom_remove_property(np, intc_prop);
+err_prop:
+	kfree(intc_prop);
+err_data:
+	kfree(irq_data);
+err_addr:
+	kfree(intc);
+
+	return ret;
+}
+
+static const struct of_device_id s3c24xx_irq_match[] __initconst = {
+	{ .compatible = "samsung,s3c24xx-irq", .data = s3c24xx_init_intc_of, },
+	{ /* sentinel */ }
+};
+
+void __init s3c24xx_init_irq_of(void)
+{
+	of_irq_init(s3c24xx_irq_match);
+}
+#endif