Commit bcb66592 authored by Lyude's avatar Lyude Committed by Sasha Levin

drm/i915/ilk: Don't disable SSC source if it's in use

[ Upstream commit 476490a9 ]

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.

Cc: stable@vger.kernel.org
Reviewed-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: default avatarLyude <cpaul@redhat.com>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/1465916649-10228-1-git-send-email-cpaul@redhat.comSigned-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: default avatarSasha Levin <sasha.levin@oracle.com>
parent 069e0fa4
...@@ -6526,12 +6526,14 @@ static void ironlake_init_pch_refclk(struct drm_device *dev) ...@@ -6526,12 +6526,14 @@ static void ironlake_init_pch_refclk(struct drm_device *dev)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_encoder *encoder; struct intel_encoder *encoder;
int i;
u32 val, final; u32 val, final;
bool has_lvds = false; bool has_lvds = false;
bool has_cpu_edp = false; bool has_cpu_edp = false;
bool has_panel = false; bool has_panel = false;
bool has_ck505 = false; bool has_ck505 = false;
bool can_ssc = false; bool can_ssc = false;
bool using_ssc_source = false;
/* We need to take the global config into account */ /* We need to take the global config into account */
for_each_intel_encoder(dev, encoder) { for_each_intel_encoder(dev, encoder) {
...@@ -6556,8 +6558,22 @@ static void ironlake_init_pch_refclk(struct drm_device *dev) ...@@ -6556,8 +6558,22 @@ static void ironlake_init_pch_refclk(struct drm_device *dev)
can_ssc = true; can_ssc = true;
} }
DRM_DEBUG_KMS("has_panel %d has_lvds %d has_ck505 %d\n", /* Check if any DPLLs are using the SSC source */
has_panel, has_lvds, has_ck505); 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 /* Ironlake: try to setup display ref clock before DPLL
* enabling. This is only under driver's control after * enabling. This is only under driver's control after
...@@ -6594,9 +6610,9 @@ static void ironlake_init_pch_refclk(struct drm_device *dev) ...@@ -6594,9 +6610,9 @@ static void ironlake_init_pch_refclk(struct drm_device *dev)
final |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD; final |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
} else } else
final |= DREF_CPU_SOURCE_OUTPUT_DISABLE; final |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
} else { } else if (using_ssc_source) {
final |= DREF_SSC_SOURCE_DISABLE; final |= DREF_SSC_SOURCE_ENABLE;
final |= DREF_CPU_SOURCE_OUTPUT_DISABLE; final |= DREF_SSC1_ENABLE;
} }
if (final == val) if (final == val)
...@@ -6642,7 +6658,7 @@ static void ironlake_init_pch_refclk(struct drm_device *dev) ...@@ -6642,7 +6658,7 @@ static void ironlake_init_pch_refclk(struct drm_device *dev)
POSTING_READ(PCH_DREF_CONTROL); POSTING_READ(PCH_DREF_CONTROL);
udelay(200); udelay(200);
} else { } else {
DRM_DEBUG_KMS("Disabling SSC entirely\n"); DRM_DEBUG_KMS("Disabling CPU source output\n");
val &= ~DREF_CPU_SOURCE_OUTPUT_MASK; val &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
...@@ -6653,16 +6669,20 @@ static void ironlake_init_pch_refclk(struct drm_device *dev) ...@@ -6653,16 +6669,20 @@ static void ironlake_init_pch_refclk(struct drm_device *dev)
POSTING_READ(PCH_DREF_CONTROL); POSTING_READ(PCH_DREF_CONTROL);
udelay(200); udelay(200);
/* Turn off the SSC source */ if (!using_ssc_source) {
val &= ~DREF_SSC_SOURCE_MASK; DRM_DEBUG_KMS("Disabling SSC source\n");
val |= DREF_SSC_SOURCE_DISABLE;
/* Turn off SSC1 */ /* Turn off the SSC source */
val &= ~DREF_SSC1_ENABLE; val &= ~DREF_SSC_SOURCE_MASK;
val |= DREF_SSC_SOURCE_DISABLE;
I915_WRITE(PCH_DREF_CONTROL, val); /* Turn off SSC1 */
POSTING_READ(PCH_DREF_CONTROL); val &= ~DREF_SSC1_ENABLE;
udelay(200);
I915_WRITE(PCH_DREF_CONTROL, val);
POSTING_READ(PCH_DREF_CONTROL);
udelay(200);
}
} }
BUG_ON(val != final); BUG_ON(val != final);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment