TianoCore EDK2 master
ArmArchTimerLib.c
Go to the documentation of this file.
1
10#include <Base.h>
11#include <Library/ArmLib.h>
12#include <Library/BaseLib.h>
13#include <Library/TimerLib.h>
14#include <Library/DebugLib.h>
15#include <Library/PcdLib.h>
17
18#define TICKS_PER_MICRO_SEC (PcdGet32 (PcdArmArchTimerFreqInHz)/1000000U)
19
20// Select appropriate multiply function for platform architecture.
21#ifdef MDE_CPU_ARM
22#define MULT_U64_X_N MultU64x32
23#else
24#define MULT_U64_X_N MultU64x64
25#endif
26
27RETURN_STATUS
28EFIAPI
29TimerConstructor (
30 VOID
31 )
32{
33 //
34 // Check if the ARM Generic Timer Extension is implemented.
35 //
36 if (ArmIsArchTimerImplemented ()) {
37 //
38 // Check if Architectural Timer frequency is pre-determined by the platform
39 // (ie. nonzero).
40 //
41 if (PcdGet32 (PcdArmArchTimerFreqInHz) != 0) {
42 //
43 // Check if ticks/uS is not 0. The Architectural timer runs at constant
44 // frequency, irrespective of CPU frequency. According to Generic Timer
45 // Ref manual, lower bound of the frequency is in the range of 1-10MHz.
46 //
47 ASSERT (TICKS_PER_MICRO_SEC);
48
49 #ifdef MDE_CPU_ARM
50 //
51 // Only set the frequency for ARMv7. We expect the secure firmware to
52 // have already done it.
53 // If the security extension is not implemented, set Timer Frequency
54 // here.
55 //
57 ArmGenericTimerSetTimerFreq (PcdGet32 (PcdArmArchTimerFreqInHz));
58 }
59
60 #endif
61 }
62
63 //
64 // Architectural Timer Frequency must be set in Secure privileged
65 // mode (if secure extension is supported).
66 // If the reset value (0) is returned, just ASSERT.
67 //
68 ASSERT (ArmGenericTimerGetTimerFreq () != 0);
69 } else {
70 DEBUG ((DEBUG_ERROR, "ARM Architectural Timer is not available in the CPU, hence this library cannot be used.\n"));
71 ASSERT (0);
72 }
73
74 return RETURN_SUCCESS;
75}
76
86EFIAPI
88 )
89{
90 UINTN TimerFreq;
91
92 TimerFreq = PcdGet32 (PcdArmArchTimerFreqInHz);
93 if (TimerFreq == 0) {
94 TimerFreq = ArmGenericTimerGetTimerFreq ();
95 }
96
97 return TimerFreq;
98}
99
108UINTN
109EFIAPI
111 IN UINTN MicroSeconds
112 )
113{
114 UINT64 TimerTicks64;
115 UINT64 SystemCounterVal;
116
117 // Calculate counter ticks that represent requested delay:
118 // = MicroSeconds x TICKS_PER_MICRO_SEC
119 // = MicroSeconds x Frequency.10^-6
120 TimerTicks64 = DivU64x32 (
121 MULT_U64_X_N (
122 MicroSeconds,
124 ),
125 1000000U
126 );
127
128 // Read System Counter value
129 SystemCounterVal = ArmGenericTimerGetSystemCount ();
130
131 TimerTicks64 += SystemCounterVal;
132
133 // Wait until delay count expires.
134 while (SystemCounterVal < TimerTicks64) {
135 SystemCounterVal = ArmGenericTimerGetSystemCount ();
136 }
137
138 return MicroSeconds;
139}
140
154UINTN
155EFIAPI
157 IN UINTN NanoSeconds
158 )
159{
160 UINTN MicroSeconds;
161
162 // Round up to 1us Tick Number
163 MicroSeconds = NanoSeconds / 1000;
164 MicroSeconds += ((NanoSeconds % 1000) == 0) ? 0 : 1;
165
166 MicroSecondDelay (MicroSeconds);
167
168 return NanoSeconds;
169}
170
182UINT64
183EFIAPI
185 VOID
186 )
187{
188 // Just return the value of system count
189 return ArmGenericTimerGetSystemCount ();
190}
191
215UINT64
216EFIAPI
218 OUT UINT64 *StartValue OPTIONAL,
219 OUT UINT64 *EndValue OPTIONAL
220 )
221{
222 if (StartValue != NULL) {
223 // Timer starts at 0
224 *StartValue = (UINT64)0ULL;
225 }
226
227 if (EndValue != NULL) {
228 // Timer counts up.
229 *EndValue = 0xFFFFFFFFFFFFFFFFUL;
230 }
231
232 return (UINT64)ArmGenericTimerGetTimerFreq ();
233}
234
246UINT64
247EFIAPI
249 IN UINT64 Ticks
250 )
251{
252 UINT64 NanoSeconds;
253 UINT32 Remainder;
254 UINT32 TimerFreq;
255
256 TimerFreq = GetPlatformTimerFreq ();
257 //
258 // Ticks
259 // Time = --------- x 1,000,000,000
260 // Frequency
261 //
262 NanoSeconds = MULT_U64_X_N (
264 Ticks,
265 TimerFreq,
266 &Remainder
267 ),
268 1000000000U
269 );
270
271 //
272 // Frequency < 0x100000000, so Remainder < 0x100000000, then (Remainder * 1,000,000,000)
273 // will not overflow 64-bit.
274 //
275 NanoSeconds += DivU64x32 (
276 MULT_U64_X_N (
277 (UINT64)Remainder,
278 1000000000U
279 ),
280 TimerFreq
281 );
282
283 return NanoSeconds;
284}
UINT64 UINTN
UINT64 EFIAPI GetPerformanceCounterProperties(OUT UINT64 *StartValue OPTIONAL, OUT UINT64 *EndValue OPTIONAL)
UINT64 EFIAPI GetTimeInNanoSecond(IN UINT64 Ticks)
STATIC UINTN EFIAPI GetPlatformTimerFreq()
UINT64 EFIAPI GetPerformanceCounter(VOID)
UINTN EFIAPI MicroSecondDelay(IN UINTN MicroSeconds)
UINTN EFIAPI NanoSecondDelay(IN UINTN NanoSeconds)
BOOLEAN EFIAPI ArmHasSecurityExtensions(VOID)
Definition: ArmV7Lib.c:99
#define NULL
Definition: Base.h:312
#define STATIC
Definition: Base.h:264
#define RETURN_SUCCESS
Definition: Base.h:962
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
UINT64 EFIAPI DivU64x32(IN UINT64 Dividend, IN UINT32 Divisor)
Definition: DivU64x32.c:29
UINT64 EFIAPI DivU64x32Remainder(IN UINT64 Dividend, IN UINT32 Divisor, OUT UINT32 *Remainder OPTIONAL)
#define DEBUG(Expression)
Definition: DebugLib.h:417
#define ASSERT(Expression)
Definition: DebugLib.h:391
#define PcdGet32(TokenName)
Definition: PcdLib.h:362