[Intel-gfx] [PATCH 09/13] drm/i915: Stash DRRS state under intel_crtc

Souza, Jose jose.souza at intel.com
Thu Mar 10 17:45:49 UTC 2022


On Thu, 2022-03-10 at 02:47 +0200, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala at linux.intel.com>
> 
> Get rid of the ugly intel_dp dependency, and one more crtc->config
> usage by storing the DRRS state under intel_crtc. intel_drrs_enable()
> copies what it needs from the crtc state, after which DRRS can be
> blissfully ignorant of anything going on around it.
> 
> This also lets multiple pipes do DRRS simultanously and entirely
> independently.
> 
> Signed-off-by: Ville Syrjälä <ville.syrjala at linux.intel.com>
> ---
>  drivers/gpu/drm/i915/display/intel_crtc.c     |   2 +
>  drivers/gpu/drm/i915/display/intel_ddi.c      |   8 +-
>  drivers/gpu/drm/i915/display/intel_display.c  |   2 +-
>  .../drm/i915/display/intel_display_debugfs.c  |  97 ++----
>  .../drm/i915/display/intel_display_types.h    |  14 +
>  drivers/gpu/drm/i915/display/intel_dp.c       |   4 +-
>  drivers/gpu/drm/i915/display/intel_drrs.c     | 300 +++++++-----------
>  drivers/gpu/drm/i915/display/intel_drrs.h     |  20 +-
>  drivers/gpu/drm/i915/i915_drv.h               |  15 -
>  9 files changed, 171 insertions(+), 291 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c
> index 65827481c1b1..f655c1622877 100644
> --- a/drivers/gpu/drm/i915/display/intel_crtc.c
> +++ b/drivers/gpu/drm/i915/display/intel_crtc.c
> @@ -24,6 +24,7 @@
>  #include "intel_display_debugfs.h"
>  #include "intel_display_trace.h"
>  #include "intel_display_types.h"
> +#include "intel_drrs.h"
>  #include "intel_dsi.h"
>  #include "intel_pipe_crc.h"
>  #include "intel_psr.h"
> @@ -367,6 +368,7 @@ int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe)
>  
>  	intel_color_init(crtc);
>  
> +	intel_crtc_drrs_init(crtc);
>  	intel_crtc_crc_init(crtc);
>  
>  	cpu_latency_qos_add_request(&crtc->vblank_pm_qos, PM_QOS_DEFAULT_VALUE);
> diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
> index 3e6d86a54850..a3bf4e876fb4 100644
> --- a/drivers/gpu/drm/i915/display/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/display/intel_ddi.c
> @@ -2820,7 +2820,7 @@ static void intel_enable_ddi_dp(struct intel_atomic_state *state,
>  	if (!dig_port->lspcon.active || dig_port->dp.has_hdmi_sink)
>  		intel_dp_set_infoframes(encoder, true, crtc_state, conn_state);
>  
> -	intel_drrs_enable(intel_dp, crtc_state);
> +	intel_drrs_enable(crtc_state);
>  
>  	if (crtc_state->has_audio)
>  		intel_audio_codec_enable(encoder, crtc_state, conn_state);
> @@ -2963,7 +2963,7 @@ static void intel_disable_ddi_dp(struct intel_atomic_state *state,
>  		intel_audio_codec_disable(encoder,
>  					  old_crtc_state, old_conn_state);
>  
> -	intel_drrs_disable(intel_dp, old_crtc_state);
> +	intel_drrs_disable(old_crtc_state);
>  	intel_psr_disable(intel_dp, old_crtc_state);
>  	intel_edp_backlight_off(old_conn_state);
>  	/* Disable the decompression in DP Sink */
> @@ -3013,12 +3013,12 @@ static void intel_ddi_update_pipe_dp(struct intel_atomic_state *state,
>  				     const struct intel_crtc_state *crtc_state,
>  				     const struct drm_connector_state *conn_state)
>  {
> -	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
> +	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
>  
>  	intel_ddi_set_dp_msa(crtc_state, conn_state);
>  
>  	intel_dp_set_infoframes(encoder, true, crtc_state, conn_state);
> -	intel_drrs_update(intel_dp, crtc_state);
> +	intel_drrs_update(state, crtc);
>  
>  	intel_backlight_update(state, encoder, crtc_state, conn_state);
>  	drm_connector_update_privacy_screen(conn_state);
> diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
> index b7c418677372..4c7c74665819 100644
> --- a/drivers/gpu/drm/i915/display/intel_display.c
> +++ b/drivers/gpu/drm/i915/display/intel_display.c
> @@ -1229,7 +1229,7 @@ static void intel_post_plane_update(struct intel_atomic_state *state,
>  
>  	hsw_ips_post_update(state, crtc);
>  	intel_fbc_post_update(state, crtc);
> -	intel_drrs_page_flip(state, crtc);
> +	intel_drrs_page_flip(crtc);
>  
>  	if (needs_async_flip_vtd_wa(old_crtc_state) &&
>  	    !needs_async_flip_vtd_wa(new_crtc_state))
> diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> index 798bf233a60f..bbf6ebd18414 100644
> --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
> @@ -1143,87 +1143,44 @@ static int i915_ddb_info(struct seq_file *m, void *unused)
>  	return 0;
>  }
>  
> -static void drrs_status_per_crtc(struct seq_file *m,
> -				 struct drm_device *dev,
> -				 struct intel_crtc *crtc)
> +static int i915_drrs_status(struct seq_file *m, void *unused)
>  {
> -	struct drm_i915_private *dev_priv = to_i915(dev);
> -	struct i915_drrs *drrs = &dev_priv->drrs;
> -	struct drm_connector *connector;
> +	struct drm_i915_private *dev_priv = node_to_i915(m->private);
>  	struct drm_connector_list_iter conn_iter;
> +	struct intel_connector *connector;
> +	struct intel_crtc *crtc;
>  
> -	drm_connector_list_iter_begin(dev, &conn_iter);
> -	drm_for_each_connector_iter(connector, &conn_iter) {
> -		bool supported = false;
> +	drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter);
> +	for_each_intel_connector_iter(connector, &conn_iter) {
> +		seq_printf(m, "[CONNECTOR:%d:%s]:\n",
> +			   connector->base.base.id, connector->base.name);
>  
> -		if (connector->state->crtc != &crtc->base)
> -			continue;
> -
> -		seq_printf(m, "%s:\n", connector->name);
> -
> -		if (connector->connector_type == DRM_MODE_CONNECTOR_eDP &&
> -		    drrs->type == DRRS_TYPE_SEAMLESS)
> -			supported = true;
> -
> -		seq_printf(m, "\tDRRS Supported: %s\n", str_yes_no(supported));
> +		seq_printf(m, "\tDRRS Supported: %s\n",
> +			   str_yes_no(connector->panel.downclock_mode));
>  	}
>  	drm_connector_list_iter_end(&conn_iter);
>  
>  	seq_puts(m, "\n");
>  
> -	if (to_intel_crtc_state(crtc->base.state)->has_drrs) {
> -		struct intel_panel *panel;
> +	for_each_intel_crtc(&dev_priv->drm, crtc) {
> +		seq_printf(m, "[CRTC:%d:%s]:\n",
> +			   crtc->base.base.id, crtc->base.name);
> +
> +		mutex_lock(&crtc->drrs.mutex);
>  
> -		mutex_lock(&drrs->mutex);
>  		/* DRRS Supported */
> -		seq_puts(m, "\tDRRS Enabled: Yes\n");
> +		seq_printf(m, "\tDRRS Enabled: %s\n",
> +			   str_yes_no(intel_drrs_is_enabled(crtc)));
>  
> -		/* disable_drrs() will make drrs->dp NULL */
> -		if (!drrs->dp) {
> -			seq_puts(m, "Idleness DRRS: Disabled\n");
> -			mutex_unlock(&drrs->mutex);
> -			return;
> -		}
> -
> -		panel = &drrs->dp->attached_connector->panel;
> -		seq_printf(m, "\t\tBusy_frontbuffer_bits: 0x%X",
> -					drrs->busy_frontbuffer_bits);
> -
> -		seq_puts(m, "\n\t\t");
> +		seq_printf(m, "\tBusy_frontbuffer_bits: 0x%X",
> +			   crtc->drrs.busy_frontbuffer_bits);
>  
>  		seq_printf(m, "DRRS refresh rate: %s\n",
> -			   drrs->refresh_rate == DRRS_REFRESH_RATE_LOW ?
> +			   crtc->drrs.refresh_rate == DRRS_REFRESH_RATE_LOW ?
>  			   "low" : "high");
> -		seq_puts(m, "\n\t\t");
>  
> -		mutex_unlock(&drrs->mutex);
> -	} else {
> -		/* DRRS not supported. Print the VBT parameter*/
> -		seq_puts(m, "\tDRRS Enabled : No");
> +		mutex_unlock(&crtc->drrs.mutex);
>  	}
> -	seq_puts(m, "\n");
> -}
> -
> -static int i915_drrs_status(struct seq_file *m, void *unused)
> -{
> -	struct drm_i915_private *dev_priv = node_to_i915(m->private);
> -	struct drm_device *dev = &dev_priv->drm;
> -	struct intel_crtc *crtc;
> -	int active_crtc_cnt = 0;
> -
> -	drm_modeset_lock_all(dev);
> -	for_each_intel_crtc(dev, crtc) {
> -		if (crtc->base.state->active) {
> -			active_crtc_cnt++;
> -			seq_printf(m, "\nCRTC %d:  ", active_crtc_cnt);
> -
> -			drrs_status_per_crtc(m, dev, crtc);
> -		}
> -	}
> -	drm_modeset_unlock_all(dev);
> -
> -	if (!active_crtc_cnt)
> -		seq_puts(m, "No active crtc found\n");
>  
>  	return 0;
>  }
> @@ -1917,26 +1874,18 @@ static int i915_drrs_ctl_set(void *data, u64 val)
>  
>  		drm_connector_list_iter_begin(dev, &conn_iter);
>  		drm_for_each_connector_iter(connector, &conn_iter) {
> -			struct intel_encoder *encoder;
> -			struct intel_dp *intel_dp;
> -
>  			if (!(crtc_state->uapi.connector_mask &
>  			      drm_connector_mask(connector)))
>  				continue;
>  
> -			encoder = intel_attached_encoder(to_intel_connector(connector));
> -			if (encoder->type != INTEL_OUTPUT_EDP)
> -				continue;
> -
>  			drm_dbg(&dev_priv->drm,
>  				"Manually %sabling DRRS. %llu\n",
>  				val ? "en" : "dis", val);
>  
> -			intel_dp = enc_to_intel_dp(encoder);
>  			if (val)
> -				intel_drrs_enable(intel_dp, crtc_state);
> +				intel_drrs_enable(crtc_state);
>  			else
> -				intel_drrs_disable(intel_dp, crtc_state);
> +				intel_drrs_disable(crtc_state);
>  		}
>  		drm_connector_list_iter_end(&conn_iter);
>  
> diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
> index 86b2fa675124..e34800ab6924 100644
> --- a/drivers/gpu/drm/i915/display/intel_display_types.h
> +++ b/drivers/gpu/drm/i915/display/intel_display_types.h
> @@ -1252,6 +1252,11 @@ enum intel_pipe_crc_source {
>  	INTEL_PIPE_CRC_SOURCE_MAX,
>  };
>  
> +enum drrs_refresh_rate {
> +	DRRS_REFRESH_RATE_HIGH,
> +	DRRS_REFRESH_RATE_LOW,
> +};
> +
>  #define INTEL_PIPE_CRC_ENTRIES_NR	128
>  struct intel_pipe_crc {
>  	spinlock_t lock;
> @@ -1294,6 +1299,15 @@ struct intel_crtc {
>  		} active;
>  	} wm;
>  
> +	struct {
> +		struct mutex mutex;
> +		struct delayed_work work;
> +		enum drrs_refresh_rate refresh_rate;
> +		unsigned int busy_frontbuffer_bits;
> +		enum transcoder cpu_transcoder;
> +		struct intel_link_m_n m_n, m2_n2;
> +	} drrs;
> +
>  	int scanline_offset;
>  
>  	struct {
> diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
> index 619546441eae..725c3350c923 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp.c
> @@ -1895,8 +1895,8 @@ intel_dp_compute_config(struct intel_encoder *encoder,
>  
>  	intel_vrr_compute_config(pipe_config, conn_state);
>  	intel_psr_compute_config(intel_dp, pipe_config, conn_state);
> -	intel_drrs_compute_config(intel_dp, pipe_config, output_bpp,
> -				  constant_n);
> +	intel_drrs_compute_config(pipe_config, intel_connector,
> +				  output_bpp, constant_n);
>  	intel_dp_compute_vsc_sdp(intel_dp, pipe_config, conn_state);
>  	intel_dp_compute_hdr_metadata_infoframe_sdp(intel_dp, pipe_config, conn_state);
>  
> diff --git a/drivers/gpu/drm/i915/display/intel_drrs.c b/drivers/gpu/drm/i915/display/intel_drrs.c
> index c97b5dee8cae..246dd0c71194 100644
> --- a/drivers/gpu/drm/i915/display/intel_drrs.c
> +++ b/drivers/gpu/drm/i915/display/intel_drrs.c
> @@ -65,15 +65,14 @@ static bool can_enable_drrs(struct intel_connector *connector,
>  		return false;
>  
>  	return connector->panel.downclock_mode &&
> -		i915->drrs.type == DRRS_TYPE_SEAMLESS;
> +		i915->vbt.drrs_type == DRRS_TYPE_SEAMLESS;
>  }
>  
>  void
> -intel_drrs_compute_config(struct intel_dp *intel_dp,
> -			  struct intel_crtc_state *pipe_config,
> +intel_drrs_compute_config(struct intel_crtc_state *pipe_config,
> +			  struct intel_connector *connector,
>  			  int output_bpp, bool constant_n)
>  {
> -	struct intel_connector *connector = intel_dp->attached_connector;
>  	struct drm_i915_private *i915 = to_i915(connector->base.dev);
>  	int pixel_clock;
>  
> @@ -102,12 +101,11 @@ intel_drrs_compute_config(struct intel_dp *intel_dp,
>  }
>  
>  static void
> -intel_drrs_set_refresh_rate_pipeconf(const struct intel_crtc_state *crtc_state,
> +intel_drrs_set_refresh_rate_pipeconf(struct intel_crtc *crtc,
>  				     enum drrs_refresh_rate refresh_rate)
>  {
> -	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
>  	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> -	enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
> +	enum transcoder cpu_transcoder = crtc->drrs.cpu_transcoder;
>  	u32 val, bit;
>  
>  	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
> @@ -126,240 +124,166 @@ intel_drrs_set_refresh_rate_pipeconf(const struct intel_crtc_state *crtc_state,
>  }
>  
>  static void
> -intel_drrs_set_refresh_rate_m_n(const struct intel_crtc_state *crtc_state,
> +intel_drrs_set_refresh_rate_m_n(struct intel_crtc *crtc,
>  				enum drrs_refresh_rate refresh_rate)
>  {
> -	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
> -
> -	intel_cpu_transcoder_set_m1_n1(crtc, crtc_state->cpu_transcoder,
> +	intel_cpu_transcoder_set_m1_n1(crtc, crtc->drrs.cpu_transcoder,
>  				       refresh_rate == DRRS_REFRESH_RATE_LOW ?
> -				       &crtc_state->dp_m2_n2 : &crtc_state->dp_m_n);
> +				       &crtc->drrs.m2_n2 : &crtc->drrs.m_n);
>  }
>  
> -static void intel_drrs_set_state(struct drm_i915_private *dev_priv,
> -				 const struct intel_crtc_state *crtc_state,
> +bool intel_drrs_is_enabled(struct intel_crtc *crtc)
> +{
> +	return crtc->drrs.cpu_transcoder != INVALID_TRANSCODER;
> +}
> +
> +static void intel_drrs_set_state(struct intel_crtc *crtc,
>  				 enum drrs_refresh_rate refresh_rate)
>  {
> -	struct intel_dp *intel_dp = dev_priv->drrs.dp;
> -	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
> +	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
>  
> -	if (!intel_dp) {
> -		drm_dbg_kms(&dev_priv->drm, "DRRS not supported.\n");
> +	if (refresh_rate == crtc->drrs.refresh_rate)
>  		return;
> -	}
> -
> -	if (!crtc) {
> -		drm_dbg_kms(&dev_priv->drm,
> -			    "DRRS: intel_crtc not initialized\n");
> -		return;
> -	}
> -
> -	if (dev_priv->drrs.type != DRRS_TYPE_SEAMLESS) {
> -		drm_dbg_kms(&dev_priv->drm, "Only Seamless DRRS supported.\n");
> -		return;
> -	}
> -
> -	if (refresh_rate == dev_priv->drrs.refresh_rate)
> -		return;
> -
> -	if (!crtc_state->hw.active) {
> -		drm_dbg_kms(&dev_priv->drm,
> -			    "eDP encoder disabled. CRTC not Active\n");
> -		return;
> -	}
>  
>  	if (DISPLAY_VER(dev_priv) >= 8 && !IS_CHERRYVIEW(dev_priv))
> -		intel_drrs_set_refresh_rate_m_n(crtc_state, refresh_rate);
> +		intel_drrs_set_refresh_rate_m_n(crtc, refresh_rate);
>  	else if (DISPLAY_VER(dev_priv) > 6)
> -		intel_drrs_set_refresh_rate_pipeconf(crtc_state, refresh_rate);
> +		intel_drrs_set_refresh_rate_pipeconf(crtc, refresh_rate);
>  
> -	dev_priv->drrs.refresh_rate = refresh_rate;
> -
> -	drm_dbg_kms(&dev_priv->drm, "eDP Refresh Rate set to : %s\n",
> -		    refresh_rate == DRRS_REFRESH_RATE_LOW ? "low" : "high");
> -}
> -
> -static void
> -intel_drrs_enable_locked(struct intel_dp *intel_dp)
> -{
> -	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> -
> -	dev_priv->drrs.busy_frontbuffer_bits = 0;
> -	dev_priv->drrs.dp = intel_dp;
> +	crtc->drrs.refresh_rate = refresh_rate;
>  }
>  
>  /**
>   * intel_drrs_enable - init drrs struct if supported
> - * @intel_dp: DP struct
>   * @crtc_state: A pointer to the active crtc state.
>   *
>   * Initializes frontbuffer_bits and drrs.dp
>   */
> -void intel_drrs_enable(struct intel_dp *intel_dp,
> -		       const struct intel_crtc_state *crtc_state)
> +void intel_drrs_enable(const struct intel_crtc_state *crtc_state)
>  {
> -	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> +	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
> +	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
>  
>  	if (!crtc_state->has_drrs)
>  		return;
>  
> -	drm_dbg_kms(&dev_priv->drm, "Enabling DRRS\n");
> +	drm_dbg_kms(&dev_priv->drm, "[CRTC:%d:%s] Enabling DRRS\n",
> +		    crtc->base.base.id, crtc->base.name);
>  
> -	mutex_lock(&dev_priv->drrs.mutex);
> +	mutex_lock(&crtc->drrs.mutex);
>  
> -	if (dev_priv->drrs.dp) {
> -		drm_warn(&dev_priv->drm, "DRRS already enabled\n");
> -		goto unlock;
> -	}
> +	crtc->drrs.cpu_transcoder = crtc_state->cpu_transcoder;
> +	crtc->drrs.m_n = crtc_state->dp_m_n;
> +	crtc->drrs.m2_n2 = crtc_state->dp_m2_n2;
> +	crtc->drrs.busy_frontbuffer_bits = 0;
>  
> -	intel_drrs_enable_locked(intel_dp);
> -
> -unlock:
> -	mutex_unlock(&dev_priv->drrs.mutex);
> -}
> -
> -static void
> -intel_drrs_disable_locked(struct intel_dp *intel_dp,
> -			  const struct intel_crtc_state *crtc_state)
> -{
> -	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> -
> -	intel_drrs_set_state(dev_priv, crtc_state, DRRS_REFRESH_RATE_HIGH);
> -	dev_priv->drrs.dp = NULL;
> +	mutex_unlock(&crtc->drrs.mutex);
>  }
>  
>  /**
>   * intel_drrs_disable - Disable DRRS
> - * @intel_dp: DP struct
> - * @old_crtc_state: Pointer to old crtc_state.
> + * @old_crtc_state: old crtc_state.
>   *
>   */
> -void intel_drrs_disable(struct intel_dp *intel_dp,
> -			const struct intel_crtc_state *old_crtc_state)
> +void intel_drrs_disable(const struct intel_crtc_state *old_crtc_state)
>  {
> -	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> +	struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc);
> +	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
>  
>  	if (!old_crtc_state->has_drrs)
>  		return;
>  
> -	mutex_lock(&dev_priv->drrs.mutex);
> -	if (!dev_priv->drrs.dp) {
> -		mutex_unlock(&dev_priv->drrs.mutex);
> -		return;
> -	}
> +	drm_dbg_kms(&dev_priv->drm, "[CRTC:%d:%s] Disabling DRRS\n",
> +		    crtc->base.base.id, crtc->base.name);
>  
> -	intel_drrs_disable_locked(intel_dp, old_crtc_state);
> -	mutex_unlock(&dev_priv->drrs.mutex);
> +	mutex_lock(&crtc->drrs.mutex);
>  
> -	cancel_delayed_work_sync(&dev_priv->drrs.work);
> +	if (intel_drrs_is_enabled(crtc))
> +		intel_drrs_set_state(crtc, DRRS_REFRESH_RATE_HIGH);
> +
> +	crtc->drrs.cpu_transcoder = INVALID_TRANSCODER;
> +	crtc->drrs.busy_frontbuffer_bits = 0;
> +
> +	mutex_unlock(&crtc->drrs.mutex);
> +
> +	cancel_delayed_work_sync(&crtc->drrs.work);
>  }
>  
>  /**
> - * intel_drrs_update - Update DRRS state
> - * @intel_dp: Intel DP
> - * @crtc_state: new CRTC state
> - *
> - * This function will update DRRS states, disabling or enabling DRRS when
> - * executing fastsets. For full modeset, intel_drrs_disable() and
> - * intel_drrs_enable() should be called instead.
> + * intel_drrs_update - Update DRRS during fastset
> + * @state: atomic state
> + * @crtc: crtc
>   */
> -void
> -intel_drrs_update(struct intel_dp *intel_dp,
> -		  const struct intel_crtc_state *crtc_state)
> +void intel_drrs_update(struct intel_atomic_state *state,
> +		       struct intel_crtc *crtc)
>  {
> -	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> +	const struct intel_crtc_state *old_crtc_state =
> +		intel_atomic_get_old_crtc_state(state, crtc);
> +	const struct intel_crtc_state *new_crtc_state =
> +		intel_atomic_get_new_crtc_state(state, crtc);
>  
> -	if (dev_priv->drrs.type != DRRS_TYPE_SEAMLESS)
> +	if (old_crtc_state->has_drrs == new_crtc_state->has_drrs)
>  		return;
>  
> -	mutex_lock(&dev_priv->drrs.mutex);
> -
> -	/* New state matches current one? */
> -	if (crtc_state->has_drrs == !!dev_priv->drrs.dp)
> -		goto unlock;
> -
> -	if (crtc_state->has_drrs)
> -		intel_drrs_enable_locked(intel_dp);
> +	if (new_crtc_state->has_drrs)
> +		intel_drrs_enable(new_crtc_state);
>  	else
> -		intel_drrs_disable_locked(intel_dp, crtc_state);
> -
> -unlock:
> -	mutex_unlock(&dev_priv->drrs.mutex);
> +		intel_drrs_disable(old_crtc_state);
>  }
>  
>  static void intel_drrs_downclock_work(struct work_struct *work)
>  {
> -	struct drm_i915_private *dev_priv =
> -		container_of(work, typeof(*dev_priv), drrs.work.work);
> -	struct intel_dp *intel_dp;
> +	struct intel_crtc *crtc = container_of(work, typeof(*crtc), drrs.work.work);
>  
> -	mutex_lock(&dev_priv->drrs.mutex);
> +	mutex_lock(&crtc->drrs.mutex);
>  
> -	intel_dp = dev_priv->drrs.dp;
> +	if (intel_drrs_is_enabled(crtc) && !crtc->drrs.busy_frontbuffer_bits)
> +		intel_drrs_set_state(crtc, DRRS_REFRESH_RATE_LOW);
>  
> -	if (!intel_dp)
> -		goto unlock;
> -
> -	/*
> -	 * The delayed work can race with an invalidate hence we need to
> -	 * recheck.
> -	 */
> -
> -	if (!dev_priv->drrs.busy_frontbuffer_bits) {
> -		struct intel_crtc *crtc =
> -			to_intel_crtc(dp_to_dig_port(intel_dp)->base.base.crtc);
> -
> -		intel_drrs_set_state(dev_priv, crtc->config,
> -				     DRRS_REFRESH_RATE_LOW);
> -	}
> -
> -unlock:
> -	mutex_unlock(&dev_priv->drrs.mutex);
> +	mutex_unlock(&crtc->drrs.mutex);
>  }
>  
>  static void intel_drrs_frontbuffer_update(struct drm_i915_private *dev_priv,
>  					  unsigned int frontbuffer_bits,
>  					  bool invalidate)
>  {
> -	struct intel_dp *intel_dp;
> -	struct drm_crtc *crtc;
> -	enum pipe pipe;
> +	struct intel_crtc *crtc;
>  
> -	if (dev_priv->drrs.type != DRRS_TYPE_SEAMLESS)
> +	if (dev_priv->vbt.drrs_type != DRRS_TYPE_SEAMLESS)
>  		return;
>  
> -	cancel_delayed_work(&dev_priv->drrs.work);
> +	for_each_intel_crtc(&dev_priv->drm, crtc) {
> +		enum pipe pipe = crtc->pipe;
>  
> -	mutex_lock(&dev_priv->drrs.mutex);
> +		cancel_delayed_work(&crtc->drrs.work);

Not a good idea cancel work at this point, you could be canceling work even if CRTC of eDP is not being updated.


>  
> -	intel_dp = dev_priv->drrs.dp;
> -	if (!intel_dp) {
> -		mutex_unlock(&dev_priv->drrs.mutex);
> -		return;
> +		mutex_lock(&crtc->drrs.mutex);
> +
> +		if (!intel_drrs_is_enabled(crtc)) {
> +			mutex_unlock(&crtc->drrs.mutex);
> +			continue;
> +		}
> +
> +		frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe);
> +		if (invalidate)
> +			crtc->drrs.busy_frontbuffer_bits |= frontbuffer_bits;
> +		else
> +			crtc->drrs.busy_frontbuffer_bits &= ~frontbuffer_bits;
> +
> +		/* flush/invalidate means busy screen hence upclock */
> +		if (frontbuffer_bits)
> +			intel_drrs_set_state(crtc, DRRS_REFRESH_RATE_HIGH);
> +
> +		/*
> +		 * flush also means no more activity hence schedule downclock, if all
> +		 * other fbs are quiescent too
> +		 */
> +		if (!invalidate && !crtc->drrs.busy_frontbuffer_bits)
> +			schedule_delayed_work(&crtc->drrs.work,
> +					      msecs_to_jiffies(1000));
> +
> +		mutex_unlock(&crtc->drrs.mutex);
>  	}
> -
> -	crtc = dp_to_dig_port(intel_dp)->base.base.crtc;
> -	pipe = to_intel_crtc(crtc)->pipe;
> -
> -	frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe);
> -	if (invalidate)
> -		dev_priv->drrs.busy_frontbuffer_bits |= frontbuffer_bits;
> -	else
> -		dev_priv->drrs.busy_frontbuffer_bits &= ~frontbuffer_bits;
> -
> -	/* flush/invalidate means busy screen hence upclock */
> -	if (frontbuffer_bits)
> -		intel_drrs_set_state(dev_priv, to_intel_crtc(crtc)->config,
> -				     DRRS_REFRESH_RATE_HIGH);
> -
> -	/*
> -	 * flush also means no more activity hence schedule downclock, if all
> -	 * other fbs are quiescent too
> -	 */
> -	if (!invalidate && !dev_priv->drrs.busy_frontbuffer_bits)
> -		schedule_delayed_work(&dev_priv->drrs.work,
> -				      msecs_to_jiffies(1000));
> -	mutex_unlock(&dev_priv->drrs.mutex);
>  }
>  
>  /**
> @@ -396,22 +320,36 @@ void intel_drrs_flush(struct drm_i915_private *dev_priv,
>  	intel_drrs_frontbuffer_update(dev_priv, frontbuffer_bits, false);
>  }
>  
> -void intel_drrs_page_flip(struct intel_atomic_state *state,
> -			  struct intel_crtc *crtc)
> +void intel_drrs_page_flip(struct intel_crtc *crtc)
>  {
> -	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
> +	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
>  	unsigned int frontbuffer_bits = INTEL_FRONTBUFFER_ALL_MASK(crtc->pipe);
>  
>  	intel_drrs_frontbuffer_update(dev_priv, frontbuffer_bits, false);
>  }
>  
>  /**
> - * intel_drrs_init - Init basic DRRS work and mutex.
> + * intel_crtc_drrs_init - Init DRRS for CRTC
> + * @crtc: crtc
> + *
> + * This function is called only once at driver load to initialize basic
> + * DRRS stuff.
> + *
> + */
> +void intel_crtc_drrs_init(struct intel_crtc *crtc)
> +{
> +	INIT_DELAYED_WORK(&crtc->drrs.work, intel_drrs_downclock_work);
> +	mutex_init(&crtc->drrs.mutex);
> +	crtc->drrs.cpu_transcoder = INVALID_TRANSCODER;
> +}
> +
> +/**
> + * intel_drrs_init - Init DRRS for eDP connector
>   * @connector: eDP connector
>   * @fixed_mode: preferred mode of panel
>   *
> - * This function is  called only once at driver load to initialize basic
> - * DRRS stuff.
> + * This function is called only once at driver load to initialize
> + * DRRS support for the connector.
>   *
>   * Returns:
>   * Downclock mode if panel supports it, else return NULL.
> @@ -424,10 +362,7 @@ intel_drrs_init(struct intel_connector *connector,
>  {
>  	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
>  	struct intel_encoder *encoder = connector->encoder;
> -	struct drm_display_mode *downclock_mode = NULL;
> -
> -	INIT_DELAYED_WORK(&dev_priv->drrs.work, intel_drrs_downclock_work);
> -	mutex_init(&dev_priv->drrs.mutex);
> +	struct drm_display_mode *downclock_mode;
>  
>  	if (DISPLAY_VER(dev_priv) <= 6) {
>  		drm_dbg_kms(&dev_priv->drm,
> @@ -460,9 +395,6 @@ intel_drrs_init(struct intel_connector *connector,
>  		return NULL;
>  	}
>  
> -	dev_priv->drrs.type = dev_priv->vbt.drrs_type;
> -
> -	dev_priv->drrs.refresh_rate = DRRS_REFRESH_RATE_HIGH;
>  	drm_dbg_kms(&dev_priv->drm,
>  		    "[CONNECTOR:%d:%s] seamless DRRS supported\n",
>  		    connector->base.base.id, connector->base.name);
> diff --git a/drivers/gpu/drm/i915/display/intel_drrs.h b/drivers/gpu/drm/i915/display/intel_drrs.h
> index 6bca7692f59f..9347cf451789 100644
> --- a/drivers/gpu/drm/i915/display/intel_drrs.h
> +++ b/drivers/gpu/drm/i915/display/intel_drrs.h
> @@ -13,23 +13,21 @@ struct intel_atomic_state;
>  struct intel_crtc;
>  struct intel_crtc_state;
>  struct intel_connector;
> -struct intel_dp;
>  
> -void intel_drrs_enable(struct intel_dp *intel_dp,
> -		       const struct intel_crtc_state *crtc_state);
> -void intel_drrs_disable(struct intel_dp *intel_dp,
> -			const struct intel_crtc_state *crtc_state);
> -void intel_drrs_update(struct intel_dp *intel_dp,
> -		       const struct intel_crtc_state *crtc_state);
> +bool intel_drrs_is_enabled(struct intel_crtc *crtc);
> +void intel_drrs_enable(const struct intel_crtc_state *crtc_state);
> +void intel_drrs_disable(const struct intel_crtc_state *crtc_state);
> +void intel_drrs_update(struct intel_atomic_state *state,
> +		       struct intel_crtc *crtc);
>  void intel_drrs_invalidate(struct drm_i915_private *dev_priv,
>  			   unsigned int frontbuffer_bits);
>  void intel_drrs_flush(struct drm_i915_private *dev_priv,
>  		      unsigned int frontbuffer_bits);
> -void intel_drrs_page_flip(struct intel_atomic_state *state,
> -			  struct intel_crtc *crtc);
> -void intel_drrs_compute_config(struct intel_dp *intel_dp,
> -			       struct intel_crtc_state *pipe_config,
> +void intel_drrs_page_flip(struct intel_crtc *crtc);
> +void intel_drrs_compute_config(struct intel_crtc_state *pipe_config,
> +			       struct intel_connector *connector,
>  			       int output_bpp, bool constant_n);
> +void intel_crtc_drrs_init(struct intel_crtc *crtc);
>  struct drm_display_mode *intel_drrs_init(struct intel_connector *connector,
>  					 const struct drm_display_mode *fixed_mode);
>  
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 7d622d1afe93..26df561a4e94 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -196,26 +196,12 @@ struct drm_i915_display_funcs {
>  
>  #define I915_COLOR_UNEVICTABLE (-1) /* a non-vma sharing the address space */
>  
> -enum drrs_refresh_rate {
> -	DRRS_REFRESH_RATE_HIGH,
> -	DRRS_REFRESH_RATE_LOW,
> -};
> -
>  enum drrs_type {
>  	DRRS_TYPE_NONE,
>  	DRRS_TYPE_STATIC,
>  	DRRS_TYPE_SEAMLESS,
>  };
>  
> -struct i915_drrs {
> -	struct mutex mutex;
> -	struct delayed_work work;
> -	struct intel_dp *dp;
> -	unsigned busy_frontbuffer_bits;
> -	enum drrs_refresh_rate refresh_rate;
> -	enum drrs_type type;
> -};
> -
>  #define QUIRK_LVDS_SSC_DISABLE (1<<1)
>  #define QUIRK_INVERT_BRIGHTNESS (1<<2)
>  #define QUIRK_BACKLIGHT_PRESENT (1<<3)
> @@ -537,7 +523,6 @@ struct drm_i915_private {
>  
>  	struct i915_hotplug hotplug;
>  	struct intel_fbc *fbc[I915_MAX_FBCS];
> -	struct i915_drrs drrs;
>  	struct intel_opregion opregion;
>  	struct intel_vbt_data vbt;
>  



More information about the Intel-gfx mailing list