upload tizen1.0 source
[kernel/linux-2.6.36.git] / drivers / media / video / samsung / fimc / fimc_overlay.c
1 /* linux/drivers/media/video/samsung/fimc/fimc_overlay.c
2  *
3  * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4  *              http://www.samsung.com/
5  *
6  * V4L2 Overlay device support file for Samsung Camera Interface (FIMC) driver
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11 */
12
13 #include <linux/slab.h>
14 #include <linux/bootmem.h>
15 #include <linux/string.h>
16 #include <linux/platform_device.h>
17 #include <linux/io.h>
18 #include <linux/uaccess.h>
19 #include <plat/media.h>
20
21 #include "fimc.h"
22
23 int fimc_try_fmt_overlay(struct file *filp, void *fh, struct v4l2_format *f)
24 {
25         struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
26         int ctx_id = ((struct fimc_prv_data *)fh)->ctx_id;
27         struct fimc_ctx *ctx;
28
29         u32 is_rotate = 0;
30         ctx = &ctrl->out->ctx[ctx_id];
31
32         fimc_info1("%s: top(%d) left(%d) width(%d) height(%d)\n", __func__,
33                         f->fmt.win.w.top, f->fmt.win.w.left,
34                         f->fmt.win.w.width, f->fmt.win.w.height);
35
36         if ((ctx->overlay.mode == FIMC_OVLY_NONE_SINGLE_BUF) ||
37                 (ctx->overlay.mode == FIMC_OVLY_NONE_MULTI_BUF) ||
38                 (ctx->overlay.mode == FIMC_OVLY_DMA_AUTO) ||
39                 (ctx->overlay.mode == FIMC_OVLY_DMA_MANUAL))
40                 return 0;
41
42         /* Check Overlay Size : Overlay size must be smaller than LCD size. */
43         is_rotate = fimc_mapping_rot_flip(ctx->rotate, ctx->flip);
44         if (is_rotate & FIMC_ROT) {     /* Landscape mode */
45                 if (f->fmt.win.w.width > ctrl->fb.lcd_vres) {
46                         fimc_warn("The width is changed %d -> %d\n",
47                                 f->fmt.win.w.width, ctrl->fb.lcd_vres);
48                                 f->fmt.win.w.width = ctrl->fb.lcd_vres;
49                 }
50
51                 if (f->fmt.win.w.height > ctrl->fb.lcd_hres) {
52                         fimc_warn("The height is changed %d -> %d\n",
53                                 f->fmt.win.w.height, ctrl->fb.lcd_hres);
54                                 f->fmt.win.w.height = ctrl->fb.lcd_hres;
55                 }
56         } else {                        /* Portrait mode */
57                 if (f->fmt.win.w.width > ctrl->fb.lcd_hres) {
58                         fimc_warn("The width is changed %d -> %d\n",
59                                 f->fmt.win.w.width, ctrl->fb.lcd_hres);
60                                 f->fmt.win.w.width = ctrl->fb.lcd_hres;
61                 }
62
63                 if (f->fmt.win.w.height > ctrl->fb.lcd_vres) {
64                         fimc_warn("The height is changed %d -> %d\n",
65                                 f->fmt.win.w.height, ctrl->fb.lcd_vres);
66                                 f->fmt.win.w.height = ctrl->fb.lcd_vres;
67                 }
68         }
69
70         return 0;
71 }
72
73 int fimc_g_fmt_vid_overlay(struct file *filp, void *fh, struct v4l2_format *f)
74 {
75         struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
76         int ctx_id = ((struct fimc_prv_data *)fh)->ctx_id;
77         struct fimc_ctx *ctx;
78
79         ctx = &ctrl->out->ctx[ctx_id];
80
81         fimc_info1("%s: called\n", __func__);
82
83         f->fmt.win = ctx->win;
84
85         return 0;
86 }
87
88 static int fimc_check_pos(struct fimc_control *ctrl,
89                           struct fimc_ctx *ctx,
90                           struct v4l2_format *f)
91 {
92         if (ctx->win.w.width != f->fmt.win.w.width) {
93                 fimc_err("%s: cannot change width(%d,%d)\n", __func__,
94                                 ctx->win.w.width, f->fmt.win.w.width);
95                 return -EINVAL;
96         } else if (ctx->win.w.height != f->fmt.win.w.height) {
97                 fimc_err("%s: cannot change height(%d,%d)\n", __func__,
98                                 ctx->win.w.height, f->fmt.win.w.height);
99                 return -EINVAL;
100         }
101
102         return 0;
103 }
104
105 static int fimc_change_fifo_position(struct fimc_control *ctrl,
106                                      struct fimc_ctx *ctx) {
107         struct v4l2_rect fimd_rect;
108         struct s3cfb_user_window window;
109         int window_id = ((ctrl->id == 3) ? 2 : ctrl->id);
110         int ret = -1;
111
112         memset(&fimd_rect, 0, sizeof(struct v4l2_rect));
113
114         ret = fimc_fimd_rect(ctrl, ctx, &fimd_rect);
115         if (ret < 0) {
116                 fimc_err("fimc_fimd_rect fail\n");
117                 return -EINVAL;
118         }
119
120         /* Update WIN position */
121         window.x = fimd_rect.left;
122         window.y = fimd_rect.top;
123         ret = s3cfb_direct_ioctl(window_id, S3CFB_WIN_POSITION,
124                         (unsigned long)&window);
125         if (ret < 0) {
126                 fimc_err("direct_ioctl(S3CFB_WIN_POSITION) fail\n");
127                 return -EINVAL;
128         }
129
130         return 0;
131 }
132
133 int fimc_s_fmt_vid_overlay(struct file *filp, void *fh, struct v4l2_format *f)
134 {
135         struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
136         int ctx_id = ((struct fimc_prv_data *)fh)->ctx_id;
137         struct fimc_ctx *ctx;
138         int ret = -1;
139         ctx = &ctrl->out->ctx[ctx_id];
140
141         fimc_info1("%s: called\n", __func__);
142
143         switch (ctx->status) {
144         case FIMC_STREAMON:
145                 ret = fimc_check_pos(ctrl, ctx, f);
146                 if (ret < 0) {
147                         fimc_err("When FIMC is running, "
148                                 "you can only move the position.\n");
149                         return -EBUSY;
150                 }
151
152                 ret = fimc_try_fmt_overlay(filp, fh, f);
153                 if (ret < 0)
154                         return ret;
155
156                 ctx->win = f->fmt.win;
157                 fimc_change_fifo_position(ctrl, ctx);
158
159                 break;
160         case FIMC_STREAMOFF:
161                 ret = fimc_try_fmt_overlay(filp, fh, f);
162                 if (ret < 0)
163                         return ret;
164                 ctx->win = f->fmt.win;
165
166                 break;
167
168         default:
169                 fimc_err("FIMC is running\n");
170                 fimc_err("%s::FIMC is running(%d)\n", __func__, ctx->status);
171                 return -EBUSY;
172         }
173
174         return ret;
175 }
176
177 int fimc_g_fbuf(struct file *filp, void *fh, struct v4l2_framebuffer *fb)
178 {
179         struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
180         int ctx_id = ((struct fimc_prv_data *)fh)->ctx_id;
181         struct fimc_ctx *ctx;
182         u32 bpp = 1, format;
183
184         ctx = &ctrl->out->ctx[ctx_id];
185
186         fimc_info1("%s: called\n", __func__);
187
188         fb->capability = ctx->fbuf.capability;
189         fb->flags = 0;
190         fb->base = ctx->fbuf.base;
191
192         fb->fmt.width = ctx->fbuf.fmt.width;
193         fb->fmt.height = ctx->fbuf.fmt.height;
194         fb->fmt.pixelformat = ctx->fbuf.fmt.pixelformat;
195         format = ctx->fbuf.fmt.pixelformat;
196
197         switch (format) {
198         case V4L2_PIX_FMT_YUV420: /* fall through */
199         case V4L2_PIX_FMT_NV12:
200                 bpp = 1;
201                 break;
202         case V4L2_PIX_FMT_RGB565:
203                 bpp = 2;
204                 break;
205         case V4L2_PIX_FMT_RGB32:
206                 bpp = 4;
207                 break;
208         }
209
210         ctx->fbuf.fmt.bytesperline = fb->fmt.width * bpp;
211         fb->fmt.bytesperline = ctx->fbuf.fmt.bytesperline;
212         fb->fmt.sizeimage = ctx->fbuf.fmt.sizeimage;
213         fb->fmt.colorspace = V4L2_COLORSPACE_SMPTE170M;
214         fb->fmt.priv = 0;
215
216         return 0;
217 }
218
219 int fimc_s_fbuf(struct file *filp, void *fh, struct v4l2_framebuffer *fb)
220 {
221         struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;
222         int ctx_id = ((struct fimc_prv_data *)fh)->ctx_id;
223         struct fimc_ctx *ctx;
224         u32 bpp = 1;
225         u32 format = fb->fmt.pixelformat;
226         ctx = &ctrl->out->ctx[ctx_id];
227
228         fimc_info1("%s: called. width(%d), height(%d)\n",
229                         __func__, fb->fmt.width, fb->fmt.height);
230
231         ctx->fbuf.capability = V4L2_FBUF_CAP_EXTERNOVERLAY;
232         ctx->fbuf.flags = 0;
233         ctx->fbuf.base = fb->base;
234
235         if (ctx->overlay.mode == FIMC_OVLY_NONE_MULTI_BUF) {
236                 ctx->fbuf.fmt.width = fb->fmt.width;
237                 ctx->fbuf.fmt.height = fb->fmt.height;
238                 ctx->fbuf.fmt.pixelformat = fb->fmt.pixelformat;
239
240                 switch (format) {
241                 case V4L2_PIX_FMT_YUV420: /* fall through */
242                 case V4L2_PIX_FMT_NV12:
243                         bpp = 1;
244                         break;
245                 case V4L2_PIX_FMT_RGB565:
246                         bpp = 2;
247                         break;
248                 case V4L2_PIX_FMT_RGB32:
249                         bpp = 4;
250                         break;
251                 }
252
253                 ctx->fbuf.fmt.bytesperline = fb->fmt.width * bpp;
254                 ctx->fbuf.fmt.sizeimage = fb->fmt.sizeimage;
255                 ctx->fbuf.fmt.colorspace = V4L2_COLORSPACE_SMPTE170M;
256                 ctx->fbuf.fmt.priv = 0;
257         } else if (fb->base) {
258                 ctx->fbuf.fmt.width = fb->fmt.width;
259                 ctx->fbuf.fmt.height = fb->fmt.height;
260                 ctx->fbuf.fmt.pixelformat = fb->fmt.pixelformat;
261
262                 switch (format) {
263                 case V4L2_PIX_FMT_YUV420:       /* fall through */
264                 case V4L2_PIX_FMT_NV12:
265                         bpp = 1;
266                         break;
267                 case V4L2_PIX_FMT_RGB565:
268                         bpp = 2;
269                         break;
270                 case V4L2_PIX_FMT_RGB32:
271                         bpp = 4;
272                         break;
273                 }
274
275                 ctx->fbuf.fmt.bytesperline = fb->fmt.width * bpp;
276                 ctx->fbuf.fmt.sizeimage = fb->fmt.sizeimage;
277                 ctx->fbuf.fmt.colorspace = V4L2_COLORSPACE_SMPTE170M;
278                 ctx->fbuf.fmt.priv = 0;
279
280                 ctx->overlay.mode = FIMC_OVLY_NONE_SINGLE_BUF;
281         } else {
282                 ctx->overlay.mode = FIMC_OVLY_NOT_FIXED;
283         }
284
285         return 0;
286 }