ColdFire: MCF5329 Update and cleanup
[platform/kernel/u-boot.git] / lib_m68k / time.c
1 /*
2  * (C) Copyright 2003 Josef Baumgartner <josef.baumgartner@telex.de>
3  *
4  * (C) Copyright 2000
5  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
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
28 #include <asm/mcftimer.h>
29 #include <asm/timer.h>
30 #include <asm/immap.h>
31
32 #ifdef  CONFIG_M5271
33 #include <asm/m5271.h>
34 #include <asm/immap_5271.h>
35 #endif
36
37 #ifdef  CONFIG_M5272
38 #include <asm/m5272.h>
39 #include <asm/immap_5272.h>
40 #endif
41
42 #ifdef  CONFIG_M5282
43 #include <asm/m5282.h>
44 #endif
45
46 #ifdef  CONFIG_M5249
47 #include <asm/m5249.h>
48 #include <asm/immap_5249.h>
49 #endif
50
51 DECLARE_GLOBAL_DATA_PTR;
52
53 static ulong timestamp;
54 #if defined(CONFIG_M5282) || defined(CONFIG_M5271)
55 static unsigned short lastinc;
56 #endif
57
58 #if defined(CONFIG_M5272)
59 /*
60  * We use timer 3 which is running with a period of 1 us
61  */
62 void udelay(unsigned long usec)
63 {
64         volatile timer_t *timerp = (timer_t *) (CFG_MBAR + MCFTIMER_BASE3);
65         uint start, now, tmp;
66
67         while (usec > 0) {
68                 if (usec > 65000)
69                         tmp = 65000;
70                 else
71                         tmp = usec;
72                 usec = usec - tmp;
73
74                 /* Set up TIMER 3 as timebase clock */
75                 timerp->timer_tmr = MCFTIMER_TMR_DISABLE;
76                 timerp->timer_tcn = 0;
77                 /* set period to 1 us */
78                 timerp->timer_tmr =
79                     (((CFG_CLK / 1000000) -
80                       1) << 8) | MCFTIMER_TMR_CLK1 | MCFTIMER_TMR_FREERUN |
81                     MCFTIMER_TMR_ENABLE;
82
83                 start = now = timerp->timer_tcn;
84                 while (now < start + tmp)
85                         now = timerp->timer_tcn;
86         }
87 }
88
89 void mcf_timer_interrupt(void *not_used)
90 {
91         volatile timer_t *timerp = (timer_t *) (CFG_MBAR + MCFTIMER_BASE4);
92         volatile intctrl_t *intp = (intctrl_t *) (CFG_MBAR + MCFSIM_ICR1);
93
94         /* check for timer 4 interrupts */
95         if ((intp->int_isr & 0x01000000) != 0) {
96                 return;
97         }
98
99         /* reset timer */
100         timerp->timer_ter = MCFTIMER_TER_CAP | MCFTIMER_TER_REF;
101         timestamp++;
102 }
103
104 void timer_init(void)
105 {
106         volatile timer_t *timerp = (timer_t *) (CFG_MBAR + MCFTIMER_BASE4);
107         volatile intctrl_t *intp = (intctrl_t *) (CFG_MBAR + MCFSIM_ICR1);
108
109         timestamp = 0;
110
111         /* Set up TIMER 4 as clock */
112         timerp->timer_tmr = MCFTIMER_TMR_DISABLE;
113
114         /* initialize and enable timer 4 interrupt */
115         irq_install_handler(72, mcf_timer_interrupt, 0);
116         intp->int_icr1 |= 0x0000000d;
117
118         timerp->timer_tcn = 0;
119         timerp->timer_trr = 1000;       /* Interrupt every ms */
120         /* set a period of 1us, set timer mode to restart and enable timer and interrupt */
121         timerp->timer_tmr =
122             (((CFG_CLK / 1000000) -
123               1) << 8) | MCFTIMER_TMR_CLK1 | MCFTIMER_TMR_RESTART |
124             MCFTIMER_TMR_ENORI | MCFTIMER_TMR_ENABLE;
125 }
126
127 void reset_timer(void)
128 {
129         timestamp = 0;
130 }
131
132 ulong get_timer(ulong base)
133 {
134         return (timestamp - base);
135 }
136
137 void set_timer(ulong t)
138 {
139         timestamp = t;
140 }
141 #endif
142
143 #if defined(CONFIG_M5282) || defined(CONFIG_M5271)
144
145 void udelay(unsigned long usec)
146 {
147         volatile unsigned short *timerp;
148         uint tmp;
149
150         timerp = (volatile unsigned short *)(CFG_MBAR + MCFTIMER_BASE3);
151
152         while (usec > 0) {
153                 if (usec > 65000)
154                         tmp = 65000;
155                 else
156                         tmp = usec;
157                 usec = usec - tmp;
158
159                 /* Set up TIMER 3 as timebase clock */
160                 timerp[MCFTIMER_PCSR] = MCFTIMER_PCSR_OVW;
161                 timerp[MCFTIMER_PMR] = 0;
162                 /* set period to 1 us */
163                 timerp[MCFTIMER_PCSR] =
164 #ifdef CONFIG_M5271
165                     (6 << 8) | MCFTIMER_PCSR_EN | MCFTIMER_PCSR_OVW;
166 #else                           /* !CONFIG_M5271 */
167                     (5 << 8) | MCFTIMER_PCSR_EN | MCFTIMER_PCSR_OVW;
168 #endif                          /* CONFIG_M5271 */
169
170                 timerp[MCFTIMER_PMR] = tmp;
171                 while (timerp[MCFTIMER_PCNTR] > 0) ;
172         }
173 }
174
175 void timer_init(void)
176 {
177         volatile unsigned short *timerp;
178
179         timerp = (volatile unsigned short *)(CFG_MBAR + MCFTIMER_BASE4);
180         timestamp = 0;
181
182         /* Set up TIMER 4 as poll clock */
183         timerp[MCFTIMER_PCSR] = MCFTIMER_PCSR_OVW;
184         timerp[MCFTIMER_PMR] = lastinc = 0;
185         timerp[MCFTIMER_PCSR] =
186 #ifdef CONFIG_M5271
187             (6 << 8) | MCFTIMER_PCSR_EN | MCFTIMER_PCSR_OVW;
188 #else                           /* !CONFIG_M5271 */
189             (5 << 8) | MCFTIMER_PCSR_EN | MCFTIMER_PCSR_OVW;
190 #endif                          /* CONFIG_M5271 */
191 }
192
193 void set_timer(ulong t)
194 {
195         volatile unsigned short *timerp;
196
197         timerp = (volatile unsigned short *)(CFG_MBAR + MCFTIMER_BASE4);
198         timestamp = 0;
199         timerp[MCFTIMER_PMR] = lastinc = 0;
200 }
201
202 ulong get_timer(ulong base)
203 {
204         unsigned short now, diff;
205         volatile unsigned short *timerp;
206
207         timerp = (volatile unsigned short *)(CFG_MBAR + MCFTIMER_BASE4);
208         now = timerp[MCFTIMER_PCNTR];
209         diff = -(now - lastinc);
210
211         timestamp += diff;
212         lastinc = now;
213         return timestamp - base;
214 }
215
216 void wait_ticks(unsigned long ticks)
217 {
218         set_timer(0);
219         while (get_timer(0) < ticks) ;
220 }
221 #endif
222
223 #if defined(CONFIG_M5249)
224 /*
225  * We use timer 1 which is running with a period of 1 us
226  */
227 void udelay(unsigned long usec)
228 {
229         volatile timer_t *timerp = (timer_t *) (CFG_MBAR + MCFTIMER_BASE1);
230         uint start, now, tmp;
231
232         while (usec > 0) {
233                 if (usec > 65000)
234                         tmp = 65000;
235                 else
236                         tmp = usec;
237                 usec = usec - tmp;
238
239                 /* Set up TIMER 1 as timebase clock */
240                 timerp->timer_tmr = MCFTIMER_TMR_DISABLE;
241                 timerp->timer_tcn = 0;
242                 /* set period to 1 us */
243                 /* on m5249 the system clock is (cpu_clk / 2) -> divide by 2000000 */
244                 timerp->timer_tmr =
245                     (((CFG_CLK / 2000000) -
246                       1) << 8) | MCFTIMER_TMR_CLK1 | MCFTIMER_TMR_FREERUN |
247                     MCFTIMER_TMR_ENABLE;
248
249                 start = now = timerp->timer_tcn;
250                 while (now < start + tmp)
251                         now = timerp->timer_tcn;
252         }
253 }
254
255 void mcf_timer_interrupt(void *not_used)
256 {
257         volatile timer_t *timerp = (timer_t *) (CFG_MBAR + MCFTIMER_BASE2);
258
259         /* check for timer 2 interrupts */
260         if ((mbar_readLong(MCFSIM_IPR) & 0x00000400) == 0) {
261                 return;
262         }
263
264         /* reset timer */
265         timerp->timer_ter = MCFTIMER_TER_CAP | MCFTIMER_TER_REF;
266         timestamp++;
267 }
268
269 void timer_init(void)
270 {
271         volatile timer_t *timerp = (timer_t *) (CFG_MBAR + MCFTIMER_BASE2);
272
273         timestamp = 0;
274
275         /* Set up TIMER 2 as clock */
276         timerp->timer_tmr = MCFTIMER_TMR_DISABLE;
277
278         /* initialize and enable timer 2 interrupt */
279         irq_install_handler(31, mcf_timer_interrupt, 0);
280         mbar_writeLong(MCFSIM_IMR, mbar_readLong(MCFSIM_IMR) & ~0x00000400);
281         mbar_writeByte(MCFSIM_TIMER2ICR,
282                        MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 |
283                        MCFSIM_ICR_PRI3);
284
285         timerp->timer_tcn = 0;
286         timerp->timer_trr = 1000;       /* Interrupt every ms */
287         /* set a period of 1us, set timer mode to restart and enable timer and interrupt */
288         /* on m5249 the system clock is (cpu_clk / 2) -> divide by 2000000 */
289         timerp->timer_tmr =
290             (((CFG_CLK / 2000000) -
291               1) << 8) | MCFTIMER_TMR_CLK1 | MCFTIMER_TMR_RESTART |
292             MCFTIMER_TMR_ENORI | MCFTIMER_TMR_ENABLE;
293 }
294
295 void reset_timer(void)
296 {
297         timestamp = 0;
298 }
299
300 ulong get_timer(ulong base)
301 {
302         return (timestamp - base);
303 }
304
305 void set_timer(ulong t)
306 {
307         timestamp = t;
308 }
309 #endif
310
311 #if defined(CONFIG_MCFTMR)
312 #ifndef CFG_UDELAY_BASE
313 #       error   "uDelay base not defined!"
314 #endif
315
316 #if !defined(CFG_TMR_BASE) || !defined(CFG_INTR_BASE) || !defined(CFG_TMRINTR_NO) || !defined(CFG_TMRINTR_MASK)
317 #       error   "TMR_BASE, INTR_BASE, TMRINTR_NO or TMRINTR_MASk not defined!"
318 #endif
319 extern void dtimer_intr_setup(void);
320
321 void udelay(unsigned long usec)
322 {
323         volatile dtmr_t *timerp = (dtmr_t *) (CFG_UDELAY_BASE);
324         uint start, now, tmp;
325
326         while (usec > 0) {
327                 if (usec > 65000)
328                         tmp = 65000;
329                 else
330                         tmp = usec;
331                 usec = usec - tmp;
332
333                 /* Set up TIMER 3 as timebase clock */
334                 timerp->tmr = DTIM_DTMR_RST_RST;
335                 timerp->tcn = 0;
336                 /* set period to 1 us */
337                 timerp->tmr =
338                     CFG_TIMER_PRESCALER | DTIM_DTMR_CLK_DIV1 | DTIM_DTMR_FRR |
339                     DTIM_DTMR_RST_EN;
340
341                 start = now = timerp->tcn;
342                 while (now < start + tmp)
343                         now = timerp->tcn;
344         }
345 }
346
347 void dtimer_interrupt(void *not_used)
348 {
349         volatile dtmr_t *timerp = (dtmr_t *) (CFG_TMR_BASE);
350
351         /* check for timer interrupt asserted */
352         if ((CFG_TMRPND_REG & CFG_TMRINTR_MASK) == CFG_TMRINTR_PEND) {
353                 timerp->ter = (DTIM_DTER_CAP | DTIM_DTER_REF);
354                 timestamp++;
355                 return;
356         }
357 }
358
359 void timer_init(void)
360 {
361         volatile dtmr_t *timerp = (dtmr_t *) (CFG_TMR_BASE);
362
363         timestamp = 0;
364
365         timerp->tcn = 0;
366         timerp->trr = 0;
367
368         /* Set up TIMER 4 as clock */
369         timerp->tmr = DTIM_DTMR_RST_RST;
370
371         /* initialize and enable timer interrupt */
372         irq_install_handler(CFG_TMRINTR_NO, dtimer_interrupt, 0);
373
374         timerp->tcn = 0;
375         timerp->trr = 1000;     /* Interrupt every ms */
376
377         dtimer_intr_setup();
378
379         /* set a period of 1us, set timer mode to restart and enable timer and interrupt */
380         timerp->tmr = CFG_TIMER_PRESCALER | DTIM_DTMR_CLK_DIV1 |
381             DTIM_DTMR_FRR | DTIM_DTMR_ORRI | DTIM_DTMR_RST_EN;
382 }
383
384 void reset_timer(void)
385 {
386         timestamp = 0;
387 }
388
389 ulong get_timer(ulong base)
390 {
391         return (timestamp - base);
392 }
393
394 void set_timer(ulong t)
395 {
396         timestamp = t;
397 }
398 #endif                          /* CONFIG_MCFTMR */
399
400 #if defined(CONFIG_MCFPIT)
401 #if !defined(CFG_PIT_BASE)
402 #       error   "CFG_PIT_BASE not defined!"
403 #endif
404
405 static unsigned short lastinc;
406
407 void udelay(unsigned long usec)
408 {
409         volatile pit_t *timerp = (pit_t *) (CFG_UDELAY_BASE);
410         uint tmp;
411
412         while (usec > 0) {
413                 if (usec > 65000)
414                         tmp = 65000;
415                 else
416                         tmp = usec;
417                 usec = usec - tmp;
418
419                 /* Set up TIMER 3 as timebase clock */
420                 timerp->pcsr = PIT_PCSR_OVW;
421                 timerp->pmr = 0;
422                 /* set period to 1 us */
423                 timerp->pcsr |= PIT_PCSR_PRE(CFG_PIT_PRESCALE) | PIT_PCSR_EN;
424
425                 timerp->pmr = tmp;
426                 while (timerp->pcntr > 0) ;
427         }
428 }
429
430 void timer_init(void)
431 {
432         volatile pit_t *timerp = (pit_t *) (CFG_PIT_BASE);
433         timestamp = 0;
434
435         /* Set up TIMER 4 as poll clock */
436         timerp->pcsr = PIT_PCSR_OVW;
437         timerp->pmr = lastinc = 0;
438         timerp->pcsr |= PIT_PCSR_PRE(CFG_PIT_PRESCALE) | PIT_PCSR_EN;
439 }
440
441 void set_timer(ulong t)
442 {
443         volatile pit_t *timerp = (pit_t *) (CFG_PIT_BASE);
444
445         timestamp = 0;
446         timerp->pmr = lastinc = 0;
447 }
448
449 ulong get_timer(ulong base)
450 {
451         unsigned short now, diff;
452         volatile pit_t *timerp = (pit_t *) (CFG_PIT_BASE);
453
454         now = timerp->pcntr;
455         diff = -(now - lastinc);
456
457         timestamp += diff;
458         lastinc = now;
459         return timestamp - base;
460 }
461
462 void wait_ticks(unsigned long ticks)
463 {
464         set_timer(0);
465         while (get_timer(0) < ticks) ;
466 }
467 #endif                          /* CONFIG_MCFPIT */
468
469 /*
470  * This function is derived from PowerPC code (read timebase as long long).
471  * On M68K it just returns the timer value.
472  */
473 unsigned long long get_ticks(void)
474 {
475         return get_timer(0);
476 }
477
478 /*
479  * This function is derived from PowerPC code (timebase clock frequency).
480  * On M68K it returns the number of timer ticks per second.
481  */
482 ulong get_tbclk(void)
483 {
484         ulong tbclk;
485         tbclk = CFG_HZ;
486         return tbclk;
487 }