linux/drivers/acpi/acpica/hwsleep.c
<<
>>
Prefs
   1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2/******************************************************************************
   3 *
   4 * Name: hwsleep.c - ACPI Hardware Sleep/Wake Support functions for the
   5 *                   original/legacy sleep/PM registers.
   6 *
   7 * Copyright (C) 2000 - 2021, Intel Corp.
   8 *
   9 *****************************************************************************/
  10
  11#include <acpi/acpi.h>
  12#include "accommon.h"
  13
  14#define _COMPONENT          ACPI_HARDWARE
  15ACPI_MODULE_NAME("hwsleep")
  16
  17#if (!ACPI_REDUCED_HARDWARE)    /* Entire module */
  18/*******************************************************************************
  19 *
  20 * FUNCTION:    acpi_hw_legacy_sleep
  21 *
  22 * PARAMETERS:  sleep_state         - Which sleep state to enter
  23 *
  24 * RETURN:      Status
  25 *
  26 * DESCRIPTION: Enter a system sleep state via the legacy FADT PM registers
  27 *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
  28 *
  29 ******************************************************************************/
  30acpi_status acpi_hw_legacy_sleep(u8 sleep_state)
  31{
  32        struct acpi_bit_register_info *sleep_type_reg_info;
  33        struct acpi_bit_register_info *sleep_enable_reg_info;
  34        u32 pm1a_control;
  35        u32 pm1b_control;
  36        u32 in_value;
  37        acpi_status status;
  38
  39        ACPI_FUNCTION_TRACE(hw_legacy_sleep);
  40
  41        sleep_type_reg_info =
  42            acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_TYPE);
  43        sleep_enable_reg_info =
  44            acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_ENABLE);
  45
  46        /* Clear wake status */
  47
  48        status = acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS,
  49                                         ACPI_CLEAR_STATUS);
  50        if (ACPI_FAILURE(status)) {
  51                return_ACPI_STATUS(status);
  52        }
  53
  54        /* Disable all GPEs */
  55        status = acpi_hw_disable_all_gpes();
  56        if (ACPI_FAILURE(status)) {
  57                return_ACPI_STATUS(status);
  58        }
  59        status = acpi_hw_clear_acpi_status();
  60        if (ACPI_FAILURE(status)) {
  61                return_ACPI_STATUS(status);
  62        }
  63        acpi_gbl_system_awake_and_running = FALSE;
  64
  65         /* Enable all wakeup GPEs */
  66        status = acpi_hw_enable_all_wakeup_gpes();
  67        if (ACPI_FAILURE(status)) {
  68                return_ACPI_STATUS(status);
  69        }
  70
  71        /* Get current value of PM1A control */
  72
  73        status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL,
  74                                       &pm1a_control);
  75        if (ACPI_FAILURE(status)) {
  76                return_ACPI_STATUS(status);
  77        }
  78        ACPI_DEBUG_PRINT((ACPI_DB_INIT,
  79                          "Entering sleep state [S%u]\n", sleep_state));
  80
  81        /* Clear the SLP_EN and SLP_TYP fields */
  82
  83        pm1a_control &= ~(sleep_type_reg_info->access_bit_mask |
  84                          sleep_enable_reg_info->access_bit_mask);
  85        pm1b_control = pm1a_control;
  86
  87        /* Insert the SLP_TYP bits */
  88
  89        pm1a_control |=
  90            (acpi_gbl_sleep_type_a << sleep_type_reg_info->bit_position);
  91        pm1b_control |=
  92            (acpi_gbl_sleep_type_b << sleep_type_reg_info->bit_position);
  93
  94        /*
  95         * We split the writes of SLP_TYP and SLP_EN to workaround
  96         * poorly implemented hardware.
  97         */
  98
  99        /* Write #1: write the SLP_TYP data to the PM1 Control registers */
 100
 101        status = acpi_hw_write_pm1_control(pm1a_control, pm1b_control);
 102        if (ACPI_FAILURE(status)) {
 103                return_ACPI_STATUS(status);
 104        }
 105
 106        /* Insert the sleep enable (SLP_EN) bit */
 107
 108        pm1a_control |= sleep_enable_reg_info->access_bit_mask;
 109        pm1b_control |= sleep_enable_reg_info->access_bit_mask;
 110
 111        /* Flush caches, as per ACPI specification */
 112
 113        ACPI_FLUSH_CPU_CACHE();
 114
 115        status = acpi_os_enter_sleep(sleep_state, pm1a_control, pm1b_control);
 116        if (status == AE_CTRL_TERMINATE) {
 117                return_ACPI_STATUS(AE_OK);
 118        }
 119        if (ACPI_FAILURE(status)) {
 120                return_ACPI_STATUS(status);
 121        }
 122
 123        /* Write #2: Write both SLP_TYP + SLP_EN */
 124
 125        status = acpi_hw_write_pm1_control(pm1a_control, pm1b_control);
 126        if (ACPI_FAILURE(status)) {
 127                return_ACPI_STATUS(status);
 128        }
 129
 130        if (sleep_state > ACPI_STATE_S3) {
 131                /*
 132                 * We wanted to sleep > S3, but it didn't happen (by virtue of the
 133                 * fact that we are still executing!)
 134                 *
 135                 * Wait ten seconds, then try again. This is to get S4/S5 to work on
 136                 * all machines.
 137                 *
 138                 * We wait so long to allow chipsets that poll this reg very slowly
 139                 * to still read the right value. Ideally, this block would go
 140                 * away entirely.
 141                 */
 142                acpi_os_stall(10 * ACPI_USEC_PER_SEC);
 143
 144                status = acpi_hw_register_write(ACPI_REGISTER_PM1_CONTROL,
 145                                                sleep_enable_reg_info->
 146                                                access_bit_mask);
 147                if (ACPI_FAILURE(status)) {
 148                        return_ACPI_STATUS(status);
 149                }
 150        }
 151
 152        /* Wait for transition back to Working State */
 153
 154        do {
 155                status =
 156                    acpi_read_bit_register(ACPI_BITREG_WAKE_STATUS, &in_value);
 157                if (ACPI_FAILURE(status)) {
 158                        return_ACPI_STATUS(status);
 159                }
 160
 161        } while (!in_value);
 162
 163        return_ACPI_STATUS(AE_OK);
 164}
 165
 166/*******************************************************************************
 167 *
 168 * FUNCTION:    acpi_hw_legacy_wake_prep
 169 *
 170 * PARAMETERS:  sleep_state         - Which sleep state we just exited
 171 *
 172 * RETURN:      Status
 173 *
 174 * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a
 175 *              sleep.
 176 *              Called with interrupts ENABLED.
 177 *
 178 ******************************************************************************/
 179
 180acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state)
 181{
 182        acpi_status status;
 183        struct acpi_bit_register_info *sleep_type_reg_info;
 184        struct acpi_bit_register_info *sleep_enable_reg_info;
 185        u32 pm1a_control;
 186        u32 pm1b_control;
 187
 188        ACPI_FUNCTION_TRACE(hw_legacy_wake_prep);
 189
 190        /*
 191         * Set SLP_TYPE and SLP_EN to state S0.
 192         * This is unclear from the ACPI Spec, but it is required
 193         * by some machines.
 194         */
 195        status = acpi_get_sleep_type_data(ACPI_STATE_S0,
 196                                          &acpi_gbl_sleep_type_a,
 197                                          &acpi_gbl_sleep_type_b);
 198        if (ACPI_SUCCESS(status)) {
 199                sleep_type_reg_info =
 200                    acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_TYPE);
 201                sleep_enable_reg_info =
 202                    acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_ENABLE);
 203
 204                /* Get current value of PM1A control */
 205
 206                status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL,
 207                                               &pm1a_control);
 208                if (ACPI_SUCCESS(status)) {
 209
 210                        /* Clear the SLP_EN and SLP_TYP fields */
 211
 212                        pm1a_control &= ~(sleep_type_reg_info->access_bit_mask |
 213                                          sleep_enable_reg_info->
 214                                          access_bit_mask);
 215                        pm1b_control = pm1a_control;
 216
 217                        /* Insert the SLP_TYP bits */
 218
 219                        pm1a_control |= (acpi_gbl_sleep_type_a <<
 220                                         sleep_type_reg_info->bit_position);
 221                        pm1b_control |= (acpi_gbl_sleep_type_b <<
 222                                         sleep_type_reg_info->bit_position);
 223
 224                        /* Write the control registers and ignore any errors */
 225
 226                        (void)acpi_hw_write_pm1_control(pm1a_control,
 227                                                        pm1b_control);
 228                }
 229        }
 230
 231        return_ACPI_STATUS(status);
 232}
 233
 234/*******************************************************************************
 235 *
 236 * FUNCTION:    acpi_hw_legacy_wake
 237 *
 238 * PARAMETERS:  sleep_state         - Which sleep state we just exited
 239 *
 240 * RETURN:      Status
 241 *
 242 * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep
 243 *              Called with interrupts ENABLED.
 244 *
 245 ******************************************************************************/
 246
 247acpi_status acpi_hw_legacy_wake(u8 sleep_state)
 248{
 249        acpi_status status;
 250
 251        ACPI_FUNCTION_TRACE(hw_legacy_wake);
 252
 253        /* Ensure enter_sleep_state_prep -> enter_sleep_state ordering */
 254
 255        acpi_gbl_sleep_type_a = ACPI_SLEEP_TYPE_INVALID;
 256        acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, ACPI_SST_WAKING);
 257
 258        /*
 259         * GPEs must be enabled before _WAK is called as GPEs
 260         * might get fired there
 261         *
 262         * Restore the GPEs:
 263         * 1) Disable all GPEs
 264         * 2) Enable all runtime GPEs
 265         */
 266        status = acpi_hw_disable_all_gpes();
 267        if (ACPI_FAILURE(status)) {
 268                return_ACPI_STATUS(status);
 269        }
 270
 271        status = acpi_hw_enable_all_runtime_gpes();
 272        if (ACPI_FAILURE(status)) {
 273                return_ACPI_STATUS(status);
 274        }
 275
 276        /*
 277         * Now we can execute _WAK, etc. Some machines require that the GPEs
 278         * are enabled before the wake methods are executed.
 279         */
 280        acpi_hw_execute_sleep_method(METHOD_PATHNAME__WAK, sleep_state);
 281
 282        /*
 283         * Some BIOS code assumes that WAK_STS will be cleared on resume
 284         * and use it to determine whether the system is rebooting or
 285         * resuming. Clear WAK_STS for compatibility.
 286         */
 287        (void)acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS,
 288                                      ACPI_CLEAR_STATUS);
 289        acpi_gbl_system_awake_and_running = TRUE;
 290
 291        /* Enable power button */
 292
 293        (void)
 294            acpi_write_bit_register(acpi_gbl_fixed_event_info
 295                                    [ACPI_EVENT_POWER_BUTTON].
 296                                    enable_register_id, ACPI_ENABLE_EVENT);
 297
 298        (void)
 299            acpi_write_bit_register(acpi_gbl_fixed_event_info
 300                                    [ACPI_EVENT_POWER_BUTTON].
 301                                    status_register_id, ACPI_CLEAR_STATUS);
 302
 303        /* Enable sleep button */
 304
 305        (void)
 306            acpi_write_bit_register(acpi_gbl_fixed_event_info
 307                                    [ACPI_EVENT_SLEEP_BUTTON].
 308                                    enable_register_id, ACPI_ENABLE_EVENT);
 309
 310        (void)
 311            acpi_write_bit_register(acpi_gbl_fixed_event_info
 312                                    [ACPI_EVENT_SLEEP_BUTTON].
 313                                    status_register_id, ACPI_CLEAR_STATUS);
 314
 315        acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, ACPI_SST_WORKING);
 316        return_ACPI_STATUS(status);
 317}
 318
 319#endif                          /* !ACPI_REDUCED_HARDWARE */
 320