drm_kunit_helpers.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. // SPDX-License-Identifier: GPL-2.0
  2. #include <drm/drm_atomic.h>
  3. #include <drm/drm_atomic_helper.h>
  4. #include <drm/drm_drv.h>
  5. #include <drm/drm_edid.h>
  6. #include <drm/drm_fourcc.h>
  7. #include <drm/drm_kunit_helpers.h>
  8. #include <drm/drm_managed.h>
  9. #include <kunit/device.h>
  10. #include <kunit/resource.h>
  11. #include <linux/device.h>
  12. #include <linux/platform_device.h>
  13. #define KUNIT_DEVICE_NAME "drm-kunit-mock-device"
  14. static const struct drm_mode_config_funcs drm_mode_config_funcs = {
  15. .atomic_check = drm_atomic_helper_check,
  16. .atomic_commit = drm_atomic_helper_commit,
  17. };
  18. /**
  19. * drm_kunit_helper_alloc_device - Allocate a mock device for a KUnit test
  20. * @test: The test context object
  21. *
  22. * This allocates a fake struct &device to create a mock for a KUnit
  23. * test. The device will also be bound to a fake driver. It will thus be
  24. * able to leverage the usual infrastructure and most notably the
  25. * device-managed resources just like a "real" device.
  26. *
  27. * Resources will be cleaned up automatically, but the removal can be
  28. * forced using @drm_kunit_helper_free_device.
  29. *
  30. * Returns:
  31. * A pointer to the new device, or an ERR_PTR() otherwise.
  32. */
  33. struct device *drm_kunit_helper_alloc_device(struct kunit *test)
  34. {
  35. return kunit_device_register(test, KUNIT_DEVICE_NAME);
  36. }
  37. EXPORT_SYMBOL_GPL(drm_kunit_helper_alloc_device);
  38. /**
  39. * drm_kunit_helper_free_device - Frees a mock device
  40. * @test: The test context object
  41. * @dev: The device to free
  42. *
  43. * Frees a device allocated with drm_kunit_helper_alloc_device().
  44. */
  45. void drm_kunit_helper_free_device(struct kunit *test, struct device *dev)
  46. {
  47. kunit_device_unregister(test, dev);
  48. }
  49. EXPORT_SYMBOL_GPL(drm_kunit_helper_free_device);
  50. struct drm_device *
  51. __drm_kunit_helper_alloc_drm_device_with_driver(struct kunit *test,
  52. struct device *dev,
  53. size_t size, size_t offset,
  54. const struct drm_driver *driver)
  55. {
  56. struct drm_device *drm;
  57. void *container;
  58. int ret;
  59. container = __devm_drm_dev_alloc(dev, driver, size, offset);
  60. if (IS_ERR(container))
  61. return ERR_CAST(container);
  62. drm = container + offset;
  63. drm->mode_config.funcs = &drm_mode_config_funcs;
  64. ret = drmm_mode_config_init(drm);
  65. if (ret)
  66. return ERR_PTR(ret);
  67. return drm;
  68. }
  69. EXPORT_SYMBOL_GPL(__drm_kunit_helper_alloc_drm_device_with_driver);
  70. static void action_drm_release_context(void *ptr)
  71. {
  72. struct drm_modeset_acquire_ctx *ctx = ptr;
  73. drm_modeset_drop_locks(ctx);
  74. drm_modeset_acquire_fini(ctx);
  75. }
  76. /**
  77. * drm_kunit_helper_acquire_ctx_alloc - Allocates an acquire context
  78. * @test: The test context object
  79. *
  80. * Allocates and initializes a modeset acquire context.
  81. *
  82. * The context is tied to the kunit test context, so we must not call
  83. * drm_modeset_acquire_fini() on it, it will be done so automatically.
  84. *
  85. * Returns:
  86. * An ERR_PTR on error, a pointer to the newly allocated context otherwise
  87. */
  88. struct drm_modeset_acquire_ctx *
  89. drm_kunit_helper_acquire_ctx_alloc(struct kunit *test)
  90. {
  91. struct drm_modeset_acquire_ctx *ctx;
  92. int ret;
  93. ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
  94. KUNIT_ASSERT_NOT_NULL(test, ctx);
  95. drm_modeset_acquire_init(ctx, 0);
  96. ret = kunit_add_action_or_reset(test,
  97. action_drm_release_context,
  98. ctx);
  99. if (ret)
  100. return ERR_PTR(ret);
  101. return ctx;
  102. }
  103. EXPORT_SYMBOL_GPL(drm_kunit_helper_acquire_ctx_alloc);
  104. static void kunit_action_drm_atomic_state_put(void *ptr)
  105. {
  106. struct drm_atomic_state *state = ptr;
  107. drm_atomic_state_put(state);
  108. }
  109. /**
  110. * drm_kunit_helper_atomic_state_alloc - Allocates an atomic state
  111. * @test: The test context object
  112. * @drm: The device to alloc the state for
  113. * @ctx: Locking context for that atomic update
  114. *
  115. * Allocates a empty atomic state.
  116. *
  117. * The state is tied to the kunit test context, so we must not call
  118. * drm_atomic_state_put() on it, it will be done so automatically.
  119. *
  120. * Returns:
  121. * An ERR_PTR on error, a pointer to the newly allocated state otherwise
  122. */
  123. struct drm_atomic_state *
  124. drm_kunit_helper_atomic_state_alloc(struct kunit *test,
  125. struct drm_device *drm,
  126. struct drm_modeset_acquire_ctx *ctx)
  127. {
  128. struct drm_atomic_state *state;
  129. int ret;
  130. state = drm_atomic_state_alloc(drm);
  131. if (!state)
  132. return ERR_PTR(-ENOMEM);
  133. ret = kunit_add_action_or_reset(test,
  134. kunit_action_drm_atomic_state_put,
  135. state);
  136. if (ret)
  137. return ERR_PTR(ret);
  138. state->acquire_ctx = ctx;
  139. return state;
  140. }
  141. EXPORT_SYMBOL_GPL(drm_kunit_helper_atomic_state_alloc);
  142. static const uint32_t default_plane_formats[] = {
  143. DRM_FORMAT_XRGB8888,
  144. };
  145. static const uint64_t default_plane_modifiers[] = {
  146. DRM_FORMAT_MOD_LINEAR,
  147. DRM_FORMAT_MOD_INVALID
  148. };
  149. static const struct drm_plane_helper_funcs default_plane_helper_funcs = {
  150. };
  151. static const struct drm_plane_funcs default_plane_funcs = {
  152. .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
  153. .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
  154. .reset = drm_atomic_helper_plane_reset,
  155. };
  156. /**
  157. * drm_kunit_helper_create_primary_plane - Creates a mock primary plane for a KUnit test
  158. * @test: The test context object
  159. * @drm: The device to alloc the plane for
  160. * @funcs: Callbacks for the new plane. Optional.
  161. * @helper_funcs: Helpers callbacks for the new plane. Optional.
  162. * @formats: array of supported formats (DRM_FORMAT\_\*). Optional.
  163. * @num_formats: number of elements in @formats
  164. * @modifiers: array of struct drm_format modifiers terminated by
  165. * DRM_FORMAT_MOD_INVALID. Optional.
  166. *
  167. * This allocates and initializes a mock struct &drm_plane meant to be
  168. * part of a mock device for a KUnit test.
  169. *
  170. * Resources will be cleaned up automatically.
  171. *
  172. * @funcs will default to the default helpers implementations.
  173. * @helper_funcs will default to an empty implementation. @formats will
  174. * default to XRGB8888 only. @modifiers will default to a linear
  175. * modifier only.
  176. *
  177. * Returns:
  178. * A pointer to the new plane, or an ERR_PTR() otherwise.
  179. */
  180. struct drm_plane *
  181. drm_kunit_helper_create_primary_plane(struct kunit *test,
  182. struct drm_device *drm,
  183. const struct drm_plane_funcs *funcs,
  184. const struct drm_plane_helper_funcs *helper_funcs,
  185. const uint32_t *formats,
  186. unsigned int num_formats,
  187. const uint64_t *modifiers)
  188. {
  189. struct drm_plane *plane;
  190. if (!funcs)
  191. funcs = &default_plane_funcs;
  192. if (!helper_funcs)
  193. helper_funcs = &default_plane_helper_funcs;
  194. if (!formats || !num_formats) {
  195. formats = default_plane_formats;
  196. num_formats = ARRAY_SIZE(default_plane_formats);
  197. }
  198. if (!modifiers)
  199. modifiers = default_plane_modifiers;
  200. plane = __drmm_universal_plane_alloc(drm,
  201. sizeof(struct drm_plane), 0,
  202. 0,
  203. funcs,
  204. formats,
  205. num_formats,
  206. default_plane_modifiers,
  207. DRM_PLANE_TYPE_PRIMARY,
  208. NULL);
  209. KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane);
  210. drm_plane_helper_add(plane, helper_funcs);
  211. return plane;
  212. }
  213. EXPORT_SYMBOL_GPL(drm_kunit_helper_create_primary_plane);
  214. static const struct drm_crtc_helper_funcs default_crtc_helper_funcs = {
  215. };
  216. static const struct drm_crtc_funcs default_crtc_funcs = {
  217. .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
  218. .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
  219. .reset = drm_atomic_helper_crtc_reset,
  220. };
  221. /**
  222. * drm_kunit_helper_create_crtc - Creates a mock CRTC for a KUnit test
  223. * @test: The test context object
  224. * @drm: The device to alloc the plane for
  225. * @primary: Primary plane for CRTC
  226. * @cursor: Cursor plane for CRTC. Optional.
  227. * @funcs: Callbacks for the new plane. Optional.
  228. * @helper_funcs: Helpers callbacks for the new plane. Optional.
  229. *
  230. * This allocates and initializes a mock struct &drm_crtc meant to be
  231. * part of a mock device for a KUnit test.
  232. *
  233. * Resources will be cleaned up automatically.
  234. *
  235. * @funcs will default to the default helpers implementations.
  236. * @helper_funcs will default to an empty implementation.
  237. *
  238. * Returns:
  239. * A pointer to the new CRTC, or an ERR_PTR() otherwise.
  240. */
  241. struct drm_crtc *
  242. drm_kunit_helper_create_crtc(struct kunit *test,
  243. struct drm_device *drm,
  244. struct drm_plane *primary,
  245. struct drm_plane *cursor,
  246. const struct drm_crtc_funcs *funcs,
  247. const struct drm_crtc_helper_funcs *helper_funcs)
  248. {
  249. struct drm_crtc *crtc;
  250. int ret;
  251. if (!funcs)
  252. funcs = &default_crtc_funcs;
  253. if (!helper_funcs)
  254. helper_funcs = &default_crtc_helper_funcs;
  255. crtc = drmm_kzalloc(drm, sizeof(*crtc), GFP_KERNEL);
  256. KUNIT_ASSERT_NOT_NULL(test, crtc);
  257. ret = drmm_crtc_init_with_planes(drm, crtc,
  258. primary,
  259. cursor,
  260. funcs,
  261. NULL);
  262. KUNIT_ASSERT_EQ(test, ret, 0);
  263. drm_crtc_helper_add(crtc, helper_funcs);
  264. return crtc;
  265. }
  266. EXPORT_SYMBOL_GPL(drm_kunit_helper_create_crtc);
  267. static void kunit_action_drm_mode_destroy(void *ptr)
  268. {
  269. struct drm_display_mode *mode = ptr;
  270. drm_mode_destroy(NULL, mode);
  271. }
  272. /**
  273. * drm_kunit_add_mode_destroy_action() - Add a drm_destroy_mode kunit action
  274. * @test: The test context object
  275. * @mode: The drm_display_mode to destroy eventually
  276. *
  277. * Registers a kunit action that will destroy the drm_display_mode at
  278. * the end of the test.
  279. *
  280. * If an error occurs, the drm_display_mode will be destroyed.
  281. *
  282. * Returns:
  283. * 0 on success, an error code otherwise.
  284. */
  285. int drm_kunit_add_mode_destroy_action(struct kunit *test,
  286. struct drm_display_mode *mode)
  287. {
  288. return kunit_add_action_or_reset(test,
  289. kunit_action_drm_mode_destroy,
  290. mode);
  291. }
  292. EXPORT_SYMBOL_GPL(drm_kunit_add_mode_destroy_action);
  293. /**
  294. * drm_kunit_display_mode_from_cea_vic() - return a mode for CEA VIC for a KUnit test
  295. * @test: The test context object
  296. * @dev: DRM device
  297. * @video_code: CEA VIC of the mode
  298. *
  299. * Creates a new mode matching the specified CEA VIC for a KUnit test.
  300. *
  301. * Resources will be cleaned up automatically.
  302. *
  303. * Returns: A new drm_display_mode on success or NULL on failure
  304. */
  305. struct drm_display_mode *
  306. drm_kunit_display_mode_from_cea_vic(struct kunit *test, struct drm_device *dev,
  307. u8 video_code)
  308. {
  309. struct drm_display_mode *mode;
  310. int ret;
  311. mode = drm_display_mode_from_cea_vic(dev, video_code);
  312. if (!mode)
  313. return NULL;
  314. ret = kunit_add_action_or_reset(test,
  315. kunit_action_drm_mode_destroy,
  316. mode);
  317. if (ret)
  318. return NULL;
  319. return mode;
  320. }
  321. EXPORT_SYMBOL_GPL(drm_kunit_display_mode_from_cea_vic);
  322. MODULE_AUTHOR("Maxime Ripard <maxime@cerno.tech>");
  323. MODULE_DESCRIPTION("KUnit test suite helper functions");
  324. MODULE_LICENSE("GPL");