cpc700_pic.c 3.9 KB

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