hwsleep.c revision 239340
171867Smsmith/****************************************************************************** 271867Smsmith * 3231844Sjkim * Name: hwsleep.c - ACPI Hardware Sleep/Wake Support functions for the 4231844Sjkim * original/legacy sleep/PM registers. 571867Smsmith * 671867Smsmith *****************************************************************************/ 771867Smsmith 8217365Sjkim/* 9229989Sjkim * Copyright (C) 2000 - 2012, Intel Corp. 1071867Smsmith * All rights reserved. 1171867Smsmith * 12217365Sjkim * Redistribution and use in source and binary forms, with or without 13217365Sjkim * modification, are permitted provided that the following conditions 14217365Sjkim * are met: 15217365Sjkim * 1. Redistributions of source code must retain the above copyright 16217365Sjkim * notice, this list of conditions, and the following disclaimer, 17217365Sjkim * without modification. 18217365Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer 19217365Sjkim * substantially similar to the "NO WARRANTY" disclaimer below 20217365Sjkim * ("Disclaimer") and any redistribution must be conditioned upon 21217365Sjkim * including a substantially similar Disclaimer requirement for further 22217365Sjkim * binary redistribution. 23217365Sjkim * 3. Neither the names of the above-listed copyright holders nor the names 24217365Sjkim * of any contributors may be used to endorse or promote products derived 25217365Sjkim * from this software without specific prior written permission. 2671867Smsmith * 27217365Sjkim * Alternatively, this software may be distributed under the terms of the 28217365Sjkim * GNU General Public License ("GPL") version 2 as published by the Free 29217365Sjkim * Software Foundation. 3071867Smsmith * 31217365Sjkim * NO WARRANTY 32217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 33217365Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 34217365Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 35217365Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 36217365Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 37217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 38217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 39217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 40217365Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 41217365Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 42217365Sjkim * POSSIBILITY OF SUCH DAMAGES. 43217365Sjkim */ 4471867Smsmith 45193341Sjkim#include <contrib/dev/acpica/include/acpi.h> 46193341Sjkim#include <contrib/dev/acpica/include/accommon.h> 4771867Smsmith 4877424Smsmith#define _COMPONENT ACPI_HARDWARE 4991116Smsmith ACPI_MODULE_NAME ("hwsleep") 5071867Smsmith 5171867Smsmith 52231844Sjkim#if (!ACPI_REDUCED_HARDWARE) /* Entire module */ 53151937Sjkim/******************************************************************************* 5471867Smsmith * 55231844Sjkim * FUNCTION: AcpiHwLegacySleep 5671867Smsmith * 5771867Smsmith * PARAMETERS: SleepState - Which sleep state to enter 5871867Smsmith * 5971867Smsmith * RETURN: Status 6071867Smsmith * 61231844Sjkim * DESCRIPTION: Enter a system sleep state via the legacy FADT PM registers 6287031Smsmith * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED 6387031Smsmith * 6487031Smsmith ******************************************************************************/ 6587031Smsmith 6687031SmsmithACPI_STATUS 67231844SjkimAcpiHwLegacySleep ( 68239340Sjkim UINT8 SleepState) 6987031Smsmith{ 70231844Sjkim ACPI_BIT_REGISTER_INFO *SleepTypeRegInfo; 71231844Sjkim ACPI_BIT_REGISTER_INFO *SleepEnableRegInfo; 72193267Sjkim UINT32 Pm1aControl; 73193267Sjkim UINT32 Pm1bControl; 7499679Siwasaki UINT32 InValue; 75193335Sjkim UINT32 Retry; 7699679Siwasaki ACPI_STATUS Status; 7787031Smsmith 7887031Smsmith 79231844Sjkim ACPI_FUNCTION_TRACE (HwLegacySleep); 8087031Smsmith 8191116Smsmith 82231844Sjkim SleepTypeRegInfo = AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_TYPE); 8391116Smsmith SleepEnableRegInfo = AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_ENABLE); 8471867Smsmith 85128245Snjl /* Clear wake status */ 86128245Snjl 87193267Sjkim Status = AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS); 88128245Snjl if (ACPI_FAILURE (Status)) 8999679Siwasaki { 90128245Snjl return_ACPI_STATUS (Status); 91128245Snjl } 9278986Smsmith 93129684Snjl /* Clear all fixed and general purpose status bits */ 94129684Snjl 95167802Sjkim Status = AcpiHwClearAcpiStatus (); 96128245Snjl if (ACPI_FAILURE (Status)) 97128245Snjl { 98128245Snjl return_ACPI_STATUS (Status); 99128245Snjl } 10087031Smsmith 101128212Snjl /* 102129684Snjl * 1) Disable/Clear all GPEs 103128212Snjl * 2) Enable all wakeup GPEs 104128212Snjl */ 105151937Sjkim Status = AcpiHwDisableAllGpes (); 10699679Siwasaki if (ACPI_FAILURE (Status)) 10799679Siwasaki { 10899679Siwasaki return_ACPI_STATUS (Status); 10999679Siwasaki } 110129684Snjl AcpiGbl_SystemAwakeAndRunning = FALSE; 11199679Siwasaki 112151937Sjkim Status = AcpiHwEnableAllWakeupGpes (); 113129684Snjl if (ACPI_FAILURE (Status)) 114129684Snjl { 115129684Snjl return_ACPI_STATUS (Status); 116129684Snjl } 117129684Snjl 11891116Smsmith /* Get current value of PM1A control */ 11978986Smsmith 120193267Sjkim Status = AcpiHwRegisterRead (ACPI_REGISTER_PM1_CONTROL, 121193267Sjkim &Pm1aControl); 12299679Siwasaki if (ACPI_FAILURE (Status)) 12399679Siwasaki { 12499679Siwasaki return_ACPI_STATUS (Status); 12599679Siwasaki } 126151937Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_INIT, 127209746Sjkim "Entering sleep state [S%u]\n", SleepState)); 12882367Smsmith 129193267Sjkim /* Clear the SLP_EN and SLP_TYP fields */ 13082367Smsmith 131193267Sjkim Pm1aControl &= ~(SleepTypeRegInfo->AccessBitMask | 132151937Sjkim SleepEnableRegInfo->AccessBitMask); 133193267Sjkim Pm1bControl = Pm1aControl; 13471867Smsmith 135193267Sjkim /* Insert the SLP_TYP bits */ 13682367Smsmith 137193267Sjkim Pm1aControl |= (AcpiGbl_SleepTypeA << SleepTypeRegInfo->BitPosition); 138193267Sjkim Pm1bControl |= (AcpiGbl_SleepTypeB << SleepTypeRegInfo->BitPosition); 13971867Smsmith 140126372Snjl /* 141126372Snjl * We split the writes of SLP_TYP and SLP_EN to workaround 142126372Snjl * poorly implemented hardware. 143126372Snjl */ 144126372Snjl 145193267Sjkim /* Write #1: write the SLP_TYP data to the PM1 Control registers */ 14671867Smsmith 147193267Sjkim Status = AcpiHwWritePm1Control (Pm1aControl, Pm1bControl); 14899679Siwasaki if (ACPI_FAILURE (Status)) 14999679Siwasaki { 15099679Siwasaki return_ACPI_STATUS (Status); 15199679Siwasaki } 15282367Smsmith 153193267Sjkim /* Insert the sleep enable (SLP_EN) bit */ 15499679Siwasaki 155193267Sjkim Pm1aControl |= SleepEnableRegInfo->AccessBitMask; 156193267Sjkim Pm1bControl |= SleepEnableRegInfo->AccessBitMask; 15782367Smsmith 158193267Sjkim /* Flush caches, as per ACPI specification */ 15971867Smsmith 16099679Siwasaki ACPI_FLUSH_CPU_CACHE (); 16180062Smsmith 162193267Sjkim /* Write #2: Write both SLP_TYP + SLP_EN */ 16399679Siwasaki 164193267Sjkim Status = AcpiHwWritePm1Control (Pm1aControl, Pm1bControl); 16599679Siwasaki if (ACPI_FAILURE (Status)) 16699679Siwasaki { 16799679Siwasaki return_ACPI_STATUS (Status); 16899679Siwasaki } 16999679Siwasaki 17082367Smsmith if (SleepState > ACPI_STATE_S3) 17182367Smsmith { 17299679Siwasaki /* 173151937Sjkim * We wanted to sleep > S3, but it didn't happen (by virtue of the 174151937Sjkim * fact that we are still executing!) 175123315Snjl * 176151937Sjkim * Wait ten seconds, then try again. This is to get S4/S5 to work on 177151937Sjkim * all machines. 178123315Snjl * 179193267Sjkim * We wait so long to allow chipsets that poll this reg very slowly 180193267Sjkim * to still read the right value. Ideally, this block would go 18199679Siwasaki * away entirely. 18299679Siwasaki */ 18399679Siwasaki AcpiOsStall (10000000); 18482367Smsmith 185193267Sjkim Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_CONTROL, 18699679Siwasaki SleepEnableRegInfo->AccessBitMask); 18799679Siwasaki if (ACPI_FAILURE (Status)) 18899679Siwasaki { 18999679Siwasaki return_ACPI_STATUS (Status); 19099679Siwasaki } 19180357Speter } 19280062Smsmith 193231844Sjkim /* Wait for transition back to Working State */ 19471867Smsmith 195193335Sjkim Retry = 1000; 196102550Siwasaki do 19783174Smsmith { 198193267Sjkim Status = AcpiReadBitRegister (ACPI_BITREG_WAKE_STATUS, &InValue); 19999679Siwasaki if (ACPI_FAILURE (Status)) 20099679Siwasaki { 20199679Siwasaki return_ACPI_STATUS (Status); 20299679Siwasaki } 20399679Siwasaki 204204920Sjkim if (AcpiGbl_EnableInterpreterSlack) 205193335Sjkim { 206204920Sjkim /* 207204920Sjkim * Some BIOSs don't set WAK_STS at all. Give up waiting after 208204920Sjkim * 1000 retries if it still isn't set. 209204920Sjkim */ 210204920Sjkim if (Retry-- == 0) 211204920Sjkim { 212204920Sjkim break; 213204920Sjkim } 214193335Sjkim } 215193335Sjkim 21699679Siwasaki } while (!InValue); 21799679Siwasaki 21871867Smsmith return_ACPI_STATUS (AE_OK); 21971867Smsmith} 22082367Smsmith 221114237Snjl 222151937Sjkim/******************************************************************************* 22382367Smsmith * 224231844Sjkim * FUNCTION: AcpiHwLegacyWakePrep 225114237Snjl * 22682367Smsmith * PARAMETERS: SleepState - Which sleep state we just exited 22782367Smsmith * 22882367Smsmith * RETURN: Status 22982367Smsmith * 230231844Sjkim * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a 231231844Sjkim * sleep. 232138287Smarks * Called with interrupts ENABLED. 23382367Smsmith * 23482367Smsmith ******************************************************************************/ 23582367Smsmith 23682367SmsmithACPI_STATUS 237231844SjkimAcpiHwLegacyWakePrep ( 238239340Sjkim UINT8 SleepState) 23982367Smsmith{ 240123315Snjl ACPI_STATUS Status; 241123315Snjl ACPI_BIT_REGISTER_INFO *SleepTypeRegInfo; 242123315Snjl ACPI_BIT_REGISTER_INFO *SleepEnableRegInfo; 243193267Sjkim UINT32 Pm1aControl; 244193267Sjkim UINT32 Pm1bControl; 24582367Smsmith 24683174Smsmith 247231844Sjkim ACPI_FUNCTION_TRACE (HwLegacyWakePrep); 24882367Smsmith 249126372Snjl /* 250126372Snjl * Set SLP_TYPE and SLP_EN to state S0. 251126372Snjl * This is unclear from the ACPI Spec, but it is required 252126372Snjl * by some machines. 253126372Snjl */ 254126372Snjl Status = AcpiGetSleepTypeData (ACPI_STATE_S0, 255126372Snjl &AcpiGbl_SleepTypeA, &AcpiGbl_SleepTypeB); 256123315Snjl if (ACPI_SUCCESS (Status)) 257123315Snjl { 258193267Sjkim SleepTypeRegInfo = 259193267Sjkim AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_TYPE); 260193267Sjkim SleepEnableRegInfo = 261193267Sjkim AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_ENABLE); 262123315Snjl 263126372Snjl /* Get current value of PM1A control */ 264123315Snjl 265193267Sjkim Status = AcpiHwRegisterRead (ACPI_REGISTER_PM1_CONTROL, 266193267Sjkim &Pm1aControl); 267126372Snjl if (ACPI_SUCCESS (Status)) 268126372Snjl { 269193267Sjkim /* Clear the SLP_EN and SLP_TYP fields */ 270126372Snjl 271193267Sjkim Pm1aControl &= ~(SleepTypeRegInfo->AccessBitMask | 272193267Sjkim SleepEnableRegInfo->AccessBitMask); 273193267Sjkim Pm1bControl = Pm1aControl; 274126372Snjl 275193267Sjkim /* Insert the SLP_TYP bits */ 276126372Snjl 277193267Sjkim Pm1aControl |= (AcpiGbl_SleepTypeA << 278193267Sjkim SleepTypeRegInfo->BitPosition); 279193267Sjkim Pm1bControl |= (AcpiGbl_SleepTypeB << 280193267Sjkim SleepTypeRegInfo->BitPosition); 281126372Snjl 282193267Sjkim /* Write the control registers and ignore any errors */ 283126372Snjl 284193267Sjkim (void) AcpiHwWritePm1Control (Pm1aControl, Pm1bControl); 285126372Snjl } 286123315Snjl } 287123315Snjl 288231844Sjkim return_ACPI_STATUS (Status); 289231844Sjkim} 29082367Smsmith 29191116Smsmith 292231844Sjkim/******************************************************************************* 293231844Sjkim * 294231844Sjkim * FUNCTION: AcpiHwLegacyWake 295231844Sjkim * 296231844Sjkim * PARAMETERS: SleepState - Which sleep state we just exited 297231844Sjkim * 298231844Sjkim * RETURN: Status 299231844Sjkim * 300231844Sjkim * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep 301231844Sjkim * Called with interrupts ENABLED. 302231844Sjkim * 303231844Sjkim ******************************************************************************/ 30491116Smsmith 305231844SjkimACPI_STATUS 306231844SjkimAcpiHwLegacyWake ( 307239340Sjkim UINT8 SleepState) 308231844Sjkim{ 309231844Sjkim ACPI_STATUS Status; 31082367Smsmith 31183174Smsmith 312231844Sjkim ACPI_FUNCTION_TRACE (HwLegacyWake); 313123315Snjl 31491116Smsmith 315231844Sjkim /* Ensure EnterSleepStatePrep -> EnterSleepState ordering */ 31691116Smsmith 317231844Sjkim AcpiGbl_SleepTypeA = ACPI_SLEEP_TYPE_INVALID; 318233250Sjkim AcpiHwExecuteSleepMethod (METHOD_PATHNAME__SST, ACPI_SST_WAKING); 319231844Sjkim 320128212Snjl /* 321231844Sjkim * GPEs must be enabled before _WAK is called as GPEs 322231844Sjkim * might get fired there 323231844Sjkim * 324128212Snjl * Restore the GPEs: 325129684Snjl * 1) Disable/Clear all GPEs 326128212Snjl * 2) Enable all runtime GPEs 327128212Snjl */ 328151937Sjkim Status = AcpiHwDisableAllGpes (); 32999679Siwasaki if (ACPI_FAILURE (Status)) 33099679Siwasaki { 33199679Siwasaki return_ACPI_STATUS (Status); 33299679Siwasaki } 33382367Smsmith 334151937Sjkim Status = AcpiHwEnableAllRuntimeGpes (); 335129684Snjl if (ACPI_FAILURE (Status)) 336129684Snjl { 337129684Snjl return_ACPI_STATUS (Status); 338129684Snjl } 339129684Snjl 340231844Sjkim /* 341231844Sjkim * Now we can execute _WAK, etc. Some machines require that the GPEs 342231844Sjkim * are enabled before the wake methods are executed. 343231844Sjkim */ 344233250Sjkim AcpiHwExecuteSleepMethod (METHOD_PATHNAME__WAK, SleepState); 345231844Sjkim 346231844Sjkim /* 347231844Sjkim * Some BIOS code assumes that WAK_STS will be cleared on resume 348231844Sjkim * and use it to determine whether the system is rebooting or 349231844Sjkim * resuming. Clear WAK_STS for compatibility. 350231844Sjkim */ 351231844Sjkim (void) AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS); 352231844Sjkim AcpiGbl_SystemAwakeAndRunning = TRUE; 353231844Sjkim 354126372Snjl /* Enable power button */ 355126372Snjl 356193267Sjkim (void) AcpiWriteBitRegister( 357193267Sjkim AcpiGbl_FixedEventInfo[ACPI_EVENT_POWER_BUTTON].EnableRegisterId, 358193267Sjkim ACPI_ENABLE_EVENT); 359151937Sjkim 360193267Sjkim (void) AcpiWriteBitRegister( 361193267Sjkim AcpiGbl_FixedEventInfo[ACPI_EVENT_POWER_BUTTON].StatusRegisterId, 362193267Sjkim ACPI_CLEAR_STATUS); 363126372Snjl 364233250Sjkim AcpiHwExecuteSleepMethod (METHOD_PATHNAME__SST, ACPI_SST_WORKING); 36599679Siwasaki return_ACPI_STATUS (Status); 36682367Smsmith} 367167802Sjkim 368231844Sjkim#endif /* !ACPI_REDUCED_HARDWARE */ 369