1 diff -Nur linux-2.6.17/arch/mips/aruba/irq.c linux-2.6.17-openwrt/arch/mips/aruba/irq.c
2 --- linux-2.6.17/arch/mips/aruba/irq.c 1970-01-01 01:00:00.000000000 +0100
3 +++ linux-2.6.17-openwrt/arch/mips/aruba/irq.c 2006-01-10 00:32:32.000000000 +0100
5 +/**************************************************************************
7 + * BRIEF MODULE DESCRIPTION
8 + * Interrupt routines for IDT EB434 boards / Atheros boards
9 + * Modified by Aruba Networks
11 + * Copyright 2004 IDT Inc. (rischelp@idt.com)
13 + * This program is free software; you can redistribute it and/or modify it
14 + * under the terms of the GNU General Public License as published by the
15 + * Free Software Foundation; either version 2 of the License, or (at your
16 + * option) any later version.
18 + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
19 + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20 + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
21 + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
24 + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25 + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 + * You should have received a copy of the GNU General Public License along
30 + * with this program; if not, write to the Free Software Foundation, Inc.,
31 + * 675 Mass Ave, Cambridge, MA 02139, USA.
34 + **************************************************************************
41 + **************************************************************************
44 +#include <linux/errno.h>
45 +#include <linux/init.h>
46 +#include <linux/kernel_stat.h>
47 +#include <linux/module.h>
48 +#include <linux/signal.h>
49 +#include <linux/sched.h>
50 +#include <linux/types.h>
51 +#include <linux/interrupt.h>
52 +#include <linux/ioport.h>
53 +#include <linux/timex.h>
54 +#include <linux/slab.h>
55 +#include <linux/random.h>
56 +#include <linux/delay.h>
58 +#include <asm/bitops.h>
59 +#include <asm/bootinfo.h>
61 +#include <asm/mipsregs.h>
62 +#include <asm/system.h>
63 +#include <asm/idt-boards/rc32434/rc32434.h>
64 +#include <asm/idt-boards/rc32434/rc32434_gpio.h>
70 +/* note: prints function name for you */
71 +#define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args)
73 +#define DPRINTK(fmt, args...)
76 +extern void aruba_timer_interrupt(struct pt_regs *regs);
77 +static unsigned int startup_irq(unsigned int irq);
78 +static void end_irq(unsigned int irq_nr);
79 +static void mask_and_ack_irq(unsigned int irq_nr);
80 +static void aruba_enable_irq(unsigned int irq_nr);
81 +static void aruba_disable_irq(unsigned int irq_nr);
83 +extern void __init init_generic_irq(void);
87 + volatile u32 *base_addr;
90 +static const intr_group_t intr_group_merlot[NUM_INTR_GROUPS] = {
91 + {0xffffffff, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 0)},
94 +#define READ_PEND_MERLOT(base) (*((volatile unsigned long *)(0xbc003010)))
95 +#define READ_MASK_MERLOT(base) (*((volatile unsigned long *)(0xbc003014)))
96 +#define WRITE_MASK_MERLOT(base, val) ((*((volatile unsigned long *)(0xbc003014))) = (val), READ_MASK_MERLOT())
98 +static const intr_group_t intr_group_muscat[NUM_INTR_GROUPS] = {
99 + {0x0000efff, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 0 * IC_GROUP_OFFSET)},
100 + {0x00001fff, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 1 * IC_GROUP_OFFSET)},
101 + {0x00000007, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 2 * IC_GROUP_OFFSET)},
102 + {0x0003ffff, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 3 * IC_GROUP_OFFSET)},
103 + {0xffffffff, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 4 * IC_GROUP_OFFSET)}
106 +#define READ_PEND_MUSCAT(base) (*(base))
107 +#define READ_MASK_MUSCAT(base) (*(base + 2))
108 +#define WRITE_MASK_MUSCAT(base, val) (*(base + 2) = (val))
110 +static inline int irq_to_group(unsigned int irq_nr)
112 + switch (mips_machtype) {
113 + case MACH_ARUBA_AP70:
114 + return ((irq_nr - GROUP0_IRQ_BASE) >> 5);
115 + case MACH_ARUBA_AP65:
116 + case MACH_ARUBA_AP60:
122 +static inline int group_to_ip(unsigned int group)
124 + switch (mips_machtype) {
125 + case MACH_ARUBA_AP70:
127 + case MACH_ARUBA_AP65:
128 + case MACH_ARUBA_AP60:
134 +static inline void enable_local_irq(unsigned int ip)
136 + set_c0_status(0x100 << ip);
137 + irq_enable_hazard();
140 +static inline void disable_local_irq(unsigned int ip)
142 + clear_c0_status(0x100 << ip);
143 + irq_disable_hazard();
146 +static void aruba_enable_irq(unsigned int irq_nr)
148 + unsigned long flags;
149 + int ip = irq_nr - GROUP0_IRQ_BASE;
150 + unsigned int group, intr_bit;
151 + volatile unsigned int *addr;
154 + local_irq_save(flags);
157 + enable_local_irq(irq_nr);
160 + switch (mips_machtype) {
161 + case MACH_ARUBA_AP70:
164 + case MACH_ARUBA_AP65:
165 + case MACH_ARUBA_AP60:
171 + // calc interrupt bit within group
172 + ip -= (group << 5);
173 + intr_bit = 1 << ip;
175 + switch (mips_machtype) {
176 + case MACH_ARUBA_AP70:
177 + addr = intr_group_muscat[group].base_addr;
178 + WRITE_MASK_MUSCAT(addr, READ_MASK_MUSCAT(addr) & ~intr_bit);
180 + case MACH_ARUBA_AP65:
181 + case MACH_ARUBA_AP60:
183 + addr = intr_group_merlot[group].base_addr;
184 + WRITE_MASK_MERLOT(addr, READ_MASK_MERLOT(addr) | intr_bit);
187 + enable_local_irq(group_to_ip(group));
190 + back_to_back_c0_hazard();
191 + local_irq_restore(flags);
195 +static void aruba_disable_irq(unsigned int irq_nr)
197 + unsigned long flags;
198 + int ip = irq_nr - GROUP0_IRQ_BASE;
199 + unsigned int group, intr_bit, mask;
200 + volatile unsigned int *addr;
202 + local_irq_save(flags);
205 + disable_local_irq(irq_nr);
208 + switch (mips_machtype) {
209 + case MACH_ARUBA_AP70:
212 + case MACH_ARUBA_AP65:
213 + case MACH_ARUBA_AP60:
219 + // calc interrupt bit within group
221 + intr_bit = 1 << ip;
223 + switch (mips_machtype) {
224 + case MACH_ARUBA_AP70:
225 + addr = intr_group_muscat[group].base_addr;
226 + // mask intr within group
227 + mask = READ_MASK_MUSCAT(addr);
229 + WRITE_MASK_MUSCAT(addr, mask);
232 + if there are no more interrupts enabled in this
233 + group, disable corresponding IP
235 + if (mask == intr_group_muscat[group].mask)
236 + disable_local_irq(group_to_ip(group));
238 + case MACH_ARUBA_AP65:
239 + case MACH_ARUBA_AP60:
241 + addr = intr_group_merlot[group].base_addr;
242 + // mask intr within group
243 + mask = READ_MASK_MERLOT(addr);
246 + disable_local_irq(group_to_ip(group));
247 + WRITE_MASK_MERLOT(addr, mask);
252 + back_to_back_c0_hazard();
253 + local_irq_restore(flags);
256 +static unsigned int startup_irq(unsigned int irq_nr)
258 + aruba_enable_irq(irq_nr);
262 +static void shutdown_irq(unsigned int irq_nr)
264 + aruba_disable_irq(irq_nr);
267 +static void mask_and_ack_irq(unsigned int irq_nr)
269 + aruba_disable_irq(irq_nr);
272 +static void end_irq(unsigned int irq_nr)
275 + int ip = irq_nr - GROUP0_IRQ_BASE;
276 + unsigned int intr_bit, group;
277 + volatile unsigned int *addr;
280 + if (irq_desc[irq_nr].status & (IRQ_DISABLED | IRQ_INPROGRESS)) {
281 + printk("warning: end_irq %d did not enable (%x)\n",
282 + irq_nr, irq_desc[irq_nr].status);
283 + /* fall through; enable the interrupt
284 + * -- It'll get stuck otherwise
290 + enable_local_irq(irq_nr);
293 + switch (mips_machtype) {
294 + case MACH_ARUBA_AP70:
295 + if (irq_nr == GROUP4_IRQ_BASE + 9) idt_gpio->gpioistat &= 0xfffffdff;
296 + else if (irq_nr == GROUP4_IRQ_BASE + 10) idt_gpio->gpioistat &= 0xfffffbff;
297 + else if (irq_nr == GROUP4_IRQ_BASE + 11) idt_gpio->gpioistat &= 0xfffff7ff;
298 + else if (irq_nr == GROUP4_IRQ_BASE + 12) idt_gpio->gpioistat &= 0xffffefff;
302 + // calc interrupt bit within group
303 + ip -= (group << 5);
304 + intr_bit = 1 << ip;
306 + // first enable the IP mapped to this IRQ
307 + enable_local_irq(group_to_ip(group));
309 + addr = intr_group_muscat[group].base_addr;
310 + // unmask intr within group
311 + WRITE_MASK_MUSCAT(addr, READ_MASK_MUSCAT(addr) & ~intr_bit);
314 + case MACH_ARUBA_AP65:
315 + case MACH_ARUBA_AP60:
319 + // calc interrupt bit within group
320 + intr_bit = 1 << ip;
322 + // first enable the IP mapped to this IRQ
323 + enable_local_irq(group_to_ip(group));
325 + addr = intr_group_merlot[group].base_addr;
326 + // unmask intr within group
327 + WRITE_MASK_MERLOT(addr, READ_MASK_MERLOT(addr) | intr_bit);
333 +static struct hw_interrupt_type aruba_irq_type = {
334 + .typename = "ARUBA",
335 + .startup = startup_irq,
336 + .shutdown = shutdown_irq,
337 + .enable = aruba_enable_irq,
338 + .disable = aruba_disable_irq,
339 + .ack = mask_and_ack_irq,
343 +void __init arch_init_irq(void)
346 + printk("Initializing IRQ's: %d out of %d\n", RC32434_NR_IRQS, NR_IRQS);
347 + memset(irq_desc, 0, sizeof(irq_desc));
349 + set_c0_status(0xFF00);
351 + for (i = 0; i < RC32434_NR_IRQS; i++) {
352 + irq_desc[i].status = IRQ_DISABLED;
353 + irq_desc[i].action = NULL;
354 + irq_desc[i].depth = 1;
355 + irq_desc[i].handler = &aruba_irq_type;
356 + spin_lock_init(&irq_desc[i].lock);
360 +/* Main Interrupt dispatcher */
362 +void plat_irq_dispatch(struct pt_regs *regs)
364 + unsigned int pend, group, ip;
365 + volatile unsigned int *addr;
366 + unsigned long cp0_cause = read_c0_cause() & read_c0_status() & CAUSEF_IP;
368 + if (cp0_cause & CAUSEF_IP7)
369 + return aruba_timer_interrupt(regs);
371 + if(cp0_cause == 0) {
372 + printk("INTERRUPT(S) FIRED WHILE MASKED\n");
374 + // debuging use -- figure out which interrupt(s) fired
375 + cp0_cause = read_c0_cause() & CAUSEF_IP;
376 + while (cp0_cause) {
377 + unsigned long intr_bit;
378 + unsigned int irq_nr;
379 + intr_bit = (31 - rc32434_clz(cp0_cause));
380 + irq_nr = intr_bit - GROUP0_IRQ_BASE;
381 + printk(" ---> MASKED IRQ %d\n",irq_nr);
382 + cp0_cause &= ~(1 << intr_bit);
388 + switch (mips_machtype) {
389 + case MACH_ARUBA_AP70:
390 + if ((ip = (cp0_cause & 0x7c00))) {
391 + group = 21 - rc32434_clz(ip);
393 + addr = intr_group_muscat[group].base_addr;
395 + pend = READ_PEND_MUSCAT(addr);
396 + pend &= ~READ_MASK_MUSCAT(addr); // only unmasked interrupts
397 + pend = 39 - rc32434_clz(pend);
398 + do_IRQ((group << 5) + pend, regs);
401 + case MACH_ARUBA_AP65:
402 + case MACH_ARUBA_AP60:
404 + if (cp0_cause & 0x4000) { // 1 << (8 +6) == irq 6
407 + addr = intr_group_merlot[group].base_addr;
408 + pend = READ_PEND_MERLOT(addr);
409 + pend &= READ_MASK_MERLOT(addr); // only unmasked interrupts
410 + /* handle one misc interrupt at a time */
413 + unsigned long intr_bit;
414 + unsigned int irq_nr;
416 + intr_bit = (31 - rc32434_clz(pend));
417 + irq_nr = intr_bit + GROUP0_IRQ_BASE;
419 + do_IRQ(irq_nr, regs);
420 + pend &= ~(1 << intr_bit);
422 + } else if (cp0_cause & 0x3c00) { // irq 2-5
425 + unsigned long intr_bit;
426 + unsigned int irq_nr;
428 + intr_bit = (31 - rc32434_clz(cp0_cause));
429 + irq_nr = intr_bit - GROUP0_IRQ_BASE;
431 + do_IRQ(irq_nr, regs);
432 + cp0_cause &= ~(1 << intr_bit);