interrupts.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. /*
  2. * (C) Copyright 2000-2002
  3. * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
  4. *
  5. * (C) Copyright 2002 (440 port)
  6. * Scott McNutt, Artesyn Communication Producs, smcnutt@artsyncp.com
  7. *
  8. * (C) Copyright 2003 (440GX port)
  9. * Travis B. Sawyer, Sandburst Corporation, tsawyer@sandburst.com
  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. #include <common.h>
  30. #include <watchdog.h>
  31. #include <command.h>
  32. #include <asm/processor.h>
  33. #include <ppc4xx.h>
  34. #include <ppc_asm.tmpl>
  35. #include <commproc.h>
  36. #if (UIC_MAX > 3)
  37. #define UICB0_ALL (UIC_MASK(VECNUM_UIC1CI) | UIC_MASK(VECNUM_UIC1NCI) | \
  38. UIC_MASK(VECNUM_UIC2CI) | UIC_MASK(VECNUM_UIC2NCI) | \
  39. UIC_MASK(VECNUM_UIC3CI) | UIC_MASK(VECNUM_UIC3NCI))
  40. #elif (UIC_MAX > 2)
  41. #if defined(CONFIG_440GX)
  42. #define UICB0_ALL (UIC_MASK(VECNUM_UIC0CI) | UIC_MASK(VECNUM_UIC0NCI) | \
  43. UIC_MASK(VECNUM_UIC1CI) | UIC_MASK(VECNUM_UIC1NCI) | \
  44. UIC_MASK(VECNUM_UIC2CI) | UIC_MASK(VECNUM_UIC2NCI))
  45. #else
  46. #define UICB0_ALL (UIC_MASK(VECNUM_UIC1CI) | UIC_MASK(VECNUM_UIC1NCI) | \
  47. UIC_MASK(VECNUM_UIC2CI) | UIC_MASK(VECNUM_UIC2NCI))
  48. #endif
  49. #elif (UIC_MAX > 1)
  50. #define UICB0_ALL (UIC_MASK(VECNUM_UIC1CI) | UIC_MASK(VECNUM_UIC1NCI))
  51. #else
  52. #define UICB0_ALL 0
  53. #endif
  54. DECLARE_GLOBAL_DATA_PTR;
  55. /*
  56. * CPM interrupt vector functions.
  57. */
  58. struct irq_action {
  59. interrupt_handler_t *handler;
  60. void *arg;
  61. int count;
  62. };
  63. static struct irq_action irq_vecs[UIC_MAX * 32];
  64. u32 get_dcr(u16);
  65. void set_dcr(u16, u32);
  66. #if (UIC_MAX > 1) && !defined(CONFIG_440GX)
  67. static void uic_cascade_interrupt(void *para);
  68. #endif
  69. #if defined(CONFIG_440)
  70. /* SPRN changed in 440 */
  71. static __inline__ void set_evpr(unsigned long val)
  72. {
  73. asm volatile("mtspr 0x03f,%0" : : "r" (val));
  74. }
  75. #else /* !defined(CONFIG_440) */
  76. static __inline__ void set_pit(unsigned long val)
  77. {
  78. asm volatile("mtpit %0" : : "r" (val));
  79. }
  80. static __inline__ void set_tcr(unsigned long val)
  81. {
  82. asm volatile("mttcr %0" : : "r" (val));
  83. }
  84. static __inline__ void set_evpr(unsigned long val)
  85. {
  86. asm volatile("mtevpr %0" : : "r" (val));
  87. }
  88. #endif /* defined(CONFIG_440 */
  89. int interrupt_init_cpu (unsigned *decrementer_count)
  90. {
  91. int vec;
  92. unsigned long val;
  93. /* decrementer is automatically reloaded */
  94. *decrementer_count = 0;
  95. /*
  96. * Mark all irqs as free
  97. */
  98. for (vec = 0; vec < (UIC_MAX * 32); vec++) {
  99. irq_vecs[vec].handler = NULL;
  100. irq_vecs[vec].arg = NULL;
  101. irq_vecs[vec].count = 0;
  102. }
  103. #ifdef CONFIG_4xx
  104. /*
  105. * Init PIT
  106. */
  107. #if defined(CONFIG_440)
  108. val = mfspr( tcr );
  109. val &= (~0x04400000); /* clear DIS & ARE */
  110. mtspr( tcr, val );
  111. mtspr( dec, 0 ); /* Prevent exception after TSR clear*/
  112. mtspr( decar, 0 ); /* clear reload */
  113. mtspr( tsr, 0x08000000 ); /* clear DEC status */
  114. val = gd->bd->bi_intfreq/1000; /* 1 msec */
  115. mtspr( decar, val ); /* Set auto-reload value */
  116. mtspr( dec, val ); /* Set inital val */
  117. #else
  118. set_pit(gd->bd->bi_intfreq / 1000);
  119. #endif
  120. #endif /* CONFIG_4xx */
  121. #ifdef CONFIG_ADCIOP
  122. /*
  123. * Init PIT
  124. */
  125. set_pit(66000);
  126. #endif
  127. /*
  128. * Enable PIT
  129. */
  130. val = mfspr(tcr);
  131. val |= 0x04400000;
  132. mtspr(tcr, val);
  133. /*
  134. * Set EVPR to 0
  135. */
  136. set_evpr(0x00000000);
  137. #if !defined(CONFIG_440GX)
  138. #if (UIC_MAX > 1)
  139. /* Install the UIC1 handlers */
  140. irq_install_handler(VECNUM_UIC1NCI, uic_cascade_interrupt, 0);
  141. irq_install_handler(VECNUM_UIC1CI, uic_cascade_interrupt, 0);
  142. #endif
  143. #if (UIC_MAX > 2)
  144. irq_install_handler(VECNUM_UIC2NCI, uic_cascade_interrupt, 0);
  145. irq_install_handler(VECNUM_UIC2CI, uic_cascade_interrupt, 0);
  146. #endif
  147. #if (UIC_MAX > 3)
  148. irq_install_handler(VECNUM_UIC3NCI, uic_cascade_interrupt, 0);
  149. irq_install_handler(VECNUM_UIC3CI, uic_cascade_interrupt, 0);
  150. #endif
  151. #else /* !defined(CONFIG_440GX) */
  152. /*
  153. * ToDo: Remove this 440GX special handling:
  154. * Move SDR0_MFR setup to cpu.c and use common code with UICB0
  155. * on 440GX. 2008-06-26, sr
  156. */
  157. /* Take the GX out of compatibility mode
  158. * Travis Sawyer, 9 Mar 2004
  159. * NOTE: 440gx user manual inconsistency here
  160. * Compatibility mode and Ethernet Clock select are not
  161. * correct in the manual
  162. */
  163. mfsdr(sdr_mfr, val);
  164. val &= ~0x10000000;
  165. mtsdr(sdr_mfr,val);
  166. /* Enable UIC interrupts via UIC Base Enable Register */
  167. mtdcr(uicb0sr, UICB0_ALL);
  168. mtdcr(uicb0er, UICB0_ALL);
  169. /* None are critical */
  170. mtdcr(uicb0cr, 0);
  171. #endif /* !defined(CONFIG_440GX) */
  172. return (0);
  173. }
  174. /* Handler for UIC interrupt */
  175. static void uic_interrupt(u32 uic_base, int vec_base)
  176. {
  177. u32 uic_msr;
  178. u32 msr_shift;
  179. int vec;
  180. /*
  181. * Read masked interrupt status register to determine interrupt source
  182. */
  183. uic_msr = get_dcr(uic_base + UIC_MSR);
  184. msr_shift = uic_msr;
  185. vec = vec_base;
  186. while (msr_shift != 0) {
  187. if (msr_shift & 0x80000000) {
  188. /*
  189. * Increment irq counter (for debug purpose only)
  190. */
  191. irq_vecs[vec].count++;
  192. if (irq_vecs[vec].handler != NULL) {
  193. /* call isr */
  194. (*irq_vecs[vec].handler)(irq_vecs[vec].arg);
  195. } else {
  196. set_dcr(uic_base + UIC_ER,
  197. get_dcr(uic_base + UIC_ER) & ~UIC_MASK(vec));
  198. printf("Masking bogus interrupt vector %d"
  199. " (UIC_BASE=0x%x)\n", vec, uic_base);
  200. }
  201. /*
  202. * After servicing the interrupt, we have to remove the
  203. * status indicator
  204. */
  205. set_dcr(uic_base + UIC_SR, UIC_MASK(vec));
  206. }
  207. /*
  208. * Shift msr to next position and increment vector
  209. */
  210. msr_shift <<= 1;
  211. vec++;
  212. }
  213. }
  214. #if (UIC_MAX > 1) && !defined(CONFIG_440GX)
  215. static void uic_cascade_interrupt(void *para)
  216. {
  217. external_interrupt(para);
  218. }
  219. #endif
  220. #if defined(CONFIG_440GX)
  221. /* 440GX uses base uic register */
  222. #define UIC_BMSR uicb0msr
  223. #define UIC_BSR uicb0sr
  224. #else
  225. #define UIC_BMSR uic0msr
  226. #define UIC_BSR uic0sr
  227. #endif
  228. /*
  229. * Handle external interrupts
  230. */
  231. void external_interrupt(struct pt_regs *regs)
  232. {
  233. u32 uic_msr;
  234. /*
  235. * Read masked interrupt status register to determine interrupt source
  236. */
  237. uic_msr = mfdcr(UIC_BMSR);
  238. #if (UIC_MAX > 1)
  239. if ((UIC_MASK(VECNUM_UIC1CI) & uic_msr) ||
  240. (UIC_MASK(VECNUM_UIC1NCI) & uic_msr))
  241. uic_interrupt(UIC1_DCR_BASE, 32);
  242. #endif
  243. #if (UIC_MAX > 2)
  244. if ((UIC_MASK(VECNUM_UIC2CI) & uic_msr) ||
  245. (UIC_MASK(VECNUM_UIC2NCI) & uic_msr))
  246. uic_interrupt(UIC2_DCR_BASE, 64);
  247. #endif
  248. #if (UIC_MAX > 3)
  249. if ((UIC_MASK(VECNUM_UIC3CI) & uic_msr) ||
  250. (UIC_MASK(VECNUM_UIC3NCI) & uic_msr))
  251. uic_interrupt(UIC3_DCR_BASE, 96);
  252. #endif
  253. #if defined(CONFIG_440)
  254. #if !defined(CONFIG_440GX)
  255. if (uic_msr & ~(UICB0_ALL))
  256. uic_interrupt(UIC0_DCR_BASE, 0);
  257. #else
  258. if ((UIC_MASK(VECNUM_UIC0CI) & uic_msr) ||
  259. (UIC_MASK(VECNUM_UIC0NCI) & uic_msr))
  260. uic_interrupt(UIC0_DCR_BASE, 0);
  261. #endif
  262. #else /* CONFIG_440 */
  263. uic_interrupt(UIC0_DCR_BASE, 0);
  264. #endif /* CONFIG_440 */
  265. mtdcr(UIC_BSR, uic_msr);
  266. return;
  267. }
  268. /*
  269. * Install and free a interrupt handler.
  270. */
  271. void irq_install_handler(int vec, interrupt_handler_t * handler, void *arg)
  272. {
  273. int i;
  274. /*
  275. * Print warning when replacing with a different irq vector
  276. */
  277. if ((irq_vecs[vec].handler != NULL) && (irq_vecs[vec].handler != handler)) {
  278. printf("Interrupt vector %d: handler 0x%x replacing 0x%x\n",
  279. vec, (uint) handler, (uint) irq_vecs[vec].handler);
  280. }
  281. irq_vecs[vec].handler = handler;
  282. irq_vecs[vec].arg = arg;
  283. i = vec & 0x1f;
  284. if ((vec >= 0) && (vec < 32))
  285. mtdcr(uicer, mfdcr(uicer) | (0x80000000 >> i));
  286. #if (UIC_MAX > 1)
  287. else if ((vec >= 32) && (vec < 64))
  288. mtdcr(uic1er, mfdcr(uic1er) | (0x80000000 >> i));
  289. #endif
  290. #if (UIC_MAX > 2)
  291. else if ((vec >= 64) && (vec < 96))
  292. mtdcr(uic2er, mfdcr(uic2er) | (0x80000000 >> i));
  293. #endif
  294. #if (UIC_MAX > 3)
  295. else if (vec >= 96)
  296. mtdcr(uic3er, mfdcr(uic3er) | (0x80000000 >> i));
  297. #endif
  298. debug("Install interrupt for vector %d ==> %p\n", vec, handler);
  299. }
  300. void irq_free_handler (int vec)
  301. {
  302. int i;
  303. debug("Free interrupt for vector %d ==> %p\n",
  304. vec, irq_vecs[vec].handler);
  305. i = vec & 0x1f;
  306. if ((vec >= 0) && (vec < 32))
  307. mtdcr(uicer, mfdcr(uicer) & ~(0x80000000 >> i));
  308. #if (UIC_MAX > 1)
  309. else if ((vec >= 32) && (vec < 64))
  310. mtdcr(uic1er, mfdcr(uic1er) & ~(0x80000000 >> i));
  311. #endif
  312. #if (UIC_MAX > 2)
  313. else if ((vec >= 64) && (vec < 96))
  314. mtdcr(uic2er, mfdcr(uic2er) & ~(0x80000000 >> i));
  315. #endif
  316. #if (UIC_MAX > 3)
  317. else if (vec >= 96)
  318. mtdcr(uic3er, mfdcr(uic3er) & ~(0x80000000 >> i));
  319. #endif
  320. irq_vecs[vec].handler = NULL;
  321. irq_vecs[vec].arg = NULL;
  322. }
  323. void timer_interrupt_cpu (struct pt_regs *regs)
  324. {
  325. /* nothing to do here */
  326. return;
  327. }
  328. #if defined(CONFIG_CMD_IRQ)
  329. int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
  330. {
  331. int vec;
  332. printf ("Interrupt-Information:\n");
  333. printf ("Nr Routine Arg Count\n");
  334. for (vec = 0; vec < (UIC_MAX * 32); vec++) {
  335. if (irq_vecs[vec].handler != NULL) {
  336. printf ("%02d %08lx %08lx %d\n",
  337. vec,
  338. (ulong)irq_vecs[vec].handler,
  339. (ulong)irq_vecs[vec].arg,
  340. irq_vecs[vec].count);
  341. }
  342. }
  343. return 0;
  344. }
  345. #endif