Commit d664b851 authored by Liviu Dudau's avatar Liviu Dudau

drm/arm/hdlcd: Reject atomic commits that disable only the plane

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: default avatarLiviu Dudau <liviu.dudau@arm.com>
parent 9fd466f5
...@@ -229,6 +229,8 @@ static const struct drm_crtc_helper_funcs hdlcd_crtc_helper_funcs = { ...@@ -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, static int hdlcd_plane_atomic_check(struct drm_plane *plane,
struct drm_plane_state *state) struct drm_plane_state *state)
{ {
int i;
struct drm_crtc *crtc;
struct drm_crtc_state *crtc_state; struct drm_crtc_state *crtc_state;
u32 src_h = state->src_h >> 16; u32 src_h = state->src_h >> 16;
...@@ -238,20 +240,17 @@ static int hdlcd_plane_atomic_check(struct drm_plane *plane, ...@@ -238,20 +240,17 @@ static int hdlcd_plane_atomic_check(struct drm_plane *plane,
return -EINVAL; return -EINVAL;
} }
if (!state->fb || !state->crtc) for_each_new_crtc_in_state(state->state, crtc, crtc_state, i) {
return 0; /* we cannot disable the plane while the CRTC is active */
if (!state->fb && crtc_state->active)
crtc_state = drm_atomic_get_existing_crtc_state(state->state, return -EINVAL;
state->crtc); return drm_atomic_helper_check_plane_state(state, crtc_state,
if (!crtc_state) { DRM_PLANE_HELPER_NO_SCALING,
DRM_DEBUG_KMS("Invalid crtc state\n"); DRM_PLANE_HELPER_NO_SCALING,
return -EINVAL; false, true);
} }
return drm_atomic_helper_check_plane_state(state, crtc_state, return 0;
DRM_PLANE_HELPER_NO_SCALING,
DRM_PLANE_HELPER_NO_SCALING,
false, true);
} }
static void hdlcd_plane_atomic_update(struct drm_plane *plane, static void hdlcd_plane_atomic_update(struct drm_plane *plane,
......
...@@ -325,6 +325,7 @@ static int hdlcd_drm_bind(struct device *dev) ...@@ -325,6 +325,7 @@ static int hdlcd_drm_bind(struct device *dev)
err_vblank: err_vblank:
pm_runtime_disable(drm->dev); pm_runtime_disable(drm->dev);
err_pm_active: err_pm_active:
drm_atomic_helper_shutdown(drm);
component_unbind_all(dev, drm); component_unbind_all(dev, drm);
err_unload: err_unload:
of_node_put(hdlcd->crtc.port); of_node_put(hdlcd->crtc.port);
...@@ -350,16 +351,18 @@ static void hdlcd_drm_unbind(struct device *dev) ...@@ -350,16 +351,18 @@ static void hdlcd_drm_unbind(struct device *dev)
component_unbind_all(dev, drm); component_unbind_all(dev, drm);
of_node_put(hdlcd->crtc.port); of_node_put(hdlcd->crtc.port);
hdlcd->crtc.port = NULL; 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); 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); 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_mode_config_cleanup(drm);
drm_dev_put(drm);
drm->dev_private = NULL; drm->dev_private = NULL;
dev_set_drvdata(dev, NULL); dev_set_drvdata(dev, NULL);
drm_dev_put(drm);
} }
static const struct component_master_ops hdlcd_master_ops = { static const struct component_master_ops hdlcd_master_ops = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment