]> git.proxmox.com Git - mirror_edk2.git/blob - PcAtChipsetPkg/Library/AcpiTimerLib/AcpiTimerLib.c
PcAtChipsetPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / PcAtChipsetPkg / Library / AcpiTimerLib / AcpiTimerLib.c
1 /** @file
2 ACPI Timer implements one instance of Timer Library.
3
4 Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include <Base.h>
10 #include <Library/TimerLib.h>
11 #include <Library/BaseLib.h>
12 #include <Library/PcdLib.h>
13 #include <Library/PciLib.h>
14 #include <Library/IoLib.h>
15 #include <Library/DebugLib.h>
16 #include <IndustryStandard/Acpi.h>
17
18 GUID mFrequencyHobGuid = { 0x3fca54f6, 0xe1a2, 0x4b20, { 0xbe, 0x76, 0x92, 0x6b, 0x4b, 0x48, 0xbf, 0xaa }};
19
20 /**
21 Internal function to retrieves the 64-bit frequency in Hz.
22
23 Internal function to retrieves the 64-bit frequency in Hz.
24
25 @return The frequency in Hz.
26
27 **/
28 UINT64
29 InternalGetPerformanceCounterFrequency (
30 VOID
31 );
32
33 /**
34 The constructor function enables ACPI IO space.
35
36 If ACPI I/O space not enabled, this function will enable it.
37 It will always return RETURN_SUCCESS.
38
39 @retval EFI_SUCCESS The constructor always returns RETURN_SUCCESS.
40
41 **/
42 RETURN_STATUS
43 EFIAPI
44 AcpiTimerLibConstructor (
45 VOID
46 )
47 {
48 UINTN Bus;
49 UINTN Device;
50 UINTN Function;
51 UINTN EnableRegister;
52 UINT8 EnableMask;
53
54 //
55 // ASSERT for the invalid PCD values. They must be configured to the real value.
56 //
57 ASSERT (PcdGet16 (PcdAcpiIoPciBarRegisterOffset) != 0xFFFF);
58 ASSERT (PcdGet16 (PcdAcpiIoPortBaseAddress) != 0xFFFF);
59
60 //
61 // If the register offset to the BAR for the ACPI I/O Port Base Address is 0x0000, then
62 // no PCI register programming is required to enable access to the the ACPI registers
63 // specified by PcdAcpiIoPortBaseAddress
64 //
65 if (PcdGet16 (PcdAcpiIoPciBarRegisterOffset) == 0x0000) {
66 return RETURN_SUCCESS;
67 }
68
69 //
70 // ASSERT for the invalid PCD values. They must be configured to the real value.
71 //
72 ASSERT (PcdGet8 (PcdAcpiIoPciDeviceNumber) != 0xFF);
73 ASSERT (PcdGet8 (PcdAcpiIoPciFunctionNumber) != 0xFF);
74 ASSERT (PcdGet16 (PcdAcpiIoPciEnableRegisterOffset) != 0xFFFF);
75
76 //
77 // Retrieve the PCD values for the PCI configuration space required to program the ACPI I/O Port Base Address
78 //
79 Bus = PcdGet8 (PcdAcpiIoPciBusNumber);
80 Device = PcdGet8 (PcdAcpiIoPciDeviceNumber);
81 Function = PcdGet8 (PcdAcpiIoPciFunctionNumber);
82 EnableRegister = PcdGet16 (PcdAcpiIoPciEnableRegisterOffset);
83 EnableMask = PcdGet8 (PcdAcpiIoBarEnableMask);
84
85 //
86 // If ACPI I/O space is not enabled yet, program ACPI I/O base address and enable it.
87 //
88 if ((PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, EnableRegister)) & EnableMask) != EnableMask) {
89 PciWrite16 (
90 PCI_LIB_ADDRESS (Bus, Device, Function, PcdGet16 (PcdAcpiIoPciBarRegisterOffset)),
91 PcdGet16 (PcdAcpiIoPortBaseAddress)
92 );
93 PciOr8 (
94 PCI_LIB_ADDRESS (Bus, Device, Function, EnableRegister),
95 EnableMask
96 );
97 }
98
99 return RETURN_SUCCESS;
100 }
101
102 /**
103 Internal function to retrieve the ACPI I/O Port Base Address.
104
105 Internal function to retrieve the ACPI I/O Port Base Address.
106
107 @return The 16-bit ACPI I/O Port Base Address.
108
109 **/
110 UINT16
111 InternalAcpiGetAcpiTimerIoPort (
112 VOID
113 )
114 {
115 UINT16 Port;
116
117 Port = PcdGet16 (PcdAcpiIoPortBaseAddress);
118
119 //
120 // If the register offset to the BAR for the ACPI I/O Port Base Address is not 0x0000, then
121 // read the PCI register for the ACPI BAR value in case the BAR has been programmed to a
122 // value other than PcdAcpiIoPortBaseAddress
123 //
124 if (PcdGet16 (PcdAcpiIoPciBarRegisterOffset) != 0x0000) {
125 Port = PciRead16 (PCI_LIB_ADDRESS (
126 PcdGet8 (PcdAcpiIoPciBusNumber),
127 PcdGet8 (PcdAcpiIoPciDeviceNumber),
128 PcdGet8 (PcdAcpiIoPciFunctionNumber),
129 PcdGet16 (PcdAcpiIoPciBarRegisterOffset)
130 ));
131 }
132
133 return (Port & PcdGet16 (PcdAcpiIoPortBaseAddressMask)) + PcdGet16 (PcdAcpiPm1TmrOffset);
134 }
135
136 /**
137 Stalls the CPU for at least the given number of ticks.
138
139 Stalls the CPU for at least the given number of ticks. It's invoked by
140 MicroSecondDelay() and NanoSecondDelay().
141
142 @param Delay A period of time to delay in ticks.
143
144 **/
145 VOID
146 InternalAcpiDelay (
147 IN UINT32 Delay
148 )
149 {
150 UINT16 Port;
151 UINT32 Ticks;
152 UINT32 Times;
153
154 Port = InternalAcpiGetAcpiTimerIoPort ();
155 Times = Delay >> 22;
156 Delay &= BIT22 - 1;
157 do {
158 //
159 // The target timer count is calculated here
160 //
161 Ticks = IoBitFieldRead32 (Port, 0, 23) + Delay;
162 Delay = BIT22;
163 //
164 // Wait until time out
165 // Delay >= 2^23 could not be handled by this function
166 // Timer wrap-arounds are handled correctly by this function
167 //
168 while (((Ticks - IoBitFieldRead32 (Port, 0, 23)) & BIT23) == 0) {
169 CpuPause ();
170 }
171 } while (Times-- > 0);
172 }
173
174 /**
175 Stalls the CPU for at least the given number of microseconds.
176
177 Stalls the CPU for the number of microseconds specified by MicroSeconds.
178
179 @param MicroSeconds The minimum number of microseconds to delay.
180
181 @return MicroSeconds
182
183 **/
184 UINTN
185 EFIAPI
186 MicroSecondDelay (
187 IN UINTN MicroSeconds
188 )
189 {
190 InternalAcpiDelay (
191 (UINT32)DivU64x32 (
192 MultU64x32 (
193 MicroSeconds,
194 ACPI_TIMER_FREQUENCY
195 ),
196 1000000u
197 )
198 );
199 return MicroSeconds;
200 }
201
202 /**
203 Stalls the CPU for at least the given number of nanoseconds.
204
205 Stalls the CPU for the number of nanoseconds specified by NanoSeconds.
206
207 @param NanoSeconds The minimum number of nanoseconds to delay.
208
209 @return NanoSeconds
210
211 **/
212 UINTN
213 EFIAPI
214 NanoSecondDelay (
215 IN UINTN NanoSeconds
216 )
217 {
218 InternalAcpiDelay (
219 (UINT32)DivU64x32 (
220 MultU64x32 (
221 NanoSeconds,
222 ACPI_TIMER_FREQUENCY
223 ),
224 1000000000u
225 )
226 );
227 return NanoSeconds;
228 }
229
230 /**
231 Retrieves the current value of a 64-bit free running performance counter.
232
233 Retrieves the current value of a 64-bit free running performance counter. The
234 counter can either count up by 1 or count down by 1. If the physical
235 performance counter counts by a larger increment, then the counter values
236 must be translated. The properties of the counter can be retrieved from
237 GetPerformanceCounterProperties().
238
239 @return The current value of the free running performance counter.
240
241 **/
242 UINT64
243 EFIAPI
244 GetPerformanceCounter (
245 VOID
246 )
247 {
248 return AsmReadTsc ();
249 }
250
251 /**
252 Retrieves the 64-bit frequency in Hz and the range of performance counter
253 values.
254
255 If StartValue is not NULL, then the value that the performance counter starts
256 with immediately after is it rolls over is returned in StartValue. If
257 EndValue is not NULL, then the value that the performance counter end with
258 immediately before it rolls over is returned in EndValue. The 64-bit
259 frequency of the performance counter in Hz is always returned. If StartValue
260 is less than EndValue, then the performance counter counts up. If StartValue
261 is greater than EndValue, then the performance counter counts down. For
262 example, a 64-bit free running counter that counts up would have a StartValue
263 of 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running counter
264 that counts down would have a StartValue of 0xFFFFFF and an EndValue of 0.
265
266 @param StartValue The value the performance counter starts with when it
267 rolls over.
268 @param EndValue The value that the performance counter ends with before
269 it rolls over.
270
271 @return The frequency in Hz.
272
273 **/
274 UINT64
275 EFIAPI
276 GetPerformanceCounterProperties (
277 OUT UINT64 *StartValue, OPTIONAL
278 OUT UINT64 *EndValue OPTIONAL
279 )
280 {
281 if (StartValue != NULL) {
282 *StartValue = 0;
283 }
284
285 if (EndValue != NULL) {
286 *EndValue = 0xffffffffffffffffULL;
287 }
288 return InternalGetPerformanceCounterFrequency ();
289 }
290
291 /**
292 Converts elapsed ticks of performance counter to time in nanoseconds.
293
294 This function converts the elapsed ticks of running performance counter to
295 time value in unit of nanoseconds.
296
297 @param Ticks The number of elapsed ticks of running performance counter.
298
299 @return The elapsed time in nanoseconds.
300
301 **/
302 UINT64
303 EFIAPI
304 GetTimeInNanoSecond (
305 IN UINT64 Ticks
306 )
307 {
308 UINT64 Frequency;
309 UINT64 NanoSeconds;
310 UINT64 Remainder;
311 INTN Shift;
312
313 Frequency = GetPerformanceCounterProperties (NULL, NULL);
314
315 //
316 // Ticks
317 // Time = --------- x 1,000,000,000
318 // Frequency
319 //
320 NanoSeconds = MultU64x32 (DivU64x64Remainder (Ticks, Frequency, &Remainder), 1000000000u);
321
322 //
323 // Ensure (Remainder * 1,000,000,000) will not overflow 64-bit.
324 // Since 2^29 < 1,000,000,000 = 0x3B9ACA00 < 2^30, Remainder should < 2^(64-30) = 2^34,
325 // i.e. highest bit set in Remainder should <= 33.
326 //
327 Shift = MAX (0, HighBitSet64 (Remainder) - 33);
328 Remainder = RShiftU64 (Remainder, (UINTN) Shift);
329 Frequency = RShiftU64 (Frequency, (UINTN) Shift);
330 NanoSeconds += DivU64x64Remainder (MultU64x32 (Remainder, 1000000000u), Frequency, NULL);
331
332 return NanoSeconds;
333 }
334
335 /**
336 Calculate TSC frequency.
337
338 The TSC counting frequency is determined by comparing how far it counts
339 during a 101.4 us period as determined by the ACPI timer.
340 The ACPI timer is used because it counts at a known frequency.
341 The TSC is sampled, followed by waiting 363 counts of the ACPI timer,
342 or 101.4 us. The TSC is then sampled again. The difference multiplied by
343 9861 is the TSC frequency. There will be a small error because of the
344 overhead of reading the ACPI timer. An attempt is made to determine and
345 compensate for this error.
346
347 @return The number of TSC counts per second.
348
349 **/
350 UINT64
351 InternalCalculateTscFrequency (
352 VOID
353 )
354 {
355 UINT64 StartTSC;
356 UINT64 EndTSC;
357 UINT16 TimerAddr;
358 UINT32 Ticks;
359 UINT64 TscFrequency;
360 BOOLEAN InterruptState;
361
362 InterruptState = SaveAndDisableInterrupts ();
363
364 TimerAddr = InternalAcpiGetAcpiTimerIoPort ();
365 //
366 // Compute the number of ticks to wait to measure TSC frequency.
367 // Use 363 * 9861 = 3579543 Hz which is within 2 Hz of ACPI_TIMER_FREQUENCY.
368 // 363 counts is a calibration time of 101.4 uS.
369 //
370 Ticks = IoBitFieldRead32 (TimerAddr, 0, 23) + 363;
371
372 StartTSC = AsmReadTsc (); // Get base value for the TSC
373 //
374 // Wait until the ACPI timer has counted 101.4 us.
375 // Timer wrap-arounds are handled correctly by this function.
376 // When the current ACPI timer value is greater than 'Ticks',
377 // the while loop will exit.
378 //
379 while (((Ticks - IoBitFieldRead32 (TimerAddr, 0, 23)) & BIT23) == 0) {
380 CpuPause();
381 }
382 EndTSC = AsmReadTsc (); // TSC value 101.4 us later
383
384 TscFrequency = MultU64x32 (
385 (EndTSC - StartTSC), // Number of TSC counts in 101.4 us
386 9861 // Number of 101.4 us in a second
387 );
388
389 SetInterruptState (InterruptState);
390
391 return TscFrequency;
392 }
393