1 2 /****************************************************************************** 3 * 4 * Name: hwsleep.c - ACPI Hardware Sleep/Wake Interface 5 * 6 *****************************************************************************/ 7 8 /* 9 * Copyright (C) 2000 - 2011, Intel Corp. 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions, and the following disclaimer, 17 * without modification. 18 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 19 * substantially similar to the "NO WARRANTY" disclaimer below 20 * ("Disclaimer") and any redistribution must be conditioned upon 21 * including a substantially similar Disclaimer requirement for further 22 * binary redistribution. 23 * 3. Neither the names of the above-listed copyright holders nor the names 24 * of any contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * Alternatively, this software may be distributed under the terms of the 28 * GNU General Public License ("GPL") version 2 as published by the Free 29 * Software Foundation. 30 * 31 * NO WARRANTY 32 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 33 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 34 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 35 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 36 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 40 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 41 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 42 * POSSIBILITY OF SUCH DAMAGES. 43 */ 44 45 #include "acpi.h" 46 #include "accommon.h" 47 48 #define _COMPONENT ACPI_HARDWARE 49 ACPI_MODULE_NAME ("hwsleep") 50 51 52 /******************************************************************************* 53 * 54 * FUNCTION: AcpiSetFirmwareWakingVector 55 * 56 * PARAMETERS: PhysicalAddress - 32-bit physical address of ACPI real mode 57 * entry point. 58 * 59 * RETURN: Status 60 * 61 * DESCRIPTION: Sets the 32-bit FirmwareWakingVector field of the FACS 62 * 63 ******************************************************************************/ 64 65 ACPI_STATUS 66 AcpiSetFirmwareWakingVector ( 67 UINT32 PhysicalAddress) 68 { 69 ACPI_FUNCTION_TRACE (AcpiSetFirmwareWakingVector); 70 71 72 /* Set the 32-bit vector */ 73 74 AcpiGbl_FACS->FirmwareWakingVector = PhysicalAddress; 75 76 /* Clear the 64-bit vector if it exists */ 77 78 if ((AcpiGbl_FACS->Length > 32) && (AcpiGbl_FACS->Version >= 1)) 79 { 80 AcpiGbl_FACS->XFirmwareWakingVector = 0; 81 } 82 83 return_ACPI_STATUS (AE_OK); 84 } 85 86 ACPI_EXPORT_SYMBOL (AcpiSetFirmwareWakingVector) 87 88 89 #if ACPI_MACHINE_WIDTH == 64 90 /******************************************************************************* 91 * 92 * FUNCTION: AcpiSetFirmwareWakingVector64 93 * 94 * PARAMETERS: PhysicalAddress - 64-bit physical address of ACPI protected 95 * mode entry point. 96 * 97 * RETURN: Status 98 * 99 * DESCRIPTION: Sets the 64-bit X_FirmwareWakingVector field of the FACS, if 100 * it exists in the table. This function is intended for use with 101 * 64-bit host operating systems. 102 * 103 ******************************************************************************/ 104 105 ACPI_STATUS 106 AcpiSetFirmwareWakingVector64 ( 107 UINT64 PhysicalAddress) 108 { 109 ACPI_FUNCTION_TRACE (AcpiSetFirmwareWakingVector64); 110 111 112 /* Determine if the 64-bit vector actually exists */ 113 114 if ((AcpiGbl_FACS->Length <= 32) || (AcpiGbl_FACS->Version < 1)) 115 { 116 return_ACPI_STATUS (AE_NOT_EXIST); 117 } 118 119 /* Clear 32-bit vector, set the 64-bit X_ vector */ 120 121 AcpiGbl_FACS->FirmwareWakingVector = 0; 122 AcpiGbl_FACS->XFirmwareWakingVector = PhysicalAddress; 123 return_ACPI_STATUS (AE_OK); 124 } 125 126 ACPI_EXPORT_SYMBOL (AcpiSetFirmwareWakingVector64) 127 #endif 128 129 /******************************************************************************* 130 * 131 * FUNCTION: AcpiEnterSleepStatePrep 132 * 133 * PARAMETERS: SleepState - Which sleep state to enter 134 * 135 * RETURN: Status 136 * 137 * DESCRIPTION: Prepare to enter a system sleep state (see ACPI 2.0 spec p 231) 138 * This function must execute with interrupts enabled. 139 * We break sleeping into 2 stages so that OSPM can handle 140 * various OS-specific tasks between the two steps. 141 * 142 ******************************************************************************/ 143 144 ACPI_STATUS 145 AcpiEnterSleepStatePrep ( 146 UINT8 SleepState) 147 { 148 ACPI_STATUS Status; 149 ACPI_OBJECT_LIST ArgList; 150 ACPI_OBJECT Arg; 151 152 153 ACPI_FUNCTION_TRACE (AcpiEnterSleepStatePrep); 154 155 156 /* _PSW methods could be run here to enable wake-on keyboard, LAN, etc. */ 157 158 Status = AcpiGetSleepTypeData (SleepState, 159 &AcpiGbl_SleepTypeA, &AcpiGbl_SleepTypeB); 160 if (ACPI_FAILURE (Status)) 161 { 162 return_ACPI_STATUS (Status); 163 } 164 165 /* Execute the _PTS method (Prepare To Sleep) */ 166 167 ArgList.Count = 1; 168 ArgList.Pointer = &Arg; 169 Arg.Type = ACPI_TYPE_INTEGER; 170 Arg.Integer.Value = SleepState; 171 172 Status = AcpiEvaluateObject (NULL, METHOD_NAME__PTS, &ArgList, NULL); 173 if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND) 174 { 175 return_ACPI_STATUS (Status); 176 } 177 178 /* Setup the argument to the _SST method (System STatus) */ 179 180 switch (SleepState) 181 { 182 case ACPI_STATE_S0: 183 Arg.Integer.Value = ACPI_SST_WORKING; 184 break; 185 186 case ACPI_STATE_S1: 187 case ACPI_STATE_S2: 188 case ACPI_STATE_S3: 189 Arg.Integer.Value = ACPI_SST_SLEEPING; 190 break; 191 192 case ACPI_STATE_S4: 193 Arg.Integer.Value = ACPI_SST_SLEEP_CONTEXT; 194 break; 195 196 default: 197 Arg.Integer.Value = ACPI_SST_INDICATOR_OFF; /* Default is off */ 198 break; 199 } 200 201 /* 202 * Set the system indicators to show the desired sleep state. 203 * _SST is an optional method (return no error if not found) 204 */ 205 Status = AcpiEvaluateObject (NULL, METHOD_NAME__SST, &ArgList, NULL); 206 if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND) 207 { 208 ACPI_EXCEPTION ((AE_INFO, Status, "While executing method _SST")); 209 } 210 211 return_ACPI_STATUS (AE_OK); 212 } 213 214 ACPI_EXPORT_SYMBOL (AcpiEnterSleepStatePrep) 215 216 217 /******************************************************************************* 218 * 219 * FUNCTION: AcpiEnterSleepState 220 * 221 * PARAMETERS: SleepState - Which sleep state to enter 222 * 223 * RETURN: Status 224 * 225 * DESCRIPTION: Enter a system sleep state 226 * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED 227 * 228 ******************************************************************************/ 229 230 ACPI_STATUS 231 AcpiEnterSleepState ( 232 UINT8 SleepState) 233 { 234 UINT32 Pm1aControl; 235 UINT32 Pm1bControl; 236 ACPI_BIT_REGISTER_INFO *SleepTypeRegInfo; 237 ACPI_BIT_REGISTER_INFO *SleepEnableRegInfo; 238 UINT32 InValue; 239 ACPI_OBJECT_LIST ArgList; 240 ACPI_OBJECT Arg; 241 ACPI_STATUS Status; 242 243 244 ACPI_FUNCTION_TRACE (AcpiEnterSleepState); 245 246 247 if ((AcpiGbl_SleepTypeA > ACPI_SLEEP_TYPE_MAX) || 248 (AcpiGbl_SleepTypeB > ACPI_SLEEP_TYPE_MAX)) 249 { 250 ACPI_ERROR ((AE_INFO, "Sleep values out of range: A=0x%X B=0x%X", 251 AcpiGbl_SleepTypeA, AcpiGbl_SleepTypeB)); 252 return_ACPI_STATUS (AE_AML_OPERAND_VALUE); 253 } 254 255 SleepTypeRegInfo = AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_TYPE); 256 SleepEnableRegInfo = AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_ENABLE); 257 258 /* Clear wake status */ 259 260 Status = AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS); 261 if (ACPI_FAILURE (Status)) 262 { 263 return_ACPI_STATUS (Status); 264 } 265 266 /* Clear all fixed and general purpose status bits */ 267 268 Status = AcpiHwClearAcpiStatus (); 269 if (ACPI_FAILURE (Status)) 270 { 271 return_ACPI_STATUS (Status); 272 } 273 274 if (SleepState != ACPI_STATE_S5) 275 { 276 /* 277 * Disable BM arbitration. This feature is contained within an 278 * optional register (PM2 Control), so ignore a BAD_ADDRESS 279 * exception. 280 */ 281 Status = AcpiWriteBitRegister (ACPI_BITREG_ARB_DISABLE, 1); 282 if (ACPI_FAILURE (Status) && (Status != AE_BAD_ADDRESS)) 283 { 284 return_ACPI_STATUS (Status); 285 } 286 } 287 288 /* 289 * 1) Disable/Clear all GPEs 290 * 2) Enable all wakeup GPEs 291 */ 292 Status = AcpiHwDisableAllGpes (); 293 if (ACPI_FAILURE (Status)) 294 { 295 return_ACPI_STATUS (Status); 296 } 297 AcpiGbl_SystemAwakeAndRunning = FALSE; 298 299 Status = AcpiHwEnableAllWakeupGpes (); 300 if (ACPI_FAILURE (Status)) 301 { 302 return_ACPI_STATUS (Status); 303 } 304 305 /* Execute the _GTS method (Going To Sleep) */ 306 307 ArgList.Count = 1; 308 ArgList.Pointer = &Arg; 309 Arg.Type = ACPI_TYPE_INTEGER; 310 Arg.Integer.Value = SleepState; 311 312 Status = AcpiEvaluateObject (NULL, METHOD_NAME__GTS, &ArgList, NULL); 313 if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND) 314 { 315 return_ACPI_STATUS (Status); 316 } 317 318 /* Get current value of PM1A control */ 319 320 Status = AcpiHwRegisterRead (ACPI_REGISTER_PM1_CONTROL, 321 &Pm1aControl); 322 if (ACPI_FAILURE (Status)) 323 { 324 return_ACPI_STATUS (Status); 325 } 326 ACPI_DEBUG_PRINT ((ACPI_DB_INIT, 327 "Entering sleep state [S%u]\n", SleepState)); 328 329 /* Clear the SLP_EN and SLP_TYP fields */ 330 331 Pm1aControl &= ~(SleepTypeRegInfo->AccessBitMask | 332 SleepEnableRegInfo->AccessBitMask); 333 Pm1bControl = Pm1aControl; 334 335 /* Insert the SLP_TYP bits */ 336 337 Pm1aControl |= (AcpiGbl_SleepTypeA << SleepTypeRegInfo->BitPosition); 338 Pm1bControl |= (AcpiGbl_SleepTypeB << SleepTypeRegInfo->BitPosition); 339 340 /* 341 * We split the writes of SLP_TYP and SLP_EN to workaround 342 * poorly implemented hardware. 343 */ 344 345 /* Write #1: write the SLP_TYP data to the PM1 Control registers */ 346 347 Status = AcpiHwWritePm1Control (Pm1aControl, Pm1bControl); 348 if (ACPI_FAILURE (Status)) 349 { 350 return_ACPI_STATUS (Status); 351 } 352 353 /* Insert the sleep enable (SLP_EN) bit */ 354 355 Pm1aControl |= SleepEnableRegInfo->AccessBitMask; 356 Pm1bControl |= SleepEnableRegInfo->AccessBitMask; 357 358 /* Flush caches, as per ACPI specification */ 359 360 ACPI_FLUSH_CPU_CACHE (); 361 362 /* Write #2: Write both SLP_TYP + SLP_EN */ 363 364 Status = AcpiHwWritePm1Control (Pm1aControl, Pm1bControl); 365 if (ACPI_FAILURE (Status)) 366 { 367 return_ACPI_STATUS (Status); 368 } 369 370 if (SleepState > ACPI_STATE_S3) 371 { 372 /* 373 * We wanted to sleep > S3, but it didn't happen (by virtue of the 374 * fact that we are still executing!) 375 * 376 * Wait ten seconds, then try again. This is to get S4/S5 to work on 377 * all machines. 378 * 379 * We wait so long to allow chipsets that poll this reg very slowly 380 * to still read the right value. Ideally, this block would go 381 * away entirely. 382 */ 383 AcpiOsStall (10000000); 384 385 Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_CONTROL, 386 SleepEnableRegInfo->AccessBitMask); 387 if (ACPI_FAILURE (Status)) 388 { 389 return_ACPI_STATUS (Status); 390 } 391 } 392 393 /* Wait until we enter sleep state */ 394 395 do 396 { 397 Status = AcpiReadBitRegister (ACPI_BITREG_WAKE_STATUS, &InValue); 398 if (ACPI_FAILURE (Status)) 399 { 400 return_ACPI_STATUS (Status); 401 } 402 403 /* Spin until we wake */ 404 405 } while (!InValue); 406 407 return_ACPI_STATUS (AE_OK); 408 } 409 410 ACPI_EXPORT_SYMBOL (AcpiEnterSleepState) 411 412 413 /******************************************************************************* 414 * 415 * FUNCTION: AcpiEnterSleepStateS4bios 416 * 417 * PARAMETERS: None 418 * 419 * RETURN: Status 420 * 421 * DESCRIPTION: Perform a S4 bios request. 422 * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED 423 * 424 ******************************************************************************/ 425 426 ACPI_STATUS 427 AcpiEnterSleepStateS4bios ( 428 void) 429 { 430 UINT32 InValue; 431 ACPI_STATUS Status; 432 433 434 ACPI_FUNCTION_TRACE (AcpiEnterSleepStateS4bios); 435 436 437 /* Clear the wake status bit (PM1) */ 438 439 Status = AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS); 440 if (ACPI_FAILURE (Status)) 441 { 442 return_ACPI_STATUS (Status); 443 } 444 445 Status = AcpiHwClearAcpiStatus (); 446 if (ACPI_FAILURE (Status)) 447 { 448 return_ACPI_STATUS (Status); 449 } 450 451 /* 452 * 1) Disable/Clear all GPEs 453 * 2) Enable all wakeup GPEs 454 */ 455 Status = AcpiHwDisableAllGpes (); 456 if (ACPI_FAILURE (Status)) 457 { 458 return_ACPI_STATUS (Status); 459 } 460 AcpiGbl_SystemAwakeAndRunning = FALSE; 461 462 Status = AcpiHwEnableAllWakeupGpes (); 463 if (ACPI_FAILURE (Status)) 464 { 465 return_ACPI_STATUS (Status); 466 } 467 468 ACPI_FLUSH_CPU_CACHE (); 469 470 Status = AcpiHwWritePort (AcpiGbl_FADT.SmiCommand, 471 (UINT32) AcpiGbl_FADT.S4BiosRequest, 8); 472 473 do { 474 AcpiOsStall(1000); 475 Status = AcpiReadBitRegister (ACPI_BITREG_WAKE_STATUS, &InValue); 476 if (ACPI_FAILURE (Status)) 477 { 478 return_ACPI_STATUS (Status); 479 } 480 } while (!InValue); 481 482 return_ACPI_STATUS (AE_OK); 483 } 484 485 ACPI_EXPORT_SYMBOL (AcpiEnterSleepStateS4bios) 486 487 488 /******************************************************************************* 489 * 490 * FUNCTION: AcpiLeaveSleepState 491 * 492 * PARAMETERS: SleepState - Which sleep state we just exited 493 * 494 * RETURN: Status 495 * 496 * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep 497 * Called with interrupts ENABLED. 498 * 499 ******************************************************************************/ 500 501 ACPI_STATUS 502 AcpiLeaveSleepState ( 503 UINT8 SleepState) 504 { 505 ACPI_OBJECT_LIST ArgList; 506 ACPI_OBJECT Arg; 507 ACPI_STATUS Status; 508 ACPI_BIT_REGISTER_INFO *SleepTypeRegInfo; 509 ACPI_BIT_REGISTER_INFO *SleepEnableRegInfo; 510 UINT32 Pm1aControl; 511 UINT32 Pm1bControl; 512 513 514 ACPI_FUNCTION_TRACE (AcpiLeaveSleepState); 515 516 517 /* 518 * Set SLP_TYPE and SLP_EN to state S0. 519 * This is unclear from the ACPI Spec, but it is required 520 * by some machines. 521 */ 522 Status = AcpiGetSleepTypeData (ACPI_STATE_S0, 523 &AcpiGbl_SleepTypeA, &AcpiGbl_SleepTypeB); 524 if (ACPI_SUCCESS (Status)) 525 { 526 SleepTypeRegInfo = 527 AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_TYPE); 528 SleepEnableRegInfo = 529 AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_ENABLE); 530 531 /* Get current value of PM1A control */ 532 533 Status = AcpiHwRegisterRead (ACPI_REGISTER_PM1_CONTROL, 534 &Pm1aControl); 535 if (ACPI_SUCCESS (Status)) 536 { 537 /* Clear the SLP_EN and SLP_TYP fields */ 538 539 Pm1aControl &= ~(SleepTypeRegInfo->AccessBitMask | 540 SleepEnableRegInfo->AccessBitMask); 541 Pm1bControl = Pm1aControl; 542 543 /* Insert the SLP_TYP bits */ 544 545 Pm1aControl |= (AcpiGbl_SleepTypeA << 546 SleepTypeRegInfo->BitPosition); 547 Pm1bControl |= (AcpiGbl_SleepTypeB << 548 SleepTypeRegInfo->BitPosition); 549 550 /* Write the control registers and ignore any errors */ 551 552 (void) AcpiHwWritePm1Control (Pm1aControl, Pm1bControl); 553 } 554 } 555 556 /* Ensure EnterSleepStatePrep -> EnterSleepState ordering */ 557 558 AcpiGbl_SleepTypeA = ACPI_SLEEP_TYPE_INVALID; 559 560 /* Setup parameter object */ 561 562 ArgList.Count = 1; 563 ArgList.Pointer = &Arg; 564 Arg.Type = ACPI_TYPE_INTEGER; 565 566 /* Ignore any errors from these methods */ 567 568 Arg.Integer.Value = ACPI_SST_WAKING; 569 Status = AcpiEvaluateObject (NULL, METHOD_NAME__SST, &ArgList, NULL); 570 if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND) 571 { 572 ACPI_EXCEPTION ((AE_INFO, Status, "During Method _SST")); 573 } 574 575 Arg.Integer.Value = SleepState; 576 Status = AcpiEvaluateObject (NULL, METHOD_NAME__BFS, &ArgList, NULL); 577 if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND) 578 { 579 ACPI_EXCEPTION ((AE_INFO, Status, "During Method _BFS")); 580 } 581 582 Status = AcpiEvaluateObject (NULL, METHOD_NAME__WAK, &ArgList, NULL); 583 if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND) 584 { 585 ACPI_EXCEPTION ((AE_INFO, Status, "During Method _WAK")); 586 } 587 /* TBD: _WAK "sometimes" returns stuff - do we want to look at it? */ 588 589 /* 590 * Restore the GPEs: 591 * 1) Disable/Clear all GPEs 592 * 2) Enable all runtime GPEs 593 */ 594 Status = AcpiHwDisableAllGpes (); 595 if (ACPI_FAILURE (Status)) 596 { 597 return_ACPI_STATUS (Status); 598 } 599 AcpiGbl_SystemAwakeAndRunning = TRUE; 600 601 Status = AcpiHwEnableAllRuntimeGpes (); 602 if (ACPI_FAILURE (Status)) 603 { 604 return_ACPI_STATUS (Status); 605 } 606 607 /* Enable power button */ 608 609 (void) AcpiWriteBitRegister( 610 AcpiGbl_FixedEventInfo[ACPI_EVENT_POWER_BUTTON].EnableRegisterId, 611 ACPI_ENABLE_EVENT); 612 613 (void) AcpiWriteBitRegister( 614 AcpiGbl_FixedEventInfo[ACPI_EVENT_POWER_BUTTON].StatusRegisterId, 615 ACPI_CLEAR_STATUS); 616 617 /* 618 * Enable BM arbitration. This feature is contained within an 619 * optional register (PM2 Control), so ignore a BAD_ADDRESS 620 * exception. 621 */ 622 Status = AcpiWriteBitRegister (ACPI_BITREG_ARB_DISABLE, 0); 623 if (ACPI_FAILURE (Status) && (Status != AE_BAD_ADDRESS)) 624 { 625 return_ACPI_STATUS (Status); 626 } 627 628 Arg.Integer.Value = ACPI_SST_WORKING; 629 Status = AcpiEvaluateObject (NULL, METHOD_NAME__SST, &ArgList, NULL); 630 if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND) 631 { 632 ACPI_EXCEPTION ((AE_INFO, Status, "During Method _SST")); 633 } 634 635 return_ACPI_STATUS (Status); 636 } 637 638 ACPI_EXPORT_SYMBOL (AcpiLeaveSleepState) 639 640