1ae115bc7Smrj /******************************************************************************
2ae115bc7Smrj *
3*385cc6b4SJerry Jelinek * Name: hwsleep.c - ACPI Hardware Sleep/Wake Support functions for the
4*385cc6b4SJerry Jelinek * original/legacy sleep/PM registers.
5ae115bc7Smrj *
6ae115bc7Smrj *****************************************************************************/
7ae115bc7Smrj
826f3cdf0SGordon Ross /*
9*385cc6b4SJerry Jelinek * Copyright (C) 2000 - 2016, Intel Corp.
10ae115bc7Smrj * All rights reserved.
11ae115bc7Smrj *
1226f3cdf0SGordon Ross * Redistribution and use in source and binary forms, with or without
1326f3cdf0SGordon Ross * modification, are permitted provided that the following conditions
1426f3cdf0SGordon Ross * are met:
1526f3cdf0SGordon Ross * 1. Redistributions of source code must retain the above copyright
1626f3cdf0SGordon Ross * notice, this list of conditions, and the following disclaimer,
1726f3cdf0SGordon Ross * without modification.
1826f3cdf0SGordon Ross * 2. Redistributions in binary form must reproduce at minimum a disclaimer
1926f3cdf0SGordon Ross * substantially similar to the "NO WARRANTY" disclaimer below
2026f3cdf0SGordon Ross * ("Disclaimer") and any redistribution must be conditioned upon
2126f3cdf0SGordon Ross * including a substantially similar Disclaimer requirement for further
2226f3cdf0SGordon Ross * binary redistribution.
2326f3cdf0SGordon Ross * 3. Neither the names of the above-listed copyright holders nor the names
2426f3cdf0SGordon Ross * of any contributors may be used to endorse or promote products derived
2526f3cdf0SGordon Ross * from this software without specific prior written permission.
26ae115bc7Smrj *
2726f3cdf0SGordon Ross * Alternatively, this software may be distributed under the terms of the
2826f3cdf0SGordon Ross * GNU General Public License ("GPL") version 2 as published by the Free
2926f3cdf0SGordon Ross * Software Foundation.
30ae115bc7Smrj *
3126f3cdf0SGordon Ross * NO WARRANTY
3226f3cdf0SGordon Ross * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3326f3cdf0SGordon Ross * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3426f3cdf0SGordon Ross * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
3526f3cdf0SGordon Ross * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3626f3cdf0SGordon Ross * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3726f3cdf0SGordon Ross * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3826f3cdf0SGordon Ross * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3926f3cdf0SGordon Ross * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
4026f3cdf0SGordon Ross * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
4126f3cdf0SGordon Ross * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
4226f3cdf0SGordon Ross * POSSIBILITY OF SUCH DAMAGES.
4326f3cdf0SGordon Ross */
44ae115bc7Smrj
45ae115bc7Smrj #include "acpi.h"
46aa2aa9a6SDana Myers #include "accommon.h"
47ae115bc7Smrj
48ae115bc7Smrj #define _COMPONENT ACPI_HARDWARE
49ae115bc7Smrj ACPI_MODULE_NAME ("hwsleep")
50ae115bc7Smrj
51ae115bc7Smrj
52*385cc6b4SJerry Jelinek #if (!ACPI_REDUCED_HARDWARE) /* Entire module */
53ae115bc7Smrj /*******************************************************************************
54ae115bc7Smrj *
55*385cc6b4SJerry Jelinek * FUNCTION: AcpiHwLegacySleep
56ae115bc7Smrj *
57ae115bc7Smrj * PARAMETERS: SleepState - Which sleep state to enter
58ae115bc7Smrj *
59ae115bc7Smrj * RETURN: Status
60ae115bc7Smrj *
61*385cc6b4SJerry Jelinek * DESCRIPTION: Enter a system sleep state via the legacy FADT PM registers
62ae115bc7Smrj * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
63ae115bc7Smrj *
64ae115bc7Smrj ******************************************************************************/
65ae115bc7Smrj
66ae115bc7Smrj ACPI_STATUS
AcpiHwLegacySleep(UINT8 SleepState)67*385cc6b4SJerry Jelinek AcpiHwLegacySleep (
68ae115bc7Smrj UINT8 SleepState)
69ae115bc7Smrj {
70ae115bc7Smrj ACPI_BIT_REGISTER_INFO *SleepTypeRegInfo;
71ae115bc7Smrj ACPI_BIT_REGISTER_INFO *SleepEnableRegInfo;
72*385cc6b4SJerry Jelinek UINT32 Pm1aControl;
73*385cc6b4SJerry Jelinek UINT32 Pm1bControl;
74ae115bc7Smrj UINT32 InValue;
75ae115bc7Smrj ACPI_STATUS Status;
76ae115bc7Smrj
77ae115bc7Smrj
78*385cc6b4SJerry Jelinek ACPI_FUNCTION_TRACE (HwLegacySleep);
79ae115bc7Smrj
80ae115bc7Smrj
81aa2aa9a6SDana Myers SleepTypeRegInfo = AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_TYPE);
82ae115bc7Smrj SleepEnableRegInfo = AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_ENABLE);
83ae115bc7Smrj
84ae115bc7Smrj /* Clear wake status */
85ae115bc7Smrj
86*385cc6b4SJerry Jelinek Status = AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS,
87*385cc6b4SJerry Jelinek ACPI_CLEAR_STATUS);
88ae115bc7Smrj if (ACPI_FAILURE (Status))
89ae115bc7Smrj {
90ae115bc7Smrj return_ACPI_STATUS (Status);
91ae115bc7Smrj }
92ae115bc7Smrj
93ae115bc7Smrj /* Clear all fixed and general purpose status bits */
94ae115bc7Smrj
95db2bae30SDana Myers Status = AcpiHwClearAcpiStatus ();
96ae115bc7Smrj if (ACPI_FAILURE (Status))
97ae115bc7Smrj {
98ae115bc7Smrj return_ACPI_STATUS (Status);
99ae115bc7Smrj }
100ae115bc7Smrj
101ae115bc7Smrj /*
102ae115bc7Smrj * 1) Disable/Clear all GPEs
103ae115bc7Smrj * 2) Enable all wakeup GPEs
104ae115bc7Smrj */
105ae115bc7Smrj Status = AcpiHwDisableAllGpes ();
106ae115bc7Smrj if (ACPI_FAILURE (Status))
107ae115bc7Smrj {
108ae115bc7Smrj return_ACPI_STATUS (Status);
109ae115bc7Smrj }
110ae115bc7Smrj AcpiGbl_SystemAwakeAndRunning = FALSE;
111ae115bc7Smrj
112ae115bc7Smrj Status = AcpiHwEnableAllWakeupGpes ();
113ae115bc7Smrj if (ACPI_FAILURE (Status))
114ae115bc7Smrj {
115ae115bc7Smrj return_ACPI_STATUS (Status);
116ae115bc7Smrj }
117ae115bc7Smrj
118ae115bc7Smrj /* Get current value of PM1A control */
119ae115bc7Smrj
120db2bae30SDana Myers Status = AcpiHwRegisterRead (ACPI_REGISTER_PM1_CONTROL,
121aa2aa9a6SDana Myers &Pm1aControl);
122ae115bc7Smrj if (ACPI_FAILURE (Status))
123ae115bc7Smrj {
124ae115bc7Smrj return_ACPI_STATUS (Status);
125ae115bc7Smrj }
126ae115bc7Smrj ACPI_DEBUG_PRINT ((ACPI_DB_INIT,
12726f3cdf0SGordon Ross "Entering sleep state [S%u]\n", SleepState));
128ae115bc7Smrj
129aa2aa9a6SDana Myers /* Clear the SLP_EN and SLP_TYP fields */
130ae115bc7Smrj
131aa2aa9a6SDana Myers Pm1aControl &= ~(SleepTypeRegInfo->AccessBitMask |
132ae115bc7Smrj SleepEnableRegInfo->AccessBitMask);
133aa2aa9a6SDana Myers Pm1bControl = Pm1aControl;
134ae115bc7Smrj
135aa2aa9a6SDana Myers /* Insert the SLP_TYP bits */
136ae115bc7Smrj
137aa2aa9a6SDana Myers Pm1aControl |= (AcpiGbl_SleepTypeA << SleepTypeRegInfo->BitPosition);
138aa2aa9a6SDana Myers Pm1bControl |= (AcpiGbl_SleepTypeB << SleepTypeRegInfo->BitPosition);
139ae115bc7Smrj
140ae115bc7Smrj /*
141ae115bc7Smrj * We split the writes of SLP_TYP and SLP_EN to workaround
142ae115bc7Smrj * poorly implemented hardware.
143ae115bc7Smrj */
144ae115bc7Smrj
145aa2aa9a6SDana Myers /* Write #1: write the SLP_TYP data to the PM1 Control registers */
146ae115bc7Smrj
147aa2aa9a6SDana Myers Status = AcpiHwWritePm1Control (Pm1aControl, Pm1bControl);
148ae115bc7Smrj if (ACPI_FAILURE (Status))
149ae115bc7Smrj {
150ae115bc7Smrj return_ACPI_STATUS (Status);
151ae115bc7Smrj }
152ae115bc7Smrj
153aa2aa9a6SDana Myers /* Insert the sleep enable (SLP_EN) bit */
154ae115bc7Smrj
155aa2aa9a6SDana Myers Pm1aControl |= SleepEnableRegInfo->AccessBitMask;
156aa2aa9a6SDana Myers Pm1bControl |= SleepEnableRegInfo->AccessBitMask;
157ae115bc7Smrj
158aa2aa9a6SDana Myers /* Flush caches, as per ACPI specification */
159ae115bc7Smrj
160ae115bc7Smrj ACPI_FLUSH_CPU_CACHE ();
161ae115bc7Smrj
162aa2aa9a6SDana Myers /* Write #2: Write both SLP_TYP + SLP_EN */
163ae115bc7Smrj
164aa2aa9a6SDana Myers Status = AcpiHwWritePm1Control (Pm1aControl, Pm1bControl);
165ae115bc7Smrj if (ACPI_FAILURE (Status))
166ae115bc7Smrj {
167ae115bc7Smrj return_ACPI_STATUS (Status);
168ae115bc7Smrj }
169ae115bc7Smrj
170ae115bc7Smrj if (SleepState > ACPI_STATE_S3)
171ae115bc7Smrj {
172ae115bc7Smrj /*
173ae115bc7Smrj * We wanted to sleep > S3, but it didn't happen (by virtue of the
174ae115bc7Smrj * fact that we are still executing!)
175ae115bc7Smrj *
176ae115bc7Smrj * Wait ten seconds, then try again. This is to get S4/S5 to work on
177ae115bc7Smrj * all machines.
178ae115bc7Smrj *
179aa2aa9a6SDana Myers * We wait so long to allow chipsets that poll this reg very slowly
180aa2aa9a6SDana Myers * to still read the right value. Ideally, this block would go
181ae115bc7Smrj * away entirely.
182ae115bc7Smrj */
183*385cc6b4SJerry Jelinek AcpiOsStall (10 * ACPI_USEC_PER_SEC);
184ae115bc7Smrj
185db2bae30SDana Myers Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_CONTROL,
186ae115bc7Smrj SleepEnableRegInfo->AccessBitMask);
187ae115bc7Smrj if (ACPI_FAILURE (Status))
188ae115bc7Smrj {
189ae115bc7Smrj return_ACPI_STATUS (Status);
190ae115bc7Smrj }
191ae115bc7Smrj }
192ae115bc7Smrj
193*385cc6b4SJerry Jelinek /* Wait for transition back to Working State */
194ae115bc7Smrj
195ae115bc7Smrj do
196ae115bc7Smrj {
197aa2aa9a6SDana Myers Status = AcpiReadBitRegister (ACPI_BITREG_WAKE_STATUS, &InValue);
198ae115bc7Smrj if (ACPI_FAILURE (Status))
199ae115bc7Smrj {
200ae115bc7Smrj return_ACPI_STATUS (Status);
201ae115bc7Smrj }
202ae115bc7Smrj
203ae115bc7Smrj } while (!InValue);
204ae115bc7Smrj
205ae115bc7Smrj return_ACPI_STATUS (AE_OK);
206ae115bc7Smrj }
207ae115bc7Smrj
208ae115bc7Smrj
209ae115bc7Smrj /*******************************************************************************
210ae115bc7Smrj *
211*385cc6b4SJerry Jelinek * FUNCTION: AcpiHwLegacyWakePrep
212ae115bc7Smrj *
213ae115bc7Smrj * PARAMETERS: SleepState - Which sleep state we just exited
214ae115bc7Smrj *
215ae115bc7Smrj * RETURN: Status
216ae115bc7Smrj *
217*385cc6b4SJerry Jelinek * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a
218*385cc6b4SJerry Jelinek * sleep.
219ae115bc7Smrj * Called with interrupts ENABLED.
220ae115bc7Smrj *
221ae115bc7Smrj ******************************************************************************/
222ae115bc7Smrj
223ae115bc7Smrj ACPI_STATUS
AcpiHwLegacyWakePrep(UINT8 SleepState)224*385cc6b4SJerry Jelinek AcpiHwLegacyWakePrep (
225ae115bc7Smrj UINT8 SleepState)
226ae115bc7Smrj {
227ae115bc7Smrj ACPI_STATUS Status;
228ae115bc7Smrj ACPI_BIT_REGISTER_INFO *SleepTypeRegInfo;
229ae115bc7Smrj ACPI_BIT_REGISTER_INFO *SleepEnableRegInfo;
230aa2aa9a6SDana Myers UINT32 Pm1aControl;
231aa2aa9a6SDana Myers UINT32 Pm1bControl;
232ae115bc7Smrj
233ae115bc7Smrj
234*385cc6b4SJerry Jelinek ACPI_FUNCTION_TRACE (HwLegacyWakePrep);
235ae115bc7Smrj
236ae115bc7Smrj /*
237ae115bc7Smrj * Set SLP_TYPE and SLP_EN to state S0.
238ae115bc7Smrj * This is unclear from the ACPI Spec, but it is required
239ae115bc7Smrj * by some machines.
240ae115bc7Smrj */
241ae115bc7Smrj Status = AcpiGetSleepTypeData (ACPI_STATE_S0,
242ae115bc7Smrj &AcpiGbl_SleepTypeA, &AcpiGbl_SleepTypeB);
243ae115bc7Smrj if (ACPI_SUCCESS (Status))
244ae115bc7Smrj {
245aa2aa9a6SDana Myers SleepTypeRegInfo =
246aa2aa9a6SDana Myers AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_TYPE);
247aa2aa9a6SDana Myers SleepEnableRegInfo =
248aa2aa9a6SDana Myers AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_ENABLE);
249ae115bc7Smrj
250ae115bc7Smrj /* Get current value of PM1A control */
251ae115bc7Smrj
252db2bae30SDana Myers Status = AcpiHwRegisterRead (ACPI_REGISTER_PM1_CONTROL,
253aa2aa9a6SDana Myers &Pm1aControl);
254ae115bc7Smrj if (ACPI_SUCCESS (Status))
255ae115bc7Smrj {
256aa2aa9a6SDana Myers /* Clear the SLP_EN and SLP_TYP fields */
257ae115bc7Smrj
258aa2aa9a6SDana Myers Pm1aControl &= ~(SleepTypeRegInfo->AccessBitMask |
259ae115bc7Smrj SleepEnableRegInfo->AccessBitMask);
260aa2aa9a6SDana Myers Pm1bControl = Pm1aControl;
261ae115bc7Smrj
262aa2aa9a6SDana Myers /* Insert the SLP_TYP bits */
263ae115bc7Smrj
264aa2aa9a6SDana Myers Pm1aControl |= (AcpiGbl_SleepTypeA <<
265aa2aa9a6SDana Myers SleepTypeRegInfo->BitPosition);
266aa2aa9a6SDana Myers Pm1bControl |= (AcpiGbl_SleepTypeB <<
267aa2aa9a6SDana Myers SleepTypeRegInfo->BitPosition);
268ae115bc7Smrj
269aa2aa9a6SDana Myers /* Write the control registers and ignore any errors */
270ae115bc7Smrj
271aa2aa9a6SDana Myers (void) AcpiHwWritePm1Control (Pm1aControl, Pm1bControl);
272ae115bc7Smrj }
273ae115bc7Smrj }
274ae115bc7Smrj
275*385cc6b4SJerry Jelinek return_ACPI_STATUS (Status);
276*385cc6b4SJerry Jelinek }
277*385cc6b4SJerry Jelinek
278*385cc6b4SJerry Jelinek
279*385cc6b4SJerry Jelinek /*******************************************************************************
280*385cc6b4SJerry Jelinek *
281*385cc6b4SJerry Jelinek * FUNCTION: AcpiHwLegacyWake
282*385cc6b4SJerry Jelinek *
283*385cc6b4SJerry Jelinek * PARAMETERS: SleepState - Which sleep state we just exited
284*385cc6b4SJerry Jelinek *
285*385cc6b4SJerry Jelinek * RETURN: Status
286*385cc6b4SJerry Jelinek *
287*385cc6b4SJerry Jelinek * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep
288*385cc6b4SJerry Jelinek * Called with interrupts ENABLED.
289*385cc6b4SJerry Jelinek *
290*385cc6b4SJerry Jelinek ******************************************************************************/
291*385cc6b4SJerry Jelinek
292*385cc6b4SJerry Jelinek ACPI_STATUS
AcpiHwLegacyWake(UINT8 SleepState)293*385cc6b4SJerry Jelinek AcpiHwLegacyWake (
294*385cc6b4SJerry Jelinek UINT8 SleepState)
295*385cc6b4SJerry Jelinek {
296*385cc6b4SJerry Jelinek ACPI_STATUS Status;
297*385cc6b4SJerry Jelinek
298*385cc6b4SJerry Jelinek
299*385cc6b4SJerry Jelinek ACPI_FUNCTION_TRACE (HwLegacyWake);
300*385cc6b4SJerry Jelinek
301*385cc6b4SJerry Jelinek
302ae115bc7Smrj /* Ensure EnterSleepStatePrep -> EnterSleepState ordering */
303ae115bc7Smrj
304ae115bc7Smrj AcpiGbl_SleepTypeA = ACPI_SLEEP_TYPE_INVALID;
305*385cc6b4SJerry Jelinek AcpiHwExecuteSleepMethod (METHOD_PATHNAME__SST, ACPI_SST_WAKING);
306ae115bc7Smrj
307ae115bc7Smrj /*
308*385cc6b4SJerry Jelinek * GPEs must be enabled before _WAK is called as GPEs
309*385cc6b4SJerry Jelinek * might get fired there
310*385cc6b4SJerry Jelinek *
311ae115bc7Smrj * Restore the GPEs:
312ae115bc7Smrj * 1) Disable/Clear all GPEs
313ae115bc7Smrj * 2) Enable all runtime GPEs
314ae115bc7Smrj */
315ae115bc7Smrj Status = AcpiHwDisableAllGpes ();
316ae115bc7Smrj if (ACPI_FAILURE (Status))
317ae115bc7Smrj {
318ae115bc7Smrj return_ACPI_STATUS (Status);
319ae115bc7Smrj }
320ae115bc7Smrj
321ae115bc7Smrj Status = AcpiHwEnableAllRuntimeGpes ();
322ae115bc7Smrj if (ACPI_FAILURE (Status))
323ae115bc7Smrj {
324ae115bc7Smrj return_ACPI_STATUS (Status);
325ae115bc7Smrj }
326ae115bc7Smrj
327*385cc6b4SJerry Jelinek /*
328*385cc6b4SJerry Jelinek * Now we can execute _WAK, etc. Some machines require that the GPEs
329*385cc6b4SJerry Jelinek * are enabled before the wake methods are executed.
330*385cc6b4SJerry Jelinek */
331*385cc6b4SJerry Jelinek AcpiHwExecuteSleepMethod (METHOD_PATHNAME__WAK, SleepState);
332*385cc6b4SJerry Jelinek
333*385cc6b4SJerry Jelinek /*
334*385cc6b4SJerry Jelinek * Some BIOS code assumes that WAK_STS will be cleared on resume
335*385cc6b4SJerry Jelinek * and use it to determine whether the system is rebooting or
336*385cc6b4SJerry Jelinek * resuming. Clear WAK_STS for compatibility.
337*385cc6b4SJerry Jelinek */
338*385cc6b4SJerry Jelinek (void) AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS,
339*385cc6b4SJerry Jelinek ACPI_CLEAR_STATUS);
340*385cc6b4SJerry Jelinek AcpiGbl_SystemAwakeAndRunning = TRUE;
341*385cc6b4SJerry Jelinek
342ae115bc7Smrj /* Enable power button */
343ae115bc7Smrj
344aa2aa9a6SDana Myers (void) AcpiWriteBitRegister(
345aa2aa9a6SDana Myers AcpiGbl_FixedEventInfo[ACPI_EVENT_POWER_BUTTON].EnableRegisterId,
346aa2aa9a6SDana Myers ACPI_ENABLE_EVENT);
347ae115bc7Smrj
348aa2aa9a6SDana Myers (void) AcpiWriteBitRegister(
349aa2aa9a6SDana Myers AcpiGbl_FixedEventInfo[ACPI_EVENT_POWER_BUTTON].StatusRegisterId,
350aa2aa9a6SDana Myers ACPI_CLEAR_STATUS);
351ae115bc7Smrj
352*385cc6b4SJerry Jelinek AcpiHwExecuteSleepMethod (METHOD_PATHNAME__SST, ACPI_SST_WORKING);
353ae115bc7Smrj return_ACPI_STATUS (Status);
354ae115bc7Smrj }
355ae115bc7Smrj
356*385cc6b4SJerry Jelinek #endif /* !ACPI_REDUCED_HARDWARE */
357