From d1943fde81ff41d7cca87f4a42f03992e90bddd5 Mon Sep 17 00:00:00 2001 From: Zheng Yang Date: Thu, 14 Sep 2017 11:08:52 +0800 Subject: [PATCH] drm: bridge: dw-hdmi: support Dynamic Range and Mastering Infoframe The Dynamic Range and Mastering InfoFrame carries data such as the EOTF and the Static Metadata associated with the dynamic range of the video stream. This function is introduced in the 2.11a version. Change-Id: I279cc0665e34d75209774013882ccc8946ce6da5 Signed-off-by: Zheng Yang --- drivers/gpu/drm/bridge/dw-hdmi.c | 102 +++++++++++++++++++++++++++++++ drivers/gpu/drm/bridge/dw-hdmi.h | 37 +++++++++++ 2 files changed, 139 insertions(+) diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index 758aa23f1527..bba046cc7479 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c @@ -1777,6 +1777,105 @@ static void hdmi_config_vendor_specific_infoframe(struct dw_hdmi *hdmi, HDMI_FC_DATAUTO0_VSD_MASK); } +#define HDR_LSB(n) ((n) & 0xff) +#define HDR_MSB(n) (((n) & 0xff00) >> 8) + +/* Set Dynamic Range and Mastering Infoframe */ +static void hdmi_config_hdr_infoframe(struct dw_hdmi *hdmi) +{ + struct hdmi_drm_infoframe frame; + struct hdr_static_metadata *hdr_metadata; + struct drm_connector_state *conn_state = hdmi->connector.state; + struct drm_hdmi_info *hdmi_info = &hdmi->connector.display_info.hdmi; + int ret; + + /* Dynamic Range and Mastering Infoframe is introduced in v2.11a. */ + if (hdmi->version < 0x211a) { + DRM_ERROR("Not support DRM Infoframe\n"); + return; + } + + hdmi_modb(hdmi, HDMI_FC_PACKET_DRM_TX_DEN, + HDMI_FC_PACKET_DRM_TX_EN_MASK, HDMI_FC_PACKET_TX_EN); + + if (!hdmi_info->hdr_panel_metadata.eotf) { + DRM_DEBUG("No need to set HDR metadata in infoframe\n"); + return; + } + + if (!conn_state->hdr_source_metadata_blob_ptr) { + DRM_DEBUG("source metadata not set yet\n"); + return; + } + + hdr_metadata = (struct hdr_static_metadata *) + conn_state->hdr_source_metadata_blob_ptr->data; + + if (!(hdmi_info->hdr_panel_metadata.eotf & BIT(hdr_metadata->eotf))) { + DRM_ERROR("Not support EOTF %d\n", hdr_metadata->eotf); + return; + } + + ret = drm_hdmi_infoframe_set_hdr_metadata(&frame, hdr_metadata); + if (ret < 0) { + DRM_ERROR("couldn't set HDR metadata in infoframe\n"); + return; + } + + hdmi_writeb(hdmi, 1, HDMI_FC_DRM_HB0); + hdmi_writeb(hdmi, frame.length, HDMI_FC_DRM_HB1); + hdmi_writeb(hdmi, frame.eotf, HDMI_FC_DRM_PB0); + hdmi_writeb(hdmi, frame.metadata_type, HDMI_FC_DRM_PB1); + hdmi_writeb(hdmi, HDR_LSB(frame.display_primaries_x[0]), + HDMI_FC_DRM_PB2); + hdmi_writeb(hdmi, HDR_MSB(frame.display_primaries_x[0]), + HDMI_FC_DRM_PB3); + hdmi_writeb(hdmi, HDR_LSB(frame.display_primaries_y[0]), + HDMI_FC_DRM_PB4); + hdmi_writeb(hdmi, HDR_MSB(frame.display_primaries_y[0]), + HDMI_FC_DRM_PB5); + hdmi_writeb(hdmi, HDR_LSB(frame.display_primaries_x[1]), + HDMI_FC_DRM_PB6); + hdmi_writeb(hdmi, HDR_MSB(frame.display_primaries_x[1]), + HDMI_FC_DRM_PB7); + hdmi_writeb(hdmi, HDR_LSB(frame.display_primaries_y[1]), + HDMI_FC_DRM_PB8); + hdmi_writeb(hdmi, HDR_MSB(frame.display_primaries_y[1]), + HDMI_FC_DRM_PB9); + hdmi_writeb(hdmi, HDR_LSB(frame.display_primaries_x[2]), + HDMI_FC_DRM_PB10); + hdmi_writeb(hdmi, HDR_MSB(frame.display_primaries_x[2]), + HDMI_FC_DRM_PB11); + hdmi_writeb(hdmi, HDR_LSB(frame.display_primaries_y[2]), + HDMI_FC_DRM_PB12); + hdmi_writeb(hdmi, HDR_MSB(frame.display_primaries_y[2]), + HDMI_FC_DRM_PB13); + hdmi_writeb(hdmi, HDR_LSB(frame.white_point_x), HDMI_FC_DRM_PB14); + hdmi_writeb(hdmi, HDR_MSB(frame.white_point_x), HDMI_FC_DRM_PB15); + hdmi_writeb(hdmi, HDR_LSB(frame.white_point_y), HDMI_FC_DRM_PB16); + hdmi_writeb(hdmi, HDR_MSB(frame.white_point_y), HDMI_FC_DRM_PB17); + hdmi_writeb(hdmi, HDR_LSB(frame.max_mastering_display_luminance), + HDMI_FC_DRM_PB18); + hdmi_writeb(hdmi, HDR_MSB(frame.max_mastering_display_luminance), + HDMI_FC_DRM_PB19); + hdmi_writeb(hdmi, HDR_LSB(frame.min_mastering_display_luminance), + HDMI_FC_DRM_PB20); + hdmi_writeb(hdmi, HDR_MSB(frame.min_mastering_display_luminance), + HDMI_FC_DRM_PB21); + hdmi_writeb(hdmi, HDR_LSB(frame.max_cll), HDMI_FC_DRM_PB22); + hdmi_writeb(hdmi, HDR_MSB(frame.max_cll), HDMI_FC_DRM_PB23); + hdmi_writeb(hdmi, HDR_LSB(frame.max_fall), HDMI_FC_DRM_PB24); + hdmi_writeb(hdmi, HDR_MSB(frame.max_fall), HDMI_FC_DRM_PB25); + hdmi_writeb(hdmi, 1, HDMI_FC_DRM_UP); + hdmi_modb(hdmi, HDMI_FC_PACKET_DRM_TX_EN, + HDMI_FC_PACKET_DRM_TX_EN_MASK, HDMI_FC_PACKET_TX_EN); + + if (conn_state->hdr_metadata_changed) + conn_state->hdr_metadata_changed = false; + + DRM_DEBUG("%s eotf %d end\n", __func__, hdr_metadata->eotf); +} + static unsigned int hdmi_get_tmdsclock(struct dw_hdmi *hdmi, unsigned long mpixelclock) { @@ -2154,6 +2253,7 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode) /* HDMI Initialization Step F - Configure AVI InfoFrame */ hdmi_config_AVI(hdmi, mode); hdmi_config_vendor_specific_infoframe(hdmi, mode); + hdmi_config_hdr_infoframe(hdmi); } else { dev_dbg(hdmi->dev, "%s DVI mode\n", __func__); } @@ -2474,6 +2574,8 @@ dw_hdmi_connector_atomic_flush(struct drm_connector *connector, enc_in_bus_format != hdmi->hdmi_data.enc_in_bus_format || enc_out_bus_format != hdmi->hdmi_data.enc_out_bus_format) dw_hdmi_setup(hdmi, &hdmi->previous_mode); + else if (connector->state->hdr_metadata_changed && hdmi->sink_is_hdmi) + hdmi_config_hdr_infoframe(hdmi); } static int diff --git a/drivers/gpu/drm/bridge/dw-hdmi.h b/drivers/gpu/drm/bridge/dw-hdmi.h index 57fafe0fd4f9..8a6e525d498b 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.h +++ b/drivers/gpu/drm/bridge/dw-hdmi.h @@ -265,6 +265,7 @@ #define HDMI_FC_POL2 0x10DB #define HDMI_FC_PRCONF 0x10E0 #define HDMI_FC_SCRAMBLER_CTRL 0x10E1 +#define HDMI_FC_PACKET_TX_EN 0x10E3 #define HDMI_FC_GMD_STAT 0x1100 #define HDMI_FC_GMD_EN 0x1101 @@ -300,6 +301,37 @@ #define HDMI_FC_GMD_PB26 0x111F #define HDMI_FC_GMD_PB27 0x1120 +#define HDMI_FC_DRM_UP 0x1167 +#define HDMI_FC_DRM_HB0 0x1168 +#define HDMI_FC_DRM_HB1 0x1169 +#define HDMI_FC_DRM_PB0 0x116a +#define HDMI_FC_DRM_PB1 0x116b +#define HDMI_FC_DRM_PB2 0x116c +#define HDMI_FC_DRM_PB3 0x116d +#define HDMI_FC_DRM_PB4 0x116e +#define HDMI_FC_DRM_PB5 0x116f +#define HDMI_FC_DRM_PB6 0x1170 +#define HDMI_FC_DRM_PB7 0x1171 +#define HDMI_FC_DRM_PB8 0x1172 +#define HDMI_FC_DRM_PB9 0x1173 +#define HDMI_FC_DRM_PB10 0x1174 +#define HDMI_FC_DRM_PB11 0x1175 +#define HDMI_FC_DRM_PB12 0x1176 +#define HDMI_FC_DRM_PB13 0x1177 +#define HDMI_FC_DRM_PB14 0x1178 +#define HDMI_FC_DRM_PB15 0x1179 +#define HDMI_FC_DRM_PB16 0x117a +#define HDMI_FC_DRM_PB17 0x117b +#define HDMI_FC_DRM_PB18 0x117c +#define HDMI_FC_DRM_PB19 0x117d +#define HDMI_FC_DRM_PB20 0x117e +#define HDMI_FC_DRM_PB21 0x117f +#define HDMI_FC_DRM_PB22 0x1180 +#define HDMI_FC_DRM_PB23 0x1181 +#define HDMI_FC_DRM_PB24 0x1182 +#define HDMI_FC_DRM_PB25 0x1183 +#define HDMI_FC_DRM_PB26 0x1184 + #define HDMI_FC_DBGFORCE 0x1200 #define HDMI_FC_DBGAUD0CH0 0x1201 #define HDMI_FC_DBGAUD1CH0 0x1202 @@ -811,6 +843,11 @@ enum { HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_MASK = 0x0F, HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_OFFSET = 0, +/* FC_PACKET_TX_EN field values */ + HDMI_FC_PACKET_DRM_TX_EN_MASK = 0x80, + HDMI_FC_PACKET_DRM_TX_EN = 0x80, + HDMI_FC_PACKET_DRM_TX_DEN = 0x00, + /* FC_AVICONF0-FC_AVICONF3 field values */ HDMI_FC_AVICONF0_PIX_FMT_MASK = 0x03, HDMI_FC_AVICONF0_PIX_FMT_RGB = 0x00,