Merge tag 'fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm...
[linux-2.6-block.git] / drivers / gpu / drm / drm_crtc.c
index bff2fa941f6004dca49ce176b928171d075584a8..d6cf77c472e710cf246193dca874bd3b8bc72b9e 100644 (file)
@@ -202,6 +202,7 @@ static struct drm_conn_prop_enum_list drm_connector_enum_list[] =
        { DRM_MODE_CONNECTOR_TV, "TV" },
        { DRM_MODE_CONNECTOR_eDP, "eDP" },
        { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" },
+       { DRM_MODE_CONNECTOR_DSI, "DSI" },
 };
 
 static const struct drm_prop_enum_list drm_encoder_enum_list[] =
@@ -211,6 +212,7 @@ static const struct drm_prop_enum_list drm_encoder_enum_list[] =
        { DRM_MODE_ENCODER_LVDS, "LVDS" },
        { DRM_MODE_ENCODER_TVDAC, "TV" },
        { DRM_MODE_ENCODER_VIRTUAL, "Virtual" },
+       { DRM_MODE_ENCODER_DSI, "DSI" },
 };
 
 void drm_connector_ida_init(void)
@@ -1301,7 +1303,7 @@ static void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out,
 }
 
 /**
- * drm_crtc_convert_to_umode - convert a modeinfo into a drm_display_mode
+ * drm_crtc_convert_umode - convert a modeinfo into a drm_display_mode
  * @out: drm_display_mode to return to the user
  * @in: drm_mode_modeinfo to use
  *
@@ -1317,6 +1319,9 @@ static int drm_crtc_convert_umode(struct drm_display_mode *out,
        if (in->clock > INT_MAX || in->vrefresh > INT_MAX)
                return -ERANGE;
 
+       if ((in->flags & DRM_MODE_FLAG_3D_MASK) > DRM_MODE_FLAG_3D_MAX)
+               return -EINVAL;
+
        out->clock = in->clock;
        out->hdisplay = in->hdisplay;
        out->hsync_start = in->hsync_start;
@@ -1552,7 +1557,7 @@ int drm_mode_getcrtc(struct drm_device *dev,
        obj = drm_mode_object_find(dev, crtc_resp->crtc_id,
                                   DRM_MODE_OBJECT_CRTC);
        if (!obj) {
-               ret = -EINVAL;
+               ret = -ENOENT;
                goto out;
        }
        crtc = obj_to_crtc(obj);
@@ -1579,6 +1584,19 @@ out:
        return ret;
 }
 
+static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode,
+                                        const struct drm_file *file_priv)
+{
+       /*
+        * If user-space hasn't configured the driver to expose the stereo 3D
+        * modes, don't expose them.
+        */
+       if (!file_priv->stereo_allowed && drm_mode_is_stereo(mode))
+               return false;
+
+       return true;
+}
+
 /**
  * drm_mode_getconnector - get connector configuration
  * @dev: drm device for the ioctl
@@ -1623,7 +1641,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
        obj = drm_mode_object_find(dev, out_resp->connector_id,
                                   DRM_MODE_OBJECT_CONNECTOR);
        if (!obj) {
-               ret = -EINVAL;
+               ret = -ENOENT;
                goto out;
        }
        connector = obj_to_connector(obj);
@@ -1644,7 +1662,8 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
 
        /* delayed so we get modes regardless of pre-fill_modes state */
        list_for_each_entry(mode, &connector->modes, head)
-               mode_count++;
+               if (drm_mode_expose_to_userspace(mode, file_priv))
+                       mode_count++;
 
        out_resp->connector_id = connector->base.id;
        out_resp->connector_type = connector->connector_type;
@@ -1666,6 +1685,9 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
                copied = 0;
                mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr;
                list_for_each_entry(mode, &connector->modes, head) {
+                       if (!drm_mode_expose_to_userspace(mode, file_priv))
+                               continue;
+
                        drm_crtc_convert_to_umode(&u_mode, mode);
                        if (copy_to_user(mode_ptr + copied,
                                         &u_mode, sizeof(u_mode))) {
@@ -1735,7 +1757,7 @@ int drm_mode_getencoder(struct drm_device *dev, void *data,
        obj = drm_mode_object_find(dev, enc_resp->encoder_id,
                                   DRM_MODE_OBJECT_ENCODER);
        if (!obj) {
-               ret = -EINVAL;
+               ret = -ENOENT;
                goto out;
        }
        encoder = obj_to_encoder(obj);
@@ -2040,6 +2062,45 @@ int drm_mode_set_config_internal(struct drm_mode_set *set)
 }
 EXPORT_SYMBOL(drm_mode_set_config_internal);
 
+/*
+ * Checks that the framebuffer is big enough for the CRTC viewport
+ * (x, y, hdisplay, vdisplay)
+ */
+static int drm_crtc_check_viewport(const struct drm_crtc *crtc,
+                                  int x, int y,
+                                  const struct drm_display_mode *mode,
+                                  const struct drm_framebuffer *fb)
+
+{
+       int hdisplay, vdisplay;
+
+       hdisplay = mode->hdisplay;
+       vdisplay = mode->vdisplay;
+
+       if (drm_mode_is_stereo(mode)) {
+               struct drm_display_mode adjusted = *mode;
+
+               drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE);
+               hdisplay = adjusted.crtc_hdisplay;
+               vdisplay = adjusted.crtc_vdisplay;
+       }
+
+       if (crtc->invert_dimensions)
+               swap(hdisplay, vdisplay);
+
+       if (hdisplay > fb->width ||
+           vdisplay > fb->height ||
+           x > fb->width - hdisplay ||
+           y > fb->height - vdisplay) {
+               DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n",
+                             fb->width, fb->height, hdisplay, vdisplay, x, y,
+                             crtc->invert_dimensions ? " (inverted)" : "");
+               return -ENOSPC;
+       }
+
+       return 0;
+}
+
 /**
  * drm_mode_setcrtc - set CRTC configuration
  * @dev: drm device for the ioctl
@@ -2080,14 +2141,13 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
                                   DRM_MODE_OBJECT_CRTC);
        if (!obj) {
                DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id);
-               ret = -EINVAL;
+               ret = -ENOENT;
                goto out;
        }
        crtc = obj_to_crtc(obj);
        DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
 
        if (crtc_req->mode_valid) {
-               int hdisplay, vdisplay;
                /* If we have a mode we need a framebuffer. */
                /* If we pass -1, set the mode with the currently bound fb */
                if (crtc_req->fb_id == -1) {
@@ -2104,7 +2164,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
                        if (!fb) {
                                DRM_DEBUG_KMS("Unknown FB ID%d\n",
                                                crtc_req->fb_id);
-                               ret = -EINVAL;
+                               ret = -ENOENT;
                                goto out;
                        }
                }
@@ -2123,23 +2183,11 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
 
                drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
 
-               hdisplay = mode->hdisplay;
-               vdisplay = mode->vdisplay;
-
-               if (crtc->invert_dimensions)
-                       swap(hdisplay, vdisplay);
-
-               if (hdisplay > fb->width ||
-                   vdisplay > fb->height ||
-                   crtc_req->x > fb->width - hdisplay ||
-                   crtc_req->y > fb->height - vdisplay) {
-                       DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n",
-                                     fb->width, fb->height,
-                                     hdisplay, vdisplay, crtc_req->x, crtc_req->y,
-                                     crtc->invert_dimensions ? " (inverted)" : "");
-                       ret = -ENOSPC;
+               ret = drm_crtc_check_viewport(crtc, crtc_req->x, crtc_req->y,
+                                             mode, fb);
+               if (ret)
                        goto out;
-               }
+
        }
 
        if (crtc_req->count_connectors == 0 && mode) {
@@ -2184,7 +2232,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
                        if (!obj) {
                                DRM_DEBUG_KMS("Connector id %d unknown\n",
                                                out_id);
-                               ret = -EINVAL;
+                               ret = -ENOENT;
                                goto out;
                        }
                        connector = obj_to_connector(obj);
@@ -2232,7 +2280,7 @@ static int drm_mode_cursor_common(struct drm_device *dev,
        obj = drm_mode_object_find(dev, req->crtc_id, DRM_MODE_OBJECT_CRTC);
        if (!obj) {
                DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id);
-               return -EINVAL;
+               return -ENOENT;
        }
        crtc = obj_to_crtc(obj);
 
@@ -2441,6 +2489,8 @@ static int format_check(const struct drm_mode_fb_cmd2 *r)
        case DRM_FORMAT_YVU444:
                return 0;
        default:
+               DRM_DEBUG_KMS("invalid pixel format %s\n",
+                             drm_get_format_name(r->pixel_format));
                return -EINVAL;
        }
 }
@@ -2606,7 +2656,7 @@ fail_lookup:
        mutex_unlock(&dev->mode_config.fb_lock);
        mutex_unlock(&file_priv->fbs_lock);
 
-       return -EINVAL;
+       return -ENOENT;
 }
 
 /**
@@ -2634,7 +2684,7 @@ int drm_mode_getfb(struct drm_device *dev,
 
        fb = drm_framebuffer_lookup(dev, r->fb_id);
        if (!fb)
-               return -EINVAL;
+               return -ENOENT;
 
        r->height = fb->height;
        r->width = fb->width;
@@ -2679,7 +2729,7 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
 
        fb = drm_framebuffer_lookup(dev, r->fb_id);
        if (!fb)
-               return -EINVAL;
+               return -ENOENT;
 
        num_clips = r->num_clips;
        clips_ptr = (struct drm_clip_rect __user *)(unsigned long)r->clips_ptr;
@@ -3011,7 +3061,7 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev,
        drm_modeset_lock_all(dev);
        obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY);
        if (!obj) {
-               ret = -EINVAL;
+               ret = -ENOENT;
                goto done;
        }
        property = obj_to_property(obj);
@@ -3140,7 +3190,7 @@ int drm_mode_getblob_ioctl(struct drm_device *dev,
        drm_modeset_lock_all(dev);
        obj = drm_mode_object_find(dev, out_resp->blob_id, DRM_MODE_OBJECT_BLOB);
        if (!obj) {
-               ret = -EINVAL;
+               ret = -ENOENT;
                goto done;
        }
        blob = obj_to_blob(obj);
@@ -3301,7 +3351,7 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
 
        obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type);
        if (!obj) {
-               ret = -EINVAL;
+               ret = -ENOENT;
                goto out;
        }
        if (!obj->properties) {
@@ -3354,8 +3404,10 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
        drm_modeset_lock_all(dev);
 
        arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type);
-       if (!arg_obj)
+       if (!arg_obj) {
+               ret = -ENOENT;
                goto out;
+       }
        if (!arg_obj->properties)
                goto out;
 
@@ -3368,8 +3420,10 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
 
        prop_obj = drm_mode_object_find(dev, arg->prop_id,
                                        DRM_MODE_OBJECT_PROPERTY);
-       if (!prop_obj)
+       if (!prop_obj) {
+               ret = -ENOENT;
                goto out;
+       }
        property = obj_to_property(prop_obj);
 
        if (!drm_property_change_is_valid(property, arg->value))
@@ -3454,7 +3508,7 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev,
        drm_modeset_lock_all(dev);
        obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC);
        if (!obj) {
-               ret = -EINVAL;
+               ret = -ENOENT;
                goto out;
        }
        crtc = obj_to_crtc(obj);
@@ -3513,7 +3567,7 @@ int drm_mode_gamma_get_ioctl(struct drm_device *dev,
        drm_modeset_lock_all(dev);
        obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC);
        if (!obj) {
-               ret = -EINVAL;
+               ret = -ENOENT;
                goto out;
        }
        crtc = obj_to_crtc(obj);
@@ -3556,7 +3610,6 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
        struct drm_framebuffer *fb = NULL, *old_fb = NULL;
        struct drm_pending_vblank_event *e = NULL;
        unsigned long flags;
-       int hdisplay, vdisplay;
        int ret = -EINVAL;
 
        if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS ||
@@ -3568,7 +3621,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
 
        obj = drm_mode_object_find(dev, page_flip->crtc_id, DRM_MODE_OBJECT_CRTC);
        if (!obj)
-               return -EINVAL;
+               return -ENOENT;
        crtc = obj_to_crtc(obj);
 
        mutex_lock(&crtc->mutex);
@@ -3585,25 +3638,14 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
                goto out;
 
        fb = drm_framebuffer_lookup(dev, page_flip->fb_id);
-       if (!fb)
+       if (!fb) {
+               ret = -ENOENT;
                goto out;
+       }
 
-       hdisplay = crtc->mode.hdisplay;
-       vdisplay = crtc->mode.vdisplay;
-
-       if (crtc->invert_dimensions)
-               swap(hdisplay, vdisplay);
-
-       if (hdisplay > fb->width ||
-           vdisplay > fb->height ||
-           crtc->x > fb->width - hdisplay ||
-           crtc->y > fb->height - vdisplay) {
-               DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n",
-                             fb->width, fb->height, hdisplay, vdisplay, crtc->x, crtc->y,
-                             crtc->invert_dimensions ? " (inverted)" : "");
-               ret = -ENOSPC;
+       ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y, &crtc->mode, fb);
+       if (ret)
                goto out;
-       }
 
        if (crtc->fb->pixel_format != fb->pixel_format) {
                DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n");
@@ -3788,7 +3830,8 @@ void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth,
                *bpp = 32;
                break;
        default:
-               DRM_DEBUG_KMS("unsupported pixel format\n");
+               DRM_DEBUG_KMS("unsupported pixel format %s\n",
+                             drm_get_format_name(format));
                *depth = 0;
                *bpp = 0;
                break;