irq_intc2.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /*
  2. * linux/arch/sh/kernel/irq_intc2.c
  3. *
  4. * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
  5. *
  6. * May be copied or modified under the terms of the GNU General Public
  7. * License. See linux/COPYING for more information.
  8. *
  9. * Interrupt handling for INTC2-based IRQ.
  10. *
  11. * These are the "new Hitachi style" interrupts, as present on the
  12. * Hitachi 7751 and the STM ST40 STB1.
  13. */
  14. #include <linux/kernel.h>
  15. #include <linux/init.h>
  16. #include <linux/irq.h>
  17. #include <asm/system.h>
  18. #include <asm/io.h>
  19. #include <asm/machvec.h>
  20. struct intc2_data {
  21. unsigned char msk_offset;
  22. unsigned char msk_shift;
  23. #ifdef CONFIG_CPU_SUBTYPE_ST40
  24. int (*clear_irq) (int);
  25. #endif
  26. };
  27. static struct intc2_data intc2_data[NR_INTC2_IRQS];
  28. static void enable_intc2_irq(unsigned int irq);
  29. static void disable_intc2_irq(unsigned int irq);
  30. /* shutdown is same as "disable" */
  31. #define shutdown_intc2_irq disable_intc2_irq
  32. static void mask_and_ack_intc2(unsigned int);
  33. static void end_intc2_irq(unsigned int irq);
  34. static unsigned int startup_intc2_irq(unsigned int irq)
  35. {
  36. enable_intc2_irq(irq);
  37. return 0; /* never anything pending */
  38. }
  39. static struct hw_interrupt_type intc2_irq_type = {
  40. .typename = "INTC2-IRQ",
  41. .startup = startup_intc2_irq,
  42. .shutdown = shutdown_intc2_irq,
  43. .enable = enable_intc2_irq,
  44. .disable = disable_intc2_irq,
  45. .ack = mask_and_ack_intc2,
  46. .end = end_intc2_irq
  47. };
  48. static void disable_intc2_irq(unsigned int irq)
  49. {
  50. int irq_offset = irq - INTC2_FIRST_IRQ;
  51. int msk_shift, msk_offset;
  52. // Sanity check
  53. if((irq_offset<0) || (irq_offset>=NR_INTC2_IRQS))
  54. return;
  55. msk_shift = intc2_data[irq_offset].msk_shift;
  56. msk_offset = intc2_data[irq_offset].msk_offset;
  57. ctrl_outl(1<<msk_shift,
  58. INTC2_BASE+INTC2_INTMSK_OFFSET+msk_offset);
  59. }
  60. static void enable_intc2_irq(unsigned int irq)
  61. {
  62. int irq_offset = irq - INTC2_FIRST_IRQ;
  63. int msk_shift, msk_offset;
  64. /* Sanity check */
  65. if((irq_offset<0) || (irq_offset>=NR_INTC2_IRQS))
  66. return;
  67. msk_shift = intc2_data[irq_offset].msk_shift;
  68. msk_offset = intc2_data[irq_offset].msk_offset;
  69. ctrl_outl(1<<msk_shift,
  70. INTC2_BASE+INTC2_INTMSKCLR_OFFSET+msk_offset);
  71. }
  72. static void mask_and_ack_intc2(unsigned int irq)
  73. {
  74. disable_intc2_irq(irq);
  75. }
  76. static void end_intc2_irq(unsigned int irq)
  77. {
  78. if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
  79. enable_intc2_irq(irq);
  80. #ifdef CONFIG_CPU_SUBTYPE_ST40
  81. if (intc2_data[irq - INTC2_FIRST_IRQ].clear_irq)
  82. intc2_data[irq - INTC2_FIRST_IRQ].clear_irq (irq);
  83. #endif
  84. }
  85. /*
  86. * Setup an INTC2 style interrupt.
  87. * NOTE: Unlike IPR interrupts, parameters are not shifted by this code,
  88. * allowing the use of the numbers straight out of the datasheet.
  89. * For example:
  90. * PIO1 which is INTPRI00[19,16] and INTMSK00[13]
  91. * would be: ^ ^ ^ ^
  92. * | | | |
  93. * make_intc2_irq(84, 0, 16, 0, 13);
  94. */
  95. void make_intc2_irq(unsigned int irq,
  96. unsigned int ipr_offset, unsigned int ipr_shift,
  97. unsigned int msk_offset, unsigned int msk_shift,
  98. unsigned int priority)
  99. {
  100. int irq_offset = irq - INTC2_FIRST_IRQ;
  101. unsigned int flags;
  102. unsigned long ipr;
  103. if((irq_offset<0) || (irq_offset>=NR_INTC2_IRQS))
  104. return;
  105. disable_irq_nosync(irq);
  106. /* Fill the data we need */
  107. intc2_data[irq_offset].msk_offset = msk_offset;
  108. intc2_data[irq_offset].msk_shift = msk_shift;
  109. #ifdef CONFIG_CPU_SUBTYPE_ST40
  110. intc2_data[irq_offset].clear_irq = NULL;
  111. #endif
  112. /* Set the priority level */
  113. local_irq_save(flags);
  114. ipr=ctrl_inl(INTC2_BASE+INTC2_INTPRI_OFFSET+ipr_offset);
  115. ipr&=~(0xf<<ipr_shift);
  116. ipr|=(priority)<<ipr_shift;
  117. ctrl_outl(ipr, INTC2_BASE+INTC2_INTPRI_OFFSET+ipr_offset);
  118. local_irq_restore(flags);
  119. irq_desc[irq].handler=&intc2_irq_type;
  120. disable_intc2_irq(irq);
  121. }
  122. #ifdef CONFIG_CPU_SUBTYPE_ST40
  123. struct intc2_init {
  124. unsigned short irq;
  125. unsigned char ipr_offset, ipr_shift;
  126. unsigned char msk_offset, msk_shift;
  127. };
  128. static struct intc2_init intc2_init_data[] __initdata = {
  129. {64, 0, 0, 0, 0}, /* PCI serr */
  130. {65, 0, 4, 0, 1}, /* PCI err */
  131. {66, 0, 4, 0, 2}, /* PCI ad */
  132. {67, 0, 4, 0, 3}, /* PCI pwd down */
  133. {72, 0, 8, 0, 5}, /* DMAC INT0 */
  134. {73, 0, 8, 0, 6}, /* DMAC INT1 */
  135. {74, 0, 8, 0, 7}, /* DMAC INT2 */
  136. {75, 0, 8, 0, 8}, /* DMAC INT3 */
  137. {76, 0, 8, 0, 9}, /* DMAC INT4 */
  138. {78, 0, 8, 0, 11}, /* DMAC ERR */
  139. {80, 0, 12, 0, 12}, /* PIO0 */
  140. {84, 0, 16, 0, 13}, /* PIO1 */
  141. {88, 0, 20, 0, 14}, /* PIO2 */
  142. {112, 4, 0, 4, 0}, /* Mailbox */
  143. #ifdef CONFIG_CPU_SUBTYPE_ST40GX1
  144. {116, 4, 4, 4, 4}, /* SSC0 */
  145. {120, 4, 8, 4, 8}, /* IR Blaster */
  146. {124, 4, 12, 4, 12}, /* USB host */
  147. {128, 4, 16, 4, 16}, /* Video processor BLITTER */
  148. {132, 4, 20, 4, 20}, /* UART0 */
  149. {134, 4, 20, 4, 22}, /* UART2 */
  150. {136, 4, 24, 4, 24}, /* IO_PIO0 */
  151. {140, 4, 28, 4, 28}, /* EMPI */
  152. {144, 8, 0, 8, 0}, /* MAFE */
  153. {148, 8, 4, 8, 4}, /* PWM */
  154. {152, 8, 8, 8, 8}, /* SSC1 */
  155. {156, 8, 12, 8, 12}, /* IO_PIO1 */
  156. {160, 8, 16, 8, 16}, /* USB target */
  157. {164, 8, 20, 8, 20}, /* UART1 */
  158. {168, 8, 24, 8, 24}, /* Teletext */
  159. {172, 8, 28, 8, 28}, /* VideoSync VTG */
  160. {173, 8, 28, 8, 29}, /* VideoSync DVP0 */
  161. {174, 8, 28, 8, 30}, /* VideoSync DVP1 */
  162. #endif
  163. };
  164. void __init init_IRQ_intc2(void)
  165. {
  166. struct intc2_init *p;
  167. printk(KERN_ALERT "init_IRQ_intc2\n");
  168. for (p = intc2_init_data;
  169. p<intc2_init_data+ARRAY_SIZE(intc2_init_data);
  170. p++) {
  171. make_intc2_irq(p->irq, p->ipr_offset, p->ipr_shift,
  172. p-> msk_offset, p->msk_shift, 13);
  173. }
  174. }
  175. /* Adds a termination callback to the interrupt */
  176. void intc2_add_clear_irq(int irq, int (*fn)(int))
  177. {
  178. if (irq < INTC2_FIRST_IRQ)
  179. return;
  180. intc2_data[irq - INTC2_FIRST_IRQ].clear_irq = fn;
  181. }
  182. #endif /* CONFIG_CPU_SUBTYPE_ST40 */