blob: 6c19059e62b3beea61b1e72b03b230ee60a53745 [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);
TsiChung Liew8e585f02007-06-18 13:50:13 -0500350
351 /* check for timer interrupt asserted */
TsiChungLiewab77bc52007-08-15 15:39:17 -0500352 if ((CFG_TMRPND_REG & CFG_TMRINTR_MASK) == CFG_TMRINTR_PEND) {
TsiChung Liew8e585f02007-06-18 13:50:13 -0500353 timerp->ter = (DTIM_DTER_CAP | DTIM_DTER_REF);
354 timestamp++;
355 return;
356 }
357}
358
359void timer_init(void)
360{
361 volatile dtmr_t *timerp = (dtmr_t *) (CFG_TMR_BASE);
TsiChung Liew8e585f02007-06-18 13:50:13 -0500362
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
TsiChungLiew52b01762007-07-05 23:36:16 -0500371 /* initialize and enable timer interrupt */
TsiChung Liew8e585f02007-06-18 13:50:13 -0500372 irq_install_handler(CFG_TMRINTR_NO, dtimer_interrupt, 0);
TsiChung Liew8e585f02007-06-18 13:50:13 -0500373
374 timerp->tcn = 0;
375 timerp->trr = 1000; /* Interrupt every ms */
376
TsiChungLiew52b01762007-07-05 23:36:16 -0500377 dtimer_intr_setup();
TsiChung Liew8e585f02007-06-18 13:50:13 -0500378
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
384void reset_timer(void)
385{
386 timestamp = 0;
387}
388
389ulong get_timer(ulong base)
390{
391 return (timestamp - base);
392}
393
394void 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
405static unsigned short lastinc;
406
407void 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
430void 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
441void 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
449ulong 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
462void wait_ticks(unsigned long ticks)
463{
464 set_timer(0);
465 while (get_timer(0) < ticks) ;
466}
467#endif /* CONFIG_MCFPIT */
stroesecd42dee2004-12-16 17:56:09 +0000468
wdenk70f05ac2004-06-09 15:24:18 +0000469/*
470 * This function is derived from PowerPC code (read timebase as long long).
471 * On M68K it just returns the timer value.
472 */
473unsigned 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 */
TsiChungLiew52b01762007-07-05 23:36:16 -0500482ulong get_tbclk(void)
wdenk70f05ac2004-06-09 15:24:18 +0000483{
484 ulong tbclk;
485 tbclk = CFG_HZ;
486 return tbclk;
487}