]>
Commit | Line | Data |
---|---|---|
f780aa2a WD |
1 | /* |
2 | * (C) Copyright 2000-2002 | |
3 | * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | |
4 | * | |
5 | * (C) Copyright 2002 (440 port) | |
6 | * Scott McNutt, Artesyn Communication Producs, smcnutt@artsyncp.com | |
7 | * | |
8 | * See file CREDITS for list of people who contributed to this | |
9 | * project. | |
10 | * | |
11 | * This program is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU General Public License as | |
13 | * published by the Free Software Foundation; either version 2 of | |
14 | * the License, or (at your option) any later version. | |
15 | * | |
16 | * This program is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 | * GNU General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU General Public License | |
22 | * along with this program; if not, write to the Free Software | |
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
24 | * MA 02111-1307 USA | |
25 | */ | |
26 | ||
27 | #include <common.h> | |
28 | #include <watchdog.h> | |
29 | #include <command.h> | |
f780aa2a WD |
30 | #include <asm/processor.h> |
31 | #include <ppc4xx.h> | |
32 | #include <ppc_asm.tmpl> | |
33 | #include <commproc.h> | |
34 | #include "vecnum.h" | |
35 | ||
36 | /****************************************************************************/ | |
37 | ||
f780aa2a WD |
38 | /* |
39 | * CPM interrupt vector functions. | |
40 | */ | |
41 | struct irq_action { | |
42 | interrupt_handler_t *handler; | |
43 | void *arg; | |
44 | int count; | |
45 | }; | |
46 | ||
47 | static struct irq_action irq_vecs[32]; | |
48 | ||
49 | #if defined(CONFIG_440) | |
50 | static struct irq_action irq_vecs1[32]; /* For UIC1 */ | |
51 | ||
52 | void uic1_interrupt( void * parms); /* UIC1 handler */ | |
53 | #endif | |
54 | ||
55 | /****************************************************************************/ | |
f780aa2a WD |
56 | #if defined(CONFIG_440) |
57 | ||
58 | /* SPRN changed in 440 */ | |
59 | static __inline__ void set_evpr(unsigned long val) | |
60 | { | |
61 | asm volatile("mtspr 0x03f,%0" : : "r" (val)); | |
62 | } | |
63 | ||
64 | #else /* !defined(CONFIG_440) */ | |
65 | ||
f780aa2a WD |
66 | static __inline__ void set_pit(unsigned long val) |
67 | { | |
68 | asm volatile("mtpit %0" : : "r" (val)); | |
69 | } | |
70 | ||
71 | ||
72 | static __inline__ void set_tcr(unsigned long val) | |
73 | { | |
74 | asm volatile("mttcr %0" : : "r" (val)); | |
75 | } | |
76 | ||
77 | ||
78 | static __inline__ void set_evpr(unsigned long val) | |
79 | { | |
80 | asm volatile("mtevpr %0" : : "r" (val)); | |
81 | } | |
82 | #endif /* defined(CONFIG_440 */ | |
83 | ||
f780aa2a WD |
84 | /****************************************************************************/ |
85 | ||
a8c7c708 | 86 | int interrupt_init_cpu (unsigned *decrementer_count) |
f780aa2a WD |
87 | { |
88 | DECLARE_GLOBAL_DATA_PTR; | |
89 | ||
90 | int vec; | |
91 | unsigned long val; | |
92 | ||
a8c7c708 WD |
93 | /* decrementer is automatically reloaded */ |
94 | *decrementer_count = 0; | |
95 | ||
f780aa2a WD |
96 | /* |
97 | * Mark all irqs as free | |
98 | */ | |
99 | for (vec=0; vec<32; vec++) { | |
100 | irq_vecs[vec].handler = NULL; | |
101 | irq_vecs[vec].arg = NULL; | |
102 | irq_vecs[vec].count = 0; | |
103 | #if defined(CONFIG_440) | |
104 | irq_vecs1[vec].handler = NULL; | |
105 | irq_vecs1[vec].arg = NULL; | |
106 | irq_vecs1[vec].count = 0; | |
107 | #endif | |
108 | } | |
109 | ||
110 | #ifdef CONFIG_4xx | |
111 | /* | |
112 | * Init PIT | |
113 | */ | |
114 | #if defined(CONFIG_440) | |
115 | val = mfspr( tcr ); | |
116 | val &= (~0x04400000); /* clear DIS & ARE */ | |
117 | mtspr( tcr, val ); | |
118 | mtspr( dec, 0 ); /* Prevent exception after TSR clear*/ | |
119 | mtspr( decar, 0 ); /* clear reload */ | |
120 | mtspr( tsr, 0x08000000 ); /* clear DEC status */ | |
121 | val = gd->bd->bi_intfreq/100; /* 10 msec */ | |
122 | mtspr( decar, val ); /* Set auto-reload value */ | |
123 | mtspr( dec, val ); /* Set inital val */ | |
124 | #else | |
125 | set_pit(gd->bd->bi_intfreq / 1000); | |
126 | #endif | |
127 | #endif /* CONFIG_4xx */ | |
128 | ||
129 | #ifdef CONFIG_ADCIOP | |
130 | /* | |
131 | * Init PIT | |
132 | */ | |
133 | set_pit(66000); | |
134 | #endif | |
135 | ||
136 | /* | |
137 | * Enable PIT | |
138 | */ | |
139 | val = mfspr(tcr); | |
140 | val |= 0x04400000; | |
141 | mtspr(tcr, val); | |
142 | ||
143 | /* | |
144 | * Set EVPR to 0 | |
145 | */ | |
146 | set_evpr(0x00000000); | |
147 | ||
148 | #if defined(CONFIG_440) | |
149 | /* Install the UIC1 handlers */ | |
150 | irq_install_handler(VECNUM_UIC1NC, uic1_interrupt, 0); | |
151 | irq_install_handler(VECNUM_UIC1C, uic1_interrupt, 0); | |
152 | #endif | |
f780aa2a WD |
153 | |
154 | return (0); | |
155 | } | |
156 | ||
157 | /****************************************************************************/ | |
158 | ||
159 | /* | |
160 | * Handle external interrupts | |
161 | */ | |
162 | void external_interrupt(struct pt_regs *regs) | |
163 | { | |
164 | ulong uic_msr; | |
165 | ulong msr_shift; | |
166 | int vec; | |
167 | ||
168 | /* | |
169 | * Read masked interrupt status register to determine interrupt source | |
170 | */ | |
171 | uic_msr = mfdcr(uicmsr); | |
172 | msr_shift = uic_msr; | |
173 | vec = 0; | |
174 | ||
175 | while (msr_shift != 0) { | |
176 | if (msr_shift & 0x80000000) { | |
177 | /* | |
178 | * Increment irq counter (for debug purpose only) | |
179 | */ | |
180 | irq_vecs[vec].count++; | |
181 | ||
182 | if (irq_vecs[vec].handler != NULL) { | |
183 | /* call isr */ | |
184 | (*irq_vecs[vec].handler)(irq_vecs[vec].arg); | |
185 | } else { | |
186 | mtdcr(uicer, mfdcr(uicer) & ~(0x80000000 >> vec)); | |
187 | printf ("Masking bogus interrupt vector 0x%x\n", vec); | |
188 | } | |
189 | ||
190 | /* | |
191 | * After servicing the interrupt, we have to remove the status indicator. | |
192 | */ | |
193 | mtdcr(uicsr, (0x80000000 >> vec)); | |
194 | } | |
195 | ||
196 | /* | |
197 | * Shift msr to next position and increment vector | |
198 | */ | |
199 | msr_shift <<= 1; | |
200 | vec++; | |
201 | } | |
202 | } | |
203 | ||
204 | #if defined(CONFIG_440) | |
205 | /* Handler for UIC1 interrupt */ | |
206 | void uic1_interrupt( void * parms) | |
207 | { | |
208 | ulong uic1_msr; | |
209 | ulong msr_shift; | |
210 | int vec; | |
211 | ||
212 | /* | |
213 | * Read masked interrupt status register to determine interrupt source | |
214 | */ | |
215 | uic1_msr = mfdcr(uic1msr); | |
216 | msr_shift = uic1_msr; | |
217 | vec = 0; | |
218 | ||
219 | while (msr_shift != 0) { | |
220 | if (msr_shift & 0x80000000) { | |
221 | /* | |
222 | * Increment irq counter (for debug purpose only) | |
223 | */ | |
224 | irq_vecs1[vec].count++; | |
225 | ||
226 | if (irq_vecs1[vec].handler != NULL) { | |
227 | /* call isr */ | |
228 | (*irq_vecs1[vec].handler)(irq_vecs1[vec].arg); | |
229 | } else { | |
230 | mtdcr(uic1er, mfdcr(uic1er) & ~(0x80000000 >> vec)); | |
231 | printf ("Masking bogus interrupt vector (uic1) 0x%x\n", vec); | |
232 | } | |
233 | ||
234 | /* | |
235 | * After servicing the interrupt, we have to remove the status indicator. | |
236 | */ | |
237 | mtdcr(uic1sr, (0x80000000 >> vec)); | |
238 | } | |
239 | ||
240 | /* | |
241 | * Shift msr to next position and increment vector | |
242 | */ | |
243 | msr_shift <<= 1; | |
244 | vec++; | |
245 | } | |
246 | } | |
247 | #endif /* defined(CONFIG_440) */ | |
248 | ||
249 | /****************************************************************************/ | |
250 | ||
251 | /* | |
252 | * Install and free a interrupt handler. | |
253 | */ | |
254 | ||
255 | void | |
256 | irq_install_handler(int vec, interrupt_handler_t *handler, void *arg) | |
257 | { | |
258 | struct irq_action *irqa = irq_vecs; | |
259 | int i = vec; | |
260 | ||
261 | #if defined(CONFIG_440) | |
262 | if (vec > 31) { | |
263 | i = vec - 32; | |
264 | irqa = irq_vecs1; | |
265 | } | |
266 | #endif | |
267 | ||
268 | if (irqa[i].handler != NULL) { | |
269 | printf ("Interrupt vector %d: handler 0x%x replacing 0x%x\n", | |
270 | vec, (uint)handler, (uint)irqa[i].handler); | |
271 | } | |
272 | irqa[i].handler = handler; | |
273 | irqa[i].arg = arg; | |
274 | ||
275 | #if defined(CONFIG_440) | |
276 | if( vec > 31 ) | |
277 | mtdcr(uic1er, mfdcr(uic1er) | (0x80000000 >> i)); | |
278 | else | |
279 | #endif | |
280 | mtdcr(uicer, mfdcr(uicer) | (0x80000000 >> i)); | |
281 | #if 0 | |
282 | printf ("Install interrupt for vector %d ==> %p\n", vec, handler); | |
283 | #endif | |
284 | } | |
285 | ||
286 | void | |
287 | irq_free_handler(int vec) | |
288 | { | |
289 | struct irq_action *irqa = irq_vecs; | |
290 | int i = vec; | |
291 | ||
292 | #if defined(CONFIG_440) | |
293 | if (vec > 31) { | |
294 | irqa = irq_vecs1; | |
295 | i = vec - 32; | |
296 | } | |
297 | #endif | |
298 | ||
299 | #if 0 | |
300 | printf ("Free interrupt for vector %d ==> %p\n", | |
301 | vec, irq_vecs[vec].handler); | |
302 | #endif | |
303 | ||
304 | #if defined(CONFIG_440) | |
305 | if (vec > 31) | |
306 | mtdcr(uic1er, mfdcr(uic1er) & ~(0x80000000 >> i)); | |
307 | else | |
308 | #endif | |
309 | mtdcr(uicer, mfdcr(uicer) & ~(0x80000000 >> i)); | |
310 | ||
311 | irqa[i].handler = NULL; | |
312 | irqa[i].arg = NULL; | |
313 | } | |
314 | ||
315 | /****************************************************************************/ | |
316 | ||
a8c7c708 | 317 | void timer_interrupt_cpu (struct pt_regs *regs) |
f780aa2a | 318 | { |
a8c7c708 WD |
319 | /* nothing to do here */ |
320 | return; | |
f780aa2a WD |
321 | } |
322 | ||
323 | /****************************************************************************/ | |
324 | ||
f780aa2a WD |
325 | #if (CONFIG_COMMANDS & CFG_CMD_IRQ) |
326 | ||
327 | /******************************************************************************* | |
328 | * | |
329 | * irqinfo - print information about PCI devices | |
330 | * | |
331 | */ | |
332 | int | |
333 | do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) | |
334 | { | |
335 | int vec; | |
336 | ||
337 | printf ("\nInterrupt-Information:\n"); | |
338 | #if defined(CONFIG_440) | |
339 | printf ("\nUIC 0\n"); | |
340 | #endif | |
341 | printf ("Nr Routine Arg Count\n"); | |
342 | ||
343 | for (vec=0; vec<32; vec++) { | |
344 | if (irq_vecs[vec].handler != NULL) { | |
345 | printf ("%02d %08lx %08lx %d\n", | |
346 | vec, | |
347 | (ulong)irq_vecs[vec].handler, | |
348 | (ulong)irq_vecs[vec].arg, | |
349 | irq_vecs[vec].count); | |
350 | } | |
351 | } | |
352 | ||
353 | #if defined(CONFIG_440) | |
354 | printf ("\nUIC 1\n"); | |
355 | printf ("Nr Routine Arg Count\n"); | |
356 | ||
357 | for (vec=0; vec<32; vec++) | |
358 | { | |
359 | if (irq_vecs1[vec].handler != NULL) | |
360 | printf ("%02d %08lx %08lx %d\n", | |
361 | vec+31, (ulong)irq_vecs1[vec].handler, | |
362 | (ulong)irq_vecs1[vec].arg, irq_vecs1[vec].count); | |
363 | } | |
364 | printf("\n"); | |
365 | #endif | |
366 | return 0; | |
367 | } | |
368 | ||
369 | ||
370 | #endif /* CONFIG_COMMANDS & CFG_CMD_IRQ */ |