m68knommu: map ColdFire interrupts to correct masking bits
authorGreg Ungerer <gerg@uclinux.org>
Fri, 22 May 2009 03:33:35 +0000 (13:33 +1000)
committerGreg Ungerer <gerg@uclinux.org>
Tue, 15 Sep 2009 23:43:52 +0000 (09:43 +1000)
The older simple ColdFire interrupt controller has no one-to-one mapping
of interrupt numbers to bits in the interrupt mask register. Create a
mapping array that each ColdFire CPU type can populate with its available
interrupts and the bits that each use in the interrupt mask register.

Signed-off-by: Greg Ungerer <gerg@uclinux.org>
arch/m68k/include/asm/mcfintc.h
arch/m68knommu/platform/5206/config.c
arch/m68knommu/platform/5206e/config.c
arch/m68knommu/platform/5249/config.c
arch/m68knommu/platform/5307/config.c
arch/m68knommu/platform/5407/config.c
arch/m68knommu/platform/coldfire/intc.c

index 213aa6c68abbdb70c8af6a972d32e50b87685818..4183320a3813cde14729b643f990e6df6ebe206c 100644 (file)
  * interrupt control purposes.
  */
 
-/*
- * Define the base address of the SIM within the MBAR address space.
- */
-#define        MCFSIM_BASE             0x0             /* Base address within SIM */
-
 /*
  * Bit definitions for the ICR family of registers.
  */
@@ -48,7 +43,9 @@
 #define        MCFSIM_ICR_PRI3         0x03            /* Priority 3 intr */
 
 /*
- * IMR bit position definitions.
+ * IMR bit position definitions. Not all ColdFire parts with this interrupt
+ * controller actually support all of these interrupt sources. But the bit
+ * numbers are the same in all cores.
  */
 #define        MCFINTC_EINT1           1               /* External int #1 */
 #define        MCFINTC_EINT2           2               /* External int #2 */
 #define        MCFINTC_QSPI            18
 
 #ifndef __ASSEMBLER__
+
+/*
+ * There is no one-is-one correspondance between the interrupt number (irq)
+ * and the bit fields on the mask register. So we create a per-cpu type
+ * mapping of irq to mask bit. The CPU platform code needs to register
+ * its supported irq's at init time, using this function.
+ */
+extern unsigned char mcf_irq2imr[];
+static inline void mcf_mapirq2imr(int irq, int imr)
+{
+       mcf_irq2imr[irq] = imr;
+}
+
 void mcf_autovector(int irq);
 void mcf_setimr(int index);
 void mcf_clrimr(int index);
index c1d24796ef2fd714be56b93206246c518982b246..9c335465e66de1a0e9a4d4e59ae53c4369810d05 100644 (file)
@@ -49,11 +49,11 @@ static void __init m5206_uart_init_line(int line, int irq)
        if (line == 0) {
                writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
                writeb(irq, MCFUART_BASE1 + MCFUART_UIVR);
-               mcf_clrimr(MCFINTC_UART0);
+               mcf_mapirq2imr(irq, MCFINTC_UART0);
        } else if (line == 1) {
                writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
                writeb(irq, MCFUART_BASE2 + MCFUART_UIVR);
-               mcf_clrimr(MCFINTC_UART1);
+               mcf_mapirq2imr(irq, MCFINTC_UART1);
        }
 }
 
@@ -73,11 +73,13 @@ static void __init m5206_timers_init(void)
        /* Timer1 is always used as system timer */
        writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3,
                MCF_MBAR + MCFSIM_TIMER1ICR);
+       mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1);
 
 #ifdef CONFIG_HIGHPROFILE
        /* Timer2 is to be used as a high speed profile timer  */
        writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3,
                MCF_MBAR + MCFSIM_TIMER2ICR);
+       mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2);
 #endif
 }
 
@@ -98,13 +100,18 @@ void __init config_BSP(char *commandp, int size)
 {
        mach_reset = m5206_cpu_reset;
        m5206_timers_init();
+       m5206_uarts_init();
+
+       /* Only support the external interrupts on their primary level */
+       mcf_mapirq2imr(25, MCFINTC_EINT1);
+       mcf_mapirq2imr(28, MCFINTC_EINT4);
+       mcf_mapirq2imr(31, MCFINTC_EINT7);
 }
 
 /***************************************************************************/
 
 static int __init init_BSP(void)
 {
-       m5206_uarts_init();
        platform_add_devices(m5206_devices, ARRAY_SIZE(m5206_devices));
        return 0;
 }
index 363296af2ee572f127539aed5518cc10cbd1d2cf..0f41ba82a3b533d1ff6a3815f59916c6d3e5f77e 100644 (file)
@@ -50,11 +50,11 @@ static void __init m5206e_uart_init_line(int line, int irq)
        if (line == 0) {
                writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
                writeb(irq, MCFUART_BASE1 + MCFUART_UIVR);
-               mcf_clrimr(MCFINTC_UART0);
+               mcf_mapirq2imr(irq, MCFINTC_UART0);
        } else if (line == 1) {
                writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
                writeb(irq, MCFUART_BASE2 + MCFUART_UIVR);
-               mcf_clrimr(MCFINTC_UART1);
+               mcf_mapirq2imr(irq, MCFINTC_UART1);
        }
 }
 
@@ -74,11 +74,13 @@ static void __init m5206e_timers_init(void)
        /* Timer1 is always used as system timer */
        writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3,
                MCF_MBAR + MCFSIM_TIMER1ICR);
+       mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1);
 
 #ifdef CONFIG_HIGHPROFILE
        /* Timer2 is to be used as a high speed profile timer  */
        writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3,
                MCF_MBAR + MCFSIM_TIMER2ICR);
+       mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2);
 #endif
 }
 
@@ -105,13 +107,18 @@ void __init config_BSP(char *commandp, int size)
 
        mach_reset = m5206e_cpu_reset;
        m5206e_timers_init();
+       m5206e_uarts_init();
+
+       /* Only support the external interrupts on their primary level */
+       mcf_mapirq2imr(25, MCFINTC_EINT1);
+       mcf_mapirq2imr(28, MCFINTC_EINT4);
+       mcf_mapirq2imr(31, MCFINTC_EINT7);
 }
 
 /***************************************************************************/
 
 static int __init init_BSP(void)
 {
-       m5206e_uarts_init();
        platform_add_devices(m5206e_devices, ARRAY_SIZE(m5206e_devices));
        return 0;
 }
index 51202b1096cc20d850dd20af1f9be3dc63e14185..646f5ba462fcb6675293f7c55a8ee6efb6e31fbf 100644 (file)
@@ -48,11 +48,11 @@ static void __init m5249_uart_init_line(int line, int irq)
        if (line == 0) {
                writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
                writeb(irq, MCF_MBAR + MCFUART_BASE1 + MCFUART_UIVR);
-               mcf_clrimr(MCFINTC_UART0);
+               mcf_mapirq2imr(irq, MCFINTC_UART0);
        } else if (line == 1) {
                writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
                writeb(irq, MCF_MBAR + MCFUART_BASE2 + MCFUART_UIVR);
-               mcf_clrimr(MCFINTC_UART1);
+               mcf_mapirq2imr(irq, MCFINTC_UART1);
        }
 }
 
@@ -72,11 +72,13 @@ static void __init m5249_timers_init(void)
        /* Timer1 is always used as system timer */
        writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3,
                MCF_MBAR + MCFSIM_TIMER1ICR);
+       mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1);
 
 #ifdef CONFIG_HIGHPROFILE
        /* Timer2 is to be used as a high speed profile timer  */
        writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3,
                MCF_MBAR + MCFSIM_TIMER2ICR);
+       mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2);
 #endif
 }
 
@@ -97,13 +99,13 @@ void __init config_BSP(char *commandp, int size)
 {
        mach_reset = m5249_cpu_reset;
        m5249_timers_init();
+       m5249_uarts_init();
 }
 
 /***************************************************************************/
 
 static int __init init_BSP(void)
 {
-       m5249_uarts_init();
        platform_add_devices(m5249_devices, ARRAY_SIZE(m5249_devices));
        return 0;
 }
index b711597ac8e1e48bb7fdb9e1aadb4967a472a75a..00900ac06a9c9e4cdb51780b5741447c940a5e6a 100644 (file)
@@ -58,11 +58,11 @@ static void __init m5307_uart_init_line(int line, int irq)
        if (line == 0) {
                writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
                writeb(irq, MCF_MBAR + MCFUART_BASE1 + MCFUART_UIVR);
-               mcf_clrimr(MCFINTC_UART0);
+               mcf_mapirq2imr(irq, MCFINTC_UART0);
        } else if (line == 1) {
                writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
                writeb(irq, MCF_MBAR + MCFUART_BASE2 + MCFUART_UIVR);
-               mcf_clrimr(MCFINTC_UART1);
+               mcf_mapirq2imr(irq, MCFINTC_UART1);
        }
 }
 
@@ -82,11 +82,13 @@ static void __init m5307_timers_init(void)
        /* Timer1 is always used as system timer */
        writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3,
                MCF_MBAR + MCFSIM_TIMER1ICR);
+       mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1);
 
 #ifdef CONFIG_HIGHPROFILE
        /* Timer2 is to be used as a high speed profile timer  */
        writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3,
                MCF_MBAR + MCFSIM_TIMER2ICR);
+       mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2);
 #endif
 }
 
@@ -114,6 +116,13 @@ void __init config_BSP(char *commandp, int size)
 
        mach_reset = m5307_cpu_reset;
        m5307_timers_init();
+       m5307_uarts_init();
+
+       /* Only support the external interrupts on their primary level */
+       mcf_mapirq2imr(25, MCFINTC_EINT1);
+       mcf_mapirq2imr(27, MCFINTC_EINT3);
+       mcf_mapirq2imr(29, MCFINTC_EINT5);
+       mcf_mapirq2imr(31, MCFINTC_EINT7);
 
 #ifdef CONFIG_BDM_DISABLE
        /*
@@ -129,7 +138,6 @@ void __init config_BSP(char *commandp, int size)
 
 static int __init init_BSP(void)
 {
-       m5307_uarts_init();
        platform_add_devices(m5307_devices, ARRAY_SIZE(m5307_devices));
        return 0;
 }
index cc80029a4a00d754025e37c7dd0ef3381b055d73..70ea789a400c7cfd0df53783b3dd61b539c05771 100644 (file)
@@ -49,12 +49,11 @@ static void __init m5407_uart_init_line(int line, int irq)
        if (line == 0) {
                writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
                writeb(irq, MCF_MBAR + MCFUART_BASE1 + MCFUART_UIVR);
-               mcf_clrimr(MCFINTC_UART0);
+               mcf_mapirq2imr(irq, MCFINTC_UART0);
        } else if (line == 1) {
                writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
                writeb(irq, MCF_MBAR + MCFUART_BASE2 + MCFUART_UIVR);
-               mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART2);
-               mcf_clrimr(MCFINTC_UART1);
+               mcf_mapirq2imr(irq, MCFINTC_UART1);
        }
 }
 
@@ -74,11 +73,13 @@ static void __init m5407_timers_init(void)
        /* Timer1 is always used as system timer */
        writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3,
                MCF_MBAR + MCFSIM_TIMER1ICR);
+       mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1);
 
 #ifdef CONFIG_HIGHPROFILE
        /* Timer2 is to be used as a high speed profile timer  */
        writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3,
                MCF_MBAR + MCFSIM_TIMER2ICR);
+       mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2);
 #endif
 }
 
@@ -99,13 +100,19 @@ void __init config_BSP(char *commandp, int size)
 {
        mach_reset = m5407_cpu_reset;
        m5407_timers_init();
+       m5407_uarts_init();
+
+       /* Only support the external interrupts on their primary level */
+       mcf_mapirq2imr(25, MCFINTC_EINT1);
+       mcf_mapirq2imr(27, MCFINTC_EINT3);
+       mcf_mapirq2imr(29, MCFINTC_EINT5);
+       mcf_mapirq2imr(31, MCFINTC_EINT7);
 }
 
 /***************************************************************************/
 
 static int __init init_BSP(void)
 {
-       m5407_uarts_init();
        platform_add_devices(m5407_devices, ARRAY_SIZE(m5407_devices));
        return 0;
 }
index 14db26bf6e2f29e0103704041eec38a5a82108d2..a4560c86db714f121074c7543ae300ed7bad8a41 100644 (file)
 #include <asm/mcfsim.h>
 
 /*
- * Define the vector numbers for the basic 7 interrupt sources.
- * These are often referred to as the "external" interrupts in
- * the ColdFire documentation (for the early ColdFire cores at least).
+ * The mapping of irq number to a mask register bit is not one-to-one.
+ * The irq numbers are either based on "level" of interrupt or fixed
+ * for an autovector-able interrupt. So we keep a local data structure
+ * that maps from irq to mask register. Not all interrupts will have
+ * an IMR bit.
+ */
+unsigned char mcf_irq2imr[NR_IRQS];
+
+/*
+ * Define the miniumun and maximum external interrupt numbers.
+ * This is also used as the "level" interrupt numbers.
  */
 #define        EIRQ1   25
 #define        EIRQ7   31
 
 void mcf_setimr(int index)
 {
-        u16 imr;
-        imr = __raw_readw(MCF_MBAR + MCFSIM_IMR);
+       u16 imr;
+       imr = __raw_readw(MCF_MBAR + MCFSIM_IMR);
        __raw_writew(imr | (0x1 << index), MCF_MBAR + MCFSIM_IMR);
 }
 
 void mcf_clrimr(int index)
 {
-        u16 imr;
-        imr = __raw_readw(MCF_MBAR + MCFSIM_IMR);
+       u16 imr;
+       imr = __raw_readw(MCF_MBAR + MCFSIM_IMR);
        __raw_writew(imr & ~(0x1 << index), MCF_MBAR + MCFSIM_IMR);
 }
 
 void mcf_maskimr(unsigned int mask)
 {
        u16 imr;
-        imr = __raw_readw(MCF_MBAR + MCFSIM_IMR);
+       imr = __raw_readw(MCF_MBAR + MCFSIM_IMR);
        imr |= mask;
        __raw_writew(imr, MCF_MBAR + MCFSIM_IMR);
 }
@@ -60,22 +68,22 @@ void mcf_maskimr(unsigned int mask)
 
 void mcf_setimr(int index)
 {
-        u32 imr;
-        imr = __raw_readl(MCF_MBAR + MCFSIM_IMR);
+       u32 imr;
+       imr = __raw_readl(MCF_MBAR + MCFSIM_IMR);
        __raw_writel(imr | (0x1 << index), MCF_MBAR + MCFSIM_IMR);
 }
 
 void mcf_clrimr(int index)
 {
-        u32 imr;
-        imr = __raw_readl(MCF_MBAR + MCFSIM_IMR);
+       u32 imr;
+       imr = __raw_readl(MCF_MBAR + MCFSIM_IMR);
        __raw_writel(imr & ~(0x1 << index), MCF_MBAR + MCFSIM_IMR);
 }
 
 void mcf_maskimr(unsigned int mask)
 {
        u32 imr;
-        imr = __raw_readl(MCF_MBAR + MCFSIM_IMR);
+       imr = __raw_readl(MCF_MBAR + MCFSIM_IMR);
        imr |= mask;
        __raw_writel(imr, MCF_MBAR + MCFSIM_IMR);
 }
@@ -93,24 +101,26 @@ void mcf_maskimr(unsigned int mask)
  */
 void mcf_autovector(int irq)
 {
+#ifdef MCFSIM_AVR
        if ((irq >= EIRQ1) && (irq <= EIRQ7)) {
                u8 avec;
                avec = __raw_readb(MCF_MBAR + MCFSIM_AVR);
                avec |= (0x1 << (irq - EIRQ1 + 1));
                __raw_writeb(avec, MCF_MBAR + MCFSIM_AVR);
        }
+#endif
 }
 
 static void intc_irq_mask(unsigned int irq)
 {
-       if ((irq >= EIRQ1) && (irq <= EIRQ7))
-               mcf_setimr(irq - EIRQ1 + 1);
+       if (mcf_irq2imr[irq])
+               mcf_setimr(mcf_irq2imr[irq]);
 }
 
 static void intc_irq_unmask(unsigned int irq)
 {
-       if ((irq >= EIRQ1) && (irq <= EIRQ7))
-               mcf_clrimr(irq - EIRQ1 + 1);
+       if (mcf_irq2imr[irq])
+               mcf_clrimr(mcf_irq2imr[irq]);
 }
 
 static int intc_irq_set_type(unsigned int irq, unsigned int type)