drm/arm/hdlcd: Reject atomic commits that disable only the plane
authorLiviu Dudau <Liviu.Dudau@arm.com>
Mon, 23 Jul 2018 11:05:53 +0000 (12:05 +0100)
committerLiviu Dudau <Liviu.Dudau@arm.com>
Tue, 31 Jul 2018 15:31:50 +0000 (16:31 +0100)
The HDLCD engine needs an active plane while the CRTC is active, as
it will start scanning out data from HDLCD_REG_FB_BASE once it gets
enabled. Make sure that the only available plane doesn't get disabled
while the CRTC remains active, as this will scanout invalid data.

Signed-off-by: Liviu Dudau <liviu.dudau@arm.com>
drivers/gpu/drm/arm/hdlcd_crtc.c
drivers/gpu/drm/arm/hdlcd_drv.c

index 8978d82159e5ca776db18a9f28edf39a36cb7d39..e4d67b70244d5716764a6afa1ef2ae991e2e51c6 100644 (file)
@@ -229,6 +229,8 @@ static const struct drm_crtc_helper_funcs hdlcd_crtc_helper_funcs = {
 static int hdlcd_plane_atomic_check(struct drm_plane *plane,
                                    struct drm_plane_state *state)
 {
+       int i;
+       struct drm_crtc *crtc;
        struct drm_crtc_state *crtc_state;
        u32 src_h = state->src_h >> 16;
 
@@ -238,20 +240,17 @@ static int hdlcd_plane_atomic_check(struct drm_plane *plane,
                return -EINVAL;
        }
 
-       if (!state->fb || !state->crtc)
-               return 0;
-
-       crtc_state = drm_atomic_get_existing_crtc_state(state->state,
-                                                       state->crtc);
-       if (!crtc_state) {
-               DRM_DEBUG_KMS("Invalid crtc state\n");
-               return -EINVAL;
+       for_each_new_crtc_in_state(state->state, crtc, crtc_state, i) {
+               /* we cannot disable the plane while the CRTC is active */
+               if (!state->fb && crtc_state->active)
+                       return -EINVAL;
+               return drm_atomic_helper_check_plane_state(state, crtc_state,
+                                               DRM_PLANE_HELPER_NO_SCALING,
+                                               DRM_PLANE_HELPER_NO_SCALING,
+                                               false, true);
        }
 
-       return drm_atomic_helper_check_plane_state(state, crtc_state,
-                                                  DRM_PLANE_HELPER_NO_SCALING,
-                                                  DRM_PLANE_HELPER_NO_SCALING,
-                                                  false, true);
+       return 0;
 }
 
 static void hdlcd_plane_atomic_update(struct drm_plane *plane,
index 70fca288313a8076b2b57446e33594445abe97e9..0ed1cde98cf8c8cdce08836e4c4b28bda3792761 100644 (file)
@@ -325,6 +325,7 @@ err_fbdev:
 err_vblank:
        pm_runtime_disable(drm->dev);
 err_pm_active:
+       drm_atomic_helper_shutdown(drm);
        component_unbind_all(dev, drm);
 err_unload:
        of_node_put(hdlcd->crtc.port);
@@ -350,16 +351,18 @@ static void hdlcd_drm_unbind(struct device *dev)
        component_unbind_all(dev, drm);
        of_node_put(hdlcd->crtc.port);
        hdlcd->crtc.port = NULL;
-       pm_runtime_get_sync(drm->dev);
+       pm_runtime_get_sync(dev);
+       drm_crtc_vblank_off(&hdlcd->crtc);
        drm_irq_uninstall(drm);
-       pm_runtime_put_sync(drm->dev);
-       pm_runtime_disable(drm->dev);
-       of_reserved_mem_device_release(drm->dev);
        drm_atomic_helper_shutdown(drm);
+       pm_runtime_put(dev);
+       if (pm_runtime_enabled(dev))
+               pm_runtime_disable(dev);
+       of_reserved_mem_device_release(dev);
        drm_mode_config_cleanup(drm);
-       drm_dev_put(drm);
        drm->dev_private = NULL;
        dev_set_drvdata(dev, NULL);
+       drm_dev_put(drm);
 }
 
 static const struct component_master_ops hdlcd_master_ops = {