hwsleep.c revision 167802
171867Smsmith
271867Smsmith/******************************************************************************
371867Smsmith *
471867Smsmith * Name: hwsleep.c - ACPI Hardware Sleep/Wake Interface
5167802Sjkim *              $Revision: 1.87 $
671867Smsmith *
771867Smsmith *****************************************************************************/
871867Smsmith
971867Smsmith/******************************************************************************
1071867Smsmith *
1171867Smsmith * 1. Copyright Notice
1271867Smsmith *
13167802Sjkim * Some or all of this work - Copyright (c) 1999 - 2007, Intel Corp.
1471867Smsmith * All rights reserved.
1571867Smsmith *
1671867Smsmith * 2. License
1771867Smsmith *
1871867Smsmith * 2.1. This is your license from Intel Corp. under its intellectual property
1971867Smsmith * rights.  You may have additional license terms from the party that provided
2071867Smsmith * you this software, covering your right to use that party's intellectual
2171867Smsmith * property rights.
2271867Smsmith *
2371867Smsmith * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
2471867Smsmith * copy of the source code appearing in this file ("Covered Code") an
2571867Smsmith * irrevocable, perpetual, worldwide license under Intel's copyrights in the
2671867Smsmith * base code distributed originally by Intel ("Original Intel Code") to copy,
2771867Smsmith * make derivatives, distribute, use and display any portion of the Covered
2871867Smsmith * Code in any form, with the right to sublicense such rights; and
2971867Smsmith *
3071867Smsmith * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
3171867Smsmith * license (with the right to sublicense), under only those claims of Intel
3271867Smsmith * patents that are infringed by the Original Intel Code, to make, use, sell,
3371867Smsmith * offer to sell, and import the Covered Code and derivative works thereof
3471867Smsmith * solely to the minimum extent necessary to exercise the above copyright
3571867Smsmith * license, and in no event shall the patent license extend to any additions
3671867Smsmith * to or modifications of the Original Intel Code.  No other license or right
3771867Smsmith * is granted directly or by implication, estoppel or otherwise;
3871867Smsmith *
3971867Smsmith * The above copyright and patent license is granted only if the following
4071867Smsmith * conditions are met:
4171867Smsmith *
4271867Smsmith * 3. Conditions
4371867Smsmith *
4471867Smsmith * 3.1. Redistribution of Source with Rights to Further Distribute Source.
4571867Smsmith * Redistribution of source code of any substantial portion of the Covered
4671867Smsmith * Code or modification with rights to further distribute source must include
4771867Smsmith * the above Copyright Notice, the above License, this list of Conditions,
4871867Smsmith * and the following Disclaimer and Export Compliance provision.  In addition,
4971867Smsmith * Licensee must cause all Covered Code to which Licensee contributes to
5071867Smsmith * contain a file documenting the changes Licensee made to create that Covered
5171867Smsmith * Code and the date of any change.  Licensee must include in that file the
5271867Smsmith * documentation of any changes made by any predecessor Licensee.  Licensee
5371867Smsmith * must include a prominent statement that the modification is derived,
5471867Smsmith * directly or indirectly, from Original Intel Code.
5571867Smsmith *
5671867Smsmith * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
5771867Smsmith * Redistribution of source code of any substantial portion of the Covered
5871867Smsmith * Code or modification without rights to further distribute source must
5971867Smsmith * include the following Disclaimer and Export Compliance provision in the
6071867Smsmith * documentation and/or other materials provided with distribution.  In
6171867Smsmith * addition, Licensee may not authorize further sublicense of source of any
6271867Smsmith * portion of the Covered Code, and must include terms to the effect that the
6371867Smsmith * license from Licensee to its licensee is limited to the intellectual
6471867Smsmith * property embodied in the software Licensee provides to its licensee, and
6571867Smsmith * not to intellectual property embodied in modifications its licensee may
6671867Smsmith * make.
6771867Smsmith *
6871867Smsmith * 3.3. Redistribution of Executable. Redistribution in executable form of any
6971867Smsmith * substantial portion of the Covered Code or modification must reproduce the
7071867Smsmith * above Copyright Notice, and the following Disclaimer and Export Compliance
7171867Smsmith * provision in the documentation and/or other materials provided with the
7271867Smsmith * distribution.
7371867Smsmith *
7471867Smsmith * 3.4. Intel retains all right, title, and interest in and to the Original
7571867Smsmith * Intel Code.
7671867Smsmith *
7771867Smsmith * 3.5. Neither the name Intel nor any other trademark owned or controlled by
7871867Smsmith * Intel shall be used in advertising or otherwise to promote the sale, use or
7971867Smsmith * other dealings in products derived from or relating to the Covered Code
8071867Smsmith * without prior written authorization from Intel.
8171867Smsmith *
8271867Smsmith * 4. Disclaimer and Export Compliance
8371867Smsmith *
8471867Smsmith * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
8571867Smsmith * HERE.  ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
8671867Smsmith * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT,  ASSISTANCE,
8771867Smsmith * INSTALLATION, TRAINING OR OTHER SERVICES.  INTEL WILL NOT PROVIDE ANY
8871867Smsmith * UPDATES, ENHANCEMENTS OR EXTENSIONS.  INTEL SPECIFICALLY DISCLAIMS ANY
8971867Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
9071867Smsmith * PARTICULAR PURPOSE.
9171867Smsmith *
9271867Smsmith * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
9371867Smsmith * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
9471867Smsmith * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
9571867Smsmith * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
9671867Smsmith * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
9771867Smsmith * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES.  THESE LIMITATIONS
9871867Smsmith * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
9971867Smsmith * LIMITED REMEDY.
10071867Smsmith *
10171867Smsmith * 4.3. Licensee shall not export, either directly or indirectly, any of this
10271867Smsmith * software or system incorporating such software without first obtaining any
10371867Smsmith * required license or other approval from the U. S. Department of Commerce or
10471867Smsmith * any other agency or department of the United States Government.  In the
10571867Smsmith * event Licensee exports any such software from the United States or
10671867Smsmith * re-exports any such software from a foreign destination, Licensee shall
10771867Smsmith * ensure that the distribution and export/re-export of the software is in
10871867Smsmith * compliance with all laws, regulations, orders, or other restrictions of the
10971867Smsmith * U.S. Export Administration Regulations. Licensee agrees that neither it nor
11071867Smsmith * any of its subsidiaries will export/re-export any technical data, process,
11171867Smsmith * software, or service, directly or indirectly, to any country for which the
11271867Smsmith * United States government or any agency thereof requires an export license,
11371867Smsmith * other governmental approval, or letter of assurance, without first obtaining
11471867Smsmith * such license, approval or letter.
11571867Smsmith *
11671867Smsmith *****************************************************************************/
11771867Smsmith
118151600Sobrien#include <contrib/dev/acpica/acpi.h>
119167802Sjkim#include <contrib/dev/acpica/actables.h>
12071867Smsmith
12177424Smsmith#define _COMPONENT          ACPI_HARDWARE
12291116Smsmith        ACPI_MODULE_NAME    ("hwsleep")
12371867Smsmith
12471867Smsmith
125151937Sjkim/*******************************************************************************
12671867Smsmith *
12771867Smsmith * FUNCTION:    AcpiSetFirmwareWakingVector
12871867Smsmith *
12971867Smsmith * PARAMETERS:  PhysicalAddress     - Physical address of ACPI real mode
13071867Smsmith *                                    entry point.
13171867Smsmith *
13291116Smsmith * RETURN:      Status
13371867Smsmith *
134151937Sjkim * DESCRIPTION: Access function for the FirmwareWakingVector field in FACS
13571867Smsmith *
13671867Smsmith ******************************************************************************/
13771867Smsmith
13871867SmsmithACPI_STATUS
13971867SmsmithAcpiSetFirmwareWakingVector (
140167802Sjkim    ACPI_PHYSICAL_ADDRESS   PhysicalAddress)
14171867Smsmith{
142167802Sjkim    ACPI_TABLE_FACS         *Facs;
143167802Sjkim    ACPI_STATUS             Status;
14471867Smsmith
14571867Smsmith
146167802Sjkim    ACPI_FUNCTION_TRACE (AcpiSetFirmwareWakingVector);
14771867Smsmith
148167802Sjkim    /* Get the FACS */
149167802Sjkim
150167802Sjkim    Status = AcpiGetTableByIndex (ACPI_TABLE_INDEX_FACS, (ACPI_TABLE_HEADER **) &Facs);
151167802Sjkim    if (ACPI_FAILURE (Status))
152167802Sjkim    {
153167802Sjkim        return_ACPI_STATUS (Status);
154167802Sjkim    }
155167802Sjkim
15671867Smsmith    /* Set the vector */
15771867Smsmith
158167802Sjkim    if ((Facs->Length < 32) ||
159167802Sjkim        (!(Facs->XFirmwareWakingVector)))
16071867Smsmith    {
161167802Sjkim        /*
162167802Sjkim         * ACPI 1.0 FACS or short table or optional X_ field is zero
163167802Sjkim         */
164167802Sjkim        Facs->FirmwareWakingVector = (UINT32) PhysicalAddress;
16571867Smsmith    }
16671867Smsmith    else
16771867Smsmith    {
168167802Sjkim        /*
169167802Sjkim         * ACPI 2.0 FACS with valid X_ field
170167802Sjkim         */
171167802Sjkim        Facs->XFirmwareWakingVector = PhysicalAddress;
17271867Smsmith    }
17371867Smsmith
17471867Smsmith    return_ACPI_STATUS (AE_OK);
17571867Smsmith}
17671867Smsmith
177167802SjkimACPI_EXPORT_SYMBOL (AcpiSetFirmwareWakingVector)
17871867Smsmith
179167802Sjkim
180151937Sjkim/*******************************************************************************
18171867Smsmith *
18271867Smsmith * FUNCTION:    AcpiGetFirmwareWakingVector
18371867Smsmith *
184151937Sjkim * PARAMETERS:  *PhysicalAddress    - Where the contents of
18571867Smsmith *                                    the FirmwareWakingVector field of
186151937Sjkim *                                    the FACS will be returned.
18771867Smsmith *
188151937Sjkim * RETURN:      Status, vector
18971867Smsmith *
190151937Sjkim * DESCRIPTION: Access function for the FirmwareWakingVector field in FACS
19171867Smsmith *
19271867Smsmith ******************************************************************************/
19371867Smsmith
19471867SmsmithACPI_STATUS
19571867SmsmithAcpiGetFirmwareWakingVector (
196167802Sjkim    ACPI_PHYSICAL_ADDRESS   *PhysicalAddress)
19771867Smsmith{
198167802Sjkim    ACPI_TABLE_FACS         *Facs;
199167802Sjkim    ACPI_STATUS             Status;
20071867Smsmith
20171867Smsmith
202167802Sjkim    ACPI_FUNCTION_TRACE (AcpiGetFirmwareWakingVector);
20371867Smsmith
204167802Sjkim
20571867Smsmith    if (!PhysicalAddress)
20671867Smsmith    {
20771867Smsmith        return_ACPI_STATUS (AE_BAD_PARAMETER);
20871867Smsmith    }
20971867Smsmith
210167802Sjkim    /* Get the FACS */
211167802Sjkim
212167802Sjkim    Status = AcpiGetTableByIndex (ACPI_TABLE_INDEX_FACS, (ACPI_TABLE_HEADER **) &Facs);
213167802Sjkim    if (ACPI_FAILURE (Status))
214167802Sjkim    {
215167802Sjkim        return_ACPI_STATUS (Status);
216167802Sjkim    }
217167802Sjkim
21871867Smsmith    /* Get the vector */
21971867Smsmith
220167802Sjkim    if ((Facs->Length < 32) ||
221167802Sjkim        (!(Facs->XFirmwareWakingVector)))
22271867Smsmith    {
223167802Sjkim        /*
224167802Sjkim         * ACPI 1.0 FACS or short table or optional X_ field is zero
225167802Sjkim         */
226167802Sjkim        *PhysicalAddress =
227167802Sjkim            (ACPI_PHYSICAL_ADDRESS) Facs->FirmwareWakingVector;
22871867Smsmith    }
22971867Smsmith    else
23071867Smsmith    {
231167802Sjkim        /*
232167802Sjkim         * ACPI 2.0 FACS with valid X_ field
233167802Sjkim         */
234167802Sjkim        *PhysicalAddress = (ACPI_PHYSICAL_ADDRESS) Facs->XFirmwareWakingVector;
23571867Smsmith    }
23671867Smsmith
23771867Smsmith    return_ACPI_STATUS (AE_OK);
23871867Smsmith}
23971867Smsmith
240167802SjkimACPI_EXPORT_SYMBOL (AcpiGetFirmwareWakingVector)
24187031Smsmith
242167802Sjkim
243151937Sjkim/*******************************************************************************
24471867Smsmith *
24587031Smsmith * FUNCTION:    AcpiEnterSleepStatePrep
24671867Smsmith *
24771867Smsmith * PARAMETERS:  SleepState          - Which sleep state to enter
24871867Smsmith *
24971867Smsmith * RETURN:      Status
25071867Smsmith *
25187031Smsmith * DESCRIPTION: Prepare to enter a system sleep state (see ACPI 2.0 spec p 231)
25287031Smsmith *              This function must execute with interrupts enabled.
25387031Smsmith *              We break sleeping into 2 stages so that OSPM can handle
25487031Smsmith *              various OS-specific tasks between the two steps.
25571867Smsmith *
25671867Smsmith ******************************************************************************/
25771867Smsmith
25871867SmsmithACPI_STATUS
25987031SmsmithAcpiEnterSleepStatePrep (
26077424Smsmith    UINT8               SleepState)
26171867Smsmith{
26277424Smsmith    ACPI_STATUS         Status;
26377424Smsmith    ACPI_OBJECT_LIST    ArgList;
26477424Smsmith    ACPI_OBJECT         Arg;
26571867Smsmith
26677424Smsmith
267167802Sjkim    ACPI_FUNCTION_TRACE (AcpiEnterSleepStatePrep);
26891116Smsmith
26991116Smsmith
27071867Smsmith    /*
27171867Smsmith     * _PSW methods could be run here to enable wake-on keyboard, LAN, etc.
27271867Smsmith     */
27399679Siwasaki    Status = AcpiGetSleepTypeData (SleepState,
27491116Smsmith                    &AcpiGbl_SleepTypeA, &AcpiGbl_SleepTypeB);
27591116Smsmith    if (ACPI_FAILURE (Status))
27671867Smsmith    {
27787031Smsmith        return_ACPI_STATUS (Status);
27871867Smsmith    }
27971867Smsmith
28091116Smsmith    /* Setup parameter object */
28177424Smsmith
28271867Smsmith    ArgList.Count = 1;
28371867Smsmith    ArgList.Pointer = &Arg;
28471867Smsmith
28571867Smsmith    Arg.Type = ACPI_TYPE_INTEGER;
28671867Smsmith    Arg.Integer.Value = SleepState;
28771867Smsmith
28891116Smsmith    /* Run the _PTS and _GTS methods */
28977424Smsmith
290126372Snjl    Status = AcpiEvaluateObject (NULL, METHOD_NAME__PTS, &ArgList, NULL);
29191116Smsmith    if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND)
29291116Smsmith    {
29391116Smsmith        return_ACPI_STATUS (Status);
29491116Smsmith    }
29591116Smsmith
296126372Snjl    Status = AcpiEvaluateObject (NULL, METHOD_NAME__GTS, &ArgList, NULL);
29791116Smsmith    if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND)
29891116Smsmith    {
29991116Smsmith        return_ACPI_STATUS (Status);
30091116Smsmith    }
30191116Smsmith
302126372Snjl    /* Setup the argument to _SST */
303126372Snjl
304126372Snjl    switch (SleepState)
305126372Snjl    {
306126372Snjl    case ACPI_STATE_S0:
307126372Snjl        Arg.Integer.Value = ACPI_SST_WORKING;
308126372Snjl        break;
309126372Snjl
310126372Snjl    case ACPI_STATE_S1:
311126372Snjl    case ACPI_STATE_S2:
312126372Snjl    case ACPI_STATE_S3:
313126372Snjl        Arg.Integer.Value = ACPI_SST_SLEEPING;
314126372Snjl        break;
315126372Snjl
316126372Snjl    case ACPI_STATE_S4:
317126372Snjl        Arg.Integer.Value = ACPI_SST_SLEEP_CONTEXT;
318126372Snjl        break;
319126372Snjl
320126372Snjl    default:
321151937Sjkim        Arg.Integer.Value = ACPI_SST_INDICATOR_OFF; /* Default is off */
322126372Snjl        break;
323126372Snjl    }
324126372Snjl
325123315Snjl    /* Set the system indicators to show the desired sleep state. */
326123315Snjl
327126372Snjl    Status = AcpiEvaluateObject (NULL, METHOD_NAME__SST, &ArgList, NULL);
328123315Snjl    if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND)
329123315Snjl    {
330167802Sjkim        ACPI_EXCEPTION ((AE_INFO, Status, "While executing method _SST"));
331123315Snjl    }
332123315Snjl
33387031Smsmith    return_ACPI_STATUS (AE_OK);
33487031Smsmith}
33587031Smsmith
336167802SjkimACPI_EXPORT_SYMBOL (AcpiEnterSleepStatePrep)
33787031Smsmith
338167802Sjkim
339151937Sjkim/*******************************************************************************
34087031Smsmith *
34187031Smsmith * FUNCTION:    AcpiEnterSleepState
34287031Smsmith *
34387031Smsmith * PARAMETERS:  SleepState          - Which sleep state to enter
34487031Smsmith *
34587031Smsmith * RETURN:      Status
34687031Smsmith *
34787031Smsmith * DESCRIPTION: Enter a system sleep state (see ACPI 2.0 spec p 231)
34887031Smsmith *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
34987031Smsmith *
35087031Smsmith ******************************************************************************/
35187031Smsmith
35287031SmsmithACPI_STATUS
35387031SmsmithAcpiEnterSleepState (
35491116Smsmith    UINT8                   SleepState)
35587031Smsmith{
35699679Siwasaki    UINT32                  PM1AControl;
35799679Siwasaki    UINT32                  PM1BControl;
35891116Smsmith    ACPI_BIT_REGISTER_INFO  *SleepTypeRegInfo;
35991116Smsmith    ACPI_BIT_REGISTER_INFO  *SleepEnableRegInfo;
36099679Siwasaki    UINT32                  InValue;
36199679Siwasaki    ACPI_STATUS             Status;
36287031Smsmith
36387031Smsmith
364167802Sjkim    ACPI_FUNCTION_TRACE (AcpiEnterSleepState);
36587031Smsmith
36691116Smsmith
36791116Smsmith    if ((AcpiGbl_SleepTypeA > ACPI_SLEEP_TYPE_MAX) ||
36891116Smsmith        (AcpiGbl_SleepTypeB > ACPI_SLEEP_TYPE_MAX))
36987031Smsmith    {
370167802Sjkim        ACPI_ERROR ((AE_INFO, "Sleep values out of range: A=%X B=%X",
37191116Smsmith            AcpiGbl_SleepTypeA, AcpiGbl_SleepTypeB));
37291116Smsmith        return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
37387031Smsmith    }
37487031Smsmith
37591116Smsmith    SleepTypeRegInfo   = AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_TYPE_A);
37691116Smsmith    SleepEnableRegInfo = AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_ENABLE);
37771867Smsmith
378128245Snjl    /* Clear wake status */
379128245Snjl
380167802Sjkim    Status = AcpiSetRegister (ACPI_BITREG_WAKE_STATUS, 1);
381128245Snjl    if (ACPI_FAILURE (Status))
38299679Siwasaki    {
383128245Snjl        return_ACPI_STATUS (Status);
384128245Snjl    }
38578986Smsmith
386129684Snjl    /* Clear all fixed and general purpose status bits */
387129684Snjl
388167802Sjkim    Status = AcpiHwClearAcpiStatus ();
389128245Snjl    if (ACPI_FAILURE (Status))
390128245Snjl    {
391128245Snjl        return_ACPI_STATUS (Status);
392128245Snjl    }
39387031Smsmith
394128245Snjl    if (SleepState != ACPI_STATE_S5)
395128245Snjl    {
396123315Snjl        /* Disable BM arbitration */
397123315Snjl
398167802Sjkim        Status = AcpiSetRegister (ACPI_BITREG_ARB_DISABLE, 1);
399123315Snjl        if (ACPI_FAILURE (Status))
400123315Snjl        {
401123315Snjl            return_ACPI_STATUS (Status);
402123315Snjl        }
40399679Siwasaki    }
40499679Siwasaki
405128212Snjl    /*
406129684Snjl     * 1) Disable/Clear all GPEs
407128212Snjl     * 2) Enable all wakeup GPEs
408128212Snjl     */
409151937Sjkim    Status = AcpiHwDisableAllGpes ();
41099679Siwasaki    if (ACPI_FAILURE (Status))
41199679Siwasaki    {
41299679Siwasaki        return_ACPI_STATUS (Status);
41399679Siwasaki    }
414129684Snjl    AcpiGbl_SystemAwakeAndRunning = FALSE;
41599679Siwasaki
416151937Sjkim    Status = AcpiHwEnableAllWakeupGpes ();
417129684Snjl    if (ACPI_FAILURE (Status))
418129684Snjl    {
419129684Snjl        return_ACPI_STATUS (Status);
420129684Snjl    }
421129684Snjl
42291116Smsmith    /* Get current value of PM1A control */
42378986Smsmith
424151937Sjkim    Status = AcpiHwRegisterRead (ACPI_MTX_DO_NOT_LOCK,
425151937Sjkim                ACPI_REGISTER_PM1_CONTROL, &PM1AControl);
42699679Siwasaki    if (ACPI_FAILURE (Status))
42799679Siwasaki    {
42899679Siwasaki        return_ACPI_STATUS (Status);
42999679Siwasaki    }
430151937Sjkim    ACPI_DEBUG_PRINT ((ACPI_DB_INIT,
431151937Sjkim        "Entering sleep state [S%d]\n", SleepState));
43282367Smsmith
43391116Smsmith    /* Clear SLP_EN and SLP_TYP fields */
43482367Smsmith
435151937Sjkim    PM1AControl &= ~(SleepTypeRegInfo->AccessBitMask |
436151937Sjkim                     SleepEnableRegInfo->AccessBitMask);
43771867Smsmith    PM1BControl = PM1AControl;
43871867Smsmith
43991116Smsmith    /* Insert SLP_TYP bits */
44082367Smsmith
44191116Smsmith    PM1AControl |= (AcpiGbl_SleepTypeA << SleepTypeRegInfo->BitPosition);
44291116Smsmith    PM1BControl |= (AcpiGbl_SleepTypeB << SleepTypeRegInfo->BitPosition);
44371867Smsmith
444126372Snjl    /*
445126372Snjl     * We split the writes of SLP_TYP and SLP_EN to workaround
446126372Snjl     * poorly implemented hardware.
447126372Snjl     */
448126372Snjl
44991116Smsmith    /* Write #1: fill in SLP_TYP data */
45071867Smsmith
451151937Sjkim    Status = AcpiHwRegisterWrite (ACPI_MTX_DO_NOT_LOCK,
452151937Sjkim                ACPI_REGISTER_PM1A_CONTROL, PM1AControl);
45399679Siwasaki    if (ACPI_FAILURE (Status))
45499679Siwasaki    {
45599679Siwasaki        return_ACPI_STATUS (Status);
45699679Siwasaki    }
45782367Smsmith
458151937Sjkim    Status = AcpiHwRegisterWrite (ACPI_MTX_DO_NOT_LOCK,
459151937Sjkim                ACPI_REGISTER_PM1B_CONTROL, PM1BControl);
46099679Siwasaki    if (ACPI_FAILURE (Status))
46199679Siwasaki    {
46299679Siwasaki        return_ACPI_STATUS (Status);
46399679Siwasaki    }
46499679Siwasaki
46591116Smsmith    /* Insert SLP_ENABLE bit */
46682367Smsmith
46791116Smsmith    PM1AControl |= SleepEnableRegInfo->AccessBitMask;
46891116Smsmith    PM1BControl |= SleepEnableRegInfo->AccessBitMask;
46971867Smsmith
47091116Smsmith    /* Write #2: SLP_TYP + SLP_EN */
47171867Smsmith
47299679Siwasaki    ACPI_FLUSH_CPU_CACHE ();
47380062Smsmith
474151937Sjkim    Status = AcpiHwRegisterWrite (ACPI_MTX_DO_NOT_LOCK,
475151937Sjkim                ACPI_REGISTER_PM1A_CONTROL, PM1AControl);
47699679Siwasaki    if (ACPI_FAILURE (Status))
47799679Siwasaki    {
47899679Siwasaki        return_ACPI_STATUS (Status);
47999679Siwasaki    }
48099679Siwasaki
481151937Sjkim    Status = AcpiHwRegisterWrite (ACPI_MTX_DO_NOT_LOCK,
482151937Sjkim                ACPI_REGISTER_PM1B_CONTROL, PM1BControl);
48399679Siwasaki    if (ACPI_FAILURE (Status))
48499679Siwasaki    {
48599679Siwasaki        return_ACPI_STATUS (Status);
48699679Siwasaki    }
48799679Siwasaki
48882367Smsmith    if (SleepState > ACPI_STATE_S3)
48982367Smsmith    {
49099679Siwasaki        /*
491151937Sjkim         * We wanted to sleep > S3, but it didn't happen (by virtue of the
492151937Sjkim         * fact that we are still executing!)
493123315Snjl         *
494151937Sjkim         * Wait ten seconds, then try again. This is to get S4/S5 to work on
495151937Sjkim         * all machines.
496123315Snjl         *
49799679Siwasaki         * We wait so long to allow chipsets that poll this reg very slowly to
498126372Snjl         * still read the right value. Ideally, this block would go
49999679Siwasaki         * away entirely.
50099679Siwasaki         */
50199679Siwasaki        AcpiOsStall (10000000);
50282367Smsmith
503151937Sjkim        Status = AcpiHwRegisterWrite (ACPI_MTX_DO_NOT_LOCK,
504151937Sjkim                    ACPI_REGISTER_PM1_CONTROL,
50599679Siwasaki                    SleepEnableRegInfo->AccessBitMask);
50699679Siwasaki        if (ACPI_FAILURE (Status))
50799679Siwasaki        {
50899679Siwasaki            return_ACPI_STATUS (Status);
50999679Siwasaki        }
51080357Speter    }
51180062Smsmith
51291116Smsmith    /* Wait until we enter sleep state */
51371867Smsmith
514102550Siwasaki    do
51583174Smsmith    {
516167802Sjkim        Status = AcpiGetRegister (ACPI_BITREG_WAKE_STATUS, &InValue);
51799679Siwasaki        if (ACPI_FAILURE (Status))
51899679Siwasaki        {
51999679Siwasaki            return_ACPI_STATUS (Status);
52099679Siwasaki        }
52199679Siwasaki
52291116Smsmith        /* Spin until we wake */
52382367Smsmith
52499679Siwasaki    } while (!InValue);
52599679Siwasaki
52671867Smsmith    return_ACPI_STATUS (AE_OK);
52771867Smsmith}
52882367Smsmith
529167802SjkimACPI_EXPORT_SYMBOL (AcpiEnterSleepState)
530114237Snjl
531167802Sjkim
532151937Sjkim/*******************************************************************************
53382367Smsmith *
534114237Snjl * FUNCTION:    AcpiEnterSleepStateS4bios
535114237Snjl *
536114237Snjl * PARAMETERS:  None
537114237Snjl *
538114237Snjl * RETURN:      Status
539114237Snjl *
540114237Snjl * DESCRIPTION: Perform a S4 bios request.
541114237Snjl *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
542114237Snjl *
543114237Snjl ******************************************************************************/
544114237Snjl
545114237SnjlACPI_STATUS
546114237SnjlAcpiEnterSleepStateS4bios (
547114237Snjl    void)
548114237Snjl{
549114237Snjl    UINT32                  InValue;
550114237Snjl    ACPI_STATUS             Status;
551114237Snjl
552114237Snjl
553167802Sjkim    ACPI_FUNCTION_TRACE (AcpiEnterSleepStateS4bios);
554114237Snjl
555123315Snjl
556167802Sjkim    Status = AcpiSetRegister (ACPI_BITREG_WAKE_STATUS, 1);
557126372Snjl    if (ACPI_FAILURE (Status))
558126372Snjl    {
559126372Snjl        return_ACPI_STATUS (Status);
560126372Snjl    }
561114237Snjl
562167802Sjkim    Status = AcpiHwClearAcpiStatus ();
563126372Snjl    if (ACPI_FAILURE (Status))
564126372Snjl    {
565126372Snjl        return_ACPI_STATUS (Status);
566126372Snjl    }
567114237Snjl
568128212Snjl    /*
569129684Snjl     * 1) Disable/Clear all GPEs
570128212Snjl     * 2) Enable all wakeup GPEs
571128212Snjl     */
572151937Sjkim    Status = AcpiHwDisableAllGpes ();
573126372Snjl    if (ACPI_FAILURE (Status))
574126372Snjl    {
575126372Snjl        return_ACPI_STATUS (Status);
576126372Snjl    }
577129684Snjl    AcpiGbl_SystemAwakeAndRunning = FALSE;
578114237Snjl
579151937Sjkim    Status = AcpiHwEnableAllWakeupGpes ();
580129684Snjl    if (ACPI_FAILURE (Status))
581129684Snjl    {
582129684Snjl        return_ACPI_STATUS (Status);
583129684Snjl    }
584129684Snjl
585126372Snjl    ACPI_FLUSH_CPU_CACHE ();
586126372Snjl
587167802Sjkim    Status = AcpiOsWritePort (AcpiGbl_FADT.SmiCommand,
588167802Sjkim                (UINT32) AcpiGbl_FADT.S4BiosRequest, 8);
589114237Snjl
590114237Snjl    do {
591114237Snjl        AcpiOsStall(1000);
592167802Sjkim        Status = AcpiGetRegister (ACPI_BITREG_WAKE_STATUS, &InValue);
593114237Snjl        if (ACPI_FAILURE (Status))
594114237Snjl        {
595114237Snjl            return_ACPI_STATUS (Status);
596114237Snjl        }
597114237Snjl    } while (!InValue);
598114237Snjl
599114237Snjl    return_ACPI_STATUS (AE_OK);
600114237Snjl}
601114237Snjl
602167802SjkimACPI_EXPORT_SYMBOL (AcpiEnterSleepStateS4bios)
603114237Snjl
604167802Sjkim
605151937Sjkim/*******************************************************************************
606114237Snjl *
60782367Smsmith * FUNCTION:    AcpiLeaveSleepState
60882367Smsmith *
60982367Smsmith * PARAMETERS:  SleepState          - Which sleep state we just exited
61082367Smsmith *
61182367Smsmith * RETURN:      Status
61282367Smsmith *
61382367Smsmith * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep
614138287Smarks *              Called with interrupts ENABLED.
61582367Smsmith *
61682367Smsmith ******************************************************************************/
61782367Smsmith
61882367SmsmithACPI_STATUS
61982367SmsmithAcpiLeaveSleepState (
620123315Snjl    UINT8                   SleepState)
62182367Smsmith{
622123315Snjl    ACPI_OBJECT_LIST        ArgList;
623123315Snjl    ACPI_OBJECT             Arg;
624123315Snjl    ACPI_STATUS             Status;
625123315Snjl    ACPI_BIT_REGISTER_INFO  *SleepTypeRegInfo;
626123315Snjl    ACPI_BIT_REGISTER_INFO  *SleepEnableRegInfo;
627126372Snjl    UINT32                  PM1AControl;
628126372Snjl    UINT32                  PM1BControl;
62982367Smsmith
63083174Smsmith
631167802Sjkim    ACPI_FUNCTION_TRACE (AcpiLeaveSleepState);
63282367Smsmith
63391116Smsmith
634126372Snjl    /*
635126372Snjl     * Set SLP_TYPE and SLP_EN to state S0.
636126372Snjl     * This is unclear from the ACPI Spec, but it is required
637126372Snjl     * by some machines.
638126372Snjl     */
639126372Snjl    Status = AcpiGetSleepTypeData (ACPI_STATE_S0,
640126372Snjl                    &AcpiGbl_SleepTypeA, &AcpiGbl_SleepTypeB);
641123315Snjl    if (ACPI_SUCCESS (Status))
642123315Snjl    {
643126372Snjl        SleepTypeRegInfo   = AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_TYPE_A);
644126372Snjl        SleepEnableRegInfo = AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_ENABLE);
645123315Snjl
646126372Snjl        /* Get current value of PM1A control */
647123315Snjl
648126372Snjl        Status = AcpiHwRegisterRead (ACPI_MTX_DO_NOT_LOCK,
649126372Snjl                    ACPI_REGISTER_PM1_CONTROL, &PM1AControl);
650126372Snjl        if (ACPI_SUCCESS (Status))
651126372Snjl        {
652126372Snjl            /* Clear SLP_EN and SLP_TYP fields */
653126372Snjl
654126372Snjl            PM1AControl &= ~(SleepTypeRegInfo->AccessBitMask |
655126372Snjl                             SleepEnableRegInfo->AccessBitMask);
656126372Snjl            PM1BControl = PM1AControl;
657126372Snjl
658126372Snjl            /* Insert SLP_TYP bits */
659126372Snjl
660126372Snjl            PM1AControl |= (AcpiGbl_SleepTypeA << SleepTypeRegInfo->BitPosition);
661126372Snjl            PM1BControl |= (AcpiGbl_SleepTypeB << SleepTypeRegInfo->BitPosition);
662126372Snjl
663126372Snjl            /* Just ignore any errors */
664126372Snjl
665126372Snjl            (void) AcpiHwRegisterWrite (ACPI_MTX_DO_NOT_LOCK,
666126372Snjl                            ACPI_REGISTER_PM1A_CONTROL, PM1AControl);
667126372Snjl            (void) AcpiHwRegisterWrite (ACPI_MTX_DO_NOT_LOCK,
668126372Snjl                            ACPI_REGISTER_PM1B_CONTROL, PM1BControl);
669126372Snjl        }
670123315Snjl    }
671123315Snjl
67287031Smsmith    /* Ensure EnterSleepStatePrep -> EnterSleepState ordering */
67382367Smsmith
67491116Smsmith    AcpiGbl_SleepTypeA = ACPI_SLEEP_TYPE_INVALID;
67591116Smsmith
67691116Smsmith    /* Setup parameter object */
67791116Smsmith
67882367Smsmith    ArgList.Count = 1;
67982367Smsmith    ArgList.Pointer = &Arg;
68082367Smsmith    Arg.Type = ACPI_TYPE_INTEGER;
68182367Smsmith
68291116Smsmith    /* Ignore any errors from these methods */
68383174Smsmith
684126372Snjl    Arg.Integer.Value = ACPI_SST_WAKING;
685126372Snjl    Status = AcpiEvaluateObject (NULL, METHOD_NAME__SST, &ArgList, NULL);
686123315Snjl    if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND)
687123315Snjl    {
688167802Sjkim        ACPI_EXCEPTION ((AE_INFO, Status, "During Method _SST"));
689123315Snjl    }
690123315Snjl
691123315Snjl    Arg.Integer.Value = SleepState;
692126372Snjl    Status = AcpiEvaluateObject (NULL, METHOD_NAME__BFS, &ArgList, NULL);
69391116Smsmith    if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND)
69491116Smsmith    {
695167802Sjkim        ACPI_EXCEPTION ((AE_INFO, Status, "During Method _BFS"));
69691116Smsmith    }
69791116Smsmith
698126372Snjl    Status = AcpiEvaluateObject (NULL, METHOD_NAME__WAK, &ArgList, NULL);
69991116Smsmith    if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND)
70091116Smsmith    {
701167802Sjkim        ACPI_EXCEPTION ((AE_INFO, Status, "During Method _WAK"));
70291116Smsmith    }
703128212Snjl    /* TBD: _WAK "sometimes" returns stuff - do we want to look at it? */
70491116Smsmith
705128212Snjl    /*
706128212Snjl     * Restore the GPEs:
707129684Snjl     * 1) Disable/Clear all GPEs
708128212Snjl     * 2) Enable all runtime GPEs
709128212Snjl     */
710151937Sjkim    Status = AcpiHwDisableAllGpes ();
71199679Siwasaki    if (ACPI_FAILURE (Status))
71299679Siwasaki    {
71399679Siwasaki        return_ACPI_STATUS (Status);
71499679Siwasaki    }
715129684Snjl    AcpiGbl_SystemAwakeAndRunning = TRUE;
71682367Smsmith
717151937Sjkim    Status = AcpiHwEnableAllRuntimeGpes ();
718129684Snjl    if (ACPI_FAILURE (Status))
719129684Snjl    {
720129684Snjl        return_ACPI_STATUS (Status);
721129684Snjl    }
722129684Snjl
723126372Snjl    /* Enable power button */
724126372Snjl
725151937Sjkim    (void) AcpiSetRegister(
726167802Sjkim            AcpiGbl_FixedEventInfo[ACPI_EVENT_POWER_BUTTON].EnableRegisterId, 1);
727151937Sjkim
728151937Sjkim    (void) AcpiSetRegister(
729167802Sjkim            AcpiGbl_FixedEventInfo[ACPI_EVENT_POWER_BUTTON].StatusRegisterId, 1);
730126372Snjl
731123315Snjl    /* Enable BM arbitration */
732123315Snjl
733167802Sjkim    Status = AcpiSetRegister (ACPI_BITREG_ARB_DISABLE, 0);
734126372Snjl    if (ACPI_FAILURE (Status))
735126372Snjl    {
736126372Snjl        return_ACPI_STATUS (Status);
737126372Snjl    }
738126372Snjl
739126372Snjl    Arg.Integer.Value = ACPI_SST_WORKING;
740126372Snjl    Status = AcpiEvaluateObject (NULL, METHOD_NAME__SST, &ArgList, NULL);
741126372Snjl    if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND)
742126372Snjl    {
743167802Sjkim        ACPI_EXCEPTION ((AE_INFO, Status, "During Method _SST"));
744126372Snjl    }
745126372Snjl
74699679Siwasaki    return_ACPI_STATUS (Status);
74782367Smsmith}
748167802Sjkim
749167802SjkimACPI_EXPORT_SYMBOL (AcpiLeaveSleepState)
750167802Sjkim
751