]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - cpu/arm920t/ep93xx/timer.c
98c759c8f0a5ba3b4e5f43996ee8c86e3249f5af
[karo-tx-uboot.git] / cpu / arm920t / ep93xx / timer.c
1 /*
2  * Cirrus Logic EP93xx timer support.
3  *
4  * Copyright (C) 2009, 2010
5  * Matthias Kaehlcke <matthias@kaehlcke.net>
6  *
7  * Copyright (C) 2004, 2005
8  * Cory T. Tusar, Videon Central, Inc., <ctusar@videon-central.com>
9  *
10  * Based on the original intr.c Cirrus Logic EP93xx Rev D. interrupt support,
11  * author unknown.
12  *
13  * See file CREDITS for list of people who contributed to this project.
14  *
15  * This program is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation; either version 2 of the License, or
18  * (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful, but
21  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
22  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23  * for more details.
24  *
25  * You should have received a copy of the GNU General Public License along
26  * with this program; if not, write to the Free Software Foundation, Inc.,
27  * 675 Mass Ave, Cambridge, MA 02139, USA.
28  */
29
30 #include <common.h>
31 #include <linux/types.h>
32 #include <asm/arch/ep93xx.h>
33 #include <asm/io.h>
34 #include <div64.h>
35
36 #define TIMER_CLKSEL    (1 << 3)
37 #define TIMER_MODE      (1 << 6)
38 #define TIMER_ENABLE    (1 << 7)
39
40 #define TIMER_FREQ      508469
41 #define TIMER_LOAD_VAL  (TIMER_FREQ / CONFIG_SYS_HZ)
42
43 static ulong timestamp;
44 static ulong lastdec;
45
46 static inline unsigned long clk_to_systicks(unsigned long clk_ticks)
47 {
48         unsigned long long sys_ticks = (clk_ticks * CONFIG_SYS_HZ);
49         do_div(sys_ticks, TIMER_FREQ);
50
51         return (unsigned long)sys_ticks;
52 }
53
54 static inline unsigned long usecs_to_ticks(unsigned long usecs)
55 {
56         unsigned long ticks;
57
58         if (usecs >= 1000) {
59                 ticks = usecs / 1000;
60                 ticks *= (TIMER_LOAD_VAL * CONFIG_SYS_HZ);
61                 ticks /= 1000;
62         } else {
63                 ticks = usecs * TIMER_LOAD_VAL * CONFIG_SYS_HZ;
64                 ticks /= (1000 * 1000);
65         }
66
67         return ticks;
68 }
69
70 static inline unsigned long read_timer(void)
71 {
72         struct timer_regs *timer = (struct timer_regs *)TIMER_BASE;
73
74         return readl(&timer->timer3.value);
75 }
76
77 /*
78  * timer without interrupts
79  */
80 unsigned long long get_ticks(void)
81 {
82         const unsigned long now = read_timer();
83
84         if (lastdec >= now) {
85                 /* normal mode */
86                 timestamp += lastdec - now;
87         } else {
88                 /* we have an overflow ... */
89                 timestamp += lastdec + TIMER_LOAD_VAL - now;
90         }
91
92         lastdec = now;
93
94         return timestamp;
95 }
96
97 unsigned long get_timer_masked(void)
98 {
99         return clk_to_systicks(get_ticks());
100 }
101
102 unsigned long get_timer(unsigned long base)
103 {
104         return get_timer_masked() - base;
105 }
106
107 void reset_timer_masked(void)
108 {
109         lastdec = read_timer();
110         timestamp = 0;
111 }
112
113 void reset_timer(void)
114 {
115         reset_timer_masked();
116 }
117
118 void set_timer(unsigned long t)
119 {
120         timestamp = t;
121 }
122
123 void __udelay(unsigned long usec)
124 {
125         const unsigned long ticks = usecs_to_ticks(usec);
126         const unsigned long target = clk_to_systicks(ticks) + get_timer(0);
127
128         while (get_timer_masked() < target)
129                 /* noop */;
130 }
131
132 void udelay_masked(unsigned long usec)
133 {
134         const unsigned long ticks = usecs_to_ticks(usec);
135         const unsigned long target = clk_to_systicks(ticks) + get_timer(0);
136
137         reset_timer_masked();
138
139         while (get_timer_masked() < target)
140                 /* noop */;
141 }
142
143 int timer_init(void)
144 {
145         struct timer_regs *timer = (struct timer_regs *)TIMER_BASE;
146
147         /* use timer 3 with 508KHz and free running */
148         writel(TIMER_CLKSEL, &timer->timer3.control);
149
150         /* auto load, manual update of Timer 3 */
151         lastdec = TIMER_LOAD_VAL;
152         writel(TIMER_LOAD_VAL, &timer->timer3.load);
153
154         /* Enable the timer and periodic mode */
155         writel(TIMER_ENABLE | TIMER_MODE | TIMER_CLKSEL,
156                 &timer->timer3.control);
157
158         reset_timer_masked();
159
160         return 0;
161 }
162
163 /*
164  * This function is derived from PowerPC code (timebase clock frequency).
165  * On ARM it returns the number of timer ticks per second.
166  */
167 unsigned long get_tbclk(void)
168 {
169         return CONFIG_SYS_HZ;
170 }