socrates_fpga_pic.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. /*
  2. * Copyright (C) 2008 Ilya Yanok, Emcraft Systems
  3. *
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License version 2 as
  7. * published by the Free Software Foundation.
  8. *
  9. */
  10. #include <linux/irq.h>
  11. #include <linux/of_address.h>
  12. #include <linux/of_irq.h>
  13. #include <linux/of_platform.h>
  14. #include <linux/io.h>
  15. /*
  16. * The FPGA supports 9 interrupt sources, which can be routed to 3
  17. * interrupt request lines of the MPIC. The line to be used can be
  18. * specified through the third cell of FDT property "interrupts".
  19. */
  20. #define SOCRATES_FPGA_NUM_IRQS 9
  21. #define FPGA_PIC_IRQCFG (0x0)
  22. #define FPGA_PIC_IRQMASK(n) (0x4 + 0x4 * (n))
  23. #define SOCRATES_FPGA_IRQ_MASK ((1 << SOCRATES_FPGA_NUM_IRQS) - 1)
  24. struct socrates_fpga_irq_info {
  25. unsigned int irq_line;
  26. int type;
  27. };
  28. /*
  29. * Interrupt routing and type table
  30. *
  31. * IRQ_TYPE_NONE means the interrupt type is configurable,
  32. * otherwise it's fixed to the specified value.
  33. */
  34. static struct socrates_fpga_irq_info fpga_irqs[SOCRATES_FPGA_NUM_IRQS] = {
  35. [0] = {0, IRQ_TYPE_NONE},
  36. [1] = {0, IRQ_TYPE_LEVEL_HIGH},
  37. [2] = {0, IRQ_TYPE_LEVEL_LOW},
  38. [3] = {0, IRQ_TYPE_NONE},
  39. [4] = {0, IRQ_TYPE_NONE},
  40. [5] = {0, IRQ_TYPE_NONE},
  41. [6] = {0, IRQ_TYPE_NONE},
  42. [7] = {0, IRQ_TYPE_NONE},
  43. [8] = {0, IRQ_TYPE_LEVEL_HIGH},
  44. };
  45. static DEFINE_RAW_SPINLOCK(socrates_fpga_pic_lock);
  46. static void __iomem *socrates_fpga_pic_iobase;
  47. static struct irq_domain *socrates_fpga_pic_irq_host;
  48. static unsigned int socrates_fpga_irqs[3];
  49. static inline uint32_t socrates_fpga_pic_read(int reg)
  50. {
  51. return in_be32(socrates_fpga_pic_iobase + reg);
  52. }
  53. static inline void socrates_fpga_pic_write(int reg, uint32_t val)
  54. {
  55. out_be32(socrates_fpga_pic_iobase + reg, val);
  56. }
  57. static inline unsigned int socrates_fpga_pic_get_irq(unsigned int irq)
  58. {
  59. uint32_t cause;
  60. unsigned long flags;
  61. int i;
  62. /* Check irq line routed to the MPIC */
  63. for (i = 0; i < 3; i++) {
  64. if (irq == socrates_fpga_irqs[i])
  65. break;
  66. }
  67. if (i == 3)
  68. return 0;
  69. raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
  70. cause = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(i));
  71. raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
  72. for (i = SOCRATES_FPGA_NUM_IRQS - 1; i >= 0; i--) {
  73. if (cause >> (i + 16))
  74. break;
  75. }
  76. return irq_linear_revmap(socrates_fpga_pic_irq_host,
  77. (irq_hw_number_t)i);
  78. }
  79. static void socrates_fpga_pic_cascade(struct irq_desc *desc)
  80. {
  81. struct irq_chip *chip = irq_desc_get_chip(desc);
  82. unsigned int irq = irq_desc_get_irq(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 = socrates_fpga_pic_get_irq(irq);
  89. if (cascade_irq)
  90. generic_handle_irq(cascade_irq);
  91. chip->irq_eoi(&desc->irq_data);
  92. }
  93. static void socrates_fpga_pic_ack(struct irq_data *d)
  94. {
  95. unsigned long flags;
  96. unsigned int irq_line, hwirq = irqd_to_hwirq(d);
  97. uint32_t mask;
  98. irq_line = fpga_irqs[hwirq].irq_line;
  99. raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
  100. mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
  101. & SOCRATES_FPGA_IRQ_MASK;
  102. mask |= (1 << (hwirq + 16));
  103. socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
  104. raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
  105. }
  106. static void socrates_fpga_pic_mask(struct irq_data *d)
  107. {
  108. unsigned long flags;
  109. unsigned int hwirq = irqd_to_hwirq(d);
  110. int irq_line;
  111. u32 mask;
  112. irq_line = fpga_irqs[hwirq].irq_line;
  113. raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
  114. mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
  115. & SOCRATES_FPGA_IRQ_MASK;
  116. mask &= ~(1 << hwirq);
  117. socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
  118. raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
  119. }
  120. static void socrates_fpga_pic_mask_ack(struct irq_data *d)
  121. {
  122. unsigned long flags;
  123. unsigned int hwirq = irqd_to_hwirq(d);
  124. int irq_line;
  125. u32 mask;
  126. irq_line = fpga_irqs[hwirq].irq_line;
  127. raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
  128. mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
  129. & SOCRATES_FPGA_IRQ_MASK;
  130. mask &= ~(1 << hwirq);
  131. mask |= (1 << (hwirq + 16));
  132. socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
  133. raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
  134. }
  135. static void socrates_fpga_pic_unmask(struct irq_data *d)
  136. {
  137. unsigned long flags;
  138. unsigned int hwirq = irqd_to_hwirq(d);
  139. int irq_line;
  140. u32 mask;
  141. irq_line = fpga_irqs[hwirq].irq_line;
  142. raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
  143. mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
  144. & SOCRATES_FPGA_IRQ_MASK;
  145. mask |= (1 << hwirq);
  146. socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
  147. raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
  148. }
  149. static void socrates_fpga_pic_eoi(struct irq_data *d)
  150. {
  151. unsigned long flags;
  152. unsigned int hwirq = irqd_to_hwirq(d);
  153. int irq_line;
  154. u32 mask;
  155. irq_line = fpga_irqs[hwirq].irq_line;
  156. raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
  157. mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
  158. & SOCRATES_FPGA_IRQ_MASK;
  159. mask |= (1 << (hwirq + 16));
  160. socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
  161. raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
  162. }
  163. static int socrates_fpga_pic_set_type(struct irq_data *d,
  164. unsigned int flow_type)
  165. {
  166. unsigned long flags;
  167. unsigned int hwirq = irqd_to_hwirq(d);
  168. int polarity;
  169. u32 mask;
  170. if (fpga_irqs[hwirq].type != IRQ_TYPE_NONE)
  171. return -EINVAL;
  172. switch (flow_type & IRQ_TYPE_SENSE_MASK) {
  173. case IRQ_TYPE_LEVEL_HIGH:
  174. polarity = 1;
  175. break;
  176. case IRQ_TYPE_LEVEL_LOW:
  177. polarity = 0;
  178. break;
  179. default:
  180. return -EINVAL;
  181. }
  182. raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
  183. mask = socrates_fpga_pic_read(FPGA_PIC_IRQCFG);
  184. if (polarity)
  185. mask |= (1 << hwirq);
  186. else
  187. mask &= ~(1 << hwirq);
  188. socrates_fpga_pic_write(FPGA_PIC_IRQCFG, mask);
  189. raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
  190. return 0;
  191. }
  192. static struct irq_chip socrates_fpga_pic_chip = {
  193. .name = "FPGA-PIC",
  194. .irq_ack = socrates_fpga_pic_ack,
  195. .irq_mask = socrates_fpga_pic_mask,
  196. .irq_mask_ack = socrates_fpga_pic_mask_ack,
  197. .irq_unmask = socrates_fpga_pic_unmask,
  198. .irq_eoi = socrates_fpga_pic_eoi,
  199. .irq_set_type = socrates_fpga_pic_set_type,
  200. };
  201. static int socrates_fpga_pic_host_map(struct irq_domain *h, unsigned int virq,
  202. irq_hw_number_t hwirq)
  203. {
  204. /* All interrupts are LEVEL sensitive */
  205. irq_set_status_flags(virq, IRQ_LEVEL);
  206. irq_set_chip_and_handler(virq, &socrates_fpga_pic_chip,
  207. handle_fasteoi_irq);
  208. return 0;
  209. }
  210. static int socrates_fpga_pic_host_xlate(struct irq_domain *h,
  211. struct device_node *ct, const u32 *intspec, unsigned int intsize,
  212. irq_hw_number_t *out_hwirq, unsigned int *out_flags)
  213. {
  214. struct socrates_fpga_irq_info *fpga_irq = &fpga_irqs[intspec[0]];
  215. *out_hwirq = intspec[0];
  216. if (fpga_irq->type == IRQ_TYPE_NONE) {
  217. /* type is configurable */
  218. if (intspec[1] != IRQ_TYPE_LEVEL_LOW &&
  219. intspec[1] != IRQ_TYPE_LEVEL_HIGH) {
  220. pr_warning("FPGA PIC: invalid irq type, "
  221. "setting default active low\n");
  222. *out_flags = IRQ_TYPE_LEVEL_LOW;
  223. } else {
  224. *out_flags = intspec[1];
  225. }
  226. } else {
  227. /* type is fixed */
  228. *out_flags = fpga_irq->type;
  229. }
  230. /* Use specified interrupt routing */
  231. if (intspec[2] <= 2)
  232. fpga_irq->irq_line = intspec[2];
  233. else
  234. pr_warning("FPGA PIC: invalid irq routing\n");
  235. return 0;
  236. }
  237. static const struct irq_domain_ops socrates_fpga_pic_host_ops = {
  238. .map = socrates_fpga_pic_host_map,
  239. .xlate = socrates_fpga_pic_host_xlate,
  240. };
  241. void socrates_fpga_pic_init(struct device_node *pic)
  242. {
  243. unsigned long flags;
  244. int i;
  245. /* Setup an irq_domain structure */
  246. socrates_fpga_pic_irq_host = irq_domain_add_linear(pic,
  247. SOCRATES_FPGA_NUM_IRQS, &socrates_fpga_pic_host_ops, NULL);
  248. if (socrates_fpga_pic_irq_host == NULL) {
  249. pr_err("FPGA PIC: Unable to allocate host\n");
  250. return;
  251. }
  252. for (i = 0; i < 3; i++) {
  253. socrates_fpga_irqs[i] = irq_of_parse_and_map(pic, i);
  254. if (!socrates_fpga_irqs[i]) {
  255. pr_warning("FPGA PIC: can't get irq%d.\n", i);
  256. continue;
  257. }
  258. irq_set_chained_handler(socrates_fpga_irqs[i],
  259. socrates_fpga_pic_cascade);
  260. }
  261. socrates_fpga_pic_iobase = of_iomap(pic, 0);
  262. raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
  263. socrates_fpga_pic_write(FPGA_PIC_IRQMASK(0),
  264. SOCRATES_FPGA_IRQ_MASK << 16);
  265. socrates_fpga_pic_write(FPGA_PIC_IRQMASK(1),
  266. SOCRATES_FPGA_IRQ_MASK << 16);
  267. socrates_fpga_pic_write(FPGA_PIC_IRQMASK(2),
  268. SOCRATES_FPGA_IRQ_MASK << 16);
  269. raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
  270. pr_info("FPGA PIC: Setting up Socrates FPGA PIC\n");
  271. }