]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/powerpc/cpu/mpc5xx/interrupts.c
Merge branch 'master' of git://git.denx.de/u-boot-ppc4xx
[karo-tx-uboot.git] / arch / powerpc / 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 <command.h>
32 #include <mpc5xx.h>
33 #include <asm/processor.h>
34
35 #if defined(CONFIG_PATI)
36 /* PATI uses IRQs for PCI doorbell */
37 #undef NR_IRQS
38 #define NR_IRQS 16
39 #endif
40
41 struct interrupt_action {
42         interrupt_handler_t *handler;
43         void *arg;
44         int count;
45 };
46
47 static struct interrupt_action irq_vecs[NR_IRQS];
48
49 /*
50  * Initialise interrupts
51  */
52
53 int interrupt_init_cpu (ulong *decrementer_count)
54 {
55         volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
56         int vec;
57
58         /* Decrementer used here for status led */
59         *decrementer_count = get_tbclk () / CONFIG_SYS_HZ;
60
61         /* Disable all interrupts */
62         immr->im_siu_conf.sc_simask = 0;
63         for (vec=0; vec<NR_IRQS; vec++) {
64                 irq_vecs[vec].handler = NULL;
65                 irq_vecs[vec].arg = NULL;
66                 irq_vecs[vec].count = 0;
67         }
68
69         return (0);
70 }
71
72 /*
73  * Handle external interrupts
74  */
75 void external_interrupt (struct pt_regs *regs)
76 {
77         volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
78         int irq;
79         ulong simask, newmask;
80         ulong vec, v_bit;
81
82         /*
83          * read the SIVEC register and shift the bits down
84          * to get the irq number
85          */
86         vec = immr->im_siu_conf.sc_sivec;
87         irq = vec >> 26;
88         v_bit = 0x80000000UL >> irq;
89
90         /*
91          * Read Interrupt Mask Register and Mask Interrupts
92          */
93         simask = immr->im_siu_conf.sc_simask;
94         newmask = simask & (~(0xFFFF0000 >> irq));
95         immr->im_siu_conf.sc_simask = newmask;
96
97         if (!(irq & 0x1)) {             /* External Interrupt ?     */
98                 ulong siel;
99
100                 /*
101                  * Read Interrupt Edge/Level Register
102                  */
103                 siel = immr->im_siu_conf.sc_siel;
104
105                 if (siel & v_bit) {     /* edge triggered interrupt ?   */
106                         /*
107                          * Rewrite SIPEND Register to clear interrupt
108                          */
109                         immr->im_siu_conf.sc_sipend = v_bit;
110                 }
111         }
112
113         if (irq_vecs[irq].handler != NULL) {
114                 irq_vecs[irq].handler (irq_vecs[irq].arg);
115         } else {
116                 printf ("\nBogus External Interrupt IRQ %d Vector %ld\n",
117                                 irq, vec);
118                 /* turn off the bogus interrupt to avoid it from now */
119                 simask &= ~v_bit;
120         }
121         /*
122          * Re-Enable old Interrupt Mask
123          */
124         immr->im_siu_conf.sc_simask = simask;
125 }
126
127 /*
128  * Install and free an interrupt handler
129  */
130 void irq_install_handler (int vec, interrupt_handler_t * handler,
131                                                   void *arg)
132 {
133         volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
134         /* SIU interrupt */
135         if (irq_vecs[vec].handler != NULL) {
136                 printf ("SIU interrupt %d 0x%x\n",
137                         vec,
138                         (uint) handler);
139         }
140         irq_vecs[vec].handler = handler;
141         irq_vecs[vec].arg = arg;
142         immr->im_siu_conf.sc_simask |= 1 << (31 - vec);
143 #if 0
144         printf ("Install SIU interrupt for vector %d ==> %p\n",
145                 vec, handler);
146 #endif
147 }
148
149 void irq_free_handler (int vec)
150 {
151         volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
152         /* SIU interrupt */
153 #if 0
154         printf ("Free CPM interrupt for vector %d\n",
155                 vec);
156 #endif
157         immr->im_siu_conf.sc_simask &= ~(1 << (31 - vec));
158         irq_vecs[vec].handler = NULL;
159         irq_vecs[vec].arg = NULL;
160 }
161
162 /*
163  *  Timer interrupt - gets called when  bit 0 of DEC changes from
164  *  0. Decrementer is enabled with bit TBE in TBSCR.
165  */
166 void timer_interrupt_cpu (struct pt_regs *regs)
167 {
168         volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
169
170 #if 0
171         printf ("*** Timer Interrupt *** ");
172 #endif
173         /* Reset Timer Status Bit and Timers Interrupt Status */
174         immr->im_clkrstk.cark_plprcrk = KAPWR_KEY;
175         __asm__ ("nop");
176         immr->im_clkrst.car_plprcr |= PLPRCR_TEXPS | PLPRCR_TMIST;
177
178         return;
179 }
180
181 #if defined(CONFIG_CMD_IRQ)
182 /*******************************************************************************
183  *
184  * irqinfo - print information about IRQs
185  *
186  */
187 int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
188 {
189         int vec;
190
191         printf ("\nInterrupt-Information:\n");
192         printf ("Nr  Routine   Arg       Count\n");
193
194         for (vec=0; vec<NR_IRQS; vec++) {
195                 if (irq_vecs[vec].handler != NULL) {
196                         printf ("%02d  %08lx  %08lx  %d\n",
197                                 vec,
198                                 (ulong)irq_vecs[vec].handler,
199                                 (ulong)irq_vecs[vec].arg,
200                                 irq_vecs[vec].count);
201                 }
202         }
203         return 0;
204 }
205
206
207 #endif