ge_pic.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. /*
  2. * Interrupt handling for GE FPGA based PIC
  3. *
  4. * Author: Martyn Welch <martyn.welch@ge.com>
  5. *
  6. * 2008 (c) GE 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 "ge_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. static DEFINE_RAW_SPINLOCK(gef_pic_lock);
  40. static void __iomem *gef_pic_irq_reg_base;
  41. static struct irq_domain *gef_pic_irq_host;
  42. static int gef_pic_cascade_irq;
  43. /*
  44. * Interrupt Controller Handling
  45. *
  46. * The interrupt controller handles interrupts for most on board interrupts,
  47. * apart from PCI interrupts. For example on SBC610:
  48. *
  49. * 17:31 RO Reserved
  50. * 16 RO PCI Express Doorbell 3 Status
  51. * 15 RO PCI Express Doorbell 2 Status
  52. * 14 RO PCI Express Doorbell 1 Status
  53. * 13 RO PCI Express Doorbell 0 Status
  54. * 12 RO Real Time Clock Interrupt Status
  55. * 11 RO Temperature Interrupt Status
  56. * 10 RO Temperature Critical Interrupt Status
  57. * 9 RO Ethernet PHY1 Interrupt Status
  58. * 8 RO Ethernet PHY3 Interrupt Status
  59. * 7 RO PEX8548 Interrupt Status
  60. * 6 RO Reserved
  61. * 5 RO Watchdog 0 Interrupt Status
  62. * 4 RO Watchdog 1 Interrupt Status
  63. * 3 RO AXIS Message FIFO A Interrupt Status
  64. * 2 RO AXIS Message FIFO B Interrupt Status
  65. * 1 RO AXIS Message FIFO C Interrupt Status
  66. * 0 RO AXIS Message FIFO D Interrupt Status
  67. *
  68. * Interrupts can be forwarded to one of two output lines. Nothing
  69. * clever is done, so if the masks are incorrectly set, a single input
  70. * interrupt could generate interrupts on both output lines!
  71. *
  72. * The dual lines are there to allow the chained interrupts to be easily
  73. * passed into two different cores. We currently do not use this functionality
  74. * in this driver.
  75. *
  76. * Controller can also be configured to generate Machine checks (MCP), again on
  77. * two lines, to be attached to two different cores. It is suggested that these
  78. * should be masked out.
  79. */
  80. static void gef_pic_cascade(struct irq_desc *desc)
  81. {
  82. struct irq_chip *chip = irq_desc_get_chip(desc);
  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)
  90. generic_handle_irq(cascade_irq);
  91. chip->irq_eoi(&desc->irq_data);
  92. }
  93. static void gef_pic_mask(struct irq_data *d)
  94. {
  95. unsigned long flags;
  96. unsigned int hwirq = irqd_to_hwirq(d);
  97. u32 mask;
  98. raw_spin_lock_irqsave(&gef_pic_lock, flags);
  99. mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
  100. mask &= ~(1 << hwirq);
  101. out_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0), mask);
  102. raw_spin_unlock_irqrestore(&gef_pic_lock, flags);
  103. }
  104. static void gef_pic_mask_ack(struct irq_data *d)
  105. {
  106. /* Don't think we actually have to do anything to ack an interrupt,
  107. * we just need to clear down the devices interrupt and it will go away
  108. */
  109. gef_pic_mask(d);
  110. }
  111. static void gef_pic_unmask(struct irq_data *d)
  112. {
  113. unsigned long flags;
  114. unsigned int hwirq = irqd_to_hwirq(d);
  115. u32 mask;
  116. raw_spin_lock_irqsave(&gef_pic_lock, flags);
  117. mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
  118. mask |= (1 << hwirq);
  119. out_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0), mask);
  120. raw_spin_unlock_irqrestore(&gef_pic_lock, flags);
  121. }
  122. static struct irq_chip gef_pic_chip = {
  123. .name = "gefp",
  124. .irq_mask = gef_pic_mask,
  125. .irq_mask_ack = gef_pic_mask_ack,
  126. .irq_unmask = gef_pic_unmask,
  127. };
  128. /* When an interrupt is being configured, this call allows some flexibilty
  129. * in deciding which irq_chip structure is used
  130. */
  131. static int gef_pic_host_map(struct irq_domain *h, unsigned int virq,
  132. irq_hw_number_t hwirq)
  133. {
  134. /* All interrupts are LEVEL sensitive */
  135. irq_set_status_flags(virq, IRQ_LEVEL);
  136. irq_set_chip_and_handler(virq, &gef_pic_chip, handle_level_irq);
  137. return 0;
  138. }
  139. static int gef_pic_host_xlate(struct irq_domain *h, struct device_node *ct,
  140. const u32 *intspec, unsigned int intsize,
  141. irq_hw_number_t *out_hwirq, unsigned int *out_flags)
  142. {
  143. *out_hwirq = intspec[0];
  144. if (intsize > 1)
  145. *out_flags = intspec[1];
  146. else
  147. *out_flags = IRQ_TYPE_LEVEL_HIGH;
  148. return 0;
  149. }
  150. static const struct irq_domain_ops gef_pic_host_ops = {
  151. .map = gef_pic_host_map,
  152. .xlate = gef_pic_host_xlate,
  153. };
  154. /*
  155. * Initialisation of PIC, this should be called in BSP
  156. */
  157. void __init gef_pic_init(struct device_node *np)
  158. {
  159. unsigned long flags;
  160. /* Map the devices registers into memory */
  161. gef_pic_irq_reg_base = of_iomap(np, 0);
  162. raw_spin_lock_irqsave(&gef_pic_lock, flags);
  163. /* Initialise everything as masked. */
  164. out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU0_INTR_MASK, 0);
  165. out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU1_INTR_MASK, 0);
  166. out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU0_MCP_MASK, 0);
  167. out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU1_MCP_MASK, 0);
  168. raw_spin_unlock_irqrestore(&gef_pic_lock, flags);
  169. /* Map controller */
  170. gef_pic_cascade_irq = irq_of_parse_and_map(np, 0);
  171. if (!gef_pic_cascade_irq) {
  172. printk(KERN_ERR "SBC610: failed to map cascade interrupt");
  173. return;
  174. }
  175. /* Setup an irq_domain structure */
  176. gef_pic_irq_host = irq_domain_add_linear(np, GEF_PIC_NUM_IRQS,
  177. &gef_pic_host_ops, NULL);
  178. if (gef_pic_irq_host == NULL)
  179. return;
  180. /* Chain with parent controller */
  181. irq_set_chained_handler(gef_pic_cascade_irq, gef_pic_cascade);
  182. }
  183. /*
  184. * This is called when we receive an interrupt with apparently comes from this
  185. * chip - check, returning the highest interrupt generated or return 0.
  186. */
  187. unsigned int gef_pic_get_irq(void)
  188. {
  189. u32 cause, mask, active;
  190. unsigned int virq = 0;
  191. int hwirq;
  192. cause = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_STATUS);
  193. mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
  194. active = cause & mask;
  195. if (active) {
  196. for (hwirq = GEF_PIC_NUM_IRQS - 1; hwirq > -1; hwirq--) {
  197. if (active & (0x1 << hwirq))
  198. break;
  199. }
  200. virq = irq_linear_revmap(gef_pic_irq_host,
  201. (irq_hw_number_t)hwirq);
  202. }
  203. return virq;
  204. }