11bb76ff1Sjsg // SPDX-License-Identifier: MIT
21bb76ff1Sjsg 
31bb76ff1Sjsg #include <linux/module.h>
41bb76ff1Sjsg 
51bb76ff1Sjsg #include <drm/display/drm_hdmi_helper.h>
61bb76ff1Sjsg #include <drm/drm_connector.h>
71bb76ff1Sjsg #include <drm/drm_edid.h>
81bb76ff1Sjsg #include <drm/drm_modes.h>
91bb76ff1Sjsg #include <drm/drm_print.h>
101bb76ff1Sjsg #include <drm/drm_property.h>
111bb76ff1Sjsg 
is_eotf_supported(u8 output_eotf,u8 sink_eotf)121bb76ff1Sjsg static inline bool is_eotf_supported(u8 output_eotf, u8 sink_eotf)
131bb76ff1Sjsg {
141bb76ff1Sjsg 	return sink_eotf & BIT(output_eotf);
151bb76ff1Sjsg }
161bb76ff1Sjsg 
171bb76ff1Sjsg /**
181bb76ff1Sjsg  * drm_hdmi_infoframe_set_hdr_metadata() - fill an HDMI DRM infoframe with
191bb76ff1Sjsg  *                                         HDR metadata from userspace
201bb76ff1Sjsg  * @frame: HDMI DRM infoframe
211bb76ff1Sjsg  * @conn_state: Connector state containing HDR metadata
221bb76ff1Sjsg  *
231bb76ff1Sjsg  * Return: 0 on success or a negative error code on failure.
241bb76ff1Sjsg  */
drm_hdmi_infoframe_set_hdr_metadata(struct hdmi_drm_infoframe * frame,const struct drm_connector_state * conn_state)251bb76ff1Sjsg int drm_hdmi_infoframe_set_hdr_metadata(struct hdmi_drm_infoframe *frame,
261bb76ff1Sjsg 					const struct drm_connector_state *conn_state)
271bb76ff1Sjsg {
281bb76ff1Sjsg 	struct drm_connector *connector;
291bb76ff1Sjsg 	struct hdr_output_metadata *hdr_metadata;
301bb76ff1Sjsg 	int err;
311bb76ff1Sjsg 
321bb76ff1Sjsg 	if (!frame || !conn_state)
331bb76ff1Sjsg 		return -EINVAL;
341bb76ff1Sjsg 
351bb76ff1Sjsg 	connector = conn_state->connector;
361bb76ff1Sjsg 
371bb76ff1Sjsg 	if (!conn_state->hdr_output_metadata)
381bb76ff1Sjsg 		return -EINVAL;
391bb76ff1Sjsg 
401bb76ff1Sjsg 	hdr_metadata = conn_state->hdr_output_metadata->data;
411bb76ff1Sjsg 
421bb76ff1Sjsg 	if (!hdr_metadata || !connector)
431bb76ff1Sjsg 		return -EINVAL;
441bb76ff1Sjsg 
451bb76ff1Sjsg 	/* Sink EOTF is Bit map while infoframe is absolute values */
461bb76ff1Sjsg 	if (!is_eotf_supported(hdr_metadata->hdmi_metadata_type1.eotf,
47*efe459efSjsg 	    connector->hdr_sink_metadata.hdmi_type1.eotf))
48*efe459efSjsg 		DRM_DEBUG_KMS("Unknown EOTF %d\n", hdr_metadata->hdmi_metadata_type1.eotf);
491bb76ff1Sjsg 
501bb76ff1Sjsg 	err = hdmi_drm_infoframe_init(frame);
511bb76ff1Sjsg 	if (err < 0)
521bb76ff1Sjsg 		return err;
531bb76ff1Sjsg 
541bb76ff1Sjsg 	frame->eotf = hdr_metadata->hdmi_metadata_type1.eotf;
551bb76ff1Sjsg 	frame->metadata_type = hdr_metadata->hdmi_metadata_type1.metadata_type;
561bb76ff1Sjsg 
571bb76ff1Sjsg 	BUILD_BUG_ON(sizeof(frame->display_primaries) !=
581bb76ff1Sjsg 		     sizeof(hdr_metadata->hdmi_metadata_type1.display_primaries));
591bb76ff1Sjsg 	BUILD_BUG_ON(sizeof(frame->white_point) !=
601bb76ff1Sjsg 		     sizeof(hdr_metadata->hdmi_metadata_type1.white_point));
611bb76ff1Sjsg 
621bb76ff1Sjsg 	memcpy(&frame->display_primaries,
631bb76ff1Sjsg 	       &hdr_metadata->hdmi_metadata_type1.display_primaries,
641bb76ff1Sjsg 	       sizeof(frame->display_primaries));
651bb76ff1Sjsg 
661bb76ff1Sjsg 	memcpy(&frame->white_point,
671bb76ff1Sjsg 	       &hdr_metadata->hdmi_metadata_type1.white_point,
681bb76ff1Sjsg 	       sizeof(frame->white_point));
691bb76ff1Sjsg 
701bb76ff1Sjsg 	frame->max_display_mastering_luminance =
711bb76ff1Sjsg 		hdr_metadata->hdmi_metadata_type1.max_display_mastering_luminance;
721bb76ff1Sjsg 	frame->min_display_mastering_luminance =
731bb76ff1Sjsg 		hdr_metadata->hdmi_metadata_type1.min_display_mastering_luminance;
741bb76ff1Sjsg 	frame->max_fall = hdr_metadata->hdmi_metadata_type1.max_fall;
751bb76ff1Sjsg 	frame->max_cll = hdr_metadata->hdmi_metadata_type1.max_cll;
761bb76ff1Sjsg 
771bb76ff1Sjsg 	return 0;
781bb76ff1Sjsg }
791bb76ff1Sjsg EXPORT_SYMBOL(drm_hdmi_infoframe_set_hdr_metadata);
801bb76ff1Sjsg 
811bb76ff1Sjsg /* HDMI Colorspace Spec Definitions */
821bb76ff1Sjsg #define FULL_COLORIMETRY_MASK		0x1FF
831bb76ff1Sjsg #define NORMAL_COLORIMETRY_MASK		0x3
841bb76ff1Sjsg #define EXTENDED_COLORIMETRY_MASK	0x7
851bb76ff1Sjsg #define EXTENDED_ACE_COLORIMETRY_MASK	0xF
861bb76ff1Sjsg 
871bb76ff1Sjsg #define C(x) ((x) << 0)
881bb76ff1Sjsg #define EC(x) ((x) << 2)
891bb76ff1Sjsg #define ACE(x) ((x) << 5)
901bb76ff1Sjsg 
911bb76ff1Sjsg #define HDMI_COLORIMETRY_NO_DATA		0x0
921bb76ff1Sjsg #define HDMI_COLORIMETRY_SMPTE_170M_YCC		(C(1) | EC(0) | ACE(0))
931bb76ff1Sjsg #define HDMI_COLORIMETRY_BT709_YCC		(C(2) | EC(0) | ACE(0))
941bb76ff1Sjsg #define HDMI_COLORIMETRY_XVYCC_601		(C(3) | EC(0) | ACE(0))
951bb76ff1Sjsg #define HDMI_COLORIMETRY_XVYCC_709		(C(3) | EC(1) | ACE(0))
961bb76ff1Sjsg #define HDMI_COLORIMETRY_SYCC_601		(C(3) | EC(2) | ACE(0))
971bb76ff1Sjsg #define HDMI_COLORIMETRY_OPYCC_601		(C(3) | EC(3) | ACE(0))
981bb76ff1Sjsg #define HDMI_COLORIMETRY_OPRGB			(C(3) | EC(4) | ACE(0))
991bb76ff1Sjsg #define HDMI_COLORIMETRY_BT2020_CYCC		(C(3) | EC(5) | ACE(0))
1001bb76ff1Sjsg #define HDMI_COLORIMETRY_BT2020_RGB		(C(3) | EC(6) | ACE(0))
1011bb76ff1Sjsg #define HDMI_COLORIMETRY_BT2020_YCC		(C(3) | EC(6) | ACE(0))
1021bb76ff1Sjsg #define HDMI_COLORIMETRY_DCI_P3_RGB_D65		(C(3) | EC(7) | ACE(0))
1031bb76ff1Sjsg #define HDMI_COLORIMETRY_DCI_P3_RGB_THEATER	(C(3) | EC(7) | ACE(1))
1041bb76ff1Sjsg 
1051bb76ff1Sjsg static const u32 hdmi_colorimetry_val[] = {
1061bb76ff1Sjsg 	[DRM_MODE_COLORIMETRY_NO_DATA] = HDMI_COLORIMETRY_NO_DATA,
1071bb76ff1Sjsg 	[DRM_MODE_COLORIMETRY_SMPTE_170M_YCC] = HDMI_COLORIMETRY_SMPTE_170M_YCC,
1081bb76ff1Sjsg 	[DRM_MODE_COLORIMETRY_BT709_YCC] = HDMI_COLORIMETRY_BT709_YCC,
1091bb76ff1Sjsg 	[DRM_MODE_COLORIMETRY_XVYCC_601] = HDMI_COLORIMETRY_XVYCC_601,
1101bb76ff1Sjsg 	[DRM_MODE_COLORIMETRY_XVYCC_709] = HDMI_COLORIMETRY_XVYCC_709,
1111bb76ff1Sjsg 	[DRM_MODE_COLORIMETRY_SYCC_601] = HDMI_COLORIMETRY_SYCC_601,
1121bb76ff1Sjsg 	[DRM_MODE_COLORIMETRY_OPYCC_601] = HDMI_COLORIMETRY_OPYCC_601,
1131bb76ff1Sjsg 	[DRM_MODE_COLORIMETRY_OPRGB] = HDMI_COLORIMETRY_OPRGB,
1141bb76ff1Sjsg 	[DRM_MODE_COLORIMETRY_BT2020_CYCC] = HDMI_COLORIMETRY_BT2020_CYCC,
1151bb76ff1Sjsg 	[DRM_MODE_COLORIMETRY_BT2020_RGB] = HDMI_COLORIMETRY_BT2020_RGB,
1161bb76ff1Sjsg 	[DRM_MODE_COLORIMETRY_BT2020_YCC] = HDMI_COLORIMETRY_BT2020_YCC,
1171bb76ff1Sjsg };
1181bb76ff1Sjsg 
1191bb76ff1Sjsg #undef C
1201bb76ff1Sjsg #undef EC
1211bb76ff1Sjsg #undef ACE
1221bb76ff1Sjsg 
1231bb76ff1Sjsg /**
1241bb76ff1Sjsg  * drm_hdmi_avi_infoframe_colorimetry() - fill the HDMI AVI infoframe
1251bb76ff1Sjsg  *                                       colorimetry information
1261bb76ff1Sjsg  * @frame: HDMI AVI infoframe
1271bb76ff1Sjsg  * @conn_state: connector state
1281bb76ff1Sjsg  */
drm_hdmi_avi_infoframe_colorimetry(struct hdmi_avi_infoframe * frame,const struct drm_connector_state * conn_state)1291bb76ff1Sjsg void drm_hdmi_avi_infoframe_colorimetry(struct hdmi_avi_infoframe *frame,
1301bb76ff1Sjsg 					const struct drm_connector_state *conn_state)
1311bb76ff1Sjsg {
1321bb76ff1Sjsg 	u32 colorimetry_val;
1331bb76ff1Sjsg 	u32 colorimetry_index = conn_state->colorspace & FULL_COLORIMETRY_MASK;
1341bb76ff1Sjsg 
1351bb76ff1Sjsg 	if (colorimetry_index >= ARRAY_SIZE(hdmi_colorimetry_val))
1361bb76ff1Sjsg 		colorimetry_val = HDMI_COLORIMETRY_NO_DATA;
1371bb76ff1Sjsg 	else
1381bb76ff1Sjsg 		colorimetry_val = hdmi_colorimetry_val[colorimetry_index];
1391bb76ff1Sjsg 
1401bb76ff1Sjsg 	frame->colorimetry = colorimetry_val & NORMAL_COLORIMETRY_MASK;
1411bb76ff1Sjsg 	/*
1421bb76ff1Sjsg 	 * ToDo: Extend it for ACE formats as well. Modify the infoframe
1431bb76ff1Sjsg 	 * structure and extend it in drivers/video/hdmi
1441bb76ff1Sjsg 	 */
1451bb76ff1Sjsg 	frame->extended_colorimetry = (colorimetry_val >> 2) &
1461bb76ff1Sjsg 					EXTENDED_COLORIMETRY_MASK;
1471bb76ff1Sjsg }
1481bb76ff1Sjsg EXPORT_SYMBOL(drm_hdmi_avi_infoframe_colorimetry);
1491bb76ff1Sjsg 
1501bb76ff1Sjsg /**
1511bb76ff1Sjsg  * drm_hdmi_avi_infoframe_bars() - fill the HDMI AVI infoframe
1521bb76ff1Sjsg  *                                 bar information
1531bb76ff1Sjsg  * @frame: HDMI AVI infoframe
1541bb76ff1Sjsg  * @conn_state: connector state
1551bb76ff1Sjsg  */
drm_hdmi_avi_infoframe_bars(struct hdmi_avi_infoframe * frame,const struct drm_connector_state * conn_state)1561bb76ff1Sjsg void drm_hdmi_avi_infoframe_bars(struct hdmi_avi_infoframe *frame,
1571bb76ff1Sjsg 				 const struct drm_connector_state *conn_state)
1581bb76ff1Sjsg {
1591bb76ff1Sjsg 	frame->right_bar = conn_state->tv.margins.right;
1601bb76ff1Sjsg 	frame->left_bar = conn_state->tv.margins.left;
1611bb76ff1Sjsg 	frame->top_bar = conn_state->tv.margins.top;
1621bb76ff1Sjsg 	frame->bottom_bar = conn_state->tv.margins.bottom;
1631bb76ff1Sjsg }
1641bb76ff1Sjsg EXPORT_SYMBOL(drm_hdmi_avi_infoframe_bars);
1651bb76ff1Sjsg 
1661bb76ff1Sjsg /**
1671bb76ff1Sjsg  * drm_hdmi_avi_infoframe_content_type() - fill the HDMI AVI infoframe
1681bb76ff1Sjsg  *                                         content type information, based
1691bb76ff1Sjsg  *                                         on correspondent DRM property.
1701bb76ff1Sjsg  * @frame: HDMI AVI infoframe
1711bb76ff1Sjsg  * @conn_state: DRM display connector state
1721bb76ff1Sjsg  *
1731bb76ff1Sjsg  */
drm_hdmi_avi_infoframe_content_type(struct hdmi_avi_infoframe * frame,const struct drm_connector_state * conn_state)1741bb76ff1Sjsg void drm_hdmi_avi_infoframe_content_type(struct hdmi_avi_infoframe *frame,
1751bb76ff1Sjsg 					 const struct drm_connector_state *conn_state)
1761bb76ff1Sjsg {
1771bb76ff1Sjsg 	switch (conn_state->content_type) {
1781bb76ff1Sjsg 	case DRM_MODE_CONTENT_TYPE_GRAPHICS:
1791bb76ff1Sjsg 		frame->content_type = HDMI_CONTENT_TYPE_GRAPHICS;
1801bb76ff1Sjsg 		break;
1811bb76ff1Sjsg 	case DRM_MODE_CONTENT_TYPE_CINEMA:
1821bb76ff1Sjsg 		frame->content_type = HDMI_CONTENT_TYPE_CINEMA;
1831bb76ff1Sjsg 		break;
1841bb76ff1Sjsg 	case DRM_MODE_CONTENT_TYPE_GAME:
1851bb76ff1Sjsg 		frame->content_type = HDMI_CONTENT_TYPE_GAME;
1861bb76ff1Sjsg 		break;
1871bb76ff1Sjsg 	case DRM_MODE_CONTENT_TYPE_PHOTO:
1881bb76ff1Sjsg 		frame->content_type = HDMI_CONTENT_TYPE_PHOTO;
1891bb76ff1Sjsg 		break;
1901bb76ff1Sjsg 	default:
1911bb76ff1Sjsg 		/* Graphics is the default(0) */
1921bb76ff1Sjsg 		frame->content_type = HDMI_CONTENT_TYPE_GRAPHICS;
1931bb76ff1Sjsg 	}
1941bb76ff1Sjsg 
1951bb76ff1Sjsg 	frame->itc = conn_state->content_type != DRM_MODE_CONTENT_TYPE_NO_DATA;
1961bb76ff1Sjsg }
1971bb76ff1Sjsg EXPORT_SYMBOL(drm_hdmi_avi_infoframe_content_type);
198