From mboxrd@z Thu Jan 1 00:00:00 1970 From: Lyude Subject: [PATCH v4] drm/i915/ilk: Don't disable SSC source if it's in use Date: Wed, 25 May 2016 14:11:02 -0400 Message-ID: <1464199863-9397-1-git-send-email-cpaul@redhat.com> References: <20160524185924.GI4329@intel.com> Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: QUOTED-PRINTABLE Return-path: In-Reply-To: <20160524185924.GI4329@intel.com> Sender: stable-owner@vger.kernel.org To: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= , intel-gfx@lists.freedesktop.org Cc: Lyude , stable@vger.kernel.org, Daniel Vetter , Jani Nikula , David Airlie , "open list:INTEL DRM DRIVERS excluding Poulsbo, Moorestow..., linux-kernel@vger.kernel.org open list" List-Id: dri-devel@lists.freedesktop.org Thanks to Ville Syrj=C3=A4l=C3=A4 for pointing me towards the cause of = this issue. Unfortunately one of the sideaffects of having the refclk for a DPLL se= t 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=3Dio+mem,de= codes=3Dio+mem:owns=3Dio+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 =E2=80=A6 later we try committing the first modeset =E2=80=A6 [drm:intel_dump_pipe_config] [CRTC:26][modeset] config ffff88041b02e800= for pipe A [drm:intel_dump_pipe_config] cpu_transcoder: A =E2=80=A6 [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 enable= d [drm:intel_dump_pipe_config] FB:42, fb =3D 800x600 format =3D 0x343= 25258 [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 =3D 0 [drm:intel_dump_pipe_config] STANDARD PLANE:27 plane: 0.1 idx: 2 disabl= ed, scaler_id =3D 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 i= ntel_disable_pipe+0x297/0x2d0 [i915] pipe_off wait timed out =E2=80=A6 ---[ 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_ck50= 5 - 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=C3=A4l=C3=A4 Signed-off-by: Lyude --- drivers/gpu/drm/i915/intel_display.c | 49 ++++++++++++++++++++++++++--= -------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i91= 5/intel_display.c index d500e6f..471e3a8 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8230,12 +8230,14 @@ static void ironlake_init_pch_refclk(struct drm= _device *dev) { struct drm_i915_private *dev_priv =3D dev->dev_private; struct intel_encoder *encoder; + int i; u32 val, final; bool has_lvds =3D false; bool has_cpu_edp =3D false; bool has_panel =3D false; bool has_ck505 =3D false; bool can_ssc =3D false; + bool using_ssc_source =3D false; =20 /* We need to take the global config into account */ for_each_intel_encoder(dev, encoder) { @@ -8262,8 +8264,22 @@ static void ironlake_init_pch_refclk(struct drm_= device *dev) can_ssc =3D true; } =20 - 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 =3D 0; i < dev_priv->num_shared_dpll; i++) { + u32 temp =3D I915_READ(PCH_DPLL(i)); + + if (!(temp & DPLL_VCO_ENABLE)) + continue; + + if ((temp & PLL_REF_INPUT_MASK) =3D=3D + PLLB_REF_INPUT_SPREADSPECTRUMIN) { + using_ssc_source =3D 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); =20 /* Ironlake: try to setup display ref clock before DPLL * enabling. This is only under driver's control after @@ -8283,9 +8299,12 @@ static void ironlake_init_pch_refclk(struct drm_= device *dev) else final |=3D DREF_NONSPREAD_SOURCE_ENABLE; =20 - final &=3D ~DREF_SSC_SOURCE_MASK; final &=3D ~DREF_CPU_SOURCE_OUTPUT_MASK; - final &=3D ~DREF_SSC1_ENABLE; + + if (!using_ssc_source) { + final &=3D ~DREF_SSC_SOURCE_MASK; + final &=3D ~DREF_SSC1_ENABLE; + } =20 if (has_panel) { final |=3D DREF_SSC_SOURCE_ENABLE; @@ -8348,7 +8367,7 @@ static void ironlake_init_pch_refclk(struct drm_d= evice *dev) POSTING_READ(PCH_DREF_CONTROL); udelay(200); } else { - DRM_DEBUG_KMS("Disabling SSC entirely\n"); + DRM_DEBUG_KMS("Disabling CPU source output\n"); =20 val &=3D ~DREF_CPU_SOURCE_OUTPUT_MASK; =20 @@ -8359,16 +8378,20 @@ static void ironlake_init_pch_refclk(struct drm= _device *dev) POSTING_READ(PCH_DREF_CONTROL); udelay(200); =20 - /* Turn off the SSC source */ - val &=3D ~DREF_SSC_SOURCE_MASK; - val |=3D DREF_SSC_SOURCE_DISABLE; + if (!using_ssc_source) { + DRM_DEBUG_KMS("Disabling SSC source\n"); =20 - /* Turn off SSC1 */ - val &=3D ~DREF_SSC1_ENABLE; + /* Turn off the SSC source */ + val &=3D ~DREF_SSC_SOURCE_MASK; + val |=3D DREF_SSC_SOURCE_DISABLE; =20 - I915_WRITE(PCH_DREF_CONTROL, val); - POSTING_READ(PCH_DREF_CONTROL); - udelay(200); + /* Turn off SSC1 */ + val &=3D ~DREF_SSC1_ENABLE; + + I915_WRITE(PCH_DREF_CONTROL, val); + POSTING_READ(PCH_DREF_CONTROL); + udelay(200); + } } =20 BUG_ON(val !=3D final); --=20 2.5.5