RK3576 HDMI 引脚复用与驱动深度分析

📅 2026/7/3 7:50:57
RK3576 HDMI 引脚复用与驱动深度分析
记录一次将 HDMI CEC/SCL/SDA 引脚释放为 GPIO 的实战过程涉及 Rockchip 平台、Synopsys DW HDMI IP 驱动、设备树 pinctrl 覆盖以及 TMDS/FRL/DDC/EDID 等概念的梳理。一、问题背景硬件设计将 GPIO4_C0SoC 的 hdmi_tx_cec_m0 引脚用作 RK628 芯片的 reset 脚。内核启动时出现 GPIO 争抢错误[ 2.658605] rockchip-pinctrl pinctrl: pin gpio4-16 already requested by 27da0000.hdmi;cannot claim for 2-0050[ 2.658636] rockchip-pinctrl pinctrl: pin-144 (2-0050) status -22[ 2.658647] rockchip-pinctrl pinctrl: could not request pin 144 (gpio4-16) from grouprk628-reset on device rockchip-pinctrl根因** SoC 的 HDMI 驱动通过 pinctrl 占用了 GPIO4_C0CEC 功能rk628 驱动尝试将其用作 reset GPIO 时报 -EBUSY。此外硬件还希望将 DDC 引脚GPIO4_C2、GPIO4_C3也释放出来做普通 I2C。二、HDMI 四根引脚详解RK3576 的 HDMI TX 通过 hdmi_txm0_pins pinctrl 组复用以下引脚均在 GPIO4 bank| 引脚 | 编号 | Function | 协议角色 | 能否去掉 ||---|---|---|---|---|| GPIO4_C0 | pin-144 | hdmi_tx_cec_m0 | CEC消费电子控制 | ✅ 可以 || GPIO4_C1 | pin-145 | hdmi_tx_hpdin_m0 | HPD热插拔检测 | ❌ 建议保留 || GPIO4_C2 | pin-146 | hdmi_tx_scl | DDC SCLEDID I2C 时钟 | ✅ 可以 || GPIO4_C3 | pin-147 | hdmi_tx_sda | DDC SDAEDID I2C 数据 | ✅ 可以 |2.1 CEC — Consumer Electronics ControlCEC 是 HDMI 协议中的**可选**功能用于电视、机顶盒、功放等设备间的联动控制如打开电视时自动打开功放。在 Linux 驱动中// dw-hdmi-qp.c:4742 if (of_property_read_bool(np, cec-enable)) { hdmi-cec_enable true; irq platform_get_irq(pdev, 1); // 拿 CEC 中断 };// 不写 cec-enable → hdmi-cec_enable 保持 false// → dw_hdmi_qp_register_cec() 直接 return 0不注册设备结论没有 cec-enable 属性时CEC 功能完全静默——不注册平台设备、不申请中断、不占用任何软件资源。去掉 pinctrl 中的 CEC 引脚不会导致任何错误。2.2 HPD — Hot Plug DetectHPD 是 HDMI PHY 用来判断对端是否插入了显示器的**唯一硬件信号**。他的工作方式不是 GPIO 输入而是通过 pinctrl 将引脚的电平路由到 HDMI IP 内部的 IOC GRF 寄存器// dw_hdmi-rockchip.c:4400 dw_hdmi_rk3576_read_hpd() { regmap_read(hdmi-regmap, RK3576_IOC_HDMITX_HPD_STATUS, val); if (val RK3576_HDMITX_LEVEL_INT) return connector_status_connected; // 读到高电平 → 认为有设备 else return connector_status_disconnected; // 读到低电平 → 认为无设备 }HPD 在整个 HDMI 管线中的作用- **DRM connector detect** 决定是否上报已连接- **FRL 训练状态机** 训练过程中每 500μs 轮询一次HPD 为低则退出- **DDC 读写操作** 每次 I2C 传输前检查 HPD确保设备还在如果 HPD 一直为低- DRM 框架认为没有显示器 → 不启动视频管线 → **黑屏**- 可通过 force-output DT 属性绕过 DRM 层检查- 但 FRL 模式和 DDC 操作中仍会直接读 HPD 寄存器建议在 GPIO4_C1 上加一个 10KΩ 上拉电阻到 3.3V让 PHY 读到持续高电平。一毛钱成本零软件副作用。2.3 DDC / SCLSDA — Display Data ChannelDDC 是 HDMI 标准规定的一个 I2C 总线用来读显示器的 EDIDExtended Display Identification Data。EDID 是一个 128/256 字节的数据块描述了显示器支持的分辨率、刷新率、色彩空间、音频格式等能力。需要注意的是HDMI 的 DDC 不是用 SoC 的通用 I2C 控制器而是 **HDMI IP 内部的专用 I2C 控制器**。驱动通过操作 HDMI 寄存器来读写 EDID// dw-hdmi-qp.c — DDC 读 EDID 流程 dw_hdmi_connector_get_modes() → edid drm_get_edid(connector, hdmi-ddc); // hdmi-ddc 是内部注册的 i2c_adapter → drm_add_edid_modes(connector, edid); // 把 EDID 里的分辨率加进 mode list 没有 DDC 时驱动有兜底逻辑} else { hdmi-hdmi_data.sink_is_hdmi true; ret rockchip_drm_add_modes_noedid(connector); // 加标准分辨率1080p、720p 等 dev_info(hdmi-dev, failed to get edid\n); }结论去掉 DDC 不会报错驱动会用标准分辨率兜底。如果你的面板是固定分辨率这是完全可接受的权衡。三、TMDS vs FRL两代 HDMI 传输协议3.1 概念| | TMDS | FRL ||---|---|---|| 全称 | Transition Minimized Differential Signaling | Fixed Rate Link || 引入版本 | HDMI 1.0 ~ 2.0 | HDMI 2.1 || 最大带宽 | 18 Gbps | 48 Gbps || 支持的典型分辨率 | 4K60Hz、1440p144Hz | 8K60Hz、4K120Hz || 链路建立 | 无需协商直接驱动 | 需要源端和显示端握手训练 || 类比 | 国道通车就是通车 | 高速公路上之前要先取卡 |3.2 模式选择逻辑// dw_hdmi-rockchip.c:1112 if (!max_frl_rate || (tmdsclk HDMI20_MAX_RATE mode.clock HDMI20_MAX_RATE)) { hdmi-link_cfg.frl_mode false; // → TMDS } else { hdmi-link_cfg.frl_mode true; // → FRL }FRL 需要**同时满足**1. max_frl_rate ! 0 — 显示器通过 EDID 声明支持 FRL需要 DDC2. 像素时钟 ≥ 600MHz — 高分辨率/高刷新率场景多数嵌入式场景走 TMDS。** 低分辨率面板 无 DDC → 100% TMDS。FRL 训练状态机在 dw-hdmi-qp.c 中由 dw_hdmi_qp_flt_work() 驱动入口条件// dw-hdmi-qp.c:3813 if (link_cfg link_cfg-frl_mode) queue_work(hdmi-workqueue, hdmi-flt_work); // 只在 FRL 模式下触发TMDS 模式下dw_hdmi_qp_is_disabled() 永远不会被调用HPD 检查仅限于 DRM connector detect 层。四、驱动架构arch/arm64/boot/dts/rockchip/ ├── rk3576.dtsi ← HDMI 节点定义reg、中断、时钟、pinctrl-0 ├── rk3576-pinctrl.dtsi ← hdmi_txm0_pins、hdmi_tx_scl、hdmi_tx_sda 等 pinctrl 组 └── x1013.dts ← 你的板级 DTS在这里覆盖/添加属性 drivers/gpu/drm/ ├── bridge/synopsys/ │ ├── dw-hdmi-qp.c ← Synopsys DW HDMI QP 通用核心 │ ├── dw-hdmi-qp-cec.c ← CEC 子模块平台设备 │ └── dw-hdmi-qp-hdcp.c ← HDCP 子模块 └── rockchip/ └── dw_hdmi-rockchip.c ← Rockchip 胶水层GRF、时钟、pinctrl drivers/misc/rk628/ ├── rk628.c ← rk628 主驱动HDMI in → DSI out └── rk628_hdmitx.c ← rk628 自带 HDMI TX分层设计** Synopsys 提供通用的 HDMI IP 核心驱动Rockchip 写一层胶水代码处理 SoC 特有的寄存器、时钟、中断映射。同样的 dw-hdmi-qp.c 也在全志、ST、NXP 的平台上使用。五、实际修改方案5.1 新增不含 CEC 的 pinctrl 组pinctrl { /* ... rk628 pinctrl ... */ hdmi_tx_nocrc { hdmi_txm0_nocrc: hdmi-txm0-nocrc { rockchip,pins /* hdmi_tx_hpdin_m0 — 只保留 HPD去掉 CEC */ 4 RK_PC1 9 pcfg_pull_none; }; }; };原来的 hdmi_txm0_pins 捆绑了 CEC 和 HPD 两根脚但我们只需要 HPD。新建一个只含 HPD 的组彻底解耦。5.2 覆盖 HDMI 节点的 pinctrlhdmi { status okay; enable-gpios gpio2 RK_PB0 GPIO_ACTIVE_HIGH; /* * 覆盖 rk3576.dtsi 中的 pinctrl-0 * - hdmi_txm0_pinsCEC HPD→ hdmi_txm0_nocrc只 HPD * - 去掉 hdmi_tx_scl hdmi_tx_sda不需要 DDC/EDID * * 释放的引脚 * GPIO4_C0 → rk628 reset * GPIO4_C2 GPIO4_C3 → GPIO / 软件 I2C */ pinctrl-names default; pinctrl-0 hdmi_txm0_nocrc; };5.3 硬件GPIO4_C1 上拉 10KΩ 到 3.3V保证 HPD 读到高电平。5.4 验证# 启动后检查 HDMI 日志 dmesg | grep -E hdmi|rk628|tmds|cec# 期望输出无报错# dw hdmi qp use tmds mode# rk628 probe 成功不再有 gpio4-16 冲突六、关键结论1. **CEC 可选** 没有 cec-enable 属性时驱动完全跳过去掉引脚无副作用。2. **DDC 可选** 不去读 EDID 时驱动用兜底分辨率去掉 SCL/SDA 不报错。3. **HPD 建议保留** PHY 层需要它判断设备状态。可通过硬件上拉或 force-output DT 属性处理。4. **低分辨率 TMDS** FRL 只在超高清场景下开启你的场景全程 TMDSFRL 相关代码不会执行。5. **pinctrl 组名对驱动透明** 驱动通过 devm_pinctrl_get() 拿整个设备的 pinctrl只按 pinctrl-names如 default、idle匹配状态不知道组的名字。改 DT 即可C 代码一行不动。6. **Synopsys IP 分层** Rockchip 的 HDMI 核心来自 Synopsys DesignWareRockchip 只负责 SoC 特有的胶水层。CEC、DDC、EDID、音频 N/CTS 等协议逻辑是通用代码。八.RK628F奇怪问题如果想使用hdmi中的ddc复用做普通i2c的时候记得把rk628f的hdmi的ddc的电阻拆掉不然会干扰到edid部分导致芯片锁hdmi信号的流程