timer.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. /*
  2. * Copyright (C) 2009 Samsung Electronics
  3. * Heungjun Kim <riverful.kim@samsung.com>
  4. * Inki Dae <inki.dae@samsung.com>
  5. * Minkyu Kang <mk7.kang@samsung.com>
  6. *
  7. * See file CREDITS for list of people who contributed to this
  8. * project.
  9. *
  10. * This program is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU General Public License as
  12. * published by the Free Software Foundation; either version 2 of
  13. * the License, or (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the Free Software
  22. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  23. * MA 02111-1307 USA
  24. */
  25. #include <common.h>
  26. #include <asm/io.h>
  27. #include <asm/arch/pwm.h>
  28. #include <asm/arch/clk.h>
  29. #define PRESCALER_1 (16 - 1) /* prescaler of timer 2, 3, 4 */
  30. #define MUX_DIV_2 1 /* 1/2 period */
  31. #define MUX_DIV_4 2 /* 1/4 period */
  32. #define MUX_DIV_8 3 /* 1/8 period */
  33. #define MUX_DIV_16 4 /* 1/16 period */
  34. #define MUX4_DIV_SHIFT 16
  35. #define TCON_TIMER4_SHIFT 20
  36. static unsigned long count_value;
  37. /* Internal tick units */
  38. static unsigned long long timestamp; /* Monotonic incrementing timer */
  39. static unsigned long lastdec; /* Last decremneter snapshot */
  40. /* macro to read the 16 bit timer */
  41. static inline struct s5pc1xx_timer *s5pc1xx_get_base_timer(void)
  42. {
  43. return (struct s5pc1xx_timer *)samsung_get_base_timer();
  44. }
  45. int timer_init(void)
  46. {
  47. struct s5pc1xx_timer *const timer = s5pc1xx_get_base_timer();
  48. u32 val;
  49. /*
  50. * @ PWM Timer 4
  51. * Timer Freq(HZ) =
  52. * PCLK / { (prescaler_value + 1) * (divider_value) }
  53. */
  54. /* set prescaler : 16 */
  55. /* set divider : 2 */
  56. writel((PRESCALER_1 & 0xff) << 8, &timer->tcfg0);
  57. writel((MUX_DIV_2 & 0xf) << MUX4_DIV_SHIFT, &timer->tcfg1);
  58. if (count_value == 0) {
  59. /* reset initial value */
  60. /* count_value = 2085937.5(HZ) (per 1 sec)*/
  61. count_value = get_pclk() / ((PRESCALER_1 + 1) *
  62. (MUX_DIV_2 + 1));
  63. /* count_value / 100 = 20859.375(HZ) (per 10 msec) */
  64. count_value = count_value / 100;
  65. }
  66. /* set count value */
  67. writel(count_value, &timer->tcntb4);
  68. lastdec = count_value;
  69. val = (readl(&timer->tcon) & ~(0x07 << TCON_TIMER4_SHIFT)) |
  70. S5PC1XX_TCON4_AUTO_RELOAD;
  71. /* auto reload & manual update */
  72. writel(val | S5PC1XX_TCON4_UPDATE, &timer->tcon);
  73. /* start PWM timer 4 */
  74. writel(val | S5PC1XX_TCON4_START, &timer->tcon);
  75. timestamp = 0;
  76. return 0;
  77. }
  78. /*
  79. * timer without interrupts
  80. */
  81. void reset_timer(void)
  82. {
  83. reset_timer_masked();
  84. }
  85. unsigned long get_timer(unsigned long base)
  86. {
  87. return get_timer_masked() - base;
  88. }
  89. void set_timer(unsigned long t)
  90. {
  91. timestamp = t;
  92. }
  93. /* delay x useconds */
  94. void __udelay(unsigned long usec)
  95. {
  96. unsigned long tmo, tmp;
  97. if (usec >= 1000) {
  98. /*
  99. * if "big" number, spread normalization
  100. * to seconds
  101. * 1. start to normalize for usec to ticks per sec
  102. * 2. find number of "ticks" to wait to achieve target
  103. * 3. finish normalize.
  104. */
  105. tmo = usec / 1000;
  106. tmo *= (CONFIG_SYS_HZ * count_value / 10);
  107. tmo /= 1000;
  108. } else {
  109. /* else small number, don't kill it prior to HZ multiply */
  110. tmo = usec * CONFIG_SYS_HZ * count_value / 10;
  111. tmo /= (1000 * 1000);
  112. }
  113. /* get current timestamp */
  114. tmp = get_timer(0);
  115. /* if setting this fordward will roll time stamp */
  116. /* reset "advancing" timestamp to 0, set lastdec value */
  117. /* else, set advancing stamp wake up time */
  118. if ((tmo + tmp + 1) < tmp)
  119. reset_timer_masked();
  120. else
  121. tmo += tmp;
  122. /* loop till event */
  123. while (get_timer_masked() < tmo)
  124. ; /* nop */
  125. }
  126. void reset_timer_masked(void)
  127. {
  128. struct s5pc1xx_timer *const timer = s5pc1xx_get_base_timer();
  129. /* reset time */
  130. lastdec = readl(&timer->tcnto4);
  131. timestamp = 0;
  132. }
  133. unsigned long get_timer_masked(void)
  134. {
  135. struct s5pc1xx_timer *const timer = s5pc1xx_get_base_timer();
  136. unsigned long now = readl(&timer->tcnto4);
  137. if (lastdec >= now)
  138. timestamp += lastdec - now;
  139. else
  140. timestamp += lastdec + count_value - now;
  141. lastdec = now;
  142. return timestamp;
  143. }
  144. /*
  145. * This function is derived from PowerPC code (read timebase as long long).
  146. * On ARM it just returns the timer value.
  147. */
  148. unsigned long long get_ticks(void)
  149. {
  150. return get_timer(0);
  151. }
  152. /*
  153. * This function is derived from PowerPC code (timebase clock frequency).
  154. * On ARM it returns the number of timer ticks per second.
  155. */
  156. unsigned long get_tbclk(void)
  157. {
  158. return CONFIG_SYS_HZ;
  159. }