From 63470fe3eedc28c8fd8c050cb5427a3f31bd99bd Mon Sep 17 00:00:00 2001
From: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
Date: Thu, 15 Jul 2021 01:08:05 +0200
Subject: [PATCH] drm/vc4: Refactor mode checking logic

Replace drm_encoder_helper_funcs::atomic_check with
drm_connector_helper_funcs::atomic_check - the former is not called
during drm_mode_obj_set_property_ioctl(). Set crtc_state->mode_changed
if TV norm changes even without explicit mode change. This makes things
like "xrandr --output Composite-1 --set mode PAL-M" work properly.

Signed-off-by: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
---
 drivers/gpu/drm/vc4/vc4_vec.c | 42 ++++++++++++++++++++++-------------
 1 file changed, 26 insertions(+), 16 deletions(-)

--- a/drivers/gpu/drm/vc4/vc4_vec.c
+++ b/drivers/gpu/drm/vc4/vc4_vec.c
@@ -421,6 +421,31 @@ static void vc4_vec_connector_reset(stru
 		connector->state->tv.mode = vc4_vec_get_default_mode(connector);
 }
 
+static int vc4_vec_connector_atomic_check(struct drm_connector *conn,
+					  struct drm_atomic_state *state)
+{
+	struct drm_connector_state *old_state =
+		drm_atomic_get_old_connector_state(state, conn);
+	struct drm_connector_state *new_state =
+		drm_atomic_get_new_connector_state(state, conn);
+
+	const struct vc4_vec_tv_mode *vec_mode =
+		&vc4_vec_tv_modes[new_state->tv.mode];
+
+	if (new_state->crtc) {
+		struct drm_crtc_state *crtc_state =
+			drm_atomic_get_new_crtc_state(state, new_state->crtc);
+
+		if (!drm_mode_equal(vec_mode->mode, &crtc_state->mode))
+			return -EINVAL;
+
+		if (old_state->tv.mode != new_state->tv.mode)
+			crtc_state->mode_changed = true;
+	}
+
+	return 0;
+}
+
 static const struct drm_connector_funcs vc4_vec_connector_funcs = {
 	.detect = vc4_vec_connector_detect,
 	.fill_modes = drm_helper_probe_single_connector_modes,
@@ -432,6 +457,7 @@ static const struct drm_connector_funcs
 
 static const struct drm_connector_helper_funcs vc4_vec_connector_helper_funcs = {
 	.get_modes = vc4_vec_connector_get_modes,
+	.atomic_check = vc4_vec_connector_atomic_check,
 };
 
 static struct drm_connector *vc4_vec_connector_init(struct drm_device *dev,
@@ -569,26 +595,10 @@ static bool vc4_vec_encoder_mode_fixup(s
 	return true;
 }
 
-static int vc4_vec_encoder_atomic_check(struct drm_encoder *encoder,
-					struct drm_crtc_state *crtc_state,
-					struct drm_connector_state *conn_state)
-{
-	const struct vc4_vec_tv_mode *vec_mode;
-
-	vec_mode = &vc4_vec_tv_modes[conn_state->tv.mode];
-
-	if (conn_state->crtc &&
-	    !drm_mode_equal(vec_mode->mode, &crtc_state->adjusted_mode))
-		return -EINVAL;
-
-	return 0;
-}
-
 static const struct drm_encoder_helper_funcs vc4_vec_encoder_helper_funcs = {
 	.disable = vc4_vec_encoder_disable,
 	.enable = vc4_vec_encoder_enable,
 	.mode_fixup = vc4_vec_encoder_mode_fixup,
-	.atomic_check = vc4_vec_encoder_atomic_check,
 };
 
 static const struct vc4_vec_variant bcm2835_vec_variant = {
