]> git.proxmox.com Git - mirror_edk2.git/blame - UefiPayloadPkg/Library/AcpiTimerLib/AcpiTimerLib.c
UefiPayloadPkg: Enhance UEFI payload for coreboot and Slim Bootloader
[mirror_edk2.git] / UefiPayloadPkg / Library / AcpiTimerLib / AcpiTimerLib.c
CommitLineData
04af8bf2
DG
1/** @file\r
2 ACPI Timer implements one instance of Timer Library.\r
3\r
4 Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
6\r
7**/\r
8\r
9#include <PiPei.h>\r
10#include <Library/TimerLib.h>\r
11#include <Library/BaseLib.h>\r
12#include <Library/IoLib.h>\r
13#include <Library/HobLib.h>\r
14#include <Library/DebugLib.h>\r
15\r
16#include <Guid/AcpiBoardInfoGuid.h>\r
17#include <IndustryStandard/Acpi.h>\r
18\r
19#define ACPI_TIMER_COUNT_SIZE BIT24\r
20\r
21UINTN mPmTimerReg = 0;\r
22\r
23/**\r
24 The constructor function enables ACPI IO space.\r
25\r
26 If ACPI I/O space not enabled, this function will enable it.\r
27 It will always return RETURN_SUCCESS.\r
28\r
29 @retval EFI_SUCCESS The constructor always returns RETURN_SUCCESS.\r
30\r
31**/\r
32RETURN_STATUS\r
33EFIAPI\r
34AcpiTimerLibConstructor (\r
35 VOID\r
36 )\r
37{\r
38 EFI_HOB_GUID_TYPE *GuidHob;\r
39 ACPI_BOARD_INFO *pAcpiBoardInfo;\r
40\r
41 //\r
42 // Find the acpi board information guid hob\r
43 //\r
44 GuidHob = GetFirstGuidHob (&gUefiAcpiBoardInfoGuid);\r
45 ASSERT (GuidHob != NULL);\r
46\r
47 pAcpiBoardInfo = (ACPI_BOARD_INFO *)GET_GUID_HOB_DATA (GuidHob);\r
48\r
49 mPmTimerReg = (UINTN)pAcpiBoardInfo->PmTimerRegBase;\r
50\r
51 return EFI_SUCCESS;\r
52}\r
53\r
54/**\r
55 Internal function to read the current tick counter of ACPI.\r
56\r
57 Internal function to read the current tick counter of ACPI.\r
58\r
59 @return The tick counter read.\r
60\r
61**/\r
62UINT32\r
63InternalAcpiGetTimerTick (\r
64 VOID\r
65 )\r
66{\r
67 if (mPmTimerReg == 0) {\r
68 AcpiTimerLibConstructor ();\r
69 }\r
70 return IoRead32 (mPmTimerReg);\r
71}\r
72\r
73/**\r
74 Stalls the CPU for at least the given number of ticks.\r
75\r
76 Stalls the CPU for at least the given number of ticks. It's invoked by\r
77 MicroSecondDelay() and NanoSecondDelay().\r
78\r
79 @param Delay A period of time to delay in ticks.\r
80\r
81**/\r
82VOID\r
83InternalAcpiDelay (\r
84 IN UINT32 Delay\r
85 )\r
86{\r
87 UINT32 Ticks;\r
88 UINT32 Times;\r
89\r
90 Times = Delay >> 22;\r
91 Delay &= BIT22 - 1;\r
92 do {\r
93 //\r
94 // The target timer count is calculated here\r
95 //\r
96 Ticks = InternalAcpiGetTimerTick () + Delay;\r
97 Delay = BIT22;\r
98 //\r
99 // Wait until time out\r
100 // Delay >= 2^23 could not be handled by this function\r
101 // Timer wrap-arounds are handled correctly by this function\r
102 //\r
103 while (((Ticks - InternalAcpiGetTimerTick ()) & BIT23) == 0) {\r
104 CpuPause ();\r
105 }\r
106 } while (Times-- > 0);\r
107}\r
108\r
109/**\r
110 Stalls the CPU for at least the given number of microseconds.\r
111\r
112 Stalls the CPU for the number of microseconds specified by MicroSeconds.\r
113\r
114 @param MicroSeconds The minimum number of microseconds to delay.\r
115\r
116 @return MicroSeconds\r
117\r
118**/\r
119UINTN\r
120EFIAPI\r
121MicroSecondDelay (\r
122 IN UINTN MicroSeconds\r
123 )\r
124{\r
125 InternalAcpiDelay (\r
126 (UINT32)DivU64x32 (\r
127 MultU64x32 (\r
128 MicroSeconds,\r
129 ACPI_TIMER_FREQUENCY\r
130 ),\r
131 1000000u\r
132 )\r
133 );\r
134 return MicroSeconds;\r
135}\r
136\r
137/**\r
138 Stalls the CPU for at least the given number of nanoseconds.\r
139\r
140 Stalls the CPU for the number of nanoseconds specified by NanoSeconds.\r
141\r
142 @param NanoSeconds The minimum number of nanoseconds to delay.\r
143\r
144 @return NanoSeconds\r
145\r
146**/\r
147UINTN\r
148EFIAPI\r
149NanoSecondDelay (\r
150 IN UINTN NanoSeconds\r
151 )\r
152{\r
153 InternalAcpiDelay (\r
154 (UINT32)DivU64x32 (\r
155 MultU64x32 (\r
156 NanoSeconds,\r
157 ACPI_TIMER_FREQUENCY\r
158 ),\r
159 1000000000u\r
160 )\r
161 );\r
162 return NanoSeconds;\r
163}\r
164\r
165/**\r
166 Retrieves the current value of a 64-bit free running performance counter.\r
167\r
168 Retrieves the current value of a 64-bit free running performance counter. The\r
169 counter can either count up by 1 or count down by 1. If the physical\r
170 performance counter counts by a larger increment, then the counter values\r
171 must be translated. The properties of the counter can be retrieved from\r
172 GetPerformanceCounterProperties().\r
173\r
174 @return The current value of the free running performance counter.\r
175\r
176**/\r
177UINT64\r
178EFIAPI\r
179GetPerformanceCounter (\r
180 VOID\r
181 )\r
182{\r
183 return (UINT64)InternalAcpiGetTimerTick ();\r
184}\r
185\r
186/**\r
187 Retrieves the 64-bit frequency in Hz and the range of performance counter\r
188 values.\r
189\r
190 If StartValue is not NULL, then the value that the performance counter starts\r
191 with immediately after is it rolls over is returned in StartValue. If\r
192 EndValue is not NULL, then the value that the performance counter end with\r
193 immediately before it rolls over is returned in EndValue. The 64-bit\r
194 frequency of the performance counter in Hz is always returned. If StartValue\r
195 is less than EndValue, then the performance counter counts up. If StartValue\r
196 is greater than EndValue, then the performance counter counts down. For\r
197 example, a 64-bit free running counter that counts up would have a StartValue\r
198 of 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running counter\r
199 that counts down would have a StartValue of 0xFFFFFF and an EndValue of 0.\r
200\r
201 @param StartValue The value the performance counter starts with when it\r
202 rolls over.\r
203 @param EndValue The value that the performance counter ends with before\r
204 it rolls over.\r
205\r
206 @return The frequency in Hz.\r
207\r
208**/\r
209UINT64\r
210EFIAPI\r
211GetPerformanceCounterProperties (\r
212 OUT UINT64 *StartValue, OPTIONAL\r
213 OUT UINT64 *EndValue OPTIONAL\r
214 )\r
215{\r
216 if (StartValue != NULL) {\r
217 *StartValue = 0;\r
218 }\r
219\r
220 if (EndValue != NULL) {\r
221 *EndValue = ACPI_TIMER_COUNT_SIZE - 1;\r
222 }\r
223\r
224 return ACPI_TIMER_FREQUENCY;\r
225}\r
226\r
227/**\r
228 Converts elapsed ticks of performance counter to time in nanoseconds.\r
229\r
230 This function converts the elapsed ticks of running performance counter to\r
231 time value in unit of nanoseconds.\r
232\r
233 @param Ticks The number of elapsed ticks of running performance counter.\r
234\r
235 @return The elapsed time in nanoseconds.\r
236\r
237**/\r
238UINT64\r
239EFIAPI\r
240GetTimeInNanoSecond (\r
241 IN UINT64 Ticks\r
242 )\r
243{\r
244 UINT64 Frequency;\r
245 UINT64 NanoSeconds;\r
246 UINT64 Remainder;\r
247 INTN Shift;\r
248\r
249 Frequency = GetPerformanceCounterProperties (NULL, NULL);\r
250\r
251 //\r
252 // Ticks\r
253 // Time = --------- x 1,000,000,000\r
254 // Frequency\r
255 //\r
256 NanoSeconds = MultU64x32 (DivU64x64Remainder (Ticks, Frequency, &Remainder), 1000000000u);\r
257\r
258 //\r
259 // Ensure (Remainder * 1,000,000,000) will not overflow 64-bit.\r
260 // Since 2^29 < 1,000,000,000 = 0x3B9ACA00 < 2^30, Remainder should < 2^(64-30) = 2^34,\r
261 // i.e. highest bit set in Remainder should <= 33.\r
262 //\r
263 Shift = MAX (0, HighBitSet64 (Remainder) - 33);\r
264 Remainder = RShiftU64 (Remainder, (UINTN) Shift);\r
265 Frequency = RShiftU64 (Frequency, (UINTN) Shift);\r
266 NanoSeconds += DivU64x64Remainder (MultU64x32 (Remainder, 1000000000u), Frequency, NULL);\r
267\r
268 return NanoSeconds;\r
269}\r
270\r