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