]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - cpu/mpc5xx/interrupts.c
* Patch by Gleb Natapov, 19 Sep 2003:
[karo-tx-uboot.git] / cpu / mpc5xx / interrupts.c
1 /*
2  * (C) Copyright 2000-2002      Wolfgang Denk, DENX Software Engineering, wd@denx.de.
3  * (C) Copyright 2003           Martin Winistoerfer, martinwinistoerfer@gmx.ch.
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation,
21  */
22
23 /*
24  * File:                interrupt.c
25  *
26  * Discription:         Contains interrupt routines needed by U-Boot
27  *
28  */
29
30 #include <common.h>
31 #include <mpc5xx.h>
32 #include <asm/processor.h>
33
34 struct interrupt_action {
35         interrupt_handler_t *handler;
36         void *arg;
37 };
38
39 static struct interrupt_action irq_vecs[NR_IRQS];
40
41 /*
42  * Initialise interrupts
43  */
44
45 int interrupt_init_cpu (ulong *decrementer_count)
46 {
47         volatile immap_t *immr = (immap_t *) CFG_IMMR;
48
49         /* Decrementer used here for status led */
50         *decrementer_count = get_tbclk () / CFG_HZ;
51
52         /* Disable all interrupts */
53         immr->im_siu_conf.sc_simask = 0;
54
55         return (0);
56 }
57
58 /*
59  * Handle external interrupts
60  */
61 void external_interrupt (struct pt_regs *regs)
62 {
63         volatile immap_t *immr = (immap_t *) CFG_IMMR;
64         int irq;
65         ulong simask, newmask;
66         ulong vec, v_bit;
67
68         /*
69          * read the SIVEC register and shift the bits down
70          * to get the irq number
71          */
72         vec = immr->im_siu_conf.sc_sivec;
73         irq = vec >> 26;
74         v_bit = 0x80000000UL >> irq;
75
76         /*
77          * Read Interrupt Mask Register and Mask Interrupts
78          */
79         simask = immr->im_siu_conf.sc_simask;
80         newmask = simask & (~(0xFFFF0000 >> irq));
81         immr->im_siu_conf.sc_simask = newmask;
82
83         if (!(irq & 0x1)) {             /* External Interrupt ?     */
84                 ulong siel;
85
86                 /*
87                  * Read Interrupt Edge/Level Register
88                  */
89                 siel = immr->im_siu_conf.sc_siel;
90
91                 if (siel & v_bit) {     /* edge triggered interrupt ?   */
92                         /*
93                          * Rewrite SIPEND Register to clear interrupt
94                          */
95                         immr->im_siu_conf.sc_sipend = v_bit;
96                 }
97         }
98
99         if (irq_vecs[irq].handler != NULL) {
100                 irq_vecs[irq].handler (irq_vecs[irq].arg);
101         } else {
102                 printf ("\nBogus External Interrupt IRQ %d Vector %ld\n",
103                                 irq, vec);
104                 /* turn off the bogus interrupt to avoid it from now */
105                 simask &= ~v_bit;
106         }
107         /*
108          * Re-Enable old Interrupt Mask
109          */
110         immr->im_siu_conf.sc_simask = simask;
111 }
112
113 /*
114  * Install and free an interrupt handler
115  */
116 void irq_install_handler (int vec, interrupt_handler_t * handler,
117                                                   void *arg)
118 {
119         volatile immap_t *immr = (immap_t *) CFG_IMMR;
120         /* SIU interrupt */
121         if (irq_vecs[vec].handler != NULL) {
122                 printf ("SIU interrupt %d 0x%x\n",
123                         vec,
124                         (uint) handler);
125         }
126         irq_vecs[vec].handler = handler;
127         irq_vecs[vec].arg = arg;
128         immr->im_siu_conf.sc_simask |= 1 << (31 - vec);
129 #if 0
130         printf ("Install SIU interrupt for vector %d ==> %p\n",
131                 vec, handler);
132 #endif
133 }
134
135 void irq_free_handler (int vec)
136 {
137         volatile immap_t *immr = (immap_t *) CFG_IMMR;
138         /* SIU interrupt */
139 #if 0
140         printf ("Free CPM interrupt for vector %d\n",
141                 vec);
142 #endif
143         immr->im_siu_conf.sc_simask &= ~(1 << (31 - vec));
144         irq_vecs[vec].handler = NULL;
145         irq_vecs[vec].arg = NULL;
146 }
147
148 /*
149  *  Timer interrupt - gets called when  bit 0 of DEC changes from
150  *  0. Decrementer is enabled with bit TBE in TBSCR.
151  */
152 void timer_interrupt_cpu (struct pt_regs *regs)
153 {
154         volatile immap_t *immr = (immap_t *) CFG_IMMR;
155
156 #if 0
157         printf ("*** Timer Interrupt *** ");
158 #endif
159         /* Reset Timer Status Bit and Timers Interrupt Status */
160         immr->im_clkrstk.cark_plprcrk = KAPWR_KEY;
161         __asm__ ("nop");
162         immr->im_clkrst.car_plprcr |= PLPRCR_TEXPS | PLPRCR_TMIST;
163
164         return;
165 }