[PATCH] arm: exynos4: Add support for dt irq specifier to linux virq conversion
Grant Likely
grant.likely at secretlab.ca
Sun Jul 31 13:46:53 EST 2011
On Wed, Jul 27, 2011 at 11:54:28PM +0530, Thomas Abraham wrote:
> Exynos4 includes two interrupt controllers - External GIC and External
> Interrupt Combiner. External GIC can handle 16 software generated
> interrupts (SGI), 16 Private Peripheral Interrupts (PPI) and 128
> Shared Peripheral Interrupts (SPI). External Interrupt Combiner manages
> 32 groups of 8 interrupts each and feeds 32 interrupts as SPI interrupts
> to the External GIC controller.
>
> This patch supports conversion of device tree interrupt specifier to
> linux virq domain for both the interrupt controllers. The concept of
> this patch is derived from Grant's 'simple' irq converter.
>
> This patch is based on Grant's following patchset
> [PATCH v3 0/2] Simple irq_domain implementation
>
> Signed-off-by: Thomas Abraham <thomas.abraham at linaro.org>
> ---
> Documentation/devicetree/bindings/arm/samsung.txt | 72 +++++++++++++
> arch/arm/mach-exynos4/Makefile | 1 +
> arch/arm/mach-exynos4/include/mach/irqs.h | 3 +
> arch/arm/mach-exynos4/irqdomain.c | 117 +++++++++++++++++++++
> arch/arm/mach-exynos4/mach-exynos4-dt.c | 8 +-
> 5 files changed, 196 insertions(+), 5 deletions(-)
> create mode 100644 arch/arm/mach-exynos4/irqdomain.c
>
> diff --git a/Documentation/devicetree/bindings/arm/samsung.txt b/Documentation/devicetree/bindings/arm/samsung.txt
> index 5676bca..878aa01 100644
> --- a/Documentation/devicetree/bindings/arm/samsung.txt
> +++ b/Documentation/devicetree/bindings/arm/samsung.txt
> @@ -6,3 +6,75 @@ Required root node properties:
> - compatible = "samsung,smdkv310", "samsung,exynos4210'.
> (a) "samsung,smdkv310" - for Samsung's SMDKV310 eval board.
> (b) "samsung,exynos4210" - for boards based on Exynos4210 processor.
> +
> +
> +Exynos4 Interrupt Controllers
> +-----------------------------
> +
> +Samsung's Exynos4 architecture includes two interrupt controllers.
> + - External GIC
> + - External Interrupt Combiner.
> +
> +The external GIC can manage
> + - 16 Software Generated Interrupts (SGI).
> + - 16 Private Peripheral Interrupts (PPI).
> + - 128 Shared Peripheral Interrupts (SPI).
> +
> +Out of the 128 Shared Peripheral Interrupts (SPI's), 32 interrupts
> +are sourced from a interrupt combiner. The interrupt combiner provides
> +32 groups of interrupts with a maximum of 8 interrupts combined per
> +group.
> +
> +External GIC properties:
> + - compatible: should be "samsung,exynos4-ext-gic".
> + - interrupt-cells: should be <2>. The meaning of the cells are
> + * First Cell: Interrupt Number.
> + * Second Cell: Type of Interrupt (0-SPI, 1-SGI, 2-PPI).
Type should probably be the first cell. That's how this has been
handled in the past for other hardware. Also, the gic binding is
going to be shared for a bunch of ARM hardware, not just Exynos. Can
you split this patch into two parts; one for gic and one for the
exynos combiner?
> + - reg: The GIC includes a Distributor Interface and CPU Interface and
> + hence requires two base addresses. The property format is
> + <Distributor-Base Distributor-Size>, <CPU-Base CPU Size>
> +
> + Example:
> +
> + EXT_GIC:interrupt-controller at 10490000 {
> + compatible = "samsung,exynos4-ext-gic";
> + #interrupt-cells = <2>;
> + interrupt-controller;
> + reg = <0x10490000 0x1000>, <0x10480000 0x100>;
> + };
> +
> + Devices using External GIC as the interrupt parent should specify two
> + cells for the interrupts property as shown below.
> +
> + watchdog at 10060000 {
> + compatible = "samsung,s3c2410-wdt";
> + reg = <0x10060000 0x400>;
> + interrupt-parent = <&EXT_GIC>;
> + interrupts = <43 0>;
> + };
> +
> +External Interrupt Combiner properties:
> + - compatible: should be "samsung,exynos4-ext-combiner".
> + - interrupt-cells: should be <2>. The meaning of the cells are
> + * First Cell: Combiner Group Number.
> + * Second Cell: Interrupt within the group.
I was under the impression that the irq groupings are programmable,
and that the combiner irq inputs are a flat numbering layout. Is that
correct? If so, then #interrupt-cells should probably be 1, and the
grouping should probably be configuration properties on the combiner
node.
> + - reg: Base address and size of interrupt combiner registers.
> +
> + Example:
> +
> + EXT_COMBINER:interrupt-controller at 10440000 {
> + compatible = "samsung,exynos4-ext-combiner";
> + #interrupt-cells = <2>;
> + interrupt-controller;
> + reg = <0x10440000 0x200>;
> + };
> +
> + Devices using External Interrupt Combiner as the interrupt parent should
> + specify two cells for the interrupts property as shown below.
> +
> + watchdog at 10060000 {
> + compatible = "samsung,s3c2410-wdt";
> + reg = <0x10060000 0x400>;
> + interrupt-parent = <&EXT_COMBINER>;
> + interrupts = <4 2>;
> + };
> diff --git a/arch/arm/mach-exynos4/Makefile b/arch/arm/mach-exynos4/Makefile
> index ac91f4f..fd532c7 100644
> --- a/arch/arm/mach-exynos4/Makefile
> +++ b/arch/arm/mach-exynos4/Makefile
> @@ -32,6 +32,7 @@ obj-$(CONFIG_MACH_ARMLEX4210) += mach-armlex4210.o
> obj-$(CONFIG_MACH_UNIVERSAL_C210) += mach-universal_c210.o
> obj-$(CONFIG_MACH_NURI) += mach-nuri.o
> obj-$(CONFIG_MACH_EXYNOS4_DT) += mach-exynos4-dt.o
> +obj-$(CONFIG_OF_IRQ) += irqdomain.o
>
> # device support
>
> diff --git a/arch/arm/mach-exynos4/include/mach/irqs.h b/arch/arm/mach-exynos4/include/mach/irqs.h
> index 934d2a4..c120aad 100644
> --- a/arch/arm/mach-exynos4/include/mach/irqs.h
> +++ b/arch/arm/mach-exynos4/include/mach/irqs.h
> @@ -15,6 +15,9 @@
>
> #include <plat/irqs.h>
>
> +/* SGI: Software Generated Interrupt */
> +#define IRQ_SGI(x) S5P_IRQ(x)
> +
> /* PPI: Private Peripheral Interrupt */
>
> #define IRQ_PPI(x) S5P_IRQ(x+16)
> diff --git a/arch/arm/mach-exynos4/irqdomain.c b/arch/arm/mach-exynos4/irqdomain.c
> new file mode 100644
> index 0000000..f50fa20
> --- /dev/null
> +++ b/arch/arm/mach-exynos4/irqdomain.c
> @@ -0,0 +1,117 @@
> +/*
> + * Exynos4 irq domain conversion from dt irq specifier to linux virq domain
> + *
> + * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
> + * http://www.samsung.com
> + *
> + * Exynos4 includes two interrupt controllers - External GIC and External
> + * Interrupt Combiner. This file provides support for converting interrupt
> + * specified in device tree to linux virq domain for both the controllers.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> +*/
> +
> +#include <linux/irq.h>
> +#include <linux/irqdomain.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/slab.h>
> +
> +#include <mach/irqs.h>
> +
> +/*
> + * The interrupt specifier for External GIC controller uses to two cells in
> + * the device tree source file. The second cell denotes the type of the
> + * interrupt (SPI/SGI/PPI). The following macros are used to represent
> + * these different types of interrupt.
> + */
> +#define EXT_GIC_SPI 0
> +#define EXT_GIC_SGI 1
> +#define EXT_GIC_PPI 2
Nit: I prefer enums over preprocessor macros, but not a big deal.
> +
> +/* Translate dt irq specifier to linux virq for external GIC controller */
> +static int exynos4_irq_domain_ext_gic_dt_translate(struct irq_domain *d,
> + struct device_node *controller,
> + const u32 *intspec, unsigned int intsize,
> + unsigned long *out_hwirq, unsigned int *out_type)
> +{
> + if (d->of_node != controller)
> + return -EINVAL;
> + if (intsize < 2)
> + return -EINVAL;
> +
> + switch (intspec[1]) {
> + case EXT_GIC_SPI:
> + *out_hwirq = IRQ_SPI(intspec[0]);
> + break;
> + case EXT_GIC_SGI:
> + *out_hwirq = IRQ_SGI(intspec[0]);
> + break;
> + case EXT_GIC_PPI:
> + *out_hwirq = IRQ_PPI(intspec[0]);
> + break;
> + default:
> + pr_info("irq_domain register: invalid ext gic intr type\n");
> + return -EINVAL;
> + }
> +
> + *out_type = IRQ_TYPE_NONE;
> + return 0;
> +}
> +
> +/* Translate dt irq specifier to linux virq for external combiner controller */
> +static int exynos4_irq_domain_ext_combiner_dt_translate(struct irq_domain *d,
> + struct device_node *controller,
> + const u32 *intspec, unsigned int intsize,
> + unsigned long *out_hwirq, unsigned int *out_type)
> +{
> + if (d->of_node != controller)
> + return -EINVAL;
> + if (intsize < 2)
> + return -EINVAL;
> +
> + *out_hwirq = COMBINER_IRQ(intspec[0], intspec[1]);
> + *out_type = IRQ_TYPE_NONE;
> + return 0;
> +}
> +
> +static struct irq_domain_ops exynos4_irq_domain_ext_gic_ops = {
> + .dt_translate = exynos4_irq_domain_ext_gic_dt_translate,
> +};
> +
> +static struct irq_domain_ops exynos4_irq_domain_ext_combiner_ops = {
> + .dt_translate = exynos4_irq_domain_ext_combiner_dt_translate,
> +};
> +
> +static struct of_device_id exynos4_irq_ctrl_of_match[] = {
> + { .compatible = "samsung,exynos4-ext-gic",
> + .data = &exynos4_irq_domain_ext_gic_ops, },
> + { .compatible = "samsung,exynos4-ext-combiner",
> + .data = &exynos4_irq_domain_ext_combiner_ops, },
> + {},
> +};
> +
> +void exynos4_register_irq_domain_dt(void)
> +{
> + struct device_node *controller;
> + struct irq_domain *domain;
> + const struct of_device_id *match;
> +
> + for_each_matching_node(controller, exynos4_irq_ctrl_of_match) {
> + domain = kzalloc(sizeof(*domain), GFP_KERNEL);
> + if (!domain) {
> + WARN_ON(1);
> + return;
> + }
> +
> + match = of_match_node(exynos4_irq_ctrl_of_match, controller);
> + domain->of_node = of_node_get(controller);
> + domain->ops = match->data;
> + irq_domain_add(domain);
> + }
> +}
> +EXPORT_SYMBOL_GPL(exynos4_register_irq_domain_dt);
> diff --git a/arch/arm/mach-exynos4/mach-exynos4-dt.c b/arch/arm/mach-exynos4/mach-exynos4-dt.c
> index 120665a..450a9ed 100644
> --- a/arch/arm/mach-exynos4/mach-exynos4-dt.c
> +++ b/arch/arm/mach-exynos4/mach-exynos4-dt.c
> @@ -16,6 +16,7 @@
> #include <linux/io.h>
> #include <linux/of_platform.h>
> #include <linux/irq.h>
> +#include <linux/irqdomain.h>
>
> #include <asm/mach/arch.h>
> #include <asm/mach-types.h>
> @@ -85,14 +86,11 @@ static void __init exynos4_dt_map_io(void)
> s3c24xx_init_uarts(smdkv310_uartcfgs, ARRAY_SIZE(smdkv310_uartcfgs));
> }
>
> -static const struct of_device_id intc_of_match[] __initconst = {
> - { .compatible = "samsung,exynos4-gic", },
> - {}
> -};
> +extern void exynos4_register_irq_domain_dt(void);
>
> static void __init exynos4_dt_machine_init(void)
> {
> - irq_domain_generate_simple(intc_of_match, EXYNOS4_PA_GIC_DIST, 0);
> + exynos4_register_irq_domain_dt();
> of_platform_populate(NULL, of_default_bus_match_table,
> exynos4_auxdata_lookup, NULL);
> }
> --
> 1.6.6.rc2
>
More information about the devicetree-discuss
mailing list