
14.1 VBLANK同步机制VBLANK全称Vertical Blanking Interval说白了就是显示器从底部扫到顶部的那段“空闲时间”。为什么要有VBLANK因为CRT时代电子枪需要时间回到左上角。到了LCD时代这个机制保留了下来但作用变了——它成了我们更新帧缓冲区的安全窗口。核心原则永远在VBLANK期间更新帧缓冲区。否则你就是在“抢跑”画面撕裂是必然的。在MTK8678上VBLANK的配置主要涉及以下几个寄存器寄存器作用典型值DISP_VBLANK_STARTVBLANK起始行10801080p屏DISP_VBLANK_ENDVBLANK结束行1125DISP_VBLANK_INT中断触发位置VBLANK起始我个人习惯把VBLANK中断配置在起始位置这样有最充裕的时间做缓冲区切换。代码示例如下// MTK8678 VBLANK中断配置 void vblank_init(struct disp_device *dev) { // 设置VBLANK起始行 writel(dev-vactive, dev-base DISP_VBLANK_START); // 设置VBLANK结束行垂直总行数 writel(dev-vtotal, dev-base DISP_VBLANK_END); // 使能VBLANK中断 writel(1, dev-base DISP_VBLANK_INT_EN); // 注册中断处理函数 request_irq(dev-irq_vblank, vblank_handler, IRQF_SHARED, vblank, dev); } static irqreturn_t vblank_handler(int irq, void *data) { struct disp_device *dev data; // 清除中断标志 writel(1, dev-base DISP_VBLANK_CLR); // 触发帧缓冲区切换 if (dev-pending_switch) { switch_framebuffer(dev); dev-pending_switch false; } // 唤醒等待VBLANK的进程 wake_up(dev-vblank_wait); return IRQ_HANDLED; }小技巧VBLANK中断处理函数里不要做耗时操作。我曾经把图像处理逻辑放在里面结果导致中断延迟反而引发了更严重的撕裂。记住中断里只做标志位切换和唤醒真正的渲染工作交给其他线程。14.2 多屏帧同步多屏显示时最头疼的问题就是帧不同步。两个屏幕各自跑自己的VBLANK画面切换节奏不一致用户体验极差。MTK8678支持两种多屏同步模式主从模式Master-Slave一个屏幕做主时钟其他屏幕跟随。我推荐这种方式实现简单稳定性高。自由运行模式Free-Run各屏幕独立运行通过软件同步。嗯这个我踩过坑后面细说。主从模式的配置其实不复杂// 主屏配置 void master_screen_config(struct disp_device *master) { // 输出同步信号 writel(1, master-base DISP_SYNC_OUT_EN); // 设置同步信号极性 writel(DISP_SYNC_POLARITY_POS, master-base DISP_SYNC_POL); } // 从屏配置 void slave_screen_config(struct disp_device *slave) { // 接收外部同步信号 writel(1, slave-base DISP_SYNC_IN_EN); // 设置为从模式 writel(DISP_MODE_SLAVE, slave-base DISP_MODE_CTRL); }自由运行模式呢说白了就是各跑各的然后软件层面做对齐。我曾在某个项目中用过这种方式结果发现两个屏幕的帧率差了0.1Hz运行半小时后偏差累积到一帧以上。解决办法是每隔N帧做一次强制同步// 自由运行模式下的周期性同步 void free_run_sync(struct disp_device *devs[], int count) { static int frame_count 0; frame_count; // 每60帧做一次同步 if (frame_count 60) { frame_count 0; // 等待所有屏幕进入VBLANK for (int i 0; i count; i) { wait_event(devs[i]-vblank_wait, devs[i]-in_vblank); } // 同时触发缓冲区切换 for (int i 0; i count; i) { devs[i]-pending_switch true; } } }注意自由运行模式下如果两个屏幕的刷新率差异较大比如一个60Hz一个30Hz强制同步可能会导致从屏丢帧。我曾经遇到过这种情况最后不得不改成主从模式才解决。14.3 TETearing Effect信号处理TE信号说白了就是屏幕告诉驱动芯片“我现在可以安全更新数据了”。这个信号通常由显示面板的时序控制器TCON产生。MTK8678的DSI接口支持硬件TE检测配置起来很方便// TE信号配置 void te_init(struct mipi_dsi_device *dsi) { // 使能TE检测 writel(1, dsi-base DSI_TE_EN); // 设置TE信号极性上升沿触发 writel(DSI_TE_POL_RISING, dsi-base DSI_TE_POL); // 设置TE超时时间防止TE信号丢失导致死等 writel(1000, dsi-base DSI_TE_TIMEOUT); // 1ms超时 } // 等待TE信号 int wait_for_te(struct mipi_dsi_device *dsi) { unsigned long timeout jiffies msecs_to_jiffies(5); while (!(readl(dsi-base DSI_TE_STATUS) DSI_TE_DETECTED)) { if (time_after(jiffies, timeout)) { pr_err(TE信号超时\n); return -ETIMEDOUT; } cpu_relax(); } // 清除TE状态 writel(DSI_TE_DETECTED, dsi-base DSI_TE_CLR); return 0; }这里有个关键点TE信号和VBLANK是什么关系说白了VBLANK是显示控制器层面的概念TE是面板层面的概念。VBLANK告诉驱动“控制器空闲了”TE告诉驱动“面板准备好了”。两者必须配合使用先等VBLANK确保控制器不在传输数据再等TE确保面板可以接收新数据最后更新帧缓冲区实战经验我在调试某款国产面板时发现它的TE信号有时会丢失。排查了半天原来是面板的TCON芯片有bug在低温环境下TE信号不稳定。解决办法是增加了TE超时重试机制超时后直接跳过TE等待用VBLANK作为后备同步信号。14.4 避坑指南做显示同步这么多年我总结了几条血泪教训不要迷信硬件同步硬件TE和VBLANK机制再完善也架不住驱动写得烂。我曾经见过一个项目硬件同步配置完全正确但驱动里在中断上下文做了内存分配导致中断延迟画面照样撕裂。多屏同步要考虑线缆延迟两个屏幕用不同长度的排线同步信号到达时间可能差几个微秒。我建议在硬件设计时就做等长布线否则软件上要加延迟补偿。TE超时处理要优雅不要一超时就panic。我习惯的做法是第一次超时重试第二次超时用VBLANK替代连续三次超时才报错。帧率匹配很重要多屏显示时尽量让所有屏幕的刷新率一致。如果实在不一致主屏选刷新率最高的那个从屏做帧率转换。最后说一句显示同步这东西理论看起来简单实际调试时各种妖魔鬼怪都会出现。我的建议是——先把单屏的VBLANK和TE调通再搞多屏同步。一步一个脚印稳扎稳打。好了这章的内容就到这里。下一章我们会讲MTK8678的显示内存管理包括DMA、带宽优化和内存压缩技术。到时候见