intc-5272.c 5.8 KB

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