mpc52xx_pic.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. /*
  2. *
  3. * Programmable Interrupt Controller functions for the Freescale MPC52xx.
  4. *
  5. * Copyright (C) 2006 bplan GmbH
  6. *
  7. * Based on the code from the 2.4 kernel by
  8. * Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg.
  9. *
  10. * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>
  11. * Copyright (C) 2003 Montavista Software, Inc
  12. *
  13. * This file is licensed under the terms of the GNU General Public License
  14. * version 2. This program is licensed "as is" without any warranty of any
  15. * kind, whether express or implied.
  16. *
  17. */
  18. #undef DEBUG
  19. #include <linux/irq.h>
  20. #include <linux/of.h>
  21. #include <asm/io.h>
  22. #include <asm/prom.h>
  23. #include <asm/mpc52xx.h>
  24. #include "mpc52xx_pic.h"
  25. /*
  26. *
  27. */
  28. /* MPC5200 device tree match tables */
  29. static struct of_device_id mpc52xx_pic_ids[] __initdata = {
  30. { .compatible = "fsl,mpc5200-pic", },
  31. { .compatible = "mpc5200-pic", },
  32. {}
  33. };
  34. static struct of_device_id mpc52xx_sdma_ids[] __initdata = {
  35. { .compatible = "fsl,mpc5200-bestcomm", },
  36. { .compatible = "mpc5200-bestcomm", },
  37. {}
  38. };
  39. static struct mpc52xx_intr __iomem *intr;
  40. static struct mpc52xx_sdma __iomem *sdma;
  41. static struct irq_host *mpc52xx_irqhost = NULL;
  42. static unsigned char mpc52xx_map_senses[4] = {
  43. IRQ_TYPE_LEVEL_HIGH,
  44. IRQ_TYPE_EDGE_RISING,
  45. IRQ_TYPE_EDGE_FALLING,
  46. IRQ_TYPE_LEVEL_LOW,
  47. };
  48. /*
  49. *
  50. */
  51. static inline void io_be_setbit(u32 __iomem *addr, int bitno)
  52. {
  53. out_be32(addr, in_be32(addr) | (1 << bitno));
  54. }
  55. static inline void io_be_clrbit(u32 __iomem *addr, int bitno)
  56. {
  57. out_be32(addr, in_be32(addr) & ~(1 << bitno));
  58. }
  59. /*
  60. * IRQ[0-3] interrupt irq_chip
  61. */
  62. static void mpc52xx_extirq_mask(unsigned int virq)
  63. {
  64. int irq;
  65. int l2irq;
  66. irq = irq_map[virq].hwirq;
  67. l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
  68. pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
  69. io_be_clrbit(&intr->ctrl, 11 - l2irq);
  70. }
  71. static void mpc52xx_extirq_unmask(unsigned int virq)
  72. {
  73. int irq;
  74. int l2irq;
  75. irq = irq_map[virq].hwirq;
  76. l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
  77. pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
  78. io_be_setbit(&intr->ctrl, 11 - l2irq);
  79. }
  80. static void mpc52xx_extirq_ack(unsigned int virq)
  81. {
  82. int irq;
  83. int l2irq;
  84. irq = irq_map[virq].hwirq;
  85. l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
  86. pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
  87. io_be_setbit(&intr->ctrl, 27-l2irq);
  88. }
  89. static struct irq_chip mpc52xx_extirq_irqchip = {
  90. .typename = " MPC52xx IRQ[0-3] ",
  91. .mask = mpc52xx_extirq_mask,
  92. .unmask = mpc52xx_extirq_unmask,
  93. .ack = mpc52xx_extirq_ack,
  94. };
  95. /*
  96. * Main interrupt irq_chip
  97. */
  98. static void mpc52xx_main_mask(unsigned int virq)
  99. {
  100. int irq;
  101. int l2irq;
  102. irq = irq_map[virq].hwirq;
  103. l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
  104. pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
  105. io_be_setbit(&intr->main_mask, 16 - l2irq);
  106. }
  107. static void mpc52xx_main_unmask(unsigned int virq)
  108. {
  109. int irq;
  110. int l2irq;
  111. irq = irq_map[virq].hwirq;
  112. l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
  113. pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
  114. io_be_clrbit(&intr->main_mask, 16 - l2irq);
  115. }
  116. static struct irq_chip mpc52xx_main_irqchip = {
  117. .typename = "MPC52xx Main",
  118. .mask = mpc52xx_main_mask,
  119. .mask_ack = mpc52xx_main_mask,
  120. .unmask = mpc52xx_main_unmask,
  121. };
  122. /*
  123. * Peripherals interrupt irq_chip
  124. */
  125. static void mpc52xx_periph_mask(unsigned int virq)
  126. {
  127. int irq;
  128. int l2irq;
  129. irq = irq_map[virq].hwirq;
  130. l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
  131. pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
  132. io_be_setbit(&intr->per_mask, 31 - l2irq);
  133. }
  134. static void mpc52xx_periph_unmask(unsigned int virq)
  135. {
  136. int irq;
  137. int l2irq;
  138. irq = irq_map[virq].hwirq;
  139. l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
  140. pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
  141. io_be_clrbit(&intr->per_mask, 31 - l2irq);
  142. }
  143. static struct irq_chip mpc52xx_periph_irqchip = {
  144. .typename = "MPC52xx Peripherals",
  145. .mask = mpc52xx_periph_mask,
  146. .mask_ack = mpc52xx_periph_mask,
  147. .unmask = mpc52xx_periph_unmask,
  148. };
  149. /*
  150. * SDMA interrupt irq_chip
  151. */
  152. static void mpc52xx_sdma_mask(unsigned int virq)
  153. {
  154. int irq;
  155. int l2irq;
  156. irq = irq_map[virq].hwirq;
  157. l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
  158. pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
  159. io_be_setbit(&sdma->IntMask, l2irq);
  160. }
  161. static void mpc52xx_sdma_unmask(unsigned int virq)
  162. {
  163. int irq;
  164. int l2irq;
  165. irq = irq_map[virq].hwirq;
  166. l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
  167. pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
  168. io_be_clrbit(&sdma->IntMask, l2irq);
  169. }
  170. static void mpc52xx_sdma_ack(unsigned int virq)
  171. {
  172. int irq;
  173. int l2irq;
  174. irq = irq_map[virq].hwirq;
  175. l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
  176. pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
  177. out_be32(&sdma->IntPend, 1 << l2irq);
  178. }
  179. static struct irq_chip mpc52xx_sdma_irqchip = {
  180. .typename = "MPC52xx SDMA",
  181. .mask = mpc52xx_sdma_mask,
  182. .unmask = mpc52xx_sdma_unmask,
  183. .ack = mpc52xx_sdma_ack,
  184. };
  185. /*
  186. * irq_host
  187. */
  188. static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct,
  189. u32 * intspec, unsigned int intsize,
  190. irq_hw_number_t * out_hwirq,
  191. unsigned int *out_flags)
  192. {
  193. int intrvect_l1;
  194. int intrvect_l2;
  195. int intrvect_type;
  196. int intrvect_linux;
  197. if (intsize != 3)
  198. return -1;
  199. intrvect_l1 = (int)intspec[0];
  200. intrvect_l2 = (int)intspec[1];
  201. intrvect_type = (int)intspec[2];
  202. intrvect_linux =
  203. (intrvect_l1 << MPC52xx_IRQ_L1_OFFSET) & MPC52xx_IRQ_L1_MASK;
  204. intrvect_linux |=
  205. (intrvect_l2 << MPC52xx_IRQ_L2_OFFSET) & MPC52xx_IRQ_L2_MASK;
  206. pr_debug("return %x, l1=%d, l2=%d\n", intrvect_linux, intrvect_l1,
  207. intrvect_l2);
  208. *out_hwirq = intrvect_linux;
  209. *out_flags = mpc52xx_map_senses[intrvect_type];
  210. return 0;
  211. }
  212. /*
  213. * this function retrieves the correct IRQ type out
  214. * of the MPC regs
  215. * Only externals IRQs needs this
  216. */
  217. static int mpc52xx_irqx_gettype(int irq)
  218. {
  219. int type;
  220. u32 ctrl_reg;
  221. ctrl_reg = in_be32(&intr->ctrl);
  222. type = (ctrl_reg >> (22 - irq * 2)) & 0x3;
  223. return mpc52xx_map_senses[type];
  224. }
  225. static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq,
  226. irq_hw_number_t irq)
  227. {
  228. int l1irq;
  229. int l2irq;
  230. struct irq_chip *good_irqchip;
  231. void *good_handle;
  232. int type;
  233. l1irq = (irq & MPC52xx_IRQ_L1_MASK) >> MPC52xx_IRQ_L1_OFFSET;
  234. l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
  235. /*
  236. * Most of ours IRQs will be level low
  237. * Only external IRQs on some platform may be others
  238. */
  239. type = IRQ_TYPE_LEVEL_LOW;
  240. switch (l1irq) {
  241. case MPC52xx_IRQ_L1_CRIT:
  242. pr_debug("%s: Critical. l2=%x\n", __func__, l2irq);
  243. BUG_ON(l2irq != 0);
  244. type = mpc52xx_irqx_gettype(l2irq);
  245. good_irqchip = &mpc52xx_extirq_irqchip;
  246. break;
  247. case MPC52xx_IRQ_L1_MAIN:
  248. pr_debug("%s: Main IRQ[1-3] l2=%x\n", __func__, l2irq);
  249. if ((l2irq >= 1) && (l2irq <= 3)) {
  250. type = mpc52xx_irqx_gettype(l2irq);
  251. good_irqchip = &mpc52xx_extirq_irqchip;
  252. } else {
  253. good_irqchip = &mpc52xx_main_irqchip;
  254. }
  255. break;
  256. case MPC52xx_IRQ_L1_PERP:
  257. pr_debug("%s: Peripherals. l2=%x\n", __func__, l2irq);
  258. good_irqchip = &mpc52xx_periph_irqchip;
  259. break;
  260. case MPC52xx_IRQ_L1_SDMA:
  261. pr_debug("%s: SDMA. l2=%x\n", __func__, l2irq);
  262. good_irqchip = &mpc52xx_sdma_irqchip;
  263. break;
  264. default:
  265. pr_debug("%s: Error, unknown L1 IRQ (0x%x)\n", __func__, l1irq);
  266. printk(KERN_ERR "Unknow IRQ!\n");
  267. return -EINVAL;
  268. }
  269. switch (type) {
  270. case IRQ_TYPE_EDGE_FALLING:
  271. case IRQ_TYPE_EDGE_RISING:
  272. good_handle = handle_edge_irq;
  273. break;
  274. default:
  275. good_handle = handle_level_irq;
  276. }
  277. set_irq_chip_and_handler(virq, good_irqchip, good_handle);
  278. pr_debug("%s: virq=%x, hw=%x. type=%x\n", __func__, virq,
  279. (int)irq, type);
  280. return 0;
  281. }
  282. static struct irq_host_ops mpc52xx_irqhost_ops = {
  283. .xlate = mpc52xx_irqhost_xlate,
  284. .map = mpc52xx_irqhost_map,
  285. };
  286. /*
  287. * init (public)
  288. */
  289. void __init mpc52xx_init_irq(void)
  290. {
  291. u32 intr_ctrl;
  292. struct device_node *picnode;
  293. struct device_node *np;
  294. /* Remap the necessary zones */
  295. picnode = of_find_matching_node(NULL, mpc52xx_pic_ids);
  296. intr = of_iomap(picnode, 0);
  297. if (!intr)
  298. panic(__FILE__ ": find_and_map failed on 'mpc5200-pic'. "
  299. "Check node !");
  300. np = of_find_matching_node(NULL, mpc52xx_sdma_ids);
  301. sdma = of_iomap(np, 0);
  302. of_node_put(np);
  303. if (!sdma)
  304. panic(__FILE__ ": find_and_map failed on 'mpc5200-bestcomm'. "
  305. "Check node !");
  306. /* Disable all interrupt sources. */
  307. out_be32(&sdma->IntPend, 0xffffffff); /* 1 means clear pending */
  308. out_be32(&sdma->IntMask, 0xffffffff); /* 1 means disabled */
  309. out_be32(&intr->per_mask, 0x7ffffc00); /* 1 means disabled */
  310. out_be32(&intr->main_mask, 0x00010fff); /* 1 means disabled */
  311. intr_ctrl = in_be32(&intr->ctrl);
  312. intr_ctrl &= 0x00ff0000; /* Keeps IRQ[0-3] config */
  313. intr_ctrl |= 0x0f000000 | /* clear IRQ 0-3 */
  314. 0x00001000 | /* MEE master external enable */
  315. 0x00000000 | /* 0 means disable IRQ 0-3 */
  316. 0x00000001; /* CEb route critical normally */
  317. out_be32(&intr->ctrl, intr_ctrl);
  318. /* Zero a bunch of the priority settings. */
  319. out_be32(&intr->per_pri1, 0);
  320. out_be32(&intr->per_pri2, 0);
  321. out_be32(&intr->per_pri3, 0);
  322. out_be32(&intr->main_pri1, 0);
  323. out_be32(&intr->main_pri2, 0);
  324. /*
  325. * As last step, add an irq host to translate the real
  326. * hw irq information provided by the ofw to linux virq
  327. */
  328. mpc52xx_irqhost = irq_alloc_host(picnode, IRQ_HOST_MAP_LINEAR,
  329. MPC52xx_IRQ_HIGHTESTHWIRQ,
  330. &mpc52xx_irqhost_ops, -1);
  331. if (!mpc52xx_irqhost)
  332. panic(__FILE__ ": Cannot allocate the IRQ host\n");
  333. printk(KERN_INFO "MPC52xx PIC is up and running!\n");
  334. }
  335. /*
  336. * get_irq (public)
  337. */
  338. unsigned int mpc52xx_get_irq(void)
  339. {
  340. u32 status;
  341. int irq = NO_IRQ_IGNORE;
  342. status = in_be32(&intr->enc_status);
  343. if (status & 0x00000400) { /* critical */
  344. irq = (status >> 8) & 0x3;
  345. if (irq == 2) /* high priority peripheral */
  346. goto peripheral;
  347. irq |= (MPC52xx_IRQ_L1_CRIT << MPC52xx_IRQ_L1_OFFSET) &
  348. MPC52xx_IRQ_L1_MASK;
  349. } else if (status & 0x00200000) { /* main */
  350. irq = (status >> 16) & 0x1f;
  351. if (irq == 4) /* low priority peripheral */
  352. goto peripheral;
  353. irq |= (MPC52xx_IRQ_L1_MAIN << MPC52xx_IRQ_L1_OFFSET) &
  354. MPC52xx_IRQ_L1_MASK;
  355. } else if (status & 0x20000000) { /* peripheral */
  356. peripheral:
  357. irq = (status >> 24) & 0x1f;
  358. if (irq == 0) { /* bestcomm */
  359. status = in_be32(&sdma->IntPend);
  360. irq = ffs(status) - 1;
  361. irq |= (MPC52xx_IRQ_L1_SDMA << MPC52xx_IRQ_L1_OFFSET) &
  362. MPC52xx_IRQ_L1_MASK;
  363. } else {
  364. irq |= (MPC52xx_IRQ_L1_PERP << MPC52xx_IRQ_L1_OFFSET) &
  365. MPC52xx_IRQ_L1_MASK;
  366. }
  367. }
  368. pr_debug("%s: irq=%x. virq=%d\n", __func__, irq,
  369. irq_linear_revmap(mpc52xx_irqhost, irq));
  370. return irq_linear_revmap(mpc52xx_irqhost, irq);
  371. }