]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Library/AcpiTimerLib/AcpiTimerLib.c
OvmfPkg: AcpiTimerLib: Access power mgmt regs based on host bridge type
[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
d3a24ff5 4 Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.<BR>\r
550486ed 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
67164dcd 11\r
49ba9447 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
67164dcd 15**/\r
49ba9447 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
830067bf 23#include <Library/PcdLib.h>\r
5a624588 24#include <IndustryStandard/Pci22.h>\r
d3a24ff5 25#include <IndustryStandard/Acpi.h>\r
550486ed 26\r
27//\r
d3a24ff5 28// PCI Location of PIIX4 Power Management PCI Configuration Registers\r
550486ed 29//\r
d3a24ff5 30#define PIIX4_POWER_MANAGEMENT_BUS 0x00\r
31#define PIIX4_POWER_MANAGEMENT_DEVICE 0x01\r
32#define PIIX4_POWER_MANAGEMENT_FUNCTION 0x03\r
49ba9447 33\r
d3a24ff5 34//\r
35// Macro to access PIIX4 Power Management PCI Configuration Registers\r
36//\r
37#define PIIX4_PCI_POWER_MANAGEMENT_REGISTER(Register) \\r
38 PCI_LIB_ADDRESS ( \\r
39 PIIX4_POWER_MANAGEMENT_BUS, \\r
40 PIIX4_POWER_MANAGEMENT_DEVICE, \\r
41 PIIX4_POWER_MANAGEMENT_FUNCTION, \\r
42 Register \\r
43 )\r
44\r
45//\r
41f80fbd 46// PCI Location of Q35 Power Management PCI Configuration Registers\r
d3a24ff5 47//\r
41f80fbd
GS
48#define Q35_POWER_MANAGEMENT_BUS 0x00\r
49#define Q35_POWER_MANAGEMENT_DEVICE 0x1f\r
50#define Q35_POWER_MANAGEMENT_FUNCTION 0x00\r
51\r
52//\r
53// Macro to access Q35 Power Management PCI Configuration Registers\r
54//\r
55#define Q35_PCI_POWER_MANAGEMENT_REGISTER(Register) \\r
56 PCI_LIB_ADDRESS ( \\r
57 Q35_POWER_MANAGEMENT_BUS, \\r
58 Q35_POWER_MANAGEMENT_DEVICE, \\r
59 Q35_POWER_MANAGEMENT_FUNCTION, \\r
60 Register \\r
61 )\r
62\r
63//\r
64// PCI Location of Host Bridge PCI Configuration Registers\r
65//\r
66#define HOST_BRIDGE_BUS 0x00\r
67#define HOST_BRIDGE_DEVICE 0x00\r
68#define HOST_BRIDGE_FUNCTION 0x00\r
69\r
70//\r
71// Macro to access Host Bridge Configuration Registers\r
72//\r
73#define HOST_BRIDGE_REGISTER(Register) \\r
74 PCI_LIB_ADDRESS ( \\r
75 HOST_BRIDGE_BUS, \\r
76 HOST_BRIDGE_DEVICE, \\r
77 HOST_BRIDGE_FUNCTION, \\r
78 Register \\r
79 )\r
80\r
81//\r
82// Host Bridge Device ID (DID) Register\r
83//\r
84#define HOST_BRIDGE_DID HOST_BRIDGE_REGISTER (0x02)\r
85\r
86//\r
87// Host Bridge DID Register values\r
88//\r
89#define PCI_DEVICE_ID_INTEL_82441 0x1237 // DID value for PIIX4\r
90#define PCI_DEVICE_ID_INTEL_Q35_MCH 0x29C0 // DID value for Q35\r
91\r
92//\r
93// Access Power Management PCI Config Regs based on Host Bridge type\r
94//\r
95#define PCI_POWER_MANAGEMENT_REGISTER(Register) \\r
96 ((PciRead16 (HOST_BRIDGE_DID) == PCI_DEVICE_ID_INTEL_Q35_MCH) ? \\r
97 Q35_PCI_POWER_MANAGEMENT_REGISTER (Register) : \\r
98 PIIX4_PCI_POWER_MANAGEMENT_REGISTER (Register))\r
99\r
100//\r
101// Power Management PCI Configuration Registers\r
102//\r
103#define PMBA PCI_POWER_MANAGEMENT_REGISTER (0x40)\r
d3a24ff5 104#define PMBA_RTE BIT0\r
41f80fbd 105#define PMREGMISC PCI_POWER_MANAGEMENT_REGISTER (0x80)\r
d3a24ff5 106#define PMIOSE BIT0\r
107\r
108//\r
41f80fbd 109// The ACPI Time is a 24-bit counter\r
d3a24ff5 110//\r
111#define ACPI_TIMER_COUNT_SIZE BIT24\r
112\r
113//\r
41f80fbd 114// Offset in the Power Management Base Address to the ACPI Timer\r
d3a24ff5 115//\r
550486ed 116#define ACPI_TIMER_OFFSET 0x8\r
49ba9447 117\r
118/**\r
119 The constructor function enables ACPI IO space.\r
120\r
121 If ACPI I/O space not enabled, this function will enable it.\r
122 It will always return RETURN_SUCCESS.\r
123\r
124 @retval EFI_SUCCESS The constructor always returns RETURN_SUCCESS.\r
125\r
126**/\r
127RETURN_STATUS\r
128EFIAPI\r
129AcpiTimerLibConstructor (\r
130 VOID\r
131 )\r
132{\r
49ba9447 133 //\r
41f80fbd 134 // Check to see if the Power Management Base Address is already enabled\r
49ba9447 135 //\r
d3a24ff5 136 if ((PciRead8 (PMREGMISC) & PMIOSE) == 0) {\r
137 //\r
41f80fbd
GS
138 // If the Power Management Base Address is not programmed,\r
139 // then program the Power Management Base Address from a PCD.\r
d3a24ff5 140 //\r
141 PciAndThenOr32 (PMBA, (UINT32)(~0x0000FFC0), PcdGet16 (PcdAcpiPmBaseAddress));\r
142\r
143 //\r
144 // Enable PMBA I/O port decodes in PMREGMISC\r
145 //\r
146 PciOr8 (PMREGMISC, PMIOSE);\r
147 }\r
148 \r
550486ed 149 return RETURN_SUCCESS;\r
49ba9447 150}\r
151\r
152/**\r
153 Internal function to read the current tick counter of ACPI.\r
154\r
155 Internal function to read the current tick counter of ACPI.\r
156\r
157 @return The tick counter read.\r
158\r
159**/\r
49ba9447 160UINT32\r
161InternalAcpiGetTimerTick (\r
162 VOID\r
163 )\r
164{\r
d3a24ff5 165 //\r
166 // Read PMBA to read and return the current ACPI timer value.\r
167 //\r
168 return IoRead32 ((PciRead32 (PMBA) & ~PMBA_RTE) + ACPI_TIMER_OFFSET);\r
49ba9447 169}\r
170\r
171/**\r
172 Stalls the CPU for at least the given number of ticks.\r
173\r
174 Stalls the CPU for at least the given number of ticks. It's invoked by\r
175 MicroSecondDelay() and NanoSecondDelay().\r
176\r
177 @param Delay A period of time to delay in ticks.\r
178\r
179**/\r
49ba9447 180VOID\r
181InternalAcpiDelay (\r
182 IN UINT32 Delay\r
183 )\r
184{\r
185 UINT32 Ticks;\r
186 UINT32 Times;\r
187\r
188 Times = Delay >> 22;\r
189 Delay &= BIT22 - 1;\r
190 do {\r
191 //\r
192 // The target timer count is calculated here\r
193 //\r
194 Ticks = InternalAcpiGetTimerTick () + Delay;\r
195 Delay = BIT22;\r
196 //\r
197 // Wait until time out\r
198 // Delay >= 2^23 could not be handled by this function\r
199 // Timer wrap-arounds are handled correctly by this function\r
200 //\r
201 while (((Ticks - InternalAcpiGetTimerTick ()) & BIT23) == 0) {\r
202 CpuPause ();\r
203 }\r
204 } while (Times-- > 0);\r
205}\r
206\r
207/**\r
208 Stalls the CPU for at least the given number of microseconds.\r
209\r
210 Stalls the CPU for the number of microseconds specified by MicroSeconds.\r
211\r
212 @param MicroSeconds The minimum number of microseconds to delay.\r
213\r
214 @return MicroSeconds\r
215\r
216**/\r
217UINTN\r
218EFIAPI\r
219MicroSecondDelay (\r
220 IN UINTN MicroSeconds\r
221 )\r
222{\r
223 InternalAcpiDelay (\r
224 (UINT32)DivU64x32 (\r
225 MultU64x32 (\r
226 MicroSeconds,\r
227 ACPI_TIMER_FREQUENCY\r
228 ),\r
229 1000000u\r
230 )\r
231 );\r
232 return MicroSeconds;\r
233}\r
234\r
235/**\r
236 Stalls the CPU for at least the given number of nanoseconds.\r
237\r
238 Stalls the CPU for the number of nanoseconds specified by NanoSeconds.\r
239\r
240 @param NanoSeconds The minimum number of nanoseconds to delay.\r
241\r
242 @return NanoSeconds\r
243\r
244**/\r
245UINTN\r
246EFIAPI\r
247NanoSecondDelay (\r
248 IN UINTN NanoSeconds\r
249 )\r
250{\r
251 InternalAcpiDelay (\r
252 (UINT32)DivU64x32 (\r
253 MultU64x32 (\r
254 NanoSeconds,\r
255 ACPI_TIMER_FREQUENCY\r
256 ),\r
257 1000000000u\r
258 )\r
259 );\r
260 return NanoSeconds;\r
261}\r
262\r
263/**\r
264 Retrieves the current value of a 64-bit free running performance counter.\r
265\r
266 Retrieves the current value of a 64-bit free running performance counter. The\r
267 counter can either count up by 1 or count down by 1. If the physical\r
268 performance counter counts by a larger increment, then the counter values\r
269 must be translated. The properties of the counter can be retrieved from\r
270 GetPerformanceCounterProperties().\r
271\r
272 @return The current value of the free running performance counter.\r
273\r
274**/\r
275UINT64\r
276EFIAPI\r
277GetPerformanceCounter (\r
278 VOID\r
279 )\r
280{\r
281 return (UINT64)InternalAcpiGetTimerTick ();\r
282}\r
283\r
284/**\r
285 Retrieves the 64-bit frequency in Hz and the range of performance counter\r
286 values.\r
287\r
288 If StartValue is not NULL, then the value that the performance counter starts\r
289 with immediately after is it rolls over is returned in StartValue. If\r
290 EndValue is not NULL, then the value that the performance counter end with\r
291 immediately before it rolls over is returned in EndValue. The 64-bit\r
292 frequency of the performance counter in Hz is always returned. If StartValue\r
293 is less than EndValue, then the performance counter counts up. If StartValue\r
294 is greater than EndValue, then the performance counter counts down. For\r
295 example, a 64-bit free running counter that counts up would have a StartValue\r
296 of 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running counter\r
297 that counts down would have a StartValue of 0xFFFFFF and an EndValue of 0.\r
298\r
299 @param StartValue The value the performance counter starts with when it\r
300 rolls over.\r
301 @param EndValue The value that the performance counter ends with before\r
302 it rolls over.\r
303\r
304 @return The frequency in Hz.\r
305\r
306**/\r
307UINT64\r
308EFIAPI\r
309GetPerformanceCounterProperties (\r
310 OUT UINT64 *StartValue, OPTIONAL\r
311 OUT UINT64 *EndValue OPTIONAL\r
312 )\r
313{\r
314 if (StartValue != NULL) {\r
315 *StartValue = 0;\r
316 }\r
317\r
318 if (EndValue != NULL) {\r
319 *EndValue = ACPI_TIMER_COUNT_SIZE - 1;\r
320 }\r
321\r
322 return ACPI_TIMER_FREQUENCY;\r
323}\r
b9610b9c 324\r
325/**\r
326 Converts elapsed ticks of performance counter to time in nanoseconds.\r
327\r
328 This function converts the elapsed ticks of running performance counter to\r
329 time value in unit of nanoseconds.\r
330\r
331 @param Ticks The number of elapsed ticks of running performance counter.\r
332\r
333 @return The elapsed time in nanoseconds.\r
334\r
335**/\r
336UINT64\r
337EFIAPI\r
338GetTimeInNanoSecond (\r
339 IN UINT64 Ticks\r
340 )\r
341{\r
342 UINT64 NanoSeconds;\r
343 UINT32 Remainder;\r
344\r
345 //\r
346 // Ticks\r
347 // Time = --------- x 1,000,000,000\r
348 // Frequency\r
349 //\r
350 NanoSeconds = MultU64x32 (DivU64x32Remainder (Ticks, ACPI_TIMER_FREQUENCY, &Remainder), 1000000000u);\r
351\r
352 //\r
353 // Frequency < 0x100000000, so Remainder < 0x100000000, then (Remainder * 1,000,000,000)\r
354 // will not overflow 64-bit.\r
355 //\r
356 NanoSeconds += DivU64x32 (MultU64x32 ((UINT64) Remainder, 1000000000u), ACPI_TIMER_FREQUENCY);\r
357\r
358 return NanoSeconds;\r
359}\r