hwsleep.c revision 217365
171867Smsmith 271867Smsmith/****************************************************************************** 371867Smsmith * 471867Smsmith * Name: hwsleep.c - ACPI Hardware Sleep/Wake Interface 571867Smsmith * 671867Smsmith *****************************************************************************/ 771867Smsmith 8217365Sjkim/* 9217365Sjkim * Copyright (C) 2000 - 2011, 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 52151937Sjkim/******************************************************************************* 5371867Smsmith * 5471867Smsmith * FUNCTION: AcpiSetFirmwareWakingVector 5571867Smsmith * 56193267Sjkim * PARAMETERS: PhysicalAddress - 32-bit physical address of ACPI real mode 5771867Smsmith * entry point. 5871867Smsmith * 5991116Smsmith * RETURN: Status 6071867Smsmith * 61193267Sjkim * DESCRIPTION: Sets the 32-bit FirmwareWakingVector field of the FACS 6271867Smsmith * 6371867Smsmith ******************************************************************************/ 6471867Smsmith 6571867SmsmithACPI_STATUS 6671867SmsmithAcpiSetFirmwareWakingVector ( 67193267Sjkim UINT32 PhysicalAddress) 6871867Smsmith{ 69193267Sjkim ACPI_FUNCTION_TRACE (AcpiSetFirmwareWakingVector); 7071867Smsmith 7171867Smsmith 72193267Sjkim /* Set the 32-bit vector */ 7371867Smsmith 74193267Sjkim AcpiGbl_FACS->FirmwareWakingVector = PhysicalAddress; 75167802Sjkim 76193267Sjkim /* Clear the 64-bit vector if it exists */ 77167802Sjkim 78193267Sjkim if ((AcpiGbl_FACS->Length > 32) && (AcpiGbl_FACS->Version >= 1)) 7971867Smsmith { 80193267Sjkim AcpiGbl_FACS->XFirmwareWakingVector = 0; 8171867Smsmith } 8271867Smsmith 8371867Smsmith return_ACPI_STATUS (AE_OK); 8471867Smsmith} 8571867Smsmith 86167802SjkimACPI_EXPORT_SYMBOL (AcpiSetFirmwareWakingVector) 8771867Smsmith 88167802Sjkim 89193267Sjkim#if ACPI_MACHINE_WIDTH == 64 90151937Sjkim/******************************************************************************* 9171867Smsmith * 92193267Sjkim * FUNCTION: AcpiSetFirmwareWakingVector64 9371867Smsmith * 94193267Sjkim * PARAMETERS: PhysicalAddress - 64-bit physical address of ACPI protected 95193267Sjkim * mode entry point. 9671867Smsmith * 97193267Sjkim * RETURN: Status 9871867Smsmith * 99193267Sjkim * DESCRIPTION: Sets the 64-bit X_FirmwareWakingVector field of the FACS, if 100193267Sjkim * it exists in the table. This function is intended for use with 101193267Sjkim * 64-bit host operating systems. 10271867Smsmith * 10371867Smsmith ******************************************************************************/ 10471867Smsmith 10571867SmsmithACPI_STATUS 106193267SjkimAcpiSetFirmwareWakingVector64 ( 107193267Sjkim UINT64 PhysicalAddress) 10871867Smsmith{ 109193267Sjkim ACPI_FUNCTION_TRACE (AcpiSetFirmwareWakingVector64); 11071867Smsmith 11171867Smsmith 112193267Sjkim /* Determine if the 64-bit vector actually exists */ 11371867Smsmith 114193267Sjkim if ((AcpiGbl_FACS->Length <= 32) || (AcpiGbl_FACS->Version < 1)) 11571867Smsmith { 116193267Sjkim return_ACPI_STATUS (AE_NOT_EXIST); 11771867Smsmith } 11871867Smsmith 119193267Sjkim /* Clear 32-bit vector, set the 64-bit X_ vector */ 120167802Sjkim 121193267Sjkim AcpiGbl_FACS->FirmwareWakingVector = 0; 122193267Sjkim AcpiGbl_FACS->XFirmwareWakingVector = PhysicalAddress; 12371867Smsmith return_ACPI_STATUS (AE_OK); 12471867Smsmith} 12571867Smsmith 126193267SjkimACPI_EXPORT_SYMBOL (AcpiSetFirmwareWakingVector64) 127193267Sjkim#endif 12887031Smsmith 129151937Sjkim/******************************************************************************* 13071867Smsmith * 13187031Smsmith * FUNCTION: AcpiEnterSleepStatePrep 13271867Smsmith * 13371867Smsmith * PARAMETERS: SleepState - Which sleep state to enter 13471867Smsmith * 13571867Smsmith * RETURN: Status 13671867Smsmith * 13787031Smsmith * DESCRIPTION: Prepare to enter a system sleep state (see ACPI 2.0 spec p 231) 13887031Smsmith * This function must execute with interrupts enabled. 13987031Smsmith * We break sleeping into 2 stages so that OSPM can handle 14087031Smsmith * various OS-specific tasks between the two steps. 14171867Smsmith * 14271867Smsmith ******************************************************************************/ 14371867Smsmith 14471867SmsmithACPI_STATUS 14587031SmsmithAcpiEnterSleepStatePrep ( 146193267Sjkim UINT8 SleepState) 14771867Smsmith{ 148193267Sjkim ACPI_STATUS Status; 149193267Sjkim ACPI_OBJECT_LIST ArgList; 150193267Sjkim ACPI_OBJECT Arg; 15171867Smsmith 15277424Smsmith 153167802Sjkim ACPI_FUNCTION_TRACE (AcpiEnterSleepStatePrep); 15491116Smsmith 15591116Smsmith 156193267Sjkim /* _PSW methods could be run here to enable wake-on keyboard, LAN, etc. */ 157193267Sjkim 15899679Siwasaki Status = AcpiGetSleepTypeData (SleepState, 15991116Smsmith &AcpiGbl_SleepTypeA, &AcpiGbl_SleepTypeB); 16091116Smsmith if (ACPI_FAILURE (Status)) 16171867Smsmith { 16287031Smsmith return_ACPI_STATUS (Status); 16371867Smsmith } 16471867Smsmith 165193267Sjkim /* Execute the _PTS method (Prepare To Sleep) */ 16677424Smsmith 16771867Smsmith ArgList.Count = 1; 16871867Smsmith ArgList.Pointer = &Arg; 16971867Smsmith Arg.Type = ACPI_TYPE_INTEGER; 17071867Smsmith Arg.Integer.Value = SleepState; 17171867Smsmith 172126372Snjl Status = AcpiEvaluateObject (NULL, METHOD_NAME__PTS, &ArgList, NULL); 17391116Smsmith if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND) 17491116Smsmith { 17591116Smsmith return_ACPI_STATUS (Status); 17691116Smsmith } 17791116Smsmith 178193267Sjkim /* Setup the argument to the _SST method (System STatus) */ 17991116Smsmith 180126372Snjl switch (SleepState) 181126372Snjl { 182126372Snjl case ACPI_STATE_S0: 183126372Snjl Arg.Integer.Value = ACPI_SST_WORKING; 184126372Snjl break; 185126372Snjl 186126372Snjl case ACPI_STATE_S1: 187126372Snjl case ACPI_STATE_S2: 188126372Snjl case ACPI_STATE_S3: 189126372Snjl Arg.Integer.Value = ACPI_SST_SLEEPING; 190126372Snjl break; 191126372Snjl 192126372Snjl case ACPI_STATE_S4: 193126372Snjl Arg.Integer.Value = ACPI_SST_SLEEP_CONTEXT; 194126372Snjl break; 195126372Snjl 196126372Snjl default: 197151937Sjkim Arg.Integer.Value = ACPI_SST_INDICATOR_OFF; /* Default is off */ 198126372Snjl break; 199126372Snjl } 200126372Snjl 201193267Sjkim /* 202193267Sjkim * Set the system indicators to show the desired sleep state. 203193267Sjkim * _SST is an optional method (return no error if not found) 204193267Sjkim */ 205126372Snjl Status = AcpiEvaluateObject (NULL, METHOD_NAME__SST, &ArgList, NULL); 206123315Snjl if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND) 207123315Snjl { 208167802Sjkim ACPI_EXCEPTION ((AE_INFO, Status, "While executing method _SST")); 209123315Snjl } 210123315Snjl 21187031Smsmith return_ACPI_STATUS (AE_OK); 21287031Smsmith} 21387031Smsmith 214167802SjkimACPI_EXPORT_SYMBOL (AcpiEnterSleepStatePrep) 21587031Smsmith 216167802Sjkim 217151937Sjkim/******************************************************************************* 21887031Smsmith * 21987031Smsmith * FUNCTION: AcpiEnterSleepState 22087031Smsmith * 22187031Smsmith * PARAMETERS: SleepState - Which sleep state to enter 22287031Smsmith * 22387031Smsmith * RETURN: Status 22487031Smsmith * 225193267Sjkim * DESCRIPTION: Enter a system sleep state 22687031Smsmith * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED 22787031Smsmith * 22887031Smsmith ******************************************************************************/ 22987031Smsmith 23087031SmsmithACPI_STATUS 23187031SmsmithAcpiEnterSleepState ( 23291116Smsmith UINT8 SleepState) 23387031Smsmith{ 234193267Sjkim UINT32 Pm1aControl; 235193267Sjkim UINT32 Pm1bControl; 23691116Smsmith ACPI_BIT_REGISTER_INFO *SleepTypeRegInfo; 23791116Smsmith ACPI_BIT_REGISTER_INFO *SleepEnableRegInfo; 23899679Siwasaki UINT32 InValue; 239193267Sjkim ACPI_OBJECT_LIST ArgList; 240193267Sjkim ACPI_OBJECT Arg; 241193335Sjkim UINT32 Retry; 24299679Siwasaki ACPI_STATUS Status; 24387031Smsmith 24487031Smsmith 245167802Sjkim ACPI_FUNCTION_TRACE (AcpiEnterSleepState); 24687031Smsmith 24791116Smsmith 24891116Smsmith if ((AcpiGbl_SleepTypeA > ACPI_SLEEP_TYPE_MAX) || 24991116Smsmith (AcpiGbl_SleepTypeB > ACPI_SLEEP_TYPE_MAX)) 25087031Smsmith { 251204773Sjkim ACPI_ERROR ((AE_INFO, "Sleep values out of range: A=0x%X B=0x%X", 25291116Smsmith AcpiGbl_SleepTypeA, AcpiGbl_SleepTypeB)); 25391116Smsmith return_ACPI_STATUS (AE_AML_OPERAND_VALUE); 25487031Smsmith } 25587031Smsmith 256193267Sjkim SleepTypeRegInfo = AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_TYPE); 25791116Smsmith SleepEnableRegInfo = AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_ENABLE); 25871867Smsmith 259128245Snjl /* Clear wake status */ 260128245Snjl 261193267Sjkim Status = AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS); 262128245Snjl if (ACPI_FAILURE (Status)) 26399679Siwasaki { 264128245Snjl return_ACPI_STATUS (Status); 265128245Snjl } 26678986Smsmith 267129684Snjl /* Clear all fixed and general purpose status bits */ 268129684Snjl 269167802Sjkim Status = AcpiHwClearAcpiStatus (); 270128245Snjl if (ACPI_FAILURE (Status)) 271128245Snjl { 272128245Snjl return_ACPI_STATUS (Status); 273128245Snjl } 27487031Smsmith 275128245Snjl if (SleepState != ACPI_STATE_S5) 276128245Snjl { 277197104Sjkim /* 278197104Sjkim * Disable BM arbitration. This feature is contained within an 279197104Sjkim * optional register (PM2 Control), so ignore a BAD_ADDRESS 280197104Sjkim * exception. 281197104Sjkim */ 282193267Sjkim Status = AcpiWriteBitRegister (ACPI_BITREG_ARB_DISABLE, 1); 283197104Sjkim if (ACPI_FAILURE (Status) && (Status != AE_BAD_ADDRESS)) 284123315Snjl { 285123315Snjl return_ACPI_STATUS (Status); 286123315Snjl } 28799679Siwasaki } 28899679Siwasaki 289128212Snjl /* 290129684Snjl * 1) Disable/Clear all GPEs 291128212Snjl * 2) Enable all wakeup GPEs 292128212Snjl */ 293151937Sjkim Status = AcpiHwDisableAllGpes (); 29499679Siwasaki if (ACPI_FAILURE (Status)) 29599679Siwasaki { 29699679Siwasaki return_ACPI_STATUS (Status); 29799679Siwasaki } 298129684Snjl AcpiGbl_SystemAwakeAndRunning = FALSE; 29999679Siwasaki 300151937Sjkim Status = AcpiHwEnableAllWakeupGpes (); 301129684Snjl if (ACPI_FAILURE (Status)) 302129684Snjl { 303129684Snjl return_ACPI_STATUS (Status); 304129684Snjl } 305129684Snjl 306193267Sjkim /* Execute the _GTS method (Going To Sleep) */ 307193267Sjkim 308193267Sjkim ArgList.Count = 1; 309193267Sjkim ArgList.Pointer = &Arg; 310193267Sjkim Arg.Type = ACPI_TYPE_INTEGER; 311193267Sjkim Arg.Integer.Value = SleepState; 312193267Sjkim 313193267Sjkim Status = AcpiEvaluateObject (NULL, METHOD_NAME__GTS, &ArgList, NULL); 314193267Sjkim if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND) 315193267Sjkim { 316193267Sjkim return_ACPI_STATUS (Status); 317193267Sjkim } 318193267Sjkim 31991116Smsmith /* Get current value of PM1A control */ 32078986Smsmith 321193267Sjkim Status = AcpiHwRegisterRead (ACPI_REGISTER_PM1_CONTROL, 322193267Sjkim &Pm1aControl); 32399679Siwasaki if (ACPI_FAILURE (Status)) 32499679Siwasaki { 32599679Siwasaki return_ACPI_STATUS (Status); 32699679Siwasaki } 327151937Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_INIT, 328209746Sjkim "Entering sleep state [S%u]\n", SleepState)); 32982367Smsmith 330193267Sjkim /* Clear the SLP_EN and SLP_TYP fields */ 33182367Smsmith 332193267Sjkim Pm1aControl &= ~(SleepTypeRegInfo->AccessBitMask | 333151937Sjkim SleepEnableRegInfo->AccessBitMask); 334193267Sjkim Pm1bControl = Pm1aControl; 33571867Smsmith 336193267Sjkim /* Insert the SLP_TYP bits */ 33782367Smsmith 338193267Sjkim Pm1aControl |= (AcpiGbl_SleepTypeA << SleepTypeRegInfo->BitPosition); 339193267Sjkim Pm1bControl |= (AcpiGbl_SleepTypeB << SleepTypeRegInfo->BitPosition); 34071867Smsmith 341126372Snjl /* 342126372Snjl * We split the writes of SLP_TYP and SLP_EN to workaround 343126372Snjl * poorly implemented hardware. 344126372Snjl */ 345126372Snjl 346193267Sjkim /* Write #1: write the SLP_TYP data to the PM1 Control registers */ 34771867Smsmith 348193267Sjkim Status = AcpiHwWritePm1Control (Pm1aControl, Pm1bControl); 34999679Siwasaki if (ACPI_FAILURE (Status)) 35099679Siwasaki { 35199679Siwasaki return_ACPI_STATUS (Status); 35299679Siwasaki } 35382367Smsmith 354193267Sjkim /* Insert the sleep enable (SLP_EN) bit */ 35599679Siwasaki 356193267Sjkim Pm1aControl |= SleepEnableRegInfo->AccessBitMask; 357193267Sjkim Pm1bControl |= SleepEnableRegInfo->AccessBitMask; 35882367Smsmith 359193267Sjkim /* Flush caches, as per ACPI specification */ 36071867Smsmith 36199679Siwasaki ACPI_FLUSH_CPU_CACHE (); 36280062Smsmith 363193267Sjkim /* Write #2: Write both SLP_TYP + SLP_EN */ 36499679Siwasaki 365193267Sjkim Status = AcpiHwWritePm1Control (Pm1aControl, Pm1bControl); 36699679Siwasaki if (ACPI_FAILURE (Status)) 36799679Siwasaki { 36899679Siwasaki return_ACPI_STATUS (Status); 36999679Siwasaki } 37099679Siwasaki 37182367Smsmith if (SleepState > ACPI_STATE_S3) 37282367Smsmith { 37399679Siwasaki /* 374151937Sjkim * We wanted to sleep > S3, but it didn't happen (by virtue of the 375151937Sjkim * fact that we are still executing!) 376123315Snjl * 377151937Sjkim * Wait ten seconds, then try again. This is to get S4/S5 to work on 378151937Sjkim * all machines. 379123315Snjl * 380193267Sjkim * We wait so long to allow chipsets that poll this reg very slowly 381193267Sjkim * to still read the right value. Ideally, this block would go 38299679Siwasaki * away entirely. 38399679Siwasaki */ 38499679Siwasaki AcpiOsStall (10000000); 38582367Smsmith 386193267Sjkim Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_CONTROL, 38799679Siwasaki SleepEnableRegInfo->AccessBitMask); 38899679Siwasaki if (ACPI_FAILURE (Status)) 38999679Siwasaki { 39099679Siwasaki return_ACPI_STATUS (Status); 39199679Siwasaki } 39280357Speter } 39380062Smsmith 39491116Smsmith /* Wait until we enter sleep state */ 39571867Smsmith 396193335Sjkim Retry = 1000; 397102550Siwasaki do 39883174Smsmith { 399193267Sjkim Status = AcpiReadBitRegister (ACPI_BITREG_WAKE_STATUS, &InValue); 40099679Siwasaki if (ACPI_FAILURE (Status)) 40199679Siwasaki { 40299679Siwasaki return_ACPI_STATUS (Status); 40399679Siwasaki } 40499679Siwasaki 405204920Sjkim if (AcpiGbl_EnableInterpreterSlack) 406193335Sjkim { 407204920Sjkim /* 408204920Sjkim * Some BIOSs don't set WAK_STS at all. Give up waiting after 409204920Sjkim * 1000 retries if it still isn't set. 410204920Sjkim */ 411204920Sjkim if (Retry-- == 0) 412204920Sjkim { 413204920Sjkim break; 414204920Sjkim } 415193335Sjkim } 416193335Sjkim 41791116Smsmith /* Spin until we wake */ 41882367Smsmith 41999679Siwasaki } while (!InValue); 42099679Siwasaki 42171867Smsmith return_ACPI_STATUS (AE_OK); 42271867Smsmith} 42382367Smsmith 424167802SjkimACPI_EXPORT_SYMBOL (AcpiEnterSleepState) 425114237Snjl 426167802Sjkim 427151937Sjkim/******************************************************************************* 42882367Smsmith * 429114237Snjl * FUNCTION: AcpiEnterSleepStateS4bios 430114237Snjl * 431114237Snjl * PARAMETERS: None 432114237Snjl * 433114237Snjl * RETURN: Status 434114237Snjl * 435114237Snjl * DESCRIPTION: Perform a S4 bios request. 436114237Snjl * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED 437114237Snjl * 438114237Snjl ******************************************************************************/ 439114237Snjl 440114237SnjlACPI_STATUS 441114237SnjlAcpiEnterSleepStateS4bios ( 442114237Snjl void) 443114237Snjl{ 444114237Snjl UINT32 InValue; 445114237Snjl ACPI_STATUS Status; 446114237Snjl 447114237Snjl 448167802Sjkim ACPI_FUNCTION_TRACE (AcpiEnterSleepStateS4bios); 449114237Snjl 450123315Snjl 451193267Sjkim /* Clear the wake status bit (PM1) */ 452193267Sjkim 453193267Sjkim Status = AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS); 454126372Snjl if (ACPI_FAILURE (Status)) 455126372Snjl { 456126372Snjl return_ACPI_STATUS (Status); 457126372Snjl } 458114237Snjl 459167802Sjkim Status = AcpiHwClearAcpiStatus (); 460126372Snjl if (ACPI_FAILURE (Status)) 461126372Snjl { 462126372Snjl return_ACPI_STATUS (Status); 463126372Snjl } 464114237Snjl 465128212Snjl /* 466129684Snjl * 1) Disable/Clear all GPEs 467128212Snjl * 2) Enable all wakeup GPEs 468128212Snjl */ 469151937Sjkim Status = AcpiHwDisableAllGpes (); 470126372Snjl if (ACPI_FAILURE (Status)) 471126372Snjl { 472126372Snjl return_ACPI_STATUS (Status); 473126372Snjl } 474129684Snjl AcpiGbl_SystemAwakeAndRunning = FALSE; 475114237Snjl 476151937Sjkim Status = AcpiHwEnableAllWakeupGpes (); 477129684Snjl if (ACPI_FAILURE (Status)) 478129684Snjl { 479129684Snjl return_ACPI_STATUS (Status); 480129684Snjl } 481129684Snjl 482126372Snjl ACPI_FLUSH_CPU_CACHE (); 483126372Snjl 484193267Sjkim Status = AcpiHwWritePort (AcpiGbl_FADT.SmiCommand, 485167802Sjkim (UINT32) AcpiGbl_FADT.S4BiosRequest, 8); 486114237Snjl 487114237Snjl do { 488114237Snjl AcpiOsStall(1000); 489193267Sjkim Status = AcpiReadBitRegister (ACPI_BITREG_WAKE_STATUS, &InValue); 490114237Snjl if (ACPI_FAILURE (Status)) 491114237Snjl { 492114237Snjl return_ACPI_STATUS (Status); 493114237Snjl } 494114237Snjl } while (!InValue); 495114237Snjl 496114237Snjl return_ACPI_STATUS (AE_OK); 497114237Snjl} 498114237Snjl 499167802SjkimACPI_EXPORT_SYMBOL (AcpiEnterSleepStateS4bios) 500114237Snjl 501167802Sjkim 502151937Sjkim/******************************************************************************* 503114237Snjl * 50482367Smsmith * FUNCTION: AcpiLeaveSleepState 50582367Smsmith * 50682367Smsmith * PARAMETERS: SleepState - Which sleep state we just exited 50782367Smsmith * 50882367Smsmith * RETURN: Status 50982367Smsmith * 51082367Smsmith * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep 511138287Smarks * Called with interrupts ENABLED. 51282367Smsmith * 51382367Smsmith ******************************************************************************/ 51482367Smsmith 51582367SmsmithACPI_STATUS 51682367SmsmithAcpiLeaveSleepState ( 517123315Snjl UINT8 SleepState) 51882367Smsmith{ 519123315Snjl ACPI_OBJECT_LIST ArgList; 520123315Snjl ACPI_OBJECT Arg; 521123315Snjl ACPI_STATUS Status; 522123315Snjl ACPI_BIT_REGISTER_INFO *SleepTypeRegInfo; 523123315Snjl ACPI_BIT_REGISTER_INFO *SleepEnableRegInfo; 524193267Sjkim UINT32 Pm1aControl; 525193267Sjkim UINT32 Pm1bControl; 52682367Smsmith 52783174Smsmith 528167802Sjkim ACPI_FUNCTION_TRACE (AcpiLeaveSleepState); 52982367Smsmith 53091116Smsmith 531126372Snjl /* 532126372Snjl * Set SLP_TYPE and SLP_EN to state S0. 533126372Snjl * This is unclear from the ACPI Spec, but it is required 534126372Snjl * by some machines. 535126372Snjl */ 536126372Snjl Status = AcpiGetSleepTypeData (ACPI_STATE_S0, 537126372Snjl &AcpiGbl_SleepTypeA, &AcpiGbl_SleepTypeB); 538123315Snjl if (ACPI_SUCCESS (Status)) 539123315Snjl { 540193267Sjkim SleepTypeRegInfo = 541193267Sjkim AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_TYPE); 542193267Sjkim SleepEnableRegInfo = 543193267Sjkim AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_ENABLE); 544123315Snjl 545126372Snjl /* Get current value of PM1A control */ 546123315Snjl 547193267Sjkim Status = AcpiHwRegisterRead (ACPI_REGISTER_PM1_CONTROL, 548193267Sjkim &Pm1aControl); 549126372Snjl if (ACPI_SUCCESS (Status)) 550126372Snjl { 551193267Sjkim /* Clear the SLP_EN and SLP_TYP fields */ 552126372Snjl 553193267Sjkim Pm1aControl &= ~(SleepTypeRegInfo->AccessBitMask | 554193267Sjkim SleepEnableRegInfo->AccessBitMask); 555193267Sjkim Pm1bControl = Pm1aControl; 556126372Snjl 557193267Sjkim /* Insert the SLP_TYP bits */ 558126372Snjl 559193267Sjkim Pm1aControl |= (AcpiGbl_SleepTypeA << 560193267Sjkim SleepTypeRegInfo->BitPosition); 561193267Sjkim Pm1bControl |= (AcpiGbl_SleepTypeB << 562193267Sjkim SleepTypeRegInfo->BitPosition); 563126372Snjl 564193267Sjkim /* Write the control registers and ignore any errors */ 565126372Snjl 566193267Sjkim (void) AcpiHwWritePm1Control (Pm1aControl, Pm1bControl); 567126372Snjl } 568123315Snjl } 569123315Snjl 57087031Smsmith /* Ensure EnterSleepStatePrep -> EnterSleepState ordering */ 57182367Smsmith 57291116Smsmith AcpiGbl_SleepTypeA = ACPI_SLEEP_TYPE_INVALID; 57391116Smsmith 57491116Smsmith /* Setup parameter object */ 57591116Smsmith 57682367Smsmith ArgList.Count = 1; 57782367Smsmith ArgList.Pointer = &Arg; 57882367Smsmith Arg.Type = ACPI_TYPE_INTEGER; 57982367Smsmith 58091116Smsmith /* Ignore any errors from these methods */ 58183174Smsmith 582126372Snjl Arg.Integer.Value = ACPI_SST_WAKING; 583126372Snjl Status = AcpiEvaluateObject (NULL, METHOD_NAME__SST, &ArgList, NULL); 584123315Snjl if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND) 585123315Snjl { 586167802Sjkim ACPI_EXCEPTION ((AE_INFO, Status, "During Method _SST")); 587123315Snjl } 588123315Snjl 589123315Snjl Arg.Integer.Value = SleepState; 590126372Snjl Status = AcpiEvaluateObject (NULL, METHOD_NAME__BFS, &ArgList, NULL); 59191116Smsmith if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND) 59291116Smsmith { 593167802Sjkim ACPI_EXCEPTION ((AE_INFO, Status, "During Method _BFS")); 59491116Smsmith } 59591116Smsmith 596126372Snjl Status = AcpiEvaluateObject (NULL, METHOD_NAME__WAK, &ArgList, NULL); 59791116Smsmith if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND) 59891116Smsmith { 599167802Sjkim ACPI_EXCEPTION ((AE_INFO, Status, "During Method _WAK")); 60091116Smsmith } 601128212Snjl /* TBD: _WAK "sometimes" returns stuff - do we want to look at it? */ 60291116Smsmith 603128212Snjl /* 604128212Snjl * Restore the GPEs: 605129684Snjl * 1) Disable/Clear all GPEs 606128212Snjl * 2) Enable all runtime GPEs 607128212Snjl */ 608151937Sjkim Status = AcpiHwDisableAllGpes (); 60999679Siwasaki if (ACPI_FAILURE (Status)) 61099679Siwasaki { 61199679Siwasaki return_ACPI_STATUS (Status); 61299679Siwasaki } 613129684Snjl AcpiGbl_SystemAwakeAndRunning = TRUE; 61482367Smsmith 615151937Sjkim Status = AcpiHwEnableAllRuntimeGpes (); 616129684Snjl if (ACPI_FAILURE (Status)) 617129684Snjl { 618129684Snjl return_ACPI_STATUS (Status); 619129684Snjl } 620129684Snjl 621126372Snjl /* Enable power button */ 622126372Snjl 623193267Sjkim (void) AcpiWriteBitRegister( 624193267Sjkim AcpiGbl_FixedEventInfo[ACPI_EVENT_POWER_BUTTON].EnableRegisterId, 625193267Sjkim ACPI_ENABLE_EVENT); 626151937Sjkim 627193267Sjkim (void) AcpiWriteBitRegister( 628193267Sjkim AcpiGbl_FixedEventInfo[ACPI_EVENT_POWER_BUTTON].StatusRegisterId, 629193267Sjkim ACPI_CLEAR_STATUS); 630126372Snjl 631197104Sjkim /* 632197104Sjkim * Enable BM arbitration. This feature is contained within an 633197104Sjkim * optional register (PM2 Control), so ignore a BAD_ADDRESS 634197104Sjkim * exception. 635197104Sjkim */ 636193267Sjkim Status = AcpiWriteBitRegister (ACPI_BITREG_ARB_DISABLE, 0); 637197104Sjkim if (ACPI_FAILURE (Status) && (Status != AE_BAD_ADDRESS)) 638126372Snjl { 639126372Snjl return_ACPI_STATUS (Status); 640126372Snjl } 641126372Snjl 642126372Snjl Arg.Integer.Value = ACPI_SST_WORKING; 643126372Snjl Status = AcpiEvaluateObject (NULL, METHOD_NAME__SST, &ArgList, NULL); 644126372Snjl if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND) 645126372Snjl { 646167802Sjkim ACPI_EXCEPTION ((AE_INFO, Status, "During Method _SST")); 647126372Snjl } 648126372Snjl 64999679Siwasaki return_ACPI_STATUS (Status); 65082367Smsmith} 651167802Sjkim 652167802SjkimACPI_EXPORT_SYMBOL (AcpiLeaveSleepState) 653167802Sjkim 654