X-Git-Url: http://git.rot13.org/?p=bcm963xx.git;a=blobdiff_plain;f=kernel%2Flinux%2Farch%2Fmips%2Fbrcm-boards%2Fbcm963xx%2Firq.c;h=33458baeba33855070cc4c4353b9c103f2d94f45;hp=ce5ad41c34a2d560d73b0ece52f8f12bfacdf802;hb=6adeba4d92a546ebbadde2562283ee6b984b22c1;hpb=dacd86d83a9fb430cca42cb78a67f9d46e289f5c diff --git a/kernel/linux/arch/mips/brcm-boards/bcm963xx/irq.c b/kernel/linux/arch/mips/brcm-boards/bcm963xx/irq.c index ce5ad41c..33458bae 100755 --- a/kernel/linux/arch/mips/brcm-boards/bcm963xx/irq.c +++ b/kernel/linux/arch/mips/brcm-boards/bcm963xx/irq.c @@ -1,16 +1,16 @@ /* <:copyright-gpl Copyright 2002 Broadcom Corp. All Rights Reserved. - + 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. @@ -52,48 +52,72 @@ static void irq_dispatch_int(struct pt_regs *regs) } while (1) { - irqBit <<= 1; - isrNumber++; - if (isrNumber == 32) { - isrNumber = 0; - irqBit = 0x1; - } - if (pendingIrqs & irqBit) { - PERF->IrqMask &= ~irqBit; // mask - do_IRQ(isrNumber + INTERNAL_ISR_TABLE_OFFSET, regs); - break; - } + irqBit <<= 1; + isrNumber++; + if (isrNumber == 32) { + isrNumber = 0; + irqBit = 0x1; + } + if (pendingIrqs & irqBit) { + unsigned int irq = isrNumber + INTERNAL_ISR_TABLE_OFFSET; +#if defined(CONFIG_BCM96358) + if (irq >= INTERRUPT_ID_EXTERNAL_0 && irq <= INTERRUPT_ID_EXTERNAL_3) { + PERF->ExtIrqCfg |= (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_CLEAR_SHFT)); // Clear + } + else if (irq >= INTERRUPT_ID_EXTERNAL_4 && irq <= INTERRUPT_ID_EXTERNAL_5) { + PERF->ExtIrqCfg1 |= (1 << (irq - INTERRUPT_ID_EXTERNAL_4 + EI_CLEAR_SHFT)); // Clear + } +#endif + PERF->IrqMask &= ~irqBit; // mask + do_IRQ(irq, regs); + break; + } } } +#if defined(CONFIG_BCM96338) || defined(CONFIG_BCM96348) static void irq_dispatch_ext(uint32 irq, struct pt_regs *regs) { if (!(PERF->ExtIrqCfg & (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_MASK_SHFT)))) { - printk("**** Ext IRQ mask. Should not dispatch ****\n"); + printk("**** Ext IRQ mask. Should not dispatch ****\n"); } /* disable and clear interrupt in the controller */ PERF->ExtIrqCfg |= (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_CLEAR_SHFT)); PERF->ExtIrqCfg &= ~(1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_MASK_SHFT)); do_IRQ(irq, regs); } +#endif + +static void irq_dispatch_sw(uint32 irq, struct pt_regs *regs) +{ + clear_c0_cause(0x1 << (CAUSEB_IP0 + irq - INTERRUPT_ID_SOFTWARE_0)); + do_IRQ(irq, regs); +} + void brcm_irq_dispatch(struct pt_regs *regs) { u32 cause; - while((cause = (read_c0_cause()& CAUSEF_IP))) { - if (cause & CAUSEF_IP7) - do_IRQ(MIPS_TIMER_INT, regs); - else if (cause & CAUSEF_IP2) - irq_dispatch_int(regs); - else if (cause & CAUSEF_IP3) - irq_dispatch_ext(INTERRUPT_ID_EXTERNAL_0, regs); - else if (cause & CAUSEF_IP4) - irq_dispatch_ext(INTERRUPT_ID_EXTERNAL_1, regs); - else if (cause & CAUSEF_IP5) - irq_dispatch_ext(INTERRUPT_ID_EXTERNAL_2, regs); - else if (cause & CAUSEF_IP6) - irq_dispatch_ext(INTERRUPT_ID_EXTERNAL_3, regs); - cli(); + while((cause = (read_c0_cause() & read_c0_status() & CAUSEF_IP))) { + if (cause & CAUSEF_IP7) + do_IRQ(MIPS_TIMER_INT, regs); + else if (cause & CAUSEF_IP2) + irq_dispatch_int(regs); +#if defined(CONFIG_BCM96338) || defined(CONFIG_BCM96348) + else if (cause & CAUSEF_IP3) + irq_dispatch_ext(INTERRUPT_ID_EXTERNAL_0, regs); + else if (cause & CAUSEF_IP4) + irq_dispatch_ext(INTERRUPT_ID_EXTERNAL_1, regs); + else if (cause & CAUSEF_IP5) + irq_dispatch_ext(INTERRUPT_ID_EXTERNAL_2, regs); + else if (cause & CAUSEF_IP6) + irq_dispatch_ext(INTERRUPT_ID_EXTERNAL_3, regs); +#endif + else if (cause & CAUSEF_IP0) + irq_dispatch_sw(INTERRUPT_ID_SOFTWARE_0, regs); + else if (cause & CAUSEF_IP1) + irq_dispatch_sw(INTERRUPT_ID_SOFTWARE_1, regs); + cli(); } } @@ -104,12 +128,17 @@ void enable_brcm_irq(unsigned int irq) local_irq_save(flags); if( irq >= INTERNAL_ISR_TABLE_OFFSET ) { - PERF->IrqMask |= (1 << (irq - INTERNAL_ISR_TABLE_OFFSET)); + PERF->IrqMask |= (1 << (irq - INTERNAL_ISR_TABLE_OFFSET)); } +#if defined(CONFIG_BCM96338) || defined(CONFIG_BCM96348) else if (irq >= INTERRUPT_ID_EXTERNAL_0 && irq <= INTERRUPT_ID_EXTERNAL_3) { - /* enable and clear interrupt in the controller */ - PERF->ExtIrqCfg |= (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_CLEAR_SHFT)); - PERF->ExtIrqCfg |= (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_MASK_SHFT)); + /* enable and clear interrupt in the controller */ + PERF->ExtIrqCfg |= (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_CLEAR_SHFT)); + PERF->ExtIrqCfg |= (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_MASK_SHFT)); + } +#endif + else if ((irq == INTERRUPT_ID_SOFTWARE_0) || (irq == INTERRUPT_ID_SOFTWARE_1)) { + set_c0_status(0x1 << (STATUSB_IP0 + irq - INTERRUPT_ID_SOFTWARE_0)); } local_irq_restore(flags); } @@ -120,11 +149,16 @@ void disable_brcm_irq(unsigned int irq) local_irq_save(flags); if( irq >= INTERNAL_ISR_TABLE_OFFSET ) { - PERF->IrqMask &= ~(1 << (irq - INTERNAL_ISR_TABLE_OFFSET)); + PERF->IrqMask &= ~(1 << (irq - INTERNAL_ISR_TABLE_OFFSET)); } +#if defined(CONFIG_BCM96338) || defined(CONFIG_BCM96348) else if (irq >= INTERRUPT_ID_EXTERNAL_0 && irq <= INTERRUPT_ID_EXTERNAL_3) { - /* disable interrupt in the controller */ - PERF->ExtIrqCfg &= ~(1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_MASK_SHFT)); + /* disable interrupt in the controller */ + PERF->ExtIrqCfg &= ~(1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_MASK_SHFT)); + } +#endif + else if ((irq == INTERRUPT_ID_SOFTWARE_0) || (irq == INTERRUPT_ID_SOFTWARE_1)) { + clear_c0_status(0x1 << (STATUSB_IP0 + irq - INTERRUPT_ID_SOFTWARE_0)); } local_irq_restore(flags); } @@ -156,18 +190,22 @@ void end_brcm_none(unsigned int irq) { } +#if defined (CONFIG_BCM96358) +#define ALLINTS_NOTIMER IE_IRQ0 +#else #define ALLINTS_NOTIMER (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4) +#endif static void __init brcm_irq_setup(void) { - extern asmlinkage void brcmIRQ(void); + extern asmlinkage void brcmIRQ(void); - clear_c0_status(ST0_BEV); - set_except_vector(0, brcmIRQ); - change_c0_status(ST0_IM, ALLINTS_NOTIMER); + clear_c0_status(ST0_BEV); + set_except_vector(0, brcmIRQ); + change_c0_status(ST0_IM, ALLINTS_NOTIMER); #ifdef CONFIG_REMOTE_DEBUG - rs_kgdb_hook(0); + rs_kgdb_hook(0); #endif } @@ -207,11 +245,12 @@ void __init arch_init_irq(void) brcm_irq_setup(); } +#if defined(CONFIG_BCM96338) || defined(CONFIG_BCM96348) int request_external_irq(unsigned int irq, - FN_HANDLER handler, - unsigned long irqflags, - const char * devname, - void *dev_id) + FN_HANDLER handler, + unsigned long irqflags, + const char * devname, + void *dev_id) { unsigned long flags; @@ -227,48 +266,97 @@ int request_external_irq(unsigned int irq, return( request_irq(irq, handler, irqflags, devname, dev_id) ); } +#endif unsigned int BcmHalMapInterrupt(FN_HANDLER pfunc, unsigned int param, - unsigned int interruptId) + unsigned int irq) { int nRet = -1; char *devname; devname = kmalloc(16, GFP_KERNEL); if (devname) - sprintf( devname, "brcm_%d", interruptId ); + sprintf( devname, "brcm_%d", irq ); /* Set the IRQ description to not automatically enable the interrupt at * the end of an ISR. The driver that handles the interrupt must * explicitly call BcmHalInterruptEnable or enable_brcm_irq. This behavior * is consistent with interrupt handling on VxWorks. */ - irq_desc[interruptId].handler = &brcm_irq_no_end_type; + irq_desc[irq].handler = &brcm_irq_no_end_type; + +#if defined(CONFIG_BCM96348) || defined(CONFIG_BCM96358) + if( irq == INTERRUPT_ID_MPI ) { + nRet = request_irq( irq, pfunc, SA_SAMPLE_RANDOM | SA_INTERRUPT | SA_SHIRQ, + devname, (void *) param ); - if( interruptId >= INTERNAL_ISR_TABLE_OFFSET ) + } + else +#endif + if( irq >= INTERNAL_ISR_TABLE_OFFSET ) { - nRet = request_irq( interruptId, pfunc, SA_SAMPLE_RANDOM | SA_INTERRUPT, - devname, (void *) param ); - +#if defined(CONFIG_BCM96358) + unsigned long flags; + + local_irq_save(flags); + if (irq >= INTERRUPT_ID_EXTERNAL_0 && irq <= INTERRUPT_ID_EXTERNAL_3) { + PERF->ExtIrqCfg |= (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_CLEAR_SHFT)); // Clear + PERF->ExtIrqCfg |= (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_MASK_SHFT)); // Unmask + PERF->ExtIrqCfg &= ~(1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_INSENS_SHFT)); // Edge insesnsitive + PERF->ExtIrqCfg |= (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_LEVEL_SHFT)); // Level triggered + PERF->ExtIrqCfg &= ~(1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_SENSE_SHFT)); // Low level + } + else if (irq >= INTERRUPT_ID_EXTERNAL_4 && irq <= INTERRUPT_ID_EXTERNAL_5) { + PERF->ExtIrqCfg1 |= (1 << (irq - INTERRUPT_ID_EXTERNAL_4 + EI_CLEAR_SHFT)); // Clear + PERF->ExtIrqCfg1 |= (1 << (irq - INTERRUPT_ID_EXTERNAL_4 + EI_MASK_SHFT)); // Unmask + PERF->ExtIrqCfg1 &= ~(1 << (irq - INTERRUPT_ID_EXTERNAL_4 + EI_INSENS_SHFT)); // Edge insesnsitive + PERF->ExtIrqCfg1 |= (1 << (irq - INTERRUPT_ID_EXTERNAL_4 + EI_LEVEL_SHFT)); // Level triggered + PERF->ExtIrqCfg1 &= ~(1 << (irq - INTERRUPT_ID_EXTERNAL_4 + EI_SENSE_SHFT)); // Low level + } + local_irq_restore(flags); +#endif + nRet = request_irq( irq, pfunc, SA_SAMPLE_RANDOM | SA_INTERRUPT, + devname, (void *) param ); + } - else if (interruptId >= INTERRUPT_ID_EXTERNAL_0 && interruptId <= INTERRUPT_ID_EXTERNAL_3) +#if defined(CONFIG_BCM96338) || defined(CONFIG_BCM96348) + else if (irq >= INTERRUPT_ID_EXTERNAL_0 && irq <= INTERRUPT_ID_EXTERNAL_3) + { + nRet = request_external_irq( irq, pfunc, SA_SAMPLE_RANDOM | SA_INTERRUPT, + devname, (void *) param ); + } +#endif + else if ((irq == INTERRUPT_ID_SOFTWARE_0) || (irq == INTERRUPT_ID_SOFTWARE_1)) { - nRet = request_external_irq( interruptId, pfunc, SA_SAMPLE_RANDOM | SA_INTERRUPT, + nRet = request_irq( irq, pfunc, SA_SAMPLE_RANDOM | SA_INTERRUPT, devname, (void *) param ); } return( nRet ); } -/* Debug function. */ -void dump_intr_regs(void) +//*************************************************************************** +// void BcmHalGenerateSoftInterrupt +// +// Triggers a software interrupt. +// +//*************************************************************************** +void BcmHalGenerateSoftInterrupt( unsigned int irq ) { - printk("PERF->ExtIrqCfg [%08x]\n", *(&(PERF->ExtIrqCfg))); -} + unsigned long flags; + + local_irq_save(flags); + + set_c0_cause(0x1 << (CAUSEB_IP0 + irq - INTERRUPT_ID_SOFTWARE_0)); + + local_irq_restore(flags); +} EXPORT_SYMBOL(enable_brcm_irq); EXPORT_SYMBOL(disable_brcm_irq); +#if defined(CONFIG_BCM96338) || defined(CONFIG_BCM96348) EXPORT_SYMBOL(request_external_irq); +#endif EXPORT_SYMBOL(BcmHalMapInterrupt); - +EXPORT_SYMBOL(BcmHalGenerateSoftInterrupt);