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 |
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 --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
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(-)