1231798Sjkim/****************************************************************************** 2231798Sjkim * 3231798Sjkim * Name: hwxfsleep.c - ACPI Hardware Sleep/Wake External Interfaces 4231798Sjkim * 5231798Sjkim *****************************************************************************/ 6231798Sjkim 7231798Sjkim/* 8245582Sjkim * Copyright (C) 2000 - 2013, Intel Corp. 9231798Sjkim * All rights reserved. 10231798Sjkim * 11231798Sjkim * Redistribution and use in source and binary forms, with or without 12231798Sjkim * modification, are permitted provided that the following conditions 13231798Sjkim * are met: 14231798Sjkim * 1. Redistributions of source code must retain the above copyright 15231798Sjkim * notice, this list of conditions, and the following disclaimer, 16231798Sjkim * without modification. 17231798Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18231798Sjkim * substantially similar to the "NO WARRANTY" disclaimer below 19231798Sjkim * ("Disclaimer") and any redistribution must be conditioned upon 20231798Sjkim * including a substantially similar Disclaimer requirement for further 21231798Sjkim * binary redistribution. 22231798Sjkim * 3. Neither the names of the above-listed copyright holders nor the names 23231798Sjkim * of any contributors may be used to endorse or promote products derived 24231798Sjkim * from this software without specific prior written permission. 25231798Sjkim * 26231798Sjkim * Alternatively, this software may be distributed under the terms of the 27231798Sjkim * GNU General Public License ("GPL") version 2 as published by the Free 28231798Sjkim * Software Foundation. 29231798Sjkim * 30231798Sjkim * NO WARRANTY 31231798Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32231798Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33231798Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 34231798Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35231798Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36231798Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37231798Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38231798Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39231798Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40231798Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41231798Sjkim * POSSIBILITY OF SUCH DAMAGES. 42231798Sjkim */ 43231798Sjkim 44231844Sjkim#include <contrib/dev/acpica/include/acpi.h> 45231844Sjkim#include <contrib/dev/acpica/include/accommon.h> 46231798Sjkim 47231798Sjkim#define _COMPONENT ACPI_HARDWARE 48231798Sjkim ACPI_MODULE_NAME ("hwxfsleep") 49231798Sjkim 50231798Sjkim/* Local prototypes */ 51231798Sjkim 52231798Sjkimstatic ACPI_STATUS 53231798SjkimAcpiHwSleepDispatch ( 54231798Sjkim UINT8 SleepState, 55231798Sjkim UINT32 FunctionId); 56231798Sjkim 57231798Sjkim/* 58231798Sjkim * Dispatch table used to efficiently branch to the various sleep 59231798Sjkim * functions. 60231798Sjkim */ 61231798Sjkim#define ACPI_SLEEP_FUNCTION_ID 0 62231798Sjkim#define ACPI_WAKE_PREP_FUNCTION_ID 1 63231798Sjkim#define ACPI_WAKE_FUNCTION_ID 2 64231798Sjkim 65231798Sjkim/* Legacy functions are optional, based upon ACPI_REDUCED_HARDWARE */ 66231798Sjkim 67231798Sjkimstatic ACPI_SLEEP_FUNCTIONS AcpiSleepDispatch[] = 68231798Sjkim{ 69231798Sjkim {ACPI_HW_OPTIONAL_FUNCTION (AcpiHwLegacySleep), AcpiHwExtendedSleep}, 70231798Sjkim {ACPI_HW_OPTIONAL_FUNCTION (AcpiHwLegacyWakePrep), AcpiHwExtendedWakePrep}, 71231798Sjkim {ACPI_HW_OPTIONAL_FUNCTION (AcpiHwLegacyWake), AcpiHwExtendedWake} 72231798Sjkim}; 73231798Sjkim 74231798Sjkim 75231798Sjkim/* 76231798Sjkim * These functions are removed for the ACPI_REDUCED_HARDWARE case: 77231798Sjkim * AcpiSetFirmwareWakingVector 78231798Sjkim * AcpiSetFirmwareWakingVector64 79231798Sjkim * AcpiEnterSleepStateS4bios 80231798Sjkim */ 81231798Sjkim 82231798Sjkim#if (!ACPI_REDUCED_HARDWARE) 83231798Sjkim/******************************************************************************* 84231798Sjkim * 85231798Sjkim * FUNCTION: AcpiSetFirmwareWakingVector 86231798Sjkim * 87231798Sjkim * PARAMETERS: PhysicalAddress - 32-bit physical address of ACPI real mode 88231798Sjkim * entry point. 89231798Sjkim * 90231798Sjkim * RETURN: Status 91231798Sjkim * 92231798Sjkim * DESCRIPTION: Sets the 32-bit FirmwareWakingVector field of the FACS 93231798Sjkim * 94231798Sjkim ******************************************************************************/ 95231798Sjkim 96231798SjkimACPI_STATUS 97231798SjkimAcpiSetFirmwareWakingVector ( 98231798Sjkim UINT32 PhysicalAddress) 99231798Sjkim{ 100231798Sjkim ACPI_FUNCTION_TRACE (AcpiSetFirmwareWakingVector); 101231798Sjkim 102231798Sjkim 103238381Sjkim /* 104238381Sjkim * According to the ACPI specification 2.0c and later, the 64-bit 105238381Sjkim * waking vector should be cleared and the 32-bit waking vector should 106238381Sjkim * be used, unless we want the wake-up code to be called by the BIOS in 107238381Sjkim * Protected Mode. Some systems (for example HP dv5-1004nr) are known 108238381Sjkim * to fail to resume if the 64-bit vector is used. 109238381Sjkim */ 110238381Sjkim 111231798Sjkim /* Set the 32-bit vector */ 112231798Sjkim 113231798Sjkim AcpiGbl_FACS->FirmwareWakingVector = PhysicalAddress; 114231798Sjkim 115231798Sjkim /* Clear the 64-bit vector if it exists */ 116231798Sjkim 117231798Sjkim if ((AcpiGbl_FACS->Length > 32) && (AcpiGbl_FACS->Version >= 1)) 118231798Sjkim { 119231798Sjkim AcpiGbl_FACS->XFirmwareWakingVector = 0; 120231798Sjkim } 121231798Sjkim 122231798Sjkim return_ACPI_STATUS (AE_OK); 123231798Sjkim} 124231798Sjkim 125231798SjkimACPI_EXPORT_SYMBOL (AcpiSetFirmwareWakingVector) 126231798Sjkim 127231798Sjkim 128231798Sjkim#if ACPI_MACHINE_WIDTH == 64 129231798Sjkim/******************************************************************************* 130231798Sjkim * 131231798Sjkim * FUNCTION: AcpiSetFirmwareWakingVector64 132231798Sjkim * 133231798Sjkim * PARAMETERS: PhysicalAddress - 64-bit physical address of ACPI protected 134231798Sjkim * mode entry point. 135231798Sjkim * 136231798Sjkim * RETURN: Status 137231798Sjkim * 138231798Sjkim * DESCRIPTION: Sets the 64-bit X_FirmwareWakingVector field of the FACS, if 139231798Sjkim * it exists in the table. This function is intended for use with 140231798Sjkim * 64-bit host operating systems. 141231798Sjkim * 142231798Sjkim ******************************************************************************/ 143231798Sjkim 144231798SjkimACPI_STATUS 145231798SjkimAcpiSetFirmwareWakingVector64 ( 146231798Sjkim UINT64 PhysicalAddress) 147231798Sjkim{ 148231798Sjkim ACPI_FUNCTION_TRACE (AcpiSetFirmwareWakingVector64); 149231798Sjkim 150231798Sjkim 151231798Sjkim /* Determine if the 64-bit vector actually exists */ 152231798Sjkim 153231798Sjkim if ((AcpiGbl_FACS->Length <= 32) || (AcpiGbl_FACS->Version < 1)) 154231798Sjkim { 155231798Sjkim return_ACPI_STATUS (AE_NOT_EXIST); 156231798Sjkim } 157231798Sjkim 158231798Sjkim /* Clear 32-bit vector, set the 64-bit X_ vector */ 159231798Sjkim 160231798Sjkim AcpiGbl_FACS->FirmwareWakingVector = 0; 161231798Sjkim AcpiGbl_FACS->XFirmwareWakingVector = PhysicalAddress; 162231798Sjkim return_ACPI_STATUS (AE_OK); 163231798Sjkim} 164231798Sjkim 165231798SjkimACPI_EXPORT_SYMBOL (AcpiSetFirmwareWakingVector64) 166231798Sjkim#endif 167231798Sjkim 168231798Sjkim 169231798Sjkim/******************************************************************************* 170231798Sjkim * 171231798Sjkim * FUNCTION: AcpiEnterSleepStateS4bios 172231798Sjkim * 173231798Sjkim * PARAMETERS: None 174231798Sjkim * 175231798Sjkim * RETURN: Status 176231798Sjkim * 177231798Sjkim * DESCRIPTION: Perform a S4 bios request. 178231798Sjkim * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED 179231798Sjkim * 180231798Sjkim ******************************************************************************/ 181231798Sjkim 182231798SjkimACPI_STATUS 183231798SjkimAcpiEnterSleepStateS4bios ( 184231798Sjkim void) 185231798Sjkim{ 186231798Sjkim UINT32 InValue; 187231798Sjkim ACPI_STATUS Status; 188231798Sjkim 189231798Sjkim 190231798Sjkim ACPI_FUNCTION_TRACE (AcpiEnterSleepStateS4bios); 191231798Sjkim 192231798Sjkim 193231798Sjkim /* Clear the wake status bit (PM1) */ 194231798Sjkim 195231798Sjkim Status = AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS); 196231798Sjkim if (ACPI_FAILURE (Status)) 197231798Sjkim { 198231798Sjkim return_ACPI_STATUS (Status); 199231798Sjkim } 200231798Sjkim 201231798Sjkim Status = AcpiHwClearAcpiStatus (); 202231798Sjkim if (ACPI_FAILURE (Status)) 203231798Sjkim { 204231798Sjkim return_ACPI_STATUS (Status); 205231798Sjkim } 206231798Sjkim 207231798Sjkim /* 208231798Sjkim * 1) Disable/Clear all GPEs 209231798Sjkim * 2) Enable all wakeup GPEs 210231798Sjkim */ 211231798Sjkim Status = AcpiHwDisableAllGpes (); 212231798Sjkim if (ACPI_FAILURE (Status)) 213231798Sjkim { 214231798Sjkim return_ACPI_STATUS (Status); 215231798Sjkim } 216231798Sjkim AcpiGbl_SystemAwakeAndRunning = FALSE; 217231798Sjkim 218231798Sjkim Status = AcpiHwEnableAllWakeupGpes (); 219231798Sjkim if (ACPI_FAILURE (Status)) 220231798Sjkim { 221231798Sjkim return_ACPI_STATUS (Status); 222231798Sjkim } 223231798Sjkim 224231798Sjkim ACPI_FLUSH_CPU_CACHE (); 225231798Sjkim 226231798Sjkim Status = AcpiHwWritePort (AcpiGbl_FADT.SmiCommand, 227231798Sjkim (UINT32) AcpiGbl_FADT.S4BiosRequest, 8); 228231798Sjkim 229231798Sjkim do { 230245582Sjkim AcpiOsStall (ACPI_USEC_PER_MSEC); 231231798Sjkim Status = AcpiReadBitRegister (ACPI_BITREG_WAKE_STATUS, &InValue); 232231798Sjkim if (ACPI_FAILURE (Status)) 233231798Sjkim { 234231798Sjkim return_ACPI_STATUS (Status); 235231798Sjkim } 236231798Sjkim } while (!InValue); 237231798Sjkim 238231798Sjkim return_ACPI_STATUS (AE_OK); 239231798Sjkim} 240231798Sjkim 241231798SjkimACPI_EXPORT_SYMBOL (AcpiEnterSleepStateS4bios) 242231798Sjkim 243231798Sjkim#endif /* !ACPI_REDUCED_HARDWARE */ 244231798Sjkim 245231798Sjkim 246231798Sjkim/******************************************************************************* 247231798Sjkim * 248231798Sjkim * FUNCTION: AcpiHwSleepDispatch 249231798Sjkim * 250231798Sjkim * PARAMETERS: SleepState - Which sleep state to enter/exit 251231798Sjkim * FunctionId - Sleep, WakePrep, or Wake 252231798Sjkim * 253231798Sjkim * RETURN: Status from the invoked sleep handling function. 254231798Sjkim * 255231798Sjkim * DESCRIPTION: Dispatch a sleep/wake request to the appropriate handling 256231798Sjkim * function. 257231798Sjkim * 258231798Sjkim ******************************************************************************/ 259231798Sjkim 260231798Sjkimstatic ACPI_STATUS 261231798SjkimAcpiHwSleepDispatch ( 262231798Sjkim UINT8 SleepState, 263231798Sjkim UINT32 FunctionId) 264231798Sjkim{ 265231798Sjkim ACPI_STATUS Status; 266231798Sjkim ACPI_SLEEP_FUNCTIONS *SleepFunctions = &AcpiSleepDispatch[FunctionId]; 267231798Sjkim 268231798Sjkim 269231798Sjkim#if (!ACPI_REDUCED_HARDWARE) 270231798Sjkim /* 271231798Sjkim * If the Hardware Reduced flag is set (from the FADT), we must 272250838Sjkim * use the extended sleep registers (FADT). Note: As per the ACPI 273250838Sjkim * specification, these extended registers are to be used for HW-reduced 274250838Sjkim * platforms only. They are not general-purpose replacements for the 275250838Sjkim * legacy PM register sleep support. 276231798Sjkim */ 277250838Sjkim if (AcpiGbl_ReducedHardware) 278231798Sjkim { 279239340Sjkim Status = SleepFunctions->ExtendedFunction (SleepState); 280231798Sjkim } 281231798Sjkim else 282231798Sjkim { 283231798Sjkim /* Legacy sleep */ 284231798Sjkim 285239340Sjkim Status = SleepFunctions->LegacyFunction (SleepState); 286231798Sjkim } 287231798Sjkim 288231798Sjkim return (Status); 289231798Sjkim 290231798Sjkim#else 291231798Sjkim /* 292231798Sjkim * For the case where reduced-hardware-only code is being generated, 293231798Sjkim * we know that only the extended sleep registers are available 294231798Sjkim */ 295239340Sjkim Status = SleepFunctions->ExtendedFunction (SleepState); 296231798Sjkim return (Status); 297231798Sjkim 298231798Sjkim#endif /* !ACPI_REDUCED_HARDWARE */ 299231798Sjkim} 300231798Sjkim 301231798Sjkim 302231798Sjkim/******************************************************************************* 303231798Sjkim * 304231798Sjkim * FUNCTION: AcpiEnterSleepStatePrep 305231798Sjkim * 306231798Sjkim * PARAMETERS: SleepState - Which sleep state to enter 307231798Sjkim * 308231798Sjkim * RETURN: Status 309231798Sjkim * 310231798Sjkim * DESCRIPTION: Prepare to enter a system sleep state. 311231798Sjkim * This function must execute with interrupts enabled. 312231798Sjkim * We break sleeping into 2 stages so that OSPM can handle 313231798Sjkim * various OS-specific tasks between the two steps. 314231798Sjkim * 315231798Sjkim ******************************************************************************/ 316231798Sjkim 317231798SjkimACPI_STATUS 318231798SjkimAcpiEnterSleepStatePrep ( 319231798Sjkim UINT8 SleepState) 320231798Sjkim{ 321231798Sjkim ACPI_STATUS Status; 322231798Sjkim ACPI_OBJECT_LIST ArgList; 323231798Sjkim ACPI_OBJECT Arg; 324231798Sjkim UINT32 SstValue; 325231798Sjkim 326231798Sjkim 327231798Sjkim ACPI_FUNCTION_TRACE (AcpiEnterSleepStatePrep); 328231798Sjkim 329231798Sjkim 330231798Sjkim Status = AcpiGetSleepTypeData (SleepState, 331231798Sjkim &AcpiGbl_SleepTypeA, &AcpiGbl_SleepTypeB); 332231798Sjkim if (ACPI_FAILURE (Status)) 333231798Sjkim { 334231798Sjkim return_ACPI_STATUS (Status); 335231798Sjkim } 336231798Sjkim 337231798Sjkim /* Execute the _PTS method (Prepare To Sleep) */ 338231798Sjkim 339231798Sjkim ArgList.Count = 1; 340231798Sjkim ArgList.Pointer = &Arg; 341231798Sjkim Arg.Type = ACPI_TYPE_INTEGER; 342231798Sjkim Arg.Integer.Value = SleepState; 343231798Sjkim 344233250Sjkim Status = AcpiEvaluateObject (NULL, METHOD_PATHNAME__PTS, &ArgList, NULL); 345231798Sjkim if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND) 346231798Sjkim { 347231798Sjkim return_ACPI_STATUS (Status); 348231798Sjkim } 349231798Sjkim 350231798Sjkim /* Setup the argument to the _SST method (System STatus) */ 351231798Sjkim 352231798Sjkim switch (SleepState) 353231798Sjkim { 354231798Sjkim case ACPI_STATE_S0: 355250838Sjkim 356231798Sjkim SstValue = ACPI_SST_WORKING; 357231798Sjkim break; 358231798Sjkim 359231798Sjkim case ACPI_STATE_S1: 360231798Sjkim case ACPI_STATE_S2: 361231798Sjkim case ACPI_STATE_S3: 362250838Sjkim 363231798Sjkim SstValue = ACPI_SST_SLEEPING; 364231798Sjkim break; 365231798Sjkim 366231798Sjkim case ACPI_STATE_S4: 367250838Sjkim 368231798Sjkim SstValue = ACPI_SST_SLEEP_CONTEXT; 369231798Sjkim break; 370231798Sjkim 371231798Sjkim default: 372250838Sjkim 373231798Sjkim SstValue = ACPI_SST_INDICATOR_OFF; /* Default is off */ 374231798Sjkim break; 375231798Sjkim } 376231798Sjkim 377231798Sjkim /* 378231798Sjkim * Set the system indicators to show the desired sleep state. 379231798Sjkim * _SST is an optional method (return no error if not found) 380231798Sjkim */ 381233250Sjkim AcpiHwExecuteSleepMethod (METHOD_PATHNAME__SST, SstValue); 382231798Sjkim return_ACPI_STATUS (AE_OK); 383231798Sjkim} 384231798Sjkim 385231798SjkimACPI_EXPORT_SYMBOL (AcpiEnterSleepStatePrep) 386231798Sjkim 387231798Sjkim 388231798Sjkim/******************************************************************************* 389231798Sjkim * 390231798Sjkim * FUNCTION: AcpiEnterSleepState 391231798Sjkim * 392231798Sjkim * PARAMETERS: SleepState - Which sleep state to enter 393231798Sjkim * 394231798Sjkim * RETURN: Status 395231798Sjkim * 396231798Sjkim * DESCRIPTION: Enter a system sleep state 397231798Sjkim * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED 398231798Sjkim * 399231798Sjkim ******************************************************************************/ 400231798Sjkim 401231798SjkimACPI_STATUS 402231798SjkimAcpiEnterSleepState ( 403239340Sjkim UINT8 SleepState) 404231798Sjkim{ 405231798Sjkim ACPI_STATUS Status; 406231798Sjkim 407231798Sjkim 408231798Sjkim ACPI_FUNCTION_TRACE (AcpiEnterSleepState); 409231798Sjkim 410231798Sjkim 411231798Sjkim if ((AcpiGbl_SleepTypeA > ACPI_SLEEP_TYPE_MAX) || 412231798Sjkim (AcpiGbl_SleepTypeB > ACPI_SLEEP_TYPE_MAX)) 413231798Sjkim { 414231798Sjkim ACPI_ERROR ((AE_INFO, "Sleep values out of range: A=0x%X B=0x%X", 415231798Sjkim AcpiGbl_SleepTypeA, AcpiGbl_SleepTypeB)); 416231798Sjkim return_ACPI_STATUS (AE_AML_OPERAND_VALUE); 417231798Sjkim } 418231798Sjkim 419239340Sjkim Status = AcpiHwSleepDispatch (SleepState, ACPI_SLEEP_FUNCTION_ID); 420231798Sjkim return_ACPI_STATUS (Status); 421231798Sjkim} 422231798Sjkim 423231798SjkimACPI_EXPORT_SYMBOL (AcpiEnterSleepState) 424231798Sjkim 425231798Sjkim 426231798Sjkim/******************************************************************************* 427231798Sjkim * 428231798Sjkim * FUNCTION: AcpiLeaveSleepStatePrep 429231798Sjkim * 430231798Sjkim * PARAMETERS: SleepState - Which sleep state we are exiting 431231798Sjkim * 432231798Sjkim * RETURN: Status 433231798Sjkim * 434231798Sjkim * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a 435231798Sjkim * sleep. Called with interrupts DISABLED. 436231798Sjkim * We break wake/resume into 2 stages so that OSPM can handle 437231798Sjkim * various OS-specific tasks between the two steps. 438231798Sjkim * 439231798Sjkim ******************************************************************************/ 440231798Sjkim 441231798SjkimACPI_STATUS 442231798SjkimAcpiLeaveSleepStatePrep ( 443239340Sjkim UINT8 SleepState) 444231798Sjkim{ 445231798Sjkim ACPI_STATUS Status; 446231798Sjkim 447231798Sjkim 448231798Sjkim ACPI_FUNCTION_TRACE (AcpiLeaveSleepStatePrep); 449231798Sjkim 450231798Sjkim 451239340Sjkim Status = AcpiHwSleepDispatch (SleepState, ACPI_WAKE_PREP_FUNCTION_ID); 452231798Sjkim return_ACPI_STATUS (Status); 453231798Sjkim} 454231798Sjkim 455231798SjkimACPI_EXPORT_SYMBOL (AcpiLeaveSleepStatePrep) 456231798Sjkim 457231798Sjkim 458231798Sjkim/******************************************************************************* 459231798Sjkim * 460231798Sjkim * FUNCTION: AcpiLeaveSleepState 461231798Sjkim * 462231798Sjkim * PARAMETERS: SleepState - Which sleep state we are exiting 463231798Sjkim * 464231798Sjkim * RETURN: Status 465231798Sjkim * 466231798Sjkim * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep 467231798Sjkim * Called with interrupts ENABLED. 468231798Sjkim * 469231798Sjkim ******************************************************************************/ 470231798Sjkim 471231798SjkimACPI_STATUS 472231798SjkimAcpiLeaveSleepState ( 473231798Sjkim UINT8 SleepState) 474231798Sjkim{ 475231798Sjkim ACPI_STATUS Status; 476231798Sjkim 477231798Sjkim 478231798Sjkim ACPI_FUNCTION_TRACE (AcpiLeaveSleepState); 479231798Sjkim 480231798Sjkim 481239340Sjkim Status = AcpiHwSleepDispatch (SleepState, ACPI_WAKE_FUNCTION_ID); 482231798Sjkim return_ACPI_STATUS (Status); 483231798Sjkim} 484231798Sjkim 485231798SjkimACPI_EXPORT_SYMBOL (AcpiLeaveSleepState) 486