blob: abe65ff4231e5e73650e79cb820cfd09277afd1b [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
Len Brown96f15ef2009-04-17 23:32:20 -040052static unsigned int gts, bfs;
53module_param(gts, uint, 0644);
54module_param(bfs, uint, 0644);
55MODULE_PARM_DESC(gts, "Enable evaluation of _GTS on suspend.");
56MODULE_PARM_DESC(bfs, "Enable evaluation of _BFS on resume".);
57
Robert Moore44f6c012005-04-18 22:49:35 -040058/*******************************************************************************
Linus Torvalds1da177e2005-04-16 15:20:36 -070059 *
Bob Mooref99648b2012-02-14 18:43:03 +080060 * FUNCTION: acpi_hw_execute_sleep_method
Bob Moore2feec472012-02-14 15:00:53 +080061 *
Bob Mooref99648b2012-02-14 18:43:03 +080062 * PARAMETERS: method_name - Pathname of method to execute
63 * integer_argument - Argument to pass to the method
Bob Moore2feec472012-02-14 15:00:53 +080064 *
65 * RETURN: None
66 *
Bob Mooref99648b2012-02-14 18:43:03 +080067 * DESCRIPTION: Execute a sleep/wake related method, with one integer argument
68 * and no return value.
Bob Moore2feec472012-02-14 15:00:53 +080069 *
70 ******************************************************************************/
Bob Mooref99648b2012-02-14 18:43:03 +080071void acpi_hw_execute_sleep_method(char *method_name, u32 integer_argument)
Bob Moore2feec472012-02-14 15:00:53 +080072{
73 struct acpi_object_list arg_list;
74 union acpi_object arg;
75 acpi_status status;
76
Bob Mooref99648b2012-02-14 18:43:03 +080077 ACPI_FUNCTION_TRACE(hw_execute_sleep_method);
Bob Moore2feec472012-02-14 15:00:53 +080078
Bob Mooref99648b2012-02-14 18:43:03 +080079 if (!ACPI_STRCMP(METHOD_NAME__GTS, method_name) && !gts)
80 return_VOID;
81
82 if (!ACPI_STRCMP(METHOD_NAME__BFS, method_name) && !bfs)
83 return_VOID;
84
85 /* One argument, integer_argument */
Bob Moore2feec472012-02-14 15:00:53 +080086
87 arg_list.count = 1;
88 arg_list.pointer = &arg;
89 arg.type = ACPI_TYPE_INTEGER;
Bob Mooref99648b2012-02-14 18:43:03 +080090 arg.integer.value = (u64)integer_argument;
Bob Moore2feec472012-02-14 15:00:53 +080091
Bob Mooref99648b2012-02-14 18:43:03 +080092 status = acpi_evaluate_object(NULL, method_name, &arg_list, NULL);
Bob Moore2feec472012-02-14 15:00:53 +080093 if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
Bob Mooref99648b2012-02-14 18:43:03 +080094 ACPI_EXCEPTION((AE_INFO, status, "While executing method %s",
95 method_name));
Bob Moore2feec472012-02-14 15:00:53 +080096 }
Bob Moore2feec472012-02-14 15:00:53 +080097
Bob Mooref99648b2012-02-14 18:43:03 +080098 return_VOID;
Bob Moore2feec472012-02-14 15:00:53 +080099}
100
Bob Moore33620c52012-02-14 18:14:27 +0800101#if (!ACPI_REDUCED_HARDWARE)
Bob Moore2feec472012-02-14 15:00:53 +0800102/*******************************************************************************
103 *
104 * FUNCTION: acpi_hw_legacy_sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 *
106 * PARAMETERS: sleep_state - Which sleep state to enter
107 *
108 * RETURN: Status
109 *
Bob Moore2feec472012-02-14 15:00:53 +0800110 * DESCRIPTION: Enter a system sleep state via the legacy FADT PM registers
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
112 *
113 ******************************************************************************/
Bob Moore2feec472012-02-14 15:00:53 +0800114
115acpi_status acpi_hw_legacy_sleep(u8 sleep_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116{
Len Brown4be44fc2005-08-05 00:44:28 -0400117 struct acpi_bit_register_info *sleep_type_reg_info;
118 struct acpi_bit_register_info *sleep_enable_reg_info;
Bob Moore2feec472012-02-14 15:00:53 +0800119 u32 pm1a_control;
120 u32 pm1b_control;
Len Brown4be44fc2005-08-05 00:44:28 -0400121 u32 in_value;
122 acpi_status status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123
Bob Moore2feec472012-02-14 15:00:53 +0800124 ACPI_FUNCTION_TRACE(hw_legacy_sleep);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125
Len Brown4be44fc2005-08-05 00:44:28 -0400126 sleep_type_reg_info =
Bob Moore82d79b82009-02-18 14:31:05 +0800127 acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_TYPE);
Len Brown4be44fc2005-08-05 00:44:28 -0400128 sleep_enable_reg_info =
129 acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130
131 /* Clear wake status */
132
Bob Moore768aaaf2009-03-06 09:49:25 +0800133 status =
134 acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS);
Len Brown4be44fc2005-08-05 00:44:28 -0400135 if (ACPI_FAILURE(status)) {
136 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 }
138
139 /* Clear all fixed and general purpose status bits */
140
Bob Moored8c71b62007-02-02 19:48:21 +0300141 status = acpi_hw_clear_acpi_status();
Len Brown4be44fc2005-08-05 00:44:28 -0400142 if (ACPI_FAILURE(status)) {
143 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144 }
145
Bob Moore2feec472012-02-14 15:00:53 +0800146 if (sleep_state != ACPI_STATE_S5) {
147 /*
148 * Disable BM arbitration. This feature is contained within an
149 * optional register (PM2 Control), so ignore a BAD_ADDRESS
150 * exception.
151 */
152 status = acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 1);
153 if (ACPI_FAILURE(status) && (status != AE_BAD_ADDRESS)) {
154 return_ACPI_STATUS(status);
155 }
156 }
157
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 /*
Pavel Machek23b168d2008-02-05 19:27:12 +0100159 * 1) Disable/Clear all GPEs
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 * 2) Enable all wakeup GPEs
161 */
Alexey Starikovskiy1d999672007-03-12 14:49:26 -0400162 status = acpi_hw_disable_all_gpes();
163 if (ACPI_FAILURE(status)) {
164 return_ACPI_STATUS(status);
165 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 acpi_gbl_system_awake_and_running = FALSE;
167
Len Brown4be44fc2005-08-05 00:44:28 -0400168 status = acpi_hw_enable_all_wakeup_gpes();
169 if (ACPI_FAILURE(status)) {
170 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 }
172
Bob Moore2feec472012-02-14 15:00:53 +0800173 /* Execute the _GTS method (Going To Sleep) */
Rafael J. Wysockic95d47a2008-01-08 00:05:21 +0100174
Bob Mooref99648b2012-02-14 18:43:03 +0800175 acpi_hw_execute_sleep_method(METHOD_NAME__GTS, sleep_state);
Rafael J. Wysockic95d47a2008-01-08 00:05:21 +0100176
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 /* Get current value of PM1A control */
178
Bob Moore32c9ef92009-02-18 14:36:05 +0800179 status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL,
180 &pm1a_control);
Len Brown4be44fc2005-08-05 00:44:28 -0400181 if (ACPI_FAILURE(status)) {
182 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 }
Len Brown4be44fc2005-08-05 00:44:28 -0400184 ACPI_DEBUG_PRINT((ACPI_DB_INIT,
Bob Mooreb27d6592010-05-26 11:47:13 +0800185 "Entering sleep state [S%u]\n", sleep_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186
Bob Moore32c9ef92009-02-18 14:36:05 +0800187 /* Clear the SLP_EN and SLP_TYP fields */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188
Bob Moore32c9ef92009-02-18 14:36:05 +0800189 pm1a_control &= ~(sleep_type_reg_info->access_bit_mask |
190 sleep_enable_reg_info->access_bit_mask);
191 pm1b_control = pm1a_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192
Bob Moore32c9ef92009-02-18 14:36:05 +0800193 /* Insert the SLP_TYP bits */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
Bob Moore32c9ef92009-02-18 14:36:05 +0800195 pm1a_control |=
Len Brown4be44fc2005-08-05 00:44:28 -0400196 (acpi_gbl_sleep_type_a << sleep_type_reg_info->bit_position);
Bob Moore32c9ef92009-02-18 14:36:05 +0800197 pm1b_control |=
Len Brown4be44fc2005-08-05 00:44:28 -0400198 (acpi_gbl_sleep_type_b << sleep_type_reg_info->bit_position);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199
200 /*
201 * We split the writes of SLP_TYP and SLP_EN to workaround
202 * poorly implemented hardware.
203 */
204
Bob Moore32c9ef92009-02-18 14:36:05 +0800205 /* Write #1: write the SLP_TYP data to the PM1 Control registers */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206
Bob Moore32c9ef92009-02-18 14:36:05 +0800207 status = acpi_hw_write_pm1_control(pm1a_control, pm1b_control);
Len Brown4be44fc2005-08-05 00:44:28 -0400208 if (ACPI_FAILURE(status)) {
209 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 }
211
Bob Moore32c9ef92009-02-18 14:36:05 +0800212 /* Insert the sleep enable (SLP_EN) bit */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213
Bob Moore32c9ef92009-02-18 14:36:05 +0800214 pm1a_control |= sleep_enable_reg_info->access_bit_mask;
215 pm1b_control |= sleep_enable_reg_info->access_bit_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216
Bob Moore32c9ef92009-02-18 14:36:05 +0800217 /* Flush caches, as per ACPI specification */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218
Len Brown4be44fc2005-08-05 00:44:28 -0400219 ACPI_FLUSH_CPU_CACHE();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220
Joseph Cihula86886e52009-06-30 19:31:07 -0700221 tboot_sleep(sleep_state, pm1a_control, pm1b_control);
222
Bob Moore32c9ef92009-02-18 14:36:05 +0800223 /* Write #2: Write both SLP_TYP + SLP_EN */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224
Bob Moore32c9ef92009-02-18 14:36:05 +0800225 status = acpi_hw_write_pm1_control(pm1a_control, pm1b_control);
Len Brown4be44fc2005-08-05 00:44:28 -0400226 if (ACPI_FAILURE(status)) {
227 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 }
229
230 if (sleep_state > ACPI_STATE_S3) {
231 /*
Robert Moore44f6c012005-04-18 22:49:35 -0400232 * We wanted to sleep > S3, but it didn't happen (by virtue of the
233 * fact that we are still executing!)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 *
Robert Moore44f6c012005-04-18 22:49:35 -0400235 * Wait ten seconds, then try again. This is to get S4/S5 to work on
236 * all machines.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 *
Bob Moored4913dc2009-03-06 10:05:18 +0800238 * We wait so long to allow chipsets that poll this reg very slowly
239 * to still read the right value. Ideally, this block would go
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 * away entirely.
241 */
Len Brown4be44fc2005-08-05 00:44:28 -0400242 acpi_os_stall(10000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243
Alexey Starikovskiyd30dc9ab2007-09-30 22:39:36 +0400244 status = acpi_hw_register_write(ACPI_REGISTER_PM1_CONTROL,
Len Brown4be44fc2005-08-05 00:44:28 -0400245 sleep_enable_reg_info->
246 access_bit_mask);
247 if (ACPI_FAILURE(status)) {
248 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 }
250 }
251
Bob Moore2feec472012-02-14 15:00:53 +0800252 /* Wait for transition back to Working State */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253
254 do {
Bob Moore50ffba12009-02-23 15:02:07 +0800255 status =
256 acpi_read_bit_register(ACPI_BITREG_WAKE_STATUS, &in_value);
Len Brown4be44fc2005-08-05 00:44:28 -0400257 if (ACPI_FAILURE(status)) {
258 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 }
Bob Moore2feec472012-02-14 15:00:53 +0800260
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 } while (!in_value);
262
Len Brown4be44fc2005-08-05 00:44:28 -0400263 return_ACPI_STATUS(AE_OK);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265
Robert Moore44f6c012005-04-18 22:49:35 -0400266/*******************************************************************************
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 *
Bob Moore2feec472012-02-14 15:00:53 +0800268 * FUNCTION: acpi_hw_legacy_wake_prep
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 *
Bob Moore2feec472012-02-14 15:00:53 +0800270 * PARAMETERS: sleep_state - Which sleep state we just exited
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 *
272 * RETURN: Status
273 *
Rafael J. Wysockic95d47a2008-01-08 00:05:21 +0100274 * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a
275 * sleep.
Bob Moore2feec472012-02-14 15:00:53 +0800276 * Called with interrupts ENABLED.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 *
278 ******************************************************************************/
Bob Moore2feec472012-02-14 15:00:53 +0800279
280acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281{
Len Brown4be44fc2005-08-05 00:44:28 -0400282 acpi_status status;
283 struct acpi_bit_register_info *sleep_type_reg_info;
284 struct acpi_bit_register_info *sleep_enable_reg_info;
Bob Moore32c9ef92009-02-18 14:36:05 +0800285 u32 pm1a_control;
286 u32 pm1b_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
Bob Moore2feec472012-02-14 15:00:53 +0800288 ACPI_FUNCTION_TRACE(hw_legacy_wake_prep);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289
290 /*
291 * Set SLP_TYPE and SLP_EN to state S0.
292 * This is unclear from the ACPI Spec, but it is required
293 * by some machines.
294 */
Len Brown4be44fc2005-08-05 00:44:28 -0400295 status = acpi_get_sleep_type_data(ACPI_STATE_S0,
296 &acpi_gbl_sleep_type_a,
297 &acpi_gbl_sleep_type_b);
298 if (ACPI_SUCCESS(status)) {
299 sleep_type_reg_info =
Bob Moore82d79b82009-02-18 14:31:05 +0800300 acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_TYPE);
Len Brown4be44fc2005-08-05 00:44:28 -0400301 sleep_enable_reg_info =
302 acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303
304 /* Get current value of PM1A control */
305
Alexey Starikovskiyd30dc9ab2007-09-30 22:39:36 +0400306 status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL,
Bob Moore32c9ef92009-02-18 14:36:05 +0800307 &pm1a_control);
Len Brown4be44fc2005-08-05 00:44:28 -0400308 if (ACPI_SUCCESS(status)) {
Bob Moore52fc0b02006-10-02 00:00:00 -0400309
Bob Moore32c9ef92009-02-18 14:36:05 +0800310 /* Clear the SLP_EN and SLP_TYP fields */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
Bob Moore32c9ef92009-02-18 14:36:05 +0800312 pm1a_control &= ~(sleep_type_reg_info->access_bit_mask |
313 sleep_enable_reg_info->
314 access_bit_mask);
315 pm1b_control = pm1a_control;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
Bob Moore32c9ef92009-02-18 14:36:05 +0800317 /* Insert the SLP_TYP bits */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
Bob Moored4913dc2009-03-06 10:05:18 +0800319 pm1a_control |= (acpi_gbl_sleep_type_a <<
320 sleep_type_reg_info->bit_position);
321 pm1b_control |= (acpi_gbl_sleep_type_b <<
322 sleep_type_reg_info->bit_position);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323
Bob Moore32c9ef92009-02-18 14:36:05 +0800324 /* Write the control registers and ignore any errors */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325
Bob Moore32c9ef92009-02-18 14:36:05 +0800326 (void)acpi_hw_write_pm1_control(pm1a_control,
327 pm1b_control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 }
329 }
330
Bob Mooref99648b2012-02-14 18:43:03 +0800331 acpi_hw_execute_sleep_method(METHOD_NAME__BFS, sleep_state);
Rafael J. Wysockic95d47a2008-01-08 00:05:21 +0100332 return_ACPI_STATUS(status);
333}
334
335/*******************************************************************************
336 *
Bob Moore2feec472012-02-14 15:00:53 +0800337 * FUNCTION: acpi_hw_legacy_wake
Rafael J. Wysockic95d47a2008-01-08 00:05:21 +0100338 *
339 * PARAMETERS: sleep_state - Which sleep state we just exited
340 *
341 * RETURN: Status
342 *
343 * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep
344 * Called with interrupts ENABLED.
345 *
346 ******************************************************************************/
Bob Moore2feec472012-02-14 15:00:53 +0800347
348acpi_status acpi_hw_legacy_wake(u8 sleep_state)
Rafael J. Wysockic95d47a2008-01-08 00:05:21 +0100349{
Rafael J. Wysockic95d47a2008-01-08 00:05:21 +0100350 acpi_status status;
351
Bob Moore2feec472012-02-14 15:00:53 +0800352 ACPI_FUNCTION_TRACE(hw_legacy_wake);
Rafael J. Wysockic95d47a2008-01-08 00:05:21 +0100353
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 /* Ensure enter_sleep_state_prep -> enter_sleep_state ordering */
355
356 acpi_gbl_sleep_type_a = ACPI_SLEEP_TYPE_INVALID;
Bob Mooref99648b2012-02-14 18:43:03 +0800357 acpi_hw_execute_sleep_method(METHOD_NAME__SST, ACPI_SST_WAKING);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 /*
Thomas Renninger79d2dfa2007-08-24 01:24:47 -0400360 * GPEs must be enabled before _WAK is called as GPEs
361 * might get fired there
362 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 * Restore the GPEs:
364 * 1) Disable/Clear all GPEs
365 * 2) Enable all runtime GPEs
366 */
Len Brown4be44fc2005-08-05 00:44:28 -0400367 status = acpi_hw_disable_all_gpes();
368 if (ACPI_FAILURE(status)) {
369 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 }
Bob Moore2feec472012-02-14 15:00:53 +0800371
Len Brown4be44fc2005-08-05 00:44:28 -0400372 status = acpi_hw_enable_all_runtime_gpes();
373 if (ACPI_FAILURE(status)) {
374 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 }
376
Bob Moore2feec472012-02-14 15:00:53 +0800377 /*
378 * Now we can execute _WAK, etc. Some machines require that the GPEs
379 * are enabled before the wake methods are executed.
380 */
Bob Mooref99648b2012-02-14 18:43:03 +0800381 acpi_hw_execute_sleep_method(METHOD_NAME__WAK, sleep_state);
Thomas Renninger79d2dfa2007-08-24 01:24:47 -0400382
Matthew Garretta68823e2008-08-06 19:12:04 +0100383 /*
Bob Moore2feec472012-02-14 15:00:53 +0800384 * Some BIOS code assumes that WAK_STS will be cleared on resume
385 * and use it to determine whether the system is rebooting or
386 * resuming. Clear WAK_STS for compatibility.
Matthew Garretta68823e2008-08-06 19:12:04 +0100387 */
Bob Moore50ffba12009-02-23 15:02:07 +0800388 acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS, 1);
Thomas Renninger79d2dfa2007-08-24 01:24:47 -0400389 acpi_gbl_system_awake_and_running = TRUE;
390
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 /* Enable power button */
392
Len Brown4be44fc2005-08-05 00:44:28 -0400393 (void)
Bob Moore50ffba12009-02-23 15:02:07 +0800394 acpi_write_bit_register(acpi_gbl_fixed_event_info
Bob Moore2feec472012-02-14 15:00:53 +0800395 [ACPI_EVENT_POWER_BUTTON].
396 enable_register_id, ACPI_ENABLE_EVENT);
Robert Moore44f6c012005-04-18 22:49:35 -0400397
Len Brown4be44fc2005-08-05 00:44:28 -0400398 (void)
Bob Moore50ffba12009-02-23 15:02:07 +0800399 acpi_write_bit_register(acpi_gbl_fixed_event_info
Bob Moore2feec472012-02-14 15:00:53 +0800400 [ACPI_EVENT_POWER_BUTTON].
401 status_register_id, ACPI_CLEAR_STATUS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402
Bob Moore2feec472012-02-14 15:00:53 +0800403 /*
404 * Enable BM arbitration. This feature is contained within an
405 * optional register (PM2 Control), so ignore a BAD_ADDRESS
406 * exception.
407 */
408 status = acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 0);
409 if (ACPI_FAILURE(status) && (status != AE_BAD_ADDRESS)) {
410 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 }
412
Bob Mooref99648b2012-02-14 18:43:03 +0800413 acpi_hw_execute_sleep_method(METHOD_NAME__SST, ACPI_SST_WORKING);
Len Brown4be44fc2005-08-05 00:44:28 -0400414 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415}
Bob Moore83135242006-10-03 00:00:00 -0400416
Bob Moore33620c52012-02-14 18:14:27 +0800417#endif /* !ACPI_REDUCED_HARDWARE */
Bob Moore2feec472012-02-14 15:00:53 +0800418
419/*******************************************************************************
420 *
421 * FUNCTION: acpi_hw_extended_sleep
422 *
423 * PARAMETERS: sleep_state - Which sleep state to enter
424 *
425 * RETURN: Status
426 *
427 * DESCRIPTION: Enter a system sleep state via the extended FADT sleep
428 * registers (V5 FADT).
429 * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
430 *
431 ******************************************************************************/
432
433acpi_status acpi_hw_extended_sleep(u8 sleep_state)
434{
435 acpi_status status;
436 u8 sleep_type_value;
437 u64 sleep_status;
438
439 ACPI_FUNCTION_TRACE(hw_extended_sleep);
440
441 /* Extended sleep registers must be valid */
442
443 if (!acpi_gbl_FADT.sleep_control.address ||
444 !acpi_gbl_FADT.sleep_status.address) {
445 return_ACPI_STATUS(AE_NOT_EXIST);
446 }
447
448 /* Clear wake status (WAK_STS) */
449
450 status = acpi_write(ACPI_X_WAKE_STATUS, &acpi_gbl_FADT.sleep_status);
451 if (ACPI_FAILURE(status)) {
452 return_ACPI_STATUS(status);
453 }
454
455 acpi_gbl_system_awake_and_running = FALSE;
456
457 /* Execute the _GTS method (Going To Sleep) */
458
Bob Mooref99648b2012-02-14 18:43:03 +0800459 acpi_hw_execute_sleep_method(METHOD_NAME__GTS, sleep_state);
Bob Moore2feec472012-02-14 15:00:53 +0800460
461 /* Flush caches, as per ACPI specification */
462
463 ACPI_FLUSH_CPU_CACHE();
464
465 /*
466 * Set the SLP_TYP and SLP_EN bits.
467 *
468 * Note: We only use the first value returned by the \_Sx method
469 * (acpi_gbl_sleep_type_a) - As per ACPI specification.
470 */
471 ACPI_DEBUG_PRINT((ACPI_DB_INIT,
472 "Entering sleep state [S%u]\n", sleep_state));
473
474 sleep_type_value =
475 ((acpi_gbl_sleep_type_a << ACPI_X_SLEEP_TYPE_POSITION) &
476 ACPI_X_SLEEP_TYPE_MASK);
477
478 status = acpi_write((sleep_type_value | ACPI_X_SLEEP_ENABLE),
479 &acpi_gbl_FADT.sleep_control);
480 if (ACPI_FAILURE(status)) {
481 return_ACPI_STATUS(status);
482 }
483
484 /* Wait for transition back to Working State */
485
486 do {
487 status = acpi_read(&sleep_status, &acpi_gbl_FADT.sleep_status);
488 if (ACPI_FAILURE(status)) {
489 return_ACPI_STATUS(status);
490 }
491
492 } while (!(((u8)sleep_status) & ACPI_X_WAKE_STATUS));
493
494 return_ACPI_STATUS(AE_OK);
495}
496
497/*******************************************************************************
498 *
499 * FUNCTION: acpi_hw_extended_wake_prep
500 *
501 * PARAMETERS: sleep_state - Which sleep state we just exited
502 *
503 * RETURN: Status
504 *
505 * DESCRIPTION: Perform first part of OS-independent ACPI cleanup after
506 * a sleep. Called with interrupts ENABLED.
507 *
508 ******************************************************************************/
509
510acpi_status acpi_hw_extended_wake_prep(u8 sleep_state)
511{
512 acpi_status status;
513 u8 sleep_type_value;
514
515 ACPI_FUNCTION_TRACE(hw_extended_wake_prep);
516
517 status = acpi_get_sleep_type_data(ACPI_STATE_S0,
518 &acpi_gbl_sleep_type_a,
519 &acpi_gbl_sleep_type_b);
520 if (ACPI_SUCCESS(status)) {
521 sleep_type_value =
522 ((acpi_gbl_sleep_type_a << ACPI_X_SLEEP_TYPE_POSITION) &
523 ACPI_X_SLEEP_TYPE_MASK);
524
525 (void)acpi_write((sleep_type_value | ACPI_X_SLEEP_ENABLE),
526 &acpi_gbl_FADT.sleep_control);
527 }
528
Bob Mooref99648b2012-02-14 18:43:03 +0800529 acpi_hw_execute_sleep_method(METHOD_NAME__BFS, sleep_state);
Bob Moore2feec472012-02-14 15:00:53 +0800530 return_ACPI_STATUS(AE_OK);
531}
532
533/*******************************************************************************
534 *
535 * FUNCTION: acpi_hw_extended_wake
536 *
537 * PARAMETERS: sleep_state - Which sleep state we just exited
538 *
539 * RETURN: Status
540 *
541 * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep
542 * Called with interrupts ENABLED.
543 *
544 ******************************************************************************/
545
546acpi_status acpi_hw_extended_wake(u8 sleep_state)
547{
548 ACPI_FUNCTION_TRACE(hw_extended_wake);
549
550 /* Ensure enter_sleep_state_prep -> enter_sleep_state ordering */
551
552 acpi_gbl_sleep_type_a = ACPI_SLEEP_TYPE_INVALID;
553
554 /* Execute the wake methods */
555
Bob Mooref99648b2012-02-14 18:43:03 +0800556 acpi_hw_execute_sleep_method(METHOD_NAME__SST, ACPI_SST_WAKING);
557 acpi_hw_execute_sleep_method(METHOD_NAME__WAK, sleep_state);
Bob Moore2feec472012-02-14 15:00:53 +0800558
559 /*
560 * Some BIOS code assumes that WAK_STS will be cleared on resume
561 * and use it to determine whether the system is rebooting or
562 * resuming. Clear WAK_STS for compatibility.
563 */
564 (void)acpi_write(ACPI_X_WAKE_STATUS, &acpi_gbl_FADT.sleep_status);
565 acpi_gbl_system_awake_and_running = TRUE;
566
Bob Mooref99648b2012-02-14 18:43:03 +0800567 acpi_hw_execute_sleep_method(METHOD_NAME__SST, ACPI_SST_WORKING);
Bob Moore2feec472012-02-14 15:00:53 +0800568 return_ACPI_STATUS(AE_OK);
569}