drm/msm/sde: reject commits that only update crtc roi

Add check to reject commits that update the CRTC ROI but do not
update the Connector ROI as well.

Change-Id: I1f9ac169cf899424f7375e361b1f5710c6566207
Signed-off-by: Lloyd Atkinson <latkinso@codeaurora.org>
diff --git a/drivers/gpu/drm/msm/msm_prop.c b/drivers/gpu/drm/msm/msm_prop.c
index ce84b7a..8e85c81 100644
--- a/drivers/gpu/drm/msm/msm_prop.c
+++ b/drivers/gpu/drm/msm/msm_prop.c
@@ -128,6 +128,20 @@
 			&property_state->dirty_list);
 }
 
+bool msm_property_is_dirty(
+		struct msm_property_info *info,
+		struct msm_property_state *property_state,
+		uint32_t property_idx)
+{
+	if (!info || !property_state || !property_state->values ||
+			property_idx >= info->property_count) {
+		DRM_ERROR("invalid argument(s), idx %u\n", property_idx);
+		return false;
+	}
+
+	return !list_empty(&property_state->values[property_idx].dirty_node);
+}
+
 /**
  * _msm_property_install_integer - install standard drm range property
  * @info: Pointer to property info container struct
diff --git a/drivers/gpu/drm/msm/msm_prop.h b/drivers/gpu/drm/msm/msm_prop.h
index d257a8c..ecc1d0b 100644
--- a/drivers/gpu/drm/msm/msm_prop.h
+++ b/drivers/gpu/drm/msm/msm_prop.h
@@ -316,6 +316,19 @@
 		int property_idx);
 
 /**
+ * msm_property_is_dirty - check whether a property is dirty
+ *	Note: Intended for use during atomic_check before pop_dirty usage
+ * @info: Pointer to property info container struct
+ * @property_state: Pointer to property state container struct
+ * @property_idx: Property index
+ * Returns: true if dirty, false otherwise
+ */
+bool msm_property_is_dirty(
+		struct msm_property_info *info,
+		struct msm_property_state *property_state,
+		uint32_t property_idx);
+
+/**
  * msm_property_atomic_set - helper function for atomic property set callback
  * @info: Pointer to property info container struct
  * @property_state: Pointer to local state structure
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index 2aeec3f..9d138cc 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -789,6 +789,21 @@
 	*crtc_roi = &crtc_state->crtc_roi;
 }
 
+bool sde_crtc_is_crtc_roi_dirty(struct drm_crtc_state *state)
+{
+	struct sde_crtc_state *cstate;
+	struct sde_crtc *sde_crtc;
+
+	if (!state || !state->crtc)
+		return false;
+
+	sde_crtc = to_sde_crtc(state->crtc);
+	cstate = to_sde_crtc_state(state);
+
+	return msm_property_is_dirty(&sde_crtc->property_info,
+			&cstate->property_state, CRTC_PROP_ROI_V1);
+}
+
 static int _sde_crtc_set_roi_v1(struct drm_crtc_state *state,
 		void __user *usr_ptr)
 {
@@ -877,6 +892,8 @@
 	struct sde_crtc_state *crtc_state;
 	struct sde_rect *crtc_roi;
 	int i, num_attached_conns = 0;
+	bool is_crtc_roi_dirty;
+	bool is_any_conn_roi_dirty;
 
 	if (!crtc || !state)
 		return -EINVAL;
@@ -885,7 +902,11 @@
 	crtc_state = to_sde_crtc_state(state);
 	crtc_roi = &crtc_state->crtc_roi;
 
+	is_crtc_roi_dirty = sde_crtc_is_crtc_roi_dirty(state);
+	is_any_conn_roi_dirty = false;
+
 	for_each_connector_in_state(state->state, conn, conn_state, i) {
+		struct sde_connector *sde_conn;
 		struct sde_connector_state *sde_conn_state;
 		struct sde_rect conn_roi;
 
@@ -900,8 +921,15 @@
 		}
 		++num_attached_conns;
 
+		sde_conn = to_sde_connector(conn_state->connector);
 		sde_conn_state = to_sde_connector_state(conn_state);
 
+		is_any_conn_roi_dirty = is_any_conn_roi_dirty ||
+				msm_property_is_dirty(
+						&sde_conn->property_info,
+						&sde_conn_state->property_state,
+						CONNECTOR_PROP_ROI_V1);
+
 		/*
 		 * current driver only supports same connector and crtc size,
 		 * but if support for different sizes is added, driver needs
@@ -921,6 +949,16 @@
 				conn_roi.w, conn_roi.h);
 	}
 
+	/*
+	 * Check against CRTC ROI and Connector ROI not being updated together.
+	 * This restriction should be relaxed when Connector ROI scaling is
+	 * supported.
+	 */
+	if (is_any_conn_roi_dirty != is_crtc_roi_dirty) {
+		SDE_ERROR("connector/crtc rois not updated together\n");
+		return -EINVAL;
+	}
+
 	sde_kms_rect_merge_rectangles(&crtc_state->user_roi_list, crtc_roi);
 
 	SDE_DEBUG("%s: crtc roi (%d,%d,%d,%d)\n", sde_crtc->name,
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h
index c6b4afa..9501d0f 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.h
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.h
@@ -684,6 +684,14 @@
 void sde_crtc_get_crtc_roi(struct drm_crtc_state *state,
 		const struct sde_rect **crtc_roi);
 
+/**
+ * sde_crtc_is_crtc_roi_dirty - retrieve whether crtc_roi was updated this frame
+ *	Note: Only use during atomic_check since dirty properties may be popped
+ * @crtc_state: Pointer to crtc state
+ * Return: true if roi is dirty, false otherwise
+ */
+bool sde_crtc_is_crtc_roi_dirty(struct drm_crtc_state *state);
+
 /** sde_crt_get_secure_level - retrieve the secure level from the give state
  *	object, this is used to determine the secure state of the crtc
  * @crtc : Pointer to drm crtc structure