1 // SPDX-License-Identifier: GPL-2.0
2
3 /*
4 * Kunit test for drm_hdmi_state_helper functions
5 */
6
7 #include <drm/drm_atomic.h>
8 #include <drm/drm_atomic_state_helper.h>
9 #include <drm/drm_atomic_uapi.h>
10 #include <drm/drm_drv.h>
11 #include <drm/drm_edid.h>
12 #include <drm/drm_connector.h>
13 #include <drm/drm_fourcc.h>
14 #include <drm/drm_kunit_helpers.h>
15 #include <drm/drm_managed.h>
16 #include <drm/drm_modeset_helper_vtables.h>
17 #include <drm/drm_print.h>
18 #include <drm/drm_probe_helper.h>
19
20 #include <drm/display/drm_hdmi_helper.h>
21 #include <drm/display/drm_hdmi_state_helper.h>
22
23 #include "../drm_crtc_internal.h"
24
25 #include <kunit/test.h>
26
27 #include "drm_kunit_edid.h"
28
29 struct drm_atomic_helper_connector_hdmi_priv {
30 struct drm_device drm;
31 struct drm_plane *plane;
32 struct drm_crtc *crtc;
33 struct drm_encoder encoder;
34 struct drm_connector connector;
35
36 const void *current_edid;
37 size_t current_edid_len;
38
39 int hdmi_update_failures;
40 };
41
42 #define connector_to_priv(c) \
43 container_of_const(c, struct drm_atomic_helper_connector_hdmi_priv, connector)
44
45 #define encoder_to_priv(e) \
46 container_of_const(e, struct drm_atomic_helper_connector_hdmi_priv, encoder)
47
find_preferred_mode(struct drm_connector * connector)48 static struct drm_display_mode *find_preferred_mode(struct drm_connector *connector)
49 {
50 struct drm_device *drm = connector->dev;
51 struct drm_display_mode *mode, *preferred;
52
53 mutex_lock(&drm->mode_config.mutex);
54 preferred = list_first_entry_or_null(&connector->modes, struct drm_display_mode, head);
55 list_for_each_entry(mode, &connector->modes, head)
56 if (mode->type & DRM_MODE_TYPE_PREFERRED)
57 preferred = mode;
58 mutex_unlock(&drm->mode_config.mutex);
59
60 return preferred;
61 }
62
set_connector_edid(struct kunit * test,struct drm_connector * connector,const void * edid,size_t edid_len)63 static int set_connector_edid(struct kunit *test, struct drm_connector *connector,
64 const void *edid, size_t edid_len)
65 {
66 struct drm_atomic_helper_connector_hdmi_priv *priv =
67 connector_to_priv(connector);
68 struct drm_device *drm = connector->dev;
69 int ret;
70
71 priv->current_edid = edid;
72 priv->current_edid_len = edid_len;
73
74 mutex_lock(&drm->mode_config.mutex);
75 ret = connector->funcs->fill_modes(connector, 4096, 4096);
76 mutex_unlock(&drm->mode_config.mutex);
77
78 return ret;
79 }
80
accept_infoframe_clear_infoframe(struct drm_connector * connector)81 static int accept_infoframe_clear_infoframe(struct drm_connector *connector)
82 {
83 return 0;
84 }
85
accept_infoframe_write_infoframe(struct drm_connector * connector,const u8 * buffer,size_t len)86 static int accept_infoframe_write_infoframe(struct drm_connector *connector,
87 const u8 *buffer, size_t len)
88 {
89 return 0;
90 }
91
92 static const struct drm_connector_hdmi_funcs dummy_connector_hdmi_funcs = {
93 .avi = {
94 .clear_infoframe = accept_infoframe_clear_infoframe,
95 .write_infoframe = accept_infoframe_write_infoframe,
96 },
97 .hdmi = {
98 .clear_infoframe = accept_infoframe_clear_infoframe,
99 .write_infoframe = accept_infoframe_write_infoframe,
100 },
101 };
102
103 static enum drm_mode_status
reject_connector_tmds_char_rate_valid(const struct drm_connector * connector,const struct drm_display_mode * mode,unsigned long long tmds_rate)104 reject_connector_tmds_char_rate_valid(const struct drm_connector *connector,
105 const struct drm_display_mode *mode,
106 unsigned long long tmds_rate)
107 {
108 return MODE_BAD;
109 }
110
111 static const struct drm_connector_hdmi_funcs reject_connector_hdmi_funcs = {
112 .tmds_char_rate_valid = reject_connector_tmds_char_rate_valid,
113 .avi = {
114 .clear_infoframe = accept_infoframe_clear_infoframe,
115 .write_infoframe = accept_infoframe_write_infoframe,
116 },
117 .hdmi = {
118 .clear_infoframe = accept_infoframe_clear_infoframe,
119 .write_infoframe = accept_infoframe_write_infoframe,
120 },
121 };
122
123 static enum drm_mode_status
reject_100mhz_connector_tmds_char_rate_valid(const struct drm_connector * connector,const struct drm_display_mode * mode,unsigned long long tmds_rate)124 reject_100mhz_connector_tmds_char_rate_valid(const struct drm_connector *connector,
125 const struct drm_display_mode *mode,
126 unsigned long long tmds_rate)
127 {
128 return (tmds_rate > 100ULL * 1000 * 1000) ? MODE_BAD : MODE_OK;
129 }
130
131 static const struct drm_connector_hdmi_funcs reject_100mhz_connector_hdmi_funcs = {
132 .tmds_char_rate_valid = reject_100mhz_connector_tmds_char_rate_valid,
133 .avi = {
134 .clear_infoframe = accept_infoframe_clear_infoframe,
135 .write_infoframe = accept_infoframe_write_infoframe,
136 },
137 .hdmi = {
138 .clear_infoframe = accept_infoframe_clear_infoframe,
139 .write_infoframe = accept_infoframe_write_infoframe,
140 },
141 };
142
dummy_connector_get_modes(struct drm_connector * connector)143 static int dummy_connector_get_modes(struct drm_connector *connector)
144 {
145 struct drm_atomic_helper_connector_hdmi_priv *priv =
146 connector_to_priv(connector);
147 const struct drm_edid *edid;
148 unsigned int num_modes;
149
150 edid = drm_edid_alloc(priv->current_edid, priv->current_edid_len);
151 if (!edid)
152 return -EINVAL;
153
154 drm_edid_connector_update(connector, edid);
155 num_modes = drm_edid_connector_add_modes(connector);
156
157 drm_edid_free(edid);
158
159 return num_modes;
160 }
161
162 static const struct drm_connector_helper_funcs dummy_connector_helper_funcs = {
163 .atomic_check = drm_atomic_helper_connector_hdmi_check,
164 .get_modes = dummy_connector_get_modes,
165 .mode_valid = drm_hdmi_connector_mode_valid,
166 };
167
dummy_hdmi_connector_reset(struct drm_connector * connector)168 static void dummy_hdmi_connector_reset(struct drm_connector *connector)
169 {
170 drm_atomic_helper_connector_reset(connector);
171 __drm_atomic_helper_connector_hdmi_reset(connector, connector->state);
172 }
173
174 static const struct drm_connector_funcs dummy_connector_funcs = {
175 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
176 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
177 .fill_modes = drm_helper_probe_single_connector_modes,
178 .reset = dummy_hdmi_connector_reset,
179 };
180
test_encoder_atomic_enable(struct drm_encoder * encoder,struct drm_atomic_state * state)181 static void test_encoder_atomic_enable(struct drm_encoder *encoder,
182 struct drm_atomic_state *state)
183 {
184 struct drm_atomic_helper_connector_hdmi_priv *priv =
185 encoder_to_priv(encoder);
186 int ret;
187
188 ret = drm_atomic_helper_connector_hdmi_update_infoframes(&priv->connector, state);
189 if (ret)
190 priv->hdmi_update_failures++;
191 }
192
193 static const struct drm_encoder_helper_funcs test_encoder_helper_funcs = {
194 .atomic_enable = test_encoder_atomic_enable,
195 };
196
197 static
198 struct drm_atomic_helper_connector_hdmi_priv *
__connector_hdmi_init(struct kunit * test,unsigned int formats,unsigned int max_bpc,const struct drm_connector_hdmi_funcs * hdmi_funcs,const void * edid_data,size_t edid_len)199 __connector_hdmi_init(struct kunit *test,
200 unsigned int formats,
201 unsigned int max_bpc,
202 const struct drm_connector_hdmi_funcs *hdmi_funcs,
203 const void *edid_data, size_t edid_len)
204 {
205 struct drm_atomic_helper_connector_hdmi_priv *priv;
206 struct drm_connector *conn;
207 struct drm_encoder *enc;
208 struct drm_device *drm;
209 struct device *dev;
210 int ret;
211
212 dev = drm_kunit_helper_alloc_device(test);
213 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
214
215 priv = drm_kunit_helper_alloc_drm_device(test, dev,
216 struct drm_atomic_helper_connector_hdmi_priv, drm,
217 DRIVER_MODESET | DRIVER_ATOMIC);
218 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
219 test->priv = priv;
220
221 drm = &priv->drm;
222 priv->plane = drm_kunit_helper_create_primary_plane(test, drm,
223 NULL,
224 NULL,
225 NULL, 0,
226 NULL);
227 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->plane);
228
229 priv->crtc = drm_kunit_helper_create_crtc(test, drm,
230 priv->plane, NULL,
231 NULL,
232 NULL);
233 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->crtc);
234
235 enc = &priv->encoder;
236 ret = drmm_encoder_init(drm, enc, NULL, DRM_MODE_ENCODER_TMDS, NULL);
237 KUNIT_ASSERT_EQ(test, ret, 0);
238
239 enc->possible_crtcs = drm_crtc_mask(priv->crtc);
240
241 conn = &priv->connector;
242 conn->ycbcr_420_allowed = !!(formats & BIT(HDMI_COLORSPACE_YUV420));
243
244 ret = drmm_connector_hdmi_init(drm, conn,
245 "Vendor", "Product",
246 &dummy_connector_funcs,
247 hdmi_funcs,
248 DRM_MODE_CONNECTOR_HDMIA,
249 NULL,
250 formats,
251 max_bpc);
252 KUNIT_ASSERT_EQ(test, ret, 0);
253
254 drm_connector_helper_add(conn, &dummy_connector_helper_funcs);
255 drm_connector_attach_encoder(conn, enc);
256
257 drm_mode_config_reset(drm);
258
259 if (edid_data && edid_len) {
260 ret = set_connector_edid(test, &priv->connector, edid_data, edid_len);
261 KUNIT_ASSERT_GT(test, ret, 0);
262 }
263
264 return priv;
265 }
266
267 #define drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, formats, max_bpc, funcs, edid) \
268 __connector_hdmi_init(test, formats, max_bpc, funcs, edid, ARRAY_SIZE(edid))
269
270 static
271 struct drm_atomic_helper_connector_hdmi_priv *
drm_kunit_helper_connector_hdmi_init(struct kunit * test,unsigned int formats,unsigned int max_bpc)272 drm_kunit_helper_connector_hdmi_init(struct kunit *test,
273 unsigned int formats,
274 unsigned int max_bpc)
275 {
276 return drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
277 formats,
278 max_bpc,
279 &dummy_connector_hdmi_funcs,
280 test_edid_hdmi_1080p_rgb_max_200mhz);
281 }
282
283 /*
284 * Test that if we change the RGB quantization property to a different
285 * value, we trigger a mode change on the connector's CRTC, which will
286 * in turn disable/enable the connector.
287 */
drm_test_check_broadcast_rgb_crtc_mode_changed(struct kunit * test)288 static void drm_test_check_broadcast_rgb_crtc_mode_changed(struct kunit *test)
289 {
290 struct drm_atomic_helper_connector_hdmi_priv *priv;
291 struct drm_modeset_acquire_ctx ctx;
292 struct drm_connector_state *old_conn_state;
293 struct drm_connector_state *new_conn_state;
294 struct drm_crtc_state *crtc_state;
295 struct drm_atomic_state *state;
296 struct drm_display_mode *preferred;
297 struct drm_connector *conn;
298 struct drm_device *drm;
299 struct drm_crtc *crtc;
300 int ret;
301
302 priv = drm_kunit_helper_connector_hdmi_init(test,
303 BIT(HDMI_COLORSPACE_RGB),
304 8);
305 KUNIT_ASSERT_NOT_NULL(test, priv);
306
307 drm = &priv->drm;
308 crtc = priv->crtc;
309 conn = &priv->connector;
310
311 preferred = find_preferred_mode(conn);
312 KUNIT_ASSERT_NOT_NULL(test, preferred);
313
314 drm_modeset_acquire_init(&ctx, 0);
315
316 retry_conn_enable:
317 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
318 crtc, conn,
319 preferred,
320 &ctx);
321 if (ret == -EDEADLK) {
322 ret = drm_modeset_backoff(&ctx);
323 if (!ret)
324 goto retry_conn_enable;
325 }
326 KUNIT_ASSERT_EQ(test, ret, 0);
327
328 state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
329 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
330
331 new_conn_state = drm_atomic_get_connector_state(state, conn);
332 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state);
333
334 old_conn_state = drm_atomic_get_old_connector_state(state, conn);
335 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_conn_state);
336
337 new_conn_state->hdmi.broadcast_rgb = DRM_HDMI_BROADCAST_RGB_FULL;
338
339 KUNIT_ASSERT_NE(test,
340 old_conn_state->hdmi.broadcast_rgb,
341 new_conn_state->hdmi.broadcast_rgb);
342
343 ret = drm_atomic_check_only(state);
344 KUNIT_ASSERT_EQ(test, ret, 0);
345
346 new_conn_state = drm_atomic_get_new_connector_state(state, conn);
347 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state);
348 KUNIT_EXPECT_EQ(test, new_conn_state->hdmi.broadcast_rgb, DRM_HDMI_BROADCAST_RGB_FULL);
349
350 crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
351 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
352 KUNIT_EXPECT_TRUE(test, crtc_state->mode_changed);
353
354 drm_modeset_drop_locks(&ctx);
355 drm_modeset_acquire_fini(&ctx);
356 }
357
358 /*
359 * Test that if we set the RGB quantization property to the same value,
360 * we don't trigger a mode change on the connector's CRTC and leave the
361 * connector unaffected.
362 */
drm_test_check_broadcast_rgb_crtc_mode_not_changed(struct kunit * test)363 static void drm_test_check_broadcast_rgb_crtc_mode_not_changed(struct kunit *test)
364 {
365 struct drm_atomic_helper_connector_hdmi_priv *priv;
366 struct drm_modeset_acquire_ctx ctx;
367 struct drm_connector_state *old_conn_state;
368 struct drm_connector_state *new_conn_state;
369 struct drm_crtc_state *crtc_state;
370 struct drm_atomic_state *state;
371 struct drm_display_mode *preferred;
372 struct drm_connector *conn;
373 struct drm_device *drm;
374 struct drm_crtc *crtc;
375 int ret;
376
377 priv = drm_kunit_helper_connector_hdmi_init(test,
378 BIT(HDMI_COLORSPACE_RGB),
379 8);
380 KUNIT_ASSERT_NOT_NULL(test, priv);
381
382 drm = &priv->drm;
383 crtc = priv->crtc;
384 conn = &priv->connector;
385
386 preferred = find_preferred_mode(conn);
387 KUNIT_ASSERT_NOT_NULL(test, preferred);
388
389 drm_modeset_acquire_init(&ctx, 0);
390
391 retry_conn_enable:
392 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
393 crtc, conn,
394 preferred,
395 &ctx);
396 if (ret == -EDEADLK) {
397 ret = drm_modeset_backoff(&ctx);
398 if (!ret)
399 goto retry_conn_enable;
400 }
401 KUNIT_ASSERT_EQ(test, ret, 0);
402
403 state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
404 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
405
406 new_conn_state = drm_atomic_get_connector_state(state, conn);
407 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state);
408
409 old_conn_state = drm_atomic_get_old_connector_state(state, conn);
410 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_conn_state);
411
412 new_conn_state->hdmi.broadcast_rgb = old_conn_state->hdmi.broadcast_rgb;
413
414 ret = drm_atomic_check_only(state);
415 KUNIT_ASSERT_EQ(test, ret, 0);
416
417 old_conn_state = drm_atomic_get_old_connector_state(state, conn);
418 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_conn_state);
419
420 new_conn_state = drm_atomic_get_new_connector_state(state, conn);
421 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state);
422
423 KUNIT_EXPECT_EQ(test,
424 old_conn_state->hdmi.broadcast_rgb,
425 new_conn_state->hdmi.broadcast_rgb);
426
427 crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
428 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
429 KUNIT_EXPECT_FALSE(test, crtc_state->mode_changed);
430
431 drm_modeset_drop_locks(&ctx);
432 drm_modeset_acquire_fini(&ctx);
433 }
434
435 /*
436 * Test that for an HDMI connector, with an HDMI monitor, if the
437 * Broadcast RGB property is set to auto with a mode that isn't the
438 * VIC-1 mode, we will get a limited RGB Quantization Range.
439 */
drm_test_check_broadcast_rgb_auto_cea_mode(struct kunit * test)440 static void drm_test_check_broadcast_rgb_auto_cea_mode(struct kunit *test)
441 {
442 struct drm_atomic_helper_connector_hdmi_priv *priv;
443 struct drm_modeset_acquire_ctx ctx;
444 struct drm_connector_state *conn_state;
445 struct drm_atomic_state *state;
446 struct drm_display_mode *preferred;
447 struct drm_connector *conn;
448 struct drm_device *drm;
449 struct drm_crtc *crtc;
450 int ret;
451
452 priv = drm_kunit_helper_connector_hdmi_init(test,
453 BIT(HDMI_COLORSPACE_RGB),
454 8);
455 KUNIT_ASSERT_NOT_NULL(test, priv);
456
457 drm = &priv->drm;
458 crtc = priv->crtc;
459 conn = &priv->connector;
460 KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi);
461
462 preferred = find_preferred_mode(conn);
463 KUNIT_ASSERT_NOT_NULL(test, preferred);
464 KUNIT_ASSERT_NE(test, drm_match_cea_mode(preferred), 1);
465
466 drm_modeset_acquire_init(&ctx, 0);
467
468 retry_conn_enable:
469 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
470 crtc, conn,
471 preferred,
472 &ctx);
473 if (ret == -EDEADLK) {
474 ret = drm_modeset_backoff(&ctx);
475 if (!ret)
476 goto retry_conn_enable;
477 }
478 KUNIT_ASSERT_EQ(test, ret, 0);
479
480 state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
481 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
482
483 conn_state = drm_atomic_get_connector_state(state, conn);
484 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
485
486 KUNIT_ASSERT_EQ(test,
487 conn_state->hdmi.broadcast_rgb,
488 DRM_HDMI_BROADCAST_RGB_AUTO);
489
490 ret = drm_atomic_check_only(state);
491 KUNIT_ASSERT_EQ(test, ret, 0);
492
493 conn_state = drm_atomic_get_new_connector_state(state, conn);
494 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
495
496 KUNIT_EXPECT_TRUE(test, conn_state->hdmi.is_limited_range);
497
498 drm_modeset_drop_locks(&ctx);
499 drm_modeset_acquire_fini(&ctx);
500 }
501
502 /*
503 * Test that for an HDMI connector, with an HDMI monitor, if the
504 * Broadcast RGB property is set to auto with a VIC-1 mode, we will get
505 * a full RGB Quantization Range.
506 */
drm_test_check_broadcast_rgb_auto_cea_mode_vic_1(struct kunit * test)507 static void drm_test_check_broadcast_rgb_auto_cea_mode_vic_1(struct kunit *test)
508 {
509 struct drm_atomic_helper_connector_hdmi_priv *priv;
510 struct drm_modeset_acquire_ctx ctx;
511 struct drm_connector_state *conn_state;
512 struct drm_atomic_state *state;
513 struct drm_display_mode *mode;
514 struct drm_connector *conn;
515 struct drm_device *drm;
516 struct drm_crtc *crtc;
517 int ret;
518
519 priv = drm_kunit_helper_connector_hdmi_init(test,
520 BIT(HDMI_COLORSPACE_RGB),
521 8);
522 KUNIT_ASSERT_NOT_NULL(test, priv);
523
524 drm = &priv->drm;
525 conn = &priv->connector;
526 KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi);
527
528 drm_modeset_acquire_init(&ctx, 0);
529
530 mode = drm_kunit_display_mode_from_cea_vic(test, drm, 1);
531 KUNIT_ASSERT_NOT_NULL(test, mode);
532
533 crtc = priv->crtc;
534
535 retry_conn_enable:
536 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
537 crtc, conn,
538 mode,
539 &ctx);
540 if (ret == -EDEADLK) {
541 ret = drm_modeset_backoff(&ctx);
542 if (!ret)
543 goto retry_conn_enable;
544 }
545 KUNIT_ASSERT_EQ(test, ret, 0);
546
547 state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
548 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
549
550 conn_state = drm_atomic_get_connector_state(state, conn);
551 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
552
553 KUNIT_ASSERT_EQ(test,
554 conn_state->hdmi.broadcast_rgb,
555 DRM_HDMI_BROADCAST_RGB_AUTO);
556
557 ret = drm_atomic_check_only(state);
558 KUNIT_ASSERT_EQ(test, ret, 0);
559
560 conn_state = drm_atomic_get_new_connector_state(state, conn);
561 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
562
563 KUNIT_EXPECT_FALSE(test, conn_state->hdmi.is_limited_range);
564
565 drm_modeset_drop_locks(&ctx);
566 drm_modeset_acquire_fini(&ctx);
567 }
568
569 /*
570 * Test that for an HDMI connector, with an HDMI monitor, if the
571 * Broadcast RGB property is set to full with a mode that isn't the
572 * VIC-1 mode, we will get a full RGB Quantization Range.
573 */
drm_test_check_broadcast_rgb_full_cea_mode(struct kunit * test)574 static void drm_test_check_broadcast_rgb_full_cea_mode(struct kunit *test)
575 {
576 struct drm_atomic_helper_connector_hdmi_priv *priv;
577 struct drm_modeset_acquire_ctx ctx;
578 struct drm_connector_state *conn_state;
579 struct drm_atomic_state *state;
580 struct drm_display_mode *preferred;
581 struct drm_connector *conn;
582 struct drm_device *drm;
583 struct drm_crtc *crtc;
584 int ret;
585
586 priv = drm_kunit_helper_connector_hdmi_init(test,
587 BIT(HDMI_COLORSPACE_RGB),
588 8);
589 KUNIT_ASSERT_NOT_NULL(test, priv);
590
591 drm = &priv->drm;
592 crtc = priv->crtc;
593 conn = &priv->connector;
594 KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi);
595
596 preferred = find_preferred_mode(conn);
597 KUNIT_ASSERT_NOT_NULL(test, preferred);
598 KUNIT_ASSERT_NE(test, drm_match_cea_mode(preferred), 1);
599
600 drm_modeset_acquire_init(&ctx, 0);
601
602 retry_conn_enable:
603 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
604 crtc, conn,
605 preferred,
606 &ctx);
607 if (ret == -EDEADLK) {
608 ret = drm_modeset_backoff(&ctx);
609 if (!ret)
610 goto retry_conn_enable;
611 }
612 KUNIT_ASSERT_EQ(test, ret, 0);
613
614 state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
615 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
616
617 conn_state = drm_atomic_get_connector_state(state, conn);
618 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
619
620 conn_state->hdmi.broadcast_rgb = DRM_HDMI_BROADCAST_RGB_FULL;
621
622 ret = drm_atomic_check_only(state);
623 KUNIT_ASSERT_EQ(test, ret, 0);
624
625 conn_state = drm_atomic_get_new_connector_state(state, conn);
626 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
627
628 KUNIT_ASSERT_EQ(test,
629 conn_state->hdmi.broadcast_rgb,
630 DRM_HDMI_BROADCAST_RGB_FULL);
631
632 KUNIT_EXPECT_FALSE(test, conn_state->hdmi.is_limited_range);
633
634 drm_modeset_drop_locks(&ctx);
635 drm_modeset_acquire_fini(&ctx);
636 }
637
638 /*
639 * Test that for an HDMI connector, with an HDMI monitor, if the
640 * Broadcast RGB property is set to full with a VIC-1 mode, we will get
641 * a full RGB Quantization Range.
642 */
drm_test_check_broadcast_rgb_full_cea_mode_vic_1(struct kunit * test)643 static void drm_test_check_broadcast_rgb_full_cea_mode_vic_1(struct kunit *test)
644 {
645 struct drm_atomic_helper_connector_hdmi_priv *priv;
646 struct drm_modeset_acquire_ctx ctx;
647 struct drm_connector_state *conn_state;
648 struct drm_atomic_state *state;
649 struct drm_display_mode *mode;
650 struct drm_connector *conn;
651 struct drm_device *drm;
652 struct drm_crtc *crtc;
653 int ret;
654
655 priv = drm_kunit_helper_connector_hdmi_init(test,
656 BIT(HDMI_COLORSPACE_RGB),
657 8);
658 KUNIT_ASSERT_NOT_NULL(test, priv);
659
660 drm = &priv->drm;
661 conn = &priv->connector;
662 KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi);
663
664 drm_modeset_acquire_init(&ctx, 0);
665
666 mode = drm_kunit_display_mode_from_cea_vic(test, drm, 1);
667 KUNIT_ASSERT_NOT_NULL(test, mode);
668
669 crtc = priv->crtc;
670
671 retry_conn_enable:
672 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
673 crtc, conn,
674 mode,
675 &ctx);
676 if (ret == -EDEADLK) {
677 ret = drm_modeset_backoff(&ctx);
678 if (!ret)
679 goto retry_conn_enable;
680 }
681 KUNIT_ASSERT_EQ(test, ret, 0);
682
683 state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
684 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
685
686 conn_state = drm_atomic_get_connector_state(state, conn);
687 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
688
689 conn_state->hdmi.broadcast_rgb = DRM_HDMI_BROADCAST_RGB_FULL;
690
691 ret = drm_atomic_check_only(state);
692 KUNIT_ASSERT_EQ(test, ret, 0);
693
694 conn_state = drm_atomic_get_new_connector_state(state, conn);
695 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
696
697 KUNIT_ASSERT_EQ(test,
698 conn_state->hdmi.broadcast_rgb,
699 DRM_HDMI_BROADCAST_RGB_FULL);
700
701 KUNIT_EXPECT_FALSE(test, conn_state->hdmi.is_limited_range);
702
703 drm_modeset_drop_locks(&ctx);
704 drm_modeset_acquire_fini(&ctx);
705 }
706
707 /*
708 * Test that for an HDMI connector, with an HDMI monitor, if the
709 * Broadcast RGB property is set to limited with a mode that isn't the
710 * VIC-1 mode, we will get a limited RGB Quantization Range.
711 */
drm_test_check_broadcast_rgb_limited_cea_mode(struct kunit * test)712 static void drm_test_check_broadcast_rgb_limited_cea_mode(struct kunit *test)
713 {
714 struct drm_atomic_helper_connector_hdmi_priv *priv;
715 struct drm_modeset_acquire_ctx ctx;
716 struct drm_connector_state *conn_state;
717 struct drm_atomic_state *state;
718 struct drm_display_mode *preferred;
719 struct drm_connector *conn;
720 struct drm_device *drm;
721 struct drm_crtc *crtc;
722 int ret;
723
724 priv = drm_kunit_helper_connector_hdmi_init(test,
725 BIT(HDMI_COLORSPACE_RGB),
726 8);
727 KUNIT_ASSERT_NOT_NULL(test, priv);
728
729 drm = &priv->drm;
730 crtc = priv->crtc;
731 conn = &priv->connector;
732 KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi);
733
734 preferred = find_preferred_mode(conn);
735 KUNIT_ASSERT_NOT_NULL(test, preferred);
736 KUNIT_ASSERT_NE(test, drm_match_cea_mode(preferred), 1);
737
738 drm_modeset_acquire_init(&ctx, 0);
739
740 retry_conn_enable:
741 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
742 crtc, conn,
743 preferred,
744 &ctx);
745 if (ret == -EDEADLK) {
746 ret = drm_modeset_backoff(&ctx);
747 if (!ret)
748 goto retry_conn_enable;
749 }
750 KUNIT_ASSERT_EQ(test, ret, 0);
751
752 state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
753 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
754
755 conn_state = drm_atomic_get_connector_state(state, conn);
756 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
757
758 conn_state->hdmi.broadcast_rgb = DRM_HDMI_BROADCAST_RGB_LIMITED;
759
760 ret = drm_atomic_check_only(state);
761 KUNIT_ASSERT_EQ(test, ret, 0);
762
763 conn_state = drm_atomic_get_new_connector_state(state, conn);
764 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
765
766 KUNIT_ASSERT_EQ(test,
767 conn_state->hdmi.broadcast_rgb,
768 DRM_HDMI_BROADCAST_RGB_LIMITED);
769
770 KUNIT_EXPECT_TRUE(test, conn_state->hdmi.is_limited_range);
771
772 drm_modeset_drop_locks(&ctx);
773 drm_modeset_acquire_fini(&ctx);
774 }
775
776 /*
777 * Test that for an HDMI connector, with an HDMI monitor, if the
778 * Broadcast RGB property is set to limited with a VIC-1 mode, we will
779 * get a limited RGB Quantization Range.
780 */
drm_test_check_broadcast_rgb_limited_cea_mode_vic_1(struct kunit * test)781 static void drm_test_check_broadcast_rgb_limited_cea_mode_vic_1(struct kunit *test)
782 {
783 struct drm_atomic_helper_connector_hdmi_priv *priv;
784 struct drm_modeset_acquire_ctx ctx;
785 struct drm_connector_state *conn_state;
786 struct drm_atomic_state *state;
787 struct drm_display_mode *mode;
788 struct drm_connector *conn;
789 struct drm_device *drm;
790 struct drm_crtc *crtc;
791 int ret;
792
793 priv = drm_kunit_helper_connector_hdmi_init(test,
794 BIT(HDMI_COLORSPACE_RGB),
795 8);
796 KUNIT_ASSERT_NOT_NULL(test, priv);
797
798 drm = &priv->drm;
799 conn = &priv->connector;
800 KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi);
801
802 drm_modeset_acquire_init(&ctx, 0);
803
804 mode = drm_kunit_display_mode_from_cea_vic(test, drm, 1);
805 KUNIT_ASSERT_NOT_NULL(test, mode);
806
807 crtc = priv->crtc;
808
809 retry_conn_enable:
810 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
811 crtc, conn,
812 mode,
813 &ctx);
814 if (ret == -EDEADLK) {
815 ret = drm_modeset_backoff(&ctx);
816 if (!ret)
817 goto retry_conn_enable;
818 }
819 KUNIT_ASSERT_EQ(test, ret, 0);
820
821 state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
822 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
823
824 conn_state = drm_atomic_get_connector_state(state, conn);
825 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
826
827 conn_state->hdmi.broadcast_rgb = DRM_HDMI_BROADCAST_RGB_LIMITED;
828
829 ret = drm_atomic_check_only(state);
830 KUNIT_ASSERT_EQ(test, ret, 0);
831
832 conn_state = drm_atomic_get_new_connector_state(state, conn);
833 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
834
835 KUNIT_ASSERT_EQ(test,
836 conn_state->hdmi.broadcast_rgb,
837 DRM_HDMI_BROADCAST_RGB_LIMITED);
838
839 KUNIT_EXPECT_TRUE(test, conn_state->hdmi.is_limited_range);
840
841 drm_modeset_drop_locks(&ctx);
842 drm_modeset_acquire_fini(&ctx);
843 }
844
845 /*
846 * Test that for an HDMI connector, with an HDMI monitor, we will
847 * get a limited RGB Quantization Range with a YUV420 mode, no
848 * matter what the value of the Broadcast RGB property is set to.
849 */
drm_test_check_broadcast_rgb_cea_mode_yuv420(struct kunit * test)850 static void drm_test_check_broadcast_rgb_cea_mode_yuv420(struct kunit *test)
851 {
852 struct drm_atomic_helper_connector_hdmi_priv *priv;
853 enum drm_hdmi_broadcast_rgb broadcast_rgb;
854 struct drm_modeset_acquire_ctx ctx;
855 struct drm_connector_state *conn_state;
856 struct drm_atomic_state *state;
857 struct drm_display_mode *mode;
858 struct drm_connector *conn;
859 struct drm_device *drm;
860 struct drm_crtc *crtc;
861 int ret;
862
863 broadcast_rgb = *(enum drm_hdmi_broadcast_rgb *)test->param_value;
864
865 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
866 BIT(HDMI_COLORSPACE_RGB) |
867 BIT(HDMI_COLORSPACE_YUV420),
868 8,
869 &dummy_connector_hdmi_funcs,
870 test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz);
871 KUNIT_ASSERT_NOT_NULL(test, priv);
872
873 drm = &priv->drm;
874 crtc = priv->crtc;
875 conn = &priv->connector;
876 KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi);
877
878 mode = drm_kunit_display_mode_from_cea_vic(test, drm, 95);
879 KUNIT_ASSERT_NOT_NULL(test, mode);
880
881 drm_modeset_acquire_init(&ctx, 0);
882
883 retry_conn_enable:
884 ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn,
885 mode, &ctx);
886 if (ret == -EDEADLK) {
887 ret = drm_modeset_backoff(&ctx);
888 if (!ret)
889 goto retry_conn_enable;
890 }
891 KUNIT_ASSERT_EQ(test, ret, 0);
892
893 state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
894 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
895
896 retry_conn_state:
897 conn_state = drm_atomic_get_connector_state(state, conn);
898 if (PTR_ERR(conn_state) == -EDEADLK) {
899 drm_atomic_state_clear(state);
900 ret = drm_modeset_backoff(&ctx);
901 if (!ret)
902 goto retry_conn_state;
903 }
904 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
905
906 conn_state->hdmi.broadcast_rgb = broadcast_rgb;
907
908 ret = drm_atomic_check_only(state);
909 if (ret == -EDEADLK) {
910 drm_atomic_state_clear(state);
911 ret = drm_modeset_backoff(&ctx);
912 if (!ret)
913 goto retry_conn_state;
914 }
915 KUNIT_ASSERT_EQ(test, ret, 0);
916
917 conn_state = drm_atomic_get_new_connector_state(state, conn);
918 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
919
920 KUNIT_ASSERT_EQ(test, conn_state->hdmi.broadcast_rgb, broadcast_rgb);
921 KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_YUV420);
922
923 KUNIT_EXPECT_TRUE(test, conn_state->hdmi.is_limited_range);
924
925 drm_modeset_drop_locks(&ctx);
926 drm_modeset_acquire_fini(&ctx);
927 }
928
929 static const enum drm_hdmi_broadcast_rgb check_broadcast_rgb_cea_mode_yuv420_tests[] = {
930 DRM_HDMI_BROADCAST_RGB_AUTO,
931 DRM_HDMI_BROADCAST_RGB_FULL,
932 DRM_HDMI_BROADCAST_RGB_LIMITED,
933 };
934
935 static void
check_broadcast_rgb_cea_mode_yuv420_desc(const enum drm_hdmi_broadcast_rgb * broadcast_rgb,char * desc)936 check_broadcast_rgb_cea_mode_yuv420_desc(const enum drm_hdmi_broadcast_rgb *broadcast_rgb,
937 char *desc)
938 {
939 sprintf(desc, "%s", drm_hdmi_connector_get_broadcast_rgb_name(*broadcast_rgb));
940 }
941
942 KUNIT_ARRAY_PARAM(check_broadcast_rgb_cea_mode_yuv420,
943 check_broadcast_rgb_cea_mode_yuv420_tests,
944 check_broadcast_rgb_cea_mode_yuv420_desc);
945
946 /*
947 * Test that if we change the maximum bpc property to a different value,
948 * we trigger a mode change on the connector's CRTC, which will in turn
949 * disable/enable the connector.
950 */
drm_test_check_output_bpc_crtc_mode_changed(struct kunit * test)951 static void drm_test_check_output_bpc_crtc_mode_changed(struct kunit *test)
952 {
953 struct drm_atomic_helper_connector_hdmi_priv *priv;
954 struct drm_modeset_acquire_ctx ctx;
955 struct drm_connector_state *old_conn_state;
956 struct drm_connector_state *new_conn_state;
957 struct drm_crtc_state *crtc_state;
958 struct drm_atomic_state *state;
959 struct drm_display_mode *preferred;
960 struct drm_connector *conn;
961 struct drm_device *drm;
962 struct drm_crtc *crtc;
963 int ret;
964
965 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
966 BIT(HDMI_COLORSPACE_RGB),
967 10,
968 &dummy_connector_hdmi_funcs,
969 test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz);
970 KUNIT_ASSERT_NOT_NULL(test, priv);
971
972 drm = &priv->drm;
973 crtc = priv->crtc;
974 conn = &priv->connector;
975 preferred = find_preferred_mode(conn);
976 KUNIT_ASSERT_NOT_NULL(test, preferred);
977
978 drm_modeset_acquire_init(&ctx, 0);
979
980 retry_conn_enable:
981 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
982 crtc, conn,
983 preferred,
984 &ctx);
985 if (ret == -EDEADLK) {
986 ret = drm_modeset_backoff(&ctx);
987 if (!ret)
988 goto retry_conn_enable;
989 }
990 KUNIT_ASSERT_EQ(test, ret, 0);
991
992 state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
993 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
994
995 new_conn_state = drm_atomic_get_connector_state(state, conn);
996 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state);
997
998 old_conn_state = drm_atomic_get_old_connector_state(state, conn);
999 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_conn_state);
1000
1001 new_conn_state->max_requested_bpc = 8;
1002
1003 KUNIT_ASSERT_NE(test,
1004 old_conn_state->max_requested_bpc,
1005 new_conn_state->max_requested_bpc);
1006
1007 ret = drm_atomic_check_only(state);
1008 KUNIT_ASSERT_EQ(test, ret, 0);
1009
1010 old_conn_state = drm_atomic_get_old_connector_state(state, conn);
1011 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_conn_state);
1012
1013 new_conn_state = drm_atomic_get_new_connector_state(state, conn);
1014 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state);
1015
1016 KUNIT_ASSERT_NE(test,
1017 old_conn_state->hdmi.output_bpc,
1018 new_conn_state->hdmi.output_bpc);
1019
1020 crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
1021 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
1022 KUNIT_EXPECT_TRUE(test, crtc_state->mode_changed);
1023
1024 drm_modeset_drop_locks(&ctx);
1025 drm_modeset_acquire_fini(&ctx);
1026 }
1027
1028 /*
1029 * Test that if we set the output bpc property to the same value, we
1030 * don't trigger a mode change on the connector's CRTC and leave the
1031 * connector unaffected.
1032 */
drm_test_check_output_bpc_crtc_mode_not_changed(struct kunit * test)1033 static void drm_test_check_output_bpc_crtc_mode_not_changed(struct kunit *test)
1034 {
1035 struct drm_atomic_helper_connector_hdmi_priv *priv;
1036 struct drm_modeset_acquire_ctx ctx;
1037 struct drm_connector_state *old_conn_state;
1038 struct drm_connector_state *new_conn_state;
1039 struct drm_crtc_state *crtc_state;
1040 struct drm_atomic_state *state;
1041 struct drm_display_mode *preferred;
1042 struct drm_connector *conn;
1043 struct drm_device *drm;
1044 struct drm_crtc *crtc;
1045 int ret;
1046
1047 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
1048 BIT(HDMI_COLORSPACE_RGB),
1049 10,
1050 &dummy_connector_hdmi_funcs,
1051 test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz);
1052 KUNIT_ASSERT_NOT_NULL(test, priv);
1053
1054 drm = &priv->drm;
1055 crtc = priv->crtc;
1056 conn = &priv->connector;
1057 preferred = find_preferred_mode(conn);
1058 KUNIT_ASSERT_NOT_NULL(test, preferred);
1059
1060 drm_modeset_acquire_init(&ctx, 0);
1061
1062 retry_conn_enable:
1063 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
1064 crtc, conn,
1065 preferred,
1066 &ctx);
1067 if (ret == -EDEADLK) {
1068 ret = drm_modeset_backoff(&ctx);
1069 if (!ret)
1070 goto retry_conn_enable;
1071 }
1072 KUNIT_ASSERT_EQ(test, ret, 0);
1073
1074 state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
1075 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
1076
1077 new_conn_state = drm_atomic_get_connector_state(state, conn);
1078 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state);
1079
1080 old_conn_state = drm_atomic_get_old_connector_state(state, conn);
1081 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_conn_state);
1082
1083 KUNIT_ASSERT_EQ(test,
1084 new_conn_state->hdmi.output_bpc,
1085 old_conn_state->hdmi.output_bpc);
1086
1087 ret = drm_atomic_check_only(state);
1088 KUNIT_ASSERT_EQ(test, ret, 0);
1089
1090 old_conn_state = drm_atomic_get_old_connector_state(state, conn);
1091 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_conn_state);
1092
1093 new_conn_state = drm_atomic_get_new_connector_state(state, conn);
1094 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state);
1095
1096 KUNIT_EXPECT_EQ(test,
1097 old_conn_state->hdmi.output_bpc,
1098 new_conn_state->hdmi.output_bpc);
1099
1100 crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
1101 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
1102 KUNIT_EXPECT_FALSE(test, crtc_state->mode_changed);
1103
1104 drm_modeset_drop_locks(&ctx);
1105 drm_modeset_acquire_fini(&ctx);
1106 }
1107
1108 /*
1109 * Test that if we have an HDMI connector but a !HDMI display, we always
1110 * output RGB with 8 bpc.
1111 */
drm_test_check_output_bpc_dvi(struct kunit * test)1112 static void drm_test_check_output_bpc_dvi(struct kunit *test)
1113 {
1114 struct drm_atomic_helper_connector_hdmi_priv *priv;
1115 struct drm_modeset_acquire_ctx ctx;
1116 struct drm_connector_state *conn_state;
1117 struct drm_display_info *info;
1118 struct drm_display_mode *preferred;
1119 struct drm_connector *conn;
1120 struct drm_device *drm;
1121 struct drm_crtc *crtc;
1122 int ret;
1123
1124 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
1125 BIT(HDMI_COLORSPACE_RGB) |
1126 BIT(HDMI_COLORSPACE_YUV422) |
1127 BIT(HDMI_COLORSPACE_YUV444),
1128 12,
1129 &dummy_connector_hdmi_funcs,
1130 test_edid_dvi_1080p);
1131 KUNIT_ASSERT_NOT_NULL(test, priv);
1132
1133 drm = &priv->drm;
1134 crtc = priv->crtc;
1135 conn = &priv->connector;
1136 info = &conn->display_info;
1137 KUNIT_ASSERT_FALSE(test, info->is_hdmi);
1138
1139 preferred = find_preferred_mode(conn);
1140 KUNIT_ASSERT_NOT_NULL(test, preferred);
1141
1142 drm_modeset_acquire_init(&ctx, 0);
1143
1144 retry_conn_enable:
1145 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
1146 crtc, conn,
1147 preferred,
1148 &ctx);
1149 if (ret == -EDEADLK) {
1150 ret = drm_modeset_backoff(&ctx);
1151 if (!ret)
1152 goto retry_conn_enable;
1153 }
1154 KUNIT_ASSERT_EQ(test, ret, 0);
1155
1156 conn_state = conn->state;
1157 KUNIT_ASSERT_NOT_NULL(test, conn_state);
1158
1159 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 8);
1160 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB);
1161
1162 drm_modeset_drop_locks(&ctx);
1163 drm_modeset_acquire_fini(&ctx);
1164 }
1165
1166 /*
1167 * Test that when doing a commit which would use RGB 8bpc, the TMDS
1168 * clock rate stored in the connector state is equal to the mode clock
1169 */
drm_test_check_tmds_char_rate_rgb_8bpc(struct kunit * test)1170 static void drm_test_check_tmds_char_rate_rgb_8bpc(struct kunit *test)
1171 {
1172 struct drm_atomic_helper_connector_hdmi_priv *priv;
1173 struct drm_modeset_acquire_ctx ctx;
1174 struct drm_connector_state *conn_state;
1175 struct drm_display_mode *preferred;
1176 struct drm_connector *conn;
1177 struct drm_device *drm;
1178 struct drm_crtc *crtc;
1179 int ret;
1180
1181 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
1182 BIT(HDMI_COLORSPACE_RGB),
1183 8,
1184 &dummy_connector_hdmi_funcs,
1185 test_edid_hdmi_1080p_rgb_max_200mhz);
1186 KUNIT_ASSERT_NOT_NULL(test, priv);
1187
1188 drm = &priv->drm;
1189 crtc = priv->crtc;
1190 conn = &priv->connector;
1191 preferred = find_preferred_mode(conn);
1192 KUNIT_ASSERT_NOT_NULL(test, preferred);
1193 KUNIT_ASSERT_FALSE(test, preferred->flags & DRM_MODE_FLAG_DBLCLK);
1194
1195 drm_modeset_acquire_init(&ctx, 0);
1196
1197 retry_conn_enable:
1198 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
1199 crtc, conn,
1200 preferred,
1201 &ctx);
1202 if (ret == -EDEADLK) {
1203 ret = drm_modeset_backoff(&ctx);
1204 if (!ret)
1205 goto retry_conn_enable;
1206 }
1207 KUNIT_ASSERT_EQ(test, ret, 0);
1208
1209 conn_state = conn->state;
1210 KUNIT_ASSERT_NOT_NULL(test, conn_state);
1211
1212 KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_bpc, 8);
1213 KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB);
1214 KUNIT_EXPECT_EQ(test, conn_state->hdmi.tmds_char_rate, preferred->clock * 1000);
1215
1216 drm_modeset_drop_locks(&ctx);
1217 drm_modeset_acquire_fini(&ctx);
1218 }
1219
1220 /*
1221 * Test that when doing a commit which would use RGB 10bpc, the TMDS
1222 * clock rate stored in the connector state is equal to 1.25 times the
1223 * mode pixel clock
1224 */
drm_test_check_tmds_char_rate_rgb_10bpc(struct kunit * test)1225 static void drm_test_check_tmds_char_rate_rgb_10bpc(struct kunit *test)
1226 {
1227 struct drm_atomic_helper_connector_hdmi_priv *priv;
1228 struct drm_modeset_acquire_ctx ctx;
1229 struct drm_connector_state *conn_state;
1230 struct drm_display_mode *preferred;
1231 struct drm_connector *conn;
1232 struct drm_device *drm;
1233 struct drm_crtc *crtc;
1234 int ret;
1235
1236 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
1237 BIT(HDMI_COLORSPACE_RGB),
1238 10,
1239 &dummy_connector_hdmi_funcs,
1240 test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz);
1241 KUNIT_ASSERT_NOT_NULL(test, priv);
1242
1243 drm = &priv->drm;
1244 crtc = priv->crtc;
1245 conn = &priv->connector;
1246 preferred = find_preferred_mode(conn);
1247 KUNIT_ASSERT_NOT_NULL(test, preferred);
1248 KUNIT_ASSERT_FALSE(test, preferred->flags & DRM_MODE_FLAG_DBLCLK);
1249
1250 drm_modeset_acquire_init(&ctx, 0);
1251
1252 retry_conn_enable:
1253 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
1254 crtc, conn,
1255 preferred,
1256 &ctx);
1257 if (ret == -EDEADLK) {
1258 ret = drm_modeset_backoff(&ctx);
1259 if (!ret)
1260 goto retry_conn_enable;
1261 }
1262 KUNIT_ASSERT_EQ(test, ret, 0);
1263
1264 conn_state = conn->state;
1265 KUNIT_ASSERT_NOT_NULL(test, conn_state);
1266
1267 KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_bpc, 10);
1268 KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB);
1269 KUNIT_EXPECT_EQ(test, conn_state->hdmi.tmds_char_rate, preferred->clock * 1250);
1270
1271 drm_modeset_drop_locks(&ctx);
1272 drm_modeset_acquire_fini(&ctx);
1273 }
1274
1275 /*
1276 * Test that when doing a commit which would use RGB 12bpc, the TMDS
1277 * clock rate stored in the connector state is equal to 1.5 times the
1278 * mode pixel clock
1279 */
drm_test_check_tmds_char_rate_rgb_12bpc(struct kunit * test)1280 static void drm_test_check_tmds_char_rate_rgb_12bpc(struct kunit *test)
1281 {
1282 struct drm_atomic_helper_connector_hdmi_priv *priv;
1283 struct drm_modeset_acquire_ctx ctx;
1284 struct drm_connector_state *conn_state;
1285 struct drm_display_mode *preferred;
1286 struct drm_connector *conn;
1287 struct drm_device *drm;
1288 struct drm_crtc *crtc;
1289 int ret;
1290
1291 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
1292 BIT(HDMI_COLORSPACE_RGB),
1293 12,
1294 &dummy_connector_hdmi_funcs,
1295 test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz);
1296 KUNIT_ASSERT_NOT_NULL(test, priv);
1297
1298 drm = &priv->drm;
1299 crtc = priv->crtc;
1300 conn = &priv->connector;
1301 preferred = find_preferred_mode(conn);
1302 KUNIT_ASSERT_NOT_NULL(test, preferred);
1303 KUNIT_ASSERT_FALSE(test, preferred->flags & DRM_MODE_FLAG_DBLCLK);
1304
1305 drm_modeset_acquire_init(&ctx, 0);
1306
1307 retry_conn_enable:
1308 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
1309 crtc, conn,
1310 preferred,
1311 &ctx);
1312 if (ret == -EDEADLK) {
1313 ret = drm_modeset_backoff(&ctx);
1314 if (!ret)
1315 goto retry_conn_enable;
1316 }
1317 KUNIT_ASSERT_EQ(test, ret, 0);
1318
1319 conn_state = conn->state;
1320 KUNIT_ASSERT_NOT_NULL(test, conn_state);
1321
1322 KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_bpc, 12);
1323 KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB);
1324 KUNIT_EXPECT_EQ(test, conn_state->hdmi.tmds_char_rate, preferred->clock * 1500);
1325
1326 drm_modeset_drop_locks(&ctx);
1327 drm_modeset_acquire_fini(&ctx);
1328 }
1329
1330 /*
1331 * Test that if we filter a rate through our hook, it's indeed rejected
1332 * by the whole atomic_check logic.
1333 *
1334 * We do so by first doing a commit on the pipeline to make sure that it
1335 * works, change the HDMI helpers pointer, and then try the same commit
1336 * again to see if it fails as it should.
1337 */
drm_test_check_hdmi_funcs_reject_rate(struct kunit * test)1338 static void drm_test_check_hdmi_funcs_reject_rate(struct kunit *test)
1339 {
1340 struct drm_atomic_helper_connector_hdmi_priv *priv;
1341 struct drm_modeset_acquire_ctx ctx;
1342 struct drm_atomic_state *state;
1343 struct drm_display_mode *preferred;
1344 struct drm_crtc_state *crtc_state;
1345 struct drm_connector *conn;
1346 struct drm_device *drm;
1347 struct drm_crtc *crtc;
1348 int ret;
1349
1350 priv = drm_kunit_helper_connector_hdmi_init(test,
1351 BIT(HDMI_COLORSPACE_RGB),
1352 8);
1353 KUNIT_ASSERT_NOT_NULL(test, priv);
1354
1355 drm = &priv->drm;
1356 crtc = priv->crtc;
1357 conn = &priv->connector;
1358
1359 preferred = find_preferred_mode(conn);
1360 KUNIT_ASSERT_NOT_NULL(test, preferred);
1361
1362 drm_modeset_acquire_init(&ctx, 0);
1363
1364 retry_conn_enable:
1365 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
1366 crtc, conn,
1367 preferred,
1368 &ctx);
1369 if (ret == -EDEADLK) {
1370 ret = drm_modeset_backoff(&ctx);
1371 if (!ret)
1372 goto retry_conn_enable;
1373 }
1374 KUNIT_ASSERT_EQ(test, ret, 0);
1375
1376 /* You shouldn't be doing that at home. */
1377 conn->hdmi.funcs = &reject_connector_hdmi_funcs;
1378
1379 state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
1380 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
1381
1382 crtc_state = drm_atomic_get_crtc_state(state, crtc);
1383 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
1384
1385 crtc_state->connectors_changed = true;
1386
1387 ret = drm_atomic_check_only(state);
1388 KUNIT_EXPECT_LT(test, ret, 0);
1389
1390 drm_modeset_drop_locks(&ctx);
1391 drm_modeset_acquire_fini(&ctx);
1392 }
1393
1394 /*
1395 * Test that if:
1396 * - We have an HDMI connector supporting RGB only
1397 * - The chosen mode has a TMDS character rate higher than the display
1398 * supports in RGB/12bpc
1399 * - The chosen mode has a TMDS character rate lower than the display
1400 * supports in RGB/10bpc.
1401 *
1402 * Then we will pick the latter, and the computed TMDS character rate
1403 * will be equal to 1.25 times the mode pixel clock.
1404 */
drm_test_check_max_tmds_rate_bpc_fallback_rgb(struct kunit * test)1405 static void drm_test_check_max_tmds_rate_bpc_fallback_rgb(struct kunit *test)
1406 {
1407 struct drm_atomic_helper_connector_hdmi_priv *priv;
1408 struct drm_modeset_acquire_ctx ctx;
1409 struct drm_connector_state *conn_state;
1410 struct drm_display_info *info;
1411 struct drm_display_mode *preferred;
1412 unsigned long long rate;
1413 struct drm_connector *conn;
1414 struct drm_device *drm;
1415 struct drm_crtc *crtc;
1416 int ret;
1417
1418 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
1419 BIT(HDMI_COLORSPACE_RGB),
1420 12,
1421 &dummy_connector_hdmi_funcs,
1422 test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz);
1423 KUNIT_ASSERT_NOT_NULL(test, priv);
1424
1425 drm = &priv->drm;
1426 crtc = priv->crtc;
1427 conn = &priv->connector;
1428 info = &conn->display_info;
1429 KUNIT_ASSERT_TRUE(test, info->is_hdmi);
1430 KUNIT_ASSERT_GT(test, info->max_tmds_clock, 0);
1431
1432 preferred = find_preferred_mode(conn);
1433 KUNIT_ASSERT_NOT_NULL(test, preferred);
1434 KUNIT_ASSERT_FALSE(test, preferred->flags & DRM_MODE_FLAG_DBLCLK);
1435
1436 rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_RGB);
1437 KUNIT_ASSERT_GT(test, rate, info->max_tmds_clock * 1000);
1438
1439 rate = drm_hdmi_compute_mode_clock(preferred, 10, HDMI_COLORSPACE_RGB);
1440 KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
1441
1442 drm_modeset_acquire_init(&ctx, 0);
1443
1444 retry_conn_enable:
1445 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
1446 crtc, conn,
1447 preferred,
1448 &ctx);
1449 if (ret == -EDEADLK) {
1450 ret = drm_modeset_backoff(&ctx);
1451 if (!ret)
1452 goto retry_conn_enable;
1453 }
1454 KUNIT_EXPECT_EQ(test, ret, 0);
1455
1456 conn_state = conn->state;
1457 KUNIT_ASSERT_NOT_NULL(test, conn_state);
1458
1459 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 10);
1460 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB);
1461 KUNIT_EXPECT_EQ(test, conn_state->hdmi.tmds_char_rate, preferred->clock * 1250);
1462
1463 drm_modeset_drop_locks(&ctx);
1464 drm_modeset_acquire_fini(&ctx);
1465 }
1466
1467 /*
1468 * Test that if:
1469 * - We have an HDMI connector and a display supporting both RGB and YUV420
1470 * - The chosen mode can be supported in YUV420 output format only
1471 * - The chosen mode has a TMDS character rate higher than the display
1472 * supports in YUV420/12bpc
1473 * - The chosen mode has a TMDS character rate lower than the display
1474 * supports in YUV420/10bpc.
1475 *
1476 * Then we will pick the latter, and the computed TMDS character rate
1477 * will be equal to 1.25 * 0.5 times the mode pixel clock.
1478 */
drm_test_check_max_tmds_rate_bpc_fallback_yuv420(struct kunit * test)1479 static void drm_test_check_max_tmds_rate_bpc_fallback_yuv420(struct kunit *test)
1480 {
1481 struct drm_atomic_helper_connector_hdmi_priv *priv;
1482 struct drm_modeset_acquire_ctx ctx;
1483 struct drm_connector_state *conn_state;
1484 struct drm_display_info *info;
1485 struct drm_display_mode *yuv420_only_mode;
1486 unsigned long long rate;
1487 struct drm_connector *conn;
1488 struct drm_device *drm;
1489 struct drm_crtc *crtc;
1490 int ret;
1491
1492 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
1493 BIT(HDMI_COLORSPACE_RGB) |
1494 BIT(HDMI_COLORSPACE_YUV420),
1495 12,
1496 &dummy_connector_hdmi_funcs,
1497 test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz);
1498 KUNIT_ASSERT_NOT_NULL(test, priv);
1499
1500 drm = &priv->drm;
1501 crtc = priv->crtc;
1502 conn = &priv->connector;
1503 info = &conn->display_info;
1504 KUNIT_ASSERT_TRUE(test, info->is_hdmi);
1505 KUNIT_ASSERT_GT(test, info->max_tmds_clock, 0);
1506 KUNIT_ASSERT_TRUE(test, conn->ycbcr_420_allowed);
1507
1508 yuv420_only_mode = drm_kunit_display_mode_from_cea_vic(test, drm, 95);
1509 KUNIT_ASSERT_NOT_NULL(test, yuv420_only_mode);
1510 KUNIT_ASSERT_TRUE(test, drm_mode_is_420_only(info, yuv420_only_mode));
1511
1512 rate = drm_hdmi_compute_mode_clock(yuv420_only_mode, 12, HDMI_COLORSPACE_YUV420);
1513 KUNIT_ASSERT_GT(test, rate, info->max_tmds_clock * 1000);
1514
1515 rate = drm_hdmi_compute_mode_clock(yuv420_only_mode, 10, HDMI_COLORSPACE_YUV420);
1516 KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
1517
1518 drm_modeset_acquire_init(&ctx, 0);
1519
1520 retry_conn_enable:
1521 ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn,
1522 yuv420_only_mode, &ctx);
1523 if (ret == -EDEADLK) {
1524 ret = drm_modeset_backoff(&ctx);
1525 if (!ret)
1526 goto retry_conn_enable;
1527 }
1528 KUNIT_EXPECT_EQ(test, ret, 0);
1529
1530 conn_state = conn->state;
1531 KUNIT_ASSERT_NOT_NULL(test, conn_state);
1532
1533 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 10);
1534 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_YUV420);
1535 KUNIT_EXPECT_EQ(test, conn_state->hdmi.tmds_char_rate, yuv420_only_mode->clock * 625);
1536
1537 drm_modeset_drop_locks(&ctx);
1538 drm_modeset_acquire_fini(&ctx);
1539 }
1540
1541 /*
1542 * Test that if:
1543 * - We have an HDMI connector supporting both RGB and YUV422 and up to
1544 * 12 bpc
1545 * - The chosen mode has a TMDS character rate higher than the display
1546 * supports in RGB/12bpc but lower than the display supports in
1547 * RGB/10bpc
1548 * - The chosen mode has a TMDS character rate lower than the display
1549 * supports in YUV422/12bpc.
1550 *
1551 * Then we will prefer to keep the RGB format with a lower bpc over
1552 * picking YUV422.
1553 */
drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv422(struct kunit * test)1554 static void drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv422(struct kunit *test)
1555 {
1556 struct drm_atomic_helper_connector_hdmi_priv *priv;
1557 struct drm_modeset_acquire_ctx ctx;
1558 struct drm_connector_state *conn_state;
1559 struct drm_display_info *info;
1560 struct drm_display_mode *preferred;
1561 unsigned long long rate;
1562 struct drm_connector *conn;
1563 struct drm_device *drm;
1564 struct drm_crtc *crtc;
1565 int ret;
1566
1567 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
1568 BIT(HDMI_COLORSPACE_RGB) |
1569 BIT(HDMI_COLORSPACE_YUV422) |
1570 BIT(HDMI_COLORSPACE_YUV444),
1571 12,
1572 &dummy_connector_hdmi_funcs,
1573 test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz);
1574 KUNIT_ASSERT_NOT_NULL(test, priv);
1575
1576 drm = &priv->drm;
1577 crtc = priv->crtc;
1578 conn = &priv->connector;
1579 info = &conn->display_info;
1580 KUNIT_ASSERT_TRUE(test, info->is_hdmi);
1581 KUNIT_ASSERT_GT(test, info->max_tmds_clock, 0);
1582
1583 preferred = find_preferred_mode(conn);
1584 KUNIT_ASSERT_NOT_NULL(test, preferred);
1585 KUNIT_ASSERT_FALSE(test, preferred->flags & DRM_MODE_FLAG_DBLCLK);
1586
1587 rate = drm_hdmi_compute_mode_clock(preferred, 10, HDMI_COLORSPACE_RGB);
1588 KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
1589
1590 rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_RGB);
1591 KUNIT_ASSERT_GT(test, rate, info->max_tmds_clock * 1000);
1592
1593 rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_YUV422);
1594 KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
1595
1596 drm_modeset_acquire_init(&ctx, 0);
1597
1598 retry_conn_enable:
1599 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
1600 crtc, conn,
1601 preferred,
1602 &ctx);
1603 if (ret == -EDEADLK) {
1604 ret = drm_modeset_backoff(&ctx);
1605 if (!ret)
1606 goto retry_conn_enable;
1607 }
1608 KUNIT_EXPECT_EQ(test, ret, 0);
1609
1610 conn_state = conn->state;
1611 KUNIT_ASSERT_NOT_NULL(test, conn_state);
1612
1613 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 10);
1614 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB);
1615
1616 drm_modeset_drop_locks(&ctx);
1617 drm_modeset_acquire_fini(&ctx);
1618 }
1619
1620 /*
1621 * Test that if:
1622 * - We have an HDMI connector supporting both RGB and YUV420 and up to
1623 * 12 bpc
1624 * - The chosen mode has a TMDS character rate higher than the display
1625 * supports in RGB/10bpc but lower than the display supports in
1626 * RGB/8bpc
1627 * - The chosen mode has a TMDS character rate lower than the display
1628 * supports in YUV420/12bpc.
1629 *
1630 * Then we will prefer to keep the RGB format with a lower bpc over
1631 * picking YUV420.
1632 */
drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv420(struct kunit * test)1633 static void drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv420(struct kunit *test)
1634 {
1635 struct drm_atomic_helper_connector_hdmi_priv *priv;
1636 struct drm_modeset_acquire_ctx ctx;
1637 struct drm_connector_state *conn_state;
1638 struct drm_display_info *info;
1639 struct drm_display_mode *preferred;
1640 unsigned long long rate;
1641 struct drm_connector *conn;
1642 struct drm_device *drm;
1643 struct drm_crtc *crtc;
1644 int ret;
1645
1646 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
1647 BIT(HDMI_COLORSPACE_RGB) |
1648 BIT(HDMI_COLORSPACE_YUV420),
1649 12,
1650 &dummy_connector_hdmi_funcs,
1651 test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz);
1652 KUNIT_ASSERT_NOT_NULL(test, priv);
1653
1654 drm = &priv->drm;
1655 crtc = priv->crtc;
1656 conn = &priv->connector;
1657 info = &conn->display_info;
1658 KUNIT_ASSERT_TRUE(test, info->is_hdmi);
1659 KUNIT_ASSERT_GT(test, info->max_tmds_clock, 0);
1660 KUNIT_ASSERT_TRUE(test, conn->ycbcr_420_allowed);
1661
1662 preferred = find_preferred_mode(conn);
1663 KUNIT_ASSERT_NOT_NULL(test, preferred);
1664 KUNIT_ASSERT_FALSE(test, preferred->flags & DRM_MODE_FLAG_DBLCLK);
1665 KUNIT_ASSERT_TRUE(test, drm_mode_is_420_also(info, preferred));
1666
1667 rate = drm_hdmi_compute_mode_clock(preferred, 8, HDMI_COLORSPACE_RGB);
1668 KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
1669
1670 rate = drm_hdmi_compute_mode_clock(preferred, 10, HDMI_COLORSPACE_RGB);
1671 KUNIT_ASSERT_GT(test, rate, info->max_tmds_clock * 1000);
1672
1673 rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_YUV420);
1674 KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
1675
1676 drm_modeset_acquire_init(&ctx, 0);
1677
1678 retry_conn_enable:
1679 ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn,
1680 preferred, &ctx);
1681 if (ret == -EDEADLK) {
1682 ret = drm_modeset_backoff(&ctx);
1683 if (!ret)
1684 goto retry_conn_enable;
1685 }
1686 KUNIT_EXPECT_EQ(test, ret, 0);
1687
1688 conn_state = conn->state;
1689 KUNIT_ASSERT_NOT_NULL(test, conn_state);
1690
1691 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 8);
1692 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB);
1693
1694 drm_modeset_drop_locks(&ctx);
1695 drm_modeset_acquire_fini(&ctx);
1696 }
1697
1698 /*
1699 * Test that if a driver supports only RGB, but the chosen mode can be
1700 * supported by the screen only in YUV420 output format, we end up with
1701 * unsuccessful fallback attempts.
1702 */
drm_test_check_driver_unsupported_fallback_yuv420(struct kunit * test)1703 static void drm_test_check_driver_unsupported_fallback_yuv420(struct kunit *test)
1704 {
1705 struct drm_atomic_helper_connector_hdmi_priv *priv;
1706 struct drm_modeset_acquire_ctx ctx;
1707 struct drm_connector_state *conn_state;
1708 struct drm_crtc_state *crtc_state;
1709 struct drm_atomic_state *state;
1710 struct drm_display_info *info;
1711 struct drm_display_mode *preferred, *yuv420_only_mode;
1712 struct drm_connector *conn;
1713 struct drm_device *drm;
1714 struct drm_crtc *crtc;
1715 int ret;
1716
1717 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
1718 BIT(HDMI_COLORSPACE_RGB),
1719 12,
1720 &dummy_connector_hdmi_funcs,
1721 test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz);
1722 KUNIT_ASSERT_NOT_NULL(test, priv);
1723
1724 drm = &priv->drm;
1725 crtc = priv->crtc;
1726 conn = &priv->connector;
1727 info = &conn->display_info;
1728 KUNIT_ASSERT_TRUE(test, info->is_hdmi);
1729 KUNIT_ASSERT_FALSE(test, conn->ycbcr_420_allowed);
1730
1731 preferred = find_preferred_mode(conn);
1732 KUNIT_ASSERT_NOT_NULL(test, preferred);
1733 KUNIT_ASSERT_FALSE(test, drm_mode_is_420_also(info, preferred));
1734
1735 yuv420_only_mode = drm_kunit_display_mode_from_cea_vic(test, drm, 95);
1736 KUNIT_ASSERT_NOT_NULL(test, yuv420_only_mode);
1737 KUNIT_ASSERT_TRUE(test, drm_mode_is_420_only(info, yuv420_only_mode));
1738
1739 drm_modeset_acquire_init(&ctx, 0);
1740
1741 retry_conn_enable:
1742 ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn,
1743 preferred, &ctx);
1744 if (ret == -EDEADLK) {
1745 ret = drm_modeset_backoff(&ctx);
1746 if (!ret)
1747 goto retry_conn_enable;
1748 }
1749 KUNIT_EXPECT_EQ(test, ret, 0);
1750
1751 conn_state = conn->state;
1752 KUNIT_ASSERT_NOT_NULL(test, conn_state);
1753 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB);
1754
1755 state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
1756 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
1757
1758 retry_crtc_state:
1759 crtc_state = drm_atomic_get_crtc_state(state, crtc);
1760 if (PTR_ERR(crtc_state) == -EDEADLK) {
1761 drm_atomic_state_clear(state);
1762 ret = drm_modeset_backoff(&ctx);
1763 if (!ret)
1764 goto retry_crtc_state;
1765 }
1766 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
1767
1768 ret = drm_atomic_set_mode_for_crtc(crtc_state, yuv420_only_mode);
1769 KUNIT_EXPECT_EQ(test, ret, 0);
1770
1771 ret = drm_atomic_check_only(state);
1772 if (ret == -EDEADLK) {
1773 drm_atomic_state_clear(state);
1774 ret = drm_modeset_backoff(&ctx);
1775 if (!ret)
1776 goto retry_crtc_state;
1777 }
1778 KUNIT_ASSERT_LT(test, ret, 0);
1779
1780 drm_modeset_drop_locks(&ctx);
1781 drm_modeset_acquire_fini(&ctx);
1782 }
1783
1784 /*
1785 * Test that if a driver and screen supports RGB and YUV formats, and we
1786 * try to set the VIC 1 mode, we end up with 8bpc RGB even if we could
1787 * have had a higher bpc.
1788 */
drm_test_check_output_bpc_format_vic_1(struct kunit * test)1789 static void drm_test_check_output_bpc_format_vic_1(struct kunit *test)
1790 {
1791 struct drm_atomic_helper_connector_hdmi_priv *priv;
1792 struct drm_modeset_acquire_ctx ctx;
1793 struct drm_connector_state *conn_state;
1794 struct drm_display_info *info;
1795 struct drm_display_mode *mode;
1796 unsigned long long rate;
1797 struct drm_connector *conn;
1798 struct drm_device *drm;
1799 struct drm_crtc *crtc;
1800 int ret;
1801
1802 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
1803 BIT(HDMI_COLORSPACE_RGB) |
1804 BIT(HDMI_COLORSPACE_YUV422) |
1805 BIT(HDMI_COLORSPACE_YUV444),
1806 12,
1807 &dummy_connector_hdmi_funcs,
1808 test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz);
1809 KUNIT_ASSERT_NOT_NULL(test, priv);
1810
1811 drm = &priv->drm;
1812 conn = &priv->connector;
1813 info = &conn->display_info;
1814 KUNIT_ASSERT_TRUE(test, info->is_hdmi);
1815 KUNIT_ASSERT_GT(test, info->max_tmds_clock, 0);
1816
1817 mode = drm_kunit_display_mode_from_cea_vic(test, drm, 1);
1818 KUNIT_ASSERT_NOT_NULL(test, mode);
1819
1820 /*
1821 * NOTE: We can't use drm_hdmi_compute_mode_clock()
1822 * here because we're trying to get the rate of an invalid
1823 * configuration.
1824 *
1825 * Thus, we have to calculate the rate by hand.
1826 */
1827 rate = mode->clock * 1500;
1828 KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
1829
1830 drm_modeset_acquire_init(&ctx, 0);
1831
1832 crtc = priv->crtc;
1833
1834 retry_conn_enable:
1835 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
1836 crtc, conn,
1837 mode,
1838 &ctx);
1839 if (ret == -EDEADLK) {
1840 ret = drm_modeset_backoff(&ctx);
1841 if (!ret)
1842 goto retry_conn_enable;
1843 }
1844 KUNIT_EXPECT_EQ(test, ret, 0);
1845
1846 conn_state = conn->state;
1847 KUNIT_ASSERT_NOT_NULL(test, conn_state);
1848
1849 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 8);
1850 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB);
1851
1852 drm_modeset_drop_locks(&ctx);
1853 drm_modeset_acquire_fini(&ctx);
1854 }
1855
1856 /*
1857 * Test that if a driver supports only RGB but the screen also supports
1858 * YUV formats, we only end up with an RGB format.
1859 */
drm_test_check_output_bpc_format_driver_rgb_only(struct kunit * test)1860 static void drm_test_check_output_bpc_format_driver_rgb_only(struct kunit *test)
1861 {
1862 struct drm_atomic_helper_connector_hdmi_priv *priv;
1863 struct drm_modeset_acquire_ctx ctx;
1864 struct drm_connector_state *conn_state;
1865 struct drm_display_info *info;
1866 struct drm_display_mode *preferred;
1867 unsigned long long rate;
1868 struct drm_connector *conn;
1869 struct drm_device *drm;
1870 struct drm_crtc *crtc;
1871 int ret;
1872
1873 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
1874 BIT(HDMI_COLORSPACE_RGB),
1875 12,
1876 &dummy_connector_hdmi_funcs,
1877 test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz);
1878 KUNIT_ASSERT_NOT_NULL(test, priv);
1879
1880 drm = &priv->drm;
1881 crtc = priv->crtc;
1882 conn = &priv->connector;
1883 info = &conn->display_info;
1884 KUNIT_ASSERT_TRUE(test, info->is_hdmi);
1885 KUNIT_ASSERT_GT(test, info->max_tmds_clock, 0);
1886
1887 preferred = find_preferred_mode(conn);
1888 KUNIT_ASSERT_NOT_NULL(test, preferred);
1889
1890 /*
1891 * We're making sure that YUV422 would be the preferred option
1892 * here: we're always favouring higher bpc, we can't have RGB
1893 * because the TMDS character rate exceeds the maximum supported
1894 * by the display, and YUV422 works for that display.
1895 *
1896 * But since the driver only supports RGB, we should fallback to
1897 * a lower bpc with RGB.
1898 */
1899 rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_RGB);
1900 KUNIT_ASSERT_GT(test, rate, info->max_tmds_clock * 1000);
1901
1902 rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_YUV422);
1903 KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
1904
1905 drm_modeset_acquire_init(&ctx, 0);
1906
1907 retry_conn_enable:
1908 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
1909 crtc, conn,
1910 preferred,
1911 &ctx);
1912 if (ret == -EDEADLK) {
1913 ret = drm_modeset_backoff(&ctx);
1914 if (!ret)
1915 goto retry_conn_enable;
1916 }
1917 KUNIT_EXPECT_EQ(test, ret, 0);
1918
1919 conn_state = conn->state;
1920 KUNIT_ASSERT_NOT_NULL(test, conn_state);
1921
1922 KUNIT_EXPECT_LT(test, conn_state->hdmi.output_bpc, 12);
1923 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB);
1924
1925 drm_modeset_drop_locks(&ctx);
1926 drm_modeset_acquire_fini(&ctx);
1927 }
1928
1929 /*
1930 * Test that if a screen supports only RGB but the driver also supports
1931 * YUV formats, we only end up with an RGB format.
1932 */
drm_test_check_output_bpc_format_display_rgb_only(struct kunit * test)1933 static void drm_test_check_output_bpc_format_display_rgb_only(struct kunit *test)
1934 {
1935 struct drm_atomic_helper_connector_hdmi_priv *priv;
1936 struct drm_modeset_acquire_ctx ctx;
1937 struct drm_connector_state *conn_state;
1938 struct drm_display_info *info;
1939 struct drm_display_mode *preferred;
1940 unsigned long long rate;
1941 struct drm_connector *conn;
1942 struct drm_device *drm;
1943 struct drm_crtc *crtc;
1944 int ret;
1945
1946 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
1947 BIT(HDMI_COLORSPACE_RGB) |
1948 BIT(HDMI_COLORSPACE_YUV422) |
1949 BIT(HDMI_COLORSPACE_YUV444),
1950 12,
1951 &dummy_connector_hdmi_funcs,
1952 test_edid_hdmi_1080p_rgb_max_200mhz);
1953 KUNIT_ASSERT_NOT_NULL(test, priv);
1954
1955 drm = &priv->drm;
1956 crtc = priv->crtc;
1957 conn = &priv->connector;
1958 info = &conn->display_info;
1959 KUNIT_ASSERT_TRUE(test, info->is_hdmi);
1960 KUNIT_ASSERT_GT(test, info->max_tmds_clock, 0);
1961
1962 preferred = find_preferred_mode(conn);
1963 KUNIT_ASSERT_NOT_NULL(test, preferred);
1964
1965 /*
1966 * We're making sure that YUV422 would be the preferred option
1967 * here: we're always favouring higher bpc, we can't have RGB
1968 * because the TMDS character rate exceeds the maximum supported
1969 * by the display, and YUV422 works for that display.
1970 *
1971 * But since the display only supports RGB, we should fallback to
1972 * a lower bpc with RGB.
1973 */
1974 rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_RGB);
1975 KUNIT_ASSERT_GT(test, rate, info->max_tmds_clock * 1000);
1976
1977 rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_YUV422);
1978 KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
1979
1980 drm_modeset_acquire_init(&ctx, 0);
1981
1982 retry_conn_enable:
1983 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
1984 crtc, conn,
1985 preferred,
1986 &ctx);
1987 if (ret == -EDEADLK) {
1988 ret = drm_modeset_backoff(&ctx);
1989 if (!ret)
1990 goto retry_conn_enable;
1991 }
1992 KUNIT_EXPECT_EQ(test, ret, 0);
1993
1994 conn_state = conn->state;
1995 KUNIT_ASSERT_NOT_NULL(test, conn_state);
1996
1997 KUNIT_EXPECT_LT(test, conn_state->hdmi.output_bpc, 12);
1998 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB);
1999
2000 drm_modeset_drop_locks(&ctx);
2001 drm_modeset_acquire_fini(&ctx);
2002 }
2003
2004 /*
2005 * Test that if a display supports higher bpc but the driver only
2006 * supports 8 bpc, we only end up with 8 bpc even if we could have had a
2007 * higher bpc.
2008 */
drm_test_check_output_bpc_format_driver_8bpc_only(struct kunit * test)2009 static void drm_test_check_output_bpc_format_driver_8bpc_only(struct kunit *test)
2010 {
2011 struct drm_atomic_helper_connector_hdmi_priv *priv;
2012 struct drm_modeset_acquire_ctx ctx;
2013 struct drm_connector_state *conn_state;
2014 struct drm_display_info *info;
2015 struct drm_display_mode *preferred;
2016 unsigned long long rate;
2017 struct drm_connector *conn;
2018 struct drm_device *drm;
2019 struct drm_crtc *crtc;
2020 int ret;
2021
2022 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
2023 BIT(HDMI_COLORSPACE_RGB),
2024 8,
2025 &dummy_connector_hdmi_funcs,
2026 test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz);
2027 KUNIT_ASSERT_NOT_NULL(test, priv);
2028
2029 drm = &priv->drm;
2030 crtc = priv->crtc;
2031 conn = &priv->connector;
2032 info = &conn->display_info;
2033 KUNIT_ASSERT_TRUE(test, info->is_hdmi);
2034 KUNIT_ASSERT_GT(test, info->max_tmds_clock, 0);
2035
2036 preferred = find_preferred_mode(conn);
2037 KUNIT_ASSERT_NOT_NULL(test, preferred);
2038
2039 /*
2040 * We're making sure that we have headroom on the TMDS character
2041 * clock to actually use 12bpc.
2042 */
2043 rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_RGB);
2044 KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
2045
2046 drm_modeset_acquire_init(&ctx, 0);
2047
2048 retry_conn_enable:
2049 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
2050 crtc, conn,
2051 preferred,
2052 &ctx);
2053 if (ret == -EDEADLK) {
2054 ret = drm_modeset_backoff(&ctx);
2055 if (!ret)
2056 goto retry_conn_enable;
2057 }
2058 KUNIT_EXPECT_EQ(test, ret, 0);
2059
2060 conn_state = conn->state;
2061 KUNIT_ASSERT_NOT_NULL(test, conn_state);
2062
2063 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 8);
2064 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB);
2065
2066 drm_modeset_drop_locks(&ctx);
2067 drm_modeset_acquire_fini(&ctx);
2068 }
2069
2070 /*
2071 * Test that if a driver supports higher bpc but the display only
2072 * supports 8 bpc, we only end up with 8 bpc even if we could have had a
2073 * higher bpc.
2074 */
drm_test_check_output_bpc_format_display_8bpc_only(struct kunit * test)2075 static void drm_test_check_output_bpc_format_display_8bpc_only(struct kunit *test)
2076 {
2077 struct drm_atomic_helper_connector_hdmi_priv *priv;
2078 struct drm_modeset_acquire_ctx ctx;
2079 struct drm_connector_state *conn_state;
2080 struct drm_display_info *info;
2081 struct drm_display_mode *preferred;
2082 unsigned long long rate;
2083 struct drm_connector *conn;
2084 struct drm_device *drm;
2085 struct drm_crtc *crtc;
2086 int ret;
2087
2088 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
2089 BIT(HDMI_COLORSPACE_RGB) |
2090 BIT(HDMI_COLORSPACE_YUV422) |
2091 BIT(HDMI_COLORSPACE_YUV444),
2092 12,
2093 &dummy_connector_hdmi_funcs,
2094 test_edid_hdmi_1080p_rgb_max_340mhz);
2095 KUNIT_ASSERT_NOT_NULL(test, priv);
2096
2097 drm = &priv->drm;
2098 crtc = priv->crtc;
2099 conn = &priv->connector;
2100 info = &conn->display_info;
2101 KUNIT_ASSERT_TRUE(test, info->is_hdmi);
2102 KUNIT_ASSERT_GT(test, info->max_tmds_clock, 0);
2103
2104 preferred = find_preferred_mode(conn);
2105 KUNIT_ASSERT_NOT_NULL(test, preferred);
2106
2107 /*
2108 * We're making sure that we have headroom on the TMDS character
2109 * clock to actually use 12bpc.
2110 */
2111 rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_RGB);
2112 KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
2113
2114 drm_modeset_acquire_init(&ctx, 0);
2115
2116 retry_conn_enable:
2117 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
2118 crtc, conn,
2119 preferred,
2120 &ctx);
2121 if (ret == -EDEADLK) {
2122 ret = drm_modeset_backoff(&ctx);
2123 if (!ret)
2124 goto retry_conn_enable;
2125 }
2126 KUNIT_EXPECT_EQ(test, ret, 0);
2127
2128 conn_state = conn->state;
2129 KUNIT_ASSERT_NOT_NULL(test, conn_state);
2130
2131 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 8);
2132 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB);
2133
2134 drm_modeset_drop_locks(&ctx);
2135 drm_modeset_acquire_fini(&ctx);
2136 }
2137
2138 /* Test that atomic check succeeds when disabling a connector. */
drm_test_check_disable_connector(struct kunit * test)2139 static void drm_test_check_disable_connector(struct kunit *test)
2140 {
2141 struct drm_atomic_helper_connector_hdmi_priv *priv;
2142 struct drm_modeset_acquire_ctx ctx;
2143 struct drm_connector_state *conn_state;
2144 struct drm_crtc_state *crtc_state;
2145 struct drm_atomic_state *state;
2146 struct drm_display_mode *preferred;
2147 struct drm_connector *conn;
2148 struct drm_device *drm;
2149 struct drm_crtc *crtc;
2150 int ret;
2151
2152 priv = drm_kunit_helper_connector_hdmi_init(test,
2153 BIT(HDMI_COLORSPACE_RGB),
2154 8);
2155 KUNIT_ASSERT_NOT_NULL(test, priv);
2156
2157 drm_modeset_acquire_init(&ctx, 0);
2158
2159 conn = &priv->connector;
2160 preferred = find_preferred_mode(conn);
2161 KUNIT_ASSERT_NOT_NULL(test, preferred);
2162
2163 drm = &priv->drm;
2164 crtc = priv->crtc;
2165
2166 retry_conn_enable:
2167 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
2168 crtc, conn,
2169 preferred,
2170 &ctx);
2171 if (ret == -EDEADLK) {
2172 ret = drm_modeset_backoff(&ctx);
2173 if (!ret)
2174 goto retry_conn_enable;
2175 }
2176 KUNIT_ASSERT_EQ(test, ret, 0);
2177
2178 state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
2179 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
2180
2181 crtc_state = drm_atomic_get_crtc_state(state, crtc);
2182 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
2183
2184 crtc_state->active = false;
2185 ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL);
2186 KUNIT_EXPECT_EQ(test, ret, 0);
2187
2188 conn_state = drm_atomic_get_connector_state(state, conn);
2189 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
2190
2191 ret = drm_atomic_set_crtc_for_connector(conn_state, NULL);
2192 KUNIT_EXPECT_EQ(test, ret, 0);
2193
2194 ret = drm_atomic_check_only(state);
2195 KUNIT_ASSERT_EQ(test, ret, 0);
2196
2197 drm_modeset_drop_locks(&ctx);
2198 drm_modeset_acquire_fini(&ctx);
2199 }
2200
2201 static struct kunit_case drm_atomic_helper_connector_hdmi_check_tests[] = {
2202 KUNIT_CASE(drm_test_check_broadcast_rgb_auto_cea_mode),
2203 KUNIT_CASE(drm_test_check_broadcast_rgb_auto_cea_mode_vic_1),
2204 KUNIT_CASE(drm_test_check_broadcast_rgb_full_cea_mode),
2205 KUNIT_CASE(drm_test_check_broadcast_rgb_full_cea_mode_vic_1),
2206 KUNIT_CASE(drm_test_check_broadcast_rgb_limited_cea_mode),
2207 KUNIT_CASE(drm_test_check_broadcast_rgb_limited_cea_mode_vic_1),
2208 KUNIT_CASE_PARAM(drm_test_check_broadcast_rgb_cea_mode_yuv420,
2209 check_broadcast_rgb_cea_mode_yuv420_gen_params),
2210 KUNIT_CASE(drm_test_check_broadcast_rgb_crtc_mode_changed),
2211 KUNIT_CASE(drm_test_check_broadcast_rgb_crtc_mode_not_changed),
2212 KUNIT_CASE(drm_test_check_disable_connector),
2213 KUNIT_CASE(drm_test_check_hdmi_funcs_reject_rate),
2214 KUNIT_CASE(drm_test_check_max_tmds_rate_bpc_fallback_rgb),
2215 KUNIT_CASE(drm_test_check_max_tmds_rate_bpc_fallback_yuv420),
2216 KUNIT_CASE(drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv422),
2217 KUNIT_CASE(drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv420),
2218 KUNIT_CASE(drm_test_check_driver_unsupported_fallback_yuv420),
2219 KUNIT_CASE(drm_test_check_output_bpc_crtc_mode_changed),
2220 KUNIT_CASE(drm_test_check_output_bpc_crtc_mode_not_changed),
2221 KUNIT_CASE(drm_test_check_output_bpc_dvi),
2222 KUNIT_CASE(drm_test_check_output_bpc_format_vic_1),
2223 KUNIT_CASE(drm_test_check_output_bpc_format_display_8bpc_only),
2224 KUNIT_CASE(drm_test_check_output_bpc_format_display_rgb_only),
2225 KUNIT_CASE(drm_test_check_output_bpc_format_driver_8bpc_only),
2226 KUNIT_CASE(drm_test_check_output_bpc_format_driver_rgb_only),
2227 KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_8bpc),
2228 KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_10bpc),
2229 KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_12bpc),
2230 /*
2231 * TODO: We should have tests to check that a change in the
2232 * format triggers a CRTC mode change just like we do for the
2233 * RGB Quantization and BPC.
2234 *
2235 * However, we don't have any way to control which format gets
2236 * picked up aside from changing the BPC or mode which would
2237 * already trigger a mode change.
2238 */
2239 { }
2240 };
2241
2242 static struct kunit_suite drm_atomic_helper_connector_hdmi_check_test_suite = {
2243 .name = "drm_atomic_helper_connector_hdmi_check",
2244 .test_cases = drm_atomic_helper_connector_hdmi_check_tests,
2245 };
2246
2247 /*
2248 * Test that the value of the Broadcast RGB property out of reset is set
2249 * to auto.
2250 */
drm_test_check_broadcast_rgb_value(struct kunit * test)2251 static void drm_test_check_broadcast_rgb_value(struct kunit *test)
2252 {
2253 struct drm_atomic_helper_connector_hdmi_priv *priv;
2254 struct drm_connector_state *conn_state;
2255 struct drm_connector *conn;
2256
2257 priv = drm_kunit_helper_connector_hdmi_init(test,
2258 BIT(HDMI_COLORSPACE_RGB),
2259 8);
2260 KUNIT_ASSERT_NOT_NULL(test, priv);
2261
2262 conn = &priv->connector;
2263 conn_state = conn->state;
2264 KUNIT_EXPECT_EQ(test, conn_state->hdmi.broadcast_rgb, DRM_HDMI_BROADCAST_RGB_AUTO);
2265 }
2266
2267 /*
2268 * Test that if the connector was initialised with a maximum bpc of 8,
2269 * the value of the max_bpc and max_requested_bpc properties out of
2270 * reset are also set to 8, and output_bpc is set to 0 and will be
2271 * filled at atomic_check time.
2272 */
drm_test_check_bpc_8_value(struct kunit * test)2273 static void drm_test_check_bpc_8_value(struct kunit *test)
2274 {
2275 struct drm_atomic_helper_connector_hdmi_priv *priv;
2276 struct drm_connector_state *conn_state;
2277 struct drm_connector *conn;
2278
2279 priv = drm_kunit_helper_connector_hdmi_init(test,
2280 BIT(HDMI_COLORSPACE_RGB),
2281 8);
2282 KUNIT_ASSERT_NOT_NULL(test, priv);
2283
2284 conn = &priv->connector;
2285 conn_state = conn->state;
2286 KUNIT_EXPECT_EQ(test, conn_state->max_bpc, 8);
2287 KUNIT_EXPECT_EQ(test, conn_state->max_requested_bpc, 8);
2288 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 0);
2289 }
2290
2291 /*
2292 * Test that if the connector was initialised with a maximum bpc of 10,
2293 * the value of the max_bpc and max_requested_bpc properties out of
2294 * reset are also set to 10, and output_bpc is set to 0 and will be
2295 * filled at atomic_check time.
2296 */
drm_test_check_bpc_10_value(struct kunit * test)2297 static void drm_test_check_bpc_10_value(struct kunit *test)
2298 {
2299 struct drm_atomic_helper_connector_hdmi_priv *priv;
2300 struct drm_connector_state *conn_state;
2301 struct drm_connector *conn;
2302
2303 priv = drm_kunit_helper_connector_hdmi_init(test,
2304 BIT(HDMI_COLORSPACE_RGB),
2305 10);
2306 KUNIT_ASSERT_NOT_NULL(test, priv);
2307
2308 conn = &priv->connector;
2309 conn_state = conn->state;
2310 KUNIT_EXPECT_EQ(test, conn_state->max_bpc, 10);
2311 KUNIT_EXPECT_EQ(test, conn_state->max_requested_bpc, 10);
2312 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 0);
2313 }
2314
2315 /*
2316 * Test that if the connector was initialised with a maximum bpc of 12,
2317 * the value of the max_bpc and max_requested_bpc properties out of
2318 * reset are also set to 12, and output_bpc is set to 0 and will be
2319 * filled at atomic_check time.
2320 */
drm_test_check_bpc_12_value(struct kunit * test)2321 static void drm_test_check_bpc_12_value(struct kunit *test)
2322 {
2323 struct drm_atomic_helper_connector_hdmi_priv *priv;
2324 struct drm_connector_state *conn_state;
2325 struct drm_connector *conn;
2326
2327 priv = drm_kunit_helper_connector_hdmi_init(test,
2328 BIT(HDMI_COLORSPACE_RGB),
2329 12);
2330 KUNIT_ASSERT_NOT_NULL(test, priv);
2331
2332 conn = &priv->connector;
2333 conn_state = conn->state;
2334 KUNIT_EXPECT_EQ(test, conn_state->max_bpc, 12);
2335 KUNIT_EXPECT_EQ(test, conn_state->max_requested_bpc, 12);
2336 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 0);
2337 }
2338
2339 /*
2340 * Test that the value of the output format property out of reset is set
2341 * to RGB, even if the driver supports more than that.
2342 */
drm_test_check_format_value(struct kunit * test)2343 static void drm_test_check_format_value(struct kunit *test)
2344 {
2345 struct drm_atomic_helper_connector_hdmi_priv *priv;
2346 struct drm_connector_state *conn_state;
2347 struct drm_connector *conn;
2348
2349 priv = drm_kunit_helper_connector_hdmi_init(test,
2350 BIT(HDMI_COLORSPACE_RGB) |
2351 BIT(HDMI_COLORSPACE_YUV422) |
2352 BIT(HDMI_COLORSPACE_YUV444),
2353 8);
2354 KUNIT_ASSERT_NOT_NULL(test, priv);
2355
2356 conn = &priv->connector;
2357 conn_state = conn->state;
2358 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, 0);
2359 }
2360
2361 /*
2362 * Test that the value of the output format property out of reset is set
2363 * to 0, and will be computed at atomic_check time.
2364 */
drm_test_check_tmds_char_value(struct kunit * test)2365 static void drm_test_check_tmds_char_value(struct kunit *test)
2366 {
2367 struct drm_atomic_helper_connector_hdmi_priv *priv;
2368 struct drm_connector_state *conn_state;
2369 struct drm_connector *conn;
2370
2371 priv = drm_kunit_helper_connector_hdmi_init(test,
2372 BIT(HDMI_COLORSPACE_RGB) |
2373 BIT(HDMI_COLORSPACE_YUV422) |
2374 BIT(HDMI_COLORSPACE_YUV444),
2375 12);
2376 KUNIT_ASSERT_NOT_NULL(test, priv);
2377
2378 conn = &priv->connector;
2379 conn_state = conn->state;
2380 KUNIT_EXPECT_EQ(test, conn_state->hdmi.tmds_char_rate, 0);
2381 }
2382
2383 static struct kunit_case drm_atomic_helper_connector_hdmi_reset_tests[] = {
2384 KUNIT_CASE(drm_test_check_broadcast_rgb_value),
2385 KUNIT_CASE(drm_test_check_bpc_8_value),
2386 KUNIT_CASE(drm_test_check_bpc_10_value),
2387 KUNIT_CASE(drm_test_check_bpc_12_value),
2388 KUNIT_CASE(drm_test_check_format_value),
2389 KUNIT_CASE(drm_test_check_tmds_char_value),
2390 { }
2391 };
2392
2393 static struct kunit_suite drm_atomic_helper_connector_hdmi_reset_test_suite = {
2394 .name = "drm_atomic_helper_connector_hdmi_reset",
2395 .test_cases = drm_atomic_helper_connector_hdmi_reset_tests,
2396 };
2397
2398 /*
2399 * Test that the default behaviour for drm_hdmi_connector_mode_valid() is not
2400 * to reject any modes. Pass a correct EDID and verify that preferred mode
2401 * matches the expectations (1080p).
2402 */
drm_test_check_mode_valid(struct kunit * test)2403 static void drm_test_check_mode_valid(struct kunit *test)
2404 {
2405 struct drm_atomic_helper_connector_hdmi_priv *priv;
2406 struct drm_connector *conn;
2407 struct drm_display_mode *preferred;
2408
2409 priv = drm_kunit_helper_connector_hdmi_init(test,
2410 BIT(HDMI_COLORSPACE_RGB),
2411 8);
2412 KUNIT_ASSERT_NOT_NULL(test, priv);
2413
2414 conn = &priv->connector;
2415 preferred = find_preferred_mode(conn);
2416 KUNIT_ASSERT_NOT_NULL(test, preferred);
2417
2418 KUNIT_EXPECT_EQ(test, preferred->hdisplay, 1920);
2419 KUNIT_EXPECT_EQ(test, preferred->vdisplay, 1080);
2420 KUNIT_EXPECT_EQ(test, preferred->clock, 148500);
2421 }
2422
2423 /*
2424 * Test that the drm_hdmi_connector_mode_valid() will reject modes depending on
2425 * the .tmds_char_rate_valid() behaviour.
2426 * Pass a correct EDID and verify that high-rate modes are filtered.
2427 */
drm_test_check_mode_valid_reject_rate(struct kunit * test)2428 static void drm_test_check_mode_valid_reject_rate(struct kunit *test)
2429 {
2430 struct drm_atomic_helper_connector_hdmi_priv *priv;
2431 struct drm_display_mode *preferred;
2432
2433 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
2434 BIT(HDMI_COLORSPACE_RGB),
2435 8,
2436 &reject_100mhz_connector_hdmi_funcs,
2437 test_edid_hdmi_1080p_rgb_max_200mhz);
2438 KUNIT_ASSERT_NOT_NULL(test, priv);
2439
2440 /*
2441 * Unlike the drm_test_check_mode_valid() here 1080p is rejected, but
2442 * 480p is allowed.
2443 */
2444 preferred = find_preferred_mode(&priv->connector);
2445 KUNIT_ASSERT_NOT_NULL(test, preferred);
2446 KUNIT_EXPECT_EQ(test, preferred->hdisplay, 640);
2447 KUNIT_EXPECT_EQ(test, preferred->vdisplay, 480);
2448 KUNIT_EXPECT_EQ(test, preferred->clock, 25200);
2449 }
2450
2451 /*
2452 * Test that the drm_hdmi_connector_mode_valid() will not mark any modes as
2453 * valid if .tmds_char_rate_valid() rejects all of them. Pass a correct EDID
2454 * and verify that there is no preferred mode and no modes were set for the
2455 * connector.
2456 */
drm_test_check_mode_valid_reject(struct kunit * test)2457 static void drm_test_check_mode_valid_reject(struct kunit *test)
2458 {
2459 struct drm_atomic_helper_connector_hdmi_priv *priv;
2460 struct drm_connector *conn;
2461 struct drm_display_mode *preferred;
2462 unsigned char no_edid[] = {};
2463 int ret;
2464
2465 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
2466 BIT(HDMI_COLORSPACE_RGB),
2467 8,
2468 &reject_connector_hdmi_funcs,
2469 no_edid);
2470 KUNIT_ASSERT_NOT_NULL(test, priv);
2471
2472 conn = &priv->connector;
2473
2474 /* should reject all modes */
2475 ret = set_connector_edid(test, conn,
2476 test_edid_hdmi_1080p_rgb_max_200mhz,
2477 ARRAY_SIZE(test_edid_hdmi_1080p_rgb_max_200mhz));
2478 KUNIT_ASSERT_EQ(test, ret, 0);
2479
2480 preferred = find_preferred_mode(conn);
2481 KUNIT_ASSERT_NULL(test, preferred);
2482 }
2483
2484 /*
2485 * Test that the drm_hdmi_connector_mode_valid() will reject modes that don't
2486 * pass the info.max_tmds_clock filter. Pass crafted EDID and verify that
2487 * high-rate modes are filtered.
2488 */
drm_test_check_mode_valid_reject_max_clock(struct kunit * test)2489 static void drm_test_check_mode_valid_reject_max_clock(struct kunit *test)
2490 {
2491 struct drm_atomic_helper_connector_hdmi_priv *priv;
2492 struct drm_connector *conn;
2493 struct drm_display_mode *preferred;
2494
2495 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
2496 BIT(HDMI_COLORSPACE_RGB),
2497 8,
2498 &dummy_connector_hdmi_funcs,
2499 test_edid_hdmi_1080p_rgb_max_100mhz);
2500 KUNIT_ASSERT_NOT_NULL(test, priv);
2501
2502 conn = &priv->connector;
2503 KUNIT_ASSERT_EQ(test, conn->display_info.max_tmds_clock, 100 * 1000);
2504
2505 preferred = find_preferred_mode(conn);
2506 KUNIT_ASSERT_NOT_NULL(test, preferred);
2507 KUNIT_EXPECT_EQ(test, preferred->hdisplay, 640);
2508 KUNIT_EXPECT_EQ(test, preferred->vdisplay, 480);
2509 KUNIT_EXPECT_EQ(test, preferred->clock, 25200);
2510 }
2511
2512 static struct kunit_case drm_atomic_helper_connector_hdmi_mode_valid_tests[] = {
2513 KUNIT_CASE(drm_test_check_mode_valid),
2514 KUNIT_CASE(drm_test_check_mode_valid_reject),
2515 KUNIT_CASE(drm_test_check_mode_valid_reject_rate),
2516 KUNIT_CASE(drm_test_check_mode_valid_reject_max_clock),
2517 { }
2518 };
2519
2520 static struct kunit_suite drm_atomic_helper_connector_hdmi_mode_valid_test_suite = {
2521 .name = "drm_atomic_helper_connector_hdmi_mode_valid",
2522 .test_cases = drm_atomic_helper_connector_hdmi_mode_valid_tests,
2523 };
2524
2525 /*
2526 * Test that the default behaviour works without errors. We expect that
2527 * infoframe-related hooks are called and there are no errors raised.
2528 */
drm_test_check_infoframes(struct kunit * test)2529 static void drm_test_check_infoframes(struct kunit *test)
2530 {
2531 struct drm_atomic_helper_connector_hdmi_priv *priv;
2532 struct drm_modeset_acquire_ctx ctx;
2533 struct drm_crtc_state *crtc_state;
2534 struct drm_atomic_state *state;
2535 struct drm_display_mode *preferred;
2536 struct drm_connector *conn;
2537 struct drm_device *drm;
2538 struct drm_crtc *crtc;
2539 int old_hdmi_update_failures;
2540 int ret;
2541
2542 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
2543 BIT(HDMI_COLORSPACE_RGB),
2544 8,
2545 &dummy_connector_hdmi_funcs,
2546 test_edid_hdmi_1080p_rgb_max_200mhz);
2547 KUNIT_ASSERT_NOT_NULL(test, priv);
2548
2549 drm = &priv->drm;
2550 crtc = priv->crtc;
2551 conn = &priv->connector;
2552
2553 preferred = find_preferred_mode(conn);
2554 KUNIT_ASSERT_NOT_NULL(test, preferred);
2555
2556 drm_modeset_acquire_init(&ctx, 0);
2557
2558 retry_conn_enable:
2559 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
2560 crtc, conn,
2561 preferred,
2562 &ctx);
2563 if (ret == -EDEADLK) {
2564 ret = drm_modeset_backoff(&ctx);
2565 if (!ret)
2566 goto retry_conn_enable;
2567 }
2568 KUNIT_ASSERT_EQ(test, ret, 0);
2569
2570 state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
2571 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
2572
2573 retry_crtc_state:
2574 crtc_state = drm_atomic_get_crtc_state(state, crtc);
2575 if (PTR_ERR(crtc_state) == -EDEADLK) {
2576 drm_atomic_state_clear(state);
2577 ret = drm_modeset_backoff(&ctx);
2578 if (!ret)
2579 goto retry_crtc_state;
2580 }
2581 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
2582
2583 crtc_state->mode_changed = true;
2584
2585 old_hdmi_update_failures = priv->hdmi_update_failures;
2586
2587 ret = drm_atomic_check_only(state);
2588 if (ret == -EDEADLK) {
2589 drm_atomic_state_clear(state);
2590 ret = drm_modeset_backoff(&ctx);
2591 if (!ret)
2592 goto retry_crtc_state;
2593 }
2594 KUNIT_ASSERT_EQ(test, ret, 0);
2595
2596 ret = drm_atomic_commit(state);
2597 if (ret == -EDEADLK) {
2598 drm_atomic_state_clear(state);
2599 ret = drm_modeset_backoff(&ctx);
2600 if (!ret)
2601 goto retry_crtc_state;
2602 }
2603 KUNIT_ASSERT_EQ(test, ret, 0);
2604
2605 KUNIT_EXPECT_GE(test, old_hdmi_update_failures, priv->hdmi_update_failures);
2606
2607 drm_modeset_drop_locks(&ctx);
2608 drm_modeset_acquire_fini(&ctx);
2609 }
2610
reject_infoframe_write_infoframe(struct drm_connector * connector,const u8 * buffer,size_t len)2611 static int reject_infoframe_write_infoframe(struct drm_connector *connector,
2612 const u8 *buffer, size_t len)
2613 {
2614 return -EOPNOTSUPP;
2615 }
2616
2617 static const struct drm_connector_hdmi_funcs reject_avi_infoframe_hdmi_funcs = {
2618 .avi = {
2619 .clear_infoframe = accept_infoframe_clear_infoframe,
2620 .write_infoframe = reject_infoframe_write_infoframe,
2621 },
2622 .hdmi = {
2623 .clear_infoframe = accept_infoframe_clear_infoframe,
2624 .write_infoframe = accept_infoframe_write_infoframe,
2625 },
2626 };
2627
2628 /*
2629 * Test that the rejection of AVI InfoFrame results in the failure of
2630 * drm_atomic_helper_connector_hdmi_update_infoframes().
2631 */
drm_test_check_reject_avi_infoframe(struct kunit * test)2632 static void drm_test_check_reject_avi_infoframe(struct kunit *test)
2633 {
2634 struct drm_atomic_helper_connector_hdmi_priv *priv;
2635 struct drm_modeset_acquire_ctx ctx;
2636 struct drm_atomic_state *state;
2637 struct drm_crtc_state *crtc_state;
2638 struct drm_display_mode *preferred;
2639 struct drm_connector *conn;
2640 struct drm_device *drm;
2641 struct drm_crtc *crtc;
2642 int old_hdmi_update_failures;
2643 int ret;
2644
2645 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
2646 BIT(HDMI_COLORSPACE_RGB),
2647 8,
2648 &reject_avi_infoframe_hdmi_funcs,
2649 test_edid_hdmi_1080p_rgb_max_200mhz);
2650 KUNIT_ASSERT_NOT_NULL(test, priv);
2651
2652 drm = &priv->drm;
2653 crtc = priv->crtc;
2654 conn = &priv->connector;
2655
2656 preferred = find_preferred_mode(conn);
2657 KUNIT_ASSERT_NOT_NULL(test, preferred);
2658
2659 drm_modeset_acquire_init(&ctx, 0);
2660
2661 retry_conn_enable:
2662 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
2663 crtc, conn,
2664 preferred,
2665 &ctx);
2666 if (ret == -EDEADLK) {
2667 ret = drm_modeset_backoff(&ctx);
2668 if (!ret)
2669 goto retry_conn_enable;
2670 }
2671 KUNIT_ASSERT_EQ(test, ret, 0);
2672
2673 drm_encoder_helper_add(&priv->encoder, &test_encoder_helper_funcs);
2674
2675 state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
2676 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
2677
2678 retry_crtc_state:
2679 crtc_state = drm_atomic_get_crtc_state(state, crtc);
2680 if (PTR_ERR(crtc_state) == -EDEADLK) {
2681 drm_atomic_state_clear(state);
2682 ret = drm_modeset_backoff(&ctx);
2683 if (!ret)
2684 goto retry_crtc_state;
2685 }
2686 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
2687
2688 crtc_state->mode_changed = true;
2689
2690 old_hdmi_update_failures = priv->hdmi_update_failures;
2691
2692 ret = drm_atomic_check_only(state);
2693 if (ret == -EDEADLK) {
2694 drm_atomic_state_clear(state);
2695 ret = drm_modeset_backoff(&ctx);
2696 if (!ret)
2697 goto retry_crtc_state;
2698 }
2699 KUNIT_ASSERT_EQ(test, ret, 0);
2700
2701 ret = drm_atomic_commit(state);
2702 if (ret == -EDEADLK) {
2703 drm_atomic_state_clear(state);
2704 ret = drm_modeset_backoff(&ctx);
2705 if (!ret)
2706 goto retry_crtc_state;
2707 }
2708 KUNIT_ASSERT_EQ(test, ret, 0);
2709
2710 KUNIT_EXPECT_NE(test, old_hdmi_update_failures, priv->hdmi_update_failures);
2711
2712 drm_modeset_drop_locks(&ctx);
2713 drm_modeset_acquire_fini(&ctx);
2714 }
2715
2716 static const struct drm_connector_hdmi_funcs reject_hdr_infoframe_hdmi_funcs = {
2717 .avi = {
2718 .clear_infoframe = accept_infoframe_clear_infoframe,
2719 .write_infoframe = accept_infoframe_write_infoframe,
2720 },
2721 .hdmi = {
2722 .clear_infoframe = accept_infoframe_clear_infoframe,
2723 .write_infoframe = accept_infoframe_write_infoframe,
2724 },
2725 .hdr_drm = {
2726 .clear_infoframe = accept_infoframe_clear_infoframe,
2727 .write_infoframe = reject_infoframe_write_infoframe,
2728 },
2729 };
2730
2731 /*
2732 * Test that the HDR InfoFrame isn't programmed in
2733 * drm_atomic_helper_connector_hdmi_update_infoframes() if the max_bpc is 8.
2734 */
drm_test_check_reject_hdr_infoframe_bpc_8(struct kunit * test)2735 static void drm_test_check_reject_hdr_infoframe_bpc_8(struct kunit *test)
2736 {
2737 struct drm_atomic_helper_connector_hdmi_priv *priv;
2738 struct drm_modeset_acquire_ctx ctx;
2739 struct drm_atomic_state *state;
2740 struct drm_connector_state *new_conn_state;
2741 struct drm_crtc_state *crtc_state;
2742 struct drm_display_mode *preferred;
2743 struct drm_connector *conn;
2744 struct drm_device *drm;
2745 struct drm_crtc *crtc;
2746 int old_hdmi_update_failures;
2747 int ret;
2748
2749 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
2750 BIT(HDMI_COLORSPACE_RGB),
2751 8,
2752 &reject_hdr_infoframe_hdmi_funcs,
2753 test_edid_hdmi_1080p_rgb_max_200mhz_hdr);
2754 KUNIT_ASSERT_NOT_NULL(test, priv);
2755
2756 drm = &priv->drm;
2757 crtc = priv->crtc;
2758 conn = &priv->connector;
2759
2760 preferred = find_preferred_mode(conn);
2761 KUNIT_ASSERT_NOT_NULL(test, preferred);
2762
2763 drm_modeset_acquire_init(&ctx, 0);
2764
2765 retry_conn_enable:
2766 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
2767 crtc, conn,
2768 preferred,
2769 &ctx);
2770 if (ret == -EDEADLK) {
2771 ret = drm_modeset_backoff(&ctx);
2772 if (!ret)
2773 goto retry_conn_enable;
2774 }
2775 KUNIT_ASSERT_EQ(test, ret, 0);
2776
2777 drm_encoder_helper_add(&priv->encoder, &test_encoder_helper_funcs);
2778
2779 state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
2780 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
2781
2782 retry_conn_state:
2783 new_conn_state = drm_atomic_get_connector_state(state, conn);
2784 if (PTR_ERR(new_conn_state) == -EDEADLK) {
2785 drm_atomic_state_clear(state);
2786 ret = drm_modeset_backoff(&ctx);
2787 if (!ret)
2788 goto retry_conn_state;
2789 }
2790 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state);
2791
2792 crtc_state = drm_atomic_get_crtc_state(state, crtc);
2793 if (PTR_ERR(crtc_state) == -EDEADLK) {
2794 drm_atomic_state_clear(state);
2795 ret = drm_modeset_backoff(&ctx);
2796 if (!ret)
2797 goto retry_conn_state;
2798 }
2799 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
2800
2801 /* Verify that there is no HDR property, so "userspace" can't set it. */
2802 for (int i = 0; i < conn->base.properties->count; i++)
2803 KUNIT_ASSERT_PTR_NE(test,
2804 drm->mode_config.hdr_output_metadata_property,
2805 conn->base.properties->properties[i]);
2806
2807 crtc_state->mode_changed = true;
2808
2809 old_hdmi_update_failures = priv->hdmi_update_failures;
2810
2811 ret = drm_atomic_check_only(state);
2812 if (ret == -EDEADLK) {
2813 drm_atomic_state_clear(state);
2814 ret = drm_modeset_backoff(&ctx);
2815 if (!ret)
2816 goto retry_conn_state;
2817 }
2818 KUNIT_ASSERT_EQ(test, ret, 0);
2819
2820 ret = drm_atomic_commit(state);
2821 if (ret == -EDEADLK) {
2822 drm_atomic_state_clear(state);
2823 ret = drm_modeset_backoff(&ctx);
2824 if (!ret)
2825 goto retry_conn_state;
2826 }
2827 KUNIT_ASSERT_EQ(test, ret, 0);
2828
2829 KUNIT_EXPECT_EQ(test, old_hdmi_update_failures, priv->hdmi_update_failures);
2830
2831 new_conn_state = conn->state;
2832 KUNIT_ASSERT_NOT_NULL(test, new_conn_state);
2833
2834 KUNIT_ASSERT_EQ(test, new_conn_state->hdmi.output_bpc, 8);
2835 KUNIT_ASSERT_EQ(test, new_conn_state->hdmi.infoframes.hdr_drm.set, false);
2836
2837 drm_modeset_drop_locks(&ctx);
2838 drm_modeset_acquire_fini(&ctx);
2839 }
2840
2841 /*
2842 * Test that the rejection of HDR InfoFrame results in the failure of
2843 * drm_atomic_helper_connector_hdmi_update_infoframes() in the high bpc is
2844 * supported.
2845 */
drm_test_check_reject_hdr_infoframe_bpc_10(struct kunit * test)2846 static void drm_test_check_reject_hdr_infoframe_bpc_10(struct kunit *test)
2847 {
2848 struct drm_atomic_helper_connector_hdmi_priv *priv;
2849 struct drm_modeset_acquire_ctx ctx;
2850 struct drm_atomic_state *state;
2851 struct drm_connector_state *new_conn_state;
2852 struct drm_crtc_state *crtc_state;
2853 struct drm_display_mode *preferred;
2854 struct drm_connector *conn;
2855 struct drm_device *drm;
2856 struct drm_crtc *crtc;
2857 int old_hdmi_update_failures;
2858 struct hdr_output_metadata hdr_data;
2859 struct drm_property_blob *hdr_blob;
2860 bool replaced;
2861 int ret;
2862
2863 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
2864 BIT(HDMI_COLORSPACE_RGB),
2865 10,
2866 &reject_hdr_infoframe_hdmi_funcs,
2867 test_edid_hdmi_1080p_rgb_max_200mhz_hdr);
2868 KUNIT_ASSERT_NOT_NULL(test, priv);
2869
2870 drm = &priv->drm;
2871 crtc = priv->crtc;
2872 conn = &priv->connector;
2873
2874 preferred = find_preferred_mode(conn);
2875 KUNIT_ASSERT_NOT_NULL(test, preferred);
2876
2877 drm_modeset_acquire_init(&ctx, 0);
2878
2879 retry_conn_enable:
2880 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
2881 crtc, conn,
2882 preferred,
2883 &ctx);
2884 if (ret == -EDEADLK) {
2885 ret = drm_modeset_backoff(&ctx);
2886 if (!ret)
2887 goto retry_conn_enable;
2888 }
2889 KUNIT_ASSERT_EQ(test, ret, 0);
2890
2891 drm_encoder_helper_add(&priv->encoder, &test_encoder_helper_funcs);
2892
2893 state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
2894 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
2895
2896 retry_conn_state:
2897 new_conn_state = drm_atomic_get_connector_state(state, conn);
2898 if (PTR_ERR(new_conn_state) == -EDEADLK) {
2899 drm_atomic_state_clear(state);
2900 ret = drm_modeset_backoff(&ctx);
2901 if (!ret)
2902 goto retry_conn_state;
2903 }
2904 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state);
2905
2906 crtc_state = drm_atomic_get_crtc_state(state, crtc);
2907 if (PTR_ERR(crtc_state) == -EDEADLK) {
2908 drm_atomic_state_clear(state);
2909 ret = drm_modeset_backoff(&ctx);
2910 if (!ret)
2911 goto retry_conn_state;
2912 }
2913 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
2914
2915 hdr_data.metadata_type = HDMI_STATIC_METADATA_TYPE1;
2916 hdr_data.hdmi_metadata_type1.eotf = HDMI_EOTF_TRADITIONAL_GAMMA_SDR;
2917 hdr_data.hdmi_metadata_type1.metadata_type = HDMI_STATIC_METADATA_TYPE1;
2918
2919 hdr_blob = drm_property_create_blob(drm, sizeof(hdr_data), &hdr_data);
2920 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hdr_blob);
2921
2922 ret = drm_property_replace_blob_from_id(drm,
2923 &new_conn_state->hdr_output_metadata,
2924 hdr_blob->base.id,
2925 -1, sizeof(struct hdr_output_metadata), -1,
2926 &replaced);
2927 KUNIT_ASSERT_EQ(test, ret, 0);
2928 KUNIT_ASSERT_EQ(test, replaced, true);
2929
2930 crtc_state->mode_changed = true;
2931
2932 old_hdmi_update_failures = priv->hdmi_update_failures;
2933
2934 ret = drm_atomic_check_only(state);
2935 if (ret == -EDEADLK) {
2936 drm_atomic_state_clear(state);
2937 ret = drm_modeset_backoff(&ctx);
2938 if (!ret)
2939 goto retry_conn_state;
2940 }
2941 KUNIT_ASSERT_EQ(test, ret, 0);
2942
2943 ret = drm_atomic_commit(state);
2944 if (ret == -EDEADLK) {
2945 drm_atomic_state_clear(state);
2946 ret = drm_modeset_backoff(&ctx);
2947 if (!ret)
2948 goto retry_conn_state;
2949 }
2950 KUNIT_ASSERT_EQ(test, ret, 0);
2951
2952 KUNIT_EXPECT_LE(test, old_hdmi_update_failures, priv->hdmi_update_failures);
2953
2954 new_conn_state = conn->state;
2955 KUNIT_ASSERT_NOT_NULL(test, new_conn_state);
2956
2957 KUNIT_ASSERT_EQ(test, new_conn_state->hdmi.output_bpc, 10);
2958 KUNIT_ASSERT_EQ(test, new_conn_state->hdmi.infoframes.hdr_drm.set, true);
2959
2960 drm_modeset_drop_locks(&ctx);
2961 drm_modeset_acquire_fini(&ctx);
2962 }
2963
2964 static const struct drm_connector_hdmi_funcs reject_audio_infoframe_hdmi_funcs = {
2965 .avi = {
2966 .clear_infoframe = accept_infoframe_clear_infoframe,
2967 .write_infoframe = accept_infoframe_write_infoframe,
2968 },
2969 .hdmi = {
2970 .clear_infoframe = accept_infoframe_clear_infoframe,
2971 .write_infoframe = accept_infoframe_write_infoframe,
2972 },
2973 .audio = {
2974 .clear_infoframe = accept_infoframe_clear_infoframe,
2975 .write_infoframe = reject_infoframe_write_infoframe,
2976 },
2977 };
2978
2979 /*
2980 * Test that Audio InfoFrame is only programmed if we call a corresponding API,
2981 * thus the drivers can safely assume that they won't get Audio InfoFrames if
2982 * they don't call it.
2983 */
drm_test_check_reject_audio_infoframe(struct kunit * test)2984 static void drm_test_check_reject_audio_infoframe(struct kunit *test)
2985 {
2986 struct drm_atomic_helper_connector_hdmi_priv *priv;
2987 struct drm_modeset_acquire_ctx ctx;
2988 struct drm_atomic_state *state;
2989 struct drm_crtc_state *crtc_state;
2990 struct drm_display_mode *preferred;
2991 struct drm_connector *conn;
2992 struct drm_device *drm;
2993 struct drm_crtc *crtc;
2994 int old_hdmi_update_failures;
2995 struct hdmi_audio_infoframe cea;
2996 int ret;
2997
2998 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
2999 BIT(HDMI_COLORSPACE_RGB),
3000 8,
3001 &reject_audio_infoframe_hdmi_funcs,
3002 test_edid_hdmi_1080p_rgb_max_200mhz);
3003 KUNIT_ASSERT_NOT_NULL(test, priv);
3004
3005 drm = &priv->drm;
3006 crtc = priv->crtc;
3007 conn = &priv->connector;
3008
3009 preferred = find_preferred_mode(conn);
3010 KUNIT_ASSERT_NOT_NULL(test, preferred);
3011
3012 drm_modeset_acquire_init(&ctx, 0);
3013
3014 retry_conn_enable:
3015 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
3016 crtc, conn,
3017 preferred,
3018 &ctx);
3019 if (ret == -EDEADLK) {
3020 ret = drm_modeset_backoff(&ctx);
3021 if (!ret)
3022 goto retry_conn_enable;
3023 }
3024 KUNIT_ASSERT_EQ(test, ret, 0);
3025
3026 drm_encoder_helper_add(&priv->encoder, &test_encoder_helper_funcs);
3027
3028 state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
3029 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
3030
3031 retry_crtc_state:
3032 crtc_state = drm_atomic_get_crtc_state(state, crtc);
3033 if (PTR_ERR(crtc_state) == -EDEADLK) {
3034 drm_atomic_state_clear(state);
3035 ret = drm_modeset_backoff(&ctx);
3036 if (!ret)
3037 goto retry_crtc_state;
3038 }
3039 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
3040
3041 crtc_state->mode_changed = true;
3042
3043 old_hdmi_update_failures = priv->hdmi_update_failures;
3044
3045 ret = drm_atomic_check_only(state);
3046 if (ret == -EDEADLK) {
3047 drm_atomic_state_clear(state);
3048 ret = drm_modeset_backoff(&ctx);
3049 if (!ret)
3050 goto retry_crtc_state;
3051 }
3052 KUNIT_ASSERT_EQ(test, ret, 0);
3053
3054 ret = drm_atomic_commit(state);
3055 if (ret == -EDEADLK) {
3056 drm_atomic_state_clear(state);
3057 ret = drm_modeset_backoff(&ctx);
3058 if (!ret)
3059 goto retry_crtc_state;
3060 }
3061 KUNIT_ASSERT_EQ(test, ret, 0);
3062
3063 KUNIT_EXPECT_EQ(test, old_hdmi_update_failures, priv->hdmi_update_failures);
3064
3065 /*
3066 * So, it works without Audio InfoFrame, let's fail with it in place,
3067 * checking that writing the infofraem actually gets triggered.
3068 */
3069
3070 hdmi_audio_infoframe_init(&cea);
3071 cea.channels = 2;
3072 cea.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM;
3073 cea.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM;
3074 cea.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM;
3075
3076 ret = drm_atomic_helper_connector_hdmi_update_audio_infoframe(conn, &cea);
3077 KUNIT_ASSERT_EQ(test, ret, -EOPNOTSUPP);
3078
3079 state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
3080 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
3081
3082 retry_crtc_state_2:
3083 crtc_state = drm_atomic_get_crtc_state(state, crtc);
3084 if (PTR_ERR(crtc_state) == -EDEADLK) {
3085 drm_atomic_state_clear(state);
3086 ret = drm_modeset_backoff(&ctx);
3087 if (!ret)
3088 goto retry_crtc_state_2;
3089 }
3090 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
3091
3092 crtc_state->mode_changed = true;
3093
3094 old_hdmi_update_failures = priv->hdmi_update_failures;
3095
3096 ret = drm_atomic_check_only(state);
3097 if (ret == -EDEADLK) {
3098 drm_atomic_state_clear(state);
3099 ret = drm_modeset_backoff(&ctx);
3100 if (!ret)
3101 goto retry_crtc_state_2;
3102 }
3103 KUNIT_ASSERT_EQ(test, ret, 0);
3104
3105 ret = drm_atomic_commit(state);
3106 if (ret == -EDEADLK) {
3107 drm_atomic_state_clear(state);
3108 ret = drm_modeset_backoff(&ctx);
3109 if (!ret)
3110 goto retry_crtc_state_2;
3111 }
3112 KUNIT_ASSERT_EQ(test, ret, 0);
3113
3114 KUNIT_EXPECT_LE(test, old_hdmi_update_failures, priv->hdmi_update_failures);
3115
3116 drm_modeset_drop_locks(&ctx);
3117 drm_modeset_acquire_fini(&ctx);
3118 }
3119
3120
3121 static struct kunit_case drm_atomic_helper_connector_hdmi_infoframes_tests[] = {
3122 KUNIT_CASE(drm_test_check_infoframes),
3123 KUNIT_CASE(drm_test_check_reject_avi_infoframe),
3124 KUNIT_CASE(drm_test_check_reject_hdr_infoframe_bpc_8),
3125 KUNIT_CASE(drm_test_check_reject_hdr_infoframe_bpc_10),
3126 KUNIT_CASE(drm_test_check_reject_audio_infoframe),
3127 { }
3128 };
3129
3130 static struct kunit_suite drm_atomic_helper_connector_hdmi_infoframes_test_suite = {
3131 .name = "drm_atomic_helper_connector_hdmi_infoframes",
3132 .test_cases = drm_atomic_helper_connector_hdmi_infoframes_tests,
3133 };
3134
3135 kunit_test_suites(
3136 &drm_atomic_helper_connector_hdmi_check_test_suite,
3137 &drm_atomic_helper_connector_hdmi_reset_test_suite,
3138 &drm_atomic_helper_connector_hdmi_mode_valid_test_suite,
3139 &drm_atomic_helper_connector_hdmi_infoframes_test_suite,
3140 );
3141
3142 MODULE_AUTHOR("Maxime Ripard <mripard@kernel.org>");
3143 MODULE_DESCRIPTION("Kunit test for drm_hdmi_state_helper functions");
3144 MODULE_LICENSE("GPL");
3145