1. 先把 Porting 拆成两条线:整体设计与思路
高通平台上的 TP 和 LCD 驱动 Porting,说白了就是让一块陌生的屏幕亮起来、让一层陌生的触摸膜准起来。在手机、平板、POS 机、车机这类整机项目里,这两件事几乎永远绑在一起做:屏不亮,触摸没得调;触摸不准,屏亮了也没法验证。它要解决的从来不是“写一个驱动”,而是“把一块面板的所有电气特性、时序特性、协议特性,准确翻译成 SoC 显示控制器和输入子系统能理解的语言”。适合谁看?刚接手 bring up 的驱动工程师、从 MCU 平台转过来的嵌入式开发者,以及需要判断供应商给的东西到底靠不靠谱的硬件负责人。
我做过不少轮这种活,最深的体会是:绝大多数“点不亮”不是驱动代码写错了,而是 DTS 里某个参数和面板规格书没对上,或者上电时序早了几毫秒。所以这篇不打算讲内核框架大道理,重点放在“顺序怎么排、参数怎么算、坑长什么样”。
1.1 LCD 和 TP 为什么必须并行推进
很多新手会想着先把屏点亮,再搞触摸,线性推进。实际项目里这么干会卡住。原因很实在:LCD 的 reset、TE、供电这几路 GPIO 和 regulator,往往和 TP 的中断脚、复位脚共用同一组 PMIC 输出或者同一个 LDO 域;你调屏的时候如果不知道 TP 那一路有没有把电压拉低、有没有在中断脚上挂一个上拉,屏的时序就会莫名其妙地飘。
我遇到过一次,屏在冷启动时大概有 20% 概率白屏闪一下。查了两天,最后发现是 TP 驱动的 probe 里把共用的 1.8V LDO 关了一下又打开,屏的 DSI PHY 已经锁定了,供电塌陷导致 link 失步。这种问题只做单侧调试是发现不了的。
更合理的做法是把 bring up 分成三个可独立验证的里程碑:第一,屏能稳定出图且有正确的初始化画面;第二,TP 能上报原始坐标,且坐标范围和屏分辨率一致;第三,两者在休眠唤醒、亮度切换、快速开关机这些交叉场景下不互相干扰。这三个里程碑各自的验证手段不同,前两个可以并行,第三个必须两者都在。
并行还有个隐含好处:屏的 TE 信号是 TP 报点同步的重要参考。有些方案会拿 TE 做触摸扫描的同步源,减少显示噪声对触摸采样的干扰。你在屏还没调通的时候就把 TP 的 TE 通路预留好,后面就不会返工。
1.2 高通平台显示链路的软件分层与改动落点
高通平台的显示子系统这些年变化不小,但分层逻辑基本稳定。最底下是 DSI 控制器和 DSI PHY,往上是 DRM 框架下的msm驱动,再往上是面板抽象层(panel driver),最上面是 SurfaceFlinger 通过 HWC 提交图层。你要动的 90% 的内容在两处:设备树里的 panel 节点,以及 panel driver 里的初始化命令序列。
现在的平台把显示驱动做成了独立可加载模块,放在 vendor 分区里,跟主内核解耦。这意味着改完 panel 参数之后,你要重新打包的是 dlkm 或者 vendor_boot,而不是整个 boot.img,迭代速度会快很多。但反过来说,如果你只 push 了 dtbo 而没同步更新 vendor 侧的模块,就会出现“参数改了但没生效”的假象,白折腾半天。
一个判断改动是否落到正确位置的小技巧:开机后去看/sys/kernel/debug/dri/下面的节点,或者直接 dump DSI 的寄存器状态。panel 名字、当前帧率、lane 数这些信息能读出来,就说明你改的 DTS 节点确实被匹配到了。读不到,那就是 compatible 字符串写错、节点被 disable、或者 dtbo 根本没刷进去,跟驱动逻辑一点关系都没有。
1.3 触摸链路的落点与选型判断
触摸这边相对简单,本质是一个挂在 I2C 或者 SPI 上的外设驱动,注册进 Linux input 子系统。但选型上有几个点值得提前想清楚。
走 I2C 还是 SPI,取决于触摸 IC 的报点率和数据量。120Hz 报点、十点触控的常规方案,I2C 400kHz 或者 1MHz 基本够用;但如果对方号称 240Hz 甚至更高报点率,还带压力、面积、防水检测这些附加数据,I2C 的带宽会成为瓶颈,这时候 SPI 更稳。判断方法很土但有效:拿规格书里的单帧数据长度乘以报点率,算出来的字节数除以总线速率,占用率超过 50% 就该考虑换总线了。
另一个选型点是中断方式。边沿触发还是电平触发,取决于触摸 IC 的 INT 引脚行为。大多数方案是“有数据时拉低、主机读完释放”,这种适合下降沿触发。但如果 IC 在固件升级或者校准期间会持续拉低,边沿触发就会漏中断,得改成电平触发并配合轮询兜底。
还有个大坑是唤醒通路。现在的项目基本都要求息屏双击唤醒,这条路径要求触摸 IC 在主 SoC 休眠时保持低功耗扫描,检测到手势后拉高中断脚,把主控叫醒。高通平台在这块有一个手势唤醒的中间层,驱动需要按它的接口把“进入低功耗”“退出低功耗”“上报唤醒事件”这三件事注册进去,否则双击能亮但系统不知道是谁唤醒的,会出现亮屏后锁屏界面没解锁、或者唤醒源统计里看不到触摸的情况。
2. LCD 驱动 Porting 的核心细节与实操要点
2.1 点屏前的硬件确认清单
动手改代码之前,我一般会花半小时把硬件层面的事情核一遍,这半小时能省掉后面至少一天的抓瞎。清单不长,但每一项都必须有确定答案。
第一是供电域。面板通常要三路:IO 电压(1.8V 或 1.2V)、模拟电压(正压 VSP)、负压 VSN。AMOLED 还可能有 ELVDD/ELVSS。你要确认这三路的实际电压值、上电先后顺序、每一路到稳定需要多久。规格书里会画一条上电时序曲线,上面标着 T1、T2、T3 这些时间点,这些数值最终会变成 DTS 里的reset-sequence和驱动里的mdelay。
第二是复位和 TE。复位脚是低有效还是高有效、需要保持多久、释放后多久才能发第一条 DSI 命令。TE 信号在 command mode 面板上是必须的,用来告诉主机“我这边帧缓冲可以更新了”,如果 TE 没接或者接错脚,画面会撕裂或者卡住。
第三是 MIPI 走线。lane 数是 4 还是 3,有没有做 lane swap,时钟 lane 和数据的极性有没有反。这些在硬件上如果做错了,软件层面是有补救手段的(DTS 里有 lane 映射的配置),但前提是你得知道硬件上到底怎么接的。
| 检查项 | 典型值/常见坑 | 确认方式 |
|---|---|---|
| IO 供电 | 1.8V,容差 ±5% | 万用表实测空载和带载 |
| 模拟正压/负压 | 5.5V / -5.5V 一类 | 示波器看上升沿斜率 |
| 复位有效电平 | 多为低有效,保持 ≥10ms | 规格书时序图 |
| 复位释放到首条命令 | 常见 10~120ms | 规格书 + 实测 |
| TE 引脚 | 必须接到 SoC 的 TE 专用脚 | 查原理图 pinmux |
| lane 数 | 4 lane 居多,小屏可能 2 lane | 规格书 + 原理图 |
2.2 设备树里必须对齐的那几组参数
面板节点里参数几十个,但真正决定能不能点亮的就是那几组。分辨率、porch、脉冲宽度、帧率、lane 数、bpp,这六组对不上,后面全是白搭。
qcom,mdss-dsi-panel-width和height是有效像素区,这个一般不会错。真正容易错的是h-front-porch、h-back-porch、h-pulse-width和对应的 v 系列。这里有个非常经典的陷阱:不同面板厂对“back porch”的定义不一样,有的把 sync 宽度算进去,有的不算。高通的定义里,h-back-porch是不含h-pulse-width的。如果供应商给的 HBP 是含 sync 的值,你直接填进去,总行数就多了几个像素,pixel clock 跟着偏,表现出来就是帧率略低于标称,或者画面在特定刷新率下抖动。
我的做法是拿到参数后自己反算一遍 pixel clock,和规格书里给的典型值比。偏差在 1% 以内算正常,超过 3% 就说明双方对 porch 的理解不一致,得回去问清楚。这个反算过程后面第 4 章会详细写。
还有qcom,mdss-dsi-traffic-mode。burst mode 是突发传输,non-burst 是同步传输。绝大多数现代面板用 burst,因为省电。但如果你用的是较老的面板,或者调试阶段画面有明显的水平条纹干扰,可以试试切到 non-burst 排除问题。
2.3 command mode 与 video mode 的取舍
这两个模式的选择不是喜好问题,是面板特性决定的。
video mode 下,主机持续不断地往面板推流,面板自己有时序发生器,靠连续的数据流维持画面。好处是简单、不需要 TE、CPU 占用可预测。坏处是息屏显示(AOD)这类超低刷新场景很费劲,因为流不能停。
command mode 下,面板内部有帧缓冲,主机只在需要更新的时候发命令和像素数据,更新完就可以停。省电,天然支持局部刷新和 AOD。但必须有 TE 信号做同步,否则你不知道什么时候能写下一帧。
现在的手机屏基本都是 command mode 加 TE,因为要支持 LTPO 那种 1Hz 到 120Hz 的自适应刷新。做这种屏的 porting,TE 的配置是重点:qcom,mdss-dsi-te-pin-select、qcom,mdss-dsi-te-dcs-command、qcom,mdss-dsi-te-check-enable这几个属性必须和面板规格书里的 TE 行为一致。TE 极性搞反了,表现是画面完全不动,或者每次更新都卡住等不到信号——很多人第一次遇到会以为是 DSI 链路的问题,其实是 TE 没配对。
2.4 上电时序与命令序列怎么写
面板初始化命令序列是从供应商那里拿到的,通常是一大串十六进制。直接粘进去能用的概率大概七成,剩下三成会出问题,原因集中在三类:命令之间的延时不够、命令格式和当前平台的打包方式不一致、以及某些命令在特定电压下才有意义。
高通的 DTS 里,命令有两种写法:一种是把命令和参数混在一起写成数组,靠qcom,mdss-dsi-on-command-state标记这条序列在什么状态下发;另一种是用更结构化的格式,每条命令的参数长度单独标注。后者更啰嗦但排错容易,我一般优先用后者。
命令之间的延时是最容易被忽略的。供应商的初始化表里经常有“发完 0x11 之后 delay 120ms 再发 0x29”这种,很多人直接省掉,结果就是有的板子能亮有的不亮,因为屏内部电源还在爬升。凡是规格书里明确写了 delay 的,一个都不能省。
有个细节值得单独说:
reset-sequence这个属性是三步数组,形如高电平时间、低电平时间、再高电平时间。写反了会变成“上电瞬间复位”,屏根本不会响应。而且这个延时是毫秒级,不是微秒,写成 1 和 1000 效果天差地别。
另外,AMOLED 面板在低亮度下对 gamma 和 ELVSS 的配合很敏感,如果初始化序列里没有针对不同亮度档位做补偿,低亮度会出现明显的色偏或者“抹布屏”。这部分通常要供应商提供额外的命令,不能自己拍脑袋加。
2.5 背光与亮度曲线的调法
背光这块看起来简单,实际是最容易出用户投诉的地方。
首先要确认背光控制方式。DC 背光是通过 DSI 的 DCS 命令直接设亮度寄存器,PWM 背光是控制外部背光 IC 的 PWM 占空比。前者简单但低亮度下限受面板限制,后者灵活但需要额外占一路 PWM,且低频 PWM 有可见闪烁。
亮度曲线我一般不会直接用线性映射。人眼对亮度的感知是接近对数关系的,线性映射的结果就是“低亮度区间几乎没变化,高亮度区间跳变剧烈”。常规做法是准备一张 256 级的映射表,把 UI 层的 0~255 映射到面板实际能接受的最小值到最大值之间,并且在高亮度段做压缩,避免电池和发热压力。
低亮度还有一个隐藏问题:DC 调光在低亮度下因为电流很小,面板的一致性会变差,同一批次不同板子可能出现明显的亮度差异。这时候要么切到 PWM 调光,要么在工厂模式里做逐台校准,把校准值写进分区。这条如果前期不考虑,量产后返修率会很难看。
3. TP 驱动 Porting 的核心细节与实操要点
3.1 驱动骨架与设备树节点
触摸驱动的基本骨架就那几块:probe 里做电源上电、GPIO 初始化、中断注册、input 设备注册,然后读固件版本、做一次自检;中断里读报点数据、解析、上报;suspend/resume 里做低功耗切换。
设备树节点一般挂在对应的 I2C 控制器下面,reg是 IC 的从地址(常见 0x38、0x3E 这类),interrupt-parent指向 GPIO 控制器,interrupts里第一个数是 GPIO 编号,第二个是触发类型。这里最容易错的是触发类型编码,不同内核版本里的宏值不完全一样,填错了表现是中断进不来,或者进来一次之后再也不进。
vdd-supply和vcc_i2c-supply要分开写,虽然实际可能是同一个 LDO,但驱动里上电顺序不同——先 IO 后核心,或者反过来,取决于 IC 规格。写错顺序有些 IC 会直接锁死,必须断电重来。
还有个必须写的是坐标范围。touchscreen-size-x和touchscreen-size-y填的是触摸 IC 的原始坐标系分辨率,不是屏幕分辨率。这两个值经常不一致,比如触摸面板是 1080x2400 对应 IC 内部 1440x3200 的坐标系,就需要在驱动里做缩放。填错的后果是所有触摸位置整体偏移,或者边缘点报不出来。
3.2 中断处理与多点触摸协议 B 上报
Linux input 子系统的多点触摸有两套协议,A 协议是无状态全量上报,B 协议是带 slot 的增量上报。现在的触摸驱动基本都用 B 协议,因为内核能自动处理“某一指抬起但其他指不变”这种场景,驱动代码更清爽。
B 协议的核心是把每个触点绑定到一个 slot 上,上报时先input_mt_slot()指定槽位,再input_mt_report_slot_state()声明这一槽位是否有手指,最后上报 X、Y、压力、面积。所有点报完后调一次input_mt_sync_frame()做帧同步。
for (i = 0; i < point_cnt; i++) { input_mt_slot(ts->input_dev, i); input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true); input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x[i]); input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y[i]); input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, w[i]); input_report_abs(ts->input_dev, ABS_MT_PRESSURE, p[i]); } input_mt_sync_frame(ts->input_dev); input_sync(ts->input_dev);这段代码看着标准,实际有三个地方会翻车。
第一,slot 的分配策略。如果每一帧都从 0 开始重新编号,快速滑动时会看到光标跳来跳去,因为内核认为“0 号手指突然从这跳到那”。正确做法是维护一份上一帧的触点列表,按距离做匹配,让同一根手指尽量留在同一个 slot 上。
第二,input_sync的调用时机。有些驱动为了省事在中断里分多次上报,中间还调了 sync,结果上层收到一堆半帧数据,表现出来就是画线断断续续。
第三,中断里读 I2C 数据。I2C 读操作可能睡眠,而很多平台的中断上下文不允许睡眠,必须改成线程化中断或者用 workqueue。这个问题在调试阶段不一定暴露,压力测试一跑就炸。
3.3 坐标映射、边缘补偿与误触策略
坐标映射是最琐碎的一环。IC 报上来的原始坐标要经过三步:先按 DTS 里的范围缩放到屏幕分辨率,再根据屏幕安装方向做旋转或镜像,最后做边缘补偿。
旋转和镜像一定要在驱动里做,不要在 HAL 层做。因为从驱动到 HAL 中间还有一层输入事件的分发,如果在 HAL 做,某些系统级手势(比如从边缘滑入)拿到的坐标还是未旋转的,逻辑就乱了。
边缘补偿针对的是物理结构问题。触摸面板的边缘电极因为电场分布不均,报点会往内侧偏。补偿方式通常是给边缘区域一个非线性的增益,越靠近边缘增益越大。这个曲线要拿实际样机打点测出来,一般打 5x5 或者 7x7 的网格,记录每个点上报值和真实值的偏差,拟合一条补偿曲线。
误触策略分几类:手掌抑制靠面积阈值,握持抑制靠触摸点分布形态,口袋模式靠接近传感器配合。这些策略的实现位置各家不同,有的在 IC 固件里,有的在驱动里,有的在框架层。如果 IC 固件自带的抑制效果够用,就别在驱动里重复做,两层逻辑叠加往往会打出负优化。
3.4 手势唤醒与低功耗通路
双击唤醒这条链路涉及的面比较广,从触摸 IC 固件到驱动到内核到电源管理,任何一环断了都不工作。
驱动侧要做三件事:suspend 时不要彻底断掉 IC 的电,而是发命令让它进入低功耗手势模式;把中断脚配置成唤醒源,让它能在系统睡眠时把 CPU 叫醒;resume 时把 IC 切回正常模式并清掉唤醒状态。
static int tp_suspend(struct device *dev) { enable_irq_wake(ts->irq); tp_enter_gesture_mode(ts); return 0; }enable_irq_wake只是一半,还得在 DTS 的中断控制器节点上确认这个 GPIO 所在的 bank 支持唤醒。有些 bank 不支持,中断脚接错了 bank,双击唤醒就永远不生效,日志里也看不出来,只能靠示波器量中断脚有没有电平变化。
还有个常见问题是唤醒后第一帧触摸丢失。原因是 resume 时重新初始化 IC 需要时间,这段时间用户的手指已经在屏上了,但 IC 还没准备好上报。解决办法是 resume 完成后主动读一次 IC 的当前状态,把已有的触点补报上去。
3.5 固件升级与产线校准
固件升级不是量产才需要考虑的事,bring up 阶段就应该把通路打通。因为供应商给你的样片固件八成是旧的,有各种奇怪的 bug,升级到最新版能省掉很多误判。
升级通路一般是通过驱动的 sysfs 节点,往里面写固件文件,驱动分块下发。这里要注意的是升级期间必须屏蔽中断和上报,否则会出现“升级到一半系统还在处理触摸事件”的诡异状态。升级完要做一次软复位并重新读版本号校验。
产线校准主要是两件事:一是屏幕和触摸的坐标对齐,二是原始数据的基准校准。前者靠打点,后者靠无触摸时采集环境基准值。校准数据写进 IC 内部或者分区,开机时驱动读出来应用。校准如果漏做,表现是“同一批次有的机器边缘点不准,有的机器有幽灵触摸”。
4. 从零到联通的完整实操流程
4.1 分阶段 bring up 顺序
我把整个过程分成六个阶段,每个阶段都有明确的通过标准,不通过不往下走。
阶段一是电源和时钟。只上电、只给 DSI 控制器时钟,不发任何命令。通过标准是用示波器量到三路电压正确、复位时序正确、DSI 时钟输出正常。
阶段二是链路训练。发最少的初始化命令,把 DSI 链路拉到高速模式,读回一个能反映链路状态的寄存器。通过标准是读回值符合预期,链路没有报错。
阶段三是点亮。发完整初始化序列,出纯色画面。通过标准是红绿蓝白四个画面都正常,没有花屏、没有局部黑块。
阶段四是时序校准。改 porch 参数,观察不同刷新率下的表现。通过标准是标称帧率实测误差在 1% 以内,长时间运行不闪。
阶段五是触摸通。屏出图的同时触摸能上报坐标,且坐标和画面上的触点位置一致。
阶段六是交叉场景。休眠唤醒、亮度切换、快速开关机、边充电边触摸。
4.2 时序参数与 MIPI 速率的手算过程
拿一块 1080x2400、60Hz、4 lane、24bpp 的面板举例。规格书给的 porch 是:hfp=40、hbp=40、hpw=4、vfp=20、vbp=12、vpw=2。
先算总行数和总列数:
- h_total = 1080 + 40 + 40 + 4 = 1164
- v_total = 2400 + 20 + 12 + 2 = 2434
再算像素时钟:
- pclk = 1164 × 2434 × 60 ≈ 169,990,560 Hz,约 170 MHz
然后算每 lane 的比特率:
- bit_rate = pclk × bpp / lane 数 = 170e6 × 24 / 4 ≈ 1.02 Gbps
这个 1.02Gbps 就是 DSI PHY 需要跑到的速率。一般会留 5%~10% 余量,取 1.1Gbps 左右配置也不会出错,因为实际传输是按 DSI 的 HS 时钟走的,不是严格等于算出来的值。
如果规格书里给的典型 pclk 是 175MHz,而你算出来 170MHz,偏差 3%,那就得回去确认 porch 定义。常见情况是供应商的 hbp 里含了 hpw,你多算了一次。
| 参数 | 规格书值 | 计算值 | 判定 |
|---|---|---|---|
| h_total | 未给 | 1164 | 需与厂方对账 |
| v_total | 未给 | 2434 | 同上 |
| pclk | 175 MHz | 170 MHz | 偏差 3%,需确认 porch 定义 |
| lane 速率 | 1.05 Gbps | 1.02 Gbps | 在容差内 |
4.3 休眠唤醒联调
这一块是交叉问题最集中的地方,我一般按这个顺序排:
先单独测屏的休眠唤醒。息屏后按电源键,看亮屏是否正常,有没有闪一下。如果闪,多半是 panel 的 off 序列和 on 序列不对称,比如 on 里加了延时但 off 里没加,导致下次上电时屏内部状态没复位干净。
再单独测触摸的休眠唤醒。息屏后随便点一下,看是否能正常上报,不要求唤醒。如果点了没反应但亮屏后能正常用,说明 suspend 时 IC 断电了或者中断被 disable 了。
最后测双击唤醒。这里如果失败,按这个顺序查:IC 是否进了手势模式、中断脚是否有电平变化、中断控制器对应 bank 是否支持唤醒、唤醒后 resume 顺序是否正确。
有个很隐晦的问题:部分平台的电源管理框架会在系统进入深度睡眠时把 I2C 控制器也挂起。如果触摸 IC 在低功耗模式下还依赖 I2C 通信(比如要轮询状态),就会卡住。这时候要么改成纯中断驱动,要么把 I2C 控制器标记为可在睡眠中唤醒。
4.4 验证清单
点亮之后别急着交差,这份清单我每次都过一遍:
- 四种纯色画面各保持 5 分钟,无闪烁、无残影
- 灰阶渐变图无断层、无色带
- 标称帧率下连续播放视频 30 分钟,无掉帧、无撕裂
- 亮度从最低到最高扫一遍,无跳变、无闪烁
- 息屏唤醒 50 次,成功率 100%
- 双击唤醒 50 次,成功率不低于 95%(受限于手势识别算法本身)
- 十点同时触摸,坐标全部正确
- 边缘 5mm 内划线,无断点
- 边充电边触摸,无跳点
- 高温(45℃)和低温(-10℃)各跑一轮基础功能
5. 常见问题与排查技巧实录
5.1 显示侧问题速查表
| 现象 | 高概率原因 | 快速验证手段 |
|---|---|---|
| 完全黑屏,无背光 | 供电未上、复位时序错、DSI 链路未建立 | 量电压、量复位脚、看 dmesg 里 DSI 报错 |
| 有背光但无图像 | 初始化序列未发或发错、lane 映射错 | 抓 DSI 波形,确认有数据输出 |
| 花屏、彩色噪点 | lane 数配置错、lane 顺序错、速率不匹配 | 逐个 lane 试、降速率试 |
| 画面偏移或压缩 | porch 参数错、分辨率配错 | 对比计算 pclk 与规格书 |
| 局部黑块 | 面板排线接触不良、初始化命令里某条未生效 | 换板对比,单独重发该条命令 |
| 闪烁 | 帧率不稳、TE 配置错、背光 PWM 频率低 | 固定帧率试、改 PWM 频率试 |
| 撕裂 | command mode 下 TE 未启用或极性反 | 检查 TE 相关属性 |
5.2 触摸侧问题速查表
| 现象 | 高概率原因 | 快速验证手段 |
|---|---|---|
| 完全无触摸 | 中断未注册成功、I2C 通信失败、供电异常 | 读 IC ID 寄存器,看中断计数 |
| 能触摸但坐标全偏 | 坐标范围配置错、旋转未做 | 打印原始坐标对比 |
| 边缘点不准 | 未做边缘补偿、坐标缩放取整误差 | 打点测试,看偏差分布 |
| 跳点、断触 | 中断丢失、上报帧不完整、电源噪声 | 看中断计数与上报帧数是否一致 |
| 多点触摸只识别一个 | slot 分配逻辑错、协议用成 A 协议 | 检查上报代码 |
| 息屏后无法唤醒 | 中断脚唤醒未使能、IC 未进手势模式 | 量中断脚电平变化 |
| 充电时触摸异常 | 电源噪声、地线干扰 | 换充电器试、加滤波电容试 |
5.3 调试手段与日志抓取
显示侧最有用的是 DSI 的状态节点。开机后去 debugfs 下找 DSI 相关目录,能看到当前面板名、lane 数、当前时序参数、错误计数。错误计数非零基本就能定位到是链路问题还是面板问题。
另一个手段是把 panel 的初始化命令逐条打印。很多驱动支持在命令序列里插入打印,或者在 debug 节点里重放命令。当屏不亮时,逐条发命令并观察现象,能快速定位到是哪一条命令之后出的问题。
触摸侧主要靠三个数据:中断计数、上报帧数、I2C 错误数。这三个数在正常状态下应该大致成比例。中断远多于上报帧数,说明中断里有大量空读;上报帧数远少于中断数,说明解析逻辑有问题;I2C 错误数非零,说明总线有干扰或者时序不满足。
# 查看中断计数 cat /proc/interrupts | grep -i tp # 查看 input 设备信息 cat /proc/bus/input/devices # 实时查看触摸事件 getevent -l /dev/input/eventXgetevent这个工具在 bring up 阶段几乎是必备的。它能直接打印出每一个 input 事件,包括 ABS_MT 类型的原始值。当上层反馈“触摸不准”时,先用它确认驱动上报的值对不对,能立刻把问题范围缩小一半。
5.4 几个踩过的坑
有一次屏幕在实验室一切正常,到了产线小批量试产,有 5% 的机器开机白屏。查了很久,最后发现是某批次面板的复位释放时间比规格书标称的长,我们按标称值给了 10ms,实际需要 15ms。这种问题的特点是“同一版软件在不同板子上表现不同”,一旦遇到首先怀疑时序余量不够,把所有延时统一乘 1.5 再试。
还有一次触摸的幽灵报点,静态放置时会随机冒出单点触摸。用getevent看到上报的坐标每次都在同一个位置,说明不是噪声而是 IC 把某个固定电平当成了触摸。最后查出来是校准数据没做,IC 的基准值还是出厂默认,和环境不匹配。这类问题的特征是“坐标固定、不随手指移动”,和真正的干扰噪声(坐标随机)能区分开。
再有一个是关于休眠的。系统休眠后触摸偶尔无法唤醒,日志里能看到唤醒中断进来了,但 resume 流程走完触摸就死了。排查发现是 resume 里重新初始化 IC 的时候,I2C 总线的时钟还没恢复稳定,第一条命令发出去就 NAK 了。解决办法是在 resume 开始时加一个短延时,或者把 I2C 的恢复顺序调到前面。
我个人在实际操作中的体会是,TP 和 LCD 的 porting 有七成时间花在“确认信息”上,只有三成在写代码。规格书里的一句话、原理图上的一个脚、供应商邮件里的一个参数,往往就是卡住一整天的那颗钉子。所以与其急着改代码,不如在动手之前把硬件、时序、协议这三份材料对着实物核一遍,把不确定的地方全部标出来逐个问清楚。真正开始写的时候,你会发现代码量其实很小,难的是知道该填什么数。