Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * drm gem framebuffer helper functions
0004  *
0005  * Copyright (C) 2017 Noralf Trønnes
0006  */
0007 
0008 #include <linux/slab.h>
0009 #include <linux/module.h>
0010 
0011 #include <drm/drm_damage_helper.h>
0012 #include <drm/drm_fb_helper.h>
0013 #include <drm/drm_fourcc.h>
0014 #include <drm/drm_framebuffer.h>
0015 #include <drm/drm_gem.h>
0016 #include <drm/drm_gem_framebuffer_helper.h>
0017 #include <drm/drm_modeset_helper.h>
0018 
0019 #include "drm_internal.h"
0020 
0021 MODULE_IMPORT_NS(DMA_BUF);
0022 
0023 #define AFBC_HEADER_SIZE        16
0024 #define AFBC_TH_LAYOUT_ALIGNMENT    8
0025 #define AFBC_HDR_ALIGN          64
0026 #define AFBC_SUPERBLOCK_PIXELS      256
0027 #define AFBC_SUPERBLOCK_ALIGNMENT   128
0028 #define AFBC_TH_BODY_START_ALIGNMENT    4096
0029 
0030 /**
0031  * DOC: overview
0032  *
0033  * This library provides helpers for drivers that don't subclass
0034  * &drm_framebuffer and use &drm_gem_object for their backing storage.
0035  *
0036  * Drivers without additional needs to validate framebuffers can simply use
0037  * drm_gem_fb_create() and everything is wired up automatically. Other drivers
0038  * can use all parts independently.
0039  */
0040 
0041 /**
0042  * drm_gem_fb_get_obj() - Get GEM object backing the framebuffer
0043  * @fb: Framebuffer
0044  * @plane: Plane index
0045  *
0046  * No additional reference is taken beyond the one that the &drm_frambuffer
0047  * already holds.
0048  *
0049  * Returns:
0050  * Pointer to &drm_gem_object for the given framebuffer and plane index or NULL
0051  * if it does not exist.
0052  */
0053 struct drm_gem_object *drm_gem_fb_get_obj(struct drm_framebuffer *fb,
0054                       unsigned int plane)
0055 {
0056     struct drm_device *dev = fb->dev;
0057 
0058     if (drm_WARN_ON_ONCE(dev, plane >= ARRAY_SIZE(fb->obj)))
0059         return NULL;
0060     else if (drm_WARN_ON_ONCE(dev, !fb->obj[plane]))
0061         return NULL;
0062 
0063     return fb->obj[plane];
0064 }
0065 EXPORT_SYMBOL_GPL(drm_gem_fb_get_obj);
0066 
0067 static int
0068 drm_gem_fb_init(struct drm_device *dev,
0069          struct drm_framebuffer *fb,
0070          const struct drm_mode_fb_cmd2 *mode_cmd,
0071          struct drm_gem_object **obj, unsigned int num_planes,
0072          const struct drm_framebuffer_funcs *funcs)
0073 {
0074     unsigned int i;
0075     int ret;
0076 
0077     drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd);
0078 
0079     for (i = 0; i < num_planes; i++)
0080         fb->obj[i] = obj[i];
0081 
0082     ret = drm_framebuffer_init(dev, fb, funcs);
0083     if (ret)
0084         drm_err(dev, "Failed to init framebuffer: %d\n", ret);
0085 
0086     return ret;
0087 }
0088 
0089 /**
0090  * drm_gem_fb_destroy - Free GEM backed framebuffer
0091  * @fb: Framebuffer
0092  *
0093  * Frees a GEM backed framebuffer with its backing buffer(s) and the structure
0094  * itself. Drivers can use this as their &drm_framebuffer_funcs->destroy
0095  * callback.
0096  */
0097 void drm_gem_fb_destroy(struct drm_framebuffer *fb)
0098 {
0099     unsigned int i;
0100 
0101     for (i = 0; i < fb->format->num_planes; i++)
0102         drm_gem_object_put(fb->obj[i]);
0103 
0104     drm_framebuffer_cleanup(fb);
0105     kfree(fb);
0106 }
0107 EXPORT_SYMBOL(drm_gem_fb_destroy);
0108 
0109 /**
0110  * drm_gem_fb_create_handle - Create handle for GEM backed framebuffer
0111  * @fb: Framebuffer
0112  * @file: DRM file to register the handle for
0113  * @handle: Pointer to return the created handle
0114  *
0115  * This function creates a handle for the GEM object backing the framebuffer.
0116  * Drivers can use this as their &drm_framebuffer_funcs->create_handle
0117  * callback. The GETFB IOCTL calls into this callback.
0118  *
0119  * Returns:
0120  * 0 on success or a negative error code on failure.
0121  */
0122 int drm_gem_fb_create_handle(struct drm_framebuffer *fb, struct drm_file *file,
0123                  unsigned int *handle)
0124 {
0125     return drm_gem_handle_create(file, fb->obj[0], handle);
0126 }
0127 EXPORT_SYMBOL(drm_gem_fb_create_handle);
0128 
0129 /**
0130  * drm_gem_fb_init_with_funcs() - Helper function for implementing
0131  *                &drm_mode_config_funcs.fb_create
0132  *                callback in cases when the driver
0133  *                allocates a subclass of
0134  *                struct drm_framebuffer
0135  * @dev: DRM device
0136  * @fb: framebuffer object
0137  * @file: DRM file that holds the GEM handle(s) backing the framebuffer
0138  * @mode_cmd: Metadata from the userspace framebuffer creation request
0139  * @funcs: vtable to be used for the new framebuffer object
0140  *
0141  * This function can be used to set &drm_framebuffer_funcs for drivers that need
0142  * custom framebuffer callbacks. Use drm_gem_fb_create() if you don't need to
0143  * change &drm_framebuffer_funcs. The function does buffer size validation.
0144  * The buffer size validation is for a general case, though, so users should
0145  * pay attention to the checks being appropriate for them or, at least,
0146  * non-conflicting.
0147  *
0148  * Returns:
0149  * Zero or a negative error code.
0150  */
0151 int drm_gem_fb_init_with_funcs(struct drm_device *dev,
0152                    struct drm_framebuffer *fb,
0153                    struct drm_file *file,
0154                    const struct drm_mode_fb_cmd2 *mode_cmd,
0155                    const struct drm_framebuffer_funcs *funcs)
0156 {
0157     const struct drm_format_info *info;
0158     struct drm_gem_object *objs[DRM_FORMAT_MAX_PLANES];
0159     unsigned int i;
0160     int ret;
0161 
0162     info = drm_get_format_info(dev, mode_cmd);
0163     if (!info) {
0164         drm_dbg_kms(dev, "Failed to get FB format info\n");
0165         return -EINVAL;
0166     }
0167 
0168     for (i = 0; i < info->num_planes; i++) {
0169         unsigned int width = mode_cmd->width / (i ? info->hsub : 1);
0170         unsigned int height = mode_cmd->height / (i ? info->vsub : 1);
0171         unsigned int min_size;
0172 
0173         objs[i] = drm_gem_object_lookup(file, mode_cmd->handles[i]);
0174         if (!objs[i]) {
0175             drm_dbg_kms(dev, "Failed to lookup GEM object\n");
0176             ret = -ENOENT;
0177             goto err_gem_object_put;
0178         }
0179 
0180         min_size = (height - 1) * mode_cmd->pitches[i]
0181              + drm_format_info_min_pitch(info, i, width)
0182              + mode_cmd->offsets[i];
0183 
0184         if (objs[i]->size < min_size) {
0185             drm_dbg_kms(dev,
0186                     "GEM object size (%zu) smaller than minimum size (%u) for plane %d\n",
0187                     objs[i]->size, min_size, i);
0188             drm_gem_object_put(objs[i]);
0189             ret = -EINVAL;
0190             goto err_gem_object_put;
0191         }
0192     }
0193 
0194     ret = drm_gem_fb_init(dev, fb, mode_cmd, objs, i, funcs);
0195     if (ret)
0196         goto err_gem_object_put;
0197 
0198     return 0;
0199 
0200 err_gem_object_put:
0201     while (i > 0) {
0202         --i;
0203         drm_gem_object_put(objs[i]);
0204     }
0205     return ret;
0206 }
0207 EXPORT_SYMBOL_GPL(drm_gem_fb_init_with_funcs);
0208 
0209 /**
0210  * drm_gem_fb_create_with_funcs() - Helper function for the
0211  *                                  &drm_mode_config_funcs.fb_create
0212  *                                  callback
0213  * @dev: DRM device
0214  * @file: DRM file that holds the GEM handle(s) backing the framebuffer
0215  * @mode_cmd: Metadata from the userspace framebuffer creation request
0216  * @funcs: vtable to be used for the new framebuffer object
0217  *
0218  * This function can be used to set &drm_framebuffer_funcs for drivers that need
0219  * custom framebuffer callbacks. Use drm_gem_fb_create() if you don't need to
0220  * change &drm_framebuffer_funcs. The function does buffer size validation.
0221  *
0222  * Returns:
0223  * Pointer to a &drm_framebuffer on success or an error pointer on failure.
0224  */
0225 struct drm_framebuffer *
0226 drm_gem_fb_create_with_funcs(struct drm_device *dev, struct drm_file *file,
0227                  const struct drm_mode_fb_cmd2 *mode_cmd,
0228                  const struct drm_framebuffer_funcs *funcs)
0229 {
0230     struct drm_framebuffer *fb;
0231     int ret;
0232 
0233     fb = kzalloc(sizeof(*fb), GFP_KERNEL);
0234     if (!fb)
0235         return ERR_PTR(-ENOMEM);
0236 
0237     ret = drm_gem_fb_init_with_funcs(dev, fb, file, mode_cmd, funcs);
0238     if (ret) {
0239         kfree(fb);
0240         return ERR_PTR(ret);
0241     }
0242 
0243     return fb;
0244 }
0245 EXPORT_SYMBOL_GPL(drm_gem_fb_create_with_funcs);
0246 
0247 static const struct drm_framebuffer_funcs drm_gem_fb_funcs = {
0248     .destroy    = drm_gem_fb_destroy,
0249     .create_handle  = drm_gem_fb_create_handle,
0250 };
0251 
0252 /**
0253  * drm_gem_fb_create() - Helper function for the
0254  *                       &drm_mode_config_funcs.fb_create callback
0255  * @dev: DRM device
0256  * @file: DRM file that holds the GEM handle(s) backing the framebuffer
0257  * @mode_cmd: Metadata from the userspace framebuffer creation request
0258  *
0259  * This function creates a new framebuffer object described by
0260  * &drm_mode_fb_cmd2. This description includes handles for the buffer(s)
0261  * backing the framebuffer.
0262  *
0263  * If your hardware has special alignment or pitch requirements these should be
0264  * checked before calling this function. The function does buffer size
0265  * validation. Use drm_gem_fb_create_with_dirty() if you need framebuffer
0266  * flushing.
0267  *
0268  * Drivers can use this as their &drm_mode_config_funcs.fb_create callback.
0269  * The ADDFB2 IOCTL calls into this callback.
0270  *
0271  * Returns:
0272  * Pointer to a &drm_framebuffer on success or an error pointer on failure.
0273  */
0274 struct drm_framebuffer *
0275 drm_gem_fb_create(struct drm_device *dev, struct drm_file *file,
0276           const struct drm_mode_fb_cmd2 *mode_cmd)
0277 {
0278     return drm_gem_fb_create_with_funcs(dev, file, mode_cmd,
0279                         &drm_gem_fb_funcs);
0280 }
0281 EXPORT_SYMBOL_GPL(drm_gem_fb_create);
0282 
0283 static const struct drm_framebuffer_funcs drm_gem_fb_funcs_dirtyfb = {
0284     .destroy    = drm_gem_fb_destroy,
0285     .create_handle  = drm_gem_fb_create_handle,
0286     .dirty      = drm_atomic_helper_dirtyfb,
0287 };
0288 
0289 /**
0290  * drm_gem_fb_create_with_dirty() - Helper function for the
0291  *                       &drm_mode_config_funcs.fb_create callback
0292  * @dev: DRM device
0293  * @file: DRM file that holds the GEM handle(s) backing the framebuffer
0294  * @mode_cmd: Metadata from the userspace framebuffer creation request
0295  *
0296  * This function creates a new framebuffer object described by
0297  * &drm_mode_fb_cmd2. This description includes handles for the buffer(s)
0298  * backing the framebuffer. drm_atomic_helper_dirtyfb() is used for the dirty
0299  * callback giving framebuffer flushing through the atomic machinery. Use
0300  * drm_gem_fb_create() if you don't need the dirty callback.
0301  * The function does buffer size validation.
0302  *
0303  * Drivers should also call drm_plane_enable_fb_damage_clips() on all planes
0304  * to enable userspace to use damage clips also with the ATOMIC IOCTL.
0305  *
0306  * Drivers can use this as their &drm_mode_config_funcs.fb_create callback.
0307  * The ADDFB2 IOCTL calls into this callback.
0308  *
0309  * Returns:
0310  * Pointer to a &drm_framebuffer on success or an error pointer on failure.
0311  */
0312 struct drm_framebuffer *
0313 drm_gem_fb_create_with_dirty(struct drm_device *dev, struct drm_file *file,
0314                  const struct drm_mode_fb_cmd2 *mode_cmd)
0315 {
0316     return drm_gem_fb_create_with_funcs(dev, file, mode_cmd,
0317                         &drm_gem_fb_funcs_dirtyfb);
0318 }
0319 EXPORT_SYMBOL_GPL(drm_gem_fb_create_with_dirty);
0320 
0321 /**
0322  * drm_gem_fb_vmap - maps all framebuffer BOs into kernel address space
0323  * @fb: the framebuffer
0324  * @map: returns the mapping's address for each BO
0325  * @data: returns the data address for each BO, can be NULL
0326  *
0327  * This function maps all buffer objects of the given framebuffer into
0328  * kernel address space and stores them in struct iosys_map. If the
0329  * mapping operation fails for one of the BOs, the function unmaps the
0330  * already established mappings automatically.
0331  *
0332  * Callers that want to access a BO's stored data should pass @data.
0333  * The argument returns the addresses of the data stored in each BO. This
0334  * is different from @map if the framebuffer's offsets field is non-zero.
0335  *
0336  * Both, @map and @data, must each refer to arrays with at least
0337  * fb->format->num_planes elements.
0338  *
0339  * See drm_gem_fb_vunmap() for unmapping.
0340  *
0341  * Returns:
0342  * 0 on success, or a negative errno code otherwise.
0343  */
0344 int drm_gem_fb_vmap(struct drm_framebuffer *fb, struct iosys_map *map,
0345             struct iosys_map *data)
0346 {
0347     struct drm_gem_object *obj;
0348     unsigned int i;
0349     int ret;
0350 
0351     for (i = 0; i < fb->format->num_planes; ++i) {
0352         obj = drm_gem_fb_get_obj(fb, i);
0353         if (!obj) {
0354             ret = -EINVAL;
0355             goto err_drm_gem_vunmap;
0356         }
0357         ret = drm_gem_vmap(obj, &map[i]);
0358         if (ret)
0359             goto err_drm_gem_vunmap;
0360     }
0361 
0362     if (data) {
0363         for (i = 0; i < fb->format->num_planes; ++i) {
0364             memcpy(&data[i], &map[i], sizeof(data[i]));
0365             if (iosys_map_is_null(&data[i]))
0366                 continue;
0367             iosys_map_incr(&data[i], fb->offsets[i]);
0368         }
0369     }
0370 
0371     return 0;
0372 
0373 err_drm_gem_vunmap:
0374     while (i) {
0375         --i;
0376         obj = drm_gem_fb_get_obj(fb, i);
0377         if (!obj)
0378             continue;
0379         drm_gem_vunmap(obj, &map[i]);
0380     }
0381     return ret;
0382 }
0383 EXPORT_SYMBOL(drm_gem_fb_vmap);
0384 
0385 /**
0386  * drm_gem_fb_vunmap - unmaps framebuffer BOs from kernel address space
0387  * @fb: the framebuffer
0388  * @map: mapping addresses as returned by drm_gem_fb_vmap()
0389  *
0390  * This function unmaps all buffer objects of the given framebuffer.
0391  *
0392  * See drm_gem_fb_vmap() for more information.
0393  */
0394 void drm_gem_fb_vunmap(struct drm_framebuffer *fb, struct iosys_map *map)
0395 {
0396     unsigned int i = fb->format->num_planes;
0397     struct drm_gem_object *obj;
0398 
0399     while (i) {
0400         --i;
0401         obj = drm_gem_fb_get_obj(fb, i);
0402         if (!obj)
0403             continue;
0404         if (iosys_map_is_null(&map[i]))
0405             continue;
0406         drm_gem_vunmap(obj, &map[i]);
0407     }
0408 }
0409 EXPORT_SYMBOL(drm_gem_fb_vunmap);
0410 
0411 static void __drm_gem_fb_end_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir,
0412                     unsigned int num_planes)
0413 {
0414     struct dma_buf_attachment *import_attach;
0415     struct drm_gem_object *obj;
0416     int ret;
0417 
0418     while (num_planes) {
0419         --num_planes;
0420         obj = drm_gem_fb_get_obj(fb, num_planes);
0421         if (!obj)
0422             continue;
0423         import_attach = obj->import_attach;
0424         if (!import_attach)
0425             continue;
0426         ret = dma_buf_end_cpu_access(import_attach->dmabuf, dir);
0427         if (ret)
0428             drm_err(fb->dev, "dma_buf_end_cpu_access(%u, %d) failed: %d\n",
0429                 ret, num_planes, dir);
0430     }
0431 }
0432 
0433 /**
0434  * drm_gem_fb_begin_cpu_access - prepares GEM buffer objects for CPU access
0435  * @fb: the framebuffer
0436  * @dir: access mode
0437  *
0438  * Prepares a framebuffer's GEM buffer objects for CPU access. This function
0439  * must be called before accessing the BO data within the kernel. For imported
0440  * BOs, the function calls dma_buf_begin_cpu_access().
0441  *
0442  * See drm_gem_fb_end_cpu_access() for signalling the end of CPU access.
0443  *
0444  * Returns:
0445  * 0 on success, or a negative errno code otherwise.
0446  */
0447 int drm_gem_fb_begin_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir)
0448 {
0449     struct dma_buf_attachment *import_attach;
0450     struct drm_gem_object *obj;
0451     unsigned int i;
0452     int ret;
0453 
0454     for (i = 0; i < fb->format->num_planes; ++i) {
0455         obj = drm_gem_fb_get_obj(fb, i);
0456         if (!obj) {
0457             ret = -EINVAL;
0458             goto err___drm_gem_fb_end_cpu_access;
0459         }
0460         import_attach = obj->import_attach;
0461         if (!import_attach)
0462             continue;
0463         ret = dma_buf_begin_cpu_access(import_attach->dmabuf, dir);
0464         if (ret)
0465             goto err___drm_gem_fb_end_cpu_access;
0466     }
0467 
0468     return 0;
0469 
0470 err___drm_gem_fb_end_cpu_access:
0471     __drm_gem_fb_end_cpu_access(fb, dir, i);
0472     return ret;
0473 }
0474 EXPORT_SYMBOL(drm_gem_fb_begin_cpu_access);
0475 
0476 /**
0477  * drm_gem_fb_end_cpu_access - signals end of CPU access to GEM buffer objects
0478  * @fb: the framebuffer
0479  * @dir: access mode
0480  *
0481  * Signals the end of CPU access to the given framebuffer's GEM buffer objects. This
0482  * function must be paired with a corresponding call to drm_gem_fb_begin_cpu_access().
0483  * For imported BOs, the function calls dma_buf_end_cpu_access().
0484  *
0485  * See also drm_gem_fb_begin_cpu_access().
0486  */
0487 void drm_gem_fb_end_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir)
0488 {
0489     __drm_gem_fb_end_cpu_access(fb, dir, fb->format->num_planes);
0490 }
0491 EXPORT_SYMBOL(drm_gem_fb_end_cpu_access);
0492 
0493 static __u32 drm_gem_afbc_get_bpp(struct drm_device *dev,
0494                   const struct drm_mode_fb_cmd2 *mode_cmd)
0495 {
0496     const struct drm_format_info *info;
0497 
0498     info = drm_get_format_info(dev, mode_cmd);
0499 
0500     /* use whatever a driver has set */
0501     if (info->cpp[0])
0502         return info->cpp[0] * 8;
0503 
0504     /* guess otherwise */
0505     switch (info->format) {
0506     case DRM_FORMAT_YUV420_8BIT:
0507         return 12;
0508     case DRM_FORMAT_YUV420_10BIT:
0509         return 15;
0510     case DRM_FORMAT_VUY101010:
0511         return 30;
0512     default:
0513         break;
0514     }
0515 
0516     /* all attempts failed */
0517     return 0;
0518 }
0519 
0520 static int drm_gem_afbc_min_size(struct drm_device *dev,
0521                  const struct drm_mode_fb_cmd2 *mode_cmd,
0522                  struct drm_afbc_framebuffer *afbc_fb)
0523 {
0524     __u32 n_blocks, w_alignment, h_alignment, hdr_alignment;
0525     /* remove bpp when all users properly encode cpp in drm_format_info */
0526     __u32 bpp;
0527 
0528     switch (mode_cmd->modifier[0] & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
0529     case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
0530         afbc_fb->block_width = 16;
0531         afbc_fb->block_height = 16;
0532         break;
0533     case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
0534         afbc_fb->block_width = 32;
0535         afbc_fb->block_height = 8;
0536         break;
0537     /* no user exists yet - fall through */
0538     case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4:
0539     case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4:
0540     default:
0541         drm_dbg_kms(dev, "Invalid AFBC_FORMAT_MOD_BLOCK_SIZE: %lld.\n",
0542                 mode_cmd->modifier[0]
0543                 & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK);
0544         return -EINVAL;
0545     }
0546 
0547     /* tiled header afbc */
0548     w_alignment = afbc_fb->block_width;
0549     h_alignment = afbc_fb->block_height;
0550     hdr_alignment = AFBC_HDR_ALIGN;
0551     if (mode_cmd->modifier[0] & AFBC_FORMAT_MOD_TILED) {
0552         w_alignment *= AFBC_TH_LAYOUT_ALIGNMENT;
0553         h_alignment *= AFBC_TH_LAYOUT_ALIGNMENT;
0554         hdr_alignment = AFBC_TH_BODY_START_ALIGNMENT;
0555     }
0556 
0557     afbc_fb->aligned_width = ALIGN(mode_cmd->width, w_alignment);
0558     afbc_fb->aligned_height = ALIGN(mode_cmd->height, h_alignment);
0559     afbc_fb->offset = mode_cmd->offsets[0];
0560 
0561     bpp = drm_gem_afbc_get_bpp(dev, mode_cmd);
0562     if (!bpp) {
0563         drm_dbg_kms(dev, "Invalid AFBC bpp value: %d\n", bpp);
0564         return -EINVAL;
0565     }
0566 
0567     n_blocks = (afbc_fb->aligned_width * afbc_fb->aligned_height)
0568            / AFBC_SUPERBLOCK_PIXELS;
0569     afbc_fb->afbc_size = ALIGN(n_blocks * AFBC_HEADER_SIZE, hdr_alignment);
0570     afbc_fb->afbc_size += n_blocks * ALIGN(bpp * AFBC_SUPERBLOCK_PIXELS / 8,
0571                            AFBC_SUPERBLOCK_ALIGNMENT);
0572 
0573     return 0;
0574 }
0575 
0576 /**
0577  * drm_gem_fb_afbc_init() - Helper function for drivers using afbc to
0578  *              fill and validate all the afbc-specific
0579  *              struct drm_afbc_framebuffer members
0580  *
0581  * @dev: DRM device
0582  * @afbc_fb: afbc-specific framebuffer
0583  * @mode_cmd: Metadata from the userspace framebuffer creation request
0584  * @afbc_fb: afbc framebuffer
0585  *
0586  * This function can be used by drivers which support afbc to complete
0587  * the preparation of struct drm_afbc_framebuffer. It must be called after
0588  * allocating the said struct and calling drm_gem_fb_init_with_funcs().
0589  * It is caller's responsibility to put afbc_fb->base.obj objects in case
0590  * the call is unsuccessful.
0591  *
0592  * Returns:
0593  * Zero on success or a negative error value on failure.
0594  */
0595 int drm_gem_fb_afbc_init(struct drm_device *dev,
0596              const struct drm_mode_fb_cmd2 *mode_cmd,
0597              struct drm_afbc_framebuffer *afbc_fb)
0598 {
0599     const struct drm_format_info *info;
0600     struct drm_gem_object **objs;
0601     int ret;
0602 
0603     objs = afbc_fb->base.obj;
0604     info = drm_get_format_info(dev, mode_cmd);
0605     if (!info)
0606         return -EINVAL;
0607 
0608     ret = drm_gem_afbc_min_size(dev, mode_cmd, afbc_fb);
0609     if (ret < 0)
0610         return ret;
0611 
0612     if (objs[0]->size < afbc_fb->afbc_size)
0613         return -EINVAL;
0614 
0615     return 0;
0616 }
0617 EXPORT_SYMBOL_GPL(drm_gem_fb_afbc_init);