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