因此,您决定建立一个新面板。在深入了解编码之前,请确保 请回答以下问题,以确保您拥有所需的一切:
如何了解设备及其寄存器的工作原理?
- 这通常称为“运算理论”。制造商通常会提供 包含寄存器定义的数据表,但这些参考资料可能无法 设备的实际使用方式。
类似开发板是否有现成的驱动程序?
- 在可行的情况下,通过重构代码并重复使用类似的开发板代码, 修改驱动程序的绑定规则。
该设备是否具有固定的显示屏?
- 一些显示控制器和面板(输出屏幕)是紧密耦合的。 如果是这种情况,新开发板就需要添加对 GPIO、I2C 和其他控件作为显示驱动程序的一部分。
前提条件
本指南假定您熟悉一个或多个应用的驱动程序开发 操作系统此外还假定您熟悉紫红色 DDK-TL。
编程语言
新驱动程序必须使用 C++ 编写。我们计划支持 Rust,但仍高度支持 实验性功能
如果已存在获得相应许可的驱动程序,且 那么可以将其移植到 Fuchsia 而不是 如何用 C++实现新版本请联系 graphics-dev@fuchsia.dev 然后再做出这个决定
使用入门
对于没有 ACPI 或 PCI 总线的平台,修改板
驱动程序。本指南假定
板驱动程序已准备就绪,并且显示驱动程序的代号为 fancy
。所有代码
适用于新驱动程序将位于 src/graphics/display/drivers/fancy-display/
。
首先,请创建:
- DisplayEngine 的最小实现
- 一组绑定规则
DisplayEngine
和绑定规则的构建配方
将驱动程序添加到 build
- 在名为
BUILD.gn
的文件中创建构建配方
# Copyright 2021 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.
import("//build/bind/bind.gni")
import("//build/drivers.gni")
driver_bind_rules("fancy-display-bind") {
rules = "meta/fancy-display.bind"
bind_output = "fancy-display.bindbc"
tests = "meta/bind_tests.json"
deps = [
"//src/devices/bind/board_maker_company.platform",
]
}
# Factored out so that it can be used in tests.
source_set("common") {
public_deps = [
":fancy-display-bind",
]
sources = [
"fancy-display.cc",
]
}
fuchsia_driver("fancy-display") {
sources = []
deps = [
":common",
"//src/devices/lib/driver",
]
}
- 将
//src/graphics/display/drivers/fancy-display
添加为 您用作测试产品的开发板。例如,如果您的设备是 Khadas VIM3 开发板的一部分,//boards/vim3.gni
可以通过添加 将您的司机添加到_common_bootfs_deps
列表中。
选择要驾驶的设备
现在您已经有了构建配方,可以继续创建绑定了 这些规则,驱动程序管理器会根据这些规则来确定驱动程序是否 都可以与设备搭配使用
- 在
src/graphics/display/drivers/fancy-display
中,创建meta/fancy-display.bind
:
// Copyright 2021 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.
using fuchsia.pci;
fuchsia.BIND_PROTOCOL == fuchsia.pci.BIND_PROTOCOL.DEVICE;
fuchsia.BIND_PCI_VID == fuchsia.pci.BIND_PCI_VID.PLANK_HW_INC;
accept fuchsia.BIND_PCI_DID {
// Fancy
0x0100,
// Fancy+ series
0x0120,
0x0121,
}
对于 PC 设备,intel-display 绑定规则就是一个很好的示例。对于 固定硬件 SoC,请参阅 Amlogic 显示规则。
最少的驱动程序
最后,添加一个基本的驱动程序,该驱动程序每次都会构建一个新对象。 成功绑定到设备的时间稍后,您可以使用数据表 让设备真正执行某些操作
在 src/graphics/display/drivers/fancy-display
中,创建 fancy-display.cc
:
#include <ddktl/device.h>
#include <fuchsia/hardware/display/controller/cpp/banjo.h>
namespace fancy_display {
class Device;
using DeviceType = ddk::Device<Device>
// A Device exposes a single display controller for use by the display
// coordinator driver in src/graphics/display/drivers/coordinator.
//
// This object is constructed once for each device that matches this
// driver's bind rules.
class Device : public DeviceType {
public:
explicit Device(zx_device_t* parent) : DeviceType(parent) {}
// If Bind() returns an error, the driver won't claim the device.
zx_status_t Bind() { return ZX_OK };
// Functionality needed by the common display driver core.
void DisplayEngineRegisterDisplayEngineListener(
const display_engine_listener_protocol* interface) {}
zx_status_t DisplayEngineImportBufferCollection(
uint64_t collection_id, zx::channel collection_token) {
return ZX_ERR_NOT_SUPPORTED;
}
zx_status_t DisplayEngineReleaseBufferCollection(
uint64_t collection_id) {
return ZX_ERR_NOT_SUPPORTED;
}
zx_status_t DisplayEngineImportImage(const image_metadata_t* image_metadata,
uint64_t collection_id, uint32_t index,
uint64_t* out_image_handle) {
return ZX_ERR_NOT_SUPPORTED;
}
void DisplayEngineReleaseImage(image_t* image) {}
config_check_result_t DisplayEngineCheckConfiguration(
const display_config_t** display_configs, size_t display_count,
client_composition_opcode_t* out_client_composition_opcodes_list, size_t client_composition_opcodes_count,
size_t* out_client_composition_opcodes_actual);
void DisplayEngineApplyConfiguration(
const display_config_t** display_config, size_t display_count) {}
zx_status_t DisplayEngineSetBufferCollectionConstraints(
const image_buffer_usage_t* usage, uint64_t collection_id) {
return ZX_ERR_NOT_SUPPORTED;
}
};
} // namespace fancy_display
// Main bind function called from dev manager.
zx_status_t fancy_display_bind(void* ctx, zx_device_t* parent) {
fbl::AllocChecker alloc_checker;
auto dev = fbl::make_unique_checked<fancy_display::Device>(
&alloc_checker, parent);
if (!alloc_checker.check()) {
return ZX_ERR_NO_MEMORY;
}
auto status = dev->Bind();
if (status == ZX_OK) {
// The driver/device manager now owns this memory.
[[maybe_unused]] auto ptr = dev.release();
}
return status;
}
// zx_driver_ops_t is the ABI between driver modules and the device manager.
// This lambda is used so that drivers can be rebuilt without compiler
// warnings if/when new fields are added to the struct.
static zx_driver_ops_t fancy_display_ops = [](){
zx_driver_ops_t ops;
ops.version = DRIVER_OPS_VERSION;
ops.bind = fancy_display_bind;
return ops;
}();
// ZIRCON_DRIVER marks the compiled driver as compatible with the zircon
// 0.1 driver ABI.
ZIRCON_DRIVER(fancy_display, fancy_display_ops, "zircon", "0.1");
需要显示屏驱动程序才能实现 DisplayEngine
协议,用于公开硬件层并实现 Vsync
通知。显示协调器驱动程序多路复用
系统上所有设备专用的驱动程序和显示驱动程序之间
堆栈客户端,即系统合成器和 Virtcon。
实现提示
驱动程序决定何时以及如何将配置传递给 ApplyConfiguration
生效。为了避免画面撕裂,驾驶员应该
vsync 后立即应用新设置。
大多数设备都会对垂直同步事件造成中断。最简单的方法就是
确保及时生成 Vsync 通知,
为这个中断提供服务即使未显示图片,司机也必须
为每个 vsync 调用 OnDisplayVsync
。
支持引导加载程序的控制器
如果显示屏在启动时处于活跃状态,例如面板打开,而图片 ,您就可以快速获得驱动程序中的基本功能。已读 引导加载程序日志和/或源代码,以查找:
- 帧缓冲区的物理地址
- 用于对
- 图片的像素尺寸,例如800x600
- 图片的像素格式,例如RGB888、NV12 或 BGRA8888
然后:
- 修改驱动程序,以报告具有格式限制的显示屏。
- 记录
image->handle
中任何已导入映像的物理地址。 - 调用
ApplyConfig
时,对寄存器重新编程。
如果您还不知道如何观察 vsync,则可以使用
以 60Hz 的频率调用 OnDisplayVsync
。
以“深色”模式启动的控制器
没有什么办法能调出甚至缺少 基本引导加载程序驱动程序。在大多数情况下,您的路线图将是: