xref: /linux/drivers/gpu/drm/tests/drm_bridge_test.c (revision c06b6cde2a1c3bcbb561bd57bb6f34eae9030921)
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_commit *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_commit *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_mode_config_reset(drm);
177 
178 	return priv;
179 }
180 
181 /*
182  * Test that drm_bridge_get_current_state() returns the last committed
183  * state for an atomic bridge.
184  */
185 static void drm_test_drm_bridge_get_current_state_atomic(struct kunit *test)
186 {
187 	struct drm_modeset_acquire_ctx ctx;
188 	struct drm_bridge_init_priv *priv;
189 	struct drm_bridge_state *curr_bridge_state;
190 	struct drm_bridge_state *bridge_state;
191 	struct drm_atomic_commit *state;
192 	struct drm_bridge *bridge;
193 	struct drm_device *drm;
194 	int ret;
195 
196 	priv = drm_test_bridge_init(test, &drm_test_bridge_atomic_funcs);
197 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
198 
199 	drm_modeset_acquire_init(&ctx, 0);
200 
201 	drm = &priv->drm;
202 	state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
203 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
204 
205 retry_commit:
206 	bridge = &priv->test_bridge->bridge;
207 	bridge_state = drm_atomic_get_bridge_state(state, bridge);
208 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, bridge_state);
209 
210 	ret = drm_atomic_commit(state);
211 	if (ret == -EDEADLK) {
212 		drm_atomic_commit_clear(state);
213 		drm_modeset_backoff(&ctx);
214 		goto retry_commit;
215 	}
216 	KUNIT_ASSERT_EQ(test, ret, 0);
217 
218 	drm_modeset_drop_locks(&ctx);
219 	drm_modeset_acquire_fini(&ctx);
220 
221 	drm_modeset_acquire_init(&ctx, 0);
222 
223 retry_state:
224 	ret = drm_modeset_lock(&bridge->base.lock, &ctx);
225 	if (ret == -EDEADLK) {
226 		drm_modeset_backoff(&ctx);
227 		goto retry_state;
228 	}
229 
230 	curr_bridge_state = drm_bridge_get_current_state(bridge);
231 	KUNIT_EXPECT_PTR_EQ(test, curr_bridge_state, bridge_state);
232 
233 	drm_modeset_unlock(&bridge->base.lock);
234 
235 	drm_modeset_drop_locks(&ctx);
236 	drm_modeset_acquire_fini(&ctx);
237 }
238 
239 /*
240  * Test that drm_bridge_get_current_state() returns NULL for a
241  * non-atomic bridge.
242  */
243 static void drm_test_drm_bridge_get_current_state_legacy(struct kunit *test)
244 {
245 	struct drm_bridge_init_priv *priv;
246 	struct drm_bridge *bridge;
247 
248 	priv = drm_test_bridge_init(test, &drm_test_bridge_legacy_funcs);
249 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
250 
251 	/*
252 	 * NOTE: Strictly speaking, we should take the bridge->base.lock
253 	 * before calling that function. However, bridge->base is only
254 	 * initialized if the bridge is atomic, while we explicitly
255 	 * initialize one that isn't there.
256 	 *
257 	 * In order to avoid unnecessary warnings, let's skip the
258 	 * locking. The function would return NULL in all cases anyway,
259 	 * so we don't really have any concurrency to worry about.
260 	 */
261 	bridge = &priv->test_bridge->bridge;
262 	KUNIT_EXPECT_NULL(test, drm_bridge_get_current_state(bridge));
263 }
264 
265 static struct kunit_case drm_bridge_get_current_state_tests[] = {
266 	KUNIT_CASE(drm_test_drm_bridge_get_current_state_atomic),
267 	KUNIT_CASE(drm_test_drm_bridge_get_current_state_legacy),
268 	{ }
269 };
270 
271 
272 static struct kunit_suite drm_bridge_get_current_state_test_suite = {
273 	.name = "drm_test_bridge_get_current_state",
274 	.test_cases = drm_bridge_get_current_state_tests,
275 };
276 
277 /*
278  * Test that an atomic bridge is properly power-cycled when calling
279  * drm_bridge_helper_reset_crtc().
280  */
281 static void drm_test_drm_bridge_helper_reset_crtc_atomic(struct kunit *test)
282 {
283 	struct drm_modeset_acquire_ctx ctx;
284 	struct drm_bridge_init_priv *priv;
285 	struct drm_display_mode *mode;
286 	struct drm_bridge_priv *bridge_priv;
287 	int ret;
288 
289 	priv = drm_test_bridge_init(test, &drm_test_bridge_atomic_funcs);
290 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
291 
292 	mode = drm_kunit_display_mode_from_cea_vic(test, &priv->drm, 16);
293 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mode);
294 
295 	drm_modeset_acquire_init(&ctx, 0);
296 
297 retry_commit:
298 	ret = drm_kunit_helper_enable_crtc_connector(test,
299 						     &priv->drm, priv->crtc,
300 						     priv->connector,
301 						     mode,
302 						     &ctx);
303 	if (ret == -EDEADLK) {
304 		drm_modeset_backoff(&ctx);
305 		goto retry_commit;
306 	}
307 	KUNIT_ASSERT_EQ(test, ret, 0);
308 
309 	drm_modeset_drop_locks(&ctx);
310 	drm_modeset_acquire_fini(&ctx);
311 
312 	bridge_priv = priv->test_bridge;
313 	KUNIT_ASSERT_EQ(test, bridge_priv->enable_count, 1);
314 	KUNIT_ASSERT_EQ(test, bridge_priv->disable_count, 0);
315 
316 	drm_modeset_acquire_init(&ctx, 0);
317 
318 retry_reset:
319 	ret = drm_bridge_helper_reset_crtc(&bridge_priv->bridge, &ctx);
320 	if (ret == -EDEADLK) {
321 		drm_modeset_backoff(&ctx);
322 		goto retry_reset;
323 	}
324 	KUNIT_ASSERT_EQ(test, ret, 0);
325 
326 	drm_modeset_drop_locks(&ctx);
327 	drm_modeset_acquire_fini(&ctx);
328 
329 	KUNIT_EXPECT_EQ(test, bridge_priv->enable_count, 2);
330 	KUNIT_EXPECT_EQ(test, bridge_priv->disable_count, 1);
331 }
332 
333 /*
334  * Test that calling drm_bridge_helper_reset_crtc() on a disabled atomic
335  * bridge will fail and not call the enable / disable callbacks
336  */
337 static void drm_test_drm_bridge_helper_reset_crtc_atomic_disabled(struct kunit *test)
338 {
339 	struct drm_modeset_acquire_ctx ctx;
340 	struct drm_bridge_init_priv *priv;
341 	struct drm_display_mode *mode;
342 	struct drm_bridge_priv *bridge_priv;
343 	int ret;
344 
345 	priv = drm_test_bridge_init(test, &drm_test_bridge_atomic_funcs);
346 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
347 
348 	mode = drm_kunit_display_mode_from_cea_vic(test, &priv->drm, 16);
349 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mode);
350 
351 	bridge_priv = priv->test_bridge;
352 	KUNIT_ASSERT_EQ(test, bridge_priv->enable_count, 0);
353 	KUNIT_ASSERT_EQ(test, bridge_priv->disable_count, 0);
354 
355 	drm_modeset_acquire_init(&ctx, 0);
356 
357 retry_reset:
358 	ret = drm_bridge_helper_reset_crtc(&bridge_priv->bridge, &ctx);
359 	if (ret == -EDEADLK) {
360 		drm_modeset_backoff(&ctx);
361 		goto retry_reset;
362 	}
363 	KUNIT_EXPECT_LT(test, ret, 0);
364 
365 	drm_modeset_drop_locks(&ctx);
366 	drm_modeset_acquire_fini(&ctx);
367 
368 	KUNIT_EXPECT_EQ(test, bridge_priv->enable_count, 0);
369 	KUNIT_EXPECT_EQ(test, bridge_priv->disable_count, 0);
370 }
371 
372 /*
373  * Test that a non-atomic bridge is properly power-cycled when calling
374  * drm_bridge_helper_reset_crtc().
375  */
376 static void drm_test_drm_bridge_helper_reset_crtc_legacy(struct kunit *test)
377 {
378 	struct drm_modeset_acquire_ctx ctx;
379 	struct drm_bridge_init_priv *priv;
380 	struct drm_display_mode *mode;
381 	struct drm_bridge_priv *bridge_priv;
382 	int ret;
383 
384 	priv = drm_test_bridge_init(test, &drm_test_bridge_legacy_funcs);
385 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
386 
387 	mode = drm_kunit_display_mode_from_cea_vic(test, &priv->drm, 16);
388 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mode);
389 
390 	drm_modeset_acquire_init(&ctx, 0);
391 
392 retry_commit:
393 	ret = drm_kunit_helper_enable_crtc_connector(test,
394 						     &priv->drm, priv->crtc,
395 						     priv->connector,
396 						     mode,
397 						     &ctx);
398 	if (ret == -EDEADLK) {
399 		drm_modeset_backoff(&ctx);
400 		goto retry_commit;
401 	}
402 	KUNIT_ASSERT_EQ(test, ret, 0);
403 
404 	drm_modeset_drop_locks(&ctx);
405 	drm_modeset_acquire_fini(&ctx);
406 
407 	bridge_priv = priv->test_bridge;
408 	KUNIT_ASSERT_EQ(test, bridge_priv->enable_count, 1);
409 	KUNIT_ASSERT_EQ(test, bridge_priv->disable_count, 0);
410 
411 	drm_modeset_acquire_init(&ctx, 0);
412 
413 retry_reset:
414 	ret = drm_bridge_helper_reset_crtc(&bridge_priv->bridge, &ctx);
415 	if (ret == -EDEADLK) {
416 		drm_modeset_backoff(&ctx);
417 		goto retry_reset;
418 	}
419 	KUNIT_ASSERT_EQ(test, ret, 0);
420 
421 	drm_modeset_drop_locks(&ctx);
422 	drm_modeset_acquire_fini(&ctx);
423 
424 	KUNIT_EXPECT_EQ(test, bridge_priv->enable_count, 2);
425 	KUNIT_EXPECT_EQ(test, bridge_priv->disable_count, 1);
426 }
427 
428 static struct kunit_case drm_bridge_helper_reset_crtc_tests[] = {
429 	KUNIT_CASE(drm_test_drm_bridge_helper_reset_crtc_atomic),
430 	KUNIT_CASE(drm_test_drm_bridge_helper_reset_crtc_atomic_disabled),
431 	KUNIT_CASE(drm_test_drm_bridge_helper_reset_crtc_legacy),
432 	{ }
433 };
434 
435 static struct kunit_suite drm_bridge_helper_reset_crtc_test_suite = {
436 	.name = "drm_test_bridge_helper_reset_crtc",
437 	.test_cases = drm_bridge_helper_reset_crtc_tests,
438 };
439 
440 static int drm_test_bridge_alloc_init(struct kunit *test)
441 {
442 	struct drm_bridge_init_priv *priv;
443 
444 	priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
445 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
446 
447 	priv->dev = kunit_device_register(test, "drm-bridge-dev");
448 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->dev);
449 
450 	test->priv = priv;
451 
452 	priv->test_bridge = devm_drm_bridge_alloc(priv->dev, struct drm_bridge_priv, bridge,
453 						  &drm_test_bridge_atomic_funcs);
454 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->test_bridge);
455 
456 	priv->test_bridge->data = priv;
457 
458 	KUNIT_ASSERT_FALSE(test, priv->destroyed);
459 
460 	return 0;
461 }
462 
463 /*
464  * Test that a bridge is freed when the device is destroyed in lack of
465  * other drm_bridge_get/put() operations.
466  */
467 static void drm_test_drm_bridge_alloc_basic(struct kunit *test)
468 {
469 	struct drm_bridge_init_priv *priv = test->priv;
470 
471 	KUNIT_ASSERT_FALSE(test, priv->destroyed);
472 
473 	kunit_device_unregister(test, priv->dev);
474 	KUNIT_EXPECT_TRUE(test, priv->destroyed);
475 }
476 
477 /*
478  * Test that a bridge is not freed when the device is destroyed when there
479  * is still a reference to it, and freed when that reference is put.
480  */
481 static void drm_test_drm_bridge_alloc_get_put(struct kunit *test)
482 {
483 	struct drm_bridge_init_priv *priv = test->priv;
484 
485 	KUNIT_ASSERT_FALSE(test, priv->destroyed);
486 
487 	drm_bridge_get(&priv->test_bridge->bridge);
488 	KUNIT_EXPECT_FALSE(test, priv->destroyed);
489 
490 	kunit_device_unregister(test, priv->dev);
491 	KUNIT_EXPECT_FALSE(test, priv->destroyed);
492 
493 	drm_bridge_put(&priv->test_bridge->bridge);
494 	KUNIT_EXPECT_TRUE(test, priv->destroyed);
495 }
496 
497 static struct kunit_case drm_bridge_alloc_tests[] = {
498 	KUNIT_CASE(drm_test_drm_bridge_alloc_basic),
499 	KUNIT_CASE(drm_test_drm_bridge_alloc_get_put),
500 	{ }
501 };
502 
503 static struct kunit_suite drm_bridge_alloc_test_suite = {
504 	.name = "drm_bridge_alloc",
505 	.init = drm_test_bridge_alloc_init,
506 	.test_cases = drm_bridge_alloc_tests,
507 };
508 
509 kunit_test_suites(
510 	&drm_bridge_get_current_state_test_suite,
511 	&drm_bridge_helper_reset_crtc_test_suite,
512 	&drm_bridge_alloc_test_suite,
513 );
514 
515 MODULE_AUTHOR("Maxime Ripard <mripard@kernel.org>");
516 MODULE_AUTHOR("Luca Ceresoli <luca.ceresoli@bootlin.com>");
517 
518 MODULE_DESCRIPTION("Kunit test for drm_bridge functions");
519 MODULE_LICENSE("GPL");
520