128c506b8Sjruoho /******************************************************************************
228c506b8Sjruoho *
328c506b8Sjruoho * Name: hwtimer.c - ACPI Power Management Timer Interface
428c506b8Sjruoho *
528c506b8Sjruoho *****************************************************************************/
628c506b8Sjruoho
7124f4c82Sjruoho /*
8*046a2985Schristos * Copyright (C) 2000 - 2023, Intel Corp.
928c506b8Sjruoho * All rights reserved.
1028c506b8Sjruoho *
11124f4c82Sjruoho * Redistribution and use in source and binary forms, with or without
12124f4c82Sjruoho * modification, are permitted provided that the following conditions
13124f4c82Sjruoho * are met:
14124f4c82Sjruoho * 1. Redistributions of source code must retain the above copyright
15124f4c82Sjruoho * notice, this list of conditions, and the following disclaimer,
16124f4c82Sjruoho * without modification.
17124f4c82Sjruoho * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18124f4c82Sjruoho * substantially similar to the "NO WARRANTY" disclaimer below
19124f4c82Sjruoho * ("Disclaimer") and any redistribution must be conditioned upon
20124f4c82Sjruoho * including a substantially similar Disclaimer requirement for further
21124f4c82Sjruoho * binary redistribution.
22124f4c82Sjruoho * 3. Neither the names of the above-listed copyright holders nor the names
23124f4c82Sjruoho * of any contributors may be used to endorse or promote products derived
24124f4c82Sjruoho * from this software without specific prior written permission.
2528c506b8Sjruoho *
26124f4c82Sjruoho * Alternatively, this software may be distributed under the terms of the
27124f4c82Sjruoho * GNU General Public License ("GPL") version 2 as published by the Free
28124f4c82Sjruoho * Software Foundation.
2928c506b8Sjruoho *
30124f4c82Sjruoho * NO WARRANTY
31124f4c82Sjruoho * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32124f4c82Sjruoho * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3346a330b4Schristos * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
34124f4c82Sjruoho * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35124f4c82Sjruoho * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36124f4c82Sjruoho * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37124f4c82Sjruoho * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38124f4c82Sjruoho * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39124f4c82Sjruoho * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40124f4c82Sjruoho * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41124f4c82Sjruoho * POSSIBILITY OF SUCH DAMAGES.
42124f4c82Sjruoho */
4328c506b8Sjruoho
44ff4a156dSchristos #define EXPORT_ACPI_INTERFACES
45ff4a156dSchristos
4628c506b8Sjruoho #include "acpi.h"
4728c506b8Sjruoho #include "accommon.h"
4828c506b8Sjruoho
4928c506b8Sjruoho #define _COMPONENT ACPI_HARDWARE
5028c506b8Sjruoho ACPI_MODULE_NAME ("hwtimer")
5128c506b8Sjruoho
5228c506b8Sjruoho
53ff4a156dSchristos #if (!ACPI_REDUCED_HARDWARE) /* Entire module */
5428c506b8Sjruoho /******************************************************************************
5528c506b8Sjruoho *
5628c506b8Sjruoho * FUNCTION: AcpiGetTimerResolution
5728c506b8Sjruoho *
5828c506b8Sjruoho * PARAMETERS: Resolution - Where the resolution is returned
5928c506b8Sjruoho *
6028c506b8Sjruoho * RETURN: Status and timer resolution
6128c506b8Sjruoho *
6228c506b8Sjruoho * DESCRIPTION: Obtains resolution of the ACPI PM Timer (24 or 32 bits).
6328c506b8Sjruoho *
6428c506b8Sjruoho ******************************************************************************/
6528c506b8Sjruoho
6628c506b8Sjruoho ACPI_STATUS
AcpiGetTimerResolution(UINT32 * Resolution)6728c506b8Sjruoho AcpiGetTimerResolution (
6828c506b8Sjruoho UINT32 *Resolution)
6928c506b8Sjruoho {
7028c506b8Sjruoho ACPI_FUNCTION_TRACE (AcpiGetTimerResolution);
7128c506b8Sjruoho
7228c506b8Sjruoho
7328c506b8Sjruoho if (!Resolution)
7428c506b8Sjruoho {
7528c506b8Sjruoho return_ACPI_STATUS (AE_BAD_PARAMETER);
7628c506b8Sjruoho }
7728c506b8Sjruoho
7828c506b8Sjruoho if ((AcpiGbl_FADT.Flags & ACPI_FADT_32BIT_TIMER) == 0)
7928c506b8Sjruoho {
8028c506b8Sjruoho *Resolution = 24;
8128c506b8Sjruoho }
8228c506b8Sjruoho else
8328c506b8Sjruoho {
8428c506b8Sjruoho *Resolution = 32;
8528c506b8Sjruoho }
8628c506b8Sjruoho
8728c506b8Sjruoho return_ACPI_STATUS (AE_OK);
8828c506b8Sjruoho }
8928c506b8Sjruoho
ACPI_EXPORT_SYMBOL(AcpiGetTimerResolution)9028c506b8Sjruoho ACPI_EXPORT_SYMBOL (AcpiGetTimerResolution)
9128c506b8Sjruoho
9228c506b8Sjruoho
9328c506b8Sjruoho /******************************************************************************
9428c506b8Sjruoho *
9528c506b8Sjruoho * FUNCTION: AcpiGetTimer
9628c506b8Sjruoho *
9728c506b8Sjruoho * PARAMETERS: Ticks - Where the timer value is returned
9828c506b8Sjruoho *
9928c506b8Sjruoho * RETURN: Status and current timer value (ticks)
10028c506b8Sjruoho *
10128c506b8Sjruoho * DESCRIPTION: Obtains current value of ACPI PM Timer (in ticks).
10228c506b8Sjruoho *
10328c506b8Sjruoho ******************************************************************************/
10428c506b8Sjruoho
10528c506b8Sjruoho ACPI_STATUS
10628c506b8Sjruoho AcpiGetTimer (
10728c506b8Sjruoho UINT32 *Ticks)
10828c506b8Sjruoho {
10928c506b8Sjruoho ACPI_STATUS Status;
11089b8eb6cSchristos UINT64 TimerValue;
11128c506b8Sjruoho
11228c506b8Sjruoho
11328c506b8Sjruoho ACPI_FUNCTION_TRACE (AcpiGetTimer);
11428c506b8Sjruoho
11528c506b8Sjruoho
11628c506b8Sjruoho if (!Ticks)
11728c506b8Sjruoho {
11828c506b8Sjruoho return_ACPI_STATUS (AE_BAD_PARAMETER);
11928c506b8Sjruoho }
12028c506b8Sjruoho
121ff4a156dSchristos /* ACPI 5.0A: PM Timer is optional */
12228c506b8Sjruoho
123ff4a156dSchristos if (!AcpiGbl_FADT.XPmTimerBlock.Address)
124ff4a156dSchristos {
125ff4a156dSchristos return_ACPI_STATUS (AE_SUPPORT);
126ff4a156dSchristos }
127ff4a156dSchristos
12889b8eb6cSchristos Status = AcpiHwRead (&TimerValue, &AcpiGbl_FADT.XPmTimerBlock);
12989b8eb6cSchristos if (ACPI_SUCCESS (Status))
13089b8eb6cSchristos {
13189b8eb6cSchristos /* ACPI PM Timer is defined to be 32 bits (PM_TMR_LEN) */
13289b8eb6cSchristos
13389b8eb6cSchristos *Ticks = (UINT32) TimerValue;
13489b8eb6cSchristos }
13589b8eb6cSchristos
13628c506b8Sjruoho return_ACPI_STATUS (Status);
13728c506b8Sjruoho }
13828c506b8Sjruoho
ACPI_EXPORT_SYMBOL(AcpiGetTimer)13928c506b8Sjruoho ACPI_EXPORT_SYMBOL (AcpiGetTimer)
14028c506b8Sjruoho
14128c506b8Sjruoho
14228c506b8Sjruoho /******************************************************************************
14328c506b8Sjruoho *
14428c506b8Sjruoho * FUNCTION: AcpiGetTimerDuration
14528c506b8Sjruoho *
14628c506b8Sjruoho * PARAMETERS: StartTicks - Starting timestamp
14728c506b8Sjruoho * EndTicks - End timestamp
14828c506b8Sjruoho * TimeElapsed - Where the elapsed time is returned
14928c506b8Sjruoho *
15028c506b8Sjruoho * RETURN: Status and TimeElapsed
15128c506b8Sjruoho *
15228c506b8Sjruoho * DESCRIPTION: Computes the time elapsed (in microseconds) between two
15328c506b8Sjruoho * PM Timer time stamps, taking into account the possibility of
15428c506b8Sjruoho * rollovers, the timer resolution, and timer frequency.
15528c506b8Sjruoho *
15628c506b8Sjruoho * The PM Timer's clock ticks at roughly 3.6 times per
15728c506b8Sjruoho * _microsecond_, and its clock continues through Cx state
15828c506b8Sjruoho * transitions (unlike many CPU timestamp counters) -- making it
15928c506b8Sjruoho * a versatile and accurate timer.
16028c506b8Sjruoho *
16128c506b8Sjruoho * Note that this function accommodates only a single timer
16228c506b8Sjruoho * rollover. Thus for 24-bit timers, this function should only
16328c506b8Sjruoho * be used for calculating durations less than ~4.6 seconds
16428c506b8Sjruoho * (~20 minutes for 32-bit timers) -- calculations below:
16528c506b8Sjruoho *
16628c506b8Sjruoho * 2**24 Ticks / 3,600,000 Ticks/Sec = 4.66 sec
16728c506b8Sjruoho * 2**32 Ticks / 3,600,000 Ticks/Sec = 1193 sec or 19.88 minutes
16828c506b8Sjruoho *
16928c506b8Sjruoho ******************************************************************************/
17028c506b8Sjruoho
17128c506b8Sjruoho ACPI_STATUS
17228c506b8Sjruoho AcpiGetTimerDuration (
17328c506b8Sjruoho UINT32 StartTicks,
17428c506b8Sjruoho UINT32 EndTicks,
17528c506b8Sjruoho UINT32 *TimeElapsed)
17628c506b8Sjruoho {
17728c506b8Sjruoho ACPI_STATUS Status;
178b406f703Schristos UINT64 DeltaTicks;
17928c506b8Sjruoho UINT64 Quotient;
18028c506b8Sjruoho
18128c506b8Sjruoho
18228c506b8Sjruoho ACPI_FUNCTION_TRACE (AcpiGetTimerDuration);
18328c506b8Sjruoho
18428c506b8Sjruoho
18528c506b8Sjruoho if (!TimeElapsed)
18628c506b8Sjruoho {
18728c506b8Sjruoho return_ACPI_STATUS (AE_BAD_PARAMETER);
18828c506b8Sjruoho }
18928c506b8Sjruoho
190ff4a156dSchristos /* ACPI 5.0A: PM Timer is optional */
191ff4a156dSchristos
192ff4a156dSchristos if (!AcpiGbl_FADT.XPmTimerBlock.Address)
193ff4a156dSchristos {
194ff4a156dSchristos return_ACPI_STATUS (AE_SUPPORT);
195ff4a156dSchristos }
196ff4a156dSchristos
197b406f703Schristos if (StartTicks == EndTicks)
198b406f703Schristos {
199b406f703Schristos *TimeElapsed = 0;
200b406f703Schristos return_ACPI_STATUS (AE_OK);
201b406f703Schristos }
202b406f703Schristos
20328c506b8Sjruoho /*
20428c506b8Sjruoho * Compute Tick Delta:
20528c506b8Sjruoho * Handle (max one) timer rollovers on 24-bit versus 32-bit timers.
20628c506b8Sjruoho */
207b406f703Schristos DeltaTicks = EndTicks;
208b406f703Schristos if (StartTicks > EndTicks)
20928c506b8Sjruoho {
21028c506b8Sjruoho if ((AcpiGbl_FADT.Flags & ACPI_FADT_32BIT_TIMER) == 0)
21128c506b8Sjruoho {
21228c506b8Sjruoho /* 24-bit Timer */
21328c506b8Sjruoho
214b406f703Schristos DeltaTicks |= (UINT64) 1 << 24;
21528c506b8Sjruoho }
21628c506b8Sjruoho else
21728c506b8Sjruoho {
21828c506b8Sjruoho /* 32-bit Timer */
21928c506b8Sjruoho
220b406f703Schristos DeltaTicks |= (UINT64) 1 << 32;
22128c506b8Sjruoho }
22228c506b8Sjruoho }
223b406f703Schristos DeltaTicks -= StartTicks;
22428c506b8Sjruoho
22528c506b8Sjruoho /*
22628c506b8Sjruoho * Compute Duration (Requires a 64-bit multiply and divide):
22728c506b8Sjruoho *
228ff4a156dSchristos * TimeElapsed (microseconds) =
229ff4a156dSchristos * (DeltaTicks * ACPI_USEC_PER_SEC) / ACPI_PM_TIMER_FREQUENCY;
23028c506b8Sjruoho */
231b406f703Schristos Status = AcpiUtShortDivide (DeltaTicks * ACPI_USEC_PER_SEC,
232ff4a156dSchristos ACPI_PM_TIMER_FREQUENCY, &Quotient, NULL);
23328c506b8Sjruoho
23428c506b8Sjruoho *TimeElapsed = (UINT32) Quotient;
23528c506b8Sjruoho return_ACPI_STATUS (Status);
23628c506b8Sjruoho }
23728c506b8Sjruoho
23828c506b8Sjruoho ACPI_EXPORT_SYMBOL (AcpiGetTimerDuration)
23928c506b8Sjruoho
240ff4a156dSchristos #endif /* !ACPI_REDUCED_HARDWARE */
241