简介:面向联发科平台的LT9611芯片驱动源码与配置文件包,适用于嵌入式显示及驱动开发人员,解决在MTK方案上实现DSI转HDMI并默认输出1080p高清显示的问题。压缩包共5个文件,包含3个C语言源文件和2个dws工程配置文件,整体仅21KB,轻量精简。目前已有974人学习下载。除驱动源码外,还附带板级配置工程:C代码覆盖芯片的初始化流程、寄存器操作和视频时序,dws文件则提供硬件管脚与项目配置的适配入口,便于在驱动移植、编译调试时迅速定位问题,减少重复查阅寄存器手册的时间。这套资源对需要在MTK平台快速实现1080p HDMI输出的工程师有直接参考价值,适合具备一定C语言与显示驱动基础的开发人员,也可作为初次接触联发科显示子系统的入门参考,资源虽小但聚焦点明确,适合作为MTK显示驱动开发和调试的参考样例。
1. mtk-lt9611_stomachhcc_lt9611_mtk:先看懂这块板子的数据流向
第一次看到mtk-lt9611_stomachhcc_lt9611_mtk这个工程名,大概都能猜到:这是 MTK 平台主控搭了一颗 LT9611 桥接芯片的项目,stomachhcc是这块板子的内部代号,大概率是一台带 HDMI 输入或者 HDMI 输出的显示类设备,比如内窥镜主机、工业一体机或者医疗显示终端。核心矛盾不是主控性能,而是 MTK 的 MIPI DSI 显示通路和 HDMI 外部接口之间,隔着一颗 LT9611,数据流看似简单,实际调起来一堆时序、供电、休眠的坑。这篇文章面向正在调这块板子的驱动工程师、方案选型人员和产线支持,讲清楚桥接芯片在 MTK 平台上的角色、最小可用的初始化序列,以及最容易让人翻车的那几个边界条件。
2. LT9611 在 MTK 平台上的接线方式:I2C、复位与电源时序
2.1 先确认 LT9611 工作在哪个方向
LT9611 是一颗双向或者成对出现的高速桥接芯片,常见两种形态:MIPI DSI 转 HDMI 输出,以及 HDMI 输入转 MIPI CSI/DSI 给主控。lt9611_mtk这个写法通常意味着 LT9611 挂在 MTK 的显示输出侧,也就是把主控的 MIPI DSI 信号变成 HDMI 接到外部显示器;但也存在另一种接法,外部 HDMI 信号进到 LT9611,转成并口或者 MIPI 后给 MTK 做采集处理。调错方向是最尴尬的开局,因为两套初始化序列完全不一样,芯片虽然能 ACK,但寄存器配置一上就花屏。
拿到板子先做三件事:看原理图标注的数据流向,量 LT9611 的 I2C 地址线、复位引脚连接的主控 GPIO 编号,再开机抓一次 LT9611 的 chip id 寄存器。LT9611 的 chip id 一般能读到固定值,如果读回来是全 FF 或者全 00,说明 I2C 地址不对、芯片没上电,或者复位脚被主控一直按着。
我手上这颗板子规格是 MT6765 平台,也就是常说的 p22t 那一档,显示输出是 4-lane MIPI DSI,LT9611 挂在 I2C1 总线上。这种 MTK 平台配 LT9611 是典型的低成本显示桥接方案,主控负责跑系统和图像处理,桥接芯片只做协议转换,不参与渲染,所以调的时候只要把主控的 DSI 面板配置当成一块 "虚拟面板" 来写就行。
2.2 设备树里怎么挂 LT9611
MTK 平台一般不走标准 DRM bridge 驱动,很多方案直接在panel节点里把 LT9611 当成一块特殊面板,或者单独写一个i2c子设备驱动。先看设备树挂法:
&i2c1 { lt9611@3b { compatible = "lontium,lt9611"; reg = <0x3b>; reset-gpios = <&pio 42 0>; interrupt-parent = <&pio>; interrupts = <43 IRQ_TYPE_LEVEL_LOW>; pinctrl-names = "default", "sleep"; pinctrl-0 = <<9611_pins_default>; pinctrl-1 = <<9611_pins_sleep>; hpd-gpios = <&pio 44 GPIO_ACTIVE_HIGH>; status = "okay"; }; };最关键的三个字段是reg、reset-gpios和hpd-gpios。reg是 I2C 地址,LT9611 常见地址是 0x3b 或者 0x39,以板端原理图为准,不要照抄别人项目的地址;reset-gpios对应 LT9611 复位引脚,MTK 平台 GPIO 默认方向要确认,否则驱动 probe 时拉一下复位,芯片直接进入异常状态;hpd-gpios是 HDMI 热插拔检测脚,有些板子直接拉高不接主控,那就别在设备树里塞这个属性,否则中断一直触发。
还有一个容易忽略的是 pinctrl。MTK 平台的 I2C 引脚和 GPIO 复用关系在pinctrl里定义,如果sleep状态把 I2C 引脚切到 GPIO 模式,系统 suspend 后 LT9611 就彻底失联了,唤醒后驱动重试 I2C 也会失败。建议 sleep 状态保留 I2C 功能,只把复位脚改成输出低。
2.3 电源域和上电顺序:不是"给电就行"
LT9611 的供电通常有 VCC、VDDIO、AVDD 好几路,分别给数字核心、I2C 接口和高速收发器供电。MTK 平台用 PMIC 的 LDO 供电时,要注意 LDO 的上下电顺序。常见翻车现象是:冷启动 30% 概率读不到 I2C,重新触发一次软复位就恢复。这类问题大多是复位脉宽不够,或者 VDDIO 起来前主控已经访问 I2C。
我一般会在驱动里做强约束:先等 VCC 稳定,延时 10ms,再把复位脚拉高,再延时 5ms,然后才开始读 chip id。如果硬件上复位脚和主控 GPIO 之间有 RC 延时,驱动里的延时可以缩短,但不要图省事把延时删掉。另一个点是 VDDIO 的水平要和 MTK 平台的 I2C 电平匹配,常见是 1.8V,如果板端用了 3.3V 而主控 I2C 是 1.8V 域,就需要电平转换,否则读回来的寄存器值偶发错乱,排查起来非常玄学。
3. 跑通 LT9611 的初始化序列:从 I2C 裸写开始
3.1 最小验证集:不加载驱动先确认总线通
在 LT9611 起来之前,先把 I2C 总线摸一遍。MTK 平台允许在串口 console 里直接用i2ctransfer工具,这是调试桥接芯片的后悔药,比反复重编内核快得多。
#!/bin/bash # 手动探测 LT9611,确认 I2C 通路 # 假设总线是 i2c-1,地址是 0x3b,8-bit 地址是 0x76 # 读 chip id 寄存器,正常返回 0x96 开头的数据 BUS=1 ADDR=0x3b # 先探测设备是否存在 i2ctransfer -y $BUS w1@$ADDR 0x00 r1 # 如果上面返回数据,读版本寄存器并打印 value=$(i2ctransfer -y $BUS w1@$ADDR 0x00 r1) printf "LT9611 chip id: 0x%02x\n" 0x$value如果读不到,不要急着查硬件。先检查i2c-detect能不能枚举到设备,再确认内核是否已经加载了 LT9611 的驱动把总线占住。很多 MTK 方案会把 I2C 子系统的i2c-transfer报文日志关掉,可以在/proc/i2c或平台的自测节点里看有没有 NACK 计数。
3.2 标准初始化序列的三个阶段
LT9611 的初始化序列分成三段:系统配置、显示通路配置、输出配置。系统配置包括软复位、时钟源选择、中断使能;显示通路配置包括输入端口选择、DSI 输入 lane 数、像素格式;输出配置包括 HDMI 分辨率、TMDS 时钟、音频以及 HDCP。对应到 MTK 平台驱动里,一般会在probe时把整段序列写进去,但这容易把问题放大:一旦某次写入顺序不对,后续寄存器全错乱,而且很难定位是哪个寄存器导致花屏。
正确做法是把初始化序列拆成三个函数,每个函数对应一段,然后通过一个全局状态来标记当前走到哪一步。比如lt9611_system_init只做软复位、读版本、配时钟源;lt9611_video_init只在面板分辨率确定后才调用;lt9611_output_init放在 HDMI 插入中断里触发。这样热插拔时不用重新初始化整个芯片,只需要重配输出段。LT9611 支持在保持 DSI 输入不变的情况下,单独重新建立 HDMI 输出,这个特性在信号源切换场景里非常关键。
3.3 MIPI 参数必须和时序联动
MTK 平台的 DSI 输出侧有独立的时钟寄存器和 lane 数配置,LT9611 这侧要一致。我见过最经常的配置错误是主控配了 4-lane,LT9611 配了 2-lane,结果画面只有一半是正常的,另一半全是雪花。
# 计算 1080p60 RGB888 4-lane 的最低 lane rate h_active = 1920 hfp = 88 hbp = 148 hsync = 44 v_active = 1080 vfp = 4 vbp = 36 vsync = 5 fps = 60 htotal = h_active + hfp + hbp + hsync vtotal = v_active + vfp + vbp + vsync pixel_clock = htotal * vtotal * fps bpp = 24 lane_num = 4 lane_rate = pixel_clock * bpp / lane_num print("pixel clock: %.2f MHz" % (pixel_clock / 1e6)) print("minimum lane rate: %.2f Mbps" % (lane_rate / 1e6))这里算出来的 lane rate 是理论最低值,实际初始化要留 10%~20% 余量。LT9611 的 HDMI 侧输出时钟由输入像素时钟决定,如果输入的 lane rate 不够,TMDS 时钟会被芯片内部 PLL 强行提升,容易引入高频抖动,画面表现为水平方向轻微横纹。参数说明:hfp/hbp是水平前后肩,vfp/vbp是垂直前后肩,这些值必须从目标 HDMI 显示器的 EDID 或者设定好的时序表里抄,不能随意改。MTK 平台里这些参数分布在mtkfb的panel_params结构体中,LT9611 驱动侧只使用 htotal/vtotal 的乘积来计算 PLL 分频。
3.4 中断和热插拔处理
LT9611 的 HPD 脚在 HDMI 线插入时会产生中断。MTK 平台的写法一般是注册一个 GPIO 中断,在线插入时重新读取 EDID、再走一遍lt9611_output_init。要注意中断触发类型:有些板子 HPD 是低有效,有些是高有效,配错会导致系统一开机就疯狂触发中断,然后整机卡死。
我在平台驱动里加了中断防抖,延时 50ms 再读 HPD 状态,同时加了一个互斥锁,防止在dsi_panel的显示流尚未 ready 时 HDMI 中断进来造成竞态。实际量产中,热插拔异常多半出在同时切换分辨率那一瞬间,处理原则是:先让 LT9611 输出端静默,再切换输入侧时序,最后重新使能输出。
4. 时序表和像素时钟:把屏参填对才能看到开机 Logo
4.1 从屏规格书到 MTK panel_params 的映射
LT9611 不只是桥接信号,它还负责从输入的 DSI 信号里提取时序参数,并生成 HDMI 输出时序。一旦输入侧时序不标准,HDMI 接收端会直接拒收。所以 MTK 平台里那块 "虚拟面板" 的时序参数,必须按照实际的 HDMI 显示器或者接收芯片的 EDID 来填,而不是照着某个 LCD 屏的手册随便填。
| 分辨率 | H_ACTIVE | HFP | HBP | HSYNC | V_ACTIVE | VFP | VBP | VSYNC | Pixel Clock |
|---|---|---|---|---|---|---|---|---|---|
| 720p60 | 1280 | 110 | 220 | 40 | 720 | 5 | 20 | 5 | 74.25 MHz |
| 1080p60 | 1920 | 88 | 148 | 44 | 1080 | 4 | 36 | 5 | 148.50 MHz |
| 1080p50 | 1920 | 528 | 148 | 44 | 1080 | 4 | 36 | 5 | 148.50 MHz |
注意 1080p50 的 pixel clock 和 1080p60 一样,但水平消隐区更大,这是 HDMI 标准里的规定。MTK 平台如果按 1080p60 的时序去推 50Hz,会导致画面右侧有压缩感。LT9611 驱动里如果写了固定的 htotal/vtotal,它会把输入的时序直接透传到 HDMI,这时候不能靠驱动去改时序,只能回 MTK 的mtkfb里调。
4.2 用开机 Logo 验证时序对错
MTK 平台有一个天然优势:开机 Logo 阶段不加载完整 Android 显示栈,只用mtkfb的简单路径输出画面。调 LT9611 时,我建议把 Logo 当成第一道验证工具,不要急着进系统看桌面。
# 替换 MTK 平台的 logo 分区并整包烧录的常用流程 # 先把目标分辨率对应的 logo.bin 放到 release 包的 image 目录下 cp logo_1080.bin $MTK_SDK_PATH/out/target/product/p22t/logo/logo.bin # 重新打包 logo 分区镜像 ./build_ota.sh --include-logo # 用 mtk 的刷机工具把整包烧进板子 # 烧完后观察串口日志,确认 logo 阶段有没有 DSI 报错如果 Logo 能正常显示,说明 MTK 的 DSI 输出时序已经正确,LT9611 的输入侧也匹配。如果 Logo 花屏或者不出画面,先不要进系统,直接在 Logo 阶段就抓串口。
logo.bin的替换是个非常快的回归手段:每个分辨率准备一张专用测试图,比如纯红、纯绿、渐变色,然后把对应的logo.bin烧进去。以后每改一次时序参数,烧一次logo.bin再看一遍,十分钟就能确认新参数是否破坏显示通路。很多开发机上线后,OTA 升级logo.bin的需求也是从这里来的,产线上换面板型号时可以只换 logo 分区,不重烧整个系统。
4.3 在 MTKfb 里打时序日志
时序不对的另一个典型表现是:Logo 阶段正常,进系统后桌面边缘被裁剪。这通常是 LCD 驱动和 GPU 合成层的时序配置不一致。在lk阶段的显示配置和 kernel 的mtkfb配置存在两套参数,LT9611 作为外接桥接时,两套都要同步改。
我一般在mtkfb的panel_params初始化函数后面加一段打印:
// 打印当前使用的时序参数,确认模式和屏参一致 pr_info("lt9611 debug: hs=%d hbp=%d hfp=%d vs=%d vbp=%d vfp=%d fps=%d\n", panel->hsc, panel->hbp, panel->hfp, panel->vsc, panel->vbp, panel->vfp, panel->fps);这些打印在长期调试里价值很大。因为 MTK 平台多个项目共用一套 BSP,经常出现屏参在别的项目里被改动,编译出来时序跟着变,光看代码很难发现。在 lk 和 kernel 各打一条,对比两边的htotal*vtotal*fps是否一致,这是最快定位 "进系统后黑屏" 的方法。
5. LT9611 调试避坑专区:休眠、I2C 掉线、花屏与黑屏
5.1 冷启动概率性 I2C 读不到设备
现象:同一台机器,冷启动 100 次里大约有 20 次读不到 LT9611,正常运行中一切正常。
原因:LT9611 的复位时间不够,主控 I2C 在芯片未退出复位状态时发起访问,芯片不 ACK;外观上偶尔表现为芯片根本没有起来。
解决:在驱动 probe 开始时先保证复位时序正确,复位拉低后延时至少 20ms,再拉高,拉高后读 chip id。如果和 PMIC 的 LDO 使能顺序耦合,就把 LDO 使能提前。这类问题不建议靠重试 I2C 掩盖,因为重试会导致系统启动时间不稳定,产线测试会偶尔卡在开机阶段。
5.2 开机有 Logo,进系统后 HDMI 黑屏
现象:预加载阶段画面正常,安卓系统起来后就黑屏,串口没有报致命错误,LT9611 I2C 仍能正常访问。
原因:MTK 平台在进系统后,显示路径从lk切换到 kernel display,再到 SurfaceFlinger,显示时钟会被重新配置。LT9611 检测到 DSI 信号中断后,进入省电模式,但驱动的resume回调没有重新补偿视频通路。
解决:在mtkfb的dsi_enable回调里,把 LT9611 的视频通路重新初始化,不要只依赖 I2C 子系统的恢复。这个函数的调用时机一般在显示时钟稳定之后,用任务延后 100ms 执行再写寄存器,会比在回调里直接写更稳。
5.3 画面色彩发红/发绿,或者有规律横纹
现象:色彩的色温整体偏移,或者屏幕上有一条条水平干涉条纹。
原因:LT9611 输入的 DSI 数据格式和 MTK 输出格式不一致,例如平台输出 RGB888,而 LT9611 被配置成 YUV420;另一种可能是 lane rate 余量不够,TMDS 时钟在高速翻转时产生串扰。
解决:先确认panel_params里的data_format,然后在 LT9611 驱动寄存器里核对输入格式。参数表里常见的组合是RGB888_4_LANE_DDR和RGB888_4_LANE_SDR,不要混淆。MTK 平台里还遇到过摄像头驱动和显示驱动共用资源导致带宽挤压的情况,那属于MTK 相机插值和显示通路抢 DPI 时钟的问题,锅不在 LT9611,要调平台时钟分配。
5.4 休眠唤醒后 LT9611 配置丢失
现象:整机 suspend 再 resume,画面能回来,但热插拔失效,或者 HDMI 显示分辨率变成 640x480。
原因:MTK 平台在 suspend 阶段会把整条 DSI 显示链路的电源断掉,LT9611 内部寄存器在掉电后全部复位。唤醒时平台没有把初始化序列完整重放一遍,只恢复了 I2C 通信。
解决:把初始化序列做成一个幂等的整体,在 resume 里强制全量重写,而不是只恢复中断。可以顺手读一次chip id,确认芯片内核没连供电都断掉。部分平台还涉及 DRAM 自刷新:如果 DDR 进入自刷新以后显示控制器还挂着 DSI 访问,唤醒会卡死,需要保证先退出自刷新再初始化 LT9611,这个顺序在mtk_dsi的suspend/resume回调里要有明确依赖。
5.5 同一份代码在不同板卡上表现不一致
现象:软件版本不变,换一张主板后,画面出现轻微偏移或者没声音。
原因:LT9611 周边的晶振频率、I2C 上拉电阻阻值、HDMI 座子的 ESD 器件寄生电容都会影响高速信号质量。很多项目里硬件换料后,没有人同步更新软件里的tx_clk参数。
解决:每一批硬件变更,都要重新测量 LT9611 输入的 DSI 信号质量和 HDMI 输出信号的眼图。不要因为软件看起来正常就忽略硬件参数漂移。时序余量少的板子往往在温度升高后才暴露问题,表现为长时间播放后偶发闪屏。给每块新板子做一次 24 小时老化测试,比调一万行驱动代码都管用。
6. 进阶调试:寄存器快照对比和串口日志分级
LT9611 这类桥接芯片本质上是个黑匣子,驱动代码写得再完整,寄存器行为不验证照样踩坑。我最常用的手段是寄存器快照:在初始化前后各抓一份全寄存器 dump,然后做 diff。正常启动下只有几十个寄存器会变化,如果上百个寄存器都在跳,说明芯片处于异常状态,或者驱动里写了冲突的配置。
#!/bin/bash # 抓取 LT9611 全部寄存器快照,用于对比上电状态和驱动初始化后的状态 BUS=1 ADDR=0x3b for i in $(seq 0 255); do reg=$(printf '0x%02x' $i) val=$(i2ctransfer -y $BUS w1@$ADDR $reg r1) printf "%s: %s\n" $reg $val done > /tmp/lt9611_reg_before.txt把这份快照保存下来,每调一个功能就重新抓一次做 diff。比如 HDMI 热插拔失效,对比插拔前后 HPD 状态寄存器的变化,就能知道是芯片没收到信号,还是收到信号后没上报中断。这个习惯帮我省了大量反复重构驱动的时间。
串口日志也要分级。MTK 平台开CONFIG_MTK_FB_DEBUG前后日志量差很多,日常调试别开全量日志,否则海量重复信息会淹没有用的 DSI 时序报错。我一般只开lcm和dsi两个模块的调试打印,等到热插拔或休眠唤醒问题出现时,再临时开全量抓一次,抓到现场就立刻关掉。
对于 MTK OTA 升级logo.bin或整包升级后的回归测试,不要只在 Android 桌面确认显示正常,要在 lk 阶段、kernel 阶段、Android 显示服务起来三个阶段分别截屏。LT9611 桥接方案里,三个阶段的显示驱动配置可能由不同组件持有,任何一套配置不对,都会在后续阶段暴露问题。先跑通 lk 到 kernel 的显示迁移,再优化 HDMI 画质。
拿到 LT9611 这类项目,先别急着写驱动,花半天时间把 I2C 通路、复位、电源时序、HPD 中断四件事全部摸一遍再来写初始化序列,后面会顺畅得多。希望帮到你。
本文还有配套的精品资源,点击获取