xref: /linux/drivers/acpi/x86/s2idle.c (revision 46767b17fda3fba1ed91dd73d7d432b0bb6851c1)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Architecture-specific ACPI-based support for suspend-to-idle.
4  *
5  * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
6  * Author: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
7  * Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
8  *
9  * On platforms supporting the Low Power S0 Idle interface there is an ACPI
10  * device object with the PNP0D80 compatible device ID (System Power Management
11  * Controller) and a specific _DSM method under it.  That method, if present,
12  * can be used to indicate to the platform that the OS is transitioning into a
13  * low-power state in which certain types of activity are not desirable or that
14  * it is leaving such a state, which allows the platform to adjust its operation
15  * mode accordingly.
16  */
17 
18 #include <linux/acpi.h>
19 #include <linux/device.h>
20 #include <linux/dmi.h>
21 #include <linux/suspend.h>
22 
23 #include "../sleep.h"
24 
25 #ifdef CONFIG_SUSPEND
26 
27 static void acpi_setup_ixx_gpes(void)
28 {
29 	acpi_handle gpe_root;
30 	unsigned int i;
31 	char gpe_nr_str[5];
32 
33 	if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_GPE", &gpe_root)))
34 		return;
35 
36 	for (i = 0; i <= 0xff; i++) {
37 		scnprintf(gpe_nr_str, sizeof(gpe_nr_str), "_I%02X", i);
38 		if (!acpi_has_method(gpe_root, gpe_nr_str))
39 			continue;
40 
41 		/*
42 		 * Enable the GPE if it has a handler method because marking it
43 		 * as wake-capable causes acpi_update_all_gpes() to skip it.
44 		 */
45 		if (ACPI_FAILURE(acpi_enable_gpe_cond(NULL, i, ACPI_GPE_DISPATCH_METHOD)))
46 			continue;
47 
48 		acpi_mark_gpe_for_wake(NULL, i);
49 		acpi_set_gpe_wake_mask(NULL, i, ACPI_GPE_ENABLE);
50 
51 		pm_pr_dbg("ACPI: GPE0x%02x armed for wake via %s\n", i, gpe_nr_str);
52 	}
53 }
54 
55 static bool sleep_no_lps0 __read_mostly;
56 module_param(sleep_no_lps0, bool, 0644);
57 MODULE_PARM_DESC(sleep_no_lps0, "Do not use the special LPS0 device interface");
58 
59 static bool check_lps0_constraints __read_mostly;
60 module_param(check_lps0_constraints, bool, 0644);
61 MODULE_PARM_DESC(check_lps0_constraints, "Check LPS0 device constraints");
62 
63 static const struct acpi_device_id lps0_device_ids[] = {
64 	{"PNP0D80", },
65 	{"", },
66 };
67 
68 /* Microsoft platform agnostic UUID */
69 #define ACPI_LPS0_DSM_UUID_MICROSOFT      "11e00d56-ce64-47ce-837b-1f898f9aa461"
70 
71 #define ACPI_LPS0_DSM_UUID	"c4eb40a0-6cd2-11e2-bcfd-0800200c9a66"
72 
73 #define ACPI_LPS0_GET_DEVICE_CONSTRAINTS	1
74 #define ACPI_LPS0_SCREEN_OFF	3
75 #define ACPI_LPS0_SCREEN_ON	4
76 #define ACPI_LPS0_ENTRY		5
77 #define ACPI_LPS0_EXIT		6
78 #define ACPI_LPS0_MS_ENTRY      7
79 #define ACPI_LPS0_MS_EXIT       8
80 #define ACPI_MS_TURN_ON_DISPLAY 9
81 
82 /* AMD */
83 #define ACPI_LPS0_DSM_UUID_AMD      "e3f32452-febc-43ce-9039-932122d37721"
84 #define ACPI_LPS0_ENTRY_AMD         2
85 #define ACPI_LPS0_EXIT_AMD          3
86 #define ACPI_LPS0_SCREEN_OFF_AMD    4
87 #define ACPI_LPS0_SCREEN_ON_AMD     5
88 
89 static acpi_handle lps0_device_handle;
90 static guid_t lps0_dsm_guid;
91 static int lps0_dsm_func_mask;
92 
93 static guid_t lps0_dsm_guid_microsoft;
94 static int lps0_dsm_func_mask_microsoft;
95 static int lps0_dsm_state;
96 
97 /* Device constraint entry structure */
98 struct lpi_device_info {
99 	char *name;
100 	int enabled;
101 	union acpi_object *package;
102 };
103 
104 /* Constraint package structure */
105 struct lpi_device_constraint {
106 	int uid;
107 	int min_dstate;
108 	int function_states;
109 };
110 
111 struct lpi_constraints {
112 	acpi_handle handle;
113 	int min_dstate;
114 };
115 
116 /* AMD Constraint package structure */
117 struct lpi_device_constraint_amd {
118 	char *name;
119 	int enabled;
120 	int function_states;
121 	int min_dstate;
122 };
123 
124 static LIST_HEAD(lps0_s2idle_devops_head);
125 
126 static struct lpi_constraints *lpi_constraints_table;
127 static int lpi_constraints_table_size;
128 static int rev_id;
129 
130 #define for_each_lpi_constraint(entry)						\
131 	for (int i = 0;								\
132 	     entry = &lpi_constraints_table[i], i < lpi_constraints_table_size;	\
133 	     i++)
134 
135 static void lpi_device_get_constraints_amd(void)
136 {
137 	union acpi_object *out_obj;
138 	int i, j, k;
139 
140 	out_obj = acpi_evaluate_dsm_typed(lps0_device_handle, &lps0_dsm_guid,
141 					  rev_id, ACPI_LPS0_GET_DEVICE_CONSTRAINTS,
142 					  NULL, ACPI_TYPE_PACKAGE);
143 
144 	acpi_handle_debug(lps0_device_handle, "_DSM function 1 eval %s\n",
145 			  out_obj ? "successful" : "failed");
146 
147 	if (!out_obj)
148 		return;
149 
150 	for (i = 0; i < out_obj->package.count; i++) {
151 		union acpi_object *package = &out_obj->package.elements[i];
152 
153 		if (package->type == ACPI_TYPE_PACKAGE) {
154 			if (lpi_constraints_table) {
155 				acpi_handle_err(lps0_device_handle,
156 						"Duplicate constraints list\n");
157 				goto free_acpi_buffer;
158 			}
159 
160 			lpi_constraints_table = kzalloc_objs(*lpi_constraints_table,
161 							     package->package.count);
162 
163 			if (!lpi_constraints_table)
164 				goto free_acpi_buffer;
165 
166 			acpi_handle_debug(lps0_device_handle,
167 					  "LPI: constraints list begin:\n");
168 
169 			for (j = 0; j < package->package.count; j++) {
170 				union acpi_object *info_obj = &package->package.elements[j];
171 				struct lpi_device_constraint_amd dev_info = {};
172 				struct lpi_constraints *list;
173 				acpi_status status;
174 
175 				list = &lpi_constraints_table[lpi_constraints_table_size];
176 
177 				for (k = 0; k < info_obj->package.count; k++) {
178 					union acpi_object *obj = &info_obj->package.elements[k];
179 
180 					switch (k) {
181 					case 0:
182 						dev_info.enabled = obj->integer.value;
183 						break;
184 					case 1:
185 						dev_info.name = obj->string.pointer;
186 						break;
187 					case 2:
188 						dev_info.function_states = obj->integer.value;
189 						break;
190 					case 3:
191 						dev_info.min_dstate = obj->integer.value;
192 						break;
193 					}
194 				}
195 
196 				acpi_handle_debug(lps0_device_handle,
197 						  "Name:%s, Enabled: %d, States: %d, MinDstate: %d\n",
198 						  dev_info.name,
199 						  dev_info.enabled,
200 						  dev_info.function_states,
201 						  dev_info.min_dstate);
202 
203 				if (!dev_info.enabled || !dev_info.name ||
204 				    !dev_info.min_dstate)
205 					continue;
206 
207 				status = acpi_get_handle(NULL, dev_info.name, &list->handle);
208 				if (ACPI_FAILURE(status))
209 					continue;
210 
211 				list->min_dstate = dev_info.min_dstate;
212 
213 				lpi_constraints_table_size++;
214 			}
215 		}
216 	}
217 
218 	acpi_handle_debug(lps0_device_handle, "LPI: constraints list end\n");
219 
220 free_acpi_buffer:
221 	ACPI_FREE(out_obj);
222 }
223 
224 static void lpi_device_get_constraints(void)
225 {
226 	union acpi_object *out_obj;
227 	int i;
228 
229 	out_obj = acpi_evaluate_dsm_typed(lps0_device_handle, &lps0_dsm_guid,
230 					  1, ACPI_LPS0_GET_DEVICE_CONSTRAINTS,
231 					  NULL, ACPI_TYPE_PACKAGE);
232 
233 	acpi_handle_debug(lps0_device_handle, "_DSM function 1 eval %s\n",
234 			  out_obj ? "successful" : "failed");
235 
236 	if (!out_obj)
237 		return;
238 
239 	lpi_constraints_table = kzalloc_objs(*lpi_constraints_table,
240 					     out_obj->package.count);
241 	if (!lpi_constraints_table)
242 		goto free_acpi_buffer;
243 
244 	acpi_handle_debug(lps0_device_handle, "LPI: constraints list begin:\n");
245 
246 	for (i = 0; i < out_obj->package.count; i++) {
247 		struct lpi_constraints *constraint;
248 		acpi_status status;
249 		union acpi_object *package = &out_obj->package.elements[i];
250 		struct lpi_device_info info = { };
251 		int package_count = 0, j;
252 
253 		if (!package)
254 			continue;
255 
256 		for (j = 0; j < package->package.count; j++) {
257 			union acpi_object *element =
258 					&(package->package.elements[j]);
259 
260 			switch (element->type) {
261 			case ACPI_TYPE_INTEGER:
262 				info.enabled = element->integer.value;
263 				break;
264 			case ACPI_TYPE_STRING:
265 				info.name = element->string.pointer;
266 				break;
267 			case ACPI_TYPE_PACKAGE:
268 				package_count = element->package.count;
269 				info.package = element->package.elements;
270 				break;
271 			}
272 		}
273 
274 		if (!info.enabled || !info.package || !info.name)
275 			continue;
276 
277 		constraint = &lpi_constraints_table[lpi_constraints_table_size];
278 
279 		status = acpi_get_handle(NULL, info.name, &constraint->handle);
280 		if (ACPI_FAILURE(status))
281 			continue;
282 
283 		acpi_handle_debug(lps0_device_handle,
284 				  "index:%d Name:%s\n", i, info.name);
285 
286 		constraint->min_dstate = -1;
287 
288 		for (j = 0; j < package_count; j++) {
289 			union acpi_object *info_obj = &info.package[j];
290 			union acpi_object *cnstr_pkg;
291 			union acpi_object *obj;
292 			struct lpi_device_constraint dev_info;
293 
294 			switch (info_obj->type) {
295 			case ACPI_TYPE_INTEGER:
296 				/* version */
297 				break;
298 			case ACPI_TYPE_PACKAGE:
299 				if (info_obj->package.count < 2)
300 					break;
301 
302 				cnstr_pkg = info_obj->package.elements;
303 				obj = &cnstr_pkg[0];
304 				dev_info.uid = obj->integer.value;
305 				obj = &cnstr_pkg[1];
306 				dev_info.min_dstate = obj->integer.value;
307 
308 				acpi_handle_debug(lps0_device_handle,
309 					"uid:%d min_dstate:%s\n",
310 					dev_info.uid,
311 					acpi_power_state_string(dev_info.min_dstate));
312 
313 				constraint->min_dstate = dev_info.min_dstate;
314 				break;
315 			}
316 		}
317 
318 		if (constraint->min_dstate < 0) {
319 			acpi_handle_debug(lps0_device_handle,
320 					  "Incomplete constraint defined\n");
321 			continue;
322 		}
323 
324 		lpi_constraints_table_size++;
325 	}
326 
327 	acpi_handle_debug(lps0_device_handle, "LPI: constraints list end\n");
328 
329 free_acpi_buffer:
330 	ACPI_FREE(out_obj);
331 }
332 
333 static void lpi_check_constraints(void)
334 {
335 	struct lpi_constraints *entry;
336 
337 	if (IS_ERR_OR_NULL(lpi_constraints_table))
338 		return;
339 
340 	for_each_lpi_constraint(entry) {
341 		struct acpi_device *adev = acpi_fetch_acpi_dev(entry->handle);
342 
343 		if (!adev)
344 			continue;
345 
346 		acpi_handle_debug(entry->handle,
347 			"LPI: required min power state:%s current power state:%s\n",
348 			acpi_power_state_string(entry->min_dstate),
349 			acpi_power_state_string(adev->power.state));
350 
351 		if (!adev->flags.power_manageable) {
352 			acpi_handle_info(entry->handle, "LPI: Device not power manageable\n");
353 			entry->handle = NULL;
354 			continue;
355 		}
356 
357 		if (adev->power.state < entry->min_dstate)
358 			acpi_handle_info(entry->handle,
359 				"LPI: Constraint not met; min power state:%s current power state:%s\n",
360 				acpi_power_state_string(entry->min_dstate),
361 				acpi_power_state_string(adev->power.state));
362 	}
363 }
364 
365 static bool acpi_s2idle_vendor_amd(void)
366 {
367 	return boot_cpu_data.x86_vendor == X86_VENDOR_AMD;
368 }
369 
370 static const char *acpi_sleep_dsm_state_to_str(unsigned int state)
371 {
372 	if (lps0_dsm_func_mask_microsoft || !acpi_s2idle_vendor_amd()) {
373 		switch (state) {
374 		case ACPI_LPS0_SCREEN_OFF:
375 			return "screen off";
376 		case ACPI_LPS0_SCREEN_ON:
377 			return "screen on";
378 		case ACPI_LPS0_ENTRY:
379 			return "lps0 entry";
380 		case ACPI_LPS0_EXIT:
381 			return "lps0 exit";
382 		case ACPI_LPS0_MS_ENTRY:
383 			return "lps0 ms entry";
384 		case ACPI_LPS0_MS_EXIT:
385 			return "lps0 ms exit";
386 		case ACPI_MS_TURN_ON_DISPLAY:
387 			return "lps0 ms turn on display";
388 		}
389 	} else {
390 		switch (state) {
391 		case ACPI_LPS0_SCREEN_ON_AMD:
392 			return "screen on";
393 		case ACPI_LPS0_SCREEN_OFF_AMD:
394 			return "screen off";
395 		case ACPI_LPS0_ENTRY_AMD:
396 			return "lps0 entry";
397 		case ACPI_LPS0_EXIT_AMD:
398 			return "lps0 exit";
399 		}
400 	}
401 
402 	return "unknown";
403 }
404 
405 static void acpi_sleep_run_lps0_dsm(unsigned int func, unsigned int func_mask, guid_t dsm_guid)
406 {
407 	union acpi_object *out_obj;
408 
409 	if (!(func_mask & (1 << func)))
410 		return;
411 
412 	out_obj = acpi_evaluate_dsm(lps0_device_handle, &dsm_guid,
413 					rev_id, func, NULL);
414 	ACPI_FREE(out_obj);
415 
416 	lps0_dsm_state = func;
417 	if (pm_debug_messages_on) {
418 		acpi_handle_info(lps0_device_handle,
419 				"%s transitioned to state %s\n",
420 				 out_obj ? "Successfully" : "Failed to",
421 				 acpi_sleep_dsm_state_to_str(lps0_dsm_state));
422 	}
423 }
424 
425 
426 static int validate_dsm(acpi_handle handle, const char *uuid, int rev, guid_t *dsm_guid)
427 {
428 	union acpi_object *obj;
429 	int ret = -EINVAL;
430 
431 	guid_parse(uuid, dsm_guid);
432 
433 	/* Check if the _DSM is present and as expected. */
434 	obj = acpi_evaluate_dsm_typed(handle, dsm_guid, rev, 0, NULL, ACPI_TYPE_BUFFER);
435 	if (!obj || obj->buffer.length == 0 || obj->buffer.length > sizeof(u32)) {
436 		acpi_handle_debug(handle,
437 				"_DSM UUID %s rev %d function 0 evaluation failed\n", uuid, rev);
438 		goto out;
439 	}
440 
441 	ret = *(int *)obj->buffer.pointer;
442 	acpi_handle_debug(handle, "_DSM UUID %s rev %d function mask: 0x%x\n", uuid, rev, ret);
443 
444 out:
445 	ACPI_FREE(obj);
446 	return ret;
447 }
448 
449 struct amd_lps0_hid_device_data {
450 	const bool check_off_by_one;
451 };
452 
453 static const struct amd_lps0_hid_device_data amd_picasso = {
454 	.check_off_by_one = true,
455 };
456 
457 static const struct amd_lps0_hid_device_data amd_cezanne = {
458 	.check_off_by_one = false,
459 };
460 
461 static const struct acpi_device_id amd_hid_ids[] = {
462 	{"AMD0004",	(kernel_ulong_t)&amd_picasso,	},
463 	{"AMD0005",	(kernel_ulong_t)&amd_picasso,	},
464 	{"AMDI0005",	(kernel_ulong_t)&amd_picasso,	},
465 	{"AMDI0006",	(kernel_ulong_t)&amd_cezanne,	},
466 	{}
467 };
468 
469 static int lps0_device_attach(struct acpi_device *adev,
470 			      const struct acpi_device_id *not_used)
471 {
472 	if (lps0_device_handle)
473 		return 0;
474 
475 	lps0_dsm_func_mask_microsoft = validate_dsm(adev->handle,
476 						    ACPI_LPS0_DSM_UUID_MICROSOFT, 0,
477 						    &lps0_dsm_guid_microsoft);
478 	if (acpi_s2idle_vendor_amd()) {
479 		static const struct acpi_device_id *dev_id;
480 		const struct amd_lps0_hid_device_data *data;
481 
482 		for (dev_id = &amd_hid_ids[0]; dev_id->id[0]; dev_id++)
483 			if (acpi_dev_hid_uid_match(adev, dev_id->id, NULL))
484 				break;
485 		if (dev_id->id[0])
486 			data = (const struct amd_lps0_hid_device_data *) dev_id->driver_data;
487 		else
488 			data = &amd_cezanne;
489 		lps0_dsm_func_mask = validate_dsm(adev->handle,
490 					ACPI_LPS0_DSM_UUID_AMD, rev_id, &lps0_dsm_guid);
491 		if (lps0_dsm_func_mask > 0x3 && data->check_off_by_one) {
492 			lps0_dsm_func_mask = (lps0_dsm_func_mask << 1) | 0x1;
493 			acpi_handle_debug(adev->handle, "_DSM UUID %s: Adjusted function mask: 0x%x\n",
494 					  ACPI_LPS0_DSM_UUID_AMD, lps0_dsm_func_mask);
495 		}
496 	} else {
497 		rev_id = 1;
498 		lps0_dsm_func_mask = validate_dsm(adev->handle,
499 					ACPI_LPS0_DSM_UUID, rev_id, &lps0_dsm_guid);
500 		if (lps0_dsm_func_mask > 0 && lps0_dsm_func_mask_microsoft > 0) {
501 			unsigned int func_mask;
502 
503 			/*
504 			 * Log a message if the _DSM function sets for two
505 			 * different UUIDs overlap.
506 			 */
507 			func_mask = lps0_dsm_func_mask & lps0_dsm_func_mask_microsoft;
508 			if (func_mask)
509 				acpi_handle_info(adev->handle,
510 						 "Duplicate LPS0 _DSM functions (mask: 0x%x)\n",
511 						 func_mask);
512 		}
513 	}
514 
515 	if (lps0_dsm_func_mask < 0 && lps0_dsm_func_mask_microsoft < 0)
516 		return 0; //function evaluation failed
517 
518 	lps0_device_handle = adev->handle;
519 
520 	/*
521 	 * Use suspend-to-idle by default if ACPI_FADT_LOW_POWER_S0 is set in
522 	 * the FADT and the default suspend mode was not set from the command
523 	 * line.
524 	 */
525 	if ((acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0) &&
526 	    mem_sleep_default > PM_SUSPEND_MEM && !acpi_sleep_default_s3) {
527 		mem_sleep_current = PM_SUSPEND_TO_IDLE;
528 		pr_info("Low-power S0 idle used by default for system suspend\n");
529 	}
530 
531 	/*
532 	 * Some LPS0 systems, like ASUS Zenbook UX430UNR/i7-8550U, require the
533 	 * EC GPE to be enabled while suspended for certain wakeup devices to
534 	 * work, so mark it as wakeup-capable.
535 	 */
536 	acpi_ec_mark_gpe_for_wake();
537 
538 	return 0;
539 }
540 
541 static struct acpi_scan_handler lps0_handler = {
542 	.ids = lps0_device_ids,
543 	.attach = lps0_device_attach,
544 };
545 
546 static int acpi_s2idle_begin_lps0(void)
547 {
548 	if (lps0_device_handle && !sleep_no_lps0 && check_lps0_constraints &&
549 	    !lpi_constraints_table) {
550 		if (acpi_s2idle_vendor_amd())
551 			lpi_device_get_constraints_amd();
552 		else
553 			lpi_device_get_constraints();
554 
555 		/*
556 		 * Try to retrieve the constraints only once because failures
557 		 * to do so usually are sticky.
558 		 */
559 		if (!lpi_constraints_table)
560 			lpi_constraints_table = ERR_PTR(-ENODATA);
561 	}
562 
563 	return acpi_s2idle_begin();
564 }
565 
566 static int acpi_s2idle_prepare_late_lps0(void)
567 {
568 	struct acpi_s2idle_dev_ops *handler;
569 
570 	if (!lps0_device_handle || sleep_no_lps0)
571 		return 0;
572 
573 	if (check_lps0_constraints)
574 		lpi_check_constraints();
575 
576 	/* Screen off */
577 	if (lps0_dsm_func_mask > 0)
578 		acpi_sleep_run_lps0_dsm(acpi_s2idle_vendor_amd() ?
579 					ACPI_LPS0_SCREEN_OFF_AMD :
580 					ACPI_LPS0_SCREEN_OFF,
581 					lps0_dsm_func_mask, lps0_dsm_guid);
582 
583 	if (lps0_dsm_func_mask_microsoft > 0)
584 		acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF,
585 				lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
586 
587 	/* LPS0 entry */
588 	if (lps0_dsm_func_mask > 0 && acpi_s2idle_vendor_amd())
589 		acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY_AMD,
590 					lps0_dsm_func_mask, lps0_dsm_guid);
591 
592 	if (lps0_dsm_func_mask_microsoft > 0) {
593 		/* Modern Standby entry */
594 		acpi_sleep_run_lps0_dsm(ACPI_LPS0_MS_ENTRY,
595 				lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
596 		acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY,
597 				lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
598 	}
599 
600 	if (lps0_dsm_func_mask > 0 && !acpi_s2idle_vendor_amd())
601 		acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY,
602 					lps0_dsm_func_mask, lps0_dsm_guid);
603 
604 	list_for_each_entry(handler, &lps0_s2idle_devops_head, list_node) {
605 		if (handler->prepare)
606 			handler->prepare();
607 	}
608 
609 	return 0;
610 }
611 
612 static void acpi_s2idle_check_lps0(void)
613 {
614 	struct acpi_s2idle_dev_ops *handler;
615 
616 	if (!lps0_device_handle || sleep_no_lps0)
617 		return;
618 
619 	list_for_each_entry(handler, &lps0_s2idle_devops_head, list_node) {
620 		if (handler->check)
621 			handler->check();
622 	}
623 }
624 
625 static void acpi_s2idle_restore_early_lps0(void)
626 {
627 	struct acpi_s2idle_dev_ops *handler;
628 
629 	if (!lps0_device_handle || sleep_no_lps0)
630 		return;
631 
632 	list_for_each_entry(handler, &lps0_s2idle_devops_head, list_node)
633 		if (handler->restore)
634 			handler->restore();
635 
636 	/* LPS0 exit */
637 	if (lps0_dsm_func_mask > 0)
638 		acpi_sleep_run_lps0_dsm(acpi_s2idle_vendor_amd() ?
639 					ACPI_LPS0_EXIT_AMD :
640 					ACPI_LPS0_EXIT,
641 					lps0_dsm_func_mask, lps0_dsm_guid);
642 
643 	if (lps0_dsm_func_mask_microsoft > 0) {
644 		acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT,
645 				lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
646 		/* Intent to turn on display */
647 		acpi_sleep_run_lps0_dsm(ACPI_MS_TURN_ON_DISPLAY,
648 				lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
649 		/* Modern Standby exit */
650 		acpi_sleep_run_lps0_dsm(ACPI_LPS0_MS_EXIT,
651 				lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
652 	}
653 
654 	/* Screen on */
655 	if (lps0_dsm_func_mask_microsoft > 0)
656 		acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON,
657 				lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
658 	if (lps0_dsm_func_mask > 0)
659 		acpi_sleep_run_lps0_dsm(acpi_s2idle_vendor_amd() ?
660 					ACPI_LPS0_SCREEN_ON_AMD :
661 					ACPI_LPS0_SCREEN_ON,
662 					lps0_dsm_func_mask, lps0_dsm_guid);
663 }
664 
665 static const struct platform_s2idle_ops acpi_s2idle_ops_lps0 = {
666 	.begin = acpi_s2idle_begin_lps0,
667 	.prepare = acpi_s2idle_prepare,
668 	.prepare_late = acpi_s2idle_prepare_late_lps0,
669 	.check = acpi_s2idle_check_lps0,
670 	.wake = acpi_s2idle_wake,
671 	.restore_early = acpi_s2idle_restore_early_lps0,
672 	.restore = acpi_s2idle_restore,
673 	.end = acpi_s2idle_end,
674 };
675 
676 void __init acpi_s2idle_setup(void)
677 {
678 	acpi_scan_add_handler(&lps0_handler);
679 	s2idle_set_ops(&acpi_s2idle_ops_lps0);
680 	acpi_setup_ixx_gpes();
681 }
682 
683 int acpi_register_lps0_dev(struct acpi_s2idle_dev_ops *arg)
684 {
685 	unsigned int sleep_flags;
686 
687 	if (!lps0_device_handle || sleep_no_lps0)
688 		return -ENODEV;
689 
690 	sleep_flags = lock_system_sleep();
691 	list_add(&arg->list_node, &lps0_s2idle_devops_head);
692 	unlock_system_sleep(sleep_flags);
693 
694 	return 0;
695 }
696 EXPORT_SYMBOL_GPL(acpi_register_lps0_dev);
697 
698 void acpi_unregister_lps0_dev(struct acpi_s2idle_dev_ops *arg)
699 {
700 	unsigned int sleep_flags;
701 
702 	if (!lps0_device_handle || sleep_no_lps0)
703 		return;
704 
705 	sleep_flags = lock_system_sleep();
706 	list_del(&arg->list_node);
707 	unlock_system_sleep(sleep_flags);
708 }
709 EXPORT_SYMBOL_GPL(acpi_unregister_lps0_dev);
710 
711 #endif /* CONFIG_SUSPEND */
712