162306a36Sopenharmony_ci// SPDX-License-Identifier: MIT 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci#include <linux/module.h> 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <drm/display/drm_hdmi_helper.h> 662306a36Sopenharmony_ci#include <drm/drm_connector.h> 762306a36Sopenharmony_ci#include <drm/drm_edid.h> 862306a36Sopenharmony_ci#include <drm/drm_modes.h> 962306a36Sopenharmony_ci#include <drm/drm_print.h> 1062306a36Sopenharmony_ci#include <drm/drm_property.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_cistatic inline bool is_eotf_supported(u8 output_eotf, u8 sink_eotf) 1362306a36Sopenharmony_ci{ 1462306a36Sopenharmony_ci return sink_eotf & BIT(output_eotf); 1562306a36Sopenharmony_ci} 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/** 1862306a36Sopenharmony_ci * drm_hdmi_infoframe_set_hdr_metadata() - fill an HDMI DRM infoframe with 1962306a36Sopenharmony_ci * HDR metadata from userspace 2062306a36Sopenharmony_ci * @frame: HDMI DRM infoframe 2162306a36Sopenharmony_ci * @conn_state: Connector state containing HDR metadata 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * Return: 0 on success or a negative error code on failure. 2462306a36Sopenharmony_ci */ 2562306a36Sopenharmony_ciint drm_hdmi_infoframe_set_hdr_metadata(struct hdmi_drm_infoframe *frame, 2662306a36Sopenharmony_ci const struct drm_connector_state *conn_state) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci struct drm_connector *connector; 2962306a36Sopenharmony_ci struct hdr_output_metadata *hdr_metadata; 3062306a36Sopenharmony_ci int err; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci if (!frame || !conn_state) 3362306a36Sopenharmony_ci return -EINVAL; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci connector = conn_state->connector; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci if (!conn_state->hdr_output_metadata) 3862306a36Sopenharmony_ci return -EINVAL; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci hdr_metadata = conn_state->hdr_output_metadata->data; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci if (!hdr_metadata || !connector) 4362306a36Sopenharmony_ci return -EINVAL; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci /* Sink EOTF is Bit map while infoframe is absolute values */ 4662306a36Sopenharmony_ci if (!is_eotf_supported(hdr_metadata->hdmi_metadata_type1.eotf, 4762306a36Sopenharmony_ci connector->hdr_sink_metadata.hdmi_type1.eotf)) 4862306a36Sopenharmony_ci DRM_DEBUG_KMS("Unknown EOTF %d\n", hdr_metadata->hdmi_metadata_type1.eotf); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci err = hdmi_drm_infoframe_init(frame); 5162306a36Sopenharmony_ci if (err < 0) 5262306a36Sopenharmony_ci return err; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci frame->eotf = hdr_metadata->hdmi_metadata_type1.eotf; 5562306a36Sopenharmony_ci frame->metadata_type = hdr_metadata->hdmi_metadata_type1.metadata_type; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(frame->display_primaries) != 5862306a36Sopenharmony_ci sizeof(hdr_metadata->hdmi_metadata_type1.display_primaries)); 5962306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(frame->white_point) != 6062306a36Sopenharmony_ci sizeof(hdr_metadata->hdmi_metadata_type1.white_point)); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci memcpy(&frame->display_primaries, 6362306a36Sopenharmony_ci &hdr_metadata->hdmi_metadata_type1.display_primaries, 6462306a36Sopenharmony_ci sizeof(frame->display_primaries)); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci memcpy(&frame->white_point, 6762306a36Sopenharmony_ci &hdr_metadata->hdmi_metadata_type1.white_point, 6862306a36Sopenharmony_ci sizeof(frame->white_point)); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci frame->max_display_mastering_luminance = 7162306a36Sopenharmony_ci hdr_metadata->hdmi_metadata_type1.max_display_mastering_luminance; 7262306a36Sopenharmony_ci frame->min_display_mastering_luminance = 7362306a36Sopenharmony_ci hdr_metadata->hdmi_metadata_type1.min_display_mastering_luminance; 7462306a36Sopenharmony_ci frame->max_fall = hdr_metadata->hdmi_metadata_type1.max_fall; 7562306a36Sopenharmony_ci frame->max_cll = hdr_metadata->hdmi_metadata_type1.max_cll; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci return 0; 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ciEXPORT_SYMBOL(drm_hdmi_infoframe_set_hdr_metadata); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci/* HDMI Colorspace Spec Definitions */ 8262306a36Sopenharmony_ci#define FULL_COLORIMETRY_MASK 0x1FF 8362306a36Sopenharmony_ci#define NORMAL_COLORIMETRY_MASK 0x3 8462306a36Sopenharmony_ci#define EXTENDED_COLORIMETRY_MASK 0x7 8562306a36Sopenharmony_ci#define EXTENDED_ACE_COLORIMETRY_MASK 0xF 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci#define C(x) ((x) << 0) 8862306a36Sopenharmony_ci#define EC(x) ((x) << 2) 8962306a36Sopenharmony_ci#define ACE(x) ((x) << 5) 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci#define HDMI_COLORIMETRY_NO_DATA 0x0 9262306a36Sopenharmony_ci#define HDMI_COLORIMETRY_SMPTE_170M_YCC (C(1) | EC(0) | ACE(0)) 9362306a36Sopenharmony_ci#define HDMI_COLORIMETRY_BT709_YCC (C(2) | EC(0) | ACE(0)) 9462306a36Sopenharmony_ci#define HDMI_COLORIMETRY_XVYCC_601 (C(3) | EC(0) | ACE(0)) 9562306a36Sopenharmony_ci#define HDMI_COLORIMETRY_XVYCC_709 (C(3) | EC(1) | ACE(0)) 9662306a36Sopenharmony_ci#define HDMI_COLORIMETRY_SYCC_601 (C(3) | EC(2) | ACE(0)) 9762306a36Sopenharmony_ci#define HDMI_COLORIMETRY_OPYCC_601 (C(3) | EC(3) | ACE(0)) 9862306a36Sopenharmony_ci#define HDMI_COLORIMETRY_OPRGB (C(3) | EC(4) | ACE(0)) 9962306a36Sopenharmony_ci#define HDMI_COLORIMETRY_BT2020_CYCC (C(3) | EC(5) | ACE(0)) 10062306a36Sopenharmony_ci#define HDMI_COLORIMETRY_BT2020_RGB (C(3) | EC(6) | ACE(0)) 10162306a36Sopenharmony_ci#define HDMI_COLORIMETRY_BT2020_YCC (C(3) | EC(6) | ACE(0)) 10262306a36Sopenharmony_ci#define HDMI_COLORIMETRY_DCI_P3_RGB_D65 (C(3) | EC(7) | ACE(0)) 10362306a36Sopenharmony_ci#define HDMI_COLORIMETRY_DCI_P3_RGB_THEATER (C(3) | EC(7) | ACE(1)) 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic const u32 hdmi_colorimetry_val[] = { 10662306a36Sopenharmony_ci [DRM_MODE_COLORIMETRY_NO_DATA] = HDMI_COLORIMETRY_NO_DATA, 10762306a36Sopenharmony_ci [DRM_MODE_COLORIMETRY_SMPTE_170M_YCC] = HDMI_COLORIMETRY_SMPTE_170M_YCC, 10862306a36Sopenharmony_ci [DRM_MODE_COLORIMETRY_BT709_YCC] = HDMI_COLORIMETRY_BT709_YCC, 10962306a36Sopenharmony_ci [DRM_MODE_COLORIMETRY_XVYCC_601] = HDMI_COLORIMETRY_XVYCC_601, 11062306a36Sopenharmony_ci [DRM_MODE_COLORIMETRY_XVYCC_709] = HDMI_COLORIMETRY_XVYCC_709, 11162306a36Sopenharmony_ci [DRM_MODE_COLORIMETRY_SYCC_601] = HDMI_COLORIMETRY_SYCC_601, 11262306a36Sopenharmony_ci [DRM_MODE_COLORIMETRY_OPYCC_601] = HDMI_COLORIMETRY_OPYCC_601, 11362306a36Sopenharmony_ci [DRM_MODE_COLORIMETRY_OPRGB] = HDMI_COLORIMETRY_OPRGB, 11462306a36Sopenharmony_ci [DRM_MODE_COLORIMETRY_BT2020_CYCC] = HDMI_COLORIMETRY_BT2020_CYCC, 11562306a36Sopenharmony_ci [DRM_MODE_COLORIMETRY_BT2020_RGB] = HDMI_COLORIMETRY_BT2020_RGB, 11662306a36Sopenharmony_ci [DRM_MODE_COLORIMETRY_BT2020_YCC] = HDMI_COLORIMETRY_BT2020_YCC, 11762306a36Sopenharmony_ci}; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci#undef C 12062306a36Sopenharmony_ci#undef EC 12162306a36Sopenharmony_ci#undef ACE 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci/** 12462306a36Sopenharmony_ci * drm_hdmi_avi_infoframe_colorimetry() - fill the HDMI AVI infoframe 12562306a36Sopenharmony_ci * colorimetry information 12662306a36Sopenharmony_ci * @frame: HDMI AVI infoframe 12762306a36Sopenharmony_ci * @conn_state: connector state 12862306a36Sopenharmony_ci */ 12962306a36Sopenharmony_civoid drm_hdmi_avi_infoframe_colorimetry(struct hdmi_avi_infoframe *frame, 13062306a36Sopenharmony_ci const struct drm_connector_state *conn_state) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci u32 colorimetry_val; 13362306a36Sopenharmony_ci u32 colorimetry_index = conn_state->colorspace & FULL_COLORIMETRY_MASK; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci if (colorimetry_index >= ARRAY_SIZE(hdmi_colorimetry_val)) 13662306a36Sopenharmony_ci colorimetry_val = HDMI_COLORIMETRY_NO_DATA; 13762306a36Sopenharmony_ci else 13862306a36Sopenharmony_ci colorimetry_val = hdmi_colorimetry_val[colorimetry_index]; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci frame->colorimetry = colorimetry_val & NORMAL_COLORIMETRY_MASK; 14162306a36Sopenharmony_ci /* 14262306a36Sopenharmony_ci * ToDo: Extend it for ACE formats as well. Modify the infoframe 14362306a36Sopenharmony_ci * structure and extend it in drivers/video/hdmi 14462306a36Sopenharmony_ci */ 14562306a36Sopenharmony_ci frame->extended_colorimetry = (colorimetry_val >> 2) & 14662306a36Sopenharmony_ci EXTENDED_COLORIMETRY_MASK; 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ciEXPORT_SYMBOL(drm_hdmi_avi_infoframe_colorimetry); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci/** 15162306a36Sopenharmony_ci * drm_hdmi_avi_infoframe_bars() - fill the HDMI AVI infoframe 15262306a36Sopenharmony_ci * bar information 15362306a36Sopenharmony_ci * @frame: HDMI AVI infoframe 15462306a36Sopenharmony_ci * @conn_state: connector state 15562306a36Sopenharmony_ci */ 15662306a36Sopenharmony_civoid drm_hdmi_avi_infoframe_bars(struct hdmi_avi_infoframe *frame, 15762306a36Sopenharmony_ci const struct drm_connector_state *conn_state) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci frame->right_bar = conn_state->tv.margins.right; 16062306a36Sopenharmony_ci frame->left_bar = conn_state->tv.margins.left; 16162306a36Sopenharmony_ci frame->top_bar = conn_state->tv.margins.top; 16262306a36Sopenharmony_ci frame->bottom_bar = conn_state->tv.margins.bottom; 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ciEXPORT_SYMBOL(drm_hdmi_avi_infoframe_bars); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci/** 16762306a36Sopenharmony_ci * drm_hdmi_avi_infoframe_content_type() - fill the HDMI AVI infoframe 16862306a36Sopenharmony_ci * content type information, based 16962306a36Sopenharmony_ci * on correspondent DRM property. 17062306a36Sopenharmony_ci * @frame: HDMI AVI infoframe 17162306a36Sopenharmony_ci * @conn_state: DRM display connector state 17262306a36Sopenharmony_ci * 17362306a36Sopenharmony_ci */ 17462306a36Sopenharmony_civoid drm_hdmi_avi_infoframe_content_type(struct hdmi_avi_infoframe *frame, 17562306a36Sopenharmony_ci const struct drm_connector_state *conn_state) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci switch (conn_state->content_type) { 17862306a36Sopenharmony_ci case DRM_MODE_CONTENT_TYPE_GRAPHICS: 17962306a36Sopenharmony_ci frame->content_type = HDMI_CONTENT_TYPE_GRAPHICS; 18062306a36Sopenharmony_ci break; 18162306a36Sopenharmony_ci case DRM_MODE_CONTENT_TYPE_CINEMA: 18262306a36Sopenharmony_ci frame->content_type = HDMI_CONTENT_TYPE_CINEMA; 18362306a36Sopenharmony_ci break; 18462306a36Sopenharmony_ci case DRM_MODE_CONTENT_TYPE_GAME: 18562306a36Sopenharmony_ci frame->content_type = HDMI_CONTENT_TYPE_GAME; 18662306a36Sopenharmony_ci break; 18762306a36Sopenharmony_ci case DRM_MODE_CONTENT_TYPE_PHOTO: 18862306a36Sopenharmony_ci frame->content_type = HDMI_CONTENT_TYPE_PHOTO; 18962306a36Sopenharmony_ci break; 19062306a36Sopenharmony_ci default: 19162306a36Sopenharmony_ci /* Graphics is the default(0) */ 19262306a36Sopenharmony_ci frame->content_type = HDMI_CONTENT_TYPE_GRAPHICS; 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci frame->itc = conn_state->content_type != DRM_MODE_CONTENT_TYPE_NO_DATA; 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ciEXPORT_SYMBOL(drm_hdmi_avi_infoframe_content_type); 198