diff mbox series

[v3,2/3] drm/i915/display: Only keep PSR enabled if there is active planes

Message ID 20210921004113.261827-2-jose.souza@intel.com (mailing list archive)
State New, archived
Headers show
Series [v3,1/3] drm/i915/display: Disable frontbuffer rendering when PSR2 selective fetch is enabled | expand

Commit Message

Souza, Jose Sept. 21, 2021, 12:41 a.m. UTC
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 84030adb9e27 ("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.

Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
Signed-off-by: José Roberto de Souza <jose.souza@intel.com>
---
 drivers/gpu/drm/i915/display/intel_ddi.c      |   2 -
 drivers/gpu/drm/i915/display/intel_display.c  |  14 +-
 .../drm/i915/display/intel_display_types.h    |   3 +-
 drivers/gpu/drm/i915/display/intel_dp.c       |   6 +-
 drivers/gpu/drm/i915/display/intel_dp.h       |   2 +-
 drivers/gpu/drm/i915/display/intel_psr.c      | 140 ++++++++++--------
 drivers/gpu/drm/i915/display/intel_psr.h      |  11 +-
 7 files changed, 98 insertions(+), 80 deletions(-)

Comments

Gwan-gyeong Mun Sept. 22, 2021, 4:28 p.m. UTC | #1
Looks good to me.
Reviewed-by: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>

On 9/21/21 3:41 AM, José Roberto de Souza wrote:
> 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 84030adb9e27 ("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.
> 
> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> Cc: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
> Signed-off-by: José Roberto de Souza <jose.souza@intel.com>
> ---
>   drivers/gpu/drm/i915/display/intel_ddi.c      |   2 -
>   drivers/gpu/drm/i915/display/intel_display.c  |  14 +-
>   .../drm/i915/display/intel_display_types.h    |   3 +-
>   drivers/gpu/drm/i915/display/intel_dp.c       |   6 +-
>   drivers/gpu/drm/i915/display/intel_dp.h       |   2 +-
>   drivers/gpu/drm/i915/display/intel_psr.c      | 140 ++++++++++--------
>   drivers/gpu/drm/i915/display/intel_psr.h      |  11 +-
>   7 files changed, 98 insertions(+), 80 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
> index bba0ab99836b1..a4667741d3548 100644
> --- a/drivers/gpu/drm/i915/display/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/display/intel_ddi.c
> @@ -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_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)
>   		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,
>   
>   	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_drrs_update(intel_dp, crtc_state);
>   
> diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
> index f6c0c595f6313..ddcd8d6efc788 100644
> --- a/drivers/gpu/drm/i915/display/intel_display.c
> +++ b/drivers/gpu/drm/i915/display/intel_display.c
> @@ -8093,10 +8093,12 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
>   		if (bp_gamma)
>   			PIPE_CONF_CHECK_COLOR_LUT(gamma_mode, hw.gamma_lut, bp_gamma);
>   
> -		PIPE_CONF_CHECK_BOOL(has_psr);
> -		PIPE_CONF_CHECK_BOOL(has_psr2);
> -		PIPE_CONF_CHECK_BOOL(enable_psr2_sel_fetch);
> -		PIPE_CONF_CHECK_I(dc3co_exitline);
> +		if (current_config->active_planes) {
> +			PIPE_CONF_CHECK_BOOL(has_psr);
> +			PIPE_CONF_CHECK_BOOL(has_psr2);
> +			PIPE_CONF_CHECK_BOOL(enable_psr2_sel_fetch);
> +			PIPE_CONF_CHECK_I(dc3co_exitline);
> +		}
>   	}
>   
>   	PIPE_CONF_CHECK_BOOL(double_wide);
> @@ -8153,7 +8155,7 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
>   		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,
>   					    ~intel_hdmi_infoframe_enable(DP_SDP_VSC));
>   	else
> @@ -10207,6 +10209,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
>   		intel_encoders_update_prepare(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) {
>   		if (new_crtc_state->uapi.async_flip)
> @@ -10270,6 +10273,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *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) {
>   		intel_post_plane_update(state, crtc);
> diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
> index e9e806d90eec4..c900bfbb7cc52 100644
> --- a/drivers/gpu/drm/i915/display/intel_display_types.h
> +++ b/drivers/gpu/drm/i915/display/intel_display_types.h
> @@ -1056,12 +1056,14 @@ struct intel_crtc_state {
>   	struct intel_link_m_n dp_m2_n2;
>   	bool has_drrs;
>   
> +	/* PSR is supported but might not be enabled due the lack of enabled planes */
>   	bool has_psr;
>   	bool has_psr2;
>   	bool enable_psr2_sel_fetch;
>   	bool req_psr2_sdp_prior_scanline;
>   	u32 dc3co_exitline;
>   	u16 su_y_granularity;
> +	struct drm_dp_vsc_sdp psr_vsc;
>   
>   	/*
>   	 * Frequence the dpll for the port should run at. Differs from the
> @@ -1525,7 +1527,6 @@ struct intel_psr {
>   	u32 dc3co_exitline;
>   	u32 dc3co_exit_delay;
>   	struct delayed_work dc3co_work;
> -	struct drm_dp_vsc_sdp vsc;
>   };
>   
>   struct intel_dp {
> diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
> index 7559911c140a7..378008873e039 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp.c
> @@ -1674,7 +1674,7 @@ void intel_dp_compute_psr_vsc_sdp(struct intel_dp *intel_dp,
>   {
>   	vsc->sdp_type = DP_SDP_VSC;
>   
> -	if (intel_dp->psr.psr2_enabled) {
> +	if (crtc_state->has_psr2) {
>   		if (intel_dp->psr.colorimetry_support &&
>   		    intel_dp_needs_vsc_sdp(crtc_state, conn_state)) {
>   			/* [PSR2, +Colorimetry] */
> @@ -1828,7 +1828,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
>   		g4x_dp_set_clock(encoder, pipe_config);
>   
>   	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,
>   				  constant_n);
>   	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,
>   
>   void intel_write_dp_vsc_sdp(struct intel_encoder *encoder,
>   			    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 drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h
> index 94b568704b22b..3343c25916807 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp.h
> +++ b/drivers/gpu/drm/i915/display/intel_dp.h
> @@ -88,7 +88,7 @@ void intel_dp_compute_psr_vsc_sdp(struct intel_dp *intel_dp,
>   				  struct drm_dp_vsc_sdp *vsc);
>   void intel_write_dp_vsc_sdp(struct intel_encoder *encoder,
>   			    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,
>   			     const struct intel_crtc_state *crtc_state,
>   			     const struct drm_connector_state *conn_state);
> diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c
> index c1894b056d6c1..8ceb22c5a1a6b 100644
> --- a/drivers/gpu/drm/i915/display/intel_psr.c
> +++ b/drivers/gpu/drm/i915/display/intel_psr.c
> @@ -949,7 +949,8 @@ static bool intel_psr2_config_valid(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);
>   	const struct drm_display_mode *adjusted_mode =
> @@ -1001,7 +1002,10 @@ void intel_psr_compute_config(struct intel_dp *intel_dp,
>   
>   	crtc_state->has_psr = true;
>   	crtc_state->has_psr2 = intel_psr2_config_valid(intel_dp, crtc_state);
> +
>   	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,
> @@ -1181,8 +1185,7 @@ static bool psr_interrupt_error_check(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 drm_connector_state *conn_state)
> +				    const struct intel_crtc_state *crtc_state)
>   {
>   	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
>   	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> @@ -1209,9 +1212,7 @@ static void intel_psr_enable_locked(struct intel_dp *intel_dp,
>   
>   	drm_dbg_kms(&dev_priv->drm, "Enabling PSR%s\n",
>   		    intel_dp->psr.psr2_enabled ? "2" : "1");
> -	intel_dp_compute_psr_vsc_sdp(intel_dp, crtc_state, conn_state,
> -				     &intel_dp->psr.vsc);
> -	intel_write_dp_vsc_sdp(encoder, crtc_state, &intel_dp->psr.vsc);
> +	intel_write_dp_vsc_sdp(encoder, crtc_state, &crtc_state->psr_vsc);
>   	intel_snps_phy_update_psr_power_state(dev_priv, phy, true);
>   	intel_psr_enable_sink(intel_dp);
>   	intel_psr_enable_source(intel_dp);
> @@ -1221,33 +1222,6 @@ static void intel_psr_enable_locked(struct intel_dp *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)
>   {
>   	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> @@ -1719,48 +1693,92 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
>   	return 0;
>   }
>   
> -/**
> - * intel_psr_update - Update PSR 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)
> +static void _intel_psr_pre_plane_update(const struct intel_atomic_state *state,
> +					const struct intel_crtc_state *crtc_state)
>   {
> -	struct intel_psr *psr = &intel_dp->psr;
> -	bool enable, psr2_enable;
> +	struct intel_encoder *encoder;
>   
> -	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;
>   
> -	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;
> -	psr2_enable = crtc_state->has_psr2;
> +static void _intel_psr_post_plane_update(const struct intel_atomic_state *state,
> +					 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 */
>   		if (crtc_state->crc_enabled && psr->enabled)
>   			psr_force_hw_tracking_exit(intel_dp);
>   
> -		goto unlock;
> +		mutex_unlock(&psr->lock);
>   	}
> +}
>   
> -	if (psr->enabled)
> -		intel_psr_disable_locked(intel_dp);
> +void intel_psr_post_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 (enable)
> -		intel_psr_enable_locked(intel_dp, crtc_state, conn_state);
> +	if (!HAS_PSR(dev_priv))
> +		return;
>   
> -unlock:
> -	mutex_unlock(&intel_dp->psr.lock);
> +	for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i)
> +		_intel_psr_post_plane_update(state, crtc_state);
>   }
>   
>   /**
> diff --git a/drivers/gpu/drm/i915/display/intel_psr.h b/drivers/gpu/drm/i915/display/intel_psr.h
> index 641521b101c82..2ca50df1f4fba 100644
> --- a/drivers/gpu/drm/i915/display/intel_psr.h
> +++ b/drivers/gpu/drm/i915/display/intel_psr.h
> @@ -20,14 +20,10 @@ struct intel_plane;
>   struct intel_encoder;
>   
>   void intel_psr_init_dpcd(struct intel_dp *intel_dp);
> -void intel_psr_enable(struct intel_dp *intel_dp,
> -		      const struct intel_crtc_state *crtc_state,
> -		      const struct drm_connector_state *conn_state);
> +void intel_psr_pre_plane_update(const struct intel_atomic_state *state);
> +void intel_psr_post_plane_update(const struct intel_atomic_state *state);
>   void intel_psr_disable(struct intel_dp *intel_dp,
>   		       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);
>   void intel_psr_invalidate(struct drm_i915_private *dev_priv,
>   			  unsigned frontbuffer_bits,
> @@ -37,7 +33,8 @@ void intel_psr_flush(struct drm_i915_private *dev_priv,
>   		     enum fb_op_origin origin);
>   void intel_psr_init(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,
>   			  struct intel_crtc_state *pipe_config);
>   void intel_psr_irq_handler(struct intel_dp *intel_dp, u32 psr_iir);
>
Gwan-gyeong Mun Sept. 22, 2021, 4:28 p.m. UTC | #2
Looks good to me.
Reviewed-by: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>

On 9/21/21 3:41 AM, José Roberto de Souza wrote:
> 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 84030adb9e27 ("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.
> 
> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> Cc: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
> Signed-off-by: José Roberto de Souza <jose.souza@intel.com>
> ---
>   drivers/gpu/drm/i915/display/intel_ddi.c      |   2 -
>   drivers/gpu/drm/i915/display/intel_display.c  |  14 +-
>   .../drm/i915/display/intel_display_types.h    |   3 +-
>   drivers/gpu/drm/i915/display/intel_dp.c       |   6 +-
>   drivers/gpu/drm/i915/display/intel_dp.h       |   2 +-
>   drivers/gpu/drm/i915/display/intel_psr.c      | 140 ++++++++++--------
>   drivers/gpu/drm/i915/display/intel_psr.h      |  11 +-
>   7 files changed, 98 insertions(+), 80 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
> index bba0ab99836b1..a4667741d3548 100644
> --- a/drivers/gpu/drm/i915/display/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/display/intel_ddi.c
> @@ -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_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)
>   		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,
>   
>   	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_drrs_update(intel_dp, crtc_state);
>   
> diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
> index f6c0c595f6313..ddcd8d6efc788 100644
> --- a/drivers/gpu/drm/i915/display/intel_display.c
> +++ b/drivers/gpu/drm/i915/display/intel_display.c
> @@ -8093,10 +8093,12 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
>   		if (bp_gamma)
>   			PIPE_CONF_CHECK_COLOR_LUT(gamma_mode, hw.gamma_lut, bp_gamma);
>   
> -		PIPE_CONF_CHECK_BOOL(has_psr);
> -		PIPE_CONF_CHECK_BOOL(has_psr2);
> -		PIPE_CONF_CHECK_BOOL(enable_psr2_sel_fetch);
> -		PIPE_CONF_CHECK_I(dc3co_exitline);
> +		if (current_config->active_planes) {
> +			PIPE_CONF_CHECK_BOOL(has_psr);
> +			PIPE_CONF_CHECK_BOOL(has_psr2);
> +			PIPE_CONF_CHECK_BOOL(enable_psr2_sel_fetch);
> +			PIPE_CONF_CHECK_I(dc3co_exitline);
> +		}
>   	}
>   
>   	PIPE_CONF_CHECK_BOOL(double_wide);
> @@ -8153,7 +8155,7 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
>   		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,
>   					    ~intel_hdmi_infoframe_enable(DP_SDP_VSC));
>   	else
> @@ -10207,6 +10209,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
>   		intel_encoders_update_prepare(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) {
>   		if (new_crtc_state->uapi.async_flip)
> @@ -10270,6 +10273,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *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) {
>   		intel_post_plane_update(state, crtc);
> diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
> index e9e806d90eec4..c900bfbb7cc52 100644
> --- a/drivers/gpu/drm/i915/display/intel_display_types.h
> +++ b/drivers/gpu/drm/i915/display/intel_display_types.h
> @@ -1056,12 +1056,14 @@ struct intel_crtc_state {
>   	struct intel_link_m_n dp_m2_n2;
>   	bool has_drrs;
>   
> +	/* PSR is supported but might not be enabled due the lack of enabled planes */
>   	bool has_psr;
>   	bool has_psr2;
>   	bool enable_psr2_sel_fetch;
>   	bool req_psr2_sdp_prior_scanline;
>   	u32 dc3co_exitline;
>   	u16 su_y_granularity;
> +	struct drm_dp_vsc_sdp psr_vsc;
>   
>   	/*
>   	 * Frequence the dpll for the port should run at. Differs from the
> @@ -1525,7 +1527,6 @@ struct intel_psr {
>   	u32 dc3co_exitline;
>   	u32 dc3co_exit_delay;
>   	struct delayed_work dc3co_work;
> -	struct drm_dp_vsc_sdp vsc;
>   };
>   
>   struct intel_dp {
> diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
> index 7559911c140a7..378008873e039 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp.c
> @@ -1674,7 +1674,7 @@ void intel_dp_compute_psr_vsc_sdp(struct intel_dp *intel_dp,
>   {
>   	vsc->sdp_type = DP_SDP_VSC;
>   
> -	if (intel_dp->psr.psr2_enabled) {
> +	if (crtc_state->has_psr2) {
>   		if (intel_dp->psr.colorimetry_support &&
>   		    intel_dp_needs_vsc_sdp(crtc_state, conn_state)) {
>   			/* [PSR2, +Colorimetry] */
> @@ -1828,7 +1828,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
>   		g4x_dp_set_clock(encoder, pipe_config);
>   
>   	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,
>   				  constant_n);
>   	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,
>   
>   void intel_write_dp_vsc_sdp(struct intel_encoder *encoder,
>   			    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 drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h
> index 94b568704b22b..3343c25916807 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp.h
> +++ b/drivers/gpu/drm/i915/display/intel_dp.h
> @@ -88,7 +88,7 @@ void intel_dp_compute_psr_vsc_sdp(struct intel_dp *intel_dp,
>   				  struct drm_dp_vsc_sdp *vsc);
>   void intel_write_dp_vsc_sdp(struct intel_encoder *encoder,
>   			    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,
>   			     const struct intel_crtc_state *crtc_state,
>   			     const struct drm_connector_state *conn_state);
> diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c
> index c1894b056d6c1..8ceb22c5a1a6b 100644
> --- a/drivers/gpu/drm/i915/display/intel_psr.c
> +++ b/drivers/gpu/drm/i915/display/intel_psr.c
> @@ -949,7 +949,8 @@ static bool intel_psr2_config_valid(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);
>   	const struct drm_display_mode *adjusted_mode =
> @@ -1001,7 +1002,10 @@ void intel_psr_compute_config(struct intel_dp *intel_dp,
>   
>   	crtc_state->has_psr = true;
>   	crtc_state->has_psr2 = intel_psr2_config_valid(intel_dp, crtc_state);
> +
>   	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,
> @@ -1181,8 +1185,7 @@ static bool psr_interrupt_error_check(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 drm_connector_state *conn_state)
> +				    const struct intel_crtc_state *crtc_state)
>   {
>   	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
>   	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> @@ -1209,9 +1212,7 @@ static void intel_psr_enable_locked(struct intel_dp *intel_dp,
>   
>   	drm_dbg_kms(&dev_priv->drm, "Enabling PSR%s\n",
>   		    intel_dp->psr.psr2_enabled ? "2" : "1");
> -	intel_dp_compute_psr_vsc_sdp(intel_dp, crtc_state, conn_state,
> -				     &intel_dp->psr.vsc);
> -	intel_write_dp_vsc_sdp(encoder, crtc_state, &intel_dp->psr.vsc);
> +	intel_write_dp_vsc_sdp(encoder, crtc_state, &crtc_state->psr_vsc);
>   	intel_snps_phy_update_psr_power_state(dev_priv, phy, true);
>   	intel_psr_enable_sink(intel_dp);
>   	intel_psr_enable_source(intel_dp);
> @@ -1221,33 +1222,6 @@ static void intel_psr_enable_locked(struct intel_dp *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)
>   {
>   	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> @@ -1719,48 +1693,92 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
>   	return 0;
>   }
>   
> -/**
> - * intel_psr_update - Update PSR 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)
> +static void _intel_psr_pre_plane_update(const struct intel_atomic_state *state,
> +					const struct intel_crtc_state *crtc_state)
>   {
> -	struct intel_psr *psr = &intel_dp->psr;
> -	bool enable, psr2_enable;
> +	struct intel_encoder *encoder;
>   
> -	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;
>   
> -	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;
> -	psr2_enable = crtc_state->has_psr2;
> +static void _intel_psr_post_plane_update(const struct intel_atomic_state *state,
> +					 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 */
>   		if (crtc_state->crc_enabled && psr->enabled)
>   			psr_force_hw_tracking_exit(intel_dp);
>   
> -		goto unlock;
> +		mutex_unlock(&psr->lock);
>   	}
> +}
>   
> -	if (psr->enabled)
> -		intel_psr_disable_locked(intel_dp);
> +void intel_psr_post_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 (enable)
> -		intel_psr_enable_locked(intel_dp, crtc_state, conn_state);
> +	if (!HAS_PSR(dev_priv))
> +		return;
>   
> -unlock:
> -	mutex_unlock(&intel_dp->psr.lock);
> +	for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i)
> +		_intel_psr_post_plane_update(state, crtc_state);
>   }
>   
>   /**
> diff --git a/drivers/gpu/drm/i915/display/intel_psr.h b/drivers/gpu/drm/i915/display/intel_psr.h
> index 641521b101c82..2ca50df1f4fba 100644
> --- a/drivers/gpu/drm/i915/display/intel_psr.h
> +++ b/drivers/gpu/drm/i915/display/intel_psr.h
> @@ -20,14 +20,10 @@ struct intel_plane;
>   struct intel_encoder;
>   
>   void intel_psr_init_dpcd(struct intel_dp *intel_dp);
> -void intel_psr_enable(struct intel_dp *intel_dp,
> -		      const struct intel_crtc_state *crtc_state,
> -		      const struct drm_connector_state *conn_state);
> +void intel_psr_pre_plane_update(const struct intel_atomic_state *state);
> +void intel_psr_post_plane_update(const struct intel_atomic_state *state);
>   void intel_psr_disable(struct intel_dp *intel_dp,
>   		       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);
>   void intel_psr_invalidate(struct drm_i915_private *dev_priv,
>   			  unsigned frontbuffer_bits,
> @@ -37,7 +33,8 @@ void intel_psr_flush(struct drm_i915_private *dev_priv,
>   		     enum fb_op_origin origin);
>   void intel_psr_init(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,
>   			  struct intel_crtc_state *pipe_config);
>   void intel_psr_irq_handler(struct intel_dp *intel_dp, u32 psr_iir);
>
diff mbox series

Patch

diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
index bba0ab99836b1..a4667741d3548 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -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_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)
 		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,
 
 	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_drrs_update(intel_dp, crtc_state);
 
diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index f6c0c595f6313..ddcd8d6efc788 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -8093,10 +8093,12 @@  intel_pipe_config_compare(const struct intel_crtc_state *current_config,
 		if (bp_gamma)
 			PIPE_CONF_CHECK_COLOR_LUT(gamma_mode, hw.gamma_lut, bp_gamma);
 
-		PIPE_CONF_CHECK_BOOL(has_psr);
-		PIPE_CONF_CHECK_BOOL(has_psr2);
-		PIPE_CONF_CHECK_BOOL(enable_psr2_sel_fetch);
-		PIPE_CONF_CHECK_I(dc3co_exitline);
+		if (current_config->active_planes) {
+			PIPE_CONF_CHECK_BOOL(has_psr);
+			PIPE_CONF_CHECK_BOOL(has_psr2);
+			PIPE_CONF_CHECK_BOOL(enable_psr2_sel_fetch);
+			PIPE_CONF_CHECK_I(dc3co_exitline);
+		}
 	}
 
 	PIPE_CONF_CHECK_BOOL(double_wide);
@@ -8153,7 +8155,7 @@  intel_pipe_config_compare(const struct intel_crtc_state *current_config,
 		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,
 					    ~intel_hdmi_infoframe_enable(DP_SDP_VSC));
 	else
@@ -10207,6 +10209,7 @@  static void intel_atomic_commit_tail(struct intel_atomic_state *state)
 		intel_encoders_update_prepare(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) {
 		if (new_crtc_state->uapi.async_flip)
@@ -10270,6 +10273,7 @@  static void intel_atomic_commit_tail(struct intel_atomic_state *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) {
 		intel_post_plane_update(state, crtc);
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index e9e806d90eec4..c900bfbb7cc52 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -1056,12 +1056,14 @@  struct intel_crtc_state {
 	struct intel_link_m_n dp_m2_n2;
 	bool has_drrs;
 
+	/* PSR is supported but might not be enabled due the lack of enabled planes */
 	bool has_psr;
 	bool has_psr2;
 	bool enable_psr2_sel_fetch;
 	bool req_psr2_sdp_prior_scanline;
 	u32 dc3co_exitline;
 	u16 su_y_granularity;
+	struct drm_dp_vsc_sdp psr_vsc;
 
 	/*
 	 * Frequence the dpll for the port should run at. Differs from the
@@ -1525,7 +1527,6 @@  struct intel_psr {
 	u32 dc3co_exitline;
 	u32 dc3co_exit_delay;
 	struct delayed_work dc3co_work;
-	struct drm_dp_vsc_sdp vsc;
 };
 
 struct intel_dp {
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 7559911c140a7..378008873e039 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -1674,7 +1674,7 @@  void intel_dp_compute_psr_vsc_sdp(struct intel_dp *intel_dp,
 {
 	vsc->sdp_type = DP_SDP_VSC;
 
-	if (intel_dp->psr.psr2_enabled) {
+	if (crtc_state->has_psr2) {
 		if (intel_dp->psr.colorimetry_support &&
 		    intel_dp_needs_vsc_sdp(crtc_state, conn_state)) {
 			/* [PSR2, +Colorimetry] */
@@ -1828,7 +1828,7 @@  intel_dp_compute_config(struct intel_encoder *encoder,
 		g4x_dp_set_clock(encoder, pipe_config);
 
 	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,
 				  constant_n);
 	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,
 
 void intel_write_dp_vsc_sdp(struct intel_encoder *encoder,
 			    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 drm_i915_private *dev_priv = to_i915(encoder->base.dev);
diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h
index 94b568704b22b..3343c25916807 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.h
+++ b/drivers/gpu/drm/i915/display/intel_dp.h
@@ -88,7 +88,7 @@  void intel_dp_compute_psr_vsc_sdp(struct intel_dp *intel_dp,
 				  struct drm_dp_vsc_sdp *vsc);
 void intel_write_dp_vsc_sdp(struct intel_encoder *encoder,
 			    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,
 			     const struct intel_crtc_state *crtc_state,
 			     const struct drm_connector_state *conn_state);
diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c
index c1894b056d6c1..8ceb22c5a1a6b 100644
--- a/drivers/gpu/drm/i915/display/intel_psr.c
+++ b/drivers/gpu/drm/i915/display/intel_psr.c
@@ -949,7 +949,8 @@  static bool intel_psr2_config_valid(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);
 	const struct drm_display_mode *adjusted_mode =
@@ -1001,7 +1002,10 @@  void intel_psr_compute_config(struct intel_dp *intel_dp,
 
 	crtc_state->has_psr = true;
 	crtc_state->has_psr2 = intel_psr2_config_valid(intel_dp, crtc_state);
+
 	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,
@@ -1181,8 +1185,7 @@  static bool psr_interrupt_error_check(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 drm_connector_state *conn_state)
+				    const struct intel_crtc_state *crtc_state)
 {
 	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
 	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
@@ -1209,9 +1212,7 @@  static void intel_psr_enable_locked(struct intel_dp *intel_dp,
 
 	drm_dbg_kms(&dev_priv->drm, "Enabling PSR%s\n",
 		    intel_dp->psr.psr2_enabled ? "2" : "1");
-	intel_dp_compute_psr_vsc_sdp(intel_dp, crtc_state, conn_state,
-				     &intel_dp->psr.vsc);
-	intel_write_dp_vsc_sdp(encoder, crtc_state, &intel_dp->psr.vsc);
+	intel_write_dp_vsc_sdp(encoder, crtc_state, &crtc_state->psr_vsc);
 	intel_snps_phy_update_psr_power_state(dev_priv, phy, true);
 	intel_psr_enable_sink(intel_dp);
 	intel_psr_enable_source(intel_dp);
@@ -1221,33 +1222,6 @@  static void intel_psr_enable_locked(struct intel_dp *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)
 {
 	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
@@ -1719,48 +1693,92 @@  int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
 	return 0;
 }
 
-/**
- * intel_psr_update - Update PSR 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)
+static void _intel_psr_pre_plane_update(const struct intel_atomic_state *state,
+					const struct intel_crtc_state *crtc_state)
 {
-	struct intel_psr *psr = &intel_dp->psr;
-	bool enable, psr2_enable;
+	struct intel_encoder *encoder;
 
-	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;
 
-	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;
-	psr2_enable = crtc_state->has_psr2;
+static void _intel_psr_post_plane_update(const struct intel_atomic_state *state,
+					 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 */
 		if (crtc_state->crc_enabled && psr->enabled)
 			psr_force_hw_tracking_exit(intel_dp);
 
-		goto unlock;
+		mutex_unlock(&psr->lock);
 	}
+}
 
-	if (psr->enabled)
-		intel_psr_disable_locked(intel_dp);
+void intel_psr_post_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 (enable)
-		intel_psr_enable_locked(intel_dp, crtc_state, conn_state);
+	if (!HAS_PSR(dev_priv))
+		return;
 
-unlock:
-	mutex_unlock(&intel_dp->psr.lock);
+	for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i)
+		_intel_psr_post_plane_update(state, crtc_state);
 }
 
 /**
diff --git a/drivers/gpu/drm/i915/display/intel_psr.h b/drivers/gpu/drm/i915/display/intel_psr.h
index 641521b101c82..2ca50df1f4fba 100644
--- a/drivers/gpu/drm/i915/display/intel_psr.h
+++ b/drivers/gpu/drm/i915/display/intel_psr.h
@@ -20,14 +20,10 @@  struct intel_plane;
 struct intel_encoder;
 
 void intel_psr_init_dpcd(struct intel_dp *intel_dp);
-void intel_psr_enable(struct intel_dp *intel_dp,
-		      const struct intel_crtc_state *crtc_state,
-		      const struct drm_connector_state *conn_state);
+void intel_psr_pre_plane_update(const struct intel_atomic_state *state);
+void intel_psr_post_plane_update(const struct intel_atomic_state *state);
 void intel_psr_disable(struct intel_dp *intel_dp,
 		       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);
 void intel_psr_invalidate(struct drm_i915_private *dev_priv,
 			  unsigned frontbuffer_bits,
@@ -37,7 +33,8 @@  void intel_psr_flush(struct drm_i915_private *dev_priv,
 		     enum fb_op_origin origin);
 void intel_psr_init(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,
 			  struct intel_crtc_state *pipe_config);
 void intel_psr_irq_handler(struct intel_dp *intel_dp, u32 psr_iir);