X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;ds=sidebyside;f=cpu%2Fppc4xx%2Finterrupts.c;h=886f405156229a730667660a5ca848f9bcfeeaf8;hb=f6e5739a68131998a5ae8aa0cf56a0316f810200;hp=0867de43225fef6743fba350687760f8bb3ea356;hpb=f780aa2a956983c7f6d22c4b5335d503cfde6949;p=oweals%2Fu-boot.git diff --git a/cpu/ppc4xx/interrupts.c b/cpu/ppc4xx/interrupts.c index 0867de4322..886f405156 100644 --- a/cpu/ppc4xx/interrupts.c +++ b/cpu/ppc4xx/interrupts.c @@ -5,6 +5,9 @@ * (C) Copyright 2002 (440 port) * Scott McNutt, Artesyn Communication Producs, smcnutt@artsyncp.com * + * (C) Copyright 2003 (440GX port) + * Travis B. Sawyer, Sandburst Corporation, tsawyer@sandburst.com + * * See file CREDITS for list of people who contributed to this * project. * @@ -27,16 +30,13 @@ #include #include #include -#include #include #include #include #include #include "vecnum.h" -/****************************************************************************/ - -unsigned decrementer_count; /* count value for 1e6/HZ microseconds */ +DECLARE_GLOBAL_DATA_PTR; /****************************************************************************/ @@ -50,28 +50,26 @@ struct irq_action { }; static struct irq_action irq_vecs[32]; +void uic0_interrupt( void * parms); /* UIC0 handler */ #if defined(CONFIG_440) static struct irq_action irq_vecs1[32]; /* For UIC1 */ void uic1_interrupt( void * parms); /* UIC1 handler */ -#endif -/****************************************************************************/ - -static __inline__ unsigned long get_msr(void) -{ - unsigned long msr; +#if defined(CONFIG_440GX) || defined(CONFIG_440SPE) +static struct irq_action irq_vecs2[32]; /* For UIC2 */ +void uic2_interrupt( void * parms); /* UIC2 handler */ +#endif /* CONFIG_440GX CONFIG_440SPE */ - asm volatile("mfmsr %0" : "=r" (msr) :); - return msr; -} +#if defined(CONFIG_440SPE) +static struct irq_action irq_vecs3[32]; /* For UIC3 */ +void uic3_interrupt( void * parms); /* UIC3 handler */ +#endif /* CONFIG_440SPE */ -static __inline__ void set_msr(unsigned long msr) -{ - asm volatile("mtmsr %0" : : "r" (msr)); -} +#endif /* CONFIG_440 */ +/****************************************************************************/ #if defined(CONFIG_440) /* SPRN changed in 440 */ @@ -82,21 +80,6 @@ static __inline__ void set_evpr(unsigned long val) #else /* !defined(CONFIG_440) */ -static __inline__ unsigned long get_dec(void) -{ - unsigned long val; - - asm volatile("mfdec %0" : "=r" (val) :); - return val; -} - - -static __inline__ void set_dec(unsigned long val) -{ - asm volatile("mtdec %0" : : "r" (val)); -} - - static __inline__ void set_pit(unsigned long val) { asm volatile("mtpit %0" : : "r" (val)); @@ -115,29 +98,16 @@ static __inline__ void set_evpr(unsigned long val) } #endif /* defined(CONFIG_440 */ - -void enable_interrupts (void) -{ - set_msr (get_msr() | MSR_EE); -} - -/* returns flag if MSR_EE was set before */ -int disable_interrupts (void) -{ - ulong msr = get_msr(); - set_msr (msr & ~MSR_EE); - return ((msr & MSR_EE) != 0); -} - /****************************************************************************/ -int interrupt_init(void) +int interrupt_init_cpu (unsigned *decrementer_count) { - DECLARE_GLOBAL_DATA_PTR; - int vec; unsigned long val; + /* decrementer is automatically reloaded */ + *decrementer_count = 0; + /* * Mark all irqs as free */ @@ -149,6 +119,16 @@ int interrupt_init(void) irq_vecs1[vec].handler = NULL; irq_vecs1[vec].arg = NULL; irq_vecs1[vec].count = 0; +#if defined(CONFIG_440GX) || defined(CONFIG_440SPE) + irq_vecs2[vec].handler = NULL; + irq_vecs2[vec].arg = NULL; + irq_vecs2[vec].count = 0; +#endif /* CONFIG_440GX */ +#if defined(CONFIG_440SPE) + irq_vecs3[vec].handler = NULL; + irq_vecs3[vec].arg = NULL; + irq_vecs3[vec].count = 0; +#endif /* CONFIG_440SPE */ #endif } @@ -163,7 +143,7 @@ int interrupt_init(void) mtspr( dec, 0 ); /* Prevent exception after TSR clear*/ mtspr( decar, 0 ); /* clear reload */ mtspr( tsr, 0x08000000 ); /* clear DEC status */ - val = gd->bd->bi_intfreq/100; /* 10 msec */ + val = gd->bd->bi_intfreq/1000; /* 1 msec */ mtspr( decar, val ); /* Set auto-reload value */ mtspr( dec, val ); /* Set inital val */ #else @@ -191,14 +171,30 @@ int interrupt_init(void) set_evpr(0x00000000); #if defined(CONFIG_440) +#if !defined(CONFIG_440GX) /* Install the UIC1 handlers */ irq_install_handler(VECNUM_UIC1NC, uic1_interrupt, 0); irq_install_handler(VECNUM_UIC1C, uic1_interrupt, 0); #endif - /* - * Enable external interrupts (including PIT) +#endif + +#if defined(CONFIG_440GX) + /* Take the GX out of compatibility mode + * Travis Sawyer, 9 Mar 2004 + * NOTE: 440gx user manual inconsistency here + * Compatibility mode and Ethernet Clock select are not + * correct in the manual */ - set_msr (get_msr() | MSR_EE); + mfsdr(sdr_mfr, val); + val &= ~0x10000000; + mtsdr(sdr_mfr,val); + + /* Enable UIC interrupts via UIC Base Enable Register */ + mtdcr(uicb0sr, UICB0_ALL); + mtdcr(uicb0er, 0x54000000); + /* None are critical */ + mtdcr(uicb0cr, 0); +#endif return (0); } @@ -208,6 +204,62 @@ int interrupt_init(void) /* * Handle external interrupts */ +#if defined(CONFIG_440GX) +void external_interrupt(struct pt_regs *regs) +{ + ulong uic_msr; + + /* + * Read masked interrupt status register to determine interrupt source + */ + /* 440 GX uses base uic register */ + uic_msr = mfdcr(uicb0msr); + + if ( (UICB0_UIC0CI & uic_msr) || (UICB0_UIC0NCI & uic_msr) ) + uic0_interrupt(0); + + if ( (UICB0_UIC1CI & uic_msr) || (UICB0_UIC1NCI & uic_msr) ) + uic1_interrupt(0); + + if ( (UICB0_UIC2CI & uic_msr) || (UICB0_UIC2NCI & uic_msr) ) + uic2_interrupt(0); + + mtdcr(uicb0sr, uic_msr); + + return; + +} /* external_interrupt CONFIG_440GX */ + +#elif defined(CONFIG_440SPE) +void external_interrupt(struct pt_regs *regs) +{ + ulong uic_msr; + + /* + * Read masked interrupt status register to determine interrupt source + */ + /* 440 SPe uses base uic register */ + uic_msr = mfdcr(uic0msr); + + if ( (UICB0_UIC1CI & uic_msr) || (UICB0_UIC1NCI & uic_msr) ) + uic1_interrupt(0); + + if ( (UICB0_UIC2CI & uic_msr) || (UICB0_UIC2NCI & uic_msr) ) + uic2_interrupt(0); + + if ( (UICB0_UIC3CI & uic_msr) || (UICB0_UIC3NCI & uic_msr) ) + uic3_interrupt(0); + + if (uic_msr & ~(UICB0_ALL)) + uic0_interrupt(0); + + mtdcr(uic0sr, uic_msr); + + return; +} /* external_interrupt CONFIG_440SPE */ + +#else + void external_interrupt(struct pt_regs *regs) { ulong uic_msr; @@ -249,6 +301,53 @@ void external_interrupt(struct pt_regs *regs) vec++; } } +#endif + +#if defined(CONFIG_440GX) || defined(CONFIG_440SPE) +/* Handler for UIC0 interrupt */ +void uic0_interrupt( void * parms) +{ + ulong uic_msr; + ulong msr_shift; + int vec; + + /* + * Read masked interrupt status register to determine interrupt source + */ + uic_msr = mfdcr(uicmsr); + msr_shift = uic_msr; + vec = 0; + + while (msr_shift != 0) { + if (msr_shift & 0x80000000) { + /* + * Increment irq counter (for debug purpose only) + */ + irq_vecs[vec].count++; + + if (irq_vecs[vec].handler != NULL) { + /* call isr */ + (*irq_vecs[vec].handler)(irq_vecs[vec].arg); + } else { + mtdcr(uicer, mfdcr(uicer) & ~(0x80000000 >> vec)); + printf ("Masking bogus interrupt vector (uic0) 0x%x\n", vec); + } + + /* + * After servicing the interrupt, we have to remove the status indicator. + */ + mtdcr(uicsr, (0x80000000 >> vec)); + } + + /* + * Shift msr to next position and increment vector + */ + msr_shift <<= 1; + vec++; + } +} + +#endif /* CONFIG_440GX */ #if defined(CONFIG_440) /* Handler for UIC1 interrupt */ @@ -295,50 +394,167 @@ void uic1_interrupt( void * parms) } #endif /* defined(CONFIG_440) */ +#if defined(CONFIG_440GX) || defined(CONFIG_440SPE) +/* Handler for UIC2 interrupt */ +void uic2_interrupt( void * parms) +{ + ulong uic2_msr; + ulong msr_shift; + int vec; + + /* + * Read masked interrupt status register to determine interrupt source + */ + uic2_msr = mfdcr(uic2msr); + msr_shift = uic2_msr; + vec = 0; + + while (msr_shift != 0) { + if (msr_shift & 0x80000000) { + /* + * Increment irq counter (for debug purpose only) + */ + irq_vecs2[vec].count++; + + if (irq_vecs2[vec].handler != NULL) { + /* call isr */ + (*irq_vecs2[vec].handler)(irq_vecs2[vec].arg); + } else { + mtdcr(uic2er, mfdcr(uic2er) & ~(0x80000000 >> vec)); + printf ("Masking bogus interrupt vector (uic2) 0x%x\n", vec); + } + + /* + * After servicing the interrupt, we have to remove the status indicator. + */ + mtdcr(uic2sr, (0x80000000 >> vec)); + } + + /* + * Shift msr to next position and increment vector + */ + msr_shift <<= 1; + vec++; + } +} +#endif /* defined(CONFIG_440GX) */ + +#if defined(CONFIG_440SPE) +/* Handler for UIC3 interrupt */ +void uic3_interrupt( void * parms) +{ + ulong uic3_msr; + ulong msr_shift; + int vec; + + /* + * Read masked interrupt status register to determine interrupt source + */ + uic3_msr = mfdcr(uic3msr); + msr_shift = uic3_msr; + vec = 0; + + while (msr_shift != 0) { + if (msr_shift & 0x80000000) { + /* + * Increment irq counter (for debug purpose only) + */ + irq_vecs3[vec].count++; + + if (irq_vecs3[vec].handler != NULL) { + /* call isr */ + (*irq_vecs3[vec].handler)(irq_vecs3[vec].arg); + } else { + mtdcr(uic3er, mfdcr(uic3er) & ~(0x80000000 >> vec)); + printf ("Masking bogus interrupt vector (uic3) 0x%x\n", vec); + } + + /* + * After servicing the interrupt, we have to remove the status indicator. + */ + mtdcr(uic3sr, (0x80000000 >> vec)); + } + + /* + * Shift msr to next position and increment vector + */ + msr_shift <<= 1; + vec++; + } +} +#endif /* defined(CONFIG_440SPE) */ + /****************************************************************************/ /* * Install and free a interrupt handler. */ -void -irq_install_handler(int vec, interrupt_handler_t *handler, void *arg) +void irq_install_handler (int vec, interrupt_handler_t * handler, void *arg) { struct irq_action *irqa = irq_vecs; - int i = vec; + int i = vec; #if defined(CONFIG_440) +#if defined(CONFIG_440GX) || defined(CONFIG_440SPE) + if ((vec > 31) && (vec < 64)) { + i = vec - 32; + irqa = irq_vecs1; + } else if (vec > 63) { + i = vec - 64; + irqa = irq_vecs2; + } +#else /* CONFIG_440GX */ if (vec > 31) { i = vec - 32; irqa = irq_vecs1; } -#endif +#endif /* CONFIG_440GX */ +#endif /* CONFIG_440 */ - if (irqa[i].handler != NULL) { + /* + * print warning when replacing with a different irq vector + */ + if ((irqa[i].handler != NULL) && (irqa[i].handler != handler)) { printf ("Interrupt vector %d: handler 0x%x replacing 0x%x\n", - vec, (uint)handler, (uint)irqa[i].handler); + vec, (uint) handler, (uint) irqa[i].handler); } irqa[i].handler = handler; - irqa[i].arg = arg; + irqa[i].arg = arg; #if defined(CONFIG_440) - if( vec > 31 ) - mtdcr(uic1er, mfdcr(uic1er) | (0x80000000 >> i)); +#if defined(CONFIG_440GX) || defined(CONFIG_440SPE) + if ((vec > 31) && (vec < 64)) + mtdcr (uic1er, mfdcr (uic1er) | (0x80000000 >> i)); + else if (vec > 63) + mtdcr (uic2er, mfdcr (uic2er) | (0x80000000 >> i)); + else +#endif /* CONFIG_440GX */ + if (vec > 31) + mtdcr (uic1er, mfdcr (uic1er) | (0x80000000 >> i)); else #endif - mtdcr(uicer, mfdcr(uicer) | (0x80000000 >> i)); + mtdcr (uicer, mfdcr (uicer) | (0x80000000 >> i)); #if 0 printf ("Install interrupt for vector %d ==> %p\n", vec, handler); #endif } -void -irq_free_handler(int vec) +void irq_free_handler (int vec) { struct irq_action *irqa = irq_vecs; - int i = vec; + int i = vec; #if defined(CONFIG_440) +#if defined(CONFIG_440GX) || defined(CONFIG_440SPE) + if ((vec > 31) && (vec < 64)) { + irqa = irq_vecs1; + i = vec - 32; + } else if (vec > 63) { + irqa = irq_vecs2; + i = vec - 64; + } +#endif /* CONFIG_440GX */ if (vec > 31) { irqa = irq_vecs1; i = vec - 32; @@ -351,59 +567,33 @@ irq_free_handler(int vec) #endif #if defined(CONFIG_440) +#if defined(CONFIG_440GX) || defined(CONFIG_440SPE) + if ((vec > 31) && (vec < 64)) + mtdcr (uic1er, mfdcr (uic1er) & ~(0x80000000 >> i)); + else if (vec > 63) + mtdcr (uic2er, mfdcr (uic2er) & ~(0x80000000 >> i)); + else +#endif /* CONFIG_440GX */ if (vec > 31) - mtdcr(uic1er, mfdcr(uic1er) & ~(0x80000000 >> i)); + mtdcr (uic1er, mfdcr (uic1er) & ~(0x80000000 >> i)); else #endif - mtdcr(uicer, mfdcr(uicer) & ~(0x80000000 >> i)); + mtdcr (uicer, mfdcr (uicer) & ~(0x80000000 >> i)); irqa[i].handler = NULL; - irqa[i].arg = NULL; + irqa[i].arg = NULL; } /****************************************************************************/ - -volatile ulong timestamp = 0; - -/* - * timer_interrupt - gets called when the decrementer overflows, - * with interrupts disabled. - * Trivial implementation - no need to be really accurate. - */ -void timer_interrupt(struct pt_regs *regs) +void timer_interrupt_cpu (struct pt_regs *regs) { -#if 0 - printf ("*** Timer Interrupt *** "); -#endif - timestamp++; - -#if defined(CONFIG_WATCHDOG) - if ((timestamp % 1000) == 0) - reset_4xx_watchdog(); -#endif /* CONFIG_WATCHDOG */ + /* nothing to do here */ + return; } /****************************************************************************/ -void reset_timer (void) -{ - timestamp = 0; -} - -ulong get_timer (ulong base) -{ - return (timestamp - base); -} - -void set_timer (ulong t) -{ - timestamp = t; -} - -/****************************************************************************/ - - #if (CONFIG_COMMANDS & CFG_CMD_IRQ) /******************************************************************************* @@ -436,8 +626,7 @@ do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) printf ("\nUIC 1\n"); printf ("Nr Routine Arg Count\n"); - for (vec=0; vec<32; vec++) - { + for (vec=0; vec<32; vec++) { if (irq_vecs1[vec].handler != NULL) printf ("%02d %08lx %08lx %d\n", vec+31, (ulong)irq_vecs1[vec].handler, @@ -445,8 +634,33 @@ do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) } printf("\n"); #endif - return 0; -} +#if defined(CONFIG_440GX) || defined(CONFIG_440SPE) + printf ("\nUIC 2\n"); + printf ("Nr Routine Arg Count\n"); + for (vec=0; vec<32; vec++) { + if (irq_vecs2[vec].handler != NULL) + printf ("%02d %08lx %08lx %d\n", + vec+63, (ulong)irq_vecs2[vec].handler, + (ulong)irq_vecs2[vec].arg, irq_vecs2[vec].count); + } + printf("\n"); +#endif + +#if defined(CONFIG_440SPE) + printf ("\nUIC 3\n"); + printf ("Nr Routine Arg Count\n"); + + for (vec=0; vec<32; vec++) { + if (irq_vecs3[vec].handler != NULL) + printf ("%02d %08lx %08lx %d\n", + vec+63, (ulong)irq_vecs3[vec].handler, + (ulong)irq_vecs3[vec].arg, irq_vecs3[vec].count); + } + printf("\n"); +#endif + + return 0; +} #endif /* CONFIG_COMMANDS & CFG_CMD_IRQ */