blob: fa341471c231771462815bb066c8308e7da46ffe [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
Bob Moore33620c52012-02-14 18:14:27 +0800200#if (!ACPI_REDUCED_HARDWARE)
Bob Moore2feec472012-02-14 15:00:53 +0800201/*******************************************************************************
202 *
203 * FUNCTION: acpi_hw_legacy_sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 *
205 * PARAMETERS: sleep_state - Which sleep state to enter
206 *
207 * RETURN: Status
208 *
Bob Moore2feec472012-02-14 15:00:53 +0800209 * DESCRIPTION: Enter a system sleep state via the legacy FADT PM registers
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
211 *
212 ******************************************************************************/
Bob Moore2feec472012-02-14 15:00:53 +0800213
214acpi_status acpi_hw_legacy_sleep(u8 sleep_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215{
Len Brown4be44fc2005-08-05 00:44:28 -0400216 struct acpi_bit_register_info *sleep_type_reg_info;
217 struct acpi_bit_register_info *sleep_enable_reg_info;
Bob Moore2feec472012-02-14 15:00:53 +0800218 u32 pm1a_control;
219 u32 pm1b_control;
Len Brown4be44fc2005-08-05 00:44:28 -0400220 u32 in_value;
221 acpi_status status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222
Bob Moore2feec472012-02-14 15:00:53 +0800223 ACPI_FUNCTION_TRACE(hw_legacy_sleep);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224
Len Brown4be44fc2005-08-05 00:44:28 -0400225 sleep_type_reg_info =
Bob Moore82d79b82009-02-18 14:31:05 +0800226 acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_TYPE);
Len Brown4be44fc2005-08-05 00:44:28 -0400227 sleep_enable_reg_info =
228 acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229
230 /* Clear wake status */
231
Bob Moore768aaaf2009-03-06 09:49:25 +0800232 status =
233 acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS);
Len Brown4be44fc2005-08-05 00:44:28 -0400234 if (ACPI_FAILURE(status)) {
235 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 }
237
238 /* Clear all fixed and general purpose status bits */
239
Bob Moored8c71b62007-02-02 19:48:21 +0300240 status = acpi_hw_clear_acpi_status();
Len Brown4be44fc2005-08-05 00:44:28 -0400241 if (ACPI_FAILURE(status)) {
242 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 }
244
Bob Moore2feec472012-02-14 15:00:53 +0800245 if (sleep_state != ACPI_STATE_S5) {
246 /*
247 * Disable BM arbitration. This feature is contained within an
248 * optional register (PM2 Control), so ignore a BAD_ADDRESS
249 * exception.
250 */
251 status = acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 1);
252 if (ACPI_FAILURE(status) && (status != AE_BAD_ADDRESS)) {
253 return_ACPI_STATUS(status);
254 }
255 }
256
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 /*
Pavel Machek23b168d2008-02-05 19:27:12 +0100258 * 1) Disable/Clear all GPEs
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 * 2) Enable all wakeup GPEs
260 */
Alexey Starikovskiy1d999672007-03-12 14:49:26 -0400261 status = acpi_hw_disable_all_gpes();
262 if (ACPI_FAILURE(status)) {
263 return_ACPI_STATUS(status);
264 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 acpi_gbl_system_awake_and_running = FALSE;
266
Len Brown4be44fc2005-08-05 00:44:28 -0400267 status = acpi_hw_enable_all_wakeup_gpes();
268 if (ACPI_FAILURE(status)) {
269 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 }
271
Bob Moore2feec472012-02-14 15:00:53 +0800272 /* Execute the _GTS method (Going To Sleep) */
Rafael J. Wysockic95d47a2008-01-08 00:05:21 +0100273
Bob Moore2feec472012-02-14 15:00:53 +0800274 acpi_hw_execute_GTS(sleep_state);
Rafael J. Wysockic95d47a2008-01-08 00:05:21 +0100275
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 /* Get current value of PM1A control */
277
Bob Moore32c9ef92009-02-18 14:36:05 +0800278 status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL,
279 &pm1a_control);
Len Brown4be44fc2005-08-05 00:44:28 -0400280 if (ACPI_FAILURE(status)) {
281 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 }
Len Brown4be44fc2005-08-05 00:44:28 -0400283 ACPI_DEBUG_PRINT((ACPI_DB_INIT,
Bob Mooreb27d6592010-05-26 11:47:13 +0800284 "Entering sleep state [S%u]\n", sleep_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285
Bob Moore32c9ef92009-02-18 14:36:05 +0800286 /* Clear the SLP_EN and SLP_TYP fields */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
Bob Moore32c9ef92009-02-18 14:36:05 +0800288 pm1a_control &= ~(sleep_type_reg_info->access_bit_mask |
289 sleep_enable_reg_info->access_bit_mask);
290 pm1b_control = pm1a_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291
Bob Moore32c9ef92009-02-18 14:36:05 +0800292 /* Insert the SLP_TYP bits */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293
Bob Moore32c9ef92009-02-18 14:36:05 +0800294 pm1a_control |=
Len Brown4be44fc2005-08-05 00:44:28 -0400295 (acpi_gbl_sleep_type_a << sleep_type_reg_info->bit_position);
Bob Moore32c9ef92009-02-18 14:36:05 +0800296 pm1b_control |=
Len Brown4be44fc2005-08-05 00:44:28 -0400297 (acpi_gbl_sleep_type_b << sleep_type_reg_info->bit_position);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298
299 /*
300 * We split the writes of SLP_TYP and SLP_EN to workaround
301 * poorly implemented hardware.
302 */
303
Bob Moore32c9ef92009-02-18 14:36:05 +0800304 /* Write #1: write the SLP_TYP data to the PM1 Control registers */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305
Bob Moore32c9ef92009-02-18 14:36:05 +0800306 status = acpi_hw_write_pm1_control(pm1a_control, pm1b_control);
Len Brown4be44fc2005-08-05 00:44:28 -0400307 if (ACPI_FAILURE(status)) {
308 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 }
310
Bob Moore32c9ef92009-02-18 14:36:05 +0800311 /* Insert the sleep enable (SLP_EN) bit */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
Bob Moore32c9ef92009-02-18 14:36:05 +0800313 pm1a_control |= sleep_enable_reg_info->access_bit_mask;
314 pm1b_control |= sleep_enable_reg_info->access_bit_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
Bob Moore32c9ef92009-02-18 14:36:05 +0800316 /* Flush caches, as per ACPI specification */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317
Len Brown4be44fc2005-08-05 00:44:28 -0400318 ACPI_FLUSH_CPU_CACHE();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319
Joseph Cihula86886e52009-06-30 19:31:07 -0700320 tboot_sleep(sleep_state, pm1a_control, pm1b_control);
321
Bob Moore32c9ef92009-02-18 14:36:05 +0800322 /* Write #2: Write both SLP_TYP + SLP_EN */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323
Bob Moore32c9ef92009-02-18 14:36:05 +0800324 status = acpi_hw_write_pm1_control(pm1a_control, pm1b_control);
Len Brown4be44fc2005-08-05 00:44:28 -0400325 if (ACPI_FAILURE(status)) {
326 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 }
328
329 if (sleep_state > ACPI_STATE_S3) {
330 /*
Robert Moore44f6c012005-04-18 22:49:35 -0400331 * We wanted to sleep > S3, but it didn't happen (by virtue of the
332 * fact that we are still executing!)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 *
Robert Moore44f6c012005-04-18 22:49:35 -0400334 * Wait ten seconds, then try again. This is to get S4/S5 to work on
335 * all machines.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 *
Bob Moored4913dc2009-03-06 10:05:18 +0800337 * We wait so long to allow chipsets that poll this reg very slowly
338 * to still read the right value. Ideally, this block would go
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 * away entirely.
340 */
Len Brown4be44fc2005-08-05 00:44:28 -0400341 acpi_os_stall(10000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342
Alexey Starikovskiyd30dc9ab2007-09-30 22:39:36 +0400343 status = acpi_hw_register_write(ACPI_REGISTER_PM1_CONTROL,
Len Brown4be44fc2005-08-05 00:44:28 -0400344 sleep_enable_reg_info->
345 access_bit_mask);
346 if (ACPI_FAILURE(status)) {
347 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 }
349 }
350
Bob Moore2feec472012-02-14 15:00:53 +0800351 /* Wait for transition back to Working State */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352
353 do {
Bob Moore50ffba12009-02-23 15:02:07 +0800354 status =
355 acpi_read_bit_register(ACPI_BITREG_WAKE_STATUS, &in_value);
Len Brown4be44fc2005-08-05 00:44:28 -0400356 if (ACPI_FAILURE(status)) {
357 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 }
Bob Moore2feec472012-02-14 15:00:53 +0800359
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 } while (!in_value);
361
Len Brown4be44fc2005-08-05 00:44:28 -0400362 return_ACPI_STATUS(AE_OK);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364
Robert Moore44f6c012005-04-18 22:49:35 -0400365/*******************************************************************************
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 *
Bob Moore2feec472012-02-14 15:00:53 +0800367 * FUNCTION: acpi_hw_legacy_wake_prep
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 *
Bob Moore2feec472012-02-14 15:00:53 +0800369 * PARAMETERS: sleep_state - Which sleep state we just exited
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 *
371 * RETURN: Status
372 *
Rafael J. Wysockic95d47a2008-01-08 00:05:21 +0100373 * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a
374 * sleep.
Bob Moore2feec472012-02-14 15:00:53 +0800375 * Called with interrupts ENABLED.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 *
377 ******************************************************************************/
Bob Moore2feec472012-02-14 15:00:53 +0800378
379acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380{
Len Brown4be44fc2005-08-05 00:44:28 -0400381 acpi_status status;
382 struct acpi_bit_register_info *sleep_type_reg_info;
383 struct acpi_bit_register_info *sleep_enable_reg_info;
Bob Moore32c9ef92009-02-18 14:36:05 +0800384 u32 pm1a_control;
385 u32 pm1b_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386
Bob Moore2feec472012-02-14 15:00:53 +0800387 ACPI_FUNCTION_TRACE(hw_legacy_wake_prep);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388
389 /*
390 * Set SLP_TYPE and SLP_EN to state S0.
391 * This is unclear from the ACPI Spec, but it is required
392 * by some machines.
393 */
Len Brown4be44fc2005-08-05 00:44:28 -0400394 status = acpi_get_sleep_type_data(ACPI_STATE_S0,
395 &acpi_gbl_sleep_type_a,
396 &acpi_gbl_sleep_type_b);
397 if (ACPI_SUCCESS(status)) {
398 sleep_type_reg_info =
Bob Moore82d79b82009-02-18 14:31:05 +0800399 acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_TYPE);
Len Brown4be44fc2005-08-05 00:44:28 -0400400 sleep_enable_reg_info =
401 acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402
403 /* Get current value of PM1A control */
404
Alexey Starikovskiyd30dc9ab2007-09-30 22:39:36 +0400405 status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL,
Bob Moore32c9ef92009-02-18 14:36:05 +0800406 &pm1a_control);
Len Brown4be44fc2005-08-05 00:44:28 -0400407 if (ACPI_SUCCESS(status)) {
Bob Moore52fc0b02006-10-02 00:00:00 -0400408
Bob Moore32c9ef92009-02-18 14:36:05 +0800409 /* Clear the SLP_EN and SLP_TYP fields */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410
Bob Moore32c9ef92009-02-18 14:36:05 +0800411 pm1a_control &= ~(sleep_type_reg_info->access_bit_mask |
412 sleep_enable_reg_info->
413 access_bit_mask);
414 pm1b_control = pm1a_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415
Bob Moore32c9ef92009-02-18 14:36:05 +0800416 /* Insert the SLP_TYP bits */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417
Bob Moored4913dc2009-03-06 10:05:18 +0800418 pm1a_control |= (acpi_gbl_sleep_type_a <<
419 sleep_type_reg_info->bit_position);
420 pm1b_control |= (acpi_gbl_sleep_type_b <<
421 sleep_type_reg_info->bit_position);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422
Bob Moore32c9ef92009-02-18 14:36:05 +0800423 /* Write the control registers and ignore any errors */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424
Bob Moore32c9ef92009-02-18 14:36:05 +0800425 (void)acpi_hw_write_pm1_control(pm1a_control,
426 pm1b_control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 }
428 }
429
Bob Moore2feec472012-02-14 15:00:53 +0800430 acpi_hw_execute_BFS(sleep_state);
Rafael J. Wysockic95d47a2008-01-08 00:05:21 +0100431 return_ACPI_STATUS(status);
432}
433
434/*******************************************************************************
435 *
Bob Moore2feec472012-02-14 15:00:53 +0800436 * FUNCTION: acpi_hw_legacy_wake
Rafael J. Wysockic95d47a2008-01-08 00:05:21 +0100437 *
438 * PARAMETERS: sleep_state - Which sleep state we just exited
439 *
440 * RETURN: Status
441 *
442 * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep
443 * Called with interrupts ENABLED.
444 *
445 ******************************************************************************/
Bob Moore2feec472012-02-14 15:00:53 +0800446
447acpi_status acpi_hw_legacy_wake(u8 sleep_state)
Rafael J. Wysockic95d47a2008-01-08 00:05:21 +0100448{
Rafael J. Wysockic95d47a2008-01-08 00:05:21 +0100449 acpi_status status;
450
Bob Moore2feec472012-02-14 15:00:53 +0800451 ACPI_FUNCTION_TRACE(hw_legacy_wake);
Rafael J. Wysockic95d47a2008-01-08 00:05:21 +0100452
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 /* Ensure enter_sleep_state_prep -> enter_sleep_state ordering */
454
455 acpi_gbl_sleep_type_a = ACPI_SLEEP_TYPE_INVALID;
Bob Moore2feec472012-02-14 15:00:53 +0800456 acpi_hw_execute_SST(ACPI_SST_WAKING);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 /*
Thomas Renninger79d2dfa2007-08-24 01:24:47 -0400459 * GPEs must be enabled before _WAK is called as GPEs
460 * might get fired there
461 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 * Restore the GPEs:
463 * 1) Disable/Clear all GPEs
464 * 2) Enable all runtime GPEs
465 */
Len Brown4be44fc2005-08-05 00:44:28 -0400466 status = acpi_hw_disable_all_gpes();
467 if (ACPI_FAILURE(status)) {
468 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 }
Bob Moore2feec472012-02-14 15:00:53 +0800470
Len Brown4be44fc2005-08-05 00:44:28 -0400471 status = acpi_hw_enable_all_runtime_gpes();
472 if (ACPI_FAILURE(status)) {
473 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 }
475
Bob Moore2feec472012-02-14 15:00:53 +0800476 /*
477 * Now we can execute _WAK, etc. Some machines require that the GPEs
478 * are enabled before the wake methods are executed.
479 */
480 acpi_hw_execute_WAK(sleep_state);
Thomas Renninger79d2dfa2007-08-24 01:24:47 -0400481
Matthew Garretta68823e2008-08-06 19:12:04 +0100482 /*
Bob Moore2feec472012-02-14 15:00:53 +0800483 * Some BIOS code assumes that WAK_STS will be cleared on resume
484 * and use it to determine whether the system is rebooting or
485 * resuming. Clear WAK_STS for compatibility.
Matthew Garretta68823e2008-08-06 19:12:04 +0100486 */
Bob Moore50ffba12009-02-23 15:02:07 +0800487 acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS, 1);
Thomas Renninger79d2dfa2007-08-24 01:24:47 -0400488 acpi_gbl_system_awake_and_running = TRUE;
489
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 /* Enable power button */
491
Len Brown4be44fc2005-08-05 00:44:28 -0400492 (void)
Bob Moore50ffba12009-02-23 15:02:07 +0800493 acpi_write_bit_register(acpi_gbl_fixed_event_info
Bob Moore2feec472012-02-14 15:00:53 +0800494 [ACPI_EVENT_POWER_BUTTON].
495 enable_register_id, ACPI_ENABLE_EVENT);
Robert Moore44f6c012005-04-18 22:49:35 -0400496
Len Brown4be44fc2005-08-05 00:44:28 -0400497 (void)
Bob Moore50ffba12009-02-23 15:02:07 +0800498 acpi_write_bit_register(acpi_gbl_fixed_event_info
Bob Moore2feec472012-02-14 15:00:53 +0800499 [ACPI_EVENT_POWER_BUTTON].
500 status_register_id, ACPI_CLEAR_STATUS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501
Bob Moore2feec472012-02-14 15:00:53 +0800502 /*
503 * Enable BM arbitration. This feature is contained within an
504 * optional register (PM2 Control), so ignore a BAD_ADDRESS
505 * exception.
506 */
507 status = acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 0);
508 if (ACPI_FAILURE(status) && (status != AE_BAD_ADDRESS)) {
509 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 }
511
Bob Moore2feec472012-02-14 15:00:53 +0800512 acpi_hw_execute_SST(ACPI_SST_WORKING);
Len Brown4be44fc2005-08-05 00:44:28 -0400513 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514}
Bob Moore83135242006-10-03 00:00:00 -0400515
Bob Moore33620c52012-02-14 18:14:27 +0800516#endif /* !ACPI_REDUCED_HARDWARE */
Bob Moore2feec472012-02-14 15:00:53 +0800517
518/*******************************************************************************
519 *
520 * FUNCTION: acpi_hw_extended_sleep
521 *
522 * PARAMETERS: sleep_state - Which sleep state to enter
523 *
524 * RETURN: Status
525 *
526 * DESCRIPTION: Enter a system sleep state via the extended FADT sleep
527 * registers (V5 FADT).
528 * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
529 *
530 ******************************************************************************/
531
532acpi_status acpi_hw_extended_sleep(u8 sleep_state)
533{
534 acpi_status status;
535 u8 sleep_type_value;
536 u64 sleep_status;
537
538 ACPI_FUNCTION_TRACE(hw_extended_sleep);
539
540 /* Extended sleep registers must be valid */
541
542 if (!acpi_gbl_FADT.sleep_control.address ||
543 !acpi_gbl_FADT.sleep_status.address) {
544 return_ACPI_STATUS(AE_NOT_EXIST);
545 }
546
547 /* Clear wake status (WAK_STS) */
548
549 status = acpi_write(ACPI_X_WAKE_STATUS, &acpi_gbl_FADT.sleep_status);
550 if (ACPI_FAILURE(status)) {
551 return_ACPI_STATUS(status);
552 }
553
554 acpi_gbl_system_awake_and_running = FALSE;
555
556 /* Execute the _GTS method (Going To Sleep) */
557
558 acpi_hw_execute_GTS(sleep_state);
559
560 /* Flush caches, as per ACPI specification */
561
562 ACPI_FLUSH_CPU_CACHE();
563
564 /*
565 * Set the SLP_TYP and SLP_EN bits.
566 *
567 * Note: We only use the first value returned by the \_Sx method
568 * (acpi_gbl_sleep_type_a) - As per ACPI specification.
569 */
570 ACPI_DEBUG_PRINT((ACPI_DB_INIT,
571 "Entering sleep state [S%u]\n", sleep_state));
572
573 sleep_type_value =
574 ((acpi_gbl_sleep_type_a << ACPI_X_SLEEP_TYPE_POSITION) &
575 ACPI_X_SLEEP_TYPE_MASK);
576
577 status = acpi_write((sleep_type_value | ACPI_X_SLEEP_ENABLE),
578 &acpi_gbl_FADT.sleep_control);
579 if (ACPI_FAILURE(status)) {
580 return_ACPI_STATUS(status);
581 }
582
583 /* Wait for transition back to Working State */
584
585 do {
586 status = acpi_read(&sleep_status, &acpi_gbl_FADT.sleep_status);
587 if (ACPI_FAILURE(status)) {
588 return_ACPI_STATUS(status);
589 }
590
591 } while (!(((u8)sleep_status) & ACPI_X_WAKE_STATUS));
592
593 return_ACPI_STATUS(AE_OK);
594}
595
596/*******************************************************************************
597 *
598 * FUNCTION: acpi_hw_extended_wake_prep
599 *
600 * PARAMETERS: sleep_state - Which sleep state we just exited
601 *
602 * RETURN: Status
603 *
604 * DESCRIPTION: Perform first part of OS-independent ACPI cleanup after
605 * a sleep. Called with interrupts ENABLED.
606 *
607 ******************************************************************************/
608
609acpi_status acpi_hw_extended_wake_prep(u8 sleep_state)
610{
611 acpi_status status;
612 u8 sleep_type_value;
613
614 ACPI_FUNCTION_TRACE(hw_extended_wake_prep);
615
616 status = acpi_get_sleep_type_data(ACPI_STATE_S0,
617 &acpi_gbl_sleep_type_a,
618 &acpi_gbl_sleep_type_b);
619 if (ACPI_SUCCESS(status)) {
620 sleep_type_value =
621 ((acpi_gbl_sleep_type_a << ACPI_X_SLEEP_TYPE_POSITION) &
622 ACPI_X_SLEEP_TYPE_MASK);
623
624 (void)acpi_write((sleep_type_value | ACPI_X_SLEEP_ENABLE),
625 &acpi_gbl_FADT.sleep_control);
626 }
627
628 acpi_hw_execute_BFS(sleep_state);
629 return_ACPI_STATUS(AE_OK);
630}
631
632/*******************************************************************************
633 *
634 * FUNCTION: acpi_hw_extended_wake
635 *
636 * PARAMETERS: sleep_state - Which sleep state we just exited
637 *
638 * RETURN: Status
639 *
640 * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep
641 * Called with interrupts ENABLED.
642 *
643 ******************************************************************************/
644
645acpi_status acpi_hw_extended_wake(u8 sleep_state)
646{
647 ACPI_FUNCTION_TRACE(hw_extended_wake);
648
649 /* Ensure enter_sleep_state_prep -> enter_sleep_state ordering */
650
651 acpi_gbl_sleep_type_a = ACPI_SLEEP_TYPE_INVALID;
652
653 /* Execute the wake methods */
654
655 acpi_hw_execute_SST(ACPI_SST_WAKING);
656 acpi_hw_execute_WAK(sleep_state);
657
658 /*
659 * Some BIOS code assumes that WAK_STS will be cleared on resume
660 * and use it to determine whether the system is rebooting or
661 * resuming. Clear WAK_STS for compatibility.
662 */
663 (void)acpi_write(ACPI_X_WAKE_STATUS, &acpi_gbl_FADT.sleep_status);
664 acpi_gbl_system_awake_and_running = TRUE;
665
666 acpi_hw_execute_SST(ACPI_SST_WORKING);
667 return_ACPI_STATUS(AE_OK);
668}