]> Pileus Git - ~andy/linux/blobdiff - drivers/gpu/drm/drm_crtc_helper.c
Merge tag 'v3.2-rc6' of /home/airlied/devel/kernel/linux-2.6 into drm-core-next
[~andy/linux] / drivers / gpu / drm / drm_crtc_helper.c
index 432d5391b93c965cb1f3bfe15ef6489d2bf60bc2..42f86e71479a13cf2b67f906694e62fa751a57b2 100644 (file)
@@ -457,6 +457,30 @@ done:
 EXPORT_SYMBOL(drm_crtc_helper_set_mode);
 
 
+static int
+drm_crtc_helper_disable(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_connector *connector;
+       struct drm_encoder *encoder;
+
+       /* Decouple all encoders and their attached connectors from this crtc */
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+               if (encoder->crtc != crtc)
+                       continue;
+
+               list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+                       if (connector->encoder != encoder)
+                               continue;
+
+                       connector->encoder = NULL;
+               }
+       }
+
+       drm_helper_disable_unused_functions(dev);
+       return 0;
+}
+
 /**
  * drm_crtc_helper_set_config - set a new config from userspace
  * @crtc: CRTC to setup
@@ -485,6 +509,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
        struct drm_connector *save_connectors, *connector;
        int count = 0, ro, fail = 0;
        struct drm_crtc_helper_funcs *crtc_funcs;
+       struct drm_mode_set save_set;
        int ret = 0;
        int i;
 
@@ -510,8 +535,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
                                (int)set->num_connectors, set->x, set->y);
        } else {
                DRM_DEBUG_KMS("[CRTC:%d] [NOFB]\n", set->crtc->base.id);
-               set->mode = NULL;
-               set->num_connectors = 0;
+               return drm_crtc_helper_disable(set->crtc);
        }
 
        dev = set->crtc->dev;
@@ -557,6 +581,12 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
                save_connectors[count++] = *connector;
        }
 
+       save_set.crtc = set->crtc;
+       save_set.mode = &set->crtc->mode;
+       save_set.x = set->crtc->x;
+       save_set.y = set->crtc->y;
+       save_set.fb = set->crtc->fb;
+
        /* We should be able to check here if the fb has the same properties
         * and then just flip_or_move it */
        if (set->crtc->fb != set->fb) {
@@ -722,6 +752,12 @@ fail:
                *connector = save_connectors[count++];
        }
 
+       /* Try to restore the config */
+       if (mode_changed &&
+           !drm_crtc_helper_set_mode(save_set.crtc, save_set.mode, save_set.x,
+                                     save_set.y, save_set.fb))
+               DRM_ERROR("failed to restore config after modeset failure\n");
+
        kfree(save_connectors);
        kfree(save_encoders);
        kfree(save_crtcs);
@@ -811,54 +847,18 @@ void drm_helper_connector_dpms(struct drm_connector *connector, int mode)
 }
 EXPORT_SYMBOL(drm_helper_connector_dpms);
 
-/*
- * Just need to support RGB formats here for compat with code that doesn't
- * use pixel formats directly yet.
- */
-void drm_helper_get_fb_bpp_depth(uint32_t format, unsigned int *depth,
-                                int *bpp)
-{
-       switch (format) {
-       case DRM_FOURCC_RGB332:
-               *depth = 8;
-               *bpp = 8;
-               break;
-       case DRM_FOURCC_RGB555:
-               *depth = 15;
-               *bpp = 16;
-               break;
-       case DRM_FOURCC_RGB565:
-               *depth = 16;
-               *bpp = 16;
-               break;
-       case DRM_FOURCC_RGB24:
-               *depth = 24;
-               *bpp = 32;
-               break;
-       case DRM_INTEL_RGB30:
-               *depth = 30;
-               *bpp = 32;
-               break;
-       case DRM_FOURCC_RGB32:
-               *depth = 32;
-               *bpp = 32;
-               break;
-       default:
-               DRM_DEBUG_KMS("unsupported pixel format\n");
-               *depth = 0;
-               *bpp = 0;
-               break;
-       }
-}
-EXPORT_SYMBOL(drm_helper_get_fb_bpp_depth);
-
 int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb,
                                   struct drm_mode_fb_cmd2 *mode_cmd)
 {
+       int i;
+
        fb->width = mode_cmd->width;
        fb->height = mode_cmd->height;
-       fb->pitch = mode_cmd->pitches[0];
-       drm_helper_get_fb_bpp_depth(mode_cmd->pixel_format, &fb->depth,
+       for (i = 0; i < 4; i++) {
+               fb->pitches[i] = mode_cmd->pitches[i];
+               fb->offsets[i] = mode_cmd->offsets[i];
+       }
+       drm_fb_get_bpp_depth(mode_cmd->pixel_format, &fb->depth,
                                    &fb->bits_per_pixel);
        fb->pixel_format = mode_cmd->pixel_format;