interrupts.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. /*
  2. * (C) Copyright 2000-2002
  3. * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
  4. *
  5. * (C) Copyright 2004, Psyent Corporation <www.psyent.com>
  6. * Scott McNutt <smcnutt@psyent.com>
  7. *
  8. * SPDX-License-Identifier: GPL-2.0+
  9. */
  10. #include <asm/nios2.h>
  11. #include <asm/types.h>
  12. #include <asm/io.h>
  13. #include <asm/ptrace.h>
  14. #include <common.h>
  15. #include <command.h>
  16. #include <watchdog.h>
  17. #ifdef CONFIG_STATUS_LED
  18. #include <status_led.h>
  19. #endif
  20. typedef volatile struct {
  21. unsigned status; /* Timer status reg */
  22. unsigned control; /* Timer control reg */
  23. unsigned periodl; /* Timeout period low */
  24. unsigned periodh; /* Timeout period high */
  25. unsigned snapl; /* Snapshot low */
  26. unsigned snaph; /* Snapshot high */
  27. } nios_timer_t;
  28. /* status register */
  29. #define NIOS_TIMER_TO (1 << 0) /* Timeout */
  30. #define NIOS_TIMER_RUN (1 << 1) /* Timer running */
  31. /* control register */
  32. #define NIOS_TIMER_ITO (1 << 0) /* Timeout int ena */
  33. #define NIOS_TIMER_CONT (1 << 1) /* Continuous mode */
  34. #define NIOS_TIMER_START (1 << 2) /* Start timer */
  35. #define NIOS_TIMER_STOP (1 << 3) /* Stop timer */
  36. #if defined(CONFIG_SYS_NIOS_TMRBASE) && !defined(CONFIG_SYS_NIOS_TMRIRQ)
  37. #error CONFIG_SYS_NIOS_TMRIRQ not defined (see documentation)
  38. #endif
  39. /****************************************************************************/
  40. struct irq_action {
  41. interrupt_handler_t *handler;
  42. void *arg;
  43. int count;
  44. };
  45. static struct irq_action vecs[32];
  46. /*************************************************************************/
  47. volatile ulong timestamp = 0;
  48. void reset_timer (void)
  49. {
  50. nios_timer_t *tmr =(nios_timer_t *)CONFIG_SYS_NIOS_TMRBASE;
  51. /* From Embedded Peripherals Handbook:
  52. *
  53. * "When the hardware is configured with Writeable period
  54. * disabled, writing to one of the period_n registers causes
  55. * the counter to reset to the fixed Timeout Period specified
  56. * at system generation time."
  57. *
  58. * Here we force a reload to prevent early timeouts from
  59. * get_timer() when the interrupt period is greater than
  60. * than 1 msec.
  61. *
  62. * Simply write to periodl with its own value to force an
  63. * internal counter reload, THEN reset the timestamp.
  64. */
  65. writel (readl (&tmr->periodl), &tmr->periodl);
  66. timestamp = 0;
  67. /* From Embedded Peripherals Handbook:
  68. *
  69. * "Writing to one of the period_n registers stops the internal
  70. * counter, except when the hardware is configured with Start/Stop
  71. * control bits off. If Start/Stop control bits is off, writing
  72. * either register does not stop the counter."
  73. *
  74. * In order to accomodate either configuration, the control
  75. * register is re-written. If the counter is stopped, it will
  76. * be restarted. If it is running, the write is essentially
  77. * a nop.
  78. */
  79. writel (NIOS_TIMER_ITO | NIOS_TIMER_CONT | NIOS_TIMER_START,
  80. &tmr->control);
  81. }
  82. ulong get_timer (ulong base)
  83. {
  84. WATCHDOG_RESET ();
  85. return (timestamp - base);
  86. }
  87. /*
  88. * This function is derived from Blackfin code (read timebase as long long).
  89. * On Nios2 it just returns the timer value.
  90. */
  91. unsigned long long get_ticks(void)
  92. {
  93. return get_timer(0);
  94. }
  95. /*
  96. * This function is derived from Blackfin code.
  97. * On Nios2 it returns the number of timer ticks per second.
  98. */
  99. ulong get_tbclk(void)
  100. {
  101. ulong tbclk;
  102. tbclk = CONFIG_SYS_HZ;
  103. return tbclk;
  104. }
  105. /* The board must handle this interrupt if a timer is not
  106. * provided.
  107. */
  108. #if defined(CONFIG_SYS_NIOS_TMRBASE)
  109. void tmr_isr (void *arg)
  110. {
  111. nios_timer_t *tmr = (nios_timer_t *)arg;
  112. /* Interrupt is cleared by writing anything to the
  113. * status register.
  114. */
  115. writel (0, &tmr->status);
  116. timestamp += CONFIG_SYS_NIOS_TMRMS;
  117. #ifdef CONFIG_STATUS_LED
  118. status_led_tick(timestamp);
  119. #endif
  120. }
  121. static void tmr_init (void)
  122. {
  123. nios_timer_t *tmr =(nios_timer_t *)CONFIG_SYS_NIOS_TMRBASE;
  124. writel (0, &tmr->status);
  125. writel (0, &tmr->control);
  126. writel (NIOS_TIMER_STOP, &tmr->control);
  127. #if defined(CONFIG_SYS_NIOS_TMRCNT)
  128. writel (CONFIG_SYS_NIOS_TMRCNT & 0xffff, &tmr->periodl);
  129. writel ((CONFIG_SYS_NIOS_TMRCNT >> 16) & 0xffff, &tmr->periodh);
  130. #endif
  131. writel (NIOS_TIMER_ITO | NIOS_TIMER_CONT | NIOS_TIMER_START,
  132. &tmr->control);
  133. irq_install_handler (CONFIG_SYS_NIOS_TMRIRQ, tmr_isr, (void *)tmr);
  134. }
  135. #endif /* CONFIG_SYS_NIOS_TMRBASE */
  136. /*************************************************************************/
  137. int disable_interrupts (void)
  138. {
  139. int val = rdctl (CTL_STATUS);
  140. wrctl (CTL_STATUS, val & ~STATUS_IE);
  141. return (val & STATUS_IE);
  142. }
  143. void enable_interrupts( void )
  144. {
  145. int val = rdctl (CTL_STATUS);
  146. wrctl (CTL_STATUS, val | STATUS_IE);
  147. }
  148. void external_interrupt (struct pt_regs *regs)
  149. {
  150. unsigned irqs;
  151. struct irq_action *act;
  152. /* Evaluate only irqs that are both enabled AND pending */
  153. irqs = rdctl (CTL_IENABLE) & rdctl (CTL_IPENDING);
  154. act = vecs;
  155. /* Assume (as does the Nios2 HAL) that bit 0 is highest
  156. * priority. NOTE: There is ALWAYS a handler assigned
  157. * (the default if no other).
  158. */
  159. while (irqs) {
  160. if (irqs & 1) {
  161. act->handler (act->arg);
  162. act->count++;
  163. }
  164. irqs >>=1;
  165. act++;
  166. }
  167. }
  168. static void def_hdlr (void *arg)
  169. {
  170. unsigned irqs = rdctl (CTL_IENABLE);
  171. /* Disable the individual interrupt -- with gratuitous
  172. * warning.
  173. */
  174. irqs &= ~(1 << (int)arg);
  175. wrctl (CTL_IENABLE, irqs);
  176. printf ("WARNING: Disabling unhandled interrupt: %d\n",
  177. (int)arg);
  178. }
  179. /*************************************************************************/
  180. void irq_install_handler (int irq, interrupt_handler_t *hdlr, void *arg)
  181. {
  182. int flag;
  183. struct irq_action *act;
  184. unsigned ena = rdctl (CTL_IENABLE);
  185. if ((irq < 0) || (irq > 31))
  186. return;
  187. act = &vecs[irq];
  188. flag = disable_interrupts ();
  189. if (hdlr) {
  190. act->handler = hdlr;
  191. act->arg = arg;
  192. ena |= (1 << irq); /* enable */
  193. } else {
  194. act->handler = def_hdlr;
  195. act->arg = (void *)irq;
  196. ena &= ~(1 << irq); /* disable */
  197. }
  198. wrctl (CTL_IENABLE, ena);
  199. if (flag) enable_interrupts ();
  200. }
  201. int interrupt_init (void)
  202. {
  203. int i;
  204. /* Assign the default handler to all */
  205. for (i = 0; i < 32; i++) {
  206. vecs[i].handler = def_hdlr;
  207. vecs[i].arg = (void *)i;
  208. vecs[i].count = 0;
  209. }
  210. #if defined(CONFIG_SYS_NIOS_TMRBASE)
  211. tmr_init ();
  212. #endif
  213. enable_interrupts ();
  214. return (0);
  215. }
  216. /*************************************************************************/
  217. #if defined(CONFIG_CMD_IRQ)
  218. int do_irqinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  219. {
  220. int i;
  221. struct irq_action *act = vecs;
  222. printf ("\nInterrupt-Information:\n\n");
  223. printf ("Nr Routine Arg Count\n");
  224. printf ("-----------------------------\n");
  225. for (i=0; i<32; i++) {
  226. if (act->handler != def_hdlr) {
  227. printf ("%02d %08lx %08lx %d\n",
  228. i,
  229. (ulong)act->handler,
  230. (ulong)act->arg,
  231. act->count);
  232. }
  233. act++;
  234. }
  235. printf ("\n");
  236. return (0);
  237. }
  238. #endif