[Intel-gfx] [PATCH 04/25] drm/i915: Use vblank notifier for IPS
ville.syrjala at linux.intel.com
ville.syrjala at linux.intel.com
Wed Jun 18 19:58:37 CEST 2014
From: Ville Syrjälä <ville.syrjala at linux.intel.com>
IPS enable must be delayed one frame after the planes have been enabled.
Currently there's a blocking vblank wait in the path. Replace that with
a vblank notify so that it can be done asynchronously. The disable path
must remain synchronous.
TODO: see if the ips state checking can be fixed, for now it's disabled
Signed-off-by: Ville Syrjälä <ville.syrjala at linux.intel.com>
---
drivers/gpu/drm/i915/i915_drv.c | 2 +
drivers/gpu/drm/i915/i915_drv.h | 12 ++++
drivers/gpu/drm/i915/intel_display.c | 110 +++++++++++++++++++++++++----------
drivers/gpu/drm/i915/intel_drv.h | 8 +--
4 files changed, 94 insertions(+), 38 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 7ae4e2a..f046a3c 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -537,6 +537,8 @@ static int i915_drm_freeze(struct drm_device *dev)
}
drm_modeset_unlock_all(dev);
+ intel_ips_cleanup(dev);
+
intel_modeset_suspend_hw(dev);
}
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 0640071..4fd8be9 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1331,6 +1331,13 @@ struct intel_pipe_crc {
wait_queue_head_t wq;
};
+struct intel_vblank_notify {
+ void (*notify)(struct intel_vblank_notify *notify);
+ struct intel_crtc *crtc;
+ struct list_head list;
+ u32 vbl_count;
+};
+
struct drm_i915_private {
struct drm_device *dev;
struct kmem_cache *slab;
@@ -1405,6 +1412,11 @@ struct drm_i915_private {
u32 hpd_event_bits;
struct timer_list hotplug_reenable_timer;
+ struct {
+ struct intel_crtc *crtc;
+ struct work_struct work;
+ struct intel_vblank_notify notify;
+ } hsw_ips;
struct i915_fbc fbc;
struct i915_drrs drrs;
struct intel_opregion opregion;
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index af7fd96..e672fed 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3774,38 +3774,70 @@ static void intel_disable_planes(struct drm_crtc *crtc)
}
}
+static void bdw_ips_work(struct work_struct *work)
+{
+ struct drm_i915_private *dev_priv =
+ container_of(work, struct drm_i915_private, hsw_ips.work);
+ struct intel_crtc *crtc = ACCESS_ONCE(dev_priv->hsw_ips.crtc);
+
+ if (!crtc)
+ return;
+
+ drm_modeset_lock(&crtc->base.mutex, NULL);
+
+ if (WARN_ON(!crtc->config.ips_enabled))
+ goto unlock;
+
+ /*
+ * IPS must have been disabled in the meantime,
+ * and may not re-enabled, at least quite so soon.
+ */
+ if (!crtc->primary_enabled ||
+ intel_vblank_notify_pending(&dev_priv->hsw_ips.notify))
+ goto unlock;
+
+ assert_plane_enabled(dev_priv, crtc->plane);
+
+ mutex_lock(&dev_priv->rps.hw_lock);
+ WARN_ON(sandybridge_pcode_write(dev_priv, DISPLAY_IPS_CONTROL,
+ IPS_ENABLE | IPS_PCODE_CONTROL));
+ mutex_unlock(&dev_priv->rps.hw_lock);
+ /* Quoting Art Runyan: "its not safe to expect any particular
+ * value in IPS_CTL bit 31 after enabling IPS through the
+ * mailbox." Moreover, the mailbox may return a bogus state,
+ * so we need to just enable it and continue on.
+ */
+
+ unlock:
+ drm_modeset_unlock(&crtc->base.mutex);
+}
+
+static void hsw_ips_notify(struct intel_vblank_notify *notify)
+{
+ struct drm_i915_private *dev_priv =
+ container_of(notify, struct drm_i915_private, hsw_ips.notify);
+
+ if (IS_BROADWELL(dev_priv->dev))
+ schedule_work(&dev_priv->hsw_ips.work);
+ else
+ I915_WRITE(IPS_CTL, IPS_ENABLE);
+}
+
void hsw_enable_ips(struct intel_crtc *crtc)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
+ lockdep_assert_held(&crtc->base.mutex.mutex.base);
+
+ WARN_ON(intel_vblank_notify_pending(&dev_priv->hsw_ips.notify));
+
if (!crtc->config.ips_enabled)
return;
- /* We can only enable IPS after we enable a plane and wait for a vblank */
- intel_wait_for_vblank(dev, crtc->pipe);
+ dev_priv->hsw_ips.crtc = crtc;
- assert_plane_enabled(dev_priv, crtc->plane);
- if (IS_BROADWELL(dev)) {
- mutex_lock(&dev_priv->rps.hw_lock);
- WARN_ON(sandybridge_pcode_write(dev_priv, DISPLAY_IPS_CONTROL,
- IPS_ENABLE | IPS_PCODE_CONTROL));
- mutex_unlock(&dev_priv->rps.hw_lock);
- /* Quoting Art Runyan: "its not safe to expect any particular
- * value in IPS_CTL bit 31 after enabling IPS through the
- * mailbox." Moreover, the mailbox may return a bogus state,
- * so we need to just enable it and continue on.
- */
- } else {
- I915_WRITE(IPS_CTL, IPS_ENABLE);
- /* The bit only becomes 1 in the next vblank, so this wait here
- * is essentially intel_wait_for_vblank. If we don't have this
- * and don't wait for vblanks until the end of crtc_enable, then
- * the HW state readout code will complain that the expected
- * IPS_CTL value is not the one we read. */
- if (wait_for(I915_READ_NOTRACE(IPS_CTL) & IPS_ENABLE, 50))
- DRM_ERROR("Timed out waiting for IPS enable\n");
- }
+ intel_vblank_notify_add(crtc, &dev_priv->hsw_ips.notify);
}
void hsw_disable_ips(struct intel_crtc *crtc)
@@ -3813,9 +3845,13 @@ void hsw_disable_ips(struct intel_crtc *crtc)
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
+ lockdep_assert_held(&crtc->base.mutex.mutex.base);
+
if (!crtc->config.ips_enabled)
return;
+ intel_vblank_notify_cancel(&dev_priv->hsw_ips.notify);
+
assert_plane_enabled(dev_priv, crtc->plane);
if (IS_BROADWELL(dev)) {
mutex_lock(&dev_priv->rps.hw_lock);
@@ -3833,6 +3869,22 @@ void hsw_disable_ips(struct intel_crtc *crtc)
intel_wait_for_vblank(dev, crtc->pipe);
}
+static void intel_ips_init(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ dev_priv->hsw_ips.notify.notify = hsw_ips_notify;
+ INIT_WORK(&dev_priv->hsw_ips.work, bdw_ips_work);
+}
+
+void intel_ips_cleanup(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ intel_vblank_notify_cancel(&dev_priv->hsw_ips.notify);
+ cancel_work_sync(&dev_priv->hsw_ips.work);
+}
+
/** Loads the palette/gamma unit for the CRTC with the prepared values */
static void intel_crtc_load_lut(struct drm_crtc *crtc)
{
@@ -7613,10 +7665,6 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
if (intel_display_power_enabled(dev_priv, pfit_domain))
ironlake_get_pfit_config(crtc, pipe_config);
- if (IS_HASWELL(dev))
- pipe_config->ips_enabled = hsw_crtc_supports_ips(crtc) &&
- (I915_READ(IPS_CTL) & IPS_ENABLE);
-
pipe_config->pixel_multiplier = 1;
return true;
@@ -10207,10 +10255,6 @@ intel_pipe_config_compare(struct drm_device *dev,
PIPE_CONF_CHECK_I(pch_pfit.size);
}
- /* BDW+ don't expose a synchronous way to read the state */
- if (IS_HASWELL(dev))
- PIPE_CONF_CHECK_I(ips_enabled);
-
PIPE_CONF_CHECK_I(double_wide);
PIPE_CONF_CHECK_I(shared_dpll);
@@ -12274,6 +12318,8 @@ void intel_modeset_init(struct drm_device *dev)
INTEL_INFO(dev)->num_pipes,
INTEL_INFO(dev)->num_pipes > 1 ? "s" : "");
+ intel_ips_init(dev);
+
for_each_pipe(pipe) {
intel_crtc_init(dev, pipe);
for_each_sprite(pipe, sprite) {
@@ -12808,6 +12854,8 @@ void intel_modeset_cleanup(struct drm_device *dev)
mutex_unlock(&dev->struct_mutex);
+ intel_ips_cleanup(dev);
+
/* flush any delayed tasks or pending work */
flush_scheduled_work();
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index c93626b..9a8eb0e 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -358,13 +358,6 @@ struct intel_pipe_wm {
bool sprites_scaled;
};
-struct intel_vblank_notify {
- void (*notify)(struct intel_vblank_notify *notify);
- struct intel_crtc *crtc;
- struct list_head list;
- u32 vbl_count;
-};
-
struct intel_mmio_flip {
u32 seqno;
u32 ring_id;
@@ -813,6 +806,7 @@ ironlake_check_encoder_dotclock(const struct intel_crtc_config *pipe_config,
bool intel_crtc_active(struct drm_crtc *crtc);
void hsw_enable_ips(struct intel_crtc *crtc);
void hsw_disable_ips(struct intel_crtc *crtc);
+void intel_ips_cleanup(struct drm_device *dev);
void intel_display_set_init_power(struct drm_i915_private *dev, bool enable);
enum intel_display_power_domain
intel_display_port_power_domain(struct intel_encoder *intel_encoder);
--
1.8.5.5
More information about the Intel-gfx
mailing list