]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - cpu/ppc4xx/interrupts.c
GCC-4.x fixes: clean up global data pointer initialization for all boards.
[karo-tx-uboot.git] / cpu / ppc4xx / interrupts.c
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  * (C) Copyright 2003 (440GX port)
9  * Travis B. Sawyer, Sandburst Corporation, tsawyer@sandburst.com
10  *
11  * See file CREDITS for list of people who contributed to this
12  * project.
13  *
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.
18  *
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.
23  *
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,
27  * MA 02111-1307 USA
28  */
29
30 #include <common.h>
31 #include <watchdog.h>
32 #include <command.h>
33 #include <asm/processor.h>
34 #include <ppc4xx.h>
35 #include <ppc_asm.tmpl>
36 #include <commproc.h>
37 #include "vecnum.h"
38
39 DECLARE_GLOBAL_DATA_PTR;
40
41 /****************************************************************************/
42
43 /*
44  * CPM interrupt vector functions.
45  */
46 struct  irq_action {
47         interrupt_handler_t *handler;
48         void *arg;
49         int count;
50 };
51
52 static struct irq_action irq_vecs[32];
53
54 #if defined(CONFIG_440)
55 static struct irq_action irq_vecs1[32]; /* For UIC1 */
56
57 void uic1_interrupt( void * parms); /* UIC1 handler */
58
59 #if defined(CONFIG_440GX)
60 static struct irq_action irq_vecs2[32]; /* For UIC2 */
61
62 void uic0_interrupt( void * parms); /* UIC0 handler */
63 void uic2_interrupt( void * parms); /* UIC2 handler */
64 #endif /* CONFIG_440GX */
65
66 #endif /* CONFIG_440 */
67
68 /****************************************************************************/
69 #if defined(CONFIG_440)
70
71 /* SPRN changed in 440 */
72 static __inline__ void set_evpr(unsigned long val)
73 {
74         asm volatile("mtspr 0x03f,%0" : : "r" (val));
75 }
76
77 #else /* !defined(CONFIG_440) */
78
79 static __inline__ void set_pit(unsigned long val)
80 {
81         asm volatile("mtpit %0" : : "r" (val));
82 }
83
84
85 static __inline__ void set_tcr(unsigned long val)
86 {
87         asm volatile("mttcr %0" : : "r" (val));
88 }
89
90
91 static __inline__ void set_evpr(unsigned long val)
92 {
93         asm volatile("mtevpr %0" : : "r" (val));
94 }
95 #endif /* defined(CONFIG_440 */
96
97 /****************************************************************************/
98
99 int interrupt_init_cpu (unsigned *decrementer_count)
100 {
101         int vec;
102         unsigned long val;
103
104         /* decrementer is automatically reloaded */
105         *decrementer_count = 0;
106
107         /*
108          * Mark all irqs as free
109          */
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 */
123 #endif
124         }
125
126 #ifdef CONFIG_4xx
127         /*
128          * Init PIT
129          */
130 #if defined(CONFIG_440)
131         val = mfspr( tcr );
132         val &= (~0x04400000);           /* clear DIS & ARE */
133         mtspr( tcr, val );
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 */
140 #else
141         set_pit(gd->bd->bi_intfreq / 1000);
142 #endif
143 #endif  /* CONFIG_4xx */
144
145 #ifdef CONFIG_ADCIOP
146         /*
147          * Init PIT
148          */
149         set_pit(66000);
150 #endif
151
152         /*
153          * Enable PIT
154          */
155         val = mfspr(tcr);
156         val |= 0x04400000;
157         mtspr(tcr, val);
158
159         /*
160          * Set EVPR to 0
161          */
162         set_evpr(0x00000000);
163
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);
169 #endif
170 #endif
171
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
178          */
179         mfsdr(sdr_mfr, val);
180         val &= ~0x10000000;
181         mtsdr(sdr_mfr,val);
182
183         /* Enable UIC interrupts via UIC Base Enable Register */
184         mtdcr(uicb0sr, UICB0_ALL);
185         mtdcr(uicb0er, 0x54000000);
186         /* None are critical */
187         mtdcr(uicb0cr, 0);
188 #endif
189
190         return (0);
191 }
192
193 /****************************************************************************/
194
195 /*
196  * Handle external interrupts
197  */
198 #if defined(CONFIG_440GX)
199 void external_interrupt(struct pt_regs *regs)
200 {
201         ulong uic_msr;
202
203         /*
204          * Read masked interrupt status register to determine interrupt source
205          */
206         /* 440 GX uses base uic register */
207         uic_msr = mfdcr(uicb0msr);
208
209         if ( (UICB0_UIC0CI & uic_msr) || (UICB0_UIC0NCI & uic_msr) )
210                 uic0_interrupt(0);
211
212         if ( (UICB0_UIC1CI & uic_msr) || (UICB0_UIC1NCI & uic_msr) )
213                 uic1_interrupt(0);
214
215         if ( (UICB0_UIC2CI & uic_msr) || (UICB0_UIC2NCI & uic_msr) )
216                 uic2_interrupt(0);
217
218         mtdcr(uicb0sr, uic_msr);
219
220         return;
221
222 } /* external_interrupt CONFIG_440GX */
223
224 #else
225
226 void external_interrupt(struct pt_regs *regs)
227 {
228         ulong uic_msr;
229         ulong msr_shift;
230         int vec;
231
232         /*
233          * Read masked interrupt status register to determine interrupt source
234          */
235         uic_msr = mfdcr(uicmsr);
236         msr_shift = uic_msr;
237         vec = 0;
238
239         while (msr_shift != 0) {
240                 if (msr_shift & 0x80000000) {
241                         /*
242                          * Increment irq counter (for debug purpose only)
243                          */
244                         irq_vecs[vec].count++;
245
246                         if (irq_vecs[vec].handler != NULL) {
247                                 /* call isr */
248                                 (*irq_vecs[vec].handler)(irq_vecs[vec].arg);
249                         } else {
250                                 mtdcr(uicer, mfdcr(uicer) & ~(0x80000000 >> vec));
251                                 printf ("Masking bogus interrupt vector 0x%x\n", vec);
252                         }
253
254                         /*
255                          * After servicing the interrupt, we have to remove the status indicator.
256                          */
257                         mtdcr(uicsr, (0x80000000 >> vec));
258                 }
259
260                 /*
261                  * Shift msr to next position and increment vector
262                  */
263                 msr_shift <<= 1;
264                 vec++;
265         }
266 }
267 #endif
268
269 #if defined(CONFIG_440GX)
270 /* Handler for UIC0 interrupt */
271 void uic0_interrupt( void * parms)
272 {
273         ulong uic_msr;
274         ulong msr_shift;
275         int vec;
276
277         /*
278          * Read masked interrupt status register to determine interrupt source
279          */
280         uic_msr = mfdcr(uicmsr);
281         msr_shift = uic_msr;
282         vec = 0;
283
284         while (msr_shift != 0) {
285                 if (msr_shift & 0x80000000) {
286                         /*
287                          * Increment irq counter (for debug purpose only)
288                          */
289                         irq_vecs[vec].count++;
290
291                         if (irq_vecs[vec].handler != NULL) {
292                                 /* call isr */
293                                 (*irq_vecs[vec].handler)(irq_vecs[vec].arg);
294                         } else {
295                                 mtdcr(uicer, mfdcr(uicer) & ~(0x80000000 >> vec));
296                                 printf ("Masking bogus interrupt vector (uic0) 0x%x\n", vec);
297                         }
298
299                         /*
300                          * After servicing the interrupt, we have to remove the status indicator.
301                          */
302                         mtdcr(uicsr, (0x80000000 >> vec));
303                 }
304
305                 /*
306                  * Shift msr to next position and increment vector
307                  */
308                 msr_shift <<= 1;
309                 vec++;
310         }
311 }
312
313 #endif /* CONFIG_440GX */
314
315 #if defined(CONFIG_440)
316 /* Handler for UIC1 interrupt */
317 void uic1_interrupt( void * parms)
318 {
319         ulong uic1_msr;
320         ulong msr_shift;
321         int vec;
322
323         /*
324          * Read masked interrupt status register to determine interrupt source
325          */
326         uic1_msr = mfdcr(uic1msr);
327         msr_shift = uic1_msr;
328         vec = 0;
329
330         while (msr_shift != 0) {
331                 if (msr_shift & 0x80000000) {
332                         /*
333                          * Increment irq counter (for debug purpose only)
334                          */
335                         irq_vecs1[vec].count++;
336
337                         if (irq_vecs1[vec].handler != NULL) {
338                                 /* call isr */
339                                 (*irq_vecs1[vec].handler)(irq_vecs1[vec].arg);
340                         } else {
341                                 mtdcr(uic1er, mfdcr(uic1er) & ~(0x80000000 >> vec));
342                                 printf ("Masking bogus interrupt vector (uic1) 0x%x\n", vec);
343                         }
344
345                         /*
346                          * After servicing the interrupt, we have to remove the status indicator.
347                          */
348                         mtdcr(uic1sr, (0x80000000 >> vec));
349                 }
350
351                 /*
352                  * Shift msr to next position and increment vector
353                  */
354                 msr_shift <<= 1;
355                 vec++;
356         }
357 }
358 #endif /* defined(CONFIG_440) */
359
360 #if defined(CONFIG_440GX)
361 /* Handler for UIC1 interrupt */
362 void uic2_interrupt( void * parms)
363 {
364         ulong uic2_msr;
365         ulong msr_shift;
366         int vec;
367
368         /*
369          * Read masked interrupt status register to determine interrupt source
370          */
371         uic2_msr = mfdcr(uic2msr);
372         msr_shift = uic2_msr;
373         vec = 0;
374
375         while (msr_shift != 0) {
376                 if (msr_shift & 0x80000000) {
377                         /*
378                          * Increment irq counter (for debug purpose only)
379                          */
380                         irq_vecs2[vec].count++;
381
382                         if (irq_vecs2[vec].handler != NULL) {
383                                 /* call isr */
384                                 (*irq_vecs2[vec].handler)(irq_vecs2[vec].arg);
385                         } else {
386                                 mtdcr(uic2er, mfdcr(uic2er) & ~(0x80000000 >> vec));
387                                 printf ("Masking bogus interrupt vector (uic1) 0x%x\n", vec);
388                         }
389
390                         /*
391                          * After servicing the interrupt, we have to remove the status indicator.
392                          */
393                         mtdcr(uic2sr, (0x80000000 >> vec));
394                 }
395
396                 /*
397                  * Shift msr to next position and increment vector
398                  */
399                 msr_shift <<= 1;
400                 vec++;
401         }
402 }
403 #endif /* defined(CONFIG_440GX) */
404
405 /****************************************************************************/
406
407 /*
408  * Install and free a interrupt handler.
409  */
410
411 void irq_install_handler (int vec, interrupt_handler_t * handler, void *arg)
412 {
413         struct irq_action *irqa = irq_vecs;
414         int i = vec;
415
416 #if defined(CONFIG_440)
417 #if defined(CONFIG_440GX)
418         if ((vec > 31) && (vec < 64)) {
419                 i = vec - 32;
420                 irqa = irq_vecs1;
421         } else if (vec > 63) {
422                 i = vec - 64;
423                 irqa = irq_vecs2;
424         }
425 #else  /* CONFIG_440GX */
426         if (vec > 31) {
427                 i = vec - 32;
428                 irqa = irq_vecs1;
429         }
430 #endif /* CONFIG_440GX */
431 #endif /* CONFIG_440 */
432
433         /*
434          * print warning when replacing with a different irq vector
435          */
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);
439         }
440         irqa[i].handler = handler;
441         irqa[i].arg = arg;
442
443 #if defined(CONFIG_440)
444 #if defined(CONFIG_440GX)
445         if ((vec > 31) && (vec < 64))
446                 mtdcr (uic1er, mfdcr (uic1er) | (0x80000000 >> i));
447         else if (vec > 63)
448                 mtdcr (uic2er, mfdcr (uic2er) | (0x80000000 >> i));
449         else
450 #endif /* CONFIG_440GX */
451         if (vec > 31)
452                 mtdcr (uic1er, mfdcr (uic1er) | (0x80000000 >> i));
453         else
454 #endif
455                 mtdcr (uicer, mfdcr (uicer) | (0x80000000 >> i));
456 #if 0
457         printf ("Install interrupt for vector %d ==> %p\n", vec, handler);
458 #endif
459 }
460
461 void irq_free_handler (int vec)
462 {
463         struct irq_action *irqa = irq_vecs;
464         int i = vec;
465
466 #if defined(CONFIG_440)
467 #if defined(CONFIG_440GX)
468         if ((vec > 31) && (vec < 64)) {
469                 irqa = irq_vecs1;
470                 i = vec - 32;
471         } else if (vec > 63) {
472                 irqa = irq_vecs2;
473                 i = vec - 64;
474         }
475 #endif /* CONFIG_440GX */
476         if (vec > 31) {
477                 irqa = irq_vecs1;
478                 i = vec - 32;
479         }
480 #endif
481
482 #if 0
483         printf ("Free interrupt for vector %d ==> %p\n",
484                 vec, irq_vecs[vec].handler);
485 #endif
486
487 #if defined(CONFIG_440)
488 #if defined(CONFIG_440GX)
489         if ((vec > 31) && (vec < 64))
490                 mtdcr (uic1er, mfdcr (uic1er) & ~(0x80000000 >> i));
491         else if (vec > 63)
492                 mtdcr (uic2er, mfdcr (uic2er) & ~(0x80000000 >> i));
493         else
494 #endif /* CONFIG_440GX */
495         if (vec > 31)
496                 mtdcr (uic1er, mfdcr (uic1er) & ~(0x80000000 >> i));
497         else
498 #endif
499                 mtdcr (uicer, mfdcr (uicer) & ~(0x80000000 >> i));
500
501         irqa[i].handler = NULL;
502         irqa[i].arg = NULL;
503 }
504
505 /****************************************************************************/
506
507 void timer_interrupt_cpu (struct pt_regs *regs)
508 {
509         /* nothing to do here */
510         return;
511 }
512
513 /****************************************************************************/
514
515 #if (CONFIG_COMMANDS & CFG_CMD_IRQ)
516
517 /*******************************************************************************
518  *
519  * irqinfo - print information about PCI devices
520  *
521  */
522 int
523 do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
524 {
525         int vec;
526
527         printf ("\nInterrupt-Information:\n");
528 #if defined(CONFIG_440)
529         printf ("\nUIC 0\n");
530 #endif
531         printf ("Nr  Routine   Arg       Count\n");
532
533         for (vec=0; vec<32; vec++) {
534                 if (irq_vecs[vec].handler != NULL) {
535                         printf ("%02d  %08lx  %08lx  %d\n",
536                                 vec,
537                                 (ulong)irq_vecs[vec].handler,
538                                 (ulong)irq_vecs[vec].arg,
539                                 irq_vecs[vec].count);
540                 }
541         }
542
543 #if defined(CONFIG_440)
544         printf ("\nUIC 1\n");
545         printf ("Nr  Routine   Arg       Count\n");
546
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);
552         }
553         printf("\n");
554 #endif
555
556 #if defined(CONFIG_440GX)
557         printf ("\nUIC 2\n");
558         printf ("Nr  Routine   Arg       Count\n");
559
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);
565         }
566         printf("\n");
567 #endif
568
569         return 0;
570 }
571 #endif  /* CONFIG_COMMANDS & CFG_CMD_IRQ */