/*- * Copyright (c) 2005-2007, Kohsuke Ohtani * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * interrupt.c - interrupt handling routines for StrongARM-110 INTC. */ #include #include #include /* 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 /* * Interrupt line routing (CPU IRQ/FIQ) */ #define IMODE_CPUIRQ 0 #define IMODE_CPUFIQ 1 /* * Interrupt priority level * * Each interrupt has its logical priority level, with 0 being the highest * priority. While some ISR is running, all lower priority interrupts * are masked off. */ volatile int irq_level; /* * Interrupt mapping table */ static int ipl_table[NIRQS]; /* Vector -> level */ 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 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. */ void interrupt_unmask(int vector, int level) { int i; uint32_t unmask = 1 << vector; ipl_table[vector] = level; /* * Unmask target interrupt for all * lower interrupt levels. */ for (i = 0; i < level; i++) mask_table[i] |= unmask; interrupt_updatemask(); } /* * Mask interrupt in PIC for specified irq. * Interrupt must be disabled when this routine is called. */ void interrupt_mask(int vector) { int i, level; 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; interrupt_updatemask(); } /* * Setup interrupt mode. * Select whether an interrupt trigger is edge or level. */ void interrupt_setup(int vector, int mode) { /* nop */ } /* * Dispatch interrupt * */ void interrupt_dispatch(int vector) { int old_ipl; printk("interrupt_dispatch()\n"); /* Save & update interrupt level */ old_ipl = irq_level; irq_level = ipl_table[vector]; interrupt_updatemask(); /* Allow another interrupt that has higher priority */ interrupt_enable(); /* Dispatch interrupt */ irq_handler(vector); interrupt_disable(); /* Restore interrupt level */ irq_level = old_ipl; interrupt_updatemask(); } /* * Common interrupt handler. * Our task is to scan active pending intrs and dispatch them. */ void interrupt_handler(void) { uint32_t bits; int vector; /* 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 & (1 << vector)) interrupt_dispatch(vector); /* XXX pending intr clears within interrupting device */ } } /* * Initialize interrupt controllers. * 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++) ipl_table[i] = IPL_NONE; for (i = 0; i < NIPLS; i++) mask_table[i] = 0; /* * 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(); }