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