MTK平台LT9611 MIPI DSI转HDMI驱动移植与调试全解析
2026/9/16 19:57:33 网站建设 项目流程

简介:面向联发科(MediaTek)平台的LT9611驱动开发资源,聚焦显示链路中DSI转HDMI的桥接方案,默认输出全高清画面,适用于嵌入式设备、智能电视或商用显示产品的驱动移植与底层调试。压缩包体积仅21KB,包含5个文件,其中3个为C语言驱动源文件,分别承担启动加载阶段与内核阶段的初始化及数据通路控制,另2个为DWS配置描述文件,用于板级引脚复用和显示参数编解码;源码与配置分离,便于在具体硬件上快速适配。结合标题中的stomachhcc来看,该驱动大概率针对特定硬件配置或项目定制,理解这一点有助于减少在相似平台间移植时的踩坑成本。目前已有964人学习,适合具备一定驱动基础、正在调试联发科显示输出或HDMI桥接方案的工程师参考。通过阅读源码和配置,可以掌握LT9611的寄存器初始化流程、DSI转HDMI的信号转换要点,以及将输出分辨率锁定为全高清的具体方法,为实际产品集成提供直接可用的基础代码与排错思路。

1. 一份 MTK 平台 LT9611 驱动源码能拆出多少东西

拿到mtk-lt9611_stomachhcc_lt9611_mtk这份源码包时,第一反应是它不是一个完整工程,而是一组散落在 LK、Kernel 和配置脚本里的关键文件:lt9611_dsi2hdmi.ccodegen.dwstb8735ap1_lr_ztk.dws。这意味着你面对的不是一份开箱即用的驱动,而是一个已经跑通过的方案切片,需要自己把它拼回目标工程里。LT9611 是 Lontium 的 MIPI DSI 转 HDMI 桥片,在 MTK 平台上常见于平板、车载或商显方案,默认输出 1080p。这里有个容易忽略的点:桥片驱动写得好不好,直接决定开机 Logo 是否闪烁、进系统后 HDMI 是否黑屏、以及dmesg里是否挂满hdmi_connector报错。源码包里出现lk路径,说明这套方案连 Preloader 之后的 LK 阶段都做了 HDMI 初始化——这是很多只改 Kernel 的移植方案最容易漏掉的一环。

我不会逐行贴源码,而是从「这份源码包到底想让你解决什么问题」出发,拆出四条线:LK 阶段初始化、Kernel 驱动框架、codegen.dws配置、以及调试手段。

2. LK 阶段:为什么开机 Logo 能不能显示取决于lt9611_dsi2hdmi.c

2.1 LK 里跑 HDMI 桥片的必要性

MTK 平台的显示链路是Display模块通过 DSI 输出,接到 LT9611 再转成 HDMI 信号给屏幕。在 LK(Little Kernel)阶段,bootloader 需要点亮屏幕显示开机 Logo,如果此时只初始化了 DSI 而没初始化 LT9611,HDMI 端就是黑的。源码包的lk目录下放着lt9611_dsi2hdmi.c,正是为了在 LK 阶段完成桥片的寄存器配置和视频参数协商。

阅读这份源码时,先看它的初始化入口。通常会有一个类似lt9611_dsi2hdmi_init的函数,内部做三件事:复位桥片、配置 I2C 通道、写 DSI 视频时序参数。代码结构大致如下:

static int lt9611_dsi2hdmi_init(void) { /* 复位桥片,等待电源稳定 */ lt9611_reset(); mdelay(20); /* 通过 I2C 读取 chip id 确认桥片在线 */ if (lt9611_read_reg(0x00) != 0x61) { printf("[LT9611] chip id mismatch\n"); return -1; } /* 配置 DSI 输出时序,1080p@60 对应 HFP=88, HBP=148, VFP=4, VBP=36 */ lt9611_set_timing(1920, 1080, 88, 148, 4, 36); /* 使能 HDMI 输出 */ lt9611_sys_power(1); return 0; }

这段代码里,lt9611_reset通常是拉 GPIO 控制复位引脚,复位时序要参考 LT9611 datasheet,一般是低电平保持至少 10ms 再拉高。lt9611_read_reg(0x00)读回的 chip id 可以用来确认 I2C 地址是否正确——LT9611 的 7-bit 地址常见为 0x3b 或 0x39,具体看硬件 design 时 SA0 引脚的高低电平。如果读不到正确 ID,大概率是 I2C 地址配错或者布线问题。

2.2 时序参数是怎么算出来的

1080p@60 的标准时序中,HFP(Horizontal Front Porch)是 88,HBP(Horizontal Back Porch)是 148,VFP(Vertical Front Porch)是 4,VBP(Vertical Back Porch)是 36。但 LK 阶段真正生效的是 DSI 的HSAHBPHACT等参数,它们需要根据dbidpi接口类型换算。MTK LK 的 display 驱动里常见写法是直接查表,源码包的tb8735ap1_lr_ztk.dws里就保存了这份面板参数。

注意 LK 阶段的 DSI 输出频率。LT9611 作为桥片,对 DSI clock 有上限要求,如果配置过高会导致画面雪花或直接无输出。我用 1080p@60 时,DSI clock 通常设在594–660MHz范围内,对应 4-lane MIPI。LK 阶段拿到的pll_clk值要配合clk_get_rate确认实际生效频率:

/* 从设备树或配置表获取 DSI PLL 频率 */ unsigned int dsi_clk = mtk_dsi_get_clk_rate(); printf("[LT9611] DSI clock: %u Hz\n", dsi_clk); /* 计算 lane 速率:bit clock / 4 lanes */ unsigned int lane_rate = dsi_clk / 4;

这里除以 4 是 4-lane 的配置。如果用的 3-lane 甚至 1-lane,要相应调整。很多 LK 阶段黑屏问题,最后定位都是 lane 数配少了,带宽不够。

3. Kernel 驱动:lt9611_dsi2hdmi.c的 DRM 接入与 I2C 通信

3.1 DRM bridge 驱动结构

Kernel 目录下的lt9611_dsi2hdmi.c是完整版的桥片驱动,基于 DRM(Direct Rendering Manager)框架的drm_bridge接口实现。它的核心逻辑是接收 DSI 数据流,转换成 HDMI 信号输出,同时处理 HDCP、EDID 读取、音频透传等。MTK 平台的显示栈是mtk_drm,LT9611 作为外置桥片,通过 I2C 与 SoC 通信,在 DRM 里注册成一个drm_bridge

先看驱动如何注册自身:

static const struct i2c_device_id lt9611_i2c_id[] = { { "lt9611", 0 }, { } }; static const struct of_device_id lt9611_of_match[] = { { .compatible = "lontium,lt9611" }, { } }; static struct i2c_driver lt9611_driver = { .driver = { .name = "lt9611", .of_match_table = lt9611_of_match, }, .probe = lt9611_probe, .id_table = lt9611_i2c_id, };

compatible字符串要和设备树里的节点匹配,常见写法是:

&i2c3 { lt9611@3b { compatible = "lontium,lt9611"; reg = <0x3b>; reset-gpio = <&pio 45 0>; interrupt-parent = <&pio>; interrupts = <46 IRQ_TYPE_EDGE_FALLING>; }; };

注意reg = <0x3b>是 8-bit 地址,而驱动里i2c传输时直接用这个值,和 LK 阶段用的 7-bit 地址要区分开——这是一个很常见的坑。芯片 datasheet 标注的地址通常是 7-bit,但设备树里写的是 8-bit(左移一位后的值),写错一个 bit 整个驱动 probe 不到设备。

3.2 probe 函数里做了什么

lt9611_probe不只注册 I2C 设备,它要做以下几件事:获取 GPIO 资源、复位桥片、初始化 I2C 通信、注册 DRM bridge、配置 HDMI 输出。

static int lt9611_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct lt9611 *lt = devm_kzalloc(&client->dev, sizeof(*lt), GFP_KERNEL); struct device_node *np = client->dev.of_node; int ret; lt->client = client; i2c_set_clientdata(client, lt); /* 解析 GPIO 资源 */ lt->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0); if (gpio_is_valid(lt->reset_gpio)) { ret = devm_gpio_request_one(&client->dev, lt->reset_gpio, GPIOF_OUT_INIT_LOW, "lt9611-reset"); } /* 复位流程:拉低 20ms,拉高 50ms */ gpio_set_value(lt->reset_gpio, 0); msleep(20); gpio_set_value(lt->reset_gpio, 1); msleep(50); /* 读取 chip id 验证通信 */ ret = lt9611_read_byte(lt, 0x00); if (ret != 0x61) { dev_err(&client->dev, "LT9611 chip id error: 0x%02x\n", ret); return -EPROBE_DEFER; } /* 注册 DRM bridge */ lt->bridge.funcs = &lt9611_bridge_funcs; lt->bridge.of_node = np; drm_bridge_add(&lt->bridge); return 0; }

这段代码里有个值得注意的细节:devm_gpio_request_oneGPIOF_OUT_INIT_LOW来申请并在 probe 时拉低复位脚,这是为了确保驱动加载时先让桥片处于复位态,后面再拉高。msleep(20)msleep(50)是两个关键延时参数——有些方案为了省时间把这两个延时缩短,结果 LT9611 上电后内部 PLL 还没锁死,驱动读 chip id 失败。如果遇到-EPROBE_DEFER,先查 I2C 地址是否正确,再查复位时序。

3.3 ATF 命令调试寄存器

Kernel 跑起来后,如果想确认 LT9611 的寄存器状态,最快的方式是用 ADB 通过 I2C 直接读写。MTK 平台/sys/bus/i2c/devices/目录下能看到设备:

adb shell cd /sys/bus/i2c/devices/3-003b cat name

如果name显示为lt9611,说明 probe 成功。接下来可以用i2ctransfer工具直接访问寄存器:

# 读 0x3b 设备 0x00 寄存器 i2ctransfer -y -f 3 w1@0x3b 0x00 r1

这里-y是跳过确认,-f是强制访问,w1@0x3b表示向地址 0x3b 写入 1 字节,0x00是寄存器地址,r1是读 1 字节。返回0x61说明通信正常,返回0xff或报错则要检查硬件连接。注意,如果设备树里节点挂在别的 I2C 总线上,把3换成实际的 bus 号。

4.codegen.dws里的 GPIO 复用与 I2C 总线分配

4.1dws文件在 MTK 平台的作用

codegen.dwstb8735ap1_lr_ztk.dws是 MTK 的 DWS(Device Wire Settings)文件,由MediaTek Configuration Tool生成,作用是配置 GPIO 复用、上下拉、驱动能力和 I2C 通道分配。LT9611 桥片的 I2C 引脚、复位 GPIO、中断 GPIO 都需要在.dws里先配置好,Kernel 的 pinctrl 子系统才能正确申请引脚。

打开codegen.dws,会看到类似下面的配置段落:

[GPIO_SETTING] ; 配置 GPIO45 为复位脚,默认输出低 GPIO45 = 0x001 ; 配置 GPIO46 为中断脚,带上拉 GPIO46 = 0x101 [I2C_SETTING] ; 将 I2C3 的 SDA/SCL 复用为功能引脚 I2C3_SDA = 0x011 I2C3_SCL = 0x011

这段配置的含义是:GPIO45 设置为模式 0(GPIO 模式),方向为输出且默认低电平;GPIO46 设置为输入、使能内部上拉;I2C3 的两个引脚复用为 I2C 功能。配置错一个引脚模式,轻则读不到设备,重则 GPIO 冲突导致其他外设异常。

4.2 修改.dws后如何生效

.dws文件改完后,需要用MediaTek Configuration Tool将其编译成对应的 header 文件,替换到 kernel 工程中。不同平台的编译产物不一样,MTK 平台上常见的做法是:

# 在 kernel 工程目录下 ./mk tb8735ap1_lr_ztk new # 或者只更新 dts 部分 ./mk tb8735ap1_lr_ztk kernel

有些平台需要先执行make clean再全编译,因为dws生成的cust_gpio_usage.hcust_i2c.h会作为头文件编译进内核,增量编译可能不识别修改。

注意 I2C 总线的选择。LT9611 挂在 I2C3 上时,.dws里如果同时还有其他 I2C 设备,要检查总线地址是否有冲突。常见问题是在dws里把 I2C3 配成了 500KHz 的高速模式,但 LT9611 在某些板卡上只能跑 100KHz——此时需要降速:

[I2C_SETTING] I2C3_SPEED = 100000

改完之后要确认 Kernel 的 dts 里clock-frequency也保持一致,否则驱动起来后 I2C 通信会偶发超时。

5. 实战验证:从编译到点亮的完整排查路径

5.1 LK 阶段验证视频链路

编译完 LK 和 Kernel 后,刷机进 Preloader 阶段,先看串口日志。LK 阶段打印的[LT9611]信息会直接暴露桥片初始化状态:

/* LK 阶段判断初始化是否成功 */ int lt9611_dsi2hdmi_init(void) { if (lt9611_chip_id_check() != 0) return -1; printf("[LT9611] init ok\n"); return 0; }

刷机后如果能看到[LT9611] init ok,但屏幕仍然黑屏,下一步就要量 HDMI 端是否有信号。用示波器量 HDMI 的 TMDS clock 引脚(Pin 16),如果有 148.5MHz 的时钟信号,说明桥片已经开始输出,问题大概率在 EDID 协商阶段。

此时在 Kernel 侧用cat /sys/class/drm/card0-HDMI-A-1/status看连接状态:

cat /sys/class/drm/card0-HDMI-A-1/status

返回connected说明 EDID 读到了,返回disconnected则停在 I2C 的 DDC 通道上。LT9611 的 DDC 引脚是独立的,它通过内部 I2C 转换到 HDMI 的 DDC 线,如果屏端 EDID 读取失败,需要检查 HDMI 座子的 HPD(Hot Plug Detect)引脚——用万用表量 HPD 是否被拉高,这是判断显示器是否在线的最快方式:

# 查看 HPD 中断是否触发 cat /proc/interrupts | grep lt9611

HPD 中断一直没有计数,说明桥片没有把 HPD 状态变化上报给 SoC,此时优先查 GPIO 中断配置。

5.2 分辨率参数与帧率抖动排查

进入系统后如果画面撕裂或帧率不稳,回到源码里查lt9611_set_video_mode函数的设定。LT9611 的0x10寄存器控制输出格式,常见配置是 RGB888 或 YCbCr444:

/* 配置视频格式为 RGB888 */ lt9611_write_reg(lt, 0x10, 0x80); /* 配置色深 24bit */ lt9611_write_reg(lt, 0x11, 0x00);

注意0x11寄存器的 bit 值在不同版本 SDK 里含义有差异,源码包里的lt9611_v1_3_MTK658_0628.c文件名里的v1_3就是桥片固件版本号,不同版本的固件对某些寄存器位的定义不一样。改参数前先确认当前桥片固件版本和源码对应关系:

/* 读取固件版本 */ int version = lt9611_read_reg(lt, 0x06); printf("LT9611 firmware v%d.%d\n", version >> 4, version & 0x0F);

如果版本号和源码注释不匹配,建议先跑桥片厂商提供的固件升级工具,再回来调驱动源码,否则会浪费很多时间在寄存器和实际行为对不上的排障上。最后提一个参数:LT9611 的数据通道 lane 映射可能不标准,如果输出画面出现「颜色偏色但不花」的情况,通常是0x05寄存器配置的 lane swap 顺序和硬件走线不一致,按实际 PCB 布线翻转映射即可。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询