blob: 5426cc5a5e8d53b30409a980aa5e8878a30e7c83 [file] [log] [blame]
Inki Dae1c248b72011-10-04 19:19:01 +09001/* exynos_drm_fb.c
2 *
3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4 * Authors:
5 * Inki Dae <inki.dae@samsung.com>
6 * Joonyoung Shim <jy0922.shim@samsung.com>
7 * Seung-Woo Kim <sw0312.kim@samsung.com>
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice (including the next
17 * paragraph) shall be included in all copies or substantial portions of the
18 * Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
24 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 * OTHER DEALINGS IN THE SOFTWARE.
27 */
28
David Howells760285e2012-10-02 18:01:07 +010029#include <drm/drmP.h>
30#include <drm/drm_crtc.h>
31#include <drm/drm_crtc_helper.h>
32#include <drm/drm_fb_helper.h>
Inki Dae0519f9a2012-10-20 07:53:42 -070033#include <uapi/drm/exynos_drm.h>
Inki Dae1c248b72011-10-04 19:19:01 +090034
Seung-Woo Kim7db3eba2011-10-18 16:58:05 +090035#include "exynos_drm_drv.h"
Inki Dae1c248b72011-10-04 19:19:01 +090036#include "exynos_drm_fb.h"
Inki Dae1c248b72011-10-04 19:19:01 +090037#include "exynos_drm_gem.h"
Inki Dae0519f9a2012-10-20 07:53:42 -070038#include "exynos_drm_iommu.h"
Inki Dae1daa8922012-11-22 17:41:23 +090039#include "exynos_drm_encoder.h"
Inki Dae1c248b72011-10-04 19:19:01 +090040
41#define to_exynos_fb(x) container_of(x, struct exynos_drm_fb, fb)
42
43/*
44 * exynos specific framebuffer structure.
45 *
46 * @fb: drm framebuffer obejct.
Inki Dae01ed8122012-08-20 20:05:56 +090047 * @buf_cnt: a buffer count to drm framebuffer.
Seung-Woo Kim229d3532011-12-15 14:36:22 +090048 * @exynos_gem_obj: array of exynos specific gem object containing a gem object.
Inki Dae1c248b72011-10-04 19:19:01 +090049 */
50struct exynos_drm_fb {
51 struct drm_framebuffer fb;
Inki Dae01ed8122012-08-20 20:05:56 +090052 unsigned int buf_cnt;
Seung-Woo Kim229d3532011-12-15 14:36:22 +090053 struct exynos_drm_gem_obj *exynos_gem_obj[MAX_FB_BUFFER];
Inki Dae1c248b72011-10-04 19:19:01 +090054};
55
Inki Dae0519f9a2012-10-20 07:53:42 -070056static int check_fb_gem_memory_type(struct drm_device *drm_dev,
57 struct exynos_drm_gem_obj *exynos_gem_obj)
58{
59 unsigned int flags;
60
61 /*
62 * if exynos drm driver supports iommu then framebuffer can use
63 * all the buffer types.
64 */
65 if (is_drm_iommu_supported(drm_dev))
66 return 0;
67
68 flags = exynos_gem_obj->flags;
69
70 /*
71 * without iommu support, not support physically non-continuous memory
72 * for framebuffer.
73 */
74 if (IS_NONCONTIG_BUFFER(flags)) {
75 DRM_ERROR("cannot use this gem memory type for fb.\n");
76 return -EINVAL;
77 }
78
79 return 0;
80}
81
Inki Dae1c248b72011-10-04 19:19:01 +090082static void exynos_drm_fb_destroy(struct drm_framebuffer *fb)
83{
84 struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb);
Laurent Pinchart07b68352012-05-16 17:08:56 +020085 unsigned int i;
Inki Dae1c248b72011-10-04 19:19:01 +090086
87 DRM_DEBUG_KMS("%s\n", __FILE__);
88
Inki Dae1daa8922012-11-22 17:41:23 +090089 /* make sure that overlay data are updated before relesing fb. */
90 exynos_drm_encoder_complete_scanout(fb);
91
Inki Dae1c248b72011-10-04 19:19:01 +090092 drm_framebuffer_cleanup(fb);
93
Laurent Pinchart07b68352012-05-16 17:08:56 +020094 for (i = 0; i < ARRAY_SIZE(exynos_fb->exynos_gem_obj); i++) {
95 struct drm_gem_object *obj;
96
97 if (exynos_fb->exynos_gem_obj[i] == NULL)
98 continue;
99
100 obj = &exynos_fb->exynos_gem_obj[i]->base;
101 drm_gem_object_unreference_unlocked(obj);
102 }
103
Inki Dae1c248b72011-10-04 19:19:01 +0900104 kfree(exynos_fb);
105 exynos_fb = NULL;
106}
107
108static int exynos_drm_fb_create_handle(struct drm_framebuffer *fb,
109 struct drm_file *file_priv,
110 unsigned int *handle)
111{
112 struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb);
113
114 DRM_DEBUG_KMS("%s\n", __FILE__);
115
116 return drm_gem_handle_create(file_priv,
Seung-Woo Kim229d3532011-12-15 14:36:22 +0900117 &exynos_fb->exynos_gem_obj[0]->base, handle);
Inki Dae1c248b72011-10-04 19:19:01 +0900118}
119
120static int exynos_drm_fb_dirty(struct drm_framebuffer *fb,
121 struct drm_file *file_priv, unsigned flags,
122 unsigned color, struct drm_clip_rect *clips,
123 unsigned num_clips)
124{
125 DRM_DEBUG_KMS("%s\n", __FILE__);
126
127 /* TODO */
128
129 return 0;
130}
131
132static struct drm_framebuffer_funcs exynos_drm_fb_funcs = {
133 .destroy = exynos_drm_fb_destroy,
134 .create_handle = exynos_drm_fb_create_handle,
135 .dirty = exynos_drm_fb_dirty,
136};
137
Inki Dae01ed8122012-08-20 20:05:56 +0900138void exynos_drm_fb_set_buf_cnt(struct drm_framebuffer *fb,
139 unsigned int cnt)
140{
141 struct exynos_drm_fb *exynos_fb;
142
143 exynos_fb = to_exynos_fb(fb);
144
145 exynos_fb->buf_cnt = cnt;
146}
147
148unsigned int exynos_drm_fb_get_buf_cnt(struct drm_framebuffer *fb)
149{
150 struct exynos_drm_fb *exynos_fb;
151
152 exynos_fb = to_exynos_fb(fb);
153
154 return exynos_fb->buf_cnt;
155}
156
Joonyoung Shime1533c02011-12-13 14:46:57 +0900157struct drm_framebuffer *
158exynos_drm_framebuffer_init(struct drm_device *dev,
159 struct drm_mode_fb_cmd2 *mode_cmd,
160 struct drm_gem_object *obj)
Inki Dae1c248b72011-10-04 19:19:01 +0900161{
162 struct exynos_drm_fb *exynos_fb;
Inki Dae0519f9a2012-10-20 07:53:42 -0700163 struct exynos_drm_gem_obj *exynos_gem_obj;
Inki Dae1c248b72011-10-04 19:19:01 +0900164 int ret;
165
Inki Dae0519f9a2012-10-20 07:53:42 -0700166 exynos_gem_obj = to_exynos_gem_obj(obj);
167
168 ret = check_fb_gem_memory_type(dev, exynos_gem_obj);
169 if (ret < 0) {
170 DRM_ERROR("cannot use this gem memory type for fb.\n");
171 return ERR_PTR(-EINVAL);
172 }
173
Inki Dae1c248b72011-10-04 19:19:01 +0900174 exynos_fb = kzalloc(sizeof(*exynos_fb), GFP_KERNEL);
175 if (!exynos_fb) {
Joonyoung Shime1533c02011-12-13 14:46:57 +0900176 DRM_ERROR("failed to allocate exynos drm framebuffer\n");
Inki Dae1c248b72011-10-04 19:19:01 +0900177 return ERR_PTR(-ENOMEM);
178 }
179
Daniel Vetterf2c00952012-12-14 13:39:03 +0900180 drm_helper_mode_fill_fb_struct(&exynos_fb->fb, mode_cmd);
Inki Dae0519f9a2012-10-20 07:53:42 -0700181 exynos_fb->exynos_gem_obj[0] = exynos_gem_obj;
182
Joonyoung Shime1533c02011-12-13 14:46:57 +0900183 ret = drm_framebuffer_init(dev, &exynos_fb->fb, &exynos_drm_fb_funcs);
Inki Dae1c248b72011-10-04 19:19:01 +0900184 if (ret) {
Joonyoung Shime1533c02011-12-13 14:46:57 +0900185 DRM_ERROR("failed to initialize framebuffer\n");
186 return ERR_PTR(ret);
Inki Dae1c248b72011-10-04 19:19:01 +0900187 }
188
Joonyoung Shime1533c02011-12-13 14:46:57 +0900189 return &exynos_fb->fb;
Inki Dae1c248b72011-10-04 19:19:01 +0900190}
191
Inki Dae01ed8122012-08-20 20:05:56 +0900192static u32 exynos_drm_format_num_buffers(struct drm_mode_fb_cmd2 *mode_cmd)
193{
194 unsigned int cnt = 0;
195
196 if (mode_cmd->pixel_format != DRM_FORMAT_NV12)
197 return drm_format_num_planes(mode_cmd->pixel_format);
198
199 while (cnt != MAX_FB_BUFFER) {
200 if (!mode_cmd->handles[cnt])
201 break;
202 cnt++;
203 }
204
205 /*
206 * check if NV12 or NV12M.
207 *
208 * NV12
209 * handles[0] = base1, offsets[0] = 0
210 * handles[1] = base1, offsets[1] = Y_size
211 *
212 * NV12M
213 * handles[0] = base1, offsets[0] = 0
214 * handles[1] = base2, offsets[1] = 0
215 */
216 if (cnt == 2) {
217 /*
218 * in case of NV12 format, offsets[1] is not 0 and
219 * handles[0] is same as handles[1].
220 */
221 if (mode_cmd->offsets[1] &&
222 mode_cmd->handles[0] == mode_cmd->handles[1])
223 cnt = 1;
224 }
225
226 return cnt;
227}
228
Joonyoung Shime1533c02011-12-13 14:46:57 +0900229static struct drm_framebuffer *
230exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
231 struct drm_mode_fb_cmd2 *mode_cmd)
Inki Dae1c248b72011-10-04 19:19:01 +0900232{
Joonyoung Shime1533c02011-12-13 14:46:57 +0900233 struct drm_gem_object *obj;
Seung-Woo Kim229d3532011-12-15 14:36:22 +0900234 struct exynos_drm_fb *exynos_fb;
Daniel Vetterf2c00952012-12-14 13:39:03 +0900235 int i, ret;
Joonyoung Shime1533c02011-12-13 14:46:57 +0900236
Inki Dae1c248b72011-10-04 19:19:01 +0900237 DRM_DEBUG_KMS("%s\n", __FILE__);
238
Joonyoung Shime1533c02011-12-13 14:46:57 +0900239 obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]);
240 if (!obj) {
241 DRM_ERROR("failed to lookup gem object\n");
242 return ERR_PTR(-ENOENT);
243 }
244
Daniel Vetterf2c00952012-12-14 13:39:03 +0900245 exynos_fb = kzalloc(sizeof(*exynos_fb), GFP_KERNEL);
246 if (!exynos_fb) {
247 DRM_ERROR("failed to allocate exynos drm framebuffer\n");
248 return ERR_PTR(-ENOMEM);
Laurent Pinchart07b68352012-05-16 17:08:56 +0200249 }
Seung-Woo Kim229d3532011-12-15 14:36:22 +0900250
Daniel Vetterf2c00952012-12-14 13:39:03 +0900251 drm_helper_mode_fill_fb_struct(&exynos_fb->fb, mode_cmd);
252 exynos_fb->exynos_gem_obj[0] = to_exynos_gem_obj(obj);
Inki Dae01ed8122012-08-20 20:05:56 +0900253 exynos_fb->buf_cnt = exynos_drm_format_num_buffers(mode_cmd);
Seung-Woo Kim229d3532011-12-15 14:36:22 +0900254
Inki Dae01ed8122012-08-20 20:05:56 +0900255 DRM_DEBUG_KMS("buf_cnt = %d\n", exynos_fb->buf_cnt);
256
257 for (i = 1; i < exynos_fb->buf_cnt; i++) {
Inki Dae0519f9a2012-10-20 07:53:42 -0700258 struct exynos_drm_gem_obj *exynos_gem_obj;
259 int ret;
260
Seung-Woo Kim229d3532011-12-15 14:36:22 +0900261 obj = drm_gem_object_lookup(dev, file_priv,
262 mode_cmd->handles[i]);
263 if (!obj) {
264 DRM_ERROR("failed to lookup gem object\n");
Daniel Vetterf2c00952012-12-14 13:39:03 +0900265 kfree(exynos_fb);
Seung-Woo Kim229d3532011-12-15 14:36:22 +0900266 return ERR_PTR(-ENOENT);
267 }
268
Inki Dae0519f9a2012-10-20 07:53:42 -0700269 exynos_gem_obj = to_exynos_gem_obj(obj);
270
271 ret = check_fb_gem_memory_type(dev, exynos_gem_obj);
272 if (ret < 0) {
273 DRM_ERROR("cannot use this gem memory type for fb.\n");
Daniel Vetterf2c00952012-12-14 13:39:03 +0900274 kfree(exynos_fb);
Inki Dae0519f9a2012-10-20 07:53:42 -0700275 return ERR_PTR(ret);
276 }
277
Seung-Woo Kim229d3532011-12-15 14:36:22 +0900278 exynos_fb->exynos_gem_obj[i] = to_exynos_gem_obj(obj);
279 }
280
Daniel Vetterf2c00952012-12-14 13:39:03 +0900281 ret = drm_framebuffer_init(dev, &exynos_fb->fb, &exynos_drm_fb_funcs);
282 if (ret) {
283 for (i = 0; i < exynos_fb->buf_cnt; i++) {
284 struct exynos_drm_gem_obj *gem_obj;
285
286 gem_obj = exynos_fb->exynos_gem_obj[i];
287 drm_gem_object_unreference_unlocked(&gem_obj->base);
288 }
289
290 kfree(exynos_fb);
291 return ERR_PTR(ret);
292 }
293
294 return &exynos_fb->fb;
Inki Dae1c248b72011-10-04 19:19:01 +0900295}
296
Seung-Woo Kim229d3532011-12-15 14:36:22 +0900297struct exynos_drm_gem_buf *exynos_drm_fb_buffer(struct drm_framebuffer *fb,
298 int index)
Inki Dae1c248b72011-10-04 19:19:01 +0900299{
300 struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb);
Inki Dae2c871122011-11-12 15:23:32 +0900301 struct exynos_drm_gem_buf *buffer;
Inki Dae1c248b72011-10-04 19:19:01 +0900302
303 DRM_DEBUG_KMS("%s\n", __FILE__);
304
Seung-Woo Kim229d3532011-12-15 14:36:22 +0900305 if (index >= MAX_FB_BUFFER)
306 return NULL;
307
308 buffer = exynos_fb->exynos_gem_obj[index]->buffer;
Inki Dae2c871122011-11-12 15:23:32 +0900309 if (!buffer)
Inki Dae19c8b832011-10-14 13:29:46 +0900310 return NULL;
Inki Dae1c248b72011-10-04 19:19:01 +0900311
Inki Dae4744ad22012-12-07 17:51:27 +0900312 DRM_DEBUG_KMS("dma_addr = 0x%lx\n", (unsigned long)buffer->dma_addr);
Inki Dae1c248b72011-10-04 19:19:01 +0900313
Inki Dae2c871122011-11-12 15:23:32 +0900314 return buffer;
Inki Dae1c248b72011-10-04 19:19:01 +0900315}
316
Seung-Woo Kim7db3eba2011-10-18 16:58:05 +0900317static void exynos_drm_output_poll_changed(struct drm_device *dev)
318{
319 struct exynos_drm_private *private = dev->dev_private;
320 struct drm_fb_helper *fb_helper = private->fb_helper;
321
322 if (fb_helper)
323 drm_fb_helper_hotplug_event(fb_helper);
324}
325
Laurent Pincharte6ecefa2012-05-17 13:27:23 +0200326static const struct drm_mode_config_funcs exynos_drm_mode_config_funcs = {
Joonyoung Shime1533c02011-12-13 14:46:57 +0900327 .fb_create = exynos_user_fb_create,
Seung-Woo Kim7db3eba2011-10-18 16:58:05 +0900328 .output_poll_changed = exynos_drm_output_poll_changed,
Inki Dae1c248b72011-10-04 19:19:01 +0900329};
330
331void exynos_drm_mode_config_init(struct drm_device *dev)
332{
333 dev->mode_config.min_width = 0;
334 dev->mode_config.min_height = 0;
335
336 /*
337 * set max width and height as default value(4096x4096).
338 * this value would be used to check framebuffer size limitation
339 * at drm_mode_addfb().
340 */
341 dev->mode_config.max_width = 4096;
342 dev->mode_config.max_height = 4096;
343
344 dev->mode_config.funcs = &exynos_drm_mode_config_funcs;
345}