summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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");