[10/16] media: sun6i-csi: Add support for MC-centric format enumeration

Message ID 20260518102451.417971-11-paulk@sys-base.io (mailing list archive)
State New
Headers
Series media: sun6i-csi/isp MC-centric support and cleanups |

Commit Message

Paul Kocialkowski May 18, 2026, 10:24 a.m. UTC
Use the dedicated helper to check possible pixelformats against the
provided mbus code in order to support MC-centric format enumeration.

Note that multiple pixelformats may be returned for a given mbus code.

Signed-off-by: Paul Kocialkowski <paulk@sys-base.io>
---
 .../sunxi/sun6i-csi/sun6i_csi_capture.c       | 38 +++++++++++++++++--
 1 file changed, 34 insertions(+), 4 deletions(-)
  

Comments

arash golgol May 27, 2026, 5:50 a.m. UTC | #1
Hi Paul,

On Mon, May 18, 2026 at 2:00 PM Paul Kocialkowski <paulk@sys-base.io> wrote:
>
> Use the dedicated helper to check possible pixelformats against the
> provided mbus code in order to support MC-centric format enumeration.
>
> Note that multiple pixelformats may be returned for a given mbus code.
>
> Signed-off-by: Paul Kocialkowski <paulk@sys-base.io>
> ---
>  .../sunxi/sun6i-csi/sun6i_csi_capture.c       | 38 +++++++++++++++++--
>  1 file changed, 34 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
> index a836fa7f081a..409c28621093 100644
> --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
> +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
> @@ -773,14 +773,43 @@ static int sun6i_csi_capture_querycap(struct file *file, void *priv,
>  static int sun6i_csi_capture_enum_fmt(struct file *file, void *priv,
>                                       struct v4l2_fmtdesc *fmtdesc)
>  {
> +       const struct sun6i_csi_capture_format *capture_format;
> +       const struct sun6i_csi_bridge_format *bridge_format;
> +       u32 mbus_code = fmtdesc->mbus_code;
>         u32 index = fmtdesc->index;
> +       unsigned int index_valid = 0;
> +       unsigned int i;
> +
> +       /* Video-node-centric enumeration. */
> +       if (!mbus_code) {
> +               if (index >= ARRAY_SIZE(sun6i_csi_capture_formats))
> +                       return -EINVAL;
> +
> +               fmtdesc->pixelformat =
> +                       sun6i_csi_capture_formats[index].pixelformat;
> +               return 0;
> +       }
>
> -       if (index >= ARRAY_SIZE(sun6i_csi_capture_formats))
> +       bridge_format = sun6i_csi_bridge_format_find(mbus_code);
> +       if (!bridge_format)
>                 return -EINVAL;
>
> -       fmtdesc->pixelformat = sun6i_csi_capture_formats[index].pixelformat;
> +       for (i = 0; i < ARRAY_SIZE(sun6i_csi_capture_formats); i++) {
> +               capture_format = &sun6i_csi_capture_formats[i];
>
> -       return 0;
> +               if (!sun6i_csi_capture_format_check(capture_format,
> +                                                   bridge_format))
> +                       continue;
> +
> +               if (index_valid == index) {
> +                       fmtdesc->pixelformat = capture_format->pixelformat;
> +                       return 0;
> +               }
> +
> +               index_valid++;
> +       }
> +
> +       return -EINVAL;
>  }
>
>  static int sun6i_csi_capture_enum_framesize(struct file *file, void *fh,
> @@ -1076,7 +1105,8 @@ int sun6i_csi_capture_setup(struct sun6i_csi_device *csi_dev)
>
>         strscpy(video_dev->name, SUN6I_CSI_CAPTURE_NAME,
>                 sizeof(video_dev->name));
> -       video_dev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
> +       video_dev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
> +                                V4L2_CAP_IO_MC;
>         video_dev->vfl_dir = VFL_DIR_RX;
>         video_dev->release = video_device_release_empty;
>         video_dev->fops = &sun6i_csi_capture_fops;
> --
> 2.54.0
>

Tested on a LicheePi Zero Dock (V3s) with the following pipeline:

ov7670 -> sun6i-csi-bridge -> sun6i-csi-capture

I verified that mbus-code-based format enumeration works correctly
from userspace and that the reported capture formats change according
to the selected media bus format.

I could also successfully start streaming with several of the
enumerated capture formats (e.g. YUYV and BA81)

However, I could not fully validate actual format conversion behavior
(e.g. MEDIA_BUS_FMT_YUYV8_2X8 to NV12) because my OV7670 setup
currently has non-functional test patterns except for 'shifting-1'
mode.

Tested-by: Arash Golgol <arash.golgol@gmail.com>

PS:

While testing this patch I also noticed that
VIDIOC_SUBDEV_ENUM_MBUS_CODE reports duplicate entries for:
 - MEDIA_BUS_FMT_UYVY8_2X8
 - MEDIA_BUS_FMT_UYVY8_1X16
on sun6i-csi-bridge.

This appears to come from duplicate format entries being exposed by
the bridge driver.
  
Paul Kocialkowski May 27, 2026, 7:59 a.m. UTC | #2
Hi Arash,

On Wed 27 May 26, 09:20, arash golgol wrote:
> On Mon, May 18, 2026 at 2:00 PM Paul Kocialkowski <paulk@sys-base.io> wrote:
> >
> > Use the dedicated helper to check possible pixelformats against the
> > provided mbus code in order to support MC-centric format enumeration.
> >
> > Note that multiple pixelformats may be returned for a given mbus code.
> >
> > Signed-off-by: Paul Kocialkowski <paulk@sys-base.io>
> > ---
> >  .../sunxi/sun6i-csi/sun6i_csi_capture.c       | 38 +++++++++++++++++--
> >  1 file changed, 34 insertions(+), 4 deletions(-)
> >
> > diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
> > index a836fa7f081a..409c28621093 100644
> > --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
> > +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
> > @@ -773,14 +773,43 @@ static int sun6i_csi_capture_querycap(struct file *file, void *priv,
> >  static int sun6i_csi_capture_enum_fmt(struct file *file, void *priv,
> >                                       struct v4l2_fmtdesc *fmtdesc)
> >  {
> > +       const struct sun6i_csi_capture_format *capture_format;
> > +       const struct sun6i_csi_bridge_format *bridge_format;
> > +       u32 mbus_code = fmtdesc->mbus_code;
> >         u32 index = fmtdesc->index;
> > +       unsigned int index_valid = 0;
> > +       unsigned int i;
> > +
> > +       /* Video-node-centric enumeration. */
> > +       if (!mbus_code) {
> > +               if (index >= ARRAY_SIZE(sun6i_csi_capture_formats))
> > +                       return -EINVAL;
> > +
> > +               fmtdesc->pixelformat =
> > +                       sun6i_csi_capture_formats[index].pixelformat;
> > +               return 0;
> > +       }
> >
> > -       if (index >= ARRAY_SIZE(sun6i_csi_capture_formats))
> > +       bridge_format = sun6i_csi_bridge_format_find(mbus_code);
> > +       if (!bridge_format)
> >                 return -EINVAL;
> >
> > -       fmtdesc->pixelformat = sun6i_csi_capture_formats[index].pixelformat;
> > +       for (i = 0; i < ARRAY_SIZE(sun6i_csi_capture_formats); i++) {
> > +               capture_format = &sun6i_csi_capture_formats[i];
> >
> > -       return 0;
> > +               if (!sun6i_csi_capture_format_check(capture_format,
> > +                                                   bridge_format))
> > +                       continue;
> > +
> > +               if (index_valid == index) {
> > +                       fmtdesc->pixelformat = capture_format->pixelformat;
> > +                       return 0;
> > +               }
> > +
> > +               index_valid++;
> > +       }
> > +
> > +       return -EINVAL;
> >  }
> >
> >  static int sun6i_csi_capture_enum_framesize(struct file *file, void *fh,
> > @@ -1076,7 +1105,8 @@ int sun6i_csi_capture_setup(struct sun6i_csi_device *csi_dev)
> >
> >         strscpy(video_dev->name, SUN6I_CSI_CAPTURE_NAME,
> >                 sizeof(video_dev->name));
> > -       video_dev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
> > +       video_dev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
> > +                                V4L2_CAP_IO_MC;
> >         video_dev->vfl_dir = VFL_DIR_RX;
> >         video_dev->release = video_device_release_empty;
> >         video_dev->fops = &sun6i_csi_capture_fops;
> > --
> > 2.54.0
> >
> 
> Tested on a LicheePi Zero Dock (V3s) with the following pipeline:
> 
> ov7670 -> sun6i-csi-bridge -> sun6i-csi-capture
> 
> I verified that mbus-code-based format enumeration works correctly
> from userspace and that the reported capture formats change according
> to the selected media bus format.
> 
> I could also successfully start streaming with several of the
> enumerated capture formats (e.g. YUYV and BA81)

Excellent, thank-you very much for testing this!

> However, I could not fully validate actual format conversion behavior
> (e.g. MEDIA_BUS_FMT_YUYV8_2X8 to NV12) because my OV7670 setup
> currently has non-functional test patterns except for 'shifting-1'
> mode.

That's fine. I don't think I have tested it recently either.

> Tested-by: Arash Golgol <arash.golgol@gmail.com>
> 
> PS:
> 
> While testing this patch I also noticed that
> VIDIOC_SUBDEV_ENUM_MBUS_CODE reports duplicate entries for:
>  - MEDIA_BUS_FMT_UYVY8_2X8
>  - MEDIA_BUS_FMT_UYVY8_1X16
> on sun6i-csi-bridge.

I just had a look and you are definitely right, the entries are clearly
duplicates and at the same time all the relevant formats are included, so they
are not taking the place of another format that was forgotten.

You're welcome to submit a patch to remove these entries if you'd like,
or I could do it otherwise.

By the way would you be interested in testing the H.264 encoder support for
V3/V3s once I send a first version for it? I had written initial support for
it a while ago (did not send it to the list) and now that my work on the V4L2
stateless uAPI has reached a point of usability I will probably try to update
my rework of the cedrus driver to use it.

All the best,

Paul

> This appears to come from duplicate format entries being exposed by
> the bridge driver.
> 
> -- 
> Regards,
> Arash Golgol
  
arash golgol May 27, 2026, 11:53 a.m. UTC | #3
Hi Paul,

On Wed, May 27, 2026 at 11:29 AM Paul Kocialkowski <paulk@sys-base.io> wrote:
>
> Hi Arash,
>
> On Wed 27 May 26, 09:20, arash golgol wrote:
> > On Mon, May 18, 2026 at 2:00 PM Paul Kocialkowski <paulk@sys-base.io> wrote:
> > >
> > > Use the dedicated helper to check possible pixelformats against the
> > > provided mbus code in order to support MC-centric format enumeration.
> > >
> > > Note that multiple pixelformats may be returned for a given mbus code.
> > >
> > > Signed-off-by: Paul Kocialkowski <paulk@sys-base.io>
> > > ---
> > >  .../sunxi/sun6i-csi/sun6i_csi_capture.c       | 38 +++++++++++++++++--
> > >  1 file changed, 34 insertions(+), 4 deletions(-)
> > >
> > > diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
> > > index a836fa7f081a..409c28621093 100644
> > > --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
> > > +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
> > > @@ -773,14 +773,43 @@ static int sun6i_csi_capture_querycap(struct file *file, void *priv,
> > >  static int sun6i_csi_capture_enum_fmt(struct file *file, void *priv,
> > >                                       struct v4l2_fmtdesc *fmtdesc)
> > >  {
> > > +       const struct sun6i_csi_capture_format *capture_format;
> > > +       const struct sun6i_csi_bridge_format *bridge_format;
> > > +       u32 mbus_code = fmtdesc->mbus_code;
> > >         u32 index = fmtdesc->index;
> > > +       unsigned int index_valid = 0;
> > > +       unsigned int i;
> > > +
> > > +       /* Video-node-centric enumeration. */
> > > +       if (!mbus_code) {
> > > +               if (index >= ARRAY_SIZE(sun6i_csi_capture_formats))
> > > +                       return -EINVAL;
> > > +
> > > +               fmtdesc->pixelformat =
> > > +                       sun6i_csi_capture_formats[index].pixelformat;
> > > +               return 0;
> > > +       }
> > >
> > > -       if (index >= ARRAY_SIZE(sun6i_csi_capture_formats))
> > > +       bridge_format = sun6i_csi_bridge_format_find(mbus_code);
> > > +       if (!bridge_format)
> > >                 return -EINVAL;
> > >
> > > -       fmtdesc->pixelformat = sun6i_csi_capture_formats[index].pixelformat;
> > > +       for (i = 0; i < ARRAY_SIZE(sun6i_csi_capture_formats); i++) {
> > > +               capture_format = &sun6i_csi_capture_formats[i];
> > >
> > > -       return 0;
> > > +               if (!sun6i_csi_capture_format_check(capture_format,
> > > +                                                   bridge_format))
> > > +                       continue;
> > > +
> > > +               if (index_valid == index) {
> > > +                       fmtdesc->pixelformat = capture_format->pixelformat;
> > > +                       return 0;
> > > +               }
> > > +
> > > +               index_valid++;
> > > +       }
> > > +
> > > +       return -EINVAL;
> > >  }
> > >
> > >  static int sun6i_csi_capture_enum_framesize(struct file *file, void *fh,
> > > @@ -1076,7 +1105,8 @@ int sun6i_csi_capture_setup(struct sun6i_csi_device *csi_dev)
> > >
> > >         strscpy(video_dev->name, SUN6I_CSI_CAPTURE_NAME,
> > >                 sizeof(video_dev->name));
> > > -       video_dev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
> > > +       video_dev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
> > > +                                V4L2_CAP_IO_MC;
> > >         video_dev->vfl_dir = VFL_DIR_RX;
> > >         video_dev->release = video_device_release_empty;
> > >         video_dev->fops = &sun6i_csi_capture_fops;
> > > --
> > > 2.54.0
> > >
> >
> > Tested on a LicheePi Zero Dock (V3s) with the following pipeline:
> >
> > ov7670 -> sun6i-csi-bridge -> sun6i-csi-capture
> >
> > I verified that mbus-code-based format enumeration works correctly
> > from userspace and that the reported capture formats change according
> > to the selected media bus format.
> >
> > I could also successfully start streaming with several of the
> > enumerated capture formats (e.g. YUYV and BA81)
>
> Excellent, thank-you very much for testing this!
>

Happy to help.

> > However, I could not fully validate actual format conversion behavior
> > (e.g. MEDIA_BUS_FMT_YUYV8_2X8 to NV12) because my OV7670 setup
> > currently has non-functional test patterns except for 'shifting-1'
> > mode.
>
> That's fine. I don't think I have tested it recently either.
>
> > Tested-by: Arash Golgol <arash.golgol@gmail.com>
> >
> > PS:
> >
> > While testing this patch I also noticed that
> > VIDIOC_SUBDEV_ENUM_MBUS_CODE reports duplicate entries for:
> >  - MEDIA_BUS_FMT_UYVY8_2X8
> >  - MEDIA_BUS_FMT_UYVY8_1X16
> > on sun6i-csi-bridge.
>
> I just had a look and you are definitely right, the entries are clearly
> duplicates and at the same time all the relevant formats are included, so they
> are not taking the place of another format that was forgotten.
>
> You're welcome to submit a patch to remove these entries if you'd like,
> or I could do it otherwise.
>

Thanks, I'll send a small patch to remove the duplicate mbus format entries.

> By the way would you be interested in testing the H.264 encoder support for
> V3/V3s once I send a first version for it? I had written initial support for
> it a while ago (did not send it to the list) and now that my work on the V4L2
> stateless uAPI has reached a point of usability I will probably try to update
> my rework of the cedrus driver to use it.
>

Yes, I would definitely be interested in testing the H.264 encoder
support on V3s once you post it. I previously did some experiments
with Cedrus on V3s (bootlin, cedrus/h264-encoding branch).

Looking forward to it!
  

Patch

diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
index a836fa7f081a..409c28621093 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
@@ -773,14 +773,43 @@  static int sun6i_csi_capture_querycap(struct file *file, void *priv,
 static int sun6i_csi_capture_enum_fmt(struct file *file, void *priv,
 				      struct v4l2_fmtdesc *fmtdesc)
 {
+	const struct sun6i_csi_capture_format *capture_format;
+	const struct sun6i_csi_bridge_format *bridge_format;
+	u32 mbus_code = fmtdesc->mbus_code;
 	u32 index = fmtdesc->index;
+	unsigned int index_valid = 0;
+	unsigned int i;
+
+	/* Video-node-centric enumeration. */
+	if (!mbus_code) {
+		if (index >= ARRAY_SIZE(sun6i_csi_capture_formats))
+			return -EINVAL;
+
+		fmtdesc->pixelformat =
+			sun6i_csi_capture_formats[index].pixelformat;
+		return 0;
+	}
 
-	if (index >= ARRAY_SIZE(sun6i_csi_capture_formats))
+	bridge_format = sun6i_csi_bridge_format_find(mbus_code);
+	if (!bridge_format)
 		return -EINVAL;
 
-	fmtdesc->pixelformat = sun6i_csi_capture_formats[index].pixelformat;
+	for (i = 0; i < ARRAY_SIZE(sun6i_csi_capture_formats); i++) {
+		capture_format = &sun6i_csi_capture_formats[i];
 
-	return 0;
+		if (!sun6i_csi_capture_format_check(capture_format,
+						    bridge_format))
+			continue;
+
+		if (index_valid == index) {
+			fmtdesc->pixelformat = capture_format->pixelformat;
+			return 0;
+		}
+
+		index_valid++;
+	}
+
+	return -EINVAL;
 }
 
 static int sun6i_csi_capture_enum_framesize(struct file *file, void *fh,
@@ -1076,7 +1105,8 @@  int sun6i_csi_capture_setup(struct sun6i_csi_device *csi_dev)
 
 	strscpy(video_dev->name, SUN6I_CSI_CAPTURE_NAME,
 		sizeof(video_dev->name));
-	video_dev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+	video_dev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
+				 V4L2_CAP_IO_MC;
 	video_dev->vfl_dir = VFL_DIR_RX;
 	video_dev->release = video_device_release_empty;
 	video_dev->fops = &sun6i_csi_capture_fops;