DRM: add mode setting support
[deliverable/linux.git] / drivers / gpu / drm / drm_irq.c
index 1e787f894b3cf38f6c46eeda39c73cb8a49ad1c5..1608f8dbfda062c9cda16ce26dfff650985ed947 100644 (file)
@@ -305,6 +305,8 @@ int drm_control(struct drm_device *dev, void *data,
        case DRM_INST_HANDLER:
                if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
                        return 0;
+               if (drm_core_check_feature(dev, DRIVER_MODESET))
+                       return 0;
                if (dev->if_version < DRM_IF_VERSION(1, 2) &&
                    ctl->irq != dev->pdev->irq)
                        return -EINVAL;
@@ -312,6 +314,8 @@ int drm_control(struct drm_device *dev, void *data,
        case DRM_UNINST_HANDLER:
                if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
                        return 0;
+               if (drm_core_check_feature(dev, DRIVER_MODESET))
+                       return 0;
                return drm_irq_uninstall(dev);
        default:
                return -EINVAL;
@@ -426,6 +430,45 @@ void drm_vblank_put(struct drm_device *dev, int crtc)
 }
 EXPORT_SYMBOL(drm_vblank_put);
 
+/**
+ * drm_vblank_pre_modeset - account for vblanks across mode sets
+ * @dev: DRM device
+ * @crtc: CRTC in question
+ * @post: post or pre mode set?
+ *
+ * Account for vblank events across mode setting events, which will likely
+ * reset the hardware frame counter.
+ */
+void drm_vblank_pre_modeset(struct drm_device *dev, int crtc)
+{
+       /*
+        * To avoid all the problems that might happen if interrupts
+        * were enabled/disabled around or between these calls, we just
+        * have the kernel take a reference on the CRTC (just once though
+        * to avoid corrupting the count if multiple, mismatch calls occur),
+        * so that interrupts remain enabled in the interim.
+        */
+       if (!dev->vblank_inmodeset[crtc]) {
+               dev->vblank_inmodeset[crtc] = 1;
+               drm_vblank_get(dev, crtc);
+       }
+}
+EXPORT_SYMBOL(drm_vblank_pre_modeset);
+
+void drm_vblank_post_modeset(struct drm_device *dev, int crtc)
+{
+       unsigned long irqflags;
+
+       if (dev->vblank_inmodeset[crtc]) {
+               spin_lock_irqsave(&dev->vbl_lock, irqflags);
+               dev->vblank_disable_allowed = 1;
+               dev->vblank_inmodeset[crtc] = 0;
+               spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
+               drm_vblank_put(dev, crtc);
+       }
+}
+EXPORT_SYMBOL(drm_vblank_post_modeset);
+
 /**
  * drm_modeset_ctl - handle vblank event counter changes across mode switch
  * @DRM_IOCTL_ARGS: standard ioctl arguments
@@ -441,7 +484,6 @@ int drm_modeset_ctl(struct drm_device *dev, void *data,
                    struct drm_file *file_priv)
 {
        struct drm_modeset_ctl *modeset = data;
-       unsigned long irqflags;
        int crtc, ret = 0;
 
        /* If drm_vblank_init() hasn't been called yet, just no-op */
@@ -454,28 +496,12 @@ int drm_modeset_ctl(struct drm_device *dev, void *data,
                goto out;
        }
 
-       /*
-        * To avoid all the problems that might happen if interrupts
-        * were enabled/disabled around or between these calls, we just
-        * have the kernel take a reference on the CRTC (just once though
-        * to avoid corrupting the count if multiple, mismatch calls occur),
-        * so that interrupts remain enabled in the interim.
-        */
        switch (modeset->cmd) {
        case _DRM_PRE_MODESET:
-               if (!dev->vblank_inmodeset[crtc]) {
-                       dev->vblank_inmodeset[crtc] = 1;
-                       drm_vblank_get(dev, crtc);
-               }
+               drm_vblank_pre_modeset(dev, crtc);
                break;
        case _DRM_POST_MODESET:
-               if (dev->vblank_inmodeset[crtc]) {
-                       spin_lock_irqsave(&dev->vbl_lock, irqflags);
-                       dev->vblank_disable_allowed = 1;
-                       dev->vblank_inmodeset[crtc] = 0;
-                       spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
-                       drm_vblank_put(dev, crtc);
-               }
+               drm_vblank_post_modeset(dev, crtc);
                break;
        default:
                ret = -EINVAL;
This page took 0.025858 seconds and 5 git commands to generate.