drm/tests: helpers: Add atomic helpers
[linux-2.6-microblaze.git] / drivers / gpu / drm / tests / drm_kunit_helpers.c
1 // SPDX-License-Identifier: GPL-2.0
2
3 #include <drm/drm_atomic.h>
4 #include <drm/drm_atomic_helper.h>
5 #include <drm/drm_drv.h>
6 #include <drm/drm_kunit_helpers.h>
7 #include <drm/drm_managed.h>
8
9 #include <kunit/device.h>
10 #include <kunit/resource.h>
11
12 #include <linux/device.h>
13 #include <linux/platform_device.h>
14
15 #define KUNIT_DEVICE_NAME       "drm-kunit-mock-device"
16
17 static const struct drm_mode_config_funcs drm_mode_config_funcs = {
18         .atomic_check   = drm_atomic_helper_check,
19         .atomic_commit  = drm_atomic_helper_commit,
20 };
21
22 /**
23  * drm_kunit_helper_alloc_device - Allocate a mock device for a KUnit test
24  * @test: The test context object
25  *
26  * This allocates a fake struct &device to create a mock for a KUnit
27  * test. The device will also be bound to a fake driver. It will thus be
28  * able to leverage the usual infrastructure and most notably the
29  * device-managed resources just like a "real" device.
30  *
31  * Resources will be cleaned up automatically, but the removal can be
32  * forced using @drm_kunit_helper_free_device.
33  *
34  * Returns:
35  * A pointer to the new device, or an ERR_PTR() otherwise.
36  */
37 struct device *drm_kunit_helper_alloc_device(struct kunit *test)
38 {
39         return kunit_device_register(test, KUNIT_DEVICE_NAME);
40 }
41 EXPORT_SYMBOL_GPL(drm_kunit_helper_alloc_device);
42
43 /**
44  * drm_kunit_helper_free_device - Frees a mock device
45  * @test: The test context object
46  * @dev: The device to free
47  *
48  * Frees a device allocated with drm_kunit_helper_alloc_device().
49  */
50 void drm_kunit_helper_free_device(struct kunit *test, struct device *dev)
51 {
52         kunit_device_unregister(test, dev);
53 }
54 EXPORT_SYMBOL_GPL(drm_kunit_helper_free_device);
55
56 struct drm_device *
57 __drm_kunit_helper_alloc_drm_device_with_driver(struct kunit *test,
58                                                 struct device *dev,
59                                                 size_t size, size_t offset,
60                                                 const struct drm_driver *driver)
61 {
62         struct drm_device *drm;
63         void *container;
64         int ret;
65
66         container = __devm_drm_dev_alloc(dev, driver, size, offset);
67         if (IS_ERR(container))
68                 return ERR_CAST(container);
69
70         drm = container + offset;
71         drm->mode_config.funcs = &drm_mode_config_funcs;
72
73         ret = drmm_mode_config_init(drm);
74         if (ret)
75                 return ERR_PTR(ret);
76
77         return drm;
78 }
79 EXPORT_SYMBOL_GPL(__drm_kunit_helper_alloc_drm_device_with_driver);
80
81 static void action_drm_release_context(void *ptr)
82 {
83         struct drm_modeset_acquire_ctx *ctx = ptr;
84
85         drm_modeset_drop_locks(ctx);
86         drm_modeset_acquire_fini(ctx);
87 }
88
89 /**
90  * drm_kunit_helper_acquire_ctx_alloc - Allocates an acquire context
91  * @test: The test context object
92  *
93  * Allocates and initializes a modeset acquire context.
94  *
95  * The context is tied to the kunit test context, so we must not call
96  * drm_modeset_acquire_fini() on it, it will be done so automatically.
97  *
98  * Returns:
99  * An ERR_PTR on error, a pointer to the newly allocated context otherwise
100  */
101 struct drm_modeset_acquire_ctx *
102 drm_kunit_helper_acquire_ctx_alloc(struct kunit *test)
103 {
104         struct drm_modeset_acquire_ctx *ctx;
105         int ret;
106
107         ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
108         KUNIT_ASSERT_NOT_NULL(test, ctx);
109
110         drm_modeset_acquire_init(ctx, 0);
111
112         ret = kunit_add_action_or_reset(test,
113                                         action_drm_release_context,
114                                         ctx);
115         if (ret)
116                 return ERR_PTR(ret);
117
118         return ctx;
119 }
120 EXPORT_SYMBOL_GPL(drm_kunit_helper_acquire_ctx_alloc);
121
122 static void kunit_action_drm_atomic_state_put(void *ptr)
123 {
124         struct drm_atomic_state *state = ptr;
125
126         drm_atomic_state_put(state);
127 }
128
129 /**
130  * drm_kunit_helper_atomic_state_alloc - Allocates an atomic state
131  * @test: The test context object
132  * @drm: The device to alloc the state for
133  * @ctx: Locking context for that atomic update
134  *
135  * Allocates a empty atomic state.
136  *
137  * The state is tied to the kunit test context, so we must not call
138  * drm_atomic_state_put() on it, it will be done so automatically.
139  *
140  * Returns:
141  * An ERR_PTR on error, a pointer to the newly allocated state otherwise
142  */
143 struct drm_atomic_state *
144 drm_kunit_helper_atomic_state_alloc(struct kunit *test,
145                                     struct drm_device *drm,
146                                     struct drm_modeset_acquire_ctx *ctx)
147 {
148         struct drm_atomic_state *state;
149         int ret;
150
151         state = drm_atomic_state_alloc(drm);
152         if (!state)
153                 return ERR_PTR(-ENOMEM);
154
155         ret = kunit_add_action_or_reset(test,
156                                         kunit_action_drm_atomic_state_put,
157                                         state);
158         if (ret)
159                 return ERR_PTR(ret);
160
161         state->acquire_ctx = ctx;
162
163         return state;
164 }
165 EXPORT_SYMBOL_GPL(drm_kunit_helper_atomic_state_alloc);
166
167 MODULE_AUTHOR("Maxime Ripard <maxime@cerno.tech>");
168 MODULE_LICENSE("GPL");