]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Library/AcpiTimerLib/AcpiTimerLib.c
Add new API GetTimeInNanoSecond() to TimerLib to convert elapsed ticks to time in...
[mirror_edk2.git] / OvmfPkg / Library / AcpiTimerLib / AcpiTimerLib.c
CommitLineData
49ba9447 1/** @file\r
2 ACPI Timer implements one instance of Timer Library.\r
3\r
550486ed 4 Copyright (c) 2008 - 2011, Intel Corporation. All rights reserved.<BR>\r
5 Copyright (c) 2011, Andrei Warkentin <andreiw@motorola.com>\r
6\r
56d7640a 7 This program and the accompanying materials are\r
49ba9447 8 licensed and made available under the terms and conditions of the BSD License\r
9 which accompanies this distribution. The full text of the license may be found at\r
10 http://opensource.org/licenses/bsd-license.php\r
11 \r
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14\r
15**/ \r
16\r
17#include <Base.h>\r
18#include <Library/TimerLib.h>\r
19#include <Library/BaseLib.h>\r
20#include <Library/IoLib.h>\r
21#include <Library/PciLib.h>\r
550486ed 22#include <Library/DebugLib.h>\r
23\r
24//\r
25// PIIX4 Power Management Base Address\r
26//\r
1c2ae02e 27UINT32 mPmba = 0x400;\r
49ba9447 28\r
550486ed 29#define PCI_BAR_IO 0x1\r
49ba9447 30#define ACPI_TIMER_FREQUENCY 3579545\r
31#define ACPI_TIMER_COUNT_SIZE 0x01000000\r
550486ed 32#define ACPI_TIMER_OFFSET 0x8\r
49ba9447 33\r
34/**\r
35 The constructor function enables ACPI IO space.\r
36\r
37 If ACPI I/O space not enabled, this function will enable it.\r
38 It will always return RETURN_SUCCESS.\r
39\r
40 @retval EFI_SUCCESS The constructor always returns RETURN_SUCCESS.\r
41\r
42**/\r
43RETURN_STATUS\r
44EFIAPI\r
45AcpiTimerLibConstructor (\r
46 VOID\r
47 )\r
48{\r
49 UINT8 Device;\r
50\r
51 Device = 1;\r
52 // Device = 7;\r
53\r
550486ed 54 if (PciRead8 (PCI_LIB_ADDRESS (0,Device,3,0x80)) & 1) {\r
55 mPmba = PciRead32 (PCI_LIB_ADDRESS (0,Device,3,0x40));\r
56 ASSERT (mPmba & PCI_BAR_IO);\r
57 mPmba &= ~PCI_BAR_IO;\r
58 } else {\r
59 PciAndThenOr32 (PCI_LIB_ADDRESS (0,Device,3,0x40),\r
60 (UINT32) ~0xfc0, mPmba);\r
61 PciOr8 (PCI_LIB_ADDRESS (0,Device,3,0x04), 0x01);\r
62 }\r
63\r
49ba9447 64 //\r
65 // ACPI Timer enable is in Bus 0, Device ?, Function 3\r
66 //\r
550486ed 67 PciOr8 (PCI_LIB_ADDRESS (0,Device,3,0x80), 0x01);\r
68 return RETURN_SUCCESS;\r
49ba9447 69}\r
70\r
71/**\r
72 Internal function to read the current tick counter of ACPI.\r
73\r
74 Internal function to read the current tick counter of ACPI.\r
75\r
76 @return The tick counter read.\r
77\r
78**/\r
79STATIC\r
80UINT32\r
81InternalAcpiGetTimerTick (\r
82 VOID\r
83 )\r
84{\r
550486ed 85 return IoRead32 (mPmba + ACPI_TIMER_OFFSET);\r
49ba9447 86}\r
87\r
88/**\r
89 Stalls the CPU for at least the given number of ticks.\r
90\r
91 Stalls the CPU for at least the given number of ticks. It's invoked by\r
92 MicroSecondDelay() and NanoSecondDelay().\r
93\r
94 @param Delay A period of time to delay in ticks.\r
95\r
96**/\r
97STATIC\r
98VOID\r
99InternalAcpiDelay (\r
100 IN UINT32 Delay\r
101 )\r
102{\r
103 UINT32 Ticks;\r
104 UINT32 Times;\r
105\r
106 Times = Delay >> 22;\r
107 Delay &= BIT22 - 1;\r
108 do {\r
109 //\r
110 // The target timer count is calculated here\r
111 //\r
112 Ticks = InternalAcpiGetTimerTick () + Delay;\r
113 Delay = BIT22;\r
114 //\r
115 // Wait until time out\r
116 // Delay >= 2^23 could not be handled by this function\r
117 // Timer wrap-arounds are handled correctly by this function\r
118 //\r
119 while (((Ticks - InternalAcpiGetTimerTick ()) & BIT23) == 0) {\r
120 CpuPause ();\r
121 }\r
122 } while (Times-- > 0);\r
123}\r
124\r
125/**\r
126 Stalls the CPU for at least the given number of microseconds.\r
127\r
128 Stalls the CPU for the number of microseconds specified by MicroSeconds.\r
129\r
130 @param MicroSeconds The minimum number of microseconds to delay.\r
131\r
132 @return MicroSeconds\r
133\r
134**/\r
135UINTN\r
136EFIAPI\r
137MicroSecondDelay (\r
138 IN UINTN MicroSeconds\r
139 )\r
140{\r
141 InternalAcpiDelay (\r
142 (UINT32)DivU64x32 (\r
143 MultU64x32 (\r
144 MicroSeconds,\r
145 ACPI_TIMER_FREQUENCY\r
146 ),\r
147 1000000u\r
148 )\r
149 );\r
150 return MicroSeconds;\r
151}\r
152\r
153/**\r
154 Stalls the CPU for at least the given number of nanoseconds.\r
155\r
156 Stalls the CPU for the number of nanoseconds specified by NanoSeconds.\r
157\r
158 @param NanoSeconds The minimum number of nanoseconds to delay.\r
159\r
160 @return NanoSeconds\r
161\r
162**/\r
163UINTN\r
164EFIAPI\r
165NanoSecondDelay (\r
166 IN UINTN NanoSeconds\r
167 )\r
168{\r
169 InternalAcpiDelay (\r
170 (UINT32)DivU64x32 (\r
171 MultU64x32 (\r
172 NanoSeconds,\r
173 ACPI_TIMER_FREQUENCY\r
174 ),\r
175 1000000000u\r
176 )\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 Retrieves the current value of a 64-bit free running performance counter. The\r
185 counter can either count up by 1 or count down by 1. If the physical\r
186 performance counter counts by a larger increment, then the counter values\r
187 must be translated. The properties of the counter can be retrieved from\r
188 GetPerformanceCounterProperties().\r
189\r
190 @return The current value of the free running performance counter.\r
191\r
192**/\r
193UINT64\r
194EFIAPI\r
195GetPerformanceCounter (\r
196 VOID\r
197 )\r
198{\r
199 return (UINT64)InternalAcpiGetTimerTick ();\r
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
233 *StartValue = 0;\r
234 }\r
235\r
236 if (EndValue != NULL) {\r
237 *EndValue = ACPI_TIMER_COUNT_SIZE - 1;\r
238 }\r
239\r
240 return ACPI_TIMER_FREQUENCY;\r
241}\r
b9610b9c 242\r
243/**\r
244 Converts elapsed ticks of performance counter to time in nanoseconds.\r
245\r
246 This function converts the elapsed ticks of running performance counter to\r
247 time value in unit of nanoseconds.\r
248\r
249 @param Ticks The number of elapsed ticks of running performance counter.\r
250\r
251 @return The elapsed time in nanoseconds.\r
252\r
253**/\r
254UINT64\r
255EFIAPI\r
256GetTimeInNanoSecond (\r
257 IN UINT64 Ticks\r
258 )\r
259{\r
260 UINT64 NanoSeconds;\r
261 UINT32 Remainder;\r
262\r
263 //\r
264 // Ticks\r
265 // Time = --------- x 1,000,000,000\r
266 // Frequency\r
267 //\r
268 NanoSeconds = MultU64x32 (DivU64x32Remainder (Ticks, ACPI_TIMER_FREQUENCY, &Remainder), 1000000000u);\r
269\r
270 //\r
271 // Frequency < 0x100000000, so Remainder < 0x100000000, then (Remainder * 1,000,000,000)\r
272 // will not overflow 64-bit.\r
273 //\r
274 NanoSeconds += DivU64x32 (MultU64x32 ((UINT64) Remainder, 1000000000u), ACPI_TIMER_FREQUENCY);\r
275\r
276 return NanoSeconds;\r
277}\r