The Video Output Processor (VOP) is RK3399’s display controller. It fetches framebuffers, composes planes, and drives the display interfaces (MIPI DSI, eDP, HDMI). RK3399 has two: VOP-Big and VOP-Lit. The PinePhone Pro panel is on VOP-Lit at 720×1440 @ 60 Hz.
Today the VOP is the primary open issue on the display path. First
modeset is fine, day-to-day Sway works, but Hyprland output reconfig
or sustained GPU load takes the modeset chain into a wedge that
sometimes panics with [CRTC:33:crtc-0] flip_done timed out.
Identity
| Property | Value |
|---|---|
| Block | RK3399 VOP-Lit |
| MMIO base | 0xff8f0000 |
| Resolution | 720×1440 @ 60 Hz on the PPP panel |
| Output | MIPI DSI → DW-MIPI-DSI bridge → HX8394 panel |
| DTS compatible | rockchip,rk3399-vop-lit |
| Linux driver | drivers/gpu/drm/rockchip/rockchip_drm_vop.c |
Driver
◐ partial Local fork of the Rockchip VOP driver under the DRM subtree.
src/sys/dev/drm/rockchip/rk_vop.c— 734 lines. CRTC + atomic-modeset glue.src/sys/dev/drm/rockchip/rk_plane.c— primary / overlay plane registration.src/sys/dev/drm/rockchip/rk_drm.c— drmcard glue; provides our customcommit_tail.
The driver has been heavily worked: full MIPI DSI bring-up
( 3462965 MIPI DSI pipeline: full driver stack, VOP outputting frames ), event-handling iterations
( c11b579 vop: fix atomic commit completion — move event to atomic_flush only , 98406a4 vop: revert atomic_begin change — keep event handling in both begin and flush ,
07aca7b vop: fix event race — handle page flip event only in atomic_flush , 736d191 vop: send commit event immediately instead of arming for vblank ), the panfrost-reset
deadlock workaround that dropped wait_for_vblanks
( 604bd8f rk_drm: skip wait_for_vblanks in commit_tail to prevent GPU reset deadlock ), then a TODO panic in
rk_vop_plane_atomic_update and a NULL deref in rk_plane
( bc6b664 drm: fix rk_plane panic that triggered DRM atomic_helper NULL deref , 1009996 rk_plane: don't gate the window off on transient invisible state ).
Open issues
The cross-driver audit identified three structurally suspect items in the modeset path that match the wedge symptoms exactly. Two code-side fixes are now in the local overlay; the driver-side event latch is still open.
drm_atomic_helper_wait_for_vblanksremoved from our customrk_drm_atomic_commit_tail. Without it,cleanup_planesruns in the same commit ascommit_hw_done, leaving the next commit’sflip_donewaiter unfulfilled. The original deadlock that motivated the removal predates the panfrost reset rework (3378d3dQueue Panfrost reset before scheduler stop ,cf2dd90Fix Panfrost reset fence signaling context ); the workaround is now over-eager.- Shared-IRQ ack wrote
~0atrk_vop.c:280, clobbering any in-flightFS_INTRthat arrived between the status read and the clear write.a830a08rk_vop: restore atomic vblank wait changed the ack toINTR_CLEAR0 = status. - Double-event drain between
rk_crtc_atomic_beginandrk_crtc_atomic_flush, plus avblank_getwithout a balancingvblank_put. The current overlay still does not hold the event on a driver-side latch between flush and theFS_INTRvblank IRQ.
The GPU under load essay tracks the wedge. The fix path is laid out in the audit’s “rk_vop / Recommendations (priority order)” section.
Status
| Question | Answer |
|---|---|
| Probes? | Yes |
| First modeset? | Yes — Sway and Hyprland come up |
| Sustained load? | Wedge — modeset-lock + flip_done timeout. Re-confirmed on #145 (2026-05-04) via kldunload bwfm_sdio && kldload bwfm_sdio; not Hyprland-specific. |
| Output reconfig? | Same wedge as above; any DRM-adjacent code path yanked while pages in flight reproduces it. |
Parity verification
Two audit fixes now have code in the overlay. Verification plan:
- IRQ ack (
rk_vop.c::rk_vop_intr,INTR_CLEAR0 = statusinstead of~0): after build + boot,dmesgunder idle should be free of newUnhandled intrlines. Linux reference:drivers/gpu/drm/rockchip/rockchip_drm_vop.c::vop_isruseswritel(active_irqs, vop->regs + INTR_CLEAR);— the same ack-only-what-fired pattern. - wait_for_vblanks restored (
rk_drm.c::rk_drm_atomic_commit_tail): runscripts/wedge-repro(per essay 08). Pre-fix it wedges in under 5 minutes with[CRTC:33:crtc-0] flip_done timed out; post-fix it should sustain a 15-minute soak without that line. - Driver-side event latch (
rk_vop.c::rk_crtc_atomic_flushandrk_vop_intr):dev.rk_vop.0.vop_event_latched_totalshould advance during page flips,dev.rk_vop.0.fs_intr_totalshould advance every frame, anddev.rk_vop.0.vblank_refs_outstandingshould settle back to 0 after the compositor stops repainting. This instrumentation is not in tree yet. - Falsifier: if
wedge-reprostill wedges after the full three-item set, capture the new sysctls plus the WARN_ON backtrace and split the next investigation between “event never latched”, “FS_INTR stopped”, and “atomic commit waited on a non-VOP fence.”
Related
- Essay 08: GPU under load — open WarStory tracking the wedge.
- Cross-driver audit (2026-04-30) — rk_vop — three-item fix list.
- GPU debugging — capture and bisect recipes.
- Hardware reference — VOP row in Display and GPU.