From patchwork Sun Nov 25 00:47:41 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?q?Heiko_St=C3=BCbner?= X-Patchwork-Id: 1801701 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork2.kernel.org (Postfix) with ESMTP id 5B058DF230 for ; Mon, 26 Nov 2012 10:57:15 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1TcwJc-0002cI-2P; Mon, 26 Nov 2012 10:53:28 +0000 Received: from gloria.sntech.de ([95.129.55.99]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1TcQNz-0001UB-Of for linux-arm-kernel@lists.infradead.org; Sun, 25 Nov 2012 00:47:53 +0000 Received: from 146-52-36-227-dynip.superkabel.de ([146.52.36.227] helo=marty.localnet) by gloria.sntech.de with esmtpsa (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.72) (envelope-from ) id 1TcQNr-0007lr-Ls; Sun, 25 Nov 2012 01:47:43 +0100 From: Heiko =?utf-8?q?St=C3=BCbner?= To: Grant Likely , Rob Herring , Kukjin Kim Subject: [RFC 1/2] ARM: S3C24XX: add devicetree support for interrupts Date: Sun, 25 Nov 2012 01:47:41 +0100 User-Agent: KMail/1.13.7 (Linux/3.2.0-3-686-pae; KDE/4.8.4; i686; ; ) References: <201211250145.21226.heiko@sntech.de> In-Reply-To: <201211250145.21226.heiko@sntech.de> MIME-Version: 1.0 Message-Id: <201211250147.42164.heiko@sntech.de> X-Bad-Reply: References and In-Reply-To but no 'Re:' in Subject. X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20121124_194751_972286_8BB838EF X-CRM114-Status: GOOD ( 27.13 ) X-Spam-Score: -2.6 (--) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-2.6 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] X-Mailman-Approved-At: Mon, 26 Nov 2012 05:53:24 -0500 Cc: devicetree-discuss@lists.ozlabs.org, linux-samsung-soc@vger.kernel.org, linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org This adds devicetree parsing of the controller-data for the interrupt controllers on S3C24XX architectures. Signed-off-by: Heiko Stuebner --- .../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 + +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 #include +#include +#include +#include #include #include @@ -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