at v6.19 521 lines 14 kB view raw
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 */ 21struct drm_bridge_priv { 22 unsigned int enable_count; 23 unsigned int disable_count; 24 struct drm_bridge bridge; 25 void *data; 26}; 27 28struct 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 40static struct drm_bridge_priv *bridge_to_priv(struct drm_bridge *bridge) 41{ 42 return container_of(bridge, struct drm_bridge_priv, bridge); 43} 44 45static 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 53static 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 60static 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 67static 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 73static 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 81static 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 89static 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 98KUNIT_DEFINE_ACTION_WRAPPER(drm_bridge_remove_wrapper, 99 drm_bridge_remove, 100 struct drm_bridge *); 101 102static 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 112static struct drm_bridge_init_priv * 113drm_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 */ 187static 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 207retry_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 225retry_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 */ 245static 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 267static 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 274static 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 */ 283static 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 299retry_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 320retry_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 */ 339static 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 359retry_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 */ 378static 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 394retry_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 415retry_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 430static 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 437static 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 442static 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 */ 469static 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 */ 483static 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 499static 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 505static 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 511kunit_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 517MODULE_AUTHOR("Maxime Ripard <mripard@kernel.org>"); 518MODULE_AUTHOR("Luca Ceresoli <luca.ceresoli@bootlin.com>"); 519 520MODULE_DESCRIPTION("Kunit test for drm_bridge functions"); 521MODULE_LICENSE("GPL");