1/* 2 * Carsten Langgaard, carstenl@mips.com 3 * Copyright (C) 2000, 2001, 2004 MIPS Technologies, Inc. 4 * Copyright (C) 2001 Ralf Baechle 5 * 6 * This program is free software; you can distribute it and/or modify it 7 * under the terms of the GNU General Public License (Version 2) as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. 18 * 19 * Routines for generic manipulation of the interrupts found on the MIPS 20 * Malta board. 21 * The interrupt controller is located in the South Bridge a PIIX4 device 22 * with two internal 82C95 interrupt controllers. 23 */ 24#include <linux/init.h> 25#include <linux/irq.h> 26#include <linux/sched.h> 27#include <linux/slab.h> 28#include <linux/interrupt.h> 29#include <linux/io.h> 30#include <linux/kernel_stat.h> 31#include <linux/kernel.h> 32#include <linux/random.h> 33 34#include <asm/traps.h> 35#include <asm/irq_cpu.h> 36#include <asm/irq_regs.h> 37#include <asm/mips-boards/generic.h> 38#include <asm/mips-boards/sead3int.h> 39#include <asm/gic.h> 40 41#define SEAD_CONFIG_GIC_PRESENT_SHF (1) 42#define SEAD_CONFIG_GIC_PRESENT_MSK (1 << SEAD_CONFIG_GIC_PRESENT_SHF) 43#define SEAD_CONFIG_BASE (0x1B100110) 44#define SEAD_CONFIG_SIZE (4) 45 46int gic_present; /* global var => auto initialized to 0 */ 47static unsigned long sead3_config_reg; 48 49/* 50 * This table defines the setup for each external GIC interrupt 51 * It is indexed by interrupt number 52 */ 53#define GIC_CPU_NMI GIC_MAP_TO_NMI_MSK 54static struct gic_intr_map gic_intr_map[GIC_NUM_INTRS] = { 55 { 0, GIC_CPU_INT4, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT }, 56 { 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT }, 57 { 0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT }, 58 { 0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT }, 59 { 0, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT }, 60 { 0, GIC_CPU_INT0, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT }, 61 { 0, GIC_CPU_INT0, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT }, 62 { 0, GIC_CPU_INT0, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT }, 63 { 0, GIC_CPU_INT0, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT }, 64 { X, X, X, X, 0 }, 65 { X, X, X, X, 0 }, 66 { X, X, X, X, 0 }, 67 { X, X, X, X, 0 }, 68 { X, X, X, X, 0 }, 69 { X, X, X, X, 0 }, 70 { X, X, X, X, 0 }, 71 /* The remainder of this table is initialised by fill_ipi_map */ 72}; 73 74/* 75 * Version of ffs that only looks at bits 8..15 76 */ 77static inline unsigned int irq_ffs(unsigned int pending) 78{ 79#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64) 80 return fls(pending) - CAUSEB_IP - 1; 81#else 82 unsigned int a0 = 7; 83 unsigned int t0; 84 85 t0 = pending & 0xf000; 86 t0 = t0 < 1; 87 t0 = t0 << 2; 88 a0 = a0 - t0; 89 pending = pending << t0; 90 91 t0 = pending & 0xc000; 92 t0 = t0 < 1; 93 t0 = t0 << 1; 94 a0 = a0 - t0; 95 pending = pending << t0; 96 97 t0 = pending & 0x8000; 98 t0 = t0 < 1; 99 /* t0 = t0 << 2; */ 100 a0 = a0 - t0; 101 /* pending = pending << t0; */ 102 103 return a0; 104#endif 105} 106 107asmlinkage void plat_irq_dispatch(void) 108{ 109 unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM; 110 int irq; 111 112 irq = irq_ffs(pending); 113 114 if (irq >= 0) 115 do_IRQ(MIPS_CPU_IRQ_BASE + irq); 116 else 117 spurious_interrupt(); 118} 119 120void __init arch_init_irq(void) 121{ 122 int i; 123 124 if (!cpu_has_veic) { 125 mips_cpu_irq_init(); 126 127 if (cpu_has_vint) { 128 /* install generic handler */ 129 for (i = 0; i < 8; i++) 130 set_vi_handler(i, plat_irq_dispatch); 131 } 132 } 133 134 sead3_config_reg = (unsigned long)ioremap_nocache(SEAD_CONFIG_BASE, SEAD_CONFIG_SIZE); 135 gic_present = (REG32(sead3_config_reg) & SEAD_CONFIG_GIC_PRESENT_MSK) >> 136 SEAD_CONFIG_GIC_PRESENT_SHF; 137 printk("GIC: %spresent\n", (gic_present) ? "" : "not "); 138 printk("EIC: %s\n", (current_cpu_data.options & MIPS_CPU_VEIC) ? "on" : "off"); 139 140 if (gic_present) { 141 gic_init(GIC_BASE_ADDR, GIC_ADDRSPACE_SZ, gic_intr_map, 142 ARRAY_SIZE(gic_intr_map), MIPS_GIC_IRQ_BASE); 143 } 144} 145