diff options
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_drv.h | 11 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_pm.c | 88 |
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"); |