hwsleep.c revision 281075
1126700Sdes/****************************************************************************** 2228991Suqs * 3126700Sdes * Name: hwsleep.c - ACPI Hardware Sleep/Wake Support functions for the 4126700Sdes * original/legacy sleep/PM registers. 5126700Sdes * 6126700Sdes *****************************************************************************/ 7126700Sdes 8126700Sdes/* 9126700Sdes * Copyright (C) 2000 - 2015, Intel Corp. 10126700Sdes * All rights reserved. 11126700Sdes * 12126700Sdes * Redistribution and use in source and binary forms, with or without 13126700Sdes * modification, are permitted provided that the following conditions 14126700Sdes * are met: 15126700Sdes * 1. Redistributions of source code must retain the above copyright 16126700Sdes * notice, this list of conditions, and the following disclaimer, 17126700Sdes * without modification. 18126700Sdes * 2. Redistributions in binary form must reproduce at minimum a disclaimer 19126700Sdes * substantially similar to the "NO WARRANTY" disclaimer below 20126700Sdes * ("Disclaimer") and any redistribution must be conditioned upon 21126700Sdes * including a substantially similar Disclaimer requirement for further 22126700Sdes * binary redistribution. 23126700Sdes * 3. Neither the names of the above-listed copyright holders nor the names 24126700Sdes * of any contributors may be used to endorse or promote products derived 25126700Sdes * from this software without specific prior written permission. 26126700Sdes * 27126700Sdes * Alternatively, this software may be distributed under the terms of the 28126700Sdes * GNU General Public License ("GPL") version 2 as published by the Free 29126700Sdes * Software Foundation. 30126700Sdes * 31126700Sdes * NO WARRANTY 32126700Sdes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 33126700Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 34126700Sdes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 35126700Sdes * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 36126700Sdes * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 37126700Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 38126700Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 39126700Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 40126700Sdes * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 41126700Sdes * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 42126700Sdes * POSSIBILITY OF SUCH DAMAGES. 43126700Sdes */ 44126700Sdes 45126700Sdes#include <contrib/dev/acpica/include/acpi.h> 46126700Sdes#include <contrib/dev/acpica/include/accommon.h> 47126700Sdes 48126700Sdes#define _COMPONENT ACPI_HARDWARE 49126700Sdes ACPI_MODULE_NAME ("hwsleep") 50126700Sdes 51126700Sdes 52126700Sdes#if (!ACPI_REDUCED_HARDWARE) /* Entire module */ 53126700Sdes/******************************************************************************* 54126700Sdes * 55126700Sdes * FUNCTION: AcpiHwLegacySleep 56126700Sdes * 57126700Sdes * PARAMETERS: SleepState - Which sleep state to enter 58126700Sdes * 59126700Sdes * RETURN: Status 60126700Sdes * 61126700Sdes * DESCRIPTION: Enter a system sleep state via the legacy FADT PM registers 62126700Sdes * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED 63126700Sdes * 64126700Sdes ******************************************************************************/ 65126700Sdes 66126700SdesACPI_STATUS 67126700SdesAcpiHwLegacySleep ( 68126700Sdes UINT8 SleepState) 69126700Sdes{ 70126700Sdes ACPI_BIT_REGISTER_INFO *SleepTypeRegInfo; 71126700Sdes ACPI_BIT_REGISTER_INFO *SleepEnableRegInfo; 72126700Sdes UINT32 Pm1aControl; 73126700Sdes UINT32 Pm1bControl; 74126700Sdes UINT32 InValue; 75126700Sdes ACPI_STATUS Status; 76126700Sdes 77126700Sdes 78126700Sdes ACPI_FUNCTION_TRACE (HwLegacySleep); 79126700Sdes 80126700Sdes 81126700Sdes SleepTypeRegInfo = AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_TYPE); 82126700Sdes SleepEnableRegInfo = AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_ENABLE); 83126700Sdes 84126700Sdes /* Clear wake status */ 85126700Sdes 86126700Sdes Status = AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS); 87126700Sdes if (ACPI_FAILURE (Status)) 88126700Sdes { 89126700Sdes return_ACPI_STATUS (Status); 90126700Sdes } 91126700Sdes 92126700Sdes /* Clear all fixed and general purpose status bits */ 93126700Sdes 94126700Sdes Status = AcpiHwClearAcpiStatus (); 95126700Sdes if (ACPI_FAILURE (Status)) 96126700Sdes { 97126700Sdes return_ACPI_STATUS (Status); 98126700Sdes } 99126700Sdes 100126700Sdes /* 101126700Sdes * 1) Disable/Clear all GPEs 102126700Sdes * 2) Enable all wakeup GPEs 103126700Sdes */ 104126700Sdes Status = AcpiHwDisableAllGpes (); 105126700Sdes if (ACPI_FAILURE (Status)) 106126700Sdes { 107126700Sdes return_ACPI_STATUS (Status); 108126700Sdes } 109126700Sdes AcpiGbl_SystemAwakeAndRunning = FALSE; 110126700Sdes 111126700Sdes Status = AcpiHwEnableAllWakeupGpes (); 112126700Sdes if (ACPI_FAILURE (Status)) 113126700Sdes { 114126700Sdes return_ACPI_STATUS (Status); 115126700Sdes } 116126700Sdes 117126700Sdes /* Get current value of PM1A control */ 118126700Sdes 119126700Sdes Status = AcpiHwRegisterRead (ACPI_REGISTER_PM1_CONTROL, 120126700Sdes &Pm1aControl); 121126700Sdes if (ACPI_FAILURE (Status)) 122126700Sdes { 123126700Sdes return_ACPI_STATUS (Status); 124126700Sdes } 125126700Sdes ACPI_DEBUG_PRINT ((ACPI_DB_INIT, 126126700Sdes "Entering sleep state [S%u]\n", SleepState)); 127126700Sdes 128126700Sdes /* Clear the SLP_EN and SLP_TYP fields */ 129126700Sdes 130126700Sdes Pm1aControl &= ~(SleepTypeRegInfo->AccessBitMask | 131126700Sdes SleepEnableRegInfo->AccessBitMask); 132126700Sdes Pm1bControl = Pm1aControl; 133126700Sdes 134126700Sdes /* Insert the SLP_TYP bits */ 135126700Sdes 136126700Sdes Pm1aControl |= (AcpiGbl_SleepTypeA << SleepTypeRegInfo->BitPosition); 137126700Sdes Pm1bControl |= (AcpiGbl_SleepTypeB << SleepTypeRegInfo->BitPosition); 138126700Sdes 139126700Sdes /* 140126700Sdes * We split the writes of SLP_TYP and SLP_EN to workaround 141126700Sdes * poorly implemented hardware. 142126700Sdes */ 143126700Sdes 144126700Sdes /* Write #1: write the SLP_TYP data to the PM1 Control registers */ 145126700Sdes 146126700Sdes Status = AcpiHwWritePm1Control (Pm1aControl, Pm1bControl); 147126700Sdes if (ACPI_FAILURE (Status)) 148126700Sdes { 149126700Sdes return_ACPI_STATUS (Status); 150126700Sdes } 151126700Sdes 152126700Sdes /* Insert the sleep enable (SLP_EN) bit */ 153126700Sdes 154126700Sdes Pm1aControl |= SleepEnableRegInfo->AccessBitMask; 155126700Sdes Pm1bControl |= SleepEnableRegInfo->AccessBitMask; 156126700Sdes 157126700Sdes /* Flush caches, as per ACPI specification */ 158126700Sdes 159126700Sdes ACPI_FLUSH_CPU_CACHE (); 160126700Sdes 161126700Sdes /* Write #2: Write both SLP_TYP + SLP_EN */ 162126700Sdes 163126700Sdes Status = AcpiHwWritePm1Control (Pm1aControl, Pm1bControl); 164126700Sdes if (ACPI_FAILURE (Status)) 165126700Sdes { 166126700Sdes return_ACPI_STATUS (Status); 167126700Sdes } 168126700Sdes 169126700Sdes if (SleepState > ACPI_STATE_S3) 170126700Sdes { 171126700Sdes /* 172126700Sdes * We wanted to sleep > S3, but it didn't happen (by virtue of the 173126700Sdes * fact that we are still executing!) 174126700Sdes * 175126700Sdes * Wait ten seconds, then try again. This is to get S4/S5 to work on 176126700Sdes * all machines. 177126700Sdes * 178126700Sdes * We wait so long to allow chipsets that poll this reg very slowly 179126700Sdes * to still read the right value. Ideally, this block would go 180126700Sdes * away entirely. 181126700Sdes */ 182126700Sdes AcpiOsStall (10 * ACPI_USEC_PER_SEC); 183126700Sdes 184126700Sdes Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_CONTROL, 185126700Sdes SleepEnableRegInfo->AccessBitMask); 186126700Sdes if (ACPI_FAILURE (Status)) 187126700Sdes { 188126700Sdes return_ACPI_STATUS (Status); 189126700Sdes } 190126700Sdes } 191126700Sdes 192126700Sdes /* Wait for transition back to Working State */ 193126700Sdes 194126700Sdes do 195126700Sdes { 196126700Sdes Status = AcpiReadBitRegister (ACPI_BITREG_WAKE_STATUS, &InValue); 197126700Sdes if (ACPI_FAILURE (Status)) 198126700Sdes { 199126700Sdes return_ACPI_STATUS (Status); 200126700Sdes } 201126700Sdes 202126700Sdes } while (!InValue); 203126700Sdes 204126700Sdes return_ACPI_STATUS (AE_OK); 205126700Sdes} 206126700Sdes 207126700Sdes 208126700Sdes/******************************************************************************* 209126700Sdes * 210126700Sdes * FUNCTION: AcpiHwLegacyWakePrep 211126700Sdes * 212126700Sdes * PARAMETERS: SleepState - Which sleep state we just exited 213126700Sdes * 214126700Sdes * RETURN: Status 215126700Sdes * 216126700Sdes * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a 217126700Sdes * sleep. 218126700Sdes * Called with interrupts ENABLED. 219126700Sdes * 220126700Sdes ******************************************************************************/ 221126700Sdes 222126700SdesACPI_STATUS 223126700SdesAcpiHwLegacyWakePrep ( 224126700Sdes UINT8 SleepState) 225126700Sdes{ 226126700Sdes ACPI_STATUS Status; 227126700Sdes ACPI_BIT_REGISTER_INFO *SleepTypeRegInfo; 228126700Sdes ACPI_BIT_REGISTER_INFO *SleepEnableRegInfo; 229126700Sdes UINT32 Pm1aControl; 230126700Sdes UINT32 Pm1bControl; 231126700Sdes 232126700Sdes 233126700Sdes ACPI_FUNCTION_TRACE (HwLegacyWakePrep); 234126700Sdes 235126700Sdes /* 236126700Sdes * Set SLP_TYPE and SLP_EN to state S0. 237126700Sdes * This is unclear from the ACPI Spec, but it is required 238126700Sdes * by some machines. 239126700Sdes */ 240126700Sdes Status = AcpiGetSleepTypeData (ACPI_STATE_S0, 241126700Sdes &AcpiGbl_SleepTypeA, &AcpiGbl_SleepTypeB); 242126700Sdes if (ACPI_SUCCESS (Status)) 243126700Sdes { 244126700Sdes SleepTypeRegInfo = 245126700Sdes AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_TYPE); 246126700Sdes SleepEnableRegInfo = 247126700Sdes AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_ENABLE); 248126700Sdes 249126700Sdes /* Get current value of PM1A control */ 250126700Sdes 251126700Sdes Status = AcpiHwRegisterRead (ACPI_REGISTER_PM1_CONTROL, 252126700Sdes &Pm1aControl); 253126700Sdes if (ACPI_SUCCESS (Status)) 254126700Sdes { 255126700Sdes /* Clear the SLP_EN and SLP_TYP fields */ 256126700Sdes 257126700Sdes Pm1aControl &= ~(SleepTypeRegInfo->AccessBitMask | 258126700Sdes SleepEnableRegInfo->AccessBitMask); 259126700Sdes Pm1bControl = Pm1aControl; 260126700Sdes 261126700Sdes /* Insert the SLP_TYP bits */ 262126700Sdes 263126700Sdes Pm1aControl |= (AcpiGbl_SleepTypeA << 264126700Sdes SleepTypeRegInfo->BitPosition); 265126700Sdes Pm1bControl |= (AcpiGbl_SleepTypeB << 266126700Sdes SleepTypeRegInfo->BitPosition); 267126700Sdes 268126700Sdes /* Write the control registers and ignore any errors */ 269126700Sdes 270126700Sdes (void) AcpiHwWritePm1Control (Pm1aControl, Pm1bControl); 271126700Sdes } 272126700Sdes } 273126700Sdes 274126700Sdes return_ACPI_STATUS (Status); 275126700Sdes} 276126700Sdes 277126700Sdes 278126700Sdes/******************************************************************************* 279126700Sdes * 280126700Sdes * FUNCTION: AcpiHwLegacyWake 281126700Sdes * 282126700Sdes * PARAMETERS: SleepState - Which sleep state we just exited 283126700Sdes * 284126700Sdes * RETURN: Status 285126700Sdes * 286126700Sdes * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep 287126700Sdes * Called with interrupts ENABLED. 288126700Sdes * 289126700Sdes ******************************************************************************/ 290126700Sdes 291126700SdesACPI_STATUS 292126700SdesAcpiHwLegacyWake ( 293126700Sdes UINT8 SleepState) 294126700Sdes{ 295126700Sdes ACPI_STATUS Status; 296126700Sdes 297126700Sdes 298126700Sdes ACPI_FUNCTION_TRACE (HwLegacyWake); 299126700Sdes 300126700Sdes 301126700Sdes /* Ensure EnterSleepStatePrep -> EnterSleepState ordering */ 302126700Sdes 303126700Sdes AcpiGbl_SleepTypeA = ACPI_SLEEP_TYPE_INVALID; 304126700Sdes AcpiHwExecuteSleepMethod (METHOD_PATHNAME__SST, ACPI_SST_WAKING); 305126700Sdes 306126700Sdes /* 307126700Sdes * GPEs must be enabled before _WAK is called as GPEs 308126700Sdes * might get fired there 309126700Sdes * 310126700Sdes * Restore the GPEs: 311126700Sdes * 1) Disable/Clear all GPEs 312126700Sdes * 2) Enable all runtime GPEs 313126700Sdes */ 314126700Sdes Status = AcpiHwDisableAllGpes (); 315126700Sdes if (ACPI_FAILURE (Status)) 316126700Sdes { 317126700Sdes return_ACPI_STATUS (Status); 318126700Sdes } 319126700Sdes 320126700Sdes Status = AcpiHwEnableAllRuntimeGpes (); 321126700Sdes if (ACPI_FAILURE (Status)) 322126700Sdes { 323126700Sdes return_ACPI_STATUS (Status); 324126700Sdes } 325126700Sdes 326126700Sdes /* 327126700Sdes * Now we can execute _WAK, etc. Some machines require that the GPEs 328126700Sdes * are enabled before the wake methods are executed. 329126700Sdes */ 330126700Sdes AcpiHwExecuteSleepMethod (METHOD_PATHNAME__WAK, SleepState); 331126700Sdes 332126700Sdes /* 333126700Sdes * Some BIOS code assumes that WAK_STS will be cleared on resume 334126700Sdes * and use it to determine whether the system is rebooting or 335126700Sdes * resuming. Clear WAK_STS for compatibility. 336126700Sdes */ 337126700Sdes (void) AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS); 338126700Sdes AcpiGbl_SystemAwakeAndRunning = TRUE; 339126700Sdes 340126700Sdes /* Enable power button */ 341126700Sdes 342126700Sdes (void) AcpiWriteBitRegister( 343126700Sdes AcpiGbl_FixedEventInfo[ACPI_EVENT_POWER_BUTTON].EnableRegisterId, 344126700Sdes ACPI_ENABLE_EVENT); 345126700Sdes 346126700Sdes (void) AcpiWriteBitRegister( 347126700Sdes AcpiGbl_FixedEventInfo[ACPI_EVENT_POWER_BUTTON].StatusRegisterId, 348126700Sdes ACPI_CLEAR_STATUS); 349126700Sdes 350126700Sdes AcpiHwExecuteSleepMethod (METHOD_PATHNAME__SST, ACPI_SST_WORKING); 351126700Sdes return_ACPI_STATUS (Status); 352126700Sdes} 353126700Sdes 354126700Sdes#endif /* !ACPI_REDUCED_HARDWARE */ 355126700Sdes