xref: /linux/drivers/gpu/drm/tests/drm_bridge_test.c (revision b08494a8f7416e5f09907318c5460ad6f6e2a548)
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/test.h>
12 
13 struct drm_bridge_init_priv {
14 	struct drm_device drm;
15 	struct drm_plane *plane;
16 	struct drm_crtc *crtc;
17 	struct drm_encoder encoder;
18 	struct drm_bridge bridge;
19 	struct drm_connector *connector;
20 	unsigned int enable_count;
21 	unsigned int disable_count;
22 };
23 
24 static void drm_test_bridge_enable(struct drm_bridge *bridge)
25 {
26 	struct drm_bridge_init_priv *priv =
27 		container_of(bridge, struct drm_bridge_init_priv, bridge);
28 
29 	priv->enable_count++;
30 }
31 
32 static void drm_test_bridge_disable(struct drm_bridge *bridge)
33 {
34 	struct drm_bridge_init_priv *priv =
35 		container_of(bridge, struct drm_bridge_init_priv, bridge);
36 
37 	priv->disable_count++;
38 }
39 
40 static const struct drm_bridge_funcs drm_test_bridge_legacy_funcs = {
41 	.enable			= drm_test_bridge_enable,
42 	.disable		= drm_test_bridge_disable,
43 };
44 
45 static void drm_test_bridge_atomic_enable(struct drm_bridge *bridge,
46 					  struct drm_atomic_state *state)
47 {
48 	struct drm_bridge_init_priv *priv =
49 		container_of(bridge, struct drm_bridge_init_priv, bridge);
50 
51 	priv->enable_count++;
52 }
53 
54 static void drm_test_bridge_atomic_disable(struct drm_bridge *bridge,
55 					   struct drm_atomic_state *state)
56 {
57 	struct drm_bridge_init_priv *priv =
58 		container_of(bridge, struct drm_bridge_init_priv, bridge);
59 
60 	priv->disable_count++;
61 }
62 
63 static const struct drm_bridge_funcs drm_test_bridge_atomic_funcs = {
64 	.atomic_enable		= drm_test_bridge_atomic_enable,
65 	.atomic_disable		= drm_test_bridge_atomic_disable,
66 	.atomic_destroy_state	= drm_atomic_helper_bridge_destroy_state,
67 	.atomic_duplicate_state	= drm_atomic_helper_bridge_duplicate_state,
68 	.atomic_reset		= drm_atomic_helper_bridge_reset,
69 };
70 
71 KUNIT_DEFINE_ACTION_WRAPPER(drm_bridge_remove_wrapper,
72 			    drm_bridge_remove,
73 			    struct drm_bridge *);
74 
75 static int drm_kunit_bridge_add(struct kunit *test,
76 				struct drm_bridge *bridge)
77 {
78 	drm_bridge_add(bridge);
79 
80 	return kunit_add_action_or_reset(test,
81 					 drm_bridge_remove_wrapper,
82 					 bridge);
83 }
84 
85 static struct drm_bridge_init_priv *
86 drm_test_bridge_init(struct kunit *test, const struct drm_bridge_funcs *funcs)
87 {
88 	struct drm_bridge_init_priv *priv;
89 	struct drm_encoder *enc;
90 	struct drm_bridge *bridge;
91 	struct drm_device *drm;
92 	struct device *dev;
93 	int ret;
94 
95 	dev = drm_kunit_helper_alloc_device(test);
96 	if (IS_ERR(dev))
97 		return ERR_CAST(dev);
98 
99 	priv = drm_kunit_helper_alloc_drm_device(test, dev,
100 						 struct drm_bridge_init_priv, drm,
101 						 DRIVER_MODESET | DRIVER_ATOMIC);
102 	if (IS_ERR(priv))
103 		return ERR_CAST(priv);
104 
105 	drm = &priv->drm;
106 	priv->plane = drm_kunit_helper_create_primary_plane(test, drm,
107 							    NULL,
108 							    NULL,
109 							    NULL, 0,
110 							    NULL);
111 	if (IS_ERR(priv->plane))
112 		return ERR_CAST(priv->plane);
113 
114 	priv->crtc = drm_kunit_helper_create_crtc(test, drm,
115 						  priv->plane, NULL,
116 						  NULL,
117 						  NULL);
118 	if (IS_ERR(priv->crtc))
119 		return ERR_CAST(priv->crtc);
120 
121 	enc = &priv->encoder;
122 	ret = drmm_encoder_init(drm, enc, NULL, DRM_MODE_ENCODER_TMDS, NULL);
123 	if (ret)
124 		return ERR_PTR(ret);
125 
126 	enc->possible_crtcs = drm_crtc_mask(priv->crtc);
127 
128 	bridge = &priv->bridge;
129 	bridge->type = DRM_MODE_CONNECTOR_VIRTUAL;
130 	bridge->funcs = funcs;
131 
132 	ret = drm_kunit_bridge_add(test, bridge);
133 	if (ret)
134 		return ERR_PTR(ret);
135 
136 	ret = drm_bridge_attach(enc, bridge, NULL, 0);
137 	if (ret)
138 		return ERR_PTR(ret);
139 
140 	priv->connector = drm_bridge_connector_init(drm, enc);
141 	if (IS_ERR(priv->connector))
142 		return ERR_CAST(priv->connector);
143 
144 	drm_connector_attach_encoder(priv->connector, enc);
145 
146 	drm_mode_config_reset(drm);
147 
148 	return priv;
149 }
150 
151 /*
152  * Test that drm_bridge_get_current_state() returns the last committed
153  * state for an atomic bridge.
154  */
155 static void drm_test_drm_bridge_get_current_state_atomic(struct kunit *test)
156 {
157 	struct drm_modeset_acquire_ctx ctx;
158 	struct drm_bridge_init_priv *priv;
159 	struct drm_bridge_state *curr_bridge_state;
160 	struct drm_bridge_state *bridge_state;
161 	struct drm_atomic_state *state;
162 	struct drm_bridge *bridge;
163 	struct drm_device *drm;
164 	int ret;
165 
166 	priv = drm_test_bridge_init(test, &drm_test_bridge_atomic_funcs);
167 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
168 
169 	drm_modeset_acquire_init(&ctx, 0);
170 
171 	drm = &priv->drm;
172 	state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
173 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
174 
175 retry_commit:
176 	bridge = &priv->bridge;
177 	bridge_state = drm_atomic_get_bridge_state(state, bridge);
178 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, bridge_state);
179 
180 	ret = drm_atomic_commit(state);
181 	if (ret == -EDEADLK) {
182 		drm_atomic_state_clear(state);
183 		drm_modeset_backoff(&ctx);
184 		goto retry_commit;
185 	}
186 	KUNIT_ASSERT_EQ(test, ret, 0);
187 
188 	drm_modeset_drop_locks(&ctx);
189 	drm_modeset_acquire_fini(&ctx);
190 
191 	drm_modeset_acquire_init(&ctx, 0);
192 
193 retry_state:
194 	ret = drm_modeset_lock(&bridge->base.lock, &ctx);
195 	if (ret == -EDEADLK) {
196 		drm_modeset_backoff(&ctx);
197 		goto retry_state;
198 	}
199 
200 	curr_bridge_state = drm_bridge_get_current_state(bridge);
201 	KUNIT_EXPECT_PTR_EQ(test, curr_bridge_state, bridge_state);
202 
203 	drm_modeset_unlock(&bridge->base.lock);
204 
205 	drm_modeset_drop_locks(&ctx);
206 	drm_modeset_acquire_fini(&ctx);
207 }
208 
209 /*
210  * Test that drm_bridge_get_current_state() returns NULL for a
211  * non-atomic bridge.
212  */
213 static void drm_test_drm_bridge_get_current_state_legacy(struct kunit *test)
214 {
215 	struct drm_bridge_init_priv *priv;
216 	struct drm_bridge *bridge;
217 
218 	priv = drm_test_bridge_init(test, &drm_test_bridge_legacy_funcs);
219 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
220 
221 	/*
222 	 * NOTE: Strictly speaking, we should take the bridge->base.lock
223 	 * before calling that function. However, bridge->base is only
224 	 * initialized if the bridge is atomic, while we explicitly
225 	 * initialize one that isn't there.
226 	 *
227 	 * In order to avoid unnecessary warnings, let's skip the
228 	 * locking. The function would return NULL in all cases anyway,
229 	 * so we don't really have any concurrency to worry about.
230 	 */
231 	bridge = &priv->bridge;
232 	KUNIT_EXPECT_NULL(test, drm_bridge_get_current_state(bridge));
233 }
234 
235 static struct kunit_case drm_bridge_get_current_state_tests[] = {
236 	KUNIT_CASE(drm_test_drm_bridge_get_current_state_atomic),
237 	KUNIT_CASE(drm_test_drm_bridge_get_current_state_legacy),
238 	{ }
239 };
240 
241 
242 static struct kunit_suite drm_bridge_get_current_state_test_suite = {
243 	.name = "drm_test_bridge_get_current_state",
244 	.test_cases = drm_bridge_get_current_state_tests,
245 };
246 
247 /*
248  * Test that an atomic bridge is properly power-cycled when calling
249  * drm_bridge_helper_reset_crtc().
250  */
251 static void drm_test_drm_bridge_helper_reset_crtc_atomic(struct kunit *test)
252 {
253 	struct drm_modeset_acquire_ctx ctx;
254 	struct drm_bridge_init_priv *priv;
255 	struct drm_display_mode *mode;
256 	struct drm_bridge *bridge;
257 	int ret;
258 
259 	priv = drm_test_bridge_init(test, &drm_test_bridge_atomic_funcs);
260 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
261 
262 	mode = drm_kunit_display_mode_from_cea_vic(test, &priv->drm, 16);
263 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mode);
264 
265 	drm_modeset_acquire_init(&ctx, 0);
266 
267 retry_commit:
268 	ret = drm_kunit_helper_enable_crtc_connector(test,
269 						     &priv->drm, priv->crtc,
270 						     priv->connector,
271 						     mode,
272 						     &ctx);
273 	if (ret == -EDEADLK) {
274 		drm_modeset_backoff(&ctx);
275 		goto retry_commit;
276 	}
277 	KUNIT_ASSERT_EQ(test, ret, 0);
278 
279 	drm_modeset_drop_locks(&ctx);
280 	drm_modeset_acquire_fini(&ctx);
281 
282 	bridge = &priv->bridge;
283 	KUNIT_ASSERT_EQ(test, priv->enable_count, 1);
284 	KUNIT_ASSERT_EQ(test, priv->disable_count, 0);
285 
286 	drm_modeset_acquire_init(&ctx, 0);
287 
288 retry_reset:
289 	ret = drm_bridge_helper_reset_crtc(bridge, &ctx);
290 	if (ret == -EDEADLK) {
291 		drm_modeset_backoff(&ctx);
292 		goto retry_reset;
293 	}
294 	KUNIT_ASSERT_EQ(test, ret, 0);
295 
296 	drm_modeset_drop_locks(&ctx);
297 	drm_modeset_acquire_fini(&ctx);
298 
299 	KUNIT_EXPECT_EQ(test, priv->enable_count, 2);
300 	KUNIT_EXPECT_EQ(test, priv->disable_count, 1);
301 }
302 
303 /*
304  * Test that calling drm_bridge_helper_reset_crtc() on a disabled atomic
305  * bridge will fail and not call the enable / disable callbacks
306  */
307 static void drm_test_drm_bridge_helper_reset_crtc_atomic_disabled(struct kunit *test)
308 {
309 	struct drm_modeset_acquire_ctx ctx;
310 	struct drm_bridge_init_priv *priv;
311 	struct drm_display_mode *mode;
312 	struct drm_bridge *bridge;
313 	int ret;
314 
315 	priv = drm_test_bridge_init(test, &drm_test_bridge_atomic_funcs);
316 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
317 
318 	mode = drm_kunit_display_mode_from_cea_vic(test, &priv->drm, 16);
319 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mode);
320 
321 	bridge = &priv->bridge;
322 	KUNIT_ASSERT_EQ(test, priv->enable_count, 0);
323 	KUNIT_ASSERT_EQ(test, priv->disable_count, 0);
324 
325 	drm_modeset_acquire_init(&ctx, 0);
326 
327 retry_reset:
328 	ret = drm_bridge_helper_reset_crtc(bridge, &ctx);
329 	if (ret == -EDEADLK) {
330 		drm_modeset_backoff(&ctx);
331 		goto retry_reset;
332 	}
333 	KUNIT_EXPECT_LT(test, ret, 0);
334 
335 	drm_modeset_drop_locks(&ctx);
336 	drm_modeset_acquire_fini(&ctx);
337 
338 	KUNIT_EXPECT_EQ(test, priv->enable_count, 0);
339 	KUNIT_EXPECT_EQ(test, priv->disable_count, 0);
340 }
341 
342 /*
343  * Test that a non-atomic bridge is properly power-cycled when calling
344  * drm_bridge_helper_reset_crtc().
345  */
346 static void drm_test_drm_bridge_helper_reset_crtc_legacy(struct kunit *test)
347 {
348 	struct drm_modeset_acquire_ctx ctx;
349 	struct drm_bridge_init_priv *priv;
350 	struct drm_display_mode *mode;
351 	struct drm_bridge *bridge;
352 	int ret;
353 
354 	priv = drm_test_bridge_init(test, &drm_test_bridge_legacy_funcs);
355 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
356 
357 	mode = drm_kunit_display_mode_from_cea_vic(test, &priv->drm, 16);
358 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mode);
359 
360 	drm_modeset_acquire_init(&ctx, 0);
361 
362 retry_commit:
363 	ret = drm_kunit_helper_enable_crtc_connector(test,
364 						     &priv->drm, priv->crtc,
365 						     priv->connector,
366 						     mode,
367 						     &ctx);
368 	if (ret == -EDEADLK) {
369 		drm_modeset_backoff(&ctx);
370 		goto retry_commit;
371 	}
372 	KUNIT_ASSERT_EQ(test, ret, 0);
373 
374 	drm_modeset_drop_locks(&ctx);
375 	drm_modeset_acquire_fini(&ctx);
376 
377 	bridge = &priv->bridge;
378 	KUNIT_ASSERT_EQ(test, priv->enable_count, 1);
379 	KUNIT_ASSERT_EQ(test, priv->disable_count, 0);
380 
381 	drm_modeset_acquire_init(&ctx, 0);
382 
383 retry_reset:
384 	ret = drm_bridge_helper_reset_crtc(bridge, &ctx);
385 	if (ret == -EDEADLK) {
386 		drm_modeset_backoff(&ctx);
387 		goto retry_reset;
388 	}
389 	KUNIT_ASSERT_EQ(test, ret, 0);
390 
391 	drm_modeset_drop_locks(&ctx);
392 	drm_modeset_acquire_fini(&ctx);
393 
394 	KUNIT_EXPECT_EQ(test, priv->enable_count, 2);
395 	KUNIT_EXPECT_EQ(test, priv->disable_count, 1);
396 }
397 
398 static struct kunit_case drm_bridge_helper_reset_crtc_tests[] = {
399 	KUNIT_CASE(drm_test_drm_bridge_helper_reset_crtc_atomic),
400 	KUNIT_CASE(drm_test_drm_bridge_helper_reset_crtc_atomic_disabled),
401 	KUNIT_CASE(drm_test_drm_bridge_helper_reset_crtc_legacy),
402 	{ }
403 };
404 
405 static struct kunit_suite drm_bridge_helper_reset_crtc_test_suite = {
406 	.name = "drm_test_bridge_helper_reset_crtc",
407 	.test_cases = drm_bridge_helper_reset_crtc_tests,
408 };
409 
410 kunit_test_suites(
411 	&drm_bridge_get_current_state_test_suite,
412 	&drm_bridge_helper_reset_crtc_test_suite,
413 );
414 
415 MODULE_AUTHOR("Maxime Ripard <mripard@kernel.org>");
416 MODULE_DESCRIPTION("Kunit test for drm_bridge functions");
417 MODULE_LICENSE("GPL");
418