
拿到一块新板子点亮屏幕是第一步。做显示驱动这几年我见过太多人卡在这一步内核日志刷了几百行硬件工程师说时序没问题软件工程师说寄存器配置没问题屏幕就是黑着。其实大多数时候不是方案不行是手里的调试工具没用对。这篇是显示驱动系列的第5篇专门聊聊调试工具这件事。DRM/KMS框架、MIPI DSI接口、framebuffer链路这些概念如果你已经接触过那这篇正好帮你把工具链理顺让你在遇到“点不亮”“闪屏”“花屏”的时候心里有数、手里有活。1. 调试工具全景与选择思路1.1 先把问题分层软件链路和硬件链路显示驱动调试最忌讳一上来就抓着一根示波器探头到处戳。我的习惯是先分链路软件侧管的是驱动加载、设备树解析、DRM实体注册、framebuffer分配、显示时序参数配置硬件侧管的是时钟、电源、差分信号、上下电时序、面板初始化序列。这两条链路对应完全不同的工具和方法。软件链路的调试入口是内核日志和debugfs核心工具是modetest、kmscube这类用户态测试程序它们能告诉你内核认不认这块屏、能不能出图、合成器工作正不正常。硬件链路则是逻辑分析仪和示波器的地盘靠抓真实波形来判断MIPI信号质量、时钟频率和上电时序是否满足面板规格。先用软件工具缩小范围再用硬件工具精确收口是我一直推荐的做法——上来就上示波器反而容易在一堆波形里迷失方向。1.2 工具选择矩阵什么场景用什么工具调试目标首选工具辅助工具说明驱动加载状态dmesg / dev_dbgtrace-cmd定位probe失败、资源申请失败DRM实体状态debugfs下的dri/0modetest -c查看connector、crtc、encoder状态出图验证modetest色彩条kmscube / glmark2验证显示链路完整性MIPI初始化序列逻辑分析仪示波器检查LP/HS时序确认命令正确发出时序测量示波器频率计量clock lane频率、压摆率、T偏斜EDID与寄存器i2c-toolshexdump读屏参、读写panel寄存器工具不在多在于每一层都能找到合适的观察手段。后面我逐个展开讲用法和踩过的坑。2. 内核态排查体系先让内核“说清楚”2.1 dmesg日志的正确打开方式驱动加载失败第一件事永远是把dmesg从内核启动开始完整看一遍。有人习惯只看最后的几十行报错这其实不够因为很多问题是在probe过程中逐步积累的真正报错的地方往往是结果而不是原因。比如panel驱动probe失败前面的i2c读取失败日志才是根源后面那一串“probe of xxx failed with error -22”只是表象。我一般这样操作先用dmesg -c清空缓冲再触发一次驱动加载重新insmod或重启然后dmesg全量输出配合grep -iE drm|hdmi|dsi|panel|backlight过滤关键子系统的日志。如果内核开了动态打印dynamic_debug还可以用echo file drivers/gpu/drm/* p /sys/kernel/debug/dynamic_debug/control打开DRM子系统的所有调试打印。这比加printk重新编译效率高得多特别是在调试一个在客户现场才出现的问题时动态打印几乎是必杀技。注意dmesg -c在部分系统上可能权限受限建议用sudo dmesg -C或直接dmesg -w实时滚动观察。另外动态打印不要全局开p日志量会非常大按文件名或函数名精确控制是最好的。2.2 tracepoint事件级别的观测手段dmesg适合看“发生了什么”但要看“事件发生的时间顺序和依赖关系”tracepoint更合适。DRM子系统有几个很有用的tracepointdrm_vblank_event、drm_fence、drm_gem_object_create等。配合trace-cmd工具可以把一次屏幕点亮过程中所有关键内核事件按时间线拉出来这在排查“间歇性黑屏”“闪烁”这类问题时非常有效。实际操作先trace-cmd list | grep drm看一下当前内核支持哪些DRM的tracepoint然后trace-cmd record -e drm:* -e fence:* sleep 5录制5秒触发一次显示操作比如切换到彩色测试画面最后trace-cmd report查看事件序列。我遇到过的情况是vblank中断明显异常——事件间隔忽大忽小顺藤摸瓜才发现是clock配置和panel实际刷新率不匹配导致的。这种问题用dmesg根本不会报错只有tracepoint能把时序问题暴露出来。2.3 debugfs手伸进DRM内部debugfs是内核态排查里最灵活的部分DRM框架在/sys/kernel/debug/dri/0/下暴露了一堆很有用的节点。i915_display_info某些显卡驱动、connector_state、crtc_state这些节点能直接看到当前连接器状态、选择的分辨率、刷新率和色彩格式。最常用的组合拳是先cat /sys/kernel/debug/dri/0/state总览所有对象状态再针对性查看某个connector的详情。有一次调试一款MIPI屏内核日志显示connector status是“disconnected”但我用i2c工具明明能从panel读回EDID这说明问题在hotplug检测逻辑或GPIO配置上而不是屏本身没接好。没有debugfs的话这个判断过程会多绕很多弯路。debugfs还能做不少写操作比如强制设置connector状态、触发一次hpd事件等。这里提醒一句debugfs的写操作设计初衷是给开发者调试用的不是生产环境运维工具改完状态之后一定要确认是否需要恢复避免把现场搞得更乱。3. 用户态工具实战让画面转起来3.1 modetest简单直接出图验证modetest是libdrm自带的测试工具几乎每个做显示驱动的人都会用它。它最核心的两个用法modetest -c查看连接器和mode列表modetest -s connector:mode把画面切到指定分辨率的测试图案。测试图案包括纯色、渐变色和黑白相间的条纹能快速判断显示通道是否打通。具体操作示例# 列出所有连接器和可用mode modetest -c # 在id32的connector上以1080p60输出彩色测试图 modetest -s 32:1920x1080-60 # 用4个plane叠出一组测试图案验证合成器 modetest -P 1:1920x1080-60 -P 2:640x4801:1920x1080-60-P参数的格式是plane_id:crtc_id:宽x高叠加方式:输出分辨率注意不同平台对plane数量的支持不同叠加层数超出硬件能力会直接报错。常见报错是“No more planes available”这时候别再往上加层了实测先跑单plane基础测试确认链路通了再叠加测试。3.2 kmscube合成扫描全链路验证modetest停留在“静态画面”层面要验证GPU合成、缩放、旋转这些能力kmscube是更合适的工具。它是一个基于GEM和KMS的OpenGL示例程序源码量不大能跑旋转的立方体动画会持续向显示链路提交帧能同时验证原子提交、buffer管理和显示时序的稳定性。跑kmscube之前建议先确认编译时的依赖libgbm、libEGL、libGLESv2缺哪个装哪个。运行时常用参数# 全屏输出到默认连接器 kmscube # 指定connector和输出大小我在4K面板上遇到过默认分辨率不对的情况这样手动指定更可控 kmscube --connector 32 --mode 3840x2160 # 跑全屏刷新并限制帧率适合长时间稳定性测试 kmscube -f 60 -c 10003.3 igt-gpu-tools专业级校验igt-gpu-tools是intel-gpu-tools的继承者如今已支持多种GPU平台里面一堆kms_*测试用例覆盖了从基本出图到复杂的多plane场景。我的建议是别一股脑全跑一来耗时太长二来很多case需要特殊硬件条件。挑几个基础但关键的# 跑基础的frame buffer CRC校验能检测到画面内容是否被正确提交 sudo igt/kms_pipe_crc_basic --run-subtest pipe-A-crc-primary # 检查连接器的热插拔处理逻辑 sudo igt/kms_hotplug --run-subtest hotplug # 验证plane的alpha混合和缩放能力 sudo igt/kms_plane --run-subtest plane-alpha-coveringkms_pipe_crc_basic是我每次改完驱动必跑的它会计算画面每一帧的CRC值如果CRC不变化说明画面根本没刷新这是判断“驱动装了但实际没跑起来”的金标准。3.4 轻量组合拳fbset与直接写framebuffer有些老平台没有完整DRM支持用的是linux-fbdev框架这时候fbset和直接写/dev/fb0是快速验证手段# 查看当前分辨率、色深和虚拟屏信息 fbset -i # 全屏刷红色验证基本显示通路 dd if/dev/zero of/dev/fb0 bs1024 count100 # 清屏为白色0xFFFFFF填充每个像素 python3 -c import mmap, os, time fd os.open(/dev/fb0, os.O_RDWR) buf mmap.mmap(fd, 0, protmmap.PROT_WRITE) buf[:] b\xff\xff\xff * (len(buf) // 3) 这个方法虽然粗糙但在驱动probe阶段能快速区分“内核链路问题”还是“用户态合成问题”——framebuffer都写不进去别指望上层系统能正常工作能写进去但屏幕上没反应问题一般出在硬件时序或panel配置上这时候就该换逻辑分析仪上场了。4. 总线与时序测量让硬件“显形”4.1 i2c-tools与panel寄存器MIPI DSI的command模式下panel通常通过I2C或DDC通道暴露一个控制接口常见的是用来读EDID或操作寄存器。i2c-tools是linux下最顺手的I2C调试工具尤其在排查“内核识别不到panel型号”这种问题上它能帮你确认硬件层面I2C通信是否正常。# 扫描总线上的设备地址判断panel挂在哪个地址 i2cdetect -y 0 # 读取设备寄存器值比如尝试读取EDID的首256字节 i2cdump -y 0 0x50 # 手动写入寄存器修改panel的某一项配置亮度、对比度等 i2cset -y 0 0x48 0x01 0x23实际操作中i2cdetect扫不到设备绝大多数情况是地址不对或者I2C总线编号不对。用i2cdetect -l列出总线的物理映射关系确认设备树里reg属性指向的地址两者对应上再扫描。我踩过最隐蔽的一个坑是同一块panel在另一款开发板上地址是0x50换平台后变成了0x51原因是I2C地址引脚被拉到了不同电平不先查硬件直接跑工具自然什么也读不到。4.2 逻辑分析仪MIPI初始化序列的“录像机”MIPI DSI初始化序列包含大量vendor私有命令这些命令通过LP模式发送逻辑分析仪是验证它们是否按预期发出的最佳工具。采样率建议至少4倍于信号速率DSI的LP模式速率一般在10Mbps以下普通24MHz采样率的逻辑分析仪完全够用。但HS模式下数据率可能高达几百Mbps甚至上Gbps这个速率下逻辑分析仪基本无力应对只能靠示波器了。抓取示例在panel驱动的prepare或init回调里把初始化命令序列打印出来同时让逻辑分析仪挂在CLK和D0-3线上然后用bus analyzer软件解析出实际的MIPI包逐条对比。我遇到过一次初始化命令发错状态寄存器显示panel已经进入sleep out但实际画面全白用逻辑分析仪抓出来才发现有一条vendor command的payload被错误地翻转了字节序对照spec后修正配置就正常了。4.3 示波器时序与信号质量的最终裁判当软件逻辑都正确但屏依然不亮时问题往往藏在上电时序和信号质量里。示波器就是最后的真相来源。需要重点测量的内容电源轨纹波vci、vcc、vddi的纹波峰峰值要求一般不超过50mV参考具体panel规格书上电时序reset、电源、MIPI信号之间的先后顺序和间隔时间典型要求reset拉低至少10ms后再拉高随后等待120ms发起初始化命令clock lane频率直接量clock lane的差分信号频率配合panel的刷新率要求计算误差是否在容差范围内data lane的压摆率过慢的压摆率会导致眼图闭合表现为近距正常远距花屏示波器带宽要选信号速率5倍以上的测MIPI HS模式至少1GHz带宽不然测出来的波形完全不能作为判断依据。实际操作记得用差分探头单端探头测差分信号会把共模噪声混进来波形完全失真。4.4 像素时钟与QTIMING参数计算显示驱动里最容易出错也最容易被忽略的部分是各种时序参数。像素时钟的计算公式是pixel_clock h_total * v_total * refresh_rate 其中 h_total h_active h_front_porch h_sync_pulse h_back_porch v_total v_active v_front_porch v_sync_pulse v_back_porch比如1920x108060Hz典型的blanking参数是h_front_porch88h_sync_pulse44h_back_porch148v_front_porch4v_sync_pulse5v_back_porch36。那么h_total2200v_total1125pixel_clock2200112560148.5MHz。这些参数在设备树或驱动代码里填错一个画面可能整体偏移、闪烁或者直接黑屏。实操心得拿到一块新panel永远先照规格书的“recommended timing”填一遍不要凭经验猜。很多panel对blanking的敏感程度超乎想象尤其是一些特殊分辨率的车载屏稍微偏离规格书的参数就会出现条纹或滚动画面。5. 一次完整的“屏幕点不亮”排查实录5.1 现象与初步定位某次调试一款搭载了MIPI DSI接口LCD屏的嵌入式平台现象是背光能亮但屏幕全黑没有任何文字或图形输出。按我前面说的思路先不碰示波器从软件层层往下剥。第一步看dmesg驱动probe成功没有报错DRM设备注册正常。第二步用modetest -c查看connector状态结果非常关键——connector status是connectedmode列表里有panel支持的native resolution。这时候问题范围就已经缩小了内核链路基本没大问题要么是出图路径断了要么是面板初始化序列没生效。5.2 一步一步收网既然modetest能看到connector接下来直接跑modetest -s输出色彩条测试图。结果依然是黑屏。这就意味着问题大概率不在用户态合成而在内核初始化或者MIPI传输层。于是打开动态打印重点看panel驱动的初始化流程用echo file xxx-panel.c p dynamic_debug/control打开panel驱动的调试输出dmesg中能看到初始化命令序列每次发一个包但是看不到明显的报错。第三步接逻辑分析仪抓MIPI总线发现初始化命令的数量只有正常预期的一半。对照panel规格书发现我用的是从另一个项目拷贝的初始化序列模板里面缺少了实际panel型号要求的一条关键命令。补上这条命令后重新上电屏幕依然黑着但逻辑分析仪显示命令序列已经完整发出。第四步上示波器。看clock lane的波形频率符合预期。看data lane的信号质量压摆率正常眼图也够清晰。最后测量reset引脚的时序发现问题reset拉低时间只有约1ms而panel规格书要求至少10ms。硬件工程师改完reset的延迟重新上电屏幕亮了。5.3 这个案例教会我的事软件工具能在5分钟内排除80%的嫌疑硬件工具能在一分钟内定位剩余80%的问题中大部分。初始化序列不要跨平台直接拷贝不同panel厂商的vendor command差异极大必须以目标panel规格书为准。reset时序和上电时序这类看起来“硬件才能管”的问题软件也能通过查设备树的reset-gpios延迟属性、电源管理的on-off序列提前排查不必等到示波器上发现问题再回头改软件。6. 结尾一点私房经验回过头看显示驱动调试工具本身都不复杂麻烦的是怎么在正确的时间用正确的工具。我个人的体会是先把软件工具玩熟尤其是dmesg的过滤和动态打印、modetest的状态查看这两个用好了能解决一大半问题再慢慢熟悉硬件工具的节奏逻辑分析仪看MIPI命令示波器看信号质量都需要和硬件工程师配合才能发挥价值。最后分享一个小技巧每次调试前把面板规格书的关键时序参数和初始化序列单独摘录成一个文本文件标注好每一条命令的作用和预期值。现场调试时对照这个文件逐条检查能省下大量来回翻手册的时间。这个文件同样可以作为后续维护阶段的基准文档遇到面板启不来的时候先拿它做diff比重新排查要快得多。显示驱动这块熬过了最初的点亮阶段后面很多问题其实都变得有迹可循。