summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Peng <peng.li@linux.intel.com>2009-12-16 16:33:26 +0100
committerGreg Kroah-Hartman <gregkh@suse.de>2009-12-18 13:44:26 -0800
commit66910003dbed5e9cc5499a8e3d207b96dd1c4026 (patch)
treec70f006d8a567afcf9c27ae85a8159bc5678d4a4
parent0b1b72ba20a7d73136f57bb57ff8e2f3f79e62ad (diff)
drm/i915: Fix sync to vblank when VGA output is turned off
commit 778c902640530371a169ad1c03566e7c51b09874 upstream In current vblank-wait implementation, if we turn off VGA output, drm_wait_vblank will still wait on the disabled pipe until timeout, because vblank on the pipe is assumed be enabled. This would cause slow system response on some system such as moblin. This patch resolve the issue by adding a drm helper function drm_vblank_off which explicitly clear vblank_enabled[crtc], wake up any waiting queue and save last vblank counter before turning off crtc. It also slightly change drm_vblank_get to ensure that we will will return immediately if trying to wait on a disabled pipe. Signed-off-by: Li Peng <peng.li@intel.com> Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org> [anholt: hand-applied for conflicts with overlay changes] Signed-off-by: Eric Anholt <eric@anholt.net> Cc: Stefan Bader <stefan.bader@canonical.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/gpu/drm/drm_irq.c34
-rw-r--r--drivers/gpu/drm/i915/intel_display.c1
-rw-r--r--include/drm/drmP.h1
3 files changed, 28 insertions, 8 deletions
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index f85aaf21e783..f298434e87c7 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -402,15 +402,21 @@ int drm_vblank_get(struct drm_device *dev, int crtc)
spin_lock_irqsave(&dev->vbl_lock, irqflags);
/* Going from 0->1 means we have to enable interrupts again */
- if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1 &&
- !dev->vblank_enabled[crtc]) {
- ret = dev->driver->enable_vblank(dev, crtc);
- DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", crtc, ret);
- if (ret)
+ if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1) {
+ if (!dev->vblank_enabled[crtc]) {
+ ret = dev->driver->enable_vblank(dev, crtc);
+ DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", crtc, ret);
+ if (ret)
+ atomic_dec(&dev->vblank_refcount[crtc]);
+ else {
+ dev->vblank_enabled[crtc] = 1;
+ drm_update_vblank_count(dev, crtc);
+ }
+ }
+ } else {
+ if (!dev->vblank_enabled[crtc]) {
atomic_dec(&dev->vblank_refcount[crtc]);
- else {
- dev->vblank_enabled[crtc] = 1;
- drm_update_vblank_count(dev, crtc);
+ ret = -EINVAL;
}
}
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
@@ -437,6 +443,18 @@ void drm_vblank_put(struct drm_device *dev, int crtc)
}
EXPORT_SYMBOL(drm_vblank_put);
+void drm_vblank_off(struct drm_device *dev, int crtc)
+{
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&dev->vbl_lock, irqflags);
+ DRM_WAKEUP(&dev->vbl_queue[crtc]);
+ dev->vblank_enabled[crtc] = 0;
+ dev->last_vblank[crtc] = dev->driver->get_vblank_counter(dev, crtc);
+ spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
+}
+EXPORT_SYMBOL(drm_vblank_off);
+
/**
* drm_vblank_pre_modeset - account for vblanks across mode sets
* @dev: DRM device
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 4f6fc00e35c4..3ac3b7c49869 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1562,6 +1562,7 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
intel_update_watermarks(dev);
/* Give the overlay scaler a chance to disable if it's on this pipe */
//intel_crtc_dpms_video(crtc, FALSE); TODO
+ drm_vblank_off(dev, pipe);
/* Disable the VGA plane that we never use */
i915_disable_vga(dev);
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 45b67d9c39c1..4637dce03fab 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -1268,6 +1268,7 @@ extern u32 drm_vblank_count(struct drm_device *dev, int crtc);
extern void drm_handle_vblank(struct drm_device *dev, int crtc);
extern int drm_vblank_get(struct drm_device *dev, int crtc);
extern void drm_vblank_put(struct drm_device *dev, int crtc);
+extern void drm_vblank_off(struct drm_device *dev, int crtc);
extern void drm_vblank_cleanup(struct drm_device *dev);
/* Modesetting support */
extern void drm_vblank_pre_modeset(struct drm_device *dev, int crtc);