sa1100Timer.c
上传用户:luoyougen
上传日期:2008-05-12
资源大小:23136k
文件大小:26k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* sa1100Timer.c - Digital Semiconductor SA-1100 timer library */
  2. /* Copyright 1997-2001 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01j,14oct01,dat  added #includes to stand alone
  8. 01i,22feb01,jpd  made auxClk support dependent on INCLUDE_AUX_CLK (SPR #64165).
  9. 01h,16nov00,sbs  corrected docs for vxWorks AE.
  10. 01g,17apr00,jpd  made sysClkInt, sysAuxClkInt functions global.
  11. 01f,29mar00,dat  removed sysHwInit2()
  12. 01e,05jan00,jpd  fixed warnings from new definition of NULL. Comments changes.
  13. 01d,23apr98,cdp  updated comment about reload correction value.
  14. 01c,22apr98,cdp  lock ints around reload of match register (preemptive ints);
  15.  add reload correction.
  16. 01b,19mar98,cdp  removed unused variable in sysTimestampInt; fix typo in docn.
  17. 01a,10dec97,cdp  created from 01f of ambaTimer.c.
  18. */
  19. /*
  20. DESCRIPTION
  21. This library contains routines to manipulate the OS timer functions of
  22. the SA-1100 with a mostly board-independent interface. This driver
  23. provides 3 main functions, system clock support, auxiliary clock
  24. support, and timestamp timer support.  The timestamp function is always
  25. conditional upon the INCLUDE_TIMESTAMP component.
  26. The SA-1100 provides a free-running 32-bit counter, which counts up
  27. from zero, and four 32-bit match registers each of which can cause an
  28. interrupt when its value matches the value of the counter.
  29. The SA-1100 also provides a watchdog timer which is not used by VxWorks.
  30. The SA-1100 timer registers are described below under the symbolic
  31. names used herein.
  32. SA1100_TIMER_CSR_OSCR (read/write): this is the "OS Timer Count
  33. Register" (OSCR) described in the SA-1100 Data Sheet.  This register,
  34. which can be read or written at any time, increments at 3.6864 MHz.
  35. SA1100_TIMER_CSR_OSMR[0..3] (read/write): these are the "OS Timer Match
  36. Registers" (OSMR[0..3]) described in the SA-1100 Data Sheet.  These
  37. registers, which can be read or written at any time, are compared with
  38. the counter every tick.  For each match register whose contents match
  39. the counter, the corresponding event bit in the status register is
  40. set.  Match registers 0, 1 and 2 are used for the system, auxiliary and
  41. timestamp clocks respectively.
  42. SA1100_TIMER_CSR_OSSR (read/write): this is the "OS Timer Status
  43. Register" (OSSR) described in the SA-1100 Data Sheet.  When this
  44. register is read, each data bit that is set (1) indicates a match
  45. register that matches the counter register; unused bits read as 0.
  46. When this register is written, each data bit that is set (1) clears the
  47. corresponding timer match event;  bits that are clear (0) have no
  48. effect.
  49. SA1100_TIMER_CSR_OIER (read/write): this is the "OS Timer Interrupt
  50. Enable Register" (OIER) described in the SA-1100 Data Sheet.  When this
  51. register is written, each data bit that is set (1) enables the
  52. interrupt when the corresponding match register matches the counter;
  53. data bits that are clear (0) do not clear the corresponding interrupt
  54. if the interrupt is already asserted.  When this register is read, each
  55. data bit that is set (1) indicates that the corresponding timer match
  56. interrupt is enabled; each data bit that is clear (0) indicates that
  57. the corresponding timer match interrupt is disabled.
  58. Note that the timestamp facility is provided by OSMR[2] and so is
  59. independent of the system clock.
  60. This driver assumes that the chip is memory-mapped and does direct
  61. memory access to the registers which are assumed to be 32 bits wide.
  62. If a different access method is needed, the BSP can redefine the parameters
  63. SA1100_TIMER_REG_READ(addr,result) and SA1100_TIMER_REG_WRITE(addr,data).
  64. The parameters SYS_CLK_RATE_MIN, SYS_CLK_RATE_MAX, AUX_CLK_RATE_MIN, and
  65. AUX_CLK_RATE_MAX must be defined to provide parameter checking for the
  66. sys[Aux]ClkRateSet() routines.  The following parameters must also be defined:
  67. .CS
  68.  SYS_TIMER_CLK /@ frequency of clock feeding SYS_CLK timer @/
  69.  AUX_TIMER_CLK /@ frequency of clock feeding AUX_CLK @/
  70.  TIMESTAMP_TIMER_CLK /@ frequency of clock feeding TIMESTAMP_CLK @/
  71.  SYS_TIMER_INT_LVL /@ interrupt level for sys Clk @/
  72.  AUX_TIMER_INT_LVL /@ interrupt level for aux Clk @/
  73.  TIMESTAMP_TIMER_INT_LVL /@ interrupt level for timestamp Clk @/
  74.  SA1100_TIMER_CSR_OSCR /@ addresses of timer registers @/
  75.  SA1100_TIMER_CSR_OSMR_0 /@ "" @/
  76.  SA1100_TIMER_CSR_OSMR_1 /@ "" @/
  77.  SA1100_TIMER_CSR_OSMR_2 /@ "" @/
  78.  SA1100_TIMER_CSR_OSSR /@ "" @/
  79.  SA1100_TIMER_CSR_OIER /@ "" @/
  80. .CE
  81. The following may also be defined, if required:
  82. .CS
  83.  SA1100_TIMER_REG_READ(reg, data) /@ read a timer register @/
  84.  SA1100_TIMER_REG_WRITE(reg, data) /@ write ... @/
  85.  SA1100_TIMER_INT_ENABLE(level) /@ enable an interrupt @/
  86.  SA1100_TIMER_INT_DISABLE(level) /@ disable an interrpt @/
  87. .CE
  88. BSP
  89. Apart from defining such parameters described above as are needed, the BSP
  90. must connect the interrupt handlers (typically in sysHwInit2()).
  91. e.g.
  92. .CS
  93.     /@ connect sys clock interrupt and auxiliary clock interrupt @/
  94.     intConnect (INUM_TO_IVEC (INT_VEC...), sysClkInt, 0);
  95.     @ifdef INCLUDE_AUX_CLK
  96.     intConnect (INUM_TO_IVEC (INT_VEC...), sysAuxClkInt, 0);
  97.     @endif
  98. .CE
  99. INCLUDES:
  100. sa1100Timer.h
  101. timestampDev.h
  102. SEE ALSO:
  103. .I "Digital StrongARM SA-1100 Portable Communications Microcontroller, Data
  104. Sheet,"
  105. */
  106. /* includes */
  107. #include "vxWorks.h"
  108. #include "sysLib.h"
  109. #include "intLib.h"
  110. #include "drv/timer/sa1100Timer.h"
  111. #include "drv/timer/timestampDev.h"
  112. /* defines */
  113. #ifndef SA1100_TIMER_REG_READ
  114. #define SA1100_TIMER_REG_READ(reg, result) 
  115. ((result) = *(volatile UINT32 *)(reg))
  116. #endif /* SA1100_TIMER_REG_READ */
  117. #ifndef SA1100_TIMER_REG_WRITE
  118. #define SA1100_TIMER_REG_WRITE(reg, data) 
  119. (*((volatile UINT32 *)(reg)) = (data))
  120. #endif /* SA1100_TIMER_REG_WRITE */
  121. #ifndef SA1100_TIMER_INT_ENABLE
  122. #define SA1100_TIMER_INT_ENABLE(level) intEnable(level)
  123. #endif
  124. #ifndef SA1100_TIMER_INT_DISABLE
  125. #define SA1100_TIMER_INT_DISABLE(level) intDisable(level)
  126. #endif
  127. /*
  128.  * A correction to account for average reload delays. This is necessary
  129.  * because the timer hardware does not reload itself and so any delays
  130.  * caused by interrupt latency etc. will stretch the gap between ticks.
  131.  * The value chosen ensures that the timer is accurate enough to pass the
  132.  * BSP Validation Suite on a 200MHz Brutus board.  If required, the
  133.  * reload code could be changed to read both counter and match registers
  134.  * and work out a suitable match register reload value based on the
  135.  * difference between the two.
  136.  */
  137. #ifndef SA1100_TIMER_RELOAD_CORRECTION
  138. #define SA1100_TIMER_RELOAD_CORRECTION 6
  139. #endif
  140. /* locals */
  141. LOCAL FUNCPTR sysClkRoutine = NULL; /* routine to call on clock interrupt */
  142. LOCAL int sysClkArg = 0; /* its argument */
  143. LOCAL int sysClkRunning = FALSE;
  144. LOCAL int sysClkConnected = FALSE;
  145. LOCAL int sysClkTicksPerSecond = 60;
  146. LOCAL UINT32 sysClkTicks; /* ticks of counter per interrupt */
  147. #ifdef INCLUDE_AUX_CLK
  148. LOCAL FUNCPTR sysAuxClkRoutine = NULL;
  149. LOCAL int sysAuxClkArg = 0;
  150. LOCAL int sysAuxClkRunning = FALSE;
  151. LOCAL int sysAuxClkTicksPerSecond = 100;
  152. LOCAL UINT32 sysAuxClkTicks; /* ticks of counter per interrupt */
  153. #endif /* INCLUDE_AUX_CLK */
  154. #ifdef INCLUDE_TIMESTAMP
  155. LOCAL BOOL sysTimestampRunning  = FALSE; /* timestamp running flag */
  156. LOCAL FUNCPTR sysTimestampRoutine = NULL;  /* routine to call on intr */
  157. LOCAL int sysTimestampArg = 0;  /* arg for routine */
  158. #endif /* INCLUDE_TIMESTAMP */
  159. #if !defined(SYS_CLK_RATE_MIN) || 
  160.     !defined(SYS_CLK_RATE_MAX) || 
  161.     !defined(SYS_TIMER_CLK) || 
  162.     !defined(TIMESTAMP_TIMER_CLK) || 
  163.     !defined(SYS_TIMER_INT_LVL) || 
  164.     !defined(TIMESTAMP_TIMER_INT_LVL) || 
  165.     !defined(SA1100_TIMER_CSR_OSCR) || 
  166.     !defined(SA1100_TIMER_CSR_OSMR_0) || 
  167.     !defined(SA1100_TIMER_CSR_OSMR_1) || 
  168.     !defined(SA1100_TIMER_CSR_OSMR_2) || 
  169.     !defined(SA1100_TIMER_CSR_OSSR) || 
  170.     !defined(SA1100_TIMER_CSR_OIER)
  171. #   error missing SA-1100 timer definitions
  172. #endif
  173. #ifdef INCLUDE_AUX_CLK
  174. #if !defined(AUX_CLK_RATE_MIN) || 
  175.     !defined(AUX_CLK_RATE_MAX) || 
  176.     !defined(AUX_TIMER_CLK) || 
  177.     !defined(AUX_TIMER_INT_LVL)
  178. #   error missing SA-1100 Aux timer definitions
  179. #endif
  180. #endif /* INCLUDE_AUX_CLK */
  181. /*******************************************************************************
  182. *
  183. * sysClkInt - interrupt level processing for system clock
  184. *
  185. * This routine handles the system clock interrupt.  It is attached to the
  186. * clock interrupt vector by the routine sysClkConnect().
  187. *
  188. * RETURNS: N/A.
  189. */
  190. void sysClkInt (void)
  191.     {
  192.     UINT32 tc;
  193.     int key;
  194.     /* clear interrupt */
  195.     SA1100_TIMER_REG_WRITE (SA1100_TIMER_CSR_OSSR, 1);
  196.     /*
  197.      * Load the match register with a new value calculated by
  198.      * adding the ticks per interrupt to the current value of the
  199.      * counter register.  Note that this may wraparound to a value
  200.      * less than the current counter value but that's OK.
  201.      */
  202.     key = intLock ();
  203.     SA1100_TIMER_REG_READ (SA1100_TIMER_CSR_OSCR, tc);
  204.     tc += sysClkTicks;
  205.     SA1100_TIMER_REG_WRITE (SA1100_TIMER_CSR_OSMR_0, tc);
  206.     /* read the match register to work around the bug in pre 2.1 silicon */
  207.     SA1100_TIMER_REG_READ (SA1100_TIMER_CSR_OSMR_0, tc);
  208.     intUnlock (key);
  209.     /* If any routine attached via sysClkConnect(), call it */
  210.     if (sysClkRoutine != NULL)
  211. (* sysClkRoutine) (sysClkArg);
  212.     }
  213. /*******************************************************************************
  214. *
  215. * sysClkConnect - connect a routine to the system clock interrupt
  216. *
  217. * This routine specifies the interrupt service routine to be called at each
  218. * clock interrupt.  It does not enable system clock interrupts.
  219. * Normally it is called from usrRoot() in usrConfig.c to connect
  220. * usrClock() to the system clock interrupt.
  221. *
  222. * RETURNS: OK, or ERROR if the routine cannot be connected to the interrupt.
  223. *
  224. * SEE ALSO: intConnect(), usrClock(), sysClkEnable()
  225. */
  226. STATUS sysClkConnect
  227.     (
  228.     FUNCPTR routine, /* routine to be called at each clock interrupt */
  229.     int arg /* argument with which to call routine */
  230.     )
  231.     {
  232. #ifdef _WRS_VXWORKS_5_X
  233.     if (sysClkConnected == FALSE)
  234.      {
  235.      sysHwInit2 (); /* VxAE does this in prjConfig */
  236.      }
  237. #endif
  238.     sysClkConnected = TRUE;
  239.     sysClkRoutine = NULL; /* ensure routine not called with wrong arg */
  240.     sysClkArg   = arg;
  241.     sysClkRoutine = routine;
  242.     return OK;
  243.     }
  244. /*******************************************************************************
  245. *
  246. * sysClkDisable - turn off system clock interrupts
  247. *
  248. * This routine disables system clock interrupts.
  249. *
  250. * RETURNS: N/A
  251. *
  252. * SEE ALSO: sysClkEnable()
  253. */
  254. void sysClkDisable (void)
  255.     {
  256.     UINT32 oier;
  257.     int key;
  258.     if (sysClkRunning)
  259. {
  260. /* disable timer interrupt in the timer */
  261. key = intLock ();
  262. SA1100_TIMER_REG_READ (SA1100_TIMER_CSR_OIER, oier);
  263. SA1100_TIMER_REG_WRITE (SA1100_TIMER_CSR_OIER, oier & ~(1 << 0));
  264. intUnlock (key);
  265. /* clear any pending interrupt */
  266. SA1100_TIMER_REG_WRITE (SA1100_TIMER_CSR_OSSR, 1 << 0);
  267. /* disable timer interrupt in the interrupt controller */
  268. SA1100_TIMER_INT_DISABLE (SYS_TIMER_INT_LVL);
  269. sysClkRunning = FALSE;
  270. }
  271.     }
  272. /*******************************************************************************
  273. *
  274. * sysClkEnable - turn on system clock interrupts
  275. *
  276. * This routine enables system clock interrupts.
  277. *
  278. * RETURNS: N/A
  279. *
  280. * SEE ALSO: sysClkConnect(), sysClkDisable(), sysClkRateSet()
  281. */
  282. void sysClkEnable (void)
  283.     {
  284.     UINT32 tc, oier;
  285.     int key;
  286.     if (!sysClkRunning)
  287. {
  288. /*
  289.  * Calculate the number of ticks of the timer clock that this
  290.  * period requires.  Do this once, here, so that the timer interrupt
  291.  * routine does not need to perform a division.
  292.  */
  293. sysClkTicks = (SYS_TIMER_CLK / sysClkTicksPerSecond) -
  294. SA1100_TIMER_RELOAD_CORRECTION;
  295. /* clear any pending interrupt */
  296. SA1100_TIMER_REG_WRITE (SA1100_TIMER_CSR_OSSR, 1 << 0);
  297. /*
  298.  * Load the match register with a new value calculated by
  299.  * adding the ticks per interrupt to the current value of the
  300.  * counter register.  Note that this may wraparound to a value
  301.  * less than the current counter value but that's OK.
  302.  */
  303. key = intLock ();
  304. SA1100_TIMER_REG_READ (SA1100_TIMER_CSR_OSCR, tc);
  305. tc += sysClkTicks;
  306. SA1100_TIMER_REG_WRITE (SA1100_TIMER_CSR_OSMR_0, tc);
  307. /* read the match register to work around the bug in per 2.1 silicon */
  308. SA1100_TIMER_REG_READ (SA1100_TIMER_CSR_OSMR_0, tc);
  309. /* enable interrupt in timer */
  310. SA1100_TIMER_REG_READ (SA1100_TIMER_CSR_OIER, oier);
  311. SA1100_TIMER_REG_WRITE (SA1100_TIMER_CSR_OIER, oier | (1 << 0));
  312. intUnlock (key);
  313. /* enable clock interrupt in interrupt controller */
  314. SA1100_TIMER_INT_ENABLE (SYS_TIMER_INT_LVL);
  315. sysClkRunning = TRUE;
  316. }
  317.     }
  318. /*******************************************************************************
  319. *
  320. * sysClkRateGet - get the system clock rate
  321. *
  322. * This routine returns the interrupt rate of the system clock.
  323. *
  324. * RETURNS: The number of ticks per second of the system clock.
  325. *
  326. * SEE ALSO: sysClkRateSet(), sysClkEnable()
  327. */
  328. int sysClkRateGet (void)
  329.     {
  330.     return sysClkTicksPerSecond;
  331.     }
  332. /*******************************************************************************
  333. *
  334. * sysClkRateSet - set the system clock rate
  335. *
  336. * This routine sets the interrupt rate of the system clock.  It does not
  337. * enable system clock interrupts unilaterally, but if the system clock is
  338. * currently enabled, the clock is disabled and then re-enabled with the new
  339. * rate.  Normally it is called by usrRoot() in usrConfig.c.
  340. *
  341. * RETURNS:
  342. * OK, or ERROR if the tick rate is invalid or the timer cannot be set.
  343. *
  344. * SEE ALSO: sysClkRateGet(), sysClkEnable()
  345. */
  346. STATUS sysClkRateSet
  347.     (
  348.     int ticksPerSecond     /* number of clock interrupts per second */
  349.     )
  350.     {
  351.     if (ticksPerSecond < SYS_CLK_RATE_MIN || ticksPerSecond > SYS_CLK_RATE_MAX)
  352. return ERROR;
  353.     sysClkTicksPerSecond = ticksPerSecond;
  354.     if (sysClkRunning)
  355. {
  356. sysClkDisable ();
  357. sysClkEnable ();
  358. }
  359.     return OK;
  360.     }
  361. #ifdef INCLUDE_AUX_CLK
  362. /*******************************************************************************
  363. *
  364. * sysAuxClkInt - handle an auxiliary clock interrupt
  365. *
  366. * This routine handles an auxiliary clock interrupt.  It acknowledges the
  367. * interrupt and calls the routine installed by sysAuxClkConnect().
  368. *
  369. * RETURNS: N/A
  370. */
  371. void sysAuxClkInt (void)
  372.     {
  373.     UINT32 tc;
  374.     int key;
  375.     /* clear interrupt */
  376.     SA1100_TIMER_REG_WRITE (SA1100_TIMER_CSR_OSSR, 1 << 1);
  377.     /*
  378.      * Load the match register with a new value calculated by
  379.      * adding the ticks per interrupt to the current value of the
  380.      * counter register.  Note that this may wraparound to a value
  381.      * less than the current counter value but that's OK.
  382.      */
  383.     key = intLock ();
  384.     SA1100_TIMER_REG_READ (SA1100_TIMER_CSR_OSCR, tc);
  385.     tc += sysAuxClkTicks;
  386.     SA1100_TIMER_REG_WRITE (SA1100_TIMER_CSR_OSMR_1, tc);
  387.     intUnlock (key);
  388.     /* If any routine attached via sysAuxClkConnect(), call it */
  389.     if (sysAuxClkRoutine != NULL)
  390. (*sysAuxClkRoutine) (sysAuxClkArg);
  391.     }
  392. /*******************************************************************************
  393. *
  394. * sysAuxClkConnect - connect a routine to the auxiliary clock interrupt
  395. *
  396. * This routine specifies the interrupt service routine to be called at each
  397. * auxiliary clock interrupt.  It also connects the clock error interrupt
  398. * service routine.
  399. *
  400. * RETURNS: OK, or ERROR if the routine cannot be connected to the interrupt.
  401. *
  402. * SEE ALSO: intConnect(), sysAuxClkEnable()
  403. */
  404. STATUS sysAuxClkConnect
  405.     (
  406.     FUNCPTR routine,    /* routine called at each aux clock interrupt */
  407.     int arg             /* argument with which to call routine        */
  408.     )
  409.     {
  410.     sysAuxClkRoutine = NULL; /* ensure routine not called with wrong arg */
  411.     sysAuxClkArg = arg;
  412.     sysAuxClkRoutine = routine;
  413.     return OK;
  414.     }
  415. /*******************************************************************************
  416. *
  417. * sysAuxClkDisable - turn off auxiliary clock interrupts
  418. *
  419. * This routine disables auxiliary clock interrupts.
  420. *
  421. * RETURNS: N/A
  422. *
  423. * SEE ALSO: sysAuxClkEnable()
  424. */
  425. void sysAuxClkDisable (void)
  426.     {
  427.     UINT32 oier;
  428.     int key;
  429.     if (sysAuxClkRunning)
  430.         {
  431. /* disable timer interrupt in the timer */
  432. key = intLock ();
  433. SA1100_TIMER_REG_READ (SA1100_TIMER_CSR_OIER, oier);
  434. SA1100_TIMER_REG_WRITE (SA1100_TIMER_CSR_OIER, oier & ~(1 << 1));
  435. intUnlock (key);
  436. /* clear any pending interrupt */
  437. SA1100_TIMER_REG_WRITE (SA1100_TIMER_CSR_OSSR, 1 << 1);
  438. /* disable timer interrupt in the interrupt controller */
  439. SA1100_TIMER_INT_DISABLE (AUX_TIMER_INT_LVL);
  440. sysAuxClkRunning = FALSE;
  441.         }
  442.     }
  443. /*******************************************************************************
  444. *
  445. * sysAuxClkEnable - turn on auxiliary clock interrupts
  446. *
  447. * This routine enables auxiliary clock interrupts.
  448. *
  449. * RETURNS: N/A
  450. *
  451. * SEE ALSO: sysAuxClkDisable()
  452. */
  453. void sysAuxClkEnable (void)
  454.     {
  455.     UINT32 tc, oier;
  456.     int key;
  457.     if (!sysAuxClkRunning)
  458. {
  459. /*
  460.  * Calculate the number of ticks of the timer clock that this
  461.  * period requires.  Do this once, here, so that the timer interrupt
  462.  * routine does not need to perform a division.
  463.  */
  464. sysAuxClkTicks = (AUX_TIMER_CLK / sysAuxClkTicksPerSecond) -
  465.     SA1100_TIMER_RELOAD_CORRECTION;
  466. /* clear any pending interrupt */
  467. SA1100_TIMER_REG_WRITE (SA1100_TIMER_CSR_OSSR, 1 << 1);
  468. /*
  469.  * Load the match register with a new value calculated by
  470.  * adding the ticks per interrupt to the current value of the
  471.  * counter register.  Note that this may wraparound to a value
  472.  * less than the current counter value but that's OK.
  473.  */
  474. key = intLock ();
  475. SA1100_TIMER_REG_READ (SA1100_TIMER_CSR_OSCR, tc);
  476. tc += sysAuxClkTicks;
  477. SA1100_TIMER_REG_WRITE (SA1100_TIMER_CSR_OSMR_1, tc);
  478. /* enable interrupt in timer */
  479. SA1100_TIMER_REG_READ (SA1100_TIMER_CSR_OIER, oier);
  480. SA1100_TIMER_REG_WRITE (SA1100_TIMER_CSR_OIER, oier | (1 << 1));
  481. intUnlock (key);
  482. /* enable clock interrupt in interrupt controller */
  483. SA1100_TIMER_INT_ENABLE (AUX_TIMER_INT_LVL);
  484. sysAuxClkRunning = TRUE;
  485. }
  486.     }
  487. /*******************************************************************************
  488. *
  489. * sysAuxClkRateGet - get the auxiliary clock rate
  490. *
  491. * This routine returns the interrupt rate of the auxiliary clock.
  492. *
  493. * RETURNS: The number of ticks per second of the auxiliary clock.
  494. *
  495. * SEE ALSO: sysAuxClkEnable(), sysAuxClkRateSet()
  496. */
  497. int sysAuxClkRateGet (void)
  498.     {
  499.     return sysAuxClkTicksPerSecond;
  500.     }
  501. /*******************************************************************************
  502. *
  503. * sysAuxClkRateSet - set the auxiliary clock rate
  504. *
  505. * This routine sets the interrupt rate of the auxiliary clock.  It does
  506. * not enable auxiliary clock interrupts unilaterally, but if the
  507. * auxiliary clock is currently enabled, the clock is disabled and then
  508. * re-enabled with the new rate.
  509. *
  510. * RETURNS: OK or ERROR.
  511. *
  512. * SEE ALSO: sysAuxClkEnable(), sysAuxClkRateGet()
  513. */
  514. STATUS sysAuxClkRateSet
  515.     (
  516.     int ticksPerSecond     /* number of clock interrupts per second */
  517.     )
  518.     {
  519.     if (ticksPerSecond < AUX_CLK_RATE_MIN || ticksPerSecond > AUX_CLK_RATE_MAX)
  520. return ERROR;
  521.     sysAuxClkTicksPerSecond = ticksPerSecond;
  522.     if (sysAuxClkRunning)
  523. {
  524. sysAuxClkDisable ();
  525. sysAuxClkEnable ();
  526. }
  527.     return OK;
  528.     }
  529. #endif /* INCLUDE_AUX_CLK */
  530. #ifdef  INCLUDE_TIMESTAMP
  531. /*******************************************************************************
  532. *
  533. * sysTimestampInt - timestamp timer interrupt handler
  534. *
  535. * This routine handles the timestamp timer interrupt.  A user routine is
  536. * called, if one was connected by sysTimestampConnect().
  537. *
  538. * RETURNS: N/A
  539. *
  540. * SEE ALSO: sysTimestampConnect()
  541. */
  542. void sysTimestampInt (void)
  543.     {
  544.     /* clear interrupt */
  545.     SA1100_TIMER_REG_WRITE (SA1100_TIMER_CSR_OSSR, 1 << 2);
  546.     /*
  547.      * do not reload the match register - another interrupt will be
  548.      * generated next time the counter hits the current value
  549.      *
  550.      * If any routine attached via sysTimestampConnect(), call it
  551.      */
  552.     if (sysTimestampRunning && sysTimestampRoutine != NULL)
  553. (*sysTimestampRoutine)(sysTimestampArg);
  554.     }
  555. /*******************************************************************************
  556. *
  557. * sysTimestampConnect - connect a user routine to the timestamp timer interrupt
  558. *
  559. * This routine specifies the user interrupt routine to be called at each
  560. * timestamp timer interrupt.  It does not enable the timestamp timer itself.
  561. *
  562. * RETURNS: OK, or ERROR if sysTimestampInt() interrupt handler is not used.
  563. */
  564. STATUS sysTimestampConnect
  565.     (
  566.     FUNCPTR routine,    /* routine called at each timestamp timer interrupt */
  567.     int arg      /* argument with which to call routine */
  568.     )
  569.     {
  570.     sysTimestampRoutine = NULL;
  571.     sysTimestampArg = arg;
  572.     sysTimestampRoutine = routine;
  573.     return OK;
  574.     }
  575. /*******************************************************************************
  576. *
  577. * sysTimestampEnable - initialize and enable the timestamp timer
  578. *
  579. * This routine connects the timestamp timer interrupt and initializes the
  580. * counter registers.  If the timestamp timer is already running, this routine
  581. * merely resets the timer counter.
  582. *
  583. * The rate of the timestamp timer should be set explicitly within the BSP,
  584. * in the sysHwInit() routine.  This routine does not intialize the timer
  585. * rate.
  586. *
  587. * RETURNS: OK, or ERROR if hardware cannot be enabled.
  588. */
  589. STATUS sysTimestampEnable (void)
  590.     {
  591.     static BOOL connected = FALSE;
  592.     UINT32 tc, oier;
  593.     int key;
  594.     if (!connected)
  595. {
  596. /* connect sysTimestampInt to the appropriate interrupt */
  597. intConnect (INUM_TO_IVEC (INT_LVL_TIMER_2), sysTimestampInt, 0);
  598. connected = TRUE;
  599. }
  600.     if (!sysTimestampRunning)
  601. {
  602. /*
  603.  * Set match register (OSMR) to (current counter value) (OSCR)
  604.  * minus one so that an interrupt will be generated when the
  605.  * counter wraps around to that value but there will not be an
  606.  * immediate interrupt. This means that the first interrupt will
  607.  * arrive one tick too soon but this inaccuracy should be
  608.  * tolerable.
  609.  */
  610. key = intLock();
  611. SA1100_TIMER_REG_READ (SA1100_TIMER_CSR_OSCR, tc);
  612. SA1100_TIMER_REG_WRITE (SA1100_TIMER_CSR_OSMR_2, tc - 1);
  613. /* clear any pending interrupt */
  614. SA1100_TIMER_REG_WRITE (SA1100_TIMER_CSR_OSSR, 1 << 2);
  615. /* enable interrupt in timer */
  616. SA1100_TIMER_REG_READ (SA1100_TIMER_CSR_OIER, oier);
  617. SA1100_TIMER_REG_WRITE (SA1100_TIMER_CSR_OIER, oier | (1 << 2));
  618. intUnlock (key);
  619. /* enable clock interrupt in interrupt controller */
  620. SA1100_TIMER_INT_ENABLE (TIMESTAMP_TIMER_INT_LVL);
  621. sysTimestampRunning = TRUE;
  622. }
  623.     return OK;
  624.     }
  625. /*******************************************************************************
  626. *
  627. * sysTimestampDisable - disable the timestamp timer
  628. *
  629. * This routine disables the timestamp timer.  Interrupts are not disabled,
  630. * although the tick counter will not increment after the timestamp timer
  631. * is disabled, thus interrupts will no longer be generated.
  632. *
  633. * RETURNS: OK, or ERROR if timer cannot be disabled.
  634. */
  635. STATUS sysTimestampDisable (void)
  636.     {
  637.     UINT32 oier;
  638.     int key;
  639.     if (sysTimestampRunning)
  640. {
  641. /* disable timer interrupt in the timer */
  642. key = intLock ();
  643. SA1100_TIMER_REG_READ (SA1100_TIMER_CSR_OIER, oier);
  644. SA1100_TIMER_REG_WRITE (SA1100_TIMER_CSR_OIER, oier & ~(1 << 2));
  645. intUnlock (key);
  646. /* clear any pending interrupt */
  647. SA1100_TIMER_REG_WRITE (SA1100_TIMER_CSR_OSSR, 1 << 2);
  648. /* disable timer interrupt in the interrupt controller */
  649. SA1100_TIMER_INT_DISABLE (TIMESTAMP_TIMER_INT_LVL);
  650.         sysTimestampRunning = FALSE;
  651. }
  652.     return OK;
  653.     }
  654. /*******************************************************************************
  655. *
  656. * sysTimestampPeriod - get the timestamp timer period
  657. *
  658. * This routine returns the period of the timestamp timer in ticks.
  659. * The period, or terminal count, is the number of ticks to which the timestamp
  660. * timer will count before rolling over and restarting the counting process.
  661. *
  662. * RETURNS: The period of the timestamp timer in counter ticks.
  663. */
  664. UINT32 sysTimestampPeriod (void)
  665.     {
  666.     return 0xFFFFFFFF; /* max value of 32-bit counter */
  667.     }
  668. /*******************************************************************************
  669. *
  670. * sysTimestampFreq - get the timestamp timer clock frequency
  671. *
  672. * This routine returns the frequency of the timer clock, in ticks per second.
  673. *
  674. * RETURNS: The timestamp timer clock frequency, in ticks per second.
  675. */
  676. UINT32 sysTimestampFreq (void)
  677.     {
  678.     return TIMESTAMP_TIMER_CLK;
  679.     }
  680. /*******************************************************************************
  681. *
  682. * sysTimestamp - get the timestamp timer tick count
  683. *
  684. * This routine returns the current value of the timestamp timer tick counter.
  685. * The tick count can be converted to seconds by dividing by the return of
  686. * sysTimestampFreq().
  687. *
  688. * This routine should be called with interrupts locked.  If interrupts are
  689. * not already locked, sysTimestampLock() should be used instead.
  690. *
  691. * RETURNS: The current timestamp timer tick count.
  692. *
  693. * SEE ALSO: sysTimestampLock()
  694. */
  695. UINT32 sysTimestamp (void)
  696.     {
  697.     UINT32 count, match;
  698.     /*
  699.      * read count and match registers - this is effectively atomic
  700.      * (since the match register is not reloaded on interrupt) so there is
  701.      * no need to disable interrupts around this.
  702.      */
  703.     SA1100_TIMER_REG_READ (SA1100_TIMER_CSR_OSCR, count);
  704.     SA1100_TIMER_REG_READ (SA1100_TIMER_CSR_OSMR_2, match);
  705.     /*
  706.      * When the timer was enabled, the match register (OSMR) was
  707.      * initialised to the current value of the count register (OSCR) and
  708.      * then generates an interrupt every time the two registers match.
  709.      * The ticks since the last interrupt are thus (OSCR - OSMR).
  710.      */
  711.     return count - match;
  712.     }
  713. /*******************************************************************************
  714. *
  715. * sysTimestampLock - get the timestamp timer tick count
  716. *
  717. * This routine returns the current value of the timestamp timer tick counter.
  718. * The tick count can be converted to seconds by dividing by the return of
  719. * sysTimestampFreq().
  720. *
  721. * This routine locks interrupts for cases where it is necessary to stop the
  722. * tick counter in order to read it, or when two independent counters must
  723. * be read.  If interrupts are already locked, sysTimestamp() should be
  724. * used instead.
  725. *
  726. * RETURNS: The current timestamp timer tick count.
  727. *
  728. * SEE ALSO: sysTimestamp()
  729. */
  730. UINT32 sysTimestampLock (void)
  731.     {
  732.     /* no need to disable interrupts - see sysTimestamp() */
  733.     return sysTimestamp ();
  734.     }
  735. #endif  /* INCLUDE_TIMESTAMP */