1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include <drm/drmP.h>
21#include <drm/drm_atomic.h>
22#include <drm/drm_crtc.h>
23#include <drm/drm_fb_helper.h>
24#include <drm/drm_crtc_helper.h>
25#include <drm/drm_gem_cma_helper.h>
26#include <drm/drm_fb_cma_helper.h>
27#include <linux/dma-buf.h>
28#include <linux/dma-mapping.h>
29#include <linux/module.h>
30#include <linux/reservation.h>
31
32#define DEFAULT_FBDEFIO_DELAY_MS 50
33
34struct drm_fb_cma {
35 struct drm_framebuffer fb;
36 struct drm_gem_cma_object *obj[4];
37};
38
39struct drm_fbdev_cma {
40 struct drm_fb_helper fb_helper;
41 struct drm_fb_cma *fb;
42 const struct drm_framebuffer_funcs *fb_funcs;
43};
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88static inline struct drm_fbdev_cma *to_fbdev_cma(struct drm_fb_helper *helper)
89{
90 return container_of(helper, struct drm_fbdev_cma, fb_helper);
91}
92
93static inline struct drm_fb_cma *to_fb_cma(struct drm_framebuffer *fb)
94{
95 return container_of(fb, struct drm_fb_cma, fb);
96}
97
98void drm_fb_cma_destroy(struct drm_framebuffer *fb)
99{
100 struct drm_fb_cma *fb_cma = to_fb_cma(fb);
101 int i;
102
103 for (i = 0; i < 4; i++) {
104 if (fb_cma->obj[i])
105 drm_gem_object_put_unlocked(&fb_cma->obj[i]->base);
106 }
107
108 drm_framebuffer_cleanup(fb);
109 kfree(fb_cma);
110}
111EXPORT_SYMBOL(drm_fb_cma_destroy);
112
113int drm_fb_cma_create_handle(struct drm_framebuffer *fb,
114 struct drm_file *file_priv, unsigned int *handle)
115{
116 struct drm_fb_cma *fb_cma = to_fb_cma(fb);
117
118 return drm_gem_handle_create(file_priv,
119 &fb_cma->obj[0]->base, handle);
120}
121EXPORT_SYMBOL(drm_fb_cma_create_handle);
122
123static struct drm_framebuffer_funcs drm_fb_cma_funcs = {
124 .destroy = drm_fb_cma_destroy,
125 .create_handle = drm_fb_cma_create_handle,
126};
127
128static struct drm_fb_cma *drm_fb_cma_alloc(struct drm_device *dev,
129 const struct drm_mode_fb_cmd2 *mode_cmd,
130 struct drm_gem_cma_object **obj,
131 unsigned int num_planes, const struct drm_framebuffer_funcs *funcs)
132{
133 struct drm_fb_cma *fb_cma;
134 int ret;
135 int i;
136
137 fb_cma = kzalloc(sizeof(*fb_cma), GFP_KERNEL);
138 if (!fb_cma)
139 return ERR_PTR(-ENOMEM);
140
141 drm_helper_mode_fill_fb_struct(dev, &fb_cma->fb, mode_cmd);
142
143 for (i = 0; i < num_planes; i++)
144 fb_cma->obj[i] = obj[i];
145
146 ret = drm_framebuffer_init(dev, &fb_cma->fb, funcs);
147 if (ret) {
148 dev_err(dev->dev, "Failed to initialize framebuffer: %d\n", ret);
149 kfree(fb_cma);
150 return ERR_PTR(ret);
151 }
152
153 return fb_cma;
154}
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169struct drm_framebuffer *drm_fb_cma_create_with_funcs(struct drm_device *dev,
170 struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd,
171 const struct drm_framebuffer_funcs *funcs)
172{
173 const struct drm_format_info *info;
174 struct drm_fb_cma *fb_cma;
175 struct drm_gem_cma_object *objs[4];
176 struct drm_gem_object *obj;
177 int ret;
178 int i;
179
180 info = drm_get_format_info(dev, mode_cmd);
181 if (!info)
182 return ERR_PTR(-EINVAL);
183
184 for (i = 0; i < info->num_planes; i++) {
185 unsigned int width = mode_cmd->width / (i ? info->hsub : 1);
186 unsigned int height = mode_cmd->height / (i ? info->vsub : 1);
187 unsigned int min_size;
188
189 obj = drm_gem_object_lookup(file_priv, mode_cmd->handles[i]);
190 if (!obj) {
191 dev_err(dev->dev, "Failed to lookup GEM object\n");
192 ret = -ENXIO;
193 goto err_gem_object_put;
194 }
195
196 min_size = (height - 1) * mode_cmd->pitches[i]
197 + width * info->cpp[i]
198 + mode_cmd->offsets[i];
199
200 if (obj->size < min_size) {
201 drm_gem_object_put_unlocked(obj);
202 ret = -EINVAL;
203 goto err_gem_object_put;
204 }
205 objs[i] = to_drm_gem_cma_obj(obj);
206 }
207
208 fb_cma = drm_fb_cma_alloc(dev, mode_cmd, objs, i, funcs);
209 if (IS_ERR(fb_cma)) {
210 ret = PTR_ERR(fb_cma);
211 goto err_gem_object_put;
212 }
213
214 return &fb_cma->fb;
215
216err_gem_object_put:
217 for (i--; i >= 0; i--)
218 drm_gem_object_put_unlocked(&objs[i]->base);
219 return ERR_PTR(ret);
220}
221EXPORT_SYMBOL_GPL(drm_fb_cma_create_with_funcs);
222
223
224
225
226
227
228
229
230
231
232
233struct drm_framebuffer *drm_fb_cma_create(struct drm_device *dev,
234 struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd)
235{
236 return drm_fb_cma_create_with_funcs(dev, file_priv, mode_cmd,
237 &drm_fb_cma_funcs);
238}
239EXPORT_SYMBOL_GPL(drm_fb_cma_create);
240
241
242
243
244
245
246
247
248
249
250struct drm_gem_cma_object *drm_fb_cma_get_gem_obj(struct drm_framebuffer *fb,
251 unsigned int plane)
252{
253 struct drm_fb_cma *fb_cma = to_fb_cma(fb);
254
255 if (plane >= 4)
256 return NULL;
257
258 return fb_cma->obj[plane];
259}
260EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_obj);
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275int drm_fb_cma_prepare_fb(struct drm_plane *plane,
276 struct drm_plane_state *state)
277{
278 struct dma_buf *dma_buf;
279 struct dma_fence *fence;
280
281 if ((plane->state->fb == state->fb) || !state->fb)
282 return 0;
283
284 dma_buf = drm_fb_cma_get_gem_obj(state->fb, 0)->base.dma_buf;
285 if (dma_buf) {
286 fence = reservation_object_get_excl_rcu(dma_buf->resv);
287 drm_atomic_set_fence_for_plane(state, fence);
288 }
289
290 return 0;
291}
292EXPORT_SYMBOL_GPL(drm_fb_cma_prepare_fb);
293
294#ifdef CONFIG_DEBUG_FS
295static void drm_fb_cma_describe(struct drm_framebuffer *fb, struct seq_file *m)
296{
297 struct drm_fb_cma *fb_cma = to_fb_cma(fb);
298 int i;
299
300 seq_printf(m, "fb: %dx%d@%4.4s\n", fb->width, fb->height,
301 (char *)&fb->format->format);
302
303 for (i = 0; i < fb->format->num_planes; i++) {
304 seq_printf(m, " %d: offset=%d pitch=%d, obj: ",
305 i, fb->offsets[i], fb->pitches[i]);
306 drm_gem_cma_describe(fb_cma->obj[i], m);
307 }
308}
309
310
311
312
313
314
315
316int drm_fb_cma_debugfs_show(struct seq_file *m, void *arg)
317{
318 struct drm_info_node *node = (struct drm_info_node *) m->private;
319 struct drm_device *dev = node->minor->dev;
320 struct drm_framebuffer *fb;
321
322 mutex_lock(&dev->mode_config.fb_lock);
323 drm_for_each_fb(fb, dev)
324 drm_fb_cma_describe(fb, m);
325 mutex_unlock(&dev->mode_config.fb_lock);
326
327 return 0;
328}
329EXPORT_SYMBOL_GPL(drm_fb_cma_debugfs_show);
330#endif
331
332static int drm_fb_cma_mmap(struct fb_info *info, struct vm_area_struct *vma)
333{
334 return dma_mmap_writecombine(info->device, vma, info->screen_base,
335 info->fix.smem_start, info->fix.smem_len);
336}
337
338static struct fb_ops drm_fbdev_cma_ops = {
339 .owner = THIS_MODULE,
340 DRM_FB_HELPER_DEFAULT_OPS,
341 .fb_fillrect = drm_fb_helper_sys_fillrect,
342 .fb_copyarea = drm_fb_helper_sys_copyarea,
343 .fb_imageblit = drm_fb_helper_sys_imageblit,
344 .fb_mmap = drm_fb_cma_mmap,
345};
346
347static int drm_fbdev_cma_deferred_io_mmap(struct fb_info *info,
348 struct vm_area_struct *vma)
349{
350 fb_deferred_io_mmap(info, vma);
351 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
352
353 return 0;
354}
355
356static int drm_fbdev_cma_defio_init(struct fb_info *fbi,
357 struct drm_gem_cma_object *cma_obj)
358{
359 struct fb_deferred_io *fbdefio;
360 struct fb_ops *fbops;
361
362
363
364
365
366
367 fbdefio = kzalloc(sizeof(*fbdefio), GFP_KERNEL);
368 fbops = kzalloc(sizeof(*fbops), GFP_KERNEL);
369 if (!fbdefio || !fbops) {
370 kfree(fbdefio);
371 kfree(fbops);
372 return -ENOMEM;
373 }
374
375
376 fbi->screen_buffer = cma_obj->vaddr;
377
378 fbi->fix.smem_start = page_to_phys(virt_to_page(fbi->screen_buffer));
379
380 *fbops = *fbi->fbops;
381 fbi->fbops = fbops;
382
383 fbdefio->delay = msecs_to_jiffies(DEFAULT_FBDEFIO_DELAY_MS);
384 fbdefio->deferred_io = drm_fb_helper_deferred_io;
385 fbi->fbdefio = fbdefio;
386 fb_deferred_io_init(fbi);
387 fbi->fbops->fb_mmap = drm_fbdev_cma_deferred_io_mmap;
388
389 return 0;
390}
391
392static void drm_fbdev_cma_defio_fini(struct fb_info *fbi)
393{
394 if (!fbi->fbdefio)
395 return;
396
397 fb_deferred_io_cleanup(fbi);
398 kfree(fbi->fbdefio);
399 kfree(fbi->fbops);
400}
401
402static int
403drm_fbdev_cma_create(struct drm_fb_helper *helper,
404 struct drm_fb_helper_surface_size *sizes)
405{
406 struct drm_fbdev_cma *fbdev_cma = to_fbdev_cma(helper);
407 struct drm_mode_fb_cmd2 mode_cmd = { 0 };
408 struct drm_device *dev = helper->dev;
409 struct drm_gem_cma_object *obj;
410 struct drm_framebuffer *fb;
411 unsigned int bytes_per_pixel;
412 unsigned long offset;
413 struct fb_info *fbi;
414 size_t size;
415 int ret;
416
417 DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d)\n",
418 sizes->surface_width, sizes->surface_height,
419 sizes->surface_bpp);
420
421 bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8);
422
423 mode_cmd.width = sizes->surface_width;
424 mode_cmd.height = sizes->surface_height;
425 mode_cmd.pitches[0] = sizes->surface_width * bytes_per_pixel;
426 mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
427 sizes->surface_depth);
428
429 size = mode_cmd.pitches[0] * mode_cmd.height;
430 obj = drm_gem_cma_create(dev, size);
431 if (IS_ERR(obj))
432 return -ENOMEM;
433
434 fbi = drm_fb_helper_alloc_fbi(helper);
435 if (IS_ERR(fbi)) {
436 ret = PTR_ERR(fbi);
437 goto err_gem_free_object;
438 }
439
440 fbdev_cma->fb = drm_fb_cma_alloc(dev, &mode_cmd, &obj, 1,
441 fbdev_cma->fb_funcs);
442 if (IS_ERR(fbdev_cma->fb)) {
443 dev_err(dev->dev, "Failed to allocate DRM framebuffer.\n");
444 ret = PTR_ERR(fbdev_cma->fb);
445 goto err_fb_info_destroy;
446 }
447
448 fb = &fbdev_cma->fb->fb;
449 helper->fb = fb;
450
451 fbi->par = helper;
452 fbi->flags = FBINFO_FLAG_DEFAULT;
453 fbi->fbops = &drm_fbdev_cma_ops;
454
455 drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->format->depth);
456 drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height);
457
458 offset = fbi->var.xoffset * bytes_per_pixel;
459 offset += fbi->var.yoffset * fb->pitches[0];
460
461 dev->mode_config.fb_base = (resource_size_t)obj->paddr;
462 fbi->screen_base = obj->vaddr + offset;
463 fbi->fix.smem_start = (unsigned long)(obj->paddr + offset);
464 fbi->screen_size = size;
465 fbi->fix.smem_len = size;
466
467 if (fbdev_cma->fb_funcs->dirty) {
468 ret = drm_fbdev_cma_defio_init(fbi, obj);
469 if (ret)
470 goto err_cma_destroy;
471 }
472
473 return 0;
474
475err_cma_destroy:
476 drm_framebuffer_remove(&fbdev_cma->fb->fb);
477err_fb_info_destroy:
478 drm_fb_helper_fini(helper);
479err_gem_free_object:
480 drm_gem_object_put_unlocked(&obj->base);
481 return ret;
482}
483
484static const struct drm_fb_helper_funcs drm_fb_cma_helper_funcs = {
485 .fb_probe = drm_fbdev_cma_create,
486};
487
488
489
490
491
492
493
494
495
496
497struct drm_fbdev_cma *drm_fbdev_cma_init_with_funcs(struct drm_device *dev,
498 unsigned int preferred_bpp, unsigned int max_conn_count,
499 const struct drm_framebuffer_funcs *funcs)
500{
501 struct drm_fbdev_cma *fbdev_cma;
502 struct drm_fb_helper *helper;
503 int ret;
504
505 fbdev_cma = kzalloc(sizeof(*fbdev_cma), GFP_KERNEL);
506 if (!fbdev_cma) {
507 dev_err(dev->dev, "Failed to allocate drm fbdev.\n");
508 return ERR_PTR(-ENOMEM);
509 }
510 fbdev_cma->fb_funcs = funcs;
511
512 helper = &fbdev_cma->fb_helper;
513
514 drm_fb_helper_prepare(dev, helper, &drm_fb_cma_helper_funcs);
515
516 ret = drm_fb_helper_init(dev, helper, max_conn_count);
517 if (ret < 0) {
518 dev_err(dev->dev, "Failed to initialize drm fb helper.\n");
519 goto err_free;
520 }
521
522 ret = drm_fb_helper_single_add_all_connectors(helper);
523 if (ret < 0) {
524 dev_err(dev->dev, "Failed to add connectors.\n");
525 goto err_drm_fb_helper_fini;
526
527 }
528
529 ret = drm_fb_helper_initial_config(helper, preferred_bpp);
530 if (ret < 0) {
531 dev_err(dev->dev, "Failed to set initial hw configuration.\n");
532 goto err_drm_fb_helper_fini;
533 }
534
535 return fbdev_cma;
536
537err_drm_fb_helper_fini:
538 drm_fb_helper_fini(helper);
539err_free:
540 kfree(fbdev_cma);
541
542 return ERR_PTR(ret);
543}
544EXPORT_SYMBOL_GPL(drm_fbdev_cma_init_with_funcs);
545
546
547
548
549
550
551
552
553
554struct drm_fbdev_cma *drm_fbdev_cma_init(struct drm_device *dev,
555 unsigned int preferred_bpp, unsigned int max_conn_count)
556{
557 return drm_fbdev_cma_init_with_funcs(dev, preferred_bpp,
558 max_conn_count,
559 &drm_fb_cma_funcs);
560}
561EXPORT_SYMBOL_GPL(drm_fbdev_cma_init);
562
563
564
565
566
567void drm_fbdev_cma_fini(struct drm_fbdev_cma *fbdev_cma)
568{
569 drm_fb_helper_unregister_fbi(&fbdev_cma->fb_helper);
570 if (fbdev_cma->fb_helper.fbdev)
571 drm_fbdev_cma_defio_fini(fbdev_cma->fb_helper.fbdev);
572
573 if (fbdev_cma->fb)
574 drm_framebuffer_remove(&fbdev_cma->fb->fb);
575
576 drm_fb_helper_fini(&fbdev_cma->fb_helper);
577 kfree(fbdev_cma);
578}
579EXPORT_SYMBOL_GPL(drm_fbdev_cma_fini);
580
581
582
583
584
585
586
587void drm_fbdev_cma_restore_mode(struct drm_fbdev_cma *fbdev_cma)
588{
589 if (fbdev_cma)
590 drm_fb_helper_restore_fbdev_mode_unlocked(&fbdev_cma->fb_helper);
591}
592EXPORT_SYMBOL_GPL(drm_fbdev_cma_restore_mode);
593
594
595
596
597
598
599
600
601void drm_fbdev_cma_hotplug_event(struct drm_fbdev_cma *fbdev_cma)
602{
603 if (fbdev_cma)
604 drm_fb_helper_hotplug_event(&fbdev_cma->fb_helper);
605}
606EXPORT_SYMBOL_GPL(drm_fbdev_cma_hotplug_event);
607
608
609
610
611
612
613
614
615
616void drm_fbdev_cma_set_suspend(struct drm_fbdev_cma *fbdev_cma, int state)
617{
618 if (fbdev_cma)
619 drm_fb_helper_set_suspend(&fbdev_cma->fb_helper, state);
620}
621EXPORT_SYMBOL(drm_fbdev_cma_set_suspend);
622
623
624
625
626
627
628
629
630
631
632void drm_fbdev_cma_set_suspend_unlocked(struct drm_fbdev_cma *fbdev_cma,
633 int state)
634{
635 if (fbdev_cma)
636 drm_fb_helper_set_suspend_unlocked(&fbdev_cma->fb_helper,
637 state);
638}
639EXPORT_SYMBOL(drm_fbdev_cma_set_suspend_unlocked);
640