2 * (C) Copyright 2000-2002 Wolfgang Denk, DENX Software Engineering, wd@denx.de.
3 * (C) Copyright 2003 Martin Winistoerfer, martinwinistoerfer@gmx.ch.
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
26 * Discription: Contains interrupt routines needed by U-Boot
33 #include <asm/processor.h>
35 /************************************************************************/
37 unsigned decrementer_count
; /* count value for 1e6/HZ microseconds */
39 /************************************************************************/
41 struct interrupt_action
{
42 interrupt_handler_t
*handler
;
46 static struct interrupt_action irq_vecs
[NR_IRQS
];
49 * Local function prototypes
51 static __inline__
unsigned long get_msr (void)
55 asm volatile ("mfmsr %0":"=r" (msr
):);
60 static __inline__
void set_msr (unsigned long msr
)
62 asm volatile ("mtmsr %0"::"r" (msr
));
65 static __inline__
unsigned long get_dec (void)
69 asm volatile ("mfdec %0":"=r" (val
):);
75 static __inline__
void set_dec (unsigned long val
)
77 asm volatile ("mtdec %0"::"r" (val
));
83 void enable_interrupts (void)
85 set_msr (get_msr () | MSR_EE
);
89 * Returns flag if MSR_EE was set before
91 int disable_interrupts (void)
93 ulong msr
= get_msr ();
95 set_msr (msr
& ~MSR_EE
);
96 return ((msr
& MSR_EE
) != 0);
100 * Initialise interrupts
103 int interrupt_init (void)
105 volatile immap_t
*immr
= (immap_t
*) CFG_IMMR
;
107 /* Decrementer used here for status led */
108 decrementer_count
= get_tbclk () / CFG_HZ
;
110 /* Disable all interrupts */
111 immr
->im_siu_conf
.sc_simask
= 0;
113 set_dec (decrementer_count
);
115 set_msr (get_msr () | MSR_EE
);
120 * Handle external interrupts
122 void external_interrupt (struct pt_regs
*regs
)
124 volatile immap_t
*immr
= (immap_t
*) CFG_IMMR
;
126 ulong simask
, newmask
;
130 * read the SIVEC register and shift the bits down
131 * to get the irq number
133 vec
= immr
->im_siu_conf
.sc_sivec
;
135 v_bit
= 0x80000000UL
>> irq
;
138 * Read Interrupt Mask Register and Mask Interrupts
140 simask
= immr
->im_siu_conf
.sc_simask
;
141 newmask
= simask
& (~(0xFFFF0000 >> irq
));
142 immr
->im_siu_conf
.sc_simask
= newmask
;
144 if (!(irq
& 0x1)) { /* External Interrupt ? */
148 * Read Interrupt Edge/Level Register
150 siel
= immr
->im_siu_conf
.sc_siel
;
152 if (siel
& v_bit
) { /* edge triggered interrupt ? */
154 * Rewrite SIPEND Register to clear interrupt
156 immr
->im_siu_conf
.sc_sipend
= v_bit
;
160 if (irq_vecs
[irq
].handler
!= NULL
) {
161 irq_vecs
[irq
].handler (irq_vecs
[irq
].arg
);
163 printf ("\nBogus External Interrupt IRQ %d Vector %ld\n",
165 /* turn off the bogus interrupt to avoid it from now */
169 * Re-Enable old Interrupt Mask
171 immr
->im_siu_conf
.sc_simask
= simask
;
175 * Install and free an interrupt handler
177 void irq_install_handler (int vec
, interrupt_handler_t
* handler
,
180 volatile immap_t
*immr
= (immap_t
*) CFG_IMMR
;
182 if (irq_vecs
[vec
].handler
!= NULL
) {
183 printf ("SIU interrupt %d 0x%x\n",
187 irq_vecs
[vec
].handler
= handler
;
188 irq_vecs
[vec
].arg
= arg
;
189 immr
->im_siu_conf
.sc_simask
|= 1 << (31 - vec
);
191 printf ("Install SIU interrupt for vector %d ==> %p\n",
196 void irq_free_handler (int vec
)
198 volatile immap_t
*immr
= (immap_t
*) CFG_IMMR
;
201 printf ("Free CPM interrupt for vector %d\n",
204 immr
->im_siu_conf
.sc_simask
&= ~(1 << (31 - vec
));
205 irq_vecs
[vec
].handler
= NULL
;
206 irq_vecs
[vec
].arg
= NULL
;
209 volatile ulong timestamp
= 0;
212 * Timer interrupt - gets called when bit 0 of DEC changes from
213 * 0. Decrementer is enabled with bit TBE in TBSCR.
215 void timer_interrupt (struct pt_regs
*regs
)
217 volatile immap_t
*immr
= (immap_t
*) CFG_IMMR
;
219 #ifdef CONFIG_STATUS_LED
220 extern void status_led_tick (ulong
);
223 printf ("*** Timer Interrupt *** ");
225 /* Reset Timer Status Bit and Timers Interrupt Status */
226 immr
->im_clkrstk
.cark_plprcrk
= KAPWR_KEY
;
228 immr
->im_clkrst
.car_plprcr
|= PLPRCR_TEXPS
| PLPRCR_TMIST
;
230 /* Restore Decrementer Count */
231 set_dec (decrementer_count
);
235 #ifdef CONFIG_STATUS_LED
236 status_led_tick (timestamp
);
237 #endif /* CONFIG_STATUS_LED */
239 #if defined(CONFIG_WATCHDOG)
241 * The shortest watchdog period of all boards
242 * is approx. 1 sec, thus re-trigger watchdog at least
243 * every 500 ms = CFG_HZ / 2
245 if ((timestamp
% (CFG_HZ
/ 2)) == 0) {
246 reset_5xx_watchdog (immr
);
248 #endif /* CONFIG_WATCHDOG */
254 void reset_timer (void)
262 ulong
get_timer (ulong base
)
264 return (timestamp
- base
);
270 void set_timer (ulong t
)