summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVille Syrjälä <ville.syrjala@linux.intel.com>2014-05-22 17:48:13 +0300
committerPaulo Zanoni <paulo.r.zanoni@intel.com>2014-12-29 16:44:02 -0200
commit43b93ef0985a0b140ed9c071337467b8953f1b29 (patch)
tree4e868463f80f7c648a9bc2367be24bee61dcee54
parent70af10edb42967e09e0408e5c2fb80e40f4cc639 (diff)
drm/i915: Split watermark programming into pre and post stepsrebase-ville-wm
We need to perform watermark programming before and after changing the plane configuration. Add two new vfuncs to do that. The pre phase is supposed to switch over to the intermediate watermarks which are computed so that they can deal with both the old and new plane configurations. The post phase will arm the vblank based update systems to switch over to the optimal target watermarks after the plane configuration has for sure changed. v2: Pass around intel_crtc and s/intel_crtc/crtc/ Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h5
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h11
-rw-r--r--drivers/gpu/drm/i915/intel_pm.c88
3 files changed, 104 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 849a4d80e903..6a2621afc52a 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -504,6 +504,7 @@ struct intel_plane_config;
struct intel_crtc;
struct intel_limit;
struct dpll;
+struct intel_crtc_wm_config;
struct drm_i915_display_funcs {
bool (*fbc_enabled)(struct drm_device *dev);
@@ -534,6 +535,10 @@ struct drm_i915_display_funcs {
struct drm_crtc *crtc,
uint32_t sprite_width, uint32_t sprite_height,
int pixel_size, bool enable, bool scaled);
+ void (*program_wm_pre)(struct intel_crtc *crtc,
+ const struct intel_crtc_wm_config *config);
+ void (*program_wm_post)(struct intel_crtc *crtc,
+ const struct intel_crtc_wm_config *config);
void (*modeset_global_resources)(struct drm_device *dev);
/* Returns the active state of the crtc, and if the crtc is active,
* fills out the pipe-config with the hw state. */
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 5e9162a86aac..d80bd42a425f 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -415,6 +415,13 @@ struct skl_pipe_wm {
uint32_t linetime;
};
+struct intel_crtc_wm_config {
+ /* target watermarks for the pipe */
+ struct intel_pipe_wm target;
+ /* intermediate watermarks for pending/active->target transition */
+ struct intel_pipe_wm intm;
+};
+
struct intel_crtc {
struct drm_crtc base;
enum pipe pipe;
@@ -1218,6 +1225,10 @@ void gen6_rps_idle(struct drm_i915_private *dev_priv);
void gen6_rps_boost(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 intel_program_watermarks_pre(struct intel_crtc *crtc,
+ const struct intel_crtc_wm_config *config);
+void intel_program_watermarks_post(struct intel_crtc *crtc,
+ const struct intel_crtc_wm_config *config);
void skl_wm_get_hw_state(struct drm_device *dev);
void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv,
struct skl_ddb_allocation *ddb /* out */);
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index f334d30dadca..a9766e68b3d4 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3432,6 +3432,20 @@ void ilk_update_pipe_wm(struct drm_device *dev, enum pipe pipe)
spin_unlock(&crtc->wm.lock);
}
+static void ilk_wm_cancel(struct intel_crtc *crtc)
+{
+ struct drm_device *dev = crtc->base.dev;
+
+ assert_spin_locked(&crtc->wm.lock);
+
+ crtc->wm.dirty = false;
+
+ if (crtc->wm.vblank) {
+ drm_vblank_put(dev, crtc->pipe);
+ crtc->wm.vblank = false;
+ }
+}
+
static void
ilk_update_sprite_wm(struct drm_plane *plane,
struct drm_crtc *crtc,
@@ -3678,6 +3692,24 @@ void intel_update_sprite_watermarks(struct drm_plane *plane,
pixel_size, enabled, scaled);
}
+void intel_program_watermarks_pre(struct intel_crtc *crtc,
+ const struct intel_crtc_wm_config *config)
+{
+ struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+
+ if (dev_priv->display.program_wm_pre)
+ dev_priv->display.program_wm_pre(crtc, config);
+}
+
+void intel_program_watermarks_post(struct intel_crtc *crtc,
+ const struct intel_crtc_wm_config *config)
+{
+ struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+
+ if (dev_priv->display.program_wm_post)
+ dev_priv->display.program_wm_post(crtc, config);
+}
+
static struct drm_i915_gem_object *
intel_alloc_context_page(struct drm_device *dev)
{
@@ -6536,6 +6568,60 @@ void intel_suspend_hw(struct drm_device *dev)
lpt_suspend_hw(dev);
}
+static void ilk_program_wm_pre(struct intel_crtc *crtc,
+ const struct intel_crtc_wm_config *config)
+{
+ struct drm_device *dev = crtc->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ mutex_lock(&dev_priv->wm.mutex);
+
+ spin_lock_irq(&crtc->wm.lock);
+ ilk_wm_cancel(crtc);
+ spin_unlock_irq(&crtc->wm.lock);
+
+ /* pending update (if any) got cancelled */
+ crtc->wm.pending = crtc->wm.active;
+
+ if (!memcmp(&crtc->wm.active, &config->intm, sizeof(config->intm)))
+ goto unlock;
+
+ crtc->wm.active = config->intm;
+
+ /* use the most up to date watermarks for other pipes */
+ ilk_refresh_pending_watermarks(dev);
+
+ /* switch over to the intermediate watermarks */
+ ilk_program_watermarks(dev);
+
+ unlock:
+ mutex_unlock(&dev_priv->wm.mutex);
+}
+
+static void ilk_program_wm_post(struct intel_crtc *crtc,
+ const struct intel_crtc_wm_config *config)
+{
+ struct drm_device *dev = crtc->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 vbl_count;
+
+ /*
+ * FIXME sample this inside the atomic section to avoid
+ * needlessly long periods w/ sub-par watermarks
+ */
+ vbl_count = dev->driver->get_vblank_counter(dev, crtc->pipe);
+
+ mutex_lock(&dev_priv->wm.mutex);
+
+ /*
+ * We can switch over to the target
+ * watermarks after the next vblank.
+ */
+ ilk_setup_pending_watermarks(crtc, &config->target, vbl_count);
+
+ mutex_unlock(&dev_priv->wm.mutex);
+}
+
/* Set up chip specific power management-related functions */
void intel_init_pm(struct drm_device *dev)
{
@@ -6568,6 +6654,8 @@ void intel_init_pm(struct drm_device *dev)
dev_priv->wm.spr_latency[0] && dev_priv->wm.cur_latency[0])) {
dev_priv->display.update_wm = ilk_update_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;
} else {
DRM_DEBUG_KMS("Failed to read display plane latency. "
"Disable CxSR\n");