blob: f111242e5314a377fb252998e994acf9fd047626 [file] [log] [blame]
Sascha Hauer1a7676f2008-03-26 20:40:42 +01001/*
2 * (C) Copyright 2007
3 * Sascha Hauer, Pengutronix
4 *
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02005 * SPDX-License-Identifier: GPL-2.0+
Sascha Hauer1a7676f2008-03-26 20:40:42 +01006 */
7
8#include <common.h>
Stefano Babic78129d92011-03-14 15:43:56 +01009#include <asm/arch/imx-regs.h>
Benoît Thébaudeau38e2f082012-08-21 11:06:03 +000010#include <asm/arch/clock.h>
Tomohiro Masubuchi9a3393b2008-10-21 13:17:16 +090011#include <div64.h>
Stefano Babice17e3312011-02-02 00:49:36 +000012#include <watchdog.h>
13#include <asm/io.h>
Sascha Hauer1a7676f2008-03-26 20:40:42 +010014
15#define TIMER_BASE 0x53f90000 /* General purpose timer 1 */
16
17/* General purpose timers registers */
Guennadi Liakhovetski4771a4c2008-09-25 20:54:37 +020018#define GPTCR __REG(TIMER_BASE) /* Control register */
19#define GPTPR __REG(TIMER_BASE + 0x4) /* Prescaler register */
20#define GPTSR __REG(TIMER_BASE + 0x8) /* Status register */
21#define GPTCNT __REG(TIMER_BASE + 0x24) /* Counter register */
Sascha Hauer1a7676f2008-03-26 20:40:42 +010022
23/* General purpose timers bitfields */
Guennadi Liakhovetski4771a4c2008-09-25 20:54:37 +020024#define GPTCR_SWR (1 << 15) /* Software reset */
25#define GPTCR_FRR (1 << 9) /* Freerun / restart */
26#define GPTCR_CLKSOURCE_32 (4 << 6) /* Clock source */
27#define GPTCR_TEN 1 /* Timer enable */
28
Heiko Schocherf2015952010-12-09 22:01:15 +000029DECLARE_GLOBAL_DATA_PTR;
Tomohiro Masubuchi9a3393b2008-10-21 13:17:16 +090030
Fabio Estevamf231efb2011-10-13 05:34:59 +000031/*
32 * "time" is measured in 1 / CONFIG_SYS_HZ seconds,
33 * "tick" is internal timer period
34 */
35
Guennadi Liakhovetski4771a4c2008-09-25 20:54:37 +020036#ifdef CONFIG_MX31_TIMER_HIGH_PRECISION
37/* ~0.4% error - measured with stop-watch on 100s boot-delay */
Tomohiro Masubuchi9a3393b2008-10-21 13:17:16 +090038static inline unsigned long long tick_to_time(unsigned long long tick)
39{
40 tick *= CONFIG_SYS_HZ;
Benoît Thébaudeau38e2f082012-08-21 11:06:03 +000041 do_div(tick, MXC_CLK32);
Tomohiro Masubuchi9a3393b2008-10-21 13:17:16 +090042 return tick;
43}
44
45static inline unsigned long long time_to_tick(unsigned long long time)
46{
Benoît Thébaudeau38e2f082012-08-21 11:06:03 +000047 time *= MXC_CLK32;
Tomohiro Masubuchi9a3393b2008-10-21 13:17:16 +090048 do_div(time, CONFIG_SYS_HZ);
49 return time;
50}
51
52static inline unsigned long long us_to_tick(unsigned long long us)
53{
Benoît Thébaudeau38e2f082012-08-21 11:06:03 +000054 us = us * MXC_CLK32 + 999999;
Tomohiro Masubuchi9a3393b2008-10-21 13:17:16 +090055 do_div(us, 1000000);
56 return us;
57}
Guennadi Liakhovetski4771a4c2008-09-25 20:54:37 +020058#else
59/* ~2% error */
Benoît Thébaudeau38e2f082012-08-21 11:06:03 +000060#define TICK_PER_TIME ((MXC_CLK32 + CONFIG_SYS_HZ / 2) / CONFIG_SYS_HZ)
61#define US_PER_TICK (1000000 / MXC_CLK32)
Sascha Hauer1a7676f2008-03-26 20:40:42 +010062
Tomohiro Masubuchi9a3393b2008-10-21 13:17:16 +090063static inline unsigned long long tick_to_time(unsigned long long tick)
64{
65 do_div(tick, TICK_PER_TIME);
66 return tick;
67}
68
69static inline unsigned long long time_to_tick(unsigned long long time)
70{
71 return time * TICK_PER_TIME;
72}
73
74static inline unsigned long long us_to_tick(unsigned long long us)
75{
76 us += US_PER_TICK - 1;
77 do_div(us, US_PER_TICK);
78 return us;
79}
80#endif
Magnus Lilja067a4f92008-08-29 10:36:17 +020081
Guennadi Liakhovetski4771a4c2008-09-25 20:54:37 +020082/* The 32768Hz 32-bit timer overruns in 131072 seconds */
Fabio Estevamf231efb2011-10-13 05:34:59 +000083int timer_init(void)
Sascha Hauer1a7676f2008-03-26 20:40:42 +010084{
85 int i;
86
87 /* setup GP Timer 1 */
88 GPTCR = GPTCR_SWR;
Guennadi Liakhovetski4771a4c2008-09-25 20:54:37 +020089 for (i = 0; i < 100; i++)
90 GPTCR = 0; /* We have no udelay by now */
Sascha Hauer1a7676f2008-03-26 20:40:42 +010091 GPTPR = 0; /* 32Khz */
Guennadi Liakhovetski4771a4c2008-09-25 20:54:37 +020092 /* Freerun Mode, PERCLK1 input */
93 GPTCR |= GPTCR_CLKSOURCE_32 | GPTCR_TEN;
Sascha Hauer1a7676f2008-03-26 20:40:42 +010094
95 return 0;
96}
97
Fabio Estevamf231efb2011-10-13 05:34:59 +000098unsigned long long get_ticks(void)
Sascha Hauer1a7676f2008-03-26 20:40:42 +010099{
Magnus Lilja067a4f92008-08-29 10:36:17 +0200100 ulong now = GPTCNT; /* current tick value */
101
Simon Glassa848da52012-12-13 20:48:35 +0000102 if (now >= gd->arch.lastinc) /* normal mode (non roll) */
Magnus Lilja067a4f92008-08-29 10:36:17 +0200103 /* move stamp forward with absolut diff ticks */
Simon Glassa848da52012-12-13 20:48:35 +0000104 gd->arch.tbl += (now - gd->arch.lastinc);
Magnus Lilja067a4f92008-08-29 10:36:17 +0200105 else /* we have rollover of incrementer */
Simon Glassa848da52012-12-13 20:48:35 +0000106 gd->arch.tbl += (0xFFFFFFFF - gd->arch.lastinc) + now;
107 gd->arch.lastinc = now;
Simon Glass2655ee12012-12-13 20:48:34 +0000108 return gd->arch.tbl;
Sascha Hauer1a7676f2008-03-26 20:40:42 +0100109}
110
Fabio Estevamf231efb2011-10-13 05:34:59 +0000111ulong get_timer_masked(void)
Guennadi Liakhovetski4771a4c2008-09-25 20:54:37 +0200112{
113 /*
114 * get_ticks() returns a long long (64 bit), it wraps in
Benoît Thébaudeau38e2f082012-08-21 11:06:03 +0000115 * 2^64 / MXC_CLK32 = 2^64 / 2^15 = 2^49 ~ 5 * 10^14 (s) ~
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200116 * 5 * 10^9 days... and get_ticks() * CONFIG_SYS_HZ wraps in
Guennadi Liakhovetski4771a4c2008-09-25 20:54:37 +0200117 * 5 * 10^6 days - long enough.
118 */
Tomohiro Masubuchi9a3393b2008-10-21 13:17:16 +0900119 return tick_to_time(get_ticks());
Guennadi Liakhovetski4771a4c2008-09-25 20:54:37 +0200120}
121
Fabio Estevamf231efb2011-10-13 05:34:59 +0000122ulong get_timer(ulong base)
Sascha Hauer1a7676f2008-03-26 20:40:42 +0100123{
Fabio Estevamf231efb2011-10-13 05:34:59 +0000124 return get_timer_masked() - base;
Sascha Hauer1a7676f2008-03-26 20:40:42 +0100125}
126
Wolfgang Denkd7cb3552010-05-21 23:13:18 +0200127/* delay x useconds AND preserve advance timestamp value */
Fabio Estevamf231efb2011-10-13 05:34:59 +0000128void __udelay(unsigned long usec)
Sascha Hauer1a7676f2008-03-26 20:40:42 +0100129{
Guennadi Liakhovetski4771a4c2008-09-25 20:54:37 +0200130 unsigned long long tmp;
131 ulong tmo;
Sascha Hauer1a7676f2008-03-26 20:40:42 +0100132
Tomohiro Masubuchi9a3393b2008-10-21 13:17:16 +0900133 tmo = us_to_tick(usec);
Guennadi Liakhovetski4771a4c2008-09-25 20:54:37 +0200134 tmp = get_ticks() + tmo; /* get current timestamp */
Sascha Hauer1a7676f2008-03-26 20:40:42 +0100135
Guennadi Liakhovetski4771a4c2008-09-25 20:54:37 +0200136 while (get_ticks() < tmp) /* loop till event */
137 /*NOP*/;
Sascha Hauer1a7676f2008-03-26 20:40:42 +0100138}
139
Stefano Babicecb6e6e2012-02-04 13:02:01 +0100140/*
141 * This function is derived from PowerPC code (timebase clock frequency).
142 * On ARM it returns the number of timer ticks per second.
143 */
144ulong get_tbclk(void)
145{
Benoît Thébaudeau38e2f082012-08-21 11:06:03 +0000146 return MXC_CLK32;
Stefano Babicecb6e6e2012-02-04 13:02:01 +0100147}