Merge Linus master into drm-next
[linux-2.6-block.git] / drivers / gpu / drm / drm_crtc.c
index b6f076b213bcfde496a61824335b68d1760b5613..3007b44e6bf4494c36e06f65210efa98ea5b4a86 100644 (file)
@@ -660,6 +660,9 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
        struct drm_mode_config *config = &dev->mode_config;
        int ret;
 
+       WARN_ON(primary && primary->type != DRM_PLANE_TYPE_PRIMARY);
+       WARN_ON(cursor && cursor->type != DRM_PLANE_TYPE_CURSOR);
+
        crtc->dev = dev;
        crtc->funcs = funcs;
        crtc->invert_dimensions = false;
@@ -1999,21 +2002,32 @@ int drm_mode_getcrtc(struct drm_device *dev,
                return -ENOENT;
 
        drm_modeset_lock_crtc(crtc, crtc->primary);
-       crtc_resp->x = crtc->x;
-       crtc_resp->y = crtc->y;
        crtc_resp->gamma_size = crtc->gamma_size;
        if (crtc->primary->fb)
                crtc_resp->fb_id = crtc->primary->fb->base.id;
        else
                crtc_resp->fb_id = 0;
 
-       if (crtc->enabled) {
-
-               drm_crtc_convert_to_umode(&crtc_resp->mode, &crtc->mode);
-               crtc_resp->mode_valid = 1;
+       if (crtc->state) {
+               crtc_resp->x = crtc->primary->state->src_x >> 16;
+               crtc_resp->y = crtc->primary->state->src_y >> 16;
+               if (crtc->state->enable) {
+                       drm_crtc_convert_to_umode(&crtc_resp->mode, &crtc->state->mode);
+                       crtc_resp->mode_valid = 1;
 
+               } else {
+                       crtc_resp->mode_valid = 0;
+               }
        } else {
-               crtc_resp->mode_valid = 0;
+               crtc_resp->x = crtc->x;
+               crtc_resp->y = crtc->y;
+               if (crtc->enabled) {
+                       drm_crtc_convert_to_umode(&crtc_resp->mode, &crtc->mode);
+                       crtc_resp->mode_valid = 1;
+
+               } else {
+                       crtc_resp->mode_valid = 0;
+               }
        }
        drm_modeset_unlock_crtc(crtc);
 
@@ -2266,8 +2280,6 @@ int drm_mode_getencoder(struct drm_device *dev, void *data,
        crtc = drm_encoder_get_crtc(encoder);
        if (crtc)
                enc_resp->crtc_id = crtc->base.id;
-       else if (encoder->crtc)
-               enc_resp->crtc_id = encoder->crtc->base.id;
        else
                enc_resp->crtc_id = 0;
        drm_modeset_unlock(&dev->mode_config.connection_mutex);
@@ -2402,6 +2414,27 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
        return 0;
 }
 
+/**
+ * drm_plane_check_pixel_format - Check if the plane supports the pixel format
+ * @plane: plane to check for format support
+ * @format: the pixel format
+ *
+ * Returns:
+ * Zero of @plane has @format in its list of supported pixel formats, -EINVAL
+ * otherwise.
+ */
+int drm_plane_check_pixel_format(const struct drm_plane *plane, u32 format)
+{
+       unsigned int i;
+
+       for (i = 0; i < plane->format_count; i++) {
+               if (format == plane->format_types[i])
+                       return 0;
+       }
+
+       return -EINVAL;
+}
+
 /*
  * setplane_internal - setplane handler for internal callers
  *
@@ -2422,7 +2455,6 @@ static int __setplane_internal(struct drm_plane *plane,
 {
        int ret = 0;
        unsigned int fb_width, fb_height;
-       unsigned int i;
 
        /* No fb means shut it down */
        if (!fb) {
@@ -2445,16 +2477,24 @@ static int __setplane_internal(struct drm_plane *plane,
        }
 
        /* Check whether this plane supports the fb pixel format. */
-       for (i = 0; i < plane->format_count; i++)
-               if (fb->pixel_format == plane->format_types[i])
-                       break;
-       if (i == plane->format_count) {
+       ret = drm_plane_check_pixel_format(plane, fb->pixel_format);
+       if (ret) {
                DRM_DEBUG_KMS("Invalid pixel format %s\n",
                              drm_get_format_name(fb->pixel_format));
-               ret = -EINVAL;
                goto out;
        }
 
+       /* Give drivers some help against integer overflows */
+       if (crtc_w > INT_MAX ||
+           crtc_x > INT_MAX - (int32_t) crtc_w ||
+           crtc_h > INT_MAX ||
+           crtc_y > INT_MAX - (int32_t) crtc_h) {
+               DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
+                             crtc_w, crtc_h, crtc_x, crtc_y);
+               return -ERANGE;
+       }
+
+
        fb_width = fb->width << 16;
        fb_height = fb->height << 16;
 
@@ -2539,17 +2579,6 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                return -EINVAL;
 
-       /* Give drivers some help against integer overflows */
-       if (plane_req->crtc_w > INT_MAX ||
-           plane_req->crtc_x > INT_MAX - (int32_t) plane_req->crtc_w ||
-           plane_req->crtc_h > INT_MAX ||
-           plane_req->crtc_y > INT_MAX - (int32_t) plane_req->crtc_h) {
-               DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
-                             plane_req->crtc_w, plane_req->crtc_h,
-                             plane_req->crtc_x, plane_req->crtc_y);
-               return -ERANGE;
-       }
-
        /*
         * First, find the plane, crtc, and fb objects.  If not available,
         * we don't bother to call the driver.
@@ -2775,6 +2804,23 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
 
                drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
 
+               /*
+                * Check whether the primary plane supports the fb pixel format.
+                * Drivers not implementing the universal planes API use a
+                * default formats list provided by the DRM core which doesn't
+                * match real hardware capabilities. Skip the check in that
+                * case.
+                */
+               if (!crtc->primary->format_default) {
+                       ret = drm_plane_check_pixel_format(crtc->primary,
+                                                          fb->pixel_format);
+                       if (ret) {
+                               DRM_DEBUG_KMS("Invalid pixel format %s\n",
+                                       drm_get_format_name(fb->pixel_format));
+                               goto out;
+                       }
+               }
+
                ret = drm_crtc_check_viewport(crtc, crtc_req->x, crtc_req->y,
                                              mode, fb);
                if (ret)
@@ -3252,6 +3298,12 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r)
                        DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i);
                        return -EINVAL;
                }
+
+               if (r->modifier[i] && !(r->flags & DRM_MODE_FB_MODIFIERS)) {
+                       DRM_DEBUG_KMS("bad fb modifier %llu for plane %d\n",
+                                     r->modifier[i], i);
+                       return -EINVAL;
+               }
        }
 
        return 0;
@@ -3266,7 +3318,7 @@ internal_framebuffer_create(struct drm_device *dev,
        struct drm_framebuffer *fb;
        int ret;
 
-       if (r->flags & ~DRM_MODE_FB_INTERLACED) {
+       if (r->flags & ~(DRM_MODE_FB_INTERLACED | DRM_MODE_FB_MODIFIERS)) {
                DRM_DEBUG_KMS("bad framebuffer flags 0x%08x\n", r->flags);
                return ERR_PTR(-EINVAL);
        }
@@ -3282,6 +3334,12 @@ internal_framebuffer_create(struct drm_device *dev,
                return ERR_PTR(-EINVAL);
        }
 
+       if (r->flags & DRM_MODE_FB_MODIFIERS &&
+           !dev->mode_config.allow_fb_modifiers) {
+               DRM_DEBUG_KMS("driver does not support fb modifiers\n");
+               return ERR_PTR(-EINVAL);
+       }
+
        ret = framebuffer_check(r);
        if (ret)
                return ERR_PTR(ret);
@@ -5543,6 +5601,7 @@ struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev,
        mutex_unlock(&dev->mode_config.idr_mutex);
        return NULL;
 }
+EXPORT_SYMBOL(drm_mode_get_tile_group);
 
 /**
  * drm_mode_create_tile_group - create a tile group from a displayid description
@@ -5581,3 +5640,4 @@ struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev,
        mutex_unlock(&dev->mode_config.idr_mutex);
        return tg;
 }
+EXPORT_SYMBOL(drm_mode_create_tile_group);