diff mbox series

[v9,4/7] drm/i915/tgl: Do modeset to enable and configure DC3CO exitline

Message ID 20190926145621.9090-5-anshuman.gupta@intel.com (mailing list archive)
State New, archived
Headers show
Series DC3CO Support for TGL | expand

Commit Message

Gupta, Anshuman Sept. 26, 2019, 2:56 p.m. UTC
DC3CO enabling B.Specs sequence requires to enable end configure
exit scanlines to TRANS_EXITLINE register, programming this register
has to be part of modeset sequence as this can't be change when
transcoder or port is enabled.
When system boots with only eDP panel there may not be real
modeset as BIOS has already programmed the necessary registers,
therefore it needs to force a modeset to enable and configure
DC3CO exitline.

v1: Computing dc3co_exitline crtc state from a DP encoder
    compute config. [Imre]
    Enabling and disabling DC3CO PSR2 transcoder exitline from
    encoder pre_enable and post_disable hooks. [Imre]
    Computing dc3co_exitline instead of has_dc3co_exitline bool. [Imre]

Cc: Jani Nikula <jani.nikula@intel.com>
Cc: Imre Deak <imre.deak@intel.com>
Cc: Animesh Manna <animesh.manna@intel.com>
Signed-off-by: Anshuman Gupta <anshuman.gupta@intel.com>
---
 drivers/gpu/drm/i915/display/intel_ddi.c      |  7 ++
 drivers/gpu/drm/i915/display/intel_display.c  |  1 +
 .../drm/i915/display/intel_display_power.c    | 87 +++++++++++++++++++
 .../drm/i915/display/intel_display_power.h    |  8 ++
 .../drm/i915/display/intel_display_types.h    |  1 +
 drivers/gpu/drm/i915/display/intel_dp.c       |  2 +
 6 files changed, 106 insertions(+)

Comments

Imre Deak Sept. 27, 2019, 3:09 p.m. UTC | #1
On Thu, Sep 26, 2019 at 08:26:18PM +0530, Anshuman Gupta wrote:
> DC3CO enabling B.Specs sequence requires to enable end configure
> exit scanlines to TRANS_EXITLINE register, programming this register
> has to be part of modeset sequence as this can't be change when
> transcoder or port is enabled.
> When system boots with only eDP panel there may not be real
> modeset as BIOS has already programmed the necessary registers,
> therefore it needs to force a modeset to enable and configure
> DC3CO exitline.
> 
> v1: Computing dc3co_exitline crtc state from a DP encoder
>     compute config. [Imre]
>     Enabling and disabling DC3CO PSR2 transcoder exitline from
>     encoder pre_enable and post_disable hooks. [Imre]
>     Computing dc3co_exitline instead of has_dc3co_exitline bool. [Imre]
> 
> Cc: Jani Nikula <jani.nikula@intel.com>
> Cc: Imre Deak <imre.deak@intel.com>
> Cc: Animesh Manna <animesh.manna@intel.com>
> Signed-off-by: Anshuman Gupta <anshuman.gupta@intel.com>
> ---
>  drivers/gpu/drm/i915/display/intel_ddi.c      |  7 ++
>  drivers/gpu/drm/i915/display/intel_display.c  |  1 +
>  .../drm/i915/display/intel_display_power.c    | 87 +++++++++++++++++++
>  .../drm/i915/display/intel_display_power.h    |  8 ++
>  .../drm/i915/display/intel_display_types.h    |  1 +
>  drivers/gpu/drm/i915/display/intel_dp.c       |  2 +
>  6 files changed, 106 insertions(+)
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
> index aa470c70a198..e0e276909e76 100644
> --- a/drivers/gpu/drm/i915/display/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/display/intel_ddi.c
> @@ -3212,6 +3212,8 @@ static void tgl_ddi_pre_enable_dp(struct intel_encoder *encoder,
>  	int level = intel_ddi_dp_level(intel_dp);
>  	enum transcoder transcoder = crtc_state->cpu_transcoder;
>  
> +	/* Program the dc3co psr2 transcoder exitline */
> +	tgl_set_psr2_transcoder_exitline(crtc_state);
>  	intel_dp_set_link_params(intel_dp, crtc_state->port_clock,
>  				 crtc_state->lane_count, is_mst);
>  
> @@ -3524,6 +3526,8 @@ static void intel_ddi_post_disable_dp(struct intel_encoder *encoder,
>  						  dig_port->ddi_io_power_domain);
>  
>  	intel_ddi_clk_disable(encoder);
> +	/* Disable the dc3co psr2 transcoder exitline */
> +	tgl_clear_psr2_transcoder_exitline(old_crtc_state);
>  }
>  
>  static void intel_ddi_post_disable_hdmi(struct intel_encoder *encoder,
> @@ -4070,6 +4074,9 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
>  		break;
>  	}
>  
> +	if (encoder->type == INTEL_OUTPUT_EDP)
> +		tgl_dc3co_exitline_get_config(pipe_config);
> +
>  	pipe_config->has_audio =
>  		intel_ddi_is_audio_enabled(dev_priv, cpu_transcoder);
>  
> diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
> index 8f125f1624bd..a467c7523e06 100644
> --- a/drivers/gpu/drm/i915/display/intel_display.c
> +++ b/drivers/gpu/drm/i915/display/intel_display.c
> @@ -12820,6 +12820,7 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
>  
>  	PIPE_CONF_CHECK_I(pixel_multiplier);
>  	PIPE_CONF_CHECK_I(output_format);
> +	PIPE_CONF_CHECK_I(dc3co_exitline);
>  	PIPE_CONF_CHECK_BOOL(has_hdmi_sink);
>  	if ((INTEL_GEN(dev_priv) < 8 && !IS_HASWELL(dev_priv)) ||
>  	    IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
> diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c
> index 9f787556f80d..84e4cfd95b43 100644
> --- a/drivers/gpu/drm/i915/display/intel_display_power.c
> +++ b/drivers/gpu/drm/i915/display/intel_display_power.c
> @@ -19,6 +19,7 @@
>  #include "intel_hotplug.h"
>  #include "intel_sideband.h"
>  #include "intel_tc.h"
> +#include "intel_pm.h"
>  
>  bool intel_display_power_well_is_enabled(struct drm_i915_private *dev_priv,
>  					 enum i915_power_well_id power_well_id);
> @@ -785,6 +786,92 @@ static void gen9_set_dc_state(struct drm_i915_private *dev_priv, u32 state)
>  	dev_priv->csr.dc_state = val & mask;
>  }
>  
> +void tgl_clear_psr2_transcoder_exitline(const struct intel_crtc_state *cstate)
> +{
> +	struct drm_i915_private *dev_priv = to_i915(cstate->base.crtc->dev);
> +	u32 val;
> +
> +	if (!cstate->dc3co_exitline)
> +		return;
> +
> +	val = I915_READ(EXITLINE(cstate->cpu_transcoder));
> +	val &= ~(EXITLINE_MASK | EXITLINE_ENABLE);
> +	I915_WRITE(EXITLINE(cstate->cpu_transcoder), val);
> +}
> +
> +void tgl_set_psr2_transcoder_exitline(const struct intel_crtc_state *cstate)
> +{
> +	u32 val, exit_scanlines;
> +	struct drm_i915_private *dev_priv = to_i915(cstate->base.crtc->dev);
> +
> +	if (!cstate->dc3co_exitline)
> +		return;
> +
> +	exit_scanlines = cstate->dc3co_exitline;
> +	exit_scanlines <<= EXITLINE_SHIFT;
> +	val = I915_READ(EXITLINE(cstate->cpu_transcoder));
> +	val &= ~(EXITLINE_MASK | EXITLINE_ENABLE);
> +	val |= exit_scanlines;
> +	val |= EXITLINE_ENABLE;
> +	I915_WRITE(EXITLINE(cstate->cpu_transcoder), val);
> +}
> +
> +/*
> + * DC3CO requires to enable exitline and program DC3CO requires
> + * exit scanlines to TRANS_EXITLINE register, which should only
> + * change before transcoder or port are enabled.
> + * This requires to disable the fastset at boot for eDP output.
> + */
> +void tgl_dc3co_exitline_compute_config(struct intel_encoder *encoder,
> +				       struct intel_crtc_state *cstate)
> +{
> +	u32 exit_scanlines;
> +	struct drm_i915_private *dev_priv = to_i915(cstate->base.crtc->dev);
> +	u32 crtc_vdisplay = cstate->base.adjusted_mode.crtc_vdisplay;
> +
> +	if (!IS_TIGERLAKE(dev_priv))
> +		return;

This should match the corresponding check in get_allowed_dc_mask(),
where it's GEN>=12. The check is also redundant then here, since below we
check allowed_dc_mask.
> +
> +	if (!(dev_priv->csr.allowed_dc_mask & DC_STATE_EN_DC3CO))
> +		return;
> +
> +	/* B.Specs:49196 DC3CO only works with pipeA and DDIA.*/
> +	if (encoder->port != PORT_A)

What about the pipe A restriction?

> +		return;
> +
> +	if (!cstate->has_psr2 || !cstate->base.active)

Let's clear cstate->dc3co_exitline in this case explicitly. Currently
not doing this only works for backwards compatibility, see
clear_intel_crtc_state().

> +		return;
> +
> +	/*
> +	 * DC3CO Exit time 200us B.Spec 49196
> +	 * PSR2 transcoder Early Exit scanlines = ROUNDUP(200 / line time) + 1
> +	 */
> +	exit_scanlines =
> +		intel_usecs_to_scanlines(&cstate->base.adjusted_mode, 200) + 1;
> +
> +	if (WARN_ON(exit_scanlines > crtc_vdisplay))
> +		return;
> +
> +	cstate->dc3co_exitline = crtc_vdisplay - exit_scanlines;
> +}
> +
> +void tgl_dc3co_exitline_get_config(struct intel_crtc_state *crtc_state)
> +{
> +	u32 val;
> +	struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev);
> +
> +	if (!IS_TIGERLAKE(dev_priv))
> +		return;

As mentioned above, this should match the check in
get_allowed_dc_mask().

> +
> +	if (!(dev_priv->csr.allowed_dc_mask & DC_STATE_EN_DC3CO))
> +		return;

We also want to read this out if the user has disabled DC3co.
compute_config() will make sure that we won't enable if then.

> +
> +	val = I915_READ(EXITLINE(crtc_state->cpu_transcoder));
> +
> +	if (val & EXITLINE_ENABLE)
> +		crtc_state->dc3co_exitline = val & EXITLINE_MASK;
> +}

There is no good reason to have any of these funcs above in
display_power.c exported, so let's just move them where they are used
(intel_ddi.c).

> +
>  static void
>  allowed_dc_mask_to_target_dc_state(struct drm_i915_private *dev_priv)
>  {
> diff --git a/drivers/gpu/drm/i915/display/intel_display_power.h b/drivers/gpu/drm/i915/display/intel_display_power.h
> index 13fc705799fd..4e76f93bbee5 100644
> --- a/drivers/gpu/drm/i915/display/intel_display_power.h
> +++ b/drivers/gpu/drm/i915/display/intel_display_power.h
> @@ -8,10 +8,13 @@
>  
>  #include "intel_display.h"
>  #include "intel_runtime_pm.h"
> +#include "intel_sprite.h"
>  #include "i915_reg.h"
>  
>  struct drm_i915_private;
>  struct intel_encoder;
> +struct intel_crtc_state;
> +struct intel_atomic_state;
>  
>  enum intel_display_power_domain {
>  	POWER_DOMAIN_DISPLAY_CORE,
> @@ -258,6 +261,11 @@ void intel_display_power_resume_early(struct drm_i915_private *i915);
>  void intel_display_power_suspend(struct drm_i915_private *i915);
>  void intel_display_power_resume(struct drm_i915_private *i915);
>  void tgl_set_target_dc_state(struct drm_i915_private *dev_priv, u32 state);
> +void tgl_dc3co_exitline_compute_config(struct intel_encoder *encoder,
> +				       struct intel_crtc_state *crtc_state);
> +void tgl_dc3co_exitline_get_config(struct intel_crtc_state *crtc_state);
> +void tgl_clear_psr2_transcoder_exitline(const struct intel_crtc_state *state);
> +void tgl_set_psr2_transcoder_exitline(const struct intel_crtc_state *state);
>  
>  const char *
>  intel_display_power_domain_str(enum intel_display_power_domain domain);
> diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
> index 976669f01a8c..8aa38ace7845 100644
> --- a/drivers/gpu/drm/i915/display/intel_display_types.h
> +++ b/drivers/gpu/drm/i915/display/intel_display_types.h
> @@ -870,6 +870,7 @@ struct intel_crtc_state {
>  
>  	bool has_psr;
>  	bool has_psr2;
> +	u32 dc3co_exitline;
>  
>  	/*
>  	 * Frequence the dpll for the port should run at. Differs from the
> diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
> index 2b1e71f992b0..77dd29627610 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp.c
> @@ -2368,6 +2368,8 @@ intel_dp_compute_config(struct intel_encoder *encoder,
>  
>  	intel_psr_compute_config(intel_dp, pipe_config);
>  
> +	tgl_dc3co_exitline_compute_config(encoder, pipe_config);
> +

The steps in compute_config hook should have a corresponding step in the
get_config hook, so let's do this readout in intel_ddi_compute_config()
instead.

>  	intel_hdcp_transcoder_config(intel_connector,
>  				     pipe_config->cpu_transcoder);
>  
> -- 
> 2.21.0
>
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 aa470c70a198..e0e276909e76 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -3212,6 +3212,8 @@  static void tgl_ddi_pre_enable_dp(struct intel_encoder *encoder,
 	int level = intel_ddi_dp_level(intel_dp);
 	enum transcoder transcoder = crtc_state->cpu_transcoder;
 
+	/* Program the dc3co psr2 transcoder exitline */
+	tgl_set_psr2_transcoder_exitline(crtc_state);
 	intel_dp_set_link_params(intel_dp, crtc_state->port_clock,
 				 crtc_state->lane_count, is_mst);
 
@@ -3524,6 +3526,8 @@  static void intel_ddi_post_disable_dp(struct intel_encoder *encoder,
 						  dig_port->ddi_io_power_domain);
 
 	intel_ddi_clk_disable(encoder);
+	/* Disable the dc3co psr2 transcoder exitline */
+	tgl_clear_psr2_transcoder_exitline(old_crtc_state);
 }
 
 static void intel_ddi_post_disable_hdmi(struct intel_encoder *encoder,
@@ -4070,6 +4074,9 @@  void intel_ddi_get_config(struct intel_encoder *encoder,
 		break;
 	}
 
+	if (encoder->type == INTEL_OUTPUT_EDP)
+		tgl_dc3co_exitline_get_config(pipe_config);
+
 	pipe_config->has_audio =
 		intel_ddi_is_audio_enabled(dev_priv, cpu_transcoder);
 
diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index 8f125f1624bd..a467c7523e06 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -12820,6 +12820,7 @@  intel_pipe_config_compare(const struct intel_crtc_state *current_config,
 
 	PIPE_CONF_CHECK_I(pixel_multiplier);
 	PIPE_CONF_CHECK_I(output_format);
+	PIPE_CONF_CHECK_I(dc3co_exitline);
 	PIPE_CONF_CHECK_BOOL(has_hdmi_sink);
 	if ((INTEL_GEN(dev_priv) < 8 && !IS_HASWELL(dev_priv)) ||
 	    IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c
index 9f787556f80d..84e4cfd95b43 100644
--- a/drivers/gpu/drm/i915/display/intel_display_power.c
+++ b/drivers/gpu/drm/i915/display/intel_display_power.c
@@ -19,6 +19,7 @@ 
 #include "intel_hotplug.h"
 #include "intel_sideband.h"
 #include "intel_tc.h"
+#include "intel_pm.h"
 
 bool intel_display_power_well_is_enabled(struct drm_i915_private *dev_priv,
 					 enum i915_power_well_id power_well_id);
@@ -785,6 +786,92 @@  static void gen9_set_dc_state(struct drm_i915_private *dev_priv, u32 state)
 	dev_priv->csr.dc_state = val & mask;
 }
 
+void tgl_clear_psr2_transcoder_exitline(const struct intel_crtc_state *cstate)
+{
+	struct drm_i915_private *dev_priv = to_i915(cstate->base.crtc->dev);
+	u32 val;
+
+	if (!cstate->dc3co_exitline)
+		return;
+
+	val = I915_READ(EXITLINE(cstate->cpu_transcoder));
+	val &= ~(EXITLINE_MASK | EXITLINE_ENABLE);
+	I915_WRITE(EXITLINE(cstate->cpu_transcoder), val);
+}
+
+void tgl_set_psr2_transcoder_exitline(const struct intel_crtc_state *cstate)
+{
+	u32 val, exit_scanlines;
+	struct drm_i915_private *dev_priv = to_i915(cstate->base.crtc->dev);
+
+	if (!cstate->dc3co_exitline)
+		return;
+
+	exit_scanlines = cstate->dc3co_exitline;
+	exit_scanlines <<= EXITLINE_SHIFT;
+	val = I915_READ(EXITLINE(cstate->cpu_transcoder));
+	val &= ~(EXITLINE_MASK | EXITLINE_ENABLE);
+	val |= exit_scanlines;
+	val |= EXITLINE_ENABLE;
+	I915_WRITE(EXITLINE(cstate->cpu_transcoder), val);
+}
+
+/*
+ * DC3CO requires to enable exitline and program DC3CO requires
+ * exit scanlines to TRANS_EXITLINE register, which should only
+ * change before transcoder or port are enabled.
+ * This requires to disable the fastset at boot for eDP output.
+ */
+void tgl_dc3co_exitline_compute_config(struct intel_encoder *encoder,
+				       struct intel_crtc_state *cstate)
+{
+	u32 exit_scanlines;
+	struct drm_i915_private *dev_priv = to_i915(cstate->base.crtc->dev);
+	u32 crtc_vdisplay = cstate->base.adjusted_mode.crtc_vdisplay;
+
+	if (!IS_TIGERLAKE(dev_priv))
+		return;
+
+	if (!(dev_priv->csr.allowed_dc_mask & DC_STATE_EN_DC3CO))
+		return;
+
+	/* B.Specs:49196 DC3CO only works with pipeA and DDIA.*/
+	if (encoder->port != PORT_A)
+		return;
+
+	if (!cstate->has_psr2 || !cstate->base.active)
+		return;
+
+	/*
+	 * DC3CO Exit time 200us B.Spec 49196
+	 * PSR2 transcoder Early Exit scanlines = ROUNDUP(200 / line time) + 1
+	 */
+	exit_scanlines =
+		intel_usecs_to_scanlines(&cstate->base.adjusted_mode, 200) + 1;
+
+	if (WARN_ON(exit_scanlines > crtc_vdisplay))
+		return;
+
+	cstate->dc3co_exitline = crtc_vdisplay - exit_scanlines;
+}
+
+void tgl_dc3co_exitline_get_config(struct intel_crtc_state *crtc_state)
+{
+	u32 val;
+	struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev);
+
+	if (!IS_TIGERLAKE(dev_priv))
+		return;
+
+	if (!(dev_priv->csr.allowed_dc_mask & DC_STATE_EN_DC3CO))
+		return;
+
+	val = I915_READ(EXITLINE(crtc_state->cpu_transcoder));
+
+	if (val & EXITLINE_ENABLE)
+		crtc_state->dc3co_exitline = val & EXITLINE_MASK;
+}
+
 static void
 allowed_dc_mask_to_target_dc_state(struct drm_i915_private *dev_priv)
 {
diff --git a/drivers/gpu/drm/i915/display/intel_display_power.h b/drivers/gpu/drm/i915/display/intel_display_power.h
index 13fc705799fd..4e76f93bbee5 100644
--- a/drivers/gpu/drm/i915/display/intel_display_power.h
+++ b/drivers/gpu/drm/i915/display/intel_display_power.h
@@ -8,10 +8,13 @@ 
 
 #include "intel_display.h"
 #include "intel_runtime_pm.h"
+#include "intel_sprite.h"
 #include "i915_reg.h"
 
 struct drm_i915_private;
 struct intel_encoder;
+struct intel_crtc_state;
+struct intel_atomic_state;
 
 enum intel_display_power_domain {
 	POWER_DOMAIN_DISPLAY_CORE,
@@ -258,6 +261,11 @@  void intel_display_power_resume_early(struct drm_i915_private *i915);
 void intel_display_power_suspend(struct drm_i915_private *i915);
 void intel_display_power_resume(struct drm_i915_private *i915);
 void tgl_set_target_dc_state(struct drm_i915_private *dev_priv, u32 state);
+void tgl_dc3co_exitline_compute_config(struct intel_encoder *encoder,
+				       struct intel_crtc_state *crtc_state);
+void tgl_dc3co_exitline_get_config(struct intel_crtc_state *crtc_state);
+void tgl_clear_psr2_transcoder_exitline(const struct intel_crtc_state *state);
+void tgl_set_psr2_transcoder_exitline(const struct intel_crtc_state *state);
 
 const char *
 intel_display_power_domain_str(enum intel_display_power_domain domain);
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index 976669f01a8c..8aa38ace7845 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -870,6 +870,7 @@  struct intel_crtc_state {
 
 	bool has_psr;
 	bool has_psr2;
+	u32 dc3co_exitline;
 
 	/*
 	 * Frequence the dpll for the port should run at. Differs from the
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 2b1e71f992b0..77dd29627610 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -2368,6 +2368,8 @@  intel_dp_compute_config(struct intel_encoder *encoder,
 
 	intel_psr_compute_config(intel_dp, pipe_config);
 
+	tgl_dc3co_exitline_compute_config(encoder, pipe_config);
+
 	intel_hdcp_transcoder_config(intel_connector,
 				     pipe_config->cpu_transcoder);