time-s3c64xx.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. /* linux/arch/arm/mach-s3c64xx/time.c
  2. *
  3. * Copyright (C) 2006 Samsung Electronics
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  18. */
  19. #include <linux/kernel.h>
  20. #include <linux/sched.h>
  21. #include <linux/init.h>
  22. #include <linux/interrupt.h>
  23. #include <linux/irq.h>
  24. #include <linux/err.h>
  25. #include <linux/clk.h>
  26. #include <asm/system.h>
  27. #include <asm/leds.h>
  28. #include <asm/mach-types.h>
  29. #include <asm/io.h>
  30. #include <asm/irq.h>
  31. #include <asm/arch/map.h>
  32. #include <asm/arch/regs-timer.h>
  33. #include <asm/arch/regs-irq.h>
  34. #include <asm/arch/regs-gpio.h>
  35. #include <asm/mach/time.h>
  36. #include <asm/plat-s3c24xx/clock.h>
  37. #include <asm/plat-s3c24xx/cpu.h>
  38. static unsigned long timer_startval;
  39. static unsigned long timer_usec_ticks;
  40. #ifdef CONFIG_NO_IDLE_HZ
  41. static unsigned long s3c_timer_cnt_per_tick;
  42. static unsigned long previous_dyn_ticks;
  43. static unsigned long last_dyn_ticks;
  44. static unsigned long sync_timer_startval;
  45. static unsigned long last_sync_timer_count;
  46. static unsigned long last_tick_count;
  47. #define JIFFIES_TO_HW_TICKS(nr_jiffies, timer_cnt_per_tick)\
  48. ((nr_jiffies) * timer_cnt_per_tick)
  49. #endif
  50. //#define T32_PROBE_TEST
  51. #define TIMER_USEC_SHIFT 16
  52. /* we use the shifted arithmetic to work out the ratio of timer ticks
  53. * to usecs, as often the peripheral clock is not a nice even multiple
  54. * of 1MHz.
  55. *
  56. * shift of 14 and 15 are too low for the 12MHz, 16 seems to be ok
  57. * for the current HZ value of 200 without producing overflows.
  58. *
  59. * Original patch by Dimitry Andric, updated by Ben Dooks
  60. */
  61. #ifdef CONFIG_NO_IDLE_HZ
  62. static inline unsigned long s3c_sync_timer_read(void)
  63. {
  64. return __raw_readl(S3C_TCNTO(3));
  65. }
  66. static inline void s3c_init_sync_timer(void)
  67. {
  68. unsigned long tcon;
  69. unsigned long tcfg1;
  70. unsigned long tcfg0;
  71. sync_timer_startval = 0xffffffff;
  72. tcon = __raw_readl(S3C_TCON);
  73. tcfg1 = __raw_readl(S3C_TCFG1);
  74. tcfg0 = __raw_readl(S3C_TCFG0);
  75. /* Sync timer setting */
  76. tcfg1 &= ~S3C_TCFG1_MUX3_MASK;
  77. tcfg1 |= S3C_TCFG1_MUX3_DIV1;
  78. __raw_writel(tcfg1, S3C_TCFG1);
  79. tcfg0 &= ~S3C_TCFG_PRESCALER1_MASK;
  80. tcfg0 |= (PRESCALER) << S3C_TCFG_PRESCALER1_SHIFT;
  81. __raw_writel(0xffffffff, S3C_TCNTB(3));
  82. tcon &= ~(0xf<<16);
  83. tcon |= S3C_TCON_T3RELOAD;
  84. tcon |= S3C_TCON_T3MANUALUPD;
  85. __raw_writel(tcon, S3C_TCON);
  86. }
  87. #endif
  88. /* timer_mask_usec_ticks
  89. *
  90. * given a clock and divisor, make the value to pass into timer_ticks_to_usec
  91. * to scale the ticks into usecs
  92. */
  93. static inline unsigned long
  94. timer_mask_usec_ticks(unsigned long scaler, unsigned long pclk)
  95. {
  96. unsigned long den = pclk / 1000;
  97. return ((1000 << TIMER_USEC_SHIFT) * scaler + (den >> 1)) / den;
  98. }
  99. /* timer_ticks_to_usec
  100. *
  101. * convert timer ticks to usec.
  102. */
  103. static inline unsigned long timer_ticks_to_usec(unsigned long ticks)
  104. {
  105. unsigned long res;
  106. res = ticks * timer_usec_ticks;
  107. res += 1 << (TIMER_USEC_SHIFT - 4); /* round up slightly */
  108. return res >> TIMER_USEC_SHIFT;
  109. }
  110. /***
  111. * Returns microsecond since last clock interrupt. Note that interrupts
  112. * will have been disabled by do_gettimeoffset()
  113. * IRQs are disabled before entering here from do_gettimeofday()
  114. */
  115. static unsigned long s3c_gettimeoffset (void)
  116. {
  117. unsigned long tval;
  118. unsigned long tdone;
  119. #ifdef CONFIG_NO_IDLE_HZ
  120. tval = s3c_sync_timer_read();
  121. if(last_tick_count >= tval)
  122. tdone = last_tick_count - tval;
  123. else
  124. tdone = 0xffffffff - tval + last_tick_count + 1;
  125. #else
  126. tval = __raw_readl(S3C_TCNTO(4));
  127. tdone = timer_startval - tval;
  128. #endif
  129. return timer_ticks_to_usec(tdone);
  130. }
  131. static inline irqreturn_t _s3c_timer_interrupt(int irq, void *dev_id)
  132. {
  133. #ifdef CONFIG_NO_IDLE_HZ
  134. unsigned long now,tmp;
  135. now = s3c_sync_timer_read();
  136. if(now <= last_tick_count) {
  137. tmp = last_tick_count - now;
  138. } else {
  139. tmp = 0xffffffff - now + last_tick_count + 1;
  140. }
  141. while(tmp >= s3c_timer_cnt_per_tick) {
  142. tmp -= s3c_timer_cnt_per_tick;
  143. if(last_tick_count > s3c_timer_cnt_per_tick)
  144. last_tick_count -= s3c_timer_cnt_per_tick;
  145. else
  146. last_tick_count = (0xffffffff - s3c_timer_cnt_per_tick + last_tick_count + 1);
  147. timer_tick();
  148. }
  149. //printk("z=0x%x\n",__raw_readl(S3C_TCNTO(4)));
  150. #else
  151. timer_tick();
  152. #endif
  153. return IRQ_HANDLED;
  154. }
  155. /*
  156. * IRQ handler for the timer
  157. */
  158. static irqreturn_t
  159. s3c_timer_interrupt(int irq, void *dev_id)
  160. {
  161. #ifdef T32_PROBE_TEST
  162. s3c_gpio_setpin(S3C_GPN14, 1);
  163. #endif
  164. write_seqlock(&xtime_lock);
  165. _s3c_timer_interrupt(irq, dev_id);
  166. write_sequnlock(&xtime_lock);
  167. __raw_writel((0x1f & __raw_readl(S3C_TINT_CSTAT)) | S3C_TINT_CSTAT_T4INT, S3C_TINT_CSTAT);
  168. // __raw_writel((0x1f & __raw_readl(S3C_TINT_CSTAT)) | S3C_TINT_CSTAT_T4INTEN, S3C_TINT_CSTAT);
  169. #ifdef T32_PROBE_TEST
  170. s3c_gpio_setpin(S3C_GPN14, 0);
  171. #endif
  172. return IRQ_HANDLED;
  173. }
  174. static struct irqaction s3c_timer_irq = {
  175. .name = "S3C Timer Tick",
  176. .flags = IRQF_DISABLED | IRQF_TIMER,
  177. .handler = s3c_timer_interrupt,
  178. };
  179. #ifdef CONFIG_NO_IDLE_HZ
  180. /*
  181. * Programs the next timer interrupt needed. Called when dynamic tick is
  182. * enabled, and to reprogram the ticks to skip from pm_idle. Note that
  183. * we can keep the timer continuous, and don't need to set it to run in
  184. * one-shot mode. This is because the timer will get reprogrammed again
  185. * after next interrupt.
  186. */
  187. void s3c_timer_reprogram(unsigned long next_tick)
  188. {
  189. unsigned long tcnt;
  190. #ifdef T32_PROBE_TEST
  191. s3c_gpio_setpin(S3C_GPN15, 1);
  192. #endif
  193. //printk("next_tick=%d\n",next_tick);
  194. if(next_tick == 0)
  195. next_tick = 1;
  196. last_dyn_ticks = next_tick;
  197. tcnt = JIFFIES_TO_HW_TICKS(next_tick, s3c_timer_cnt_per_tick);
  198. //printk("tcnt=0x%x\n",tcnt);
  199. __raw_writel((tcnt - 1), S3C_TCNTB(4));
  200. #ifdef T32_PROBE_TEST
  201. s3c_gpio_setpin(S3C_GPN15, 0);
  202. #endif
  203. }
  204. static int s3c_timer_enable_dyn_tick(void)
  205. {
  206. return 0;
  207. }
  208. static int s3c_timer_disable_dyn_tick(void)
  209. {
  210. unsigned long tcnt;
  211. last_dyn_ticks = 1;
  212. tcnt = JIFFIES_TO_HW_TICKS(1, s3c_timer_cnt_per_tick);
  213. __raw_writel((tcnt - 1), S3C_TCNTB(0));
  214. return 0;
  215. }
  216. static irqreturn_t s3c_dyn_tick_handler(int irq, void *dev_id)
  217. {
  218. //printk("dyntick irq%d\n",irq);
  219. return _s3c_timer_interrupt(irq, dev_id);
  220. }
  221. static struct dyn_tick_timer s3c_dyn_tick_timer = {
  222. .enable = s3c_timer_enable_dyn_tick,
  223. .disable = s3c_timer_disable_dyn_tick,
  224. .reprogram = s3c_timer_reprogram,
  225. .handler = s3c_dyn_tick_handler,
  226. };
  227. #endif
  228. /*
  229. * Set up timer interrupt, and return the current time in seconds.
  230. *
  231. * Currently we only use timer4, as it is the only timer which has no
  232. * other function that can be exploited externally
  233. */
  234. static void s3c_timer_setup (void)
  235. {
  236. unsigned long tcon;
  237. unsigned long tcnt;
  238. unsigned long tcfg1;
  239. unsigned long tcfg0;
  240. unsigned long pclk;
  241. unsigned long timerclock;
  242. struct clk *clk;
  243. #ifdef T32_PROBE_TEST
  244. s3c_gpio_cfgpin(S3C_GPN14, S3C_GPN14_OUTP);
  245. s3c_gpio_cfgpin(S3C_GPN15, S3C_GPN15_OUTP);
  246. s3c_gpio_setpin(S3C_GPN14, 0);
  247. s3c_gpio_setpin(S3C_GPN15, 0);
  248. /* read the current timer configuration bits */
  249. #endif
  250. tcnt = 0xffffffff; /* default value for tcnt */
  251. /* read the current timer configuration bits */
  252. tcfg1 = __raw_readl(S3C_TCFG1);
  253. tcfg0 = __raw_readl(S3C_TCFG0);
  254. /* this is used as default if no other timer can be found */
  255. clk = clk_get(NULL, "timers");
  256. if (IS_ERR(clk))
  257. panic("failed to get clock for system timer");
  258. clk_enable(clk);
  259. pclk = clk_get_rate(clk);
  260. timerclock = (pclk / ((PRESCALER + 1)*DIVIDER));
  261. /* configure clock tick */
  262. timer_usec_ticks = timer_mask_usec_ticks(((PRESCALER + 1)*DIVIDER), pclk);
  263. tcfg1 &= ~S3C_TCFG1_MUX4_MASK;
  264. tcfg1 |= S3C_TCFG1_MUX4_DIV1;
  265. tcfg0 &= ~S3C_TCFG_PRESCALER1_MASK;
  266. tcfg0 |= (PRESCALER) << S3C_TCFG_PRESCALER1_SHIFT;
  267. tcnt = timerclock / HZ;
  268. /* timers reload after counting zero, so reduce the count by 1 */
  269. tcnt--;
  270. __raw_writel(tcfg1, S3C_TCFG1);
  271. __raw_writel(tcfg0, S3C_TCFG0);
  272. timer_startval = tcnt;
  273. __raw_writel(tcnt, S3C_TCNTB(4));
  274. /* ensure timer is stopped... */
  275. #ifdef CONFIG_NO_IDLE_HZ
  276. s3c_timer_cnt_per_tick = (timerclock/HZ);
  277. previous_dyn_ticks = 1;
  278. last_dyn_ticks = 1;
  279. last_sync_timer_count = 0xffffffff;
  280. last_tick_count = 0xffffffff;
  281. s3c_init_sync_timer();
  282. #endif
  283. tcon = __raw_readl(S3C_TCON);
  284. tcon &= ~(7<<20);
  285. tcon |= S3C_TCON_T4RELOAD;
  286. tcon |= S3C_TCON_T4MANUALUPD;
  287. __raw_writel(tcon, S3C_TCON);
  288. __raw_writel(tcnt, S3C_TCNTB(4));
  289. //__raw_writel(tcnt, S3C_TCMPB(4));
  290. printk("timer tcon=%08lx, tcnt %04lx, tcfg %08lx,%08lx, usec %08lx\n",
  291. tcon, tcnt, tcfg0, tcfg1, timer_usec_ticks);
  292. /* start the timer running */
  293. #ifdef CONFIG_NO_IDLE_HZ
  294. tcon |= S3C_TCON_T4START|S3C_TCON_T3START;
  295. tcon &= ~(S3C_TCON_T4MANUALUPD|S3C_TCON_T3MANUALUPD);
  296. #else
  297. tcon |= S3C_TCON_T4START;
  298. tcon &= ~S3C_TCON_T4MANUALUPD;
  299. #endif
  300. __raw_writel(tcon, S3C_TCON);
  301. /* timer4 interrupt enable */
  302. __raw_writel(__raw_readl(S3C_TINT_CSTAT) | S3C_TINT_CSTAT_T4INTEN, S3C_TINT_CSTAT);
  303. }
  304. static void __init s3c_timer_init (void)
  305. {
  306. s3c_timer_setup();
  307. setup_irq(IRQ_TIMER4, &s3c_timer_irq);
  308. }
  309. struct sys_timer s3c_timer = {
  310. .init = s3c_timer_init,
  311. .offset = s3c_gettimeoffset,
  312. .resume = s3c_timer_setup,
  313. #ifdef CONFIG_NO_IDLE_HZ
  314. .dyn_tick = &s3c_dyn_tick_timer,
  315. #endif
  316. };