hwsleep.c revision 231844
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 ( 6891116Smsmith 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 101128245Snjl if (SleepState != ACPI_STATE_S5) 102128245Snjl { 103197104Sjkim /* 104197104Sjkim * Disable BM arbitration. This feature is contained within an 105197104Sjkim * optional register (PM2 Control), so ignore a BAD_ADDRESS 106197104Sjkim * exception. 107197104Sjkim */ 108193267Sjkim Status = AcpiWriteBitRegister (ACPI_BITREG_ARB_DISABLE, 1); 109197104Sjkim if (ACPI_FAILURE (Status) && (Status != AE_BAD_ADDRESS)) 110123315Snjl { 111123315Snjl return_ACPI_STATUS (Status); 112123315Snjl } 11399679Siwasaki } 11499679Siwasaki 115128212Snjl /* 116129684Snjl * 1) Disable/Clear all GPEs 117128212Snjl * 2) Enable all wakeup GPEs 118128212Snjl */ 119151937Sjkim Status = AcpiHwDisableAllGpes (); 12099679Siwasaki if (ACPI_FAILURE (Status)) 12199679Siwasaki { 12299679Siwasaki return_ACPI_STATUS (Status); 12399679Siwasaki } 124129684Snjl AcpiGbl_SystemAwakeAndRunning = FALSE; 12599679Siwasaki 126151937Sjkim Status = AcpiHwEnableAllWakeupGpes (); 127129684Snjl if (ACPI_FAILURE (Status)) 128129684Snjl { 129129684Snjl return_ACPI_STATUS (Status); 130129684Snjl } 131129684Snjl 132193267Sjkim /* Execute the _GTS method (Going To Sleep) */ 133193267Sjkim 134231844Sjkim AcpiHwExecuteSleepMethod (METHOD_NAME__GTS, SleepState); 135193267Sjkim 13691116Smsmith /* Get current value of PM1A control */ 13778986Smsmith 138193267Sjkim Status = AcpiHwRegisterRead (ACPI_REGISTER_PM1_CONTROL, 139193267Sjkim &Pm1aControl); 14099679Siwasaki if (ACPI_FAILURE (Status)) 14199679Siwasaki { 14299679Siwasaki return_ACPI_STATUS (Status); 14399679Siwasaki } 144151937Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_INIT, 145209746Sjkim "Entering sleep state [S%u]\n", SleepState)); 14682367Smsmith 147193267Sjkim /* Clear the SLP_EN and SLP_TYP fields */ 14882367Smsmith 149193267Sjkim Pm1aControl &= ~(SleepTypeRegInfo->AccessBitMask | 150151937Sjkim SleepEnableRegInfo->AccessBitMask); 151193267Sjkim Pm1bControl = Pm1aControl; 15271867Smsmith 153193267Sjkim /* Insert the SLP_TYP bits */ 15482367Smsmith 155193267Sjkim Pm1aControl |= (AcpiGbl_SleepTypeA << SleepTypeRegInfo->BitPosition); 156193267Sjkim Pm1bControl |= (AcpiGbl_SleepTypeB << SleepTypeRegInfo->BitPosition); 15771867Smsmith 158126372Snjl /* 159126372Snjl * We split the writes of SLP_TYP and SLP_EN to workaround 160126372Snjl * poorly implemented hardware. 161126372Snjl */ 162126372Snjl 163193267Sjkim /* Write #1: write the SLP_TYP data to the PM1 Control registers */ 16471867Smsmith 165193267Sjkim Status = AcpiHwWritePm1Control (Pm1aControl, Pm1bControl); 16699679Siwasaki if (ACPI_FAILURE (Status)) 16799679Siwasaki { 16899679Siwasaki return_ACPI_STATUS (Status); 16999679Siwasaki } 17082367Smsmith 171193267Sjkim /* Insert the sleep enable (SLP_EN) bit */ 17299679Siwasaki 173193267Sjkim Pm1aControl |= SleepEnableRegInfo->AccessBitMask; 174193267Sjkim Pm1bControl |= SleepEnableRegInfo->AccessBitMask; 17582367Smsmith 176193267Sjkim /* Flush caches, as per ACPI specification */ 17771867Smsmith 17899679Siwasaki ACPI_FLUSH_CPU_CACHE (); 17980062Smsmith 180193267Sjkim /* Write #2: Write both SLP_TYP + SLP_EN */ 18199679Siwasaki 182193267Sjkim Status = AcpiHwWritePm1Control (Pm1aControl, Pm1bControl); 18399679Siwasaki if (ACPI_FAILURE (Status)) 18499679Siwasaki { 18599679Siwasaki return_ACPI_STATUS (Status); 18699679Siwasaki } 18799679Siwasaki 18882367Smsmith if (SleepState > ACPI_STATE_S3) 18982367Smsmith { 19099679Siwasaki /* 191151937Sjkim * We wanted to sleep > S3, but it didn't happen (by virtue of the 192151937Sjkim * fact that we are still executing!) 193123315Snjl * 194151937Sjkim * Wait ten seconds, then try again. This is to get S4/S5 to work on 195151937Sjkim * all machines. 196123315Snjl * 197193267Sjkim * We wait so long to allow chipsets that poll this reg very slowly 198193267Sjkim * to still read the right value. Ideally, this block would go 19999679Siwasaki * away entirely. 20099679Siwasaki */ 20199679Siwasaki AcpiOsStall (10000000); 20282367Smsmith 203193267Sjkim Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_CONTROL, 20499679Siwasaki SleepEnableRegInfo->AccessBitMask); 20599679Siwasaki if (ACPI_FAILURE (Status)) 20699679Siwasaki { 20799679Siwasaki return_ACPI_STATUS (Status); 20899679Siwasaki } 20980357Speter } 21080062Smsmith 211231844Sjkim /* Wait for transition back to Working State */ 21271867Smsmith 213193335Sjkim Retry = 1000; 214102550Siwasaki do 21583174Smsmith { 216193267Sjkim Status = AcpiReadBitRegister (ACPI_BITREG_WAKE_STATUS, &InValue); 21799679Siwasaki if (ACPI_FAILURE (Status)) 21899679Siwasaki { 21999679Siwasaki return_ACPI_STATUS (Status); 22099679Siwasaki } 22199679Siwasaki 222204920Sjkim if (AcpiGbl_EnableInterpreterSlack) 223193335Sjkim { 224204920Sjkim /* 225204920Sjkim * Some BIOSs don't set WAK_STS at all. Give up waiting after 226204920Sjkim * 1000 retries if it still isn't set. 227204920Sjkim */ 228204920Sjkim if (Retry-- == 0) 229204920Sjkim { 230204920Sjkim break; 231204920Sjkim } 232193335Sjkim } 233193335Sjkim 23499679Siwasaki } while (!InValue); 23599679Siwasaki 23671867Smsmith return_ACPI_STATUS (AE_OK); 23771867Smsmith} 23882367Smsmith 239114237Snjl 240151937Sjkim/******************************************************************************* 24182367Smsmith * 242231844Sjkim * FUNCTION: AcpiHwLegacyWakePrep 243114237Snjl * 24482367Smsmith * PARAMETERS: SleepState - Which sleep state we just exited 24582367Smsmith * 24682367Smsmith * RETURN: Status 24782367Smsmith * 248231844Sjkim * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a 249231844Sjkim * sleep. 250138287Smarks * Called with interrupts ENABLED. 25182367Smsmith * 25282367Smsmith ******************************************************************************/ 25382367Smsmith 25482367SmsmithACPI_STATUS 255231844SjkimAcpiHwLegacyWakePrep ( 256123315Snjl UINT8 SleepState) 25782367Smsmith{ 258123315Snjl ACPI_STATUS Status; 259123315Snjl ACPI_BIT_REGISTER_INFO *SleepTypeRegInfo; 260123315Snjl ACPI_BIT_REGISTER_INFO *SleepEnableRegInfo; 261193267Sjkim UINT32 Pm1aControl; 262193267Sjkim UINT32 Pm1bControl; 26382367Smsmith 26483174Smsmith 265231844Sjkim ACPI_FUNCTION_TRACE (HwLegacyWakePrep); 26682367Smsmith 267126372Snjl /* 268126372Snjl * Set SLP_TYPE and SLP_EN to state S0. 269126372Snjl * This is unclear from the ACPI Spec, but it is required 270126372Snjl * by some machines. 271126372Snjl */ 272126372Snjl Status = AcpiGetSleepTypeData (ACPI_STATE_S0, 273126372Snjl &AcpiGbl_SleepTypeA, &AcpiGbl_SleepTypeB); 274123315Snjl if (ACPI_SUCCESS (Status)) 275123315Snjl { 276193267Sjkim SleepTypeRegInfo = 277193267Sjkim AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_TYPE); 278193267Sjkim SleepEnableRegInfo = 279193267Sjkim AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_ENABLE); 280123315Snjl 281126372Snjl /* Get current value of PM1A control */ 282123315Snjl 283193267Sjkim Status = AcpiHwRegisterRead (ACPI_REGISTER_PM1_CONTROL, 284193267Sjkim &Pm1aControl); 285126372Snjl if (ACPI_SUCCESS (Status)) 286126372Snjl { 287193267Sjkim /* Clear the SLP_EN and SLP_TYP fields */ 288126372Snjl 289193267Sjkim Pm1aControl &= ~(SleepTypeRegInfo->AccessBitMask | 290193267Sjkim SleepEnableRegInfo->AccessBitMask); 291193267Sjkim Pm1bControl = Pm1aControl; 292126372Snjl 293193267Sjkim /* Insert the SLP_TYP bits */ 294126372Snjl 295193267Sjkim Pm1aControl |= (AcpiGbl_SleepTypeA << 296193267Sjkim SleepTypeRegInfo->BitPosition); 297193267Sjkim Pm1bControl |= (AcpiGbl_SleepTypeB << 298193267Sjkim SleepTypeRegInfo->BitPosition); 299126372Snjl 300193267Sjkim /* Write the control registers and ignore any errors */ 301126372Snjl 302193267Sjkim (void) AcpiHwWritePm1Control (Pm1aControl, Pm1bControl); 303126372Snjl } 304123315Snjl } 305123315Snjl 306231844Sjkim AcpiHwExecuteSleepMethod (METHOD_NAME__BFS, SleepState); 307231844Sjkim return_ACPI_STATUS (Status); 308231844Sjkim} 30982367Smsmith 31091116Smsmith 311231844Sjkim/******************************************************************************* 312231844Sjkim * 313231844Sjkim * FUNCTION: AcpiHwLegacyWake 314231844Sjkim * 315231844Sjkim * PARAMETERS: SleepState - Which sleep state we just exited 316231844Sjkim * 317231844Sjkim * RETURN: Status 318231844Sjkim * 319231844Sjkim * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep 320231844Sjkim * Called with interrupts ENABLED. 321231844Sjkim * 322231844Sjkim ******************************************************************************/ 32391116Smsmith 324231844SjkimACPI_STATUS 325231844SjkimAcpiHwLegacyWake ( 326231844Sjkim UINT8 SleepState) 327231844Sjkim{ 328231844Sjkim ACPI_STATUS Status; 32982367Smsmith 33083174Smsmith 331231844Sjkim ACPI_FUNCTION_TRACE (HwLegacyWake); 332123315Snjl 33391116Smsmith 334231844Sjkim /* Ensure EnterSleepStatePrep -> EnterSleepState ordering */ 33591116Smsmith 336231844Sjkim AcpiGbl_SleepTypeA = ACPI_SLEEP_TYPE_INVALID; 337231844Sjkim AcpiHwExecuteSleepMethod (METHOD_NAME__SST, ACPI_SST_WAKING); 338231844Sjkim 339128212Snjl /* 340231844Sjkim * GPEs must be enabled before _WAK is called as GPEs 341231844Sjkim * might get fired there 342231844Sjkim * 343128212Snjl * Restore the GPEs: 344129684Snjl * 1) Disable/Clear all GPEs 345128212Snjl * 2) Enable all runtime GPEs 346128212Snjl */ 347151937Sjkim Status = AcpiHwDisableAllGpes (); 34899679Siwasaki if (ACPI_FAILURE (Status)) 34999679Siwasaki { 35099679Siwasaki return_ACPI_STATUS (Status); 35199679Siwasaki } 35282367Smsmith 353151937Sjkim Status = AcpiHwEnableAllRuntimeGpes (); 354129684Snjl if (ACPI_FAILURE (Status)) 355129684Snjl { 356129684Snjl return_ACPI_STATUS (Status); 357129684Snjl } 358129684Snjl 359231844Sjkim /* 360231844Sjkim * Now we can execute _WAK, etc. Some machines require that the GPEs 361231844Sjkim * are enabled before the wake methods are executed. 362231844Sjkim */ 363231844Sjkim AcpiHwExecuteSleepMethod (METHOD_NAME__WAK, SleepState); 364231844Sjkim 365231844Sjkim /* 366231844Sjkim * Some BIOS code assumes that WAK_STS will be cleared on resume 367231844Sjkim * and use it to determine whether the system is rebooting or 368231844Sjkim * resuming. Clear WAK_STS for compatibility. 369231844Sjkim */ 370231844Sjkim (void) AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS); 371231844Sjkim AcpiGbl_SystemAwakeAndRunning = TRUE; 372231844Sjkim 373126372Snjl /* Enable power button */ 374126372Snjl 375193267Sjkim (void) AcpiWriteBitRegister( 376193267Sjkim AcpiGbl_FixedEventInfo[ACPI_EVENT_POWER_BUTTON].EnableRegisterId, 377193267Sjkim ACPI_ENABLE_EVENT); 378151937Sjkim 379193267Sjkim (void) AcpiWriteBitRegister( 380193267Sjkim AcpiGbl_FixedEventInfo[ACPI_EVENT_POWER_BUTTON].StatusRegisterId, 381193267Sjkim ACPI_CLEAR_STATUS); 382126372Snjl 383197104Sjkim /* 384197104Sjkim * Enable BM arbitration. This feature is contained within an 385197104Sjkim * optional register (PM2 Control), so ignore a BAD_ADDRESS 386197104Sjkim * exception. 387197104Sjkim */ 388193267Sjkim Status = AcpiWriteBitRegister (ACPI_BITREG_ARB_DISABLE, 0); 389197104Sjkim if (ACPI_FAILURE (Status) && (Status != AE_BAD_ADDRESS)) 390126372Snjl { 391126372Snjl return_ACPI_STATUS (Status); 392126372Snjl } 393126372Snjl 394231844Sjkim AcpiHwExecuteSleepMethod (METHOD_NAME__SST, ACPI_SST_WORKING); 39599679Siwasaki return_ACPI_STATUS (Status); 39682367Smsmith} 397167802Sjkim 398231844Sjkim#endif /* !ACPI_REDUCED_HARDWARE */ 399