1f86b9e03SGreg Ungerer /* 2f86b9e03SGreg Ungerer * intc.c -- interrupt controller or ColdFire 5272 SoC 3f86b9e03SGreg Ungerer * 4f86b9e03SGreg Ungerer * (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com> 5f86b9e03SGreg Ungerer * 6f86b9e03SGreg Ungerer * This file is subject to the terms and conditions of the GNU General Public 7f86b9e03SGreg Ungerer * License. See the file COPYING in the main directory of this archive 8f86b9e03SGreg Ungerer * for more details. 9f86b9e03SGreg Ungerer */ 10f86b9e03SGreg Ungerer 11f86b9e03SGreg Ungerer #include <linux/types.h> 12f86b9e03SGreg Ungerer #include <linux/init.h> 13f86b9e03SGreg Ungerer #include <linux/kernel.h> 14f86b9e03SGreg Ungerer #include <linux/interrupt.h> 15f86b9e03SGreg Ungerer #include <linux/kernel_stat.h> 16f86b9e03SGreg Ungerer #include <linux/irq.h> 17f86b9e03SGreg Ungerer #include <linux/io.h> 18f86b9e03SGreg Ungerer #include <asm/coldfire.h> 19f86b9e03SGreg Ungerer #include <asm/mcfsim.h> 20f86b9e03SGreg Ungerer #include <asm/traps.h> 21f86b9e03SGreg Ungerer 22f86b9e03SGreg Ungerer /* 23f86b9e03SGreg Ungerer * The 5272 ColdFire interrupt controller is nothing like any other 24f86b9e03SGreg Ungerer * ColdFire interrupt controller - it truly is completely different. 25f86b9e03SGreg Ungerer * Given its age it is unlikely to be used on any other ColdFire CPU. 26f86b9e03SGreg Ungerer */ 27f86b9e03SGreg Ungerer 28f86b9e03SGreg Ungerer /* 29f86b9e03SGreg Ungerer * The masking and priproty setting of interrupts on the 5272 is done 30f86b9e03SGreg Ungerer * via a set of 4 "Interrupt Controller Registers" (ICR). There is a 31f86b9e03SGreg Ungerer * loose mapping of vector number to register and internal bits, but 32f86b9e03SGreg Ungerer * a table is the easiest and quickest way to map them. 33f86b9e03SGreg Ungerer * 34f86b9e03SGreg Ungerer * Note that the external interrupts are edge triggered (unlike the 35f86b9e03SGreg Ungerer * internal interrupt sources which are level triggered). Which means 36f86b9e03SGreg Ungerer * they also need acknowledging via acknowledge bits. 37f86b9e03SGreg Ungerer */ 38f86b9e03SGreg Ungerer struct irqmap { 39ecb6bdcdSGreg Ungerer unsigned int icr; 40f86b9e03SGreg Ungerer unsigned char index; 41f86b9e03SGreg Ungerer unsigned char ack; 42f86b9e03SGreg Ungerer }; 43f86b9e03SGreg Ungerer 44f86b9e03SGreg Ungerer static struct irqmap intc_irqmap[MCFINT_VECMAX - MCFINT_VECBASE] = { 45f86b9e03SGreg Ungerer /*MCF_IRQ_SPURIOUS*/ { .icr = 0, .index = 0, .ack = 0, }, 46f86b9e03SGreg Ungerer /*MCF_IRQ_EINT1*/ { .icr = MCFSIM_ICR1, .index = 28, .ack = 1, }, 47f86b9e03SGreg Ungerer /*MCF_IRQ_EINT2*/ { .icr = MCFSIM_ICR1, .index = 24, .ack = 1, }, 48f86b9e03SGreg Ungerer /*MCF_IRQ_EINT3*/ { .icr = MCFSIM_ICR1, .index = 20, .ack = 1, }, 49f86b9e03SGreg Ungerer /*MCF_IRQ_EINT4*/ { .icr = MCFSIM_ICR1, .index = 16, .ack = 1, }, 50f86b9e03SGreg Ungerer /*MCF_IRQ_TIMER1*/ { .icr = MCFSIM_ICR1, .index = 12, .ack = 0, }, 51f86b9e03SGreg Ungerer /*MCF_IRQ_TIMER2*/ { .icr = MCFSIM_ICR1, .index = 8, .ack = 0, }, 52f86b9e03SGreg Ungerer /*MCF_IRQ_TIMER3*/ { .icr = MCFSIM_ICR1, .index = 4, .ack = 0, }, 53f86b9e03SGreg Ungerer /*MCF_IRQ_TIMER4*/ { .icr = MCFSIM_ICR1, .index = 0, .ack = 0, }, 54f86b9e03SGreg Ungerer /*MCF_IRQ_UART1*/ { .icr = MCFSIM_ICR2, .index = 28, .ack = 0, }, 55f86b9e03SGreg Ungerer /*MCF_IRQ_UART2*/ { .icr = MCFSIM_ICR2, .index = 24, .ack = 0, }, 56f86b9e03SGreg Ungerer /*MCF_IRQ_PLIP*/ { .icr = MCFSIM_ICR2, .index = 20, .ack = 0, }, 57f86b9e03SGreg Ungerer /*MCF_IRQ_PLIA*/ { .icr = MCFSIM_ICR2, .index = 16, .ack = 0, }, 58f86b9e03SGreg Ungerer /*MCF_IRQ_USB0*/ { .icr = MCFSIM_ICR2, .index = 12, .ack = 0, }, 59f86b9e03SGreg Ungerer /*MCF_IRQ_USB1*/ { .icr = MCFSIM_ICR2, .index = 8, .ack = 0, }, 60f86b9e03SGreg Ungerer /*MCF_IRQ_USB2*/ { .icr = MCFSIM_ICR2, .index = 4, .ack = 0, }, 61f86b9e03SGreg Ungerer /*MCF_IRQ_USB3*/ { .icr = MCFSIM_ICR2, .index = 0, .ack = 0, }, 62f86b9e03SGreg Ungerer /*MCF_IRQ_USB4*/ { .icr = MCFSIM_ICR3, .index = 28, .ack = 0, }, 63f86b9e03SGreg Ungerer /*MCF_IRQ_USB5*/ { .icr = MCFSIM_ICR3, .index = 24, .ack = 0, }, 64f86b9e03SGreg Ungerer /*MCF_IRQ_USB6*/ { .icr = MCFSIM_ICR3, .index = 20, .ack = 0, }, 65f86b9e03SGreg Ungerer /*MCF_IRQ_USB7*/ { .icr = MCFSIM_ICR3, .index = 16, .ack = 0, }, 66f86b9e03SGreg Ungerer /*MCF_IRQ_DMA*/ { .icr = MCFSIM_ICR3, .index = 12, .ack = 0, }, 67f86b9e03SGreg Ungerer /*MCF_IRQ_ERX*/ { .icr = MCFSIM_ICR3, .index = 8, .ack = 0, }, 68f86b9e03SGreg Ungerer /*MCF_IRQ_ETX*/ { .icr = MCFSIM_ICR3, .index = 4, .ack = 0, }, 69f86b9e03SGreg Ungerer /*MCF_IRQ_ENTC*/ { .icr = MCFSIM_ICR3, .index = 0, .ack = 0, }, 70f86b9e03SGreg Ungerer /*MCF_IRQ_QSPI*/ { .icr = MCFSIM_ICR4, .index = 28, .ack = 0, }, 71f86b9e03SGreg Ungerer /*MCF_IRQ_EINT5*/ { .icr = MCFSIM_ICR4, .index = 24, .ack = 1, }, 72f86b9e03SGreg Ungerer /*MCF_IRQ_EINT6*/ { .icr = MCFSIM_ICR4, .index = 20, .ack = 1, }, 73f86b9e03SGreg Ungerer /*MCF_IRQ_SWTO*/ { .icr = MCFSIM_ICR4, .index = 16, .ack = 0, }, 74f86b9e03SGreg Ungerer }; 75f86b9e03SGreg Ungerer 76f86b9e03SGreg Ungerer /* 77f86b9e03SGreg Ungerer * The act of masking the interrupt also has a side effect of 'ack'ing 78f86b9e03SGreg Ungerer * an interrupt on this irq (for the external irqs). So this mask function 79f86b9e03SGreg Ungerer * is also an ack_mask function. 80f86b9e03SGreg Ungerer */ 81f86b9e03SGreg Ungerer static void intc_irq_mask(struct irq_data *d) 82f86b9e03SGreg Ungerer { 83f86b9e03SGreg Ungerer unsigned int irq = d->irq; 84f86b9e03SGreg Ungerer 85f86b9e03SGreg Ungerer if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) { 86f86b9e03SGreg Ungerer u32 v; 87f86b9e03SGreg Ungerer irq -= MCFINT_VECBASE; 88f86b9e03SGreg Ungerer v = 0x8 << intc_irqmap[irq].index; 89f86b9e03SGreg Ungerer writel(v, intc_irqmap[irq].icr); 90f86b9e03SGreg Ungerer } 91f86b9e03SGreg Ungerer } 92f86b9e03SGreg Ungerer 93f86b9e03SGreg Ungerer static void intc_irq_unmask(struct irq_data *d) 94f86b9e03SGreg Ungerer { 95f86b9e03SGreg Ungerer unsigned int irq = d->irq; 96f86b9e03SGreg Ungerer 97f86b9e03SGreg Ungerer if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) { 98f86b9e03SGreg Ungerer u32 v; 99f86b9e03SGreg Ungerer irq -= MCFINT_VECBASE; 100f86b9e03SGreg Ungerer v = 0xd << intc_irqmap[irq].index; 101f86b9e03SGreg Ungerer writel(v, intc_irqmap[irq].icr); 102f86b9e03SGreg Ungerer } 103f86b9e03SGreg Ungerer } 104f86b9e03SGreg Ungerer 105f86b9e03SGreg Ungerer static void intc_irq_ack(struct irq_data *d) 106f86b9e03SGreg Ungerer { 107f86b9e03SGreg Ungerer unsigned int irq = d->irq; 108f86b9e03SGreg Ungerer 109f86b9e03SGreg Ungerer /* Only external interrupts are acked */ 110f86b9e03SGreg Ungerer if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) { 111f86b9e03SGreg Ungerer irq -= MCFINT_VECBASE; 112f86b9e03SGreg Ungerer if (intc_irqmap[irq].ack) { 113f86b9e03SGreg Ungerer u32 v; 114f86b9e03SGreg Ungerer v = readl(intc_irqmap[irq].icr); 115f86b9e03SGreg Ungerer v &= (0x7 << intc_irqmap[irq].index); 116f86b9e03SGreg Ungerer v |= (0x8 << intc_irqmap[irq].index); 117f86b9e03SGreg Ungerer writel(v, intc_irqmap[irq].icr); 118f86b9e03SGreg Ungerer } 119f86b9e03SGreg Ungerer } 120f86b9e03SGreg Ungerer } 121f86b9e03SGreg Ungerer 122f86b9e03SGreg Ungerer static int intc_irq_set_type(struct irq_data *d, unsigned int type) 123f86b9e03SGreg Ungerer { 124f86b9e03SGreg Ungerer unsigned int irq = d->irq; 125f86b9e03SGreg Ungerer 126f86b9e03SGreg Ungerer if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) { 127f86b9e03SGreg Ungerer irq -= MCFINT_VECBASE; 128f86b9e03SGreg Ungerer if (intc_irqmap[irq].ack) { 129f86b9e03SGreg Ungerer u32 v; 130f86b9e03SGreg Ungerer v = readl(MCFSIM_PITR); 131f86b9e03SGreg Ungerer if (type == IRQ_TYPE_EDGE_FALLING) 132f86b9e03SGreg Ungerer v &= ~(0x1 << (32 - irq)); 133f86b9e03SGreg Ungerer else 134f86b9e03SGreg Ungerer v |= (0x1 << (32 - irq)); 135f86b9e03SGreg Ungerer writel(v, MCFSIM_PITR); 136f86b9e03SGreg Ungerer } 137f86b9e03SGreg Ungerer } 138f86b9e03SGreg Ungerer return 0; 139f86b9e03SGreg Ungerer } 140f86b9e03SGreg Ungerer 141f86b9e03SGreg Ungerer /* 142f86b9e03SGreg Ungerer * Simple flow handler to deal with the external edge triggered interrupts. 143f86b9e03SGreg Ungerer * We need to be careful with the masking/acking due to the side effects 144f86b9e03SGreg Ungerer * of masking an interrupt. 145f86b9e03SGreg Ungerer */ 146*bd0b9ac4SThomas Gleixner static void intc_external_irq(struct irq_desc *desc) 147f86b9e03SGreg Ungerer { 148f86b9e03SGreg Ungerer irq_desc_get_chip(desc)->irq_ack(&desc->irq_data); 149*bd0b9ac4SThomas Gleixner handle_simple_irq(desc); 150f86b9e03SGreg Ungerer } 151f86b9e03SGreg Ungerer 152f86b9e03SGreg Ungerer static struct irq_chip intc_irq_chip = { 153f86b9e03SGreg Ungerer .name = "CF-INTC", 154f86b9e03SGreg Ungerer .irq_mask = intc_irq_mask, 155f86b9e03SGreg Ungerer .irq_unmask = intc_irq_unmask, 156f86b9e03SGreg Ungerer .irq_mask_ack = intc_irq_mask, 157f86b9e03SGreg Ungerer .irq_ack = intc_irq_ack, 158f86b9e03SGreg Ungerer .irq_set_type = intc_irq_set_type, 159f86b9e03SGreg Ungerer }; 160f86b9e03SGreg Ungerer 161f86b9e03SGreg Ungerer void __init init_IRQ(void) 162f86b9e03SGreg Ungerer { 163f86b9e03SGreg Ungerer int irq, edge; 164f86b9e03SGreg Ungerer 165f86b9e03SGreg Ungerer /* Mask all interrupt sources */ 166f86b9e03SGreg Ungerer writel(0x88888888, MCFSIM_ICR1); 167f86b9e03SGreg Ungerer writel(0x88888888, MCFSIM_ICR2); 168f86b9e03SGreg Ungerer writel(0x88888888, MCFSIM_ICR3); 169f86b9e03SGreg Ungerer writel(0x88888888, MCFSIM_ICR4); 170f86b9e03SGreg Ungerer 171f86b9e03SGreg Ungerer for (irq = 0; (irq < NR_IRQS); irq++) { 172f86b9e03SGreg Ungerer irq_set_chip(irq, &intc_irq_chip); 173f86b9e03SGreg Ungerer edge = 0; 174f86b9e03SGreg Ungerer if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) 175f86b9e03SGreg Ungerer edge = intc_irqmap[irq - MCFINT_VECBASE].ack; 176f86b9e03SGreg Ungerer if (edge) { 177f86b9e03SGreg Ungerer irq_set_irq_type(irq, IRQ_TYPE_EDGE_RISING); 178f86b9e03SGreg Ungerer irq_set_handler(irq, intc_external_irq); 179f86b9e03SGreg Ungerer } else { 180f86b9e03SGreg Ungerer irq_set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH); 181f86b9e03SGreg Ungerer irq_set_handler(irq, handle_level_irq); 182f86b9e03SGreg Ungerer } 183f86b9e03SGreg Ungerer } 184f86b9e03SGreg Ungerer } 185f86b9e03SGreg Ungerer 186