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

Generated by: LCOV version 1.14