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
AcpiTimerLibConstructor(VOID)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
InternalAcpiGetTimerTick(VOID)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
InternalAcpiDelay(IN UINT32 Delay)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
MicroSecondDelay(IN UINTN MicroSeconds)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
NanoSecondDelay(IN UINTN NanoSeconds)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
GetPerformanceCounter(VOID)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
GetPerformanceCounterProperties(OUT UINT64 * StartValue,OPTIONAL OUT UINT64 * EndValue OPTIONAL)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
GetTimeInNanoSecond(IN UINT64 Ticks)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 
271