]>
git.ipfire.org Git - people/ms/u-boot.git/blob - cpu/ppc4xx/interrupts.c
1d8dc7c221deb4be50465424e94f46cc29a00875
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 /****************************************************************************/
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_440GX)
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_440GX */
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_440GX)
119 irq_vecs2
[vec
].handler
= NULL
;
120 irq_vecs2
[vec
].arg
= NULL
;
121 irq_vecs2
[vec
].count
= 0;
122 #endif /* CONFIG_440GX */
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
/1000; /* 1 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_440GX)
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_440GX)
173 /* Take the GX out of compatibility mode
174 * Travis Sawyer, 9 Mar 2004
175 * NOTE: 440gx user manual inconsistency here
176 * Compatibility mode and Ethernet Clock select are not
177 * correct in the manual
183 /* Enable UIC interrupts via UIC Base Enable Register */
184 mtdcr(uicb0sr
, UICB0_ALL
);
185 mtdcr(uicb0er
, 0x54000000);
186 /* None are critical */
193 /****************************************************************************/
196 * Handle external interrupts
198 #if defined(CONFIG_440GX)
199 void external_interrupt(struct pt_regs
*regs
)
204 * Read masked interrupt status register to determine interrupt source
206 /* 440 GX uses base uic register */
207 uic_msr
= mfdcr(uicb0msr
);
209 if ( (UICB0_UIC0CI
& uic_msr
) || (UICB0_UIC0NCI
& uic_msr
) )
212 if ( (UICB0_UIC1CI
& uic_msr
) || (UICB0_UIC1NCI
& uic_msr
) )
215 if ( (UICB0_UIC2CI
& uic_msr
) || (UICB0_UIC2NCI
& uic_msr
) )
218 mtdcr(uicb0sr
, uic_msr
);
222 } /* external_interrupt CONFIG_440GX */
226 void external_interrupt(struct pt_regs
*regs
)
233 * Read masked interrupt status register to determine interrupt source
235 uic_msr
= mfdcr(uicmsr
);
239 while (msr_shift
!= 0) {
240 if (msr_shift
& 0x80000000) {
242 * Increment irq counter (for debug purpose only)
244 irq_vecs
[vec
].count
++;
246 if (irq_vecs
[vec
].handler
!= NULL
) {
248 (*irq_vecs
[vec
].handler
)(irq_vecs
[vec
].arg
);
250 mtdcr(uicer
, mfdcr(uicer
) & ~(0x80000000 >> vec
));
251 printf ("Masking bogus interrupt vector 0x%x\n", vec
);
255 * After servicing the interrupt, we have to remove the status indicator.
257 mtdcr(uicsr
, (0x80000000 >> vec
));
261 * Shift msr to next position and increment vector
269 #if defined(CONFIG_440GX)
270 /* Handler for UIC0 interrupt */
271 void uic0_interrupt( void * parms
)
278 * Read masked interrupt status register to determine interrupt source
280 uic_msr
= mfdcr(uicmsr
);
284 while (msr_shift
!= 0) {
285 if (msr_shift
& 0x80000000) {
287 * Increment irq counter (for debug purpose only)
289 irq_vecs
[vec
].count
++;
291 if (irq_vecs
[vec
].handler
!= NULL
) {
293 (*irq_vecs
[vec
].handler
)(irq_vecs
[vec
].arg
);
295 mtdcr(uicer
, mfdcr(uicer
) & ~(0x80000000 >> vec
));
296 printf ("Masking bogus interrupt vector (uic0) 0x%x\n", vec
);
300 * After servicing the interrupt, we have to remove the status indicator.
302 mtdcr(uicsr
, (0x80000000 >> vec
));
306 * Shift msr to next position and increment vector
313 #endif /* CONFIG_440GX */
315 #if defined(CONFIG_440)
316 /* Handler for UIC1 interrupt */
317 void uic1_interrupt( void * parms
)
324 * Read masked interrupt status register to determine interrupt source
326 uic1_msr
= mfdcr(uic1msr
);
327 msr_shift
= uic1_msr
;
330 while (msr_shift
!= 0) {
331 if (msr_shift
& 0x80000000) {
333 * Increment irq counter (for debug purpose only)
335 irq_vecs1
[vec
].count
++;
337 if (irq_vecs1
[vec
].handler
!= NULL
) {
339 (*irq_vecs1
[vec
].handler
)(irq_vecs1
[vec
].arg
);
341 mtdcr(uic1er
, mfdcr(uic1er
) & ~(0x80000000 >> vec
));
342 printf ("Masking bogus interrupt vector (uic1) 0x%x\n", vec
);
346 * After servicing the interrupt, we have to remove the status indicator.
348 mtdcr(uic1sr
, (0x80000000 >> vec
));
352 * Shift msr to next position and increment vector
358 #endif /* defined(CONFIG_440) */
360 #if defined(CONFIG_440GX)
361 /* Handler for UIC1 interrupt */
362 void uic2_interrupt( void * parms
)
369 * Read masked interrupt status register to determine interrupt source
371 uic2_msr
= mfdcr(uic2msr
);
372 msr_shift
= uic2_msr
;
375 while (msr_shift
!= 0) {
376 if (msr_shift
& 0x80000000) {
378 * Increment irq counter (for debug purpose only)
380 irq_vecs2
[vec
].count
++;
382 if (irq_vecs2
[vec
].handler
!= NULL
) {
384 (*irq_vecs2
[vec
].handler
)(irq_vecs2
[vec
].arg
);
386 mtdcr(uic2er
, mfdcr(uic2er
) & ~(0x80000000 >> vec
));
387 printf ("Masking bogus interrupt vector (uic1) 0x%x\n", vec
);
391 * After servicing the interrupt, we have to remove the status indicator.
393 mtdcr(uic2sr
, (0x80000000 >> vec
));
397 * Shift msr to next position and increment vector
403 #endif /* defined(CONFIG_440GX) */
405 /****************************************************************************/
408 * Install and free a interrupt handler.
411 void irq_install_handler (int vec
, interrupt_handler_t
* handler
, void *arg
)
413 struct irq_action
*irqa
= irq_vecs
;
416 #if defined(CONFIG_440)
417 #if defined(CONFIG_440GX)
418 if ((vec
> 31) && (vec
< 64)) {
421 } else if (vec
> 63) {
425 #else /* CONFIG_440GX */
430 #endif /* CONFIG_440GX */
431 #endif /* CONFIG_440 */
434 * print warning when replacing with a different irq vector
436 if ((irqa
[i
].handler
!= NULL
) && (irqa
[i
].handler
!= handler
)) {
437 printf ("Interrupt vector %d: handler 0x%x replacing 0x%x\n",
438 vec
, (uint
) handler
, (uint
) irqa
[i
].handler
);
440 irqa
[i
].handler
= handler
;
443 #if defined(CONFIG_440)
444 #if defined(CONFIG_440GX)
445 if ((vec
> 31) && (vec
< 64))
446 mtdcr (uic1er
, mfdcr (uic1er
) | (0x80000000 >> i
));
448 mtdcr (uic2er
, mfdcr (uic2er
) | (0x80000000 >> i
));
450 #endif /* CONFIG_440GX */
452 mtdcr (uic1er
, mfdcr (uic1er
) | (0x80000000 >> i
));
455 mtdcr (uicer
, mfdcr (uicer
) | (0x80000000 >> i
));
457 printf ("Install interrupt for vector %d ==> %p\n", vec
, handler
);
461 void irq_free_handler (int vec
)
463 struct irq_action
*irqa
= irq_vecs
;
466 #if defined(CONFIG_440)
467 #if defined(CONFIG_440GX)
468 if ((vec
> 31) && (vec
< 64)) {
471 } else if (vec
> 63) {
475 #endif /* CONFIG_440GX */
483 printf ("Free interrupt for vector %d ==> %p\n",
484 vec
, irq_vecs
[vec
].handler
);
487 #if defined(CONFIG_440)
488 #if defined(CONFIG_440GX)
489 if ((vec
> 31) && (vec
< 64))
490 mtdcr (uic1er
, mfdcr (uic1er
) & ~(0x80000000 >> i
));
492 mtdcr (uic2er
, mfdcr (uic2er
) & ~(0x80000000 >> i
));
494 #endif /* CONFIG_440GX */
496 mtdcr (uic1er
, mfdcr (uic1er
) & ~(0x80000000 >> i
));
499 mtdcr (uicer
, mfdcr (uicer
) & ~(0x80000000 >> i
));
501 irqa
[i
].handler
= NULL
;
505 /****************************************************************************/
507 void timer_interrupt_cpu (struct pt_regs
*regs
)
509 /* nothing to do here */
513 /****************************************************************************/
515 #if (CONFIG_COMMANDS & CFG_CMD_IRQ)
517 /*******************************************************************************
519 * irqinfo - print information about PCI devices
523 do_irqinfo(cmd_tbl_t
*cmdtp
, int flag
, int argc
, char *argv
[])
527 printf ("\nInterrupt-Information:\n");
528 #if defined(CONFIG_440)
529 printf ("\nUIC 0\n");
531 printf ("Nr Routine Arg Count\n");
533 for (vec
=0; vec
<32; vec
++) {
534 if (irq_vecs
[vec
].handler
!= NULL
) {
535 printf ("%02d %08lx %08lx %d\n",
537 (ulong
)irq_vecs
[vec
].handler
,
538 (ulong
)irq_vecs
[vec
].arg
,
539 irq_vecs
[vec
].count
);
543 #if defined(CONFIG_440)
544 printf ("\nUIC 1\n");
545 printf ("Nr Routine Arg Count\n");
547 for (vec
=0; vec
<32; vec
++) {
548 if (irq_vecs1
[vec
].handler
!= NULL
)
549 printf ("%02d %08lx %08lx %d\n",
550 vec
+31, (ulong
)irq_vecs1
[vec
].handler
,
551 (ulong
)irq_vecs1
[vec
].arg
, irq_vecs1
[vec
].count
);
556 #if defined(CONFIG_440GX)
557 printf ("\nUIC 2\n");
558 printf ("Nr Routine Arg Count\n");
560 for (vec
=0; vec
<32; vec
++) {
561 if (irq_vecs2
[vec
].handler
!= NULL
)
562 printf ("%02d %08lx %08lx %d\n",
563 vec
+63, (ulong
)irq_vecs2
[vec
].handler
,
564 (ulong
)irq_vecs2
[vec
].arg
, irq_vecs2
[vec
].count
);
571 #endif /* CONFIG_COMMANDS & CFG_CMD_IRQ */