diff options
| -rw-r--r-- | Documentation/devicetree/bindings/interrupt-controller/marvell,orion-intc.txt | 48 | ||||
| -rw-r--r-- | drivers/irqchip/Kconfig | 5 | ||||
| -rw-r--r-- | drivers/irqchip/Makefile | 1 | ||||
| -rw-r--r-- | drivers/irqchip/irq-orion.c | 192 |
4 files changed, 246 insertions, 0 deletions
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 @@ | |||
| 1 | Marvell Orion SoC interrupt controllers | ||
| 2 | |||
| 3 | * Main interrupt controller | ||
| 4 | |||
| 5 | Required properties: | ||
| 6 | - compatible: shall be "marvell,orion-intc" | ||
| 7 | - reg: base address(es) of interrupt registers starting with CAUSE register | ||
| 8 | - interrupt-controller: identifies the node as an interrupt controller | ||
| 9 | - #interrupt-cells: number of cells to encode an interrupt source, shall be 1 | ||
| 10 | |||
| 11 | The interrupt sources map to the corresponding bits in the interrupt | ||
| 12 | registers, i.e. | ||
| 13 | - 0 maps to bit 0 of first base address, | ||
| 14 | - 1 maps to bit 1 of first base address, | ||
| 15 | - 32 maps to bit 0 of second base address, and so on. | ||
| 16 | |||
| 17 | Example: | ||
| 18 | intc: interrupt-controller { | ||
| 19 | compatible = "marvell,orion-intc"; | ||
| 20 | interrupt-controller; | ||
| 21 | #interrupt-cells = <1>; | ||
| 22 | /* Dove has 64 first level interrupts */ | ||
| 23 | reg = <0x20200 0x10>, <0x20210 0x10>; | ||
| 24 | }; | ||
| 25 | |||
| 26 | * Bridge interrupt controller | ||
| 27 | |||
| 28 | Required properties: | ||
| 29 | - compatible: shall be "marvell,orion-bridge-intc" | ||
| 30 | - reg: base address of bridge interrupt registers starting with CAUSE register | ||
| 31 | - interrupts: bridge interrupt of the main interrupt controller | ||
| 32 | - interrupt-controller: identifies the node as an interrupt controller | ||
| 33 | - #interrupt-cells: number of cells to encode an interrupt source, shall be 1 | ||
| 34 | |||
| 35 | Optional properties: | ||
| 36 | - marvell,#interrupts: number of interrupts provided by bridge interrupt | ||
| 37 | controller, defaults to 32 if not set | ||
| 38 | |||
| 39 | Example: | ||
| 40 | bridge_intc: interrupt-controller { | ||
| 41 | compatible = "marvell,orion-bridge-intc"; | ||
| 42 | interrupt-controller; | ||
| 43 | #interrupt-cells = <1>; | ||
| 44 | reg = <0x20110 0x8>; | ||
| 45 | interrupts = <0>; | ||
| 46 | /* Dove bridge provides 5 interrupts */ | ||
| 47 | marvell,#interrupts = <5>; | ||
| 48 | }; | ||
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 4a33351c25dc..68c31071968d 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig | |||
| @@ -25,6 +25,11 @@ config ARM_VIC_NR | |||
| 25 | The maximum number of VICs available in the system, for | 25 | The maximum number of VICs available in the system, for |
| 26 | power management. | 26 | power management. |
| 27 | 27 | ||
| 28 | config ORION_IRQCHIP | ||
| 29 | bool | ||
| 30 | select IRQ_DOMAIN | ||
| 31 | select MULTI_IRQ_HANDLER | ||
| 32 | |||
| 28 | config RENESAS_INTC_IRQPIN | 33 | config RENESAS_INTC_IRQPIN |
| 29 | bool | 34 | bool |
| 30 | select IRQ_DOMAIN | 35 | select IRQ_DOMAIN |
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index cda4cb5f7327..55df3bdf804d 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile | |||
| @@ -7,6 +7,7 @@ obj-$(CONFIG_ARCH_MXS) += irq-mxs.o | |||
| 7 | obj-$(CONFIG_ARCH_S3C24XX) += irq-s3c24xx.o | 7 | obj-$(CONFIG_ARCH_S3C24XX) += irq-s3c24xx.o |
| 8 | obj-$(CONFIG_METAG) += irq-metag-ext.o | 8 | obj-$(CONFIG_METAG) += irq-metag-ext.o |
| 9 | obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o | 9 | obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o |
| 10 | obj-$(CONFIG_ORION_IRQCHIP) += irq-orion.o | ||
| 10 | obj-$(CONFIG_ARCH_SUNXI) += irq-sun4i.o | 11 | obj-$(CONFIG_ARCH_SUNXI) += irq-sun4i.o |
| 11 | obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o | 12 | obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o |
| 12 | obj-$(CONFIG_ARM_GIC) += irq-gic.o | 13 | 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 000000000000..e51d40031884 --- /dev/null +++ b/drivers/irqchip/irq-orion.c | |||
| @@ -0,0 +1,192 @@ | |||
| 1 | /* | ||
| 2 | * Marvell Orion SoCs IRQ chip driver. | ||
| 3 | * | ||
| 4 | * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> | ||
| 5 | * | ||
| 6 | * This file is licensed under the terms of the GNU General Public | ||
| 7 | * License version 2. This program is licensed "as is" without any | ||
| 8 | * warranty of any kind, whether express or implied. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/io.h> | ||
| 12 | #include <linux/irq.h> | ||
| 13 | #include <linux/of.h> | ||
| 14 | #include <linux/of_address.h> | ||
| 15 | #include <linux/of_irq.h> | ||
| 16 | #include <asm/exception.h> | ||
| 17 | #include <asm/mach/irq.h> | ||
| 18 | |||
| 19 | #include "irqchip.h" | ||
| 20 | |||
| 21 | /* | ||
| 22 | * Orion SoC main interrupt controller | ||
| 23 | */ | ||
| 24 | #define ORION_IRQS_PER_CHIP 32 | ||
| 25 | |||
| 26 | #define ORION_IRQ_CAUSE 0x00 | ||
| 27 | #define ORION_IRQ_MASK 0x04 | ||
| 28 | #define ORION_IRQ_FIQ_MASK 0x08 | ||
| 29 | #define ORION_IRQ_ENDP_MASK 0x0c | ||
| 30 | |||
| 31 | static struct irq_domain *orion_irq_domain; | ||
| 32 | |||
| 33 | static asmlinkage void | ||
| 34 | __exception_irq_entry orion_handle_irq(struct pt_regs *regs) | ||
| 35 | { | ||
| 36 | struct irq_domain_chip_generic *dgc = orion_irq_domain->gc; | ||
| 37 | int n, base = 0; | ||
| 38 | |||
| 39 | for (n = 0; n < dgc->num_chips; n++, base += ORION_IRQS_PER_CHIP) { | ||
| 40 | struct irq_chip_generic *gc = | ||
| 41 | irq_get_domain_generic_chip(orion_irq_domain, base); | ||
| 42 | u32 stat = readl_relaxed(gc->reg_base + ORION_IRQ_CAUSE) & | ||
| 43 | gc->mask_cache; | ||
| 44 | while (stat) { | ||
| 45 | u32 hwirq = ffs(stat) - 1; | ||
| 46 | u32 irq = irq_find_mapping(orion_irq_domain, | ||
| 47 | gc->irq_base + hwirq); | ||
| 48 | handle_IRQ(irq, regs); | ||
| 49 | stat &= ~(1 << hwirq); | ||
| 50 | } | ||
| 51 | } | ||
| 52 | } | ||
| 53 | |||
| 54 | static int __init orion_irq_init(struct device_node *np, | ||
| 55 | struct device_node *parent) | ||
| 56 | { | ||
| 57 | unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; | ||
| 58 | int n, ret, base, num_chips = 0; | ||
| 59 | struct resource r; | ||
| 60 | |||
| 61 | /* count number of irq chips by valid reg addresses */ | ||
| 62 | while (of_address_to_resource(np, num_chips, &r) == 0) | ||
| 63 | num_chips++; | ||
| 64 | |||
| 65 | orion_irq_domain = irq_domain_add_linear(np, | ||
| 66 | num_chips * ORION_IRQS_PER_CHIP, | ||
| 67 | &irq_generic_chip_ops, NULL); | ||
| 68 | if (!orion_irq_domain) | ||
| 69 | panic("%s: unable to add irq domain\n", np->name); | ||
| 70 | |||
| 71 | ret = irq_alloc_domain_generic_chips(orion_irq_domain, | ||
| 72 | ORION_IRQS_PER_CHIP, 1, np->name, | ||
| 73 | handle_level_irq, clr, 0, | ||
| 74 | IRQ_GC_INIT_MASK_CACHE); | ||
| 75 | if (ret) | ||
| 76 | panic("%s: unable to alloc irq domain gc\n", np->name); | ||
| 77 | |||
| 78 | for (n = 0, base = 0; n < num_chips; n++, base += ORION_IRQS_PER_CHIP) { | ||
| 79 | struct irq_chip_generic *gc = | ||
| 80 | irq_get_domain_generic_chip(orion_irq_domain, base); | ||
| 81 | |||
| 82 | of_address_to_resource(np, n, &r); | ||
| 83 | |||
| 84 | if (!request_mem_region(r.start, resource_size(&r), np->name)) | ||
| 85 | panic("%s: unable to request mem region %d", | ||
| 86 | np->name, n); | ||
| 87 | |||
| 88 | gc->reg_base = ioremap(r.start, resource_size(&r)); | ||
| 89 | if (!gc->reg_base) | ||
| 90 | panic("%s: unable to map resource %d", np->name, n); | ||
| 91 | |||
| 92 | gc->chip_types[0].regs.mask = ORION_IRQ_MASK; | ||
| 93 | gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit; | ||
| 94 | gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit; | ||
| 95 | |||
| 96 | /* mask all interrupts */ | ||
| 97 | writel(0, gc->reg_base + ORION_IRQ_MASK); | ||
| 98 | } | ||
| 99 | |||
| 100 | set_handle_irq(orion_handle_irq); | ||
| 101 | return 0; | ||
| 102 | } | ||
| 103 | IRQCHIP_DECLARE(orion_intc, "marvell,orion-intc", orion_irq_init); | ||
| 104 | |||
| 105 | /* | ||
| 106 | * Orion SoC bridge interrupt controller | ||
| 107 | */ | ||
