1 #include <linux/errno.h>
2 #include <linux/init.h>
3 #include <linux/kernel_stat.h>
4 #include <linux/module.h>
5 #include <linux/signal.h>
6 #include <linux/sched.h>
7 #include <linux/types.h>
8 #include <linux/interrupt.h>
9 #include <linux/ioport.h>
10 #include <linux/timex.h>
11 #include <linux/slab.h>
12 #include <linux/random.h>
13 #include <linux/delay.h>
15 #include <asm/bitops.h>
16 #include <asm/bootinfo.h>
18 #include <asm/mipsregs.h>
19 #include <asm/system.h>
20 #include <asm/idt-boards/rc32434/rc32434.h>
21 #include <asm/idt-boards/rc32434/rc32434_gpio.h>
25 extern void aruba_timer_interrupt(struct pt_regs
*regs
);
29 volatile u32
*base_addr
;
32 static const intr_group_t intr_group_merlot
[NUM_INTR_GROUPS
] = {
33 {0x00000000, (u32
*) KSEG1ADDR(IC_GROUP0_PEND
+ 0)},
36 #define READ_PEND_MERLOT(base) (*((volatile unsigned long *)(0xbc003010)))
37 #define READ_MASK_MERLOT(base) (*((volatile unsigned long *)(0xbc003014)))
38 #define WRITE_MASK_MERLOT(base, val) ((*((volatile unsigned long *)(0xbc003014))) = (val), READ_MASK_MERLOT())
40 static const intr_group_t intr_group_muscat
[NUM_INTR_GROUPS
] = {
41 {0x0000efff, (u32
*) KSEG1ADDR(IC_GROUP0_PEND
+ 0 * IC_GROUP_OFFSET
)},
42 {0x00001fff, (u32
*) KSEG1ADDR(IC_GROUP0_PEND
+ 1 * IC_GROUP_OFFSET
)},
43 {0x00000007, (u32
*) KSEG1ADDR(IC_GROUP0_PEND
+ 2 * IC_GROUP_OFFSET
)},
44 {0x0003ffff, (u32
*) KSEG1ADDR(IC_GROUP0_PEND
+ 3 * IC_GROUP_OFFSET
)},
45 {0xffffffff, (u32
*) KSEG1ADDR(IC_GROUP0_PEND
+ 4 * IC_GROUP_OFFSET
)}
48 #define READ_PEND_MUSCAT(base) (*(base))
49 #define READ_MASK_MUSCAT(base) (*(base + 2))
50 #define WRITE_MASK_MUSCAT(base, val) (*(base + 2) = (val))
52 static inline int group_to_ip(unsigned int group
)
54 switch (mips_machtype
) {
64 static inline void enable_local_irq(unsigned int irq
)
66 clear_c0_cause(0x100 << irq
);
67 set_c0_status(0x100 << irq
);
71 static inline void disable_local_irq(unsigned int irq
)
73 clear_c0_status(0x100 << irq
);
74 clear_c0_cause(0x100 << irq
);
78 static inline void aruba_irq_enable(unsigned int irq
)
81 unsigned int group
, intr_bit
;
82 volatile unsigned int *addr
;
84 local_irq_save(flags
);
86 if (irq
< GROUP0_IRQ_BASE
) {
87 enable_local_irq(irq
);
89 int ip
= irq
- GROUP0_IRQ_BASE
;
90 switch (mips_machtype
) {
92 if (irq
>= GROUP4_IRQ_BASE
)
93 idt_gpio
->gpioistat
&= ~(1 << (irq
- GROUP4_IRQ_BASE
));
95 // irqs are in groups of 32
96 // ip is set to the remainder
102 addr
= intr_group_muscat
[group
].base_addr
;
103 WRITE_MASK_MUSCAT(addr
, READ_MASK_MUSCAT(addr
) & ~intr_bit
);
106 case MACH_ARUBA_AP65
:
107 case MACH_ARUBA_AP60
:
110 // bit -> 1 = unmasked
112 addr
= intr_group_merlot
[group
].base_addr
;
113 WRITE_MASK_MERLOT(addr
, READ_MASK_MERLOT(addr
) | intr_bit
);
116 enable_local_irq(group_to_ip(group
));
119 back_to_back_c0_hazard();
120 local_irq_restore(flags
);
123 static void aruba_irq_disable(unsigned int irq
)
126 unsigned int group
, intr_bit
, mask
;
127 volatile unsigned int *addr
;
129 local_irq_save(flags
);
131 if (irq
< GROUP0_IRQ_BASE
) {
132 disable_local_irq(irq
);
134 int ip
= irq
- GROUP0_IRQ_BASE
;
135 switch (mips_machtype
) {
136 case MACH_ARUBA_AP70
:
137 idt_gpio
->gpioistat
&= ~(1 << ip
);
139 // irqs are in groups of 32
140 // ip is set to the remainder
146 addr
= intr_group_muscat
[group
].base_addr
;
148 mask
= READ_MASK_MUSCAT(addr
);
150 WRITE_MASK_MUSCAT(addr
, mask
);
152 if (mask
== intr_group_muscat
[group
].mask
) {
153 disable_local_irq(group_to_ip(group
));
157 case MACH_ARUBA_AP65
:
158 case MACH_ARUBA_AP60
:
163 addr
= intr_group_merlot
[group
].base_addr
;
165 mask
= READ_MASK_MERLOT(addr
);
167 WRITE_MASK_MERLOT(addr
, mask
);
169 if (mask
== intr_group_merlot
[group
].mask
) {
170 disable_local_irq(group_to_ip(group
));
176 back_to_back_c0_hazard();
177 local_irq_restore(flags
);
180 static unsigned int aruba_irq_startup(unsigned int irq
)
182 aruba_irq_enable(irq
);
186 #define aruba_irq_shutdown aruba_irq_disable
188 static void aruba_irq_ack(unsigned int irq
)
190 aruba_irq_disable(irq
);
193 static void aruba_irq_end(unsigned int irq
)
195 if (!(irq_desc
[irq
].status
& (IRQ_DISABLED
| IRQ_INPROGRESS
)))
196 aruba_irq_enable(irq
);
199 static struct hw_interrupt_type aruba_irq_type
= {
201 .startup
= aruba_irq_startup
,
202 .shutdown
= aruba_irq_shutdown
,
203 .enable
= aruba_irq_enable
,
204 .disable
= aruba_irq_disable
,
205 .ack
= aruba_irq_ack
,
206 .end
= aruba_irq_end
,
209 void __init
arch_init_irq(void)
212 printk("Initializing IRQ's: %d out of %d\n", RC32434_NR_IRQS
, NR_IRQS
);
213 memset(irq_desc
, 0, sizeof(irq_desc
));
215 for (i
= 0; i
< RC32434_NR_IRQS
; i
++) {
216 irq_desc
[i
].status
= IRQ_DISABLED
;
217 irq_desc
[i
].action
= NULL
;
218 irq_desc
[i
].depth
= 1;
219 irq_desc
[i
].chip
= &aruba_irq_type
;
220 spin_lock_init(&irq_desc
[i
].lock
);
224 /* Main Interrupt dispatcher */
226 void plat_irq_dispatch(struct pt_regs
*regs
)
228 unsigned int pend
, group
, ip
;
229 volatile unsigned int *addr
;
230 unsigned long cp0_cause
= read_c0_cause() & read_c0_status() & CAUSEF_IP
;
232 if (cp0_cause
& CAUSEF_IP7
)
233 return aruba_timer_interrupt(regs
);
236 printk("INTERRUPT(S) FIRED WHILE MASKED\n");
238 // debuging use -- figure out which interrupt(s) fired
239 cp0_cause
= read_c0_cause() & CAUSEF_IP
;
241 unsigned long intr_bit
;
243 intr_bit
= (31 - rc32434_clz(cp0_cause
));
244 irq_nr
= intr_bit
- GROUP0_IRQ_BASE
;
245 printk(" ---> MASKED IRQ %d\n",irq_nr
);
246 cp0_cause
&= ~(1 << intr_bit
);
252 switch (mips_machtype
) {
253 case MACH_ARUBA_AP70
:
254 if ((ip
= (cp0_cause
& 0x7c00))) {
255 group
= 21 - rc32434_clz(ip
);
257 addr
= intr_group_muscat
[group
].base_addr
;
259 pend
= READ_PEND_MUSCAT(addr
);
260 pend
&= ~READ_MASK_MUSCAT(addr
); // only unmasked interrupts
261 pend
= 39 - rc32434_clz(pend
);
262 do_IRQ(pend
+ (group
<< 5));
265 case MACH_ARUBA_AP65
:
266 case MACH_ARUBA_AP60
:
268 if (cp0_cause
& 0x4000) { // 1 << (8 +6) == irq 6
272 addr
= intr_group_merlot
[group
].base_addr
;
274 pend
= READ_PEND_MERLOT(addr
);
275 pend
&= READ_MASK_MERLOT(addr
); // only unmasked interrupts
276 pend
= 31 - rc32434_clz(pend
);
277 do_IRQ(pend
+ GROUP0_IRQ_BASE
);
279 if ((ip
= (cp0_cause
& 0x3c00))) { // irq 2-5
280 pend
= 31 - rc32434_clz(ip
);
281 do_IRQ(pend
- GROUP0_IRQ_BASE
);