hwsleep.c revision 217365
171867Smsmith
271867Smsmith/******************************************************************************
371867Smsmith *
471867Smsmith * Name: hwsleep.c - ACPI Hardware Sleep/Wake Interface
571867Smsmith *
671867Smsmith *****************************************************************************/
771867Smsmith
8217365Sjkim/*
9217365Sjkim * Copyright (C) 2000 - 2011, Intel Corp.
1071867Smsmith * All rights reserved.
1171867Smsmith *
12217365Sjkim * Redistribution and use in source and binary forms, with or without
13217365Sjkim * modification, are permitted provided that the following conditions
14217365Sjkim * are met:
15217365Sjkim * 1. Redistributions of source code must retain the above copyright
16217365Sjkim *    notice, this list of conditions, and the following disclaimer,
17217365Sjkim *    without modification.
18217365Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer
19217365Sjkim *    substantially similar to the "NO WARRANTY" disclaimer below
20217365Sjkim *    ("Disclaimer") and any redistribution must be conditioned upon
21217365Sjkim *    including a substantially similar Disclaimer requirement for further
22217365Sjkim *    binary redistribution.
23217365Sjkim * 3. Neither the names of the above-listed copyright holders nor the names
24217365Sjkim *    of any contributors may be used to endorse or promote products derived
25217365Sjkim *    from this software without specific prior written permission.
2671867Smsmith *
27217365Sjkim * Alternatively, this software may be distributed under the terms of the
28217365Sjkim * GNU General Public License ("GPL") version 2 as published by the Free
29217365Sjkim * Software Foundation.
3071867Smsmith *
31217365Sjkim * NO WARRANTY
32217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
33217365Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
34217365Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
35217365Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
36217365Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40217365Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
41217365Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42217365Sjkim * POSSIBILITY OF SUCH DAMAGES.
43217365Sjkim */
4471867Smsmith
45193341Sjkim#include <contrib/dev/acpica/include/acpi.h>
46193341Sjkim#include <contrib/dev/acpica/include/accommon.h>
4771867Smsmith
4877424Smsmith#define _COMPONENT          ACPI_HARDWARE
4991116Smsmith        ACPI_MODULE_NAME    ("hwsleep")
5071867Smsmith
5171867Smsmith
52151937Sjkim/*******************************************************************************
5371867Smsmith *
5471867Smsmith * FUNCTION:    AcpiSetFirmwareWakingVector
5571867Smsmith *
56193267Sjkim * PARAMETERS:  PhysicalAddress     - 32-bit physical address of ACPI real mode
5771867Smsmith *                                    entry point.
5871867Smsmith *
5991116Smsmith * RETURN:      Status
6071867Smsmith *
61193267Sjkim * DESCRIPTION: Sets the 32-bit FirmwareWakingVector field of the FACS
6271867Smsmith *
6371867Smsmith ******************************************************************************/
6471867Smsmith
6571867SmsmithACPI_STATUS
6671867SmsmithAcpiSetFirmwareWakingVector (
67193267Sjkim    UINT32                  PhysicalAddress)
6871867Smsmith{
69193267Sjkim    ACPI_FUNCTION_TRACE (AcpiSetFirmwareWakingVector);
7071867Smsmith
7171867Smsmith
72193267Sjkim    /* Set the 32-bit vector */
7371867Smsmith
74193267Sjkim    AcpiGbl_FACS->FirmwareWakingVector = PhysicalAddress;
75167802Sjkim
76193267Sjkim    /* Clear the 64-bit vector if it exists */
77167802Sjkim
78193267Sjkim    if ((AcpiGbl_FACS->Length > 32) && (AcpiGbl_FACS->Version >= 1))
7971867Smsmith    {
80193267Sjkim        AcpiGbl_FACS->XFirmwareWakingVector = 0;
8171867Smsmith    }
8271867Smsmith
8371867Smsmith    return_ACPI_STATUS (AE_OK);
8471867Smsmith}
8571867Smsmith
86167802SjkimACPI_EXPORT_SYMBOL (AcpiSetFirmwareWakingVector)
8771867Smsmith
88167802Sjkim
89193267Sjkim#if ACPI_MACHINE_WIDTH == 64
90151937Sjkim/*******************************************************************************
9171867Smsmith *
92193267Sjkim * FUNCTION:    AcpiSetFirmwareWakingVector64
9371867Smsmith *
94193267Sjkim * PARAMETERS:  PhysicalAddress     - 64-bit physical address of ACPI protected
95193267Sjkim *                                    mode entry point.
9671867Smsmith *
97193267Sjkim * RETURN:      Status
9871867Smsmith *
99193267Sjkim * DESCRIPTION: Sets the 64-bit X_FirmwareWakingVector field of the FACS, if
100193267Sjkim *              it exists in the table. This function is intended for use with
101193267Sjkim *              64-bit host operating systems.
10271867Smsmith *
10371867Smsmith ******************************************************************************/
10471867Smsmith
10571867SmsmithACPI_STATUS
106193267SjkimAcpiSetFirmwareWakingVector64 (
107193267Sjkim    UINT64                  PhysicalAddress)
10871867Smsmith{
109193267Sjkim    ACPI_FUNCTION_TRACE (AcpiSetFirmwareWakingVector64);
11071867Smsmith
11171867Smsmith
112193267Sjkim    /* Determine if the 64-bit vector actually exists */
11371867Smsmith
114193267Sjkim    if ((AcpiGbl_FACS->Length <= 32) || (AcpiGbl_FACS->Version < 1))
11571867Smsmith    {
116193267Sjkim        return_ACPI_STATUS (AE_NOT_EXIST);
11771867Smsmith    }
11871867Smsmith
119193267Sjkim    /* Clear 32-bit vector, set the 64-bit X_ vector */
120167802Sjkim
121193267Sjkim    AcpiGbl_FACS->FirmwareWakingVector = 0;
122193267Sjkim    AcpiGbl_FACS->XFirmwareWakingVector = PhysicalAddress;
12371867Smsmith    return_ACPI_STATUS (AE_OK);
12471867Smsmith}
12571867Smsmith
126193267SjkimACPI_EXPORT_SYMBOL (AcpiSetFirmwareWakingVector64)
127193267Sjkim#endif
12887031Smsmith
129151937Sjkim/*******************************************************************************
13071867Smsmith *
13187031Smsmith * FUNCTION:    AcpiEnterSleepStatePrep
13271867Smsmith *
13371867Smsmith * PARAMETERS:  SleepState          - Which sleep state to enter
13471867Smsmith *
13571867Smsmith * RETURN:      Status
13671867Smsmith *
13787031Smsmith * DESCRIPTION: Prepare to enter a system sleep state (see ACPI 2.0 spec p 231)
13887031Smsmith *              This function must execute with interrupts enabled.
13987031Smsmith *              We break sleeping into 2 stages so that OSPM can handle
14087031Smsmith *              various OS-specific tasks between the two steps.
14171867Smsmith *
14271867Smsmith ******************************************************************************/
14371867Smsmith
14471867SmsmithACPI_STATUS
14587031SmsmithAcpiEnterSleepStatePrep (
146193267Sjkim    UINT8                   SleepState)
14771867Smsmith{
148193267Sjkim    ACPI_STATUS             Status;
149193267Sjkim    ACPI_OBJECT_LIST        ArgList;
150193267Sjkim    ACPI_OBJECT             Arg;
15171867Smsmith
15277424Smsmith
153167802Sjkim    ACPI_FUNCTION_TRACE (AcpiEnterSleepStatePrep);
15491116Smsmith
15591116Smsmith
156193267Sjkim    /* _PSW methods could be run here to enable wake-on keyboard, LAN, etc. */
157193267Sjkim
15899679Siwasaki    Status = AcpiGetSleepTypeData (SleepState,
15991116Smsmith                    &AcpiGbl_SleepTypeA, &AcpiGbl_SleepTypeB);
16091116Smsmith    if (ACPI_FAILURE (Status))
16171867Smsmith    {
16287031Smsmith        return_ACPI_STATUS (Status);
16371867Smsmith    }
16471867Smsmith
165193267Sjkim    /* Execute the _PTS method (Prepare To Sleep) */
16677424Smsmith
16771867Smsmith    ArgList.Count = 1;
16871867Smsmith    ArgList.Pointer = &Arg;
16971867Smsmith    Arg.Type = ACPI_TYPE_INTEGER;
17071867Smsmith    Arg.Integer.Value = SleepState;
17171867Smsmith
172126372Snjl    Status = AcpiEvaluateObject (NULL, METHOD_NAME__PTS, &ArgList, NULL);
17391116Smsmith    if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND)
17491116Smsmith    {
17591116Smsmith        return_ACPI_STATUS (Status);
17691116Smsmith    }
17791116Smsmith
178193267Sjkim    /* Setup the argument to the _SST method (System STatus) */
17991116Smsmith
180126372Snjl    switch (SleepState)
181126372Snjl    {
182126372Snjl    case ACPI_STATE_S0:
183126372Snjl        Arg.Integer.Value = ACPI_SST_WORKING;
184126372Snjl        break;
185126372Snjl
186126372Snjl    case ACPI_STATE_S1:
187126372Snjl    case ACPI_STATE_S2:
188126372Snjl    case ACPI_STATE_S3:
189126372Snjl        Arg.Integer.Value = ACPI_SST_SLEEPING;
190126372Snjl        break;
191126372Snjl
192126372Snjl    case ACPI_STATE_S4:
193126372Snjl        Arg.Integer.Value = ACPI_SST_SLEEP_CONTEXT;
194126372Snjl        break;
195126372Snjl
196126372Snjl    default:
197151937Sjkim        Arg.Integer.Value = ACPI_SST_INDICATOR_OFF; /* Default is off */
198126372Snjl        break;
199126372Snjl    }
200126372Snjl
201193267Sjkim    /*
202193267Sjkim     * Set the system indicators to show the desired sleep state.
203193267Sjkim     * _SST is an optional method (return no error if not found)
204193267Sjkim     */
205126372Snjl    Status = AcpiEvaluateObject (NULL, METHOD_NAME__SST, &ArgList, NULL);
206123315Snjl    if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND)
207123315Snjl    {
208167802Sjkim        ACPI_EXCEPTION ((AE_INFO, Status, "While executing method _SST"));
209123315Snjl    }
210123315Snjl
21187031Smsmith    return_ACPI_STATUS (AE_OK);
21287031Smsmith}
21387031Smsmith
214167802SjkimACPI_EXPORT_SYMBOL (AcpiEnterSleepStatePrep)
21587031Smsmith
216167802Sjkim
217151937Sjkim/*******************************************************************************
21887031Smsmith *
21987031Smsmith * FUNCTION:    AcpiEnterSleepState
22087031Smsmith *
22187031Smsmith * PARAMETERS:  SleepState          - Which sleep state to enter
22287031Smsmith *
22387031Smsmith * RETURN:      Status
22487031Smsmith *
225193267Sjkim * DESCRIPTION: Enter a system sleep state
22687031Smsmith *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
22787031Smsmith *
22887031Smsmith ******************************************************************************/
22987031Smsmith
23087031SmsmithACPI_STATUS
23187031SmsmithAcpiEnterSleepState (
23291116Smsmith    UINT8                   SleepState)
23387031Smsmith{
234193267Sjkim    UINT32                  Pm1aControl;
235193267Sjkim    UINT32                  Pm1bControl;
23691116Smsmith    ACPI_BIT_REGISTER_INFO  *SleepTypeRegInfo;
23791116Smsmith    ACPI_BIT_REGISTER_INFO  *SleepEnableRegInfo;
23899679Siwasaki    UINT32                  InValue;
239193267Sjkim    ACPI_OBJECT_LIST        ArgList;
240193267Sjkim    ACPI_OBJECT             Arg;
241193335Sjkim    UINT32                  Retry;
24299679Siwasaki    ACPI_STATUS             Status;
24387031Smsmith
24487031Smsmith
245167802Sjkim    ACPI_FUNCTION_TRACE (AcpiEnterSleepState);
24687031Smsmith
24791116Smsmith
24891116Smsmith    if ((AcpiGbl_SleepTypeA > ACPI_SLEEP_TYPE_MAX) ||
24991116Smsmith        (AcpiGbl_SleepTypeB > ACPI_SLEEP_TYPE_MAX))
25087031Smsmith    {
251204773Sjkim        ACPI_ERROR ((AE_INFO, "Sleep values out of range: A=0x%X B=0x%X",
25291116Smsmith            AcpiGbl_SleepTypeA, AcpiGbl_SleepTypeB));
25391116Smsmith        return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
25487031Smsmith    }
25587031Smsmith
256193267Sjkim    SleepTypeRegInfo   = AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_TYPE);
25791116Smsmith    SleepEnableRegInfo = AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_ENABLE);
25871867Smsmith
259128245Snjl    /* Clear wake status */
260128245Snjl
261193267Sjkim    Status = AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS);
262128245Snjl    if (ACPI_FAILURE (Status))
26399679Siwasaki    {
264128245Snjl        return_ACPI_STATUS (Status);
265128245Snjl    }
26678986Smsmith
267129684Snjl    /* Clear all fixed and general purpose status bits */
268129684Snjl
269167802Sjkim    Status = AcpiHwClearAcpiStatus ();
270128245Snjl    if (ACPI_FAILURE (Status))
271128245Snjl    {
272128245Snjl        return_ACPI_STATUS (Status);
273128245Snjl    }
27487031Smsmith
275128245Snjl    if (SleepState != ACPI_STATE_S5)
276128245Snjl    {
277197104Sjkim        /*
278197104Sjkim         * Disable BM arbitration. This feature is contained within an
279197104Sjkim         * optional register (PM2 Control), so ignore a BAD_ADDRESS
280197104Sjkim         * exception.
281197104Sjkim         */
282193267Sjkim        Status = AcpiWriteBitRegister (ACPI_BITREG_ARB_DISABLE, 1);
283197104Sjkim        if (ACPI_FAILURE (Status) && (Status != AE_BAD_ADDRESS))
284123315Snjl        {
285123315Snjl            return_ACPI_STATUS (Status);
286123315Snjl        }
28799679Siwasaki    }
28899679Siwasaki
289128212Snjl    /*
290129684Snjl     * 1) Disable/Clear all GPEs
291128212Snjl     * 2) Enable all wakeup GPEs
292128212Snjl     */
293151937Sjkim    Status = AcpiHwDisableAllGpes ();
29499679Siwasaki    if (ACPI_FAILURE (Status))
29599679Siwasaki    {
29699679Siwasaki        return_ACPI_STATUS (Status);
29799679Siwasaki    }
298129684Snjl    AcpiGbl_SystemAwakeAndRunning = FALSE;
29999679Siwasaki
300151937Sjkim    Status = AcpiHwEnableAllWakeupGpes ();
301129684Snjl    if (ACPI_FAILURE (Status))
302129684Snjl    {
303129684Snjl        return_ACPI_STATUS (Status);
304129684Snjl    }
305129684Snjl
306193267Sjkim    /* Execute the _GTS method (Going To Sleep) */
307193267Sjkim
308193267Sjkim    ArgList.Count = 1;
309193267Sjkim    ArgList.Pointer = &Arg;
310193267Sjkim    Arg.Type = ACPI_TYPE_INTEGER;
311193267Sjkim    Arg.Integer.Value = SleepState;
312193267Sjkim
313193267Sjkim    Status = AcpiEvaluateObject (NULL, METHOD_NAME__GTS, &ArgList, NULL);
314193267Sjkim    if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND)
315193267Sjkim    {
316193267Sjkim        return_ACPI_STATUS (Status);
317193267Sjkim    }
318193267Sjkim
31991116Smsmith    /* Get current value of PM1A control */
32078986Smsmith
321193267Sjkim    Status = AcpiHwRegisterRead (ACPI_REGISTER_PM1_CONTROL,
322193267Sjkim                &Pm1aControl);
32399679Siwasaki    if (ACPI_FAILURE (Status))
32499679Siwasaki    {
32599679Siwasaki        return_ACPI_STATUS (Status);
32699679Siwasaki    }
327151937Sjkim    ACPI_DEBUG_PRINT ((ACPI_DB_INIT,
328209746Sjkim        "Entering sleep state [S%u]\n", SleepState));
32982367Smsmith
330193267Sjkim    /* Clear the SLP_EN and SLP_TYP fields */
33182367Smsmith
332193267Sjkim    Pm1aControl &= ~(SleepTypeRegInfo->AccessBitMask |
333151937Sjkim                     SleepEnableRegInfo->AccessBitMask);
334193267Sjkim    Pm1bControl = Pm1aControl;
33571867Smsmith
336193267Sjkim    /* Insert the SLP_TYP bits */
33782367Smsmith
338193267Sjkim    Pm1aControl |= (AcpiGbl_SleepTypeA << SleepTypeRegInfo->BitPosition);
339193267Sjkim    Pm1bControl |= (AcpiGbl_SleepTypeB << SleepTypeRegInfo->BitPosition);
34071867Smsmith
341126372Snjl    /*
342126372Snjl     * We split the writes of SLP_TYP and SLP_EN to workaround
343126372Snjl     * poorly implemented hardware.
344126372Snjl     */
345126372Snjl
346193267Sjkim    /* Write #1: write the SLP_TYP data to the PM1 Control registers */
34771867Smsmith
348193267Sjkim    Status = AcpiHwWritePm1Control (Pm1aControl, Pm1bControl);
34999679Siwasaki    if (ACPI_FAILURE (Status))
35099679Siwasaki    {
35199679Siwasaki        return_ACPI_STATUS (Status);
35299679Siwasaki    }
35382367Smsmith
354193267Sjkim    /* Insert the sleep enable (SLP_EN) bit */
35599679Siwasaki
356193267Sjkim    Pm1aControl |= SleepEnableRegInfo->AccessBitMask;
357193267Sjkim    Pm1bControl |= SleepEnableRegInfo->AccessBitMask;
35882367Smsmith
359193267Sjkim    /* Flush caches, as per ACPI specification */
36071867Smsmith
36199679Siwasaki    ACPI_FLUSH_CPU_CACHE ();
36280062Smsmith
363193267Sjkim    /* Write #2: Write both SLP_TYP + SLP_EN */
36499679Siwasaki
365193267Sjkim    Status = AcpiHwWritePm1Control (Pm1aControl, Pm1bControl);
36699679Siwasaki    if (ACPI_FAILURE (Status))
36799679Siwasaki    {
36899679Siwasaki        return_ACPI_STATUS (Status);
36999679Siwasaki    }
37099679Siwasaki
37182367Smsmith    if (SleepState > ACPI_STATE_S3)
37282367Smsmith    {
37399679Siwasaki        /*
374151937Sjkim         * We wanted to sleep > S3, but it didn't happen (by virtue of the
375151937Sjkim         * fact that we are still executing!)
376123315Snjl         *
377151937Sjkim         * Wait ten seconds, then try again. This is to get S4/S5 to work on
378151937Sjkim         * all machines.
379123315Snjl         *
380193267Sjkim         * We wait so long to allow chipsets that poll this reg very slowly
381193267Sjkim         * to still read the right value. Ideally, this block would go
38299679Siwasaki         * away entirely.
38399679Siwasaki         */
38499679Siwasaki        AcpiOsStall (10000000);
38582367Smsmith
386193267Sjkim        Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_CONTROL,
38799679Siwasaki                    SleepEnableRegInfo->AccessBitMask);
38899679Siwasaki        if (ACPI_FAILURE (Status))
38999679Siwasaki        {
39099679Siwasaki            return_ACPI_STATUS (Status);
39199679Siwasaki        }
39280357Speter    }
39380062Smsmith
39491116Smsmith    /* Wait until we enter sleep state */
39571867Smsmith
396193335Sjkim    Retry = 1000;
397102550Siwasaki    do
39883174Smsmith    {
399193267Sjkim        Status = AcpiReadBitRegister (ACPI_BITREG_WAKE_STATUS, &InValue);
40099679Siwasaki        if (ACPI_FAILURE (Status))
40199679Siwasaki        {
40299679Siwasaki            return_ACPI_STATUS (Status);
40399679Siwasaki        }
40499679Siwasaki
405204920Sjkim        if (AcpiGbl_EnableInterpreterSlack)
406193335Sjkim        {
407204920Sjkim            /*
408204920Sjkim             * Some BIOSs don't set WAK_STS at all.  Give up waiting after
409204920Sjkim             * 1000 retries if it still isn't set.
410204920Sjkim             */
411204920Sjkim            if (Retry-- == 0)
412204920Sjkim            {
413204920Sjkim                break;
414204920Sjkim            }
415193335Sjkim        }
416193335Sjkim
41791116Smsmith        /* Spin until we wake */
41882367Smsmith
41999679Siwasaki    } while (!InValue);
42099679Siwasaki
42171867Smsmith    return_ACPI_STATUS (AE_OK);
42271867Smsmith}
42382367Smsmith
424167802SjkimACPI_EXPORT_SYMBOL (AcpiEnterSleepState)
425114237Snjl
426167802Sjkim
427151937Sjkim/*******************************************************************************
42882367Smsmith *
429114237Snjl * FUNCTION:    AcpiEnterSleepStateS4bios
430114237Snjl *
431114237Snjl * PARAMETERS:  None
432114237Snjl *
433114237Snjl * RETURN:      Status
434114237Snjl *
435114237Snjl * DESCRIPTION: Perform a S4 bios request.
436114237Snjl *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
437114237Snjl *
438114237Snjl ******************************************************************************/
439114237Snjl
440114237SnjlACPI_STATUS
441114237SnjlAcpiEnterSleepStateS4bios (
442114237Snjl    void)
443114237Snjl{
444114237Snjl    UINT32                  InValue;
445114237Snjl    ACPI_STATUS             Status;
446114237Snjl
447114237Snjl
448167802Sjkim    ACPI_FUNCTION_TRACE (AcpiEnterSleepStateS4bios);
449114237Snjl
450123315Snjl
451193267Sjkim    /* Clear the wake status bit (PM1) */
452193267Sjkim
453193267Sjkim    Status = AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS);
454126372Snjl    if (ACPI_FAILURE (Status))
455126372Snjl    {
456126372Snjl        return_ACPI_STATUS (Status);
457126372Snjl    }
458114237Snjl
459167802Sjkim    Status = AcpiHwClearAcpiStatus ();
460126372Snjl    if (ACPI_FAILURE (Status))
461126372Snjl    {
462126372Snjl        return_ACPI_STATUS (Status);
463126372Snjl    }
464114237Snjl
465128212Snjl    /*
466129684Snjl     * 1) Disable/Clear all GPEs
467128212Snjl     * 2) Enable all wakeup GPEs
468128212Snjl     */
469151937Sjkim    Status = AcpiHwDisableAllGpes ();
470126372Snjl    if (ACPI_FAILURE (Status))
471126372Snjl    {
472126372Snjl        return_ACPI_STATUS (Status);
473126372Snjl    }
474129684Snjl    AcpiGbl_SystemAwakeAndRunning = FALSE;
475114237Snjl
476151937Sjkim    Status = AcpiHwEnableAllWakeupGpes ();
477129684Snjl    if (ACPI_FAILURE (Status))
478129684Snjl    {
479129684Snjl        return_ACPI_STATUS (Status);
480129684Snjl    }
481129684Snjl
482126372Snjl    ACPI_FLUSH_CPU_CACHE ();
483126372Snjl
484193267Sjkim    Status = AcpiHwWritePort (AcpiGbl_FADT.SmiCommand,
485167802Sjkim                (UINT32) AcpiGbl_FADT.S4BiosRequest, 8);
486114237Snjl
487114237Snjl    do {
488114237Snjl        AcpiOsStall(1000);
489193267Sjkim        Status = AcpiReadBitRegister (ACPI_BITREG_WAKE_STATUS, &InValue);
490114237Snjl        if (ACPI_FAILURE (Status))
491114237Snjl        {
492114237Snjl            return_ACPI_STATUS (Status);
493114237Snjl        }
494114237Snjl    } while (!InValue);
495114237Snjl
496114237Snjl    return_ACPI_STATUS (AE_OK);
497114237Snjl}
498114237Snjl
499167802SjkimACPI_EXPORT_SYMBOL (AcpiEnterSleepStateS4bios)
500114237Snjl
501167802Sjkim
502151937Sjkim/*******************************************************************************
503114237Snjl *
50482367Smsmith * FUNCTION:    AcpiLeaveSleepState
50582367Smsmith *
50682367Smsmith * PARAMETERS:  SleepState          - Which sleep state we just exited
50782367Smsmith *
50882367Smsmith * RETURN:      Status
50982367Smsmith *
51082367Smsmith * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep
511138287Smarks *              Called with interrupts ENABLED.
51282367Smsmith *
51382367Smsmith ******************************************************************************/
51482367Smsmith
51582367SmsmithACPI_STATUS
51682367SmsmithAcpiLeaveSleepState (
517123315Snjl    UINT8                   SleepState)
51882367Smsmith{
519123315Snjl    ACPI_OBJECT_LIST        ArgList;
520123315Snjl    ACPI_OBJECT             Arg;
521123315Snjl    ACPI_STATUS             Status;
522123315Snjl    ACPI_BIT_REGISTER_INFO  *SleepTypeRegInfo;
523123315Snjl    ACPI_BIT_REGISTER_INFO  *SleepEnableRegInfo;
524193267Sjkim    UINT32                  Pm1aControl;
525193267Sjkim    UINT32                  Pm1bControl;
52682367Smsmith
52783174Smsmith
528167802Sjkim    ACPI_FUNCTION_TRACE (AcpiLeaveSleepState);
52982367Smsmith
53091116Smsmith
531126372Snjl    /*
532126372Snjl     * Set SLP_TYPE and SLP_EN to state S0.
533126372Snjl     * This is unclear from the ACPI Spec, but it is required
534126372Snjl     * by some machines.
535126372Snjl     */
536126372Snjl    Status = AcpiGetSleepTypeData (ACPI_STATE_S0,
537126372Snjl                    &AcpiGbl_SleepTypeA, &AcpiGbl_SleepTypeB);
538123315Snjl    if (ACPI_SUCCESS (Status))
539123315Snjl    {
540193267Sjkim        SleepTypeRegInfo =
541193267Sjkim            AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_TYPE);
542193267Sjkim        SleepEnableRegInfo =
543193267Sjkim            AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_ENABLE);
544123315Snjl
545126372Snjl        /* Get current value of PM1A control */
546123315Snjl
547193267Sjkim        Status = AcpiHwRegisterRead (ACPI_REGISTER_PM1_CONTROL,
548193267Sjkim                    &Pm1aControl);
549126372Snjl        if (ACPI_SUCCESS (Status))
550126372Snjl        {
551193267Sjkim            /* Clear the SLP_EN and SLP_TYP fields */
552126372Snjl
553193267Sjkim            Pm1aControl &= ~(SleepTypeRegInfo->AccessBitMask |
554193267Sjkim                SleepEnableRegInfo->AccessBitMask);
555193267Sjkim            Pm1bControl = Pm1aControl;
556126372Snjl
557193267Sjkim            /* Insert the SLP_TYP bits */
558126372Snjl
559193267Sjkim            Pm1aControl |= (AcpiGbl_SleepTypeA <<
560193267Sjkim                SleepTypeRegInfo->BitPosition);
561193267Sjkim            Pm1bControl |= (AcpiGbl_SleepTypeB <<
562193267Sjkim                SleepTypeRegInfo->BitPosition);
563126372Snjl
564193267Sjkim            /* Write the control registers and ignore any errors */
565126372Snjl
566193267Sjkim            (void) AcpiHwWritePm1Control (Pm1aControl, Pm1bControl);
567126372Snjl        }
568123315Snjl    }
569123315Snjl
57087031Smsmith    /* Ensure EnterSleepStatePrep -> EnterSleepState ordering */
57182367Smsmith
57291116Smsmith    AcpiGbl_SleepTypeA = ACPI_SLEEP_TYPE_INVALID;
57391116Smsmith
57491116Smsmith    /* Setup parameter object */
57591116Smsmith
57682367Smsmith    ArgList.Count = 1;
57782367Smsmith    ArgList.Pointer = &Arg;
57882367Smsmith    Arg.Type = ACPI_TYPE_INTEGER;
57982367Smsmith
58091116Smsmith    /* Ignore any errors from these methods */
58183174Smsmith
582126372Snjl    Arg.Integer.Value = ACPI_SST_WAKING;
583126372Snjl    Status = AcpiEvaluateObject (NULL, METHOD_NAME__SST, &ArgList, NULL);
584123315Snjl    if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND)
585123315Snjl    {
586167802Sjkim        ACPI_EXCEPTION ((AE_INFO, Status, "During Method _SST"));
587123315Snjl    }
588123315Snjl
589123315Snjl    Arg.Integer.Value = SleepState;
590126372Snjl    Status = AcpiEvaluateObject (NULL, METHOD_NAME__BFS, &ArgList, NULL);
59191116Smsmith    if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND)
59291116Smsmith    {
593167802Sjkim        ACPI_EXCEPTION ((AE_INFO, Status, "During Method _BFS"));
59491116Smsmith    }
59591116Smsmith
596126372Snjl    Status = AcpiEvaluateObject (NULL, METHOD_NAME__WAK, &ArgList, NULL);
59791116Smsmith    if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND)
59891116Smsmith    {
599167802Sjkim        ACPI_EXCEPTION ((AE_INFO, Status, "During Method _WAK"));
60091116Smsmith    }
601128212Snjl    /* TBD: _WAK "sometimes" returns stuff - do we want to look at it? */
60291116Smsmith
603128212Snjl    /*
604128212Snjl     * Restore the GPEs:
605129684Snjl     * 1) Disable/Clear all GPEs
606128212Snjl     * 2) Enable all runtime GPEs
607128212Snjl     */
608151937Sjkim    Status = AcpiHwDisableAllGpes ();
60999679Siwasaki    if (ACPI_FAILURE (Status))
61099679Siwasaki    {
61199679Siwasaki        return_ACPI_STATUS (Status);
61299679Siwasaki    }
613129684Snjl    AcpiGbl_SystemAwakeAndRunning = TRUE;
61482367Smsmith
615151937Sjkim    Status = AcpiHwEnableAllRuntimeGpes ();
616129684Snjl    if (ACPI_FAILURE (Status))
617129684Snjl    {
618129684Snjl        return_ACPI_STATUS (Status);
619129684Snjl    }
620129684Snjl
621126372Snjl    /* Enable power button */
622126372Snjl
623193267Sjkim    (void) AcpiWriteBitRegister(
624193267Sjkim            AcpiGbl_FixedEventInfo[ACPI_EVENT_POWER_BUTTON].EnableRegisterId,
625193267Sjkim            ACPI_ENABLE_EVENT);
626151937Sjkim
627193267Sjkim    (void) AcpiWriteBitRegister(
628193267Sjkim            AcpiGbl_FixedEventInfo[ACPI_EVENT_POWER_BUTTON].StatusRegisterId,
629193267Sjkim            ACPI_CLEAR_STATUS);
630126372Snjl
631197104Sjkim    /*
632197104Sjkim     * Enable BM arbitration. This feature is contained within an
633197104Sjkim     * optional register (PM2 Control), so ignore a BAD_ADDRESS
634197104Sjkim     * exception.
635197104Sjkim     */
636193267Sjkim    Status = AcpiWriteBitRegister (ACPI_BITREG_ARB_DISABLE, 0);
637197104Sjkim    if (ACPI_FAILURE (Status) && (Status != AE_BAD_ADDRESS))
638126372Snjl    {
639126372Snjl        return_ACPI_STATUS (Status);
640126372Snjl    }
641126372Snjl
642126372Snjl    Arg.Integer.Value = ACPI_SST_WORKING;
643126372Snjl    Status = AcpiEvaluateObject (NULL, METHOD_NAME__SST, &ArgList, NULL);
644126372Snjl    if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND)
645126372Snjl    {
646167802Sjkim        ACPI_EXCEPTION ((AE_INFO, Status, "During Method _SST"));
647126372Snjl    }
648126372Snjl
64999679Siwasaki    return_ACPI_STATUS (Status);
65082367Smsmith}
651167802Sjkim
652167802SjkimACPI_EXPORT_SYMBOL (AcpiLeaveSleepState)
653167802Sjkim
654