Hotdry.
systems-engineering

RISC-V GPU内核驱动与3D渲染管道的工程实现

深入分析在T-HEAD TH1520 RISC-V SoC上实现完全上游化GPU驱动的技术挑战,包括电源序列管理、显示管道集成与Vulkan原生栈构建。

RISC-V GPU 生态的突破:从内核管道到 3D 渲染

在嵌入式 GPU 领域,Imagination Technologies 的 PowerVR GPU 长期占据主导地位,但其驱动程序一直停留在厂商提供的闭源或树外版本中。随着 RISC-V 架构的崛起,这一局面正在发生根本性改变。2025 年底,T-HEAD TH1520 成为首个支持完全上游化 GPU 驱动的 RISC-V SoC,这一里程碑标志着开源 GPU 生态在 RISC-V 平台上的重大突破。

硬件基础:TH1520 的 GPU 架构

T-HEAD TH1520 是一款基于 RISC-V Xuantie C910 四核处理器的 SoC,集成了 Imagination BXM-4-64 PowerVR GPU。这款 GPU 支持 OpenGL ES 3.0/3.1/3.2、OpenCL 1.1/1.2/2.0 以及 Vulkan 1.1/1.2,理论性能达到 50.7 GFLOPS,像素填充率为 3168M 像素 / 秒。在 Lichee Pi 4A 单板计算机上,这款 SoC 为开发者提供了完整的 RISC-V 图形计算平台。

然而,硬件支持只是第一步。真正的挑战在于如何让这些硬件在 Linux 内核中 "活" 起来。

依赖链分析:GPU 启动的四个层级

启用 TH1520 的 GPU 并非简单的 Kconfig 配置修改,而是一个复杂的系统工程。GPU 子系统被一系列硬件依赖所保护,这些依赖在 Linux 内核中原本没有对应的驱动程序。

1. 邮箱驱动(mailbox-th1520)

TH1520 使用一个安全协处理器(E902)来管理电源。第一步是编写邮箱驱动程序,在主 CPU 和协处理器之间建立物理通信链路。这个驱动实现了基本的消息传递机制,为后续的电源管理协议奠定了基础。

2. AON 协议驱动(thead-aon-protocol)

在邮箱驱动之上,需要实现 Always-On(AON)固件协议。这个驱动程序处理特定的消息格式,用于向协处理器请求电源状态变更。AON 协议定义了电源管理的命令集和响应机制,是电源域管理的前置条件。

3. 电源域驱动(pmdomain-thead)

有了 AON 协议,GPU 的电源轨可以作为标准的 Linux 通用电源域(GenPD)暴露出来。这使得内核能够以通用方式管理 GPU 的电源状态。电源域驱动将硬件特定的电源管理抽象为标准的 Linux 电源管理接口。

4. 时钟与复位控制器

最后,需要扩展时钟驱动(clk-th1520-vo)并实现新的复位控制器(reset-th1520),以处理视频输出(VO)子系统的特定要求。GPU 位于 VO 子系统中,需要精确的时钟和复位序列才能正常工作。

Power Sequencing 框架的创新应用

在平台驱动程序就位后,一个关键的集成挑战仍然存在:TH1520 需要特定的、时间敏感的序列来启动 GPU。这个序列包括:启用电源域、等待电压稳定、然后以特定顺序解除复位。

传统方法的局限性

历史上,内核中的电源序列主要局限于 MMC / 蓝牙子系统(用于切换 WiFi 芯片的 GPIO)。对于复杂的 GPU 启动序列,缺乏标准化的解决方案。

pwrseq 框架的引入

Linux 内核最近引入了通用的 **Power Sequencing(pwrseq)** 子系统,由 Bartosz Golaszewski 开发,旨在标准化这个问题。在代码审查过程中,电源管理子系统维护者 Ulf Hansson 指出,TH1520 的 GPU 是这个新框架的完美候选者。

实现细节:pwrseq-thead-gpu

pwrseq-thead-gpu驱动的最有趣部分是match函数,它允许序列器 "收养"GPU 的资源:

static int pwrseq_thead_gpu_match(struct pwrseq_device *pwrseq,
                                  struct device *dev)
{
    struct pwrseq_thead_gpu_ctx *ctx = pwrseq_device_get_drvdata(pwrseq);
    
    /* 1. 只匹配特定的T-HEAD TH1520 GPU兼容性 */
    if (!of_device_is_compatible(dev->of_node, "thead,th1520-gpu"))
        return 0;
    
    /* 2. 从消费者设备节点动态获取资源 */
    ctx->num_clks = ARRAY_SIZE(clk_names);
    ctx->clks = kcalloc(ctx->num_clks, sizeof(*ctx->clks), GFP_KERNEL);
    
    for (i = 0; i < ctx->num_clks; i++)
        ctx->clks[i].id = clk_names[i];
    
    /* 序列器从GPU的DT节点获取'core'和'sys'时钟 */
    ret = clk_bulk_get(dev, ctx->num_clks, ctx->clks);
    if (ret)
        goto err_free_clks;
    
    ctx->gpu_reset = reset_control_get_shared(dev, NULL);
    
    return 1;
}

架构优势

这种架构提供了三个主要优势:

  1. 清晰的抽象:GPU 驱动程序不需要了解 T-HEAD 特定的复位顺序或微秒级延迟。它只需调用通用的pwr_ops->power_on()

  2. 控制反转:序列器在匹配阶段从 GPU 的设备树节点 "窃取" 资源句柄(时钟和复位)。这使得序列器能够控制概念上属于 GPU 的资源,确保正确的启动顺序,而无需修改 GPU 驱动程序逻辑。

  3. 严格的顺序:通过将逻辑集中在专用驱动程序中,我们保证clkgen复位(由父节点控制)和gpu_core复位(由消费者节点控制)按照硬件手册要求的精确顺序解除。

显示管道的分离架构

启动 GPU 是一个重大胜利,但这只解决了问题的一半。GPU 可以将美丽的 3D 场景渲染到内存中,但如果没有显示控制器将这些缓冲区扫描到屏幕上,你仍然只能看到黑色终端。

Verisilicon DC8200 显示控制器

在 TH1520 上,显示职责由Verisilicon DC8200 IP 块处理,连接到 Synopsys DesignWare HDMI 桥接器。

生态系统说明:如果你关注 RISC-V 领域,这个 IP 可能听起来很熟悉。StarFive JH7110(用于 VisionFive 2)使用完全相同的 Verisilicon DC8200 显示控制器。

实际上,我正在并行为 JH7110 启用显示栈。虽然 IP 相同,但集成方式大不相同 ——JH7110 在 HDMI PHY 和时钟发生器之间存在复杂的循环依赖,需要完全重新思考架构。但这将是未来博客文章的故事。

协作开发模式

虽然我专注于 TH1520 的电源序列和 GPU 启用,但显示驱动程序工作由Icenowy Zheng领导,他是 RISC-V 生态系统中另一位杰出的工程师。

这是上游内核开发的美丽之处:你不需要独自构建整个世界。Icenowy 一直在为Verisilicon 显示控制器开发通用的 DRM 驱动程序,使其支持 TH1520 上找到的特定 HDMI PHY。

由于这些补丁目前正在审查过程中(v4),它们尚未进入主线。为了构建工作演示,我在主线内核之上应用了 Icenowy 的补丁系列。

有了 Icenowy 的显示驱动程序处理 "扫描输出",我的基础设施处理 "电源启动",我们终于有了完整的管道:内存 -> GPU 渲染 -> 内存 -> 显示控制器 -> HDMI

Vulkan 原生驱动与 Zink 栈构建

现在内核可以与硬件通信,我们需要用户空间栈来渲染图形。

历史上,启用新 GPU 意味着为 Mesa 编写两个庞大的驱动程序:一个用于 Vulkan,一个用于 OpenGL。但开源图形世界已经发生了变化。drm/imagination驱动程序被设计为Vulkan 原生

Zink:OpenGL over Vulkan

与其编写复杂的传统 OpenGL 驱动程序,我们使用Zink。Zink 是一个在 Vulkan 之上实现 OpenGL 的 Mesa 驱动程序,它允许我们利用现有的 Vulkan 驱动程序来提供 OpenGL 支持,而无需编写和维护单独的 OpenGL 驱动程序。

栈架构:渲染与显示的分离

由于 TH1520 使用分离的 DRM 架构,流程不是一条直线。GPU 和显示控制器是通过内存(DMA-BUF)共享数据的独立设备。

      [ 应用程序 (glmark2) ]
                 │
                 ▼
      [    Zink (OpenGL)      ]
                 │
                 ▼
      [ Mesa PowerVR (Vulkan) ]
                 │
      ┌──────────┴──────────┐
      │     Linux内核      │
      ▼                     ▼
[ GPU驱动程序 ]       [ 显示驱动程序 ]
 (渲染节点)         (KMS/卡节点)
      │                     │
      ▼        DMA-BUF      ▼
 [ GPU硬件 ] ──(内存)──▶ [ 显示硬件 ] ──▶ HDMI

这种分离解释了为什么第 1 部分(GPU)和第 2 部分(显示)的内核管道必须独立完成,然后才能协同工作。

实际部署参数与性能基准

对于想要在自己的 Lichee Pi 4A 上重现此功能的开发者,精确的版本匹配至关重要。

内核构建

我使用 Linux 6.19 作为基础,并在其上应用了未合并的显示控制器补丁。确切的代码树可以在这里找到。

Mesa 构建配置

我使用了 Icenowy Zheng 工作的分支,其中包括必要的粘合代码,使 Zink 能够与此特定的硬件组合良好配合。

确切的 Meson 配置用于构建纯 Vulkan+Zink 栈:

meson setup build \
    -D buildtype=release \
    -D platforms=x11,wayland \
    -D vulkan-drivers=imagination \
    -D gallium-drivers=zink \
    -D glx=disabled \
    -D gles1=disabled \
    -D gles2=enabled \
    -D egl=enabled \
    -D tools=imagination \
    -D glvnd=disabled

环境变量配置

由于驱动程序仍在积极开发中,尚未完全符合规范,我们需要传递一些标志来说服 Mesa 运行。

最重要的是PVR_I_WANT_A_BROKEN_VULKAN_DRIVER=1。没有这个,驱动程序的安全防护会阻止加载。我们还强制使用 Zink 驱动程序并明确选择我们的设备:

export PVR_I_WANT_A_BROKEN_VULKAN_DRIVER=1
export GALLIUM_DRIVER=zink
export MESA_VK_DEVICE_SELECT=1010:36104182!

性能基准

启动 Weston 合成器会话使用 DRM 后端:

weston --backend=drm-backend.so --continue-without-input &

然后运行glmark2-es2-wayland进行基准测试。结果显示,我们正在通过 Zink 在 PowerVR GPU 上完全加速运行:

=======================================================
    glmark2 2023.01
=======================================================
    OpenGL Information
    GL_VENDOR:      Mesa
    GL_RENDERER:    zink Vulkan 1.2(PowerVR B-Series BXM-4-64 MC1 (IMAGINATION_OPEN_SOURCE_MESA))
    GL_VERSION:     OpenGL ES 2.0 Mesa 26.0.0-devel (git-601d20e81e)
    Surface Config: buf=32 r=8 g=8 b=8 a=8 depth=24 stencil=0 samples=0
    Surface Size:   800x600 windowed
=======================================================
[build] use-vbo=false: FPS: 67 FrameTime: 14.960 ms
[build] use-vbo=true: FPS: 98 FrameTime: 10.252 ms
[texture] texture-filter=nearest: FPS: 97 FrameTime: 10.332 ms
[texture] texture-filter=linear: FPS: 93 FrameTime: 10.868 ms
[texture] texture-filter=mipmap: FPS: 101 FrameTime: 9.957 ms

工程挑战与解决方案总结

1. 电源管理复杂性

TH1520 的 GPU 电源管理涉及多个层级:邮箱通信、AON 协议、电源域控制、时钟和复位管理。解决方案是采用模块化设计,每个组件都有专门的驱动程序,通过标准的 Linux 接口进行交互。

2. 启动序列的时序敏感性

GPU 启动需要精确的时序控制,包括电压稳定等待和特定的复位解除顺序。Power Sequencing 框架提供了标准化的解决方案,将时序逻辑封装在专用驱动中。

3. 显示管道的分离架构

渲染和显示是独立的硬件组件,需要通过 DMA-BUF 共享内存。这种分离架构要求两个驱动程序(GPU 和显示)能够协同工作,同时保持各自的独立性。

4. 用户空间栈的构建

传统的双驱动(Vulkan + OpenGL)方法被 Vulkan 原生驱动 + Zink 的组合所取代,这减少了维护负担,同时提供了完整的图形 API 支持。

未来展望与社区影响

TH1520 GPU 的上游化工作为 RISC-V 图形生态树立了重要先例。这项工作展示了如何将复杂的专有硬件集成到开源生态系统中,同时保持代码质量和可维护性。

对其他 RISC-V 平台的影响

相同的技术方法可以应用于其他 RISC-V SoC,如 StarFive JH7110,它使用相同的 Verisilicon DC8200 显示控制器。虽然硬件集成细节可能不同,但基本的架构模式 —— 分离的渲染和显示管道、标准化的电源管理接口、Vulkan 原生用户空间栈 —— 都是可重用的。

开源 GPU 生态的推动

Imagination Technologies 对上游开源驱动的承诺是一个重要信号。随着更多厂商采用类似的方法,RISC-V 平台的图形支持将变得更加成熟和可靠。

结论

在 T-HEAD TH1520 上实现完全上游化的 GPU 支持是一个复杂的系统工程,涉及内核多个子系统的深度集成。从电源序列管理到显示管道协调,再到用户空间栈构建,每个环节都需要精细的设计和实现。

这项工作不仅为 Lichee Pi 4A 用户提供了硬件加速的 3D 图形,更重要的是为整个 RISC-V 生态系统的图形支持建立了可复用的模式。随着 Linux 6.18 中这些驱动的合并,RISC-V 平台终于拥有了与 Arm 平台相媲美的图形支持基础设施。

开源协作的力量在这一项目中得到了充分体现:来自不同公司和背景的开发者共同解决了复杂的技术挑战,最终将 "黑暗硅" 变成了现代、Vulkan 能力的图形平台。


资料来源

  1. Michał Wilczyński, "Igniting the GPU: From Kernel Plumbing to 3D Rendering on RISC-V", https://mwilczynski.dev/posts/riscv-gpu-zink/
  2. Michael Larabel, "Imagination PowerVR Driver With Linux 6.18 To Support RISC-V", Phoronix, https://www.phoronix.com/news/Linux-6.18-PowerVR-RISC-V
查看归档