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