=================================================================== RCS file: /cvs/prex-old/sys/arch/arm/cats/interrupt.c,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- prex-old/sys/arch/arm/cats/interrupt.c 2008/07/18 21:21:48 1.1 +++ prex-old/sys/arch/arm/cats/interrupt.c 2008/07/22 15:40:52 1.2 @@ -28,28 +28,28 @@ */ /* - * interrupt.c - interrupt handling routines for GBA + * interrupt.c - interrupt handling routines for StrongARM-110 INTC. */ #include #include #include -/* Interrupt hook vector */ -#define IRQ_VECTOR *(uint32_t *)0x3007ffc +/* Registers for interrupt control unit */ +#define SAIC_BASE 0x90050000 +#define SAIC_ICIP 0 +#define SAIC_ICMR 0x04 +#define SAIC_ICLR 0x08 +#define SAIC_ICFP 0x10 +#define SAIC_ICPR 0x20 +#define SAIC_ICCR 0x0c -/* Registers for interrupt control unit - enable/flag/master */ -#define ICU_IE (*(volatile uint16_t *)0x4000200) -#define ICU_IF (*(volatile uint16_t *)0x4000202) -#define ICU_IME (*(volatile uint16_t *)0x4000208) +/* + * Interrupt line routing (CPU IRQ/FIQ) + */ +#define IMODE_CPUIRQ 0 +#define IMODE_CPUFIQ 1 -/* ICU_IE */ -#define IRQ_VALID 0x3fff - -/* ICU_IME */ -#define IRQ_OFF 0 -#define IRQ_ON 1 - /* * Interrupt priority level * @@ -63,14 +63,53 @@ * Interrupt mapping table */ static int ipl_table[NIRQS]; /* Vector -> level */ -static uint16_t mask_table[NIPLS]; /* Level -> mask */ +static uint32_t mask_table[NIPLS]; /* Level -> mask */ + +void saic_updatemask(uint32_t mask); +void saic_routeto(int intrno, int irqfiq); /* * Set mask for current ipl */ -#define update_mask() ICU_IE = mask_table[irq_level] +#define interrupt_updatemask() saic_updatemask(mask_table[irq_level]); /* + * Write new mask to Mask Register. + */ +void +saic_updatemask(uint32_t mask) +{ + /* XXX */ + *(volatile uint32_t *)(SAIC_BASE + SAIC_ICMR) = mask; +} + +/* + * Interrupt line routing to IRQ/FIQ. + */ +void +saic_routeto(int intrno, int irqfiq) +{ + uint32_t bits; + + + bits = *(volatile uint32_t *)(SAIC_BASE + SAIC_ICLR); + + switch(irqfiq) { + case IMODE_CPUIRQ: + bits &= ~(1 << intrno); + break; + + case IMODE_CPUFIQ: + bits |= 1 << intrno; + break; + + default: + panic("saic_routeto: bogus irqfiq %u for intr %u", irqfiq, intrno); + /* NOTREACHED */ + } +} + +/* * Unmask interrupt in PIC for specified irq. * The interrupt mask table is also updated. * Assumed CPU interrupt is disabled in caller. @@ -79,7 +118,7 @@ interrupt_unmask(int vector, int level) { int i; - uint16_t unmask = (uint16_t)1 << vector; + uint32_t unmask = 1 << vector; ipl_table[vector] = level; /* @@ -88,7 +127,8 @@ */ for (i = 0; i < level; i++) mask_table[i] |= unmask; - update_mask(); + + interrupt_updatemask(); } /* @@ -99,13 +139,15 @@ interrupt_mask(int vector) { int i, level; - u_int mask = (uint16_t)~(1 << vector); + uint32_t mask = (uint32_t)~(1 << vector); level = ipl_table[vector]; for (i = 0; i < level; i++) mask_table[i] &= mask; + ipl_table[vector] = IPL_NONE; - update_mask(); + + interrupt_updatemask(); } /* @@ -127,14 +169,13 @@ { int old_ipl; + printk("interrupt_dispatch()\n"); + /* Save & update interrupt level */ old_ipl = irq_level; irq_level = ipl_table[vector]; - update_mask(); + interrupt_updatemask(); - /* Send acknowledge to ICU for this irq */ - ICU_IF = (uint16_t)(1 << vector); - /* Allow another interrupt that has higher priority */ interrupt_enable(); @@ -145,49 +186,44 @@ /* Restore interrupt level */ irq_level = old_ipl; - update_mask(); + interrupt_updatemask(); } /* * Common interrupt handler. + * Our task is to scan active pending intrs and dispatch them. */ void interrupt_handler(void) { - uint16_t bits; + uint32_t bits; int vector; - bits = ICU_IF; -retry: + + /* XXX we use only IRQs for now, so don't count FIQs */ + bits = *(volatile uint32_t *)(SAIC_BASE + SAIC_ICIP); + + /* dispatch all pending interrupts */ for (vector = 0; vector < NIRQS; vector++) { - if (bits & (uint16_t)(1 << vector)) - break; + if (bits & (1 << vector)) + interrupt_dispatch(vector); + + /* XXX pending intr clears within interrupting device */ } - if (vector == NIRQS) - goto out; - interrupt_dispatch(vector); - - /* - * Multiple interrupts can be fired in case of GBA. - * So, we have to check the interrupt status, again. - */ - bits = ICU_IF; - if (bits & IRQ_VALID) - goto retry; -out: - return; } /* * Initialize interrupt controllers. - * All interrupts will be masked off. + * All interrupts will be masked off and routed to CPU IRQ line. */ void interrupt_init(void) { int i; + interrupt_disable(); + irq_level = IPL_NONE; for (i = 0; i < NIRQS; i++) @@ -196,8 +232,13 @@ for (i = 0; i < NIPLS; i++) mask_table[i] = 0; - ICU_IME = IRQ_OFF; - IRQ_VECTOR = (uint32_t)interrupt_entry; /* Interrupt hook address */ - ICU_IE = 0; /* Mask all interrupts */ - ICU_IME = IRQ_ON; + /* + * XXX route all Interrupt Controller interrupts to CPU IRQ line. + */ + for (i = 0; i < NIRQS; i++) + saic_routeto(i, IMODE_CPUIRQ); + + interrupt_updatemask(); + + interrupt_enable(); }