]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blame - drivers/acpi/acpica/hwsleep.c
ACPICA: adding SPDX headers
[mirror_ubuntu-hirsute-kernel.git] / drivers / acpi / acpica / hwsleep.c
CommitLineData
95857638 1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
1da177e4
LT
2/******************************************************************************
3 *
70958576
BM
4 * Name: hwsleep.c - ACPI Hardware Sleep/Wake Support functions for the
5 * original/legacy sleep/PM registers.
1da177e4 6 *
da6f8320 7 * Copyright (C) 2000 - 2018, Intel Corp.
1da177e4 8 *
95857638 9 *****************************************************************************/
1da177e4 10
1da177e4 11#include <acpi/acpi.h>
e2f7a777 12#include "accommon.h"
1da177e4
LT
13
14#define _COMPONENT ACPI_HARDWARE
4be44fcd 15ACPI_MODULE_NAME("hwsleep")
1da177e4 16
70958576 17#if (!ACPI_REDUCED_HARDWARE) /* Entire module */
44f6c012 18/*******************************************************************************
1da177e4 19 *
2feec47d 20 * FUNCTION: acpi_hw_legacy_sleep
1da177e4
LT
21 *
22 * PARAMETERS: sleep_state - Which sleep state to enter
23 *
24 * RETURN: Status
25 *
2feec47d 26 * DESCRIPTION: Enter a system sleep state via the legacy FADT PM registers
1da177e4
LT
27 * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
28 *
29 ******************************************************************************/
3f6f49c7 30acpi_status acpi_hw_legacy_sleep(u8 sleep_state)
1da177e4 31{
4be44fcd
LB
32 struct acpi_bit_register_info *sleep_type_reg_info;
33 struct acpi_bit_register_info *sleep_enable_reg_info;
2feec47d
BM
34 u32 pm1a_control;
35 u32 pm1b_control;
4be44fcd
LB
36 u32 in_value;
37 acpi_status status;
1da177e4 38
2feec47d 39 ACPI_FUNCTION_TRACE(hw_legacy_sleep);
1da177e4 40
4be44fcd 41 sleep_type_reg_info =
82d79b86 42 acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_TYPE);
4be44fcd
LB
43 sleep_enable_reg_info =
44 acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_ENABLE);
1da177e4
LT
45
46 /* Clear wake status */
47
1fad8738
BM
48 status = acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS,
49 ACPI_CLEAR_STATUS);
4be44fcd
LB
50 if (ACPI_FAILURE(status)) {
51 return_ACPI_STATUS(status);
1da177e4
LT
52 }
53
1da177e4 54 /*
18996f2d 55 * 1) Disable all GPEs
1da177e4
LT
56 * 2) Enable all wakeup GPEs
57 */
1d99967b
AS
58 status = acpi_hw_disable_all_gpes();
59 if (ACPI_FAILURE(status)) {
60 return_ACPI_STATUS(status);
61 }
1da177e4
LT
62 acpi_gbl_system_awake_and_running = FALSE;
63
4be44fcd
LB
64 status = acpi_hw_enable_all_wakeup_gpes();
65 if (ACPI_FAILURE(status)) {
66 return_ACPI_STATUS(status);
1da177e4
LT
67 }
68
69 /* Get current value of PM1A control */
70
32c9ef99
BM
71 status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL,
72 &pm1a_control);
4be44fcd
LB
73 if (ACPI_FAILURE(status)) {
74 return_ACPI_STATUS(status);
1da177e4 75 }
4be44fcd 76 ACPI_DEBUG_PRINT((ACPI_DB_INIT,
b27d6597 77 "Entering sleep state [S%u]\n", sleep_state));
1da177e4 78
32c9ef99 79 /* Clear the SLP_EN and SLP_TYP fields */
1da177e4 80
32c9ef99
BM
81 pm1a_control &= ~(sleep_type_reg_info->access_bit_mask |
82 sleep_enable_reg_info->access_bit_mask);
83 pm1b_control = pm1a_control;
1da177e4 84
32c9ef99 85 /* Insert the SLP_TYP bits */
1da177e4 86
32c9ef99 87 pm1a_control |=
4be44fcd 88 (acpi_gbl_sleep_type_a << sleep_type_reg_info->bit_position);
32c9ef99 89 pm1b_control |=
4be44fcd 90 (acpi_gbl_sleep_type_b << sleep_type_reg_info->bit_position);
1da177e4
LT
91
92 /*
93 * We split the writes of SLP_TYP and SLP_EN to workaround
94 * poorly implemented hardware.
95 */
96
32c9ef99 97 /* Write #1: write the SLP_TYP data to the PM1 Control registers */
1da177e4 98
32c9ef99 99 status = acpi_hw_write_pm1_control(pm1a_control, pm1b_control);
4be44fcd
LB
100 if (ACPI_FAILURE(status)) {
101 return_ACPI_STATUS(status);
1da177e4
LT
102 }
103
32c9ef99 104 /* Insert the sleep enable (SLP_EN) bit */
1da177e4 105
32c9ef99
BM
106 pm1a_control |= sleep_enable_reg_info->access_bit_mask;
107 pm1b_control |= sleep_enable_reg_info->access_bit_mask;
1da177e4 108
32c9ef99 109 /* Flush caches, as per ACPI specification */
1da177e4 110
4be44fcd 111 ACPI_FLUSH_CPU_CACHE();
1da177e4 112
0fc5e8f4
LZ
113 status = acpi_os_enter_sleep(sleep_state, pm1a_control, pm1b_control);
114 if (status == AE_CTRL_TERMINATE) {
09f98a82 115 return_ACPI_STATUS(AE_OK);
0fc5e8f4
LZ
116 }
117 if (ACPI_FAILURE(status)) {
09f98a82 118 return_ACPI_STATUS(status);
0fc5e8f4
LZ
119 }
120
32c9ef99 121 /* Write #2: Write both SLP_TYP + SLP_EN */
1da177e4 122
32c9ef99 123 status = acpi_hw_write_pm1_control(pm1a_control, pm1b_control);
4be44fcd
LB
124 if (ACPI_FAILURE(status)) {
125 return_ACPI_STATUS(status);
1da177e4
LT
126 }
127
128 if (sleep_state > ACPI_STATE_S3) {
129 /*
44f6c012
RM
130 * We wanted to sleep > S3, but it didn't happen (by virtue of the
131 * fact that we are still executing!)
1da177e4 132 *
44f6c012
RM
133 * Wait ten seconds, then try again. This is to get S4/S5 to work on
134 * all machines.
1da177e4 135 *
d4913dc6
BM
136 * We wait so long to allow chipsets that poll this reg very slowly
137 * to still read the right value. Ideally, this block would go
1da177e4
LT
138 * away entirely.
139 */
c41679a4 140 acpi_os_stall(10 * ACPI_USEC_PER_SEC);
4be44fcd 141
d30dc9ab 142 status = acpi_hw_register_write(ACPI_REGISTER_PM1_CONTROL,
4be44fcd
LB
143 sleep_enable_reg_info->
144 access_bit_mask);
145 if (ACPI_FAILURE(status)) {
146 return_ACPI_STATUS(status);
1da177e4
LT
147 }
148 }
149
2feec47d 150 /* Wait for transition back to Working State */
1da177e4
LT
151
152 do {
50ffba1b
BM
153 status =
154 acpi_read_bit_register(ACPI_BITREG_WAKE_STATUS, &in_value);
4be44fcd
LB
155 if (ACPI_FAILURE(status)) {
156 return_ACPI_STATUS(status);
1da177e4 157 }
2feec47d 158
1da177e4
LT
159 } while (!in_value);
160
4be44fcd 161 return_ACPI_STATUS(AE_OK);
1da177e4 162}
1da177e4 163
44f6c012 164/*******************************************************************************
1da177e4 165 *
2feec47d 166 * FUNCTION: acpi_hw_legacy_wake_prep
1da177e4 167 *
2feec47d 168 * PARAMETERS: sleep_state - Which sleep state we just exited
1da177e4
LT
169 *
170 * RETURN: Status
171 *
c95d47a8
RW
172 * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a
173 * sleep.
2feec47d 174 * Called with interrupts ENABLED.
1da177e4
LT
175 *
176 ******************************************************************************/
2feec47d 177
3f6f49c7 178acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state)
1da177e4 179{
4be44fcd
LB
180 acpi_status status;
181 struct acpi_bit_register_info *sleep_type_reg_info;
182 struct acpi_bit_register_info *sleep_enable_reg_info;
32c9ef99
BM
183 u32 pm1a_control;
184 u32 pm1b_control;
1da177e4 185
2feec47d 186 ACPI_FUNCTION_TRACE(hw_legacy_wake_prep);
1da177e4
LT
187
188 /*
189 * Set SLP_TYPE and SLP_EN to state S0.
190 * This is unclear from the ACPI Spec, but it is required
191 * by some machines.
192 */
4be44fcd
LB
193 status = acpi_get_sleep_type_data(ACPI_STATE_S0,
194 &acpi_gbl_sleep_type_a,
195 &acpi_gbl_sleep_type_b);
196 if (ACPI_SUCCESS(status)) {
197 sleep_type_reg_info =
82d79b86 198 acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_TYPE);
4be44fcd
LB
199 sleep_enable_reg_info =
200 acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_ENABLE);
1da177e4
LT
201
202 /* Get current value of PM1A control */
203
d30dc9ab 204 status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL,
32c9ef99 205 &pm1a_control);
4be44fcd 206 if (ACPI_SUCCESS(status)) {
52fc0b02 207
32c9ef99 208 /* Clear the SLP_EN and SLP_TYP fields */
1da177e4 209
32c9ef99
BM
210 pm1a_control &= ~(sleep_type_reg_info->access_bit_mask |
211 sleep_enable_reg_info->
212 access_bit_mask);
213 pm1b_control = pm1a_control;
1da177e4 214
32c9ef99 215 /* Insert the SLP_TYP bits */
1da177e4 216
d4913dc6
BM
217 pm1a_control |= (acpi_gbl_sleep_type_a <<
218 sleep_type_reg_info->bit_position);
219 pm1b_control |= (acpi_gbl_sleep_type_b <<
220 sleep_type_reg_info->bit_position);
1da177e4 221
32c9ef99 222 /* Write the control registers and ignore any errors */
1da177e4 223
32c9ef99
BM
224 (void)acpi_hw_write_pm1_control(pm1a_control,
225 pm1b_control);
1da177e4
LT
226 }
227 }
228
c95d47a8
RW
229 return_ACPI_STATUS(status);
230}
231
232/*******************************************************************************
233 *
2feec47d 234 * FUNCTION: acpi_hw_legacy_wake
c95d47a8
RW
235 *
236 * PARAMETERS: sleep_state - Which sleep state we just exited
237 *
238 * RETURN: Status
239 *
240 * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep
241 * Called with interrupts ENABLED.
242 *
243 ******************************************************************************/
2feec47d 244
3f6f49c7 245acpi_status acpi_hw_legacy_wake(u8 sleep_state)
c95d47a8 246{
c95d47a8
RW
247 acpi_status status;
248
2feec47d 249 ACPI_FUNCTION_TRACE(hw_legacy_wake);
c95d47a8 250
1da177e4
LT
251 /* Ensure enter_sleep_state_prep -> enter_sleep_state ordering */
252
253 acpi_gbl_sleep_type_a = ACPI_SLEEP_TYPE_INVALID;
4efeeecd 254 acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, ACPI_SST_WAKING);
1da177e4 255
1da177e4 256 /*
79d2dfaa
TR
257 * GPEs must be enabled before _WAK is called as GPEs
258 * might get fired there
259 *
1da177e4 260 * Restore the GPEs:
18996f2d 261 * 1) Disable all GPEs
1da177e4
LT
262 * 2) Enable all runtime GPEs
263 */
4be44fcd
LB
264 status = acpi_hw_disable_all_gpes();
265 if (ACPI_FAILURE(status)) {
266 return_ACPI_STATUS(status);
1da177e4 267 }
2feec47d 268
4be44fcd
LB
269 status = acpi_hw_enable_all_runtime_gpes();
270 if (ACPI_FAILURE(status)) {
271 return_ACPI_STATUS(status);
1da177e4
LT
272 }
273
2feec47d
BM
274 /*
275 * Now we can execute _WAK, etc. Some machines require that the GPEs
276 * are enabled before the wake methods are executed.
277 */
4efeeecd 278 acpi_hw_execute_sleep_method(METHOD_PATHNAME__WAK, sleep_state);
79d2dfaa 279
a68823ee 280 /*
2feec47d
BM
281 * Some BIOS code assumes that WAK_STS will be cleared on resume
282 * and use it to determine whether the system is rebooting or
283 * resuming. Clear WAK_STS for compatibility.
a68823ee 284 */
739dcbb9
LZ
285 (void)acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS,
286 ACPI_CLEAR_STATUS);
79d2dfaa
TR
287 acpi_gbl_system_awake_and_running = TRUE;
288
1da177e4
LT
289 /* Enable power button */
290
4be44fcd 291 (void)
50ffba1b 292 acpi_write_bit_register(acpi_gbl_fixed_event_info
2feec47d
BM
293 [ACPI_EVENT_POWER_BUTTON].
294 enable_register_id, ACPI_ENABLE_EVENT);
44f6c012 295
4be44fcd 296 (void)
50ffba1b 297 acpi_write_bit_register(acpi_gbl_fixed_event_info
2feec47d
BM
298 [ACPI_EVENT_POWER_BUTTON].
299 status_register_id, ACPI_CLEAR_STATUS);
1da177e4 300
4efeeecd 301 acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, ACPI_SST_WORKING);
4be44fcd 302 return_ACPI_STATUS(status);
1da177e4 303}
8313524a 304
33620c54 305#endif /* !ACPI_REDUCED_HARDWARE */