1. 问题现象与初步分析
最近在使用荣品PRO-RK3566核心板搭配buildroot系统时,遇到了一个棘手的显示问题:HDMI接口无法正常输出图像,同时系统日志中不断出现rockchip-vop2 fe040000.vop: [drm:vop2_isr] *ERROR* POST_BUF_EMPTY irq err at vp0的错误提示。这个错误看起来与显示控制器(VOP2)的中断处理有关,具体表现为帧缓冲区的状态异常。
从日志中可以观察到几个关键信息点:
- 错误类型是
POST_BUF_EMPTY,这通常表示显示控制器在预期接收图像数据时遇到了空缓冲区 - 错误发生在
vp0(Video Port 0),这是Rockchip VOP2架构中的主要显示通道 - 伴随出现的还有
dwhdmi-rockchip fe0a0000.hdmi: failed to get edid错误,说明HDMI的EDID信息获取也失败了
在实际调试过程中,我发现这个问题有几个特点:
- 系统启动时HDMI显示器完全没有信号输出
- 即使连接了标准的HDMI显示器,系统也无法正确识别显示器的EDID信息
- 错误信息会以每秒数次的频率持续输出,说明这是一个持续性的硬件通信问题
2. Rockchip VOP2架构解析
要理解这个错误的根源,我们需要先了解Rockchip VOP2显示控制器的基本工作原理。VOP2(Video Output Processor version 2)是Rockchip新一代的显示控制器,相比前代VOP1有了显著的架构改进。
VOP2的主要特点包括:
- 支持多视频端口(vp0/vp1/vp2)输出
- 每个视频端口可以独立配置分辨率、时序等参数
- 支持多种显示接口:HDMI、eDP、MIPI-DSI等
- 采用DRM(Direct Rendering Manager)框架进行管理
在PRO-RK3566的硬件设计中:
- VOP2控制器位于fe040000地址空间
- HDMI控制器位于fe0a0000地址空间
- 默认配置使用vp0作为主显示通道
当系统启动时,显示子系统的工作流程大致如下:
- DRM驱动初始化VOP2硬件
- 配置默认显示参数
- 尝试通过HDMI读取EDID信息
- 根据EDID信息配置合适的显示模式
- 建立帧缓冲区并开始图像输出
3. 错误原因深度分析
结合日志和VOP2的工作原理,我们可以分析出POST_BUF_EMPTY错误的几个可能原因:
3.1 帧缓冲区配置问题
POST_BUF_EMPTY错误直接表明显示控制器在预期接收图像数据时遇到了空缓冲区。这可能由以下情况导致:
- 帧缓冲区内存分配失败
- 缓冲区地址未正确配置到VOP2寄存器
- 缓冲区大小与显示模式不匹配
在buildroot系统中,帧缓冲区通常由DRM的rockchip驱动管理。检查dmesg日志时,我发现系统确实尝试设置了1280x720@60Hz的模式,但没有看到成功的缓冲区分配记录。
3.2 HDMI EDID读取失败
日志中反复出现的failed to get edid错误也很关键。EDID是显示器用来告知主机其支持分辨率的重要数据。当EDID读取失败时,系统会使用默认的显示模式,这可能与实际的显示器参数不匹配。
在PRO-RK3566上,EDID读取失败可能有以下原因:
- HDMI物理连接问题
- I2C通信异常(EDID通过I2C总线读取)
- HDMI控制器初始化不完整
- 内核驱动中的EDID处理逻辑有问题
3.3 时钟与电源管理问题
Rockchip SoC的显示子系统对时钟和电源管理非常敏感。如果相关时钟没有正确配置或使能,也会导致显示控制器工作异常。特别是:
- VOP2的DCLK(像素时钟)
- HDMI的TMDS时钟
- 相关电源域的供电状态
4. 解决方案与调试步骤
经过多次尝试和验证,我总结出一套有效的解决方案,以下是详细的操作步骤:
4.1 修改内核设备树配置
首先需要检查并修改设备树中对VOP2和HDMI的配置。在arch/arm64/boot/dts/rockchip/rk3566-pro.dtsi文件中:
&vop { status = "okay"; assigned-clocks = <&cru DCLK_VOP0>, <&cru DCLK_VOP1>; assigned-clock-parents = <&pmucru PLL_HPLL>, <&pmucru PLL_HPLL>; }; &hdmi { status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&hdmitx_scl &hdmitx_sda &hdmitxm0_cec>; ddc-i2c-scl-high-time-ns = <9625>; ddc-i2c-scl-low-time-ns = <10000>; };关键修改点包括:
- 确保VOP和HDMI的status都是"okay"
- 明确指定VOP的时钟源
- 调整HDMI DDC(EDID读取)的I2C时序参数
4.2 调整内核启动参数
在buildroot的启动参数中添加以下配置:
# 在bootargs中添加 earlycon=uart8250,mmio32,0xfe660000 console=ttyFIQ0 rootwait root=/dev/mmcblk0p5这些参数确保:
- 早期控制台输出可用,便于调试
- 使用正确的根文件系统分区
- 避免因显示问题导致系统挂起
4.3 修改DRM驱动参数
在buildroot的kernel配置中,确保以下选项已启用:
CONFIG_DRM_ROCKCHIP=y CONFIG_ROCKCHIP_VOP2=y CONFIG_DRM_DW_HDMI_ROCKCHIP=y CONFIG_DRM_DW_HDMI=y同时,可以添加以下内核启动参数来调整DRM行为:
drm.debug=0x0F drm_kms_helper.edid_firmware=edid/1280x720.bin这个配置:
- 启用详细的DRM调试输出
- 指定一个备用的EDID固件文件,当物理EDID读取失败时使用
4.4 编译并更新系统
完成上述修改后,需要重新编译内核和buildroot系统:
make linux-rebuild make然后将生成的镜像烧写到开发板。建议使用rockchip提供的升级工具进行烧写:
sudo rkdeveloptool db rk356x_spl_loader_v1.08.111.bin sudo rkdeveloptool wl 0x0 buildroot/output/images/sdcard.img sudo rkdeveloptool rd5. 验证与测试
完成系统更新后,需要进行全面的显示功能测试:
- 连接HDMI显示器并上电
- 观察串口输出,确认没有
POST_BUF_EMPTY错误 - 检查
/sys/kernel/debug/dri/0/下的调试文件 - 使用modetest工具测试显示输出:
modetest -M rockchip -s 114@71:1280x720 -P 39@71:1280x720这个命令会:
- 使用Rockchip DRM驱动
- 在connector 114(HDMI)上设置1280x720模式
- 在plane 39上显示测试图案
如果一切正常,你应该能在HDMI显示器上看到彩条测试图案,同时系统日志中不再出现VOP2错误信息。
6. 常见问题与解决方法
在实际应用中,可能会遇到以下问题:
6.1 EDID仍然读取失败
如果EDID读取问题仍然存在,可以尝试:
- 检查HDMI物理连接是否良好
- 使用示波器检查HDMI DDC线路的I2C信号
- 在内核中添加EDID强制模式:
&hdmi { forced-output = "1280x720p-60"; };6.2 显示闪烁或不同步
出现显示异常时,可以:
- 检查VOP2的时钟配置是否正确
- 调整像素时钟相位:
&vop { rockchip,grf = <&grf>; rockchip,vop-grf = <&vop_grf>; rockchip,pmu = <&pmu>; rockchip,cru = <&cru>; assigned-clocks = <&cru DCLK_VOP0>, <&cru DCLK_VOP1>; assigned-clock-rates = <74250000>, <148500000>; };6.3 多显示配置问题
如果需要同时使用多个显示接口,需要特别注意:
- 确保每个视频端口(vp)分配了独立的时钟和资源
- 正确配置显示合成器(Cluster/WIN/Area)
- 在设备树中明确定义各显示接口的优先级
7. 性能优化建议
在解决基本显示问题后,可以考虑以下优化措施:
- 启用DRM原子模式设置:
CONFIG_DRM_ATOMIC=y- 调整VOP2的带宽分配:
&vop { rockchip,default-max-bw = <2500000>; };- 启用DRM的帧缓冲区压缩(FBC):
CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM=y- 优化DRM内存管理:
CONFIG_DRM_ROCKCHIP_MMU=y CONFIG_DRM_ROCKCHIP_VIDEO_FRAMEBUFFER=y这些优化可以显著提升显示性能,特别是在高分辨率或高刷新率场景下。