root/arch/m68k/coldfire/intc-5272.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. intc_irq_mask
  2. intc_irq_unmask
  3. intc_irq_ack
  4. intc_irq_set_type
  5. intc_external_irq
  6. init_IRQ

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

/* [<][>][^][v][top][bottom][index][help] */