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,