]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
media: v4l2-common: add v4l2_fill_pixfmt_mp_aligned helper
authorSven Püschel <s.pueschel@pengutronix.de>
Wed, 20 May 2026 22:44:10 +0000 (00:44 +0200)
committerHans Verkuil <hverkuil+cisco@kernel.org>
Thu, 21 May 2026 10:32:19 +0000 (12:32 +0200)
Add a v4l2_fill_pixfmt_mp_aligned helper which allows the user to
specify a custom stride alignment in bytes. This is necessary for
hardware like the Rockchip RGA3, which requires the stride value to be
aligned to a 16 bytes boundary.

The code makes some assumptions about the v4l2 format to simplify the
calculation. They currently hold for all known v4l2 formats.

v4l2_format_plane_stride uses an unsigned int as argument type to avoid
the later multiplication from overflowing the u8 value. All other places
use u8, as no practical use cases for a larger alignment are known at
the moment.

Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Signed-off-by: Sven Püschel <s.pueschel@pengutronix.de>
Signed-off-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
drivers/media/v4l2-core/v4l2-common.c
include/media/v4l2-common.h

index 3cc8b04e1ea633ba688ab7009a2c41e26546a91a..65db7340ad3847c3f72ff3e5b71181314b2d600a 100644 (file)
@@ -432,14 +432,33 @@ static inline unsigned int v4l2_format_block_height(const struct v4l2_format_inf
 }
 
 static inline unsigned int v4l2_format_plane_stride(const struct v4l2_format_info *info, int plane,
-                                                   unsigned int width)
+                                                   unsigned int width, unsigned int byte_alignment)
 {
        unsigned int hdiv = plane ? info->hdiv : 1;
        unsigned int aligned_width =
                ALIGN(width, v4l2_format_block_width(info, plane));
 
-       return DIV_ROUND_UP(aligned_width, hdiv) *
-              info->bpp[plane] / info->bpp_div[plane];
+       /*
+        * Formats with a single memory plane derive the stride of the
+        * other planes from the y stride. To avoid hardware or software
+        * deriving a different stride for the composite plane,
+        * multiply the alignment accordingly.
+        *
+        * It assumes the following format properties:
+        * - bpp_div[0] == bpp_div[1]
+        * - The multiplication factor doesn't differ between the non y planes
+        * - The multiplication factor is a power of 2
+        */
+       if (info->mem_planes == 1 && info->comp_planes > 1) {
+               if (plane == 0)
+                       byte_alignment *= DIV_ROUND_UP(info->hdiv * info->bpp[0], info->bpp[1]);
+               else
+                       byte_alignment *= DIV_ROUND_UP(info->bpp[1], info->hdiv * info->bpp[0]);
+       }
+
+       return ALIGN(DIV_ROUND_UP(aligned_width, hdiv) * info->bpp[plane] /
+                            info->bpp_div[plane],
+                    byte_alignment);
 }
 
 static inline unsigned int v4l2_format_plane_height(const struct v4l2_format_info *info, int plane,
@@ -453,9 +472,10 @@ static inline unsigned int v4l2_format_plane_height(const struct v4l2_format_inf
 }
 
 static inline unsigned int v4l2_format_plane_size(const struct v4l2_format_info *info, int plane,
-                                                 unsigned int width, unsigned int height)
+                                                 unsigned int width, unsigned int height,
+                                                 u8 stride_alignment)
 {
-       return v4l2_format_plane_stride(info, plane, width) *
+       return v4l2_format_plane_stride(info, plane, width, stride_alignment) *
               v4l2_format_plane_height(info, plane, height);
 }
 
@@ -476,8 +496,9 @@ void v4l2_apply_frmsize_constraints(u32 *width, u32 *height,
 }
 EXPORT_SYMBOL_GPL(v4l2_apply_frmsize_constraints);
 
-int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt,
-                       u32 pixelformat, u32 width, u32 height)
+int v4l2_fill_pixfmt_mp_aligned(struct v4l2_pix_format_mplane *pixfmt,
+                               u32 pixelformat, u32 width, u32 height,
+                               u8 stride_alignment)
 {
        const struct v4l2_format_info *info;
        struct v4l2_plane_pix_format *plane;
@@ -494,23 +515,34 @@ int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt,
 
        if (info->mem_planes == 1) {
                plane = &pixfmt->plane_fmt[0];
-               plane->bytesperline = v4l2_format_plane_stride(info, 0, width);
+               plane->bytesperline = v4l2_format_plane_stride(info, 0, width,
+                                                              stride_alignment);
                plane->sizeimage = 0;
 
                for (i = 0; i < info->comp_planes; i++)
                        plane->sizeimage +=
-                               v4l2_format_plane_size(info, i, width, height);
+                               v4l2_format_plane_size(info, i, width, height,
+                                                      stride_alignment);
        } else {
                for (i = 0; i < info->comp_planes; i++) {
                        plane = &pixfmt->plane_fmt[i];
                        plane->bytesperline =
-                               v4l2_format_plane_stride(info, i, width);
+                               v4l2_format_plane_stride(info, i, width,
+                                                        stride_alignment);
                        plane->sizeimage = plane->bytesperline *
                                v4l2_format_plane_height(info, i, height);
                }
        }
        return 0;
 }
+EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt_mp_aligned);
+
+int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt,
+                       u32 pixelformat, u32 width, u32 height)
+{
+       return v4l2_fill_pixfmt_mp_aligned(pixfmt, pixelformat,
+                                          width, height, 1);
+}
 EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt_mp);
 
 int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, u32 pixelformat,
@@ -530,12 +562,12 @@ int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, u32 pixelformat,
        pixfmt->width = width;
        pixfmt->height = height;
        pixfmt->pixelformat = pixelformat;
-       pixfmt->bytesperline = v4l2_format_plane_stride(info, 0, width);
+       pixfmt->bytesperline = v4l2_format_plane_stride(info, 0, width, 1);
        pixfmt->sizeimage = 0;
 
        for (i = 0; i < info->comp_planes; i++)
                pixfmt->sizeimage +=
-                       v4l2_format_plane_size(info, i, width, height);
+                       v4l2_format_plane_size(info, i, width, height, 1);
        return 0;
 }
 EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt);
index 401d8506c24b50cb22d1b3f713c9bc80de349a4a..edd416178c333348714c27c4d41aaeaec0d5a361 100644 (file)
@@ -558,6 +558,10 @@ int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, u32 pixelformat,
                     u32 width, u32 height);
 int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt, u32 pixelformat,
                        u32 width, u32 height);
+/* @stride_alignment is a power of 2 value in bytes */
+int v4l2_fill_pixfmt_mp_aligned(struct v4l2_pix_format_mplane *pixfmt,
+                               u32 pixelformat, u32 width, u32 height,
+                               u8 stride_alignment);
 
 /**
  * v4l2_get_link_freq - Get link rate from transmitter