aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLyude <cpaul@redhat.com>2016-05-25 14:11:02 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2016-05-26 03:55:12 -0400
commitf165d2834ceb3d5c29bebadadc27629bebf402ac (patch)
tree813303847080ab5b03efa9ccc0421dc09d2fc664
parentd66a21947e2147a0e313825ee461e954e8fe39cb (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.c49
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);