| logs | ||
| 0001-pixel-clock-fix.patch | ||
| 0002-hdmi-reconnect-races.patch | ||
| README.md | ||
Asahi DCP: HDMI reconnect fixes
Two patches for external-display reconnect problems after HDMI hotplug or a TV power-cycle, related to AsahiLinux/linux#610 ("HDMI hotplug hangs compositor indefinitely on MacBookPro18,1 and MacBookAir10,1"). Together they turn an unreliable reconnect (1-2 manual retries needed) into one that just works.
Status
Not submitted to AsahiLinux/linux. I opened a pull request for the first patch (AsahiLinux/linux#632) and withdrew it, because Asahi's Generative AI Policy forbids AI-assisted contributions, and I used AI to develop both patches (see Disclosure). Publishing here instead, under the kernel's own GPL-2.0 license, for anyone hitting the same bug.
Patch 1: external display pixel clock (0001-pixel-clock-fix.patch)
On external (DP-to-HDMI) displays, the DT clock entry for the DCP is a
fixed-clock placeholder that always reads 0 Hz. When the firmware calls
getClockFrequency() during a modeset, it gets 0 and logs:
RTKit: syslog message: PPipeDCP_H13P.cpp:11109: IOMFB updateFrequencies EDT ERROR:
getClockFrequency(0) (0) < videoClock 297000000! Giving up on frequencies.
...then does an unreliable modeset anyway. In practice, the external display often stays dark after a hotplug or TV power-cycle.
Fix: cache the real pixel clock from the DRM mode (mode->mode.clock, in
kHz) during iomfb_modeset(), and return that from
dcpep_cb_get_frequency() for external displays instead of the always-zero
clk_get_rate() result. Cleared on disconnect. Integrated (eDP) panels aren't
affected, they have a real clock entry and keep using clk_get_rate(). Two
files, 14 lines: dcp-internal.h, iomfb_template.c.
Patch 2: HDMI reconnect races (0002-hdmi-reconnect-races.patch)
Even with Patch 1, a fast TV off/on cycle would often still leave the display dark on the first reconnect, needing a second unplug/replug. Two races caused it:
dcp_poweroff()only released the DPTX link if the HPD GPIO read LOW at that exact moment. On a fast unplug/replug the cable's often already back in by then, so the link never tore down, and every laterdcp_dptx_connect()silently no-op'd against a staleconnectedflag.- When
dcp_dptx_connect()races ahead of the firmware's own HPD handling, the firmware enumerates an empty mode list. The hotplug uevent goes out with 0 modes, userspace has nothing to work with and gives up, and nothing re-notifies it once the real modes show up.
Fix: always release the DPTX link on poweroff regardless of GPIO state;
suppress stale disconnect events when the GPIO still reads connected instead
of tearing down a live link; retry the DPTX connect (bounded, 1s apart) when
TimingElements comes back empty; re-fire the hotplug uevent if valid modes
arrive after an empty one already went out. Three files: dcp.c,
dcp-internal.h, iomfb_template.c.
Testing
Built and booted together on a Mac mini (Apple Silicon M2), Debian (Bananas) on Apple Silicon, against a TCL 43T69C TV over HDMI.
- Patch 1 alone: confirmed via dmesg that "giving up on frequencies" no longer shows up on modesets, across several boot/test sessions (2026-09-20/21).
- Patch 1 + 2 together: 6/6 controlled TV power-cycles recovered correctly. Every failure-prone cycle got caught by Patch 2's retry logic, never needing a second manual attempt. Then a full day of ordinary use (2026-09-21), 100% recovery, no manual intervention needed once.
Evidence
Raw logs behind the Testing section, for anyone who'd rather check than take my word for it.
logs/journalctl-failures-2026-05-to-09-21.txt— full, uneditedsudo journalctl --grep="Giving up on frequencies"output, every boot from 2026-05-01 to 2026-09-21. 274 lines, recurring across dozens of boots against several different displays (the Mac mini moved through a few temporary locations over this period), withvideoClockvalues 74250000, 297000000, 148351664 and 74175832 Hz. Not one display's quirk, reproduces across different hardware and locations. The TCL TV used for the live capture below has only been in use for 2 days, it's the current test rig, not the source of this history.
logs/tcl-hdmi-diagnosis-2026-09-21.jpg— the TCL TV's own HDMI diagnostics, captured during a failed reconnect on an unpatched boot: connection status, signal reception and screen display all fail, while audio and AV sync (which don't depend on the video link) pass. Independent confirmation from the display's own side.logs/hdmifix10-boot-clean.txt— kernel version, uptime, and a dmesg grep for the same error on the currently-running7.1.13-hdmifix10boot (both patches applied): zero hits.logs/live-tv-cycle-2026-09-21.txt— admesg -Tbefore/after diff around a real TV power-off/on cycle on the patched kernel, captured live. Shows the full sequence: HPD deassert on power-off, HPD reassert 7s after power-on, the empty-mode race from Patch 2 happening exactly as expected (TimingElements parsed: nr_modes:0), the automatic retry catching it, the stale-disconnect suppression firing twice during the retry, and a successful 3840x2160@60 modeset 11 seconds after power-on. One retry, no manual replugging, no errors anywhere in the capture.
Hardware scope
The root cause of Patch 1 (external display's clock always reading 0) also shows up on a MacBook Pro, through a different HDMI bridge chip (AppleDCPMCDP29XX, vs. the Mac mini's DP2HDMI). Same underlying bug, not specific to one Mac model or bridge chip. On that MacBook Pro's stock, unpatched kernel, the modeset still recovered right after the error each time, no sign of Patch 2's reconnect races, so the root cause is general but whether it actually blanks the screen depends on extra timing/race conditions that aren't present on every machine.
With hdmifix10 (this repo's patches) installed on that same MacBook Pro, three consecutive TV off/on cycles (logs/mbp-hdmifix10-tv-cycle-2026-09-22.txt) all completed cleanly, every reconnect finished a modeset within 1-2 seconds, zero errors in the capture. Confirms Patch 1 fixes the root cause on a second Mac model, not just the one it was developed on.
Disclosure
I used AI (Claude) for the root-cause analysis, both fixes, and this writeup. The testing was done by hand, on real hardware, by me. Disclosed explicitly because Asahi's contribution policy treats hiding AI involvement as a serious violation. Publishing here instead of submitting upstream respects that policy while still making the fixes available to anyone who needs them.
License
GPL-2.0, same as the Linux kernel these patches apply to.
