]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/arm/cpu/armv7/imx-common/timer.c
Unified codebase for TX28, TX48, TX51, TX53
[karo-tx-uboot.git] / arch / arm / cpu / armv7 / imx-common / timer.c
1 /*
2  * (C) Copyright 2007
3  * Sascha Hauer, Pengutronix
4  *
5  * (C) Copyright 2009 Freescale Semiconductor, Inc.
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
26 #include <common.h>
27 #include <asm/io.h>
28 #include <div64.h>
29 #include <asm/arch/imx-regs.h>
30
31 /* General purpose timers registers */
32 struct mxc_gpt {
33         unsigned int control;
34         unsigned int prescaler;
35         unsigned int status;
36         unsigned int nouse[6];
37         unsigned int counter;
38 };
39
40 static struct mxc_gpt *cur_gpt = (struct mxc_gpt *)GPT1_BASE_ADDR;
41
42 /* General purpose timers bitfields */
43 #define GPTCR_SWR               (1 << 15)       /* Software reset */
44 #define GPTCR_FRR               (1 << 9)        /* Freerun / restart */
45 #define GPTCR_CLKSOURCE_IPG     (1 << 6)        /* Clock source */
46 #define GPTCR_CLKSOURCE_CKIH    (2 << 6)
47 #define GPTCR_CLKSOURCE_32kHz   (4 << 6)
48 #define GPTCR_CLKSOURCE_OSC     (5 << 6)
49 #define GPTCR_CLKSOURCE_MASK    (7 << 6)
50 #define GPTCR_TEN               1               /* Timer enable */
51
52 #define GPT_CLKSOURCE           GPTCR_CLKSOURCE_32kHz
53 #define GPT_REFCLK              32768
54 #define GPT_PRESCALER           1
55 #define GPT_CLK                 (GPT_REFCLK / GPT_PRESCALER)
56
57 #ifdef DEBUG_TIMER_WRAP
58 /*
59  * Let the timer wrap 30 seconds after start to catch misbehaving
60  * timer related code early
61  */
62 #define TIMER_START             (-time_to_tick(30 * CONFIG_SYS_HZ))
63 #else
64 #define TIMER_START             0UL
65 #endif
66
67 DECLARE_GLOBAL_DATA_PTR;
68
69 static inline unsigned long tick_to_time(unsigned long tick)
70 {
71         unsigned long long t = (unsigned long long)tick * CONFIG_SYS_HZ;
72         do_div(t, GPT_CLK);
73         return t;
74 }
75
76 static inline unsigned long time_to_tick(unsigned long time)
77 {
78         unsigned long long ticks = (unsigned long long)time;
79
80         ticks *= GPT_CLK;
81         do_div(ticks, CONFIG_SYS_HZ);
82         return ticks;
83 }
84
85 static inline unsigned long us_to_tick(unsigned long usec)
86 {
87         unsigned long long ticks = (unsigned long long)usec;
88
89         ticks *= GPT_CLK;
90         do_div(ticks, 1000 * CONFIG_SYS_HZ);
91         return ticks;
92 }
93
94 int timer_init(void)
95 {
96         int i;
97         ulong val;
98
99         /* setup GP Timer 1 */
100         __raw_writel(GPTCR_SWR, &cur_gpt->control);
101
102         /* We have no udelay by now */
103         for (i = 0; i < 100; i++)
104                 __raw_writel(0, &cur_gpt->control);
105
106         __raw_writel(0, &cur_gpt->prescaler);
107
108         /* Freerun Mode, PERCLK1 input */
109         i = __raw_readl(&cur_gpt->control);
110         i &= ~GPTCR_CLKSOURCE_MASK;
111         __raw_writel(i | GPT_CLKSOURCE | GPTCR_TEN, &cur_gpt->control);
112
113         val = __raw_readl(&cur_gpt->counter);
114         gd->lastinc = val;
115         gd->tbu = 0;
116         gd->tbl = TIMER_START;
117         gd->timer_rate_hz = GPT_CLK;
118
119         return 0;
120 }
121
122 unsigned long long get_ticks(void)
123 {
124         ulong now = __raw_readl(&cur_gpt->counter); /* current tick value */
125         ulong inc = now - gd->lastinc;
126
127         gd->tbl += inc;
128         gd->lastinc = now;
129         return gd->tbl;
130 }
131
132 ulong get_timer_masked(void)
133 {
134         /*
135          * get_ticks() returns a long long (64 bit), it wraps in
136          * 2^64 / CONFIG_MX25_CLK32 = 2^64 / 2^15 = 2^49 ~ 5 * 10^14 (s) ~
137          * 5 * 10^9 days... and get_ticks() * CONFIG_SYS_HZ wraps in
138          * 5 * 10^6 days - long enough.
139          */
140         /*
141          * LW: get_ticks() returns a long long with the top 32 bits always ZERO!
142          * Thus the calculation above is not true.
143          * A 64bit timer value would only make sense if it was
144          * consistently used throughout the code. Thus also the parameter
145          * to get_timer() and its return value would need to be 64bit wide!
146          */
147         return tick_to_time(get_ticks());
148 }
149
150 ulong get_timer(ulong base)
151 {
152         return tick_to_time(get_ticks() - time_to_tick(base));
153 }
154
155 /* delay x useconds AND preserve advance timstamp value */
156 void __udelay(unsigned long usec)
157 {
158         unsigned long start = __raw_readl(&cur_gpt->counter);
159         unsigned long ticks;
160
161         if (usec == 0)
162                 return;
163
164         ticks = us_to_tick(usec);
165         if (ticks == 0)
166                 ticks++;
167
168         while (__raw_readl(&cur_gpt->counter) - start < ticks)
169                 /* loop till event */;
170 }
171
172 /*
173  * This function is derived from PowerPC code (timebase clock frequency).
174  * On ARM it returns the number of timer ticks per second.
175  */
176 ulong get_tbclk(void)
177 {
178         return gd->timer_rate_hz;
179 }