diff mbox series

[1/6] drm/i915/display/psr: Handle SU Y granularity

Message ID 20210616203158.118111-1-jose.souza@intel.com (mailing list archive)
State New, archived
Headers show
Series [1/6] drm/i915/display/psr: Handle SU Y granularity | expand

Commit Message

Souza, Jose June 16, 2021, 8:31 p.m. UTC
We were only handling X and width granularity, what was causing issues
when sink had a granularity different than 4.

While at it, renaming su_x_granularity to su_w_granularity to better
match reality.

Cc: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
Signed-off-by: José Roberto de Souza <jose.souza@intel.com>
---
 .../drm/i915/display/intel_display_types.h    |   4 +-
 drivers/gpu/drm/i915/display/intel_psr.c      | 110 ++++++++++++------
 2 files changed, 80 insertions(+), 34 deletions(-)

Comments

Gwan-gyeong Mun June 23, 2021, 11:55 a.m. UTC | #1
looks good to me.

Reviewed-by: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>

On 6/16/21 11:31 PM, José Roberto de Souza wrote:
> We were only handling X and width granularity, what was causing issues
> when sink had a granularity different than 4.
> 
> While at it, renaming su_x_granularity to su_w_granularity to better
> match reality.
> 
> Cc: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
> Signed-off-by: José Roberto de Souza <jose.souza@intel.com>
> ---
>   .../drm/i915/display/intel_display_types.h    |   4 +-
>   drivers/gpu/drm/i915/display/intel_psr.c      | 110 ++++++++++++------
>   2 files changed, 80 insertions(+), 34 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
> index 15e91a99c8b9a..f89152ca52a20 100644
> --- a/drivers/gpu/drm/i915/display/intel_display_types.h
> +++ b/drivers/gpu/drm/i915/display/intel_display_types.h
> @@ -1041,6 +1041,7 @@ struct intel_crtc_state {
>   	bool has_psr2;
>   	bool enable_psr2_sel_fetch;
>   	u32 dc3co_exitline;
> +	u16 su_y_granularity;
>   
>   	/*
>   	 * Frequence the dpll for the port should run at. Differs from the
> @@ -1498,7 +1499,8 @@ struct intel_psr {
>   	ktime_t last_exit;
>   	bool sink_not_reliable;
>   	bool irq_aux_error;
> -	u16 su_x_granularity;
> +	u16 su_w_granularity;
> +	u16 su_y_granularity;
>   	u32 dc3co_exitline;
>   	u32 dc3co_exit_delay;
>   	struct delayed_work dc3co_work;
> diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c
> index 77865cf6641f8..fde30f937504e 100644
> --- a/drivers/gpu/drm/i915/display/intel_psr.c
> +++ b/drivers/gpu/drm/i915/display/intel_psr.c
> @@ -265,32 +265,44 @@ static u8 intel_dp_get_sink_sync_latency(struct intel_dp *intel_dp)
>   	return val;
>   }
>   
> -static u16 intel_dp_get_su_x_granulartiy(struct intel_dp *intel_dp)
> +static void intel_dp_get_su_granularity(struct intel_dp *intel_dp)
>   {
>   	struct drm_i915_private *i915 = dp_to_i915(intel_dp);
> -	u16 val;
>   	ssize_t r;
> +	u16 w;
> +	u8 y;
> +
> +	/* If sink don't have specific granularity requirements set legacy ones */
> +	if (!(intel_dp->psr_dpcd[1] & DP_PSR2_SU_GRANULARITY_REQUIRED)) {
> +		/* As PSR2 HW sends full lines, we do not care about x granularity */
> +		w = 4;
> +		y = 4;
> +		goto exit;
> +	}
>   
> -	/*
> -	 * Returning the default X granularity if granularity not required or
> -	 * if DPCD read fails
> -	 */
> -	if (!(intel_dp->psr_dpcd[1] & DP_PSR2_SU_GRANULARITY_REQUIRED))
> -		return 4;
> -
> -	r = drm_dp_dpcd_read(&intel_dp->aux, DP_PSR2_SU_X_GRANULARITY, &val, 2);
> +	r = drm_dp_dpcd_read(&intel_dp->aux, DP_PSR2_SU_X_GRANULARITY, &w, 2);
>   	if (r != 2)
>   		drm_dbg_kms(&i915->drm,
>   			    "Unable to read DP_PSR2_SU_X_GRANULARITY\n");
> -
>   	/*
>   	 * Spec says that if the value read is 0 the default granularity should
>   	 * be used instead.
>   	 */
> -	if (r != 2 || val == 0)
> -		val = 4;
> +	if (r != 2 || w == 0)
> +		w = 4;
>   
> -	return val;
> +	r = drm_dp_dpcd_read(&intel_dp->aux, DP_PSR2_SU_Y_GRANULARITY, &y, 1);
> +	if (r != 1) {
> +		drm_dbg_kms(&i915->drm,
> +			    "Unable to read DP_PSR2_SU_Y_GRANULARITY\n");
> +		y = 4;
> +	}
> +	if (y == 0)
> +		y = 1;
> +
> +exit:
> +	intel_dp->psr.su_w_granularity = w;
> +	intel_dp->psr.su_y_granularity = y;
>   }
>   
>   void intel_psr_init_dpcd(struct intel_dp *intel_dp)
> @@ -346,8 +358,7 @@ void intel_psr_init_dpcd(struct intel_dp *intel_dp)
>   		if (intel_dp->psr.sink_psr2_support) {
>   			intel_dp->psr.colorimetry_support =
>   				intel_dp_get_colorimetry_status(intel_dp);
> -			intel_dp->psr.su_x_granularity =
> -				intel_dp_get_su_x_granulartiy(intel_dp);
> +			intel_dp_get_su_granularity(intel_dp);
>   		}
>   	}
>   }
> @@ -742,6 +753,40 @@ static bool intel_psr2_sel_fetch_config_valid(struct intel_dp *intel_dp,
>   	return crtc_state->enable_psr2_sel_fetch = true;
>   }
>   
> +static bool psr2_granularity_check(struct intel_dp *intel_dp,
> +				   struct intel_crtc_state *crtc_state)
> +{
> +	const int crtc_hdisplay = crtc_state->hw.adjusted_mode.crtc_hdisplay;
> +	const int crtc_vdisplay = crtc_state->hw.adjusted_mode.crtc_vdisplay;
> +	u16 y_granularity = 0;
> +
> +	/* PSR2 HW only send full lines so we only need to validate the width */
> +	if (crtc_hdisplay % intel_dp->psr.su_w_granularity)
> +		return false;
> +
> +	if (crtc_vdisplay % intel_dp->psr.su_y_granularity)
> +		return false;
> +
> +	/* HW tracking is only aligned to 4 lines */
> +	if (!crtc_state->enable_psr2_sel_fetch)
> +		return intel_dp->psr.su_y_granularity == 4;
> +
> +	/*
> +	 * For SW tracking we can adjust the y to match sink requirement if
> +	 * multiple of 4
> +	 */
> +	if (intel_dp->psr.su_y_granularity <= 2)
> +		y_granularity = 4;
> +	else if ((intel_dp->psr.su_y_granularity % 4) == 0)
> +		y_granularity = intel_dp->psr.su_y_granularity;
> +
> +	if (y_granularity == 0 || crtc_vdisplay % y_granularity)
> +		return false;
> +
> +	crtc_state->su_y_granularity = y_granularity;
> +	return true;
> +}
> +
>   static bool intel_psr2_config_valid(struct intel_dp *intel_dp,
>   				    struct intel_crtc_state *crtc_state)
>   {
> @@ -824,19 +869,6 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp,
>   		return false;
>   	}
>   
> -	/*
> -	 * HW sends SU blocks of size four scan lines, which means the starting
> -	 * X coordinate and Y granularity requirements will always be met. We
> -	 * only need to validate the SU block width is a multiple of
> -	 * x granularity.
> -	 */
> -	if (crtc_hdisplay % intel_dp->psr.su_x_granularity) {
> -		drm_dbg_kms(&dev_priv->drm,
> -			    "PSR2 not enabled, hdisplay(%d) not multiple of %d\n",
> -			    crtc_hdisplay, intel_dp->psr.su_x_granularity);
> -		return false;
> -	}
> -
>   	if (HAS_PSR2_SEL_FETCH(dev_priv)) {
>   		if (!intel_psr2_sel_fetch_config_valid(intel_dp, crtc_state) &&
>   		    !HAS_PSR_HW_TRACKING(dev_priv)) {
> @@ -853,6 +885,11 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp,
>   		return false;
>   	}
>   
> +	if (!psr2_granularity_check(intel_dp, crtc_state)) {
> +		drm_dbg_kms(&dev_priv->drm, "PSR2 not enabled, SU granularity not compatible\n");
> +		return false;
> +	}
> +
>   	if (!crtc_state->enable_psr2_sel_fetch &&
>   	    (crtc_hdisplay > psr_max_h || crtc_vdisplay > psr_max_v)) {
>   		drm_dbg_kms(&dev_priv->drm,
> @@ -1432,6 +1469,16 @@ static void clip_area_update(struct drm_rect *overlap_damage_area,
>   		overlap_damage_area->y2 = damage_area->y2;
>   }
>   
> +static void intel_psr2_sel_fetch_pipe_alignment(const struct intel_crtc_state *crtc_state,
> +						struct drm_rect *pipe_clip)
> +{
> +	const u16 y_alignment = crtc_state->su_y_granularity;
> +
> +	pipe_clip->y1 -= pipe_clip->y1 % y_alignment;
> +	if (pipe_clip->y2 % y_alignment)
> +		pipe_clip->y2 = ((pipe_clip->y2 / y_alignment) + 1) * y_alignment;
> +}
> +
>   int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
>   				struct intel_crtc *crtc)
>   {
> @@ -1540,10 +1587,7 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
>   	if (full_update)
>   		goto skip_sel_fetch_set_loop;
>   
> -	/* It must be aligned to 4 lines */
> -	pipe_clip.y1 -= pipe_clip.y1 % 4;
> -	if (pipe_clip.y2 % 4)
> -		pipe_clip.y2 = ((pipe_clip.y2 / 4) + 1) * 4;
> +	intel_psr2_sel_fetch_pipe_alignment(crtc_state, &pipe_clip);
>   
>   	/*
>   	 * Now that we have the pipe damaged area check if it intersect with
>
diff mbox series

Patch

diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index 15e91a99c8b9a..f89152ca52a20 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -1041,6 +1041,7 @@  struct intel_crtc_state {
 	bool has_psr2;
 	bool enable_psr2_sel_fetch;
 	u32 dc3co_exitline;
+	u16 su_y_granularity;
 
 	/*
 	 * Frequence the dpll for the port should run at. Differs from the
@@ -1498,7 +1499,8 @@  struct intel_psr {
 	ktime_t last_exit;
 	bool sink_not_reliable;
 	bool irq_aux_error;
-	u16 su_x_granularity;
+	u16 su_w_granularity;
+	u16 su_y_granularity;
 	u32 dc3co_exitline;
 	u32 dc3co_exit_delay;
 	struct delayed_work dc3co_work;
diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c
index 77865cf6641f8..fde30f937504e 100644
--- a/drivers/gpu/drm/i915/display/intel_psr.c
+++ b/drivers/gpu/drm/i915/display/intel_psr.c
@@ -265,32 +265,44 @@  static u8 intel_dp_get_sink_sync_latency(struct intel_dp *intel_dp)
 	return val;
 }
 
-static u16 intel_dp_get_su_x_granulartiy(struct intel_dp *intel_dp)
+static void intel_dp_get_su_granularity(struct intel_dp *intel_dp)
 {
 	struct drm_i915_private *i915 = dp_to_i915(intel_dp);
-	u16 val;
 	ssize_t r;
+	u16 w;
+	u8 y;
+
+	/* If sink don't have specific granularity requirements set legacy ones */
+	if (!(intel_dp->psr_dpcd[1] & DP_PSR2_SU_GRANULARITY_REQUIRED)) {
+		/* As PSR2 HW sends full lines, we do not care about x granularity */
+		w = 4;
+		y = 4;
+		goto exit;
+	}
 
-	/*
-	 * Returning the default X granularity if granularity not required or
-	 * if DPCD read fails
-	 */
-	if (!(intel_dp->psr_dpcd[1] & DP_PSR2_SU_GRANULARITY_REQUIRED))
-		return 4;
-
-	r = drm_dp_dpcd_read(&intel_dp->aux, DP_PSR2_SU_X_GRANULARITY, &val, 2);
+	r = drm_dp_dpcd_read(&intel_dp->aux, DP_PSR2_SU_X_GRANULARITY, &w, 2);
 	if (r != 2)
 		drm_dbg_kms(&i915->drm,
 			    "Unable to read DP_PSR2_SU_X_GRANULARITY\n");
-
 	/*
 	 * Spec says that if the value read is 0 the default granularity should
 	 * be used instead.
 	 */
-	if (r != 2 || val == 0)
-		val = 4;
+	if (r != 2 || w == 0)
+		w = 4;
 
-	return val;
+	r = drm_dp_dpcd_read(&intel_dp->aux, DP_PSR2_SU_Y_GRANULARITY, &y, 1);
+	if (r != 1) {
+		drm_dbg_kms(&i915->drm,
+			    "Unable to read DP_PSR2_SU_Y_GRANULARITY\n");
+		y = 4;
+	}
+	if (y == 0)
+		y = 1;
+
+exit:
+	intel_dp->psr.su_w_granularity = w;
+	intel_dp->psr.su_y_granularity = y;
 }
 
 void intel_psr_init_dpcd(struct intel_dp *intel_dp)
@@ -346,8 +358,7 @@  void intel_psr_init_dpcd(struct intel_dp *intel_dp)
 		if (intel_dp->psr.sink_psr2_support) {
 			intel_dp->psr.colorimetry_support =
 				intel_dp_get_colorimetry_status(intel_dp);
-			intel_dp->psr.su_x_granularity =
-				intel_dp_get_su_x_granulartiy(intel_dp);
+			intel_dp_get_su_granularity(intel_dp);
 		}
 	}
 }
@@ -742,6 +753,40 @@  static bool intel_psr2_sel_fetch_config_valid(struct intel_dp *intel_dp,
 	return crtc_state->enable_psr2_sel_fetch = true;
 }
 
+static bool psr2_granularity_check(struct intel_dp *intel_dp,
+				   struct intel_crtc_state *crtc_state)
+{
+	const int crtc_hdisplay = crtc_state->hw.adjusted_mode.crtc_hdisplay;
+	const int crtc_vdisplay = crtc_state->hw.adjusted_mode.crtc_vdisplay;
+	u16 y_granularity = 0;
+
+	/* PSR2 HW only send full lines so we only need to validate the width */
+	if (crtc_hdisplay % intel_dp->psr.su_w_granularity)
+		return false;
+
+	if (crtc_vdisplay % intel_dp->psr.su_y_granularity)
+		return false;
+
+	/* HW tracking is only aligned to 4 lines */
+	if (!crtc_state->enable_psr2_sel_fetch)
+		return intel_dp->psr.su_y_granularity == 4;
+
+	/*
+	 * For SW tracking we can adjust the y to match sink requirement if
+	 * multiple of 4
+	 */
+	if (intel_dp->psr.su_y_granularity <= 2)
+		y_granularity = 4;
+	else if ((intel_dp->psr.su_y_granularity % 4) == 0)
+		y_granularity = intel_dp->psr.su_y_granularity;
+
+	if (y_granularity == 0 || crtc_vdisplay % y_granularity)
+		return false;
+
+	crtc_state->su_y_granularity = y_granularity;
+	return true;
+}
+
 static bool intel_psr2_config_valid(struct intel_dp *intel_dp,
 				    struct intel_crtc_state *crtc_state)
 {
@@ -824,19 +869,6 @@  static bool intel_psr2_config_valid(struct intel_dp *intel_dp,
 		return false;
 	}
 
-	/*
-	 * HW sends SU blocks of size four scan lines, which means the starting
-	 * X coordinate and Y granularity requirements will always be met. We
-	 * only need to validate the SU block width is a multiple of
-	 * x granularity.
-	 */
-	if (crtc_hdisplay % intel_dp->psr.su_x_granularity) {
-		drm_dbg_kms(&dev_priv->drm,
-			    "PSR2 not enabled, hdisplay(%d) not multiple of %d\n",
-			    crtc_hdisplay, intel_dp->psr.su_x_granularity);
-		return false;
-	}
-
 	if (HAS_PSR2_SEL_FETCH(dev_priv)) {
 		if (!intel_psr2_sel_fetch_config_valid(intel_dp, crtc_state) &&
 		    !HAS_PSR_HW_TRACKING(dev_priv)) {
@@ -853,6 +885,11 @@  static bool intel_psr2_config_valid(struct intel_dp *intel_dp,
 		return false;
 	}
 
+	if (!psr2_granularity_check(intel_dp, crtc_state)) {
+		drm_dbg_kms(&dev_priv->drm, "PSR2 not enabled, SU granularity not compatible\n");
+		return false;
+	}
+
 	if (!crtc_state->enable_psr2_sel_fetch &&
 	    (crtc_hdisplay > psr_max_h || crtc_vdisplay > psr_max_v)) {
 		drm_dbg_kms(&dev_priv->drm,
@@ -1432,6 +1469,16 @@  static void clip_area_update(struct drm_rect *overlap_damage_area,
 		overlap_damage_area->y2 = damage_area->y2;
 }
 
+static void intel_psr2_sel_fetch_pipe_alignment(const struct intel_crtc_state *crtc_state,
+						struct drm_rect *pipe_clip)
+{
+	const u16 y_alignment = crtc_state->su_y_granularity;
+
+	pipe_clip->y1 -= pipe_clip->y1 % y_alignment;
+	if (pipe_clip->y2 % y_alignment)
+		pipe_clip->y2 = ((pipe_clip->y2 / y_alignment) + 1) * y_alignment;
+}
+
 int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
 				struct intel_crtc *crtc)
 {
@@ -1540,10 +1587,7 @@  int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
 	if (full_update)
 		goto skip_sel_fetch_set_loop;
 
-	/* It must be aligned to 4 lines */
-	pipe_clip.y1 -= pipe_clip.y1 % 4;
-	if (pipe_clip.y2 % 4)
-		pipe_clip.y2 = ((pipe_clip.y2 / 4) + 1) * 4;
+	intel_psr2_sel_fetch_pipe_alignment(crtc_state, &pipe_clip);
 
 	/*
 	 * Now that we have the pipe damaged area check if it intersect with