From 5c7e5a22c126e4d7839e6bdcc05b3c4dfa945a72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 8 Dec 2017 20:37:34 +0100 Subject: [PATCH 1/5] drm/arm/hdlcd: Use drm_mode_config_helper_suspend/resume() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace driver's code with the generic helpers that do the same thing including the NULL check. Cc: Liviu Dudau Cc: Brian Starkey Signed-off-by: Noralf Trønnes Signed-off-by: Liviu Dudau --- drivers/gpu/drm/arm/hdlcd_drv.c | 25 +++---------------------- drivers/gpu/drm/arm/hdlcd_drv.h | 1 - 2 files changed, 3 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/arm/hdlcd_drv.c b/drivers/gpu/drm/arm/hdlcd_drv.c index feaa8bc3d7b7..9800a9e388ef 100644 --- a/drivers/gpu/drm/arm/hdlcd_drv.c +++ b/drivers/gpu/drm/arm/hdlcd_drv.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include "hdlcd_drv.h" @@ -427,35 +428,15 @@ MODULE_DEVICE_TABLE(of, hdlcd_of_match); static int __maybe_unused hdlcd_pm_suspend(struct device *dev) { struct drm_device *drm = dev_get_drvdata(dev); - struct hdlcd_drm_private *hdlcd = drm ? drm->dev_private : NULL; - if (!hdlcd) - return 0; - - drm_kms_helper_poll_disable(drm); - drm_fbdev_cma_set_suspend_unlocked(hdlcd->fbdev, 1); - - hdlcd->state = drm_atomic_helper_suspend(drm); - if (IS_ERR(hdlcd->state)) { - drm_fbdev_cma_set_suspend_unlocked(hdlcd->fbdev, 0); - drm_kms_helper_poll_enable(drm); - return PTR_ERR(hdlcd->state); - } - - return 0; + return drm_mode_config_helper_suspend(drm); } static int __maybe_unused hdlcd_pm_resume(struct device *dev) { struct drm_device *drm = dev_get_drvdata(dev); - struct hdlcd_drm_private *hdlcd = drm ? drm->dev_private : NULL; - if (!hdlcd) - return 0; - - drm_atomic_helper_resume(drm, hdlcd->state); - drm_fbdev_cma_set_suspend_unlocked(hdlcd->fbdev, 0); - drm_kms_helper_poll_enable(drm); + drm_mode_config_helper_resume(drm); return 0; } diff --git a/drivers/gpu/drm/arm/hdlcd_drv.h b/drivers/gpu/drm/arm/hdlcd_drv.h index 56f34dfff640..58d75d7e1b20 100644 --- a/drivers/gpu/drm/arm/hdlcd_drv.h +++ b/drivers/gpu/drm/arm/hdlcd_drv.h @@ -12,7 +12,6 @@ struct hdlcd_drm_private { struct drm_fbdev_cma *fbdev; struct drm_crtc crtc; struct drm_plane *plane; - struct drm_atomic_state *state; #ifdef CONFIG_DEBUG_FS atomic_t buffer_underrun_count; atomic_t bus_error_count; From 1785dbc412c257879274e8807afd6dfdfe06c47b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 8 Dec 2017 20:37:35 +0100 Subject: [PATCH 2/5] drm/arm/hdlcd: Use drm_fb_cma_fbdev_init/fini() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use drm_fb_cma_fbdev_init() and drm_fb_cma_fbdev_fini() which relies on the fact that drm_device holds a pointer to the drm_fb_helper structure. This means that the driver doesn't have to keep track of that. Also use the drm_fb_helper functions directly. Cc: Liviu Dudau Cc: Brian Starkey Signed-off-by: Noralf Trønnes Acked-by: Liviu Dudau Signed-off-by: Liviu Dudau --- drivers/gpu/drm/arm/hdlcd_drv.c | 37 ++++++--------------------------- drivers/gpu/drm/arm/hdlcd_drv.h | 1 - 2 files changed, 6 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/arm/hdlcd_drv.c b/drivers/gpu/drm/arm/hdlcd_drv.c index 9800a9e388ef..fd5b8c44af14 100644 --- a/drivers/gpu/drm/arm/hdlcd_drv.c +++ b/drivers/gpu/drm/arm/hdlcd_drv.c @@ -101,16 +101,9 @@ setup_fail: return ret; } -static void hdlcd_fb_output_poll_changed(struct drm_device *drm) -{ - struct hdlcd_drm_private *hdlcd = drm->dev_private; - - drm_fbdev_cma_hotplug_event(hdlcd->fbdev); -} - static const struct drm_mode_config_funcs hdlcd_mode_config_funcs = { .fb_create = drm_gem_fb_create, - .output_poll_changed = hdlcd_fb_output_poll_changed, + .output_poll_changed = drm_fb_helper_output_poll_changed, .atomic_check = drm_atomic_helper_check, .atomic_commit = drm_atomic_helper_commit, }; @@ -125,13 +118,6 @@ static void hdlcd_setup_mode_config(struct drm_device *drm) drm->mode_config.funcs = &hdlcd_mode_config_funcs; } -static void hdlcd_lastclose(struct drm_device *drm) -{ - struct hdlcd_drm_private *hdlcd = drm->dev_private; - - drm_fbdev_cma_restore_mode(hdlcd->fbdev); -} - static irqreturn_t hdlcd_irq(int irq, void *arg) { struct drm_device *drm = arg; @@ -247,7 +233,7 @@ static struct drm_driver hdlcd_driver = { .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_ATOMIC, - .lastclose = hdlcd_lastclose, + .lastclose = drm_fb_helper_lastclose, .irq_handler = hdlcd_irq, .irq_preinstall = hdlcd_irq_preinstall, .irq_postinstall = hdlcd_irq_postinstall, @@ -322,14 +308,9 @@ static int hdlcd_drm_bind(struct device *dev) drm_mode_config_reset(drm); drm_kms_helper_poll_init(drm); - hdlcd->fbdev = drm_fbdev_cma_init(drm, 32, - drm->mode_config.num_connector); - - if (IS_ERR(hdlcd->fbdev)) { - ret = PTR_ERR(hdlcd->fbdev); - hdlcd->fbdev = NULL; + ret = drm_fb_cma_fbdev_init(drm, 32, 0); + if (ret) goto err_fbdev; - } ret = drm_dev_register(drm, 0); if (ret) @@ -338,10 +319,7 @@ static int hdlcd_drm_bind(struct device *dev) return 0; err_register: - if (hdlcd->fbdev) { - drm_fbdev_cma_fini(hdlcd->fbdev); - hdlcd->fbdev = NULL; - } + drm_fb_cma_fbdev_fini(drm); err_fbdev: drm_kms_helper_poll_fini(drm); err_vblank: @@ -367,10 +345,7 @@ static void hdlcd_drm_unbind(struct device *dev) struct hdlcd_drm_private *hdlcd = drm->dev_private; drm_dev_unregister(drm); - if (hdlcd->fbdev) { - drm_fbdev_cma_fini(hdlcd->fbdev); - hdlcd->fbdev = NULL; - } + drm_fb_cma_fbdev_fini(drm); drm_kms_helper_poll_fini(drm); component_unbind_all(dev, drm); of_node_put(hdlcd->crtc.port); diff --git a/drivers/gpu/drm/arm/hdlcd_drv.h b/drivers/gpu/drm/arm/hdlcd_drv.h index 58d75d7e1b20..fd438d177b64 100644 --- a/drivers/gpu/drm/arm/hdlcd_drv.h +++ b/drivers/gpu/drm/arm/hdlcd_drv.h @@ -9,7 +9,6 @@ struct hdlcd_drm_private { void __iomem *mmio; struct clk *clk; - struct drm_fbdev_cma *fbdev; struct drm_crtc crtc; struct drm_plane *plane; #ifdef CONFIG_DEBUG_FS From 8df24d57d34cd229e7094cfd1b927b585585202d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 17 Jan 2018 23:55:27 +0200 Subject: [PATCH 3/5] drm: arm: hdlcd: Don't destroy plane manually in hdlcd_setup_crtc() The top-level error handler calls drm_mode_config_cleanup() which will destroy all planes. There's no need to destroy them manually in lower error handlers. Signed-off-by: Laurent Pinchart Signed-off-by: Liviu Dudau --- drivers/gpu/drm/arm/hdlcd_crtc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/arm/hdlcd_crtc.c b/drivers/gpu/drm/arm/hdlcd_crtc.c index f3f08cd6e9ef..c36c75bef6d9 100644 --- a/drivers/gpu/drm/arm/hdlcd_crtc.c +++ b/drivers/gpu/drm/arm/hdlcd_crtc.c @@ -334,10 +334,8 @@ int hdlcd_setup_crtc(struct drm_device *drm) ret = drm_crtc_init_with_planes(drm, &hdlcd->crtc, primary, NULL, &hdlcd_crtc_funcs, NULL); - if (ret) { - hdlcd_plane_destroy(primary); + if (ret) return ret; - } drm_crtc_helper_add(&hdlcd->crtc, &hdlcd_crtc_helper_funcs); return 0; From 9fd466f54f89fc3a2dc6f86fce2ea0b993ff83bd Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 17 Jan 2018 23:55:28 +0200 Subject: [PATCH 4/5] drm: arm: hdlcd: Use drm_atomic_helper_shutdown() to disable planes on removal The plane cleanup handler currently calls drm_plane_helper_disable(), which is a legacy helper function. Replace it with a call to drm_atomic_helper_shutdown() at removal time. The plane .destroy() handler now consisting only of a call to drm_plane_cleanup(), replace it with direct calls to that function. Signed-off-by: Laurent Pinchart Signed-off-by: Liviu Dudau --- drivers/gpu/drm/arm/hdlcd_crtc.c | 8 +------- drivers/gpu/drm/arm/hdlcd_drv.c | 1 + 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/arm/hdlcd_crtc.c b/drivers/gpu/drm/arm/hdlcd_crtc.c index c36c75bef6d9..8978d82159e5 100644 --- a/drivers/gpu/drm/arm/hdlcd_crtc.c +++ b/drivers/gpu/drm/arm/hdlcd_crtc.c @@ -280,16 +280,10 @@ static const struct drm_plane_helper_funcs hdlcd_plane_helper_funcs = { .atomic_update = hdlcd_plane_atomic_update, }; -static void hdlcd_plane_destroy(struct drm_plane *plane) -{ - drm_plane_helper_disable(plane, NULL); - drm_plane_cleanup(plane); -} - static const struct drm_plane_funcs hdlcd_plane_funcs = { .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, - .destroy = hdlcd_plane_destroy, + .destroy = drm_plane_cleanup, .reset = drm_atomic_helper_plane_reset, .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, diff --git a/drivers/gpu/drm/arm/hdlcd_drv.c b/drivers/gpu/drm/arm/hdlcd_drv.c index fd5b8c44af14..70fca288313a 100644 --- a/drivers/gpu/drm/arm/hdlcd_drv.c +++ b/drivers/gpu/drm/arm/hdlcd_drv.c @@ -355,6 +355,7 @@ static void hdlcd_drm_unbind(struct device *dev) pm_runtime_put_sync(drm->dev); pm_runtime_disable(drm->dev); of_reserved_mem_device_release(drm->dev); + drm_atomic_helper_shutdown(drm); drm_mode_config_cleanup(drm); drm_dev_put(drm); drm->dev_private = NULL; From d664b851eb2bcdf84a3c063cf59457bb15bc6120 Mon Sep 17 00:00:00 2001 From: Liviu Dudau Date: Mon, 23 Jul 2018 12:05:53 +0100 Subject: [PATCH 5/5] 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: Liviu Dudau --- drivers/gpu/drm/arm/hdlcd_crtc.c | 23 +++++++++++------------ drivers/gpu/drm/arm/hdlcd_drv.c | 13 ++++++++----- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/arm/hdlcd_crtc.c b/drivers/gpu/drm/arm/hdlcd_crtc.c index 8978d82159e5..e4d67b70244d 100644 --- a/drivers/gpu/drm/arm/hdlcd_crtc.c +++ b/drivers/gpu/drm/arm/hdlcd_crtc.c @@ -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, diff --git a/drivers/gpu/drm/arm/hdlcd_drv.c b/drivers/gpu/drm/arm/hdlcd_drv.c index 70fca288313a..0ed1cde98cf8 100644 --- a/drivers/gpu/drm/arm/hdlcd_drv.c +++ b/drivers/gpu/drm/arm/hdlcd_drv.c @@ -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 = {