irq.c 5.1 KB

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