timer.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * (C) Copyright 2016 Nexell
  4. * Hyunseok, Jung <hsjung@nexell.co.kr>
  5. */
  6. #include <common.h>
  7. #include <log.h>
  8. #include <asm/io.h>
  9. #include <asm/arch/nexell.h>
  10. #include <asm/arch/clk.h>
  11. #if defined(CONFIG_ARCH_S5P4418)
  12. #include <asm/arch/reset.h>
  13. #endif
  14. #if (CONFIG_TIMER_SYS_TICK_CH > 3)
  15. #error Not support timer channel. Please use "0~3" channels.
  16. #endif
  17. /* global variables to save timer count
  18. *
  19. * Section ".data" must be used because BSS is not available before relocation,
  20. * in board_init_f(), respectively! I.e. global variables can not be used!
  21. */
  22. static unsigned long timestamp __section(".data");
  23. static unsigned long lastdec __section(".data");
  24. static int timerinit __section(".data");
  25. /* macro to hw timer tick config */
  26. static long TIMER_FREQ = 1000000;
  27. static long TIMER_HZ = 1000000 / CONFIG_SYS_HZ;
  28. static long TIMER_COUNT = 0xFFFFFFFF;
  29. #define REG_TCFG0 (0x00)
  30. #define REG_TCFG1 (0x04)
  31. #define REG_TCON (0x08)
  32. #define REG_TCNTB0 (0x0C)
  33. #define REG_TCMPB0 (0x10)
  34. #define REG_TCNT0 (0x14)
  35. #define REG_CSTAT (0x44)
  36. #define TCON_BIT_AUTO (1 << 3)
  37. #define TCON_BIT_INVT (1 << 2)
  38. #define TCON_BIT_UP (1 << 1)
  39. #define TCON_BIT_RUN (1 << 0)
  40. #define TCFG0_BIT_CH(ch) ((ch) == 0 || (ch) == 1 ? 0 : 8)
  41. #define TCFG1_BIT_CH(ch) ((ch) * 4)
  42. #define TCON_BIT_CH(ch) ((ch) ? (ch) * 4 + 4 : 0)
  43. #define TINT_CH(ch) (ch)
  44. #define TINT_CSTAT_BIT_CH(ch) ((ch) + 5)
  45. #define TINT_CSTAT_MASK (0x1F)
  46. #define TIMER_TCNT_OFFS (0xC)
  47. void reset_timer_masked(void);
  48. unsigned long get_timer_masked(void);
  49. /*
  50. * Timer HW
  51. */
  52. static inline void timer_clock(void __iomem *base, int ch, int mux, int scl)
  53. {
  54. u32 val = readl(base + REG_TCFG0) & ~(0xFF << TCFG0_BIT_CH(ch));
  55. writel(val | ((scl - 1) << TCFG0_BIT_CH(ch)), base + REG_TCFG0);
  56. val = readl(base + REG_TCFG1) & ~(0xF << TCFG1_BIT_CH(ch));
  57. writel(val | (mux << TCFG1_BIT_CH(ch)), base + REG_TCFG1);
  58. }
  59. static inline void timer_count(void __iomem *base, int ch, unsigned int cnt)
  60. {
  61. writel((cnt - 1), base + REG_TCNTB0 + (TIMER_TCNT_OFFS * ch));
  62. writel((cnt - 1), base + REG_TCMPB0 + (TIMER_TCNT_OFFS * ch));
  63. }
  64. static inline void timer_start(void __iomem *base, int ch)
  65. {
  66. int on = 0;
  67. u32 val = readl(base + REG_CSTAT) & ~(TINT_CSTAT_MASK << 5 | 0x1 << ch);
  68. writel(val | (0x1 << TINT_CSTAT_BIT_CH(ch) | on << ch),
  69. base + REG_CSTAT);
  70. val = readl(base + REG_TCON) & ~(0xE << TCON_BIT_CH(ch));
  71. writel(val | (TCON_BIT_UP << TCON_BIT_CH(ch)), base + REG_TCON);
  72. val &= ~(TCON_BIT_UP << TCON_BIT_CH(ch));
  73. val |= ((TCON_BIT_AUTO | TCON_BIT_RUN) << TCON_BIT_CH(ch));
  74. writel(val, base + REG_TCON);
  75. dmb();
  76. }
  77. static inline void timer_stop(void __iomem *base, int ch)
  78. {
  79. int on = 0;
  80. u32 val = readl(base + REG_CSTAT) & ~(TINT_CSTAT_MASK << 5 | 0x1 << ch);
  81. writel(val | (0x1 << TINT_CSTAT_BIT_CH(ch) | on << ch),
  82. base + REG_CSTAT);
  83. val = readl(base + REG_TCON) & ~(TCON_BIT_RUN << TCON_BIT_CH(ch));
  84. writel(val, base + REG_TCON);
  85. }
  86. static inline unsigned long timer_read(void __iomem *base, int ch)
  87. {
  88. unsigned long ret;
  89. ret = TIMER_COUNT - readl(base + REG_TCNT0 + (TIMER_TCNT_OFFS * ch));
  90. return ret;
  91. }
  92. int timer_init(void)
  93. {
  94. struct clk *clk = NULL;
  95. char name[16] = "pclk";
  96. int ch = CONFIG_TIMER_SYS_TICK_CH;
  97. unsigned long rate, tclk = 0;
  98. unsigned long mout, thz, cmp = -1UL;
  99. int tcnt, tscl = 0, tmux = 0;
  100. int mux = 0, scl = 0;
  101. void __iomem *base = (void __iomem *)PHY_BASEADDR_TIMER;
  102. if (timerinit)
  103. return 0;
  104. /* get with PCLK */
  105. clk = clk_get(name);
  106. rate = clk_get_rate(clk);
  107. for (mux = 0; mux < 5; mux++) {
  108. mout = rate / (1 << mux), scl = mout / TIMER_FREQ,
  109. thz = mout / scl;
  110. if (!(mout % TIMER_FREQ) && 256 > scl) {
  111. tclk = thz, tmux = mux, tscl = scl;
  112. break;
  113. }
  114. if (scl > 256)
  115. continue;
  116. if (abs(thz - TIMER_FREQ) >= cmp)
  117. continue;
  118. tclk = thz, tmux = mux, tscl = scl;
  119. cmp = abs(thz - TIMER_FREQ);
  120. }
  121. tcnt = tclk; /* Timer Count := 1 Mhz counting */
  122. TIMER_FREQ = tcnt; /* Timer Count := 1 Mhz counting */
  123. TIMER_HZ = TIMER_FREQ / CONFIG_SYS_HZ;
  124. tcnt = TIMER_COUNT == 0xFFFFFFFF ? TIMER_COUNT + 1 : tcnt;
  125. timer_stop(base, ch);
  126. timer_clock(base, ch, tmux, tscl);
  127. timer_count(base, ch, tcnt);
  128. timer_start(base, ch);
  129. reset_timer_masked();
  130. timerinit = 1;
  131. return 0;
  132. }
  133. void reset_timer(void)
  134. {
  135. reset_timer_masked();
  136. }
  137. unsigned long get_timer(unsigned long base)
  138. {
  139. long ret;
  140. unsigned long time = get_timer_masked();
  141. unsigned long hz = TIMER_HZ;
  142. ret = time / hz - base;
  143. return ret;
  144. }
  145. void set_timer(unsigned long t)
  146. {
  147. timestamp = (unsigned long)t;
  148. }
  149. void reset_timer_masked(void)
  150. {
  151. void __iomem *base = (void __iomem *)PHY_BASEADDR_TIMER;
  152. int ch = CONFIG_TIMER_SYS_TICK_CH;
  153. /* reset time */
  154. /* capure current decrementer value time */
  155. lastdec = timer_read(base, ch);
  156. /* start "advancing" time stamp from 0 */
  157. timestamp = 0;
  158. }
  159. unsigned long get_timer_masked(void)
  160. {
  161. void __iomem *base = (void __iomem *)PHY_BASEADDR_TIMER;
  162. int ch = CONFIG_TIMER_SYS_TICK_CH;
  163. unsigned long now = timer_read(base, ch); /* current tick value */
  164. if (now >= lastdec) { /* normal mode (non roll) */
  165. /* move stamp fordward with absolute diff ticks */
  166. timestamp += now - lastdec;
  167. } else {
  168. /* we have overflow of the count down timer */
  169. /* nts = ts + ld + (TLV - now)
  170. * ts=old stamp, ld=time that passed before passing through -1
  171. * (TLV-now) amount of time after passing though -1
  172. * nts = new "advancing time stamp"...
  173. * it could also roll and cause problems.
  174. */
  175. timestamp += now + TIMER_COUNT - lastdec;
  176. }
  177. /* save last */
  178. lastdec = now;
  179. debug("now=%lu, last=%lu, timestamp=%lu\n", now, lastdec, timestamp);
  180. return (unsigned long)timestamp;
  181. }
  182. void __udelay(unsigned long usec)
  183. {
  184. unsigned long tmo, tmp;
  185. debug("+udelay=%ld\n", usec);
  186. if (!timerinit)
  187. timer_init();
  188. /* if "big" number, spread normalization to seconds */
  189. if (usec >= 1000) {
  190. /* start to normalize for usec to ticks per sec */
  191. tmo = usec / 1000;
  192. /* find number of "ticks" to wait to achieve target */
  193. tmo *= TIMER_FREQ;
  194. /* finish normalize. */
  195. tmo /= 1000;
  196. /* else small number, don't kill it prior to HZ multiply */
  197. } else {
  198. tmo = usec * TIMER_FREQ;
  199. tmo /= (1000 * 1000);
  200. }
  201. tmp = get_timer_masked(); /* get current timestamp */
  202. debug("A. tmo=%ld, tmp=%ld\n", tmo, tmp);
  203. /* if setting this fordward will roll time stamp */
  204. if (tmp > (tmo + tmp + 1))
  205. /* reset "advancing" timestamp to 0, set lastdec value */
  206. reset_timer_masked();
  207. else
  208. /* set advancing stamp wake up time */
  209. tmo += tmp;
  210. debug("B. tmo=%ld, tmp=%ld\n", tmo, tmp);
  211. /* loop till event */
  212. do {
  213. tmp = get_timer_masked();
  214. } while (tmo > tmp);
  215. debug("-udelay=%ld\n", usec);
  216. }
  217. void udelay_masked(unsigned long usec)
  218. {
  219. unsigned long tmo, endtime;
  220. signed long diff;
  221. /* if "big" number, spread normalization to seconds */
  222. if (usec >= 1000) {
  223. /* start to normalize for usec to ticks per sec */
  224. tmo = usec / 1000;
  225. /* find number of "ticks" to wait to achieve target */
  226. tmo *= TIMER_FREQ;
  227. /* finish normalize. */
  228. tmo /= 1000;
  229. } else { /* else small number, don't kill it prior to HZ multiply */
  230. tmo = usec * TIMER_FREQ;
  231. tmo /= (1000 * 1000);
  232. }
  233. endtime = get_timer_masked() + tmo;
  234. do {
  235. unsigned long now = get_timer_masked();
  236. diff = endtime - now;
  237. } while (diff >= 0);
  238. }
  239. unsigned long long get_ticks(void)
  240. {
  241. return get_timer_masked();
  242. }
  243. #if defined(CONFIG_ARCH_S5P4418)
  244. ulong get_tbclk(void)
  245. {
  246. ulong tbclk = TIMER_FREQ;
  247. return tbclk;
  248. }
  249. #endif