]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
media: renesas: vsp1: Implement pixel format enumeration
authorLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Tue, 29 Apr 2025 23:28:56 +0000 (02:28 +0300)
committerHans Verkuil <hverkuil@xs4all.nl>
Fri, 2 May 2025 08:16:44 +0000 (10:16 +0200)
The VSP1 driver is missing the ability to enumerate pixel formats on its
video nodes, which is supposed to be supported according to the V4L2
API. Implement the enumeration to fix this issue.

As the device is media controller-centric, also implement the ability to
filter pixel formats by media bus code, and report the missing
V4L2_CAP_IO_MC capability.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Reviewed-by: Tomi Valkeinen <tomi.valkeinen+renesas@ideasonboard.com>
Link: https://lore.kernel.org/r/20250429232904.26413-2-laurent.pinchart+renesas@ideasonboard.com
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
drivers/media/platform/renesas/vsp1/vsp1_pipe.c
drivers/media/platform/renesas/vsp1/vsp1_pipe.h
drivers/media/platform/renesas/vsp1/vsp1_video.c

index 8e9be3ec1b4dbdad1cbe35ae3a88952f46e41343..15ff39c02cbe6a9b2f86073691538860e8b27bc8 100644 (file)
@@ -138,14 +138,6 @@ static const struct vsp1_format_info vsp1_video_formats[] = {
          VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
          VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
          1, { 32, 0, 0 }, false, false, 1, 1, false },
-       { V4L2_PIX_FMT_HSV24, MEDIA_BUS_FMT_AHSV8888_1X32,
-         VI6_FMT_RGB_888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
-         VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
-         1, { 24, 0, 0 }, false, false, 1, 1, false },
-       { V4L2_PIX_FMT_HSV32, MEDIA_BUS_FMT_AHSV8888_1X32,
-         VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
-         VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
-         1, { 32, 0, 0 }, false, false, 1, 1, false },
        { V4L2_PIX_FMT_RGBX1010102, MEDIA_BUS_FMT_ARGB8888_1X32,
          VI6_FMT_RGB10_RGB10A2_A2RGB10,
          VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS,
@@ -162,10 +154,6 @@ static const struct vsp1_format_info vsp1_video_formats[] = {
          VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
          VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
          1, { 16, 0, 0 }, false, false, 2, 1, false },
-       { V4L2_PIX_FMT_VYUY, MEDIA_BUS_FMT_AYUV8_1X32,
-         VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
-         VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
-         1, { 16, 0, 0 }, false, true, 2, 1, false },
        { V4L2_PIX_FMT_YUYV, MEDIA_BUS_FMT_AYUV8_1X32,
          VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
          VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
@@ -222,6 +210,21 @@ static const struct vsp1_format_info vsp1_video_formats[] = {
          1, { 32, 0, 0 }, false, false, 2, 1, false },
 };
 
+static const struct vsp1_format_info vsp1_video_gen2_formats[] = {
+       { V4L2_PIX_FMT_VYUY, MEDIA_BUS_FMT_AYUV8_1X32,
+         VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+         VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
+         1, { 16, 0, 0 }, false, true, 2, 1, false },
+       { V4L2_PIX_FMT_HSV24, MEDIA_BUS_FMT_AHSV8888_1X32,
+         VI6_FMT_RGB_888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+         VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
+         1, { 24, 0, 0 }, false, false, 1, 1, false },
+       { V4L2_PIX_FMT_HSV32, MEDIA_BUS_FMT_AHSV8888_1X32,
+         VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+         VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
+         1, { 32, 0, 0 }, false, false, 1, 1, false },
+};
+
 /**
  * vsp1_get_format_info - Retrieve format information for a 4CC
  * @vsp1: the VSP1 device
@@ -235,21 +238,77 @@ const struct vsp1_format_info *vsp1_get_format_info(struct vsp1_device *vsp1,
 {
        unsigned int i;
 
-       /* Special case, the VYUY and HSV formats are supported on Gen2 only. */
-       if (vsp1->info->gen != 2) {
-               switch (fourcc) {
-               case V4L2_PIX_FMT_VYUY:
-               case V4L2_PIX_FMT_HSV24:
-               case V4L2_PIX_FMT_HSV32:
-                       return NULL;
+       for (i = 0; i < ARRAY_SIZE(vsp1_video_formats); ++i) {
+               const struct vsp1_format_info *info = &vsp1_video_formats[i];
+
+               if (info->fourcc == fourcc)
+                       return info;
+       }
+
+       if (vsp1->info->gen == 2) {
+               for (i = 0; i < ARRAY_SIZE(vsp1_video_gen2_formats); ++i) {
+                       const struct vsp1_format_info *info =
+                               &vsp1_video_gen2_formats[i];
+
+                       if (info->fourcc == fourcc)
+                               return info;
+               }
+       }
+
+       return NULL;
+}
+
+/**
+ * vsp1_get_format_info_by_index - Enumerate format information
+ * @vsp1: the VSP1 device
+ * @index: the format index
+ * @code: media bus code to limit enumeration
+ *
+ * Return a pointer to the format information structure corresponding to the
+ * given index, or NULL if the index exceeds the supported formats list. If the
+ * @code parameter is not zero, only formats compatible with the media bus code
+ * will be enumerated.
+ */
+const struct vsp1_format_info *
+vsp1_get_format_info_by_index(struct vsp1_device *vsp1, unsigned int index,
+                             u32 code)
+{
+       unsigned int i;
+
+       if (!code) {
+               if (index < ARRAY_SIZE(vsp1_video_formats))
+                       return &vsp1_video_formats[index];
+
+               if (vsp1->info->gen == 2) {
+                       index -= ARRAY_SIZE(vsp1_video_formats);
+                       if (index < ARRAY_SIZE(vsp1_video_gen2_formats))
+                               return &vsp1_video_gen2_formats[index];
                }
+
+               return NULL;
        }
 
        for (i = 0; i < ARRAY_SIZE(vsp1_video_formats); ++i) {
                const struct vsp1_format_info *info = &vsp1_video_formats[i];
 
-               if (info->fourcc == fourcc)
-                       return info;
+               if (info->mbus == code) {
+                       if (!index)
+                               return info;
+                       index--;
+               }
+       }
+
+       if (vsp1->info->gen == 2) {
+               for (i = 0; i < ARRAY_SIZE(vsp1_video_gen2_formats); ++i) {
+                       const struct vsp1_format_info *info =
+                               &vsp1_video_gen2_formats[i];
+
+                       if (info->mbus == code) {
+                               if (!index)
+                                       return info;
+                               index--;
+                       }
+               }
        }
 
        return NULL;
index 1655a820da102003d3d7da82a7cdd64e01c29ac6..383951c5bd9017a1a5a71233b8ec94501a02c48d 100644 (file)
@@ -180,5 +180,8 @@ void vsp1_pipeline_calculate_partition(struct vsp1_pipeline *pipe,
 
 const struct vsp1_format_info *vsp1_get_format_info(struct vsp1_device *vsp1,
                                                    u32 fourcc);
+const struct vsp1_format_info *
+vsp1_get_format_info_by_index(struct vsp1_device *vsp1, unsigned int index,
+                             u32 code);
 
 #endif /* __VSP1_PIPE_H__ */
index 03f4efd6b82bd76419ff048f24c82ecce44f321c..da578993f4720a94186cac1a078de65738a04b62 100644 (file)
@@ -888,7 +888,7 @@ vsp1_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
        struct vsp1_video *video = to_vsp1_video(vfh->vdev);
 
        cap->capabilities = V4L2_CAP_DEVICE_CAPS | V4L2_CAP_STREAMING
-                         | V4L2_CAP_VIDEO_CAPTURE_MPLANE
+                         | V4L2_CAP_IO_MC | V4L2_CAP_VIDEO_CAPTURE_MPLANE
                          | V4L2_CAP_VIDEO_OUTPUT_MPLANE;
 
 
@@ -898,6 +898,22 @@ vsp1_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
        return 0;
 }
 
+static int vsp1_video_enum_format(struct file *file, void *fh,
+                                 struct v4l2_fmtdesc *f)
+{
+       struct v4l2_fh *vfh = file->private_data;
+       struct vsp1_video *video = to_vsp1_video(vfh->vdev);
+       const struct vsp1_format_info *info;
+
+       info = vsp1_get_format_info_by_index(video->vsp1, f->index, f->mbus_code);
+       if (!info)
+               return -EINVAL;
+
+       f->pixelformat = info->fourcc;
+
+       return 0;
+}
+
 static int
 vsp1_video_get_format(struct file *file, void *fh, struct v4l2_format *format)
 {
@@ -1013,6 +1029,8 @@ err_pipe:
 
 static const struct v4l2_ioctl_ops vsp1_video_ioctl_ops = {
        .vidioc_querycap                = vsp1_video_querycap,
+       .vidioc_enum_fmt_vid_cap        = vsp1_video_enum_format,
+       .vidioc_enum_fmt_vid_out        = vsp1_video_enum_format,
        .vidioc_g_fmt_vid_cap_mplane    = vsp1_video_get_format,
        .vidioc_s_fmt_vid_cap_mplane    = vsp1_video_set_format,
        .vidioc_try_fmt_vid_cap_mplane  = vsp1_video_try_format,
@@ -1207,14 +1225,14 @@ struct vsp1_video *vsp1_video_create(struct vsp1_device *vsp1,
                video->pad.flags = MEDIA_PAD_FL_SOURCE;
                video->video.vfl_dir = VFL_DIR_TX;
                video->video.device_caps = V4L2_CAP_VIDEO_OUTPUT_MPLANE |
-                                          V4L2_CAP_STREAMING;
+                                          V4L2_CAP_STREAMING | V4L2_CAP_IO_MC;
        } else {
                direction = "output";
                video->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
                video->pad.flags = MEDIA_PAD_FL_SINK;
                video->video.vfl_dir = VFL_DIR_RX;
                video->video.device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE |
-                                          V4L2_CAP_STREAMING;
+                                          V4L2_CAP_STREAMING | V4L2_CAP_IO_MC;
        }
 
        mutex_init(&video->lock);