1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * sleep.c - ACPI sleep support.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (c) 2005 Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
6*4882a593Smuzhiyun * Copyright (c) 2004 David Shaohua Li <shaohua.li@intel.com>
7*4882a593Smuzhiyun * Copyright (c) 2000-2003 Patrick Mochel
8*4882a593Smuzhiyun * Copyright (c) 2003 Open Source Development Lab
9*4882a593Smuzhiyun */
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #include <linux/delay.h>
12*4882a593Smuzhiyun #include <linux/irq.h>
13*4882a593Smuzhiyun #include <linux/dmi.h>
14*4882a593Smuzhiyun #include <linux/device.h>
15*4882a593Smuzhiyun #include <linux/interrupt.h>
16*4882a593Smuzhiyun #include <linux/suspend.h>
17*4882a593Smuzhiyun #include <linux/reboot.h>
18*4882a593Smuzhiyun #include <linux/acpi.h>
19*4882a593Smuzhiyun #include <linux/module.h>
20*4882a593Smuzhiyun #include <linux/syscore_ops.h>
21*4882a593Smuzhiyun #include <asm/io.h>
22*4882a593Smuzhiyun #include <trace/events/power.h>
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun #include "internal.h"
25*4882a593Smuzhiyun #include "sleep.h"
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun /*
28*4882a593Smuzhiyun * Some HW-full platforms do not have _S5, so they may need
29*4882a593Smuzhiyun * to leverage efi power off for a shutdown.
30*4882a593Smuzhiyun */
31*4882a593Smuzhiyun bool acpi_no_s5;
32*4882a593Smuzhiyun static u8 sleep_states[ACPI_S_STATE_COUNT];
33*4882a593Smuzhiyun
acpi_sleep_tts_switch(u32 acpi_state)34*4882a593Smuzhiyun static void acpi_sleep_tts_switch(u32 acpi_state)
35*4882a593Smuzhiyun {
36*4882a593Smuzhiyun acpi_status status;
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun status = acpi_execute_simple_method(NULL, "\\_TTS", acpi_state);
39*4882a593Smuzhiyun if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
40*4882a593Smuzhiyun /*
41*4882a593Smuzhiyun * OS can't evaluate the _TTS object correctly. Some warning
42*4882a593Smuzhiyun * message will be printed. But it won't break anything.
43*4882a593Smuzhiyun */
44*4882a593Smuzhiyun printk(KERN_NOTICE "Failure in evaluating _TTS object\n");
45*4882a593Smuzhiyun }
46*4882a593Smuzhiyun }
47*4882a593Smuzhiyun
tts_notify_reboot(struct notifier_block * this,unsigned long code,void * x)48*4882a593Smuzhiyun static int tts_notify_reboot(struct notifier_block *this,
49*4882a593Smuzhiyun unsigned long code, void *x)
50*4882a593Smuzhiyun {
51*4882a593Smuzhiyun acpi_sleep_tts_switch(ACPI_STATE_S5);
52*4882a593Smuzhiyun return NOTIFY_DONE;
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun static struct notifier_block tts_notifier = {
56*4882a593Smuzhiyun .notifier_call = tts_notify_reboot,
57*4882a593Smuzhiyun .next = NULL,
58*4882a593Smuzhiyun .priority = 0,
59*4882a593Smuzhiyun };
60*4882a593Smuzhiyun
acpi_sleep_prepare(u32 acpi_state)61*4882a593Smuzhiyun static int acpi_sleep_prepare(u32 acpi_state)
62*4882a593Smuzhiyun {
63*4882a593Smuzhiyun #ifdef CONFIG_ACPI_SLEEP
64*4882a593Smuzhiyun unsigned long acpi_wakeup_address;
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun /* do we have a wakeup address for S2 and S3? */
67*4882a593Smuzhiyun if (acpi_state == ACPI_STATE_S3) {
68*4882a593Smuzhiyun acpi_wakeup_address = acpi_get_wakeup_address();
69*4882a593Smuzhiyun if (!acpi_wakeup_address)
70*4882a593Smuzhiyun return -EFAULT;
71*4882a593Smuzhiyun acpi_set_waking_vector(acpi_wakeup_address);
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun ACPI_FLUSH_CPU_CACHE();
75*4882a593Smuzhiyun #endif
76*4882a593Smuzhiyun printk(KERN_INFO PREFIX "Preparing to enter system sleep state S%d\n",
77*4882a593Smuzhiyun acpi_state);
78*4882a593Smuzhiyun acpi_enable_wakeup_devices(acpi_state);
79*4882a593Smuzhiyun acpi_enter_sleep_state_prep(acpi_state);
80*4882a593Smuzhiyun return 0;
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun
acpi_sleep_state_supported(u8 sleep_state)83*4882a593Smuzhiyun bool acpi_sleep_state_supported(u8 sleep_state)
84*4882a593Smuzhiyun {
85*4882a593Smuzhiyun acpi_status status;
86*4882a593Smuzhiyun u8 type_a, type_b;
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun status = acpi_get_sleep_type_data(sleep_state, &type_a, &type_b);
89*4882a593Smuzhiyun return ACPI_SUCCESS(status) && (!acpi_gbl_reduced_hardware
90*4882a593Smuzhiyun || (acpi_gbl_FADT.sleep_control.address
91*4882a593Smuzhiyun && acpi_gbl_FADT.sleep_status.address));
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun #ifdef CONFIG_ACPI_SLEEP
95*4882a593Smuzhiyun static bool sleep_no_lps0 __read_mostly;
96*4882a593Smuzhiyun module_param(sleep_no_lps0, bool, 0644);
97*4882a593Smuzhiyun MODULE_PARM_DESC(sleep_no_lps0, "Do not use the special LPS0 device interface");
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun static u32 acpi_target_sleep_state = ACPI_STATE_S0;
100*4882a593Smuzhiyun
acpi_target_system_state(void)101*4882a593Smuzhiyun u32 acpi_target_system_state(void)
102*4882a593Smuzhiyun {
103*4882a593Smuzhiyun return acpi_target_sleep_state;
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(acpi_target_system_state);
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun static bool pwr_btn_event_pending;
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun /*
110*4882a593Smuzhiyun * The ACPI specification wants us to save NVS memory regions during hibernation
111*4882a593Smuzhiyun * and to restore them during the subsequent resume. Windows does that also for
112*4882a593Smuzhiyun * suspend to RAM. However, it is known that this mechanism does not work on
113*4882a593Smuzhiyun * all machines, so we allow the user to disable it with the help of the
114*4882a593Smuzhiyun * 'acpi_sleep=nonvs' kernel command line option.
115*4882a593Smuzhiyun */
116*4882a593Smuzhiyun static bool nvs_nosave;
117*4882a593Smuzhiyun
acpi_nvs_nosave(void)118*4882a593Smuzhiyun void __init acpi_nvs_nosave(void)
119*4882a593Smuzhiyun {
120*4882a593Smuzhiyun nvs_nosave = true;
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun /*
124*4882a593Smuzhiyun * The ACPI specification wants us to save NVS memory regions during hibernation
125*4882a593Smuzhiyun * but says nothing about saving NVS during S3. Not all versions of Windows
126*4882a593Smuzhiyun * save NVS on S3 suspend either, and it is clear that not all systems need
127*4882a593Smuzhiyun * NVS to be saved at S3 time. To improve suspend/resume time, allow the
128*4882a593Smuzhiyun * user to disable saving NVS on S3 if their system does not require it, but
129*4882a593Smuzhiyun * continue to save/restore NVS for S4 as specified.
130*4882a593Smuzhiyun */
131*4882a593Smuzhiyun static bool nvs_nosave_s3;
132*4882a593Smuzhiyun
acpi_nvs_nosave_s3(void)133*4882a593Smuzhiyun void __init acpi_nvs_nosave_s3(void)
134*4882a593Smuzhiyun {
135*4882a593Smuzhiyun nvs_nosave_s3 = true;
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun
init_nvs_save_s3(const struct dmi_system_id * d)138*4882a593Smuzhiyun static int __init init_nvs_save_s3(const struct dmi_system_id *d)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun nvs_nosave_s3 = false;
141*4882a593Smuzhiyun return 0;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun /*
145*4882a593Smuzhiyun * ACPI 1.0 wants us to execute _PTS before suspending devices, so we allow the
146*4882a593Smuzhiyun * user to request that behavior by using the 'acpi_old_suspend_ordering'
147*4882a593Smuzhiyun * kernel command line option that causes the following variable to be set.
148*4882a593Smuzhiyun */
149*4882a593Smuzhiyun static bool old_suspend_ordering;
150*4882a593Smuzhiyun
acpi_old_suspend_ordering(void)151*4882a593Smuzhiyun void __init acpi_old_suspend_ordering(void)
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun old_suspend_ordering = true;
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun
init_old_suspend_ordering(const struct dmi_system_id * d)156*4882a593Smuzhiyun static int __init init_old_suspend_ordering(const struct dmi_system_id *d)
157*4882a593Smuzhiyun {
158*4882a593Smuzhiyun acpi_old_suspend_ordering();
159*4882a593Smuzhiyun return 0;
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun
init_nvs_nosave(const struct dmi_system_id * d)162*4882a593Smuzhiyun static int __init init_nvs_nosave(const struct dmi_system_id *d)
163*4882a593Smuzhiyun {
164*4882a593Smuzhiyun acpi_nvs_nosave();
165*4882a593Smuzhiyun return 0;
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun static bool acpi_sleep_default_s3;
169*4882a593Smuzhiyun
init_default_s3(const struct dmi_system_id * d)170*4882a593Smuzhiyun static int __init init_default_s3(const struct dmi_system_id *d)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun acpi_sleep_default_s3 = true;
173*4882a593Smuzhiyun return 0;
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun static const struct dmi_system_id acpisleep_dmi_table[] __initconst = {
177*4882a593Smuzhiyun {
178*4882a593Smuzhiyun .callback = init_old_suspend_ordering,
179*4882a593Smuzhiyun .ident = "Abit KN9 (nForce4 variant)",
180*4882a593Smuzhiyun .matches = {
181*4882a593Smuzhiyun DMI_MATCH(DMI_BOARD_VENDOR, "http://www.abit.com.tw/"),
182*4882a593Smuzhiyun DMI_MATCH(DMI_BOARD_NAME, "KN9 Series(NF-CK804)"),
183*4882a593Smuzhiyun },
184*4882a593Smuzhiyun },
185*4882a593Smuzhiyun {
186*4882a593Smuzhiyun .callback = init_old_suspend_ordering,
187*4882a593Smuzhiyun .ident = "HP xw4600 Workstation",
188*4882a593Smuzhiyun .matches = {
189*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
190*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "HP xw4600 Workstation"),
191*4882a593Smuzhiyun },
192*4882a593Smuzhiyun },
193*4882a593Smuzhiyun {
194*4882a593Smuzhiyun .callback = init_old_suspend_ordering,
195*4882a593Smuzhiyun .ident = "Asus Pundit P1-AH2 (M2N8L motherboard)",
196*4882a593Smuzhiyun .matches = {
197*4882a593Smuzhiyun DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTek Computer INC."),
198*4882a593Smuzhiyun DMI_MATCH(DMI_BOARD_NAME, "M2N8L"),
199*4882a593Smuzhiyun },
200*4882a593Smuzhiyun },
201*4882a593Smuzhiyun {
202*4882a593Smuzhiyun .callback = init_old_suspend_ordering,
203*4882a593Smuzhiyun .ident = "Panasonic CF51-2L",
204*4882a593Smuzhiyun .matches = {
205*4882a593Smuzhiyun DMI_MATCH(DMI_BOARD_VENDOR,
206*4882a593Smuzhiyun "Matsushita Electric Industrial Co.,Ltd."),
207*4882a593Smuzhiyun DMI_MATCH(DMI_BOARD_NAME, "CF51-2L"),
208*4882a593Smuzhiyun },
209*4882a593Smuzhiyun },
210*4882a593Smuzhiyun {
211*4882a593Smuzhiyun .callback = init_nvs_nosave,
212*4882a593Smuzhiyun .ident = "Sony Vaio VGN-FW41E_H",
213*4882a593Smuzhiyun .matches = {
214*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
215*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW41E_H"),
216*4882a593Smuzhiyun },
217*4882a593Smuzhiyun },
218*4882a593Smuzhiyun {
219*4882a593Smuzhiyun .callback = init_nvs_nosave,
220*4882a593Smuzhiyun .ident = "Sony Vaio VGN-FW21E",
221*4882a593Smuzhiyun .matches = {
222*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
223*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW21E"),
224*4882a593Smuzhiyun },
225*4882a593Smuzhiyun },
226*4882a593Smuzhiyun {
227*4882a593Smuzhiyun .callback = init_nvs_nosave,
228*4882a593Smuzhiyun .ident = "Sony Vaio VGN-FW21M",
229*4882a593Smuzhiyun .matches = {
230*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
231*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW21M"),
232*4882a593Smuzhiyun },
233*4882a593Smuzhiyun },
234*4882a593Smuzhiyun {
235*4882a593Smuzhiyun .callback = init_nvs_nosave,
236*4882a593Smuzhiyun .ident = "Sony Vaio VPCEB17FX",
237*4882a593Smuzhiyun .matches = {
238*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
239*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB17FX"),
240*4882a593Smuzhiyun },
241*4882a593Smuzhiyun },
242*4882a593Smuzhiyun {
243*4882a593Smuzhiyun .callback = init_nvs_nosave,
244*4882a593Smuzhiyun .ident = "Sony Vaio VGN-SR11M",
245*4882a593Smuzhiyun .matches = {
246*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
247*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR11M"),
248*4882a593Smuzhiyun },
249*4882a593Smuzhiyun },
250*4882a593Smuzhiyun {
251*4882a593Smuzhiyun .callback = init_nvs_nosave,
252*4882a593Smuzhiyun .ident = "Everex StepNote Series",
253*4882a593Smuzhiyun .matches = {
254*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "Everex Systems, Inc."),
255*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "Everex StepNote Series"),
256*4882a593Smuzhiyun },
257*4882a593Smuzhiyun },
258*4882a593Smuzhiyun {
259*4882a593Smuzhiyun .callback = init_nvs_nosave,
260*4882a593Smuzhiyun .ident = "Sony Vaio VPCEB1Z1E",
261*4882a593Smuzhiyun .matches = {
262*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
263*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB1Z1E"),
264*4882a593Smuzhiyun },
265*4882a593Smuzhiyun },
266*4882a593Smuzhiyun {
267*4882a593Smuzhiyun .callback = init_nvs_nosave,
268*4882a593Smuzhiyun .ident = "Sony Vaio VGN-NW130D",
269*4882a593Smuzhiyun .matches = {
270*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
271*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "VGN-NW130D"),
272*4882a593Smuzhiyun },
273*4882a593Smuzhiyun },
274*4882a593Smuzhiyun {
275*4882a593Smuzhiyun .callback = init_nvs_nosave,
276*4882a593Smuzhiyun .ident = "Sony Vaio VPCCW29FX",
277*4882a593Smuzhiyun .matches = {
278*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
279*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "VPCCW29FX"),
280*4882a593Smuzhiyun },
281*4882a593Smuzhiyun },
282*4882a593Smuzhiyun {
283*4882a593Smuzhiyun .callback = init_nvs_nosave,
284*4882a593Smuzhiyun .ident = "Averatec AV1020-ED2",
285*4882a593Smuzhiyun .matches = {
286*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "AVERATEC"),
287*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "1000 Series"),
288*4882a593Smuzhiyun },
289*4882a593Smuzhiyun },
290*4882a593Smuzhiyun {
291*4882a593Smuzhiyun .callback = init_old_suspend_ordering,
292*4882a593Smuzhiyun .ident = "Asus A8N-SLI DELUXE",
293*4882a593Smuzhiyun .matches = {
294*4882a593Smuzhiyun DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
295*4882a593Smuzhiyun DMI_MATCH(DMI_BOARD_NAME, "A8N-SLI DELUXE"),
296*4882a593Smuzhiyun },
297*4882a593Smuzhiyun },
298*4882a593Smuzhiyun {
299*4882a593Smuzhiyun .callback = init_old_suspend_ordering,
300*4882a593Smuzhiyun .ident = "Asus A8N-SLI Premium",
301*4882a593Smuzhiyun .matches = {
302*4882a593Smuzhiyun DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
303*4882a593Smuzhiyun DMI_MATCH(DMI_BOARD_NAME, "A8N-SLI Premium"),
304*4882a593Smuzhiyun },
305*4882a593Smuzhiyun },
306*4882a593Smuzhiyun {
307*4882a593Smuzhiyun .callback = init_nvs_nosave,
308*4882a593Smuzhiyun .ident = "Sony Vaio VGN-SR26GN_P",
309*4882a593Smuzhiyun .matches = {
310*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
311*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR26GN_P"),
312*4882a593Smuzhiyun },
313*4882a593Smuzhiyun },
314*4882a593Smuzhiyun {
315*4882a593Smuzhiyun .callback = init_nvs_nosave,
316*4882a593Smuzhiyun .ident = "Sony Vaio VPCEB1S1E",
317*4882a593Smuzhiyun .matches = {
318*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
319*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB1S1E"),
320*4882a593Smuzhiyun },
321*4882a593Smuzhiyun },
322*4882a593Smuzhiyun {
323*4882a593Smuzhiyun .callback = init_nvs_nosave,
324*4882a593Smuzhiyun .ident = "Sony Vaio VGN-FW520F",
325*4882a593Smuzhiyun .matches = {
326*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
327*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW520F"),
328*4882a593Smuzhiyun },
329*4882a593Smuzhiyun },
330*4882a593Smuzhiyun {
331*4882a593Smuzhiyun .callback = init_nvs_nosave,
332*4882a593Smuzhiyun .ident = "Asus K54C",
333*4882a593Smuzhiyun .matches = {
334*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
335*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "K54C"),
336*4882a593Smuzhiyun },
337*4882a593Smuzhiyun },
338*4882a593Smuzhiyun {
339*4882a593Smuzhiyun .callback = init_nvs_nosave,
340*4882a593Smuzhiyun .ident = "Asus K54HR",
341*4882a593Smuzhiyun .matches = {
342*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
343*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "K54HR"),
344*4882a593Smuzhiyun },
345*4882a593Smuzhiyun },
346*4882a593Smuzhiyun {
347*4882a593Smuzhiyun .callback = init_nvs_save_s3,
348*4882a593Smuzhiyun .ident = "Asus 1025C",
349*4882a593Smuzhiyun .matches = {
350*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
351*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "1025C"),
352*4882a593Smuzhiyun },
353*4882a593Smuzhiyun },
354*4882a593Smuzhiyun /*
355*4882a593Smuzhiyun * https://bugzilla.kernel.org/show_bug.cgi?id=189431
356*4882a593Smuzhiyun * Lenovo G50-45 is a platform later than 2012, but needs nvs memory
357*4882a593Smuzhiyun * saving during S3.
358*4882a593Smuzhiyun */
359*4882a593Smuzhiyun {
360*4882a593Smuzhiyun .callback = init_nvs_save_s3,
361*4882a593Smuzhiyun .ident = "Lenovo G50-45",
362*4882a593Smuzhiyun .matches = {
363*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
364*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "80E3"),
365*4882a593Smuzhiyun },
366*4882a593Smuzhiyun },
367*4882a593Smuzhiyun {
368*4882a593Smuzhiyun .callback = init_nvs_save_s3,
369*4882a593Smuzhiyun .ident = "Lenovo G40-45",
370*4882a593Smuzhiyun .matches = {
371*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
372*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "80E1"),
373*4882a593Smuzhiyun },
374*4882a593Smuzhiyun },
375*4882a593Smuzhiyun /*
376*4882a593Smuzhiyun * ThinkPad X1 Tablet(2016) cannot do suspend-to-idle using
377*4882a593Smuzhiyun * the Low Power S0 Idle firmware interface (see
378*4882a593Smuzhiyun * https://bugzilla.kernel.org/show_bug.cgi?id=199057).
379*4882a593Smuzhiyun */
380*4882a593Smuzhiyun {
381*4882a593Smuzhiyun .callback = init_default_s3,
382*4882a593Smuzhiyun .ident = "ThinkPad X1 Tablet(2016)",
383*4882a593Smuzhiyun .matches = {
384*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
385*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "20GGA00L00"),
386*4882a593Smuzhiyun },
387*4882a593Smuzhiyun },
388*4882a593Smuzhiyun /*
389*4882a593Smuzhiyun * ASUS B1400CEAE hangs on resume from suspend (see
390*4882a593Smuzhiyun * https://bugzilla.kernel.org/show_bug.cgi?id=215742).
391*4882a593Smuzhiyun */
392*4882a593Smuzhiyun {
393*4882a593Smuzhiyun .callback = init_default_s3,
394*4882a593Smuzhiyun .ident = "ASUS B1400CEAE",
395*4882a593Smuzhiyun .matches = {
396*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
397*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "ASUS EXPERTBOOK B1400CEAE"),
398*4882a593Smuzhiyun },
399*4882a593Smuzhiyun },
400*4882a593Smuzhiyun {},
401*4882a593Smuzhiyun };
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun static bool ignore_blacklist;
404*4882a593Smuzhiyun
acpi_sleep_no_blacklist(void)405*4882a593Smuzhiyun void __init acpi_sleep_no_blacklist(void)
406*4882a593Smuzhiyun {
407*4882a593Smuzhiyun ignore_blacklist = true;
408*4882a593Smuzhiyun }
409*4882a593Smuzhiyun
acpi_sleep_dmi_check(void)410*4882a593Smuzhiyun static void __init acpi_sleep_dmi_check(void)
411*4882a593Smuzhiyun {
412*4882a593Smuzhiyun if (ignore_blacklist)
413*4882a593Smuzhiyun return;
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun if (dmi_get_bios_year() >= 2012)
416*4882a593Smuzhiyun acpi_nvs_nosave_s3();
417*4882a593Smuzhiyun
418*4882a593Smuzhiyun dmi_check_system(acpisleep_dmi_table);
419*4882a593Smuzhiyun }
420*4882a593Smuzhiyun
421*4882a593Smuzhiyun /**
422*4882a593Smuzhiyun * acpi_pm_freeze - Disable the GPEs and suspend EC transactions.
423*4882a593Smuzhiyun */
acpi_pm_freeze(void)424*4882a593Smuzhiyun static int acpi_pm_freeze(void)
425*4882a593Smuzhiyun {
426*4882a593Smuzhiyun acpi_disable_all_gpes();
427*4882a593Smuzhiyun acpi_os_wait_events_complete();
428*4882a593Smuzhiyun acpi_ec_block_transactions();
429*4882a593Smuzhiyun return 0;
430*4882a593Smuzhiyun }
431*4882a593Smuzhiyun
432*4882a593Smuzhiyun /**
433*4882a593Smuzhiyun * acpi_pre_suspend - Enable wakeup devices, "freeze" EC and save NVS.
434*4882a593Smuzhiyun */
acpi_pm_pre_suspend(void)435*4882a593Smuzhiyun static int acpi_pm_pre_suspend(void)
436*4882a593Smuzhiyun {
437*4882a593Smuzhiyun acpi_pm_freeze();
438*4882a593Smuzhiyun return suspend_nvs_save();
439*4882a593Smuzhiyun }
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun /**
442*4882a593Smuzhiyun * __acpi_pm_prepare - Prepare the platform to enter the target state.
443*4882a593Smuzhiyun *
444*4882a593Smuzhiyun * If necessary, set the firmware waking vector and do arch-specific
445*4882a593Smuzhiyun * nastiness to get the wakeup code to the waking vector.
446*4882a593Smuzhiyun */
__acpi_pm_prepare(void)447*4882a593Smuzhiyun static int __acpi_pm_prepare(void)
448*4882a593Smuzhiyun {
449*4882a593Smuzhiyun int error = acpi_sleep_prepare(acpi_target_sleep_state);
450*4882a593Smuzhiyun if (error)
451*4882a593Smuzhiyun acpi_target_sleep_state = ACPI_STATE_S0;
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun return error;
454*4882a593Smuzhiyun }
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun /**
457*4882a593Smuzhiyun * acpi_pm_prepare - Prepare the platform to enter the target sleep
458*4882a593Smuzhiyun * state and disable the GPEs.
459*4882a593Smuzhiyun */
acpi_pm_prepare(void)460*4882a593Smuzhiyun static int acpi_pm_prepare(void)
461*4882a593Smuzhiyun {
462*4882a593Smuzhiyun int error = __acpi_pm_prepare();
463*4882a593Smuzhiyun if (!error)
464*4882a593Smuzhiyun error = acpi_pm_pre_suspend();
465*4882a593Smuzhiyun
466*4882a593Smuzhiyun return error;
467*4882a593Smuzhiyun }
468*4882a593Smuzhiyun
469*4882a593Smuzhiyun /**
470*4882a593Smuzhiyun * acpi_pm_finish - Instruct the platform to leave a sleep state.
471*4882a593Smuzhiyun *
472*4882a593Smuzhiyun * This is called after we wake back up (or if entering the sleep state
473*4882a593Smuzhiyun * failed).
474*4882a593Smuzhiyun */
acpi_pm_finish(void)475*4882a593Smuzhiyun static void acpi_pm_finish(void)
476*4882a593Smuzhiyun {
477*4882a593Smuzhiyun struct acpi_device *pwr_btn_adev;
478*4882a593Smuzhiyun u32 acpi_state = acpi_target_sleep_state;
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun acpi_ec_unblock_transactions();
481*4882a593Smuzhiyun suspend_nvs_free();
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun if (acpi_state == ACPI_STATE_S0)
484*4882a593Smuzhiyun return;
485*4882a593Smuzhiyun
486*4882a593Smuzhiyun printk(KERN_INFO PREFIX "Waking up from system sleep state S%d\n",
487*4882a593Smuzhiyun acpi_state);
488*4882a593Smuzhiyun acpi_disable_wakeup_devices(acpi_state);
489*4882a593Smuzhiyun acpi_leave_sleep_state(acpi_state);
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun /* reset firmware waking vector */
492*4882a593Smuzhiyun acpi_set_waking_vector(0);
493*4882a593Smuzhiyun
494*4882a593Smuzhiyun acpi_target_sleep_state = ACPI_STATE_S0;
495*4882a593Smuzhiyun
496*4882a593Smuzhiyun acpi_resume_power_resources();
497*4882a593Smuzhiyun
498*4882a593Smuzhiyun /* If we were woken with the fixed power button, provide a small
499*4882a593Smuzhiyun * hint to userspace in the form of a wakeup event on the fixed power
500*4882a593Smuzhiyun * button device (if it can be found).
501*4882a593Smuzhiyun *
502*4882a593Smuzhiyun * We delay the event generation til now, as the PM layer requires
503*4882a593Smuzhiyun * timekeeping to be running before we generate events. */
504*4882a593Smuzhiyun if (!pwr_btn_event_pending)
505*4882a593Smuzhiyun return;
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun pwr_btn_event_pending = false;
508*4882a593Smuzhiyun pwr_btn_adev = acpi_dev_get_first_match_dev(ACPI_BUTTON_HID_POWERF,
509*4882a593Smuzhiyun NULL, -1);
510*4882a593Smuzhiyun if (pwr_btn_adev) {
511*4882a593Smuzhiyun pm_wakeup_event(&pwr_btn_adev->dev, 0);
512*4882a593Smuzhiyun acpi_dev_put(pwr_btn_adev);
513*4882a593Smuzhiyun }
514*4882a593Smuzhiyun }
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun /**
517*4882a593Smuzhiyun * acpi_pm_start - Start system PM transition.
518*4882a593Smuzhiyun */
acpi_pm_start(u32 acpi_state)519*4882a593Smuzhiyun static void acpi_pm_start(u32 acpi_state)
520*4882a593Smuzhiyun {
521*4882a593Smuzhiyun acpi_target_sleep_state = acpi_state;
522*4882a593Smuzhiyun acpi_sleep_tts_switch(acpi_target_sleep_state);
523*4882a593Smuzhiyun acpi_scan_lock_acquire();
524*4882a593Smuzhiyun }
525*4882a593Smuzhiyun
526*4882a593Smuzhiyun /**
527*4882a593Smuzhiyun * acpi_pm_end - Finish up system PM transition.
528*4882a593Smuzhiyun */
acpi_pm_end(void)529*4882a593Smuzhiyun static void acpi_pm_end(void)
530*4882a593Smuzhiyun {
531*4882a593Smuzhiyun acpi_turn_off_unused_power_resources();
532*4882a593Smuzhiyun acpi_scan_lock_release();
533*4882a593Smuzhiyun /*
534*4882a593Smuzhiyun * This is necessary in case acpi_pm_finish() is not called during a
535*4882a593Smuzhiyun * failing transition to a sleep state.
536*4882a593Smuzhiyun */
537*4882a593Smuzhiyun acpi_target_sleep_state = ACPI_STATE_S0;
538*4882a593Smuzhiyun acpi_sleep_tts_switch(acpi_target_sleep_state);
539*4882a593Smuzhiyun }
540*4882a593Smuzhiyun #else /* !CONFIG_ACPI_SLEEP */
541*4882a593Smuzhiyun #define sleep_no_lps0 (1)
542*4882a593Smuzhiyun #define acpi_target_sleep_state ACPI_STATE_S0
543*4882a593Smuzhiyun #define acpi_sleep_default_s3 (1)
acpi_sleep_dmi_check(void)544*4882a593Smuzhiyun static inline void acpi_sleep_dmi_check(void) {}
545*4882a593Smuzhiyun #endif /* CONFIG_ACPI_SLEEP */
546*4882a593Smuzhiyun
547*4882a593Smuzhiyun #ifdef CONFIG_SUSPEND
548*4882a593Smuzhiyun static u32 acpi_suspend_states[] = {
549*4882a593Smuzhiyun [PM_SUSPEND_ON] = ACPI_STATE_S0,
550*4882a593Smuzhiyun [PM_SUSPEND_STANDBY] = ACPI_STATE_S1,
551*4882a593Smuzhiyun [PM_SUSPEND_MEM] = ACPI_STATE_S3,
552*4882a593Smuzhiyun [PM_SUSPEND_MAX] = ACPI_STATE_S5
553*4882a593Smuzhiyun };
554*4882a593Smuzhiyun
555*4882a593Smuzhiyun /**
556*4882a593Smuzhiyun * acpi_suspend_begin - Set the target system sleep state to the state
557*4882a593Smuzhiyun * associated with given @pm_state, if supported.
558*4882a593Smuzhiyun */
acpi_suspend_begin(suspend_state_t pm_state)559*4882a593Smuzhiyun static int acpi_suspend_begin(suspend_state_t pm_state)
560*4882a593Smuzhiyun {
561*4882a593Smuzhiyun u32 acpi_state = acpi_suspend_states[pm_state];
562*4882a593Smuzhiyun int error;
563*4882a593Smuzhiyun
564*4882a593Smuzhiyun error = (nvs_nosave || nvs_nosave_s3) ? 0 : suspend_nvs_alloc();
565*4882a593Smuzhiyun if (error)
566*4882a593Smuzhiyun return error;
567*4882a593Smuzhiyun
568*4882a593Smuzhiyun if (!sleep_states[acpi_state]) {
569*4882a593Smuzhiyun pr_err("ACPI does not support sleep state S%u\n", acpi_state);
570*4882a593Smuzhiyun return -ENOSYS;
571*4882a593Smuzhiyun }
572*4882a593Smuzhiyun if (acpi_state > ACPI_STATE_S1)
573*4882a593Smuzhiyun pm_set_suspend_via_firmware();
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun acpi_pm_start(acpi_state);
576*4882a593Smuzhiyun return 0;
577*4882a593Smuzhiyun }
578*4882a593Smuzhiyun
579*4882a593Smuzhiyun /**
580*4882a593Smuzhiyun * acpi_suspend_enter - Actually enter a sleep state.
581*4882a593Smuzhiyun * @pm_state: ignored
582*4882a593Smuzhiyun *
583*4882a593Smuzhiyun * Flush caches and go to sleep. For STR we have to call arch-specific
584*4882a593Smuzhiyun * assembly, which in turn call acpi_enter_sleep_state().
585*4882a593Smuzhiyun * It's unfortunate, but it works. Please fix if you're feeling frisky.
586*4882a593Smuzhiyun */
acpi_suspend_enter(suspend_state_t pm_state)587*4882a593Smuzhiyun static int acpi_suspend_enter(suspend_state_t pm_state)
588*4882a593Smuzhiyun {
589*4882a593Smuzhiyun acpi_status status = AE_OK;
590*4882a593Smuzhiyun u32 acpi_state = acpi_target_sleep_state;
591*4882a593Smuzhiyun int error;
592*4882a593Smuzhiyun
593*4882a593Smuzhiyun ACPI_FLUSH_CPU_CACHE();
594*4882a593Smuzhiyun
595*4882a593Smuzhiyun trace_suspend_resume(TPS("acpi_suspend"), acpi_state, true);
596*4882a593Smuzhiyun switch (acpi_state) {
597*4882a593Smuzhiyun case ACPI_STATE_S1:
598*4882a593Smuzhiyun barrier();
599*4882a593Smuzhiyun status = acpi_enter_sleep_state(acpi_state);
600*4882a593Smuzhiyun break;
601*4882a593Smuzhiyun
602*4882a593Smuzhiyun case ACPI_STATE_S3:
603*4882a593Smuzhiyun if (!acpi_suspend_lowlevel)
604*4882a593Smuzhiyun return -ENOSYS;
605*4882a593Smuzhiyun error = acpi_suspend_lowlevel();
606*4882a593Smuzhiyun if (error)
607*4882a593Smuzhiyun return error;
608*4882a593Smuzhiyun pr_info(PREFIX "Low-level resume complete\n");
609*4882a593Smuzhiyun pm_set_resume_via_firmware();
610*4882a593Smuzhiyun break;
611*4882a593Smuzhiyun }
612*4882a593Smuzhiyun trace_suspend_resume(TPS("acpi_suspend"), acpi_state, false);
613*4882a593Smuzhiyun
614*4882a593Smuzhiyun /* This violates the spec but is required for bug compatibility. */
615*4882a593Smuzhiyun acpi_write_bit_register(ACPI_BITREG_SCI_ENABLE, 1);
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun /* Reprogram control registers */
618*4882a593Smuzhiyun acpi_leave_sleep_state_prep(acpi_state);
619*4882a593Smuzhiyun
620*4882a593Smuzhiyun /* ACPI 3.0 specs (P62) says that it's the responsibility
621*4882a593Smuzhiyun * of the OSPM to clear the status bit [ implying that the
622*4882a593Smuzhiyun * POWER_BUTTON event should not reach userspace ]
623*4882a593Smuzhiyun *
624*4882a593Smuzhiyun * However, we do generate a small hint for userspace in the form of
625*4882a593Smuzhiyun * a wakeup event. We flag this condition for now and generate the
626*4882a593Smuzhiyun * event later, as we're currently too early in resume to be able to
627*4882a593Smuzhiyun * generate wakeup events.
628*4882a593Smuzhiyun */
629*4882a593Smuzhiyun if (ACPI_SUCCESS(status) && (acpi_state == ACPI_STATE_S3)) {
630*4882a593Smuzhiyun acpi_event_status pwr_btn_status = ACPI_EVENT_FLAG_DISABLED;
631*4882a593Smuzhiyun
632*4882a593Smuzhiyun acpi_get_event_status(ACPI_EVENT_POWER_BUTTON, &pwr_btn_status);
633*4882a593Smuzhiyun
634*4882a593Smuzhiyun if (pwr_btn_status & ACPI_EVENT_FLAG_STATUS_SET) {
635*4882a593Smuzhiyun acpi_clear_event(ACPI_EVENT_POWER_BUTTON);
636*4882a593Smuzhiyun /* Flag for later */
637*4882a593Smuzhiyun pwr_btn_event_pending = true;
638*4882a593Smuzhiyun }
639*4882a593Smuzhiyun }
640*4882a593Smuzhiyun
641*4882a593Smuzhiyun /*
642*4882a593Smuzhiyun * Disable and clear GPE status before interrupt is enabled. Some GPEs
643*4882a593Smuzhiyun * (like wakeup GPE) haven't handler, this can avoid such GPE misfire.
644*4882a593Smuzhiyun * acpi_leave_sleep_state will reenable specific GPEs later
645*4882a593Smuzhiyun */
646*4882a593Smuzhiyun acpi_disable_all_gpes();
647*4882a593Smuzhiyun /* Allow EC transactions to happen. */
648*4882a593Smuzhiyun acpi_ec_unblock_transactions();
649*4882a593Smuzhiyun
650*4882a593Smuzhiyun suspend_nvs_restore();
651*4882a593Smuzhiyun
652*4882a593Smuzhiyun return ACPI_SUCCESS(status) ? 0 : -EFAULT;
653*4882a593Smuzhiyun }
654*4882a593Smuzhiyun
acpi_suspend_state_valid(suspend_state_t pm_state)655*4882a593Smuzhiyun static int acpi_suspend_state_valid(suspend_state_t pm_state)
656*4882a593Smuzhiyun {
657*4882a593Smuzhiyun u32 acpi_state;
658*4882a593Smuzhiyun
659*4882a593Smuzhiyun switch (pm_state) {
660*4882a593Smuzhiyun case PM_SUSPEND_ON:
661*4882a593Smuzhiyun case PM_SUSPEND_STANDBY:
662*4882a593Smuzhiyun case PM_SUSPEND_MEM:
663*4882a593Smuzhiyun acpi_state = acpi_suspend_states[pm_state];
664*4882a593Smuzhiyun
665*4882a593Smuzhiyun return sleep_states[acpi_state];
666*4882a593Smuzhiyun default:
667*4882a593Smuzhiyun return 0;
668*4882a593Smuzhiyun }
669*4882a593Smuzhiyun }
670*4882a593Smuzhiyun
671*4882a593Smuzhiyun static const struct platform_suspend_ops acpi_suspend_ops = {
672*4882a593Smuzhiyun .valid = acpi_suspend_state_valid,
673*4882a593Smuzhiyun .begin = acpi_suspend_begin,
674*4882a593Smuzhiyun .prepare_late = acpi_pm_prepare,
675*4882a593Smuzhiyun .enter = acpi_suspend_enter,
676*4882a593Smuzhiyun .wake = acpi_pm_finish,
677*4882a593Smuzhiyun .end = acpi_pm_end,
678*4882a593Smuzhiyun };
679*4882a593Smuzhiyun
680*4882a593Smuzhiyun /**
681*4882a593Smuzhiyun * acpi_suspend_begin_old - Set the target system sleep state to the
682*4882a593Smuzhiyun * state associated with given @pm_state, if supported, and
683*4882a593Smuzhiyun * execute the _PTS control method. This function is used if the
684*4882a593Smuzhiyun * pre-ACPI 2.0 suspend ordering has been requested.
685*4882a593Smuzhiyun */
acpi_suspend_begin_old(suspend_state_t pm_state)686*4882a593Smuzhiyun static int acpi_suspend_begin_old(suspend_state_t pm_state)
687*4882a593Smuzhiyun {
688*4882a593Smuzhiyun int error = acpi_suspend_begin(pm_state);
689*4882a593Smuzhiyun if (!error)
690*4882a593Smuzhiyun error = __acpi_pm_prepare();
691*4882a593Smuzhiyun
692*4882a593Smuzhiyun return error;
693*4882a593Smuzhiyun }
694*4882a593Smuzhiyun
695*4882a593Smuzhiyun /*
696*4882a593Smuzhiyun * The following callbacks are used if the pre-ACPI 2.0 suspend ordering has
697*4882a593Smuzhiyun * been requested.
698*4882a593Smuzhiyun */
699*4882a593Smuzhiyun static const struct platform_suspend_ops acpi_suspend_ops_old = {
700*4882a593Smuzhiyun .valid = acpi_suspend_state_valid,
701*4882a593Smuzhiyun .begin = acpi_suspend_begin_old,
702*4882a593Smuzhiyun .prepare_late = acpi_pm_pre_suspend,
703*4882a593Smuzhiyun .enter = acpi_suspend_enter,
704*4882a593Smuzhiyun .wake = acpi_pm_finish,
705*4882a593Smuzhiyun .end = acpi_pm_end,
706*4882a593Smuzhiyun .recover = acpi_pm_finish,
707*4882a593Smuzhiyun };
708*4882a593Smuzhiyun
709*4882a593Smuzhiyun static bool s2idle_wakeup;
710*4882a593Smuzhiyun
711*4882a593Smuzhiyun /*
712*4882a593Smuzhiyun * On platforms supporting the Low Power S0 Idle interface there is an ACPI
713*4882a593Smuzhiyun * device object with the PNP0D80 compatible device ID (System Power Management
714*4882a593Smuzhiyun * Controller) and a specific _DSM method under it. That method, if present,
715*4882a593Smuzhiyun * can be used to indicate to the platform that the OS is transitioning into a
716*4882a593Smuzhiyun * low-power state in which certain types of activity are not desirable or that
717*4882a593Smuzhiyun * it is leaving such a state, which allows the platform to adjust its operation
718*4882a593Smuzhiyun * mode accordingly.
719*4882a593Smuzhiyun */
720*4882a593Smuzhiyun static const struct acpi_device_id lps0_device_ids[] = {
721*4882a593Smuzhiyun {"PNP0D80", },
722*4882a593Smuzhiyun {"", },
723*4882a593Smuzhiyun };
724*4882a593Smuzhiyun
725*4882a593Smuzhiyun #define ACPI_LPS0_DSM_UUID "c4eb40a0-6cd2-11e2-bcfd-0800200c9a66"
726*4882a593Smuzhiyun
727*4882a593Smuzhiyun #define ACPI_LPS0_GET_DEVICE_CONSTRAINTS 1
728*4882a593Smuzhiyun #define ACPI_LPS0_SCREEN_OFF 3
729*4882a593Smuzhiyun #define ACPI_LPS0_SCREEN_ON 4
730*4882a593Smuzhiyun #define ACPI_LPS0_ENTRY 5
731*4882a593Smuzhiyun #define ACPI_LPS0_EXIT 6
732*4882a593Smuzhiyun
733*4882a593Smuzhiyun static acpi_handle lps0_device_handle;
734*4882a593Smuzhiyun static guid_t lps0_dsm_guid;
735*4882a593Smuzhiyun static char lps0_dsm_func_mask;
736*4882a593Smuzhiyun
737*4882a593Smuzhiyun /* Device constraint entry structure */
738*4882a593Smuzhiyun struct lpi_device_info {
739*4882a593Smuzhiyun char *name;
740*4882a593Smuzhiyun int enabled;
741*4882a593Smuzhiyun union acpi_object *package;
742*4882a593Smuzhiyun };
743*4882a593Smuzhiyun
744*4882a593Smuzhiyun /* Constraint package structure */
745*4882a593Smuzhiyun struct lpi_device_constraint {
746*4882a593Smuzhiyun int uid;
747*4882a593Smuzhiyun int min_dstate;
748*4882a593Smuzhiyun int function_states;
749*4882a593Smuzhiyun };
750*4882a593Smuzhiyun
751*4882a593Smuzhiyun struct lpi_constraints {
752*4882a593Smuzhiyun acpi_handle handle;
753*4882a593Smuzhiyun int min_dstate;
754*4882a593Smuzhiyun };
755*4882a593Smuzhiyun
756*4882a593Smuzhiyun static struct lpi_constraints *lpi_constraints_table;
757*4882a593Smuzhiyun static int lpi_constraints_table_size;
758*4882a593Smuzhiyun
lpi_device_get_constraints(void)759*4882a593Smuzhiyun static void lpi_device_get_constraints(void)
760*4882a593Smuzhiyun {
761*4882a593Smuzhiyun union acpi_object *out_obj;
762*4882a593Smuzhiyun int i;
763*4882a593Smuzhiyun
764*4882a593Smuzhiyun out_obj = acpi_evaluate_dsm_typed(lps0_device_handle, &lps0_dsm_guid,
765*4882a593Smuzhiyun 1, ACPI_LPS0_GET_DEVICE_CONSTRAINTS,
766*4882a593Smuzhiyun NULL, ACPI_TYPE_PACKAGE);
767*4882a593Smuzhiyun
768*4882a593Smuzhiyun acpi_handle_debug(lps0_device_handle, "_DSM function 1 eval %s\n",
769*4882a593Smuzhiyun out_obj ? "successful" : "failed");
770*4882a593Smuzhiyun
771*4882a593Smuzhiyun if (!out_obj)
772*4882a593Smuzhiyun return;
773*4882a593Smuzhiyun
774*4882a593Smuzhiyun lpi_constraints_table = kcalloc(out_obj->package.count,
775*4882a593Smuzhiyun sizeof(*lpi_constraints_table),
776*4882a593Smuzhiyun GFP_KERNEL);
777*4882a593Smuzhiyun if (!lpi_constraints_table)
778*4882a593Smuzhiyun goto free_acpi_buffer;
779*4882a593Smuzhiyun
780*4882a593Smuzhiyun acpi_handle_debug(lps0_device_handle, "LPI: constraints list begin:\n");
781*4882a593Smuzhiyun
782*4882a593Smuzhiyun for (i = 0; i < out_obj->package.count; i++) {
783*4882a593Smuzhiyun struct lpi_constraints *constraint;
784*4882a593Smuzhiyun acpi_status status;
785*4882a593Smuzhiyun union acpi_object *package = &out_obj->package.elements[i];
786*4882a593Smuzhiyun struct lpi_device_info info = { };
787*4882a593Smuzhiyun int package_count = 0, j;
788*4882a593Smuzhiyun
789*4882a593Smuzhiyun if (!package)
790*4882a593Smuzhiyun continue;
791*4882a593Smuzhiyun
792*4882a593Smuzhiyun for (j = 0; j < package->package.count; ++j) {
793*4882a593Smuzhiyun union acpi_object *element =
794*4882a593Smuzhiyun &(package->package.elements[j]);
795*4882a593Smuzhiyun
796*4882a593Smuzhiyun switch (element->type) {
797*4882a593Smuzhiyun case ACPI_TYPE_INTEGER:
798*4882a593Smuzhiyun info.enabled = element->integer.value;
799*4882a593Smuzhiyun break;
800*4882a593Smuzhiyun case ACPI_TYPE_STRING:
801*4882a593Smuzhiyun info.name = element->string.pointer;
802*4882a593Smuzhiyun break;
803*4882a593Smuzhiyun case ACPI_TYPE_PACKAGE:
804*4882a593Smuzhiyun package_count = element->package.count;
805*4882a593Smuzhiyun info.package = element->package.elements;
806*4882a593Smuzhiyun break;
807*4882a593Smuzhiyun }
808*4882a593Smuzhiyun }
809*4882a593Smuzhiyun
810*4882a593Smuzhiyun if (!info.enabled || !info.package || !info.name)
811*4882a593Smuzhiyun continue;
812*4882a593Smuzhiyun
813*4882a593Smuzhiyun constraint = &lpi_constraints_table[lpi_constraints_table_size];
814*4882a593Smuzhiyun
815*4882a593Smuzhiyun status = acpi_get_handle(NULL, info.name, &constraint->handle);
816*4882a593Smuzhiyun if (ACPI_FAILURE(status))
817*4882a593Smuzhiyun continue;
818*4882a593Smuzhiyun
819*4882a593Smuzhiyun acpi_handle_debug(lps0_device_handle,
820*4882a593Smuzhiyun "index:%d Name:%s\n", i, info.name);
821*4882a593Smuzhiyun
822*4882a593Smuzhiyun constraint->min_dstate = -1;
823*4882a593Smuzhiyun
824*4882a593Smuzhiyun for (j = 0; j < package_count; ++j) {
825*4882a593Smuzhiyun union acpi_object *info_obj = &info.package[j];
826*4882a593Smuzhiyun union acpi_object *cnstr_pkg;
827*4882a593Smuzhiyun union acpi_object *obj;
828*4882a593Smuzhiyun struct lpi_device_constraint dev_info;
829*4882a593Smuzhiyun
830*4882a593Smuzhiyun switch (info_obj->type) {
831*4882a593Smuzhiyun case ACPI_TYPE_INTEGER:
832*4882a593Smuzhiyun /* version */
833*4882a593Smuzhiyun break;
834*4882a593Smuzhiyun case ACPI_TYPE_PACKAGE:
835*4882a593Smuzhiyun if (info_obj->package.count < 2)
836*4882a593Smuzhiyun break;
837*4882a593Smuzhiyun
838*4882a593Smuzhiyun cnstr_pkg = info_obj->package.elements;
839*4882a593Smuzhiyun obj = &cnstr_pkg[0];
840*4882a593Smuzhiyun dev_info.uid = obj->integer.value;
841*4882a593Smuzhiyun obj = &cnstr_pkg[1];
842*4882a593Smuzhiyun dev_info.min_dstate = obj->integer.value;
843*4882a593Smuzhiyun
844*4882a593Smuzhiyun acpi_handle_debug(lps0_device_handle,
845*4882a593Smuzhiyun "uid:%d min_dstate:%s\n",
846*4882a593Smuzhiyun dev_info.uid,
847*4882a593Smuzhiyun acpi_power_state_string(dev_info.min_dstate));
848*4882a593Smuzhiyun
849*4882a593Smuzhiyun constraint->min_dstate = dev_info.min_dstate;
850*4882a593Smuzhiyun break;
851*4882a593Smuzhiyun }
852*4882a593Smuzhiyun }
853*4882a593Smuzhiyun
854*4882a593Smuzhiyun if (constraint->min_dstate < 0) {
855*4882a593Smuzhiyun acpi_handle_debug(lps0_device_handle,
856*4882a593Smuzhiyun "Incomplete constraint defined\n");
857*4882a593Smuzhiyun continue;
858*4882a593Smuzhiyun }
859*4882a593Smuzhiyun
860*4882a593Smuzhiyun lpi_constraints_table_size++;
861*4882a593Smuzhiyun }
862*4882a593Smuzhiyun
863*4882a593Smuzhiyun acpi_handle_debug(lps0_device_handle, "LPI: constraints list end\n");
864*4882a593Smuzhiyun
865*4882a593Smuzhiyun free_acpi_buffer:
866*4882a593Smuzhiyun ACPI_FREE(out_obj);
867*4882a593Smuzhiyun }
868*4882a593Smuzhiyun
lpi_check_constraints(void)869*4882a593Smuzhiyun static void lpi_check_constraints(void)
870*4882a593Smuzhiyun {
871*4882a593Smuzhiyun int i;
872*4882a593Smuzhiyun
873*4882a593Smuzhiyun for (i = 0; i < lpi_constraints_table_size; ++i) {
874*4882a593Smuzhiyun acpi_handle handle = lpi_constraints_table[i].handle;
875*4882a593Smuzhiyun struct acpi_device *adev;
876*4882a593Smuzhiyun
877*4882a593Smuzhiyun if (!handle || acpi_bus_get_device(handle, &adev))
878*4882a593Smuzhiyun continue;
879*4882a593Smuzhiyun
880*4882a593Smuzhiyun acpi_handle_debug(handle,
881*4882a593Smuzhiyun "LPI: required min power state:%s current power state:%s\n",
882*4882a593Smuzhiyun acpi_power_state_string(lpi_constraints_table[i].min_dstate),
883*4882a593Smuzhiyun acpi_power_state_string(adev->power.state));
884*4882a593Smuzhiyun
885*4882a593Smuzhiyun if (!adev->flags.power_manageable) {
886*4882a593Smuzhiyun acpi_handle_info(handle, "LPI: Device not power manageable\n");
887*4882a593Smuzhiyun lpi_constraints_table[i].handle = NULL;
888*4882a593Smuzhiyun continue;
889*4882a593Smuzhiyun }
890*4882a593Smuzhiyun
891*4882a593Smuzhiyun if (adev->power.state < lpi_constraints_table[i].min_dstate)
892*4882a593Smuzhiyun acpi_handle_info(handle,
893*4882a593Smuzhiyun "LPI: Constraint not met; min power state:%s current power state:%s\n",
894*4882a593Smuzhiyun acpi_power_state_string(lpi_constraints_table[i].min_dstate),
895*4882a593Smuzhiyun acpi_power_state_string(adev->power.state));
896*4882a593Smuzhiyun }
897*4882a593Smuzhiyun }
898*4882a593Smuzhiyun
acpi_sleep_run_lps0_dsm(unsigned int func)899*4882a593Smuzhiyun static void acpi_sleep_run_lps0_dsm(unsigned int func)
900*4882a593Smuzhiyun {
901*4882a593Smuzhiyun union acpi_object *out_obj;
902*4882a593Smuzhiyun
903*4882a593Smuzhiyun if (!(lps0_dsm_func_mask & (1 << func)))
904*4882a593Smuzhiyun return;
905*4882a593Smuzhiyun
906*4882a593Smuzhiyun out_obj = acpi_evaluate_dsm(lps0_device_handle, &lps0_dsm_guid, 1, func, NULL);
907*4882a593Smuzhiyun ACPI_FREE(out_obj);
908*4882a593Smuzhiyun
909*4882a593Smuzhiyun acpi_handle_debug(lps0_device_handle, "_DSM function %u evaluation %s\n",
910*4882a593Smuzhiyun func, out_obj ? "successful" : "failed");
911*4882a593Smuzhiyun }
912*4882a593Smuzhiyun
lps0_device_attach(struct acpi_device * adev,const struct acpi_device_id * not_used)913*4882a593Smuzhiyun static int lps0_device_attach(struct acpi_device *adev,
914*4882a593Smuzhiyun const struct acpi_device_id *not_used)
915*4882a593Smuzhiyun {
916*4882a593Smuzhiyun union acpi_object *out_obj;
917*4882a593Smuzhiyun
918*4882a593Smuzhiyun if (lps0_device_handle)
919*4882a593Smuzhiyun return 0;
920*4882a593Smuzhiyun
921*4882a593Smuzhiyun if (!(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0))
922*4882a593Smuzhiyun return 0;
923*4882a593Smuzhiyun
924*4882a593Smuzhiyun guid_parse(ACPI_LPS0_DSM_UUID, &lps0_dsm_guid);
925*4882a593Smuzhiyun /* Check if the _DSM is present and as expected. */
926*4882a593Smuzhiyun out_obj = acpi_evaluate_dsm(adev->handle, &lps0_dsm_guid, 1, 0, NULL);
927*4882a593Smuzhiyun if (!out_obj || out_obj->type != ACPI_TYPE_BUFFER) {
928*4882a593Smuzhiyun acpi_handle_debug(adev->handle,
929*4882a593Smuzhiyun "_DSM function 0 evaluation failed\n");
930*4882a593Smuzhiyun return 0;
931*4882a593Smuzhiyun }
932*4882a593Smuzhiyun
933*4882a593Smuzhiyun lps0_dsm_func_mask = *(char *)out_obj->buffer.pointer;
934*4882a593Smuzhiyun
935*4882a593Smuzhiyun ACPI_FREE(out_obj);
936*4882a593Smuzhiyun
937*4882a593Smuzhiyun acpi_handle_debug(adev->handle, "_DSM function mask: 0x%x\n",
938*4882a593Smuzhiyun lps0_dsm_func_mask);
939*4882a593Smuzhiyun
940*4882a593Smuzhiyun lps0_device_handle = adev->handle;
941*4882a593Smuzhiyun
942*4882a593Smuzhiyun lpi_device_get_constraints();
943*4882a593Smuzhiyun
944*4882a593Smuzhiyun /*
945*4882a593Smuzhiyun * Use suspend-to-idle by default if the default suspend mode was not
946*4882a593Smuzhiyun * set from the command line.
947*4882a593Smuzhiyun */
948*4882a593Smuzhiyun if (mem_sleep_default > PM_SUSPEND_MEM && !acpi_sleep_default_s3)
949*4882a593Smuzhiyun mem_sleep_current = PM_SUSPEND_TO_IDLE;
950*4882a593Smuzhiyun
951*4882a593Smuzhiyun /*
952*4882a593Smuzhiyun * Some LPS0 systems, like ASUS Zenbook UX430UNR/i7-8550U, require the
953*4882a593Smuzhiyun * EC GPE to be enabled while suspended for certain wakeup devices to
954*4882a593Smuzhiyun * work, so mark it as wakeup-capable.
955*4882a593Smuzhiyun */
956*4882a593Smuzhiyun acpi_ec_mark_gpe_for_wake();
957*4882a593Smuzhiyun
958*4882a593Smuzhiyun return 0;
959*4882a593Smuzhiyun }
960*4882a593Smuzhiyun
961*4882a593Smuzhiyun static struct acpi_scan_handler lps0_handler = {
962*4882a593Smuzhiyun .ids = lps0_device_ids,
963*4882a593Smuzhiyun .attach = lps0_device_attach,
964*4882a593Smuzhiyun };
965*4882a593Smuzhiyun
acpi_s2idle_begin(void)966*4882a593Smuzhiyun static int acpi_s2idle_begin(void)
967*4882a593Smuzhiyun {
968*4882a593Smuzhiyun acpi_scan_lock_acquire();
969*4882a593Smuzhiyun return 0;
970*4882a593Smuzhiyun }
971*4882a593Smuzhiyun
acpi_s2idle_prepare(void)972*4882a593Smuzhiyun static int acpi_s2idle_prepare(void)
973*4882a593Smuzhiyun {
974*4882a593Smuzhiyun if (acpi_sci_irq_valid()) {
975*4882a593Smuzhiyun enable_irq_wake(acpi_sci_irq);
976*4882a593Smuzhiyun acpi_ec_set_gpe_wake_mask(ACPI_GPE_ENABLE);
977*4882a593Smuzhiyun }
978*4882a593Smuzhiyun
979*4882a593Smuzhiyun acpi_enable_wakeup_devices(ACPI_STATE_S0);
980*4882a593Smuzhiyun
981*4882a593Smuzhiyun /* Change the configuration of GPEs to avoid spurious wakeup. */
982*4882a593Smuzhiyun acpi_enable_all_wakeup_gpes();
983*4882a593Smuzhiyun acpi_os_wait_events_complete();
984*4882a593Smuzhiyun
985*4882a593Smuzhiyun s2idle_wakeup = true;
986*4882a593Smuzhiyun return 0;
987*4882a593Smuzhiyun }
988*4882a593Smuzhiyun
acpi_s2idle_prepare_late(void)989*4882a593Smuzhiyun static int acpi_s2idle_prepare_late(void)
990*4882a593Smuzhiyun {
991*4882a593Smuzhiyun if (!lps0_device_handle || sleep_no_lps0)
992*4882a593Smuzhiyun return 0;
993*4882a593Smuzhiyun
994*4882a593Smuzhiyun if (pm_debug_messages_on)
995*4882a593Smuzhiyun lpi_check_constraints();
996*4882a593Smuzhiyun
997*4882a593Smuzhiyun acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF);
998*4882a593Smuzhiyun acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY);
999*4882a593Smuzhiyun
1000*4882a593Smuzhiyun return 0;
1001*4882a593Smuzhiyun }
1002*4882a593Smuzhiyun
acpi_s2idle_wake(void)1003*4882a593Smuzhiyun static bool acpi_s2idle_wake(void)
1004*4882a593Smuzhiyun {
1005*4882a593Smuzhiyun if (!acpi_sci_irq_valid())
1006*4882a593Smuzhiyun return pm_wakeup_pending();
1007*4882a593Smuzhiyun
1008*4882a593Smuzhiyun while (pm_wakeup_pending()) {
1009*4882a593Smuzhiyun /*
1010*4882a593Smuzhiyun * If IRQD_WAKEUP_ARMED is set for the SCI at this point, the
1011*4882a593Smuzhiyun * SCI has not triggered while suspended, so bail out (the
1012*4882a593Smuzhiyun * wakeup is pending anyway and the SCI is not the source of
1013*4882a593Smuzhiyun * it).
1014*4882a593Smuzhiyun */
1015*4882a593Smuzhiyun if (irqd_is_wakeup_armed(irq_get_irq_data(acpi_sci_irq))) {
1016*4882a593Smuzhiyun pm_pr_dbg("Wakeup unrelated to ACPI SCI\n");
1017*4882a593Smuzhiyun return true;
1018*4882a593Smuzhiyun }
1019*4882a593Smuzhiyun
1020*4882a593Smuzhiyun /*
1021*4882a593Smuzhiyun * If the status bit of any enabled fixed event is set, the
1022*4882a593Smuzhiyun * wakeup is regarded as valid.
1023*4882a593Smuzhiyun */
1024*4882a593Smuzhiyun if (acpi_any_fixed_event_status_set()) {
1025*4882a593Smuzhiyun pm_pr_dbg("ACPI fixed event wakeup\n");
1026*4882a593Smuzhiyun return true;
1027*4882a593Smuzhiyun }
1028*4882a593Smuzhiyun
1029*4882a593Smuzhiyun /* Check wakeups from drivers sharing the SCI. */
1030*4882a593Smuzhiyun if (acpi_check_wakeup_handlers()) {
1031*4882a593Smuzhiyun pm_pr_dbg("ACPI custom handler wakeup\n");
1032*4882a593Smuzhiyun return true;
1033*4882a593Smuzhiyun }
1034*4882a593Smuzhiyun
1035*4882a593Smuzhiyun /* Check non-EC GPE wakeups and dispatch the EC GPE. */
1036*4882a593Smuzhiyun if (acpi_ec_dispatch_gpe()) {
1037*4882a593Smuzhiyun pm_pr_dbg("ACPI non-EC GPE wakeup\n");
1038*4882a593Smuzhiyun return true;
1039*4882a593Smuzhiyun }
1040*4882a593Smuzhiyun
1041*4882a593Smuzhiyun /*
1042*4882a593Smuzhiyun * Cancel the SCI wakeup and process all pending events in case
1043*4882a593Smuzhiyun * there are any wakeup ones in there.
1044*4882a593Smuzhiyun *
1045*4882a593Smuzhiyun * Note that if any non-EC GPEs are active at this point, the
1046*4882a593Smuzhiyun * SCI will retrigger after the rearming below, so no events
1047*4882a593Smuzhiyun * should be missed by canceling the wakeup here.
1048*4882a593Smuzhiyun */
1049*4882a593Smuzhiyun pm_system_cancel_wakeup();
1050*4882a593Smuzhiyun acpi_os_wait_events_complete();
1051*4882a593Smuzhiyun
1052*4882a593Smuzhiyun /*
1053*4882a593Smuzhiyun * The SCI is in the "suspended" state now and it cannot produce
1054*4882a593Smuzhiyun * new wakeup events till the rearming below, so if any of them
1055*4882a593Smuzhiyun * are pending here, they must be resulting from the processing
1056*4882a593Smuzhiyun * of EC events above or coming from somewhere else.
1057*4882a593Smuzhiyun */
1058*4882a593Smuzhiyun if (pm_wakeup_pending()) {
1059*4882a593Smuzhiyun pm_pr_dbg("Wakeup after ACPI Notify sync\n");
1060*4882a593Smuzhiyun return true;
1061*4882a593Smuzhiyun }
1062*4882a593Smuzhiyun
1063*4882a593Smuzhiyun pm_wakeup_clear(acpi_sci_irq);
1064*4882a593Smuzhiyun rearm_wake_irq(acpi_sci_irq);
1065*4882a593Smuzhiyun }
1066*4882a593Smuzhiyun
1067*4882a593Smuzhiyun return false;
1068*4882a593Smuzhiyun }
1069*4882a593Smuzhiyun
acpi_s2idle_restore_early(void)1070*4882a593Smuzhiyun static void acpi_s2idle_restore_early(void)
1071*4882a593Smuzhiyun {
1072*4882a593Smuzhiyun if (!lps0_device_handle || sleep_no_lps0)
1073*4882a593Smuzhiyun return;
1074*4882a593Smuzhiyun
1075*4882a593Smuzhiyun acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT);
1076*4882a593Smuzhiyun acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON);
1077*4882a593Smuzhiyun }
1078*4882a593Smuzhiyun
acpi_s2idle_restore(void)1079*4882a593Smuzhiyun static void acpi_s2idle_restore(void)
1080*4882a593Smuzhiyun {
1081*4882a593Smuzhiyun /*
1082*4882a593Smuzhiyun * Drain pending events before restoring the working-state configuration
1083*4882a593Smuzhiyun * of GPEs.
1084*4882a593Smuzhiyun */
1085*4882a593Smuzhiyun acpi_os_wait_events_complete(); /* synchronize GPE processing */
1086*4882a593Smuzhiyun acpi_ec_flush_work(); /* flush the EC driver's workqueues */
1087*4882a593Smuzhiyun acpi_os_wait_events_complete(); /* synchronize Notify handling */
1088*4882a593Smuzhiyun
1089*4882a593Smuzhiyun s2idle_wakeup = false;
1090*4882a593Smuzhiyun
1091*4882a593Smuzhiyun acpi_enable_all_runtime_gpes();
1092*4882a593Smuzhiyun
1093*4882a593Smuzhiyun acpi_disable_wakeup_devices(ACPI_STATE_S0);
1094*4882a593Smuzhiyun
1095*4882a593Smuzhiyun if (acpi_sci_irq_valid()) {
1096*4882a593Smuzhiyun acpi_ec_set_gpe_wake_mask(ACPI_GPE_DISABLE);
1097*4882a593Smuzhiyun disable_irq_wake(acpi_sci_irq);
1098*4882a593Smuzhiyun }
1099*4882a593Smuzhiyun }
1100*4882a593Smuzhiyun
acpi_s2idle_end(void)1101*4882a593Smuzhiyun static void acpi_s2idle_end(void)
1102*4882a593Smuzhiyun {
1103*4882a593Smuzhiyun acpi_scan_lock_release();
1104*4882a593Smuzhiyun }
1105*4882a593Smuzhiyun
1106*4882a593Smuzhiyun static const struct platform_s2idle_ops acpi_s2idle_ops = {
1107*4882a593Smuzhiyun .begin = acpi_s2idle_begin,
1108*4882a593Smuzhiyun .prepare = acpi_s2idle_prepare,
1109*4882a593Smuzhiyun .prepare_late = acpi_s2idle_prepare_late,
1110*4882a593Smuzhiyun .wake = acpi_s2idle_wake,
1111*4882a593Smuzhiyun .restore_early = acpi_s2idle_restore_early,
1112*4882a593Smuzhiyun .restore = acpi_s2idle_restore,
1113*4882a593Smuzhiyun .end = acpi_s2idle_end,
1114*4882a593Smuzhiyun };
1115*4882a593Smuzhiyun
acpi_sleep_suspend_setup(void)1116*4882a593Smuzhiyun static void acpi_sleep_suspend_setup(void)
1117*4882a593Smuzhiyun {
1118*4882a593Smuzhiyun int i;
1119*4882a593Smuzhiyun
1120*4882a593Smuzhiyun for (i = ACPI_STATE_S1; i < ACPI_STATE_S4; i++)
1121*4882a593Smuzhiyun if (acpi_sleep_state_supported(i))
1122*4882a593Smuzhiyun sleep_states[i] = 1;
1123*4882a593Smuzhiyun
1124*4882a593Smuzhiyun suspend_set_ops(old_suspend_ordering ?
1125*4882a593Smuzhiyun &acpi_suspend_ops_old : &acpi_suspend_ops);
1126*4882a593Smuzhiyun
1127*4882a593Smuzhiyun acpi_scan_add_handler(&lps0_handler);
1128*4882a593Smuzhiyun s2idle_set_ops(&acpi_s2idle_ops);
1129*4882a593Smuzhiyun }
1130*4882a593Smuzhiyun
1131*4882a593Smuzhiyun #else /* !CONFIG_SUSPEND */
1132*4882a593Smuzhiyun #define s2idle_wakeup (false)
1133*4882a593Smuzhiyun #define lps0_device_handle (NULL)
acpi_sleep_suspend_setup(void)1134*4882a593Smuzhiyun static inline void acpi_sleep_suspend_setup(void) {}
1135*4882a593Smuzhiyun #endif /* !CONFIG_SUSPEND */
1136*4882a593Smuzhiyun
acpi_s2idle_wakeup(void)1137*4882a593Smuzhiyun bool acpi_s2idle_wakeup(void)
1138*4882a593Smuzhiyun {
1139*4882a593Smuzhiyun return s2idle_wakeup;
1140*4882a593Smuzhiyun }
1141*4882a593Smuzhiyun
1142*4882a593Smuzhiyun #ifdef CONFIG_PM_SLEEP
1143*4882a593Smuzhiyun static u32 saved_bm_rld;
1144*4882a593Smuzhiyun
acpi_save_bm_rld(void)1145*4882a593Smuzhiyun static int acpi_save_bm_rld(void)
1146*4882a593Smuzhiyun {
1147*4882a593Smuzhiyun acpi_read_bit_register(ACPI_BITREG_BUS_MASTER_RLD, &saved_bm_rld);
1148*4882a593Smuzhiyun return 0;
1149*4882a593Smuzhiyun }
1150*4882a593Smuzhiyun
acpi_restore_bm_rld(void)1151*4882a593Smuzhiyun static void acpi_restore_bm_rld(void)
1152*4882a593Smuzhiyun {
1153*4882a593Smuzhiyun u32 resumed_bm_rld = 0;
1154*4882a593Smuzhiyun
1155*4882a593Smuzhiyun acpi_read_bit_register(ACPI_BITREG_BUS_MASTER_RLD, &resumed_bm_rld);
1156*4882a593Smuzhiyun if (resumed_bm_rld == saved_bm_rld)
1157*4882a593Smuzhiyun return;
1158*4882a593Smuzhiyun
1159*4882a593Smuzhiyun acpi_write_bit_register(ACPI_BITREG_BUS_MASTER_RLD, saved_bm_rld);
1160*4882a593Smuzhiyun }
1161*4882a593Smuzhiyun
1162*4882a593Smuzhiyun static struct syscore_ops acpi_sleep_syscore_ops = {
1163*4882a593Smuzhiyun .suspend = acpi_save_bm_rld,
1164*4882a593Smuzhiyun .resume = acpi_restore_bm_rld,
1165*4882a593Smuzhiyun };
1166*4882a593Smuzhiyun
acpi_sleep_syscore_init(void)1167*4882a593Smuzhiyun static void acpi_sleep_syscore_init(void)
1168*4882a593Smuzhiyun {
1169*4882a593Smuzhiyun register_syscore_ops(&acpi_sleep_syscore_ops);
1170*4882a593Smuzhiyun }
1171*4882a593Smuzhiyun #else
acpi_sleep_syscore_init(void)1172*4882a593Smuzhiyun static inline void acpi_sleep_syscore_init(void) {}
1173*4882a593Smuzhiyun #endif /* CONFIG_PM_SLEEP */
1174*4882a593Smuzhiyun
1175*4882a593Smuzhiyun #ifdef CONFIG_HIBERNATION
1176*4882a593Smuzhiyun static unsigned long s4_hardware_signature;
1177*4882a593Smuzhiyun static struct acpi_table_facs *facs;
1178*4882a593Smuzhiyun static bool nosigcheck;
1179*4882a593Smuzhiyun
acpi_no_s4_hw_signature(void)1180*4882a593Smuzhiyun void __init acpi_no_s4_hw_signature(void)
1181*4882a593Smuzhiyun {
1182*4882a593Smuzhiyun nosigcheck = true;
1183*4882a593Smuzhiyun }
1184*4882a593Smuzhiyun
acpi_hibernation_begin(pm_message_t stage)1185*4882a593Smuzhiyun static int acpi_hibernation_begin(pm_message_t stage)
1186*4882a593Smuzhiyun {
1187*4882a593Smuzhiyun if (!nvs_nosave) {
1188*4882a593Smuzhiyun int error = suspend_nvs_alloc();
1189*4882a593Smuzhiyun if (error)
1190*4882a593Smuzhiyun return error;
1191*4882a593Smuzhiyun }
1192*4882a593Smuzhiyun
1193*4882a593Smuzhiyun if (stage.event == PM_EVENT_HIBERNATE)
1194*4882a593Smuzhiyun pm_set_suspend_via_firmware();
1195*4882a593Smuzhiyun
1196*4882a593Smuzhiyun acpi_pm_start(ACPI_STATE_S4);
1197*4882a593Smuzhiyun return 0;
1198*4882a593Smuzhiyun }
1199*4882a593Smuzhiyun
acpi_hibernation_enter(void)1200*4882a593Smuzhiyun static int acpi_hibernation_enter(void)
1201*4882a593Smuzhiyun {
1202*4882a593Smuzhiyun acpi_status status = AE_OK;
1203*4882a593Smuzhiyun
1204*4882a593Smuzhiyun ACPI_FLUSH_CPU_CACHE();
1205*4882a593Smuzhiyun
1206*4882a593Smuzhiyun /* This shouldn't return. If it returns, we have a problem */
1207*4882a593Smuzhiyun status = acpi_enter_sleep_state(ACPI_STATE_S4);
1208*4882a593Smuzhiyun /* Reprogram control registers */
1209*4882a593Smuzhiyun acpi_leave_sleep_state_prep(ACPI_STATE_S4);
1210*4882a593Smuzhiyun
1211*4882a593Smuzhiyun return ACPI_SUCCESS(status) ? 0 : -EFAULT;
1212*4882a593Smuzhiyun }
1213*4882a593Smuzhiyun
acpi_hibernation_leave(void)1214*4882a593Smuzhiyun static void acpi_hibernation_leave(void)
1215*4882a593Smuzhiyun {
1216*4882a593Smuzhiyun pm_set_resume_via_firmware();
1217*4882a593Smuzhiyun /*
1218*4882a593Smuzhiyun * If ACPI is not enabled by the BIOS and the boot kernel, we need to
1219*4882a593Smuzhiyun * enable it here.
1220*4882a593Smuzhiyun */
1221*4882a593Smuzhiyun acpi_enable();
1222*4882a593Smuzhiyun /* Reprogram control registers */
1223*4882a593Smuzhiyun acpi_leave_sleep_state_prep(ACPI_STATE_S4);
1224*4882a593Smuzhiyun /* Check the hardware signature */
1225*4882a593Smuzhiyun if (facs && s4_hardware_signature != facs->hardware_signature)
1226*4882a593Smuzhiyun pr_crit("ACPI: Hardware changed while hibernated, success doubtful!\n");
1227*4882a593Smuzhiyun /* Restore the NVS memory area */
1228*4882a593Smuzhiyun suspend_nvs_restore();
1229*4882a593Smuzhiyun /* Allow EC transactions to happen. */
1230*4882a593Smuzhiyun acpi_ec_unblock_transactions();
1231*4882a593Smuzhiyun }
1232*4882a593Smuzhiyun
acpi_pm_thaw(void)1233*4882a593Smuzhiyun static void acpi_pm_thaw(void)
1234*4882a593Smuzhiyun {
1235*4882a593Smuzhiyun acpi_ec_unblock_transactions();
1236*4882a593Smuzhiyun acpi_enable_all_runtime_gpes();
1237*4882a593Smuzhiyun }
1238*4882a593Smuzhiyun
1239*4882a593Smuzhiyun static const struct platform_hibernation_ops acpi_hibernation_ops = {
1240*4882a593Smuzhiyun .begin = acpi_hibernation_begin,
1241*4882a593Smuzhiyun .end = acpi_pm_end,
1242*4882a593Smuzhiyun .pre_snapshot = acpi_pm_prepare,
1243*4882a593Smuzhiyun .finish = acpi_pm_finish,
1244*4882a593Smuzhiyun .prepare = acpi_pm_prepare,
1245*4882a593Smuzhiyun .enter = acpi_hibernation_enter,
1246*4882a593Smuzhiyun .leave = acpi_hibernation_leave,
1247*4882a593Smuzhiyun .pre_restore = acpi_pm_freeze,
1248*4882a593Smuzhiyun .restore_cleanup = acpi_pm_thaw,
1249*4882a593Smuzhiyun };
1250*4882a593Smuzhiyun
1251*4882a593Smuzhiyun /**
1252*4882a593Smuzhiyun * acpi_hibernation_begin_old - Set the target system sleep state to
1253*4882a593Smuzhiyun * ACPI_STATE_S4 and execute the _PTS control method. This
1254*4882a593Smuzhiyun * function is used if the pre-ACPI 2.0 suspend ordering has been
1255*4882a593Smuzhiyun * requested.
1256*4882a593Smuzhiyun */
acpi_hibernation_begin_old(pm_message_t stage)1257*4882a593Smuzhiyun static int acpi_hibernation_begin_old(pm_message_t stage)
1258*4882a593Smuzhiyun {
1259*4882a593Smuzhiyun int error;
1260*4882a593Smuzhiyun /*
1261*4882a593Smuzhiyun * The _TTS object should always be evaluated before the _PTS object.
1262*4882a593Smuzhiyun * When the old_suspended_ordering is true, the _PTS object is
1263*4882a593Smuzhiyun * evaluated in the acpi_sleep_prepare.
1264*4882a593Smuzhiyun */
1265*4882a593Smuzhiyun acpi_sleep_tts_switch(ACPI_STATE_S4);
1266*4882a593Smuzhiyun
1267*4882a593Smuzhiyun error = acpi_sleep_prepare(ACPI_STATE_S4);
1268*4882a593Smuzhiyun if (error)
1269*4882a593Smuzhiyun return error;
1270*4882a593Smuzhiyun
1271*4882a593Smuzhiyun if (!nvs_nosave) {
1272*4882a593Smuzhiyun error = suspend_nvs_alloc();
1273*4882a593Smuzhiyun if (error)
1274*4882a593Smuzhiyun return error;
1275*4882a593Smuzhiyun }
1276*4882a593Smuzhiyun
1277*4882a593Smuzhiyun if (stage.event == PM_EVENT_HIBERNATE)
1278*4882a593Smuzhiyun pm_set_suspend_via_firmware();
1279*4882a593Smuzhiyun
1280*4882a593Smuzhiyun acpi_target_sleep_state = ACPI_STATE_S4;
1281*4882a593Smuzhiyun acpi_scan_lock_acquire();
1282*4882a593Smuzhiyun return 0;
1283*4882a593Smuzhiyun }
1284*4882a593Smuzhiyun
1285*4882a593Smuzhiyun /*
1286*4882a593Smuzhiyun * The following callbacks are used if the pre-ACPI 2.0 suspend ordering has
1287*4882a593Smuzhiyun * been requested.
1288*4882a593Smuzhiyun */
1289*4882a593Smuzhiyun static const struct platform_hibernation_ops acpi_hibernation_ops_old = {
1290*4882a593Smuzhiyun .begin = acpi_hibernation_begin_old,
1291*4882a593Smuzhiyun .end = acpi_pm_end,
1292*4882a593Smuzhiyun .pre_snapshot = acpi_pm_pre_suspend,
1293*4882a593Smuzhiyun .prepare = acpi_pm_freeze,
1294*4882a593Smuzhiyun .finish = acpi_pm_finish,
1295*4882a593Smuzhiyun .enter = acpi_hibernation_enter,
1296*4882a593Smuzhiyun .leave = acpi_hibernation_leave,
1297*4882a593Smuzhiyun .pre_restore = acpi_pm_freeze,
1298*4882a593Smuzhiyun .restore_cleanup = acpi_pm_thaw,
1299*4882a593Smuzhiyun .recover = acpi_pm_finish,
1300*4882a593Smuzhiyun };
1301*4882a593Smuzhiyun
acpi_sleep_hibernate_setup(void)1302*4882a593Smuzhiyun static void acpi_sleep_hibernate_setup(void)
1303*4882a593Smuzhiyun {
1304*4882a593Smuzhiyun if (!acpi_sleep_state_supported(ACPI_STATE_S4))
1305*4882a593Smuzhiyun return;
1306*4882a593Smuzhiyun
1307*4882a593Smuzhiyun hibernation_set_ops(old_suspend_ordering ?
1308*4882a593Smuzhiyun &acpi_hibernation_ops_old : &acpi_hibernation_ops);
1309*4882a593Smuzhiyun sleep_states[ACPI_STATE_S4] = 1;
1310*4882a593Smuzhiyun if (nosigcheck)
1311*4882a593Smuzhiyun return;
1312*4882a593Smuzhiyun
1313*4882a593Smuzhiyun acpi_get_table(ACPI_SIG_FACS, 1, (struct acpi_table_header **)&facs);
1314*4882a593Smuzhiyun if (facs)
1315*4882a593Smuzhiyun s4_hardware_signature = facs->hardware_signature;
1316*4882a593Smuzhiyun }
1317*4882a593Smuzhiyun #else /* !CONFIG_HIBERNATION */
acpi_sleep_hibernate_setup(void)1318*4882a593Smuzhiyun static inline void acpi_sleep_hibernate_setup(void) {}
1319*4882a593Smuzhiyun #endif /* !CONFIG_HIBERNATION */
1320*4882a593Smuzhiyun
acpi_power_off_prepare(void)1321*4882a593Smuzhiyun static void acpi_power_off_prepare(void)
1322*4882a593Smuzhiyun {
1323*4882a593Smuzhiyun /* Prepare to power off the system */
1324*4882a593Smuzhiyun acpi_sleep_prepare(ACPI_STATE_S5);
1325*4882a593Smuzhiyun acpi_disable_all_gpes();
1326*4882a593Smuzhiyun acpi_os_wait_events_complete();
1327*4882a593Smuzhiyun }
1328*4882a593Smuzhiyun
acpi_power_off(void)1329*4882a593Smuzhiyun static void acpi_power_off(void)
1330*4882a593Smuzhiyun {
1331*4882a593Smuzhiyun /* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */
1332*4882a593Smuzhiyun printk(KERN_DEBUG "%s called\n", __func__);
1333*4882a593Smuzhiyun local_irq_disable();
1334*4882a593Smuzhiyun acpi_enter_sleep_state(ACPI_STATE_S5);
1335*4882a593Smuzhiyun }
1336*4882a593Smuzhiyun
acpi_sleep_init(void)1337*4882a593Smuzhiyun int __init acpi_sleep_init(void)
1338*4882a593Smuzhiyun {
1339*4882a593Smuzhiyun char supported[ACPI_S_STATE_COUNT * 3 + 1];
1340*4882a593Smuzhiyun char *pos = supported;
1341*4882a593Smuzhiyun int i;
1342*4882a593Smuzhiyun
1343*4882a593Smuzhiyun acpi_sleep_dmi_check();
1344*4882a593Smuzhiyun
1345*4882a593Smuzhiyun sleep_states[ACPI_STATE_S0] = 1;
1346*4882a593Smuzhiyun
1347*4882a593Smuzhiyun acpi_sleep_syscore_init();
1348*4882a593Smuzhiyun acpi_sleep_suspend_setup();
1349*4882a593Smuzhiyun acpi_sleep_hibernate_setup();
1350*4882a593Smuzhiyun
1351*4882a593Smuzhiyun if (acpi_sleep_state_supported(ACPI_STATE_S5)) {
1352*4882a593Smuzhiyun sleep_states[ACPI_STATE_S5] = 1;
1353*4882a593Smuzhiyun pm_power_off_prepare = acpi_power_off_prepare;
1354*4882a593Smuzhiyun pm_power_off = acpi_power_off;
1355*4882a593Smuzhiyun } else {
1356*4882a593Smuzhiyun acpi_no_s5 = true;
1357*4882a593Smuzhiyun }
1358*4882a593Smuzhiyun
1359*4882a593Smuzhiyun supported[0] = 0;
1360*4882a593Smuzhiyun for (i = 0; i < ACPI_S_STATE_COUNT; i++) {
1361*4882a593Smuzhiyun if (sleep_states[i])
1362*4882a593Smuzhiyun pos += sprintf(pos, " S%d", i);
1363*4882a593Smuzhiyun }
1364*4882a593Smuzhiyun pr_info(PREFIX "(supports%s)\n", supported);
1365*4882a593Smuzhiyun
1366*4882a593Smuzhiyun /*
1367*4882a593Smuzhiyun * Register the tts_notifier to reboot notifier list so that the _TTS
1368*4882a593Smuzhiyun * object can also be evaluated when the system enters S5.
1369*4882a593Smuzhiyun */
1370*4882a593Smuzhiyun register_reboot_notifier(&tts_notifier);
1371*4882a593Smuzhiyun return 0;
1372*4882a593Smuzhiyun }
1373