root/arch/arm/mach-omap1/irq.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. irq_bank_readl
  2. irq_bank_writel
  3. omap_ack_irq
  4. omap_mask_ack_irq
  5. omap_irq_set_cfg
  6. omap1_handle_irq
  7. omap_alloc_gc
  8. omap1_init_irq

   1 /*
   2  * linux/arch/arm/mach-omap1/irq.c
   3  *
   4  * Interrupt handler for all OMAP boards
   5  *
   6  * Copyright (C) 2004 Nokia Corporation
   7  * Written by Tony Lindgren <tony@atomide.com>
   8  * Major cleanups by Juha Yrjölä <juha.yrjola@nokia.com>
   9  *
  10  * Completely re-written to support various OMAP chips with bank specific
  11  * interrupt handlers.
  12  *
  13  * Some snippets of the code taken from the older OMAP interrupt handler
  14  * Copyright (C) 2001 RidgeRun, Inc. Greg Lonnon <glonnon@ridgerun.com>
  15  *
  16  * GPIO interrupt handler moved to gpio.c by Juha Yrjola
  17  *
  18  * This program is free software; you can redistribute it and/or modify it
  19  * under the terms of the GNU General Public License as published by the
  20  * Free Software Foundation; either version 2 of the License, or (at your
  21  * option) any later version.
  22  *
  23  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
  24  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  25  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
  26  * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  28  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  29  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  30  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  32  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  33  *
  34  * You should have received a copy of the  GNU General Public License along
  35  * with this program; if not, write  to the Free Software Foundation, Inc.,
  36  * 675 Mass Ave, Cambridge, MA 02139, USA.
  37  */
  38 #include <linux/gpio.h>
  39 #include <linux/init.h>
  40 #include <linux/module.h>
  41 #include <linux/sched.h>
  42 #include <linux/interrupt.h>
  43 #include <linux/io.h>
  44 
  45 #include <asm/irq.h>
  46 #include <asm/exception.h>
  47 #include <asm/mach/irq.h>
  48 
  49 #include "soc.h"
  50 
  51 #include <mach/hardware.h>
  52 
  53 #include "common.h"
  54 
  55 #define IRQ_BANK(irq) ((irq) >> 5)
  56 #define IRQ_BIT(irq)  ((irq) & 0x1f)
  57 
  58 struct omap_irq_bank {
  59         unsigned long base_reg;
  60         void __iomem *va;
  61         unsigned long trigger_map;
  62         unsigned long wake_enable;
  63 };
  64 
  65 static u32 omap_l2_irq;
  66 static unsigned int irq_bank_count;
  67 static struct omap_irq_bank *irq_banks;
  68 static struct irq_domain *domain;
  69 
  70 static inline unsigned int irq_bank_readl(int bank, int offset)
  71 {
  72         return readl_relaxed(irq_banks[bank].va + offset);
  73 }
  74 static inline void irq_bank_writel(unsigned long value, int bank, int offset)
  75 {
  76         writel_relaxed(value, irq_banks[bank].va + offset);
  77 }
  78 
  79 static void omap_ack_irq(int irq)
  80 {
  81         if (irq > 31)
  82                 writel_relaxed(0x1, irq_banks[1].va + IRQ_CONTROL_REG_OFFSET);
  83 
  84         writel_relaxed(0x1, irq_banks[0].va + IRQ_CONTROL_REG_OFFSET);
  85 }
  86 
  87 static void omap_mask_ack_irq(struct irq_data *d)
  88 {
  89         struct irq_chip_type *ct = irq_data_get_chip_type(d);
  90 
  91         ct->chip.irq_mask(d);
  92         omap_ack_irq(d->irq);
  93 }
  94 
  95 /*
  96  * Allows tuning the IRQ type and priority
  97  *
  98  * NOTE: There is currently no OMAP fiq handler for Linux. Read the
  99  *       mailing list threads on FIQ handlers if you are planning to
 100  *       add a FIQ handler for OMAP.
 101  */
 102 static void omap_irq_set_cfg(int irq, int fiq, int priority, int trigger)
 103 {
 104         signed int bank;
 105         unsigned long val, offset;
 106 
 107         bank = IRQ_BANK(irq);
 108         /* FIQ is only available on bank 0 interrupts */
 109         fiq = bank ? 0 : (fiq & 0x1);
 110         val = fiq | ((priority & 0x1f) << 2) | ((trigger & 0x1) << 1);
 111         offset = IRQ_ILR0_REG_OFFSET + IRQ_BIT(irq) * 0x4;
 112         irq_bank_writel(val, bank, offset);
 113 }
 114 
 115 #if defined (CONFIG_ARCH_OMAP730) || defined (CONFIG_ARCH_OMAP850)
 116 static struct omap_irq_bank omap7xx_irq_banks[] = {
 117         { .base_reg = OMAP_IH1_BASE,            .trigger_map = 0xb3f8e22f },
 118         { .base_reg = OMAP_IH2_BASE,            .trigger_map = 0xfdb9c1f2 },
 119         { .base_reg = OMAP_IH2_BASE + 0x100,    .trigger_map = 0x800040f3 },
 120 };
 121 #endif
 122 
 123 #ifdef CONFIG_ARCH_OMAP15XX
 124 static struct omap_irq_bank omap1510_irq_banks[] = {
 125         { .base_reg = OMAP_IH1_BASE,            .trigger_map = 0xb3febfff },
 126         { .base_reg = OMAP_IH2_BASE,            .trigger_map = 0xffbfffed },
 127 };
 128 static struct omap_irq_bank omap310_irq_banks[] = {
 129         { .base_reg = OMAP_IH1_BASE,            .trigger_map = 0xb3faefc3 },
 130         { .base_reg = OMAP_IH2_BASE,            .trigger_map = 0x65b3c061 },
 131 };
 132 #endif
 133 
 134 #if defined(CONFIG_ARCH_OMAP16XX)
 135 
 136 static struct omap_irq_bank omap1610_irq_banks[] = {
 137         { .base_reg = OMAP_IH1_BASE,            .trigger_map = 0xb3fefe8f },
 138         { .base_reg = OMAP_IH2_BASE,            .trigger_map = 0xfdb7c1fd },
 139         { .base_reg = OMAP_IH2_BASE + 0x100,    .trigger_map = 0xffffb7ff },
 140         { .base_reg = OMAP_IH2_BASE + 0x200,    .trigger_map = 0xffffffff },
 141 };
 142 #endif
 143 
 144 asmlinkage void __exception_irq_entry omap1_handle_irq(struct pt_regs *regs)
 145 {
 146         void __iomem *l1 = irq_banks[0].va;
 147         void __iomem *l2 = irq_banks[1].va;
 148         u32 irqnr;
 149 
 150         do {
 151                 irqnr = readl_relaxed(l1 + IRQ_ITR_REG_OFFSET);
 152                 irqnr &= ~(readl_relaxed(l1 + IRQ_MIR_REG_OFFSET) & 0xffffffff);
 153                 if (!irqnr)
 154                         break;
 155 
 156                 irqnr = readl_relaxed(l1 + IRQ_SIR_FIQ_REG_OFFSET);
 157                 if (irqnr)
 158                         goto irq;
 159 
 160                 irqnr = readl_relaxed(l1 + IRQ_SIR_IRQ_REG_OFFSET);
 161                 if (irqnr == omap_l2_irq) {
 162                         irqnr = readl_relaxed(l2 + IRQ_SIR_IRQ_REG_OFFSET);
 163                         if (irqnr)
 164                                 irqnr += 32;
 165                 }
 166 irq:
 167                 if (irqnr)
 168                         handle_domain_irq(domain, irqnr, regs);
 169                 else
 170                         break;
 171         } while (irqnr);
 172 }
 173 
 174 static __init void
 175 omap_alloc_gc(void __iomem *base, unsigned int irq_start, unsigned int num)
 176 {
 177         struct irq_chip_generic *gc;
 178         struct irq_chip_type *ct;
 179 
 180         gc = irq_alloc_generic_chip("MPU", 1, irq_start, base,
 181                                     handle_level_irq);
 182         ct = gc->chip_types;
 183         ct->chip.irq_ack = omap_mask_ack_irq;
 184         ct->chip.irq_mask = irq_gc_mask_set_bit;
 185         ct->chip.irq_unmask = irq_gc_mask_clr_bit;
 186         ct->chip.irq_set_wake = irq_gc_set_wake;
 187         ct->regs.mask = IRQ_MIR_REG_OFFSET;
 188         irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE,
 189                                IRQ_NOREQUEST | IRQ_NOPROBE, 0);
 190 }
 191 
 192 void __init omap1_init_irq(void)
 193 {
 194         struct irq_chip_type *ct;
 195         struct irq_data *d = NULL;
 196         int i, j, irq_base;
 197         unsigned long nr_irqs;
 198 
 199 #if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
 200         if (cpu_is_omap7xx()) {
 201                 irq_banks = omap7xx_irq_banks;
 202                 irq_bank_count = ARRAY_SIZE(omap7xx_irq_banks);
 203         }
 204 #endif
 205 #ifdef CONFIG_ARCH_OMAP15XX
 206         if (cpu_is_omap1510()) {
 207                 irq_banks = omap1510_irq_banks;
 208                 irq_bank_count = ARRAY_SIZE(omap1510_irq_banks);
 209         }
 210         if (cpu_is_omap310()) {
 211                 irq_banks = omap310_irq_banks;
 212                 irq_bank_count = ARRAY_SIZE(omap310_irq_banks);
 213         }
 214 #endif
 215 #if defined(CONFIG_ARCH_OMAP16XX)
 216         if (cpu_is_omap16xx()) {
 217                 irq_banks = omap1610_irq_banks;
 218                 irq_bank_count = ARRAY_SIZE(omap1610_irq_banks);
 219         }
 220 #endif
 221 
 222         for (i = 0; i < irq_bank_count; i++) {
 223                 irq_banks[i].va = ioremap(irq_banks[i].base_reg, 0xff);
 224                 if (WARN_ON(!irq_banks[i].va))
 225                         return;
 226         }
 227 
 228         nr_irqs = irq_bank_count * 32;
 229 
 230         irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
 231         if (irq_base < 0) {
 232                 pr_warn("Couldn't allocate IRQ numbers\n");
 233                 irq_base = 0;
 234         }
 235         omap_l2_irq = cpu_is_omap7xx() ? irq_base + 1 : irq_base;
 236         omap_l2_irq -= NR_IRQS_LEGACY;
 237 
 238         domain = irq_domain_add_legacy(NULL, nr_irqs, irq_base, 0,
 239                                        &irq_domain_simple_ops, NULL);
 240 
 241         pr_info("Total of %lu interrupts in %i interrupt banks\n",
 242                 nr_irqs, irq_bank_count);
 243 
 244         /* Mask and clear all interrupts */
 245         for (i = 0; i < irq_bank_count; i++) {
 246                 irq_bank_writel(~0x0, i, IRQ_MIR_REG_OFFSET);
 247                 irq_bank_writel(0x0, i, IRQ_ITR_REG_OFFSET);
 248         }
 249 
 250         /* Clear any pending interrupts */
 251         irq_bank_writel(0x03, 0, IRQ_CONTROL_REG_OFFSET);
 252         irq_bank_writel(0x03, 1, IRQ_CONTROL_REG_OFFSET);
 253 
 254         /* Enable interrupts in global mask */
 255         if (cpu_is_omap7xx())
 256                 irq_bank_writel(0x0, 0, IRQ_GMR_REG_OFFSET);
 257 
 258         /* Install the interrupt handlers for each bank */
 259         for (i = 0; i < irq_bank_count; i++) {
 260                 for (j = i * 32; j < (i + 1) * 32; j++) {
 261                         int irq_trigger;
 262 
 263                         irq_trigger = irq_banks[i].trigger_map >> IRQ_BIT(j);
 264                         omap_irq_set_cfg(j, 0, 0, irq_trigger);
 265                         irq_clear_status_flags(j, IRQ_NOREQUEST);
 266                 }
 267                 omap_alloc_gc(irq_banks[i].va, irq_base + i * 32, 32);
 268         }
 269 
 270         /* Unmask level 2 handler */
 271         d = irq_get_irq_data(irq_find_mapping(domain, omap_l2_irq));
 272         if (d) {
 273                 ct = irq_data_get_chip_type(d);
 274                 ct->chip.irq_unmask(d);
 275         }
 276 }

/* [<][>][^][v][top][bottom][index][help] */