interrupts.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. /*
  2. * (C) Copyright 2006
  3. * Detlev Zundel, DENX Software Engineering, dzu@denx.de
  4. *
  5. * (C) Copyright -2003
  6. * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
  7. *
  8. * (C) Copyright 2001
  9. * Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc.
  10. *
  11. * See file CREDITS for list of people who contributed to this
  12. * project.
  13. *
  14. * This program is free software; you can redistribute it and/or
  15. * modify it under the terms of the GNU General Public License as
  16. * published by the Free Software Foundation; either version 2 of
  17. * the License, or (at your option) any later version.
  18. *
  19. * This program is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. * GNU General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU General Public License
  25. * along with this program; if not, write to the Free Software
  26. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  27. * MA 02111-1307 USA
  28. */
  29. /* this section was ripped out of arch/ppc/syslib/mpc52xx_pic.c in the
  30. * Linux 2.6 source with the following copyright.
  31. *
  32. * Based on (well, mostly copied from) the code from the 2.4 kernel by
  33. * Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg.
  34. *
  35. * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>
  36. * Copyright (C) 2003 Montavista Software, Inc
  37. */
  38. #include <common.h>
  39. #include <asm/processor.h>
  40. #include <asm/io.h>
  41. #include <command.h>
  42. struct irq_action {
  43. interrupt_handler_t *handler;
  44. void *arg;
  45. ulong count;
  46. };
  47. static struct irq_action irq_handlers[NR_IRQS];
  48. static struct mpc5xxx_intr *intr;
  49. static struct mpc5xxx_sdma *sdma;
  50. static void mpc5xxx_ic_disable(unsigned int irq)
  51. {
  52. u32 val;
  53. if (irq == MPC5XXX_IRQ0) {
  54. val = in_be32(&intr->ctrl);
  55. val &= ~(1 << 11);
  56. out_be32(&intr->ctrl, val);
  57. } else if (irq < MPC5XXX_IRQ1) {
  58. BUG();
  59. } else if (irq <= MPC5XXX_IRQ3) {
  60. val = in_be32(&intr->ctrl);
  61. val &= ~(1 << (10 - (irq - MPC5XXX_IRQ1)));
  62. out_be32(&intr->ctrl, val);
  63. } else if (irq < MPC5XXX_SDMA_IRQ_BASE) {
  64. val = in_be32(&intr->main_mask);
  65. val |= 1 << (16 - (irq - MPC5XXX_MAIN_IRQ_BASE));
  66. out_be32(&intr->main_mask, val);
  67. } else if (irq < MPC5XXX_PERP_IRQ_BASE) {
  68. val = in_be32(&sdma->IntMask);
  69. val |= 1 << (irq - MPC5XXX_SDMA_IRQ_BASE);
  70. out_be32(&sdma->IntMask, val);
  71. } else {
  72. val = in_be32(&intr->per_mask);
  73. val |= 1 << (31 - (irq - MPC5XXX_PERP_IRQ_BASE));
  74. out_be32(&intr->per_mask, val);
  75. }
  76. }
  77. static void mpc5xxx_ic_enable(unsigned int irq)
  78. {
  79. u32 val;
  80. if (irq == MPC5XXX_IRQ0) {
  81. val = in_be32(&intr->ctrl);
  82. val |= 1 << 11;
  83. out_be32(&intr->ctrl, val);
  84. } else if (irq < MPC5XXX_IRQ1) {
  85. BUG();
  86. } else if (irq <= MPC5XXX_IRQ3) {
  87. val = in_be32(&intr->ctrl);
  88. val |= 1 << (10 - (irq - MPC5XXX_IRQ1));
  89. out_be32(&intr->ctrl, val);
  90. } else if (irq < MPC5XXX_SDMA_IRQ_BASE) {
  91. val = in_be32(&intr->main_mask);
  92. val &= ~(1 << (16 - (irq - MPC5XXX_MAIN_IRQ_BASE)));
  93. out_be32(&intr->main_mask, val);
  94. } else if (irq < MPC5XXX_PERP_IRQ_BASE) {
  95. val = in_be32(&sdma->IntMask);
  96. val &= ~(1 << (irq - MPC5XXX_SDMA_IRQ_BASE));
  97. out_be32(&sdma->IntMask, val);
  98. } else {
  99. val = in_be32(&intr->per_mask);
  100. val &= ~(1 << (31 - (irq - MPC5XXX_PERP_IRQ_BASE)));
  101. out_be32(&intr->per_mask, val);
  102. }
  103. }
  104. static void mpc5xxx_ic_ack(unsigned int irq)
  105. {
  106. u32 val;
  107. /*
  108. * Only some irqs are reset here, others in interrupting hardware.
  109. */
  110. switch (irq) {
  111. case MPC5XXX_IRQ0:
  112. val = in_be32(&intr->ctrl);
  113. val |= 0x08000000;
  114. out_be32(&intr->ctrl, val);
  115. break;
  116. case MPC5XXX_CCS_IRQ:
  117. val = in_be32(&intr->enc_status);
  118. val |= 0x00000400;
  119. out_be32(&intr->enc_status, val);
  120. break;
  121. case MPC5XXX_IRQ1:
  122. val = in_be32(&intr->ctrl);
  123. val |= 0x04000000;
  124. out_be32(&intr->ctrl, val);
  125. break;
  126. case MPC5XXX_IRQ2:
  127. val = in_be32(&intr->ctrl);
  128. val |= 0x02000000;
  129. out_be32(&intr->ctrl, val);
  130. break;
  131. case MPC5XXX_IRQ3:
  132. val = in_be32(&intr->ctrl);
  133. val |= 0x01000000;
  134. out_be32(&intr->ctrl, val);
  135. break;
  136. default:
  137. if (irq >= MPC5XXX_SDMA_IRQ_BASE
  138. && irq < (MPC5XXX_SDMA_IRQ_BASE + MPC5XXX_SDMA_IRQ_NUM)) {
  139. out_be32(&sdma->IntPend,
  140. 1 << (irq - MPC5XXX_SDMA_IRQ_BASE));
  141. }
  142. break;
  143. }
  144. }
  145. static void mpc5xxx_ic_disable_and_ack(unsigned int irq)
  146. {
  147. mpc5xxx_ic_disable(irq);
  148. mpc5xxx_ic_ack(irq);
  149. }
  150. static void mpc5xxx_ic_end(unsigned int irq)
  151. {
  152. mpc5xxx_ic_enable(irq);
  153. }
  154. void mpc5xxx_init_irq(void)
  155. {
  156. u32 intr_ctrl;
  157. /* Remap the necessary zones */
  158. intr = (struct mpc5xxx_intr *)(MPC5XXX_ICTL);
  159. sdma = (struct mpc5xxx_sdma *)(MPC5XXX_SDMA);
  160. /* Disable all interrupt sources. */
  161. out_be32(&sdma->IntPend, 0xffffffff); /* 1 means clear pending */
  162. out_be32(&sdma->IntMask, 0xffffffff); /* 1 means disabled */
  163. out_be32(&intr->per_mask, 0x7ffffc00); /* 1 means disabled */
  164. out_be32(&intr->main_mask, 0x00010fff); /* 1 means disabled */
  165. intr_ctrl = in_be32(&intr->ctrl);
  166. intr_ctrl |= 0x0f000000 | /* clear IRQ 0-3 */
  167. 0x00ff0000 | /* IRQ 0-3 level sensitive low active */
  168. 0x00001000 | /* MEE master external enable */
  169. 0x00000000 | /* 0 means disable IRQ 0-3 */
  170. 0x00000001; /* CEb route critical normally */
  171. out_be32(&intr->ctrl, intr_ctrl);
  172. /* Zero a bunch of the priority settings. */
  173. out_be32(&intr->per_pri1, 0);
  174. out_be32(&intr->per_pri2, 0);
  175. out_be32(&intr->per_pri3, 0);
  176. out_be32(&intr->main_pri1, 0);
  177. out_be32(&intr->main_pri2, 0);
  178. }
  179. int mpc5xxx_get_irq(struct pt_regs *regs)
  180. {
  181. u32 status;
  182. int irq = -1;
  183. status = in_be32(&intr->enc_status);
  184. if (status & 0x00000400) { /* critical */
  185. irq = (status >> 8) & 0x3;
  186. if (irq == 2) /* high priority peripheral */
  187. goto peripheral;
  188. irq += MPC5XXX_CRIT_IRQ_BASE;
  189. } else if (status & 0x00200000) { /* main */
  190. irq = (status >> 16) & 0x1f;
  191. if (irq == 4) /* low priority peripheral */
  192. goto peripheral;
  193. irq += MPC5XXX_MAIN_IRQ_BASE;
  194. } else if (status & 0x20000000) { /* peripheral */
  195. peripheral:
  196. irq = (status >> 24) & 0x1f;
  197. if (irq == 0) { /* bestcomm */
  198. status = in_be32(&sdma->IntPend);
  199. irq = ffs(status) + MPC5XXX_SDMA_IRQ_BASE - 1;
  200. } else
  201. irq += MPC5XXX_PERP_IRQ_BASE;
  202. }
  203. return irq;
  204. }
  205. /****************************************************************************/
  206. int interrupt_init_cpu(ulong * decrementer_count)
  207. {
  208. *decrementer_count = get_tbclk() / CONFIG_SYS_HZ;
  209. mpc5xxx_init_irq();
  210. return (0);
  211. }
  212. /****************************************************************************/
  213. /*
  214. * Handle external interrupts
  215. */
  216. void external_interrupt(struct pt_regs *regs)
  217. {
  218. int irq, unmask = 1;
  219. irq = mpc5xxx_get_irq(regs);
  220. mpc5xxx_ic_disable_and_ack(irq);
  221. enable_interrupts();
  222. if (irq_handlers[irq].handler != NULL)
  223. (*irq_handlers[irq].handler) (irq_handlers[irq].arg);
  224. else {
  225. printf("\nBogus External Interrupt IRQ %d\n", irq);
  226. /*
  227. * turn off the bogus interrupt, otherwise it
  228. * might repeat forever
  229. */
  230. unmask = 0;
  231. }
  232. if (unmask)
  233. mpc5xxx_ic_end(irq);
  234. }
  235. void timer_interrupt_cpu(struct pt_regs *regs)
  236. {
  237. /* nothing to do here */
  238. return;
  239. }
  240. /****************************************************************************/
  241. /*
  242. * Install and free a interrupt handler.
  243. */
  244. void irq_install_handler(int irq, interrupt_handler_t * handler, void *arg)
  245. {
  246. if (irq < 0 || irq >= NR_IRQS) {
  247. printf("irq_install_handler: bad irq number %d\n", irq);
  248. return;
  249. }
  250. if (irq_handlers[irq].handler != NULL)
  251. printf("irq_install_handler: 0x%08lx replacing 0x%08lx\n",
  252. (ulong) handler, (ulong) irq_handlers[irq].handler);
  253. irq_handlers[irq].handler = handler;
  254. irq_handlers[irq].arg = arg;
  255. mpc5xxx_ic_enable(irq);
  256. }
  257. void irq_free_handler(int irq)
  258. {
  259. if (irq < 0 || irq >= NR_IRQS) {
  260. printf("irq_free_handler: bad irq number %d\n", irq);
  261. return;
  262. }
  263. mpc5xxx_ic_disable(irq);
  264. irq_handlers[irq].handler = NULL;
  265. irq_handlers[irq].arg = NULL;
  266. }
  267. /****************************************************************************/
  268. #if defined(CONFIG_CMD_IRQ)
  269. void do_irqinfo(cmd_tbl_t * cmdtp, bd_t * bd, int flag, int argc, char *argv[])
  270. {
  271. int irq, re_enable;
  272. u32 intr_ctrl;
  273. char *irq_config[] = { "level sensitive, active high",
  274. "edge sensitive, rising active edge",
  275. "edge sensitive, falling active edge",
  276. "level sensitive, active low"
  277. };
  278. re_enable = disable_interrupts();
  279. intr_ctrl = in_be32(&intr->ctrl);
  280. printf("Interrupt configuration:\n");
  281. for (irq = 0; irq <= 3; irq++) {
  282. printf("IRQ%d: %s\n", irq,
  283. irq_config[(intr_ctrl >> (22 - 2 * irq)) & 0x3]);
  284. }
  285. puts("\nInterrupt-Information:\n" "Nr Routine Arg Count\n");
  286. for (irq = 0; irq < NR_IRQS; irq++)
  287. if (irq_handlers[irq].handler != NULL)
  288. printf("%02d %08lx %08lx %ld\n", irq,
  289. (ulong) irq_handlers[irq].handler,
  290. (ulong) irq_handlers[irq].arg,
  291. irq_handlers[irq].count);
  292. if (re_enable)
  293. enable_interrupts();
  294. }
  295. #endif