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> 16b8cd337cSArnd Bergmann #include <asm/exception.h> 17edabd38eSSaeed Bishara #include <asm/mach/arch.h> 18edabd38eSSaeed Bishara #include <plat/irq.h> 19edabd38eSSaeed Bishara #include <asm/mach/irq.h> 20edabd38eSSaeed Bishara #include <mach/pm.h> 21edabd38eSSaeed Bishara #include <mach/bridge-regs.h> 22ce91574cSRob Herring #include <plat/orion-gpio.h> 23edabd38eSSaeed Bishara #include "common.h" 24edabd38eSSaeed Bishara 25aa456a6eSLennert Buytenhek static void pmu_irq_mask(struct irq_data *d) 26edabd38eSSaeed Bishara { 27aa456a6eSLennert Buytenhek int pin = irq_to_pmu(d->irq); 28edabd38eSSaeed Bishara u32 u; 29edabd38eSSaeed Bishara 30edabd38eSSaeed Bishara u = readl(PMU_INTERRUPT_MASK); 31edabd38eSSaeed Bishara u &= ~(1 << (pin & 31)); 32edabd38eSSaeed Bishara writel(u, PMU_INTERRUPT_MASK); 33edabd38eSSaeed Bishara } 34edabd38eSSaeed Bishara 35aa456a6eSLennert Buytenhek static void pmu_irq_unmask(struct irq_data *d) 36edabd38eSSaeed Bishara { 37aa456a6eSLennert Buytenhek int pin = irq_to_pmu(d->irq); 38edabd38eSSaeed Bishara u32 u; 39edabd38eSSaeed Bishara 40edabd38eSSaeed Bishara u = readl(PMU_INTERRUPT_MASK); 41edabd38eSSaeed Bishara u |= 1 << (pin & 31); 42edabd38eSSaeed Bishara writel(u, PMU_INTERRUPT_MASK); 43edabd38eSSaeed Bishara } 44edabd38eSSaeed Bishara 45aa456a6eSLennert Buytenhek static void pmu_irq_ack(struct irq_data *d) 46edabd38eSSaeed Bishara { 47aa456a6eSLennert Buytenhek int pin = irq_to_pmu(d->irq); 48edabd38eSSaeed Bishara u32 u; 49edabd38eSSaeed Bishara 505d3df935SRussell King - ARM Linux /* 515d3df935SRussell King - ARM Linux * The PMU mask register is not RW0C: it is RW. This means that 525d3df935SRussell King - ARM Linux * the bits take whatever value is written to them; if you write 535d3df935SRussell King - ARM Linux * a '1', you will set the interrupt. 545d3df935SRussell King - ARM Linux * 555d3df935SRussell King - ARM Linux * Unfortunately this means there is NO race free way to clear 565d3df935SRussell King - ARM Linux * these interrupts. 575d3df935SRussell King - ARM Linux * 585d3df935SRussell King - ARM Linux * So, let's structure the code so that the window is as small as 595d3df935SRussell King - ARM Linux * possible. 605d3df935SRussell King - ARM Linux */ 61edabd38eSSaeed Bishara u = ~(1 << (pin & 31)); 625d3df935SRussell King - ARM Linux u &= readl_relaxed(PMU_INTERRUPT_CAUSE); 635d3df935SRussell King - ARM Linux writel_relaxed(u, PMU_INTERRUPT_CAUSE); 64edabd38eSSaeed Bishara } 65edabd38eSSaeed Bishara 66edabd38eSSaeed Bishara static struct irq_chip pmu_irq_chip = { 67edabd38eSSaeed Bishara .name = "pmu_irq", 68aa456a6eSLennert Buytenhek .irq_mask = pmu_irq_mask, 69aa456a6eSLennert Buytenhek .irq_unmask = pmu_irq_unmask, 70aa456a6eSLennert Buytenhek .irq_ack = pmu_irq_ack, 71edabd38eSSaeed Bishara }; 72edabd38eSSaeed Bishara 73bd0b9ac4SThomas Gleixner static void pmu_irq_handler(struct irq_desc *desc) 74edabd38eSSaeed Bishara { 75edabd38eSSaeed Bishara unsigned long cause = readl(PMU_INTERRUPT_CAUSE); 76bd0b9ac4SThomas Gleixner unsigned int irq; 77edabd38eSSaeed Bishara 78edabd38eSSaeed Bishara cause &= readl(PMU_INTERRUPT_MASK); 79edabd38eSSaeed Bishara if (cause == 0) { 80bd0b9ac4SThomas Gleixner do_bad_IRQ(desc); 81edabd38eSSaeed Bishara return; 82edabd38eSSaeed Bishara } 83edabd38eSSaeed Bishara 84edabd38eSSaeed Bishara for (irq = 0; irq < NR_PMU_IRQS; irq++) { 85edabd38eSSaeed Bishara if (!(cause & (1 << irq))) 86edabd38eSSaeed Bishara continue; 87edabd38eSSaeed Bishara irq = pmu_to_irq(irq); 88cf0d6b76SThomas Gleixner generic_handle_irq(irq); 89edabd38eSSaeed Bishara } 90edabd38eSSaeed Bishara } 91edabd38eSSaeed Bishara 92278b45b0SAndrew Lunn static int __initdata gpio0_irqs[4] = { 93278b45b0SAndrew Lunn IRQ_DOVE_GPIO_0_7, 94278b45b0SAndrew Lunn IRQ_DOVE_GPIO_8_15, 95278b45b0SAndrew Lunn IRQ_DOVE_GPIO_16_23, 96278b45b0SAndrew Lunn IRQ_DOVE_GPIO_24_31, 97278b45b0SAndrew Lunn }; 98278b45b0SAndrew Lunn 99278b45b0SAndrew Lunn static int __initdata gpio1_irqs[4] = { 100278b45b0SAndrew Lunn IRQ_DOVE_HIGH_GPIO, 101278b45b0SAndrew Lunn 0, 102278b45b0SAndrew Lunn 0, 103278b45b0SAndrew Lunn 0, 104278b45b0SAndrew Lunn }; 105278b45b0SAndrew Lunn 106278b45b0SAndrew Lunn static int __initdata gpio2_irqs[4] = { 107278b45b0SAndrew Lunn 0, 108278b45b0SAndrew Lunn 0, 109278b45b0SAndrew Lunn 0, 110278b45b0SAndrew Lunn 0, 111278b45b0SAndrew Lunn }; 112278b45b0SAndrew Lunn 113deac3d87SThomas Petazzoni static void __iomem *dove_irq_base = IRQ_VIRT_BASE; 114deac3d87SThomas Petazzoni 115deac3d87SThomas Petazzoni static asmlinkage void 116deac3d87SThomas Petazzoni __exception_irq_entry dove_legacy_handle_irq(struct pt_regs *regs) 117deac3d87SThomas Petazzoni { 118deac3d87SThomas Petazzoni u32 stat; 119deac3d87SThomas Petazzoni 120deac3d87SThomas Petazzoni stat = readl_relaxed(dove_irq_base + IRQ_CAUSE_LOW_OFF); 121deac3d87SThomas Petazzoni stat &= readl_relaxed(dove_irq_base + IRQ_MASK_LOW_OFF); 122deac3d87SThomas Petazzoni if (stat) { 1235d6bed2aSRussell King unsigned int hwirq = 1 + __fls(stat); 124deac3d87SThomas Petazzoni handle_IRQ(hwirq, regs); 125deac3d87SThomas Petazzoni return; 126deac3d87SThomas Petazzoni } 127deac3d87SThomas Petazzoni stat = readl_relaxed(dove_irq_base + IRQ_CAUSE_HIGH_OFF); 128deac3d87SThomas Petazzoni stat &= readl_relaxed(dove_irq_base + IRQ_MASK_HIGH_OFF); 129deac3d87SThomas Petazzoni if (stat) { 1305d6bed2aSRussell King unsigned int hwirq = 33 + __fls(stat); 131deac3d87SThomas Petazzoni handle_IRQ(hwirq, regs); 132deac3d87SThomas Petazzoni return; 133deac3d87SThomas Petazzoni } 134deac3d87SThomas Petazzoni } 135deac3d87SThomas Petazzoni 136edabd38eSSaeed Bishara void __init dove_init_irq(void) 137edabd38eSSaeed Bishara { 138edabd38eSSaeed Bishara int i; 139edabd38eSSaeed Bishara 1405d6bed2aSRussell King orion_irq_init(1, IRQ_VIRT_BASE + IRQ_MASK_LOW_OFF); 1415d6bed2aSRussell King orion_irq_init(33, IRQ_VIRT_BASE + IRQ_MASK_HIGH_OFF); 142edabd38eSSaeed Bishara 143deac3d87SThomas Petazzoni set_handle_irq(dove_legacy_handle_irq); 144deac3d87SThomas Petazzoni 145edabd38eSSaeed Bishara /* 1469eac6d0aSLennert Buytenhek * Initialize gpiolib for GPIOs 0-71. 147edabd38eSSaeed Bishara */ 148c3c5a281SThomas Petazzoni orion_gpio_init(NULL, 0, 32, DOVE_GPIO_LO_VIRT_BASE, 0, 149278b45b0SAndrew Lunn IRQ_DOVE_GPIO_START, gpio0_irqs); 1509eac6d0aSLennert Buytenhek 151c3c5a281SThomas Petazzoni orion_gpio_init(NULL, 32, 32, DOVE_GPIO_HI_VIRT_BASE, 0, 152278b45b0SAndrew Lunn IRQ_DOVE_GPIO_START + 32, gpio1_irqs); 1539eac6d0aSLennert Buytenhek 154c3c5a281SThomas Petazzoni orion_gpio_init(NULL, 64, 8, DOVE_GPIO2_VIRT_BASE, 0, 155278b45b0SAndrew Lunn IRQ_DOVE_GPIO_START + 64, gpio2_irqs); 156edabd38eSSaeed Bishara 157edabd38eSSaeed Bishara /* 158edabd38eSSaeed Bishara * Mask and clear PMU interrupts 159edabd38eSSaeed Bishara */ 160edabd38eSSaeed Bishara writel(0, PMU_INTERRUPT_MASK); 161edabd38eSSaeed Bishara writel(0, PMU_INTERRUPT_CAUSE); 162edabd38eSSaeed Bishara 163edabd38eSSaeed Bishara for (i = IRQ_DOVE_PMU_START; i < NR_IRQS; i++) { 164f38c02f3SThomas Gleixner irq_set_chip_and_handler(i, &pmu_irq_chip, handle_level_irq); 165cf0d6b76SThomas Gleixner irq_set_status_flags(i, IRQ_LEVEL); 166e8d36d5dSRob Herring irq_clear_status_flags(i, IRQ_NOREQUEST); 167edabd38eSSaeed Bishara } 1686845664aSThomas Gleixner irq_set_chained_handler(IRQ_DOVE_PMU, pmu_irq_handler); 169edabd38eSSaeed Bishara } 170