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