1/* irq.c: FRV IRQ handling 2 * 3 * Copyright (C) 2003, 2004, 2006 Red Hat, Inc. All Rights Reserved. 4 * Written by David Howells (dhowells@redhat.com) 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 9 * 2 of the License, or (at your option) any later version. 10 */ 11 12#include <linux/ptrace.h> 13#include <linux/errno.h> 14#include <linux/signal.h> 15#include <linux/sched.h> 16#include <linux/ioport.h> 17#include <linux/interrupt.h> 18#include <linux/timex.h> 19#include <linux/slab.h> 20#include <linux/random.h> 21#include <linux/init.h> 22#include <linux/kernel_stat.h> 23#include <linux/irq.h> 24#include <linux/proc_fs.h> 25#include <linux/seq_file.h> 26#include <linux/module.h> 27 28#include <asm/atomic.h> 29#include <asm/io.h> 30#include <asm/smp.h> 31#include <asm/system.h> 32#include <asm/bitops.h> 33#include <asm/uaccess.h> 34#include <asm/pgalloc.h> 35#include <asm/delay.h> 36#include <asm/irq.h> 37#include <asm/irc-regs.h> 38#include <asm/gdb-stub.h> 39 40#define set_IRR(N,A,B,C,D) __set_IRR(N, (A << 28) | (B << 24) | (C << 20) | (D << 16)) 41 42extern void __init fpga_init(void); 43#ifdef CONFIG_FUJITSU_MB93493 44extern void __init mb93493_init(void); 45#endif 46 47#define __reg16(ADDR) (*(volatile unsigned short *)(ADDR)) 48 49atomic_t irq_err_count; 50 51/* 52 * Generic, controller-independent functions: 53 */ 54int show_interrupts(struct seq_file *p, void *v) 55{ 56 int i = *(loff_t *) v, cpu; 57 struct irqaction * action; 58 unsigned long flags; 59 60 if (i == 0) { 61 char cpuname[12]; 62 63 seq_printf(p, " "); 64 for_each_present_cpu(cpu) { 65 sprintf(cpuname, "CPU%d", cpu); 66 seq_printf(p, " %10s", cpuname); 67 } 68 seq_putc(p, '\n'); 69 } 70 71 if (i < NR_IRQS) { 72 spin_lock_irqsave(&irq_desc[i].lock, flags); 73 action = irq_desc[i].action; 74 if (action) { 75 seq_printf(p, "%3d: ", i); 76 for_each_present_cpu(cpu) 77 seq_printf(p, "%10u ", kstat_cpu(cpu).irqs[i]); 78 seq_printf(p, " %10s", irq_desc[i].chip->name ? : "-"); 79 seq_printf(p, " %s", action->name); 80 for (action = action->next; 81 action; 82 action = action->next) 83 seq_printf(p, ", %s", action->name); 84 85 seq_putc(p, '\n'); 86 } 87 88 spin_unlock_irqrestore(&irq_desc[i].lock, flags); 89 } else if (i == NR_IRQS) { 90 seq_printf(p, "Err: %10u\n", atomic_read(&irq_err_count)); 91 } 92 93 return 0; 94} 95 96/* 97 * on-CPU PIC operations 98 */ 99static void frv_cpupic_ack(unsigned int irqlevel) 100{ 101 __clr_RC(irqlevel); 102 __clr_IRL(); 103} 104 105static void frv_cpupic_mask(unsigned int irqlevel) 106{ 107 __set_MASK(irqlevel); 108} 109 110static void frv_cpupic_mask_ack(unsigned int irqlevel) 111{ 112 __set_MASK(irqlevel); 113 __clr_RC(irqlevel); 114 __clr_IRL(); 115} 116 117static void frv_cpupic_unmask(unsigned int irqlevel) 118{ 119 __clr_MASK(irqlevel); 120} 121 122static void frv_cpupic_end(unsigned int irqlevel) 123{ 124 __clr_MASK(irqlevel); 125} 126 127static struct irq_chip frv_cpu_pic = { 128 .name = "cpu", 129 .ack = frv_cpupic_ack, 130 .mask = frv_cpupic_mask, 131 .mask_ack = frv_cpupic_mask_ack, 132 .unmask = frv_cpupic_unmask, 133 .end = frv_cpupic_end, 134}; 135 136/* 137 * handles all normal device IRQ's 138 * - registers are referred to by the __frame variable (GR28) 139 * - IRQ distribution is complicated in this arch because of the many PICs, the 140 * way they work and the way they cascade 141 */ 142asmlinkage void do_IRQ(void) 143{ 144 irq_enter(); 145 generic_handle_irq(__get_IRL()); 146 irq_exit(); 147} 148 149/* 150 * handles all NMIs when not co-opted by the debugger 151 * - registers are referred to by the __frame variable (GR28) 152 */ 153asmlinkage void do_NMI(void) 154{ 155} 156 157/* 158 * initialise the interrupt system 159 */ 160void __init init_IRQ(void) 161{ 162 int level; 163 164 for (level = 1; level <= 14; level++) 165 set_irq_chip_and_handler(level, &frv_cpu_pic, 166 handle_level_irq); 167 168 set_irq_handler(IRQ_CPU_TIMER0, handle_edge_irq); 169 170 /* set the trigger levels for internal interrupt sources 171 * - timers all falling-edge 172 * - ERR0 is rising-edge 173 * - all others are high-level 174 */ 175 __set_IITMR(0, 0x003f0000); /* DMA0-3, TIMER0-2 */ 176 __set_IITMR(1, 0x20000000); /* ERR0-1, UART0-1, DMA4-7 */ 177 178 /* route internal interrupts */ 179 set_IRR(4, IRQ_DMA3_LEVEL, IRQ_DMA2_LEVEL, IRQ_DMA1_LEVEL, 180 IRQ_DMA0_LEVEL); 181 set_IRR(5, 0, IRQ_TIMER2_LEVEL, IRQ_TIMER1_LEVEL, IRQ_TIMER0_LEVEL); 182 set_IRR(6, IRQ_GDBSTUB_LEVEL, IRQ_GDBSTUB_LEVEL, 183 IRQ_UART1_LEVEL, IRQ_UART0_LEVEL); 184 set_IRR(7, IRQ_DMA7_LEVEL, IRQ_DMA6_LEVEL, IRQ_DMA5_LEVEL, 185 IRQ_DMA4_LEVEL); 186 187 /* route external interrupts */ 188 set_IRR(2, IRQ_XIRQ7_LEVEL, IRQ_XIRQ6_LEVEL, IRQ_XIRQ5_LEVEL, 189 IRQ_XIRQ4_LEVEL); 190 set_IRR(3, IRQ_XIRQ3_LEVEL, IRQ_XIRQ2_LEVEL, IRQ_XIRQ1_LEVEL, 191 IRQ_XIRQ0_LEVEL); 192 193#if defined(CONFIG_MB93091_VDK) 194 __set_TM1(0x55550000); /* XIRQ7-0 all active low */ 195#elif defined(CONFIG_MB93093_PDK) 196 __set_TM1(0x15550000); /* XIRQ7 active high, 6-0 all active low */ 197#else 198#error dont know external IRQ trigger levels for this setup 199#endif 200 201 fpga_init(); 202#ifdef CONFIG_FUJITSU_MB93493 203 mb93493_init(); 204#endif 205} 206