DRM显示子系统:显示管线的拼接方式

对象拆清楚之后,下一步就是:这些对象是怎么连成一条真实显示链路的?

1. 从输入到输出,不是一根线,而是一串对象关系

一条完整链路通常会长这样:

flowchart LR PL0[Plane 0] PL1[Plane 1] CRTC[CRTC] ENC[Encoder] BR0[Bridge 0] BR1[Bridge 1] CONN[Connector] PANEL[Panel] PL0 --> CRTC PL1 --> CRTC CRTC --> ENC ENC --> BR0 BR0 --> BR1 BR1 --> CONN CONN --> PANEL

这里有三个点值得注意。

第一,多个 plane 可以汇到同一个 CRTC。
这代表一帧画面往往是“多图层输入 -> 一次统一输出”。

第二,encoder 后面不一定只有一个 bridge。
外部链路稍微复杂一点时,中间可能串好几个 bridge。

第三,connector 不一定意味着“外接显示器插口”。
对固定内屏来说,它依然可以是用户态看到的输出对象,只是背后接的是一个固定 panel。

2. SoC 显示驱动中的 component 框架

很多 SoC 的显示子系统不是一个 monolithic 驱动,而是分散成多个 platform driver:

  • 显示控制器自己一个驱动;
  • DSI / HDMI / DP 主机控制器各自一个驱动;
  • bridge 芯片又是单独驱动;
  • panel 再单独一个驱动。

这些东西物理上属于一条链,软件上却不是同一个模块。component 框架的价值就在这里:
它允许“主设备”等待一组子组件都准备好,再把整条链路组装起来。

所以在 SoC DRM 驱动里经常会看到这样一种节奏:

  1. master 先创建 drm_devicemode_config
  2. 各子模块各自 probe;
  3. 所有组件就绪后统一 bind;
  4. bind 阶段把 plane、crtc、encoder、connector、bridge 串起来。

这一步解决的是“驱动组织方式”的问题。

3. OF graph 解决的是“谁和谁相连”的问题

驱动组织好了,还需要知道链路关系本身。这个时候经常会用到设备树里的 OF graph。

它的核心元素并不多:

  • port:某个设备的一个输入或输出端口;
  • endpoint:这个端口上的具体连接点;
  • remote-endpoint:它连到对端哪个 endpoint。

可以把 OF graph 理解成一张连线图,DRM 沿着这张图把输出路径找出来。

4. Bridge 链的递归拼接

Bridge 之所以好用,一个关键原因是它天生支持链式组合。

最常见的过程是:

  1. encoder 确定自己后面接的第一个 bridge;
  2. 第一个 bridge 在 attach 时,再去找自己后面的下一个 bridge 或 panel;
  3. 这个过程一直递归下去,直到链路末端。

如果末端是 panel,常见做法是把 panel 包成 bridge,或者通过 bridge helper 把 panel 挂进链路。这样整条输出路径在框架眼里就统一成了一串 bridge/connector/panel 的组合。

注意:bridge 的 attach 不是“上电”,而是“把链关系建立起来”。

5. Connector 的用户态视角

很多内核对象名词很适合从硬件视角去理解,connector 则相反,它更适合从用户态视角去理解。

用户态关心的是:

  • 这个输出端现在是否 connected;
  • 它支持哪些 mode;
  • 我能不能往这个口上设一个 1920x1080@60 的模式;
  • 它有没有热插拔事件。

这些信息最终都应该落在 connector 这一层暴露出去。

所以如果写驱动时脑子里只想着 panel、bridge、DSI host,很容易把 connector 的位置写得模糊。需要注意:connector 是给用户态看的输出对象。

posted @ 2026-07-21 11:32  G777  阅读(3)  评论(0)    收藏  举报