1 // SPDX-License-Identifier: GPL-2.0
3 #include <drm/drm_atomic.h>
4 #include <drm/drm_drv.h>
5 #include <drm/drm_kunit_helpers.h>
6 #include <drm/drm_managed.h>
8 #include <kunit/resource.h>
10 #include <linux/device.h>
11 #include <linux/platform_device.h>
13 #define KUNIT_DEVICE_NAME "drm-kunit-mock-device"
15 static const struct drm_mode_config_funcs drm_mode_config_funcs = {
18 static int fake_probe(struct platform_device *pdev)
23 static struct platform_driver fake_platform_driver = {
26 .name = KUNIT_DEVICE_NAME,
30 static void kunit_action_platform_driver_unregister(void *ptr)
32 struct platform_driver *drv = ptr;
34 platform_driver_unregister(drv);
38 static void kunit_action_platform_device_put(void *ptr)
40 struct platform_device *pdev = ptr;
42 platform_device_put(pdev);
45 static void kunit_action_platform_device_del(void *ptr)
47 struct platform_device *pdev = ptr;
49 platform_device_del(pdev);
53 * drm_kunit_helper_alloc_device - Allocate a mock device for a KUnit test
54 * @test: The test context object
56 * This allocates a fake struct &device to create a mock for a KUnit
57 * test. The device will also be bound to a fake driver. It will thus be
58 * able to leverage the usual infrastructure and most notably the
59 * device-managed resources just like a "real" device.
61 * Resources will be cleaned up automatically, but the removal can be
62 * forced using @drm_kunit_helper_free_device.
65 * A pointer to the new device, or an ERR_PTR() otherwise.
67 struct device *drm_kunit_helper_alloc_device(struct kunit *test)
69 struct platform_device *pdev;
72 ret = platform_driver_register(&fake_platform_driver);
73 KUNIT_ASSERT_EQ(test, ret, 0);
75 ret = kunit_add_action_or_reset(test,
76 kunit_action_platform_driver_unregister,
77 &fake_platform_driver);
78 KUNIT_ASSERT_EQ(test, ret, 0);
80 pdev = platform_device_alloc(KUNIT_DEVICE_NAME, PLATFORM_DEVID_NONE);
81 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
83 ret = kunit_add_action_or_reset(test,
84 kunit_action_platform_device_put,
86 KUNIT_ASSERT_EQ(test, ret, 0);
88 ret = platform_device_add(pdev);
89 KUNIT_ASSERT_EQ(test, ret, 0);
91 ret = kunit_add_action_or_reset(test,
92 kunit_action_platform_device_del,
94 KUNIT_ASSERT_EQ(test, ret, 0);
98 EXPORT_SYMBOL_GPL(drm_kunit_helper_alloc_device);
101 * drm_kunit_helper_free_device - Frees a mock device
102 * @test: The test context object
103 * @dev: The device to free
105 * Frees a device allocated with drm_kunit_helper_alloc_device().
107 void drm_kunit_helper_free_device(struct kunit *test, struct device *dev)
109 struct platform_device *pdev = to_platform_device(dev);
111 kunit_release_action(test,
112 kunit_action_platform_device_del,
115 kunit_release_action(test,
116 kunit_action_platform_device_put,
119 kunit_release_action(test,
120 kunit_action_platform_driver_unregister,
121 &fake_platform_driver);
123 EXPORT_SYMBOL_GPL(drm_kunit_helper_free_device);
126 __drm_kunit_helper_alloc_drm_device_with_driver(struct kunit *test,
128 size_t size, size_t offset,
129 const struct drm_driver *driver)
131 struct drm_device *drm;
135 container = __devm_drm_dev_alloc(dev, driver, size, offset);
136 if (IS_ERR(container))
137 return ERR_CAST(container);
139 drm = container + offset;
140 drm->mode_config.funcs = &drm_mode_config_funcs;
142 ret = drmm_mode_config_init(drm);
148 EXPORT_SYMBOL_GPL(__drm_kunit_helper_alloc_drm_device_with_driver);
150 static void action_drm_release_context(void *ptr)
152 struct drm_modeset_acquire_ctx *ctx = ptr;
154 drm_modeset_drop_locks(ctx);
155 drm_modeset_acquire_fini(ctx);
159 * drm_kunit_helper_acquire_ctx_alloc - Allocates an acquire context
160 * @test: The test context object
162 * Allocates and initializes a modeset acquire context.
164 * The context is tied to the kunit test context, so we must not call
165 * drm_modeset_acquire_fini() on it, it will be done so automatically.
168 * An ERR_PTR on error, a pointer to the newly allocated context otherwise
170 struct drm_modeset_acquire_ctx *
171 drm_kunit_helper_acquire_ctx_alloc(struct kunit *test)
173 struct drm_modeset_acquire_ctx *ctx;
176 ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
177 KUNIT_ASSERT_NOT_NULL(test, ctx);
179 drm_modeset_acquire_init(ctx, 0);
181 ret = kunit_add_action_or_reset(test,
182 action_drm_release_context,
189 EXPORT_SYMBOL_GPL(drm_kunit_helper_acquire_ctx_alloc);
191 static void kunit_action_drm_atomic_state_put(void *ptr)
193 struct drm_atomic_state *state = ptr;
195 drm_atomic_state_put(state);
199 * drm_kunit_helper_atomic_state_alloc - Allocates an atomic state
200 * @test: The test context object
201 * @drm: The device to alloc the state for
202 * @ctx: Locking context for that atomic update
204 * Allocates a empty atomic state.
206 * The state is tied to the kunit test context, so we must not call
207 * drm_atomic_state_put() on it, it will be done so automatically.
210 * An ERR_PTR on error, a pointer to the newly allocated state otherwise
212 struct drm_atomic_state *
213 drm_kunit_helper_atomic_state_alloc(struct kunit *test,
214 struct drm_device *drm,
215 struct drm_modeset_acquire_ctx *ctx)
217 struct drm_atomic_state *state;
220 state = drm_atomic_state_alloc(drm);
222 return ERR_PTR(-ENOMEM);
224 ret = kunit_add_action_or_reset(test,
225 kunit_action_drm_atomic_state_put,
230 state->acquire_ctx = ctx;
234 EXPORT_SYMBOL_GPL(drm_kunit_helper_atomic_state_alloc);
236 MODULE_AUTHOR("Maxime Ripard <maxime@cerno.tech>");
237 MODULE_LICENSE("GPL");