xref: /titanic_52/usr/src/uts/intel/io/acpica/hardware/hwsleep.c (revision 385cc6b4ad1792caef3f84eb61eed3f27085801f)
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
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
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
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