| 1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 | 
|---|
| 2 | /****************************************************************************** | 
|---|
| 3 | * | 
|---|
| 4 | * Name: hwesleep.c - ACPI Hardware Sleep/Wake Support functions for the | 
|---|
| 5 | *                    extended FADT-V5 sleep registers. | 
|---|
| 6 | * | 
|---|
| 7 | * Copyright (C) 2000 - 2025, Intel Corp. | 
|---|
| 8 | * | 
|---|
| 9 | *****************************************************************************/ | 
|---|
| 10 |  | 
|---|
| 11 | #include <acpi/acpi.h> | 
|---|
| 12 | #include "accommon.h" | 
|---|
| 13 |  | 
|---|
| 14 | #define _COMPONENT          ACPI_HARDWARE | 
|---|
| 15 | ACPI_MODULE_NAME( "hwesleep") | 
|---|
| 16 |  | 
|---|
| 17 | /******************************************************************************* | 
|---|
| 18 | * | 
|---|
| 19 | * FUNCTION:    acpi_hw_execute_sleep_method | 
|---|
| 20 | * | 
|---|
| 21 | * PARAMETERS:  method_pathname     - Pathname of method to execute | 
|---|
| 22 | *              integer_argument    - Argument to pass to the method | 
|---|
| 23 | * | 
|---|
| 24 | * RETURN:      None | 
|---|
| 25 | * | 
|---|
| 26 | * DESCRIPTION: Execute a sleep/wake related method with one integer argument | 
|---|
| 27 | *              and no return value. | 
|---|
| 28 | * | 
|---|
| 29 | ******************************************************************************/ | 
|---|
| 30 | void acpi_hw_execute_sleep_method(char *method_pathname, u32 integer_argument) | 
|---|
| 31 | { | 
|---|
| 32 | struct acpi_object_list arg_list; | 
|---|
| 33 | union acpi_object arg; | 
|---|
| 34 | acpi_status status; | 
|---|
| 35 |  | 
|---|
| 36 | ACPI_FUNCTION_TRACE(hw_execute_sleep_method); | 
|---|
| 37 |  | 
|---|
| 38 | /* One argument, integer_argument; No return value expected */ | 
|---|
| 39 |  | 
|---|
| 40 | arg_list.count = 1; | 
|---|
| 41 | arg_list.pointer = &arg; | 
|---|
| 42 | arg.type = ACPI_TYPE_INTEGER; | 
|---|
| 43 | arg.integer.value = (u64)integer_argument; | 
|---|
| 44 |  | 
|---|
| 45 | status = acpi_evaluate_object(NULL, pathname: method_pathname, parameter_objects: &arg_list, NULL); | 
|---|
| 46 | if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { | 
|---|
| 47 | ACPI_EXCEPTION((AE_INFO, status, "While executing method %s", | 
|---|
| 48 | method_pathname)); | 
|---|
| 49 | } | 
|---|
| 50 |  | 
|---|
| 51 | return_VOID; | 
|---|
| 52 | } | 
|---|
| 53 |  | 
|---|
| 54 | /******************************************************************************* | 
|---|
| 55 | * | 
|---|
| 56 | * FUNCTION:    acpi_hw_extended_sleep | 
|---|
| 57 | * | 
|---|
| 58 | * PARAMETERS:  sleep_state         - Which sleep state to enter | 
|---|
| 59 | * | 
|---|
| 60 | * RETURN:      Status | 
|---|
| 61 | * | 
|---|
| 62 | * DESCRIPTION: Enter a system sleep state via the extended FADT sleep | 
|---|
| 63 | *              registers (V5 FADT). | 
|---|
| 64 | *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED | 
|---|
| 65 | * | 
|---|
| 66 | ******************************************************************************/ | 
|---|
| 67 |  | 
|---|
| 68 | acpi_status acpi_hw_extended_sleep(u8 sleep_state) | 
|---|
| 69 | { | 
|---|
| 70 | acpi_status status; | 
|---|
| 71 | u8 sleep_control; | 
|---|
| 72 | u64 sleep_status; | 
|---|
| 73 |  | 
|---|
| 74 | ACPI_FUNCTION_TRACE(hw_extended_sleep); | 
|---|
| 75 |  | 
|---|
| 76 | /* Extended sleep registers must be valid */ | 
|---|
| 77 |  | 
|---|
| 78 | if (!acpi_gbl_FADT.sleep_control.address || | 
|---|
| 79 | !acpi_gbl_FADT.sleep_status.address) { | 
|---|
| 80 | return_ACPI_STATUS(AE_NOT_EXIST); | 
|---|
| 81 | } | 
|---|
| 82 |  | 
|---|
| 83 | /* Clear wake status (WAK_STS) */ | 
|---|
| 84 |  | 
|---|
| 85 | status = acpi_write(value: (u64)ACPI_X_WAKE_STATUS, | 
|---|
| 86 | reg: &acpi_gbl_FADT.sleep_status); | 
|---|
| 87 | if (ACPI_FAILURE(status)) { | 
|---|
| 88 | return_ACPI_STATUS(status); | 
|---|
| 89 | } | 
|---|
| 90 |  | 
|---|
| 91 | acpi_gbl_system_awake_and_running = FALSE; | 
|---|
| 92 |  | 
|---|
| 93 | /* | 
|---|
| 94 | * Set the SLP_TYP and SLP_EN bits. | 
|---|
| 95 | * | 
|---|
| 96 | * Note: We only use the first value returned by the \_Sx method | 
|---|
| 97 | * (acpi_gbl_sleep_type_a) - As per ACPI specification. | 
|---|
| 98 | */ | 
|---|
| 99 | ACPI_DEBUG_PRINT((ACPI_DB_INIT, | 
|---|
| 100 | "Entering sleep state [S%u]\n", sleep_state)); | 
|---|
| 101 |  | 
|---|
| 102 | sleep_control = ((acpi_gbl_sleep_type_a << ACPI_X_SLEEP_TYPE_POSITION) & | 
|---|
| 103 | ACPI_X_SLEEP_TYPE_MASK) | ACPI_X_SLEEP_ENABLE; | 
|---|
| 104 |  | 
|---|
| 105 | /* Flush caches, as per ACPI specification */ | 
|---|
| 106 |  | 
|---|
| 107 | if (sleep_state < ACPI_STATE_S4) { | 
|---|
| 108 | ACPI_FLUSH_CPU_CACHE(); | 
|---|
| 109 | } | 
|---|
| 110 |  | 
|---|
| 111 | status = acpi_os_enter_sleep(sleep_state, rega_value: sleep_control, regb_value: 0); | 
|---|
| 112 | if (status == AE_CTRL_TERMINATE) { | 
|---|
| 113 | return_ACPI_STATUS(AE_OK); | 
|---|
| 114 | } | 
|---|
| 115 | if (ACPI_FAILURE(status)) { | 
|---|
| 116 | return_ACPI_STATUS(status); | 
|---|
| 117 | } | 
|---|
| 118 |  | 
|---|
| 119 | status = acpi_write(value: (u64)sleep_control, reg: &acpi_gbl_FADT.sleep_control); | 
|---|
| 120 | if (ACPI_FAILURE(status)) { | 
|---|
| 121 | return_ACPI_STATUS(status); | 
|---|
| 122 | } | 
|---|
| 123 |  | 
|---|
| 124 | /* Wait for transition back to Working State */ | 
|---|
| 125 |  | 
|---|
| 126 | do { | 
|---|
| 127 | status = acpi_read(value: &sleep_status, reg: &acpi_gbl_FADT.sleep_status); | 
|---|
| 128 | if (ACPI_FAILURE(status)) { | 
|---|
| 129 | return_ACPI_STATUS(status); | 
|---|
| 130 | } | 
|---|
| 131 |  | 
|---|
| 132 | } while (!(((u8)sleep_status) & ACPI_X_WAKE_STATUS)); | 
|---|
| 133 |  | 
|---|
| 134 | return_ACPI_STATUS(AE_OK); | 
|---|
| 135 | } | 
|---|
| 136 |  | 
|---|
| 137 | /******************************************************************************* | 
|---|
| 138 | * | 
|---|
| 139 | * FUNCTION:    acpi_hw_extended_wake_prep | 
|---|
| 140 | * | 
|---|
| 141 | * PARAMETERS:  sleep_state         - Which sleep state we just exited | 
|---|
| 142 | * | 
|---|
| 143 | * RETURN:      Status | 
|---|
| 144 | * | 
|---|
| 145 | * DESCRIPTION: Perform first part of OS-independent ACPI cleanup after | 
|---|
| 146 | *              a sleep. Called with interrupts ENABLED. | 
|---|
| 147 | * | 
|---|
| 148 | ******************************************************************************/ | 
|---|
| 149 |  | 
|---|
| 150 | acpi_status acpi_hw_extended_wake_prep(u8 sleep_state) | 
|---|
| 151 | { | 
|---|
| 152 | u8 sleep_type_value; | 
|---|
| 153 |  | 
|---|
| 154 | ACPI_FUNCTION_TRACE(hw_extended_wake_prep); | 
|---|
| 155 |  | 
|---|
| 156 | if (acpi_gbl_sleep_type_a_s0 != ACPI_SLEEP_TYPE_INVALID) { | 
|---|
| 157 | sleep_type_value = | 
|---|
| 158 | ((acpi_gbl_sleep_type_a_s0 << ACPI_X_SLEEP_TYPE_POSITION) & | 
|---|
| 159 | ACPI_X_SLEEP_TYPE_MASK); | 
|---|
| 160 |  | 
|---|
| 161 | (void)acpi_write(value: (u64)(sleep_type_value | ACPI_X_SLEEP_ENABLE), | 
|---|
| 162 | reg: &acpi_gbl_FADT.sleep_control); | 
|---|
| 163 | } | 
|---|
| 164 |  | 
|---|
| 165 | return_ACPI_STATUS(AE_OK); | 
|---|
| 166 | } | 
|---|
| 167 |  | 
|---|
| 168 | /******************************************************************************* | 
|---|
| 169 | * | 
|---|
| 170 | * FUNCTION:    acpi_hw_extended_wake | 
|---|
| 171 | * | 
|---|
| 172 | * PARAMETERS:  sleep_state         - Which sleep state we just exited | 
|---|
| 173 | * | 
|---|
| 174 | * RETURN:      Status | 
|---|
| 175 | * | 
|---|
| 176 | * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep | 
|---|
| 177 | *              Called with interrupts ENABLED. | 
|---|
| 178 | * | 
|---|
| 179 | ******************************************************************************/ | 
|---|
| 180 |  | 
|---|
| 181 | acpi_status acpi_hw_extended_wake(u8 sleep_state) | 
|---|
| 182 | { | 
|---|
| 183 | ACPI_FUNCTION_TRACE(hw_extended_wake); | 
|---|
| 184 |  | 
|---|
| 185 | /* Ensure enter_sleep_state_prep -> enter_sleep_state ordering */ | 
|---|
| 186 |  | 
|---|
| 187 | acpi_gbl_sleep_type_a = ACPI_SLEEP_TYPE_INVALID; | 
|---|
| 188 |  | 
|---|
| 189 | /* Execute the wake methods */ | 
|---|
| 190 |  | 
|---|
| 191 | acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, ACPI_SST_WAKING); | 
|---|
| 192 | acpi_hw_execute_sleep_method(METHOD_PATHNAME__WAK, integer_argument: sleep_state); | 
|---|
| 193 |  | 
|---|
| 194 | /* | 
|---|
| 195 | * Some BIOS code assumes that WAK_STS will be cleared on resume | 
|---|
| 196 | * and use it to determine whether the system is rebooting or | 
|---|
| 197 | * resuming. Clear WAK_STS for compatibility. | 
|---|
| 198 | */ | 
|---|
| 199 | (void)acpi_write(value: (u64)ACPI_X_WAKE_STATUS, reg: &acpi_gbl_FADT.sleep_status); | 
|---|
| 200 | acpi_gbl_system_awake_and_running = TRUE; | 
|---|
| 201 |  | 
|---|
| 202 | acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, ACPI_SST_WORKING); | 
|---|
| 203 | return_ACPI_STATUS(AE_OK); | 
|---|
| 204 | } | 
|---|
| 205 |  | 
|---|