2 * (C) Copyright 2000-2002
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5 * See file CREDITS for list of people who contributed to this
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.
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.
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, Inc., 59 Temple Place, Suite 330, Boston,
26 #include <mpc8xx_irq.h>
27 #include <asm/processor.h>
30 /************************************************************************/
33 * CPM interrupt vector functions.
35 struct interrupt_action
{
36 interrupt_handler_t
*handler
;
40 static struct interrupt_action cpm_vecs
[CPMVEC_NR
];
41 static struct interrupt_action irq_vecs
[NR_IRQS
];
43 static void cpm_interrupt_init (void);
44 static void cpm_interrupt (void *regs
);
46 /************************************************************************/
48 int interrupt_init_cpu (unsigned *decrementer_count
)
50 volatile immap_t
*immr
= (immap_t
*) CONFIG_SYS_IMMR
;
52 *decrementer_count
= get_tbclk () / CONFIG_SYS_HZ
;
54 /* disable all interrupts */
55 immr
->im_siu_conf
.sc_simask
= 0;
57 /* Configure CPM interrupts */
58 cpm_interrupt_init ();
63 /************************************************************************/
66 * Handle external interrupts
68 void external_interrupt (struct pt_regs
*regs
)
70 volatile immap_t
*immr
= (immap_t
*) CONFIG_SYS_IMMR
;
72 ulong simask
, newmask
;
76 * read the SIVEC register and shift the bits down
77 * to get the irq number
79 vec
= immr
->im_siu_conf
.sc_sivec
;
81 v_bit
= 0x80000000UL
>> irq
;
84 * Read Interrupt Mask Register and Mask Interrupts
86 simask
= immr
->im_siu_conf
.sc_simask
;
87 newmask
= simask
& (~(0xFFFF0000 >> irq
));
88 immr
->im_siu_conf
.sc_simask
= newmask
;
90 if (!(irq
& 0x1)) { /* External Interrupt ? */
94 * Read Interrupt Edge/Level Register
96 siel
= immr
->im_siu_conf
.sc_siel
;
98 if (siel
& v_bit
) { /* edge triggered interrupt ? */
100 * Rewrite SIPEND Register to clear interrupt
102 immr
->im_siu_conf
.sc_sipend
= v_bit
;
106 if (irq_vecs
[irq
].handler
!= NULL
) {
107 irq_vecs
[irq
].handler (irq_vecs
[irq
].arg
);
109 printf ("\nBogus External Interrupt IRQ %d Vector %ld\n",
111 /* turn off the bogus interrupt to avoid it from now */
115 * Re-Enable old Interrupt Mask
117 immr
->im_siu_conf
.sc_simask
= simask
;
120 /************************************************************************/
123 * CPM interrupt handler
125 static void cpm_interrupt (void *regs
)
127 volatile immap_t
*immr
= (immap_t
*) CONFIG_SYS_IMMR
;
131 * Get the vector by setting the ACK bit
132 * and then reading the register.
134 immr
->im_cpic
.cpic_civr
= 1;
135 vec
= immr
->im_cpic
.cpic_civr
;
138 if (cpm_vecs
[vec
].handler
!= NULL
) {
139 (*cpm_vecs
[vec
].handler
) (cpm_vecs
[vec
].arg
);
141 immr
->im_cpic
.cpic_cimr
&= ~(1 << vec
);
142 printf ("Masking bogus CPM interrupt vector 0x%x\n", vec
);
145 * After servicing the interrupt,
146 * we have to remove the status indicator.
148 immr
->im_cpic
.cpic_cisr
|= (1 << vec
);
152 * The CPM can generate the error interrupt when there is a race
153 * condition between generating and masking interrupts. All we have
154 * to do is ACK it and return. This is a no-op function so we don't
155 * need any special tests in the interrupt handler.
157 static void cpm_error_interrupt (void *dummy
)
161 /************************************************************************/
163 * Install and free an interrupt handler
165 void irq_install_handler (int vec
, interrupt_handler_t
* handler
,
168 volatile immap_t
*immr
= (immap_t
*) CONFIG_SYS_IMMR
;
170 if ((vec
& CPMVEC_OFFSET
) != 0) {
173 if (cpm_vecs
[vec
].handler
!= NULL
) {
174 printf ("CPM interrupt 0x%x replacing 0x%x\n",
176 (uint
) cpm_vecs
[vec
].handler
);
178 cpm_vecs
[vec
].handler
= handler
;
179 cpm_vecs
[vec
].arg
= arg
;
180 immr
->im_cpic
.cpic_cimr
|= (1 << vec
);
182 printf ("Install CPM interrupt for vector %d ==> %p\n",
187 if (irq_vecs
[vec
].handler
!= NULL
) {
188 printf ("SIU interrupt %d 0x%x replacing 0x%x\n",
191 (uint
) cpm_vecs
[vec
].handler
);
193 irq_vecs
[vec
].handler
= handler
;
194 irq_vecs
[vec
].arg
= arg
;
195 immr
->im_siu_conf
.sc_simask
|= 1 << (31 - vec
);
197 printf ("Install SIU interrupt for vector %d ==> %p\n",
203 void irq_free_handler (int vec
)
205 volatile immap_t
*immr
= (immap_t
*) CONFIG_SYS_IMMR
;
207 if ((vec
& CPMVEC_OFFSET
) != 0) {
211 printf ("Free CPM interrupt for vector %d ==> %p\n",
212 vec
, cpm_vecs
[vec
].handler
);
214 immr
->im_cpic
.cpic_cimr
&= ~(1 << vec
);
215 cpm_vecs
[vec
].handler
= NULL
;
216 cpm_vecs
[vec
].arg
= NULL
;
220 printf ("Free CPM interrupt for vector %d ==> %p\n",
221 vec
, cpm_vecs
[vec
].handler
);
223 immr
->im_siu_conf
.sc_simask
&= ~(1 << (31 - vec
));
224 irq_vecs
[vec
].handler
= NULL
;
225 irq_vecs
[vec
].arg
= NULL
;
229 /************************************************************************/
231 static void cpm_interrupt_init (void)
233 volatile immap_t
*immr
= (immap_t
*) CONFIG_SYS_IMMR
;
236 * Initialize the CPM interrupt controller.
239 immr
->im_cpic
.cpic_cicr
=
243 CICR_SCA_SCC1
) | ((CPM_INTERRUPT
/ 2) << 13) | CICR_HP_MASK
;
245 immr
->im_cpic
.cpic_cimr
= 0;
248 * Install the error handler.
250 irq_install_handler (CPMVEC_ERROR
, cpm_error_interrupt
, NULL
);
252 immr
->im_cpic
.cpic_cicr
|= CICR_IEN
;
255 * Install the cpm interrupt handler
257 irq_install_handler (CPM_INTERRUPT
, cpm_interrupt
, NULL
);
260 /************************************************************************/
263 * timer_interrupt - gets called when the decrementer overflows,
264 * with interrupts disabled.
265 * Trivial implementation - no need to be really accurate.
267 void timer_interrupt_cpu (struct pt_regs
*regs
)
269 volatile immap_t
*immr
= (immap_t
*) CONFIG_SYS_IMMR
;
272 printf ("*** Timer Interrupt *** ");
274 /* Reset Timer Expired and Timers Interrupt Status */
275 immr
->im_clkrstk
.cark_plprcrk
= KAPWR_KEY
;
278 Clear TEXPS (and TMIST on older chips). SPLSS (on older
279 chips) is cleared too.
281 Bitwise OR is a read-modify-write operation so ALL bits
282 which are cleared by writing `1' would be cleared by
285 immr->im_clkrst.car_plprcr |= PLPRCR_TEXPS;
287 The same can be achieved by simple writing of the PLPRCR
288 to itself. If a bit value should be preserved, read the
289 register, ZERO the bit and write, not OR, the result back.
291 immr
->im_clkrst
.car_plprcr
= immr
->im_clkrst
.car_plprcr
;
294 /************************************************************************/