aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_crtc.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2014-07-08 20:38:42 -0400
committerDave Airlie <airlied@redhat.com>2014-07-08 20:38:42 -0400
commitca5a1b9ba0fb5291b555a23b76dbe5f6c30bfd7a (patch)
tree9a012a2a610ad4e9500c8e4f0aa68ecdc23c4dba /drivers/gpu/drm/drm_crtc.c
parentc7dbc6c9ae5c3baa3be755a228a349374d043b5b (diff)
parent34882298b93e998d5fccde852b860e8fbe6c8f6b (diff)
Merge tag 'drm-intel-next-2014-06-20' of git://anongit.freedesktop.org/drm-intel into drm-next
- Accurate frontbuffer tracking and frontbuffer rendering invalidate, flush and flip events. This is prep work for proper PSR support and should also be useful for DRRS&fbc. - Runtime suspend hardware on system suspend to support the new SOix sleep states, from Jesse. - PSR updates for broadwell (Rodrigo) - Universal plane support for cursors (Matt Roper), including core drm patches. - Prefault gtt mappings (Chris) - baytrail write-enable pte bit support (Akash Goel) - mmio based flips (Sourab Gupta) instead of blitter ring flips - interrupt handling race fixes (Oscar Mateo) And old, not yet merged features from the previous round: - rps/turbo support for chv (Deepak) - some other straggling chv patches (Ville) - proper universal plane conversion for the primary plane (Matt Roper) - ppgtt on vlv from Jesse - pile of cleanups, little fixes for insane corner cases and improved debug support all over * tag 'drm-intel-next-2014-06-20' of git://anongit.freedesktop.org/drm-intel: (99 commits) drm/i915: Update DRIVER_DATE to 20140620 drivers/i915: Fix unnoticed failure of init_ring_common() drm/i915: Track frontbuffer invalidation/flushing drm/i915: Use new frontbuffer bits to increase pll clock drm/i915: don't take runtime PM reference around freeze/thaw drm/i915: use runtime irq suspend/resume in freeze/thaw drm/i915: Properly track domain of the fbcon fb drm/i915: Print obj->frontbuffer_bits in debugfs output drm/i915: Introduce accurate frontbuffer tracking drm/i915: Drop schedule_back from psr_exit drm/i915: Ditch intel_edp_psr_update drm/i915: Drop unecessary complexity from psr_inactivate drm/i915: Remove ctx->last_ring drm/i915/chv: Ack interrupts before handling them (CHV) drm/i915/bdw: Ack interrupts before handling them (GEN8) drm/i915/vlv: Ack interrupts before handling them (VLV) drm/i915: Ack interrupts before handling them (GEN5 - GEN7) drm/i915: Don't BUG_ON in i915_gem_obj_offset drm/i915: Grab dev->struct_mutex in i915_gem_pageflip_info drm/i915: Add some L3 registers to the parser whitelist ... Conflicts: drivers/gpu/drm/i915/i915_drv.c
Diffstat (limited to 'drivers/gpu/drm/drm_crtc.c')
-rw-r--r--drivers/gpu/drm/drm_crtc.c357
1 files changed, 255 insertions, 102 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index bd7422676638..c808a092d824 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -41,6 +41,10 @@
41 41
42#include "drm_crtc_internal.h" 42#include "drm_crtc_internal.h"
43 43
44static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev,
45 struct drm_mode_fb_cmd2 *r,
46 struct drm_file *file_priv);
47
44/** 48/**
45 * drm_modeset_lock_all - take all modeset locks 49 * drm_modeset_lock_all - take all modeset locks
46 * @dev: drm device 50 * @dev: drm device
@@ -723,7 +727,7 @@ DEFINE_WW_CLASS(crtc_ww_class);
723 */ 727 */
724int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, 728int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
725 struct drm_plane *primary, 729 struct drm_plane *primary,
726 void *cursor, 730 struct drm_plane *cursor,
727 const struct drm_crtc_funcs *funcs) 731 const struct drm_crtc_funcs *funcs)
728{ 732{
729 struct drm_mode_config *config = &dev->mode_config; 733 struct drm_mode_config *config = &dev->mode_config;
@@ -748,8 +752,11 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
748 config->num_crtc++; 752 config->num_crtc++;
749 753
750 crtc->primary = primary; 754 crtc->primary = primary;
755 crtc->cursor = cursor;
751 if (primary) 756 if (primary)
752 primary->possible_crtcs = 1 << drm_crtc_index(crtc); 757 primary->possible_crtcs = 1 << drm_crtc_index(crtc);
758 if (cursor)
759 cursor->possible_crtcs = 1 << drm_crtc_index(crtc);
753 760
754 out: 761 out:
755 drm_modeset_unlock_all(dev); 762 drm_modeset_unlock_all(dev);
@@ -2177,45 +2184,32 @@ out:
2177 return ret; 2184 return ret;
2178} 2185}
2179 2186
2180/** 2187/*
2181 * drm_mode_setplane - configure a plane's configuration 2188 * setplane_internal - setplane handler for internal callers
2182 * @dev: DRM device
2183 * @data: ioctl data*
2184 * @file_priv: DRM file info
2185 * 2189 *
2186 * Set plane configuration, including placement, fb, scaling, and other factors. 2190 * Note that we assume an extra reference has already been taken on fb. If the
2187 * Or pass a NULL fb to disable. 2191 * update fails, this reference will be dropped before return; if it succeeds,
2192 * the previous framebuffer (if any) will be unreferenced instead.
2188 * 2193 *
2189 * Returns: 2194 * src_{x,y,w,h} are provided in 16.16 fixed point format
2190 * Zero on success, errno on failure.
2191 */ 2195 */
2192int drm_mode_setplane(struct drm_device *dev, void *data, 2196static int setplane_internal(struct drm_plane *plane,
2193 struct drm_file *file_priv) 2197 struct drm_crtc *crtc,
2198 struct drm_framebuffer *fb,
2199 int32_t crtc_x, int32_t crtc_y,
2200 uint32_t crtc_w, uint32_t crtc_h,
2201 /* src_{x,y,w,h} values are 16.16 fixed point */
2202 uint32_t src_x, uint32_t src_y,
2203 uint32_t src_w, uint32_t src_h)
2194{ 2204{
2195 struct drm_mode_set_plane *plane_req = data; 2205 struct drm_device *dev = plane->dev;
2196 struct drm_plane *plane; 2206 struct drm_framebuffer *old_fb = NULL;
2197 struct drm_crtc *crtc;
2198 struct drm_framebuffer *fb = NULL, *old_fb = NULL;
2199 int ret = 0; 2207 int ret = 0;
2200 unsigned int fb_width, fb_height; 2208 unsigned int fb_width, fb_height;
2201 int i; 2209 int i;
2202 2210
2203 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2204 return -EINVAL;
2205
2206 /*
2207 * First, find the plane, crtc, and fb objects. If not available,
2208 * we don't bother to call the driver.
2209 */
2210 plane = drm_plane_find(dev, plane_req->plane_id);
2211 if (!plane) {
2212 DRM_DEBUG_KMS("Unknown plane ID %d\n",
2213 plane_req->plane_id);
2214 return -ENOENT;
2215 }
2216
2217 /* No fb means shut it down */ 2211 /* No fb means shut it down */
2218 if (!plane_req->fb_id) { 2212 if (!fb) {
2219 drm_modeset_lock_all(dev); 2213 drm_modeset_lock_all(dev);
2220 old_fb = plane->fb; 2214 old_fb = plane->fb;
2221 ret = plane->funcs->disable_plane(plane); 2215 ret = plane->funcs->disable_plane(plane);
@@ -2229,14 +2223,6 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
2229 goto out; 2223 goto out;
2230 } 2224 }
2231 2225
2232 crtc = drm_crtc_find(dev, plane_req->crtc_id);
2233 if (!crtc) {
2234 DRM_DEBUG_KMS("Unknown crtc ID %d\n",
2235 plane_req->crtc_id);
2236 ret = -ENOENT;
2237 goto out;
2238 }
2239
2240 /* Check whether this plane is usable on this CRTC */ 2226 /* Check whether this plane is usable on this CRTC */
2241 if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) { 2227 if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) {
2242 DRM_DEBUG_KMS("Invalid crtc for plane\n"); 2228 DRM_DEBUG_KMS("Invalid crtc for plane\n");
@@ -2244,14 +2230,6 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
2244 goto out; 2230 goto out;
2245 } 2231 }
2246 2232
2247 fb = drm_framebuffer_lookup(dev, plane_req->fb_id);
2248 if (!fb) {
2249 DRM_DEBUG_KMS("Unknown framebuffer ID %d\n",
2250 plane_req->fb_id);
2251 ret = -ENOENT;
2252 goto out;
2253 }
2254
2255 /* Check whether this plane supports the fb pixel format. */ 2233 /* Check whether this plane supports the fb pixel format. */
2256 for (i = 0; i < plane->format_count; i++) 2234 for (i = 0; i < plane->format_count; i++)
2257 if (fb->pixel_format == plane->format_types[i]) 2235 if (fb->pixel_format == plane->format_types[i])
@@ -2267,43 +2245,25 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
2267 fb_height = fb->height << 16; 2245 fb_height = fb->height << 16;
2268 2246
2269 /* Make sure source coordinates are inside the fb. */ 2247 /* Make sure source coordinates are inside the fb. */
2270 if (plane_req->src_w > fb_width || 2248 if (src_w > fb_width ||
2271 plane_req->src_x > fb_width - plane_req->src_w || 2249 src_x > fb_width - src_w ||
2272 plane_req->src_h > fb_height || 2250 src_h > fb_height ||
2273 plane_req->src_y > fb_height - plane_req->src_h) { 2251 src_y > fb_height - src_h) {
2274 DRM_DEBUG_KMS("Invalid source coordinates " 2252 DRM_DEBUG_KMS("Invalid source coordinates "
2275 "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n", 2253 "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n",
2276 plane_req->src_w >> 16, 2254 src_w >> 16, ((src_w & 0xffff) * 15625) >> 10,
2277 ((plane_req->src_w & 0xffff) * 15625) >> 10, 2255 src_h >> 16, ((src_h & 0xffff) * 15625) >> 10,
2278 plane_req->src_h >> 16, 2256 src_x >> 16, ((src_x & 0xffff) * 15625) >> 10,
2279 ((plane_req->src_h & 0xffff) * 15625) >> 10, 2257 src_y >> 16, ((src_y & 0xffff) * 15625) >> 10);
2280 plane_req->src_x >> 16,
2281 ((plane_req->src_x & 0xffff) * 15625) >> 10,
2282 plane_req->src_y >> 16,
2283 ((plane_req->src_y & 0xffff) * 15625) >> 10);
2284 ret = -ENOSPC; 2258 ret = -ENOSPC;
2285 goto out; 2259 goto out;
2286 } 2260 }
2287 2261
2288 /* Give drivers some help against integer overflows */
2289 if (plane_req->crtc_w > INT_MAX ||
2290 plane_req->crtc_x > INT_MAX - (int32_t) plane_req->crtc_w ||
2291 plane_req->crtc_h > INT_MAX ||
2292 plane_req->crtc_y > INT_MAX - (int32_t) plane_req->crtc_h) {
2293 DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
2294 plane_req->crtc_w, plane_req->crtc_h,
2295 plane_req->crtc_x, plane_req->crtc_y);
2296 ret = -ERANGE;
2297 goto out;
2298 }
2299
2300 drm_modeset_lock_all(dev); 2262 drm_modeset_lock_all(dev);
2301 old_fb = plane->fb; 2263 old_fb = plane->fb;
2302 ret = plane->funcs->update_plane(plane, crtc, fb, 2264 ret = plane->funcs->update_plane(plane, crtc, fb,
2303 plane_req->crtc_x, plane_req->crtc_y, 2265 crtc_x, crtc_y, crtc_w, crtc_h,
2304 plane_req->crtc_w, plane_req->crtc_h, 2266 src_x, src_y, src_w, src_h);
2305 plane_req->src_x, plane_req->src_y,
2306 plane_req->src_w, plane_req->src_h);
2307 if (!ret) { 2267 if (!ret) {
2308 plane->crtc = crtc; 2268 plane->crtc = crtc;
2309 plane->fb = fb; 2269 plane->fb = fb;
@@ -2320,6 +2280,85 @@ out:
2320 drm_framebuffer_unreference(old_fb); 2280 drm_framebuffer_unreference(old_fb);
2321 2281
2322 return ret; 2282 return ret;
2283
2284}
2285
2286/**
2287 * drm_mode_setplane - configure a plane's configuration
2288 * @dev: DRM device
2289 * @data: ioctl data*
2290 * @file_priv: DRM file info
2291 *
2292 * Set plane configuration, including placement, fb, scaling, and other factors.
2293 * Or pass a NULL fb to disable (planes may be disabled without providing a
2294 * valid crtc).
2295 *
2296 * Returns:
2297 * Zero on success, errno on failure.
2298 */
2299int drm_mode_setplane(struct drm_device *dev, void *data,
2300 struct drm_file *file_priv)
2301{
2302 struct drm_mode_set_plane *plane_req = data;
2303 struct drm_mode_object *obj;
2304 struct drm_plane *plane;
2305 struct drm_crtc *crtc = NULL;
2306 struct drm_framebuffer *fb = NULL;
2307
2308 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2309 return -EINVAL;
2310
2311 /* Give drivers some help against integer overflows */
2312 if (plane_req->crtc_w > INT_MAX ||
2313 plane_req->crtc_x > INT_MAX - (int32_t) plane_req->crtc_w ||
2314 plane_req->crtc_h > INT_MAX ||
2315 plane_req->crtc_y > INT_MAX - (int32_t) plane_req->crtc_h) {
2316 DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
2317 plane_req->crtc_w, plane_req->crtc_h,
2318 plane_req->crtc_x, plane_req->crtc_y);
2319 return -ERANGE;
2320 }
2321
2322 /*
2323 * First, find the plane, crtc, and fb objects. If not available,
2324 * we don't bother to call the driver.
2325 */
2326 obj = drm_mode_object_find(dev, plane_req->plane_id,
2327 DRM_MODE_OBJECT_PLANE);
2328 if (!obj) {
2329 DRM_DEBUG_KMS("Unknown plane ID %d\n",
2330 plane_req->plane_id);
2331 return -ENOENT;
2332 }
2333 plane = obj_to_plane(obj);
2334
2335 if (plane_req->fb_id) {
2336 fb = drm_framebuffer_lookup(dev, plane_req->fb_id);
2337 if (!fb) {
2338 DRM_DEBUG_KMS("Unknown framebuffer ID %d\n",
2339 plane_req->fb_id);
2340 return -ENOENT;
2341 }
2342
2343 obj = drm_mode_object_find(dev, plane_req->crtc_id,
2344 DRM_MODE_OBJECT_CRTC);
2345 if (!obj) {
2346 DRM_DEBUG_KMS("Unknown crtc ID %d\n",
2347 plane_req->crtc_id);
2348 return -ENOENT;
2349 }
2350 crtc = obj_to_crtc(obj);
2351 }
2352
2353 /*
2354 * setplane_internal will take care of deref'ing either the old or new
2355 * framebuffer depending on success.
2356 */
2357 return setplane_internal(plane, crtc, fb,
2358 plane_req->crtc_x, plane_req->crtc_y,
2359 plane_req->crtc_w, plane_req->crtc_h,
2360 plane_req->src_x, plane_req->src_y,
2361 plane_req->src_w, plane_req->src_h);
2323} 2362}
2324 2363
2325/** 2364/**
@@ -2568,6 +2607,102 @@ out:
2568 return ret; 2607 return ret;
2569} 2608}
2570 2609
2610/**
2611 * drm_mode_cursor_universal - translate legacy cursor ioctl call into a
2612 * universal plane handler call
2613 * @crtc: crtc to update cursor for
2614 * @req: data pointer for the ioctl
2615 * @file_priv: drm file for the ioctl call
2616 *
2617 * Legacy cursor ioctl's work directly with driver buffer handles. To
2618 * translate legacy ioctl calls into universal plane handler calls, we need to
2619 * wrap the native buffer handle in a drm_framebuffer.
2620 *
2621 * Note that we assume any handle passed to the legacy ioctls was a 32-bit ARGB
2622 * buffer with a pitch of 4*width; the universal plane interface should be used
2623 * directly in cases where the hardware can support other buffer settings and
2624 * userspace wants to make use of these capabilities.
2625 *
2626 * Returns:
2627 * Zero on success, errno on failure.
2628 */
2629static int drm_mode_cursor_universal(struct drm_crtc *crtc,
2630 struct drm_mode_cursor2 *req,
2631 struct drm_file *file_priv)
2632{
2633 struct drm_device *dev = crtc->dev;
2634 struct drm_framebuffer *fb = NULL;
2635 struct drm_mode_fb_cmd2 fbreq = {
2636 .width = req->width,
2637 .height = req->height,
2638 .pixel_format = DRM_FORMAT_ARGB8888,
2639 .pitches = { req->width * 4 },
2640 .handles = { req->handle },
2641 };
2642 int32_t crtc_x, crtc_y;
2643 uint32_t crtc_w = 0, crtc_h = 0;
2644 uint32_t src_w = 0, src_h = 0;
2645 int ret = 0;
2646
2647 BUG_ON(!crtc->cursor);
2648
2649 /*
2650 * Obtain fb we'll be using (either new or existing) and take an extra
2651 * reference to it if fb != null. setplane will take care of dropping
2652 * the reference if the plane update fails.
2653 */
2654 if (req->flags & DRM_MODE_CURSOR_BO) {
2655 if (req->handle) {
2656 fb = add_framebuffer_internal(dev, &fbreq, file_priv);
2657 if (IS_ERR(fb)) {
2658 DRM_DEBUG_KMS("failed to wrap cursor buffer in drm framebuffer\n");
2659 return PTR_ERR(fb);
2660 }
2661
2662 drm_framebuffer_reference(fb);
2663 } else {
2664 fb = NULL;
2665 }
2666 } else {
2667 mutex_lock(&dev->mode_config.mutex);
2668 fb = crtc->cursor->fb;
2669 if (fb)
2670 drm_framebuffer_reference(fb);
2671 mutex_unlock(&dev->mode_config.mutex);
2672 }
2673
2674 if (req->flags & DRM_MODE_CURSOR_MOVE) {
2675 crtc_x = req->x;
2676 crtc_y = req->y;
2677 } else {
2678 crtc_x = crtc->cursor_x;
2679 crtc_y = crtc->cursor_y;
2680 }
2681
2682 if (fb) {
2683 crtc_w = fb->width;
2684 crtc_h = fb->height;
2685 src_w = fb->width << 16;
2686 src_h = fb->height << 16;
2687 }
2688
2689 /*
2690 * setplane_internal will take care of deref'ing either the old or new
2691 * framebuffer depending on success.
2692 */
2693 ret = setplane_internal(crtc->cursor, crtc, fb,
2694 crtc_x, crtc_y, crtc_w, crtc_h,
2695 0, 0, src_w, src_h);
2696
2697 /* Update successful; save new cursor position, if necessary */
2698 if (ret == 0 && req->flags & DRM_MODE_CURSOR_MOVE) {
2699 crtc->cursor_x = req->x;
2700 crtc->cursor_y = req->y;
2701 }
2702
2703 return ret;
2704}
2705
2571static int drm_mode_cursor_common(struct drm_device *dev, 2706static int drm_mode_cursor_common(struct drm_device *dev,
2572 struct drm_mode_cursor2 *req, 2707 struct drm_mode_cursor2 *req,
2573 struct drm_file *file_priv) 2708 struct drm_file *file_priv)
@@ -2587,6 +2722,13 @@ static int drm_mode_cursor_common(struct drm_device *dev,
2587 return -ENOENT; 2722 return -ENOENT;
2588 } 2723 }
2589 2724
2725 /*
2726 * If this crtc has a universal cursor plane, call that plane's update
2727 * handler rather than using legacy cursor handlers.
2728 */
2729 if (crtc->cursor)
2730 return drm_mode_cursor_universal(crtc, req, file_priv);
2731
2590 drm_modeset_lock(&crtc->mutex, NULL); 2732 drm_modeset_lock(&crtc->mutex, NULL);
2591 if (req->flags & DRM_MODE_CURSOR_BO) { 2733 if (req->flags & DRM_MODE_CURSOR_BO) {
2592 if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) { 2734 if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) {
@@ -2886,56 +3028,38 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r)
2886 return 0; 3028 return 0;
2887} 3029}
2888 3030
2889/** 3031static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev,
2890 * drm_mode_addfb2 - add an FB to the graphics configuration 3032 struct drm_mode_fb_cmd2 *r,
2891 * @dev: drm device for the ioctl 3033 struct drm_file *file_priv)
2892 * @data: data pointer for the ioctl
2893 * @file_priv: drm file for the ioctl call
2894 *
2895 * Add a new FB to the specified CRTC, given a user request with format. This is
2896 * the 2nd version of the addfb ioctl, which supports multi-planar framebuffers
2897 * and uses fourcc codes as pixel format specifiers.
2898 *
2899 * Called by the user via ioctl.
2900 *
2901 * Returns:
2902 * Zero on success, errno on failure.
2903 */
2904int drm_mode_addfb2(struct drm_device *dev,
2905 void *data, struct drm_file *file_priv)
2906{ 3034{
2907 struct drm_mode_fb_cmd2 *r = data;
2908 struct drm_mode_config *config = &dev->mode_config; 3035 struct drm_mode_config *config = &dev->mode_config;
2909 struct drm_framebuffer *fb; 3036 struct drm_framebuffer *fb;
2910 int ret; 3037 int ret;
2911 3038
2912 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2913 return -EINVAL;
2914
2915 if (r->flags & ~DRM_MODE_FB_INTERLACED) { 3039 if (r->flags & ~DRM_MODE_FB_INTERLACED) {
2916 DRM_DEBUG_KMS("bad framebuffer flags 0x%08x\n", r->flags); 3040 DRM_DEBUG_KMS("bad framebuffer flags 0x%08x\n", r->flags);
2917 return -EINVAL; 3041 return ERR_PTR(-EINVAL);
2918 } 3042 }
2919 3043
2920 if ((config->min_width > r->width) || (r->width > config->max_width)) { 3044 if ((config->min_width > r->width) || (r->width > config->max_width)) {
2921 DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n", 3045 DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",
2922 r->width, config->min_width, config->max_width); 3046 r->width, config->min_width, config->max_width);
2923 return -EINVAL; 3047 return ERR_PTR(-EINVAL);
2924 } 3048 }
2925 if ((config->min_height > r->height) || (r->height > config->max_height)) { 3049 if ((config->min_height > r->height) || (r->height > config->max_height)) {
2926 DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n", 3050 DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n",
2927 r->height, config->min_height, config->max_height); 3051 r->height, config->min_height, config->max_height);
2928 return -EINVAL; 3052 return ERR_PTR(-EINVAL);
2929 } 3053 }
2930 3054
2931 ret = framebuffer_check(r); 3055 ret = framebuffer_check(r);
2932 if (ret) 3056 if (ret)
2933 return ret; 3057 return ERR_PTR(ret);
2934 3058
2935 fb = dev->mode_config.funcs->fb_create(dev, file_priv, r); 3059 fb = dev->mode_config.funcs->fb_create(dev, file_priv, r);
2936 if (IS_ERR(fb)) { 3060 if (IS_ERR(fb)) {
2937 DRM_DEBUG_KMS("could not create framebuffer\n"); 3061 DRM_DEBUG_KMS("could not create framebuffer\n");
2938 return PTR_ERR(fb); 3062 return fb;
2939 } 3063 }
2940 3064
2941 mutex_lock(&file_priv->fbs_lock); 3065 mutex_lock(&file_priv->fbs_lock);
@@ -2944,8 +3068,37 @@ int drm_mode_addfb2(struct drm_device *dev,
2944 DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id); 3068 DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
2945 mutex_unlock(&file_priv->fbs_lock); 3069 mutex_unlock(&file_priv->fbs_lock);
2946 3070
3071 return fb;
3072}
2947 3073
2948 return ret; 3074/**
3075 * drm_mode_addfb2 - add an FB to the graphics configuration
3076 * @dev: drm device for the ioctl
3077 * @data: data pointer for the ioctl
3078 * @file_priv: drm file for the ioctl call
3079 *
3080 * Add a new FB to the specified CRTC, given a user request with format. This is
3081 * the 2nd version of the addfb ioctl, which supports multi-planar framebuffers
3082 * and uses fourcc codes as pixel format specifiers.
3083 *
3084 * Called by the user via ioctl.
3085 *
3086 * Returns:
3087 * Zero on success, errno on failure.
3088 */
3089int drm_mode_addfb2(struct drm_device *dev,
3090 void *data, struct drm_file *file_priv)
3091{
3092 struct drm_framebuffer *fb;
3093
3094 if (!drm_core_check_feature(dev, DRIVER_MODESET))
3095 return -EINVAL;
3096
3097 fb = add_framebuffer_internal(dev, data, file_priv);
3098 if (IS_ERR(fb))
3099 return PTR_ERR(fb);
3100
3101 return 0;
2949} 3102}
2950 3103
2951/** 3104/**