171867Smsmith/****************************************************************************** 271867Smsmith * 3231844Sjkim * Name: hwsleep.c - ACPI Hardware Sleep/Wake Support functions for the 4231844Sjkim * original/legacy sleep/PM registers. 571867Smsmith * 671867Smsmith *****************************************************************************/ 771867Smsmith 8217365Sjkim/* 9306536Sjkim * Copyright (C) 2000 - 2016, 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; 7599679Siwasaki ACPI_STATUS Status; 7687031Smsmith 7787031Smsmith 78231844Sjkim ACPI_FUNCTION_TRACE (HwLegacySleep); 7987031Smsmith 8091116Smsmith 81231844Sjkim SleepTypeRegInfo = AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_TYPE); 8291116Smsmith SleepEnableRegInfo = AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_ENABLE); 8371867Smsmith 84128245Snjl /* Clear wake status */ 85128245Snjl 86306536Sjkim Status = AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS, 87306536Sjkim 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, 121306536Sjkim &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 | 132306536Sjkim 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 */ 183245582Sjkim AcpiOsStall (10 * ACPI_USEC_PER_SEC); 18482367Smsmith 185193267Sjkim Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_CONTROL, 186306536Sjkim 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 195102550Siwasaki do 19683174Smsmith { 197193267Sjkim Status = AcpiReadBitRegister (ACPI_BITREG_WAKE_STATUS, &InValue); 19899679Siwasaki if (ACPI_FAILURE (Status)) 19999679Siwasaki { 20099679Siwasaki return_ACPI_STATUS (Status); 20199679Siwasaki } 20299679Siwasaki 20399679Siwasaki } while (!InValue); 20499679Siwasaki 20571867Smsmith return_ACPI_STATUS (AE_OK); 20671867Smsmith} 20782367Smsmith 208114237Snjl 209151937Sjkim/******************************************************************************* 21082367Smsmith * 211231844Sjkim * FUNCTION: AcpiHwLegacyWakePrep 212114237Snjl * 21382367Smsmith * PARAMETERS: SleepState - Which sleep state we just exited 21482367Smsmith * 21582367Smsmith * RETURN: Status 21682367Smsmith * 217231844Sjkim * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a 218231844Sjkim * sleep. 219138287Smarks * Called with interrupts ENABLED. 22082367Smsmith * 22182367Smsmith ******************************************************************************/ 22282367Smsmith 22382367SmsmithACPI_STATUS 224231844SjkimAcpiHwLegacyWakePrep ( 225239340Sjkim UINT8 SleepState) 22682367Smsmith{ 227123315Snjl ACPI_STATUS Status; 228123315Snjl ACPI_BIT_REGISTER_INFO *SleepTypeRegInfo; 229123315Snjl ACPI_BIT_REGISTER_INFO *SleepEnableRegInfo; 230193267Sjkim UINT32 Pm1aControl; 231193267Sjkim UINT32 Pm1bControl; 23282367Smsmith 23383174Smsmith 234231844Sjkim ACPI_FUNCTION_TRACE (HwLegacyWakePrep); 23582367Smsmith 236126372Snjl /* 237126372Snjl * Set SLP_TYPE and SLP_EN to state S0. 238126372Snjl * This is unclear from the ACPI Spec, but it is required 239126372Snjl * by some machines. 240126372Snjl */ 241126372Snjl Status = AcpiGetSleepTypeData (ACPI_STATE_S0, 242306536Sjkim &AcpiGbl_SleepTypeA, &AcpiGbl_SleepTypeB); 243123315Snjl if (ACPI_SUCCESS (Status)) 244123315Snjl { 245193267Sjkim SleepTypeRegInfo = 246193267Sjkim AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_TYPE); 247193267Sjkim SleepEnableRegInfo = 248193267Sjkim AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_ENABLE); 249123315Snjl 250126372Snjl /* Get current value of PM1A control */ 251123315Snjl 252193267Sjkim Status = AcpiHwRegisterRead (ACPI_REGISTER_PM1_CONTROL, 253306536Sjkim &Pm1aControl); 254126372Snjl if (ACPI_SUCCESS (Status)) 255126372Snjl { 256193267Sjkim /* Clear the SLP_EN and SLP_TYP fields */ 257126372Snjl 258193267Sjkim Pm1aControl &= ~(SleepTypeRegInfo->AccessBitMask | 259193267Sjkim SleepEnableRegInfo->AccessBitMask); 260193267Sjkim Pm1bControl = Pm1aControl; 261126372Snjl 262193267Sjkim /* Insert the SLP_TYP bits */ 263126372Snjl 264193267Sjkim Pm1aControl |= (AcpiGbl_SleepTypeA << 265193267Sjkim SleepTypeRegInfo->BitPosition); 266193267Sjkim Pm1bControl |= (AcpiGbl_SleepTypeB << 267193267Sjkim SleepTypeRegInfo->BitPosition); 268126372Snjl 269193267Sjkim /* Write the control registers and ignore any errors */ 270126372Snjl 271193267Sjkim (void) AcpiHwWritePm1Control (Pm1aControl, Pm1bControl); 272126372Snjl } 273123315Snjl } 274123315Snjl 275231844Sjkim return_ACPI_STATUS (Status); 276231844Sjkim} 27782367Smsmith 27891116Smsmith 279231844Sjkim/******************************************************************************* 280231844Sjkim * 281231844Sjkim * FUNCTION: AcpiHwLegacyWake 282231844Sjkim * 283231844Sjkim * PARAMETERS: SleepState - Which sleep state we just exited 284231844Sjkim * 285231844Sjkim * RETURN: Status 286231844Sjkim * 287231844Sjkim * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep 288231844Sjkim * Called with interrupts ENABLED. 289231844Sjkim * 290231844Sjkim ******************************************************************************/ 29191116Smsmith 292231844SjkimACPI_STATUS 293231844SjkimAcpiHwLegacyWake ( 294239340Sjkim UINT8 SleepState) 295231844Sjkim{ 296231844Sjkim ACPI_STATUS Status; 29782367Smsmith 29883174Smsmith 299231844Sjkim ACPI_FUNCTION_TRACE (HwLegacyWake); 300123315Snjl 30191116Smsmith 302231844Sjkim /* Ensure EnterSleepStatePrep -> EnterSleepState ordering */ 30391116Smsmith 304231844Sjkim AcpiGbl_SleepTypeA = ACPI_SLEEP_TYPE_INVALID; 305233250Sjkim AcpiHwExecuteSleepMethod (METHOD_PATHNAME__SST, ACPI_SST_WAKING); 306231844Sjkim 307128212Snjl /* 308231844Sjkim * GPEs must be enabled before _WAK is called as GPEs 309231844Sjkim * might get fired there 310231844Sjkim * 311128212Snjl * Restore the GPEs: 312129684Snjl * 1) Disable/Clear all GPEs 313128212Snjl * 2) Enable all runtime GPEs 314128212Snjl */ 315151937Sjkim Status = AcpiHwDisableAllGpes (); 31699679Siwasaki if (ACPI_FAILURE (Status)) 31799679Siwasaki { 31899679Siwasaki return_ACPI_STATUS (Status); 31999679Siwasaki } 32082367Smsmith 321151937Sjkim Status = AcpiHwEnableAllRuntimeGpes (); 322129684Snjl if (ACPI_FAILURE (Status)) 323129684Snjl { 324129684Snjl return_ACPI_STATUS (Status); 325129684Snjl } 326129684Snjl 327231844Sjkim /* 328231844Sjkim * Now we can execute _WAK, etc. Some machines require that the GPEs 329231844Sjkim * are enabled before the wake methods are executed. 330231844Sjkim */ 331233250Sjkim AcpiHwExecuteSleepMethod (METHOD_PATHNAME__WAK, SleepState); 332231844Sjkim 333231844Sjkim /* 334231844Sjkim * Some BIOS code assumes that WAK_STS will be cleared on resume 335231844Sjkim * and use it to determine whether the system is rebooting or 336231844Sjkim * resuming. Clear WAK_STS for compatibility. 337231844Sjkim */ 338306536Sjkim (void) AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS, 339306536Sjkim ACPI_CLEAR_STATUS); 340231844Sjkim AcpiGbl_SystemAwakeAndRunning = TRUE; 341231844Sjkim 342126372Snjl /* Enable power button */ 343126372Snjl 344193267Sjkim (void) AcpiWriteBitRegister( 345193267Sjkim AcpiGbl_FixedEventInfo[ACPI_EVENT_POWER_BUTTON].EnableRegisterId, 346193267Sjkim ACPI_ENABLE_EVENT); 347151937Sjkim 348193267Sjkim (void) AcpiWriteBitRegister( 349193267Sjkim AcpiGbl_FixedEventInfo[ACPI_EVENT_POWER_BUTTON].StatusRegisterId, 350193267Sjkim ACPI_CLEAR_STATUS); 351126372Snjl 352233250Sjkim AcpiHwExecuteSleepMethod (METHOD_PATHNAME__SST, ACPI_SST_WORKING); 35399679Siwasaki return_ACPI_STATUS (Status); 35482367Smsmith} 355167802Sjkim 356231844Sjkim#endif /* !ACPI_REDUCED_HARDWARE */ 357