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