RK3576 video output
This page describes the display pipeline of the Rockchip RK3576 SoC used in Flipper One:
- Video Output Processor (VOP)
- Video Ports (VP0, VP1, VP2)
- Display interfaces each port can drive
- How to reroute an interface to a different port at the device-tree level
RK3576 has a single VOP IP instance: compatible = "rockchip,rk3576-vop", handled by the mainline vop2 driver. (Although earlier Rockchip reference and some issue titles refer to VOP1 / VOP2 as separate blocks.) "VOP2" is the driver family, not a second controller. The three independent display pipelines are Video Ports, not separate VOPs.
Architecture overview
The VOP is one hardware block at 0x27d00000. It composes several overlay windows into up to three independent display streams, one per Video Port. Each Video Port has its own pixel clock (DCLK_VP0/1/2) and its own interrupt, and is steered to a physical display interface (HDMI, eDP, MIPI DSI, DisplayPort) through an interface multiplexer.
flowchart LR
subgraph VOP["VOP (rk3576-vop)"]
direction TB
subgraph WINS["Overlay windows"]
direction TB
C0["Cluster0 ยท 4K"]
C1["Cluster1 ยท 4K"]
E0["Esmart0 ยท 4K"]
E1["Esmart1 ยท 4K"]
E2["Esmart2 ยท 2K"]
E3["Esmart3 ยท 2K"]
end
SEL{{"Layer-select<br/>(window โ port)"}}
VP0["VP0 ยท 4K"]
VP1["VP1 ยท 2.5K"]
VP2["VP2 ยท 1080p"]
C0 --> SEL
C1 --> SEL
E0 --> SEL
E1 --> SEL
E2 --> SEL
E3 --> SEL
SEL --> VP0
SEL --> VP1
SEL --> VP2
end
VP0 --> MUX{{"Interface<br/>mux"}}
VP1 --> MUX
VP2 --> MUX
MUX --> HDMI["HDMI0"]
MUX --> EDP["eDP0"]
MUX --> DSI["MIPI DSI0"]
MUX --> DP0["DP0"]
MUX --> DP1["DP1"]
MUX --> DP2["DP2"]Video ports
Each Video Port is a fixed display controller with its own maximum timing. Windows are assigned to a port by the overlay layer-select logic; the port is then connected to exactly one active interface at a time.
Video Port | Max resolution | Max refresh | Can drive |
|---|---|---|---|
VP0 | 4096x2160 | 120 Hz | HDMI0, eDP0, MIPI DSI0, DP0 |
VP1 | 2560x1600 | 60 Hz | HDMI0, eDP0, MIPI DSI0, DP0, DP1 |
VP2 | 1920x1080 | 60 Hz | HDMI0, MIPI DSI0, DP1, DP2 |
4K@120 on VP0 is reachable over HDMI 2.1 or DisplayPort; eDP0 cannot drive it.
The interface a port drives is selected in hardware by the RK3576_DSP_IF_MUX field inside the per-interface RK3576_DSP_IF_CTRL registers (HDMI0 at 0x184, eDP0 at 0x188, DP0 at 0x18C, DP1 at 0x1A4). The mux field holds the VP ID, so each interface is pointed at the port that should feed it. The mainline driver programs these from the device-tree routing described below โ you do not write them by hand.
Routing interfaces to ports (device tree)
In mainline rk3576.dtsi the VOP vp0/vp1/vp2 ports are declared empty โ unlike rk3588, no *_in_vpN endpoints are pre-defined. A routing is a pair of of_graph endpoints you add in the board DTS: one in the interface's *_in port pointing at the VP, and the matching one in &vpN pointing back. (BSP kernels ship pre-baked &hdmi_in_vp0 { status = "okay"; } endpoints; that pattern does not exist in mainline.)
Example Usage
Three-screen routing, one interface per port:
&hdmi { status = "okay"; };
&dsi { status = "okay"; };
&dp { status = "okay"; };
&hdmi_in {
hdmi_in_vp0: endpoint { remote-endpoint = <&vp0_out_hdmi>; };
};
&dp0_in {
dp0_in_vp1: endpoint { remote-endpoint = <&vp1_out_dp0>; };
};
&dsi_in {
dsi_in_vp2: endpoint { remote-endpoint = <&vp2_out_dsi>; };
};
&vp0 {
vp0_out_hdmi: endpoint@0 { reg = <0>; remote-endpoint = <&hdmi_in_vp0>; };
};
&vp1 {
vp1_out_dp0: endpoint@0 { reg = <0>; remote-endpoint = <&dp0_in_vp1>; };
};
&vp2 {
vp2_out_dsi: endpoint@0 { reg = <0>; remote-endpoint = <&dsi_in_vp2>; };
};This drives three independent screens at once (same or different content), each capped by its port's maximum timing.
Note: Mainline rarely enables MIPI DSI and usually drives DisplayPort on VP1.
Rerouting an interface to a different port
To move an interface, repoint both ends of its endpoint pair at the new VP. Example โ DisplayPort defaults to VP2 (capped at 1920x1080@60); moving it to VP0 unlocks 4K@120:
/* was: dp0 -> vp2 */
&dp0_in {
dp0_in_vp0: endpoint { remote-endpoint = <&vp0_out_dp0>; };
};
&vp0 {
vp0_out_dp0: endpoint@0 { reg = <0>; remote-endpoint = <&dp0_in_vp0>; };
};Pick a target port that the interface is allowed to drive (see the Video Ports table๏ปฟ) and that is not already bound to another active interface. When a VP feeds more than one interface across the tree, give each &vpN endpoint a distinct reg/endpoint@N.
A port can feed only one active interface at a time, and an interface must be routed to a port it actually supports. Enabling two *_in_vpN endpoints for the same interface, or routing to an unsupported port, can produce no/unstable output.
References
RK3576-specific
- Bit-Brick SSOM-3576 HDMI driver docs โ HDMI-to-VP binding from a board-vendor perspective.
- Rockchip RK3576 Quick Datasheet โ high level overview of RK3576 capabilities, which does mention video capabilities.
Code and driver info
- rk3576.dtsi โ mainline VOP node, video-port port@0/1/2 definitions, clocks, and interrupts (see lines dsi: 1430, hdmi: 1458, dp:1499).
- drm/rockchip: vop2: Add support for rk3576 โ VP-to-interface routing, RK3576_DSP_IF_CTRL mux.
- drm/rockchip: vop2: Add support for rk3576 โ v15 thread โ mailing-list review thread for the mainline VOP2 RK3576 patch series.
- Deepwiki - friendlyarm/kernel-rockchip VOP section โ general Rockchip VOP architecture overview.
Related methods on other boards
- Firefly ROC-RK3576-PC display usage โ device-tree *_in_vpN routing and rerouting examples.
- Firefly AIO-3576C display usage โ second board's display guide, confirms per-port routing behavior.