ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

MIPI转LVDS桥接芯片调试实战:从UEFI到Kernel显示链路全解析

MIPI转LVDS桥接芯片调试实战:从UEFI到Kernel显示链路全解析 做显示驱动调试的人大概率都遇到过这么个场景主控侧明明只给了MIPI DSI接口客户手里的屏偏偏是LVDS还是那种量已经跑开、成本压到不能再压的工业屏。硬件改版不可能换主控不现实唯一的出路就是在主控和屏幕之间加一颗MIPI转LVDS的桥接芯片。这个方案本身并不复杂难点在于“点亮”不等于“点亮”从UEFI固件阶段到Kernel驱动阶段每一步都要让面板保持输出一致、时序一致、寄存器一致否则就会出现UEFI阶段出字、Kernel阶段黑屏这种让人抓狂的问题。这篇文章是我在多个嵌入式平台上调试MIPI转LVDS桥片的实操记录覆盖Kernel侧DRM驱动配置、UEFI阶段固件初始化、信号测试方法以及我在现场踩过的各种坑。不管你是刚接触显示子系统的新手还是被lsmod和modetest搞得焦头烂额的老兵只要手里有MIPI转LVDS的方案这篇内容应该能帮你把定位问题的范围缩小一大半。1. 项目背景与桥接方案选型1.1 为什么非要用MIPI转LVDS现在的应用处理器几乎把RGB和BT.1120这类“古董”接口砍光了中低端SoC留给显示输出的通常只有MIPI DSI和eDP两条路。但工业设备、车载后装、医疗仪器这些领域里LVDS屏的存量依然巨大尤其是7寸到15.6寸的LCD面板很多厂商只出LVDS版本因为驱动板方案成熟、抗干扰能力好、还能低成本拉长到几十厘米。一边是只出MIPI的处理器一边是只有LVDS的面板桥接芯片就是中间那个翻译官。它接收MIPI DSI的高速串行数据通过内部寄存器配置好像素格式、时序参数和输出通道数再把RGB数据重新打包成LVDS差分信号输出给屏。这里有个关键认知桥接芯片不仅仅是电平转换它还得处理时钟、同步信号和像素排列所以它的初始化序列和寄存器配置直接决定屏幕能不能点出正确图像。我在实际项目里遇到过最典型的情况是某个客户从A平台切到B平台屏幕还是原来的LVDS屏。B平台只有MIPI DSI输出客户以为软件改改设备树就行结果发现屏要么不亮要么出现明显的颜色错误。这个问题的根源就是桥接芯片的数据通道映射和像素格式不匹配不是设备树里加一个compatible就能解决的。1.2 桥接芯片选型逻辑同样功能不同脾气市面上常见的MIPI转LVDS桥接芯片有几颗比如Lontium的LT8912B、TI的DS90UB系列、瑞盟的TC358775还有一些国产兼容型号。选型时不能只看手册上写的“4 Lane MIPI to Dual Link LVDS”还要看三件事第一最大支持的分辨率和像素时钟。有的桥片标称支持1080P60但实际在4K分辨率或者高频点下会发热严重时序裕量变小画面会有轻微水波纹。第二MIPI侧和LVDS侧的通道数是否匹配。如果屏是双通道LVDS比如WUXGA分辨率而桥片只支持单通道输出那就点不高分辨率屏。第三I2C地址和寄存器操作的复杂程度。LT8912B的I2C地址是可配置的最好根据原理图实际读取一遍否则后续驱动里地址写错调试一天都查不出来。另外要关注桥片有没有内置的MIPI DSI解析功能还是只是简易的RGB转LVDS。我之前碰到过一款桥片它虽然标称支持MIPI输入实际上是通过一个并行RGB接口加一颗外部MIPI接收器实现的这种方案在驱动配置上会多一层寄存器。选型时优先看厂商SDK里针对哪种SoC有现成的初始化例程这会省下大量时间。在Kernel侧Linux内核的DRM/MIPI DSI框架对多数主流桥片都已经有现成的driver比如lt8912b.c、tc358775.c这类驱动文件。如果你的芯片比较新内核里没有对应驱动那就只能参考类似的桥片驱动来改或者用“准standard”的I2C寄存器读写方式在panel驱动里硬初始化。后面我会再展开说哪种方式更适合量产。2. Kernel侧驱动调试实战2.1 设备树与DRM Bridge框架先把数据流理清在Linux系统里MIPI转LVDS桥片在DRM框架下通常扮演一个bridge角色。数据流的路径是SoC DSI Controller - DSI Bridge - LVDS Panel设备树绑定的顺序很有讲究。我在瑞芯微平台上的设备树片段大概是这样的dsi { status okay; rockchip,lane-rate 800; #address-cells 1; #size-cells 0; panel0 { compatible some-common-lvds-panel; reg 0; enable-gpios gpio3 RK_PA5 GPIO_ACTIVE_HIGH; pinctrl-names default; pinctrl-0 lcd_pwr_en; backlight backlight0; ports { #address-cells 0x1; #size-cells 0x0; port0 { reg 0; bridge_in: endpoint { remote-endpoint bridge_out; }; }; }; }; ports { #address-cells 0x1; #size-cells 0x0; port1 { reg 1; bridge_out: endpoint { remote-endpoint panel_in; }; }; }; };这里要特别留意panel节点和bridge节点的嘴唇位置。很多资料会把bridge写成一个独立的i2c device挂在i2c总线上然后通过video-interfaces指定endpoint。如果发生数据流顺序错位内核会报failed to find dsi bridge但屏幕不亮这个现象往往更隐蔽。我习惯的做法是先把代码里直接看一下probe流程。在lt8912b驱动中probe函数会先通过i2c读芯片ID再做drm_bridge_add。如果设备树里没有把bridge与dsi endpoint连起来即使i2c通信正常Kernel也不会去调用bridge的mode_set和enable接口。所以排查桥片相关问题时我第一件事是用modetest -c看有没有出现该连接的connector设备如果没有说明bridge没有正确附着到DSI链路上。2.2 时序参数配置与寄存器初始化把HS和LP搞清楚MIPI DSI在物理层上有两种模式HSHigh-Speed和LPLow-Power。HS模式用于传像素数据LP模式用于传命令。桥接芯片在与SoC通信时需要正确解析MIPI的LANE数和时钟频率。这里最容易出错的地方是“计算MIPI频率”。MIPI DSI的bit clock频率并不等于像素时钟。以一个7寸1024x600的LVDS屏为例像素时钟大约是51MHz如果使用3个DSI Lane每个lane的bit rate大约是bit_rate pixel_clock * bpp / lane_countbppbits per pixel在RGB888下是24所以bit_rate 51MHz * 24 / 3 408Mbps。但这只是理想值实际驱动里还要加上blanking开销同时MIPI规范里每个lane的速率上限与版本有关常见设定在200Mbps到2.0Gbps之间。设备树里的lane-rate或clk-lane-frequency就得按这个思路去设不是随便填一个数就行。还有一个常被忽略的参数是dsi,flags。不同桥片对MIPI数据中的BLLPblanking或low-power模式有着各自的偏好。例如有的桥片要求MIPI侧必须严格的non-burst mode with sync events如果SoC配置成了burst mode画面能显示但会出现随机闪烁或白条。这个不是驱动“写错”而是两边对MIPI时序协议的默认行为不同。寄存器初始化序列是另一个大坑。拿LT8912B举例它内部有数十个寄存器除了ID、复位、PLL设置之外还要配置MIPI lane数和LVDS输出格式。很多国产桥片的手册里给了一堆“初始值”但实际需要根据你的屏幕参数去改比如LVDS的映射格式VESA还是JEIDA、颜色深度是6bit还是8bit、LVDS通道数、像素时钟极性。改错一个映射格式屏幕不会不亮而是会显示“负片”或者明显偏色这个现象非常经典。2.3 点亮验证与常见加载问题Kernel侧把设备树和驱动都加载成功后验证方法其实很直接看dmesg看sysfs再看能不能跑起来一个UI帧。第一步确认桥片被正确枚举。在dmesg里应该能看到类似这样的输出lt8912b 3-0030: chip id: 0x2921 lt8912b 3-0030: lane count: 4如果看不到这类log先确认I2C地址和引脚复用再看reset引脚有没有拉高。很多硬件设计喜欢把桥片reset和屏幕power使能两个GPIO放在一起控制导致Kernel启动时reset还没释放i2c probe自然是失败的。第二步确认DRM设备树链路。在/sys/kernel/debug/dri/0/state里能看到所有connector的状态。如果只有eDP或者HDMI没有LVDS那说明bridge的-attach没有成功。这时候用drm_bridge_chain_mode_valid源码加一点调试打印能很快定位到是在哪个环节断的。第三步用modetest直接测试。这是我最常用的命令modetest -M rockchip -s 94:1024x60060这里的94是connector id需要从modetest -M rockchip -c查询。如果命令执行后屏幕能显示彩条或测试图案说明整条链路已经通了。但要注意modetest打的是纯DRM测试图案不涉及GPU合成和框架场景所以它亮不代表你的UI一定显示正常只是说明输出链路没问题。我在Kernel侧踩过最离谱的一个坑桥片驱动probe成功endpoint也正常但modetest一跑就黑屏。查了一天最后发现是reset GPIO在驱动remove时被拉低了而系统从U-Boot启动时正好reset过一次GPIO电平正好和驱动预期相反。这类问题靠示波器量GPIO最直接看完波形后再回设备树里改enable-active-high。3. UEFI阶段点亮流程与VBT配置3.1 UEFI显示初始化路径为什么固件点亮和系统点亮不一样很多做Kernel驱动的人会觉得系统能点亮的屏UEFI阶段不也应该自然点亮吗这个想法对内置eDP屏也许成立但对MIPI转LVDS桥片往往不成立。原因在于UEFI固件里通常没有完整的MIPI DSI驱动栈也没有DRM框架。它做显示初始化一般是直接操作芯片寄存器把显示控制器配置好再把framebuffer地址填进寄存器就完事。对应到Intel平台上这一块依赖Video BIOS TableVBT来定义面板时序、DDC通道、背光PWM参数等而对应到ARM平台更像是我们做的嵌入式UEFI阶段往往是直接在PlatformPI或BoardInit里通过I2C/GPIO操作桥片寄存器完成所谓的“编码点亮”。所以UEFI阶段的本质是绕过操作系统预先完成显示控制器的时序配置和桥片的初始化序列。如果你把这一步做对了Boot Logo就能正常显示并且从UEFI到Kernel的切换过程屏幕不会黑闪如果做错了Kernel驱动再次初始化桥片时可能出现两个阶段寄存器状态不一致表现为“UEFI下正常Kernel下花屏”或相反。UEFI阶段还有一个现实问题内存映射。UEFI会锁定内存bufferGOP驱动通过AllocatePages分了一块framebuffer而到了OS阶段这块内存会重新映射。如果固件中的显示控制器base address和Kernel驱动里读到的地址不一致图像就会错位或者撕裂。这跟桥片的MIPI转LVDS没什么关系但在梳理问题时很容易被混淆。3.2 在固件里塞一段桥片初始化代码的常见思路我们在实际项目里UEFI阶段初始化桥片一般走下面几步第一步看桥片的datasheet抄一份最小初始化序列。在驱动里写成一个函数指针数组每个元素包含寄存器地址和值最后统一写入。注意I2C总线上桥片地址不能和板上其他设备冲突而且写寄存器前通常要先软复位。第二步配置MIPI DSI控制器。不同SoC在UEFI下的寄存器命名不一样但核心思路是一致的设置lane数、设置时钟分频、配置hfp/hbp等时序参数使输出信号匹配桥片的期望。这一步如果参考的是System Reference Manual里“Panel Initialization”章节最清楚。第三步关闭或绕过UEFI自身的GOP设置改成手动输出。有的UEFI会默认调用Gop-Blt来显示Logo这需要EDID或VBT的支持。如果桥片无法提供EDID直接给GOP塞一个假EDID或者直接把LCD panel信息写死在VBT里会更省事。比较贪心的做法是在固件里定制一个UEFI Driver比如MipiLvdsDxe负责探测桥片、初始化它、把framebuffer地址写到显示控制器并提供GOP服务给Boot Manager。这样Windows的winload.efi也能正常用因为Windows在启动过程中只认UEFI的GOP不认具体的桥片驱动。这里有个细节值得强调给UEFI固件加显示驱动的复杂度和平台类型密切相关。x86平台通常有VBT和GOP这些成熟机制而ARM平台更多用U-Boot配合UEFI代码路径差异很大。在ARM上我更倾向在C代码里直接用mmio指针操作display controller而不是去套用Intel风格的GOP架构灵活度更高。3.3 GOP模式下验证要点如果UEFI阶段已经产生了GOP契约并且桥片正常点亮那么验证要看四件事屏幕是否持续显示同一帧内容。如果UEFI Logo能显示但不刷新可能是fbsize不对或者Display controller的plane层没有使能。这跟桥片无关但经常会和桥片初始化错误叠加。切换system time的时候显示是否短暂黑屏。UEFI和Kernel的驱动如果有两次初始化你会看到屏幕灭一下再亮。要消除这个现象最好的方式是让Kernel驱动在UEFI已经完成初始化的基础上做“增量配置”而不是直接drm_mode_set重置面板。在DRM框架下可以尝试复用固件已经设好的初始化序列实在做不到就接受一次轻微的闪烁。测试UEFI Shell下的displaymode是否识别正确分辨率。UEFI Shell里常用GOP测试脚本直接输出各种模式如果模式清单里没有你的LVDS分辨率说明GOP Edid或VBT data不完整。还要检查桥片两端的供电和复位时序是否满足桥片手册里的上电时间要求。很多桥片要求DVDD和AVDD先上再拉高Reset之后等一小段时间才可以访问I2C。UEFI驱动在早于这个时间访问I2C时可能返回超时进而导致初始化中断。我们在一个项目里遇到UEFI反复微亮的现象就是Reset释放到I2C初始化之间不足10ms在固件里加了一个Stall(10000)后彻底解决。4. 信号测试与硬件协作不要只盯软件4.1 示波器看MIPI和LVDS两套完全不同的差分世界我见过不少软件工程师屏幕点不亮就死磕设备树和寄存器最后发现是硬件问题。MIPI和LVDS信号在示波器上长得很不一样学会看波形能把问题范围缩小至少一半。MIPI DSI的HS模式是一个差分信号对摆幅通常在200mV-800mV之间共模电压略高于1V时钟频率在几十MHz到GHz级。在示波器上如果你把通道带宽设置为1GHz以上能看到清晰的差分摆幅和稳定的周期。如果幅度太低比如低于100mV很可能是signal integrity问题比如走线太长、阻抗不匹配、串联电阻过大。如果波形抖动明显还要检查SoC端的DSI时钟源配置和PLL锁定状态。LVDS则是另一种差分信号摆幅一般在250mV-450mV左右电流驱动型。它的共模电压在1.1V到1.3V之间和MIPI的HS模式共模电压不同但这并不意味着两种接口可以直接对接。反过来LVDS是一种相对“慢”的标准时钟频率通常低于100MHzMIPI则要高很多两者之间的转换不仅仅是“把电压抬一抬”还需要完整的协议重组。HCSLHost Clock Signal Level是另一个差分标准常见于PCIe时钟摆幅更低约为400-700mV峰值但驱动方式与LVDS不同。遇到有人问“能否用LVDS直接替代HCSL”答案基本是否定的除非你处理了偏置和接收端输入架构的差异。示波器上判断桥片是否正常工作我一般先测MIPI lane是否有连续的数据翻转再看LVDS输出端口是否有差分信号。如果MIPI有信号LVDS没输出说明桥片内部初始化序列有问题或芯片未运行如果LVDS有输出但屏幕不亮那就把测试点往后移看屏端连接器的信号是否正常。用示波器探头接触屏端连接器时记得用差分探头或者两个单端探头做减法否则看到的是噪声而非真实波形。4.2 寄存器读写与Pattern调试的妙用在复杂的桥片调试现场我推荐在UEFI阶段和Kernel阶段分别准备一个寄存器读写脚本。在Linux下可以用i2c-tools直接读例如i2cdetect -y 3 i2cget -y 3 0x30 0x0a i2cset -y 3 0x30 0x0a 0x01但很多桥片的寄存器并不是连续地址映射的比如LT8912B内部有bank的概念先写bank select寄存器再写offset。这种芯片在调试时特别容易把人绕晕我的经验是先画一张寄存器访问流程表把要改的寄存器按bank分组然后每次修改后都要读回确认写进去了。Pattern测试图案功能是很高级的调试手段。部分桥片打开内部pattern generator后不需要接收MIPI数据也能输出LVDS图案用来验证桥片到屏幕这一段是否正常。比如屏幕上如果出现红绿蓝三色竖条就可以确定LVDS信号链路和屏端逻辑都正常。此时如果pattern显示正常而主控数据注入后黑屏问题基本都在MIPI信号捕获或时序配置上。我经历过一个案例Linux驱动配置全部正常UEFI阶段也能出Logo但跑Android UI时屏幕会偶发性闪断。后来用pattern功能把问题定位到LVDS线缆过长导致的信号衰减跟驱动一点关系都没有。所以当驱动和寄存器都“看起来”正确时pattern测试能帮我们快速排除软件变量。5. 问题排查与避坑经验5.1 屏幕不亮、花屏、偏色的典型原因屏幕完全不亮是最常见也最容易排的。优先查上电时序、reset电平、背光使能这三个信号。在桥片方案里上电时序尤其重要很多桥片要求MIPI侧、LVDS侧和逻辑电源按特定顺序上电如果硬件上忽略了芯片可能进入I2C读写异常的状态。花屏的方向很多常见的有两种。一种是一条横向条纹看起来像画面撕裂这种通常是MIPI时序blanking参数没匹配上修改hback-porch或者de-active delay一般能解决。另一种是棋盘格状乱码更可能是lane number或者lane mapping配置错误比如SoC把数据放到了lane0而桥片认为数据在lane1。调这类问题用“逐个lane切换”的方式配合pattern能很快排查出来。偏色问题几乎都和像素格式或者LVDS映射有关。常见的组合是VESA和JEIDA两种映射。VESA映射是LVDS标准里最老的一种JEIDA更常用于新屏。同一根LVDS接口在两种映射下颜色顺序完全不同桥片会在初始化寄存器里告诉你它按哪种格式输出所以这里一定要和屏端datasheet对齐。RGB666和RGB888也会导致偏色尤其是低6位和高6位互换时屏幕会表现出明显的绿色或蓝色通道反转。Kernel驱动阶段还有一个经典问题系统在启动过程中出现unable to handle kernel null pointer dereference这类内核崩溃且堆栈指向bridge驱动。这种往往是在DT里漏了panel节点或者bridge没有拿到panel结构体就去访问modes。解决办法是检查设备树里remote-endpoint是否一一对应以及给驱动代码加上NULL保护。5.2 从UEFI切到Kernel的衔接问题UEFI阶段点亮后Kernel阶段无缝切换是产品体验的关键。这里最常见的坑是Kernel启动时没有重新初始化桥片导致UEFI阶段已经拉到高电平的reset引脚在Kernel驱动里被再次拉低又拉高这时如果没有PLL稳定时间屏幕就会闪一下。大多桥片在datasheet里规定了reset to PLL lock的最小时间例如10ms。在Kernel的bridge驱动enable回调里加一条msleep(20)就能解决大多数闪屏。另一个衔接问题是UEFI设定好的分辨率在Kernel里显示模式可能被覆盖。实际上Kernel在mode_set阶段会用EDID或者panel-fixed-mode来设置时序如果这个新时序和UEFI阶段配置的桥片寄存器不一致桥片会按新配置重新初始化这时屏幕必然会经历一次“黑屏重置”。要避免的话尽量保证Kernel使用与UEFI相同的时序同时在桥片驱动中支持“不重复初始化”的逻辑。比如在probe成功时读回芯片寄存器如果发现PLL已经lock且输出使能就直接跳过写初始化序列。5.3 其他几个容易被忽略的细节电源域和时钟域隔离问题。桥片工作异常时第一阶段测量它的PLL VCO电源和参考时钟是否正常。有的桥片需要独立参考晶振有的会复用SoC输出的clock。如果SoC的时钟输出未初始化桥片会表现为I2C通信正常但没有输出。I2C总线被挂死。我发现过一种搞笑的情况i2c detect能扫描到地址但一写寄存器就返回NACK后来查出来是屏幕排线的LVDS信号和I2C信号在拉长线时发生串扰导致总线上有持续的高频毛刺。解决办法是在桥片的I2C引脚上并联小电容减少串扰或者在硬件上把I2C走线和LVDS差分对拉开距离。热插拔问题。LVDS面板标准上是不支持热插拔的如果你在系统运行中插拔了排线桥片内部的ESD保护结构可能进入异常状态再次开机时它会表现为寄存器可以读写但输出永远无信号。处理这种情况最简单的方式是断电重启从设计上做HDMI热插拔检测并无意义。最后补充一点关于CPU占用和性能的观察。桥片本身不参与构图只做时序转换因此它的驱动不会对CPU和GPU造成明显负载但如果MIPI频率设置太低系统跑一个高刷新率动效时就可能出现卡顿。在调试阶段用perf top观察irq/softirq占比如果显示有大量DSI中断考虑软件层的数据传输效率和时序参数设置。这些细节看起来零碎但在实际项目中任何一个都足以让整机点亮失败。根据我个人经验调试顺序上优先级最高是硬件信号其次是电源时序再其次才是驱动和固件代码。只要这三个方向按序列排查MIPI转LVDS的“点不亮”问题基本都能在半天内有明确结论。希望这套从头到尾的实战记录能帮你缩短调试周期少走几段弯路。
返回列表