drm/i915/display: Only keep PSR enabled if there is active planes

PSR always had a requirement to only be enabled if there is active
planes but not following that never caused any issues.
But that changes in Alderlake-P, leaving PSR enabled without
active planes causes transcoder/port underruns.

Similar behavior was fixed during the pipe disable sequence by
commit 84030adb ("drm/i915/display: Disable audio, DRRS and PSR before planes").

intel_dp_compute_psr_vsc_sdp() had to move from
intel_psr_enable_locked() to intel_psr_compute_config() because we
need to be able to disable/enable PSR from atomic states without
connector and encoder state.
Reviewed-by: default avatarGwan-gyeong Mun <gwan-gyeong.mun@intel.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
Signed-off-by: default avatarJosé Roberto de Souza <jose.souza@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20210922215242.66683-3-jose.souza@intel.com
parent 73262db6
...@@ -3034,7 +3034,6 @@ static void intel_enable_ddi_dp(struct intel_atomic_state *state, ...@@ -3034,7 +3034,6 @@ static void intel_enable_ddi_dp(struct intel_atomic_state *state,
intel_dp_stop_link_train(intel_dp, crtc_state); intel_dp_stop_link_train(intel_dp, crtc_state);
intel_edp_backlight_on(crtc_state, conn_state); intel_edp_backlight_on(crtc_state, conn_state);
intel_psr_enable(intel_dp, crtc_state, conn_state);
if (!dig_port->lspcon.active || dig_port->dp.has_hdmi_sink) if (!dig_port->lspcon.active || dig_port->dp.has_hdmi_sink)
intel_dp_set_infoframes(encoder, true, crtc_state, conn_state); intel_dp_set_infoframes(encoder, true, crtc_state, conn_state);
...@@ -3255,7 +3254,6 @@ static void intel_ddi_update_pipe_dp(struct intel_atomic_state *state, ...@@ -3255,7 +3254,6 @@ static void intel_ddi_update_pipe_dp(struct intel_atomic_state *state,
intel_ddi_set_dp_msa(crtc_state, conn_state); intel_ddi_set_dp_msa(crtc_state, conn_state);
intel_psr_update(intel_dp, crtc_state, conn_state);
intel_dp_set_infoframes(encoder, true, crtc_state, conn_state); intel_dp_set_infoframes(encoder, true, crtc_state, conn_state);
intel_drrs_update(intel_dp, crtc_state); intel_drrs_update(intel_dp, crtc_state);
......
...@@ -8098,10 +8098,12 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, ...@@ -8098,10 +8098,12 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
if (bp_gamma) if (bp_gamma)
PIPE_CONF_CHECK_COLOR_LUT(gamma_mode, hw.gamma_lut, bp_gamma); PIPE_CONF_CHECK_COLOR_LUT(gamma_mode, hw.gamma_lut, bp_gamma);
PIPE_CONF_CHECK_BOOL(has_psr); if (current_config->active_planes) {
PIPE_CONF_CHECK_BOOL(has_psr2); PIPE_CONF_CHECK_BOOL(has_psr);
PIPE_CONF_CHECK_BOOL(enable_psr2_sel_fetch); PIPE_CONF_CHECK_BOOL(has_psr2);
PIPE_CONF_CHECK_I(dc3co_exitline); PIPE_CONF_CHECK_BOOL(enable_psr2_sel_fetch);
PIPE_CONF_CHECK_I(dc3co_exitline);
}
} }
PIPE_CONF_CHECK_BOOL(double_wide); PIPE_CONF_CHECK_BOOL(double_wide);
...@@ -8158,7 +8160,7 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, ...@@ -8158,7 +8160,7 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
PIPE_CONF_CHECK_I(min_voltage_level); PIPE_CONF_CHECK_I(min_voltage_level);
} }
if (fastset && (current_config->has_psr || pipe_config->has_psr)) if (current_config->has_psr || pipe_config->has_psr)
PIPE_CONF_CHECK_X_WITH_MASK(infoframes.enable, PIPE_CONF_CHECK_X_WITH_MASK(infoframes.enable,
~intel_hdmi_infoframe_enable(DP_SDP_VSC)); ~intel_hdmi_infoframe_enable(DP_SDP_VSC));
else else
...@@ -10212,6 +10214,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) ...@@ -10212,6 +10214,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
intel_encoders_update_prepare(state); intel_encoders_update_prepare(state);
intel_dbuf_pre_plane_update(state); intel_dbuf_pre_plane_update(state);
intel_psr_pre_plane_update(state);
for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) {
if (new_crtc_state->uapi.async_flip) if (new_crtc_state->uapi.async_flip)
...@@ -10275,6 +10278,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) ...@@ -10275,6 +10278,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
} }
intel_dbuf_post_plane_update(state); intel_dbuf_post_plane_update(state);
intel_psr_post_plane_update(state);
for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
intel_post_plane_update(state, crtc); intel_post_plane_update(state, crtc);
......
...@@ -1054,12 +1054,14 @@ struct intel_crtc_state { ...@@ -1054,12 +1054,14 @@ struct intel_crtc_state {
struct intel_link_m_n dp_m2_n2; struct intel_link_m_n dp_m2_n2;
bool has_drrs; bool has_drrs;
/* PSR is supported but might not be enabled due the lack of enabled planes */
bool has_psr; bool has_psr;
bool has_psr2; bool has_psr2;
bool enable_psr2_sel_fetch; bool enable_psr2_sel_fetch;
bool req_psr2_sdp_prior_scanline; bool req_psr2_sdp_prior_scanline;
u32 dc3co_exitline; u32 dc3co_exitline;
u16 su_y_granularity; u16 su_y_granularity;
struct drm_dp_vsc_sdp psr_vsc;
/* /*
* Frequence the dpll for the port should run at. Differs from the * Frequence the dpll for the port should run at. Differs from the
...@@ -1523,7 +1525,6 @@ struct intel_psr { ...@@ -1523,7 +1525,6 @@ struct intel_psr {
u32 dc3co_exitline; u32 dc3co_exitline;
u32 dc3co_exit_delay; u32 dc3co_exit_delay;
struct delayed_work dc3co_work; struct delayed_work dc3co_work;
struct drm_dp_vsc_sdp vsc;
}; };
struct intel_dp { struct intel_dp {
......
...@@ -1674,7 +1674,7 @@ void intel_dp_compute_psr_vsc_sdp(struct intel_dp *intel_dp, ...@@ -1674,7 +1674,7 @@ void intel_dp_compute_psr_vsc_sdp(struct intel_dp *intel_dp,
{ {
vsc->sdp_type = DP_SDP_VSC; vsc->sdp_type = DP_SDP_VSC;
if (intel_dp->psr.psr2_enabled) { if (crtc_state->has_psr2) {
if (intel_dp->psr.colorimetry_support && if (intel_dp->psr.colorimetry_support &&
intel_dp_needs_vsc_sdp(crtc_state, conn_state)) { intel_dp_needs_vsc_sdp(crtc_state, conn_state)) {
/* [PSR2, +Colorimetry] */ /* [PSR2, +Colorimetry] */
...@@ -1828,7 +1828,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, ...@@ -1828,7 +1828,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
g4x_dp_set_clock(encoder, pipe_config); g4x_dp_set_clock(encoder, pipe_config);
intel_vrr_compute_config(pipe_config, conn_state); intel_vrr_compute_config(pipe_config, conn_state);
intel_psr_compute_config(intel_dp, pipe_config); intel_psr_compute_config(intel_dp, pipe_config, conn_state);
intel_drrs_compute_config(intel_dp, pipe_config, output_bpp, intel_drrs_compute_config(intel_dp, pipe_config, output_bpp,
constant_n); constant_n);
intel_dp_compute_vsc_sdp(intel_dp, pipe_config, conn_state); intel_dp_compute_vsc_sdp(intel_dp, pipe_config, conn_state);
...@@ -2888,7 +2888,7 @@ static void intel_write_dp_sdp(struct intel_encoder *encoder, ...@@ -2888,7 +2888,7 @@ static void intel_write_dp_sdp(struct intel_encoder *encoder,
void intel_write_dp_vsc_sdp(struct intel_encoder *encoder, void intel_write_dp_vsc_sdp(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state, const struct intel_crtc_state *crtc_state,
struct drm_dp_vsc_sdp *vsc) const struct drm_dp_vsc_sdp *vsc)
{ {
struct intel_digital_port *dig_port = enc_to_dig_port(encoder); struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
......
...@@ -88,7 +88,7 @@ void intel_dp_compute_psr_vsc_sdp(struct intel_dp *intel_dp, ...@@ -88,7 +88,7 @@ void intel_dp_compute_psr_vsc_sdp(struct intel_dp *intel_dp,
struct drm_dp_vsc_sdp *vsc); struct drm_dp_vsc_sdp *vsc);
void intel_write_dp_vsc_sdp(struct intel_encoder *encoder, void intel_write_dp_vsc_sdp(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state, const struct intel_crtc_state *crtc_state,
struct drm_dp_vsc_sdp *vsc); const struct drm_dp_vsc_sdp *vsc);
void intel_dp_set_infoframes(struct intel_encoder *encoder, bool enable, void intel_dp_set_infoframes(struct intel_encoder *encoder, bool enable,
const struct intel_crtc_state *crtc_state, const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state); const struct drm_connector_state *conn_state);
......
...@@ -950,7 +950,8 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp, ...@@ -950,7 +950,8 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp,
} }
void intel_psr_compute_config(struct intel_dp *intel_dp, void intel_psr_compute_config(struct intel_dp *intel_dp,
struct intel_crtc_state *crtc_state) struct intel_crtc_state *crtc_state,
struct drm_connector_state *conn_state)
{ {
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
const struct drm_display_mode *adjusted_mode = const struct drm_display_mode *adjusted_mode =
...@@ -1002,7 +1003,10 @@ void intel_psr_compute_config(struct intel_dp *intel_dp, ...@@ -1002,7 +1003,10 @@ void intel_psr_compute_config(struct intel_dp *intel_dp,
crtc_state->has_psr = true; crtc_state->has_psr = true;
crtc_state->has_psr2 = intel_psr2_config_valid(intel_dp, crtc_state); crtc_state->has_psr2 = intel_psr2_config_valid(intel_dp, crtc_state);
crtc_state->infoframes.enable |= intel_hdmi_infoframe_enable(DP_SDP_VSC); crtc_state->infoframes.enable |= intel_hdmi_infoframe_enable(DP_SDP_VSC);
intel_dp_compute_psr_vsc_sdp(intel_dp, crtc_state, conn_state,
&crtc_state->psr_vsc);
} }
void intel_psr_get_config(struct intel_encoder *encoder, void intel_psr_get_config(struct intel_encoder *encoder,
...@@ -1182,8 +1186,7 @@ static bool psr_interrupt_error_check(struct intel_dp *intel_dp) ...@@ -1182,8 +1186,7 @@ static bool psr_interrupt_error_check(struct intel_dp *intel_dp)
} }
static void intel_psr_enable_locked(struct intel_dp *intel_dp, static void intel_psr_enable_locked(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state, const struct intel_crtc_state *crtc_state)
const struct drm_connector_state *conn_state)
{ {
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
...@@ -1210,9 +1213,7 @@ static void intel_psr_enable_locked(struct intel_dp *intel_dp, ...@@ -1210,9 +1213,7 @@ static void intel_psr_enable_locked(struct intel_dp *intel_dp,
drm_dbg_kms(&dev_priv->drm, "Enabling PSR%s\n", drm_dbg_kms(&dev_priv->drm, "Enabling PSR%s\n",
intel_dp->psr.psr2_enabled ? "2" : "1"); intel_dp->psr.psr2_enabled ? "2" : "1");
intel_dp_compute_psr_vsc_sdp(intel_dp, crtc_state, conn_state, intel_write_dp_vsc_sdp(encoder, crtc_state, &crtc_state->psr_vsc);
&intel_dp->psr.vsc);
intel_write_dp_vsc_sdp(encoder, crtc_state, &intel_dp->psr.vsc);
intel_snps_phy_update_psr_power_state(dev_priv, phy, true); intel_snps_phy_update_psr_power_state(dev_priv, phy, true);
intel_psr_enable_sink(intel_dp); intel_psr_enable_sink(intel_dp);
intel_psr_enable_source(intel_dp); intel_psr_enable_source(intel_dp);
...@@ -1222,33 +1223,6 @@ static void intel_psr_enable_locked(struct intel_dp *intel_dp, ...@@ -1222,33 +1223,6 @@ static void intel_psr_enable_locked(struct intel_dp *intel_dp,
intel_psr_activate(intel_dp); intel_psr_activate(intel_dp);
} }
/**
* intel_psr_enable - Enable PSR
* @intel_dp: Intel DP
* @crtc_state: new CRTC state
* @conn_state: new CONNECTOR state
*
* This function can only be called after the pipe is fully trained and enabled.
*/
void intel_psr_enable(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
if (!CAN_PSR(intel_dp))
return;
if (!crtc_state->has_psr)
return;
drm_WARN_ON(&dev_priv->drm, dev_priv->drrs.dp);
mutex_lock(&intel_dp->psr.lock);
intel_psr_enable_locked(intel_dp, crtc_state, conn_state);
mutex_unlock(&intel_dp->psr.lock);
}
static void intel_psr_exit(struct intel_dp *intel_dp) static void intel_psr_exit(struct intel_dp *intel_dp)
{ {
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
...@@ -1734,48 +1708,92 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, ...@@ -1734,48 +1708,92 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
return 0; return 0;
} }
/** static void _intel_psr_pre_plane_update(const struct intel_atomic_state *state,
* intel_psr_update - Update PSR state const struct intel_crtc_state *crtc_state)
* @intel_dp: Intel DP
* @crtc_state: new CRTC state
* @conn_state: new CONNECTOR state
*
* This functions will update PSR states, disabling, enabling or switching PSR
* version when executing fastsets. For full modeset, intel_psr_disable() and
* intel_psr_enable() should be called instead.
*/
void intel_psr_update(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state)
{ {
struct intel_psr *psr = &intel_dp->psr; struct intel_encoder *encoder;
bool enable, psr2_enable;
if (!CAN_PSR(intel_dp)) for_each_intel_encoder_mask_with_psr(state->base.dev, encoder,
crtc_state->uapi.encoder_mask) {
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
struct intel_psr *psr = &intel_dp->psr;
bool needs_to_disable = false;
mutex_lock(&psr->lock);
/*
* Reasons to disable:
* - PSR disabled in new state
* - All planes will go inactive
* - Changing between PSR versions
*/
needs_to_disable |= !crtc_state->has_psr;
needs_to_disable |= !crtc_state->active_planes;
needs_to_disable |= crtc_state->has_psr2 != psr->psr2_enabled;
if (psr->enabled && needs_to_disable)
intel_psr_disable_locked(intel_dp);
mutex_unlock(&psr->lock);
}
}
void intel_psr_pre_plane_update(const struct intel_atomic_state *state)
{
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
struct intel_crtc_state *crtc_state;
struct intel_crtc *crtc;
int i;
if (!HAS_PSR(dev_priv))
return; return;
mutex_lock(&intel_dp->psr.lock); for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i)
_intel_psr_pre_plane_update(state, crtc_state);
}
enable = crtc_state->has_psr; static void _intel_psr_post_plane_update(const struct intel_atomic_state *state,
psr2_enable = crtc_state->has_psr2; const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
struct intel_encoder *encoder;
if (!crtc_state->has_psr)
return;
for_each_intel_encoder_mask_with_psr(state->base.dev, encoder,
crtc_state->uapi.encoder_mask) {
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
struct intel_psr *psr = &intel_dp->psr;
mutex_lock(&psr->lock);
drm_WARN_ON(&dev_priv->drm, psr->enabled && !crtc_state->active_planes);
/* Only enable if there is active planes */
if (!psr->enabled && crtc_state->active_planes)
intel_psr_enable_locked(intel_dp, crtc_state);
if (enable == psr->enabled && psr2_enable == psr->psr2_enabled &&
crtc_state->enable_psr2_sel_fetch == psr->psr2_sel_fetch_enabled) {
/* Force a PSR exit when enabling CRC to avoid CRC timeouts */ /* Force a PSR exit when enabling CRC to avoid CRC timeouts */
if (crtc_state->crc_enabled && psr->enabled) if (crtc_state->crc_enabled && psr->enabled)
psr_force_hw_tracking_exit(intel_dp); psr_force_hw_tracking_exit(intel_dp);
goto unlock; mutex_unlock(&psr->lock);
} }
}
if (psr->enabled) void intel_psr_post_plane_update(const struct intel_atomic_state *state)
intel_psr_disable_locked(intel_dp); {
struct drm_i915_private *dev_priv = to_i915(state->base.dev);
struct intel_crtc_state *crtc_state;
struct intel_crtc *crtc;
int i;
if (enable) if (!HAS_PSR(dev_priv))
intel_psr_enable_locked(intel_dp, crtc_state, conn_state); return;
unlock: for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i)
mutex_unlock(&intel_dp->psr.lock); _intel_psr_post_plane_update(state, crtc_state);
} }
/** /**
......
...@@ -20,14 +20,10 @@ struct intel_plane; ...@@ -20,14 +20,10 @@ struct intel_plane;
struct intel_encoder; struct intel_encoder;
void intel_psr_init_dpcd(struct intel_dp *intel_dp); void intel_psr_init_dpcd(struct intel_dp *intel_dp);
void intel_psr_enable(struct intel_dp *intel_dp, void intel_psr_pre_plane_update(const struct intel_atomic_state *state);
const struct intel_crtc_state *crtc_state, void intel_psr_post_plane_update(const struct intel_atomic_state *state);
const struct drm_connector_state *conn_state);
void intel_psr_disable(struct intel_dp *intel_dp, void intel_psr_disable(struct intel_dp *intel_dp,
const struct intel_crtc_state *old_crtc_state); const struct intel_crtc_state *old_crtc_state);
void intel_psr_update(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state);
int intel_psr_debug_set(struct intel_dp *intel_dp, u64 value); int intel_psr_debug_set(struct intel_dp *intel_dp, u64 value);
void intel_psr_invalidate(struct drm_i915_private *dev_priv, void intel_psr_invalidate(struct drm_i915_private *dev_priv,
unsigned frontbuffer_bits, unsigned frontbuffer_bits,
...@@ -37,7 +33,8 @@ void intel_psr_flush(struct drm_i915_private *dev_priv, ...@@ -37,7 +33,8 @@ void intel_psr_flush(struct drm_i915_private *dev_priv,
enum fb_op_origin origin); enum fb_op_origin origin);
void intel_psr_init(struct intel_dp *intel_dp); void intel_psr_init(struct intel_dp *intel_dp);
void intel_psr_compute_config(struct intel_dp *intel_dp, void intel_psr_compute_config(struct intel_dp *intel_dp,
struct intel_crtc_state *crtc_state); struct intel_crtc_state *crtc_state,
struct drm_connector_state *conn_state);
void intel_psr_get_config(struct intel_encoder *encoder, void intel_psr_get_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config); struct intel_crtc_state *pipe_config);
void intel_psr_irq_handler(struct intel_dp *intel_dp, u32 psr_iir); void intel_psr_irq_handler(struct intel_dp *intel_dp, u32 psr_iir);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment