i8259.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. /*
  2. * (C) Copyright 2002
  3. * John W. Linville, linville@tuxdriver.com
  4. *
  5. * See file CREDITS for list of people who contributed to this
  6. * project.
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License as
  10. * published by the Free Software Foundation; either version 2 of
  11. * the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  21. * MA 02111-1307 USA
  22. */
  23. #include <common.h>
  24. #include "i8259.h"
  25. #undef IRQ_DEBUG
  26. #ifdef IRQ_DEBUG
  27. #define PRINTF(fmt,args...) printf (fmt ,##args)
  28. #else
  29. #define PRINTF(fmt,args...)
  30. #endif
  31. static inline unsigned char read_byte(volatile unsigned char* from)
  32. {
  33. int x;
  34. asm volatile ("lbz %0,%1\n eieio" : "=r" (x) : "m" (*from));
  35. return (unsigned char)x;
  36. }
  37. static inline void write_byte(volatile unsigned char *to, int x)
  38. {
  39. asm volatile ("stb %1,%0\n eieio" : "=m" (*to) : "r" (x));
  40. }
  41. static inline unsigned long read_long_little(volatile unsigned long *from)
  42. {
  43. unsigned long x;
  44. asm volatile ("lwbrx %0,0,%1\n eieio\n sync" : "=r" (x) : "r" (from), "m"(*from));
  45. return (unsigned long)x;
  46. }
  47. #ifdef out8
  48. #undef out8
  49. #endif
  50. #ifdef in8
  51. #undef in8
  52. #endif
  53. #define out8(addr, byte) write_byte(0xFE000000 | addr, byte)
  54. #define in8(addr) read_byte(0xFE000000 | addr)
  55. /*
  56. * This contains the irq mask for both 8259A irq controllers,
  57. */
  58. static char cached_imr[2] = {0xff, 0xff};
  59. #define cached_imr1 (cached_imr[0])
  60. #define cached_imr2 (cached_imr[1])
  61. void i8259_init(void)
  62. {
  63. char dummy;
  64. PRINTF("Initializing Interrupt controller\n");
  65. /* init master interrupt controller */
  66. out8(0x20, 0x11); /* 0x19); /###* Start init sequence */
  67. out8(0x21, 0x00); /* Vector base */
  68. out8(0x21, 0x04); /* edge tiggered, Cascade (slave) on IRQ2 */
  69. out8(0x21, 0x11); /* was: 0x01); /###* Select 8086 mode */
  70. /* init slave interrupt controller */
  71. out8(0xA0, 0x11); /* 0x19); /###* Start init sequence */
  72. out8(0xA1, 0x08); /* Vector base */
  73. out8(0xA1, 0x02); /* edge triggered, Cascade (slave) on IRQ2 */
  74. out8(0xA1, 0x11); /* was: 0x01); /###* Select 8086 mode */
  75. /* always read ISR */
  76. out8(0x20, 0x0B);
  77. dummy = in8(ISR_1);
  78. out8(0xA0, 0x0B);
  79. dummy = in8(ISR_2);
  80. /* out8(0x43, 0x30); */
  81. /* out8(0x40, 0); */
  82. /* out8(0x40, 0); */
  83. /* out8(0x43, 0x70); */
  84. /* out8(0x41, 0); */
  85. /* out8(0x41, 0); */
  86. /* out8(0x43, 0xb0); */
  87. /* out8(0x42, 0); */
  88. /* out8(0x42, 0); */
  89. /* Mask all interrupts */
  90. out8(IMR_2, cached_imr2);
  91. out8(IMR_1, cached_imr1);
  92. i8259_unmask_irq(2);
  93. #if 0
  94. {
  95. int i;
  96. for (i=0; i<16; i++)
  97. {
  98. i8259_unmask_irq(i);
  99. }
  100. }
  101. #endif
  102. }
  103. static volatile char *pci_intack = (void *)0xFEF00000;
  104. int i8259_irq(void)
  105. {
  106. int irq;
  107. irq = read_long_little(pci_intack) & 0xff;
  108. if (irq==7) {
  109. /*
  110. * This may be a spurious interrupt.
  111. *
  112. * Read the interrupt status register (ISR). If the most
  113. * significant bit is not set then there is no valid
  114. * interrupt.
  115. */
  116. if(~in8(0x20)&0x80) {
  117. irq = -1;
  118. }
  119. }
  120. return irq;
  121. }
  122. int i8259_get_irq(struct pt_regs *regs)
  123. {
  124. unsigned char irq;
  125. /*
  126. * Perform an interrupt acknowledge cycle on controller 1
  127. */
  128. out8(OCW3_1, 0x0C); /* prepare for poll */
  129. irq = in8(IPL_1) & 7;
  130. if (irq == 2) {
  131. /*
  132. * Interrupt is cascaded so perform interrupt
  133. * acknowledge on controller 2
  134. */
  135. out8(OCW3_2, 0x0C); /* prepare for poll */
  136. irq = (in8(IPL_2) & 7) + 8;
  137. if (irq == 15) {
  138. /*
  139. * This may be a spurious interrupt
  140. *
  141. * Read the interrupt status register. If the most
  142. * significant bit is not set then there is no valid
  143. * interrupt
  144. */
  145. out8(OCW3_2, 0x0b);
  146. if (~(in8(ISR_2) & 0x80)) {
  147. return -1;
  148. }
  149. }
  150. } else if (irq == 7) {
  151. /*
  152. * This may be a spurious interrupt
  153. *
  154. * Read the interrupt status register. If the most
  155. * significant bit is not set then there is no valid
  156. * interrupt
  157. */
  158. out8(OCW3_1, 0x0b);
  159. if (~(in8(ISR_1) & 0x80)) {
  160. return -1;
  161. }
  162. }
  163. return irq;
  164. }
  165. /*
  166. * Careful! The 8259A is a fragile beast, it pretty
  167. * much _has_ to be done exactly like this (mask it
  168. * first, _then_ send the EOI, and the order of EOI
  169. * to the two 8259s is important!
  170. */
  171. void i8259_mask_and_ack(int irq)
  172. {
  173. if (irq > 7) {
  174. cached_imr2 |= (1 << (irq - 8));
  175. in8(IMR_2); /* DUMMY */
  176. out8(IMR_2, cached_imr2);
  177. out8(OCW2_2, 0x20); /* Non-specific EOI */
  178. out8(OCW2_1, 0x20); /* Non-specific EOI to cascade */
  179. } else {
  180. cached_imr1 |= (1 << irq);
  181. in8(IMR_1); /* DUMMY */
  182. out8(IMR_1, cached_imr1);
  183. out8(OCW2_1, 0x20); /* Non-specific EOI */
  184. }
  185. }
  186. void i8259_mask_irq(int irq)
  187. {
  188. if (irq & 8) {
  189. cached_imr2 |= (1 << (irq & 7));
  190. out8(IMR_2, cached_imr2);
  191. } else {
  192. cached_imr1 |= (1 << irq);
  193. out8(IMR_1, cached_imr1);
  194. }
  195. }
  196. void i8259_unmask_irq(int irq)
  197. {
  198. if (irq & 8) {
  199. cached_imr2 &= ~(1 << (irq & 7));
  200. out8(IMR_2, cached_imr2);
  201. } else {
  202. cached_imr1 &= ~(1 << irq);
  203. out8(IMR_1, cached_imr1);
  204. }
  205. }