Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/core: Add drm_afbc_framebuffer and a corresponding helper

The new struct contains afbc-specific data.

The new function can be used by drivers which support afbc to complete
the preparation of struct drm_afbc_framebuffer. It must be called after
allocating the said struct and calling drm_gem_fb_init_with_funcs().

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
Reviewed-by: James Qian Wang <james.qian.wang@arm.com>
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: https://patchwork.freedesktop.org/patch/msgid/20200311145541.29186-3-andrzej.p@collabora.com

+178
+15
Documentation/gpu/todo.rst
··· 404 404 405 405 Level: Intermediate 406 406 407 + Encode cpp properly in malidp 408 + ----------------------------- 409 + 410 + cpp (chars per pixel) is not encoded properly in malidp, zero is 411 + used instead. afbc implementation needs bpp or cpp, but if it is 412 + zero it needs to be provided elsewhere, and so the bpp field exists 413 + in struct drm_afbc_framebuffer. 414 + 415 + Properly encode cpp in malidp and remove the bpp field in struct 416 + drm_afbc_framebuffer. 417 + 418 + Contact: malidp maintainers 419 + 420 + Level: Intermediate 421 + 407 422 Core refactorings 408 423 ================= 409 424
+108
drivers/gpu/drm/drm_gem_framebuffer_helper.c
··· 21 21 #include <drm/drm_modeset_helper.h> 22 22 #include <drm/drm_simple_kms_helper.h> 23 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 30 + 24 31 /** 25 32 * DOC: overview 26 33 * ··· 308 301 &drm_gem_fb_funcs_dirtyfb); 309 302 } 310 303 EXPORT_SYMBOL_GPL(drm_gem_fb_create_with_dirty); 304 + 305 + static int drm_gem_afbc_min_size(struct drm_device *dev, 306 + const struct drm_mode_fb_cmd2 *mode_cmd, 307 + struct drm_afbc_framebuffer *afbc_fb) 308 + { 309 + const struct drm_format_info *info; 310 + __u32 n_blocks, w_alignment, h_alignment, hdr_alignment; 311 + /* remove bpp when all users properly encode cpp in drm_format_info */ 312 + __u32 bpp; 313 + 314 + switch (mode_cmd->modifier[0] & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) { 315 + case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16: 316 + afbc_fb->block_width = 16; 317 + afbc_fb->block_height = 16; 318 + break; 319 + case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8: 320 + afbc_fb->block_width = 32; 321 + afbc_fb->block_height = 8; 322 + break; 323 + /* no user exists yet - fall through */ 324 + case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4: 325 + case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4: 326 + default: 327 + DRM_DEBUG_KMS("Invalid AFBC_FORMAT_MOD_BLOCK_SIZE: %lld.\n", 328 + mode_cmd->modifier[0] 329 + & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK); 330 + return -EINVAL; 331 + } 332 + 333 + /* tiled header afbc */ 334 + w_alignment = afbc_fb->block_width; 335 + h_alignment = afbc_fb->block_height; 336 + hdr_alignment = AFBC_HDR_ALIGN; 337 + if (mode_cmd->modifier[0] & AFBC_FORMAT_MOD_TILED) { 338 + w_alignment *= AFBC_TH_LAYOUT_ALIGNMENT; 339 + h_alignment *= AFBC_TH_LAYOUT_ALIGNMENT; 340 + hdr_alignment = AFBC_TH_BODY_START_ALIGNMENT; 341 + } 342 + 343 + afbc_fb->aligned_width = ALIGN(mode_cmd->width, w_alignment); 344 + afbc_fb->aligned_height = ALIGN(mode_cmd->height, h_alignment); 345 + afbc_fb->offset = mode_cmd->offsets[0]; 346 + 347 + info = drm_get_format_info(dev, mode_cmd); 348 + /* 349 + * Change to always using info->cpp[0] 350 + * when all users properly encode it 351 + */ 352 + bpp = info->cpp[0] ? info->cpp[0] * 8 : afbc_fb->bpp; 353 + 354 + n_blocks = (afbc_fb->aligned_width * afbc_fb->aligned_height) 355 + / AFBC_SUPERBLOCK_PIXELS; 356 + afbc_fb->afbc_size = ALIGN(n_blocks * AFBC_HEADER_SIZE, hdr_alignment); 357 + afbc_fb->afbc_size += n_blocks * ALIGN(bpp * AFBC_SUPERBLOCK_PIXELS / 8, 358 + AFBC_SUPERBLOCK_ALIGNMENT); 359 + 360 + return 0; 361 + } 362 + 363 + /** 364 + * drm_gem_fb_afbc_init() - Helper function for drivers using afbc to 365 + * fill and validate all the afbc-specific 366 + * struct drm_afbc_framebuffer members 367 + * 368 + * @dev: DRM device 369 + * @afbc_fb: afbc-specific framebuffer 370 + * @mode_cmd: Metadata from the userspace framebuffer creation request 371 + * @afbc_fb: afbc framebuffer 372 + * 373 + * This function can be used by drivers which support afbc to complete 374 + * the preparation of struct drm_afbc_framebuffer. It must be called after 375 + * allocating the said struct and calling drm_gem_fb_init_with_funcs(). 376 + * It is caller's responsibility to put afbc_fb->base.obj objects in case 377 + * the call is unsuccessful. 378 + * 379 + * Returns: 380 + * Zero on success or a negative error value on failure. 381 + */ 382 + int drm_gem_fb_afbc_init(struct drm_device *dev, 383 + const struct drm_mode_fb_cmd2 *mode_cmd, 384 + struct drm_afbc_framebuffer *afbc_fb) 385 + { 386 + const struct drm_format_info *info; 387 + struct drm_gem_object **objs; 388 + int ret; 389 + 390 + objs = afbc_fb->base.obj; 391 + info = drm_get_format_info(dev, mode_cmd); 392 + if (!info) 393 + return -EINVAL; 394 + 395 + ret = drm_gem_afbc_min_size(dev, mode_cmd, afbc_fb); 396 + if (ret < 0) 397 + return ret; 398 + 399 + if (objs[0]->size < afbc_fb->afbc_size) 400 + return -EINVAL; 401 + 402 + return 0; 403 + } 404 + EXPORT_SYMBOL_GPL(drm_gem_fb_afbc_init); 311 405 312 406 /** 313 407 * drm_gem_fb_prepare_fb() - Prepare a GEM backed framebuffer
+45
include/drm/drm_framebuffer.h
··· 297 297 int drm_framebuffer_plane_height(int height, 298 298 const struct drm_framebuffer *fb, int plane); 299 299 300 + /** 301 + * struct drm_afbc_framebuffer - a special afbc frame buffer object 302 + * 303 + * A derived class of struct drm_framebuffer, dedicated for afbc use cases. 304 + */ 305 + struct drm_afbc_framebuffer { 306 + /** 307 + * @base: base framebuffer structure. 308 + */ 309 + struct drm_framebuffer base; 310 + /** 311 + * @block_widht: width of a single afbc block 312 + */ 313 + u32 block_width; 314 + /** 315 + * @block_widht: height of a single afbc block 316 + */ 317 + u32 block_height; 318 + /** 319 + * @aligned_width: aligned frame buffer width 320 + */ 321 + u32 aligned_width; 322 + /** 323 + * @aligned_height: aligned frame buffer height 324 + */ 325 + u32 aligned_height; 326 + /** 327 + * @offset: offset of the first afbc header 328 + */ 329 + u32 offset; 330 + /** 331 + * @afbc_size: minimum size of afbc buffer 332 + */ 333 + u32 afbc_size; 334 + /** 335 + * @bpp: bpp value for this afbc buffer 336 + * To be removed when users such as malidp 337 + * properly store the cpp in drm_format_info. 338 + * New users should not start using this field. 339 + */ 340 + u32 bpp; 341 + }; 342 + 343 + #define fb_to_afbc_fb(x) container_of(x, struct drm_afbc_framebuffer, base) 344 + 300 345 #endif
+10
include/drm/drm_gem_framebuffer_helper.h
··· 1 1 #ifndef __DRM_GEM_FB_HELPER_H__ 2 2 #define __DRM_GEM_FB_HELPER_H__ 3 3 4 + struct drm_afbc_framebuffer; 4 5 struct drm_device; 5 6 struct drm_fb_helper_surface_size; 6 7 struct drm_file; ··· 12 11 struct drm_plane; 13 12 struct drm_plane_state; 14 13 struct drm_simple_display_pipe; 14 + 15 + #define AFBC_VENDOR_AND_TYPE_MASK GENMASK_ULL(63, 52) 15 16 16 17 struct drm_gem_object *drm_gem_fb_get_obj(struct drm_framebuffer *fb, 17 18 unsigned int plane); ··· 36 33 struct drm_framebuffer * 37 34 drm_gem_fb_create_with_dirty(struct drm_device *dev, struct drm_file *file, 38 35 const struct drm_mode_fb_cmd2 *mode_cmd); 36 + 37 + #define drm_is_afbc(modifier) \ 38 + (((modifier) & AFBC_VENDOR_AND_TYPE_MASK) == DRM_FORMAT_MOD_ARM_AFBC(0)) 39 + 40 + int drm_gem_fb_afbc_init(struct drm_device *dev, 41 + const struct drm_mode_fb_cmd2 *mode_cmd, 42 + struct drm_afbc_framebuffer *afbc_fb); 39 43 40 44 int drm_gem_fb_prepare_fb(struct drm_plane *plane, 41 45 struct drm_plane_state *state);