2 * (C) Copyright 2000-2002 Wolfgang Denk, DENX Software Engineering, wd@denx.de.
3 * (C) Copyright 2003 Martin Winistoerfer, martinwinistoerfer@gmx.ch.
5 * SPDX-License-Identifier: GPL-2.0+
11 * Discription: Contains interrupt routines needed by U-Boot
18 #include <asm/processor.h>
20 #if defined(CONFIG_PATI)
21 /* PATI uses IRQs for PCI doorbell */
26 struct interrupt_action
{
27 interrupt_handler_t
*handler
;
32 static struct interrupt_action irq_vecs
[NR_IRQS
];
35 * Initialise interrupts
38 int interrupt_init_cpu (ulong
*decrementer_count
)
40 volatile immap_t
*immr
= (immap_t
*) CONFIG_SYS_IMMR
;
43 /* Decrementer used here for status led */
44 *decrementer_count
= get_tbclk () / CONFIG_SYS_HZ
;
46 /* Disable all interrupts */
47 immr
->im_siu_conf
.sc_simask
= 0;
48 for (vec
=0; vec
<NR_IRQS
; vec
++) {
49 irq_vecs
[vec
].handler
= NULL
;
50 irq_vecs
[vec
].arg
= NULL
;
51 irq_vecs
[vec
].count
= 0;
58 * Handle external interrupts
60 void external_interrupt (struct pt_regs
*regs
)
62 volatile immap_t
*immr
= (immap_t
*) CONFIG_SYS_IMMR
;
64 ulong simask
, newmask
;
68 * read the SIVEC register and shift the bits down
69 * to get the irq number
71 vec
= immr
->im_siu_conf
.sc_sivec
;
73 v_bit
= 0x80000000UL
>> irq
;
76 * Read Interrupt Mask Register and Mask Interrupts
78 simask
= immr
->im_siu_conf
.sc_simask
;
79 newmask
= simask
& (~(0xFFFF0000 >> irq
));
80 immr
->im_siu_conf
.sc_simask
= newmask
;
82 if (!(irq
& 0x1)) { /* External Interrupt ? */
86 * Read Interrupt Edge/Level Register
88 siel
= immr
->im_siu_conf
.sc_siel
;
90 if (siel
& v_bit
) { /* edge triggered interrupt ? */
92 * Rewrite SIPEND Register to clear interrupt
94 immr
->im_siu_conf
.sc_sipend
= v_bit
;
98 if (irq_vecs
[irq
].handler
!= NULL
) {
99 irq_vecs
[irq
].handler (irq_vecs
[irq
].arg
);
101 printf ("\nBogus External Interrupt IRQ %d Vector %ld\n",
103 /* turn off the bogus interrupt to avoid it from now */
107 * Re-Enable old Interrupt Mask
109 immr
->im_siu_conf
.sc_simask
= simask
;
113 * Install and free an interrupt handler
115 void irq_install_handler (int vec
, interrupt_handler_t
* handler
,
118 volatile immap_t
*immr
= (immap_t
*) CONFIG_SYS_IMMR
;
120 if (irq_vecs
[vec
].handler
!= NULL
) {
121 printf ("SIU interrupt %d 0x%x\n",
125 irq_vecs
[vec
].handler
= handler
;
126 irq_vecs
[vec
].arg
= arg
;
127 immr
->im_siu_conf
.sc_simask
|= 1 << (31 - vec
);
129 printf ("Install SIU interrupt for vector %d ==> %p\n",
134 void irq_free_handler (int vec
)
136 volatile immap_t
*immr
= (immap_t
*) CONFIG_SYS_IMMR
;
139 printf ("Free CPM interrupt for vector %d\n",
142 immr
->im_siu_conf
.sc_simask
&= ~(1 << (31 - vec
));
143 irq_vecs
[vec
].handler
= NULL
;
144 irq_vecs
[vec
].arg
= NULL
;
148 * Timer interrupt - gets called when bit 0 of DEC changes from
149 * 0. Decrementer is enabled with bit TBE in TBSCR.
151 void timer_interrupt_cpu (struct pt_regs
*regs
)
153 volatile immap_t
*immr
= (immap_t
*) CONFIG_SYS_IMMR
;
156 printf ("*** Timer Interrupt *** ");
158 /* Reset Timer Status Bit and Timers Interrupt Status */
159 immr
->im_clkrstk
.cark_plprcrk
= KAPWR_KEY
;
161 immr
->im_clkrst
.car_plprcr
|= PLPRCR_TEXPS
| PLPRCR_TMIST
;
166 #if defined(CONFIG_CMD_IRQ)
167 /*******************************************************************************
169 * irqinfo - print information about IRQs
172 int do_irqinfo(cmd_tbl_t
*cmdtp
, int flag
, int argc
, char * const argv
[])
176 printf ("\nInterrupt-Information:\n");
177 printf ("Nr Routine Arg Count\n");
179 for (vec
=0; vec
<NR_IRQS
; vec
++) {
180 if (irq_vecs
[vec
].handler
!= NULL
) {
181 printf ("%02d %08lx %08lx %d\n",
183 (ulong
)irq_vecs
[vec
].handler
,
184 (ulong
)irq_vecs
[vec
].arg
,
185 irq_vecs
[vec
].count
);