Currently we are storing only one set of granularity information for panels supporting both PSR and Panel Replay. As panel is informing own granularities for PSR and Panel Replay they could be different. Let's use own granularities for PSR and Panel Replay instead of having only one set for both. This is done by having intel_connector::psr_caps and panel_replay_caps both containing granularity information.
Also remove complexity of sharing granularity read between PSR and Panel Replay. v2: - use __le16 for two byte values in dpcd - use sizeof instead of hardcoded size in reading dpcd - drop unnecessarily passing intel_dp pointer Signed-off-by: Jouni Högander <[email protected]> Reviewed-by: Imre Deak <[email protected]> --- drivers/gpu/drm/i915/display/intel_dp.c | 4 +- drivers/gpu/drm/i915/display/intel_psr.c | 147 +++++++++++------------ drivers/gpu/drm/i915/display/intel_psr.h | 2 +- 3 files changed, 72 insertions(+), 81 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 7df0e5e13688d..dcceb0ae2a56d 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -4562,7 +4562,7 @@ intel_edp_init_dpcd(struct intel_dp *intel_dp, struct intel_connector *connector * This has to be called after intel_dp->edp_dpcd is filled, PSR checks * for SET_POWER_CAPABLE bit in intel_dp->edp_dpcd[1] */ - intel_psr_init_dpcd(intel_dp); + intel_psr_init_dpcd(intel_dp, connector); intel_edp_set_sink_rates(intel_dp); intel_dp_set_max_sink_lane_count(intel_dp); @@ -6074,7 +6074,7 @@ intel_dp_detect(struct drm_connector *_connector, connector->base.epoch_counter++; if (!intel_dp_is_edp(intel_dp)) - intel_psr_init_dpcd(intel_dp); + intel_psr_init_dpcd(intel_dp, connector); intel_dp_detect_dsc_caps(intel_dp, connector); diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 15ef3b6caad6e..5f8df67f9993e 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -494,82 +494,37 @@ static u8 intel_dp_get_sink_sync_latency(struct intel_dp *intel_dp) return val; } -static u8 intel_dp_get_su_capability(struct intel_dp *intel_dp) -{ - u8 su_capability = 0; - - if (intel_dp->psr.sink_panel_replay_su_support) { - if (drm_dp_dpcd_read_byte(&intel_dp->aux, - DP_PANEL_REPLAY_CAP_CAPABILITY, - &su_capability) < 0) - return 0; - } else { - su_capability = intel_dp->psr_dpcd[1]; - } - - return su_capability; -} - -static unsigned int -intel_dp_get_su_x_granularity_offset(struct intel_dp *intel_dp) -{ - return intel_dp->psr.sink_panel_replay_su_support ? - DP_PANEL_REPLAY_CAP_X_GRANULARITY : - DP_PSR2_SU_X_GRANULARITY; -} - -static unsigned int -intel_dp_get_su_y_granularity_offset(struct intel_dp *intel_dp) -{ - return intel_dp->psr.sink_panel_replay_su_support ? - DP_PANEL_REPLAY_CAP_Y_GRANULARITY : - DP_PSR2_SU_Y_GRANULARITY; -} - -/* - * Note: Bits related to granularity are same in panel replay and psr - * registers. Rely on PSR definitions on these "common" bits. - */ -static void intel_dp_get_su_granularity(struct intel_dp *intel_dp) +static void _psr_compute_su_granularity(struct intel_dp *intel_dp, + struct intel_connector *connector) { struct intel_display *display = to_intel_display(intel_dp); ssize_t r; - u16 w; + __le16 w; u8 y; - /* - * TODO: Do we need to take into account panel supporting both PSR and - * Panel replay? - */ - /* * If sink don't have specific granularity requirements set legacy * ones. */ - if (!(intel_dp_get_su_capability(intel_dp) & - DP_PSR2_SU_GRANULARITY_REQUIRED)) { + 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; } - r = drm_dp_dpcd_read(&intel_dp->aux, - intel_dp_get_su_x_granularity_offset(intel_dp), - &w, 2); - if (r != 2) + r = drm_dp_dpcd_read(&intel_dp->aux, DP_PSR2_SU_X_GRANULARITY, &w, sizeof(w)); + if (r != sizeof(w)) drm_dbg_kms(display->drm, "Unable to read selective update x granularity\n"); /* * Spec says that if the value read is 0 the default granularity should * be used instead. */ - if (r != 2 || w == 0) + if (r != sizeof(w) || w == 0) w = 4; - r = drm_dp_dpcd_read(&intel_dp->aux, - intel_dp_get_su_y_granularity_offset(intel_dp), - &y, 1); + r = drm_dp_dpcd_read(&intel_dp->aux, DP_PSR2_SU_Y_GRANULARITY, &y, 1); if (r != 1) { drm_dbg_kms(display->drm, "Unable to read selective update y granularity\n"); @@ -579,8 +534,8 @@ static void intel_dp_get_su_granularity(struct intel_dp *intel_dp) y = 1; exit: - intel_dp->psr.su_w_granularity = w; - intel_dp->psr.su_y_granularity = y; + connector->dp.psr_caps.su_w_granularity = le16_to_cpu(w); + connector->dp.psr_caps.su_y_granularity = y; } static enum intel_panel_replay_dsc_support @@ -621,7 +576,32 @@ static const char *panel_replay_dsc_support_str(enum intel_panel_replay_dsc_supp }; } -static void _panel_replay_init_dpcd(struct intel_dp *intel_dp) +static void _panel_replay_compute_su_granularity(struct intel_dp *intel_dp, + struct intel_connector *connector) +{ + u16 w; + u8 y; + + if (!(intel_dp->pr_dpcd[INTEL_PR_DPCD_INDEX(DP_PANEL_REPLAY_CAP_CAPABILITY)] & + DP_PANEL_REPLAY_SU_GRANULARITY_REQUIRED)) { + w = 4; + y = 4; + goto exit; + } + + /* + * Spec says that if the value read is 0 the default granularity should + * be used instead. + */ + w = le16_to_cpu(*(__le16 *)&intel_dp->pr_dpcd[INTEL_PR_DPCD_INDEX(DP_PANEL_REPLAY_CAP_X_GRANULARITY)]) ? : 4; + y = intel_dp->pr_dpcd[INTEL_PR_DPCD_INDEX(DP_PANEL_REPLAY_CAP_Y_GRANULARITY)] ? : 1; + +exit: + connector->dp.panel_replay_caps.su_w_granularity = w; + connector->dp.panel_replay_caps.su_y_granularity = y; +} + +static void _panel_replay_init_dpcd(struct intel_dp *intel_dp, struct intel_connector *connector) { struct intel_display *display = to_intel_display(intel_dp); int ret; @@ -657,9 +637,12 @@ static void _panel_replay_init_dpcd(struct intel_dp *intel_dp) intel_dp->psr.sink_panel_replay_support = true; if (intel_dp->pr_dpcd[INTEL_PR_DPCD_INDEX(DP_PANEL_REPLAY_CAP_SUPPORT)] & - DP_PANEL_REPLAY_SU_SUPPORT) + DP_PANEL_REPLAY_SU_SUPPORT) { intel_dp->psr.sink_panel_replay_su_support = true; + _panel_replay_compute_su_granularity(intel_dp, connector); + } + intel_dp->psr.sink_panel_replay_dsc_support = compute_pr_dsc_support(intel_dp); drm_dbg_kms(display->drm, @@ -669,7 +652,7 @@ static void _panel_replay_init_dpcd(struct intel_dp *intel_dp) panel_replay_dsc_support_str(intel_dp->psr.sink_panel_replay_dsc_support)); } -static void _psr_init_dpcd(struct intel_dp *intel_dp) +static void _psr_init_dpcd(struct intel_dp *intel_dp, struct intel_connector *connector) { struct intel_display *display = to_intel_display(intel_dp); int ret; @@ -722,17 +705,16 @@ static void _psr_init_dpcd(struct intel_dp *intel_dp) drm_dbg_kms(display->drm, "PSR2 %ssupported\n", intel_dp->psr.sink_psr2_support ? "" : "not "); } + + if (intel_dp->psr.sink_psr2_support) + _psr_compute_su_granularity(intel_dp, connector); } -void intel_psr_init_dpcd(struct intel_dp *intel_dp) +void intel_psr_init_dpcd(struct intel_dp *intel_dp, struct intel_connector *connector) { - _psr_init_dpcd(intel_dp); - - _panel_replay_init_dpcd(intel_dp); + _psr_init_dpcd(intel_dp, connector); - if (intel_dp->psr.sink_psr2_support || - intel_dp->psr.sink_panel_replay_su_support) - intel_dp_get_su_granularity(intel_dp); + _panel_replay_init_dpcd(intel_dp, connector); } static void hsw_psr_setup_aux(struct intel_dp *intel_dp) @@ -1304,25 +1286,32 @@ 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) +static bool psr2_granularity_check(struct intel_crtc_state *crtc_state, + struct intel_connector *connector) { + struct intel_dp *intel_dp = intel_attached_dp(connector); struct intel_display *display = to_intel_display(intel_dp); const struct drm_dsc_config *vdsc_cfg = &crtc_state->dsc.config; 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; + u16 sink_y_granularity = crtc_state->has_panel_replay ? + connector->dp.panel_replay_caps.su_y_granularity : + connector->dp.psr_caps.su_y_granularity; + u16 sink_w_granularity = crtc_state->has_panel_replay ? + connector->dp.panel_replay_caps.su_w_granularity : + connector->dp.psr_caps.su_w_granularity; /* PSR2 HW only send full lines so we only need to validate the width */ - if (crtc_hdisplay % intel_dp->psr.su_w_granularity) + if (crtc_hdisplay % sink_w_granularity) return false; - if (crtc_vdisplay % intel_dp->psr.su_y_granularity) + if (crtc_vdisplay % sink_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; + return sink_y_granularity == 4; /* * adl_p and mtl platforms have 1 line granularity. @@ -1330,11 +1319,11 @@ static bool psr2_granularity_check(struct intel_dp *intel_dp, * to match sink requirement if multiple of 4. */ if (display->platform.alderlake_p || DISPLAY_VER(display) >= 14) - y_granularity = intel_dp->psr.su_y_granularity; - else if (intel_dp->psr.su_y_granularity <= 2) + y_granularity = sink_y_granularity; + else if (sink_y_granularity <= 2) y_granularity = 4; - else if ((intel_dp->psr.su_y_granularity % 4) == 0) - y_granularity = intel_dp->psr.su_y_granularity; + else if ((sink_y_granularity % 4) == 0) + y_granularity = sink_y_granularity; if (y_granularity == 0 || crtc_vdisplay % y_granularity) return false; @@ -1621,9 +1610,11 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp, return true; } -static bool intel_sel_update_config_valid(struct intel_dp *intel_dp, - struct intel_crtc_state *crtc_state) +static bool intel_sel_update_config_valid(struct intel_crtc_state *crtc_state, + struct drm_connector_state *conn_state) { + struct intel_connector *connector = to_intel_connector(conn_state->connector); + struct intel_dp *intel_dp = intel_attached_dp(connector); struct intel_display *display = to_intel_display(intel_dp); if (HAS_PSR2_SEL_FETCH(display) && @@ -1671,7 +1662,7 @@ static bool intel_sel_update_config_valid(struct intel_dp *intel_dp, goto unsupported; } - if (!psr2_granularity_check(intel_dp, crtc_state)) { + if (!psr2_granularity_check(crtc_state, connector)) { drm_dbg_kms(display->drm, "Selective update not enabled, SU granularity not compatible\n"); goto unsupported; @@ -1866,7 +1857,7 @@ void intel_psr_compute_config(struct intel_dp *intel_dp, if (!crtc_state->has_psr) return; - crtc_state->has_sel_update = intel_sel_update_config_valid(intel_dp, crtc_state); + crtc_state->has_sel_update = intel_sel_update_config_valid(crtc_state, conn_state); } void intel_psr_get_config(struct intel_encoder *encoder, diff --git a/drivers/gpu/drm/i915/display/intel_psr.h b/drivers/gpu/drm/i915/display/intel_psr.h index 024ee4c309852..b41dc4d44ff29 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.h +++ b/drivers/gpu/drm/i915/display/intel_psr.h @@ -28,7 +28,7 @@ struct intel_plane_state; bool intel_encoder_can_psr(struct intel_encoder *encoder); bool intel_psr_needs_aux_io_power(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state); -void intel_psr_init_dpcd(struct intel_dp *intel_dp); +void intel_psr_init_dpcd(struct intel_dp *intel_dp, struct intel_connector *connector); void intel_psr_panel_replay_enable_sink(struct intel_dp *intel_dp); void intel_psr_pre_plane_update(struct intel_atomic_state *state, struct intel_crtc *crtc); -- 2.43.0
