summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/tidss/tidss_kms.c
diff options
context:
space:
mode:
authorJyri Sarha <jsarha@ti.com>2020-02-27 15:00:52 +0300
committerJyri Sarha <jsarha@ti.com>2020-02-28 15:48:58 +0300
commitb33b54748866f7bc29696837c472f49413169d4e (patch)
tree85563d8f0987887e553b6bd537a8f55eee128490 /drivers/gpu/drm/tidss/tidss_kms.c
parentd6b8bbca6bc83b9c57e528b28df6177b9b57e19d (diff)
downloadlinux-b33b54748866f7bc29696837c472f49413169d4e.tar.xz
drm/tidss: dispc: Fix broken plane positioning code
The old implementation of placing planes on the CRTC while configuring the planes was naive and relied on the order in which the planes were configured, enabled, and disabled. The situation where a plane's zpos was changed on the fly was completely broken. The usual symptoms of this problem was scrambled display and a flood of sync lost errors, when a plane was active in two layers at the same time, or a missing plane, in case when a layer was accidentally disabled. The rewrite takes a more straight forward approach when HW is concerned. The plane positioning registers are in the CRTC (or actually OVR) register space and it is more natural to configure them in a one go when configuring the CRTC. To do this we need make sure we have all the planes on the updated CRTCs in the new atomic state. The untouched planes on CRTCs that need plane position update are added to the atomic state in tidss_atomic_check(). Signed-off-by: Jyri Sarha <jsarha@ti.com> Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ti.com> Link: https://patchwork.freedesktop.org/patch/msgid/20200227120052.23168-1-jsarha@ti.com
Diffstat (limited to 'drivers/gpu/drm/tidss/tidss_kms.c')
-rw-r--r--drivers/gpu/drm/tidss/tidss_kms.c52
1 files changed, 51 insertions, 1 deletions
diff --git a/drivers/gpu/drm/tidss/tidss_kms.c b/drivers/gpu/drm/tidss/tidss_kms.c
index 3b6f8d54a016..7d419960b030 100644
--- a/drivers/gpu/drm/tidss/tidss_kms.c
+++ b/drivers/gpu/drm/tidss/tidss_kms.c
@@ -47,9 +47,59 @@ static const struct drm_mode_config_helper_funcs mode_config_helper_funcs = {
.atomic_commit_tail = tidss_atomic_commit_tail,
};
+static int tidss_atomic_check(struct drm_device *ddev,
+ struct drm_atomic_state *state)
+{
+ struct drm_plane_state *opstate;
+ struct drm_plane_state *npstate;
+ struct drm_plane *plane;
+ struct drm_crtc_state *cstate;
+ struct drm_crtc *crtc;
+ int ret, i;
+
+ ret = drm_atomic_helper_check(ddev, state);
+ if (ret)
+ return ret;
+
+ /*
+ * Add all active planes on a CRTC to the atomic state, if
+ * x/y/z position or activity of any plane on that CRTC
+ * changes. This is needed for updating the plane positions in
+ * tidss_crtc_position_planes() which is called from
+ * crtc_atomic_enable() and crtc_atomic_flush(). We have an
+ * extra flag to to mark x,y-position changes and together
+ * with zpos_changed the condition recognizes all the above
+ * cases.
+ */
+ for_each_oldnew_plane_in_state(state, plane, opstate, npstate, i) {
+ if (!npstate->crtc || !npstate->visible)
+ continue;
+
+ if (!opstate->crtc || opstate->crtc_x != npstate->crtc_x ||
+ opstate->crtc_y != npstate->crtc_y) {
+ cstate = drm_atomic_get_crtc_state(state,
+ npstate->crtc);
+ if (IS_ERR(cstate))
+ return PTR_ERR(cstate);
+ to_tidss_crtc_state(cstate)->plane_pos_changed = true;
+ }
+ }
+
+ for_each_new_crtc_in_state(state, crtc, cstate, i) {
+ if (to_tidss_crtc_state(cstate)->plane_pos_changed ||
+ cstate->zpos_changed) {
+ ret = drm_atomic_add_affected_planes(state, crtc);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
static const struct drm_mode_config_funcs mode_config_funcs = {
.fb_create = drm_gem_fb_create,
- .atomic_check = drm_atomic_helper_check,
+ .atomic_check = tidss_atomic_check,
.atomic_commit = drm_atomic_helper_commit,
};