ppc4xx: Consolidate PPC4xx UIC defines
[platform/kernel/u-boot.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
38 DECLARE_GLOBAL_DATA_PTR;
39
40 /*
41  * Define the number of UIC's
42  */
43 #if defined(CONFIG_440SPE) || \
44     defined(CONFIG_460EX) || defined(CONFIG_460GT)
45 #define UIC_MAX         4
46 #elif defined(CONFIG_440GX) || \
47     defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
48     defined(CONFIG_405EX)
49 #define UIC_MAX         3
50 #elif defined(CONFIG_440GP) || defined(CONFIG_440SP) || \
51     defined(CONFIG_440EP) || defined(CONFIG_440GR)
52 #define UIC_MAX         2
53 #else
54 #define UIC_MAX         1
55 #endif
56
57 /*
58  * CPM interrupt vector functions.
59  */
60 struct  irq_action {
61         interrupt_handler_t *handler;
62         void *arg;
63         int count;
64 };
65
66 static struct irq_action irq_vecs[UIC_MAX * 32];
67
68 u32 get_dcr(u16);
69 void set_dcr(u16, u32);
70
71 #if (UIC_MAX > 1) && !defined(CONFIG_440GX)
72 static void uic_cascade_interrupt(void *para);
73 #endif
74
75 #if defined(CONFIG_440)
76
77 /* SPRN changed in 440 */
78 static __inline__ void set_evpr(unsigned long val)
79 {
80         asm volatile("mtspr 0x03f,%0" : : "r" (val));
81 }
82
83 #else /* !defined(CONFIG_440) */
84
85 static __inline__ void set_pit(unsigned long val)
86 {
87         asm volatile("mtpit %0" : : "r" (val));
88 }
89
90
91 static __inline__ void set_tcr(unsigned long val)
92 {
93         asm volatile("mttcr %0" : : "r" (val));
94 }
95
96
97 static __inline__ void set_evpr(unsigned long val)
98 {
99         asm volatile("mtevpr %0" : : "r" (val));
100 }
101 #endif /* defined(CONFIG_440 */
102
103 int interrupt_init_cpu (unsigned *decrementer_count)
104 {
105         int vec;
106         unsigned long val;
107
108         /* decrementer is automatically reloaded */
109         *decrementer_count = 0;
110
111         /*
112          * Mark all irqs as free
113          */
114         for (vec = 0; vec < (UIC_MAX * 32); vec++) {
115                 irq_vecs[vec].handler = NULL;
116                 irq_vecs[vec].arg = NULL;
117                 irq_vecs[vec].count = 0;
118         }
119
120 #ifdef CONFIG_4xx
121         /*
122          * Init PIT
123          */
124 #if defined(CONFIG_440)
125         val = mfspr( tcr );
126         val &= (~0x04400000);           /* clear DIS & ARE */
127         mtspr( tcr, val );
128         mtspr( dec, 0 );                /* Prevent exception after TSR clear*/
129         mtspr( decar, 0 );              /* clear reload */
130         mtspr( tsr, 0x08000000 );       /* clear DEC status */
131         val = gd->bd->bi_intfreq/1000;  /* 1 msec */
132         mtspr( decar, val );            /* Set auto-reload value */
133         mtspr( dec, val );              /* Set inital val */
134 #else
135         set_pit(gd->bd->bi_intfreq / 1000);
136 #endif
137 #endif  /* CONFIG_4xx */
138
139 #ifdef CONFIG_ADCIOP
140         /*
141          * Init PIT
142          */
143         set_pit(66000);
144 #endif
145
146         /*
147          * Enable PIT
148          */
149         val = mfspr(tcr);
150         val |= 0x04400000;
151         mtspr(tcr, val);
152
153         /*
154          * Set EVPR to 0
155          */
156         set_evpr(0x00000000);
157
158 #if !defined(CONFIG_440GX)
159 #if (UIC_MAX > 1)
160         /* Install the UIC1 handlers */
161         irq_install_handler(VECNUM_UIC1NC, uic_cascade_interrupt, 0);
162         irq_install_handler(VECNUM_UIC1C, uic_cascade_interrupt, 0);
163 #endif
164 #if (UIC_MAX > 2)
165         irq_install_handler(VECNUM_UIC2NC, uic_cascade_interrupt, 0);
166         irq_install_handler(VECNUM_UIC2C, uic_cascade_interrupt, 0);
167 #endif
168 #if (UIC_MAX > 3)
169         irq_install_handler(VECNUM_UIC3NC, uic_cascade_interrupt, 0);
170         irq_install_handler(VECNUM_UIC3C, uic_cascade_interrupt, 0);
171 #endif
172 #else /* !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 /* !defined(CONFIG_440GX) */
189
190         return (0);
191 }
192
193 /* Handler for UIC interrupt */
194 static void uic_interrupt(u32 uic_base, int vec_base)
195 {
196         u32 uic_msr;
197         u32 msr_shift;
198         int vec;
199
200         /*
201          * Read masked interrupt status register to determine interrupt source
202          */
203         uic_msr = get_dcr(uic_base + UIC_MSR);
204         msr_shift = uic_msr;
205         vec = vec_base;
206
207         while (msr_shift != 0) {
208                 if (msr_shift & 0x80000000) {
209                         /*
210                          * Increment irq counter (for debug purpose only)
211                          */
212                         irq_vecs[vec].count++;
213
214                         if (irq_vecs[vec].handler != NULL) {
215                                 /* call isr */
216                                 (*irq_vecs[vec].handler)(irq_vecs[vec].arg);
217                         } else {
218                                 set_dcr(uic_base + UIC_ER,
219                                         get_dcr(uic_base + UIC_ER) &
220                                         ~(0x80000000 >> (vec & 0x1f)));
221                                 printf("Masking bogus interrupt vector %d"
222                                        " (UIC_BASE=0x%x)\n", vec, uic_base);
223                         }
224
225                         /*
226                          * After servicing the interrupt, we have to remove the
227                          * status indicator
228                          */
229                         set_dcr(uic_base + UIC_SR, (0x80000000 >> (vec & 0x1f)));
230                 }
231
232                 /*
233                  * Shift msr to next position and increment vector
234                  */
235                 msr_shift <<= 1;
236                 vec++;
237         }
238 }
239
240 #if (UIC_MAX > 1) && !defined(CONFIG_440GX)
241 static void uic_cascade_interrupt(void *para)
242 {
243         external_interrupt(para);
244 }
245 #endif
246
247 #if defined(CONFIG_440)
248 #if defined(CONFIG_440GX)
249 /* 440GX uses base uic register */
250 #define UIC_BMSR        uicb0msr
251 #define UIC_BSR         uicb0sr
252 #else
253 #define UIC_BMSR        uic0msr
254 #define UIC_BSR         uic0sr
255 #endif
256 #else /* CONFIG_440 */
257 #define UIC_BMSR        uicmsr
258 #define UIC_BSR         uicsr
259 #endif /* CONFIG_440 */
260
261 /*
262  * Handle external interrupts
263  */
264 void external_interrupt(struct pt_regs *regs)
265 {
266         u32 uic_msr;
267
268         /*
269          * Read masked interrupt status register to determine interrupt source
270          */
271         uic_msr = mfdcr(UIC_BMSR);
272
273 #if (UIC_MAX > 1)
274         if ((UICB0_UIC1CI & uic_msr) || (UICB0_UIC1NCI & uic_msr))
275                 uic_interrupt(UIC1_DCR_BASE, 32);
276 #endif
277
278 #if (UIC_MAX > 2)
279         if ((UICB0_UIC2CI & uic_msr) || (UICB0_UIC2NCI & uic_msr))
280                 uic_interrupt(UIC2_DCR_BASE, 64);
281 #endif
282
283 #if (UIC_MAX > 3)
284         if ((UICB0_UIC3CI & uic_msr) || (UICB0_UIC3NCI & uic_msr))
285                 uic_interrupt(UIC3_DCR_BASE, 96);
286 #endif
287
288 #if defined(CONFIG_440)
289 #if !defined(CONFIG_440GX)
290         if (uic_msr & ~(UICB0_ALL))
291                 uic_interrupt(UIC0_DCR_BASE, 0);
292 #else
293         if ((UICB0_UIC0CI & uic_msr) || (UICB0_UIC0NCI & uic_msr))
294                 uic_interrupt(UIC0_DCR_BASE, 0);
295 #endif
296 #else /* CONFIG_440 */
297         uic_interrupt(UIC0_DCR_BASE, 0);
298 #endif /* CONFIG_440 */
299
300         mtdcr(UIC_BSR, uic_msr);
301
302         return;
303 }
304
305 /*
306  * Install and free a interrupt handler.
307  */
308 void irq_install_handler(int vec, interrupt_handler_t * handler, void *arg)
309 {
310         int i;
311
312         /*
313          * Print warning when replacing with a different irq vector
314          */
315         if ((irq_vecs[vec].handler != NULL) && (irq_vecs[vec].handler != handler)) {
316                 printf("Interrupt vector %d: handler 0x%x replacing 0x%x\n",
317                        vec, (uint) handler, (uint) irq_vecs[vec].handler);
318         }
319         irq_vecs[vec].handler = handler;
320         irq_vecs[vec].arg = arg;
321
322         i = vec & 0x1f;
323         if ((vec >= 0) && (vec < 32))
324                 mtdcr(uicer, mfdcr(uicer) | (0x80000000 >> i));
325 #if (UIC_MAX > 1)
326         else if ((vec >= 32) && (vec < 64))
327                 mtdcr(uic1er, mfdcr(uic1er) | (0x80000000 >> i));
328 #endif
329 #if (UIC_MAX > 2)
330         else if ((vec >= 64) && (vec < 96))
331                 mtdcr(uic2er, mfdcr(uic2er) | (0x80000000 >> i));
332 #endif
333 #if (UIC_MAX > 3)
334         else if (vec >= 96)
335                 mtdcr(uic3er, mfdcr(uic3er) | (0x80000000 >> i));
336 #endif
337
338         debug("Install interrupt for vector %d ==> %p\n", vec, handler);
339 }
340
341 void irq_free_handler (int vec)
342 {
343         int i;
344
345         debug("Free interrupt for vector %d ==> %p\n",
346               vec, irq_vecs[vec].handler);
347
348         i = vec & 0x1f;
349         if ((vec >= 0) && (vec < 32))
350                 mtdcr(uicer, mfdcr(uicer) & ~(0x80000000 >> i));
351 #if (UIC_MAX > 1)
352         else if ((vec >= 32) && (vec < 64))
353                 mtdcr(uic1er, mfdcr(uic1er) & ~(0x80000000 >> i));
354 #endif
355 #if (UIC_MAX > 2)
356         else if ((vec >= 64) && (vec < 96))
357                 mtdcr(uic2er, mfdcr(uic2er) & ~(0x80000000 >> i));
358 #endif
359 #if (UIC_MAX > 3)
360         else if (vec >= 96)
361                 mtdcr(uic3er, mfdcr(uic3er) & ~(0x80000000 >> i));
362 #endif
363
364         irq_vecs[vec].handler = NULL;
365         irq_vecs[vec].arg = NULL;
366 }
367
368 void timer_interrupt_cpu (struct pt_regs *regs)
369 {
370         /* nothing to do here */
371         return;
372 }
373
374 #if defined(CONFIG_CMD_IRQ)
375 int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
376 {
377         int vec;
378
379         printf ("Interrupt-Information:\n");
380         printf ("Nr  Routine   Arg       Count\n");
381
382         for (vec = 0; vec < (UIC_MAX * 32); vec++) {
383                 if (irq_vecs[vec].handler != NULL) {
384                         printf ("%02d  %08lx  %08lx  %d\n",
385                                 vec,
386                                 (ulong)irq_vecs[vec].handler,
387                                 (ulong)irq_vecs[vec].arg,
388                                 irq_vecs[vec].count);
389                 }
390         }
391
392         return 0;
393 }
394 #endif