Skip to content

tgl-display: PSR1 on the T14's panel, enabled from the compositor's first present (stage 4) - #1136

Closed
Japabu wants to merge 1 commit into
mainfrom
display-stage4
Closed

Japabu wants to merge 1 commit into
mainfrom
display-stage4

Conversation

@Japabu

@Japabu Japabu commented Nov 1, 2026 •

Copy link
Copy Markdown
Collaborator

Draft, stacked on #1134 (display-stage3, e884ee2f6). Not to land before the owner has seen the T14's PSR exit latency in absolute numbers (the track's stage 4 rule).

Problem

With the pipe lit, the engine enters DC5 only while PSR is active (Vol 12 "Display C5 and C6"). So stage 2's DC6 saves almost nothing until the panel self-refreshes.

What this PR does

Stage 4 of issues/each-gpu-drives-its-displays-from-a-userland-driver.md: PSR1 on the T14's eDP panel.

  • aux: native AUX reads and writes on DDI A, by Vol 12 "AUX Functional Sequence".
    • The data registers are MSbyte first (Vol 2c DDI_AUX_DATA).
    • The timeout is the 4 ms maximum, as step 4 asks.
    • The fast-wake sync count is 7, which Vol 2c says to "always" program, and the sync count is 31, at least the 25 it requires.
    • DEFER, NACK and short replies are retried up to 32 times, with the requester's reply time-out (500 µs) between attempts.
  • psr::prepare runs before DC6 is allowed, since step 2 forbids AUX with PSR or DC5/DC6 on.
    • It refuses by name:

      • PSR already on;
      • a PSR AUX error in PSR_IIR;
      • a vertical blank delayed past vertical active;
      • a disabled watermark level.

      The last two need a latency-reporting chicken bit this driver does not set (see Decisions).

    • It powers AUX A's IO (Vol 12 "AUX IO Power Enabling").

    • It reads and checks the panel. The panel is refused without PSR, without SET_POWER, with a reserved setup time, or with PSR errors or an internal error:

      • DPCD 00070h-00071h, PSR version and capabilities;
      • 00700h-00701h, eDP revision and SET_POWER capability;
      • 02006h-02009h, error status, ESI, PSR status and synchronisation latency.
    • The setup time must fit vertical blank less a line (Vol 2c SRD_CTL).

    • Then it programs both sides:

      • it tells the panel the main link stays active, then enables it and sets D0;
      • it enables the VSC DIP with hardware supplying PSR1's header and data (Vol 2c VIDEO_DIP_CTL VSC select 00b, "Recommended for use when PSR is enabled");
      • it masks max sleep, memory-up and hotplug, and unmasks the exit and AUX-error identities.
  • Prepared::activate enables SRD. The hardware's context-restore bit is kept, TP1 and TP2 take 2.5 ms each, TP4 is skipped ("Always program TP4 to 11b"), and idle frames are at least 6.
  • Presents through PSR.
    • Psr::update flips the scan-out's surface to itself: a frame-update event, so the change reaches the panel.
    • A present is answered at the first vblank at which SRD_STATUS reads awake (000b IDLE or 001b).
    • fault disables PSR on a PSR AUX error, and disable awaits IDLE within Vol 12's bound (a frame + 6 ms + 1.5 ms).
  • PSR only while the compositor presents.
    • tgl-display enables PSR at a connection's first present and disables it when the connection ends. Nothing else would end SRD for a change.
    • Psr hands its Prepared back on disable, with the panel still configured, so after display-output: the compositor presents to the display driver, and tgl-display answers at vblank (stage 3) #1134's reconnect the next connection's first present enables SRD again with no AUX. A PSR AUX error disables PSR for the boot.
    • The first present is the whole output, sent by toyos_display_output::Output as it takes the hello. That closes the window where frames composed before the hello reached no present.
  • The measurement.
    • The driver logs each of the first 16 presents: its latency from arrival to the vblank carrying it, and SRD_STATUS at arrival and after.
    • It then logs windows of 16, split by whether SRD had to end first, with SRD_PERF_CNT.
    • The T14 row psr_exit_latency requires at least one present that arrived in SRD and prints every sample.

Decisions

  • PRM over the brief, on link standby. Vol 2c SRD_CTL Link Ctrl says: "This field is ignored by transcoder A/B/C since they only operate in standby." The clean-room brief's vendor-code fact (F4) says Tiger Lake turns the main link off and retrains on exit. Root CLAUDE.md puts the vendor's document first, so:

    • the panel is told the link stays active (00170h bit 1);
    • SRD_CTL bit 27 stays 0, which the PRM says transcoder A ignores and the brief requires.

    The boot reads SRD_STATUS's state, which separates 010b "SRD entry with Link OFF" from 111b "SRD entry with Link ON", and its link field, on entry (at a present's arrival) and on exit. If the bench sides with the brief, the panel's configuration bit flips, and nothing else.

  • The PRM replaces several of the brief's vendor-code mechanisms:

  • CRC off. The PRM allows it, and it avoids the CRC/max-sleep interplay Vol 2c notes. Link CRC errors then go unreported by the panel.

  • The two vendor-code workarounds, refused instead. The brief's J1 and J2 set a latency-reporting chicken bit, with a delayed vblank or a disabled watermark level. Neither is in the PRM. The T14 has neither, so the conditions are refused by name rather than worked around.

  • No VBT. Its PSR entry lives in the IGD OpRegion, which no ToyOS mechanism reaches. TP1 and TP2 take 2.5 ms, the brief's safest, and the idle frames come from the panel's latency. Reaching the OpRegion needs a decision on the mechanism (a loader or kernel hand-over beside the framebuffer's EDID), which goes to the orchestrator.

  • PSR2 and selective fetch are out until PSR1 is measured. The brief records a Tiger Lake flicker history.

Checks

At 823066157:

  • cargo run -- --ci host: exit 0, 107 steps green, with toyos-tgl-display's 44 tests. 8 of them are new:
    • native read and write, MSbyte first;
    • DEFER retried, and timeout and endless DEFER refused;
    • the T14 sequence, including the SRD_CTL word;
    • each panel refusal, with the panel left unconfigured;
    • setup time past vblank;
    • the firmware-state refusals before any AUX;
    • the awake states and the AUX-error disable;
    • disable awaiting IDLE.
  • Negative controls, each a checked mutation restored in the same run, exit 101 each:
    • the panel told the link goes off;
    • no setup-time check;
    • no AUX retry;
    • sink errors ignored.
  • cargo run -- --build-only: exit 0. The metal staging builds the image too.

Evidence: https://github.com/ToyOSOrg/evidence/blob/cc5f4e961d9ded3b2f1b2d415273128a3f9a3cc8/r1/README.md

T14 boot r1 (8230661): ran, exit 0; PSR refused

Evidence: https://github.com/ToyOSOrg/evidence/blob/40c40a4332a0e0b0811614bebf962b1b66ba8199/r2/README.md

  • PSR stayed off: PSR stays off — the panel names no PSR version. DPCD 00070h read 0 with no AUX fault, and nothing else of the panel was said. No link state on entry or exit, and no exit latency, was observed.
  • Without PSR, four presents took 14.52, 15.87, 15.35 and 15.24 ms from arrival to the vblank that carried them. That is a p50 of about 15.3 ms and a max of 15.87 ms at a 16.672 ms refresh; four samples give no p99. SRD_STATUS read 04000000 (IDLE, link on).
  • display_output_presents passes with the tone judge's fix. psr_exit_latency fails.

T14 boot r3 (f714a51): staged, not yet run

This head, rebased onto #1134's fixes, image sha256 faf2bc9d…. Evidence: https://github.com/ToyOSOrg/evidence/blob/741e00ace7ca6b3605b1a13a729b268f9f46949c/r3/README.md. Host CI exit 0.

T14 boot r2 (b62a342): queued as staged, for the panel's DPCD

The panel is now read apart from prepare, adding DPCD 00000h-0000Fh, the receiver capabilities, whose revision byte is never 0 from a receiver that answered. Every byte is said before anything decides on them. The boot says whether the panel has no PSR or the AUX path answers zeros. Image sha256 38b1bbfbfd7dd3eb….

Risks

  • Visual quality is owner-protected. A wrong PSR configuration can freeze or corrupt the panel. Guards:

    • PSR only while presents flow;
    • disabled when the connection ends;
    • an exit that does not reach a vblank within 84 ms ends presents and disables PSR.

    The bench sees the log, not the panel, so someone should look at the panel during the first boot.

  • The panel side rests on the brief. Its sink facts are secondary quotations of VESA text; the PR's evidence lists every one used.

  • Link standby. If the PRM's claim does not hold on this panel, the first boot may show AUX or link errors. They are said by name, and PSR is disabled.

🤖 Generated with Claude Code

…irst present (stage 4)

The engine enters DC5 with the pipe lit only while PSR is active (Vol 12
"Display C5 and C6"), so stage 2's DC6 saves little without it.

The source side follows Vol 2c and Vol 12 throughout. The panel's side
comes from the clean-room brief of VESA facts and is recorded in the PR's
evidence:
- the AUX framing;
- DPCD 00070h-00071h, 00170h, 00600h and 02006h-02009h;
- the setup-time table.

- `aux`: native reads and writes on DDI A's channel, by Vol 12 "AUX
  Functional Sequence".
  - The data registers are MSbyte first.
  - The timeout is the 4 ms maximum.
  - The fast-wake count is 7 and the sync count 31, Vol 2c's values.
  - DEFER, NACK and short replies are retried, with the reply time-out
    between attempts.
  - A transaction runs only with PSR off and DC states disallowed, by the
    sequence's step 2.
- `psr::prepare`, before DC6:
  - refuses PSR already on, a PSR AUX error, a delayed vblank and a
    disabled watermark level. The last two need a latency-reporting change
    this driver does not make;
  - powers AUX A's IO;
  - reads the panel's PSR version and capabilities, eDP capability, error
    status and status, and refuses a panel without PSR, without SET_POWER,
    with a reserved setup time or with errors;
  - holds the setup time to vertical blank less a line (Vol 2c SRD_CTL);
  - tells the panel the main link stays active, then enables it and sets
    D0;
  - enables the VSC DIP with hardware's header and data;
  - masks max sleep, memory-up and hotplug, and unmasks the exit and
    AUX-error identities.
- `Prepared::activate` enables SRD. Context restore is kept, TP1 and TP2
  take 2.5 ms, TP4 is skipped, and idle frames are at least 6.
- `Psr::update` flips the surface to itself, a frame update event. `awake`
  reads SRD_STATUS's state, `disable` awaits IDLE within Vol 12's bound,
  and `fault` disables on a PSR AUX error.

Vol 2c's SRD_CTL says transcoder A's SRD "only operate[s] in standby".
The brief's vendor-code fact says Tiger Lake turns the link off. The PRM
decides, so the panel is told the link stays active, and the boot reads
both SRD_STATUS's state (010b link off, 111b link on) and its link field.

tgl-display enables PSR only at the compositor's first present, and
disables it when the connection ends. Nothing else would end SRD for a
change, and the compositor's first present is now the whole output as it
stands when it reads the hello. A present is answered at the first vblank
out of SRD. The driver says each of the first 16 presents' latency and SRD_STATUS,
then windows of 16 split by whether SRD had to end first, with
SRD_PERF_CNT. The T14 row `psr_exit_latency` rides
display_output_presents' boot.

The panel is read apart from `psr::prepare` (`psr::read_sink`), with DPCD
00000h-0000Fh, the receiver capabilities: its DPCD revision is never 0
from a receiver that answered, and a zero is refused by name
(`NoReceiver`). Every byte read is said before anything decides on it.
The T14's first boot (8230661) refused PSR on a zero at 00070h and said
nothing else of the panel.

Rebased onto #1134's review fixes:
- The whole first present is `toyos_display_output::Output`'s: a taken
  hello answers it (`Received::Offered { first }`), and the compositor
  sends it.
- A connection that ends from the compositor's side is connected to
  again. `Psr` keeps its `Prepared`, so `disable` hands it back with the
  panel still configured, and the next connection's first present enables
  SRD again with no AUX. A PSR AUX error disables PSR for the boot.

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

Japabu commented Nov 1, 2026

Copy link
Copy Markdown
Collaborator Author

Closed by the orchestrator's decision, 2026-11-01. The branch display-stage4 (f714a5161) is kept as the restart point.

The T14's panel does not support PSR, so this is code that cannot be verified and that has no caller. No other bench has an Intel panel. The T14 boot at f714a5161 passed. Its evidence is at https://github.com/ToyOSOrg/evidence/blob/5830b5b51493cce5d952acd8f2c2c98a0b16fe7e/r4/README.md:

  • DPCD 00070h (PSR_SUPPORT) reads 00, no PSR. 00700h reads 01, eDP 1.2. PSR1 is an eDP 1.3 feature.
  • r2's boot at 823066157 read the same values.
  • SRD_STATUS stayed 04000000 (IDLE, link full on), and PSR never entered.

Without PSR, Vol 12 "Display C5 and C6" rules out DC5/DC6 with the pipe lit on this panel. The display track issue records that limit, and that this branch and the clean-room PSR facts are where to restart if a PSR-capable panel appears.

🤖 Generated with Claude Code

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