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