]> git.ipfire.org Git - people/ms/u-boot.git/blame - cpu/ppc4xx/interrupts.c
Patch by Reinhard Meyer, 28 Dec 2003:
[people/ms/u-boot.git] / cpu / ppc4xx / interrupts.c
CommitLineData
f780aa2a
WD
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 * See file CREDITS for list of people who contributed to this
9 * project.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License as
13 * published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
24 * MA 02111-1307 USA
25 */
26
27#include <common.h>
28#include <watchdog.h>
29#include <command.h>
f780aa2a
WD
30#include <asm/processor.h>
31#include <ppc4xx.h>
32#include <ppc_asm.tmpl>
33#include <commproc.h>
34#include "vecnum.h"
35
36/****************************************************************************/
37
f780aa2a
WD
38/*
39 * CPM interrupt vector functions.
40 */
41struct irq_action {
42 interrupt_handler_t *handler;
43 void *arg;
44 int count;
45};
46
47static struct irq_action irq_vecs[32];
48
49#if defined(CONFIG_440)
50static struct irq_action irq_vecs1[32]; /* For UIC1 */
51
52void uic1_interrupt( void * parms); /* UIC1 handler */
53#endif
54
55/****************************************************************************/
f780aa2a
WD
56#if defined(CONFIG_440)
57
58/* SPRN changed in 440 */
59static __inline__ void set_evpr(unsigned long val)
60{
61 asm volatile("mtspr 0x03f,%0" : : "r" (val));
62}
63
64#else /* !defined(CONFIG_440) */
65
f780aa2a
WD
66static __inline__ void set_pit(unsigned long val)
67{
68 asm volatile("mtpit %0" : : "r" (val));
69}
70
71
72static __inline__ void set_tcr(unsigned long val)
73{
74 asm volatile("mttcr %0" : : "r" (val));
75}
76
77
78static __inline__ void set_evpr(unsigned long val)
79{
80 asm volatile("mtevpr %0" : : "r" (val));
81}
82#endif /* defined(CONFIG_440 */
83
f780aa2a
WD
84/****************************************************************************/
85
a8c7c708 86int interrupt_init_cpu (unsigned *decrementer_count)
f780aa2a
WD
87{
88 DECLARE_GLOBAL_DATA_PTR;
89
90 int vec;
91 unsigned long val;
92
a8c7c708
WD
93 /* decrementer is automatically reloaded */
94 *decrementer_count = 0;
95
f780aa2a
WD
96 /*
97 * Mark all irqs as free
98 */
99 for (vec=0; vec<32; vec++) {
100 irq_vecs[vec].handler = NULL;
101 irq_vecs[vec].arg = NULL;
102 irq_vecs[vec].count = 0;
103#if defined(CONFIG_440)
104 irq_vecs1[vec].handler = NULL;
105 irq_vecs1[vec].arg = NULL;
106 irq_vecs1[vec].count = 0;
107#endif
108 }
109
110#ifdef CONFIG_4xx
111 /*
112 * Init PIT
113 */
114#if defined(CONFIG_440)
115 val = mfspr( tcr );
116 val &= (~0x04400000); /* clear DIS & ARE */
117 mtspr( tcr, val );
118 mtspr( dec, 0 ); /* Prevent exception after TSR clear*/
119 mtspr( decar, 0 ); /* clear reload */
120 mtspr( tsr, 0x08000000 ); /* clear DEC status */
121 val = gd->bd->bi_intfreq/100; /* 10 msec */
122 mtspr( decar, val ); /* Set auto-reload value */
123 mtspr( dec, val ); /* Set inital val */
124#else
125 set_pit(gd->bd->bi_intfreq / 1000);
126#endif
127#endif /* CONFIG_4xx */
128
129#ifdef CONFIG_ADCIOP
130 /*
131 * Init PIT
132 */
133 set_pit(66000);
134#endif
135
136 /*
137 * Enable PIT
138 */
139 val = mfspr(tcr);
140 val |= 0x04400000;
141 mtspr(tcr, val);
142
143 /*
144 * Set EVPR to 0
145 */
146 set_evpr(0x00000000);
147
148#if defined(CONFIG_440)
149 /* Install the UIC1 handlers */
150 irq_install_handler(VECNUM_UIC1NC, uic1_interrupt, 0);
151 irq_install_handler(VECNUM_UIC1C, uic1_interrupt, 0);
152#endif
f780aa2a
WD
153
154 return (0);
155}
156
157/****************************************************************************/
158
159/*
160 * Handle external interrupts
161 */
162void external_interrupt(struct pt_regs *regs)
163{
164 ulong uic_msr;
165 ulong msr_shift;
166 int vec;
167
168 /*
169 * Read masked interrupt status register to determine interrupt source
170 */
171 uic_msr = mfdcr(uicmsr);
172 msr_shift = uic_msr;
173 vec = 0;
174
175 while (msr_shift != 0) {
176 if (msr_shift & 0x80000000) {
177 /*
178 * Increment irq counter (for debug purpose only)
179 */
180 irq_vecs[vec].count++;
181
182 if (irq_vecs[vec].handler != NULL) {
183 /* call isr */
184 (*irq_vecs[vec].handler)(irq_vecs[vec].arg);
185 } else {
186 mtdcr(uicer, mfdcr(uicer) & ~(0x80000000 >> vec));
187 printf ("Masking bogus interrupt vector 0x%x\n", vec);
188 }
189
190 /*
191 * After servicing the interrupt, we have to remove the status indicator.
192 */
193 mtdcr(uicsr, (0x80000000 >> vec));
194 }
195
196 /*
197 * Shift msr to next position and increment vector
198 */
199 msr_shift <<= 1;
200 vec++;
201 }
202}
203
204#if defined(CONFIG_440)
205/* Handler for UIC1 interrupt */
206void uic1_interrupt( void * parms)
207{
208 ulong uic1_msr;
209 ulong msr_shift;
210 int vec;
211
212 /*
213 * Read masked interrupt status register to determine interrupt source
214 */
215 uic1_msr = mfdcr(uic1msr);
216 msr_shift = uic1_msr;
217 vec = 0;
218
219 while (msr_shift != 0) {
220 if (msr_shift & 0x80000000) {
221 /*
222 * Increment irq counter (for debug purpose only)
223 */
224 irq_vecs1[vec].count++;
225
226 if (irq_vecs1[vec].handler != NULL) {
227 /* call isr */
228 (*irq_vecs1[vec].handler)(irq_vecs1[vec].arg);
229 } else {
230 mtdcr(uic1er, mfdcr(uic1er) & ~(0x80000000 >> vec));
231 printf ("Masking bogus interrupt vector (uic1) 0x%x\n", vec);
232 }
233
234 /*
235 * After servicing the interrupt, we have to remove the status indicator.
236 */
237 mtdcr(uic1sr, (0x80000000 >> vec));
238 }
239
240 /*
241 * Shift msr to next position and increment vector
242 */
243 msr_shift <<= 1;
244 vec++;
245 }
246}
247#endif /* defined(CONFIG_440) */
248
249/****************************************************************************/
250
251/*
252 * Install and free a interrupt handler.
253 */
254
255void
256irq_install_handler(int vec, interrupt_handler_t *handler, void *arg)
257{
258 struct irq_action *irqa = irq_vecs;
259 int i = vec;
260
261#if defined(CONFIG_440)
262 if (vec > 31) {
263 i = vec - 32;
264 irqa = irq_vecs1;
265 }
266#endif
267
268 if (irqa[i].handler != NULL) {
269 printf ("Interrupt vector %d: handler 0x%x replacing 0x%x\n",
270 vec, (uint)handler, (uint)irqa[i].handler);
271 }
272 irqa[i].handler = handler;
273 irqa[i].arg = arg;
274
275#if defined(CONFIG_440)
276 if( vec > 31 )
277 mtdcr(uic1er, mfdcr(uic1er) | (0x80000000 >> i));
278 else
279#endif
280 mtdcr(uicer, mfdcr(uicer) | (0x80000000 >> i));
281#if 0
282 printf ("Install interrupt for vector %d ==> %p\n", vec, handler);
283#endif
284}
285
286void
287irq_free_handler(int vec)
288{
289 struct irq_action *irqa = irq_vecs;
290 int i = vec;
291
292#if defined(CONFIG_440)
293 if (vec > 31) {
294 irqa = irq_vecs1;
295 i = vec - 32;
296 }
297#endif
298
299#if 0
300 printf ("Free interrupt for vector %d ==> %p\n",
301 vec, irq_vecs[vec].handler);
302#endif
303
304#if defined(CONFIG_440)
305 if (vec > 31)
306 mtdcr(uic1er, mfdcr(uic1er) & ~(0x80000000 >> i));
307 else
308#endif
309 mtdcr(uicer, mfdcr(uicer) & ~(0x80000000 >> i));
310
311 irqa[i].handler = NULL;
312 irqa[i].arg = NULL;
313}
314
315/****************************************************************************/
316
a8c7c708 317void timer_interrupt_cpu (struct pt_regs *regs)
f780aa2a 318{
a8c7c708
WD
319 /* nothing to do here */
320 return;
f780aa2a
WD
321}
322
323/****************************************************************************/
324
f780aa2a
WD
325#if (CONFIG_COMMANDS & CFG_CMD_IRQ)
326
327/*******************************************************************************
328 *
329 * irqinfo - print information about PCI devices
330 *
331 */
332int
333do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
334{
335 int vec;
336
337 printf ("\nInterrupt-Information:\n");
338#if defined(CONFIG_440)
339 printf ("\nUIC 0\n");
340#endif
341 printf ("Nr Routine Arg Count\n");
342
343 for (vec=0; vec<32; vec++) {
344 if (irq_vecs[vec].handler != NULL) {
345 printf ("%02d %08lx %08lx %d\n",
346 vec,
347 (ulong)irq_vecs[vec].handler,
348 (ulong)irq_vecs[vec].arg,
349 irq_vecs[vec].count);
350 }
351 }
352
353#if defined(CONFIG_440)
354 printf ("\nUIC 1\n");
355 printf ("Nr Routine Arg Count\n");
356
357 for (vec=0; vec<32; vec++)
358 {
359 if (irq_vecs1[vec].handler != NULL)
360 printf ("%02d %08lx %08lx %d\n",
361 vec+31, (ulong)irq_vecs1[vec].handler,
362 (ulong)irq_vecs1[vec].arg, irq_vecs1[vec].count);
363 }
364 printf("\n");
365#endif
366 return 0;
367}
368
369
370#endif /* CONFIG_COMMANDS & CFG_CMD_IRQ */