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