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