1edabd38eSSaeed Bishara /* 2edabd38eSSaeed Bishara * arch/arm/mach-dove/irq.c 3edabd38eSSaeed Bishara * 4edabd38eSSaeed Bishara * Dove IRQ handling. 5edabd38eSSaeed Bishara * 6edabd38eSSaeed Bishara * This file is licensed under the terms of the GNU General Public 7edabd38eSSaeed Bishara * License version 2. This program is licensed "as is" without any 8edabd38eSSaeed Bishara * warranty of any kind, whether express or implied. 9edabd38eSSaeed Bishara */ 10edabd38eSSaeed Bishara 11edabd38eSSaeed Bishara #include <linux/kernel.h> 12edabd38eSSaeed Bishara #include <linux/init.h> 13edabd38eSSaeed Bishara #include <linux/irq.h> 14edabd38eSSaeed Bishara #include <linux/gpio.h> 15edabd38eSSaeed Bishara #include <linux/io.h> 16edabd38eSSaeed Bishara #include <asm/mach/arch.h> 17edabd38eSSaeed Bishara #include <plat/irq.h> 18edabd38eSSaeed Bishara #include <asm/mach/irq.h> 19edabd38eSSaeed Bishara #include <mach/pm.h> 20edabd38eSSaeed Bishara #include <mach/bridge-regs.h> 21ce91574cSRob Herring #include <plat/orion-gpio.h> 22edabd38eSSaeed Bishara #include "common.h" 23edabd38eSSaeed Bishara 24aa456a6eSLennert Buytenhek static void pmu_irq_mask(struct irq_data *d) 25edabd38eSSaeed Bishara { 26aa456a6eSLennert Buytenhek int pin = irq_to_pmu(d->irq); 27edabd38eSSaeed Bishara u32 u; 28edabd38eSSaeed Bishara 29edabd38eSSaeed Bishara u = readl(PMU_INTERRUPT_MASK); 30edabd38eSSaeed Bishara u &= ~(1 << (pin & 31)); 31edabd38eSSaeed Bishara writel(u, PMU_INTERRUPT_MASK); 32edabd38eSSaeed Bishara } 33edabd38eSSaeed Bishara 34aa456a6eSLennert Buytenhek static void pmu_irq_unmask(struct irq_data *d) 35edabd38eSSaeed Bishara { 36aa456a6eSLennert Buytenhek int pin = irq_to_pmu(d->irq); 37edabd38eSSaeed Bishara u32 u; 38edabd38eSSaeed Bishara 39edabd38eSSaeed Bishara u = readl(PMU_INTERRUPT_MASK); 40edabd38eSSaeed Bishara u |= 1 << (pin & 31); 41edabd38eSSaeed Bishara writel(u, PMU_INTERRUPT_MASK); 42edabd38eSSaeed Bishara } 43edabd38eSSaeed Bishara 44aa456a6eSLennert Buytenhek static void pmu_irq_ack(struct irq_data *d) 45edabd38eSSaeed Bishara { 46aa456a6eSLennert Buytenhek int pin = irq_to_pmu(d->irq); 47edabd38eSSaeed Bishara u32 u; 48edabd38eSSaeed Bishara 495d3df935SRussell King - ARM Linux /* 505d3df935SRussell King - ARM Linux * The PMU mask register is not RW0C: it is RW. This means that 515d3df935SRussell King - ARM Linux * the bits take whatever value is written to them; if you write 525d3df935SRussell King - ARM Linux * a '1', you will set the interrupt. 535d3df935SRussell King - ARM Linux * 545d3df935SRussell King - ARM Linux * Unfortunately this means there is NO race free way to clear 555d3df935SRussell King - ARM Linux * these interrupts. 565d3df935SRussell King - ARM Linux * 575d3df935SRussell King - ARM Linux * So, let's structure the code so that the window is as small as 585d3df935SRussell King - ARM Linux * possible. 595d3df935SRussell King - ARM Linux */ 60edabd38eSSaeed Bishara u = ~(1 << (pin & 31)); 615d3df935SRussell King - ARM Linux u &= readl_relaxed(PMU_INTERRUPT_CAUSE); 625d3df935SRussell King - ARM Linux writel_relaxed(u, PMU_INTERRUPT_CAUSE); 63edabd38eSSaeed Bishara } 64edabd38eSSaeed Bishara 65edabd38eSSaeed Bishara static struct irq_chip pmu_irq_chip = { 66edabd38eSSaeed Bishara .name = "pmu_irq", 67aa456a6eSLennert Buytenhek .irq_mask = pmu_irq_mask, 68aa456a6eSLennert Buytenhek .irq_unmask = pmu_irq_unmask, 69aa456a6eSLennert Buytenhek .irq_ack = pmu_irq_ack, 70edabd38eSSaeed Bishara }; 71edabd38eSSaeed Bishara 72edabd38eSSaeed Bishara static void pmu_irq_handler(unsigned int irq, struct irq_desc *desc) 73edabd38eSSaeed Bishara { 74edabd38eSSaeed Bishara unsigned long cause = readl(PMU_INTERRUPT_CAUSE); 75edabd38eSSaeed Bishara 76edabd38eSSaeed Bishara cause &= readl(PMU_INTERRUPT_MASK); 77edabd38eSSaeed Bishara if (cause == 0) { 78edabd38eSSaeed Bishara do_bad_IRQ(irq, desc); 79edabd38eSSaeed Bishara return; 80edabd38eSSaeed Bishara } 81edabd38eSSaeed Bishara 82edabd38eSSaeed Bishara for (irq = 0; irq < NR_PMU_IRQS; irq++) { 83edabd38eSSaeed Bishara if (!(cause & (1 << irq))) 84edabd38eSSaeed Bishara continue; 85edabd38eSSaeed Bishara irq = pmu_to_irq(irq); 86cf0d6b76SThomas Gleixner generic_handle_irq(irq); 87edabd38eSSaeed Bishara } 88edabd38eSSaeed Bishara } 89edabd38eSSaeed Bishara 90278b45b0SAndrew Lunn static int __initdata gpio0_irqs[4] = { 91278b45b0SAndrew Lunn IRQ_DOVE_GPIO_0_7, 92278b45b0SAndrew Lunn IRQ_DOVE_GPIO_8_15, 93278b45b0SAndrew Lunn IRQ_DOVE_GPIO_16_23, 94278b45b0SAndrew Lunn IRQ_DOVE_GPIO_24_31, 95278b45b0SAndrew Lunn }; 96278b45b0SAndrew Lunn 97278b45b0SAndrew Lunn static int __initdata gpio1_irqs[4] = { 98278b45b0SAndrew Lunn IRQ_DOVE_HIGH_GPIO, 99278b45b0SAndrew Lunn 0, 100278b45b0SAndrew Lunn 0, 101278b45b0SAndrew Lunn 0, 102278b45b0SAndrew Lunn }; 103278b45b0SAndrew Lunn 104278b45b0SAndrew Lunn static int __initdata gpio2_irqs[4] = { 105278b45b0SAndrew Lunn 0, 106278b45b0SAndrew Lunn 0, 107278b45b0SAndrew Lunn 0, 108278b45b0SAndrew Lunn 0, 109278b45b0SAndrew Lunn }; 110278b45b0SAndrew Lunn 111deac3d87SThomas Petazzoni #ifdef CONFIG_MULTI_IRQ_HANDLER 112deac3d87SThomas Petazzoni /* 113deac3d87SThomas Petazzoni * Compiling with both non-DT and DT support enabled, will 114deac3d87SThomas Petazzoni * break asm irq handler used by non-DT boards. Therefore, 115deac3d87SThomas Petazzoni * we provide a C-style irq handler even for non-DT boards, 116deac3d87SThomas Petazzoni * if MULTI_IRQ_HANDLER is set. 117deac3d87SThomas Petazzoni */ 118deac3d87SThomas Petazzoni 119deac3d87SThomas Petazzoni static void __iomem *dove_irq_base = IRQ_VIRT_BASE; 120deac3d87SThomas Petazzoni 121deac3d87SThomas Petazzoni static asmlinkage void 122deac3d87SThomas Petazzoni __exception_irq_entry dove_legacy_handle_irq(struct pt_regs *regs) 123deac3d87SThomas Petazzoni { 124deac3d87SThomas Petazzoni u32 stat; 125deac3d87SThomas Petazzoni 126deac3d87SThomas Petazzoni stat = readl_relaxed(dove_irq_base + IRQ_CAUSE_LOW_OFF); 127deac3d87SThomas Petazzoni stat &= readl_relaxed(dove_irq_base + IRQ_MASK_LOW_OFF); 128deac3d87SThomas Petazzoni if (stat) { 129deac3d87SThomas Petazzoni unsigned int hwirq = __fls(stat); 130deac3d87SThomas Petazzoni handle_IRQ(hwirq, regs); 131deac3d87SThomas Petazzoni return; 132deac3d87SThomas Petazzoni } 133deac3d87SThomas Petazzoni stat = readl_relaxed(dove_irq_base + IRQ_CAUSE_HIGH_OFF); 134deac3d87SThomas Petazzoni stat &= readl_relaxed(dove_irq_base + IRQ_MASK_HIGH_OFF); 135deac3d87SThomas Petazzoni if (stat) { 136deac3d87SThomas Petazzoni unsigned int hwirq = 32 + __fls(stat); 137deac3d87SThomas Petazzoni handle_IRQ(hwirq, regs); 138deac3d87SThomas Petazzoni return; 139deac3d87SThomas Petazzoni } 140deac3d87SThomas Petazzoni } 141deac3d87SThomas Petazzoni #endif 142deac3d87SThomas Petazzoni 143edabd38eSSaeed Bishara void __init dove_init_irq(void) 144edabd38eSSaeed Bishara { 145edabd38eSSaeed Bishara int i; 146edabd38eSSaeed Bishara 147c3c5a281SThomas Petazzoni orion_irq_init(0, IRQ_VIRT_BASE + IRQ_MASK_LOW_OFF); 148c3c5a281SThomas Petazzoni orion_irq_init(32, IRQ_VIRT_BASE + IRQ_MASK_HIGH_OFF); 149edabd38eSSaeed Bishara 150deac3d87SThomas Petazzoni #ifdef CONFIG_MULTI_IRQ_HANDLER 151deac3d87SThomas Petazzoni set_handle_irq(dove_legacy_handle_irq); 152deac3d87SThomas Petazzoni #endif 153deac3d87SThomas Petazzoni 154edabd38eSSaeed Bishara /* 1559eac6d0aSLennert Buytenhek * Initialize gpiolib for GPIOs 0-71. 156edabd38eSSaeed Bishara */ 157c3c5a281SThomas Petazzoni orion_gpio_init(NULL, 0, 32, DOVE_GPIO_LO_VIRT_BASE, 0, 158278b45b0SAndrew Lunn IRQ_DOVE_GPIO_START, gpio0_irqs); 1599eac6d0aSLennert Buytenhek 160c3c5a281SThomas Petazzoni orion_gpio_init(NULL, 32, 32, DOVE_GPIO_HI_VIRT_BASE, 0, 161278b45b0SAndrew Lunn IRQ_DOVE_GPIO_START + 32, gpio1_irqs); 1629eac6d0aSLennert Buytenhek 163c3c5a281SThomas Petazzoni orion_gpio_init(NULL, 64, 8, DOVE_GPIO2_VIRT_BASE, 0, 164278b45b0SAndrew Lunn IRQ_DOVE_GPIO_START + 64, gpio2_irqs); 165edabd38eSSaeed Bishara 166edabd38eSSaeed Bishara /* 167edabd38eSSaeed Bishara * Mask and clear PMU interrupts 168edabd38eSSaeed Bishara */ 169edabd38eSSaeed Bishara writel(0, PMU_INTERRUPT_MASK); 170edabd38eSSaeed Bishara writel(0, PMU_INTERRUPT_CAUSE); 171edabd38eSSaeed Bishara 172edabd38eSSaeed Bishara for (i = IRQ_DOVE_PMU_START; i < NR_IRQS; i++) { 173f38c02f3SThomas Gleixner irq_set_chip_and_handler(i, &pmu_irq_chip, handle_level_irq); 174cf0d6b76SThomas Gleixner irq_set_status_flags(i, IRQ_LEVEL); 175edabd38eSSaeed Bishara set_irq_flags(i, IRQF_VALID); 176edabd38eSSaeed Bishara } 1776845664aSThomas Gleixner irq_set_chained_handler(IRQ_DOVE_PMU, pmu_irq_handler); 178edabd38eSSaeed Bishara } 179