Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v6.16-rc3 417 lines 11 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/test.h> 12 13struct 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 24static 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 32static 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 40static const struct drm_bridge_funcs drm_test_bridge_legacy_funcs = { 41 .enable = drm_test_bridge_enable, 42 .disable = drm_test_bridge_disable, 43}; 44 45static 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 54static 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 63static 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 71KUNIT_DEFINE_ACTION_WRAPPER(drm_bridge_remove_wrapper, 72 drm_bridge_remove, 73 struct drm_bridge *); 74 75static 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 85static struct drm_bridge_init_priv * 86drm_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 */ 155static 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 175retry_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 193retry_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 */ 213static 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 235static 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 242static 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 */ 251static 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 267retry_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 288retry_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 */ 307static 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 327retry_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 */ 346static 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 362retry_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 383retry_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 398static 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 405static 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 410kunit_test_suites( 411 &drm_bridge_get_current_state_test_suite, 412 &drm_bridge_helper_reset_crtc_test_suite, 413); 414 415MODULE_AUTHOR("Maxime Ripard <mripard@kernel.org>"); 416MODULE_DESCRIPTION("Kunit test for drm_bridge functions"); 417MODULE_LICENSE("GPL");