SA8155平台GPU驱动与MDP通路调试实战工程 - 第3节

3.1 Adreno GPU 架构概览

Adreno GPU 是高通骁龙/Snapdragon 平台的核心图形处理器,在 SA8155 中集成 Adreno 640/650 系列。其架构采用统一着色器模型与 Tile-Based 渲染管线,兼顾高性能与低功耗。

架构要点: Adreno 采用分层结构:应用层通过 OpenGL ES / Vulkan 驱动提交命令 → 内核态 KGSL 驱动管理上下文与内存 → 硬件前端调度器分发到多个着色器核心簇(Shader Core Cluster),每个簇包含 ALU、纹理单元与 L1 缓存,最终通过渲染后端(RB)输出到帧缓冲。
Adreno GPU 内部架构分层图 应用层 (User Space) — OpenGL ES / Vulkan / OpenCL 驱动 内核层 (Kernel Space) — KGSL 驱动 + DRM/KMS 硬件前端 — 命令解析器 / 上下文调度器 / MMU 着色器核心簇 (Shader Core Cluster) × N ALU 阵列 | 纹理单元 | L1 指令/数据缓存 渲染后端 (RB) — 像素合并 / Z-Test / 帧缓冲输出

3.1.1 Tile-Based 渲染与 GMEM

Adreno 使用 Tile-Based 渲染,将帧缓冲划分为 16×16 或 32×32 像素的 Tile,在片内 GMEM(通用内存)中完成深度测试与颜色混合,减少对外部 DDR 的带宽消耗。

特性说明
Tile 尺寸16×16 / 32×32 像素(可配置)
GMEM 容量Adreno 640 约 1MB,Adreno 650 约 1.5MB
带宽节省相比直接渲染节省 40%~60% 外部内存访问
适用场景高分辨率 UI、游戏渲染、合成

3.2 内核驱动模块加载流程

SA8155 平台 GPU 驱动以内核模块形式加载,主要涉及 KGSL(Kernel Graphics Support Layer)与 DRM 显示驱动。加载流程遵循标准 Linux 设备驱动模型:设备树匹配 → probe → 资源申请 → 初始化 → 注册。

KGSL 驱动模块加载流程 1. 设备树解析 of_match_table 匹配 2. probe 入口 kgsl_device_probe() 3. 资源获取 IRQ / 寄存器 / 时钟 / 电源 4. 硬件初始化 GMEM / MMU / 微码加载 5. 驱动注册 misc / DRM / devfreq 6. 加载完成

3.2.1 关键函数调用链

// 驱动入口
module_init(kgsl_driver_init);
module_exit(kgsl_driver_exit);

// probe 流程简化
static int kgsl_device_probe(struct platform_device *pdev) {
    // 1. 从设备树获取寄存器基址、中断号
    struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    // 2. 映射寄存器空间
    device->reg_base = devm_ioremap_resource(&pdev->dev, res);
    // 3. 获取时钟与电源域
    device->gpu_clk = clk_get(&pdev->dev, "core_clk");
    // 4. 初始化 MMU 与 GMEM
    kgsl_mmu_init(device);
    // 5. 加载 GPU 微码
    kgsl_fw_load(device, "a650_sqe.fw");
    // 6. 注册 misc 设备
    misc_register(&device->miscdev);
    // 7. 注册 devfreq 调频
    devfreq_add_device(&device->dev, &kgsl_devfreq_profile, "kgsl-3d0", NULL);
    return 0;
}

3.3 设备树配置解析

SA8155 平台通过设备树(Device Tree)描述 GPU 硬件资源。设备树节点位于 arch/arm64/boot/dts/qcom/sa8155.dtsi,核心节点为 qcom,kgsl-3d0。

3.3.1 关键属性说明

属性名类型说明
compatiblestring"qcom,adreno-650.0", "qcom,kgsl-3d0"
regaddress-cells × 2寄存器基址与大小(GMEM + 核心寄存器)
interruptsu32GPU 中断号(通常为 0~3)
clocksphandle list核心时钟、总线时钟、内存时钟
qcom,gpu-modelstring"adreno650v2"
qcom,initial-pwrlevelu32初始电源等级
qcom,gmuphandleGMU(Graphics Management Unit)节点引用

3.3.2 典型设备树片段

&gpu {
    compatible = "qcom,adreno-650.0", "qcom,kgsl-3d0";
    reg = <0 0x3d00000 0 0x40000>,
          <0 0x3d9c000 0 0x10000>;
    reg-names = "kgsl_3d0_reg_memory", "kgsl_3d0_gmem";
    interrupts = <0 300 0>;
    clocks = <&gpucc GPU_CC_GX_GFX3D_CLK>,
             <&gpucc GPU_CC_CX_GMU_CLK>;
    clock-names = "core_clk", "gmu_clk";
    qcom,gpu-model = "adreno650v2";
    qcom,initial-pwrlevel = <5>;
    qcom,gmu = <&gmu>;
    status = "okay";
};
调试提示: 在 SA8155 开发板上,可通过 cat /sys/kernel/debug/kgsl-3d0/registers 查看 GPU 寄存器状态,确认设备树映射是否正确。若 reg 地址错误,会导致 probe 失败,dmesg 中可见 kgsl: failed to ioremap 错误。

3.3.3 电源与调频配置

设备树中通过 qcom,gpu-pwrlevels 子节点定义 GPU 频率/电压等级,驱动根据负载动态切换。

qcom,gpu-pwrlevels {
    #address-cells = <1>;
    #size-cells = <0>;
    compatible = "qcom,gpu-pwrlevels";

    qcom,gpu-pwrlevel@0 {
        reg = <0>;
        qcom,initial-freq = <670000000>;   // 670 MHz
        qcom,min-freq = <200000000>;
        qcom,max-freq = <670000000>;
    };
    qcom,gpu-pwrlevel@1 {
        reg = <1>;
        qcom,initial-freq = <500000000>;
        qcom,min-freq = <200000000>;
        qcom,max-freq = <500000000>;
    };
};

3.4 本章小结

  • Adreno 架构:统一着色器 + Tile-Based 渲染 + GMEM,核心簇与渲染后端流水线清晰。
  • 驱动加载:设备树匹配 → probe → 资源获取 → 硬件初始化 → 注册,关键函数 kgsl_device_probe()。
  • 设备树:qcom,kgsl-3d0 节点定义寄存器、中断、时钟、电源等级,是驱动与硬件之间的桥梁。
常见踩坑: 设备树中 qcom,gmu 节点引用错误会导致 GMU 固件加载失败,GPU 无法进入低功耗状态。务必检查 dmesg | grep gmu 确认 GMU 初始化是否正常。