interrupts.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. /*
  2. * (C) Copyright 2000-2002
  3. * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
  4. *
  5. * See file CREDITS for list of people who contributed to this
  6. * project.
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License as
  10. * published by the Free Software Foundation; either version 2 of
  11. * the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  21. * MA 02111-1307 USA
  22. */
  23. #include <common.h>
  24. #include <watchdog.h>
  25. #include <mpc8xx.h>
  26. #include <mpc8xx_irq.h>
  27. #include <asm/processor.h>
  28. #include <commproc.h>
  29. /************************************************************************/
  30. unsigned decrementer_count; /* count value for 1e6/HZ microseconds */
  31. /************************************************************************/
  32. /*
  33. * CPM interrupt vector functions.
  34. */
  35. struct interrupt_action {
  36. interrupt_handler_t *handler;
  37. void *arg;
  38. };
  39. static struct interrupt_action cpm_vecs[CPMVEC_NR];
  40. static struct interrupt_action irq_vecs[NR_IRQS];
  41. static void cpm_interrupt_init (void);
  42. static void cpm_interrupt (void *regs);
  43. /************************************************************************/
  44. static __inline__ unsigned long get_msr (void)
  45. {
  46. unsigned long msr;
  47. asm volatile ("mfmsr %0":"=r" (msr):);
  48. return msr;
  49. }
  50. static __inline__ void set_msr (unsigned long msr)
  51. {
  52. asm volatile ("mtmsr %0"::"r" (msr));
  53. }
  54. static __inline__ unsigned long get_dec (void)
  55. {
  56. unsigned long val;
  57. asm volatile ("mfdec %0":"=r" (val):);
  58. return val;
  59. }
  60. static __inline__ void set_dec (unsigned long val)
  61. {
  62. asm volatile ("mtdec %0"::"r" (val));
  63. }
  64. void enable_interrupts (void)
  65. {
  66. set_msr (get_msr () | MSR_EE);
  67. }
  68. /* returns flag if MSR_EE was set before */
  69. int disable_interrupts (void)
  70. {
  71. ulong msr = get_msr ();
  72. set_msr (msr & ~MSR_EE);
  73. return ((msr & MSR_EE) != 0);
  74. }
  75. /************************************************************************/
  76. int interrupt_init (void)
  77. {
  78. volatile immap_t *immr = (immap_t *) CFG_IMMR;
  79. decrementer_count = get_tbclk () / CFG_HZ;
  80. /* disable all interrupts */
  81. immr->im_siu_conf.sc_simask = 0;
  82. /* Configure CPM interrupts */
  83. cpm_interrupt_init ();
  84. set_dec (decrementer_count);
  85. set_msr (get_msr () | MSR_EE);
  86. return (0);
  87. }
  88. /************************************************************************/
  89. /*
  90. * Handle external interrupts
  91. */
  92. void external_interrupt (struct pt_regs *regs)
  93. {
  94. volatile immap_t *immr = (immap_t *) CFG_IMMR;
  95. int irq;
  96. ulong simask, newmask;
  97. ulong vec, v_bit;
  98. /*
  99. * read the SIVEC register and shift the bits down
  100. * to get the irq number
  101. */
  102. vec = immr->im_siu_conf.sc_sivec;
  103. irq = vec >> 26;
  104. v_bit = 0x80000000UL >> irq;
  105. /*
  106. * Read Interrupt Mask Register and Mask Interrupts
  107. */
  108. simask = immr->im_siu_conf.sc_simask;
  109. newmask = simask & (~(0xFFFF0000 >> irq));
  110. immr->im_siu_conf.sc_simask = newmask;
  111. if (!(irq & 0x1)) { /* External Interrupt ? */
  112. ulong siel;
  113. /*
  114. * Read Interrupt Edge/Level Register
  115. */
  116. siel = immr->im_siu_conf.sc_siel;
  117. if (siel & v_bit) { /* edge triggered interrupt ? */
  118. /*
  119. * Rewrite SIPEND Register to clear interrupt
  120. */
  121. immr->im_siu_conf.sc_sipend = v_bit;
  122. }
  123. }
  124. if (irq_vecs[irq].handler != NULL) {
  125. irq_vecs[irq].handler (irq_vecs[irq].arg);
  126. } else {
  127. printf ("\nBogus External Interrupt IRQ %d Vector %ld\n",
  128. irq, vec);
  129. /* turn off the bogus interrupt to avoid it from now */
  130. simask &= ~v_bit;
  131. }
  132. /*
  133. * Re-Enable old Interrupt Mask
  134. */
  135. immr->im_siu_conf.sc_simask = simask;
  136. }
  137. /************************************************************************/
  138. /*
  139. * CPM interrupt handler
  140. */
  141. static void cpm_interrupt (void *regs)
  142. {
  143. volatile immap_t *immr = (immap_t *) CFG_IMMR;
  144. uint vec;
  145. /*
  146. * Get the vector by setting the ACK bit
  147. * and then reading the register.
  148. */
  149. immr->im_cpic.cpic_civr = 1;
  150. vec = immr->im_cpic.cpic_civr;
  151. vec >>= 11;
  152. if (cpm_vecs[vec].handler != NULL) {
  153. (*cpm_vecs[vec].handler) (cpm_vecs[vec].arg);
  154. } else {
  155. immr->im_cpic.cpic_cimr &= ~(1 << vec);
  156. printf ("Masking bogus CPM interrupt vector 0x%x\n", vec);
  157. }
  158. /*
  159. * After servicing the interrupt,
  160. * we have to remove the status indicator.
  161. */
  162. immr->im_cpic.cpic_cisr |= (1 << vec);
  163. }
  164. /*
  165. * The CPM can generate the error interrupt when there is a race
  166. * condition between generating and masking interrupts. All we have
  167. * to do is ACK it and return. This is a no-op function so we don't
  168. * need any special tests in the interrupt handler.
  169. */
  170. static void cpm_error_interrupt (void *dummy)
  171. {
  172. }
  173. /************************************************************************/
  174. /*
  175. * Install and free an interrupt handler
  176. */
  177. void irq_install_handler (int vec, interrupt_handler_t * handler,
  178. void *arg)
  179. {
  180. volatile immap_t *immr = (immap_t *) CFG_IMMR;
  181. if ((vec & CPMVEC_OFFSET) != 0) {
  182. /* CPM interrupt */
  183. vec &= 0xffff;
  184. if (cpm_vecs[vec].handler != NULL) {
  185. printf ("CPM interrupt 0x%x replacing 0x%x\n",
  186. (uint) handler,
  187. (uint) cpm_vecs[vec].handler);
  188. }
  189. cpm_vecs[vec].handler = handler;
  190. cpm_vecs[vec].arg = arg;
  191. immr->im_cpic.cpic_cimr |= (1 << vec);
  192. #if 0
  193. printf ("Install CPM interrupt for vector %d ==> %p\n",
  194. vec, handler);
  195. #endif
  196. } else {
  197. /* SIU interrupt */
  198. if (irq_vecs[vec].handler != NULL) {
  199. printf ("SIU interrupt %d 0x%x replacing 0x%x\n",
  200. vec,
  201. (uint) handler,
  202. (uint) cpm_vecs[vec].handler);
  203. }
  204. irq_vecs[vec].handler = handler;
  205. irq_vecs[vec].arg = arg;
  206. immr->im_siu_conf.sc_simask |= 1 << (31 - vec);
  207. #if 0
  208. printf ("Install SIU interrupt for vector %d ==> %p\n",
  209. vec, handler);
  210. #endif
  211. }
  212. }
  213. void irq_free_handler (int vec)
  214. {
  215. volatile immap_t *immr = (immap_t *) CFG_IMMR;
  216. if ((vec & CPMVEC_OFFSET) != 0) {
  217. /* CPM interrupt */
  218. vec &= 0xffff;
  219. #if 0
  220. printf ("Free CPM interrupt for vector %d ==> %p\n",
  221. vec, cpm_vecs[vec].handler);
  222. #endif
  223. immr->im_cpic.cpic_cimr &= ~(1 << vec);
  224. cpm_vecs[vec].handler = NULL;
  225. cpm_vecs[vec].arg = NULL;
  226. } else {
  227. /* SIU interrupt */
  228. #if 0
  229. printf ("Free CPM interrupt for vector %d ==> %p\n",
  230. vec, cpm_vecs[vec].handler);
  231. #endif
  232. immr->im_siu_conf.sc_simask &= ~(1 << (31 - vec));
  233. irq_vecs[vec].handler = NULL;
  234. irq_vecs[vec].arg = NULL;
  235. }
  236. }
  237. /************************************************************************/
  238. static void cpm_interrupt_init (void)
  239. {
  240. volatile immap_t *immr = (immap_t *) CFG_IMMR;
  241. /*
  242. * Initialize the CPM interrupt controller.
  243. */
  244. immr->im_cpic.cpic_cicr =
  245. (CICR_SCD_SCC4 |
  246. CICR_SCC_SCC3 |
  247. CICR_SCB_SCC2 |
  248. CICR_SCA_SCC1) | ((CPM_INTERRUPT / 2) << 13) | CICR_HP_MASK;
  249. immr->im_cpic.cpic_cimr = 0;
  250. /*
  251. * Install the error handler.
  252. */
  253. irq_install_handler (CPMVEC_ERROR, cpm_error_interrupt, NULL);
  254. immr->im_cpic.cpic_cicr |= CICR_IEN;
  255. /*
  256. * Install the cpm interrupt handler
  257. */
  258. irq_install_handler (CPM_INTERRUPT, cpm_interrupt, NULL);
  259. }
  260. /************************************************************************/
  261. volatile ulong timestamp = 0;
  262. /*
  263. * timer_interrupt - gets called when the decrementer overflows,
  264. * with interrupts disabled.
  265. * Trivial implementation - no need to be really accurate.
  266. */
  267. void timer_interrupt (struct pt_regs *regs)
  268. {
  269. volatile immap_t *immr = (immap_t *) CFG_IMMR;
  270. #ifdef CONFIG_STATUS_LED
  271. extern void status_led_tick (ulong);
  272. #endif
  273. #if 0
  274. printf ("*** Timer Interrupt *** ");
  275. #endif
  276. /* Reset Timer Expired and Timers Interrupt Status */
  277. immr->im_clkrstk.cark_plprcrk = KAPWR_KEY;
  278. __asm__ ("nop");
  279. #ifdef CONFIG_MPC866_et_al
  280. immr->im_clkrst.car_plprcr |= PLPRCR_TEXPS;
  281. #else
  282. immr->im_clkrst.car_plprcr |= PLPRCR_TEXPS | PLPRCR_TMIST;
  283. #endif
  284. /* Restore Decrementer Count */
  285. set_dec (decrementer_count);
  286. timestamp++;
  287. #ifdef CONFIG_STATUS_LED
  288. status_led_tick (timestamp);
  289. #endif /* CONFIG_STATUS_LED */
  290. #if defined(CONFIG_WATCHDOG) || defined(CFG_CMA_LCD_HEARTBEAT)
  291. /*
  292. * The shortest watchdog period of all boards (except LWMON)
  293. * is approx. 1 sec, thus re-trigger watchdog at least
  294. * every 500 ms = CFG_HZ / 2
  295. */
  296. #ifndef CONFIG_LWMON
  297. if ((timestamp % (CFG_HZ / 2)) == 0) {
  298. #else
  299. if ((timestamp % (CFG_HZ / 20)) == 0) {
  300. #endif
  301. #if defined(CFG_CMA_LCD_HEARTBEAT)
  302. extern void lcd_heartbeat (void);
  303. lcd_heartbeat ();
  304. #endif /* CFG_CMA_LCD_HEARTBEAT */
  305. #if defined(CONFIG_WATCHDOG)
  306. reset_8xx_watchdog (immr);
  307. #endif /* CONFIG_WATCHDOG */
  308. }
  309. #endif /* CONFIG_WATCHDOG || CFG_CMA_LCD_HEARTBEAT */
  310. }
  311. /************************************************************************/
  312. void reset_timer (void)
  313. {
  314. timestamp = 0;
  315. }
  316. ulong get_timer (ulong base)
  317. {
  318. return (timestamp - base);
  319. }
  320. void set_timer (ulong t)
  321. {
  322. timestamp = t;
  323. }
  324. /************************************************************************/