]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - cpu/arm926ejs/mx23/timer.c
applied patches from Freescale and Ka-Ro
[karo-tx-uboot.git] / cpu / arm926ejs / mx23 / timer.c
1 /*
2  * (C) Copyright 2003
3  * Texas Instruments <www.ti.com>
4  *
5  * (C) Copyright 2002
6  * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
7  * Marius Groeger <mgroeger@sysgo.de>
8  *
9  * (C) Copyright 2002
10  * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
11  * Alex Zuepke <azu@sysgo.de>
12  *
13  * (C) Copyright 2002-2004
14  * Gary Jennejohn, DENX Software Engineering, <gj@denx.de>
15  *
16  * (C) Copyright 2004
17  * Philippe Robin, ARM Ltd. <philippe.robin@arm.com>
18  *
19  * (C) Copyright 2009-2010 Freescale Semiconductor, Inc.
20  *
21  * See file CREDITS for list of people who contributed to this
22  * project.
23  *
24  * This program is free software; you can redistribute it and/or
25  * modify it under the terms of the GNU General Public License as
26  * published by the Free Software Foundation; either version 2 of
27  * the License, or (at your option) any later version.
28  *
29  * This program is distributed in the hope that it will be useful,
30  * but WITHOUT ANY WARRANTY; without even the implied warranty of
31  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
32  * GNU General Public License for more details.
33  *
34  * You should have received a copy of the GNU General Public License
35  * along with this program; if not, write to the Free Software
36  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
37  * MA 02111-1307 USA
38  */
39
40 #include <common.h>
41 #include <asm/arch/mx23.h>
42 #include <asm/arch/timrot.h>
43
44 #define CONFIG_USE_TIMER0
45
46 #if defined(CONFIG_USE_TIMER0)
47 #define TIMCTRL         TIMCTRL0
48 #define TIMCOUNT        TIMCOUNT0
49 #elif defined(CONFIG_USE_TIMER1)
50 #define TIMCTRL         TIMCTRL1
51 #define TIMCOUNT        TIMCOUNT1
52 #elif defined(CONFIG_USE_TIMER2)
53 #define TIMCTRL         TIMCTRL2
54 #define TIMCOUNT        TIMCOUNT2
55 #elif defined(CONFIG_USE_TIMER3)
56 #define TIMCTRL         TIMCTRL3
57 #define TIMCOUNT        TIMCOUNT3
58 #else
59 #error "Define which MX23 timer to use"
60 #endif
61
62 #define TIMER_LOAD_VAL 0x0000ffff
63
64 /* macro to read the 16 bit timer */
65 #define READ_TIMER ((REG_RD(TIMROT_BASE + TIMCOUNT) & 0xffff0000) >> 16)
66
67 static ulong timestamp;
68 static ulong lastdec;
69
70 int timer_init(void)
71 {
72         u32 val;
73
74         /*
75          * Reset Timers and Rotary Encoder module
76          */
77
78         /* Clear SFTRST */
79         REG_CLR(TIMROT_BASE + ROTCTRL, 1 << 31);
80         while (REG_RD(TIMROT_BASE + ROTCTRL) & (1 << 31))
81                 ;
82
83         /* Clear CLKGATE */
84         REG_CLR(TIMROT_BASE + ROTCTRL, 1 << 30);
85
86         /* Set SFTRST and wait until CLKGATE is set */
87         REG_SET(TIMROT_BASE + ROTCTRL, 1 << 31);
88         while (!(REG_RD(TIMROT_BASE + ROTCTRL) & (1 << 30)))
89                 ;
90
91         /* Clear SFTRST and CLKGATE */
92         REG_CLR(TIMROT_BASE + ROTCTRL, 1 << 31);
93         REG_CLR(TIMROT_BASE + ROTCTRL, 1 << 30);
94
95         /*
96         * Now initialize timer
97         */
98
99         /* Set fixed_count to 0 */
100         REG_WR(TIMROT_BASE + TIMCOUNT, 0);
101
102         /* set UPDATE bit and 1Khz frequency */
103         REG_WR(TIMROT_BASE + TIMCTRL,
104                TIMCTRL_RELOAD | TIMCTRL_UPDATE | TIMCTRL_SELECT_1KHZ);
105
106         /* Set fixed_count to maximal value */
107         REG_WR(TIMROT_BASE + TIMCOUNT, TIMER_LOAD_VAL);
108
109         /* init the timestamp and lastdec value */
110         reset_timer_masked();
111
112         return 0;
113 }
114
115 /*
116  * timer without interrupts
117  */
118
119 void reset_timer(void)
120 {
121         reset_timer_masked();
122 }
123
124 ulong get_timer(ulong base)
125 {
126         return get_timer_masked() - base;
127 }
128
129 void set_timer(ulong t)
130 {
131         timestamp = t;
132 }
133
134 /* delay x useconds AND perserve advance timstamp value */
135 void udelay(unsigned long usec)
136 {
137         ulong tmo, tmp;
138
139         if (usec >= 1000) {
140                 /* if "big" number, spread normalization to seconds */
141                 tmo = usec / 1000;
142                 /* start to normalize for usec to ticks per sec */
143                 tmo *= CONFIG_SYS_HZ;
144                 /* find number of "ticks" to wait to achieve target */
145                 tmo /= 1000;
146                 /* finish normalize. */
147         } else {
148                 /* else small number, don't kill it prior to HZ multiply */
149                 tmo = usec * CONFIG_SYS_HZ;
150                 tmo /= (1000*1000);
151         }
152
153         tmp = get_timer(0);
154                 /* get current timestamp */
155         if ((tmo + tmp + 1) < tmp)
156                 /* if setting this fordward will roll time stamp */
157                 reset_timer_masked();
158                 /* reset "advancing" timestamp to 0, set lastdec value */
159         else
160                 tmo += tmp;
161                 /* else, set advancing stamp wake up time */
162
163         while (get_timer_masked() < tmo)/* loop till event */
164                 /*NOP*/;
165 }
166
167 void reset_timer_masked(void)
168 {
169         /* reset time */
170         lastdec = READ_TIMER;  /* capure current decrementer value time */
171         timestamp = 0;         /* start "advancing" time stamp from 0 */
172 }
173
174 ulong get_timer_masked(void)
175 {
176         ulong now = READ_TIMER;         /* current tick value */
177
178         if (lastdec >= now) {           /* normal mode (non roll) */
179                 /* normal mode */
180                 timestamp += lastdec - now;
181                 /* move stamp fordward with absoulte diff ticks */
182         } else {
183                 /* we have overflow of the count down timer */
184                 /* nts = ts + ld + (TLV - now)
185                  * ts=old stamp, ld=time that passed before passing through -1
186                  * (TLV-now) amount of time after passing though -1
187                  * nts = new "advancing time stamp"...it could also roll
188                  * and cause problems.
189                  */
190                 timestamp += lastdec + TIMER_LOAD_VAL - now + 1;
191         }
192         lastdec = now;
193
194         return timestamp;
195 }
196
197 /* waits specified delay value and resets timestamp */
198 void udelay_masked(unsigned long usec)
199 {
200         ulong tmo;
201         ulong endtime;
202         signed long diff;
203
204         if (usec >= 1000) {
205                 /* if "big" number, spread normalization to seconds */
206                 tmo = usec / 1000;
207                 /* start to normalize for usec to ticks per sec */
208                 tmo *= CONFIG_SYS_HZ;
209                 /* find number of "ticks" to wait to achieve target */
210                 tmo /= 1000;
211                 /* finish normalize. */
212         } else {
213                 /* else small number, don't kill it prior to HZ multiply */
214                 tmo = usec * CONFIG_SYS_HZ;
215                 tmo /= (1000*1000);
216         }
217
218         endtime = get_timer_masked() + tmo;
219
220         do {
221                 ulong now = get_timer_masked();
222                 diff = endtime - now;
223         } while (diff >= 0);
224 }
225
226 /*
227  * This function is derived from PowerPC code (read timebase as long long).
228  * On ARM it just returns the timer value.
229  */
230 unsigned long long get_ticks(void)
231 {
232         return get_timer(0);
233 }
234
235 /*
236  * This function is derived from PowerPC code (timebase clock frequency).
237  * On ARM it returns the number of timer ticks per second.
238  */
239 ulong get_tbclk(void)
240 {
241         ulong tbclk;
242
243         tbclk = CONFIG_SYS_HZ;
244         return tbclk;
245 }