timer.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. /*
  2. * (C) Copyright 2002
  3. * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
  4. * Marius Groeger <mgroeger@sysgo.de>
  5. *
  6. * (C) Copyright 2002
  7. * David Mueller, ELSOFT AG, <d.mueller@elsoft.ch>
  8. *
  9. * (C) Copyright 2003
  10. * Texas Instruments, <www.ti.com>
  11. * Kshitij Gupta <Kshitij@ti.com>
  12. *
  13. * (C) Copyright 2004
  14. * ARM Ltd.
  15. * Philippe Robin, <philippe.robin@arm.com>
  16. *
  17. * See file CREDITS for list of people who contributed to this
  18. * project.
  19. *
  20. * This program is free software; you can redistribute it and/or
  21. * modify it under the terms of the GNU General Public License as
  22. * published by the Free Software Foundation; either version 2 of
  23. * the License, or (at your option) any later version.
  24. *
  25. * This program is distributed in the hope that it will be useful,
  26. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  27. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  28. * GNU General Public License for more details.
  29. *
  30. * You should have received a copy of the GNU General Public License
  31. * along with this program; if not, write to the Free Software
  32. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  33. * MA 02111-1307 USA
  34. */
  35. #include <common.h>
  36. #include <div64.h>
  37. #ifdef CONFIG_ARCH_CINTEGRATOR
  38. #define DIV_CLOCK_INIT 1
  39. #define TIMER_LOAD_VAL 0xFFFFFFFFL
  40. #else
  41. #define DIV_CLOCK_INIT 256
  42. #define TIMER_LOAD_VAL 0x0000FFFFL
  43. #endif
  44. /* The Integrator/CP timer1 is clocked at 1MHz
  45. * can be divided by 16 or 256
  46. * and can be set up as a 32-bit timer
  47. */
  48. /* U-Boot expects a 32 bit timer, running at CONFIG_SYS_HZ */
  49. /* Keep total timer count to avoid losing decrements < div_timer */
  50. static unsigned long long total_count = 0;
  51. static unsigned long long lastdec; /* Timer reading at last call */
  52. /* Divisor applied to timer clock */
  53. static unsigned long long div_clock = DIV_CLOCK_INIT;
  54. static unsigned long long div_timer = 1; /* Divisor to convert timer reading
  55. * change to U-Boot ticks
  56. */
  57. /* CONFIG_SYS_HZ = CONFIG_SYS_HZ_CLOCK/(div_clock * div_timer) */
  58. static ulong timestamp; /* U-Boot ticks since startup */
  59. #define READ_TIMER (*(volatile ulong *)(CONFIG_SYS_TIMERBASE+4))
  60. /* all function return values in U-Boot ticks i.e. (1/CONFIG_SYS_HZ) sec
  61. * - unless otherwise stated
  62. */
  63. /* starts up a counter
  64. * - the Integrator/CP timer can be set up to issue an interrupt */
  65. int timer_init (void)
  66. {
  67. /* Load timer with initial value */
  68. *(volatile ulong *)(CONFIG_SYS_TIMERBASE + 0) = TIMER_LOAD_VAL;
  69. #ifdef CONFIG_ARCH_CINTEGRATOR
  70. /* Set timer to be
  71. * enabled 1
  72. * periodic 1
  73. * no interrupts 0
  74. * X 0
  75. * divider 1 00 == less rounding error
  76. * 32 bit 1
  77. * wrapping 0
  78. */
  79. *(volatile ulong *)(CONFIG_SYS_TIMERBASE + 8) = 0x000000C2;
  80. #else
  81. /* Set timer to be
  82. * enabled 1
  83. * free-running 0
  84. * XX 00
  85. * divider 256 10
  86. * XX 00
  87. */
  88. *(volatile ulong *)(CONFIG_SYS_TIMERBASE + 8) = 0x00000088;
  89. #endif
  90. /* init the timestamp */
  91. total_count = 0ULL;
  92. reset_timer_masked();
  93. div_timer = CONFIG_SYS_HZ_CLOCK;
  94. do_div(div_timer, CONFIG_SYS_HZ);
  95. do_div(div_timer, div_clock);
  96. return (0);
  97. }
  98. /*
  99. * timer without interrupts
  100. */
  101. void reset_timer (void)
  102. {
  103. reset_timer_masked ();
  104. }
  105. ulong get_timer (ulong base_ticks)
  106. {
  107. return get_timer_masked () - base_ticks;
  108. }
  109. void set_timer (ulong ticks)
  110. {
  111. timestamp = ticks;
  112. total_count = ticks * div_timer;
  113. }
  114. /* delay usec useconds */
  115. void udelay (unsigned long usec)
  116. {
  117. ulong tmo, tmp;
  118. /* Convert to U-Boot ticks */
  119. tmo = usec * CONFIG_SYS_HZ;
  120. tmo /= (1000000L);
  121. tmp = get_timer_masked(); /* get current timestamp */
  122. tmo += tmp; /* form target timestamp */
  123. while (get_timer_masked () < tmo) {/* loop till event */
  124. /*NOP*/;
  125. }
  126. }
  127. void reset_timer_masked (void)
  128. {
  129. /* capure current decrementer value */
  130. lastdec = READ_TIMER;
  131. /* start "advancing" time stamp from 0 */
  132. timestamp = 0L;
  133. }
  134. /* converts the timer reading to U-Boot ticks */
  135. /* the timestamp is the number of ticks since reset */
  136. ulong get_timer_masked (void)
  137. {
  138. /* get current count */
  139. unsigned long long now = READ_TIMER;
  140. if(now > lastdec) {
  141. /* Must have wrapped */
  142. total_count += lastdec + TIMER_LOAD_VAL + 1 - now;
  143. } else {
  144. total_count += lastdec - now;
  145. }
  146. lastdec = now;
  147. /* Reuse "now" */
  148. now = total_count;
  149. do_div(now, div_timer);
  150. timestamp = now;
  151. return timestamp;
  152. }
  153. /* waits specified delay value and resets timestamp */
  154. void udelay_masked (unsigned long usec)
  155. {
  156. udelay(usec);
  157. }
  158. /*
  159. * This function is derived from PowerPC code (read timebase as long long).
  160. * On ARM it just returns the timer value.
  161. */
  162. unsigned long long get_ticks(void)
  163. {
  164. return get_timer(0);
  165. }
  166. /*
  167. * Return the timebase clock frequency
  168. * i.e. how often the timer decrements
  169. */
  170. ulong get_tbclk (void)
  171. {
  172. unsigned long long tmp = CONFIG_SYS_HZ_CLOCK;
  173. do_div(tmp, div_clock);
  174. return tmp;
  175. }