MLK-17634-12: drm: imx: hdp: Send HDR metadata to the sink
authorLaurentiu Palcu <laurentiu.palcu@nxp.com>
Mon, 12 Feb 2018 08:23:48 +0000 (10:23 +0200)
committerLeonard Crestez <leonard.crestez@nxp.com>
Wed, 17 Apr 2019 23:51:34 +0000 (02:51 +0300)
If the HDR metadata proprety is set, then the metadata will be sent
to the sink at the next mode set.

Signed-off-by: Laurentiu Palcu <laurentiu.palcu@nxp.com>
drivers/gpu/drm/imx/hdp/imx-hdmi.c
drivers/gpu/drm/imx/hdp/imx-hdmi.h
drivers/gpu/drm/imx/hdp/imx-hdp.c
drivers/gpu/drm/imx/hdp/imx-hdp.h

index d262743..fa9932f 100644 (file)
@@ -267,3 +267,26 @@ int hdmi_get_hpd_state(state_struct *state, u8 *hpd)
        ret = CDN_API_HDMITX_GetHpdStatus_blocking(state, hpd);
        return ret;
 }
+
+int hdmi_write_hdr_metadata(state_struct *state,
+                           union hdmi_infoframe *hdr_infoframe)
+{
+       struct imx_hdp *hdp = container_of(state, struct imx_hdp, state);
+       u8 buffer[40];
+       int infoframe_size;
+
+       infoframe_size = hdmi_infoframe_pack(hdr_infoframe,
+                                            buffer + 1, sizeof(buffer) - 1);
+       if (infoframe_size < 0) {
+               dev_err(hdp->dev, "Wrong metadata infoframe: %d\n",
+                       infoframe_size);
+               return infoframe_size;
+       }
+
+       buffer[0] = 0;
+       infoframe_size++;
+
+       return CDN_API_InfoframeSet(state, 1, infoframe_size,
+                                   (u32 *)buffer,
+                                   HDMI_INFOFRAME_TYPE_DRM);
+}
index de46462..c39f1ca 100644 (file)
@@ -22,5 +22,7 @@ int hdmi_get_edid_block(void *data, u8 *buf, u32 block, size_t len);
 int hdmi_get_hpd_state(state_struct *state, u8 *hpd);
 int hdmi_phy_init_t28hpc(state_struct *state, int vic, int format, int color_depth);
 void hdmi_mode_set_t28hpc(state_struct *state, int vic, int format, int color_depth, int temp);
+int hdmi_write_hdr_metadata(state_struct *state,
+                           union hdmi_infoframe *hdr_infoframe);
 
 #endif
index 28842a4..0bf34d5 100644 (file)
@@ -675,13 +675,49 @@ static int imx_hdp_imx_encoder_atomic_check(struct drm_encoder *encoder,
        struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state);
 
        imx_crtc_state->bus_format = MEDIA_BUS_FMT_RGB101010_1X30;
+
+       if (conn_state->hdr_metadata_changed)
+               crtc_state->mode_changed = true;
+
        return 0;
 }
 
+static void imx_hdp_imx_encoder_atomic_modeset(struct drm_encoder *encoder,
+                                            struct drm_crtc_state *crtc_state,
+                                       struct drm_connector_state *conn_state)
+{
+       struct imx_hdp *hdp = container_of(encoder, struct imx_hdp, encoder);
+       union hdmi_infoframe frame;
+       struct hdr_static_metadata *hdr_metadata;
+       int ret;
+
+       if (!hdp->ops->write_hdr_metadata)
+               return;
+
+       if (!conn_state->hdr_source_metadata_blob_ptr ||
+           conn_state->hdr_source_metadata_blob_ptr->length == 0)
+               return;
+
+       if (!conn_state->hdr_metadata_changed)
+               return;
+
+       hdr_metadata = (struct hdr_static_metadata *)
+                       conn_state->hdr_source_metadata_blob_ptr->data;
+
+       ret = drm_hdmi_infoframe_set_hdr_metadata(&frame.drm, hdr_metadata);
+       if (ret < 0) {
+               DRM_ERROR("could not set HDR metadata in infoframe\n");
+               return;
+       }
+
+       hdp->ops->write_hdr_metadata(&hdp->state, &frame);
+}
+
 static const struct drm_encoder_helper_funcs imx_hdp_imx_encoder_helper_funcs = {
        .enable     = imx_hdp_imx_encoder_enable,
        .disable    = imx_hdp_imx_encoder_disable,
        .atomic_check = imx_hdp_imx_encoder_atomic_check,
+       .atomic_mode_set = imx_hdp_imx_encoder_atomic_modeset,
 };
 
 static const struct drm_encoder_funcs imx_hdp_imx_encoder_funcs = {
@@ -853,6 +889,7 @@ static struct hdp_ops imx8mq_ops = {
        .mode_set = hdmi_mode_set_t28hpc,
        .get_edid_block = hdmi_get_edid_block,
        .get_hpd_state = hdmi_get_hpd_state,
+       .write_hdr_metadata = hdmi_write_hdr_metadata,
 };
 
 static struct hdp_devtype imx8mq_hdmi_devtype = {
index 7b5cfd8..94564b0 100644 (file)
@@ -22,6 +22,7 @@
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_encoder_slave.h>
+#include <drm/drm_atomic.h>
 #include <soc/imx8/sc/sci.h>
 
 #include <drm/drm_dp_helper.h>
@@ -89,6 +90,8 @@ struct hdp_ops {
        void (*mode_set)(state_struct *state, int vic, int format, int color_depth, int max_link);
        int (*get_edid_block)(void *data, u8 *buf, u32 block, size_t len);
        int (*get_hpd_state)(state_struct *state, u8 *hpd);
+       int (*write_hdr_metadata)(state_struct *state,
+                                 union hdmi_infoframe *hdr_infoframe);
 
        void (*phy_reset)(sc_ipc_t ipcHndl, u8 reset);
        int (*pixel_link_init)(state_struct *state);