1. 初始化Rockchip DRM/KMS框架

初始化Rockchip DRM/KMS框架 学习卡片

任务目标

在Rockchip平台(以RK3568为例)上编写一个最小DRM驱动模块,完成向DRM子系统的注册与注销,验证模块加载/卸载时驱动的bind与unbind回调被正确调用。

环境依赖

  • Linux内核源码树(版本4.19或5.10,Rockchip SDK内核)
  • 交叉编译工具链(aarch64-linux-gnu-)
  • 目标板:RK3568 EVB或类似平台,内核已开启CONFIG_DRM与CONFIG_DRM_ROCKCHIP

核心实现

驱动通过platform_driver匹配设备树节点,在probe中调用drm_dev_alloc分配DRM设备并注册到DRM子系统。使用component框架与Rockchip DRM主设备协同工作,这是Rockchip平台DRM驱动的标准接入方式。

#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/component.h>
#include <drm/drm_device.h>
#include <drm/drm_drv.h>
#include <drm/drm_print.h>

static int demo_drm_bind(struct device *dev)
{
    struct drm_device *drm;
    int ret;

    drm = drm_dev_alloc(NULL, dev);
    if (IS_ERR(drm))
        return PTR_ERR(drm);

    /* 设置最小DRM驱动能力:仅支持PRIME内存管理 */
    drm->driver = kzalloc(sizeof(struct drm_driver), GFP_KERNEL);
    if (!drm->driver) {
        drm_dev_put(drm);
        return -ENOMEM;
    }
    drm->driver->prime_fd_to_handle = drm_gem_prime_fd_to_handle;
    drm->driver->gem_prime_handle_to_fd = drm_gem_prime_handle_to_fd;

    ret = drm_dev_register(drm, 0);
    if (ret) {
        kfree(drm->driver);
        drm_dev_put(drm);
        return ret;
    }

    dev_set_drvdata(dev, drm);
    drm_info(drm, "Rockchip DRM demo driver registered\n");
    return 0;
}

static void demo_drm_unbind(struct device *dev)
{
    struct drm_device *drm = dev_get_drvdata(dev);

    drm_dev_unregister(drm);
    kfree(drm->driver);
    drm_dev_put(drm);
    dev_set_drvdata(dev, NULL);
}

static const struct component_ops demo_drm_ops = {
    .bind = demo_drm_bind,
    .unbind = demo_drm_unbind,
};

static int demo_drm_probe(struct platform_device *pdev)
{
    return component_add(&pdev->dev, &demo_drm_ops);
}

static int demo_drm_remove(struct platform_device *pdev)
{
    component_del(&pdev->dev, &demo_drm_ops);
    return 0;
}

static const struct of_device_id demo_drm_of_match[] = {
    { .compatible = "rockchip,drm-demo" },
    { }
};
MODULE_DEVICE_TABLE(of, demo_drm_of_match);

static struct platform_driver demo_drm_platform_driver = {
    .probe = demo_drm_probe,
    .remove = demo_drm_remove,
    .driver = {
        .name = "rockchip-drm-demo",
        .of_match_table = demo_drm_of_match,
    },
};
module_platform_driver(demo_drm_platform_driver);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("DRM Demo");
MODULE_DESCRIPTION("Rockchip DRM minimal init/cleanup demo");

设备树节点

在目标板设备树中追加以下节点,使驱动能够匹配并绑定:

&drm_demo {
    status = "okay";
};

/ {
    drm_demo: drm-demo {
        compatible = "rockchip,drm-demo";
        status = "disabled";
    };
};

编译与安装

# 将源码放入 drivers/gpu/drm/rockchip/drm-demo.c
# 在 drivers/gpu/drm/rockchip/Makefile 中添加:
# obj-$(CONFIG_DRM_ROCKCHIP) += drm-demo.o

make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- Image dtbs
# 将内核与dtb烧录至目标板后重启

验证方法

  1. 模块加载后执行 dmesg | grep "drm-demo",应看到 Rockchip DRM demo driver registered 日志,说明bind回调成功执行且DRM设备已注册。
  2. 执行 ls /sys/class/drm/,若注册成功,会出现新的card节点(如card0或card1),且 cat /sys/class/drm/cardX/device/uevent 中 DRIVER=rockchip-drm-demo。
  3. 卸载模块(rmmod drm_demo)后再次执行 dmesg,确认无错误信息,且对应card节点消失,说明unbind清理路径正确。

通过条件:上述三条均满足,且系统无内核崩溃或内存泄漏警告。