timer.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * (C) Copyright 2002
  4. * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
  5. * Marius Groeger <mgroeger@sysgo.de>
  6. *
  7. * (C) Copyright 2002
  8. * David Mueller, ELSOFT AG, <d.mueller@elsoft.ch>
  9. *
  10. * (C) Copyright 2003
  11. * Texas Instruments, <www.ti.com>
  12. * Kshitij Gupta <Kshitij@ti.com>
  13. *
  14. * (C) Copyright 2004
  15. * ARM Ltd.
  16. * Philippe Robin, <philippe.robin@arm.com>
  17. */
  18. #include <common.h>
  19. #include <div64.h>
  20. #ifdef CONFIG_ARCH_CINTEGRATOR
  21. #define DIV_CLOCK_INIT 1
  22. #define TIMER_LOAD_VAL 0xFFFFFFFFL
  23. #else
  24. #define DIV_CLOCK_INIT 256
  25. #define TIMER_LOAD_VAL 0x0000FFFFL
  26. #endif
  27. /* The Integrator/CP timer1 is clocked at 1MHz
  28. * can be divided by 16 or 256
  29. * and can be set up as a 32-bit timer
  30. */
  31. /* U-Boot expects a 32 bit timer, running at CONFIG_SYS_HZ */
  32. /* Keep total timer count to avoid losing decrements < div_timer */
  33. static unsigned long long total_count = 0;
  34. static unsigned long long lastdec; /* Timer reading at last call */
  35. /* Divisor applied to timer clock */
  36. static unsigned long long div_clock = DIV_CLOCK_INIT;
  37. static unsigned long long div_timer = 1; /* Divisor to convert timer reading
  38. * change to U-Boot ticks
  39. */
  40. /* CONFIG_SYS_HZ = CONFIG_SYS_HZ_CLOCK/(div_clock * div_timer) */
  41. static ulong timestamp; /* U-Boot ticks since startup */
  42. #define READ_TIMER (*(volatile ulong *)(CONFIG_SYS_TIMERBASE+4))
  43. /* all function return values in U-Boot ticks i.e. (1/CONFIG_SYS_HZ) sec
  44. * - unless otherwise stated
  45. */
  46. /* starts up a counter
  47. * - the Integrator/CP timer can be set up to issue an interrupt */
  48. int timer_init (void)
  49. {
  50. /* Load timer with initial value */
  51. *(volatile ulong *)(CONFIG_SYS_TIMERBASE + 0) = TIMER_LOAD_VAL;
  52. #ifdef CONFIG_ARCH_CINTEGRATOR
  53. /* Set timer to be
  54. * enabled 1
  55. * periodic 1
  56. * no interrupts 0
  57. * X 0
  58. * divider 1 00 == less rounding error
  59. * 32 bit 1
  60. * wrapping 0
  61. */
  62. *(volatile ulong *)(CONFIG_SYS_TIMERBASE + 8) = 0x000000C2;
  63. #else
  64. /* Set timer to be
  65. * enabled 1
  66. * free-running 0
  67. * XX 00
  68. * divider 256 10
  69. * XX 00
  70. */
  71. *(volatile ulong *)(CONFIG_SYS_TIMERBASE + 8) = 0x00000088;
  72. #endif
  73. /* init the timestamp */
  74. total_count = 0ULL;
  75. /* capure current decrementer value */
  76. lastdec = READ_TIMER;
  77. /* start "advancing" time stamp from 0 */
  78. timestamp = 0L;
  79. div_timer = CONFIG_SYS_HZ_CLOCK;
  80. do_div(div_timer, CONFIG_SYS_HZ);
  81. do_div(div_timer, div_clock);
  82. return (0);
  83. }
  84. /*
  85. * timer without interrupts
  86. */
  87. ulong get_timer (ulong base_ticks)
  88. {
  89. return get_timer_masked () - base_ticks;
  90. }
  91. /* delay usec useconds */
  92. void __udelay (unsigned long usec)
  93. {
  94. ulong tmo, tmp;
  95. /* Convert to U-Boot ticks */
  96. tmo = usec * CONFIG_SYS_HZ;
  97. tmo /= (1000000L);
  98. tmp = get_timer_masked(); /* get current timestamp */
  99. tmo += tmp; /* form target timestamp */
  100. while (get_timer_masked () < tmo) {/* loop till event */
  101. /*NOP*/;
  102. }
  103. }
  104. /* converts the timer reading to U-Boot ticks */
  105. /* the timestamp is the number of ticks since reset */
  106. ulong get_timer_masked (void)
  107. {
  108. /* get current count */
  109. unsigned long long now = READ_TIMER;
  110. if(now > lastdec) {
  111. /* Must have wrapped */
  112. total_count += lastdec + TIMER_LOAD_VAL + 1 - now;
  113. } else {
  114. total_count += lastdec - now;
  115. }
  116. lastdec = now;
  117. /* Reuse "now" */
  118. now = total_count;
  119. do_div(now, div_timer);
  120. timestamp = now;
  121. return timestamp;
  122. }
  123. /* waits specified delay value and resets timestamp */
  124. void udelay_masked (unsigned long usec)
  125. {
  126. udelay(usec);
  127. }
  128. /*
  129. * This function is derived from PowerPC code (read timebase as long long).
  130. * On ARM it just returns the timer value.
  131. */
  132. unsigned long long get_ticks(void)
  133. {
  134. return get_timer(0);
  135. }
  136. /*
  137. * Return the timebase clock frequency
  138. * i.e. how often the timer decrements
  139. */
  140. ulong get_tbclk (void)
  141. {
  142. unsigned long long tmp = CONFIG_SYS_HZ_CLOCK;
  143. do_div(tmp, div_clock);
  144. return tmp;
  145. }