]> Gentwo Git Trees - linux/.git/commitdiff
drm/rockchip: vop2: Use OVL_LAYER_SEL configuration instead of use win_mask calculate...
authorAndy Yan <andy.yan@rock-chips.com>
Wed, 12 Nov 2025 08:50:23 +0000 (16:50 +0800)
committerHeiko Stuebner <heiko@sntech.de>
Fri, 14 Nov 2025 23:36:09 +0000 (00:36 +0100)
When there are multiple Video Ports, and only one of them is working
(for example, VP1 is working while VP0 is not), in this case, the
win_mask of VP0 is 0. However, we have already set the port mux for VP0
according to vp0->nlayers, and at the same time, in the OVL_LAYER_SEL
register, there are windows will also be assigned to layers which will
map to the inactive VPs. In this situation, vp0->win_mask is zero as it
now working, it is more reliable to calculate the used layers based on
the configuration of the OVL_LAYER_SEL register.

Note: as the configuration of OVL_LAYER_SEL is take effect when the
vsync is come, so we use the value backup in vop2->old_layer_sel instead
of read OVL_LAYER_SEL directly.

Fixes: 3e89a8c68354 ("drm/rockchip: vop2: Fix the update of LAYER/PORT select registers when there are multi display output on rk3588/rk3568")
Cc: stable@vger.kernel.org
Reported-by: Diederik de Haas <diederik@cknow-tech.com>
Closes: https://bugs.kde.org/show_bug.cgi?id=511274
Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
Tested-by: Dang Huynh <dang.huynh@mainlining.org>
Tested-by: Diederik de Haas <diederik@cknow-tech.com>
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Link: https://lore.kernel.org/r/20251112085024.2480111-1-andyshrk@163.com
drivers/gpu/drm/rockchip/rockchip_vop2_reg.c

index 38c49030c7ab6416c4af6b5c7be7b241e3c9db18..cd8380f0eddc849e50c292f4beed32d6e702b783 100644 (file)
@@ -1369,6 +1369,25 @@ static const struct vop2_regs_dump rk3588_regs_dump[] = {
        },
 };
 
+/*
+ * phys_id is used to identify a main window(Cluster Win/Smart Win, not
+ * include the sub win of a cluster or the multi area) that can do overlay
+ * in main overlay stage.
+ */
+static struct vop2_win *vop2_find_win_by_phys_id(struct vop2 *vop2, uint8_t phys_id)
+{
+       struct vop2_win *win;
+       int i;
+
+       for (i = 0; i < vop2->data->win_size; i++) {
+               win = &vop2->win[i];
+               if (win->data->phys_id == phys_id)
+                       return win;
+       }
+
+       return NULL;
+}
+
 static unsigned long rk3568_set_intf_mux(struct vop2_video_port *vp, int id, u32 polflags)
 {
        struct vop2 *vop2 = vp->vop2;
@@ -1842,15 +1861,31 @@ static void vop2_parse_alpha(struct vop2_alpha_config *alpha_config,
        alpha->dst_alpha_ctrl.bits.factor_mode = ALPHA_SRC_INVERSE;
 }
 
-static int vop2_find_start_mixer_id_for_vp(struct vop2 *vop2, u8 port_id)
+static int vop2_find_start_mixer_id_for_vp(struct vop2_video_port *vp)
 {
-       struct vop2_video_port *vp;
-       int used_layer = 0;
+       struct vop2 *vop2 = vp->vop2;
+       struct vop2_win *win;
+       u32 layer_sel = vop2->old_layer_sel;
+       u32 used_layer = 0;
+       unsigned long win_mask = vp->win_mask;
+       unsigned long phys_id;
+       bool match;
        int i;
 
-       for (i = 0; i < port_id; i++) {
-               vp = &vop2->vps[i];
-               used_layer += hweight32(vp->win_mask);
+       for (i = 0; i < 31; i += 4) {
+               match = false;
+               for_each_set_bit(phys_id, &win_mask, ROCKCHIP_VOP2_ESMART3) {
+                       win = vop2_find_win_by_phys_id(vop2, phys_id);
+                       if (win->data->layer_sel_id[vp->id] == ((layer_sel >> i) & 0xf)) {
+                               match = true;
+                               break;
+                       }
+               }
+
+               if (!match)
+                       used_layer += 1;
+               else
+                       break;
        }
 
        return used_layer;
@@ -1935,7 +1970,7 @@ static void vop2_setup_alpha(struct vop2_video_port *vp)
        u32 dst_global_alpha = DRM_BLEND_ALPHA_OPAQUE;
 
        if (vop2->version <= VOP_VERSION_RK3588)
-               mixer_id = vop2_find_start_mixer_id_for_vp(vop2, vp->id);
+               mixer_id = vop2_find_start_mixer_id_for_vp(vp);
        else
                mixer_id = 0;