diff options
author | Uma Shankar <uma.shankar@intel.com> | 2018-01-19 14:42:00 +0200 |
---|---|---|
committer | Jason Liu <jason.hui.liu@nxp.com> | 2019-02-12 10:30:44 +0800 |
commit | b3c6511337c44b7e5b07f3244e4545b09e92c805 (patch) | |
tree | 04b8da58d55b2891694101511a8c25787f293dd2 /drivers/video | |
parent | a37e9acb54a646b57ed182f157009665a9bd8c8f (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.
Signed-off-by: Uma Shankar <uma.shankar@intel.com>
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/hdmi.c | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c index 111a0ab6280a..28b1e325536f 100644 --- a/drivers/video/hdmi.c +++ b/drivers/video/hdmi.c @@ -393,6 +393,103 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame, } EXPORT_SYMBOL(hdmi_vendor_infoframe_pack); +/** + * hdmi_drm_infoframe_init() - initialize an HDMI Dynaminc Range and + * mastering infoframe + * @frame: HDMI DRM infoframe + * + * Returns 0 on success or a negative error code on failure. + */ +int hdmi_drm_infoframe_init(struct hdmi_drm_infoframe *frame) +{ + memset(frame, 0, sizeof(*frame)); + + frame->type = HDMI_INFOFRAME_TYPE_DRM; + frame->version = 1; + + return 0; +} +EXPORT_SYMBOL(hdmi_drm_infoframe_init); + +/** + * hdmi_drm_infoframe_pack() - write HDMI DRM infoframe to binary buffer + * @frame: HDMI DRM infoframe + * @buffer: destination buffer + * @size: size of buffer + * + * Packs the information contained in the @frame structure into a binary + * representation that can be written into the corresponding controller + * registers. Also computes the checksum as required by section 5.3.5 of + * the HDMI 1.4 specification. + * + * Returns the number of bytes packed into the binary buffer or a negative + * error code on failure. + */ +ssize_t hdmi_drm_infoframe_pack(struct hdmi_drm_infoframe *frame, void *buffer, + size_t size) +{ + u8 *ptr = buffer; + size_t length; + + length = HDMI_INFOFRAME_HEADER_SIZE + frame->length; + + if (size < length) + return -ENOSPC; + + memset(buffer, 0, size); + + ptr[0] = frame->type; + ptr[1] = frame->version; + ptr[2] = frame->length; + ptr[3] = 0; /* checksum */ + + /* start infoframe payload */ + ptr += HDMI_INFOFRAME_HEADER_SIZE; + + ptr[0] = frame->eotf; + ptr[1] = frame->metadata_type; + + ptr[2] = frame->display_primaries_x[0] & 0xff; + ptr[3] = frame->display_primaries_x[0] >> 8; + + ptr[4] = frame->display_primaries_x[1] & 0xff; + ptr[5] = frame->display_primaries_x[1] >> 8; + + ptr[6] = frame->display_primaries_x[2] & 0xff; + ptr[7] = frame->display_primaries_x[2] >> 8; + + ptr[9] = frame->display_primaries_y[0] & 0xff; + ptr[10] = frame->display_primaries_y[0] >> 8; + + ptr[11] = frame->display_primaries_y[1] & 0xff; + ptr[12] = frame->display_primaries_y[1] >> 8; + + ptr[13] = frame->display_primaries_y[2] & 0xff; + ptr[14] = frame->display_primaries_y[2] >> 8; + + ptr[15] = frame->white_point_x & 0xff; + ptr[16] = frame->white_point_x >> 8; + + ptr[17] = frame->white_point_y & 0xff; + ptr[18] = frame->white_point_y >> 8; + + ptr[19] = frame->max_mastering_display_luminance & 0xff; + ptr[20] = frame->max_mastering_display_luminance >> 8; + + ptr[21] = frame->min_mastering_display_luminance & 0xff; + ptr[22] = frame->min_mastering_display_luminance >> 8; + + ptr[23] = frame->max_cll & 0xff; + ptr[24] = frame->max_cll >> 8; + + ptr[25] = frame->max_fall & 0xff; + ptr[26] = frame->max_fall >> 8; + + hdmi_infoframe_set_checksum(buffer, length); + + return length; +} + /* * hdmi_vendor_any_infoframe_pack() - write a vendor infoframe to binary buffer */ @@ -430,6 +527,9 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size) case HDMI_INFOFRAME_TYPE_AVI: length = hdmi_avi_infoframe_pack(&frame->avi, buffer, size); break; + case HDMI_INFOFRAME_TYPE_DRM: + length = hdmi_drm_infoframe_pack(&frame->drm, buffer, size); + break; case HDMI_INFOFRAME_TYPE_SPD: length = hdmi_spd_infoframe_pack(&frame->spd, buffer, size); break; @@ -462,6 +562,8 @@ static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type) return "Source Product Description (SPD)"; case HDMI_INFOFRAME_TYPE_AUDIO: return "Audio"; + case HDMI_INFOFRAME_TYPE_DRM: + return "Dynamic Range and Mastering"; } return "Reserved"; } @@ -908,6 +1010,39 @@ static void hdmi_audio_infoframe_log(const char *level, frame->downmix_inhibit ? "Yes" : "No"); } +/** + * hdmi_drm_infoframe_log() - log info of HDMI DRM infoframe + * @level: logging level + * @dev: device + * @frame: HDMI DRM infoframe + */ +static void hdmi_drm_infoframe_log(const char *level, + struct device *dev, + struct hdmi_drm_infoframe *frame) +{ + int i; + + hdmi_infoframe_log_header(level, dev, + (struct hdmi_any_infoframe *)frame); + hdmi_log("length: %d\n", frame->length); + hdmi_log("eotf: %d\n", frame->eotf); + for (i = 0; i <= 2; i++) { + hdmi_log("x[%d]: %d\n", i, frame->display_primaries_x[i]); + hdmi_log("y[%d]: %d\n", i, frame->display_primaries_y[i]); + } + + hdmi_log("white point x: %d\n", frame->white_point_x); + hdmi_log("white point y: %d\n", frame->white_point_y); + + hdmi_log("max_mastering_display_luminance: %d\n", + frame->max_mastering_display_luminance); + hdmi_log("min_mastering_display_luminance: %d\n", + frame->min_mastering_display_luminance); + + hdmi_log("max_cll: %d\n", frame->max_cll); + hdmi_log("max_fall: %d\n", frame->max_fall); +} + static const char * hdmi_3d_structure_get_name(enum hdmi_3d_structure s3d_struct) { @@ -996,6 +1131,9 @@ void hdmi_infoframe_log(const char *level, case HDMI_INFOFRAME_TYPE_VENDOR: hdmi_vendor_any_infoframe_log(level, dev, &frame->vendor); break; + case HDMI_INFOFRAME_TYPE_DRM: + hdmi_drm_infoframe_log(level, dev, &frame->drm); + break; } } EXPORT_SYMBOL(hdmi_infoframe_log); |