drm_bridge_test.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  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. #include <kunit/device.h>
  11. #include <kunit/test.h>
  12. /*
  13. * Mimick the typical "private" struct defined by a bridge driver, which
  14. * embeds a bridge plus other fields.
  15. *
  16. * Having at least one member before @bridge ensures we test non-zero
  17. * @bridge offset.
  18. */
  19. struct drm_bridge_priv {
  20. unsigned int enable_count;
  21. unsigned int disable_count;
  22. struct drm_bridge bridge;
  23. void *data;
  24. };
  25. struct drm_bridge_init_priv {
  26. struct drm_device drm;
  27. /** @dev: device, only for tests not needing a whole drm_device */
  28. struct device *dev;
  29. struct drm_plane *plane;
  30. struct drm_crtc *crtc;
  31. struct drm_encoder encoder;
  32. struct drm_bridge_priv *test_bridge;
  33. struct drm_connector *connector;
  34. bool destroyed;
  35. };
  36. static struct drm_bridge_priv *bridge_to_priv(struct drm_bridge *bridge)
  37. {
  38. return container_of(bridge, struct drm_bridge_priv, bridge);
  39. }
  40. static void drm_test_bridge_priv_destroy(struct drm_bridge *bridge)
  41. {
  42. struct drm_bridge_priv *bridge_priv = bridge_to_priv(bridge);
  43. struct drm_bridge_init_priv *priv = (struct drm_bridge_init_priv *)bridge_priv->data;
  44. priv->destroyed = true;
  45. }
  46. static void drm_test_bridge_enable(struct drm_bridge *bridge)
  47. {
  48. struct drm_bridge_priv *priv = bridge_to_priv(bridge);
  49. priv->enable_count++;
  50. }
  51. static void drm_test_bridge_disable(struct drm_bridge *bridge)
  52. {
  53. struct drm_bridge_priv *priv = bridge_to_priv(bridge);
  54. priv->disable_count++;
  55. }
  56. static const struct drm_bridge_funcs drm_test_bridge_legacy_funcs = {
  57. .destroy = drm_test_bridge_priv_destroy,
  58. .enable = drm_test_bridge_enable,
  59. .disable = drm_test_bridge_disable,
  60. };
  61. static void drm_test_bridge_atomic_enable(struct drm_bridge *bridge,
  62. struct drm_atomic_state *state)
  63. {
  64. struct drm_bridge_priv *priv = bridge_to_priv(bridge);
  65. priv->enable_count++;
  66. }
  67. static void drm_test_bridge_atomic_disable(struct drm_bridge *bridge,
  68. struct drm_atomic_state *state)
  69. {
  70. struct drm_bridge_priv *priv = bridge_to_priv(bridge);
  71. priv->disable_count++;
  72. }
  73. static const struct drm_bridge_funcs drm_test_bridge_atomic_funcs = {
  74. .destroy = drm_test_bridge_priv_destroy,
  75. .atomic_enable = drm_test_bridge_atomic_enable,
  76. .atomic_disable = drm_test_bridge_atomic_disable,
  77. .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
  78. .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
  79. .atomic_reset = drm_atomic_helper_bridge_reset,
  80. };
  81. KUNIT_DEFINE_ACTION_WRAPPER(drm_bridge_remove_wrapper,
  82. drm_bridge_remove,
  83. struct drm_bridge *);
  84. static int drm_kunit_bridge_add(struct kunit *test,
  85. struct drm_bridge *bridge)
  86. {
  87. drm_bridge_add(bridge);
  88. return kunit_add_action_or_reset(test,
  89. drm_bridge_remove_wrapper,
  90. bridge);
  91. }
  92. static struct drm_bridge_init_priv *
  93. drm_test_bridge_init(struct kunit *test, const struct drm_bridge_funcs *funcs)
  94. {
  95. struct drm_bridge_init_priv *priv;
  96. struct drm_encoder *enc;
  97. struct drm_bridge *bridge;
  98. struct drm_device *drm;
  99. struct device *dev;
  100. int ret;
  101. dev = drm_kunit_helper_alloc_device(test);
  102. if (IS_ERR(dev))
  103. return ERR_CAST(dev);
  104. priv = drm_kunit_helper_alloc_drm_device(test, dev,
  105. struct drm_bridge_init_priv, drm,
  106. DRIVER_MODESET | DRIVER_ATOMIC);
  107. if (IS_ERR(priv))
  108. return ERR_CAST(priv);
  109. priv->test_bridge = devm_drm_bridge_alloc(dev, struct drm_bridge_priv, bridge, funcs);
  110. if (IS_ERR(priv->test_bridge))
  111. return ERR_CAST(priv->test_bridge);
  112. priv->test_bridge->data = priv;
  113. drm = &priv->drm;
  114. priv->plane = drm_kunit_helper_create_primary_plane(test, drm,
  115. NULL,
  116. NULL,
  117. NULL, 0,
  118. NULL);
  119. if (IS_ERR(priv->plane))
  120. return ERR_CAST(priv->plane);
  121. priv->crtc = drm_kunit_helper_create_crtc(test, drm,
  122. priv->plane, NULL,
  123. NULL,
  124. NULL);
  125. if (IS_ERR(priv->crtc))
  126. return ERR_CAST(priv->crtc);
  127. enc = &priv->encoder;
  128. ret = drmm_encoder_init(drm, enc, NULL, DRM_MODE_ENCODER_TMDS, NULL);
  129. if (ret)
  130. return ERR_PTR(ret);
  131. enc->possible_crtcs = drm_crtc_mask(priv->crtc);
  132. bridge = &priv->test_bridge->bridge;
  133. bridge->type = DRM_MODE_CONNECTOR_VIRTUAL;
  134. ret = drm_kunit_bridge_add(test, bridge);
  135. if (ret)
  136. return ERR_PTR(ret);
  137. ret = drm_bridge_attach(enc, bridge, NULL, 0);
  138. if (ret)
  139. return ERR_PTR(ret);
  140. priv->connector = drm_bridge_connector_init(drm, enc);
  141. if (IS_ERR(priv->connector))
  142. return ERR_CAST(priv->connector);
  143. drm_connector_attach_encoder(priv->connector, enc);
  144. drm_mode_config_reset(drm);
  145. return priv;
  146. }
  147. /*
  148. * Test that drm_bridge_get_current_state() returns the last committed
  149. * state for an atomic bridge.
  150. */
  151. static void drm_test_drm_bridge_get_current_state_atomic(struct kunit *test)
  152. {
  153. struct drm_modeset_acquire_ctx ctx;
  154. struct drm_bridge_init_priv *priv;
  155. struct drm_bridge_state *curr_bridge_state;
  156. struct drm_bridge_state *bridge_state;
  157. struct drm_atomic_state *state;
  158. struct drm_bridge *bridge;
  159. struct drm_device *drm;
  160. int ret;
  161. priv = drm_test_bridge_init(test, &drm_test_bridge_atomic_funcs);
  162. KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
  163. drm_modeset_acquire_init(&ctx, 0);
  164. drm = &priv->drm;
  165. state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
  166. KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
  167. retry_commit:
  168. bridge = &priv->test_bridge->bridge;
  169. bridge_state = drm_atomic_get_bridge_state(state, bridge);
  170. KUNIT_ASSERT_NOT_ERR_OR_NULL(test, bridge_state);
  171. ret = drm_atomic_commit(state);
  172. if (ret == -EDEADLK) {
  173. drm_atomic_state_clear(state);
  174. drm_modeset_backoff(&ctx);
  175. goto retry_commit;
  176. }
  177. KUNIT_ASSERT_EQ(test, ret, 0);
  178. drm_modeset_drop_locks(&ctx);
  179. drm_modeset_acquire_fini(&ctx);
  180. drm_modeset_acquire_init(&ctx, 0);
  181. retry_state:
  182. ret = drm_modeset_lock(&bridge->base.lock, &ctx);
  183. if (ret == -EDEADLK) {
  184. drm_modeset_backoff(&ctx);
  185. goto retry_state;
  186. }
  187. curr_bridge_state = drm_bridge_get_current_state(bridge);
  188. KUNIT_EXPECT_PTR_EQ(test, curr_bridge_state, bridge_state);
  189. drm_modeset_unlock(&bridge->base.lock);
  190. drm_modeset_drop_locks(&ctx);
  191. drm_modeset_acquire_fini(&ctx);
  192. }
  193. /*
  194. * Test that drm_bridge_get_current_state() returns NULL for a
  195. * non-atomic bridge.
  196. */
  197. static void drm_test_drm_bridge_get_current_state_legacy(struct kunit *test)
  198. {
  199. struct drm_bridge_init_priv *priv;
  200. struct drm_bridge *bridge;
  201. priv = drm_test_bridge_init(test, &drm_test_bridge_legacy_funcs);
  202. KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
  203. /*
  204. * NOTE: Strictly speaking, we should take the bridge->base.lock
  205. * before calling that function. However, bridge->base is only
  206. * initialized if the bridge is atomic, while we explicitly
  207. * initialize one that isn't there.
  208. *
  209. * In order to avoid unnecessary warnings, let's skip the
  210. * locking. The function would return NULL in all cases anyway,
  211. * so we don't really have any concurrency to worry about.
  212. */
  213. bridge = &priv->test_bridge->bridge;
  214. KUNIT_EXPECT_NULL(test, drm_bridge_get_current_state(bridge));
  215. }
  216. static struct kunit_case drm_bridge_get_current_state_tests[] = {
  217. KUNIT_CASE(drm_test_drm_bridge_get_current_state_atomic),
  218. KUNIT_CASE(drm_test_drm_bridge_get_current_state_legacy),
  219. { }
  220. };
  221. static struct kunit_suite drm_bridge_get_current_state_test_suite = {
  222. .name = "drm_test_bridge_get_current_state",
  223. .test_cases = drm_bridge_get_current_state_tests,
  224. };
  225. /*
  226. * Test that an atomic bridge is properly power-cycled when calling
  227. * drm_bridge_helper_reset_crtc().
  228. */
  229. static void drm_test_drm_bridge_helper_reset_crtc_atomic(struct kunit *test)
  230. {
  231. struct drm_modeset_acquire_ctx ctx;
  232. struct drm_bridge_init_priv *priv;
  233. struct drm_display_mode *mode;
  234. struct drm_bridge_priv *bridge_priv;
  235. int ret;
  236. priv = drm_test_bridge_init(test, &drm_test_bridge_atomic_funcs);
  237. KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
  238. mode = drm_kunit_display_mode_from_cea_vic(test, &priv->drm, 16);
  239. KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mode);
  240. drm_modeset_acquire_init(&ctx, 0);
  241. retry_commit:
  242. ret = drm_kunit_helper_enable_crtc_connector(test,
  243. &priv->drm, priv->crtc,
  244. priv->connector,
  245. mode,
  246. &ctx);
  247. if (ret == -EDEADLK) {
  248. drm_modeset_backoff(&ctx);
  249. goto retry_commit;
  250. }
  251. KUNIT_ASSERT_EQ(test, ret, 0);
  252. drm_modeset_drop_locks(&ctx);
  253. drm_modeset_acquire_fini(&ctx);
  254. bridge_priv = priv->test_bridge;
  255. KUNIT_ASSERT_EQ(test, bridge_priv->enable_count, 1);
  256. KUNIT_ASSERT_EQ(test, bridge_priv->disable_count, 0);
  257. drm_modeset_acquire_init(&ctx, 0);
  258. retry_reset:
  259. ret = drm_bridge_helper_reset_crtc(&bridge_priv->bridge, &ctx);
  260. if (ret == -EDEADLK) {
  261. drm_modeset_backoff(&ctx);
  262. goto retry_reset;
  263. }
  264. KUNIT_ASSERT_EQ(test, ret, 0);
  265. drm_modeset_drop_locks(&ctx);
  266. drm_modeset_acquire_fini(&ctx);
  267. KUNIT_EXPECT_EQ(test, bridge_priv->enable_count, 2);
  268. KUNIT_EXPECT_EQ(test, bridge_priv->disable_count, 1);
  269. }
  270. /*
  271. * Test that calling drm_bridge_helper_reset_crtc() on a disabled atomic
  272. * bridge will fail and not call the enable / disable callbacks
  273. */
  274. static void drm_test_drm_bridge_helper_reset_crtc_atomic_disabled(struct kunit *test)
  275. {
  276. struct drm_modeset_acquire_ctx ctx;
  277. struct drm_bridge_init_priv *priv;
  278. struct drm_display_mode *mode;
  279. struct drm_bridge_priv *bridge_priv;
  280. int ret;
  281. priv = drm_test_bridge_init(test, &drm_test_bridge_atomic_funcs);
  282. KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
  283. mode = drm_kunit_display_mode_from_cea_vic(test, &priv->drm, 16);
  284. KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mode);
  285. bridge_priv = priv->test_bridge;
  286. KUNIT_ASSERT_EQ(test, bridge_priv->enable_count, 0);
  287. KUNIT_ASSERT_EQ(test, bridge_priv->disable_count, 0);
  288. drm_modeset_acquire_init(&ctx, 0);
  289. retry_reset:
  290. ret = drm_bridge_helper_reset_crtc(&bridge_priv->bridge, &ctx);
  291. if (ret == -EDEADLK) {
  292. drm_modeset_backoff(&ctx);
  293. goto retry_reset;
  294. }
  295. KUNIT_EXPECT_LT(test, ret, 0);
  296. drm_modeset_drop_locks(&ctx);
  297. drm_modeset_acquire_fini(&ctx);
  298. KUNIT_EXPECT_EQ(test, bridge_priv->enable_count, 0);
  299. KUNIT_EXPECT_EQ(test, bridge_priv->disable_count, 0);
  300. }
  301. /*
  302. * Test that a non-atomic bridge is properly power-cycled when calling
  303. * drm_bridge_helper_reset_crtc().
  304. */
  305. static void drm_test_drm_bridge_helper_reset_crtc_legacy(struct kunit *test)
  306. {
  307. struct drm_modeset_acquire_ctx ctx;
  308. struct drm_bridge_init_priv *priv;
  309. struct drm_display_mode *mode;
  310. struct drm_bridge_priv *bridge_priv;
  311. int ret;
  312. priv = drm_test_bridge_init(test, &drm_test_bridge_legacy_funcs);
  313. KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
  314. mode = drm_kunit_display_mode_from_cea_vic(test, &priv->drm, 16);
  315. KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mode);
  316. drm_modeset_acquire_init(&ctx, 0);
  317. retry_commit:
  318. ret = drm_kunit_helper_enable_crtc_connector(test,
  319. &priv->drm, priv->crtc,
  320. priv->connector,
  321. mode,
  322. &ctx);
  323. if (ret == -EDEADLK) {
  324. drm_modeset_backoff(&ctx);
  325. goto retry_commit;
  326. }
  327. KUNIT_ASSERT_EQ(test, ret, 0);
  328. drm_modeset_drop_locks(&ctx);
  329. drm_modeset_acquire_fini(&ctx);
  330. bridge_priv = priv->test_bridge;
  331. KUNIT_ASSERT_EQ(test, bridge_priv->enable_count, 1);
  332. KUNIT_ASSERT_EQ(test, bridge_priv->disable_count, 0);
  333. drm_modeset_acquire_init(&ctx, 0);
  334. retry_reset:
  335. ret = drm_bridge_helper_reset_crtc(&bridge_priv->bridge, &ctx);
  336. if (ret == -EDEADLK) {
  337. drm_modeset_backoff(&ctx);
  338. goto retry_reset;
  339. }
  340. KUNIT_ASSERT_EQ(test, ret, 0);
  341. drm_modeset_drop_locks(&ctx);
  342. drm_modeset_acquire_fini(&ctx);
  343. KUNIT_EXPECT_EQ(test, bridge_priv->enable_count, 2);
  344. KUNIT_EXPECT_EQ(test, bridge_priv->disable_count, 1);
  345. }
  346. static struct kunit_case drm_bridge_helper_reset_crtc_tests[] = {
  347. KUNIT_CASE(drm_test_drm_bridge_helper_reset_crtc_atomic),
  348. KUNIT_CASE(drm_test_drm_bridge_helper_reset_crtc_atomic_disabled),
  349. KUNIT_CASE(drm_test_drm_bridge_helper_reset_crtc_legacy),
  350. { }
  351. };
  352. static struct kunit_suite drm_bridge_helper_reset_crtc_test_suite = {
  353. .name = "drm_test_bridge_helper_reset_crtc",
  354. .test_cases = drm_bridge_helper_reset_crtc_tests,
  355. };
  356. static int drm_test_bridge_alloc_init(struct kunit *test)
  357. {
  358. struct drm_bridge_init_priv *priv;
  359. priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
  360. KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
  361. priv->dev = kunit_device_register(test, "drm-bridge-dev");
  362. KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->dev);
  363. test->priv = priv;
  364. priv->test_bridge = devm_drm_bridge_alloc(priv->dev, struct drm_bridge_priv, bridge,
  365. &drm_test_bridge_atomic_funcs);
  366. KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->test_bridge);
  367. priv->test_bridge->data = priv;
  368. KUNIT_ASSERT_FALSE(test, priv->destroyed);
  369. return 0;
  370. }
  371. /*
  372. * Test that a bridge is freed when the device is destroyed in lack of
  373. * other drm_bridge_get/put() operations.
  374. */
  375. static void drm_test_drm_bridge_alloc_basic(struct kunit *test)
  376. {
  377. struct drm_bridge_init_priv *priv = test->priv;
  378. KUNIT_ASSERT_FALSE(test, priv->destroyed);
  379. kunit_device_unregister(test, priv->dev);
  380. KUNIT_EXPECT_TRUE(test, priv->destroyed);
  381. }
  382. /*
  383. * Test that a bridge is not freed when the device is destroyed when there
  384. * is still a reference to it, and freed when that reference is put.
  385. */
  386. static void drm_test_drm_bridge_alloc_get_put(struct kunit *test)
  387. {
  388. struct drm_bridge_init_priv *priv = test->priv;
  389. KUNIT_ASSERT_FALSE(test, priv->destroyed);
  390. drm_bridge_get(&priv->test_bridge->bridge);
  391. KUNIT_EXPECT_FALSE(test, priv->destroyed);
  392. kunit_device_unregister(test, priv->dev);
  393. KUNIT_EXPECT_FALSE(test, priv->destroyed);
  394. drm_bridge_put(&priv->test_bridge->bridge);
  395. KUNIT_EXPECT_TRUE(test, priv->destroyed);
  396. }
  397. static struct kunit_case drm_bridge_alloc_tests[] = {
  398. KUNIT_CASE(drm_test_drm_bridge_alloc_basic),
  399. KUNIT_CASE(drm_test_drm_bridge_alloc_get_put),
  400. { }
  401. };
  402. static struct kunit_suite drm_bridge_alloc_test_suite = {
  403. .name = "drm_bridge_alloc",
  404. .init = drm_test_bridge_alloc_init,
  405. .test_cases = drm_bridge_alloc_tests,
  406. };
  407. kunit_test_suites(
  408. &drm_bridge_get_current_state_test_suite,
  409. &drm_bridge_helper_reset_crtc_test_suite,
  410. &drm_bridge_alloc_test_suite,
  411. );
  412. MODULE_AUTHOR("Maxime Ripard <mripard@kernel.org>");
  413. MODULE_AUTHOR("Luca Ceresoli <luca.ceresoli@bootlin.com>");
  414. MODULE_DESCRIPTION("Kunit test for drm_bridge functions");
  415. MODULE_LICENSE("GPL");