From patchwork Thu May 2 23:48:35 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sebastian Hesselbarth X-Patchwork-Id: 2514171 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) by patchwork2.kernel.org (Postfix) with ESMTP id 79CBEDF215 for ; Thu, 2 May 2013 23:50:11 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1UY3Fu-00053X-8u; Thu, 02 May 2013 23:49:42 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1UY3Fj-0004Td-T1; Thu, 02 May 2013 23:49:31 +0000 Received: from mail-bk0-x230.google.com ([2a00:1450:4008:c01::230]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1UY3FZ-0004Qt-8Q for linux-arm-kernel@lists.infradead.org; Thu, 02 May 2013 23:49:24 +0000 Received: by mail-bk0-f48.google.com with SMTP id jf3so494990bkc.21 for ; Thu, 02 May 2013 16:48:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=x-received:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references; bh=YTdr95pTqQoiHOSJI+/qOIY/JWwGxLNbOnvs/g/heFI=; b=V38i+bpmTcazN0cdoDHydhF3A3hxddKd3hhXxmRYHyjnMZmp+skepgtvzdYmVZ4MHk VZlWAN1wHa7XFFzJ6qODAxT/vWwNFvvaQ13/HhrvF7cJO9uAsDn7xpbUn8aR9bUUIuEs N5Rjj0kAdQWagXyKKaFK6IQrqC49i2OvXEBVZkQOExj1W6sKP/ff2xY9p5BzXC+9TrRf 7Vus8+03stR6ccE47w2y85s3wy3HGdDcM5Ys55cQSm2OMa03HP+ozanwd0arqaJDnw1x f8EPRjY65lYJDzirMXNU3r5OxQ2EJZsaqEfEFj3OEiCU//dMrCAkrknnQi0DonjJqjhB /uaw== X-Received: by 10.204.199.70 with SMTP id er6mr2736631bkb.122.1367538539142; Thu, 02 May 2013 16:48:59 -0700 (PDT) Received: from topkick.lan (dslc-082-083-251-181.pools.arcor-ip.net. [82.83.251.181]) by mx.google.com with ESMTPSA id iy11sm1866479bkb.11.2013.05.02.16.48.57 for (version=TLSv1.2 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 02 May 2013 16:48:58 -0700 (PDT) Received: from edge.lan (magicgate.lan [192.168.1.1]) by topkick.lan (Postfix) with ESMTPSA id 1E89C60471; Fri, 3 May 2013 01:48:32 +0200 (CEST) From: Sebastian Hesselbarth To: Sebastian Hesselbarth Subject: [PATCH v2 1/5] irqchip: add support for Marvell Orion SoCs Date: Fri, 3 May 2013 01:48:35 +0200 Message-Id: <1367538519-23940-2-git-send-email-sebastian.hesselbarth@gmail.com> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1367538519-23940-1-git-send-email-sebastian.hesselbarth@gmail.com> References: <1367519104-19677-1-git-send-email-sebastian.hesselbarth@gmail.com> <1367538519-23940-1-git-send-email-sebastian.hesselbarth@gmail.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130502_194921_651351_BCCE2BB4 X-CRM114-Status: GOOD ( 24.80 ) X-Spam-Score: -2.0 (--) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-2.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider (sebastian.hesselbarth[at]gmail.com) -0.0 SPF_PASS SPF: sender matches SPF record -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature Cc: Thomas Petazzoni , Andrew Lunn , Russell King , Jason Cooper , Arnd Bergmann , Jean-Francois Moine , devicetree-discuss@lists.ozlabs.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, Rob Herring , Jason Gunthorpe , Gregory Clement , Rob Landley , Grant Likely , Thomas Gleixner , Ezequiel Garcia , linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org This patch adds an irqchip driver for the main interrupt controller found on Marvell Orion SoCs (Kirkwood, Dove, Orion5x, Discovery Innovation). Corresponding device tree documentation is also added. Signed-off-by: Sebastian Hesselbarth --- Note: This patch triggers a checkpatch warning for WARNING: Avoid CamelCase: Changelog: v1->v2: - rename compatible string to "marvell,orion-intc" (Suggested by Jason Gunthorpe) - request mem regions for irq base registers (Suggested by Jason Gunthorpe) - make orion_handle_irq static (Suggested by Jason Gunthorpe) - make use of IRQCHIP_DECLARE (Suggested by Jason Gunthorpe) Cc: Grant Likely Cc: Rob Herring Cc: Rob Landley Cc: Thomas Gleixner Cc: Russell King Cc: Arnd Bergmann Cc: Jason Cooper Cc: Andrew Lunn Cc: Jason Gunthorpe Cc: Thomas Petazzoni Cc: Gregory Clement Cc: Ezequiel Garcia Cc: Jean-Francois Moine Cc: devicetree-discuss@lists.ozlabs.org Cc: linux-doc@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org --- .../interrupt-controller/marvell,orion-intc.txt | 22 ++++ drivers/irqchip/Kconfig | 5 + drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-orion.c | 133 ++++++++++++++++++++ 4 files changed, 161 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/marvell,orion-intc.txt create mode 100644 drivers/irqchip/irq-orion.c diff --git a/Documentation/devicetree/bindings/interrupt-controller/marvell,orion-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/marvell,orion-intc.txt new file mode 100644 index 0000000..9b7aee9 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/marvell,orion-intc.txt @@ -0,0 +1,22 @@ +Marvell Orion SoC main interrupt controller + +Required properties: +- compatible: shall be "marvell,orion-intc" +- reg: base address(es) of interrupt registers starting with CAUSE register +- interrupt-controller: identifies the node as an interrupt controller +- #interrupt-cells: number of cells to encode an interrupt source, shall be 1. + +The interrupt sources map to the corresponding bits in the interrupt +registers, i.e. +- 0 maps to bit 0 of first base address, +- 1 maps to bit 1 of first base address, +- 32 maps to bit 0 of second base address, and so on. + +Example: + intc: interrupt-controller { + compatible = "marvell,orion-intc"; + interrupt-controller; + #interrupt-cells = <1>; + /* Dove has 64 first level interrupts */ + reg = <0x20200 0x10>, <0x20210 0x10>; + }; diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index a350969..8da3559 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -2,6 +2,11 @@ config IRQCHIP def_bool y depends on OF_IRQ +config IRQCHIP_ORION + bool + select IRQ_DOMAIN + select MULTI_IRQ_HANDLER + config ARM_GIC bool select IRQ_DOMAIN diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 10ef57f..2cad23d 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_ARCH_EXYNOS) += exynos-combiner.o obj-$(CONFIG_ARCH_MXS) += irq-mxs.o obj-$(CONFIG_METAG) += irq-metag-ext.o obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o +obj-$(CONFIG_IRQCHIP_ORION) += irq-orion.o obj-$(CONFIG_ARCH_SUNXI) += irq-sun4i.o obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o obj-$(CONFIG_ARM_GIC) += irq-gic.o diff --git a/drivers/irqchip/irq-orion.c b/drivers/irqchip/irq-orion.c new file mode 100644 index 0000000..21ebe6c --- /dev/null +++ b/drivers/irqchip/irq-orion.c @@ -0,0 +1,133 @@ +/* + * Marvell Orion SoCs IRQ chip driver. + * + * Sebastian Hesselbarth + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "irqchip.h" + +/* max number of handled irq register blocks */ +#define ORION_MAX_IRQREG 2 + +#define ORION_IRQ_CAUSE 0x00 +#define ORION_IRQ_MASK 0x04 +#define ORION_IRQ_FIQ_MASK 0x08 +#define ORION_IRQ_ENDP_MASK 0x0c + +static void __iomem *orion_irq_base[ORION_MAX_IRQREG]; +static unsigned int orion_irq_regs; +static struct irq_domain *orion_irq_domain; + +static asmlinkage void __exception_irq_entry orion_handle_irq( + struct pt_regs *regs) +{ + int n; + for (n = 0; n < orion_irq_regs; n++) { + u32 hwirq_base = n * 32; + u32 stat = readl_relaxed(orion_irq_base[n] + ORION_IRQ_CAUSE) & + readl_relaxed(orion_irq_base[n] + ORION_IRQ_MASK); + while (stat) { + u32 hwirq = ffs(stat) - 1; + u32 irq = irq_find_mapping(orion_irq_domain, + hwirq_base + hwirq); + handle_IRQ(irq, regs); + stat &= ~(1 << hwirq); + } + } +} + +static void orion_irq_mask(struct irq_data *irqd) +{ + unsigned int irq = irqd_to_hwirq(irqd); + unsigned int irq_off = irq % 32; + int reg = irq / 32; + u32 val; + + val = readl(orion_irq_base[reg] + ORION_IRQ_MASK); + writel(val & ~(1 << irq_off), orion_irq_base[reg] + ORION_IRQ_MASK); +} + +static void orion_irq_unmask(struct irq_data *irqd) +{ + unsigned int irq = irqd_to_hwirq(irqd); + unsigned int irq_off = irq % 32; + int reg = irq / 32; + u32 val; + + val = readl(orion_irq_base[reg] + ORION_IRQ_MASK); + writel(val | (1 << irq_off), orion_irq_base[reg] + ORION_IRQ_MASK); +} + +static struct irq_chip orion_irq_chip = { + .name = "orion_irq", + .irq_mask = orion_irq_mask, + .irq_unmask = orion_irq_unmask, +}; + +static int orion_irq_map(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hw) +{ + irq_set_chip_and_handler(virq, &orion_irq_chip, + handle_level_irq); + set_irq_flags(virq, IRQF_VALID | IRQF_PROBE); + + return 0; +} + +static struct irq_domain_ops orion_irq_ops = { + .map = orion_irq_map, + .xlate = irq_domain_xlate_onecell, +}; + +static int __init orion_of_init(struct device_node *np, + struct device_node *parent) +{ + int n; + + for (n = 0; n < ORION_MAX_IRQREG; n++) { + struct resource r; + + /* parsing reg property may fail silently here */ + if (of_address_to_resource(np, n, &r)) + continue; + + if (!request_mem_region(r.start, resource_size(&r), np->name)) + panic("%s: unable to request mem region %d", + np->full_name, n); + + orion_irq_base[n] = ioremap(r.start, resource_size(&r)); + if (!orion_irq_base[n]) + panic("%s: unable to map resource %d", + np->full_name, n); + + /* mask all interrupts */ + writel(0, orion_irq_base[n] + ORION_IRQ_MASK); + orion_irq_regs++; + } + + /* at least one irq reg must be set */ + if (!orion_irq_regs) + panic("%s: unable to map IRQC registers\n", np->full_name); + + orion_irq_domain = irq_domain_add_linear(np, orion_irq_regs * 32, + &orion_irq_ops, NULL); + if (!orion_irq_domain) + panic("%s: unable to create IRQ domain\n", np->full_name); + + set_handle_irq(orion_handle_irq); + + return 0; +} +IRQCHIP_DECLARE(orion_intc, "marvell,orion-intc", orion_of_init);