============================================== GPU — Adreno A619, the GMU, and the zap shader ============================================== The graphics subsystem: the Adreno A619, the GMU microcontroller that powers it, and the TrustZone-loaded **zap shader** that unlocks its secure registers. This is catalogued as below-userspace *firmware* — the zap image is authenticated and loaded by TZ (PAS), and the GMU runs its own microcode — even though the GPU is not on the boot path (`Bootloader relevance`_ below). All facts are from ``artifacts/boot_a/board.dts`` and the XBL ``uefiplat.cfg`` MMAP. Adreno A619 =========== ``kgsl-3d0@3d00000``, ``compatible = "qcom,kgsl-3d0"``. :Chip id: ``qcom,chipid = 0x6010900`` → core **6**, major **1**, minor **9** = **Adreno A619** (the a6xx family GPU of the SM6350). :Register windows: ``kgsl_3d0_reg_memory`` **0x3D00000** size **0x40000** (the GPU register block), ``cx_dbgc`` **0x3D61000** (0x800, CX debug), ``cx_misc`` **0x3D9E000** (0x1000). GPU QDSS-STM at ``0x161C0000`` (0x40000). :Interrupt: SPI ``0x12C`` (300). :Clocks: ``core_clk``, ``rbbmtimer_clk``, ``mem_clk``, ``mem_iface_clk``, ``gmu_clk`` — sourced from GPUCC (:doc:`clocks`). :Rails: ``vddcx`` (the CX always-on rail) and ``vdd`` (the GX graphics rail); the GX rail is collapsed when the GPU is idle and restored by the GMU. **DVFS and speed bins.** The A619 runs a 7-level DVFS ladder (bin 0), top to idle: **850, 800, 650, 565, 430, 355, 253 MHz**, then an off level. There are **five** power-level tables (``qcom,gpu-pwrlevels-0`` … ``-4``); the one used is chosen at runtime from two QFPROM fuses declared as nvmem cells — ``speed_bin`` and ``gaming_bin`` — which are the ``gpu_speed_bin`` (row 6015) and ``gpu_gaming_bin`` (row 6026) fuses already documented in :doc:`/open-questions`. This is the one place the GPU touches the fuse story: binning selects the frequency cap. The GMU (Graphics Management Unit) ================================== ``gmu@3d6a000``, ``compatible = "qcom,gpu-gmu"`` — a small dedicated microcontroller that owns GPU power, clocking and DVFS autonomously, without AP intervention. :Register windows: ``kgsl_gmu_reg`` **0x3D6A000** size **0x31000** (GMU core), ``kgsl_gmu_pdc_cfg`` **0xB290000** (0x10000) and ``kgsl_gmu_pdc_seq`` **0xB490000** (0x10000) — the PDC config and sequence RAM the GMU uses to drive RPMh rail transitions autonomously. :Interrupts: SPI ``0x130`` (304) and ``0x131`` (305) — GMU and HFI. :Clocks: ``gmu_clk``, ``cxo_clk``, ``axi_clk``, ``memnoc_clk``. :SMMU: its own context bank ``qcom,smmu-gmu-user-cb`` (``iommus = <… 0x04>``) — GMU DMA is translated separately from the GPU's own contexts. Companion windows in the XBL MMAP: ``GPU_GMU_CX_BLK 0x03D7D000`` (0xC000, the CX block the GMU controls), ``GPU_CC 0x03D90000`` (GPUCC, :doc:`clocks`) and ``GPU_CPR 0x03D9A000`` (closed-loop voltage for the GX rail). The GMU boots its own microcode (the a6xx GMU firmware), then talks to the kgsl driver over the HFI (Hardware Function Interface) mailbox; that microcode is delivered from the vendor firmware partition (Android userspace, out of scope as a file), loaded by the in-kernel kgsl driver. The zap shader ============== Before a non-secure driver may submit to the GPU, the GPU's secure registers (the ``RBBM_SECVID`` block and the CP protection that fence off secure memory) have to be initialised — and that init can only run from the secure world. That is the **zap shader**: a small signed blob TrustZone authenticates and executes on the GPU to program those registers, after which the HLOS driver can use the GPU without being able to reach secure memory. On this device it is a PIL/PAS peripheral: - Node ``qcom,kgsl-hyp``, ``compatible = "qcom,pil-tz-generic"``. - ``qcom,pas-id = 0x0D`` (13) — the Peripheral Authentication Service id for the GPU zap image. - ``qcom,firmware-name = "a615_zap"`` — the a6xx zap image (the A615/A619 GMU family shares one zap binary; the name is ``a615`` even though the GPU is an A619). So the flow is: HLOS calls ``PAS_INIT_IMAGE`` / ``PAS_AUTH_AND_RESET`` (an SCM call into TZ) for PAS id 13; TZ verifies the ``a615_zap`` signature and runs it to unlock the GPU secure path (:doc:`/trustzone/secure-world`). The ``a615_zap.mbn`` image itself lives in the vendor firmware partition (out of scope as a file), but the **authentication and load are a TZ/PAS action** — below userspace — which is why it belongs in this catalogue. Firmware inventory ================== .. list-table:: :header-rows: 1 :widths: 24 26 50 * - Blob - Loaded by - Below userspace? * - ``a615_zap`` (zap shader) - **TZ / PAS** (id 13), triggered by an HLOS SCM call - **yes** — authenticated & run by the secure world * - a6xx **GMU** microcode - in-kernel kgsl driver → GMU - kernel, but delivered from vendor firmware (file out of scope) * - CP **SQE** microcode - in-kernel kgsl driver → GPU CP - kernel; same provenance Bootloader relevance ==================== None on the boot path. GPUCC, the GMU and the zap shader all come up under Linux; XBL and ABL never start the 3D core (the boot splash and e-ink UI go through the DPU, :doc:`/display/panel`). A replacement bootloader can ignore the GPU entirely. The single below-userspace hook is the **PAS id 13** entry in the TZ authentication table — a custom secure world would need to keep honouring it (or the GPU stays unusable to Android), and the zap-shader load is one more consumer of the same PIL/PAS path used by the DSP images (:doc:`/audio/dsp-firmware`). Static end ========== The GPU model, the GMU/CX/PDC/CPR windows, the DVFS ladder, the five speed-bin tables and their selecting fuses, and the zap shader's PAS id and image name are all fixed from the tree and the XBL map. What is not in the dump is the **content of the firmware blobs** (zap / GMU / SQE) — they are signed images in the vendor partition and are not analysed here — and the **live GPU register state**, which only exists when the GMU has powered the core on a running device. Provenance ========== :Source: ``artifacts/boot_a/board.dts`` (``kgsl-3d0@3d00000``, ``gmu@3d6a000``, ``qcom,kgsl-hyp`` zap node, ``qcom,gpu-pwrlevels-*`` tables, ``nvmem-cells`` speed/gaming bins, GPU rails/SMMU) and ``_READONLY/lun1/xbl_a.bin`` (``uefiplat.cfg`` MMAP: ``GPU_GMU_CX_BLK``, ``GPU_CC``, ``GPU_CPR``). :Method: DTB node reading + XBL MMAP cross-check; chip id decoded; GPU frequencies decoded from ``qcom,gpu-freq``. No code executed. :Cross-refs: :doc:`clocks` (GPUCC), :doc:`/trustzone/secure-world` (TZ / PAS authentication), :doc:`/audio/dsp-firmware` (the shared PIL/PAS path), :doc:`/open-questions` (``gpu_speed_bin`` / ``gpu_gaming_bin`` fuses, fuse rows), :doc:`/display/panel` (the actual display path).