timer.c 3.7 KB

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