diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 2c4b1c44296c..f1975f267710 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -93,6 +93,8 @@ intel_crtc_duplicate_state(struct drm_crtc *crtc) __drm_atomic_helper_crtc_duplicate_state(crtc, &crtc_state->base); + crtc_state->update_pipe = false; + return &crtc_state->base; } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 19049198364a..1691ec23bb95 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -112,6 +112,9 @@ static void skl_init_scalers(struct drm_device *dev, struct intel_crtc *intel_cr struct intel_crtc_state *crtc_state); static int i9xx_get_refclk(const struct intel_crtc_state *crtc_state, int num_connectors); +static void skylake_pfit_enable(struct intel_crtc *crtc); +static void ironlake_pfit_disable(struct intel_crtc *crtc, bool force); +static void ironlake_pfit_enable(struct intel_crtc *crtc); static void intel_modeset_setup_hw_state(struct drm_device *dev); typedef struct { @@ -3265,14 +3268,20 @@ static bool intel_crtc_has_pending_flip(struct drm_crtc *crtc) return pending; } -static void intel_update_pipe_size(struct intel_crtc *crtc) +static void intel_update_pipe_config(struct intel_crtc *crtc, + struct intel_crtc_state *old_crtc_state) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - const struct drm_display_mode *adjusted_mode; + struct intel_crtc_state *pipe_config = + to_intel_crtc_state(crtc->base.state); - if (!i915.fastboot) - return; + /* drm_atomic_helper_update_legacy_modeset_state might not be called. */ + crtc->base.mode = crtc->base.state->mode; + + DRM_DEBUG_KMS("Updating pipe size %ix%i -> %ix%i\n", + old_crtc_state->pipe_src_w, old_crtc_state->pipe_src_h, + pipe_config->pipe_src_w, pipe_config->pipe_src_h); if (HAS_DDI(dev)) intel_set_pipe_csc(&crtc->base); @@ -3284,27 +3293,24 @@ static void intel_update_pipe_size(struct intel_crtc *crtc) * fastboot case, we'll flip, but if we don't update the pipesrc and * pfit state, we'll end up with a big fb scanned out into the wrong * sized surface. - * - * To fix this properly, we need to hoist the checks up into - * compute_mode_changes (or above), check the actual pfit state and - * whether the platform allows pfit disable with pipe active, and only - * then update the pipesrc and pfit state, even on the flip path. */ - adjusted_mode = &crtc->config->base.adjusted_mode; - I915_WRITE(PIPESRC(crtc->pipe), - ((adjusted_mode->crtc_hdisplay - 1) << 16) | - (adjusted_mode->crtc_vdisplay - 1)); - if (!crtc->config->pch_pfit.enabled && - (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) || - intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))) { - I915_WRITE(PF_CTL(crtc->pipe), 0); - I915_WRITE(PF_WIN_POS(crtc->pipe), 0); - I915_WRITE(PF_WIN_SZ(crtc->pipe), 0); + ((pipe_config->pipe_src_w - 1) << 16) | + (pipe_config->pipe_src_h - 1)); + + /* on skylake this is done by detaching scalers */ + if (INTEL_INFO(dev)->gen >= 9) { + skl_detach_scalers(crtc); + + if (pipe_config->pch_pfit.enabled) + skylake_pfit_enable(crtc); + } else if (HAS_PCH_SPLIT(dev)) { + if (pipe_config->pch_pfit.enabled) + ironlake_pfit_enable(crtc); + else if (old_crtc_state->pch_pfit.enabled) + ironlake_pfit_disable(crtc, true); } - crtc->config->pipe_src_w = adjusted_mode->crtc_hdisplay; - crtc->config->pipe_src_h = adjusted_mode->crtc_vdisplay; } static void intel_fdi_normal_train(struct drm_crtc *crtc) @@ -4961,7 +4967,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) } } -static void ironlake_pfit_disable(struct intel_crtc *crtc) +static void ironlake_pfit_disable(struct intel_crtc *crtc, bool force) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -4969,7 +4975,7 @@ static void ironlake_pfit_disable(struct intel_crtc *crtc) /* To avoid upsetting the power well on haswell only disable the pfit if * it's in use. The hw state code will make sure we get this right. */ - if (crtc->config->pch_pfit.enabled) { + if (force || crtc->config->pch_pfit.enabled) { I915_WRITE(PF_CTL(pipe), 0); I915_WRITE(PF_WIN_POS(pipe), 0); I915_WRITE(PF_WIN_SZ(pipe), 0); @@ -4996,7 +5002,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) intel_disable_pipe(intel_crtc); - ironlake_pfit_disable(intel_crtc); + ironlake_pfit_disable(intel_crtc, false); if (intel_crtc->config->has_pch_encoder) ironlake_fdi_disable(crtc); @@ -5059,7 +5065,7 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) if (INTEL_INFO(dev)->gen >= 9) skylake_scaler_disable(intel_crtc); else - ironlake_pfit_disable(intel_crtc); + ironlake_pfit_disable(intel_crtc, false); intel_ddi_disable_pipe_clock(intel_crtc); @@ -12218,7 +12224,6 @@ static bool intel_fuzzy_clock_check(int clock1, int clock2) base.head) \ if (mask & (1 <<(intel_crtc)->pipe)) - static bool intel_compare_m_n(unsigned int m, unsigned int n, unsigned int m2, unsigned int n2, @@ -12439,19 +12444,21 @@ intel_pipe_config_compare(struct drm_device *dev, DRM_MODE_FLAG_NVSYNC); } - PIPE_CONF_CHECK_I(pipe_src_w); - PIPE_CONF_CHECK_I(pipe_src_h); - PIPE_CONF_CHECK_X(gmch_pfit.control); /* pfit ratios are autocomputed by the hw on gen4+ */ if (INTEL_INFO(dev)->gen < 4) PIPE_CONF_CHECK_I(gmch_pfit.pgm_ratios); PIPE_CONF_CHECK_X(gmch_pfit.lvds_border_bits); - PIPE_CONF_CHECK_I(pch_pfit.enabled); - if (current_config->pch_pfit.enabled) { - PIPE_CONF_CHECK_X(pch_pfit.pos); - PIPE_CONF_CHECK_X(pch_pfit.size); + if (!adjust) { + PIPE_CONF_CHECK_I(pipe_src_w); + PIPE_CONF_CHECK_I(pipe_src_h); + + PIPE_CONF_CHECK_I(pch_pfit.enabled); + if (current_config->pch_pfit.enabled) { + PIPE_CONF_CHECK_X(pch_pfit.pos); + PIPE_CONF_CHECK_X(pch_pfit.size); + } } PIPE_CONF_CHECK_I(scaler_state.scaler_id); @@ -12616,7 +12623,8 @@ check_crtc_state(struct drm_device *dev, struct drm_atomic_state *old_state) struct intel_crtc_state *pipe_config, *sw_config; bool active; - if (!needs_modeset(crtc->state)) + if (!needs_modeset(crtc->state) && + !to_intel_crtc_state(crtc->state)->update_pipe) continue; __drm_atomic_helper_crtc_destroy_state(crtc, old_crtc_state); @@ -12912,7 +12920,6 @@ static int intel_modeset_all_pipes(struct drm_atomic_state *state) return ret; } - static int intel_modeset_checks(struct drm_atomic_state *state) { struct drm_device *dev = state->dev; @@ -13003,6 +13010,7 @@ static int intel_atomic_check(struct drm_device *dev, to_intel_crtc_state(crtc->state), pipe_config, true)) { crtc_state->mode_changed = false; + to_intel_crtc_state(crtc_state)->update_pipe = true; } if (needs_modeset(crtc_state)) { @@ -13100,16 +13108,30 @@ static int intel_atomic_commit(struct drm_device *dev, for_each_crtc_in_state(state, crtc, crtc_state, i) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); bool modeset = needs_modeset(crtc->state); + bool update_pipe = !modeset && + to_intel_crtc_state(crtc->state)->update_pipe; + unsigned long put_domains = 0; if (modeset && crtc->state->active) { update_scanline_offset(to_intel_crtc(crtc)); dev_priv->display.crtc_enable(crtc); } + if (update_pipe) { + put_domains = modeset_get_crtc_power_domains(crtc); + + /* make sure intel_modeset_check_state runs */ + any_ms = true; + } + if (!modeset) intel_pre_plane_update(intel_crtc); drm_atomic_helper_commit_planes_on_crtc(crtc_state); + + if (put_domains) + modeset_put_power_domains(dev_priv, put_domains); + intel_post_plane_update(intel_crtc); } @@ -13426,10 +13448,6 @@ intel_commit_primary_plane(struct drm_plane *plane, if (!crtc->state->active) return; - if (state->visible) - /* FIXME: kill this fastboot hack */ - intel_update_pipe_size(intel_crtc); - dev_priv->display.update_primary_plane(crtc, fb, state->src.x1 >> 16, state->src.y1 >> 16); @@ -13450,6 +13468,9 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc, { struct drm_device *dev = crtc->dev; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_crtc_state *old_intel_state = + to_intel_crtc_state(old_crtc_state); + bool modeset = needs_modeset(crtc->state); if (intel_crtc->atomic.update_wm_pre) intel_update_watermarks(crtc); @@ -13458,7 +13479,12 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc, if (crtc->state->active) intel_pipe_update_start(intel_crtc); - if (!needs_modeset(crtc->state) && INTEL_INFO(dev)->gen >= 9) + if (modeset) + return; + + if (to_intel_crtc_state(crtc->state)->update_pipe) + intel_update_pipe_config(intel_crtc, old_intel_state); + else if (INTEL_INFO(dev)->gen >= 9) skl_detach_scalers(intel_crtc); } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 129d99e33bc2..e9e5cfd2d9b8 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -338,6 +338,8 @@ struct intel_crtc_state { #define PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS (1<<0) /* unreliable sync mode.flags */ unsigned long quirks; + bool update_pipe; + /* Pipe source size (ie. panel fitter input size) * All planes will be positioned inside this space, * and get clipped at the edges. */