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