1 /******************************************************************************
   2  *
   3  * Name: hwsleep.c - ACPI Hardware Sleep/Wake Support functions for the
   4  *                   original/legacy sleep/PM registers.
   5  *
   6  *****************************************************************************/
   7 
   8 /*
   9  * Copyright (C) 2000 - 2014, Intel Corp.
  10  * All rights reserved.
  11  *
  12  * Redistribution and use in source and binary forms, with or without
  13  * modification, are permitted provided that the following conditions
  14  * are met:
  15  * 1. Redistributions of source code must retain the above copyright
  16  *    notice, this list of conditions, and the following disclaimer,
  17  *    without modification.
  18  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
  19  *    substantially similar to the "NO WARRANTY" disclaimer below
  20  *    ("Disclaimer") and any redistribution must be conditioned upon
  21  *    including a substantially similar Disclaimer requirement for further
  22  *    binary redistribution.
  23  * 3. Neither the names of the above-listed copyright holders nor the names
  24  *    of any contributors may be used to endorse or promote products derived
  25  *    from this software without specific prior written permission.
  26  *
  27  * Alternatively, this software may be distributed under the terms of the
  28  * GNU General Public License ("GPL") version 2 as published by the Free
  29  * Software Foundation.
  30  *
  31  * NO WARRANTY
  32  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  33  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  34  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
  35  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  36  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  40  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  41  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  42  * POSSIBILITY OF SUCH DAMAGES.
  43  */
  44 
  45 #include "acpi.h"
  46 #include "accommon.h"
  47 
  48 #define _COMPONENT          ACPI_HARDWARE
  49         ACPI_MODULE_NAME    ("hwsleep")
  50 
  51 
  52 #if (!ACPI_REDUCED_HARDWARE) /* Entire module */
  53 /*******************************************************************************
  54  *
  55  * FUNCTION:    AcpiHwLegacySleep
  56  *
  57  * PARAMETERS:  SleepState          - Which sleep state to enter
  58  *
  59  * RETURN:      Status
  60  *
  61  * DESCRIPTION: Enter a system sleep state via the legacy FADT PM registers
  62  *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
  63  *
  64  ******************************************************************************/
  65 
  66 ACPI_STATUS
  67 AcpiHwLegacySleep (
  68     UINT8                   SleepState)
  69 {
  70     ACPI_BIT_REGISTER_INFO  *SleepTypeRegInfo;
  71     ACPI_BIT_REGISTER_INFO  *SleepEnableRegInfo;
  72     UINT32                  Pm1aControl;
  73     UINT32                  Pm1bControl;
  74     UINT32                  InValue;
  75     ACPI_STATUS             Status;
  76 
  77 
  78     ACPI_FUNCTION_TRACE (HwLegacySleep);
  79 
  80 
  81     SleepTypeRegInfo = AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_TYPE);
  82     SleepEnableRegInfo = AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_ENABLE);
  83 
  84     /* Clear wake status */
  85 
  86     Status = AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS);
  87     if (ACPI_FAILURE (Status))
  88     {
  89         return_ACPI_STATUS (Status);
  90     }
  91 
  92     /* Clear all fixed and general purpose status bits */
  93 
  94     Status = AcpiHwClearAcpiStatus ();
  95     if (ACPI_FAILURE (Status))
  96     {
  97         return_ACPI_STATUS (Status);
  98     }
  99 
 100     /*
 101      * 1) Disable/Clear all GPEs
 102      * 2) Enable all wakeup GPEs
 103      */
 104     Status = AcpiHwDisableAllGpes ();
 105     if (ACPI_FAILURE (Status))
 106     {
 107         return_ACPI_STATUS (Status);
 108     }
 109     AcpiGbl_SystemAwakeAndRunning = FALSE;
 110 
 111     Status = AcpiHwEnableAllWakeupGpes ();
 112     if (ACPI_FAILURE (Status))
 113     {
 114         return_ACPI_STATUS (Status);
 115     }
 116 
 117     /* Get current value of PM1A control */
 118 
 119     Status = AcpiHwRegisterRead (ACPI_REGISTER_PM1_CONTROL,
 120                 &Pm1aControl);
 121     if (ACPI_FAILURE (Status))
 122     {
 123         return_ACPI_STATUS (Status);
 124     }
 125     ACPI_DEBUG_PRINT ((ACPI_DB_INIT,
 126         "Entering sleep state [S%u]\n", SleepState));
 127 
 128     /* Clear the SLP_EN and SLP_TYP fields */
 129 
 130     Pm1aControl &= ~(SleepTypeRegInfo->AccessBitMask |
 131                      SleepEnableRegInfo->AccessBitMask);
 132     Pm1bControl = Pm1aControl;
 133 
 134     /* Insert the SLP_TYP bits */
 135 
 136     Pm1aControl |= (AcpiGbl_SleepTypeA << SleepTypeRegInfo->BitPosition);
 137     Pm1bControl |= (AcpiGbl_SleepTypeB << SleepTypeRegInfo->BitPosition);
 138 
 139     /*
 140      * We split the writes of SLP_TYP and SLP_EN to workaround
 141      * poorly implemented hardware.
 142      */
 143 
 144     /* Write #1: write the SLP_TYP data to the PM1 Control registers */
 145 
 146     Status = AcpiHwWritePm1Control (Pm1aControl, Pm1bControl);
 147     if (ACPI_FAILURE (Status))
 148     {
 149         return_ACPI_STATUS (Status);
 150     }
 151 
 152     /* Insert the sleep enable (SLP_EN) bit */
 153 
 154     Pm1aControl |= SleepEnableRegInfo->AccessBitMask;
 155     Pm1bControl |= SleepEnableRegInfo->AccessBitMask;
 156 
 157     /* Flush caches, as per ACPI specification */
 158 
 159     ACPI_FLUSH_CPU_CACHE ();
 160 
 161     /* Write #2: Write both SLP_TYP + SLP_EN */
 162 
 163     Status = AcpiHwWritePm1Control (Pm1aControl, Pm1bControl);
 164     if (ACPI_FAILURE (Status))
 165     {
 166         return_ACPI_STATUS (Status);
 167     }
 168 
 169     if (SleepState > ACPI_STATE_S3)
 170     {
 171         /*
 172          * We wanted to sleep > S3, but it didn't happen (by virtue of the
 173          * fact that we are still executing!)
 174          *
 175          * Wait ten seconds, then try again. This is to get S4/S5 to work on
 176          * all machines.
 177          *
 178          * We wait so long to allow chipsets that poll this reg very slowly
 179          * to still read the right value. Ideally, this block would go
 180          * away entirely.
 181          */
 182         AcpiOsStall (10 * ACPI_USEC_PER_SEC);
 183 
 184         Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_CONTROL,
 185                     SleepEnableRegInfo->AccessBitMask);
 186         if (ACPI_FAILURE (Status))
 187         {
 188             return_ACPI_STATUS (Status);
 189         }
 190     }
 191 
 192     /* Wait for transition back to Working State */
 193 
 194     do
 195     {
 196         Status = AcpiReadBitRegister (ACPI_BITREG_WAKE_STATUS, &InValue);
 197         if (ACPI_FAILURE (Status))
 198         {
 199             return_ACPI_STATUS (Status);
 200         }
 201 
 202     } while (!InValue);
 203 
 204     return_ACPI_STATUS (AE_OK);
 205 }
 206 
 207 
 208 /*******************************************************************************
 209  *
 210  * FUNCTION:    AcpiHwLegacyWakePrep
 211  *
 212  * PARAMETERS:  SleepState          - Which sleep state we just exited
 213  *
 214  * RETURN:      Status
 215  *
 216  * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a
 217  *              sleep.
 218  *              Called with interrupts ENABLED.
 219  *
 220  ******************************************************************************/
 221 
 222 ACPI_STATUS
 223 AcpiHwLegacyWakePrep (
 224     UINT8                   SleepState)
 225 {
 226     ACPI_STATUS             Status;
 227     ACPI_BIT_REGISTER_INFO  *SleepTypeRegInfo;
 228     ACPI_BIT_REGISTER_INFO  *SleepEnableRegInfo;
 229     UINT32                  Pm1aControl;
 230     UINT32                  Pm1bControl;
 231 
 232 
 233     ACPI_FUNCTION_TRACE (HwLegacyWakePrep);
 234 
 235     /*
 236      * Set SLP_TYPE and SLP_EN to state S0.
 237      * This is unclear from the ACPI Spec, but it is required
 238      * by some machines.
 239      */
 240     Status = AcpiGetSleepTypeData (ACPI_STATE_S0,
 241                     &AcpiGbl_SleepTypeA, &AcpiGbl_SleepTypeB);
 242     if (ACPI_SUCCESS (Status))
 243     {
 244         SleepTypeRegInfo =
 245             AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_TYPE);
 246         SleepEnableRegInfo =
 247             AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_ENABLE);
 248 
 249         /* Get current value of PM1A control */
 250 
 251         Status = AcpiHwRegisterRead (ACPI_REGISTER_PM1_CONTROL,
 252                     &Pm1aControl);
 253         if (ACPI_SUCCESS (Status))
 254         {
 255             /* Clear the SLP_EN and SLP_TYP fields */
 256 
 257             Pm1aControl &= ~(SleepTypeRegInfo->AccessBitMask |
 258                 SleepEnableRegInfo->AccessBitMask);
 259             Pm1bControl = Pm1aControl;
 260 
 261             /* Insert the SLP_TYP bits */
 262 
 263             Pm1aControl |= (AcpiGbl_SleepTypeA <<
 264                 SleepTypeRegInfo->BitPosition);
 265             Pm1bControl |= (AcpiGbl_SleepTypeB <<
 266                 SleepTypeRegInfo->BitPosition);
 267 
 268             /* Write the control registers and ignore any errors */
 269 
 270             (void) AcpiHwWritePm1Control (Pm1aControl, Pm1bControl);
 271         }
 272     }
 273 
 274     return_ACPI_STATUS (Status);
 275 }
 276 
 277 
 278 /*******************************************************************************
 279  *
 280  * FUNCTION:    AcpiHwLegacyWake
 281  *
 282  * PARAMETERS:  SleepState          - Which sleep state we just exited
 283  *
 284  * RETURN:      Status
 285  *
 286  * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep
 287  *              Called with interrupts ENABLED.
 288  *
 289  ******************************************************************************/
 290 
 291 ACPI_STATUS
 292 AcpiHwLegacyWake (
 293     UINT8                   SleepState)
 294 {
 295     ACPI_STATUS             Status;
 296 
 297 
 298     ACPI_FUNCTION_TRACE (HwLegacyWake);
 299 
 300 
 301     /* Ensure EnterSleepStatePrep -> EnterSleepState ordering */
 302 
 303     AcpiGbl_SleepTypeA = ACPI_SLEEP_TYPE_INVALID;
 304     AcpiHwExecuteSleepMethod (METHOD_PATHNAME__SST, ACPI_SST_WAKING);
 305 
 306     /*
 307      * GPEs must be enabled before _WAK is called as GPEs
 308      * might get fired there
 309      *
 310      * Restore the GPEs:
 311      * 1) Disable/Clear all GPEs
 312      * 2) Enable all runtime GPEs
 313      */
 314     Status = AcpiHwDisableAllGpes ();
 315     if (ACPI_FAILURE (Status))
 316     {
 317         return_ACPI_STATUS (Status);
 318     }
 319 
 320     Status = AcpiHwEnableAllRuntimeGpes ();
 321     if (ACPI_FAILURE (Status))
 322     {
 323         return_ACPI_STATUS (Status);
 324     }
 325 
 326     /*
 327      * Now we can execute _WAK, etc. Some machines require that the GPEs
 328      * are enabled before the wake methods are executed.
 329      */
 330     AcpiHwExecuteSleepMethod (METHOD_PATHNAME__WAK, SleepState);
 331 
 332     /*
 333      * Some BIOS code assumes that WAK_STS will be cleared on resume
 334      * and use it to determine whether the system is rebooting or
 335      * resuming. Clear WAK_STS for compatibility.
 336      */
 337     (void) AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS);
 338     AcpiGbl_SystemAwakeAndRunning = TRUE;
 339 
 340     /* Enable power button */
 341 
 342     (void) AcpiWriteBitRegister(
 343             AcpiGbl_FixedEventInfo[ACPI_EVENT_POWER_BUTTON].EnableRegisterId,
 344             ACPI_ENABLE_EVENT);
 345 
 346     (void) AcpiWriteBitRegister(
 347             AcpiGbl_FixedEventInfo[ACPI_EVENT_POWER_BUTTON].StatusRegisterId,
 348             ACPI_CLEAR_STATUS);
 349 
 350     AcpiHwExecuteSleepMethod (METHOD_PATHNAME__SST, ACPI_SST_WORKING);
 351     return_ACPI_STATUS (Status);
 352 }
 353 
 354 #endif /* !ACPI_REDUCED_HARDWARE */