2 * (C) Copyright 2000-2002
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5 * (C) Copyright 2002 (440 port)
6 * Scott McNutt, Artesyn Communication Producs, smcnutt@artsyncp.com
8 * (C) Copyright 2003 (440GX port)
9 * Travis B. Sawyer, Sandburst Corporation, tsawyer@sandburst.com
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 DECLARE_GLOBAL_DATA_PTR;
41 /****************************************************************************/
44 * CPM interrupt vector functions.
47 interrupt_handler_t *handler;
52 static struct irq_action irq_vecs[32];
53 void uic0_interrupt( void * parms); /* UIC0 handler */
55 #if defined(CONFIG_440)
56 static struct irq_action irq_vecs1[32]; /* For UIC1 */
58 void uic1_interrupt( void * parms); /* UIC1 handler */
60 #if defined(CONFIG_440GX) || defined(CONFIG_440SPE)
61 static struct irq_action irq_vecs2[32]; /* For UIC2 */
62 void uic2_interrupt( void * parms); /* UIC2 handler */
63 #endif /* CONFIG_440GX CONFIG_440SPE */
65 #if defined(CONFIG_440SPE)
66 static struct irq_action irq_vecs3[32]; /* For UIC3 */
67 void uic3_interrupt( void * parms); /* UIC3 handler */
68 #endif /* CONFIG_440SPE */
70 #endif /* CONFIG_440 */
72 /****************************************************************************/
73 #if defined(CONFIG_440)
75 /* SPRN changed in 440 */
76 static __inline__ void set_evpr(unsigned long val)
78 asm volatile("mtspr 0x03f,%0" : : "r" (val));
81 #else /* !defined(CONFIG_440) */
83 static __inline__ void set_pit(unsigned long val)
85 asm volatile("mtpit %0" : : "r" (val));
89 static __inline__ void set_tcr(unsigned long val)
91 asm volatile("mttcr %0" : : "r" (val));
95 static __inline__ void set_evpr(unsigned long val)
97 asm volatile("mtevpr %0" : : "r" (val));
99 #endif /* defined(CONFIG_440 */
101 /****************************************************************************/
103 int interrupt_init_cpu (unsigned *decrementer_count)
108 /* decrementer is automatically reloaded */
109 *decrementer_count = 0;
112 * Mark all irqs as free
114 for (vec=0; vec<32; vec++) {
115 irq_vecs[vec].handler = NULL;
116 irq_vecs[vec].arg = NULL;
117 irq_vecs[vec].count = 0;
118 #if defined(CONFIG_440)
119 irq_vecs1[vec].handler = NULL;
120 irq_vecs1[vec].arg = NULL;
121 irq_vecs1[vec].count = 0;
122 #if defined(CONFIG_440GX) || defined(CONFIG_440SPE)
123 irq_vecs2[vec].handler = NULL;
124 irq_vecs2[vec].arg = NULL;
125 irq_vecs2[vec].count = 0;
126 #endif /* CONFIG_440GX */
127 #if defined(CONFIG_440SPE)
128 irq_vecs3[vec].handler = NULL;
129 irq_vecs3[vec].arg = NULL;
130 irq_vecs3[vec].count = 0;
131 #endif /* CONFIG_440SPE */
139 #if defined(CONFIG_440)
141 val &= (~0x04400000); /* clear DIS & ARE */
143 mtspr( dec, 0 ); /* Prevent exception after TSR clear*/
144 mtspr( decar, 0 ); /* clear reload */
145 mtspr( tsr, 0x08000000 ); /* clear DEC status */
146 val = gd->bd->bi_intfreq/1000; /* 1 msec */
147 mtspr( decar, val ); /* Set auto-reload value */
148 mtspr( dec, val ); /* Set inital val */
150 set_pit(gd->bd->bi_intfreq / 1000);
152 #endif /* CONFIG_4xx */
171 set_evpr(0x00000000);
173 #if defined(CONFIG_440)
174 #if !defined(CONFIG_440GX)
175 /* Install the UIC1 handlers */
176 irq_install_handler(VECNUM_UIC1NC, uic1_interrupt, 0);
177 irq_install_handler(VECNUM_UIC1C, uic1_interrupt, 0);
181 #if defined(CONFIG_440GX)
182 /* Take the GX out of compatibility mode
183 * Travis Sawyer, 9 Mar 2004
184 * NOTE: 440gx user manual inconsistency here
185 * Compatibility mode and Ethernet Clock select are not
186 * correct in the manual
192 /* Enable UIC interrupts via UIC Base Enable Register */
193 mtdcr(uicb0sr, UICB0_ALL);
194 mtdcr(uicb0er, 0x54000000);
195 /* None are critical */
202 /****************************************************************************/
205 * Handle external interrupts
207 #if defined(CONFIG_440GX)
208 void external_interrupt(struct pt_regs *regs)
213 * Read masked interrupt status register to determine interrupt source
215 /* 440 GX uses base uic register */
216 uic_msr = mfdcr(uicb0msr);
218 if ( (UICB0_UIC0CI & uic_msr) || (UICB0_UIC0NCI & uic_msr) )
221 if ( (UICB0_UIC1CI & uic_msr) || (UICB0_UIC1NCI & uic_msr) )
224 if ( (UICB0_UIC2CI & uic_msr) || (UICB0_UIC2NCI & uic_msr) )
227 mtdcr(uicb0sr, uic_msr);
231 } /* external_interrupt CONFIG_440GX */
233 #elif defined(CONFIG_440SPE)
234 void external_interrupt(struct pt_regs *regs)
239 * Read masked interrupt status register to determine interrupt source
241 /* 440 SPe uses base uic register */
242 uic_msr = mfdcr(uic0msr);
244 if ( (UICB0_UIC1CI & uic_msr) || (UICB0_UIC1NCI & uic_msr) )
247 if ( (UICB0_UIC2CI & uic_msr) || (UICB0_UIC2NCI & uic_msr) )
250 if ( (UICB0_UIC3CI & uic_msr) || (UICB0_UIC3NCI & uic_msr) )
253 if (uic_msr & ~(UICB0_ALL))
256 mtdcr(uic0sr, uic_msr);
259 } /* external_interrupt CONFIG_440SPE */
263 void external_interrupt(struct pt_regs *regs)
270 * Read masked interrupt status register to determine interrupt source
272 uic_msr = mfdcr(uicmsr);
276 while (msr_shift != 0) {
277 if (msr_shift & 0x80000000) {
279 * Increment irq counter (for debug purpose only)
281 irq_vecs[vec].count++;
283 if (irq_vecs[vec].handler != NULL) {
285 (*irq_vecs[vec].handler)(irq_vecs[vec].arg);
287 mtdcr(uicer, mfdcr(uicer) & ~(0x80000000 >> vec));
288 printf ("Masking bogus interrupt vector 0x%x\n", vec);
292 * After servicing the interrupt, we have to remove the status indicator.
294 mtdcr(uicsr, (0x80000000 >> vec));
298 * Shift msr to next position and increment vector
306 #if defined(CONFIG_440GX) || defined(CONFIG_440SPE)
307 /* Handler for UIC0 interrupt */
308 void uic0_interrupt( void * parms)
315 * Read masked interrupt status register to determine interrupt source
317 uic_msr = mfdcr(uicmsr);
321 while (msr_shift != 0) {
322 if (msr_shift & 0x80000000) {
324 * Increment irq counter (for debug purpose only)
326 irq_vecs[vec].count++;
328 if (irq_vecs[vec].handler != NULL) {
330 (*irq_vecs[vec].handler)(irq_vecs[vec].arg);
332 mtdcr(uicer, mfdcr(uicer) & ~(0x80000000 >> vec));
333 printf ("Masking bogus interrupt vector (uic0) 0x%x\n", vec);
337 * After servicing the interrupt, we have to remove the status indicator.
339 mtdcr(uicsr, (0x80000000 >> vec));
343 * Shift msr to next position and increment vector
350 #endif /* CONFIG_440GX */
352 #if defined(CONFIG_440)
353 /* Handler for UIC1 interrupt */
354 void uic1_interrupt( void * parms)
361 * Read masked interrupt status register to determine interrupt source
363 uic1_msr = mfdcr(uic1msr);
364 msr_shift = uic1_msr;
367 while (msr_shift != 0) {
368 if (msr_shift & 0x80000000) {
370 * Increment irq counter (for debug purpose only)
372 irq_vecs1[vec].count++;
374 if (irq_vecs1[vec].handler != NULL) {
376 (*irq_vecs1[vec].handler)(irq_vecs1[vec].arg);
378 mtdcr(uic1er, mfdcr(uic1er) & ~(0x80000000 >> vec));
379 printf ("Masking bogus interrupt vector (uic1) 0x%x\n", vec);
383 * After servicing the interrupt, we have to remove the status indicator.
385 mtdcr(uic1sr, (0x80000000 >> vec));
389 * Shift msr to next position and increment vector
395 #endif /* defined(CONFIG_440) */
397 #if defined(CONFIG_440GX) || defined(CONFIG_440SPE)
398 /* Handler for UIC2 interrupt */
399 void uic2_interrupt( void * parms)
406 * Read masked interrupt status register to determine interrupt source
408 uic2_msr = mfdcr(uic2msr);
409 msr_shift = uic2_msr;
412 while (msr_shift != 0) {
413 if (msr_shift & 0x80000000) {
415 * Increment irq counter (for debug purpose only)
417 irq_vecs2[vec].count++;
419 if (irq_vecs2[vec].handler != NULL) {
421 (*irq_vecs2[vec].handler)(irq_vecs2[vec].arg);
423 mtdcr(uic2er, mfdcr(uic2er) & ~(0x80000000 >> vec));
424 printf ("Masking bogus interrupt vector (uic2) 0x%x\n", vec);
428 * After servicing the interrupt, we have to remove the status indicator.
430 mtdcr(uic2sr, (0x80000000 >> vec));
434 * Shift msr to next position and increment vector
440 #endif /* defined(CONFIG_440GX) */
442 #if defined(CONFIG_440SPE)
443 /* Handler for UIC3 interrupt */
444 void uic3_interrupt( void * parms)
451 * Read masked interrupt status register to determine interrupt source
453 uic3_msr = mfdcr(uic3msr);
454 msr_shift = uic3_msr;
457 while (msr_shift != 0) {
458 if (msr_shift & 0x80000000) {
460 * Increment irq counter (for debug purpose only)
462 irq_vecs3[vec].count++;
464 if (irq_vecs3[vec].handler != NULL) {
466 (*irq_vecs3[vec].handler)(irq_vecs3[vec].arg);
468 mtdcr(uic3er, mfdcr(uic3er) & ~(0x80000000 >> vec));
469 printf ("Masking bogus interrupt vector (uic3) 0x%x\n", vec);
473 * After servicing the interrupt, we have to remove the status indicator.
475 mtdcr(uic3sr, (0x80000000 >> vec));
479 * Shift msr to next position and increment vector
485 #endif /* defined(CONFIG_440SPE) */
487 /****************************************************************************/
490 * Install and free a interrupt handler.
493 void irq_install_handler (int vec, interrupt_handler_t * handler, void *arg)
495 struct irq_action *irqa = irq_vecs;
498 #if defined(CONFIG_440)
499 #if defined(CONFIG_440GX) || defined(CONFIG_440SPE)
500 if ((vec > 31) && (vec < 64)) {
503 } else if (vec > 63) {
507 #else /* CONFIG_440GX */
512 #endif /* CONFIG_440GX */
513 #endif /* CONFIG_440 */
516 * print warning when replacing with a different irq vector
518 if ((irqa[i].handler != NULL) && (irqa[i].handler != handler)) {
519 printf ("Interrupt vector %d: handler 0x%x replacing 0x%x\n",
520 vec, (uint) handler, (uint) irqa[i].handler);
522 irqa[i].handler = handler;
525 #if defined(CONFIG_440)
526 #if defined(CONFIG_440GX) || defined(CONFIG_440SPE)
527 if ((vec > 31) && (vec < 64))
528 mtdcr (uic1er, mfdcr (uic1er) | (0x80000000 >> i));
530 mtdcr (uic2er, mfdcr (uic2er) | (0x80000000 >> i));
532 #endif /* CONFIG_440GX */
534 mtdcr (uic1er, mfdcr (uic1er) | (0x80000000 >> i));
537 mtdcr (uicer, mfdcr (uicer) | (0x80000000 >> i));
539 printf ("Install interrupt for vector %d ==> %p\n", vec, handler);
543 void irq_free_handler (int vec)
545 struct irq_action *irqa = irq_vecs;
548 #if defined(CONFIG_440)
549 #if defined(CONFIG_440GX) || defined(CONFIG_440SPE)
550 if ((vec > 31) && (vec < 64)) {
553 } else if (vec > 63) {
557 #endif /* CONFIG_440GX */
565 printf ("Free interrupt for vector %d ==> %p\n",
566 vec, irq_vecs[vec].handler);
569 #if defined(CONFIG_440)
570 #if defined(CONFIG_440GX) || defined(CONFIG_440SPE)
571 if ((vec > 31) && (vec < 64))
572 mtdcr (uic1er, mfdcr (uic1er) & ~(0x80000000 >> i));
574 mtdcr (uic2er, mfdcr (uic2er) & ~(0x80000000 >> i));
576 #endif /* CONFIG_440GX */
578 mtdcr (uic1er, mfdcr (uic1er) & ~(0x80000000 >> i));
581 mtdcr (uicer, mfdcr (uicer) & ~(0x80000000 >> i));
583 irqa[i].handler = NULL;
587 /****************************************************************************/
589 void timer_interrupt_cpu (struct pt_regs *regs)
591 /* nothing to do here */
595 /****************************************************************************/
597 #if (CONFIG_COMMANDS & CFG_CMD_IRQ)
599 /*******************************************************************************
601 * irqinfo - print information about PCI devices
605 do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
609 printf ("\nInterrupt-Information:\n");
610 #if defined(CONFIG_440)
611 printf ("\nUIC 0\n");
613 printf ("Nr Routine Arg Count\n");
615 for (vec=0; vec<32; vec++) {
616 if (irq_vecs[vec].handler != NULL) {
617 printf ("%02d %08lx %08lx %d\n",
619 (ulong)irq_vecs[vec].handler,
620 (ulong)irq_vecs[vec].arg,
621 irq_vecs[vec].count);
625 #if defined(CONFIG_440)
626 printf ("\nUIC 1\n");
627 printf ("Nr Routine Arg Count\n");
629 for (vec=0; vec<32; vec++) {
630 if (irq_vecs1[vec].handler != NULL)
631 printf ("%02d %08lx %08lx %d\n",
632 vec+31, (ulong)irq_vecs1[vec].handler,
633 (ulong)irq_vecs1[vec].arg, irq_vecs1[vec].count);
638 #if defined(CONFIG_440GX) || defined(CONFIG_440SPE)
639 printf ("\nUIC 2\n");
640 printf ("Nr Routine Arg Count\n");
642 for (vec=0; vec<32; vec++) {
643 if (irq_vecs2[vec].handler != NULL)
644 printf ("%02d %08lx %08lx %d\n",
645 vec+63, (ulong)irq_vecs2[vec].handler,
646 (ulong)irq_vecs2[vec].arg, irq_vecs2[vec].count);
651 #if defined(CONFIG_440SPE)
652 printf ("\nUIC 3\n");
653 printf ("Nr Routine Arg Count\n");
655 for (vec=0; vec<32; vec++) {
656 if (irq_vecs3[vec].handler != NULL)
657 printf ("%02d %08lx %08lx %d\n",
658 vec+63, (ulong)irq_vecs3[vec].handler,
659 (ulong)irq_vecs3[vec].arg, irq_vecs3[vec].count);
666 #endif /* CONFIG_COMMANDS & CFG_CMD_IRQ */