/* * Gary Jennejohn (C) 2003 * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. * * Routines for generic manipulation of the interrupts found on the * AMAZON_SE boards. * * HISTORY * $Version $Date $Author $Comment * 2.0.0 27/04/07 Teh Kok How Use unified function calls and defines * between Danube and Amazon_SE. Benefits is, * of course, better code management. */ #include #include #include #include #include #include #include #include #include #if defined(CONFIG_AMAZON_S) #include #include #elif defined(CONFIG_AMAZON_SE) #include #include #elif defined(CONFIG_DANUBE) #include #include #else #error Platform Undefined!!! #endif #include #ifdef CONFIG_KGDB #include #endif #undef BSP_INTERRUPT_DEBUG_MSG // #define BSP_INTERRUPT_DEBUG_MSG #ifdef BSP_INTERRUPT_DEBUG_MSG #define BSP_INTERRUPT_DMSG(fmt,args...) printk(KERN_ERR "[%s %d]: " fmt, __FUNCTION__ , __LINE__, ##args) // #define BSP_INTERRUPT_DMSG(fmt,args...) prom_printf("[%s %d]: " fmt, __FUNCTION__ , __LINE__, ##args) #else #define BSP_INTERRUPT_DMSG(x...) #endif #ifdef CONFIG_DANUBE #define BSP_PLATFORM "DANUBE" #define BSP_ICU_IM0_IER DANUBE_ICU_IM0_IER #define BSP_ICU_IM1_IER DANUBE_ICU_IM1_IER #define BSP_ICU_IM2_IER DANUBE_ICU_IM2_IER #define BSP_ICU_IM3_IER DANUBE_ICU_IM3_IER #define BSP_ICU_IM4_IER DANUBE_ICU_IM4_IER #define BSP_ICU_IM0_IER_IR DANUBE_ICU_IM0_IER_IR #define BSP_ICU_IM1_IER_IR DANUBE_ICU_IM1_IER_IR #define BSP_ICU_IM2_IER_IR DANUBE_ICU_IM2_IER_IR #define BSP_ICU_IM3_IER_IR DANUBE_ICU_IM3_IER_IR #define BSP_ICU_IM4_IER_IR DANUBE_ICU_IM4_IER_IR #define BSP_ICU_IM0_ISR DANUBE_ICU_IM0_ISR #define BSP_ICU_IM1_ISR DANUBE_ICU_IM1_ISR #define BSP_ICU_IM2_ISR DANUBE_ICU_IM2_ISR #define BSP_ICU_IM3_ISR DANUBE_ICU_IM3_ISR #define BSP_ICU_IM4_ISR DANUBE_ICU_IM4_ISR #define BSP_ICU_IM0_ISR_IR DANUBE_ICU_IM0_ISR_IR #define BSP_ICU_IM1_ISR_IR DANUBE_ICU_IM1_ISR_IR #define BSP_ICU_IM2_ISR_IR DANUBE_ICU_IM2_ISR_IR #define BSP_ICU_IM3_ISR_IR DANUBE_ICU_IM3_ISR_IR #define BSP_ICU_IM4_ISR_IR DANUBE_ICU_IM4_ISR_IR #define BSP_ICU_IM0_IOSR DANUBE_ICU_IM0_IOSR #define BSP_ICU_IM1_IOSR DANUBE_ICU_IM1_IOSR #define BSP_ICU_IM2_IOSR DANUBE_ICU_IM2_IOSR #define BSP_ICU_IM3_IOSR DANUBE_ICU_IM3_IOSR #define BSP_ICU_IM4_IOSR DANUBE_ICU_IM4_IOSR #define BSP_ICU_IM0_IOSR DANUBE_ICU_IM0_IOSR #define BSP_ICU_IM1_IOSR DANUBE_ICU_IM1_IOSR #define BSP_ICU_IM2_IOSR DANUBE_ICU_IM2_IOSR #define BSP_ICU_IM3_IOSR DANUBE_ICU_IM3_IOSR #define BSP_ICU_IM4_IOSR DANUBE_ICU_IM4_IOSR #define BSP_ICU_IM_VEC DANUBE_ICU_IM_VEC #define BSP_ICU_IM0_VEC_MASK DANUBE_ICU_IM0_VEC_MASK #define BSP_ICU_IM1_VEC_MASK DANUBE_ICU_IM1_VEC_MASK #define BSP_ICU_IM2_VEC_MASK DANUBE_ICU_IM2_VEC_MASK #define BSP_ICU_IM3_VEC_MASK DANUBE_ICU_IM3_VEC_MASK #define BSP_ICU_IM4_VEC_MASK DANUBE_ICU_IM4_VEC_MASK #define BSP_EBU_PCC_ISTAT DANUBE_EBU_PCC_ISTAT #elif defined(CONFIG_AMAZON_SE) #define BSP_PLATFORM "AMAZON_SE" #define BSP_ICU_IM0_IER AMAZON_SE_ICU_IM0_IER #define BSP_ICU_IM1_IER AMAZON_SE_ICU_IM1_IER #define BSP_ICU_IM2_IER AMAZON_SE_ICU_IM2_IER #define BSP_ICU_IM3_IER AMAZON_SE_ICU_IM3_IER #define BSP_ICU_IM4_IER AMAZON_SE_ICU_IM4_IER #define BSP_ICU_IM0_IER_IR AMAZON_SE_ICU_IM0_IER_IR #define BSP_ICU_IM1_IER_IR AMAZON_SE_ICU_IM1_IER_IR #define BSP_ICU_IM2_IER_IR AMAZON_SE_ICU_IM2_IER_IR #define BSP_ICU_IM3_IER_IR AMAZON_SE_ICU_IM3_IER_IR #define BSP_ICU_IM4_IER_IR AMAZON_SE_ICU_IM4_IER_IR #define BSP_ICU_IM0_ISR AMAZON_SE_ICU_IM0_ISR #define BSP_ICU_IM1_ISR AMAZON_SE_ICU_IM1_ISR #define BSP_ICU_IM2_ISR AMAZON_SE_ICU_IM2_ISR #define BSP_ICU_IM3_ISR AMAZON_SE_ICU_IM3_ISR #define BSP_ICU_IM4_ISR AMAZON_SE_ICU_IM4_ISR #define BSP_ICU_IM0_ISR_IR AMAZON_SE_ICU_IM0_ISR_IR #define BSP_ICU_IM1_ISR_IR AMAZON_SE_ICU_IM1_ISR_IR #define BSP_ICU_IM2_ISR_IR AMAZON_SE_ICU_IM2_ISR_IR #define BSP_ICU_IM3_ISR_IR AMAZON_SE_ICU_IM3_ISR_IR #define BSP_ICU_IM4_ISR_IR AMAZON_SE_ICU_IM4_ISR_IR #define BSP_ICU_IM0_IOSR AMAZON_SE_ICU_IM0_IOSR #define BSP_ICU_IM1_IOSR AMAZON_SE_ICU_IM1_IOSR #define BSP_ICU_IM2_IOSR AMAZON_SE_ICU_IM2_IOSR #define BSP_ICU_IM3_IOSR AMAZON_SE_ICU_IM3_IOSR #define BSP_ICU_IM4_IOSR AMAZON_SE_ICU_IM4_IOSR #define BSP_ICU_IM0_IOSR AMAZON_SE_ICU_IM0_IOSR #define BSP_ICU_IM1_IOSR AMAZON_SE_ICU_IM1_IOSR #define BSP_ICU_IM2_IOSR AMAZON_SE_ICU_IM2_IOSR #define BSP_ICU_IM3_IOSR AMAZON_SE_ICU_IM3_IOSR #define BSP_ICU_IM4_IOSR AMAZON_SE_ICU_IM4_IOSR #define BSP_ICU_IM_VEC AMAZON_SE_ICU_IM_VEC #define BSP_ICU_IM0_VEC_MASK AMAZON_SE_ICU_IM0_VEC_MASK #define BSP_ICU_IM1_VEC_MASK AMAZON_SE_ICU_IM1_VEC_MASK #define BSP_ICU_IM2_VEC_MASK AMAZON_SE_ICU_IM2_VEC_MASK #define BSP_ICU_IM3_VEC_MASK AMAZON_SE_ICU_IM3_VEC_MASK #define BSP_ICU_IM4_VEC_MASK AMAZON_SE_ICU_IM4_VEC_MASK #define BSP_EBU_PCC_ISTAT AMAZON_SE_EBU_PCC_ISTAT #elif defined(CONFIG_AMAZON_S) #define BSP_PLATFORM "AMAZON_S" #define BSP_ICU_IM0_IER AMAZON_S_ICU_IM0_IER #define BSP_ICU_IM1_IER AMAZON_S_ICU_IM1_IER #define BSP_ICU_IM2_IER AMAZON_S_ICU_IM2_IER #define BSP_ICU_IM3_IER AMAZON_S_ICU_IM3_IER #define BSP_ICU_IM4_IER AMAZON_S_ICU_IM4_IER #define BSP_ICU_IM0_IER_IR AMAZON_S_ICU_IM0_IER_IR #define BSP_ICU_IM1_IER_IR AMAZON_S_ICU_IM1_IER_IR #define BSP_ICU_IM2_IER_IR AMAZON_S_ICU_IM2_IER_IR #define BSP_ICU_IM3_IER_IR AMAZON_S_ICU_IM3_IER_IR #define BSP_ICU_IM4_IER_IR AMAZON_S_ICU_IM4_IER_IR #define BSP_ICU_IM0_ISR AMAZON_S_ICU_IM0_ISR #define BSP_ICU_IM1_ISR AMAZON_S_ICU_IM1_ISR #define BSP_ICU_IM2_ISR AMAZON_S_ICU_IM2_ISR #define BSP_ICU_IM3_ISR AMAZON_S_ICU_IM3_ISR #define BSP_ICU_IM4_ISR AMAZON_S_ICU_IM4_ISR #define BSP_ICU_IM0_ISR_IR AMAZON_S_ICU_IM0_ISR_IR #define BSP_ICU_IM1_ISR_IR AMAZON_S_ICU_IM1_ISR_IR #define BSP_ICU_IM2_ISR_IR AMAZON_S_ICU_IM2_ISR_IR #define BSP_ICU_IM3_ISR_IR AMAZON_S_ICU_IM3_ISR_IR #define BSP_ICU_IM4_ISR_IR AMAZON_S_ICU_IM4_ISR_IR #define BSP_ICU_IM0_IOSR AMAZON_S_ICU_IM0_IOSR #define BSP_ICU_IM1_IOSR AMAZON_S_ICU_IM1_IOSR #define BSP_ICU_IM2_IOSR AMAZON_S_ICU_IM2_IOSR #define BSP_ICU_IM3_IOSR AMAZON_S_ICU_IM3_IOSR #define BSP_ICU_IM4_IOSR AMAZON_S_ICU_IM4_IOSR #define BSP_ICU_IM_VEC AMAZON_S_ICU_IM_VEC #define BSP_ICU_IM0_VEC_MASK AMAZON_S_ICU_IM0_VEC_MASK #define BSP_ICU_IM1_VEC_MASK AMAZON_S_ICU_IM1_VEC_MASK #define BSP_ICU_IM2_VEC_MASK AMAZON_S_ICU_IM2_VEC_MASK #define BSP_ICU_IM3_VEC_MASK AMAZON_S_ICU_IM3_VEC_MASK #define BSP_ICU_IM4_VEC_MASK AMAZON_S_ICU_IM4_VEC_MASK #define BSP_EBU_PCC_ISTAT AMAZON_S_EBU_PCC_ISTAT #endif u32 hardware_irq_count[NR_CPUS][6]; int bsp_get_irq_status(u32 irq_nr) { if (irq_nr <= INT_NUM_IM0_IRL31 && irq_nr >= INT_NUM_IM0_IRL0) return *BSP_ICU_IM0_ISR & BSP_ICU_IM0_ISR_IR(irq_nr); else if (irq_nr <= INT_NUM_IM1_IRL31 && irq_nr >= INT_NUM_IM1_IRL0) return *BSP_ICU_IM1_ISR & BSP_ICU_IM1_ISR_IR(irq_nr - 32); else if (irq_nr <= INT_NUM_IM2_IRL31 && irq_nr >= INT_NUM_IM2_IRL0) return *BSP_ICU_IM2_ISR & BSP_ICU_IM2_ISR_IR(irq_nr - 64); else if (irq_nr <= INT_NUM_IM3_IRL31 && irq_nr >= INT_NUM_IM3_IRL0) return *BSP_ICU_IM3_ISR & BSP_ICU_IM3_ISR_IR(irq_nr - 96); else if (irq_nr <= INT_NUM_IM4_IRL31 && irq_nr >= INT_NUM_IM4_IRL0) return *BSP_ICU_IM4_ISR & BSP_ICU_IM4_ISR_IR(irq_nr - 128); return 0; } int bsp_get_irq_ier(u32 irq_nr) { if (irq_nr <= INT_NUM_IM0_IRL31 && irq_nr >= INT_NUM_IM0_IRL0) return *BSP_ICU_IM0_IER & BSP_ICU_IM0_IER_IR(irq_nr); else if (irq_nr <= INT_NUM_IM1_IRL31 && irq_nr >= INT_NUM_IM1_IRL0) return *BSP_ICU_IM1_IER & BSP_ICU_IM1_IER_IR(irq_nr - 32); else if (irq_nr <= INT_NUM_IM2_IRL31 && irq_nr >= INT_NUM_IM2_IRL0) return *BSP_ICU_IM2_IER & BSP_ICU_IM2_IER_IR(irq_nr - 64); else if (irq_nr <= INT_NUM_IM3_IRL31 && irq_nr >= INT_NUM_IM3_IRL0) return *BSP_ICU_IM3_IER & BSP_ICU_IM3_IER_IR(irq_nr - 96); else if (irq_nr <= INT_NUM_IM4_IRL31 && irq_nr >= INT_NUM_IM4_IRL0) return *BSP_ICU_IM4_IER & BSP_ICU_IM4_IER_IR(irq_nr - 128); return 0; } void bsp_disable_irq(unsigned int irq_nr) { if(irq_nr != 1) BSP_INTERRUPT_DMSG("disable:irq: %d\n", irq_nr); /* have to access the correct register here */ if (irq_nr <= INT_NUM_IM0_IRL31 && irq_nr >= INT_NUM_IM0_IRL0) /* access IM0 */ *BSP_ICU_IM0_IER &= (~BSP_ICU_IM0_IER_IR(irq_nr)); else if (irq_nr <= INT_NUM_IM1_IRL31 && irq_nr >= INT_NUM_IM1_IRL0) /* access IM1 */ *BSP_ICU_IM1_IER &= (~BSP_ICU_IM1_IER_IR(irq_nr - 32)); else if (irq_nr <= INT_NUM_IM2_IRL31 && irq_nr >= INT_NUM_IM2_IRL0) /* access IM2 */ *BSP_ICU_IM2_IER &= (~BSP_ICU_IM2_IER_IR(irq_nr - 64)); else if (irq_nr <= INT_NUM_IM3_IRL31 && irq_nr >= INT_NUM_IM3_IRL0) /* access IM3 */ *BSP_ICU_IM3_IER &= (~BSP_ICU_IM3_IER_IR((irq_nr - 96))); else if (irq_nr <= INT_NUM_IM4_IRL31 && irq_nr >= INT_NUM_IM4_IRL0) /* access IM4 */ *BSP_ICU_IM4_IER &= (~BSP_ICU_IM4_IER_IR((irq_nr - 128))); } void bsp_mask_and_ack_irq(unsigned int irq_nr) { if(irq_nr != 1) BSP_INTERRUPT_DMSG("mask+ack:irq: %d\n", irq_nr); /* have to access the correct register here */ if (irq_nr <= INT_NUM_IM0_IRL31 && irq_nr >= INT_NUM_IM0_IRL0) { /* access IM0 */ /* mask */ *BSP_ICU_IM0_IER &= ~BSP_ICU_IM0_IER_IR(irq_nr); /* ack */ *BSP_ICU_IM0_ISR = BSP_ICU_IM0_ISR_IR(irq_nr); } else if (irq_nr <= INT_NUM_IM1_IRL31 && irq_nr >= INT_NUM_IM1_IRL0) { /* access IM1 */ /* mask */ *BSP_ICU_IM1_IER &= ~BSP_ICU_IM1_IER_IR(irq_nr - 32); /* ack */ *BSP_ICU_IM1_ISR = BSP_ICU_IM1_ISR_IR(irq_nr - 32); } else if (irq_nr <= INT_NUM_IM2_IRL31 && irq_nr >= INT_NUM_IM2_IRL0) { /* access IM2 */ /* mask */ *BSP_ICU_IM2_IER &= ~BSP_ICU_IM2_IER_IR(irq_nr - 64); /* ack */ *BSP_ICU_IM2_ISR = BSP_ICU_IM2_ISR_IR(irq_nr - 64); } else if (irq_nr <= INT_NUM_IM3_IRL31 && irq_nr >= INT_NUM_IM3_IRL0) { /* access IM3 */ /* mask */ *BSP_ICU_IM3_IER &= ~BSP_ICU_IM3_IER_IR(irq_nr - 96); /* ack */ *BSP_ICU_IM3_ISR = BSP_ICU_IM3_ISR_IR(irq_nr - 96); } else if (irq_nr <= INT_NUM_IM4_IRL31 && irq_nr >= INT_NUM_IM4_IRL0) { /* access IM4 */ /* mask */ *BSP_ICU_IM4_IER &= ~BSP_ICU_IM4_IER_IR(irq_nr - 128); /* ack */ *BSP_ICU_IM4_ISR = BSP_ICU_IM4_ISR_IR(irq_nr - 128); } } void bsp_mask_irq(unsigned int irq_nr) { if(irq_nr != 1) BSP_INTERRUPT_DMSG("mask:irq: %d\n", irq_nr); /* have to access the correct register here */ if (irq_nr <= INT_NUM_IM0_IRL31 && irq_nr >= INT_NUM_IM0_IRL0) { /* access IM0 */ /* mask */ *BSP_ICU_IM0_IER &= ~BSP_ICU_IM0_IER_IR(irq_nr); } else if (irq_nr <= INT_NUM_IM1_IRL31 && irq_nr >= INT_NUM_IM1_IRL0) { /* access IM1 */ /* mask */ *BSP_ICU_IM1_IER &= ~BSP_ICU_IM1_IER_IR(irq_nr - 32); } else if (irq_nr <= INT_NUM_IM2_IRL31 && irq_nr >= INT_NUM_IM2_IRL0) { /* access IM2 */ /* mask */ *BSP_ICU_IM2_IER &= ~BSP_ICU_IM2_IER_IR(irq_nr - 64); } else if (irq_nr <= INT_NUM_IM3_IRL31 && irq_nr >= INT_NUM_IM3_IRL0) { /* access IM3 */ /* mask */ *BSP_ICU_IM3_IER &= ~BSP_ICU_IM3_IER_IR(irq_nr - 96); } else if (irq_nr <= INT_NUM_IM4_IRL31 && irq_nr >= INT_NUM_IM4_IRL0) { /* access IM4 */ /* mask */ *BSP_ICU_IM4_IER &= ~BSP_ICU_IM4_IER_IR(irq_nr - 128); } } void bsp_ack_irq(unsigned int irq_nr) { if(irq_nr != 1) BSP_INTERRUPT_DMSG("ack:irq: %d\n", irq_nr); /* have to access the correct register here */ if (irq_nr <= INT_NUM_IM0_IRL31 && irq_nr >= INT_NUM_IM0_IRL0) { /* access IM0 */ /* ack */ *BSP_ICU_IM0_ISR = BSP_ICU_IM0_ISR_IR(irq_nr); } else if (irq_nr <= INT_NUM_IM1_IRL31 && irq_nr >= INT_NUM_IM1_IRL0) { /* access IM1 */ /* ack */ *BSP_ICU_IM1_ISR = BSP_ICU_IM1_ISR_IR(irq_nr - 32); } else if (irq_nr <= INT_NUM_IM2_IRL31 && irq_nr >= INT_NUM_IM2_IRL0) { /* access IM2 */ /* ack */ *BSP_ICU_IM2_ISR = BSP_ICU_IM2_ISR_IR(irq_nr - 64); } else if (irq_nr <= INT_NUM_IM3_IRL31 && irq_nr >= INT_NUM_IM3_IRL0) { /* access IM3 */ /* ack */ *BSP_ICU_IM3_ISR = BSP_ICU_IM3_ISR_IR(irq_nr - 96); } else if (irq_nr <= INT_NUM_IM4_IRL31 && irq_nr >= INT_NUM_IM4_IRL0) { /* access IM4 */ /* ack */ *BSP_ICU_IM4_ISR = BSP_ICU_IM4_ISR_IR(irq_nr - 128); } } void bsp_enable_irq(unsigned int irq_nr) { if(irq_nr != 1) BSP_INTERRUPT_DMSG("enable:irq: %d\n", irq_nr); /* have to access the correct register here */ if (irq_nr <= INT_NUM_IM0_IRL31 && irq_nr >= INT_NUM_IM0_IRL0) /* access IM0 */ *BSP_ICU_IM0_IER |= BSP_ICU_IM0_IER_IR(irq_nr); else if (irq_nr <= INT_NUM_IM1_IRL31 && irq_nr >= INT_NUM_IM1_IRL0) /* access IM1 */ *BSP_ICU_IM1_IER |= BSP_ICU_IM1_IER_IR(irq_nr - 32); else if (irq_nr <= INT_NUM_IM2_IRL31 && irq_nr >= INT_NUM_IM2_IRL0) /* access IM2 */ *BSP_ICU_IM2_IER |= BSP_ICU_IM2_IER_IR(irq_nr - 64); else if (irq_nr <= INT_NUM_IM3_IRL31 && irq_nr >= INT_NUM_IM3_IRL0) /* access IM3 */ *BSP_ICU_IM3_IER |= BSP_ICU_IM3_IER_IR((irq_nr - 96)); else if (irq_nr <= INT_NUM_IM4_IRL31 && irq_nr >= INT_NUM_IM4_IRL0) /* access IM4 */ *BSP_ICU_IM4_IER |= BSP_ICU_IM4_IER_IR((irq_nr - 128)); } #if 0 static unsigned int bsp_startup_irq(unsigned int irq) { bsp_enable_irq(irq); return 0; /* never anything pending */ } #endif static void bsp_end_irq(unsigned int irq_nr) { if (irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS)) { if(irq_nr != 1) BSP_INTERRUPT_DMSG("disabled/inprogress:irq: %d\n", irq_nr); return; } if(irq_nr != 1) BSP_INTERRUPT_DMSG("end:irq: %d\n", irq_nr); /* have to access the correct register here */ if (irq_nr <= INT_NUM_IM0_IRL31 && irq_nr >= INT_NUM_IM0_IRL0) { /* access IM0 */ *BSP_ICU_IM0_IER |= BSP_ICU_IM0_IER_IR(irq_nr); set_c0_status(IE_IRQ0); } else if (irq_nr <= INT_NUM_IM1_IRL31 && irq_nr >= INT_NUM_IM1_IRL0) { /* access IM1 */ *BSP_ICU_IM1_IER |= BSP_ICU_IM1_IER_IR(irq_nr - 32); set_c0_status(IE_IRQ1); } else if (irq_nr <= INT_NUM_IM2_IRL31 && irq_nr >= INT_NUM_IM2_IRL0) { /* access IM2 */ *BSP_ICU_IM2_IER |= BSP_ICU_IM2_IER_IR(irq_nr - 64); set_c0_status(IE_IRQ2); } else if (irq_nr <= INT_NUM_IM3_IRL31 && irq_nr >= INT_NUM_IM3_IRL0){ /* access IM3 */ *BSP_ICU_IM3_IER |= BSP_ICU_IM3_IER_IR((irq_nr - 96)); set_c0_status(IE_IRQ3); } else if (irq_nr <= INT_NUM_IM4_IRL31 && irq_nr >= INT_NUM_IM4_IRL0) { /* access IM4 */ *BSP_ICU_IM4_IER |= BSP_ICU_IM4_IER_IR((irq_nr - 128)); set_c0_status(IE_IRQ4); } } //static unsigned int startup_none(unsigned int irq) { return 0; } static void enable_none(unsigned int irq) { } static void disable_none(unsigned int irq) { } static void ack_none(unsigned int irq) { } static void end_timer_irq(unsigned int irq) { set_c0_status(IE_IRQ5); } /* Set up bus error handling */ #if 0 static irqreturn_t bcu_error_handler(int irq, void *dev_id); #endif void prom_printf(const char * fmt, ...); /* startup is the same as "enable", shutdown is same as "disable" */ #define shutdown_none disable_none #define end_none enable_none struct irq_chip bsp_timer_irq_type = { .typename = "TIMER", .ack = ack_none, .mask = disable_none, .mask_ack = disable_none, .unmask = enable_none, .eoi = end_timer_irq, }; static struct irq_chip bsp_irq_type = { .typename = BSP_PLATFORM, .ack = bsp_ack_irq, .mask = bsp_mask_irq, .mask_ack = bsp_mask_and_ack_irq, .unmask = bsp_enable_irq, .eoi = bsp_end_irq, #ifdef CONFIG_MIPS_MT_SMTC_IRQAFF .set_affinity = plat_set_irq_affinity, #endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */ }; /* Set up bus error handling */ #if 0 static struct irqaction master_bcu = { .handler = bcu_error_handler, .flags = IRQF_DISABLED, .name = "master_bcu", .dev_id = "master_bcu", }; static struct irqaction slave_bcu = { .handler = bcu_error_handler, .flags = IRQF_DISABLED, .name = "slave_bcu", .dev_id = "slave_bcu", }; #endif #undef IVEC_BUG_FIX //#define IVEC_BUG_FIX /** * Find least significant bit. * This function searches for the least significant bit in 32bit value. * * \param x - The value to be checked. * \return Position of the least significant bit (0..31) */ static inline int clz(unsigned long x) { __asm__ ( " .set push \n" " .set mips32 \n" " clz %0, %1 \n" " .set pop \n" : "=r" (x) : "r" (x)); return 31 - x; } /*--- #define NESTED_IRQ ---*/ /* Cascaded interrupts from IM0 */ void hw0_irqdispatch(void) { #ifdef NESTED_IRQ unsigned long flags; #endif u32 irq; int cpu = smp_processor_id(); #ifdef NESTED_IRQ local_save_flags(flags); clear_c0_status(IE_SW0|IE_SW1|IE_IRQ0); local_irq_enable(); #endif #ifdef IVEC_BUG_FIX irq = (*BSP_ICU_IM0_IOSR); /* if int_status == 0, then the interrupt has already been cleared */ if (irq == 0) return; irq = clz(irq); #else irq = (*BSP_ICU_IM_VEC) & BSP_ICU_IM0_VEC_MASK; if (irq == 0) return; irq--; #endif /*IVEC_BUG_FIX*/ if (irq == 22){ /*clear EBU interrupt */ *(BSP_EBU_PCC_ISTAT) |= 0x10; } if(irq != 1) BSP_INTERRUPT_DMSG("irq: %d\n", irq); hardware_irq_count[cpu][0]++; do_IRQ((int)irq); #ifdef NESTED_IRQ local_irq_restore(flags); #else set_c0_status(IE_IRQ0); #endif return; } /* Cascaded interrupts from IM1 */ void hw1_irqdispatch(void) { #ifdef NESTED_IRQ unsigned long flags; #endif u32 irq; int cpu = smp_processor_id(); #ifdef NESTED_IRQ local_save_flags(flags); clear_c0_status(IE_SW0|IE_SW1|IE_IRQ0|IE_IRQ1); local_irq_enable(); #endif #ifdef IVEC_BUG_FIX irq = (*BSP_ICU_IM1_IOSR); /* if int_status == 0, then the interrupt has already been cleared */ if (irq == 0) return; irq = clz(irq)+32; #else irq = ((*BSP_ICU_IM_VEC) & BSP_ICU_IM1_VEC_MASK) >>6; if (irq == 0) return; irq+=31; #endif /*IVEC_BUG_FIX*/ BSP_INTERRUPT_DMSG("irq: %d\n", irq); hardware_irq_count[cpu][1]++; do_IRQ((int)irq); #ifdef NESTED_IRQ local_irq_restore(flags); #else set_c0_status(IE_IRQ1); #endif return; } /* Cascaded interrupts from IM2 */ void hw2_irqdispatch(void) { #ifdef NESTED_IRQ unsigned long flags; #endif u32 irq; int cpu = smp_processor_id(); #ifdef NESTED_IRQ local_save_flags(flags); clear_c0_status(IE_SW0|IE_SW1|IE_IRQ0|IE_IRQ1|IE_IRQ2); local_irq_enable(); #endif #ifdef IVEC_BUG_FIX irq = (*BSP_ICU_IM2_IOSR); /* if int_status == 0, then the interrupt has already been cleared */ if (irq == 0) return; irq = clz(irq)+64; #else irq = ((*BSP_ICU_IM_VEC) & BSP_ICU_IM2_VEC_MASK) >>12; if (irq == 0) return; irq += 63; #endif /*IVEC_BUG_FIX*/ BSP_INTERRUPT_DMSG("irq: %d\n", irq); hardware_irq_count[cpu][2]++; do_IRQ((int)irq); #ifdef NESTED_IRQ local_irq_restore(flags); #else set_c0_status(IE_IRQ2); #endif return; } /* Cascaded interrupts from IM3 */ void hw3_irqdispatch(void) { #ifdef NESTED_IRQ unsigned long flags; #endif u32 irq; int cpu = smp_processor_id(); #ifdef NESTED_IRQ local_save_flags(flags); clear_c0_status(IE_SW0|IE_SW1|IE_IRQ0|IE_IRQ1|IE_IRQ2|IE_IRQ3); local_irq_enable(); #endif #ifdef IVEC_BUG_FIX irq = (*BSP_ICU_IM3_IOSR); /* if int_status == 0, then the interrupt has already been cleared */ if (irq == 0) return; irq = clz(irq)+96; #else irq = ((*BSP_ICU_IM_VEC) & BSP_ICU_IM3_VEC_MASK) >>18; if (irq ==0) return; irq += 95; #endif /*IVEC_BUG_FIX*/ BSP_INTERRUPT_DMSG("irq: %d\n", irq); hardware_irq_count[cpu][3]++; do_IRQ((int)irq); #ifdef NESTED_IRQ local_irq_restore(flags); #else set_c0_status(IE_IRQ3); #endif return; } /* Cascaded interrupts from IM4 */ void hw4_irqdispatch(void) { #ifdef NESTED_IRQ unsigned long flags; #endif u32 irq; int cpu = smp_processor_id(); #ifdef NESTED_IRQ local_save_flags(flags); clear_c0_status(IE_SW0|IE_SW1|IE_IRQ0|IE_IRQ1|IE_IRQ2|IE_IRQ3|IE_IRQ4); local_irq_enable(); #endif #ifdef IVEC_BUG_FIX irq = (*BSP_ICU_IM4_IOSR); /* if int_status == 0, then the interrupt has already been cleared */ if (irq == 0) return; irq = clz(irq)+128; #else irq = ((*BSP_ICU_IM_VEC) & BSP_ICU_IM4_VEC_MASK) >> 24; if (irq == 0) return; irq += 127; #endif /*IVEC_BUG_FIX*/ BSP_INTERRUPT_DMSG("irq: %d\n", irq); hardware_irq_count[cpu][4]++; do_IRQ((int)irq); #ifdef NESTED_IRQ local_irq_restore(flags); #else set_c0_status(IE_IRQ4); #endif return; } /* Cascaded interrupts from IM5 */ void hw5_irqdispatch (void) { #ifdef NESTED_IRQ unsigned long flags; #endif int cpu = smp_processor_id(); #ifdef NESTED_IRQ local_save_flags(flags); clear_c0_status(IE_SW0|IE_SW1|IE_IRQ0|IE_IRQ1|IE_IRQ2|IE_IRQ3|IE_IRQ4|IE_IRQ5); local_irq_enable(); #endif //BSP_INTERRUPT_DMSG("irq: MIPS_CPU_TIMER_IRQ\n"); hardware_irq_count[cpu][5]++; do_IRQ(MIPS_CPU_TIMER_IRQ); #ifdef NESTED_IRQ local_irq_restore(flags); #endif return; } typedef struct { volatile u32 bcu_econ; volatile u32 bcu_eadd; volatile u32 bcu_edata; } bcu_error_reg_t; typedef struct { volatile u32 bcu_irnen; volatile u32 bcu_irnicr; volatile u32 bcu_irncr; } bcu_ir_reg_t; #if 0 // Danube bus error handling volatile bcu_error_reg_t *master_bcu_error_reg = (volatile bcu_error_reg_t *)DANUBE_BCU_ECON; volatile bcu_error_reg_t *slave_bcu_error_reg = (volatile bcu_error_reg_t *)DANUBE_SLAVE_BCU_ECON; volatile bcu_ir_reg_t *master_bcu_ir_reg = (volatile bcu_ir_reg_t *)DANUBE_BCU_IRNEN; volatile bcu_ir_reg_t *slave_bcu_ir_reg = (volatile bcu_ir_reg_t *)DANUBE_SLAVE_BCU_IRNEN; /* Set up bus error handling */ static irqreturn_t bcu_error_handler(int irq, void *dev_id) { u32 econ, eaddr, edata; struct pt_regs *regs = get_irq_regs(); if (irq == DANUBE_FPI_MASTER_BCU_IRQ) { if (master_bcu_ir_reg->bcu_irncr & 1) { econ = master_bcu_error_reg->bcu_econ; eaddr = master_bcu_error_reg->bcu_eadd; edata = master_bcu_error_reg->bcu_edata; master_bcu_ir_reg->bcu_irncr |= 1; } else return IRQ_NONE; } else if (irq == DANUBE_FPI_SLAVE_BCU_IRQ) { if (slave_bcu_ir_reg->bcu_irncr & 1) { econ = slave_bcu_error_reg->bcu_econ; eaddr = slave_bcu_error_reg->bcu_eadd; edata = slave_bcu_error_reg->bcu_edata; slave_bcu_ir_reg->bcu_irncr |= 1; } else return IRQ_NONE; } else return IRQ_NONE; printk(KERN_ERR "%s irq%d:\n", (const char*)dev_id, irq); printk(KERN_ERR "DANUBE_BCU_ECON %#x:\n", econ); printk(KERN_ERR "\tBus Operation Code: %#x\n", (econ >> 28) & 0xF); printk(KERN_ERR "\tBus TAG: %#x\n", (econ >> 24) & 0xF); printk(KERN_ERR "\tBus ACK: %#x\n", (econ >> 19) & 3); printk(KERN_ERR "\tBus flags: "); if (econ & DANUBE_BCU_BCU_ECON_TOUT) /* Active High */ printk("TOUT "); if (econ & DANUBE_BCU_BCU_ECON_RDY) /* Active High */ printk("RDY "); if (!(econ & DANUBE_BCU_BCU_ECON_ABT)) /* Active Low */ printk("ABT "); if (econ & DANUBE_BCU_BCU_ECON_SVM) /* Active High */ printk("SVM "); if (!(econ & DANUBE_BCU_BCU_ECON_WRN)) /* Active Low */ printk("WR "); if (!(econ & DANUBE_BCU_BCU_ECON_RDN)) /* Active Low */ printk("RD"); printk(KERN_INFO "\n"); printk(KERN_INFO "\tBus Error Counter %#x\n", econ & 0xFFFF); printk(KERN_INFO "Error Address %#x\n", eaddr); printk(KERN_INFO "Error Data %#x\n", edata); die_if_kernel("Oops", regs); force_sig(SIGBUS, current); return IRQ_HANDLED; } #endif #ifdef CONFIG_AMAZON_S_PCI extern int pci_bus_error_flag; #endif int bus_error_handler(struct pt_regs *regs, int is_fixup) { #ifdef CONFIG_AMAZON_S_PCI if (pci_bus_error_flag) return MIPS_BE_DISCARD; #endif printk(KERN_INFO "Bus Error!\n"); if (is_fixup) return MIPS_BE_FIXUP; else return MIPS_BE_FATAL; } /* * * Version of ffs that only looks at bits 12..15. * */ static inline unsigned int irq_ffs(unsigned int pending) { #if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64) return clz(pending) - CAUSEB_IP; #else unsigned int a0 = 7; unsigned int t0; t0 = pending & 0xf000; t0 = t0 < 1; t0 = t0 << 2; a0 = a0 - t0; pending = pending << t0; t0 = pending & 0xc000; t0 = t0 < 1; t0 = t0 << 1; a0 = a0 - t0; pending = pending << t0; t0 = pending & 0x8000; t0 = t0 < 1; //t0 = t0 << 2; a0 = a0 - t0; //pending = pending << t0; return a0; #endif } /* * IRQs on the Malta board look basically (barring software IRQs which we * don't use at all and all external interrupt sources are combined together * on hardware interrupt 0 (MIPS IRQ 2)) like: * * MIPS IRQ Source * -------- ------ * 0 Software0 * 1 Software1 * 2 Hardware0 * 3 Hardware1 * 4 Hardware2 * 5 Hardware3 * 6 Hardware4 * 7 R4k timer(what we use) * * We handle the IRQ according to _our_ priority which is: * * Highest ---- R4k Timer * Lowest ---- Combined hardware interrupt * * then we just return, if multiple IRQs are pending then we will just take * another exception, big deal. */ asmlinkage void plat_irq_dispatch(void) { unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM; int irq; irq = irq_ffs(pending); prom_printf("[%s %d]: pending %#x, irq %d\n", __func__, __LINE__, pending, irq); switch (irq) { case 0: case 1: do_IRQ(irq); break; case 2: hw0_irqdispatch(); break; case 3: hw1_irqdispatch(); break; case 4: hw2_irqdispatch(); break; case 5: hw3_irqdispatch(); break; case 6: hw4_irqdispatch(); break; case 7: hw5_irqdispatch(); break; default: spurious_interrupt(); break; } } extern unsigned long ebase; extern char except_vec_vi, except_vec_vi_lui, except_vec_vi_ori, except_vec_vi_end; /* Function for careful CP0 interrupt mask access */ void __init arch_init_irq(void) { const int lui_offset = &except_vec_vi_lui - &except_vec_vi; const int ori_offset = &except_vec_vi_ori - &except_vec_vi; int i; //u32 ebase = read_c0_ebase(); BSP_INTERRUPT_DMSG("\n"); board_be_handler = &bus_error_handler; #if 0 if (!cpu_has_veic) mips_cpu_irq_init(0); #endif /* mask all interrupt sources */ *BSP_ICU_IM0_IER = 0; *BSP_ICU_IM1_IER = 0; *BSP_ICU_IM2_IER = 0; *BSP_ICU_IM3_IER = 0; *BSP_ICU_IM4_IER = 0; /* Clear pending interrupts */ *BSP_ICU_IM0_ISR = -1; *BSP_ICU_IM1_ISR = -1; *BSP_ICU_IM2_ISR = -1; *BSP_ICU_IM3_ISR = -1; *BSP_ICU_IM4_ISR = -1; /* Setting up Vectored Interrupt Table * Vectored Interrupt Mode is used when the following conditions are met: * CONFIG3[VInt] = 1 * CONFIG3[Veic] = 0 * INTCTL[VS] != 0 * CAUSE[IV] = 1 * STATUS[BEV] = 0 * A vector number is generated by the interrupt control logic. This number is combined with IntCtlVS to create * interrupt offset, which is added to 0x200 to create exception vector offset. * Vector Number 0 and 1 = Software interrupt 0 and 1 * Vector Number 2 to 7 = Hardware interrupt 0 to 5 */ /* Now safe to set the exception vector. */ if (cpu_has_vint) { printk(KERN_INFO "Setting up vectored interrupts\n"); set_vi_handler(2, hw0_irqdispatch); set_vi_handler(3, hw1_irqdispatch); set_vi_handler(4, hw2_irqdispatch); set_vi_handler(5, hw3_irqdispatch); set_vi_handler(6, hw4_irqdispatch); set_vi_handler(7, hw5_irqdispatch); } BSP_INTERRUPT_DMSG("CONFIG = %#08x\n", read_c0_config()); BSP_INTERRUPT_DMSG("CONFIG1 = %#08x\n", read_c0_config1()); BSP_INTERRUPT_DMSG("CONFIG2 = %#08x\n", read_c0_config2()); BSP_INTERRUPT_DMSG("CONFIG3 = %#08x\n", read_c0_config3()); BSP_INTERRUPT_DMSG("STATUS = %#08x\n", read_c0_status()); BSP_INTERRUPT_DMSG("CAUSE = %#08x\n", read_c0_cause()); BSP_INTERRUPT_DMSG("INTCTL = %#08x\n", read_c0_intctl()); BSP_INTERRUPT_DMSG("SRSCTL = %#08x\n", read_c0_srsctl()); BSP_INTERRUPT_DMSG("SRSMAP = %#08x\n", read_c0_srsmap()); BSP_INTERRUPT_DMSG("EBASE = %#08x\n", read_c0_ebase()); /*--------------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------------*/ { int irq_spacing = 32 * ((read_c0_intctl() >> 5) & ((1 << 5) - 1)); int ii; printk(KERN_INFO "ebase: 0x%x irq_spacing 0x%x\n", ebase, irq_spacing); for(ii = 0 ; ii < 8 ; ii++) { printk(KERN_INFO "vec_vi[%d]:0x%x: 0x%x\n", ii, ebase + 0x0200 + irq_spacing * ii, *(unsigned int *)(ebase + 0x0200 + irq_spacing * ii)); } } for (i = 0; i <= INT_NUM_IM4_IRL31; i++) { if (i != MIPS_CPU_TIMER_IRQ) set_irq_chip_and_handler(i, &bsp_irq_type, handle_level_irq); } #ifdef CONFIG_SMP set_irq_chip_and_handler(MIPS_CPU_TIMER_IRQ, &bsp_timer_irq_type, handle_percpu_irq); set_irq_chip_and_handler(MIPSCPU_INT_BASE + 0, &bsp_timer_irq_type, handle_percpu_irq); set_irq_chip_and_handler(MIPSCPU_INT_BASE + 1, &bsp_timer_irq_type, handle_percpu_irq); #else set_irq_chip_and_handler(MIPS_CPU_TIMER_IRQ, &bsp_timer_irq_type, handle_level_irq); #endif /* Set up bus error handling */ #if 0 *DANUBE_BCU_CON &= ~(DANUBE_BCU_STARVATION_MASK | DANUBE_BCU_TOUT_MASK); *DANUBE_BCU_CON |= ((0 << DANUBE_BCU_STARVATION_SHIFT) | 200); /* 52 is the cut-off point that system boots without bus error */ *DANUBE_SLAVE_BCU_CON &= ~(DANUBE_BCU_STARVATION_MASK | DANUBE_BCU_TOUT_MASK); *DANUBE_SLAVE_BCU_CON |= ((0 << DANUBE_BCU_STARVATION_SHIFT) | 200);/* 52 is the cut-off point that system boots without bus error */ bsp_mask_and_ack_irq(DANUBE_FPI_SLAVE_BCU_IRQ); bsp_mask_and_ack_irq(DANUBE_FPI_MASTER_BCU_IRQ); master_bcu_ir_reg->bcu_irncr |= 1; slave_bcu_ir_reg->bcu_irncr |= 1; if (setup_irq(DANUBE_FPI_SLAVE_BCU_IRQ, &slave_bcu)) printk(KERN_ERR "[%s %d]: setup_irq %d error!\n", __func__, __LINE__, DANUBE_FPI_SLAVE_BCU_IRQ); else slave_bcu_ir_reg->bcu_irnen |= 1; if (setup_irq(DANUBE_FPI_MASTER_BCU_IRQ, &master_bcu)) printk(KERN_ERR "[%s %d]: setup_irq %d error!\n", __func__, __LINE__, DANUBE_FPI_MASTER_BCU_IRQ); else master_bcu_ir_reg->bcu_irnen |= 1; printk(KERN_INFO "[%s %d]: Master BCU_CON %#x Slave BCU_CON %#x\n", __func__, __LINE__, *DANUBE_BCU_CON, *DANUBE_SLAVE_BCU_CON); #endif #if !defined(CONFIG_MIPS_MT_SMP) && !defined(CONFIG_MIPS_MT_SMTC) set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5); #else set_c0_status(IE_SW0 | IE_SW1 | IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5); #endif #ifdef CONFIG_KGDB set_debug_traps(); breakpoint(); #endif } EXPORT_SYMBOL(bsp_get_irq_status); EXPORT_SYMBOL(bsp_get_irq_ier); EXPORT_SYMBOL(bsp_disable_irq); EXPORT_SYMBOL(bsp_mask_and_ack_irq); EXPORT_SYMBOL(bsp_ack_irq); EXPORT_SYMBOL(bsp_mask_irq); EXPORT_SYMBOL(bsp_enable_irq);