diff mbox series

[v4,4/6] drm/i915/panelreplay: Initializaton and compute config for panel replay

Message ID 20230824040952.186407-5-animesh.manna@intel.com (mailing list archive)
State New, archived
Headers show
Series Panel replay phase1 implementation | expand

Commit Message

Manna, Animesh Aug. 24, 2023, 4:09 a.m. UTC
Modify existing PSR implementation to enable panel replay feature of DP 2.0
which is similar to PSR feature of EDP panel. There is different DPCD
address to check panel capability compare to PSR and vsc sdp header
is different.

v1: Initial version.
v2:
- Set source_panel_replay_support flag under HAS_PNEL_REPLAY() check. [Jouni]
- Code restructured around intel_panel_replay_init
and renamed to intel_panel_replay_init_dpcd. [Jouni]
- Remove the initial code modification around has_psr2 flag. [Jouni]
- Add CAN_PANEL_REPLAY() in intel_encoder_can_psr which is used to
enable in intel_psr_post_plane_update. [Jouni]
v3:
- Initialize both psr and panel-replay. [Jouni]
- Initialize both panel replay and psr if detected. [Jouni]
- Refactoring psr function by introducing _psr_compute_config(). [Jouni]
- Add check for !is_edp while deriving source_panel_replay_support. [Jouni]
- Enable panel replay dpcd initialization in a separate patch. [Jouni]

v4:
- HAS_PANEL_REPLAY() check not needed during sink capability check.[Jouni]
- Set either panel replay source support or psr.[Jouni]

Cc: Jouni Högander <jouni.hogander@intel.com>
Signed-off-by: Animesh Manna <animesh.manna@intel.com>
---
 .../drm/i915/display/intel_display_types.h    | 12 ++-
 drivers/gpu/drm/i915/display/intel_dp.c       | 44 ++++++++--
 drivers/gpu/drm/i915/display/intel_dp_mst.c   |  3 +
 drivers/gpu/drm/i915/display/intel_psr.c      | 87 +++++++++++++------
 4 files changed, 107 insertions(+), 39 deletions(-)

Comments

Jani Nikula Aug. 24, 2023, 11:35 a.m. UTC | #1
On Thu, 24 Aug 2023, Animesh Manna <animesh.manna@intel.com> wrote:
> Modify existing PSR implementation to enable panel replay feature of DP 2.0
> which is similar to PSR feature of EDP panel. There is different DPCD
> address to check panel capability compare to PSR and vsc sdp header
> is different.
>
> v1: Initial version.
> v2:
> - Set source_panel_replay_support flag under HAS_PNEL_REPLAY() check. [Jouni]
> - Code restructured around intel_panel_replay_init
> and renamed to intel_panel_replay_init_dpcd. [Jouni]
> - Remove the initial code modification around has_psr2 flag. [Jouni]
> - Add CAN_PANEL_REPLAY() in intel_encoder_can_psr which is used to
> enable in intel_psr_post_plane_update. [Jouni]
> v3:
> - Initialize both psr and panel-replay. [Jouni]
> - Initialize both panel replay and psr if detected. [Jouni]
> - Refactoring psr function by introducing _psr_compute_config(). [Jouni]
> - Add check for !is_edp while deriving source_panel_replay_support. [Jouni]
> - Enable panel replay dpcd initialization in a separate patch. [Jouni]
>
> v4:
> - HAS_PANEL_REPLAY() check not needed during sink capability check.[Jouni]
> - Set either panel replay source support or psr.[Jouni]
>
> Cc: Jouni Högander <jouni.hogander@intel.com>
> Signed-off-by: Animesh Manna <animesh.manna@intel.com>
> ---
>  .../drm/i915/display/intel_display_types.h    | 12 ++-
>  drivers/gpu/drm/i915/display/intel_dp.c       | 44 ++++++++--
>  drivers/gpu/drm/i915/display/intel_dp_mst.c   |  3 +
>  drivers/gpu/drm/i915/display/intel_psr.c      | 87 +++++++++++++------
>  4 files changed, 107 insertions(+), 39 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
> index 731f2ec04d5c..97cef458f42b 100644
> --- a/drivers/gpu/drm/i915/display/intel_display_types.h
> +++ b/drivers/gpu/drm/i915/display/intel_display_types.h
> @@ -1202,6 +1202,7 @@ struct intel_crtc_state {
>  	bool has_psr2;
>  	bool enable_psr2_sel_fetch;
>  	bool req_psr2_sdp_prior_scanline;
> +	bool has_panel_replay;
>  	bool wm_level_disabled;
>  	u32 dc3co_exitline;
>  	u16 su_y_granularity;
> @@ -1693,6 +1694,8 @@ struct intel_psr {
>  	bool irq_aux_error;
>  	u16 su_w_granularity;
>  	u16 su_y_granularity;
> +	bool source_panel_replay_support;
> +	bool sink_panel_replay_support;
>  	u32 dc3co_exitline;
>  	u32 dc3co_exit_delay;
>  	struct delayed_work dc3co_work;
> @@ -1983,12 +1986,15 @@ dp_to_lspcon(struct intel_dp *intel_dp)
>  #define CAN_PSR(intel_dp) ((intel_dp)->psr.sink_support && \
>  			   (intel_dp)->psr.source_support)
>  
> +#define CAN_PANEL_REPLAY(intel_dp) ((intel_dp)->psr.sink_panel_replay_support && \
> +			  (intel_dp)->psr.source_panel_replay_support)
> +
>  static inline bool intel_encoder_can_psr(struct intel_encoder *encoder)
>  {
> -	if (!intel_encoder_is_dp(encoder))
> +	if (intel_encoder_is_dp(encoder) || (encoder->type == INTEL_OUTPUT_DP_MST))
> +		return CAN_PSR(enc_to_intel_dp(encoder)) || CAN_PANEL_REPLAY(enc_to_intel_dp(encoder));
> +	else
>  		return false;
> -
> -	return CAN_PSR(enc_to_intel_dp(encoder));
>  }

The whole function and macros should live in intel_psr.c as proper
functions.

>  
>  static inline struct intel_digital_port *
> diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
> index 7067ee3a4bd3..b3301cf0da0a 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp.c
> @@ -2337,12 +2337,22 @@ static void intel_dp_compute_vsc_colorimetry(const struct intel_crtc_state *crtc
>  	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
>  	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
>  
> -	/*
> -	 * Prepare VSC Header for SU as per DP 1.4 spec, Table 2-118
> -	 * VSC SDP supporting 3D stereo, PSR2, and Pixel Encoding/
> -	 * Colorimetry Format indication.
> -	 */
> -	vsc->revision = 0x5;
> +	if (crtc_state->has_panel_replay) {
> +		/*
> +		 * Prepare VSC Header for SU as per DP 2.0 spec, Table 2-223
> +		 * VSC SDP supporting 3D stereo, Panel Replay, and Pixel
> +		 * Encoding/Colorimetry Format indication.
> +		 */
> +		vsc->revision = 0x7;
> +	} else {
> +		/*
> +		 * Prepare VSC Header for SU as per DP 1.4 spec, Table 2-118
> +		 * VSC SDP supporting 3D stereo, PSR2, and Pixel Encoding/
> +		 * Colorimetry Format indication.
> +		 */
> +		vsc->revision = 0x5;
> +	}
> +
>  	vsc->length = 0x13;
>  
>  	/* DP 1.4a spec, Table 2-120 */
> @@ -2451,6 +2461,21 @@ void intel_dp_compute_psr_vsc_sdp(struct intel_dp *intel_dp,
>  			vsc->revision = 0x4;
>  			vsc->length = 0xe;
>  		}
> +	} else if (crtc_state->has_panel_replay) {
> +		if (intel_dp->psr.colorimetry_support &&
> +		    intel_dp_needs_vsc_sdp(crtc_state, conn_state)) {
> +			/* [Panel Replay with colorimetry info] */
> +			intel_dp_compute_vsc_colorimetry(crtc_state, conn_state,
> +							 vsc);
> +		} else {
> +			/*
> +			 * [Panel Replay without colorimetry info]
> +			 * Prepare VSC Header for SU as per DP 2.0 spec, Table 2-223
> +			 * VSC SDP supporting 3D stereo + Panel Replay.
> +			 */
> +			vsc->revision = 0x6;
> +			vsc->length = 0x10;
> +		}
>  	} else {
>  		/*
>  		 * [PSR1]
> @@ -3744,10 +3769,11 @@ static ssize_t intel_dp_vsc_sdp_pack(const struct drm_dp_vsc_sdp *vsc,
>  	sdp->sdp_header.HB3 = vsc->length; /* Number of Valid Data Bytes */
>  
>  	/*
> -	 * Only revision 0x5 supports Pixel Encoding/Colorimetry Format as
> -	 * per DP 1.4a spec.
> +	 * Other than revision 0x5 which supports Pixel Encoding/Colorimetry
> +	 * Format as per DP 1.4a spec, revision 0x7 also supports Pixel
> +	 * Encoding/Colorimetry Format as per DP 2.0 spec.
>  	 */
> -	if (vsc->revision != 0x5)
> +	if (vsc->revision != 0x5 || vsc->revision != 0x7)
>  		goto out;
>  
>  	/* VSC SDP Payload for DB16 through DB18 */
> diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c
> index 3eb085fbc7c8..07a3ab473be2 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c
> @@ -44,6 +44,7 @@
>  #include "intel_hdcp.h"
>  #include "intel_hotplug.h"
>  #include "skl_scaler.h"
> +#include "intel_psr.h"

Please keep these sorted.

>  
>  static int intel_dp_mst_check_constraints(struct drm_i915_private *i915, int bpp,
>  					  const struct drm_display_mode *adjusted_mode,
> @@ -398,6 +399,8 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder,
>  
>  	intel_ddi_compute_min_voltage_level(dev_priv, pipe_config);
>  
> +	intel_psr_compute_config(intel_dp, pipe_config, conn_state);
> +
>  	return 0;
>  }
>  
> diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c
> index b1c0494826f9..8dd61c62492d 100644
> --- a/drivers/gpu/drm/i915/display/intel_psr.c
> +++ b/drivers/gpu/drm/i915/display/intel_psr.c
> @@ -472,6 +472,24 @@ static void intel_dp_get_su_granularity(struct intel_dp *intel_dp)
>  	intel_dp->psr.su_y_granularity = y;
>  }
>  
> +static void _panel_replay_init_dpcd(struct intel_dp *intel_dp)
> +{
> +	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> +	u8 pr_dpcd = 0;
> +
> +	drm_dp_dpcd_readb(&intel_dp->aux, DP_PANEL_REPLAY_CAP, &pr_dpcd);
> +
> +	if (!(pr_dpcd & DP_PANEL_REPLAY_SUPPORT)) {
> +		drm_dbg_kms(&dev_priv->drm,
> +			    "Panel replay is not supported by panel\n");
> +		return;
> +	}
> +
> +	drm_dbg_kms(&dev_priv->drm,
> +		    "Panel replay is supported by panel\n");
> +	intel_dp->psr.sink_panel_replay_support = true;

This is not eDP so clearing the cached value matters. I don't see this
cleared anywhere.

> +}
> +
>  static void _psr_init_dpcd(struct intel_dp *intel_dp)
>  {
>  	struct drm_i915_private *i915 =
> @@ -521,12 +539,13 @@ static void _psr_init_dpcd(struct intel_dp *intel_dp)
>  
>  void intel_psr_init_dpcd(struct intel_dp *intel_dp)
>  {
> +	_panel_replay_init_dpcd(intel_dp);
> +
>  	drm_dp_dpcd_read(&intel_dp->aux, DP_PSR_SUPPORT, intel_dp->psr_dpcd,
>  			 sizeof(intel_dp->psr_dpcd));
>  
>  	if (intel_dp->psr_dpcd[0])
>  		_psr_init_dpcd(intel_dp);
> -	/* TODO: Add PR case here */
>  
>  	if (intel_dp->psr.sink_psr2_support) {
>  		intel_dp->psr.colorimetry_support =
> @@ -1207,13 +1226,11 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp,
>  	return false;
>  }
>  
> -void intel_psr_compute_config(struct intel_dp *intel_dp,
> -			      struct intel_crtc_state *crtc_state,
> -			      struct drm_connector_state *conn_state)
> +static bool _psr_compute_config(struct intel_dp *intel_dp,
> +				struct intel_crtc_state *crtc_state)
>  {
>  	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> -	const struct drm_display_mode *adjusted_mode =
> -		&crtc_state->hw.adjusted_mode;
> +	const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
>  	int psr_setup_time;
>  
>  	/*
> @@ -1221,10 +1238,36 @@ void intel_psr_compute_config(struct intel_dp *intel_dp,
>  	 * So if VRR is enabled, do not enable PSR.
>  	 */
>  	if (crtc_state->vrr.enable)
> -		return;
> +		return false;
>  
>  	if (!CAN_PSR(intel_dp))
> -		return;
> +		return false;
> +
> +	psr_setup_time = drm_dp_psr_setup_time(intel_dp->psr_dpcd);
> +	if (psr_setup_time < 0) {
> +		drm_dbg_kms(&dev_priv->drm,
> +			    "PSR condition failed: Invalid PSR setup time (0x%02x)\n",
> +			    intel_dp->psr_dpcd[1]);
> +		return false;
> +	}
> +
> +	if (intel_usecs_to_scanlines(adjusted_mode, psr_setup_time) >
> +	    adjusted_mode->crtc_vtotal - adjusted_mode->crtc_vdisplay - 1) {
> +		drm_dbg_kms(&dev_priv->drm,
> +			    "PSR condition failed: PSR setup time (%d us) too long\n",
> +			    psr_setup_time);
> +		return false;
> +	}
> +
> +	return true;
> +}
> +
> +void intel_psr_compute_config(struct intel_dp *intel_dp,
> +			      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 = &crtc_state->hw.adjusted_mode;
>  
>  	if (!psr_global_enabled(intel_dp)) {
>  		drm_dbg_kms(&dev_priv->drm, "PSR disabled by flag\n");
> @@ -1234,7 +1277,6 @@ void intel_psr_compute_config(struct intel_dp *intel_dp,
>  	if (intel_dp->psr.sink_not_reliable) {
>  		drm_dbg_kms(&dev_priv->drm,
>  			    "PSR sink implementation is not reliable\n");
> -		return;
>  	}
>  
>  	if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
> @@ -1243,23 +1285,11 @@ void intel_psr_compute_config(struct intel_dp *intel_dp,
>  		return;
>  	}
>  
> -	psr_setup_time = drm_dp_psr_setup_time(intel_dp->psr_dpcd);
> -	if (psr_setup_time < 0) {
> -		drm_dbg_kms(&dev_priv->drm,
> -			    "PSR condition failed: Invalid PSR setup time (0x%02x)\n",
> -			    intel_dp->psr_dpcd[1]);
> -		return;
> -	}
> -
> -	if (intel_usecs_to_scanlines(adjusted_mode, psr_setup_time) >
> -	    adjusted_mode->crtc_vtotal - adjusted_mode->crtc_vdisplay - 1) {
> -		drm_dbg_kms(&dev_priv->drm,
> -			    "PSR condition failed: PSR setup time (%d us) too long\n",
> -			    psr_setup_time);
> -		return;
> -	}
> +	if (CAN_PANEL_REPLAY(intel_dp))
> +		crtc_state->has_panel_replay = true;
> +	else
> +		crtc_state->has_psr = _psr_compute_config(intel_dp, crtc_state);
>  
> -	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);
> @@ -2699,7 +2729,7 @@ void intel_psr_init(struct intel_dp *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);
>  
> -	if (!HAS_PSR(dev_priv))
> +	if (!(HAS_PSR(dev_priv) || HAS_PANEL_REPLAY(dev_priv)))
>  		return;
>  
>  	/*
> @@ -2717,7 +2747,10 @@ void intel_psr_init(struct intel_dp *intel_dp)
>  		return;
>  	}
>  
> -	intel_dp->psr.source_support = true;
> +	if (HAS_PANEL_REPLAY(dev_priv) && !intel_dp_is_edp(intel_dp))
> +		intel_dp->psr.source_panel_replay_support = true;
> +	else
> +		intel_dp->psr.source_support = true;
>  
>  	/* Set link_standby x link_off defaults */
>  	if (DISPLAY_VER(dev_priv) < 12)
Manna, Animesh Aug. 25, 2023, 8:35 a.m. UTC | #2
> -----Original Message-----
> From: Jani Nikula <jani.nikula@linux.intel.com>
> Sent: Thursday, August 24, 2023 5:05 PM
> To: Manna, Animesh <animesh.manna@intel.com>; intel-
> gfx@lists.freedesktop.org
> Subject: Re: [Intel-gfx] [PATCH v4 4/6] drm/i915/panelreplay: Initializaton and
> compute config for panel replay
> 
> On Thu, 24 Aug 2023, Animesh Manna <animesh.manna@intel.com> wrote:
> > Modify existing PSR implementation to enable panel replay feature of
> > DP 2.0 which is similar to PSR feature of EDP panel. There is
> > different DPCD address to check panel capability compare to PSR and
> > vsc sdp header is different.
> >
> > v1: Initial version.
> > v2:
> > - Set source_panel_replay_support flag under HAS_PNEL_REPLAY() check.
> > [Jouni]
> > - Code restructured around intel_panel_replay_init and renamed to
> > intel_panel_replay_init_dpcd. [Jouni]
> > - Remove the initial code modification around has_psr2 flag. [Jouni]
> > - Add CAN_PANEL_REPLAY() in intel_encoder_can_psr which is used to
> > enable in intel_psr_post_plane_update. [Jouni]
> > v3:
> > - Initialize both psr and panel-replay. [Jouni]
> > - Initialize both panel replay and psr if detected. [Jouni]
> > - Refactoring psr function by introducing _psr_compute_config().
> > [Jouni]
> > - Add check for !is_edp while deriving source_panel_replay_support.
> > [Jouni]
> > - Enable panel replay dpcd initialization in a separate patch. [Jouni]
> >
> > v4:
> > - HAS_PANEL_REPLAY() check not needed during sink capability
> > check.[Jouni]
> > - Set either panel replay source support or psr.[Jouni]
> >
> > Cc: Jouni Högander <jouni.hogander@intel.com>
> > Signed-off-by: Animesh Manna <animesh.manna@intel.com>
> > ---
> >  .../drm/i915/display/intel_display_types.h    | 12 ++-
> >  drivers/gpu/drm/i915/display/intel_dp.c       | 44 ++++++++--
> >  drivers/gpu/drm/i915/display/intel_dp_mst.c   |  3 +
> >  drivers/gpu/drm/i915/display/intel_psr.c      | 87 +++++++++++++------
> >  4 files changed, 107 insertions(+), 39 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h
> > b/drivers/gpu/drm/i915/display/intel_display_types.h
> > index 731f2ec04d5c..97cef458f42b 100644
> > --- a/drivers/gpu/drm/i915/display/intel_display_types.h
> > +++ b/drivers/gpu/drm/i915/display/intel_display_types.h
> > @@ -1202,6 +1202,7 @@ struct intel_crtc_state {
> >  	bool has_psr2;
> >  	bool enable_psr2_sel_fetch;
> >  	bool req_psr2_sdp_prior_scanline;
> > +	bool has_panel_replay;
> >  	bool wm_level_disabled;
> >  	u32 dc3co_exitline;
> >  	u16 su_y_granularity;
> > @@ -1693,6 +1694,8 @@ struct intel_psr {
> >  	bool irq_aux_error;
> >  	u16 su_w_granularity;
> >  	u16 su_y_granularity;
> > +	bool source_panel_replay_support;
> > +	bool sink_panel_replay_support;
> >  	u32 dc3co_exitline;
> >  	u32 dc3co_exit_delay;
> >  	struct delayed_work dc3co_work;
> > @@ -1983,12 +1986,15 @@ dp_to_lspcon(struct intel_dp *intel_dp)
> > #define CAN_PSR(intel_dp) ((intel_dp)->psr.sink_support && \
> >  			   (intel_dp)->psr.source_support)
> >
> > +#define CAN_PANEL_REPLAY(intel_dp) ((intel_dp)-
> >psr.sink_panel_replay_support && \
> > +			  (intel_dp)->psr.source_panel_replay_support)
> > +
> >  static inline bool intel_encoder_can_psr(struct intel_encoder
> > *encoder)  {
> > -	if (!intel_encoder_is_dp(encoder))
> > +	if (intel_encoder_is_dp(encoder) || (encoder->type ==
> INTEL_OUTPUT_DP_MST))
> > +		return CAN_PSR(enc_to_intel_dp(encoder)) ||
> CAN_PANEL_REPLAY(enc_to_intel_dp(encoder));
> > +	else
> >  		return false;
> > -
> > -	return CAN_PSR(enc_to_intel_dp(encoder));
> >  }
> 
> The whole function and macros should live in intel_psr.c as proper functions.
> 
> >
> >  static inline struct intel_digital_port * diff --git
> > a/drivers/gpu/drm/i915/display/intel_dp.c
> > b/drivers/gpu/drm/i915/display/intel_dp.c
> > index 7067ee3a4bd3..b3301cf0da0a 100644
> > --- a/drivers/gpu/drm/i915/display/intel_dp.c
> > +++ b/drivers/gpu/drm/i915/display/intel_dp.c
> > @@ -2337,12 +2337,22 @@ static void
> intel_dp_compute_vsc_colorimetry(const struct intel_crtc_state *crtc
> >  	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
> >  	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> >
> > -	/*
> > -	 * Prepare VSC Header for SU as per DP 1.4 spec, Table 2-118
> > -	 * VSC SDP supporting 3D stereo, PSR2, and Pixel Encoding/
> > -	 * Colorimetry Format indication.
> > -	 */
> > -	vsc->revision = 0x5;
> > +	if (crtc_state->has_panel_replay) {
> > +		/*
> > +		 * Prepare VSC Header for SU as per DP 2.0 spec, Table 2-223
> > +		 * VSC SDP supporting 3D stereo, Panel Replay, and Pixel
> > +		 * Encoding/Colorimetry Format indication.
> > +		 */
> > +		vsc->revision = 0x7;
> > +	} else {
> > +		/*
> > +		 * Prepare VSC Header for SU as per DP 1.4 spec, Table 2-118
> > +		 * VSC SDP supporting 3D stereo, PSR2, and Pixel Encoding/
> > +		 * Colorimetry Format indication.
> > +		 */
> > +		vsc->revision = 0x5;
> > +	}
> > +
> >  	vsc->length = 0x13;
> >
> >  	/* DP 1.4a spec, Table 2-120 */
> > @@ -2451,6 +2461,21 @@ void intel_dp_compute_psr_vsc_sdp(struct
> intel_dp *intel_dp,
> >  			vsc->revision = 0x4;
> >  			vsc->length = 0xe;
> >  		}
> > +	} else if (crtc_state->has_panel_replay) {
> > +		if (intel_dp->psr.colorimetry_support &&
> > +		    intel_dp_needs_vsc_sdp(crtc_state, conn_state)) {
> > +			/* [Panel Replay with colorimetry info] */
> > +			intel_dp_compute_vsc_colorimetry(crtc_state,
> conn_state,
> > +							 vsc);
> > +		} else {
> > +			/*
> > +			 * [Panel Replay without colorimetry info]
> > +			 * Prepare VSC Header for SU as per DP 2.0 spec,
> Table 2-223
> > +			 * VSC SDP supporting 3D stereo + Panel Replay.
> > +			 */
> > +			vsc->revision = 0x6;
> > +			vsc->length = 0x10;
> > +		}
> >  	} else {
> >  		/*
> >  		 * [PSR1]
> > @@ -3744,10 +3769,11 @@ static ssize_t intel_dp_vsc_sdp_pack(const
> struct drm_dp_vsc_sdp *vsc,
> >  	sdp->sdp_header.HB3 = vsc->length; /* Number of Valid Data Bytes */
> >
> >  	/*
> > -	 * Only revision 0x5 supports Pixel Encoding/Colorimetry Format as
> > -	 * per DP 1.4a spec.
> > +	 * Other than revision 0x5 which supports Pixel Encoding/Colorimetry
> > +	 * Format as per DP 1.4a spec, revision 0x7 also supports Pixel
> > +	 * Encoding/Colorimetry Format as per DP 2.0 spec.
> >  	 */
> > -	if (vsc->revision != 0x5)
> > +	if (vsc->revision != 0x5 || vsc->revision != 0x7)
> >  		goto out;
> >
> >  	/* VSC SDP Payload for DB16 through DB18 */ diff --git
> > a/drivers/gpu/drm/i915/display/intel_dp_mst.c
> > b/drivers/gpu/drm/i915/display/intel_dp_mst.c
> > index 3eb085fbc7c8..07a3ab473be2 100644
> > --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c
> > +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c
> > @@ -44,6 +44,7 @@
> >  #include "intel_hdcp.h"
> >  #include "intel_hotplug.h"
> >  #include "skl_scaler.h"
> > +#include "intel_psr.h"
> 
> Please keep these sorted.

Sure.

> 
> >
> >  static int intel_dp_mst_check_constraints(struct drm_i915_private *i915, int
> bpp,
> >  					  const struct drm_display_mode
> *adjusted_mode, @@ -398,6 +399,8
> > @@ static int intel_dp_mst_compute_config(struct intel_encoder
> > *encoder,
> >
> >  	intel_ddi_compute_min_voltage_level(dev_priv, pipe_config);
> >
> > +	intel_psr_compute_config(intel_dp, pipe_config, conn_state);
> > +
> >  	return 0;
> >  }
> >
> > diff --git a/drivers/gpu/drm/i915/display/intel_psr.c
> > b/drivers/gpu/drm/i915/display/intel_psr.c
> > index b1c0494826f9..8dd61c62492d 100644
> > --- a/drivers/gpu/drm/i915/display/intel_psr.c
> > +++ b/drivers/gpu/drm/i915/display/intel_psr.c
> > @@ -472,6 +472,24 @@ static void intel_dp_get_su_granularity(struct
> intel_dp *intel_dp)
> >  	intel_dp->psr.su_y_granularity = y;
> >  }
> >
> > +static void _panel_replay_init_dpcd(struct intel_dp *intel_dp) {
> > +	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> > +	u8 pr_dpcd = 0;
> > +
> > +	drm_dp_dpcd_readb(&intel_dp->aux, DP_PANEL_REPLAY_CAP,
> &pr_dpcd);
> > +
> > +	if (!(pr_dpcd & DP_PANEL_REPLAY_SUPPORT)) {
> > +		drm_dbg_kms(&dev_priv->drm,
> > +			    "Panel replay is not supported by panel\n");
> > +		return;
> > +	}
> > +
> > +	drm_dbg_kms(&dev_priv->drm,
> > +		    "Panel replay is supported by panel\n");
> > +	intel_dp->psr.sink_panel_replay_support = true;
> 
> This is not eDP so clearing the cached value matters. I don't see this cleared
> anywhere.

Sure, will reset the flag in encoder->detect(). Thanks for catching it.

Regards,
Animesh

> 
> > +}
> > +
> >  static void _psr_init_dpcd(struct intel_dp *intel_dp)  {
> >  	struct drm_i915_private *i915 =
> > @@ -521,12 +539,13 @@ static void _psr_init_dpcd(struct intel_dp
> > *intel_dp)
> >
> >  void intel_psr_init_dpcd(struct intel_dp *intel_dp)  {
> > +	_panel_replay_init_dpcd(intel_dp);
> > +
> >  	drm_dp_dpcd_read(&intel_dp->aux, DP_PSR_SUPPORT, intel_dp-
> >psr_dpcd,
> >  			 sizeof(intel_dp->psr_dpcd));
> >
> >  	if (intel_dp->psr_dpcd[0])
> >  		_psr_init_dpcd(intel_dp);
> > -	/* TODO: Add PR case here */
> >
> >  	if (intel_dp->psr.sink_psr2_support) {
> >  		intel_dp->psr.colorimetry_support = @@ -1207,13 +1226,11
> @@ static
> > bool intel_psr2_config_valid(struct intel_dp *intel_dp,
> >  	return false;
> >  }
> >
> > -void intel_psr_compute_config(struct intel_dp *intel_dp,
> > -			      struct intel_crtc_state *crtc_state,
> > -			      struct drm_connector_state *conn_state)
> > +static bool _psr_compute_config(struct intel_dp *intel_dp,
> > +				struct intel_crtc_state *crtc_state)
> >  {
> >  	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> > -	const struct drm_display_mode *adjusted_mode =
> > -		&crtc_state->hw.adjusted_mode;
> > +	const struct drm_display_mode *adjusted_mode =
> > +&crtc_state->hw.adjusted_mode;
> >  	int psr_setup_time;
> >
> >  	/*
> > @@ -1221,10 +1238,36 @@ void intel_psr_compute_config(struct intel_dp
> *intel_dp,
> >  	 * So if VRR is enabled, do not enable PSR.
> >  	 */
> >  	if (crtc_state->vrr.enable)
> > -		return;
> > +		return false;
> >
> >  	if (!CAN_PSR(intel_dp))
> > -		return;
> > +		return false;
> > +
> > +	psr_setup_time = drm_dp_psr_setup_time(intel_dp->psr_dpcd);
> > +	if (psr_setup_time < 0) {
> > +		drm_dbg_kms(&dev_priv->drm,
> > +			    "PSR condition failed: Invalid PSR setup time
> (0x%02x)\n",
> > +			    intel_dp->psr_dpcd[1]);
> > +		return false;
> > +	}
> > +
> > +	if (intel_usecs_to_scanlines(adjusted_mode, psr_setup_time) >
> > +	    adjusted_mode->crtc_vtotal - adjusted_mode->crtc_vdisplay - 1) {
> > +		drm_dbg_kms(&dev_priv->drm,
> > +			    "PSR condition failed: PSR setup time (%d us) too
> long\n",
> > +			    psr_setup_time);
> > +		return false;
> > +	}
> > +
> > +	return true;
> > +}
> > +
> > +void intel_psr_compute_config(struct intel_dp *intel_dp,
> > +			      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 =
> > +&crtc_state->hw.adjusted_mode;
> >
> >  	if (!psr_global_enabled(intel_dp)) {
> >  		drm_dbg_kms(&dev_priv->drm, "PSR disabled by flag\n");
> @@ -1234,7
> > +1277,6 @@ void intel_psr_compute_config(struct intel_dp *intel_dp,
> >  	if (intel_dp->psr.sink_not_reliable) {
> >  		drm_dbg_kms(&dev_priv->drm,
> >  			    "PSR sink implementation is not reliable\n");
> > -		return;
> >  	}
> >
> >  	if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) { @@ -
> 1243,23
> > +1285,11 @@ void intel_psr_compute_config(struct intel_dp *intel_dp,
> >  		return;
> >  	}
> >
> > -	psr_setup_time = drm_dp_psr_setup_time(intel_dp->psr_dpcd);
> > -	if (psr_setup_time < 0) {
> > -		drm_dbg_kms(&dev_priv->drm,
> > -			    "PSR condition failed: Invalid PSR setup time
> (0x%02x)\n",
> > -			    intel_dp->psr_dpcd[1]);
> > -		return;
> > -	}
> > -
> > -	if (intel_usecs_to_scanlines(adjusted_mode, psr_setup_time) >
> > -	    adjusted_mode->crtc_vtotal - adjusted_mode->crtc_vdisplay - 1) {
> > -		drm_dbg_kms(&dev_priv->drm,
> > -			    "PSR condition failed: PSR setup time (%d us) too
> long\n",
> > -			    psr_setup_time);
> > -		return;
> > -	}
> > +	if (CAN_PANEL_REPLAY(intel_dp))
> > +		crtc_state->has_panel_replay = true;
> > +	else
> > +		crtc_state->has_psr = _psr_compute_config(intel_dp,
> crtc_state);
> >
> > -	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);
> > @@ -2699,7 +2729,7 @@ void intel_psr_init(struct intel_dp *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);
> >
> > -	if (!HAS_PSR(dev_priv))
> > +	if (!(HAS_PSR(dev_priv) || HAS_PANEL_REPLAY(dev_priv)))
> >  		return;
> >
> >  	/*
> > @@ -2717,7 +2747,10 @@ void intel_psr_init(struct intel_dp *intel_dp)
> >  		return;
> >  	}
> >
> > -	intel_dp->psr.source_support = true;
> > +	if (HAS_PANEL_REPLAY(dev_priv) && !intel_dp_is_edp(intel_dp))
> > +		intel_dp->psr.source_panel_replay_support = true;
> > +	else
> > +		intel_dp->psr.source_support = true;
> >
> >  	/* Set link_standby x link_off defaults */
> >  	if (DISPLAY_VER(dev_priv) < 12)
> 
> --
> Jani Nikula, Intel Open Source Graphics Center
kernel test robot Aug. 26, 2023, 2:05 a.m. UTC | #3
Hi Animesh,

kernel test robot noticed the following build warnings:

[auto build test WARNING on drm-tip/drm-tip]

url:    https://github.com/intel-lab-lkp/linux/commits/Animesh-Manna/drm-panelreplay-dpcd-register-definition-for-panelreplay/20230824-122224
base:   git://anongit.freedesktop.org/drm/drm-tip drm-tip
patch link:    https://lore.kernel.org/r/20230824040952.186407-5-animesh.manna%40intel.com
patch subject: [Intel-gfx] [PATCH v4 4/6] drm/i915/panelreplay: Initializaton and compute config for panel replay
config: x86_64-rhel-8.3-rust (https://download.01.org/0day-ci/archive/20230826/202308260901.MphIjr2l-lkp@intel.com/config)
compiler: clang version 15.0.7 (https://github.com/llvm/llvm-project.git 8dfdcc7b7bf66834a761bd8de445840ef68e4d1a)
reproduce: (https://download.01.org/0day-ci/archive/20230826/202308260901.MphIjr2l-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202308260901.MphIjr2l-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> drivers/gpu/drm/i915/display/intel_dp.c:3776:27: warning: overlapping comparisons always evaluate to true [-Wtautological-overlap-compare]
           if (vsc->revision != 0x5 || vsc->revision != 0x7)
               ~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~
   1 warning generated.


vim +3776 drivers/gpu/drm/i915/display/intel_dp.c

  3751	
  3752	static ssize_t intel_dp_vsc_sdp_pack(const struct drm_dp_vsc_sdp *vsc,
  3753					     struct dp_sdp *sdp, size_t size)
  3754	{
  3755		size_t length = sizeof(struct dp_sdp);
  3756	
  3757		if (size < length)
  3758			return -ENOSPC;
  3759	
  3760		memset(sdp, 0, size);
  3761	
  3762		/*
  3763		 * Prepare VSC Header for SU as per DP 1.4a spec, Table 2-119
  3764		 * VSC SDP Header Bytes
  3765		 */
  3766		sdp->sdp_header.HB0 = 0; /* Secondary-Data Packet ID = 0 */
  3767		sdp->sdp_header.HB1 = vsc->sdp_type; /* Secondary-data Packet Type */
  3768		sdp->sdp_header.HB2 = vsc->revision; /* Revision Number */
  3769		sdp->sdp_header.HB3 = vsc->length; /* Number of Valid Data Bytes */
  3770	
  3771		/*
  3772		 * Other than revision 0x5 which supports Pixel Encoding/Colorimetry
  3773		 * Format as per DP 1.4a spec, revision 0x7 also supports Pixel
  3774		 * Encoding/Colorimetry Format as per DP 2.0 spec.
  3775		 */
> 3776		if (vsc->revision != 0x5 || vsc->revision != 0x7)
  3777			goto out;
  3778	
  3779		/* VSC SDP Payload for DB16 through DB18 */
  3780		/* Pixel Encoding and Colorimetry Formats  */
  3781		sdp->db[16] = (vsc->pixelformat & 0xf) << 4; /* DB16[7:4] */
  3782		sdp->db[16] |= vsc->colorimetry & 0xf; /* DB16[3:0] */
  3783	
  3784		switch (vsc->bpc) {
  3785		case 6:
  3786			/* 6bpc: 0x0 */
  3787			break;
  3788		case 8:
  3789			sdp->db[17] = 0x1; /* DB17[3:0] */
  3790			break;
  3791		case 10:
  3792			sdp->db[17] = 0x2;
  3793			break;
  3794		case 12:
  3795			sdp->db[17] = 0x3;
  3796			break;
  3797		case 16:
  3798			sdp->db[17] = 0x4;
  3799			break;
  3800		default:
  3801			MISSING_CASE(vsc->bpc);
  3802			break;
  3803		}
  3804		/* Dynamic Range and Component Bit Depth */
  3805		if (vsc->dynamic_range == DP_DYNAMIC_RANGE_CTA)
  3806			sdp->db[17] |= 0x80;  /* DB17[7] */
  3807	
  3808		/* Content Type */
  3809		sdp->db[18] = vsc->content_type & 0x7;
  3810	
  3811	out:
  3812		return length;
  3813	}
  3814
diff mbox series

Patch

diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index 731f2ec04d5c..97cef458f42b 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -1202,6 +1202,7 @@  struct intel_crtc_state {
 	bool has_psr2;
 	bool enable_psr2_sel_fetch;
 	bool req_psr2_sdp_prior_scanline;
+	bool has_panel_replay;
 	bool wm_level_disabled;
 	u32 dc3co_exitline;
 	u16 su_y_granularity;
@@ -1693,6 +1694,8 @@  struct intel_psr {
 	bool irq_aux_error;
 	u16 su_w_granularity;
 	u16 su_y_granularity;
+	bool source_panel_replay_support;
+	bool sink_panel_replay_support;
 	u32 dc3co_exitline;
 	u32 dc3co_exit_delay;
 	struct delayed_work dc3co_work;
@@ -1983,12 +1986,15 @@  dp_to_lspcon(struct intel_dp *intel_dp)
 #define CAN_PSR(intel_dp) ((intel_dp)->psr.sink_support && \
 			   (intel_dp)->psr.source_support)
 
+#define CAN_PANEL_REPLAY(intel_dp) ((intel_dp)->psr.sink_panel_replay_support && \
+			  (intel_dp)->psr.source_panel_replay_support)
+
 static inline bool intel_encoder_can_psr(struct intel_encoder *encoder)
 {
-	if (!intel_encoder_is_dp(encoder))
+	if (intel_encoder_is_dp(encoder) || (encoder->type == INTEL_OUTPUT_DP_MST))
+		return CAN_PSR(enc_to_intel_dp(encoder)) || CAN_PANEL_REPLAY(enc_to_intel_dp(encoder));
+	else
 		return false;
-
-	return CAN_PSR(enc_to_intel_dp(encoder));
 }
 
 static inline struct intel_digital_port *
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 7067ee3a4bd3..b3301cf0da0a 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -2337,12 +2337,22 @@  static void intel_dp_compute_vsc_colorimetry(const struct intel_crtc_state *crtc
 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
 
-	/*
-	 * Prepare VSC Header for SU as per DP 1.4 spec, Table 2-118
-	 * VSC SDP supporting 3D stereo, PSR2, and Pixel Encoding/
-	 * Colorimetry Format indication.
-	 */
-	vsc->revision = 0x5;
+	if (crtc_state->has_panel_replay) {
+		/*
+		 * Prepare VSC Header for SU as per DP 2.0 spec, Table 2-223
+		 * VSC SDP supporting 3D stereo, Panel Replay, and Pixel
+		 * Encoding/Colorimetry Format indication.
+		 */
+		vsc->revision = 0x7;
+	} else {
+		/*
+		 * Prepare VSC Header for SU as per DP 1.4 spec, Table 2-118
+		 * VSC SDP supporting 3D stereo, PSR2, and Pixel Encoding/
+		 * Colorimetry Format indication.
+		 */
+		vsc->revision = 0x5;
+	}
+
 	vsc->length = 0x13;
 
 	/* DP 1.4a spec, Table 2-120 */
@@ -2451,6 +2461,21 @@  void intel_dp_compute_psr_vsc_sdp(struct intel_dp *intel_dp,
 			vsc->revision = 0x4;
 			vsc->length = 0xe;
 		}
+	} else if (crtc_state->has_panel_replay) {
+		if (intel_dp->psr.colorimetry_support &&
+		    intel_dp_needs_vsc_sdp(crtc_state, conn_state)) {
+			/* [Panel Replay with colorimetry info] */
+			intel_dp_compute_vsc_colorimetry(crtc_state, conn_state,
+							 vsc);
+		} else {
+			/*
+			 * [Panel Replay without colorimetry info]
+			 * Prepare VSC Header for SU as per DP 2.0 spec, Table 2-223
+			 * VSC SDP supporting 3D stereo + Panel Replay.
+			 */
+			vsc->revision = 0x6;
+			vsc->length = 0x10;
+		}
 	} else {
 		/*
 		 * [PSR1]
@@ -3744,10 +3769,11 @@  static ssize_t intel_dp_vsc_sdp_pack(const struct drm_dp_vsc_sdp *vsc,
 	sdp->sdp_header.HB3 = vsc->length; /* Number of Valid Data Bytes */
 
 	/*
-	 * Only revision 0x5 supports Pixel Encoding/Colorimetry Format as
-	 * per DP 1.4a spec.
+	 * Other than revision 0x5 which supports Pixel Encoding/Colorimetry
+	 * Format as per DP 1.4a spec, revision 0x7 also supports Pixel
+	 * Encoding/Colorimetry Format as per DP 2.0 spec.
 	 */
-	if (vsc->revision != 0x5)
+	if (vsc->revision != 0x5 || vsc->revision != 0x7)
 		goto out;
 
 	/* VSC SDP Payload for DB16 through DB18 */
diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c
index 3eb085fbc7c8..07a3ab473be2 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c
@@ -44,6 +44,7 @@ 
 #include "intel_hdcp.h"
 #include "intel_hotplug.h"
 #include "skl_scaler.h"
+#include "intel_psr.h"
 
 static int intel_dp_mst_check_constraints(struct drm_i915_private *i915, int bpp,
 					  const struct drm_display_mode *adjusted_mode,
@@ -398,6 +399,8 @@  static int intel_dp_mst_compute_config(struct intel_encoder *encoder,
 
 	intel_ddi_compute_min_voltage_level(dev_priv, pipe_config);
 
+	intel_psr_compute_config(intel_dp, pipe_config, conn_state);
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c
index b1c0494826f9..8dd61c62492d 100644
--- a/drivers/gpu/drm/i915/display/intel_psr.c
+++ b/drivers/gpu/drm/i915/display/intel_psr.c
@@ -472,6 +472,24 @@  static void intel_dp_get_su_granularity(struct intel_dp *intel_dp)
 	intel_dp->psr.su_y_granularity = y;
 }
 
+static void _panel_replay_init_dpcd(struct intel_dp *intel_dp)
+{
+	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+	u8 pr_dpcd = 0;
+
+	drm_dp_dpcd_readb(&intel_dp->aux, DP_PANEL_REPLAY_CAP, &pr_dpcd);
+
+	if (!(pr_dpcd & DP_PANEL_REPLAY_SUPPORT)) {
+		drm_dbg_kms(&dev_priv->drm,
+			    "Panel replay is not supported by panel\n");
+		return;
+	}
+
+	drm_dbg_kms(&dev_priv->drm,
+		    "Panel replay is supported by panel\n");
+	intel_dp->psr.sink_panel_replay_support = true;
+}
+
 static void _psr_init_dpcd(struct intel_dp *intel_dp)
 {
 	struct drm_i915_private *i915 =
@@ -521,12 +539,13 @@  static void _psr_init_dpcd(struct intel_dp *intel_dp)
 
 void intel_psr_init_dpcd(struct intel_dp *intel_dp)
 {
+	_panel_replay_init_dpcd(intel_dp);
+
 	drm_dp_dpcd_read(&intel_dp->aux, DP_PSR_SUPPORT, intel_dp->psr_dpcd,
 			 sizeof(intel_dp->psr_dpcd));
 
 	if (intel_dp->psr_dpcd[0])
 		_psr_init_dpcd(intel_dp);
-	/* TODO: Add PR case here */
 
 	if (intel_dp->psr.sink_psr2_support) {
 		intel_dp->psr.colorimetry_support =
@@ -1207,13 +1226,11 @@  static bool intel_psr2_config_valid(struct intel_dp *intel_dp,
 	return false;
 }
 
-void intel_psr_compute_config(struct intel_dp *intel_dp,
-			      struct intel_crtc_state *crtc_state,
-			      struct drm_connector_state *conn_state)
+static bool _psr_compute_config(struct intel_dp *intel_dp,
+				struct intel_crtc_state *crtc_state)
 {
 	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-	const struct drm_display_mode *adjusted_mode =
-		&crtc_state->hw.adjusted_mode;
+	const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
 	int psr_setup_time;
 
 	/*
@@ -1221,10 +1238,36 @@  void intel_psr_compute_config(struct intel_dp *intel_dp,
 	 * So if VRR is enabled, do not enable PSR.
 	 */
 	if (crtc_state->vrr.enable)
-		return;
+		return false;
 
 	if (!CAN_PSR(intel_dp))
-		return;
+		return false;
+
+	psr_setup_time = drm_dp_psr_setup_time(intel_dp->psr_dpcd);
+	if (psr_setup_time < 0) {
+		drm_dbg_kms(&dev_priv->drm,
+			    "PSR condition failed: Invalid PSR setup time (0x%02x)\n",
+			    intel_dp->psr_dpcd[1]);
+		return false;
+	}
+
+	if (intel_usecs_to_scanlines(adjusted_mode, psr_setup_time) >
+	    adjusted_mode->crtc_vtotal - adjusted_mode->crtc_vdisplay - 1) {
+		drm_dbg_kms(&dev_priv->drm,
+			    "PSR condition failed: PSR setup time (%d us) too long\n",
+			    psr_setup_time);
+		return false;
+	}
+
+	return true;
+}
+
+void intel_psr_compute_config(struct intel_dp *intel_dp,
+			      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 = &crtc_state->hw.adjusted_mode;
 
 	if (!psr_global_enabled(intel_dp)) {
 		drm_dbg_kms(&dev_priv->drm, "PSR disabled by flag\n");
@@ -1234,7 +1277,6 @@  void intel_psr_compute_config(struct intel_dp *intel_dp,
 	if (intel_dp->psr.sink_not_reliable) {
 		drm_dbg_kms(&dev_priv->drm,
 			    "PSR sink implementation is not reliable\n");
-		return;
 	}
 
 	if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
@@ -1243,23 +1285,11 @@  void intel_psr_compute_config(struct intel_dp *intel_dp,
 		return;
 	}
 
-	psr_setup_time = drm_dp_psr_setup_time(intel_dp->psr_dpcd);
-	if (psr_setup_time < 0) {
-		drm_dbg_kms(&dev_priv->drm,
-			    "PSR condition failed: Invalid PSR setup time (0x%02x)\n",
-			    intel_dp->psr_dpcd[1]);
-		return;
-	}
-
-	if (intel_usecs_to_scanlines(adjusted_mode, psr_setup_time) >
-	    adjusted_mode->crtc_vtotal - adjusted_mode->crtc_vdisplay - 1) {
-		drm_dbg_kms(&dev_priv->drm,
-			    "PSR condition failed: PSR setup time (%d us) too long\n",
-			    psr_setup_time);
-		return;
-	}
+	if (CAN_PANEL_REPLAY(intel_dp))
+		crtc_state->has_panel_replay = true;
+	else
+		crtc_state->has_psr = _psr_compute_config(intel_dp, crtc_state);
 
-	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);
@@ -2699,7 +2729,7 @@  void intel_psr_init(struct intel_dp *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);
 
-	if (!HAS_PSR(dev_priv))
+	if (!(HAS_PSR(dev_priv) || HAS_PANEL_REPLAY(dev_priv)))
 		return;
 
 	/*
@@ -2717,7 +2747,10 @@  void intel_psr_init(struct intel_dp *intel_dp)
 		return;
 	}
 
-	intel_dp->psr.source_support = true;
+	if (HAS_PANEL_REPLAY(dev_priv) && !intel_dp_is_edp(intel_dp))
+		intel_dp->psr.source_panel_replay_support = true;
+	else
+		intel_dp->psr.source_support = true;
 
 	/* Set link_standby x link_off defaults */
 	if (DISPLAY_VER(dev_priv) < 12)