On Wed Apr 30 02:28:56 2025 +0300, Laurent Pinchart wrote:
> 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+rene...@ideasonboard.com>
> Reviewed-by: Tomi Valkeinen <tomi.valkeinen+rene...@ideasonboard.com>
> Link: 
> https://lore.kernel.org/r/20250429232904.26413-2-laurent.pinchart+rene...@ideasonboard.com
> Signed-off-by: Laurent Pinchart <laurent.pinch...@ideasonboard.com>
> Signed-off-by: Hans Verkuil <hverk...@xs4all.nl>

Patch committed.

Thanks,
Hans Verkuil

 drivers/media/platform/renesas/vsp1/vsp1_pipe.c  | 101 ++++++++++++++++++-----
 drivers/media/platform/renesas/vsp1/vsp1_pipe.h  |   3 +
 drivers/media/platform/renesas/vsp1/vsp1_video.c |  24 +++++-
 3 files changed, 104 insertions(+), 24 deletions(-)

---

diff --git a/drivers/media/platform/renesas/vsp1/vsp1_pipe.c 
b/drivers/media/platform/renesas/vsp1/vsp1_pipe.c
index 8e9be3ec1b4d..15ff39c02cbe 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_pipe.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_pipe.c
@@ -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;
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_pipe.h 
b/drivers/media/platform/renesas/vsp1/vsp1_pipe.h
index 1655a820da10..383951c5bd90 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_pipe.h
+++ b/drivers/media/platform/renesas/vsp1/vsp1_pipe.h
@@ -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__ */
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_video.c 
b/drivers/media/platform/renesas/vsp1/vsp1_video.c
index 03f4efd6b82b..da578993f472 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_video.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_video.c
@@ -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);

Reply via email to