aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/platform/omap
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-10-07 04:49:05 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-10-07 04:49:05 -0400
commit0b8e74c6f44094189dbe78baf4101acc7570c6af (patch)
tree6440561d09fb71ba5928664604ec92f29940be6b /drivers/media/platform/omap
parent7f60ba388f5b9dd8b0da463b394412dace3ab814 (diff)
parentbd0d10498826ed150da5e4c45baf8b9c7088fb71 (diff)
Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab: "The first part of the media updates for Kernel 3.7. This series contain: - A major tree renaming patch series: now, drivers are organized internally by their used bus, instead of by V4L2 and/or DVB API, providing a cleaner driver location for hybrid drivers that implement both APIs, and allowing to cleanup the Kconfig items and make them more intuitive for the end user; - Media Kernel developers are typically very lazy with their duties of keeping the MAINTAINERS entries for their drivers updated. As now the tree is more organized, we're doing an effort to add/update those entries for the drivers that aren't currently orphan; - Several DVB USB drivers got moved to a new DVB USB v2 core; the new core fixes several bugs (as the existing one that got bitroted). Now, suspend/resume finally started to work fine (at least with some devices - we should expect more work with regards to it); - added multistream support for DVB-T2, and unified the API for DVB-S2 and ISDB-S. Backward binary support is preserved; - as usual, a few new drivers, some V4L2 core improvements and lots of drivers improvements and fixes. There are some points to notice on this series: 1) you should expect a trivial merge conflict on your tree, with the removal of Documentation/feature-removal-schedule.txt: this series would be adding two additional entries there. I opted to not rebase it due to this recent change; 2) With regards to the PCTV 520e udev-related breakage, I opted to fix it in a way that the patches can be backported to 3.5 even without your firmware fix patch. This way, Greg doesn't need to rush backporting your patch (as there are still the firmware cache and firmware path customization issues to be addressed there). I'll send later a patch (likely after the end of the merge window) reverting the rest of the DRX-K async firmware request, fully restoring its original behaviour to allow media drivers to initialize everything serialized as before for 3.7 and upper. 3) I'm planning to work on this weekend to test the DMABUF patches for V4L2. The patches are on my queue for several Kernel cycles, but, up to now, there is/was no way to test the series locally. I have some concerns about this particular changeset with regards to security issues, and with regards to the replacement of the old VIDIOC_OVERLAY ioctl's that is broken on modern systems, due to GPU drivers change. The Overlay API allows direct PCI2PCI transfers from a media capture card into the GPU framebuffer, but its API is crappy. Also, the only existing X11 driver that implements it requires a XV extension that is not available anymore on modern drivers. The DMABUF can do the same thing, but with it is promising to be a properly-designed API. If I can successfully test this series and be happy with it, I should be asking you to pull them next week." * 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (717 commits) em28xx: regression fix: use DRX-K sync firmware requests on em28xx drxk: allow loading firmware synchrousnously em28xx: Make all em28xx extensions to be initialized asynchronously [media] tda18271: properly report read errors in tda18271_get_id [media] tda18271: delay IR & RF calibration until init() if delay_cal is set [media] MAINTAINERS: add Michael Krufky as tda827x maintainer [media] MAINTAINERS: add Michael Krufky as tda8290 maintainer [media] MAINTAINERS: add Michael Krufky as cxusb maintainer [media] MAINTAINERS: add Michael Krufky as lg2160 maintainer [media] MAINTAINERS: add Michael Krufky as lgdt3305 maintainer [media] MAINTAINERS: add Michael Krufky as mxl111sf maintainer [media] MAINTAINERS: add Michael Krufky as mxl5007t maintainer [media] MAINTAINERS: add Michael Krufky as tda18271 maintainer [media] s5p-tv: Report only multi-plane capabilities in vidioc_querycap [media] s5p-mfc: Fix misplaced return statement in s5p_mfc_suspend() [media] exynos-gsc: Add missing static storage class specifiers [media] exynos-gsc: Remove <linux/version.h> header file inclusion [media] s5p-fimc: Fix incorrect condition in fimc_lite_reqbufs() [media] s5p-tv: Fix potential NULL pointer dereference error [media] s5k6aa: Fix possible NULL pointer dereference ...
Diffstat (limited to 'drivers/media/platform/omap')
-rw-r--r--drivers/media/platform/omap/Kconfig14
-rw-r--r--drivers/media/platform/omap/Makefile8
-rw-r--r--drivers/media/platform/omap/omap_vout.c2291
-rw-r--r--drivers/media/platform/omap/omap_vout_vrfb.c390
-rw-r--r--drivers/media/platform/omap/omap_vout_vrfb.h40
-rw-r--r--drivers/media/platform/omap/omap_voutdef.h225
-rw-r--r--drivers/media/platform/omap/omap_voutlib.c339
-rw-r--r--drivers/media/platform/omap/omap_voutlib.h36
8 files changed, 3343 insertions, 0 deletions
diff --git a/drivers/media/platform/omap/Kconfig b/drivers/media/platform/omap/Kconfig
new file mode 100644
index 000000000000..390ab094f9f2
--- /dev/null
+++ b/drivers/media/platform/omap/Kconfig
@@ -0,0 +1,14 @@
1config VIDEO_OMAP2_VOUT_VRFB
2 bool
3
4config VIDEO_OMAP2_VOUT
5 tristate "OMAP2/OMAP3 V4L2-Display driver"
6 depends on ARCH_OMAP2 || ARCH_OMAP3
7 select VIDEOBUF_GEN
8 select VIDEOBUF_DMA_CONTIG
9 select OMAP2_DSS
10 select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3
11 select VIDEO_OMAP2_VOUT_VRFB if VIDEO_OMAP2_VOUT && OMAP2_VRFB
12 default n
13 ---help---
14 V4L2 Display driver support for OMAP2/3 based boards.
diff --git a/drivers/media/platform/omap/Makefile b/drivers/media/platform/omap/Makefile
new file mode 100644
index 000000000000..d80df41fde28
--- /dev/null
+++ b/drivers/media/platform/omap/Makefile
@@ -0,0 +1,8 @@
1#
2# Makefile for the omap video device drivers.
3#
4
5# OMAP2/3 Display driver
6omap-vout-y += omap_vout.o omap_voutlib.o
7omap-vout-$(CONFIG_VIDEO_OMAP2_VOUT_VRFB) += omap_vout_vrfb.o
8obj-$(CONFIG_VIDEO_OMAP2_VOUT) += omap-vout.o
diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c
new file mode 100644
index 000000000000..66ac21d466af
--- /dev/null
+++ b/drivers/media/platform/omap/omap_vout.c
@@ -0,0 +1,2291 @@
1/*
2 * omap_vout.c
3 *
4 * Copyright (C) 2005-2010 Texas Instruments.
5 *
6 * This file is licensed under the terms of the GNU General Public License
7 * version 2. This program is licensed "as is" without any warranty of any
8 * kind, whether express or implied.
9 *
10 * Leveraged code from the OMAP2 camera driver
11 * Video-for-Linux (Version 2) camera capture driver for
12 * the OMAP24xx camera controller.
13 *
14 * Author: Andy Lowe (source@mvista.com)
15 *
16 * Copyright (C) 2004 MontaVista Software, Inc.
17 * Copyright (C) 2010 Texas Instruments.
18 *
19 * History:
20 * 20-APR-2006 Khasim Modified VRFB based Rotation,
21 * The image data is always read from 0 degree
22 * view and written
23 * to the virtual space of desired rotation angle
24 * 4-DEC-2006 Jian Changed to support better memory management
25 *
26 * 17-Nov-2008 Hardik Changed driver to use video_ioctl2
27 *
28 * 23-Feb-2010 Vaibhav H Modified to use new DSS2 interface
29 *
30 */
31
32#include <linux/init.h>
33#include <linux/module.h>
34#include <linux/vmalloc.h>
35#include <linux/sched.h>
36#include <linux/types.h>
37#include <linux/platform_device.h>
38#include <linux/irq.h>
39#include <linux/videodev2.h>
40#include <linux/dma-mapping.h>
41#include <linux/slab.h>
42
43#include <media/videobuf-dma-contig.h>
44#include <media/v4l2-device.h>
45#include <media/v4l2-ioctl.h>
46
47#include <plat/cpu.h>
48#include <plat/dma.h>
49#include <plat/vrfb.h>
50#include <video/omapdss.h>
51
52#include "omap_voutlib.h"
53#include "omap_voutdef.h"
54#include "omap_vout_vrfb.h"
55
56MODULE_AUTHOR("Texas Instruments");
57MODULE_DESCRIPTION("OMAP Video for Linux Video out driver");
58MODULE_LICENSE("GPL");
59
60/* Driver Configuration macros */
61#define VOUT_NAME "omap_vout"
62
63enum omap_vout_channels {
64 OMAP_VIDEO1,
65 OMAP_VIDEO2,
66};
67
68static struct videobuf_queue_ops video_vbq_ops;
69/* Variables configurable through module params*/
70static u32 video1_numbuffers = 3;
71static u32 video2_numbuffers = 3;
72static u32 video1_bufsize = OMAP_VOUT_MAX_BUF_SIZE;
73static u32 video2_bufsize = OMAP_VOUT_MAX_BUF_SIZE;
74static bool vid1_static_vrfb_alloc;
75static bool vid2_static_vrfb_alloc;
76static bool debug;
77
78/* Module parameters */
79module_param(video1_numbuffers, uint, S_IRUGO);
80MODULE_PARM_DESC(video1_numbuffers,
81 "Number of buffers to be allocated at init time for Video1 device.");
82
83module_param(video2_numbuffers, uint, S_IRUGO);
84MODULE_PARM_DESC(video2_numbuffers,
85 "Number of buffers to be allocated at init time for Video2 device.");
86
87module_param(video1_bufsize, uint, S_IRUGO);
88MODULE_PARM_DESC(video1_bufsize,
89 "Size of the buffer to be allocated for video1 device");
90
91module_param(video2_bufsize, uint, S_IRUGO);
92MODULE_PARM_DESC(video2_bufsize,
93 "Size of the buffer to be allocated for video2 device");
94
95module_param(vid1_static_vrfb_alloc, bool, S_IRUGO);
96MODULE_PARM_DESC(vid1_static_vrfb_alloc,
97 "Static allocation of the VRFB buffer for video1 device");
98
99module_param(vid2_static_vrfb_alloc, bool, S_IRUGO);
100MODULE_PARM_DESC(vid2_static_vrfb_alloc,
101 "Static allocation of the VRFB buffer for video2 device");
102
103module_param(debug, bool, S_IRUGO);
104MODULE_PARM_DESC(debug, "Debug level (0-1)");
105
106/* list of image formats supported by OMAP2 video pipelines */
107static const struct v4l2_fmtdesc omap_formats[] = {
108 {
109 /* Note: V4L2 defines RGB565 as:
110 *
111 * Byte 0 Byte 1
112 * g2 g1 g0 r4 r3 r2 r1 r0 b4 b3 b2 b1 b0 g5 g4 g3
113 *
114 * We interpret RGB565 as:
115 *
116 * Byte 0 Byte 1
117 * g2 g1 g0 b4 b3 b2 b1 b0 r4 r3 r2 r1 r0 g5 g4 g3
118 */
119 .description = "RGB565, le",
120 .pixelformat = V4L2_PIX_FMT_RGB565,
121 },
122 {
123 /* Note: V4L2 defines RGB32 as: RGB-8-8-8-8 we use
124 * this for RGB24 unpack mode, the last 8 bits are ignored
125 * */
126 .description = "RGB32, le",
127 .pixelformat = V4L2_PIX_FMT_RGB32,
128 },
129 {
130 /* Note: V4L2 defines RGB24 as: RGB-8-8-8 we use
131 * this for RGB24 packed mode
132 *
133 */
134 .description = "RGB24, le",
135 .pixelformat = V4L2_PIX_FMT_RGB24,
136 },
137 {
138 .description = "YUYV (YUV 4:2:2), packed",
139 .pixelformat = V4L2_PIX_FMT_YUYV,
140 },
141 {
142 .description = "UYVY, packed",
143 .pixelformat = V4L2_PIX_FMT_UYVY,
144 },
145};
146
147#define NUM_OUTPUT_FORMATS (ARRAY_SIZE(omap_formats))
148
149/*
150 * Try format
151 */
152static int omap_vout_try_format(struct v4l2_pix_format *pix)
153{
154 int ifmt, bpp = 0;
155
156 pix->height = clamp(pix->height, (u32)VID_MIN_HEIGHT,
157 (u32)VID_MAX_HEIGHT);
158 pix->width = clamp(pix->width, (u32)VID_MIN_WIDTH, (u32)VID_MAX_WIDTH);
159
160 for (ifmt = 0; ifmt < NUM_OUTPUT_FORMATS; ifmt++) {
161 if (pix->pixelformat == omap_formats[ifmt].pixelformat)
162 break;
163 }
164
165 if (ifmt == NUM_OUTPUT_FORMATS)
166 ifmt = 0;
167
168 pix->pixelformat = omap_formats[ifmt].pixelformat;
169 pix->field = V4L2_FIELD_ANY;
170 pix->priv = 0;
171
172 switch (pix->pixelformat) {
173 case V4L2_PIX_FMT_YUYV:
174 case V4L2_PIX_FMT_UYVY:
175 default:
176 pix->colorspace = V4L2_COLORSPACE_JPEG;
177 bpp = YUYV_BPP;
178 break;
179 case V4L2_PIX_FMT_RGB565:
180 case V4L2_PIX_FMT_RGB565X:
181 pix->colorspace = V4L2_COLORSPACE_SRGB;
182 bpp = RGB565_BPP;
183 break;
184 case V4L2_PIX_FMT_RGB24:
185 pix->colorspace = V4L2_COLORSPACE_SRGB;
186 bpp = RGB24_BPP;
187 break;
188 case V4L2_PIX_FMT_RGB32:
189 case V4L2_PIX_FMT_BGR32:
190 pix->colorspace = V4L2_COLORSPACE_SRGB;
191 bpp = RGB32_BPP;
192 break;
193 }
194 pix->bytesperline = pix->width * bpp;
195 pix->sizeimage = pix->bytesperline * pix->height;
196
197 return bpp;
198}
199
200/*
201 * omap_vout_uservirt_to_phys: This inline function is used to convert user
202 * space virtual address to physical address.
203 */
204static u32 omap_vout_uservirt_to_phys(u32 virtp)
205{
206 unsigned long physp = 0;
207 struct vm_area_struct *vma;
208 struct mm_struct *mm = current->mm;
209
210 vma = find_vma(mm, virtp);
211 /* For kernel direct-mapped memory, take the easy way */
212 if (virtp >= PAGE_OFFSET) {
213 physp = virt_to_phys((void *) virtp);
214 } else if (vma && (vma->vm_flags & VM_IO) && vma->vm_pgoff) {
215 /* this will catch, kernel-allocated, mmaped-to-usermode
216 addresses */
217 physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start);
218 } else {
219 /* otherwise, use get_user_pages() for general userland pages */
220 int res, nr_pages = 1;
221 struct page *pages;
222 down_read(&current->mm->mmap_sem);
223
224 res = get_user_pages(current, current->mm, virtp, nr_pages, 1,
225 0, &pages, NULL);
226 up_read(&current->mm->mmap_sem);
227
228 if (res == nr_pages) {
229 physp = __pa(page_address(&pages[0]) +
230 (virtp & ~PAGE_MASK));
231 } else {
232 printk(KERN_WARNING VOUT_NAME
233 "get_user_pages failed\n");
234 return 0;
235 }
236 }
237
238 return physp;
239}
240
241/*
242 * Free the V4L2 buffers
243 */
244void omap_vout_free_buffers(struct omap_vout_device *vout)
245{
246 int i, numbuffers;
247
248 /* Allocate memory for the buffers */
249 numbuffers = (vout->vid) ? video2_numbuffers : video1_numbuffers;
250 vout->buffer_size = (vout->vid) ? video2_bufsize : video1_bufsize;
251
252 for (i = 0; i < numbuffers; i++) {
253 omap_vout_free_buffer(vout->buf_virt_addr[i],
254 vout->buffer_size);
255 vout->buf_phy_addr[i] = 0;
256 vout->buf_virt_addr[i] = 0;
257 }
258}
259
260/*
261 * Convert V4L2 rotation to DSS rotation
262 * V4L2 understand 0, 90, 180, 270.
263 * Convert to 0, 1, 2 and 3 respectively for DSS
264 */
265static int v4l2_rot_to_dss_rot(int v4l2_rotation,
266 enum dss_rotation *rotation, bool mirror)
267{
268 int ret = 0;
269
270 switch (v4l2_rotation) {
271 case 90:
272 *rotation = dss_rotation_90_degree;
273 break;
274 case 180:
275 *rotation = dss_rotation_180_degree;
276 break;
277 case 270:
278 *rotation = dss_rotation_270_degree;
279 break;
280 case 0:
281 *rotation = dss_rotation_0_degree;
282 break;
283 default:
284 ret = -EINVAL;
285 }
286 return ret;
287}
288
289static int omap_vout_calculate_offset(struct omap_vout_device *vout)
290{
291 struct omapvideo_info *ovid;
292 struct v4l2_rect *crop = &vout->crop;
293 struct v4l2_pix_format *pix = &vout->pix;
294 int *cropped_offset = &vout->cropped_offset;
295 int ps = 2, line_length = 0;
296
297 ovid = &vout->vid_info;
298
299 if (ovid->rotation_type == VOUT_ROT_VRFB) {
300 omap_vout_calculate_vrfb_offset(vout);
301 } else {
302 vout->line_length = line_length = pix->width;
303
304 if (V4L2_PIX_FMT_YUYV == pix->pixelformat ||
305 V4L2_PIX_FMT_UYVY == pix->pixelformat)
306 ps = 2;
307 else if (V4L2_PIX_FMT_RGB32 == pix->pixelformat)
308 ps = 4;
309 else if (V4L2_PIX_FMT_RGB24 == pix->pixelformat)
310 ps = 3;
311
312 vout->ps = ps;
313
314 *cropped_offset = (line_length * ps) *
315 crop->top + crop->left * ps;
316 }
317
318 v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "%s Offset:%x\n",
319 __func__, vout->cropped_offset);
320
321 return 0;
322}
323
324/*
325 * Convert V4L2 pixel format to DSS pixel format
326 */
327static int video_mode_to_dss_mode(struct omap_vout_device *vout)
328{
329 struct omap_overlay *ovl;
330 struct omapvideo_info *ovid;
331 struct v4l2_pix_format *pix = &vout->pix;
332 enum omap_color_mode mode;
333
334 ovid = &vout->vid_info;
335 ovl = ovid->overlays[0];
336
337 switch (pix->pixelformat) {
338 case 0:
339 break;
340 case V4L2_PIX_FMT_YUYV:
341 mode = OMAP_DSS_COLOR_YUV2;
342 break;
343 case V4L2_PIX_FMT_UYVY:
344 mode = OMAP_DSS_COLOR_UYVY;
345 break;
346 case V4L2_PIX_FMT_RGB565:
347 mode = OMAP_DSS_COLOR_RGB16;
348 break;
349 case V4L2_PIX_FMT_RGB24:
350 mode = OMAP_DSS_COLOR_RGB24P;
351 break;
352 case V4L2_PIX_FMT_RGB32:
353 mode = (ovl->id == OMAP_DSS_VIDEO1) ?
354 OMAP_DSS_COLOR_RGB24U : OMAP_DSS_COLOR_ARGB32;
355 break;
356 case V4L2_PIX_FMT_BGR32:
357 mode = OMAP_DSS_COLOR_RGBX32;
358 break;
359 default:
360 mode = -EINVAL;
361 }
362 return mode;
363}
364
365/*
366 * Setup the overlay
367 */
368static int omapvid_setup_overlay(struct omap_vout_device *vout,
369 struct omap_overlay *ovl, int posx, int posy, int outw,
370 int outh, u32 addr)
371{
372 int ret = 0;
373 struct omap_overlay_info info;
374 int cropheight, cropwidth, pixheight, pixwidth;
375
376 if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0 &&
377 (outw != vout->pix.width || outh != vout->pix.height)) {
378 ret = -EINVAL;
379 goto setup_ovl_err;
380 }
381
382 vout->dss_mode = video_mode_to_dss_mode(vout);
383 if (vout->dss_mode == -EINVAL) {
384 ret = -EINVAL;
385 goto setup_ovl_err;
386 }
387
388 /* Setup the input plane parameters according to
389 * rotation value selected.
390 */
391 if (is_rotation_90_or_270(vout)) {
392 cropheight = vout->crop.width;
393 cropwidth = vout->crop.height;
394 pixheight = vout->pix.width;
395 pixwidth = vout->pix.height;
396 } else {
397 cropheight = vout->crop.height;
398 cropwidth = vout->crop.width;
399 pixheight = vout->pix.height;
400 pixwidth = vout->pix.width;
401 }
402
403 ovl->get_overlay_info(ovl, &info);
404 info.paddr = addr;
405 info.width = cropwidth;
406 info.height = cropheight;
407 info.color_mode = vout->dss_mode;
408 info.mirror = vout->mirror;
409 info.pos_x = posx;
410 info.pos_y = posy;
411 info.out_width = outw;
412 info.out_height = outh;
413 info.global_alpha = vout->win.global_alpha;
414 if (!is_rotation_enabled(vout)) {
415 info.rotation = 0;
416 info.rotation_type = OMAP_DSS_ROT_DMA;
417 info.screen_width = pixwidth;
418 } else {
419 info.rotation = vout->rotation;
420 info.rotation_type = OMAP_DSS_ROT_VRFB;
421 info.screen_width = 2048;
422 }
423
424 v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev,
425 "%s enable=%d addr=%x width=%d\n height=%d color_mode=%d\n"
426 "rotation=%d mirror=%d posx=%d posy=%d out_width = %d \n"
427 "out_height=%d rotation_type=%d screen_width=%d\n",
428 __func__, ovl->is_enabled(ovl), info.paddr, info.width, info.height,
429 info.color_mode, info.rotation, info.mirror, info.pos_x,
430 info.pos_y, info.out_width, info.out_height, info.rotation_type,
431 info.screen_width);
432
433 ret = ovl->set_overlay_info(ovl, &info);
434 if (ret)
435 goto setup_ovl_err;
436
437 return 0;
438
439setup_ovl_err:
440 v4l2_warn(&vout->vid_dev->v4l2_dev, "setup_overlay failed\n");
441 return ret;
442}
443
444/*
445 * Initialize the overlay structure
446 */
447static int omapvid_init(struct omap_vout_device *vout, u32 addr)
448{
449 int ret = 0, i;
450 struct v4l2_window *win;
451 struct omap_overlay *ovl;
452 int posx, posy, outw, outh, temp;
453 struct omap_video_timings *timing;
454 struct omapvideo_info *ovid = &vout->vid_info;
455
456 win = &vout->win;
457 for (i = 0; i < ovid->num_overlays; i++) {
458 ovl = ovid->overlays[i];
459 if (!ovl->manager || !ovl->manager->device)
460 return -EINVAL;
461
462 timing = &ovl->manager->device->panel.timings;
463
464 outw = win->w.width;
465 outh = win->w.height;
466 switch (vout->rotation) {
467 case dss_rotation_90_degree:
468 /* Invert the height and width for 90
469 * and 270 degree rotation
470 */
471 temp = outw;
472 outw = outh;
473 outh = temp;
474 posy = (timing->y_res - win->w.width) - win->w.left;
475 posx = win->w.top;
476 break;
477
478 case dss_rotation_180_degree:
479 posx = (timing->x_res - win->w.width) - win->w.left;
480 posy = (timing->y_res - win->w.height) - win->w.top;
481 break;
482
483 case dss_rotation_270_degree:
484 temp = outw;
485 outw = outh;
486 outh = temp;
487 posy = win->w.left;
488 posx = (timing->x_res - win->w.height) - win->w.top;
489 break;
490
491 default:
492 posx = win->w.left;
493 posy = win->w.top;
494 break;
495 }
496
497 ret = omapvid_setup_overlay(vout, ovl, posx, posy,
498 outw, outh, addr);
499 if (ret)
500 goto omapvid_init_err;
501 }
502 return 0;
503
504omapvid_init_err:
505 v4l2_warn(&vout->vid_dev->v4l2_dev, "apply_changes failed\n");
506 return ret;
507}
508
509/*
510 * Apply the changes set the go bit of DSS
511 */
512static int omapvid_apply_changes(struct omap_vout_device *vout)
513{
514 int i;
515 struct omap_overlay *ovl;
516 struct omapvideo_info *ovid = &vout->vid_info;
517
518 for (i = 0; i < ovid->num_overlays; i++) {
519 ovl = ovid->overlays[i];
520 if (!ovl->manager || !ovl->manager->device)
521 return -EINVAL;
522 ovl->manager->apply(ovl->manager);
523 }
524
525 return 0;
526}
527
528static int omapvid_handle_interlace_display(struct omap_vout_device *vout,
529 unsigned int irqstatus, struct timeval timevalue)
530{
531 u32 fid;
532
533 if (vout->first_int) {
534 vout->first_int = 0;
535 goto err;
536 }
537
538 if (irqstatus & DISPC_IRQ_EVSYNC_ODD)
539 fid = 1;
540 else if (irqstatus & DISPC_IRQ_EVSYNC_EVEN)
541 fid = 0;
542 else
543 goto err;
544
545 vout->field_id ^= 1;
546 if (fid != vout->field_id) {
547 if (fid == 0)
548 vout->field_id = fid;
549 } else if (0 == fid) {
550 if (vout->cur_frm == vout->next_frm)
551 goto err;
552
553 vout->cur_frm->ts = timevalue;
554 vout->cur_frm->state = VIDEOBUF_DONE;
555 wake_up_interruptible(&vout->cur_frm->done);
556 vout->cur_frm = vout->next_frm;
557 } else {
558 if (list_empty(&vout->dma_queue) ||
559 (vout->cur_frm != vout->next_frm))
560 goto err;
561 }
562
563 return vout->field_id;
564err:
565 return 0;
566}
567
568static void omap_vout_isr(void *arg, unsigned int irqstatus)
569{
570 int ret, fid, mgr_id;
571 u32 addr, irq;
572 struct omap_overlay *ovl;
573 struct timeval timevalue;
574 struct omapvideo_info *ovid;
575 struct omap_dss_device *cur_display;
576 struct omap_vout_device *vout = (struct omap_vout_device *)arg;
577
578 if (!vout->streaming)
579 return;
580
581 ovid = &vout->vid_info;
582 ovl = ovid->overlays[0];
583 /* get the display device attached to the overlay */
584 if (!ovl->manager || !ovl->manager->device)
585 return;
586
587 mgr_id = ovl->manager->id;
588 cur_display = ovl->manager->device;
589
590 spin_lock(&vout->vbq_lock);
591 do_gettimeofday(&timevalue);
592
593 switch (cur_display->type) {
594 case OMAP_DISPLAY_TYPE_DSI:
595 case OMAP_DISPLAY_TYPE_DPI:
596 if (mgr_id == OMAP_DSS_CHANNEL_LCD)
597 irq = DISPC_IRQ_VSYNC;
598 else if (mgr_id == OMAP_DSS_CHANNEL_LCD2)
599 irq = DISPC_IRQ_VSYNC2;
600 else
601 goto vout_isr_err;
602
603 if (!(irqstatus & irq))
604 goto vout_isr_err;
605 break;
606 case OMAP_DISPLAY_TYPE_VENC:
607 fid = omapvid_handle_interlace_display(vout, irqstatus,
608 timevalue);
609 if (!fid)
610 goto vout_isr_err;
611 break;
612 case OMAP_DISPLAY_TYPE_HDMI:
613 if (!(irqstatus & DISPC_IRQ_EVSYNC_EVEN))
614 goto vout_isr_err;
615 break;
616 default:
617 goto vout_isr_err;
618 }
619
620 if (!vout->first_int && (vout->cur_frm != vout->next_frm)) {
621 vout->cur_frm->ts = timevalue;
622 vout->cur_frm->state = VIDEOBUF_DONE;
623 wake_up_interruptible(&vout->cur_frm->done);
624 vout->cur_frm = vout->next_frm;
625 }
626
627 vout->first_int = 0;
628 if (list_empty(&vout->dma_queue))
629 goto vout_isr_err;
630
631 vout->next_frm = list_entry(vout->dma_queue.next,
632 struct videobuf_buffer, queue);
633 list_del(&vout->next_frm->queue);
634
635 vout->next_frm->state = VIDEOBUF_ACTIVE;
636
637 addr = (unsigned long) vout->queued_buf_addr[vout->next_frm->i]
638 + vout->cropped_offset;
639
640 /* First save the configuration in ovelray structure */
641 ret = omapvid_init(vout, addr);
642 if (ret)
643 printk(KERN_ERR VOUT_NAME
644 "failed to set overlay info\n");
645 /* Enable the pipeline and set the Go bit */
646 ret = omapvid_apply_changes(vout);
647 if (ret)
648 printk(KERN_ERR VOUT_NAME "failed to change mode\n");
649
650vout_isr_err:
651 spin_unlock(&vout->vbq_lock);
652}
653
654/* Video buffer call backs */
655
656/*
657 * Buffer setup function is called by videobuf layer when REQBUF ioctl is
658 * called. This is used to setup buffers and return size and count of
659 * buffers allocated. After the call to this buffer, videobuf layer will
660 * setup buffer queue depending on the size and count of buffers
661 */
662static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count,
663 unsigned int *size)
664{
665 int startindex = 0, i, j;
666 u32 phy_addr = 0, virt_addr = 0;
667 struct omap_vout_device *vout = q->priv_data;
668 struct omapvideo_info *ovid = &vout->vid_info;
669 int vid_max_buf_size;
670
671 if (!vout)
672 return -EINVAL;
673
674 vid_max_buf_size = vout->vid == OMAP_VIDEO1 ? video1_bufsize :
675 video2_bufsize;
676
677 if (V4L2_BUF_TYPE_VIDEO_OUTPUT != q->type)
678 return -EINVAL;
679
680 startindex = (vout->vid == OMAP_VIDEO1) ?
681 video1_numbuffers : video2_numbuffers;
682 if (V4L2_MEMORY_MMAP == vout->memory && *count < startindex)
683 *count = startindex;
684
685 if (ovid->rotation_type == VOUT_ROT_VRFB) {
686 if (omap_vout_vrfb_buffer_setup(vout, count, startindex))
687 return -ENOMEM;
688 }
689
690 if (V4L2_MEMORY_MMAP != vout->memory)
691 return 0;
692
693 /* Now allocated the V4L2 buffers */
694 *size = PAGE_ALIGN(vout->pix.width * vout->pix.height * vout->bpp);
695 startindex = (vout->vid == OMAP_VIDEO1) ?
696 video1_numbuffers : video2_numbuffers;
697
698 /* Check the size of the buffer */
699 if (*size > vid_max_buf_size) {
700 v4l2_err(&vout->vid_dev->v4l2_dev,
701 "buffer allocation mismatch [%u] [%u]\n",
702 *size, vout->buffer_size);
703 return -ENOMEM;
704 }
705
706 for (i = startindex; i < *count; i++) {
707 vout->buffer_size = *size;
708
709 virt_addr = omap_vout_alloc_buffer(vout->buffer_size,
710 &phy_addr);
711 if (!virt_addr) {
712 if (ovid->rotation_type == VOUT_ROT_NONE) {
713 break;
714 } else {
715 if (!is_rotation_enabled(vout))
716 break;
717 /* Free the VRFB buffers if no space for V4L2 buffers */
718 for (j = i; j < *count; j++) {
719 omap_vout_free_buffer(
720 vout->smsshado_virt_addr[j],
721 vout->smsshado_size);
722 vout->smsshado_virt_addr[j] = 0;
723 vout->smsshado_phy_addr[j] = 0;
724 }
725 }
726 }
727 vout->buf_virt_addr[i] = virt_addr;
728 vout->buf_phy_addr[i] = phy_addr;
729 }
730 *count = vout->buffer_allocated = i;
731
732 return 0;
733}
734
735/*
736 * Free the V4L2 buffers additionally allocated than default
737 * number of buffers
738 */
739static void omap_vout_free_extra_buffers(struct omap_vout_device *vout)
740{
741 int num_buffers = 0, i;
742
743 num_buffers = (vout->vid == OMAP_VIDEO1) ?
744 video1_numbuffers : video2_numbuffers;
745
746 for (i = num_buffers; i < vout->buffer_allocated; i++) {
747 if (vout->buf_virt_addr[i])
748 omap_vout_free_buffer(vout->buf_virt_addr[i],
749 vout->buffer_size);
750
751 vout->buf_virt_addr[i] = 0;
752 vout->buf_phy_addr[i] = 0;
753 }
754 vout->buffer_allocated = num_buffers;
755}
756
757/*
758 * This function will be called when VIDIOC_QBUF ioctl is called.
759 * It prepare buffers before give out for the display. This function
760 * converts user space virtual address into physical address if userptr memory
761 * exchange mechanism is used. If rotation is enabled, it copies entire
762 * buffer into VRFB memory space before giving it to the DSS.
763 */
764static int omap_vout_buffer_prepare(struct videobuf_queue *q,
765 struct videobuf_buffer *vb,
766 enum v4l2_field field)
767{
768 struct omap_vout_device *vout = q->priv_data;
769 struct omapvideo_info *ovid = &vout->vid_info;
770
771 if (VIDEOBUF_NEEDS_INIT == vb->state) {
772 vb->width = vout->pix.width;
773 vb->height = vout->pix.height;
774 vb->size = vb->width * vb->height * vout->bpp;
775 vb->field = field;
776 }
777 vb->state = VIDEOBUF_PREPARED;
778 /* if user pointer memory mechanism is used, get the physical
779 * address of the buffer
780 */
781 if (V4L2_MEMORY_USERPTR == vb->memory) {
782 if (0 == vb->baddr)
783 return -EINVAL;
784 /* Physical address */
785 vout->queued_buf_addr[vb->i] = (u8 *)
786 omap_vout_uservirt_to_phys(vb->baddr);
787 } else {
788 u32 addr, dma_addr;
789 unsigned long size;
790
791 addr = (unsigned long) vout->buf_virt_addr[vb->i];
792 size = (unsigned long) vb->size;
793
794 dma_addr = dma_map_single(vout->vid_dev->v4l2_dev.dev, (void *) addr,
795 size, DMA_TO_DEVICE);
796 if (dma_mapping_error(vout->vid_dev->v4l2_dev.dev, dma_addr))
797 v4l2_err(&vout->vid_dev->v4l2_dev, "dma_map_single failed\n");
798
799 vout->queued_buf_addr[vb->i] = (u8 *)vout->buf_phy_addr[vb->i];
800 }
801
802 if (ovid->rotation_type == VOUT_ROT_VRFB)
803 return omap_vout_prepare_vrfb(vout, vb);
804 else
805 return 0;
806}
807
808/*
809 * Buffer queue function will be called from the videobuf layer when _QBUF
810 * ioctl is called. It is used to enqueue buffer, which is ready to be
811 * displayed.
812 */
813static void omap_vout_buffer_queue(struct videobuf_queue *q,
814 struct videobuf_buffer *vb)
815{
816 struct omap_vout_device *vout = q->priv_data;
817
818 /* Driver is also maintainig a queue. So enqueue buffer in the driver
819 * queue */
820 list_add_tail(&vb->queue, &vout->dma_queue);
821
822 vb->state = VIDEOBUF_QUEUED;
823}
824
825/*
826 * Buffer release function is called from videobuf layer to release buffer
827 * which are already allocated
828 */
829static void omap_vout_buffer_release(struct videobuf_queue *q,
830 struct videobuf_buffer *vb)
831{
832 struct omap_vout_device *vout = q->priv_data;
833
834 vb->state = VIDEOBUF_NEEDS_INIT;
835
836 if (V4L2_MEMORY_MMAP != vout->memory)
837 return;
838}
839
840/*
841 * File operations
842 */
843static unsigned int omap_vout_poll(struct file *file,
844 struct poll_table_struct *wait)
845{
846 struct omap_vout_device *vout = file->private_data;
847 struct videobuf_queue *q = &vout->vbq;
848
849 return videobuf_poll_stream(file, q, wait);
850}
851
852static void omap_vout_vm_open(struct vm_area_struct *vma)
853{
854 struct omap_vout_device *vout = vma->vm_private_data;
855
856 v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev,
857 "vm_open [vma=%08lx-%08lx]\n", vma->vm_start, vma->vm_end);
858 vout->mmap_count++;
859}
860
861static void omap_vout_vm_close(struct vm_area_struct *vma)
862{
863 struct omap_vout_device *vout = vma->vm_private_data;
864
865 v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev,
866 "vm_close [vma=%08lx-%08lx]\n", vma->vm_start, vma->vm_end);
867 vout->mmap_count--;
868}
869
870static struct vm_operations_struct omap_vout_vm_ops = {
871 .open = omap_vout_vm_open,
872 .close = omap_vout_vm_close,
873};
874
875static int omap_vout_mmap(struct file *file, struct vm_area_struct *vma)
876{
877 int i;
878 void *pos;
879 unsigned long start = vma->vm_start;
880 unsigned long size = (vma->vm_end - vma->vm_start);
881 struct omap_vout_device *vout = file->private_data;
882 struct videobuf_queue *q = &vout->vbq;
883
884 v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev,
885 " %s pgoff=0x%lx, start=0x%lx, end=0x%lx\n", __func__,
886 vma->vm_pgoff, vma->vm_start, vma->vm_end);
887
888 /* look for the buffer to map */
889 for (i = 0; i < VIDEO_MAX_FRAME; i++) {
890 if (NULL == q->bufs[i])
891 continue;
892 if (V4L2_MEMORY_MMAP != q->bufs[i]->memory)
893 continue;
894 if (q->bufs[i]->boff == (vma->vm_pgoff << PAGE_SHIFT))
895 break;
896 }
897
898 if (VIDEO_MAX_FRAME == i) {
899 v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev,
900 "offset invalid [offset=0x%lx]\n",
901 (vma->vm_pgoff << PAGE_SHIFT));
902 return -EINVAL;
903 }
904 /* Check the size of the buffer */
905 if (size > vout->buffer_size) {
906 v4l2_err(&vout->vid_dev->v4l2_dev,
907 "insufficient memory [%lu] [%u]\n",
908 size, vout->buffer_size);
909 return -ENOMEM;
910 }
911
912 q->bufs[i]->baddr = vma->vm_start;
913
914 vma->vm_flags |= VM_RESERVED;
915 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
916 vma->vm_ops = &omap_vout_vm_ops;
917 vma->vm_private_data = (void *) vout;
918 pos = (void *)vout->buf_virt_addr[i];
919 vma->vm_pgoff = virt_to_phys((void *)pos) >> PAGE_SHIFT;
920 while (size > 0) {
921 unsigned long pfn;
922 pfn = virt_to_phys((void *) pos) >> PAGE_SHIFT;
923 if (remap_pfn_range(vma, start, pfn, PAGE_SIZE, PAGE_SHARED))
924 return -EAGAIN;
925 start += PAGE_SIZE;
926 pos += PAGE_SIZE;
927 size -= PAGE_SIZE;
928 }
929 vout->mmap_count++;
930 v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Exiting %s\n", __func__);
931
932 return 0;
933}
934
935static int omap_vout_release(struct file *file)
936{
937 unsigned int ret, i;
938 struct videobuf_queue *q;
939 struct omapvideo_info *ovid;
940 struct omap_vout_device *vout = file->private_data;
941
942 v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Entering %s\n", __func__);
943 ovid = &vout->vid_info;
944
945 if (!vout)
946 return 0;
947
948 q = &vout->vbq;
949 /* Disable all the overlay managers connected with this interface */
950 for (i = 0; i < ovid->num_overlays; i++) {
951 struct omap_overlay *ovl = ovid->overlays[i];
952 if (ovl->manager && ovl->manager->device)
953 ovl->disable(ovl);
954 }
955 /* Turn off the pipeline */
956 ret = omapvid_apply_changes(vout);
957 if (ret)
958 v4l2_warn(&vout->vid_dev->v4l2_dev,
959 "Unable to apply changes\n");
960
961 /* Free all buffers */
962 omap_vout_free_extra_buffers(vout);
963
964 /* Free the VRFB buffers only if they are allocated
965 * during reqbufs. Don't free if init time allocated
966 */
967 if (ovid->rotation_type == VOUT_ROT_VRFB) {
968 if (!vout->vrfb_static_allocation)
969 omap_vout_free_vrfb_buffers(vout);
970 }
971 videobuf_mmap_free(q);
972
973 /* Even if apply changes fails we should continue
974 freeing allocated memory */
975 if (vout->streaming) {
976 u32 mask = 0;
977
978 mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN |
979 DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_VSYNC2;
980 omap_dispc_unregister_isr(omap_vout_isr, vout, mask);
981 vout->streaming = 0;
982
983 videobuf_streamoff(q);
984 videobuf_queue_cancel(q);
985 }
986
987 if (vout->mmap_count != 0)
988 vout->mmap_count = 0;
989
990 vout->opened -= 1;
991 file->private_data = NULL;
992
993 if (vout->buffer_allocated)
994 videobuf_mmap_free(q);
995
996 v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Exiting %s\n", __func__);
997 return ret;
998}
999
1000static int omap_vout_open(struct file *file)
1001{
1002 struct videobuf_queue *q;
1003 struct omap_vout_device *vout = NULL;
1004
1005 vout = video_drvdata(file);
1006 v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Entering %s\n", __func__);
1007
1008 if (vout == NULL)
1009 return -ENODEV;
1010
1011 /* for now, we only support single open */
1012 if (vout->opened)
1013 return -EBUSY;
1014
1015 vout->opened += 1;
1016
1017 file->private_data = vout;
1018 vout->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
1019
1020 q = &vout->vbq;
1021 video_vbq_ops.buf_setup = omap_vout_buffer_setup;
1022 video_vbq_ops.buf_prepare = omap_vout_buffer_prepare;
1023 video_vbq_ops.buf_release = omap_vout_buffer_release;
1024 video_vbq_ops.buf_queue = omap_vout_buffer_queue;
1025 spin_lock_init(&vout->vbq_lock);
1026
1027 videobuf_queue_dma_contig_init(q, &video_vbq_ops, q->dev,
1028 &vout->vbq_lock, vout->type, V4L2_FIELD_NONE,
1029 sizeof(struct videobuf_buffer), vout, NULL);
1030
1031 v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Exiting %s\n", __func__);
1032 return 0;
1033}
1034
1035/*
1036 * V4L2 ioctls
1037 */
1038static int vidioc_querycap(struct file *file, void *fh,
1039 struct v4l2_capability *cap)
1040{
1041 struct omap_vout_device *vout = fh;
1042
1043 strlcpy(cap->driver, VOUT_NAME, sizeof(cap->driver));
1044 strlcpy(cap->card, vout->vfd->name, sizeof(cap->card));
1045 cap->bus_info[0] = '\0';
1046 cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT |
1047 V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
1048
1049 return 0;
1050}
1051
1052static int vidioc_enum_fmt_vid_out(struct file *file, void *fh,
1053 struct v4l2_fmtdesc *fmt)
1054{
1055 int index = fmt->index;
1056
1057 if (index >= NUM_OUTPUT_FORMATS)
1058 return -EINVAL;
1059
1060 fmt->flags = omap_formats[index].flags;
1061 strlcpy(fmt->description, omap_formats[index].description,
1062 sizeof(fmt->description));
1063 fmt->pixelformat = omap_formats[index].pixelformat;
1064
1065 return 0;
1066}
1067
1068static int vidioc_g_fmt_vid_out(struct file *file, void *fh,
1069 struct v4l2_format *f)
1070{
1071 struct omap_vout_device *vout = fh;
1072
1073 f->fmt.pix = vout->pix;
1074 return 0;
1075
1076}
1077
1078static int vidioc_try_fmt_vid_out(struct file *file, void *fh,
1079 struct v4l2_format *f)
1080{
1081 struct omap_overlay *ovl;
1082 struct omapvideo_info *ovid;
1083 struct omap_video_timings *timing;
1084 struct omap_vout_device *vout = fh;
1085
1086 ovid = &vout->vid_info;
1087 ovl = ovid->overlays[0];
1088
1089 if (!ovl->manager || !ovl->manager->device)
1090 return -EINVAL;
1091 /* get the display device attached to the overlay */
1092 timing = &ovl->manager->device->panel.timings;
1093
1094 vout->fbuf.fmt.height = timing->y_res;
1095 vout->fbuf.fmt.width = timing->x_res;
1096
1097 omap_vout_try_format(&f->fmt.pix);
1098 return 0;
1099}
1100
1101static int vidioc_s_fmt_vid_out(struct file *file, void *fh,
1102 struct v4l2_format *f)
1103{
1104 int ret, bpp;
1105 struct omap_overlay *ovl;
1106 struct omapvideo_info *ovid;
1107 struct omap_video_timings *timing;
1108 struct omap_vout_device *vout = fh;
1109
1110 if (vout->streaming)
1111 return -EBUSY;
1112
1113 mutex_lock(&vout->lock);
1114
1115 ovid = &vout->vid_info;
1116 ovl = ovid->overlays[0];
1117
1118 /* get the display device attached to the overlay */
1119 if (!ovl->manager || !ovl->manager->device) {
1120 ret = -EINVAL;
1121 goto s_fmt_vid_out_exit;
1122 }
1123 timing = &ovl->manager->device->panel.timings;
1124
1125 /* We dont support RGB24-packed mode if vrfb rotation
1126 * is enabled*/
1127 if ((is_rotation_enabled(vout)) &&
1128 f->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24) {
1129 ret = -EINVAL;
1130 goto s_fmt_vid_out_exit;
1131 }
1132
1133 /* get the framebuffer parameters */
1134
1135 if (is_rotation_90_or_270(vout)) {
1136 vout->fbuf.fmt.height = timing->x_res;
1137 vout->fbuf.fmt.width = timing->y_res;
1138 } else {
1139 vout->fbuf.fmt.height = timing->y_res;
1140 vout->fbuf.fmt.width = timing->x_res;
1141 }
1142
1143 /* change to samller size is OK */
1144
1145 bpp = omap_vout_try_format(&f->fmt.pix);
1146 f->fmt.pix.sizeimage = f->fmt.pix.width * f->fmt.pix.height * bpp;
1147
1148 /* try & set the new output format */
1149 vout->bpp = bpp;
1150 vout->pix = f->fmt.pix;
1151 vout->vrfb_bpp = 1;
1152
1153 /* If YUYV then vrfb bpp is 2, for others its 1 */
1154 if (V4L2_PIX_FMT_YUYV == vout->pix.pixelformat ||
1155 V4L2_PIX_FMT_UYVY == vout->pix.pixelformat)
1156 vout->vrfb_bpp = 2;
1157
1158 /* set default crop and win */
1159 omap_vout_new_format(&vout->pix, &vout->fbuf, &vout->crop, &vout->win);
1160
1161 /* Save the changes in the overlay strcuture */
1162 ret = omapvid_init(vout, 0);
1163 if (ret) {
1164 v4l2_err(&vout->vid_dev->v4l2_dev, "failed to change mode\n");
1165 goto s_fmt_vid_out_exit;
1166 }
1167
1168 ret = 0;
1169
1170s_fmt_vid_out_exit:
1171 mutex_unlock(&vout->lock);
1172 return ret;
1173}
1174
1175static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh,
1176 struct v4l2_format *f)
1177{
1178 int ret = 0;
1179 struct omap_vout_device *vout = fh;
1180 struct omap_overlay *ovl;
1181 struct omapvideo_info *ovid;
1182 struct v4l2_window *win = &f->fmt.win;
1183
1184 ovid = &vout->vid_info;
1185 ovl = ovid->overlays[0];
1186
1187 ret = omap_vout_try_window(&vout->fbuf, win);
1188
1189 if (!ret) {
1190 if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
1191 win->global_alpha = 255;
1192 else
1193 win->global_alpha = f->fmt.win.global_alpha;
1194 }
1195
1196 return ret;
1197}
1198
1199static int vidioc_s_fmt_vid_overlay(struct file *file, void *fh,
1200 struct v4l2_format *f)
1201{
1202 int ret = 0;
1203 struct omap_overlay *ovl;
1204 struct omapvideo_info *ovid;
1205 struct omap_vout_device *vout = fh;
1206 struct v4l2_window *win = &f->fmt.win;
1207
1208 mutex_lock(&vout->lock);
1209 ovid = &vout->vid_info;
1210 ovl = ovid->overlays[0];
1211
1212 ret = omap_vout_new_window(&vout->crop, &vout->win, &vout->fbuf, win);
1213 if (!ret) {
1214 /* Video1 plane does not support global alpha on OMAP3 */
1215 if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
1216 vout->win.global_alpha = 255;
1217 else
1218 vout->win.global_alpha = f->fmt.win.global_alpha;
1219
1220 vout->win.chromakey = f->fmt.win.chromakey;
1221 }
1222 mutex_unlock(&vout->lock);
1223 return ret;
1224}
1225
1226static int vidioc_enum_fmt_vid_overlay(struct file *file, void *fh,
1227 struct v4l2_fmtdesc *fmt)
1228{
1229 int index = fmt->index;
1230
1231 if (index >= NUM_OUTPUT_FORMATS)
1232 return -EINVAL;
1233
1234 fmt->flags = omap_formats[index].flags;
1235 strlcpy(fmt->description, omap_formats[index].description,
1236 sizeof(fmt->description));
1237 fmt->pixelformat = omap_formats[index].pixelformat;
1238 return 0;
1239}
1240
1241static int vidioc_g_fmt_vid_overlay(struct file *file, void *fh,
1242 struct v4l2_format *f)
1243{
1244 u32 key_value = 0;
1245 struct omap_overlay *ovl;
1246 struct omapvideo_info *ovid;
1247 struct omap_vout_device *vout = fh;
1248 struct omap_overlay_manager_info info;
1249 struct v4l2_window *win = &f->fmt.win;
1250
1251 ovid = &vout->vid_info;
1252 ovl = ovid->overlays[0];
1253
1254 win->w = vout->win.w;
1255 win->field = vout->win.field;
1256 win->global_alpha = vout->win.global_alpha;
1257
1258 if (ovl->manager && ovl->manager->get_manager_info) {
1259 ovl->manager->get_manager_info(ovl->manager, &info);
1260 key_value = info.trans_key;
1261 }
1262 win->chromakey = key_value;
1263 return 0;
1264}
1265
1266static int vidioc_cropcap(struct file *file, void *fh,
1267 struct v4l2_cropcap *cropcap)
1268{
1269 struct omap_vout_device *vout = fh;
1270 struct v4l2_pix_format *pix = &vout->pix;
1271
1272 if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
1273 return -EINVAL;
1274
1275 /* Width and height are always even */
1276 cropcap->bounds.width = pix->width & ~1;
1277 cropcap->bounds.height = pix->height & ~1;
1278
1279 omap_vout_default_crop(&vout->pix, &vout->fbuf, &cropcap->defrect);
1280 cropcap->pixelaspect.numerator = 1;
1281 cropcap->pixelaspect.denominator = 1;
1282 return 0;
1283}
1284
1285static int vidioc_g_crop(struct file *file, void *fh, struct v4l2_crop *crop)
1286{
1287 struct omap_vout_device *vout = fh;
1288
1289 if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
1290 return -EINVAL;
1291 crop->c = vout->crop;
1292 return 0;
1293}
1294
1295static int vidioc_s_crop(struct file *file, void *fh, const struct v4l2_crop *crop)
1296{
1297 int ret = -EINVAL;
1298 struct omap_vout_device *vout = fh;
1299 struct omapvideo_info *ovid;
1300 struct omap_overlay *ovl;
1301 struct omap_video_timings *timing;
1302
1303 if (vout->streaming)
1304 return -EBUSY;
1305
1306 mutex_lock(&vout->lock);
1307 ovid = &vout->vid_info;
1308 ovl = ovid->overlays[0];
1309
1310 if (!ovl->manager || !ovl->manager->device) {
1311 ret = -EINVAL;
1312 goto s_crop_err;
1313 }
1314 /* get the display device attached to the overlay */
1315 timing = &ovl->manager->device->panel.timings;
1316
1317 if (is_rotation_90_or_270(vout)) {
1318 vout->fbuf.fmt.height = timing->x_res;
1319 vout->fbuf.fmt.width = timing->y_res;
1320 } else {
1321 vout->fbuf.fmt.height = timing->y_res;
1322 vout->fbuf.fmt.width = timing->x_res;
1323 }
1324
1325 if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
1326 ret = omap_vout_new_crop(&vout->pix, &vout->crop, &vout->win,
1327 &vout->fbuf, &crop->c);
1328
1329s_crop_err:
1330 mutex_unlock(&vout->lock);
1331 return ret;
1332}
1333
1334static int vidioc_queryctrl(struct file *file, void *fh,
1335 struct v4l2_queryctrl *ctrl)
1336{
1337 int ret = 0;
1338
1339 switch (ctrl->id) {
1340 case V4L2_CID_ROTATE:
1341 ret = v4l2_ctrl_query_fill(ctrl, 0, 270, 90, 0);
1342 break;
1343 case V4L2_CID_BG_COLOR:
1344 ret = v4l2_ctrl_query_fill(ctrl, 0, 0xFFFFFF, 1, 0);
1345 break;
1346 case V4L2_CID_VFLIP:
1347 ret = v4l2_ctrl_query_fill(ctrl, 0, 1, 1, 0);
1348 break;
1349 default:
1350 ctrl->name[0] = '\0';
1351 ret = -EINVAL;
1352 }
1353 return ret;
1354}
1355
1356static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *ctrl)
1357{
1358 int ret = 0;
1359 struct omap_vout_device *vout = fh;
1360
1361 switch (ctrl->id) {
1362 case V4L2_CID_ROTATE:
1363 ctrl->value = vout->control[0].value;
1364 break;
1365 case V4L2_CID_BG_COLOR:
1366 {
1367 struct omap_overlay_manager_info info;
1368 struct omap_overlay *ovl;
1369
1370 ovl = vout->vid_info.overlays[0];
1371 if (!ovl->manager || !ovl->manager->get_manager_info) {
1372 ret = -EINVAL;
1373 break;
1374 }
1375
1376 ovl->manager->get_manager_info(ovl->manager, &info);
1377 ctrl->value = info.default_color;
1378 break;
1379 }
1380 case V4L2_CID_VFLIP:
1381 ctrl->value = vout->control[2].value;
1382 break;
1383 default:
1384 ret = -EINVAL;
1385 }
1386 return ret;
1387}
1388
1389static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *a)
1390{
1391 int ret = 0;
1392 struct omap_vout_device *vout = fh;
1393
1394 switch (a->id) {
1395 case V4L2_CID_ROTATE:
1396 {
1397 struct omapvideo_info *ovid;
1398 int rotation = a->value;
1399
1400 ovid = &vout->vid_info;
1401
1402 mutex_lock(&vout->lock);
1403 if (rotation && ovid->rotation_type == VOUT_ROT_NONE) {
1404 mutex_unlock(&vout->lock);
1405 ret = -ERANGE;
1406 break;
1407 }
1408
1409 if (rotation && vout->pix.pixelformat == V4L2_PIX_FMT_RGB24) {
1410 mutex_unlock(&vout->lock);
1411 ret = -EINVAL;
1412 break;
1413 }
1414
1415 if (v4l2_rot_to_dss_rot(rotation, &vout->rotation,
1416 vout->mirror)) {
1417 mutex_unlock(&vout->lock);
1418 ret = -EINVAL;
1419 break;
1420 }
1421
1422 vout->control[0].value = rotation;
1423 mutex_unlock(&vout->lock);
1424 break;
1425 }
1426 case V4L2_CID_BG_COLOR:
1427 {
1428 struct omap_overlay *ovl;
1429 unsigned int color = a->value;
1430 struct omap_overlay_manager_info info;
1431
1432 ovl = vout->vid_info.overlays[0];
1433
1434 mutex_lock(&vout->lock);
1435 if (!ovl->manager || !ovl->manager->get_manager_info) {
1436 mutex_unlock(&vout->lock);
1437 ret = -EINVAL;
1438 break;
1439 }
1440
1441 ovl->manager->get_manager_info(ovl->manager, &info);
1442 info.default_color = color;
1443 if (ovl->manager->set_manager_info(ovl->manager, &info)) {
1444 mutex_unlock(&vout->lock);
1445 ret = -EINVAL;
1446 break;
1447 }
1448
1449 vout->control[1].value = color;
1450 mutex_unlock(&vout->lock);
1451 break;
1452 }
1453 case V4L2_CID_VFLIP:
1454 {
1455 struct omap_overlay *ovl;
1456 struct omapvideo_info *ovid;
1457 unsigned int mirror = a->value;
1458
1459 ovid = &vout->vid_info;
1460 ovl = ovid->overlays[0];
1461
1462 mutex_lock(&vout->lock);
1463 if (mirror && ovid->rotation_type == VOUT_ROT_NONE) {
1464 mutex_unlock(&vout->lock);
1465 ret = -ERANGE;
1466 break;
1467 }
1468
1469 if (mirror && vout->pix.pixelformat == V4L2_PIX_FMT_RGB24) {
1470 mutex_unlock(&vout->lock);
1471 ret = -EINVAL;
1472 break;
1473 }
1474 vout->mirror = mirror;
1475 vout->control[2].value = mirror;
1476 mutex_unlock(&vout->lock);
1477 break;
1478 }
1479 default:
1480 ret = -EINVAL;
1481 }
1482 return ret;
1483}
1484
1485static int vidioc_reqbufs(struct file *file, void *fh,
1486 struct v4l2_requestbuffers *req)
1487{
1488 int ret = 0;
1489 unsigned int i, num_buffers = 0;
1490 struct omap_vout_device *vout = fh;
1491 struct videobuf_queue *q = &vout->vbq;
1492
1493 if ((req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) || (req->count < 0))
1494 return -EINVAL;
1495 /* if memory is not mmp or userptr
1496 return error */
1497 if ((V4L2_MEMORY_MMAP != req->memory) &&
1498 (V4L2_MEMORY_USERPTR != req->memory))
1499 return -EINVAL;
1500
1501 mutex_lock(&vout->lock);
1502 /* Cannot be requested when streaming is on */
1503 if (vout->streaming) {
1504 ret = -EBUSY;
1505 goto reqbuf_err;
1506 }
1507
1508 /* If buffers are already allocated free them */
1509 if (q->bufs[0] && (V4L2_MEMORY_MMAP == q->bufs[0]->memory)) {
1510 if (vout->mmap_count) {
1511 ret = -EBUSY;
1512 goto reqbuf_err;
1513 }
1514 num_buffers = (vout->vid == OMAP_VIDEO1) ?
1515 video1_numbuffers : video2_numbuffers;
1516 for (i = num_buffers; i < vout->buffer_allocated; i++) {
1517 omap_vout_free_buffer(vout->buf_virt_addr[i],
1518 vout->buffer_size);
1519 vout->buf_virt_addr[i] = 0;
1520 vout->buf_phy_addr[i] = 0;
1521 }
1522 vout->buffer_allocated = num_buffers;
1523 videobuf_mmap_free(q);
1524 } else if (q->bufs[0] && (V4L2_MEMORY_USERPTR == q->bufs[0]->memory)) {
1525 if (vout->buffer_allocated) {
1526 videobuf_mmap_free(q);
1527 for (i = 0; i < vout->buffer_allocated; i++) {
1528 kfree(q->bufs[i]);
1529 q->bufs[i] = NULL;
1530 }
1531 vout->buffer_allocated = 0;
1532 }
1533 }
1534
1535 /*store the memory type in data structure */
1536 vout->memory = req->memory;
1537
1538 INIT_LIST_HEAD(&vout->dma_queue);
1539
1540 /* call videobuf_reqbufs api */
1541 ret = videobuf_reqbufs(q, req);
1542 if (ret < 0)
1543 goto reqbuf_err;
1544
1545 vout->buffer_allocated = req->count;
1546
1547reqbuf_err:
1548 mutex_unlock(&vout->lock);
1549 return ret;
1550}
1551
1552static int vidioc_querybuf(struct file *file, void *fh,
1553 struct v4l2_buffer *b)
1554{
1555 struct omap_vout_device *vout = fh;
1556
1557 return videobuf_querybuf(&vout->vbq, b);
1558}
1559
1560static int vidioc_qbuf(struct file *file, void *fh,
1561 struct v4l2_buffer *buffer)
1562{
1563 struct omap_vout_device *vout = fh;
1564 struct videobuf_queue *q = &vout->vbq;
1565
1566 if ((V4L2_BUF_TYPE_VIDEO_OUTPUT != buffer->type) ||
1567 (buffer->index >= vout->buffer_allocated) ||
1568 (q->bufs[buffer->index]->memory != buffer->memory)) {
1569 return -EINVAL;
1570 }
1571 if (V4L2_MEMORY_USERPTR == buffer->memory) {
1572 if ((buffer->length < vout->pix.sizeimage) ||
1573 (0 == buffer->m.userptr)) {
1574 return -EINVAL;
1575 }
1576 }
1577
1578 if ((is_rotation_enabled(vout)) &&
1579 vout->vrfb_dma_tx.req_status == DMA_CHAN_NOT_ALLOTED) {
1580 v4l2_warn(&vout->vid_dev->v4l2_dev,
1581 "DMA Channel not allocated for Rotation\n");
1582 return -EINVAL;
1583 }
1584
1585 return videobuf_qbuf(q, buffer);
1586}
1587
1588static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
1589{
1590 struct omap_vout_device *vout = fh;
1591 struct videobuf_queue *q = &vout->vbq;
1592
1593 int ret;
1594 u32 addr;
1595 unsigned long size;
1596 struct videobuf_buffer *vb;
1597
1598 vb = q->bufs[b->index];
1599
1600 if (!vout->streaming)
1601 return -EINVAL;
1602
1603 if (file->f_flags & O_NONBLOCK)
1604 /* Call videobuf_dqbuf for non blocking mode */
1605 ret = videobuf_dqbuf(q, (struct v4l2_buffer *)b, 1);
1606 else
1607 /* Call videobuf_dqbuf for blocking mode */
1608 ret = videobuf_dqbuf(q, (struct v4l2_buffer *)b, 0);
1609
1610 addr = (unsigned long) vout->buf_phy_addr[vb->i];
1611 size = (unsigned long) vb->size;
1612 dma_unmap_single(vout->vid_dev->v4l2_dev.dev, addr,
1613 size, DMA_TO_DEVICE);
1614 return ret;
1615}
1616
1617static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
1618{
1619 int ret = 0, j;
1620 u32 addr = 0, mask = 0;
1621 struct omap_vout_device *vout = fh;
1622 struct videobuf_queue *q = &vout->vbq;
1623 struct omapvideo_info *ovid = &vout->vid_info;
1624
1625 mutex_lock(&vout->lock);
1626
1627 if (vout->streaming) {
1628 ret = -EBUSY;
1629 goto streamon_err;
1630 }
1631
1632 ret = videobuf_streamon(q);
1633 if (ret)
1634 goto streamon_err;
1635
1636 if (list_empty(&vout->dma_queue)) {
1637 ret = -EIO;
1638 goto streamon_err1;
1639 }
1640
1641 /* Get the next frame from the buffer queue */
1642 vout->next_frm = vout->cur_frm = list_entry(vout->dma_queue.next,
1643 struct videobuf_buffer, queue);
1644 /* Remove buffer from the buffer queue */
1645 list_del(&vout->cur_frm->queue);
1646 /* Mark state of the current frame to active */
1647 vout->cur_frm->state = VIDEOBUF_ACTIVE;
1648 /* Initialize field_id and started member */
1649 vout->field_id = 0;
1650
1651 /* set flag here. Next QBUF will start DMA */
1652 vout->streaming = 1;
1653
1654 vout->first_int = 1;
1655
1656 if (omap_vout_calculate_offset(vout)) {
1657 ret = -EINVAL;
1658 goto streamon_err1;
1659 }
1660 addr = (unsigned long) vout->queued_buf_addr[vout->cur_frm->i]
1661 + vout->cropped_offset;
1662
1663 mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD
1664 | DISPC_IRQ_VSYNC2;
1665
1666 omap_dispc_register_isr(omap_vout_isr, vout, mask);
1667
1668 for (j = 0; j < ovid->num_overlays; j++) {
1669 struct omap_overlay *ovl = ovid->overlays[j];
1670
1671 if (ovl->manager && ovl->manager->device) {
1672 struct omap_overlay_info info;
1673 ovl->get_overlay_info(ovl, &info);
1674 info.paddr = addr;
1675 if (ovl->set_overlay_info(ovl, &info)) {
1676 ret = -EINVAL;
1677 goto streamon_err1;
1678 }
1679 }
1680 }
1681
1682 /* First save the configuration in ovelray structure */
1683 ret = omapvid_init(vout, addr);
1684 if (ret)
1685 v4l2_err(&vout->vid_dev->v4l2_dev,
1686 "failed to set overlay info\n");
1687 /* Enable the pipeline and set the Go bit */
1688 ret = omapvid_apply_changes(vout);
1689 if (ret)
1690 v4l2_err(&vout->vid_dev->v4l2_dev, "failed to change mode\n");
1691
1692 for (j = 0; j < ovid->num_overlays; j++) {
1693 struct omap_overlay *ovl = ovid->overlays[j];
1694
1695 if (ovl->manager && ovl->manager->device) {
1696 ret = ovl->enable(ovl);
1697 if (ret)
1698 goto streamon_err1;
1699 }
1700 }
1701
1702 ret = 0;
1703
1704streamon_err1:
1705 if (ret)
1706 ret = videobuf_streamoff(q);
1707streamon_err:
1708 mutex_unlock(&vout->lock);
1709 return ret;
1710}
1711
1712static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
1713{
1714 u32 mask = 0;
1715 int ret = 0, j;
1716 struct omap_vout_device *vout = fh;
1717 struct omapvideo_info *ovid = &vout->vid_info;
1718
1719 if (!vout->streaming)
1720 return -EINVAL;
1721
1722 vout->streaming = 0;
1723 mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD
1724 | DISPC_IRQ_VSYNC2;
1725
1726 omap_dispc_unregister_isr(omap_vout_isr, vout, mask);
1727
1728 for (j = 0; j < ovid->num_overlays; j++) {
1729 struct omap_overlay *ovl = ovid->overlays[j];
1730
1731 if (ovl->manager && ovl->manager->device)
1732 ovl->disable(ovl);
1733 }
1734
1735 /* Turn of the pipeline */
1736 ret = omapvid_apply_changes(vout);
1737 if (ret)
1738 v4l2_err(&vout->vid_dev->v4l2_dev, "failed to change mode in"
1739 " streamoff\n");
1740
1741 INIT_LIST_HEAD(&vout->dma_queue);
1742 ret = videobuf_streamoff(&vout->vbq);
1743
1744 return ret;
1745}
1746
1747static int vidioc_s_fbuf(struct file *file, void *fh,
1748 const struct v4l2_framebuffer *a)
1749{
1750 int enable = 0;
1751 struct omap_overlay *ovl;
1752 struct omapvideo_info *ovid;
1753 struct omap_vout_device *vout = fh;
1754 struct omap_overlay_manager_info info;
1755 enum omap_dss_trans_key_type key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
1756
1757 ovid = &vout->vid_info;
1758 ovl = ovid->overlays[0];
1759
1760 /* OMAP DSS doesn't support Source and Destination color
1761 key together */
1762 if ((a->flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY) &&
1763 (a->flags & V4L2_FBUF_FLAG_CHROMAKEY))
1764 return -EINVAL;
1765 /* OMAP DSS Doesn't support the Destination color key
1766 and alpha blending together */
1767 if ((a->flags & V4L2_FBUF_FLAG_CHROMAKEY) &&
1768 (a->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA))
1769 return -EINVAL;
1770
1771 if ((a->flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY)) {
1772 vout->fbuf.flags |= V4L2_FBUF_FLAG_SRC_CHROMAKEY;
1773 key_type = OMAP_DSS_COLOR_KEY_VID_SRC;
1774 } else
1775 vout->fbuf.flags &= ~V4L2_FBUF_FLAG_SRC_CHROMAKEY;
1776
1777 if ((a->flags & V4L2_FBUF_FLAG_CHROMAKEY)) {
1778 vout->fbuf.flags |= V4L2_FBUF_FLAG_CHROMAKEY;
1779 key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
1780 } else
1781 vout->fbuf.flags &= ~V4L2_FBUF_FLAG_CHROMAKEY;
1782
1783 if (a->flags & (V4L2_FBUF_FLAG_CHROMAKEY |
1784 V4L2_FBUF_FLAG_SRC_CHROMAKEY))
1785 enable = 1;
1786 else
1787 enable = 0;
1788 if (ovl->manager && ovl->manager->get_manager_info &&
1789 ovl->manager->set_manager_info) {
1790
1791 ovl->manager->get_manager_info(ovl->manager, &info);
1792 info.trans_enabled = enable;
1793 info.trans_key_type = key_type;
1794 info.trans_key = vout->win.chromakey;
1795
1796 if (ovl->manager->set_manager_info(ovl->manager, &info))
1797 return -EINVAL;
1798 }
1799 if (a->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) {
1800 vout->fbuf.flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
1801 enable = 1;
1802 } else {
1803 vout->fbuf.flags &= ~V4L2_FBUF_FLAG_LOCAL_ALPHA;
1804 enable = 0;
1805 }
1806 if (ovl->manager && ovl->manager->get_manager_info &&
1807 ovl->manager->set_manager_info) {
1808 ovl->manager->get_manager_info(ovl->manager, &info);
1809 /* enable this only if there is no zorder cap */
1810 if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)
1811 info.partial_alpha_enabled = enable;
1812 if (ovl->manager->set_manager_info(ovl->manager, &info))
1813 return -EINVAL;
1814 }
1815
1816 return 0;
1817}
1818
1819static int vidioc_g_fbuf(struct file *file, void *fh,
1820 struct v4l2_framebuffer *a)
1821{
1822 struct omap_overlay *ovl;
1823 struct omapvideo_info *ovid;
1824 struct omap_vout_device *vout = fh;
1825 struct omap_overlay_manager_info info;
1826
1827 ovid = &vout->vid_info;
1828 ovl = ovid->overlays[0];
1829
1830 /* The video overlay must stay within the framebuffer and can't be
1831 positioned independently. */
1832 a->flags = V4L2_FBUF_FLAG_OVERLAY;
1833 a->capability = V4L2_FBUF_CAP_LOCAL_ALPHA | V4L2_FBUF_CAP_CHROMAKEY
1834 | V4L2_FBUF_CAP_SRC_CHROMAKEY;
1835
1836 if (ovl->manager && ovl->manager->get_manager_info) {
1837 ovl->manager->get_manager_info(ovl->manager, &info);
1838 if (info.trans_key_type == OMAP_DSS_COLOR_KEY_VID_SRC)
1839 a->flags |= V4L2_FBUF_FLAG_SRC_CHROMAKEY;
1840 if (info.trans_key_type == OMAP_DSS_COLOR_KEY_GFX_DST)
1841 a->flags |= V4L2_FBUF_FLAG_CHROMAKEY;
1842 }
1843 if (ovl->manager && ovl->manager->get_manager_info) {
1844 ovl->manager->get_manager_info(ovl->manager, &info);
1845 if (info.partial_alpha_enabled)
1846 a->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
1847 }
1848
1849 return 0;
1850}
1851
1852static const struct v4l2_ioctl_ops vout_ioctl_ops = {
1853 .vidioc_querycap = vidioc_querycap,
1854 .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
1855 .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out,
1856 .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
1857 .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out,
1858 .vidioc_queryctrl = vidioc_queryctrl,
1859 .vidioc_g_ctrl = vidioc_g_ctrl,
1860 .vidioc_s_fbuf = vidioc_s_fbuf,
1861 .vidioc_g_fbuf = vidioc_g_fbuf,
1862 .vidioc_s_ctrl = vidioc_s_ctrl,
1863 .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_vid_overlay,
1864 .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_vid_overlay,
1865 .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt_vid_overlay,
1866 .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_vid_overlay,
1867 .vidioc_cropcap = vidioc_cropcap,
1868 .vidioc_g_crop = vidioc_g_crop,
1869 .vidioc_s_crop = vidioc_s_crop,
1870 .vidioc_reqbufs = vidioc_reqbufs,
1871 .vidioc_querybuf = vidioc_querybuf,
1872 .vidioc_qbuf = vidioc_qbuf,
1873 .vidioc_dqbuf = vidioc_dqbuf,
1874 .vidioc_streamon = vidioc_streamon,
1875 .vidioc_streamoff = vidioc_streamoff,
1876};
1877
1878static const struct v4l2_file_operations omap_vout_fops = {
1879 .owner = THIS_MODULE,
1880 .poll = omap_vout_poll,
1881 .unlocked_ioctl = video_ioctl2,
1882 .mmap = omap_vout_mmap,
1883 .open = omap_vout_open,
1884 .release = omap_vout_release,
1885};
1886
1887/* Init functions used during driver initialization */
1888/* Initial setup of video_data */
1889static int __init omap_vout_setup_video_data(struct omap_vout_device *vout)
1890{
1891 struct video_device *vfd;
1892 struct v4l2_pix_format *pix;
1893 struct v4l2_control *control;
1894 struct omap_dss_device *display =
1895 vout->vid_info.overlays[0]->manager->device;
1896
1897 /* set the default pix */
1898 pix = &vout->pix;
1899
1900 /* Set the default picture of QVGA */
1901 pix->width = QQVGA_WIDTH;
1902 pix->height = QQVGA_HEIGHT;
1903
1904 /* Default pixel format is RGB 5-6-5 */
1905 pix->pixelformat = V4L2_PIX_FMT_RGB565;
1906 pix->field = V4L2_FIELD_ANY;
1907 pix->bytesperline = pix->width * 2;
1908 pix->sizeimage = pix->bytesperline * pix->height;
1909 pix->priv = 0;
1910 pix->colorspace = V4L2_COLORSPACE_JPEG;
1911
1912 vout->bpp = RGB565_BPP;
1913 vout->fbuf.fmt.width = display->panel.timings.x_res;
1914 vout->fbuf.fmt.height = display->panel.timings.y_res;
1915
1916 /* Set the data structures for the overlay parameters*/
1917 vout->win.global_alpha = 255;
1918 vout->fbuf.flags = 0;
1919 vout->fbuf.capability = V4L2_FBUF_CAP_LOCAL_ALPHA |
1920 V4L2_FBUF_CAP_SRC_CHROMAKEY | V4L2_FBUF_CAP_CHROMAKEY;
1921 vout->win.chromakey = 0;
1922
1923 omap_vout_new_format(pix, &vout->fbuf, &vout->crop, &vout->win);
1924
1925 /*Initialize the control variables for
1926 rotation, flipping and background color. */
1927 control = vout->control;
1928 control[0].id = V4L2_CID_ROTATE;
1929 control[0].value = 0;
1930 vout->rotation = 0;
1931 vout->mirror = 0;
1932 vout->control[2].id = V4L2_CID_HFLIP;
1933 vout->control[2].value = 0;
1934 if (vout->vid_info.rotation_type == VOUT_ROT_VRFB)
1935 vout->vrfb_bpp = 2;
1936
1937 control[1].id = V4L2_CID_BG_COLOR;
1938 control[1].value = 0;
1939
1940 /* initialize the video_device struct */
1941 vfd = vout->vfd = video_device_alloc();
1942
1943 if (!vfd) {
1944 printk(KERN_ERR VOUT_NAME ": could not allocate"
1945 " video device struct\n");
1946 return -ENOMEM;
1947 }
1948 vfd->release = video_device_release;
1949 vfd->ioctl_ops = &vout_ioctl_ops;
1950
1951 strlcpy(vfd->name, VOUT_NAME, sizeof(vfd->name));
1952
1953 vfd->fops = &omap_vout_fops;
1954 vfd->v4l2_dev = &vout->vid_dev->v4l2_dev;
1955 vfd->vfl_dir = VFL_DIR_TX;
1956 mutex_init(&vout->lock);
1957
1958 vfd->minor = -1;
1959 return 0;
1960
1961}
1962
1963/* Setup video buffers */
1964static int __init omap_vout_setup_video_bufs(struct platform_device *pdev,
1965 int vid_num)
1966{
1967 u32 numbuffers;
1968 int ret = 0, i;
1969 struct omapvideo_info *ovid;
1970 struct omap_vout_device *vout;
1971 struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
1972 struct omap2video_device *vid_dev =
1973 container_of(v4l2_dev, struct omap2video_device, v4l2_dev);
1974
1975 vout = vid_dev->vouts[vid_num];
1976 ovid = &vout->vid_info;
1977
1978 numbuffers = (vid_num == 0) ? video1_numbuffers : video2_numbuffers;
1979 vout->buffer_size = (vid_num == 0) ? video1_bufsize : video2_bufsize;
1980 dev_info(&pdev->dev, "Buffer Size = %d\n", vout->buffer_size);
1981
1982 for (i = 0; i < numbuffers; i++) {
1983 vout->buf_virt_addr[i] =
1984 omap_vout_alloc_buffer(vout->buffer_size,
1985 (u32 *) &vout->buf_phy_addr[i]);
1986 if (!vout->buf_virt_addr[i]) {
1987 numbuffers = i;
1988 ret = -ENOMEM;
1989 goto free_buffers;
1990 }
1991 }
1992
1993 vout->cropped_offset = 0;
1994
1995 if (ovid->rotation_type == VOUT_ROT_VRFB) {
1996 int static_vrfb_allocation = (vid_num == 0) ?
1997 vid1_static_vrfb_alloc : vid2_static_vrfb_alloc;
1998 ret = omap_vout_setup_vrfb_bufs(pdev, vid_num,
1999 static_vrfb_allocation);
2000 }
2001
2002 return ret;
2003
2004free_buffers:
2005 for (i = 0; i < numbuffers; i++) {
2006 omap_vout_free_buffer(vout->buf_virt_addr[i],
2007 vout->buffer_size);
2008 vout->buf_virt_addr[i] = 0;
2009 vout->buf_phy_addr[i] = 0;
2010 }
2011 return ret;
2012
2013}
2014
2015/* Create video out devices */
2016static int __init omap_vout_create_video_devices(struct platform_device *pdev)
2017{
2018 int ret = 0, k;
2019 struct omap_vout_device *vout;
2020 struct video_device *vfd = NULL;
2021 struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
2022 struct omap2video_device *vid_dev = container_of(v4l2_dev,
2023 struct omap2video_device, v4l2_dev);
2024
2025 for (k = 0; k < pdev->num_resources; k++) {
2026
2027 vout = kzalloc(sizeof(struct omap_vout_device), GFP_KERNEL);
2028 if (!vout) {
2029 dev_err(&pdev->dev, ": could not allocate memory\n");
2030 return -ENOMEM;
2031 }
2032
2033 vout->vid = k;
2034 vid_dev->vouts[k] = vout;
2035 vout->vid_dev = vid_dev;
2036 /* Select video2 if only 1 overlay is controlled by V4L2 */
2037 if (pdev->num_resources == 1)
2038 vout->vid_info.overlays[0] = vid_dev->overlays[k + 2];
2039 else
2040 /* Else select video1 and video2 one by one. */
2041 vout->vid_info.overlays[0] = vid_dev->overlays[k + 1];
2042 vout->vid_info.num_overlays = 1;
2043 vout->vid_info.id = k + 1;
2044
2045 /* Set VRFB as rotation_type for omap2 and omap3 */
2046 if (cpu_is_omap24xx() || cpu_is_omap34xx())
2047 vout->vid_info.rotation_type = VOUT_ROT_VRFB;
2048
2049 /* Setup the default configuration for the video devices
2050 */
2051 if (omap_vout_setup_video_data(vout) != 0) {
2052 ret = -ENOMEM;
2053 goto error;
2054 }
2055
2056 /* Allocate default number of buffers for the video streaming
2057 * and reserve the VRFB space for rotation
2058 */
2059 if (omap_vout_setup_video_bufs(pdev, k) != 0) {
2060 ret = -ENOMEM;
2061 goto error1;
2062 }
2063
2064 /* Register the Video device with V4L2
2065 */
2066 vfd = vout->vfd;
2067 if (video_register_device(vfd, VFL_TYPE_GRABBER, -1) < 0) {
2068 dev_err(&pdev->dev, ": Could not register "
2069 "Video for Linux device\n");
2070 vfd->minor = -1;
2071 ret = -ENODEV;
2072 goto error2;
2073 }
2074 video_set_drvdata(vfd, vout);
2075
2076 /* Configure the overlay structure */
2077 ret = omapvid_init(vid_dev->vouts[k], 0);
2078 if (!ret)
2079 goto success;
2080
2081error2:
2082 if (vout->vid_info.rotation_type == VOUT_ROT_VRFB)
2083 omap_vout_release_vrfb(vout);
2084 omap_vout_free_buffers(vout);
2085error1:
2086 video_device_release(vfd);
2087error:
2088 kfree(vout);
2089 return ret;
2090
2091success:
2092 dev_info(&pdev->dev, ": registered and initialized"
2093 " video device %d\n", vfd->minor);
2094 if (k == (pdev->num_resources - 1))
2095 return 0;
2096 }
2097
2098 return -ENODEV;
2099}
2100/* Driver functions */
2101static void omap_vout_cleanup_device(struct omap_vout_device *vout)
2102{
2103 struct video_device *vfd;
2104 struct omapvideo_info *ovid;
2105
2106 if (!vout)
2107 return;
2108
2109 vfd = vout->vfd;
2110 ovid = &vout->vid_info;
2111 if (vfd) {
2112 if (!video_is_registered(vfd)) {
2113 /*
2114 * The device was never registered, so release the
2115 * video_device struct directly.
2116 */
2117 video_device_release(vfd);
2118 } else {
2119 /*
2120 * The unregister function will release the video_device
2121 * struct as well as unregistering it.
2122 */
2123 video_unregister_device(vfd);
2124 }
2125 }
2126 if (ovid->rotation_type == VOUT_ROT_VRFB) {
2127 omap_vout_release_vrfb(vout);
2128 /* Free the VRFB buffer if allocated
2129 * init time
2130 */
2131 if (vout->vrfb_static_allocation)
2132 omap_vout_free_vrfb_buffers(vout);
2133 }
2134 omap_vout_free_buffers(vout);
2135
2136 kfree(vout);
2137}
2138
2139static int omap_vout_remove(struct platform_device *pdev)
2140{
2141 int k;
2142 struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
2143 struct omap2video_device *vid_dev = container_of(v4l2_dev, struct
2144 omap2video_device, v4l2_dev);
2145
2146 v4l2_device_unregister(v4l2_dev);
2147 for (k = 0; k < pdev->num_resources; k++)
2148 omap_vout_cleanup_device(vid_dev->vouts[k]);
2149
2150 for (k = 0; k < vid_dev->num_displays; k++) {
2151 if (vid_dev->displays[k]->state != OMAP_DSS_DISPLAY_DISABLED)
2152 vid_dev->displays[k]->driver->disable(vid_dev->displays[k]);
2153
2154 omap_dss_put_device(vid_dev->displays[k]);
2155 }
2156 kfree(vid_dev);
2157 return 0;
2158}
2159
2160static int __init omap_vout_probe(struct platform_device *pdev)
2161{
2162 int ret = 0, i;
2163 struct omap_overlay *ovl;
2164 struct omap_dss_device *dssdev = NULL;
2165 struct omap_dss_device *def_display;
2166 struct omap2video_device *vid_dev = NULL;
2167
2168 if (pdev->num_resources == 0) {
2169 dev_err(&pdev->dev, "probed for an unknown device\n");
2170 return -ENODEV;
2171 }
2172
2173 vid_dev = kzalloc(sizeof(struct omap2video_device), GFP_KERNEL);
2174 if (vid_dev == NULL)
2175 return -ENOMEM;
2176
2177 vid_dev->num_displays = 0;
2178 for_each_dss_dev(dssdev) {
2179 omap_dss_get_device(dssdev);
2180
2181 if (!dssdev->driver) {
2182 dev_warn(&pdev->dev, "no driver for display: %s\n",
2183 dssdev->name);
2184 omap_dss_put_device(dssdev);
2185 continue;
2186 }
2187
2188 vid_dev->displays[vid_dev->num_displays++] = dssdev;
2189 }
2190
2191 if (vid_dev->num_displays == 0) {
2192 dev_err(&pdev->dev, "no displays\n");
2193 ret = -EINVAL;
2194 goto probe_err0;
2195 }
2196
2197 vid_dev->num_overlays = omap_dss_get_num_overlays();
2198 for (i = 0; i < vid_dev->num_overlays; i++)
2199 vid_dev->overlays[i] = omap_dss_get_overlay(i);
2200
2201 vid_dev->num_managers = omap_dss_get_num_overlay_managers();
2202 for (i = 0; i < vid_dev->num_managers; i++)
2203 vid_dev->managers[i] = omap_dss_get_overlay_manager(i);
2204
2205 /* Get the Video1 overlay and video2 overlay.
2206 * Setup the Display attached to that overlays
2207 */
2208 for (i = 1; i < vid_dev->num_overlays; i++) {
2209 ovl = omap_dss_get_overlay(i);
2210 if (ovl->manager && ovl->manager->device) {
2211 def_display = ovl->manager->device;
2212 } else {
2213 dev_warn(&pdev->dev, "cannot find display\n");
2214 def_display = NULL;
2215 }
2216 if (def_display) {
2217 struct omap_dss_driver *dssdrv = def_display->driver;
2218
2219 ret = dssdrv->enable(def_display);
2220 if (ret) {
2221 /* Here we are not considering a error
2222 * as display may be enabled by frame
2223 * buffer driver
2224 */
2225 dev_warn(&pdev->dev,
2226 "'%s' Display already enabled\n",
2227 def_display->name);
2228 }
2229 }
2230 }
2231
2232 if (v4l2_device_register(&pdev->dev, &vid_dev->v4l2_dev) < 0) {
2233 dev_err(&pdev->dev, "v4l2_device_register failed\n");
2234 ret = -ENODEV;
2235 goto probe_err1;
2236 }
2237
2238 ret = omap_vout_create_video_devices(pdev);
2239 if (ret)
2240 goto probe_err2;
2241
2242 for (i = 0; i < vid_dev->num_displays; i++) {
2243 struct omap_dss_device *display = vid_dev->displays[i];
2244
2245 if (display->driver->update)
2246 display->driver->update(display, 0, 0,
2247 display->panel.timings.x_res,
2248 display->panel.timings.y_res);
2249 }
2250 return 0;
2251
2252probe_err2:
2253 v4l2_device_unregister(&vid_dev->v4l2_dev);
2254probe_err1:
2255 for (i = 1; i < vid_dev->num_overlays; i++) {
2256 def_display = NULL;
2257 ovl = omap_dss_get_overlay(i);
2258 if (ovl->manager && ovl->manager->device)
2259 def_display = ovl->manager->device;
2260
2261 if (def_display && def_display->driver)
2262 def_display->driver->disable(def_display);
2263 }
2264probe_err0:
2265 kfree(vid_dev);
2266 return ret;
2267}
2268
2269static struct platform_driver omap_vout_driver = {
2270 .driver = {
2271 .name = VOUT_NAME,
2272 },
2273 .remove = omap_vout_remove,
2274};
2275
2276static int __init omap_vout_init(void)
2277{
2278 if (platform_driver_probe(&omap_vout_driver, omap_vout_probe) != 0) {
2279 printk(KERN_ERR VOUT_NAME ":Could not register Video driver\n");
2280 return -EINVAL;
2281 }
2282 return 0;
2283}
2284
2285static void omap_vout_cleanup(void)
2286{
2287 platform_driver_unregister(&omap_vout_driver);
2288}
2289
2290late_initcall(omap_vout_init);
2291module_exit(omap_vout_cleanup);
diff --git a/drivers/media/platform/omap/omap_vout_vrfb.c b/drivers/media/platform/omap/omap_vout_vrfb.c
new file mode 100644
index 000000000000..4be26abf6cea
--- /dev/null
+++ b/drivers/media/platform/omap/omap_vout_vrfb.c
@@ -0,0 +1,390 @@
1/*
2 * omap_vout_vrfb.c
3 *
4 * Copyright (C) 2010 Texas Instruments.
5 *
6 * This file is licensed under the terms of the GNU General Public License
7 * version 2. This program is licensed "as is" without any warranty of any
8 * kind, whether express or implied.
9 *
10 */
11
12#include <linux/sched.h>
13#include <linux/platform_device.h>
14#include <linux/videodev2.h>
15
16#include <media/videobuf-dma-contig.h>
17#include <media/v4l2-device.h>
18
19#include <plat/dma.h>
20#include <plat/vrfb.h>
21
22#include "omap_voutdef.h"
23#include "omap_voutlib.h"
24
25/*
26 * Function for allocating video buffers
27 */
28static int omap_vout_allocate_vrfb_buffers(struct omap_vout_device *vout,
29 unsigned int *count, int startindex)
30{
31 int i, j;
32
33 for (i = 0; i < *count; i++) {
34 if (!vout->smsshado_virt_addr[i]) {
35 vout->smsshado_virt_addr[i] =
36 omap_vout_alloc_buffer(vout->smsshado_size,
37 &vout->smsshado_phy_addr[i]);
38 }
39 if (!vout->smsshado_virt_addr[i] && startindex != -1) {
40 if (V4L2_MEMORY_MMAP == vout->memory && i >= startindex)
41 break;
42 }
43 if (!vout->smsshado_virt_addr[i]) {
44 for (j = 0; j < i; j++) {
45 omap_vout_free_buffer(
46 vout->smsshado_virt_addr[j],
47 vout->smsshado_size);
48 vout->smsshado_virt_addr[j] = 0;
49 vout->smsshado_phy_addr[j] = 0;
50 }
51 *count = 0;
52 return -ENOMEM;
53 }
54 memset((void *) vout->smsshado_virt_addr[i], 0,
55 vout->smsshado_size);
56 }
57 return 0;
58}
59
60/*
61 * Wakes up the application once the DMA transfer to VRFB space is completed.
62 */
63static void omap_vout_vrfb_dma_tx_callback(int lch, u16 ch_status, void *data)
64{
65 struct vid_vrfb_dma *t = (struct vid_vrfb_dma *) data;
66
67 t->tx_status = 1;
68 wake_up_interruptible(&t->wait);
69}
70
71/*
72 * Free VRFB buffers
73 */
74void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout)
75{
76 int j;
77
78 for (j = 0; j < VRFB_NUM_BUFS; j++) {
79 omap_vout_free_buffer(vout->smsshado_virt_addr[j],
80 vout->smsshado_size);
81 vout->smsshado_virt_addr[j] = 0;
82 vout->smsshado_phy_addr[j] = 0;
83 }
84}
85
86int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num,
87 bool static_vrfb_allocation)
88{
89 int ret = 0, i, j;
90 struct omap_vout_device *vout;
91 struct video_device *vfd;
92 int image_width, image_height;
93 int vrfb_num_bufs = VRFB_NUM_BUFS;
94 struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
95 struct omap2video_device *vid_dev =
96 container_of(v4l2_dev, struct omap2video_device, v4l2_dev);
97
98 vout = vid_dev->vouts[vid_num];
99 vfd = vout->vfd;
100
101 for (i = 0; i < VRFB_NUM_BUFS; i++) {
102 if (omap_vrfb_request_ctx(&vout->vrfb_context[i])) {
103 dev_info(&pdev->dev, ": VRFB allocation failed\n");
104 for (j = 0; j < i; j++)
105 omap_vrfb_release_ctx(&vout->vrfb_context[j]);
106 ret = -ENOMEM;
107 goto free_buffers;
108 }
109 }
110
111 /* Calculate VRFB memory size */
112 /* allocate for worst case size */
113 image_width = VID_MAX_WIDTH / TILE_SIZE;
114 if (VID_MAX_WIDTH % TILE_SIZE)
115 image_width++;
116
117 image_width = image_width * TILE_SIZE;
118 image_height = VID_MAX_HEIGHT / TILE_SIZE;
119
120 if (VID_MAX_HEIGHT % TILE_SIZE)
121 image_height++;
122
123 image_height = image_height * TILE_SIZE;
124 vout->smsshado_size = PAGE_ALIGN(image_width * image_height * 2 * 2);
125
126 /*
127 * Request and Initialize DMA, for DMA based VRFB transfer
128 */
129 vout->vrfb_dma_tx.dev_id = OMAP_DMA_NO_DEVICE;
130 vout->vrfb_dma_tx.dma_ch = -1;
131 vout->vrfb_dma_tx.req_status = DMA_CHAN_ALLOTED;
132 ret = omap_request_dma(vout->vrfb_dma_tx.dev_id, "VRFB DMA TX",
133 omap_vout_vrfb_dma_tx_callback,
134 (void *) &vout->vrfb_dma_tx, &vout->vrfb_dma_tx.dma_ch);
135 if (ret < 0) {
136 vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED;
137 dev_info(&pdev->dev, ": failed to allocate DMA Channel for"
138 " video%d\n", vfd->minor);
139 }
140 init_waitqueue_head(&vout->vrfb_dma_tx.wait);
141
142 /* statically allocated the VRFB buffer is done through
143 commands line aruments */
144 if (static_vrfb_allocation) {
145 if (omap_vout_allocate_vrfb_buffers(vout, &vrfb_num_bufs, -1)) {
146 ret = -ENOMEM;
147 goto release_vrfb_ctx;
148 }
149 vout->vrfb_static_allocation = 1;
150 }
151 return 0;
152
153release_vrfb_ctx:
154 for (j = 0; j < VRFB_NUM_BUFS; j++)
155 omap_vrfb_release_ctx(&vout->vrfb_context[j]);
156free_buffers:
157 omap_vout_free_buffers(vout);
158
159 return ret;
160}
161
162/*
163 * Release the VRFB context once the module exits
164 */
165void omap_vout_release_vrfb(struct omap_vout_device *vout)
166{
167 int i;
168
169 for (i = 0; i < VRFB_NUM_BUFS; i++)
170 omap_vrfb_release_ctx(&vout->vrfb_context[i]);
171
172 if (vout->vrfb_dma_tx.req_status == DMA_CHAN_ALLOTED) {
173 vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED;
174 omap_free_dma(vout->vrfb_dma_tx.dma_ch);
175 }
176}
177
178/*
179 * Allocate the buffers for the VRFB space. Data is copied from V4L2
180 * buffers to the VRFB buffers using the DMA engine.
181 */
182int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout,
183 unsigned int *count, unsigned int startindex)
184{
185 int i;
186 bool yuv_mode;
187
188 if (!is_rotation_enabled(vout))
189 return 0;
190
191 /* If rotation is enabled, allocate memory for VRFB space also */
192 *count = *count > VRFB_NUM_BUFS ? VRFB_NUM_BUFS : *count;
193
194 /* Allocate the VRFB buffers only if the buffers are not
195 * allocated during init time.
196 */
197 if (!vout->vrfb_static_allocation)
198 if (omap_vout_allocate_vrfb_buffers(vout, count, startindex))
199 return -ENOMEM;
200
201 if (vout->dss_mode == OMAP_DSS_COLOR_YUV2 ||
202 vout->dss_mode == OMAP_DSS_COLOR_UYVY)
203 yuv_mode = true;
204 else
205 yuv_mode = false;
206
207 for (i = 0; i < *count; i++)
208 omap_vrfb_setup(&vout->vrfb_context[i],
209 vout->smsshado_phy_addr[i], vout->pix.width,
210 vout->pix.height, vout->bpp, yuv_mode);
211
212 return 0;
213}
214
215int omap_vout_prepare_vrfb(struct omap_vout_device *vout,
216 struct videobuf_buffer *vb)
217{
218 dma_addr_t dmabuf;
219 struct vid_vrfb_dma *tx;
220 enum dss_rotation rotation;
221 u32 dest_frame_index = 0, src_element_index = 0;
222 u32 dest_element_index = 0, src_frame_index = 0;
223 u32 elem_count = 0, frame_count = 0, pixsize = 2;
224
225 if (!is_rotation_enabled(vout))
226 return 0;
227
228 dmabuf = vout->buf_phy_addr[vb->i];
229 /* If rotation is enabled, copy input buffer into VRFB
230 * memory space using DMA. We are copying input buffer
231 * into VRFB memory space of desired angle and DSS will
232 * read image VRFB memory for 0 degree angle
233 */
234 pixsize = vout->bpp * vout->vrfb_bpp;
235 /*
236 * DMA transfer in double index mode
237 */
238
239 /* Frame index */
240 dest_frame_index = ((MAX_PIXELS_PER_LINE * pixsize) -
241 (vout->pix.width * vout->bpp)) + 1;
242
243 /* Source and destination parameters */
244 src_element_index = 0;
245 src_frame_index = 0;
246 dest_element_index = 1;
247 /* Number of elements per frame */
248 elem_count = vout->pix.width * vout->bpp;
249 frame_count = vout->pix.height;
250 tx = &vout->vrfb_dma_tx;
251 tx->tx_status = 0;
252 omap_set_dma_transfer_params(tx->dma_ch, OMAP_DMA_DATA_TYPE_S32,
253 (elem_count / 4), frame_count, OMAP_DMA_SYNC_ELEMENT,
254 tx->dev_id, 0x0);
255 /* src_port required only for OMAP1 */
256 omap_set_dma_src_params(tx->dma_ch, 0, OMAP_DMA_AMODE_POST_INC,
257 dmabuf, src_element_index, src_frame_index);
258 /*set dma source burst mode for VRFB */
259 omap_set_dma_src_burst_mode(tx->dma_ch, OMAP_DMA_DATA_BURST_16);
260 rotation = calc_rotation(vout);
261
262 /* dest_port required only for OMAP1 */
263 omap_set_dma_dest_params(tx->dma_ch, 0, OMAP_DMA_AMODE_DOUBLE_IDX,
264 vout->vrfb_context[vb->i].paddr[0], dest_element_index,
265 dest_frame_index);
266 /*set dma dest burst mode for VRFB */
267 omap_set_dma_dest_burst_mode(tx->dma_ch, OMAP_DMA_DATA_BURST_16);
268 omap_dma_set_global_params(DMA_DEFAULT_ARB_RATE, 0x20, 0);
269
270 omap_start_dma(tx->dma_ch);
271 interruptible_sleep_on_timeout(&tx->wait, VRFB_TX_TIMEOUT);
272
273 if (tx->tx_status == 0) {
274 omap_stop_dma(tx->dma_ch);
275 return -EINVAL;
276 }
277 /* Store buffers physical address into an array. Addresses
278 * from this array will be used to configure DSS */
279 vout->queued_buf_addr[vb->i] = (u8 *)
280 vout->vrfb_context[vb->i].paddr[rotation];
281 return 0;
282}
283
284/*
285 * Calculate the buffer offsets from which the streaming should
286 * start. This offset calculation is mainly required because of
287 * the VRFB 32 pixels alignment with rotation.
288 */
289void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout)
290{
291 enum dss_rotation rotation;
292 bool mirroring = vout->mirror;
293 struct v4l2_rect *crop = &vout->crop;
294 struct v4l2_pix_format *pix = &vout->pix;
295 int *cropped_offset = &vout->cropped_offset;
296 int vr_ps = 1, ps = 2, temp_ps = 2;
297 int offset = 0, ctop = 0, cleft = 0, line_length = 0;
298
299 rotation = calc_rotation(vout);
300
301 if (V4L2_PIX_FMT_YUYV == pix->pixelformat ||
302 V4L2_PIX_FMT_UYVY == pix->pixelformat) {
303 if (is_rotation_enabled(vout)) {
304 /*
305 * ps - Actual pixel size for YUYV/UYVY for
306 * VRFB/Mirroring is 4 bytes
307 * vr_ps - Virtually pixel size for YUYV/UYVY is
308 * 2 bytes
309 */
310 ps = 4;
311 vr_ps = 2;
312 } else {
313 ps = 2; /* otherwise the pixel size is 2 byte */
314 }
315 } else if (V4L2_PIX_FMT_RGB32 == pix->pixelformat) {
316 ps = 4;
317 } else if (V4L2_PIX_FMT_RGB24 == pix->pixelformat) {
318 ps = 3;
319 }
320 vout->ps = ps;
321 vout->vr_ps = vr_ps;
322
323 if (is_rotation_enabled(vout)) {
324 line_length = MAX_PIXELS_PER_LINE;
325 ctop = (pix->height - crop->height) - crop->top;
326 cleft = (pix->width - crop->width) - crop->left;
327 } else {
328 line_length = pix->width;
329 }
330 vout->line_length = line_length;
331 switch (rotation) {
332 case dss_rotation_90_degree:
333 offset = vout->vrfb_context[0].yoffset *
334 vout->vrfb_context[0].bytespp;
335 temp_ps = ps / vr_ps;
336 if (mirroring == 0) {
337 *cropped_offset = offset + line_length *
338 temp_ps * cleft + crop->top * temp_ps;
339 } else {
340 *cropped_offset = offset + line_length * temp_ps *
341 cleft + crop->top * temp_ps + (line_length *
342 ((crop->width / (vr_ps)) - 1) * ps);
343 }
344 break;
345 case dss_rotation_180_degree:
346 offset = ((MAX_PIXELS_PER_LINE * vout->vrfb_context[0].yoffset *
347 vout->vrfb_context[0].bytespp) +
348 (vout->vrfb_context[0].xoffset *
349 vout->vrfb_context[0].bytespp));
350 if (mirroring == 0) {
351 *cropped_offset = offset + (line_length * ps * ctop) +
352 (cleft / vr_ps) * ps;
353
354 } else {
355 *cropped_offset = offset + (line_length * ps * ctop) +
356 (cleft / vr_ps) * ps + (line_length *
357 (crop->height - 1) * ps);
358 }
359 break;
360 case dss_rotation_270_degree:
361 offset = MAX_PIXELS_PER_LINE * vout->vrfb_context[0].xoffset *
362 vout->vrfb_context[0].bytespp;
363 temp_ps = ps / vr_ps;
364 if (mirroring == 0) {
365 *cropped_offset = offset + line_length *
366 temp_ps * crop->left + ctop * ps;
367 } else {
368 *cropped_offset = offset + line_length *
369 temp_ps * crop->left + ctop * ps +
370 (line_length * ((crop->width / vr_ps) - 1) *
371 ps);
372 }
373 break;
374 case dss_rotation_0_degree:
375 if (mirroring == 0) {
376 *cropped_offset = (line_length * ps) *
377 crop->top + (crop->left / vr_ps) * ps;
378 } else {
379 *cropped_offset = (line_length * ps) *
380 crop->top + (crop->left / vr_ps) * ps +
381 (line_length * (crop->height - 1) * ps);
382 }
383 break;
384 default:
385 *cropped_offset = (line_length * ps * crop->top) /
386 vr_ps + (crop->left * ps) / vr_ps +
387 ((crop->width / vr_ps) - 1) * ps;
388 break;
389 }
390}
diff --git a/drivers/media/platform/omap/omap_vout_vrfb.h b/drivers/media/platform/omap/omap_vout_vrfb.h
new file mode 100644
index 000000000000..ffde741e0590
--- /dev/null
+++ b/drivers/media/platform/omap/omap_vout_vrfb.h
@@ -0,0 +1,40 @@
1/*
2 * omap_vout_vrfb.h
3 *
4 * Copyright (C) 2010 Texas Instruments.
5 *
6 * This file is licensed under the terms of the GNU General Public License
7 * version 2. This program is licensed "as is" without any warranty of any
8 * kind, whether express or implied.
9 *
10 */
11
12#ifndef OMAP_VOUT_VRFB_H
13#define OMAP_VOUT_VRFB_H
14
15#ifdef CONFIG_VIDEO_OMAP2_VOUT_VRFB
16void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout);
17int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num,
18 u32 static_vrfb_allocation);
19void omap_vout_release_vrfb(struct omap_vout_device *vout);
20int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout,
21 unsigned int *count, unsigned int startindex);
22int omap_vout_prepare_vrfb(struct omap_vout_device *vout,
23 struct videobuf_buffer *vb);
24void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout);
25#else
26void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout) { }
27int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num,
28 u32 static_vrfb_allocation)
29 { return 0; }
30void omap_vout_release_vrfb(struct omap_vout_device *vout) { }
31int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout,
32 unsigned int *count, unsigned int startindex)
33 { return 0; }
34int omap_vout_prepare_vrfb(struct omap_vout_device *vout,
35 struct videobuf_buffer *vb)
36 { return 0; }
37void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout) { }
38#endif
39
40#endif
diff --git a/drivers/media/platform/omap/omap_voutdef.h b/drivers/media/platform/omap/omap_voutdef.h
new file mode 100644
index 000000000000..27a95d23b913
--- /dev/null
+++ b/drivers/media/platform/omap/omap_voutdef.h
@@ -0,0 +1,225 @@
1/*
2 * omap_voutdef.h
3 *
4 * Copyright (C) 2010 Texas Instruments.
5 *
6 * This file is licensed under the terms of the GNU General Public License
7 * version 2. This program is licensed "as is" without any warranty of any
8 * kind, whether express or implied.
9 */
10
11#ifndef OMAP_VOUTDEF_H
12#define OMAP_VOUTDEF_H
13
14#include <video/omapdss.h>
15#include <plat/vrfb.h>
16
17#define YUYV_BPP 2
18#define RGB565_BPP 2
19#define RGB24_BPP 3
20#define RGB32_BPP 4
21#define TILE_SIZE 32
22#define YUYV_VRFB_BPP 2
23#define RGB_VRFB_BPP 1
24#define MAX_CID 3
25#define MAC_VRFB_CTXS 4
26#define MAX_VOUT_DEV 2
27#define MAX_OVLS 3
28#define MAX_DISPLAYS 10
29#define MAX_MANAGERS 3
30
31#define QQVGA_WIDTH 160
32#define QQVGA_HEIGHT 120
33
34/* Max Resolution supported by the driver */
35#define VID_MAX_WIDTH 1280 /* Largest width */
36#define VID_MAX_HEIGHT 720 /* Largest height */
37
38/* Mimimum requirement is 2x2 for DSS */
39#define VID_MIN_WIDTH 2
40#define VID_MIN_HEIGHT 2
41
42/* 2048 x 2048 is max res supported by OMAP display controller */
43#define MAX_PIXELS_PER_LINE 2048
44
45#define VRFB_TX_TIMEOUT 1000
46#define VRFB_NUM_BUFS 4
47
48/* Max buffer size tobe allocated during init */
49#define OMAP_VOUT_MAX_BUF_SIZE (VID_MAX_WIDTH*VID_MAX_HEIGHT*4)
50
51enum dma_channel_state {
52 DMA_CHAN_NOT_ALLOTED,
53 DMA_CHAN_ALLOTED,
54};
55
56/* Enum for Rotation
57 * DSS understands rotation in 0, 1, 2, 3 context
58 * while V4L2 driver understands it as 0, 90, 180, 270
59 */
60enum dss_rotation {
61 dss_rotation_0_degree = 0,
62 dss_rotation_90_degree = 1,
63 dss_rotation_180_degree = 2,
64 dss_rotation_270_degree = 3,
65};
66
67/* Enum for choosing rotation type for vout
68 * DSS2 doesn't understand no rotation as an
69 * option while V4L2 driver doesn't support
70 * rotation in the case where VRFB is not built in
71 * the kernel
72 */
73enum vout_rotaion_type {
74 VOUT_ROT_NONE = 0,
75 VOUT_ROT_VRFB = 1,
76};
77
78/*
79 * This structure is used to store the DMA transfer parameters
80 * for VRFB hidden buffer
81 */
82struct vid_vrfb_dma {
83 int dev_id;
84 int dma_ch;
85 int req_status;
86 int tx_status;
87 wait_queue_head_t wait;
88};
89
90struct omapvideo_info {
91 int id;
92 int num_overlays;
93 struct omap_overlay *overlays[MAX_OVLS];
94 enum vout_rotaion_type rotation_type;
95};
96
97struct omap2video_device {
98 struct mutex mtx;
99
100 int state;
101
102 struct v4l2_device v4l2_dev;
103 struct omap_vout_device *vouts[MAX_VOUT_DEV];
104
105 int num_displays;
106 struct omap_dss_device *displays[MAX_DISPLAYS];
107 int num_overlays;
108 struct omap_overlay *overlays[MAX_OVLS];
109 int num_managers;
110 struct omap_overlay_manager *managers[MAX_MANAGERS];
111};
112
113/* per-device data structure */
114struct omap_vout_device {
115
116 struct omapvideo_info vid_info;
117 struct video_device *vfd;
118 struct omap2video_device *vid_dev;
119 int vid;
120 int opened;
121
122 /* we don't allow to change image fmt/size once buffer has
123 * been allocated
124 */
125 int buffer_allocated;
126 /* allow to reuse previously allocated buffer which is big enough */
127 int buffer_size;
128 /* keep buffer info across opens */
129 unsigned long buf_virt_addr[VIDEO_MAX_FRAME];
130 unsigned long buf_phy_addr[VIDEO_MAX_FRAME];
131 enum omap_color_mode dss_mode;
132
133 /* we don't allow to request new buffer when old buffers are
134 * still mmaped
135 */
136 int mmap_count;
137
138 spinlock_t vbq_lock; /* spinlock for videobuf queues */
139 unsigned long field_count; /* field counter for videobuf_buffer */
140
141 /* non-NULL means streaming is in progress. */
142 bool streaming;
143
144 struct v4l2_pix_format pix;
145 struct v4l2_rect crop;
146 struct v4l2_window win;
147 struct v4l2_framebuffer fbuf;
148
149 /* Lock to protect the shared data structures in ioctl */
150 struct mutex lock;
151
152 /* V4L2 control structure for different control id */
153 struct v4l2_control control[MAX_CID];
154 enum dss_rotation rotation;
155 bool mirror;
156 int flicker_filter;
157 /* V4L2 control structure for different control id */
158
159 int bpp; /* bytes per pixel */
160 int vrfb_bpp; /* bytes per pixel with respect to VRFB */
161
162 struct vid_vrfb_dma vrfb_dma_tx;
163 unsigned int smsshado_phy_addr[MAC_VRFB_CTXS];
164 unsigned int smsshado_virt_addr[MAC_VRFB_CTXS];
165 struct vrfb vrfb_context[MAC_VRFB_CTXS];
166 bool vrfb_static_allocation;
167 unsigned int smsshado_size;
168 unsigned char pos;
169
170 int ps, vr_ps, line_length, first_int, field_id;
171 enum v4l2_memory memory;
172 struct videobuf_buffer *cur_frm, *next_frm;
173 struct list_head dma_queue;
174 u8 *queued_buf_addr[VIDEO_MAX_FRAME];
175 u32 cropped_offset;
176 s32 tv_field1_offset;
177 void *isr_handle;
178
179 /* Buffer queue variables */
180 struct omap_vout_device *vout;
181 enum v4l2_buf_type type;
182 struct videobuf_queue vbq;
183 int io_allowed;
184
185};
186
187/*
188 * Return true if rotation is 90 or 270
189 */
190static inline int is_rotation_90_or_270(const struct omap_vout_device *vout)
191{
192 return (vout->rotation == dss_rotation_90_degree ||
193 vout->rotation == dss_rotation_270_degree);
194}
195
196/*
197 * Return true if rotation is enabled
198 */
199static inline int is_rotation_enabled(const struct omap_vout_device *vout)
200{
201 return vout->rotation || vout->mirror;
202}
203
204/*
205 * Reverse the rotation degree if mirroring is enabled
206 */
207static inline int calc_rotation(const struct omap_vout_device *vout)
208{
209 if (!vout->mirror)
210 return vout->rotation;
211
212 switch (vout->rotation) {
213 case dss_rotation_90_degree:
214 return dss_rotation_270_degree;
215 case dss_rotation_270_degree:
216 return dss_rotation_90_degree;
217 case dss_rotation_180_degree:
218 return dss_rotation_0_degree;
219 default:
220 return dss_rotation_180_degree;
221 }
222}
223
224void omap_vout_free_buffers(struct omap_vout_device *vout);
225#endif /* ifndef OMAP_VOUTDEF_H */
diff --git a/drivers/media/platform/omap/omap_voutlib.c b/drivers/media/platform/omap/omap_voutlib.c
new file mode 100644
index 000000000000..115408b9274f
--- /dev/null
+++ b/drivers/media/platform/omap/omap_voutlib.c
@@ -0,0 +1,339 @@
1/*
2 * omap_voutlib.c
3 *
4 * Copyright (C) 2005-2010 Texas Instruments.
5 *
6 * This file is licensed under the terms of the GNU General Public License
7 * version 2. This program is licensed "as is" without any warranty of any
8 * kind, whether express or implied.
9 *
10 * Based on the OMAP2 camera driver
11 * Video-for-Linux (Version 2) camera capture driver for
12 * the OMAP24xx camera controller.
13 *
14 * Author: Andy Lowe (source@mvista.com)
15 *
16 * Copyright (C) 2004 MontaVista Software, Inc.
17 * Copyright (C) 2010 Texas Instruments.
18 *
19 */
20
21#include <linux/module.h>
22#include <linux/errno.h>
23#include <linux/kernel.h>
24#include <linux/types.h>
25#include <linux/videodev2.h>
26
27#include <linux/dma-mapping.h>
28
29#include <plat/cpu.h>
30
31#include "omap_voutlib.h"
32
33MODULE_AUTHOR("Texas Instruments");
34MODULE_DESCRIPTION("OMAP Video library");
35MODULE_LICENSE("GPL");
36
37/* Return the default overlay cropping rectangle in crop given the image
38 * size in pix and the video display size in fbuf. The default
39 * cropping rectangle is the largest rectangle no larger than the capture size
40 * that will fit on the display. The default cropping rectangle is centered in
41 * the image. All dimensions and offsets are rounded down to even numbers.
42 */
43void omap_vout_default_crop(struct v4l2_pix_format *pix,
44 struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop)
45{
46 crop->width = (pix->width < fbuf->fmt.width) ?
47 pix->width : fbuf->fmt.width;
48 crop->height = (pix->height < fbuf->fmt.height) ?
49 pix->height : fbuf->fmt.height;
50 crop->width &= ~1;
51 crop->height &= ~1;
52 crop->left = ((pix->width - crop->width) >> 1) & ~1;
53 crop->top = ((pix->height - crop->height) >> 1) & ~1;
54}
55EXPORT_SYMBOL_GPL(omap_vout_default_crop);
56
57/* Given a new render window in new_win, adjust the window to the
58 * nearest supported configuration. The adjusted window parameters are
59 * returned in new_win.
60 * Returns zero if successful, or -EINVAL if the requested window is
61 * impossible and cannot reasonably be adjusted.
62 */
63int omap_vout_try_window(struct v4l2_framebuffer *fbuf,
64 struct v4l2_window *new_win)
65{
66 struct v4l2_rect try_win;
67
68 /* make a working copy of the new_win rectangle */
69 try_win = new_win->w;
70
71 /* adjust the preview window so it fits on the display by clipping any
72 * offscreen areas
73 */
74 if (try_win.left < 0) {
75 try_win.width += try_win.left;
76 try_win.left = 0;
77 }
78 if (try_win.top < 0) {
79 try_win.height += try_win.top;
80 try_win.top = 0;
81 }
82 try_win.width = (try_win.width < fbuf->fmt.width) ?
83 try_win.width : fbuf->fmt.width;
84 try_win.height = (try_win.height < fbuf->fmt.height) ?
85 try_win.height : fbuf->fmt.height;
86 if (try_win.left + try_win.width > fbuf->fmt.width)
87 try_win.width = fbuf->fmt.width - try_win.left;
88 if (try_win.top + try_win.height > fbuf->fmt.height)
89 try_win.height = fbuf->fmt.height - try_win.top;
90 try_win.width &= ~1;
91 try_win.height &= ~1;
92
93 if (try_win.width <= 0 || try_win.height <= 0)
94 return -EINVAL;
95
96 /* We now have a valid preview window, so go with it */
97 new_win->w = try_win;
98 new_win->field = V4L2_FIELD_ANY;
99 return 0;
100}
101EXPORT_SYMBOL_GPL(omap_vout_try_window);
102
103/* Given a new render window in new_win, adjust the window to the
104 * nearest supported configuration. The image cropping window in crop
105 * will also be adjusted if necessary. Preference is given to keeping the
106 * the window as close to the requested configuration as possible. If
107 * successful, new_win, vout->win, and crop are updated.
108 * Returns zero if successful, or -EINVAL if the requested preview window is
109 * impossible and cannot reasonably be adjusted.
110 */
111int omap_vout_new_window(struct v4l2_rect *crop,
112 struct v4l2_window *win, struct v4l2_framebuffer *fbuf,
113 struct v4l2_window *new_win)
114{
115 int err;
116
117 err = omap_vout_try_window(fbuf, new_win);
118 if (err)
119 return err;
120
121 /* update our preview window */
122 win->w = new_win->w;
123 win->field = new_win->field;
124 win->chromakey = new_win->chromakey;
125
126 /* Adjust the cropping window to allow for resizing limitation */
127 if (cpu_is_omap24xx()) {
128 /* For 24xx limit is 8x to 1/2x scaling. */
129 if ((crop->height/win->w.height) >= 2)
130 crop->height = win->w.height * 2;
131
132 if ((crop->width/win->w.width) >= 2)
133 crop->width = win->w.width * 2;
134
135 if (crop->width > 768) {
136 /* The OMAP2420 vertical resizing line buffer is 768
137 * pixels wide. If the cropped image is wider than
138 * 768 pixels then it cannot be vertically resized.
139 */
140 if (crop->height != win->w.height)
141 crop->width = 768;
142 }
143 } else if (cpu_is_omap34xx()) {
144 /* For 34xx limit is 8x to 1/4x scaling. */
145 if ((crop->height/win->w.height) >= 4)
146 crop->height = win->w.height * 4;
147
148 if ((crop->width/win->w.width) >= 4)
149 crop->width = win->w.width * 4;
150 }
151 return 0;
152}
153EXPORT_SYMBOL_GPL(omap_vout_new_window);
154
155/* Given a new cropping rectangle in new_crop, adjust the cropping rectangle to
156 * the nearest supported configuration. The image render window in win will
157 * also be adjusted if necessary. The preview window is adjusted such that the
158 * horizontal and vertical rescaling ratios stay constant. If the render
159 * window would fall outside the display boundaries, the cropping rectangle
160 * will also be adjusted to maintain the rescaling ratios. If successful, crop
161 * and win are updated.
162 * Returns zero if successful, or -EINVAL if the requested cropping rectangle is
163 * impossible and cannot reasonably be adjusted.
164 */
165int omap_vout_new_crop(struct v4l2_pix_format *pix,
166 struct v4l2_rect *crop, struct v4l2_window *win,
167 struct v4l2_framebuffer *fbuf, const struct v4l2_rect *new_crop)
168{
169 struct v4l2_rect try_crop;
170 unsigned long vresize, hresize;
171
172 /* make a working copy of the new_crop rectangle */
173 try_crop = *new_crop;
174
175 /* adjust the cropping rectangle so it fits in the image */
176 if (try_crop.left < 0) {
177 try_crop.width += try_crop.left;
178 try_crop.left = 0;
179 }
180 if (try_crop.top < 0) {
181 try_crop.height += try_crop.top;
182 try_crop.top = 0;
183 }
184 try_crop.width = (try_crop.width < pix->width) ?
185 try_crop.width : pix->width;
186 try_crop.height = (try_crop.height < pix->height) ?
187 try_crop.height : pix->height;
188 if (try_crop.left + try_crop.width > pix->width)
189 try_crop.width = pix->width - try_crop.left;
190 if (try_crop.top + try_crop.height > pix->height)
191 try_crop.height = pix->height - try_crop.top;
192
193 try_crop.width &= ~1;
194 try_crop.height &= ~1;
195
196 if (try_crop.width <= 0 || try_crop.height <= 0)
197 return -EINVAL;
198
199 if (cpu_is_omap24xx()) {
200 if (try_crop.height != win->w.height) {
201 /* If we're resizing vertically, we can't support a
202 * crop width wider than 768 pixels.
203 */
204 if (try_crop.width > 768)
205 try_crop.width = 768;
206 }
207 }
208 /* vertical resizing */
209 vresize = (1024 * try_crop.height) / win->w.height;
210 if (cpu_is_omap24xx() && (vresize > 2048))
211 vresize = 2048;
212 else if (cpu_is_omap34xx() && (vresize > 4096))
213 vresize = 4096;
214
215 win->w.height = ((1024 * try_crop.height) / vresize) & ~1;
216 if (win->w.height == 0)
217 win->w.height = 2;
218 if (win->w.height + win->w.top > fbuf->fmt.height) {
219 /* We made the preview window extend below the bottom of the
220 * display, so clip it to the display boundary and resize the
221 * cropping height to maintain the vertical resizing ratio.
222 */
223 win->w.height = (fbuf->fmt.height - win->w.top) & ~1;
224 if (try_crop.height == 0)
225 try_crop.height = 2;
226 }
227 /* horizontal resizing */
228 hresize = (1024 * try_crop.width) / win->w.width;
229 if (cpu_is_omap24xx() && (hresize > 2048))
230 hresize = 2048;
231 else if (cpu_is_omap34xx() && (hresize > 4096))
232 hresize = 4096;
233
234 win->w.width = ((1024 * try_crop.width) / hresize) & ~1;
235 if (win->w.width == 0)
236 win->w.width = 2;
237 if (win->w.width + win->w.left > fbuf->fmt.width) {
238 /* We made the preview window extend past the right side of the
239 * display, so clip it to the display boundary and resize the
240 * cropping width to maintain the horizontal resizing ratio.
241 */
242 win->w.width = (fbuf->fmt.width - win->w.left) & ~1;
243 if (try_crop.width == 0)
244 try_crop.width = 2;
245 }
246 if (cpu_is_omap24xx()) {
247 if ((try_crop.height/win->w.height) >= 2)
248 try_crop.height = win->w.height * 2;
249
250 if ((try_crop.width/win->w.width) >= 2)
251 try_crop.width = win->w.width * 2;
252
253 if (try_crop.width > 768) {
254 /* The OMAP2420 vertical resizing line buffer is
255 * 768 pixels wide. If the cropped image is wider
256 * than 768 pixels then it cannot be vertically resized.
257 */
258 if (try_crop.height != win->w.height)
259 try_crop.width = 768;
260 }
261 } else if (cpu_is_omap34xx()) {
262 if ((try_crop.height/win->w.height) >= 4)
263 try_crop.height = win->w.height * 4;
264
265 if ((try_crop.width/win->w.width) >= 4)
266 try_crop.width = win->w.width * 4;
267 }
268 /* update our cropping rectangle and we're done */
269 *crop = try_crop;
270 return 0;
271}
272EXPORT_SYMBOL_GPL(omap_vout_new_crop);
273
274/* Given a new format in pix and fbuf, crop and win
275 * structures are initialized to default values. crop
276 * is initialized to the largest window size that will fit on the display. The
277 * crop window is centered in the image. win is initialized to
278 * the same size as crop and is centered on the display.
279 * All sizes and offsets are constrained to be even numbers.
280 */
281void omap_vout_new_format(struct v4l2_pix_format *pix,
282 struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop,
283 struct v4l2_window *win)
284{
285 /* crop defines the preview source window in the image capture
286 * buffer
287 */
288 omap_vout_default_crop(pix, fbuf, crop);
289
290 /* win defines the preview target window on the display */
291 win->w.width = crop->width;
292 win->w.height = crop->height;
293 win->w.left = ((fbuf->fmt.width - win->w.width) >> 1) & ~1;
294 win->w.top = ((fbuf->fmt.height - win->w.height) >> 1) & ~1;
295}
296EXPORT_SYMBOL_GPL(omap_vout_new_format);
297
298/*
299 * Allocate buffers
300 */
301unsigned long omap_vout_alloc_buffer(u32 buf_size, u32 *phys_addr)
302{
303 u32 order, size;
304 unsigned long virt_addr, addr;
305
306 size = PAGE_ALIGN(buf_size);
307 order = get_order(size);
308 virt_addr = __get_free_pages(GFP_KERNEL, order);
309 addr = virt_addr;
310
311 if (virt_addr) {
312 while (size > 0) {
313 SetPageReserved(virt_to_page(addr));
314 addr += PAGE_SIZE;
315 size -= PAGE_SIZE;
316 }
317 }
318 *phys_addr = (u32) virt_to_phys((void *) virt_addr);
319 return virt_addr;
320}
321
322/*
323 * Free buffers
324 */
325void omap_vout_free_buffer(unsigned long virtaddr, u32 buf_size)
326{
327 u32 order, size;
328 unsigned long addr = virtaddr;
329
330 size = PAGE_ALIGN(buf_size);
331 order = get_order(size);
332
333 while (size > 0) {
334 ClearPageReserved(virt_to_page(addr));
335 addr += PAGE_SIZE;
336 size -= PAGE_SIZE;
337 }
338 free_pages((unsigned long) virtaddr, order);
339}
diff --git a/drivers/media/platform/omap/omap_voutlib.h b/drivers/media/platform/omap/omap_voutlib.h
new file mode 100644
index 000000000000..e51750a597e3
--- /dev/null
+++ b/drivers/media/platform/omap/omap_voutlib.h
@@ -0,0 +1,36 @@
1/*
2 * omap_voutlib.h
3 *
4 * Copyright (C) 2010 Texas Instruments.
5 *
6 * This file is licensed under the terms of the GNU General Public License
7 * version 2. This program is licensed "as is" without any warranty of any
8 * kind, whether express or implied.
9 *
10 */
11
12#ifndef OMAP_VOUTLIB_H
13#define OMAP_VOUTLIB_H
14
15void omap_vout_default_crop(struct v4l2_pix_format *pix,
16 struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop);
17
18int omap_vout_new_crop(struct v4l2_pix_format *pix,
19 struct v4l2_rect *crop, struct v4l2_window *win,
20 struct v4l2_framebuffer *fbuf,
21 const struct v4l2_rect *new_crop);
22
23int omap_vout_try_window(struct v4l2_framebuffer *fbuf,
24 struct v4l2_window *new_win);
25
26int omap_vout_new_window(struct v4l2_rect *crop,
27 struct v4l2_window *win, struct v4l2_framebuffer *fbuf,
28 struct v4l2_window *new_win);
29
30void omap_vout_new_format(struct v4l2_pix_format *pix,
31 struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop,
32 struct v4l2_window *win);
33unsigned long omap_vout_alloc_buffer(u32 buf_size, u32 *phys_addr);
34void omap_vout_free_buffer(unsigned long virtaddr, u32 buf_size);
35#endif /* #ifndef OMAP_VOUTLIB_H */
36