blob: 10e6c23ec32154a634396846fc9ca638b8ff799a [file] [log] [blame]
// Copyright 2023 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 "qemu-riscv64.h"
#include <assert.h>
#include <fidl/fuchsia.hardware.platform.bus/cpp/driver/fidl.h>
#include <fidl/fuchsia.hardware.platform.bus/cpp/fidl.h>
#include <lib/ddk/binding_driver.h>
#include <lib/ddk/debug.h>
#include <lib/ddk/device.h>
#include <lib/ddk/driver.h>
#include <lib/ddk/platform-defs.h>
#include <lib/zx/result.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <zircon/threads.h>
#include <fbl/alloc_checker.h>
#include "fidl/fuchsia.hardware.platform.bus/cpp/natural_types.h"
#include "lib/fdf/cpp/arena.h"
namespace board_qemu_riscv64 {
namespace fpbus = fuchsia_hardware_platform_bus;
void QemuRiscv64::SysinfoInit() {
fdf::Arena arena('RISC');
fpbus::BootloaderInfo bootloader_info;
bootloader_info.vendor() = "<unknown>";
{
fidl::Arena fidl_arena;
auto result = pbus_.buffer(arena)->SetBootloaderInfo(fidl::ToWire(fidl_arena, bootloader_info));
if (!result.ok()) {
zxlogf(ERROR, "SetBoardInfo request failed: %s", result.FormatDescription().data());
} else if (result->is_error()) {
zxlogf(ERROR, "SetBoardInfo failed: %s", zx_status_get_string(result->error_value()));
}
}
}
void QemuRiscv64::DdkInit(ddk::InitTxn txn) {
SysinfoInit();
zx::result<> result = SysmemInit();
if (result.is_error()) {
zxlogf(ERROR, "Couldn't initialize sysmem: %s", result.status_string());
return txn.Reply(result.error_value());
}
result = RtcInit();
if (result.is_error()) {
zxlogf(ERROR, "Couldn't initialize rtc: %s", result.status_string());
return txn.Reply(result.error_value());
}
result = PcirootInit();
if (result.is_error()) {
zxlogf(ERROR, "Couldn't initialize pciroot: %s", result.status_string());
return txn.Reply(result.error_value());
}
zxlogf(DEBUG, "Init successful");
txn.Reply(ZX_OK);
}
zx_status_t QemuRiscv64::Create(void* ctx, zx_device_t* parent) {
auto endpoints = fdf::CreateEndpoints<fuchsia_hardware_platform_bus::PlatformBus>();
if (endpoints.is_error()) {
return endpoints.error_value();
}
zx_status_t status = device_connect_runtime_protocol(
parent, fpbus::Service::PlatformBus::ServiceName, fpbus::Service::PlatformBus::Name,
endpoints->server.TakeHandle().release());
if (status != ZX_OK) {
zxlogf(ERROR, "Failed to connect to platform bus: %s", zx_status_get_string(status));
return status;
}
fbl::AllocChecker ac;
auto board = fbl::make_unique_checked<QemuRiscv64>(&ac, parent, std::move(endpoints->client));
if (!ac.check()) {
return ZX_ERR_NO_MEMORY;
}
status = board->DdkAdd("qemu-riscv64", DEVICE_ADD_NON_BINDABLE);
if (status != ZX_OK) {
zxlogf(ERROR, "DdkAdd failed: %s", zx_status_get_string(status));
return status;
}
[[maybe_unused]] auto ptr = board.release();
return ZX_OK;
}
} // namespace board_qemu_riscv64
static constexpr zx_driver_ops_t driver_ops = []() {
zx_driver_ops_t ops = {};
ops.version = DRIVER_OPS_VERSION;
ops.bind = board_qemu_riscv64::QemuRiscv64::Create;
return ops;
}();
// clang-format off
ZIRCON_DRIVER(qemu-riscv64, driver_ops, "zircon", "0.1");
// clang-format on