blob: 267a3cdbc78253a1f6a290b77e97786af287e4a3 [file] [log] [blame]
wdenk4e5ca3e2003-12-08 01:34:36 +00001/*
wdenkbf9e3b32004-02-12 00:47:09 +00002 * (C) Copyright 2003 Josef Baumgartner <josef.baumgartner@telex.de>
3 *
4 * (C) Copyright 2000
wdenk4e5ca3e2003-12-08 01:34:36 +00005 * 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
wdenkbf9e3b32004-02-12 00:47:09 +000017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
wdenk4e5ca3e2003-12-08 01:34:36 +000018 * 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
wdenkbf9e3b32004-02-12 00:47:09 +000028#include <asm/mcftimer.h>
TsiChungLiew52b01762007-07-05 23:36:16 -050029#include <asm/timer.h>
30#include <asm/immap.h>
wdenk4e5ca3e2003-12-08 01:34:36 +000031
Zachary P. Landaueacbd312006-01-26 17:35:56 -050032#ifdef CONFIG_M5271
33#include <asm/m5271.h>
34#include <asm/immap_5271.h>
35#endif
36
wdenkbf9e3b32004-02-12 00:47:09 +000037#ifdef CONFIG_M5272
38#include <asm/m5272.h>
39#include <asm/immap_5272.h>
40#endif
wdenk4e5ca3e2003-12-08 01:34:36 +000041
wdenkbf9e3b32004-02-12 00:47:09 +000042#ifdef CONFIG_M5282
43#include <asm/m5282.h>
44#endif
45
stroesecd42dee2004-12-16 17:56:09 +000046#ifdef CONFIG_M5249
47#include <asm/m5249.h>
48#include <asm/immap_5249.h>
49#endif
50
wdenkbf9e3b32004-02-12 00:47:09 +000051static ulong timestamp;
Zachary P. Landaueacbd312006-01-26 17:35:56 -050052#if defined(CONFIG_M5282) || defined(CONFIG_M5271)
wdenkbf9e3b32004-02-12 00:47:09 +000053static unsigned short lastinc;
54#endif
55
wdenkbf9e3b32004-02-12 00:47:09 +000056#if defined(CONFIG_M5272)
wdenk4e5ca3e2003-12-08 01:34:36 +000057/*
wdenkbf9e3b32004-02-12 00:47:09 +000058 * We use timer 3 which is running with a period of 1 us
wdenk4e5ca3e2003-12-08 01:34:36 +000059 */
60void udelay(unsigned long usec)
61{
wdenkbf9e3b32004-02-12 00:47:09 +000062 volatile timer_t *timerp = (timer_t *) (CFG_MBAR + MCFTIMER_BASE3);
63 uint start, now, tmp;
wdenk4e5ca3e2003-12-08 01:34:36 +000064
wdenkbf9e3b32004-02-12 00:47:09 +000065 while (usec > 0) {
66 if (usec > 65000)
67 tmp = 65000;
68 else
69 tmp = usec;
70 usec = usec - tmp;
71
72 /* Set up TIMER 3 as timebase clock */
73 timerp->timer_tmr = MCFTIMER_TMR_DISABLE;
74 timerp->timer_tcn = 0;
75 /* set period to 1 us */
TsiChungLiew52b01762007-07-05 23:36:16 -050076 timerp->timer_tmr =
77 (((CFG_CLK / 1000000) -
78 1) << 8) | MCFTIMER_TMR_CLK1 | MCFTIMER_TMR_FREERUN |
79 MCFTIMER_TMR_ENABLE;
wdenkbf9e3b32004-02-12 00:47:09 +000080
81 start = now = timerp->timer_tcn;
82 while (now < start + tmp)
83 now = timerp->timer_tcn;
84 }
wdenk4e5ca3e2003-12-08 01:34:36 +000085}
86
TsiChungLiew52b01762007-07-05 23:36:16 -050087void mcf_timer_interrupt(void *not_used)
88{
wdenkbf9e3b32004-02-12 00:47:09 +000089 volatile timer_t *timerp = (timer_t *) (CFG_MBAR + MCFTIMER_BASE4);
90 volatile intctrl_t *intp = (intctrl_t *) (CFG_MBAR + MCFSIM_ICR1);
wdenk4e5ca3e2003-12-08 01:34:36 +000091
wdenkbf9e3b32004-02-12 00:47:09 +000092 /* check for timer 4 interrupts */
93 if ((intp->int_isr & 0x01000000) != 0) {
94 return;
95 }
96
97 /* reset timer */
98 timerp->timer_ter = MCFTIMER_TER_CAP | MCFTIMER_TER_REF;
TsiChungLiew52b01762007-07-05 23:36:16 -050099 timestamp++;
wdenkbf9e3b32004-02-12 00:47:09 +0000100}
101
TsiChungLiew52b01762007-07-05 23:36:16 -0500102void timer_init(void)
103{
wdenkbf9e3b32004-02-12 00:47:09 +0000104 volatile timer_t *timerp = (timer_t *) (CFG_MBAR + MCFTIMER_BASE4);
105 volatile intctrl_t *intp = (intctrl_t *) (CFG_MBAR + MCFSIM_ICR1);
106
107 timestamp = 0;
108
109 /* Set up TIMER 4 as clock */
110 timerp->timer_tmr = MCFTIMER_TMR_DISABLE;
111
112 /* initialize and enable timer 4 interrupt */
TsiChungLiew52b01762007-07-05 23:36:16 -0500113 irq_install_handler(72, mcf_timer_interrupt, 0);
wdenkbf9e3b32004-02-12 00:47:09 +0000114 intp->int_icr1 |= 0x0000000d;
115
116 timerp->timer_tcn = 0;
117 timerp->timer_trr = 1000; /* Interrupt every ms */
118 /* set a period of 1us, set timer mode to restart and enable timer and interrupt */
TsiChungLiew52b01762007-07-05 23:36:16 -0500119 timerp->timer_tmr =
120 (((CFG_CLK / 1000000) -
121 1) << 8) | MCFTIMER_TMR_CLK1 | MCFTIMER_TMR_RESTART |
122 MCFTIMER_TMR_ENORI | MCFTIMER_TMR_ENABLE;
wdenkbf9e3b32004-02-12 00:47:09 +0000123}
124
TsiChungLiew52b01762007-07-05 23:36:16 -0500125void reset_timer(void)
wdenk4e5ca3e2003-12-08 01:34:36 +0000126{
wdenkbf9e3b32004-02-12 00:47:09 +0000127 timestamp = 0;
wdenk4e5ca3e2003-12-08 01:34:36 +0000128}
129
TsiChungLiew52b01762007-07-05 23:36:16 -0500130ulong get_timer(ulong base)
wdenk4e5ca3e2003-12-08 01:34:36 +0000131{
wdenkbf9e3b32004-02-12 00:47:09 +0000132 return (timestamp - base);
wdenk4e5ca3e2003-12-08 01:34:36 +0000133}
134
TsiChungLiew52b01762007-07-05 23:36:16 -0500135void set_timer(ulong t)
wdenkbf9e3b32004-02-12 00:47:09 +0000136{
137 timestamp = t;
138}
139#endif
140
Zachary P. Landaueacbd312006-01-26 17:35:56 -0500141#if defined(CONFIG_M5282) || defined(CONFIG_M5271)
wdenkbf9e3b32004-02-12 00:47:09 +0000142
143void udelay(unsigned long usec)
144{
wdenk50712ba2005-04-03 23:35:57 +0000145 volatile unsigned short *timerp;
146 uint tmp;
147
TsiChungLiew52b01762007-07-05 23:36:16 -0500148 timerp = (volatile unsigned short *)(CFG_MBAR + MCFTIMER_BASE3);
wdenk3c2b3d42005-04-05 23:32:21 +0000149
wdenk50712ba2005-04-03 23:35:57 +0000150 while (usec > 0) {
151 if (usec > 65000)
152 tmp = 65000;
153 else
154 tmp = usec;
155 usec = usec - tmp;
156
157 /* Set up TIMER 3 as timebase clock */
158 timerp[MCFTIMER_PCSR] = MCFTIMER_PCSR_OVW;
159 timerp[MCFTIMER_PMR] = 0;
160 /* set period to 1 us */
161 timerp[MCFTIMER_PCSR] =
Bartlomiej Siekadaa6e412006-12-20 00:27:32 +0100162#ifdef CONFIG_M5271
TsiChungLiew52b01762007-07-05 23:36:16 -0500163 (6 << 8) | MCFTIMER_PCSR_EN | MCFTIMER_PCSR_OVW;
164#else /* !CONFIG_M5271 */
165 (5 << 8) | MCFTIMER_PCSR_EN | MCFTIMER_PCSR_OVW;
166#endif /* CONFIG_M5271 */
wdenk50712ba2005-04-03 23:35:57 +0000167
wdenk3c2b3d42005-04-05 23:32:21 +0000168 timerp[MCFTIMER_PMR] = tmp;
TsiChungLiew52b01762007-07-05 23:36:16 -0500169 while (timerp[MCFTIMER_PCNTR] > 0) ;
wdenk50712ba2005-04-03 23:35:57 +0000170 }
wdenkbf9e3b32004-02-12 00:47:09 +0000171}
172
TsiChungLiew52b01762007-07-05 23:36:16 -0500173void timer_init(void)
wdenkbf9e3b32004-02-12 00:47:09 +0000174{
175 volatile unsigned short *timerp;
176
TsiChungLiew52b01762007-07-05 23:36:16 -0500177 timerp = (volatile unsigned short *)(CFG_MBAR + MCFTIMER_BASE4);
wdenkbf9e3b32004-02-12 00:47:09 +0000178 timestamp = 0;
179
180 /* Set up TIMER 4 as poll clock */
181 timerp[MCFTIMER_PCSR] = MCFTIMER_PCSR_OVW;
182 timerp[MCFTIMER_PMR] = lastinc = 0;
183 timerp[MCFTIMER_PCSR] =
Bartlomiej Siekadaa6e412006-12-20 00:27:32 +0100184#ifdef CONFIG_M5271
TsiChungLiew52b01762007-07-05 23:36:16 -0500185 (6 << 8) | MCFTIMER_PCSR_EN | MCFTIMER_PCSR_OVW;
186#else /* !CONFIG_M5271 */
187 (5 << 8) | MCFTIMER_PCSR_EN | MCFTIMER_PCSR_OVW;
188#endif /* CONFIG_M5271 */
wdenkbf9e3b32004-02-12 00:47:09 +0000189}
190
TsiChungLiew52b01762007-07-05 23:36:16 -0500191void set_timer(ulong t)
wdenkbf9e3b32004-02-12 00:47:09 +0000192{
193 volatile unsigned short *timerp;
194
TsiChungLiew52b01762007-07-05 23:36:16 -0500195 timerp = (volatile unsigned short *)(CFG_MBAR + MCFTIMER_BASE4);
wdenkbf9e3b32004-02-12 00:47:09 +0000196 timestamp = 0;
197 timerp[MCFTIMER_PMR] = lastinc = 0;
198}
199
TsiChungLiew52b01762007-07-05 23:36:16 -0500200ulong get_timer(ulong base)
wdenkbf9e3b32004-02-12 00:47:09 +0000201{
202 unsigned short now, diff;
203 volatile unsigned short *timerp;
204
TsiChungLiew52b01762007-07-05 23:36:16 -0500205 timerp = (volatile unsigned short *)(CFG_MBAR + MCFTIMER_BASE4);
wdenkbf9e3b32004-02-12 00:47:09 +0000206 now = timerp[MCFTIMER_PCNTR];
207 diff = -(now - lastinc);
208
209 timestamp += diff;
210 lastinc = now;
211 return timestamp - base;
212}
213
TsiChungLiew52b01762007-07-05 23:36:16 -0500214void wait_ticks(unsigned long ticks)
wdenkbf9e3b32004-02-12 00:47:09 +0000215{
TsiChungLiew52b01762007-07-05 23:36:16 -0500216 set_timer(0);
217 while (get_timer(0) < ticks) ;
wdenkbf9e3b32004-02-12 00:47:09 +0000218}
219#endif
wdenk70f05ac2004-06-09 15:24:18 +0000220
stroesecd42dee2004-12-16 17:56:09 +0000221#if defined(CONFIG_M5249)
222/*
223 * We use timer 1 which is running with a period of 1 us
224 */
225void udelay(unsigned long usec)
226{
227 volatile timer_t *timerp = (timer_t *) (CFG_MBAR + MCFTIMER_BASE1);
228 uint start, now, tmp;
229
230 while (usec > 0) {
231 if (usec > 65000)
232 tmp = 65000;
233 else
234 tmp = usec;
235 usec = usec - tmp;
236
237 /* Set up TIMER 1 as timebase clock */
238 timerp->timer_tmr = MCFTIMER_TMR_DISABLE;
239 timerp->timer_tcn = 0;
240 /* set period to 1 us */
241 /* on m5249 the system clock is (cpu_clk / 2) -> divide by 2000000 */
TsiChungLiew52b01762007-07-05 23:36:16 -0500242 timerp->timer_tmr =
243 (((CFG_CLK / 2000000) -
244 1) << 8) | MCFTIMER_TMR_CLK1 | MCFTIMER_TMR_FREERUN |
245 MCFTIMER_TMR_ENABLE;
stroesecd42dee2004-12-16 17:56:09 +0000246
247 start = now = timerp->timer_tcn;
248 while (now < start + tmp)
249 now = timerp->timer_tcn;
250 }
251}
252
TsiChungLiew52b01762007-07-05 23:36:16 -0500253void mcf_timer_interrupt(void *not_used)
254{
stroesecd42dee2004-12-16 17:56:09 +0000255 volatile timer_t *timerp = (timer_t *) (CFG_MBAR + MCFTIMER_BASE2);
256
257 /* check for timer 2 interrupts */
258 if ((mbar_readLong(MCFSIM_IPR) & 0x00000400) == 0) {
259 return;
260 }
261
262 /* reset timer */
263 timerp->timer_ter = MCFTIMER_TER_CAP | MCFTIMER_TER_REF;
TsiChungLiew52b01762007-07-05 23:36:16 -0500264 timestamp++;
stroesecd42dee2004-12-16 17:56:09 +0000265}
266
TsiChungLiew52b01762007-07-05 23:36:16 -0500267void timer_init(void)
268{
stroesecd42dee2004-12-16 17:56:09 +0000269 volatile timer_t *timerp = (timer_t *) (CFG_MBAR + MCFTIMER_BASE2);
270
271 timestamp = 0;
272
273 /* Set up TIMER 2 as clock */
274 timerp->timer_tmr = MCFTIMER_TMR_DISABLE;
275
276 /* initialize and enable timer 2 interrupt */
TsiChungLiew52b01762007-07-05 23:36:16 -0500277 irq_install_handler(31, mcf_timer_interrupt, 0);
stroesecd42dee2004-12-16 17:56:09 +0000278 mbar_writeLong(MCFSIM_IMR, mbar_readLong(MCFSIM_IMR) & ~0x00000400);
TsiChungLiew52b01762007-07-05 23:36:16 -0500279 mbar_writeByte(MCFSIM_TIMER2ICR,
280 MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 |
281 MCFSIM_ICR_PRI3);
stroesecd42dee2004-12-16 17:56:09 +0000282
283 timerp->timer_tcn = 0;
284 timerp->timer_trr = 1000; /* Interrupt every ms */
285 /* set a period of 1us, set timer mode to restart and enable timer and interrupt */
286 /* on m5249 the system clock is (cpu_clk / 2) -> divide by 2000000 */
TsiChungLiew52b01762007-07-05 23:36:16 -0500287 timerp->timer_tmr =
288 (((CFG_CLK / 2000000) -
289 1) << 8) | MCFTIMER_TMR_CLK1 | MCFTIMER_TMR_RESTART |
290 MCFTIMER_TMR_ENORI | MCFTIMER_TMR_ENABLE;
stroesecd42dee2004-12-16 17:56:09 +0000291}
292
TsiChungLiew52b01762007-07-05 23:36:16 -0500293void reset_timer(void)
stroesecd42dee2004-12-16 17:56:09 +0000294{
295 timestamp = 0;
296}
297
TsiChungLiew52b01762007-07-05 23:36:16 -0500298ulong get_timer(ulong base)
stroesecd42dee2004-12-16 17:56:09 +0000299{
300 return (timestamp - base);
301}
302
TsiChungLiew52b01762007-07-05 23:36:16 -0500303void set_timer(ulong t)
stroesecd42dee2004-12-16 17:56:09 +0000304{
305 timestamp = t;
306}
307#endif
308
TsiChung Liew8e585f02007-06-18 13:50:13 -0500309#if defined(CONFIG_MCFTMR)
310#ifndef CFG_UDELAY_BASE
311# error "uDelay base not defined!"
312#endif
313
314#if !defined(CFG_TMR_BASE) || !defined(CFG_INTR_BASE) || !defined(CFG_TMRINTR_NO) || !defined(CFG_TMRINTR_MASK)
315# error "TMR_BASE, INTR_BASE, TMRINTR_NO or TMRINTR_MASk not defined!"
316#endif
TsiChungLiew52b01762007-07-05 23:36:16 -0500317extern void dtimer_intr_setup(void);
TsiChung Liew8e585f02007-06-18 13:50:13 -0500318
319void udelay(unsigned long usec)
320{
321 volatile dtmr_t *timerp = (dtmr_t *) (CFG_UDELAY_BASE);
322 uint start, now, tmp;
323
324 while (usec > 0) {
325 if (usec > 65000)
326 tmp = 65000;
327 else
328 tmp = usec;
329 usec = usec - tmp;
330
331 /* Set up TIMER 3 as timebase clock */
332 timerp->tmr = DTIM_DTMR_RST_RST;
333 timerp->tcn = 0;
334 /* set period to 1 us */
335 timerp->tmr =
TsiChungLiew52b01762007-07-05 23:36:16 -0500336 CFG_TIMER_PRESCALER | DTIM_DTMR_CLK_DIV1 | DTIM_DTMR_FRR |
337 DTIM_DTMR_RST_EN;
TsiChung Liew8e585f02007-06-18 13:50:13 -0500338
339 start = now = timerp->tcn;
340 while (now < start + tmp)
341 now = timerp->tcn;
342 }
343}
344
345void dtimer_interrupt(void *not_used)
346{
347 volatile dtmr_t *timerp = (dtmr_t *) (CFG_TMR_BASE);
348 volatile int0_t *intp = (int0_t *) (CFG_INTR_BASE);
349
350 /* check for timer interrupt asserted */
351 if ((intp->iprh0 & CFG_TMRINTR_MASK) == CFG_TMRINTR_MASK) {
352 timerp->ter = (DTIM_DTER_CAP | DTIM_DTER_REF);
353 timestamp++;
354 return;
355 }
356}
357
358void timer_init(void)
359{
360 volatile dtmr_t *timerp = (dtmr_t *) (CFG_TMR_BASE);
TsiChung Liew8e585f02007-06-18 13:50:13 -0500361
362 timestamp = 0;
363
364 timerp->tcn = 0;
365 timerp->trr = 0;
366
367 /* Set up TIMER 4 as clock */
368 timerp->tmr = DTIM_DTMR_RST_RST;
369
TsiChungLiew52b01762007-07-05 23:36:16 -0500370 /* initialize and enable timer interrupt */
TsiChung Liew8e585f02007-06-18 13:50:13 -0500371 irq_install_handler(CFG_TMRINTR_NO, dtimer_interrupt, 0);
TsiChung Liew8e585f02007-06-18 13:50:13 -0500372
373 timerp->tcn = 0;
374 timerp->trr = 1000; /* Interrupt every ms */
375
TsiChungLiew52b01762007-07-05 23:36:16 -0500376 dtimer_intr_setup();
TsiChung Liew8e585f02007-06-18 13:50:13 -0500377
378 /* set a period of 1us, set timer mode to restart and enable timer and interrupt */
379 timerp->tmr = CFG_TIMER_PRESCALER | DTIM_DTMR_CLK_DIV1 |
380 DTIM_DTMR_FRR | DTIM_DTMR_ORRI | DTIM_DTMR_RST_EN;
381}
382
383void reset_timer(void)
384{
385 timestamp = 0;
386}
387
388ulong get_timer(ulong base)
389{
390 return (timestamp - base);
391}
392
393void set_timer(ulong t)
394{
395 timestamp = t;
396}
397#endif /* CONFIG_MCFTMR */
398
399#if defined(CONFIG_MCFPIT)
400#if !defined(CFG_PIT_BASE)
401# error "CFG_PIT_BASE not defined!"
402#endif
403
404static unsigned short lastinc;
405
406void udelay(unsigned long usec)
407{
408 volatile pit_t *timerp = (pit_t *) (CFG_UDELAY_BASE);
409 uint tmp;
410
411 while (usec > 0) {
412 if (usec > 65000)
413 tmp = 65000;
414 else
415 tmp = usec;
416 usec = usec - tmp;
417
418 /* Set up TIMER 3 as timebase clock */
419 timerp->pcsr = PIT_PCSR_OVW;
420 timerp->pmr = 0;
421 /* set period to 1 us */
422 timerp->pcsr |= PIT_PCSR_PRE(CFG_PIT_PRESCALE) | PIT_PCSR_EN;
423
424 timerp->pmr = tmp;
425 while (timerp->pcntr > 0) ;
426 }
427}
428
429void timer_init(void)
430{
431 volatile pit_t *timerp = (pit_t *) (CFG_PIT_BASE);
432 timestamp = 0;
433
434 /* Set up TIMER 4 as poll clock */
435 timerp->pcsr = PIT_PCSR_OVW;
436 timerp->pmr = lastinc = 0;
437 timerp->pcsr |= PIT_PCSR_PRE(CFG_PIT_PRESCALE) | PIT_PCSR_EN;
438}
439
440void set_timer(ulong t)
441{
442 volatile pit_t *timerp = (pit_t *) (CFG_PIT_BASE);
443
444 timestamp = 0;
445 timerp->pmr = lastinc = 0;
446}
447
448ulong get_timer(ulong base)
449{
450 unsigned short now, diff;
451 volatile pit_t *timerp = (pit_t *) (CFG_PIT_BASE);
452
453 now = timerp->pcntr;
454 diff = -(now - lastinc);
455
456 timestamp += diff;
457 lastinc = now;
458 return timestamp - base;
459}
460
461void wait_ticks(unsigned long ticks)
462{
463 set_timer(0);
464 while (get_timer(0) < ticks) ;
465}
466#endif /* CONFIG_MCFPIT */
stroesecd42dee2004-12-16 17:56:09 +0000467
wdenk70f05ac2004-06-09 15:24:18 +0000468/*
469 * This function is derived from PowerPC code (read timebase as long long).
470 * On M68K it just returns the timer value.
471 */
472unsigned long long get_ticks(void)
473{
474 return get_timer(0);
475}
476
477/*
478 * This function is derived from PowerPC code (timebase clock frequency).
479 * On M68K it returns the number of timer ticks per second.
480 */
TsiChungLiew52b01762007-07-05 23:36:16 -0500481ulong get_tbclk(void)
wdenk70f05ac2004-06-09 15:24:18 +0000482{
483 ulong tbclk;
484 tbclk = CFG_HZ;
485 return tbclk;
486}