]>
Commit | Line | Data |
---|---|---|
1dc4da74 IY |
1 | /* |
2 | * (C) Copyright 2002 | |
3 | * Sysgo Real-Time Solutions, GmbH <www.elinos.com> | |
4 | * Marius Groeger <mgroeger@sysgo.de> | |
5 | * | |
6 | * (C) Copyright 2002 | |
7 | * Sysgo Real-Time Solutions, GmbH <www.elinos.com> | |
8 | * Alex Zuepke <azu@sysgo.de> | |
9 | * | |
10 | * (C) Copyright 2002 | |
11 | * Gary Jennejohn, DENX Software Engineering, <gj@denx.de> | |
12 | * | |
13 | * (C) Copyright 2009 | |
14 | * Ilya Yanok, Emcraft Systems Ltd, <yanok@emcraft.com> | |
15 | * | |
16 | * See file CREDITS for list of people who contributed to this | |
17 | * project. | |
18 | * | |
19 | * This program is free software; you can redistribute it and/or | |
20 | * modify it under the terms of the GNU General Public License as | |
21 | * published by the Free Software Foundation; either version 2 of | |
22 | * the License, or (at your option) any later version. | |
23 | * | |
24 | * This program is distributed in the hope that it will be useful, | |
25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
27 | * GNU General Public License for more details. | |
28 | * | |
29 | * You should have received a copy of the GNU General Public License | |
30 | * along with this program; if not, write to the Free Software | |
31 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
32 | * MA 02111-1307 USA | |
33 | */ | |
34 | ||
35 | #include <common.h> | |
36 | #include <div64.h> | |
37 | #include <asm/io.h> | |
38 | #include <asm/arch/imx-regs.h> | |
39 | ||
40 | /* General purpose timers bitfields */ | |
41 | #define GPTCR_SWR (1 << 15) /* Software reset */ | |
42 | #define GPTCR_FRR (1 << 8) /* Freerun / restart */ | |
43 | #define GPTCR_CLKSOURCE_32 (4 << 1) /* Clock source */ | |
44 | #define GPTCR_TEN 1 /* Timer enable */ | |
45 | ||
46 | static ulong timestamp; | |
47 | static ulong lastinc; | |
48 | ||
49 | /* | |
50 | * "time" is measured in 1 / CONFIG_SYS_HZ seconds, | |
51 | * "tick" is internal timer period | |
52 | */ | |
53 | #ifdef CONFIG_MX27_TIMER_HIGH_PRECISION | |
54 | /* ~0.4% error - measured with stop-watch on 100s boot-delay */ | |
55 | static inline unsigned long long tick_to_time(unsigned long long tick) | |
56 | { | |
57 | tick *= CONFIG_SYS_HZ; | |
58 | do_div(tick, CONFIG_MX27_CLK32); | |
59 | return tick; | |
60 | } | |
61 | ||
62 | static inline unsigned long long time_to_tick(unsigned long long time) | |
63 | { | |
64 | time *= CONFIG_MX27_CLK32; | |
65 | do_div(time, CONFIG_SYS_HZ); | |
66 | return time; | |
67 | } | |
68 | ||
69 | static inline unsigned long long us_to_tick(unsigned long long us) | |
70 | { | |
71 | us = us * CONFIG_MX27_CLK32 + 999999; | |
72 | do_div(us, 1000000); | |
73 | return us; | |
74 | } | |
75 | #else | |
76 | /* ~2% error */ | |
77 | #define TICK_PER_TIME ((CONFIG_MX27_CLK32 + CONFIG_SYS_HZ / 2) / \ | |
78 | CONFIG_SYS_HZ) | |
79 | #define US_PER_TICK (1000000 / CONFIG_MX27_CLK32) | |
80 | ||
81 | static inline unsigned long long tick_to_time(unsigned long long tick) | |
82 | { | |
83 | do_div(tick, TICK_PER_TIME); | |
84 | return tick; | |
85 | } | |
86 | ||
87 | static inline unsigned long long time_to_tick(unsigned long long time) | |
88 | { | |
89 | return time * TICK_PER_TIME; | |
90 | } | |
91 | ||
92 | static inline unsigned long long us_to_tick(unsigned long long us) | |
93 | { | |
94 | us += US_PER_TICK - 1; | |
95 | do_div(us, US_PER_TICK); | |
96 | return us; | |
97 | } | |
98 | #endif | |
99 | ||
100 | /* nothing really to do with interrupts, just starts up a counter. */ | |
101 | /* The 32768Hz 32-bit timer overruns in 131072 seconds */ | |
102 | int timer_init(void) | |
103 | { | |
104 | int i; | |
105 | struct gpt_regs *regs = (struct gpt_regs *)IMX_TIM1_BASE; | |
106 | struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; | |
107 | ||
108 | /* setup GP Timer 1 */ | |
109 | writel(GPTCR_SWR, ®s->gpt_tctl); | |
110 | ||
111 | writel(readl(&pll->pccr0) | PCCR0_GPT1_EN, &pll->pccr0); | |
112 | writel(readl(&pll->pccr1) | PCCR1_PERCLK1_EN, &pll->pccr1); | |
113 | ||
114 | for (i = 0; i < 100; i++) | |
115 | writel(0, ®s->gpt_tctl); /* We have no udelay by now */ | |
116 | writel(0, ®s->gpt_tprer); /* 32Khz */ | |
117 | /* Freerun Mode, PERCLK1 input */ | |
118 | writel(readl(®s->gpt_tctl) | GPTCR_CLKSOURCE_32 | GPTCR_FRR, | |
119 | ®s->gpt_tctl); | |
120 | writel(readl(®s->gpt_tctl) | GPTCR_TEN, ®s->gpt_tctl); | |
121 | ||
122 | return 0; | |
123 | } | |
124 | ||
125 | void reset_timer_masked(void) | |
126 | { | |
127 | struct gpt_regs *regs = (struct gpt_regs *)IMX_TIM1_BASE; | |
128 | /* reset time */ | |
129 | /* capture current incrementer value time */ | |
130 | lastinc = readl(®s->gpt_tcn); | |
131 | timestamp = 0; /* start "advancing" time stamp from 0 */ | |
132 | } | |
133 | ||
134 | void reset_timer(void) | |
135 | { | |
136 | reset_timer_masked(); | |
137 | } | |
138 | ||
139 | unsigned long long get_ticks (void) | |
140 | { | |
141 | struct gpt_regs *regs = (struct gpt_regs *)IMX_TIM1_BASE; | |
142 | ulong now = readl(®s->gpt_tcn); /* current tick value */ | |
143 | ||
144 | if (now >= lastinc) { | |
145 | /* | |
146 | * normal mode (non roll) | |
147 | * move stamp forward with absolut diff ticks | |
148 | */ | |
149 | timestamp += (now - lastinc); | |
150 | } else { | |
151 | /* we have rollover of incrementer */ | |
152 | timestamp += (0xFFFFFFFF - lastinc) + now; | |
153 | } | |
154 | lastinc = now; | |
155 | return timestamp; | |
156 | } | |
157 | ||
158 | ulong get_timer_masked (void) | |
159 | { | |
160 | /* | |
161 | * get_ticks() returns a long long (64 bit), it wraps in | |
162 | * 2^64 / CONFIG_MX27_CLK32 = 2^64 / 2^15 = 2^49 ~ 5 * 10^14 (s) ~ | |
163 | * 5 * 10^9 days... and get_ticks() * CONFIG_SYS_HZ wraps in | |
164 | * 5 * 10^6 days - long enough. | |
165 | */ | |
166 | return tick_to_time(get_ticks()); | |
167 | } | |
168 | ||
169 | ulong get_timer (ulong base) | |
170 | { | |
171 | return get_timer_masked () - base; | |
172 | } | |
173 | ||
174 | void set_timer (ulong t) | |
175 | { | |
176 | timestamp = time_to_tick(t); | |
177 | } | |
178 | ||
8e5e9b94 | 179 | /* delay x useconds AND preserve advance timstamp value */ |
3eb90bad | 180 | void __udelay (unsigned long usec) |
1dc4da74 IY |
181 | { |
182 | unsigned long long tmp; | |
183 | ulong tmo; | |
184 | ||
185 | tmo = us_to_tick(usec); | |
186 | tmp = get_ticks() + tmo; /* get current timestamp */ | |
187 | ||
188 | while (get_ticks() < tmp) /* loop till event */ | |
189 | /*NOP*/; | |
190 | } |