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