diff mbox

[v6,4/6] media: i2c: Add TDA1997x HDMI receiver driver

Message ID 83695d60-5052-14ba-4f7b-23f153a05a85@xs4all.nl (mailing list archive)
State New, archived
Headers show

Commit Message

Hans Verkuil Jan. 31, 2018, 1:22 p.m. UTC
On 01/31/18 08:38, Hans Verkuil wrote:
> On 01/31/2018 05:51 AM, Tim Harvey wrote:
>> On Mon, Jan 29, 2018 at 4:00 AM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
>>> On 01/25/2018 05:15 PM, Tim Harvey wrote:
>> <snip>
>>>>>
>>>>> Hmm. This receiver supports multiple output formats, but you advertise only one.
>>>>> That looks wrong. If nothing else, you should be able to switch between RGB and
>>>>> YUV 4:4:4 since they use the same port config.
>>>>>
>>>>> It's a common use-case that you want to switch between RGB and YUV depending on
>>>>> the source material (i.e. if you receive a desktop/graphics then RGB is best, if
>>>>> you receive video then YUV 4:2:2 or 4:2:0 is best).
>>>>>
>>>>> Hardcoding just one format won't do.
>>>>>
>>>>
>>>> I've been thinking about this a bit. I had hard-coded a single format
>>>> for now because I haven't had any good ideas on how to deal with the
>>>> fact that the port mappings would need to differ if you change from
>>>> the RGB888/YUV444 (I think these are referred to as 'planar' formats?)
>>>> to YUV422 (semi-planar) and BT656 formats. It is true though that the
>>>> 36bit (TDA19973) RGB888/YUV444 and 24bit (TDA19971/2) formats can both
>>>> be supported with the same port mappings / pinout.
>>>
>>> Regarding terminology:
>>>
>>> RGB and YUV are typically interleaved, i.e. the color components are
>>> (for two pixels) either RGBRGB for RGB888, YUVYUV for YUV444 or YUYV
>>> for YUV422.
>>>
>>> Planar formats are in practice only seen for YUV and will first output
>>> all Y samples, and then the UV samples. This requires that the hardware
>>> buffers the frame and that's not normally done by HDMI receivers.
>>>
>>> The DMA engine, however, is often able to split up the interleaved YUV
>>> samples that it receives and DMA them to separate buffers, thus turning
>>> an interleaved media bus format to a planar memory format.
>>>
>>> BT656 doesn't refer to how the samples are transferred, instead it
>>> refers to how the hsync and vsync are reported. The enum v4l2_mbus_type
>>> has various options, one of them being BT656.
>>>
>>> Which mbus type is used is board specific (and should come from the
>>> device tree). Whether to transmit RGB888, YUV444 or YUV422 (or possibly
>>> even YUV420) is dynamic and is up to userspace since it is use-case
>>> dependent.
>>>
>>> So you'll never switch between BT656 and CSI, but you can switch between
>>> BT656+RGB and BT656+YUV, or between CSI+RGB and CSI+YUV.
>>>
>>>>
>>>> For example the GW5400 has a TDA19971 mapped to IMX6 CSI_DATA[19:4]
>>>> (16bit) for YUV422. However if you want to use BT656 you have to shift
>>>> the TDA19971 port mappings to get the YCbCr pins mapped to
>>>> CSI_DATA[19:x] and those pin groups are at the bottom of the bus for
>>>> the RGB888/YUV444 format.
>>>
>>> As mentioned above, you wouldn't switch between mbus types.
>>>
>>>>
>>>> I suppose however that perhaps for the example above if I have a 16bit
>>>> width required to support YUV422 there would never be a useful case
>>>> for supporting 8-bit/10-bit/12-bit BT656 on the same board?
>>>
>>> You wouldn't switch between mbus types, but if the device tree configures
>>> BT.656 with a bus width of 24 bits, then the application might very well
>>> want to dynamically switch between 8, 10 and 12 bits per color component.
>>>
>>
>> Hans,
>>
>> I just submitted a v7 with multiple format support. Your point about
>> bus_type being specified by dt is exactly what I needed to help make
>> sense of the formats.
> 
> Ah, good. It took me some time as well before I realized that the confusion
> was in mixing up bus types and formats.
> 
>> That said, I'm unsure how to properly test the enum_mbus_code() pad op
>> function. How do you obtain a list of valid formats on a subdev?
>>
>> I tried the following:
>> root@ventana:~# media-ctl -e 'tda19971 2-0048'
>> /dev/v4l-subdev1
>> root@ventana:~# media-ctl --get-v4l2 '"tda19971 2-0048":0'
>>                 [fmt:UYVY8_2X8/1280x720 field:none colorspace:srgb]
>> ^^^^ calls get_format and returns the 1 and only format available for
>> my tda19971 with 16bit parallel bus
>> root@ventana:~# v4l2-ctl -d /dev/v4l-subdev1 --get-fmt-video-out
>> VIDIOC_G_FMT: failed: Inappropriate ioctl for device
>> root@ventana:~# v4l2-ctl -d /dev/v4l-subdev1 --list-formats-out
>> ioctl: VIDIOC_ENUM_FMT
>>
>> I'm thinking perhaps enumerating the list of possible formats is a
>> missing feature in media-ctl?
> 
> Yeah, it is. Surprising, really. Ditto for the SUBDEV_ENUM_FRAME_SIZE/INTERVAL
> ioctls.
> 
> I wonder whether this should be added to v4l2-ctl, media-ctl or both. I always
> felt that media-ctl is more about setting up the whole pipeline, whereas v4l2-ctl
> is specific to a V4L2 device.
> 
> Regards,
> 
> 	Hans
> 

Here is a quick patch adding support for enumerating mbus codes to v4l2-ctl.
You get some compile warnings, just ignore those.

An example using vimc, listing the code for pad 1:

$ ./v4l2-ctl -d /dev/v4l-subdev5 --list-subdev-mbus-codes=1
ioctl: VIDIOC_SUBDEV_ENUM_MBUS_CODE
        0x00001013: BGR888_1X24
        0x0000100a: RGB888_1X24
        0x0000100d: ARGB8888_1X32

Regards,

	Hans

---------------- cut here ------------------------

Comments

Tim Harvey Feb. 1, 2018, 4:47 a.m. UTC | #1
Tim Harvey - Principal Software Engineer
Gateworks Corporation - http://www.gateworks.com/
3026 S. Higuera St. San Luis Obispo CA 93401
805-781-2000


On Wed, Jan 31, 2018 at 5:22 AM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
> On 01/31/18 08:38, Hans Verkuil wrote:
>> On 01/31/2018 05:51 AM, Tim Harvey wrote:
>>> On Mon, Jan 29, 2018 at 4:00 AM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
>>>> On 01/25/2018 05:15 PM, Tim Harvey wrote:
>>> <snip>
>>>>>>
>>>>>> Hmm. This receiver supports multiple output formats, but you advertise only one.
>>>>>> That looks wrong. If nothing else, you should be able to switch between RGB and
>>>>>> YUV 4:4:4 since they use the same port config.
>>>>>>
>>>>>> It's a common use-case that you want to switch between RGB and YUV depending on
>>>>>> the source material (i.e. if you receive a desktop/graphics then RGB is best, if
>>>>>> you receive video then YUV 4:2:2 or 4:2:0 is best).
>>>>>>
>>>>>> Hardcoding just one format won't do.
>>>>>>
>>>>>
>>>>> I've been thinking about this a bit. I had hard-coded a single format
>>>>> for now because I haven't had any good ideas on how to deal with the
>>>>> fact that the port mappings would need to differ if you change from
>>>>> the RGB888/YUV444 (I think these are referred to as 'planar' formats?)
>>>>> to YUV422 (semi-planar) and BT656 formats. It is true though that the
>>>>> 36bit (TDA19973) RGB888/YUV444 and 24bit (TDA19971/2) formats can both
>>>>> be supported with the same port mappings / pinout.
>>>>
>>>> Regarding terminology:
>>>>
>>>> RGB and YUV are typically interleaved, i.e. the color components are
>>>> (for two pixels) either RGBRGB for RGB888, YUVYUV for YUV444 or YUYV
>>>> for YUV422.
>>>>
>>>> Planar formats are in practice only seen for YUV and will first output
>>>> all Y samples, and then the UV samples. This requires that the hardware
>>>> buffers the frame and that's not normally done by HDMI receivers.
>>>>
>>>> The DMA engine, however, is often able to split up the interleaved YUV
>>>> samples that it receives and DMA them to separate buffers, thus turning
>>>> an interleaved media bus format to a planar memory format.
>>>>
>>>> BT656 doesn't refer to how the samples are transferred, instead it
>>>> refers to how the hsync and vsync are reported. The enum v4l2_mbus_type
>>>> has various options, one of them being BT656.
>>>>
>>>> Which mbus type is used is board specific (and should come from the
>>>> device tree). Whether to transmit RGB888, YUV444 or YUV422 (or possibly
>>>> even YUV420) is dynamic and is up to userspace since it is use-case
>>>> dependent.
>>>>
>>>> So you'll never switch between BT656 and CSI, but you can switch between
>>>> BT656+RGB and BT656+YUV, or between CSI+RGB and CSI+YUV.
>>>>
>>>>>
>>>>> For example the GW5400 has a TDA19971 mapped to IMX6 CSI_DATA[19:4]
>>>>> (16bit) for YUV422. However if you want to use BT656 you have to shift
>>>>> the TDA19971 port mappings to get the YCbCr pins mapped to
>>>>> CSI_DATA[19:x] and those pin groups are at the bottom of the bus for
>>>>> the RGB888/YUV444 format.
>>>>
>>>> As mentioned above, you wouldn't switch between mbus types.
>>>>
>>>>>
>>>>> I suppose however that perhaps for the example above if I have a 16bit
>>>>> width required to support YUV422 there would never be a useful case
>>>>> for supporting 8-bit/10-bit/12-bit BT656 on the same board?
>>>>
>>>> You wouldn't switch between mbus types, but if the device tree configures
>>>> BT.656 with a bus width of 24 bits, then the application might very well
>>>> want to dynamically switch between 8, 10 and 12 bits per color component.
>>>>
>>>
>>> Hans,
>>>
>>> I just submitted a v7 with multiple format support. Your point about
>>> bus_type being specified by dt is exactly what I needed to help make
>>> sense of the formats.
>>
>> Ah, good. It took me some time as well before I realized that the confusion
>> was in mixing up bus types and formats.
>>
>>> That said, I'm unsure how to properly test the enum_mbus_code() pad op
>>> function. How do you obtain a list of valid formats on a subdev?
>>>
>>> I tried the following:
>>> root@ventana:~# media-ctl -e 'tda19971 2-0048'
>>> /dev/v4l-subdev1
>>> root@ventana:~# media-ctl --get-v4l2 '"tda19971 2-0048":0'
>>>                 [fmt:UYVY8_2X8/1280x720 field:none colorspace:srgb]
>>> ^^^^ calls get_format and returns the 1 and only format available for
>>> my tda19971 with 16bit parallel bus
>>> root@ventana:~# v4l2-ctl -d /dev/v4l-subdev1 --get-fmt-video-out
>>> VIDIOC_G_FMT: failed: Inappropriate ioctl for device
>>> root@ventana:~# v4l2-ctl -d /dev/v4l-subdev1 --list-formats-out
>>> ioctl: VIDIOC_ENUM_FMT
>>>
>>> I'm thinking perhaps enumerating the list of possible formats is a
>>> missing feature in media-ctl?
>>
>> Yeah, it is. Surprising, really. Ditto for the SUBDEV_ENUM_FRAME_SIZE/INTERVAL
>> ioctls.
>>
>> I wonder whether this should be added to v4l2-ctl, media-ctl or both. I always
>> felt that media-ctl is more about setting up the whole pipeline, whereas v4l2-ctl
>> is specific to a V4L2 device.
>>
>> Regards,
>>
>>       Hans
>>
>
> Here is a quick patch adding support for enumerating mbus codes to v4l2-ctl.
> You get some compile warnings, just ignore those.
>
> An example using vimc, listing the code for pad 1:
>
> $ ./v4l2-ctl -d /dev/v4l-subdev5 --list-subdev-mbus-codes=1
> ioctl: VIDIOC_SUBDEV_ENUM_MBUS_CODE
>         0x00001013: BGR888_1X24
>         0x0000100a: RGB888_1X24
>         0x0000100d: ARGB8888_1X32
>
> Regards,
>
>         Hans
>
> ---------------- cut here ------------------------
> diff --git a/utils/v4l2-ctl/Makefile.am b/utils/v4l2-ctl/Makefile.am
> index 83fa49a3..b3ccfc8b 100644
> --- a/utils/v4l2-ctl/Makefile.am
> +++ b/utils/v4l2-ctl/Makefile.am
> @@ -6,9 +6,16 @@ v4l2_ctl_SOURCES = v4l2-ctl.cpp v4l2-ctl.h v4l2-ctl-common.cpp v4l2-ctl-tuner.cp
>         v4l2-ctl-io.cpp v4l2-ctl-stds.cpp v4l2-ctl-vidcap.cpp v4l2-ctl-vidout.cpp \
>         v4l2-ctl-overlay.cpp v4l2-ctl-vbi.cpp v4l2-ctl-selection.cpp v4l2-ctl-misc.cpp \
>         v4l2-ctl-streaming.cpp v4l2-ctl-sdr.cpp v4l2-ctl-edid.cpp v4l2-ctl-modes.cpp \
> -       v4l2-tpg-colors.c v4l2-tpg-core.c v4l-stream.c v4l2-ctl-meta.cpp
> +       v4l2-ctl-subdev.cpp v4l2-tpg-colors.c v4l2-tpg-core.c v4l-stream.c v4l2-ctl-meta.cpp
>  v4l2_ctl_CPPFLAGS = -I$(top_srcdir)/utils/common
>
> +media-bus-format-names.h: ../../include/linux/media-bus-format.h
> +       sed -e '/#define MEDIA_BUS_FMT/ ! d; s/.*FMT_//; /FIXED/ d; s/\t.*//; s/.*/{ \"&\", MEDIA_BUS_FMT_& },/;' \
> +       < $< > $@
> +
> +BUILT_SOURCES = media-bus-format-names.h
> +CLEANFILES = $(BUILT_SOURCES)
> +
>  if WITH_V4L2_CTL_LIBV4L
>  v4l2_ctl_LDADD = ../../lib/libv4l2/libv4l2.la ../../lib/libv4lconvert/libv4lconvert.la -lrt -lpthread
>  else
> diff --git a/utils/v4l2-ctl/v4l2-ctl-common.cpp b/utils/v4l2-ctl/v4l2-ctl-common.cpp
> index 46e621f7..2f521f5d 100644
> --- a/utils/v4l2-ctl/v4l2-ctl-common.cpp
> +++ b/utils/v4l2-ctl/v4l2-ctl-common.cpp
> @@ -91,6 +91,8 @@ void common_usage(void)
>  #ifndef NO_LIBV4L2
>                "  -w, --wrapper      use the libv4l2 wrapper library.\n"
>  #endif
> +              "  --which-is-try     set the 'which' argument to V4L2_SUBDEV_FORMAT_TRY instead of\n"
> +              "                     V4L2_SUBDEV_FORMAT_ACTIVE (the default)\n"
>                "  --list-devices     list all v4l devices\n"
>                "  --log-status       log the board status in the kernel log [VIDIOC_LOG_STATUS]\n"
>                "  --get-priority     query the current access priority [VIDIOC_G_PRIORITY]\n"
> diff --git a/utils/v4l2-ctl/v4l2-ctl.cpp b/utils/v4l2-ctl/v4l2-ctl.cpp
> index e02dc756..9dced5b1 100644
> --- a/utils/v4l2-ctl/v4l2-ctl.cpp
> +++ b/utils/v4l2-ctl/v4l2-ctl.cpp
> @@ -83,6 +83,7 @@ static struct option long_options[] = {
>         {"help-vbi", no_argument, 0, OptHelpVbi},
>         {"help-sdr", no_argument, 0, OptHelpSdr},
>         {"help-meta", no_argument, 0, OptHelpMeta},
> +       {"help-subdev", no_argument, 0, OptHelpSubDev},
>         {"help-selection", no_argument, 0, OptHelpSelection},
>         {"help-misc", no_argument, 0, OptHelpMisc},
>         {"help-streaming", no_argument, 0, OptHelpStreaming},
> @@ -91,6 +92,7 @@ static struct option long_options[] = {
>  #ifndef NO_LIBV4L2
>         {"wrapper", no_argument, 0, OptUseWrapper},
>  #endif
> +       {"which-is-try", no_argument, 0, OptWhichIsTry},
>         {"concise", no_argument, 0, OptConcise},
>         {"get-output", no_argument, 0, OptGetOutput},
>         {"set-output", required_argument, 0, OptSetOutput},
> @@ -115,6 +117,7 @@ static struct option long_options[] = {
>         {"list-formats-sdr-out", no_argument, 0, OptListSdrOutFormats},
>         {"list-formats-out", no_argument, 0, OptListOutFormats},
>         {"list-formats-meta", no_argument, 0, OptListMetaFormats},
> +       {"list-subdev-mbus-codes", optional_argument, 0, OptListSubDevMBusCodes},
>         {"list-fields-out", no_argument, 0, OptListOutFields},
>         {"clear-clips", no_argument, 0, OptClearClips},
>         {"clear-bitmap", no_argument, 0, OptClearBitmap},
> @@ -1212,6 +1215,7 @@ int main(int argc, char **argv)
>         const char *wait_event_id = NULL;
>         __u32 poll_for_event = 0;       /* poll for this event */
>         const char *poll_event_id = NULL;
> +       __u32 which = V4L2_SUBDEV_FORMAT_ACTIVE;
>         unsigned secs = 0;
>         char short_options[26 * 2 * 3 + 1];
>         int idx = 0;
> @@ -1274,6 +1278,9 @@ int main(int argc, char **argv)
>                 case OptHelpMeta:
>                         meta_usage();
>                         return 0;
> +               case OptHelpSubDev:
> +                       subdev_usage();
> +                       return 0;
>                 case OptHelpSelection:
>                         selection_usage();
>                         return 0;
> @@ -1317,6 +1324,9 @@ int main(int argc, char **argv)
>                         if (poll_for_event == 0)
>                                 return 1;
>                         break;
> +               case OptWhichIsTry:
> +                       which = V4L2_SUBDEV_FORMAT_TRY;
> +                       break;
>                 case OptSleep:
>                         secs = strtoul(optarg, 0L, 0);
>                         break;
> @@ -1341,6 +1351,7 @@ int main(int argc, char **argv)
>                         vbi_cmd(ch, optarg);
>                         sdr_cmd(ch, optarg);
>                         meta_cmd(ch, optarg);
> +                       subdev_cmd(ch, optarg);
>                         selection_cmd(ch, optarg);
>                         misc_cmd(ch, optarg);
>                         streaming_cmd(ch, optarg);
> @@ -1480,6 +1491,7 @@ int main(int argc, char **argv)
>         vbi_set(fd);
>         sdr_set(fd);
>         meta_set(fd);
> +       subdev_set(fd, which);
>         selection_set(fd);
>         streaming_set(fd, out_fd);
>         misc_set(fd);
> @@ -1497,6 +1509,7 @@ int main(int argc, char **argv)
>         vbi_get(fd);
>         sdr_get(fd);
>         meta_get(fd);
> +       subdev_get(fd, which);
>         selection_get(fd);
>         misc_get(fd);
>         edid_get(fd);
> @@ -1512,6 +1525,7 @@ int main(int argc, char **argv)
>         vbi_list(fd);
>         sdr_list(fd);
>         meta_list(fd);
> +       subdev_list(fd, which);
>         streaming_list(fd, out_fd);
>
>         if (options[OptWaitForEvent]) {
> diff --git a/utils/v4l2-ctl/v4l2-ctl.h b/utils/v4l2-ctl/v4l2-ctl.h
> index 3b56d8a6..2ac29268 100644
> --- a/utils/v4l2-ctl/v4l2-ctl.h
> +++ b/utils/v4l2-ctl/v4l2-ctl.h
> @@ -10,6 +10,7 @@
>  #include <string>
>
>  #include <linux/videodev2.h>
> +#include <linux/v4l2-subdev.h>
>
>  #ifndef NO_LIBV4L2
>  #include <libv4l2.h>
> @@ -58,6 +59,7 @@ enum Option {
>         OptGetVideoFormat = 'V',
>         OptSetVideoFormat = 'v',
>         OptUseWrapper = 'w',
> +       OptWhichIsTry = 'W',
>
>         OptGetSlicedVbiOutFormat = 128,
>         OptGetOverlayFormat,
> @@ -97,6 +99,7 @@ enum Option {
>         OptListSdrOutFormats,
>         OptListOutFormats,
>         OptListMetaFormats,
> +       OptListSubDevMBusCodes,
>         OptListOutFields,
>         OptClearClips,
>         OptClearBitmap,
> @@ -211,6 +214,7 @@ enum Option {
>         OptHelpVbi,
>         OptHelpSdr,
>         OptHelpMeta,
> +       OptHelpSubDev,
>         OptHelpSelection,
>         OptHelpMisc,
>         OptHelpStreaming,
> @@ -345,6 +349,13 @@ void meta_set(int fd);
>  void meta_get(int fd);
>  void meta_list(int fd);
>
> +// v4l2-ctl-subdev.cpp
> +void subdev_usage(void);
> +void subdev_cmd(int ch, char *optarg);
> +void subdev_set(int fd, __u32 which);
> +void subdev_get(int fd, __u32 which);
> +void subdev_list(int fd, __u32 which);
> +
>  // v4l2-ctl-selection.cpp
>  void selection_usage(void);
>  void selection_cmd(int ch, char *optarg);
>

Hans,

You forgot to include v4l2-ctl-selection.cpp in your patch.

Regards,

Tim
Hans Verkuil Feb. 1, 2018, 7:19 a.m. UTC | #2
On 02/01/2018 05:47 AM, Tim Harvey wrote:
> Hans,
> 
> You forgot to include v4l2-ctl-selection.cpp in your patch.

You mean v4l2-ctl-subdev.cpp :-)

Anyway, I plan on committing this to v4l2-ctl soon. I'll let you know
when that's done.

I added support for almost all subdev ioctls to v4l2-ctl.

Regards,

	Hans
diff mbox

Patch

diff --git a/utils/v4l2-ctl/Makefile.am b/utils/v4l2-ctl/Makefile.am
index 83fa49a3..b3ccfc8b 100644
--- a/utils/v4l2-ctl/Makefile.am
+++ b/utils/v4l2-ctl/Makefile.am
@@ -6,9 +6,16 @@  v4l2_ctl_SOURCES = v4l2-ctl.cpp v4l2-ctl.h v4l2-ctl-common.cpp v4l2-ctl-tuner.cp
 	v4l2-ctl-io.cpp v4l2-ctl-stds.cpp v4l2-ctl-vidcap.cpp v4l2-ctl-vidout.cpp \
 	v4l2-ctl-overlay.cpp v4l2-ctl-vbi.cpp v4l2-ctl-selection.cpp v4l2-ctl-misc.cpp \
 	v4l2-ctl-streaming.cpp v4l2-ctl-sdr.cpp v4l2-ctl-edid.cpp v4l2-ctl-modes.cpp \
-	v4l2-tpg-colors.c v4l2-tpg-core.c v4l-stream.c v4l2-ctl-meta.cpp
+	v4l2-ctl-subdev.cpp v4l2-tpg-colors.c v4l2-tpg-core.c v4l-stream.c v4l2-ctl-meta.cpp
 v4l2_ctl_CPPFLAGS = -I$(top_srcdir)/utils/common

+media-bus-format-names.h: ../../include/linux/media-bus-format.h
+	sed -e '/#define MEDIA_BUS_FMT/ ! d; s/.*FMT_//; /FIXED/ d; s/\t.*//; s/.*/{ \"&\", MEDIA_BUS_FMT_& },/;' \
+	< $< > $@
+
+BUILT_SOURCES = media-bus-format-names.h
+CLEANFILES = $(BUILT_SOURCES)
+
 if WITH_V4L2_CTL_LIBV4L
 v4l2_ctl_LDADD = ../../lib/libv4l2/libv4l2.la ../../lib/libv4lconvert/libv4lconvert.la -lrt -lpthread
 else
diff --git a/utils/v4l2-ctl/v4l2-ctl-common.cpp b/utils/v4l2-ctl/v4l2-ctl-common.cpp
index 46e621f7..2f521f5d 100644
--- a/utils/v4l2-ctl/v4l2-ctl-common.cpp
+++ b/utils/v4l2-ctl/v4l2-ctl-common.cpp
@@ -91,6 +91,8 @@  void common_usage(void)
 #ifndef NO_LIBV4L2
 	       "  -w, --wrapper      use the libv4l2 wrapper library.\n"
 #endif
+	       "  --which-is-try     set the 'which' argument to V4L2_SUBDEV_FORMAT_TRY instead of\n"
+	       "                     V4L2_SUBDEV_FORMAT_ACTIVE (the default)\n"
 	       "  --list-devices     list all v4l devices\n"
 	       "  --log-status       log the board status in the kernel log [VIDIOC_LOG_STATUS]\n"
 	       "  --get-priority     query the current access priority [VIDIOC_G_PRIORITY]\n"
diff --git a/utils/v4l2-ctl/v4l2-ctl.cpp b/utils/v4l2-ctl/v4l2-ctl.cpp
index e02dc756..9dced5b1 100644
--- a/utils/v4l2-ctl/v4l2-ctl.cpp
+++ b/utils/v4l2-ctl/v4l2-ctl.cpp
@@ -83,6 +83,7 @@  static struct option long_options[] = {
 	{"help-vbi", no_argument, 0, OptHelpVbi},
 	{"help-sdr", no_argument, 0, OptHelpSdr},
 	{"help-meta", no_argument, 0, OptHelpMeta},
+	{"help-subdev", no_argument, 0, OptHelpSubDev},
 	{"help-selection", no_argument, 0, OptHelpSelection},
 	{"help-misc", no_argument, 0, OptHelpMisc},
 	{"help-streaming", no_argument, 0, OptHelpStreaming},
@@ -91,6 +92,7 @@  static struct option long_options[] = {
 #ifndef NO_LIBV4L2
 	{"wrapper", no_argument, 0, OptUseWrapper},
 #endif
+	{"which-is-try", no_argument, 0, OptWhichIsTry},
 	{"concise", no_argument, 0, OptConcise},
 	{"get-output", no_argument, 0, OptGetOutput},
 	{"set-output", required_argument, 0, OptSetOutput},
@@ -115,6 +117,7 @@  static struct option long_options[] = {
 	{"list-formats-sdr-out", no_argument, 0, OptListSdrOutFormats},
 	{"list-formats-out", no_argument, 0, OptListOutFormats},
 	{"list-formats-meta", no_argument, 0, OptListMetaFormats},
+	{"list-subdev-mbus-codes", optional_argument, 0, OptListSubDevMBusCodes},
 	{"list-fields-out", no_argument, 0, OptListOutFields},
 	{"clear-clips", no_argument, 0, OptClearClips},
 	{"clear-bitmap", no_argument, 0, OptClearBitmap},
@@ -1212,6 +1215,7 @@  int main(int argc, char **argv)
 	const char *wait_event_id = NULL;
 	__u32 poll_for_event = 0;	/* poll for this event */
 	const char *poll_event_id = NULL;
+	__u32 which = V4L2_SUBDEV_FORMAT_ACTIVE;
 	unsigned secs = 0;
 	char short_options[26 * 2 * 3 + 1];
 	int idx = 0;
@@ -1274,6 +1278,9 @@  int main(int argc, char **argv)
 		case OptHelpMeta:
 			meta_usage();
 			return 0;
+		case OptHelpSubDev:
+			subdev_usage();
+			return 0;
 		case OptHelpSelection:
 			selection_usage();
 			return 0;
@@ -1317,6 +1324,9 @@  int main(int argc, char **argv)
 			if (poll_for_event == 0)
 				return 1;
 			break;
+		case OptWhichIsTry:
+			which = V4L2_SUBDEV_FORMAT_TRY;
+			break;
 		case OptSleep:
 			secs = strtoul(optarg, 0L, 0);
 			break;
@@ -1341,6 +1351,7 @@  int main(int argc, char **argv)
 			vbi_cmd(ch, optarg);
 			sdr_cmd(ch, optarg);
 			meta_cmd(ch, optarg);
+			subdev_cmd(ch, optarg);
 			selection_cmd(ch, optarg);
 			misc_cmd(ch, optarg);
 			streaming_cmd(ch, optarg);
@@ -1480,6 +1491,7 @@  int main(int argc, char **argv)
 	vbi_set(fd);
 	sdr_set(fd);
 	meta_set(fd);
+	subdev_set(fd, which);
 	selection_set(fd);
 	streaming_set(fd, out_fd);
 	misc_set(fd);
@@ -1497,6 +1509,7 @@  int main(int argc, char **argv)
 	vbi_get(fd);
 	sdr_get(fd);
 	meta_get(fd);
+	subdev_get(fd, which);
 	selection_get(fd);
 	misc_get(fd);
 	edid_get(fd);
@@ -1512,6 +1525,7 @@  int main(int argc, char **argv)
 	vbi_list(fd);
 	sdr_list(fd);
 	meta_list(fd);
+	subdev_list(fd, which);
 	streaming_list(fd, out_fd);

 	if (options[OptWaitForEvent]) {
diff --git a/utils/v4l2-ctl/v4l2-ctl.h b/utils/v4l2-ctl/v4l2-ctl.h
index 3b56d8a6..2ac29268 100644
--- a/utils/v4l2-ctl/v4l2-ctl.h
+++ b/utils/v4l2-ctl/v4l2-ctl.h
@@ -10,6 +10,7 @@ 
 #include <string>

 #include <linux/videodev2.h>
+#include <linux/v4l2-subdev.h>

 #ifndef NO_LIBV4L2
 #include <libv4l2.h>
@@ -58,6 +59,7 @@  enum Option {
 	OptGetVideoFormat = 'V',
 	OptSetVideoFormat = 'v',
 	OptUseWrapper = 'w',
+	OptWhichIsTry = 'W',

 	OptGetSlicedVbiOutFormat = 128,
 	OptGetOverlayFormat,
@@ -97,6 +99,7 @@  enum Option {
 	OptListSdrOutFormats,
 	OptListOutFormats,
 	OptListMetaFormats,
+	OptListSubDevMBusCodes,
 	OptListOutFields,
 	OptClearClips,
 	OptClearBitmap,
@@ -211,6 +214,7 @@  enum Option {
 	OptHelpVbi,
 	OptHelpSdr,
 	OptHelpMeta,
+	OptHelpSubDev,
 	OptHelpSelection,
 	OptHelpMisc,
 	OptHelpStreaming,
@@ -345,6 +349,13 @@  void meta_set(int fd);
 void meta_get(int fd);
 void meta_list(int fd);

+// v4l2-ctl-subdev.cpp
+void subdev_usage(void);
+void subdev_cmd(int ch, char *optarg);
+void subdev_set(int fd, __u32 which);
+void subdev_get(int fd, __u32 which);
+void subdev_list(int fd, __u32 which);
+
 // v4l2-ctl-selection.cpp
 void selection_usage(void);
 void selection_cmd(int ch, char *optarg);