Skip to content

RK3576: DP Alt Mode display management (auto-switch + manual cycle)#2678

Open
pgratz1 wants to merge 1 commit into
ROCKNIX:nextfrom
pgratz1:pr/rk3576-dp-userspace
Open

RK3576: DP Alt Mode display management (auto-switch + manual cycle)#2678
pgratz1 wants to merge 1 commit into
ROCKNIX:nextfrom
pgratz1:pr/rk3576-dp-userspace

Conversation

@pgratz1
Copy link
Copy Markdown
Contributor

@pgratz1 pgratz1 commented May 9, 2026

Summary

Userspace changes to manage display output when an external display is connected via USB-C DP Alt Mode on RK3576 devices.

Depends on: #2680 (kernel patches for DP Alt Mode support)

Changes

dp_monitor

  • Subscribes to sway IPC output events rather than udev — avoids the race condition where wlr-randr/swaymsg require sway to have already processed the new output before they can act on it
  • Automatically disables the internal panel (DSI-1) when an external DP/HDMI display is connected and re-enables it on disconnect
  • Moves EmulationStation to the external display on hotplug
  • Stops the USB gadget when DP Alt Mode is active (data lane conflict on RK3576)
  • Launched automatically by 111-sway-init on any sway device with DP or HDMI hardware connectors — not RK3576-specific

dp_output_cycle (new)

  • Manual display output cycle bound to L1 + Select: external-only → internal-only → both → repeat
  • Replaces the broken screen_switch binding on the same hotkey
  • Sets a lock file before making any output changes so dp_monitor cannot react mid-transition
  • Uses sysfs connector status to distinguish a physical cable unplug from a software-disabled output, so the lock is only cleared when the cable is truly removed
  • Prevents concurrent invocations from racing if the hotkey is pressed rapidly

sway config (111-sway-init)

  • Assigns workspace 1 to prefer DP-1 with the internal display as fallback, so sway automatically migrates ES between outputs as they are enabled/disabled
  • Adds for_window [app_id="emulationstation"] move output DP-1 so ES opens on the external display when first connected

Test plan

  • Build RK3576 image: make docker-RK3576
  • Boot RG Vita Pro with DP cable pre-connected — ES should appear on external display, internal panel off
  • Hot-plug DP cable while on home screen — ES should move to external display, internal panel off
  • Unplug DP cable — internal panel re-enables, ES returns to device screen
  • Press L1 + Select while on external display → internal-only: device screen on, external dark, mako notification "Display: Internal Only"
  • Press L1 + Select again → both: both screens on, mako notification "Display: Both Screens"
  • Press L1 + Select again → external-only: device screen off, mako notification "Display: External Only"
  • Unplug cable while in any manual mode — dp_monitor resumes automatic control, internal screen re-enables
  • USB gadget stops when DP is active, does not restart until cable is unplugged
  • wlr-randr output reflects enabled/disabled state correctly after each cycle step

🤖 Generated with Claude Code

@pgratz1
Copy link
Copy Markdown
Contributor Author

pgratz1 commented May 9, 2026

Tested on ANBERNIC RG Vita Pro with VITURE Pro XR glasses (combined with #2676). Plugging in the glasses via USB-C automatically moves workspace 1 to the glasses and powers off the internal DSI-1 panel. Unplugging restores the internal display and EmulationStation restarts at the correct resolution.

@pgratz1
Copy link
Copy Markdown
Contributor Author

pgratz1 commented May 9, 2026

Updated based on reviewer feedback.

This revision makes dp_monitor output-agnostic and addresses the inotifyd suggestion.

What changed:

  • dp_monitor no longer hard-codes DP-1 or DSI-1. It now dynamically discovers external outputs (DP-*, HDMI-*, DisplayPort-*) and internal outputs (DSI-*, eDP-*, LVDS-*) via wlr-randr, making it applicable to any device with external display hardware.
  • exec dp_monitor is moved out of the DP-1-specific block in 111-sway-init into a separate hardware-presence check, so it starts whenever any DP or HDMI connector exists in sysfs — not just for the RG Vita Pro's DP-1 path.
  • The unnecessary killall emulationstation on output transitions has been removed. Sway's workspace output priority config (workspace 1 output DP-1 DSI-1) already moves the workspace to whichever output is available, and Wayland sends xdg-toplevel configure events so ES-DE resizes correctly without a restart.

Why inotifyd won't work here:

inotifyd (and Linux inotify generally) monitors VFS-level write operations on real files. Sysfs pseudo-files are populated in-memory by the kernel and do not go through the VFS write path when their content changes, so inotify events are never generated for /sys/class/drm/*/status. This codebase already documents this limitation — see the comment in powerstate.sh: "we can't use inotifyd to watch the status in /sys".

The correct approach for normal DRM hotplug events is a udev rule (as used by hdmi_sense), which listens to kernel netlink events. However, the RK3576 DP Alt Mode driver does not call drm_kms_helper_hotplug_event, so udev is never triggered. Sway discovers DP-1 through its own DRM polling, making sway IPC the only reliable notification mechanism on this hardware.

Audio note:

DP audio over the USB-C connection is not yet handled. The VITURE glasses expose only HID and CDC serial interfaces over USB — no USB Audio Class. DP audio would require adding ASoC DAI component registration to dw-dp.c (the driver currently only acquires i2s_clk/spdif_clk but never registers a sound component). That is a separate kernel driver effort and will be addressed in a follow-on PR.

@pgratz1 pgratz1 force-pushed the pr/rk3576-dp-userspace branch from d755366 to 6789c74 Compare May 9, 2026 20:25
@pgratz1 pgratz1 changed the title RK3576: Add dp_monitor for DP Alt Mode display switching RK3576: dp_monitor and sway config for DP Alt Mode display switching May 9, 2026
@pgratz1
Copy link
Copy Markdown
Contributor Author

pgratz1 commented May 10, 2026

Tested on ANBERNIC RG Vita Pro with VITURE Pro XR glasses:

  • Boot with glasses pre-connected: ES appears on glasses, internal panel off ✓
  • Hot-plug (unplug + replug at runtime): ES moves to glasses correctly ✓
  • Unplug: internal panel re-enables, ES returns to device screen ✓

@pgratz1 pgratz1 force-pushed the pr/rk3576-dp-userspace branch 2 times, most recently from fcd6a3b to 567e941 Compare May 10, 2026 01:59
@pgratz1 pgratz1 force-pushed the pr/rk3576-dp-userspace branch from 567e941 to d01957b Compare May 17, 2026 14:44
@xzn
Copy link
Copy Markdown
Contributor

xzn commented May 20, 2026

Any update on this? I'm looking to improve dual screen support when external monitors are hotplugged (no pr yet, just a plan so far), seems like this branch contains many helpful changes.

Specifically: 080-dual_screen_mode does its check once on startup, and Ayaneo Pocket DS for instance, will have three connected monitors on start if already plugged in to an external display, making DEVICE_HAS_DUAL_SCREEN false. I'm looking to make it more dynamic like your pr is trying to do.

Another example is start_steam.sh, it checks the currently focused display for --force-orientation, however that option does not affect external connectors for gamescope (which only considers eDP, LVDS, and DSI internal), so its probably okay to always check what the primary DSI connector's rotation is (and ignore the external one if focused).

wlr-randr 2>/dev/null | awk '/^(DSI|eDP|LVDS)-/ { print $1 }'
}

# Returns the PipeWire sink for DP audio (hdmi-audio-codec on 27e40000.dp).
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not very platform agnostic that 27e40000.dp ...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's fair, this weekend I'll have some more time to play with this and maybe make this a bit less RG Vita Pro specific....

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK so this particular code was part of a rabbit hole I went down trying to get audio working via the DP device. I actually never got it working so I'm rolling back that change. I'm testing the roll back but it should be clean since it was working before (TF if I know why I can't get the sound working on the glasses I have though... works great from my phone).

@pgratz1 pgratz1 force-pushed the pr/rk3576-dp-userspace branch 2 times, most recently from 8aec0c6 to a099c94 Compare May 24, 2026 18:14
@pgratz1
Copy link
Copy Markdown
Contributor Author

pgratz1 commented May 24, 2026

@xzn Still active, just got bogged down with work, just rebased on the current next head and removed the code Loki666 didn't like.

A few notes that might be useful for your dual-screen work:

On dp_monitor's approach: The core mechanism is a sway IPC subscription (swaymsg -t subscribe '["output"]'). Because sway has already processed the output change by the time the event fires, wlr-randr reliably reflects the current state without polling delays. The 10 s timeout loop is a fallback for boot-time hotplug where sway fires the event before it finishes configuring the output.

On 080-dual_screen_mode: You're right that the one-shot startup check is a limitation. Worth noting that dp_monitor as written specifically targets devices without DEVICE_HAS_DUAL_SCREEN=true (RK3576 DP Alt Mode via USB-C), so the dual-screen path in 111-sway-init is a separate code path that wouldn't be affected by this PR. For the Ayaneo Pocket DS case, a sway IPC subscribe loop similar to dp_monitor's that re-evaluates connector state on output events would probably solve the "three outputs at boot" problem cleanly.

On start_steam.sh: Your read of --force-orientation is correct — gamescope limits that flag to internal connectors (eDP, LVDS, DSI), so always deriving orientation from the primary DSI connector regardless of focus makes sense. That fix looks self-contained and could land independently of this PR.

@pgratz1
Copy link
Copy Markdown
Contributor Author

pgratz1 commented May 29, 2026

@loki666 Are you all happy with the approach I'm taking here or do you have any advice on how I should rework it? I'm thinking about doing a hotkey to switch output from device to DP to both in a round robin. I don't have any other devices so I don't have anything to compare against, so let me know what you think and what you'd like to see to get this merged.

@loki666
Copy link
Copy Markdown
Contributor

loki666 commented May 29, 2026

Changes looks ok... (need testing for regression)

Question : what's the issue currently? I thought we already had some mechanism to switch output to external display. (Or is currently only covering HDMI)
Can't this be merged with HDMI?

@pgratz1
Copy link
Copy Markdown
Contributor Author

pgratz1 commented May 29, 2026

So the main issue this is trying to solve is that with the current next head, while the kernel is recognizing that there is a DP inserted, and it is powering the display, Sway isn't putting ES on that screen (also doesn't work on insertion of HDMI). With this patch when you insert DP (or HDMI) it will move ES to the DP or HDMI and power down the local screen.

I'm thinking of augmenting this to allow round robin between DP/HDMI or device screen or both via hotkey combo (any suggestions which? Claude says L1+BNT_South is not used, maybe that?)

BTW, just saw that L1+BNT_BACK is supposed to do something like switch screens but on the vita pro it doesn't do anything in ES.

@pgratz1
Copy link
Copy Markdown
Contributor Author

pgratz1 commented May 29, 2026

Just did a little testing with the next head. With that if you boot with HDMI plugged in it does go there but inserting it after boot does not work w/o my patch. Booting with DP does not work on stock though. Brings up the display sideways on the device.

@loki666
Copy link
Copy Markdown
Contributor

loki666 commented May 29, 2026

Ok thanks. This is indeed something we'll probably want to pull.

We are currently in feature freeze for upcoming monthly release. But I guess next week we can merge this.

Could you force push this in one single commit.
It will allow us to easily revert if we have issues.

@pgratz1
Copy link
Copy Markdown
Contributor Author

pgratz1 commented May 29, 2026

OK sure, let me test my round robin thing and if that works I'll do it as a single commit.

Adds dp_monitor, a daemon that subscribes to sway IPC output events and
automatically powers the device's internal display off when a DP Alt Mode
display is connected, and back on when it disconnects.  Using sway IPC
rather than udev avoids the race condition where wlr-randr/swaymsg require
sway to have already processed the new output before they can act on it.

Wires dp_monitor into 111-sway-init so it launches automatically on any
sway device that has DP or HDMI hardware connectors.

Also adds dp_output_cycle, a script that manually cycles display output
mode (external-only → internal-only → both → repeat) on L1+Select,
replacing the broken screen_switch binding on the same hotkey.
dp_output_cycle coordinates with dp_monitor via a lock file so the two
never fight over output state.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@pgratz1 pgratz1 force-pushed the pr/rk3576-dp-userspace branch from a099c94 to efd9f9f Compare May 30, 2026 03:18
@pgratz1 pgratz1 changed the title RK3576: dp_monitor and sway config for DP Alt Mode display switching RK3576: DP Alt Mode display management (auto-switch + manual cycle) May 30, 2026
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.

3 participants