Skip to content

tgl-display: the DMC's program loaded, PG3-PG5 down and DC6 allowed (stage 2) - #1132

Merged
Japabu merged 3 commits into
mainfrom
display-stage2
Nov 1, 2026
Merged

Japabu merged 3 commits into
mainfrom
display-stage2

Conversation

@Japabu

@Japabu Japabu commented Nov 1, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

The T14's display engine never enters DC5 or DC6. The GOP leaves:

  • the DMC's program as the platform firmware loaded it;
  • PWR_WELL_CTL2 at 0xff, so PG1-PG4 are requested and on, PG3 and PG4 for pipes that are off;
  • DC_STATE_EN at 0 (the scout, 2026-10-31).

Vol 12-12.21 "Sequences for Display C5 and C6" allows DC5/DC6 only when three things hold: the CSR program is loaded, PG3 and above are off, and 45520h[1:0] are set.

What this PR does

Stage 2 of issues/each-gpu-drives-its-displays-from-a-userland-driver.md.

  1. The payload. It is Intel's i915/tgl_dmc_ver2_12.bin, from linux-firmware tag 20261019 (commit a2dcb924f), unmodified.
    • 19,760 bytes, sha256 3c013ef0…f325afca, pinned in NOTICE and in the licence gate's row (LicenseRef-Intel-i915-Firmware, firmware-only).
    • LICENSE.i915 permits binary redistribution without modification, so an image that builds tgl-display carries the licence text under /system/share/licenses/.
    • The licence's patent grant covers use alone or with an OSI-licensed OS; NOTICE records that.
  2. dmc::Package::parse reads the CSS header, the package header and every program the entries name, by Vol 12 "DMC Firmware Package".
    • It refuses a file that does not hold together.
    • It refuses a main program whose storage or header writes fall outside 80000h-8FFFFh, or are unaligned.
    • The main program is chosen for the display stepping Vol 4 "Steppings and Device IDs" gives the PCI revision (9A49: 1h is C0, 3h is D0). Exceptions come before defaults.
  3. allow_display_c6 runs after the watermarks, on the one-plane scan-out scanout() found. It:
    • refuses by name a transcoder A on any DDI but A (Vol 12: only port A's PHY programming survives DC6), or VGA display on;
    • disallows DC states that are already allowed;
    • stores the payload and reads it back, then makes the header's writes;
    • withdraws PG5, PG4 and PG3 from both PWR_WELL_CTL instances and awaits each state (20 µs, Vol 12 "Power Well"), the verdict a read made after the deadline;
    • clears AUDIO_PIN_BUF_CTL bit 31 after PG3 (Vol 12 "Audio Bios Programming Sequence");
    • sets 45520h[1:0] and allows up to DC6.
    • A refusal before the load writes nothing, and no refusal allows DC6.
  4. Issue nothing-shows-the-tiger-lake-display-engine-verifies-its-dmc-program.md: the CSS keySize, modulusSize and exponentSize are "Not used" (Vol 12) and 0 in this file, and its CSS size covers the whole file. Nothing on record shows the engine verifies the program.
  5. The track: stage 2's facts are recorded. By the orchestrator's ruling, the compositor's present/damage piece of display-output is now ordered before PSR, rather than an interim signal.

Decisions

  • Loading is MMIO in the iGPU's own BAR, with no DMA. Vol 12 says to copy the payload into the CSR program storage, then make the header's writes, in 80000h-8FFFFh. The program's DMA, if any, goes through the iGPU's VT-d domain.
  • Only the main DMC is loaded. The package also has a pipe A program at 90000h. Vol 2c PIPEDMC_CONTROL says a pipe DMC must be enabled before use, and the DC5/DC6 sequence names one CSR program.
  • The storage is read back. The scout read the T14's storage at 80000h as 0c004040 00010002, which are this payload's first two words. So the storage reads back, and the platform firmware had already loaded this program (an inference from two words).
  • DC6, not DC5: DC6 is required for S0ix. With the pipe lit, the engine enters DC5 only while PSR is active, so this stage alone saves at most what PG3 and PG4 cost.
  • PG2 stays on. Vol 12 requires only PG3 and above off.
  • The DMC header's project bytes read 00 0c 00 00, while Vol 12's table prints 0x000C0000. The byte order is ambiguous, so it is not checked.

Checks

Review r1's fixes, at aa618bbb7: host CI exit 0, 107 steps green; --build-only exit 0; 33 tests (2 new); three controls, exit 101 each. Evidence: https://github.com/ToyOSOrg/evidence/blob/41dbdb5c47719577570035a2f8a3acea8a1c1f33/r3/README.md. The T14 boot for hda and the panel is #1134's display_output_presents, staged on this head.

At b0c58dc88:

All rerun at b0c58dc88, after the session's first logs were lost. Evidence: https://github.com/ToyOSOrg/evidence/blob/20e336cae02e7fbff288325d326121f9792c23f2/r1/README.md

  • cargo run -- --ci host: exit 0, 107 steps green.
  • cargo test -p toyos-tgl-display: 31 pass (12 new). The new tests cover:
    • the pinned file parsed;
    • stepping selection;
    • exceptions before defaults;
    • a pipe entry never taken as the main program;
    • the window, alignment and malformed cases;
    • the whole T14 write order;
    • DC already allowed;
    • each refusal.
  • Negative controls, each a checked mutation restored in the same run (each compiles, and its run exits 101):
    • header writes not held to the window;
    • PWR_WELL_CTL2 never withdrawn;
    • no storage readback.
  • cargo run -- --build-only: exit 0. The image's bytes name Intel-i915-firmware-license.txt once.

T14 boot

display-stage2-ab df14d21d6 is this branch plus stage 1's named-only row display_energy, on benchcase-display.toml. Image sha256 d269de8b…ff95ea3b. The orchestrator ran it: exit 0, verdict passed. It is compared with stage 1's B rerun (d0dc7c34a). Evidence: https://github.com/ToyOSOrg/evidence/blob/0ba93921bc9556d74aa5359cd0eee1bef7502bbf/r2/README.md

  • tgl-display: DMC package 0002000c, main program 00010002 at 0x80000 for revision 0x01 (C0).
  • PWR_WELL_CTL1 went from 0x55 to 0x05 and PWR_WELL_CTL2 from 0xff to 0x0f, so PG3 and PG4 are off. DC_STATE_EN went from 0 to 2. Each read back.
  • No DMA fault, fault record or isolation refusal.
  • Idle PC2/PC3: 346/646 ‰, the same as stage 1.
  • The 10 ms sleeper: 2643 mW against 2647 mW. PG3/PG4 off saves nothing this bench resolves; the series spans 2594-2683 mW. The idle package row swings 4.2-17.7 W in both runs, so it is no comparator.
  • The scan-out still reading is an inference. It rests on two things: the residency is identical to stage 1's, and nothing faulted. Stopping the plane's fetches altogether gave 338/656 ‰, close to these figures, so the residency separates the two weakly. Nobody looked at the panel during this boot.

Risks

  • hda and the display codec. PG3 holds audio, and the T14's HDA walks the display codec at address 2. hda reports a silent codec per codec without ending the link, so the analog codec should be unaffected (inference from code). The bench image has no hda, so this boot cannot show it. A boot of the system image with both drivers would. This risk stays open until display-output: the compositor presents to the display driver, and tgl-display answers at vblank (stage 3) #1134's display_output_presents boot shows hda's tone played after DC6 is allowed. Vol 12's link-wakeup order (the audio driver stops the iDisp link before the pin buffer is cleared) needs hda's coordination, and is recorded under display audio.
  • The platform firmware may hold a well through a request instance this driver does not see. That is refused by name (PowerWellHeld) and leaves DC6 disallowed.
  • The model assumes transcoder A on DDI A. The driver now requires it and logs the value read. The stage2-b boot predates that log, but its DC6 allow passed the older A-C check.

Integration tests

T14 only: this is the Tiger Lake display engine. The boot is the display_energy row from a measurement branch, because the driver holds its claim for the boot.

🤖 Generated with Claude Code

…stage 2)

The display engine can enter DC5 and DC6 only with its context save and
restore program loaded and every power well above PG2 off (Vol 12-12.21
"Sequences for Display C5 and C6"). The T14's GOP leaves PG1-PG4
requested and DC_STATE_EN at 0.

`toyos-tgl-display` now embeds Intel's Tiger Lake DMC package,
`i915/tgl_dmc_ver2_12.bin` from linux-firmware tag 20261019, unmodified
and pinned by sha256 in NOTICE and the licence gate. LICENSE.i915 permits
binary redistribution without modification, so an image that builds
tgl-display carries its text under /system/share/licenses/.

`dmc::Package::parse` reads the CSS header, the package header and every
program the entries name, by the layouts Vol 12 "DMC Firmware Package"
gives. It refuses a file that does not hold together, and a main program
whose storage or header writes fall outside 80000h-8FFFFh. The main
program is chosen for the display stepping that Vol 4 "Steppings and
Device IDs" gives the function's PCI revision (9A49: 1h is C0, 3h is D0),
with exceptions listed before defaults.

`allow_display_c6` runs after the watermarks, on the one-plane scan-out
`scanout` found:
- it refuses a transcoder A on a DDI outside PG1, and VGA display on,
  since both need PG3;
- it disallows DC states already allowed, since a DC5/DC6 switch goes
  through Disable and a reload;
- it stores the payload, reads it back and makes the header's writes;
- it withdraws the PG5, PG4 and PG3 requests and awaits each state
  (20 us, Vol 12 "Power Well");
- it sets 45520h[1:0] and allows up to DC6.
Every refusal is by name, and DC6 is never allowed after one.

Loading is MMIO in the iGPU's own BAR, with no DMA. The CSS header's key,
modulus and exponent fields are "Not used" and 0 in this file, so nothing
on record shows the engine verifies the program
(issues/nothing-shows-the-tiger-lake-display-engine-verifies-its-dmc-program.md).

With the pipe lit, DC5 is entered only while PSR is active, so this stage
alone saves at most what PG3 and PG4 cost. The track now orders the
compositor's present/damage piece of `display-output` before PSR, by the
orchestrator's ruling, rather than an interim signal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Japabu

Japabu commented Nov 1, 2026

Copy link
Copy Markdown
Collaborator Author

Review r1 of #1132 at b0c58dc88

Architecture

The ownership is right. The userland driver that owns the device loads the firmware through its own BAR, with no DMA and no kernel change. The payload is embedded in the driver, not the kernel. toyos-abi appears only at the SDK boundary (PciId, RegWidth). The parser is small and direct, and every main-program write is checked before a Program exists. Production code grows by about 400 lines (dmc.rs 232, lib.rs +112, regs.rs +32, main.rs +28, build +21). Tests grow by about 270 (dc_tests.rs 223, model +47).

One ownership question is left for later and is acceptable today. PG3 is shared: it holds hda's display codec, and tgl-display now powers it down on its own. With no external outputs, nothing uses display audio, and the track already stages display audio as item 10. The final design will need hda/soundserver to ask the display driver for PG3.

What I verified independently

  • Pins. I fetched linux-firmware at a2dcb924f with the build user-agent.
    • i915/tgl_dmc_ver2_12.bin and LICENSES/LICENSE.i915 match the NOTICE hashes byte for byte, and the committed licence text is identical.
    • WHENCE names LicenseRef-LICENSE.i915. ver2_12 is the newest TGL DMC that WHENCE lists (2_04, 2_06, 2_08, 2_12).
    • The build/licence.rs row and FIRMWARE_ONLY entry are correct. build.rs ships the text exactly when tgl-display is built.
  • Layout. I checked the parser's offsets against Vol 12-12.21 pp. 154–156: CSS version at 58h; numEntries at 12; 12-byte FWInfo entries ×32; DMC v3 fwSize at 0Ch, startMMIOAddr at 14h, mmioCount at 5Ch, addr/data at 60h/B0h.
  • No panics. I found no panic path on hostile input:
    • every index follows a length check: header[at+1..=3] sits under header.len() >= header_bytes >= 400;
    • &header[..header_bytes] is reached only after the payload get has proven len >= header_bytes;
    • writes() reads at most to 100h, which is at most header_bytes;
    • multiplications are checked, or are a u32 widened to a 64-bit usize.
  • Header writes stay in the window. Every write of a main program is checked for dword alignment and for 80000h–8FFFFh in parse. main_program re-derives the program from an entry that check already passed. Pipe programs are left unchecked, and they are never loaded.
  • The file itself. I decoded the pinned file's headers. Both entries are * *. The main payload is 17,840 bytes at 80000h–845B0h, and its 9 writes fall in 8F004h–8F074h.
  • Sequence order. The order matches Vol 12 p. 152 steps 1–4 and the p. 221 disable sequence: reverse order, each state awaited for 20 µs.
  • The DC5/DC6 switch rule (p. 153, "Disable" and a reload in between) is met by disallowing first and always reloading.
  • No AUX or modeset is issued, so p. 153's "disable DC5/DC6 around mode set / AUX" has nothing to apply to yet.
  • Host evidence checks out: the logs show 31 tests passing, and each of the three mutations exits 101 with the expected test failing. The T14 boot df14d21d6 is this head plus a test row only (git diff --stat). Its log line matches the PR's register figures.

Required

  1. system/tgl-display/driver/src/lib.rs:337 — DC6 is allowed with eDP on DDI B or C.
    • The rule. Vol 12 p. 152: "Ports A IO/PHY programming is preserved when DC6 is enabled. The programming for other combo PHY ports may not be. After disabling DC6, before enabling the other ports, follow the combo phy initialization sequence…"
    • The failure. A 9a49 machine whose transcoder A drives DDI B passes this check and gets DC6 allowed. Once PSR lets the engine enter DC6, port B's PHY programming can be lost, and the panel's link dies on exit.
    • The fix. For DC6, accept only DDI select 1h. Fix Refusal::Port's doc (:90) and its message (:122) too: the constraint is no longer "outside PG1". Log the DDI value read, which also closes the PR's own "value not logged" gap.
  2. lib.rs:367-371 — a stale read is reported as PowerWellHeld.
    • The failure. The loop reads the state, then the clock. Suppose the process is preempted for more than 20 µs between them while the well is still turning off: a timer tick or IPI is enough for a userland process. The loop then returns PowerWellHeld although the well is off. DC6 stays disallowed for that boot, under a false diagnosis ("power well 4 stayed on with its requests withdrawn").
    • The fix. mailbox's wait (lib.rs, the idle() after its deadline) already avoids this. Take the decision from one fresh read after the deadline.
  3. PG3 off without the vendor's paired audio step.
    • The rule. Vol 12 p. 376, "Audio Bios Programming Sequence", "For Sx and Connected Standby": "GFX driver disables AUDIO_PIN_BUF_CTL bit 31 after turning off the power well for audio (PG3)". The table on the same page gives PG3 as Tiger Lake's audio well.
    • The gap. This PR turns PG3 off and leaves the iDisp link's buffer enabled to an unpowered codec. Its hda risk analysis does not consider this step. DC6 exists for S0ix (p. 152), so the step's context is the one this stage is preparing.
    • The failure. Vol 12 does not document what the HDA controller sees on that link while the codec is unpowered. A stray or late response gives hda WrongCodec/Extra. Unlike Silent, that ends its link (system/hda/driver/src/controller.rs:483), and with it the analog codec.
    • To resolve: either implement the step with its citation, or explain why it does not apply to runtime PG3-off.
  4. Evidence gap: hda and the panel on the T14 system image.
    • The gap. images/system.toml:130-142 runs hda and tgl-display together on the T14, and this change powers down the display codec's well under hda. The PR says the risk "stays open". The track's own stage 2 text says what this stage can show is "the scan-out and hda unharmed", yet neither was shown. The bench image had no hda and no compositor, and nobody looked at the panel. Root forbids weakening audible or visual quality without the owner's agreement, and leaving the gap open and unrecorded is not allowed either.
    • Cheapest sufficient check: one T14 boot of an image with tgl-display, hda and soundserver where audio_tone plays after the tgl-display: DMC package … line. For example, metalcase plus the tgl-display row: the row matches only 8086:9a49, so it does nothing on the other bench, and it would make the interaction a standing regression check. In the same boot, either observe the panel or log pipe A's frame counter advancing after the allow. Timestamps should show which driver went first.
  5. lib.rs:14 and lib.rs:61 — comment no longer true. Both say a refusal leaves the firmware's state "as found". NotStored comes after DC states are disallowed and the storage rewritten. PowerWellHeld comes after PG5/PG4 requests are withdrawn, and a hidden requester is exactly "firmware state not understood". Say what actually holds: refusals before the load leave state untouched, and every refusal leaves DC6 disallowed.

Optional

  • dmc.rs:23-24: the doc says "major version 2 of the package", but version is never checked. Each header's own version is checked instead, which suffices. Either check version >> 16 == 2, or drop the clause.
  • lib.rs:332: _alone: &Scanout is no proof token. Scanout is Copy with public fields, so anyone can build one. Drop it or make it a real token.
  • allow_display_c6's doc: one line with p. 153's contract ("Disable DC5 and DC6 before a DDI AUX channel transaction… during mode set"). Stage 4's PSR is the first caller to need AUX, and nothing else in the code says so.
  • system/tgl-display/src/main.rs:55-56 repeats the dmc.rs module header's contract; one copy is enough.

T14 evidence against the claims

  • Supported by readback: the storage was rewritten and read back; PG3/PG4 are off (CTL1 55h→05h, CTL2 FFh→0Fh); DC_STATE_EN is 2h; no fault.
  • Power: "no resolvable saving" is reported honestly. It is what Vol 12 predicts with the pipe lit and no PSR, so it does not count against the design.
  • Inference, labelled as such: that the scan-out is still reading.
  • Not yet exercised: the DMC actually saving and restoring through DC5/DC6. The PR does not claim this.

SEND BACK

…ine, and the audio buffer off after PG3

- DC6 is allowed only with transcoder A on DDI A. Vol 12 "Sequence to
  Allow DC5 or DC6": "Ports A IO/PHY programming is preserved when DC6 is
  enabled. The programming for other combo PHY ports may not be." A panel
  on DDI B or C is refused by name. The DDI select read is logged with
  the allow, beside pipe A's frame counter, so a later reading shows the
  timing generator ran through it.
- A power well's wait takes its verdict from a read made after the
  deadline. Before, a wait preempted past 20 µs while the well was still
  turning off was called held, and DC6 stayed disallowed under a false
  name.
- AUDIO_PIN_BUF_CTL's enable is cleared after PG3 goes down, the step Vol 12
  "Audio Bios Programming Sequence" pairs with it. The link-wakeup sequence
  also has the audio driver stop the iDisp link first. That needs `hda`
  and this driver to coordinate, so the track records it under display
  audio, with PG3's sharing.
- The comments claimed every refusal leaves the firmware's state as
  found. What holds: a refusal before the load writes nothing, and none
  leaves DC6 allowed.
- `allow_display_c6` drops its `Scanout` argument, which proved nothing.
  Its doc names the AUX and mode-set contract PSR will need. The DMC
  package doc no longer claims a version check it does not make, and a
  duplicate comment in main goes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Japabu added a commit that referenced this pull request Nov 1, 2026
…ugh it

Review r1 of #1132 asks for one T14 boot showing `hda` and the panel
unharmed by stage 2. This row's metalcase boot already runs tgl-display
beside `hda`; what it lacked was order and the panel.

- `tone_after_dc6` waits in this boot's log for tgl-display's DC6 allow,
  then plays `audio_tone`'s muted tone through `hda` to its end, so the
  analog codec is shown playing with PG3 down. A refusal of DC6 fails it
  by name. metalcase's test-runner now receives `volume`, which the
  muted tone needs.
- tgl-display logs pipe A's frame counter at its first answered present.
  The judge holds it past the counter logged with the allow: the timing
  generator ran on after DC6 was allowed.
- The judge requires DC6 allowed on DDI A with DC_STATE_EN 2. It says
  whether `hda` walked its codecs before or after PG3 went down.
- `audio::tone_played` is `tone_on_metal` for any job.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Japabu

Japabu commented Nov 1, 2026

Copy link
Copy Markdown
Collaborator Author

Review r1, addressed at aa618bbb7. Evidence: https://github.com/ToyOSOrg/evidence/blob/41dbdb5c47719577570035a2f8a3acea8a1c1f33/r3/README.md

Required

  1. DC6 only on DDI A. allow_display_c6 refuses any DDI select but 1h, and Refusal::Port's doc and message cite Vol 12's port A rule. The allow's line logs the DDI select, AUDIO_PIN_BUF_CTL and pipe A's frame counter. New test: a_panel_on_ddi_b_is_refused_untouched. Control mutation-ddi-a-to-c: exit 101.
  2. Fresh verdict past the deadline. Each turn reads the clock before the well's state, so the read that decides "held" is made after the deadline. The model gains a one-shot preemption: a stale state read, then the clock 30 µs on. New test: a_wait_preempted_past_its_deadline_reads_the_well_again. Control mutation-stale-verdict: exit 101.
  3. AUDIO_PIN_BUF_CTL. Implemented, cited at the site: bit 31 is cleared after PG3, by p. 376. Vol 12's link-wakeup sequence (p. 381) also has the audio driver stop the iDisp link (LCTL1.SPA, CPA) before the buffer is cleared. That needs hda and this driver to coordinate. The track records it under display audio, beside your point that PG3 is shared. The T14 test pins the write's place. Control mutation-pins-kept: exit 101.
  4. hda and the panel on the T14. display-output: the compositor presents to the display driver, and tgl-display answers at vblank (stage 3) #1134 is rebased onto this fix, and its display_output_presents boot is restaged as one metalcase boot with tgl-display, hda and soundserver.
    • tone_after_dc6 waits in the boot's log for the DC6 allow, then plays the muted tone through hda to its end. A DC6 refusal fails it by name.
    • The judge holds pipe A's frame counter at the first answered present past the one logged with the allow.
    • It requires DC6 on DDI A, and says whether hda walked its codecs before or after PG3 went down.
  5. Comments. The crate header and Refusal's doc now say what holds: a refusal before the load writes nothing, and none leaves DC6 allowed. allow_display_c6's doc says how far a refusal after the load got.

Optional, all taken:

  • The DMC package doc no longer claims a version check.
  • The Scanout argument is gone.
  • allow_display_c6's doc names the AUX and mode-set contract.
  • main's duplicate comment is gone.

Checks: cargo run -- --ci host exit 0, 107 steps green; --build-only exit 0.

@Japabu

Japabu commented Nov 1, 2026

Copy link
Copy Markdown
Collaborator Author

Review r2 of #1132 at aa618bbb7 (r1 fixes only)

I checked each r1 item against b0c58dc88..aa618bbb7, against Vol 12/Vol 2c, and against #1134's T14 readback (33149bbeb r3; I also checked the raw kernel.log behind it).

r1 items

  1. DC6 only on DDI A, with the value logged: resolved.
    • lib.rs:343 refuses any DDI select but DDI_A (1h).
    • Refusal::Port's doc and message now cite the port A rule.
    • a_panel_on_ddi_b_is_refused_untouched checks that nothing is written.
    • The allow line logs DDI select 0x1, and the T14 boot shows it.
  2. A fresh read after the 20 µs deadline: resolved.
    • power_down takes the clock first and reads the state after, so a late verdict always comes from a read made past the deadline.
    • I traced the model's preempted path. The stale 0xff is the first read of PWR_WELL_CTL2 in the wait loop, and the 30 µs jump comes on the next nanos(). The old loop would have returned PowerWellHeld(4), and the new one reads the well off. The test therefore separates the two orders.
  3. AUDIO_PIN_BUF_CTL bit 31 cleared after PG3: resolved.
    • The write comes after power_down(3) succeeds, and the Vol 12 p. 376 text is cited correctly. The register is 48414h by Vol 2c.
    • The track's item 10 records the p. 381 link-stop order (LCTL1.SPA/CPA before the buffer is cleared) and the need for hda to coordinate.
    • The T14 read 300a7077, so bit 31 is clear.
  4. hda and panel evidence: resolved by display-output: the compositor presents to the display driver, and tgl-display answers at vblank (stage 3) #1134's boot.
    • tone_after_dc6 waited for the DC6 line (12.057 s), opened its stream at 12.144 s, and played to the end with 0 underruns.
    • Pipe A's frame counter went from 421 at the allow to 453 at the first answered present.
    • The README honestly reports that hda walked its codecs before PG3 went down (11.556 s).
    • allow_display_c6 is the same in that boot and on this head. Stage 3 only adds the interrupt claim after it, so the evidence holds for this PR.
  5. Corrected refusal comments: one sentence is still false. See the blocker below.

r1's optional items are all taken.

Required

  • system/tgl-display/driver/src/lib.rs:14-15: "no refusal leaves DC6 allowed" is false in a case the code itself reaches.
    • The failure. Suppose the firmware left DC_STATE_EN = 10b and transcoder A is on DDI B, or VGA is on. Port/Vga are refused before any write (lib.rs:343-348), so DC6 stays allowed. This matches the sentence just before it ("a refusal before a write leaves the state as found"), so the two sentences contradict each other.
    • Why it matters. This is a contract that later stages will read. PSR's AUX path, for one, needs to know whether DC6 can be on after a refusal.
    • The fix. Say what holds, e.g. "and no refusal allows DC6". allow_display_c6's own doc (lib.rs:338-339) is already accurate.

Optional

  • Allowed::ddi is always DDI_A on Ok, so logging it on success says nothing new; the refusal already carries the value. Keep or drop it, as you prefer.

SEND BACK — one comment sentence. The fixes are otherwise complete.

…owed

A refusal before any write (a panel off DDI A, VGA on) leaves DC6 allowed
where the firmware allowed it, so "no refusal leaves DC6 allowed"
contradicted the sentence before it. What holds is that no refusal
allows DC6.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Japabu added a commit that referenced this pull request Nov 1, 2026
…ugh it

Review r1 of #1132 asks for one T14 boot showing `hda` and the panel
unharmed by stage 2. This row's metalcase boot already runs tgl-display
beside `hda`; what it lacked was order and the panel.

- `tone_after_dc6` waits in this boot's log for tgl-display's DC6 allow,
  then plays `audio_tone`'s muted tone through `hda` to its end, so the
  analog codec is shown playing with PG3 down. A refusal of DC6 fails it
  by name. metalcase's test-runner now receives `volume`, which the
  muted tone needs.
- tgl-display logs pipe A's frame counter at its first answered present.
  The judge holds it past the counter logged with the allow: the timing
  generator ran on after DC6 was allowed.
- The judge requires DC6 allowed on DDI A with DC_STATE_EN 2. It says
  whether `hda` walked its codecs before or after PG3 went down.
- `audio::tone_played` is `tone_on_metal` for any job.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Japabu
Japabu marked this pull request as ready for review November 1, 2026 15:35
@Japabu
Japabu added this pull request to the merge queue Nov 1, 2026
Merged via the queue into main with commit 342bdd4 Nov 1, 2026
10 checks passed
@Japabu
Japabu deleted the display-stage2 branch November 1, 2026 15:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant