📺 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 还不太熟的人阅读。文章分四部分:

  1. RK3588 上 DP 硬件到底是怎么存在的
  2. Linux 下 RK3588 的 DP/Type-C 驱动结构是什么
  3. 这次问题为什么表面像 DP,实际上却不是 DP 主驱动问题
  4. 最终修复代码和调试方法应该怎么落地

在这里插入图片描述

二、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 设备   |
          +----------------------+

这个模型里,最重要的不是“谁更高级”,而是“谁在前,谁在后”。

顺序关系很重要:

  1. Type-C 先识别连接状态
  2. TCPM/FUSB302 建立 Type-C port
  3. role switch / orientation switch / mux 正常获取
  4. 进入 DP Alt Mode
  5. DRM/dw-dp 才开始真正完成显示输出
  6. 显示器被识别,EDID 可读,modes 才会出现
  7. 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@fde50000okay
  • usbdp_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,要先问自己:

  1. 这个 DP 是不是通过 Type-C 出来的?
  2. /sys/class/typec/ 有没有 port0?
  3. TCPM/FUSB302 有没有正常起来?
  4. role switch / orientation switch / mode mux 有没有拿到?

七、这次排查是怎么一步步缩圈的?

下面我把这次调试逻辑整理成一个可复用的方法。

第一步:先看 DRM 端口状态

先看:

cat /sys/class/drm/card0-DP-1/status
cat /sys/class/drm/card0-DP-1/modes

如果看到:

  • status = disconnected
  • modes 为空

说明当前还没有成功建立显示连接。

但这只能说明“现象”,不能直接给出根因。


第二步:确认是不是 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.ctcpm.cclass.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 = connected
  • card0-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.c
  • fusb302.c
  • class.c

这些日志包括:

  • failed to get usb role switch
  • failed to register tcpm power supply
  • failed to register typec port
  • failed to get orientation switch
  • failed to get mode mux
  • registered tcpm port

这些日志本身不会让系统变好,它们只是为了把失败点打透,方便定位。你后面也确认了:

  • 不改状态机
  • 不改时序
  • 不改功能路径
  • 影响主要只是日志变多
  • 正式版本建议去掉,只保留 DTS 主修复

这个判断是对的。


九、那 bq25890 的 VBUS 报错是不是根因?

这也是你这次调试里一个非常容易被带偏的点。

日志里有:

bq25890-charger ... Cannot register otg vbus regulator

这个错误是真问题,但不是这次 DP 不亮的主因。因为你当时已经确认:

  • fusb302@22vbus-supply 指向的是固定 5V 节点 vbus5v0_typec
  • 并不是直接指向 bq25890 的 OTG regulator

所以这条报错更像是独立的 DTS 电源建模问题,不是导致这次 DP-1 disconnected 的第一根因。


十、如果以后真的是 VBUS 电源路径问题,应该怎么接?

这个问题你当时也问到了,我这里顺手整理一下思路。

如果后续确认原理图上 Type-C 的 5V 确实由 bq25890 提供,那么正确建模思路通常是:

  1. charger@6a 下补 regulators 子节点
  2. 定义一个 otg-vbus regulator
  3. fusb302@22vbus-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 = disconnected
  • modes 为空
  • 屏幕不亮

但真正根因不是 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


Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐