diff -Nur linux-2.6.17/arch/mips/aruba/irq.c linux-2.6.17-openwrt/arch/mips/aruba/irq.c --- linux-2.6.17/arch/mips/aruba/irq.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.17-openwrt/arch/mips/aruba/irq.c 2006-10-12 14:32:40.026285000 -0700 @@ -0,0 +1,282 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +extern void aruba_timer_interrupt(struct pt_regs *regs); + +typedef struct { + u32 mask; + volatile u32 *base_addr; +} intr_group_t; + +static const intr_group_t intr_group_merlot[NUM_INTR_GROUPS] = { + {0x00000000, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 0)}, +}; + +#define READ_PEND_MERLOT(base) (*((volatile unsigned long *)(0xbc003010))) +#define READ_MASK_MERLOT(base) (*((volatile unsigned long *)(0xbc003014))) +#define WRITE_MASK_MERLOT(base, val) ((*((volatile unsigned long *)(0xbc003014))) = (val), READ_MASK_MERLOT()) + +static const intr_group_t intr_group_muscat[NUM_INTR_GROUPS] = { + {0x0000efff, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 0 * IC_GROUP_OFFSET)}, + {0x00001fff, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 1 * IC_GROUP_OFFSET)}, + {0x00000007, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 2 * IC_GROUP_OFFSET)}, + {0x0003ffff, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 3 * IC_GROUP_OFFSET)}, + {0xffffffff, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 4 * IC_GROUP_OFFSET)} +}; + +#define READ_PEND_MUSCAT(base) (*(base)) +#define READ_MASK_MUSCAT(base) (*(base + 2)) +#define WRITE_MASK_MUSCAT(base, val) (*(base + 2) = (val)) + +static inline int group_to_ip(unsigned int group) +{ + switch (mips_machtype) { + case MACH_ARUBA_AP70: + return group + 2; + case MACH_ARUBA_AP65: + case MACH_ARUBA_AP60: + default: + return 6; + } +} + +static inline void enable_local_irq(unsigned int irq) +{ + clear_c0_cause(0x100 << irq); + set_c0_status(0x100 << irq); + irq_enable_hazard(); +} + +static inline void disable_local_irq(unsigned int irq) +{ + clear_c0_status(0x100 << irq); + clear_c0_cause(0x100 << irq); + irq_disable_hazard(); +} + +static inline void aruba_irq_enable(unsigned int irq) +{ + unsigned long flags; + unsigned int group, intr_bit; + volatile unsigned int *addr; + + local_irq_save(flags); + + if (irq < GROUP0_IRQ_BASE) { + enable_local_irq(irq); + } else { + int ip = irq - GROUP0_IRQ_BASE; + switch (mips_machtype) { + case MACH_ARUBA_AP70: + // irqs are in groups of 32 + // ip is set to the remainder + group = ip >> 5; + ip &= 0x1f; + + // bit -> 0 = unmask + intr_bit = 1 << ip; + addr = intr_group_muscat[group].base_addr; + WRITE_MASK_MUSCAT(addr, READ_MASK_MUSCAT(addr) & ~intr_bit); + break; + + case MACH_ARUBA_AP65: + case MACH_ARUBA_AP60: + group = 0; + + // bit -> 1 = unmasked + intr_bit = 1 << ip; + addr = intr_group_merlot[group].base_addr; + WRITE_MASK_MERLOT(addr, READ_MASK_MERLOT(addr) | intr_bit); + break; + } + enable_local_irq(group_to_ip(group)); + } + + back_to_back_c0_hazard(); + local_irq_restore(flags); +} + +static void aruba_irq_disable(unsigned int irq) +{ + unsigned long flags; + unsigned int group, intr_bit, mask; + volatile unsigned int *addr; + + local_irq_save(flags); + + if (irq < GROUP0_IRQ_BASE) { + disable_local_irq(irq); + } else { + int ip = irq - GROUP0_IRQ_BASE; + switch (mips_machtype) { + case MACH_ARUBA_AP70: + idt_gpio->gpioistat &= ~(1 << ip); + + // irqs are in groups of 32 + // ip is set to the remainder + group = ip >> 5; + ip &= 0x1f; + + // bit -> 1 = mask + intr_bit = 1 << ip; + addr = intr_group_muscat[group].base_addr; + + mask = READ_MASK_MUSCAT(addr); + mask |= intr_bit; + WRITE_MASK_MUSCAT(addr, mask); + + if (mask == intr_group_muscat[group].mask) { + disable_local_irq(group_to_ip(group)); + } + break; + + case MACH_ARUBA_AP65: + case MACH_ARUBA_AP60: + group = 0; + + // bit -> 0 = masked + intr_bit = 1 << ip; + addr = intr_group_merlot[group].base_addr; + + mask = READ_MASK_MERLOT(addr); + mask &= ~intr_bit; + WRITE_MASK_MERLOT(addr, mask); + + if (mask == intr_group_merlot[group].mask) { + disable_local_irq(group_to_ip(group)); + } + break; + } + } + + back_to_back_c0_hazard(); + local_irq_restore(flags); +} + +static unsigned int aruba_irq_startup(unsigned int irq) +{ + aruba_irq_enable(irq); + return 0; +} + +#define aruba_irq_shutdown aruba_irq_disable + +static void aruba_irq_ack(unsigned int irq) +{ + aruba_irq_disable(irq); +} + +static void aruba_irq_end(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) + aruba_irq_enable(irq); +} + +static struct hw_interrupt_type aruba_irq_type = { + .typename = "ARUBA", + .startup = aruba_irq_startup, + .shutdown = aruba_irq_shutdown, + .enable = aruba_irq_enable, + .disable = aruba_irq_disable, + .ack = aruba_irq_ack, + .end = aruba_irq_end, +}; + +void __init arch_init_irq(void) +{ + int i; + printk("Initializing IRQ's: %d out of %d\n", RC32434_NR_IRQS, NR_IRQS); + memset(irq_desc, 0, sizeof(irq_desc)); + + for (i = 0; i < RC32434_NR_IRQS; i++) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = NULL; + irq_desc[i].depth = 1; + irq_desc[i].handler = &aruba_irq_type; + spin_lock_init(&irq_desc[i].lock); + } +} + +/* Main Interrupt dispatcher */ + +void plat_irq_dispatch(struct pt_regs *regs) +{ + unsigned int pend, group, ip; + volatile unsigned int *addr; + unsigned long cp0_cause = read_c0_cause() & read_c0_status() & CAUSEF_IP; + + if (cp0_cause & CAUSEF_IP7) + return aruba_timer_interrupt(regs); + + if(cp0_cause == 0) { + printk("INTERRUPT(S) FIRED WHILE MASKED\n"); +#ifdef ARUBA_DEBUG + // debuging use -- figure out which interrupt(s) fired + cp0_cause = read_c0_cause() & CAUSEF_IP; + while (cp0_cause) { + unsigned long intr_bit; + unsigned int irq_nr; + intr_bit = (31 - rc32434_clz(cp0_cause)); + irq_nr = intr_bit - GROUP0_IRQ_BASE; + printk(" ---> MASKED IRQ %d\n",irq_nr); + cp0_cause &= ~(1 << intr_bit); + } +#endif + return; + } + + switch (mips_machtype) { + case MACH_ARUBA_AP70: + if ((ip = (cp0_cause & 0x7c00))) { + group = 21 - rc32434_clz(ip); + + addr = intr_group_muscat[group].base_addr; + + pend = READ_PEND_MUSCAT(addr); + pend &= ~READ_MASK_MUSCAT(addr); // only unmasked interrupts + pend = 39 - rc32434_clz(pend); + do_IRQ(pend + (group << 5), regs); + } + break; + case MACH_ARUBA_AP65: + case MACH_ARUBA_AP60: + default: + if (cp0_cause & 0x4000) { // 1 << (8 +6) == irq 6 + // Misc Interrupt + group = 0; + + addr = intr_group_merlot[group].base_addr; + + pend = READ_PEND_MERLOT(addr); + pend &= READ_MASK_MERLOT(addr); // only unmasked interrupts + pend = 31 - rc32434_clz(pend); + do_IRQ(pend + GROUP0_IRQ_BASE, regs); + } + if ((ip = (cp0_cause & 0x3c00))) { // irq 2-5 + pend = 31 - rc32434_clz(ip); + do_IRQ(pend - GROUP0_IRQ_BASE, regs); + } + break; + } +}