Repository navigation
drm: apple: Type-C relink and DPMS wake fixes, DCP audio, AVD buffers, AV slot reuse (port to aurora-wip-rebase) - #328
Merged
DjDeveloperr merged 9 commits intoOct 16, 2026
Conversation
A USB-C monitor with a built-in USB hub (EIZO EV2780) intermittently stays dark after a cold boot or a hot-plug on the M1 MacBook Air and the M1 Mac mini. DCP trains the link for the first modeset at about the time the monitor's hub brings its SuperSpeed link up. When the two overlap, the sink loses the link, but DCP still reports the modeset as linked: UnifiedPipeline::mode_set_gated(): 2560x1440@59 Hz link: 1 Then one of two things happens. DCP gives up on its own 2.008 s after asserting HPD: IOMFB: IOAVVideoInterface terminated VideoInterfaceIOAV::unplug_gated(): display HPD removed or it keeps driving the dead link without noticing, while the monitor pulses HPD about 2-4 s later to be detected again. In both cases the CD321x still reports DP alt mode with HPD high, and nothing re-detects the sink. With dwc3 kept off the port, 5 out of 5 boots brought the display up; with it, 3 out of 6 failed. Replay an unplug and replug of the sink when DCP drops a sink that still asserts HPD, or when the sink asks for attention (IRQ_HPD): the link is then retrained after the hub has settled, as a cable replug does. A request from the sink within 4 s after a relink is the sink's late reaction to the loss the relink already handled and is ignored; another relink would only interrupt the new link. A sink request must not be dropped as an unchanged route state either. A connection gets at most three relinks; the replay does not reset that count. Pulsing only DCP's HPD instead, with the connector kept connected, raced with DCP re-detecting the sink on its own and left the display dark on the Mac mini. H17P and native external pipes keep their own recovery. Once the relink budget is spent, a sink request falls back to dcp_dptx_recover_irq() or dcp_retrain_oob() as before. With this, 8 out of 8 cold boots of the MacBook Air and 8 out of 8 of the Mac mini (EIZO on the port that failed) brought the display up. Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
A DisplayPort sink that lost the link drops HPD and raises it again to be detected anew. The EIZO EV2780 does so for about 250 ms, which falls within the 500 ms debounce of cd321x_update_work(). The worker then sees DP alt mode with HPD high, the state it already applied, and cd321x_typec_update_mode() returns without telling the mux, so the display driver never learns that the sink wants attention and the display stays dark. The out-of-band DRM hotplug event does not cover this either on the M1 MacBook Air and Mac mini: their connector nodes have no "displayport" reference, so connector_fwnode is NULL. When HPD changed within the debounce window and is high before and after, pass the state on with DP_STATUS_IRQ_HPD set, even though it otherwise matches the applied one. Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
Waking a DP alt mode display from DPMS off with sway ("output * power
on") on the M1 Mac mini (Fujitsu E24T-7 Pro on USB-C, which keeps HPD
asserted while blanked) power cycles the display about every 750 ms
until reboot:
dcp_hotplug() connected:1 valid_mode:0 nr_modes:1
dcp_poweron() starting
set_digital_out_mode finished
dcp_poweroff() done
...
With the cable attached, dcp_poweron() reconnects DPTX and waits for
IOMFB to report the sink before the commit does its modeset. At that
point no mode is valid yet, so dcpep_cb_hotplug() takes the HPD for a
sink that asserted HPD only after a failed modeset and sends
DCP_HOTPLUG_NOTIFY. dcp_hotplug() then sets the connector's link-status
to BAD. wlroots treats a bad link as a disconnect and recreates the
output, which disables the CRTC and enables it again. That wake does
the same, so the loop never ends. Each round also leaks AFK service
slots ("AFK[ep:29]: no reusable service slots") and the system becomes
sluggish.
Do not take the HPD that dcp_poweron() waits for as a late one: the
modeset of the same commit follows. A sink that asserts HPD only after
dcp_poweron() stopped waiting is still handled as before.
Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
On the M1 Mac mini with two Fujitsu E24T-7 Pro monitors, which have no audio (single-block EDID 1.3), PipeWire logs spa.alsa: hw:0p: snd_pcm_start: No such device or address about 130000 times a second, for hours, as soon as something plays to a DCP audio output: 4.1 million log lines in one boot, with journald dropping most of them, and a core kept busy. Without a sink, opening, configuring and preparing the PCM succeed, as userspace drops an output that fails its probe for good, but START fails with -ENXIO. That does not stop userspace from trying: PipeWire starts playback after its first write and ignores the error, and a stream that never starts never makes it wait, so the next wakeup is immediate and tries again. Any other error ends up in its recovery, which prepares and starts again. Play into the void instead, as HDMI PCMs on other platforms do: without a sink, or once the sink the stream was opened for is gone, START succeeds and the stream runs on the clock, without DMA and without a DCP audio link. The position follows the time since START and a work item reports the periods. The samples are dropped. A stream playing into the void is not stopped as disconnected when a sink goes away; a sink attached later is used by the next stream opened. Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
A USB-C monitor with a built-in hub drops the DP link right after the first modeset of every DPMS wake, which dcp_typec_relink() recovers by replaying an unplug and replug. Its retry counter is only reset when the Type-C generation changes, i.e. on a real cable replug, so all wakes of one connection share DPTX_RELINK_RETRIES tries: after three wakes the fourth drop is handled as an unplug and the display stays dark until the cable is replugged. The limit exists to stop relink loops within one link bring-up. Reset it in dcp_poweron() when the CRTC comes back from DPMS off. No relink can run while the CRTC is off, dcp_typec_relink_start() refuses then. Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
Since commit 57f9f36 ("drm/apple: fence EDID publication by service lifetime and unblock RX"), the teardown of DCP's AV service schedules the connector hotplug worker to invalidate the EDID. DCP tears that service down whenever a Type-C CRTC is powered off with the display attached (DPMS off). dcp_hotplug() then finds the connector connected without a valid mode and reports the link as bad. wlroots treats a bad link as a disconnect and replaces the output on the next wake, which powers the CRTC off and on again, and that power off does the same: the display never comes back from the first DPMS off (Mac mini, EIZO EV2780 on USB-C). There is no link while the CRTC is off, and dcp_poweron() retrains one on wake. Leave the link status and the CRTC alone then; the EDID is still invalidated. Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
SIO has 64 descriptor slots, shared by all its channels, and its cyclic prep takes one slot per period. The PCM allowed any number of periods, so PipeWire's default of 256-frame periods in a 32768-frame buffer asked for 128 of them. sio_prep_dma_cyclic() then ran out of slots, snd_dmaengine_pcm_trigger() returned -ENOMEM, ALSA undid the START with a STOP (a stop_link round trip to DCP), and PipeWire retried about 100 times a second with no sound. Up to three DP audio outputs share one SIO on t600x and t602x, so allow at most 16 periods per stream, 48 slots for all three. Fixes: cb24343 ("gpu: drm: apple: Add DCP audio driver") Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
The capture queue never sets max_num_buffers, so vb2 limits every context to VB2_MAX_FRAME (32) buffers. Nothing in the driver needs that limit: reference frames are looked up by timestamp (vb2_find_buffer()) and handed to the hardware by DMA address, never by buffer index. 32 buffers leave too little room for userspace to decode ahead. With a 16-frame DPB, four frame threads and the frames held for display, mpv's decoder queue (--vd-queue) gets only a few frames before VIDIOC_CREATE_BUFS fails with ENOBUFS, and the FFmpeg V4L2 request hwaccel then falls back to software decoding. Decoding ahead is needed because the t8103 AVD decodes 4K59.94 H.264 at only ~41 fps during a 125-156 Mbit/s burst, so playback drops frames unless the decoder has built up a lead of 60-90 frames beforehand. Add a max_capture_buffers module parameter, default 128. Buffers are still allocated on demand by userspace, so this only raises the limit. Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
The AV endpoint (0x29) announces a fresh DCPAVSimpleVideoInterface and DCPAVAudioInterface on new channels for every DPTX connection, so every display replug or DPMS wake that drops HPD uses two more slots. Since "drm/apple: pin DP service owners before recycling retired AFK slots" a torn-down slot is only reclaimed if its ops opt in with .reusable, which the AV services never did. After eight connections the 16-slot table is full, every later announcement fails with AFK[ep:29]: no reusable service slots and the audio service of that port is not re-registered until reboot. Convert the AV owners and opt in to reuse: - DCPAVSimpleVideoInterface keeps no pointer to its service. - asrv->srv now holds an owner pin taken in init and dropped in teardown. A teardown of an older generation no longer clears the pointer or unplugs the jack of its successor. - av_service_connect() and av_service_disconnect() call into the service after dropping srv_rwsem, so they pin it for the duration. Add afk_service_pin() for this; unlike afk_service_get() it also succeeds after teardown, so the close is still sent. Add a KUnit case for a close pinned across teardown. Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
This was referenced Oct 19, 2026
This was referenced Oct 25, 2026
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This ports my open aurora-wip PRs onto aurora-wip-rebase (7f83518):
The commit messages are unchanged apart from a short note in the relink commit. See the original PRs for the full background.
Why the relink is needed on aurora-wip-rebase
On aurora-wip-rebase alone, the USB-C display (EIZO EV2780, dcpext on the Mac mini j274) came up at boot and went dark about 5 s after login. PipeWire probed the DP audio PCMs, and then DCP restarted its AV interfaces and dropped a sink that still asserted HPD. There was no Type-C unplug and no IRQ_HPD, so nothing recovered it:
That is the case the first commit handles ("DCP dropped a sink that asserts HPD").
Commits
dcp.c/dcp-fabric.c.external_native), which recover through their own lifecycle.dcp_dptx_recover_irq()(disconnected connector) ordcp_retrain_oob()(connected) run as before.dcp_dptx_disconnect_oob()/dcp_dptx_connect_oob(). Each of them bumpstypec_generationexactly once, so the check for a real replug during the replay still holds.dcp.chunk todcp_poweron_h17p(). I moved it todcp_poweron(), which is the path the 12.x/13.x firmware uses.dcp_pcm_hw_unpluggedandopen_unpluggedcode. On this base, opening a DCP PCM without a sink is only allowed on H17P. Elsewhere open fails with-ENXIO, so the void path covers a sink that goes away after open, and H17P's unplugged open.dcp_poweroff()) does not bumptypec_generation, so it does not reset the budget.dcp_hotplug().dcp_pcm_hw_unplugged.av.cstill don't opt in with.reusable.I dropped one commit of #275, "drm: apple: update connector dimensions without a hotplug". aurora-wip-rebase already applies
DisplayAttributesdimensions through its owndimensions_wqwithout a hotplug.Testing
W=1, apple drm + tipd + avdDRM_APPLE_KUNIT_TEST,DRM_APPLE_DISPLAY_KUNIT_TEST,DRM_APPLE_FABRIC_KUNIT_TEST)apple-display-parser.parser_route_programming_guard(dcp_crtc_needs_route_start()with a tunnel route, parser-test.c:823), fails the same way on 7f83518 alone (209/211). The newafk_service_close_pin_testpasses.tools/testing/selftests/drivers/gpu/apple-dcp/run.sh)quiesce.py(atypec_mux_*marker is not found inmux.c).swaymsg "output * power off/on"aplayto both DCP cards-ENXIO(upstream behaviour on non-H17P). PipeWire: 0 errors, 0% CPUmpv --hwdec=v4l2request, vd-queue 96 (needs more than 32 capture buffers)ffmpeg -hwaccel v4l2requestdecodes 15 s (900 frames) without AVD errorsNot tested yet on this base: the EIZO EV2780 on USB-C, which triggers the relink above, and a cable replug. I'll add the results here.