drm/msm: program hdr information to HDMI registers
HDR metadata information is passed down from userspace
based on the HDR frame.
Program these properties to relevant HDMI registers
using the pre_kickoff callback registered for the
DRM HDMI connector.
This ensures that HDR information is updated on a
per-frame basis to the sink.
Change-Id: I20c4018316329b1b35a11b8ab4b96e923b3abb3a
Signed-off-by: Abhinav Kumar <abhinavk@codeaurora.org>
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
index 8e60235..2ee75a2 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
@@ -1867,6 +1867,106 @@
return rc;
}
+static void sde_hdmi_panel_set_hdr_infoframe(struct sde_hdmi *display,
+struct drm_msm_ext_panel_hdr_metadata *hdr_meta)
+{
+ u32 packet_payload = 0;
+ u32 packet_header = 0;
+ u32 packet_control = 0;
+ u32 const type_code = 0x87;
+ u32 const version = 0x01;
+ u32 const length = 0x1a;
+ u32 const descriptor_id = 0x00;
+ struct hdmi *hdmi;
+ struct drm_connector *connector;
+
+ if (!display || !hdr_meta) {
+ SDE_ERROR("invalid input\n");
+ return;
+ }
+
+ hdmi = display->ctrl.ctrl;
+ connector = display->ctrl.ctrl->connector;
+
+ if (!hdmi || !connector) {
+ SDE_ERROR("invalid input\n");
+ return;
+ }
+
+ if (!connector->hdr_supported) {
+ SDE_ERROR("Sink does not support HDR\n");
+ return;
+ }
+
+ /* Setup Packet header and payload */
+ packet_header = type_code | (version << 8) | (length << 16);
+ hdmi_write(hdmi, HDMI_GENERIC0_HDR, packet_header);
+
+ packet_payload = (hdr_meta->eotf << 8);
+ if (connector->hdr_metadata_type_one) {
+ packet_payload |= (descriptor_id << 16)
+ | (HDMI_GET_LSB(hdr_meta->display_primaries_x[0])
+ << 24);
+ hdmi_write(hdmi, HDMI_GENERIC0_0, packet_payload);
+ } else {
+ pr_debug("Metadata Type 1 not supported\n");
+ hdmi_write(hdmi, HDMI_GENERIC0_0, packet_payload);
+ goto enable_packet_control;
+ }
+
+ packet_payload =
+ (HDMI_GET_MSB(hdr_meta->display_primaries_x[0]))
+ | (HDMI_GET_LSB(hdr_meta->display_primaries_y[0]) << 8)
+ | (HDMI_GET_MSB(hdr_meta->display_primaries_y[0]) << 16)
+ | (HDMI_GET_LSB(hdr_meta->display_primaries_x[1]) << 24);
+ hdmi_write(hdmi, HDMI_GENERIC0_1, packet_payload);
+
+ packet_payload =
+ (HDMI_GET_MSB(hdr_meta->display_primaries_x[1]))
+ | (HDMI_GET_LSB(hdr_meta->display_primaries_y[1]) << 8)
+ | (HDMI_GET_MSB(hdr_meta->display_primaries_y[1]) << 16)
+ | (HDMI_GET_LSB(hdr_meta->display_primaries_x[2]) << 24);
+ hdmi_write(hdmi, HDMI_GENERIC0_2, packet_payload);
+
+ packet_payload =
+ (HDMI_GET_MSB(hdr_meta->display_primaries_x[2]))
+ | (HDMI_GET_LSB(hdr_meta->display_primaries_y[2]) << 8)
+ | (HDMI_GET_MSB(hdr_meta->display_primaries_y[2]) << 16)
+ | (HDMI_GET_LSB(hdr_meta->white_point_x) << 24);
+ hdmi_write(hdmi, HDMI_GENERIC0_3, packet_payload);
+
+ packet_payload =
+ (HDMI_GET_MSB(hdr_meta->white_point_x))
+ | (HDMI_GET_LSB(hdr_meta->white_point_y) << 8)
+ | (HDMI_GET_MSB(hdr_meta->white_point_y) << 16)
+ | (HDMI_GET_LSB(hdr_meta->max_luminance) << 24);
+ hdmi_write(hdmi, HDMI_GENERIC0_4, packet_payload);
+
+ packet_payload =
+ (HDMI_GET_MSB(hdr_meta->max_luminance))
+ | (HDMI_GET_LSB(hdr_meta->min_luminance) << 8)
+ | (HDMI_GET_MSB(hdr_meta->min_luminance) << 16)
+ | (HDMI_GET_LSB(hdr_meta->max_content_light_level) << 24);
+ hdmi_write(hdmi, HDMI_GENERIC0_5, packet_payload);
+
+ packet_payload =
+ (HDMI_GET_MSB(hdr_meta->max_content_light_level))
+ | (HDMI_GET_LSB(hdr_meta->max_average_light_level) << 8)
+ | (HDMI_GET_MSB(hdr_meta->max_average_light_level) << 16);
+ hdmi_write(hdmi, HDMI_GENERIC0_6, packet_payload);
+
+enable_packet_control:
+ /*
+ * GENERIC0_LINE | GENERIC0_CONT | GENERIC0_SEND
+ * Setup HDMI TX generic packet control
+ * Enable this packet to transmit every frame
+ * Enable HDMI TX engine to transmit Generic packet 1
+ */
+ packet_control = hdmi_read(hdmi, HDMI_GEN_PKT_CTRL);
+ packet_control |= BIT(0) | BIT(1) | BIT(2) | BIT(16);
+ hdmi_write(hdmi, HDMI_GEN_PKT_CTRL, packet_control);
+}
+
int sde_hdmi_set_property(struct drm_connector *connector,
struct drm_connector_state *state,
int property_index,
@@ -2207,6 +2307,10 @@
void *display,
struct msm_display_kickoff_params *params)
{
+
+ sde_hdmi_panel_set_hdr_infoframe(display,
+ params->hdr_metadata);
+
return 0;
}
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h
index 6b310ac..8b69dd31 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h
@@ -94,6 +94,9 @@
/* default hsyncs for 4k@60 for 200ms */
#define HDMI_DEFAULT_TIMEOUT_HSYNC 28571
+#define HDMI_GET_MSB(x)(x >> 8)
+#define HDMI_GET_LSB(x)(x & 0xff)
+
/*
* Bits 1:0 in HDMI_HW_DDC_CTRL that dictate how the HDCP 2.2 RxStatus will be
* read by the hardware