cpc700_pic.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. /*
  2. * arch/ppc/syslib/cpc700_pic.c
  3. *
  4. * Interrupt controller support for IBM Spruce
  5. *
  6. * Authors: Mark Greer, Matt Porter, and Johnnie Peters
  7. * mgreer@mvista.com
  8. * mporter@mvista.com
  9. * jpeters@mvista.com
  10. *
  11. * 2001-2002 (c) MontaVista, Software, Inc. This file is licensed under
  12. * the terms of the GNU General Public License version 2. This program
  13. * is licensed "as is" without any warranty of any kind, whether express
  14. * or implied.
  15. */
  16. #include <linux/stddef.h>
  17. #include <linux/init.h>
  18. #include <linux/sched.h>
  19. #include <linux/signal.h>
  20. #include <linux/irq.h>
  21. #include <asm/io.h>
  22. #include <asm/system.h>
  23. #include <asm/irq.h>
  24. #include "cpc700.h"
  25. static void
  26. cpc700_unmask_irq(unsigned int irq)
  27. {
  28. unsigned int tr_bits;
  29. /*
  30. * IRQ 31 is largest IRQ supported.
  31. * IRQs 17-19 are reserved.
  32. */
  33. if ((irq <= 31) && ((irq < 17) || (irq > 19))) {
  34. tr_bits = CPC700_IN_32(CPC700_UIC_UICTR);
  35. if ((tr_bits & (1 << (31 - irq))) == 0) {
  36. /* level trigger interrupt, clear bit in status
  37. * register */
  38. CPC700_OUT_32(CPC700_UIC_UICSR, 1 << (31 - irq));
  39. }
  40. /* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */
  41. ppc_cached_irq_mask[0] |= CPC700_UIC_IRQ_BIT(irq);
  42. CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]);
  43. }
  44. return;
  45. }
  46. static void
  47. cpc700_mask_irq(unsigned int irq)
  48. {
  49. /*
  50. * IRQ 31 is largest IRQ supported.
  51. * IRQs 17-19 are reserved.
  52. */
  53. if ((irq <= 31) && ((irq < 17) || (irq > 19))) {
  54. /* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */
  55. ppc_cached_irq_mask[0] &=
  56. ~CPC700_UIC_IRQ_BIT(irq);
  57. CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]);
  58. }
  59. return;
  60. }
  61. static void
  62. cpc700_mask_and_ack_irq(unsigned int irq)
  63. {
  64. u_int bit;
  65. /*
  66. * IRQ 31 is largest IRQ supported.
  67. * IRQs 17-19 are reserved.
  68. */
  69. if ((irq <= 31) && ((irq < 17) || (irq > 19))) {
  70. /* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */
  71. bit = CPC700_UIC_IRQ_BIT(irq);
  72. ppc_cached_irq_mask[0] &= ~bit;
  73. CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]);
  74. CPC700_OUT_32(CPC700_UIC_UICSR, bit); /* Write 1 clears IRQ */
  75. }
  76. return;
  77. }
  78. static struct hw_interrupt_type cpc700_pic = {
  79. "CPC700 PIC",
  80. NULL,
  81. NULL,
  82. cpc700_unmask_irq,
  83. cpc700_mask_irq,
  84. cpc700_mask_and_ack_irq,
  85. NULL,
  86. NULL
  87. };
  88. __init static void
  89. cpc700_pic_init_irq(unsigned int irq)
  90. {
  91. unsigned int tmp;
  92. /* Set interrupt sense */
  93. tmp = CPC700_IN_32(CPC700_UIC_UICTR);
  94. if (cpc700_irq_assigns[irq][0] == 0) {
  95. tmp &= ~CPC700_UIC_IRQ_BIT(irq);
  96. } else {
  97. tmp |= CPC700_UIC_IRQ_BIT(irq);
  98. }
  99. CPC700_OUT_32(CPC700_UIC_UICTR, tmp);
  100. /* Set interrupt polarity */
  101. tmp = CPC700_IN_32(CPC700_UIC_UICPR);
  102. if (cpc700_irq_assigns[irq][1]) {
  103. tmp |= CPC700_UIC_IRQ_BIT(irq);
  104. } else {
  105. tmp &= ~CPC700_UIC_IRQ_BIT(irq);
  106. }
  107. CPC700_OUT_32(CPC700_UIC_UICPR, tmp);
  108. /* Set interrupt critical */
  109. tmp = CPC700_IN_32(CPC700_UIC_UICCR);
  110. tmp |= CPC700_UIC_IRQ_BIT(irq);
  111. CPC700_OUT_32(CPC700_UIC_UICCR, tmp);
  112. return;
  113. }
  114. __init void
  115. cpc700_init_IRQ(void)
  116. {
  117. int i;
  118. ppc_cached_irq_mask[0] = 0;
  119. CPC700_OUT_32(CPC700_UIC_UICER, 0x00000000); /* Disable all irq's */
  120. CPC700_OUT_32(CPC700_UIC_UICSR, 0xffffffff); /* Clear cur intrs */
  121. CPC700_OUT_32(CPC700_UIC_UICCR, 0xffffffff); /* Gen INT not MCP */
  122. CPC700_OUT_32(CPC700_UIC_UICPR, 0x00000000); /* Active low */
  123. CPC700_OUT_32(CPC700_UIC_UICTR, 0x00000000); /* Level Sensitive */
  124. CPC700_OUT_32(CPC700_UIC_UICVR, CPC700_UIC_UICVCR_0_HI);
  125. /* IRQ 0 is highest */
  126. for (i = 0; i < 17; i++) {
  127. irq_desc[i].handler = &cpc700_pic;
  128. cpc700_pic_init_irq(i);
  129. }
  130. for (i = 20; i < 32; i++) {
  131. irq_desc[i].handler = &cpc700_pic;
  132. cpc700_pic_init_irq(i);
  133. }
  134. return;
  135. }
  136. /*
  137. * Find the highest IRQ that generating an interrupt, if any.
  138. */
  139. int
  140. cpc700_get_irq(struct pt_regs *regs)
  141. {
  142. int irq = 0;
  143. u_int irq_status, irq_test = 1;
  144. irq_status = CPC700_IN_32(CPC700_UIC_UICMSR);
  145. do
  146. {
  147. if (irq_status & irq_test)
  148. break;
  149. irq++;
  150. irq_test <<= 1;
  151. } while (irq < NR_IRQS);
  152. if (irq == NR_IRQS)
  153. irq = 33;
  154. return (31 - irq);
  155. }