| From 476490a945e1f0f6bd58e303058d2d8ca93a974c Mon Sep 17 00:00:00 2001 |
| From: Lyude <cpaul@redhat.com> |
| Date: Tue, 14 Jun 2016 11:04:09 -0400 |
| Subject: drm/i915/ilk: Don't disable SSC source if it's in use |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| From: Lyude <cpaul@redhat.com> |
| |
| commit 476490a945e1f0f6bd58e303058d2d8ca93a974c upstream. |
| |
| 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 v4: |
| - Fix calculation of final for systems with LVDS panels (fixes BUG() on |
| CI test suite) |
| 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. |
| |
| 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/1465916649-10228-1-git-send-email-cpaul@redhat.com |
| Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/gpu/drm/i915/intel_display.c | 48 ++++++++++++++++++++++++----------- |
| 1 file changed, 34 insertions(+), 14 deletions(-) |
| |
| --- a/drivers/gpu/drm/i915/intel_display.c |
| +++ b/drivers/gpu/drm/i915/intel_display.c |
| @@ -8228,12 +8228,14 @@ static void ironlake_init_pch_refclk(str |
| { |
| struct drm_i915_private *dev_priv = dev->dev_private; |
| struct intel_encoder *encoder; |
| + int i; |
| u32 val, final; |
| bool has_lvds = false; |
| bool has_cpu_edp = false; |
| bool has_panel = false; |
| bool has_ck505 = false; |
| bool can_ssc = false; |
| + bool using_ssc_source = false; |
| |
| /* We need to take the global config into account */ |
| for_each_intel_encoder(dev, encoder) { |
| @@ -8260,8 +8262,22 @@ static void ironlake_init_pch_refclk(str |
| can_ssc = true; |
| } |
| |
| - DRM_DEBUG_KMS("has_panel %d has_lvds %d has_ck505 %d\n", |
| - has_panel, has_lvds, has_ck505); |
| + /* Check if any DPLLs are using the SSC source */ |
| + for (i = 0; i < dev_priv->num_shared_dpll; i++) { |
| + u32 temp = I915_READ(PCH_DPLL(i)); |
| + |
| + if (!(temp & DPLL_VCO_ENABLE)) |
| + continue; |
| + |
| + if ((temp & PLL_REF_INPUT_MASK) == |
| + PLLB_REF_INPUT_SPREADSPECTRUMIN) { |
| + using_ssc_source = true; |
| + break; |
| + } |
| + } |
| + |
| + DRM_DEBUG_KMS("has_panel %d has_lvds %d has_ck505 %d using_ssc_source %d\n", |
| + has_panel, has_lvds, has_ck505, using_ssc_source); |
| |
| /* Ironlake: try to setup display ref clock before DPLL |
| * enabling. This is only under driver's control after |
| @@ -8298,9 +8314,9 @@ static void ironlake_init_pch_refclk(str |
| final |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD; |
| } else |
| final |= DREF_CPU_SOURCE_OUTPUT_DISABLE; |
| - } else { |
| - final |= DREF_SSC_SOURCE_DISABLE; |
| - final |= DREF_CPU_SOURCE_OUTPUT_DISABLE; |
| + } else if (using_ssc_source) { |
| + final |= DREF_SSC_SOURCE_ENABLE; |
| + final |= DREF_SSC1_ENABLE; |
| } |
| |
| if (final == val) |
| @@ -8346,7 +8362,7 @@ static void ironlake_init_pch_refclk(str |
| POSTING_READ(PCH_DREF_CONTROL); |
| udelay(200); |
| } else { |
| - DRM_DEBUG_KMS("Disabling SSC entirely\n"); |
| + DRM_DEBUG_KMS("Disabling CPU source output\n"); |
| |
| val &= ~DREF_CPU_SOURCE_OUTPUT_MASK; |
| |
| @@ -8357,16 +8373,20 @@ static void ironlake_init_pch_refclk(str |
| POSTING_READ(PCH_DREF_CONTROL); |
| udelay(200); |
| |
| - /* Turn off the SSC source */ |
| - val &= ~DREF_SSC_SOURCE_MASK; |
| - val |= DREF_SSC_SOURCE_DISABLE; |
| + if (!using_ssc_source) { |
| + DRM_DEBUG_KMS("Disabling SSC source\n"); |
| |
| - /* Turn off SSC1 */ |
| - val &= ~DREF_SSC1_ENABLE; |
| + /* Turn off the SSC source */ |
| + val &= ~DREF_SSC_SOURCE_MASK; |
| + val |= DREF_SSC_SOURCE_DISABLE; |
| |
| - I915_WRITE(PCH_DREF_CONTROL, val); |
| - POSTING_READ(PCH_DREF_CONTROL); |
| - udelay(200); |
| + /* Turn off SSC1 */ |
| + val &= ~DREF_SSC1_ENABLE; |
| + |
| + I915_WRITE(PCH_DREF_CONTROL, val); |
| + POSTING_READ(PCH_DREF_CONTROL); |
| + udelay(200); |
| + } |
| } |
| |
| BUG_ON(val != final); |