diff mbox

drm/i915/ilk: Disable SSC for DPLLs if we're not using it

Message ID 1464029814-28187-1-git-send-email-cpaul@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

cpaul@redhat.com May 23, 2016, 6:56 p.m. UTC
Thanks to Ville Syrjälä for pointing me towards the cause of this issue.

Unfortunately one of the sideaffects of having the refclk for a DPLL
set to SSC is that as long as it's set to SSC, the GPU will prevent us
from powering down any of the pipes or transcoders using it. A couple of
BIOSes, despite the fact they don't actually need it, enable SSC both in
PCH_DREF_CONTROL and on the DPLL configurations. This causes issues on
the first modeset, since we don't expect SSC to be left on and as a
result, can't successfully power down the pipes or the transcoders using
it. Here's an example from this Dell OptiPlex 990:

[drm:intel_modeset_init] SSC enabled by BIOS, overriding VBT which says disabled
[drm:intel_modeset_init] 2 display pipes available.
[drm:intel_update_cdclk] Current CD clock rate: 400000 kHz
[drm:intel_update_max_cdclk] Max CD clock rate: 400000 kHz
[drm:intel_update_max_cdclk] Max dotclock rate: 360000 kHz
vgaarb: device changed decodes: PCI:0000:00:02.0,olddecodes=io+mem,decodes=io+mem:owns=io+mem
[drm:intel_crt_reset] crt adpa set to 0xf40000
[drm:intel_dp_init_connector] Adding DP connector on port C
[drm:intel_dp_aux_init] registering DPDDC-C bus for card0-DP-1
[drm:ironlake_init_pch_refclk] has_panel 0 has_lvds 0 has_ck505 0
[drm:ironlake_init_pch_refclk] Disabling SSC entirely
… later we try committing the first modeset …
[drm:intel_dump_pipe_config] [CRTC:26][modeset] config ffff88041b02e800 for pipe A
[drm:intel_dump_pipe_config] cpu_transcoder: A
…
[drm:intel_dump_pipe_config] dpll_hw_state: dpll: 0xc4016001, dpll_md: 0x0, fp0: 0x20e08, fp1: 0x30d07
[drm:intel_dump_pipe_config] planes on this crtc
[drm:intel_dump_pipe_config] STANDARD PLANE:23 plane: 0.0 idx: 0 enabled
[drm:intel_dump_pipe_config]     FB:42, fb = 800x600 format = 0x34325258
[drm:intel_dump_pipe_config]     scaler:0 src (0, 0) 800x600 dst (0, 0) 800x600
[drm:intel_dump_pipe_config] CURSOR PLANE:25 plane: 0.1 idx: 1 disabled, scaler_id = 0
[drm:intel_dump_pipe_config] STANDARD PLANE:27 plane: 0.1 idx: 2 disabled, scaler_id = 0
[drm:intel_get_shared_dpll] CRTC:26 allocated PCH DPLL A
[drm:intel_get_shared_dpll] using PCH DPLL A for pipe A
[drm:ilk_audio_codec_disable] Disable audio codec on port C, pipe A
[drm:intel_disable_pipe] disabling pipe A
------------[ cut here ]------------
WARNING: CPU: 1 PID: 130 at drivers/gpu/drm/i915/intel_display.c:1146 intel_disable_pipe+0x297/0x2d0 [i915]
pipe_off wait timed out
…
---[ end trace 94fc8aa03ae139e8 ]---
[drm:intel_dp_link_down]
[drm:ironlake_crtc_disable [i915]] *ERROR* failed to disable transcoder A

Later modesets succeed since they reset the DPLL's configuration anyway,
but this is enough to get stuck with a big fat warning in dmesg.

Normally we'd need to add some sort of ref counting mechanism to the
CRTCs so we avoid accidentally trying to shut off a shared resource, but
since ignore what the BIOS does anyway and we shut off the refclks
before any modesets, this workaround should suffice for now.

Cc: stable@vger.kernel.org
Signed-off-by: Lyude <cpaul@redhat.com>
---
 drivers/gpu/drm/i915/intel_display.c | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

Comments

Ville Syrjala May 23, 2016, 7:16 p.m. UTC | #1
On Mon, May 23, 2016 at 02:56:54PM -0400, Lyude wrote:
> Thanks to Ville Syrjälä for pointing me towards the cause of this issue.
> 
> Unfortunately one of the sideaffects of having the refclk for a DPLL
> set to SSC is that as long as it's set to SSC, the GPU will prevent us
> from powering down any of the pipes or transcoders using it. A couple of
> BIOSes, despite the fact they don't actually need it, enable SSC both in
> PCH_DREF_CONTROL and on the DPLL configurations. This causes issues on
> the first modeset, since we don't expect SSC to be left on and as a
> result, can't successfully power down the pipes or the transcoders using
> it. Here's an example from this Dell OptiPlex 990:
> 
> [drm:intel_modeset_init] SSC enabled by BIOS, overriding VBT which says disabled
> [drm:intel_modeset_init] 2 display pipes available.
> [drm:intel_update_cdclk] Current CD clock rate: 400000 kHz
> [drm:intel_update_max_cdclk] Max CD clock rate: 400000 kHz
> [drm:intel_update_max_cdclk] Max dotclock rate: 360000 kHz
> vgaarb: device changed decodes: PCI:0000:00:02.0,olddecodes=io+mem,decodes=io+mem:owns=io+mem
> [drm:intel_crt_reset] crt adpa set to 0xf40000
> [drm:intel_dp_init_connector] Adding DP connector on port C
> [drm:intel_dp_aux_init] registering DPDDC-C bus for card0-DP-1
> [drm:ironlake_init_pch_refclk] has_panel 0 has_lvds 0 has_ck505 0
> [drm:ironlake_init_pch_refclk] Disabling SSC entirely
> … later we try committing the first modeset …
> [drm:intel_dump_pipe_config] [CRTC:26][modeset] config ffff88041b02e800 for pipe A
> [drm:intel_dump_pipe_config] cpu_transcoder: A
> …
> [drm:intel_dump_pipe_config] dpll_hw_state: dpll: 0xc4016001, dpll_md: 0x0, fp0: 0x20e08, fp1: 0x30d07
> [drm:intel_dump_pipe_config] planes on this crtc
> [drm:intel_dump_pipe_config] STANDARD PLANE:23 plane: 0.0 idx: 0 enabled
> [drm:intel_dump_pipe_config]     FB:42, fb = 800x600 format = 0x34325258
> [drm:intel_dump_pipe_config]     scaler:0 src (0, 0) 800x600 dst (0, 0) 800x600
> [drm:intel_dump_pipe_config] CURSOR PLANE:25 plane: 0.1 idx: 1 disabled, scaler_id = 0
> [drm:intel_dump_pipe_config] STANDARD PLANE:27 plane: 0.1 idx: 2 disabled, scaler_id = 0
> [drm:intel_get_shared_dpll] CRTC:26 allocated PCH DPLL A
> [drm:intel_get_shared_dpll] using PCH DPLL A for pipe A
> [drm:ilk_audio_codec_disable] Disable audio codec on port C, pipe A
> [drm:intel_disable_pipe] disabling pipe A
> ------------[ cut here ]------------
> WARNING: CPU: 1 PID: 130 at drivers/gpu/drm/i915/intel_display.c:1146 intel_disable_pipe+0x297/0x2d0 [i915]
> pipe_off wait timed out
> …
> ---[ end trace 94fc8aa03ae139e8 ]---
> [drm:intel_dp_link_down]
> [drm:ironlake_crtc_disable [i915]] *ERROR* failed to disable transcoder A
> 
> Later modesets succeed since they reset the DPLL's configuration anyway,
> but this is enough to get stuck with a big fat warning in dmesg.
> 
> Normally we'd need to add some sort of ref counting mechanism to the
> CRTCs so we avoid accidentally trying to shut off a shared resource, but
> since ignore what the BIOS does anyway and we shut off the refclks
> before any modesets, this workaround should suffice for now.
> 
> Cc: stable@vger.kernel.org
> Signed-off-by: Lyude <cpaul@redhat.com>
> ---
>  drivers/gpu/drm/i915/intel_display.c | 19 ++++++++++++++++++-
>  1 file changed, 18 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index d500e6f..3fb6025 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -8230,7 +8230,8 @@ static void ironlake_init_pch_refclk(struct drm_device *dev)
>  {
>  	struct drm_i915_private *dev_priv = dev->dev_private;
>  	struct intel_encoder *encoder;
> -	u32 val, final;
> +	int i;
> +	u32 val, temp, final;
>  	bool has_lvds = false;
>  	bool has_cpu_edp = false;
>  	bool has_panel = false;
> @@ -8369,6 +8370,22 @@ static void ironlake_init_pch_refclk(struct drm_device *dev)
>  		I915_WRITE(PCH_DREF_CONTROL, val);
>  		POSTING_READ(PCH_DREF_CONTROL);
>  		udelay(200);
> +
> +		/* Unset SSC as the refclk for all of the DPLLs */
> +		for (i = 0; i < dev_priv->num_shared_dpll; i++) {
> +			temp = I915_READ(PCH_DPLL(i));
> +
> +			if (!(temp & PLLB_REF_INPUT_SPREADSPECTRUMIN))

should be something like
(temp & (DPLL_VCO_ENABLE | PLL_REF_INPUT_MASK)) != (DPLL_VCO_ENABLE | PLL_REF_INPUT_SPREADSPECTRUMIN)

> +				continue;
> +
> +			DRM_DEBUG_KMS("Disabling SSC refclk for %s\n",
> +				      dev_priv->shared_dplls[i].name);
> +
> +			/* Change refclk to DREFCLK */
> +			temp &= ~PLL_REF_INPUT_MASK;

I doubt that's safe. We need to just leave the SSC source enabled
instead if any DPLL depends on it. I think something along these 
lines should be sufficient:

-       final &= ~DREF_SSC_SOURCE_MASK;
        final &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
-       final &= ~DREF_SSC1_ENABLE;
+
+       /* blah */
+       if (!dpll_uses_ssc()) {
+               final &= ~DREF_SSC_SOURCE_MASK;
+               final &= ~DREF_SSC1_ENABLE;
+       }


> +
> +			I915_WRITE(PCH_DPLL(i), temp);
> +		}
>  	}
>  
>  	BUG_ON(val != final);
> -- 
> 2.5.5
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index d500e6f..3fb6025 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -8230,7 +8230,8 @@  static void ironlake_init_pch_refclk(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_encoder *encoder;
-	u32 val, final;
+	int i;
+	u32 val, temp, final;
 	bool has_lvds = false;
 	bool has_cpu_edp = false;
 	bool has_panel = false;
@@ -8369,6 +8370,22 @@  static void ironlake_init_pch_refclk(struct drm_device *dev)
 		I915_WRITE(PCH_DREF_CONTROL, val);
 		POSTING_READ(PCH_DREF_CONTROL);
 		udelay(200);
+
+		/* Unset SSC as the refclk for all of the DPLLs */
+		for (i = 0; i < dev_priv->num_shared_dpll; i++) {
+			temp = I915_READ(PCH_DPLL(i));
+
+			if (!(temp & PLLB_REF_INPUT_SPREADSPECTRUMIN))
+				continue;
+
+			DRM_DEBUG_KMS("Disabling SSC refclk for %s\n",
+				      dev_priv->shared_dplls[i].name);
+
+			/* Change refclk to DREFCLK */
+			temp &= ~PLL_REF_INPUT_MASK;
+
+			I915_WRITE(PCH_DPLL(i), temp);
+		}
 	}
 
 	BUG_ON(val != final);