diff mbox series

[RFC,7/7] media: i2c: tc358743: export InfoFrames to debugfs

Message ID 501bb64b027022ebcfb9636e9267dfba520c4a67.1724249421.git.hverkuil-cisco@xs4all.nl (mailing list archive)
State New
Headers show
Series media: export InfoFrames to debugfs | expand

Commit Message

Hans Verkuil Aug. 21, 2024, 2:10 p.m. UTC
Export InfoFrames to debugfs.

Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
---
 drivers/media/i2c/tc358743.c | 36 +++++++++++++++++++++++++++++++++++-
 1 file changed, 35 insertions(+), 1 deletion(-)

Comments

Dave Stevenson Aug. 21, 2024, 4:12 p.m. UTC | #1
Hi Hans

This is a very useful little series - thanks.

On Wed, 21 Aug 2024 at 15:16, Hans Verkuil <hverkuil-cisco@xs4all.nl> wrote:
>
> Export InfoFrames to debugfs.

I had a tc358743 to hand, so thought this warranted a quick test.
I think you have an off-by-one on the length that this exposes.

log_status is giving me state
   [  428.600874] tc358743 10-000f: -----HDMI status-----
   [  428.600881] tc358743 10-000f: HDCP encrypted content: no
   [  428.600887] tc358743 10-000f: Input color space: RGB limited range
   [  428.601404] tc358743 10-000f: AV Mute: off
   [  428.601921] tc358743 10-000f: Deep color mode: 8-bits per channel
   [  428.604407] tc358743 10-000f: HDMI infoframe: Auxiliary Video
Information (AVI), version 2, length 13
   [  428.604425] tc358743 10-000f:     colorspace: RGB
   [  428.604433] tc358743 10-000f:     scan mode: Underscan
   [  428.604441] tc358743 10-000f:     colorimetry: No Data
   [  428.604449] tc358743 10-000f:     picture aspect: 16:9
   [  428.604456] tc358743 10-000f:     active aspect: Same as Picture
   [  428.604463] tc358743 10-000f:     itc: No Data
   [  428.604469] tc358743 10-000f:     extended colorimetry: xvYCC 601
   [  428.604476] tc358743 10-000f:     quantization range: Limited
   [  428.604483] tc358743 10-000f:     nups: Unknown Non-uniform Scaling
   [  428.604490] tc358743 10-000f:     video code: 4
   [  428.604497] tc358743 10-000f:     ycc quantization range: Limited
   [  428.604505] tc358743 10-000f:     hdmi content type: Graphics
   [  428.604511] tc358743 10-000f:     pixel repeat: 0
   [  428.604519] tc358743 10-000f:     bar top 0, bottom 0, left 0, right 0

pi@bookworm64:~/edid-decode $ xxd /sys/kernel/debug/v4l2/tc358743\
10-000f/infoframes/avi
00000000: 8202 0d2d 1228 0404 0000 0000 0000 0000  ...-.(..........

At the transmitting end I've got
pi@bookworm64:~/edid-decode $ sudo xxd
/sys/kernel/debug/dri/1/HDMI-A-1/infoframes/avi
00000000: 8202 0d2d 1228 0404 0000 0000 0000 0000  ...-.(..........
00000010: 00

edid-decode -I decodes the latter fine, but aborts on the former.
Oddly the "fail" message from parse_if_hdr [1] doesn't get printed, it
just stops with
pi@bookworm64:~/edid-decode $ ./build/edid-decode -I
/sys/kernel/debug/v4l2/tc358743\ 10-000f/infoframes/avi
edid-decode InfoFrame (hex):

82 02 0d 2d 12 28 04 04 00 00 00 00 00 00 00 00

----------------

HDMI InfoFrame Checksum: 0x2d

AVI InfoFrame
  Version: 2
  Length: 13


[1] https://git.linuxtv.org/edid-decode.git/tree/parse-if.cpp#n21

> Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
> ---
>  drivers/media/i2c/tc358743.c | 36 +++++++++++++++++++++++++++++++++++-
>  1 file changed, 35 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c
> index 65d58ddf0287..c7652c0dbaeb 100644
> --- a/drivers/media/i2c/tc358743.c
> +++ b/drivers/media/i2c/tc358743.c
> @@ -87,6 +87,10 @@ struct tc358743_state {
>         struct timer_list timer;
>         struct work_struct work_i2c_poll;
>
> +       /* debugfs */
> +       struct dentry *debugfs_dir;
> +       struct v4l2_debugfs_if *infoframes;
> +
>         /* edid  */
>         u8 edid_blocks_written;
>
> @@ -430,12 +434,35 @@ static void tc358743_erase_bksv(struct v4l2_subdev *sd)
>
>  /* --------------- AVI infoframe --------------- */
>
> +static ssize_t
> +tc358743_debugfs_if_read(u32 type, void *priv, struct file *filp,
> +                        char __user *ubuf, size_t count, loff_t *ppos)
> +{
> +       u8 buf[V4L2_DEBUGFS_IF_MAX_LEN] = {};
> +       struct v4l2_subdev *sd = priv;
> +       int len;
> +
> +       if (!is_hdmi(sd))
> +               return 0;
> +
> +       if (type != V4L2_DEBUGFS_IF_AVI)
> +               return 0;
> +
> +       i2c_rd(sd, PK_AVI_0HEAD, buf, PK_AVI_16BYTE - PK_AVI_0HEAD + 1);
> +       len = buf[2] + 3;

tda1997x has len = buffer[2] + 4;
adv7842 and adv7604 have len = buf[2] + 1; and then return len + 3;
adv7511 has len = buffer[2]; and return len + 4;

So I think this should be len = buf[2] + 4;

Doing so makes edid-decode happy.
pi@bookworm64:~/edid-decode $ sudo ./build/edid-decode -I
/sys/kernel/debug/v4l2/tc358743\ 10-000f/infoframes/avi
edid-decode InfoFrame (hex):

82 02 0d 2d 12 28 04 04 00 00 00 00 00 00 00 00
00

----------------

HDMI InfoFrame Checksum: 0x2d

AVI InfoFrame
  Version: 2
  Length: 13
  VIC   4:  1280x720    60.000000 Hz  16:9     45.000 kHz     74.250000 MHz
  Y: Color Component Sample Format: RGB
  A: Active Format Information Present: Yes
  B: Bar Data Present: Bar Data not present
  S: Scan Information: Composed for an underscanned display
  C: Colorimetry: No Data
  M: Picture Aspect Ratio: 16:9
  R: Active Portion Aspect Ratio: 8
  ITC: IT Content: No Data
  EC: Extended Colorimetry: xvYCC601
  Q: RGB Quantization Range: Limited Range
  SC: Non-Uniform Picture Scaling: No Known non-uniform scaling
  YQ: YCC Quantization Range: Limited Range
  CN: IT Content Type: Graphics
  PR: Pixel Data Repetition Count: 0
  Line Number of End of Top Bar: 0
  Line Number of Start of Bottom Bar: 0
  Pixel Number of End of Left Bar: 0
  Pixel Number of Start of Right Bar: 0

I haven't double checked the maths to ensure that we have read that
extra byte via i2c_rd though.

  Dave

> +       if (len > V4L2_DEBUGFS_IF_MAX_LEN)
> +               len = -ENOENT;
> +       if (len > 0)
> +               len = simple_read_from_buffer(ubuf, count, ppos, buf, len);
> +       return len < 0 ? 0 : len;
> +}
> +
>  static void print_avi_infoframe(struct v4l2_subdev *sd)
>  {
>         struct i2c_client *client = v4l2_get_subdevdata(sd);
>         struct device *dev = &client->dev;
>         union hdmi_infoframe frame;
> -       u8 buffer[HDMI_INFOFRAME_SIZE(AVI)];
> +       u8 buffer[HDMI_INFOFRAME_SIZE(AVI)] = {};
>
>         if (!is_hdmi(sd)) {
>                 v4l2_info(sd, "DVI-D signal - AVI infoframe not supported\n");
> @@ -2161,6 +2188,11 @@ static int tc358743_probe(struct i2c_client *client)
>         if (err < 0)
>                 goto err_work_queues;
>
> +       state->debugfs_dir = debugfs_create_dir(sd->name, v4l2_debugfs_root());
> +       state->infoframes = v4l2_debugfs_if_alloc(state->debugfs_dir,
> +                                                 V4L2_DEBUGFS_IF_AVI, sd,
> +                                                 tc358743_debugfs_if_read);
> +
>         v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name,
>                   client->addr << 1, client->adapter->name);
>
> @@ -2188,6 +2220,8 @@ static void tc358743_remove(struct i2c_client *client)
>                 flush_work(&state->work_i2c_poll);
>         }
>         cancel_delayed_work_sync(&state->delayed_work_enable_hotplug);
> +       v4l2_debugfs_if_free(state->infoframes);
> +       debugfs_remove_recursive(state->debugfs_dir);
>         cec_unregister_adapter(state->cec_adap);
>         v4l2_async_unregister_subdev(sd);
>         v4l2_device_unregister_subdev(sd);
> --
> 2.43.0
>
Hans Verkuil Aug. 21, 2024, 6:15 p.m. UTC | #2
On 21/08/2024 18:12, Dave Stevenson wrote:
> Hi Hans
> 
> This is a very useful little series - thanks.
> 
> On Wed, 21 Aug 2024 at 15:16, Hans Verkuil <hverkuil-cisco@xs4all.nl> wrote:
>>
>> Export InfoFrames to debugfs.
> 
> I had a tc358743 to hand, so thought this warranted a quick test.
> I think you have an off-by-one on the length that this exposes.
> 
> log_status is giving me state
>    [  428.600874] tc358743 10-000f: -----HDMI status-----
>    [  428.600881] tc358743 10-000f: HDCP encrypted content: no
>    [  428.600887] tc358743 10-000f: Input color space: RGB limited range
>    [  428.601404] tc358743 10-000f: AV Mute: off
>    [  428.601921] tc358743 10-000f: Deep color mode: 8-bits per channel
>    [  428.604407] tc358743 10-000f: HDMI infoframe: Auxiliary Video
> Information (AVI), version 2, length 13
>    [  428.604425] tc358743 10-000f:     colorspace: RGB
>    [  428.604433] tc358743 10-000f:     scan mode: Underscan
>    [  428.604441] tc358743 10-000f:     colorimetry: No Data
>    [  428.604449] tc358743 10-000f:     picture aspect: 16:9
>    [  428.604456] tc358743 10-000f:     active aspect: Same as Picture
>    [  428.604463] tc358743 10-000f:     itc: No Data
>    [  428.604469] tc358743 10-000f:     extended colorimetry: xvYCC 601
>    [  428.604476] tc358743 10-000f:     quantization range: Limited
>    [  428.604483] tc358743 10-000f:     nups: Unknown Non-uniform Scaling
>    [  428.604490] tc358743 10-000f:     video code: 4
>    [  428.604497] tc358743 10-000f:     ycc quantization range: Limited
>    [  428.604505] tc358743 10-000f:     hdmi content type: Graphics
>    [  428.604511] tc358743 10-000f:     pixel repeat: 0
>    [  428.604519] tc358743 10-000f:     bar top 0, bottom 0, left 0, right 0
> 
> pi@bookworm64:~/edid-decode $ xxd /sys/kernel/debug/v4l2/tc358743\
> 10-000f/infoframes/avi
> 00000000: 8202 0d2d 1228 0404 0000 0000 0000 0000  ...-.(..........
> 
> At the transmitting end I've got
> pi@bookworm64:~/edid-decode $ sudo xxd
> /sys/kernel/debug/dri/1/HDMI-A-1/infoframes/avi
> 00000000: 8202 0d2d 1228 0404 0000 0000 0000 0000  ...-.(..........
> 00000010: 00
> 
> edid-decode -I decodes the latter fine, but aborts on the former.
> Oddly the "fail" message from parse_if_hdr [1] doesn't get printed, it
> just stops with

I fixed this in edid-decode.

> pi@bookworm64:~/edid-decode $ ./build/edid-decode -I
> /sys/kernel/debug/v4l2/tc358743\ 10-000f/infoframes/avi
> edid-decode InfoFrame (hex):
> 
> 82 02 0d 2d 12 28 04 04 00 00 00 00 00 00 00 00
> 
> ----------------
> 
> HDMI InfoFrame Checksum: 0x2d
> 
> AVI InfoFrame
>   Version: 2
>   Length: 13
> 
> 
> [1] https://git.linuxtv.org/edid-decode.git/tree/parse-if.cpp#n21
> 
>> Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
>> ---
>>  drivers/media/i2c/tc358743.c | 36 +++++++++++++++++++++++++++++++++++-
>>  1 file changed, 35 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c
>> index 65d58ddf0287..c7652c0dbaeb 100644
>> --- a/drivers/media/i2c/tc358743.c
>> +++ b/drivers/media/i2c/tc358743.c
>> @@ -87,6 +87,10 @@ struct tc358743_state {
>>         struct timer_list timer;
>>         struct work_struct work_i2c_poll;
>>
>> +       /* debugfs */
>> +       struct dentry *debugfs_dir;
>> +       struct v4l2_debugfs_if *infoframes;
>> +
>>         /* edid  */
>>         u8 edid_blocks_written;
>>
>> @@ -430,12 +434,35 @@ static void tc358743_erase_bksv(struct v4l2_subdev *sd)
>>
>>  /* --------------- AVI infoframe --------------- */
>>
>> +static ssize_t
>> +tc358743_debugfs_if_read(u32 type, void *priv, struct file *filp,
>> +                        char __user *ubuf, size_t count, loff_t *ppos)
>> +{
>> +       u8 buf[V4L2_DEBUGFS_IF_MAX_LEN] = {};
>> +       struct v4l2_subdev *sd = priv;
>> +       int len;
>> +
>> +       if (!is_hdmi(sd))
>> +               return 0;
>> +
>> +       if (type != V4L2_DEBUGFS_IF_AVI)
>> +               return 0;
>> +
>> +       i2c_rd(sd, PK_AVI_0HEAD, buf, PK_AVI_16BYTE - PK_AVI_0HEAD + 1);
>> +       len = buf[2] + 3;
> 
> tda1997x has len = buffer[2] + 4;
> adv7842 and adv7604 have len = buf[2] + 1; and then return len + 3;
> adv7511 has len = buffer[2]; and return len + 4;
> 
> So I think this should be len = buf[2] + 4;

Yes, that's correct. I forgot about the extra checksum byte that HDMI
inserts in InfoFrames.

Thank you, I've updated the patch and added a Tested-by with your email.

Regards,

	Hans

> 
> Doing so makes edid-decode happy.
> pi@bookworm64:~/edid-decode $ sudo ./build/edid-decode -I
> /sys/kernel/debug/v4l2/tc358743\ 10-000f/infoframes/avi
> edid-decode InfoFrame (hex):
> 
> 82 02 0d 2d 12 28 04 04 00 00 00 00 00 00 00 00
> 00
> 
> ----------------
> 
> HDMI InfoFrame Checksum: 0x2d
> 
> AVI InfoFrame
>   Version: 2
>   Length: 13
>   VIC   4:  1280x720    60.000000 Hz  16:9     45.000 kHz     74.250000 MHz
>   Y: Color Component Sample Format: RGB
>   A: Active Format Information Present: Yes
>   B: Bar Data Present: Bar Data not present
>   S: Scan Information: Composed for an underscanned display
>   C: Colorimetry: No Data
>   M: Picture Aspect Ratio: 16:9
>   R: Active Portion Aspect Ratio: 8
>   ITC: IT Content: No Data
>   EC: Extended Colorimetry: xvYCC601
>   Q: RGB Quantization Range: Limited Range
>   SC: Non-Uniform Picture Scaling: No Known non-uniform scaling
>   YQ: YCC Quantization Range: Limited Range
>   CN: IT Content Type: Graphics
>   PR: Pixel Data Repetition Count: 0
>   Line Number of End of Top Bar: 0
>   Line Number of Start of Bottom Bar: 0
>   Pixel Number of End of Left Bar: 0
>   Pixel Number of Start of Right Bar: 0
> 
> I haven't double checked the maths to ensure that we have read that
> extra byte via i2c_rd though.
> 
>   Dave
> 
>> +       if (len > V4L2_DEBUGFS_IF_MAX_LEN)
>> +               len = -ENOENT;
>> +       if (len > 0)
>> +               len = simple_read_from_buffer(ubuf, count, ppos, buf, len);
>> +       return len < 0 ? 0 : len;
>> +}
>> +
>>  static void print_avi_infoframe(struct v4l2_subdev *sd)
>>  {
>>         struct i2c_client *client = v4l2_get_subdevdata(sd);
>>         struct device *dev = &client->dev;
>>         union hdmi_infoframe frame;
>> -       u8 buffer[HDMI_INFOFRAME_SIZE(AVI)];
>> +       u8 buffer[HDMI_INFOFRAME_SIZE(AVI)] = {};
>>
>>         if (!is_hdmi(sd)) {
>>                 v4l2_info(sd, "DVI-D signal - AVI infoframe not supported\n");
>> @@ -2161,6 +2188,11 @@ static int tc358743_probe(struct i2c_client *client)
>>         if (err < 0)
>>                 goto err_work_queues;
>>
>> +       state->debugfs_dir = debugfs_create_dir(sd->name, v4l2_debugfs_root());
>> +       state->infoframes = v4l2_debugfs_if_alloc(state->debugfs_dir,
>> +                                                 V4L2_DEBUGFS_IF_AVI, sd,
>> +                                                 tc358743_debugfs_if_read);
>> +
>>         v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name,
>>                   client->addr << 1, client->adapter->name);
>>
>> @@ -2188,6 +2220,8 @@ static void tc358743_remove(struct i2c_client *client)
>>                 flush_work(&state->work_i2c_poll);
>>         }
>>         cancel_delayed_work_sync(&state->delayed_work_enable_hotplug);
>> +       v4l2_debugfs_if_free(state->infoframes);
>> +       debugfs_remove_recursive(state->debugfs_dir);
>>         cec_unregister_adapter(state->cec_adap);
>>         v4l2_async_unregister_subdev(sd);
>>         v4l2_device_unregister_subdev(sd);
>> --
>> 2.43.0
>>
>
diff mbox series

Patch

diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c
index 65d58ddf0287..c7652c0dbaeb 100644
--- a/drivers/media/i2c/tc358743.c
+++ b/drivers/media/i2c/tc358743.c
@@ -87,6 +87,10 @@  struct tc358743_state {
 	struct timer_list timer;
 	struct work_struct work_i2c_poll;
 
+	/* debugfs */
+	struct dentry *debugfs_dir;
+	struct v4l2_debugfs_if *infoframes;
+
 	/* edid  */
 	u8 edid_blocks_written;
 
@@ -430,12 +434,35 @@  static void tc358743_erase_bksv(struct v4l2_subdev *sd)
 
 /* --------------- AVI infoframe --------------- */
 
+static ssize_t
+tc358743_debugfs_if_read(u32 type, void *priv, struct file *filp,
+			 char __user *ubuf, size_t count, loff_t *ppos)
+{
+	u8 buf[V4L2_DEBUGFS_IF_MAX_LEN] = {};
+	struct v4l2_subdev *sd = priv;
+	int len;
+
+	if (!is_hdmi(sd))
+		return 0;
+
+	if (type != V4L2_DEBUGFS_IF_AVI)
+		return 0;
+
+	i2c_rd(sd, PK_AVI_0HEAD, buf, PK_AVI_16BYTE - PK_AVI_0HEAD + 1);
+	len = buf[2] + 3;
+	if (len > V4L2_DEBUGFS_IF_MAX_LEN)
+		len = -ENOENT;
+	if (len > 0)
+		len = simple_read_from_buffer(ubuf, count, ppos, buf, len);
+	return len < 0 ? 0 : len;
+}
+
 static void print_avi_infoframe(struct v4l2_subdev *sd)
 {
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
 	struct device *dev = &client->dev;
 	union hdmi_infoframe frame;
-	u8 buffer[HDMI_INFOFRAME_SIZE(AVI)];
+	u8 buffer[HDMI_INFOFRAME_SIZE(AVI)] = {};
 
 	if (!is_hdmi(sd)) {
 		v4l2_info(sd, "DVI-D signal - AVI infoframe not supported\n");
@@ -2161,6 +2188,11 @@  static int tc358743_probe(struct i2c_client *client)
 	if (err < 0)
 		goto err_work_queues;
 
+	state->debugfs_dir = debugfs_create_dir(sd->name, v4l2_debugfs_root());
+	state->infoframes = v4l2_debugfs_if_alloc(state->debugfs_dir,
+						  V4L2_DEBUGFS_IF_AVI, sd,
+						  tc358743_debugfs_if_read);
+
 	v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name,
 		  client->addr << 1, client->adapter->name);
 
@@ -2188,6 +2220,8 @@  static void tc358743_remove(struct i2c_client *client)
 		flush_work(&state->work_i2c_poll);
 	}
 	cancel_delayed_work_sync(&state->delayed_work_enable_hotplug);
+	v4l2_debugfs_if_free(state->infoframes);
+	debugfs_remove_recursive(state->debugfs_dir);
 	cec_unregister_adapter(state->cec_adap);
 	v4l2_async_unregister_subdev(sd);
 	v4l2_device_unregister_subdev(sd);