[PATCH 20/24] drm/i915: Disable LP1+ watermarks while changing the number of active pipes

ville.syrjala
2014-03-07T16:33:40Z

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

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@linux.intel.com>
---
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, &params);
+
+ intel_compute_pipe_wm(crtc, &params, &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