blob: a77f4d1d7e53d49385c645198161e7c8f2d4df93 [file] [log] [blame]
// Copyright 2020 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 "src/devices/board/drivers/vim3/vim3.h"
#include <assert.h>
#include <fidl/fuchsia.hardware.platform.bus/cpp/markers.h>
#include <lib/async/cpp/task.h>
#include <lib/ddk/binding.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 <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fbl/algorithm.h>
#include <fbl/alloc_checker.h>
namespace vim3 {
zx_status_t Vim3::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, fuchsia_hardware_platform_bus::Service::PlatformBus::ServiceName,
fuchsia_hardware_platform_bus::Service::PlatformBus::Name,
endpoints->server.TakeHandle().release());
if (status != ZX_OK) {
return status;
}
fbl::AllocChecker ac;
auto board = fbl::make_unique_checked<Vim3>(&ac, parent, std::move(endpoints->client));
if (!ac.check()) {
return ZX_ERR_NO_MEMORY;
}
status = board->DdkAdd("vim3", DEVICE_ADD_NON_BINDABLE);
if (status != ZX_OK) {
return status;
}
if (status == ZX_OK) {
// devmgr is now in charge of the device.
[[maybe_unused]] auto* dummy = board.release();
}
return status;
}
int Vim3::Thread() {
// Load protocol implementation drivers first.
zx_status_t status;
if ((status = SysmemInit()) != ZX_OK) {
zxlogf(ERROR, "SysmemInit() failed: %d", status);
init_txn_->Reply(ZX_ERR_INTERNAL);
return status;
}
if ((status = I2cInit()) != ZX_OK) {
zxlogf(ERROR, "I2cInit() failed: %d", status);
init_txn_->Reply(ZX_ERR_INTERNAL);
return status;
}
if ((status = McuInit()) != ZX_OK) {
zxlogf(ERROR, "McuInit() failed: %d", status);
init_txn_->Reply(ZX_ERR_INTERNAL);
return status;
}
if ((status = EthInit()) != ZX_OK) {
zxlogf(ERROR, "EthInit() failed: %d", status);
init_txn_->Reply(ZX_ERR_INTERNAL);
return status;
}
if ((status = EmmcInit()) != ZX_OK) {
zxlogf(ERROR, "EmmcInit() failed: %d\n", status);
init_txn_->Reply(ZX_ERR_INTERNAL);
return status;
}
if ((status = SdInit()) != ZX_OK) {
zxlogf(ERROR, "SdInit() failed: %d\n", status);
init_txn_->Reply(ZX_ERR_INTERNAL);
return status;
}
if ((status = SdioInit()) != ZX_OK) {
zxlogf(ERROR, "SdioInit() failed: %d\n", status);
init_txn_->Reply(ZX_ERR_INTERNAL);
return status;
}
if ((status = UsbInit()) != ZX_OK) {
zxlogf(ERROR, "UsbInit() failed: %d", status);
init_txn_->Reply(ZX_ERR_INTERNAL);
return status;
}
if ((status = PowerInit()) != ZX_OK) {
zxlogf(ERROR, "PowerInit() failed: %d", status);
init_txn_->Reply(ZX_ERR_INTERNAL);
return status;
}
if ((status = AudioInit()) != ZX_OK) {
zxlogf(ERROR, "AudioInit() failed: %d", status);
init_txn_->Reply(ZX_ERR_INTERNAL);
return status;
}
if ((status = BluetoothInit()) != ZX_OK) {
zxlogf(ERROR, "BluetoothInit() failed: %d", status);
init_txn_->Reply(ZX_ERR_INTERNAL);
return status;
}
if ((status = TemperatureInit()) != ZX_OK) {
zxlogf(ERROR, "TemperatureInit() failed: %d", status);
init_txn_->Reply(ZX_ERR_INTERNAL);
return status;
}
// ClkInit() must be called after other subsystems that bind to clock have had a chance to add
// their init steps.
if ((status = ClkInit()) != ZX_OK) {
zxlogf(ERROR, "ClkInit() failed: %d", status);
init_txn_->Reply(ZX_ERR_INTERNAL);
return status;
}
clock_init_steps_.clear();
// GpioInit() must be called after other subsystems that bind to GPIO have had a chance to add
// their init steps.
if ((status = GpioInit()) != ZX_OK) {
zxlogf(ERROR, "GpioInit() failed: %d", status);
init_txn_->Reply(ZX_ERR_INTERNAL);
return status;
}
if ((status = RegistersInit()) != ZX_OK) {
zxlogf(ERROR, "RegistersInit() failed: %d", status);
init_txn_->Reply(ZX_ERR_INTERNAL);
return status;
}
if ((status = MaliInit()) != ZX_OK) {
zxlogf(ERROR, "MaliInit() failed: %d\n", status);
}
if ((status = NnaInit()) != ZX_OK) {
zxlogf(ERROR, "NnaInit() failed: %d", status);
init_txn_->Reply(ZX_ERR_INTERNAL);
return status;
}
if (auto result = HrTimerInit(); result.is_error()) {
zxlogf(ERROR, "HrTimerInit() failed: %s", result.status_string());
init_txn_->Reply(result.error_value());
return result.error_value();
}
if (auto result = AdcInit(); result.is_error()) {
zxlogf(ERROR, "AdcInit() failed: %s", result.status_string());
init_txn_->Reply(result.error_value());
return result.error_value();
}
if (auto result = ButtonsInit(); result.is_error()) {
zxlogf(ERROR, "ButtonsInit() failed: %s", result.status_string());
init_txn_->Reply(result.error_value());
return result.error_value();
}
if ((status = CanvasInit()) != ZX_OK) {
zxlogf(ERROR, "CanvasInit() failed: %d", status);
init_txn_->Reply(ZX_ERR_INTERNAL);
return status;
}
if ((status = DisplayInit()) != ZX_OK) {
zxlogf(ERROR, "DisplayInit() failed: %d", status);
init_txn_->Reply(ZX_ERR_INTERNAL);
return status;
}
if ((status = TouchInit()) != ZX_OK) {
zxlogf(ERROR, "TouchInit() failed: %d", status);
init_txn_->Reply(ZX_ERR_INTERNAL);
return status;
}
if ((status = PwmInit()) != ZX_OK) {
zxlogf(ERROR, "PwmInit() failed: %d", status);
init_txn_->Reply(ZX_ERR_INTERNAL);
return status;
}
if ((status = BacklightInit()) != ZX_OK) {
zxlogf(ERROR, "BacklightInit() failed: %d", status);
init_txn_->Reply(ZX_ERR_INTERNAL);
return status;
}
if ((status = CpuInit()) != ZX_OK) {
zxlogf(ERROR, "CpuInit() failed: %d", status);
init_txn_->Reply(ZX_ERR_INTERNAL);
return status;
}
if ((status = VideoInit()) != ZX_OK) {
zxlogf(ERROR, "VideoInit() failed: %d", status);
init_txn_->Reply(ZX_ERR_INTERNAL);
return status;
}
if ((status = SuspendInit()) != ZX_OK) {
zxlogf(ERROR, "SuspendInit() failed: %d", status);
init_txn_->Reply(ZX_ERR_INTERNAL);
return status;
}
ZX_ASSERT_MSG(clock_init_steps_.empty(), "Clock init steps added but not applied");
init_txn_->Reply(status);
return ZX_OK;
}
void Vim3::DdkInit(ddk::InitTxn txn) {
init_txn_ = std::move(txn);
async::PostTask(fdf::Dispatcher::GetCurrent()->async_dispatcher(), [this]() { Thread(); });
}
static constexpr zx_driver_ops_t vim3_driver_ops = []() {
zx_driver_ops_t ops = {};
ops.version = DRIVER_OPS_VERSION;
ops.bind = Vim3::Create;
return ops;
}();
} // namespace vim3
ZIRCON_DRIVER(vim3, vim3::vim3_driver_ops, "zircon", "0.1");