timer.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  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. if (cpu_is_s5pc110())
  44. return (struct s5pc1xx_timer *)S5PC110_TIMER_BASE;
  45. else
  46. return (struct s5pc1xx_timer *)S5PC100_TIMER_BASE;
  47. }
  48. int timer_init(void)
  49. {
  50. struct s5pc1xx_timer *const timer = s5pc1xx_get_base_timer();
  51. u32 val;
  52. /*
  53. * @ PWM Timer 4
  54. * Timer Freq(HZ) =
  55. * PCLK / { (prescaler_value + 1) * (divider_value) }
  56. */
  57. /* set prescaler : 16 */
  58. /* set divider : 2 */
  59. writel((PRESCALER_1 & 0xff) << 8, &timer->tcfg0);
  60. writel((MUX_DIV_2 & 0xf) << MUX4_DIV_SHIFT, &timer->tcfg1);
  61. if (count_value == 0) {
  62. /* reset initial value */
  63. /* count_value = 2085937.5(HZ) (per 1 sec)*/
  64. count_value = get_pclk() / ((PRESCALER_1 + 1) *
  65. (MUX_DIV_2 + 1));
  66. /* count_value / 100 = 20859.375(HZ) (per 10 msec) */
  67. count_value = count_value / 100;
  68. }
  69. /* set count value */
  70. writel(count_value, &timer->tcntb4);
  71. lastdec = count_value;
  72. val = (readl(&timer->tcon) & ~(0x07 << TCON_TIMER4_SHIFT)) |
  73. S5PC1XX_TCON4_AUTO_RELOAD;
  74. /* auto reload & manual update */
  75. writel(val | S5PC1XX_TCON4_UPDATE, &timer->tcon);
  76. /* start PWM timer 4 */
  77. writel(val | S5PC1XX_TCON4_START, &timer->tcon);
  78. timestamp = 0;
  79. return 0;
  80. }
  81. /*
  82. * timer without interrupts
  83. */
  84. void reset_timer(void)
  85. {
  86. reset_timer_masked();
  87. }
  88. unsigned long get_timer(unsigned long base)
  89. {
  90. return get_timer_masked() - base;
  91. }
  92. void set_timer(unsigned long t)
  93. {
  94. timestamp = t;
  95. }
  96. /* delay x useconds */
  97. void udelay(unsigned long usec)
  98. {
  99. unsigned long tmo, tmp;
  100. if (usec >= 1000) {
  101. /*
  102. * if "big" number, spread normalization
  103. * to seconds
  104. * 1. start to normalize for usec to ticks per sec
  105. * 2. find number of "ticks" to wait to achieve target
  106. * 3. finish normalize.
  107. */
  108. tmo = usec / 1000;
  109. tmo *= (CONFIG_SYS_HZ * count_value / 10);
  110. tmo /= 1000;
  111. } else {
  112. /* else small number, don't kill it prior to HZ multiply */
  113. tmo = usec * CONFIG_SYS_HZ * count_value / 10;
  114. tmo /= (1000 * 1000);
  115. }
  116. /* get current timestamp */
  117. tmp = get_timer(0);
  118. /* if setting this fordward will roll time stamp */
  119. /* reset "advancing" timestamp to 0, set lastdec value */
  120. /* else, set advancing stamp wake up time */
  121. if ((tmo + tmp + 1) < tmp)
  122. reset_timer_masked();
  123. else
  124. tmo += tmp;
  125. /* loop till event */
  126. while (get_timer_masked() < tmo)
  127. ; /* nop */
  128. }
  129. void reset_timer_masked(void)
  130. {
  131. struct s5pc1xx_timer *const timer = s5pc1xx_get_base_timer();
  132. /* reset time */
  133. lastdec = readl(&timer->tcnto4);
  134. timestamp = 0;
  135. }
  136. unsigned long get_timer_masked(void)
  137. {
  138. struct s5pc1xx_timer *const timer = s5pc1xx_get_base_timer();
  139. unsigned long now = readl(&timer->tcnto4);
  140. if (lastdec >= now)
  141. timestamp += lastdec - now;
  142. else
  143. timestamp += lastdec + count_value - now;
  144. lastdec = now;
  145. return timestamp;
  146. }
  147. /*
  148. * This function is derived from PowerPC code (read timebase as long long).
  149. * On ARM it just returns the timer value.
  150. */
  151. unsigned long long get_ticks(void)
  152. {
  153. return get_timer(0);
  154. }
  155. /*
  156. * This function is derived from PowerPC code (timebase clock frequency).
  157. * On ARM it returns the number of timer ticks per second.
  158. */
  159. unsigned long get_tbclk(void)
  160. {
  161. return CONFIG_SYS_HZ;
  162. }