Merge "drm/msm/sde: add autorefresh property to sde crtc" into msm-4.9
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 4471d0b..934bea1 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -164,6 +164,7 @@
 	/* enum/bitmask properties */
 	CONNECTOR_PROP_TOPOLOGY_NAME,
 	CONNECTOR_PROP_TOPOLOGY_CONTROL,
+	CONNECTOR_PROP_AUTOREFRESH,
 
 	/* total # of properties */
 	CONNECTOR_PROP_COUNT
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c
index e3f8261..9f8d7ee 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.c
+++ b/drivers/gpu/drm/msm/sde/sde_connector.c
@@ -21,6 +21,9 @@
 
 #define BL_NODE_NAME_SIZE 32
 
+/* Autorefresh will occur after FRAME_CNT frames. Large values are unlikely */
+#define AUTOREFRESH_MAX_FRAME_CNT 6
+
 #define SDE_DEBUG_CONN(c, fmt, ...) SDE_DEBUG("conn%d " fmt,\
 		(c) ? (c)->base.base.id : -1, ##__VA_ARGS__)
 
@@ -990,6 +993,10 @@
 	msm_property_install_range(&c_conn->property_info, "RETIRE_FENCE",
 			0x0, 0, INR_OPEN_MAX, 0, CONNECTOR_PROP_RETIRE_FENCE);
 
+	msm_property_install_range(&c_conn->property_info, "autorefresh",
+			0x0, 0, AUTOREFRESH_MAX_FRAME_CNT, 0,
+			CONNECTOR_PROP_AUTOREFRESH);
+
 	/* enum/bitmask properties */
 	msm_property_install_enum(&c_conn->property_info, "topology_name",
 			DRM_MODE_PROP_IMMUTABLE, 0, e_topology_name,
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index 6bae083..12bb1a3 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -808,6 +808,44 @@
 	return 0;
 }
 
+static int _sde_crtc_check_autorefresh(struct drm_crtc *crtc,
+		struct drm_crtc_state *state)
+{
+	struct sde_crtc *sde_crtc;
+	struct sde_crtc_state *crtc_state;
+	struct drm_connector *conn;
+	struct drm_connector_state *conn_state;
+	int i;
+
+	if (!crtc || !state)
+		return -EINVAL;
+
+	sde_crtc = to_sde_crtc(crtc);
+	crtc_state = to_sde_crtc_state(state);
+
+	if (sde_kms_rect_is_null(&crtc_state->crtc_roi))
+		return 0;
+
+	/* partial update active, check if autorefresh is also requested */
+	for_each_connector_in_state(state->state, conn, conn_state, i) {
+		uint64_t autorefresh;
+
+		if (!conn_state || conn_state->crtc != crtc)
+			continue;
+
+		autorefresh = sde_connector_get_property(conn_state,
+				CONNECTOR_PROP_AUTOREFRESH);
+		if (autorefresh) {
+			SDE_ERROR(
+				"%s: autorefresh & partial crtc roi incompatible %llu\n",
+					sde_crtc->name, autorefresh);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
 static int _sde_crtc_set_lm_roi(struct drm_crtc *crtc,
 		struct drm_crtc_state *state, int lm_idx)
 {
@@ -953,6 +991,10 @@
 	if (rc)
 		return rc;
 
+	rc = _sde_crtc_check_autorefresh(crtc, state);
+	if (rc)
+		return rc;
+
 	for (lm_idx = 0; lm_idx < sde_crtc->num_mixers; lm_idx++) {
 		rc = _sde_crtc_set_lm_roi(crtc, state, lm_idx);
 		if (rc)