1/* 2 * linux/arch/arm/mach-omap2/irq.c 3 * 4 * Interrupt handler for OMAP2 boards. 5 * 6 * Copyright (C) 2005 Nokia Corporation 7 * Author: Paul Mundt <paul.mundt@nokia.com> 8 * 9 * This file is subject to the terms and conditions of the GNU General Public 10 * License. See the file "COPYING" in the main directory of this archive 11 * for more details. 12 */ 13#include <linux/kernel.h> 14#include <linux/init.h> 15#include <linux/interrupt.h> 16#include <linux/io.h> 17#include <mach/hardware.h> 18#include <asm/mach/irq.h> 19 20 21/* selected INTC register offsets */ 22 23#define INTC_REVISION 0x0000 24#define INTC_SYSCONFIG 0x0010 25#define INTC_SYSSTATUS 0x0014 26#define INTC_SIR 0x0040 27#define INTC_CONTROL 0x0048 28#define INTC_PROTECTION 0x004C 29#define INTC_IDLE 0x0050 30#define INTC_THRESHOLD 0x0068 31#define INTC_MIR0 0x0084 32#define INTC_MIR_CLEAR0 0x0088 33#define INTC_MIR_SET0 0x008c 34#define INTC_PENDING_IRQ0 0x0098 35/* Number of IRQ state bits in each MIR register */ 36#define IRQ_BITS_PER_REG 32 37 38/* 39 * OMAP2 has a number of different interrupt controllers, each interrupt 40 * controller is identified as its own "bank". Register definitions are 41 * fairly consistent for each bank, but not all registers are implemented 42 * for each bank.. when in doubt, consult the TRM. 43 */ 44static struct omap_irq_bank { 45 void __iomem *base_reg; 46 unsigned int nr_irqs; 47} __attribute__ ((aligned(4))) irq_banks[] = { 48 { 49 /* MPU INTC */ 50 .base_reg = 0, 51 .nr_irqs = 96, 52 }, 53}; 54 55/* Structure to save interrupt controller context */ 56struct omap3_intc_regs { 57 u32 sysconfig; 58 u32 protection; 59 u32 idle; 60 u32 threshold; 61 u32 ilr[INTCPS_NR_IRQS]; 62 u32 mir[INTCPS_NR_MIR_REGS]; 63}; 64 65static struct omap3_intc_regs intc_context[ARRAY_SIZE(irq_banks)]; 66 67/* INTC bank register get/set */ 68 69static void intc_bank_write_reg(u32 val, struct omap_irq_bank *bank, u16 reg) 70{ 71 __raw_writel(val, bank->base_reg + reg); 72} 73 74static u32 intc_bank_read_reg(struct omap_irq_bank *bank, u16 reg) 75{ 76 return __raw_readl(bank->base_reg + reg); 77} 78 79static int previous_irq; 80 81/* 82 * On 34xx we can get occasional spurious interrupts if the ack from 83 * an interrupt handler does not get posted before we unmask. Warn about 84 * the interrupt handlers that need to flush posted writes. 85 */ 86static int omap_check_spurious(unsigned int irq) 87{ 88 u32 sir, spurious; 89 90 sir = intc_bank_read_reg(&irq_banks[0], INTC_SIR); 91 spurious = sir >> 7; 92 93 if (spurious) { 94 printk(KERN_WARNING "Spurious irq %i: 0x%08x, please flush " 95 "posted write for irq %i\n", 96 irq, sir, previous_irq); 97 return spurious; 98 } 99 100 return 0; 101} 102 103static void omap_ack_irq(unsigned int irq) 104{ 105 intc_bank_write_reg(0x1, &irq_banks[0], INTC_CONTROL); 106} 107 108static void omap_mask_irq(unsigned int irq) 109{ 110 int offset = irq & (~(IRQ_BITS_PER_REG - 1)); 111 112 if (cpu_is_omap34xx()) { 113 int spurious = 0; 114 115 /* 116 * INT_34XX_GPT12_IRQ is also the spurious irq. Maybe because 117 * it is the highest irq number? 118 */ 119 if (irq == INT_34XX_GPT12_IRQ) 120 spurious = omap_check_spurious(irq); 121 122 if (!spurious) 123 previous_irq = irq; 124 } 125 126 irq &= (IRQ_BITS_PER_REG - 1); 127 128 intc_bank_write_reg(1 << irq, &irq_banks[0], INTC_MIR_SET0 + offset); 129} 130 131static void omap_unmask_irq(unsigned int irq) 132{ 133 int offset = irq & (~(IRQ_BITS_PER_REG - 1)); 134 135 irq &= (IRQ_BITS_PER_REG - 1); 136 137 intc_bank_write_reg(1 << irq, &irq_banks[0], INTC_MIR_CLEAR0 + offset); 138} 139 140static void omap_mask_ack_irq(unsigned int irq) 141{ 142 omap_mask_irq(irq); 143 omap_ack_irq(irq); 144} 145 146static struct irq_chip omap_irq_chip = { 147 .name = "INTC", 148 .ack = omap_mask_ack_irq, 149 .mask = omap_mask_irq, 150 .unmask = omap_unmask_irq, 151}; 152 153static void __init omap_irq_bank_init_one(struct omap_irq_bank *bank) 154{ 155 unsigned long tmp; 156 157 tmp = intc_bank_read_reg(bank, INTC_REVISION) & 0xff; 158 printk(KERN_INFO "IRQ: Found an INTC at 0x%p " 159 "(revision %ld.%ld) with %d interrupts\n", 160 bank->base_reg, tmp >> 4, tmp & 0xf, bank->nr_irqs); 161 162 tmp = intc_bank_read_reg(bank, INTC_SYSCONFIG); 163 tmp |= 1 << 1; /* soft reset */ 164 intc_bank_write_reg(tmp, bank, INTC_SYSCONFIG); 165 166 while (!(intc_bank_read_reg(bank, INTC_SYSSTATUS) & 0x1)) 167 /* Wait for reset to complete */; 168 169 /* Enable autoidle */ 170 intc_bank_write_reg(1 << 0, bank, INTC_SYSCONFIG); 171} 172 173int omap_irq_pending(void) 174{ 175 int i; 176 177 for (i = 0; i < ARRAY_SIZE(irq_banks); i++) { 178 struct omap_irq_bank *bank = irq_banks + i; 179 int irq; 180 181 for (irq = 0; irq < bank->nr_irqs; irq += 32) 182 if (intc_bank_read_reg(bank, INTC_PENDING_IRQ0 + 183 ((irq >> 5) << 5))) 184 return 1; 185 } 186 return 0; 187} 188 189void __init omap_init_irq(void) 190{ 191 unsigned long nr_of_irqs = 0; 192 unsigned int nr_banks = 0; 193 int i; 194 195 for (i = 0; i < ARRAY_SIZE(irq_banks); i++) { 196 unsigned long base = 0; 197 struct omap_irq_bank *bank = irq_banks + i; 198 199 if (cpu_is_omap24xx()) 200 base = OMAP24XX_IC_BASE; 201 else if (cpu_is_omap34xx()) 202 base = OMAP34XX_IC_BASE; 203 204 BUG_ON(!base); 205 206 /* Static mapping, never released */ 207 bank->base_reg = ioremap(base, SZ_4K); 208 if (!bank->base_reg) { 209 printk(KERN_ERR "Could not ioremap irq bank%i\n", i); 210 continue; 211 } 212 213 omap_irq_bank_init_one(bank); 214 215 nr_of_irqs += bank->nr_irqs; 216 nr_banks++; 217 } 218 219 printk(KERN_INFO "Total of %ld interrupts on %d active controller%s\n", 220 nr_of_irqs, nr_banks, nr_banks > 1 ? "s" : ""); 221 222 for (i = 0; i < nr_of_irqs; i++) { 223 set_irq_chip(i, &omap_irq_chip); 224 set_irq_handler(i, handle_level_irq); 225 set_irq_flags(i, IRQF_VALID); 226 } 227} 228 229#ifdef CONFIG_ARCH_OMAP3 230void omap_intc_save_context(void) 231{ 232 int ind = 0, i = 0; 233 for (ind = 0; ind < ARRAY_SIZE(irq_banks); ind++) { 234 struct omap_irq_bank *bank = irq_banks + ind; 235 intc_context[ind].sysconfig = 236 intc_bank_read_reg(bank, INTC_SYSCONFIG); 237 intc_context[ind].protection = 238 intc_bank_read_reg(bank, INTC_PROTECTION); 239 intc_context[ind].idle = 240 intc_bank_read_reg(bank, INTC_IDLE); 241 intc_context[ind].threshold = 242 intc_bank_read_reg(bank, INTC_THRESHOLD); 243 for (i = 0; i < INTCPS_NR_IRQS; i++) 244 intc_context[ind].ilr[i] = 245 intc_bank_read_reg(bank, (0x100 + 0x4*i)); 246 for (i = 0; i < INTCPS_NR_MIR_REGS; i++) 247 intc_context[ind].mir[i] = 248 intc_bank_read_reg(&irq_banks[0], INTC_MIR0 + 249 (0x20 * i)); 250 } 251} 252 253void omap_intc_restore_context(void) 254{ 255 int ind = 0, i = 0; 256 257 for (ind = 0; ind < ARRAY_SIZE(irq_banks); ind++) { 258 struct omap_irq_bank *bank = irq_banks + ind; 259 intc_bank_write_reg(intc_context[ind].sysconfig, 260 bank, INTC_SYSCONFIG); 261 intc_bank_write_reg(intc_context[ind].sysconfig, 262 bank, INTC_SYSCONFIG); 263 intc_bank_write_reg(intc_context[ind].protection, 264 bank, INTC_PROTECTION); 265 intc_bank_write_reg(intc_context[ind].idle, 266 bank, INTC_IDLE); 267 intc_bank_write_reg(intc_context[ind].threshold, 268 bank, INTC_THRESHOLD); 269 for (i = 0; i < INTCPS_NR_IRQS; i++) 270 intc_bank_write_reg(intc_context[ind].ilr[i], 271 bank, (0x100 + 0x4*i)); 272 for (i = 0; i < INTCPS_NR_MIR_REGS; i++) 273 intc_bank_write_reg(intc_context[ind].mir[i], 274 &irq_banks[0], INTC_MIR0 + (0x20 * i)); 275 } 276 /* MIRs are saved and restore with other PRCM registers */ 277} 278 279void omap3_intc_suspend(void) 280{ 281 /* A pending interrupt would prevent OMAP from entering suspend */ 282 omap_ack_irq(0); 283} 284 285void omap3_intc_prepare_idle(void) 286{ 287 /* Disable autoidle as it can stall interrupt controller */ 288 intc_bank_write_reg(0, &irq_banks[0], INTC_SYSCONFIG); 289} 290 291void omap3_intc_resume_idle(void) 292{ 293 /* Re-enable autoidle */ 294 intc_bank_write_reg(1, &irq_banks[0], INTC_SYSCONFIG); 295} 296#endif /* CONFIG_ARCH_OMAP3 */ 297