2 * (C) Copyright 2000-2002
5 * (C) Copyright 2002 (440 port)
8 * (C) Copyright 2003 (440GX port)
11 * See file CREDITS for list of people who contributed to this
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License as
16 * published by the Free Software Foundation; either version 2 of
17 * the License, or (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
33 #include <asm/processor.h>
35 #include <ppc_asm.tmpl>
39 /****************************************************************************/
42 * CPM interrupt vector functions.
45 interrupt_handler_t *handler;
50 static struct irq_action irq_vecs[32];
52 #if defined(CONFIG_440)
53 static struct irq_action irq_vecs1[32]; /* For UIC1 */
55 void uic1_interrupt( void * parms); /* UIC1 handler */
57 #if defined(CONFIG_440_GX)
58 static struct irq_action irq_vecs2[32]; /* For UIC2 */
60 void uic0_interrupt( void * parms); /* UIC0 handler */
61 void uic2_interrupt( void * parms); /* UIC2 handler */
62 #endif /* CONFIG_440_GX */
64 #endif /* CONFIG_440 */
66 /****************************************************************************/
67 #if defined(CONFIG_440)
69 /* SPRN changed in 440 */
70 static __inline__ void set_evpr(unsigned long val)
72 asm volatile("mtspr 0x03f,%0" : : "r" (val));
75 #else /* !defined(CONFIG_440) */
77 static __inline__ void set_pit(unsigned long val)
79 asm volatile("mtpit %0" : : "r" (val));
83 static __inline__ void set_tcr(unsigned long val)
85 asm volatile("mttcr %0" : : "r" (val));
89 static __inline__ void set_evpr(unsigned long val)
91 asm volatile("mtevpr %0" : : "r" (val));
93 #endif /* defined(CONFIG_440 */
95 /****************************************************************************/
97 int interrupt_init_cpu (unsigned *decrementer_count)
99 DECLARE_GLOBAL_DATA_PTR;
104 /* decrementer is automatically reloaded */
105 *decrementer_count = 0;
108 * Mark all irqs as free
110 for (vec=0; vec<32; vec++) {
111 irq_vecs[vec].handler = NULL;
112 irq_vecs[vec].arg = NULL;
113 irq_vecs[vec].count = 0;
114 #if defined(CONFIG_440)
115 irq_vecs1[vec].handler = NULL;
116 irq_vecs1[vec].arg = NULL;
117 irq_vecs1[vec].count = 0;
118 #if defined(CONFIG_440_GX)
119 irq_vecs2[vec].handler = NULL;
120 irq_vecs2[vec].arg = NULL;
121 irq_vecs2[vec].count = 0;
122 #endif /* CONFIG_440_GX */
130 #if defined(CONFIG_440)
132 val &= (~0x04400000); /* clear DIS & ARE */
134 mtspr( dec, 0 ); /* Prevent exception after TSR clear*/
135 mtspr( decar, 0 ); /* clear reload */
136 mtspr( tsr, 0x08000000 ); /* clear DEC status */
137 val = gd->bd->bi_intfreq/100; /* 10 msec */
138 mtspr( decar, val ); /* Set auto-reload value */
139 mtspr( dec, val ); /* Set inital val */
141 set_pit(gd->bd->bi_intfreq / 1000);
143 #endif /* CONFIG_4xx */
162 set_evpr(0x00000000);
164 #if defined(CONFIG_440)
165 #if !defined(CONFIG_440_GX)
166 /* Install the UIC1 handlers */
167 irq_install_handler(VECNUM_UIC1NC, uic1_interrupt, 0);
168 irq_install_handler(VECNUM_UIC1C, uic1_interrupt, 0);
172 #if defined(CONFIG_440_GX)
173 /* Enable UIC interrupts via UIC Base Enable Register */
174 mtdcr(uicb0er, UICB0_ALL);
175 mtdcr(uicb0cr, UICB0_ALL);
181 /****************************************************************************/
184 * Handle external interrupts
186 #if defined(CONFIG_440_GX)
187 void external_interrupt(struct pt_regs *regs)
192 * Read masked interrupt status register to determine interrupt source
194 /* 440 GX uses base uic register */
195 uic_msr = mfdcr(uicb0msr);
201 mtdcr(uicb0sr, UICB0_ALL);
205 } /* external_interrupt CONFIG_440_GX */
209 void external_interrupt(struct pt_regs *regs)
216 * Read masked interrupt status register to determine interrupt source
218 uic_msr = mfdcr(uicmsr);
222 while (msr_shift != 0) {
223 if (msr_shift & 0x80000000) {
225 * Increment irq counter (for debug purpose only)
227 irq_vecs[vec].count++;
229 if (irq_vecs[vec].handler != NULL) {
231 (*irq_vecs[vec].handler)(irq_vecs[vec].arg);
233 mtdcr(uicer, mfdcr(uicer) & ~(0x80000000 >> vec));
234 printf ("Masking bogus interrupt vector 0x%x\n", vec);
238 * After servicing the interrupt, we have to remove the status indicator.
240 mtdcr(uicsr, (0x80000000 >> vec));
244 * Shift msr to next position and increment vector
252 #if defined(CONFIG_440_GX)
253 /* Handler for UIC0 interrupt */
254 void uic0_interrupt( void * parms)
261 * Read masked interrupt status register to determine interrupt source
263 uic_msr = mfdcr(uicmsr);
267 while (msr_shift != 0) {
268 if (msr_shift & 0x80000000) {
270 * Increment irq counter (for debug purpose only)
272 irq_vecs[vec].count++;
274 if (irq_vecs[vec].handler != NULL) {
276 (*irq_vecs[vec].handler)(irq_vecs[vec].arg);
278 mtdcr(uicer, mfdcr(uicer) & ~(0x80000000 >> vec));
279 printf ("Masking bogus interrupt vector (uic0) 0x%x\n", vec);
283 * After servicing the interrupt, we have to remove the status indicator.
285 mtdcr(uicsr, (0x80000000 >> vec));
289 * Shift msr to next position and increment vector
296 #endif /* CONFIG_440_GX */
298 #if defined(CONFIG_440)
299 /* Handler for UIC1 interrupt */
300 void uic1_interrupt( void * parms)
307 * Read masked interrupt status register to determine interrupt source
309 uic1_msr = mfdcr(uic1msr);
310 msr_shift = uic1_msr;
313 while (msr_shift != 0) {
314 if (msr_shift & 0x80000000) {
316 * Increment irq counter (for debug purpose only)
318 irq_vecs1[vec].count++;
320 if (irq_vecs1[vec].handler != NULL) {
322 (*irq_vecs1[vec].handler)(irq_vecs1[vec].arg);
324 mtdcr(uic1er, mfdcr(uic1er) & ~(0x80000000 >> vec));
325 printf ("Masking bogus interrupt vector (uic1) 0x%x\n", vec);
329 * After servicing the interrupt, we have to remove the status indicator.
331 mtdcr(uic1sr, (0x80000000 >> vec));
335 * Shift msr to next position and increment vector
341 #endif /* defined(CONFIG_440) */
343 #if defined(CONFIG_440_GX)
344 /* Handler for UIC1 interrupt */
345 void uic2_interrupt( void * parms)
352 * Read masked interrupt status register to determine interrupt source
354 uic2_msr = mfdcr(uic2msr);
355 msr_shift = uic2_msr;
358 while (msr_shift != 0) {
359 if (msr_shift & 0x80000000) {
361 * Increment irq counter (for debug purpose only)
363 irq_vecs2[vec].count++;
365 if (irq_vecs2[vec].handler != NULL) {
367 (*irq_vecs2[vec].handler)(irq_vecs2[vec].arg);
369 mtdcr(uic2er, mfdcr(uic2er) & ~(0x80000000 >> vec));
370 printf ("Masking bogus interrupt vector (uic1) 0x%x\n", vec);
374 * After servicing the interrupt, we have to remove the status indicator.
376 mtdcr(uic2sr, (0x80000000 >> vec));
380 * Shift msr to next position and increment vector
386 #endif /* defined(CONFIG_440_GX) */
388 /****************************************************************************/
391 * Install and free a interrupt handler.
394 void irq_install_handler (int vec, interrupt_handler_t * handler, void *arg)
396 struct irq_action *irqa = irq_vecs;
399 #if defined(CONFIG_440)
400 #if defined(CONFIG_440_GX)
401 if ((vec > 31) && (vec < 64)) {
404 } else if (vec > 63) {
408 #else /* CONFIG_440_GX */
413 #endif /* CONFIG_440_GX */
414 #endif /* CONFIG_440 */
416 if (irqa[i].handler != NULL) {
417 printf ("Interrupt vector %d: handler 0x%x replacing 0x%x\n",
418 vec, (uint) handler, (uint) irqa[i].handler);
420 irqa[i].handler = handler;
423 #if defined(CONFIG_440)
424 #if defined(CONFIG_440_GX)
425 if ((vec > 31) && (vec < 64))
426 mtdcr (uic1er, mfdcr (uic1er) | (0x80000000 >> i));
428 mtdcr (uic2er, mfdcr (uic2er) | (0x80000000 >> i));
430 #endif /* CONFIG_440_GX */
432 mtdcr (uic1er, mfdcr (uic1er) | (0x80000000 >> i));
435 mtdcr (uicer, mfdcr (uicer) | (0x80000000 >> i));
437 printf ("Install interrupt for vector %d ==> %p\n", vec, handler);
441 void irq_free_handler (int vec)
443 struct irq_action *irqa = irq_vecs;
446 #if defined(CONFIG_440)
447 #if defined(CONFIG_440_GX)
448 if ((vec > 31) && (vec < 64)) {
451 } else if (vec > 63) {
455 #endif /* CONFIG_440_GX */
463 printf ("Free interrupt for vector %d ==> %p\n",
464 vec, irq_vecs[vec].handler);
467 #if defined(CONFIG_440)
468 #if defined(CONFIG_440_GX)
469 if ((vec > 31) && (vec < 64))
470 mtdcr (uic1er, mfdcr (uic1er) & ~(0x80000000 >> i));
472 mtdcr (uic2er, mfdcr (uic2er) & ~(0x80000000 >> i));
474 #endif /* CONFIG_440_GX */
476 mtdcr (uic1er, mfdcr (uic1er) & ~(0x80000000 >> i));
479 mtdcr (uicer, mfdcr (uicer) & ~(0x80000000 >> i));
481 irqa[i].handler = NULL;
485 /****************************************************************************/
487 void timer_interrupt_cpu (struct pt_regs *regs)
489 /* nothing to do here */
493 /****************************************************************************/
495 #if (CONFIG_COMMANDS & CFG_CMD_IRQ)
497 /*******************************************************************************
499 * irqinfo - print information about PCI devices
503 do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
507 printf ("\nInterrupt-Information:\n");
508 #if defined(CONFIG_440)
509 printf ("\nUIC 0\n");
511 printf ("Nr Routine Arg Count\n");
513 for (vec=0; vec<32; vec++) {
514 if (irq_vecs[vec].handler != NULL) {
515 printf ("%02d %08lx %08lx %d\n",
517 (ulong)irq_vecs[vec].handler,
518 (ulong)irq_vecs[vec].arg,
519 irq_vecs[vec].count);
523 #if defined(CONFIG_440)
524 printf ("\nUIC 1\n");
525 printf ("Nr Routine Arg Count\n");
527 for (vec=0; vec<32; vec++) {
528 if (irq_vecs1[vec].handler != NULL)
529 printf ("%02d %08lx %08lx %d\n",
530 vec+31, (ulong)irq_vecs1[vec].handler,
531 (ulong)irq_vecs1[vec].arg, irq_vecs1[vec].count);
536 #if defined(CONFIG_440_GX)
537 printf ("\nUIC 2\n");
538 printf ("Nr Routine Arg Count\n");
540 for (vec=0; vec<32; vec++) {
541 if (irq_vecs2[vec].handler != NULL)
542 printf ("%02d %08lx %08lx %d\n",
543 vec+63, (ulong)irq_vecs2[vec].handler,
544 (ulong)irq_vecs2[vec].arg, irq_vecs2[vec].count);
551 #endif /* CONFIG_COMMANDS & CFG_CMD_IRQ */