blob: 3dbce07213ef27db06ed98e937bedf4f37b4be22 [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
TsiChungLiew99c03c12007-08-05 03:58:52 -050051DECLARE_GLOBAL_DATA_PTR;
52
wdenkbf9e3b32004-02-12 00:47:09 +000053static ulong timestamp;
Zachary P. Landaueacbd312006-01-26 17:35:56 -050054#if defined(CONFIG_M5282) || defined(CONFIG_M5271)
wdenkbf9e3b32004-02-12 00:47:09 +000055static unsigned short lastinc;
56#endif
57
wdenkbf9e3b32004-02-12 00:47:09 +000058#if defined(CONFIG_M5272)
wdenk4e5ca3e2003-12-08 01:34:36 +000059/*
wdenkbf9e3b32004-02-12 00:47:09 +000060 * We use timer 3 which is running with a period of 1 us
wdenk4e5ca3e2003-12-08 01:34:36 +000061 */
62void udelay(unsigned long usec)
63{
wdenkbf9e3b32004-02-12 00:47:09 +000064 volatile timer_t *timerp = (timer_t *) (CFG_MBAR + MCFTIMER_BASE3);
65 uint start, now, tmp;
wdenk4e5ca3e2003-12-08 01:34:36 +000066
wdenkbf9e3b32004-02-12 00:47:09 +000067 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 */
TsiChungLiew52b01762007-07-05 23:36:16 -050078 timerp->timer_tmr =
79 (((CFG_CLK / 1000000) -
80 1) << 8) | MCFTIMER_TMR_CLK1 | MCFTIMER_TMR_FREERUN |
81 MCFTIMER_TMR_ENABLE;
wdenkbf9e3b32004-02-12 00:47:09 +000082
83 start = now = timerp->timer_tcn;
84 while (now < start + tmp)
85 now = timerp->timer_tcn;
86 }
wdenk4e5ca3e2003-12-08 01:34:36 +000087}
88
TsiChungLiew52b01762007-07-05 23:36:16 -050089void mcf_timer_interrupt(void *not_used)
90{
wdenkbf9e3b32004-02-12 00:47:09 +000091 volatile timer_t *timerp = (timer_t *) (CFG_MBAR + MCFTIMER_BASE4);
92 volatile intctrl_t *intp = (intctrl_t *) (CFG_MBAR + MCFSIM_ICR1);
wdenk4e5ca3e2003-12-08 01:34:36 +000093
wdenkbf9e3b32004-02-12 00:47:09 +000094 /* 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;
TsiChungLiew52b01762007-07-05 23:36:16 -0500101 timestamp++;
wdenkbf9e3b32004-02-12 00:47:09 +0000102}
103
TsiChungLiew52b01762007-07-05 23:36:16 -0500104void timer_init(void)
105{
wdenkbf9e3b32004-02-12 00:47:09 +0000106 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 */
TsiChungLiew52b01762007-07-05 23:36:16 -0500115 irq_install_handler(72, mcf_timer_interrupt, 0);
wdenkbf9e3b32004-02-12 00:47:09 +0000116 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 */
TsiChungLiew52b01762007-07-05 23:36:16 -0500121 timerp->timer_tmr =
122 (((CFG_CLK / 1000000) -
123 1) << 8) | MCFTIMER_TMR_CLK1 | MCFTIMER_TMR_RESTART |
124 MCFTIMER_TMR_ENORI | MCFTIMER_TMR_ENABLE;
wdenkbf9e3b32004-02-12 00:47:09 +0000125}
126
TsiChungLiew52b01762007-07-05 23:36:16 -0500127void reset_timer(void)
wdenk4e5ca3e2003-12-08 01:34:36 +0000128{
wdenkbf9e3b32004-02-12 00:47:09 +0000129 timestamp = 0;
wdenk4e5ca3e2003-12-08 01:34:36 +0000130}
131
TsiChungLiew52b01762007-07-05 23:36:16 -0500132ulong get_timer(ulong base)
wdenk4e5ca3e2003-12-08 01:34:36 +0000133{
wdenkbf9e3b32004-02-12 00:47:09 +0000134 return (timestamp - base);
wdenk4e5ca3e2003-12-08 01:34:36 +0000135}
136
TsiChungLiew52b01762007-07-05 23:36:16 -0500137void set_timer(ulong t)
wdenkbf9e3b32004-02-12 00:47:09 +0000138{
139 timestamp = t;
140}
141#endif
142
Zachary P. Landaueacbd312006-01-26 17:35:56 -0500143#if defined(CONFIG_M5282) || defined(CONFIG_M5271)
wdenkbf9e3b32004-02-12 00:47:09 +0000144
145void udelay(unsigned long usec)
146{
wdenk50712ba2005-04-03 23:35:57 +0000147 volatile unsigned short *timerp;
148 uint tmp;
149
TsiChungLiew52b01762007-07-05 23:36:16 -0500150 timerp = (volatile unsigned short *)(CFG_MBAR + MCFTIMER_BASE3);
wdenk3c2b3d42005-04-05 23:32:21 +0000151
wdenk50712ba2005-04-03 23:35:57 +0000152 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] =
Bartlomiej Siekadaa6e412006-12-20 00:27:32 +0100164#ifdef CONFIG_M5271
TsiChungLiew52b01762007-07-05 23:36:16 -0500165 (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 */
wdenk50712ba2005-04-03 23:35:57 +0000169
wdenk3c2b3d42005-04-05 23:32:21 +0000170 timerp[MCFTIMER_PMR] = tmp;
TsiChungLiew52b01762007-07-05 23:36:16 -0500171 while (timerp[MCFTIMER_PCNTR] > 0) ;
wdenk50712ba2005-04-03 23:35:57 +0000172 }
wdenkbf9e3b32004-02-12 00:47:09 +0000173}
174
TsiChungLiew52b01762007-07-05 23:36:16 -0500175void timer_init(void)
wdenkbf9e3b32004-02-12 00:47:09 +0000176{
177 volatile unsigned short *timerp;
178
TsiChungLiew52b01762007-07-05 23:36:16 -0500179 timerp = (volatile unsigned short *)(CFG_MBAR + MCFTIMER_BASE4);
wdenkbf9e3b32004-02-12 00:47:09 +0000180 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] =
Bartlomiej Siekadaa6e412006-12-20 00:27:32 +0100186#ifdef CONFIG_M5271
TsiChungLiew52b01762007-07-05 23:36:16 -0500187 (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 */
wdenkbf9e3b32004-02-12 00:47:09 +0000191}
192
TsiChungLiew52b01762007-07-05 23:36:16 -0500193void set_timer(ulong t)
wdenkbf9e3b32004-02-12 00:47:09 +0000194{
195 volatile unsigned short *timerp;
196
TsiChungLiew52b01762007-07-05 23:36:16 -0500197 timerp = (volatile unsigned short *)(CFG_MBAR + MCFTIMER_BASE4);
wdenkbf9e3b32004-02-12 00:47:09 +0000198 timestamp = 0;
199 timerp[MCFTIMER_PMR] = lastinc = 0;
200}
201
TsiChungLiew52b01762007-07-05 23:36:16 -0500202ulong get_timer(ulong base)
wdenkbf9e3b32004-02-12 00:47:09 +0000203{
204 unsigned short now, diff;
205 volatile unsigned short *timerp;
206
TsiChungLiew52b01762007-07-05 23:36:16 -0500207 timerp = (volatile unsigned short *)(CFG_MBAR + MCFTIMER_BASE4);
wdenkbf9e3b32004-02-12 00:47:09 +0000208 now = timerp[MCFTIMER_PCNTR];
209 diff = -(now - lastinc);
210
211 timestamp += diff;
212 lastinc = now;
213 return timestamp - base;
214}
215
TsiChungLiew52b01762007-07-05 23:36:16 -0500216void wait_ticks(unsigned long ticks)
wdenkbf9e3b32004-02-12 00:47:09 +0000217{
TsiChungLiew52b01762007-07-05 23:36:16 -0500218 set_timer(0);
219 while (get_timer(0) < ticks) ;
wdenkbf9e3b32004-02-12 00:47:09 +0000220}
221#endif
wdenk70f05ac2004-06-09 15:24:18 +0000222
stroesecd42dee2004-12-16 17:56:09 +0000223#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 */
TsiChungLiew52b01762007-07-05 23:36:16 -0500244 timerp->timer_tmr =
245 (((CFG_CLK / 2000000) -
246 1) << 8) | MCFTIMER_TMR_CLK1 | MCFTIMER_TMR_FREERUN |
247 MCFTIMER_TMR_ENABLE;
stroesecd42dee2004-12-16 17:56:09 +0000248
249 start = now = timerp->timer_tcn;
250 while (now < start + tmp)
251 now = timerp->timer_tcn;
252 }
253}
254
TsiChungLiew52b01762007-07-05 23:36:16 -0500255void mcf_timer_interrupt(void *not_used)
256{
stroesecd42dee2004-12-16 17:56:09 +0000257 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;
TsiChungLiew52b01762007-07-05 23:36:16 -0500266 timestamp++;
stroesecd42dee2004-12-16 17:56:09 +0000267}
268
TsiChungLiew52b01762007-07-05 23:36:16 -0500269void timer_init(void)
270{
stroesecd42dee2004-12-16 17:56:09 +0000271 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 */
TsiChungLiew52b01762007-07-05 23:36:16 -0500279 irq_install_handler(31, mcf_timer_interrupt, 0);
stroesecd42dee2004-12-16 17:56:09 +0000280 mbar_writeLong(MCFSIM_IMR, mbar_readLong(MCFSIM_IMR) & ~0x00000400);
TsiChungLiew52b01762007-07-05 23:36:16 -0500281 mbar_writeByte(MCFSIM_TIMER2ICR,
282 MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 |
283 MCFSIM_ICR_PRI3);
stroesecd42dee2004-12-16 17:56:09 +0000284
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 */
TsiChungLiew52b01762007-07-05 23:36:16 -0500289 timerp->timer_tmr =
290 (((CFG_CLK / 2000000) -
291 1) << 8) | MCFTIMER_TMR_CLK1 | MCFTIMER_TMR_RESTART |
292 MCFTIMER_TMR_ENORI | MCFTIMER_TMR_ENABLE;
stroesecd42dee2004-12-16 17:56:09 +0000293}
294
TsiChungLiew52b01762007-07-05 23:36:16 -0500295void reset_timer(void)
stroesecd42dee2004-12-16 17:56:09 +0000296{
297 timestamp = 0;
298}
299
TsiChungLiew52b01762007-07-05 23:36:16 -0500300ulong get_timer(ulong base)
stroesecd42dee2004-12-16 17:56:09 +0000301{
302 return (timestamp - base);
303}
304
TsiChungLiew52b01762007-07-05 23:36:16 -0500305void set_timer(ulong t)
stroesecd42dee2004-12-16 17:56:09 +0000306{
307 timestamp = t;
308}
309#endif
310
TsiChung Liew8e585f02007-06-18 13:50:13 -0500311#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
TsiChungLiew52b01762007-07-05 23:36:16 -0500319extern void dtimer_intr_setup(void);
TsiChung Liew8e585f02007-06-18 13:50:13 -0500320
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 =
TsiChungLiew52b01762007-07-05 23:36:16 -0500338 CFG_TIMER_PRESCALER | DTIM_DTMR_CLK_DIV1 | DTIM_DTMR_FRR |
339 DTIM_DTMR_RST_EN;
TsiChung Liew8e585f02007-06-18 13:50:13 -0500340
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);
TsiChung Liew8e585f02007-06-18 13:50:13 -0500363
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
TsiChungLiew52b01762007-07-05 23:36:16 -0500372 /* initialize and enable timer interrupt */
TsiChung Liew8e585f02007-06-18 13:50:13 -0500373 irq_install_handler(CFG_TMRINTR_NO, dtimer_interrupt, 0);
TsiChung Liew8e585f02007-06-18 13:50:13 -0500374
375 timerp->tcn = 0;
376 timerp->trr = 1000; /* Interrupt every ms */
377
TsiChungLiew52b01762007-07-05 23:36:16 -0500378 dtimer_intr_setup();
TsiChung Liew8e585f02007-06-18 13:50:13 -0500379
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 */
stroesecd42dee2004-12-16 17:56:09 +0000469
wdenk70f05ac2004-06-09 15:24:18 +0000470/*
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 */
TsiChungLiew52b01762007-07-05 23:36:16 -0500483ulong get_tbclk(void)
wdenk70f05ac2004-06-09 15:24:18 +0000484{
485 ulong tbclk;
486 tbclk = CFG_HZ;
487 return tbclk;
488}