OSDN Git Service

drm/msm: add checksum for HDR infoframe
authorAbhinav Kumar <abhinavk@codeaurora.org>
Sat, 22 Sep 2018 06:51:50 +0000 (23:51 -0700)
committerAbhinav Kumar <abhinavk@codeaurora.org>
Thu, 4 Oct 2018 02:01:20 +0000 (19:01 -0700)
Checksum for the HDR infoframe is set to zero by default
as this is not a mandatory field as per the HDMI spec.

However certain HDMI sinks still expect a non-zero
checksum. Otherwise they disregard the infoframe
and the sink does not enter HDR mode despite other fields
of the infoframe being valid.

Add a valid checksum to the HDR infoframe to improve
interoperability of our HDR solution for HDMI.

Change-Id: Ie826e5e637fc1f053203bdcf6a829d0246a9ed67
Signed-off-by: Abhinav Kumar <abhinavk@codeaurora.org>
drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.c
drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h

index 83141aa..8177091 100644 (file)
@@ -2009,6 +2009,7 @@ struct drm_msm_ext_panel_hdr_metadata *hdr_meta)
        u32 const version = 0x01;
        u32 const length = 0x1a;
        u32 const descriptor_id = 0x00;
+       u8 checksum;
        struct hdmi *hdmi;
        struct drm_connector *connector;
 
@@ -2029,7 +2030,19 @@ struct drm_msm_ext_panel_hdr_metadata *hdr_meta)
        packet_header = type_code | (version << 8) | (length << 16);
        hdmi_write(hdmi, HDMI_GENERIC0_HDR, packet_header);
 
-       packet_payload = (hdr_meta->eotf << 8);
+       /**
+        * Checksum is not a mandatory field for
+        * the HDR infoframe as per CEA-861-3 specification.
+        * However some HDMI sinks still expect a
+        * valid checksum to be included as part of
+        * the infoframe. Hence compute and add
+        * the checksum to improve sink interoperability
+        * for our HDR solution on HDMI.
+        */
+       checksum = sde_hdmi_hdr_set_chksum(hdr_meta);
+
+       packet_payload = (hdr_meta->eotf << 8) | checksum;
+
        if (connector->hdr_metadata_type_one) {
                packet_payload |= (descriptor_id << 16)
                        | (HDMI_GET_LSB(hdr_meta->display_primaries_x[0])
index 8ce90b9..a037ea2 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -77,6 +77,96 @@ static const char *sde_hdmi_hdr_sname(enum sde_hdmi_hdr_state hdr_state)
        }
 }
 
+static u8 sde_hdmi_infoframe_checksum(u8 *ptr, size_t size)
+{
+       u8 csum = 0;
+       size_t i;
+
+       /* compute checksum */
+       for (i = 0; i < size; i++)
+               csum += ptr[i];
+
+       return 256 - csum;
+}
+
+u8 sde_hdmi_hdr_set_chksum(struct drm_msm_ext_panel_hdr_metadata *hdr_meta)
+{
+       u8 *buff;
+       u8 *ptr;
+       u32 length;
+       u32 size;
+       u32 chksum = 0;
+       u32 const type_code = 0x87;
+       u32 const version = 0x01;
+       u32 const descriptor_id = 0x00;
+
+       /* length of metadata is 26 bytes */
+       length = 0x1a;
+       /* add 4 bytes for the header */
+       size = length + HDMI_INFOFRAME_HEADER_SIZE;
+
+       buff = kzalloc(size, GFP_KERNEL);
+
+       if (!buff) {
+               SDE_ERROR("invalid buff\n");
+               goto err_alloc;
+       }
+
+       ptr = buff;
+
+       buff[0] = type_code;
+       buff[1] = version;
+       buff[2] = length;
+       buff[3] = 0;
+       /* start infoframe payload */
+       buff += HDMI_INFOFRAME_HEADER_SIZE;
+
+       buff[0] = hdr_meta->eotf;
+       buff[1] = descriptor_id;
+
+       buff[2] = hdr_meta->display_primaries_x[0] & 0xff;
+       buff[3] = hdr_meta->display_primaries_x[0] >> 8;
+
+       buff[4] = hdr_meta->display_primaries_x[1] & 0xff;
+       buff[5] = hdr_meta->display_primaries_x[1] >> 8;
+
+       buff[6] = hdr_meta->display_primaries_x[2] & 0xff;
+       buff[7] = hdr_meta->display_primaries_x[2] >> 8;
+
+       buff[8] = hdr_meta->display_primaries_y[0] & 0xff;
+       buff[9] = hdr_meta->display_primaries_y[0] >> 8;
+
+       buff[10] = hdr_meta->display_primaries_y[1] & 0xff;
+       buff[11] = hdr_meta->display_primaries_y[1] >> 8;
+
+       buff[12] = hdr_meta->display_primaries_y[2] & 0xff;
+       buff[13] = hdr_meta->display_primaries_y[2] >> 8;
+
+       buff[14] = hdr_meta->white_point_x & 0xff;
+       buff[15] = hdr_meta->white_point_x >> 8;
+       buff[16] = hdr_meta->white_point_y & 0xff;
+       buff[17] = hdr_meta->white_point_y >> 8;
+
+       buff[18] = hdr_meta->max_luminance & 0xff;
+       buff[19] = hdr_meta->max_luminance >> 8;
+
+       buff[20] = hdr_meta->min_luminance & 0xff;
+       buff[21] = hdr_meta->min_luminance >> 8;
+
+       buff[22] = hdr_meta->max_content_light_level & 0xff;
+       buff[23] = hdr_meta->max_content_light_level >> 8;
+
+       buff[24] = hdr_meta->max_average_light_level & 0xff;
+       buff[25] = hdr_meta->max_average_light_level >> 8;
+
+       chksum = sde_hdmi_infoframe_checksum(ptr, size);
+
+       kfree(ptr);
+
+err_alloc:
+       return chksum;
+}
+
 /**
  * sde_hdmi_dump_regs - utility to dump HDMI regs
  * @hdmi_display: Pointer to private display handle
index 340e665..56a8be6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -200,5 +200,6 @@ u8 sde_hdmi_hdr_get_ops(u8 curr_state,
        u8 new_state);
 void sde_hdmi_ctrl_reset(struct hdmi *hdmi);
 void sde_hdmi_ctrl_cfg(struct hdmi *hdmi, bool power_on);
+u8 sde_hdmi_hdr_set_chksum(struct drm_msm_ext_panel_hdr_metadata *hdr_meta);
 
 #endif /* _SDE_HDMI_UTIL_H_ */