xref: /openbmc/linux/drivers/acpi/acpica/hwxfsleep.c (revision 74ce1896)
1 /******************************************************************************
2  *
3  * Name: hwxfsleep.c - ACPI Hardware Sleep/Wake External Interfaces
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2017, Intel Corp.
9  * 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 
44 #define EXPORT_ACPI_INTERFACES
45 
46 #include <acpi/acpi.h>
47 #include "accommon.h"
48 
49 #define _COMPONENT          ACPI_HARDWARE
50 ACPI_MODULE_NAME("hwxfsleep")
51 
52 /* Local prototypes */
53 #if (!ACPI_REDUCED_HARDWARE)
54 static acpi_status
55 acpi_hw_set_firmware_waking_vector(struct acpi_table_facs *facs,
56 				   acpi_physical_address physical_address,
57 				   acpi_physical_address physical_address64);
58 #endif
59 
60 static acpi_status acpi_hw_sleep_dispatch(u8 sleep_state, u32 function_id);
61 
62 /*
63  * Dispatch table used to efficiently branch to the various sleep
64  * functions.
65  */
66 #define ACPI_SLEEP_FUNCTION_ID         0
67 #define ACPI_WAKE_PREP_FUNCTION_ID     1
68 #define ACPI_WAKE_FUNCTION_ID          2
69 
70 /* Legacy functions are optional, based upon ACPI_REDUCED_HARDWARE */
71 
72 static struct acpi_sleep_functions acpi_sleep_dispatch[] = {
73 	{ACPI_STRUCT_INIT(legacy_function,
74 			  ACPI_HW_OPTIONAL_FUNCTION(acpi_hw_legacy_sleep)),
75 	 ACPI_STRUCT_INIT(extended_function,
76 			  acpi_hw_extended_sleep)},
77 	{ACPI_STRUCT_INIT(legacy_function,
78 			  ACPI_HW_OPTIONAL_FUNCTION(acpi_hw_legacy_wake_prep)),
79 	 ACPI_STRUCT_INIT(extended_function,
80 			  acpi_hw_extended_wake_prep)},
81 	{ACPI_STRUCT_INIT(legacy_function,
82 			  ACPI_HW_OPTIONAL_FUNCTION(acpi_hw_legacy_wake)),
83 	 ACPI_STRUCT_INIT(extended_function,
84 			  acpi_hw_extended_wake)}
85 };
86 
87 /*
88  * These functions are removed for the ACPI_REDUCED_HARDWARE case:
89  *      acpi_set_firmware_waking_vector
90  *      acpi_enter_sleep_state_s4bios
91  */
92 
93 #if (!ACPI_REDUCED_HARDWARE)
94 /*******************************************************************************
95  *
96  * FUNCTION:    acpi_hw_set_firmware_waking_vector
97  *
98  * PARAMETERS:  facs                - Pointer to FACS table
99  *              physical_address    - 32-bit physical address of ACPI real mode
100  *                                    entry point
101  *              physical_address64  - 64-bit physical address of ACPI protected
102  *                                    mode entry point
103  *
104  * RETURN:      Status
105  *
106  * DESCRIPTION: Sets the firmware_waking_vector fields of the FACS
107  *
108  ******************************************************************************/
109 
110 static acpi_status
111 acpi_hw_set_firmware_waking_vector(struct acpi_table_facs *facs,
112 				   acpi_physical_address physical_address,
113 				   acpi_physical_address physical_address64)
114 {
115 	ACPI_FUNCTION_TRACE(acpi_hw_set_firmware_waking_vector);
116 
117 
118 	/*
119 	 * According to the ACPI specification 2.0c and later, the 64-bit
120 	 * waking vector should be cleared and the 32-bit waking vector should
121 	 * be used, unless we want the wake-up code to be called by the BIOS in
122 	 * Protected Mode.  Some systems (for example HP dv5-1004nr) are known
123 	 * to fail to resume if the 64-bit vector is used.
124 	 */
125 
126 	/* Set the 32-bit vector */
127 
128 	facs->firmware_waking_vector = (u32)physical_address;
129 
130 	if (facs->length > 32) {
131 		if (facs->version >= 1) {
132 
133 			/* Set the 64-bit vector */
134 
135 			facs->xfirmware_waking_vector = physical_address64;
136 		} else {
137 			/* Clear the 64-bit vector if it exists */
138 
139 			facs->xfirmware_waking_vector = 0;
140 		}
141 	}
142 
143 	return_ACPI_STATUS(AE_OK);
144 }
145 
146 /*******************************************************************************
147  *
148  * FUNCTION:    acpi_set_firmware_waking_vector
149  *
150  * PARAMETERS:  physical_address    - 32-bit physical address of ACPI real mode
151  *                                    entry point
152  *              physical_address64  - 64-bit physical address of ACPI protected
153  *                                    mode entry point
154  *
155  * RETURN:      Status
156  *
157  * DESCRIPTION: Sets the firmware_waking_vector fields of the FACS
158  *
159  ******************************************************************************/
160 
161 acpi_status
162 acpi_set_firmware_waking_vector(acpi_physical_address physical_address,
163 				acpi_physical_address physical_address64)
164 {
165 
166 	ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector);
167 
168 	if (acpi_gbl_FACS) {
169 		(void)acpi_hw_set_firmware_waking_vector(acpi_gbl_FACS,
170 							 physical_address,
171 							 physical_address64);
172 	}
173 
174 	return_ACPI_STATUS(AE_OK);
175 }
176 
177 ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector)
178 
179 /*******************************************************************************
180  *
181  * FUNCTION:    acpi_enter_sleep_state_s4bios
182  *
183  * PARAMETERS:  None
184  *
185  * RETURN:      Status
186  *
187  * DESCRIPTION: Perform a S4 bios request.
188  *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
189  *
190  ******************************************************************************/
191 acpi_status acpi_enter_sleep_state_s4bios(void)
192 {
193 	u32 in_value;
194 	acpi_status status;
195 
196 	ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_s4bios);
197 
198 	/* Clear the wake status bit (PM1) */
199 
200 	status =
201 	    acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS);
202 	if (ACPI_FAILURE(status)) {
203 		return_ACPI_STATUS(status);
204 	}
205 
206 	status = acpi_hw_clear_acpi_status();
207 	if (ACPI_FAILURE(status)) {
208 		return_ACPI_STATUS(status);
209 	}
210 
211 	/*
212 	 * 1) Disable/Clear all GPEs
213 	 * 2) Enable all wakeup GPEs
214 	 */
215 	status = acpi_hw_disable_all_gpes();
216 	if (ACPI_FAILURE(status)) {
217 		return_ACPI_STATUS(status);
218 	}
219 	acpi_gbl_system_awake_and_running = FALSE;
220 
221 	status = acpi_hw_enable_all_wakeup_gpes();
222 	if (ACPI_FAILURE(status)) {
223 		return_ACPI_STATUS(status);
224 	}
225 
226 	ACPI_FLUSH_CPU_CACHE();
227 
228 	status = acpi_hw_write_port(acpi_gbl_FADT.smi_command,
229 				    (u32)acpi_gbl_FADT.s4_bios_request, 8);
230 
231 	do {
232 		acpi_os_stall(ACPI_USEC_PER_MSEC);
233 		status =
234 		    acpi_read_bit_register(ACPI_BITREG_WAKE_STATUS, &in_value);
235 		if (ACPI_FAILURE(status)) {
236 			return_ACPI_STATUS(status);
237 		}
238 
239 	} while (!in_value);
240 
241 	return_ACPI_STATUS(AE_OK);
242 }
243 
244 ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_s4bios)
245 #endif				/* !ACPI_REDUCED_HARDWARE */
246 /*******************************************************************************
247  *
248  * FUNCTION:    acpi_hw_sleep_dispatch
249  *
250  * PARAMETERS:  sleep_state         - Which sleep state to enter/exit
251  *              function_id         - Sleep, wake_prep, or Wake
252  *
253  * RETURN:      Status from the invoked sleep handling function.
254  *
255  * DESCRIPTION: Dispatch a sleep/wake request to the appropriate handling
256  *              function.
257  *
258  ******************************************************************************/
259 static acpi_status acpi_hw_sleep_dispatch(u8 sleep_state, u32 function_id)
260 {
261 	acpi_status status;
262 	struct acpi_sleep_functions *sleep_functions =
263 	    &acpi_sleep_dispatch[function_id];
264 
265 #if (!ACPI_REDUCED_HARDWARE)
266 	/*
267 	 * If the Hardware Reduced flag is set (from the FADT), we must
268 	 * use the extended sleep registers (FADT). Note: As per the ACPI
269 	 * specification, these extended registers are to be used for HW-reduced
270 	 * platforms only. They are not general-purpose replacements for the
271 	 * legacy PM register sleep support.
272 	 */
273 	if (acpi_gbl_reduced_hardware) {
274 		status = sleep_functions->extended_function(sleep_state);
275 	} else {
276 		/* Legacy sleep */
277 
278 		status = sleep_functions->legacy_function(sleep_state);
279 	}
280 
281 	return (status);
282 
283 #else
284 	/*
285 	 * For the case where reduced-hardware-only code is being generated,
286 	 * we know that only the extended sleep registers are available
287 	 */
288 	status = sleep_functions->extended_function(sleep_state);
289 	return (status);
290 
291 #endif				/* !ACPI_REDUCED_HARDWARE */
292 }
293 
294 /*******************************************************************************
295  *
296  * FUNCTION:    acpi_enter_sleep_state_prep
297  *
298  * PARAMETERS:  sleep_state         - Which sleep state to enter
299  *
300  * RETURN:      Status
301  *
302  * DESCRIPTION: Prepare to enter a system sleep state.
303  *              This function must execute with interrupts enabled.
304  *              We break sleeping into 2 stages so that OSPM can handle
305  *              various OS-specific tasks between the two steps.
306  *
307  ******************************************************************************/
308 
309 acpi_status acpi_enter_sleep_state_prep(u8 sleep_state)
310 {
311 	acpi_status status;
312 	struct acpi_object_list arg_list;
313 	union acpi_object arg;
314 	u32 sst_value;
315 
316 	ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_prep);
317 
318 	status = acpi_get_sleep_type_data(sleep_state,
319 					  &acpi_gbl_sleep_type_a,
320 					  &acpi_gbl_sleep_type_b);
321 	if (ACPI_FAILURE(status)) {
322 		return_ACPI_STATUS(status);
323 	}
324 
325 	/* Execute the _PTS method (Prepare To Sleep) */
326 
327 	arg_list.count = 1;
328 	arg_list.pointer = &arg;
329 	arg.type = ACPI_TYPE_INTEGER;
330 	arg.integer.value = sleep_state;
331 
332 	status =
333 	    acpi_evaluate_object(NULL, METHOD_PATHNAME__PTS, &arg_list, NULL);
334 	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
335 		return_ACPI_STATUS(status);
336 	}
337 
338 	/* Setup the argument to the _SST method (System STatus) */
339 
340 	switch (sleep_state) {
341 	case ACPI_STATE_S0:
342 
343 		sst_value = ACPI_SST_WORKING;
344 		break;
345 
346 	case ACPI_STATE_S1:
347 	case ACPI_STATE_S2:
348 	case ACPI_STATE_S3:
349 
350 		sst_value = ACPI_SST_SLEEPING;
351 		break;
352 
353 	case ACPI_STATE_S4:
354 
355 		sst_value = ACPI_SST_SLEEP_CONTEXT;
356 		break;
357 
358 	default:
359 
360 		sst_value = ACPI_SST_INDICATOR_OFF;	/* Default is off */
361 		break;
362 	}
363 
364 	/*
365 	 * Set the system indicators to show the desired sleep state.
366 	 * _SST is an optional method (return no error if not found)
367 	 */
368 	acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, sst_value);
369 	return_ACPI_STATUS(AE_OK);
370 }
371 
372 ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_prep)
373 
374 /*******************************************************************************
375  *
376  * FUNCTION:    acpi_enter_sleep_state
377  *
378  * PARAMETERS:  sleep_state         - Which sleep state to enter
379  *
380  * RETURN:      Status
381  *
382  * DESCRIPTION: Enter a system sleep state
383  *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
384  *
385  ******************************************************************************/
386 acpi_status acpi_enter_sleep_state(u8 sleep_state)
387 {
388 	acpi_status status;
389 
390 	ACPI_FUNCTION_TRACE(acpi_enter_sleep_state);
391 
392 	if ((acpi_gbl_sleep_type_a > ACPI_SLEEP_TYPE_MAX) ||
393 	    (acpi_gbl_sleep_type_b > ACPI_SLEEP_TYPE_MAX)) {
394 		ACPI_ERROR((AE_INFO, "Sleep values out of range: A=0x%X B=0x%X",
395 			    acpi_gbl_sleep_type_a, acpi_gbl_sleep_type_b));
396 		return_ACPI_STATUS(AE_AML_OPERAND_VALUE);
397 	}
398 
399 	status = acpi_hw_sleep_dispatch(sleep_state, ACPI_SLEEP_FUNCTION_ID);
400 	return_ACPI_STATUS(status);
401 }
402 
403 ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state)
404 
405 /*******************************************************************************
406  *
407  * FUNCTION:    acpi_leave_sleep_state_prep
408  *
409  * PARAMETERS:  sleep_state         - Which sleep state we are exiting
410  *
411  * RETURN:      Status
412  *
413  * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a
414  *              sleep. Called with interrupts DISABLED.
415  *              We break wake/resume into 2 stages so that OSPM can handle
416  *              various OS-specific tasks between the two steps.
417  *
418  ******************************************************************************/
419 acpi_status acpi_leave_sleep_state_prep(u8 sleep_state)
420 {
421 	acpi_status status;
422 
423 	ACPI_FUNCTION_TRACE(acpi_leave_sleep_state_prep);
424 
425 	status =
426 	    acpi_hw_sleep_dispatch(sleep_state, ACPI_WAKE_PREP_FUNCTION_ID);
427 	return_ACPI_STATUS(status);
428 }
429 
430 ACPI_EXPORT_SYMBOL(acpi_leave_sleep_state_prep)
431 
432 /*******************************************************************************
433  *
434  * FUNCTION:    acpi_leave_sleep_state
435  *
436  * PARAMETERS:  sleep_state         - Which sleep state we are exiting
437  *
438  * RETURN:      Status
439  *
440  * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep
441  *              Called with interrupts ENABLED.
442  *
443  ******************************************************************************/
444 acpi_status acpi_leave_sleep_state(u8 sleep_state)
445 {
446 	acpi_status status;
447 
448 	ACPI_FUNCTION_TRACE(acpi_leave_sleep_state);
449 
450 	status = acpi_hw_sleep_dispatch(sleep_state, ACPI_WAKE_FUNCTION_ID);
451 	return_ACPI_STATUS(status);
452 }
453 
454 ACPI_EXPORT_SYMBOL(acpi_leave_sleep_state)
455