Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * linux/arch/arm/mach-omap2/irq.c
0003  *
0004  * Interrupt handler for OMAP2 boards.
0005  *
0006  * Copyright (C) 2005 Nokia Corporation
0007  * Author: Paul Mundt <paul.mundt@nokia.com>
0008  *
0009  * This file is subject to the terms and conditions of the GNU General Public
0010  * License. See the file "COPYING" in the main directory of this archive
0011  * for more details.
0012  */
0013 #include <linux/kernel.h>
0014 #include <linux/module.h>
0015 #include <linux/init.h>
0016 #include <linux/interrupt.h>
0017 #include <linux/io.h>
0018 
0019 #include <asm/exception.h>
0020 #include <linux/irqchip.h>
0021 #include <linux/irqdomain.h>
0022 #include <linux/of.h>
0023 #include <linux/of_address.h>
0024 #include <linux/of_irq.h>
0025 
0026 #include <linux/irqchip/irq-omap-intc.h>
0027 
0028 /* selected INTC register offsets */
0029 
0030 #define INTC_REVISION       0x0000
0031 #define INTC_SYSCONFIG      0x0010
0032 #define INTC_SYSSTATUS      0x0014
0033 #define INTC_SIR        0x0040
0034 #define INTC_CONTROL        0x0048
0035 #define INTC_PROTECTION     0x004C
0036 #define INTC_IDLE       0x0050
0037 #define INTC_THRESHOLD      0x0068
0038 #define INTC_MIR0       0x0084
0039 #define INTC_MIR_CLEAR0     0x0088
0040 #define INTC_MIR_SET0       0x008c
0041 #define INTC_PENDING_IRQ0   0x0098
0042 #define INTC_PENDING_IRQ1   0x00b8
0043 #define INTC_PENDING_IRQ2   0x00d8
0044 #define INTC_PENDING_IRQ3   0x00f8
0045 #define INTC_ILR0       0x0100
0046 
0047 #define ACTIVEIRQ_MASK      0x7f    /* omap2/3 active interrupt bits */
0048 #define SPURIOUSIRQ_MASK    (0x1ffffff << 7)
0049 #define INTCPS_NR_ILR_REGS  128
0050 #define INTCPS_NR_MIR_REGS  4
0051 
0052 #define INTC_IDLE_FUNCIDLE  (1 << 0)
0053 #define INTC_IDLE_TURBO     (1 << 1)
0054 
0055 #define INTC_PROTECTION_ENABLE  (1 << 0)
0056 
0057 struct omap_intc_regs {
0058     u32 sysconfig;
0059     u32 protection;
0060     u32 idle;
0061     u32 threshold;
0062     u32 ilr[INTCPS_NR_ILR_REGS];
0063     u32 mir[INTCPS_NR_MIR_REGS];
0064 };
0065 static struct omap_intc_regs intc_context;
0066 
0067 static struct irq_domain *domain;
0068 static void __iomem *omap_irq_base;
0069 static int omap_nr_pending;
0070 static int omap_nr_irqs;
0071 
0072 static void intc_writel(u32 reg, u32 val)
0073 {
0074     writel_relaxed(val, omap_irq_base + reg);
0075 }
0076 
0077 static u32 intc_readl(u32 reg)
0078 {
0079     return readl_relaxed(omap_irq_base + reg);
0080 }
0081 
0082 void omap_intc_save_context(void)
0083 {
0084     int i;
0085 
0086     intc_context.sysconfig =
0087         intc_readl(INTC_SYSCONFIG);
0088     intc_context.protection =
0089         intc_readl(INTC_PROTECTION);
0090     intc_context.idle =
0091         intc_readl(INTC_IDLE);
0092     intc_context.threshold =
0093         intc_readl(INTC_THRESHOLD);
0094 
0095     for (i = 0; i < omap_nr_irqs; i++)
0096         intc_context.ilr[i] =
0097             intc_readl((INTC_ILR0 + 0x4 * i));
0098     for (i = 0; i < INTCPS_NR_MIR_REGS; i++)
0099         intc_context.mir[i] =
0100             intc_readl(INTC_MIR0 + (0x20 * i));
0101 }
0102 
0103 void omap_intc_restore_context(void)
0104 {
0105     int i;
0106 
0107     intc_writel(INTC_SYSCONFIG, intc_context.sysconfig);
0108     intc_writel(INTC_PROTECTION, intc_context.protection);
0109     intc_writel(INTC_IDLE, intc_context.idle);
0110     intc_writel(INTC_THRESHOLD, intc_context.threshold);
0111 
0112     for (i = 0; i < omap_nr_irqs; i++)
0113         intc_writel(INTC_ILR0 + 0x4 * i,
0114                 intc_context.ilr[i]);
0115 
0116     for (i = 0; i < INTCPS_NR_MIR_REGS; i++)
0117         intc_writel(INTC_MIR0 + 0x20 * i,
0118             intc_context.mir[i]);
0119     /* MIRs are saved and restore with other PRCM registers */
0120 }
0121 
0122 void omap3_intc_prepare_idle(void)
0123 {
0124     /*
0125      * Disable autoidle as it can stall interrupt controller,
0126      * cf. errata ID i540 for 3430 (all revisions up to 3.1.x)
0127      */
0128     intc_writel(INTC_SYSCONFIG, 0);
0129     intc_writel(INTC_IDLE, INTC_IDLE_TURBO);
0130 }
0131 
0132 void omap3_intc_resume_idle(void)
0133 {
0134     /* Re-enable autoidle */
0135     intc_writel(INTC_SYSCONFIG, 1);
0136     intc_writel(INTC_IDLE, 0);
0137 }
0138 
0139 /* XXX: FIQ and additional INTC support (only MPU at the moment) */
0140 static void omap_ack_irq(struct irq_data *d)
0141 {
0142     intc_writel(INTC_CONTROL, 0x1);
0143 }
0144 
0145 static void omap_mask_ack_irq(struct irq_data *d)
0146 {
0147     irq_gc_mask_disable_reg(d);
0148     omap_ack_irq(d);
0149 }
0150 
0151 static void __init omap_irq_soft_reset(void)
0152 {
0153     unsigned long tmp;
0154 
0155     tmp = intc_readl(INTC_REVISION) & 0xff;
0156 
0157     pr_info("IRQ: Found an INTC at 0x%p (revision %ld.%ld) with %d interrupts\n",
0158         omap_irq_base, tmp >> 4, tmp & 0xf, omap_nr_irqs);
0159 
0160     tmp = intc_readl(INTC_SYSCONFIG);
0161     tmp |= 1 << 1;  /* soft reset */
0162     intc_writel(INTC_SYSCONFIG, tmp);
0163 
0164     while (!(intc_readl(INTC_SYSSTATUS) & 0x1))
0165         /* Wait for reset to complete */;
0166 
0167     /* Enable autoidle */
0168     intc_writel(INTC_SYSCONFIG, 1 << 0);
0169 }
0170 
0171 int omap_irq_pending(void)
0172 {
0173     int i;
0174 
0175     for (i = 0; i < omap_nr_pending; i++)
0176         if (intc_readl(INTC_PENDING_IRQ0 + (0x20 * i)))
0177             return 1;
0178     return 0;
0179 }
0180 
0181 void omap3_intc_suspend(void)
0182 {
0183     /* A pending interrupt would prevent OMAP from entering suspend */
0184     omap_ack_irq(NULL);
0185 }
0186 
0187 static int __init omap_alloc_gc_of(struct irq_domain *d, void __iomem *base)
0188 {
0189     int ret;
0190     int i;
0191 
0192     ret = irq_alloc_domain_generic_chips(d, 32, 1, "INTC",
0193             handle_level_irq, IRQ_NOREQUEST | IRQ_NOPROBE,
0194             IRQ_LEVEL, 0);
0195     if (ret) {
0196         pr_warn("Failed to allocate irq chips\n");
0197         return ret;
0198     }
0199 
0200     for (i = 0; i < omap_nr_pending; i++) {
0201         struct irq_chip_generic *gc;
0202         struct irq_chip_type *ct;
0203 
0204         gc = irq_get_domain_generic_chip(d, 32 * i);
0205         gc->reg_base = base;
0206         ct = gc->chip_types;
0207 
0208         ct->type = IRQ_TYPE_LEVEL_MASK;
0209 
0210         ct->chip.irq_ack = omap_mask_ack_irq;
0211         ct->chip.irq_mask = irq_gc_mask_disable_reg;
0212         ct->chip.irq_unmask = irq_gc_unmask_enable_reg;
0213 
0214         ct->chip.flags |= IRQCHIP_SKIP_SET_WAKE;
0215 
0216         ct->regs.enable = INTC_MIR_CLEAR0 + 32 * i;
0217         ct->regs.disable = INTC_MIR_SET0 + 32 * i;
0218     }
0219 
0220     return 0;
0221 }
0222 
0223 static void __init omap_alloc_gc_legacy(void __iomem *base,
0224         unsigned int irq_start, unsigned int num)
0225 {
0226     struct irq_chip_generic *gc;
0227     struct irq_chip_type *ct;
0228 
0229     gc = irq_alloc_generic_chip("INTC", 1, irq_start, base,
0230             handle_level_irq);
0231     ct = gc->chip_types;
0232     ct->chip.irq_ack = omap_mask_ack_irq;
0233     ct->chip.irq_mask = irq_gc_mask_disable_reg;
0234     ct->chip.irq_unmask = irq_gc_unmask_enable_reg;
0235     ct->chip.flags |= IRQCHIP_SKIP_SET_WAKE;
0236 
0237     ct->regs.enable = INTC_MIR_CLEAR0;
0238     ct->regs.disable = INTC_MIR_SET0;
0239     irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE,
0240             IRQ_NOREQUEST | IRQ_NOPROBE, 0);
0241 }
0242 
0243 static int __init omap_init_irq_of(struct device_node *node)
0244 {
0245     int ret;
0246 
0247     omap_irq_base = of_iomap(node, 0);
0248     if (WARN_ON(!omap_irq_base))
0249         return -ENOMEM;
0250 
0251     domain = irq_domain_add_linear(node, omap_nr_irqs,
0252             &irq_generic_chip_ops, NULL);
0253 
0254     omap_irq_soft_reset();
0255 
0256     ret = omap_alloc_gc_of(domain, omap_irq_base);
0257     if (ret < 0)
0258         irq_domain_remove(domain);
0259 
0260     return ret;
0261 }
0262 
0263 static int __init omap_init_irq_legacy(u32 base, struct device_node *node)
0264 {
0265     int j, irq_base;
0266 
0267     omap_irq_base = ioremap(base, SZ_4K);
0268     if (WARN_ON(!omap_irq_base))
0269         return -ENOMEM;
0270 
0271     irq_base = irq_alloc_descs(-1, 0, omap_nr_irqs, 0);
0272     if (irq_base < 0) {
0273         pr_warn("Couldn't allocate IRQ numbers\n");
0274         irq_base = 0;
0275     }
0276 
0277     domain = irq_domain_add_legacy(node, omap_nr_irqs, irq_base, 0,
0278             &irq_domain_simple_ops, NULL);
0279 
0280     omap_irq_soft_reset();
0281 
0282     for (j = 0; j < omap_nr_irqs; j += 32)
0283         omap_alloc_gc_legacy(omap_irq_base + j, j + irq_base, 32);
0284 
0285     return 0;
0286 }
0287 
0288 static void __init omap_irq_enable_protection(void)
0289 {
0290     u32 reg;
0291 
0292     reg = intc_readl(INTC_PROTECTION);
0293     reg |= INTC_PROTECTION_ENABLE;
0294     intc_writel(INTC_PROTECTION, reg);
0295 }
0296 
0297 static int __init omap_init_irq(u32 base, struct device_node *node)
0298 {
0299     int ret;
0300 
0301     /*
0302      * FIXME legacy OMAP DMA driver sitting under arch/arm/plat-omap/dma.c
0303      * depends is still not ready for linear IRQ domains; because of that
0304      * we need to temporarily "blacklist" OMAP2 and OMAP3 devices from using
0305      * linear IRQ Domain until that driver is finally fixed.
0306      */
0307     if (of_device_is_compatible(node, "ti,omap2-intc") ||
0308             of_device_is_compatible(node, "ti,omap3-intc")) {
0309         struct resource res;
0310 
0311         if (of_address_to_resource(node, 0, &res))
0312             return -ENOMEM;
0313 
0314         base = res.start;
0315         ret = omap_init_irq_legacy(base, node);
0316     } else if (node) {
0317         ret = omap_init_irq_of(node);
0318     } else {
0319         ret = omap_init_irq_legacy(base, NULL);
0320     }
0321 
0322     if (ret == 0)
0323         omap_irq_enable_protection();
0324 
0325     return ret;
0326 }
0327 
0328 static asmlinkage void __exception_irq_entry
0329 omap_intc_handle_irq(struct pt_regs *regs)
0330 {
0331     extern unsigned long irq_err_count;
0332     u32 irqnr;
0333 
0334     irqnr = intc_readl(INTC_SIR);
0335 
0336     /*
0337      * A spurious IRQ can result if interrupt that triggered the
0338      * sorting is no longer active during the sorting (10 INTC
0339      * functional clock cycles after interrupt assertion). Or a
0340      * change in interrupt mask affected the result during sorting
0341      * time. There is no special handling required except ignoring
0342      * the SIR register value just read and retrying.
0343      * See section 6.2.5 of AM335x TRM Literature Number: SPRUH73K
0344      *
0345      * Many a times, a spurious interrupt situation has been fixed
0346      * by adding a flush for the posted write acking the IRQ in
0347      * the device driver. Typically, this is going be the device
0348      * driver whose interrupt was handled just before the spurious
0349      * IRQ occurred. Pay attention to those device drivers if you
0350      * run into hitting the spurious IRQ condition below.
0351      */
0352     if (unlikely((irqnr & SPURIOUSIRQ_MASK) == SPURIOUSIRQ_MASK)) {
0353         pr_err_once("%s: spurious irq!\n", __func__);
0354         irq_err_count++;
0355         omap_ack_irq(NULL);
0356         return;
0357     }
0358 
0359     irqnr &= ACTIVEIRQ_MASK;
0360     generic_handle_domain_irq(domain, irqnr);
0361 }
0362 
0363 static int __init intc_of_init(struct device_node *node,
0364                  struct device_node *parent)
0365 {
0366     int ret;
0367 
0368     omap_nr_pending = 3;
0369     omap_nr_irqs = 96;
0370 
0371     if (WARN_ON(!node))
0372         return -ENODEV;
0373 
0374     if (of_device_is_compatible(node, "ti,dm814-intc") ||
0375         of_device_is_compatible(node, "ti,dm816-intc") ||
0376         of_device_is_compatible(node, "ti,am33xx-intc")) {
0377         omap_nr_irqs = 128;
0378         omap_nr_pending = 4;
0379     }
0380 
0381     ret = omap_init_irq(-1, of_node_get(node));
0382     if (ret < 0)
0383         return ret;
0384 
0385     set_handle_irq(omap_intc_handle_irq);
0386 
0387     return 0;
0388 }
0389 
0390 IRQCHIP_DECLARE(omap2_intc, "ti,omap2-intc", intc_of_init);
0391 IRQCHIP_DECLARE(omap3_intc, "ti,omap3-intc", intc_of_init);
0392 IRQCHIP_DECLARE(dm814x_intc, "ti,dm814-intc", intc_of_init);
0393 IRQCHIP_DECLARE(dm816x_intc, "ti,dm816-intc", intc_of_init);
0394 IRQCHIP_DECLARE(am33xx_intc, "ti,am33xx-intc", intc_of_init);