]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Library/ArmArchTimerLib/ArmArchTimerLib.c
ArmPkg: Apply uncrustify changes
[mirror_edk2.git] / ArmPkg / Library / ArmArchTimerLib / ArmArchTimerLib.c
CommitLineData
da9675a2 1/** @file\r
2 Generic ARM implementation of TimerLib.h\r
3\r
0fc54a6a 4 Copyright (c) 2011 - 2021, Arm Limited. All rights reserved.<BR>\r
27331bff 5\r
4059386c 6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
da9675a2 7\r
8**/\r
9\r
da9675a2 10#include <Base.h>\r
168d7245 11#include <Library/ArmLib.h>\r
da9675a2 12#include <Library/BaseLib.h>\r
13#include <Library/TimerLib.h>\r
14#include <Library/DebugLib.h>\r
15#include <Library/PcdLib.h>\r
4f6d34b4 16#include <Library/ArmGenericTimerCounterLib.h>\r
da9675a2 17\r
429309e0 18#define TICKS_PER_MICRO_SEC (PcdGet32 (PcdArmArchTimerFreqInHz)/1000000U)\r
da9675a2 19\r
cbdece17
SM
20// Select appropriate multiply function for platform architecture.\r
21#ifdef MDE_CPU_ARM\r
429309e0 22#define MULT_U64_X_N MultU64x32\r
cbdece17 23#else\r
429309e0 24#define MULT_U64_X_N MultU64x64\r
cbdece17
SM
25#endif\r
26\r
da9675a2 27RETURN_STATUS\r
28EFIAPI\r
31d196c1 29TimerConstructor (\r
da9675a2 30 VOID\r
31 )\r
32{\r
074a67fc
LE
33 //\r
34 // Check if the ARM Generic Timer Extension is implemented.\r
35 //\r
da9675a2 36 if (ArmIsArchTimerImplemented ()) {\r
074a67fc 37 //\r
16b7aff0
LE
38 // Check if Architectural Timer frequency is pre-determined by the platform\r
39 // (ie. nonzero).\r
074a67fc 40 //\r
16b7aff0
LE
41 if (PcdGet32 (PcdArmArchTimerFreqInHz) != 0) {\r
42 //\r
43 // Check if ticks/uS is not 0. The Architectural timer runs at constant\r
f75cda77 44 // frequency, irrespective of CPU frequency. According to Generic Timer\r
16b7aff0
LE
45 // Ref manual, lower bound of the frequency is in the range of 1-10MHz.\r
46 //\r
47 ASSERT (TICKS_PER_MICRO_SEC);\r
da9675a2 48\r
429309e0 49 #ifdef MDE_CPU_ARM\r
16b7aff0
LE
50 //\r
51 // Only set the frequency for ARMv7. We expect the secure firmware to\r
52 // have already done it.\r
53 // If the security extension is not implemented, set Timer Frequency\r
54 // here.\r
55 //\r
0dd0d42a 56 if (ArmHasSecurityExtensions ()) {\r
16b7aff0
LE
57 ArmGenericTimerSetTimerFreq (PcdGet32 (PcdArmArchTimerFreqInHz));\r
58 }\r
429309e0
MK
59\r
60 #endif\r
16b7aff0 61 }\r
da9675a2 62\r
074a67fc 63 //\r
f75cda77 64 // Architectural Timer Frequency must be set in Secure privileged\r
074a67fc
LE
65 // mode (if secure extension is supported).\r
66 // If the reset value (0) is returned, just ASSERT.\r
67 //\r
b843b373 68 ASSERT (ArmGenericTimerGetTimerFreq () != 0);\r
da9675a2 69 } else {\r
a4a582e1 70 DEBUG ((DEBUG_ERROR, "ARM Architectural Timer is not available in the CPU, hence this library cannot be used.\n"));\r
da9675a2 71 ASSERT (0);\r
72 }\r
73\r
74 return RETURN_SUCCESS;\r
75}\r
76\r
cbdece17
SM
77/**\r
78 A local utility function that returns the PCD value, if specified.\r
79 Otherwise it defaults to ArmGenericTimerGetTimerFreq.\r
80\r
81 @return The timer frequency.\r
82\r
83**/\r
84STATIC\r
85UINTN\r
86EFIAPI\r
87GetPlatformTimerFreq (\r
88 )\r
89{\r
429309e0 90 UINTN TimerFreq;\r
cbdece17
SM
91\r
92 TimerFreq = PcdGet32 (PcdArmArchTimerFreqInHz);\r
93 if (TimerFreq == 0) {\r
94 TimerFreq = ArmGenericTimerGetTimerFreq ();\r
95 }\r
429309e0 96\r
cbdece17
SM
97 return TimerFreq;\r
98}\r
99\r
da9675a2 100/**\r
101 Stalls the CPU for the number of microseconds specified by MicroSeconds.\r
102\r
103 @param MicroSeconds The minimum number of microseconds to delay.\r
104\r
f75cda77 105 @return The value of MicroSeconds input.\r
da9675a2 106\r
107**/\r
108UINTN\r
109EFIAPI\r
110MicroSecondDelay (\r
429309e0 111 IN UINTN MicroSeconds\r
da9675a2 112 )\r
113{\r
429309e0
MK
114 UINT64 TimerTicks64;\r
115 UINT64 SystemCounterVal;\r
da9675a2 116\r
f75cda77 117 // Calculate counter ticks that represent requested delay:\r
33292af5
OM
118 // = MicroSeconds x TICKS_PER_MICRO_SEC\r
119 // = MicroSeconds x Frequency.10^-6\r
b36bc5af 120 TimerTicks64 = DivU64x32 (\r
0fc54a6a 121 MULT_U64_X_N (\r
b36bc5af 122 MicroSeconds,\r
cbdece17 123 GetPlatformTimerFreq ()\r
b36bc5af
LE
124 ),\r
125 1000000U\r
126 );\r
da9675a2 127\r
128 // Read System Counter value\r
4f6d34b4 129 SystemCounterVal = ArmGenericTimerGetSystemCount ();\r
da9675a2 130\r
131 TimerTicks64 += SystemCounterVal;\r
132\r
f75cda77 133 // Wait until delay count expires.\r
da9675a2 134 while (SystemCounterVal < TimerTicks64) {\r
4f6d34b4 135 SystemCounterVal = ArmGenericTimerGetSystemCount ();\r
da9675a2 136 }\r
137\r
138 return MicroSeconds;\r
139}\r
140\r
da9675a2 141/**\r
142 Stalls the CPU for at least the given number of nanoseconds.\r
143\r
144 Stalls the CPU for the number of nanoseconds specified by NanoSeconds.\r
145\r
146 When the timer frequency is 1MHz, each tick corresponds to 1 microsecond.\r
147 Therefore, the nanosecond delay will be rounded up to the nearest 1 microsecond.\r
148\r
149 @param NanoSeconds The minimum number of nanoseconds to delay.\r
150\r
ff5fef14 151 @return The value of NanoSeconds inputted.\r
da9675a2 152\r
153**/\r
154UINTN\r
155EFIAPI\r
156NanoSecondDelay (\r
429309e0 157 IN UINTN NanoSeconds\r
da9675a2 158 )\r
159{\r
160 UINTN MicroSeconds;\r
161\r
162 // Round up to 1us Tick Number\r
429309e0 163 MicroSeconds = NanoSeconds / 1000;\r
da9675a2 164 MicroSeconds += ((NanoSeconds % 1000) == 0) ? 0 : 1;\r
165\r
166 MicroSecondDelay (MicroSeconds);\r
167\r
168 return NanoSeconds;\r
169}\r
170\r
171/**\r
172 Retrieves the current value of a 64-bit free running performance counter.\r
173\r
174 The counter can either count up by 1 or count down by 1. If the physical\r
175 performance counter counts by a larger increment, then the counter values\r
176 must be translated. The properties of the counter can be retrieved from\r
177 GetPerformanceCounterProperties().\r
178\r
179 @return The current value of the free running performance counter.\r
180\r
181**/\r
182UINT64\r
183EFIAPI\r
184GetPerformanceCounter (\r
185 VOID\r
186 )\r
187{\r
188 // Just return the value of system count\r
4f6d34b4 189 return ArmGenericTimerGetSystemCount ();\r
da9675a2 190}\r
191\r
192/**\r
193 Retrieves the 64-bit frequency in Hz and the range of performance counter\r
194 values.\r
195\r
196 If StartValue is not NULL, then the value that the performance counter starts\r
197 with immediately after is it rolls over is returned in StartValue. If\r
198 EndValue is not NULL, then the value that the performance counter end with\r
199 immediately before it rolls over is returned in EndValue. The 64-bit\r
200 frequency of the performance counter in Hz is always returned. If StartValue\r
201 is less than EndValue, then the performance counter counts up. If StartValue\r
202 is greater than EndValue, then the performance counter counts down. For\r
203 example, a 64-bit free running counter that counts up would have a StartValue\r
204 of 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running counter\r
205 that counts down would have a StartValue of 0xFFFFFF and an EndValue of 0.\r
206\r
207 @param StartValue The value the performance counter starts with when it\r
208 rolls over.\r
209 @param EndValue The value that the performance counter ends with before\r
210 it rolls over.\r
211\r
212 @return The frequency in Hz.\r
213\r
214**/\r
215UINT64\r
216EFIAPI\r
217GetPerformanceCounterProperties (\r
429309e0
MK
218 OUT UINT64 *StartValue OPTIONAL,\r
219 OUT UINT64 *EndValue OPTIONAL\r
da9675a2 220 )\r
221{\r
222 if (StartValue != NULL) {\r
f75cda77 223 // Timer starts at 0\r
429309e0 224 *StartValue = (UINT64)0ULL;\r
da9675a2 225 }\r
226\r
227 if (EndValue != NULL) {\r
f75cda77 228 // Timer counts up.\r
89bbce11 229 *EndValue = 0xFFFFFFFFFFFFFFFFUL;\r
da9675a2 230 }\r
231\r
4f6d34b4 232 return (UINT64)ArmGenericTimerGetTimerFreq ();\r
da9675a2 233}\r
96a80ae3
SM
234\r
235/**\r
236 Converts elapsed ticks of performance counter to time in nanoseconds.\r
237\r
238 This function converts the elapsed ticks of running performance counter to\r
239 time value in unit of nanoseconds.\r
240\r
241 @param Ticks The number of elapsed ticks of running performance counter.\r
242\r
243 @return The elapsed time in nanoseconds.\r
244\r
245**/\r
246UINT64\r
247EFIAPI\r
248GetTimeInNanoSecond (\r
429309e0 249 IN UINT64 Ticks\r
96a80ae3
SM
250 )\r
251{\r
252 UINT64 NanoSeconds;\r
253 UINT32 Remainder;\r
254 UINT32 TimerFreq;\r
255\r
256 TimerFreq = GetPlatformTimerFreq ();\r
257 //\r
258 // Ticks\r
259 // Time = --------- x 1,000,000,000\r
260 // Frequency\r
261 //\r
0fc54a6a 262 NanoSeconds = MULT_U64_X_N (\r
96a80ae3
SM
263 DivU64x32Remainder (\r
264 Ticks,\r
265 TimerFreq,\r
429309e0
MK
266 &Remainder\r
267 ),\r
96a80ae3
SM
268 1000000000U\r
269 );\r
270\r
271 //\r
272 // Frequency < 0x100000000, so Remainder < 0x100000000, then (Remainder * 1,000,000,000)\r
273 // will not overflow 64-bit.\r
274 //\r
275 NanoSeconds += DivU64x32 (\r
0fc54a6a 276 MULT_U64_X_N (\r
429309e0
MK
277 (UINT64)Remainder,\r
278 1000000000U\r
279 ),\r
96a80ae3
SM
280 TimerFreq\r
281 );\r
282\r
283 return NanoSeconds;\r
284}\r