1/* 2 * arch/mips/philips/nino/irq.c 3 * 4 * Copyright (C) 2001 Steven J. Hill (sjhill@realitydiluted.com) 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 * 10 * Interrupt service routines for Philips Nino 11 */ 12#include <linux/config.h> 13#include <linux/init.h> 14#include <linux/sched.h> 15#include <linux/interrupt.h> 16#include <asm/io.h> 17#include <asm/mipsregs.h> 18#include <asm/tx3912.h> 19 20#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5) 21 22extern asmlinkage void do_IRQ(int irq, struct pt_regs *regs); 23 24static void enable_irq6(unsigned int irq) 25{ 26 if(irq == 0) { 27 outl(inl(TX3912_INT6_ENABLE) | 28 TX3912_INT6_ENABLE_PRIORITYMASK_PERINT, 29 TX3912_INT6_ENABLE); 30 outl(inl(TX3912_INT5_ENABLE) | TX3912_INT5_PERINT, 31 TX3912_INT5_ENABLE); 32 } 33 if(irq == 3) { 34 outl(inl(TX3912_INT6_ENABLE) | 35 TX3912_INT6_ENABLE_PRIORITYMASK_UARTARXINT, 36 TX3912_INT6_ENABLE); 37 outl(inl(TX3912_INT2_ENABLE) | TX3912_INT2_UARTA_RX_BITS, 38 TX3912_INT2_ENABLE); 39 } 40} 41 42static unsigned int startup_irq6(unsigned int irq) 43{ 44 enable_irq6(irq); 45 46 return 0; /* Never anything pending */ 47} 48 49static void disable_irq6(unsigned int irq) 50{ 51 if(irq == 0) { 52 outl(inl(TX3912_INT6_ENABLE) & 53 ~TX3912_INT6_ENABLE_PRIORITYMASK_PERINT, 54 TX3912_INT6_ENABLE); 55 outl(inl(TX3912_INT5_ENABLE) & ~TX3912_INT5_PERINT, 56 TX3912_INT5_ENABLE); 57 outl(inl(TX3912_INT5_CLEAR) | TX3912_INT5_PERINT, 58 TX3912_INT5_CLEAR); 59 } 60 if(irq == 3) { 61 outl(inl(TX3912_INT6_ENABLE) & 62 ~TX3912_INT6_ENABLE_PRIORITYMASK_UARTARXINT, 63 TX3912_INT6_ENABLE); 64 outl(inl(TX3912_INT2_ENABLE) & ~TX3912_INT2_UARTA_RX_BITS, 65 TX3912_INT2_ENABLE); 66 } 67} 68 69#define shutdown_irq6 disable_irq6 70#define mask_and_ack_irq6 disable_irq6 71 72static void end_irq6(unsigned int irq) 73{ 74 if(!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) 75 enable_irq6(irq); 76} 77 78static struct hw_interrupt_type irq6_type = { 79 "MIPS", 80 startup_irq6, 81 shutdown_irq6, 82 enable_irq6, 83 disable_irq6, 84 mask_and_ack_irq6, 85 end_irq6, 86 NULL 87}; 88 89void irq6_dispatch(struct pt_regs *regs) 90{ 91 int irq = -1; 92 93 if((inl(TX3912_INT6_STATUS) & TX3912_INT6_STATUS_INTVEC_UARTARXINT) == 94 TX3912_INT6_STATUS_INTVEC_UARTARXINT) { 95 irq = 3; 96 goto done; 97 } 98 if ((inl(TX3912_INT6_STATUS) & TX3912_INT6_STATUS_INTVEC_PERINT) == 99 TX3912_INT6_STATUS_INTVEC_PERINT) { 100 irq = 0; 101 goto done; 102 } 103 104 /* if irq == -1, then interrupt was cleared or is invalid */ 105 if (irq == -1) { 106 panic("Unhandled High Priority PR31700 Interrupt = 0x%08x", 107 inl(TX3912_INT6_STATUS)); 108 } 109 110done: 111 do_IRQ(irq, regs); 112} 113 114static void enable_irq4(unsigned int irq) 115{ 116 set_c0_status(STATUSF_IP4); 117 if (irq == 2) { 118 outl(inl(TX3912_INT2_CLEAR) | TX3912_INT2_UARTA_TX_BITS, 119 TX3912_INT2_CLEAR); 120 outl(inl(TX3912_INT2_ENABLE) | TX3912_INT2_UARTA_TX_BITS, 121 TX3912_INT2_ENABLE); 122 } 123} 124 125static unsigned int startup_irq4(unsigned int irq) 126{ 127 enable_irq4(irq); 128 129 return 0; /* Never anything pending */ 130} 131 132static void disable_irq4(unsigned int irq) 133{ 134 clear_c0_status(STATUSF_IP4); 135} 136 137#define shutdown_irq4 disable_irq4 138#define mask_and_ack_irq4 disable_irq4 139 140static void end_irq4(unsigned int irq) 141{ 142 if(!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) 143 enable_irq4(irq); 144} 145 146static struct hw_interrupt_type irq4_type = { 147 "MIPS", 148 startup_irq4, 149 shutdown_irq4, 150 enable_irq4, 151 disable_irq4, 152 mask_and_ack_irq4, 153 end_irq4, 154 NULL 155}; 156 157void irq4_dispatch(struct pt_regs *regs) 158{ 159 int irq = -1; 160 161 if(inl(TX3912_INT2_STATUS) & TX3912_INT2_UARTA_TX_BITS) { 162 irq = 2; 163 goto done; 164 } 165 166 /* if irq == -1, then interrupt was cleared or is invalid */ 167 if (irq == -1) { 168 printk("PR31700 Interrupt Status Register 1 = 0x%08x\n", 169 inl(TX3912_INT1_STATUS)); 170 printk("PR31700 Interrupt Status Register 2 = 0x%08x\n", 171 inl(TX3912_INT2_STATUS)); 172 printk("PR31700 Interrupt Status Register 3 = 0x%08x\n", 173 inl(TX3912_INT3_STATUS)); 174 printk("PR31700 Interrupt Status Register 4 = 0x%08x\n", 175 inl(TX3912_INT4_STATUS)); 176 printk("PR31700 Interrupt Status Register 5 = 0x%08x\n", 177 inl(TX3912_INT5_STATUS)); 178 panic("Unhandled Low Priority PR31700 Interrupt"); 179 } 180 181done: 182 do_IRQ(irq, regs); 183 return; 184} 185 186void irq_bad(struct pt_regs *regs) 187{ 188 /* This should never happen */ 189 printk(" CAUSE register = 0x%08lx\n", regs->cp0_cause); 190 printk("STATUS register = 0x%08lx\n", regs->cp0_status); 191 printk(" EPC register = 0x%08lx\n", regs->cp0_epc); 192 panic("Stray interrupt, spinning..."); 193} 194 195void __init nino_irq_setup(void) 196{ 197 extern asmlinkage void ninoIRQ(void); 198 199 unsigned int i; 200 201 /* Disable all hardware interrupts */ 202 change_c0_status(ST0_IM, 0x00); 203 204 /* Clear interrupts */ 205 outl(0xffffffff, TX3912_INT1_CLEAR); 206 outl(0xffffffff, TX3912_INT2_CLEAR); 207 outl(0xffffffff, TX3912_INT3_CLEAR); 208 outl(0xffffffff, TX3912_INT4_CLEAR); 209 outl(0xffffffff, TX3912_INT5_CLEAR); 210 211 outl(0x00000000, TX3912_INT1_ENABLE); 212 outl(0x00000000, TX3912_INT2_ENABLE); 213 outl(0x00000000, TX3912_INT3_ENABLE); 214 outl(0x00000000, TX3912_INT4_ENABLE); 215 outl(0x00000000, TX3912_INT5_ENABLE); 216 217 /* Initialize IRQ vector table */ 218 init_generic_irq(); 219 220 /* Initialize IRQ action handlers */ 221 for (i = 0; i < 16; i++) { 222 hw_irq_controller *handler = NULL; 223 if (i == 0 || i == 3) 224 handler = &irq6_type; 225 else 226 handler = &irq4_type; 227 228 irq_desc[i].status = IRQ_DISABLED; 229 irq_desc[i].action = 0; 230 irq_desc[i].depth = 1; 231 irq_desc[i].handler = handler; 232 } 233 234 /* Set up the external interrupt exception vector */ 235 set_except_vector(0, ninoIRQ); 236 237 /* Enable high priority interrupts */ 238 outl(TX3912_INT6_ENABLE_GLOBALEN | TX3912_INT6_ENABLE_HIGH_PRIORITY, 239 TX3912_INT6_ENABLE); 240 241 /* Enable all interrupts */ 242 change_c0_status(ST0_IM, ALLINTS); 243} 244 245void (*irq_setup)(void); 246 247void __init init_IRQ(void) 248{ 249#ifdef CONFIG_REMOTE_DEBUG 250 extern void breakpoint(void); 251 extern void set_debug_traps(void); 252 253 printk("Wait for gdb client connection ...\n"); 254 set_debug_traps(); 255 breakpoint(); 256#endif 257 258 /* Invoke board-specific irq setup */ 259 irq_setup(); 260} 261