diff options
author | Lyude <cpaul@redhat.com> | 2016-05-25 14:11:02 -0400 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2016-05-26 03:55:12 -0400 |
commit | f165d2834ceb3d5c29bebadadc27629bebf402ac (patch) | |
tree | 813303847080ab5b03efa9ccc0421dc09d2fc664 | |
parent | d66a21947e2147a0e313825ee461e954e8fe39cb (diff) |
drm/i915/ilk: Don't disable SSC source if it's in use
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 enable SSC in both PCH_DREF_CONTROL and in 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.
A better solution would be to add refcounts for the SSC source, but for
now leaving the source clock on should suffice.
Changes since v3:
- Move temp variable into loop
- Move checks for using_ssc_source to after we've figured out has_ck505
- Add using_ssc_source to debug output
Changes since v2:
- Fix debug output for when we disable the CPU source
Changes since v1:
- Leave the SSC source clock on instead of just shutting it off on all
of the DPLL configurations.
Cc: stable@vger.kernel.org
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Lyude <cpaul@redhat.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/1464199863-9397-1-git-send-email-cpaul@redhat.com
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 49 |
1 files changed, 36 insertions, 13 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d6d075c7b8fe..5b382e80414e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
@@ -8358,12 +8358,14 @@ static void ironlake_init_pch_refclk(struct drm_device *dev) | |||
8358 | { | 8358 | { |
8359 | struct drm_i915_private *dev_priv = dev->dev_private; | 8359 | struct drm_i915_private *dev_priv = dev->dev_private; |
8360 | struct intel_encoder *encoder; | 8360 | struct intel_encoder *encoder; |
8361 | int i; | ||
8361 | u32 val, final; | 8362 | u32 val, final; |
8362 | bool has_lvds = false; | 8363 | bool has_lvds = false; |
8363 | bool has_cpu_edp = false; | 8364 | bool has_cpu_edp = false; |
8364 | bool has_panel = false; | 8365 | bool has_panel = false; |
8365 | bool has_ck505 = false; | 8366 | bool has_ck505 = false; |
8366 | bool can_ssc = false; | 8367 | bool can_ssc = false; |
8368 | bool using_ssc_source = false; | ||
8367 | 8369 | ||
8368 | /* We need to take the global config into account */ | 8370 | /* We need to take the global config into account */ |
8369 | for_each_intel_encoder(dev, encoder) { | 8371 | for_each_intel_encoder(dev, encoder) { |
@@ -8390,8 +8392,22 @@ static void ironlake_init_pch_refclk(struct drm_device *dev) | |||
8390 | can_ssc = true; | 8392 | can_ssc = true; |
8391 | } | 8393 | } |
8392 | 8394 | ||
8393 | DRM_DEBUG_KMS("has_panel %d has_lvds %d has_ck505 %d\n", | 8395 | /* Check if any DPLLs are using the SSC source */ |
8394 | has_panel, has_lvds, has_ck505); | 8396 | for (i = 0; i < dev_priv->num_shared_dpll; i++) { |
8397 | u32 temp = I915_READ(PCH_DPLL(i)); | ||
8398 | |||
8399 | if (!(temp & DPLL_VCO_ENABLE)) | ||
8400 | continue; | ||
8401 | |||
8402 | if ((temp & PLL_REF_INPUT_MASK) == | ||
8403 | PLLB_REF_INPUT_SPREADSPECTRUMIN) { | ||
8404 | using_ssc_source = true; | ||
8405 | break; | ||
8406 | } | ||
8407 | } | ||
8408 | |||
8409 | DRM_DEBUG_KMS("has_panel %d has_lvds %d has_ck505 %d using_ssc_source %d\n", | ||
8410 | has_panel, has_lvds, has_ck505, using_ssc_source); | ||
8395 | 8411 | ||
8396 | /* Ironlake: try to setup display ref clock before DPLL | 8412 | /* Ironlake: try to setup display ref clock before DPLL |
8397 | * enabling. This is only under driver's control after | 8413 | * enabling. This is only under driver's control after |
@@ -8411,9 +8427,12 @@ static void ironlake_init_pch_refclk(struct drm_device *dev) | |||
8411 | else | 8427 | else |
8412 | final |= DREF_NONSPREAD_SOURCE_ENABLE; | 8428 | final |= DREF_NONSPREAD_SOURCE_ENABLE; |
8413 | 8429 | ||
8414 | final &= ~DREF_SSC_SOURCE_MASK; | ||
8415 | final &= ~DREF_CPU_SOURCE_OUTPUT_MASK; | 8430 | final &= ~DREF_CPU_SOURCE_OUTPUT_MASK; |
8416 | final &= ~DREF_SSC1_ENABLE; | 8431 | |
8432 | if (!using_ssc_source) { | ||
8433 | final &= ~DREF_SSC_SOURCE_MASK; | ||
8434 | final &= ~DREF_SSC1_ENABLE; | ||
8435 | } | ||
8417 | 8436 | ||
8418 | if (has_panel) { | 8437 | if (has_panel) { |
8419 | final |= DREF_SSC_SOURCE_ENABLE; | 8438 | final |= DREF_SSC_SOURCE_ENABLE; |
@@ -8476,7 +8495,7 @@ static void ironlake_init_pch_refclk(struct drm_device *dev) | |||
8476 | POSTING_READ(PCH_DREF_CONTROL); | 8495 | POSTING_READ(PCH_DREF_CONTROL); |
8477 | udelay(200); | 8496 | udelay(200); |
8478 | } else { | 8497 | } else { |
8479 | DRM_DEBUG_KMS("Disabling SSC entirely\n"); | 8498 | DRM_DEBUG_KMS("Disabling CPU source output\n"); |
8480 | 8499 | ||
8481 | val &= ~DREF_CPU_SOURCE_OUTPUT_MASK; | 8500 | val &= ~DREF_CPU_SOURCE_OUTPUT_MASK; |
8482 | 8501 | ||
@@ -8487,16 +8506,20 @@ static void ironlake_init_pch_refclk(struct drm_device *dev) | |||
8487 | POSTING_READ(PCH_DREF_CONTROL); | 8506 | POSTING_READ(PCH_DREF_CONTROL); |
8488 | udelay(200); | 8507 | udelay(200); |
8489 | 8508 | ||
8490 | /* Turn off the SSC source */ | 8509 | if (!using_ssc_source) { |
8491 | val &= ~DREF_SSC_SOURCE_MASK; | 8510 | DRM_DEBUG_KMS("Disabling SSC source\n"); |
8492 | val |= DREF_SSC_SOURCE_DISABLE; | ||
8493 | 8511 | ||
8494 | /* Turn off SSC1 */ | 8512 | /* Turn off the SSC source */ |
8495 | val &= ~DREF_SSC1_ENABLE; | 8513 | val &= ~DREF_SSC_SOURCE_MASK; |
8514 | val |= DREF_SSC_SOURCE_DISABLE; | ||
8496 | 8515 | ||
8497 | I915_WRITE(PCH_DREF_CONTROL, val); | 8516 | /* Turn off SSC1 */ |
8498 | POSTING_READ(PCH_DREF_CONTROL); | 8517 | val &= ~DREF_SSC1_ENABLE; |
8499 | udelay(200); | 8518 | |
8519 | I915_WRITE(PCH_DREF_CONTROL, val); | ||
8520 | POSTING_READ(PCH_DREF_CONTROL); | ||
8521 | udelay(200); | ||
8522 | } | ||
8500 | } | 8523 | } |
8501 | 8524 | ||
8502 | BUG_ON(val != final); | 8525 | BUG_ON(val != final); |