3 Copyright 2002 Broadcom Corp. All Rights Reserved.
5 This program is free software; you can distribute it and/or modify it
6 under the terms of the GNU General Public License (Version 2) as
7 published by the Free Software Foundation.
9 This program is distributed in the hope it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
20 * Interrupt control functions for Broadcom 963xx MIPS boards
23 #include <asm/atomic.h>
25 #include <linux/delay.h>
26 #include <linux/init.h>
27 #include <linux/ioport.h>
28 #include <linux/irq.h>
29 #include <linux/interrupt.h>
30 #include <linux/kernel.h>
31 #include <linux/slab.h>
32 #include <linux/module.h>
35 #include <asm/mipsregs.h>
36 #include <asm/addrspace.h>
37 #include <asm/signal.h>
38 #include <6348_map_part.h>
39 #include <6348_intr.h>
40 #include <bcm_map_part.h>
43 static void irq_dispatch_int(void)
45 unsigned int pendingIrqs
;
46 static unsigned int irqBit
;
47 static unsigned int isrNumber
= 31;
49 pendingIrqs
= PERF
->IrqStatus
& PERF
->IrqMask
;
57 if (isrNumber
== 32) {
61 if (pendingIrqs
& irqBit
) {
62 PERF
->IrqMask
&= ~irqBit
; // mask
63 do_IRQ(isrNumber
+ INTERNAL_ISR_TABLE_OFFSET
);
69 static void irq_dispatch_ext(uint32 irq
)
71 if (!(PERF
->ExtIrqCfg
& (1 << (irq
- INTERRUPT_ID_EXTERNAL_0
+ EI_MASK_SHFT
)))) {
72 printk("**** Ext IRQ mask. Should not dispatch ****\n");
74 /* disable and clear interrupt in the controller */
75 PERF
->ExtIrqCfg
|= (1 << (irq
- INTERRUPT_ID_EXTERNAL_0
+ EI_CLEAR_SHFT
));
76 PERF
->ExtIrqCfg
&= ~(1 << (irq
- INTERRUPT_ID_EXTERNAL_0
+ EI_MASK_SHFT
));
81 //extern void brcm_timer_interrupt(struct pt_regs *regs);
83 asmlinkage
void plat_irq_dispatch(void)
87 cause
= read_c0_status() & read_c0_cause() & ST0_IM
;
88 if (cause
& CAUSEF_IP7
)
90 else if (cause
& CAUSEF_IP2
)
92 else if (cause
& CAUSEF_IP3
)
93 irq_dispatch_ext(INTERRUPT_ID_EXTERNAL_0
);
94 else if (cause
& CAUSEF_IP4
)
95 irq_dispatch_ext(INTERRUPT_ID_EXTERNAL_1
);
96 else if (cause
& CAUSEF_IP5
)
97 irq_dispatch_ext(INTERRUPT_ID_EXTERNAL_2
);
98 else if (cause
& CAUSEF_IP6
) {
99 irq_dispatch_ext(INTERRUPT_ID_EXTERNAL_3
);
105 void enable_brcm_irq(unsigned int irq
)
109 local_irq_save(flags
);
110 if( irq
>= INTERNAL_ISR_TABLE_OFFSET
) {
111 PERF
->IrqMask
|= (1 << (irq
- INTERNAL_ISR_TABLE_OFFSET
));
113 else if (irq
>= INTERRUPT_ID_EXTERNAL_0
&& irq
<= INTERRUPT_ID_EXTERNAL_3
) {
114 /* enable and clear interrupt in the controller */
115 PERF
->ExtIrqCfg
|= (1 << (irq
- INTERRUPT_ID_EXTERNAL_0
+ EI_CLEAR_SHFT
));
116 PERF
->ExtIrqCfg
|= (1 << (irq
- INTERRUPT_ID_EXTERNAL_0
+ EI_MASK_SHFT
));
118 local_irq_restore(flags
);
121 void disable_brcm_irq(unsigned int irq
)
125 local_irq_save(flags
);
126 if( irq
>= INTERNAL_ISR_TABLE_OFFSET
) {
127 PERF
->IrqMask
&= ~(1 << (irq
- INTERNAL_ISR_TABLE_OFFSET
));
129 else if (irq
>= INTERRUPT_ID_EXTERNAL_0
&& irq
<= INTERRUPT_ID_EXTERNAL_3
) {
130 /* disable interrupt in the controller */
131 PERF
->ExtIrqCfg
&= ~(1 << (irq
- INTERRUPT_ID_EXTERNAL_0
+ EI_MASK_SHFT
));
133 local_irq_restore(flags
);
136 void ack_brcm_irq(unsigned int irq
)
138 /* Already done in brcm_irq_dispatch */
141 unsigned int startup_brcm_irq(unsigned int irq
)
143 enable_brcm_irq(irq
);
145 return 0; /* never anything pending */
148 unsigned int startup_brcm_none(unsigned int irq
)
153 void end_brcm_irq(unsigned int irq
)
155 if (!(irq_desc
[irq
].status
& (IRQ_DISABLED
|IRQ_INPROGRESS
)))
156 enable_brcm_irq(irq
);
159 void end_brcm_none(unsigned int irq
)
163 static struct hw_interrupt_type brcm_irq_type
= {
165 .startup
= startup_brcm_irq
,
166 .shutdown
= disable_brcm_irq
,
167 .enable
= enable_brcm_irq
,
168 .disable
= disable_brcm_irq
,
174 static struct hw_interrupt_type brcm_irq_no_end_type
= {
176 .startup
= startup_brcm_none
,
177 .shutdown
= disable_brcm_irq
,
178 .enable
= enable_brcm_irq
,
179 .disable
= disable_brcm_irq
,
181 .end
= end_brcm_none
,
185 void __init
arch_init_irq(void)
189 clear_c0_status(ST0_BEV
);
190 change_c0_status(ST0_IM
, (IE_IRQ0
| IE_IRQ1
| IE_IRQ2
| IE_IRQ3
| IE_IRQ4
));
192 for (i
= 0; i
< NR_IRQS
; i
++) {
193 irq_desc
[i
].status
= IRQ_DISABLED
;
194 irq_desc
[i
].action
= 0;
195 irq_desc
[i
].depth
= 1;
196 irq_desc
[i
].chip
= &brcm_irq_type
;
200 int request_external_irq(unsigned int irq
,
202 unsigned long irqflags
,
203 const char * devname
,
208 local_irq_save(flags
);
210 PERF
->ExtIrqCfg
|= (1 << (irq
- INTERRUPT_ID_EXTERNAL_0
+ EI_CLEAR_SHFT
)); // Clear
211 PERF
->ExtIrqCfg
&= ~(1 << (irq
- INTERRUPT_ID_EXTERNAL_0
+ EI_MASK_SHFT
)); // Mask
212 PERF
->ExtIrqCfg
&= ~(1 << (irq
- INTERRUPT_ID_EXTERNAL_0
+ EI_INSENS_SHFT
)); // Edge insesnsitive
213 PERF
->ExtIrqCfg
|= (1 << (irq
- INTERRUPT_ID_EXTERNAL_0
+ EI_LEVEL_SHFT
)); // Level triggered
214 PERF
->ExtIrqCfg
&= ~(1 << (irq
- INTERRUPT_ID_EXTERNAL_0
+ EI_SENSE_SHFT
)); // Low level
216 local_irq_restore(flags
);
218 return( request_irq(irq
, handler
, irqflags
, devname
, dev_id
) );
221 /* VxWorks compatibility function(s). */
223 unsigned int BcmHalMapInterrupt(FN_HANDLER pfunc
, unsigned int param
,
224 unsigned int interruptId
)
229 devname
= kmalloc(16, GFP_KERNEL
);
231 sprintf( devname
, "brcm_%d", interruptId
);
233 /* Set the IRQ description to not automatically enable the interrupt at
234 * the end of an ISR. The driver that handles the interrupt must
235 * explicitly call BcmHalInterruptEnable or enable_brcm_irq. This behavior
236 * is consistent with interrupt handling on VxWorks.
238 irq_desc
[interruptId
].chip
= &brcm_irq_no_end_type
;
240 if( interruptId
>= INTERNAL_ISR_TABLE_OFFSET
)
242 printk("BcmHalMapInterrupt : internal IRQ\n");
243 nRet
= request_irq( interruptId
, pfunc
, IRQF_DISABLED
, devname
, (void *) param
);
245 else if (interruptId
>= INTERRUPT_ID_EXTERNAL_0
&& interruptId
<= INTERRUPT_ID_EXTERNAL_3
)
247 printk("BcmHalMapInterrupt : external IRQ\n");
248 nRet
= request_external_irq( interruptId
, pfunc
, IRQF_DISABLED
, devname
, (void *) param
);
255 EXPORT_SYMBOL(enable_brcm_irq
);
256 EXPORT_SYMBOL(disable_brcm_irq
);
257 EXPORT_SYMBOL(request_external_irq
);
258 EXPORT_SYMBOL(BcmHalMapInterrupt
);