blob: 8215dc652edb1d0fe5fb947ac547d558173bb53c [file] [log] [blame]
wdenkf780aa22002-09-18 19:21:21 +00001/*
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 *
wdenkba56f622004-02-06 23:19:44 +00008 * (C) Copyright 2003 (440GX port)
9 * Travis B. Sawyer, Sandburst Corporation, tsawyer@sandburst.com
10 *
wdenkf780aa22002-09-18 19:21:21 +000011 * 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>
wdenkf780aa22002-09-18 19:21:21 +000033#include <asm/processor.h>
34#include <ppc4xx.h>
35#include <ppc_asm.tmpl>
36#include <commproc.h>
wdenkf780aa22002-09-18 19:21:21 +000037
Stefan Roesed1631fe2008-06-26 13:40:57 +020038#if (UIC_MAX > 3)
39#define UICB0_ALL (UIC_MASK(VECNUM_UIC1CI) | UIC_MASK(VECNUM_UIC1NCI) | \
40 UIC_MASK(VECNUM_UIC2CI) | UIC_MASK(VECNUM_UIC2NCI) | \
41 UIC_MASK(VECNUM_UIC3CI) | UIC_MASK(VECNUM_UIC3NCI))
42#elif (UIC_MAX > 2)
Stefan Roesed1631fe2008-06-26 13:40:57 +020043#define UICB0_ALL (UIC_MASK(VECNUM_UIC1CI) | UIC_MASK(VECNUM_UIC1NCI) | \
44 UIC_MASK(VECNUM_UIC2CI) | UIC_MASK(VECNUM_UIC2NCI))
Stefan Roesed1631fe2008-06-26 13:40:57 +020045#elif (UIC_MAX > 1)
46#define UICB0_ALL (UIC_MASK(VECNUM_UIC1CI) | UIC_MASK(VECNUM_UIC1NCI))
47#else
48#define UICB0_ALL 0
49#endif
50
51DECLARE_GLOBAL_DATA_PTR;
wdenkf780aa22002-09-18 19:21:21 +000052
wdenkf780aa22002-09-18 19:21:21 +000053/*
54 * CPM interrupt vector functions.
55 */
56struct irq_action {
57 interrupt_handler_t *handler;
58 void *arg;
59 int count;
60};
61
Stefan Roese56e41012008-02-19 22:07:57 +010062static struct irq_action irq_vecs[UIC_MAX * 32];
wdenkf780aa22002-09-18 19:21:21 +000063
Stefan Roese56e41012008-02-19 22:07:57 +010064u32 get_dcr(u16);
65void set_dcr(u16, u32);
wdenkf780aa22002-09-18 19:21:21 +000066
wdenkf780aa22002-09-18 19:21:21 +000067#if defined(CONFIG_440)
68
69/* SPRN changed in 440 */
70static __inline__ void set_evpr(unsigned long val)
71{
72 asm volatile("mtspr 0x03f,%0" : : "r" (val));
73}
74
75#else /* !defined(CONFIG_440) */
76
wdenkf780aa22002-09-18 19:21:21 +000077static __inline__ void set_pit(unsigned long val)
78{
79 asm volatile("mtpit %0" : : "r" (val));
80}
81
82
83static __inline__ void set_tcr(unsigned long val)
84{
85 asm volatile("mttcr %0" : : "r" (val));
86}
87
88
89static __inline__ void set_evpr(unsigned long val)
90{
91 asm volatile("mtevpr %0" : : "r" (val));
92}
93#endif /* defined(CONFIG_440 */
94
wdenka8c7c702003-12-06 19:49:23 +000095int interrupt_init_cpu (unsigned *decrementer_count)
wdenkf780aa22002-09-18 19:21:21 +000096{
wdenkf780aa22002-09-18 19:21:21 +000097 int vec;
98 unsigned long val;
99
wdenka8c7c702003-12-06 19:49:23 +0000100 /* decrementer is automatically reloaded */
101 *decrementer_count = 0;
wdenkd4ca31c2004-01-02 14:00:00 +0000102
wdenkf780aa22002-09-18 19:21:21 +0000103 /*
104 * Mark all irqs as free
105 */
Stefan Roese56e41012008-02-19 22:07:57 +0100106 for (vec = 0; vec < (UIC_MAX * 32); vec++) {
wdenkf780aa22002-09-18 19:21:21 +0000107 irq_vecs[vec].handler = NULL;
108 irq_vecs[vec].arg = NULL;
109 irq_vecs[vec].count = 0;
wdenkf780aa22002-09-18 19:21:21 +0000110 }
111
112#ifdef CONFIG_4xx
113 /*
114 * Init PIT
115 */
116#if defined(CONFIG_440)
117 val = mfspr( tcr );
118 val &= (~0x04400000); /* clear DIS & ARE */
119 mtspr( tcr, val );
120 mtspr( dec, 0 ); /* Prevent exception after TSR clear*/
121 mtspr( decar, 0 ); /* clear reload */
122 mtspr( tsr, 0x08000000 ); /* clear DEC status */
stroese68e02362005-04-07 05:32:44 +0000123 val = gd->bd->bi_intfreq/1000; /* 1 msec */
wdenkf780aa22002-09-18 19:21:21 +0000124 mtspr( decar, val ); /* Set auto-reload value */
125 mtspr( dec, val ); /* Set inital val */
126#else
127 set_pit(gd->bd->bi_intfreq / 1000);
128#endif
129#endif /* CONFIG_4xx */
130
131#ifdef CONFIG_ADCIOP
132 /*
133 * Init PIT
134 */
135 set_pit(66000);
136#endif
137
138 /*
139 * Enable PIT
140 */
141 val = mfspr(tcr);
142 val |= 0x04400000;
143 mtspr(tcr, val);
144
145 /*
146 * Set EVPR to 0
147 */
148 set_evpr(0x00000000);
149
Stefan Roese56e41012008-02-19 22:07:57 +0100150#if (UIC_MAX > 1)
wdenkf780aa22002-09-18 19:21:21 +0000151 /* Install the UIC1 handlers */
Stefan Roese5de85142008-06-26 17:36:39 +0200152 irq_install_handler(VECNUM_UIC1NCI, (void *)(void *)external_interrupt, 0);
153 irq_install_handler(VECNUM_UIC1CI, (void *)(void *)external_interrupt, 0);
wdenkf780aa22002-09-18 19:21:21 +0000154#endif
Stefan Roese56e41012008-02-19 22:07:57 +0100155#if (UIC_MAX > 2)
Stefan Roese5de85142008-06-26 17:36:39 +0200156 irq_install_handler(VECNUM_UIC2NCI, (void *)(void *)external_interrupt, 0);
157 irq_install_handler(VECNUM_UIC2CI, (void *)(void *)external_interrupt, 0);
wdenkba56f622004-02-06 23:19:44 +0000158#endif
Stefan Roese56e41012008-02-19 22:07:57 +0100159#if (UIC_MAX > 3)
Stefan Roese5de85142008-06-26 17:36:39 +0200160 irq_install_handler(VECNUM_UIC3NCI, (void *)(void *)external_interrupt, 0);
161 irq_install_handler(VECNUM_UIC3CI, (void *)(void *)external_interrupt, 0);
Stefan Roese56e41012008-02-19 22:07:57 +0100162#endif
wdenkf780aa22002-09-18 19:21:21 +0000163
164 return (0);
165}
166
Stefan Roese56e41012008-02-19 22:07:57 +0100167/* Handler for UIC interrupt */
168static void uic_interrupt(u32 uic_base, int vec_base)
169{
170 u32 uic_msr;
171 u32 msr_shift;
172 int vec;
173
174 /*
175 * Read masked interrupt status register to determine interrupt source
176 */
177 uic_msr = get_dcr(uic_base + UIC_MSR);
178 msr_shift = uic_msr;
179 vec = vec_base;
180
181 while (msr_shift != 0) {
182 if (msr_shift & 0x80000000) {
183 /*
184 * Increment irq counter (for debug purpose only)
185 */
186 irq_vecs[vec].count++;
187
188 if (irq_vecs[vec].handler != NULL) {
189 /* call isr */
190 (*irq_vecs[vec].handler)(irq_vecs[vec].arg);
191 } else {
192 set_dcr(uic_base + UIC_ER,
Stefan Roesed1631fe2008-06-26 13:40:57 +0200193 get_dcr(uic_base + UIC_ER) & ~UIC_MASK(vec));
Stefan Roese56e41012008-02-19 22:07:57 +0100194 printf("Masking bogus interrupt vector %d"
195 " (UIC_BASE=0x%x)\n", vec, uic_base);
196 }
197
198 /*
Stefan Roesed8bd6432008-03-27 08:47:26 +0100199 * After servicing the interrupt, we have to remove the
200 * status indicator
Stefan Roese56e41012008-02-19 22:07:57 +0100201 */
Stefan Roesed1631fe2008-06-26 13:40:57 +0200202 set_dcr(uic_base + UIC_SR, UIC_MASK(vec));
Stefan Roese56e41012008-02-19 22:07:57 +0100203 }
204
205 /*
206 * Shift msr to next position and increment vector
207 */
208 msr_shift <<= 1;
209 vec++;
210 }
211}
212
wdenkf780aa22002-09-18 19:21:21 +0000213/*
214 * Handle external interrupts
215 */
wdenkba56f622004-02-06 23:19:44 +0000216void external_interrupt(struct pt_regs *regs)
217{
Stefan Roese56e41012008-02-19 22:07:57 +0100218 u32 uic_msr;
wdenkba56f622004-02-06 23:19:44 +0000219
220 /*
221 * Read masked interrupt status register to determine interrupt source
222 */
Stefan Roese5de85142008-06-26 17:36:39 +0200223 uic_msr = mfdcr(uic0msr);
wdenkba56f622004-02-06 23:19:44 +0000224
Stefan Roese56e41012008-02-19 22:07:57 +0100225#if (UIC_MAX > 1)
Stefan Roesed1631fe2008-06-26 13:40:57 +0200226 if ((UIC_MASK(VECNUM_UIC1CI) & uic_msr) ||
227 (UIC_MASK(VECNUM_UIC1NCI) & uic_msr))
Stefan Roese56e41012008-02-19 22:07:57 +0100228 uic_interrupt(UIC1_DCR_BASE, 32);
wdenkba56f622004-02-06 23:19:44 +0000229#endif
230
Stefan Roese56e41012008-02-19 22:07:57 +0100231#if (UIC_MAX > 2)
Stefan Roesed1631fe2008-06-26 13:40:57 +0200232 if ((UIC_MASK(VECNUM_UIC2CI) & uic_msr) ||
233 (UIC_MASK(VECNUM_UIC2NCI) & uic_msr))
Stefan Roese56e41012008-02-19 22:07:57 +0100234 uic_interrupt(UIC2_DCR_BASE, 64);
235#endif
wdenkba56f622004-02-06 23:19:44 +0000236
Stefan Roese56e41012008-02-19 22:07:57 +0100237#if (UIC_MAX > 3)
Stefan Roesed1631fe2008-06-26 13:40:57 +0200238 if ((UIC_MASK(VECNUM_UIC3CI) & uic_msr) ||
239 (UIC_MASK(VECNUM_UIC3NCI) & uic_msr))
Stefan Roese56e41012008-02-19 22:07:57 +0100240 uic_interrupt(UIC3_DCR_BASE, 96);
241#endif
wdenkba56f622004-02-06 23:19:44 +0000242
Stefan Roese56e41012008-02-19 22:07:57 +0100243 if (uic_msr & ~(UICB0_ALL))
244 uic_interrupt(UIC0_DCR_BASE, 0);
wdenkba56f622004-02-06 23:19:44 +0000245
Stefan Roese5de85142008-06-26 17:36:39 +0200246 mtdcr(uic0sr, uic_msr);
wdenkba56f622004-02-06 23:19:44 +0000247
Stefan Roese56e41012008-02-19 22:07:57 +0100248 return;
wdenkba56f622004-02-06 23:19:44 +0000249}
250
wdenkf780aa22002-09-18 19:21:21 +0000251/*
252 * Install and free a interrupt handler.
253 */
Stefan Roese56e41012008-02-19 22:07:57 +0100254void irq_install_handler(int vec, interrupt_handler_t * handler, void *arg)
wdenkf780aa22002-09-18 19:21:21 +0000255{
Stefan Roesec157d8e2005-08-01 16:41:48 +0200256 /*
Stefan Roese56e41012008-02-19 22:07:57 +0100257 * Print warning when replacing with a different irq vector
Stefan Roesec157d8e2005-08-01 16:41:48 +0200258 */
Stefan Roese56e41012008-02-19 22:07:57 +0100259 if ((irq_vecs[vec].handler != NULL) && (irq_vecs[vec].handler != handler)) {
260 printf("Interrupt vector %d: handler 0x%x replacing 0x%x\n",
261 vec, (uint) handler, (uint) irq_vecs[vec].handler);
wdenkf780aa22002-09-18 19:21:21 +0000262 }
Stefan Roese56e41012008-02-19 22:07:57 +0100263 irq_vecs[vec].handler = handler;
264 irq_vecs[vec].arg = arg;
wdenkf780aa22002-09-18 19:21:21 +0000265
Stefan Roese56e41012008-02-19 22:07:57 +0100266 if ((vec >= 0) && (vec < 32))
Stefan Roese5de85142008-06-26 17:36:39 +0200267 mtdcr(uicer, mfdcr(uicer) | UIC_MASK(vec));
Stefan Roese56e41012008-02-19 22:07:57 +0100268#if (UIC_MAX > 1)
269 else if ((vec >= 32) && (vec < 64))
Stefan Roese5de85142008-06-26 17:36:39 +0200270 mtdcr(uic1er, mfdcr(uic1er) | UIC_MASK(vec));
wdenkf780aa22002-09-18 19:21:21 +0000271#endif
Stefan Roese56e41012008-02-19 22:07:57 +0100272#if (UIC_MAX > 2)
273 else if ((vec >= 64) && (vec < 96))
Stefan Roese5de85142008-06-26 17:36:39 +0200274 mtdcr(uic2er, mfdcr(uic2er) | UIC_MASK(vec));
wdenkf780aa22002-09-18 19:21:21 +0000275#endif
Stefan Roese56e41012008-02-19 22:07:57 +0100276#if (UIC_MAX > 3)
277 else if (vec >= 96)
Stefan Roese5de85142008-06-26 17:36:39 +0200278 mtdcr(uic3er, mfdcr(uic3er) | UIC_MASK(vec));
Stefan Roese56e41012008-02-19 22:07:57 +0100279#endif
280
281 debug("Install interrupt for vector %d ==> %p\n", vec, handler);
wdenkf780aa22002-09-18 19:21:21 +0000282}
283
wdenkba56f622004-02-06 23:19:44 +0000284void irq_free_handler (int vec)
wdenkf780aa22002-09-18 19:21:21 +0000285{
Stefan Roese56e41012008-02-19 22:07:57 +0100286 debug("Free interrupt for vector %d ==> %p\n",
287 vec, irq_vecs[vec].handler);
288
Stefan Roese56e41012008-02-19 22:07:57 +0100289 if ((vec >= 0) && (vec < 32))
Stefan Roese5de85142008-06-26 17:36:39 +0200290 mtdcr(uicer, mfdcr(uicer) & ~UIC_MASK(vec));
Stefan Roese56e41012008-02-19 22:07:57 +0100291#if (UIC_MAX > 1)
292 else if ((vec >= 32) && (vec < 64))
Stefan Roese5de85142008-06-26 17:36:39 +0200293 mtdcr(uic1er, mfdcr(uic1er) & ~UIC_MASK(vec));
Stefan Roese56e41012008-02-19 22:07:57 +0100294#endif
295#if (UIC_MAX > 2)
296 else if ((vec >= 64) && (vec < 96))
Stefan Roese5de85142008-06-26 17:36:39 +0200297 mtdcr(uic2er, mfdcr(uic2er) & ~UIC_MASK(vec));
Stefan Roese56e41012008-02-19 22:07:57 +0100298#endif
299#if (UIC_MAX > 3)
300 else if (vec >= 96)
Stefan Roese5de85142008-06-26 17:36:39 +0200301 mtdcr(uic3er, mfdcr(uic3er) & ~UIC_MASK(vec));
wdenkf780aa22002-09-18 19:21:21 +0000302#endif
303
Stefan Roese56e41012008-02-19 22:07:57 +0100304 irq_vecs[vec].handler = NULL;
305 irq_vecs[vec].arg = NULL;
wdenkf780aa22002-09-18 19:21:21 +0000306}
307
wdenka8c7c702003-12-06 19:49:23 +0000308void timer_interrupt_cpu (struct pt_regs *regs)
wdenkf780aa22002-09-18 19:21:21 +0000309{
wdenka8c7c702003-12-06 19:49:23 +0000310 /* nothing to do here */
311 return;
wdenkf780aa22002-09-18 19:21:21 +0000312}
313
Jon Loeliger3a1ed1e2007-07-09 18:57:22 -0500314#if defined(CONFIG_CMD_IRQ)
Stefan Roese56e41012008-02-19 22:07:57 +0100315int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
wdenkf780aa22002-09-18 19:21:21 +0000316{
317 int vec;
318
Stefan Roese56e41012008-02-19 22:07:57 +0100319 printf ("Interrupt-Information:\n");
wdenkf780aa22002-09-18 19:21:21 +0000320 printf ("Nr Routine Arg Count\n");
321
Stefan Roese56e41012008-02-19 22:07:57 +0100322 for (vec = 0; vec < (UIC_MAX * 32); vec++) {
wdenkf780aa22002-09-18 19:21:21 +0000323 if (irq_vecs[vec].handler != NULL) {
324 printf ("%02d %08lx %08lx %d\n",
325 vec,
326 (ulong)irq_vecs[vec].handler,
327 (ulong)irq_vecs[vec].arg,
328 irq_vecs[vec].count);
329 }
330 }
331
wdenkf780aa22002-09-18 19:21:21 +0000332 return 0;
333}
Jon Loeliger3a1ed1e2007-07-09 18:57:22 -0500334#endif