diff mbox

drm/i915/glk, cnl: Implement WaDisableScalarClockGating

Message ID 20170928195436.32272-1-imre.deak@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Imre Deak Sept. 28, 2017, 7:54 p.m. UTC
On GLK and CNL enabling a pipe with its pipe scaler enabled will result
in a FIFO underrun. This happens only once after driver loading or
system/runtime resume, more specifically after power well 1 gets
enabled; subsequent modesets seem to be free of underruns. The BSpec
workaround for this is to disable the pipe scaler clock gating for the
duration of modeset. Based on my tests disabling clock gating must be
done before enabling pipe scaling and we can re-enable it after the pipe
is enabled and one vblank has passed.

For consistency I also checked if plane scaling would cause the same
problem, but that doesn't seem to trigger this problem.

The patch is based on an earlier version from Ander.

Cc: Ander Conselvan de Oliveira <conselvan2@gmail.com>
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=100302
Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/i915_reg.h      |  8 ++++++++
 drivers/gpu/drm/i915/intel_display.c | 25 +++++++++++++++++++++++++
 2 files changed, 33 insertions(+)

Comments

Rodrigo Vivi Sept. 28, 2017, 8:18 p.m. UTC | #1
On Thu, Sep 28, 2017 at 07:54:36PM +0000, Imre Deak wrote:
> On GLK and CNL enabling a pipe with its pipe scaler enabled will result
> in a FIFO underrun. This happens only once after driver loading or
> system/runtime resume, more specifically after power well 1 gets
> enabled; subsequent modesets seem to be free of underruns. The BSpec
> workaround for this is to disable the pipe scaler clock gating for the
> duration of modeset. Based on my tests disabling clock gating must be
> done before enabling pipe scaling and we can re-enable it after the pipe
> is enabled and one vblank has passed.

Oh! Great!
I had this Wa in my list here, but I was without access to HDSES
and was postponing it...

But now that you mention the bits it was easy to find on BSpec as well.

> 
> For consistency I also checked if plane scaling would cause the same
> problem, but that doesn't seem to trigger this problem.
> 
> The patch is based on an earlier version from Ander.
> 
> Cc: Ander Conselvan de Oliveira <conselvan2@gmail.com>
> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=100302
> Signed-off-by: Imre Deak <imre.deak@intel.com>
> ---
>  drivers/gpu/drm/i915/i915_reg.h      |  8 ++++++++
>  drivers/gpu/drm/i915/intel_display.c | 25 +++++++++++++++++++++++++
>  2 files changed, 33 insertions(+)
> 
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index 82f36dd0cd94..40a3c045d9d0 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -3811,6 +3811,14 @@ enum {
>  #define   PWM2_GATING_DIS		(1 << 14)
>  #define   PWM1_GATING_DIS		(1 << 13)
>  
> +#define _CLKGATE_DIS_PSL_A		0x46520
> +#define _CLKGATE_DIS_PSL_B		0x46524
> +#define _CLKGATE_DIS_PSL_C		0x46528
> +#define   DPF_GATING_DIS		(1 << 10)

On BSpec they also tells us to disable bits 8 and 9:

"To disable Scaler clock gating, set bits 8, 9, and 10 of 0x46520 (Pipe A), 0x46524 (Pipe B), or 0x46528 (Pipe C)"

> +
> +#define CLKGATE_DIS_PSL(pipe) \
> +	_MMIO_PIPE(pipe, _CLKGATE_DIS_PSL_A, _CLKGATE_DIS_PSL_B)
> +
>  /*
>   * GEN10 clock gating regs
>   */
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 026fa5460fe5..9d0b5a5596a5 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -5459,6 +5459,19 @@ static bool hsw_crtc_supports_ips(struct intel_crtc *crtc)
>  	return HAS_IPS(to_i915(crtc->base.dev)) && crtc->pipe == PIPE_A;
>  }
>  
> +static void glk_pipe_scaler_clock_gating_wa(struct drm_i915_private *dev_priv,
> +					    enum pipe pipe, bool apply)
> +{
> +	u32 tmp = I915_READ(CLKGATE_DIS_PSL(pipe));
> +
> +	if (apply)
> +		tmp |= DPF_GATING_DIS;
> +	else
> +		tmp &= ~DPF_GATING_DIS;
> +
> +	I915_WRITE(CLKGATE_DIS_PSL(pipe), tmp);
> +}
> +
>  static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
>  				struct drm_atomic_state *old_state)
>  {
> @@ -5469,6 +5482,7 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
>  	enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
>  	struct intel_atomic_state *old_intel_state =
>  		to_intel_atomic_state(old_state);
> +	bool psl_clkgate_wa;
>  
>  	if (WARN_ON(intel_crtc->active))
>  		return;
> @@ -5522,6 +5536,12 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
>  	if (!transcoder_is_dsi(cpu_transcoder))
>  		intel_ddi_enable_pipe_clock(pipe_config);
>  
> +	/* WaDisableScalarClockGating: glk, cnl */

Please also add the BSpec reference Display WA #1180.


> +	psl_clkgate_wa = (IS_GEMINILAKE(dev_priv) || IS_CANNONLAKE(dev_priv)) &&
> +			 intel_crtc->config->pch_pfit.enabled;
> +	if (psl_clkgate_wa)
> +		glk_pipe_scaler_clock_gating_wa(dev_priv, pipe, true);
> +

Is this place enough? Wouldn't be better to start that on atomic commit before we set cdclock
and mainly before we do a pre plane update?

Also on spec they say:
"
Chance of underflows when the Pipe Scaler is enabled during a mode-set while the Planes are disabled.
Workaround: Disable the Scaler clock gating when entering a mode-set routine.
The Scaler clock gating should be re-enabled at the end of the mode-set sequence.
"

So I wonder if here is not already too late to disable the clock gatings.

>  	if (INTEL_GEN(dev_priv) >= 9)
>  		skylake_pfit_enable(intel_crtc);
>  	else
> @@ -5555,6 +5575,11 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
>  
>  	intel_encoders_enable(crtc, pipe_config, old_state);
>  
> +	if (psl_clkgate_wa) {
> +		intel_wait_for_vblank(dev_priv, pipe);
> +		glk_pipe_scaler_clock_gating_wa(dev_priv, pipe, false);
> +	}
> +
>  	if (intel_crtc->config->has_pch_encoder) {
>  		intel_wait_for_vblank(dev_priv, pipe);
>  		intel_wait_for_vblank(dev_priv, pipe);
> -- 
> 2.13.2
>
Imre Deak Sept. 29, 2017, 11:18 a.m. UTC | #2
On Thu, Sep 28, 2017 at 01:18:30PM -0700, Rodrigo Vivi wrote:
> On Thu, Sep 28, 2017 at 07:54:36PM +0000, Imre Deak wrote:
> > On GLK and CNL enabling a pipe with its pipe scaler enabled will result
> > in a FIFO underrun. This happens only once after driver loading or
> > system/runtime resume, more specifically after power well 1 gets
> > enabled; subsequent modesets seem to be free of underruns. The BSpec
> > workaround for this is to disable the pipe scaler clock gating for the
> > duration of modeset. Based on my tests disabling clock gating must be
> > done before enabling pipe scaling and we can re-enable it after the pipe
> > is enabled and one vblank has passed.
> 
> Oh! Great!
> I had this Wa in my list here, but I was without access to HDSES
> and was postponing it...
> 
> But now that you mention the bits it was easy to find on BSpec as well.
> 
> > 
> > For consistency I also checked if plane scaling would cause the same
> > problem, but that doesn't seem to trigger this problem.
> > 
> > The patch is based on an earlier version from Ander.
> > 
> > Cc: Ander Conselvan de Oliveira <conselvan2@gmail.com>
> > Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
> > Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=100302
> > Signed-off-by: Imre Deak <imre.deak@intel.com>
> > ---
> >  drivers/gpu/drm/i915/i915_reg.h      |  8 ++++++++
> >  drivers/gpu/drm/i915/intel_display.c | 25 +++++++++++++++++++++++++
> >  2 files changed, 33 insertions(+)
> > 
> > diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> > index 82f36dd0cd94..40a3c045d9d0 100644
> > --- a/drivers/gpu/drm/i915/i915_reg.h
> > +++ b/drivers/gpu/drm/i915/i915_reg.h
> > @@ -3811,6 +3811,14 @@ enum {
> >  #define   PWM2_GATING_DIS		(1 << 14)
> >  #define   PWM1_GATING_DIS		(1 << 13)
> >  
> > +#define _CLKGATE_DIS_PSL_A		0x46520
> > +#define _CLKGATE_DIS_PSL_B		0x46524
> > +#define _CLKGATE_DIS_PSL_C		0x46528
> > +#define   DPF_GATING_DIS		(1 << 10)
> 
> On BSpec they also tells us to disable bits 8 and 9:
> 
> "To disable Scaler clock gating, set bits 8, 9, and 10 of 0x46520 (Pipe A), 0x46524 (Pipe B), or 0x46528 (Pipe C)"

Right, thanks for catching this. The original WA was only bit 10, and it
does get rid of the problem. I haven't noticed this change, will update
the patch based on that.

> 
> > +
> > +#define CLKGATE_DIS_PSL(pipe) \
> > +	_MMIO_PIPE(pipe, _CLKGATE_DIS_PSL_A, _CLKGATE_DIS_PSL_B)
> > +
> >  /*
> >   * GEN10 clock gating regs
> >   */
> > diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> > index 026fa5460fe5..9d0b5a5596a5 100644
> > --- a/drivers/gpu/drm/i915/intel_display.c
> > +++ b/drivers/gpu/drm/i915/intel_display.c
> > @@ -5459,6 +5459,19 @@ static bool hsw_crtc_supports_ips(struct intel_crtc *crtc)
> >  	return HAS_IPS(to_i915(crtc->base.dev)) && crtc->pipe == PIPE_A;
> >  }
> >  
> > +static void glk_pipe_scaler_clock_gating_wa(struct drm_i915_private *dev_priv,
> > +					    enum pipe pipe, bool apply)
> > +{
> > +	u32 tmp = I915_READ(CLKGATE_DIS_PSL(pipe));
> > +
> > +	if (apply)
> > +		tmp |= DPF_GATING_DIS;
> > +	else
> > +		tmp &= ~DPF_GATING_DIS;
> > +
> > +	I915_WRITE(CLKGATE_DIS_PSL(pipe), tmp);
> > +}
> > +
> >  static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
> >  				struct drm_atomic_state *old_state)
> >  {
> > @@ -5469,6 +5482,7 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
> >  	enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
> >  	struct intel_atomic_state *old_intel_state =
> >  		to_intel_atomic_state(old_state);
> > +	bool psl_clkgate_wa;
> >  
> >  	if (WARN_ON(intel_crtc->active))
> >  		return;
> > @@ -5522,6 +5536,12 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
> >  	if (!transcoder_is_dsi(cpu_transcoder))
> >  		intel_ddi_enable_pipe_clock(pipe_config);
> >  
> > +	/* WaDisableScalarClockGating: glk, cnl */
> 
> Please also add the BSpec reference Display WA #1180.

Ok.

> > +	psl_clkgate_wa = (IS_GEMINILAKE(dev_priv) || IS_CANNONLAKE(dev_priv)) &&
> > +			 intel_crtc->config->pch_pfit.enabled;
> > +	if (psl_clkgate_wa)
> > +		glk_pipe_scaler_clock_gating_wa(dev_priv, pipe, true);
> > +
> 
> Is this place enough? Wouldn't be better to start that on atomic commit before we set cdclock
> and mainly before we do a pre plane update?

I'd prefer keeping it here leaving the WA's range narrow, unless it's
proven that it's not enough. If CD clock would be a factor, then we'd
have to force a CD clock disable/re-enable if the CD clock rate wouldn't
change and that's not required by the WA. pre_plane_update is only
called on the fastset path, and this WA is only needed during a full
modeset (luckily b/c of the vblank wait).

> 
> Also on spec they say:
> "
> Chance of underflows when the Pipe Scaler is enabled during a mode-set while the Planes are disabled.
> Workaround: Disable the Scaler clock gating when entering a mode-set routine.
> The Scaler clock gating should be re-enabled at the end of the mode-set sequence.
> "
> 
> So I wonder if here is not already too late to disable the clock gatings.

Yea, the wording is a bit unclear, it doesn't either say for example
when to re-enable the clock gating. I will ask for clarification, but
I'd say it's a reasonable assumption that the pipe scaler clock gating
doesn't have any effect until the pipe scaler is enabled and this is
also what I see during my tests. So imo we can go with this until proven
otherwise.

> 
> >  	if (INTEL_GEN(dev_priv) >= 9)
> >  		skylake_pfit_enable(intel_crtc);
> >  	else
> > @@ -5555,6 +5575,11 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
> >  
> >  	intel_encoders_enable(crtc, pipe_config, old_state);
> >  
> > +	if (psl_clkgate_wa) {
> > +		intel_wait_for_vblank(dev_priv, pipe);
> > +		glk_pipe_scaler_clock_gating_wa(dev_priv, pipe, false);
> > +	}
> > +
> >  	if (intel_crtc->config->has_pch_encoder) {
> >  		intel_wait_for_vblank(dev_priv, pipe);
> >  		intel_wait_for_vblank(dev_priv, pipe);
> > -- 
> > 2.13.2
> >
Imre Deak Oct. 3, 2017, 9:13 a.m. UTC | #3
On Mon, Oct 02, 2017 at 08:55:28AM +0000, Patchwork wrote:
> == Series Details ==
> 
> Series: drm/i915/glk, cnl: Implement WaDisableScalarClockGating (rev2)
> URL   : https://patchwork.freedesktop.org/series/31094/
> State : success

Thanks for the review, pushed this to -dinq.

> 
> == Summary ==
> 
> Series 31094v2 drm/i915/glk, cnl: Implement WaDisableScalarClockGating
> https://patchwork.freedesktop.org/api/1.0/series/31094/revisions/2/mbox/
> 
> fi-bdw-5557u     total:289  pass:268  dwarn:0   dfail:0   fail:0   skip:21  time:458s
> fi-bdw-gvtdvm    total:289  pass:265  dwarn:0   dfail:0   fail:0   skip:24  time:471s
> fi-blb-e6850     total:289  pass:224  dwarn:1   dfail:0   fail:0   skip:64  time:392s
> fi-bsw-n3050     total:289  pass:243  dwarn:0   dfail:0   fail:0   skip:46  time:575s
> fi-bwr-2160      total:289  pass:184  dwarn:0   dfail:0   fail:0   skip:105 time:289s
> fi-bxt-dsi       total:289  pass:259  dwarn:0   dfail:0   fail:0   skip:30  time:535s
> fi-bxt-j4205     total:289  pass:260  dwarn:0   dfail:0   fail:0   skip:29  time:532s
> fi-byt-j1900     total:289  pass:254  dwarn:1   dfail:0   fail:0   skip:34  time:542s
> fi-byt-n2820     total:289  pass:250  dwarn:1   dfail:0   fail:0   skip:38  time:534s
> fi-cfl-s         total:289  pass:256  dwarn:1   dfail:0   fail:0   skip:32  time:564s
> fi-cnl-y         total:289  pass:261  dwarn:1   dfail:0   fail:0   skip:27  time:620s
> fi-elk-e7500     total:289  pass:230  dwarn:0   dfail:0   fail:0   skip:59  time:435s
> fi-glk-1         total:289  pass:257  dwarn:3   dfail:0   fail:0   skip:29  time:593s
> fi-hsw-4770      total:289  pass:263  dwarn:0   dfail:0   fail:0   skip:26  time:440s
> fi-hsw-4770r     total:289  pass:263  dwarn:0   dfail:0   fail:0   skip:26  time:426s
> fi-ilk-650       total:289  pass:229  dwarn:0   dfail:0   fail:0   skip:60  time:467s
> fi-ivb-3520m     total:289  pass:261  dwarn:0   dfail:0   fail:0   skip:28  time:505s
> fi-ivb-3770      total:289  pass:261  dwarn:0   dfail:0   fail:0   skip:28  time:479s
> fi-kbl-7500u     total:289  pass:264  dwarn:1   dfail:0   fail:0   skip:24  time:507s
> fi-kbl-7560u     total:289  pass:270  dwarn:0   dfail:0   fail:0   skip:19  time:583s
> fi-kbl-7567u     total:289  pass:265  dwarn:4   dfail:0   fail:0   skip:20  time:485s
> fi-kbl-r         total:289  pass:262  dwarn:0   dfail:0   fail:0   skip:27  time:589s
> fi-pnv-d510      total:289  pass:223  dwarn:1   dfail:0   fail:0   skip:65  time:657s
> fi-skl-6260u     total:289  pass:269  dwarn:0   dfail:0   fail:0   skip:20  time:473s
> fi-skl-6700k     total:289  pass:265  dwarn:0   dfail:0   fail:0   skip:24  time:543s
> fi-skl-6770hq    total:289  pass:269  dwarn:0   dfail:0   fail:0   skip:20  time:591s
> fi-skl-gvtdvm    total:289  pass:266  dwarn:0   dfail:0   fail:0   skip:23  time:473s
> fi-snb-2520m     total:289  pass:251  dwarn:0   dfail:0   fail:0   skip:38  time:584s
> fi-snb-2600      total:289  pass:250  dwarn:0   dfail:0   fail:0   skip:39  time:433s
> 
> b89a3b1a69f77be194ad4786906048a5e02b9975 drm-tip: 2017y-10m-02d-08h-07m-17s UTC integration manifest
> 27ae0ed67a28 drm/i915/glk, cnl: Implement WaDisableScalarClockGating
> 
> == Logs ==
> 
> For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_5867/
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 82f36dd0cd94..40a3c045d9d0 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -3811,6 +3811,14 @@  enum {
 #define   PWM2_GATING_DIS		(1 << 14)
 #define   PWM1_GATING_DIS		(1 << 13)
 
+#define _CLKGATE_DIS_PSL_A		0x46520
+#define _CLKGATE_DIS_PSL_B		0x46524
+#define _CLKGATE_DIS_PSL_C		0x46528
+#define   DPF_GATING_DIS		(1 << 10)
+
+#define CLKGATE_DIS_PSL(pipe) \
+	_MMIO_PIPE(pipe, _CLKGATE_DIS_PSL_A, _CLKGATE_DIS_PSL_B)
+
 /*
  * GEN10 clock gating regs
  */
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 026fa5460fe5..9d0b5a5596a5 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -5459,6 +5459,19 @@  static bool hsw_crtc_supports_ips(struct intel_crtc *crtc)
 	return HAS_IPS(to_i915(crtc->base.dev)) && crtc->pipe == PIPE_A;
 }
 
+static void glk_pipe_scaler_clock_gating_wa(struct drm_i915_private *dev_priv,
+					    enum pipe pipe, bool apply)
+{
+	u32 tmp = I915_READ(CLKGATE_DIS_PSL(pipe));
+
+	if (apply)
+		tmp |= DPF_GATING_DIS;
+	else
+		tmp &= ~DPF_GATING_DIS;
+
+	I915_WRITE(CLKGATE_DIS_PSL(pipe), tmp);
+}
+
 static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
 				struct drm_atomic_state *old_state)
 {
@@ -5469,6 +5482,7 @@  static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
 	enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
 	struct intel_atomic_state *old_intel_state =
 		to_intel_atomic_state(old_state);
+	bool psl_clkgate_wa;
 
 	if (WARN_ON(intel_crtc->active))
 		return;
@@ -5522,6 +5536,12 @@  static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
 	if (!transcoder_is_dsi(cpu_transcoder))
 		intel_ddi_enable_pipe_clock(pipe_config);
 
+	/* WaDisableScalarClockGating: glk, cnl */
+	psl_clkgate_wa = (IS_GEMINILAKE(dev_priv) || IS_CANNONLAKE(dev_priv)) &&
+			 intel_crtc->config->pch_pfit.enabled;
+	if (psl_clkgate_wa)
+		glk_pipe_scaler_clock_gating_wa(dev_priv, pipe, true);
+
 	if (INTEL_GEN(dev_priv) >= 9)
 		skylake_pfit_enable(intel_crtc);
 	else
@@ -5555,6 +5575,11 @@  static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
 
 	intel_encoders_enable(crtc, pipe_config, old_state);
 
+	if (psl_clkgate_wa) {
+		intel_wait_for_vblank(dev_priv, pipe);
+		glk_pipe_scaler_clock_gating_wa(dev_priv, pipe, false);
+	}
+
 	if (intel_crtc->config->has_pch_encoder) {
 		intel_wait_for_vblank(dev_priv, pipe);
 		intel_wait_for_vblank(dev_priv, pipe);