2
2
3
3
#include <drm/drm_atomic.h>
4
4
#include <drm/drm_connector.h>
5
+ #include <drm/drm_edid.h>
6
+ #include <drm/drm_print.h>
5
7
6
8
#include <drm/display/drm_hdmi_helper.h>
7
9
#include <drm/display/drm_hdmi_state_helper.h>
@@ -48,6 +50,126 @@ connector_state_get_mode(const struct drm_connector_state *conn_state)
48
50
return & crtc_state -> mode ;
49
51
}
50
52
53
+ static bool
54
+ sink_supports_format_bpc (const struct drm_connector * connector ,
55
+ const struct drm_display_info * info ,
56
+ const struct drm_display_mode * mode ,
57
+ unsigned int format , unsigned int bpc )
58
+ {
59
+ struct drm_device * dev = connector -> dev ;
60
+ u8 vic = drm_match_cea_mode (mode );
61
+
62
+ /*
63
+ * CTA-861-F, section 5.4 - Color Coding & Quantization states
64
+ * that the bpc must be 8, 10, 12 or 16 except for the default
65
+ * 640x480 VIC1 where the value must be 8.
66
+ *
67
+ * The definition of default here is ambiguous but the spec
68
+ * refers to VIC1 being the default timing in several occasions
69
+ * so our understanding is that for the default timing (ie,
70
+ * VIC1), the bpc must be 8.
71
+ */
72
+ if (vic == 1 && bpc != 8 ) {
73
+ drm_dbg_kms (dev , "VIC1 requires a bpc of 8, got %u\n" , bpc );
74
+ return false;
75
+ }
76
+
77
+ if (!info -> is_hdmi &&
78
+ (format != HDMI_COLORSPACE_RGB || bpc != 8 )) {
79
+ drm_dbg_kms (dev , "DVI Monitors require an RGB output at 8 bpc\n" );
80
+ return false;
81
+ }
82
+
83
+ if (!(connector -> hdmi .supported_formats & BIT (format ))) {
84
+ drm_dbg_kms (dev , "%s format unsupported by the connector.\n" ,
85
+ drm_hdmi_connector_get_output_format_name (format ));
86
+ return false;
87
+ }
88
+
89
+ switch (format ) {
90
+ case HDMI_COLORSPACE_RGB :
91
+ drm_dbg_kms (dev , "RGB Format, checking the constraints.\n" );
92
+
93
+ /*
94
+ * In some cases, like when the EDID readout fails, or
95
+ * is not an HDMI compliant EDID for some reason, the
96
+ * color_formats field will be blank and not report any
97
+ * format supported. In such a case, assume that RGB is
98
+ * supported so we can keep things going and light up
99
+ * the display.
100
+ */
101
+ if (!(info -> color_formats & DRM_COLOR_FORMAT_RGB444 ))
102
+ drm_warn (dev , "HDMI Sink doesn't support RGB, something's wrong.\n" );
103
+
104
+ if (bpc == 10 && !(info -> edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_30 )) {
105
+ drm_dbg_kms (dev , "10 BPC but sink doesn't support Deep Color 30.\n" );
106
+ return false;
107
+ }
108
+
109
+ if (bpc == 12 && !(info -> edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_36 )) {
110
+ drm_dbg_kms (dev , "12 BPC but sink doesn't support Deep Color 36.\n" );
111
+ return false;
112
+ }
113
+
114
+ drm_dbg_kms (dev , "RGB format supported in that configuration.\n" );
115
+
116
+ return true;
117
+
118
+ case HDMI_COLORSPACE_YUV420 :
119
+ /* TODO: YUV420 is unsupported at the moment. */
120
+ drm_dbg_kms (dev , "YUV420 format isn't supported yet.\n" );
121
+ return false;
122
+
123
+ case HDMI_COLORSPACE_YUV422 :
124
+ drm_dbg_kms (dev , "YUV422 format, checking the constraints.\n" );
125
+
126
+ if (!(info -> color_formats & DRM_COLOR_FORMAT_YCBCR422 )) {
127
+ drm_dbg_kms (dev , "Sink doesn't support YUV422.\n" );
128
+ return false;
129
+ }
130
+
131
+ if (bpc > 12 ) {
132
+ drm_dbg_kms (dev , "YUV422 only supports 12 bpc or lower.\n" );
133
+ return false;
134
+ }
135
+
136
+ /*
137
+ * HDMI Spec 1.3 - Section 6.5 Pixel Encodings and Color Depth
138
+ * states that Deep Color is not relevant for YUV422 so we
139
+ * don't need to check the Deep Color bits in the EDIDs here.
140
+ */
141
+
142
+ drm_dbg_kms (dev , "YUV422 format supported in that configuration.\n" );
143
+
144
+ return true;
145
+
146
+ case HDMI_COLORSPACE_YUV444 :
147
+ drm_dbg_kms (dev , "YUV444 format, checking the constraints.\n" );
148
+
149
+ if (!(info -> color_formats & DRM_COLOR_FORMAT_YCBCR444 )) {
150
+ drm_dbg_kms (dev , "Sink doesn't support YUV444.\n" );
151
+ return false;
152
+ }
153
+
154
+ if (bpc == 10 && !(info -> edid_hdmi_ycbcr444_dc_modes & DRM_EDID_HDMI_DC_30 )) {
155
+ drm_dbg_kms (dev , "10 BPC but sink doesn't support Deep Color 30.\n" );
156
+ return false;
157
+ }
158
+
159
+ if (bpc == 12 && !(info -> edid_hdmi_ycbcr444_dc_modes & DRM_EDID_HDMI_DC_36 )) {
160
+ drm_dbg_kms (dev , "12 BPC but sink doesn't support Deep Color 36.\n" );
161
+ return false;
162
+ }
163
+
164
+ drm_dbg_kms (dev , "YUV444 format supported in that configuration.\n" );
165
+
166
+ return true;
167
+ }
168
+
169
+ drm_dbg_kms (dev , "Unsupported pixel format.\n" );
170
+ return false;
171
+ }
172
+
51
173
static enum drm_mode_status
52
174
hdmi_clock_valid (const struct drm_connector * connector ,
53
175
const struct drm_display_mode * mode ,
@@ -92,6 +214,97 @@ hdmi_compute_clock(const struct drm_connector *connector,
92
214
return 0 ;
93
215
}
94
216
217
+ static bool
218
+ hdmi_try_format_bpc (const struct drm_connector * connector ,
219
+ struct drm_connector_state * conn_state ,
220
+ const struct drm_display_mode * mode ,
221
+ unsigned int bpc , enum hdmi_colorspace fmt )
222
+ {
223
+ const struct drm_display_info * info = & connector -> display_info ;
224
+ struct drm_device * dev = connector -> dev ;
225
+ int ret ;
226
+
227
+ drm_dbg_kms (dev , "Trying %s output format\n" ,
228
+ drm_hdmi_connector_get_output_format_name (fmt ));
229
+
230
+ if (!sink_supports_format_bpc (connector , info , mode , fmt , bpc )) {
231
+ drm_dbg_kms (dev , "%s output format not supported with %u bpc\n" ,
232
+ drm_hdmi_connector_get_output_format_name (fmt ),
233
+ bpc );
234
+ return false;
235
+ }
236
+
237
+ ret = hdmi_compute_clock (connector , conn_state , mode , bpc , fmt );
238
+ if (ret ) {
239
+ drm_dbg_kms (dev , "Couldn't compute clock for %s output format and %u bpc\n" ,
240
+ drm_hdmi_connector_get_output_format_name (fmt ),
241
+ bpc );
242
+ return false;
243
+ }
244
+
245
+ drm_dbg_kms (dev , "%s output format supported with %u (TMDS char rate: %llu Hz)\n" ,
246
+ drm_hdmi_connector_get_output_format_name (fmt ),
247
+ bpc , conn_state -> hdmi .tmds_char_rate );
248
+
249
+ return true;
250
+ }
251
+
252
+ static int
253
+ hdmi_compute_format (const struct drm_connector * connector ,
254
+ struct drm_connector_state * conn_state ,
255
+ const struct drm_display_mode * mode ,
256
+ unsigned int bpc )
257
+ {
258
+ struct drm_device * dev = connector -> dev ;
259
+
260
+ /*
261
+ * TODO: Add support for YCbCr420 output for HDMI 2.0 capable
262
+ * devices, for modes that only support YCbCr420.
263
+ */
264
+ if (hdmi_try_format_bpc (connector , conn_state , mode , bpc , HDMI_COLORSPACE_RGB )) {
265
+ conn_state -> hdmi .output_format = HDMI_COLORSPACE_RGB ;
266
+ return 0 ;
267
+ }
268
+
269
+ drm_dbg_kms (dev , "Failed. No Format Supported for that bpc count.\n" );
270
+
271
+ return - EINVAL ;
272
+ }
273
+
274
+ static int
275
+ hdmi_compute_config (const struct drm_connector * connector ,
276
+ struct drm_connector_state * conn_state ,
277
+ const struct drm_display_mode * mode )
278
+ {
279
+ struct drm_device * dev = connector -> dev ;
280
+ unsigned int max_bpc = clamp_t (unsigned int ,
281
+ conn_state -> max_bpc ,
282
+ 8 , connector -> max_bpc );
283
+ unsigned int bpc ;
284
+ int ret ;
285
+
286
+ for (bpc = max_bpc ; bpc >= 8 ; bpc -= 2 ) {
287
+ drm_dbg_kms (dev , "Trying with a %d bpc output\n" , bpc );
288
+
289
+ ret = hdmi_compute_format (connector , conn_state , mode , bpc );
290
+ if (ret )
291
+ continue ;
292
+
293
+ conn_state -> hdmi .output_bpc = bpc ;
294
+
295
+ drm_dbg_kms (dev ,
296
+ "Mode %ux%u @ %uHz: Found configuration: bpc: %u, fmt: %s, clock: %llu\n" ,
297
+ mode -> hdisplay , mode -> vdisplay , drm_mode_vrefresh (mode ),
298
+ conn_state -> hdmi .output_bpc ,
299
+ drm_hdmi_connector_get_output_format_name (conn_state -> hdmi .output_format ),
300
+ conn_state -> hdmi .tmds_char_rate );
301
+
302
+ return 0 ;
303
+ }
304
+
305
+ return - EINVAL ;
306
+ }
307
+
95
308
/**
96
309
* drm_atomic_helper_connector_hdmi_check() - Helper to check HDMI connector atomic state
97
310
* @connector: DRM Connector
@@ -115,9 +328,7 @@ int drm_atomic_helper_connector_hdmi_check(struct drm_connector *connector,
115
328
connector_state_get_mode (new_conn_state );
116
329
int ret ;
117
330
118
- ret = hdmi_compute_clock (connector , new_conn_state , mode ,
119
- new_conn_state -> hdmi .output_bpc ,
120
- new_conn_state -> hdmi .output_format );
331
+ ret = hdmi_compute_config (connector , new_conn_state , mode );
121
332
if (ret )
122
333
return ret ;
123
334
0 commit comments