X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=cpu%2Fppc4xx%2Finterrupts.c;h=7fa2f7760038275483d11c242b29a055642e4d32;hb=9aea95307fdb0ffe0d3a98a17ac73e5040c9756a;hp=b6a956c152ced8f08e4b2e7f95e525d014bb5cb4;hpb=8bde7f776c77b343aca29b8c7b58464d915ac245;p=oweals%2Fu-boot.git diff --git a/cpu/ppc4xx/interrupts.c b/cpu/ppc4xx/interrupts.c index b6a956c152..7fa2f77600 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. * @@ -35,10 +38,6 @@ /****************************************************************************/ -unsigned decrementer_count; /* count value for 1e6/HZ microseconds */ - -/****************************************************************************/ - /* * CPM interrupt vector functions. */ @@ -54,23 +53,17 @@ static struct irq_action irq_vecs[32]; static struct irq_action irq_vecs1[32]; /* For UIC1 */ void uic1_interrupt( void * parms); /* UIC1 handler */ -#endif -/****************************************************************************/ +#if defined(CONFIG_440_GX) +static struct irq_action irq_vecs2[32]; /* For UIC2 */ -static __inline__ unsigned long get_msr(void) -{ - unsigned long msr; - - asm volatile("mfmsr %0" : "=r" (msr) :); - return msr; -} +void uic0_interrupt( void * parms); /* UIC0 handler */ +void uic2_interrupt( void * parms); /* UIC2 handler */ +#endif /* CONFIG_440_GX */ -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 */ @@ -81,21 +74,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)); @@ -114,29 +92,18 @@ 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 */ @@ -148,6 +115,11 @@ int interrupt_init(void) irq_vecs1[vec].handler = NULL; irq_vecs1[vec].arg = NULL; irq_vecs1[vec].count = 0; +#if defined(CONFIG_440_GX) + irq_vecs2[vec].handler = NULL; + irq_vecs2[vec].arg = NULL; + irq_vecs2[vec].count = 0; +#endif /* CONFIG_440_GX */ #endif } @@ -190,14 +162,30 @@ int interrupt_init(void) set_evpr(0x00000000); #if defined(CONFIG_440) +#if !defined(CONFIG_440_GX) /* 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_440_GX) + /* 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); } @@ -207,6 +195,34 @@ int interrupt_init(void) /* * Handle external interrupts */ +#if defined(CONFIG_440_GX) +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_440_GX */ + +#else + void external_interrupt(struct pt_regs *regs) { ulong uic_msr; @@ -248,6 +264,53 @@ void external_interrupt(struct pt_regs *regs) vec++; } } +#endif + +#if defined(CONFIG_440_GX) +/* 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_440_GX */ #if defined(CONFIG_440) /* Handler for UIC1 interrupt */ @@ -294,50 +357,119 @@ void uic1_interrupt( void * parms) } #endif /* defined(CONFIG_440) */ +#if defined(CONFIG_440_GX) +/* Handler for UIC1 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 (uic1) 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_440_GX) */ + /****************************************************************************/ /* * 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_440_GX) + if ((vec > 31) && (vec < 64)) { + i = vec - 32; + irqa = irq_vecs1; + } else if (vec > 63) { + i = vec - 64; + irqa = irq_vecs2; + } +#else /* CONFIG_440_GX */ if (vec > 31) { i = vec - 32; irqa = irq_vecs1; } -#endif +#endif /* CONFIG_440_GX */ +#endif /* CONFIG_440 */ if (irqa[i].handler != NULL) { 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_440_GX) + if ((vec > 31) && (vec < 64)) + mtdcr (uic1er, mfdcr (uic1er) | (0x80000000 >> i)); + else if (vec > 63) + mtdcr (uic2er, mfdcr (uic2er) | (0x80000000 >> i)); + else +#endif /* CONFIG_440_GX */ + 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_440_GX) + if ((vec > 31) && (vec < 64)) { + irqa = irq_vecs1; + i = vec - 32; + } else if (vec > 63) { + irqa = irq_vecs2; + i = vec - 64; + } +#endif /* CONFIG_440_GX */ if (vec > 31) { irqa = irq_vecs1; i = vec - 32; @@ -350,59 +482,33 @@ irq_free_handler(int vec) #endif #if defined(CONFIG_440) +#if defined(CONFIG_440_GX) + if ((vec > 31) && (vec < 64)) + mtdcr (uic1er, mfdcr (uic1er) & ~(0x80000000 >> i)); + else if (vec > 63) + mtdcr (uic2er, mfdcr (uic2er) & ~(0x80000000 >> i)); + else +#endif /* CONFIG_440_GX */ 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) /******************************************************************************* @@ -435,8 +541,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, @@ -444,8 +549,20 @@ do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) } printf("\n"); #endif - return 0; -} +#if defined(CONFIG_440_GX) + 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 + return 0; +} #endif /* CONFIG_COMMANDS & CFG_CMD_IRQ */