4、内核编译与模块加载:内核配置选项(Kconfig)、编译DU驱动模块、动态加载与调试

好,咱们进入第四章。这一章讲的是怎么把DU驱动真正跑起来。说白了,就是三件事:配好内核、编出模块、加载调试。

我见过不少工程师,驱动代码写得挺漂亮,结果卡在编译和加载环节。嗯,这里要注意,R-Car的图形栈对内核配置有硬性要求,漏一个选项就可能黑屏。

4.1 内核配置选项(Kconfig)

先说说Kconfig。DU驱动在内核里不是默认打开的,你得手动选上。我个人习惯是在做BSP移植时,先把所有图形相关选项列个清单,然后逐项确认。

关键路径在这里:

Device Drivers  --->
    Graphics support  --->
        <*> DRM Support for Renesas R-Car DU
        [*]   Enable HDMI output support
        [*]   Enable LVDS output support
        [*]   Enable VSP-based display support

注意,<*> 表示编译进内核,<M> 表示编译成模块。我建议前期调试阶段用 <M>,这样改完驱动不用整个重编内核,省时间。

除了DU本身,还有几个依赖项必须打开:

配置项 路径 说明
CONFIG_DRM Graphics support → DRM DRM核心框架,DU的上层依赖
CONFIG_DRM_RCAR_DU Graphics support → Renesas R-Car DU DU驱动主模块
CONFIG_DRM_RCAR_HDMI 同上,子选项 HDMI输出支持
CONFIG_DRM_RCAR_LVDS 同上,子选项 LVDS输出支持
CONFIG_DRM_RCAR_VSP 同上,子选项 VSP硬件合成支持
CONFIG_VIDEO_RENESAS_VSP1 Multimedia support → VSP1 VSP1驱动,DU依赖它做合成
我曾经遇到过一个问题:CONFIG_DRM_RCAR_VSP 没开,结果DU驱动加载成功了,但画面死活不显示。查了两天才发现是VSP没使能。所以,这几个依赖项一定要检查到位。

4.2 编译DU驱动模块

配置完内核,接下来就是编译。如果你把DU设成了模块(<M>),编译命令很简单:

make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- modules

编完之后,在 drivers/gpu/drm/rcar-du/ 目录下会生成 rcar-du-drm.ko 文件。这就是我们要的模块。

如果你想把所有模块打包到内核镜像里一起烧录,可以用:

make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- modules_install INSTALL_MOD_PATH=/path/to/rootfs

我个人习惯是单独编模块,然后手动拷贝到目标板。这样每次改驱动只需要重新编一个 .ko 文件,不用重新打包整个文件系统。

小技巧: 编模块时加 V=1 参数可以看到完整编译命令,方便排查头文件路径或链接错误。比如:make V=1 ARCH=arm64 ...

4.3 动态加载与卸载

模块编好了,怎么加载到内核里?最直接的方式是用 insmod:

insmod rcar-du-drm.ko

但注意,DU模块有依赖关系。它依赖 drm.ko 和 vsp1.ko。如果这些模块没先加载,insmod 会报错。我建议用 modprobe,它会自动处理依赖:

modprobe rcar-du-drm

卸载模块用 rmmod:

rmmod rcar-du-drm

你想想看,如果模块正在被使用(比如有应用程序打开了DRM设备),rmmod 会失败。这时候得先关掉那些进程。

查看模块是否加载成功,用 lsmod:

lsmod | grep rcar

如果看到 rcar_du_drm 在列表里,说明加载成功了。

加载顺序建议:
  1. 先加载 vsp1.ko(VSP驱动)
  2. 再加载 rcar-du-drm.ko(DU驱动)
  3. 最后检查 /dev/dri/ 目录下是否有 card0 或 controlD64 设备节点

4.4 调试手段

驱动加载完了,怎么知道它工作正常?我常用的调试手段有这几个:

  • dmesg 日志:加载模块后立刻看内核日志。dmesg | tail -50。如果看到 "rcar-du: probe failed" 之类的错误,说明初始化有问题。
  • DRM调试接口:内核提供了 /sys/kernel/debug/dri/ 目录,里面能看到每个DRM设备的状态。比如 cat /sys/kernel/debug/dri/0/name 可以查看设备名称。
  • modinfo:查看模块的详细信息,包括作者、描述、参数等。modinfo rcar-du-drm.ko。
  • strace:如果应用程序打不开DRM设备,用 strace -e openat,ioctl 跟踪系统调用,看是哪个步骤失败了。
注意: 调试接口需要挂载debugfs:mount -t debugfs none /sys/kernel/debug。有些文件系统默认没挂载,不挂的话 /sys/kernel/debug/dri/ 目录是空的。

4.5 知识体系图

下面这张图总结了本章的核心流程,从内核配置到模块加载再到调试,一条线串下来:

DU驱动编译与加载流程 DU驱动编译与加载流程 1. 内核配置 (Kconfig) 2. 编译模块 (make modules) 3. 动态加载 (insmod) CONFIG_DRM_RCAR_DU=y/m 依赖项:VSP、HDMI、LVDS 生成 rcar-du-drm.ko 拷贝到目标板 /lib/modules modprobe rcar-du-drm 检查 /dev/dri/card0 4. 调试验证 dmesg 查看日志 debugfs 状态检查 modinfo 查看参数 strace 跟踪调用 关键:先配Kconfig → 编模块 → 按依赖顺序加载 → 用dmesg/debugfs验证 漏掉VSP或debugfs未挂载是常见坑

4.6 常见问题与避坑

最后,我总结几个实际项目中容易踩的坑:

  • 模块加载顺序错误:先加载DU再加载VSP,会导致DU初始化时找不到VSP,probe失败。正确顺序是先VSP后DU。
  • 内核版本不匹配:编模块用的内核头文件版本必须和运行内核一致。否则 insmod 会报 "Invalid module format"。用 uname -r 确认版本。
  • debugfs未挂载:前面提过,不挂载debugfs就看不了DRM状态。很多新手会忽略这一步。
  • 设备树节点缺失:DU驱动依赖设备树中的 rcar-du 节点。如果设备树里没配或者配错了,驱动加载成功但不会创建DRM设备。
我的习惯: 每次改完驱动,我都会写一个简单的加载脚本,把依赖检查和加载顺序都写进去。这样既省时间又不容易出错。脚本大概长这样:
#!/bin/sh
modprobe vsp1
modprobe rcar-du-drm
sleep 1
ls /dev/dri/
dmesg | tail -10

嗯,这一章的内容就到这儿。配置、编译、加载、调试,四个步骤环环相扣。把这些搞定了,DU驱动就能在你的板子上跑起来了。