# Native AMD GPU support — feasibility and roadmap **Status: research snapshot, not implemented.** This records what a *minimal, display-only* native driver for a real discrete AMD GPU — specifically an **RX 6600-class card (Navi 23, RDNA2, DCN 3.0.2)**, the market analog of the RTX 3060 — would take, and how it slots into danos's pluggable scanout architecture. It is a survey of primary sources (the Linux [amdgpu Display Core](https://github.com/torvalds/linux/tree/master/drivers/gpu/drm/amd/display) driver and its [kernel documentation](https://docs.kernel.org/gpu/amdgpu/display/index.html), the AtomBIOS interpreter in [drivers/gpu/drm/amd](https://github.com/torvalds/linux/tree/master/drivers/gpu/drm/amd), linux-firmware's `LICENSE.amdgpu`, and Haiku's [radeon_hd](https://github.com/haiku/haiku/tree/master/src/add-ons/kernel/drivers/graphics/radeon_hd)), not an implementation. It completes the trilogy with [nvidia-gpus.md](nvidia-gpus.md) and [intel-igpu.md](intel-igpu.md) and should be read against both — AMD lands *between* them: NVIDIA-class discrete-card mechanics, but Intel-class (better, in one way) reference material. Read [display.md](display.md) and [display-v2.md](display-v2.md) first — this doc assumes the v2 model where scanout is a **pluggable backend** and a native driver is just another `.scanout` service (like the virtio-gpu one), announcing to the compositor over `attach_scanout`. ## TL;DR - **AMD's decisive advantage is that the vendor's own display driver is the register manual, and it's MIT-licensed.** The entire Display Core (DC) — hardware sequencer, per-block code for OTG/OPTC, HUBP, DPP, MPC, DIO/link encoders, plus the `asic_reg` register headers — ships in the Linux tree under MIT/X11, deliberately written OS-agnostic because AMD shares it across operating systems. You can study it, port it, even copy from it into a danos driver without license contamination. NVIDIA has no analog (nouveau is GPL); Intel has PRM prose but you still write the code yourself. - **The firmware wall is one small blob, not a GSP.** The only display-side firmware the Linux driver hard-requires is **DMCUB** (the display microcontroller), and only on **DCN 2.1 through 4.x** — which includes Navi 23. It is redistributable from linux-firmware, and it is a display helper, not a full-card resource manager: on DCN 3.0.x, hardware init (`dcn30_init_hw`) is **host-driven direct register programming** — the only DMUB call in it is a capability query. All DCE generations, DCN 1.0 (Raven), and DCN 2.0 (Navi 10/12/14) run display with **no display firmware at all**. - **Whether the *silicon* (vs. the Linux driver) needs DMCUB for a bare GOP-inheriting modeset is unproven** — Linux fails init with `-EINVAL` if the blob is missing on a DMUB ASIC, but what it's *used for* at minimum scope (vs. PSR/ABM/offloaded DP link training) isn't documented. The safe plan ships the blob; it's legally and practically cheap to do so. - **Programming model is direct MMIO, not channel DMA.** DCN mode-set is ordered register-write sequences (the DC "hardware sequencer") against named, header-documented registers — no pushbuffers, no method streams, no RAMHT, no supervisor-interrupt handshake. This deletes the hardest structural layer of the NVIDIA path. - **Scanout is VRAM-only on discrete cards** — the claim that DCN can scan out of GTT/system memory was checked and *refuted* for dGPUs (Linux allows GTT scanout only on select APUs). So a small VRAM allocator + BAR CPU mapping is required, same as NVIDIA. Pitch-linear surfaces are supported; no DCC/tiling needed. - **danos's GOP boot helps here too, with a caveat.** DC explicitly models taking over a VBIOS/GOP-lit pipe (`dc_validate_boot_timing` reads back live DIG/OTG/pixel-clock state), so "repoint the surface on the running pipe" is demonstrably hardware-feasible — but Linux's seamless-boot path is **eDP-only and default-off on discrete cards**, so plan on a full self-owned modeset (including DP retrain) right after first light rather than living on the inherited link. - **AMD has real non-Linux prior art — but only for the old hardware.** Haiku's MIT `radeon_hd` mode-sets by executing VBIOS **AtomBIOS command tables** through AMD's own MIT interpreter; its compiled-in ceiling is **DCE 8.5 (Hawaii, ~2013)** — every Polaris/Vega/Navi entry sits in a `#if 0` block. There is zero non-Linux DCN precedent; a danos DCN driver would be first. - **Effort tier ≈ high-3 to 4** for a native DCN 3.0.x display-only driver on Navi 23 — the raw register surface is GA106-class (tier 4), but the MIT vendor reference, the one-blob firmware wall, and the absence of channel-DMA plumbing pull real risk out. The AtomBIOS-interpreter route is tier ≈ 3 but dead-ends at pre-2016 silicon. - **Recommendation:** the same sober conclusion as the other two docs — GOP already gives native-res scanout for zero code — but if danos ever does drive real discrete silicon natively, **an RDNA2 card is the best target of the three**: modern, mainstream, in-warranty hardware with a legally clean, vendor-authored reference. That combination exists nowhere else. ## The firmware wall (a fence, next to NVIDIA's wall) AMD GPUs carry a zoo of firmware: PSP (security processor), SMU (power/clock management), CP/RLC (graphics), SDMA, VCN (media) — and, on the display side, DMCU (legacy) then **DMCUB** ("Display Micro-Controller Unit, version B"), a per-generation blob in linux-firmware (`navi23_dmcub.bin` etc.). The display-only question is: which of these does a scanout driver actually need? The Linux answer is precise and readable in [`amdgpu_dm.c`](https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c): `dm_init_microcode()` switches on the display IP version — **DCN 2.1 (Renoir) through DCN 3.0.x / 3.1.x / 3.2 / 3.5 / 4.x** request a DMCUB blob as `AMDGPU_UCODE_REQUIRED`, and `dm_dmub_hw_init()` fails driver init with `-EINVAL` if it's absent. Everything earlier — **all of DCE (Southern Islands through Vega), DCN 1.0 (Raven), and DCN 2.0 (Navi 10/12/14)** — hits the `default:` case, `dmub_srv` stays NULL, and display runs with no display firmware at all ([kernel display-manager doc](https://docs.kernel.org/6.2/gpu/amdgpu/display/display-manager.html)). Two nuances survive verification: - **The requirement is Linux-driver enforcement backed by real functional need, and it's version-sensitive.** AMD force-switched all Renoir ASICs to DMUB to fix a USB-C/resume bug (kernel commit `652de07addd2`, "with new dmub f/w dmcu is superseded"), which regressed users on old blobs and had to be patched with explicit `dmcub_fw_version` gating (`91adec9e0709`). What DMUB is *used for* varies with blob version. Ship a current blob. - **DMCUB is an architectural fixture, not a bolt-on** — the DCN hardware itself contains a DMU block housing the microcontroller ([DCN overview](https://docs.kernel.org/gpu/amdgpu/display/dcn-overview.html)) — but it is **not a mediator of the programming model** on DCN 3.0: `dcn30_init_hw()` initializes clocks, disables power gating, and powers up link encoders via direct register writes; its sole DMUB interaction is `dc_dmub_srv_query_caps_cmd`. Firmware-*assisted* PHY/link bring-up appears from **DCN 3.1** onward — one more reason to target 3.0.x. Features like PSR and ABM are DMUB-offloaded on all generations; a minimal driver simply doesn't enable them. **Contrast with NVIDIA's GSP:** the GSP is a full resource manager with a signed multi-stage boot chain and a firmware ABI that breaks every driver release. DMCUB is a display helper blob you copy onto the boot image once, load into a reserved buffer, and mostly ignore. There is no signature fuse-matching, no WPR carve-out, no RPC-only register access. The one genuinely open question — whether a GOP-inheriting minimal modeset could skip DMCUB entirely on DCN 3.0.2 — doesn't need answering, because shipping the blob costs nothing (see [Licensing](#licensing)). **PSP/SMU remain the flagged risk.** Nothing display-only touches CP/RLC/SDMA (those gate the graphics rings, exactly like NVIDIA's PGRAPH — irrelevant here). But `dcn30_init_hw` calls into the clock manager, and on discrete cards the clock manager may message the SMU to change display clocks (DISPCLK/DPPCLK). Whether inherited GOP boot clocks suffice for a same-or-lower mode — avoiding SMU (and hence PSP firmware-load) entirely — is the largest unverified assumption in the milestone list below. The survey produced no confirmed claim either way. ## The display engine landscape Two eras, one boundary that matters: | Generation | Display IP | Cards | Display firmware | Route | |---|---|---|---|---| | GCN 1–4 (SI→Polaris) | DCE 6/8/10/11 | HD 7000 → RX 580 | none | AtomBIOS tables or direct DCE registers | | Vega / Raven | DCE 12 / DCN 1.0 | Vega 56/64, APUs | none | DC code (first DCN) | | Navi 1x (RDNA1) | DCN 2.0 | RX 5500–5700 | none | DC code | | Renoir APU | DCN 2.1 | 4000-series APUs | **DMCUB required** | DC code | | **Navi 2x (RDNA2)** | **DCN 3.0.x** | **RX 6600–6900** | **DMCUB required** | **DC code, host-driven init** | | RDNA3/RDNA4+ | DCN 3.1+/3.2/3.5/4.x | RX 7000/9000 | DMCUB required, fw-assisted PHY | DC code, more DMUB offload | The best modern first-pixel target is **DCN 3.0.x**: it has the full MIT block stack from the June 2020 Sienna Cichlid patch series (207 patches, Linux 5.9; Navi 23 reuses the dcn30 sequencer), host-driven hardware init, and sits *before* the DCN 3.1 shift toward firmware-assisted link management. Older DCE cards are even simpler (no firmware at all, plus the AtomBIOS escape hatch) but are 2013–2016 hardware; newer DCN 3.5/4.x pushes more into DMUB. The DCN pipe, in one line each (the vocabulary the DC code speaks — [programming model](https://docs.kernel.org/next/gpu/amdgpu/display/programming-model-dcn.html)): **HUBP** fetches and unpacks the surface from memory (this is where the scanout address and pitch live), **DPP** scales/converts colors, **MPC** blends planes (bypassable for one plane), **OPP** packs output, **OTG/OPTC** generates raster timings (the CRTC), and the **DIO** block's DIG encoders + PHY drive the connector. Mode-set is the DC *hardware sequencer* walking these blocks with ordered register writes — plain MMIO with polling, no pushbuffer channels, no supervisor interrupts. Structurally this is Intel-shaped, not NVIDIA-shaped. ## Two routes: AtomBIOS interpreter vs. native DC-derived registers **AtomBIOS** is AMD's VBIOS bytecode: every card's ROM carries *data tables* (connector topology, clock limits — the DCB equivalent) and *command tables* (`SetPixelClock`, `SetCRTC_Timing`, `EnableCRTC`, DIG encoder/transmitter control), executed by a small interpreter the driver embeds (`atom.c`, ~1.5k lines). The classic radeon driver and Haiku's `radeon_hd` mode-set this way: parse the tables, execute them, and the VBIOS does the register-level work for you — inherently per-board correct, since the tables come from the card's own ROM. - **Where it's proven:** through DCE 8.5 (Haiku's ceiling, below) and in Linux's pre-DC code through Polaris (DCE 11.2). AMD's interpreter itself is MIT (Haiku ships AMD's own `atom.cpp`, "Copyright 2008 Advanced Micro Devices"). - **Where it's unproven:** DCN. amdgpu's DC still *uses* AtomBIOS for init sub-steps (`bios_golden_init` in `dcn30_init_hw` executes host-interpreted tables) and reads the data tables for connector topology — but nobody drives a full DCN modeset from command tables, and whether RDNA2 VBIOSes still carry a complete modeset path or vestigial init-only tables is an open question no source answers. Do not bet on it. **The native route** is: port the relevant slice of DC. Not wholesale — in-tree DC has accumulated Linux-isms (kernel-FPU guards around DML, the bandwidth-calculation library, which a single-plane fixed-mode driver can largely sidestep) — but the DC core is *designed* to be retargeted: the kernel docs state outright that DC "is shared with other OSes" and holds the OS-agnostic hardware programming behind a `dm_services` shim (register access, memory, delays, firmware loading). Dave Airlie initially rejected the DAL/DC merge in 2016 *because* it was AMD's cross-OS codebase — hostile-witness confirmation that this exact code runs outside Linux. Reimplement the shim in Zig, and the dcn30 sequences sit on top. ## The memory floor Same shape as NVIDIA's, and the survey *hardened* one assumption: - **VRAM-only scanout on discrete cards.** The documented DCN fetch path is VRAM → Data Fabric (SDP) → DCHUB → HUBP; the claim that display buffers can live in GTT/system memory was refuted for dGPUs in verification — Linux permits GTT scanout only on select APUs. The NVIDIA doc's "maybe sysmem ctxdma?" hope has a firm *no* here. Budget for a small VRAM allocator. - **Pitch-linear is fine.** HUBP programs a surface address + pitch; linear (untiled, no DCC) surfaces are first-class for scanout. No tiling math. - **CPU access via the VRAM BAR.** Compositing writes go through the PCI VRAM aperture; resizable BAR helps but isn't needed — one pitch-linear surface fits comfortably in a fixed 256 MB small-BAR window. - **No GPU VMM.** Display addresses are physical VRAM addresses programmed into HUBP; no page tables, no GEM/TTM, no eviction. **Net:** (1) a contiguous aligned VRAM allocator, (2) a BAR CPU mapping, (3) a small reserved buffer for the DMCUB firmware regions. That's the whole memory story. ## Inheriting GOP state danos's GOP boot pays off again, with sharper edges than on NVIDIA: - **DC models pipe takeover explicitly.** `dc_validate_boot_timing()` ([dc.c](https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/amd/display/dc/core/dc.c)) reads back *live* hardware — `is_dig_enabled` on the link encoder, OTG timing registers, pixel clock within tolerance — and keeps the VBIOS/GOP-lit pipe running until first flip. This is a vendor-blessed recipe for milestone 2 below: the exact register set that tells you which pipe is alive and how it's configured. - **But Linux's seamless path is eDP-only and APU-gated.** The code comment is blunt: "Support seamless boot on EDP displays only", and the enabling check requires an APU with DCN ≥ 3.0 unless forced with `amdgpu.seamless=1`. On a discrete RX 6600 with DP/HDMI, Linux does a full modeset at takeover. Read that as a warning, not a prohibition: repointing HUBP at your own surface on the live pipe should still work (the readback code proves the state is inspectable), but plan the full self-owned modeset — **including DP retraining** — as the immediate next step, not a someday. - **No supervisor handshake exists to re-learn.** The NVIDIA doc's SV1/SV2/SV3 open question has no AMD counterpart; commit sequencing is ordered register writes + vblank/lock waits in the hwseq, all visible in MIT source. ## Licensing The inverse of the NVIDIA situation, and the single strongest argument for AMD: - **The reference code is MIT.** `amdgpu_dm.c` carries `SPDX-License-Identifier: MIT`; `dc/core/dc.c` and `dmub_srv.h` carry the full X11-style grant (use, copy, modify, merge, publish, distribute, sell). The `asic_reg` register headers ship under the same terms. One diligence note: SPDX tagging isn't uniform across the tree, so header-check each file before copying from it — but no GPL files are known inside `dc/`. Where nouveau forces a GPL-or-clean-room choice, here the *easy technical path and the permissive path are the same path*. - **Firmware redistribution is a solved problem.** linux-firmware's `LICENSE.amdgpu` grants anyone a royalty-free right to reproduce and distribute the blobs, binary-only, with the license text attached — no OSI-license gate like NVIDIA's, no AMD agreement needed. danos can ship `navi23_dmcub.bin` (and PSP/SMU blobs if ever needed) on its boot image today. The same license **prohibits reverse-engineering the blobs** — all programming knowledge must come from the MIT source, never from blob disassembly. (VBIOS images aren't in linux-firmware; they're read from the card's own ROM, as Haiku does.) - **Prose register docs are a DCE-era artifact.** AMD's classic X.Org-hosted PDFs cover the old families — and the famous `R6xx_3D_Registers.pdf` turns out to be 3D-only (verified: zero display content; the display material lives in the separate per-ASIC Register Reference Guides). For DCN there is **no prose display spec at all**: the MIT DC source plus the `asic_reg` headers *are* the register manual. Plan accordingly. ## Prior art AMD, unlike NVIDIA, has genuine working non-Linux precedent — with a hard generational ceiling: - **Haiku `radeon_hd`** (MIT, still in the tree): a real, shipping, from-scratch display driver that executes AtomBIOS command tables via AMD's own MIT interpreter. Verified ceiling: the last *enabled* device entry is **Hawaii (DCE 8.5, 0x67be)**; everything newer — Tonga/Fiji, Carrizo/Polaris, Vega/Raven, and every Navi/RDNA2 entry up to the RX 6900 XT — sits inside one `#if 0 /* disabled for R1/beta5 */` block under the comment "WARN: DCE versions below here get sketchy." - **AmigaOS/MorphOS RadeonHD drivers** (hdrlab): commercial non-Linux Radeon display drivers, again for the DCE era. - **FreeBSD** `drm-kmod`: a port of Linux amdgpu (DC and all), not independent prior art — but proof the DC codebase transplants. **Nobody has driven DCN outside Linux-derived code.** A danos DCN 3.0.x driver would be a first — but a first with the vendor's MIT code as its map, which is a different proposition from nouveau-as-only-reference. ## Alternatives | Option | What you get | The tradeoff | |---|---|---| | **Stay on GOP** (working today) | Native-res scanout, zero GPU code/firmware/maintenance | Resolution frozen at ExitBootServices; no runtime mode change, no hardware vsync, no multihead | | **AtomBIOS interpreter on an old DCE card** | Proven end-to-end (Haiku); interpreter is small + MIT; board-correct by construction | 2013–2016 hardware ceiling; tier ≈ 3; teaches AtomBIOS, not modern DCN | | **Native DCN 3.0.x on RX 6600** (this doc) | Runtime modeset, vsync, multihead on modern silicon; MIT vendor reference; one redistributable blob | Tier ≈ high-3–4; SMU/clock question open; no non-Linux precedent | | **Port DC wholesale** (reimplement `dm_services`) | Vendor-maintained sequences verbatim; designed-for-porting seam | Big codebase to carry (DML, abstractions); Linux-isms to shear off; overkill for one plane | | **RDNA3+/DCN 3.5+** | Newer cards | More DMUB offload (fw-assisted PHY from DCN 3.1); strictly harder than 3.0.x for no display-only gain | ## "First light" milestones (native DCN 3.0.x path) Framed as a danos `.scanout` service, inheriting the GOP-initialized display: 1. **PCI/BAR bring-up** — enumerate Navi 23, map the register BAR and the VRAM BAR via danos MMIO grants; prove the pipe is GOP-live by writing pixels into the *existing* GOP framebuffer through the VRAM BAR. 2. **Read back the live pipe** — port the `dc_validate_boot_timing` register set: which OTG is running, its timings, which DIG/link encoder is enabled, current HUBP surface address/pitch. This is pure reads — zero risk, high information. 3. **Repoint the surface** — allocate a danos-owned pitch-linear VRAM surface, program the HUBP surface address/pitch on the live pipe at vblank. First self-owned pixel with **no modeset, no firmware, no clock changes**. 4. **DMCUB bring-up** — load `navi23_dmcub.bin` (redistributed per `LICENSE.amdgpu`) into its reserved regions, minimal `dmub_srv` init, verify the caps query answers. 5. **Full owned modeset** — port the dcn30 hwseq slice: OTG timing programming, MPC bypass (single plane), DIG/PHY enable, **DP link retrain** (or start on HDMI to defer it, exactly as the NVIDIA doc advises). This is where the SMU/clock question lands — first attempt: reuse inherited boot clocks for a same-or-lower mode. 6. **EDID** — AUX (DP) / DDC (HDMI) over the DCN AUX engine registers; parse and build the mode list; connector topology from the VBIOS AtomBIOS data tables. 7. **Wire into the compositor** — `attach_scanout`, vsync from the vblank/pageflip interrupt, then multihead. Keep the GOP backend as the fallback the whole way — a stall at any step still leaves danos with a working display (the resilience v2 already provides via re-attach). ## Reading list **The DC core (MIT — the register manual for DCN):** - `drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c` — hardware init + the modeset sequencer for the target generation (host-driven; one DMUB caps query). - `dc/dcn30/` + `dc/dcn302/` blocks: `dcn30_hubp.c` (surface address/pitch — milestone 3), `dcn30_optc.c` (OTG timings), `dcn30_dio_link_encoder.c` (DIG/PHY), `dcn30_mpc.c` (bypass), `clk_mgr/dcn30/` (the SMU question, read before milestone 5). - `dc/core/dc.c` — `dc_validate_boot_timing()`: the GOP-takeover readback recipe. - `asic_reg/dcn/dcn_3_0_0_{offset,sh_mask}.h` — every register name and bitfield. - `dmub/` (`dmub_srv.h`, `src/dmub_dcn30.c`) — firmware regions + bring-up for milestone 4. **The Linux glue (for logic, not porting):** [`amdgpu_dm.c`](https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c) — `dm_init_microcode` / `dm_dmub_hw_init` (the firmware-wall switch), seamless-boot gating. **Kernel docs (read first):** [DCN overview](https://docs.kernel.org/gpu/amdgpu/display/dcn-overview.html) (the block diagram + VRAM→DF→DCHUB fetch path) · [DC programming model](https://docs.kernel.org/next/gpu/amdgpu/display/programming-model-dcn.html) (dc_plane/dc_stream/dc_link objects, hwseq, block APIs) · [display manager](https://docs.kernel.org/6.2/gpu/amdgpu/display/display-manager.html). **AtomBIOS:** `drivers/gpu/drm/amd/amdgpu/atom.c` (the interpreter), `atombios.h` (table formats), [osdev AMD AtomBIOS](https://wiki.osdev.org/AMD_Atombios) (hobby-OS orientation), Haiku [`radeon_hd`](https://github.com/haiku/haiku/tree/master/src/add-ons/kernel/drivers/graphics/radeon_hd) (a complete worked example, MIT, through DCE 8.5). **Licensing:** linux-firmware [`LICENSE.amdgpu`](https://github.com/endlessm/linux-firmware/blob/master/LICENSE.amdgpu); DCE-era prose specs at [x.org/docs/AMD](https://www.x.org/docs/AMD/) (Register Reference Guides — display; note `R6xx_3D_Registers.pdf` is 3D-only). ## Open questions (unresolved by the survey) - **Does DCN 3.0.2 silicon need DMCUB for a bare inherit-and-modeset path**, or only for PSR/ABM/offloaded features? (Moot if the blob is shipped regardless — but it decides whether milestone 3 can precede milestone 4.) - **Can a display-only driver avoid PSP and SMU entirely** by inheriting GOP boot clocks — what does the dcn30 clock manager actually require from SMU messaging on Navi 23 for a same-or-lower mode? *The largest open risk in the plan.* - **Do RDNA2 VBIOS command tables still carry a complete modeset path**, or are they vestigial init-only tables? (Would open a Haiku-style route on modern cards; no source answers it.) - **Is the DCN 3.0 AUX/DDC engine and DP retrain fully host-drivable without DMUB**, as `dcn30_hwseq` implies? - Exact HUBP surface alignment/pitch constraints for linear scanout on Navi 23 (in the headers; not captured verbatim in the survey). --- *Research snapshot (2026-07); findings pinned to Linux master and Haiku master as of the survey date. DMUB coverage only grows with new DCN generations — re-verify the firmware-wall switch in `amdgpu_dm.c` against current source before building.*