ge_pic.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. /*
  2. * Interrupt handling for GE FPGA based PIC
  3. *
  4. * Author: Martyn Welch <[email protected]>
  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/irqdomain.h>
  17. #include <linux/interrupt.h>
  18. #include <linux/of_address.h>
  19. #include <linux/of_irq.h>
  20. #include <linux/spinlock.h>
  21. #include <asm/byteorder.h>
  22. #include <asm/io.h>
  23. #include <asm/irq.h>
  24. #include "ge_pic.h"
  25. #define DEBUG
  26. #undef DEBUG
  27. #ifdef DEBUG
  28. #define DBG(fmt...) do { printk(KERN_DEBUG "gef_pic: " fmt); } while (0)
  29. #else
  30. #define DBG(fmt...) do { } while (0)
  31. #endif
  32. #define GEF_PIC_NUM_IRQS 32
  33. /* Interrupt Controller Interface Registers */
  34. #define GEF_PIC_INTR_STATUS 0x0000
  35. #define GEF_PIC_INTR_MASK(cpu) (0x0010 + (0x4 * cpu))
  36. #define GEF_PIC_CPU0_INTR_MASK GEF_PIC_INTR_MASK(0)
  37. #define GEF_PIC_CPU1_INTR_MASK GEF_PIC_INTR_MASK(1)
  38. #define GEF_PIC_MCP_MASK(cpu) (0x0018 + (0x4 * cpu))
  39. #define GEF_PIC_CPU0_MCP_MASK GEF_PIC_MCP_MASK(0)
  40. #define GEF_PIC_CPU1_MCP_MASK GEF_PIC_MCP_MASK(1)
  41. static DEFINE_RAW_SPINLOCK(gef_pic_lock);
  42. static void __iomem *gef_pic_irq_reg_base;
  43. static struct irq_domain *gef_pic_irq_host;
  44. static int gef_pic_cascade_irq;
  45. /*
  46. * Interrupt Controller Handling
  47. *
  48. * The interrupt controller handles interrupts for most on board interrupts,
  49. * apart from PCI interrupts. For example on SBC610:
  50. *
  51. * 17:31 RO Reserved
  52. * 16 RO PCI Express Doorbell 3 Status
  53. * 15 RO PCI Express Doorbell 2 Status
  54. * 14 RO PCI Express Doorbell 1 Status
  55. * 13 RO PCI Express Doorbell 0 Status
  56. * 12 RO Real Time Clock Interrupt Status
  57. * 11 RO Temperature Interrupt Status
  58. * 10 RO Temperature Critical Interrupt Status
  59. * 9 RO Ethernet PHY1 Interrupt Status
  60. * 8 RO Ethernet PHY3 Interrupt Status
  61. * 7 RO PEX8548 Interrupt Status
  62. * 6 RO Reserved
  63. * 5 RO Watchdog 0 Interrupt Status
  64. * 4 RO Watchdog 1 Interrupt Status
  65. * 3 RO AXIS Message FIFO A Interrupt Status
  66. * 2 RO AXIS Message FIFO B Interrupt Status
  67. * 1 RO AXIS Message FIFO C Interrupt Status
  68. * 0 RO AXIS Message FIFO D Interrupt Status
  69. *
  70. * Interrupts can be forwarded to one of two output lines. Nothing
  71. * clever is done, so if the masks are incorrectly set, a single input
  72. * interrupt could generate interrupts on both output lines!
  73. *
  74. * The dual lines are there to allow the chained interrupts to be easily
  75. * passed into two different cores. We currently do not use this functionality
  76. * in this driver.
  77. *
  78. * Controller can also be configured to generate Machine checks (MCP), again on
  79. * two lines, to be attached to two different cores. It is suggested that these
  80. * should be masked out.
  81. */
  82. static void gef_pic_cascade(struct irq_desc *desc)
  83. {
  84. struct irq_chip *chip = irq_desc_get_chip(desc);
  85. unsigned int cascade_irq;
  86. /*
  87. * See if we actually have an interrupt, call generic handling code if
  88. * we do.
  89. */
  90. cascade_irq = gef_pic_get_irq();
  91. if (cascade_irq)
  92. generic_handle_irq(cascade_irq);
  93. chip->irq_eoi(&desc->irq_data);
  94. }
  95. static void gef_pic_mask(struct irq_data *d)
  96. {
  97. unsigned long flags;
  98. unsigned int hwirq = irqd_to_hwirq(d);
  99. u32 mask;
  100. raw_spin_lock_irqsave(&gef_pic_lock, flags);
  101. mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
  102. mask &= ~(1 << hwirq);
  103. out_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0), mask);
  104. raw_spin_unlock_irqrestore(&gef_pic_lock, flags);
  105. }
  106. static void gef_pic_mask_ack(struct irq_data *d)
  107. {
  108. /* Don't think we actually have to do anything to ack an interrupt,
  109. * we just need to clear down the devices interrupt and it will go away
  110. */
  111. gef_pic_mask(d);
  112. }
  113. static void gef_pic_unmask(struct irq_data *d)
  114. {
  115. unsigned long flags;
  116. unsigned int hwirq = irqd_to_hwirq(d);
  117. u32 mask;
  118. raw_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. raw_spin_unlock_irqrestore(&gef_pic_lock, flags);
  123. }
  124. static struct irq_chip gef_pic_chip = {
  125. .name = "gefp",
  126. .irq_mask = gef_pic_mask,
  127. .irq_mask_ack = gef_pic_mask_ack,
  128. .irq_unmask = gef_pic_unmask,
  129. };
  130. /* When an interrupt is being configured, this call allows some flexibility
  131. * in deciding which irq_chip structure is used
  132. */
  133. static int gef_pic_host_map(struct irq_domain *h, unsigned int virq,
  134. irq_hw_number_t hwirq)
  135. {
  136. /* All interrupts are LEVEL sensitive */
  137. irq_set_status_flags(virq, IRQ_LEVEL);
  138. irq_set_chip_and_handler(virq, &gef_pic_chip, handle_level_irq);
  139. return 0;
  140. }
  141. static int gef_pic_host_xlate(struct irq_domain *h, struct device_node *ct,
  142. const 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 const struct irq_domain_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. raw_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. raw_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) {
  174. printk(KERN_ERR "SBC610: failed to map cascade interrupt");
  175. return;
  176. }
  177. /* Setup an irq_domain structure */
  178. gef_pic_irq_host = irq_domain_add_linear(np, GEF_PIC_NUM_IRQS,
  179. &gef_pic_host_ops, NULL);
  180. if (gef_pic_irq_host == NULL)
  181. return;
  182. /* Chain with parent controller */
  183. irq_set_chained_handler(gef_pic_cascade_irq, gef_pic_cascade);
  184. }
  185. /*
  186. * This is called when we receive an interrupt with apparently comes from this
  187. * chip - check, returning the highest interrupt generated or return 0.
  188. */
  189. unsigned int gef_pic_get_irq(void)
  190. {
  191. u32 cause, mask, active;
  192. unsigned int virq = 0;
  193. int hwirq;
  194. cause = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_STATUS);
  195. mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
  196. active = cause & mask;
  197. if (active) {
  198. for (hwirq = GEF_PIC_NUM_IRQS - 1; hwirq > -1; hwirq--) {
  199. if (active & (0x1 << hwirq))
  200. break;
  201. }
  202. virq = irq_linear_revmap(gef_pic_irq_host,
  203. (irq_hw_number_t)hwirq);
  204. }
  205. return virq;
  206. }