blob: 6b4109ea16928d979a6031be43865f83e998a5f5 [file] [log] [blame]
// Copyright 2018 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.
#ifndef SRC_DEVICES_BOARD_DRIVERS_X86_INCLUDE_ACPI_PRIVATE_H_
#define SRC_DEVICES_BOARD_DRIVERS_X86_INCLUDE_ACPI_PRIVATE_H_
#include <vector>
#include <ddk/protocol/auxdata.h>
#include <ddk/protocol/pciroot.h>
#include <ddktl/device.h>
#include <ddktl/protocol/acpi.h>
#include <fbl/mutex.h>
#include "resources.h"
#define MAX_NAMESPACE_DEPTH 100
struct AcpiDevicePioResource {
explicit AcpiDevicePioResource(const resource_io& io)
: base_address{io.minimum}, alignment{io.alignment}, address_length{io.address_length} {}
uint32_t base_address;
uint32_t alignment;
uint32_t address_length;
};
struct AcpiDeviceMmioResource {
AcpiDeviceMmioResource(bool writeable, uint32_t base_address, uint32_t alignment,
uint32_t address_length)
: writeable{writeable},
base_address{base_address},
alignment{alignment},
address_length{address_length} {}
explicit AcpiDeviceMmioResource(const resource_memory_t& mem)
: AcpiDeviceMmioResource{mem.writeable, mem.minimum, mem.alignment, mem.address_length} {}
bool writeable;
uint32_t base_address;
uint32_t alignment;
uint32_t address_length;
};
struct AcpiDeviceIrqResource {
AcpiDeviceIrqResource(const resource_irq irq, int pin_index)
: trigger{irq.trigger},
polarity{irq.polarity},
sharable{irq.sharable},
wake_capable{irq.wake_capable},
pin{static_cast<uint8_t>(irq.pins[pin_index])} {}
uint8_t trigger;
#define ACPI_IRQ_TRIGGER_LEVEL 0
#define ACPI_IRQ_TRIGGER_EDGE 1
uint8_t polarity;
#define ACPI_IRQ_ACTIVE_HIGH 0
#define ACPI_IRQ_ACTIVE_LOW 1
#define ACPI_IRQ_ACTIVE_BOTH 2
uint8_t sharable;
#define ACPI_IRQ_EXCLUSIVE 0
#define ACPI_IRQ_SHARED 1
uint8_t wake_capable;
uint8_t pin;
};
class AcpiDevice;
using AcpiType = ddk::Device<AcpiDevice>;
class AcpiDevice : public AcpiType, public ddk::AcpiProtocol<AcpiDevice, ddk::base_protocol> {
public:
AcpiDevice(zx_device_t* parent, ACPI_HANDLE acpi_handle, zx_device_t* platform_bus)
: AcpiType{parent}, acpi_handle_{acpi_handle}, platform_bus_{platform_bus} {}
void AcpiDeviceStub() {}
// DDK mix-in impls.
void DdkRelease() { delete this; }
ACPI_HANDLE acpi_handle() const { return acpi_handle_; }
zx_device_t* platform_bus() const { return platform_bus_; }
zx_device_t** mutable_zxdev() { return &zxdev_; }
zx_status_t AcpiGetPio(uint32_t index, zx::resource* out_pio);
zx_status_t AcpiGetMmio(uint32_t index, acpi_mmio* out_mmio);
zx_status_t AcpiMapInterrupt(int64_t which_irq, zx::interrupt* handle);
zx_status_t AcpiGetBti(uint32_t bdf, uint32_t index, zx::bti* bti);
zx_status_t AcpiConnectSysmem(zx::channel connection);
zx_status_t AcpiRegisterSysmemHeap(uint64_t heap, zx::channel connection);
private:
// Handle to the corresponding ACPI node
ACPI_HANDLE acpi_handle_;
zx_device_t* platform_bus_;
mutable fbl::Mutex lock_;
bool got_resources_ = false;
// Port, memory, and interrupt resources from _CRS respectively
std::vector<AcpiDevicePioResource> pio_resources_;
std::vector<AcpiDeviceMmioResource> mmio_resources_;
std::vector<AcpiDeviceIrqResource> irqs_;
zx_status_t ReportCurrentResources();
ACPI_STATUS AddResource(ACPI_RESOURCE*);
};
class AcpiWalker {
public:
AcpiWalker(zx_device_t* sys_root, zx_device_t* acpi_root, zx_device_t* platform_bus)
: sys_root_{sys_root},
acpi_root_{acpi_root},
platform_bus_{platform_bus},
found_pci_{false},
last_pci_{kNoLastPci} {}
zx_device_t* platform_bus() const { return platform_bus_; }
bool found_pci() const { return found_pci_; }
void set_found_pci(bool found_pci) { found_pci_ = found_pci; }
uint8_t last_pci() const { return last_pci_; }
uint8_t* mutable_last_pci() { return &last_pci_; }
ACPI_STATUS OnDescent(ACPI_HANDLE object);
ACPI_STATUS OnAscent(ACPI_HANDLE object) { return AE_OK; }
static ACPI_STATUS OnDescentCallback(ACPI_HANDLE object, uint32_t depth, void* context,
void** return_value) {
return reinterpret_cast<AcpiWalker*>(context)->OnDescent(object);
}
static ACPI_STATUS OnAscentCallback(ACPI_HANDLE object, uint32_t depth, void* context,
void** return_value) {
return reinterpret_cast<AcpiWalker*>(context)->OnAscent(object);
}
private:
zx_device_t* PublishAcpiDevice(const char* name, ACPI_HANDLE handle, ACPI_DEVICE_INFO* info);
zx_device_t* sys_root_;
zx_device_t* acpi_root_;
zx_device_t* platform_bus_;
bool found_pci_;
uint8_t last_pci_; // bus number of the last PCI root seen
constexpr static auto kNoLastPci = std::numeric_limits<decltype(last_pci_)>::max();
};
struct pci_child_auxdata_ctx_t {
uint8_t max;
uint8_t i;
auxdata_i2c_device_t* data;
};
// TODO(cja): this is here because of kpci.cc and can be removed once
// kernel pci is out of the tree.
device_add_args_t get_device_add_args(const char* name, ACPI_DEVICE_INFO* info,
std::array<zx_device_prop_t, 4>* out_props);
const zx_protocol_device_t* get_acpi_root_device_proto(void);
#endif // SRC_DEVICES_BOARD_DRIVERS_X86_INCLUDE_ACPI_PRIVATE_H_