From 9dbd90f17e4f380593ec5194c2a4d5e52c5f72d1 Mon Sep 17 00:00:00 2001 From: Sebastian Hesselbarth Date: Thu, 6 Jun 2013 18:27:09 +0200 Subject: irqchip: Add support for Marvell Orion SoCs 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 Acked-by: Grant Likely Cc: Rob Herring Cc: Rob Landley Cc: John Stultz Cc: Russell King Cc: Jason Cooper Cc: Andrew Lunn Cc: Thomas Petazzoni Cc: Gregory Clement Cc: devicetree-discuss@lists.ozlabs.org Cc: linux-arm-kernel@lists.infradead.org Link: http://lkml.kernel.org/r/1370536034-23956-2-git-send-email-sebastian.hesselbarth@gmail.com Signed-off-by: Thomas Gleixner --- .../interrupt-controller/marvell,orion-intc.txt | 48 ++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/marvell,orion-intc.txt (limited to 'Documentation') 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 000000000000..2c11ac76fac9 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/marvell,orion-intc.txt @@ -0,0 +1,48 @@ +Marvell Orion SoC interrupt controllers + +* 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>; + }; + +* Bridge interrupt controller + +Required properties: +- compatible: shall be "marvell,orion-bridge-intc" +- reg: base address of bridge interrupt registers starting with CAUSE register +- interrupts: bridge interrupt of the main interrupt controller +- interrupt-controller: identifies the node as an interrupt controller +- #interrupt-cells: number of cells to encode an interrupt source, shall be 1 + +Optional properties: +- marvell,#interrupts: number of interrupts provided by bridge interrupt + controller, defaults to 32 if not set + +Example: + bridge_intc: interrupt-controller { + compatible = "marvell,orion-bridge-intc"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x20110 0x8>; + interrupts = <0>; + /* Dove bridge provides 5 interrupts */ + marvell,#interrupts = <5>; + }; -- cgit v1.2.3 From b06eb0173ef1d9366d14b4ca3e8e38dc72b03e8b Mon Sep 17 00:00:00 2001 From: Christian Ruppert Date: Tue, 25 Jun 2013 18:29:57 +0200 Subject: irqchip: Add TB10x interrupt controller driver The SOC interrupt controller driver for the Abilis Systems TB10x series of SOCs based on ARC700 CPUs. Signed-off-by: Christian Ruppert Signed-off-by: Pierrick Hascoet Cc: Vineet Gupta Cc: Grant Likely Cc: Rob Herring Cc: Rob Landley Cc: devicetree-discuss@lists.ozlabs.org Link: http://lkml.kernel.org/r/1372177797-9458-1-git-send-email-christian.ruppert@abilis.com Signed-off-by: Thomas Gleixner --- .../interrupt-controller/abilis,tb10x-ictl.txt | 38 ++++ drivers/irqchip/Kconfig | 5 + drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-tb10x.c | 195 +++++++++++++++++++++ 4 files changed, 239 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/abilis,tb10x-ictl.txt create mode 100644 drivers/irqchip/irq-tb10x.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/interrupt-controller/abilis,tb10x-ictl.txt b/Documentation/devicetree/bindings/interrupt-controller/abilis,tb10x-ictl.txt new file mode 100644 index 000000000000..9d52d5afe3e9 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/abilis,tb10x-ictl.txt @@ -0,0 +1,38 @@ +TB10x Top Level Interrupt Controller +==================================== + +The Abilis TB10x SOC contains a custom interrupt controller. It performs +one-to-one mapping of external interrupt sources to CPU interrupts and +provides support for reconfigurable trigger modes. + +Required properties +------------------- + +- compatible: Should be "abilis,tb10x-ictl" +- reg: specifies physical base address and size of register range. +- interrupt-congroller: Identifies the node as an interrupt controller. +- #interrupt cells: Specifies the number of cells used to encode an interrupt + source connected to this controller. The value shall be 2. +- interrupt-parent: Specifies the parent interrupt controller. +- interrupts: Specifies the list of interrupt lines which are handled by + the interrupt controller in the parent controller's notation. Interrupts + are mapped one-to-one to parent interrupts. + +Example +------- + +intc: interrupt-controller { /* Parent interrupt controller */ + interrupt-controller; + #interrupt-cells = <1>; /* For example below */ + /* ... */ +}; + +tb10x_ictl: pic@2000 { /* TB10x interrupt controller */ + compatible = "abilis,tb10x-ictl"; + reg = <0x2000 0x20>; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&intc>; + interrupts = <5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 + 20 21 22 23 24 25 26 27 28 29 30 31>; +}; diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 68c31071968d..d4d1f4bde10b 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -38,6 +38,11 @@ config RENESAS_IRQC bool select IRQ_DOMAIN +config TB10X_IRQC + bool + select IRQ_DOMAIN + select GENERIC_IRQ_CHIP + config VERSATILE_FPGA_IRQ bool select IRQ_DOMAIN diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 55df3bdf804d..8fe6ad57ee4b 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -17,3 +17,4 @@ obj-$(CONFIG_RENESAS_INTC_IRQPIN) += irq-renesas-intc-irqpin.o obj-$(CONFIG_RENESAS_IRQC) += irq-renesas-irqc.o obj-$(CONFIG_VERSATILE_FPGA_IRQ) += irq-versatile-fpga.o obj-$(CONFIG_ARCH_VT8500) += irq-vt8500.o +obj-$(CONFIG_TB10X_IRQC) += irq-tb10x.o diff --git a/drivers/irqchip/irq-tb10x.c b/drivers/irqchip/irq-tb10x.c new file mode 100644 index 000000000000..7c44c99bf1f2 --- /dev/null +++ b/drivers/irqchip/irq-tb10x.c @@ -0,0 +1,195 @@ +/* + * Abilis Systems interrupt controller driver + * + * Copyright (C) Abilis Systems 2012 + * + * Author: Christian Ruppert + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "irqchip.h" + +#define AB_IRQCTL_INT_ENABLE 0x00 +#define AB_IRQCTL_INT_STATUS 0x04 +#define AB_IRQCTL_SRC_MODE 0x08 +#define AB_IRQCTL_SRC_POLARITY 0x0C +#define AB_IRQCTL_INT_MODE 0x10 +#define AB_IRQCTL_INT_POLARITY 0x14 +#define AB_IRQCTL_INT_FORCE 0x18 + +#define AB_IRQCTL_MAXIRQ 32 + +static inline void ab_irqctl_writereg(struct irq_chip_generic *gc, u32 reg, + u32 val) +{ + irq_reg_writel(val, gc->reg_base + reg); +} + +static inline u32 ab_irqctl_readreg(struct irq_chip_generic *gc, u32 reg) +{ + return irq_reg_readl(gc->reg_base + reg); +} + +static int tb10x_irq_set_type(struct irq_data *data, unsigned int flow_type) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); + uint32_t im, mod, pol; + + im = data->mask; + + irq_gc_lock(gc); + + mod = ab_irqctl_readreg(gc, AB_IRQCTL_SRC_MODE) | im; + pol = ab_irqctl_readreg(gc, AB_IRQCTL_SRC_POLARITY) | im; + + switch (flow_type & IRQF_TRIGGER_MASK) { + case IRQ_TYPE_EDGE_FALLING: + pol ^= im; + break; + case IRQ_TYPE_LEVEL_HIGH: + mod ^= im; + break; + case IRQ_TYPE_NONE: + flow_type = IRQ_TYPE_LEVEL_LOW; + case IRQ_TYPE_LEVEL_LOW: + mod ^= im; + pol ^= im; + break; + case IRQ_TYPE_EDGE_RISING: + break; + default: + irq_gc_unlock(gc); + pr_err("%s: Cannot assign multiple trigger modes to IRQ %d.\n", + __func__, data->irq); + return -EBADR; + } + + irqd_set_trigger_type(data, flow_type); + irq_setup_alt_chip(data, flow_type); + + ab_irqctl_writereg(gc, AB_IRQCTL_SRC_MODE, mod); + ab_irqctl_writereg(gc, AB_IRQCTL_SRC_POLARITY, pol); + ab_irqctl_writereg(gc, AB_IRQCTL_INT_STATUS, im); + + irq_gc_unlock(gc); + + return IRQ_SET_MASK_OK; +} + +static void tb10x_irq_cascade(unsigned int irq, struct irq_desc *desc) +{ + struct irq_domain *domain = irq_desc_get_handler_data(desc); + + generic_handle_irq(irq_find_mapping(domain, irq)); +} + +static int __init of_tb10x_init_irq(struct device_node *ictl, + struct device_node *parent) +{ + int i, ret, nrirqs = of_irq_count(ictl); + struct resource mem; + struct irq_chip_generic *gc; + struct irq_domain *domain; + void __iomem *reg_base; + + if (of_address_to_resource(ictl, 0, &mem)) { + pr_err("%s: No registers declared in DeviceTree.\n", + ictl->name); + return -EINVAL; + } + + if (!request_mem_region(mem.start, resource_size(&mem), + ictl->name)) { + pr_err("%s: Request mem region failed.\n", ictl->name); + return -EBUSY; + } + + reg_base = ioremap(mem.start, resource_size(&mem)); + if (!reg_base) { + ret = -EBUSY; + pr_err("%s: ioremap failed.\n", ictl->name); + goto ioremap_fail; + } + + domain = irq_domain_add_linear(ictl, AB_IRQCTL_MAXIRQ, + &irq_generic_chip_ops, NULL); + if (!domain) { + ret = -ENOMEM; + pr_err("%s: Could not register interrupt domain.\n", + ictl->name); + goto irq_domain_add_fail; + } + + ret = irq_alloc_domain_generic_chips(domain, AB_IRQCTL_MAXIRQ, + 2, ictl->name, handle_level_irq, + IRQ_NOREQUEST, IRQ_NOPROBE, + IRQ_GC_INIT_MASK_CACHE); + if (ret) { + pr_err("%s: Could not allocate generic interrupt chip.\n", + ictl->name); + goto gc_alloc_fail; + } + + gc = domain->gc->gc[0]; + gc->reg_base = reg_base; + + gc->chip_types[0].type = IRQ_TYPE_LEVEL_MASK; + gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit; + gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit; + gc->chip_types[0].chip.irq_set_type = tb10x_irq_set_type; + gc->chip_types[0].regs.mask = AB_IRQCTL_INT_ENABLE; + + gc->chip_types[1].type = IRQ_TYPE_EDGE_BOTH; + gc->chip_types[1].chip.name = gc->chip_types[0].chip.name; + gc->chip_types[1].chip.irq_ack = irq_gc_ack_set_bit; + gc->chip_types[1].chip.irq_mask = irq_gc_mask_clr_bit; + gc->chip_types[1].chip.irq_unmask = irq_gc_mask_set_bit; + gc->chip_types[1].chip.irq_set_type = tb10x_irq_set_type; + gc->chip_types[1].regs.ack = AB_IRQCTL_INT_STATUS; + gc->chip_types[1].regs.mask = AB_IRQCTL_INT_ENABLE; + gc->chip_types[1].handler = handle_edge_irq; + + for (i = 0; i < nrirqs; i++) { + unsigned int irq = irq_of_parse_and_map(ictl, i); + + irq_set_handler_data(irq, domain); + irq_set_chained_handler(irq, tb10x_irq_cascade); + } + + ab_irqctl_writereg(gc, AB_IRQCTL_INT_ENABLE, 0); + ab_irqctl_writereg(gc, AB_IRQCTL_INT_MODE, 0); + ab_irqctl_writereg(gc, AB_IRQCTL_INT_POLARITY, 0); + ab_irqctl_writereg(gc, AB_IRQCTL_INT_STATUS, ~0UL); + + return 0; + +gc_alloc_fail: + irq_domain_remove(domain); +irq_domain_add_fail: + iounmap(reg_base); +ioremap_fail: + release_mem_region(mem.start, resource_size(&mem)); + return ret; +} +IRQCHIP_DECLARE(tb10x_intc, "abilis,tb10x-ictl", of_tb10x_init_irq); -- cgit v1.2.3 From ccc414f83914178c7ab04ac4d4f0331fe4c37231 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 28 Jun 2013 11:45:15 +0200 Subject: genirq: Add the generic chip to the genirq docbook Signed-off-by: Thomas Gleixner Cc: Randy Dunlap --- Documentation/DocBook/genericirq.tmpl | 13 +++++++++++++ kernel/irq/generic-chip.c | 11 ++++++----- 2 files changed, 19 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/genericirq.tmpl b/Documentation/DocBook/genericirq.tmpl index b3422341d65c..d16d21b7a3b7 100644 --- a/Documentation/DocBook/genericirq.tmpl +++ b/Documentation/DocBook/genericirq.tmpl @@ -464,6 +464,19 @@ if (desc->irq_data.chip->irq_eoi) protected via desc->lock, by the generic layer. + + + Generic interrupt chip + + To avoid copies of identical implementations of irq chips the + core provides a configurable generic interrupt chip + implementation. Developers should check carefuly whether the + generic chip fits their needs before implementing the same + functionality slightly different themself. + +!Ekernel/irq/generic-chip.c + + Structures diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c index 76ea748324f5..1c39eccc1eaf 100644 --- a/kernel/irq/generic-chip.c +++ b/kernel/irq/generic-chip.c @@ -45,7 +45,7 @@ void irq_gc_mask_disable_reg(struct irq_data *d) } /** - * irq_gc_mask_set_mask_bit - Mask chip via setting bit in mask register + * irq_gc_mask_set_bit - Mask chip via setting bit in mask register * @d: irq_data * * Chip has a single mask register. Values of this register are cached @@ -65,7 +65,7 @@ void irq_gc_mask_set_bit(struct irq_data *d) EXPORT_SYMBOL_GPL(irq_gc_mask_set_bit); /** - * irq_gc_mask_set_mask_bit - Mask chip via clearing bit in mask register + * irq_gc_mask_clr_bit - Mask chip via clearing bit in mask register * @d: irq_data * * Chip has a single mask register. Values of this register are cached @@ -167,7 +167,8 @@ void irq_gc_eoi(struct irq_data *d) /** * irq_gc_set_wake - Set/clr wake bit for an interrupt - * @d: irq_data + * @d: irq_data + * @on: Indicates whether the wake bit should be set or cleared * * For chips where the wake from suspend functionality is not * configured in a separate register and the wakeup active state is @@ -339,7 +340,7 @@ EXPORT_SYMBOL_GPL(irq_get_domain_generic_chip); */ static struct lock_class_key irq_nested_lock_class; -/** +/* * irq_map_generic_chip - Map a generic chip for an irq domain */ static int irq_map_generic_chip(struct irq_domain *d, unsigned int virq, @@ -454,7 +455,7 @@ EXPORT_SYMBOL_GPL(irq_setup_generic_chip); /** * irq_setup_alt_chip - Switch to alternative chip * @d: irq_data for this interrupt - * @type Flow type to be initialized + * @type: Flow type to be initialized * * Only to be called from chip->irq_set_type() callbacks. */ -- cgit v1.2.3