irq.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. /*
  2. * Copyright (C) 2000 David J. Mckay (david.mckay@st.com)
  3. *
  4. * May be copied or modified under the terms of the GNU General Public
  5. * License. See linux/COPYING for more information.
  6. *
  7. * Looks after interrupts on the overdrive board.
  8. *
  9. * Bases on the IPR irq system
  10. */
  11. #include <linux/config.h>
  12. #include <linux/init.h>
  13. #include <linux/irq.h>
  14. #include <asm/system.h>
  15. #include <asm/io.h>
  16. #include <asm/overdrive/overdrive.h>
  17. struct od_data {
  18. int overdrive_irq;
  19. int irq_mask;
  20. };
  21. #define NUM_EXTERNAL_IRQS 16
  22. #define EXTERNAL_IRQ_NOT_IN_USE (-1)
  23. #define EXTERNAL_IRQ_NOT_ASSIGNED (-1)
  24. /*
  25. * This table is used to determine what to program into the FPGA's CT register
  26. * for the specified Linux IRQ.
  27. *
  28. * The irq_mask gives the interrupt number from the PCI board (PCI_Int(6:0))
  29. * but is one greater than that because the because the FPGA treats 0
  30. * as disabled, a value of 1 asserts PCI_Int0, and so on.
  31. *
  32. * The overdrive_irq specifies which of the eight interrupt sources generates
  33. * that interrupt, and but is multiplied by four to give the bit offset into
  34. * the CT register.
  35. *
  36. * The seven interrupts levels (SH4 IRL's) we have available here is hardwired
  37. * by the EPLD. The assignments here of which PCI interrupt generates each
  38. * level is arbitary.
  39. */
  40. static struct od_data od_data_table[NUM_EXTERNAL_IRQS] = {
  41. /* overdrive_irq , irq_mask */
  42. {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 0 */
  43. {EXTERNAL_IRQ_NOT_ASSIGNED, 7}, /* 1 */
  44. {EXTERNAL_IRQ_NOT_ASSIGNED, 6}, /* 2 */
  45. {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 3 */
  46. {EXTERNAL_IRQ_NOT_ASSIGNED, 5}, /* 4 */
  47. {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 5 */
  48. {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 6 */
  49. {EXTERNAL_IRQ_NOT_ASSIGNED, 4}, /* 7 */
  50. {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 8 */
  51. {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 9 */
  52. {EXTERNAL_IRQ_NOT_ASSIGNED, 3}, /* 10 */
  53. {EXTERNAL_IRQ_NOT_ASSIGNED, 2}, /* 11 */
  54. {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 12 */
  55. {EXTERNAL_IRQ_NOT_ASSIGNED, 1}, /* 13 */
  56. {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 14 */
  57. {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE} /* 15 */
  58. };
  59. static void set_od_data(int overdrive_irq, int irq)
  60. {
  61. if (irq >= NUM_EXTERNAL_IRQS || irq < 0)
  62. return;
  63. od_data_table[irq].overdrive_irq = overdrive_irq << 2;
  64. }
  65. static void enable_od_irq(unsigned int irq);
  66. void disable_od_irq(unsigned int irq);
  67. /* shutdown is same as "disable" */
  68. #define shutdown_od_irq disable_od_irq
  69. static void mask_and_ack_od(unsigned int);
  70. static void end_od_irq(unsigned int irq);
  71. static unsigned int startup_od_irq(unsigned int irq)
  72. {
  73. enable_od_irq(irq);
  74. return 0; /* never anything pending */
  75. }
  76. static struct hw_interrupt_type od_irq_type = {
  77. "Overdrive-IRQ",
  78. startup_od_irq,
  79. shutdown_od_irq,
  80. enable_od_irq,
  81. disable_od_irq,
  82. mask_and_ack_od,
  83. end_od_irq
  84. };
  85. static void disable_od_irq(unsigned int irq)
  86. {
  87. unsigned val, flags;
  88. int overdrive_irq;
  89. unsigned mask;
  90. /* Not a valid interrupt */
  91. if (irq < 0 || irq >= NUM_EXTERNAL_IRQS)
  92. return;
  93. /* Is is necessary to use a cli here? Would a spinlock not be
  94. * mroe efficient?
  95. */
  96. local_irq_save(flags);
  97. overdrive_irq = od_data_table[irq].overdrive_irq;
  98. if (overdrive_irq != EXTERNAL_IRQ_NOT_ASSIGNED) {
  99. mask = ~(0x7 << overdrive_irq);
  100. val = ctrl_inl(OVERDRIVE_INT_CT);
  101. val &= mask;
  102. ctrl_outl(val, OVERDRIVE_INT_CT);
  103. }
  104. local_irq_restore(flags);
  105. }
  106. static void enable_od_irq(unsigned int irq)
  107. {
  108. unsigned val, flags;
  109. int overdrive_irq;
  110. unsigned mask;
  111. /* Not a valid interrupt */
  112. if (irq < 0 || irq >= NUM_EXTERNAL_IRQS)
  113. return;
  114. /* Set priority in OD back to original value */
  115. local_irq_save(flags);
  116. /* This one is not in use currently */
  117. overdrive_irq = od_data_table[irq].overdrive_irq;
  118. if (overdrive_irq != EXTERNAL_IRQ_NOT_ASSIGNED) {
  119. val = ctrl_inl(OVERDRIVE_INT_CT);
  120. mask = ~(0x7 << overdrive_irq);
  121. val &= mask;
  122. mask = od_data_table[irq].irq_mask << overdrive_irq;
  123. val |= mask;
  124. ctrl_outl(val, OVERDRIVE_INT_CT);
  125. }
  126. local_irq_restore(flags);
  127. }
  128. /* this functions sets the desired irq handler to be an overdrive type */
  129. static void __init make_od_irq(unsigned int irq)
  130. {
  131. disable_irq_nosync(irq);
  132. irq_desc[irq].handler = &od_irq_type;
  133. disable_od_irq(irq);
  134. }
  135. static void mask_and_ack_od(unsigned int irq)
  136. {
  137. disable_od_irq(irq);
  138. }
  139. static void end_od_irq(unsigned int irq)
  140. {
  141. enable_od_irq(irq);
  142. }
  143. void __init init_overdrive_irq(void)
  144. {
  145. int i;
  146. /* Disable all interrupts */
  147. ctrl_outl(0, OVERDRIVE_INT_CT);
  148. /* Update interrupt pin mode to use encoded interrupts */
  149. i = ctrl_inw(INTC_ICR);
  150. i &= ~INTC_ICR_IRLM;
  151. ctrl_outw(i, INTC_ICR);
  152. for (i = 0; i < NUM_EXTERNAL_IRQS; i++) {
  153. if (od_data_table[i].irq_mask != EXTERNAL_IRQ_NOT_IN_USE) {
  154. make_od_irq(i);
  155. } else if (i != 15) { // Cannot use imask on level 15
  156. make_imask_irq(i);
  157. }
  158. }
  159. /* Set up the interrupts */
  160. set_od_data(OVERDRIVE_PCI_INTA, OVERDRIVE_PCI_IRQ1);
  161. set_od_data(OVERDRIVE_PCI_INTB, OVERDRIVE_PCI_IRQ2);
  162. set_od_data(OVERDRIVE_AUDIO_INT, OVERDRIVE_ESS_IRQ);
  163. }