drm_hdmi_helper.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. // SPDX-License-Identifier: MIT
  2. #include <linux/module.h>
  3. #include <drm/display/drm_hdmi_helper.h>
  4. #include <drm/drm_connector.h>
  5. #include <drm/drm_edid.h>
  6. #include <drm/drm_modes.h>
  7. #include <drm/drm_print.h>
  8. #include <drm/drm_property.h>
  9. static inline bool is_eotf_supported(u8 output_eotf, u8 sink_eotf)
  10. {
  11. return sink_eotf & BIT(output_eotf);
  12. }
  13. /**
  14. * drm_hdmi_infoframe_set_hdr_metadata() - fill an HDMI DRM infoframe with
  15. * HDR metadata from userspace
  16. * @frame: HDMI DRM infoframe
  17. * @conn_state: Connector state containing HDR metadata
  18. *
  19. * Return: 0 on success or a negative error code on failure.
  20. */
  21. int drm_hdmi_infoframe_set_hdr_metadata(struct hdmi_drm_infoframe *frame,
  22. const struct drm_connector_state *conn_state)
  23. {
  24. struct drm_connector *connector;
  25. struct hdr_output_metadata *hdr_metadata;
  26. int err;
  27. if (!frame || !conn_state)
  28. return -EINVAL;
  29. connector = conn_state->connector;
  30. if (!conn_state->hdr_output_metadata)
  31. return -EINVAL;
  32. hdr_metadata = conn_state->hdr_output_metadata->data;
  33. if (!hdr_metadata || !connector)
  34. return -EINVAL;
  35. /* Sink EOTF is Bit map while infoframe is absolute values */
  36. if (!is_eotf_supported(hdr_metadata->hdmi_metadata_type1.eotf,
  37. connector->hdr_sink_metadata.hdmi_type1.eotf))
  38. DRM_DEBUG_KMS("Unknown EOTF %d\n", hdr_metadata->hdmi_metadata_type1.eotf);
  39. err = hdmi_drm_infoframe_init(frame);
  40. if (err < 0)
  41. return err;
  42. frame->eotf = hdr_metadata->hdmi_metadata_type1.eotf;
  43. frame->metadata_type = hdr_metadata->hdmi_metadata_type1.metadata_type;
  44. BUILD_BUG_ON(sizeof(frame->display_primaries) !=
  45. sizeof(hdr_metadata->hdmi_metadata_type1.display_primaries));
  46. BUILD_BUG_ON(sizeof(frame->white_point) !=
  47. sizeof(hdr_metadata->hdmi_metadata_type1.white_point));
  48. memcpy(&frame->display_primaries,
  49. &hdr_metadata->hdmi_metadata_type1.display_primaries,
  50. sizeof(frame->display_primaries));
  51. memcpy(&frame->white_point,
  52. &hdr_metadata->hdmi_metadata_type1.white_point,
  53. sizeof(frame->white_point));
  54. frame->max_display_mastering_luminance =
  55. hdr_metadata->hdmi_metadata_type1.max_display_mastering_luminance;
  56. frame->min_display_mastering_luminance =
  57. hdr_metadata->hdmi_metadata_type1.min_display_mastering_luminance;
  58. frame->max_fall = hdr_metadata->hdmi_metadata_type1.max_fall;
  59. frame->max_cll = hdr_metadata->hdmi_metadata_type1.max_cll;
  60. return 0;
  61. }
  62. EXPORT_SYMBOL(drm_hdmi_infoframe_set_hdr_metadata);
  63. /* HDMI Colorspace Spec Definitions */
  64. #define FULL_COLORIMETRY_MASK 0x1FF
  65. #define NORMAL_COLORIMETRY_MASK 0x3
  66. #define EXTENDED_COLORIMETRY_MASK 0x7
  67. #define EXTENDED_ACE_COLORIMETRY_MASK 0xF
  68. #define C(x) ((x) << 0)
  69. #define EC(x) ((x) << 2)
  70. #define ACE(x) ((x) << 5)
  71. #define HDMI_COLORIMETRY_NO_DATA 0x0
  72. #define HDMI_COLORIMETRY_SMPTE_170M_YCC (C(1) | EC(0) | ACE(0))
  73. #define HDMI_COLORIMETRY_BT709_YCC (C(2) | EC(0) | ACE(0))
  74. #define HDMI_COLORIMETRY_XVYCC_601 (C(3) | EC(0) | ACE(0))
  75. #define HDMI_COLORIMETRY_XVYCC_709 (C(3) | EC(1) | ACE(0))
  76. #define HDMI_COLORIMETRY_SYCC_601 (C(3) | EC(2) | ACE(0))
  77. #define HDMI_COLORIMETRY_OPYCC_601 (C(3) | EC(3) | ACE(0))
  78. #define HDMI_COLORIMETRY_OPRGB (C(3) | EC(4) | ACE(0))
  79. #define HDMI_COLORIMETRY_BT2020_CYCC (C(3) | EC(5) | ACE(0))
  80. #define HDMI_COLORIMETRY_BT2020_RGB (C(3) | EC(6) | ACE(0))
  81. #define HDMI_COLORIMETRY_BT2020_YCC (C(3) | EC(6) | ACE(0))
  82. #define HDMI_COLORIMETRY_DCI_P3_RGB_D65 (C(3) | EC(7) | ACE(0))
  83. #define HDMI_COLORIMETRY_DCI_P3_RGB_THEATER (C(3) | EC(7) | ACE(1))
  84. static const u32 hdmi_colorimetry_val[] = {
  85. [DRM_MODE_COLORIMETRY_NO_DATA] = HDMI_COLORIMETRY_NO_DATA,
  86. [DRM_MODE_COLORIMETRY_SMPTE_170M_YCC] = HDMI_COLORIMETRY_SMPTE_170M_YCC,
  87. [DRM_MODE_COLORIMETRY_BT709_YCC] = HDMI_COLORIMETRY_BT709_YCC,
  88. [DRM_MODE_COLORIMETRY_XVYCC_601] = HDMI_COLORIMETRY_XVYCC_601,
  89. [DRM_MODE_COLORIMETRY_XVYCC_709] = HDMI_COLORIMETRY_XVYCC_709,
  90. [DRM_MODE_COLORIMETRY_SYCC_601] = HDMI_COLORIMETRY_SYCC_601,
  91. [DRM_MODE_COLORIMETRY_OPYCC_601] = HDMI_COLORIMETRY_OPYCC_601,
  92. [DRM_MODE_COLORIMETRY_OPRGB] = HDMI_COLORIMETRY_OPRGB,
  93. [DRM_MODE_COLORIMETRY_BT2020_CYCC] = HDMI_COLORIMETRY_BT2020_CYCC,
  94. [DRM_MODE_COLORIMETRY_BT2020_RGB] = HDMI_COLORIMETRY_BT2020_RGB,
  95. [DRM_MODE_COLORIMETRY_BT2020_YCC] = HDMI_COLORIMETRY_BT2020_YCC,
  96. };
  97. #undef C
  98. #undef EC
  99. #undef ACE
  100. /**
  101. * drm_hdmi_avi_infoframe_colorimetry() - fill the HDMI AVI infoframe
  102. * colorimetry information
  103. * @frame: HDMI AVI infoframe
  104. * @conn_state: connector state
  105. */
  106. void drm_hdmi_avi_infoframe_colorimetry(struct hdmi_avi_infoframe *frame,
  107. const struct drm_connector_state *conn_state)
  108. {
  109. u32 colorimetry_val;
  110. u32 colorimetry_index = conn_state->colorspace & FULL_COLORIMETRY_MASK;
  111. if (colorimetry_index >= ARRAY_SIZE(hdmi_colorimetry_val))
  112. colorimetry_val = HDMI_COLORIMETRY_NO_DATA;
  113. else
  114. colorimetry_val = hdmi_colorimetry_val[colorimetry_index];
  115. frame->colorimetry = colorimetry_val & NORMAL_COLORIMETRY_MASK;
  116. /*
  117. * ToDo: Extend it for ACE formats as well. Modify the infoframe
  118. * structure and extend it in drivers/video/hdmi
  119. */
  120. frame->extended_colorimetry = (colorimetry_val >> 2) &
  121. EXTENDED_COLORIMETRY_MASK;
  122. }
  123. EXPORT_SYMBOL(drm_hdmi_avi_infoframe_colorimetry);
  124. /**
  125. * drm_hdmi_avi_infoframe_bars() - fill the HDMI AVI infoframe
  126. * bar information
  127. * @frame: HDMI AVI infoframe
  128. * @conn_state: connector state
  129. */
  130. void drm_hdmi_avi_infoframe_bars(struct hdmi_avi_infoframe *frame,
  131. const struct drm_connector_state *conn_state)
  132. {
  133. frame->right_bar = conn_state->tv.margins.right;
  134. frame->left_bar = conn_state->tv.margins.left;
  135. frame->top_bar = conn_state->tv.margins.top;
  136. frame->bottom_bar = conn_state->tv.margins.bottom;
  137. }
  138. EXPORT_SYMBOL(drm_hdmi_avi_infoframe_bars);
  139. /**
  140. * drm_hdmi_avi_infoframe_content_type() - fill the HDMI AVI infoframe
  141. * content type information, based
  142. * on correspondent DRM property.
  143. * @frame: HDMI AVI infoframe
  144. * @conn_state: DRM display connector state
  145. *
  146. */
  147. void drm_hdmi_avi_infoframe_content_type(struct hdmi_avi_infoframe *frame,
  148. const struct drm_connector_state *conn_state)
  149. {
  150. switch (conn_state->content_type) {
  151. case DRM_MODE_CONTENT_TYPE_GRAPHICS:
  152. frame->content_type = HDMI_CONTENT_TYPE_GRAPHICS;
  153. break;
  154. case DRM_MODE_CONTENT_TYPE_CINEMA:
  155. frame->content_type = HDMI_CONTENT_TYPE_CINEMA;
  156. break;
  157. case DRM_MODE_CONTENT_TYPE_GAME:
  158. frame->content_type = HDMI_CONTENT_TYPE_GAME;
  159. break;
  160. case DRM_MODE_CONTENT_TYPE_PHOTO:
  161. frame->content_type = HDMI_CONTENT_TYPE_PHOTO;
  162. break;
  163. default:
  164. /* Graphics is the default(0) */
  165. frame->content_type = HDMI_CONTENT_TYPE_GRAPHICS;
  166. }
  167. frame->itc = conn_state->content_type != DRM_MODE_CONTENT_TYPE_NO_DATA;
  168. }
  169. EXPORT_SYMBOL(drm_hdmi_avi_infoframe_content_type);
  170. /**
  171. * drm_hdmi_compute_mode_clock() - Computes the TMDS Character Rate
  172. * @mode: Display mode to compute the clock for
  173. * @bpc: Bits per character
  174. * @fmt: Output Pixel Format used
  175. *
  176. * Returns the TMDS Character Rate for a given mode, bpc count and output format.
  177. *
  178. * RETURNS:
  179. * The TMDS Character Rate, in Hertz, or 0 on error.
  180. */
  181. unsigned long long
  182. drm_hdmi_compute_mode_clock(const struct drm_display_mode *mode,
  183. unsigned int bpc, enum hdmi_colorspace fmt)
  184. {
  185. unsigned long long clock = mode->clock * 1000ULL;
  186. unsigned int vic = drm_match_cea_mode(mode);
  187. /*
  188. * CTA-861-G Spec, section 5.4 - Color Coding and Quantization
  189. * mandates that VIC 1 always uses 8 bpc.
  190. */
  191. if (vic == 1 && bpc != 8)
  192. return 0;
  193. if (fmt == HDMI_COLORSPACE_YUV422) {
  194. /*
  195. * HDMI 1.0 Spec, section 6.5 - Pixel Encoding states that
  196. * YUV422 sends 24 bits over three channels, with Cb and Cr
  197. * components being sent on odd and even pixels, respectively.
  198. *
  199. * If fewer than 12 bpc are sent, data are left justified.
  200. */
  201. if (bpc > 12)
  202. return 0;
  203. /*
  204. * HDMI 1.0 Spec, section 6.5 - Pixel Encoding
  205. * specifies that YUV422 sends two 12-bits components over
  206. * three TMDS channels per pixel clock, which is equivalent to
  207. * three 8-bits components over three channels used by RGB as
  208. * far as the clock rate goes.
  209. */
  210. bpc = 8;
  211. }
  212. /*
  213. * HDMI 2.0 Spec, Section 7.1 - YCbCr 4:2:0 Pixel Encoding
  214. * specifies that YUV420 encoding is carried at a TMDS Character Rate
  215. * equal to half the pixel clock rate.
  216. */
  217. if (fmt == HDMI_COLORSPACE_YUV420)
  218. clock = clock / 2;
  219. if (mode->flags & DRM_MODE_FLAG_DBLCLK)
  220. clock = clock * 2;
  221. return DIV_ROUND_CLOSEST_ULL(clock * bpc, 8);
  222. }
  223. EXPORT_SYMBOL(drm_hdmi_compute_mode_clock);