18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * drm gem framebuffer helper functions 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2017 Noralf Trønnes 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/dma-buf.h> 98c2ecf20Sopenharmony_ci#include <linux/dma-fence.h> 108c2ecf20Sopenharmony_ci#include <linux/dma-resv.h> 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <drm/drm_atomic.h> 148c2ecf20Sopenharmony_ci#include <drm/drm_atomic_uapi.h> 158c2ecf20Sopenharmony_ci#include <drm/drm_damage_helper.h> 168c2ecf20Sopenharmony_ci#include <drm/drm_fb_helper.h> 178c2ecf20Sopenharmony_ci#include <drm/drm_fourcc.h> 188c2ecf20Sopenharmony_ci#include <drm/drm_framebuffer.h> 198c2ecf20Sopenharmony_ci#include <drm/drm_gem.h> 208c2ecf20Sopenharmony_ci#include <drm/drm_gem_framebuffer_helper.h> 218c2ecf20Sopenharmony_ci#include <drm/drm_modeset_helper.h> 228c2ecf20Sopenharmony_ci#include <drm/drm_simple_kms_helper.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define AFBC_HEADER_SIZE 16 258c2ecf20Sopenharmony_ci#define AFBC_TH_LAYOUT_ALIGNMENT 8 268c2ecf20Sopenharmony_ci#define AFBC_HDR_ALIGN 64 278c2ecf20Sopenharmony_ci#define AFBC_SUPERBLOCK_PIXELS 256 288c2ecf20Sopenharmony_ci#define AFBC_SUPERBLOCK_ALIGNMENT 128 298c2ecf20Sopenharmony_ci#define AFBC_TH_BODY_START_ALIGNMENT 4096 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/** 328c2ecf20Sopenharmony_ci * DOC: overview 338c2ecf20Sopenharmony_ci * 348c2ecf20Sopenharmony_ci * This library provides helpers for drivers that don't subclass 358c2ecf20Sopenharmony_ci * &drm_framebuffer and use &drm_gem_object for their backing storage. 368c2ecf20Sopenharmony_ci * 378c2ecf20Sopenharmony_ci * Drivers without additional needs to validate framebuffers can simply use 388c2ecf20Sopenharmony_ci * drm_gem_fb_create() and everything is wired up automatically. Other drivers 398c2ecf20Sopenharmony_ci * can use all parts independently. 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/** 438c2ecf20Sopenharmony_ci * drm_gem_fb_get_obj() - Get GEM object backing the framebuffer 448c2ecf20Sopenharmony_ci * @fb: Framebuffer 458c2ecf20Sopenharmony_ci * @plane: Plane index 468c2ecf20Sopenharmony_ci * 478c2ecf20Sopenharmony_ci * No additional reference is taken beyond the one that the &drm_frambuffer 488c2ecf20Sopenharmony_ci * already holds. 498c2ecf20Sopenharmony_ci * 508c2ecf20Sopenharmony_ci * Returns: 518c2ecf20Sopenharmony_ci * Pointer to &drm_gem_object for the given framebuffer and plane index or NULL 528c2ecf20Sopenharmony_ci * if it does not exist. 538c2ecf20Sopenharmony_ci */ 548c2ecf20Sopenharmony_cistruct drm_gem_object *drm_gem_fb_get_obj(struct drm_framebuffer *fb, 558c2ecf20Sopenharmony_ci unsigned int plane) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci if (plane >= 4) 588c2ecf20Sopenharmony_ci return NULL; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci return fb->obj[plane]; 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(drm_gem_fb_get_obj); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic int 658c2ecf20Sopenharmony_cidrm_gem_fb_init(struct drm_device *dev, 668c2ecf20Sopenharmony_ci struct drm_framebuffer *fb, 678c2ecf20Sopenharmony_ci const struct drm_mode_fb_cmd2 *mode_cmd, 688c2ecf20Sopenharmony_ci struct drm_gem_object **obj, unsigned int num_planes, 698c2ecf20Sopenharmony_ci const struct drm_framebuffer_funcs *funcs) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci int ret, i; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci for (i = 0; i < num_planes; i++) 768c2ecf20Sopenharmony_ci fb->obj[i] = obj[i]; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci ret = drm_framebuffer_init(dev, fb, funcs); 798c2ecf20Sopenharmony_ci if (ret) 808c2ecf20Sopenharmony_ci drm_err(dev, "Failed to init framebuffer: %d\n", ret); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci return ret; 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci/** 868c2ecf20Sopenharmony_ci * drm_gem_fb_destroy - Free GEM backed framebuffer 878c2ecf20Sopenharmony_ci * @fb: Framebuffer 888c2ecf20Sopenharmony_ci * 898c2ecf20Sopenharmony_ci * Frees a GEM backed framebuffer with its backing buffer(s) and the structure 908c2ecf20Sopenharmony_ci * itself. Drivers can use this as their &drm_framebuffer_funcs->destroy 918c2ecf20Sopenharmony_ci * callback. 928c2ecf20Sopenharmony_ci */ 938c2ecf20Sopenharmony_civoid drm_gem_fb_destroy(struct drm_framebuffer *fb) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci int i; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) 988c2ecf20Sopenharmony_ci drm_gem_object_put(fb->obj[i]); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci drm_framebuffer_cleanup(fb); 1018c2ecf20Sopenharmony_ci kfree(fb); 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_gem_fb_destroy); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci/** 1068c2ecf20Sopenharmony_ci * drm_gem_fb_create_handle - Create handle for GEM backed framebuffer 1078c2ecf20Sopenharmony_ci * @fb: Framebuffer 1088c2ecf20Sopenharmony_ci * @file: DRM file to register the handle for 1098c2ecf20Sopenharmony_ci * @handle: Pointer to return the created handle 1108c2ecf20Sopenharmony_ci * 1118c2ecf20Sopenharmony_ci * This function creates a handle for the GEM object backing the framebuffer. 1128c2ecf20Sopenharmony_ci * Drivers can use this as their &drm_framebuffer_funcs->create_handle 1138c2ecf20Sopenharmony_ci * callback. The GETFB IOCTL calls into this callback. 1148c2ecf20Sopenharmony_ci * 1158c2ecf20Sopenharmony_ci * Returns: 1168c2ecf20Sopenharmony_ci * 0 on success or a negative error code on failure. 1178c2ecf20Sopenharmony_ci */ 1188c2ecf20Sopenharmony_ciint drm_gem_fb_create_handle(struct drm_framebuffer *fb, struct drm_file *file, 1198c2ecf20Sopenharmony_ci unsigned int *handle) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci return drm_gem_handle_create(file, fb->obj[0], handle); 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_gem_fb_create_handle); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci/** 1268c2ecf20Sopenharmony_ci * drm_gem_fb_init_with_funcs() - Helper function for implementing 1278c2ecf20Sopenharmony_ci * &drm_mode_config_funcs.fb_create 1288c2ecf20Sopenharmony_ci * callback in cases when the driver 1298c2ecf20Sopenharmony_ci * allocates a subclass of 1308c2ecf20Sopenharmony_ci * struct drm_framebuffer 1318c2ecf20Sopenharmony_ci * @dev: DRM device 1328c2ecf20Sopenharmony_ci * @fb: framebuffer object 1338c2ecf20Sopenharmony_ci * @file: DRM file that holds the GEM handle(s) backing the framebuffer 1348c2ecf20Sopenharmony_ci * @mode_cmd: Metadata from the userspace framebuffer creation request 1358c2ecf20Sopenharmony_ci * @funcs: vtable to be used for the new framebuffer object 1368c2ecf20Sopenharmony_ci * 1378c2ecf20Sopenharmony_ci * This function can be used to set &drm_framebuffer_funcs for drivers that need 1388c2ecf20Sopenharmony_ci * custom framebuffer callbacks. Use drm_gem_fb_create() if you don't need to 1398c2ecf20Sopenharmony_ci * change &drm_framebuffer_funcs. The function does buffer size validation. 1408c2ecf20Sopenharmony_ci * The buffer size validation is for a general case, though, so users should 1418c2ecf20Sopenharmony_ci * pay attention to the checks being appropriate for them or, at least, 1428c2ecf20Sopenharmony_ci * non-conflicting. 1438c2ecf20Sopenharmony_ci * 1448c2ecf20Sopenharmony_ci * Returns: 1458c2ecf20Sopenharmony_ci * Zero or a negative error code. 1468c2ecf20Sopenharmony_ci */ 1478c2ecf20Sopenharmony_ciint drm_gem_fb_init_with_funcs(struct drm_device *dev, 1488c2ecf20Sopenharmony_ci struct drm_framebuffer *fb, 1498c2ecf20Sopenharmony_ci struct drm_file *file, 1508c2ecf20Sopenharmony_ci const struct drm_mode_fb_cmd2 *mode_cmd, 1518c2ecf20Sopenharmony_ci const struct drm_framebuffer_funcs *funcs) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci const struct drm_format_info *info; 1548c2ecf20Sopenharmony_ci struct drm_gem_object *objs[4]; 1558c2ecf20Sopenharmony_ci int ret, i; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci info = drm_get_format_info(dev, mode_cmd); 1588c2ecf20Sopenharmony_ci if (!info) 1598c2ecf20Sopenharmony_ci return -EINVAL; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci for (i = 0; i < info->num_planes; i++) { 1628c2ecf20Sopenharmony_ci unsigned int width = mode_cmd->width / (i ? info->hsub : 1); 1638c2ecf20Sopenharmony_ci unsigned int height = mode_cmd->height / (i ? info->vsub : 1); 1648c2ecf20Sopenharmony_ci unsigned int min_size; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci objs[i] = drm_gem_object_lookup(file, mode_cmd->handles[i]); 1678c2ecf20Sopenharmony_ci if (!objs[i]) { 1688c2ecf20Sopenharmony_ci drm_dbg_kms(dev, "Failed to lookup GEM object\n"); 1698c2ecf20Sopenharmony_ci ret = -ENOENT; 1708c2ecf20Sopenharmony_ci goto err_gem_object_put; 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci min_size = (height - 1) * mode_cmd->pitches[i] 1748c2ecf20Sopenharmony_ci + drm_format_info_min_pitch(info, i, width) 1758c2ecf20Sopenharmony_ci + mode_cmd->offsets[i]; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci if (objs[i]->size < min_size) { 1788c2ecf20Sopenharmony_ci drm_gem_object_put(objs[i]); 1798c2ecf20Sopenharmony_ci ret = -EINVAL; 1808c2ecf20Sopenharmony_ci goto err_gem_object_put; 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci ret = drm_gem_fb_init(dev, fb, mode_cmd, objs, i, funcs); 1858c2ecf20Sopenharmony_ci if (ret) 1868c2ecf20Sopenharmony_ci goto err_gem_object_put; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci return 0; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cierr_gem_object_put: 1918c2ecf20Sopenharmony_ci for (i--; i >= 0; i--) 1928c2ecf20Sopenharmony_ci drm_gem_object_put(objs[i]); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci return ret; 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(drm_gem_fb_init_with_funcs); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci/** 1998c2ecf20Sopenharmony_ci * drm_gem_fb_create_with_funcs() - Helper function for the 2008c2ecf20Sopenharmony_ci * &drm_mode_config_funcs.fb_create 2018c2ecf20Sopenharmony_ci * callback 2028c2ecf20Sopenharmony_ci * @dev: DRM device 2038c2ecf20Sopenharmony_ci * @file: DRM file that holds the GEM handle(s) backing the framebuffer 2048c2ecf20Sopenharmony_ci * @mode_cmd: Metadata from the userspace framebuffer creation request 2058c2ecf20Sopenharmony_ci * @funcs: vtable to be used for the new framebuffer object 2068c2ecf20Sopenharmony_ci * 2078c2ecf20Sopenharmony_ci * This function can be used to set &drm_framebuffer_funcs for drivers that need 2088c2ecf20Sopenharmony_ci * custom framebuffer callbacks. Use drm_gem_fb_create() if you don't need to 2098c2ecf20Sopenharmony_ci * change &drm_framebuffer_funcs. The function does buffer size validation. 2108c2ecf20Sopenharmony_ci * 2118c2ecf20Sopenharmony_ci * Returns: 2128c2ecf20Sopenharmony_ci * Pointer to a &drm_framebuffer on success or an error pointer on failure. 2138c2ecf20Sopenharmony_ci */ 2148c2ecf20Sopenharmony_cistruct drm_framebuffer * 2158c2ecf20Sopenharmony_cidrm_gem_fb_create_with_funcs(struct drm_device *dev, struct drm_file *file, 2168c2ecf20Sopenharmony_ci const struct drm_mode_fb_cmd2 *mode_cmd, 2178c2ecf20Sopenharmony_ci const struct drm_framebuffer_funcs *funcs) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci struct drm_framebuffer *fb; 2208c2ecf20Sopenharmony_ci int ret; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci fb = kzalloc(sizeof(*fb), GFP_KERNEL); 2238c2ecf20Sopenharmony_ci if (!fb) 2248c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci ret = drm_gem_fb_init_with_funcs(dev, fb, file, mode_cmd, funcs); 2278c2ecf20Sopenharmony_ci if (ret) { 2288c2ecf20Sopenharmony_ci kfree(fb); 2298c2ecf20Sopenharmony_ci return ERR_PTR(ret); 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci return fb; 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(drm_gem_fb_create_with_funcs); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic const struct drm_framebuffer_funcs drm_gem_fb_funcs = { 2378c2ecf20Sopenharmony_ci .destroy = drm_gem_fb_destroy, 2388c2ecf20Sopenharmony_ci .create_handle = drm_gem_fb_create_handle, 2398c2ecf20Sopenharmony_ci}; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci/** 2428c2ecf20Sopenharmony_ci * drm_gem_fb_create() - Helper function for the 2438c2ecf20Sopenharmony_ci * &drm_mode_config_funcs.fb_create callback 2448c2ecf20Sopenharmony_ci * @dev: DRM device 2458c2ecf20Sopenharmony_ci * @file: DRM file that holds the GEM handle(s) backing the framebuffer 2468c2ecf20Sopenharmony_ci * @mode_cmd: Metadata from the userspace framebuffer creation request 2478c2ecf20Sopenharmony_ci * 2488c2ecf20Sopenharmony_ci * This function creates a new framebuffer object described by 2498c2ecf20Sopenharmony_ci * &drm_mode_fb_cmd2. This description includes handles for the buffer(s) 2508c2ecf20Sopenharmony_ci * backing the framebuffer. 2518c2ecf20Sopenharmony_ci * 2528c2ecf20Sopenharmony_ci * If your hardware has special alignment or pitch requirements these should be 2538c2ecf20Sopenharmony_ci * checked before calling this function. The function does buffer size 2548c2ecf20Sopenharmony_ci * validation. Use drm_gem_fb_create_with_dirty() if you need framebuffer 2558c2ecf20Sopenharmony_ci * flushing. 2568c2ecf20Sopenharmony_ci * 2578c2ecf20Sopenharmony_ci * Drivers can use this as their &drm_mode_config_funcs.fb_create callback. 2588c2ecf20Sopenharmony_ci * The ADDFB2 IOCTL calls into this callback. 2598c2ecf20Sopenharmony_ci * 2608c2ecf20Sopenharmony_ci * Returns: 2618c2ecf20Sopenharmony_ci * Pointer to a &drm_framebuffer on success or an error pointer on failure. 2628c2ecf20Sopenharmony_ci */ 2638c2ecf20Sopenharmony_cistruct drm_framebuffer * 2648c2ecf20Sopenharmony_cidrm_gem_fb_create(struct drm_device *dev, struct drm_file *file, 2658c2ecf20Sopenharmony_ci const struct drm_mode_fb_cmd2 *mode_cmd) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci return drm_gem_fb_create_with_funcs(dev, file, mode_cmd, 2688c2ecf20Sopenharmony_ci &drm_gem_fb_funcs); 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(drm_gem_fb_create); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cistatic const struct drm_framebuffer_funcs drm_gem_fb_funcs_dirtyfb = { 2738c2ecf20Sopenharmony_ci .destroy = drm_gem_fb_destroy, 2748c2ecf20Sopenharmony_ci .create_handle = drm_gem_fb_create_handle, 2758c2ecf20Sopenharmony_ci .dirty = drm_atomic_helper_dirtyfb, 2768c2ecf20Sopenharmony_ci}; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci/** 2798c2ecf20Sopenharmony_ci * drm_gem_fb_create_with_dirty() - Helper function for the 2808c2ecf20Sopenharmony_ci * &drm_mode_config_funcs.fb_create callback 2818c2ecf20Sopenharmony_ci * @dev: DRM device 2828c2ecf20Sopenharmony_ci * @file: DRM file that holds the GEM handle(s) backing the framebuffer 2838c2ecf20Sopenharmony_ci * @mode_cmd: Metadata from the userspace framebuffer creation request 2848c2ecf20Sopenharmony_ci * 2858c2ecf20Sopenharmony_ci * This function creates a new framebuffer object described by 2868c2ecf20Sopenharmony_ci * &drm_mode_fb_cmd2. This description includes handles for the buffer(s) 2878c2ecf20Sopenharmony_ci * backing the framebuffer. drm_atomic_helper_dirtyfb() is used for the dirty 2888c2ecf20Sopenharmony_ci * callback giving framebuffer flushing through the atomic machinery. Use 2898c2ecf20Sopenharmony_ci * drm_gem_fb_create() if you don't need the dirty callback. 2908c2ecf20Sopenharmony_ci * The function does buffer size validation. 2918c2ecf20Sopenharmony_ci * 2928c2ecf20Sopenharmony_ci * Drivers should also call drm_plane_enable_fb_damage_clips() on all planes 2938c2ecf20Sopenharmony_ci * to enable userspace to use damage clips also with the ATOMIC IOCTL. 2948c2ecf20Sopenharmony_ci * 2958c2ecf20Sopenharmony_ci * Drivers can use this as their &drm_mode_config_funcs.fb_create callback. 2968c2ecf20Sopenharmony_ci * The ADDFB2 IOCTL calls into this callback. 2978c2ecf20Sopenharmony_ci * 2988c2ecf20Sopenharmony_ci * Returns: 2998c2ecf20Sopenharmony_ci * Pointer to a &drm_framebuffer on success or an error pointer on failure. 3008c2ecf20Sopenharmony_ci */ 3018c2ecf20Sopenharmony_cistruct drm_framebuffer * 3028c2ecf20Sopenharmony_cidrm_gem_fb_create_with_dirty(struct drm_device *dev, struct drm_file *file, 3038c2ecf20Sopenharmony_ci const struct drm_mode_fb_cmd2 *mode_cmd) 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci return drm_gem_fb_create_with_funcs(dev, file, mode_cmd, 3068c2ecf20Sopenharmony_ci &drm_gem_fb_funcs_dirtyfb); 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(drm_gem_fb_create_with_dirty); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_cistatic __u32 drm_gem_afbc_get_bpp(struct drm_device *dev, 3118c2ecf20Sopenharmony_ci const struct drm_mode_fb_cmd2 *mode_cmd) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci const struct drm_format_info *info; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci info = drm_get_format_info(dev, mode_cmd); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci /* use whatever a driver has set */ 3188c2ecf20Sopenharmony_ci if (info->cpp[0]) 3198c2ecf20Sopenharmony_ci return info->cpp[0] * 8; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci /* guess otherwise */ 3228c2ecf20Sopenharmony_ci switch (info->format) { 3238c2ecf20Sopenharmony_ci case DRM_FORMAT_YUV420_8BIT: 3248c2ecf20Sopenharmony_ci return 12; 3258c2ecf20Sopenharmony_ci case DRM_FORMAT_YUV420_10BIT: 3268c2ecf20Sopenharmony_ci return 15; 3278c2ecf20Sopenharmony_ci case DRM_FORMAT_VUY101010: 3288c2ecf20Sopenharmony_ci return 30; 3298c2ecf20Sopenharmony_ci default: 3308c2ecf20Sopenharmony_ci break; 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci /* all attempts failed */ 3348c2ecf20Sopenharmony_ci return 0; 3358c2ecf20Sopenharmony_ci} 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_cistatic int drm_gem_afbc_min_size(struct drm_device *dev, 3388c2ecf20Sopenharmony_ci const struct drm_mode_fb_cmd2 *mode_cmd, 3398c2ecf20Sopenharmony_ci struct drm_afbc_framebuffer *afbc_fb) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci __u32 n_blocks, w_alignment, h_alignment, hdr_alignment; 3428c2ecf20Sopenharmony_ci /* remove bpp when all users properly encode cpp in drm_format_info */ 3438c2ecf20Sopenharmony_ci __u32 bpp; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci switch (mode_cmd->modifier[0] & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) { 3468c2ecf20Sopenharmony_ci case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16: 3478c2ecf20Sopenharmony_ci afbc_fb->block_width = 16; 3488c2ecf20Sopenharmony_ci afbc_fb->block_height = 16; 3498c2ecf20Sopenharmony_ci break; 3508c2ecf20Sopenharmony_ci case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8: 3518c2ecf20Sopenharmony_ci afbc_fb->block_width = 32; 3528c2ecf20Sopenharmony_ci afbc_fb->block_height = 8; 3538c2ecf20Sopenharmony_ci break; 3548c2ecf20Sopenharmony_ci /* no user exists yet - fall through */ 3558c2ecf20Sopenharmony_ci case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4: 3568c2ecf20Sopenharmony_ci case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4: 3578c2ecf20Sopenharmony_ci default: 3588c2ecf20Sopenharmony_ci drm_dbg_kms(dev, "Invalid AFBC_FORMAT_MOD_BLOCK_SIZE: %lld.\n", 3598c2ecf20Sopenharmony_ci mode_cmd->modifier[0] 3608c2ecf20Sopenharmony_ci & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK); 3618c2ecf20Sopenharmony_ci return -EINVAL; 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci /* tiled header afbc */ 3658c2ecf20Sopenharmony_ci w_alignment = afbc_fb->block_width; 3668c2ecf20Sopenharmony_ci h_alignment = afbc_fb->block_height; 3678c2ecf20Sopenharmony_ci hdr_alignment = AFBC_HDR_ALIGN; 3688c2ecf20Sopenharmony_ci if (mode_cmd->modifier[0] & AFBC_FORMAT_MOD_TILED) { 3698c2ecf20Sopenharmony_ci w_alignment *= AFBC_TH_LAYOUT_ALIGNMENT; 3708c2ecf20Sopenharmony_ci h_alignment *= AFBC_TH_LAYOUT_ALIGNMENT; 3718c2ecf20Sopenharmony_ci hdr_alignment = AFBC_TH_BODY_START_ALIGNMENT; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci afbc_fb->aligned_width = ALIGN(mode_cmd->width, w_alignment); 3758c2ecf20Sopenharmony_ci afbc_fb->aligned_height = ALIGN(mode_cmd->height, h_alignment); 3768c2ecf20Sopenharmony_ci afbc_fb->offset = mode_cmd->offsets[0]; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci bpp = drm_gem_afbc_get_bpp(dev, mode_cmd); 3798c2ecf20Sopenharmony_ci if (!bpp) { 3808c2ecf20Sopenharmony_ci drm_dbg_kms(dev, "Invalid AFBC bpp value: %d\n", bpp); 3818c2ecf20Sopenharmony_ci return -EINVAL; 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci n_blocks = (afbc_fb->aligned_width * afbc_fb->aligned_height) 3858c2ecf20Sopenharmony_ci / AFBC_SUPERBLOCK_PIXELS; 3868c2ecf20Sopenharmony_ci afbc_fb->afbc_size = ALIGN(n_blocks * AFBC_HEADER_SIZE, hdr_alignment); 3878c2ecf20Sopenharmony_ci afbc_fb->afbc_size += n_blocks * ALIGN(bpp * AFBC_SUPERBLOCK_PIXELS / 8, 3888c2ecf20Sopenharmony_ci AFBC_SUPERBLOCK_ALIGNMENT); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci return 0; 3918c2ecf20Sopenharmony_ci} 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci/** 3948c2ecf20Sopenharmony_ci * drm_gem_fb_afbc_init() - Helper function for drivers using afbc to 3958c2ecf20Sopenharmony_ci * fill and validate all the afbc-specific 3968c2ecf20Sopenharmony_ci * struct drm_afbc_framebuffer members 3978c2ecf20Sopenharmony_ci * 3988c2ecf20Sopenharmony_ci * @dev: DRM device 3998c2ecf20Sopenharmony_ci * @afbc_fb: afbc-specific framebuffer 4008c2ecf20Sopenharmony_ci * @mode_cmd: Metadata from the userspace framebuffer creation request 4018c2ecf20Sopenharmony_ci * @afbc_fb: afbc framebuffer 4028c2ecf20Sopenharmony_ci * 4038c2ecf20Sopenharmony_ci * This function can be used by drivers which support afbc to complete 4048c2ecf20Sopenharmony_ci * the preparation of struct drm_afbc_framebuffer. It must be called after 4058c2ecf20Sopenharmony_ci * allocating the said struct and calling drm_gem_fb_init_with_funcs(). 4068c2ecf20Sopenharmony_ci * It is caller's responsibility to put afbc_fb->base.obj objects in case 4078c2ecf20Sopenharmony_ci * the call is unsuccessful. 4088c2ecf20Sopenharmony_ci * 4098c2ecf20Sopenharmony_ci * Returns: 4108c2ecf20Sopenharmony_ci * Zero on success or a negative error value on failure. 4118c2ecf20Sopenharmony_ci */ 4128c2ecf20Sopenharmony_ciint drm_gem_fb_afbc_init(struct drm_device *dev, 4138c2ecf20Sopenharmony_ci const struct drm_mode_fb_cmd2 *mode_cmd, 4148c2ecf20Sopenharmony_ci struct drm_afbc_framebuffer *afbc_fb) 4158c2ecf20Sopenharmony_ci{ 4168c2ecf20Sopenharmony_ci const struct drm_format_info *info; 4178c2ecf20Sopenharmony_ci struct drm_gem_object **objs; 4188c2ecf20Sopenharmony_ci int ret; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci objs = afbc_fb->base.obj; 4218c2ecf20Sopenharmony_ci info = drm_get_format_info(dev, mode_cmd); 4228c2ecf20Sopenharmony_ci if (!info) 4238c2ecf20Sopenharmony_ci return -EINVAL; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci ret = drm_gem_afbc_min_size(dev, mode_cmd, afbc_fb); 4268c2ecf20Sopenharmony_ci if (ret < 0) 4278c2ecf20Sopenharmony_ci return ret; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci if (objs[0]->size < afbc_fb->afbc_size) 4308c2ecf20Sopenharmony_ci return -EINVAL; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci return 0; 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(drm_gem_fb_afbc_init); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci/** 4378c2ecf20Sopenharmony_ci * drm_gem_fb_prepare_fb() - Prepare a GEM backed framebuffer 4388c2ecf20Sopenharmony_ci * @plane: Plane 4398c2ecf20Sopenharmony_ci * @state: Plane state the fence will be attached to 4408c2ecf20Sopenharmony_ci * 4418c2ecf20Sopenharmony_ci * This function extracts the exclusive fence from &drm_gem_object.resv and 4428c2ecf20Sopenharmony_ci * attaches it to plane state for the atomic helper to wait on. This is 4438c2ecf20Sopenharmony_ci * necessary to correctly implement implicit synchronization for any buffers 4448c2ecf20Sopenharmony_ci * shared as a struct &dma_buf. This function can be used as the 4458c2ecf20Sopenharmony_ci * &drm_plane_helper_funcs.prepare_fb callback. 4468c2ecf20Sopenharmony_ci * 4478c2ecf20Sopenharmony_ci * There is no need for &drm_plane_helper_funcs.cleanup_fb hook for simple 4488c2ecf20Sopenharmony_ci * gem based framebuffer drivers which have their buffers always pinned in 4498c2ecf20Sopenharmony_ci * memory. 4508c2ecf20Sopenharmony_ci * 4518c2ecf20Sopenharmony_ci * See drm_atomic_set_fence_for_plane() for a discussion of implicit and 4528c2ecf20Sopenharmony_ci * explicit fencing in atomic modeset updates. 4538c2ecf20Sopenharmony_ci */ 4548c2ecf20Sopenharmony_ciint drm_gem_fb_prepare_fb(struct drm_plane *plane, 4558c2ecf20Sopenharmony_ci struct drm_plane_state *state) 4568c2ecf20Sopenharmony_ci{ 4578c2ecf20Sopenharmony_ci struct drm_gem_object *obj; 4588c2ecf20Sopenharmony_ci struct dma_fence *fence; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci if (!state->fb) 4618c2ecf20Sopenharmony_ci return 0; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci obj = drm_gem_fb_get_obj(state->fb, 0); 4648c2ecf20Sopenharmony_ci fence = dma_resv_get_excl_rcu(obj->resv); 4658c2ecf20Sopenharmony_ci drm_atomic_set_fence_for_plane(state, fence); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci return 0; 4688c2ecf20Sopenharmony_ci} 4698c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(drm_gem_fb_prepare_fb); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci/** 4728c2ecf20Sopenharmony_ci * drm_gem_fb_simple_display_pipe_prepare_fb - prepare_fb helper for 4738c2ecf20Sopenharmony_ci * &drm_simple_display_pipe 4748c2ecf20Sopenharmony_ci * @pipe: Simple display pipe 4758c2ecf20Sopenharmony_ci * @plane_state: Plane state 4768c2ecf20Sopenharmony_ci * 4778c2ecf20Sopenharmony_ci * This function uses drm_gem_fb_prepare_fb() to extract the exclusive fence 4788c2ecf20Sopenharmony_ci * from &drm_gem_object.resv and attaches it to plane state for the atomic 4798c2ecf20Sopenharmony_ci * helper to wait on. This is necessary to correctly implement implicit 4808c2ecf20Sopenharmony_ci * synchronization for any buffers shared as a struct &dma_buf. Drivers can use 4818c2ecf20Sopenharmony_ci * this as their &drm_simple_display_pipe_funcs.prepare_fb callback. 4828c2ecf20Sopenharmony_ci * 4838c2ecf20Sopenharmony_ci * See drm_atomic_set_fence_for_plane() for a discussion of implicit and 4848c2ecf20Sopenharmony_ci * explicit fencing in atomic modeset updates. 4858c2ecf20Sopenharmony_ci */ 4868c2ecf20Sopenharmony_ciint drm_gem_fb_simple_display_pipe_prepare_fb(struct drm_simple_display_pipe *pipe, 4878c2ecf20Sopenharmony_ci struct drm_plane_state *plane_state) 4888c2ecf20Sopenharmony_ci{ 4898c2ecf20Sopenharmony_ci return drm_gem_fb_prepare_fb(&pipe->plane, plane_state); 4908c2ecf20Sopenharmony_ci} 4918c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_gem_fb_simple_display_pipe_prepare_fb); 492