尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

i.MX8MQ平台LT8619c HDMI转LVDS驱动移植与Android显示适配实战

i.MX8MQ平台LT8619c HDMI转LVDS驱动移植与Android显示适配实战 1. 项目背景与LT8619c芯片定位最近在基于NXP i.MX8MQ平台做Android 10的BSP适配其中一个核心任务是把一颗HDMI转LVDS的桥接芯片——LT8619c的I2C驱动给移植上去。这活儿听起来就是改改设备树、调调驱动但真干起来里头的门道和坑一点不少。LT8619c这颗芯片在车载中控、工业显示这些领域用得挺多主要就是负责把主控SoC输出的HDMI信号转换成大屏需要的LVDS信号同时还能通过I2C总线进行色彩、分辨率、时序等一堆参数的精细配置。在Android系统里这块通常归到Display HAL层下面管驱动本身不复杂但让它在一个全新的硬件平台上稳定跑起来尤其是配合Android复杂的显示框架就得把内核驱动、设备树、HAL层乃至Framework层的调用链路都捋顺了。我这次移植的目标平台是NXP的i.MX8MQCPU性能足够显示子系统也挺强大。但原厂BSP里默认的显示输出可能是MIPI-DSI或者直接是LVDS并没有LT8619c的现成配置。所以整个移植过程其实就是一场“牵线搭桥”的工作在内核里为这颗芯片准备好“座位”设备节点和“沟通方式”驱动并确保Android上层能通过标准的接口找到它、控制它。整个过程会涉及到Linux内核的I2C子系统、设备树Device Tree的编写、以及Android硬件抽象层HAL的适配。下面我就把这次移植中关键的步骤、遇到的坑以及最终的解决方案掰开揉碎了讲清楚。2. 内核层驱动移植从源码到设备树驱动移植的第一步肯定是搞定内核部分。LT8619c的驱动本质上是一个标准的I2C客户端client驱动。2.1 驱动源码获取与初步审查首先得找到驱动源码。通常芯片原厂比如龙迅半导体会提供一个Linux内核驱动模块可能是一个独立的.c文件加一个.h头文件或者是一个已经打好补丁的内核分支。我拿到的是一个名为lt8619c.c的驱动文件。拿到源码先别急着往里塞第一件事是通读一遍重点看几个地方驱动兼容性列表of_match_table这是驱动和设备树绑定的关键。代码里肯定会有一个struct of_device_id数组里面包含类似{ .compatible “lontium,lt8619c” }的条目。这个“lontium,lt8619c”字符串就是我们在设备树里要写的compatible属性必须一字不差。I2C设备ID表i2c_device_id用于非设备树纯靠i2c_board_info的旧式匹配现在基本以设备树为主但这个表通常也得有里面会有像{ “lt8619c”, 0 }这样的条目。Probe函数这是驱动的入口函数。要看清楚它在probe里都干了啥是不是注册了一个i2c_client有没有创建字符设备或者sysfs节点最关键的是它如何控制芯片是仅仅通过I2C读写寄存器还是需要操作额外的GPIO比如复位脚、使能脚电源管理有没有用到regulator稳压器suspend和resume函数里是怎么处理芯片状态的这对Android系统的休眠唤醒至关重要。我手里的这个驱动probe函数主要做了三件事解析设备树获取配置比如复位GPIO号、I2C从地址申请并控制复位GPIO最后通过I2C向LT8619c写入一系列初始化寄存器序列通常是一个长长的数组里面是{寄存器地址 值}对。这很典型。2.2 设备树DTS节点编写这是移植的核心环节也是最容易出错的地方。我们需要在i.MX8MQ的平台设备树文件比如imx8mq-evk.dts或你自定义的板级DTS文件里添加LT8619c的节点。首先要确定LT8619c挂载在哪个I2C总线上。i.MX8MQ有好几个I2C控制器I2C1, I2C2, I2C3…。需要查看硬件原理图确认LT8619c的I2C_SCL和I2C_SDA线连接到了SoC的哪两个引脚然后根据引脚复用关系找到对应的I2C总线。假设它接在I2C2上。其次要确定芯片的I2C从地址。LT8619c的地址通常由硬件引脚ADDR的上拉或下拉决定原理图上会标明常见的是0x647位地址。在设备树里reg属性就填这个地址。最后需要处理控制引脚主要是复位RESET和可能有的电源使能PWR_EN或中断INT引脚。这些引脚需要配置为GPIO功能。下面是一个设备树节点的示例我把它放在i2c2节点下i2c2 { clock-frequency 100000; // I2C总线速率100kHz通常够用 pinctrl-names default; pinctrl-0 pinctrl_i2c2; // 引用I2C2的引脚复用配置 status okay; lt8619c: lt8619c64 { compatible lontium,lt8619c; // 必须与驱动中的of_match_table一致 reg 0x64; // I2C从设备地址 pinctrl-names default; pinctrl-0 pinctrl_lt8619c; // 专门为LT8619c控制引脚定义的复用组 // 复位GPIO低电平有效 reset-gpios gpio1 12 GPIO_ACTIVE_LOW; // 电源使能GPIO高电平有效如果有 // enable-gpios gpio1 13 GPIO_ACTIVE_HIGH; // 供电稳压器引用如果有 // vcc-supply reg_3v3; // 芯片内部配置可能通过属性传递或在驱动里硬编码 lontium,input-format rgb; // 假设输入格式 lontium,output-format lvds; // 输出格式 lontium,data-lane-count 4; // LVDS数据通道数 // 显示时序参数这些有时会在驱动里计算但也可以在这里预定义 display-timings { native-mode timing0; timing0: timing0 { clock-frequency 74250000; // 像素时钟74.25MHz对应1080p60 hactive 1920; vactive 1080; hfront-porch 88; hsync-len 44; hback-porch 148; vfront-porch 4; vsync-len 5; vback-porch 36; hsync-active 1; // 高电平有效 vsync-active 1; // 高电平有效 de-active 1; // 数据使能高有效 pixelclk-active 0; // 像素时钟下降沿采样 }; }; }; };同时必须在引脚控制器pinctrl部分定义用到的GPIO。在iomuxc节点下添加pinctrl_lt8619c: lt8619cgrp { fsl,pins MX8MQ_IOMUXC_GPIO1_IO12_GPIO1_IO12 0x19 /* RESET */ // MX8MQ_IOMUXC_GPIO1_IO13_GPIO1_IO13 0x19 /* PWR_EN */ ; };这里的0x19是引脚配置字包含了上下拉、驱动强度、速率等需要参考i.MX8MQ的参考手册和现有板级DTS来设置不能乱写。注意设备树里的display-timings节点非常关键但它描述的是LT8619c输出给LCD屏的时序。而LT8619c输入的HDMI时序是由主控SoCi.MX8MQ的显示控制器如DCSS或LCDIF产生的。这两组时序必须匹配或者驱动能在芯片内部完成转换。通常我们更关注输出时序因为它直接关系到屏幕能否点亮。输入时序则在配置SoC的显示输出时设置。2.3 驱动集成与内核配置有了设备树接下来要把驱动源码集成到内核编译体系中。放置源码将lt8619c.c和lt8619c.h放到内核源码的合适目录比如drivers/gpu/drm/bridge/因为它是一个显示桥接芯片或者drivers/misc/。我选择放在drivers/gpu/drm/bridge/这更符合其功能分类。修改Kconfig在所在目录的Kconfig文件中添加配置选项。例如在drivers/gpu/drm/bridge/Kconfig里添加config DRM_LONTIUM_LT8619C tristate Lontium LT8619c HDMI to LVDS bridge depends on DRM I2C select DRM_KMS_HELPER select DRM_PANEL_BRIDGE help Driver for Lontium LT8619c HDMI to LVDS converter.修改Makefile在对应目录的Makefile中添加编译条目obj-$(CONFIG_DRM_LONTIUM_LT8619C) lt8619c.o配置内核执行make menuconfig在图形界面中找到Device Drivers - Graphics support - Display Interface Bridges - M Lontium LT8619c HDMI to LVDS bridge将其编译为模块M或直接内置*。建议先选M方便调试。编译内核和模块后将新的设备树Blob.dtb文件和驱动模块.ko文件烧录到设备。3. 系统启动与驱动加载调试烧录完新镜像上电启动这才是“实战”的开始。你需要通过串口控制台观察内核日志。3.1 检查设备树解析与Probe首先看驱动是否被正确匹配和加载。在串口日志中搜索“lt8619c”[ 2.345678] lt8619c 2-0064: probing LT8619c HDMI to LVDS bridge [ 2.345690] lt8619c 2-0064: Reset GPIO: 456 [ 2.345700] lt8619c 2-0064: Found initialization sequence, 120 entries [ 2.456789] lt8619c 2-0064: LT8619c initialized successfully.如果看到类似的成功信息恭喜你设备树匹配和驱动probe都成功了。2-0064表示I2C总线2适配器编号2从地址0x64。如果没看到可能的问题有兼容字符串不匹配检查设备树compatible属性和驱动of_match_table是否完全一致包括大小写和标点。I2C总线不对确认设备树节点放在了正确的i2cX节点下。可以用命令i2cdetect -l列出所有I2C适配器再用i2cdetect -y XX为适配器号扫描该总线看能否看到地址0x64的设备。引脚复用冲突检查pinctrl设置是否正确该引脚是否被其他功能占用。查看/sys/kernel/debug/pinctrl/pinctrl-handles或/sys/kernel/debug/gpio可以帮助诊断。驱动未编译确认内核配置已选中该驱动并已编译进镜像或模块已正确加载lsmod | grep lt8619c。3.2 I2C通信故障排查驱动probe时最常卡住的地方就是I2C读写初始化序列。如果日志停在“probing”之后没有成功消息或者直接报I2C通信错误就需要排查。硬件检查用示波器或逻辑分析仪抓取I2C总线的SCL和SDA波形是最直接的方法。看是否有起始信号、地址应答、数据波形。软件调试在驱动源码的probe函数开始和第一个I2C操作前添加dev_info或pr_debug打印确认执行流。可以临时修改驱动将初始化序列的长度减少到1-2条最简单的寄存器写入命令排除因某条特定命令导致芯片无应答的可能。检查I2C从地址。有时芯片的7位地址需要左移一位addr 1作为读写标志但标准Linux I2C驱动框架会处理这个通常设备树里写7位地址即可。但有些原厂驱动可能自己处理需要看驱动源码的具体实现。检查电源和复位时序。LT8619c可能对电源上电顺序和复位脉冲宽度有要求。确保在驱动probe之前芯片的供电包括核心电和IO电已经稳定并且复位引脚处于无效状态根据硬件设计可能是高电平或低电平。复位操作应该在供电稳定后进行I2C通信前完成。驱动里的复位逻辑通常是拉低复位脚 - 延时几毫秒- 拉高复位脚 - 延时几十毫秒等待芯片内部初始化。3.3 与Display框架的集成LT8619c作为一个显示桥接芯片在现代Linux DRMDirect Rendering Manager框架下它应该被注册为一个drm_bridge。检查驱动源码看它在probe的最后是否调用了drm_bridge_add或类似的函数。成功注册为bridge后它需要被连接到SoC的显示输出端口如HDMI TX或DP和LVDS面板或panel之间。这个连接关系也是在设备树中描述的。一个更完整的显示链路设备树可能像这样/ { ... lvds_panel: panel { compatible panel-lvds; // 假设的LVDS面板通用驱动 >
返回列表