On Thu May 21 00:44:10 2026 +0200, Sven Püschel wrote:
> 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 <[email protected]>
> Signed-off-by: Sven Püschel <[email protected]>
> Signed-off-by: Nicolas Dufresne <[email protected]>
> Signed-off-by: Hans Verkuil <[email protected]>

Patch committed.

Thanks,
Hans Verkuil

 drivers/media/v4l2-core/v4l2-common.c | 56 +++++++++++++++++++++++++++--------
 include/media/v4l2-common.h           |  4 +++
 2 files changed, 48 insertions(+), 12 deletions(-)

---

diff --git a/drivers/media/v4l2-core/v4l2-common.c 
b/drivers/media/v4l2-core/v4l2-common.c
index 3cc8b04e1ea6..65db7340ad38 100644
--- a/drivers/media/v4l2-core/v4l2-common.c
+++ b/drivers/media/v4l2-core/v4l2-common.c
@@ -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);
diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
index 401d8506c24b..edd416178c33 100644
--- a/include/media/v4l2-common.h
+++ b/include/media/v4l2-common.h
@@ -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
_______________________________________________
linuxtv-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to