DRM(1) -- DRM internals

DRM Internals Driver Initialization driver 首先需要静态初始化一个 struct drm_driver 结构体,然后调用 drm_dev_alloc() 来 创建一个 struct drm_device 结构体,初始化必要的 fields 后,最后调用 drm_dev_register() 注册 drm_device. Driver Information 在 struct drm_driver 结构体中的.major, .minor, .patchlevel, .name, .desc .date 字段用于描述 driver 的基本信息。 通过 DRM_IOCTL_VERSION 和 DRM_IOCTL_SET_VERSION 两个 ioctl 可以获取和设置 driver 基本信息。 Module Initialization 在 drm_module.h 中提供了一些封装的 api 来注册 module platform/pci driver: drm_module_pci_driver(__pci_drv); drm_module_platform_driver(__platform_drv); Device Instance and Driver Handling 这里有一个 driver 的 template, 具体查看官方文档。 如果需要支持热插拔 drm 设备,比如 USB, DT overlay unload, 需要使用 drm_dev_unplug() 代替 drm_dev_unregister()....

2025-04-15 · 5 min

DRM(11) -- Bridge

Overview struct drm_bridge 代表挂在 encoder 后面的设备。当 drm_encoder 不能完全代表整个 encoder chain 的时候, drm_bridge 就有用了。 Encoder –> Bridge A –> Bridge B drm bridge 和 drm panel 一样,不是 drm_mode_object, 对 userspace 是不可见的。他们只是用来提供额外的 hooks 来得到 encoder chain 最终的理想输出。 Display driver 负责把 encoder link 到第一个 bridge,通过devm_drm_of_get_bridge()获取 bridge,再通过drm_bridge_attach()将 bridge attach 到 encoder 上。 Bridge driver 负责把自己 link 到下一级 bridge,通过在 drm_bridges_funcs.attach 中调用drm_bridge_attach()。 最后一级 Bridge driver 还参与实现 drm connector, 通过drm_bridge_connector_init() helper 来创建 drm_connector. 或者通过 bridge 暴露出来的 connector 相关操作函数来手动实现 connector....

2025-04-15 · 4 min

DRM(13) -- Memory Management

Introduction DRM 核心包括两个内存管理器,分别是 Translation Table Manager(TTM) 和 Graphics Execution Manager(GEM). TTM 是第一个被开发的 DRM 内存管理器。它提供了一个单一的用户空间 API 来满足所有硬件的需求,支持统一内存体系结构 (Unified Memory Architecture,UMA) 设备和具有专用视频 RAM (即大多数离散显卡) 的设备。这导致了一大段复杂的代码,结果很难用于驱动程序开发。 由于 TTM 的复杂性,GEM 最初是由英特尔 (Intel) 赞助的一个项目。GEM 没有提供每个图形内存相关问题的解决方案,而是确定了驱动程序之间的公共代码,并创建了一个支持库来共享它。GEM 的初始化和执行要求比 TTM 简单,但没有视频 RAM 管理功能,因此仅限于 UMA 设备。 GEM Initialization 在 struct drm_driver driver feature 中设置 DRIVER_GEM bit. 中间层会自动调用drm_gem_init()来完成 GEM 的初始化。 GEM Objects Creation GEM object 由结构体 struct drm_gem_object表示,通过drm_gem_oject_init()初始化,利用 shmem 来分配 anonymous pageable memory. 如果 hardware 需要 physical contiguous system memory(通常是嵌入式设备需求), 那么可以不需要使用 shmem, 而是通过drm_gem_private_object_init()初始化。...

2024-12-10 · 3 min

DRM(12) -- Panel

Panel and Bridge 对于 dpi, mipi dsi connector, DRM core 提供了 struct drm_panel 来简化流程。 情况 1:设备树存在 panel 节点 imx6ull-dhcom-pdk2.dts 中的存在 panel 节点,对应 panel-simple.c: &lcdif { status = "okay"; port { display_out: endpoint { remote-endpoint = <&panel_in>; }; }; }; panel { compatible = "auo,g101evn010"; power-supply = <&ldo4_ext>; backlight = <&lcd_backlight>; port { panel_in: endpoint { remote-endpoint = <&display_out>; }; }; }; 这种情况比较简单,在底层 driver 中调用drm_of_find_panel_or_bridge找到设备树中的 panel 节点,和 panel driver 匹配,找到 panel driver 注册的 drm_panel 结构体。...

2024-10-15 · 3 min

Debug DRM driver in QEMU with Buildroot support

Buildroot 编译 kernel 和 rootfs 我们想在 QEMU 中进行 debug,那么首先需要准备好 kernel image 和 rootfs。这边我们采用的是 buildroot 的方式来创建我们需要的 kernel 和 rootfs。 下载 buildroot 2024: wget https://buildroot.org/downloads/buildroot-2024.02.6.tar.gz 接着进入 buildroot 目录,执行 make qemu_x86_64_defconfig,使用 qemu 的配置: cd buildroot-2024.02.6/ make qemu_x86_64_defconfig 对该 config 文件作如下改动: # support custom linux source code BR2_PACKAGE_OVERRIDE_FILE="board/qemu/x86_64/custom_override.mk" BR2_LINUX_KERNEL_CUSTOM_VERSION=y BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="linux-6.10" BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="board/qemu/x86_64/custom_linux.config" # GDB support BR2_PACKAGE_HOST_GDB=y # cross gdb for host machine BR2_PACKAGE_GDB=y BR2_PACKAGE_GDB_SERVER=y BR2_TOOLCHAIN_BUILDROOT_CXX=y BR2_DEBUG_3=y BR2_ENABLE_DEBUG=y # enable debug symbol in packages BR2_OPTIMIZE_0=y BR2_PACKAGE_LIBDRM=y BR2_PACKAGE_DRMTEST=y # custom drm test package 改动目的主要是:...

2024-09-26 · 2 min

DRM(8) -- Encoder

encoder 从 CRTC 拿到 pixel data,并将其转化为 connector 需要的 format。 encoder 通过 drm_encoder_init() 初始化,drm_encoder_cleanup() 清除。 struct drm_encoder_funcs { void (*reset)(struct drm_encoder *encoder); void (*destroy)(struct drm_encoder *encoder); int (*late_register)(struct drm_encoder *encoder); void (*early_unregister)(struct drm_encoder *encoder); void (*debugfs_init)(struct drm_encoder *encoder, struct dentry *root); }; reset: reset encoder。 destroy: drm_encoder_cleanup。如果用 drmm_encoder_init() 初始化的则不需要实现.destroy. late_register: 和 crtc 相关接口类似。 early_unregister: 同上。 debugfs_init: 注册 debugfs_init。 struct drm_encoder { struct drm_device *dev; struct list_head head; struct drm_mode_object base; char *name; int encoder_type; unsigned index; uint32_t possible_crtcs; uint32_t possible_clones; struct list_head bridge_chain; const struct drm_encoder_funcs *funcs; const struct drm_encoder_helper_funcs *helper_private; struct dentry *debugfs_entry; }; encoder_type: DRM_MODE_ENCODER_<foo>...

2024-09-18 · 1 min

DRM(7) -- Connector

DRM connector 是对显示接收器 (display sink) 的抽象,包括固定的 panels, 或者其他任何可以显示像素的东西。 通过 drm_connector_init() 和 drm_connector_register() 初始化和注册。 connector 使用前必须 attach 到 encoder 上,对于 encoder 和 connector 1:1 的情况,在初始化流程中调用 drm_connector_attach_encoder(). Data Structure struct drm_connector { struct drm_device *dev; struct device *kdev; struct device_attribute *attr; struct fwnode_handle *fwnode; struct list_head head; struct list_head global_connector_list_entry; struct drm_mode_object base; char *name; struct mutex mutex; unsigned index; int connector_type; int connector_type_id; bool interlace_allowed; bool doublescan_allowed; bool stereo_allowed; bool ycbcr_420_allowed; enum drm_connector_registration_state registration_state; struct list_head modes; enum drm_connector_status status; struct list_head probed_modes; struct drm_display_info display_info; const struct drm_connector_funcs *funcs; struct drm_property_blob *edid_blob_ptr; struct drm_object_properties properties; uint8_t polled; const struct drm_connector_helper_funcs *helper_private; struct drm_cmdline_mode cmdline_mode; enum drm_connector_force force; u64 epoch_counter; u32 possible_encoders; struct drm_encoder *encoder; struct i2c_adapter *ddc; struct dentry *debugfs_entry; struct drm_connector_state *state; }; connector_type: DRM_MODE_CONNECTOR_XXX。...

2024-09-18 · 4 min

DRM(4) -- CRTC

Overview CRTC 代表整个 display pipeline。它接收来自 drm_plane 的像素数据并将它们混合在一起。drm_display_mode 也附加在 CRTC 上,用于指定显示时序。在输出端,数据被送入一个或多个 drm_encoder,然后每个 encoder 都连接到一个 drm_connector 上。 crtc 使用drm_crtc_init_with_planes() 来初始化。 数据结构 drm_crtc struct drm_crtc { struct drm_device *dev; struct device_node *port; struct list_head head; char *name; struct drm_modeset_lock mutex; struct drm_mode_object base; unsigned index; const struct drm_crtc_funcs *funcs; const struct drm_crtc_helper_funcs *helper_private; struct drm_object_properties properties; struct drm_property *scaling_filter_property; struct drm_crtc_state *state; struct list_head commit_list; spinlock_t commit_lock; struct dentry *debugfs_entry; struct drm_crtc_crc crc; unsigned int fence_context; spinlock_t fence_lock; unsigned long fence_seqno; char timeline_name[32]; struct drm_self_refresh_data *self_refresh_data; }; drm_crtc_state struct drm_crtc_state { struct drm_crtc *crtc; bool enable; bool active; bool planes_changed : 1; bool mode_changed : 1; bool active_changed : 1; bool connectors_changed : 1; bool zpos_changed : 1; bool color_mgmt_changed : 1; bool no_vblank : 1; u32 plane_mask; u32 connector_mask; u32 encoder_mask; struct drm_display_mode adjusted_mode; struct drm_display_mode mode; struct drm_property_blob *mode_blob; struct drm_property_blob *degamma_lut; struct drm_property_blob *ctm; struct drm_property_blob *gamma_lut; u32 target_vblank; bool async_flip; bool vrr_enabled; bool self_refresh_active; enum drm_scaling_filter scaling_filter; struct drm_pending_vblank_event *event; struct drm_crtc_commit *commit; struct drm_atomic_state *state; }; enable: userspace set CRTC MODE_ID property, 进入 drm_atomic_set_mode_prop_for_crtc() 函数中设置 crtc 的 enable 状态。...

2024-09-04 · 4 min

DRM(9) -- Object and Property

Modeset Base Object Abstraction 所有 KMS objects 的 base structure 是 struct drm_mode_object, 用来追踪 property. property 可以通过 drm_object_attach_property() attach 到不同的 object 上。 Object 每个 drm mode 包括 drm_crtc, drm_connector, drm_framebuffer 等结构体中都会有一个 drm_mode_object 数据结构,其中保存了该 crtc/connector/fb/plane 的 id, 用于 id tracking. 还有对应的 property 属性等。 drm_mode_object 结构体: struct drm_mode_object { uint32_t id; uint32_t type; struct drm_object_properties *properties; struct kref refcount; void (*free_cb)(struct kref *kref); } id: 用户空间操作的 id. type: DRM_MODE_OBJECT_XXX, 包括 DRM_MODE_OBJECT_CRTC/CONNECTOR/ENCODER/MODE/PROPERTY/FB/BLOB/PLANE/ANY Userspace 只能对 CONNECTOR, CRTC, PLANE 三种 type 的 object property 进行设置 properties: drm object 用来追踪 property 的结构体。...

2024-09-02 · 4 min

DRM(3) -- Atomic commit

Atomic Mode Setting 在 DRM 子系统中,atomic mode setting 是指一种用于显示配置更新的机制,它允许将多个显示参数的变更作为一个原子性的操作一次性提交和应用。 整个更新作为一个单元被处理,不会出现部分应用的情况,所有显示参数的变更在同一个垂直消隐期间同步生效。 drm_atomic_state - 包含整个显示状态的快照 drm_crtc_state, drm_plane_state, drm_connector_state - 各组件的状态对象 crtc, plane, connector object 都包含一个 state,drm_plane_state, drm_crtc_state, drm_connector_state,这些 state 是在 atomic 过程中用户可见并且设置的。 在 driver 内部,如果需要保存一些内部状态,可以 subclass 这些 state,或者一个整体的 drm_private_state. Handling Driver Private State 通常 DRM objects (connector, crtc, plane) 不能与硬件完全的匹配映射。 比如在 planes, crtc 等之间一些共享的资源,shared clock, scaler units, bandwidth, fifo limits. 这时候我们需要创建一个仅内部可见的 private state. struct drm_private_state { struct drm_atomic_state *state; struct drm_private_obj *obj; }; state: backpointer,指向 atomic state...

2024-08-28 · 4 min