blob: 34355663fbebc90c06dcf8108f0be4711e95e67c [file] [log] [blame]
// Copyright 2024 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/graphics/display/drivers/amlogic-display/display-device-driver-dfv1.h"
#include <lib/ddk/binding_driver.h>
#include <lib/ddk/debug.h>
#include <lib/ddk/device.h>
#include <lib/ddk/driver.h>
#include <lib/fit/defer.h>
#include <lib/zx/result.h>
#include <zircon/errors.h>
#include <zircon/types.h>
#include <memory>
#include <ddktl/device.h>
#include <fbl/alloc_checker.h>
#include "src/graphics/display/lib/driver-framework-migration-utils/dispatcher/dispatcher-factory.h"
#include "src/graphics/display/lib/driver-framework-migration-utils/dispatcher/loop-backed-dispatcher-factory.h"
#include "src/graphics/display/lib/driver-framework-migration-utils/metadata/metadata-getter-dfv1.h"
#include "src/graphics/display/lib/driver-framework-migration-utils/metadata/metadata-getter.h"
#include "src/graphics/display/lib/driver-framework-migration-utils/namespace/namespace-dfv1.h"
#include "src/graphics/display/lib/driver-framework-migration-utils/namespace/namespace.h"
namespace amlogic_display {
// static
zx_status_t DisplayDeviceDriverDfv1::Create(zx_device_t* parent) {
zx::result<std::unique_ptr<display::Namespace>> create_incoming_result =
display::NamespaceDfv1::Create(parent);
if (create_incoming_result.is_error()) {
zxlogf(ERROR, "Failed to create incoming display::Namespace: %s",
create_incoming_result.status_string());
return create_incoming_result.status_value();
}
std::unique_ptr<display::Namespace> incoming = std::move(create_incoming_result).value();
zx::result<std::unique_ptr<display::MetadataGetter>> create_metadata_getter_result =
display::MetadataGetterDfv1::Create(parent);
if (create_metadata_getter_result.is_error()) {
zxlogf(ERROR, "Failed to create Metadata getter: %s",
create_metadata_getter_result.status_string());
return create_metadata_getter_result.status_value();
}
std::unique_ptr<display::MetadataGetter> metadata_getter =
std::move(create_metadata_getter_result).value();
zx::result<std::unique_ptr<display::DispatcherFactory>> create_dispatcher_factory_result =
display::LoopBackedDispatcherFactory::Create(parent);
if (create_dispatcher_factory_result.is_error()) {
zxlogf(ERROR, "Failed to create Dispatcher factory: %s",
create_dispatcher_factory_result.status_string());
return create_dispatcher_factory_result.status_value();
}
std::unique_ptr<display::DispatcherFactory> dispatcher_factory =
std::move(create_dispatcher_factory_result).value();
zx::result<std::unique_ptr<DisplayEngine>> display_engine_result =
DisplayEngine::Create(incoming.get(), metadata_getter.get(), dispatcher_factory.get());
if (display_engine_result.is_error()) {
zxlogf(ERROR, "Failed to create DisplayEngine instance: %s",
display_engine_result.status_string());
return display_engine_result.status_value();
}
std::unique_ptr<DisplayEngine> display_engine = std::move(display_engine_result).value();
auto cleanup =
fit::defer([display_engine = display_engine.get()]() { display_engine->Deinitialize(); });
fbl::AllocChecker alloc_checker;
auto display_device_driver = fbl::make_unique_checked<DisplayDeviceDriverDfv1>(
&alloc_checker, parent, std::move(incoming), std::move(metadata_getter),
std::move(dispatcher_factory), std::move(display_engine));
if (!alloc_checker.check()) {
zxlogf(ERROR, "Failed to allocate memory for DisplayDeviceDriver");
return ZX_ERR_NO_MEMORY;
}
zx::result<> init_result = display_device_driver->Init();
if (init_result.is_error()) {
zxlogf(ERROR, "Failed to add device: %s", init_result.status_string());
return init_result.status_value();
}
// `display_device_driver` is managed by the device manager.
[[maybe_unused]] DisplayDeviceDriverDfv1* display_device_driver_ptr =
display_device_driver.release();
cleanup.cancel();
return ZX_OK;
}
DisplayDeviceDriverDfv1::DisplayDeviceDriverDfv1(
zx_device_t* parent, std::unique_ptr<display::Namespace> incoming,
std::unique_ptr<display::MetadataGetter> metadata_getter,
std::unique_ptr<display::DispatcherFactory> dispatcher_factory,
std::unique_ptr<DisplayEngine> display_engine)
: DeviceType(parent),
incoming_(std::move(incoming)),
metadata_getter_(std::move(metadata_getter)),
dispatcher_factory_(std::move(dispatcher_factory)),
display_engine_(std::move(display_engine)) {}
DisplayDeviceDriverDfv1::~DisplayDeviceDriverDfv1() = default;
zx::result<> DisplayDeviceDriverDfv1::Init() {
const ddk::DeviceAddArgs args = ddk::DeviceAddArgs("amlogic-display")
.set_proto_id(ZX_PROTOCOL_DISPLAY_CONTROLLER_IMPL)
.set_flags(DEVICE_ADD_ALLOW_MULTI_COMPOSITE)
.set_inspect_vmo(display_engine_->inspector().DuplicateVmo());
return zx::make_result(DdkAdd(args));
}
void DisplayDeviceDriverDfv1::DdkRelease() {
display_engine_->Deinitialize();
delete this;
}
zx_status_t DisplayDeviceDriverDfv1::DdkGetProtocol(uint32_t proto_id, void* out_protocol) {
ZX_DEBUG_ASSERT(display_engine_ != nullptr);
auto* proto = static_cast<ddk::AnyProtocol*>(out_protocol);
proto->ctx = display_engine_.get();
switch (proto_id) {
case ZX_PROTOCOL_DISPLAY_CONTROLLER_IMPL:
proto->ops = display_engine_->display_controller_impl_protocol_ops();
return ZX_OK;
default:
return ZX_ERR_NOT_SUPPORTED;
}
}
namespace {
constexpr zx_driver_ops_t kDriverOps = {
.version = DRIVER_OPS_VERSION,
.bind = [](void* ctx, zx_device_t* parent) { return DisplayDeviceDriverDfv1::Create(parent); },
};
} // namespace
} // namespace amlogic_display
// clang-format off
ZIRCON_DRIVER(amlogic_display, amlogic_display::kDriverOps, "zircon", "0.1");