drm 驱动系列 - 第二章 KMS

本文详细介绍了KernelModeSetting(KMS)的核心思想,包括CRTC、ENCODER、CONNECTOR、PLANE等组件的作用,以及drm_mode_object结构的管理机制。KMS通过drm_mode_config组件提供灵活的管理模式,允许用户通过ioctl配置硬件显示链路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

文章目录


作者: baron

KMS(Kernel Mode Setting) 的核心思想就是将图形子系统的各个组件进行拆分和抽象,相对于 fbdev 使得内核能够更灵活、可扩展地管理这些组件。他们被拆分为 PLANE, CRTC, CONNECTOR, ENCODER, FB. 等组件

kms = drm_mode_config + 组件(obj)


元素说明
CRTC对显示 buffer 进行扫描,并产生时序信号的硬件模块,通常指 Display Controller
ENCODER负责将 CRTC 输出的 timing 时序转换成外部设备所需要的信号的模块,如 HDMI 转换器或 DSI Controller
CONNECTOR连接物理显示设备的连接器,如 HDMI、DisplayPort、DSI 总线,通常和 Encoder 驱动绑定在一起
PLANE硬件图层,有的 Display 硬件支持多层合成显示,但所有的 Display Controller 至少要有 1 个 plane
FBFramebuffer,单个图层的显示内容,唯一一个和硬件无关的基本元素
VBLANK软件和硬件的同步机制,RGB 时序中的垂直消影区,软件通常使用硬件 VSYNC 来实现
property任何你想设置的参数,都可以做成 property,是 DRM 驱动中最灵活、最方便的 Mode setting 机制
DUMB只支持连续物理内存,基于 kernel 中通用 CMA API 实现,多用于小分辨率简单场景
PRIME连续、非连续物理内存都支持,基于 DMA-BUF 机制,可以实现 buffer 共享,多用于大内存复杂场景
fencebuffer 同步机制,基于内核 dma_fence 机制实现,用于防止显示内容出现异步问题

此处参考最简单的DRM应用程序 (double-buffer)


上述的组件都由 drm_mode_object 描述. 通过 type 来确定 obj 描述的对象类型.

struct drm_mode_object {
    uint32_t id;  // 由 dev->mode_config.crtc_idr 申请过来的 idr, 本质是查找 obj 的索引

    /*
     #define DRM_MODE_OBJECT_CRTC 0xcccccccc
     #define DRM_MODE_OBJECT_CONNECTOR 0xc0c0c0c0
     #define DRM_MODE_OBJECT_ENCODER 0xe0e0e0e0
     #define DRM_MODE_OBJECT_MODE 0xdededede
     #define DRM_MODE_OBJECT_PROPERTY 0xb0b0b0b0
     #define DRM_MODE_OBJECT_FB 0xfbfbfbfb
     #define DRM_MODE_OBJECT_BLOB 0xbbbbbbbb
     #define DRM_MODE_OBJECT_PLANE 0xeeeeeeee
     #define DRM_MODE_OBJECT_ANY 0
     */
    uint32_t type;  // obj 类型, 不同的 type 表示不同的对象.
    struct drm_object_properties *properties; // 最多支持 24 个 properties
    struct kref refcount;
    void (*free_cb)(struct kref *kref);  // 释放回调接口
};

从结构体描述可知这些对象主要包括三个部分的内容.

  1. 对象 id 管理, 通过对象的 id, 可以通过 dev->mode_config.crtc_idr 查找到对应的对象.
  2. 属性(paropertise)管理, 对象的属性统一被存放到 properties.
  3. 对象生命周期管理, 释放对象时提供了 free_cb 接口.

内核提供了接口 drm_mode_object_get用初始化 obj. 该函数从 dev->mode_config.crtc_idr上申请一个 dir , 并用这个 idr 作为索引初始化 obj 的 id

// dev : 所属的 drm_device
// obj : 要初始化的 obj
// obj_type : obj 是什么对象. 对象包括 CRTC, CONNECTOR, ENCODER, FB, PLANE, PROPERTY 等这些类型
int drm_mode_object_get(struct drm_device *dev,
            struct drm_mode_object *obj, uint32_t obj_type)
{
    return drm_mode_object_get_reg(dev, obj, obj_type, true, NULL);
}

int drm_mode_object_get_reg(struct drm_device *dev,
                struct drm_mode_object *obj,
                uint32_t obj_type,
                bool register_obj,
                void (*obj_free_cb)(struct kref *kref))
{
    int ret;

    mutex_lock(&dev->mode_config.idr_mutex);
    ret = idr_alloc(&dev->mode_config.crtc_idr, register_obj ? obj : NULL, 1, 0, GFP_KERNEL);
    if (ret >= 0) {
        obj->id = ret;        // 设置 id
        obj->type = obj_type; // 设置类型
        if (obj_free_cb) {    // 设置 free_cb
            obj->free_cb = obj_free_cb;
            kref_init(&obj->refcount);
        }
    }
    mutex_unlock(&dev->mode_config.idr_mutex);

    return ret < 0 ? ret : 0;
}

上述 kms 相关的组件 (obj) 通过 drm_mode_config 进行维护和管理. 所以这个数据结构非常重要, 它也是 kms 的核心. 他们的关系如下图所示.

在这里插入图片描述

这些组件 (obj) + drm_mode_config 就组成了 kms. 通过 drm_dev 导出的 ioctl 我们就可以使用任意 plane + crtc + encoder + connector + panel 来组合我们需要的硬件显示链路了.例如我们有如下硬件结构

plane0 --> crtc0 --> encoder0(mipi) --> connector0 --> panel0(lcd1)
                 --> encoder1(hdmi) --> connector1 --> panel1(lcd2)
                                                   --> panel2(lcd3)

我们有个 mipi lcd3 想用它显示, 用户可以通过 ioctl 设置我们需要的硬件链路, 十分方便.

plane0 --> crtc0 --> encoder0(mipi) --> connector0 --> panel3
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值