1*b1479ebbSBoris BREZILLON /* 2*b1479ebbSBoris BREZILLON * Atmel AT91 AIC (Advanced Interrupt Controller) driver 3*b1479ebbSBoris BREZILLON * 4*b1479ebbSBoris BREZILLON * Copyright (C) 2004 SAN People 5*b1479ebbSBoris BREZILLON * Copyright (C) 2004 ATMEL 6*b1479ebbSBoris BREZILLON * Copyright (C) Rick Bronson 7*b1479ebbSBoris BREZILLON * Copyright (C) 2014 Free Electrons 8*b1479ebbSBoris BREZILLON * 9*b1479ebbSBoris BREZILLON * Author: Boris BREZILLON <boris.brezillon@free-electrons.com> 10*b1479ebbSBoris BREZILLON * 11*b1479ebbSBoris BREZILLON * This file is licensed under the terms of the GNU General Public 12*b1479ebbSBoris BREZILLON * License version 2. This program is licensed "as is" without any 13*b1479ebbSBoris BREZILLON * warranty of any kind, whether express or implied. 14*b1479ebbSBoris BREZILLON */ 15*b1479ebbSBoris BREZILLON 16*b1479ebbSBoris BREZILLON #include <linux/init.h> 17*b1479ebbSBoris BREZILLON #include <linux/module.h> 18*b1479ebbSBoris BREZILLON #include <linux/mm.h> 19*b1479ebbSBoris BREZILLON #include <linux/bitmap.h> 20*b1479ebbSBoris BREZILLON #include <linux/types.h> 21*b1479ebbSBoris BREZILLON #include <linux/irq.h> 22*b1479ebbSBoris BREZILLON #include <linux/of.h> 23*b1479ebbSBoris BREZILLON #include <linux/of_address.h> 24*b1479ebbSBoris BREZILLON #include <linux/of_irq.h> 25*b1479ebbSBoris BREZILLON #include <linux/irqdomain.h> 26*b1479ebbSBoris BREZILLON #include <linux/err.h> 27*b1479ebbSBoris BREZILLON #include <linux/slab.h> 28*b1479ebbSBoris BREZILLON #include <linux/io.h> 29*b1479ebbSBoris BREZILLON 30*b1479ebbSBoris BREZILLON #include <asm/exception.h> 31*b1479ebbSBoris BREZILLON #include <asm/mach/irq.h> 32*b1479ebbSBoris BREZILLON 33*b1479ebbSBoris BREZILLON #include "irq-atmel-aic-common.h" 34*b1479ebbSBoris BREZILLON #include "irqchip.h" 35*b1479ebbSBoris BREZILLON 36*b1479ebbSBoris BREZILLON /* Number of irq lines managed by AIC */ 37*b1479ebbSBoris BREZILLON #define NR_AIC_IRQS 32 38*b1479ebbSBoris BREZILLON 39*b1479ebbSBoris BREZILLON #define AT91_AIC_SMR(n) ((n) * 4) 40*b1479ebbSBoris BREZILLON 41*b1479ebbSBoris BREZILLON #define AT91_AIC_SVR(n) (0x80 + ((n) * 4)) 42*b1479ebbSBoris BREZILLON #define AT91_AIC_IVR 0x100 43*b1479ebbSBoris BREZILLON #define AT91_AIC_FVR 0x104 44*b1479ebbSBoris BREZILLON #define AT91_AIC_ISR 0x108 45*b1479ebbSBoris BREZILLON 46*b1479ebbSBoris BREZILLON #define AT91_AIC_IPR 0x10c 47*b1479ebbSBoris BREZILLON #define AT91_AIC_IMR 0x110 48*b1479ebbSBoris BREZILLON #define AT91_AIC_CISR 0x114 49*b1479ebbSBoris BREZILLON 50*b1479ebbSBoris BREZILLON #define AT91_AIC_IECR 0x120 51*b1479ebbSBoris BREZILLON #define AT91_AIC_IDCR 0x124 52*b1479ebbSBoris BREZILLON #define AT91_AIC_ICCR 0x128 53*b1479ebbSBoris BREZILLON #define AT91_AIC_ISCR 0x12c 54*b1479ebbSBoris BREZILLON #define AT91_AIC_EOICR 0x130 55*b1479ebbSBoris BREZILLON #define AT91_AIC_SPU 0x134 56*b1479ebbSBoris BREZILLON #define AT91_AIC_DCR 0x138 57*b1479ebbSBoris BREZILLON 58*b1479ebbSBoris BREZILLON static struct irq_domain *aic_domain; 59*b1479ebbSBoris BREZILLON 60*b1479ebbSBoris BREZILLON static asmlinkage void __exception_irq_entry 61*b1479ebbSBoris BREZILLON aic_handle(struct pt_regs *regs) 62*b1479ebbSBoris BREZILLON { 63*b1479ebbSBoris BREZILLON struct irq_domain_chip_generic *dgc = aic_domain->gc; 64*b1479ebbSBoris BREZILLON struct irq_chip_generic *gc = dgc->gc[0]; 65*b1479ebbSBoris BREZILLON u32 irqnr; 66*b1479ebbSBoris BREZILLON u32 irqstat; 67*b1479ebbSBoris BREZILLON 68*b1479ebbSBoris BREZILLON irqnr = irq_reg_readl(gc->reg_base + AT91_AIC_IVR); 69*b1479ebbSBoris BREZILLON irqstat = irq_reg_readl(gc->reg_base + AT91_AIC_ISR); 70*b1479ebbSBoris BREZILLON 71*b1479ebbSBoris BREZILLON irqnr = irq_find_mapping(aic_domain, irqnr); 72*b1479ebbSBoris BREZILLON 73*b1479ebbSBoris BREZILLON if (!irqstat) 74*b1479ebbSBoris BREZILLON irq_reg_writel(0, gc->reg_base + AT91_AIC_EOICR); 75*b1479ebbSBoris BREZILLON else 76*b1479ebbSBoris BREZILLON handle_IRQ(irqnr, regs); 77*b1479ebbSBoris BREZILLON } 78*b1479ebbSBoris BREZILLON 79*b1479ebbSBoris BREZILLON static int aic_retrigger(struct irq_data *d) 80*b1479ebbSBoris BREZILLON { 81*b1479ebbSBoris BREZILLON struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 82*b1479ebbSBoris BREZILLON 83*b1479ebbSBoris BREZILLON /* Enable interrupt on AIC5 */ 84*b1479ebbSBoris BREZILLON irq_gc_lock(gc); 85*b1479ebbSBoris BREZILLON irq_reg_writel(d->mask, gc->reg_base + AT91_AIC_ISCR); 86*b1479ebbSBoris BREZILLON irq_gc_unlock(gc); 87*b1479ebbSBoris BREZILLON 88*b1479ebbSBoris BREZILLON return 0; 89*b1479ebbSBoris BREZILLON } 90*b1479ebbSBoris BREZILLON 91*b1479ebbSBoris BREZILLON static int aic_set_type(struct irq_data *d, unsigned type) 92*b1479ebbSBoris BREZILLON { 93*b1479ebbSBoris BREZILLON struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 94*b1479ebbSBoris BREZILLON unsigned int smr; 95*b1479ebbSBoris BREZILLON int ret; 96*b1479ebbSBoris BREZILLON 97*b1479ebbSBoris BREZILLON smr = irq_reg_readl(gc->reg_base + AT91_AIC_SMR(d->hwirq)); 98*b1479ebbSBoris BREZILLON ret = aic_common_set_type(d, type, &smr); 99*b1479ebbSBoris BREZILLON if (ret) 100*b1479ebbSBoris BREZILLON return ret; 101*b1479ebbSBoris BREZILLON 102*b1479ebbSBoris BREZILLON irq_reg_writel(smr, gc->reg_base + AT91_AIC_SMR(d->hwirq)); 103*b1479ebbSBoris BREZILLON 104*b1479ebbSBoris BREZILLON return 0; 105*b1479ebbSBoris BREZILLON } 106*b1479ebbSBoris BREZILLON 107*b1479ebbSBoris BREZILLON #ifdef CONFIG_PM 108*b1479ebbSBoris BREZILLON static void aic_suspend(struct irq_data *d) 109*b1479ebbSBoris BREZILLON { 110*b1479ebbSBoris BREZILLON struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 111*b1479ebbSBoris BREZILLON 112*b1479ebbSBoris BREZILLON irq_gc_lock(gc); 113*b1479ebbSBoris BREZILLON irq_reg_writel(gc->mask_cache, gc->reg_base + AT91_AIC_IDCR); 114*b1479ebbSBoris BREZILLON irq_reg_writel(gc->wake_active, gc->reg_base + AT91_AIC_IECR); 115*b1479ebbSBoris BREZILLON irq_gc_unlock(gc); 116*b1479ebbSBoris BREZILLON } 117*b1479ebbSBoris BREZILLON 118*b1479ebbSBoris BREZILLON static void aic_resume(struct irq_data *d) 119*b1479ebbSBoris BREZILLON { 120*b1479ebbSBoris BREZILLON struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 121*b1479ebbSBoris BREZILLON 122*b1479ebbSBoris BREZILLON irq_gc_lock(gc); 123*b1479ebbSBoris BREZILLON irq_reg_writel(gc->wake_active, gc->reg_base + AT91_AIC_IDCR); 124*b1479ebbSBoris BREZILLON irq_reg_writel(gc->mask_cache, gc->reg_base + AT91_AIC_IECR); 125*b1479ebbSBoris BREZILLON irq_gc_unlock(gc); 126*b1479ebbSBoris BREZILLON } 127*b1479ebbSBoris BREZILLON 128*b1479ebbSBoris BREZILLON static void aic_pm_shutdown(struct irq_data *d) 129*b1479ebbSBoris BREZILLON { 130*b1479ebbSBoris BREZILLON struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 131*b1479ebbSBoris BREZILLON 132*b1479ebbSBoris BREZILLON irq_gc_lock(gc); 133*b1479ebbSBoris BREZILLON irq_reg_writel(0xffffffff, gc->reg_base + AT91_AIC_IDCR); 134*b1479ebbSBoris BREZILLON irq_reg_writel(0xffffffff, gc->reg_base + AT91_AIC_ICCR); 135*b1479ebbSBoris BREZILLON irq_gc_unlock(gc); 136*b1479ebbSBoris BREZILLON } 137*b1479ebbSBoris BREZILLON #else 138*b1479ebbSBoris BREZILLON #define aic_suspend NULL 139*b1479ebbSBoris BREZILLON #define aic_resume NULL 140*b1479ebbSBoris BREZILLON #define aic_pm_shutdown NULL 141*b1479ebbSBoris BREZILLON #endif /* CONFIG_PM */ 142*b1479ebbSBoris BREZILLON 143*b1479ebbSBoris BREZILLON static void __init aic_hw_init(struct irq_domain *domain) 144*b1479ebbSBoris BREZILLON { 145*b1479ebbSBoris BREZILLON struct irq_chip_generic *gc = irq_get_domain_generic_chip(domain, 0); 146*b1479ebbSBoris BREZILLON int i; 147*b1479ebbSBoris BREZILLON 148*b1479ebbSBoris BREZILLON /* 149*b1479ebbSBoris BREZILLON * Perform 8 End Of Interrupt Command to make sure AIC 150*b1479ebbSBoris BREZILLON * will not Lock out nIRQ 151*b1479ebbSBoris BREZILLON */ 152*b1479ebbSBoris BREZILLON for (i = 0; i < 8; i++) 153*b1479ebbSBoris BREZILLON irq_reg_writel(0, gc->reg_base + AT91_AIC_EOICR); 154*b1479ebbSBoris BREZILLON 155*b1479ebbSBoris BREZILLON /* 156*b1479ebbSBoris BREZILLON * Spurious Interrupt ID in Spurious Vector Register. 157*b1479ebbSBoris BREZILLON * When there is no current interrupt, the IRQ Vector Register 158*b1479ebbSBoris BREZILLON * reads the value stored in AIC_SPU 159*b1479ebbSBoris BREZILLON */ 160*b1479ebbSBoris BREZILLON irq_reg_writel(0xffffffff, gc->reg_base + AT91_AIC_SPU); 161*b1479ebbSBoris BREZILLON 162*b1479ebbSBoris BREZILLON /* No debugging in AIC: Debug (Protect) Control Register */ 163*b1479ebbSBoris BREZILLON irq_reg_writel(0, gc->reg_base + AT91_AIC_DCR); 164*b1479ebbSBoris BREZILLON 165*b1479ebbSBoris BREZILLON /* Disable and clear all interrupts initially */ 166*b1479ebbSBoris BREZILLON irq_reg_writel(0xffffffff, gc->reg_base + AT91_AIC_IDCR); 167*b1479ebbSBoris BREZILLON irq_reg_writel(0xffffffff, gc->reg_base + AT91_AIC_ICCR); 168*b1479ebbSBoris BREZILLON 169*b1479ebbSBoris BREZILLON for (i = 0; i < 32; i++) 170*b1479ebbSBoris BREZILLON irq_reg_writel(i, gc->reg_base + AT91_AIC_SVR(i)); 171*b1479ebbSBoris BREZILLON } 172*b1479ebbSBoris BREZILLON 173*b1479ebbSBoris BREZILLON static int aic_irq_domain_xlate(struct irq_domain *d, 174*b1479ebbSBoris BREZILLON struct device_node *ctrlr, 175*b1479ebbSBoris BREZILLON const u32 *intspec, unsigned int intsize, 176*b1479ebbSBoris BREZILLON irq_hw_number_t *out_hwirq, 177*b1479ebbSBoris BREZILLON unsigned int *out_type) 178*b1479ebbSBoris BREZILLON { 179*b1479ebbSBoris BREZILLON struct irq_domain_chip_generic *dgc = d->gc; 180*b1479ebbSBoris BREZILLON struct irq_chip_generic *gc; 181*b1479ebbSBoris BREZILLON unsigned smr; 182*b1479ebbSBoris BREZILLON int idx; 183*b1479ebbSBoris BREZILLON int ret; 184*b1479ebbSBoris BREZILLON 185*b1479ebbSBoris BREZILLON if (!dgc) 186*b1479ebbSBoris BREZILLON return -EINVAL; 187*b1479ebbSBoris BREZILLON 188*b1479ebbSBoris BREZILLON ret = aic_common_irq_domain_xlate(d, ctrlr, intspec, intsize, 189*b1479ebbSBoris BREZILLON out_hwirq, out_type); 190*b1479ebbSBoris BREZILLON if (ret) 191*b1479ebbSBoris BREZILLON return ret; 192*b1479ebbSBoris BREZILLON 193*b1479ebbSBoris BREZILLON idx = intspec[0] / dgc->irqs_per_chip; 194*b1479ebbSBoris BREZILLON if (idx >= dgc->num_chips) 195*b1479ebbSBoris BREZILLON return -EINVAL; 196*b1479ebbSBoris BREZILLON 197*b1479ebbSBoris BREZILLON gc = dgc->gc[idx]; 198*b1479ebbSBoris BREZILLON 199*b1479ebbSBoris BREZILLON irq_gc_lock(gc); 200*b1479ebbSBoris BREZILLON smr = irq_reg_readl(gc->reg_base + AT91_AIC_SMR(*out_hwirq)); 201*b1479ebbSBoris BREZILLON ret = aic_common_set_priority(intspec[2], &smr); 202*b1479ebbSBoris BREZILLON if (!ret) 203*b1479ebbSBoris BREZILLON irq_reg_writel(smr, gc->reg_base + AT91_AIC_SMR(*out_hwirq)); 204*b1479ebbSBoris BREZILLON irq_gc_unlock(gc); 205*b1479ebbSBoris BREZILLON 206*b1479ebbSBoris BREZILLON return ret; 207*b1479ebbSBoris BREZILLON } 208*b1479ebbSBoris BREZILLON 209*b1479ebbSBoris BREZILLON static const struct irq_domain_ops aic_irq_ops = { 210*b1479ebbSBoris BREZILLON .map = irq_map_generic_chip, 211*b1479ebbSBoris BREZILLON .xlate = aic_irq_domain_xlate, 212*b1479ebbSBoris BREZILLON }; 213*b1479ebbSBoris BREZILLON 214*b1479ebbSBoris BREZILLON static int __init aic_of_init(struct device_node *node, 215*b1479ebbSBoris BREZILLON struct device_node *parent) 216*b1479ebbSBoris BREZILLON { 217*b1479ebbSBoris BREZILLON struct irq_chip_generic *gc; 218*b1479ebbSBoris BREZILLON struct irq_domain *domain; 219*b1479ebbSBoris BREZILLON 220*b1479ebbSBoris BREZILLON if (aic_domain) 221*b1479ebbSBoris BREZILLON return -EEXIST; 222*b1479ebbSBoris BREZILLON 223*b1479ebbSBoris BREZILLON domain = aic_common_of_init(node, &aic_irq_ops, "atmel-aic", 224*b1479ebbSBoris BREZILLON NR_AIC_IRQS); 225*b1479ebbSBoris BREZILLON if (IS_ERR(domain)) 226*b1479ebbSBoris BREZILLON return PTR_ERR(domain); 227*b1479ebbSBoris BREZILLON 228*b1479ebbSBoris BREZILLON aic_domain = domain; 229*b1479ebbSBoris BREZILLON gc = irq_get_domain_generic_chip(domain, 0); 230*b1479ebbSBoris BREZILLON 231*b1479ebbSBoris BREZILLON gc->chip_types[0].regs.eoi = AT91_AIC_EOICR; 232*b1479ebbSBoris BREZILLON gc->chip_types[0].regs.enable = AT91_AIC_IECR; 233*b1479ebbSBoris BREZILLON gc->chip_types[0].regs.disable = AT91_AIC_IDCR; 234*b1479ebbSBoris BREZILLON gc->chip_types[0].chip.irq_mask = irq_gc_mask_disable_reg; 235*b1479ebbSBoris BREZILLON gc->chip_types[0].chip.irq_unmask = irq_gc_unmask_enable_reg; 236*b1479ebbSBoris BREZILLON gc->chip_types[0].chip.irq_retrigger = aic_retrigger; 237*b1479ebbSBoris BREZILLON gc->chip_types[0].chip.irq_set_type = aic_set_type; 238*b1479ebbSBoris BREZILLON gc->chip_types[0].chip.irq_suspend = aic_suspend; 239*b1479ebbSBoris BREZILLON gc->chip_types[0].chip.irq_resume = aic_resume; 240*b1479ebbSBoris BREZILLON gc->chip_types[0].chip.irq_pm_shutdown = aic_pm_shutdown; 241*b1479ebbSBoris BREZILLON 242*b1479ebbSBoris BREZILLON aic_hw_init(domain); 243*b1479ebbSBoris BREZILLON set_handle_irq(aic_handle); 244*b1479ebbSBoris BREZILLON 245*b1479ebbSBoris BREZILLON return 0; 246*b1479ebbSBoris BREZILLON } 247*b1479ebbSBoris BREZILLON IRQCHIP_DECLARE(at91rm9200_aic, "atmel,at91rm9200-aic", aic_of_init); 248