1 | // SPDX-License-Identifier: MIT |
2 | |
3 | #include <linux/module.h> |
4 | |
5 | #include <drm/display/drm_hdmi_helper.h> |
6 | #include <drm/drm_connector.h> |
7 | #include <drm/drm_edid.h> |
8 | #include <drm/drm_modes.h> |
9 | #include <drm/drm_print.h> |
10 | #include <drm/drm_property.h> |
11 | |
12 | static inline bool is_eotf_supported(u8 output_eotf, u8 sink_eotf) |
13 | { |
14 | return sink_eotf & BIT(output_eotf); |
15 | } |
16 | |
17 | /** |
18 | * drm_hdmi_infoframe_set_hdr_metadata() - fill an HDMI DRM infoframe with |
19 | * HDR metadata from userspace |
20 | * @frame: HDMI DRM infoframe |
21 | * @conn_state: Connector state containing HDR metadata |
22 | * |
23 | * Return: 0 on success or a negative error code on failure. |
24 | */ |
25 | int drm_hdmi_infoframe_set_hdr_metadata(struct hdmi_drm_infoframe *frame, |
26 | const struct drm_connector_state *conn_state) |
27 | { |
28 | struct drm_connector *connector; |
29 | struct hdr_output_metadata *hdr_metadata; |
30 | int err; |
31 | |
32 | if (!frame || !conn_state) |
33 | return -EINVAL; |
34 | |
35 | connector = conn_state->connector; |
36 | |
37 | if (!conn_state->hdr_output_metadata) |
38 | return -EINVAL; |
39 | |
40 | hdr_metadata = conn_state->hdr_output_metadata->data; |
41 | |
42 | if (!hdr_metadata || !connector) |
43 | return -EINVAL; |
44 | |
45 | /* Sink EOTF is Bit map while infoframe is absolute values */ |
46 | if (!is_eotf_supported(output_eotf: hdr_metadata->hdmi_metadata_type1.eotf, |
47 | sink_eotf: connector->hdr_sink_metadata.hdmi_type1.eotf)) |
48 | DRM_DEBUG_KMS("Unknown EOTF %d\n" , hdr_metadata->hdmi_metadata_type1.eotf); |
49 | |
50 | err = hdmi_drm_infoframe_init(frame); |
51 | if (err < 0) |
52 | return err; |
53 | |
54 | frame->eotf = hdr_metadata->hdmi_metadata_type1.eotf; |
55 | frame->metadata_type = hdr_metadata->hdmi_metadata_type1.metadata_type; |
56 | |
57 | BUILD_BUG_ON(sizeof(frame->display_primaries) != |
58 | sizeof(hdr_metadata->hdmi_metadata_type1.display_primaries)); |
59 | BUILD_BUG_ON(sizeof(frame->white_point) != |
60 | sizeof(hdr_metadata->hdmi_metadata_type1.white_point)); |
61 | |
62 | memcpy(&frame->display_primaries, |
63 | &hdr_metadata->hdmi_metadata_type1.display_primaries, |
64 | sizeof(frame->display_primaries)); |
65 | |
66 | memcpy(&frame->white_point, |
67 | &hdr_metadata->hdmi_metadata_type1.white_point, |
68 | sizeof(frame->white_point)); |
69 | |
70 | frame->max_display_mastering_luminance = |
71 | hdr_metadata->hdmi_metadata_type1.max_display_mastering_luminance; |
72 | frame->min_display_mastering_luminance = |
73 | hdr_metadata->hdmi_metadata_type1.min_display_mastering_luminance; |
74 | frame->max_fall = hdr_metadata->hdmi_metadata_type1.max_fall; |
75 | frame->max_cll = hdr_metadata->hdmi_metadata_type1.max_cll; |
76 | |
77 | return 0; |
78 | } |
79 | EXPORT_SYMBOL(drm_hdmi_infoframe_set_hdr_metadata); |
80 | |
81 | /* HDMI Colorspace Spec Definitions */ |
82 | #define FULL_COLORIMETRY_MASK 0x1FF |
83 | #define NORMAL_COLORIMETRY_MASK 0x3 |
84 | #define EXTENDED_COLORIMETRY_MASK 0x7 |
85 | #define EXTENDED_ACE_COLORIMETRY_MASK 0xF |
86 | |
87 | #define C(x) ((x) << 0) |
88 | #define EC(x) ((x) << 2) |
89 | #define ACE(x) ((x) << 5) |
90 | |
91 | #define HDMI_COLORIMETRY_NO_DATA 0x0 |
92 | #define HDMI_COLORIMETRY_SMPTE_170M_YCC (C(1) | EC(0) | ACE(0)) |
93 | #define HDMI_COLORIMETRY_BT709_YCC (C(2) | EC(0) | ACE(0)) |
94 | #define HDMI_COLORIMETRY_XVYCC_601 (C(3) | EC(0) | ACE(0)) |
95 | #define HDMI_COLORIMETRY_XVYCC_709 (C(3) | EC(1) | ACE(0)) |
96 | #define HDMI_COLORIMETRY_SYCC_601 (C(3) | EC(2) | ACE(0)) |
97 | #define HDMI_COLORIMETRY_OPYCC_601 (C(3) | EC(3) | ACE(0)) |
98 | #define HDMI_COLORIMETRY_OPRGB (C(3) | EC(4) | ACE(0)) |
99 | #define HDMI_COLORIMETRY_BT2020_CYCC (C(3) | EC(5) | ACE(0)) |
100 | #define HDMI_COLORIMETRY_BT2020_RGB (C(3) | EC(6) | ACE(0)) |
101 | #define HDMI_COLORIMETRY_BT2020_YCC (C(3) | EC(6) | ACE(0)) |
102 | #define HDMI_COLORIMETRY_DCI_P3_RGB_D65 (C(3) | EC(7) | ACE(0)) |
103 | #define HDMI_COLORIMETRY_DCI_P3_RGB_THEATER (C(3) | EC(7) | ACE(1)) |
104 | |
105 | static const u32 hdmi_colorimetry_val[] = { |
106 | [DRM_MODE_COLORIMETRY_NO_DATA] = HDMI_COLORIMETRY_NO_DATA, |
107 | [DRM_MODE_COLORIMETRY_SMPTE_170M_YCC] = HDMI_COLORIMETRY_SMPTE_170M_YCC, |
108 | [DRM_MODE_COLORIMETRY_BT709_YCC] = HDMI_COLORIMETRY_BT709_YCC, |
109 | [DRM_MODE_COLORIMETRY_XVYCC_601] = HDMI_COLORIMETRY_XVYCC_601, |
110 | [DRM_MODE_COLORIMETRY_XVYCC_709] = HDMI_COLORIMETRY_XVYCC_709, |
111 | [DRM_MODE_COLORIMETRY_SYCC_601] = HDMI_COLORIMETRY_SYCC_601, |
112 | [DRM_MODE_COLORIMETRY_OPYCC_601] = HDMI_COLORIMETRY_OPYCC_601, |
113 | [DRM_MODE_COLORIMETRY_OPRGB] = HDMI_COLORIMETRY_OPRGB, |
114 | [DRM_MODE_COLORIMETRY_BT2020_CYCC] = HDMI_COLORIMETRY_BT2020_CYCC, |
115 | [DRM_MODE_COLORIMETRY_BT2020_RGB] = HDMI_COLORIMETRY_BT2020_RGB, |
116 | [DRM_MODE_COLORIMETRY_BT2020_YCC] = HDMI_COLORIMETRY_BT2020_YCC, |
117 | }; |
118 | |
119 | #undef C |
120 | #undef EC |
121 | #undef ACE |
122 | |
123 | /** |
124 | * drm_hdmi_avi_infoframe_colorimetry() - fill the HDMI AVI infoframe |
125 | * colorimetry information |
126 | * @frame: HDMI AVI infoframe |
127 | * @conn_state: connector state |
128 | */ |
129 | void drm_hdmi_avi_infoframe_colorimetry(struct hdmi_avi_infoframe *frame, |
130 | const struct drm_connector_state *conn_state) |
131 | { |
132 | u32 colorimetry_val; |
133 | u32 colorimetry_index = conn_state->colorspace & FULL_COLORIMETRY_MASK; |
134 | |
135 | if (colorimetry_index >= ARRAY_SIZE(hdmi_colorimetry_val)) |
136 | colorimetry_val = HDMI_COLORIMETRY_NO_DATA; |
137 | else |
138 | colorimetry_val = hdmi_colorimetry_val[colorimetry_index]; |
139 | |
140 | frame->colorimetry = colorimetry_val & NORMAL_COLORIMETRY_MASK; |
141 | /* |
142 | * ToDo: Extend it for ACE formats as well. Modify the infoframe |
143 | * structure and extend it in drivers/video/hdmi |
144 | */ |
145 | frame->extended_colorimetry = (colorimetry_val >> 2) & |
146 | EXTENDED_COLORIMETRY_MASK; |
147 | } |
148 | EXPORT_SYMBOL(drm_hdmi_avi_infoframe_colorimetry); |
149 | |
150 | /** |
151 | * drm_hdmi_avi_infoframe_bars() - fill the HDMI AVI infoframe |
152 | * bar information |
153 | * @frame: HDMI AVI infoframe |
154 | * @conn_state: connector state |
155 | */ |
156 | void drm_hdmi_avi_infoframe_bars(struct hdmi_avi_infoframe *frame, |
157 | const struct drm_connector_state *conn_state) |
158 | { |
159 | frame->right_bar = conn_state->tv.margins.right; |
160 | frame->left_bar = conn_state->tv.margins.left; |
161 | frame->top_bar = conn_state->tv.margins.top; |
162 | frame->bottom_bar = conn_state->tv.margins.bottom; |
163 | } |
164 | EXPORT_SYMBOL(drm_hdmi_avi_infoframe_bars); |
165 | |
166 | /** |
167 | * drm_hdmi_avi_infoframe_content_type() - fill the HDMI AVI infoframe |
168 | * content type information, based |
169 | * on correspondent DRM property. |
170 | * @frame: HDMI AVI infoframe |
171 | * @conn_state: DRM display connector state |
172 | * |
173 | */ |
174 | void drm_hdmi_avi_infoframe_content_type(struct hdmi_avi_infoframe *frame, |
175 | const struct drm_connector_state *conn_state) |
176 | { |
177 | switch (conn_state->content_type) { |
178 | case DRM_MODE_CONTENT_TYPE_GRAPHICS: |
179 | frame->content_type = HDMI_CONTENT_TYPE_GRAPHICS; |
180 | break; |
181 | case DRM_MODE_CONTENT_TYPE_CINEMA: |
182 | frame->content_type = HDMI_CONTENT_TYPE_CINEMA; |
183 | break; |
184 | case DRM_MODE_CONTENT_TYPE_GAME: |
185 | frame->content_type = HDMI_CONTENT_TYPE_GAME; |
186 | break; |
187 | case DRM_MODE_CONTENT_TYPE_PHOTO: |
188 | frame->content_type = HDMI_CONTENT_TYPE_PHOTO; |
189 | break; |
190 | default: |
191 | /* Graphics is the default(0) */ |
192 | frame->content_type = HDMI_CONTENT_TYPE_GRAPHICS; |
193 | } |
194 | |
195 | frame->itc = conn_state->content_type != DRM_MODE_CONTENT_TYPE_NO_DATA; |
196 | } |
197 | EXPORT_SYMBOL(drm_hdmi_avi_infoframe_content_type); |
198 | |