timer.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. /*
  2. * (C) Copyright 2000
  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 <commproc.h>
  25. #include <mpc8xx_irq.h>
  26. #include <syscall.h>
  27. #undef DEBUG
  28. #define TIMER_PERIOD 1000000 /* 1 second clock */
  29. static void timer_handler (void *arg);
  30. /* Access functions for the Machine State Register */
  31. static __inline__ unsigned long get_msr(void)
  32. {
  33. unsigned long msr;
  34. asm volatile("mfmsr %0" : "=r" (msr) :);
  35. return msr;
  36. }
  37. static __inline__ void set_msr(unsigned long msr)
  38. {
  39. asm volatile("mtmsr %0" : : "r" (msr));
  40. }
  41. /*
  42. * Definitions to access the CPM Timer registers
  43. * See 8xx_immap.h for Internal Memory Map layout,
  44. * and commproc.h for CPM Interrupt vectors (aka "IRQ"s)
  45. */
  46. typedef struct tid_8xx_cpmtimer_s {
  47. int cpm_vec; /* CPM Interrupt Vector for this timer */
  48. ushort *tgcrp; /* Pointer to Timer Global Config Reg. */
  49. ushort *tmrp; /* Pointer to Timer Mode Register */
  50. ushort *trrp; /* Pointer to Timer Reference Register */
  51. ushort *tcrp; /* Pointer to Timer Capture Register */
  52. ushort *tcnp; /* Pointer to Timer Counter Register */
  53. ushort *terp; /* Pointer to Timer Event Register */
  54. } tid_8xx_cpmtimer_t;
  55. #ifndef CLOCKRATE
  56. # define CLOCKRATE 64
  57. #endif
  58. #define CPMT_CLOCK_DIV 16
  59. #define CPMT_MAX_PRESCALER 256
  60. #define CPMT_MAX_REFERENCE 65535 /* max. unsigned short */
  61. #define CPMT_MAX_TICKS (CPMT_MAX_REFERENCE * CPMT_MAX_PRESCALER)
  62. #define CPMT_MAX_TICKS_WITH_DIV (CPMT_MAX_REFERENCE * CPMT_MAX_PRESCALER * CPMT_CLOCK_DIV)
  63. #define CPMT_MAX_INTERVAL (CPMT_MAX_TICKS_WITH_DIV / CLOCKRATE)
  64. /* For now: always use max. prescaler value */
  65. #define CPMT_PRESCALER (CPMT_MAX_PRESCALER)
  66. /* CPM Timer Event Register Bits */
  67. #define CPMT_EVENT_CAP 0x0001 /* Capture Event */
  68. #define CPMT_EVENT_REF 0x0002 /* Reference Counter Event */
  69. /* CPM Timer Global Config Register */
  70. #define CPMT_GCR_RST 0x0001 /* Reset Timer */
  71. #define CPMT_GCR_STP 0x0002 /* Stop Timer */
  72. #define CPMT_GCR_FRZ 0x0004 /* Freeze Timer */
  73. #define CPMT_GCR_GM_CAS 0x0008 /* Gate Mode / Cascade Timers */
  74. #define CPMT_GCR_MASK (CPMT_GCR_RST|CPMT_GCR_STP|CPMT_GCR_FRZ|CPMT_GCR_GM_CAS)
  75. /* CPM Timer Mode register */
  76. #define CPMT_MR_GE 0x0001 /* Gate Enable */
  77. #define CPMT_MR_ICLK_CASC 0x0000 /* Clock internally cascaded */
  78. #define CPMT_MR_ICLK_CLK 0x0002 /* Clock = system clock */
  79. #define CPMT_MR_ICLK_CLKDIV 0x0004 /* Clock = system clock / 16 */
  80. #define CPMT_MR_ICLK_TIN 0x0006 /* Clock = TINx signal */
  81. #define CPMT_MR_FRR 0x0008 /* Free Run / Restart */
  82. #define CPMT_MR_ORI 0x0010 /* Out. Reference Interrupt En. */
  83. #define CPMT_MR_OM 0x0020 /* Output Mode */
  84. #define CPMT_MR_CE_DIS 0x0000 /* Capture/Interrupt disabled */
  85. #define CPMT_MR_CE_RISE 0x0040 /* Capt./Interr. on rising TIN */
  86. #define CPMT_MR_CE_FALL 0x0080 /* Capt./Interr. on falling TIN */
  87. #define CPMT_MR_CE_ANY 0x00C0 /* Capt./Interr. on any TIN edge*/
  88. /*
  89. * which CPM timer to use - index starts at 0 (= timer 1)
  90. */
  91. #define TID_TIMER_ID 0 /* use CPM timer 1 */
  92. void setPeriod (tid_8xx_cpmtimer_t *hwp, ulong interval);
  93. static char *usage = "\n[q, b, e, ?] ";
  94. int timer (int argc, char *argv[])
  95. {
  96. DECLARE_GLOBAL_DATA_PTR;
  97. cpmtimer8xx_t *cpmtimerp; /* Pointer to the CPM Timer structure */
  98. tid_8xx_cpmtimer_t hw;
  99. tid_8xx_cpmtimer_t *hwp = &hw;
  100. int c;
  101. int running;
  102. /* Pointer to CPM Timer structure */
  103. cpmtimerp = &((immap_t *) gd->bd->bi_immr_base)->im_cpmtimer;
  104. mon_printf ("TIMERS=0x%x\n", (unsigned) cpmtimerp);
  105. /* Initialize pointers depending on which timer we use */
  106. switch (TID_TIMER_ID) {
  107. case 0:
  108. hwp->tmrp = &(cpmtimerp->cpmt_tmr1);
  109. hwp->trrp = &(cpmtimerp->cpmt_trr1);
  110. hwp->tcrp = &(cpmtimerp->cpmt_tcr1);
  111. hwp->tcnp = &(cpmtimerp->cpmt_tcn1);
  112. hwp->terp = &(cpmtimerp->cpmt_ter1);
  113. hwp->cpm_vec = CPMVEC_TIMER1;
  114. break;
  115. case 1:
  116. hwp->tmrp = &(cpmtimerp->cpmt_tmr2);
  117. hwp->trrp = &(cpmtimerp->cpmt_trr2);
  118. hwp->tcrp = &(cpmtimerp->cpmt_tcr2);
  119. hwp->tcnp = &(cpmtimerp->cpmt_tcn2);
  120. hwp->terp = &(cpmtimerp->cpmt_ter2);
  121. hwp->cpm_vec = CPMVEC_TIMER2;
  122. break;
  123. case 2:
  124. hwp->tmrp = &(cpmtimerp->cpmt_tmr3);
  125. hwp->trrp = &(cpmtimerp->cpmt_trr3);
  126. hwp->tcrp = &(cpmtimerp->cpmt_tcr3);
  127. hwp->tcnp = &(cpmtimerp->cpmt_tcn3);
  128. hwp->terp = &(cpmtimerp->cpmt_ter3);
  129. hwp->cpm_vec = CPMVEC_TIMER3;
  130. break;
  131. case 3:
  132. hwp->tmrp = &(cpmtimerp->cpmt_tmr4);
  133. hwp->trrp = &(cpmtimerp->cpmt_trr4);
  134. hwp->tcrp = &(cpmtimerp->cpmt_tcr4);
  135. hwp->tcnp = &(cpmtimerp->cpmt_tcn4);
  136. hwp->terp = &(cpmtimerp->cpmt_ter4);
  137. hwp->cpm_vec = CPMVEC_TIMER4;
  138. break;
  139. }
  140. hwp->tgcrp = &cpmtimerp->cpmt_tgcr;
  141. mon_printf ("Using timer %d\n"
  142. "tgcr @ 0x%x, tmr @ 0x%x, trr @ 0x%x,"
  143. " tcr @ 0x%x, tcn @ 0x%x, ter @ 0x%x\n",
  144. TID_TIMER_ID + 1,
  145. (unsigned) hwp->tgcrp,
  146. (unsigned) hwp->tmrp,
  147. (unsigned) hwp->trrp,
  148. (unsigned) hwp->tcrp,
  149. (unsigned) hwp->tcnp,
  150. (unsigned) hwp->terp
  151. );
  152. /* reset timer */
  153. *hwp->tgcrp &= ~(CPMT_GCR_MASK << TID_TIMER_ID);
  154. /* clear all events */
  155. *hwp->terp = (CPMT_EVENT_CAP | CPMT_EVENT_REF);
  156. mon_printf (usage);
  157. running = 0;
  158. while ((c = mon_getc()) != 'q') {
  159. if (c == 'b') {
  160. setPeriod (hwp, TIMER_PERIOD); /* Set period and start ticking */
  161. /* Install interrupt handler (enable timer in CIMR) */
  162. mon_install_hdlr (hwp->cpm_vec, timer_handler, hwp);
  163. mon_printf ("Enabling timer\n");
  164. /* enable timer */
  165. *hwp->tgcrp |= (CPMT_GCR_RST << TID_TIMER_ID);
  166. running = 1;
  167. #ifdef DEBUG
  168. mon_printf ("tgcr=0x%x, tmr=0x%x, trr=0x%x,"
  169. " tcr=0x%x, tcn=0x%x, ter=0x%x\n",
  170. *hwp->tgcrp, *hwp->tmrp, *hwp->trrp,
  171. *hwp->tcrp, *hwp->tcnp, *hwp->terp
  172. );
  173. #endif
  174. } else if (c == 'e') {
  175. mon_printf ("Stopping timer\n");
  176. *hwp->tgcrp &= ~(CPMT_GCR_MASK << TID_TIMER_ID);
  177. running = 0;
  178. #ifdef DEBUG
  179. mon_printf ("tgcr=0x%x, tmr=0x%x, trr=0x%x,"
  180. " tcr=0x%x, tcn=0x%x, ter=0x%x\n",
  181. *hwp->tgcrp, *hwp->tmrp, *hwp->trrp,
  182. *hwp->tcrp, *hwp->tcnp, *hwp->terp
  183. );
  184. #endif
  185. /* Uninstall interrupt handler */
  186. mon_free_hdlr (hwp->cpm_vec);
  187. } else if (c == '?') {
  188. #ifdef DEBUG
  189. cpic8xx_t *cpm_icp = &((immap_t *) gd->bd->bi_immr_base)->im_cpic;
  190. sysconf8xx_t *siup = &((immap_t *) gd->bd->bi_immr_base)->im_siu_conf;
  191. #endif
  192. mon_printf ("\ntgcr=0x%x, tmr=0x%x, trr=0x%x,"
  193. " tcr=0x%x, tcn=0x%x, ter=0x%x\n",
  194. *hwp->tgcrp, *hwp->tmrp, *hwp->trrp,
  195. *hwp->tcrp, *hwp->tcnp, *hwp->terp
  196. );
  197. #ifdef DEBUG
  198. mon_printf ("SIUMCR=0x%08lx, SYPCR=0x%08lx,"
  199. " SIMASK=0x%08lx, SIPEND=0x%08lx\n",
  200. siup->sc_siumcr,
  201. siup->sc_sypcr,
  202. siup->sc_simask,
  203. siup->sc_sipend
  204. );
  205. mon_printf ("CIMR=0x%08lx, CICR=0x%08lx, CIPR=0x%08lx\n",
  206. cpm_icp->cpic_cimr,
  207. cpm_icp->cpic_cicr,
  208. cpm_icp->cpic_cipr
  209. );
  210. #endif
  211. } else {
  212. mon_printf ("\nEnter: q - quit, b - start timer, e - stop timer, ? - get status\n");
  213. }
  214. mon_printf (usage);
  215. }
  216. if (running) {
  217. mon_printf ("Stopping timer\n");
  218. *hwp->tgcrp &= ~(CPMT_GCR_MASK << TID_TIMER_ID);
  219. mon_free_hdlr (hwp->cpm_vec);
  220. }
  221. return (0);
  222. }
  223. /* Set period in microseconds and start.
  224. * Truncate to maximum period if more than this is requested - but warn about it.
  225. */
  226. void setPeriod (tid_8xx_cpmtimer_t *hwp, ulong interval)
  227. {
  228. unsigned short prescaler;
  229. unsigned long ticks;
  230. mon_printf ("Set interval %ld us\n", interval);
  231. /* Warn if requesting longer period than possible */
  232. if (interval > CPMT_MAX_INTERVAL) {
  233. mon_printf ("Truncate interval %ld to maximum (%d)\n",
  234. interval, CPMT_MAX_INTERVAL);
  235. interval = CPMT_MAX_INTERVAL;
  236. }
  237. /*
  238. * Check if we want to use clock divider:
  239. * Since the reference counter can be incremented only in integer steps,
  240. * we try to keep it as big as possible to allow the resulting period to be
  241. * as precise as possible.
  242. */
  243. /* prescaler, enable interrupt, restart after ref count is reached */
  244. prescaler = (ushort) ((CPMT_PRESCALER - 1) << 8) |
  245. CPMT_MR_ORI |
  246. CPMT_MR_FRR;
  247. ticks = ((ulong) CLOCKRATE * interval);
  248. if (ticks > CPMT_MAX_TICKS) {
  249. ticks /= CPMT_CLOCK_DIV;
  250. prescaler |= CPMT_MR_ICLK_CLKDIV; /* use system clock divided by 16 */
  251. } else {
  252. prescaler |= CPMT_MR_ICLK_CLK; /* use system clock without divider */
  253. }
  254. #ifdef DEBUG
  255. mon_printf ("clock/%d, prescale factor %d, reference %ld, ticks %ld\n",
  256. (ticks > CPMT_MAX_TICKS) ? CPMT_CLOCK_DIV : 1,
  257. CPMT_PRESCALER,
  258. (ticks / CPMT_PRESCALER),
  259. ticks
  260. );
  261. #endif
  262. /* set prescaler register */
  263. *hwp->tmrp = prescaler;
  264. /* clear timer counter */
  265. *hwp->tcnp = 0;
  266. /* set reference register */
  267. *hwp->trrp = (unsigned short) (ticks / CPMT_PRESCALER);
  268. #ifdef DEBUG
  269. mon_printf ("tgcr=0x%x, tmr=0x%x, trr=0x%x,"
  270. " tcr=0x%x, tcn=0x%x, ter=0x%x\n",
  271. *hwp->tgcrp, *hwp->tmrp, *hwp->trrp,
  272. *hwp->tcrp, *hwp->tcnp, *hwp->terp
  273. );
  274. #endif
  275. }
  276. /*
  277. * Handler for CPMVEC_TIMER1 interrupt
  278. */
  279. static
  280. void timer_handler (void *arg)
  281. {
  282. tid_8xx_cpmtimer_t *hwp = (tid_8xx_cpmtimer_t *)arg;
  283. /* printf ("** TER1=%04x ** ", *hwp->terp); */
  284. /* just for demonstration */
  285. mon_printf (".");
  286. /* clear all possible events: Ref. and Cap. */
  287. *hwp->terp = (CPMT_EVENT_CAP | CPMT_EVENT_REF);
  288. }