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