timer.c 9.6 KB

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