Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

m68knommu: map ColdFire interrupts to correct masking bits

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>

+90 -39
+16 -6
arch/m68k/include/asm/mcfintc.h
··· 25 25 */ 26 26 27 27 /* 28 - * Define the base address of the SIM within the MBAR address space. 29 - */ 30 - #define MCFSIM_BASE 0x0 /* Base address within SIM */ 31 - 32 - /* 33 28 * Bit definitions for the ICR family of registers. 34 29 */ 35 30 #define MCFSIM_ICR_AUTOVEC 0x80 /* Auto-vectored intr */ ··· 43 48 #define MCFSIM_ICR_PRI3 0x03 /* Priority 3 intr */ 44 49 45 50 /* 46 - * IMR bit position definitions. 51 + * IMR bit position definitions. Not all ColdFire parts with this interrupt 52 + * controller actually support all of these interrupt sources. But the bit 53 + * numbers are the same in all cores. 47 54 */ 48 55 #define MCFINTC_EINT1 1 /* External int #1 */ 49 56 #define MCFINTC_EINT2 2 /* External int #2 */ ··· 67 70 #define MCFINTC_QSPI 18 68 71 69 72 #ifndef __ASSEMBLER__ 73 + 74 + /* 75 + * There is no one-is-one correspondance between the interrupt number (irq) 76 + * and the bit fields on the mask register. So we create a per-cpu type 77 + * mapping of irq to mask bit. The CPU platform code needs to register 78 + * its supported irq's at init time, using this function. 79 + */ 80 + extern unsigned char mcf_irq2imr[]; 81 + static inline void mcf_mapirq2imr(int irq, int imr) 82 + { 83 + mcf_irq2imr[irq] = imr; 84 + } 85 + 70 86 void mcf_autovector(int irq); 71 87 void mcf_setimr(int index); 72 88 void mcf_clrimr(int index);
+10 -3
arch/m68knommu/platform/5206/config.c
··· 49 49 if (line == 0) { 50 50 writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR); 51 51 writeb(irq, MCFUART_BASE1 + MCFUART_UIVR); 52 - mcf_clrimr(MCFINTC_UART0); 52 + mcf_mapirq2imr(irq, MCFINTC_UART0); 53 53 } else if (line == 1) { 54 54 writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR); 55 55 writeb(irq, MCFUART_BASE2 + MCFUART_UIVR); 56 - mcf_clrimr(MCFINTC_UART1); 56 + mcf_mapirq2imr(irq, MCFINTC_UART1); 57 57 } 58 58 } 59 59 ··· 73 73 /* Timer1 is always used as system timer */ 74 74 writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3, 75 75 MCF_MBAR + MCFSIM_TIMER1ICR); 76 + mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1); 76 77 77 78 #ifdef CONFIG_HIGHPROFILE 78 79 /* Timer2 is to be used as a high speed profile timer */ 79 80 writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3, 80 81 MCF_MBAR + MCFSIM_TIMER2ICR); 82 + mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2); 81 83 #endif 82 84 } 83 85 ··· 100 98 { 101 99 mach_reset = m5206_cpu_reset; 102 100 m5206_timers_init(); 101 + m5206_uarts_init(); 102 + 103 + /* Only support the external interrupts on their primary level */ 104 + mcf_mapirq2imr(25, MCFINTC_EINT1); 105 + mcf_mapirq2imr(28, MCFINTC_EINT4); 106 + mcf_mapirq2imr(31, MCFINTC_EINT7); 103 107 } 104 108 105 109 /***************************************************************************/ 106 110 107 111 static int __init init_BSP(void) 108 112 { 109 - m5206_uarts_init(); 110 113 platform_add_devices(m5206_devices, ARRAY_SIZE(m5206_devices)); 111 114 return 0; 112 115 }
+10 -3
arch/m68knommu/platform/5206e/config.c
··· 50 50 if (line == 0) { 51 51 writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR); 52 52 writeb(irq, MCFUART_BASE1 + MCFUART_UIVR); 53 - mcf_clrimr(MCFINTC_UART0); 53 + mcf_mapirq2imr(irq, MCFINTC_UART0); 54 54 } else if (line == 1) { 55 55 writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR); 56 56 writeb(irq, MCFUART_BASE2 + MCFUART_UIVR); 57 - mcf_clrimr(MCFINTC_UART1); 57 + mcf_mapirq2imr(irq, MCFINTC_UART1); 58 58 } 59 59 } 60 60 ··· 74 74 /* Timer1 is always used as system timer */ 75 75 writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3, 76 76 MCF_MBAR + MCFSIM_TIMER1ICR); 77 + mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1); 77 78 78 79 #ifdef CONFIG_HIGHPROFILE 79 80 /* Timer2 is to be used as a high speed profile timer */ 80 81 writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3, 81 82 MCF_MBAR + MCFSIM_TIMER2ICR); 83 + mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2); 82 84 #endif 83 85 } 84 86 ··· 107 105 108 106 mach_reset = m5206e_cpu_reset; 109 107 m5206e_timers_init(); 108 + m5206e_uarts_init(); 109 + 110 + /* Only support the external interrupts on their primary level */ 111 + mcf_mapirq2imr(25, MCFINTC_EINT1); 112 + mcf_mapirq2imr(28, MCFINTC_EINT4); 113 + mcf_mapirq2imr(31, MCFINTC_EINT7); 110 114 } 111 115 112 116 /***************************************************************************/ 113 117 114 118 static int __init init_BSP(void) 115 119 { 116 - m5206e_uarts_init(); 117 120 platform_add_devices(m5206e_devices, ARRAY_SIZE(m5206e_devices)); 118 121 return 0; 119 122 }
+5 -3
arch/m68knommu/platform/5249/config.c
··· 48 48 if (line == 0) { 49 49 writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR); 50 50 writeb(irq, MCF_MBAR + MCFUART_BASE1 + MCFUART_UIVR); 51 - mcf_clrimr(MCFINTC_UART0); 51 + mcf_mapirq2imr(irq, MCFINTC_UART0); 52 52 } else if (line == 1) { 53 53 writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR); 54 54 writeb(irq, MCF_MBAR + MCFUART_BASE2 + MCFUART_UIVR); 55 - mcf_clrimr(MCFINTC_UART1); 55 + mcf_mapirq2imr(irq, MCFINTC_UART1); 56 56 } 57 57 } 58 58 ··· 72 72 /* Timer1 is always used as system timer */ 73 73 writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3, 74 74 MCF_MBAR + MCFSIM_TIMER1ICR); 75 + mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1); 75 76 76 77 #ifdef CONFIG_HIGHPROFILE 77 78 /* Timer2 is to be used as a high speed profile timer */ 78 79 writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3, 79 80 MCF_MBAR + MCFSIM_TIMER2ICR); 81 + mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2); 80 82 #endif 81 83 } 82 84 ··· 99 97 { 100 98 mach_reset = m5249_cpu_reset; 101 99 m5249_timers_init(); 100 + m5249_uarts_init(); 102 101 } 103 102 104 103 /***************************************************************************/ 105 104 106 105 static int __init init_BSP(void) 107 106 { 108 - m5249_uarts_init(); 109 107 platform_add_devices(m5249_devices, ARRAY_SIZE(m5249_devices)); 110 108 return 0; 111 109 }
+11 -3
arch/m68knommu/platform/5307/config.c
··· 58 58 if (line == 0) { 59 59 writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR); 60 60 writeb(irq, MCF_MBAR + MCFUART_BASE1 + MCFUART_UIVR); 61 - mcf_clrimr(MCFINTC_UART0); 61 + mcf_mapirq2imr(irq, MCFINTC_UART0); 62 62 } else if (line == 1) { 63 63 writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR); 64 64 writeb(irq, MCF_MBAR + MCFUART_BASE2 + MCFUART_UIVR); 65 - mcf_clrimr(MCFINTC_UART1); 65 + mcf_mapirq2imr(irq, MCFINTC_UART1); 66 66 } 67 67 } 68 68 ··· 82 82 /* Timer1 is always used as system timer */ 83 83 writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3, 84 84 MCF_MBAR + MCFSIM_TIMER1ICR); 85 + mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1); 85 86 86 87 #ifdef CONFIG_HIGHPROFILE 87 88 /* Timer2 is to be used as a high speed profile timer */ 88 89 writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3, 89 90 MCF_MBAR + MCFSIM_TIMER2ICR); 91 + mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2); 90 92 #endif 91 93 } 92 94 ··· 116 114 117 115 mach_reset = m5307_cpu_reset; 118 116 m5307_timers_init(); 117 + m5307_uarts_init(); 118 + 119 + /* Only support the external interrupts on their primary level */ 120 + mcf_mapirq2imr(25, MCFINTC_EINT1); 121 + mcf_mapirq2imr(27, MCFINTC_EINT3); 122 + mcf_mapirq2imr(29, MCFINTC_EINT5); 123 + mcf_mapirq2imr(31, MCFINTC_EINT7); 119 124 120 125 #ifdef CONFIG_BDM_DISABLE 121 126 /* ··· 138 129 139 130 static int __init init_BSP(void) 140 131 { 141 - m5307_uarts_init(); 142 132 platform_add_devices(m5307_devices, ARRAY_SIZE(m5307_devices)); 143 133 return 0; 144 134 }
+11 -4
arch/m68knommu/platform/5407/config.c
··· 49 49 if (line == 0) { 50 50 writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR); 51 51 writeb(irq, MCF_MBAR + MCFUART_BASE1 + MCFUART_UIVR); 52 - mcf_clrimr(MCFINTC_UART0); 52 + mcf_mapirq2imr(irq, MCFINTC_UART0); 53 53 } else if (line == 1) { 54 54 writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR); 55 55 writeb(irq, MCF_MBAR + MCFUART_BASE2 + MCFUART_UIVR); 56 - mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART2); 57 - mcf_clrimr(MCFINTC_UART1); 56 + mcf_mapirq2imr(irq, MCFINTC_UART1); 58 57 } 59 58 } 60 59 ··· 73 74 /* Timer1 is always used as system timer */ 74 75 writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3, 75 76 MCF_MBAR + MCFSIM_TIMER1ICR); 77 + mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1); 76 78 77 79 #ifdef CONFIG_HIGHPROFILE 78 80 /* Timer2 is to be used as a high speed profile timer */ 79 81 writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3, 80 82 MCF_MBAR + MCFSIM_TIMER2ICR); 83 + mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2); 81 84 #endif 82 85 } 83 86 ··· 100 99 { 101 100 mach_reset = m5407_cpu_reset; 102 101 m5407_timers_init(); 102 + m5407_uarts_init(); 103 + 104 + /* Only support the external interrupts on their primary level */ 105 + mcf_mapirq2imr(25, MCFINTC_EINT1); 106 + mcf_mapirq2imr(27, MCFINTC_EINT3); 107 + mcf_mapirq2imr(29, MCFINTC_EINT5); 108 + mcf_mapirq2imr(31, MCFINTC_EINT7); 103 109 } 104 110 105 111 /***************************************************************************/ 106 112 107 113 static int __init init_BSP(void) 108 114 { 109 - m5407_uarts_init(); 110 115 platform_add_devices(m5407_devices, ARRAY_SIZE(m5407_devices)); 111 116 return 0; 112 117 }
+27 -17
arch/m68knommu/platform/coldfire/intc.c
··· 19 19 #include <asm/mcfsim.h> 20 20 21 21 /* 22 - * Define the vector numbers for the basic 7 interrupt sources. 23 - * These are often referred to as the "external" interrupts in 24 - * the ColdFire documentation (for the early ColdFire cores at least). 22 + * The mapping of irq number to a mask register bit is not one-to-one. 23 + * The irq numbers are either based on "level" of interrupt or fixed 24 + * for an autovector-able interrupt. So we keep a local data structure 25 + * that maps from irq to mask register. Not all interrupts will have 26 + * an IMR bit. 27 + */ 28 + unsigned char mcf_irq2imr[NR_IRQS]; 29 + 30 + /* 31 + * Define the miniumun and maximum external interrupt numbers. 32 + * This is also used as the "level" interrupt numbers. 25 33 */ 26 34 #define EIRQ1 25 27 35 #define EIRQ7 31 ··· 44 36 45 37 void mcf_setimr(int index) 46 38 { 47 - u16 imr; 48 - imr = __raw_readw(MCF_MBAR + MCFSIM_IMR); 39 + u16 imr; 40 + imr = __raw_readw(MCF_MBAR + MCFSIM_IMR); 49 41 __raw_writew(imr | (0x1 << index), MCF_MBAR + MCFSIM_IMR); 50 42 } 51 43 52 44 void mcf_clrimr(int index) 53 45 { 54 - u16 imr; 55 - imr = __raw_readw(MCF_MBAR + MCFSIM_IMR); 46 + u16 imr; 47 + imr = __raw_readw(MCF_MBAR + MCFSIM_IMR); 56 48 __raw_writew(imr & ~(0x1 << index), MCF_MBAR + MCFSIM_IMR); 57 49 } 58 50 59 51 void mcf_maskimr(unsigned int mask) 60 52 { 61 53 u16 imr; 62 - imr = __raw_readw(MCF_MBAR + MCFSIM_IMR); 54 + imr = __raw_readw(MCF_MBAR + MCFSIM_IMR); 63 55 imr |= mask; 64 56 __raw_writew(imr, MCF_MBAR + MCFSIM_IMR); 65 57 } ··· 68 60 69 61 void mcf_setimr(int index) 70 62 { 71 - u32 imr; 72 - imr = __raw_readl(MCF_MBAR + MCFSIM_IMR); 63 + u32 imr; 64 + imr = __raw_readl(MCF_MBAR + MCFSIM_IMR); 73 65 __raw_writel(imr | (0x1 << index), MCF_MBAR + MCFSIM_IMR); 74 66 } 75 67 76 68 void mcf_clrimr(int index) 77 69 { 78 - u32 imr; 79 - imr = __raw_readl(MCF_MBAR + MCFSIM_IMR); 70 + u32 imr; 71 + imr = __raw_readl(MCF_MBAR + MCFSIM_IMR); 80 72 __raw_writel(imr & ~(0x1 << index), MCF_MBAR + MCFSIM_IMR); 81 73 } 82 74 83 75 void mcf_maskimr(unsigned int mask) 84 76 { 85 77 u32 imr; 86 - imr = __raw_readl(MCF_MBAR + MCFSIM_IMR); 78 + imr = __raw_readl(MCF_MBAR + MCFSIM_IMR); 87 79 imr |= mask; 88 80 __raw_writel(imr, MCF_MBAR + MCFSIM_IMR); 89 81 } ··· 101 93 */ 102 94 void mcf_autovector(int irq) 103 95 { 96 + #ifdef MCFSIM_AVR 104 97 if ((irq >= EIRQ1) && (irq <= EIRQ7)) { 105 98 u8 avec; 106 99 avec = __raw_readb(MCF_MBAR + MCFSIM_AVR); 107 100 avec |= (0x1 << (irq - EIRQ1 + 1)); 108 101 __raw_writeb(avec, MCF_MBAR + MCFSIM_AVR); 109 102 } 103 + #endif 110 104 } 111 105 112 106 static void intc_irq_mask(unsigned int irq) 113 107 { 114 - if ((irq >= EIRQ1) && (irq <= EIRQ7)) 115 - mcf_setimr(irq - EIRQ1 + 1); 108 + if (mcf_irq2imr[irq]) 109 + mcf_setimr(mcf_irq2imr[irq]); 116 110 } 117 111 118 112 static void intc_irq_unmask(unsigned int irq) 119 113 { 120 - if ((irq >= EIRQ1) && (irq <= EIRQ7)) 121 - mcf_clrimr(irq - EIRQ1 + 1); 114 + if (mcf_irq2imr[irq]) 115 + mcf_clrimr(mcf_irq2imr[irq]); 122 116 } 123 117 124 118 static int intc_irq_set_type(unsigned int irq, unsigned int type)