101eb5698SLennert Buytenhek /* 201eb5698SLennert Buytenhek * arch/arm/plat-orion/irq.c 301eb5698SLennert Buytenhek * 401eb5698SLennert Buytenhek * Marvell Orion SoC IRQ handling. 501eb5698SLennert Buytenhek * 601eb5698SLennert Buytenhek * This file is licensed under the terms of the GNU General Public 701eb5698SLennert Buytenhek * License version 2. This program is licensed "as is" without any 801eb5698SLennert Buytenhek * warranty of any kind, whether express or implied. 901eb5698SLennert Buytenhek */ 1001eb5698SLennert Buytenhek 1101eb5698SLennert Buytenhek #include <linux/kernel.h> 1201eb5698SLennert Buytenhek #include <linux/init.h> 1301eb5698SLennert Buytenhek #include <linux/irq.h> 14278b45b0SAndrew Lunn #include <linux/irqdomain.h> 1501eb5698SLennert Buytenhek #include <linux/io.h> 16278b45b0SAndrew Lunn #include <linux/of_address.h> 17278b45b0SAndrew Lunn #include <linux/of_irq.h> 18f28d7de6SSebastian Hesselbarth #include <asm/exception.h> 196f088f1dSLennert Buytenhek #include <plat/irq.h> 20ce91574cSRob Herring #include <plat/orion-gpio.h> 21f28d7de6SSebastian Hesselbarth #include <mach/bridge-regs.h> 22f28d7de6SSebastian Hesselbarth 23f28d7de6SSebastian Hesselbarth #ifdef CONFIG_MULTI_IRQ_HANDLER 24f28d7de6SSebastian Hesselbarth /* 25f28d7de6SSebastian Hesselbarth * Compiling with both non-DT and DT support enabled, will 26f28d7de6SSebastian Hesselbarth * break asm irq handler used by non-DT boards. Therefore, 27f28d7de6SSebastian Hesselbarth * we provide a C-style irq handler even for non-DT boards, 28f28d7de6SSebastian Hesselbarth * if MULTI_IRQ_HANDLER is set. 29f28d7de6SSebastian Hesselbarth * 30f28d7de6SSebastian Hesselbarth * Notes: 31f28d7de6SSebastian Hesselbarth * - this is prepared for Kirkwood and Dove only, update 32f28d7de6SSebastian Hesselbarth * accordingly if you add Orion5x or MV78x00. 33f28d7de6SSebastian Hesselbarth * - Orion5x uses different macro names and has only one 34f28d7de6SSebastian Hesselbarth * set of CAUSE/MASK registers. 35f28d7de6SSebastian Hesselbarth * - MV78x00 uses the same macro names but has a third 36f28d7de6SSebastian Hesselbarth * set of CAUSE/MASK registers. 37f28d7de6SSebastian Hesselbarth * 38f28d7de6SSebastian Hesselbarth */ 39f28d7de6SSebastian Hesselbarth 40f28d7de6SSebastian Hesselbarth static void __iomem *orion_irq_base = IRQ_VIRT_BASE; 41f28d7de6SSebastian Hesselbarth 42f28d7de6SSebastian Hesselbarth asmlinkage void 43f28d7de6SSebastian Hesselbarth __exception_irq_entry orion_legacy_handle_irq(struct pt_regs *regs) 44f28d7de6SSebastian Hesselbarth { 45f28d7de6SSebastian Hesselbarth u32 stat; 46f28d7de6SSebastian Hesselbarth 47f28d7de6SSebastian Hesselbarth stat = readl_relaxed(orion_irq_base + IRQ_CAUSE_LOW_OFF); 48f28d7de6SSebastian Hesselbarth stat &= readl_relaxed(orion_irq_base + IRQ_MASK_LOW_OFF); 49f28d7de6SSebastian Hesselbarth if (stat) { 50f28d7de6SSebastian Hesselbarth unsigned int hwirq = __fls(stat); 51f28d7de6SSebastian Hesselbarth handle_IRQ(hwirq, regs); 52f28d7de6SSebastian Hesselbarth return; 53f28d7de6SSebastian Hesselbarth } 54f28d7de6SSebastian Hesselbarth stat = readl_relaxed(orion_irq_base + IRQ_CAUSE_HIGH_OFF); 55f28d7de6SSebastian Hesselbarth stat &= readl_relaxed(orion_irq_base + IRQ_MASK_HIGH_OFF); 56f28d7de6SSebastian Hesselbarth if (stat) { 57f28d7de6SSebastian Hesselbarth unsigned int hwirq = 32 + __fls(stat); 58f28d7de6SSebastian Hesselbarth handle_IRQ(hwirq, regs); 59f28d7de6SSebastian Hesselbarth return; 60f28d7de6SSebastian Hesselbarth } 61f28d7de6SSebastian Hesselbarth } 62f28d7de6SSebastian Hesselbarth #endif 6301eb5698SLennert Buytenhek 6401eb5698SLennert Buytenhek void __init orion_irq_init(unsigned int irq_start, void __iomem *maskaddr) 6501eb5698SLennert Buytenhek { 66e59347a1SThomas Gleixner struct irq_chip_generic *gc; 67e59347a1SThomas Gleixner struct irq_chip_type *ct; 6801eb5698SLennert Buytenhek 6901eb5698SLennert Buytenhek /* 7001eb5698SLennert Buytenhek * Mask all interrupts initially. 7101eb5698SLennert Buytenhek */ 7201eb5698SLennert Buytenhek writel(0, maskaddr); 7301eb5698SLennert Buytenhek 74e59347a1SThomas Gleixner gc = irq_alloc_generic_chip("orion_irq", 1, irq_start, maskaddr, 75f38c02f3SThomas Gleixner handle_level_irq); 76e59347a1SThomas Gleixner ct = gc->chip_types; 77e59347a1SThomas Gleixner ct->chip.irq_mask = irq_gc_mask_clr_bit; 78e59347a1SThomas Gleixner ct->chip.irq_unmask = irq_gc_mask_set_bit; 79e59347a1SThomas Gleixner irq_setup_generic_chip(gc, IRQ_MSK(32), IRQ_GC_INIT_MASK_CACHE, 80e59347a1SThomas Gleixner IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE); 81f28d7de6SSebastian Hesselbarth 82f28d7de6SSebastian Hesselbarth #ifdef CONFIG_MULTI_IRQ_HANDLER 83f28d7de6SSebastian Hesselbarth set_handle_irq(orion_legacy_handle_irq); 84f28d7de6SSebastian Hesselbarth #endif 8501eb5698SLennert Buytenhek } 86278b45b0SAndrew Lunn 87278b45b0SAndrew Lunn #ifdef CONFIG_OF 88278b45b0SAndrew Lunn static int __init orion_add_irq_domain(struct device_node *np, 89278b45b0SAndrew Lunn struct device_node *interrupt_parent) 90278b45b0SAndrew Lunn { 91f9e75922SAndrew Lunn int i = 0; 92278b45b0SAndrew Lunn void __iomem *base; 93278b45b0SAndrew Lunn 94278b45b0SAndrew Lunn do { 95278b45b0SAndrew Lunn base = of_iomap(np, i); 96278b45b0SAndrew Lunn if (base) { 97fa8c5a81SSebastian Hesselbarth orion_irq_init(i * 32, base + 0x04); 98278b45b0SAndrew Lunn i++; 99278b45b0SAndrew Lunn } 100278b45b0SAndrew Lunn } while (base); 101278b45b0SAndrew Lunn 102278b45b0SAndrew Lunn irq_domain_add_legacy(np, i * 32, 0, 0, 103278b45b0SAndrew Lunn &irq_domain_simple_ops, NULL); 104278b45b0SAndrew Lunn return 0; 105278b45b0SAndrew Lunn } 106278b45b0SAndrew Lunn 107278b45b0SAndrew Lunn static const struct of_device_id orion_irq_match[] = { 108278b45b0SAndrew Lunn { .compatible = "marvell,orion-intc", 109278b45b0SAndrew Lunn .data = orion_add_irq_domain, }, 110278b45b0SAndrew Lunn {}, 111278b45b0SAndrew Lunn }; 112278b45b0SAndrew Lunn 113278b45b0SAndrew Lunn void __init orion_dt_init_irq(void) 114278b45b0SAndrew Lunn { 115278b45b0SAndrew Lunn of_irq_init(orion_irq_match); 116278b45b0SAndrew Lunn } 117278b45b0SAndrew Lunn #endif 118