1 2/****************************************************************************** 3 * 4 * Name: hwsleep.c - ACPI Hardware Sleep/Wake Interface 5 * $Revision: 1.1.1.1 $ 6 * 7 *****************************************************************************/ 8 9/* 10 * Copyright (C) 2000, 2001 R. Byron Moore 11 * 12 * This program is free software; you can redistribute it and/or modify 13 * it under the terms of the GNU General Public License as published by 14 * the Free Software Foundation; either version 2 of the License, or 15 * (at your option) any later version. 16 * 17 * This program is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * GNU General Public License for more details. 21 * 22 * You should have received a copy of the GNU General Public License 23 * along with this program; if not, write to the Free Software 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 25 */ 26 27#include "acpi.h" 28#include "acnamesp.h" 29#include "achware.h" 30 31#define _COMPONENT ACPI_HARDWARE 32 MODULE_NAME ("hwsleep") 33 34 35/****************************************************************************** 36 * 37 * FUNCTION: Acpi_set_firmware_waking_vector 38 * 39 * PARAMETERS: Physical_address - Physical address of ACPI real mode 40 * entry point. 41 * 42 * RETURN: AE_OK or AE_ERROR 43 * 44 * DESCRIPTION: Access function for d_firmware_waking_vector field in FACS 45 * 46 ******************************************************************************/ 47 48acpi_status 49acpi_set_firmware_waking_vector ( 50 ACPI_PHYSICAL_ADDRESS physical_address) 51{ 52 53 FUNCTION_TRACE ("Acpi_set_firmware_waking_vector"); 54 55 56 /* Make sure that we have an FACS */ 57 58 if (!acpi_gbl_FACS) { 59 return_ACPI_STATUS (AE_NO_ACPI_TABLES); 60 } 61 62 /* Set the vector */ 63 64 if (acpi_gbl_FACS->vector_width == 32) { 65 * (u32 *) acpi_gbl_FACS->firmware_waking_vector = (u32) physical_address; 66 } 67 else { 68 *acpi_gbl_FACS->firmware_waking_vector = physical_address; 69 } 70 71 return_ACPI_STATUS (AE_OK); 72} 73 74 75/****************************************************************************** 76 * 77 * FUNCTION: Acpi_get_firmware_waking_vector 78 * 79 * PARAMETERS: *Physical_address - Output buffer where contents of 80 * the Firmware_waking_vector field of 81 * the FACS will be stored. 82 * 83 * RETURN: Status 84 * 85 * DESCRIPTION: Access function for d_firmware_waking_vector field in FACS 86 * 87 ******************************************************************************/ 88 89acpi_status 90acpi_get_firmware_waking_vector ( 91 ACPI_PHYSICAL_ADDRESS *physical_address) 92{ 93 94 FUNCTION_TRACE ("Acpi_get_firmware_waking_vector"); 95 96 97 if (!physical_address) { 98 return_ACPI_STATUS (AE_BAD_PARAMETER); 99 } 100 101 /* Make sure that we have an FACS */ 102 103 if (!acpi_gbl_FACS) { 104 return_ACPI_STATUS (AE_NO_ACPI_TABLES); 105 } 106 107 /* Get the vector */ 108 109 if (acpi_gbl_FACS->vector_width == 32) { 110 *physical_address = * (u32 *) acpi_gbl_FACS->firmware_waking_vector; 111 } 112 else { 113 *physical_address = *acpi_gbl_FACS->firmware_waking_vector; 114 } 115 116 return_ACPI_STATUS (AE_OK); 117} 118 119/****************************************************************************** 120 * 121 * FUNCTION: Acpi_enter_sleep_state 122 * 123 * PARAMETERS: Sleep_state - Which sleep state to enter 124 * 125 * RETURN: Status 126 * 127 * DESCRIPTION: Enter a system sleep state (see ACPI 2.0 spec p 231) 128 * 129 ******************************************************************************/ 130 131acpi_status 132acpi_enter_sleep_state ( 133 u8 sleep_state) 134{ 135 acpi_status status; 136 acpi_object_list arg_list; 137 acpi_object arg; 138 u8 type_a; 139 u8 type_b; 140 u16 PM1Acontrol; 141 u16 PM1Bcontrol; 142 143 144 FUNCTION_TRACE ("Acpi_enter_sleep_state"); 145 146 147 /* 148 * _PSW methods could be run here to enable wake-on keyboard, LAN, etc. 149 */ 150 status = acpi_hw_obtain_sleep_type_register_data (sleep_state, &type_a, &type_b); 151 if (!ACPI_SUCCESS (status)) { 152 return status; 153 } 154 155 /* run the _PTS and _GTS methods */ 156 157 MEMSET(&arg_list, 0, sizeof(arg_list)); 158 arg_list.count = 1; 159 arg_list.pointer = &arg; 160 161 MEMSET(&arg, 0, sizeof(arg)); 162 arg.type = ACPI_TYPE_INTEGER; 163 arg.integer.value = sleep_state; 164 165 acpi_evaluate_object (NULL, "\\_PTS", &arg_list, NULL); 166 acpi_evaluate_object (NULL, "\\_GTS", &arg_list, NULL); 167 168 /* clear wake status */ 169 170 acpi_hw_register_bit_access (ACPI_WRITE, ACPI_MTX_LOCK, WAK_STS, 1); 171 172 disable (); 173 174 acpi_hw_disable_non_wakeup_gpes(); 175 176 PM1Acontrol = (u16) acpi_hw_register_read (ACPI_MTX_LOCK, PM1_CONTROL); 177 178 ACPI_DEBUG_PRINT ((ACPI_DB_OK, "Entering S%d\n", sleep_state)); 179 180 /* mask off SLP_EN and SLP_TYP fields */ 181 182 PM1Acontrol &= ~(SLP_TYPE_X_MASK | SLP_EN_MASK); 183 PM1Bcontrol = PM1Acontrol; 184 185 /* mask in SLP_TYP */ 186 187 PM1Acontrol |= (type_a << acpi_hw_get_bit_shift (SLP_TYPE_X_MASK)); 188 PM1Bcontrol |= (type_b << acpi_hw_get_bit_shift (SLP_TYPE_X_MASK)); 189 190 /* write #1: fill in SLP_TYP data */ 191 192 acpi_hw_register_write (ACPI_MTX_LOCK, PM1A_CONTROL, PM1Acontrol); 193 acpi_hw_register_write (ACPI_MTX_LOCK, PM1B_CONTROL, PM1Bcontrol); 194 195 /* mask in SLP_EN */ 196 197 PM1Acontrol |= (1 << acpi_hw_get_bit_shift (SLP_EN_MASK)); 198 PM1Bcontrol |= (1 << acpi_hw_get_bit_shift (SLP_EN_MASK)); 199 200 /* flush caches */ 201 202 wbinvd(); 203 204 /* write #2: SLP_TYP + SLP_EN */ 205 206 acpi_hw_register_write (ACPI_MTX_LOCK, PM1A_CONTROL, PM1Acontrol); 207 acpi_hw_register_write (ACPI_MTX_LOCK, PM1B_CONTROL, PM1Bcontrol); 208 209 /* 210 * Wait a second, then try again. This is to get S4/5 to work on all machines. 211 */ 212 if (sleep_state > ACPI_STATE_S3) { 213 acpi_os_stall(1000000); 214 215 acpi_hw_register_write (ACPI_MTX_LOCK, PM1_CONTROL, 216 (1 << acpi_hw_get_bit_shift (SLP_EN_MASK))); 217 } 218 219 /* wait until we enter sleep state */ 220 221 do { 222 acpi_os_stall(10000); 223 } 224 while (!acpi_hw_register_bit_access (ACPI_READ, ACPI_MTX_LOCK, WAK_STS)); 225 226 acpi_hw_enable_non_wakeup_gpes(); 227 228 enable (); 229 230 return_ACPI_STATUS (AE_OK); 231} 232 233/****************************************************************************** 234 * 235 * FUNCTION: Acpi_leave_sleep_state 236 * 237 * PARAMETERS: Sleep_state - Which sleep state we just exited 238 * 239 * RETURN: Status 240 * 241 * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep 242 * 243 ******************************************************************************/ 244 245acpi_status 246acpi_leave_sleep_state ( 247 u8 sleep_state) 248{ 249 acpi_object_list arg_list; 250 acpi_object arg; 251 252 253 FUNCTION_TRACE ("Acpi_leave_sleep_state"); 254 255 256 MEMSET (&arg_list, 0, sizeof(arg_list)); 257 arg_list.count = 1; 258 arg_list.pointer = &arg; 259 260 MEMSET (&arg, 0, sizeof(arg)); 261 arg.type = ACPI_TYPE_INTEGER; 262 arg.integer.value = sleep_state; 263 264 acpi_evaluate_object (NULL, "\\_BFS", &arg_list, NULL); 265 acpi_evaluate_object (NULL, "\\_WAK", &arg_list, NULL); 266 267 /* _WAK returns stuff - do we want to look at it? */ 268 269 acpi_hw_enable_non_wakeup_gpes(); 270 271 return_ACPI_STATUS (AE_OK); 272} 273