Merge tag 'iwlwifi-next-for-kalle-2016-07-01' of git://git.kernel.org/pub/scm/linux...
[deliverable/linux.git] / drivers / gpu / drm / mediatek / mtk_drm_fb.c
1 /*
2 * Copyright (c) 2015 MediaTek Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14 #include <drm/drmP.h>
15 #include <drm/drm_crtc_helper.h>
16 #include <drm/drm_fb_helper.h>
17 #include <drm/drm_gem.h>
18 #include <linux/dma-buf.h>
19 #include <linux/reservation.h>
20
21 #include "mtk_drm_drv.h"
22 #include "mtk_drm_fb.h"
23 #include "mtk_drm_gem.h"
24
25 /*
26 * mtk specific framebuffer structure.
27 *
28 * @fb: drm framebuffer object.
29 * @gem_obj: array of gem objects.
30 */
31 struct mtk_drm_fb {
32 struct drm_framebuffer base;
33 /* For now we only support a single plane */
34 struct drm_gem_object *gem_obj;
35 };
36
37 #define to_mtk_fb(x) container_of(x, struct mtk_drm_fb, base)
38
39 struct drm_gem_object *mtk_fb_get_gem_obj(struct drm_framebuffer *fb)
40 {
41 struct mtk_drm_fb *mtk_fb = to_mtk_fb(fb);
42
43 return mtk_fb->gem_obj;
44 }
45
46 static int mtk_drm_fb_create_handle(struct drm_framebuffer *fb,
47 struct drm_file *file_priv,
48 unsigned int *handle)
49 {
50 struct mtk_drm_fb *mtk_fb = to_mtk_fb(fb);
51
52 return drm_gem_handle_create(file_priv, mtk_fb->gem_obj, handle);
53 }
54
55 static void mtk_drm_fb_destroy(struct drm_framebuffer *fb)
56 {
57 struct mtk_drm_fb *mtk_fb = to_mtk_fb(fb);
58
59 drm_framebuffer_cleanup(fb);
60
61 drm_gem_object_unreference_unlocked(mtk_fb->gem_obj);
62
63 kfree(mtk_fb);
64 }
65
66 static const struct drm_framebuffer_funcs mtk_drm_fb_funcs = {
67 .create_handle = mtk_drm_fb_create_handle,
68 .destroy = mtk_drm_fb_destroy,
69 };
70
71 static struct mtk_drm_fb *mtk_drm_framebuffer_init(struct drm_device *dev,
72 const struct drm_mode_fb_cmd2 *mode,
73 struct drm_gem_object *obj)
74 {
75 struct mtk_drm_fb *mtk_fb;
76 int ret;
77
78 if (drm_format_num_planes(mode->pixel_format) != 1)
79 return ERR_PTR(-EINVAL);
80
81 mtk_fb = kzalloc(sizeof(*mtk_fb), GFP_KERNEL);
82 if (!mtk_fb)
83 return ERR_PTR(-ENOMEM);
84
85 drm_helper_mode_fill_fb_struct(&mtk_fb->base, mode);
86
87 mtk_fb->gem_obj = obj;
88
89 ret = drm_framebuffer_init(dev, &mtk_fb->base, &mtk_drm_fb_funcs);
90 if (ret) {
91 DRM_ERROR("failed to initialize framebuffer\n");
92 kfree(mtk_fb);
93 return ERR_PTR(ret);
94 }
95
96 return mtk_fb;
97 }
98
99 /*
100 * Wait for any exclusive fence in fb's gem object's reservation object.
101 *
102 * Returns -ERESTARTSYS if interrupted, else 0.
103 */
104 int mtk_fb_wait(struct drm_framebuffer *fb)
105 {
106 struct drm_gem_object *gem;
107 struct reservation_object *resv;
108 long ret;
109
110 if (!fb)
111 return 0;
112
113 gem = mtk_fb_get_gem_obj(fb);
114 if (!gem || !gem->dma_buf || !gem->dma_buf->resv)
115 return 0;
116
117 resv = gem->dma_buf->resv;
118 ret = reservation_object_wait_timeout_rcu(resv, false, true,
119 MAX_SCHEDULE_TIMEOUT);
120 /* MAX_SCHEDULE_TIMEOUT on success, -ERESTARTSYS if interrupted */
121 if (WARN_ON(ret < 0))
122 return ret;
123
124 return 0;
125 }
126
127 struct drm_framebuffer *mtk_drm_mode_fb_create(struct drm_device *dev,
128 struct drm_file *file,
129 const struct drm_mode_fb_cmd2 *cmd)
130 {
131 struct mtk_drm_fb *mtk_fb;
132 struct drm_gem_object *gem;
133 unsigned int width = cmd->width;
134 unsigned int height = cmd->height;
135 unsigned int size, bpp;
136 int ret;
137
138 if (drm_format_num_planes(cmd->pixel_format) != 1)
139 return ERR_PTR(-EINVAL);
140
141 gem = drm_gem_object_lookup(file, cmd->handles[0]);
142 if (!gem)
143 return ERR_PTR(-ENOENT);
144
145 bpp = drm_format_plane_cpp(cmd->pixel_format, 0);
146 size = (height - 1) * cmd->pitches[0] + width * bpp;
147 size += cmd->offsets[0];
148
149 if (gem->size < size) {
150 ret = -EINVAL;
151 goto unreference;
152 }
153
154 mtk_fb = mtk_drm_framebuffer_init(dev, cmd, gem);
155 if (IS_ERR(mtk_fb)) {
156 ret = PTR_ERR(mtk_fb);
157 goto unreference;
158 }
159
160 return &mtk_fb->base;
161
162 unreference:
163 drm_gem_object_unreference_unlocked(gem);
164 return ERR_PTR(ret);
165 }
This page took 0.052833 seconds and 6 git commands to generate.