[PATCH 17/24] drm/i915: Actually perform the watermark update in two phases

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

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

Switch the code over to using the two phase watermark update. The steps
generally follow this pattern:

1. Calculate new plane parameters for changed planes
2. Calculate new target and intermediate watermarks
3. Check that both the target and intermediate watermarks are valid
4. Program the hardware with the intermediate watermarks
5. Program the plane registers
6. Arm the vblank watermark update machinery for the next vblank
7. Program the hardware with the target watermarks (after vblank)

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
drivers/gpu/drm/i915/i915_drv.h | 13 +-
drivers/gpu/drm/i915/intel_display.c | 59 ++++++++-
drivers/gpu/drm/i915/intel_drv.h | 39 ++++--
drivers/gpu/drm/i915/intel_pm.c | 230 +++++++++++++++++++++++++++--------
drivers/gpu/drm/i915/intel_sprite.c | 118 ++++++++++++------
5 files changed, 351 insertions(+), 108 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index eb5f8f8..b625601 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -409,6 +409,8 @@ struct intel_crtc;
struct intel_limit;
struct dpll;
struct intel_crtc_wm_config;
+struct intel_plane_wm_parameters;
+struct intel_crtc_wm_config;

struct drm_i915_display_funcs {
bool (*fbc_enabled)(struct drm_device *dev);
@@ -435,10 +437,13 @@ struct drm_i915_display_funcs {
struct dpll *match_clock,
struct dpll *best_clock);
void (*update_wm)(struct drm_crtc *crtc);
- void (*update_sprite_wm)(struct drm_plane *plane,
- struct drm_crtc *crtc,
- uint32_t sprite_width, int pixel_size,
- bool enable, bool scaled);
+ int (*update_primary_wm)(struct drm_crtc *crtc,
+ struct intel_crtc_wm_config *config);
+ int (*update_cursor_wm)(struct drm_crtc *crtc,
+ struct intel_crtc_wm_config *config);
+ int (*update_sprite_wm)(struct drm_plane *plane,
+ struct drm_crtc *crtc,
+ struct intel_crtc_wm_config *config);
void (*program_wm_pre)(struct drm_crtc *crtc,
const struct intel_crtc_wm_config *config);
void (*program_wm_post)(struct drm_crtc *crtc,
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index aa9acc5..8d16ada7 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1871,6 +1871,18 @@ void intel_flush_primary_plane(struct drm_i915_private *dev_priv,
POSTING_READ(reg);
}

+static void update_pri_params(struct intel_crtc *intel_crtc,
+ struct intel_plane_wm_parameters *params,
+ bool primary_enabled)
+{
+ if (!intel_crtc->active || !primary_enabled)
+ return;
+
+ params->horiz_pixels = intel_crtc->config.pipe_src_w;
+ params->bytes_per_pixel = drm_format_plane_cpp(intel_crtc->base.fb->pixel_format, 0);
+ params->enabled = true;
+}
+
/**
* intel_enable_primary_plane - enable the primary plane on a given pipe
* @dev_priv: i915 private structure
@@ -1882,8 +1894,11 @@ void intel_flush_primary_plane(struct drm_i915_private *dev_priv,
static void intel_enable_primary_plane(struct drm_i915_private *dev_priv,
enum plane plane, enum pipe pipe)
{
+ struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
struct intel_crtc *intel_crtc =
to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
+ struct intel_crtc_wm_config config = {};
+ int ret;
int reg;
u32 val;

@@ -1892,13 +1907,23 @@ static void intel_enable_primary_plane(struct drm_i915_private *dev_priv,

WARN(intel_crtc->primary_enabled, "Primary plane already enabled\n");

+ update_pri_params(intel_crtc, &config.pri, true);
+
+ ret = intel_update_primary_watermarks(crtc, &config);
+ WARN(ret, "primary watermarks invalid\n");
+
intel_crtc->primary_enabled = true;

reg = DSPCNTR(plane);
val = I915_READ(reg);

+ intel_crtc->pri_wm = config.pri;
+ intel_program_watermarks_pre(crtc, &config);
+
I915_WRITE(reg, val | DISPLAY_PLANE_ENABLE);
intel_flush_primary_plane(dev_priv, plane);
+
+ intel_program_watermarks_post(crtc, &config);
}

/**
@@ -1912,20 +1937,33 @@ static void intel_enable_primary_plane(struct drm_i915_private *dev_priv,
static void intel_disable_primary_plane(struct drm_i915_private *dev_priv,
enum plane plane, enum pipe pipe)
{
+ struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
struct intel_crtc *intel_crtc =
to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
+ struct intel_crtc_wm_config config = {};
+ int ret;
int reg;
u32 val;

WARN(!intel_crtc->primary_enabled, "Primary plane already disabled\n");

+ update_pri_params(intel_crtc, &config.pri, false);
+
+ ret = intel_update_primary_watermarks(crtc, &config);
+ WARN(ret, "primary watermarks invalid\n");
+
intel_crtc->primary_enabled = false;

reg = DSPCNTR(plane);
val = I915_READ(reg);

+ intel_crtc->pri_wm = config.pri;
+ intel_program_watermarks_pre(crtc, &config);
+
I915_WRITE(reg, val & ~DISPLAY_PLANE_ENABLE);
intel_flush_primary_plane(dev_priv, plane);
+
+ intel_program_watermarks_post(crtc, &config);
}

static bool need_vtd_wa(struct drm_device *dev)
@@ -3622,7 +3660,6 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
*/
intel_crtc_load_lut(crtc);

- intel_update_watermarks(crtc);
intel_enable_pipe(intel_crtc);

if (intel_crtc->config.has_pch_encoder)
@@ -3721,7 +3758,6 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
intel_ddi_set_pipe_settings(crtc);
intel_ddi_enable_transcoder_func(crtc);

- intel_update_watermarks(crtc);
intel_enable_pipe(intel_crtc);

if (intel_crtc->config.has_pch_encoder)
@@ -3809,7 +3845,6 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
}

intel_crtc->active = false;
- intel_update_watermarks(crtc);

mutex_lock(&dev->struct_mutex);
intel_update_fbc(dev);
@@ -3856,7 +3891,6 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
}

intel_crtc->active = false;
- intel_update_watermarks(crtc);

mutex_lock(&dev->struct_mutex);
intel_update_fbc(dev);
@@ -7431,11 +7465,13 @@ static void intel_crtc_update_cursor(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 intel_crtc_wm_config config = {};
int pipe = intel_crtc->pipe;
int x = intel_crtc->cursor_x;
int y = intel_crtc->cursor_y;
u32 base = 0, pos = 0;
bool visible;
+ int ret;

if (on)
base = intel_crtc->cursor_addr;
@@ -7468,6 +7504,19 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
if (!visible && !intel_crtc->cursor_visible)
return;

+ if (visible) {
+ /* FIXME should we use the clipped width? */
+ config.cur.horiz_pixels = 64;
+ config.cur.bytes_per_pixel = 4;
+ config.cur.enabled = true;
+ }
+
+ ret = intel_update_cursor_watermarks(crtc, &config);
+ WARN(ret, "cursor watermarks invalid\n");
+
+ intel_crtc->cur_wm = config.cur;
+ intel_program_watermarks_pre(crtc, &config);
+
if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev) || IS_BROADWELL(dev)) {
I915_WRITE(CURPOS_IVB(pipe), pos);
ivb_update_cursor(crtc, base);
@@ -7478,6 +7527,8 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
else
i9xx_update_cursor(crtc, base);
}
+
+ intel_program_watermarks_post(crtc, &config);
}

static int intel_crtc_cursor_set(struct drm_crtc *crtc,
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 2ec600d8..c654a89 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -338,7 +338,15 @@ struct intel_pipe_wm {
bool sprites_scaled;
};

+struct intel_plane_wm_parameters {
+ uint32_t horiz_pixels;
+ uint8_t bytes_per_pixel;
+ bool enabled;
+ bool scaled;
+};
+
struct intel_crtc_wm_config {
+ struct intel_plane_wm_parameters pri, spr, cur;
/* target watermarks for the pipe */
struct intel_pipe_wm target;
/* intermediate watermarks for pending/active->target transition */
@@ -424,14 +432,10 @@ struct intel_crtc {
spinlock_t lock;
} wm;

- wait_queue_head_t vbl_wait;
-};
+ struct intel_plane_wm_parameters pri_wm;
+ struct intel_plane_wm_parameters cur_wm;

-struct intel_plane_wm_parameters {
- uint32_t horiz_pixels;
- uint8_t bytes_per_pixel;
- bool enabled;
- bool scaled;
+ wait_queue_head_t vbl_wait;
};

struct intel_plane {
@@ -461,9 +465,11 @@ struct intel_plane {
int crtc_x, int crtc_y,
unsigned int crtc_w, unsigned int crtc_h,
uint32_t x, uint32_t y,
- uint32_t src_w, uint32_t src_h);
+ uint32_t src_w, uint32_t src_h,
+ const struct intel_crtc_wm_config *config);
void (*disable_plane)(struct drm_plane *plane,
- struct drm_crtc *crtc);
+ struct drm_crtc *crtc,
+ const struct intel_crtc_wm_config *config);
int (*update_colorkey)(struct drm_plane *plane,
struct drm_intel_sprite_colorkey *key);
void (*get_colorkey)(struct drm_plane *plane,
@@ -903,10 +909,17 @@ extern struct drm_display_mode *intel_find_panel_downclock(
void intel_init_clock_gating(struct drm_device *dev);
void intel_suspend_hw(struct drm_device *dev);
void intel_update_watermarks(struct drm_crtc *crtc);
-void intel_update_sprite_watermarks(struct drm_plane *plane,
- struct drm_crtc *crtc,
- uint32_t sprite_width, int pixel_size,
- bool enabled, bool scaled);
+int intel_update_cursor_watermarks(struct drm_crtc *crtc,
+ struct intel_crtc_wm_config *config);
+int intel_update_primary_watermarks(struct drm_crtc *crtc,
+ struct intel_crtc_wm_config *config);
+int intel_update_sprite_watermarks(struct drm_plane *plane,
+ struct drm_crtc *crtc,
+ struct intel_crtc_wm_config *config);
+void intel_program_watermarks_pre(struct drm_crtc *crtc,
+ const struct intel_crtc_wm_config *config);
+void intel_program_watermarks_post(struct drm_crtc *crtc,
+ const struct intel_crtc_wm_config *config);
void intel_init_pm(struct drm_device *dev);
void intel_pm_setup(struct drm_device *dev);
bool intel_fbc_enabled(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 468d6a5..38fbd9a 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -2136,13 +2136,9 @@ static void ilk_compute_wm_parameters(struct drm_crtc *crtc,
p->active = true;
p->pipe_htotal = intel_crtc->config.adjusted_mode.crtc_htotal;
p->pixel_rate = ilk_pipe_pixel_rate(dev, crtc);
- p->pri.bytes_per_pixel = crtc->fb->bits_per_pixel / 8;
- p->cur.bytes_per_pixel = 4;
- p->pri.horiz_pixels = intel_crtc->config.pipe_src_w;
- p->cur.horiz_pixels = 64;
- /* TODO: for now, assume primary and cursor planes are always enabled. */
- p->pri.enabled = true;
- p->cur.enabled = true;
+
+ p->pri = intel_crtc->pri_wm;
+ p->cur = intel_crtc->cur_wm;

list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
struct intel_plane *intel_plane = to_intel_plane(plane);
@@ -2242,6 +2238,35 @@ static bool intel_compute_pipe_wm(struct drm_crtc *crtc,
}

/*
+ * Merge two pipe watermark sets.
+ * Used for computing intermediate watermark levels
+ * for transitioning between two different configurations.
+ */
+static void ilk_wm_merge_intermediate(struct drm_device *dev,
+ struct intel_pipe_wm *a,
+ const struct intel_pipe_wm *b)
+{
+ int level, max_level = ilk_wm_max_level(dev);
+
+ a->pipe_enabled |= b->pipe_enabled;
+ a->sprites_enabled |= b->sprites_enabled;
+ a->sprites_scaled |= b->sprites_scaled;
+
+ /* Merge _all_ levels including 0 */
+ for (level = 0; level <= max_level; level++) {
+ struct intel_wm_level *a_wm = &a->wm[level];
+ const struct intel_wm_level *b_wm = &b->wm[level];
+
+ a_wm->enable &= b_wm->enable;
+
+ a_wm->pri_val = max(a_wm->pri_val, b_wm->pri_val);
+ a_wm->spr_val = max(a_wm->spr_val, b_wm->spr_val);
+ a_wm->cur_val = max(a_wm->cur_val, b_wm->cur_val);
+ a_wm->fbc_val = max(a_wm->fbc_val, b_wm->fbc_val);
+ }
+}
+
+/*
* Merge the watermarks from all active pipes for a specific level.
*/
static void ilk_merge_wm_level(struct drm_device *dev,
@@ -2793,31 +2818,6 @@ static void ilk_program_watermarks(struct drm_device *dev)
ilk_write_wm_values(dev_priv, &results);
}

-static void ilk_update_wm(struct drm_crtc *crtc)
-{
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- struct drm_device *dev = crtc->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct ilk_pipe_wm_parameters params = {};
- struct intel_pipe_wm pipe_wm = {};
-
- ilk_compute_wm_parameters(crtc, &params);
-
- intel_compute_pipe_wm(crtc, &params, &pipe_wm);
-
- mutex_lock(&dev_priv->wm.mutex);
-
- if (!memcmp(&intel_crtc->wm.active, &pipe_wm, sizeof(pipe_wm)))
- goto unlock;
-
- intel_crtc->wm.active = pipe_wm;
-
- ilk_program_watermarks(dev);
-
- unlock:
- mutex_unlock(&dev_priv->wm.mutex);
-}
-
static void ilk_update_watermarks(struct drm_device *dev)
{
bool changed;
@@ -2872,6 +2872,72 @@ static void ilk_setup_pending_watermarks(struct intel_crtc *intel_crtc,
spin_unlock_irq(&intel_crtc->wm.lock);
}

+static int ilk_pipe_compute_watermarks(struct drm_crtc *crtc,
+ struct intel_pipe_wm *target,
+ struct intel_pipe_wm *intm)
+{
+ 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 intel_pipe_wm intm_pending;
+ bool dirty;
+
+ /* are the target watermarks valid at all? */
+ if (!ilk_validate_pipe_wm(dev, target))
+ return -EINVAL;
+
+ /*
+ * We need to come up with intermediate watermark levels
+ * that will support both the old and new plane configuration
+ * since we can't flip over to the final watermarks until
+ * the plane configuration has been latched at some future vblank.
+ *
+ * Additionally if there's already an update pending, we can't
+ * yet be sure which plane configuration will be active at the
+ * time we apply the intermediate watermarks, so we must account
+ * for both possibilities.
+ */
+ mutex_lock(&dev_priv->wm.mutex);
+
+ intm_pending = intel_crtc->wm.pending;
+ *intm = intel_crtc->wm.active;
+
+ spin_lock_irq(&intel_crtc->wm.lock);
+ dirty = intel_crtc->wm.dirty;
+ spin_unlock_irq(&intel_crtc->wm.lock);
+
+ mutex_unlock(&dev_priv->wm.mutex);
+
+ /*
+ * If the intermediate watermarks aren't valid, we must tell the user to
+ * try something a bit different. There are two cases to be considered.
+ * 1) there is no pending update:
+ * If the intermediate watermarks for transitioning from the currently
+ * active configuration to the new configuration aren't valid, the
+ * user must choose another configuration as there is no safe way to
+ * transition from the currently active config to the new config.
+ * 2) there is a pending update:
+ * If the intermediate watermarks for transitioning from the ccurrently
+ * pending configuration to the new configuration are valid, we can
+ * simply tell the user to try again after a while.
+ */
+ if (dirty) {
+ ilk_wm_merge_intermediate(dev, &intm_pending, target);
+ if (!ilk_validate_pipe_wm(dev, &intm_pending))
+ return -EINVAL;
+
+ ilk_wm_merge_intermediate(dev, intm, &intm_pending);
+ if (!ilk_validate_pipe_wm(dev, intm))
+ return -EAGAIN;
+ } else {
+ ilk_wm_merge_intermediate(dev, intm, target);
+ if (!ilk_validate_pipe_wm(dev, intm))
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static void ilk_watermark_work(struct work_struct *work)
{
struct drm_i915_private *dev_priv =
@@ -2913,18 +2979,46 @@ static void ilk_wm_cancel(struct intel_crtc *intel_crtc)
}
}

-static void ilk_update_sprite_wm(struct drm_plane *plane,
- struct drm_crtc *crtc,
- uint32_t sprite_width, int pixel_size,
- bool enabled, bool scaled)
+static int ilk_update_primary_wm(struct drm_crtc *crtc,
+ struct intel_crtc_wm_config *config)
{
- struct drm_device *dev = plane->dev;
- struct intel_plane *intel_plane = to_intel_plane(plane);
+ struct ilk_pipe_wm_parameters params = {};
+
+ ilk_compute_wm_parameters(crtc, &params);
+
+ params.pri = config->pri;

- intel_plane->wm.enabled = enabled;
- intel_plane->wm.scaled = scaled;
- intel_plane->wm.horiz_pixels = sprite_width;
- intel_plane->wm.bytes_per_pixel = pixel_size;
+ intel_compute_pipe_wm(crtc, &params, &config->target);
+
+ return ilk_pipe_compute_watermarks(crtc,
+ &config->target,
+ &config->intm);
+}
+
+static int ilk_update_cursor_wm(struct drm_crtc *crtc,
+ struct intel_crtc_wm_config *config)
+{
+ struct ilk_pipe_wm_parameters params = {};
+
+ ilk_compute_wm_parameters(crtc, &params);
+
+ params.cur = config->cur;
+
+ intel_compute_pipe_wm(crtc, &params, &config->target);
+
+ return ilk_pipe_compute_watermarks(crtc,
+ &config->target,
+ &config->intm);
+}
+
+static int ilk_update_sprite_wm(struct drm_plane *plane,
+ struct drm_crtc *crtc,
+ struct intel_crtc_wm_config *config)
+{
+ struct drm_device *dev = crtc->dev;
+ struct ilk_pipe_wm_parameters params = {};
+
+ ilk_compute_wm_parameters(crtc, &params);

/*
* IVB workaround: must disable low power watermarks for at least
@@ -2933,10 +3027,17 @@ static void ilk_update_sprite_wm(struct drm_plane *plane,
*
* WaCxSRDisabledForSpriteScaling:ivb
*/
- if (IS_IVYBRIDGE(dev) && scaled && ilk_disable_lp_wm(dev))
- intel_wait_for_vblank(dev, intel_plane->pipe);
+ if (IS_IVYBRIDGE(dev) && config->spr.scaled && ilk_disable_lp_wm(dev))
+ intel_wait_for_vblank(dev, to_intel_plane(plane)->pipe);
+
+ params.pri = config->pri;
+ params.spr = config->spr;

- ilk_update_wm(crtc);
+ intel_compute_pipe_wm(crtc, &params, &config->target);
+
+ return ilk_pipe_compute_watermarks(crtc,
+ &config->target,
+ &config->intm);
}

static void _ilk_pipe_wm_hw_to_sw(struct drm_crtc *crtc)
@@ -3035,16 +3136,38 @@ void intel_update_watermarks(struct drm_crtc *crtc)
dev_priv->display.update_wm(crtc);
}

-void intel_update_sprite_watermarks(struct drm_plane *plane,
- struct drm_crtc *crtc,
- uint32_t sprite_width, int pixel_size,
- bool enabled, bool scaled)
+int intel_update_primary_watermarks(struct drm_crtc *crtc,
+ struct intel_crtc_wm_config *config)
+{
+ struct drm_i915_private *dev_priv = crtc->dev->dev_private;
+
+ if (dev_priv->display.update_primary_wm)
+ return dev_priv->display.update_primary_wm(crtc, config);
+
+ return 0;
+}
+
+int intel_update_cursor_watermarks(struct drm_crtc *crtc,
+ struct intel_crtc_wm_config *config)
+{
+ struct drm_i915_private *dev_priv = crtc->dev->dev_private;
+
+ if (dev_priv->display.update_cursor_wm)
+ return dev_priv->display.update_cursor_wm(crtc, config);
+
+ return 0;
+}
+
+int intel_update_sprite_watermarks(struct drm_plane *plane,
+ struct drm_crtc *crtc,
+ struct intel_crtc_wm_config *config)
{
- struct drm_i915_private *dev_priv = plane->dev->dev_private;
+ struct drm_i915_private *dev_priv = crtc->dev->dev_private;

if (dev_priv->display.update_sprite_wm)
- dev_priv->display.update_sprite_wm(plane, crtc, sprite_width,
- pixel_size, enabled, scaled);
+ return dev_priv->display.update_sprite_wm(plane, crtc, config);
+
+ return 0;
}

void intel_program_watermarks_pre(struct drm_crtc *crtc,
@@ -6046,7 +6169,8 @@ void intel_init_pm(struct drm_device *dev)
dev_priv->wm.spr_latency[1] && dev_priv->wm.cur_latency[1]) ||
(!IS_GEN5(dev) && dev_priv->wm.pri_latency[0] &&
dev_priv->wm.spr_latency[0] && dev_priv->wm.cur_latency[0])) {
- dev_priv->display.update_wm = ilk_update_wm;
+ dev_priv->display.update_primary_wm = ilk_update_primary_wm;
+ dev_priv->display.update_cursor_wm = ilk_update_cursor_wm;
dev_priv->display.update_sprite_wm = ilk_update_sprite_wm;
dev_priv->display.program_wm_pre = ilk_program_wm_pre;
dev_priv->display.program_wm_post = ilk_program_wm_post;
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index 213cd58..a9500ba 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -131,7 +131,7 @@ static void intel_update_primary_plane(struct intel_crtc *crtc)
struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
int reg = DSPCNTR(crtc->plane);

- if (crtc->primary_enabled)
+ if (crtc->pri_wm.enabled)
I915_WRITE(reg, I915_READ(reg) | DISPLAY_PLANE_ENABLE);
else
I915_WRITE(reg, I915_READ(reg) & ~DISPLAY_PLANE_ENABLE);
@@ -143,7 +143,8 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
unsigned int crtc_w, unsigned int crtc_h,
uint32_t x, uint32_t y,
- uint32_t src_w, uint32_t src_h)
+ uint32_t src_w, uint32_t src_h,
+ const struct intel_crtc_wm_config *config)
{
struct drm_device *dev = dplane->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -218,9 +219,6 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,

sprctl |= SP_ENABLE;

- intel_update_sprite_watermarks(dplane, crtc, src_w, pixel_size, true,
- src_w != crtc_w || src_h != crtc_h);
-
/* Sizes are 0 based */
src_w--;
src_h--;
@@ -234,6 +232,10 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
fb->pitches[0]);
linear_offset -= sprsurf_offset;

+ intel_crtc->pri_wm = config->pri;
+ intel_plane->wm = config->spr;
+ intel_program_watermarks_pre(crtc, config);
+
atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);

intel_update_primary_plane(intel_crtc);
@@ -255,10 +257,13 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,

if (atomic_update)
intel_pipe_update_end(intel_crtc, start_vbl_count);
+
+ intel_program_watermarks_post(crtc, config);
}

static void
-vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc)
+vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
+ const struct intel_crtc_wm_config *config)
{
struct drm_device *dev = dplane->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -269,6 +274,10 @@ vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc)
u32 start_vbl_count;
bool atomic_update;

+ intel_crtc->pri_wm = config->pri;
+ intel_plane->wm = config->spr;
+ intel_program_watermarks_pre(crtc, config);
+
atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);

intel_update_primary_plane(intel_crtc);
@@ -283,7 +292,7 @@ vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc)
if (atomic_update)
intel_pipe_update_end(intel_crtc, start_vbl_count);

- intel_update_sprite_watermarks(dplane, crtc, 0, 0, false, false);
+ intel_program_watermarks_post(crtc, config);
}

static int
@@ -343,7 +352,8 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
unsigned int crtc_w, unsigned int crtc_h,
uint32_t x, uint32_t y,
- uint32_t src_w, uint32_t src_h)
+ uint32_t src_w, uint32_t src_h,
+ const struct intel_crtc_wm_config *config)
{
struct drm_device *dev = plane->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -406,9 +416,6 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
if (IS_HASWELL(dev) || IS_BROADWELL(dev))
sprctl |= SPRITE_PIPE_CSC_ENABLE;

- intel_update_sprite_watermarks(plane, crtc, src_w, pixel_size, true,
- src_w != crtc_w || src_h != crtc_h);
-
/* Sizes are 0 based */
src_w--;
src_h--;
@@ -424,6 +431,10 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
pixel_size, fb->pitches[0]);
linear_offset -= sprsurf_offset;

+ intel_crtc->pri_wm = config->pri;
+ intel_plane->wm = config->spr;
+ intel_program_watermarks_pre(crtc, config);
+
atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);

intel_update_primary_plane(intel_crtc);
@@ -451,10 +462,13 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,

if (atomic_update)
intel_pipe_update_end(intel_crtc, start_vbl_count);
+
+ intel_program_watermarks_post(crtc, config);
}

static void
-ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
+ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc,
+ const struct intel_crtc_wm_config *config)
{
struct drm_device *dev = plane->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -464,6 +478,10 @@ ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
u32 start_vbl_count;
bool atomic_update;

+ intel_crtc->pri_wm = config->pri;
+ intel_plane->wm = config->spr;
+ intel_program_watermarks_pre(crtc, config);
+
atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);

intel_update_primary_plane(intel_crtc);
@@ -480,13 +498,7 @@ ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
if (atomic_update)
intel_pipe_update_end(intel_crtc, start_vbl_count);

- /*
- * Avoid underruns when disabling the sprite.
- * FIXME remove once watermark updates are done properly.
- */
- intel_wait_for_vblank(dev, pipe);
-
- intel_update_sprite_watermarks(plane, crtc, 0, 0, false, false);
+ intel_program_watermarks_post(crtc, config);
}

static int
@@ -549,7 +561,8 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
unsigned int crtc_w, unsigned int crtc_h,
uint32_t x, uint32_t y,
- uint32_t src_w, uint32_t src_h)
+ uint32_t src_w, uint32_t src_h,
+ const struct intel_crtc_wm_config *config)
{
struct drm_device *dev = plane->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -606,9 +619,6 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
dvscntr |= DVS_TRICKLE_FEED_DISABLE; /* must disable */
dvscntr |= DVS_ENABLE;

- intel_update_sprite_watermarks(plane, crtc, src_w, pixel_size, true,
- src_w != crtc_w || src_h != crtc_h);
-
/* Sizes are 0 based */
src_w--;
src_h--;
@@ -625,6 +635,10 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
pixel_size, fb->pitches[0]);
linear_offset -= dvssurf_offset;

+ intel_crtc->pri_wm = config->pri;
+ intel_plane->wm = config->spr;
+ intel_program_watermarks_pre(crtc, config);
+
atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);

intel_update_primary_plane(intel_crtc);
@@ -647,10 +661,13 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,

if (atomic_update)
intel_pipe_update_end(intel_crtc, start_vbl_count);
+
+ intel_program_watermarks_post(crtc, config);
}

static void
-ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
+ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc,
+ const struct intel_crtc_wm_config *config)
{
struct drm_device *dev = plane->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -660,6 +677,10 @@ ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
u32 start_vbl_count;
bool atomic_update;

+ intel_crtc->pri_wm = config->pri;
+ intel_plane->wm = config->spr;
+ intel_program_watermarks_pre(crtc, config);
+
atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);

intel_update_primary_plane(intel_crtc);
@@ -675,13 +696,7 @@ ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
if (atomic_update)
intel_pipe_update_end(intel_crtc, start_vbl_count);

- /*
- * Avoid underruns when disabling the sprite.
- * FIXME remove once watermark updates are done properly.
- */
- intel_wait_for_vblank(dev, pipe);
-
- intel_update_sprite_watermarks(plane, crtc, 0, 0, false, false);
+ intel_program_watermarks_post(crtc, config);
}

static void
@@ -804,6 +819,18 @@ static bool colorkey_enabled(struct intel_plane *intel_plane)
return key.flags != I915_SET_COLORKEY_NONE;
}

+static void update_pri_params(struct intel_crtc *intel_crtc,
+ struct intel_plane_wm_parameters *params,
+ bool primary_enabled)
+{
+ if (!intel_crtc->active || !primary_enabled)
+ return;
+
+ params->horiz_pixels = intel_crtc->config.pipe_src_w;
+ params->bytes_per_pixel = drm_format_plane_cpp(intel_crtc->base.fb->pixel_format, 0);
+ params->enabled = true;
+}
+
static int
intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
struct drm_framebuffer *fb, int crtc_x, int crtc_y,
@@ -855,6 +882,7 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
.src_w = src_w,
.src_h = src_h,
};
+ struct intel_crtc_wm_config config = {};

/* Don't modify another pipe's plane */
if (intel_plane->pipe != intel_crtc->pipe) {
@@ -992,6 +1020,19 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
primary_enabled = !drm_rect_equals(&dst, &clip) || colorkey_enabled(intel_plane);
WARN_ON(!primary_enabled && !visible && intel_crtc->active);

+ if (visible) {
+ config.spr.horiz_pixels = src_w;
+ config.spr.bytes_per_pixel = pixel_size;
+ config.spr.enabled = true;
+ config.spr.scaled = src_w != crtc_w || src_h != crtc_h;
+ }
+
+ update_pri_params(intel_crtc, &config.pri, primary_enabled);
+
+ ret = intel_update_sprite_watermarks(plane, crtc, &config);
+ if (ret)
+ return ret;
+
mutex_lock(&dev->struct_mutex);

/* Note that this will apply the VT-d workaround for scanouts,
@@ -1027,9 +1068,10 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
if (visible)
intel_plane->update_plane(plane, crtc, fb, obj,
crtc_x, crtc_y, crtc_w, crtc_h,
- src_x, src_y, src_w, src_h);
+ src_x, src_y, src_w, src_h,
+ &config);
else
- intel_plane->disable_plane(plane, crtc);
+ intel_plane->disable_plane(plane, crtc, &config);

if (!primary_was_enabled && primary_enabled)
intel_post_enable_primary(crtc);
@@ -1060,6 +1102,8 @@ intel_disable_plane(struct drm_plane *plane)
struct drm_device *dev = plane->dev;
struct intel_plane *intel_plane = to_intel_plane(plane);
struct intel_crtc *intel_crtc;
+ struct intel_crtc_wm_config config = {};
+ int ret;

if (!plane->fb)
return 0;
@@ -1069,12 +1113,18 @@ intel_disable_plane(struct drm_plane *plane)

intel_crtc = to_intel_crtc(plane->crtc);

+ update_pri_params(intel_crtc, &config.pri, true);
+
+ ret = intel_update_sprite_watermarks(plane, plane->crtc, &config);
+ if (ret)
+ return ret;
+
if (intel_crtc->active) {
bool primary_was_enabled = intel_crtc->primary_enabled;

intel_crtc->primary_enabled = true;

- intel_plane->disable_plane(plane, plane->crtc);
+ intel_plane->disable_plane(plane, plane->crtc, &config);

if (!primary_was_enabled && intel_crtc->primary_enabled)
intel_post_enable_primary(plane->crtc);
--
1.8.3.2