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