interrupts.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  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 cpm_action {
  36. interrupt_handler_t *handler;
  37. void *arg;
  38. };
  39. static struct cpm_action cpm_vecs[CPMVEC_NR];
  40. static void cpm_interrupt_init (void);
  41. static void cpm_interrupt(int irq, struct pt_regs * regs);
  42. /****************************************************************************/
  43. static __inline__ unsigned long get_msr(void)
  44. {
  45. unsigned long msr;
  46. asm volatile("mfmsr %0" : "=r" (msr) :);
  47. return msr;
  48. }
  49. static __inline__ void set_msr(unsigned long msr)
  50. {
  51. asm volatile("mtmsr %0" : : "r" (msr));
  52. }
  53. static __inline__ unsigned long get_dec(void)
  54. {
  55. unsigned long val;
  56. asm volatile("mfdec %0" : "=r" (val) :);
  57. return val;
  58. }
  59. static __inline__ void set_dec(unsigned long val)
  60. {
  61. asm volatile("mtdec %0" : : "r" (val));
  62. }
  63. void enable_interrupts (void)
  64. {
  65. set_msr (get_msr() | MSR_EE);
  66. }
  67. /* returns flag if MSR_EE was set before */
  68. int disable_interrupts (void)
  69. {
  70. ulong msr = get_msr();
  71. set_msr (msr & ~MSR_EE);
  72. return ((msr & MSR_EE) != 0);
  73. }
  74. /****************************************************************************/
  75. int interrupt_init(void)
  76. {
  77. volatile immap_t *immr = (immap_t *)CFG_IMMR;
  78. decrementer_count = get_tbclk() / CFG_HZ;
  79. cpm_interrupt_init();
  80. /* disable all interrupts except for the CPM interrupt */
  81. immr->im_siu_conf.sc_simask = 1 << (31-CPM_INTERRUPT);
  82. set_dec (decrementer_count);
  83. set_msr (get_msr() | MSR_EE);
  84. return (0);
  85. }
  86. /****************************************************************************/
  87. /*
  88. * Handle external interrupts
  89. */
  90. void external_interrupt(struct pt_regs *regs)
  91. {
  92. volatile immap_t *immr = (immap_t *)CFG_IMMR;
  93. int irq;
  94. ulong simask, newmask;
  95. ulong vec, v_bit;
  96. /*
  97. * read the SIVEC register and shift the bits down
  98. * to get the irq number
  99. */
  100. vec = immr->im_siu_conf.sc_sivec;
  101. irq = vec >> 26;
  102. v_bit = 0x80000000UL >> irq;
  103. /*
  104. * Read Interrupt Mask Register and Mask Interrupts
  105. */
  106. simask = immr->im_siu_conf.sc_simask;
  107. newmask = simask & (~(0xFFFF0000 >> irq));
  108. immr->im_siu_conf.sc_simask = newmask;
  109. if (!(irq & 0x1)) { /* External Interrupt ? */
  110. ulong siel;
  111. /*
  112. * Read Interrupt Edge/Level Register
  113. */
  114. siel = immr->im_siu_conf.sc_siel;
  115. if (siel & v_bit) { /* edge triggered interrupt ? */
  116. /*
  117. * Rewrite SIPEND Register to clear interrupt
  118. */
  119. immr->im_siu_conf.sc_sipend = v_bit;
  120. }
  121. }
  122. switch (irq) {
  123. case CPM_INTERRUPT:
  124. cpm_interrupt (irq, regs);
  125. break;
  126. default:
  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. break;
  132. }
  133. /*
  134. * Re-Enable old Interrupt Mask
  135. */
  136. immr->im_siu_conf.sc_simask = simask;
  137. }
  138. /****************************************************************************/
  139. /*
  140. * CPM interrupt handler
  141. */
  142. static void
  143. cpm_interrupt(int irq, struct pt_regs * regs)
  144. {
  145. volatile immap_t *immr = (immap_t *)CFG_IMMR;
  146. uint vec;
  147. /*
  148. * Get the vector by setting the ACK bit
  149. * and then reading the register.
  150. */
  151. immr->im_cpic.cpic_civr = 1;
  152. vec = immr->im_cpic.cpic_civr;
  153. vec >>= 11;
  154. if (cpm_vecs[vec].handler != NULL) {
  155. (*cpm_vecs[vec].handler)(cpm_vecs[vec].arg);
  156. } else {
  157. immr->im_cpic.cpic_cimr &= ~(1 << vec);
  158. printf ("Masking bogus CPM interrupt vector 0x%x\n", vec);
  159. }
  160. /*
  161. * After servicing the interrupt, we have to remove the status indicator.
  162. */
  163. immr->im_cpic.cpic_cisr |= (1 << vec);
  164. }
  165. /*
  166. * The CPM can generate the error interrupt when there is a race
  167. * condition between generating and masking interrupts. All we have
  168. * to do is ACK it and return. This is a no-op function so we don't
  169. * need any special tests in the interrupt handler.
  170. */
  171. static void
  172. cpm_error_interrupt (void *dummy)
  173. {
  174. }
  175. /****************************************************************************/
  176. /*
  177. * Install and free a CPM interrupt handler.
  178. */
  179. void
  180. irq_install_handler(int vec, interrupt_handler_t *handler, void *arg)
  181. {
  182. volatile immap_t *immr = (immap_t *)CFG_IMMR;
  183. if (cpm_vecs[vec].handler != NULL) {
  184. printf ("CPM interrupt 0x%x replacing 0x%x\n",
  185. (uint)handler, (uint)cpm_vecs[vec].handler);
  186. }
  187. cpm_vecs[vec].handler = handler;
  188. cpm_vecs[vec].arg = arg;
  189. immr->im_cpic.cpic_cimr |= (1 << vec);
  190. #if 0
  191. printf ("Install CPM interrupt for vector %d ==> %p\n", vec, handler);
  192. #endif
  193. }
  194. void
  195. irq_free_handler(int vec)
  196. {
  197. volatile immap_t *immr = (immap_t *)CFG_IMMR;
  198. #if 0
  199. printf ("Free CPM interrupt for vector %d ==> %p\n",
  200. vec, cpm_vecs[vec].handler);
  201. #endif
  202. immr->im_cpic.cpic_cimr &= ~(1 << vec);
  203. cpm_vecs[vec].handler = NULL;
  204. cpm_vecs[vec].arg = NULL;
  205. }
  206. /****************************************************************************/
  207. static void
  208. cpm_interrupt_init (void)
  209. {
  210. volatile immap_t *immr = (immap_t *)CFG_IMMR;
  211. /*
  212. * Initialize the CPM interrupt controller.
  213. */
  214. immr->im_cpic.cpic_cicr =
  215. ( CICR_SCD_SCC4 |
  216. CICR_SCC_SCC3 |
  217. CICR_SCB_SCC2 |
  218. CICR_SCA_SCC1 ) | ((CPM_INTERRUPT/2) << 13) | CICR_HP_MASK;
  219. immr->im_cpic.cpic_cimr = 0;
  220. /*
  221. * Install the error handler.
  222. */
  223. irq_install_handler(CPMVEC_ERROR, cpm_error_interrupt, NULL);
  224. immr->im_cpic.cpic_cicr |= CICR_IEN;
  225. }
  226. /****************************************************************************/
  227. volatile ulong timestamp = 0;
  228. /*
  229. * timer_interrupt - gets called when the decrementer overflows,
  230. * with interrupts disabled.
  231. * Trivial implementation - no need to be really accurate.
  232. */
  233. void timer_interrupt(struct pt_regs *regs)
  234. {
  235. volatile immap_t *immr = (immap_t *)CFG_IMMR;
  236. #ifdef CONFIG_STATUS_LED
  237. extern void status_led_tick (ulong);
  238. #endif
  239. #if 0
  240. printf ("*** Timer Interrupt *** ");
  241. #endif
  242. /* Reset Timer Expired and Timers Interrupt Status */
  243. immr->im_clkrstk.cark_plprcrk = KAPWR_KEY;
  244. __asm__("nop");
  245. immr->im_clkrst.car_plprcr |= PLPRCR_TEXPS | PLPRCR_TMIST;
  246. /* Restore Decrementer Count */
  247. set_dec (decrementer_count);
  248. timestamp++;
  249. #ifdef CONFIG_STATUS_LED
  250. status_led_tick (timestamp);
  251. #endif /* CONFIG_STATUS_LED */
  252. #if defined(CONFIG_WATCHDOG) || defined(CFG_CMA_LCD_HEARTBEAT)
  253. /*
  254. * The shortest watchdog period of all boards (except LWMON)
  255. * is approx. 1 sec, thus re-trigger watchdog at least
  256. * every 500 ms = CFG_HZ / 2
  257. */
  258. #ifndef CONFIG_LWMON
  259. if ((timestamp % (CFG_HZ / 2)) == 0) {
  260. #else
  261. if ((timestamp % (CFG_HZ / 20)) == 0) {
  262. #endif
  263. #if defined(CFG_CMA_LCD_HEARTBEAT)
  264. extern void lcd_heartbeat(void);
  265. lcd_heartbeat();
  266. #endif /* CFG_CMA_LCD_HEARTBEAT */
  267. #if defined(CONFIG_WATCHDOG)
  268. reset_8xx_watchdog(immr);
  269. #endif /* CONFIG_WATCHDOG */
  270. }
  271. #endif /* CONFIG_WATCHDOG || CFG_CMA_LCD_HEARTBEAT */
  272. }
  273. /****************************************************************************/
  274. void reset_timer (void)
  275. {
  276. timestamp = 0;
  277. }
  278. ulong get_timer (ulong base)
  279. {
  280. return (timestamp - base);
  281. }
  282. void set_timer (ulong t)
  283. {
  284. timestamp = t;
  285. }
  286. /****************************************************************************/