LCOV - code coverage report
Current view: top level - drivers/gpu/drm - drm_gem_framebuffer_helper.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 158 0.0 %
Date: 2023-08-24 13:40:31 Functions: 0 16 0.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-or-later
       2             : /*
       3             :  * drm gem framebuffer helper functions
       4             :  *
       5             :  * Copyright (C) 2017 Noralf Trønnes
       6             :  */
       7             : 
       8             : #include <linux/slab.h>
       9             : #include <linux/module.h>
      10             : 
      11             : #include <drm/drm_damage_helper.h>
      12             : #include <drm/drm_drv.h>
      13             : #include <drm/drm_fourcc.h>
      14             : #include <drm/drm_framebuffer.h>
      15             : #include <drm/drm_gem.h>
      16             : #include <drm/drm_gem_framebuffer_helper.h>
      17             : #include <drm/drm_modeset_helper.h>
      18             : 
      19             : #include "drm_internal.h"
      20             : 
      21             : MODULE_IMPORT_NS(DMA_BUF);
      22             : 
      23             : #define AFBC_HEADER_SIZE                16
      24             : #define AFBC_TH_LAYOUT_ALIGNMENT        8
      25             : #define AFBC_HDR_ALIGN                  64
      26             : #define AFBC_SUPERBLOCK_PIXELS          256
      27             : #define AFBC_SUPERBLOCK_ALIGNMENT       128
      28             : #define AFBC_TH_BODY_START_ALIGNMENT    4096
      29             : 
      30             : /**
      31             :  * DOC: overview
      32             :  *
      33             :  * This library provides helpers for drivers that don't subclass
      34             :  * &drm_framebuffer and use &drm_gem_object for their backing storage.
      35             :  *
      36             :  * Drivers without additional needs to validate framebuffers can simply use
      37             :  * drm_gem_fb_create() and everything is wired up automatically. Other drivers
      38             :  * can use all parts independently.
      39             :  */
      40             : 
      41             : /**
      42             :  * drm_gem_fb_get_obj() - Get GEM object backing the framebuffer
      43             :  * @fb: Framebuffer
      44             :  * @plane: Plane index
      45             :  *
      46             :  * No additional reference is taken beyond the one that the &drm_frambuffer
      47             :  * already holds.
      48             :  *
      49             :  * Returns:
      50             :  * Pointer to &drm_gem_object for the given framebuffer and plane index or NULL
      51             :  * if it does not exist.
      52             :  */
      53           0 : struct drm_gem_object *drm_gem_fb_get_obj(struct drm_framebuffer *fb,
      54             :                                           unsigned int plane)
      55             : {
      56           0 :         struct drm_device *dev = fb->dev;
      57             : 
      58           0 :         if (drm_WARN_ON_ONCE(dev, plane >= ARRAY_SIZE(fb->obj)))
      59             :                 return NULL;
      60           0 :         else if (drm_WARN_ON_ONCE(dev, !fb->obj[plane]))
      61             :                 return NULL;
      62             : 
      63           0 :         return fb->obj[plane];
      64             : }
      65             : EXPORT_SYMBOL_GPL(drm_gem_fb_get_obj);
      66             : 
      67             : static int
      68           0 : drm_gem_fb_init(struct drm_device *dev,
      69             :                  struct drm_framebuffer *fb,
      70             :                  const struct drm_mode_fb_cmd2 *mode_cmd,
      71             :                  struct drm_gem_object **obj, unsigned int num_planes,
      72             :                  const struct drm_framebuffer_funcs *funcs)
      73             : {
      74             :         unsigned int i;
      75             :         int ret;
      76             : 
      77           0 :         drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd);
      78             : 
      79           0 :         for (i = 0; i < num_planes; i++)
      80           0 :                 fb->obj[i] = obj[i];
      81             : 
      82           0 :         ret = drm_framebuffer_init(dev, fb, funcs);
      83           0 :         if (ret)
      84           0 :                 drm_err(dev, "Failed to init framebuffer: %d\n", ret);
      85             : 
      86           0 :         return ret;
      87             : }
      88             : 
      89             : /**
      90             :  * drm_gem_fb_destroy - Free GEM backed framebuffer
      91             :  * @fb: Framebuffer
      92             :  *
      93             :  * Frees a GEM backed framebuffer with its backing buffer(s) and the structure
      94             :  * itself. Drivers can use this as their &drm_framebuffer_funcs->destroy
      95             :  * callback.
      96             :  */
      97           0 : void drm_gem_fb_destroy(struct drm_framebuffer *fb)
      98             : {
      99             :         unsigned int i;
     100             : 
     101           0 :         for (i = 0; i < fb->format->num_planes; i++)
     102           0 :                 drm_gem_object_put(fb->obj[i]);
     103             : 
     104           0 :         drm_framebuffer_cleanup(fb);
     105           0 :         kfree(fb);
     106           0 : }
     107             : EXPORT_SYMBOL(drm_gem_fb_destroy);
     108             : 
     109             : /**
     110             :  * drm_gem_fb_create_handle - Create handle for GEM backed framebuffer
     111             :  * @fb: Framebuffer
     112             :  * @file: DRM file to register the handle for
     113             :  * @handle: Pointer to return the created handle
     114             :  *
     115             :  * This function creates a handle for the GEM object backing the framebuffer.
     116             :  * Drivers can use this as their &drm_framebuffer_funcs->create_handle
     117             :  * callback. The GETFB IOCTL calls into this callback.
     118             :  *
     119             :  * Returns:
     120             :  * 0 on success or a negative error code on failure.
     121             :  */
     122           0 : int drm_gem_fb_create_handle(struct drm_framebuffer *fb, struct drm_file *file,
     123             :                              unsigned int *handle)
     124             : {
     125           0 :         return drm_gem_handle_create(file, fb->obj[0], handle);
     126             : }
     127             : EXPORT_SYMBOL(drm_gem_fb_create_handle);
     128             : 
     129             : /**
     130             :  * drm_gem_fb_init_with_funcs() - Helper function for implementing
     131             :  *                                &drm_mode_config_funcs.fb_create
     132             :  *                                callback in cases when the driver
     133             :  *                                allocates a subclass of
     134             :  *                                struct drm_framebuffer
     135             :  * @dev: DRM device
     136             :  * @fb: framebuffer object
     137             :  * @file: DRM file that holds the GEM handle(s) backing the framebuffer
     138             :  * @mode_cmd: Metadata from the userspace framebuffer creation request
     139             :  * @funcs: vtable to be used for the new framebuffer object
     140             :  *
     141             :  * This function can be used to set &drm_framebuffer_funcs for drivers that need
     142             :  * custom framebuffer callbacks. Use drm_gem_fb_create() if you don't need to
     143             :  * change &drm_framebuffer_funcs. The function does buffer size validation.
     144             :  * The buffer size validation is for a general case, though, so users should
     145             :  * pay attention to the checks being appropriate for them or, at least,
     146             :  * non-conflicting.
     147             :  *
     148             :  * Returns:
     149             :  * Zero or a negative error code.
     150             :  */
     151           0 : int drm_gem_fb_init_with_funcs(struct drm_device *dev,
     152             :                                struct drm_framebuffer *fb,
     153             :                                struct drm_file *file,
     154             :                                const struct drm_mode_fb_cmd2 *mode_cmd,
     155             :                                const struct drm_framebuffer_funcs *funcs)
     156             : {
     157             :         const struct drm_format_info *info;
     158             :         struct drm_gem_object *objs[DRM_FORMAT_MAX_PLANES];
     159             :         unsigned int i;
     160             :         int ret;
     161             : 
     162           0 :         info = drm_get_format_info(dev, mode_cmd);
     163           0 :         if (!info) {
     164           0 :                 drm_dbg_kms(dev, "Failed to get FB format info\n");
     165           0 :                 return -EINVAL;
     166             :         }
     167             : 
     168           0 :         if (drm_drv_uses_atomic_modeset(dev) &&
     169           0 :             !drm_any_plane_has_format(dev, mode_cmd->pixel_format,
     170             :                                       mode_cmd->modifier[0])) {
     171           0 :                 drm_dbg_kms(dev, "Unsupported pixel format %p4cc / modifier 0x%llx\n",
     172             :                             &mode_cmd->pixel_format, mode_cmd->modifier[0]);
     173           0 :                 return -EINVAL;
     174             :         }
     175             : 
     176           0 :         for (i = 0; i < info->num_planes; i++) {
     177           0 :                 unsigned int width = mode_cmd->width / (i ? info->hsub : 1);
     178           0 :                 unsigned int height = mode_cmd->height / (i ? info->vsub : 1);
     179             :                 unsigned int min_size;
     180             : 
     181           0 :                 objs[i] = drm_gem_object_lookup(file, mode_cmd->handles[i]);
     182           0 :                 if (!objs[i]) {
     183           0 :                         drm_dbg_kms(dev, "Failed to lookup GEM object\n");
     184           0 :                         ret = -ENOENT;
     185           0 :                         goto err_gem_object_put;
     186             :                 }
     187             : 
     188           0 :                 min_size = (height - 1) * mode_cmd->pitches[i]
     189           0 :                          + drm_format_info_min_pitch(info, i, width)
     190           0 :                          + mode_cmd->offsets[i];
     191             : 
     192           0 :                 if (objs[i]->size < min_size) {
     193           0 :                         drm_dbg_kms(dev,
     194             :                                     "GEM object size (%zu) smaller than minimum size (%u) for plane %d\n",
     195             :                                     objs[i]->size, min_size, i);
     196           0 :                         drm_gem_object_put(objs[i]);
     197             :                         ret = -EINVAL;
     198             :                         goto err_gem_object_put;
     199             :                 }
     200             :         }
     201             : 
     202           0 :         ret = drm_gem_fb_init(dev, fb, mode_cmd, objs, i, funcs);
     203           0 :         if (ret)
     204             :                 goto err_gem_object_put;
     205             : 
     206             :         return 0;
     207             : 
     208             : err_gem_object_put:
     209           0 :         while (i > 0) {
     210           0 :                 --i;
     211           0 :                 drm_gem_object_put(objs[i]);
     212             :         }
     213             :         return ret;
     214             : }
     215             : EXPORT_SYMBOL_GPL(drm_gem_fb_init_with_funcs);
     216             : 
     217             : /**
     218             :  * drm_gem_fb_create_with_funcs() - Helper function for the
     219             :  *                                  &drm_mode_config_funcs.fb_create
     220             :  *                                  callback
     221             :  * @dev: DRM device
     222             :  * @file: DRM file that holds the GEM handle(s) backing the framebuffer
     223             :  * @mode_cmd: Metadata from the userspace framebuffer creation request
     224             :  * @funcs: vtable to be used for the new framebuffer object
     225             :  *
     226             :  * This function can be used to set &drm_framebuffer_funcs for drivers that need
     227             :  * custom framebuffer callbacks. Use drm_gem_fb_create() if you don't need to
     228             :  * change &drm_framebuffer_funcs. The function does buffer size validation.
     229             :  *
     230             :  * Returns:
     231             :  * Pointer to a &drm_framebuffer on success or an error pointer on failure.
     232             :  */
     233             : struct drm_framebuffer *
     234           0 : drm_gem_fb_create_with_funcs(struct drm_device *dev, struct drm_file *file,
     235             :                              const struct drm_mode_fb_cmd2 *mode_cmd,
     236             :                              const struct drm_framebuffer_funcs *funcs)
     237             : {
     238             :         struct drm_framebuffer *fb;
     239             :         int ret;
     240             : 
     241           0 :         fb = kzalloc(sizeof(*fb), GFP_KERNEL);
     242           0 :         if (!fb)
     243             :                 return ERR_PTR(-ENOMEM);
     244             : 
     245           0 :         ret = drm_gem_fb_init_with_funcs(dev, fb, file, mode_cmd, funcs);
     246           0 :         if (ret) {
     247           0 :                 kfree(fb);
     248           0 :                 return ERR_PTR(ret);
     249             :         }
     250             : 
     251             :         return fb;
     252             : }
     253             : EXPORT_SYMBOL_GPL(drm_gem_fb_create_with_funcs);
     254             : 
     255             : static const struct drm_framebuffer_funcs drm_gem_fb_funcs = {
     256             :         .destroy        = drm_gem_fb_destroy,
     257             :         .create_handle  = drm_gem_fb_create_handle,
     258             : };
     259             : 
     260             : /**
     261             :  * drm_gem_fb_create() - Helper function for the
     262             :  *                       &drm_mode_config_funcs.fb_create callback
     263             :  * @dev: DRM device
     264             :  * @file: DRM file that holds the GEM handle(s) backing the framebuffer
     265             :  * @mode_cmd: Metadata from the userspace framebuffer creation request
     266             :  *
     267             :  * This function creates a new framebuffer object described by
     268             :  * &drm_mode_fb_cmd2. This description includes handles for the buffer(s)
     269             :  * backing the framebuffer.
     270             :  *
     271             :  * If your hardware has special alignment or pitch requirements these should be
     272             :  * checked before calling this function. The function does buffer size
     273             :  * validation. Use drm_gem_fb_create_with_dirty() if you need framebuffer
     274             :  * flushing.
     275             :  *
     276             :  * Drivers can use this as their &drm_mode_config_funcs.fb_create callback.
     277             :  * The ADDFB2 IOCTL calls into this callback.
     278             :  *
     279             :  * Returns:
     280             :  * Pointer to a &drm_framebuffer on success or an error pointer on failure.
     281             :  */
     282             : struct drm_framebuffer *
     283           0 : drm_gem_fb_create(struct drm_device *dev, struct drm_file *file,
     284             :                   const struct drm_mode_fb_cmd2 *mode_cmd)
     285             : {
     286           0 :         return drm_gem_fb_create_with_funcs(dev, file, mode_cmd,
     287             :                                             &drm_gem_fb_funcs);
     288             : }
     289             : EXPORT_SYMBOL_GPL(drm_gem_fb_create);
     290             : 
     291             : static const struct drm_framebuffer_funcs drm_gem_fb_funcs_dirtyfb = {
     292             :         .destroy        = drm_gem_fb_destroy,
     293             :         .create_handle  = drm_gem_fb_create_handle,
     294             :         .dirty          = drm_atomic_helper_dirtyfb,
     295             : };
     296             : 
     297             : /**
     298             :  * drm_gem_fb_create_with_dirty() - Helper function for the
     299             :  *                       &drm_mode_config_funcs.fb_create callback
     300             :  * @dev: DRM device
     301             :  * @file: DRM file that holds the GEM handle(s) backing the framebuffer
     302             :  * @mode_cmd: Metadata from the userspace framebuffer creation request
     303             :  *
     304             :  * This function creates a new framebuffer object described by
     305             :  * &drm_mode_fb_cmd2. This description includes handles for the buffer(s)
     306             :  * backing the framebuffer. drm_atomic_helper_dirtyfb() is used for the dirty
     307             :  * callback giving framebuffer flushing through the atomic machinery. Use
     308             :  * drm_gem_fb_create() if you don't need the dirty callback.
     309             :  * The function does buffer size validation.
     310             :  *
     311             :  * Drivers should also call drm_plane_enable_fb_damage_clips() on all planes
     312             :  * to enable userspace to use damage clips also with the ATOMIC IOCTL.
     313             :  *
     314             :  * Drivers can use this as their &drm_mode_config_funcs.fb_create callback.
     315             :  * The ADDFB2 IOCTL calls into this callback.
     316             :  *
     317             :  * Returns:
     318             :  * Pointer to a &drm_framebuffer on success or an error pointer on failure.
     319             :  */
     320             : struct drm_framebuffer *
     321           0 : drm_gem_fb_create_with_dirty(struct drm_device *dev, struct drm_file *file,
     322             :                              const struct drm_mode_fb_cmd2 *mode_cmd)
     323             : {
     324           0 :         return drm_gem_fb_create_with_funcs(dev, file, mode_cmd,
     325             :                                             &drm_gem_fb_funcs_dirtyfb);
     326             : }
     327             : EXPORT_SYMBOL_GPL(drm_gem_fb_create_with_dirty);
     328             : 
     329             : /**
     330             :  * drm_gem_fb_vmap - maps all framebuffer BOs into kernel address space
     331             :  * @fb: the framebuffer
     332             :  * @map: returns the mapping's address for each BO
     333             :  * @data: returns the data address for each BO, can be NULL
     334             :  *
     335             :  * This function maps all buffer objects of the given framebuffer into
     336             :  * kernel address space and stores them in struct iosys_map. If the
     337             :  * mapping operation fails for one of the BOs, the function unmaps the
     338             :  * already established mappings automatically.
     339             :  *
     340             :  * Callers that want to access a BO's stored data should pass @data.
     341             :  * The argument returns the addresses of the data stored in each BO. This
     342             :  * is different from @map if the framebuffer's offsets field is non-zero.
     343             :  *
     344             :  * Both, @map and @data, must each refer to arrays with at least
     345             :  * fb->format->num_planes elements.
     346             :  *
     347             :  * See drm_gem_fb_vunmap() for unmapping.
     348             :  *
     349             :  * Returns:
     350             :  * 0 on success, or a negative errno code otherwise.
     351             :  */
     352           0 : int drm_gem_fb_vmap(struct drm_framebuffer *fb, struct iosys_map *map,
     353             :                     struct iosys_map *data)
     354             : {
     355             :         struct drm_gem_object *obj;
     356             :         unsigned int i;
     357             :         int ret;
     358             : 
     359           0 :         for (i = 0; i < fb->format->num_planes; ++i) {
     360           0 :                 obj = drm_gem_fb_get_obj(fb, i);
     361           0 :                 if (!obj) {
     362             :                         ret = -EINVAL;
     363             :                         goto err_drm_gem_vunmap;
     364             :                 }
     365           0 :                 ret = drm_gem_vmap_unlocked(obj, &map[i]);
     366           0 :                 if (ret)
     367             :                         goto err_drm_gem_vunmap;
     368             :         }
     369             : 
     370           0 :         if (data) {
     371           0 :                 for (i = 0; i < fb->format->num_planes; ++i) {
     372           0 :                         memcpy(&data[i], &map[i], sizeof(data[i]));
     373           0 :                         if (iosys_map_is_null(&data[i]))
     374           0 :                                 continue;
     375           0 :                         iosys_map_incr(&data[i], fb->offsets[i]);
     376             :                 }
     377             :         }
     378             : 
     379             :         return 0;
     380             : 
     381             : err_drm_gem_vunmap:
     382           0 :         while (i) {
     383           0 :                 --i;
     384           0 :                 obj = drm_gem_fb_get_obj(fb, i);
     385           0 :                 if (!obj)
     386           0 :                         continue;
     387           0 :                 drm_gem_vunmap_unlocked(obj, &map[i]);
     388             :         }
     389             :         return ret;
     390             : }
     391             : EXPORT_SYMBOL(drm_gem_fb_vmap);
     392             : 
     393             : /**
     394             :  * drm_gem_fb_vunmap - unmaps framebuffer BOs from kernel address space
     395             :  * @fb: the framebuffer
     396             :  * @map: mapping addresses as returned by drm_gem_fb_vmap()
     397             :  *
     398             :  * This function unmaps all buffer objects of the given framebuffer.
     399             :  *
     400             :  * See drm_gem_fb_vmap() for more information.
     401             :  */
     402           0 : void drm_gem_fb_vunmap(struct drm_framebuffer *fb, struct iosys_map *map)
     403             : {
     404           0 :         unsigned int i = fb->format->num_planes;
     405             :         struct drm_gem_object *obj;
     406             : 
     407           0 :         while (i) {
     408           0 :                 --i;
     409           0 :                 obj = drm_gem_fb_get_obj(fb, i);
     410           0 :                 if (!obj)
     411           0 :                         continue;
     412           0 :                 if (iosys_map_is_null(&map[i]))
     413           0 :                         continue;
     414           0 :                 drm_gem_vunmap_unlocked(obj, &map[i]);
     415             :         }
     416           0 : }
     417             : EXPORT_SYMBOL(drm_gem_fb_vunmap);
     418             : 
     419           0 : static void __drm_gem_fb_end_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir,
     420             :                                         unsigned int num_planes)
     421             : {
     422             :         struct dma_buf_attachment *import_attach;
     423             :         struct drm_gem_object *obj;
     424             :         int ret;
     425             : 
     426           0 :         while (num_planes) {
     427           0 :                 --num_planes;
     428           0 :                 obj = drm_gem_fb_get_obj(fb, num_planes);
     429           0 :                 if (!obj)
     430           0 :                         continue;
     431           0 :                 import_attach = obj->import_attach;
     432           0 :                 if (!import_attach)
     433           0 :                         continue;
     434           0 :                 ret = dma_buf_end_cpu_access(import_attach->dmabuf, dir);
     435           0 :                 if (ret)
     436           0 :                         drm_err(fb->dev, "dma_buf_end_cpu_access(%u, %d) failed: %d\n",
     437             :                                 ret, num_planes, dir);
     438             :         }
     439           0 : }
     440             : 
     441             : /**
     442             :  * drm_gem_fb_begin_cpu_access - prepares GEM buffer objects for CPU access
     443             :  * @fb: the framebuffer
     444             :  * @dir: access mode
     445             :  *
     446             :  * Prepares a framebuffer's GEM buffer objects for CPU access. This function
     447             :  * must be called before accessing the BO data within the kernel. For imported
     448             :  * BOs, the function calls dma_buf_begin_cpu_access().
     449             :  *
     450             :  * See drm_gem_fb_end_cpu_access() for signalling the end of CPU access.
     451             :  *
     452             :  * Returns:
     453             :  * 0 on success, or a negative errno code otherwise.
     454             :  */
     455           0 : int drm_gem_fb_begin_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir)
     456             : {
     457             :         struct dma_buf_attachment *import_attach;
     458             :         struct drm_gem_object *obj;
     459             :         unsigned int i;
     460             :         int ret;
     461             : 
     462           0 :         for (i = 0; i < fb->format->num_planes; ++i) {
     463           0 :                 obj = drm_gem_fb_get_obj(fb, i);
     464           0 :                 if (!obj) {
     465             :                         ret = -EINVAL;
     466             :                         goto err___drm_gem_fb_end_cpu_access;
     467             :                 }
     468           0 :                 import_attach = obj->import_attach;
     469           0 :                 if (!import_attach)
     470           0 :                         continue;
     471           0 :                 ret = dma_buf_begin_cpu_access(import_attach->dmabuf, dir);
     472           0 :                 if (ret)
     473             :                         goto err___drm_gem_fb_end_cpu_access;
     474             :         }
     475             : 
     476             :         return 0;
     477             : 
     478             : err___drm_gem_fb_end_cpu_access:
     479           0 :         __drm_gem_fb_end_cpu_access(fb, dir, i);
     480           0 :         return ret;
     481             : }
     482             : EXPORT_SYMBOL(drm_gem_fb_begin_cpu_access);
     483             : 
     484             : /**
     485             :  * drm_gem_fb_end_cpu_access - signals end of CPU access to GEM buffer objects
     486             :  * @fb: the framebuffer
     487             :  * @dir: access mode
     488             :  *
     489             :  * Signals the end of CPU access to the given framebuffer's GEM buffer objects. This
     490             :  * function must be paired with a corresponding call to drm_gem_fb_begin_cpu_access().
     491             :  * For imported BOs, the function calls dma_buf_end_cpu_access().
     492             :  *
     493             :  * See also drm_gem_fb_begin_cpu_access().
     494             :  */
     495           0 : void drm_gem_fb_end_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir)
     496             : {
     497           0 :         __drm_gem_fb_end_cpu_access(fb, dir, fb->format->num_planes);
     498           0 : }
     499             : EXPORT_SYMBOL(drm_gem_fb_end_cpu_access);
     500             : 
     501             : // TODO Drop this function and replace by drm_format_info_bpp() once all
     502             : // DRM_FORMAT_* provide proper block info in drivers/gpu/drm/drm_fourcc.c
     503           0 : static __u32 drm_gem_afbc_get_bpp(struct drm_device *dev,
     504             :                                   const struct drm_mode_fb_cmd2 *mode_cmd)
     505             : {
     506             :         const struct drm_format_info *info;
     507             : 
     508           0 :         info = drm_get_format_info(dev, mode_cmd);
     509             : 
     510           0 :         switch (info->format) {
     511             :         case DRM_FORMAT_YUV420_8BIT:
     512             :                 return 12;
     513             :         case DRM_FORMAT_YUV420_10BIT:
     514           0 :                 return 15;
     515             :         case DRM_FORMAT_VUY101010:
     516           0 :                 return 30;
     517             :         default:
     518           0 :                 return drm_format_info_bpp(info, 0);
     519             :         }
     520             : }
     521             : 
     522           0 : static int drm_gem_afbc_min_size(struct drm_device *dev,
     523             :                                  const struct drm_mode_fb_cmd2 *mode_cmd,
     524             :                                  struct drm_afbc_framebuffer *afbc_fb)
     525             : {
     526             :         __u32 n_blocks, w_alignment, h_alignment, hdr_alignment;
     527             :         /* remove bpp when all users properly encode cpp in drm_format_info */
     528             :         __u32 bpp;
     529             : 
     530           0 :         switch (mode_cmd->modifier[0] & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
     531             :         case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
     532           0 :                 afbc_fb->block_width = 16;
     533           0 :                 afbc_fb->block_height = 16;
     534           0 :                 break;
     535             :         case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
     536           0 :                 afbc_fb->block_width = 32;
     537           0 :                 afbc_fb->block_height = 8;
     538           0 :                 break;
     539             :         /* no user exists yet - fall through */
     540             :         case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4:
     541             :         case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4:
     542             :         default:
     543           0 :                 drm_dbg_kms(dev, "Invalid AFBC_FORMAT_MOD_BLOCK_SIZE: %lld.\n",
     544             :                             mode_cmd->modifier[0]
     545             :                             & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK);
     546           0 :                 return -EINVAL;
     547             :         }
     548             : 
     549             :         /* tiled header afbc */
     550           0 :         w_alignment = afbc_fb->block_width;
     551           0 :         h_alignment = afbc_fb->block_height;
     552           0 :         hdr_alignment = AFBC_HDR_ALIGN;
     553           0 :         if (mode_cmd->modifier[0] & AFBC_FORMAT_MOD_TILED) {
     554           0 :                 w_alignment *= AFBC_TH_LAYOUT_ALIGNMENT;
     555           0 :                 h_alignment *= AFBC_TH_LAYOUT_ALIGNMENT;
     556           0 :                 hdr_alignment = AFBC_TH_BODY_START_ALIGNMENT;
     557             :         }
     558             : 
     559           0 :         afbc_fb->aligned_width = ALIGN(mode_cmd->width, w_alignment);
     560           0 :         afbc_fb->aligned_height = ALIGN(mode_cmd->height, h_alignment);
     561           0 :         afbc_fb->offset = mode_cmd->offsets[0];
     562             : 
     563           0 :         bpp = drm_gem_afbc_get_bpp(dev, mode_cmd);
     564           0 :         if (!bpp) {
     565           0 :                 drm_dbg_kms(dev, "Invalid AFBC bpp value: %d\n", bpp);
     566           0 :                 return -EINVAL;
     567             :         }
     568             : 
     569           0 :         n_blocks = (afbc_fb->aligned_width * afbc_fb->aligned_height)
     570             :                    / AFBC_SUPERBLOCK_PIXELS;
     571           0 :         afbc_fb->afbc_size = ALIGN(n_blocks * AFBC_HEADER_SIZE, hdr_alignment);
     572           0 :         afbc_fb->afbc_size += n_blocks * ALIGN(bpp * AFBC_SUPERBLOCK_PIXELS / 8,
     573             :                                                AFBC_SUPERBLOCK_ALIGNMENT);
     574             : 
     575           0 :         return 0;
     576             : }
     577             : 
     578             : /**
     579             :  * drm_gem_fb_afbc_init() - Helper function for drivers using afbc to
     580             :  *                          fill and validate all the afbc-specific
     581             :  *                          struct drm_afbc_framebuffer members
     582             :  *
     583             :  * @dev: DRM device
     584             :  * @afbc_fb: afbc-specific framebuffer
     585             :  * @mode_cmd: Metadata from the userspace framebuffer creation request
     586             :  * @afbc_fb: afbc framebuffer
     587             :  *
     588             :  * This function can be used by drivers which support afbc to complete
     589             :  * the preparation of struct drm_afbc_framebuffer. It must be called after
     590             :  * allocating the said struct and calling drm_gem_fb_init_with_funcs().
     591             :  * It is caller's responsibility to put afbc_fb->base.obj objects in case
     592             :  * the call is unsuccessful.
     593             :  *
     594             :  * Returns:
     595             :  * Zero on success or a negative error value on failure.
     596             :  */
     597           0 : int drm_gem_fb_afbc_init(struct drm_device *dev,
     598             :                          const struct drm_mode_fb_cmd2 *mode_cmd,
     599             :                          struct drm_afbc_framebuffer *afbc_fb)
     600             : {
     601             :         const struct drm_format_info *info;
     602             :         struct drm_gem_object **objs;
     603             :         int ret;
     604             : 
     605           0 :         objs = afbc_fb->base.obj;
     606           0 :         info = drm_get_format_info(dev, mode_cmd);
     607           0 :         if (!info)
     608             :                 return -EINVAL;
     609             : 
     610           0 :         ret = drm_gem_afbc_min_size(dev, mode_cmd, afbc_fb);
     611           0 :         if (ret < 0)
     612             :                 return ret;
     613             : 
     614           0 :         if (objs[0]->size < afbc_fb->afbc_size)
     615             :                 return -EINVAL;
     616             : 
     617           0 :         return 0;
     618             : }
     619             : EXPORT_SYMBOL_GPL(drm_gem_fb_afbc_init);

Generated by: LCOV version 1.14