RK3588 DP 硬件与驱动结构完全解析:从 USB Type-C DP Alt Mode 到 Linux 内核排障实战
📺 B站:博主个人介绍
📘 博主书籍-京东购买链接*:Yocto项目实战教程
📘 加博主微信,进技术交流群: jerrydev
RK3588 DP 硬件与驱动结构完全解析:从 USB Type-C DP Alt Mode 到 Linux 内核排障实战
一、前言
最近在调试 RK3588 的外接显示时,遇到一个很典型、也很容易把人绕进去的问题:
- 系统里
card0-DP-1/status一直是disconnected modes为空- 屏幕不亮
- 乍看很像是 DP 主驱动、GStreamer、EDID 或 link training 的问题
但这次真正的根因,并不在 DP 主驱动本身,而在 USB Type-C 到 DP Alt Mode 的前置链路。更准确地说,是 Type-C role-switch graph 在 DTS 里接错了,导致 FUSB302/TCPM 这一层没有把 Type-C 端口注册出来,进一步导致 DP Alt Mode 根本没有建立,最后才表现为 card0-DP-1/status = disconnected。
这篇文章,我不只想讲“最后改了哪几行代码”,而是把这一块从头到尾讲清楚,适合对 DP、Type-C、Linux DRM、TCPM 还不太熟的人阅读。文章分四部分:
- RK3588 上 DP 硬件到底是怎么存在的
- Linux 下 RK3588 的 DP/Type-C 驱动结构是什么
- 这次问题为什么表面像 DP,实际上却不是 DP 主驱动问题
- 最终修复代码和调试方法应该怎么落地

二、RK3588 上的 DP,到底是不是“一个独立 DP 口”?
很多人刚接触 RK3588 时,会默认把 DP 理解成“和 HDMI 一样,是一个单独的显示输出口”。这个理解在 PC 上常常成立,但在 RK3588 板级设计里,经常不成立。
RK3588 的 DP,在很多板子上并不是直接拉成一个标准 DP 母座,而是复用在 USB Type-C 接口 上,通过 DP Alt Mode 输出视频。
也就是说,很多时候你看到的是一个 Type-C 口,但它既承担:
- USB2.0
- USB3.x
- Type-C 插入方向识别
- 角色切换
- DP Alt Mode 视频输出
这就决定了一个关键事实:
RK3588 上的 DP 是否能正常出图,并不只取决于 DP 控制器和 DRM 驱动,还取决于 Type-C 协商链路是否正常建立。
如果 Type-C 这一层没有起来,那么后面的 DP 主链路甚至连开始的机会都没有。
三、先建立一个整体模型:RK3588 的外接 DP 链路是怎么走的?
先给出一个简化逻辑图。
+----------------------+
| 用户空间 |
| kms / weston / app |
+----------+-----------+
|
v
+----------------------+
| DRM / dw-dp 驱动 |
| 输出 DP 主链路信号 |
+----------+-----------+
|
v
+----------------------+
| Rockchip USBDP PHY |
| 负责 PHY / lane / |
| orientation / mux |
+----------+-----------+
|
v
+----------------------+
| Type-C / TCPM / PD |
| FUSB302 + tcpm/typec |
+----------+-----------+
|
v
+----------------------+
| Type-C 接口/线缆 |
| DP Alt Mode 协商 |
+----------+-----------+
|
v
+----------------------+
| 外接显示器 / HUB / |
| Type-C 转 DP 设备 |
+----------------------+
这个模型里,最重要的不是“谁更高级”,而是“谁在前,谁在后”。
顺序关系很重要:
- Type-C 先识别连接状态
- TCPM/FUSB302 建立 Type-C port
- role switch / orientation switch / mux 正常获取
- 进入 DP Alt Mode
- DRM/dw-dp 才开始真正完成显示输出
- 显示器被识别,EDID 可读,
modes才会出现 card0-DP-1/status才会从 disconnected 变成 connected
所以如果链路断在第 2 步或第 3 步,后面的 DP 驱动即便本身没坏,也一定表现为“不通”。
四、DP、Type-C、HUB 三者之间是什么关系?
很多人调 DP 时,容易把下面几种设备混为一谈:
| 设备类型 | 本质 | 是否需要 Type-C Alt Mode |
|---|---|---|
| 标准 DP 线直连显示器 | 纯 DP 输出 | 不一定 |
| Type-C 转 DP 线 | Type-C 承载 DP Alt Mode | 需要 |
| Type-C Dock / HUB 带 DP/HDMI | Type-C Alt Mode + 多路复用/转换 | 需要 |
| USB 显卡类扩展坞 | 走 USB 数据协议,不是原生 DP | 不一定 |
你这次的问题属于第二、第三类:通过 Type-C 走原生 DP Alt Mode 输出。
这意味着 Type-C 口必须先正常工作:
- 要有 CC 检测
- 要能识别插入方向
- 要能完成 role switch
- 要能拿到 orientation switch 和 mode mux
- 要能把物理 lane 切到正确方向
- 要能让 DP Alt Mode 注册出来
如果其中有一个环节失败,最终从 DRM 视角看就是“DP 端口没连上”。
五、Linux 里这条驱动链到底是谁管谁?
很多新手第一次看这一块时,最容易困惑的是:文件太多了,DTS、DRM、Type-C、PHY、PD、DWC3 全掺在一起,不知道该从哪一层切。
下面我把这条链按职责拆开。
1. dw-dp:DP 主驱动层
这一层的职责是:
- 管理 DP connector
- 进行显示输出流程
- 读 EDID
- link training
- 设置显示模式
如果这一层完全没起来,通常会看到:
- DRM 节点本身异常
- connector 不存在
- 驱动 probe 失败
- 相关
dp@...节点不正常
但你这次不是这种情况。你前面的记录已经明确说明:
dp@fde50000是okayusbdp_phy0也是okay
也就是说,DP0 主驱动和 USBDP PHY 本体并没有挂。这是判断方向的第一个关键点。
2. USBDP PHY:物理层和切换层
这一层很关键,但很多人第一次不会想到它。
USBDP PHY 不只是“电气 PHY”,在 Type-C DP Alt Mode 场景里,它通常还承担:
- lane 方向适配
- orientation switch
- mode mux
- USB 与 DP 复用切换
你前面的排查里已经点出了这一点:class.c 里会继续去拿 typec_switch_get() / typec_mux_get(),而这些 switch/mux 的提供者就在 phy-rockchip-usbdp.c 这一层。
也就是说,USBDP PHY 不是孤立存在的,它是 Type-C 到 DP 输出的重要桥梁。
3. FUSB302:Type-C/PD 检测芯片
FUSB302 是这条链里的入口之一。它负责:
- 监测 CC
- 感知插入
- 上报状态
- 参与 Type-C/PD 协商
- 驱动 TCPM 状态机
如果它 probe 都没走完,整个 Type-C 口都可能起不来。
你前面的调试里,一个非常关键的现象是:
/sys/class/typec为空/sys/bus/typec/devices为空card0-DP-1/status还是disconnected
这组三连现象基本就说明:
Type-C port 没有真正注册成功。
4. TCPM:Type-C Port Manager
TCPM 是 Linux 内核里负责 Type-C 端口管理的核心状态机层。它会做很多关键事情,比如:
- 解析端口能力
- 注册 Type-C port
- 获取 usb role switch
- 获取 orientation switch
- 获取 mode mux
- 驱动 Alt Mode 建立
你这次调试里,最终把问题锁定到这一层,核心依据是:
fusb302@22 -> tcpm_register_port()这条链没成功走完,所以没有 Type-C port,也就没有 DP Alt Mode,最终DP-1一直是 disconnected。
这个判断非常重要,因为它把问题从“图像驱动”转移到了“Type-C 端口管理”。
5. DWC3:真正的 role switch 提供者
这次问题的决定性根因,就在这里。
你板子的 DTS 里,原先把 fusb302@22 的 endpoint 接到了 usb2phy。
但这份内核里,真正会注册 usb_role_switch 的提供者并不是 usb2phy,而是 dwc3。
这意味着什么?
意味着 TCPM 在调用 usb_role_switch_get() 时,沿着 DTS graph 去找 role switch 对象,结果找到了一个不对的对象路径,于是拿不到正确的 switch,后面的 Type-C port 注册流程就起不来。
这就是这次问题最核心的一句话:
不是 DP 驱动坏了,而是 Type-C role-switch graph 接错了。
六、为什么 card0-DP-1/status = disconnected 不能直接说明“DP 驱动坏了”?
这是这次调试里最容易误判的点。
很多人看见:
cat /sys/class/drm/card0-DP-1/status
disconnected
第一反应会是:
- DP 主驱动坏了
- HPD 没上来
- EDID 读不到
- 线有问题
- 显示器不兼容
这些方向不能说完全错,但它们都建立在一个前提上:
DP 主链路已经真正建立尝试过。
而你这次的问题是,链路根本还没走到那么后面。因为:
/sys/class/typec当时是空的- 没有
port0 - 没有
partner - 说明 Type-C 口本身都没注册出来
这种情况下,disconnected 更准确的含义不是“DP 驱动坏了”,而是:
从 DRM 的角度看,这个 DP 输出端口没有真正完成下层连接建立。
所以当你看到 disconnected 时,不要立刻只盯 DRM,要先问自己:
- 这个 DP 是不是通过 Type-C 出来的?
/sys/class/typec/有没有 port0?- TCPM/FUSB302 有没有正常起来?
- role switch / orientation switch / mode mux 有没有拿到?
七、这次排查是怎么一步步缩圈的?
下面我把这次调试逻辑整理成一个可复用的方法。
第一步:先看 DRM 端口状态
先看:
cat /sys/class/drm/card0-DP-1/status
cat /sys/class/drm/card0-DP-1/modes
如果看到:
status = disconnectedmodes为空
说明当前还没有成功建立显示连接。
但这只能说明“现象”,不能直接给出根因。
第二步:确认是不是 Type-C DP Alt Mode 口
如果板子用的是 Type-C 出图,那就一定要看:
ls /sys/class/typec
ls /sys/bus/typec/devices
你前面的现象非常典型:
/sys/class/typec为空/sys/bus/typec/devices为空
这个现象非常致命,因为它说明:
Type-C 端口对象本身都没被注册出来。
这时继续去折腾 GStreamer、kms sink、EDID、显示模式,意义都不大,因为外部显示链路还没起来。
第三步:确认 DP 主驱动是不是其实已经正常了
你前面已经确认过:
dp@fde50000正常usbdp_phy0正常
这一步很关键,它排除了“DP 主体没起”的大方向。
第四步:看 Type-C/TCPM/FUSB302 相关日志是否存在
你当时又做了一个很对的动作:
往 fusb302.c、tcpm.c、class.c 里加调试日志,去观察失败到底卡在哪一层。
这种做法的意义在于:
- 如果根本没有 Type-C port,问题肯定在 DRM 之前
- 那么继续猜测不如直接把 TCPM 关键路径打点
- 看看到底卡在
usb role switch - 还是
orientation switch - 还是
mode mux - 还是
typec port register
第五步:看 DTS graph 连接对象到底是不是对的
这一步是最终破案点。
你最后确认:
fusb302@22原先接的是usb2phy- 但真正注册
usb_role_switch的是dwc3 - 所以 graph 接错了
最终把它改成:
fusb302 -> dwc3 role-switch
问题立刻打通。
八、这次最终修复到底改了什么?
1. 主修复:修改 DTS 的 role-switch graph
这是唯一真正让功能恢复的改动。
修改前的本质
fusb302 ---> usb2phy
修改后的本质
fusb302 ---> dwc3 role-switch
你最后已经验证:
/sys/class/typec/port0出现了/sys/bus/typec/devices里出现了port0-partner.*card0-DP-1/status = connectedcard0-DP-1/modes可以正常读出一大串分辨率
这已经直接证明主修复生效。
2. 核心 DTS 代码
下面这段就是你这次记录里最核心的修复示意,可以直接放博文。
usb@fc000000 {
...
usb-role-switch;
port {
#address-cells = <1>;
#size-cells = <0>;
endpoint@0 {
reg = <0>;
remote-endpoint = <0x0000006f>;
phandle = <0x000001bb>;
};
};
};
fusb302@22 {
...
ports {
port@0 {
reg = <0>;
endpoint@0 {
remote-endpoint = <0x000001bb>;
phandle = <0x0000006f>;
};
};
};
};
这段代码背后的本质只有一句话:
把 FUSB302 的 role-switch graph 从 usb2phy 改接到真正提供 usb_role_switch 的 dwc3。
3. 调试日志增强:不是主因修复,但很有价值
你还在几处代码里补了日志:
tcpm.cfusb302.cclass.c
这些日志包括:
failed to get usb role switchfailed to register tcpm power supplyfailed to register typec portfailed to get orientation switchfailed to get mode muxregistered tcpm port
这些日志本身不会让系统变好,它们只是为了把失败点打透,方便定位。你后面也确认了:
- 不改状态机
- 不改时序
- 不改功能路径
- 影响主要只是日志变多
- 正式版本建议去掉,只保留 DTS 主修复
这个判断是对的。
九、那 bq25890 的 VBUS 报错是不是根因?
这也是你这次调试里一个非常容易被带偏的点。
日志里有:
bq25890-charger ... Cannot register otg vbus regulator
这个错误是真问题,但不是这次 DP 不亮的主因。因为你当时已经确认:
fusb302@22的vbus-supply指向的是固定 5V 节点vbus5v0_typec- 并不是直接指向 bq25890 的 OTG regulator
所以这条报错更像是独立的 DTS 电源建模问题,不是导致这次 DP-1 disconnected 的第一根因。
十、如果以后真的是 VBUS 电源路径问题,应该怎么接?
这个问题你当时也问到了,我这里顺手整理一下思路。
如果后续确认原理图上 Type-C 的 5V 确实由 bq25890 提供,那么正确建模思路通常是:
- 在
charger@6a下补regulators子节点 - 定义一个
otg-vbusregulator - 把
fusb302@22的vbus-supply指到这个 regulator
逻辑图大致如下:
bq25890 charger
|
+---- regulators {
otg-vbus
}
|
v
fusb302 vbus-supply
但这里有个很重要的工程原则:
在没有确认原理图前,不要为了“消掉日志”而盲改供电路径。
因为如果当前板子本来就是外部固定 5V 供电,那你强行改成从 bq25890 取,反而会引入新问题。
十一、修复成功后,系统侧会出现什么现象?
这次你的修复成功后,现象非常标准:
1. Type-C 设备节点出现
/sys/class/typec:
port0 port0-partner
/sys/bus/typec/devices:
port0-partner.0 port0-partner.1
2. DRM connector 状态变为 connected
cat /sys/class/drm/card0-DP-1/status
connected
3. modes 能读到显示器支持的模式列表
包括:
- 3840x2160
- 2560x1440
- 1920x1080
- 1280x720
- 640x480
等等
这说明:
- Type-C port 已建立
- partner 已识别
- DP Alt Mode 已经工作
- 下游显示设备可见
- EDID 已被成功读取
- DRM connector 已正常工作
这套现象链是完整闭环的。
十二、这次问题给我们的真正经验是什么?
我觉得这次排障最有价值的,不是“修了两行 DTS”,而是下面这几个经验。
经验 1:不要把 DP 问题只当成 DRM 问题
如果是 Type-C DP Alt Mode 口,DP 只是输出结果,前面还有:
- Type-C
- TCPM
- FUSB302
- role switch
- orientation switch
- mode mux
- USBDP PHY
这些环节都可能导致最终“屏不亮”。
经验 2:disconnected 不等于 DP 主驱动坏了
它只说明“从 DRM 看,这个 connector 没连上”。
原因可能在更下层。
经验 3:先看 /sys/class/typec,这一步能极大缩圈
如果 Type-C 口本身都没起来,那么后面很多显示层调试都属于“打空气”。
经验 4:DTS graph 接错,是这类问题里非常高频但很隐蔽的根因
尤其是在:
- 平台代码移植
- 参考板改板
- 内核版本切换
- DWC3 / USB2PHY / Type-C 子系统演进
这些场景下,很容易出现“节点都在,但 graph 接错”的问题。
经验 5:日志增强非常有价值,但最终交付应保留最小必要修改
这次真正解决问题的是 DTS 主修复。
调试日志只是定位工具,不应长期保留太多。
十三、最后给一个可复用的排障流程
以后再碰到 RK3588 Type-C 出 DP 不亮,可以按这个顺序查:
1. 看 DRM
- /sys/class/drm/card0-DP-1/status
- /sys/class/drm/card0-DP-1/modes
2. 看 Type-C
- ls /sys/class/typec
- ls /sys/bus/typec/devices
3. 看内核配置
- CONFIG_TYPEC
- CONFIG_TYPEC_TCPM
- CONFIG_TYPEC_FUSB302
- CONFIG_TYPEC_DP_ALTMODE
- CONFIG_USB_ROLE_SWITCH
- CONFIG_PHY_ROCKCHIP_USBDP
4. 看 dmesg
- fusb302
- tcpm
- typec
- role switch
- orientation switch
- mode mux
5. 看 DTS graph
- fusb302 的 endpoint 接到了谁
- 真正提供 usb_role_switch 的是谁
- dwc3 / usb2phy / usbdp phy 的关系是否正确
6. 确认修复后闭环
- port0 出现
- partner 出现
- DP-1 connected
- modes 可读
十四、总结
这次 RK3588 外接显示问题,表面现象是:
card0-DP-1/status = disconnectedmodes为空- 屏幕不亮
但真正根因不是 DP 主驱动坏了,而是:
USB Type-C DP Alt Mode 的前置链路没有建立。更具体地说,是 DTS 里的 Type-C role-switch graph 接错了:FUSB302 原先接到了 usb2phy,而当前内核里真正提供 usb_role_switch 的是 dwc3。
修复方法也很明确:
把
fusb302 -> usb2phy改成fusb302 -> dwc3 role-switch。
修完之后,Type-C 端口成功注册,partner 出现,DP-1 变成 connected,显示模式正常枚举,问题彻底打通。这个最终结论和修复路径,已经在你的调试记录和结果中被完整验证。
📺 B站:博主个人介绍
📘 博主书籍-京东购买链接*:Yocto项目实战教程
📘 加博主微信,进技术交流群: jerrydev
更多推荐




所有评论(0)