Merge remote-tracking branch 'drm/drm-next' into drm-misc-next
[sfrench/cifs-2.6.git] / drivers / gpu / drm / rockchip / rockchip_drm_vop.c
index 2a5e2c67b02a240ea581bc2552f750dff96ab05b..09a790c2f3a1ead32cd7360b645eca62a1d2f1a0 100644 (file)
@@ -1,15 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
  * Author:Mark Yao <mark.yao@rock-chips.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
  */
 
 #include <drm/drm.h>
@@ -919,29 +911,17 @@ static void vop_plane_atomic_async_update(struct drm_plane *plane,
                                          struct drm_plane_state *new_state)
 {
        struct vop *vop = to_vop(plane->state->crtc);
-       struct drm_plane_state *plane_state;
-
-       plane_state = plane->funcs->atomic_duplicate_state(plane);
-       plane_state->crtc_x = new_state->crtc_x;
-       plane_state->crtc_y = new_state->crtc_y;
-       plane_state->crtc_h = new_state->crtc_h;
-       plane_state->crtc_w = new_state->crtc_w;
-       plane_state->src_x = new_state->src_x;
-       plane_state->src_y = new_state->src_y;
-       plane_state->src_h = new_state->src_h;
-       plane_state->src_w = new_state->src_w;
-
-       if (plane_state->fb != new_state->fb)
-               drm_atomic_set_fb_for_plane(plane_state, new_state->fb);
-
-       swap(plane_state, plane->state);
-
-       if (plane->state->fb && plane->state->fb != new_state->fb) {
-               drm_framebuffer_get(plane->state->fb);
-               WARN_ON(drm_crtc_vblank_get(plane->state->crtc) != 0);
-               drm_flip_work_queue(&vop->fb_unref_work, plane->state->fb);
-               set_bit(VOP_PENDING_FB_UNREF, &vop->pending);
-       }
+       struct drm_framebuffer *old_fb = plane->state->fb;
+
+       plane->state->crtc_x = new_state->crtc_x;
+       plane->state->crtc_y = new_state->crtc_y;
+       plane->state->crtc_h = new_state->crtc_h;
+       plane->state->crtc_w = new_state->crtc_w;
+       plane->state->src_x = new_state->src_x;
+       plane->state->src_y = new_state->src_y;
+       plane->state->src_h = new_state->src_h;
+       plane->state->src_w = new_state->src_w;
+       swap(plane->state->fb, new_state->fb);
 
        if (vop->is_enabled) {
                rockchip_drm_psr_inhibit_get_state(new_state->state);
@@ -950,9 +930,22 @@ static void vop_plane_atomic_async_update(struct drm_plane *plane,
                vop_cfg_done(vop);
                spin_unlock(&vop->reg_lock);
                rockchip_drm_psr_inhibit_put_state(new_state->state);
-       }
 
-       plane->funcs->atomic_destroy_state(plane, plane_state);
+               /*
+                * A scanout can still be occurring, so we can't drop the
+                * reference to the old framebuffer. To solve this we get a
+                * reference to old_fb and set a worker to release it later.
+                * FIXME: if we perform 500 async_update calls before the
+                * vblank, then we can have 500 different framebuffers waiting
+                * to be released.
+                */
+               if (old_fb && plane->state->fb != old_fb) {
+                       drm_framebuffer_get(old_fb);
+                       WARN_ON(drm_crtc_vblank_get(plane->state->crtc) != 0);
+                       drm_flip_work_queue(&vop->fb_unref_work, old_fb);
+                       set_bit(VOP_PENDING_FB_UNREF, &vop->pending);
+               }
+       }
 }
 
 static const struct drm_plane_helper_funcs plane_helper_funcs = {