X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=cpu%2Fppc4xx%2Finterrupts.c;h=886f405156229a730667660a5ca848f9bcfeeaf8;hb=f6e5739a68131998a5ae8aa0cf56a0316f810200;hp=974797f4d56b15710b296b59999236c2f7e04626;hpb=d4ca31c40e8888b36635967522ec7ea03fd7e70b;p=oweals%2Fu-boot.git diff --git a/cpu/ppc4xx/interrupts.c b/cpu/ppc4xx/interrupts.c index 974797f4d5..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. * @@ -33,6 +36,8 @@ #include #include "vecnum.h" +DECLARE_GLOBAL_DATA_PTR; + /****************************************************************************/ /* @@ -45,12 +50,24 @@ 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 + +#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 */ + +#if defined(CONFIG_440SPE) +static struct irq_action irq_vecs3[32]; /* For UIC3 */ +void uic3_interrupt( void * parms); /* UIC3 handler */ +#endif /* CONFIG_440SPE */ + +#endif /* CONFIG_440 */ /****************************************************************************/ #if defined(CONFIG_440) @@ -85,8 +102,6 @@ static __inline__ void set_evpr(unsigned long val) int interrupt_init_cpu (unsigned *decrementer_count) { - DECLARE_GLOBAL_DATA_PTR; - int vec; unsigned long val; @@ -104,6 +119,16 @@ int interrupt_init_cpu (unsigned *decrementer_count) 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 } @@ -118,7 +143,7 @@ int interrupt_init_cpu (unsigned *decrementer_count) 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 @@ -146,10 +171,30 @@ int interrupt_init_cpu (unsigned *decrementer_count) 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 +#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 + */ + 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); } @@ -159,6 +204,62 @@ int interrupt_init_cpu (unsigned *decrementer_count) /* * 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; @@ -200,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 */ @@ -246,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; @@ -302,14 +567,21 @@ 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; } /****************************************************************************/ @@ -354,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, @@ -363,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 */