docs: native GPU driver feasibility studies (NVIDIA + Intel)
Two companion research snapshots on what a minimal display-only native driver (EDID + mode-set + framebuffer scanout, no acceleration) would take as a danos .scanout backend, and how the two vendors compare. - nvidia-gpus.md — RTX 3060 (Ampere GA106). Display is not GSP-gated: nouveau's ga102.c has a direct register path, and danos's GOP boot lets a driver attach to a live, already-devinit'd display. Tier-4 effort; the register-level display code lives in GPL nouveau while the permissive OGKM reference is the hard GSP path. GA10x is the last NVIDIA family that keeps a register-level display path. - intel-igpu.md — the companion, and a materially easier, lower-tier target. Intel publishes register-level Display Engine PRMs, so a clean-room permissive driver is viable; the DMC microcontroller is optional (power states only), scanout comes from system RAM via the GGTT (no VRAM manager), and coreboot's libgfxinit is a compact native reference. The catch is hardware: an iGPU may not drive the monitor on a discrete-GPU desktop. Sourced, cited snapshots — not implementations; each ends with a "first light" milestone ladder framed as a danos .scanout service. Not yet linked from docs/README.md.
This commit is contained in:
@@ -0,0 +1,556 @@
|
|||||||
|
# Native Intel iGPU display support — feasibility and roadmap
|
||||||
|
|
||||||
|
**Status: research snapshot, not implemented.** This records what a *minimal, display-only*
|
||||||
|
native driver for an **Intel integrated GPU** — EDID read + mode-set + framebuffer scanout, with
|
||||||
|
**no** 3D/media/compute — would take, and how it slots into danos's pluggable scanout
|
||||||
|
architecture. It is a survey of primary sources (Intel's open-source
|
||||||
|
[Programmer's Reference Manuals](https://www.intel.com/content/www/us/en/docs/graphics-for-linux/developer-reference/1-0/overview.html),
|
||||||
|
coreboot's [libgfxinit](https://doc.coreboot.org/gfx/libgfxinit.html), the Linux
|
||||||
|
[i915 display](https://github.com/torvalds/linux/tree/master/drivers/gpu/drm/i915/display) driver,
|
||||||
|
and Haiku's [intel_extreme](https://github.com/haiku/haiku/tree/master/src/add-ons/kernel/drivers/graphics/intel_extreme/)),
|
||||||
|
not an implementation. It is the companion to [nvidia-gpus.md](nvidia-gpus.md) and should be read
|
||||||
|
against it — the two answer the same question for opposite silicon.
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
- **Intel is a materially easier, lower-tier target than the NVIDIA RTX 3060 — and the reason is
|
||||||
|
documentation, not silicon.** Intel publishes official, register-level, per-platform **Display
|
||||||
|
Engine** PRMs with named registers, bitfields, and numbered enable sequences; NVIDIA publishes
|
||||||
|
no display PRM and forces reverse-engineering against GPL nouveau. A minimal Intel display-only
|
||||||
|
driver is roughly **tier 2 to low-tier 3** for well-covered generations (Skylake / Kaby Lake /
|
||||||
|
Coffee Lake), versus NVIDIA's **tier 4** for GA106. This is the load-bearing conclusion.
|
||||||
|
- **The display block is a genuinely separable register domain.** Mode-set + scanout touch only
|
||||||
|
display registers (pipes, planes, transcoders, DDI buffers, PLLs, power wells, GMBUS/AUX) — **no
|
||||||
|
render engine, no command streamer, no GEM/3D, no signed microcode.** Two small carve-outs, both
|
||||||
|
trivial pokes that do *not* pull in the render engine: a real CDCLK frequency change writes the
|
||||||
|
shared GT PCODE mailbox, and the plane's surface register is a GGTT (memory-interface) address.
|
||||||
|
- **There is no firmware wall on the display path.** The only display microcontroller (DMC / "CSR",
|
||||||
|
Skylake+) is **optional** — its sole job is saving/restoring display state across DC5/DC6
|
||||||
|
low-power idle. Without it, i915 prints "Disabling runtime power management" and mode-sets and
|
||||||
|
scans out normally. GuC/HuC are render/media coprocessors, never touched by a display driver.
|
||||||
|
Pre-Skylake parts have no display microcontroller at all yet mode-set fine. There is **nothing
|
||||||
|
analogous to NVIDIA's GSP**.
|
||||||
|
- **The scanout memory model is dramatically simpler than a discrete GPU.** Intel iGPUs have **no
|
||||||
|
VRAM**: the display scans out of ordinary system RAM addressed through the Global GTT (GGTT), a
|
||||||
|
flat single-level page table. Linear (untiled) framebuffers are first-class. You need **no
|
||||||
|
GEM/TTM, no VMM, no VRAM allocator, no BAR1 aperture juggling** — the exact machinery the NVIDIA
|
||||||
|
path forces on you.
|
||||||
|
- **coreboot libgfxinit is a compact, complete, display-only reference** doing precisely this scope
|
||||||
|
(EDID + PLL/mode-set + scanout, zero 3D) in ~22k lines of formally-analysed SPARK/Ada — versus
|
||||||
|
i915's ~400k lines. It is a *read-and-reimplement* reference, not drop-in code (GPL-2.0-or-later,
|
||||||
|
and Ada, not Zig).
|
||||||
|
- **The clean-room, permissively-licensed path is real** — you can implement from the PRM without
|
||||||
|
reading GPL code, and Haiku's MIT `intel_extreme` is a permissive precedent. This is the decisive
|
||||||
|
contrast with NVIDIA, where no vendor register spec exists.
|
||||||
|
- **The practical catch is hardware, not software.** On a desktop with an RTX 3060, the monitor is
|
||||||
|
almost certainly cabled to the *card*, so an iGPU driver would light a dark motherboard port; the
|
||||||
|
CPU may be an **F-SKU with the iGPU fused off entirely**; and every clean-room reference targets
|
||||||
|
*older* Intel. Intel is the right target to **learn** display bring-up — "run it on my machine"
|
||||||
|
is a separate, machine-dependent question that may not resolve in the reader's favour.
|
||||||
|
- **Recommendation:** as with the NVIDIA doc, GOP already gives native-resolution scanout with zero
|
||||||
|
GPU code. A native Intel driver buys runtime mode changes, hardware vsync, and multihead — and it
|
||||||
|
reaches "first pixel" far faster than the NVIDIA path *if* the target machine actually has a
|
||||||
|
usable, cable-attached iGPU of a documented generation.
|
||||||
|
|
||||||
|
## Display engine architecture, and why it's separable
|
||||||
|
|
||||||
|
For the common single-display path (SST DisplayPort / HDMI / eDP), the Intel display data flow is a
|
||||||
|
small, fully documented, essentially fixed sequence:
|
||||||
|
|
||||||
|
```
|
||||||
|
memory surface → PLANE(s) → PIPE → TRANSCODER → DDI (drives IO/PHY) → connector
|
||||||
|
```
|
||||||
|
|
||||||
|
The Tiger Lake PRM Vol 12 states it verbatim: *"The front end of the display contains the pipes.
|
||||||
|
The pipes connect to the transcoders. The transcoders, except for wireless, connect to the DDIs to
|
||||||
|
drive the IO/PHY."* A **pipe** blends planes (primary/sprite/cursor) into one raster stream; the
|
||||||
|
**transcoder** wraps it in port-protocol timing (DP/HDMI/eDP/DSI); the **DDI** is the physical port
|
||||||
|
and PHY. Pipe, Planes, Transcoder, and Digital Display Interface are each first-class PRM chapters
|
||||||
|
with per-object files in libgfxinit
|
||||||
|
([TGL PRM Vol 12](https://cdrdv2-public.intel.com/705833/intel-gfx-prm-osrc-tgl-vol-12-display-engine.pdf)).
|
||||||
|
|
||||||
|
**Two honest qualifications** the raw research overstated (per verification):
|
||||||
|
|
||||||
|
- The pipeline is *not* strictly linear in all cases — the same PRM pages document optional branches
|
||||||
|
a minimal driver simply ignores (wireless writeback to memory, MIPI DSI, DisplayPort multistream
|
||||||
|
many-to-one, DSC/tiled pipe-joining). Ignoring them does not weaken feasibility.
|
||||||
|
- The four-object model *as named* is **Haswell-onward** (DDI introduced ~2013), not "every gen."
|
||||||
|
Pre-Haswell used FDI + PCH transcoders + port-specific encoders. Within the modern iGPU range
|
||||||
|
danos would realistically target (Skylake → Meteor/Lunar Lake) the model is stable.
|
||||||
|
|
||||||
|
**The DPLL/clock block is a separate, per-port programmable clock source** and is one of the harder,
|
||||||
|
most gen-specific pieces: pick/enable a PLL, route its output to the DDI, then bring up the port.
|
||||||
|
The register layout and divider math change substantially per generation — pre-SKL SPLL/WRPLL/LCPLL,
|
||||||
|
Skylake+ shared DPLL0–3, Gen11+ combo-PHY plus Type-C MG/DKL PLLs. Pixel-clock computation is a
|
||||||
|
classic per-gen rewrite.
|
||||||
|
|
||||||
|
### Separable from render — the single most important enabler
|
||||||
|
|
||||||
|
The display is a distinct register domain from render/media, and this is confirmed at the primary
|
||||||
|
level: the TGL PRM ships display as its own volume (Vol 12), separate from Render Engine (Vol 9) and
|
||||||
|
Media (Vol 11); Linux's KMS "is provided by Intel Display Driver, and **shared with drm/xe**"
|
||||||
|
([kernel.org i915](https://docs.kernel.org/gpu/i915.html)) — i.e. the display module is
|
||||||
|
reused across two different GPU drivers. A full mode-set lights a display end-to-end using only power
|
||||||
|
wells, PLL/port-clock, DDI-buffer/PHY, transcoder and pipe registers — **zero render commands, zero
|
||||||
|
GEM objects, zero command-streamer.** libgfxinit is decisive proof: complete EDID + modeset +
|
||||||
|
framebuffer with no render/3D code at all.
|
||||||
|
|
||||||
|
Two carve-outs the "touches ONLY display registers" phrasing needs (per verification), **neither of
|
||||||
|
which drags in the render engine**:
|
||||||
|
|
||||||
|
1. A mode-set that changes the **Core Display Clock (CDCLK)** frequency/voltage pokes the shared **GT
|
||||||
|
Driver Mailbox** (PCODE/PCU power-controller interface), per Vol 12's own "Display Voltage
|
||||||
|
Frequency Switching" step. A trivial register handshake, documented alongside the display sequence.
|
||||||
|
2. The primary plane's surface register (`PLANE_SURF`) holds a **GGTT graphics address** (a
|
||||||
|
memory-interface concept, not covered in Vol 12). Using pre-mapped stolen memory — as libgfxinit
|
||||||
|
does — sidesteps any active GGTT programming. See [Memory and scanout](#memory-and-scanout).
|
||||||
|
|
||||||
|
### Per-gen churn: what's stable, what you rewrite
|
||||||
|
|
||||||
|
The **object model** (pipes/planes/transcoders/DDIs, GMBUS-for-EDID, double-buffered plane registers
|
||||||
|
armed atomically) is conceptually stable from Ironlake/Haswell through Tiger Lake. What you rewrite
|
||||||
|
per generation is:
|
||||||
|
|
||||||
|
1. the **CPU-vs-PCH split and interconnect**,
|
||||||
|
2. the **port/PHY + DPLL** programming,
|
||||||
|
3. **register offsets + power-well / CDCLK topology**, and
|
||||||
|
4. the **mode-set enable sequence itself** (power-well ordering, PLL lock, DDI-buffer enable,
|
||||||
|
transcoder clock-select) — an effective fourth axis the raw research folded into (1)/(2).
|
||||||
|
|
||||||
|
Interconnect eras, with the timeline **corrected** (the cited Haiku doc was chronologically loose):
|
||||||
|
|
||||||
|
- **Gen5 Ironlake (2010) → Ivy Bridge:** FDI (Flexible Display Interface) links the CPU display
|
||||||
|
engine to PCH-resident ports. The FDI/PCH-split era begins at **Ironlake**, not Gen7.
|
||||||
|
- **Haswell (Gen7.5):** the main digital outputs come **back onto the CPU die as DDIs** (DDI A = eDP)
|
||||||
|
— the *opposite* of "moving output to the PCH," and it collapses the FDI/PCH dance **for the
|
||||||
|
digital ports only**. FDI is **retained** for the legacy VGA/CRT path (DDI E → PCH CRT DAC), so a
|
||||||
|
driver gets the single DDI code path only by omitting analog VGA (which a minimal driver does).
|
||||||
|
- **Skylake (Gen9):** reworks clock/PLL, CDCLK, and the power-well model; introduces the optional DMC.
|
||||||
|
- **Gen11 Ice Lake / Gen12 Tiger Lake:** add combo-PHY + USB-Type-C/Thunderbolt MG/DKL PHYs — the
|
||||||
|
single biggest cost increase, and the reason "newest silicon" is *not* the easiest target. (DSC is
|
||||||
|
documented per-**pipe**; MSO is an eDP feature — not "per-transcoder" as the raw research said.)
|
||||||
|
|
||||||
|
### The tractable sweet spot
|
||||||
|
|
||||||
|
The documented, tractable sweet spot for a from-scratch display-only driver is the
|
||||||
|
**Haswell (Gen7.5) / Broadwell (Gen8) DDI family, with Skylake (Gen9) as the modern-hardware pick**
|
||||||
|
since it shares the same DDI object model. Rationale:
|
||||||
|
|
||||||
|
- Broadwell has a complete, freely downloadable
|
||||||
|
[PRM Vol 11 Display](https://cdrdv2-public.intel.com/690828/intel-gfx-prm-osrc-bdw-vol-11-display.pdf);
|
||||||
|
its engine (3 pipes A/B/C, 4 transcoders incl. transcoder-EDP that floats onto any pipe, DDI A–E,
|
||||||
|
WRPLL/SPLL/LCPLL) is the classic "DDI + transcoder + WRPLL" model.
|
||||||
|
- It predates the combo-PHY / Type-C / MG-DKL complexity of Ice Lake / Tiger Lake.
|
||||||
|
- libgfxinit's DDI **connector/EDID/DP layer is uniform from Haswell through Coffee Lake**, so the
|
||||||
|
hardest-to-get-right port logic generalises widely.
|
||||||
|
|
||||||
|
Two supporting claims from the raw research are **wrong and corrected here (verification):**
|
||||||
|
|
||||||
|
- **The BDW and SKL PRMs are NOT 0BSD-licensed.** Both carry a Creative Commons
|
||||||
|
**Attribution-NoDerivatives** notice. Only the *newer* OSRC PRMs (Tiger Lake 2021 onward) put their
|
||||||
|
embedded code samples under **Zero-Clause BSD**. So for the recommended Haswell/Broadwell/Skylake
|
||||||
|
generations there are no "copy-pasteable 0BSD code samples" — the legal basis is *reimplementation
|
||||||
|
from a CC-BY-ND spec* (register facts are not copyrightable), not copying.
|
||||||
|
- **FDI+PCH is not fully eliminated on Haswell/Broadwell.** The BDW PRM keeps FDI for the DDI E → PCH
|
||||||
|
CRT DAC. The "one DDI code path" holds only for the digital outputs a minimal driver targets.
|
||||||
|
|
||||||
|
Sandy/Ivy Bridge (Gen6/7) is where the hobby-doc walkthroughs concentrate (the OSDev GMBUS/EDID
|
||||||
|
material) but carries the FDI+PCH split cost. *(Low confidence on the OSDev specifics — the wiki
|
||||||
|
returns 403 to automated fetches and its "guaranteed to work" phrasing is a hobby assertion, not a
|
||||||
|
silicon guarantee.)*
|
||||||
|
|
||||||
|
## Documentation — and the clean-room question
|
||||||
|
|
||||||
|
This is the crux of the whole comparison. **Intel hands you the register spec that NVIDIA withholds.**
|
||||||
|
|
||||||
|
- The Tiger Lake **"Vol 12: Display Engine"** PRM is a real, first-party, open-source document —
|
||||||
|
**433 pages, verified by direct download** — with named registers + addresses + bitfield tables
|
||||||
|
(`TRANS_DDI_FUNC_CTL`, `DDI_BUF_CTL`, `DP_TP_CTL`, `PLANE_STRIDE`, `DPLL_CFGCR0/1`, `CDCLK_CTL`,
|
||||||
|
`PWR_WELL_CTL_DDI`, …) and **numbered, step-by-step enable sequences** with explicit writes, wait
|
||||||
|
conditions, and microsecond timeouts. It even includes the "magic value" tables older PRMs deferred
|
||||||
|
to the driver (DisplayPort PLL DCO/divider values; voltage-swing/de-emphasis in mV). *"A spec you
|
||||||
|
could write a driver from directly"* is well-supported, not hyperbole
|
||||||
|
([TGL Vol 12](https://cdrdv2-public.intel.com/705833/intel-gfx-prm-osrc-tgl-vol-12-display-engine.pdf)).
|
||||||
|
- **Clean-room, permissively-licensed implementation is legally and practically feasible from the
|
||||||
|
PRM alone.** CC-BY-ND governs redistribution of the *document*; register addresses and bit
|
||||||
|
definitions are functional facts, and original code implementing a described hardware interface is
|
||||||
|
not a derivative of the PDF. *(This is standard copyright reasoning, not adjudicated case law —
|
||||||
|
treat it as well-grounded, not settled.)* Two independent implementations already exist built
|
||||||
|
essentially from these docs (libgfxinit, Haiku), so the spec is demonstrably sufficient.
|
||||||
|
|
||||||
|
**The documentation ceiling — corrected.** The raw research said public PRMs stop "roughly at Ice
|
||||||
|
Lake / Tiger Lake." Verification refuted this: full public **"Vol 12 Display Engine"** PRMs exist for
|
||||||
|
Ice Lake, Lakefield, Tiger Lake, Rocket Lake, DG1, **and DG2/Arc "Alchemist" (Gen12.5, 2022)** —
|
||||||
|
[the ACM display PRM is public](https://www.x.org/docs/intel/ACM/intel-gfx-prm-osrc-acm-vol12-displayengine.pdf).
|
||||||
|
The genuine cliff is **Meteor Lake (2023) and newer**: those have only a high-level architecture
|
||||||
|
overview, no register-level display PRM, and i915 references their display registers by opaque
|
||||||
|
internal **Bspec numeric IDs**. Alder Lake and Raptor Lake iGPUs are Gen12 Xe-LP display — the same
|
||||||
|
IP as Tiger Lake — so despite lacking a dedicated PRM they are effectively covered by the TGL PRM.
|
||||||
|
|
||||||
|
Net: a from-docs driver can confidently target **Skylake through DG2/Arc**, which is essentially the
|
||||||
|
entire current laptop/NUC installed base; only Meteor Lake and later slide back toward the NVIDIA
|
||||||
|
situation (reverse-engineering or reading GPL i915). The PRMs also survived 01.org's shutdown and are
|
||||||
|
mirrored in several stable places (Intel's cdrdv2 host, the
|
||||||
|
[Igalia CC-BY-ND archive](https://github.com/Igalia/intel-osrc-gfx-prm) for Gen4–Gen9.5,
|
||||||
|
[kiwitree](https://kiwitree.net/~lina/intel-gfx-docs/prm/), x.org) — not a single point of failure.
|
||||||
|
*(Note: the Igalia archive stops at Kaby Lake and contains no Display Engine volume; the TGL/DG2
|
||||||
|
display PRMs are separate Intel/x.org downloads.)*
|
||||||
|
|
||||||
|
## coreboot libgfxinit — the native reference
|
||||||
|
|
||||||
|
[libgfxinit](https://doc.coreboot.org/gfx/libgfxinit.html) is the closest thing to a template danos
|
||||||
|
could ask for: a self-contained **native modeset library** (no VBIOS/int10, no firmware blobs) that
|
||||||
|
probes displays via EDID over DDC/I²C and DP AUX, and drives LVDS, eDP, DP1–3, HDMI1–3, analog VGA,
|
||||||
|
plus USB-C DP/HDMI alt-mode on Tiger Lake. It sets up pipes (Primary/Secondary/Tertiary), planes,
|
||||||
|
transcoders, PLLs, panel power/backlight, the GTT, and framebuffer scanout — **display-only, zero
|
||||||
|
3D/media/compute**, which is exactly danos's scope. Its public entry is essentially
|
||||||
|
`Initialize()` then `Update_Outputs(Pipe_Configs)`, where each `Pipe_Config` carries
|
||||||
|
`{Port, Framebuffer, Cursor, Mode}` — a near-perfect fit for a pluggable scanout backend.
|
||||||
|
|
||||||
|
Why it beats i915 as a reference (**verified by measurement**): **131 Ada source files, ~818 KB,
|
||||||
|
~22k code lines** across *all* generations, factored precisely along the axes you care about (`edid`,
|
||||||
|
`dp_aux`, `dp_training`, `pipe_setup`, `transcoder`, `plls`, `connectors`, `port_detect`), with
|
||||||
|
**none** of the DRM/KMS/GEM/TTM, GT/3D, RC6/RPS, or GuC/HuC machinery that makes
|
||||||
|
`drivers/gpu/drm/i915` **~419k lines / 900 files / 12 MB**. (A grep confirms *zero* gem/ttm/guc/huc/
|
||||||
|
execbuf identifiers in the tree.) It depends only on a small HW-access shim, `libhwbase`
|
||||||
|
(`HW.PCI`, `HW.Port_IO`, `HW.MMIO`, `HW.Time`), which maps naturally onto danos's MMIO-grant + IPC
|
||||||
|
primitives — you provide Zig equivalents and the modeset logic sits on top. *(Correction to the raw
|
||||||
|
research: the widely-quoted "~13–14k LOC" is only the generic `common/` layer; the eight
|
||||||
|
per-generation subdirs roughly double it.)*
|
||||||
|
|
||||||
|
**It is a read-and-reimplement reference, not drop-in code.** Two hard constraints:
|
||||||
|
|
||||||
|
- **License is GPL-2.0-or-later** (the COPYING file is GPLv2; per-file headers add "or any later
|
||||||
|
version"). The CC-BY-4.0 on the docs *site* is a footer, not the source license. Copyleft applies
|
||||||
|
to ported code.
|
||||||
|
- **It is SPARK/Ada, and designed to run as coreboot boot-firmware**, not a runtime OS driver. A
|
||||||
|
danos port means either an Ada/GNAT toolchain in the build or hand-transliteration into Zig; the
|
||||||
|
SPARK "absence of runtime errors" proof does **not** carry over to your reimplementation (and note
|
||||||
|
it proves absence of runtime errors, **not** functional modeset correctness).
|
||||||
|
|
||||||
|
Two more caveats worth knowing: its **error handling is limited** — "only the case that no display
|
||||||
|
could be found counts as failure"; a later DP link-training failure is *not* propagated. And its
|
||||||
|
**verified-in-coreboot** hardware list stops at **Coffee Lake + Apollo Lake**, even though the tree
|
||||||
|
contains a `tigerlake/` directory (Ice Lake has no directory at all, and Alder Lake support is only
|
||||||
|
"begun"). So treat Haswell..Coffee Lake as the trustworthy transliteration window and TGL as
|
||||||
|
present-but-less-proven.
|
||||||
|
|
||||||
|
The orchestration reads as a clean state machine (`hw-gfx-gma.adb` `Enable_Output`):
|
||||||
|
`Fill_Port_Config → Preferred_Link_Setting → PLLs.Alloc → [retry] Connectors.Pre_On →
|
||||||
|
Display_Controller.On → Connectors.Post_On`, with a literal *"try each DP-lane configuration twice"*
|
||||||
|
inner retry and an outer link-setting step-down. `hw-gfx-dp_training.adb` (398 lines) is a complete,
|
||||||
|
generic DP link-training implementation (TP1/TP2/TP3, CR + EQ loops, swing/pre-emphasis adjust from
|
||||||
|
sink status). Per-generation buffer translations plug in underneath via
|
||||||
|
`Program_Buffer_Translations`, gated on `Config.Has_DDI_Buffer_Trans`. All of this was confirmed
|
||||||
|
against the source line-by-line.
|
||||||
|
|
||||||
|
## The EDID + mode-set path (Haswell/Broadwell target)
|
||||||
|
|
||||||
|
The whole path is memory-mapped register programming with polled status bits — no command ring, no
|
||||||
|
microcode, no DMA channel.
|
||||||
|
|
||||||
|
**EDID over DDC (GMBUS).** Pure MMIO poking of the GMBUS I²C controller (`GMBUS0`–`GMBUS5`): `GMBUS0`
|
||||||
|
selects pin-pair/port + clock; `GMBUS1` carries slave address (`0x50` for EDID), byte count,
|
||||||
|
direction, SW-ready; `GMBUS2` exposes HW-ready/NAK/ACTIVE to poll; `GMBUS3` is a 4-byte data FIFO;
|
||||||
|
`GMBUS5` gives the 2-byte segment index for E-DDC. A read is: write `GMBUS0`, write `GMBUS1`
|
||||||
|
(`CYCLE_WAIT | count | SLAVE_READ | SW_RDY | slave<<addr`), loop {poll `HW_RDY`, read 4 bytes}, then
|
||||||
|
STOP ([i915 intel_gmbus.c](https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/i915/display/intel_gmbus.c)).
|
||||||
|
|
||||||
|
**EDID + DPCD over DP AUX.** For DisplayPort/eDP, EDID (as I²C-over-AUX to `0x50`) and all DPCD
|
||||||
|
capability/link-status registers are read over the AUX channel: per-DDI `DDI_AUX_CTL` + 5×
|
||||||
|
`DDI_AUX_DATA`. Build a 3–5 byte header + payload, set SEND_BUSY, poll it clear, read
|
||||||
|
DONE/TIMEOUT/RECEIVE_ERROR. Message size 1–20 bytes; spec requires ≥3 retries. On Haswell/BDW the AUX
|
||||||
|
clock divider is programmed explicitly; SKL+ derive it automatically
|
||||||
|
([i915 intel_dp_aux.c](https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/i915/display/intel_dp_aux.c)).
|
||||||
|
Both GMBUS and DP-AUX live in libgfxinit's shared `common/` — cheap and nearly gen-invariant.
|
||||||
|
|
||||||
|
**The mode-set is a fixed, documented register sequence.** The Broadwell DisplayPort enable order
|
||||||
|
(verbatim from BDW PRM Vol 11, pp.98–99): (1) DDI lane capability; (2) panel power sequencing if
|
||||||
|
needed; (3) enable the CPU display PLL (WRPLL/SPLL) and wait ~20 µs; (4) Port Clock Select → DDI,
|
||||||
|
enable `DP_TP_CTL` with training pattern 1, configure `DDI_BUF_TRANS`, enable `DDI_BUF_CTL`, wait
|
||||||
|
>518 µs, run link training, set `DP_TP_CTL` to Normal (Idle first for eDP); (5) Transcoder Clock
|
||||||
|
Select, enable the plane, panel fitter if needed, program transcoder timings + M/N/TU, enable
|
||||||
|
`TRANS_DDI_FUNC_CTL`, enable `TRANS_CONF`, then backlight. Disable is the exact reverse — a bounded
|
||||||
|
checklist.
|
||||||
|
|
||||||
|
**DisplayPort/eDP link training is driver-driven in software over AUX** — the CPU runs the
|
||||||
|
clock-recovery and channel-equalization state machines by hand; it is **not** offloaded to a hardware
|
||||||
|
sequencer or firmware. The source side exposes only primitives: `DP_TP_CTL` selects the training
|
||||||
|
pattern the port emits; `DDI_BUF_CTL`/`DDI_BUF_TRANS` set voltage-swing/pre-emphasis. The driver
|
||||||
|
loops: emit pattern + set source levels → write `TRAINING_PATTERN_SET` (DPCD 0x102) + `TRAINING_LANEx_SET`
|
||||||
|
(0x103) over AUX → delay (100 µs CR / 400 µs EQ) → read `LANE_STATUS` → on failure adjust to the
|
||||||
|
sink's `ADJUST_REQUEST` values and retry. A few hundred lines of ordinary CPU/AUX code (libgfxinit
|
||||||
|
`Train_DP`: CR loop 1..32, EQ loop 1..6). **This is the single fiddliest, most fragile piece** — a
|
||||||
|
TMDS/HDMI panel avoids it entirely, and targeting an already-lit eDP panel avoids most of it.
|
||||||
|
|
||||||
|
**The clock (WRPLL) is documented divider math, not a magic table.** On Haswell/BDW the WRPLL derives
|
||||||
|
the symbol clock from a 2700 MHz LCPLL reference through R2/N2/P dividers with VCO 2400–4800 MHz —
|
||||||
|
small integer arithmetic. DP is *easier* than HDMI because it runs at a few fixed link rates (1.62 /
|
||||||
|
2.7 / 5.4 GHz), so a DP/eDP-only minimal driver can often use fixed rates and skip most of the search.
|
||||||
|
|
||||||
|
**Plane/scanout programming is trivial for a compositor.** The primary plane is `PRI_CTL`
|
||||||
|
(enable + pixel format), `PRI_STRIDE`, `PRI_SURF` (surface base — writing it triggers the atomic
|
||||||
|
update), `PRI_OFFSET`; formats include 32-bit BGRX 8:8:8 and 16-bit BGRX 5:6:5 — a direct match for a
|
||||||
|
linear XRGB compositor buffer. Plane registers are double-buffered and latch at vblank via an
|
||||||
|
**arming** write — so a page-flip is "write base + stride + size, then the arming write." This is
|
||||||
|
*exactly* the primitive danos's damage-driven compositor already expresses over GOP/virtio-gpu; the
|
||||||
|
incremental work is "program these display-domain registers," not a new scanout model. The panel
|
||||||
|
fitter (`PF_WIN_POS`/`PF_WIN_SZ`/`PF_CTRL`) can be left disabled for native-resolution scanout;
|
||||||
|
Skylake+ replaces it with a shared pipe-scaler (`PS_CTRL`).
|
||||||
|
|
||||||
|
**Smallest useful target:** eDP (DDI A / transcoder-EDP) or a single DP output at native resolution,
|
||||||
|
panel fitter off, plane in 32bpp XRGB. That is: GMBUS + I²C-over-AUX EDID/DPCD, one fixed-rate or
|
||||||
|
WRPLL config, the ~20-step enable sequence, the software CR/EQ loop, and `PRI_*` plane setup with
|
||||||
|
`PRI_SURF`-write flips. Out of scope: 3D, media, tiling, RC6/power-gating, PSR, audio.
|
||||||
|
|
||||||
|
## Memory and scanout
|
||||||
|
|
||||||
|
This is where Intel's *architecture* — not just its docs — makes the job smaller, and it is the
|
||||||
|
biggest single simplification versus a discrete GPU.
|
||||||
|
|
||||||
|
- **No VRAM.** Intel iGPUs have a unified memory architecture; the display scans out of ordinary
|
||||||
|
**system RAM** addressed through the **Global GTT (GGTT)**. The only way to give the GPU memory is
|
||||||
|
to bind system pages into the GGTT
|
||||||
|
([i915/GEM crashcourse](https://blog.ffwll.ch/2012/10/i915gem-crashcourse.html)).
|
||||||
|
- **The plane surface register is a GGTT offset**, not a raw physical address — the display walks the
|
||||||
|
GGTT to fetch pixels, so a scanout buffer must be GGTT-mapped (global, not per-process). libgfxinit
|
||||||
|
writes the framebuffer offset straight into `DSPSURF`/`PLANE_SURF` masked to 4 KB.
|
||||||
|
- **Linear (untiled) scanout is a first-class supported mode** — the plane's tiling field value 0 is
|
||||||
|
Linear. No X/Y/Yf tiling engine is needed for a display-only driver. (UEFI GOP itself hands off a
|
||||||
|
linear framebuffer the plane is already scanning.)
|
||||||
|
- **No memory manager.** You need only (1) some contiguous-ish system pages and (2) GGTT PTEs
|
||||||
|
pointing at them (`physical_addr | valid_bit` — the GGTT is a flat single-level array of PTEs in
|
||||||
|
the `GTTMMADR` MMIO BAR), then program the plane. **No GEM/TTM/PPGTT/GuC.** coreboot's native-init
|
||||||
|
literally does `for(i…) WRITE32(base + i*inc | 1, (i*4) | 1)`.
|
||||||
|
- **"Stolen memory"** (GSM/DSM) is firmware-reserved system RAM where the firmware places the GGTT
|
||||||
|
itself and the boot framebuffer. A driver is not obligated to keep scanout there — it can rebind
|
||||||
|
GGTT entries to its own pages. Stolen memory matters mainly for *inheriting* the GOP framebuffer at
|
||||||
|
handoff.
|
||||||
|
|
||||||
|
**The contrast with NVIDIA is stark.** On a discrete GPU the scanout surface must live in **VRAM**
|
||||||
|
(nouveau always pins scanout to VRAM), CPU access goes through the **BAR1** aperture (which on
|
||||||
|
consumer cards can be far smaller than total VRAM unless Resizable BAR is on), and you need a
|
||||||
|
contiguous aligned VRAM allocator plus a BAR1 mapping. The Intel iGPU path **eliminates all of that**
|
||||||
|
— scanout is plain system RAM, and a userspace compositor can write the framebuffer pages directly
|
||||||
|
(as danos already does with the GOP WC framebuffer).
|
||||||
|
|
||||||
|
Because danos boots via GOP, an Intel driver attaches to a display whose **GGTT is already populated
|
||||||
|
and whose plane is already scanning a linear framebuffer at native resolution.** A minimal driver can
|
||||||
|
reuse that live mapping and reprogram the running plane rather than come up from cold — the same
|
||||||
|
"attach to a live display" advantage the NVIDIA doc identifies, but with a far smaller register
|
||||||
|
surface and no firmware wall. *(Low-confidence, per-target details to pin from the specific gen's
|
||||||
|
PRM: GGTT PTE size — 4-byte pre-gen8 vs 8-byte gen8+ — the `GTTMMADR`/aperture BAR layout, surface
|
||||||
|
alignment — 4 KB floor but some gens/tilings want 256 KB — and whether the display's GGTT-mediated
|
||||||
|
DMA sits before or after danos's M16 IOMMU on the target platform.)*
|
||||||
|
|
||||||
|
## Firmware
|
||||||
|
|
||||||
|
A minimal display-only Intel driver is **effectively firmware-free — more so than NVIDIA.**
|
||||||
|
|
||||||
|
- **DMC (Display Microcontroller, "CSR", Skylake+) is NOT required for mode-set or scanout.** Its
|
||||||
|
sole job is saving/restoring display-engine registers across DC5/DC6 low-power idle. Absent, i915
|
||||||
|
prints *"Failed to load DMC firmware … Disabling runtime power management"* and the display
|
||||||
|
mode-sets and scans out normally — you lose only the deep display idle states, not output
|
||||||
|
([intel_dmc.c](https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/i915/display/intel_dmc.c);
|
||||||
|
corroborated by multiple distro bug threads). *(A source-level `HAS_DMC` early-return citation would
|
||||||
|
strengthen this beyond distro testimony, but the conclusion is well-supported.)*
|
||||||
|
- **Pre-Skylake parts have no display microcontroller at all** yet perform full mode-set (and even
|
||||||
|
Panel Self Refresh). This confirms the display engine is fundamentally CPU/MMIO-driven; the
|
||||||
|
microcontroller is an add-on for autonomous idling, not a prerequisite for lighting a panel.
|
||||||
|
Targeting a pre-Skylake or DMC-optional generation sidesteps the question entirely.
|
||||||
|
- **GuC and HuC are render/media microcontrollers on the GT side** — GuC schedules the render engines,
|
||||||
|
HuC assists HEVC/H.265 codec (plus later HDCP/PXP/GSC). Neither is in the scanout path; a
|
||||||
|
display-only driver never loads them
|
||||||
|
([kernel.org microcontrollers](https://docs.kernel.org/gpu/i915.html)).
|
||||||
|
- **PSR firmware lives on the panel**, not in the OS — a minimal driver simply doesn't enable PSR.
|
||||||
|
- **Type-C/TCSS (Ice Lake+) firmware** (PMC/IOM/PHY) is part of platform BIOS/coreboot init and the
|
||||||
|
hardware, *not* a signed blob the display driver loads at runtime. A driver attaching to an
|
||||||
|
already-lit GOP connector, or targeting classic DDI ports, avoids it. *(Cold DP-alt-mode changes
|
||||||
|
from a userspace driver on modern TCSS platforms were not traced to primary source — flagged.)*
|
||||||
|
|
||||||
|
There is **no signed-firmware wall over the Intel GPU at all** on the display path. This is the
|
||||||
|
architectural opposite of NVIDIA's mandatory, unsignable, ABI-unstable GSP — which even on the
|
||||||
|
near-side "direct" display path is a permanent maintenance liability for anything beyond scanout.
|
||||||
|
|
||||||
|
## Licensing
|
||||||
|
|
||||||
|
The situation is *better* than NVIDIA's but still nuanced.
|
||||||
|
|
||||||
|
- **The two best code references are both GPL** — Linux i915 (GPL-2.0) and coreboot libgfxinit
|
||||||
|
(GPL-2.0-or-later). You cannot copy either into a permissively-licensed danos. libgfxinit's WRPLL
|
||||||
|
divider math is itself copied from i915, so it carries the same encumbrance.
|
||||||
|
- **But you don't need to copy code.** The Intel PRM is a *specification*, and a clean-room Zig
|
||||||
|
implementation written from the PRM (using libgfxinit/i915 only to understand behaviour, never to
|
||||||
|
copy) is legitimate — register numbers and bit definitions are functional facts, not copyrightable
|
||||||
|
expression. This is the exact inverse of the NVIDIA case, where no such spec exists and the only
|
||||||
|
guide is the GPL/RE'd code itself.
|
||||||
|
- **A permissive precedent exists: Haiku's `intel_extreme` is MIT-licensed** and was built from
|
||||||
|
Intel's public docs. So if danos wants a permissive license, the model is: implement from the PRM,
|
||||||
|
optionally read MIT Haiku for structure, treat GPL libgfxinit/i915 as documentation-of-last-resort.
|
||||||
|
- **A licensing nuance on the recommended generations:** the "copy the 0BSD PRM code samples" shortcut
|
||||||
|
only applies to Tiger-Lake-era (2021+) PRMs. The Haswell/Broadwell/Skylake PRMs are CC-BY-ND, so
|
||||||
|
their register *facts* are free to implement but there are no code samples to lift.
|
||||||
|
|
||||||
|
As with the NVIDIA doc: danos's userspace-driver-over-IPC model (a driver is a separate process behind
|
||||||
|
a defined protocol) is the cleanest possible license boundary if the project ever chooses to ship a
|
||||||
|
GPL display-driver binary and keep the rest of danos permissive — but that is a boundary judgement
|
||||||
|
wanting real diligence, not a settled fact. The clean-room-from-PRM route avoids the question.
|
||||||
|
|
||||||
|
## Prior art outside Linux
|
||||||
|
|
||||||
|
This is a **real contrast with NVIDIA**, where no one has built a from-scratch native driver outside
|
||||||
|
Linux. For Intel there are **multiple independent, non-Linux, clean-room native modeset
|
||||||
|
implementations** to learn from:
|
||||||
|
|
||||||
|
- **coreboot libgfxinit** — SPARK/Ada, G45/GM45 and Arrandale → Coffee Lake + Apollo Lake (TGL
|
||||||
|
in-tree), the strongest structural reference.
|
||||||
|
- **Haiku `intel_extreme`** — modeset-only (no 2D/3D accel), **MIT-licensed**, i845 through Sandy
|
||||||
|
Bridge solid, newer Gemini/Ice/Tiger Lake in progress but "hit or miss, as the driver lags behind
|
||||||
|
the specs" ([Haiku generations](https://www.haiku-os.org/docs/develop/drivers/intel_extreme/generations.html),
|
||||||
|
[Phoronix Sept 2024](https://www.phoronix.com/news/Haiku-OS-September-2024)).
|
||||||
|
- **SerenityOS** — added basic native Intel graphics ([PR #6277](https://github.com/SerenityOS/serenity/pull/6277)),
|
||||||
|
though only for very old ICH7-class hardware.
|
||||||
|
- **managarm** — native Intel G45 support.
|
||||||
|
|
||||||
|
The catch: **every clean-room non-Linux implementation targets old hardware.** A modern Gen12 "Xe"
|
||||||
|
desktop iGPU is beyond all of them; for the very newest parts only GPL i915 covers the registers. So
|
||||||
|
the wealth of prior art is real but concentrated below Tiger Lake.
|
||||||
|
|
||||||
|
## The practical desktop caveat
|
||||||
|
|
||||||
|
Before any effort estimate is trusted, three hardware realities — the honest reason "Intel is easier"
|
||||||
|
does **not** automatically mean "it'll light up the reader's monitor":
|
||||||
|
|
||||||
|
1. **Muxing / cabling.** On a desktop with a discrete RTX 3060, the monitor is almost certainly
|
||||||
|
plugged into the *card's* outputs, not the motherboard's. An iGPU driver would light a
|
||||||
|
**different, currently-dark** output. To see danos on Intel the reader would have to physically
|
||||||
|
move the cable to a motherboard video port **and** likely enable the iGPU / "IGD Multi-Monitor" in
|
||||||
|
BIOS. Intel-first probably does **not** light the current display without re-cabling.
|
||||||
|
2. **No iGPU at all.** Intel **F-SKU** desktop chips (i5-9400F, i5-12400F, i5-13400F, i7-13700KF, …)
|
||||||
|
ship the graphics **fused off** and cannot be re-enabled. These are extremely common in
|
||||||
|
budget/mid gaming builds paired with an RTX 3060. On an F-SKU (or an X-series HEDT part) the
|
||||||
|
Intel-iGPU path is a **non-starter** regardless of cabling.
|
||||||
|
3. **Generation coverage.** If the CPU *is* a recent non-F part, its iGPU may be Gen12 Xe (Alder/
|
||||||
|
Raptor Lake), beyond libgfxinit's verified set and beyond most non-Linux prior art — leaving GPL
|
||||||
|
i915 (or the TGL-class PRM, which covers Alder/Raptor display IP) as the only reference.
|
||||||
|
|
||||||
|
A cleaner path for *learning* without the hardware lottery: an older bare-metal Intel box (Haswell/
|
||||||
|
Skylake NUC or laptop) whose panel is natively on the iGPU. Note QEMU does **not** emulate an Intel
|
||||||
|
iGPU display engine, so a VM cannot exercise a real Intel modeset path — virtio-gpu (already working)
|
||||||
|
is the VM answer.
|
||||||
|
|
||||||
|
## Alternatives, and the honest Intel-vs-NVIDIA verdict
|
||||||
|
|
||||||
|
| 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 |
|
||||||
|
| **Intel iGPU, reuse-GOP** | EDID read + plane page-flips on the GOP-set mode | Still bounded to GOP's resolution; but real driver-owned scanout |
|
||||||
|
| **Intel iGPU, full modeset** (this doc) | Runtime modeset, vsync, multihead, from public docs | Tier 2–3 effort; DP link training; per-gen churn; **needs a cable-attached, documented iGPU** |
|
||||||
|
| **Native NVIDIA GA106 direct** ([nvidia-gpus.md](nvidia-gpus.md)) | Same, on the RTX 3060 the monitor is actually plugged into | **Tier 4**; GPL-only reference; DMA channel modeset; de-emphasised legacy path |
|
||||||
|
| **GA106 via GSP/OGKM** | Also unlocks 3D later | Tier 5; unstable version-pinned firmware ABI |
|
||||||
|
|
||||||
|
**The verdict for *this reader* (RTX 3060 box):** For pure "see danos on my screen," **NVIDIA-direct
|
||||||
|
is paradoxically the more relevant path**, because the monitor is already cabled to the 3060 and GOP
|
||||||
|
already drives it — a native NVIDIA driver reprograms *that* live display. An Intel driver, however
|
||||||
|
much easier to *write*, likely lights a dark motherboard port the reader isn't looking at, or hits an
|
||||||
|
F-SKU with no iGPU.
|
||||||
|
|
||||||
|
**The verdict for *learning display bring-up*:** **Intel wins decisively.** Public register PRMs, four
|
||||||
|
independent open reference drivers, an MIT precedent (Haiku), a compact formally-analysed blueprint
|
||||||
|
(libgfxinit), no signed-firmware wall, no VRAM/BAR memory manager, and a legitimate permissive
|
||||||
|
clean-room path. It reaches "first pixel" far faster than the NVIDIA native path — *on hardware that
|
||||||
|
actually has a cable-attached, documented Intel iGPU.* Those two goals — "run on my machine" and
|
||||||
|
"learn the craft" — point at different silicon, and that is the honest bottom line.
|
||||||
|
|
||||||
|
## "First light" milestones — a danos `.scanout` service
|
||||||
|
|
||||||
|
Framed as a danos `.scanout` service (like the virtio-gpu and proposed NVIDIA ones), inheriting the
|
||||||
|
GOP-initialized display — no firmware, no cold POST:
|
||||||
|
|
||||||
|
1. **PCI/BAR bring-up** — enumerate the iGPU, map its MMIO BAR (`GTTMMADR` + register block) and the
|
||||||
|
aperture BAR via danos MMIO grants; confirm the display engine is GOP-live.
|
||||||
|
2. **EDID** — implement GMBUS DDC (`0x50`) and DP AUX; read + parse the panel EDID and DPCD caps.
|
||||||
|
*(Smallest self-contained, gen-invariant milestone — a good first commit.)*
|
||||||
|
3. **First pixel = reprogram, don't re-modeset** — with GOP's mode and GGTT mapping inherited,
|
||||||
|
reprogram the running plane (`PRI_CTL`/`PRI_STRIDE`/`PRI_SURF`, linear, 32bpp XRGB) to point at a
|
||||||
|
danos-owned system-RAM buffer; prove a page-flip via the `PRI_SURF` arming write on the *current*
|
||||||
|
mode before changing timings. This defers the entire DPLL/DDI/transcoder/link-training surface —
|
||||||
|
the hardest, most gen-specific ~70% of the work.
|
||||||
|
4. **GGTT ownership** — write your own GGTT PTEs (via an MMIO grant to `GTTMMADR`) pointing at
|
||||||
|
compositor-owned pages, for double-buffered damage-driven present.
|
||||||
|
5. **Wire into the compositor `.scanout` backend** (`attach_scanout`); add vsync via the display
|
||||||
|
vblank interrupt (IRQ-as-IPC).
|
||||||
|
6. **Full mode-set** (the hard, gen-specific step) — for one chosen generation (Haswell/Broadwell or
|
||||||
|
Skylake): WRPLL/DPLL programming, the ~20-step DDI/transcoder/pipe enable sequence, panel power
|
||||||
|
sequencing for eDP (`PP_CONTROL`/`PP_ON_DELAYS`/`PP_OFF_DELAYS` — a common black-screen pitfall).
|
||||||
|
7. **DisplayPort link training** — only if the panel is DP and GOP's link can't be reused; the
|
||||||
|
software CR/EQ state machine over AUX. TMDS/HDMI avoids it; a live eDP panel avoids most of it.
|
||||||
|
8. **Multihead**, then optionally a second generation once one is solid.
|
||||||
|
|
||||||
|
Keep the GOP backend as the fallback the whole way — a stall at any step still leaves danos with a
|
||||||
|
working display, exactly the resilience v2 already provides via re-attach.
|
||||||
|
|
||||||
|
## Reading list
|
||||||
|
|
||||||
|
**Native reference — coreboot libgfxinit (GPL-2.0-or-later, SPARK/Ada):**
|
||||||
|
- `common/hw-gfx-gma.adb` — `Enable_Output`, the end-to-end modeset state machine.
|
||||||
|
- `common/hw-gfx-dp_training.adb` — the complete generic DP link-training CR/EQ loops.
|
||||||
|
- `common/hw-gfx-gma-pipe_setup.adb` — plane/pipe/scaler + `DSPSURF`/`DSPSTRIDE`/`DSPCNTR` scanout.
|
||||||
|
- `common/hw-gfx-gma-transcoder.adb` — timing generator; `common/hw-gfx-edid.adb`,
|
||||||
|
`hw-gfx-gma-i2c.adb`, `hw-gfx-dp_aux_ch.adb` — EDID/DDC/AUX; `hw-gfx-gma-registers.ads` — offsets.
|
||||||
|
- `common/haswell*/`, `skylake/`, `tigerlake/` — the per-gen PLL/PHY/buffer-translation backends.
|
||||||
|
|
||||||
|
**Vendor register specs — Intel OSRC PRMs:**
|
||||||
|
- [Broadwell Vol 11: Display](https://cdrdv2-public.intel.com/690828/intel-gfx-prm-osrc-bdw-vol-11-display.pdf)
|
||||||
|
(CC-BY-ND) — the recommended Haswell/Broadwell-class enable sequences, plane, panel fitter.
|
||||||
|
- [Tiger Lake Vol 12: Display Engine](https://cdrdv2-public.intel.com/705833/intel-gfx-prm-osrc-tgl-vol-12-display-engine.pdf)
|
||||||
|
(code samples 0BSD) — the most complete modern reference incl. PLL/voltage-swing value tables.
|
||||||
|
- [DG2/Arc Vol 12: Display Engine](https://www.x.org/docs/intel/ACM/intel-gfx-prm-osrc-acm-vol12-displayengine.pdf)
|
||||||
|
— the newest public display PRM (Gen12.5, 2022).
|
||||||
|
- [Igalia CC-BY-ND archive](https://github.com/Igalia/intel-osrc-gfx-prm) (Gen4–Gen9.5) and the
|
||||||
|
[kiwitree mirror](https://kiwitree.net/~lina/intel-gfx-docs/prm/) — stable mirrors.
|
||||||
|
|
||||||
|
**GPL reference-of-last-resort — Linux i915 display:**
|
||||||
|
- `intel_gmbus.c`, `intel_dp_aux.c` — the concrete EDID/DDC and DP-AUX register sequences.
|
||||||
|
- `intel_ddi.c` / `intel_ddi_buf_trans.c`, `intel_cdclk.c`, `intel_dpll_mgr.c` — DDI/CDCLK/PLL;
|
||||||
|
`i9xx_plane.c`, `intel_crtc.c` — plane/pipe; `intel_dp.c` — link training. Huge and modular; a
|
||||||
|
reference to confirm undocumented quirks, not a template.
|
||||||
|
|
||||||
|
**Permissive prior art — Haiku `intel_extreme` (MIT):**
|
||||||
|
- [`src/add-ons/kernel/drivers/graphics/intel_extreme/`](https://github.com/haiku/haiku/tree/master/src/add-ons/kernel/drivers/graphics/intel_extreme/)
|
||||||
|
— a second independent modeset-only driver; MIT, so structurally readable for a permissive danos.
|
||||||
|
- [generations.html](https://www.haiku-os.org/docs/develop/drivers/intel_extreme/generations.html)
|
||||||
|
— the best plain-English per-generation fault-line map.
|
||||||
|
|
||||||
|
## Open questions (unresolved by the survey)
|
||||||
|
|
||||||
|
- **Does the target machine have a usable, cable-attached iGPU at all?** F-SKU check, CPU generation,
|
||||||
|
and monitor cabling must be resolved before any effort estimate is trusted (see
|
||||||
|
[practical caveat](#the-practical-desktop-caveat)).
|
||||||
|
- **Does danos even need native mode-*setting*, or only plane/scanout control on the GOP-set mode?**
|
||||||
|
If runtime mode changes aren't required, the driver collapses to EDID + plane page-flips, dropping
|
||||||
|
the DPLL/DDI/link-training ~70% of the work.
|
||||||
|
- **GGTT vs raw physical:** confirm from the exact target-gen PRM that `PLANE_SURF` is interpreted as
|
||||||
|
a GGTT graphics address (well-established, but per-gen confirmation advisable), and the PTE size /
|
||||||
|
`GTTMMADR` / aperture layout for writing GGTT entries.
|
||||||
|
- **Reuse the firmware/GOP GGTT + framebuffer, or install your own GGTT entries?** The latter (needed
|
||||||
|
for double-buffering) means writing GGTT PTEs from the userspace driver via an MMIO grant.
|
||||||
|
- **eDP panel power sequencing** (`PP_*`, T1–T12 delays) — not covered in this pass and a common
|
||||||
|
black-screen source.
|
||||||
|
- **IOMMU interaction** — whether the display's GGTT-mediated DMA needs IOMMU passthrough for the
|
||||||
|
framebuffer pages under danos's M16 IOMMU, or sits before the IOMMU on the target platform.
|
||||||
|
- **DP link-training / AUX robustness and per-generation register drift** are the dominant *risks* —
|
||||||
|
not documentation scarcity.
|
||||||
|
- **Exact Haswell/BDW MMIO offsets** (commonly cited: GMBUS ~`0xC5100`, `DDI_AUX_CTL_A` ~`0x64010`,
|
||||||
|
`DDI_BUF_CTL_A` ~`0x64000`, `DP_TP_CTL_A` ~`0x64040`) were not extracted verbatim from the PRM —
|
||||||
|
confirm against `i915_reg.h` before coding.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Research snapshot; verify against current libgfxinit / i915 source and the specific target
|
||||||
|
generation's PRM before building. Intel's public-PRM coverage and the muxing/F-SKU realities of a
|
||||||
|
given machine both change what is actually achievable.*
|
||||||
@@ -0,0 +1,246 @@
|
|||||||
|
# Native NVIDIA GPU support — feasibility and roadmap
|
||||||
|
|
||||||
|
**Status: research snapshot, not implemented.** This records what a *native* display driver for a
|
||||||
|
real discrete NVIDIA GPU — specifically an **RTX 3060 (Ampere GA106)** — would take, and how it
|
||||||
|
would slot into danos's pluggable scanout architecture. It is a survey of primary sources
|
||||||
|
(NVIDIA's [open-gpu-kernel-modules](https://github.com/NVIDIA/open-gpu-kernel-modules), the Linux
|
||||||
|
[nouveau/nvkm](https://github.com/torvalds/linux/tree/master/drivers/gpu/drm/nouveau) driver,
|
||||||
|
NVIDIA's [open-gpu-doc](https://nvidia.github.io/open-gpu-doc/), and
|
||||||
|
[linux-firmware](https://github.com/NVIDIA/linux-firmware)), not an implementation. The NVIDIA
|
||||||
|
driver landscape moves quickly (GSP defaults, firmware ABIs); treat specifics as a mid-decade
|
||||||
|
snapshot and re-verify against current source before building.
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
- A **minimal display-only driver** (EDID + mode-set + framebuffer scanout, **no** 3D/compute)
|
||||||
|
for the RTX 3060 **can and should avoid the GSP entirely**. nouveau has a register-level,
|
||||||
|
CPU-driven display path for Ampere (`nvkm/engine/disp/ga102.c`) that lights up GA106 with no
|
||||||
|
external firmware; the signed-firmware wall gates the **compute/graphics** engines (PGRAPH),
|
||||||
|
**not** the display controller. "GSP is mandatory on Ampere" is true only for NVIDIA's own
|
||||||
|
RM-object route.
|
||||||
|
- **danos's UEFI GOP boot is the single biggest thing in its favour.** The VBIOS/GOP has already
|
||||||
|
run devinit and brought up the display PLLs, so a driver attaches to a **live, initialized**
|
||||||
|
GA106 — no firmware load, no cold-boot POST, no devinit interpreter. You reprogram a running
|
||||||
|
display rather than bring one up from cold.
|
||||||
|
- It is still a **hard, multi-week-to-months expert effort** (effort tier ≈ 4/5) dominated by
|
||||||
|
NVDisplay channel-DMA programming, SOR/head routing, DisplayPort AUX + link training, and the
|
||||||
|
display supervisor handshake. The GSP/RM route is tier 5 (near-infeasible solo).
|
||||||
|
- The **licensing tension is counterintuitive**: the permissively-licensed reference (NVIDIA
|
||||||
|
open-gpu-kernel-modules, MIT/GPLv2) is the **hard GSP path**; the register-level display code
|
||||||
|
you actually want lives in **GPL nouveau**. See [Licensing](#licensing).
|
||||||
|
- The **window is closing**: GA10x (Ampere) is the *last* NVIDIA family with a register-level
|
||||||
|
display path — Ada (RTX 40) deleted its non-GSP display HAL. Targeting Ampere specifically
|
||||||
|
matters.
|
||||||
|
- **Recommendation:** for *this card*, GOP already gives native-resolution scanout with zero GPU
|
||||||
|
code and zero maintenance. A native driver buys only runtime mode changes, hardware
|
||||||
|
vsync/vblank, and multihead. It is justified if that runtime control is a danos goal, or to
|
||||||
|
*learn the craft* — for which an Intel iGPU or a pre-Turing NVIDIA card reaches "first pixel"
|
||||||
|
far faster.
|
||||||
|
|
||||||
|
## The GSP wall, and why display sits on the near side of it
|
||||||
|
|
||||||
|
On Turing and later, NVIDIA split its driver's Resource Manager into a host **CPU-RM** and a
|
||||||
|
**GSP-RM** running on an on-die RISC-V core ("Peregrine"), talking over RPC
|
||||||
|
([LWN 953144](https://lwn.net/Articles/953144/)). The GSP is a *full resource manager*, not a
|
||||||
|
display coprocessor — there is no "display-only" GSP image and no small display RPC subset. Its
|
||||||
|
boot chain is entirely signed and mandatory: a VBIOS-resident **FWSEC-FRTS** app carves a
|
||||||
|
write-protected region (WPR2), a signed **Booter** on the SEC2 falcon loads the GSP bootloader,
|
||||||
|
and that loads **GSP-RM** inside WPR. The firmware ships pre-computed signatures and the driver
|
||||||
|
picks one by an on-chip fuse-version register — **you cannot self-sign**, and there is **no stable
|
||||||
|
firmware ABI** (it is revised every driver release; nouveau and the Rust nova-core driver each pin
|
||||||
|
exactly one version). A GSP driver is a permanent maintenance liability, not a one-time build
|
||||||
|
([LWN 1037379](https://lwn.net/Articles/1037379/),
|
||||||
|
[nova-core cover letter](https://lore.freedesktop.org/nouveau/20250826-nova_firmware-v2-7-93566252fe3a@nvidia.com/T/)).
|
||||||
|
|
||||||
|
**But display doesn't need any of that on Ampere.** `nvkm/engine/disp/ga102.c` dual-dispatches:
|
||||||
|
|
||||||
|
```
|
||||||
|
if (nvkm_gsp_rm(device->gsp)) return r535_disp_new(&ga102_disp, ...); // GSP RPC path
|
||||||
|
return nvkm_disp_new_(&ga102_disp, ...); // direct register path
|
||||||
|
```
|
||||||
|
|
||||||
|
Both branches use the same `ga102_disp` HAL and the same `GA102_DISP_*` class IDs; GSP merely
|
||||||
|
swaps register programming for RPC. GA106 (chipset `0x176`) is wired to `ga102_disp_new` in the
|
||||||
|
device table, identical to GA102/103/104/107. Ampere lit up displays via the **direct** path in
|
||||||
|
Linux 5.11/5.17 — two years before GSP-RM landed (6.7, 2023)
|
||||||
|
([ga102.c](https://raw.githubusercontent.com/torvalds/linux/master/drivers/gpu/drm/nouveau/nvkm/engine/disp/ga102.c),
|
||||||
|
[Phoronix GA106](https://www.phoronix.com/news/Nouveau-NVIDIA-GA106)).
|
||||||
|
|
||||||
|
**Caveat — this is now the legacy path.** As of Linux 6.18, nouveau defaults to GSP on
|
||||||
|
Turing/Ampere; the direct path is a retained, forceable fallback (`nouveau.config=NvGspRm=0`, and
|
||||||
|
automatic when GSP firmware is absent). It is stable and proven, but NVIDIA and nova-core are
|
||||||
|
moving to GSP-only, and **Ada already deleted its non-GSP display HAL**. GA10x is the last family
|
||||||
|
that keeps a register-level display path.
|
||||||
|
|
||||||
|
## What "direct" actually entails
|
||||||
|
|
||||||
|
"Direct" is not "plain register pokes." Only SOR / PLL / DP-link / clock setup is bare MMIO. The
|
||||||
|
**mode-set and scanout themselves flow through the NVDisplay channels — a DMA pushbuffer**:
|
||||||
|
|
||||||
|
- Display classes for Ampere (the C670 family): core `GA102_DISP_CORE_CHANNEL_DMA` (`0xc67d`),
|
||||||
|
window `0xc67e`, window-immediate `0xc67b`, cursor `0xc67a` (headers `clc67d.h` / `clc67e.h` /
|
||||||
|
`clc67a.h` in [open-gpu-doc `classes/display/`](https://github.com/NVIDIA/open-gpu-doc/tree/master/classes/display)).
|
||||||
|
- The core channel needs **instance memory, a RAMHT, DMA objects, and a channel user-MMIO
|
||||||
|
region** ([disp/chan.c](https://raw.githubusercontent.com/torvalds/linux/master/drivers/gpu/drm/nouveau/nvkm/engine/disp/chan.c)).
|
||||||
|
The register-level "plumbing" to allocate/kick a channel is in NVIDIA's GA102 display register
|
||||||
|
manual: `NV_PDISP_FE_CHNCTL_CORE/WIN/CURS`, `NV_PDISP_FE_PBBASE/PBBASEHI`
|
||||||
|
([dev_display_withoffset.ref.txt](https://raw.githubusercontent.com/NVIDIA/open-gpu-doc/master/manuals/ampere/ga102/dev_display_withoffset.ref.txt)).
|
||||||
|
- **Mode-set is a method stream** on the core channel: `HEAD_SET_RASTER_*`,
|
||||||
|
`HEAD_SET_PIXEL_CLOCK_FREQUENCY`, `HEAD_SET_CONTROL_OUTPUT_RESOURCE`, `SOR_SET_CONTROL`
|
||||||
|
(protocol select), viewport/scaler, then `UPDATE`. The window channel points at the scanout
|
||||||
|
surface (`SET_CONTEXT_DMA_ISO`, `SET_STORAGE`, `SET_OFFSET`).
|
||||||
|
- After `UPDATE` you must complete the display **supervisor** interrupt handshake (SV1/SV2/SV3).
|
||||||
|
|
||||||
|
**EDID and DisplayPort are a separate subdev you must port.** open-gpu-doc documents *none* of
|
||||||
|
EDID/DDC/AUX. On the direct path you read EDID in-driver via nouveau's `nvkm/subdev/i2c`: bit-bang
|
||||||
|
**DDC/I²C at address `0x50`** (E-DDC `0x30`) for TMDS/HDMI, or native **DP AUX** in `i2c/aux.c`
|
||||||
|
for DisplayPort. DisplayPort **link training** (the `dp.c` `train_cr` / `train_eq` state machine
|
||||||
|
over AUX — clock recovery, lane/rate, voltage-swing/pre-emphasis) is the single hardest and most
|
||||||
|
fragile piece; a DVI/HDMI (TMDS) panel avoids it entirely.
|
||||||
|
|
||||||
|
## The memory floor (smaller than you'd fear)
|
||||||
|
|
||||||
|
Neither route hands you a framebuffer allocator — even GSP-RM does not manage the scanout
|
||||||
|
framebuffer; the driver owns VRAM and merely tells GSP where its page directory is. But
|
||||||
|
display-only is a small fraction of a full GEM/TTM stack:
|
||||||
|
|
||||||
|
- **Pitch-linear (untiled) scanout is allowed** on nv50→Ampere — the window's storage method has a
|
||||||
|
`PITCH` layout mode, so you skip block-linear tiling math
|
||||||
|
([wndwc37e.c](https://raw.githubusercontent.com/torvalds/linux/master/drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c)).
|
||||||
|
- The window references its surface through a simple **display context-DMA**
|
||||||
|
(`SET_CONTEXT_DMA_ISO` + a 256-byte-granular `SET_OFFSET = addr>>8`) — a base/limit descriptor,
|
||||||
|
**not** the GPU's 5-level compute page tables. **No full GPU VMM is needed** for scanout.
|
||||||
|
- The surface must live in **VRAM** in practice (nouveau always pins scanout to VRAM). *Open
|
||||||
|
question:* whether GA10x can scan out from a system-memory (GART) surface via a sysmem-target
|
||||||
|
ctxdma — which would let danos skip a VRAM allocator. No source forbids it; nouveau never does
|
||||||
|
it (confidence: medium).
|
||||||
|
- **CPU access** to the framebuffer for compositing goes through **BAR1** (a VRAM aperture); BAR0
|
||||||
|
is the 16 MB register window. BAR1 can be smaller than 12 GB of VRAM unless Resizable BAR maps
|
||||||
|
it all.
|
||||||
|
|
||||||
|
**Net:** you need (1) a contiguous aligned VRAM allocator (256-byte base, pitch a multiple of
|
||||||
|
64 bytes — confirm against the Ampere display refs), (2) a little instmem for the channel
|
||||||
|
pushbuffers + iso ctxdma, (3) a BAR1 CPU mapping. You do **not** need the 5-level VMM, GEM/TTM
|
||||||
|
eviction, or tiling.
|
||||||
|
|
||||||
|
## Licensing
|
||||||
|
|
||||||
|
The tension is the opposite of convenient:
|
||||||
|
|
||||||
|
- **NVIDIA open-gpu-kernel-modules is dual MIT/GPLv2** — usable under MIT, no copyleft on your
|
||||||
|
other code — **but its display logic is the GSP/RM-object route.** Its class headers
|
||||||
|
(`cl0073.h`, `cl2080.h`, `ctrl0073*.h`) are useful, permissive references.
|
||||||
|
- **nouveau is GPLv2**, and the **register-level display sequences you actually want live in
|
||||||
|
nouveau**, not in the MIT code. So the *easy technical path is the GPL-licensed one.* Reading
|
||||||
|
GPL nouveau and reimplementing it in Zig is a derivative-work risk proportional to how closely
|
||||||
|
your code tracks its structure/constants.
|
||||||
|
|
||||||
|
Options: **(a)** accept that the danos NVIDIA display driver is a **GPL component**. danos's
|
||||||
|
userspace-driver-over-IPC model (a driver is a separate process behind a defined protocol, not
|
||||||
|
linked into the kernel) is about the cleanest possible GPL boundary, so the GPL would be contained
|
||||||
|
to that one binary and the rest of danos could keep its own license — but this is a
|
||||||
|
licensing-boundary judgement that wants real diligence, not a settled fact. **(b)** clean-room
|
||||||
|
from *specification* rather than *code*: [envytools](https://envytools.readthedocs.io) + NVIDIA's
|
||||||
|
open-gpu-doc register manuals + the MIT OGKM class headers, treating nouveau as
|
||||||
|
documentation-of-last-resort.
|
||||||
|
|
||||||
|
**Firmware licensing is moot for the direct path** (no firmware is loaded). For completeness: the
|
||||||
|
GSP blobs are marked redistributable under `LICENCE.nvidia`, which permits use by **any
|
||||||
|
OSI-approved open-source OS** (not just Linux), on NVIDIA GPUs, **unmodified**, with **no
|
||||||
|
reverse-engineering of the firmware binary**. The one gate — is danos released under an OSI
|
||||||
|
license? — is only reached on the GSP route, which this doc recommends against for this card.
|
||||||
|
|
||||||
|
## Prior art
|
||||||
|
|
||||||
|
**No one has built a from-scratch native NVIDIA driver outside Linux.** FreeBSD ships
|
||||||
|
`nvidia-drm-kmod`, a *port of NVIDIA's own closed `nvidia-drm.ko`* loading the GSP blob (its old
|
||||||
|
nouveau port was removed). Haiku's NVIDIA support is likewise a *port of OGKM* (GSP, Turing+, very
|
||||||
|
alpha). OpenBSD / DragonFly have neither. Every non-Linux OS that supports modern NVIDIA chose to
|
||||||
|
**wrap NVIDIA's GSP stack** rather than write a native driver. A danos direct-register driver
|
||||||
|
would have exactly one reference implementation — GPL nouveau — and no non-Linux precedent.
|
||||||
|
|
||||||
|
## 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** |
|
||||||
|
| **Pre-Turing NVIDIA** (Kepler / early Maxwell) | Direct EVO/disp-core + CRTC/PLL modeset, **no signed firmware, no coprocessor**; mature nouveau reference | Older display class; not this card; only reclocking is firmware-gated |
|
||||||
|
| **Intel iGPU** | **Publicly documented** register interfaces (Intel PRMs); no coprocessor mediating modeset | i915 is huge + generation-specific; write one generation from the PRM |
|
||||||
|
| **Native GA106 direct** (this doc) | Runtime modeset, vsync, multihead on the actual card | Tier-4 effort; GPL reference; DP link training; legacy/de-emphasized path |
|
||||||
|
| **GA106 via GSP/OGKM** | Also unlocks 3D / reclocking later | Tier-5; ~14k-line ante; unstable version-pinned ABI; unprecedented outside Linux |
|
||||||
|
|
||||||
|
## "First light" milestones (direct path, inheriting GOP state)
|
||||||
|
|
||||||
|
Framed as a danos `.scanout` service (like the virtio-gpu driver), taking the direct register path
|
||||||
|
and inheriting the GOP-initialized display — no signed firmware, no devinit, no GSP:
|
||||||
|
|
||||||
|
1. **PCI/BAR bring-up** — enumerate GA106 (`0x176`), map **BAR0** (registers) and **BAR1** (VRAM
|
||||||
|
aperture) via danos MMIO grants; confirm the display engine is GOP-live.
|
||||||
|
2. **VRAM + instmem allocator** — contiguous aligned VRAM for the scanout surface (256-byte base)
|
||||||
|
+ small instmem for pushbuffers / RAMHT / iso ctxdma. No VMM, no TTM.
|
||||||
|
3. **EDID** — port `nvkm/subdev/i2c` DDC (`0x50`) + DP-AUX (`aux.c`); read + parse the panel EDID.
|
||||||
|
4. **Core channel up** — allocate the `0xc67d` core channel as a DMA pushbuffer; stand up the
|
||||||
|
SV1/SV2/SV3 supervisor-interrupt handshake.
|
||||||
|
5. **First pixel = reprogram, don't re-POST** — bind a window (`0xc67e`) at the existing WC
|
||||||
|
framebuffer via `SET_CONTEXT_DMA_ISO` + `SET_OFFSET`, pitch-linear, `UPDATE`; prove you can
|
||||||
|
drive the *current* GOP mode from your own channel before changing anything.
|
||||||
|
6. **Modeset** — push raster timings on a head, route head→SOR→connector, program the pixel-clock
|
||||||
|
PLL, switch to an EDID mode (needs the `clc67d/e` method opcodes from the OGKM headers + the
|
||||||
|
supervisor timing from nouveau `head.c`).
|
||||||
|
7. **DisplayPort link training** — only if the panel is DP and GOP's link can't be reused; the
|
||||||
|
`dp.c` `train_cr`/`train_eq` state machine. TMDS/HDMI is far simpler.
|
||||||
|
8. **Wire into the compositor `.scanout` backend** (`attach_scanout`), add vsync via the display
|
||||||
|
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 (exactly the resilience v2 already provides via re-attach).
|
||||||
|
|
||||||
|
## Reading list
|
||||||
|
|
||||||
|
**Direct path — nouveau (GPLv2):**
|
||||||
|
- `nvkm/engine/disp/ga102.c` — the GA10x display HAL + the GSP/non-GSP dispatch.
|
||||||
|
- `nvkm/engine/disp/{head.c, ior.c, dp.c, hdmi.c, chan.c}` — head/SOR routing, DP AUX + link
|
||||||
|
training, channel-DMA plumbing.
|
||||||
|
- `dispnv50/{corec37d.c, corec57d.c, wndwc37e.c, wndwc57e.c, wndwc67e.c, headc37d.c, cursc37a.c}`.
|
||||||
|
- `nvkm/subdev/i2c` (DDC + `aux.c`) for EDID; `nvkm/subdev/bios/init.c` + `devinit/` **only** if
|
||||||
|
you ever have to re-POST (danos's GOP handoff means you shouldn't).
|
||||||
|
|
||||||
|
**Object model / GSP path — NVIDIA OGKM (MIT/GPLv2):** class headers `cl0073.h`, `cl2080.h`,
|
||||||
|
`ctrl0073system.h`, `ctrl0073specific.h`; `src/nvidia/` for RM control sequences.
|
||||||
|
`nvidia-modeset.ko` (NVKMS) is a *policy* layer over RM and can be bypassed entirely.
|
||||||
|
[nova-core](https://lore.freedesktop.org/nouveau/) (Rust) is the forward-looking reference for GSP
|
||||||
|
boot mechanics (falcon signing, queue rings, RPC).
|
||||||
|
|
||||||
|
**Register / method specs — NVIDIA open-gpu-doc:**
|
||||||
|
- [`classes/display/README.txt`](https://raw.githubusercontent.com/NVIDIA/open-gpu-doc/master/classes/display/README.txt)
|
||||||
|
— the channel model + class-to-GPU map (read first).
|
||||||
|
- [`classes/display/clc67d.h`](https://raw.githubusercontent.com/NVIDIA/open-gpu-doc/master/classes/display/clc67d.h)
|
||||||
|
+ `clc67e.h` / `clc67a.h` — the Ampere core/window/cursor mode-set method vocabulary.
|
||||||
|
- [`manuals/ampere/ga102/dev_display_withoffset.ref.txt`](https://raw.githubusercontent.com/NVIDIA/open-gpu-doc/master/manuals/ampere/ga102/dev_display_withoffset.ref.txt)
|
||||||
|
— `NV_PDISP_FE_*` channel/pushbuffer registers + SOR.
|
||||||
|
- [`DCB`](https://github.com/NVIDIA/open-gpu-doc/tree/master/DCB) — connector→output-resource
|
||||||
|
routing; [`Devinit`](https://github.com/NVIDIA/open-gpu-doc/tree/master/Devinit) +
|
||||||
|
[`BIOS-Information-Table`](https://github.com/NVIDIA/open-gpu-doc/tree/master/BIOS-Information-Table)
|
||||||
|
— VBIOS parsing (bring-up reference; not needed if inheriting GOP).
|
||||||
|
- The 632 KB Volta [`dev_display.ref`](https://download.nvidia.com/open-gpu-doc/Display-Ref-Manuals/1/gv100/dev_display.ref)
|
||||||
|
is the best shot at SOR-DP/AUX register detail the smaller Ampere file omits.
|
||||||
|
|
||||||
|
## Open questions (unresolved by the survey)
|
||||||
|
|
||||||
|
Each needs a direct read of the named nouveau file or experimentation on the actual card:
|
||||||
|
|
||||||
|
- Exact GA106 register/method offsets and PADLINK→SOR→connector wiring (can vary by board vendor).
|
||||||
|
- Whether *any* PLL/devinit re-run is unavoidable vs. fully inherited from GOP.
|
||||||
|
- Whether DisplayPort needs full retraining on takeover, or the GOP-established link can be reused.
|
||||||
|
- The precise SV1/SV2/SV3 supervisor sequence.
|
||||||
|
- Whether a system-memory-target scanout ctxdma could eliminate the VRAM allocator.
|
||||||
|
- The exact `clc67d.h`/`clc67e.h` method opcode numbers (not captured verbatim in the survey).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Research snapshot; verify against current nouveau / open-gpu-kernel-modules source before
|
||||||
|
building — NVIDIA's GSP defaults and firmware ABIs change per release.*
|
||||||
Reference in New Issue
Block a user