xref: /openbmc/linux/drivers/acpi/acpica/hwxfsleep.c (revision 612c2932)
195857638SErik Schmauss // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
22feec47dSBob Moore /******************************************************************************
32feec47dSBob Moore  *
42feec47dSBob Moore  * Name: hwxfsleep.c - ACPI Hardware Sleep/Wake External Interfaces
52feec47dSBob Moore  *
6*612c2932SBob Moore  * Copyright (C) 2000 - 2023, Intel Corp.
72feec47dSBob Moore  *
895857638SErik Schmauss  *****************************************************************************/
92feec47dSBob Moore 
10839e928fSLv Zheng #define EXPORT_ACPI_INTERFACES
11839e928fSLv Zheng 
122feec47dSBob Moore #include <acpi/acpi.h>
132feec47dSBob Moore #include "accommon.h"
142feec47dSBob Moore 
152feec47dSBob Moore #define _COMPONENT          ACPI_HARDWARE
162feec47dSBob Moore ACPI_MODULE_NAME("hwxfsleep")
172feec47dSBob Moore 
1872a8887aSBob Moore /* Local prototypes */
19f06147f9SLv Zheng #if (!ACPI_REDUCED_HARDWARE)
20f06147f9SLv Zheng static acpi_status
21e3e9b577SRafael J. Wysocki acpi_hw_set_firmware_waking_vector(struct acpi_table_facs *facs,
22f06147f9SLv Zheng 				   acpi_physical_address physical_address,
23f06147f9SLv Zheng 				   acpi_physical_address physical_address64);
24f06147f9SLv Zheng #endif
25f06147f9SLv Zheng 
2672a8887aSBob Moore /*
2772a8887aSBob Moore  * These functions are removed for the ACPI_REDUCED_HARDWARE case:
2872a8887aSBob Moore  *      acpi_set_firmware_waking_vector
2972a8887aSBob Moore  *      acpi_enter_sleep_state_s4bios
3072a8887aSBob Moore  */
3172a8887aSBob Moore 
3233620c54SBob Moore #if (!ACPI_REDUCED_HARDWARE)
332feec47dSBob Moore /*******************************************************************************
342feec47dSBob Moore  *
35e3e9b577SRafael J. Wysocki  * FUNCTION:    acpi_hw_set_firmware_waking_vector
36f06147f9SLv Zheng  *
37f06147f9SLv Zheng  * PARAMETERS:  facs                - Pointer to FACS table
38f06147f9SLv Zheng  *              physical_address    - 32-bit physical address of ACPI real mode
39e3e9b577SRafael J. Wysocki  *                                    entry point
40f06147f9SLv Zheng  *              physical_address64  - 64-bit physical address of ACPI protected
41e3e9b577SRafael J. Wysocki  *                                    mode entry point
42f06147f9SLv Zheng  *
43f06147f9SLv Zheng  * RETURN:      Status
44f06147f9SLv Zheng  *
45f06147f9SLv Zheng  * DESCRIPTION: Sets the firmware_waking_vector fields of the FACS
46f06147f9SLv Zheng  *
47f06147f9SLv Zheng  ******************************************************************************/
48f06147f9SLv Zheng 
49f06147f9SLv Zheng static acpi_status
acpi_hw_set_firmware_waking_vector(struct acpi_table_facs * facs,acpi_physical_address physical_address,acpi_physical_address physical_address64)50e3e9b577SRafael J. Wysocki acpi_hw_set_firmware_waking_vector(struct acpi_table_facs *facs,
51f06147f9SLv Zheng 				   acpi_physical_address physical_address,
52f06147f9SLv Zheng 				   acpi_physical_address physical_address64)
53f06147f9SLv Zheng {
54e3e9b577SRafael J. Wysocki 	ACPI_FUNCTION_TRACE(acpi_hw_set_firmware_waking_vector);
55f06147f9SLv Zheng 
56f06147f9SLv Zheng 
57f06147f9SLv Zheng 	/*
58f06147f9SLv Zheng 	 * According to the ACPI specification 2.0c and later, the 64-bit
59f06147f9SLv Zheng 	 * waking vector should be cleared and the 32-bit waking vector should
60f06147f9SLv Zheng 	 * be used, unless we want the wake-up code to be called by the BIOS in
61f06147f9SLv Zheng 	 * Protected Mode.  Some systems (for example HP dv5-1004nr) are known
62f06147f9SLv Zheng 	 * to fail to resume if the 64-bit vector is used.
63f06147f9SLv Zheng 	 */
64f06147f9SLv Zheng 
65f06147f9SLv Zheng 	/* Set the 32-bit vector */
66f06147f9SLv Zheng 
67f06147f9SLv Zheng 	facs->firmware_waking_vector = (u32)physical_address;
68f06147f9SLv Zheng 
69f06147f9SLv Zheng 	if (facs->length > 32) {
70f06147f9SLv Zheng 		if (facs->version >= 1) {
71f06147f9SLv Zheng 
72f06147f9SLv Zheng 			/* Set the 64-bit vector */
73f06147f9SLv Zheng 
74f06147f9SLv Zheng 			facs->xfirmware_waking_vector = physical_address64;
75f06147f9SLv Zheng 		} else {
76f06147f9SLv Zheng 			/* Clear the 64-bit vector if it exists */
77f06147f9SLv Zheng 
78f06147f9SLv Zheng 			facs->xfirmware_waking_vector = 0;
79f06147f9SLv Zheng 		}
80f06147f9SLv Zheng 	}
81f06147f9SLv Zheng 
82f06147f9SLv Zheng 	return_ACPI_STATUS(AE_OK);
83f06147f9SLv Zheng }
84f06147f9SLv Zheng 
85f06147f9SLv Zheng /*******************************************************************************
86f06147f9SLv Zheng  *
87e3e9b577SRafael J. Wysocki  * FUNCTION:    acpi_set_firmware_waking_vector
882feec47dSBob Moore  *
892feec47dSBob Moore  * PARAMETERS:  physical_address    - 32-bit physical address of ACPI real mode
90e3e9b577SRafael J. Wysocki  *                                    entry point
91aca2a5d3SLv Zheng  *              physical_address64  - 64-bit physical address of ACPI protected
92e3e9b577SRafael J. Wysocki  *                                    mode entry point
932feec47dSBob Moore  *
942feec47dSBob Moore  * RETURN:      Status
952feec47dSBob Moore  *
96aca2a5d3SLv Zheng  * DESCRIPTION: Sets the firmware_waking_vector fields of the FACS
972feec47dSBob Moore  *
982feec47dSBob Moore  ******************************************************************************/
9972a8887aSBob Moore 
100aca2a5d3SLv Zheng acpi_status
acpi_set_firmware_waking_vector(acpi_physical_address physical_address,acpi_physical_address physical_address64)101e3e9b577SRafael J. Wysocki acpi_set_firmware_waking_vector(acpi_physical_address physical_address,
102aca2a5d3SLv Zheng 				acpi_physical_address physical_address64)
1032feec47dSBob Moore {
104f06147f9SLv Zheng 
105e3e9b577SRafael J. Wysocki 	ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector);
1062feec47dSBob Moore 
1077484619bSLv Zheng 	if (acpi_gbl_FACS) {
108e3e9b577SRafael J. Wysocki 		(void)acpi_hw_set_firmware_waking_vector(acpi_gbl_FACS,
109f06147f9SLv Zheng 							 physical_address,
110f06147f9SLv Zheng 							 physical_address64);
111aca2a5d3SLv Zheng 	}
1122feec47dSBob Moore 
1132feec47dSBob Moore 	return_ACPI_STATUS(AE_OK);
1142feec47dSBob Moore }
1152feec47dSBob Moore 
ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector)1162feec47dSBob Moore ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector)
1172feec47dSBob Moore 
1182feec47dSBob Moore /*******************************************************************************
1192feec47dSBob Moore  *
1202feec47dSBob Moore  * FUNCTION:    acpi_enter_sleep_state_s4bios
1212feec47dSBob Moore  *
1222feec47dSBob Moore  * PARAMETERS:  None
1232feec47dSBob Moore  *
1242feec47dSBob Moore  * RETURN:      Status
1252feec47dSBob Moore  *
1262feec47dSBob Moore  * DESCRIPTION: Perform a S4 bios request.
1272feec47dSBob Moore  *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
1282feec47dSBob Moore  *
1292feec47dSBob Moore  ******************************************************************************/
13040bce100SLv Zheng acpi_status acpi_enter_sleep_state_s4bios(void)
1312feec47dSBob Moore {
1322feec47dSBob Moore 	u32 in_value;
1332feec47dSBob Moore 	acpi_status status;
1342feec47dSBob Moore 
1352feec47dSBob Moore 	ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_s4bios);
1362feec47dSBob Moore 
1372feec47dSBob Moore 	/* Clear the wake status bit (PM1) */
1382feec47dSBob Moore 
1392feec47dSBob Moore 	status =
1402feec47dSBob Moore 	    acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS);
1412feec47dSBob Moore 	if (ACPI_FAILURE(status)) {
1422feec47dSBob Moore 		return_ACPI_STATUS(status);
1432feec47dSBob Moore 	}
1442feec47dSBob Moore 
1452feec47dSBob Moore 	status = acpi_hw_clear_acpi_status();
1462feec47dSBob Moore 	if (ACPI_FAILURE(status)) {
1472feec47dSBob Moore 		return_ACPI_STATUS(status);
1482feec47dSBob Moore 	}
1492feec47dSBob Moore 
1502feec47dSBob Moore 	/*
15118996f2dSErik Schmauss 	 * 1) Disable all GPEs
1522feec47dSBob Moore 	 * 2) Enable all wakeup GPEs
1532feec47dSBob Moore 	 */
1542feec47dSBob Moore 	status = acpi_hw_disable_all_gpes();
1552feec47dSBob Moore 	if (ACPI_FAILURE(status)) {
1562feec47dSBob Moore 		return_ACPI_STATUS(status);
1572feec47dSBob Moore 	}
1582feec47dSBob Moore 	acpi_gbl_system_awake_and_running = FALSE;
1592feec47dSBob Moore 
1602feec47dSBob Moore 	status = acpi_hw_enable_all_wakeup_gpes();
1612feec47dSBob Moore 	if (ACPI_FAILURE(status)) {
1622feec47dSBob Moore 		return_ACPI_STATUS(status);
1632feec47dSBob Moore 	}
1642feec47dSBob Moore 
1652feec47dSBob Moore 	status = acpi_hw_write_port(acpi_gbl_FADT.smi_command,
166ba494beeSBob Moore 				    (u32)acpi_gbl_FADT.s4_bios_request, 8);
167aaf7566fSBob Moore 	if (ACPI_FAILURE(status)) {
168aaf7566fSBob Moore 		return_ACPI_STATUS(status);
169aaf7566fSBob Moore 	}
1702feec47dSBob Moore 
1712feec47dSBob Moore 	do {
172c41679a4SBob Moore 		acpi_os_stall(ACPI_USEC_PER_MSEC);
1732feec47dSBob Moore 		status =
1742feec47dSBob Moore 		    acpi_read_bit_register(ACPI_BITREG_WAKE_STATUS, &in_value);
1752feec47dSBob Moore 		if (ACPI_FAILURE(status)) {
1762feec47dSBob Moore 			return_ACPI_STATUS(status);
1772feec47dSBob Moore 		}
1781fad8738SBob Moore 
1792feec47dSBob Moore 	} while (!in_value);
1802feec47dSBob Moore 
1812feec47dSBob Moore 	return_ACPI_STATUS(AE_OK);
1822feec47dSBob Moore }
1832feec47dSBob Moore 
ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_s4bios)1842feec47dSBob Moore ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_s4bios)
18533620c54SBob Moore #endif				/* !ACPI_REDUCED_HARDWARE */
18672a8887aSBob Moore 
18772a8887aSBob Moore /*******************************************************************************
18872a8887aSBob Moore  *
1892feec47dSBob Moore  * FUNCTION:    acpi_enter_sleep_state_prep
1902feec47dSBob Moore  *
1912feec47dSBob Moore  * PARAMETERS:  sleep_state         - Which sleep state to enter
1922feec47dSBob Moore  *
1932feec47dSBob Moore  * RETURN:      Status
1942feec47dSBob Moore  *
19572a8887aSBob Moore  * DESCRIPTION: Prepare to enter a system sleep state.
1962feec47dSBob Moore  *              This function must execute with interrupts enabled.
1972feec47dSBob Moore  *              We break sleeping into 2 stages so that OSPM can handle
1982feec47dSBob Moore  *              various OS-specific tasks between the two steps.
1992feec47dSBob Moore  *
2002feec47dSBob Moore  ******************************************************************************/
20172a8887aSBob Moore 
2022feec47dSBob Moore acpi_status acpi_enter_sleep_state_prep(u8 sleep_state)
2032feec47dSBob Moore {
2042feec47dSBob Moore 	acpi_status status;
2052feec47dSBob Moore 	struct acpi_object_list arg_list;
2062feec47dSBob Moore 	union acpi_object arg;
2072feec47dSBob Moore 	u32 sst_value;
2082feec47dSBob Moore 
2092feec47dSBob Moore 	ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_prep);
2102feec47dSBob Moore 
2112feec47dSBob Moore 	status = acpi_get_sleep_type_data(sleep_state,
2122feec47dSBob Moore 					  &acpi_gbl_sleep_type_a,
2132feec47dSBob Moore 					  &acpi_gbl_sleep_type_b);
2142feec47dSBob Moore 	if (ACPI_FAILURE(status)) {
2152feec47dSBob Moore 		return_ACPI_STATUS(status);
2162feec47dSBob Moore 	}
2172feec47dSBob Moore 
218d3c4b6f6SRafael J. Wysocki 	status = acpi_get_sleep_type_data(ACPI_STATE_S0,
219d3c4b6f6SRafael J. Wysocki 					  &acpi_gbl_sleep_type_a_s0,
220d3c4b6f6SRafael J. Wysocki 					  &acpi_gbl_sleep_type_b_s0);
221d3c4b6f6SRafael J. Wysocki 	if (ACPI_FAILURE(status)) {
222d3c4b6f6SRafael J. Wysocki 		acpi_gbl_sleep_type_a_s0 = ACPI_SLEEP_TYPE_INVALID;
223d3c4b6f6SRafael J. Wysocki 	}
224d3c4b6f6SRafael J. Wysocki 
2252feec47dSBob Moore 	/* Execute the _PTS method (Prepare To Sleep) */
2262feec47dSBob Moore 
2272feec47dSBob Moore 	arg_list.count = 1;
2282feec47dSBob Moore 	arg_list.pointer = &arg;
2292feec47dSBob Moore 	arg.type = ACPI_TYPE_INTEGER;
2302feec47dSBob Moore 	arg.integer.value = sleep_state;
2312feec47dSBob Moore 
2324efeeecdSBob Moore 	status =
2334efeeecdSBob Moore 	    acpi_evaluate_object(NULL, METHOD_PATHNAME__PTS, &arg_list, NULL);
2342feec47dSBob Moore 	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
2352feec47dSBob Moore 		return_ACPI_STATUS(status);
2362feec47dSBob Moore 	}
2372feec47dSBob Moore 
2382feec47dSBob Moore 	/* Setup the argument to the _SST method (System STatus) */
2392feec47dSBob Moore 
2402feec47dSBob Moore 	switch (sleep_state) {
2412feec47dSBob Moore 	case ACPI_STATE_S0:
2421d1ea1b7SChao Guan 
2432feec47dSBob Moore 		sst_value = ACPI_SST_WORKING;
2442feec47dSBob Moore 		break;
2452feec47dSBob Moore 
2462feec47dSBob Moore 	case ACPI_STATE_S1:
2472feec47dSBob Moore 	case ACPI_STATE_S2:
2482feec47dSBob Moore 	case ACPI_STATE_S3:
2491d1ea1b7SChao Guan 
2502feec47dSBob Moore 		sst_value = ACPI_SST_SLEEPING;
2512feec47dSBob Moore 		break;
2522feec47dSBob Moore 
2532feec47dSBob Moore 	case ACPI_STATE_S4:
2541d1ea1b7SChao Guan 
2552feec47dSBob Moore 		sst_value = ACPI_SST_SLEEP_CONTEXT;
2562feec47dSBob Moore 		break;
2572feec47dSBob Moore 
2582feec47dSBob Moore 	default:
2591d1ea1b7SChao Guan 
2602feec47dSBob Moore 		sst_value = ACPI_SST_INDICATOR_OFF;	/* Default is off */
2612feec47dSBob Moore 		break;
2622feec47dSBob Moore 	}
2632feec47dSBob Moore 
2642feec47dSBob Moore 	/*
2652feec47dSBob Moore 	 * Set the system indicators to show the desired sleep state.
2662feec47dSBob Moore 	 * _SST is an optional method (return no error if not found)
2672feec47dSBob Moore 	 */
2684efeeecdSBob Moore 	acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, sst_value);
2692feec47dSBob Moore 	return_ACPI_STATUS(AE_OK);
2702feec47dSBob Moore }
2712feec47dSBob Moore 
ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_prep)2722feec47dSBob Moore ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_prep)
2732feec47dSBob Moore 
2742feec47dSBob Moore /*******************************************************************************
2752feec47dSBob Moore  *
2762feec47dSBob Moore  * FUNCTION:    acpi_enter_sleep_state
2772feec47dSBob Moore  *
2782feec47dSBob Moore  * PARAMETERS:  sleep_state         - Which sleep state to enter
2792feec47dSBob Moore  *
2802feec47dSBob Moore  * RETURN:      Status
2812feec47dSBob Moore  *
28275c8044fSLv Zheng  * DESCRIPTION: Enter a system sleep state
2832feec47dSBob Moore  *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
2842feec47dSBob Moore  *
2852feec47dSBob Moore  ******************************************************************************/
28640bce100SLv Zheng acpi_status acpi_enter_sleep_state(u8 sleep_state)
2872feec47dSBob Moore {
2882feec47dSBob Moore 	acpi_status status;
2892feec47dSBob Moore 
2902feec47dSBob Moore 	ACPI_FUNCTION_TRACE(acpi_enter_sleep_state);
2912feec47dSBob Moore 
2922feec47dSBob Moore 	if ((acpi_gbl_sleep_type_a > ACPI_SLEEP_TYPE_MAX) ||
2932feec47dSBob Moore 	    (acpi_gbl_sleep_type_b > ACPI_SLEEP_TYPE_MAX)) {
2942feec47dSBob Moore 		ACPI_ERROR((AE_INFO, "Sleep values out of range: A=0x%X B=0x%X",
2952feec47dSBob Moore 			    acpi_gbl_sleep_type_a, acpi_gbl_sleep_type_b));
2962feec47dSBob Moore 		return_ACPI_STATUS(AE_AML_OPERAND_VALUE);
2972feec47dSBob Moore 	}
2982feec47dSBob Moore 
299f2fee24cSChristoph Hellwig #if !ACPI_REDUCED_HARDWARE
300f2fee24cSChristoph Hellwig 	if (!acpi_gbl_reduced_hardware)
301f2fee24cSChristoph Hellwig 		status = acpi_hw_legacy_sleep(sleep_state);
302f2fee24cSChristoph Hellwig 	else
303f2fee24cSChristoph Hellwig #endif
304f2fee24cSChristoph Hellwig 		status = acpi_hw_extended_sleep(sleep_state);
3052feec47dSBob Moore 	return_ACPI_STATUS(status);
3062feec47dSBob Moore }
3072feec47dSBob Moore 
ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state)3082feec47dSBob Moore ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state)
3092feec47dSBob Moore 
3102feec47dSBob Moore /*******************************************************************************
3112feec47dSBob Moore  *
3122feec47dSBob Moore  * FUNCTION:    acpi_leave_sleep_state_prep
3132feec47dSBob Moore  *
3142feec47dSBob Moore  * PARAMETERS:  sleep_state         - Which sleep state we are exiting
3152feec47dSBob Moore  *
3162feec47dSBob Moore  * RETURN:      Status
3172feec47dSBob Moore  *
3182feec47dSBob Moore  * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a
31975c8044fSLv Zheng  *              sleep. Called with interrupts DISABLED.
32075c8044fSLv Zheng  *              We break wake/resume into 2 stages so that OSPM can handle
32175c8044fSLv Zheng  *              various OS-specific tasks between the two steps.
3222feec47dSBob Moore  *
3232feec47dSBob Moore  ******************************************************************************/
3243f6f49c7SLen Brown acpi_status acpi_leave_sleep_state_prep(u8 sleep_state)
3252feec47dSBob Moore {
3262feec47dSBob Moore 	acpi_status status;
3272feec47dSBob Moore 
32872a8887aSBob Moore 	ACPI_FUNCTION_TRACE(acpi_leave_sleep_state_prep);
3292feec47dSBob Moore 
330f2fee24cSChristoph Hellwig #if !ACPI_REDUCED_HARDWARE
331f2fee24cSChristoph Hellwig 	if (!acpi_gbl_reduced_hardware)
332f2fee24cSChristoph Hellwig 		status = acpi_hw_legacy_wake_prep(sleep_state);
333f2fee24cSChristoph Hellwig 	else
334f2fee24cSChristoph Hellwig #endif
335f2fee24cSChristoph Hellwig 		status = acpi_hw_extended_wake_prep(sleep_state);
3362feec47dSBob Moore 	return_ACPI_STATUS(status);
3372feec47dSBob Moore }
3382feec47dSBob Moore 
ACPI_EXPORT_SYMBOL(acpi_leave_sleep_state_prep)3392feec47dSBob Moore ACPI_EXPORT_SYMBOL(acpi_leave_sleep_state_prep)
3402feec47dSBob Moore 
3412feec47dSBob Moore /*******************************************************************************
3422feec47dSBob Moore  *
3432feec47dSBob Moore  * FUNCTION:    acpi_leave_sleep_state
3442feec47dSBob Moore  *
34572a8887aSBob Moore  * PARAMETERS:  sleep_state         - Which sleep state we are exiting
3462feec47dSBob Moore  *
3472feec47dSBob Moore  * RETURN:      Status
3482feec47dSBob Moore  *
3492feec47dSBob Moore  * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep
3502feec47dSBob Moore  *              Called with interrupts ENABLED.
3512feec47dSBob Moore  *
3522feec47dSBob Moore  ******************************************************************************/
3532feec47dSBob Moore acpi_status acpi_leave_sleep_state(u8 sleep_state)
3542feec47dSBob Moore {
3552feec47dSBob Moore 	acpi_status status;
3562feec47dSBob Moore 
3572feec47dSBob Moore 	ACPI_FUNCTION_TRACE(acpi_leave_sleep_state);
3582feec47dSBob Moore 
359f2fee24cSChristoph Hellwig #if !ACPI_REDUCED_HARDWARE
360f2fee24cSChristoph Hellwig 	if (!acpi_gbl_reduced_hardware)
361f2fee24cSChristoph Hellwig 		status = acpi_hw_legacy_wake(sleep_state);
362f2fee24cSChristoph Hellwig 	else
363f2fee24cSChristoph Hellwig #endif
364f2fee24cSChristoph Hellwig 		status = acpi_hw_extended_wake(sleep_state);
3652feec47dSBob Moore 	return_ACPI_STATUS(status);
3662feec47dSBob Moore }
3672feec47dSBob Moore 
3682feec47dSBob Moore ACPI_EXPORT_SYMBOL(acpi_leave_sleep_state)
369