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
40 #define connector_to_priv(c) \
41 container_of_const(c, struct drm_atomic_helper_connector_hdmi_priv, connector)
42
find_preferred_mode(struct drm_connector * connector)43 static struct drm_display_mode *find_preferred_mode(struct drm_connector *connector)
44 {
45 struct drm_device *drm = connector->dev;
46 struct drm_display_mode *mode, *preferred;
47
48 mutex_lock(&drm->mode_config.mutex);
49 preferred = list_first_entry_or_null(&connector->modes, struct drm_display_mode, head);
50 list_for_each_entry(mode, &connector->modes, head)
51 if (mode->type & DRM_MODE_TYPE_PREFERRED)
52 preferred = mode;
53 mutex_unlock(&drm->mode_config.mutex);
54
55 return preferred;
56 }
57
set_connector_edid(struct kunit * test,struct drm_connector * connector,const void * edid,size_t edid_len)58 static int set_connector_edid(struct kunit *test, struct drm_connector *connector,
59 const void *edid, size_t edid_len)
60 {
61 struct drm_atomic_helper_connector_hdmi_priv *priv =
62 connector_to_priv(connector);
63 struct drm_device *drm = connector->dev;
64 int ret;
65
66 priv->current_edid = edid;
67 priv->current_edid_len = edid_len;
68
69 mutex_lock(&drm->mode_config.mutex);
70 ret = connector->funcs->fill_modes(connector, 4096, 4096);
71 mutex_unlock(&drm->mode_config.mutex);
72
73 return ret;
74 }
75
76 static const struct drm_connector_hdmi_funcs dummy_connector_hdmi_funcs = {
77 };
78
79 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)80 reject_connector_tmds_char_rate_valid(const struct drm_connector *connector,
81 const struct drm_display_mode *mode,
82 unsigned long long tmds_rate)
83 {
84 return MODE_BAD;
85 }
86
87 static const struct drm_connector_hdmi_funcs reject_connector_hdmi_funcs = {
88 .tmds_char_rate_valid = reject_connector_tmds_char_rate_valid,
89 };
90
91 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)92 reject_100mhz_connector_tmds_char_rate_valid(const struct drm_connector *connector,
93 const struct drm_display_mode *mode,
94 unsigned long long tmds_rate)
95 {
96 return (tmds_rate > 100ULL * 1000 * 1000) ? MODE_BAD : MODE_OK;
97 }
98
99 static const struct drm_connector_hdmi_funcs reject_100mhz_connector_hdmi_funcs = {
100 .tmds_char_rate_valid = reject_100mhz_connector_tmds_char_rate_valid,
101 };
102
dummy_connector_get_modes(struct drm_connector * connector)103 static int dummy_connector_get_modes(struct drm_connector *connector)
104 {
105 struct drm_atomic_helper_connector_hdmi_priv *priv =
106 connector_to_priv(connector);
107 const struct drm_edid *edid;
108 unsigned int num_modes;
109
110 edid = drm_edid_alloc(priv->current_edid, priv->current_edid_len);
111 if (!edid)
112 return -EINVAL;
113
114 drm_edid_connector_update(connector, edid);
115 num_modes = drm_edid_connector_add_modes(connector);
116
117 drm_edid_free(edid);
118
119 return num_modes;
120 }
121
122 static const struct drm_connector_helper_funcs dummy_connector_helper_funcs = {
123 .atomic_check = drm_atomic_helper_connector_hdmi_check,
124 .get_modes = dummy_connector_get_modes,
125 .mode_valid = drm_hdmi_connector_mode_valid,
126 };
127
dummy_hdmi_connector_reset(struct drm_connector * connector)128 static void dummy_hdmi_connector_reset(struct drm_connector *connector)
129 {
130 drm_atomic_helper_connector_reset(connector);
131 __drm_atomic_helper_connector_hdmi_reset(connector, connector->state);
132 }
133
134 static const struct drm_connector_funcs dummy_connector_funcs = {
135 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
136 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
137 .fill_modes = drm_helper_probe_single_connector_modes,
138 .reset = dummy_hdmi_connector_reset,
139 };
140
141 static
142 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)143 __connector_hdmi_init(struct kunit *test,
144 unsigned int formats,
145 unsigned int max_bpc,
146 const struct drm_connector_hdmi_funcs *hdmi_funcs,
147 const void *edid_data, size_t edid_len)
148 {
149 struct drm_atomic_helper_connector_hdmi_priv *priv;
150 struct drm_connector *conn;
151 struct drm_encoder *enc;
152 struct drm_device *drm;
153 struct device *dev;
154 int ret;
155
156 dev = drm_kunit_helper_alloc_device(test);
157 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
158
159 priv = drm_kunit_helper_alloc_drm_device(test, dev,
160 struct drm_atomic_helper_connector_hdmi_priv, drm,
161 DRIVER_MODESET | DRIVER_ATOMIC);
162 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
163 test->priv = priv;
164
165 drm = &priv->drm;
166 priv->plane = drm_kunit_helper_create_primary_plane(test, drm,
167 NULL,
168 NULL,
169 NULL, 0,
170 NULL);
171 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->plane);
172
173 priv->crtc = drm_kunit_helper_create_crtc(test, drm,
174 priv->plane, NULL,
175 NULL,
176 NULL);
177 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->crtc);
178
179 enc = &priv->encoder;
180 ret = drmm_encoder_init(drm, enc, NULL, DRM_MODE_ENCODER_TMDS, NULL);
181 KUNIT_ASSERT_EQ(test, ret, 0);
182
183 enc->possible_crtcs = drm_crtc_mask(priv->crtc);
184
185 conn = &priv->connector;
186 conn->ycbcr_420_allowed = !!(formats & BIT(HDMI_COLORSPACE_YUV420));
187
188 ret = drmm_connector_hdmi_init(drm, conn,
189 "Vendor", "Product",
190 &dummy_connector_funcs,
191 hdmi_funcs,
192 DRM_MODE_CONNECTOR_HDMIA,
193 NULL,
194 formats,
195 max_bpc);
196 KUNIT_ASSERT_EQ(test, ret, 0);
197
198 drm_connector_helper_add(conn, &dummy_connector_helper_funcs);
199 drm_connector_attach_encoder(conn, enc);
200
201 drm_mode_config_reset(drm);
202
203 if (edid_data && edid_len) {
204 ret = set_connector_edid(test, &priv->connector, edid_data, edid_len);
205 KUNIT_ASSERT_GT(test, ret, 0);
206 }
207
208 return priv;
209 }
210
211 #define drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, formats, max_bpc, funcs, edid) \
212 __connector_hdmi_init(test, formats, max_bpc, funcs, edid, ARRAY_SIZE(edid))
213
214 static
215 struct drm_atomic_helper_connector_hdmi_priv *
drm_kunit_helper_connector_hdmi_init(struct kunit * test,unsigned int formats,unsigned int max_bpc)216 drm_kunit_helper_connector_hdmi_init(struct kunit *test,
217 unsigned int formats,
218 unsigned int max_bpc)
219 {
220 return drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
221 formats,
222 max_bpc,
223 &dummy_connector_hdmi_funcs,
224 test_edid_hdmi_1080p_rgb_max_200mhz);
225 }
226
227 /*
228 * Test that if we change the RGB quantization property to a different
229 * value, we trigger a mode change on the connector's CRTC, which will
230 * in turn disable/enable the connector.
231 */
drm_test_check_broadcast_rgb_crtc_mode_changed(struct kunit * test)232 static void drm_test_check_broadcast_rgb_crtc_mode_changed(struct kunit *test)
233 {
234 struct drm_atomic_helper_connector_hdmi_priv *priv;
235 struct drm_modeset_acquire_ctx ctx;
236 struct drm_connector_state *old_conn_state;
237 struct drm_connector_state *new_conn_state;
238 struct drm_crtc_state *crtc_state;
239 struct drm_atomic_state *state;
240 struct drm_display_mode *preferred;
241 struct drm_connector *conn;
242 struct drm_device *drm;
243 struct drm_crtc *crtc;
244 int ret;
245
246 priv = drm_kunit_helper_connector_hdmi_init(test,
247 BIT(HDMI_COLORSPACE_RGB),
248 8);
249 KUNIT_ASSERT_NOT_NULL(test, priv);
250
251 drm = &priv->drm;
252 crtc = priv->crtc;
253 conn = &priv->connector;
254
255 preferred = find_preferred_mode(conn);
256 KUNIT_ASSERT_NOT_NULL(test, preferred);
257
258 drm_modeset_acquire_init(&ctx, 0);
259
260 retry_conn_enable:
261 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
262 crtc, conn,
263 preferred,
264 &ctx);
265 if (ret == -EDEADLK) {
266 ret = drm_modeset_backoff(&ctx);
267 if (!ret)
268 goto retry_conn_enable;
269 }
270 KUNIT_ASSERT_EQ(test, ret, 0);
271
272 state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
273 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
274
275 new_conn_state = drm_atomic_get_connector_state(state, conn);
276 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state);
277
278 old_conn_state = drm_atomic_get_old_connector_state(state, conn);
279 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_conn_state);
280
281 new_conn_state->hdmi.broadcast_rgb = DRM_HDMI_BROADCAST_RGB_FULL;
282
283 KUNIT_ASSERT_NE(test,
284 old_conn_state->hdmi.broadcast_rgb,
285 new_conn_state->hdmi.broadcast_rgb);
286
287 ret = drm_atomic_check_only(state);
288 KUNIT_ASSERT_EQ(test, ret, 0);
289
290 new_conn_state = drm_atomic_get_new_connector_state(state, conn);
291 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state);
292 KUNIT_EXPECT_EQ(test, new_conn_state->hdmi.broadcast_rgb, DRM_HDMI_BROADCAST_RGB_FULL);
293
294 crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
295 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
296 KUNIT_EXPECT_TRUE(test, crtc_state->mode_changed);
297
298 drm_modeset_drop_locks(&ctx);
299 drm_modeset_acquire_fini(&ctx);
300 }
301
302 /*
303 * Test that if we set the RGB quantization property to the same value,
304 * we don't trigger a mode change on the connector's CRTC and leave the
305 * connector unaffected.
306 */
drm_test_check_broadcast_rgb_crtc_mode_not_changed(struct kunit * test)307 static void drm_test_check_broadcast_rgb_crtc_mode_not_changed(struct kunit *test)
308 {
309 struct drm_atomic_helper_connector_hdmi_priv *priv;
310 struct drm_modeset_acquire_ctx ctx;
311 struct drm_connector_state *old_conn_state;
312 struct drm_connector_state *new_conn_state;
313 struct drm_crtc_state *crtc_state;
314 struct drm_atomic_state *state;
315 struct drm_display_mode *preferred;
316 struct drm_connector *conn;
317 struct drm_device *drm;
318 struct drm_crtc *crtc;
319 int ret;
320
321 priv = drm_kunit_helper_connector_hdmi_init(test,
322 BIT(HDMI_COLORSPACE_RGB),
323 8);
324 KUNIT_ASSERT_NOT_NULL(test, priv);
325
326 drm = &priv->drm;
327 crtc = priv->crtc;
328 conn = &priv->connector;
329
330 preferred = find_preferred_mode(conn);
331 KUNIT_ASSERT_NOT_NULL(test, preferred);
332
333 drm_modeset_acquire_init(&ctx, 0);
334
335 retry_conn_enable:
336 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
337 crtc, conn,
338 preferred,
339 &ctx);
340 if (ret == -EDEADLK) {
341 ret = drm_modeset_backoff(&ctx);
342 if (!ret)
343 goto retry_conn_enable;
344 }
345 KUNIT_ASSERT_EQ(test, ret, 0);
346
347 state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
348 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
349
350 new_conn_state = drm_atomic_get_connector_state(state, conn);
351 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state);
352
353 old_conn_state = drm_atomic_get_old_connector_state(state, conn);
354 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_conn_state);
355
356 new_conn_state->hdmi.broadcast_rgb = old_conn_state->hdmi.broadcast_rgb;
357
358 ret = drm_atomic_check_only(state);
359 KUNIT_ASSERT_EQ(test, ret, 0);
360
361 old_conn_state = drm_atomic_get_old_connector_state(state, conn);
362 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_conn_state);
363
364 new_conn_state = drm_atomic_get_new_connector_state(state, conn);
365 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state);
366
367 KUNIT_EXPECT_EQ(test,
368 old_conn_state->hdmi.broadcast_rgb,
369 new_conn_state->hdmi.broadcast_rgb);
370
371 crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
372 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
373 KUNIT_EXPECT_FALSE(test, crtc_state->mode_changed);
374
375 drm_modeset_drop_locks(&ctx);
376 drm_modeset_acquire_fini(&ctx);
377 }
378
379 /*
380 * Test that for an HDMI connector, with an HDMI monitor, if the
381 * Broadcast RGB property is set to auto with a mode that isn't the
382 * VIC-1 mode, we will get a limited RGB Quantization Range.
383 */
drm_test_check_broadcast_rgb_auto_cea_mode(struct kunit * test)384 static void drm_test_check_broadcast_rgb_auto_cea_mode(struct kunit *test)
385 {
386 struct drm_atomic_helper_connector_hdmi_priv *priv;
387 struct drm_modeset_acquire_ctx ctx;
388 struct drm_connector_state *conn_state;
389 struct drm_atomic_state *state;
390 struct drm_display_mode *preferred;
391 struct drm_connector *conn;
392 struct drm_device *drm;
393 struct drm_crtc *crtc;
394 int ret;
395
396 priv = drm_kunit_helper_connector_hdmi_init(test,
397 BIT(HDMI_COLORSPACE_RGB),
398 8);
399 KUNIT_ASSERT_NOT_NULL(test, priv);
400
401 drm = &priv->drm;
402 crtc = priv->crtc;
403 conn = &priv->connector;
404 KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi);
405
406 preferred = find_preferred_mode(conn);
407 KUNIT_ASSERT_NOT_NULL(test, preferred);
408 KUNIT_ASSERT_NE(test, drm_match_cea_mode(preferred), 1);
409
410 drm_modeset_acquire_init(&ctx, 0);
411
412 retry_conn_enable:
413 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
414 crtc, conn,
415 preferred,
416 &ctx);
417 if (ret == -EDEADLK) {
418 ret = drm_modeset_backoff(&ctx);
419 if (!ret)
420 goto retry_conn_enable;
421 }
422 KUNIT_ASSERT_EQ(test, ret, 0);
423
424 state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
425 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
426
427 conn_state = drm_atomic_get_connector_state(state, conn);
428 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
429
430 KUNIT_ASSERT_EQ(test,
431 conn_state->hdmi.broadcast_rgb,
432 DRM_HDMI_BROADCAST_RGB_AUTO);
433
434 ret = drm_atomic_check_only(state);
435 KUNIT_ASSERT_EQ(test, ret, 0);
436
437 conn_state = drm_atomic_get_new_connector_state(state, conn);
438 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
439
440 KUNIT_EXPECT_TRUE(test, conn_state->hdmi.is_limited_range);
441
442 drm_modeset_drop_locks(&ctx);
443 drm_modeset_acquire_fini(&ctx);
444 }
445
446 /*
447 * Test that for an HDMI connector, with an HDMI monitor, if the
448 * Broadcast RGB property is set to auto with a VIC-1 mode, we will get
449 * a full RGB Quantization Range.
450 */
drm_test_check_broadcast_rgb_auto_cea_mode_vic_1(struct kunit * test)451 static void drm_test_check_broadcast_rgb_auto_cea_mode_vic_1(struct kunit *test)
452 {
453 struct drm_atomic_helper_connector_hdmi_priv *priv;
454 struct drm_modeset_acquire_ctx ctx;
455 struct drm_connector_state *conn_state;
456 struct drm_atomic_state *state;
457 struct drm_display_mode *mode;
458 struct drm_connector *conn;
459 struct drm_device *drm;
460 struct drm_crtc *crtc;
461 int ret;
462
463 priv = drm_kunit_helper_connector_hdmi_init(test,
464 BIT(HDMI_COLORSPACE_RGB),
465 8);
466 KUNIT_ASSERT_NOT_NULL(test, priv);
467
468 drm = &priv->drm;
469 conn = &priv->connector;
470 KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi);
471
472 drm_modeset_acquire_init(&ctx, 0);
473
474 mode = drm_kunit_display_mode_from_cea_vic(test, drm, 1);
475 KUNIT_ASSERT_NOT_NULL(test, mode);
476
477 crtc = priv->crtc;
478
479 retry_conn_enable:
480 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
481 crtc, conn,
482 mode,
483 &ctx);
484 if (ret == -EDEADLK) {
485 ret = drm_modeset_backoff(&ctx);
486 if (!ret)
487 goto retry_conn_enable;
488 }
489 KUNIT_ASSERT_EQ(test, ret, 0);
490
491 state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
492 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
493
494 conn_state = drm_atomic_get_connector_state(state, conn);
495 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
496
497 KUNIT_ASSERT_EQ(test,
498 conn_state->hdmi.broadcast_rgb,
499 DRM_HDMI_BROADCAST_RGB_AUTO);
500
501 ret = drm_atomic_check_only(state);
502 KUNIT_ASSERT_EQ(test, ret, 0);
503
504 conn_state = drm_atomic_get_new_connector_state(state, conn);
505 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
506
507 KUNIT_EXPECT_FALSE(test, conn_state->hdmi.is_limited_range);
508
509 drm_modeset_drop_locks(&ctx);
510 drm_modeset_acquire_fini(&ctx);
511 }
512
513 /*
514 * Test that for an HDMI connector, with an HDMI monitor, if the
515 * Broadcast RGB property is set to full with a mode that isn't the
516 * VIC-1 mode, we will get a full RGB Quantization Range.
517 */
drm_test_check_broadcast_rgb_full_cea_mode(struct kunit * test)518 static void drm_test_check_broadcast_rgb_full_cea_mode(struct kunit *test)
519 {
520 struct drm_atomic_helper_connector_hdmi_priv *priv;
521 struct drm_modeset_acquire_ctx ctx;
522 struct drm_connector_state *conn_state;
523 struct drm_atomic_state *state;
524 struct drm_display_mode *preferred;
525 struct drm_connector *conn;
526 struct drm_device *drm;
527 struct drm_crtc *crtc;
528 int ret;
529
530 priv = drm_kunit_helper_connector_hdmi_init(test,
531 BIT(HDMI_COLORSPACE_RGB),
532 8);
533 KUNIT_ASSERT_NOT_NULL(test, priv);
534
535 drm = &priv->drm;
536 crtc = priv->crtc;
537 conn = &priv->connector;
538 KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi);
539
540 preferred = find_preferred_mode(conn);
541 KUNIT_ASSERT_NOT_NULL(test, preferred);
542 KUNIT_ASSERT_NE(test, drm_match_cea_mode(preferred), 1);
543
544 drm_modeset_acquire_init(&ctx, 0);
545
546 retry_conn_enable:
547 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
548 crtc, conn,
549 preferred,
550 &ctx);
551 if (ret == -EDEADLK) {
552 ret = drm_modeset_backoff(&ctx);
553 if (!ret)
554 goto retry_conn_enable;
555 }
556 KUNIT_ASSERT_EQ(test, ret, 0);
557
558 state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
559 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
560
561 conn_state = drm_atomic_get_connector_state(state, conn);
562 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
563
564 conn_state->hdmi.broadcast_rgb = DRM_HDMI_BROADCAST_RGB_FULL;
565
566 ret = drm_atomic_check_only(state);
567 KUNIT_ASSERT_EQ(test, ret, 0);
568
569 conn_state = drm_atomic_get_new_connector_state(state, conn);
570 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
571
572 KUNIT_ASSERT_EQ(test,
573 conn_state->hdmi.broadcast_rgb,
574 DRM_HDMI_BROADCAST_RGB_FULL);
575
576 KUNIT_EXPECT_FALSE(test, conn_state->hdmi.is_limited_range);
577
578 drm_modeset_drop_locks(&ctx);
579 drm_modeset_acquire_fini(&ctx);
580 }
581
582 /*
583 * Test that for an HDMI connector, with an HDMI monitor, if the
584 * Broadcast RGB property is set to full with a VIC-1 mode, we will get
585 * a full RGB Quantization Range.
586 */
drm_test_check_broadcast_rgb_full_cea_mode_vic_1(struct kunit * test)587 static void drm_test_check_broadcast_rgb_full_cea_mode_vic_1(struct kunit *test)
588 {
589 struct drm_atomic_helper_connector_hdmi_priv *priv;
590 struct drm_modeset_acquire_ctx ctx;
591 struct drm_connector_state *conn_state;
592 struct drm_atomic_state *state;
593 struct drm_display_mode *mode;
594 struct drm_connector *conn;
595 struct drm_device *drm;
596 struct drm_crtc *crtc;
597 int ret;
598
599 priv = drm_kunit_helper_connector_hdmi_init(test,
600 BIT(HDMI_COLORSPACE_RGB),
601 8);
602 KUNIT_ASSERT_NOT_NULL(test, priv);
603
604 drm = &priv->drm;
605 conn = &priv->connector;
606 KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi);
607
608 drm_modeset_acquire_init(&ctx, 0);
609
610 mode = drm_kunit_display_mode_from_cea_vic(test, drm, 1);
611 KUNIT_ASSERT_NOT_NULL(test, mode);
612
613 crtc = priv->crtc;
614
615 retry_conn_enable:
616 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
617 crtc, conn,
618 mode,
619 &ctx);
620 if (ret == -EDEADLK) {
621 ret = drm_modeset_backoff(&ctx);
622 if (!ret)
623 goto retry_conn_enable;
624 }
625 KUNIT_ASSERT_EQ(test, ret, 0);
626
627 state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
628 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
629
630 conn_state = drm_atomic_get_connector_state(state, conn);
631 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
632
633 conn_state->hdmi.broadcast_rgb = DRM_HDMI_BROADCAST_RGB_FULL;
634
635 ret = drm_atomic_check_only(state);
636 KUNIT_ASSERT_EQ(test, ret, 0);
637
638 conn_state = drm_atomic_get_new_connector_state(state, conn);
639 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
640
641 KUNIT_ASSERT_EQ(test,
642 conn_state->hdmi.broadcast_rgb,
643 DRM_HDMI_BROADCAST_RGB_FULL);
644
645 KUNIT_EXPECT_FALSE(test, conn_state->hdmi.is_limited_range);
646
647 drm_modeset_drop_locks(&ctx);
648 drm_modeset_acquire_fini(&ctx);
649 }
650
651 /*
652 * Test that for an HDMI connector, with an HDMI monitor, if the
653 * Broadcast RGB property is set to limited with a mode that isn't the
654 * VIC-1 mode, we will get a limited RGB Quantization Range.
655 */
drm_test_check_broadcast_rgb_limited_cea_mode(struct kunit * test)656 static void drm_test_check_broadcast_rgb_limited_cea_mode(struct kunit *test)
657 {
658 struct drm_atomic_helper_connector_hdmi_priv *priv;
659 struct drm_modeset_acquire_ctx ctx;
660 struct drm_connector_state *conn_state;
661 struct drm_atomic_state *state;
662 struct drm_display_mode *preferred;
663 struct drm_connector *conn;
664 struct drm_device *drm;
665 struct drm_crtc *crtc;
666 int ret;
667
668 priv = drm_kunit_helper_connector_hdmi_init(test,
669 BIT(HDMI_COLORSPACE_RGB),
670 8);
671 KUNIT_ASSERT_NOT_NULL(test, priv);
672
673 drm = &priv->drm;
674 crtc = priv->crtc;
675 conn = &priv->connector;
676 KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi);
677
678 preferred = find_preferred_mode(conn);
679 KUNIT_ASSERT_NOT_NULL(test, preferred);
680 KUNIT_ASSERT_NE(test, drm_match_cea_mode(preferred), 1);
681
682 drm_modeset_acquire_init(&ctx, 0);
683
684 retry_conn_enable:
685 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
686 crtc, conn,
687 preferred,
688 &ctx);
689 if (ret == -EDEADLK) {
690 ret = drm_modeset_backoff(&ctx);
691 if (!ret)
692 goto retry_conn_enable;
693 }
694 KUNIT_ASSERT_EQ(test, ret, 0);
695
696 state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
697 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
698
699 conn_state = drm_atomic_get_connector_state(state, conn);
700 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
701
702 conn_state->hdmi.broadcast_rgb = DRM_HDMI_BROADCAST_RGB_LIMITED;
703
704 ret = drm_atomic_check_only(state);
705 KUNIT_ASSERT_EQ(test, ret, 0);
706
707 conn_state = drm_atomic_get_new_connector_state(state, conn);
708 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
709
710 KUNIT_ASSERT_EQ(test,
711 conn_state->hdmi.broadcast_rgb,
712 DRM_HDMI_BROADCAST_RGB_LIMITED);
713
714 KUNIT_EXPECT_TRUE(test, conn_state->hdmi.is_limited_range);
715
716 drm_modeset_drop_locks(&ctx);
717 drm_modeset_acquire_fini(&ctx);
718 }
719
720 /*
721 * Test that for an HDMI connector, with an HDMI monitor, if the
722 * Broadcast RGB property is set to limited with a VIC-1 mode, we will
723 * get a limited RGB Quantization Range.
724 */
drm_test_check_broadcast_rgb_limited_cea_mode_vic_1(struct kunit * test)725 static void drm_test_check_broadcast_rgb_limited_cea_mode_vic_1(struct kunit *test)
726 {
727 struct drm_atomic_helper_connector_hdmi_priv *priv;
728 struct drm_modeset_acquire_ctx ctx;
729 struct drm_connector_state *conn_state;
730 struct drm_atomic_state *state;
731 struct drm_display_mode *mode;
732 struct drm_connector *conn;
733 struct drm_device *drm;
734 struct drm_crtc *crtc;
735 int ret;
736
737 priv = drm_kunit_helper_connector_hdmi_init(test,
738 BIT(HDMI_COLORSPACE_RGB),
739 8);
740 KUNIT_ASSERT_NOT_NULL(test, priv);
741
742 drm = &priv->drm;
743 conn = &priv->connector;
744 KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi);
745
746 drm_modeset_acquire_init(&ctx, 0);
747
748 mode = drm_kunit_display_mode_from_cea_vic(test, drm, 1);
749 KUNIT_ASSERT_NOT_NULL(test, mode);
750
751 crtc = priv->crtc;
752
753 retry_conn_enable:
754 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
755 crtc, conn,
756 mode,
757 &ctx);
758 if (ret == -EDEADLK) {
759 ret = drm_modeset_backoff(&ctx);
760 if (!ret)
761 goto retry_conn_enable;
762 }
763 KUNIT_ASSERT_EQ(test, ret, 0);
764
765 state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
766 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
767
768 conn_state = drm_atomic_get_connector_state(state, conn);
769 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
770
771 conn_state->hdmi.broadcast_rgb = DRM_HDMI_BROADCAST_RGB_LIMITED;
772
773 ret = drm_atomic_check_only(state);
774 KUNIT_ASSERT_EQ(test, ret, 0);
775
776 conn_state = drm_atomic_get_new_connector_state(state, conn);
777 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
778
779 KUNIT_ASSERT_EQ(test,
780 conn_state->hdmi.broadcast_rgb,
781 DRM_HDMI_BROADCAST_RGB_LIMITED);
782
783 KUNIT_EXPECT_TRUE(test, conn_state->hdmi.is_limited_range);
784
785 drm_modeset_drop_locks(&ctx);
786 drm_modeset_acquire_fini(&ctx);
787 }
788
789 /*
790 * Test that for an HDMI connector, with an HDMI monitor, we will
791 * get a limited RGB Quantization Range with a YUV420 mode, no
792 * matter what the value of the Broadcast RGB property is set to.
793 */
drm_test_check_broadcast_rgb_cea_mode_yuv420(struct kunit * test)794 static void drm_test_check_broadcast_rgb_cea_mode_yuv420(struct kunit *test)
795 {
796 struct drm_atomic_helper_connector_hdmi_priv *priv;
797 enum drm_hdmi_broadcast_rgb broadcast_rgb;
798 struct drm_modeset_acquire_ctx ctx;
799 struct drm_connector_state *conn_state;
800 struct drm_atomic_state *state;
801 struct drm_display_mode *mode;
802 struct drm_connector *conn;
803 struct drm_device *drm;
804 struct drm_crtc *crtc;
805 int ret;
806
807 broadcast_rgb = *(enum drm_hdmi_broadcast_rgb *)test->param_value;
808
809 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
810 BIT(HDMI_COLORSPACE_RGB) |
811 BIT(HDMI_COLORSPACE_YUV420),
812 8,
813 &dummy_connector_hdmi_funcs,
814 test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz);
815 KUNIT_ASSERT_NOT_NULL(test, priv);
816
817 drm = &priv->drm;
818 crtc = priv->crtc;
819 conn = &priv->connector;
820 KUNIT_ASSERT_TRUE(test, conn->display_info.is_hdmi);
821
822 mode = drm_kunit_display_mode_from_cea_vic(test, drm, 95);
823 KUNIT_ASSERT_NOT_NULL(test, mode);
824
825 drm_modeset_acquire_init(&ctx, 0);
826
827 retry_conn_enable:
828 ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn,
829 mode, &ctx);
830 if (ret == -EDEADLK) {
831 ret = drm_modeset_backoff(&ctx);
832 if (!ret)
833 goto retry_conn_enable;
834 }
835 KUNIT_ASSERT_EQ(test, ret, 0);
836
837 state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
838 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
839
840 retry_conn_state:
841 conn_state = drm_atomic_get_connector_state(state, conn);
842 if (PTR_ERR(conn_state) == -EDEADLK) {
843 drm_atomic_state_clear(state);
844 ret = drm_modeset_backoff(&ctx);
845 if (!ret)
846 goto retry_conn_state;
847 }
848 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
849
850 conn_state->hdmi.broadcast_rgb = broadcast_rgb;
851
852 ret = drm_atomic_check_only(state);
853 if (ret == -EDEADLK) {
854 drm_atomic_state_clear(state);
855 ret = drm_modeset_backoff(&ctx);
856 if (!ret)
857 goto retry_conn_state;
858 }
859 KUNIT_ASSERT_EQ(test, ret, 0);
860
861 conn_state = drm_atomic_get_new_connector_state(state, conn);
862 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
863
864 KUNIT_ASSERT_EQ(test, conn_state->hdmi.broadcast_rgb, broadcast_rgb);
865 KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_YUV420);
866
867 KUNIT_EXPECT_TRUE(test, conn_state->hdmi.is_limited_range);
868
869 drm_modeset_drop_locks(&ctx);
870 drm_modeset_acquire_fini(&ctx);
871 }
872
873 static const enum drm_hdmi_broadcast_rgb check_broadcast_rgb_cea_mode_yuv420_tests[] = {
874 DRM_HDMI_BROADCAST_RGB_AUTO,
875 DRM_HDMI_BROADCAST_RGB_FULL,
876 DRM_HDMI_BROADCAST_RGB_LIMITED,
877 };
878
879 static void
check_broadcast_rgb_cea_mode_yuv420_desc(const enum drm_hdmi_broadcast_rgb * broadcast_rgb,char * desc)880 check_broadcast_rgb_cea_mode_yuv420_desc(const enum drm_hdmi_broadcast_rgb *broadcast_rgb,
881 char *desc)
882 {
883 sprintf(desc, "%s", drm_hdmi_connector_get_broadcast_rgb_name(*broadcast_rgb));
884 }
885
886 KUNIT_ARRAY_PARAM(check_broadcast_rgb_cea_mode_yuv420,
887 check_broadcast_rgb_cea_mode_yuv420_tests,
888 check_broadcast_rgb_cea_mode_yuv420_desc);
889
890 /*
891 * Test that if we change the maximum bpc property to a different value,
892 * we trigger a mode change on the connector's CRTC, which will in turn
893 * disable/enable the connector.
894 */
drm_test_check_output_bpc_crtc_mode_changed(struct kunit * test)895 static void drm_test_check_output_bpc_crtc_mode_changed(struct kunit *test)
896 {
897 struct drm_atomic_helper_connector_hdmi_priv *priv;
898 struct drm_modeset_acquire_ctx ctx;
899 struct drm_connector_state *old_conn_state;
900 struct drm_connector_state *new_conn_state;
901 struct drm_crtc_state *crtc_state;
902 struct drm_atomic_state *state;
903 struct drm_display_mode *preferred;
904 struct drm_connector *conn;
905 struct drm_device *drm;
906 struct drm_crtc *crtc;
907 int ret;
908
909 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
910 BIT(HDMI_COLORSPACE_RGB),
911 10,
912 &dummy_connector_hdmi_funcs,
913 test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz);
914 KUNIT_ASSERT_NOT_NULL(test, priv);
915
916 drm = &priv->drm;
917 crtc = priv->crtc;
918 conn = &priv->connector;
919 preferred = find_preferred_mode(conn);
920 KUNIT_ASSERT_NOT_NULL(test, preferred);
921
922 drm_modeset_acquire_init(&ctx, 0);
923
924 retry_conn_enable:
925 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
926 crtc, conn,
927 preferred,
928 &ctx);
929 if (ret == -EDEADLK) {
930 ret = drm_modeset_backoff(&ctx);
931 if (!ret)
932 goto retry_conn_enable;
933 }
934 KUNIT_ASSERT_EQ(test, ret, 0);
935
936 state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
937 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
938
939 new_conn_state = drm_atomic_get_connector_state(state, conn);
940 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state);
941
942 old_conn_state = drm_atomic_get_old_connector_state(state, conn);
943 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_conn_state);
944
945 new_conn_state->max_requested_bpc = 8;
946
947 KUNIT_ASSERT_NE(test,
948 old_conn_state->max_requested_bpc,
949 new_conn_state->max_requested_bpc);
950
951 ret = drm_atomic_check_only(state);
952 KUNIT_ASSERT_EQ(test, ret, 0);
953
954 old_conn_state = drm_atomic_get_old_connector_state(state, conn);
955 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_conn_state);
956
957 new_conn_state = drm_atomic_get_new_connector_state(state, conn);
958 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state);
959
960 KUNIT_ASSERT_NE(test,
961 old_conn_state->hdmi.output_bpc,
962 new_conn_state->hdmi.output_bpc);
963
964 crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
965 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
966 KUNIT_EXPECT_TRUE(test, crtc_state->mode_changed);
967
968 drm_modeset_drop_locks(&ctx);
969 drm_modeset_acquire_fini(&ctx);
970 }
971
972 /*
973 * Test that if we set the output bpc property to the same value, we
974 * don't trigger a mode change on the connector's CRTC and leave the
975 * connector unaffected.
976 */
drm_test_check_output_bpc_crtc_mode_not_changed(struct kunit * test)977 static void drm_test_check_output_bpc_crtc_mode_not_changed(struct kunit *test)
978 {
979 struct drm_atomic_helper_connector_hdmi_priv *priv;
980 struct drm_modeset_acquire_ctx ctx;
981 struct drm_connector_state *old_conn_state;
982 struct drm_connector_state *new_conn_state;
983 struct drm_crtc_state *crtc_state;
984 struct drm_atomic_state *state;
985 struct drm_display_mode *preferred;
986 struct drm_connector *conn;
987 struct drm_device *drm;
988 struct drm_crtc *crtc;
989 int ret;
990
991 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
992 BIT(HDMI_COLORSPACE_RGB),
993 10,
994 &dummy_connector_hdmi_funcs,
995 test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz);
996 KUNIT_ASSERT_NOT_NULL(test, priv);
997
998 drm = &priv->drm;
999 crtc = priv->crtc;
1000 conn = &priv->connector;
1001 preferred = find_preferred_mode(conn);
1002 KUNIT_ASSERT_NOT_NULL(test, preferred);
1003
1004 drm_modeset_acquire_init(&ctx, 0);
1005
1006 retry_conn_enable:
1007 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
1008 crtc, conn,
1009 preferred,
1010 &ctx);
1011 if (ret == -EDEADLK) {
1012 ret = drm_modeset_backoff(&ctx);
1013 if (!ret)
1014 goto retry_conn_enable;
1015 }
1016 KUNIT_ASSERT_EQ(test, ret, 0);
1017
1018 state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
1019 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
1020
1021 new_conn_state = drm_atomic_get_connector_state(state, conn);
1022 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state);
1023
1024 old_conn_state = drm_atomic_get_old_connector_state(state, conn);
1025 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_conn_state);
1026
1027 KUNIT_ASSERT_EQ(test,
1028 new_conn_state->hdmi.output_bpc,
1029 old_conn_state->hdmi.output_bpc);
1030
1031 ret = drm_atomic_check_only(state);
1032 KUNIT_ASSERT_EQ(test, ret, 0);
1033
1034 old_conn_state = drm_atomic_get_old_connector_state(state, conn);
1035 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_conn_state);
1036
1037 new_conn_state = drm_atomic_get_new_connector_state(state, conn);
1038 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state);
1039
1040 KUNIT_EXPECT_EQ(test,
1041 old_conn_state->hdmi.output_bpc,
1042 new_conn_state->hdmi.output_bpc);
1043
1044 crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
1045 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
1046 KUNIT_EXPECT_FALSE(test, crtc_state->mode_changed);
1047
1048 drm_modeset_drop_locks(&ctx);
1049 drm_modeset_acquire_fini(&ctx);
1050 }
1051
1052 /*
1053 * Test that if we have an HDMI connector but a !HDMI display, we always
1054 * output RGB with 8 bpc.
1055 */
drm_test_check_output_bpc_dvi(struct kunit * test)1056 static void drm_test_check_output_bpc_dvi(struct kunit *test)
1057 {
1058 struct drm_atomic_helper_connector_hdmi_priv *priv;
1059 struct drm_modeset_acquire_ctx ctx;
1060 struct drm_connector_state *conn_state;
1061 struct drm_display_info *info;
1062 struct drm_display_mode *preferred;
1063 struct drm_connector *conn;
1064 struct drm_device *drm;
1065 struct drm_crtc *crtc;
1066 int ret;
1067
1068 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
1069 BIT(HDMI_COLORSPACE_RGB) |
1070 BIT(HDMI_COLORSPACE_YUV422) |
1071 BIT(HDMI_COLORSPACE_YUV444),
1072 12,
1073 &dummy_connector_hdmi_funcs,
1074 test_edid_dvi_1080p);
1075 KUNIT_ASSERT_NOT_NULL(test, priv);
1076
1077 drm = &priv->drm;
1078 crtc = priv->crtc;
1079 conn = &priv->connector;
1080 info = &conn->display_info;
1081 KUNIT_ASSERT_FALSE(test, info->is_hdmi);
1082
1083 preferred = find_preferred_mode(conn);
1084 KUNIT_ASSERT_NOT_NULL(test, preferred);
1085
1086 drm_modeset_acquire_init(&ctx, 0);
1087
1088 retry_conn_enable:
1089 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
1090 crtc, conn,
1091 preferred,
1092 &ctx);
1093 if (ret == -EDEADLK) {
1094 ret = drm_modeset_backoff(&ctx);
1095 if (!ret)
1096 goto retry_conn_enable;
1097 }
1098 KUNIT_ASSERT_EQ(test, ret, 0);
1099
1100 conn_state = conn->state;
1101 KUNIT_ASSERT_NOT_NULL(test, conn_state);
1102
1103 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 8);
1104 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB);
1105
1106 drm_modeset_drop_locks(&ctx);
1107 drm_modeset_acquire_fini(&ctx);
1108 }
1109
1110 /*
1111 * Test that when doing a commit which would use RGB 8bpc, the TMDS
1112 * clock rate stored in the connector state is equal to the mode clock
1113 */
drm_test_check_tmds_char_rate_rgb_8bpc(struct kunit * test)1114 static void drm_test_check_tmds_char_rate_rgb_8bpc(struct kunit *test)
1115 {
1116 struct drm_atomic_helper_connector_hdmi_priv *priv;
1117 struct drm_modeset_acquire_ctx ctx;
1118 struct drm_connector_state *conn_state;
1119 struct drm_display_mode *preferred;
1120 struct drm_connector *conn;
1121 struct drm_device *drm;
1122 struct drm_crtc *crtc;
1123 int ret;
1124
1125 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
1126 BIT(HDMI_COLORSPACE_RGB),
1127 8,
1128 &dummy_connector_hdmi_funcs,
1129 test_edid_hdmi_1080p_rgb_max_200mhz);
1130 KUNIT_ASSERT_NOT_NULL(test, priv);
1131
1132 drm = &priv->drm;
1133 crtc = priv->crtc;
1134 conn = &priv->connector;
1135 preferred = find_preferred_mode(conn);
1136 KUNIT_ASSERT_NOT_NULL(test, preferred);
1137 KUNIT_ASSERT_FALSE(test, preferred->flags & DRM_MODE_FLAG_DBLCLK);
1138
1139 drm_modeset_acquire_init(&ctx, 0);
1140
1141 retry_conn_enable:
1142 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
1143 crtc, conn,
1144 preferred,
1145 &ctx);
1146 if (ret == -EDEADLK) {
1147 ret = drm_modeset_backoff(&ctx);
1148 if (!ret)
1149 goto retry_conn_enable;
1150 }
1151 KUNIT_ASSERT_EQ(test, ret, 0);
1152
1153 conn_state = conn->state;
1154 KUNIT_ASSERT_NOT_NULL(test, conn_state);
1155
1156 KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_bpc, 8);
1157 KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB);
1158 KUNIT_EXPECT_EQ(test, conn_state->hdmi.tmds_char_rate, preferred->clock * 1000);
1159
1160 drm_modeset_drop_locks(&ctx);
1161 drm_modeset_acquire_fini(&ctx);
1162 }
1163
1164 /*
1165 * Test that when doing a commit which would use RGB 10bpc, the TMDS
1166 * clock rate stored in the connector state is equal to 1.25 times the
1167 * mode pixel clock
1168 */
drm_test_check_tmds_char_rate_rgb_10bpc(struct kunit * test)1169 static void drm_test_check_tmds_char_rate_rgb_10bpc(struct kunit *test)
1170 {
1171 struct drm_atomic_helper_connector_hdmi_priv *priv;
1172 struct drm_modeset_acquire_ctx ctx;
1173 struct drm_connector_state *conn_state;
1174 struct drm_display_mode *preferred;
1175 struct drm_connector *conn;
1176 struct drm_device *drm;
1177 struct drm_crtc *crtc;
1178 int ret;
1179
1180 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
1181 BIT(HDMI_COLORSPACE_RGB),
1182 10,
1183 &dummy_connector_hdmi_funcs,
1184 test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz);
1185 KUNIT_ASSERT_NOT_NULL(test, priv);
1186
1187 drm = &priv->drm;
1188 crtc = priv->crtc;
1189 conn = &priv->connector;
1190 preferred = find_preferred_mode(conn);
1191 KUNIT_ASSERT_NOT_NULL(test, preferred);
1192 KUNIT_ASSERT_FALSE(test, preferred->flags & DRM_MODE_FLAG_DBLCLK);
1193
1194 drm_modeset_acquire_init(&ctx, 0);
1195
1196 retry_conn_enable:
1197 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
1198 crtc, conn,
1199 preferred,
1200 &ctx);
1201 if (ret == -EDEADLK) {
1202 ret = drm_modeset_backoff(&ctx);
1203 if (!ret)
1204 goto retry_conn_enable;
1205 }
1206 KUNIT_ASSERT_EQ(test, ret, 0);
1207
1208 conn_state = conn->state;
1209 KUNIT_ASSERT_NOT_NULL(test, conn_state);
1210
1211 KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_bpc, 10);
1212 KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB);
1213 KUNIT_EXPECT_EQ(test, conn_state->hdmi.tmds_char_rate, preferred->clock * 1250);
1214
1215 drm_modeset_drop_locks(&ctx);
1216 drm_modeset_acquire_fini(&ctx);
1217 }
1218
1219 /*
1220 * Test that when doing a commit which would use RGB 12bpc, the TMDS
1221 * clock rate stored in the connector state is equal to 1.5 times the
1222 * mode pixel clock
1223 */
drm_test_check_tmds_char_rate_rgb_12bpc(struct kunit * test)1224 static void drm_test_check_tmds_char_rate_rgb_12bpc(struct kunit *test)
1225 {
1226 struct drm_atomic_helper_connector_hdmi_priv *priv;
1227 struct drm_modeset_acquire_ctx ctx;
1228 struct drm_connector_state *conn_state;
1229 struct drm_display_mode *preferred;
1230 struct drm_connector *conn;
1231 struct drm_device *drm;
1232 struct drm_crtc *crtc;
1233 int ret;
1234
1235 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
1236 BIT(HDMI_COLORSPACE_RGB),
1237 12,
1238 &dummy_connector_hdmi_funcs,
1239 test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz);
1240 KUNIT_ASSERT_NOT_NULL(test, priv);
1241
1242 drm = &priv->drm;
1243 crtc = priv->crtc;
1244 conn = &priv->connector;
1245 preferred = find_preferred_mode(conn);
1246 KUNIT_ASSERT_NOT_NULL(test, preferred);
1247 KUNIT_ASSERT_FALSE(test, preferred->flags & DRM_MODE_FLAG_DBLCLK);
1248
1249 drm_modeset_acquire_init(&ctx, 0);
1250
1251 retry_conn_enable:
1252 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
1253 crtc, conn,
1254 preferred,
1255 &ctx);
1256 if (ret == -EDEADLK) {
1257 ret = drm_modeset_backoff(&ctx);
1258 if (!ret)
1259 goto retry_conn_enable;
1260 }
1261 KUNIT_ASSERT_EQ(test, ret, 0);
1262
1263 conn_state = conn->state;
1264 KUNIT_ASSERT_NOT_NULL(test, conn_state);
1265
1266 KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_bpc, 12);
1267 KUNIT_ASSERT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB);
1268 KUNIT_EXPECT_EQ(test, conn_state->hdmi.tmds_char_rate, preferred->clock * 1500);
1269
1270 drm_modeset_drop_locks(&ctx);
1271 drm_modeset_acquire_fini(&ctx);
1272 }
1273
1274 /*
1275 * Test that if we filter a rate through our hook, it's indeed rejected
1276 * by the whole atomic_check logic.
1277 *
1278 * We do so by first doing a commit on the pipeline to make sure that it
1279 * works, change the HDMI helpers pointer, and then try the same commit
1280 * again to see if it fails as it should.
1281 */
drm_test_check_hdmi_funcs_reject_rate(struct kunit * test)1282 static void drm_test_check_hdmi_funcs_reject_rate(struct kunit *test)
1283 {
1284 struct drm_atomic_helper_connector_hdmi_priv *priv;
1285 struct drm_modeset_acquire_ctx ctx;
1286 struct drm_atomic_state *state;
1287 struct drm_display_mode *preferred;
1288 struct drm_crtc_state *crtc_state;
1289 struct drm_connector *conn;
1290 struct drm_device *drm;
1291 struct drm_crtc *crtc;
1292 int ret;
1293
1294 priv = drm_kunit_helper_connector_hdmi_init(test,
1295 BIT(HDMI_COLORSPACE_RGB),
1296 8);
1297 KUNIT_ASSERT_NOT_NULL(test, priv);
1298
1299 drm = &priv->drm;
1300 crtc = priv->crtc;
1301 conn = &priv->connector;
1302
1303 preferred = find_preferred_mode(conn);
1304 KUNIT_ASSERT_NOT_NULL(test, preferred);
1305
1306 drm_modeset_acquire_init(&ctx, 0);
1307
1308 retry_conn_enable:
1309 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
1310 crtc, conn,
1311 preferred,
1312 &ctx);
1313 if (ret == -EDEADLK) {
1314 ret = drm_modeset_backoff(&ctx);
1315 if (!ret)
1316 goto retry_conn_enable;
1317 }
1318 KUNIT_ASSERT_EQ(test, ret, 0);
1319
1320 /* You shouldn't be doing that at home. */
1321 conn->hdmi.funcs = &reject_connector_hdmi_funcs;
1322
1323 state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
1324 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
1325
1326 crtc_state = drm_atomic_get_crtc_state(state, crtc);
1327 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
1328
1329 crtc_state->connectors_changed = true;
1330
1331 ret = drm_atomic_check_only(state);
1332 KUNIT_EXPECT_LT(test, ret, 0);
1333
1334 drm_modeset_drop_locks(&ctx);
1335 drm_modeset_acquire_fini(&ctx);
1336 }
1337
1338 /*
1339 * Test that if:
1340 * - We have an HDMI connector supporting RGB only
1341 * - The chosen mode has a TMDS character rate higher than the display
1342 * supports in RGB/12bpc
1343 * - The chosen mode has a TMDS character rate lower than the display
1344 * supports in RGB/10bpc.
1345 *
1346 * Then we will pick the latter, and the computed TMDS character rate
1347 * will be equal to 1.25 times the mode pixel clock.
1348 */
drm_test_check_max_tmds_rate_bpc_fallback_rgb(struct kunit * test)1349 static void drm_test_check_max_tmds_rate_bpc_fallback_rgb(struct kunit *test)
1350 {
1351 struct drm_atomic_helper_connector_hdmi_priv *priv;
1352 struct drm_modeset_acquire_ctx ctx;
1353 struct drm_connector_state *conn_state;
1354 struct drm_display_info *info;
1355 struct drm_display_mode *preferred;
1356 unsigned long long rate;
1357 struct drm_connector *conn;
1358 struct drm_device *drm;
1359 struct drm_crtc *crtc;
1360 int ret;
1361
1362 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
1363 BIT(HDMI_COLORSPACE_RGB),
1364 12,
1365 &dummy_connector_hdmi_funcs,
1366 test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz);
1367 KUNIT_ASSERT_NOT_NULL(test, priv);
1368
1369 drm = &priv->drm;
1370 crtc = priv->crtc;
1371 conn = &priv->connector;
1372 info = &conn->display_info;
1373 KUNIT_ASSERT_TRUE(test, info->is_hdmi);
1374 KUNIT_ASSERT_GT(test, info->max_tmds_clock, 0);
1375
1376 preferred = find_preferred_mode(conn);
1377 KUNIT_ASSERT_NOT_NULL(test, preferred);
1378 KUNIT_ASSERT_FALSE(test, preferred->flags & DRM_MODE_FLAG_DBLCLK);
1379
1380 rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_RGB);
1381 KUNIT_ASSERT_GT(test, rate, info->max_tmds_clock * 1000);
1382
1383 rate = drm_hdmi_compute_mode_clock(preferred, 10, HDMI_COLORSPACE_RGB);
1384 KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
1385
1386 drm_modeset_acquire_init(&ctx, 0);
1387
1388 retry_conn_enable:
1389 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
1390 crtc, conn,
1391 preferred,
1392 &ctx);
1393 if (ret == -EDEADLK) {
1394 ret = drm_modeset_backoff(&ctx);
1395 if (!ret)
1396 goto retry_conn_enable;
1397 }
1398 KUNIT_EXPECT_EQ(test, ret, 0);
1399
1400 conn_state = conn->state;
1401 KUNIT_ASSERT_NOT_NULL(test, conn_state);
1402
1403 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 10);
1404 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB);
1405 KUNIT_EXPECT_EQ(test, conn_state->hdmi.tmds_char_rate, preferred->clock * 1250);
1406
1407 drm_modeset_drop_locks(&ctx);
1408 drm_modeset_acquire_fini(&ctx);
1409 }
1410
1411 /*
1412 * Test that if:
1413 * - We have an HDMI connector and a display supporting both RGB and YUV420
1414 * - The chosen mode can be supported in YUV420 output format only
1415 * - The chosen mode has a TMDS character rate higher than the display
1416 * supports in YUV420/12bpc
1417 * - The chosen mode has a TMDS character rate lower than the display
1418 * supports in YUV420/10bpc.
1419 *
1420 * Then we will pick the latter, and the computed TMDS character rate
1421 * will be equal to 1.25 * 0.5 times the mode pixel clock.
1422 */
drm_test_check_max_tmds_rate_bpc_fallback_yuv420(struct kunit * test)1423 static void drm_test_check_max_tmds_rate_bpc_fallback_yuv420(struct kunit *test)
1424 {
1425 struct drm_atomic_helper_connector_hdmi_priv *priv;
1426 struct drm_modeset_acquire_ctx ctx;
1427 struct drm_connector_state *conn_state;
1428 struct drm_display_info *info;
1429 struct drm_display_mode *yuv420_only_mode;
1430 unsigned long long rate;
1431 struct drm_connector *conn;
1432 struct drm_device *drm;
1433 struct drm_crtc *crtc;
1434 int ret;
1435
1436 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
1437 BIT(HDMI_COLORSPACE_RGB) |
1438 BIT(HDMI_COLORSPACE_YUV420),
1439 12,
1440 &dummy_connector_hdmi_funcs,
1441 test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz);
1442 KUNIT_ASSERT_NOT_NULL(test, priv);
1443
1444 drm = &priv->drm;
1445 crtc = priv->crtc;
1446 conn = &priv->connector;
1447 info = &conn->display_info;
1448 KUNIT_ASSERT_TRUE(test, info->is_hdmi);
1449 KUNIT_ASSERT_GT(test, info->max_tmds_clock, 0);
1450 KUNIT_ASSERT_TRUE(test, conn->ycbcr_420_allowed);
1451
1452 yuv420_only_mode = drm_kunit_display_mode_from_cea_vic(test, drm, 95);
1453 KUNIT_ASSERT_NOT_NULL(test, yuv420_only_mode);
1454 KUNIT_ASSERT_TRUE(test, drm_mode_is_420_only(info, yuv420_only_mode));
1455
1456 rate = drm_hdmi_compute_mode_clock(yuv420_only_mode, 12, HDMI_COLORSPACE_YUV420);
1457 KUNIT_ASSERT_GT(test, rate, info->max_tmds_clock * 1000);
1458
1459 rate = drm_hdmi_compute_mode_clock(yuv420_only_mode, 10, HDMI_COLORSPACE_YUV420);
1460 KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
1461
1462 drm_modeset_acquire_init(&ctx, 0);
1463
1464 retry_conn_enable:
1465 ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn,
1466 yuv420_only_mode, &ctx);
1467 if (ret == -EDEADLK) {
1468 ret = drm_modeset_backoff(&ctx);
1469 if (!ret)
1470 goto retry_conn_enable;
1471 }
1472 KUNIT_EXPECT_EQ(test, ret, 0);
1473
1474 conn_state = conn->state;
1475 KUNIT_ASSERT_NOT_NULL(test, conn_state);
1476
1477 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 10);
1478 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_YUV420);
1479 KUNIT_EXPECT_EQ(test, conn_state->hdmi.tmds_char_rate, yuv420_only_mode->clock * 625);
1480
1481 drm_modeset_drop_locks(&ctx);
1482 drm_modeset_acquire_fini(&ctx);
1483 }
1484
1485 /*
1486 * Test that if:
1487 * - We have an HDMI connector supporting both RGB and YUV422 and up to
1488 * 12 bpc
1489 * - The chosen mode has a TMDS character rate higher than the display
1490 * supports in RGB/12bpc but lower than the display supports in
1491 * RGB/10bpc
1492 * - The chosen mode has a TMDS character rate lower than the display
1493 * supports in YUV422/12bpc.
1494 *
1495 * Then we will prefer to keep the RGB format with a lower bpc over
1496 * picking YUV422.
1497 */
drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv422(struct kunit * test)1498 static void drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv422(struct kunit *test)
1499 {
1500 struct drm_atomic_helper_connector_hdmi_priv *priv;
1501 struct drm_modeset_acquire_ctx ctx;
1502 struct drm_connector_state *conn_state;
1503 struct drm_display_info *info;
1504 struct drm_display_mode *preferred;
1505 unsigned long long rate;
1506 struct drm_connector *conn;
1507 struct drm_device *drm;
1508 struct drm_crtc *crtc;
1509 int ret;
1510
1511 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
1512 BIT(HDMI_COLORSPACE_RGB) |
1513 BIT(HDMI_COLORSPACE_YUV422) |
1514 BIT(HDMI_COLORSPACE_YUV444),
1515 12,
1516 &dummy_connector_hdmi_funcs,
1517 test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz);
1518 KUNIT_ASSERT_NOT_NULL(test, priv);
1519
1520 drm = &priv->drm;
1521 crtc = priv->crtc;
1522 conn = &priv->connector;
1523 info = &conn->display_info;
1524 KUNIT_ASSERT_TRUE(test, info->is_hdmi);
1525 KUNIT_ASSERT_GT(test, info->max_tmds_clock, 0);
1526
1527 preferred = find_preferred_mode(conn);
1528 KUNIT_ASSERT_NOT_NULL(test, preferred);
1529 KUNIT_ASSERT_FALSE(test, preferred->flags & DRM_MODE_FLAG_DBLCLK);
1530
1531 rate = drm_hdmi_compute_mode_clock(preferred, 10, HDMI_COLORSPACE_RGB);
1532 KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
1533
1534 rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_RGB);
1535 KUNIT_ASSERT_GT(test, rate, info->max_tmds_clock * 1000);
1536
1537 rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_YUV422);
1538 KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
1539
1540 drm_modeset_acquire_init(&ctx, 0);
1541
1542 retry_conn_enable:
1543 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
1544 crtc, conn,
1545 preferred,
1546 &ctx);
1547 if (ret == -EDEADLK) {
1548 ret = drm_modeset_backoff(&ctx);
1549 if (!ret)
1550 goto retry_conn_enable;
1551 }
1552 KUNIT_EXPECT_EQ(test, ret, 0);
1553
1554 conn_state = conn->state;
1555 KUNIT_ASSERT_NOT_NULL(test, conn_state);
1556
1557 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 10);
1558 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB);
1559
1560 drm_modeset_drop_locks(&ctx);
1561 drm_modeset_acquire_fini(&ctx);
1562 }
1563
1564 /*
1565 * Test that if:
1566 * - We have an HDMI connector supporting both RGB and YUV420 and up to
1567 * 12 bpc
1568 * - The chosen mode has a TMDS character rate higher than the display
1569 * supports in RGB/10bpc but lower than the display supports in
1570 * RGB/8bpc
1571 * - The chosen mode has a TMDS character rate lower than the display
1572 * supports in YUV420/12bpc.
1573 *
1574 * Then we will prefer to keep the RGB format with a lower bpc over
1575 * picking YUV420.
1576 */
drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv420(struct kunit * test)1577 static void drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv420(struct kunit *test)
1578 {
1579 struct drm_atomic_helper_connector_hdmi_priv *priv;
1580 struct drm_modeset_acquire_ctx ctx;
1581 struct drm_connector_state *conn_state;
1582 struct drm_display_info *info;
1583 struct drm_display_mode *preferred;
1584 unsigned long long rate;
1585 struct drm_connector *conn;
1586 struct drm_device *drm;
1587 struct drm_crtc *crtc;
1588 int ret;
1589
1590 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
1591 BIT(HDMI_COLORSPACE_RGB) |
1592 BIT(HDMI_COLORSPACE_YUV420),
1593 12,
1594 &dummy_connector_hdmi_funcs,
1595 test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz);
1596 KUNIT_ASSERT_NOT_NULL(test, priv);
1597
1598 drm = &priv->drm;
1599 crtc = priv->crtc;
1600 conn = &priv->connector;
1601 info = &conn->display_info;
1602 KUNIT_ASSERT_TRUE(test, info->is_hdmi);
1603 KUNIT_ASSERT_GT(test, info->max_tmds_clock, 0);
1604 KUNIT_ASSERT_TRUE(test, conn->ycbcr_420_allowed);
1605
1606 preferred = find_preferred_mode(conn);
1607 KUNIT_ASSERT_NOT_NULL(test, preferred);
1608 KUNIT_ASSERT_FALSE(test, preferred->flags & DRM_MODE_FLAG_DBLCLK);
1609 KUNIT_ASSERT_TRUE(test, drm_mode_is_420_also(info, preferred));
1610
1611 rate = drm_hdmi_compute_mode_clock(preferred, 8, HDMI_COLORSPACE_RGB);
1612 KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
1613
1614 rate = drm_hdmi_compute_mode_clock(preferred, 10, HDMI_COLORSPACE_RGB);
1615 KUNIT_ASSERT_GT(test, rate, info->max_tmds_clock * 1000);
1616
1617 rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_YUV420);
1618 KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
1619
1620 drm_modeset_acquire_init(&ctx, 0);
1621
1622 retry_conn_enable:
1623 ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn,
1624 preferred, &ctx);
1625 if (ret == -EDEADLK) {
1626 ret = drm_modeset_backoff(&ctx);
1627 if (!ret)
1628 goto retry_conn_enable;
1629 }
1630 KUNIT_EXPECT_EQ(test, ret, 0);
1631
1632 conn_state = conn->state;
1633 KUNIT_ASSERT_NOT_NULL(test, conn_state);
1634
1635 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 8);
1636 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB);
1637
1638 drm_modeset_drop_locks(&ctx);
1639 drm_modeset_acquire_fini(&ctx);
1640 }
1641
1642 /*
1643 * Test that if a driver supports only RGB, but the chosen mode can be
1644 * supported by the screen only in YUV420 output format, we end up with
1645 * unsuccessful fallback attempts.
1646 */
drm_test_check_driver_unsupported_fallback_yuv420(struct kunit * test)1647 static void drm_test_check_driver_unsupported_fallback_yuv420(struct kunit *test)
1648 {
1649 struct drm_atomic_helper_connector_hdmi_priv *priv;
1650 struct drm_modeset_acquire_ctx ctx;
1651 struct drm_connector_state *conn_state;
1652 struct drm_crtc_state *crtc_state;
1653 struct drm_atomic_state *state;
1654 struct drm_display_info *info;
1655 struct drm_display_mode *preferred, *yuv420_only_mode;
1656 struct drm_connector *conn;
1657 struct drm_device *drm;
1658 struct drm_crtc *crtc;
1659 int ret;
1660
1661 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
1662 BIT(HDMI_COLORSPACE_RGB),
1663 12,
1664 &dummy_connector_hdmi_funcs,
1665 test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz);
1666 KUNIT_ASSERT_NOT_NULL(test, priv);
1667
1668 drm = &priv->drm;
1669 crtc = priv->crtc;
1670 conn = &priv->connector;
1671 info = &conn->display_info;
1672 KUNIT_ASSERT_TRUE(test, info->is_hdmi);
1673 KUNIT_ASSERT_FALSE(test, conn->ycbcr_420_allowed);
1674
1675 preferred = find_preferred_mode(conn);
1676 KUNIT_ASSERT_NOT_NULL(test, preferred);
1677 KUNIT_ASSERT_FALSE(test, drm_mode_is_420_also(info, preferred));
1678
1679 yuv420_only_mode = drm_kunit_display_mode_from_cea_vic(test, drm, 95);
1680 KUNIT_ASSERT_NOT_NULL(test, yuv420_only_mode);
1681 KUNIT_ASSERT_TRUE(test, drm_mode_is_420_only(info, yuv420_only_mode));
1682
1683 drm_modeset_acquire_init(&ctx, 0);
1684
1685 retry_conn_enable:
1686 ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn,
1687 preferred, &ctx);
1688 if (ret == -EDEADLK) {
1689 ret = drm_modeset_backoff(&ctx);
1690 if (!ret)
1691 goto retry_conn_enable;
1692 }
1693 KUNIT_EXPECT_EQ(test, ret, 0);
1694
1695 conn_state = conn->state;
1696 KUNIT_ASSERT_NOT_NULL(test, conn_state);
1697 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB);
1698
1699 state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
1700 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
1701
1702 retry_crtc_state:
1703 crtc_state = drm_atomic_get_crtc_state(state, crtc);
1704 if (PTR_ERR(crtc_state) == -EDEADLK) {
1705 drm_atomic_state_clear(state);
1706 ret = drm_modeset_backoff(&ctx);
1707 if (!ret)
1708 goto retry_crtc_state;
1709 }
1710 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
1711
1712 ret = drm_atomic_set_mode_for_crtc(crtc_state, yuv420_only_mode);
1713 KUNIT_EXPECT_EQ(test, ret, 0);
1714
1715 ret = drm_atomic_check_only(state);
1716 if (ret == -EDEADLK) {
1717 drm_atomic_state_clear(state);
1718 ret = drm_modeset_backoff(&ctx);
1719 if (!ret)
1720 goto retry_crtc_state;
1721 }
1722 KUNIT_ASSERT_LT(test, ret, 0);
1723
1724 drm_modeset_drop_locks(&ctx);
1725 drm_modeset_acquire_fini(&ctx);
1726 }
1727
1728 /*
1729 * Test that if a driver and screen supports RGB and YUV formats, and we
1730 * try to set the VIC 1 mode, we end up with 8bpc RGB even if we could
1731 * have had a higher bpc.
1732 */
drm_test_check_output_bpc_format_vic_1(struct kunit * test)1733 static void drm_test_check_output_bpc_format_vic_1(struct kunit *test)
1734 {
1735 struct drm_atomic_helper_connector_hdmi_priv *priv;
1736 struct drm_modeset_acquire_ctx ctx;
1737 struct drm_connector_state *conn_state;
1738 struct drm_display_info *info;
1739 struct drm_display_mode *mode;
1740 unsigned long long rate;
1741 struct drm_connector *conn;
1742 struct drm_device *drm;
1743 struct drm_crtc *crtc;
1744 int ret;
1745
1746 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
1747 BIT(HDMI_COLORSPACE_RGB) |
1748 BIT(HDMI_COLORSPACE_YUV422) |
1749 BIT(HDMI_COLORSPACE_YUV444),
1750 12,
1751 &dummy_connector_hdmi_funcs,
1752 test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz);
1753 KUNIT_ASSERT_NOT_NULL(test, priv);
1754
1755 drm = &priv->drm;
1756 conn = &priv->connector;
1757 info = &conn->display_info;
1758 KUNIT_ASSERT_TRUE(test, info->is_hdmi);
1759 KUNIT_ASSERT_GT(test, info->max_tmds_clock, 0);
1760
1761 mode = drm_kunit_display_mode_from_cea_vic(test, drm, 1);
1762 KUNIT_ASSERT_NOT_NULL(test, mode);
1763
1764 /*
1765 * NOTE: We can't use drm_hdmi_compute_mode_clock()
1766 * here because we're trying to get the rate of an invalid
1767 * configuration.
1768 *
1769 * Thus, we have to calculate the rate by hand.
1770 */
1771 rate = mode->clock * 1500;
1772 KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
1773
1774 drm_modeset_acquire_init(&ctx, 0);
1775
1776 crtc = priv->crtc;
1777
1778 retry_conn_enable:
1779 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
1780 crtc, conn,
1781 mode,
1782 &ctx);
1783 if (ret == -EDEADLK) {
1784 ret = drm_modeset_backoff(&ctx);
1785 if (!ret)
1786 goto retry_conn_enable;
1787 }
1788 KUNIT_EXPECT_EQ(test, ret, 0);
1789
1790 conn_state = conn->state;
1791 KUNIT_ASSERT_NOT_NULL(test, conn_state);
1792
1793 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 8);
1794 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB);
1795
1796 drm_modeset_drop_locks(&ctx);
1797 drm_modeset_acquire_fini(&ctx);
1798 }
1799
1800 /*
1801 * Test that if a driver supports only RGB but the screen also supports
1802 * YUV formats, we only end up with an RGB format.
1803 */
drm_test_check_output_bpc_format_driver_rgb_only(struct kunit * test)1804 static void drm_test_check_output_bpc_format_driver_rgb_only(struct kunit *test)
1805 {
1806 struct drm_atomic_helper_connector_hdmi_priv *priv;
1807 struct drm_modeset_acquire_ctx ctx;
1808 struct drm_connector_state *conn_state;
1809 struct drm_display_info *info;
1810 struct drm_display_mode *preferred;
1811 unsigned long long rate;
1812 struct drm_connector *conn;
1813 struct drm_device *drm;
1814 struct drm_crtc *crtc;
1815 int ret;
1816
1817 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
1818 BIT(HDMI_COLORSPACE_RGB),
1819 12,
1820 &dummy_connector_hdmi_funcs,
1821 test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz);
1822 KUNIT_ASSERT_NOT_NULL(test, priv);
1823
1824 drm = &priv->drm;
1825 crtc = priv->crtc;
1826 conn = &priv->connector;
1827 info = &conn->display_info;
1828 KUNIT_ASSERT_TRUE(test, info->is_hdmi);
1829 KUNIT_ASSERT_GT(test, info->max_tmds_clock, 0);
1830
1831 preferred = find_preferred_mode(conn);
1832 KUNIT_ASSERT_NOT_NULL(test, preferred);
1833
1834 /*
1835 * We're making sure that YUV422 would be the preferred option
1836 * here: we're always favouring higher bpc, we can't have RGB
1837 * because the TMDS character rate exceeds the maximum supported
1838 * by the display, and YUV422 works for that display.
1839 *
1840 * But since the driver only supports RGB, we should fallback to
1841 * a lower bpc with RGB.
1842 */
1843 rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_RGB);
1844 KUNIT_ASSERT_GT(test, rate, info->max_tmds_clock * 1000);
1845
1846 rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_YUV422);
1847 KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
1848
1849 drm_modeset_acquire_init(&ctx, 0);
1850
1851 retry_conn_enable:
1852 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
1853 crtc, conn,
1854 preferred,
1855 &ctx);
1856 if (ret == -EDEADLK) {
1857 ret = drm_modeset_backoff(&ctx);
1858 if (!ret)
1859 goto retry_conn_enable;
1860 }
1861 KUNIT_EXPECT_EQ(test, ret, 0);
1862
1863 conn_state = conn->state;
1864 KUNIT_ASSERT_NOT_NULL(test, conn_state);
1865
1866 KUNIT_EXPECT_LT(test, conn_state->hdmi.output_bpc, 12);
1867 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB);
1868
1869 drm_modeset_drop_locks(&ctx);
1870 drm_modeset_acquire_fini(&ctx);
1871 }
1872
1873 /*
1874 * Test that if a screen supports only RGB but the driver also supports
1875 * YUV formats, we only end up with an RGB format.
1876 */
drm_test_check_output_bpc_format_display_rgb_only(struct kunit * test)1877 static void drm_test_check_output_bpc_format_display_rgb_only(struct kunit *test)
1878 {
1879 struct drm_atomic_helper_connector_hdmi_priv *priv;
1880 struct drm_modeset_acquire_ctx ctx;
1881 struct drm_connector_state *conn_state;
1882 struct drm_display_info *info;
1883 struct drm_display_mode *preferred;
1884 unsigned long long rate;
1885 struct drm_connector *conn;
1886 struct drm_device *drm;
1887 struct drm_crtc *crtc;
1888 int ret;
1889
1890 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
1891 BIT(HDMI_COLORSPACE_RGB) |
1892 BIT(HDMI_COLORSPACE_YUV422) |
1893 BIT(HDMI_COLORSPACE_YUV444),
1894 12,
1895 &dummy_connector_hdmi_funcs,
1896 test_edid_hdmi_1080p_rgb_max_200mhz);
1897 KUNIT_ASSERT_NOT_NULL(test, priv);
1898
1899 drm = &priv->drm;
1900 crtc = priv->crtc;
1901 conn = &priv->connector;
1902 info = &conn->display_info;
1903 KUNIT_ASSERT_TRUE(test, info->is_hdmi);
1904 KUNIT_ASSERT_GT(test, info->max_tmds_clock, 0);
1905
1906 preferred = find_preferred_mode(conn);
1907 KUNIT_ASSERT_NOT_NULL(test, preferred);
1908
1909 /*
1910 * We're making sure that YUV422 would be the preferred option
1911 * here: we're always favouring higher bpc, we can't have RGB
1912 * because the TMDS character rate exceeds the maximum supported
1913 * by the display, and YUV422 works for that display.
1914 *
1915 * But since the display only supports RGB, we should fallback to
1916 * a lower bpc with RGB.
1917 */
1918 rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_RGB);
1919 KUNIT_ASSERT_GT(test, rate, info->max_tmds_clock * 1000);
1920
1921 rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_YUV422);
1922 KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
1923
1924 drm_modeset_acquire_init(&ctx, 0);
1925
1926 retry_conn_enable:
1927 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
1928 crtc, conn,
1929 preferred,
1930 &ctx);
1931 if (ret == -EDEADLK) {
1932 ret = drm_modeset_backoff(&ctx);
1933 if (!ret)
1934 goto retry_conn_enable;
1935 }
1936 KUNIT_EXPECT_EQ(test, ret, 0);
1937
1938 conn_state = conn->state;
1939 KUNIT_ASSERT_NOT_NULL(test, conn_state);
1940
1941 KUNIT_EXPECT_LT(test, conn_state->hdmi.output_bpc, 12);
1942 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB);
1943
1944 drm_modeset_drop_locks(&ctx);
1945 drm_modeset_acquire_fini(&ctx);
1946 }
1947
1948 /*
1949 * Test that if a display supports higher bpc but the driver only
1950 * supports 8 bpc, we only end up with 8 bpc even if we could have had a
1951 * higher bpc.
1952 */
drm_test_check_output_bpc_format_driver_8bpc_only(struct kunit * test)1953 static void drm_test_check_output_bpc_format_driver_8bpc_only(struct kunit *test)
1954 {
1955 struct drm_atomic_helper_connector_hdmi_priv *priv;
1956 struct drm_modeset_acquire_ctx ctx;
1957 struct drm_connector_state *conn_state;
1958 struct drm_display_info *info;
1959 struct drm_display_mode *preferred;
1960 unsigned long long rate;
1961 struct drm_connector *conn;
1962 struct drm_device *drm;
1963 struct drm_crtc *crtc;
1964 int ret;
1965
1966 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
1967 BIT(HDMI_COLORSPACE_RGB),
1968 8,
1969 &dummy_connector_hdmi_funcs,
1970 test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz);
1971 KUNIT_ASSERT_NOT_NULL(test, priv);
1972
1973 drm = &priv->drm;
1974 crtc = priv->crtc;
1975 conn = &priv->connector;
1976 info = &conn->display_info;
1977 KUNIT_ASSERT_TRUE(test, info->is_hdmi);
1978 KUNIT_ASSERT_GT(test, info->max_tmds_clock, 0);
1979
1980 preferred = find_preferred_mode(conn);
1981 KUNIT_ASSERT_NOT_NULL(test, preferred);
1982
1983 /*
1984 * We're making sure that we have headroom on the TMDS character
1985 * clock to actually use 12bpc.
1986 */
1987 rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_RGB);
1988 KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
1989
1990 drm_modeset_acquire_init(&ctx, 0);
1991
1992 retry_conn_enable:
1993 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
1994 crtc, conn,
1995 preferred,
1996 &ctx);
1997 if (ret == -EDEADLK) {
1998 ret = drm_modeset_backoff(&ctx);
1999 if (!ret)
2000 goto retry_conn_enable;
2001 }
2002 KUNIT_EXPECT_EQ(test, ret, 0);
2003
2004 conn_state = conn->state;
2005 KUNIT_ASSERT_NOT_NULL(test, conn_state);
2006
2007 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 8);
2008 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB);
2009
2010 drm_modeset_drop_locks(&ctx);
2011 drm_modeset_acquire_fini(&ctx);
2012 }
2013
2014 /*
2015 * Test that if a driver supports higher bpc but the display only
2016 * supports 8 bpc, we only end up with 8 bpc even if we could have had a
2017 * higher bpc.
2018 */
drm_test_check_output_bpc_format_display_8bpc_only(struct kunit * test)2019 static void drm_test_check_output_bpc_format_display_8bpc_only(struct kunit *test)
2020 {
2021 struct drm_atomic_helper_connector_hdmi_priv *priv;
2022 struct drm_modeset_acquire_ctx ctx;
2023 struct drm_connector_state *conn_state;
2024 struct drm_display_info *info;
2025 struct drm_display_mode *preferred;
2026 unsigned long long rate;
2027 struct drm_connector *conn;
2028 struct drm_device *drm;
2029 struct drm_crtc *crtc;
2030 int ret;
2031
2032 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
2033 BIT(HDMI_COLORSPACE_RGB) |
2034 BIT(HDMI_COLORSPACE_YUV422) |
2035 BIT(HDMI_COLORSPACE_YUV444),
2036 12,
2037 &dummy_connector_hdmi_funcs,
2038 test_edid_hdmi_1080p_rgb_max_340mhz);
2039 KUNIT_ASSERT_NOT_NULL(test, priv);
2040
2041 drm = &priv->drm;
2042 crtc = priv->crtc;
2043 conn = &priv->connector;
2044 info = &conn->display_info;
2045 KUNIT_ASSERT_TRUE(test, info->is_hdmi);
2046 KUNIT_ASSERT_GT(test, info->max_tmds_clock, 0);
2047
2048 preferred = find_preferred_mode(conn);
2049 KUNIT_ASSERT_NOT_NULL(test, preferred);
2050
2051 /*
2052 * We're making sure that we have headroom on the TMDS character
2053 * clock to actually use 12bpc.
2054 */
2055 rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_RGB);
2056 KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
2057
2058 drm_modeset_acquire_init(&ctx, 0);
2059
2060 retry_conn_enable:
2061 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
2062 crtc, conn,
2063 preferred,
2064 &ctx);
2065 if (ret == -EDEADLK) {
2066 ret = drm_modeset_backoff(&ctx);
2067 if (!ret)
2068 goto retry_conn_enable;
2069 }
2070 KUNIT_EXPECT_EQ(test, ret, 0);
2071
2072 conn_state = conn->state;
2073 KUNIT_ASSERT_NOT_NULL(test, conn_state);
2074
2075 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 8);
2076 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB);
2077
2078 drm_modeset_drop_locks(&ctx);
2079 drm_modeset_acquire_fini(&ctx);
2080 }
2081
2082 /* Test that atomic check succeeds when disabling a connector. */
drm_test_check_disable_connector(struct kunit * test)2083 static void drm_test_check_disable_connector(struct kunit *test)
2084 {
2085 struct drm_atomic_helper_connector_hdmi_priv *priv;
2086 struct drm_modeset_acquire_ctx ctx;
2087 struct drm_connector_state *conn_state;
2088 struct drm_crtc_state *crtc_state;
2089 struct drm_atomic_state *state;
2090 struct drm_display_mode *preferred;
2091 struct drm_connector *conn;
2092 struct drm_device *drm;
2093 struct drm_crtc *crtc;
2094 int ret;
2095
2096 priv = drm_kunit_helper_connector_hdmi_init(test,
2097 BIT(HDMI_COLORSPACE_RGB),
2098 8);
2099 KUNIT_ASSERT_NOT_NULL(test, priv);
2100
2101 drm_modeset_acquire_init(&ctx, 0);
2102
2103 conn = &priv->connector;
2104 preferred = find_preferred_mode(conn);
2105 KUNIT_ASSERT_NOT_NULL(test, preferred);
2106
2107 drm = &priv->drm;
2108 crtc = priv->crtc;
2109
2110 retry_conn_enable:
2111 ret = drm_kunit_helper_enable_crtc_connector(test, drm,
2112 crtc, conn,
2113 preferred,
2114 &ctx);
2115 if (ret == -EDEADLK) {
2116 ret = drm_modeset_backoff(&ctx);
2117 if (!ret)
2118 goto retry_conn_enable;
2119 }
2120 KUNIT_ASSERT_EQ(test, ret, 0);
2121
2122 state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
2123 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
2124
2125 crtc_state = drm_atomic_get_crtc_state(state, crtc);
2126 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
2127
2128 crtc_state->active = false;
2129 ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL);
2130 KUNIT_EXPECT_EQ(test, ret, 0);
2131
2132 conn_state = drm_atomic_get_connector_state(state, conn);
2133 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
2134
2135 ret = drm_atomic_set_crtc_for_connector(conn_state, NULL);
2136 KUNIT_EXPECT_EQ(test, ret, 0);
2137
2138 ret = drm_atomic_check_only(state);
2139 KUNIT_ASSERT_EQ(test, ret, 0);
2140
2141 drm_modeset_drop_locks(&ctx);
2142 drm_modeset_acquire_fini(&ctx);
2143 }
2144
2145 static struct kunit_case drm_atomic_helper_connector_hdmi_check_tests[] = {
2146 KUNIT_CASE(drm_test_check_broadcast_rgb_auto_cea_mode),
2147 KUNIT_CASE(drm_test_check_broadcast_rgb_auto_cea_mode_vic_1),
2148 KUNIT_CASE(drm_test_check_broadcast_rgb_full_cea_mode),
2149 KUNIT_CASE(drm_test_check_broadcast_rgb_full_cea_mode_vic_1),
2150 KUNIT_CASE(drm_test_check_broadcast_rgb_limited_cea_mode),
2151 KUNIT_CASE(drm_test_check_broadcast_rgb_limited_cea_mode_vic_1),
2152 KUNIT_CASE_PARAM(drm_test_check_broadcast_rgb_cea_mode_yuv420,
2153 check_broadcast_rgb_cea_mode_yuv420_gen_params),
2154 KUNIT_CASE(drm_test_check_broadcast_rgb_crtc_mode_changed),
2155 KUNIT_CASE(drm_test_check_broadcast_rgb_crtc_mode_not_changed),
2156 KUNIT_CASE(drm_test_check_disable_connector),
2157 KUNIT_CASE(drm_test_check_hdmi_funcs_reject_rate),
2158 KUNIT_CASE(drm_test_check_max_tmds_rate_bpc_fallback_rgb),
2159 KUNIT_CASE(drm_test_check_max_tmds_rate_bpc_fallback_yuv420),
2160 KUNIT_CASE(drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv422),
2161 KUNIT_CASE(drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv420),
2162 KUNIT_CASE(drm_test_check_driver_unsupported_fallback_yuv420),
2163 KUNIT_CASE(drm_test_check_output_bpc_crtc_mode_changed),
2164 KUNIT_CASE(drm_test_check_output_bpc_crtc_mode_not_changed),
2165 KUNIT_CASE(drm_test_check_output_bpc_dvi),
2166 KUNIT_CASE(drm_test_check_output_bpc_format_vic_1),
2167 KUNIT_CASE(drm_test_check_output_bpc_format_display_8bpc_only),
2168 KUNIT_CASE(drm_test_check_output_bpc_format_display_rgb_only),
2169 KUNIT_CASE(drm_test_check_output_bpc_format_driver_8bpc_only),
2170 KUNIT_CASE(drm_test_check_output_bpc_format_driver_rgb_only),
2171 KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_8bpc),
2172 KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_10bpc),
2173 KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_12bpc),
2174 /*
2175 * TODO: We should have tests to check that a change in the
2176 * format triggers a CRTC mode change just like we do for the
2177 * RGB Quantization and BPC.
2178 *
2179 * However, we don't have any way to control which format gets
2180 * picked up aside from changing the BPC or mode which would
2181 * already trigger a mode change.
2182 */
2183 { }
2184 };
2185
2186 static struct kunit_suite drm_atomic_helper_connector_hdmi_check_test_suite = {
2187 .name = "drm_atomic_helper_connector_hdmi_check",
2188 .test_cases = drm_atomic_helper_connector_hdmi_check_tests,
2189 };
2190
2191 /*
2192 * Test that the value of the Broadcast RGB property out of reset is set
2193 * to auto.
2194 */
drm_test_check_broadcast_rgb_value(struct kunit * test)2195 static void drm_test_check_broadcast_rgb_value(struct kunit *test)
2196 {
2197 struct drm_atomic_helper_connector_hdmi_priv *priv;
2198 struct drm_connector_state *conn_state;
2199 struct drm_connector *conn;
2200
2201 priv = drm_kunit_helper_connector_hdmi_init(test,
2202 BIT(HDMI_COLORSPACE_RGB),
2203 8);
2204 KUNIT_ASSERT_NOT_NULL(test, priv);
2205
2206 conn = &priv->connector;
2207 conn_state = conn->state;
2208 KUNIT_EXPECT_EQ(test, conn_state->hdmi.broadcast_rgb, DRM_HDMI_BROADCAST_RGB_AUTO);
2209 }
2210
2211 /*
2212 * Test that if the connector was initialised with a maximum bpc of 8,
2213 * the value of the max_bpc and max_requested_bpc properties out of
2214 * reset are also set to 8, and output_bpc is set to 0 and will be
2215 * filled at atomic_check time.
2216 */
drm_test_check_bpc_8_value(struct kunit * test)2217 static void drm_test_check_bpc_8_value(struct kunit *test)
2218 {
2219 struct drm_atomic_helper_connector_hdmi_priv *priv;
2220 struct drm_connector_state *conn_state;
2221 struct drm_connector *conn;
2222
2223 priv = drm_kunit_helper_connector_hdmi_init(test,
2224 BIT(HDMI_COLORSPACE_RGB),
2225 8);
2226 KUNIT_ASSERT_NOT_NULL(test, priv);
2227
2228 conn = &priv->connector;
2229 conn_state = conn->state;
2230 KUNIT_EXPECT_EQ(test, conn_state->max_bpc, 8);
2231 KUNIT_EXPECT_EQ(test, conn_state->max_requested_bpc, 8);
2232 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 0);
2233 }
2234
2235 /*
2236 * Test that if the connector was initialised with a maximum bpc of 10,
2237 * the value of the max_bpc and max_requested_bpc properties out of
2238 * reset are also set to 10, and output_bpc is set to 0 and will be
2239 * filled at atomic_check time.
2240 */
drm_test_check_bpc_10_value(struct kunit * test)2241 static void drm_test_check_bpc_10_value(struct kunit *test)
2242 {
2243 struct drm_atomic_helper_connector_hdmi_priv *priv;
2244 struct drm_connector_state *conn_state;
2245 struct drm_connector *conn;
2246
2247 priv = drm_kunit_helper_connector_hdmi_init(test,
2248 BIT(HDMI_COLORSPACE_RGB),
2249 10);
2250 KUNIT_ASSERT_NOT_NULL(test, priv);
2251
2252 conn = &priv->connector;
2253 conn_state = conn->state;
2254 KUNIT_EXPECT_EQ(test, conn_state->max_bpc, 10);
2255 KUNIT_EXPECT_EQ(test, conn_state->max_requested_bpc, 10);
2256 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 0);
2257 }
2258
2259 /*
2260 * Test that if the connector was initialised with a maximum bpc of 12,
2261 * the value of the max_bpc and max_requested_bpc properties out of
2262 * reset are also set to 12, and output_bpc is set to 0 and will be
2263 * filled at atomic_check time.
2264 */
drm_test_check_bpc_12_value(struct kunit * test)2265 static void drm_test_check_bpc_12_value(struct kunit *test)
2266 {
2267 struct drm_atomic_helper_connector_hdmi_priv *priv;
2268 struct drm_connector_state *conn_state;
2269 struct drm_connector *conn;
2270
2271 priv = drm_kunit_helper_connector_hdmi_init(test,
2272 BIT(HDMI_COLORSPACE_RGB),
2273 12);
2274 KUNIT_ASSERT_NOT_NULL(test, priv);
2275
2276 conn = &priv->connector;
2277 conn_state = conn->state;
2278 KUNIT_EXPECT_EQ(test, conn_state->max_bpc, 12);
2279 KUNIT_EXPECT_EQ(test, conn_state->max_requested_bpc, 12);
2280 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 0);
2281 }
2282
2283 /*
2284 * Test that the value of the output format property out of reset is set
2285 * to RGB, even if the driver supports more than that.
2286 */
drm_test_check_format_value(struct kunit * test)2287 static void drm_test_check_format_value(struct kunit *test)
2288 {
2289 struct drm_atomic_helper_connector_hdmi_priv *priv;
2290 struct drm_connector_state *conn_state;
2291 struct drm_connector *conn;
2292
2293 priv = drm_kunit_helper_connector_hdmi_init(test,
2294 BIT(HDMI_COLORSPACE_RGB) |
2295 BIT(HDMI_COLORSPACE_YUV422) |
2296 BIT(HDMI_COLORSPACE_YUV444),
2297 8);
2298 KUNIT_ASSERT_NOT_NULL(test, priv);
2299
2300 conn = &priv->connector;
2301 conn_state = conn->state;
2302 KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, 0);
2303 }
2304
2305 /*
2306 * Test that the value of the output format property out of reset is set
2307 * to 0, and will be computed at atomic_check time.
2308 */
drm_test_check_tmds_char_value(struct kunit * test)2309 static void drm_test_check_tmds_char_value(struct kunit *test)
2310 {
2311 struct drm_atomic_helper_connector_hdmi_priv *priv;
2312 struct drm_connector_state *conn_state;
2313 struct drm_connector *conn;
2314
2315 priv = drm_kunit_helper_connector_hdmi_init(test,
2316 BIT(HDMI_COLORSPACE_RGB) |
2317 BIT(HDMI_COLORSPACE_YUV422) |
2318 BIT(HDMI_COLORSPACE_YUV444),
2319 12);
2320 KUNIT_ASSERT_NOT_NULL(test, priv);
2321
2322 conn = &priv->connector;
2323 conn_state = conn->state;
2324 KUNIT_EXPECT_EQ(test, conn_state->hdmi.tmds_char_rate, 0);
2325 }
2326
2327 static struct kunit_case drm_atomic_helper_connector_hdmi_reset_tests[] = {
2328 KUNIT_CASE(drm_test_check_broadcast_rgb_value),
2329 KUNIT_CASE(drm_test_check_bpc_8_value),
2330 KUNIT_CASE(drm_test_check_bpc_10_value),
2331 KUNIT_CASE(drm_test_check_bpc_12_value),
2332 KUNIT_CASE(drm_test_check_format_value),
2333 KUNIT_CASE(drm_test_check_tmds_char_value),
2334 { }
2335 };
2336
2337 static struct kunit_suite drm_atomic_helper_connector_hdmi_reset_test_suite = {
2338 .name = "drm_atomic_helper_connector_hdmi_reset",
2339 .test_cases = drm_atomic_helper_connector_hdmi_reset_tests,
2340 };
2341
2342 /*
2343 * Test that the default behaviour for drm_hdmi_connector_mode_valid() is not
2344 * to reject any modes. Pass a correct EDID and verify that preferred mode
2345 * matches the expectations (1080p).
2346 */
drm_test_check_mode_valid(struct kunit * test)2347 static void drm_test_check_mode_valid(struct kunit *test)
2348 {
2349 struct drm_atomic_helper_connector_hdmi_priv *priv;
2350 struct drm_connector *conn;
2351 struct drm_display_mode *preferred;
2352
2353 priv = drm_kunit_helper_connector_hdmi_init(test,
2354 BIT(HDMI_COLORSPACE_RGB),
2355 8);
2356 KUNIT_ASSERT_NOT_NULL(test, priv);
2357
2358 conn = &priv->connector;
2359 preferred = find_preferred_mode(conn);
2360 KUNIT_ASSERT_NOT_NULL(test, preferred);
2361
2362 KUNIT_EXPECT_EQ(test, preferred->hdisplay, 1920);
2363 KUNIT_EXPECT_EQ(test, preferred->vdisplay, 1080);
2364 KUNIT_EXPECT_EQ(test, preferred->clock, 148500);
2365 }
2366
2367 /*
2368 * Test that the drm_hdmi_connector_mode_valid() will reject modes depending on
2369 * the .tmds_char_rate_valid() behaviour.
2370 * Pass a correct EDID and verify that high-rate modes are filtered.
2371 */
drm_test_check_mode_valid_reject_rate(struct kunit * test)2372 static void drm_test_check_mode_valid_reject_rate(struct kunit *test)
2373 {
2374 struct drm_atomic_helper_connector_hdmi_priv *priv;
2375 struct drm_display_mode *preferred;
2376
2377 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
2378 BIT(HDMI_COLORSPACE_RGB),
2379 8,
2380 &reject_100mhz_connector_hdmi_funcs,
2381 test_edid_hdmi_1080p_rgb_max_200mhz);
2382 KUNIT_ASSERT_NOT_NULL(test, priv);
2383
2384 /*
2385 * Unlike the drm_test_check_mode_valid() here 1080p is rejected, but
2386 * 480p is allowed.
2387 */
2388 preferred = find_preferred_mode(&priv->connector);
2389 KUNIT_ASSERT_NOT_NULL(test, preferred);
2390 KUNIT_EXPECT_EQ(test, preferred->hdisplay, 640);
2391 KUNIT_EXPECT_EQ(test, preferred->vdisplay, 480);
2392 KUNIT_EXPECT_EQ(test, preferred->clock, 25200);
2393 }
2394
2395 /*
2396 * Test that the drm_hdmi_connector_mode_valid() will not mark any modes as
2397 * valid if .tmds_char_rate_valid() rejects all of them. Pass a correct EDID
2398 * and verify that there is no preferred mode and no modes were set for the
2399 * connector.
2400 */
drm_test_check_mode_valid_reject(struct kunit * test)2401 static void drm_test_check_mode_valid_reject(struct kunit *test)
2402 {
2403 struct drm_atomic_helper_connector_hdmi_priv *priv;
2404 struct drm_connector *conn;
2405 struct drm_display_mode *preferred;
2406 unsigned char no_edid[] = {};
2407 int ret;
2408
2409 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
2410 BIT(HDMI_COLORSPACE_RGB),
2411 8,
2412 &reject_connector_hdmi_funcs,
2413 no_edid);
2414 KUNIT_ASSERT_NOT_NULL(test, priv);
2415
2416 conn = &priv->connector;
2417
2418 /* should reject all modes */
2419 ret = set_connector_edid(test, conn,
2420 test_edid_hdmi_1080p_rgb_max_200mhz,
2421 ARRAY_SIZE(test_edid_hdmi_1080p_rgb_max_200mhz));
2422 KUNIT_ASSERT_EQ(test, ret, 0);
2423
2424 preferred = find_preferred_mode(conn);
2425 KUNIT_ASSERT_NULL(test, preferred);
2426 }
2427
2428 /*
2429 * Test that the drm_hdmi_connector_mode_valid() will reject modes that don't
2430 * pass the info.max_tmds_clock filter. Pass crafted EDID and verify that
2431 * high-rate modes are filtered.
2432 */
drm_test_check_mode_valid_reject_max_clock(struct kunit * test)2433 static void drm_test_check_mode_valid_reject_max_clock(struct kunit *test)
2434 {
2435 struct drm_atomic_helper_connector_hdmi_priv *priv;
2436 struct drm_connector *conn;
2437 struct drm_display_mode *preferred;
2438
2439 priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
2440 BIT(HDMI_COLORSPACE_RGB),
2441 8,
2442 &dummy_connector_hdmi_funcs,
2443 test_edid_hdmi_1080p_rgb_max_100mhz);
2444 KUNIT_ASSERT_NOT_NULL(test, priv);
2445
2446 conn = &priv->connector;
2447 KUNIT_ASSERT_EQ(test, conn->display_info.max_tmds_clock, 100 * 1000);
2448
2449 preferred = find_preferred_mode(conn);
2450 KUNIT_ASSERT_NOT_NULL(test, preferred);
2451 KUNIT_EXPECT_EQ(test, preferred->hdisplay, 640);
2452 KUNIT_EXPECT_EQ(test, preferred->vdisplay, 480);
2453 KUNIT_EXPECT_EQ(test, preferred->clock, 25200);
2454 }
2455
2456 static struct kunit_case drm_atomic_helper_connector_hdmi_mode_valid_tests[] = {
2457 KUNIT_CASE(drm_test_check_mode_valid),
2458 KUNIT_CASE(drm_test_check_mode_valid_reject),
2459 KUNIT_CASE(drm_test_check_mode_valid_reject_rate),
2460 KUNIT_CASE(drm_test_check_mode_valid_reject_max_clock),
2461 { }
2462 };
2463
2464 static struct kunit_suite drm_atomic_helper_connector_hdmi_mode_valid_test_suite = {
2465 .name = "drm_atomic_helper_connector_hdmi_mode_valid",
2466 .test_cases = drm_atomic_helper_connector_hdmi_mode_valid_tests,
2467 };
2468
2469 kunit_test_suites(
2470 &drm_atomic_helper_connector_hdmi_check_test_suite,
2471 &drm_atomic_helper_connector_hdmi_reset_test_suite,
2472 &drm_atomic_helper_connector_hdmi_mode_valid_test_suite,
2473 );
2474
2475 MODULE_AUTHOR("Maxime Ripard <mripard@kernel.org>");
2476 MODULE_DESCRIPTION("Kunit test for drm_hdmi_state_helper functions");
2477 MODULE_LICENSE("GPL");
2478