[PATCH 5/9] drm/i915: Disable PSR2 while getting pipe CRC

José Roberto de Souza jose.souza at intel.com
Thu Jan 31 01:47:56 UTC 2019


As stated in CRC_CTL spec, CRC must be enabled before enable PSR
because it will be calculate in PSR entry state.
But for PSR2 it is more problematic as a page flip could trigger a
partial screen update causing the CRC value not to be calculated over
the full pipe or plane.

So here if PSR2 is enabled, it will exit and keep PSR2 inactive while
there is CRC users of the pipe used by eDP panel.

BSpec: 7536

Cc: Dhinakaran Pandiyan <dhinakaran.pandiyan at intel.com>
Cc: Ville Syrjälä <ville.syrjala at linux.intel.com>
Signed-off-by: José Roberto de Souza <jose.souza at intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h       |  1 +
 drivers/gpu/drm/i915/intel_drv.h      |  2 +
 drivers/gpu/drm/i915/intel_pipe_crc.c | 34 +++++++++++++++
 drivers/gpu/drm/i915/intel_psr.c      | 62 +++++++++++++++++++++++++++
 4 files changed, 99 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index f75b4ce4df5f..f9cee5e64071 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -512,6 +512,7 @@ struct i915_psr {
 	bool sink_not_reliable;
 	bool irq_aux_error;
 	u16 su_x_granularity;
+	u8 pipe_crc_refcount;
 };
 
 enum intel_pch {
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 4c01decc30d3..b23ff4a897dc 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -2085,6 +2085,8 @@ void intel_psr_short_pulse(struct intel_dp *intel_dp);
 int intel_psr_wait_for_idle(const struct intel_crtc_state *new_crtc_state,
 			    u32 *out_value);
 bool intel_psr_enabled(struct intel_dp *intel_dp);
+bool intel_psr_crc_prepare(struct intel_dp *intel_dp);
+bool intel_psr_crc_finish(struct intel_dp *intel_dp);
 
 /* intel_quirks.c */
 void intel_init_quirks(struct drm_i915_private *dev_priv);
diff --git a/drivers/gpu/drm/i915/intel_pipe_crc.c b/drivers/gpu/drm/i915/intel_pipe_crc.c
index a8554dc4f196..d462a929170d 100644
--- a/drivers/gpu/drm/i915/intel_pipe_crc.c
+++ b/drivers/gpu/drm/i915/intel_pipe_crc.c
@@ -583,6 +583,34 @@ int intel_crtc_verify_crc_source(struct drm_crtc *crtc, const char *source_name,
 	return -EINVAL;
 }
 
+static void intel_crtc_crc_prepare_or_finish(struct drm_crtc *crtc, bool prepare)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_connector_list_iter conn_iter;
+	struct drm_connector *connector;
+
+	drm_connector_list_iter_begin(dev, &conn_iter);
+	drm_for_each_connector_iter(connector, &conn_iter) {
+		struct intel_encoder *encoder;
+		struct intel_dp *intel_dp;
+
+		if (connector->connector_type != DRM_MODE_CONNECTOR_eDP)
+			continue;
+
+		encoder = to_intel_encoder(connector->encoder);
+		intel_dp = enc_to_intel_dp(&encoder->base);
+
+		if (prepare)
+			intel_psr_crc_prepare(intel_dp);
+		else
+			intel_psr_crc_finish(intel_dp);
+	}
+	drm_connector_list_iter_end(&conn_iter);
+}
+
+#define intel_crtc_crc_prepare(crtc) intel_crtc_crc_prepare_or_finish(crtc, true)
+#define intel_crtc_crc_finish(crtc) intel_crtc_crc_prepare_or_finish(crtc, false)
+
 int intel_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name)
 {
 	struct drm_i915_private *dev_priv = to_i915(crtc->dev);
@@ -605,6 +633,8 @@ int intel_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name)
 		return -EIO;
 	}
 
+	intel_crtc_crc_prepare(crtc);
+
 	ret = get_new_crc_ctl_reg(dev_priv, crtc->index, &source, &val, true);
 	if (ret != 0)
 		goto out;
@@ -641,6 +671,8 @@ void intel_crtc_enable_pipe_crc(struct intel_crtc *intel_crtc)
 	if (!crtc->crc.opened)
 		return;
 
+	intel_crtc_crc_prepare(crtc);
+
 	if (get_new_crc_ctl_reg(dev_priv, crtc->index, &pipe_crc->source, &val, false) < 0)
 		return;
 
@@ -662,6 +694,8 @@ void intel_crtc_disable_pipe_crc(struct intel_crtc *intel_crtc)
 	pipe_crc->skipped = INT_MIN;
 	spin_unlock_irq(&pipe_crc->lock);
 
+	intel_crtc_crc_finish(crtc);
+
 	I915_WRITE(PIPE_CRC_CTL(crtc->index), 0);
 	POSTING_READ(PIPE_CRC_CTL(crtc->index));
 	synchronize_irq(dev_priv->drm.irq);
diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c
index 7ee30b7f6b33..2814244ca947 100644
--- a/drivers/gpu/drm/i915/intel_psr.c
+++ b/drivers/gpu/drm/i915/intel_psr.c
@@ -1078,6 +1078,9 @@ static void intel_psr_work(struct work_struct *work)
 	if (dev_priv->psr.busy_frontbuffer_bits || dev_priv->psr.active)
 		goto unlock;
 
+	if (dev_priv->psr.pipe_crc_refcount)
+		goto unlock;
+
 	intel_psr_activate(dev_priv->psr.dp);
 unlock:
 	mutex_unlock(&dev_priv->psr.lock);
@@ -1288,3 +1291,62 @@ bool intel_psr_enabled(struct intel_dp *intel_dp)
 
 	return ret;
 }
+
+bool intel_psr_crc_prepare(struct intel_dp *intel_dp)
+{
+	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+	bool ret = false;
+
+	if (!CAN_PSR(dev_priv) || !intel_dp_is_edp(intel_dp))
+		return false;
+
+	mutex_lock(&dev_priv->psr.lock);
+
+	if (dev_priv->psr.dp != intel_dp)
+		goto unlock;
+
+	dev_priv->psr.pipe_crc_refcount++;
+	ret = true;
+
+	if (!dev_priv->psr.active || !dev_priv->psr.psr2_enabled)
+		goto unlock;
+
+	DRM_DEBUG_KMS("Exiting PSR2 because pipe CRC is requested\n");
+	intel_psr_exit(dev_priv);
+unlock:
+	mutex_unlock(&dev_priv->psr.lock);
+
+	return ret;
+}
+
+bool intel_psr_crc_finish(struct intel_dp *intel_dp)
+{
+	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+	bool ret = false;
+
+	if (!CAN_PSR(dev_priv) || !intel_dp_is_edp(intel_dp))
+		return false;
+
+	mutex_lock(&dev_priv->psr.lock);
+
+	if (dev_priv->psr.dp != intel_dp)
+		goto unlock;
+
+	ret = true;
+	dev_priv->psr.pipe_crc_refcount--;
+
+	if (dev_priv->psr.pipe_crc_refcount)
+		goto unlock;
+
+	if (dev_priv->psr.enabled && dev_priv->psr.psr2_enabled) {
+		DRM_DEBUG_KMS("No more pipe CRC users, scheduling PSR2 enable\n");
+
+		if (!dev_priv->psr.busy_frontbuffer_bits)
+			schedule_work(&dev_priv->psr.work);
+	}
+
+unlock:
+	mutex_unlock(&dev_priv->psr.lock);
+
+	return ret;
+}
-- 
2.20.1



More information about the Intel-gfx-trybot mailing list