timer.c 3.7 KB

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