162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
262306a36Sopenharmony_ci/******************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Name: hwesleep.c - ACPI Hardware Sleep/Wake Support functions for the
562306a36Sopenharmony_ci *                    extended FADT-V5 sleep registers.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright (C) 2000 - 2023, Intel Corp.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci *****************************************************************************/
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <acpi/acpi.h>
1262306a36Sopenharmony_ci#include "accommon.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#define _COMPONENT          ACPI_HARDWARE
1562306a36Sopenharmony_ciACPI_MODULE_NAME("hwesleep")
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci/*******************************************************************************
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci * FUNCTION:    acpi_hw_execute_sleep_method
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * PARAMETERS:  method_pathname     - Pathname of method to execute
2262306a36Sopenharmony_ci *              integer_argument    - Argument to pass to the method
2362306a36Sopenharmony_ci *
2462306a36Sopenharmony_ci * RETURN:      None
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci * DESCRIPTION: Execute a sleep/wake related method with one integer argument
2762306a36Sopenharmony_ci *              and no return value.
2862306a36Sopenharmony_ci *
2962306a36Sopenharmony_ci ******************************************************************************/
3062306a36Sopenharmony_civoid acpi_hw_execute_sleep_method(char *method_pathname, u32 integer_argument)
3162306a36Sopenharmony_ci{
3262306a36Sopenharmony_ci	struct acpi_object_list arg_list;
3362306a36Sopenharmony_ci	union acpi_object arg;
3462306a36Sopenharmony_ci	acpi_status status;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(hw_execute_sleep_method);
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	/* One argument, integer_argument; No return value expected */
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	arg_list.count = 1;
4162306a36Sopenharmony_ci	arg_list.pointer = &arg;
4262306a36Sopenharmony_ci	arg.type = ACPI_TYPE_INTEGER;
4362306a36Sopenharmony_ci	arg.integer.value = (u64)integer_argument;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	status = acpi_evaluate_object(NULL, method_pathname, &arg_list, NULL);
4662306a36Sopenharmony_ci	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
4762306a36Sopenharmony_ci		ACPI_EXCEPTION((AE_INFO, status, "While executing method %s",
4862306a36Sopenharmony_ci				method_pathname));
4962306a36Sopenharmony_ci	}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	return_VOID;
5262306a36Sopenharmony_ci}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci/*******************************************************************************
5562306a36Sopenharmony_ci *
5662306a36Sopenharmony_ci * FUNCTION:    acpi_hw_extended_sleep
5762306a36Sopenharmony_ci *
5862306a36Sopenharmony_ci * PARAMETERS:  sleep_state         - Which sleep state to enter
5962306a36Sopenharmony_ci *
6062306a36Sopenharmony_ci * RETURN:      Status
6162306a36Sopenharmony_ci *
6262306a36Sopenharmony_ci * DESCRIPTION: Enter a system sleep state via the extended FADT sleep
6362306a36Sopenharmony_ci *              registers (V5 FADT).
6462306a36Sopenharmony_ci *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
6562306a36Sopenharmony_ci *
6662306a36Sopenharmony_ci ******************************************************************************/
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ciacpi_status acpi_hw_extended_sleep(u8 sleep_state)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	acpi_status status;
7162306a36Sopenharmony_ci	u8 sleep_control;
7262306a36Sopenharmony_ci	u64 sleep_status;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(hw_extended_sleep);
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	/* Extended sleep registers must be valid */
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	if (!acpi_gbl_FADT.sleep_control.address ||
7962306a36Sopenharmony_ci	    !acpi_gbl_FADT.sleep_status.address) {
8062306a36Sopenharmony_ci		return_ACPI_STATUS(AE_NOT_EXIST);
8162306a36Sopenharmony_ci	}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	/* Clear wake status (WAK_STS) */
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	status = acpi_write((u64)ACPI_X_WAKE_STATUS,
8662306a36Sopenharmony_ci			    &acpi_gbl_FADT.sleep_status);
8762306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
8862306a36Sopenharmony_ci		return_ACPI_STATUS(status);
8962306a36Sopenharmony_ci	}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	acpi_gbl_system_awake_and_running = FALSE;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	/*
9462306a36Sopenharmony_ci	 * Set the SLP_TYP and SLP_EN bits.
9562306a36Sopenharmony_ci	 *
9662306a36Sopenharmony_ci	 * Note: We only use the first value returned by the \_Sx method
9762306a36Sopenharmony_ci	 * (acpi_gbl_sleep_type_a) - As per ACPI specification.
9862306a36Sopenharmony_ci	 */
9962306a36Sopenharmony_ci	ACPI_DEBUG_PRINT((ACPI_DB_INIT,
10062306a36Sopenharmony_ci			  "Entering sleep state [S%u]\n", sleep_state));
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	sleep_control = ((acpi_gbl_sleep_type_a << ACPI_X_SLEEP_TYPE_POSITION) &
10362306a36Sopenharmony_ci			 ACPI_X_SLEEP_TYPE_MASK) | ACPI_X_SLEEP_ENABLE;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	/* Flush caches, as per ACPI specification */
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	if (sleep_state < ACPI_STATE_S4) {
10862306a36Sopenharmony_ci		ACPI_FLUSH_CPU_CACHE();
10962306a36Sopenharmony_ci	}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	status = acpi_os_enter_sleep(sleep_state, sleep_control, 0);
11262306a36Sopenharmony_ci	if (status == AE_CTRL_TERMINATE) {
11362306a36Sopenharmony_ci		return_ACPI_STATUS(AE_OK);
11462306a36Sopenharmony_ci	}
11562306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
11662306a36Sopenharmony_ci		return_ACPI_STATUS(status);
11762306a36Sopenharmony_ci	}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	status = acpi_write((u64)sleep_control, &acpi_gbl_FADT.sleep_control);
12062306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
12162306a36Sopenharmony_ci		return_ACPI_STATUS(status);
12262306a36Sopenharmony_ci	}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	/* Wait for transition back to Working State */
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	do {
12762306a36Sopenharmony_ci		status = acpi_read(&sleep_status, &acpi_gbl_FADT.sleep_status);
12862306a36Sopenharmony_ci		if (ACPI_FAILURE(status)) {
12962306a36Sopenharmony_ci			return_ACPI_STATUS(status);
13062306a36Sopenharmony_ci		}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	} while (!(((u8)sleep_status) & ACPI_X_WAKE_STATUS));
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	return_ACPI_STATUS(AE_OK);
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci/*******************************************************************************
13862306a36Sopenharmony_ci *
13962306a36Sopenharmony_ci * FUNCTION:    acpi_hw_extended_wake_prep
14062306a36Sopenharmony_ci *
14162306a36Sopenharmony_ci * PARAMETERS:  sleep_state         - Which sleep state we just exited
14262306a36Sopenharmony_ci *
14362306a36Sopenharmony_ci * RETURN:      Status
14462306a36Sopenharmony_ci *
14562306a36Sopenharmony_ci * DESCRIPTION: Perform first part of OS-independent ACPI cleanup after
14662306a36Sopenharmony_ci *              a sleep. Called with interrupts ENABLED.
14762306a36Sopenharmony_ci *
14862306a36Sopenharmony_ci ******************************************************************************/
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ciacpi_status acpi_hw_extended_wake_prep(u8 sleep_state)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	u8 sleep_type_value;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(hw_extended_wake_prep);
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	if (acpi_gbl_sleep_type_a_s0 != ACPI_SLEEP_TYPE_INVALID) {
15762306a36Sopenharmony_ci		sleep_type_value =
15862306a36Sopenharmony_ci		    ((acpi_gbl_sleep_type_a_s0 << ACPI_X_SLEEP_TYPE_POSITION) &
15962306a36Sopenharmony_ci		     ACPI_X_SLEEP_TYPE_MASK);
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci		(void)acpi_write((u64)(sleep_type_value | ACPI_X_SLEEP_ENABLE),
16262306a36Sopenharmony_ci				 &acpi_gbl_FADT.sleep_control);
16362306a36Sopenharmony_ci	}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	return_ACPI_STATUS(AE_OK);
16662306a36Sopenharmony_ci}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci/*******************************************************************************
16962306a36Sopenharmony_ci *
17062306a36Sopenharmony_ci * FUNCTION:    acpi_hw_extended_wake
17162306a36Sopenharmony_ci *
17262306a36Sopenharmony_ci * PARAMETERS:  sleep_state         - Which sleep state we just exited
17362306a36Sopenharmony_ci *
17462306a36Sopenharmony_ci * RETURN:      Status
17562306a36Sopenharmony_ci *
17662306a36Sopenharmony_ci * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep
17762306a36Sopenharmony_ci *              Called with interrupts ENABLED.
17862306a36Sopenharmony_ci *
17962306a36Sopenharmony_ci ******************************************************************************/
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ciacpi_status acpi_hw_extended_wake(u8 sleep_state)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(hw_extended_wake);
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	/* Ensure enter_sleep_state_prep -> enter_sleep_state ordering */
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	acpi_gbl_sleep_type_a = ACPI_SLEEP_TYPE_INVALID;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	/* Execute the wake methods */
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, ACPI_SST_WAKING);
19262306a36Sopenharmony_ci	acpi_hw_execute_sleep_method(METHOD_PATHNAME__WAK, sleep_state);
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	/*
19562306a36Sopenharmony_ci	 * Some BIOS code assumes that WAK_STS will be cleared on resume
19662306a36Sopenharmony_ci	 * and use it to determine whether the system is rebooting or
19762306a36Sopenharmony_ci	 * resuming. Clear WAK_STS for compatibility.
19862306a36Sopenharmony_ci	 */
19962306a36Sopenharmony_ci	(void)acpi_write((u64)ACPI_X_WAKE_STATUS, &acpi_gbl_FADT.sleep_status);
20062306a36Sopenharmony_ci	acpi_gbl_system_awake_and_running = TRUE;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, ACPI_SST_WORKING);
20362306a36Sopenharmony_ci	return_ACPI_STATUS(AE_OK);
20462306a36Sopenharmony_ci}
205