]> git.ipfire.org Git - people/ms/u-boot.git/blame - lib_m68k/time.c
Changed CFG_CLK to gd->bus_clk for CFG_TIMER_PRESCALER. Added DECLARE_GLOBAL_DATA_PTR...
[people/ms/u-boot.git] / lib_m68k / time.c
CommitLineData
4e5ca3eb 1/*
bf9e3b38
WD
2 * (C) Copyright 2003 Josef Baumgartner <josef.baumgartner@telex.de>
3 *
4 * (C) Copyright 2000
4e5ca3eb
WD
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
bf9e3b38 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4e5ca3eb
WD
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
bf9e3b38 28#include <asm/mcftimer.h>
52b01760
TL
29#include <asm/timer.h>
30#include <asm/immap.h>
bf9e3b38 31
eacbd317
ZL
32#ifdef CONFIG_M5271
33#include <asm/m5271.h>
34#include <asm/immap_5271.h>
35#endif
36
bf9e3b38
WD
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
cd42deeb
SR
46#ifdef CONFIG_M5249
47#include <asm/m5249.h>
48#include <asm/immap_5249.h>
49#endif
50
99c03c17
TL
51DECLARE_GLOBAL_DATA_PTR;
52
bf9e3b38 53static ulong timestamp;
eacbd317 54#if defined(CONFIG_M5282) || defined(CONFIG_M5271)
bf9e3b38
WD
55static unsigned short lastinc;
56#endif
4e5ca3eb 57
bf9e3b38 58#if defined(CONFIG_M5272)
4e5ca3eb 59/*
bf9e3b38 60 * We use timer 3 which is running with a period of 1 us
4e5ca3eb 61 */
bf9e3b38 62void udelay(unsigned long usec)
4e5ca3eb 63{
bf9e3b38
WD
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 */
52b01760
TL
78 timerp->timer_tmr =
79 (((CFG_CLK / 1000000) -
80 1) << 8) | MCFTIMER_TMR_CLK1 | MCFTIMER_TMR_FREERUN |
81 MCFTIMER_TMR_ENABLE;
bf9e3b38
WD
82
83 start = now = timerp->timer_tcn;
84 while (now < start + tmp)
85 now = timerp->timer_tcn;
86 }
87}
88
52b01760
TL
89void mcf_timer_interrupt(void *not_used)
90{
bf9e3b38
WD
91 volatile timer_t *timerp = (timer_t *) (CFG_MBAR + MCFTIMER_BASE4);
92 volatile intctrl_t *intp = (intctrl_t *) (CFG_MBAR + MCFSIM_ICR1);
4e5ca3eb 93
bf9e3b38
WD
94 /* check for timer 4 interrupts */
95 if ((intp->int_isr & 0x01000000) != 0) {
96 return;
4e5ca3eb
WD
97 }
98
bf9e3b38
WD
99 /* reset timer */
100 timerp->timer_ter = MCFTIMER_TER_CAP | MCFTIMER_TER_REF;
52b01760 101 timestamp++;
4e5ca3eb
WD
102}
103
52b01760
TL
104void timer_init(void)
105{
bf9e3b38
WD
106 volatile timer_t *timerp = (timer_t *) (CFG_MBAR + MCFTIMER_BASE4);
107 volatile intctrl_t *intp = (intctrl_t *) (CFG_MBAR + MCFSIM_ICR1);
4e5ca3eb 108
bf9e3b38
WD
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 */
52b01760 115 irq_install_handler(72, mcf_timer_interrupt, 0);
bf9e3b38
WD
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 */
52b01760
TL
121 timerp->timer_tmr =
122 (((CFG_CLK / 1000000) -
123 1) << 8) | MCFTIMER_TMR_CLK1 | MCFTIMER_TMR_RESTART |
124 MCFTIMER_TMR_ENORI | MCFTIMER_TMR_ENABLE;
bf9e3b38
WD
125}
126
52b01760 127void reset_timer(void)
4e5ca3eb 128{
bf9e3b38
WD
129 timestamp = 0;
130}
4e5ca3eb 131
52b01760 132ulong get_timer(ulong base)
bf9e3b38
WD
133{
134 return (timestamp - base);
4e5ca3eb
WD
135}
136
52b01760 137void set_timer(ulong t)
bf9e3b38
WD
138{
139 timestamp = t;
140}
141#endif
4e5ca3eb 142
eacbd317 143#if defined(CONFIG_M5282) || defined(CONFIG_M5271)
bf9e3b38
WD
144
145void udelay(unsigned long usec)
4e5ca3eb 146{
50712ba1
WD
147 volatile unsigned short *timerp;
148 uint tmp;
149
52b01760 150 timerp = (volatile unsigned short *)(CFG_MBAR + MCFTIMER_BASE3);
3c2b3d45 151
50712ba1
WD
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] =
daa6e418 164#ifdef CONFIG_M5271
52b01760
TL
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 */
50712ba1 169
3c2b3d45 170 timerp[MCFTIMER_PMR] = tmp;
52b01760 171 while (timerp[MCFTIMER_PCNTR] > 0) ;
50712ba1 172 }
4e5ca3eb
WD
173}
174
52b01760 175void timer_init(void)
bf9e3b38
WD
176{
177 volatile unsigned short *timerp;
178
52b01760 179 timerp = (volatile unsigned short *)(CFG_MBAR + MCFTIMER_BASE4);
bf9e3b38
WD
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] =
daa6e418 186#ifdef CONFIG_M5271
52b01760
TL
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 */
bf9e3b38 191}
4e5ca3eb 192
52b01760 193void set_timer(ulong t)
4e5ca3eb 194{
bf9e3b38
WD
195 volatile unsigned short *timerp;
196
52b01760 197 timerp = (volatile unsigned short *)(CFG_MBAR + MCFTIMER_BASE4);
bf9e3b38
WD
198 timestamp = 0;
199 timerp[MCFTIMER_PMR] = lastinc = 0;
200}
201
52b01760 202ulong get_timer(ulong base)
bf9e3b38
WD
203{
204 unsigned short now, diff;
205 volatile unsigned short *timerp;
206
52b01760 207 timerp = (volatile unsigned short *)(CFG_MBAR + MCFTIMER_BASE4);
bf9e3b38
WD
208 now = timerp[MCFTIMER_PCNTR];
209 diff = -(now - lastinc);
210
211 timestamp += diff;
212 lastinc = now;
213 return timestamp - base;
4e5ca3eb
WD
214}
215
52b01760 216void wait_ticks(unsigned long ticks)
bf9e3b38 217{
52b01760
TL
218 set_timer(0);
219 while (get_timer(0) < ticks) ;
bf9e3b38
WD
220}
221#endif
70f05ac3 222
cd42deeb
SR
223#if defined(CONFIG_M5249)
224/*
225 * We use timer 1 which is running with a period of 1 us
226 */
227void 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 */
52b01760
TL
244 timerp->timer_tmr =
245 (((CFG_CLK / 2000000) -
246 1) << 8) | MCFTIMER_TMR_CLK1 | MCFTIMER_TMR_FREERUN |
247 MCFTIMER_TMR_ENABLE;
cd42deeb
SR
248
249 start = now = timerp->timer_tcn;
250 while (now < start + tmp)
251 now = timerp->timer_tcn;
252 }
253}
254
52b01760
TL
255void mcf_timer_interrupt(void *not_used)
256{
cd42deeb
SR
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;
52b01760 266 timestamp++;
cd42deeb
SR
267}
268
52b01760
TL
269void timer_init(void)
270{
cd42deeb
SR
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 */
52b01760 279 irq_install_handler(31, mcf_timer_interrupt, 0);
cd42deeb 280 mbar_writeLong(MCFSIM_IMR, mbar_readLong(MCFSIM_IMR) & ~0x00000400);
52b01760
TL
281 mbar_writeByte(MCFSIM_TIMER2ICR,
282 MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 |
283 MCFSIM_ICR_PRI3);
cd42deeb
SR
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 */
52b01760
TL
289 timerp->timer_tmr =
290 (((CFG_CLK / 2000000) -
291 1) << 8) | MCFTIMER_TMR_CLK1 | MCFTIMER_TMR_RESTART |
292 MCFTIMER_TMR_ENORI | MCFTIMER_TMR_ENABLE;
cd42deeb
SR
293}
294
52b01760 295void reset_timer(void)
cd42deeb
SR
296{
297 timestamp = 0;
298}
299
52b01760 300ulong get_timer(ulong base)
cd42deeb
SR
301{
302 return (timestamp - base);
303}
304
52b01760 305void set_timer(ulong t)
cd42deeb
SR
306{
307 timestamp = t;
308}
309#endif
310
8e585f02
TL
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
52b01760 319extern void dtimer_intr_setup(void);
8e585f02
TL
320
321void 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 =
52b01760
TL
338 CFG_TIMER_PRESCALER | DTIM_DTMR_CLK_DIV1 | DTIM_DTMR_FRR |
339 DTIM_DTMR_RST_EN;
8e585f02
TL
340
341 start = now = timerp->tcn;
342 while (now < start + tmp)
343 now = timerp->tcn;
344 }
345}
346
347void dtimer_interrupt(void *not_used)
348{
349 volatile dtmr_t *timerp = (dtmr_t *) (CFG_TMR_BASE);
350 volatile int0_t *intp = (int0_t *) (CFG_INTR_BASE);
351
352 /* check for timer interrupt asserted */
353 if ((intp->iprh0 & CFG_TMRINTR_MASK) == CFG_TMRINTR_MASK) {
354 timerp->ter = (DTIM_DTER_CAP | DTIM_DTER_REF);
355 timestamp++;
356 return;
357 }
358}
359
360void timer_init(void)
361{
362 volatile dtmr_t *timerp = (dtmr_t *) (CFG_TMR_BASE);
8e585f02
TL
363
364 timestamp = 0;
365
366 timerp->tcn = 0;
367 timerp->trr = 0;
368
369 /* Set up TIMER 4 as clock */
370 timerp->tmr = DTIM_DTMR_RST_RST;
371
52b01760 372 /* initialize and enable timer interrupt */
8e585f02 373 irq_install_handler(CFG_TMRINTR_NO, dtimer_interrupt, 0);
8e585f02
TL
374
375 timerp->tcn = 0;
376 timerp->trr = 1000; /* Interrupt every ms */
377
52b01760 378 dtimer_intr_setup();
8e585f02
TL
379
380 /* set a period of 1us, set timer mode to restart and enable timer and interrupt */
381 timerp->tmr = CFG_TIMER_PRESCALER | DTIM_DTMR_CLK_DIV1 |
382 DTIM_DTMR_FRR | DTIM_DTMR_ORRI | DTIM_DTMR_RST_EN;
383}
384
385void reset_timer(void)
386{
387 timestamp = 0;
388}
389
390ulong get_timer(ulong base)
391{
392 return (timestamp - base);
393}
394
395void set_timer(ulong t)
396{
397 timestamp = t;
398}
399#endif /* CONFIG_MCFTMR */
400
401#if defined(CONFIG_MCFPIT)
402#if !defined(CFG_PIT_BASE)
403# error "CFG_PIT_BASE not defined!"
404#endif
405
406static unsigned short lastinc;
407
408void udelay(unsigned long usec)
409{
410 volatile pit_t *timerp = (pit_t *) (CFG_UDELAY_BASE);
411 uint tmp;
412
413 while (usec > 0) {
414 if (usec > 65000)
415 tmp = 65000;
416 else
417 tmp = usec;
418 usec = usec - tmp;
419
420 /* Set up TIMER 3 as timebase clock */
421 timerp->pcsr = PIT_PCSR_OVW;
422 timerp->pmr = 0;
423 /* set period to 1 us */
424 timerp->pcsr |= PIT_PCSR_PRE(CFG_PIT_PRESCALE) | PIT_PCSR_EN;
425
426 timerp->pmr = tmp;
427 while (timerp->pcntr > 0) ;
428 }
429}
430
431void timer_init(void)
432{
433 volatile pit_t *timerp = (pit_t *) (CFG_PIT_BASE);
434 timestamp = 0;
435
436 /* Set up TIMER 4 as poll clock */
437 timerp->pcsr = PIT_PCSR_OVW;
438 timerp->pmr = lastinc = 0;
439 timerp->pcsr |= PIT_PCSR_PRE(CFG_PIT_PRESCALE) | PIT_PCSR_EN;
440}
441
442void set_timer(ulong t)
443{
444 volatile pit_t *timerp = (pit_t *) (CFG_PIT_BASE);
445
446 timestamp = 0;
447 timerp->pmr = lastinc = 0;
448}
449
450ulong get_timer(ulong base)
451{
452 unsigned short now, diff;
453 volatile pit_t *timerp = (pit_t *) (CFG_PIT_BASE);
454
455 now = timerp->pcntr;
456 diff = -(now - lastinc);
457
458 timestamp += diff;
459 lastinc = now;
460 return timestamp - base;
461}
462
463void wait_ticks(unsigned long ticks)
464{
465 set_timer(0);
466 while (get_timer(0) < ticks) ;
467}
468#endif /* CONFIG_MCFPIT */
cd42deeb 469
70f05ac3
WD
470/*
471 * This function is derived from PowerPC code (read timebase as long long).
472 * On M68K it just returns the timer value.
473 */
474unsigned long long get_ticks(void)
475{
476 return get_timer(0);
477}
478
479/*
480 * This function is derived from PowerPC code (timebase clock frequency).
481 * On M68K it returns the number of timer ticks per second.
482 */
52b01760 483ulong get_tbclk(void)
70f05ac3
WD
484{
485 ulong tbclk;
486 tbclk = CFG_HZ;
487 return tbclk;
488}