☰
MT8788 Android 12 HDMI补丁:从DTS到HAL的完整修复指南
2026/10/20 12:23:42 网站建设 项目流程

简介:针对MT8788平台Android 12系统HDMI(IT66121)适配的kernel 4.19补丁包,面向嵌入式驱动开发与定制ROM维护工程师,用于解决HDMI显示输出、CEC/HDCP等功能集成与调试问题。资源以ZIP压缩包形式提供,共26个文件,包含15个.h头文件、9个.c源文件和2个Makefile,包体约81KB,结构精简,重点覆盖hdmi_drv/hdmitx_drv等主驱动框架,以及hdmicec、HDCP、it66121桥接芯片的IO与utility模块;头文件多用于寄存器定义与接口声明,C代码实现驱动核心流程,Makefile便于按模块编译或合入内核源码。目前已有481人学习/下载。可用于快速定位Android 12下HDMI无输出、CEC唤醒或HDCP认证异常等常见问题,也可作为MT8788平台驱动移植与二次开发的参考模板,省去从零梳理驱动框架的时间;其中sha1/mcu及sys/debug相关文件还能辅助验证加解密流程与调试输出,适合有一定BSP经验的工程师直接对照补丁改动。

1. mt8788 android12 HDMI patch:它到底是什么,解决了什么

一块 MT8788 平台的板子切到 Android 12 之后,插上 HDMI 最常见的结局是三种:屏幕永久黑着、拔掉再插第二次就认不出来、或者画面对着但声音永远停在喇叭那边。这不是硬件坏了,而是 Android 12 对显示、音频和 vendor 分区的要求都变了,老的 HDMI 相关驱动没有跟着适配。这份「mt8788 android12 HDMI patch」补丁包,就是把这条链路重新打通:内核 DTS 节点、HDMI 桥片驱动、HAL 设备枚举、AudioPolicy 路由和 init 服务,按 Android 12 的规则补了一遍。适合正在做 MT8788 板卡 Android 12 移植的 BSP 工程师,也适合接手上一个升级半途而废的项目、被 HDMI 报错卡住的人。

2. 补丁的来龙去脉:Android 12 对 HDMI 链路的三层要求

2.1 先确认 MT8788 方案的 HDMI 是怎么接出来的

MT8788 这颗 SoC 的大多数单板设计没有原生 HDMI PHY,HDMI 是靠显示控制器先出 MIPI DSI,再接一颗 DSI 转 HDMI 的桥片,桥片通过 I2C 被主控配置。所以这份补丁里真正决定 HDMI 生死的就是两个东西:桥片的驱动能不能被 probe,桥片的热插拔中断能不能正确上报给内核。跟全新 bringup 相比,Android 12 升级时最容易翻车的反而不是驱动代码本身,而是设备树里引脚和时钟的描述发生了变化。

内核升级后 DTS 最常见的兼容性问题有几个:pinctrl 的引脚功能描述从直接塞入宏变成了引用 pio 子节点;电源域的 regulator 名称变了,导致 bridge 的 avcc-supply 找不到对应的固定电压域;I2C 总线上的 clock-frequency 被新 dtsi 覆盖,桥片的 I2C 时序对不上。踩过这些坑之后,我拿到补丁的第一件事永远是先反编译当前固件里的 DTB,跟目标 DTS 做一次 diff,确认补丁不是把整个 dtsi 替换掉,而是只动了跟 HDMI 相关的节点。

具体做法是:

# 把 boot 分区里的 dtb 提出来反编译 adb root && sleep 2 adb shell dd if=/dev/block/by-name/boot of=/data/local/tmp/boot.img adb pull /data/local/tmp/boot.img # 解出 dtb 再反成 dts dtc -I dtb -O dts -o current.dts boot.img

这一步我一般会直接在板子上抓,因为仓库里的 dts 经常和实际烧进去的不一致,只有反编译出来的才是真身。补丁本身没带这套脚本也没关系,三分钟就能跑完,重点是把 diff 结果和补丁里 dts 的改动对应上,避免内核里其他外设节点被误改。如果 diff 里出现了跟 HDMI 无关的节点差异,要谨慎看待,那可能是补丁的基线分支和你的分支不一样。

2.2 Android 12 的分区约束把 HDMI HAL 逼进了 vendor

老平台通常在 system 或 product 里直接放私有 so 库,Android 12 把 system 分区只读这条规则执行得非常彻底,vendor 必须独立启动,所有供应商私有的 HAL、daemon、so 都要编进 vendor.img。HDMI 补丁里最常被忽略的部分就是 Android.bp 中的所有权声明。同一个源文件,如果编译目标还挂在 product 分区,最终表现是系统起来之后完全“看不见”HDMI。

我在一个平板项目里遇到过类似的事,logcat 里一点 HDMI 相关错误都没有,dumpsys display 也没有外接屏幕,最后发现 vendor/lib64/hw 下根本不存在 hdmi 对应的 so。原因是 HAL 的 vendor_available 没打开,链接器把库丢到了 product。这类问题往往不是一个补丁单独造成的,也可能是升级时把整个 vendor 目录换了路径。所以检查补丁时,我一般会把 Android.bp 里 proprietary、vendor_available、product_available 逐个过一遍,确认最终安装路径是 /vendor。

SELinux 也是一个大坑。Android 12 对 vendor 进程访问 sysfs 的限制比 11 更严,HDMI 状态是通过 sysfs 节点读的,补丁一般会在 sepolicy 里补一条 allow 规则,允许 vendor 的 hdmi 相关 domain 读写 sysfs class switch 或者 hdmi 专用节点。如果规则没进去,现象非常玄学:进程看起来活着,热插拔状态永远停留在第一次读到的值。所以我在验证时不只看功能,还会配 dmesg 把 avc denied 抓到,再反查是缺了哪一条 policy。

2.3 补丁包目录结构:拿到手先判断这 patch 完不完整

以常见 MT8788 平台的内核目录结构为例,一份我认可的补丁通常长成这样:

补丁根目录/ ├── kernel/ │ └── arch/arm64/boot/dts/ │ ├── mt8788.dtsi # 平台级差异 │ └── mt8788-xxx-hdmi.dts # 板级 hdmi 桥片配置 ├── device/ │ └── vendor_xxx/board_xxx/ │ ├── audio_policy_configuration.xml # HDMI 音频 sink 端口 │ ├── init.rc # hdmi 服务与属性 │ ├── sepolicy/ # hdmi 的 sepolicy 规则 │ └── overlay/frameworks/base/ │ └── res/values/config.xml # 显示设备枚举配置 ├── vendor/ │ └── mtk/proprietary/ │ ├── hdmi_hal/Android.bp # HAL 编译目标 │ ├── hdmi_hal/hdmi_hw.cpp # HAL 实现 │ └── modules/hdmi/ # 桥片驱动源码 └── README.md

一个在板子上真正跑得通的项目通常要同时覆盖三层。内核层只负责把 HDMI 桥片驱动起来;device 层是板级配置,负责音频策略、SELinux、init 服务和 overlay;vendor 层放 HAL 可执行部分。如果拿到的补丁只有一个目录,大概率是“半棵草”,后面要自己补。

还有一个容易被忽略的点,是 Android 12 的 GKI 内核趋势。如果厂商开启 GKI,hdmi 桥片驱动只能以 ko 模块方式放在 vendor_boot 里,补丁里就应该有 modules.load 或者对应 list 的改动。MT8788 老项目多数没开 GKI,但一旦目标版本要求 vendor_boot 单独分区,而补丁还是老的“编进内核”方式,HDMI 驱动永远不会被加载。拿到补丁先搜 vendor_boot 和 .ko 关键字,能省掉很多时间。

3. 核心模块拆解:一个 HDMI 热插拔事件从硬件到上层的完整链路

3.1 内核侧:DTS 节点和桥片驱动的加载

桥片的 dts 节点,是老式平台上 HDMI 补丁里改动量最大的地方:

&i2c1 { status = "okay"; clock-frequency = <400000>; hdmi_bridge: hdmi-bridge@48 { compatible = "vendor,dsi2hdmi"; reg = <0x48>; // 桥片 i2c 地址 reset-gpio = <&pio 45 GPIO_ACTIVE_LOW>; enable-gpio = <&pio 44 GPIO_ACTIVE_HIGH>; avcc-supply = <&reg_3v3>; // 模拟电源域 interrupt-parent = <&pio>; interrupts = <46 IRQ_TYPE_EDGE_RISING>; // hpd 检测脚 hdmi,audio = <1>; // 支持音频回传 status = "okay"; }; };

这段 dts 里值得解释的参数有几个。reg 是桥片的 7 位 I2C 地址,0x48 是常见地址,如果你的板子上桥片地址不一样(比如 0x3d),这里要跟着改,否则 i2c 扫描永远找不到,内核日志里会一直刷 no such client。reset-gpio 和 enable-gpio 配合完成复位时序,复位动作必须等 avcc-supply 稳定之后再拉低再拉高,很多上电顺序问题都出在这一步。interrupt-parent 指向 pio 后,interrupts 里的 46 是一个普通 GPIO 口,HDMI 插座的检测线就接在这里;GPIO_ACTIVE_LOW 和 GPIO_ACTIVE_HIGH 的定义必须和原理图一致,反了的话热插拔状态永远反相,上层每次都会拿到错误状态。hdmi,audio 是驱动私有属性,表示这个桥片支持音频回传,HAL 读到它才会去打开对应的 audio path。

除了 DTS,驱动里常见的错误是桥片 probe 之后立刻读 EDID,但此时 DSI 链路还没起来,读回的内容全是 0xFF 或者 0x00。补丁通常会把首次 EDID 读取推迟到主显示完成一次 commit 之后,用 delayed_work 来做。如果补丁里看到这一类改动,说明作者把上电时序处理过一遍,可以放心些。

3.2 HAL 侧:netlink 收到 UEvent,触发状态上报

内核只管把状态写到 sysfs,真正让上层感知到“我插了 HDMI”的是 HAL 里的 UEvent 监听。下面这段是这类 HAL 里最典型的一块逻辑:

static int hdmi_read_state() { char buf[8]; int fd = open("/sys/class/switch/hdmi/state", O_RDONLY); if (fd < 0) return 0; read(fd, buf, sizeof(buf) - 1); // 读 0 或 1 close(fd); return atoi(buf); } static void hdmi_uevent_listener() { int fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); char buf[1024]; while (1) { int len = recv(fd, buf, sizeof(buf), 0); if (strstr(buf, "hdmi/state")) { int state = hdmi_read_state(); hw_connect_display(HWC_DISPLAY_HDMI, state); } } }

HAL 通过 netlink 收内核的 uevent,收到与 hdmi/state 相关的事件后,再读一次 state 节点拿到最新值,调用 hw_connect_display 告诉 composer 外接屏幕连接状态。参数方面,HWC_DISPLAY_HDMI 是 composer 里约定的外接屏幕 ID,state 为 1 表示已连接,0 表示断开。

这里常见的问题是 socket 没加 SO_RCVBUFFORCE,内核事件一多就丢 uevent,表现是拔插一两次之后 HAL 就没反应。我在代码里一般会加 setsockopt 把接收缓冲区拉大到 128KB,这属于那种不写上板没感觉、写上空闲的人看半天的改动。另一个坑是 /sys/class/switch/hdmi/state 这个路径在 Android 12 对应的新内核上可能不存在,老 vendor 代码很少主动改,补丁实际做的事往往是把读取函数改成兼容两个路径:先读 /sys/class/switch/hdmi/state,没有就读 /sys/bus/i2c/devices/xxxx/hdmi_hpd。

3.3 框架侧:AudioPolicy 里补 HDMI sink 端口

画面之外,HDMI 的声音能不能出来,绕不开 audio policy 的配置。Android 12 的 audio policy 配置文件里,HDMI 作为一个 sink device 必须被显式枚举出来:

<module name="primary" halLibName="libaudiopolicymanager"> <devicePorts> <!-- HDMI 作为 audio sink 设备注册进来 --> <devicePort tagName="HDMI Out" type="AUDIO_DEVICE_OUT_HDMI" role="sink" address="hdmi"/> </devicePorts> <mixerPorts> <mixerPort name="hdmi output" role="source"/> </mixerPorts> <routes> <route type="mix"> <mixerPort name="hdmi output"/> <devicePort tagName="HDMI Out"/> </route> </routes> </module>

这段配置的核心作用是把 HDMI 注册成 audio output device,没有它 AudioFlinger 永远不认 HDMI。参数上,type 里的 AUDIO_DEVICE_OUT_HDMI 是固定枚举,不要手写成字符串,否则加载直接失败;address 是给 HAL 做声卡匹配用的别名;tagName 是上层客户端拿到的设备显示名。补丁实践里经常还需要在 device 的 config.xml overlay 里打开与 HDMI 相关的开关,比如 config_hdmi_audio,这些 flag 决定系统设置界面里会不会出现“HDMI 音频”选项。

Android 12 的 audio policy 跟 10/11 还有一个差别:HDMI 和 ARC/eARC 的设备枚举被分开,老补丁如果只注册了 AUDIO_DEVICE_OUT_HDMI,在支持 eARC 的主板上可能拿不到最高音频格式。做维护时我一般会看 dumpsys media.audio_flinger 的输出,确认 HDMI 相关 device 有没有被自动路由,没有就补上新枚举里对应的 arc 条目。

3.4 集成脚本:init.rc 里的服务启动和属性

配置补完,最后一步是把服务挂进 init。下面是这类补丁里一个比较规范的 init.rc 片段:

# 等待 bootanim 结束再拉 hdmi 服务,避免抢显示资源 on property:init.svc.bootanim=stopped start vendor.hdmi service vendor.hdmi /vendor/bin/hw/vendor.hdmi class vendor user system group system audio seclabel u:r:vendor_hdmi:s0 on property:vendor.hdmi.ready=1 setprop sys.hdmi.connected 1

这段 init 里有个不错的技巧是等 bootanim 结束再启动 hdmi 服务,避免跟 primary display 抢初始化资源。HAL 起来之后自己把 vendor.hdmi.ready 写 1,触发框架层广播 ACTION_HDMI_PLUG,上面的 setprop 就是干这个用的。参数上,seclabel 必须和 sepolicy 里定义的类型完全一致,写错一个字符 init 启动服务时就直接报错重启;user 和 group 视设备而定,但不给 audio 组的话,HAL 打开 ALSA 声卡那一步会 permission denied。

从 3.1 到 3.4,可以看到一条完整的链路:内核把状态写 sysfs,HAL 监听 uevent 后调 composer,audio policy 保证声音路由,init 负责把服务串起来。补丁缺了任何一环,表现都不会是“崩得很明显”,而是“看起来整个系统没有 HDMI”。

4. 实战排查:打上补丁后最容易翻车的 5 个场景

在讲具体坑之前,先把一套补丁从仓库到板子的落地顺序说清楚:内核补丁单独编 boot.img,device 和 vendor 的改动编 vendor.img 和 system.img,全部烧完再进系统。内核对不上分区、或者 SELinux contexts 没打进去,就会出现下面这些奇奇怪怪的现象。

4.1 现象 1:插上 HDMI 完全黑屏,串口里只有 edid read failed

原因:桥片驱动 probe 成功,但 DDC 通道没有上拉电源,或者 reset 时序没等 power rail 稳定。很多 DSI 转 HDMI 桥片的 DDC 引脚需要独立的收发供电,dts 里漏配了对应电源节点就会出现这个现象,而这类电源节点在旧版 DTS 里可能根本没有。

解决:先看 dmesg 里有没有 probe failed 之前的打印。如果驱动打印了 probe 成功,去查 pinctrl 的总线上拉和 DDC 电源;如果 probe 都没打印,去查节点 compatible 和 i2c 地址。我一般会在 dts 里临时给桥片加一个固定 3.3V 的 regulator,再一步步对比确认。注意不要上来就怀疑 EDID 缓存,先分清是“读不到”还是“读到的内容不对”。

4.2 现象 2:补丁打上之后系统起不来,串口卡在 service not found 一直重启

原因:init.rc 引用了不存在的 service,或者 seclabel 定义缺失。Android 12 的 init 对这类错误处理得比旧版严格,不会跳过去,而是直接重启。

解决:先把 init.rc 里 service 段临时注释掉,能起系统就说明是 init 配置问题。然后对比补丁里 sepolicy 目录下的 file_contexts 是否同步改了,确认 /vendor/bin/hw/vendor.hdmi 对应的安全上下文存在。补丁里带了 file_contexts 改动但 apply 时被漏掉,是这类现象里最高频的原因。

4.3 现象 3:能出图,但系统设置里的分辨率列表只有最低档

原因:EDID 解析完成后,display 的逻辑分辨率走的是 composer 的 mode 列表,老 HAL 用固定列表没跟 EDID 刷新;也有可能是 DSI 转 HDMI 桥片在主控看来是单条 DSI 的固定 timing,无法按 EDID 的 preferred timing 上报。

解决:先 dumpsys display 看 mode 列表是否包含目标分辨率。不包含就检查补丁有没有在 HAL 里动态构建 mode list。固定 timing 的方案下,常见做法是直接在 DTS 里把 virtual display 的分辨率改成面板原生分辨率,再在框架层做缩放。这里有个经验:别为了“看起来支持 4K”硬上 4K 时序,DSI 带宽不够时画面会有横纹,这类问题用仪器都不好抓。

4.4 现象 4:热插拔能识别,但声音永远输不出

原因:audio policy 里的 route 配了,但 mixer_paths.xml 没把 HDMI 声卡的 PCM 口接进去,或者声卡 index 在 Android 12 下发生了变化。

解决:cat /proc/asound/cards 确认 HDMI 声卡在不在,然后在 mixer_paths.xml 里添加对应 path 的 hdmi 控件。还有一个常见做法是 HAL 里写死声卡编号,但这种方案在 Android 12 的 USB 设备老插拔之后很容易错位,我一般改成按 device 类型查找声卡,而不是用固定 index。

4.5 现象 5:第一次插上识别正常,拔了再插就没反应

原因:uevent 监听 socket 缓冲不足丢事件,或者内核在拔掉时没有把 state 写回 0。前者是 HAL 侧问题,后者是内核驱动问题,两个都要排查。

解决:先按 3.2 的方法调整 socket 缓冲,再检查内核驱动拔插回调里有没有把 sysfs state 更新成 0。很多桥片驱动只在检测脚上升沿发一次中断,下降沿没处理,于是第二次插入内核本身就不感知。可以直接在 sysfs 里手动写值测试,如果内核层就看不出变化,那就不是 HAL 能管的事。

5. 二次开发:把补丁改成适合你自己那片主板的东西

5.1 先把板级参数抽出来

同一份补丁落到不同主板上,要改的往往不过五处。我习惯整理成一张参数表:

参数常见值修改位置
桥片 I2C 地址0x48 / 0x3dDTS 中桥片节点的 reg
热插拔检测 GPIOGPIO46DTS interrupts 编号
reset / enable GPIOGPIO45 / GPIO44DTS reset-gpio / enable-gpio
供电 railreg_3v3DTS 中 avcc-supply 的实际电压域
默认分辨率1080p@60HAL mode list 或 DTS 固定 timing

这个表的意义是把补丁和原理图对应起来。拿到新板子,先看原理图里桥片的 I2C 地址、检测脚、复位脚,再回填 DTS,千万别把整个 dtsi 照抄,否则两块主板之间显示输出会互相干扰,甚至你在这块板子上调好的参数,换一块板直接黑屏。

5.2 两个值得保留的验证习惯

一个是 apply 前的 dry-run:patch -p1 --dry-run < hdmi.patch。它能把所有 hunk 对不上的地方提前暴露出来,对不上的 hunk 我一般手动改行号再 apply,而不是用 --force 硬打,force 会静默丢内容,等到上板才发现少了关键片段。第二个习惯是上板后同时抓内核和框架两层证据:dmesg 抓 hdmi/dsi/bridge 关键字,再用 dumpsys display 确认外接显示器是否被枚举,这两条命令缺一条都可能让你把问题定位错层。

从那以后我每次接手 BSP 补丁,都强制走一遍“反编译 dts diff → patch dry-run → 上板抓 dmesg → 热插拔循环 20 次”这个顺序,补丁里的坑大部分都能在几分钟内浮出来。希望帮到你。

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

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

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

立即咨询