2018-03-14 16:13:07 -07:00
// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2005-04-16 15:20:36 -07:00
/******************************************************************************
*
2012-02-14 18:47:42 +08:00
* Name : hwsleep . c - ACPI Hardware Sleep / Wake Support functions for the
* original / legacy sleep / PM registers .
2005-04-16 15:20:36 -07:00
*
2019-01-14 09:55:25 -08:00
* Copyright ( C ) 2000 - 2019 , Intel Corp .
2005-04-16 15:20:36 -07:00
*
2018-03-14 16:13:07 -07:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-04-16 15:20:36 -07:00
# include <acpi/acpi.h>
2009-01-09 00:30:03 -05:00
# include "accommon.h"
2005-04-16 15:20:36 -07:00
# define _COMPONENT ACPI_HARDWARE
2005-08-05 00:44:28 -04:00
ACPI_MODULE_NAME ( " hwsleep " )
2005-04-16 15:20:36 -07:00
2012-02-14 18:47:42 +08:00
# if (!ACPI_REDUCED_HARDWARE) /* Entire module */
2005-04-18 22:49:35 -04:00
/*******************************************************************************
2005-04-16 15:20:36 -07:00
*
2012-02-14 15:00:53 +08:00
* FUNCTION : acpi_hw_legacy_sleep
2005-04-16 15:20:36 -07:00
*
* PARAMETERS : sleep_state - Which sleep state to enter
*
* RETURN : Status
*
2012-02-14 15:00:53 +08:00
* DESCRIPTION : Enter a system sleep state via the legacy FADT PM registers
2005-04-16 15:20:36 -07:00
* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2012-07-26 20:08:54 -04:00
acpi_status acpi_hw_legacy_sleep ( u8 sleep_state )
2005-04-16 15:20:36 -07:00
{
2005-08-05 00:44:28 -04:00
struct acpi_bit_register_info * sleep_type_reg_info ;
struct acpi_bit_register_info * sleep_enable_reg_info ;
2012-02-14 15:00:53 +08:00
u32 pm1a_control ;
u32 pm1b_control ;
2005-08-05 00:44:28 -04:00
u32 in_value ;
acpi_status status ;
2005-04-16 15:20:36 -07:00
2012-02-14 15:00:53 +08:00
ACPI_FUNCTION_TRACE ( hw_legacy_sleep ) ;
2005-04-16 15:20:36 -07:00
2005-08-05 00:44:28 -04:00
sleep_type_reg_info =
2009-02-18 14:31:05 +08:00
acpi_hw_get_bit_register_info ( ACPI_BITREG_SLEEP_TYPE ) ;
2005-08-05 00:44:28 -04:00
sleep_enable_reg_info =
acpi_hw_get_bit_register_info ( ACPI_BITREG_SLEEP_ENABLE ) ;
2005-04-16 15:20:36 -07:00
/* Clear wake status */
2015-12-29 13:54:36 +08:00
status = acpi_write_bit_register ( ACPI_BITREG_WAKE_STATUS ,
ACPI_CLEAR_STATUS ) ;
2005-08-05 00:44:28 -04:00
if ( ACPI_FAILURE ( status ) ) {
return_ACPI_STATUS ( status ) ;
2005-04-16 15:20:36 -07:00
}
2018-07-09 11:01:07 +02:00
/* Disable all GPEs */
2007-03-12 14:49:26 -04:00
status = acpi_hw_disable_all_gpes ( ) ;
if ( ACPI_FAILURE ( status ) ) {
return_ACPI_STATUS ( status ) ;
}
2018-08-12 12:50:09 +02:00
status = acpi_hw_clear_acpi_status ( ) ;
if ( ACPI_FAILURE ( status ) ) {
return_ACPI_STATUS ( status ) ;
2018-07-09 11:01:07 +02:00
}
2005-04-16 15:20:36 -07:00
acpi_gbl_system_awake_and_running = FALSE ;
2018-07-09 11:01:07 +02:00
/* Enable all wakeup GPEs */
2005-08-05 00:44:28 -04:00
status = acpi_hw_enable_all_wakeup_gpes ( ) ;
if ( ACPI_FAILURE ( status ) ) {
return_ACPI_STATUS ( status ) ;
2005-04-16 15:20:36 -07:00
}
/* Get current value of PM1A control */
2009-02-18 14:36:05 +08:00
status = acpi_hw_register_read ( ACPI_REGISTER_PM1_CONTROL ,
& pm1a_control ) ;
2005-08-05 00:44:28 -04:00
if ( ACPI_FAILURE ( status ) ) {
return_ACPI_STATUS ( status ) ;
2005-04-16 15:20:36 -07:00
}
2005-08-05 00:44:28 -04:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_INIT ,
2010-05-26 11:47:13 +08:00
" Entering sleep state [S%u] \n " , sleep_state ) ) ;
2005-04-16 15:20:36 -07:00
2009-02-18 14:36:05 +08:00
/* Clear the SLP_EN and SLP_TYP fields */
2005-04-16 15:20:36 -07:00
2009-02-18 14:36:05 +08:00
pm1a_control & = ~ ( sleep_type_reg_info - > access_bit_mask |
sleep_enable_reg_info - > access_bit_mask ) ;
pm1b_control = pm1a_control ;
2005-04-16 15:20:36 -07:00
2009-02-18 14:36:05 +08:00
/* Insert the SLP_TYP bits */
2005-04-16 15:20:36 -07:00
2009-02-18 14:36:05 +08:00
pm1a_control | =
2005-08-05 00:44:28 -04:00
( acpi_gbl_sleep_type_a < < sleep_type_reg_info - > bit_position ) ;
2009-02-18 14:36:05 +08:00
pm1b_control | =
2005-08-05 00:44:28 -04:00
( acpi_gbl_sleep_type_b < < sleep_type_reg_info - > bit_position ) ;
2005-04-16 15:20:36 -07:00
/*
* We split the writes of SLP_TYP and SLP_EN to workaround
* poorly implemented hardware .
*/
2009-02-18 14:36:05 +08:00
/* Write #1: write the SLP_TYP data to the PM1 Control registers */
2005-04-16 15:20:36 -07:00
2009-02-18 14:36:05 +08:00
status = acpi_hw_write_pm1_control ( pm1a_control , pm1b_control ) ;
2005-08-05 00:44:28 -04:00
if ( ACPI_FAILURE ( status ) ) {
return_ACPI_STATUS ( status ) ;
2005-04-16 15:20:36 -07:00
}
2009-02-18 14:36:05 +08:00
/* Insert the sleep enable (SLP_EN) bit */
2005-04-16 15:20:36 -07:00
2009-02-18 14:36:05 +08:00
pm1a_control | = sleep_enable_reg_info - > access_bit_mask ;
pm1b_control | = sleep_enable_reg_info - > access_bit_mask ;
2005-04-16 15:20:36 -07:00
2009-02-18 14:36:05 +08:00
/* Flush caches, as per ACPI specification */
2005-04-16 15:20:36 -07:00
2005-08-05 00:44:28 -04:00
ACPI_FLUSH_CPU_CACHE ( ) ;
2005-04-16 15:20:36 -07:00
2016-12-28 15:28:49 +08:00
status = acpi_os_enter_sleep ( sleep_state , pm1a_control , pm1b_control ) ;
if ( status = = AE_CTRL_TERMINATE ) {
2011-12-09 10:05:54 +08:00
return_ACPI_STATUS ( AE_OK ) ;
2016-12-28 15:28:49 +08:00
}
if ( ACPI_FAILURE ( status ) ) {
2011-12-09 10:05:54 +08:00
return_ACPI_STATUS ( status ) ;
2016-12-28 15:28:49 +08:00
}
2009-02-18 14:36:05 +08:00
/* Write #2: Write both SLP_TYP + SLP_EN */
2005-04-16 15:20:36 -07:00
2009-02-18 14:36:05 +08:00
status = acpi_hw_write_pm1_control ( pm1a_control , pm1b_control ) ;
2005-08-05 00:44:28 -04:00
if ( ACPI_FAILURE ( status ) ) {
return_ACPI_STATUS ( status ) ;
2005-04-16 15:20:36 -07:00
}
if ( sleep_state > ACPI_STATE_S3 ) {
/*
2005-04-18 22:49:35 -04:00
* We wanted to sleep > S3 , but it didn ' t happen ( by virtue of the
* fact that we are still executing ! )
2005-04-16 15:20:36 -07:00
*
2005-04-18 22:49:35 -04:00
* Wait ten seconds , then try again . This is to get S4 / S5 to work on
* all machines .
2005-04-16 15:20:36 -07:00
*
2009-03-06 10:05:18 +08:00
* We wait so long to allow chipsets that poll this reg very slowly
* to still read the right value . Ideally , this block would go
2005-04-16 15:20:36 -07:00
* away entirely .
*/
2012-12-31 00:05:46 +00:00
acpi_os_stall ( 10 * ACPI_USEC_PER_SEC ) ;
2005-08-05 00:44:28 -04:00
2007-09-30 22:39:36 +04:00
status = acpi_hw_register_write ( ACPI_REGISTER_PM1_CONTROL ,
2005-08-05 00:44:28 -04:00
sleep_enable_reg_info - >
access_bit_mask ) ;
if ( ACPI_FAILURE ( status ) ) {
return_ACPI_STATUS ( status ) ;
2005-04-16 15:20:36 -07:00
}
}
2012-02-14 15:00:53 +08:00
/* Wait for transition back to Working State */
2005-04-16 15:20:36 -07:00
do {
2009-02-23 15:02:07 +08:00
status =
acpi_read_bit_register ( ACPI_BITREG_WAKE_STATUS , & in_value ) ;
2005-08-05 00:44:28 -04:00
if ( ACPI_FAILURE ( status ) ) {
return_ACPI_STATUS ( status ) ;
2005-04-16 15:20:36 -07:00
}
2012-02-14 15:00:53 +08:00
2005-04-16 15:20:36 -07:00
} while ( ! in_value ) ;
2005-08-05 00:44:28 -04:00
return_ACPI_STATUS ( AE_OK ) ;
2005-04-16 15:20:36 -07:00
}
2005-04-18 22:49:35 -04:00
/*******************************************************************************
2005-04-16 15:20:36 -07:00
*
2012-02-14 15:00:53 +08:00
* FUNCTION : acpi_hw_legacy_wake_prep
2005-04-16 15:20:36 -07:00
*
2012-02-14 15:00:53 +08:00
* PARAMETERS : sleep_state - Which sleep state we just exited
2005-04-16 15:20:36 -07:00
*
* RETURN : Status
*
2008-01-08 00:05:21 +01:00
* DESCRIPTION : Perform the first state of OS - independent ACPI cleanup after a
* sleep .
2012-02-14 15:00:53 +08:00
* Called with interrupts ENABLED .
2005-04-16 15:20:36 -07:00
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2012-02-14 15:00:53 +08:00
2012-07-26 20:08:54 -04:00
acpi_status acpi_hw_legacy_wake_prep ( u8 sleep_state )
2005-04-16 15:20:36 -07:00
{
2005-08-05 00:44:28 -04:00
acpi_status status ;
struct acpi_bit_register_info * sleep_type_reg_info ;
struct acpi_bit_register_info * sleep_enable_reg_info ;
2009-02-18 14:36:05 +08:00
u32 pm1a_control ;
u32 pm1b_control ;
2005-04-16 15:20:36 -07:00
2012-02-14 15:00:53 +08:00
ACPI_FUNCTION_TRACE ( hw_legacy_wake_prep ) ;
2005-04-16 15:20:36 -07:00
/*
* Set SLP_TYPE and SLP_EN to state S0 .
* This is unclear from the ACPI Spec , but it is required
* by some machines .
*/
2005-08-05 00:44:28 -04:00
status = acpi_get_sleep_type_data ( ACPI_STATE_S0 ,
& acpi_gbl_sleep_type_a ,
& acpi_gbl_sleep_type_b ) ;
if ( ACPI_SUCCESS ( status ) ) {
sleep_type_reg_info =
2009-02-18 14:31:05 +08:00
acpi_hw_get_bit_register_info ( ACPI_BITREG_SLEEP_TYPE ) ;
2005-08-05 00:44:28 -04:00
sleep_enable_reg_info =
acpi_hw_get_bit_register_info ( ACPI_BITREG_SLEEP_ENABLE ) ;
2005-04-16 15:20:36 -07:00
/* Get current value of PM1A control */
2007-09-30 22:39:36 +04:00
status = acpi_hw_register_read ( ACPI_REGISTER_PM1_CONTROL ,
2009-02-18 14:36:05 +08:00
& pm1a_control ) ;
2005-08-05 00:44:28 -04:00
if ( ACPI_SUCCESS ( status ) ) {
2006-10-02 00:00:00 -04:00
2009-02-18 14:36:05 +08:00
/* Clear the SLP_EN and SLP_TYP fields */
2005-04-16 15:20:36 -07:00
2009-02-18 14:36:05 +08:00
pm1a_control & = ~ ( sleep_type_reg_info - > access_bit_mask |
sleep_enable_reg_info - >
access_bit_mask ) ;
pm1b_control = pm1a_control ;
2005-04-16 15:20:36 -07:00
2009-02-18 14:36:05 +08:00
/* Insert the SLP_TYP bits */
2005-04-16 15:20:36 -07:00
2009-03-06 10:05:18 +08:00
pm1a_control | = ( acpi_gbl_sleep_type_a < <
sleep_type_reg_info - > bit_position ) ;
pm1b_control | = ( acpi_gbl_sleep_type_b < <
sleep_type_reg_info - > bit_position ) ;
2005-04-16 15:20:36 -07:00
2009-02-18 14:36:05 +08:00
/* Write the control registers and ignore any errors */
2005-04-16 15:20:36 -07:00
2009-02-18 14:36:05 +08:00
( void ) acpi_hw_write_pm1_control ( pm1a_control ,
pm1b_control ) ;
2005-04-16 15:20:36 -07:00
}
}
2008-01-08 00:05:21 +01:00
return_ACPI_STATUS ( status ) ;
}
/*******************************************************************************
*
2012-02-14 15:00:53 +08:00
* FUNCTION : acpi_hw_legacy_wake
2008-01-08 00:05:21 +01:00
*
* PARAMETERS : sleep_state - Which sleep state we just exited
*
* RETURN : Status
*
* DESCRIPTION : Perform OS - independent ACPI cleanup after a sleep
* Called with interrupts ENABLED .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2012-02-14 15:00:53 +08:00
2012-07-26 20:08:54 -04:00
acpi_status acpi_hw_legacy_wake ( u8 sleep_state )
2008-01-08 00:05:21 +01:00
{
acpi_status status ;
2012-02-14 15:00:53 +08:00
ACPI_FUNCTION_TRACE ( hw_legacy_wake ) ;
2008-01-08 00:05:21 +01:00
2005-04-16 15:20:36 -07:00
/* Ensure enter_sleep_state_prep -> enter_sleep_state ordering */
acpi_gbl_sleep_type_a = ACPI_SLEEP_TYPE_INVALID ;
2012-03-21 09:42:45 +08:00
acpi_hw_execute_sleep_method ( METHOD_PATHNAME__SST , ACPI_SST_WAKING ) ;
2005-04-16 15:20:36 -07:00
/*
2007-08-24 01:24:47 -04:00
* GPEs must be enabled before _WAK is called as GPEs
* might get fired there
*
2005-04-16 15:20:36 -07:00
* Restore the GPEs :
2018-03-14 16:12:57 -07:00
* 1 ) Disable all GPEs
2005-04-16 15:20:36 -07:00
* 2 ) Enable all runtime GPEs
*/
2005-08-05 00:44:28 -04:00
status = acpi_hw_disable_all_gpes ( ) ;
if ( ACPI_FAILURE ( status ) ) {
return_ACPI_STATUS ( status ) ;
2005-04-16 15:20:36 -07:00
}
2012-02-14 15:00:53 +08:00
2005-08-05 00:44:28 -04:00
status = acpi_hw_enable_all_runtime_gpes ( ) ;
if ( ACPI_FAILURE ( status ) ) {
return_ACPI_STATUS ( status ) ;
2005-04-16 15:20:36 -07:00
}
2012-02-14 15:00:53 +08:00
/*
* Now we can execute _WAK , etc . Some machines require that the GPEs
* are enabled before the wake methods are executed .
*/
2012-03-21 09:42:45 +08:00
acpi_hw_execute_sleep_method ( METHOD_PATHNAME__WAK , sleep_state ) ;
2007-08-24 01:24:47 -04:00
2008-08-06 19:12:04 +01:00
/*
2012-02-14 15:00:53 +08:00
* Some BIOS code assumes that WAK_STS will be cleared on resume
* and use it to determine whether the system is rebooting or
* resuming . Clear WAK_STS for compatibility .
2008-08-06 19:12:04 +01:00
*/
2012-12-20 01:07:26 +00:00
( void ) acpi_write_bit_register ( ACPI_BITREG_WAKE_STATUS ,
ACPI_CLEAR_STATUS ) ;
2007-08-24 01:24:47 -04:00
acpi_gbl_system_awake_and_running = TRUE ;
2005-04-16 15:20:36 -07:00
/* Enable power button */
2005-08-05 00:44:28 -04:00
( void )
2009-02-23 15:02:07 +08:00
acpi_write_bit_register ( acpi_gbl_fixed_event_info
2012-02-14 15:00:53 +08:00
[ ACPI_EVENT_POWER_BUTTON ] .
enable_register_id , ACPI_ENABLE_EVENT ) ;
2005-04-18 22:49:35 -04:00
2005-08-05 00:44:28 -04:00
( void )
2009-02-23 15:02:07 +08:00
acpi_write_bit_register ( acpi_gbl_fixed_event_info
2012-02-14 15:00:53 +08:00
[ ACPI_EVENT_POWER_BUTTON ] .
status_register_id , ACPI_CLEAR_STATUS ) ;
2005-04-16 15:20:36 -07:00
2012-03-21 09:42:45 +08:00
acpi_hw_execute_sleep_method ( METHOD_PATHNAME__SST , ACPI_SST_WORKING ) ;
2005-08-05 00:44:28 -04:00
return_ACPI_STATUS ( status ) ;
2005-04-16 15:20:36 -07:00
}
2006-10-03 00:00:00 -04:00
2012-02-14 18:14:27 +08:00
# endif /* !ACPI_REDUCED_HARDWARE */