mutex_unlock(&vop2->vop2_lock);
 }
 
-/*
- * Note:
- * The write mask function is documented but missing on rk3566/8, writes
- * to these bits have no effect. For newer soc(rk3588 and following) the
- * write mask is needed for register writes.
- *
- * GLB_CFG_DONE_EN has no write mask bit.
- *
- */
-static void vop2_cfg_done(struct vop2_video_port *vp)
-{
-       struct vop2 *vop2 = vp->vop2;
-       u32 val = RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN;
-
-       val |= BIT(vp->id) | (BIT(vp->id) << 16);
-
-       regmap_set_bits(vop2->map, RK3568_REG_CFG_DONE, val);
-}
-
 static void vop2_win_disable(struct vop2_win *win)
 {
        vop2_win_write(win, VOP2_WIN_ENABLE, 0);
        if (vop2->version == VOP_VERSION_RK3588)
                rk3588_vop2_power_domain_enable_all(vop2);
 
+       if (vop2->version <= VOP_VERSION_RK3588) {
+               vop2->old_layer_sel = vop2_readl(vop2, RK3568_OVL_LAYER_SEL);
+               vop2->old_port_sel = vop2_readl(vop2, RK3568_OVL_PORT_SEL);
+       }
+
        vop2_writel(vop2, RK3568_REG_CFG_DONE, RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN);
 
        /*
                return dev_err_probe(drm->dev, vop2->irq, "cannot find irq for vop2\n");
 
        mutex_init(&vop2->vop2_lock);
+       mutex_init(&vop2->ovl_lock);
 
        ret = devm_request_irq(dev, vop2->irq, vop2_isr, IRQF_SHARED, dev_name(dev), vop2);
        if (ret)
 
        /* optional internal rgb encoder */
        struct rockchip_rgb *rgb;
 
+       /*
+        * Used to record layer selection configuration on rk356x/rk3588
+        * as register RK3568_OVL_LAYER_SEL and RK3568_OVL_PORT_SEL are
+        * shared for all the Video Ports.
+        */
+       u32 old_layer_sel;
+       u32 old_port_sel;
+       /*
+        * Ensure that the updates to these two registers(RKK3568_OVL_LAYER_SEL/RK3568_OVL_PORT_SEL)
+        * take effect in sequence.
+        */
+       struct mutex ovl_lock;
+
        /* must be put at the end of the struct */
        struct vop2_win win[];
 };
 #define RK3588_OVL_PORT_SEL__CLUSTER2                  GENMASK(21, 20)
 #define RK3568_OVL_PORT_SEL__CLUSTER1                  GENMASK(19, 18)
 #define RK3568_OVL_PORT_SEL__CLUSTER0                  GENMASK(17, 16)
+#define RK3588_OVL_PORT_SET__PORT3_MUX                 GENMASK(15, 12)
 #define RK3568_OVL_PORT_SET__PORT2_MUX                 GENMASK(11, 8)
 #define RK3568_OVL_PORT_SET__PORT1_MUX                 GENMASK(7, 4)
 #define RK3568_OVL_PORT_SET__PORT0_MUX                 GENMASK(3, 0)
        return container_of(p, struct vop2_win, base);
 }
 
+/*
+ * Note:
+ * The write mask function is documented but missing on rk3566/8, writes
+ * to these bits have no effect. For newer soc(rk3588 and following) the
+ * write mask is needed for register writes.
+ *
+ * GLB_CFG_DONE_EN has no write mask bit.
+ *
+ */
+static inline void vop2_cfg_done(struct vop2_video_port *vp)
+{
+       struct vop2 *vop2 = vp->vop2;
+       u32 val = RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN;
+
+       val |= BIT(vp->id) | (BIT(vp->id) << 16);
+
+       regmap_set_bits(vop2->map, RK3568_REG_CFG_DONE, val);
+}
+
 #endif /* _ROCKCHIP_DRM_VOP2_H */
 
        }
 }
 
+static u32 rk3568_vop2_read_port_mux(struct vop2 *vop2)
+{
+       return vop2_readl(vop2, RK3568_OVL_PORT_SEL);
+}
+
+static void rk3568_vop2_wait_for_port_mux_done(struct vop2 *vop2)
+{
+       u32 port_mux_sel;
+       int ret;
+
+       /*
+        * Spin until the previous port_mux figuration is done.
+        */
+       ret = readx_poll_timeout_atomic(rk3568_vop2_read_port_mux, vop2, port_mux_sel,
+                                       port_mux_sel == vop2->old_port_sel, 0, 50 * 1000);
+       if (ret)
+               DRM_DEV_ERROR(vop2->dev, "wait port_mux done timeout: 0x%x--0x%x\n",
+                             port_mux_sel, vop2->old_port_sel);
+}
+
+static u32 rk3568_vop2_read_layer_cfg(struct vop2 *vop2)
+{
+       return vop2_readl(vop2, RK3568_OVL_LAYER_SEL);
+}
+
+static void rk3568_vop2_wait_for_layer_cfg_done(struct vop2 *vop2, u32 cfg)
+{
+       u32 atv_layer_cfg;
+       int ret;
+
+       /*
+        * Spin until the previous layer configuration is done.
+        */
+       ret = readx_poll_timeout_atomic(rk3568_vop2_read_layer_cfg, vop2, atv_layer_cfg,
+                                       atv_layer_cfg == cfg, 0, 50 * 1000);
+       if (ret)
+               DRM_DEV_ERROR(vop2->dev, "wait layer cfg done timeout: 0x%x--0x%x\n",
+                             atv_layer_cfg, cfg);
+}
+
 static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp)
 {
        struct vop2 *vop2 = vp->vop2;
        struct drm_plane *plane;
        u32 layer_sel = 0;
        u32 port_sel;
+       u32 old_layer_sel = 0;
+       u32 atv_layer_sel = 0;
+       u32 old_port_sel = 0;
        u8 layer_id;
        u8 old_layer_id;
        u8 layer_sel_id;
        struct vop2_video_port *vp2 = &vop2->vps[2];
        struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(vp->crtc.state);
 
+       mutex_lock(&vop2->ovl_lock);
        ovl_ctrl = vop2_readl(vop2, RK3568_OVL_CTRL);
        ovl_ctrl &= ~RK3568_OVL_CTRL__LAYERSEL_REGDONE_IMD;
        ovl_ctrl &= ~RK3568_OVL_CTRL__LAYERSEL_REGDONE_SEL;
-       ovl_ctrl |= FIELD_PREP(RK3568_OVL_CTRL__LAYERSEL_REGDONE_SEL, vp->id);
 
        if (vcstate->yuv_overlay)
                ovl_ctrl |= RK3568_OVL_CTRL__YUV_MODE(vp->id);
        else
                ovl_ctrl &= ~RK3568_OVL_CTRL__YUV_MODE(vp->id);
 
-       vop2_writel(vop2, RK3568_OVL_CTRL, ovl_ctrl);
-
-       port_sel = vop2_readl(vop2, RK3568_OVL_PORT_SEL);
+       old_port_sel = vop2->old_port_sel;
+       port_sel = old_port_sel;
        port_sel &= RK3568_OVL_PORT_SEL__SEL_PORT;
 
        if (vp0->nlayers)
        else
                port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT2_MUX, 8);
 
-       layer_sel = vop2_readl(vop2, RK3568_OVL_LAYER_SEL);
+       /* Fixed value for rk3588 */
+       if (vop2->version == VOP_VERSION_RK3588)
+               port_sel |= FIELD_PREP(RK3588_OVL_PORT_SET__PORT3_MUX, 7);
+
+       atv_layer_sel = vop2_readl(vop2, RK3568_OVL_LAYER_SEL);
+       old_layer_sel = vop2->old_layer_sel;
+       layer_sel = old_layer_sel;
 
        ofs = 0;
        for (i = 0; i < vp->id; i++)
                             old_win->data->layer_sel_id[vp->id]);
        }
 
+       vop2->old_layer_sel = layer_sel;
+       vop2->old_port_sel = port_sel;
+       /*
+        * As the RK3568_OVL_LAYER_SEL and RK3568_OVL_PORT_SEL are shared by all Video Ports,
+        * and the configuration take effect by one Video Port's vsync.
+        * When performing layer migration or change the zpos of layers, there are two things
+        * to be observed and followed:
+        * 1. When a layer is migrated from one VP to another, the configuration of the layer
+        *    can only take effect after the Port mux configuration is enabled.
+        *
+        * 2. When we change the zpos of layers, we must ensure that the change for the previous
+        *    VP takes effect before we proceed to change the next VP. Otherwise, the new
+        *    configuration might overwrite the previous one for the previous VP, or it could
+        *    lead to the configuration of the previous VP being take effect along with the VSYNC
+        *    of the new VP.
+        */
+       if (layer_sel != old_layer_sel || port_sel != old_port_sel)
+               ovl_ctrl |= FIELD_PREP(RK3568_OVL_CTRL__LAYERSEL_REGDONE_SEL, vp->id);
+       vop2_writel(vop2, RK3568_OVL_CTRL, ovl_ctrl);
+
+       if (port_sel != old_port_sel) {
+               vop2_writel(vop2, RK3568_OVL_PORT_SEL, port_sel);
+               vop2_cfg_done(vp);
+               rk3568_vop2_wait_for_port_mux_done(vop2);
+       }
+
+       if (layer_sel != old_layer_sel && atv_layer_sel != old_layer_sel)
+               rk3568_vop2_wait_for_layer_cfg_done(vop2, vop2->old_layer_sel);
+
        vop2_writel(vop2, RK3568_OVL_LAYER_SEL, layer_sel);
-       vop2_writel(vop2, RK3568_OVL_PORT_SEL, port_sel);
+       mutex_unlock(&vop2->ovl_lock);
 }
 
 static void rk3568_vop2_setup_dly_for_windows(struct vop2_video_port *vp)