drm/i915: Do not touch the PCH SSC reference if a PLL is using it
[sfrench/cifs-2.6.git] / drivers / gpu / drm / i915 / intel_display.c
index 048cb8d7ae65ba1c824218560d85c5b48da7d386..352c42826cb1a2482bfc7e83971f78e4736c5a03 100644 (file)
@@ -2463,10 +2463,14 @@ static unsigned int intel_fb_modifier_to_tiling(u64 fb_modifier)
  * main surface.
  */
 static const struct drm_format_info ccs_formats[] = {
-       { .format = DRM_FORMAT_XRGB8888, .depth = 24, .num_planes = 2, .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, },
-       { .format = DRM_FORMAT_XBGR8888, .depth = 24, .num_planes = 2, .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, },
-       { .format = DRM_FORMAT_ARGB8888, .depth = 32, .num_planes = 2, .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, },
-       { .format = DRM_FORMAT_ABGR8888, .depth = 32, .num_planes = 2, .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, },
+       { .format = DRM_FORMAT_XRGB8888, .depth = 24, .num_planes = 2,
+         .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, },
+       { .format = DRM_FORMAT_XBGR8888, .depth = 24, .num_planes = 2,
+         .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, },
+       { .format = DRM_FORMAT_ARGB8888, .depth = 32, .num_planes = 2,
+         .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, .has_alpha = true, },
+       { .format = DRM_FORMAT_ABGR8888, .depth = 32, .num_planes = 2,
+         .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, .has_alpha = true, },
 };
 
 static const struct drm_format_info *
@@ -8661,6 +8665,7 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
                pipe_config->cgm_mode = I915_READ(CGM_PIPE_MODE(crtc->pipe));
 
        i9xx_get_pipe_color_config(pipe_config);
+       intel_color_get_config(pipe_config);
 
        if (INTEL_GEN(dev_priv) < 4)
                pipe_config->double_wide = tmp & PIPECONF_DOUBLE_WIDE;
@@ -9121,22 +9126,95 @@ static void lpt_bend_clkout_dp(struct drm_i915_private *dev_priv, int steps)
 
 #undef BEND_IDX
 
+static bool spll_uses_pch_ssc(struct drm_i915_private *dev_priv)
+{
+       u32 fuse_strap = I915_READ(FUSE_STRAP);
+       u32 ctl = I915_READ(SPLL_CTL);
+
+       if ((ctl & SPLL_PLL_ENABLE) == 0)
+               return false;
+
+       if ((ctl & SPLL_PLL_REF_MASK) == SPLL_PLL_SSC &&
+           (fuse_strap & HSW_CPU_SSC_ENABLE) == 0)
+               return true;
+
+       if (IS_BROADWELL(dev_priv) &&
+           (ctl & SPLL_PLL_REF_MASK) == SPLL_PLL_NON_SSC)
+               return true;
+
+       return false;
+}
+
+static bool wrpll_uses_pch_ssc(struct drm_i915_private *dev_priv,
+                              enum intel_dpll_id id)
+{
+       u32 fuse_strap = I915_READ(FUSE_STRAP);
+       u32 ctl = I915_READ(WRPLL_CTL(id));
+
+       if ((ctl & WRPLL_PLL_ENABLE) == 0)
+               return false;
+
+       if ((ctl & WRPLL_PLL_REF_MASK) == WRPLL_PLL_SSC)
+               return true;
+
+       if ((IS_BROADWELL(dev_priv) || IS_HSW_ULT(dev_priv)) &&
+           (ctl & WRPLL_PLL_REF_MASK) == WRPLL_PLL_NON_SSC &&
+           (fuse_strap & HSW_CPU_SSC_ENABLE) == 0)
+               return true;
+
+       return false;
+}
+
 static void lpt_init_pch_refclk(struct drm_i915_private *dev_priv)
 {
        struct intel_encoder *encoder;
-       bool has_vga = false;
+       bool pch_ssc_in_use = false;
+       bool has_fdi = false;
 
        for_each_intel_encoder(&dev_priv->drm, encoder) {
                switch (encoder->type) {
                case INTEL_OUTPUT_ANALOG:
-                       has_vga = true;
+                       has_fdi = true;
                        break;
                default:
                        break;
                }
        }
 
-       if (has_vga) {
+       /*
+        * The BIOS may have decided to use the PCH SSC
+        * reference so we must not disable it until the
+        * relevant PLLs have stopped relying on it. We'll
+        * just leave the PCH SSC reference enabled in case
+        * any active PLL is using it. It will get disabled
+        * after runtime suspend if we don't have FDI.
+        *
+        * TODO: Move the whole reference clock handling
+        * to the modeset sequence proper so that we can
+        * actually enable/disable/reconfigure these things
+        * safely. To do that we need to introduce a real
+        * clock hierarchy. That would also allow us to do
+        * clock bending finally.
+        */
+       if (spll_uses_pch_ssc(dev_priv)) {
+               DRM_DEBUG_KMS("SPLL using PCH SSC\n");
+               pch_ssc_in_use = true;
+       }
+
+       if (wrpll_uses_pch_ssc(dev_priv, DPLL_ID_WRPLL1)) {
+               DRM_DEBUG_KMS("WRPLL1 using PCH SSC\n");
+               pch_ssc_in_use = true;
+       }
+
+       if (wrpll_uses_pch_ssc(dev_priv, DPLL_ID_WRPLL2)) {
+               DRM_DEBUG_KMS("WRPLL2 using PCH SSC\n");
+               pch_ssc_in_use = true;
+       }
+
+       if (pch_ssc_in_use)
+               return;
+
+       if (has_fdi) {
                lpt_bend_clkout_dp(dev_priv, 0);
                lpt_enable_clkout_dp(dev_priv, true, true);
        } else {
@@ -9758,6 +9836,7 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
        pipe_config->csc_mode = I915_READ(PIPE_CSC_MODE(crtc->pipe));
 
        i9xx_get_pipe_color_config(pipe_config);
+       intel_color_get_config(pipe_config);
 
        if (I915_READ(PCH_TRANSCONF(crtc->pipe)) & TRANS_ENABLE) {
                struct intel_shared_dpll *pll;
@@ -10206,6 +10285,8 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
                i9xx_get_pipe_color_config(pipe_config);
        }
 
+       intel_color_get_config(pipe_config);
+
        power_domain = POWER_DOMAIN_PIPE_PANEL_FITTER(crtc->pipe);
        WARN_ON(power_domain_mask & BIT_ULL(power_domain));
 
@@ -11705,17 +11786,19 @@ compute_baseline_pipe_bpp(struct intel_crtc *crtc,
 static void intel_dump_crtc_timings(const struct drm_display_mode *mode)
 {
        DRM_DEBUG_KMS("crtc timings: %d %d %d %d %d %d %d %d %d, "
-                       "type: 0x%x flags: 0x%x\n",
-               mode->crtc_clock,
-               mode->crtc_hdisplay, mode->crtc_hsync_start,
-               mode->crtc_hsync_end, mode->crtc_htotal,
-               mode->crtc_vdisplay, mode->crtc_vsync_start,
-               mode->crtc_vsync_end, mode->crtc_vtotal, mode->type, mode->flags);
+                     "type: 0x%x flags: 0x%x\n",
+                     mode->crtc_clock,
+                     mode->crtc_hdisplay, mode->crtc_hsync_start,
+                     mode->crtc_hsync_end, mode->crtc_htotal,
+                     mode->crtc_vdisplay, mode->crtc_vsync_start,
+                     mode->crtc_vsync_end, mode->crtc_vtotal,
+                     mode->type, mode->flags);
 }
 
 static inline void
-intel_dump_m_n_config(struct intel_crtc_state *pipe_config, char *id,
-                     unsigned int lane_count, struct intel_link_m_n *m_n)
+intel_dump_m_n_config(const struct intel_crtc_state *pipe_config,
+                     const char *id, unsigned int lane_count,
+                     const struct intel_link_m_n *m_n)
 {
        DRM_DEBUG_KMS("%s: lanes: %i; gmch_m: %u, gmch_n: %u, link_m: %u, link_n: %u, tu: %u\n",
                      id, lane_count,
@@ -11793,22 +11876,50 @@ static const char *output_formats(enum intel_output_format format)
        return output_format_str[format];
 }
 
-static void intel_dump_pipe_config(struct intel_crtc_state *pipe_config,
+static void intel_dump_plane_state(const struct intel_plane_state *plane_state)
+{
+       struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
+       const struct drm_framebuffer *fb = plane_state->base.fb;
+       struct drm_format_name_buf format_name;
+
+       if (!fb) {
+               DRM_DEBUG_KMS("[PLANE:%d:%s] fb: [NOFB], visible: %s\n",
+                             plane->base.base.id, plane->base.name,
+                             yesno(plane_state->base.visible));
+               return;
+       }
+
+       DRM_DEBUG_KMS("[PLANE:%d:%s] fb: [FB:%d] %ux%u format = %s, visible: %s\n",
+                     plane->base.base.id, plane->base.name,
+                     fb->base.id, fb->width, fb->height,
+                     drm_get_format_name(fb->format->format, &format_name),
+                     yesno(plane_state->base.visible));
+       DRM_DEBUG_KMS("\trotation: 0x%x, scaler: %d\n",
+                     plane_state->base.rotation, plane_state->scaler_id);
+       if (plane_state->base.visible)
+               DRM_DEBUG_KMS("\tsrc: " DRM_RECT_FP_FMT " dst: " DRM_RECT_FMT "\n",
+                             DRM_RECT_FP_ARG(&plane_state->base.src),
+                             DRM_RECT_ARG(&plane_state->base.dst));
+}
+
+static void intel_dump_pipe_config(const struct intel_crtc_state *pipe_config,
+                                  struct intel_atomic_state *state,
                                   const char *context)
 {
        struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
-       struct drm_device *dev = crtc->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct drm_plane *plane;
-       struct intel_plane *intel_plane;
-       struct intel_plane_state *state;
-       struct drm_framebuffer *fb;
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       const struct intel_plane_state *plane_state;
+       struct intel_plane *plane;
        char buf[64];
+       int i;
 
        DRM_DEBUG_KMS("[CRTC:%d:%s] enable: %s %s\n",
                      crtc->base.base.id, crtc->base.name,
                      yesno(pipe_config->base.enable), context);
 
+       if (!pipe_config->base.enable)
+               goto dump_planes;
+
        snprintf_output_types(buf, sizeof(buf), pipe_config->output_types);
        DRM_DEBUG_KMS("active: %s, output_types: %s (0x%x), output format: %s\n",
                      yesno(pipe_config->base.active),
@@ -11883,35 +11994,13 @@ static void intel_dump_pipe_config(struct intel_crtc_state *pipe_config,
 
        intel_dpll_dump_hw_state(dev_priv, &pipe_config->dpll_hw_state);
 
-       DRM_DEBUG_KMS("planes on this crtc\n");
-       list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
-               struct drm_format_name_buf format_name;
-               intel_plane = to_intel_plane(plane);
-               if (intel_plane->pipe != crtc->pipe)
-                       continue;
-
-               state = to_intel_plane_state(plane->state);
-               fb = state->base.fb;
-               if (!fb) {
-                       DRM_DEBUG_KMS("[PLANE:%d:%s] disabled, scaler_id = %d\n",
-                                     plane->base.id, plane->name, state->scaler_id);
-                       continue;
-               }
+dump_planes:
+       if (!state)
+               return;
 
-               DRM_DEBUG_KMS("[PLANE:%d:%s] FB:%d, fb = %ux%u format = %s\n",
-                             plane->base.id, plane->name,
-                             fb->base.id, fb->width, fb->height,
-                             drm_get_format_name(fb->format->format, &format_name));
-               if (INTEL_GEN(dev_priv) >= 9)
-                       DRM_DEBUG_KMS("\tscaler:%d src %dx%d+%d+%d dst %dx%d+%d+%d\n",
-                                     state->scaler_id,
-                                     state->base.src.x1 >> 16,
-                                     state->base.src.y1 >> 16,
-                                     drm_rect_width(&state->base.src) >> 16,
-                                     drm_rect_height(&state->base.src) >> 16,
-                                     state->base.dst.x1, state->base.dst.y1,
-                                     drm_rect_width(&state->base.dst),
-                                     drm_rect_height(&state->base.dst));
+       for_each_new_intel_plane_in_state(state, plane, plane_state, i) {
+               if (plane->pipe == crtc->pipe)
+                       intel_dump_plane_state(plane_state);
        }
 }
 
@@ -12151,7 +12240,7 @@ encoder_retry:
        return 0;
 }
 
-static bool intel_fuzzy_clock_check(int clock1, int clock2)
+bool intel_fuzzy_clock_check(int clock1, int clock2)
 {
        int diff;
 
@@ -12901,8 +12990,8 @@ verify_crtc_state(struct drm_crtc *crtc,
        if (!intel_pipe_config_compare(dev_priv, sw_config,
                                       pipe_config, false)) {
                I915_STATE_WARN(1, "pipe state doesn't match!\n");
-               intel_dump_pipe_config(pipe_config, "[hw state]");
-               intel_dump_pipe_config(sw_config, "[sw state]");
+               intel_dump_pipe_config(pipe_config, NULL, "[hw state]");
+               intel_dump_pipe_config(sw_config, NULL, "[sw state]");
        }
 }
 
@@ -13369,7 +13458,7 @@ static int intel_atomic_check(struct drm_device *dev,
 
        ret = drm_atomic_helper_check_modeset(dev, &state->base);
        if (ret)
-               return ret;
+               goto fail;
 
        for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
                                            new_crtc_state, i) {
@@ -13382,12 +13471,8 @@ static int intel_atomic_check(struct drm_device *dev,
                }
 
                ret = intel_modeset_pipe_config(new_crtc_state);
-               if (ret == -EDEADLK)
-                       return ret;
-               if (ret) {
-                       intel_dump_pipe_config(new_crtc_state, "[failed]");
-                       return ret;
-               }
+               if (ret)
+                       goto fail;
 
                if (intel_pipe_config_compare(dev_priv, old_crtc_state,
                                              new_crtc_state, true)) {
@@ -13401,32 +13486,32 @@ static int intel_atomic_check(struct drm_device *dev,
 
        ret = drm_dp_mst_atomic_check(&state->base);
        if (ret)
-               return ret;
+               goto fail;
 
        if (any_ms) {
                ret = intel_modeset_checks(state);
                if (ret)
-                       return ret;
+                       goto fail;
        } else {
                state->cdclk.logical = dev_priv->cdclk.logical;
        }
 
        ret = icl_add_linked_planes(state);
        if (ret)
-               return ret;
+               goto fail;
 
        ret = drm_atomic_helper_check_planes(dev, &state->base);
        if (ret)
-               return ret;
+               goto fail;
 
        intel_fbc_choose_crtc(dev_priv, state);
        ret = calc_watermark_data(state);
        if (ret)
-               return ret;
+               goto fail;
 
        ret = intel_bw_atomic_check(state);
        if (ret)
-               return ret;
+               goto fail;
 
        for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
                                            new_crtc_state, i) {
@@ -13434,12 +13519,26 @@ static int intel_atomic_check(struct drm_device *dev,
                    !new_crtc_state->update_pipe)
                        continue;
 
-               intel_dump_pipe_config(new_crtc_state,
+               intel_dump_pipe_config(new_crtc_state, state,
                                       needs_modeset(&new_crtc_state->base) ?
                                       "[modeset]" : "[fastset]");
        }
 
        return 0;
+
+ fail:
+       if (ret == -EDEADLK)
+               return ret;
+
+       /*
+        * FIXME would probably be nice to know which crtc specifically
+        * caused the failure, in cases where we can pinpoint it.
+        */
+       for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
+                                           new_crtc_state, i)
+               intel_dump_pipe_config(new_crtc_state, state, "[failed]");
+
+       return ret;
 }
 
 static int intel_atomic_prepare_commit(struct drm_device *dev,
@@ -16665,7 +16764,7 @@ intel_modeset_setup_hw_state(struct drm_device *dev,
        for_each_intel_crtc(&dev_priv->drm, crtc) {
                crtc_state = to_intel_crtc_state(crtc->base.state);
                intel_sanitize_crtc(crtc, ctx);
-               intel_dump_pipe_config(crtc_state, "[setup_hw_state]");
+               intel_dump_pipe_config(crtc_state, NULL, "[setup_hw_state]");
        }
 
        intel_modeset_update_connector_atomic_state(dev);