AYN Odin 2: fix external display output: micro HDMI capped at 1024x768, USB-C output often undetected, audio broken across hotplug and sleep - #3080
Conversation
2734859 to
450b766
Compare
|
Heads up for reviewers: testing on the new release 20260801 shows the 7.1 kernel bump has broken the USB-C DisplayPort path on SM8550 entirely, which affects the dock half of this PR. Symptom on an AYN Odin 2 on 20260801 (kernel 7.1.2): power delivery negotiates (device charges, typec partner registers) but DP-1 never leaves "disconnected", and the boot log shows the connector being built without its SBU mux: The same dock works on the same hardware on release 20260701 (kernel 7.0.11). This is the typec_mux_match() dedup regression from the 7.1 merge window, already identified and fixed for SM8750 in #3068, whose commit message notes it is not device specific. |
450b766 to
b0840b8
Compare
|
Update: the 0517 kernel patch is now hardware validated on the Odin 2. I built this branch for SM8550 and flashed the image on the device: with the dock connected the display comes up at boot, DP-1 reports connected, the sink's 256 byte EDID is read, and the output runs 1920x1080@60. Unplug, replug and the micro HDMI path were re-tested on the same build. On stock 20260801 the same dock never leaves "disconnected". Correction to my earlier comment: the boot line Rebased on next and marking this ready for review. PS: the PR description itself has been amended as well, so reviewers reading it now get the corrected wording rather than this comment's version: item 5 no longer cites that boot line as the symptom, and the Testing section carries the hardware results above. |
|
Let's put this PR in Draft until #2954 is getting merged. |
|
I keep this PR as draft waiting any progress regarding #3126 |
c93f6bd to
135d112
Compare
b0840b8 to
67e4eee
Compare
67e4eee to
3af5b96
Compare
check_hdmi_connected in rocknix-fake-suspend, _get_present_externals and _get_all_internals in output_monitor, and the internal panel blanking all answered the same two questions from their own copies: is an external display attached, and which outputs are internal panels. Three copies of each invites them to drift apart, and drifting changes behaviour silently. Move both into /usr/bin/external-display and have the callers ask: external-display connected|list|internals|blank [backlight]|unblank fake-suspend loses its connector glob, its compositor ladder and its backlight helpers, 66 lines net. output_monitor loses two functions. Two behaviour changes fall out. blank falls back to the backlight when the DPMS path powered nothing off, where before an internal panel missing from wlr-randr left the screen on. And the connector match now accepts a two digit index, so HDMI-A-10 counts. blank touches internal panels only while unblank restores every output. That asymmetry is deliberate: powering off an external output drops the DP audio jack, while powering one on is free and recovers an output that something else left dark. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Found on an AYN Odin 2 on kernel 7.1.2. Unplug an external display and audio is gone until a reboot. Every userspace indicator looks healthy while it happens, which is what made it hard to see: the Speaker sink is marked default, both sinks sit at the user volume, and the amp registers read 0. The DSP is where it goes wrong. DP0 Jack stays on after the cable is pulled, so the route stays on DISPLAY_PORT_RX_0 with RX_CODEC_DMA_RX_0 and PRIMARY_MI2S_RX switched off, and playback lands on a backend with nothing on the end of it. Userspace does not notice because nothing in userspace is wrong. _switch_audio was gated off entirely here because the micro HDMI port carries no audio. That gate also suppressed the switch back, which is the only thing that rebuilds the route. It was invisible until now because on 7.0 the jack reported the unplug and wireplumber moved audio back by itself. Gate the outbound direction only: docking still needs no help, coming back does. Re-selecting the profile re-initialises the codec and resets SPK_L and SPK_R PCM Playback Volume to their silent 1023 default, and that can land after the single write that unparks them. Assert the unpark until it sticks, otherwise the speakers stay mute with everything else looking fine. Pin auto to 60 Hz while here. Falling back to 1920x1080 at any refresh let a dock's EDID put the output at 100 or 144 Hz. auto now tries 1080p60, then 720p60, then leaves the sink on its preferred mode. Tested on an AYN Odin 2, dock and micro HDMI, connect and disconnect: audio returns to the speakers every time with no reboot. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
3af5b96 to
d8f0ef3
Compare
|
Rebased onto current next, and out of draft. This isn't waiting on #3126 anymore. Here is why it was waiting. Once real suspend works, the power key stops going through It doesn't. Two scripts were each answering the same two questions with their own code: is an external display plugged in, and which outputs are the built-in panels. Both answers now come from one helper:
Doing that refactor turned up two bugs, both fixed here. Audio stayed dead after unplugging a display until a reboot: switching back to the speakers was being skipped along with switching out to the display, and switching back is the only thing that rebuilds the route. And All retested end to end on an AYN Odin 2 over fake suspend: dock and micro HDMI, connect and disconnect, power key docked and undocked. Audio comes back on the speakers every time with no reboot. If suspend land as merged, will do a new PR to follow this new helper for it. |
Summary
Make external displays work properly on the AYN Odin 2 / Odin 2 Mini, on both of their output paths: reliable detection, correct video modes with a way to choose them, and sane audio behaviour across hotplug and sleep.
While the work was driven and tested on the Odin 2, several fixes live in shared scripts and benefit any device with external display support: display detection when the compositor misses a hotplug event, internal panel rotation after unplug, volume handling across connect/disconnect, and the fake-suspend behaviour with an external display attached (including a timed shutdown that could power off a device while it was driving a TV).
These devices have two external display paths. The USB-C path uses native DisplayPort alt mode; this covers the Odin 2 Official Dock and equally any USB-C video adapter (tested, they behave the same): once the connector is detected, EDID negotiation and audio work natively, but the hotplug event itself is often missed on current builds, leaving the dock undetected (this PR fixes that, see below). The micro HDMI port however goes through a Lontium LT8912B DSI to HDMI bridge, which has no DDC support at all (per Lontium's product brief, confirmed by probing on hardware), so the sink's EDID can never be read on this port. The kernel therefore falls back to fail safe modes topping out at 1024x768, and the hardcoded
1920x1080@60modeset inoutput_monitorfails silently.What this PR does:
1920x1080@60(preferred) and1280x720@60. 1080p60 is the most this bridge can output (150 MHz pixel clock limit), so no higher modes are possible. 30 Hz modes were also tested on hardware, but the bridge produced a corrupted signal with every 30 Hz timing an EDID can encode, so only the two 60 Hz modes are present on this PR.external_display.modesetting, applied live byoutput_monitorwithin about 10 seconds, no replug or reboot needed:auto(default, keeps today's 1080p60 behaviour) or a fixedWIDTHxHEIGHT@RATE. A fixed mode the sink cannot do falls back to auto.output_monitorrobustness fixes found while testing on hardware:DEVICE_EXTERNAL_DISPLAY_AUDIO. The micro HDMI port carries video only, no audio: testing AYN's Android firmware on the same hardware shows the same behaviour, and reverse engineering with Claude Code (the mainline lt8912b driver has no audio support and the DSP topology has no backend for the bridge's audio input) reached the same conclusion. Gating the audio switching off also removes the profile probing churn (including a wireplumber restart retry loop) that could randomly reset sink volumes to 100%. The DP alt mode path keeps its native jack based audio switching, which works.audio.volume), and a lost default sink is re-picked explicitly (wireplumber loses it on some profile flips, leaving dead volume keys and silence). Audio used to blast at 100% during the handoff and stay wrong until a volume key press.wpctl/pw-clicalls are wrapped in timeouts so a wedged audio stack cannot freeze display switching.111-sway-inithonours the configured mode for displays already connected at boot, and defaults added to thesystem.cfgtemplate.fake-suspendfixes, each verified on hardware and against the mainline msm DP code:display_offpowers off only internal panels. A DPMS off on an active DP output makesmsm_dp_display_disable()report the audio jack as unplugged, and HPD plug events arriving while the display is off are silently discarded, leaving DP audio dead until a physical replug.check_hdmi_connectednow also matches DP connectors. Before, a docked (USB-C DP) device would fake-suspend despite the existing ROCKNIX "do not suspend while on an external display" rule, and its timed shutdown would then power the device off after 15 minutes while it was driving a TV.Usage (no UI yet)
This concerns the micro HDMI port: with no EDID available there, the mode has to be chosen from the fixed list below (the USB-C path negotiates with the display natively and needs no manual setting). Until a settings menu exists, the mode is set over SSH and picked up live:
autoreproduces what the current output_monitor code already hardcodes on connect (note: the wiki documents the older manual sway config method, not this): try1920x1080@60first, then1920x1080at any refresh rate, and if the display offers no 1080p at all, keep the display's own preferred mode. This PR does not change that default, it makes it explicit and selectable. On the micro HDMI port auto always lands on 1080p60, since the synthetic EDID advertises it as preferred. A fixed mode the display cannot do falls back to auto.Behaviour on other devices
The device quirk (synthetic EDID, audio gate) installs only on the AYN Odin 2 / Odin 2 Mini; no other device gets it, SM8550 or otherwise. The changes to the shared scripts (
output_monitor,fake-suspend,111-sway-init) do apply to every device with external display support: they are written to preserve the existing defaults (modeautokeeps the current hardcoded behaviour, the amp parking only acts where the amp controls exist, the audio gate only acts where the quirk sets it), but they were hardware tested on the Odin 2 only. Reviewers may want a smoke test on one non Odin device with HDMI out.Testing
AYN Odin 2, ROCKNIX 20260701, real hardware over SSH, with a boot time rig replicating the shipped ordering (quirk arms the EDID before sway starts). Sink was a Magewell USB Capture Card reporting exact mode and refresh.
Micro HDMI adapter (LT8912B path):
auto: 1920x1080 at a true 60 Hz on the sink (previously 1024x768)1280x720@60and1920x1080@60: applied live within 10s, verified on the sink OSD, and a fixed mode survives replugOdin 2 Official Dock and USB-C adapters (DisplayPort alt mode path):
external_display.modeapplies to this path too (auto / 720p60 / 1080p60 verified)Release 20260801 (kernel 7.1.2) and the 0517 kernel patch: on stock 20260801 the dock is dead, PD negotiates but DP-1 stays "disconnected" for as long as it is plugged in. This branch was built for SM8550 and flashed on the Odin 2: with the dock connected the display comes up at boot, DP-1 reports connected, the sink's real 256 byte EDID is read and the output runs 1920x1080@60. Unplug, replug and the micro HDMI path were re-tested on that build and behave as described above, including the speakers staying on the user volume while the video-only micro HDMI output is connected. One note for anyone bisecting this: the boot line
pmic-glink: Failed to create device link ... with supplier usb0-sbu-muxis present with and without the patch, so it is a fw_devlink artifact, not the signature of the fault; the reliable symptom is DP-1 never leaving "disconnected".A third party USB-C hub (HDMI plus USB/ethernet) was also tested and behaves identically to the Official Dock. Not hardware tested: note that I do not have an AYN Odin 2 Mini (same bridge, same display path) to test, but it should work in theory. Other devices could maybe inherit from this PR if needed.
Additional Context
output_monitoris shared by all devices with external connectors. The new behaviour is gated on quirk variables and on a single setting whose default preserves today's behaviour.AI Usage
Did you use AI tools to help write this code? PARTIALLY
Parts of the implementation were review/refactor with Claude Code. Root PR, debug analysis, design decisions, hardware testing and validation were done on a real Odin 2 by a human (Me).