1
2
3
4
5
6
7
8
9
10#include <drm/drm_atomic.h>
11#include <drm/drm_atomic_helper.h>
12#include <drm/drm_crtc_helper.h>
13#include <drm/tinydrm/tinydrm.h>
14#include <linux/device.h>
15#include <linux/dma-buf.h>
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45void tinydrm_lastclose(struct drm_device *drm)
46{
47 struct tinydrm_device *tdev = drm->dev_private;
48
49 DRM_DEBUG_KMS("\n");
50 drm_fbdev_cma_restore_mode(tdev->fbdev_cma);
51}
52EXPORT_SYMBOL(tinydrm_lastclose);
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72struct drm_gem_object *
73tinydrm_gem_cma_prime_import_sg_table(struct drm_device *drm,
74 struct dma_buf_attachment *attach,
75 struct sg_table *sgt)
76{
77 struct drm_gem_cma_object *cma_obj;
78 struct drm_gem_object *obj;
79 void *vaddr;
80
81 vaddr = dma_buf_vmap(attach->dmabuf);
82 if (!vaddr) {
83 DRM_ERROR("Failed to vmap PRIME buffer\n");
84 return ERR_PTR(-ENOMEM);
85 }
86
87 obj = drm_gem_cma_prime_import_sg_table(drm, attach, sgt);
88 if (IS_ERR(obj)) {
89 dma_buf_vunmap(attach->dmabuf, vaddr);
90 return obj;
91 }
92
93 cma_obj = to_drm_gem_cma_obj(obj);
94 cma_obj->vaddr = vaddr;
95
96 return obj;
97}
98EXPORT_SYMBOL(tinydrm_gem_cma_prime_import_sg_table);
99
100
101
102
103
104
105
106
107
108
109
110
111void tinydrm_gem_cma_free_object(struct drm_gem_object *gem_obj)
112{
113 if (gem_obj->import_attach) {
114 struct drm_gem_cma_object *cma_obj;
115
116 cma_obj = to_drm_gem_cma_obj(gem_obj);
117 dma_buf_vunmap(gem_obj->import_attach->dmabuf, cma_obj->vaddr);
118 cma_obj->vaddr = NULL;
119 }
120
121 drm_gem_cma_free_object(gem_obj);
122}
123EXPORT_SYMBOL_GPL(tinydrm_gem_cma_free_object);
124
125static struct drm_framebuffer *
126tinydrm_fb_create(struct drm_device *drm, struct drm_file *file_priv,
127 const struct drm_mode_fb_cmd2 *mode_cmd)
128{
129 struct tinydrm_device *tdev = drm->dev_private;
130
131 return drm_fb_cma_create_with_funcs(drm, file_priv, mode_cmd,
132 tdev->fb_funcs);
133}
134
135static const struct drm_mode_config_funcs tinydrm_mode_config_funcs = {
136 .fb_create = tinydrm_fb_create,
137 .atomic_check = drm_atomic_helper_check,
138 .atomic_commit = drm_atomic_helper_commit,
139};
140
141static int tinydrm_init(struct device *parent, struct tinydrm_device *tdev,
142 const struct drm_framebuffer_funcs *fb_funcs,
143 struct drm_driver *driver)
144{
145 struct drm_device *drm;
146
147 mutex_init(&tdev->dirty_lock);
148 tdev->fb_funcs = fb_funcs;
149
150
151
152
153
154
155
156 drm = drm_dev_alloc(driver, parent);
157 if (IS_ERR(drm))
158 return PTR_ERR(drm);
159
160 tdev->drm = drm;
161 drm->dev_private = tdev;
162 drm_mode_config_init(drm);
163 drm->mode_config.funcs = &tinydrm_mode_config_funcs;
164
165 return 0;
166}
167
168static void tinydrm_fini(struct tinydrm_device *tdev)
169{
170 drm_mode_config_cleanup(tdev->drm);
171 mutex_destroy(&tdev->dirty_lock);
172 tdev->drm->dev_private = NULL;
173 drm_dev_unref(tdev->drm);
174}
175
176static void devm_tinydrm_release(void *data)
177{
178 tinydrm_fini(data);
179}
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195int devm_tinydrm_init(struct device *parent, struct tinydrm_device *tdev,
196 const struct drm_framebuffer_funcs *fb_funcs,
197 struct drm_driver *driver)
198{
199 int ret;
200
201 ret = tinydrm_init(parent, tdev, fb_funcs, driver);
202 if (ret)
203 return ret;
204
205 ret = devm_add_action(parent, devm_tinydrm_release, tdev);
206 if (ret)
207 tinydrm_fini(tdev);
208
209 return ret;
210}
211EXPORT_SYMBOL(devm_tinydrm_init);
212
213static int tinydrm_register(struct tinydrm_device *tdev)
214{
215 struct drm_device *drm = tdev->drm;
216 int bpp = drm->mode_config.preferred_depth;
217 struct drm_fbdev_cma *fbdev;
218 int ret;
219
220 ret = drm_dev_register(tdev->drm, 0);
221 if (ret)
222 return ret;
223
224 fbdev = drm_fbdev_cma_init_with_funcs(drm, bpp ? bpp : 32,
225 drm->mode_config.num_connector,
226 tdev->fb_funcs);
227 if (IS_ERR(fbdev))
228 DRM_ERROR("Failed to initialize fbdev: %ld\n", PTR_ERR(fbdev));
229 else
230 tdev->fbdev_cma = fbdev;
231
232 return 0;
233}
234
235static void tinydrm_unregister(struct tinydrm_device *tdev)
236{
237 struct drm_fbdev_cma *fbdev_cma = tdev->fbdev_cma;
238
239 drm_atomic_helper_shutdown(tdev->drm);
240
241 tdev->fbdev_cma = NULL;
242 drm_dev_unregister(tdev->drm);
243 if (fbdev_cma)
244 drm_fbdev_cma_fini(fbdev_cma);
245}
246
247static void devm_tinydrm_register_release(void *data)
248{
249 tinydrm_unregister(data);
250}
251
252
253
254
255
256
257
258
259
260
261
262
263int devm_tinydrm_register(struct tinydrm_device *tdev)
264{
265 struct device *dev = tdev->drm->dev;
266 int ret;
267
268 ret = tinydrm_register(tdev);
269 if (ret)
270 return ret;
271
272 ret = devm_add_action(dev, devm_tinydrm_register_release, tdev);
273 if (ret)
274 tinydrm_unregister(tdev);
275
276 return ret;
277}
278EXPORT_SYMBOL(devm_tinydrm_register);
279
280
281
282
283
284
285
286
287
288void tinydrm_shutdown(struct tinydrm_device *tdev)
289{
290 drm_atomic_helper_shutdown(tdev->drm);
291}
292EXPORT_SYMBOL(tinydrm_shutdown);
293
294
295
296
297
298
299
300
301
302
303
304
305int tinydrm_suspend(struct tinydrm_device *tdev)
306{
307 struct drm_atomic_state *state;
308
309 if (tdev->suspend_state) {
310 DRM_ERROR("Failed to suspend: state already set\n");
311 return -EINVAL;
312 }
313
314 drm_fbdev_cma_set_suspend_unlocked(tdev->fbdev_cma, 1);
315 state = drm_atomic_helper_suspend(tdev->drm);
316 if (IS_ERR(state)) {
317 drm_fbdev_cma_set_suspend_unlocked(tdev->fbdev_cma, 0);
318 return PTR_ERR(state);
319 }
320
321 tdev->suspend_state = state;
322
323 return 0;
324}
325EXPORT_SYMBOL(tinydrm_suspend);
326
327
328
329
330
331
332
333
334
335
336
337int tinydrm_resume(struct tinydrm_device *tdev)
338{
339 struct drm_atomic_state *state = tdev->suspend_state;
340 int ret;
341
342 if (!state) {
343 DRM_ERROR("Failed to resume: state is not set\n");
344 return -EINVAL;
345 }
346
347 tdev->suspend_state = NULL;
348
349 ret = drm_atomic_helper_resume(tdev->drm, state);
350 if (ret) {
351 DRM_ERROR("Error resuming state: %d\n", ret);
352 return ret;
353 }
354
355 drm_fbdev_cma_set_suspend_unlocked(tdev->fbdev_cma, 0);
356
357 return 0;
358}
359EXPORT_SYMBOL(tinydrm_resume);
360
361MODULE_LICENSE("GPL");
362