[PATCH] [RFC] drm/i915/skl+: enable PF_ID interlace mode in SKL

Mahesh Kumar mahesh1.kumar at intel.com
Tue Jun 6 08:25:14 UTC 2017


Default Interlace mode enabled is IF-ID, but IF-ID has limitations in
SKL. This mode doesn't supported with y-tiling, 90-270 rotation is not
supported & YUV-420 planar  source pixel formats are not supported with
above mode.

This patch make changes to use PF-ID Interlace mode in SKL+ platforms.
PF-ID mode require one scaler to be attached in pipe-scaling mode.

Signed-off-by: Mahesh Kumar <mahesh1.kumar at intel.com>
---
 drivers/gpu/drm/i915/intel_atomic.c  |  6 ++++++
 drivers/gpu/drm/i915/intel_display.c | 38 ++++++++++++++++++++++++++++++++----
 drivers/gpu/drm/i915/intel_drv.h     | 10 ++++++++++
 drivers/gpu/drm/i915/intel_panel.c   |  9 +++++++--
 drivers/gpu/drm/i915/intel_pm.c      |  3 +++
 5 files changed, 60 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c
index d791b3ef89b5..8e7d003240ca 100644
--- a/drivers/gpu/drm/i915/intel_atomic.c
+++ b/drivers/gpu/drm/i915/intel_atomic.c
@@ -264,6 +264,12 @@ int intel_atomic_setup_scalers(struct drm_i915_private *dev_priv,
 
 			/* panel fitter case: assign as a crtc scaler */
 			scaler_id = &scaler_state->scaler_id;
+		} else if (i == SKL_PF_ID_INDEX) {
+			name = "PF-ID INTERLACE MODE";
+			idx = intel_crtc->base.base.id;
+
+			/* PF-ID interlaced mode case: needs a pipe scaler */
+			scaler_id = &scaler_state->scaler_id;
 		} else {
 			name = "PLANE";
 
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index ed41b59ee8e3..849006fab426 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -4623,6 +4623,11 @@ skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach,
 		(src_h != dst_w || src_w != dst_h):
 		(src_w != dst_w || src_h != dst_h);
 
+	if ((crtc_state->base.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
+		&& scaler_user == SKL_PF_ID_INDEX)
+		/* PF-ID Interlace mode needs a scaler */
+		need_scaling = true;
+
 	/*
 	 * if plane is being disabled or scaler is no more required or force detach
 	 *  - free scaler binded to this plane/crtc
@@ -4632,9 +4637,12 @@ skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach,
 	 * scaler can be assigned to other user. Actual register
 	 * update to free the scaler is done in plane/panel-fit programming.
 	 * For this purpose crtc/plane_state->scaler_id isn't reset here.
+	 * Now Interlace mode is new a user of pipe-scaler, so free the scaler-id
+	 * only if call is for respective user.
 	 */
 	if (force_detach || !need_scaling) {
-		if (*scaler_id >= 0) {
+		if (*scaler_id >= 0 && (scaler_state->scaler_users & (1 <<
+					scaler_user))) {
 			scaler_state->scaler_users &= ~(1 << scaler_user);
 			scaler_state->scalers[*scaler_id].in_use = 0;
 
@@ -4688,6 +4696,16 @@ int skl_update_scaler_crtc(struct intel_crtc_state *state)
 		adjusted_mode->crtc_hdisplay, adjusted_mode->crtc_vdisplay);
 }
 
+static int skl_update_scaler_crtc_pf_id_output(struct intel_crtc_state *state)
+{
+	const struct drm_display_mode *mode = &state->base.adjusted_mode;
+
+	return skl_update_scaler(state, !state->base.active,
+		SKL_PF_ID_INDEX, &state->scaler_state.scaler_id,
+		DRM_MODE_ROTATE_0, state->pipe_src_w, state->pipe_src_h,
+		mode->crtc_hdisplay, mode->crtc_vdisplay);
+}
+
 /**
  * skl_update_scaler_plane - Stages update to scaler state for a given plane.
  *
@@ -6256,6 +6274,15 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc,
 		}
 	}
 
+	if (INTEL_GEN(dev_priv) >= 9) {
+		if (skl_update_scaler_crtc_pf_id_output(pipe_config)) {
+			DRM_ERROR("Unable to set scaler for PF-ID mode\n");
+			return -EINVAL;
+		}
+		intel_pch_panel_fitting(crtc, pipe_config,
+					DRM_MODE_SCALE_FULLSCREEN);
+	}
+
 	if (adjusted_mode->crtc_clock > clock_limit) {
 		DRM_DEBUG_KMS("requested pixel clock (%d kHz) too high (max: %d kHz, double wide: %s)\n",
 			      adjusted_mode->crtc_clock, clock_limit,
@@ -8043,9 +8070,12 @@ static void haswell_set_pipeconf(struct drm_crtc *crtc)
 	if (IS_HASWELL(dev_priv) && intel_crtc->config->dither)
 		val |= (PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_SP);
 
-	if (intel_crtc->config->base.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
-		val |= PIPECONF_INTERLACED_ILK;
-	else
+	if (intel_crtc->config->base.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) {
+		if (INTEL_GEN(dev_priv) >= 9)
+			val |= PIPECONF_PFIT_PF_INTERLACED_ILK;
+		else
+			val |= PIPECONF_INTERLACED_ILK;
+	} else
 		val |= PIPECONF_PROGRESSIVE;
 
 	I915_WRITE(PIPECONF(cpu_transcoder), val);
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 83dd40905821..d4546f6498b9 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -483,6 +483,7 @@ struct intel_crtc_scaler_state {
 	 * avilability.
 	 */
 #define SKL_CRTC_INDEX 31
+#define SKL_PF_ID_INDEX 29
 	unsigned scaler_users;
 
 	/* scaler used by crtc for panel fitting purpose */
@@ -1206,6 +1207,15 @@ hdmi_to_dig_port(struct intel_hdmi *intel_hdmi)
 	return container_of(intel_hdmi, struct intel_digital_port, hdmi);
 }
 
+static inline bool
+is_skl_interlace_mode(struct drm_i915_private *dev_priv,
+		      const struct drm_display_mode *mode)
+{
+	if (INTEL_GEN(dev_priv) < 9)
+		return false;
+	return mode->flags & DRM_MODE_FLAG_INTERLACE;
+}
+
 /* intel_fifo_underrun.c */
 bool intel_set_cpu_fifo_underrun_reporting(struct drm_i915_private *dev_priv,
 					   enum pipe pipe, bool enable);
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index 4114cb3f14e7..fae7fe7802f8 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -108,9 +108,14 @@ intel_pch_panel_fitting(struct intel_crtc *intel_crtc,
 	const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
 	int x = 0, y = 0, width = 0, height = 0;
 
-	/* Native modes don't need fitting */
+	/*
+	 * Native modes don't need fitting
+	 * PF-ID Interlace mode in SKL+ require a pipe scaler
+	 */
 	if (adjusted_mode->crtc_hdisplay == pipe_config->pipe_src_w &&
-	    adjusted_mode->crtc_vdisplay == pipe_config->pipe_src_h)
+	    adjusted_mode->crtc_vdisplay == pipe_config->pipe_src_h &&
+	    !(is_skl_interlace_mode(to_i915(intel_crtc->base.dev),
+				    adjusted_mode)))
 		goto done;
 
 	switch (fitting_mode) {
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index ae36df02948a..3b27d42eb8fa 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -4408,6 +4408,9 @@ skl_adjusted_plane_pixel_rate(const struct intel_crtc_state *cstate,
 	 * with additional adjustments for plane-specific scaling.
 	 */
 	adjusted_pixel_rate = cstate->pixel_rate;
+	if (cstate->base.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
+		adjusted_pixel_rate *= 2;
+
 	downscale_amount = skl_plane_downscale_amount(cstate, pstate);
 
 	return mul_round_up_u32_fixed16(adjusted_pixel_rate,
-- 
2.11.0



More information about the Intel-gfx-trybot mailing list