mpc52xx_pic.c 11 KB

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