gef_pic.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. /*
  2. * Interrupt handling for GE Fanuc's FPGA based PIC
  3. *
  4. * Author: Martyn Welch <martyn.welch@gefanuc.com>
  5. *
  6. * 2008 (c) GE Fanuc Intelligent Platforms Embedded Systems, Inc.
  7. *
  8. * This file is licensed under the terms of the GNU General Public License
  9. * version 2. This program is licensed "as is" without any warranty of any
  10. * kind, whether express or implied.
  11. */
  12. #include <linux/stddef.h>
  13. #include <linux/kernel.h>
  14. #include <linux/init.h>
  15. #include <linux/irq.h>
  16. #include <linux/interrupt.h>
  17. #include <linux/spinlock.h>
  18. #include <asm/byteorder.h>
  19. #include <asm/io.h>
  20. #include <asm/prom.h>
  21. #include <asm/irq.h>
  22. #include "gef_pic.h"
  23. #define DEBUG
  24. #undef DEBUG
  25. #ifdef DEBUG
  26. #define DBG(fmt...) do { printk(KERN_DEBUG "gef_pic: " fmt); } while (0)
  27. #else
  28. #define DBG(fmt...) do { } while (0)
  29. #endif
  30. #define GEF_PIC_NUM_IRQS 32
  31. /* Interrupt Controller Interface Registers */
  32. #define GEF_PIC_INTR_STATUS 0x0000
  33. #define GEF_PIC_INTR_MASK(cpu) (0x0010 + (0x4 * cpu))
  34. #define GEF_PIC_CPU0_INTR_MASK GEF_PIC_INTR_MASK(0)
  35. #define GEF_PIC_CPU1_INTR_MASK GEF_PIC_INTR_MASK(1)
  36. #define GEF_PIC_MCP_MASK(cpu) (0x0018 + (0x4 * cpu))
  37. #define GEF_PIC_CPU0_MCP_MASK GEF_PIC_MCP_MASK(0)
  38. #define GEF_PIC_CPU1_MCP_MASK GEF_PIC_MCP_MASK(1)
  39. #define gef_irq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq)
  40. static DEFINE_SPINLOCK(gef_pic_lock);
  41. static void __iomem *gef_pic_irq_reg_base;
  42. static struct irq_host *gef_pic_irq_host;
  43. static int gef_pic_cascade_irq;
  44. /*
  45. * Interrupt Controller Handling
  46. *
  47. * The interrupt controller handles interrupts for most on board interrupts,
  48. * apart from PCI interrupts. For example on SBC610:
  49. *
  50. * 17:31 RO Reserved
  51. * 16 RO PCI Express Doorbell 3 Status
  52. * 15 RO PCI Express Doorbell 2 Status
  53. * 14 RO PCI Express Doorbell 1 Status
  54. * 13 RO PCI Express Doorbell 0 Status
  55. * 12 RO Real Time Clock Interrupt Status
  56. * 11 RO Temperature Interrupt Status
  57. * 10 RO Temperature Critical Interrupt Status
  58. * 9 RO Ethernet PHY1 Interrupt Status
  59. * 8 RO Ethernet PHY3 Interrupt Status
  60. * 7 RO PEX8548 Interrupt Status
  61. * 6 RO Reserved
  62. * 5 RO Watchdog 0 Interrupt Status
  63. * 4 RO Watchdog 1 Interrupt Status
  64. * 3 RO AXIS Message FIFO A Interrupt Status
  65. * 2 RO AXIS Message FIFO B Interrupt Status
  66. * 1 RO AXIS Message FIFO C Interrupt Status
  67. * 0 RO AXIS Message FIFO D Interrupt Status
  68. *
  69. * Interrupts can be forwarded to one of two output lines. Nothing
  70. * clever is done, so if the masks are incorrectly set, a single input
  71. * interrupt could generate interrupts on both output lines!
  72. *
  73. * The dual lines are there to allow the chained interrupts to be easily
  74. * passed into two different cores. We currently do not use this functionality
  75. * in this driver.
  76. *
  77. * Controller can also be configured to generate Machine checks (MCP), again on
  78. * two lines, to be attached to two different cores. It is suggested that these
  79. * should be masked out.
  80. */
  81. void gef_pic_cascade(unsigned int irq, struct irq_desc *desc)
  82. {
  83. unsigned int cascade_irq;
  84. /*
  85. * See if we actually have an interrupt, call generic handling code if
  86. * we do.
  87. */
  88. cascade_irq = gef_pic_get_irq();
  89. if (cascade_irq != NO_IRQ)
  90. generic_handle_irq(cascade_irq);
  91. desc->chip->eoi(irq);
  92. }
  93. static void gef_pic_mask(unsigned int virq)
  94. {
  95. unsigned long flags;
  96. unsigned int hwirq;
  97. u32 mask;
  98. hwirq = gef_irq_to_hw(virq);
  99. spin_lock_irqsave(&gef_pic_lock, flags);
  100. mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
  101. mask &= ~(1 << hwirq);
  102. out_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0), mask);
  103. spin_unlock_irqrestore(&gef_pic_lock, flags);
  104. }
  105. static void gef_pic_mask_ack(unsigned int virq)
  106. {
  107. /* Don't think we actually have to do anything to ack an interrupt,
  108. * we just need to clear down the devices interrupt and it will go away
  109. */
  110. gef_pic_mask(virq);
  111. }
  112. static void gef_pic_unmask(unsigned int virq)
  113. {
  114. unsigned long flags;
  115. unsigned int hwirq;
  116. u32 mask;
  117. hwirq = gef_irq_to_hw(virq);
  118. spin_lock_irqsave(&gef_pic_lock, flags);
  119. mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
  120. mask |= (1 << hwirq);
  121. out_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0), mask);
  122. spin_unlock_irqrestore(&gef_pic_lock, flags);
  123. }
  124. static struct irq_chip gef_pic_chip = {
  125. .typename = "gefp",
  126. .mask = gef_pic_mask,
  127. .mask_ack = gef_pic_mask_ack,
  128. .unmask = gef_pic_unmask,
  129. };
  130. /* When an interrupt is being configured, this call allows some flexibilty
  131. * in deciding which irq_chip structure is used
  132. */
  133. static int gef_pic_host_map(struct irq_host *h, unsigned int virq,
  134. irq_hw_number_t hwirq)
  135. {
  136. /* All interrupts are LEVEL sensitive */
  137. get_irq_desc(virq)->status |= IRQ_LEVEL;
  138. set_irq_chip_and_handler(virq, &gef_pic_chip, handle_level_irq);
  139. return 0;
  140. }
  141. static int gef_pic_host_xlate(struct irq_host *h, struct device_node *ct,
  142. u32 *intspec, unsigned int intsize,
  143. irq_hw_number_t *out_hwirq, unsigned int *out_flags)
  144. {
  145. *out_hwirq = intspec[0];
  146. if (intsize > 1)
  147. *out_flags = intspec[1];
  148. else
  149. *out_flags = IRQ_TYPE_LEVEL_HIGH;
  150. return 0;
  151. }
  152. static struct irq_host_ops gef_pic_host_ops = {
  153. .map = gef_pic_host_map,
  154. .xlate = gef_pic_host_xlate,
  155. };
  156. /*
  157. * Initialisation of PIC, this should be called in BSP
  158. */
  159. void __init gef_pic_init(struct device_node *np)
  160. {
  161. unsigned long flags;
  162. /* Map the devices registers into memory */
  163. gef_pic_irq_reg_base = of_iomap(np, 0);
  164. spin_lock_irqsave(&gef_pic_lock, flags);
  165. /* Initialise everything as masked. */
  166. out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU0_INTR_MASK, 0);
  167. out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU1_INTR_MASK, 0);
  168. out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU0_MCP_MASK, 0);
  169. out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU1_MCP_MASK, 0);
  170. spin_unlock_irqrestore(&gef_pic_lock, flags);
  171. /* Map controller */
  172. gef_pic_cascade_irq = irq_of_parse_and_map(np, 0);
  173. if (gef_pic_cascade_irq == NO_IRQ) {
  174. printk(KERN_ERR "SBC610: failed to map cascade interrupt");
  175. return;
  176. }
  177. /* Setup an irq_host structure */
  178. gef_pic_irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR,
  179. GEF_PIC_NUM_IRQS,
  180. &gef_pic_host_ops, NO_IRQ);
  181. if (gef_pic_irq_host == NULL)
  182. return;
  183. /* Chain with parent controller */
  184. set_irq_chained_handler(gef_pic_cascade_irq, gef_pic_cascade);
  185. }
  186. /*
  187. * This is called when we receive an interrupt with apparently comes from this
  188. * chip - check, returning the highest interrupt generated or return NO_IRQ
  189. */
  190. unsigned int gef_pic_get_irq(void)
  191. {
  192. u32 cause, mask, active;
  193. unsigned int virq = NO_IRQ;
  194. int hwirq;
  195. cause = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_STATUS);
  196. mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
  197. active = cause & mask;
  198. if (active) {
  199. for (hwirq = GEF_PIC_NUM_IRQS - 1; hwirq > -1; hwirq--) {
  200. if (active & (0x1 << hwirq))
  201. break;
  202. }
  203. virq = irq_linear_revmap(gef_pic_irq_host,
  204. (irq_hw_number_t)hwirq);
  205. }
  206. return virq;
  207. }