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

drm/fourcc: Add char_per_block, block_w and block_h in drm_format_info

For some pixel formats .cpp structure in drm_format info it's not
enough to describe the peculiarities of the pixel layout, for example
tiled formats or packed formats at bit level.

What's implemented here is to add three new members to drm_format_info
that could describe such formats:

- char_per_block[3]
- block_w[3]
- block_h[3]

char_per_block will be put in a union alongside cpp, for transparent
compatibility with the existing format descriptions.

Regarding, block_w and block_h they are intended to be used through
their equivalent getters drm_format_info_block_width /
drm_format_info_block_height, the reason of the getters is to abstract
the fact that for normal formats block_w and block_h will be unset/0,
but the methods will be returning 1.

Additionally, convenience function drm_format_info_min_pitch had been
added that computes the minimum required pitch for a given pixel
format and buffer width.

Using that the following drm core functions had been updated to
generically handle both block and non-block formats:

- drm_fb_cma_get_gem_addr: for block formats it will just return the
beginning of the block.
- framebuffer_check: Use the newly added drm_format_info_min_pitch.
- drm_gem_fb_create_with_funcs: Use the newly added
drm_format_info_min_pitch.
- In places where is not expecting to handle block formats, like fbdev
helpers I just added some warnings in case the block width/height
are greater than 1.

Changes since v3:
- Add helper function for computing the minimum required pitch.
- Improve/cleanup documentation

Changes since v8:
- Fixed build on 32bits arm architectures, with:

- return DIV_ROUND_UP((u64)buffer_width * info->char_per_block[plane],
+ return DIV_ROUND_UP_ULL((u64)buffer_width * info->char_per_block[plane],

Reviewed-by: Brian Starkey <brian.starkey@arm.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Alexandru Gheorghe <alexandru-cosmin.gheorghe@arm.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20181101170055.5433-1-alexandru-cosmin.gheorghe@arm.com

+148 -9
+17 -3
drivers/gpu/drm/drm_fb_cma_helper.c
··· 72 72 EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_obj); 73 73 74 74 /** 75 - * drm_fb_cma_get_gem_addr() - Get physical address for framebuffer 75 + * drm_fb_cma_get_gem_addr() - Get physical address for framebuffer, for pixel 76 + * formats where values are grouped in blocks this will get you the beginning of 77 + * the block 76 78 * @fb: The framebuffer 77 79 * @state: Which state of drm plane 78 80 * @plane: Which plane ··· 89 87 struct drm_gem_cma_object *obj; 90 88 dma_addr_t paddr; 91 89 u8 h_div = 1, v_div = 1; 90 + u32 block_w = drm_format_info_block_width(fb->format, plane); 91 + u32 block_h = drm_format_info_block_height(fb->format, plane); 92 + u32 block_size = fb->format->char_per_block[plane]; 93 + u32 sample_x; 94 + u32 sample_y; 95 + u32 block_start_y; 96 + u32 num_hblocks; 92 97 93 98 obj = drm_fb_cma_get_gem_obj(fb, plane); 94 99 if (!obj) ··· 108 99 v_div = fb->format->vsub; 109 100 } 110 101 111 - paddr += (fb->format->cpp[plane] * (state->src_x >> 16)) / h_div; 112 - paddr += (fb->pitches[plane] * (state->src_y >> 16)) / v_div; 102 + sample_x = (state->src_x >> 16) / h_div; 103 + sample_y = (state->src_y >> 16) / v_div; 104 + block_start_y = (sample_y / block_h) * block_h; 105 + num_hblocks = sample_x / block_w; 106 + 107 + paddr += fb->pitches[plane] * block_start_y; 108 + paddr += block_size * num_hblocks; 113 109 114 110 return paddr; 115 111 }
+6
drivers/gpu/drm/drm_fb_helper.c
··· 1614 1614 if (var->pixclock != 0 || in_dbg_master()) 1615 1615 return -EINVAL; 1616 1616 1617 + if ((drm_format_info_block_width(fb->format, 0) > 1) || 1618 + (drm_format_info_block_height(fb->format, 0) > 1)) 1619 + return -EINVAL; 1620 + 1617 1621 /* 1618 1622 * Changes struct fb_var_screeninfo are currently not pushed back 1619 1623 * to KMS, hence fail if different settings are requested. ··· 1992 1988 { 1993 1989 struct drm_framebuffer *fb = fb_helper->fb; 1994 1990 1991 + WARN_ON((drm_format_info_block_width(fb->format, 0) > 1) || 1992 + (drm_format_info_block_height(fb->format, 0) > 1)); 1995 1993 info->pseudo_palette = fb_helper->pseudo_palette; 1996 1994 info->var.xres_virtual = fb->width; 1997 1995 info->var.yres_virtual = fb->height;
+62
drivers/gpu/drm/drm_fourcc.c
··· 400 400 return height / info->vsub; 401 401 } 402 402 EXPORT_SYMBOL(drm_format_plane_height); 403 + 404 + /** 405 + * drm_format_info_block_width - width in pixels of block. 406 + * @info: pixel format info 407 + * @plane: plane index 408 + * 409 + * Returns: 410 + * The width in pixels of a block, depending on the plane index. 411 + */ 412 + unsigned int drm_format_info_block_width(const struct drm_format_info *info, 413 + int plane) 414 + { 415 + if (!info || plane < 0 || plane >= info->num_planes) 416 + return 0; 417 + 418 + if (!info->block_w[plane]) 419 + return 1; 420 + return info->block_w[plane]; 421 + } 422 + EXPORT_SYMBOL(drm_format_info_block_width); 423 + 424 + /** 425 + * drm_format_info_block_height - height in pixels of a block 426 + * @info: pixel format info 427 + * @plane: plane index 428 + * 429 + * Returns: 430 + * The height in pixels of a block, depending on the plane index. 431 + */ 432 + unsigned int drm_format_info_block_height(const struct drm_format_info *info, 433 + int plane) 434 + { 435 + if (!info || plane < 0 || plane >= info->num_planes) 436 + return 0; 437 + 438 + if (!info->block_h[plane]) 439 + return 1; 440 + return info->block_h[plane]; 441 + } 442 + EXPORT_SYMBOL(drm_format_info_block_height); 443 + 444 + /** 445 + * drm_format_info_min_pitch - computes the minimum required pitch in bytes 446 + * @info: pixel format info 447 + * @plane: plane index 448 + * @buffer_width: buffer width in pixels 449 + * 450 + * Returns: 451 + * The minimum required pitch in bytes for a buffer by taking into consideration 452 + * the pixel format information and the buffer width. 453 + */ 454 + uint64_t drm_format_info_min_pitch(const struct drm_format_info *info, 455 + int plane, unsigned int buffer_width) 456 + { 457 + if (!info || plane < 0 || plane >= info->num_planes) 458 + return 0; 459 + 460 + return DIV_ROUND_UP_ULL((u64)buffer_width * info->char_per_block[plane], 461 + drm_format_info_block_width(info, plane) * 462 + drm_format_info_block_height(info, plane)); 463 + } 464 + EXPORT_SYMBOL(drm_format_info_min_pitch);
+3 -3
drivers/gpu/drm/drm_framebuffer.c
··· 195 195 for (i = 0; i < info->num_planes; i++) { 196 196 unsigned int width = fb_plane_width(r->width, info, i); 197 197 unsigned int height = fb_plane_height(r->height, info, i); 198 - unsigned int cpp = info->cpp[i]; 198 + u64 min_pitch = drm_format_info_min_pitch(info, i, width); 199 199 200 200 if (!r->handles[i]) { 201 201 DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i); 202 202 return -EINVAL; 203 203 } 204 204 205 - if ((uint64_t) width * cpp > UINT_MAX) 205 + if (min_pitch > UINT_MAX) 206 206 return -ERANGE; 207 207 208 208 if ((uint64_t) height * r->pitches[i] + r->offsets[i] > UINT_MAX) 209 209 return -ERANGE; 210 210 211 - if (r->pitches[i] < width * cpp) { 211 + if (r->pitches[i] < min_pitch) { 212 212 DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i); 213 213 return -EINVAL; 214 214 }
+1 -1
drivers/gpu/drm/drm_gem_framebuffer_helper.c
··· 171 171 } 172 172 173 173 min_size = (height - 1) * mode_cmd->pitches[i] 174 - + width * info->cpp[i] 174 + + drm_format_info_min_pitch(info, i, width) 175 175 + mode_cmd->offsets[i]; 176 176 177 177 if (objs[i]->size < min_size) {
+59 -2
include/drm/drm_fourcc.h
··· 69 69 /** @num_planes: Number of color planes (1 to 3) */ 70 70 u8 num_planes; 71 71 72 - /** @cpp: Number of bytes per pixel (per plane) */ 73 - u8 cpp[3]; 72 + union { 73 + /** 74 + * @cpp: 75 + * 76 + * Number of bytes per pixel (per plane), this is aliased with 77 + * @char_per_block. It is deprecated in favour of using the 78 + * triplet @char_per_block, @block_w, @block_h for better 79 + * describing the pixel format. 80 + */ 81 + u8 cpp[3]; 82 + 83 + /** 84 + * @char_per_block: 85 + * 86 + * Number of bytes per block (per plane), where blocks are 87 + * defined as a rectangle of pixels which are stored next to 88 + * each other in a byte aligned memory region. Together with 89 + * @block_w and @block_h this is used to properly describe tiles 90 + * in tiled formats or to describe groups of pixels in packed 91 + * formats for which the memory needed for a single pixel is not 92 + * byte aligned. 93 + * 94 + * @cpp has been kept for historical reasons because there are 95 + * a lot of places in drivers where it's used. In drm core for 96 + * generic code paths the preferred way is to use 97 + * @char_per_block, drm_format_info_block_width() and 98 + * drm_format_info_block_height() which allows handling both 99 + * block and non-block formats in the same way. 100 + * 101 + * For formats that are intended to be used only with non-linear 102 + * modifiers both @cpp and @char_per_block must be 0 in the 103 + * generic format table. Drivers could supply accurate 104 + * information from their drm_mode_config.get_format_info hook 105 + * if they want the core to be validating the pitch. 106 + */ 107 + u8 char_per_block[3]; 108 + }; 109 + 110 + /** 111 + * @block_w: 112 + * 113 + * Block width in pixels, this is intended to be accessed through 114 + * drm_format_info_block_width() 115 + */ 116 + u8 block_w[3]; 117 + 118 + /** 119 + * @block_h: 120 + * 121 + * Block height in pixels, this is intended to be accessed through 122 + * drm_format_info_block_height() 123 + */ 124 + u8 block_h[3]; 74 125 75 126 /** @hsub: Horizontal chroma subsampling factor */ 76 127 u8 hsub; ··· 157 106 int drm_format_vert_chroma_subsampling(uint32_t format); 158 107 int drm_format_plane_width(int width, uint32_t format, int plane); 159 108 int drm_format_plane_height(int height, uint32_t format, int plane); 109 + unsigned int drm_format_info_block_width(const struct drm_format_info *info, 110 + int plane); 111 + unsigned int drm_format_info_block_height(const struct drm_format_info *info, 112 + int plane); 113 + uint64_t drm_format_info_min_pitch(const struct drm_format_info *info, 114 + int plane, unsigned int buffer_width); 160 115 const char *drm_get_format_name(uint32_t format, struct drm_format_name_buf *buf); 161 116 162 117 #endif /* __DRM_FOURCC_H__ */