From: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> When we switch between one active pipe and multiple active pipes, the display FIFO gets repartitioned. Disable the LP1+ waterwarks while that is happening to make sure we don't get any glitches on other active pipes while doing a modeset on another other pipe. Signed-off-by: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> --- drivers/gpu/drm/i915/intel_display.c | 45 +++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_drv.h | 2 ++ drivers/gpu/drm/i915/intel_pm.c | 48 ++++++++++++++++++++++++++++++++---- 3 files changed, 90 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ad36749..9c43751 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3642,6 +3642,27 @@ static struct intel_crtc *get_other_active_crtc(struct intel_crtc *crtc) return other_active_crtc; } +static void ilk_prepare_for_num_pipes_change(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct intel_crtc *other_active_crtc = get_other_active_crtc(crtc); + + /* + * If we change between one pipe and multiple pipes, + * make sure the other active pipe is prepared + * for having its FIFO resized. We do that by making + * sure the pipe isn't using LP1+ watermarks when + * the second pipe gets enabled or disabled. + */ + if (!other_active_crtc) + return; + + ilk_wm_synchronize(&other_active_crtc->base); + + if (ilk_disable_lp_wm(dev)) + intel_wait_for_vblank(dev, other_active_crtc->pipe); +} + static void ironlake_crtc_enable(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -3657,6 +3678,9 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) intel_crtc->active = true; + /* Make sure other pipes are prepared for FIFO resizing */ + ilk_prepare_for_num_pipes_change(intel_crtc); + intel_set_cpu_fifo_underrun_reporting(dev, pipe, true); intel_set_pch_fifo_underrun_reporting(dev, pipe, true); @@ -3745,6 +3769,9 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) intel_crtc->active = true; + /* Make sure other pipes are prepared for FIFO resizing */ + ilk_prepare_for_num_pipes_change(intel_crtc); + intel_set_cpu_fifo_underrun_reporting(dev, pipe, true); if (intel_crtc->config.has_pch_encoder) intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, true); @@ -3814,6 +3841,9 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) ilk_crtc_disable_planes(crtc); + /* Make sure other pipes are prepared for FIFO resizing */ + ilk_prepare_for_num_pipes_change(intel_crtc); + for_each_encoder_on_crtc(dev, crtc, encoder) encoder->disable(encoder); @@ -3857,6 +3887,12 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) intel_crtc->active = false; + /* + * Potentially let some other pipe use the + * full FIFO, and re-enable LP1+ watermarks. + */ + ilk_wm_pipe_post_disable(crtc); + mutex_lock(&dev->struct_mutex); intel_update_fbc(dev); mutex_unlock(&dev->struct_mutex); @@ -3876,6 +3912,9 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) ilk_crtc_disable_planes(crtc); + /* Make sure other pipes are prepared for FIFO resizing */ + ilk_prepare_for_num_pipes_change(intel_crtc); + for_each_encoder_on_crtc(dev, crtc, encoder) { intel_opregion_notify_encoder(encoder, false); encoder->disable(encoder); @@ -3903,6 +3942,12 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) intel_crtc->active = false; + /* + * Potentially let some other pipe use the + * full FIFO, and re-enable LP1+ watermarks. + */ + ilk_wm_pipe_post_disable(crtc); + mutex_lock(&dev->struct_mutex); intel_update_fbc(dev); mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 4d8f646..94e90ad 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -952,6 +952,8 @@ void intel_fini_runtime_pm(struct drm_i915_private *dev_priv); void ilk_wm_get_hw_state(struct drm_device *dev); void ilk_update_pipe_wm(struct drm_device *dev, enum pipe pipe); void ilk_wm_synchronize(struct drm_crtc *crtc); +void ilk_wm_pipe_post_disable(struct drm_crtc *crtc); +bool ilk_disable_lp_wm(struct drm_device *dev); /* intel_sdvo.c */ diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index a76fa82..7230748 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2714,7 +2714,7 @@ static void ilk_write_wm_values(struct drm_i915_private *dev_priv, } } -static bool ilk_disable_lp_wm(struct drm_device *dev) +bool ilk_disable_lp_wm(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; bool changed; @@ -2822,16 +2822,17 @@ static void ilk_program_watermarks(struct drm_device *dev) ilk_write_wm_values(dev_priv, &results); } -static void ilk_update_watermarks(struct drm_device *dev) +static void ilk_update_watermarks(struct drm_device *dev, bool force) { bool changed; changed = ilk_refresh_pending_watermarks(dev); - if (changed) + if (changed || force) ilk_program_watermarks(dev); } +/* Prepare the pipe to update the its watermarks on the next vblank */ static void ilk_setup_pending_watermarks(struct intel_crtc *intel_crtc, const struct intel_pipe_wm *pipe_wm, u32 vbl_count) @@ -2854,7 +2855,7 @@ static void ilk_setup_pending_watermarks(struct intel_crtc *intel_crtc, spin_unlock_irq(&intel_crtc->wm.lock); /* try to update immediately */ - ilk_update_watermarks(dev); + ilk_update_watermarks(dev, false); spin_lock_irq(&intel_crtc->wm.lock); @@ -2949,7 +2950,7 @@ static void ilk_watermark_work(struct work_struct *work) mutex_lock(&dev_priv->wm.mutex); - ilk_update_watermarks(dev_priv->dev); + ilk_update_watermarks(dev_priv->dev, false); mutex_unlock(&dev_priv->wm.mutex); } @@ -3011,6 +3012,43 @@ void ilk_wm_synchronize(struct drm_crtc *crtc) mutex_unlock(&dev_priv->wm.mutex); } +void ilk_wm_pipe_post_disable(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct ilk_pipe_wm_parameters params = {}; + struct intel_pipe_wm pipe_wm = {}; + + WARN(intel_crtc->active, "pipe %c should be disabled\n", + pipe_name(intel_crtc->pipe)); + + ilk_compute_wm_parameters(crtc, ¶ms); + + intel_compute_pipe_wm(crtc, ¶ms, &pipe_wm); + + mutex_lock(&dev_priv->wm.mutex); + + spin_lock_irq(&intel_crtc->wm.lock); + + WARN(intel_crtc->wm.dirty, "pipe %c disabled with dirty watermarks\n", + pipe_name(intel_crtc->pipe)); + + /* clean up if something is left behind */ + ilk_wm_cancel(intel_crtc); + + spin_unlock_irq(&intel_crtc->wm.lock); + + intel_crtc->wm.active = pipe_wm; + + /* pending update (if any) got cancelled */ + intel_crtc->wm.pending = intel_crtc->wm.active; + + ilk_update_watermarks(dev, true); + + mutex_unlock(&dev_priv->wm.mutex); +} + static int ilk_update_primary_wm(struct drm_crtc *crtc, struct intel_crtc_wm_config *config) { -- 1.8.3.2 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx