1// Copyright 2016 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "power.h"
6
7#include <acpica/acpi.h>
8#include <ddk/debug.h>
9#include <zircon/syscalls/system.h>
10
11void poweroff(void) {
12    ACPI_STATUS status = AcpiEnterSleepStatePrep(5);
13    if (status == AE_OK) {
14        AcpiEnterSleepState(5);
15    }
16}
17
18void reboot(void) {
19    AcpiReset();
20}
21
22zx_status_t suspend_to_ram(void) {
23    zx_status_t status = ZX_OK;
24
25    acpica_enable_noncontested_mode();
26
27    status = zx_system_powerctl(get_root_resource(),
28                                ZX_SYSTEM_POWERCTL_DISABLE_ALL_CPUS_BUT_PRIMARY, NULL);
29    if (status != ZX_OK) {
30        zxlogf(ERROR, "acpi: Failed to shutdown CPUs: %d\n", status);
31        goto cleanup;
32    }
33
34    ACPI_STATUS acpi_status = AcpiEnterSleepStatePrep(3);
35    if (acpi_status != AE_OK) {
36        zxlogf(ERROR, "acpi: Failed to prep enter sleep state: %x\n", acpi_status);
37        // TODO: I think we need to do LeaveSleepState{Prep,} on failure
38        status = ZX_ERR_INTERNAL;
39        goto cleanup;
40    }
41
42    acpi_status = AcpiEnterSleepState(3);
43    if (acpi_status != AE_OK) {
44        status = ZX_ERR_INTERNAL;
45        zxlogf(ERROR, "acpi: Failed to enter sleep state: %x\n", acpi_status);
46        // Continue executing to try to get the system back to where it was
47    }
48    zxlogf(TRACE, "acpi: Woke up from sleep\n");
49
50    acpi_status = AcpiLeaveSleepStatePrep(3);
51    if (acpi_status != AE_OK) {
52        status = ZX_ERR_INTERNAL;
53        zxlogf(ERROR, "acpi: Failed to prep leave sleep state: %x\n", acpi_status);
54    }
55
56    acpi_status = AcpiLeaveSleepState(3);
57    if (acpi_status != AE_OK) {
58        status = ZX_ERR_INTERNAL;
59        zxlogf(ERROR, "acpi: Failed to leave sleep state: %x\n", acpi_status);
60    }
61
62    zx_status_t status2;
63cleanup:
64    status2 = zx_system_powerctl(get_root_resource(), ZX_SYSTEM_POWERCTL_ENABLE_ALL_CPUS, NULL);
65    if (status2 != ZX_OK) {
66        zxlogf(ERROR, "acpi: Re-enabling all cpus failed: %d\n", status2);
67    }
68
69    acpica_disable_noncontested_mode();
70
71    zxlogf(INFO, "acpi: Finished processing suspend: %d\n", status);
72    return status;
73}
74