1
2
3
4
5
6#include <drm/drmP.h>
7#include <drm/drm_modeset_helper.h>
8#include <drm/drm_fb_helper.h>
9#include <drm/drm_gem.h>
10#include <drm/drm_gem_framebuffer_helper.h>
11#include <linux/dma-buf.h>
12#include <linux/reservation.h>
13
14#include "mtk_drm_drv.h"
15#include "mtk_drm_fb.h"
16#include "mtk_drm_gem.h"
17
18static const struct drm_framebuffer_funcs mtk_drm_fb_funcs = {
19 .create_handle = drm_gem_fb_create_handle,
20 .destroy = drm_gem_fb_destroy,
21};
22
23static struct drm_framebuffer *mtk_drm_framebuffer_init(struct drm_device *dev,
24 const struct drm_mode_fb_cmd2 *mode,
25 struct drm_gem_object *obj)
26{
27 const struct drm_format_info *info = drm_get_format_info(dev, mode);
28 struct drm_framebuffer *fb;
29 int ret;
30
31 if (info->num_planes != 1)
32 return ERR_PTR(-EINVAL);
33
34 fb = kzalloc(sizeof(*fb), GFP_KERNEL);
35 if (!fb)
36 return ERR_PTR(-ENOMEM);
37
38 drm_helper_mode_fill_fb_struct(dev, fb, mode);
39
40 fb->obj[0] = obj;
41
42 ret = drm_framebuffer_init(dev, fb, &mtk_drm_fb_funcs);
43 if (ret) {
44 DRM_ERROR("failed to initialize framebuffer\n");
45 kfree(fb);
46 return ERR_PTR(ret);
47 }
48
49 return fb;
50}
51
52
53
54
55
56
57int mtk_fb_wait(struct drm_framebuffer *fb)
58{
59 struct drm_gem_object *gem;
60 struct reservation_object *resv;
61 long ret;
62
63 if (!fb)
64 return 0;
65
66 gem = fb->obj[0];
67 if (!gem || !gem->dma_buf || !gem->dma_buf->resv)
68 return 0;
69
70 resv = gem->dma_buf->resv;
71 ret = reservation_object_wait_timeout_rcu(resv, false, true,
72 MAX_SCHEDULE_TIMEOUT);
73
74 if (WARN_ON(ret < 0))
75 return ret;
76
77 return 0;
78}
79
80struct drm_framebuffer *mtk_drm_mode_fb_create(struct drm_device *dev,
81 struct drm_file *file,
82 const struct drm_mode_fb_cmd2 *cmd)
83{
84 const struct drm_format_info *info = drm_get_format_info(dev, cmd);
85 struct drm_framebuffer *fb;
86 struct drm_gem_object *gem;
87 unsigned int width = cmd->width;
88 unsigned int height = cmd->height;
89 unsigned int size, bpp;
90 int ret;
91
92 if (info->num_planes != 1)
93 return ERR_PTR(-EINVAL);
94
95 gem = drm_gem_object_lookup(file, cmd->handles[0]);
96 if (!gem)
97 return ERR_PTR(-ENOENT);
98
99 bpp = info->cpp[0];
100 size = (height - 1) * cmd->pitches[0] + width * bpp;
101 size += cmd->offsets[0];
102
103 if (gem->size < size) {
104 ret = -EINVAL;
105 goto unreference;
106 }
107
108 fb = mtk_drm_framebuffer_init(dev, cmd, gem);
109 if (IS_ERR(fb)) {
110 ret = PTR_ERR(fb);
111 goto unreference;
112 }
113
114 return fb;
115
116unreference:
117 drm_gem_object_put_unlocked(gem);
118 return ERR_PTR(ret);
119}
120