]>
Commit | Line | Data |
---|---|---|
f54851a6 JCPV |
1 | /* |
2 | * (C) Copyright 2002 | |
3 | * Sysgo Real-Time Solutions, GmbH <www.elinos.com> | |
4 | * Marius Groeger <mgroeger@sysgo.de> | |
5 | * | |
6 | * (C) Copyright 2002 | |
7 | * David Mueller, ELSOFT AG, <d.mueller@elsoft.ch> | |
8 | * | |
9 | * (C) Copyright 2003 | |
10 | * Texas Instruments, <www.ti.com> | |
11 | * Kshitij Gupta <Kshitij@ti.com> | |
12 | * | |
13 | * (C) Copyright 2004 | |
14 | * ARM Ltd. | |
15 | * Philippe Robin, <philippe.robin@arm.com> | |
16 | * | |
3765b3e7 | 17 | * SPDX-License-Identifier: GPL-2.0+ |
f54851a6 JCPV |
18 | */ |
19 | ||
20 | #include <common.h> | |
21 | #include <div64.h> | |
22 | ||
576afd4f JCPV |
23 | #ifdef CONFIG_ARCH_CINTEGRATOR |
24 | #define DIV_CLOCK_INIT 1 | |
25 | #define TIMER_LOAD_VAL 0xFFFFFFFFL | |
26 | #else | |
27 | #define DIV_CLOCK_INIT 256 | |
28 | #define TIMER_LOAD_VAL 0x0000FFFFL | |
29 | #endif | |
f54851a6 JCPV |
30 | /* The Integrator/CP timer1 is clocked at 1MHz |
31 | * can be divided by 16 or 256 | |
32 | * and can be set up as a 32-bit timer | |
33 | */ | |
34 | /* U-Boot expects a 32 bit timer, running at CONFIG_SYS_HZ */ | |
35 | /* Keep total timer count to avoid losing decrements < div_timer */ | |
36 | static unsigned long long total_count = 0; | |
37 | static unsigned long long lastdec; /* Timer reading at last call */ | |
576afd4f JCPV |
38 | /* Divisor applied to timer clock */ |
39 | static unsigned long long div_clock = DIV_CLOCK_INIT; | |
f54851a6 JCPV |
40 | static unsigned long long div_timer = 1; /* Divisor to convert timer reading |
41 | * change to U-Boot ticks | |
42 | */ | |
43 | /* CONFIG_SYS_HZ = CONFIG_SYS_HZ_CLOCK/(div_clock * div_timer) */ | |
576afd4f | 44 | static ulong timestamp; /* U-Boot ticks since startup */ |
f54851a6 | 45 | |
f54851a6 JCPV |
46 | #define READ_TIMER (*(volatile ulong *)(CONFIG_SYS_TIMERBASE+4)) |
47 | ||
48 | /* all function return values in U-Boot ticks i.e. (1/CONFIG_SYS_HZ) sec | |
49 | * - unless otherwise stated | |
50 | */ | |
51 | ||
52 | /* starts up a counter | |
53 | * - the Integrator/CP timer can be set up to issue an interrupt */ | |
54 | int timer_init (void) | |
55 | { | |
56 | /* Load timer with initial value */ | |
57 | *(volatile ulong *)(CONFIG_SYS_TIMERBASE + 0) = TIMER_LOAD_VAL; | |
576afd4f | 58 | #ifdef CONFIG_ARCH_CINTEGRATOR |
f54851a6 | 59 | /* Set timer to be |
576afd4f JCPV |
60 | * enabled 1 |
61 | * periodic 1 | |
62 | * no interrupts 0 | |
63 | * X 0 | |
64 | * divider 1 00 == less rounding error | |
65 | * 32 bit 1 | |
66 | * wrapping 0 | |
f54851a6 JCPV |
67 | */ |
68 | *(volatile ulong *)(CONFIG_SYS_TIMERBASE + 8) = 0x000000C2; | |
576afd4f JCPV |
69 | #else |
70 | /* Set timer to be | |
71 | * enabled 1 | |
72 | * free-running 0 | |
73 | * XX 00 | |
74 | * divider 256 10 | |
75 | * XX 00 | |
76 | */ | |
77 | *(volatile ulong *)(CONFIG_SYS_TIMERBASE + 8) = 0x00000088; | |
78 | #endif | |
79 | ||
f54851a6 JCPV |
80 | /* init the timestamp */ |
81 | total_count = 0ULL; | |
17659d7d GR |
82 | /* capure current decrementer value */ |
83 | lastdec = READ_TIMER; | |
84 | /* start "advancing" time stamp from 0 */ | |
85 | timestamp = 0L; | |
f54851a6 | 86 | |
576afd4f JCPV |
87 | div_timer = CONFIG_SYS_HZ_CLOCK; |
88 | do_div(div_timer, CONFIG_SYS_HZ); | |
89 | do_div(div_timer, div_clock); | |
f54851a6 JCPV |
90 | |
91 | return (0); | |
92 | } | |
93 | ||
94 | /* | |
95 | * timer without interrupts | |
96 | */ | |
f54851a6 JCPV |
97 | ulong get_timer (ulong base_ticks) |
98 | { | |
99 | return get_timer_masked () - base_ticks; | |
100 | } | |
101 | ||
f54851a6 | 102 | /* delay usec useconds */ |
3eb90bad | 103 | void __udelay (unsigned long usec) |
f54851a6 JCPV |
104 | { |
105 | ulong tmo, tmp; | |
106 | ||
107 | /* Convert to U-Boot ticks */ | |
108 | tmo = usec * CONFIG_SYS_HZ; | |
109 | tmo /= (1000000L); | |
110 | ||
111 | tmp = get_timer_masked(); /* get current timestamp */ | |
112 | tmo += tmp; /* form target timestamp */ | |
113 | ||
114 | while (get_timer_masked () < tmo) {/* loop till event */ | |
115 | /*NOP*/; | |
116 | } | |
117 | } | |
118 | ||
f54851a6 JCPV |
119 | /* converts the timer reading to U-Boot ticks */ |
120 | /* the timestamp is the number of ticks since reset */ | |
121 | ulong get_timer_masked (void) | |
122 | { | |
123 | /* get current count */ | |
576afd4f | 124 | unsigned long long now = READ_TIMER; |
f54851a6 JCPV |
125 | |
126 | if(now > lastdec) { | |
127 | /* Must have wrapped */ | |
128 | total_count += lastdec + TIMER_LOAD_VAL + 1 - now; | |
129 | } else { | |
130 | total_count += lastdec - now; | |
131 | } | |
576afd4f | 132 | lastdec = now; |
f54851a6 JCPV |
133 | |
134 | /* Reuse "now" */ | |
135 | now = total_count; | |
136 | do_div(now, div_timer); | |
137 | timestamp = now; | |
138 | ||
139 | return timestamp; | |
140 | } | |
141 | ||
142 | /* waits specified delay value and resets timestamp */ | |
143 | void udelay_masked (unsigned long usec) | |
144 | { | |
145 | udelay(usec); | |
146 | } | |
147 | ||
148 | /* | |
149 | * This function is derived from PowerPC code (read timebase as long long). | |
150 | * On ARM it just returns the timer value. | |
151 | */ | |
152 | unsigned long long get_ticks(void) | |
153 | { | |
576afd4f | 154 | return get_timer(0); |
f54851a6 JCPV |
155 | } |
156 | ||
157 | /* | |
158 | * Return the timebase clock frequency | |
159 | * i.e. how often the timer decrements | |
160 | */ | |
161 | ulong get_tbclk (void) | |
162 | { | |
576afd4f JCPV |
163 | unsigned long long tmp = CONFIG_SYS_HZ_CLOCK; |
164 | ||
165 | do_div(tmp, div_clock); | |
166 | ||
167 | return tmp; | |
f54851a6 | 168 | } |