10d02842fSSascha Wildner /****************************************************************************** 20d02842fSSascha Wildner * 30d02842fSSascha Wildner * Name: hwsleep.c - ACPI Hardware Sleep/Wake Support functions for the 40d02842fSSascha Wildner * original/legacy sleep/PM registers. 50d02842fSSascha Wildner * 60d02842fSSascha Wildner *****************************************************************************/ 70d02842fSSascha Wildner 80d02842fSSascha Wildner /* 9*f5f76cf2SSascha Wildner * Copyright (C) 2000 - 2016, Intel Corp. 100d02842fSSascha Wildner * All rights reserved. 110d02842fSSascha Wildner * 120d02842fSSascha Wildner * Redistribution and use in source and binary forms, with or without 130d02842fSSascha Wildner * modification, are permitted provided that the following conditions 140d02842fSSascha Wildner * are met: 150d02842fSSascha Wildner * 1. Redistributions of source code must retain the above copyright 160d02842fSSascha Wildner * notice, this list of conditions, and the following disclaimer, 170d02842fSSascha Wildner * without modification. 180d02842fSSascha Wildner * 2. Redistributions in binary form must reproduce at minimum a disclaimer 190d02842fSSascha Wildner * substantially similar to the "NO WARRANTY" disclaimer below 200d02842fSSascha Wildner * ("Disclaimer") and any redistribution must be conditioned upon 210d02842fSSascha Wildner * including a substantially similar Disclaimer requirement for further 220d02842fSSascha Wildner * binary redistribution. 230d02842fSSascha Wildner * 3. Neither the names of the above-listed copyright holders nor the names 240d02842fSSascha Wildner * of any contributors may be used to endorse or promote products derived 250d02842fSSascha Wildner * from this software without specific prior written permission. 260d02842fSSascha Wildner * 270d02842fSSascha Wildner * Alternatively, this software may be distributed under the terms of the 280d02842fSSascha Wildner * GNU General Public License ("GPL") version 2 as published by the Free 290d02842fSSascha Wildner * Software Foundation. 300d02842fSSascha Wildner * 310d02842fSSascha Wildner * NO WARRANTY 320d02842fSSascha Wildner * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 330d02842fSSascha Wildner * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 340d02842fSSascha Wildner * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 350d02842fSSascha Wildner * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 360d02842fSSascha Wildner * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 370d02842fSSascha Wildner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 380d02842fSSascha Wildner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 390d02842fSSascha Wildner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 400d02842fSSascha Wildner * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 410d02842fSSascha Wildner * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 420d02842fSSascha Wildner * POSSIBILITY OF SUCH DAMAGES. 430d02842fSSascha Wildner */ 440d02842fSSascha Wildner 450d02842fSSascha Wildner #include "acpi.h" 460d02842fSSascha Wildner #include "accommon.h" 470d02842fSSascha Wildner 480d02842fSSascha Wildner #define _COMPONENT ACPI_HARDWARE 490d02842fSSascha Wildner ACPI_MODULE_NAME ("hwsleep") 500d02842fSSascha Wildner 510d02842fSSascha Wildner 520d02842fSSascha Wildner #if (!ACPI_REDUCED_HARDWARE) /* Entire module */ 530d02842fSSascha Wildner /******************************************************************************* 540d02842fSSascha Wildner * 550d02842fSSascha Wildner * FUNCTION: AcpiHwLegacySleep 560d02842fSSascha Wildner * 570d02842fSSascha Wildner * PARAMETERS: SleepState - Which sleep state to enter 580d02842fSSascha Wildner * 590d02842fSSascha Wildner * RETURN: Status 600d02842fSSascha Wildner * 610d02842fSSascha Wildner * DESCRIPTION: Enter a system sleep state via the legacy FADT PM registers 620d02842fSSascha Wildner * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED 630d02842fSSascha Wildner * 640d02842fSSascha Wildner ******************************************************************************/ 650d02842fSSascha Wildner 660d02842fSSascha Wildner ACPI_STATUS 670d02842fSSascha Wildner AcpiHwLegacySleep ( 680d02842fSSascha Wildner UINT8 SleepState) 690d02842fSSascha Wildner { 700d02842fSSascha Wildner ACPI_BIT_REGISTER_INFO *SleepTypeRegInfo; 710d02842fSSascha Wildner ACPI_BIT_REGISTER_INFO *SleepEnableRegInfo; 720d02842fSSascha Wildner UINT32 Pm1aControl; 730d02842fSSascha Wildner UINT32 Pm1bControl; 740d02842fSSascha Wildner UINT32 InValue; 750d02842fSSascha Wildner ACPI_STATUS Status; 760d02842fSSascha Wildner 770d02842fSSascha Wildner 780d02842fSSascha Wildner ACPI_FUNCTION_TRACE (HwLegacySleep); 790d02842fSSascha Wildner 800d02842fSSascha Wildner 810d02842fSSascha Wildner SleepTypeRegInfo = AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_TYPE); 820d02842fSSascha Wildner SleepEnableRegInfo = AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_ENABLE); 830d02842fSSascha Wildner 840d02842fSSascha Wildner /* Clear wake status */ 850d02842fSSascha Wildner 86820c5b08SSascha Wildner Status = AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS, 87820c5b08SSascha Wildner ACPI_CLEAR_STATUS); 880d02842fSSascha Wildner if (ACPI_FAILURE (Status)) 890d02842fSSascha Wildner { 900d02842fSSascha Wildner return_ACPI_STATUS (Status); 910d02842fSSascha Wildner } 920d02842fSSascha Wildner 930d02842fSSascha Wildner /* Clear all fixed and general purpose status bits */ 940d02842fSSascha Wildner 950d02842fSSascha Wildner Status = AcpiHwClearAcpiStatus (); 960d02842fSSascha Wildner if (ACPI_FAILURE (Status)) 970d02842fSSascha Wildner { 980d02842fSSascha Wildner return_ACPI_STATUS (Status); 990d02842fSSascha Wildner } 1000d02842fSSascha Wildner 1010d02842fSSascha Wildner /* 1020d02842fSSascha Wildner * 1) Disable/Clear all GPEs 1030d02842fSSascha Wildner * 2) Enable all wakeup GPEs 1040d02842fSSascha Wildner */ 1050d02842fSSascha Wildner Status = AcpiHwDisableAllGpes (); 1060d02842fSSascha Wildner if (ACPI_FAILURE (Status)) 1070d02842fSSascha Wildner { 1080d02842fSSascha Wildner return_ACPI_STATUS (Status); 1090d02842fSSascha Wildner } 1100d02842fSSascha Wildner AcpiGbl_SystemAwakeAndRunning = FALSE; 1110d02842fSSascha Wildner 1120d02842fSSascha Wildner Status = AcpiHwEnableAllWakeupGpes (); 1130d02842fSSascha Wildner if (ACPI_FAILURE (Status)) 1140d02842fSSascha Wildner { 1150d02842fSSascha Wildner return_ACPI_STATUS (Status); 1160d02842fSSascha Wildner } 1170d02842fSSascha Wildner 1180d02842fSSascha Wildner /* Get current value of PM1A control */ 1190d02842fSSascha Wildner 1200d02842fSSascha Wildner Status = AcpiHwRegisterRead (ACPI_REGISTER_PM1_CONTROL, 1210d02842fSSascha Wildner &Pm1aControl); 1220d02842fSSascha Wildner if (ACPI_FAILURE (Status)) 1230d02842fSSascha Wildner { 1240d02842fSSascha Wildner return_ACPI_STATUS (Status); 1250d02842fSSascha Wildner } 1260d02842fSSascha Wildner ACPI_DEBUG_PRINT ((ACPI_DB_INIT, 1270d02842fSSascha Wildner "Entering sleep state [S%u]\n", SleepState)); 1280d02842fSSascha Wildner 1290d02842fSSascha Wildner /* Clear the SLP_EN and SLP_TYP fields */ 1300d02842fSSascha Wildner 1310d02842fSSascha Wildner Pm1aControl &= ~(SleepTypeRegInfo->AccessBitMask | 1320d02842fSSascha Wildner SleepEnableRegInfo->AccessBitMask); 1330d02842fSSascha Wildner Pm1bControl = Pm1aControl; 1340d02842fSSascha Wildner 1350d02842fSSascha Wildner /* Insert the SLP_TYP bits */ 1360d02842fSSascha Wildner 1370d02842fSSascha Wildner Pm1aControl |= (AcpiGbl_SleepTypeA << SleepTypeRegInfo->BitPosition); 1380d02842fSSascha Wildner Pm1bControl |= (AcpiGbl_SleepTypeB << SleepTypeRegInfo->BitPosition); 1390d02842fSSascha Wildner 1400d02842fSSascha Wildner /* 1410d02842fSSascha Wildner * We split the writes of SLP_TYP and SLP_EN to workaround 1420d02842fSSascha Wildner * poorly implemented hardware. 1430d02842fSSascha Wildner */ 1440d02842fSSascha Wildner 1450d02842fSSascha Wildner /* Write #1: write the SLP_TYP data to the PM1 Control registers */ 1460d02842fSSascha Wildner 1470d02842fSSascha Wildner Status = AcpiHwWritePm1Control (Pm1aControl, Pm1bControl); 1480d02842fSSascha Wildner if (ACPI_FAILURE (Status)) 1490d02842fSSascha Wildner { 1500d02842fSSascha Wildner return_ACPI_STATUS (Status); 1510d02842fSSascha Wildner } 1520d02842fSSascha Wildner 1530d02842fSSascha Wildner /* Insert the sleep enable (SLP_EN) bit */ 1540d02842fSSascha Wildner 1550d02842fSSascha Wildner Pm1aControl |= SleepEnableRegInfo->AccessBitMask; 1560d02842fSSascha Wildner Pm1bControl |= SleepEnableRegInfo->AccessBitMask; 1570d02842fSSascha Wildner 1580d02842fSSascha Wildner /* Flush caches, as per ACPI specification */ 1590d02842fSSascha Wildner 1600d02842fSSascha Wildner ACPI_FLUSH_CPU_CACHE (); 1610d02842fSSascha Wildner 1620d02842fSSascha Wildner /* Write #2: Write both SLP_TYP + SLP_EN */ 1630d02842fSSascha Wildner 1640d02842fSSascha Wildner Status = AcpiHwWritePm1Control (Pm1aControl, Pm1bControl); 1650d02842fSSascha Wildner if (ACPI_FAILURE (Status)) 1660d02842fSSascha Wildner { 1670d02842fSSascha Wildner return_ACPI_STATUS (Status); 1680d02842fSSascha Wildner } 1690d02842fSSascha Wildner 1700d02842fSSascha Wildner if (SleepState > ACPI_STATE_S3) 1710d02842fSSascha Wildner { 1720d02842fSSascha Wildner /* 1730d02842fSSascha Wildner * We wanted to sleep > S3, but it didn't happen (by virtue of the 1740d02842fSSascha Wildner * fact that we are still executing!) 1750d02842fSSascha Wildner * 1760d02842fSSascha Wildner * Wait ten seconds, then try again. This is to get S4/S5 to work on 1770d02842fSSascha Wildner * all machines. 1780d02842fSSascha Wildner * 1790d02842fSSascha Wildner * We wait so long to allow chipsets that poll this reg very slowly 1800d02842fSSascha Wildner * to still read the right value. Ideally, this block would go 1810d02842fSSascha Wildner * away entirely. 1820d02842fSSascha Wildner */ 1830d02842fSSascha Wildner AcpiOsStall (10 * ACPI_USEC_PER_SEC); 1840d02842fSSascha Wildner 1850d02842fSSascha Wildner Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_CONTROL, 1860d02842fSSascha Wildner SleepEnableRegInfo->AccessBitMask); 1870d02842fSSascha Wildner if (ACPI_FAILURE (Status)) 1880d02842fSSascha Wildner { 1890d02842fSSascha Wildner return_ACPI_STATUS (Status); 1900d02842fSSascha Wildner } 1910d02842fSSascha Wildner } 1920d02842fSSascha Wildner 1930d02842fSSascha Wildner /* Wait for transition back to Working State */ 1940d02842fSSascha Wildner 1950d02842fSSascha Wildner do 1960d02842fSSascha Wildner { 1970d02842fSSascha Wildner Status = AcpiReadBitRegister (ACPI_BITREG_WAKE_STATUS, &InValue); 1980d02842fSSascha Wildner if (ACPI_FAILURE (Status)) 1990d02842fSSascha Wildner { 2000d02842fSSascha Wildner return_ACPI_STATUS (Status); 2010d02842fSSascha Wildner } 2020d02842fSSascha Wildner 2030d02842fSSascha Wildner } while (!InValue); 2040d02842fSSascha Wildner 2050d02842fSSascha Wildner return_ACPI_STATUS (AE_OK); 2060d02842fSSascha Wildner } 2070d02842fSSascha Wildner 2080d02842fSSascha Wildner 2090d02842fSSascha Wildner /******************************************************************************* 2100d02842fSSascha Wildner * 2110d02842fSSascha Wildner * FUNCTION: AcpiHwLegacyWakePrep 2120d02842fSSascha Wildner * 2130d02842fSSascha Wildner * PARAMETERS: SleepState - Which sleep state we just exited 2140d02842fSSascha Wildner * 2150d02842fSSascha Wildner * RETURN: Status 2160d02842fSSascha Wildner * 2170d02842fSSascha Wildner * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a 2180d02842fSSascha Wildner * sleep. 2190d02842fSSascha Wildner * Called with interrupts ENABLED. 2200d02842fSSascha Wildner * 2210d02842fSSascha Wildner ******************************************************************************/ 2220d02842fSSascha Wildner 2230d02842fSSascha Wildner ACPI_STATUS 2240d02842fSSascha Wildner AcpiHwLegacyWakePrep ( 2250d02842fSSascha Wildner UINT8 SleepState) 2260d02842fSSascha Wildner { 2270d02842fSSascha Wildner ACPI_STATUS Status; 2280d02842fSSascha Wildner ACPI_BIT_REGISTER_INFO *SleepTypeRegInfo; 2290d02842fSSascha Wildner ACPI_BIT_REGISTER_INFO *SleepEnableRegInfo; 2300d02842fSSascha Wildner UINT32 Pm1aControl; 2310d02842fSSascha Wildner UINT32 Pm1bControl; 2320d02842fSSascha Wildner 2330d02842fSSascha Wildner 2340d02842fSSascha Wildner ACPI_FUNCTION_TRACE (HwLegacyWakePrep); 2350d02842fSSascha Wildner 2360d02842fSSascha Wildner /* 2370d02842fSSascha Wildner * Set SLP_TYPE and SLP_EN to state S0. 2380d02842fSSascha Wildner * This is unclear from the ACPI Spec, but it is required 2390d02842fSSascha Wildner * by some machines. 2400d02842fSSascha Wildner */ 2410d02842fSSascha Wildner Status = AcpiGetSleepTypeData (ACPI_STATE_S0, 2420d02842fSSascha Wildner &AcpiGbl_SleepTypeA, &AcpiGbl_SleepTypeB); 2430d02842fSSascha Wildner if (ACPI_SUCCESS (Status)) 2440d02842fSSascha Wildner { 2450d02842fSSascha Wildner SleepTypeRegInfo = 2460d02842fSSascha Wildner AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_TYPE); 2470d02842fSSascha Wildner SleepEnableRegInfo = 2480d02842fSSascha Wildner AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_ENABLE); 2490d02842fSSascha Wildner 2500d02842fSSascha Wildner /* Get current value of PM1A control */ 2510d02842fSSascha Wildner 2520d02842fSSascha Wildner Status = AcpiHwRegisterRead (ACPI_REGISTER_PM1_CONTROL, 2530d02842fSSascha Wildner &Pm1aControl); 2540d02842fSSascha Wildner if (ACPI_SUCCESS (Status)) 2550d02842fSSascha Wildner { 2560d02842fSSascha Wildner /* Clear the SLP_EN and SLP_TYP fields */ 2570d02842fSSascha Wildner 2580d02842fSSascha Wildner Pm1aControl &= ~(SleepTypeRegInfo->AccessBitMask | 2590d02842fSSascha Wildner SleepEnableRegInfo->AccessBitMask); 2600d02842fSSascha Wildner Pm1bControl = Pm1aControl; 2610d02842fSSascha Wildner 2620d02842fSSascha Wildner /* Insert the SLP_TYP bits */ 2630d02842fSSascha Wildner 2640d02842fSSascha Wildner Pm1aControl |= (AcpiGbl_SleepTypeA << 2650d02842fSSascha Wildner SleepTypeRegInfo->BitPosition); 2660d02842fSSascha Wildner Pm1bControl |= (AcpiGbl_SleepTypeB << 2670d02842fSSascha Wildner SleepTypeRegInfo->BitPosition); 2680d02842fSSascha Wildner 2690d02842fSSascha Wildner /* Write the control registers and ignore any errors */ 2700d02842fSSascha Wildner 2710d02842fSSascha Wildner (void) AcpiHwWritePm1Control (Pm1aControl, Pm1bControl); 2720d02842fSSascha Wildner } 2730d02842fSSascha Wildner } 2740d02842fSSascha Wildner 2750d02842fSSascha Wildner return_ACPI_STATUS (Status); 2760d02842fSSascha Wildner } 2770d02842fSSascha Wildner 2780d02842fSSascha Wildner 2790d02842fSSascha Wildner /******************************************************************************* 2800d02842fSSascha Wildner * 2810d02842fSSascha Wildner * FUNCTION: AcpiHwLegacyWake 2820d02842fSSascha Wildner * 2830d02842fSSascha Wildner * PARAMETERS: SleepState - Which sleep state we just exited 2840d02842fSSascha Wildner * 2850d02842fSSascha Wildner * RETURN: Status 2860d02842fSSascha Wildner * 2870d02842fSSascha Wildner * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep 2880d02842fSSascha Wildner * Called with interrupts ENABLED. 2890d02842fSSascha Wildner * 2900d02842fSSascha Wildner ******************************************************************************/ 2910d02842fSSascha Wildner 2920d02842fSSascha Wildner ACPI_STATUS 2930d02842fSSascha Wildner AcpiHwLegacyWake ( 2940d02842fSSascha Wildner UINT8 SleepState) 2950d02842fSSascha Wildner { 2960d02842fSSascha Wildner ACPI_STATUS Status; 2970d02842fSSascha Wildner 2980d02842fSSascha Wildner 2990d02842fSSascha Wildner ACPI_FUNCTION_TRACE (HwLegacyWake); 3000d02842fSSascha Wildner 3010d02842fSSascha Wildner 3020d02842fSSascha Wildner /* Ensure EnterSleepStatePrep -> EnterSleepState ordering */ 3030d02842fSSascha Wildner 3040d02842fSSascha Wildner AcpiGbl_SleepTypeA = ACPI_SLEEP_TYPE_INVALID; 3050d02842fSSascha Wildner AcpiHwExecuteSleepMethod (METHOD_PATHNAME__SST, ACPI_SST_WAKING); 3060d02842fSSascha Wildner 3070d02842fSSascha Wildner /* 3080d02842fSSascha Wildner * GPEs must be enabled before _WAK is called as GPEs 3090d02842fSSascha Wildner * might get fired there 3100d02842fSSascha Wildner * 3110d02842fSSascha Wildner * Restore the GPEs: 3120d02842fSSascha Wildner * 1) Disable/Clear all GPEs 3130d02842fSSascha Wildner * 2) Enable all runtime GPEs 3140d02842fSSascha Wildner */ 3150d02842fSSascha Wildner Status = AcpiHwDisableAllGpes (); 3160d02842fSSascha Wildner if (ACPI_FAILURE (Status)) 3170d02842fSSascha Wildner { 3180d02842fSSascha Wildner return_ACPI_STATUS (Status); 3190d02842fSSascha Wildner } 3200d02842fSSascha Wildner 3210d02842fSSascha Wildner Status = AcpiHwEnableAllRuntimeGpes (); 3220d02842fSSascha Wildner if (ACPI_FAILURE (Status)) 3230d02842fSSascha Wildner { 3240d02842fSSascha Wildner return_ACPI_STATUS (Status); 3250d02842fSSascha Wildner } 3260d02842fSSascha Wildner 3270d02842fSSascha Wildner /* 3280d02842fSSascha Wildner * Now we can execute _WAK, etc. Some machines require that the GPEs 3290d02842fSSascha Wildner * are enabled before the wake methods are executed. 3300d02842fSSascha Wildner */ 3310d02842fSSascha Wildner AcpiHwExecuteSleepMethod (METHOD_PATHNAME__WAK, SleepState); 3320d02842fSSascha Wildner 3330d02842fSSascha Wildner /* 3340d02842fSSascha Wildner * Some BIOS code assumes that WAK_STS will be cleared on resume 3350d02842fSSascha Wildner * and use it to determine whether the system is rebooting or 3360d02842fSSascha Wildner * resuming. Clear WAK_STS for compatibility. 3370d02842fSSascha Wildner */ 338820c5b08SSascha Wildner (void) AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS, 339820c5b08SSascha Wildner ACPI_CLEAR_STATUS); 3400d02842fSSascha Wildner AcpiGbl_SystemAwakeAndRunning = TRUE; 3410d02842fSSascha Wildner 3420d02842fSSascha Wildner /* Enable power button */ 3430d02842fSSascha Wildner 3440d02842fSSascha Wildner (void) AcpiWriteBitRegister( 3450d02842fSSascha Wildner AcpiGbl_FixedEventInfo[ACPI_EVENT_POWER_BUTTON].EnableRegisterId, 3460d02842fSSascha Wildner ACPI_ENABLE_EVENT); 3470d02842fSSascha Wildner 3480d02842fSSascha Wildner (void) AcpiWriteBitRegister( 3490d02842fSSascha Wildner AcpiGbl_FixedEventInfo[ACPI_EVENT_POWER_BUTTON].StatusRegisterId, 3500d02842fSSascha Wildner ACPI_CLEAR_STATUS); 3510d02842fSSascha Wildner 3520d02842fSSascha Wildner AcpiHwExecuteSleepMethod (METHOD_PATHNAME__SST, ACPI_SST_WORKING); 3530d02842fSSascha Wildner return_ACPI_STATUS (Status); 3540d02842fSSascha Wildner } 3550d02842fSSascha Wildner 3560d02842fSSascha Wildner #endif /* !ACPI_REDUCED_HARDWARE */ 357