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