1228753Smm/******************************************************************************
2228753Smm *
3228753Smm * Name: hwxfsleep.c - ACPI Hardware Sleep/Wake External Interfaces
4228753Smm *
5228753Smm *****************************************************************************/
6228753Smm
7228753Smm/*
8228753Smm * Copyright (C) 2000 - 2016, Intel Corp.
9228753Smm * All rights reserved.
10228753Smm *
11228753Smm * Redistribution and use in source and binary forms, with or without
12228753Smm * modification, are permitted provided that the following conditions
13228753Smm * are met:
14228753Smm * 1. Redistributions of source code must retain the above copyright
15228753Smm *    notice, this list of conditions, and the following disclaimer,
16228753Smm *    without modification.
17228753Smm * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18228753Smm *    substantially similar to the "NO WARRANTY" disclaimer below
19228753Smm *    ("Disclaimer") and any redistribution must be conditioned upon
20228753Smm *    including a substantially similar Disclaimer requirement for further
21228753Smm *    binary redistribution.
22228753Smm * 3. Neither the names of the above-listed copyright holders nor the names
23228753Smm *    of any contributors may be used to endorse or promote products derived
24228753Smm *    from this software without specific prior written permission.
25228763Smm *
26228753Smm * Alternatively, this software may be distributed under the terms of the
27238856Smm * GNU General Public License ("GPL") version 2 as published by the Free
28238856Smm * Software Foundation.
29228753Smm *
30228753Smm * NO WARRANTY
31228753Smm * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32228753Smm * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33228753Smm * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34228753Smm * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35228753Smm * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36228753Smm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37228753Smm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38228753Smm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39228753Smm * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40228753Smm * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41228753Smm * POSSIBILITY OF SUCH DAMAGES.
42228753Smm */
43228753Smm
44232153Smm#define EXPORT_ACPI_INTERFACES
45228753Smm
46228753Smm#include <contrib/dev/acpica/include/acpi.h>
47232153Smm#include <contrib/dev/acpica/include/accommon.h>
48228753Smm
49228753Smm#define _COMPONENT          ACPI_HARDWARE
50228753Smm        ACPI_MODULE_NAME    ("hwxfsleep")
51228753Smm
52232153Smm/* Local prototypes */
53228753Smm
54228753Smm#if (!ACPI_REDUCED_HARDWARE)
55228753Smmstatic ACPI_STATUS
56228753SmmAcpiHwSetFirmwareWakingVector (
57228753Smm    ACPI_TABLE_FACS         *Facs,
58228753Smm    ACPI_PHYSICAL_ADDRESS   PhysicalAddress,
59228753Smm    ACPI_PHYSICAL_ADDRESS   PhysicalAddress64);
60228753Smm#endif
61228753Smm
62228753Smmstatic ACPI_STATUS
63228753SmmAcpiHwSleepDispatch (
64228753Smm    UINT8                   SleepState,
65228753Smm    UINT32                  FunctionId);
66228753Smm
67228753Smm/*
68228753Smm * Dispatch table used to efficiently branch to the various sleep
69228753Smm * functions.
70228753Smm */
71228753Smm#define ACPI_SLEEP_FUNCTION_ID          0
72228753Smm#define ACPI_WAKE_PREP_FUNCTION_ID      1
73228753Smm#define ACPI_WAKE_FUNCTION_ID           2
74228753Smm
75228753Smm/* Legacy functions are optional, based upon ACPI_REDUCED_HARDWARE */
76228753Smm
77228753Smmstatic ACPI_SLEEP_FUNCTIONS         AcpiSleepDispatch[] =
78228753Smm{
79228753Smm    {ACPI_HW_OPTIONAL_FUNCTION (AcpiHwLegacySleep),    AcpiHwExtendedSleep},
80228753Smm    {ACPI_HW_OPTIONAL_FUNCTION (AcpiHwLegacyWakePrep), AcpiHwExtendedWakePrep},
81228753Smm    {ACPI_HW_OPTIONAL_FUNCTION (AcpiHwLegacyWake),     AcpiHwExtendedWake}
82228753Smm};
83228753Smm
84228753Smm
85228753Smm/*
86228753Smm * These functions are removed for the ACPI_REDUCED_HARDWARE case:
87228753Smm *      AcpiSetFirmwareWakingVector
88228753Smm *      AcpiEnterSleepStateS4bios
89228753Smm */
90228753Smm
91228753Smm#if (!ACPI_REDUCED_HARDWARE)
92228753Smm/*******************************************************************************
93228753Smm *
94228753Smm * FUNCTION:    AcpiHwSetFirmwareWakingVector
95228753Smm *
96228753Smm * PARAMETERS:  Facs                - Pointer to FACS table
97228753Smm *              PhysicalAddress     - 32-bit physical address of ACPI real mode
98228753Smm *                                    entry point
99228753Smm *              PhysicalAddress64   - 64-bit physical address of ACPI protected
100228753Smm *                                    mode entry point
101228753Smm *
102228753Smm * RETURN:      Status
103228753Smm *
104228753Smm * DESCRIPTION: Sets the FirmwareWakingVector fields of the FACS
105228753Smm *
106228753Smm ******************************************************************************/
107228753Smm
108228753Smmstatic ACPI_STATUS
109228753SmmAcpiHwSetFirmwareWakingVector (
110228753Smm    ACPI_TABLE_FACS         *Facs,
111228753Smm    ACPI_PHYSICAL_ADDRESS   PhysicalAddress,
112228753Smm    ACPI_PHYSICAL_ADDRESS   PhysicalAddress64)
113228753Smm{
114228753Smm    ACPI_FUNCTION_TRACE (AcpiHwSetFirmwareWakingVector);
115228753Smm
116228753Smm
117228753Smm    /*
118228753Smm     * According to the ACPI specification 2.0c and later, the 64-bit
119228753Smm     * waking vector should be cleared and the 32-bit waking vector should
120228753Smm     * be used, unless we want the wake-up code to be called by the BIOS in
121228753Smm     * Protected Mode. Some systems (for example HP dv5-1004nr) are known
122228753Smm     * to fail to resume if the 64-bit vector is used.
123228753Smm     */
124228753Smm
125228753Smm    /* Set the 32-bit vector */
126228753Smm
127228753Smm    Facs->FirmwareWakingVector = (UINT32) PhysicalAddress;
128228753Smm
129228753Smm    if (Facs->Length > 32)
130228753Smm    {
131228753Smm        if (Facs->Version >= 1)
132228753Smm        {
133228753Smm            /* Set the 64-bit vector */
134228753Smm
135228753Smm            Facs->XFirmwareWakingVector = PhysicalAddress64;
136228753Smm        }
137228753Smm        else
138228753Smm        {
139228753Smm            /* Clear the 64-bit vector if it exists */
140228753Smm
141228753Smm            Facs->XFirmwareWakingVector = 0;
142228753Smm        }
143228753Smm    }
144228753Smm
145228753Smm    return_ACPI_STATUS (AE_OK);
146228753Smm}
147228753Smm
148228753Smm
149228753Smm/*******************************************************************************
150228753Smm *
151228753Smm * FUNCTION:    AcpiSetFirmwareWakingVector
152228753Smm *
153228753Smm * PARAMETERS:  PhysicalAddress     - 32-bit physical address of ACPI real mode
154228753Smm *                                    entry point
155228753Smm *              PhysicalAddress64   - 64-bit physical address of ACPI protected
156228753Smm *                                    mode entry point
157228753Smm *
158228753Smm * RETURN:      Status
159228753Smm *
160228753Smm * DESCRIPTION: Sets the FirmwareWakingVector fields of the FACS
161228753Smm *
162228753Smm ******************************************************************************/
163228753Smm
164228753SmmACPI_STATUS
165228753SmmAcpiSetFirmwareWakingVector (
166228753Smm    ACPI_PHYSICAL_ADDRESS   PhysicalAddress,
167228753Smm    ACPI_PHYSICAL_ADDRESS   PhysicalAddress64)
168228753Smm{
169228753Smm
170228753Smm    ACPI_FUNCTION_TRACE (AcpiSetFirmwareWakingVector);
171228753Smm
172228753Smm    if (AcpiGbl_FACS)
173228753Smm    {
174228753Smm        (void) AcpiHwSetFirmwareWakingVector (AcpiGbl_FACS,
175228753Smm            PhysicalAddress, PhysicalAddress64);
176228753Smm    }
177228753Smm
178228753Smm    return_ACPI_STATUS (AE_OK);
179228753Smm}
180228753Smm
181228753SmmACPI_EXPORT_SYMBOL (AcpiSetFirmwareWakingVector)
182228753Smm
183228753Smm
184228753Smm/*******************************************************************************
185228753Smm *
186228753Smm * FUNCTION:    AcpiEnterSleepStateS4bios
187228753Smm *
188228753Smm * PARAMETERS:  None
189228753Smm *
190228753Smm * RETURN:      Status
191228753Smm *
192228753Smm * DESCRIPTION: Perform a S4 bios request.
193228753Smm *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
194228753Smm *
195228753Smm ******************************************************************************/
196228753Smm
197228753SmmACPI_STATUS
198228753SmmAcpiEnterSleepStateS4bios (
199228753Smm    void)
200228753Smm{
201228753Smm    UINT32                  InValue;
202228753Smm    ACPI_STATUS             Status;
203228753Smm
204228753Smm
205228753Smm    ACPI_FUNCTION_TRACE (AcpiEnterSleepStateS4bios);
206228753Smm
207228753Smm
208228753Smm    /* Clear the wake status bit (PM1) */
209228753Smm
210228753Smm    Status = AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS);
211228753Smm    if (ACPI_FAILURE (Status))
212228753Smm    {
213228753Smm        return_ACPI_STATUS (Status);
214228753Smm    }
215228753Smm
216228753Smm    Status = AcpiHwClearAcpiStatus ();
217228753Smm    if (ACPI_FAILURE (Status))
218228753Smm    {
219228753Smm        return_ACPI_STATUS (Status);
220228753Smm    }
221228753Smm
222228753Smm    /*
223228753Smm     * 1) Disable/Clear all GPEs
224228753Smm     * 2) Enable all wakeup GPEs
225228753Smm     */
226228753Smm    Status = AcpiHwDisableAllGpes ();
227228753Smm    if (ACPI_FAILURE (Status))
228228753Smm    {
229228753Smm        return_ACPI_STATUS (Status);
230228753Smm    }
231228753Smm    AcpiGbl_SystemAwakeAndRunning = FALSE;
232228753Smm
233228753Smm    Status = AcpiHwEnableAllWakeupGpes ();
234228753Smm    if (ACPI_FAILURE (Status))
235228753Smm    {
236228753Smm        return_ACPI_STATUS (Status);
237228753Smm    }
238228753Smm
239228753Smm    ACPI_FLUSH_CPU_CACHE ();
240228753Smm
241228753Smm    Status = AcpiHwWritePort (AcpiGbl_FADT.SmiCommand,
242228753Smm        (UINT32) AcpiGbl_FADT.S4BiosRequest, 8);
243228753Smm
244228753Smm    do {
245228753Smm        AcpiOsStall (ACPI_USEC_PER_MSEC);
246228753Smm        Status = AcpiReadBitRegister (ACPI_BITREG_WAKE_STATUS, &InValue);
247228753Smm        if (ACPI_FAILURE (Status))
248228753Smm        {
249228753Smm            return_ACPI_STATUS (Status);
250228753Smm        }
251228753Smm
252228753Smm    } while (!InValue);
253228753Smm
254228753Smm    return_ACPI_STATUS (AE_OK);
255228753Smm}
256228753Smm
257228753SmmACPI_EXPORT_SYMBOL (AcpiEnterSleepStateS4bios)
258228753Smm
259228753Smm#endif /* !ACPI_REDUCED_HARDWARE */
260228753Smm
261228753Smm
262228753Smm/*******************************************************************************
263228753Smm *
264228753Smm * FUNCTION:    AcpiHwSleepDispatch
265228753Smm *
266228753Smm * PARAMETERS:  SleepState          - Which sleep state to enter/exit
267228753Smm *              FunctionId          - Sleep, WakePrep, or Wake
268228753Smm *
269228753Smm * RETURN:      Status from the invoked sleep handling function.
270228753Smm *
271228753Smm * DESCRIPTION: Dispatch a sleep/wake request to the appropriate handling
272228753Smm *              function.
273228753Smm *
274228753Smm ******************************************************************************/
275228753Smm
276228753Smmstatic ACPI_STATUS
277228753SmmAcpiHwSleepDispatch (
278228753Smm    UINT8                   SleepState,
279228753Smm    UINT32                  FunctionId)
280228753Smm{
281228753Smm    ACPI_STATUS             Status;
282228753Smm    ACPI_SLEEP_FUNCTIONS    *SleepFunctions = &AcpiSleepDispatch[FunctionId];
283228753Smm
284228753Smm
285228753Smm#if (!ACPI_REDUCED_HARDWARE)
286228753Smm    /*
287228753Smm     * If the Hardware Reduced flag is set (from the FADT), we must
288228753Smm     * use the extended sleep registers (FADT). Note: As per the ACPI
289228753Smm     * specification, these extended registers are to be used for HW-reduced
290228753Smm     * platforms only. They are not general-purpose replacements for the
291228753Smm     * legacy PM register sleep support.
292228753Smm     */
293228753Smm    if (AcpiGbl_ReducedHardware)
294228753Smm    {
295228753Smm        Status = SleepFunctions->ExtendedFunction (SleepState);
296228753Smm    }
297228753Smm    else
298228753Smm    {
299228753Smm        /* Legacy sleep */
300228753Smm
301228753Smm        Status = SleepFunctions->LegacyFunction (SleepState);
302228753Smm    }
303228753Smm
304228753Smm    return (Status);
305228753Smm
306228753Smm#else
307228753Smm    /*
308228753Smm     * For the case where reduced-hardware-only code is being generated,
309228753Smm     * we know that only the extended sleep registers are available
310228753Smm     */
311228753Smm    Status = SleepFunctions->ExtendedFunction (SleepState);
312228753Smm    return (Status);
313228753Smm
314228753Smm#endif /* !ACPI_REDUCED_HARDWARE */
315228753Smm}
316228753Smm
317228753Smm
318228753Smm/*******************************************************************************
319228753Smm *
320228753Smm * FUNCTION:    AcpiEnterSleepStatePrep
321228753Smm *
322228753Smm * PARAMETERS:  SleepState          - Which sleep state to enter
323228753Smm *
324228753Smm * RETURN:      Status
325228753Smm *
326228753Smm * DESCRIPTION: Prepare to enter a system sleep state.
327228753Smm *              This function must execute with interrupts enabled.
328228753Smm *              We break sleeping into 2 stages so that OSPM can handle
329228753Smm *              various OS-specific tasks between the two steps.
330228753Smm *
331228753Smm ******************************************************************************/
332228753Smm
333228753SmmACPI_STATUS
334228753SmmAcpiEnterSleepStatePrep (
335228753Smm    UINT8                   SleepState)
336228753Smm{
337228753Smm    ACPI_STATUS             Status;
338228753Smm    ACPI_OBJECT_LIST        ArgList;
339228753Smm    ACPI_OBJECT             Arg;
340228753Smm    UINT32                  SstValue;
341228753Smm
342228753Smm
343228753Smm    ACPI_FUNCTION_TRACE (AcpiEnterSleepStatePrep);
344228753Smm
345228753Smm
346228753Smm    Status = AcpiGetSleepTypeData (SleepState,
347228753Smm        &AcpiGbl_SleepTypeA, &AcpiGbl_SleepTypeB);
348228753Smm    if (ACPI_FAILURE (Status))
349228753Smm    {
350228753Smm        return_ACPI_STATUS (Status);
351228753Smm    }
352228753Smm
353353377Smm    /* Execute the _PTS method (Prepare To Sleep) */
354353377Smm
355228753Smm    ArgList.Count = 1;
356228753Smm    ArgList.Pointer = &Arg;
357228753Smm    Arg.Type = ACPI_TYPE_INTEGER;
358228753Smm    Arg.Integer.Value = SleepState;
359228753Smm
360228753Smm    Status = AcpiEvaluateObject (NULL, METHOD_PATHNAME__PTS, &ArgList, NULL);
361228753Smm    if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND)
362228753Smm    {
363228753Smm        return_ACPI_STATUS (Status);
364228753Smm    }
365228753Smm
366    /* Setup the argument to the _SST method (System STatus) */
367
368    switch (SleepState)
369    {
370    case ACPI_STATE_S0:
371
372        SstValue = ACPI_SST_WORKING;
373        break;
374
375    case ACPI_STATE_S1:
376    case ACPI_STATE_S2:
377    case ACPI_STATE_S3:
378
379        SstValue = ACPI_SST_SLEEPING;
380        break;
381
382    case ACPI_STATE_S4:
383
384        SstValue = ACPI_SST_SLEEP_CONTEXT;
385        break;
386
387    default:
388
389        SstValue = ACPI_SST_INDICATOR_OFF; /* Default is off */
390        break;
391    }
392
393    /*
394     * Set the system indicators to show the desired sleep state.
395     * _SST is an optional method (return no error if not found)
396     */
397    AcpiHwExecuteSleepMethod (METHOD_PATHNAME__SST, SstValue);
398    return_ACPI_STATUS (AE_OK);
399}
400
401ACPI_EXPORT_SYMBOL (AcpiEnterSleepStatePrep)
402
403
404/*******************************************************************************
405 *
406 * FUNCTION:    AcpiEnterSleepState
407 *
408 * PARAMETERS:  SleepState          - Which sleep state to enter
409 *
410 * RETURN:      Status
411 *
412 * DESCRIPTION: Enter a system sleep state
413 *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
414 *
415 ******************************************************************************/
416
417ACPI_STATUS
418AcpiEnterSleepState (
419    UINT8                   SleepState)
420{
421    ACPI_STATUS             Status;
422
423
424    ACPI_FUNCTION_TRACE (AcpiEnterSleepState);
425
426
427    if ((AcpiGbl_SleepTypeA > ACPI_SLEEP_TYPE_MAX) ||
428        (AcpiGbl_SleepTypeB > ACPI_SLEEP_TYPE_MAX))
429    {
430        ACPI_ERROR ((AE_INFO, "Sleep values out of range: A=0x%X B=0x%X",
431            AcpiGbl_SleepTypeA, AcpiGbl_SleepTypeB));
432        return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
433    }
434
435    Status = AcpiHwSleepDispatch (SleepState, ACPI_SLEEP_FUNCTION_ID);
436    return_ACPI_STATUS (Status);
437}
438
439ACPI_EXPORT_SYMBOL (AcpiEnterSleepState)
440
441
442/*******************************************************************************
443 *
444 * FUNCTION:    AcpiLeaveSleepStatePrep
445 *
446 * PARAMETERS:  SleepState          - Which sleep state we are exiting
447 *
448 * RETURN:      Status
449 *
450 * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a
451 *              sleep. Called with interrupts DISABLED.
452 *              We break wake/resume into 2 stages so that OSPM can handle
453 *              various OS-specific tasks between the two steps.
454 *
455 ******************************************************************************/
456
457ACPI_STATUS
458AcpiLeaveSleepStatePrep (
459    UINT8                   SleepState)
460{
461    ACPI_STATUS             Status;
462
463
464    ACPI_FUNCTION_TRACE (AcpiLeaveSleepStatePrep);
465
466
467    Status = AcpiHwSleepDispatch (SleepState, ACPI_WAKE_PREP_FUNCTION_ID);
468    return_ACPI_STATUS (Status);
469}
470
471ACPI_EXPORT_SYMBOL (AcpiLeaveSleepStatePrep)
472
473
474/*******************************************************************************
475 *
476 * FUNCTION:    AcpiLeaveSleepState
477 *
478 * PARAMETERS:  SleepState          - Which sleep state we are exiting
479 *
480 * RETURN:      Status
481 *
482 * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep
483 *              Called with interrupts ENABLED.
484 *
485 ******************************************************************************/
486
487ACPI_STATUS
488AcpiLeaveSleepState (
489    UINT8                   SleepState)
490{
491    ACPI_STATUS             Status;
492
493
494    ACPI_FUNCTION_TRACE (AcpiLeaveSleepState);
495
496
497    Status = AcpiHwSleepDispatch (SleepState, ACPI_WAKE_FUNCTION_ID);
498    return_ACPI_STATUS (Status);
499}
500
501ACPI_EXPORT_SYMBOL (AcpiLeaveSleepState)
502