blob: 59a2a6b897d40ea1dc2e5c5d8256e7e3aa0303be [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/******************************************************************************
2 *
Bob Moore2feec472012-02-14 15:00:53 +08003 * Name: hwsleep.c - ACPI Hardware Sleep/Wake Support Functions
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 *
5 *****************************************************************************/
6
7/*
Bob Moore77848132012-01-12 13:27:23 +08008 * Copyright (C) 2000 - 2012, Intel Corp.
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions, and the following disclaimer,
16 * without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 * substantially similar to the "NO WARRANTY" disclaimer below
19 * ("Disclaimer") and any redistribution must be conditioned upon
20 * including a substantially similar Disclaimer requirement for further
21 * binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 * of any contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
29 *
30 * NO WARRANTY
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
42 */
43
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#include <acpi/acpi.h>
Len Browne2f7a772009-01-09 00:30:03 -050045#include "accommon.h"
Shane Wang69575d32009-09-01 18:25:07 -070046#include <linux/tboot.h>
Paul Gortmakercc4b8592011-07-01 14:30:49 -040047#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070048
49#define _COMPONENT ACPI_HARDWARE
Len Brown4be44fc2005-08-05 00:44:28 -040050ACPI_MODULE_NAME("hwsleep")
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
Bob Moore2feec472012-02-14 15:00:53 +080052/* Local prototypes */
53static void acpi_hw_execute_GTS(u8 sleep_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
Bob Moore2feec472012-02-14 15:00:53 +080055static void acpi_hw_execute_BFS(u8 sleep_state);
Bob Mooref3d2e782007-02-02 19:48:18 +030056
Bob Moore2feec472012-02-14 15:00:53 +080057static void acpi_hw_execute_WAK(u8 sleep_state);
Bob Moore83135242006-10-03 00:00:00 -040058
Len Brown96f15ef2009-04-17 23:32:20 -040059static unsigned int gts, bfs;
60module_param(gts, uint, 0644);
61module_param(bfs, uint, 0644);
62MODULE_PARM_DESC(gts, "Enable evaluation of _GTS on suspend.");
63MODULE_PARM_DESC(bfs, "Enable evaluation of _BFS on resume".);
64
Robert Moore44f6c012005-04-18 22:49:35 -040065/*******************************************************************************
Linus Torvalds1da177e2005-04-16 15:20:36 -070066 *
Bob Moore2feec472012-02-14 15:00:53 +080067 * FUNCTION: acpi_hw_execute_GTS
68 *
69 * PARAMETERS: sleep_state - Sleep state that will be entered
70 *
71 * RETURN: None
72 *
73 * DESCRIPTION: Execute the optional _GTS method (Going To Sleep)
74 *
75 ******************************************************************************/
76
77static void acpi_hw_execute_GTS(u8 sleep_state)
78{
79 struct acpi_object_list arg_list;
80 union acpi_object arg;
81 acpi_status status;
82
83 if (!gts)
84 return;
85
86 /* One argument, sleep_state */
87
88 arg_list.count = 1;
89 arg_list.pointer = &arg;
90 arg.type = ACPI_TYPE_INTEGER;
91 arg.integer.value = sleep_state;
92
93 status = acpi_evaluate_object(NULL, METHOD_NAME__GTS, &arg_list, NULL);
94 if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
95 ACPI_EXCEPTION((AE_INFO, status,
96 "While executing method _GTS"));
97 }
98}
99
100/*******************************************************************************
101 *
102 * FUNCTION: acpi_hw_execute_BFS
103 *
104 * PARAMETERS: sleep_state - Which sleep state we just exited
105 *
106 * RETURN: None
107 *
108 * DESCRIPTION: Execute the optional _BFS method (Back From Sleep)
109 *
110 ******************************************************************************/
111
112static void acpi_hw_execute_BFS(u8 sleep_state)
113{
114 struct acpi_object_list arg_list;
115 union acpi_object arg;
116 acpi_status status;
117
118 if (!bfs)
119 return;
120
121 /* One argument, sleep_state */
122
123 arg_list.count = 1;
124 arg_list.pointer = &arg;
125 arg.type = ACPI_TYPE_INTEGER;
126 arg.integer.value = sleep_state;
127
128 status = acpi_evaluate_object(NULL, METHOD_NAME__BFS, &arg_list, NULL);
129 if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
130 ACPI_EXCEPTION((AE_INFO, status,
131 "While executing method _BFS"));
132 }
133}
134
135/*******************************************************************************
136 *
137 * FUNCTION: acpi_hw_execute_WAK
138 *
139 * PARAMETERS: sleep_state - Which sleep state we just exited
140 *
141 * RETURN: None
142 *
143 * DESCRIPTION: Execute the _WAK method (System Wake)
144 *
145 ******************************************************************************/
146
147static void acpi_hw_execute_WAK(u8 sleep_state)
148{
149 struct acpi_object_list arg_list;
150 union acpi_object arg;
151 acpi_status status;
152
153 /* One argument, sleep_state */
154
155 arg_list.count = 1;
156 arg_list.pointer = &arg;
157 arg.type = ACPI_TYPE_INTEGER;
158 arg.integer.value = sleep_state;
159
160 status = acpi_evaluate_object(NULL, METHOD_NAME__WAK, &arg_list, NULL);
161 if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
162 ACPI_EXCEPTION((AE_INFO, status,
163 "While executing method _WAK"));
164 }
165 /* TBD: _WAK "sometimes" returns stuff - do we want to look at it? */
166}
167
168/*******************************************************************************
169 *
170 * FUNCTION: acpi_hw_execute_SST
171 *
172 * PARAMETERS: indicator_id - Value to be passed to the _SST method
173 *
174 * RETURN: None
175 *
176 * DESCRIPTION: Execute the optional _SST method (System Status)
177 *
178 ******************************************************************************/
179
180void acpi_hw_execute_SST(u32 indicator_id)
181{
182 struct acpi_object_list arg_list;
183 union acpi_object arg;
184 acpi_status status;
185
186 /* One argument, status indicator ID */
187
188 arg_list.count = 1;
189 arg_list.pointer = &arg;
190 arg.type = ACPI_TYPE_INTEGER;
191
192 arg.integer.value = indicator_id;
193 status = acpi_evaluate_object(NULL, METHOD_NAME__SST, &arg_list, NULL);
194 if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
195 ACPI_EXCEPTION((AE_INFO, status,
196 "While executing method _SST"));
197 }
198}
199
200/*******************************************************************************
201 *
202 * FUNCTION: acpi_hw_legacy_sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 *
204 * PARAMETERS: sleep_state - Which sleep state to enter
205 *
206 * RETURN: Status
207 *
Bob Moore2feec472012-02-14 15:00:53 +0800208 * DESCRIPTION: Enter a system sleep state via the legacy FADT PM registers
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
210 *
211 ******************************************************************************/
Bob Moore2feec472012-02-14 15:00:53 +0800212
213acpi_status acpi_hw_legacy_sleep(u8 sleep_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214{
Len Brown4be44fc2005-08-05 00:44:28 -0400215 struct acpi_bit_register_info *sleep_type_reg_info;
216 struct acpi_bit_register_info *sleep_enable_reg_info;
Bob Moore2feec472012-02-14 15:00:53 +0800217 u32 pm1a_control;
218 u32 pm1b_control;
Len Brown4be44fc2005-08-05 00:44:28 -0400219 u32 in_value;
220 acpi_status status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221
Bob Moore2feec472012-02-14 15:00:53 +0800222 ACPI_FUNCTION_TRACE(hw_legacy_sleep);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223
Len Brown4be44fc2005-08-05 00:44:28 -0400224 sleep_type_reg_info =
Bob Moore82d79b82009-02-18 14:31:05 +0800225 acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_TYPE);
Len Brown4be44fc2005-08-05 00:44:28 -0400226 sleep_enable_reg_info =
227 acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228
229 /* Clear wake status */
230
Bob Moore768aaaf2009-03-06 09:49:25 +0800231 status =
232 acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS);
Len Brown4be44fc2005-08-05 00:44:28 -0400233 if (ACPI_FAILURE(status)) {
234 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 }
236
237 /* Clear all fixed and general purpose status bits */
238
Bob Moored8c71b62007-02-02 19:48:21 +0300239 status = acpi_hw_clear_acpi_status();
Len Brown4be44fc2005-08-05 00:44:28 -0400240 if (ACPI_FAILURE(status)) {
241 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 }
243
Bob Moore2feec472012-02-14 15:00:53 +0800244 if (sleep_state != ACPI_STATE_S5) {
245 /*
246 * Disable BM arbitration. This feature is contained within an
247 * optional register (PM2 Control), so ignore a BAD_ADDRESS
248 * exception.
249 */
250 status = acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 1);
251 if (ACPI_FAILURE(status) && (status != AE_BAD_ADDRESS)) {
252 return_ACPI_STATUS(status);
253 }
254 }
255
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 /*
Pavel Machek23b168d2008-02-05 19:27:12 +0100257 * 1) Disable/Clear all GPEs
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 * 2) Enable all wakeup GPEs
259 */
Alexey Starikovskiy1d999672007-03-12 14:49:26 -0400260 status = acpi_hw_disable_all_gpes();
261 if (ACPI_FAILURE(status)) {
262 return_ACPI_STATUS(status);
263 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 acpi_gbl_system_awake_and_running = FALSE;
265
Len Brown4be44fc2005-08-05 00:44:28 -0400266 status = acpi_hw_enable_all_wakeup_gpes();
267 if (ACPI_FAILURE(status)) {
268 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 }
270
Bob Moore2feec472012-02-14 15:00:53 +0800271 /* Execute the _GTS method (Going To Sleep) */
Rafael J. Wysockic95d47a2008-01-08 00:05:21 +0100272
Bob Moore2feec472012-02-14 15:00:53 +0800273 acpi_hw_execute_GTS(sleep_state);
Rafael J. Wysockic95d47a2008-01-08 00:05:21 +0100274
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 /* Get current value of PM1A control */
276
Bob Moore32c9ef92009-02-18 14:36:05 +0800277 status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL,
278 &pm1a_control);
Len Brown4be44fc2005-08-05 00:44:28 -0400279 if (ACPI_FAILURE(status)) {
280 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 }
Len Brown4be44fc2005-08-05 00:44:28 -0400282 ACPI_DEBUG_PRINT((ACPI_DB_INIT,
Bob Mooreb27d6592010-05-26 11:47:13 +0800283 "Entering sleep state [S%u]\n", sleep_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284
Bob Moore32c9ef92009-02-18 14:36:05 +0800285 /* Clear the SLP_EN and SLP_TYP fields */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286
Bob Moore32c9ef92009-02-18 14:36:05 +0800287 pm1a_control &= ~(sleep_type_reg_info->access_bit_mask |
288 sleep_enable_reg_info->access_bit_mask);
289 pm1b_control = pm1a_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290
Bob Moore32c9ef92009-02-18 14:36:05 +0800291 /* Insert the SLP_TYP bits */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292
Bob Moore32c9ef92009-02-18 14:36:05 +0800293 pm1a_control |=
Len Brown4be44fc2005-08-05 00:44:28 -0400294 (acpi_gbl_sleep_type_a << sleep_type_reg_info->bit_position);
Bob Moore32c9ef92009-02-18 14:36:05 +0800295 pm1b_control |=
Len Brown4be44fc2005-08-05 00:44:28 -0400296 (acpi_gbl_sleep_type_b << sleep_type_reg_info->bit_position);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297
298 /*
299 * We split the writes of SLP_TYP and SLP_EN to workaround
300 * poorly implemented hardware.
301 */
302
Bob Moore32c9ef92009-02-18 14:36:05 +0800303 /* Write #1: write the SLP_TYP data to the PM1 Control registers */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
Bob Moore32c9ef92009-02-18 14:36:05 +0800305 status = acpi_hw_write_pm1_control(pm1a_control, pm1b_control);
Len Brown4be44fc2005-08-05 00:44:28 -0400306 if (ACPI_FAILURE(status)) {
307 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 }
309
Bob Moore32c9ef92009-02-18 14:36:05 +0800310 /* Insert the sleep enable (SLP_EN) bit */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
Bob Moore32c9ef92009-02-18 14:36:05 +0800312 pm1a_control |= sleep_enable_reg_info->access_bit_mask;
313 pm1b_control |= sleep_enable_reg_info->access_bit_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314
Bob Moore32c9ef92009-02-18 14:36:05 +0800315 /* Flush caches, as per ACPI specification */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
Len Brown4be44fc2005-08-05 00:44:28 -0400317 ACPI_FLUSH_CPU_CACHE();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
Joseph Cihula86886e52009-06-30 19:31:07 -0700319 tboot_sleep(sleep_state, pm1a_control, pm1b_control);
320
Bob Moore32c9ef92009-02-18 14:36:05 +0800321 /* Write #2: Write both SLP_TYP + SLP_EN */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322
Bob Moore32c9ef92009-02-18 14:36:05 +0800323 status = acpi_hw_write_pm1_control(pm1a_control, pm1b_control);
Len Brown4be44fc2005-08-05 00:44:28 -0400324 if (ACPI_FAILURE(status)) {
325 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 }
327
328 if (sleep_state > ACPI_STATE_S3) {
329 /*
Robert Moore44f6c012005-04-18 22:49:35 -0400330 * We wanted to sleep > S3, but it didn't happen (by virtue of the
331 * fact that we are still executing!)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 *
Robert Moore44f6c012005-04-18 22:49:35 -0400333 * Wait ten seconds, then try again. This is to get S4/S5 to work on
334 * all machines.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 *
Bob Moored4913dc2009-03-06 10:05:18 +0800336 * We wait so long to allow chipsets that poll this reg very slowly
337 * to still read the right value. Ideally, this block would go
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 * away entirely.
339 */
Len Brown4be44fc2005-08-05 00:44:28 -0400340 acpi_os_stall(10000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
Alexey Starikovskiyd30dc9ab2007-09-30 22:39:36 +0400342 status = acpi_hw_register_write(ACPI_REGISTER_PM1_CONTROL,
Len Brown4be44fc2005-08-05 00:44:28 -0400343 sleep_enable_reg_info->
344 access_bit_mask);
345 if (ACPI_FAILURE(status)) {
346 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 }
348 }
349
Bob Moore2feec472012-02-14 15:00:53 +0800350 /* Wait for transition back to Working State */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351
352 do {
Bob Moore50ffba12009-02-23 15:02:07 +0800353 status =
354 acpi_read_bit_register(ACPI_BITREG_WAKE_STATUS, &in_value);
Len Brown4be44fc2005-08-05 00:44:28 -0400355 if (ACPI_FAILURE(status)) {
356 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 }
Bob Moore2feec472012-02-14 15:00:53 +0800358
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 } while (!in_value);
360
Len Brown4be44fc2005-08-05 00:44:28 -0400361 return_ACPI_STATUS(AE_OK);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363
Robert Moore44f6c012005-04-18 22:49:35 -0400364/*******************************************************************************
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 *
Bob Moore2feec472012-02-14 15:00:53 +0800366 * FUNCTION: acpi_hw_legacy_wake_prep
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 *
Bob Moore2feec472012-02-14 15:00:53 +0800368 * PARAMETERS: sleep_state - Which sleep state we just exited
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 *
370 * RETURN: Status
371 *
Rafael J. Wysockic95d47a2008-01-08 00:05:21 +0100372 * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a
373 * sleep.
Bob Moore2feec472012-02-14 15:00:53 +0800374 * Called with interrupts ENABLED.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 *
376 ******************************************************************************/
Bob Moore2feec472012-02-14 15:00:53 +0800377
378acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379{
Len Brown4be44fc2005-08-05 00:44:28 -0400380 acpi_status status;
381 struct acpi_bit_register_info *sleep_type_reg_info;
382 struct acpi_bit_register_info *sleep_enable_reg_info;
Bob Moore32c9ef92009-02-18 14:36:05 +0800383 u32 pm1a_control;
384 u32 pm1b_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385
Bob Moore2feec472012-02-14 15:00:53 +0800386 ACPI_FUNCTION_TRACE(hw_legacy_wake_prep);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387
388 /*
389 * Set SLP_TYPE and SLP_EN to state S0.
390 * This is unclear from the ACPI Spec, but it is required
391 * by some machines.
392 */
Len Brown4be44fc2005-08-05 00:44:28 -0400393 status = acpi_get_sleep_type_data(ACPI_STATE_S0,
394 &acpi_gbl_sleep_type_a,
395 &acpi_gbl_sleep_type_b);
396 if (ACPI_SUCCESS(status)) {
397 sleep_type_reg_info =
Bob Moore82d79b82009-02-18 14:31:05 +0800398 acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_TYPE);
Len Brown4be44fc2005-08-05 00:44:28 -0400399 sleep_enable_reg_info =
400 acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401
402 /* Get current value of PM1A control */
403
Alexey Starikovskiyd30dc9ab2007-09-30 22:39:36 +0400404 status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL,
Bob Moore32c9ef92009-02-18 14:36:05 +0800405 &pm1a_control);
Len Brown4be44fc2005-08-05 00:44:28 -0400406 if (ACPI_SUCCESS(status)) {
Bob Moore52fc0b02006-10-02 00:00:00 -0400407
Bob Moore32c9ef92009-02-18 14:36:05 +0800408 /* Clear the SLP_EN and SLP_TYP fields */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409
Bob Moore32c9ef92009-02-18 14:36:05 +0800410 pm1a_control &= ~(sleep_type_reg_info->access_bit_mask |
411 sleep_enable_reg_info->
412 access_bit_mask);
413 pm1b_control = pm1a_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414
Bob Moore32c9ef92009-02-18 14:36:05 +0800415 /* Insert the SLP_TYP bits */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416
Bob Moored4913dc2009-03-06 10:05:18 +0800417 pm1a_control |= (acpi_gbl_sleep_type_a <<
418 sleep_type_reg_info->bit_position);
419 pm1b_control |= (acpi_gbl_sleep_type_b <<
420 sleep_type_reg_info->bit_position);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421
Bob Moore32c9ef92009-02-18 14:36:05 +0800422 /* Write the control registers and ignore any errors */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423
Bob Moore32c9ef92009-02-18 14:36:05 +0800424 (void)acpi_hw_write_pm1_control(pm1a_control,
425 pm1b_control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 }
427 }
428
Bob Moore2feec472012-02-14 15:00:53 +0800429 acpi_hw_execute_BFS(sleep_state);
Rafael J. Wysockic95d47a2008-01-08 00:05:21 +0100430 return_ACPI_STATUS(status);
431}
432
433/*******************************************************************************
434 *
Bob Moore2feec472012-02-14 15:00:53 +0800435 * FUNCTION: acpi_hw_legacy_wake
Rafael J. Wysockic95d47a2008-01-08 00:05:21 +0100436 *
437 * PARAMETERS: sleep_state - Which sleep state we just exited
438 *
439 * RETURN: Status
440 *
441 * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep
442 * Called with interrupts ENABLED.
443 *
444 ******************************************************************************/
Bob Moore2feec472012-02-14 15:00:53 +0800445
446acpi_status acpi_hw_legacy_wake(u8 sleep_state)
Rafael J. Wysockic95d47a2008-01-08 00:05:21 +0100447{
Rafael J. Wysockic95d47a2008-01-08 00:05:21 +0100448 acpi_status status;
449
Bob Moore2feec472012-02-14 15:00:53 +0800450 ACPI_FUNCTION_TRACE(hw_legacy_wake);
Rafael J. Wysockic95d47a2008-01-08 00:05:21 +0100451
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 /* Ensure enter_sleep_state_prep -> enter_sleep_state ordering */
453
454 acpi_gbl_sleep_type_a = ACPI_SLEEP_TYPE_INVALID;
Bob Moore2feec472012-02-14 15:00:53 +0800455 acpi_hw_execute_SST(ACPI_SST_WAKING);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 /*
Thomas Renninger79d2dfa2007-08-24 01:24:47 -0400458 * GPEs must be enabled before _WAK is called as GPEs
459 * might get fired there
460 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 * Restore the GPEs:
462 * 1) Disable/Clear all GPEs
463 * 2) Enable all runtime GPEs
464 */
Len Brown4be44fc2005-08-05 00:44:28 -0400465 status = acpi_hw_disable_all_gpes();
466 if (ACPI_FAILURE(status)) {
467 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 }
Bob Moore2feec472012-02-14 15:00:53 +0800469
Len Brown4be44fc2005-08-05 00:44:28 -0400470 status = acpi_hw_enable_all_runtime_gpes();
471 if (ACPI_FAILURE(status)) {
472 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 }
474
Bob Moore2feec472012-02-14 15:00:53 +0800475 /*
476 * Now we can execute _WAK, etc. Some machines require that the GPEs
477 * are enabled before the wake methods are executed.
478 */
479 acpi_hw_execute_WAK(sleep_state);
Thomas Renninger79d2dfa2007-08-24 01:24:47 -0400480
Matthew Garretta68823e2008-08-06 19:12:04 +0100481 /*
Bob Moore2feec472012-02-14 15:00:53 +0800482 * Some BIOS code assumes that WAK_STS will be cleared on resume
483 * and use it to determine whether the system is rebooting or
484 * resuming. Clear WAK_STS for compatibility.
Matthew Garretta68823e2008-08-06 19:12:04 +0100485 */
Bob Moore50ffba12009-02-23 15:02:07 +0800486 acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS, 1);
Thomas Renninger79d2dfa2007-08-24 01:24:47 -0400487 acpi_gbl_system_awake_and_running = TRUE;
488
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 /* Enable power button */
490
Len Brown4be44fc2005-08-05 00:44:28 -0400491 (void)
Bob Moore50ffba12009-02-23 15:02:07 +0800492 acpi_write_bit_register(acpi_gbl_fixed_event_info
Bob Moore2feec472012-02-14 15:00:53 +0800493 [ACPI_EVENT_POWER_BUTTON].
494 enable_register_id, ACPI_ENABLE_EVENT);
Robert Moore44f6c012005-04-18 22:49:35 -0400495
Len Brown4be44fc2005-08-05 00:44:28 -0400496 (void)
Bob Moore50ffba12009-02-23 15:02:07 +0800497 acpi_write_bit_register(acpi_gbl_fixed_event_info
Bob Moore2feec472012-02-14 15:00:53 +0800498 [ACPI_EVENT_POWER_BUTTON].
499 status_register_id, ACPI_CLEAR_STATUS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500
Bob Moore2feec472012-02-14 15:00:53 +0800501 /*
502 * Enable BM arbitration. This feature is contained within an
503 * optional register (PM2 Control), so ignore a BAD_ADDRESS
504 * exception.
505 */
506 status = acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 0);
507 if (ACPI_FAILURE(status) && (status != AE_BAD_ADDRESS)) {
508 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 }
510
Bob Moore2feec472012-02-14 15:00:53 +0800511 acpi_hw_execute_SST(ACPI_SST_WORKING);
Len Brown4be44fc2005-08-05 00:44:28 -0400512 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513}
Bob Moore83135242006-10-03 00:00:00 -0400514
Bob Moore2feec472012-02-14 15:00:53 +0800515
516/*******************************************************************************
517 *
518 * FUNCTION: acpi_hw_extended_sleep
519 *
520 * PARAMETERS: sleep_state - Which sleep state to enter
521 *
522 * RETURN: Status
523 *
524 * DESCRIPTION: Enter a system sleep state via the extended FADT sleep
525 * registers (V5 FADT).
526 * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
527 *
528 ******************************************************************************/
529
530acpi_status acpi_hw_extended_sleep(u8 sleep_state)
531{
532 acpi_status status;
533 u8 sleep_type_value;
534 u64 sleep_status;
535
536 ACPI_FUNCTION_TRACE(hw_extended_sleep);
537
538 /* Extended sleep registers must be valid */
539
540 if (!acpi_gbl_FADT.sleep_control.address ||
541 !acpi_gbl_FADT.sleep_status.address) {
542 return_ACPI_STATUS(AE_NOT_EXIST);
543 }
544
545 /* Clear wake status (WAK_STS) */
546
547 status = acpi_write(ACPI_X_WAKE_STATUS, &acpi_gbl_FADT.sleep_status);
548 if (ACPI_FAILURE(status)) {
549 return_ACPI_STATUS(status);
550 }
551
552 acpi_gbl_system_awake_and_running = FALSE;
553
554 /* Execute the _GTS method (Going To Sleep) */
555
556 acpi_hw_execute_GTS(sleep_state);
557
558 /* Flush caches, as per ACPI specification */
559
560 ACPI_FLUSH_CPU_CACHE();
561
562 /*
563 * Set the SLP_TYP and SLP_EN bits.
564 *
565 * Note: We only use the first value returned by the \_Sx method
566 * (acpi_gbl_sleep_type_a) - As per ACPI specification.
567 */
568 ACPI_DEBUG_PRINT((ACPI_DB_INIT,
569 "Entering sleep state [S%u]\n", sleep_state));
570
571 sleep_type_value =
572 ((acpi_gbl_sleep_type_a << ACPI_X_SLEEP_TYPE_POSITION) &
573 ACPI_X_SLEEP_TYPE_MASK);
574
575 status = acpi_write((sleep_type_value | ACPI_X_SLEEP_ENABLE),
576 &acpi_gbl_FADT.sleep_control);
577 if (ACPI_FAILURE(status)) {
578 return_ACPI_STATUS(status);
579 }
580
581 /* Wait for transition back to Working State */
582
583 do {
584 status = acpi_read(&sleep_status, &acpi_gbl_FADT.sleep_status);
585 if (ACPI_FAILURE(status)) {
586 return_ACPI_STATUS(status);
587 }
588
589 } while (!(((u8)sleep_status) & ACPI_X_WAKE_STATUS));
590
591 return_ACPI_STATUS(AE_OK);
592}
593
594/*******************************************************************************
595 *
596 * FUNCTION: acpi_hw_extended_wake_prep
597 *
598 * PARAMETERS: sleep_state - Which sleep state we just exited
599 *
600 * RETURN: Status
601 *
602 * DESCRIPTION: Perform first part of OS-independent ACPI cleanup after
603 * a sleep. Called with interrupts ENABLED.
604 *
605 ******************************************************************************/
606
607acpi_status acpi_hw_extended_wake_prep(u8 sleep_state)
608{
609 acpi_status status;
610 u8 sleep_type_value;
611
612 ACPI_FUNCTION_TRACE(hw_extended_wake_prep);
613
614 status = acpi_get_sleep_type_data(ACPI_STATE_S0,
615 &acpi_gbl_sleep_type_a,
616 &acpi_gbl_sleep_type_b);
617 if (ACPI_SUCCESS(status)) {
618 sleep_type_value =
619 ((acpi_gbl_sleep_type_a << ACPI_X_SLEEP_TYPE_POSITION) &
620 ACPI_X_SLEEP_TYPE_MASK);
621
622 (void)acpi_write((sleep_type_value | ACPI_X_SLEEP_ENABLE),
623 &acpi_gbl_FADT.sleep_control);
624 }
625
626 acpi_hw_execute_BFS(sleep_state);
627 return_ACPI_STATUS(AE_OK);
628}
629
630/*******************************************************************************
631 *
632 * FUNCTION: acpi_hw_extended_wake
633 *
634 * PARAMETERS: sleep_state - Which sleep state we just exited
635 *
636 * RETURN: Status
637 *
638 * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep
639 * Called with interrupts ENABLED.
640 *
641 ******************************************************************************/
642
643acpi_status acpi_hw_extended_wake(u8 sleep_state)
644{
645 ACPI_FUNCTION_TRACE(hw_extended_wake);
646
647 /* Ensure enter_sleep_state_prep -> enter_sleep_state ordering */
648
649 acpi_gbl_sleep_type_a = ACPI_SLEEP_TYPE_INVALID;
650
651 /* Execute the wake methods */
652
653 acpi_hw_execute_SST(ACPI_SST_WAKING);
654 acpi_hw_execute_WAK(sleep_state);
655
656 /*
657 * Some BIOS code assumes that WAK_STS will be cleared on resume
658 * and use it to determine whether the system is rebooting or
659 * resuming. Clear WAK_STS for compatibility.
660 */
661 (void)acpi_write(ACPI_X_WAKE_STATUS, &acpi_gbl_FADT.sleep_status);
662 acpi_gbl_system_awake_and_running = TRUE;
663
664 acpi_hw_execute_SST(ACPI_SST_WORKING);
665 return_ACPI_STATUS(AE_OK);
666}