blob: 77f1b77117406eb1bd6cb81e41ee47f81199fe8c [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stdio.h>
#include <acpica/acpi.h>
#include <magenta/process.h>
#include <magenta/processargs.h>
#include <magenta/syscalls.h>
#include <magenta/syscalls/port.h>
#include "ec.h"
#include "pci.h"
#include "powerbtn.h"
#include "processor.h"
#include "resource_tree.h"
#define ACPI_MAX_INIT_TABLES 32
static ACPI_STATUS set_apic_irq_mode(void);
static ACPI_STATUS init(void);
mx_handle_t root_resource_handle;
int main(int argc, char** argv) {
root_resource_handle = mx_get_startup_handle(PA_HND(PA_USER0, 0));
if (root_resource_handle <= 0) {
printf("Failed to find root resource handle\n");
return 1;
}
// Get handle from devmgr to serve as the ACPI root handle
mx_handle_t acpi_root = mx_get_startup_handle(PA_HND(PA_USER1, 0));
if (acpi_root <= 0) {
printf("Failed to find acpi root handle\n");
return 1;
}
ACPI_STATUS status = init();
if (status != MX_OK) {
printf("Failed to initialize ACPI\n");
return 3;
}
printf("Initialized ACPI\n");
mx_handle_t port;
mx_status_t mx_status = mx_port_create(0, &port);
if (mx_status != MX_OK) {
printf("Failed to construct resource port\n");
return 4;
}
ec_init();
mx_status = install_powerbtn_handlers();
if (mx_status != MX_OK) {
printf("Failed to install powerbtn handler\n");
}
mx_status = pci_report_current_resources(root_resource_handle);
if (mx_status != MX_OK) {
printf("WARNING: ACPI failed to report all current resources!\n");
}
return begin_processing(acpi_root);
}
static ACPI_STATUS init(void) {
// This sequence is described in section 10.1.2.1 (Full ACPICA Initialization)
// of the ACPICA developer's reference.
ACPI_STATUS status = AcpiInitializeSubsystem();
if (status != AE_OK) {
printf("WARNING: could not initialize ACPI\n");
return status;
}
status = AcpiInitializeTables(NULL, ACPI_MAX_INIT_TABLES, FALSE);
if (status == AE_NOT_FOUND) {
printf("WARNING: could not find ACPI tables\n");
return status;
} else if (status == AE_NO_MEMORY) {
printf("WARNING: could not initialize ACPI tables\n");
return status;
} else if (status != AE_OK) {
printf("WARNING: could not initialize ACPI tables for unknown reason\n");
return status;
}
status = AcpiLoadTables();
if (status != AE_OK) {
printf("WARNING: could not load ACPI tables: %d\n", status);
return status;
}
status = AcpiEnableSubsystem(ACPI_FULL_INITIALIZATION);
if (status != AE_OK) {
printf("WARNING: could not enable ACPI\n");
return status;
}
status = AcpiInitializeObjects(ACPI_FULL_INITIALIZATION);
if (status != AE_OK) {
printf("WARNING: could not initialize ACPI objects\n");
return status;
}
status = set_apic_irq_mode();
if (status == AE_NOT_FOUND) {
printf("WARNING: Could not find ACPI IRQ mode switch\n");
} else if (status != AE_OK) {
printf("Failed to set APIC IRQ mode\n");
return status;
}
// TODO(teisenbe): Maybe back out of ACPI mode on failure, but we rely on
// ACPI for some critical things right now, so failure will likely prevent
// successful boot anyway.
return AE_OK;
}
/* @brief Switch interrupts to APIC model (controls IRQ routing) */
static ACPI_STATUS set_apic_irq_mode(void) {
ACPI_OBJECT selector = {
.Integer.Type = ACPI_TYPE_INTEGER,
.Integer.Value = 1, // 1 means APIC mode according to ACPI v5 5.8.1
};
ACPI_OBJECT_LIST params = {
.Count = 1,
.Pointer = &selector,
};
return AcpiEvaluateObject(NULL, (char*)"\\_PIC", &params, NULL);
}