hwsleep.c revision 231844
1/****************************************************************************** 2 * 3 * Name: hwsleep.c - ACPI Hardware Sleep/Wake Support functions for the 4 * original/legacy sleep/PM registers. 5 * 6 *****************************************************************************/ 7 8/* 9 * Copyright (C) 2000 - 2012, 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 <contrib/dev/acpica/include/acpi.h> 46#include <contrib/dev/acpica/include/accommon.h> 47 48#define _COMPONENT ACPI_HARDWARE 49 ACPI_MODULE_NAME ("hwsleep") 50 51 52#if (!ACPI_REDUCED_HARDWARE) /* Entire module */ 53/******************************************************************************* 54 * 55 * FUNCTION: AcpiHwLegacySleep 56 * 57 * PARAMETERS: SleepState - Which sleep state to enter 58 * 59 * RETURN: Status 60 * 61 * DESCRIPTION: Enter a system sleep state via the legacy FADT PM registers 62 * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED 63 * 64 ******************************************************************************/ 65 66ACPI_STATUS 67AcpiHwLegacySleep ( 68 UINT8 SleepState) 69{ 70 ACPI_BIT_REGISTER_INFO *SleepTypeRegInfo; 71 ACPI_BIT_REGISTER_INFO *SleepEnableRegInfo; 72 UINT32 Pm1aControl; 73 UINT32 Pm1bControl; 74 UINT32 InValue; 75 UINT32 Retry; 76 ACPI_STATUS Status; 77 78 79 ACPI_FUNCTION_TRACE (HwLegacySleep); 80 81 82 SleepTypeRegInfo = AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_TYPE); 83 SleepEnableRegInfo = AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_ENABLE); 84 85 /* Clear wake status */ 86 87 Status = AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS); 88 if (ACPI_FAILURE (Status)) 89 { 90 return_ACPI_STATUS (Status); 91 } 92 93 /* Clear all fixed and general purpose status bits */ 94 95 Status = AcpiHwClearAcpiStatus (); 96 if (ACPI_FAILURE (Status)) 97 { 98 return_ACPI_STATUS (Status); 99 } 100 101 if (SleepState != ACPI_STATE_S5) 102 { 103 /* 104 * Disable BM arbitration. This feature is contained within an 105 * optional register (PM2 Control), so ignore a BAD_ADDRESS 106 * exception. 107 */ 108 Status = AcpiWriteBitRegister (ACPI_BITREG_ARB_DISABLE, 1); 109 if (ACPI_FAILURE (Status) && (Status != AE_BAD_ADDRESS)) 110 { 111 return_ACPI_STATUS (Status); 112 } 113 } 114 115 /* 116 * 1) Disable/Clear all GPEs 117 * 2) Enable all wakeup GPEs 118 */ 119 Status = AcpiHwDisableAllGpes (); 120 if (ACPI_FAILURE (Status)) 121 { 122 return_ACPI_STATUS (Status); 123 } 124 AcpiGbl_SystemAwakeAndRunning = FALSE; 125 126 Status = AcpiHwEnableAllWakeupGpes (); 127 if (ACPI_FAILURE (Status)) 128 { 129 return_ACPI_STATUS (Status); 130 } 131 132 /* Execute the _GTS method (Going To Sleep) */ 133 134 AcpiHwExecuteSleepMethod (METHOD_NAME__GTS, SleepState); 135 136 /* Get current value of PM1A control */ 137 138 Status = AcpiHwRegisterRead (ACPI_REGISTER_PM1_CONTROL, 139 &Pm1aControl); 140 if (ACPI_FAILURE (Status)) 141 { 142 return_ACPI_STATUS (Status); 143 } 144 ACPI_DEBUG_PRINT ((ACPI_DB_INIT, 145 "Entering sleep state [S%u]\n", SleepState)); 146 147 /* Clear the SLP_EN and SLP_TYP fields */ 148 149 Pm1aControl &= ~(SleepTypeRegInfo->AccessBitMask | 150 SleepEnableRegInfo->AccessBitMask); 151 Pm1bControl = Pm1aControl; 152 153 /* Insert the SLP_TYP bits */ 154 155 Pm1aControl |= (AcpiGbl_SleepTypeA << SleepTypeRegInfo->BitPosition); 156 Pm1bControl |= (AcpiGbl_SleepTypeB << SleepTypeRegInfo->BitPosition); 157 158 /* 159 * We split the writes of SLP_TYP and SLP_EN to workaround 160 * poorly implemented hardware. 161 */ 162 163 /* Write #1: write the SLP_TYP data to the PM1 Control registers */ 164 165 Status = AcpiHwWritePm1Control (Pm1aControl, Pm1bControl); 166 if (ACPI_FAILURE (Status)) 167 { 168 return_ACPI_STATUS (Status); 169 } 170 171 /* Insert the sleep enable (SLP_EN) bit */ 172 173 Pm1aControl |= SleepEnableRegInfo->AccessBitMask; 174 Pm1bControl |= SleepEnableRegInfo->AccessBitMask; 175 176 /* Flush caches, as per ACPI specification */ 177 178 ACPI_FLUSH_CPU_CACHE (); 179 180 /* Write #2: Write both SLP_TYP + SLP_EN */ 181 182 Status = AcpiHwWritePm1Control (Pm1aControl, Pm1bControl); 183 if (ACPI_FAILURE (Status)) 184 { 185 return_ACPI_STATUS (Status); 186 } 187 188 if (SleepState > ACPI_STATE_S3) 189 { 190 /* 191 * We wanted to sleep > S3, but it didn't happen (by virtue of the 192 * fact that we are still executing!) 193 * 194 * Wait ten seconds, then try again. This is to get S4/S5 to work on 195 * all machines. 196 * 197 * We wait so long to allow chipsets that poll this reg very slowly 198 * to still read the right value. Ideally, this block would go 199 * away entirely. 200 */ 201 AcpiOsStall (10000000); 202 203 Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_CONTROL, 204 SleepEnableRegInfo->AccessBitMask); 205 if (ACPI_FAILURE (Status)) 206 { 207 return_ACPI_STATUS (Status); 208 } 209 } 210 211 /* Wait for transition back to Working State */ 212 213 Retry = 1000; 214 do 215 { 216 Status = AcpiReadBitRegister (ACPI_BITREG_WAKE_STATUS, &InValue); 217 if (ACPI_FAILURE (Status)) 218 { 219 return_ACPI_STATUS (Status); 220 } 221 222 if (AcpiGbl_EnableInterpreterSlack) 223 { 224 /* 225 * Some BIOSs don't set WAK_STS at all. Give up waiting after 226 * 1000 retries if it still isn't set. 227 */ 228 if (Retry-- == 0) 229 { 230 break; 231 } 232 } 233 234 } while (!InValue); 235 236 return_ACPI_STATUS (AE_OK); 237} 238 239 240/******************************************************************************* 241 * 242 * FUNCTION: AcpiHwLegacyWakePrep 243 * 244 * PARAMETERS: SleepState - Which sleep state we just exited 245 * 246 * RETURN: Status 247 * 248 * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a 249 * sleep. 250 * Called with interrupts ENABLED. 251 * 252 ******************************************************************************/ 253 254ACPI_STATUS 255AcpiHwLegacyWakePrep ( 256 UINT8 SleepState) 257{ 258 ACPI_STATUS Status; 259 ACPI_BIT_REGISTER_INFO *SleepTypeRegInfo; 260 ACPI_BIT_REGISTER_INFO *SleepEnableRegInfo; 261 UINT32 Pm1aControl; 262 UINT32 Pm1bControl; 263 264 265 ACPI_FUNCTION_TRACE (HwLegacyWakePrep); 266 267 /* 268 * Set SLP_TYPE and SLP_EN to state S0. 269 * This is unclear from the ACPI Spec, but it is required 270 * by some machines. 271 */ 272 Status = AcpiGetSleepTypeData (ACPI_STATE_S0, 273 &AcpiGbl_SleepTypeA, &AcpiGbl_SleepTypeB); 274 if (ACPI_SUCCESS (Status)) 275 { 276 SleepTypeRegInfo = 277 AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_TYPE); 278 SleepEnableRegInfo = 279 AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_ENABLE); 280 281 /* Get current value of PM1A control */ 282 283 Status = AcpiHwRegisterRead (ACPI_REGISTER_PM1_CONTROL, 284 &Pm1aControl); 285 if (ACPI_SUCCESS (Status)) 286 { 287 /* Clear the SLP_EN and SLP_TYP fields */ 288 289 Pm1aControl &= ~(SleepTypeRegInfo->AccessBitMask | 290 SleepEnableRegInfo->AccessBitMask); 291 Pm1bControl = Pm1aControl; 292 293 /* Insert the SLP_TYP bits */ 294 295 Pm1aControl |= (AcpiGbl_SleepTypeA << 296 SleepTypeRegInfo->BitPosition); 297 Pm1bControl |= (AcpiGbl_SleepTypeB << 298 SleepTypeRegInfo->BitPosition); 299 300 /* Write the control registers and ignore any errors */ 301 302 (void) AcpiHwWritePm1Control (Pm1aControl, Pm1bControl); 303 } 304 } 305 306 AcpiHwExecuteSleepMethod (METHOD_NAME__BFS, SleepState); 307 return_ACPI_STATUS (Status); 308} 309 310 311/******************************************************************************* 312 * 313 * FUNCTION: AcpiHwLegacyWake 314 * 315 * PARAMETERS: SleepState - Which sleep state we just exited 316 * 317 * RETURN: Status 318 * 319 * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep 320 * Called with interrupts ENABLED. 321 * 322 ******************************************************************************/ 323 324ACPI_STATUS 325AcpiHwLegacyWake ( 326 UINT8 SleepState) 327{ 328 ACPI_STATUS Status; 329 330 331 ACPI_FUNCTION_TRACE (HwLegacyWake); 332 333 334 /* Ensure EnterSleepStatePrep -> EnterSleepState ordering */ 335 336 AcpiGbl_SleepTypeA = ACPI_SLEEP_TYPE_INVALID; 337 AcpiHwExecuteSleepMethod (METHOD_NAME__SST, ACPI_SST_WAKING); 338 339 /* 340 * GPEs must be enabled before _WAK is called as GPEs 341 * might get fired there 342 * 343 * Restore the GPEs: 344 * 1) Disable/Clear all GPEs 345 * 2) Enable all runtime GPEs 346 */ 347 Status = AcpiHwDisableAllGpes (); 348 if (ACPI_FAILURE (Status)) 349 { 350 return_ACPI_STATUS (Status); 351 } 352 353 Status = AcpiHwEnableAllRuntimeGpes (); 354 if (ACPI_FAILURE (Status)) 355 { 356 return_ACPI_STATUS (Status); 357 } 358 359 /* 360 * Now we can execute _WAK, etc. Some machines require that the GPEs 361 * are enabled before the wake methods are executed. 362 */ 363 AcpiHwExecuteSleepMethod (METHOD_NAME__WAK, SleepState); 364 365 /* 366 * Some BIOS code assumes that WAK_STS will be cleared on resume 367 * and use it to determine whether the system is rebooting or 368 * resuming. Clear WAK_STS for compatibility. 369 */ 370 (void) AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS); 371 AcpiGbl_SystemAwakeAndRunning = TRUE; 372 373 /* Enable power button */ 374 375 (void) AcpiWriteBitRegister( 376 AcpiGbl_FixedEventInfo[ACPI_EVENT_POWER_BUTTON].EnableRegisterId, 377 ACPI_ENABLE_EVENT); 378 379 (void) AcpiWriteBitRegister( 380 AcpiGbl_FixedEventInfo[ACPI_EVENT_POWER_BUTTON].StatusRegisterId, 381 ACPI_CLEAR_STATUS); 382 383 /* 384 * Enable BM arbitration. This feature is contained within an 385 * optional register (PM2 Control), so ignore a BAD_ADDRESS 386 * exception. 387 */ 388 Status = AcpiWriteBitRegister (ACPI_BITREG_ARB_DISABLE, 0); 389 if (ACPI_FAILURE (Status) && (Status != AE_BAD_ADDRESS)) 390 { 391 return_ACPI_STATUS (Status); 392 } 393 394 AcpiHwExecuteSleepMethod (METHOD_NAME__SST, ACPI_SST_WORKING); 395 return_ACPI_STATUS (Status); 396} 397 398#endif /* !ACPI_REDUCED_HARDWARE */ 399