Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

media: i2c: tc358743: add support for more infoframe types

Add support for SPD, AUDIO, DRM and HDMI InfoFrames.

Also add support for ISRC1 and ISRC2 Packet Types and a programmable
type for both Packet and InfoFrames.

The tc358743 HDMI-to-CSI2 bridge is widely available, and it has quite
flexible InfoFrame/Packet Type support, so this makes it a very nice
device to capture such data.

The ACP (Audio Content Protection) Packet capture data is chosen as the
programmable type. ACP is typically only used for protected audio, which
is quite rare, so instead it is reprogrammed to capture DRM InfoFrames
by default. This can be changed by using the packet_type module option to
anything you want, and you can change it on the fly as well. It will be
updated whenever VIDIOC_LOG_STATUS is called (it's really a debug feature).

Tested on my Raspberry Pi 5.

Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>

authored by

Hans Verkuil and committed by
Mauro Carvalho Chehab
04f08db5 0b6cb344

+135 -31
+95 -14
drivers/media/i2c/tc358743.c
··· 38 38 39 39 static int debug; 40 40 module_param(debug, int, 0644); 41 - MODULE_PARM_DESC(debug, "debug level (0-3)"); 41 + MODULE_PARM_DESC(debug, " debug level (0-3)"); 42 + 43 + static int packet_type = 0x87; 44 + module_param(packet_type, int, 0644); 45 + MODULE_PARM_DESC(packet_type, 46 + " Programmable Packet Type. Possible values:\n" 47 + "\t\t 0x87: DRM InfoFrame (Default).\n" 48 + "\t\t 0x01: Audio Clock Regeneration Packet\n" 49 + "\t\t 0x02: Audio Sample Packet\n" 50 + "\t\t 0x03: General Control Packet\n" 51 + "\t\t 0x04: ACP Packet\n" 52 + "\t\t 0x07: One Bit Audio Sample Packet\n" 53 + "\t\t 0x08: DST Audio Packet\n" 54 + "\t\t 0x09: High Bitrate Audio Stream Packet\n" 55 + "\t\t 0x0a: Gamut Metadata Packet\n"); 42 56 43 57 MODULE_DESCRIPTION("Toshiba TC358743 HDMI to CSI-2 bridge driver"); 44 58 MODULE_AUTHOR("Ramakrishnan Muthukrishnan <ram@rkrishnan.org>"); ··· 480 466 if (!is_hdmi(sd)) 481 467 return 0; 482 468 483 - if (type != V4L2_DEBUGFS_IF_AVI) 469 + switch (type) { 470 + case V4L2_DEBUGFS_IF_AVI: 471 + i2c_rd(sd, PK_AVI_0HEAD, buf, PK_AVI_LEN); 472 + break; 473 + case V4L2_DEBUGFS_IF_AUDIO: 474 + i2c_rd(sd, PK_AUD_0HEAD, buf, PK_AUD_LEN); 475 + break; 476 + case V4L2_DEBUGFS_IF_SPD: 477 + i2c_rd(sd, PK_SPD_0HEAD, buf, PK_SPD_LEN); 478 + break; 479 + case V4L2_DEBUGFS_IF_HDMI: 480 + i2c_rd(sd, PK_VS_0HEAD, buf, PK_VS_LEN); 481 + break; 482 + case V4L2_DEBUGFS_IF_DRM: 483 + i2c_rd(sd, PK_ACP_0HEAD, buf, PK_ACP_LEN); 484 + break; 485 + default: 484 486 return 0; 487 + } 485 488 486 - i2c_rd(sd, PK_AVI_0HEAD, buf, PK_AVI_16BYTE - PK_AVI_0HEAD + 1); 489 + if (!buf[2]) 490 + return -ENOENT; 491 + 487 492 len = buf[2] + 4; 488 493 if (len > V4L2_DEBUGFS_IF_MAX_LEN) 489 494 len = -ENOENT; ··· 511 478 return len < 0 ? 0 : len; 512 479 } 513 480 514 - static void print_avi_infoframe(struct v4l2_subdev *sd) 481 + static void print_infoframes(struct v4l2_subdev *sd) 515 482 { 516 483 struct i2c_client *client = v4l2_get_subdevdata(sd); 517 484 struct device *dev = &client->dev; 518 485 union hdmi_infoframe frame; 519 - u8 buffer[HDMI_INFOFRAME_SIZE(AVI)] = {}; 486 + u8 buffer[V4L2_DEBUGFS_IF_MAX_LEN] = {}; 487 + 488 + /* 489 + * Updating the ACP TYPE here allows for dynamically 490 + * changing the type you want to monitor, without having 491 + * to reload the driver with a new packet_type module option value. 492 + * 493 + * Instead you can set it with the new value, then call 494 + * VIDIOC_LOG_STATUS. 495 + */ 496 + i2c_wr8(sd, TYP_ACP_SET, packet_type); 520 497 521 498 if (!is_hdmi(sd)) { 522 - v4l2_info(sd, "DVI-D signal - AVI infoframe not supported\n"); 499 + v4l2_info(sd, "DVI-D signal - InfoFrames not supported\n"); 523 500 return; 524 501 } 525 502 526 - i2c_rd(sd, PK_AVI_0HEAD, buffer, HDMI_INFOFRAME_SIZE(AVI)); 503 + i2c_rd(sd, PK_AVI_0HEAD, buffer, PK_AVI_LEN); 504 + if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) >= 0) 505 + hdmi_infoframe_log(KERN_INFO, dev, &frame); 527 506 528 - if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) < 0) { 529 - v4l2_err(sd, "%s: unpack of AVI infoframe failed\n", __func__); 530 - return; 507 + i2c_rd(sd, PK_VS_0HEAD, buffer, PK_VS_LEN); 508 + if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) >= 0) 509 + hdmi_infoframe_log(KERN_INFO, dev, &frame); 510 + 511 + i2c_rd(sd, PK_AUD_0HEAD, buffer, PK_AUD_LEN); 512 + if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) >= 0) 513 + hdmi_infoframe_log(KERN_INFO, dev, &frame); 514 + 515 + i2c_rd(sd, PK_SPD_0HEAD, buffer, PK_SPD_LEN); 516 + if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) >= 0) 517 + hdmi_infoframe_log(KERN_INFO, dev, &frame); 518 + 519 + i2c_rd(sd, PK_ACP_0HEAD, buffer, PK_ACP_LEN); 520 + if (buffer[0] == packet_type) { 521 + if (packet_type < 0x80) 522 + v4l2_info(sd, "Packet: %*ph\n", PK_ACP_LEN, buffer); 523 + else if (packet_type != 0x87) 524 + v4l2_info(sd, "InfoFrame: %*ph\n", PK_ACP_LEN, buffer); 525 + else if (hdmi_infoframe_unpack(&frame, buffer, 526 + sizeof(buffer)) >= 0) 527 + hdmi_infoframe_log(KERN_INFO, dev, &frame); 531 528 } 532 529 533 - hdmi_infoframe_log(KERN_INFO, dev, &frame); 530 + i2c_rd(sd, PK_MS_0HEAD, buffer, PK_MS_LEN); 531 + if (buffer[2] && buffer[2] + 3 <= PK_MS_LEN) 532 + v4l2_info(sd, "MPEG Source InfoFrame: %*ph\n", 533 + buffer[2] + 3, buffer); 534 + 535 + i2c_rd(sd, PK_ISRC1_0HEAD, buffer, PK_ISRC1_LEN); 536 + if (buffer[0] == 0x05) 537 + v4l2_info(sd, "ISRC1 Packet: %*ph\n", 538 + PK_ISRC1_LEN, buffer); 539 + 540 + i2c_rd(sd, PK_ISRC2_0HEAD, buffer, PK_ISRC2_LEN); 541 + if (buffer[0] == 0x06) 542 + v4l2_info(sd, "ISRC2 Packet: %*ph\n", 543 + PK_ISRC2_LEN, buffer); 534 544 } 535 545 536 546 /* --------------- CTRLS --------------- */ ··· 1451 1375 v4l2_info(sd, "Deep color mode: %d-bits per channel\n", 1452 1376 deep_color_mode[(i2c_rd8(sd, VI_STATUS1) & 1453 1377 MASK_S_DEEPCOLOR) >> 2]); 1454 - print_avi_infoframe(sd); 1378 + print_infoframes(sd); 1455 1379 1456 1380 return 0; 1457 1381 } ··· 2308 2232 if (err < 0) 2309 2233 goto err_work_queues; 2310 2234 2235 + i2c_wr8(sd, TYP_ACP_SET, packet_type); 2236 + i2c_wr8(sd, PK_AUTO_CLR, 0xff); 2237 + i2c_wr8(sd, NO_PKT_CLR, MASK_NO_ACP_CLR); 2238 + 2311 2239 state->debugfs_dir = debugfs_create_dir(sd->name, v4l2_debugfs_root()); 2312 2240 state->infoframes = v4l2_debugfs_if_alloc(state->debugfs_dir, 2313 - V4L2_DEBUGFS_IF_AVI, sd, 2314 - tc358743_debugfs_if_read); 2241 + V4L2_DEBUGFS_IF_AVI | V4L2_DEBUGFS_IF_AUDIO | 2242 + V4L2_DEBUGFS_IF_SPD | V4L2_DEBUGFS_IF_HDMI | 2243 + V4L2_DEBUGFS_IF_DRM, sd, tc358743_debugfs_if_read); 2315 2244 2316 2245 v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name, 2317 2246 client->addr << 1, client->adapter->name);
+40 -17
drivers/media/i2c/tc358743_regs.h
··· 692 692 #define MASK_NCO_F0_MOD_42MHZ 0x00 693 693 #define MASK_NCO_F0_MOD_27MHZ 0x01 694 694 695 + #define TYP_ACP_SET 0x8706 696 + 695 697 #define PK_INT_MODE 0x8709 696 698 #define MASK_ISRC2_INT_MODE 0x80 697 699 #define MASK_ISRC_INT_MODE 0x40 ··· 703 701 #define MASK_MS_INT_MODE 0x04 704 702 #define MASK_AUD_INT_MODE 0x02 705 703 #define MASK_AVI_INT_MODE 0x01 704 + 705 + #define PK_AUTO_CLR 0x870a 706 706 707 707 #define NO_PKT_LIMIT 0x870B 708 708 #define MASK_NO_ACP_LIMIT 0xf0 ··· 724 720 #define ERR_PK_LIMIT 0x870D 725 721 #define NO_PKT_LIMIT2 0x870E 726 722 #define PK_AVI_0HEAD 0x8710 727 - #define PK_AVI_1HEAD 0x8711 728 - #define PK_AVI_2HEAD 0x8712 729 723 #define PK_AVI_0BYTE 0x8713 730 - #define PK_AVI_1BYTE 0x8714 731 - #define PK_AVI_2BYTE 0x8715 732 - #define PK_AVI_3BYTE 0x8716 733 - #define PK_AVI_4BYTE 0x8717 734 - #define PK_AVI_5BYTE 0x8718 735 - #define PK_AVI_6BYTE 0x8719 736 - #define PK_AVI_7BYTE 0x871A 737 - #define PK_AVI_8BYTE 0x871B 738 - #define PK_AVI_9BYTE 0x871C 739 - #define PK_AVI_10BYTE 0x871D 740 - #define PK_AVI_11BYTE 0x871E 741 - #define PK_AVI_12BYTE 0x871F 742 - #define PK_AVI_13BYTE 0x8720 743 - #define PK_AVI_14BYTE 0x8721 744 - #define PK_AVI_15BYTE 0x8722 745 724 #define PK_AVI_16BYTE 0x8723 725 + #define PK_AVI_LEN (PK_AVI_16BYTE - PK_AVI_0HEAD + 1) 726 + 727 + #define PK_AUD_0HEAD 0x8730 728 + #define PK_AUD_0BYTE 0x8733 729 + #define PK_AUD_10BYTE 0x873d 730 + #define PK_AUD_LEN (PK_AUD_10BYTE - PK_AUD_0HEAD + 1) 731 + 732 + #define PK_MS_0HEAD 0x8740 733 + #define PK_MS_0BYTE 0x8743 734 + #define PK_MS_10BYTE 0x874d 735 + #define PK_MS_LEN (PK_MS_10BYTE - PK_MS_0HEAD + 1) 736 + 737 + #define PK_SPD_0HEAD 0x8750 738 + #define PK_SPD_0BYTE 0x8753 739 + #define PK_SPD_27BYTE 0x876e 740 + #define PK_SPD_LEN (PK_SPD_27BYTE - PK_SPD_0HEAD + 1) 741 + 742 + #define PK_VS_0HEAD 0x8770 743 + #define PK_VS_0BYTE 0x8773 744 + #define PK_VS_27BYTE 0x878e 745 + #define PK_VS_LEN (PK_VS_27BYTE - PK_VS_0HEAD + 1) 746 + 747 + #define PK_ACP_0HEAD 0x8790 748 + #define PK_ACP_0BYTE 0x8793 749 + #define PK_ACP_27BYTE 0x87ae 750 + #define PK_ACP_LEN (PK_ACP_27BYTE - PK_ACP_0HEAD + 1) 751 + 752 + #define PK_ISRC1_0HEAD 0x87b0 753 + #define PK_ISRC1_0BYTE 0x87b3 754 + #define PK_ISRC1_27BYTE 0x87c2 755 + #define PK_ISRC1_LEN (PK_ISRC1_27BYTE - PK_ISRC1_0HEAD + 1) 756 + 757 + #define PK_ISRC2_0HEAD 0x87d0 758 + #define PK_ISRC2_0BYTE 0x87d3 759 + #define PK_ISRC2_27BYTE 0x87ee 760 + #define PK_ISRC2_LEN (PK_ISRC2_27BYTE - PK_ISRC2_0HEAD + 1) 746 761 747 762 #define BKSV 0x8800 748 763