/* * Copyright (C) 2001 MontaVista Software Inc. * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net * * linux/arch/mips/vr4181/common/irq.c * Completely re-written to use the new irq.c * * Credits to Bradley D. LaRonde and Michael Klar for writing the original * irq.c file which was derived from the common irq.c file. * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * */ #include #include #include #include #include #include #include #include #include #include #include #include /* * Strategy: * * We essentially have three irq controllers, CPU, system, and gpio. * * CPU irq controller is taken care by arch/mips/kernel/irq_cpu.c and * CONFIG_IRQ_CPU config option. * * We here provide sys_irq and gpio_irq controller code. */ static int sys_irq_base; static int gpio_irq_base; /* ---------------------- sys irq ------------------------ */ static void sys_irq_enable(unsigned int irq) { irq -= sys_irq_base; if (irq < 16) { *VR4181_MSYSINT1REG |= (u16)(1 << irq); } else { irq -= 16; *VR4181_MSYSINT2REG |= (u16)(1 << irq); } } static void sys_irq_disable(unsigned int irq) { irq -= sys_irq_base; if (irq < 16) { *VR4181_MSYSINT1REG &= ~((u16)(1 << irq)); } else { irq -= 16; *VR4181_MSYSINT2REG &= ~((u16)(1 << irq)); } } static unsigned int sys_irq_startup(unsigned int irq) { sys_irq_enable(irq); return 0; } #define sys_irq_shutdown sys_irq_disable #define sys_irq_ack sys_irq_disable static void sys_irq_end(unsigned int irq) { if(!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) sys_irq_enable(irq); } static hw_irq_controller sys_irq_controller = { "vr4181_sys_irq", sys_irq_startup, sys_irq_shutdown, sys_irq_enable, sys_irq_disable, sys_irq_ack, sys_irq_end, NULL /* no affinity stuff for UP */ }; /* ---------------------- gpio irq ------------------------ */ /* gpio irq lines use reverse logic */ static void gpio_irq_enable(unsigned int irq) { irq -= gpio_irq_base; *VR4181_GPINTMSK &= ~((u16)(1 << irq)); } static void gpio_irq_disable(unsigned int irq) { irq -= gpio_irq_base; *VR4181_GPINTMSK |= (u16)(1 << irq); } static unsigned int gpio_irq_startup(unsigned int irq) { gpio_irq_enable(irq); irq -= gpio_irq_base; *VR4181_GPINTEN |= (u16)(1 << irq ); return 0; } static void gpio_irq_shutdown(unsigned int irq) { gpio_irq_disable(irq); irq -= gpio_irq_base; *VR4181_GPINTEN &= ~((u16)(1 << irq )); } static void gpio_irq_ack(unsigned int irq) { u16 irqtype; u16 irqshift; gpio_irq_disable(irq); /* we clear interrupt if it is edge triggered */ irq -= gpio_irq_base; if (irq < 8) { irqtype = *VR4181_GPINTTYPL; irqshift = 2 << (irq*2); } else { irqtype = *VR4181_GPINTTYPH; irqshift = 2 << ((irq-8)*2); } if ( ! (irqtype & irqshift) ) { *VR4181_GPINTSTAT = (u16) (1 << irq); } } static void gpio_irq_end(unsigned int irq) { if(!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) gpio_irq_enable(irq); } static hw_irq_controller gpio_irq_controller = { "vr4181_gpio_irq", gpio_irq_startup, gpio_irq_shutdown, gpio_irq_enable, gpio_irq_disable, gpio_irq_ack, gpio_irq_end, NULL /* no affinity stuff for UP */ }; /* --------------------- IRQ init stuff ---------------------- */ extern asmlinkage void vr4181_handle_irq(void); extern void breakpoint(void); extern int setup_irq(unsigned int irq, struct irqaction *irqaction); extern void mips_cpu_irq_init(u32 irq_base); static struct irqaction cascade = { no_action, SA_INTERRUPT, 0, "cascade", NULL, NULL }; static struct irqaction reserved = { no_action, SA_INTERRUPT, 0, "cascade", NULL, NULL }; void __init init_IRQ(void) { int i; extern irq_desc_t irq_desc[]; set_except_vector(0, vr4181_handle_irq); /* init CPU irqs */ mips_cpu_irq_init(VR4181_CPU_IRQ_BASE); /* init sys irqs */ sys_irq_base = VR4181_SYS_IRQ_BASE; for (i=sys_irq_base; i < sys_irq_base + VR4181_NUM_SYS_IRQ; i++) { irq_desc[i].status = IRQ_DISABLED; irq_desc[i].action = NULL; irq_desc[i].depth = 1; irq_desc[i].handler = &sys_irq_controller; } /* init gpio irqs */ gpio_irq_base = VR4181_GPIO_IRQ_BASE; for (i=gpio_irq_base; i < gpio_irq_base + VR4181_NUM_GPIO_IRQ; i++) { irq_desc[i].status = IRQ_DISABLED; irq_desc[i].action = NULL; irq_desc[i].depth = 1; irq_desc[i].handler = &gpio_irq_controller; } /* Default all ICU IRQs to off ... */ *VR4181_MSYSINT1REG = 0; *VR4181_MSYSINT2REG = 0; /* We initialize the level 2 ICU registers to all bits disabled. */ *VR4181_MPIUINTREG = 0; *VR4181_MAIUINTREG = 0; *VR4181_MKIUINTREG = 0; /* disable all GPIO intrs */ *VR4181_GPINTMSK = 0xffff; /* vector handler. What these do is register the IRQ as non-sharable */ setup_irq(VR4181_IRQ_INT0, &cascade); setup_irq(VR4181_IRQ_GIU, &cascade); /* * RTC interrupts are interesting. They have two destinations. * One is at sys irq controller, and the other is at CPU IP3 and IP4. * RTC timer is used as system timer. * We enable them here, but timer routine will register later * with CPU IP3/IP4. */ setup_irq(VR4181_IRQ_RTCL1, &reserved); setup_irq(VR4181_IRQ_RTCL2, &reserved); #ifdef CONFIG_REMOTE_DEBUG printk("Setting debug traps - please connect the remote debugger.\n"); set_debug_traps(); // you may move this line to whereever you want breakpoint(); #endif }