summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUma Shankar <uma.shankar@intel.com>2019-05-16 10:10:09 -0400
committerVille Syrjälä <ville.syrjala@linux.intel.com>2019-05-22 15:46:35 -0400
commit2cdbfd66a82969770ce1a7032fb1e2155a08cee8 (patch)
treeaaa856471b49a8c9f3c5fd9565c17d58d4ea7f3b
parente85959d6cbe08521942a6118568a38ac671e8d7f (diff)
drm: Enable HDR infoframe support
Enable Dynamic Range and Mastering Infoframe for HDR content, which is defined in CEA 861.3 spec. The metadata will be computed based on blending policy in userspace compositors and passed as a connector property blob to driver. The same will be sent as infoframe to panel which support HDR. Added the const version of infoframe for DRM metadata for HDR. v2: Rebase and added Ville's POC changes. v3: No Change v4: Addressed Shashank's review comments and merged the patch making drm infoframe function arguments as constant. v5: Rebase v6: Fixed checkpatch warnings with --strict option. Addressed Shashank's review comments and added his RB. v7: Addressed Brian Starkey's review comments. Merged 2 patches into one. v8: Addressed Jonas Karlman review comments. v9: Addressed Jonas Karlman review comments. v10: Addressed Ville's review comments. v11: Added BUILD_BUG_ON and sizeof instead of magic numbers as per Ville's comments. Signed-off-by: Uma Shankar <uma.shankar@intel.com> Reviewed-by: Shashank Sharma <shashank.sharma@intel.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/1558015817-12025-5-git-send-email-uma.shankar@intel.com
-rw-r--r--drivers/gpu/drm/drm_edid.c72
-rw-r--r--drivers/video/hdmi.c190
-rw-r--r--include/drm/drm_edid.h5
-rw-r--r--include/linux/hdmi.h28
4 files changed, 295 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index a5ef9f45fee0..73560c9437cd 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -4904,6 +4904,78 @@ static bool is_hdmi2_sink(struct drm_connector *connector)
4904 connector->display_info.color_formats & DRM_COLOR_FORMAT_YCRCB420; 4904 connector->display_info.color_formats & DRM_COLOR_FORMAT_YCRCB420;
4905} 4905}
4906 4906
4907static inline bool is_eotf_supported(u8 output_eotf, u8 sink_eotf)
4908{
4909 return sink_eotf & BIT(output_eotf);
4910}
4911
4912/**
4913 * drm_hdmi_infoframe_set_hdr_metadata() - fill an HDMI DRM infoframe with
4914 * HDR metadata from userspace
4915 * @frame: HDMI DRM infoframe
4916 * @hdr_metadata: hdr_source_metadata info from userspace
4917 *
4918 * Return: 0 on success or a negative error code on failure.
4919 */
4920int
4921drm_hdmi_infoframe_set_hdr_metadata(struct hdmi_drm_infoframe *frame,
4922 const struct drm_connector_state *conn_state)
4923{
4924 struct drm_connector *connector;
4925 struct hdr_output_metadata *hdr_metadata;
4926 int err;
4927
4928 if (!frame || !conn_state)
4929 return -EINVAL;
4930
4931 connector = conn_state->connector;
4932
4933 if (!conn_state->hdr_output_metadata)
4934 return -EINVAL;
4935
4936 hdr_metadata = conn_state->hdr_output_metadata->data;
4937
4938 if (!hdr_metadata || !connector)
4939 return -EINVAL;
4940
4941 /* Sink EOTF is Bit map while infoframe is absolute values */
4942 if (!is_eotf_supported(hdr_metadata->hdmi_metadata_type1.eotf,
4943 connector->hdr_sink_metadata.hdmi_type1.eotf)) {
4944 DRM_DEBUG_KMS("EOTF Not Supported\n");
4945 return -EINVAL;
4946 }
4947
4948 err = hdmi_drm_infoframe_init(frame);
4949 if (err < 0)
4950 return err;
4951
4952 frame->eotf = hdr_metadata->hdmi_metadata_type1.eotf;
4953 frame->metadata_type = hdr_metadata->hdmi_metadata_type1.metadata_type;
4954
4955 BUILD_BUG_ON(sizeof(frame->display_primaries) !=
4956 sizeof(hdr_metadata->hdmi_metadata_type1.display_primaries));
4957 BUILD_BUG_ON(sizeof(frame->white_point) !=
4958 sizeof(hdr_metadata->hdmi_metadata_type1.white_point));
4959
4960 memcpy(&frame->display_primaries,
4961 &hdr_metadata->hdmi_metadata_type1.display_primaries,
4962 sizeof(frame->display_primaries));
4963
4964 memcpy(&frame->white_point,
4965 &hdr_metadata->hdmi_metadata_type1.white_point,
4966 sizeof(frame->white_point));
4967
4968 frame->max_display_mastering_luminance =
4969 hdr_metadata->hdmi_metadata_type1.max_display_mastering_luminance;
4970 frame->min_display_mastering_luminance =
4971 hdr_metadata->hdmi_metadata_type1.min_display_mastering_luminance;
4972 frame->max_fall = hdr_metadata->hdmi_metadata_type1.max_fall;
4973 frame->max_cll = hdr_metadata->hdmi_metadata_type1.max_cll;
4974
4975 return 0;
4976}
4977EXPORT_SYMBOL(drm_hdmi_infoframe_set_hdr_metadata);
4978
4907/** 4979/**
4908 * drm_hdmi_avi_infoframe_from_display_mode() - fill an HDMI AVI infoframe with 4980 * drm_hdmi_avi_infoframe_from_display_mode() - fill an HDMI AVI infoframe with
4909 * data from a DRM display mode 4981 * data from a DRM display mode
diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index 799ae49774f5..481f0367dfd3 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -650,6 +650,150 @@ hdmi_vendor_any_infoframe_check_only(const union hdmi_vendor_any_infoframe *fram
650 return 0; 650 return 0;
651} 651}
652 652
653/**
654 * hdmi_drm_infoframe_init() - initialize an HDMI Dynaminc Range and
655 * mastering infoframe
656 * @frame: HDMI DRM infoframe
657 *
658 * Returns 0 on success or a negative error code on failure.
659 */
660int hdmi_drm_infoframe_init(struct hdmi_drm_infoframe *frame)
661{
662 memset(frame, 0, sizeof(*frame));
663
664 frame->type = HDMI_INFOFRAME_TYPE_DRM;
665 frame->version = 1;
666 frame->length = HDMI_DRM_INFOFRAME_SIZE;
667
668 return 0;
669}
670EXPORT_SYMBOL(hdmi_drm_infoframe_init);
671
672static int hdmi_drm_infoframe_check_only(const struct hdmi_drm_infoframe *frame)
673{
674 if (frame->type != HDMI_INFOFRAME_TYPE_DRM ||
675 frame->version != 1)
676 return -EINVAL;
677
678 if (frame->length != HDMI_DRM_INFOFRAME_SIZE)
679 return -EINVAL;
680
681 return 0;
682}
683
684/**
685 * hdmi_drm_infoframe_check() - check a HDMI DRM infoframe
686 * @frame: HDMI DRM infoframe
687 *
688 * Validates that the infoframe is consistent.
689 * Returns 0 on success or a negative error code on failure.
690 */
691int hdmi_drm_infoframe_check(struct hdmi_drm_infoframe *frame)
692{
693 return hdmi_drm_infoframe_check_only(frame);
694}
695EXPORT_SYMBOL(hdmi_drm_infoframe_check);
696
697/**
698 * hdmi_drm_infoframe_pack_only() - write HDMI DRM infoframe to binary buffer
699 * @frame: HDMI DRM infoframe
700 * @buffer: destination buffer
701 * @size: size of buffer
702 *
703 * Packs the information contained in the @frame structure into a binary
704 * representation that can be written into the corresponding controller
705 * registers. Also computes the checksum as required by section 5.3.5 of
706 * the HDMI 1.4 specification.
707 *
708 * Returns the number of bytes packed into the binary buffer or a negative
709 * error code on failure.
710 */
711ssize_t hdmi_drm_infoframe_pack_only(const struct hdmi_drm_infoframe *frame,
712 void *buffer, size_t size)
713{
714 u8 *ptr = buffer;
715 size_t length;
716 int i;
717
718 length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
719
720 if (size < length)
721 return -ENOSPC;
722
723 memset(buffer, 0, size);
724
725 ptr[0] = frame->type;
726 ptr[1] = frame->version;
727 ptr[2] = frame->length;
728 ptr[3] = 0; /* checksum */
729
730 /* start infoframe payload */
731 ptr += HDMI_INFOFRAME_HEADER_SIZE;
732
733 *ptr++ = frame->eotf;
734 *ptr++ = frame->metadata_type;
735
736 for (i = 0; i < 3; i++) {
737 *ptr++ = frame->display_primaries[i].x;
738 *ptr++ = frame->display_primaries[i].x >> 8;
739 *ptr++ = frame->display_primaries[i].y;
740 *ptr++ = frame->display_primaries[i].y >> 8;
741 }
742
743 *ptr++ = frame->white_point.x;
744 *ptr++ = frame->white_point.x >> 8;
745
746 *ptr++ = frame->white_point.y;
747 *ptr++ = frame->white_point.y >> 8;
748
749 *ptr++ = frame->max_display_mastering_luminance;
750 *ptr++ = frame->max_display_mastering_luminance >> 8;
751
752 *ptr++ = frame->min_display_mastering_luminance;
753 *ptr++ = frame->min_display_mastering_luminance >> 8;
754
755 *ptr++ = frame->max_cll;
756 *ptr++ = frame->max_cll >> 8;
757
758 *ptr++ = frame->max_fall;
759 *ptr++ = frame->max_fall >> 8;
760
761 hdmi_infoframe_set_checksum(buffer, length);
762
763 return length;
764}
765EXPORT_SYMBOL(hdmi_drm_infoframe_pack_only);
766
767/**
768 * hdmi_drm_infoframe_pack() - check a HDMI DRM infoframe,
769 * and write it to binary buffer
770 * @frame: HDMI DRM infoframe
771 * @buffer: destination buffer
772 * @size: size of buffer
773 *
774 * Validates that the infoframe is consistent and updates derived fields
775 * (eg. length) based on other fields, after which it packs the information
776 * contained in the @frame structure into a binary representation that
777 * can be written into the corresponding controller registers. This function
778 * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
779 * specification.
780 *
781 * Returns the number of bytes packed into the binary buffer or a negative
782 * error code on failure.
783 */
784ssize_t hdmi_drm_infoframe_pack(struct hdmi_drm_infoframe *frame,
785 void *buffer, size_t size)
786{
787 int ret;
788
789 ret = hdmi_drm_infoframe_check(frame);
790 if (ret)
791 return ret;
792
793 return hdmi_drm_infoframe_pack_only(frame, buffer, size);
794}
795EXPORT_SYMBOL(hdmi_drm_infoframe_pack);
796
653/* 797/*
654 * hdmi_vendor_any_infoframe_check() - check a vendor infoframe 798 * hdmi_vendor_any_infoframe_check() - check a vendor infoframe
655 */ 799 */
@@ -758,6 +902,10 @@ hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t
758 length = hdmi_avi_infoframe_pack_only(&frame->avi, 902 length = hdmi_avi_infoframe_pack_only(&frame->avi,
759 buffer, size); 903 buffer, size);
760 break; 904 break;
905 case HDMI_INFOFRAME_TYPE_DRM:
906 length = hdmi_drm_infoframe_pack_only(&frame->drm,
907 buffer, size);
908 break;
761 case HDMI_INFOFRAME_TYPE_SPD: 909 case HDMI_INFOFRAME_TYPE_SPD:
762 length = hdmi_spd_infoframe_pack_only(&frame->spd, 910 length = hdmi_spd_infoframe_pack_only(&frame->spd,
763 buffer, size); 911 buffer, size);
@@ -806,6 +954,9 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame,
806 case HDMI_INFOFRAME_TYPE_AVI: 954 case HDMI_INFOFRAME_TYPE_AVI:
807 length = hdmi_avi_infoframe_pack(&frame->avi, buffer, size); 955 length = hdmi_avi_infoframe_pack(&frame->avi, buffer, size);
808 break; 956 break;
957 case HDMI_INFOFRAME_TYPE_DRM:
958 length = hdmi_drm_infoframe_pack(&frame->drm, buffer, size);
959 break;
809 case HDMI_INFOFRAME_TYPE_SPD: 960 case HDMI_INFOFRAME_TYPE_SPD:
810 length = hdmi_spd_infoframe_pack(&frame->spd, buffer, size); 961 length = hdmi_spd_infoframe_pack(&frame->spd, buffer, size);
811 break; 962 break;
@@ -838,6 +989,8 @@ static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)
838 return "Source Product Description (SPD)"; 989 return "Source Product Description (SPD)";
839 case HDMI_INFOFRAME_TYPE_AUDIO: 990 case HDMI_INFOFRAME_TYPE_AUDIO:
840 return "Audio"; 991 return "Audio";
992 case HDMI_INFOFRAME_TYPE_DRM:
993 return "Dynamic Range and Mastering";
841 } 994 }
842 return "Reserved"; 995 return "Reserved";
843} 996}
@@ -1284,6 +1437,40 @@ static void hdmi_audio_infoframe_log(const char *level,
1284 frame->downmix_inhibit ? "Yes" : "No"); 1437 frame->downmix_inhibit ? "Yes" : "No");
1285} 1438}
1286 1439
1440/**
1441 * hdmi_drm_infoframe_log() - log info of HDMI DRM infoframe
1442 * @level: logging level
1443 * @dev: device
1444 * @frame: HDMI DRM infoframe
1445 */
1446static void hdmi_drm_infoframe_log(const char *level,
1447 struct device *dev,
1448 const struct hdmi_drm_infoframe *frame)
1449{
1450 int i;
1451
1452 hdmi_infoframe_log_header(level, dev,
1453 (struct hdmi_any_infoframe *)frame);
1454 hdmi_log("length: %d\n", frame->length);
1455 hdmi_log("metadata type: %d\n", frame->metadata_type);
1456 hdmi_log("eotf: %d\n", frame->eotf);
1457 for (i = 0; i < 3; i++) {
1458 hdmi_log("x[%d]: %d\n", i, frame->display_primaries[i].x);
1459 hdmi_log("y[%d]: %d\n", i, frame->display_primaries[i].y);
1460 }
1461
1462 hdmi_log("white point x: %d\n", frame->white_point.x);
1463 hdmi_log("white point y: %d\n", frame->white_point.y);
1464
1465 hdmi_log("max_display_mastering_luminance: %d\n",
1466 frame->max_display_mastering_luminance);
1467 hdmi_log("min_display_mastering_luminance: %d\n",
1468 frame->min_display_mastering_luminance);
1469
1470 hdmi_log("max_cll: %d\n", frame->max_cll);
1471 hdmi_log("max_fall: %d\n", frame->max_fall);
1472}
1473
1287static const char * 1474static const char *
1288hdmi_3d_structure_get_name(enum hdmi_3d_structure s3d_struct) 1475hdmi_3d_structure_get_name(enum hdmi_3d_structure s3d_struct)
1289{ 1476{
@@ -1372,6 +1559,9 @@ void hdmi_infoframe_log(const char *level,
1372 case HDMI_INFOFRAME_TYPE_VENDOR: 1559 case HDMI_INFOFRAME_TYPE_VENDOR:
1373 hdmi_vendor_any_infoframe_log(level, dev, &frame->vendor); 1560 hdmi_vendor_any_infoframe_log(level, dev, &frame->vendor);
1374 break; 1561 break;
1562 case HDMI_INFOFRAME_TYPE_DRM:
1563 hdmi_drm_infoframe_log(level, dev, &frame->drm);
1564 break;
1375 } 1565 }
1376} 1566}
1377EXPORT_SYMBOL(hdmi_infoframe_log); 1567EXPORT_SYMBOL(hdmi_infoframe_log);
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
index 9d3b5b93102c..0e21e91c4314 100644
--- a/include/drm/drm_edid.h
+++ b/include/drm/drm_edid.h
@@ -25,6 +25,7 @@
25 25
26#include <linux/types.h> 26#include <linux/types.h>
27#include <linux/hdmi.h> 27#include <linux/hdmi.h>
28#include <drm/drm_mode.h>
28 29
29struct drm_device; 30struct drm_device;
30struct i2c_adapter; 31struct i2c_adapter;
@@ -370,6 +371,10 @@ drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame,
370 const struct drm_display_mode *mode, 371 const struct drm_display_mode *mode,
371 enum hdmi_quantization_range rgb_quant_range); 372 enum hdmi_quantization_range rgb_quant_range);
372 373
374int
375drm_hdmi_infoframe_set_hdr_metadata(struct hdmi_drm_infoframe *frame,
376 const struct drm_connector_state *conn_state);
377
373/** 378/**
374 * drm_eld_mnl - Get ELD monitor name length in bytes. 379 * drm_eld_mnl - Get ELD monitor name length in bytes.
375 * @eld: pointer to an eld memory structure with mnl set 380 * @eld: pointer to an eld memory structure with mnl set
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index 6780476dcbff..bcf3c6c3499e 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -47,6 +47,7 @@ enum hdmi_infoframe_type {
47 HDMI_INFOFRAME_TYPE_AVI = 0x82, 47 HDMI_INFOFRAME_TYPE_AVI = 0x82,
48 HDMI_INFOFRAME_TYPE_SPD = 0x83, 48 HDMI_INFOFRAME_TYPE_SPD = 0x83,
49 HDMI_INFOFRAME_TYPE_AUDIO = 0x84, 49 HDMI_INFOFRAME_TYPE_AUDIO = 0x84,
50 HDMI_INFOFRAME_TYPE_DRM = 0x87,
50}; 51};
51 52
52#define HDMI_IEEE_OUI 0x000c03 53#define HDMI_IEEE_OUI 0x000c03
@@ -55,6 +56,7 @@ enum hdmi_infoframe_type {
55#define HDMI_AVI_INFOFRAME_SIZE 13 56#define HDMI_AVI_INFOFRAME_SIZE 13
56#define HDMI_SPD_INFOFRAME_SIZE 25 57#define HDMI_SPD_INFOFRAME_SIZE 25
57#define HDMI_AUDIO_INFOFRAME_SIZE 10 58#define HDMI_AUDIO_INFOFRAME_SIZE 10
59#define HDMI_DRM_INFOFRAME_SIZE 26
58 60
59#define HDMI_INFOFRAME_SIZE(type) \ 61#define HDMI_INFOFRAME_SIZE(type) \
60 (HDMI_INFOFRAME_HEADER_SIZE + HDMI_ ## type ## _INFOFRAME_SIZE) 62 (HDMI_INFOFRAME_HEADER_SIZE + HDMI_ ## type ## _INFOFRAME_SIZE)
@@ -185,12 +187,37 @@ struct hdmi_avi_infoframe {
185 unsigned short right_bar; 187 unsigned short right_bar;
186}; 188};
187 189
190/* DRM Infoframe as per CTA 861.G spec */
191struct hdmi_drm_infoframe {
192 enum hdmi_infoframe_type type;
193 unsigned char version;
194 unsigned char length;
195 enum hdmi_eotf eotf;
196 enum hdmi_metadata_type metadata_type;
197 struct {
198 u16 x, y;
199 } display_primaries[3];
200 struct {
201 u16 x, y;
202 } white_point;
203 u16 max_display_mastering_luminance;
204 u16 min_display_mastering_luminance;
205 u16 max_cll;
206 u16 max_fall;
207};
208
188int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame); 209int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame);
189ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer, 210ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
190 size_t size); 211 size_t size);
191ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame, 212ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
192 void *buffer, size_t size); 213 void *buffer, size_t size);
193int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame); 214int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame);
215int hdmi_drm_infoframe_init(struct hdmi_drm_infoframe *frame);
216ssize_t hdmi_drm_infoframe_pack(struct hdmi_drm_infoframe *frame, void *buffer,
217 size_t size);
218ssize_t hdmi_drm_infoframe_pack_only(const struct hdmi_drm_infoframe *frame,
219 void *buffer, size_t size);
220int hdmi_drm_infoframe_check(struct hdmi_drm_infoframe *frame);
194 221
195enum hdmi_spd_sdi { 222enum hdmi_spd_sdi {
196 HDMI_SPD_SDI_UNKNOWN, 223 HDMI_SPD_SDI_UNKNOWN,
@@ -381,6 +408,7 @@ union hdmi_infoframe {
381 struct hdmi_spd_infoframe spd; 408 struct hdmi_spd_infoframe spd;
382 union hdmi_vendor_any_infoframe vendor; 409 union hdmi_vendor_any_infoframe vendor;
383 struct hdmi_audio_infoframe audio; 410 struct hdmi_audio_infoframe audio;
411 struct hdmi_drm_infoframe drm;
384}; 412};
385 413
386ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, 414ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,