195857638SErik Schmauss // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
270958576SBob Moore /******************************************************************************
370958576SBob Moore *
470958576SBob Moore * Name: hwesleep.c - ACPI Hardware Sleep/Wake Support functions for the
570958576SBob Moore * extended FADT-V5 sleep registers.
670958576SBob Moore *
7*612c2932SBob Moore * Copyright (C) 2000 - 2023, Intel Corp.
870958576SBob Moore *
995857638SErik Schmauss *****************************************************************************/
1070958576SBob Moore
1170958576SBob Moore #include <acpi/acpi.h>
1270958576SBob Moore #include "accommon.h"
1370958576SBob Moore
1470958576SBob Moore #define _COMPONENT ACPI_HARDWARE
1570958576SBob Moore ACPI_MODULE_NAME("hwesleep")
1670958576SBob Moore
1770958576SBob Moore /*******************************************************************************
1870958576SBob Moore *
1970958576SBob Moore * FUNCTION: acpi_hw_execute_sleep_method
2070958576SBob Moore *
214efeeecdSBob Moore * PARAMETERS: method_pathname - Pathname of method to execute
2270958576SBob Moore * integer_argument - Argument to pass to the method
2370958576SBob Moore *
2470958576SBob Moore * RETURN: None
2570958576SBob Moore *
2670958576SBob Moore * DESCRIPTION: Execute a sleep/wake related method with one integer argument
2770958576SBob Moore * and no return value.
2870958576SBob Moore *
2970958576SBob Moore ******************************************************************************/
acpi_hw_execute_sleep_method(char * method_pathname,u32 integer_argument)304efeeecdSBob Moore void acpi_hw_execute_sleep_method(char *method_pathname, u32 integer_argument)
3170958576SBob Moore {
3270958576SBob Moore struct acpi_object_list arg_list;
3370958576SBob Moore union acpi_object arg;
3470958576SBob Moore acpi_status status;
3570958576SBob Moore
3670958576SBob Moore ACPI_FUNCTION_TRACE(hw_execute_sleep_method);
3770958576SBob Moore
3870958576SBob Moore /* One argument, integer_argument; No return value expected */
3970958576SBob Moore
4070958576SBob Moore arg_list.count = 1;
4170958576SBob Moore arg_list.pointer = &arg;
4270958576SBob Moore arg.type = ACPI_TYPE_INTEGER;
4370958576SBob Moore arg.integer.value = (u64)integer_argument;
4470958576SBob Moore
454efeeecdSBob Moore status = acpi_evaluate_object(NULL, method_pathname, &arg_list, NULL);
4670958576SBob Moore if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
4770958576SBob Moore ACPI_EXCEPTION((AE_INFO, status, "While executing method %s",
484efeeecdSBob Moore method_pathname));
4970958576SBob Moore }
5070958576SBob Moore
5170958576SBob Moore return_VOID;
5270958576SBob Moore }
5370958576SBob Moore
5470958576SBob Moore /*******************************************************************************
5570958576SBob Moore *
5670958576SBob Moore * FUNCTION: acpi_hw_extended_sleep
5770958576SBob Moore *
5870958576SBob Moore * PARAMETERS: sleep_state - Which sleep state to enter
5970958576SBob Moore *
6070958576SBob Moore * RETURN: Status
6170958576SBob Moore *
6270958576SBob Moore * DESCRIPTION: Enter a system sleep state via the extended FADT sleep
6370958576SBob Moore * registers (V5 FADT).
6470958576SBob Moore * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
6570958576SBob Moore *
6670958576SBob Moore ******************************************************************************/
6770958576SBob Moore
acpi_hw_extended_sleep(u8 sleep_state)683f6f49c7SLen Brown acpi_status acpi_hw_extended_sleep(u8 sleep_state)
6970958576SBob Moore {
7070958576SBob Moore acpi_status status;
710fc5e8f4SLv Zheng u8 sleep_control;
7270958576SBob Moore u64 sleep_status;
7370958576SBob Moore
7470958576SBob Moore ACPI_FUNCTION_TRACE(hw_extended_sleep);
7570958576SBob Moore
7670958576SBob Moore /* Extended sleep registers must be valid */
7770958576SBob Moore
7870958576SBob Moore if (!acpi_gbl_FADT.sleep_control.address ||
7970958576SBob Moore !acpi_gbl_FADT.sleep_status.address) {
8070958576SBob Moore return_ACPI_STATUS(AE_NOT_EXIST);
8170958576SBob Moore }
8270958576SBob Moore
8370958576SBob Moore /* Clear wake status (WAK_STS) */
8470958576SBob Moore
851fad8738SBob Moore status = acpi_write((u64)ACPI_X_WAKE_STATUS,
861fad8738SBob Moore &acpi_gbl_FADT.sleep_status);
8770958576SBob Moore if (ACPI_FAILURE(status)) {
8870958576SBob Moore return_ACPI_STATUS(status);
8970958576SBob Moore }
9070958576SBob Moore
9170958576SBob Moore acpi_gbl_system_awake_and_running = FALSE;
9270958576SBob Moore
9370958576SBob Moore /*
9470958576SBob Moore * Set the SLP_TYP and SLP_EN bits.
9570958576SBob Moore *
9670958576SBob Moore * Note: We only use the first value returned by the \_Sx method
9770958576SBob Moore * (acpi_gbl_sleep_type_a) - As per ACPI specification.
9870958576SBob Moore */
9970958576SBob Moore ACPI_DEBUG_PRINT((ACPI_DB_INIT,
10070958576SBob Moore "Entering sleep state [S%u]\n", sleep_state));
10170958576SBob Moore
1020fc5e8f4SLv Zheng sleep_control = ((acpi_gbl_sleep_type_a << ACPI_X_SLEEP_TYPE_POSITION) &
1030fc5e8f4SLv Zheng ACPI_X_SLEEP_TYPE_MASK) | ACPI_X_SLEEP_ENABLE;
10470958576SBob Moore
1050fc5e8f4SLv Zheng /* Flush caches, as per ACPI specification */
1060fc5e8f4SLv Zheng
1071d4e0b3aSKirill A. Shutemov if (sleep_state < ACPI_STATE_S4) {
1080fc5e8f4SLv Zheng ACPI_FLUSH_CPU_CACHE();
1091d4e0b3aSKirill A. Shutemov }
1100fc5e8f4SLv Zheng
1110fc5e8f4SLv Zheng status = acpi_os_enter_sleep(sleep_state, sleep_control, 0);
1120fc5e8f4SLv Zheng if (status == AE_CTRL_TERMINATE) {
1130fc5e8f4SLv Zheng return_ACPI_STATUS(AE_OK);
1140fc5e8f4SLv Zheng }
1150fc5e8f4SLv Zheng if (ACPI_FAILURE(status)) {
1160fc5e8f4SLv Zheng return_ACPI_STATUS(status);
1170fc5e8f4SLv Zheng }
1180fc5e8f4SLv Zheng
1190fc5e8f4SLv Zheng status = acpi_write((u64)sleep_control, &acpi_gbl_FADT.sleep_control);
12070958576SBob Moore if (ACPI_FAILURE(status)) {
12170958576SBob Moore return_ACPI_STATUS(status);
12270958576SBob Moore }
12370958576SBob Moore
12470958576SBob Moore /* Wait for transition back to Working State */
12570958576SBob Moore
12670958576SBob Moore do {
12770958576SBob Moore status = acpi_read(&sleep_status, &acpi_gbl_FADT.sleep_status);
12870958576SBob Moore if (ACPI_FAILURE(status)) {
12970958576SBob Moore return_ACPI_STATUS(status);
13070958576SBob Moore }
13170958576SBob Moore
13270958576SBob Moore } while (!(((u8)sleep_status) & ACPI_X_WAKE_STATUS));
13370958576SBob Moore
13470958576SBob Moore return_ACPI_STATUS(AE_OK);
13570958576SBob Moore }
13670958576SBob Moore
13770958576SBob Moore /*******************************************************************************
13870958576SBob Moore *
13970958576SBob Moore * FUNCTION: acpi_hw_extended_wake_prep
14070958576SBob Moore *
14170958576SBob Moore * PARAMETERS: sleep_state - Which sleep state we just exited
14270958576SBob Moore *
14370958576SBob Moore * RETURN: Status
14470958576SBob Moore *
14570958576SBob Moore * DESCRIPTION: Perform first part of OS-independent ACPI cleanup after
14670958576SBob Moore * a sleep. Called with interrupts ENABLED.
14770958576SBob Moore *
14870958576SBob Moore ******************************************************************************/
14970958576SBob Moore
acpi_hw_extended_wake_prep(u8 sleep_state)1503f6f49c7SLen Brown acpi_status acpi_hw_extended_wake_prep(u8 sleep_state)
15170958576SBob Moore {
15270958576SBob Moore u8 sleep_type_value;
15370958576SBob Moore
15470958576SBob Moore ACPI_FUNCTION_TRACE(hw_extended_wake_prep);
15570958576SBob Moore
156d3c4b6f6SRafael J. Wysocki if (acpi_gbl_sleep_type_a_s0 != ACPI_SLEEP_TYPE_INVALID) {
15770958576SBob Moore sleep_type_value =
158d3c4b6f6SRafael J. Wysocki ((acpi_gbl_sleep_type_a_s0 << ACPI_X_SLEEP_TYPE_POSITION) &
15970958576SBob Moore ACPI_X_SLEEP_TYPE_MASK);
16070958576SBob Moore
1615134abfcSBob Moore (void)acpi_write((u64)(sleep_type_value | ACPI_X_SLEEP_ENABLE),
16270958576SBob Moore &acpi_gbl_FADT.sleep_control);
16370958576SBob Moore }
16470958576SBob Moore
16570958576SBob Moore return_ACPI_STATUS(AE_OK);
16670958576SBob Moore }
16770958576SBob Moore
16870958576SBob Moore /*******************************************************************************
16970958576SBob Moore *
17070958576SBob Moore * FUNCTION: acpi_hw_extended_wake
17170958576SBob Moore *
17270958576SBob Moore * PARAMETERS: sleep_state - Which sleep state we just exited
17370958576SBob Moore *
17470958576SBob Moore * RETURN: Status
17570958576SBob Moore *
17670958576SBob Moore * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep
17770958576SBob Moore * Called with interrupts ENABLED.
17870958576SBob Moore *
17970958576SBob Moore ******************************************************************************/
18070958576SBob Moore
acpi_hw_extended_wake(u8 sleep_state)1813f6f49c7SLen Brown acpi_status acpi_hw_extended_wake(u8 sleep_state)
18270958576SBob Moore {
18370958576SBob Moore ACPI_FUNCTION_TRACE(hw_extended_wake);
18470958576SBob Moore
18570958576SBob Moore /* Ensure enter_sleep_state_prep -> enter_sleep_state ordering */
18670958576SBob Moore
18770958576SBob Moore acpi_gbl_sleep_type_a = ACPI_SLEEP_TYPE_INVALID;
18870958576SBob Moore
18970958576SBob Moore /* Execute the wake methods */
19070958576SBob Moore
1914efeeecdSBob Moore acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, ACPI_SST_WAKING);
1924efeeecdSBob Moore acpi_hw_execute_sleep_method(METHOD_PATHNAME__WAK, sleep_state);
19370958576SBob Moore
19470958576SBob Moore /*
19570958576SBob Moore * Some BIOS code assumes that WAK_STS will be cleared on resume
19670958576SBob Moore * and use it to determine whether the system is rebooting or
19770958576SBob Moore * resuming. Clear WAK_STS for compatibility.
19870958576SBob Moore */
1995134abfcSBob Moore (void)acpi_write((u64)ACPI_X_WAKE_STATUS, &acpi_gbl_FADT.sleep_status);
20070958576SBob Moore acpi_gbl_system_awake_and_running = TRUE;
20170958576SBob Moore
2024efeeecdSBob Moore acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, ACPI_SST_WORKING);
20370958576SBob Moore return_ACPI_STATUS(AE_OK);
20470958576SBob Moore }
205