xref: /linux/drivers/gpu/drm/tests/drm_bridge_test.c (revision 260f6f4fda93c8485c8037865c941b42b9cba5d2)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Kunit test for drm_bridge functions
4  */
5 #include <drm/drm_atomic_state_helper.h>
6 #include <drm/drm_bridge.h>
7 #include <drm/drm_bridge_connector.h>
8 #include <drm/drm_bridge_helper.h>
9 #include <drm/drm_kunit_helpers.h>
10 
11 #include <kunit/device.h>
12 #include <kunit/test.h>
13 
14 /*
15  * Mimick the typical "private" struct defined by a bridge driver, which
16  * embeds a bridge plus other fields.
17  *
18  * Having at least one member before @bridge ensures we test non-zero
19  * @bridge offset.
20  */
21 struct drm_bridge_priv {
22 	unsigned int enable_count;
23 	unsigned int disable_count;
24 	struct drm_bridge bridge;
25 	void *data;
26 };
27 
28 struct drm_bridge_init_priv {
29 	struct drm_device drm;
30 	/** @dev: device, only for tests not needing a whole drm_device */
31 	struct device *dev;
32 	struct drm_plane *plane;
33 	struct drm_crtc *crtc;
34 	struct drm_encoder encoder;
35 	struct drm_bridge_priv *test_bridge;
36 	struct drm_connector *connector;
37 	bool destroyed;
38 };
39 
40 static struct drm_bridge_priv *bridge_to_priv(struct drm_bridge *bridge)
41 {
42 	return container_of(bridge, struct drm_bridge_priv, bridge);
43 }
44 
45 static void drm_test_bridge_priv_destroy(struct drm_bridge *bridge)
46 {
47 	struct drm_bridge_priv *bridge_priv = bridge_to_priv(bridge);
48 	struct drm_bridge_init_priv *priv = (struct drm_bridge_init_priv *)bridge_priv->data;
49 
50 	priv->destroyed = true;
51 }
52 
53 static void drm_test_bridge_enable(struct drm_bridge *bridge)
54 {
55 	struct drm_bridge_priv *priv = bridge_to_priv(bridge);
56 
57 	priv->enable_count++;
58 }
59 
60 static void drm_test_bridge_disable(struct drm_bridge *bridge)
61 {
62 	struct drm_bridge_priv *priv = bridge_to_priv(bridge);
63 
64 	priv->disable_count++;
65 }
66 
67 static const struct drm_bridge_funcs drm_test_bridge_legacy_funcs = {
68 	.destroy		= drm_test_bridge_priv_destroy,
69 	.enable			= drm_test_bridge_enable,
70 	.disable		= drm_test_bridge_disable,
71 };
72 
73 static void drm_test_bridge_atomic_enable(struct drm_bridge *bridge,
74 					  struct drm_atomic_state *state)
75 {
76 	struct drm_bridge_priv *priv = bridge_to_priv(bridge);
77 
78 	priv->enable_count++;
79 }
80 
81 static void drm_test_bridge_atomic_disable(struct drm_bridge *bridge,
82 					   struct drm_atomic_state *state)
83 {
84 	struct drm_bridge_priv *priv = bridge_to_priv(bridge);
85 
86 	priv->disable_count++;
87 }
88 
89 static const struct drm_bridge_funcs drm_test_bridge_atomic_funcs = {
90 	.destroy		= drm_test_bridge_priv_destroy,
91 	.atomic_enable		= drm_test_bridge_atomic_enable,
92 	.atomic_disable		= drm_test_bridge_atomic_disable,
93 	.atomic_destroy_state	= drm_atomic_helper_bridge_destroy_state,
94 	.atomic_duplicate_state	= drm_atomic_helper_bridge_duplicate_state,
95 	.atomic_reset		= drm_atomic_helper_bridge_reset,
96 };
97 
98 KUNIT_DEFINE_ACTION_WRAPPER(drm_bridge_remove_wrapper,
99 			    drm_bridge_remove,
100 			    struct drm_bridge *);
101 
102 static int drm_kunit_bridge_add(struct kunit *test,
103 				struct drm_bridge *bridge)
104 {
105 	drm_bridge_add(bridge);
106 
107 	return kunit_add_action_or_reset(test,
108 					 drm_bridge_remove_wrapper,
109 					 bridge);
110 }
111 
112 static struct drm_bridge_init_priv *
113 drm_test_bridge_init(struct kunit *test, const struct drm_bridge_funcs *funcs)
114 {
115 	struct drm_bridge_init_priv *priv;
116 	struct drm_encoder *enc;
117 	struct drm_bridge *bridge;
118 	struct drm_device *drm;
119 	struct device *dev;
120 	int ret;
121 
122 	dev = drm_kunit_helper_alloc_device(test);
123 	if (IS_ERR(dev))
124 		return ERR_CAST(dev);
125 
126 	priv = drm_kunit_helper_alloc_drm_device(test, dev,
127 						 struct drm_bridge_init_priv, drm,
128 						 DRIVER_MODESET | DRIVER_ATOMIC);
129 	if (IS_ERR(priv))
130 		return ERR_CAST(priv);
131 
132 	priv->test_bridge = devm_drm_bridge_alloc(dev, struct drm_bridge_priv, bridge, funcs);
133 	if (IS_ERR(priv->test_bridge))
134 		return ERR_CAST(priv->test_bridge);
135 
136 	priv->test_bridge->data = priv;
137 
138 	drm = &priv->drm;
139 	priv->plane = drm_kunit_helper_create_primary_plane(test, drm,
140 							    NULL,
141 							    NULL,
142 							    NULL, 0,
143 							    NULL);
144 	if (IS_ERR(priv->plane))
145 		return ERR_CAST(priv->plane);
146 
147 	priv->crtc = drm_kunit_helper_create_crtc(test, drm,
148 						  priv->plane, NULL,
149 						  NULL,
150 						  NULL);
151 	if (IS_ERR(priv->crtc))
152 		return ERR_CAST(priv->crtc);
153 
154 	enc = &priv->encoder;
155 	ret = drmm_encoder_init(drm, enc, NULL, DRM_MODE_ENCODER_TMDS, NULL);
156 	if (ret)
157 		return ERR_PTR(ret);
158 
159 	enc->possible_crtcs = drm_crtc_mask(priv->crtc);
160 
161 	bridge = &priv->test_bridge->bridge;
162 	bridge->type = DRM_MODE_CONNECTOR_VIRTUAL;
163 
164 	ret = drm_kunit_bridge_add(test, bridge);
165 	if (ret)
166 		return ERR_PTR(ret);
167 
168 	ret = drm_bridge_attach(enc, bridge, NULL, 0);
169 	if (ret)
170 		return ERR_PTR(ret);
171 
172 	priv->connector = drm_bridge_connector_init(drm, enc);
173 	if (IS_ERR(priv->connector))
174 		return ERR_CAST(priv->connector);
175 
176 	drm_connector_attach_encoder(priv->connector, enc);
177 
178 	drm_mode_config_reset(drm);
179 
180 	return priv;
181 }
182 
183 /*
184  * Test that drm_bridge_get_current_state() returns the last committed
185  * state for an atomic bridge.
186  */
187 static void drm_test_drm_bridge_get_current_state_atomic(struct kunit *test)
188 {
189 	struct drm_modeset_acquire_ctx ctx;
190 	struct drm_bridge_init_priv *priv;
191 	struct drm_bridge_state *curr_bridge_state;
192 	struct drm_bridge_state *bridge_state;
193 	struct drm_atomic_state *state;
194 	struct drm_bridge *bridge;
195 	struct drm_device *drm;
196 	int ret;
197 
198 	priv = drm_test_bridge_init(test, &drm_test_bridge_atomic_funcs);
199 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
200 
201 	drm_modeset_acquire_init(&ctx, 0);
202 
203 	drm = &priv->drm;
204 	state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
205 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
206 
207 retry_commit:
208 	bridge = &priv->test_bridge->bridge;
209 	bridge_state = drm_atomic_get_bridge_state(state, bridge);
210 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, bridge_state);
211 
212 	ret = drm_atomic_commit(state);
213 	if (ret == -EDEADLK) {
214 		drm_atomic_state_clear(state);
215 		drm_modeset_backoff(&ctx);
216 		goto retry_commit;
217 	}
218 	KUNIT_ASSERT_EQ(test, ret, 0);
219 
220 	drm_modeset_drop_locks(&ctx);
221 	drm_modeset_acquire_fini(&ctx);
222 
223 	drm_modeset_acquire_init(&ctx, 0);
224 
225 retry_state:
226 	ret = drm_modeset_lock(&bridge->base.lock, &ctx);
227 	if (ret == -EDEADLK) {
228 		drm_modeset_backoff(&ctx);
229 		goto retry_state;
230 	}
231 
232 	curr_bridge_state = drm_bridge_get_current_state(bridge);
233 	KUNIT_EXPECT_PTR_EQ(test, curr_bridge_state, bridge_state);
234 
235 	drm_modeset_unlock(&bridge->base.lock);
236 
237 	drm_modeset_drop_locks(&ctx);
238 	drm_modeset_acquire_fini(&ctx);
239 }
240 
241 /*
242  * Test that drm_bridge_get_current_state() returns NULL for a
243  * non-atomic bridge.
244  */
245 static void drm_test_drm_bridge_get_current_state_legacy(struct kunit *test)
246 {
247 	struct drm_bridge_init_priv *priv;
248 	struct drm_bridge *bridge;
249 
250 	priv = drm_test_bridge_init(test, &drm_test_bridge_legacy_funcs);
251 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
252 
253 	/*
254 	 * NOTE: Strictly speaking, we should take the bridge->base.lock
255 	 * before calling that function. However, bridge->base is only
256 	 * initialized if the bridge is atomic, while we explicitly
257 	 * initialize one that isn't there.
258 	 *
259 	 * In order to avoid unnecessary warnings, let's skip the
260 	 * locking. The function would return NULL in all cases anyway,
261 	 * so we don't really have any concurrency to worry about.
262 	 */
263 	bridge = &priv->test_bridge->bridge;
264 	KUNIT_EXPECT_NULL(test, drm_bridge_get_current_state(bridge));
265 }
266 
267 static struct kunit_case drm_bridge_get_current_state_tests[] = {
268 	KUNIT_CASE(drm_test_drm_bridge_get_current_state_atomic),
269 	KUNIT_CASE(drm_test_drm_bridge_get_current_state_legacy),
270 	{ }
271 };
272 
273 
274 static struct kunit_suite drm_bridge_get_current_state_test_suite = {
275 	.name = "drm_test_bridge_get_current_state",
276 	.test_cases = drm_bridge_get_current_state_tests,
277 };
278 
279 /*
280  * Test that an atomic bridge is properly power-cycled when calling
281  * drm_bridge_helper_reset_crtc().
282  */
283 static void drm_test_drm_bridge_helper_reset_crtc_atomic(struct kunit *test)
284 {
285 	struct drm_modeset_acquire_ctx ctx;
286 	struct drm_bridge_init_priv *priv;
287 	struct drm_display_mode *mode;
288 	struct drm_bridge_priv *bridge_priv;
289 	int ret;
290 
291 	priv = drm_test_bridge_init(test, &drm_test_bridge_atomic_funcs);
292 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
293 
294 	mode = drm_kunit_display_mode_from_cea_vic(test, &priv->drm, 16);
295 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mode);
296 
297 	drm_modeset_acquire_init(&ctx, 0);
298 
299 retry_commit:
300 	ret = drm_kunit_helper_enable_crtc_connector(test,
301 						     &priv->drm, priv->crtc,
302 						     priv->connector,
303 						     mode,
304 						     &ctx);
305 	if (ret == -EDEADLK) {
306 		drm_modeset_backoff(&ctx);
307 		goto retry_commit;
308 	}
309 	KUNIT_ASSERT_EQ(test, ret, 0);
310 
311 	drm_modeset_drop_locks(&ctx);
312 	drm_modeset_acquire_fini(&ctx);
313 
314 	bridge_priv = priv->test_bridge;
315 	KUNIT_ASSERT_EQ(test, bridge_priv->enable_count, 1);
316 	KUNIT_ASSERT_EQ(test, bridge_priv->disable_count, 0);
317 
318 	drm_modeset_acquire_init(&ctx, 0);
319 
320 retry_reset:
321 	ret = drm_bridge_helper_reset_crtc(&bridge_priv->bridge, &ctx);
322 	if (ret == -EDEADLK) {
323 		drm_modeset_backoff(&ctx);
324 		goto retry_reset;
325 	}
326 	KUNIT_ASSERT_EQ(test, ret, 0);
327 
328 	drm_modeset_drop_locks(&ctx);
329 	drm_modeset_acquire_fini(&ctx);
330 
331 	KUNIT_EXPECT_EQ(test, bridge_priv->enable_count, 2);
332 	KUNIT_EXPECT_EQ(test, bridge_priv->disable_count, 1);
333 }
334 
335 /*
336  * Test that calling drm_bridge_helper_reset_crtc() on a disabled atomic
337  * bridge will fail and not call the enable / disable callbacks
338  */
339 static void drm_test_drm_bridge_helper_reset_crtc_atomic_disabled(struct kunit *test)
340 {
341 	struct drm_modeset_acquire_ctx ctx;
342 	struct drm_bridge_init_priv *priv;
343 	struct drm_display_mode *mode;
344 	struct drm_bridge_priv *bridge_priv;
345 	int ret;
346 
347 	priv = drm_test_bridge_init(test, &drm_test_bridge_atomic_funcs);
348 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
349 
350 	mode = drm_kunit_display_mode_from_cea_vic(test, &priv->drm, 16);
351 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mode);
352 
353 	bridge_priv = priv->test_bridge;
354 	KUNIT_ASSERT_EQ(test, bridge_priv->enable_count, 0);
355 	KUNIT_ASSERT_EQ(test, bridge_priv->disable_count, 0);
356 
357 	drm_modeset_acquire_init(&ctx, 0);
358 
359 retry_reset:
360 	ret = drm_bridge_helper_reset_crtc(&bridge_priv->bridge, &ctx);
361 	if (ret == -EDEADLK) {
362 		drm_modeset_backoff(&ctx);
363 		goto retry_reset;
364 	}
365 	KUNIT_EXPECT_LT(test, ret, 0);
366 
367 	drm_modeset_drop_locks(&ctx);
368 	drm_modeset_acquire_fini(&ctx);
369 
370 	KUNIT_EXPECT_EQ(test, bridge_priv->enable_count, 0);
371 	KUNIT_EXPECT_EQ(test, bridge_priv->disable_count, 0);
372 }
373 
374 /*
375  * Test that a non-atomic bridge is properly power-cycled when calling
376  * drm_bridge_helper_reset_crtc().
377  */
378 static void drm_test_drm_bridge_helper_reset_crtc_legacy(struct kunit *test)
379 {
380 	struct drm_modeset_acquire_ctx ctx;
381 	struct drm_bridge_init_priv *priv;
382 	struct drm_display_mode *mode;
383 	struct drm_bridge_priv *bridge_priv;
384 	int ret;
385 
386 	priv = drm_test_bridge_init(test, &drm_test_bridge_legacy_funcs);
387 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
388 
389 	mode = drm_kunit_display_mode_from_cea_vic(test, &priv->drm, 16);
390 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mode);
391 
392 	drm_modeset_acquire_init(&ctx, 0);
393 
394 retry_commit:
395 	ret = drm_kunit_helper_enable_crtc_connector(test,
396 						     &priv->drm, priv->crtc,
397 						     priv->connector,
398 						     mode,
399 						     &ctx);
400 	if (ret == -EDEADLK) {
401 		drm_modeset_backoff(&ctx);
402 		goto retry_commit;
403 	}
404 	KUNIT_ASSERT_EQ(test, ret, 0);
405 
406 	drm_modeset_drop_locks(&ctx);
407 	drm_modeset_acquire_fini(&ctx);
408 
409 	bridge_priv = priv->test_bridge;
410 	KUNIT_ASSERT_EQ(test, bridge_priv->enable_count, 1);
411 	KUNIT_ASSERT_EQ(test, bridge_priv->disable_count, 0);
412 
413 	drm_modeset_acquire_init(&ctx, 0);
414 
415 retry_reset:
416 	ret = drm_bridge_helper_reset_crtc(&bridge_priv->bridge, &ctx);
417 	if (ret == -EDEADLK) {
418 		drm_modeset_backoff(&ctx);
419 		goto retry_reset;
420 	}
421 	KUNIT_ASSERT_EQ(test, ret, 0);
422 
423 	drm_modeset_drop_locks(&ctx);
424 	drm_modeset_acquire_fini(&ctx);
425 
426 	KUNIT_EXPECT_EQ(test, bridge_priv->enable_count, 2);
427 	KUNIT_EXPECT_EQ(test, bridge_priv->disable_count, 1);
428 }
429 
430 static struct kunit_case drm_bridge_helper_reset_crtc_tests[] = {
431 	KUNIT_CASE(drm_test_drm_bridge_helper_reset_crtc_atomic),
432 	KUNIT_CASE(drm_test_drm_bridge_helper_reset_crtc_atomic_disabled),
433 	KUNIT_CASE(drm_test_drm_bridge_helper_reset_crtc_legacy),
434 	{ }
435 };
436 
437 static struct kunit_suite drm_bridge_helper_reset_crtc_test_suite = {
438 	.name = "drm_test_bridge_helper_reset_crtc",
439 	.test_cases = drm_bridge_helper_reset_crtc_tests,
440 };
441 
442 static int drm_test_bridge_alloc_init(struct kunit *test)
443 {
444 	struct drm_bridge_init_priv *priv;
445 
446 	priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
447 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
448 
449 	priv->dev = kunit_device_register(test, "drm-bridge-dev");
450 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->dev);
451 
452 	test->priv = priv;
453 
454 	priv->test_bridge = devm_drm_bridge_alloc(priv->dev, struct drm_bridge_priv, bridge,
455 						  &drm_test_bridge_atomic_funcs);
456 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->test_bridge);
457 
458 	priv->test_bridge->data = priv;
459 
460 	KUNIT_ASSERT_FALSE(test, priv->destroyed);
461 
462 	return 0;
463 }
464 
465 /*
466  * Test that a bridge is freed when the device is destroyed in lack of
467  * other drm_bridge_get/put() operations.
468  */
469 static void drm_test_drm_bridge_alloc_basic(struct kunit *test)
470 {
471 	struct drm_bridge_init_priv *priv = test->priv;
472 
473 	KUNIT_ASSERT_FALSE(test, priv->destroyed);
474 
475 	kunit_device_unregister(test, priv->dev);
476 	KUNIT_EXPECT_TRUE(test, priv->destroyed);
477 }
478 
479 /*
480  * Test that a bridge is not freed when the device is destroyed when there
481  * is still a reference to it, and freed when that reference is put.
482  */
483 static void drm_test_drm_bridge_alloc_get_put(struct kunit *test)
484 {
485 	struct drm_bridge_init_priv *priv = test->priv;
486 
487 	KUNIT_ASSERT_FALSE(test, priv->destroyed);
488 
489 	drm_bridge_get(&priv->test_bridge->bridge);
490 	KUNIT_EXPECT_FALSE(test, priv->destroyed);
491 
492 	kunit_device_unregister(test, priv->dev);
493 	KUNIT_EXPECT_FALSE(test, priv->destroyed);
494 
495 	drm_bridge_put(&priv->test_bridge->bridge);
496 	KUNIT_EXPECT_TRUE(test, priv->destroyed);
497 }
498 
499 static struct kunit_case drm_bridge_alloc_tests[] = {
500 	KUNIT_CASE(drm_test_drm_bridge_alloc_basic),
501 	KUNIT_CASE(drm_test_drm_bridge_alloc_get_put),
502 	{ }
503 };
504 
505 static struct kunit_suite drm_bridge_alloc_test_suite = {
506 	.name = "drm_bridge_alloc",
507 	.init = drm_test_bridge_alloc_init,
508 	.test_cases = drm_bridge_alloc_tests,
509 };
510 
511 kunit_test_suites(
512 	&drm_bridge_get_current_state_test_suite,
513 	&drm_bridge_helper_reset_crtc_test_suite,
514 	&drm_bridge_alloc_test_suite,
515 );
516 
517 MODULE_AUTHOR("Maxime Ripard <mripard@kernel.org>");
518 MODULE_AUTHOR("Luca Ceresoli <luca.ceresoli@bootlin.com>");
519 
520 MODULE_DESCRIPTION("Kunit test for drm_bridge functions");
521 MODULE_LICENSE("GPL");
522