]>
git.ipfire.org Git - people/ms/u-boot.git/blob - cpu/ppc4xx/interrupts.c
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 defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
62 static struct irq_action irq_vecs2
[32]; /* For UIC2 */
63 void uic2_interrupt( void * parms
); /* UIC2 handler */
64 #endif /* CONFIG_440GX CONFIG_440SPE */
66 #if defined(CONFIG_440SPE) || defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
67 static struct irq_action irq_vecs3
[32]; /* For UIC3 */
68 void uic3_interrupt( void * parms
); /* UIC3 handler */
69 #endif /* CONFIG_440SPE */
71 #endif /* CONFIG_440 */
73 /****************************************************************************/
74 #if defined(CONFIG_440)
76 /* SPRN changed in 440 */
77 static __inline__
void set_evpr(unsigned long val
)
79 asm volatile("mtspr 0x03f,%0" : : "r" (val
));
82 #else /* !defined(CONFIG_440) */
84 static __inline__
void set_pit(unsigned long val
)
86 asm volatile("mtpit %0" : : "r" (val
));
90 static __inline__
void set_tcr(unsigned long val
)
92 asm volatile("mttcr %0" : : "r" (val
));
96 static __inline__
void set_evpr(unsigned long val
)
98 asm volatile("mtevpr %0" : : "r" (val
));
100 #endif /* defined(CONFIG_440 */
102 /****************************************************************************/
104 int interrupt_init_cpu (unsigned *decrementer_count
)
109 /* decrementer is automatically reloaded */
110 *decrementer_count
= 0;
113 * Mark all irqs as free
115 for (vec
=0; vec
<32; vec
++) {
116 irq_vecs
[vec
].handler
= NULL
;
117 irq_vecs
[vec
].arg
= NULL
;
118 irq_vecs
[vec
].count
= 0;
119 #if defined(CONFIG_440)
120 irq_vecs1
[vec
].handler
= NULL
;
121 irq_vecs1
[vec
].arg
= NULL
;
122 irq_vecs1
[vec
].count
= 0;
123 #if defined(CONFIG_440GX) || defined(CONFIG_440SPE) || \
124 defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
125 irq_vecs2
[vec
].handler
= NULL
;
126 irq_vecs2
[vec
].arg
= NULL
;
127 irq_vecs2
[vec
].count
= 0;
128 #endif /* CONFIG_440GX */
129 #if defined(CONFIG_440SPE) || defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
130 irq_vecs3
[vec
].handler
= NULL
;
131 irq_vecs3
[vec
].arg
= NULL
;
132 irq_vecs3
[vec
].count
= 0;
133 #endif /* CONFIG_440SPE */
141 #if defined(CONFIG_440)
143 val
&= (~0x04400000); /* clear DIS & ARE */
145 mtspr( dec
, 0 ); /* Prevent exception after TSR clear*/
146 mtspr( decar
, 0 ); /* clear reload */
147 mtspr( tsr
, 0x08000000 ); /* clear DEC status */
148 val
= gd
->bd
->bi_intfreq
/1000; /* 1 msec */
149 mtspr( decar
, val
); /* Set auto-reload value */
150 mtspr( dec
, val
); /* Set inital val */
152 set_pit(gd
->bd
->bi_intfreq
/ 1000);
154 #endif /* CONFIG_4xx */
173 set_evpr(0x00000000);
175 #if defined(CONFIG_440)
176 #if !defined(CONFIG_440GX)
177 /* Install the UIC1 handlers */
178 irq_install_handler(VECNUM_UIC1NC
, uic1_interrupt
, 0);
179 irq_install_handler(VECNUM_UIC1C
, uic1_interrupt
, 0);
183 #if defined(CONFIG_440GX)
184 /* Take the GX out of compatibility mode
185 * Travis Sawyer, 9 Mar 2004
186 * NOTE: 440gx user manual inconsistency here
187 * Compatibility mode and Ethernet Clock select are not
188 * correct in the manual
194 /* Enable UIC interrupts via UIC Base Enable Register */
195 mtdcr(uicb0sr
, UICB0_ALL
);
196 mtdcr(uicb0er
, 0x54000000);
197 /* None are critical */
204 /****************************************************************************/
207 * Handle external interrupts
209 #if defined(CONFIG_440GX)
210 void external_interrupt(struct pt_regs
*regs
)
215 * Read masked interrupt status register to determine interrupt source
217 /* 440 GX uses base uic register */
218 uic_msr
= mfdcr(uicb0msr
);
220 if ( (UICB0_UIC0CI
& uic_msr
) || (UICB0_UIC0NCI
& uic_msr
) )
223 if ( (UICB0_UIC1CI
& uic_msr
) || (UICB0_UIC1NCI
& uic_msr
) )
226 if ( (UICB0_UIC2CI
& uic_msr
) || (UICB0_UIC2NCI
& uic_msr
) )
229 mtdcr(uicb0sr
, uic_msr
);
233 } /* external_interrupt CONFIG_440GX */
235 #elif defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
236 void external_interrupt(struct pt_regs
*regs
)
241 * Read masked interrupt status register to determine interrupt source
243 /* 440 SPe uses base uic register */
244 uic_msr
= mfdcr(uic0msr
);
246 if ( (UICB0_UIC1CI
& uic_msr
) || (UICB0_UIC1NCI
& uic_msr
) )
249 if ( (UICB0_UIC2CI
& uic_msr
) || (UICB0_UIC2NCI
& uic_msr
) )
252 if (uic_msr
& ~(UICB0_ALL
))
255 mtdcr(uic0sr
, uic_msr
);
259 } /* external_interrupt CONFIG_440EPX & CONFIG_440GRX */
261 #elif defined(CONFIG_440SPE)
262 void external_interrupt(struct pt_regs
*regs
)
267 * Read masked interrupt status register to determine interrupt source
269 /* 440 SPe uses base uic register */
270 uic_msr
= mfdcr(uic0msr
);
272 if ( (UICB0_UIC1CI
& uic_msr
) || (UICB0_UIC1NCI
& uic_msr
) )
275 if ( (UICB0_UIC2CI
& uic_msr
) || (UICB0_UIC2NCI
& uic_msr
) )
278 if ( (UICB0_UIC3CI
& uic_msr
) || (UICB0_UIC3NCI
& uic_msr
) )
281 if (uic_msr
& ~(UICB0_ALL
))
284 mtdcr(uic0sr
, uic_msr
);
287 } /* external_interrupt CONFIG_440SPE */
291 void external_interrupt(struct pt_regs
*regs
)
298 * Read masked interrupt status register to determine interrupt source
300 uic_msr
= mfdcr(uicmsr
);
304 while (msr_shift
!= 0) {
305 if (msr_shift
& 0x80000000) {
307 * Increment irq counter (for debug purpose only)
309 irq_vecs
[vec
].count
++;
311 if (irq_vecs
[vec
].handler
!= NULL
) {
313 (*irq_vecs
[vec
].handler
)(irq_vecs
[vec
].arg
);
315 mtdcr(uicer
, mfdcr(uicer
) & ~(0x80000000 >> vec
));
316 printf ("Masking bogus interrupt vector 0x%x\n", vec
);
320 * After servicing the interrupt, we have to remove the status indicator.
322 mtdcr(uicsr
, (0x80000000 >> vec
));
326 * Shift msr to next position and increment vector
334 #if defined(CONFIG_440GX) || defined(CONFIG_440SPE) || \
335 defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
336 /* Handler for UIC0 interrupt */
337 void uic0_interrupt( void * parms
)
344 * Read masked interrupt status register to determine interrupt source
346 uic_msr
= mfdcr(uicmsr
);
350 while (msr_shift
!= 0) {
351 if (msr_shift
& 0x80000000) {
353 * Increment irq counter (for debug purpose only)
355 irq_vecs
[vec
].count
++;
357 if (irq_vecs
[vec
].handler
!= NULL
) {
359 (*irq_vecs
[vec
].handler
)(irq_vecs
[vec
].arg
);
361 mtdcr(uicer
, mfdcr(uicer
) & ~(0x80000000 >> vec
));
362 printf ("Masking bogus interrupt vector (uic0) 0x%x\n", vec
);
366 * After servicing the interrupt, we have to remove the status indicator.
368 mtdcr(uicsr
, (0x80000000 >> vec
));
372 * Shift msr to next position and increment vector
379 #endif /* CONFIG_440GX */
381 #if defined(CONFIG_440)
382 /* Handler for UIC1 interrupt */
383 void uic1_interrupt( void * parms
)
390 * Read masked interrupt status register to determine interrupt source
392 uic1_msr
= mfdcr(uic1msr
);
393 msr_shift
= uic1_msr
;
396 while (msr_shift
!= 0) {
397 if (msr_shift
& 0x80000000) {
399 * Increment irq counter (for debug purpose only)
401 irq_vecs1
[vec
].count
++;
403 if (irq_vecs1
[vec
].handler
!= NULL
) {
405 (*irq_vecs1
[vec
].handler
)(irq_vecs1
[vec
].arg
);
407 mtdcr(uic1er
, mfdcr(uic1er
) & ~(0x80000000 >> vec
));
408 printf ("Masking bogus interrupt vector (uic1) 0x%x\n", vec
);
412 * After servicing the interrupt, we have to remove the status indicator.
414 mtdcr(uic1sr
, (0x80000000 >> vec
));
418 * Shift msr to next position and increment vector
424 #endif /* defined(CONFIG_440) */
426 #if defined(CONFIG_440GX) || defined(CONFIG_440SPE) || \
427 defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
428 /* Handler for UIC2 interrupt */
429 void uic2_interrupt( void * parms
)
436 * Read masked interrupt status register to determine interrupt source
438 uic2_msr
= mfdcr(uic2msr
);
439 msr_shift
= uic2_msr
;
442 while (msr_shift
!= 0) {
443 if (msr_shift
& 0x80000000) {
445 * Increment irq counter (for debug purpose only)
447 irq_vecs2
[vec
].count
++;
449 if (irq_vecs2
[vec
].handler
!= NULL
) {
451 (*irq_vecs2
[vec
].handler
)(irq_vecs2
[vec
].arg
);
453 mtdcr(uic2er
, mfdcr(uic2er
) & ~(0x80000000 >> vec
));
454 printf ("Masking bogus interrupt vector (uic2) 0x%x\n", vec
);
458 * After servicing the interrupt, we have to remove the status indicator.
460 mtdcr(uic2sr
, (0x80000000 >> vec
));
464 * Shift msr to next position and increment vector
470 #endif /* defined(CONFIG_440GX) */
472 #if defined(CONFIG_440SPE)
473 /* Handler for UIC3 interrupt */
474 void uic3_interrupt( void * parms
)
481 * Read masked interrupt status register to determine interrupt source
483 uic3_msr
= mfdcr(uic3msr
);
484 msr_shift
= uic3_msr
;
487 while (msr_shift
!= 0) {
488 if (msr_shift
& 0x80000000) {
490 * Increment irq counter (for debug purpose only)
492 irq_vecs3
[vec
].count
++;
494 if (irq_vecs3
[vec
].handler
!= NULL
) {
496 (*irq_vecs3
[vec
].handler
)(irq_vecs3
[vec
].arg
);
498 mtdcr(uic3er
, mfdcr(uic3er
) & ~(0x80000000 >> vec
));
499 printf ("Masking bogus interrupt vector (uic3) 0x%x\n", vec
);
503 * After servicing the interrupt, we have to remove the status indicator.
505 mtdcr(uic3sr
, (0x80000000 >> vec
));
509 * Shift msr to next position and increment vector
515 #endif /* defined(CONFIG_440SPE) */
517 /****************************************************************************/
520 * Install and free a interrupt handler.
523 void irq_install_handler (int vec
, interrupt_handler_t
* handler
, void *arg
)
525 struct irq_action
*irqa
= irq_vecs
;
528 #if defined(CONFIG_440)
529 #if defined(CONFIG_440GX) || defined(CONFIG_440SPE) || \
530 defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
531 if ((vec
> 31) && (vec
< 64)) {
534 } else if (vec
> 63) {
538 #else /* CONFIG_440GX */
543 #endif /* CONFIG_440GX */
544 #endif /* CONFIG_440 */
547 * print warning when replacing with a different irq vector
549 if ((irqa
[i
].handler
!= NULL
) && (irqa
[i
].handler
!= handler
)) {
550 printf ("Interrupt vector %d: handler 0x%x replacing 0x%x\n",
551 vec
, (uint
) handler
, (uint
) irqa
[i
].handler
);
553 irqa
[i
].handler
= handler
;
556 #if defined(CONFIG_440)
557 #if defined(CONFIG_440GX) || defined(CONFIG_440SPE) || \
558 defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
559 if ((vec
> 31) && (vec
< 64))
560 mtdcr (uic1er
, mfdcr (uic1er
) | (0x80000000 >> i
));
562 mtdcr (uic2er
, mfdcr (uic2er
) | (0x80000000 >> i
));
564 #endif /* CONFIG_440GX */
566 mtdcr (uic1er
, mfdcr (uic1er
) | (0x80000000 >> i
));
569 mtdcr (uicer
, mfdcr (uicer
) | (0x80000000 >> i
));
571 printf ("Install interrupt for vector %d ==> %p\n", vec
, handler
);
575 void irq_free_handler (int vec
)
577 struct irq_action
*irqa
= irq_vecs
;
580 #if defined(CONFIG_440)
581 #if defined(CONFIG_440GX) || defined(CONFIG_440SPE) || \
582 defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
583 if ((vec
> 31) && (vec
< 64)) {
586 } else if (vec
> 63) {
590 #endif /* CONFIG_440GX */
598 printf ("Free interrupt for vector %d ==> %p\n",
599 vec
, irq_vecs
[vec
].handler
);
602 #if defined(CONFIG_440)
603 #if defined(CONFIG_440GX) || defined(CONFIG_440SPE) || \
604 defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
605 if ((vec
> 31) && (vec
< 64))
606 mtdcr (uic1er
, mfdcr (uic1er
) & ~(0x80000000 >> i
));
608 mtdcr (uic2er
, mfdcr (uic2er
) & ~(0x80000000 >> i
));
610 #endif /* CONFIG_440GX */
612 mtdcr (uic1er
, mfdcr (uic1er
) & ~(0x80000000 >> i
));
615 mtdcr (uicer
, mfdcr (uicer
) & ~(0x80000000 >> i
));
617 irqa
[i
].handler
= NULL
;
621 /****************************************************************************/
623 void timer_interrupt_cpu (struct pt_regs
*regs
)
625 /* nothing to do here */
629 /****************************************************************************/
631 #if (CONFIG_COMMANDS & CFG_CMD_IRQ)
633 /*******************************************************************************
635 * irqinfo - print information about PCI devices
639 do_irqinfo(cmd_tbl_t
*cmdtp
, int flag
, int argc
, char *argv
[])
643 printf ("\nInterrupt-Information:\n");
644 #if defined(CONFIG_440)
645 printf ("\nUIC 0\n");
647 printf ("Nr Routine Arg Count\n");
649 for (vec
=0; vec
<32; vec
++) {
650 if (irq_vecs
[vec
].handler
!= NULL
) {
651 printf ("%02d %08lx %08lx %d\n",
653 (ulong
)irq_vecs
[vec
].handler
,
654 (ulong
)irq_vecs
[vec
].arg
,
655 irq_vecs
[vec
].count
);
659 #if defined(CONFIG_440)
660 printf ("\nUIC 1\n");
661 printf ("Nr Routine Arg Count\n");
663 for (vec
=0; vec
<32; vec
++) {
664 if (irq_vecs1
[vec
].handler
!= NULL
)
665 printf ("%02d %08lx %08lx %d\n",
666 vec
+31, (ulong
)irq_vecs1
[vec
].handler
,
667 (ulong
)irq_vecs1
[vec
].arg
, irq_vecs1
[vec
].count
);
672 #if defined(CONFIG_440GX) || defined(CONFIG_440SPE) || \
673 defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
674 printf ("\nUIC 2\n");
675 printf ("Nr Routine Arg Count\n");
677 for (vec
=0; vec
<32; vec
++) {
678 if (irq_vecs2
[vec
].handler
!= NULL
)
679 printf ("%02d %08lx %08lx %d\n",
680 vec
+63, (ulong
)irq_vecs2
[vec
].handler
,
681 (ulong
)irq_vecs2
[vec
].arg
, irq_vecs2
[vec
].count
);
686 #if defined(CONFIG_440SPE)
687 printf ("\nUIC 3\n");
688 printf ("Nr Routine Arg Count\n");
690 for (vec
=0; vec
<32; vec
++) {
691 if (irq_vecs3
[vec
].handler
!= NULL
)
692 printf ("%02d %08lx %08lx %d\n",
693 vec
+63, (ulong
)irq_vecs3
[vec
].handler
,
694 (ulong
)irq_vecs3
[vec
].arg
, irq_vecs3
[vec
].count
);
701 #endif /* CONFIG_COMMANDS & CFG_CMD_IRQ */