Merge branch 'master' into u-boot-5329-early
[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 static ulong timestamp;
52 #if defined(CONFIG_M5282) || defined(CONFIG_M5271)
53 static unsigned short lastinc;
54 #endif
55
56 #if defined(CONFIG_M5272)
57 /*
58  * We use timer 3 which is running with a period of 1 us
59  */
60 void udelay(unsigned long usec)
61 {
62         volatile timer_t *timerp = (timer_t *) (CFG_MBAR + MCFTIMER_BASE3);
63         uint start, now, tmp;
64
65         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 */
76                 timerp->timer_tmr =
77                     (((CFG_CLK / 1000000) -
78                       1) << 8) | MCFTIMER_TMR_CLK1 | MCFTIMER_TMR_FREERUN |
79                     MCFTIMER_TMR_ENABLE;
80
81                 start = now = timerp->timer_tcn;
82                 while (now < start + tmp)
83                         now = timerp->timer_tcn;
84         }
85 }
86
87 void mcf_timer_interrupt(void *not_used)
88 {
89         volatile timer_t *timerp = (timer_t *) (CFG_MBAR + MCFTIMER_BASE4);
90         volatile intctrl_t *intp = (intctrl_t *) (CFG_MBAR + MCFSIM_ICR1);
91
92         /* 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;
99         timestamp++;
100 }
101
102 void timer_init(void)
103 {
104         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 */
113         irq_install_handler(72, mcf_timer_interrupt, 0);
114         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 */
119         timerp->timer_tmr =
120             (((CFG_CLK / 1000000) -
121               1) << 8) | MCFTIMER_TMR_CLK1 | MCFTIMER_TMR_RESTART |
122             MCFTIMER_TMR_ENORI | MCFTIMER_TMR_ENABLE;
123 }
124
125 void reset_timer(void)
126 {
127         timestamp = 0;
128 }
129
130 ulong get_timer(ulong base)
131 {
132         return (timestamp - base);
133 }
134
135 void set_timer(ulong t)
136 {
137         timestamp = t;
138 }
139 #endif
140
141 #if defined(CONFIG_M5282) || defined(CONFIG_M5271)
142
143 void udelay(unsigned long usec)
144 {
145         volatile unsigned short *timerp;
146         uint tmp;
147
148         timerp = (volatile unsigned short *)(CFG_MBAR + MCFTIMER_BASE3);
149
150         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] =
162 #ifdef CONFIG_M5271
163                     (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 */
167
168                 timerp[MCFTIMER_PMR] = tmp;
169                 while (timerp[MCFTIMER_PCNTR] > 0) ;
170         }
171 }
172
173 void timer_init(void)
174 {
175         volatile unsigned short *timerp;
176
177         timerp = (volatile unsigned short *)(CFG_MBAR + MCFTIMER_BASE4);
178         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] =
184 #ifdef CONFIG_M5271
185             (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 */
189 }
190
191 void set_timer(ulong t)
192 {
193         volatile unsigned short *timerp;
194
195         timerp = (volatile unsigned short *)(CFG_MBAR + MCFTIMER_BASE4);
196         timestamp = 0;
197         timerp[MCFTIMER_PMR] = lastinc = 0;
198 }
199
200 ulong get_timer(ulong base)
201 {
202         unsigned short now, diff;
203         volatile unsigned short *timerp;
204
205         timerp = (volatile unsigned short *)(CFG_MBAR + MCFTIMER_BASE4);
206         now = timerp[MCFTIMER_PCNTR];
207         diff = -(now - lastinc);
208
209         timestamp += diff;
210         lastinc = now;
211         return timestamp - base;
212 }
213
214 void wait_ticks(unsigned long ticks)
215 {
216         set_timer(0);
217         while (get_timer(0) < ticks) ;
218 }
219 #endif
220
221 #if defined(CONFIG_M5249)
222 /*
223  * We use timer 1 which is running with a period of 1 us
224  */
225 void 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 */
242                 timerp->timer_tmr =
243                     (((CFG_CLK / 2000000) -
244                       1) << 8) | MCFTIMER_TMR_CLK1 | MCFTIMER_TMR_FREERUN |
245                     MCFTIMER_TMR_ENABLE;
246
247                 start = now = timerp->timer_tcn;
248                 while (now < start + tmp)
249                         now = timerp->timer_tcn;
250         }
251 }
252
253 void mcf_timer_interrupt(void *not_used)
254 {
255         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;
264         timestamp++;
265 }
266
267 void timer_init(void)
268 {
269         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 */
277         irq_install_handler(31, mcf_timer_interrupt, 0);
278         mbar_writeLong(MCFSIM_IMR, mbar_readLong(MCFSIM_IMR) & ~0x00000400);
279         mbar_writeByte(MCFSIM_TIMER2ICR,
280                        MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 |
281                        MCFSIM_ICR_PRI3);
282
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 */
287         timerp->timer_tmr =
288             (((CFG_CLK / 2000000) -
289               1) << 8) | MCFTIMER_TMR_CLK1 | MCFTIMER_TMR_RESTART |
290             MCFTIMER_TMR_ENORI | MCFTIMER_TMR_ENABLE;
291 }
292
293 void reset_timer(void)
294 {
295         timestamp = 0;
296 }
297
298 ulong get_timer(ulong base)
299 {
300         return (timestamp - base);
301 }
302
303 void set_timer(ulong t)
304 {
305         timestamp = t;
306 }
307 #endif
308
309 #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
317 extern void dtimer_intr_setup(void);
318
319 void 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 =
336                     CFG_TIMER_PRESCALER | DTIM_DTMR_CLK_DIV1 | DTIM_DTMR_FRR |
337                     DTIM_DTMR_RST_EN;
338
339                 start = now = timerp->tcn;
340                 while (now < start + tmp)
341                         now = timerp->tcn;
342         }
343 }
344
345 void 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
358 void timer_init(void)
359 {
360         volatile dtmr_t *timerp = (dtmr_t *) (CFG_TMR_BASE);
361
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
370         /* initialize and enable timer interrupt */
371         irq_install_handler(CFG_TMRINTR_NO, dtimer_interrupt, 0);
372
373         timerp->tcn = 0;
374         timerp->trr = 1000;     /* Interrupt every ms */
375
376         dtimer_intr_setup();
377
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
383 void reset_timer(void)
384 {
385         timestamp = 0;
386 }
387
388 ulong get_timer(ulong base)
389 {
390         return (timestamp - base);
391 }
392
393 void 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
404 static unsigned short lastinc;
405
406 void 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
429 void 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
440 void 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
448 ulong 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
461 void wait_ticks(unsigned long ticks)
462 {
463         set_timer(0);
464         while (get_timer(0) < ticks) ;
465 }
466 #endif                          /* CONFIG_MCFPIT */
467
468 /*
469  * This function is derived from PowerPC code (read timebase as long long).
470  * On M68K it just returns the timer value.
471  */
472 unsigned 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  */
481 ulong get_tbclk(void)
482 {
483         ulong tbclk;
484         tbclk = CFG_HZ;
485         return tbclk;
486 }