.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * drm gem framebuffer helper functions |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (C) 2017 Noralf Trønnes |
---|
5 | | - * |
---|
6 | | - * This program is free software; you can redistribute it and/or modify |
---|
7 | | - * it under the terms of the GNU General Public License as published by |
---|
8 | | - * the Free Software Foundation; either version 2 of the License, or |
---|
9 | | - * (at your option) any later version. |
---|
10 | 6 | */ |
---|
11 | 7 | |
---|
12 | 8 | #include <linux/dma-buf.h> |
---|
13 | 9 | #include <linux/dma-fence.h> |
---|
14 | | -#include <linux/reservation.h> |
---|
| 10 | +#include <linux/dma-resv.h> |
---|
15 | 11 | #include <linux/slab.h> |
---|
16 | 12 | |
---|
17 | | -#include <drm/drmP.h> |
---|
18 | 13 | #include <drm/drm_atomic.h> |
---|
| 14 | +#include <drm/drm_atomic_uapi.h> |
---|
| 15 | +#include <drm/drm_damage_helper.h> |
---|
19 | 16 | #include <drm/drm_fb_helper.h> |
---|
20 | 17 | #include <drm/drm_fourcc.h> |
---|
21 | 18 | #include <drm/drm_framebuffer.h> |
---|
.. | .. |
---|
23 | 20 | #include <drm/drm_gem_framebuffer_helper.h> |
---|
24 | 21 | #include <drm/drm_modeset_helper.h> |
---|
25 | 22 | #include <drm/drm_simple_kms_helper.h> |
---|
| 23 | + |
---|
| 24 | +#define AFBC_HEADER_SIZE 16 |
---|
| 25 | +#define AFBC_TH_LAYOUT_ALIGNMENT 8 |
---|
| 26 | +#define AFBC_HDR_ALIGN 64 |
---|
| 27 | +#define AFBC_SUPERBLOCK_PIXELS 256 |
---|
| 28 | +#define AFBC_SUPERBLOCK_ALIGNMENT 128 |
---|
| 29 | +#define AFBC_TH_BODY_START_ALIGNMENT 4096 |
---|
26 | 30 | |
---|
27 | 31 | /** |
---|
28 | 32 | * DOC: overview |
---|
.. | .. |
---|
57 | 61 | } |
---|
58 | 62 | EXPORT_SYMBOL_GPL(drm_gem_fb_get_obj); |
---|
59 | 63 | |
---|
60 | | -static struct drm_framebuffer * |
---|
61 | | -drm_gem_fb_alloc(struct drm_device *dev, |
---|
| 64 | +static int |
---|
| 65 | +drm_gem_fb_init(struct drm_device *dev, |
---|
| 66 | + struct drm_framebuffer *fb, |
---|
62 | 67 | const struct drm_mode_fb_cmd2 *mode_cmd, |
---|
63 | 68 | struct drm_gem_object **obj, unsigned int num_planes, |
---|
64 | 69 | const struct drm_framebuffer_funcs *funcs) |
---|
65 | 70 | { |
---|
66 | | - struct drm_framebuffer *fb; |
---|
67 | 71 | int ret, i; |
---|
68 | | - |
---|
69 | | - fb = kzalloc(sizeof(*fb), GFP_KERNEL); |
---|
70 | | - if (!fb) |
---|
71 | | - return ERR_PTR(-ENOMEM); |
---|
72 | 72 | |
---|
73 | 73 | drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd); |
---|
74 | 74 | |
---|
.. | .. |
---|
76 | 76 | fb->obj[i] = obj[i]; |
---|
77 | 77 | |
---|
78 | 78 | ret = drm_framebuffer_init(dev, fb, funcs); |
---|
79 | | - if (ret) { |
---|
80 | | - DRM_DEV_ERROR(dev->dev, "Failed to init framebuffer: %d\n", |
---|
81 | | - ret); |
---|
82 | | - kfree(fb); |
---|
83 | | - return ERR_PTR(ret); |
---|
84 | | - } |
---|
| 79 | + if (ret) |
---|
| 80 | + drm_err(dev, "Failed to init framebuffer: %d\n", ret); |
---|
85 | 81 | |
---|
86 | | - return fb; |
---|
| 82 | + return ret; |
---|
87 | 83 | } |
---|
88 | 84 | |
---|
89 | 85 | /** |
---|
.. | .. |
---|
99 | 95 | int i; |
---|
100 | 96 | |
---|
101 | 97 | for (i = 0; i < 4; i++) |
---|
102 | | - drm_gem_object_put_unlocked(fb->obj[i]); |
---|
| 98 | + drm_gem_object_put(fb->obj[i]); |
---|
103 | 99 | |
---|
104 | 100 | drm_framebuffer_cleanup(fb); |
---|
105 | 101 | kfree(fb); |
---|
.. | .. |
---|
127 | 123 | EXPORT_SYMBOL(drm_gem_fb_create_handle); |
---|
128 | 124 | |
---|
129 | 125 | /** |
---|
| 126 | + * drm_gem_fb_init_with_funcs() - Helper function for implementing |
---|
| 127 | + * &drm_mode_config_funcs.fb_create |
---|
| 128 | + * callback in cases when the driver |
---|
| 129 | + * allocates a subclass of |
---|
| 130 | + * struct drm_framebuffer |
---|
| 131 | + * @dev: DRM device |
---|
| 132 | + * @fb: framebuffer object |
---|
| 133 | + * @file: DRM file that holds the GEM handle(s) backing the framebuffer |
---|
| 134 | + * @mode_cmd: Metadata from the userspace framebuffer creation request |
---|
| 135 | + * @funcs: vtable to be used for the new framebuffer object |
---|
| 136 | + * |
---|
| 137 | + * This function can be used to set &drm_framebuffer_funcs for drivers that need |
---|
| 138 | + * custom framebuffer callbacks. Use drm_gem_fb_create() if you don't need to |
---|
| 139 | + * change &drm_framebuffer_funcs. The function does buffer size validation. |
---|
| 140 | + * The buffer size validation is for a general case, though, so users should |
---|
| 141 | + * pay attention to the checks being appropriate for them or, at least, |
---|
| 142 | + * non-conflicting. |
---|
| 143 | + * |
---|
| 144 | + * Returns: |
---|
| 145 | + * Zero or a negative error code. |
---|
| 146 | + */ |
---|
| 147 | +int drm_gem_fb_init_with_funcs(struct drm_device *dev, |
---|
| 148 | + struct drm_framebuffer *fb, |
---|
| 149 | + struct drm_file *file, |
---|
| 150 | + const struct drm_mode_fb_cmd2 *mode_cmd, |
---|
| 151 | + const struct drm_framebuffer_funcs *funcs) |
---|
| 152 | +{ |
---|
| 153 | + const struct drm_format_info *info; |
---|
| 154 | + struct drm_gem_object *objs[4]; |
---|
| 155 | + int ret, i; |
---|
| 156 | + |
---|
| 157 | + info = drm_get_format_info(dev, mode_cmd); |
---|
| 158 | + if (!info) { |
---|
| 159 | + drm_dbg_kms(dev, "Failed to get FB format info\n"); |
---|
| 160 | + return -EINVAL; |
---|
| 161 | + } |
---|
| 162 | + |
---|
| 163 | + for (i = 0; i < info->num_planes; i++) { |
---|
| 164 | + unsigned int width = mode_cmd->width / (i ? info->hsub : 1); |
---|
| 165 | + unsigned int height = mode_cmd->height / (i ? info->vsub : 1); |
---|
| 166 | + unsigned int min_size; |
---|
| 167 | + |
---|
| 168 | + objs[i] = drm_gem_object_lookup(file, mode_cmd->handles[i]); |
---|
| 169 | + if (!objs[i]) { |
---|
| 170 | + drm_dbg_kms(dev, "Failed to lookup GEM object\n"); |
---|
| 171 | + ret = -ENOENT; |
---|
| 172 | + goto err_gem_object_put; |
---|
| 173 | + } |
---|
| 174 | + |
---|
| 175 | + min_size = (height - 1) * mode_cmd->pitches[i] |
---|
| 176 | + + drm_format_info_min_pitch(info, i, width) |
---|
| 177 | + + mode_cmd->offsets[i]; |
---|
| 178 | + |
---|
| 179 | + if (objs[i]->size < min_size) { |
---|
| 180 | + drm_dbg_kms(dev, |
---|
| 181 | + "GEM object size (%zu) smaller than minimum size (%u) for plane %d\n", |
---|
| 182 | + objs[i]->size, min_size, i); |
---|
| 183 | + drm_gem_object_put(objs[i]); |
---|
| 184 | + ret = -EINVAL; |
---|
| 185 | + goto err_gem_object_put; |
---|
| 186 | + } |
---|
| 187 | + } |
---|
| 188 | + |
---|
| 189 | + ret = drm_gem_fb_init(dev, fb, mode_cmd, objs, i, funcs); |
---|
| 190 | + if (ret) |
---|
| 191 | + goto err_gem_object_put; |
---|
| 192 | + |
---|
| 193 | + return 0; |
---|
| 194 | + |
---|
| 195 | +err_gem_object_put: |
---|
| 196 | + for (i--; i >= 0; i--) |
---|
| 197 | + drm_gem_object_put(objs[i]); |
---|
| 198 | + |
---|
| 199 | + return ret; |
---|
| 200 | +} |
---|
| 201 | +EXPORT_SYMBOL_GPL(drm_gem_fb_init_with_funcs); |
---|
| 202 | + |
---|
| 203 | +/** |
---|
130 | 204 | * drm_gem_fb_create_with_funcs() - Helper function for the |
---|
131 | 205 | * &drm_mode_config_funcs.fb_create |
---|
132 | 206 | * callback |
---|
.. | .. |
---|
135 | 209 | * @mode_cmd: Metadata from the userspace framebuffer creation request |
---|
136 | 210 | * @funcs: vtable to be used for the new framebuffer object |
---|
137 | 211 | * |
---|
138 | | - * This can be used to set &drm_framebuffer_funcs for drivers that need the |
---|
139 | | - * &drm_framebuffer_funcs.dirty callback. Use drm_gem_fb_create() if you don't |
---|
140 | | - * need to change &drm_framebuffer_funcs. |
---|
141 | | - * The function does buffer size validation. |
---|
| 212 | + * This function can be used to set &drm_framebuffer_funcs for drivers that need |
---|
| 213 | + * custom framebuffer callbacks. Use drm_gem_fb_create() if you don't need to |
---|
| 214 | + * change &drm_framebuffer_funcs. The function does buffer size validation. |
---|
142 | 215 | * |
---|
143 | 216 | * Returns: |
---|
144 | 217 | * Pointer to a &drm_framebuffer on success or an error pointer on failure. |
---|
.. | .. |
---|
148 | 221 | const struct drm_mode_fb_cmd2 *mode_cmd, |
---|
149 | 222 | const struct drm_framebuffer_funcs *funcs) |
---|
150 | 223 | { |
---|
151 | | - const struct drm_format_info *info; |
---|
152 | | - struct drm_gem_object *objs[4]; |
---|
153 | 224 | struct drm_framebuffer *fb; |
---|
154 | | - int ret, i; |
---|
| 225 | + int ret; |
---|
155 | 226 | |
---|
156 | | - info = drm_get_format_info(dev, mode_cmd); |
---|
157 | | - if (!info) |
---|
158 | | - return ERR_PTR(-EINVAL); |
---|
| 227 | + fb = kzalloc(sizeof(*fb), GFP_KERNEL); |
---|
| 228 | + if (!fb) |
---|
| 229 | + return ERR_PTR(-ENOMEM); |
---|
159 | 230 | |
---|
160 | | - for (i = 0; i < info->num_planes; i++) { |
---|
161 | | - unsigned int width = mode_cmd->width / (i ? info->hsub : 1); |
---|
162 | | - unsigned int height = mode_cmd->height / (i ? info->vsub : 1); |
---|
163 | | - unsigned int min_size; |
---|
164 | | - |
---|
165 | | - objs[i] = drm_gem_object_lookup(file, mode_cmd->handles[i]); |
---|
166 | | - if (!objs[i]) { |
---|
167 | | - DRM_DEBUG_KMS("Failed to lookup GEM object\n"); |
---|
168 | | - ret = -ENOENT; |
---|
169 | | - goto err_gem_object_put; |
---|
170 | | - } |
---|
171 | | - |
---|
172 | | - min_size = (height - 1) * mode_cmd->pitches[i] |
---|
173 | | - + width * info->bpp[i] / 8 |
---|
174 | | - + mode_cmd->offsets[i]; |
---|
175 | | - |
---|
176 | | - if (objs[i]->size < min_size) { |
---|
177 | | - drm_gem_object_put_unlocked(objs[i]); |
---|
178 | | - ret = -EINVAL; |
---|
179 | | - goto err_gem_object_put; |
---|
180 | | - } |
---|
181 | | - } |
---|
182 | | - |
---|
183 | | - fb = drm_gem_fb_alloc(dev, mode_cmd, objs, i, funcs); |
---|
184 | | - if (IS_ERR(fb)) { |
---|
185 | | - ret = PTR_ERR(fb); |
---|
186 | | - goto err_gem_object_put; |
---|
| 231 | + ret = drm_gem_fb_init_with_funcs(dev, fb, file, mode_cmd, funcs); |
---|
| 232 | + if (ret) { |
---|
| 233 | + kfree(fb); |
---|
| 234 | + return ERR_PTR(ret); |
---|
187 | 235 | } |
---|
188 | 236 | |
---|
189 | 237 | return fb; |
---|
190 | | - |
---|
191 | | -err_gem_object_put: |
---|
192 | | - for (i--; i >= 0; i--) |
---|
193 | | - drm_gem_object_put_unlocked(objs[i]); |
---|
194 | | - |
---|
195 | | - return ERR_PTR(ret); |
---|
196 | 238 | } |
---|
197 | 239 | EXPORT_SYMBOL_GPL(drm_gem_fb_create_with_funcs); |
---|
198 | 240 | |
---|
.. | .. |
---|
214 | 256 | * |
---|
215 | 257 | * If your hardware has special alignment or pitch requirements these should be |
---|
216 | 258 | * checked before calling this function. The function does buffer size |
---|
217 | | - * validation. Use drm_gem_fb_create_with_funcs() if you need to set |
---|
218 | | - * &drm_framebuffer_funcs.dirty. |
---|
| 259 | + * validation. Use drm_gem_fb_create_with_dirty() if you need framebuffer |
---|
| 260 | + * flushing. |
---|
219 | 261 | * |
---|
220 | 262 | * Drivers can use this as their &drm_mode_config_funcs.fb_create callback. |
---|
221 | 263 | * The ADDFB2 IOCTL calls into this callback. |
---|
.. | .. |
---|
232 | 274 | } |
---|
233 | 275 | EXPORT_SYMBOL_GPL(drm_gem_fb_create); |
---|
234 | 276 | |
---|
| 277 | +static const struct drm_framebuffer_funcs drm_gem_fb_funcs_dirtyfb = { |
---|
| 278 | + .destroy = drm_gem_fb_destroy, |
---|
| 279 | + .create_handle = drm_gem_fb_create_handle, |
---|
| 280 | + .dirty = drm_atomic_helper_dirtyfb, |
---|
| 281 | +}; |
---|
| 282 | + |
---|
| 283 | +/** |
---|
| 284 | + * drm_gem_fb_create_with_dirty() - Helper function for the |
---|
| 285 | + * &drm_mode_config_funcs.fb_create callback |
---|
| 286 | + * @dev: DRM device |
---|
| 287 | + * @file: DRM file that holds the GEM handle(s) backing the framebuffer |
---|
| 288 | + * @mode_cmd: Metadata from the userspace framebuffer creation request |
---|
| 289 | + * |
---|
| 290 | + * This function creates a new framebuffer object described by |
---|
| 291 | + * &drm_mode_fb_cmd2. This description includes handles for the buffer(s) |
---|
| 292 | + * backing the framebuffer. drm_atomic_helper_dirtyfb() is used for the dirty |
---|
| 293 | + * callback giving framebuffer flushing through the atomic machinery. Use |
---|
| 294 | + * drm_gem_fb_create() if you don't need the dirty callback. |
---|
| 295 | + * The function does buffer size validation. |
---|
| 296 | + * |
---|
| 297 | + * Drivers should also call drm_plane_enable_fb_damage_clips() on all planes |
---|
| 298 | + * to enable userspace to use damage clips also with the ATOMIC IOCTL. |
---|
| 299 | + * |
---|
| 300 | + * Drivers can use this as their &drm_mode_config_funcs.fb_create callback. |
---|
| 301 | + * The ADDFB2 IOCTL calls into this callback. |
---|
| 302 | + * |
---|
| 303 | + * Returns: |
---|
| 304 | + * Pointer to a &drm_framebuffer on success or an error pointer on failure. |
---|
| 305 | + */ |
---|
| 306 | +struct drm_framebuffer * |
---|
| 307 | +drm_gem_fb_create_with_dirty(struct drm_device *dev, struct drm_file *file, |
---|
| 308 | + const struct drm_mode_fb_cmd2 *mode_cmd) |
---|
| 309 | +{ |
---|
| 310 | + return drm_gem_fb_create_with_funcs(dev, file, mode_cmd, |
---|
| 311 | + &drm_gem_fb_funcs_dirtyfb); |
---|
| 312 | +} |
---|
| 313 | +EXPORT_SYMBOL_GPL(drm_gem_fb_create_with_dirty); |
---|
| 314 | + |
---|
| 315 | +static __u32 drm_gem_afbc_get_bpp(struct drm_device *dev, |
---|
| 316 | + const struct drm_mode_fb_cmd2 *mode_cmd) |
---|
| 317 | +{ |
---|
| 318 | + const struct drm_format_info *info; |
---|
| 319 | + |
---|
| 320 | + info = drm_get_format_info(dev, mode_cmd); |
---|
| 321 | + |
---|
| 322 | + /* use whatever a driver has set */ |
---|
| 323 | + if (info->cpp[0]) |
---|
| 324 | + return info->cpp[0] * 8; |
---|
| 325 | + |
---|
| 326 | + /* guess otherwise */ |
---|
| 327 | + switch (info->format) { |
---|
| 328 | + case DRM_FORMAT_YUV420_8BIT: |
---|
| 329 | + return 12; |
---|
| 330 | + case DRM_FORMAT_YUV420_10BIT: |
---|
| 331 | + return 15; |
---|
| 332 | + case DRM_FORMAT_VUY101010: |
---|
| 333 | + return 30; |
---|
| 334 | + default: |
---|
| 335 | + break; |
---|
| 336 | + } |
---|
| 337 | + |
---|
| 338 | + /* all attempts failed */ |
---|
| 339 | + return 0; |
---|
| 340 | +} |
---|
| 341 | + |
---|
| 342 | +static int drm_gem_afbc_min_size(struct drm_device *dev, |
---|
| 343 | + const struct drm_mode_fb_cmd2 *mode_cmd, |
---|
| 344 | + struct drm_afbc_framebuffer *afbc_fb) |
---|
| 345 | +{ |
---|
| 346 | + __u32 n_blocks, w_alignment, h_alignment, hdr_alignment; |
---|
| 347 | + /* remove bpp when all users properly encode cpp in drm_format_info */ |
---|
| 348 | + __u32 bpp; |
---|
| 349 | + |
---|
| 350 | + switch (mode_cmd->modifier[0] & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) { |
---|
| 351 | + case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16: |
---|
| 352 | + afbc_fb->block_width = 16; |
---|
| 353 | + afbc_fb->block_height = 16; |
---|
| 354 | + break; |
---|
| 355 | + case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8: |
---|
| 356 | + afbc_fb->block_width = 32; |
---|
| 357 | + afbc_fb->block_height = 8; |
---|
| 358 | + break; |
---|
| 359 | + /* no user exists yet - fall through */ |
---|
| 360 | + case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4: |
---|
| 361 | + case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4: |
---|
| 362 | + default: |
---|
| 363 | + drm_dbg_kms(dev, "Invalid AFBC_FORMAT_MOD_BLOCK_SIZE: %lld.\n", |
---|
| 364 | + mode_cmd->modifier[0] |
---|
| 365 | + & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK); |
---|
| 366 | + return -EINVAL; |
---|
| 367 | + } |
---|
| 368 | + |
---|
| 369 | + /* tiled header afbc */ |
---|
| 370 | + w_alignment = afbc_fb->block_width; |
---|
| 371 | + h_alignment = afbc_fb->block_height; |
---|
| 372 | + hdr_alignment = AFBC_HDR_ALIGN; |
---|
| 373 | + if (mode_cmd->modifier[0] & AFBC_FORMAT_MOD_TILED) { |
---|
| 374 | + w_alignment *= AFBC_TH_LAYOUT_ALIGNMENT; |
---|
| 375 | + h_alignment *= AFBC_TH_LAYOUT_ALIGNMENT; |
---|
| 376 | + hdr_alignment = AFBC_TH_BODY_START_ALIGNMENT; |
---|
| 377 | + } |
---|
| 378 | + |
---|
| 379 | + afbc_fb->aligned_width = ALIGN(mode_cmd->width, w_alignment); |
---|
| 380 | + afbc_fb->aligned_height = ALIGN(mode_cmd->height, h_alignment); |
---|
| 381 | + afbc_fb->offset = mode_cmd->offsets[0]; |
---|
| 382 | + |
---|
| 383 | + bpp = drm_gem_afbc_get_bpp(dev, mode_cmd); |
---|
| 384 | + if (!bpp) { |
---|
| 385 | + drm_dbg_kms(dev, "Invalid AFBC bpp value: %d\n", bpp); |
---|
| 386 | + return -EINVAL; |
---|
| 387 | + } |
---|
| 388 | + |
---|
| 389 | + n_blocks = (afbc_fb->aligned_width * afbc_fb->aligned_height) |
---|
| 390 | + / AFBC_SUPERBLOCK_PIXELS; |
---|
| 391 | + afbc_fb->afbc_size = ALIGN(n_blocks * AFBC_HEADER_SIZE, hdr_alignment); |
---|
| 392 | + afbc_fb->afbc_size += n_blocks * ALIGN(bpp * AFBC_SUPERBLOCK_PIXELS / 8, |
---|
| 393 | + AFBC_SUPERBLOCK_ALIGNMENT); |
---|
| 394 | + |
---|
| 395 | + return 0; |
---|
| 396 | +} |
---|
| 397 | + |
---|
| 398 | +/** |
---|
| 399 | + * drm_gem_fb_afbc_init() - Helper function for drivers using afbc to |
---|
| 400 | + * fill and validate all the afbc-specific |
---|
| 401 | + * struct drm_afbc_framebuffer members |
---|
| 402 | + * |
---|
| 403 | + * @dev: DRM device |
---|
| 404 | + * @afbc_fb: afbc-specific framebuffer |
---|
| 405 | + * @mode_cmd: Metadata from the userspace framebuffer creation request |
---|
| 406 | + * @afbc_fb: afbc framebuffer |
---|
| 407 | + * |
---|
| 408 | + * This function can be used by drivers which support afbc to complete |
---|
| 409 | + * the preparation of struct drm_afbc_framebuffer. It must be called after |
---|
| 410 | + * allocating the said struct and calling drm_gem_fb_init_with_funcs(). |
---|
| 411 | + * It is caller's responsibility to put afbc_fb->base.obj objects in case |
---|
| 412 | + * the call is unsuccessful. |
---|
| 413 | + * |
---|
| 414 | + * Returns: |
---|
| 415 | + * Zero on success or a negative error value on failure. |
---|
| 416 | + */ |
---|
| 417 | +int drm_gem_fb_afbc_init(struct drm_device *dev, |
---|
| 418 | + const struct drm_mode_fb_cmd2 *mode_cmd, |
---|
| 419 | + struct drm_afbc_framebuffer *afbc_fb) |
---|
| 420 | +{ |
---|
| 421 | + const struct drm_format_info *info; |
---|
| 422 | + struct drm_gem_object **objs; |
---|
| 423 | + int ret; |
---|
| 424 | + |
---|
| 425 | + objs = afbc_fb->base.obj; |
---|
| 426 | + info = drm_get_format_info(dev, mode_cmd); |
---|
| 427 | + if (!info) |
---|
| 428 | + return -EINVAL; |
---|
| 429 | + |
---|
| 430 | + ret = drm_gem_afbc_min_size(dev, mode_cmd, afbc_fb); |
---|
| 431 | + if (ret < 0) |
---|
| 432 | + return ret; |
---|
| 433 | + |
---|
| 434 | + if (objs[0]->size < afbc_fb->afbc_size) |
---|
| 435 | + return -EINVAL; |
---|
| 436 | + |
---|
| 437 | + return 0; |
---|
| 438 | +} |
---|
| 439 | +EXPORT_SYMBOL_GPL(drm_gem_fb_afbc_init); |
---|
| 440 | + |
---|
235 | 441 | /** |
---|
236 | 442 | * drm_gem_fb_prepare_fb() - Prepare a GEM backed framebuffer |
---|
237 | 443 | * @plane: Plane |
---|
238 | 444 | * @state: Plane state the fence will be attached to |
---|
239 | 445 | * |
---|
240 | | - * This function prepares a GEM backed framebuffer for scanout by checking if |
---|
241 | | - * the plane framebuffer has a DMA-BUF attached. If it does, it extracts the |
---|
242 | | - * exclusive fence and attaches it to the plane state for the atomic helper to |
---|
243 | | - * wait on. This function can be used as the &drm_plane_helper_funcs.prepare_fb |
---|
244 | | - * callback. |
---|
| 446 | + * This function extracts the exclusive fence from &drm_gem_object.resv and |
---|
| 447 | + * attaches it to plane state for the atomic helper to wait on. This is |
---|
| 448 | + * necessary to correctly implement implicit synchronization for any buffers |
---|
| 449 | + * shared as a struct &dma_buf. This function can be used as the |
---|
| 450 | + * &drm_plane_helper_funcs.prepare_fb callback. |
---|
245 | 451 | * |
---|
246 | 452 | * There is no need for &drm_plane_helper_funcs.cleanup_fb hook for simple |
---|
247 | 453 | * gem based framebuffer drivers which have their buffers always pinned in |
---|
248 | 454 | * memory. |
---|
| 455 | + * |
---|
| 456 | + * See drm_atomic_set_fence_for_plane() for a discussion of implicit and |
---|
| 457 | + * explicit fencing in atomic modeset updates. |
---|
249 | 458 | */ |
---|
250 | 459 | int drm_gem_fb_prepare_fb(struct drm_plane *plane, |
---|
251 | 460 | struct drm_plane_state *state) |
---|
252 | 461 | { |
---|
253 | | - struct dma_buf *dma_buf; |
---|
| 462 | + struct drm_gem_object *obj; |
---|
254 | 463 | struct dma_fence *fence; |
---|
255 | 464 | |
---|
256 | 465 | if (!state->fb) |
---|
257 | 466 | return 0; |
---|
258 | 467 | |
---|
259 | | - dma_buf = drm_gem_fb_get_obj(state->fb, 0)->dma_buf; |
---|
260 | | - if (dma_buf) { |
---|
261 | | - fence = reservation_object_get_excl_rcu(dma_buf->resv); |
---|
262 | | - drm_atomic_set_fence_for_plane(state, fence); |
---|
263 | | - } |
---|
| 468 | + obj = drm_gem_fb_get_obj(state->fb, 0); |
---|
| 469 | + fence = dma_resv_get_excl_rcu(obj->resv); |
---|
| 470 | + drm_atomic_set_fence_for_plane(state, fence); |
---|
264 | 471 | |
---|
265 | 472 | return 0; |
---|
266 | 473 | } |
---|
.. | .. |
---|
272 | 479 | * @pipe: Simple display pipe |
---|
273 | 480 | * @plane_state: Plane state |
---|
274 | 481 | * |
---|
275 | | - * This function uses drm_gem_fb_prepare_fb() to check if the plane FB has a |
---|
276 | | - * &dma_buf attached, extracts the exclusive fence and attaches it to plane |
---|
277 | | - * state for the atomic helper to wait on. Drivers can use this as their |
---|
278 | | - * &drm_simple_display_pipe_funcs.prepare_fb callback. |
---|
| 482 | + * This function uses drm_gem_fb_prepare_fb() to extract the exclusive fence |
---|
| 483 | + * from &drm_gem_object.resv and attaches it to plane state for the atomic |
---|
| 484 | + * helper to wait on. This is necessary to correctly implement implicit |
---|
| 485 | + * synchronization for any buffers shared as a struct &dma_buf. Drivers can use |
---|
| 486 | + * this as their &drm_simple_display_pipe_funcs.prepare_fb callback. |
---|
| 487 | + * |
---|
| 488 | + * See drm_atomic_set_fence_for_plane() for a discussion of implicit and |
---|
| 489 | + * explicit fencing in atomic modeset updates. |
---|
279 | 490 | */ |
---|
280 | 491 | int drm_gem_fb_simple_display_pipe_prepare_fb(struct drm_simple_display_pipe *pipe, |
---|
281 | 492 | struct drm_plane_state *plane_state) |
---|
.. | .. |
---|
283 | 494 | return drm_gem_fb_prepare_fb(&pipe->plane, plane_state); |
---|
284 | 495 | } |
---|
285 | 496 | EXPORT_SYMBOL(drm_gem_fb_simple_display_pipe_prepare_fb); |
---|
286 | | - |
---|
287 | | -/** |
---|
288 | | - * drm_gem_fbdev_fb_create - Create a GEM backed &drm_framebuffer for fbdev |
---|
289 | | - * emulation |
---|
290 | | - * @dev: DRM device |
---|
291 | | - * @sizes: fbdev size description |
---|
292 | | - * @pitch_align: Optional pitch alignment |
---|
293 | | - * @obj: GEM object backing the framebuffer |
---|
294 | | - * @funcs: Optional vtable to be used for the new framebuffer object when the |
---|
295 | | - * dirty callback is needed. |
---|
296 | | - * |
---|
297 | | - * This function creates a framebuffer from a &drm_fb_helper_surface_size |
---|
298 | | - * description for use in the &drm_fb_helper_funcs.fb_probe callback. |
---|
299 | | - * |
---|
300 | | - * Returns: |
---|
301 | | - * Pointer to a &drm_framebuffer on success or an error pointer on failure. |
---|
302 | | - */ |
---|
303 | | -struct drm_framebuffer * |
---|
304 | | -drm_gem_fbdev_fb_create(struct drm_device *dev, |
---|
305 | | - struct drm_fb_helper_surface_size *sizes, |
---|
306 | | - unsigned int pitch_align, struct drm_gem_object *obj, |
---|
307 | | - const struct drm_framebuffer_funcs *funcs) |
---|
308 | | -{ |
---|
309 | | - struct drm_mode_fb_cmd2 mode_cmd = { 0 }; |
---|
310 | | - |
---|
311 | | - mode_cmd.width = sizes->surface_width; |
---|
312 | | - mode_cmd.height = sizes->surface_height; |
---|
313 | | - mode_cmd.pitches[0] = sizes->surface_width * |
---|
314 | | - DIV_ROUND_UP(sizes->surface_bpp, 8); |
---|
315 | | - if (pitch_align) |
---|
316 | | - mode_cmd.pitches[0] = roundup(mode_cmd.pitches[0], |
---|
317 | | - pitch_align); |
---|
318 | | - mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, |
---|
319 | | - sizes->surface_depth); |
---|
320 | | - if (obj->size < mode_cmd.pitches[0] * mode_cmd.height) |
---|
321 | | - return ERR_PTR(-EINVAL); |
---|
322 | | - |
---|
323 | | - if (!funcs) |
---|
324 | | - funcs = &drm_gem_fb_funcs; |
---|
325 | | - |
---|
326 | | - return drm_gem_fb_alloc(dev, &mode_cmd, &obj, 1, funcs); |
---|
327 | | -} |
---|
328 | | -EXPORT_SYMBOL(drm_gem_fbdev_fb_create); |
---|