Skip to content

omacom sync: display (DCP audio, M3 panel backlight, DP/HDMI audio on by default) - #767

Closed
RyanTheTide wants to merge 31 commits into
aurora-wipfrom
omacom-sync/display
Closed

RyanTheTide wants to merge 31 commits into
aurora-wipfrom
omacom-sync/display

Conversation

@RyanTheTide

@RyanTheTide RyanTheTide commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

Display lane of the omacom integration/aurora up-port (2026-11-01). It brings in what our tree lacked from the omacom display work, after a review of every commit, on top of aurora-wip 5cf4c5e.

What it brings.

  • DP/HDMI audio on the native link path (14.7 external role and our desktop 26.6 external role, so the J616s HDMI port): stale prepare rejection, completing a live link after a disconnect, holding a stereo link between streams on a silence that the SIO channel plays as an idle transfer (no gap, no restart the sink mutes), one rate and sample size while links are held. The hold_link knob that one commit adds is removed again later in the series.
  • apple-sio: the descriptor bitmap was allocated 2 bytes for 64 bits (a real overflow on every SIO user, M1 and M2 included), and an idle transfer handover. Channels that never get an idle transfer (M1, M2) keep the old accounting.
  • DP/HDMI audio on by default. A fixup of ours goes first: avep_init() now looks for the audio device in the DT before it checks the firmware, so a processor without one (the J700 H17P processors, internal panels) stays exactly as it was with hdmi_audio off instead of logging "Audio not supported for firmware" as an error.
  • M3 Pro/Max (T6030/T6031) and M3 Air (J613): the scoped 14.7 panel backlight with its KUnit suites, J516C and J613 admission, J516C swap timestamps (120 fps), setting an external DSC mode again once the display is on, Type-C DP audio on J514S/J516S (DPA2), and withdrawing the PMP external display requests in system sleep.
  • Shared: internal panel dimensions restored after EDID clears, AFK debugfs skipped for unrouted connectors, a soft dependency on the display crossbar module.
  • Selftest fixture repairs so the apple-dcp host tests build the ported code.

The shared backlight code was merged by hand: the T8132 panel stays active, configurable and registrable as before, the desktop 26.x readback is kept, and soft DPMS now excludes only the 14.7 panel (which has its own blank and restore hooks) instead of every panel that is not H17P, as the omacom version did.

Per-commit verdicts (all 29 commits of the lane)

omacom author subject verdict reason ours
55832c2e3dd8 Oliver Lukschander route Thunderbolt DP tunnels through the Type-C crossbar SUPERSEDED our own commit (from #8) carried to omacom with a 7.2.10 adaptation; ours has it and the later dcp-fabric.c rework (tb_lock, per-route DP IN, dcp_tunnel_crossbar_up) replaces that version; the omacom copy also has no Signed-off-by fb4efa4e677f, dcp-fabric.c
d77c55666a80 Naeem Malik give the J516C panel an EDID REJECTED a second panel EDID builder (dcp-panel-edid.c, a DT compatible to PNP ID table) beside ours in dcp-display-metadata.c (dcp_panel_edid(), dcp_panel_edid_snapshot()); the 14.7 panel EDID gap is real and should be closed by feeding that panel into our builder none
e3f69b773c8f Naeem Malik stamp the J516C panel's 14.7 swaps PORTED J516C only, measured 120 fps, KUnit covered; adapted (no base_edid field) 47d53ce42303
378d88cdee47 Chris Kearney port the scoped T6030 14.7 panel backlight PORTED missing here; gated on the T6030 record plus J514S/J516S machine admission; shared backlight merged by hand as described above 279f5f641cc1
fb8f91beaed5 Chris Kearney initialize backlight KUnit GEM and mode fixtures PORTED test fixture init 8cb8074ad4ff
964323ebf32a Chris Kearney tidy the panel backlight port formatting PORTED formatting of the above 572c9be85ea1
f4ef473afffc Chris Kearney check the suspended backlight worker admission PORTED test only 985a20a0bf88
40eb318ba3db Chris Kearney address the panel backlight review PORTED 14.7 panel only fixes; the review link trailer is dropped 63123a1ae1ea
fa224e85a01a Chris Kearney drain the failed-panel test kick before checking idle PORTED test only b2cb665d307e
b7c75a932a9c Eryk Wieliczko restore panel dimensions after mode probes PORTED 4 lines, every internal panel; its host case needed a fixture repair (797fee6e64ee) bb0c381424d9
c92eb3943810 Eryk Wieliczko skip AFK debugfs setup for unrouted connectors PORTED NULL dereference with DRM_APPLE_DEBUG on unrouted Type-C connectors 4db122d9804d
c806e16bbdd3 Eryk Wieliczko reject stale native audio prepares PORTED instance checks around prepare; our tree already checked the status inside the lock; tests parameterised for 14.7 and desktop 26.6 ae21253a44e6
d00568eaae5b Eryk Wieliczko complete live audio links after disconnect PORTED link completed on the instance that owns it 3300eb46d126
69e431f5787d Eryk Wieliczko apple-sio: allocate the full descriptor bitmap PORTED real out-of-bounds bitmap use on every SIO 630faace180c
459ba2444ce5 Eryk Wieliczko hold the native HDMI audio link between streams PORTED native link path only; its hold_link parameter is removed by 653176dcb94e below f9d4b9ae1878
5ab5f59ee831 Eryk Wieliczko t603x-j514s-j516s: add Type-C DisplayPort audio PORTED adapted: DPA2 at the root like our DPA1 (no AP-side registers); CHECK_DTBS on t6030-j514s/j516s identical to base 519aa78285cb
0ec6112931ec Eryk Wieliczko hold the HDMI audio link at one rate and sample size PORTED userspace resamples to the held 48 kHz/24-bit link, layouts stay free 9251c670aaf0
f4dd5a248256 Eryk Wieliczko apple-sio: hand over to an idle transfer without a gap PORTED ring accounting only from a channel's first idle transfer; M1/M2 channels keep the old path bc8ef9e9050f
c0b3d14f91bb Eryk Wieliczko keep the held HDMI audio link's samples flowing PORTED silence becomes the SIO idle transfer d2997336a230
b28cb3a4bb17 Eryk Wieliczko pmp-report: withdraw external display requests in sleep PORTED adapted to our renamed display-gate.c; only apple,t6030-dcpext requests are marked; PMP graph host test 27 cases pass af498ab24df4
12c1012b5739 Jeppe Bylov declare a soft dependency on the display crossbar PORTED initramfs generators pick up mux-apple-display-crossbar; harmless when built in 88d7cf95f30e
a91ccf0abdee Samuel Carreño v14.7: admit panel brightness on the J516C PORTED J516C admission to the ported path 5e5fc3e36a68
6f96bfb2f9ab Lucas Goossen answer eDP for the J313 backlight and cap it at 394 nits REJECTED the cap belongs in the J313 DT (apple,max-brightness), not a driver string match on apple,panel-j313; dropping the firmware 26 guard in dcpep_cb_create_backlight_service() changes every older firmware (M1 Pro, M2) and the author's own follow-up says it changes nothing on J313; not booted none
86a999abd1c9 Lucas Goossen clamp J313 backlight readback to the panel maximum REJECTED depends on the cap above; clamps firmware reports on every old firmware machine; not hardware tested none
dbb6bcce98cb Chris Kearney selftests: follow the one-argument cd321x_display_taken() PORTED our helper still takes two arguments, so only the zero-initialised cd321x_pm_state takes effect; the one-argument branch is inert dac8e09a3119
7ef3bc138e59 Eryk Wieliczko set an external mode again once the display is on PORTED 14.7 external DSC modes; KUnit case included 38759961f62e
653176dcb94e Eryk Wieliczko hold the audio link on the Type-C ports too PORTED removes the hold_link knob 640abc32a8bc
c9e5b2575e38 Eryk Wieliczko turn DP/HDMI audio on by default PORTED DT link drives it, not a knob; preceded by our fffd99a81921 so the J700 stays quiet; needs the hardware run before ready 94ea41017a3f
eec64583605c DjDeveloperr enable the J613 panel brightness path PORTED J613 admission, measured by the author 2984ba957d9e

Our own commits: fffd99a81921 (avep_init looks for the audio device first), e6c35fdde648 and 797fee6e64ee (host selftest fixture repairs).

Gates

All on the buildbox, run again on the branch head 918af9e23af6, which merges aurora-wip e4b030d746f2 (the integration/aurora sync and the J616s VRR gamma work) with no conflicts; the numbers below are the same before and after that merge. Base for the host tests is the coordinator's run on aurora-wip 5cf4c5e5d944; aurora-wip PR #754 fixed the 10 avd-av1-tail failures in between.

  1. Fleet config build (Fedora Asahi base plus asahi.config, olddefconfig, survival check 136 requests and 0 mismatches, distro gate list all ok, Image modules dtbs): rc 0, 5872 modules, 0 warnings in the whole build log.
  2. W=1 of drivers/gpu/drm/apple, drivers/dma, drivers/pmdomain/apple, drivers/soc/apple (162 objects each side): base 0 warnings, branch 0 warnings. CHECK_DTBS W=1 for t6030-j514s and t6030-j516s: 423 lines on base and branch, identical, no new message from the DPA2 node.
  3. KUnit (qemu arm64, LLVM; drm/apple incl. display and audio suites, apple-sio, pmp-report, fabric): 446 run, 444 passed, 2 skipped (g17 UCLAMP and an S35 policy case, both unrelated), 0 failed. New or changed suites all pass: apple-av-native-audio 15, apple-dcpaud-release-link 11, dcp_v14_backlight 13, dcp_v14_backlight_lifetime 7, apple-dcp-v14-board 7, dcp_v14_external_modeset 2, apple-pmp-report 12, apple-sio 10.
  4. Host tests from a clean tmpfs: run-host-tests.py base 148 ok and 10 FAIL (avd-av1-tail), branch 158 ok and 0 FAIL; apple-dcp run.py base 83/83, branch 84/84 (the new panel-dimensions case). PMP graph host test 27 cases with the new sleep cases. Two fixture repairs of ours were needed (e6c35fdde648, 797fee6e64ee).

Hardware plan (for the coordinator's run)

Baseline is the fleet kernel of aurora-wip, candidate is this branch's kit. On every machine record, for both kernels: dmesg -p3 | wc -l (err and worse, it must not grow), aurora-diag check --expect (exit code and any new warn/fail), aurora-diag snapshot then aurora-diag diff, and cat /sys/module/appledrm/parameters/hdmi_audio (N on the baseline, Y on the candidate). On the candidate also check that dmesg | grep -iE 'Audio not supported|Failed to start AV endpoint|did not complete, stopping|synchronized without being stopped|silence kept|audio link (stop|complete) failed|ack without an issued|report without a descriptor' prints nothing. Speaker protection is untouched by this branch (no sound/soc or speakerguardd change); still confirm systemctl is-active speakerguardd and one quiet internal speaker playback on the J616s and the M2.

J616s (M4 Pro, T6041, desktop 26.6 DCP). The held-link audio code runs here, on the HDMI port (dcpext, native link), and DP/HDMI audio is now on by default.

  • aplay -l lists the DCP HDMI card without any boot parameter.
  • With dynamic debug on (echo 'file audio.c +p' > /sys/kernel/debug/dynamic_debug/control): pw-play a 48 kHz stereo file to the HDMI sink twice back to back, then a 44.1 kHz file. Each must be heard on the monitor (attended) and dmesg must show "link held, playing silence" after the first and "stream follows the held link's silence" on the next.
  • While playing, cat /proc/asound/card<N>/pcm0p/sub0/hw_params shows rate 48000, format S24_LE (or S16_LE if the sink offers no 24-bit), and a period of 50 ms or less.
  • Leave it idle 90 s, play again (heard). Unplug and replug HDMI while idle and again while playing, then play (heard, no stuck PCM). One s2idle suspend and resume with the display attached, then play.
  • After unplug, cat /sys/bus/platform/devices/*audio-controller*/power/runtime_status returns to suspended (the held silence gave back its PM reference).
  • Internal panel: for v in 50 300 500; do echo $v > /sys/class/backlight/apple-panel-bl/brightness; sleep 1; cat /sys/class/backlight/apple-panel-bl/actual_brightness; done and a keyboard brightness step, as on the baseline (shared backlight code was merged by hand).

M2 (T8112, 13.5 DCP). Type-C DisplayPort audio on the old (non-native) path is now on by default; the SIO bitmap fix and the SIO changes for channels without an idle transfer run here.

  • With a DP monitor with speakers on USB-C: aplay -l lists the DCP DP card; pw-play a stereo file twice, stop and start, unplug and replug, one suspend and resume, play again.
  • Without a monitor: the card stays quiet, no new dmesg lines.
  • Internal panel: the brightness loop above and actual_brightness readback; plug and unplug an external display, then modetest -M apple -c | grep -A3 eDP still reports a non-zero physical size for eDP-1 (panel dimensions after EDID clears).

J700 Neo (T8140, H17P DCP). No DT audio link, so with audio on by default its processors must stay exactly as before.

  • No "Audio not supported for firmware" or "Failed to start AV endpoint" lines, and aplay -l shows no DCP card.
  • Internal panel: the brightness loop above, a blank and unblank (idle blank in GNOME, or echo 4 > /sys/class/backlight/apple-panel-bl/bl_power then echo 0), as on the baseline (soft DPMS for H17P is unchanged by design).
  • External display on USB-C: hotplug, mode set, unplug, replug; eDP physical size still non-zero afterwards (modetest -M apple -c); one s2idle cycle with the external attached.

M1 Pro (T6000, headless, panel dead). DP/HDMI audio is now on by default for its HDMI (dcpext, dpaudio1/2).

  • Boots; dmesg -p3 count unchanged; aplay -l lists the HDMI card(s) with no errors and no sink. If an HDMI sink is attached, play and stop twice.
  • No backlight work runs (dead panel); confirm no new backlight registration errors.

Code that only runs on hardware we do not have: everything gated on the 14.7 board records and external role (T6030/T6031: J514S, J516S, J516C, J514C; T8122: J613), the DPA2 node, the external DSC re-modeset, the J516C swap timestamps, and the PMP sleep withdrawal (only apple,t6030-dcpext requests get apple,release-for-sleep).

Only omacom hardware can prove

M3 Pro/Max (T6030, T6031: J514S, J516S, J516C, J514C) and M3 Air (T8122, J613): the 14.7 panel backlight and its admission, J516C swap timestamps, the external DSC re-modeset, 14.7 native HDMI and Type-C audio, DPA2, and the PMP sleep withdrawal (the display gate marks only apple,t6030-dcpext requests). On our machines only the J616s exercises the held-link audio code, through the desktop 26.6 role.

🤖 Generated with Claude Code

malik-na and others added 30 commits November 1, 2026 10:52
On the J516C the 120 Hz panel presented at 60 fps: the 14.7 swap record
is sent with its timestamps zeroed, and the firmware then completes at
most one swap per 16.7 ms. Counter values (1 GHz on T6031) in the
timestamp slots make the firmware time out on the first swap. Write the
constant 120 in timestamp slots 0, 1 and 6 instead, a time that is never
in the future, after the swap record is encoded.

Add a swap_timestamps flag to the 14.x board records, set only in the
J516C record, and stamp a swap only for the internal panel of such a
record. The J514C (untested), the T6030 (J514S, J516S) and T8122 panels
and the external processors, which have no board record, send zero
timestamps, byte for byte as before. The counter timestamps of the
IOMFB template path (VRR modes on a main display) are not used by the
native 14.7 path and are unchanged.

Measured on the J516C on this branch: kmscube (atomic) presents at
120 fps (120.03 on two boots) on the panel's 120 Hz mode, 3456x2160
with the 74 notch rows hidden, and the first swaps of a boot complete
in 2.9 to 8.1 ms instead of 16.7 ms.

KUnit (apple-dcp-v14-board): the J516C record stamps its internal
panel's swaps; the external role, the J514C, T6030 and J613 records and
no record do not; a stamped swap holds 120 in slots 0, 1 and 6 and
is otherwise the encoded record, with and without a surface.

Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Naeem Malik <malik2015naeem@gmail.com>
[ryan: the J516C base EDID (d77c556) is not carried, so the board record and header gain only swap_timestamps]
(cherry picked from commit e3f69b7)
Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
Port the SF 44fe00e5eb58 panel-level implementation and its 4b318c41
fixture-lifetime correction onto PR177's current shared backlight API.
Keep panel_nits on the T6030 board record, with separate immutable root
machine admission for J514S and J516S. Other 14.7 boards and external pipes
keep their existing level encoding and policy behavior.

Register the requested default without sending it. Keep the loader's
unknown level until userspace requests brightness, and report actual
brightness as unknown until a successful present carries a level. Preserve
the H17P fade/default behavior and its soft-DPMS dispatch; the 14.7 panel
uses its own known-level-only blank and restore hooks.

Use the existing v14 RPC lock to serialize a swap with publication of its
active framebuffer and copied surface. Brightness work holds that lock
and the active framebuffer reference throughout its present. Close the
queue gate under that lock, then cancel outside it. Permanent teardown
also publishes quiescing, drains shared registration/update work, and
unregisters the class device while its CRTC is still valid.

Retain the original KUnit suite and add actual present/publication thread
interleavings, running-work suspend, real DPMS dispatch, failed-submit
actual-level checks, and shared registration/unbind controls. Static stubs
replace only the RPC boundary and a one-shot publication pause; the latter
continues through the real publication body.

Based-on: 44fe00e5eb58d54baf1cc9ad607293e774bfed44
Based-on: 4b318c4140e83e44033168836fe8cf4f76e16d80
Based-on: omacom/linux-aurora PR148 commit 0252453 (DjDeveloperr)
Generated-by: LLM
Signed-off-by: Chris Kearney <303316+iconidentify@users.noreply.github.com>
[ryan: resolved onto the 7.3 shared backlight: the T8132 (iomfb_is_m4) panel stays active, configurable and registrable as before, the desktop 26.x readback is kept, and soft DPMS excludes only the 14.7 panel (which has its own hooks) instead of every non-H17P panel; the swap keeps the J516C timestamps before the level block]
(cherry picked from commit 378d88c)
Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
Give the framebuffer fixtures real private GEM objects on a GEM-capable
DRM device. Release their initial references after the framebuffer and
active-scanout references, with the matching public object release.
Initialize the mode-state spinlock used by the actual unbind path.

Set the fixture panel dimensions so real DPMS dispatch also detects a
regression that routes this panel through H17P soft DPMS. Exercise the
J514S admission branch as well as J516S and the other-machine refusal.
Production code is unchanged.

Generated-by: LLM
Signed-off-by: Chris Kearney <303316+iconidentify@users.noreply.github.com>
(cherry picked from commit fb8f91b)
Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
Wrap and align the new declarations and calls, describe the gate spinlock,
and remove an extra blank line. Split two fixture field assignments and
write its null-callback assertion as a boolean expectation. Document that
resume reopens admission and leaves a pending level for the next normal
CRTC restore present.

The production C token stream is unchanged after removing comments and
whitespace. Keep the qualified encoder's constant-only layout assertions;
their checkpatch comparison warning does not indicate an operand-order
bug. New files are already covered by the Apple DRM maintainer path.

Generated-by: LLM
Signed-off-by: Chris Kearney <303316+iconidentify@users.noreply.github.com>
(cherry picked from commit 964323e)
Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
After the running brightness present and suspend have completed, leave a
new level pending and invoke the real callback as a previously queued
callback could arrive. It must refuse the level without another RPC even
though the framebuffer is still pinned. This separately checks callback
admission as well as the queue-side gate.

Generated-by: LLM
Signed-off-by: Chris Kearney <303316+iconidentify@users.noreply.github.com>
(cherry picked from commit f4ef473)
Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
A refused internal swap latches the panel failure state. Do not queue a
brightness retry that cannot be admitted after that failure; exercise the
real refused swap and subsequent work admission in the lifecycle test.

Declare the KUnit-visible registration worker in the shared internal
header so its definition has a prototype in KUnit builds. Replace the
nonexistent variant-tree reference with the public source commit.

Keep fbdev unblank notifications from sending the advertised default
before a level is known. Exercise the registered class operations before
and after a real present, and take the DPMS and suspend controls through
the restore present and its encoded level.

Generated-by: LLM
Signed-off-by: Chris Kearney <303316+iconidentify@users.noreply.github.com>
[ryan: dropped the Link: trailer to the review on the omacom tree]
(cherry picked from commit 40eb318)
Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
A late class kick may queue a worker even after the panel failure is
latched; the worker refuses to send the swap. Drain that asynchronous
callback before checking that no work remains, and keep the submit-count
assertion on both the queued and directly invoked callback paths.

Generated-by: LLM
Signed-off-by: Chris Kearney <303316+iconidentify@users.noreply.github.com>
(cherry picked from commit fa224e8)
Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
EDID invalidation clears display_info after the panel's startup dimensions
were set. Without an EDID, later probes leave a 0x0 mm connector and KWin
falls back to 1x scaling.

Restore the internal panel's dimensions after publishing its modes. Cover
repeated EDID clears, firmware sizes, DT fallback and external EDID sizes
with the production get_modes path under ASan/UBSan.

Generated-by: LLM
Signed-off-by: Eryk Wieliczko <eryk@wieliczko.ninja>
(cherry picked from commit b7c75a9)
Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
Type-C connectors have no DCP until a pipeline is routed. With
DRM_APPLE_DEBUG enabled, registering one dereferences the null platform
device. Skip the pipeline debug directory until a DCP is available.

Fixes: 2314090 ("drm: apple: route Type-C displays through a shared DCP fabric")
Signed-off-by: Eryk Wieliczko <eryk@wieliczko.ninja>
Assisted-by: Claude:claude-opus-5-5
(cherry picked from commit c92eb39)
Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
Check the published instance before Prepare and after its reply. Record the
link owner only after the firmware accepts it.

Fixes: f627d77 ("drm/apple: av: carry a Terminate's instance through its whole disconnect")
Signed-off-by: Eryk Wieliczko <eryk@wieliczko.ninja>
Assisted-by: Claude:claude-opus-5-5
[ryan: the 7.3 test runs every case on the 14.7 and desktop 26.6 roles and answers link status through its link_status field, so the new cases are parameterised and use it; the reply status check was already inside the open lock here]
(cherry picked from commit c806e16)
Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
A disconnected PCM can still own a prepared firmware link. Complete that
link before closing its client, including when sync_stop wins the race
against the deferred owner release.

Fixes: 3fe0ef0 ("drm: apple: Add the DCP 14.7 external role's HDMI audio")
Signed-off-by: Eryk Wieliczko <eryk@wieliczko.ninja>
Assisted-by: Claude:claude-opus-5-5
(cherry picked from commit d00568e)
Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
The 64-slot descriptor bitmap is only allocated two bytes. Use the bitmap
allocator so unsigned-long bitmap operations have enough storage.

Fixes: 5fdca02 ("dmaengine: apple-sio: Add Apple SIO driver")
Signed-off-by: Eryk Wieliczko <eryk@wieliczko.ninja>
Assisted-by: Claude:claude-opus-5-5
(cherry picked from commit 69e431f)
Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
The sink behind the J514S HDMI port (PS190 converter, TV) mutes the
audio of a link stopped and started again with an unchanged format,
until the DP link trains again. macOS never does that: it starts the
link once and, between streams, keeps it running on a cleared buffer
until the display sleeps or the format changes.

Do the same for stereo on the HDMI port: the stopped stream's DMA is
replaced by silence and the link is held. The mute was measured behind
the HDMI port only, so a Type-C output keeps one link per stream unless
hold_link=2; hold_link=0 restores one link per stream everywhere.

While links are held, a link is not started in the first 1.5 s after the
sink connects: once, at boot, a link started 0.2 s after the display
came on was not heard, and holding it kept it silent. A link prepared at
START configures the SIO channel first, as the PCM's prepare does.

Signed-off-by: Eryk Wieliczko <eryk@wieliczko.ninja>
Assisted-by: Claude:claude-opus-5-5
(cherry picked from commit 459ba24)
Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
Link the Type-C DisplayPort processor (dcpext1) to DPA2 on SIO channel
0x68, as the ADT links dcpext1 to dp-audio2, so a display on a USB-C
port gets an audio device too.

Signed-off-by: Eryk Wieliczko <eryk@wieliczko.ninja>
Assisted-by: Claude:claude-opus-5-5
[ryan: the DPA2 audio controller sits at the root, as this tree places DPA1 in t603x-j514s-j516s-hdmi.dtsi (neither has AP-side registers, so neither is a simple-bus child)]
(cherry picked from commit 5ab5f59)
Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
PipeWire changes the device rate to follow its streams: 44.1 kHz music,
48 kHz video. A held link of another rate or sample size was replaced at
START by one with the same channel layout, which the J514S sink mutes like
a same-format restart. After 48 kHz then 44.1 kHz streams, every stream
was silent until a replug.

macOS runs the link at one nominal rate and format and converts streams to
it. While links are held, the PCM now offers one rate (48 kHz, else 44.1
or 32 kHz) and one sample size (24 bits, else 16), taken from one element
that offers them together in stereo, and userspace resamples. The pair
covers every channel layout: userspace sets the format before the channel
count, so a pair applied only to stereo let it rule stereo out. Channel
layouts stay free: a layout change is heard.

Signed-off-by: Eryk Wieliczko <eryk@wieliczko.ninja>
Assisted-by: Claude:claude-opus-5-5
(cherry picked from commit 0ec6112)
Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
A DP audio sink behind the J514S HDMI port mutes for good when its
samples stop for 20 ms or more, until the DP link trains again. Swapping
one cyclic transfer for another stops the channel with TERMINATE and
starts the next one after its acknowledgment: usually short enough,
sometimes not.

Let a client set an idle transfer (struct apple_sio_idle, passed as
peripheral_config in a slave config call of its own). The channel issues
it while no other transfer runs. Terminating a transfer then hands over
to it after the issued descriptors, with no TERMINATE, and a transfer
issued later follows its issued descriptors the same way.

From its first idle transfer until it is quiet again, a channel accounts
for its issued descriptors in a ring, seeded with what it has in flight:
reports complete them in issue order, so each is charged to the transfer
that issued it, and one ISSUE is outstanding at a time.
dmaengine_synchronize() waits for an ended transfer's descriptors. If
they do not complete within 500 ms, it stops the channel with TERMINATE
and waits for their reports again, and resets the ring if they never
come. Removing the idle transfer does the same, and fails if the channel
cannot be confirmed stopped.

A channel that never had an idle transfer keeps the old accounting
unchanged: the DP audio of M1 and M2 Macs sets none.

Signed-off-by: Eryk Wieliczko <eryk@wieliczko.ninja>
Assisted-by: Claude:claude-opus-5-5
(cherry picked from commit f4dd5a2)
Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
The held link's silence replaced a stopped stream's DMA and was replaced
by the next stream's with a SIO TERMINATE in between, and closing the PCM
terminated it once more. A gap of 20 ms in the samples mutes the J514S
sink until the DP link trains again, as a link restart does: with a gap
forced to 20 ms, every later stream was silent, and Chromium resuming
after a 30 s pause was silent in 2 of 7 runs without one.

Make the silence the SIO channel's idle transfer while the link is held.
A stream's DMA follows it and hands back to it in descriptor order, and
the PCM's terminate at close leaves it running. Its periods shrink to
4 KiB, so a stream starts at most about 85 ms after its START.

A stream that ends into the silence leaves up to four periods issued,
which dmaengine_synchronize() waits for, 500 ms at most: on a port that
holds links, stream periods are kept to 50 ms. A silence whose channel
could not be stopped is not freed.

Signed-off-by: Eryk Wieliczko <eryk@wieliczko.ninja>
Assisted-by: Claude:claude-opus-5-5
(cherry picked from commit c0b3d14)
Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
An acknowledged DISPEXT request keeps the PMP's external display state
up while no display is shown. The requests are asserted once at probe
(apple,always-on) and never withdrawn, so they also hold through
suspend-to-idle.

Give report entries marked apple,release-for-sleep noirq sleep
callbacks: by then every display processor has suspended, with its
displays off and its links released or idle. Withdraw such a request if
it is acknowledged, with one replacement write of the request entry as
macOS releases its display requests, and assert it again in
resume_noirq, before the processors resume. Without the request the
external display stays dark until reboot, so a re-assert the PMP does
not acknowledge in time is written again, three times at most. The
T6030 display gate marks the DISPEXT requests of the processors it
enables.

The PMP graph host test runs the new callbacks against its fake PMP:
an acknowledged request is withdrawn and asserted again, an
unacknowledged or unmarked one is left alone, and a re-assert
acknowledged late is written again.

Signed-off-by: Eryk Wieliczko <eryk@wieliczko.ninja>
Assisted-by: Claude:claude-opus-5-5
[ryan: the gate hunk goes to drivers/soc/apple/display-gate.c (the renamed T6030 gate, still marking only apple,t6030-dcpext processors); the PMP graph test keeps this tree DRAM metadata cases and IRQ-safe entries beside the new sleep cases]
(cherry picked from commit b28cb3a)
Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
The DCPs take their HDMI ("dp-xbar") and Type-C ("typecN-dpinM") route
mux controls from mux-apple-display-crossbar. Nothing tells userspace
about that dependency, so mkinitcpio puts appledrm in the initramfs but
not the crossbar. The crossbar then loads only from the root filesystem.

With an encrypted root the passphrase prompt can outlast the deferred
probe timeout. On an M3 Pro (J514S) both external DCPs gave up their
routes 12 s into boot, and the crossbar bound at 44 s, after unlock:

  apple-dcp 2d2c00000.dcp: deferred probe timeout, ignoring dependency
  apple-dcp 2d2c00000.dcp: HDMI output unusable (dp-xbar: -110); USB-C displays are not affected
  apple-dcp 2d2c00000.dcp: Type-C display routes unusable: -110; USB-C ports go on without this processor
  apple-dcp 2d2c00000.dcp: external display processor unusable: its Type-C display routes did not register
  apple-dcp 2d6c00000.dcp: external display processor unusable: its Type-C display routes did not register
  [   44.078721] apple-display-crossbar 70304c000.mux: dpphy: T602X route -2, clocks disabled

No external display worked until reboot. Adding the crossbar (together
with the sn201202x PD driver) to the initramfs fixed it on the next boot.
The routes only take mux controls from the crossbar, so the crossbar is
the dependency to declare here.

Declare MODULE_SOFTDEP("pre: mux-apple-display-crossbar"). mkinitcpio
adds soft dependencies to the image, and modprobe loads the crossbar
first. Soft dependencies are optional, so a kernel with the crossbar
built in or disabled is unaffected.

Signed-off-by: Jeppe Bylov <jeppe@bylov.net>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 12c1012)
Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
The J516C runs the J516S panel, and its own 14.7 DCP image takes the same
level block in the swap (present byte +0x354, binary64 nits +0x35c, at most
500 nits): the e272b67 path presented brightness that way on this machine.
Set panel_nits on its board record and admit apple,j516c.

Generated-by: LLM
Signed-off-by: Samuel Carreño <soyminero11yt@gmail.com>
(cherry picked from commit a91ccf0)
Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
On a tree where an occupied display pipeline is reported as -ENOSPC on
every SoC, cd321x_display_taken() takes only the return code, and
-EBUSY means a transient mux or PHY failure. The probe controls still
call the two-argument form and no longer build there, and the
disconnect scenario injects -EBUSY as an occupied display, which such a
tree retries instead.

When the tree has the one-argument helper, check its contract in the
probe controls (-ENOSPC is taken; -EBUSY, -EAGAIN, -ETIMEDOUT, -EIO and
0 are not). In the disconnect scenario, let the mode stub classify its
error through the real helper, inject -ENOSPC as the occupied display,
and add a transient -EBUSY case that must retry before the USB role is
switched. A tree with the two-argument helper runs the old checks
unchanged.

The probe control also zero-initializes its cd321x_pm_state:
cd321x_pm_init() does not set setup_pending, which cd321x_pm_ready()
reads.

Signed-off-by: Chris Kearney <303316+chriskearney@users.noreply.github.com>
Generated-by: LLM
[ryan: kept the desktop 26.6 connect stub of this tree beside the new block; on this tree cd321x_display_taken() still takes two arguments, so only the zero-initialised cd321x_pm_state takes effect]
(cherry picked from commit dbb6bcc)
Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
An external mode is set with the display powered down, and the display
is powered up after it. For a mode that needs DSC (3840x2160 at 100 and
120 Hz on the J514S HDMI and Type-C ports) the firmware refuses that mode
set ("Modeset done, but pipe not enabled") and resets DSC, and the
power-on only configures DSC: the timings start in a mode set the
firmware makes on its own, after a hotplug notification it sends itself.
A swap that reaches it before then is dropped ("swallowed swap ID 1 as
timings are not enabled") and never completed, so A407 times out after
5 s and the display stays dark until a reboot. A fresh attach lost that
race 3 times out of 3. Without DSC, the power-on starts the timings
itself.

Set the mode once more after the power-on, with the pipe enabled. The
firmware then starts the timings before that call returns, before the
first swap; its own mode set finds them running. KUnit cases check
the calls of an attach and of a mode change.

Signed-off-by: Eryk Wieliczko <eryk@wieliczko.ninja>
Assisted-by: Claude:claude-opus-5-5
(cherry picked from commit 7ef3bc1)
Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
A stereo audio link is held between streams so that the sink does not
mute it on a restart with the same format. The hold_link parameter
limited that to the HDMI port by default (hold_link=1) until the Type-C
ports had been tested with it; hold_link=2 extended it to them and 0
turned it off.

On the J514S, a TV on a Type-C port behaves as it does on the HDMI port:
without the hold, every stream starts a new link with an unchanged
format, the TV mutes it, and USB-C audio stays silent after the first
stream. With hold_link=2 it played across Chromium stop/start, pw-play
runs and a PipeWire restart, and held links survived 90 s idle and
sleep.

Hold the link on every port and drop the parameter. Nothing needs to
turn the hold off, and a parameter that only makes audio go silent is
not worth keeping. Streams of more than two channels still get a link
of their own, as before.

Signed-off-by: Eryk Wieliczko <eryk@wieliczko.ninja>
Assisted-by: Claude:claude-opus-5-5
(cherry picked from commit 653176d)
Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
avep_init() checks the DCP firmware before it looks in the device tree
for the audio device linked from port@0. With hdmi_audio set, every
processor that starts through the IOMFB template path gets there,
including the H17P ones of the J700, whose firmware has no audio service
here and whose device tree links no audio device: each logs "Audio not
supported for firmware" as an error and dcp_start() then warns that the
AV endpoint failed. Processors of the other firmware without an audio
device (the internal panels) allocate the audio service state for
nothing and log "No audio support".

Look for the audio device first and return quietly without one, leaving
the processor exactly as it is with hdmi_audio off: no audio service
state, no AV endpoint. Processors that link an audio device go on as
before.

This matters once DP/HDMI audio is on by default, which the next commit
does.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
DP/HDMI audio through the display coprocessor has been off unless
appledrm.hdmi_audio=1 was set, so a distribution that wants it has to
ship that option in a modprobe.d file.

Make it the default and keep the parameter as the way to turn it off:
appledrm.hdmi_audio=0 on the kernel command line, or
"options appledrm hdmi_audio=0" in modprobe.d before the driver loads.
The default applies to every machine the driver supports, M1 and M2
included.

Signed-off-by: Eryk Wieliczko <eryk@wieliczko.ninja>
Assisted-by: Claude:claude-opus-5-5
[ryan: the dcpext_probe and t6030_show_notch parameters of the conflicting context are not in this tree; the previous commit keeps processors without an audio device (the J700 H17P ones) quiet once this is on]
(cherry picked from commit c9e5b25)
Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
The J613 board record does not admit panel nits, so the working 14.7
display session never registers a backlight device. Admit the J613 to
the existing nits path and keep the firmware UUID and display handoff
checks. J615 and J514C remain excluded.

Run the existing swap-level KUnit case for J613 as well as T6030. Expose
the existing completion and refusal counters in debugfs so a requested
level can be distinguished from one the firmware accepted.

On a 13-inch M3 MacBook Air with 23J220 DCP firmware, the driver registered
apple-panel-bl and completed requests for 100, 250, 400, 1, 500 and 140
nits with no refusals or display failures. The user confirmed visible
brightness changes in person.

Assisted-by: OpenAI Codex (gpt-6.1-sol)
Signed-off-by: DjDeveloperr <hey@djdev.me>
(cherry picked from commit eec6458)
Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
…t fixtures

The panel-takeover-registration and m4-dpms-retirement host tests build
dcp_get_brightness(), dcp_backlight_register() and dcp_backlight_active()
from dcp_backlight.c. Since "drm/apple: port the scoped T6030 14.7 panel
backlight" these call dcp_backlight_presents_nits() and
iomfb_v14_7_panel_nits() and pick dcp_backlight_ops_v14 for the 14.7
panel, so both stopped compiling.

Build the real dcp_backlight_presents_nits() into both units and answer
iomfb_v14_7_panel_nits() with false: neither the desktop 26.6 panel nor
the T8132 one is a 14.7 panel. The checks themselves are unchanged.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
The panel-dimensions case from "drm/apple: restore panel dimensions after
mode probes" was written against a publication fixture whose connector
already carried display_info's physical size and whose get_modes() had no
T8132 branch. Here neither holds, so the case did not compile.

Give the fixture's display_info its width_mm and height_mm, and add the
case to the fixtures that select the older external backends, which
define the T8132 hooks away as publication-hpd does. The case's checks
are unchanged and pass.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
aurora-wip moved on (AOP, AVE and AVD fixes) after this branch was cut
from 5cf4c5e. No conflicts: none of its changes touch the files of
this lane.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
aurora-wip moved on again (AVD safety recovery). No conflicts: it does
not touch the files of this lane.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
aurora-wip took the integration/aurora sync, a dwc3 Kconfig fix, the
arm64 CPU model name and the J616s VRR gamma work. Git merged them
cleanly; the sync touches dcp.c, iomfb.c, iomfb_template.c and the
display gate next to this lane, so the host selftests, KUnit and the
fleet build ran again on the result.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
@RyanTheTide

Copy link
Copy Markdown
Contributor Author

Folded into the single omacom up-port branch omacom-sync/all (head b463cf8), which carries this lane unchanged as a merge. One PR for the whole up-port follows once the combined kernel has passed the hardware regression run. Per-commit verdicts above stay as the record.

@RyanTheTide RyanTheTide closed this Nov 1, 2026
@RyanTheTide
RyanTheTide deleted the omacom-sync/display branch November 1, 2026 04:55
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.

6 participants