3. CRTC初始化与模式设置

CRTC初始化与模式设置 学习卡片

任务目标

在Linux DRM子系统中,CRTC(Cathode Ray Tube Controller)负责将帧缓冲扫描输出到显示器。本案例实现一个最小可用的CRTC初始化流程:创建drm_crtc实例,并实现其mode_set与atomic_check回调,使CRTC能够被DRM核心正确注册并参与模式配置。

核心实现

#include <drm/drm_crtc.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_modeset_helper.h>

/* mode_set回调:在CRTC模式切换时被调用,负责设置显示时序 */
static int my_crtc_mode_set(struct drm_crtc *crtc,
                            struct drm_display_mode *mode,
                            struct drm_display_mode *adjusted_mode,
                            int x, int y,
                            struct drm_framebuffer *old_fb)
{
    /* 实际硬件驱动在此配置CRTC寄存器(时序参数、分辨率等)
     * 本例为最小实现,仅记录模式信息供验证 */
    drm_mode_copy(&crtc->state->mode, mode);
    return 0;
}

/* atomic_check回调:验证CRTC状态变更的合法性 */
static int my_crtc_atomic_check(struct drm_crtc *crtc,
                                struct drm_atomic_state *state)
{
    struct drm_crtc_state *crtc_state;

    crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
    if (!crtc_state)
        return 0;

    /* 检查:若CRTC使能,则必须有有效的显示模式 */
    if (crtc_state->enable && !drm_mode_valid(crtc_state->mode)) {
        DRM_DEBUG_ATOMIC("CRTC %d: enable with invalid mode\n", crtc->base.id);
        return -EINVAL;
    }

    return 0;
}

/* CRTC辅助回调结构 */
static const struct drm_crtc_helper_funcs my_crtc_helper_funcs = {
    .mode_set = my_crtc_mode_set,
    .atomic_check = my_crtc_atomic_check,
};

/* CRTC核心回调结构 */
static const struct drm_crtc_funcs my_crtc_funcs = {
    .reset = drm_atomic_helper_crtc_reset,
    .destroy = drm_crtc_cleanup,
    .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
    .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
};

/* CRTC初始化入口 */
int my_crtc_init(struct drm_device *dev)
{
    struct drm_crtc *crtc;
    int ret;

    crtc = kzalloc(sizeof(*crtc), GFP_KERNEL);
    if (!crtc)
        return -ENOMEM;

    /* 创建CRTC实例,index=0表示第一个CRTC */
    ret = drm_crtc_init_with_planes(dev, crtc, NULL, NULL,
                                    &my_crtc_funcs, NULL);
    if (ret) {
        kfree(crtc);
        return ret;
    }

    /* 挂载辅助回调 */
    drm_crtc_helper_add(crtc, &my_crtc_helper_funcs);

    DRM_INFO("CRTC initialized (id=%u)\n", crtc->base.id);
    return 0;
}

集成与依赖

上述代码需嵌入你的DRM驱动中。在驱动的bind或load函数内调用my_crtc_init(dev)即可完成CRTC注册。依赖内核配置开启CONFIG_DRM与CONFIG_DRM_KMS_HELPER。若驱动使用atomic接口,还需在drm_mode_config中设置.atomic = true。

验证方法

  1. 编译验证:驱动模块成功编译且加载无报错,dmesg中出现CRTC initialized (id=0)日志。
  2. 状态查询:加载后执行modetest -c(需安装libdrm测试工具),输出中应包含CRTC列表,且状态为"ok"。
  3. atomic_check验证:使用modetest -s <connector_id>:<mode>设置显示模式。若设置非法分辨率(如超出硬件范围),命令应失败并返回Invalid argument,dmesg中出现enable with invalid mode调试信息。
  4. mode_set验证:成功设置模式后,通过cat /sys/kernel/debug/dri/0/state查看CRTC状态,确认mode字段与设置值一致。

通过标准:CRTC成功注册、合法模式可正常设置、非法模式被atomic_check拒绝,且无内核错误日志。