blob: 7b1afc8585c697d1f1035c9c43ee3dde1cfac27d [file] [log] [blame]
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001/*
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>
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -030038#include <linux/irq.h>
39#include <linux/videodev2.h>
Amber Jain72915e82011-07-07 06:03:25 -030040#include <linux/dma-mapping.h>
Gary Thomasd1ee8872011-12-01 08:51:09 -030041#include <linux/slab.h>
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -030042
Vaibhav Hiremathdd880dd2010-05-27 08:17:08 -030043#include <media/videobuf-dma-contig.h>
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -030044#include <media/v4l2-device.h>
45#include <media/v4l2-ioctl.h>
46
47#include <plat/dma.h>
Tomi Valkeinen6a1c9f62012-10-08 14:52:24 +030048#include <video/omapvrfb.h>
Tomi Valkeinena0b38cc2011-05-11 14:05:07 +030049#include <video/omapdss.h>
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -030050
51#include "omap_voutlib.h"
52#include "omap_voutdef.h"
archit taneja445e2582011-06-14 03:54:47 -030053#include "omap_vout_vrfb.h"
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -030054
55MODULE_AUTHOR("Texas Instruments");
56MODULE_DESCRIPTION("OMAP Video for Linux Video out driver");
57MODULE_LICENSE("GPL");
58
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -030059/* Driver Configuration macros */
60#define VOUT_NAME "omap_vout"
61
62enum omap_vout_channels {
63 OMAP_VIDEO1,
64 OMAP_VIDEO2,
65};
66
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -030067static struct videobuf_queue_ops video_vbq_ops;
68/* Variables configurable through module params*/
69static u32 video1_numbuffers = 3;
70static u32 video2_numbuffers = 3;
71static u32 video1_bufsize = OMAP_VOUT_MAX_BUF_SIZE;
72static u32 video2_bufsize = OMAP_VOUT_MAX_BUF_SIZE;
Rusty Russell90ab5ee2012-01-13 09:32:20 +103073static bool vid1_static_vrfb_alloc;
74static bool vid2_static_vrfb_alloc;
75static bool debug;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -030076
77/* Module parameters */
78module_param(video1_numbuffers, uint, S_IRUGO);
79MODULE_PARM_DESC(video1_numbuffers,
80 "Number of buffers to be allocated at init time for Video1 device.");
81
82module_param(video2_numbuffers, uint, S_IRUGO);
83MODULE_PARM_DESC(video2_numbuffers,
84 "Number of buffers to be allocated at init time for Video2 device.");
85
86module_param(video1_bufsize, uint, S_IRUGO);
87MODULE_PARM_DESC(video1_bufsize,
88 "Size of the buffer to be allocated for video1 device");
89
90module_param(video2_bufsize, uint, S_IRUGO);
91MODULE_PARM_DESC(video2_bufsize,
92 "Size of the buffer to be allocated for video2 device");
93
94module_param(vid1_static_vrfb_alloc, bool, S_IRUGO);
95MODULE_PARM_DESC(vid1_static_vrfb_alloc,
96 "Static allocation of the VRFB buffer for video1 device");
97
98module_param(vid2_static_vrfb_alloc, bool, S_IRUGO);
99MODULE_PARM_DESC(vid2_static_vrfb_alloc,
100 "Static allocation of the VRFB buffer for video2 device");
101
102module_param(debug, bool, S_IRUGO);
103MODULE_PARM_DESC(debug, "Debug level (0-1)");
104
105/* list of image formats supported by OMAP2 video pipelines */
Jesper Juhl0d334f72011-07-09 18:22:17 -0300106static const struct v4l2_fmtdesc omap_formats[] = {
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300107 {
108 /* Note: V4L2 defines RGB565 as:
109 *
110 * Byte 0 Byte 1
111 * g2 g1 g0 r4 r3 r2 r1 r0 b4 b3 b2 b1 b0 g5 g4 g3
112 *
113 * We interpret RGB565 as:
114 *
115 * Byte 0 Byte 1
116 * g2 g1 g0 b4 b3 b2 b1 b0 r4 r3 r2 r1 r0 g5 g4 g3
117 */
118 .description = "RGB565, le",
119 .pixelformat = V4L2_PIX_FMT_RGB565,
120 },
121 {
122 /* Note: V4L2 defines RGB32 as: RGB-8-8-8-8 we use
123 * this for RGB24 unpack mode, the last 8 bits are ignored
124 * */
125 .description = "RGB32, le",
126 .pixelformat = V4L2_PIX_FMT_RGB32,
127 },
128 {
129 /* Note: V4L2 defines RGB24 as: RGB-8-8-8 we use
130 * this for RGB24 packed mode
131 *
132 */
133 .description = "RGB24, le",
134 .pixelformat = V4L2_PIX_FMT_RGB24,
135 },
136 {
137 .description = "YUYV (YUV 4:2:2), packed",
138 .pixelformat = V4L2_PIX_FMT_YUYV,
139 },
140 {
141 .description = "UYVY, packed",
142 .pixelformat = V4L2_PIX_FMT_UYVY,
143 },
144};
145
146#define NUM_OUTPUT_FORMATS (ARRAY_SIZE(omap_formats))
147
148/*
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300149 * Try format
150 */
151static int omap_vout_try_format(struct v4l2_pix_format *pix)
152{
153 int ifmt, bpp = 0;
154
155 pix->height = clamp(pix->height, (u32)VID_MIN_HEIGHT,
156 (u32)VID_MAX_HEIGHT);
157 pix->width = clamp(pix->width, (u32)VID_MIN_WIDTH, (u32)VID_MAX_WIDTH);
158
159 for (ifmt = 0; ifmt < NUM_OUTPUT_FORMATS; ifmt++) {
160 if (pix->pixelformat == omap_formats[ifmt].pixelformat)
161 break;
162 }
163
164 if (ifmt == NUM_OUTPUT_FORMATS)
165 ifmt = 0;
166
167 pix->pixelformat = omap_formats[ifmt].pixelformat;
168 pix->field = V4L2_FIELD_ANY;
169 pix->priv = 0;
170
171 switch (pix->pixelformat) {
172 case V4L2_PIX_FMT_YUYV:
173 case V4L2_PIX_FMT_UYVY:
174 default:
175 pix->colorspace = V4L2_COLORSPACE_JPEG;
176 bpp = YUYV_BPP;
177 break;
178 case V4L2_PIX_FMT_RGB565:
179 case V4L2_PIX_FMT_RGB565X:
180 pix->colorspace = V4L2_COLORSPACE_SRGB;
181 bpp = RGB565_BPP;
182 break;
183 case V4L2_PIX_FMT_RGB24:
184 pix->colorspace = V4L2_COLORSPACE_SRGB;
185 bpp = RGB24_BPP;
186 break;
187 case V4L2_PIX_FMT_RGB32:
188 case V4L2_PIX_FMT_BGR32:
189 pix->colorspace = V4L2_COLORSPACE_SRGB;
190 bpp = RGB32_BPP;
191 break;
192 }
193 pix->bytesperline = pix->width * bpp;
194 pix->sizeimage = pix->bytesperline * pix->height;
195
196 return bpp;
197}
198
199/*
200 * omap_vout_uservirt_to_phys: This inline function is used to convert user
201 * space virtual address to physical address.
202 */
203static u32 omap_vout_uservirt_to_phys(u32 virtp)
204{
205 unsigned long physp = 0;
206 struct vm_area_struct *vma;
207 struct mm_struct *mm = current->mm;
208
209 vma = find_vma(mm, virtp);
210 /* For kernel direct-mapped memory, take the easy way */
211 if (virtp >= PAGE_OFFSET) {
212 physp = virt_to_phys((void *) virtp);
213 } else if (vma && (vma->vm_flags & VM_IO) && vma->vm_pgoff) {
214 /* this will catch, kernel-allocated, mmaped-to-usermode
215 addresses */
216 physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start);
217 } else {
218 /* otherwise, use get_user_pages() for general userland pages */
219 int res, nr_pages = 1;
220 struct page *pages;
221 down_read(&current->mm->mmap_sem);
222
223 res = get_user_pages(current, current->mm, virtp, nr_pages, 1,
224 0, &pages, NULL);
225 up_read(&current->mm->mmap_sem);
226
227 if (res == nr_pages) {
228 physp = __pa(page_address(&pages[0]) +
229 (virtp & ~PAGE_MASK));
230 } else {
231 printk(KERN_WARNING VOUT_NAME
232 "get_user_pages failed\n");
233 return 0;
234 }
235 }
236
237 return physp;
238}
239
240/*
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300241 * Free the V4L2 buffers
242 */
archit taneja445e2582011-06-14 03:54:47 -0300243void omap_vout_free_buffers(struct omap_vout_device *vout)
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300244{
245 int i, numbuffers;
246
247 /* Allocate memory for the buffers */
248 numbuffers = (vout->vid) ? video2_numbuffers : video1_numbuffers;
249 vout->buffer_size = (vout->vid) ? video2_bufsize : video1_bufsize;
250
251 for (i = 0; i < numbuffers; i++) {
252 omap_vout_free_buffer(vout->buf_virt_addr[i],
253 vout->buffer_size);
254 vout->buf_phy_addr[i] = 0;
255 vout->buf_virt_addr[i] = 0;
256 }
257}
258
259/*
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300260 * Convert V4L2 rotation to DSS rotation
261 * V4L2 understand 0, 90, 180, 270.
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300262 * Convert to 0, 1, 2 and 3 respectively for DSS
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300263 */
264static int v4l2_rot_to_dss_rot(int v4l2_rotation,
265 enum dss_rotation *rotation, bool mirror)
266{
267 int ret = 0;
268
269 switch (v4l2_rotation) {
270 case 90:
271 *rotation = dss_rotation_90_degree;
272 break;
273 case 180:
274 *rotation = dss_rotation_180_degree;
275 break;
276 case 270:
277 *rotation = dss_rotation_270_degree;
278 break;
279 case 0:
280 *rotation = dss_rotation_0_degree;
281 break;
282 default:
283 ret = -EINVAL;
284 }
285 return ret;
286}
287
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300288static int omap_vout_calculate_offset(struct omap_vout_device *vout)
289{
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300290 struct omapvideo_info *ovid;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300291 struct v4l2_rect *crop = &vout->crop;
292 struct v4l2_pix_format *pix = &vout->pix;
293 int *cropped_offset = &vout->cropped_offset;
archit taneja445e2582011-06-14 03:54:47 -0300294 int ps = 2, line_length = 0;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300295
296 ovid = &vout->vid_info;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300297
archit taneja445e2582011-06-14 03:54:47 -0300298 if (ovid->rotation_type == VOUT_ROT_VRFB) {
299 omap_vout_calculate_vrfb_offset(vout);
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300300 } else {
archit taneja445e2582011-06-14 03:54:47 -0300301 vout->line_length = line_length = pix->width;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300302
archit taneja445e2582011-06-14 03:54:47 -0300303 if (V4L2_PIX_FMT_YUYV == pix->pixelformat ||
304 V4L2_PIX_FMT_UYVY == pix->pixelformat)
305 ps = 2;
306 else if (V4L2_PIX_FMT_RGB32 == pix->pixelformat)
307 ps = 4;
308 else if (V4L2_PIX_FMT_RGB24 == pix->pixelformat)
309 ps = 3;
310
311 vout->ps = ps;
312
313 *cropped_offset = (line_length * ps) *
314 crop->top + crop->left * ps;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300315 }
archit taneja445e2582011-06-14 03:54:47 -0300316
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300317 v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "%s Offset:%x\n",
archit taneja445e2582011-06-14 03:54:47 -0300318 __func__, vout->cropped_offset);
319
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300320 return 0;
321}
322
323/*
324 * Convert V4L2 pixel format to DSS pixel format
325 */
Vaibhav Hiremath72fcf2a2010-04-11 10:50:23 -0300326static int video_mode_to_dss_mode(struct omap_vout_device *vout)
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300327{
328 struct omap_overlay *ovl;
329 struct omapvideo_info *ovid;
330 struct v4l2_pix_format *pix = &vout->pix;
331 enum omap_color_mode mode;
332
333 ovid = &vout->vid_info;
334 ovl = ovid->overlays[0];
335
336 switch (pix->pixelformat) {
337 case 0:
338 break;
339 case V4L2_PIX_FMT_YUYV:
340 mode = OMAP_DSS_COLOR_YUV2;
341 break;
342 case V4L2_PIX_FMT_UYVY:
343 mode = OMAP_DSS_COLOR_UYVY;
344 break;
345 case V4L2_PIX_FMT_RGB565:
346 mode = OMAP_DSS_COLOR_RGB16;
347 break;
348 case V4L2_PIX_FMT_RGB24:
349 mode = OMAP_DSS_COLOR_RGB24P;
350 break;
351 case V4L2_PIX_FMT_RGB32:
352 mode = (ovl->id == OMAP_DSS_VIDEO1) ?
353 OMAP_DSS_COLOR_RGB24U : OMAP_DSS_COLOR_ARGB32;
354 break;
355 case V4L2_PIX_FMT_BGR32:
356 mode = OMAP_DSS_COLOR_RGBX32;
357 break;
358 default:
359 mode = -EINVAL;
360 }
361 return mode;
362}
363
364/*
365 * Setup the overlay
366 */
archit tanejaa137ac82011-06-14 03:54:45 -0300367static int omapvid_setup_overlay(struct omap_vout_device *vout,
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300368 struct omap_overlay *ovl, int posx, int posy, int outw,
369 int outh, u32 addr)
370{
371 int ret = 0;
372 struct omap_overlay_info info;
373 int cropheight, cropwidth, pixheight, pixwidth;
374
375 if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0 &&
376 (outw != vout->pix.width || outh != vout->pix.height)) {
377 ret = -EINVAL;
378 goto setup_ovl_err;
379 }
380
381 vout->dss_mode = video_mode_to_dss_mode(vout);
382 if (vout->dss_mode == -EINVAL) {
383 ret = -EINVAL;
384 goto setup_ovl_err;
385 }
386
387 /* Setup the input plane parameters according to
388 * rotation value selected.
389 */
archit tanejab3668882011-06-14 03:54:46 -0300390 if (is_rotation_90_or_270(vout)) {
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300391 cropheight = vout->crop.width;
392 cropwidth = vout->crop.height;
393 pixheight = vout->pix.width;
394 pixwidth = vout->pix.height;
395 } else {
396 cropheight = vout->crop.height;
397 cropwidth = vout->crop.width;
398 pixheight = vout->pix.height;
399 pixwidth = vout->pix.width;
400 }
401
402 ovl->get_overlay_info(ovl, &info);
403 info.paddr = addr;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300404 info.width = cropwidth;
405 info.height = cropheight;
406 info.color_mode = vout->dss_mode;
407 info.mirror = vout->mirror;
408 info.pos_x = posx;
409 info.pos_y = posy;
410 info.out_width = outw;
411 info.out_height = outh;
412 info.global_alpha = vout->win.global_alpha;
archit tanejab3668882011-06-14 03:54:46 -0300413 if (!is_rotation_enabled(vout)) {
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300414 info.rotation = 0;
415 info.rotation_type = OMAP_DSS_ROT_DMA;
416 info.screen_width = pixwidth;
417 } else {
418 info.rotation = vout->rotation;
419 info.rotation_type = OMAP_DSS_ROT_VRFB;
420 info.screen_width = 2048;
421 }
422
423 v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev,
424 "%s enable=%d addr=%x width=%d\n height=%d color_mode=%d\n"
425 "rotation=%d mirror=%d posx=%d posy=%d out_width = %d \n"
426 "out_height=%d rotation_type=%d screen_width=%d\n",
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200427 __func__, ovl->is_enabled(ovl), info.paddr, info.width, info.height,
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300428 info.color_mode, info.rotation, info.mirror, info.pos_x,
429 info.pos_y, info.out_width, info.out_height, info.rotation_type,
430 info.screen_width);
431
432 ret = ovl->set_overlay_info(ovl, &info);
433 if (ret)
434 goto setup_ovl_err;
435
436 return 0;
437
438setup_ovl_err:
439 v4l2_warn(&vout->vid_dev->v4l2_dev, "setup_overlay failed\n");
440 return ret;
441}
442
443/*
444 * Initialize the overlay structure
445 */
archit tanejaa137ac82011-06-14 03:54:45 -0300446static int omapvid_init(struct omap_vout_device *vout, u32 addr)
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300447{
448 int ret = 0, i;
449 struct v4l2_window *win;
450 struct omap_overlay *ovl;
451 int posx, posy, outw, outh, temp;
452 struct omap_video_timings *timing;
453 struct omapvideo_info *ovid = &vout->vid_info;
454
455 win = &vout->win;
456 for (i = 0; i < ovid->num_overlays; i++) {
Linus Torvalds5f769452012-10-12 10:21:02 +0900457 struct omap_dss_device *dssdev;
458
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300459 ovl = ovid->overlays[i];
Linus Torvalds5f769452012-10-12 10:21:02 +0900460 dssdev = ovl->get_device(ovl);
461
462 if (!dssdev)
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300463 return -EINVAL;
464
Linus Torvalds5f769452012-10-12 10:21:02 +0900465 timing = &dssdev->panel.timings;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300466
467 outw = win->w.width;
468 outh = win->w.height;
469 switch (vout->rotation) {
470 case dss_rotation_90_degree:
471 /* Invert the height and width for 90
472 * and 270 degree rotation
473 */
474 temp = outw;
475 outw = outh;
476 outh = temp;
477 posy = (timing->y_res - win->w.width) - win->w.left;
478 posx = win->w.top;
479 break;
480
481 case dss_rotation_180_degree:
482 posx = (timing->x_res - win->w.width) - win->w.left;
483 posy = (timing->y_res - win->w.height) - win->w.top;
484 break;
485
486 case dss_rotation_270_degree:
487 temp = outw;
488 outw = outh;
489 outh = temp;
490 posy = win->w.left;
491 posx = (timing->x_res - win->w.height) - win->w.top;
492 break;
493
494 default:
495 posx = win->w.left;
496 posy = win->w.top;
497 break;
498 }
499
500 ret = omapvid_setup_overlay(vout, ovl, posx, posy,
501 outw, outh, addr);
502 if (ret)
503 goto omapvid_init_err;
504 }
505 return 0;
506
507omapvid_init_err:
508 v4l2_warn(&vout->vid_dev->v4l2_dev, "apply_changes failed\n");
509 return ret;
510}
511
512/*
513 * Apply the changes set the go bit of DSS
514 */
archit tanejaa137ac82011-06-14 03:54:45 -0300515static int omapvid_apply_changes(struct omap_vout_device *vout)
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300516{
517 int i;
518 struct omap_overlay *ovl;
519 struct omapvideo_info *ovid = &vout->vid_info;
520
521 for (i = 0; i < ovid->num_overlays; i++) {
Linus Torvalds5f769452012-10-12 10:21:02 +0900522 struct omap_dss_device *dssdev;
523
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300524 ovl = ovid->overlays[i];
Linus Torvalds5f769452012-10-12 10:21:02 +0900525 dssdev = ovl->get_device(ovl);
526 if (!dssdev)
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300527 return -EINVAL;
528 ovl->manager->apply(ovl->manager);
529 }
530
531 return 0;
532}
533
Archit Taneja27801682011-09-28 10:49:25 -0300534static int omapvid_handle_interlace_display(struct omap_vout_device *vout,
535 unsigned int irqstatus, struct timeval timevalue)
536{
537 u32 fid;
538
539 if (vout->first_int) {
540 vout->first_int = 0;
541 goto err;
542 }
543
544 if (irqstatus & DISPC_IRQ_EVSYNC_ODD)
545 fid = 1;
546 else if (irqstatus & DISPC_IRQ_EVSYNC_EVEN)
547 fid = 0;
548 else
549 goto err;
550
551 vout->field_id ^= 1;
552 if (fid != vout->field_id) {
553 if (fid == 0)
554 vout->field_id = fid;
555 } else if (0 == fid) {
556 if (vout->cur_frm == vout->next_frm)
557 goto err;
558
559 vout->cur_frm->ts = timevalue;
560 vout->cur_frm->state = VIDEOBUF_DONE;
561 wake_up_interruptible(&vout->cur_frm->done);
562 vout->cur_frm = vout->next_frm;
563 } else {
564 if (list_empty(&vout->dma_queue) ||
565 (vout->cur_frm != vout->next_frm))
566 goto err;
567 }
568
569 return vout->field_id;
570err:
571 return 0;
572}
573
archit tanejaa137ac82011-06-14 03:54:45 -0300574static void omap_vout_isr(void *arg, unsigned int irqstatus)
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300575{
Archit Tanejae144ca62011-09-28 10:49:26 -0300576 int ret, fid, mgr_id;
577 u32 addr, irq;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300578 struct omap_overlay *ovl;
579 struct timeval timevalue;
580 struct omapvideo_info *ovid;
581 struct omap_dss_device *cur_display;
582 struct omap_vout_device *vout = (struct omap_vout_device *)arg;
583
584 if (!vout->streaming)
585 return;
586
587 ovid = &vout->vid_info;
588 ovl = ovid->overlays[0];
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300589
Archit Tanejae144ca62011-09-28 10:49:26 -0300590 mgr_id = ovl->manager->id;
Linus Torvalds5f769452012-10-12 10:21:02 +0900591
592 /* get the display device attached to the overlay */
593 cur_display = ovl->get_device(ovl);
594
595 if (!cur_display)
596 return;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300597
598 spin_lock(&vout->vbq_lock);
599 do_gettimeofday(&timevalue);
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300600
Archit Taneja27801682011-09-28 10:49:25 -0300601 switch (cur_display->type) {
Archit Taneja881a9642011-09-28 10:49:27 -0300602 case OMAP_DISPLAY_TYPE_DSI:
Archit Taneja27801682011-09-28 10:49:25 -0300603 case OMAP_DISPLAY_TYPE_DPI:
Archit Tanejae144ca62011-09-28 10:49:26 -0300604 if (mgr_id == OMAP_DSS_CHANNEL_LCD)
605 irq = DISPC_IRQ_VSYNC;
606 else if (mgr_id == OMAP_DSS_CHANNEL_LCD2)
607 irq = DISPC_IRQ_VSYNC2;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300608 else
609 goto vout_isr_err;
610
Archit Tanejae144ca62011-09-28 10:49:26 -0300611 if (!(irqstatus & irq))
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300612 goto vout_isr_err;
Archit Taneja27801682011-09-28 10:49:25 -0300613 break;
614 case OMAP_DISPLAY_TYPE_VENC:
615 fid = omapvid_handle_interlace_display(vout, irqstatus,
616 timevalue);
617 if (!fid)
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300618 goto vout_isr_err;
Archit Taneja27801682011-09-28 10:49:25 -0300619 break;
620 case OMAP_DISPLAY_TYPE_HDMI:
621 if (!(irqstatus & DISPC_IRQ_EVSYNC_EVEN))
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300622 goto vout_isr_err;
Archit Taneja27801682011-09-28 10:49:25 -0300623 break;
624 default:
625 goto vout_isr_err;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300626 }
627
Archit Taneja27801682011-09-28 10:49:25 -0300628 if (!vout->first_int && (vout->cur_frm != vout->next_frm)) {
629 vout->cur_frm->ts = timevalue;
630 vout->cur_frm->state = VIDEOBUF_DONE;
631 wake_up_interruptible(&vout->cur_frm->done);
632 vout->cur_frm = vout->next_frm;
633 }
634
635 vout->first_int = 0;
636 if (list_empty(&vout->dma_queue))
637 goto vout_isr_err;
638
639 vout->next_frm = list_entry(vout->dma_queue.next,
640 struct videobuf_buffer, queue);
641 list_del(&vout->next_frm->queue);
642
643 vout->next_frm->state = VIDEOBUF_ACTIVE;
644
645 addr = (unsigned long) vout->queued_buf_addr[vout->next_frm->i]
646 + vout->cropped_offset;
647
648 /* First save the configuration in ovelray structure */
649 ret = omapvid_init(vout, addr);
650 if (ret)
651 printk(KERN_ERR VOUT_NAME
652 "failed to set overlay info\n");
653 /* Enable the pipeline and set the Go bit */
654 ret = omapvid_apply_changes(vout);
655 if (ret)
656 printk(KERN_ERR VOUT_NAME "failed to change mode\n");
657
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300658vout_isr_err:
659 spin_unlock(&vout->vbq_lock);
660}
661
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300662/* Video buffer call backs */
663
664/*
665 * Buffer setup function is called by videobuf layer when REQBUF ioctl is
666 * called. This is used to setup buffers and return size and count of
667 * buffers allocated. After the call to this buffer, videobuf layer will
668 * setup buffer queue depending on the size and count of buffers
669 */
670static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count,
671 unsigned int *size)
672{
673 int startindex = 0, i, j;
674 u32 phy_addr = 0, virt_addr = 0;
675 struct omap_vout_device *vout = q->priv_data;
archit taneja445e2582011-06-14 03:54:47 -0300676 struct omapvideo_info *ovid = &vout->vid_info;
Archit Tanejad06db7e2011-09-28 10:49:24 -0300677 int vid_max_buf_size;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300678
679 if (!vout)
680 return -EINVAL;
681
Archit Tanejad06db7e2011-09-28 10:49:24 -0300682 vid_max_buf_size = vout->vid == OMAP_VIDEO1 ? video1_bufsize :
683 video2_bufsize;
684
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300685 if (V4L2_BUF_TYPE_VIDEO_OUTPUT != q->type)
686 return -EINVAL;
687
688 startindex = (vout->vid == OMAP_VIDEO1) ?
689 video1_numbuffers : video2_numbuffers;
690 if (V4L2_MEMORY_MMAP == vout->memory && *count < startindex)
691 *count = startindex;
692
archit taneja445e2582011-06-14 03:54:47 -0300693 if (ovid->rotation_type == VOUT_ROT_VRFB) {
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300694 if (omap_vout_vrfb_buffer_setup(vout, count, startindex))
695 return -ENOMEM;
archit taneja445e2582011-06-14 03:54:47 -0300696 }
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300697
698 if (V4L2_MEMORY_MMAP != vout->memory)
699 return 0;
700
701 /* Now allocated the V4L2 buffers */
702 *size = PAGE_ALIGN(vout->pix.width * vout->pix.height * vout->bpp);
703 startindex = (vout->vid == OMAP_VIDEO1) ?
704 video1_numbuffers : video2_numbuffers;
705
Vaibhav Hiremath383e4f62011-04-14 13:42:34 -0300706 /* Check the size of the buffer */
Archit Tanejad06db7e2011-09-28 10:49:24 -0300707 if (*size > vid_max_buf_size) {
Vaibhav Hiremath383e4f62011-04-14 13:42:34 -0300708 v4l2_err(&vout->vid_dev->v4l2_dev,
709 "buffer allocation mismatch [%u] [%u]\n",
710 *size, vout->buffer_size);
711 return -ENOMEM;
712 }
713
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300714 for (i = startindex; i < *count; i++) {
715 vout->buffer_size = *size;
716
717 virt_addr = omap_vout_alloc_buffer(vout->buffer_size,
718 &phy_addr);
719 if (!virt_addr) {
archit taneja445e2582011-06-14 03:54:47 -0300720 if (ovid->rotation_type == VOUT_ROT_NONE) {
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300721 break;
archit taneja445e2582011-06-14 03:54:47 -0300722 } else {
723 if (!is_rotation_enabled(vout))
724 break;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300725 /* Free the VRFB buffers if no space for V4L2 buffers */
726 for (j = i; j < *count; j++) {
727 omap_vout_free_buffer(
728 vout->smsshado_virt_addr[j],
729 vout->smsshado_size);
730 vout->smsshado_virt_addr[j] = 0;
731 vout->smsshado_phy_addr[j] = 0;
archit taneja445e2582011-06-14 03:54:47 -0300732 }
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300733 }
734 }
735 vout->buf_virt_addr[i] = virt_addr;
736 vout->buf_phy_addr[i] = phy_addr;
737 }
738 *count = vout->buffer_allocated = i;
739
740 return 0;
741}
742
743/*
744 * Free the V4L2 buffers additionally allocated than default
archit taneja445e2582011-06-14 03:54:47 -0300745 * number of buffers
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300746 */
archit taneja445e2582011-06-14 03:54:47 -0300747static void omap_vout_free_extra_buffers(struct omap_vout_device *vout)
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300748{
749 int num_buffers = 0, i;
750
751 num_buffers = (vout->vid == OMAP_VIDEO1) ?
752 video1_numbuffers : video2_numbuffers;
753
754 for (i = num_buffers; i < vout->buffer_allocated; i++) {
755 if (vout->buf_virt_addr[i])
756 omap_vout_free_buffer(vout->buf_virt_addr[i],
757 vout->buffer_size);
758
759 vout->buf_virt_addr[i] = 0;
760 vout->buf_phy_addr[i] = 0;
761 }
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300762 vout->buffer_allocated = num_buffers;
763}
764
765/*
766 * This function will be called when VIDIOC_QBUF ioctl is called.
767 * It prepare buffers before give out for the display. This function
768 * converts user space virtual address into physical address if userptr memory
769 * exchange mechanism is used. If rotation is enabled, it copies entire
770 * buffer into VRFB memory space before giving it to the DSS.
771 */
772static int omap_vout_buffer_prepare(struct videobuf_queue *q,
archit taneja445e2582011-06-14 03:54:47 -0300773 struct videobuf_buffer *vb,
774 enum v4l2_field field)
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300775{
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300776 struct omap_vout_device *vout = q->priv_data;
archit taneja445e2582011-06-14 03:54:47 -0300777 struct omapvideo_info *ovid = &vout->vid_info;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300778
779 if (VIDEOBUF_NEEDS_INIT == vb->state) {
780 vb->width = vout->pix.width;
781 vb->height = vout->pix.height;
782 vb->size = vb->width * vb->height * vout->bpp;
783 vb->field = field;
784 }
785 vb->state = VIDEOBUF_PREPARED;
786 /* if user pointer memory mechanism is used, get the physical
787 * address of the buffer
788 */
789 if (V4L2_MEMORY_USERPTR == vb->memory) {
790 if (0 == vb->baddr)
791 return -EINVAL;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300792 /* Physical address */
Vaibhav Hiremathdd880dd2010-05-27 08:17:08 -0300793 vout->queued_buf_addr[vb->i] = (u8 *)
794 omap_vout_uservirt_to_phys(vb->baddr);
795 } else {
Amber Jain72915e82011-07-07 06:03:25 -0300796 u32 addr, dma_addr;
797 unsigned long size;
798
799 addr = (unsigned long) vout->buf_virt_addr[vb->i];
800 size = (unsigned long) vb->size;
801
802 dma_addr = dma_map_single(vout->vid_dev->v4l2_dev.dev, (void *) addr,
803 size, DMA_TO_DEVICE);
804 if (dma_mapping_error(vout->vid_dev->v4l2_dev.dev, dma_addr))
805 v4l2_err(&vout->vid_dev->v4l2_dev, "dma_map_single failed\n");
806
Vaibhav Hiremathdd880dd2010-05-27 08:17:08 -0300807 vout->queued_buf_addr[vb->i] = (u8 *)vout->buf_phy_addr[vb->i];
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300808 }
809
archit taneja445e2582011-06-14 03:54:47 -0300810 if (ovid->rotation_type == VOUT_ROT_VRFB)
811 return omap_vout_prepare_vrfb(vout, vb);
812 else
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300813 return 0;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300814}
815
816/*
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300817 * Buffer queue function will be called from the videobuf layer when _QBUF
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300818 * ioctl is called. It is used to enqueue buffer, which is ready to be
819 * displayed.
820 */
821static void omap_vout_buffer_queue(struct videobuf_queue *q,
822 struct videobuf_buffer *vb)
823{
824 struct omap_vout_device *vout = q->priv_data;
825
826 /* Driver is also maintainig a queue. So enqueue buffer in the driver
827 * queue */
828 list_add_tail(&vb->queue, &vout->dma_queue);
829
830 vb->state = VIDEOBUF_QUEUED;
831}
832
833/*
834 * Buffer release function is called from videobuf layer to release buffer
835 * which are already allocated
836 */
837static void omap_vout_buffer_release(struct videobuf_queue *q,
838 struct videobuf_buffer *vb)
839{
840 struct omap_vout_device *vout = q->priv_data;
841
842 vb->state = VIDEOBUF_NEEDS_INIT;
843
844 if (V4L2_MEMORY_MMAP != vout->memory)
845 return;
846}
847
848/*
849 * File operations
850 */
Laurent Pinchart94f3f482011-01-20 21:15:42 -0300851static unsigned int omap_vout_poll(struct file *file,
852 struct poll_table_struct *wait)
853{
854 struct omap_vout_device *vout = file->private_data;
855 struct videobuf_queue *q = &vout->vbq;
856
857 return videobuf_poll_stream(file, q, wait);
858}
859
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300860static void omap_vout_vm_open(struct vm_area_struct *vma)
861{
862 struct omap_vout_device *vout = vma->vm_private_data;
863
864 v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev,
865 "vm_open [vma=%08lx-%08lx]\n", vma->vm_start, vma->vm_end);
866 vout->mmap_count++;
867}
868
869static void omap_vout_vm_close(struct vm_area_struct *vma)
870{
871 struct omap_vout_device *vout = vma->vm_private_data;
872
873 v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev,
874 "vm_close [vma=%08lx-%08lx]\n", vma->vm_start, vma->vm_end);
875 vout->mmap_count--;
876}
877
878static struct vm_operations_struct omap_vout_vm_ops = {
879 .open = omap_vout_vm_open,
880 .close = omap_vout_vm_close,
881};
882
883static int omap_vout_mmap(struct file *file, struct vm_area_struct *vma)
884{
885 int i;
886 void *pos;
887 unsigned long start = vma->vm_start;
888 unsigned long size = (vma->vm_end - vma->vm_start);
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300889 struct omap_vout_device *vout = file->private_data;
890 struct videobuf_queue *q = &vout->vbq;
891
892 v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev,
893 " %s pgoff=0x%lx, start=0x%lx, end=0x%lx\n", __func__,
894 vma->vm_pgoff, vma->vm_start, vma->vm_end);
895
896 /* look for the buffer to map */
897 for (i = 0; i < VIDEO_MAX_FRAME; i++) {
898 if (NULL == q->bufs[i])
899 continue;
900 if (V4L2_MEMORY_MMAP != q->bufs[i]->memory)
901 continue;
902 if (q->bufs[i]->boff == (vma->vm_pgoff << PAGE_SHIFT))
903 break;
904 }
905
906 if (VIDEO_MAX_FRAME == i) {
907 v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev,
908 "offset invalid [offset=0x%lx]\n",
909 (vma->vm_pgoff << PAGE_SHIFT));
910 return -EINVAL;
911 }
Vaibhav Hiremath383e4f62011-04-14 13:42:34 -0300912 /* Check the size of the buffer */
913 if (size > vout->buffer_size) {
914 v4l2_err(&vout->vid_dev->v4l2_dev,
915 "insufficient memory [%lu] [%u]\n",
916 size, vout->buffer_size);
917 return -ENOMEM;
918 }
919
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300920 q->bufs[i]->baddr = vma->vm_start;
921
Konstantin Khlebnikov314e51b2012-10-08 16:29:02 -0700922 vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300923 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
924 vma->vm_ops = &omap_vout_vm_ops;
925 vma->vm_private_data = (void *) vout;
Vaibhav Hiremathdd880dd2010-05-27 08:17:08 -0300926 pos = (void *)vout->buf_virt_addr[i];
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300927 vma->vm_pgoff = virt_to_phys((void *)pos) >> PAGE_SHIFT;
928 while (size > 0) {
929 unsigned long pfn;
930 pfn = virt_to_phys((void *) pos) >> PAGE_SHIFT;
931 if (remap_pfn_range(vma, start, pfn, PAGE_SIZE, PAGE_SHARED))
932 return -EAGAIN;
933 start += PAGE_SIZE;
934 pos += PAGE_SIZE;
935 size -= PAGE_SIZE;
936 }
937 vout->mmap_count++;
938 v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Exiting %s\n", __func__);
939
940 return 0;
941}
942
943static int omap_vout_release(struct file *file)
944{
945 unsigned int ret, i;
946 struct videobuf_queue *q;
947 struct omapvideo_info *ovid;
948 struct omap_vout_device *vout = file->private_data;
949
950 v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Entering %s\n", __func__);
951 ovid = &vout->vid_info;
952
953 if (!vout)
954 return 0;
955
956 q = &vout->vbq;
957 /* Disable all the overlay managers connected with this interface */
958 for (i = 0; i < ovid->num_overlays; i++) {
959 struct omap_overlay *ovl = ovid->overlays[i];
Linus Torvalds5f769452012-10-12 10:21:02 +0900960 struct omap_dss_device *dssdev = ovl->get_device(ovl);
961
962 if (dssdev)
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200963 ovl->disable(ovl);
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300964 }
965 /* Turn off the pipeline */
966 ret = omapvid_apply_changes(vout);
967 if (ret)
968 v4l2_warn(&vout->vid_dev->v4l2_dev,
969 "Unable to apply changes\n");
970
971 /* Free all buffers */
archit taneja445e2582011-06-14 03:54:47 -0300972 omap_vout_free_extra_buffers(vout);
973
974 /* Free the VRFB buffers only if they are allocated
975 * during reqbufs. Don't free if init time allocated
976 */
977 if (ovid->rotation_type == VOUT_ROT_VRFB) {
978 if (!vout->vrfb_static_allocation)
979 omap_vout_free_vrfb_buffers(vout);
980 }
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300981 videobuf_mmap_free(q);
982
983 /* Even if apply changes fails we should continue
Uwe Kleine-Königb5950762010-11-01 15:38:34 -0400984 freeing allocated memory */
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300985 if (vout->streaming) {
986 u32 mask = 0;
987
988 mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN |
Amber Jain5251dd62011-06-02 02:30:10 -0300989 DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_VSYNC2;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300990 omap_dispc_unregister_isr(omap_vout_isr, vout, mask);
991 vout->streaming = 0;
992
993 videobuf_streamoff(q);
994 videobuf_queue_cancel(q);
995 }
996
997 if (vout->mmap_count != 0)
998 vout->mmap_count = 0;
999
1000 vout->opened -= 1;
1001 file->private_data = NULL;
1002
1003 if (vout->buffer_allocated)
1004 videobuf_mmap_free(q);
1005
1006 v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Exiting %s\n", __func__);
1007 return ret;
1008}
1009
1010static int omap_vout_open(struct file *file)
1011{
1012 struct videobuf_queue *q;
1013 struct omap_vout_device *vout = NULL;
1014
1015 vout = video_drvdata(file);
1016 v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Entering %s\n", __func__);
1017
1018 if (vout == NULL)
1019 return -ENODEV;
1020
1021 /* for now, we only support single open */
1022 if (vout->opened)
1023 return -EBUSY;
1024
1025 vout->opened += 1;
1026
1027 file->private_data = vout;
1028 vout->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
1029
1030 q = &vout->vbq;
1031 video_vbq_ops.buf_setup = omap_vout_buffer_setup;
1032 video_vbq_ops.buf_prepare = omap_vout_buffer_prepare;
1033 video_vbq_ops.buf_release = omap_vout_buffer_release;
1034 video_vbq_ops.buf_queue = omap_vout_buffer_queue;
1035 spin_lock_init(&vout->vbq_lock);
1036
Vaibhav Hiremathdd880dd2010-05-27 08:17:08 -03001037 videobuf_queue_dma_contig_init(q, &video_vbq_ops, q->dev,
1038 &vout->vbq_lock, vout->type, V4L2_FIELD_NONE,
Hans Verkuile3cfd442010-09-30 09:18:52 -03001039 sizeof(struct videobuf_buffer), vout, NULL);
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001040
1041 v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Exiting %s\n", __func__);
1042 return 0;
1043}
1044
1045/*
1046 * V4L2 ioctls
1047 */
1048static int vidioc_querycap(struct file *file, void *fh,
1049 struct v4l2_capability *cap)
1050{
1051 struct omap_vout_device *vout = fh;
1052
1053 strlcpy(cap->driver, VOUT_NAME, sizeof(cap->driver));
1054 strlcpy(cap->card, vout->vfd->name, sizeof(cap->card));
1055 cap->bus_info[0] = '\0';
Hans Verkuil047a01f2011-11-22 08:23:19 -03001056 cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT |
1057 V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001058
1059 return 0;
1060}
1061
1062static int vidioc_enum_fmt_vid_out(struct file *file, void *fh,
1063 struct v4l2_fmtdesc *fmt)
1064{
1065 int index = fmt->index;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001066
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001067 if (index >= NUM_OUTPUT_FORMATS)
1068 return -EINVAL;
1069
1070 fmt->flags = omap_formats[index].flags;
1071 strlcpy(fmt->description, omap_formats[index].description,
1072 sizeof(fmt->description));
1073 fmt->pixelformat = omap_formats[index].pixelformat;
1074
1075 return 0;
1076}
1077
1078static int vidioc_g_fmt_vid_out(struct file *file, void *fh,
1079 struct v4l2_format *f)
1080{
1081 struct omap_vout_device *vout = fh;
1082
1083 f->fmt.pix = vout->pix;
1084 return 0;
1085
1086}
1087
1088static int vidioc_try_fmt_vid_out(struct file *file, void *fh,
1089 struct v4l2_format *f)
1090{
1091 struct omap_overlay *ovl;
1092 struct omapvideo_info *ovid;
1093 struct omap_video_timings *timing;
1094 struct omap_vout_device *vout = fh;
Linus Torvalds5f769452012-10-12 10:21:02 +09001095 struct omap_dss_device *dssdev;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001096
1097 ovid = &vout->vid_info;
1098 ovl = ovid->overlays[0];
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001099 /* get the display device attached to the overlay */
Linus Torvalds5f769452012-10-12 10:21:02 +09001100 dssdev = ovl->get_device(ovl);
1101
1102 if (!dssdev)
1103 return -EINVAL;
1104
1105 timing = &dssdev->panel.timings;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001106
1107 vout->fbuf.fmt.height = timing->y_res;
1108 vout->fbuf.fmt.width = timing->x_res;
1109
1110 omap_vout_try_format(&f->fmt.pix);
1111 return 0;
1112}
1113
1114static int vidioc_s_fmt_vid_out(struct file *file, void *fh,
1115 struct v4l2_format *f)
1116{
1117 int ret, bpp;
1118 struct omap_overlay *ovl;
1119 struct omapvideo_info *ovid;
1120 struct omap_video_timings *timing;
1121 struct omap_vout_device *vout = fh;
Linus Torvalds5f769452012-10-12 10:21:02 +09001122 struct omap_dss_device *dssdev;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001123
1124 if (vout->streaming)
1125 return -EBUSY;
1126
1127 mutex_lock(&vout->lock);
1128
1129 ovid = &vout->vid_info;
1130 ovl = ovid->overlays[0];
Linus Torvalds5f769452012-10-12 10:21:02 +09001131 dssdev = ovl->get_device(ovl);
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001132
1133 /* get the display device attached to the overlay */
Linus Torvalds5f769452012-10-12 10:21:02 +09001134 if (!dssdev) {
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001135 ret = -EINVAL;
1136 goto s_fmt_vid_out_exit;
1137 }
Linus Torvalds5f769452012-10-12 10:21:02 +09001138 timing = &dssdev->panel.timings;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001139
1140 /* We dont support RGB24-packed mode if vrfb rotation
1141 * is enabled*/
archit tanejab3668882011-06-14 03:54:46 -03001142 if ((is_rotation_enabled(vout)) &&
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001143 f->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24) {
1144 ret = -EINVAL;
1145 goto s_fmt_vid_out_exit;
1146 }
1147
1148 /* get the framebuffer parameters */
1149
archit tanejab3668882011-06-14 03:54:46 -03001150 if (is_rotation_90_or_270(vout)) {
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001151 vout->fbuf.fmt.height = timing->x_res;
1152 vout->fbuf.fmt.width = timing->y_res;
1153 } else {
1154 vout->fbuf.fmt.height = timing->y_res;
1155 vout->fbuf.fmt.width = timing->x_res;
1156 }
1157
1158 /* change to samller size is OK */
1159
1160 bpp = omap_vout_try_format(&f->fmt.pix);
1161 f->fmt.pix.sizeimage = f->fmt.pix.width * f->fmt.pix.height * bpp;
1162
1163 /* try & set the new output format */
1164 vout->bpp = bpp;
1165 vout->pix = f->fmt.pix;
1166 vout->vrfb_bpp = 1;
1167
1168 /* If YUYV then vrfb bpp is 2, for others its 1 */
1169 if (V4L2_PIX_FMT_YUYV == vout->pix.pixelformat ||
1170 V4L2_PIX_FMT_UYVY == vout->pix.pixelformat)
1171 vout->vrfb_bpp = 2;
1172
1173 /* set default crop and win */
1174 omap_vout_new_format(&vout->pix, &vout->fbuf, &vout->crop, &vout->win);
1175
1176 /* Save the changes in the overlay strcuture */
1177 ret = omapvid_init(vout, 0);
1178 if (ret) {
1179 v4l2_err(&vout->vid_dev->v4l2_dev, "failed to change mode\n");
1180 goto s_fmt_vid_out_exit;
1181 }
1182
1183 ret = 0;
1184
1185s_fmt_vid_out_exit:
1186 mutex_unlock(&vout->lock);
1187 return ret;
1188}
1189
1190static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh,
1191 struct v4l2_format *f)
1192{
1193 int ret = 0;
1194 struct omap_vout_device *vout = fh;
Archit Taneja11354dd2011-09-26 11:47:29 +05301195 struct omap_overlay *ovl;
1196 struct omapvideo_info *ovid;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001197 struct v4l2_window *win = &f->fmt.win;
1198
Archit Taneja11354dd2011-09-26 11:47:29 +05301199 ovid = &vout->vid_info;
1200 ovl = ovid->overlays[0];
1201
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001202 ret = omap_vout_try_window(&vout->fbuf, win);
1203
1204 if (!ret) {
Archit Taneja11354dd2011-09-26 11:47:29 +05301205 if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001206 win->global_alpha = 255;
1207 else
1208 win->global_alpha = f->fmt.win.global_alpha;
1209 }
1210
1211 return ret;
1212}
1213
1214static int vidioc_s_fmt_vid_overlay(struct file *file, void *fh,
1215 struct v4l2_format *f)
1216{
1217 int ret = 0;
1218 struct omap_overlay *ovl;
1219 struct omapvideo_info *ovid;
1220 struct omap_vout_device *vout = fh;
1221 struct v4l2_window *win = &f->fmt.win;
1222
1223 mutex_lock(&vout->lock);
1224 ovid = &vout->vid_info;
1225 ovl = ovid->overlays[0];
1226
1227 ret = omap_vout_new_window(&vout->crop, &vout->win, &vout->fbuf, win);
1228 if (!ret) {
Archit Taneja11354dd2011-09-26 11:47:29 +05301229 /* Video1 plane does not support global alpha on OMAP3 */
1230 if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001231 vout->win.global_alpha = 255;
1232 else
1233 vout->win.global_alpha = f->fmt.win.global_alpha;
1234
1235 vout->win.chromakey = f->fmt.win.chromakey;
1236 }
1237 mutex_unlock(&vout->lock);
1238 return ret;
1239}
1240
1241static int vidioc_enum_fmt_vid_overlay(struct file *file, void *fh,
1242 struct v4l2_fmtdesc *fmt)
1243{
1244 int index = fmt->index;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001245
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001246 if (index >= NUM_OUTPUT_FORMATS)
1247 return -EINVAL;
1248
1249 fmt->flags = omap_formats[index].flags;
1250 strlcpy(fmt->description, omap_formats[index].description,
1251 sizeof(fmt->description));
1252 fmt->pixelformat = omap_formats[index].pixelformat;
1253 return 0;
1254}
1255
1256static int vidioc_g_fmt_vid_overlay(struct file *file, void *fh,
1257 struct v4l2_format *f)
1258{
1259 u32 key_value = 0;
1260 struct omap_overlay *ovl;
1261 struct omapvideo_info *ovid;
1262 struct omap_vout_device *vout = fh;
1263 struct omap_overlay_manager_info info;
1264 struct v4l2_window *win = &f->fmt.win;
1265
1266 ovid = &vout->vid_info;
1267 ovl = ovid->overlays[0];
1268
1269 win->w = vout->win.w;
1270 win->field = vout->win.field;
1271 win->global_alpha = vout->win.global_alpha;
1272
1273 if (ovl->manager && ovl->manager->get_manager_info) {
1274 ovl->manager->get_manager_info(ovl->manager, &info);
1275 key_value = info.trans_key;
1276 }
1277 win->chromakey = key_value;
1278 return 0;
1279}
1280
1281static int vidioc_cropcap(struct file *file, void *fh,
1282 struct v4l2_cropcap *cropcap)
1283{
1284 struct omap_vout_device *vout = fh;
1285 struct v4l2_pix_format *pix = &vout->pix;
1286
1287 if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
1288 return -EINVAL;
1289
1290 /* Width and height are always even */
1291 cropcap->bounds.width = pix->width & ~1;
1292 cropcap->bounds.height = pix->height & ~1;
1293
1294 omap_vout_default_crop(&vout->pix, &vout->fbuf, &cropcap->defrect);
1295 cropcap->pixelaspect.numerator = 1;
1296 cropcap->pixelaspect.denominator = 1;
1297 return 0;
1298}
1299
1300static int vidioc_g_crop(struct file *file, void *fh, struct v4l2_crop *crop)
1301{
1302 struct omap_vout_device *vout = fh;
1303
1304 if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
1305 return -EINVAL;
1306 crop->c = vout->crop;
1307 return 0;
1308}
1309
Hans Verkuil4f996592012-09-05 05:10:48 -03001310static int vidioc_s_crop(struct file *file, void *fh, const struct v4l2_crop *crop)
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001311{
1312 int ret = -EINVAL;
1313 struct omap_vout_device *vout = fh;
1314 struct omapvideo_info *ovid;
1315 struct omap_overlay *ovl;
1316 struct omap_video_timings *timing;
Linus Torvalds5f769452012-10-12 10:21:02 +09001317 struct omap_dss_device *dssdev;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001318
1319 if (vout->streaming)
1320 return -EBUSY;
1321
1322 mutex_lock(&vout->lock);
1323 ovid = &vout->vid_info;
1324 ovl = ovid->overlays[0];
Linus Torvalds5f769452012-10-12 10:21:02 +09001325 /* get the display device attached to the overlay */
1326 dssdev = ovl->get_device(ovl);
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001327
Linus Torvalds5f769452012-10-12 10:21:02 +09001328 if (!dssdev) {
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001329 ret = -EINVAL;
1330 goto s_crop_err;
1331 }
Linus Torvalds5f769452012-10-12 10:21:02 +09001332
1333 timing = &dssdev->panel.timings;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001334
archit tanejab3668882011-06-14 03:54:46 -03001335 if (is_rotation_90_or_270(vout)) {
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001336 vout->fbuf.fmt.height = timing->x_res;
1337 vout->fbuf.fmt.width = timing->y_res;
1338 } else {
1339 vout->fbuf.fmt.height = timing->y_res;
1340 vout->fbuf.fmt.width = timing->x_res;
1341 }
1342
1343 if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
1344 ret = omap_vout_new_crop(&vout->pix, &vout->crop, &vout->win,
1345 &vout->fbuf, &crop->c);
1346
1347s_crop_err:
1348 mutex_unlock(&vout->lock);
1349 return ret;
1350}
1351
1352static int vidioc_queryctrl(struct file *file, void *fh,
1353 struct v4l2_queryctrl *ctrl)
1354{
1355 int ret = 0;
1356
1357 switch (ctrl->id) {
1358 case V4L2_CID_ROTATE:
1359 ret = v4l2_ctrl_query_fill(ctrl, 0, 270, 90, 0);
1360 break;
1361 case V4L2_CID_BG_COLOR:
1362 ret = v4l2_ctrl_query_fill(ctrl, 0, 0xFFFFFF, 1, 0);
1363 break;
1364 case V4L2_CID_VFLIP:
1365 ret = v4l2_ctrl_query_fill(ctrl, 0, 1, 1, 0);
1366 break;
1367 default:
1368 ctrl->name[0] = '\0';
1369 ret = -EINVAL;
1370 }
1371 return ret;
1372}
1373
1374static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *ctrl)
1375{
1376 int ret = 0;
1377 struct omap_vout_device *vout = fh;
1378
1379 switch (ctrl->id) {
1380 case V4L2_CID_ROTATE:
1381 ctrl->value = vout->control[0].value;
1382 break;
1383 case V4L2_CID_BG_COLOR:
1384 {
1385 struct omap_overlay_manager_info info;
1386 struct omap_overlay *ovl;
1387
1388 ovl = vout->vid_info.overlays[0];
1389 if (!ovl->manager || !ovl->manager->get_manager_info) {
1390 ret = -EINVAL;
1391 break;
1392 }
1393
1394 ovl->manager->get_manager_info(ovl->manager, &info);
1395 ctrl->value = info.default_color;
1396 break;
1397 }
1398 case V4L2_CID_VFLIP:
1399 ctrl->value = vout->control[2].value;
1400 break;
1401 default:
1402 ret = -EINVAL;
1403 }
1404 return ret;
1405}
1406
1407static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *a)
1408{
1409 int ret = 0;
1410 struct omap_vout_device *vout = fh;
1411
1412 switch (a->id) {
1413 case V4L2_CID_ROTATE:
1414 {
archit taneja445e2582011-06-14 03:54:47 -03001415 struct omapvideo_info *ovid;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001416 int rotation = a->value;
1417
archit taneja445e2582011-06-14 03:54:47 -03001418 ovid = &vout->vid_info;
1419
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001420 mutex_lock(&vout->lock);
archit taneja445e2582011-06-14 03:54:47 -03001421 if (rotation && ovid->rotation_type == VOUT_ROT_NONE) {
1422 mutex_unlock(&vout->lock);
1423 ret = -ERANGE;
1424 break;
1425 }
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001426
1427 if (rotation && vout->pix.pixelformat == V4L2_PIX_FMT_RGB24) {
1428 mutex_unlock(&vout->lock);
1429 ret = -EINVAL;
1430 break;
1431 }
1432
1433 if (v4l2_rot_to_dss_rot(rotation, &vout->rotation,
1434 vout->mirror)) {
1435 mutex_unlock(&vout->lock);
1436 ret = -EINVAL;
1437 break;
1438 }
1439
1440 vout->control[0].value = rotation;
1441 mutex_unlock(&vout->lock);
1442 break;
1443 }
1444 case V4L2_CID_BG_COLOR:
1445 {
1446 struct omap_overlay *ovl;
1447 unsigned int color = a->value;
1448 struct omap_overlay_manager_info info;
1449
1450 ovl = vout->vid_info.overlays[0];
1451
1452 mutex_lock(&vout->lock);
1453 if (!ovl->manager || !ovl->manager->get_manager_info) {
1454 mutex_unlock(&vout->lock);
1455 ret = -EINVAL;
1456 break;
1457 }
1458
1459 ovl->manager->get_manager_info(ovl->manager, &info);
1460 info.default_color = color;
1461 if (ovl->manager->set_manager_info(ovl->manager, &info)) {
1462 mutex_unlock(&vout->lock);
1463 ret = -EINVAL;
1464 break;
1465 }
1466
1467 vout->control[1].value = color;
1468 mutex_unlock(&vout->lock);
1469 break;
1470 }
1471 case V4L2_CID_VFLIP:
1472 {
1473 struct omap_overlay *ovl;
1474 struct omapvideo_info *ovid;
1475 unsigned int mirror = a->value;
1476
1477 ovid = &vout->vid_info;
1478 ovl = ovid->overlays[0];
1479
1480 mutex_lock(&vout->lock);
archit taneja445e2582011-06-14 03:54:47 -03001481 if (mirror && ovid->rotation_type == VOUT_ROT_NONE) {
1482 mutex_unlock(&vout->lock);
1483 ret = -ERANGE;
1484 break;
1485 }
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001486
1487 if (mirror && vout->pix.pixelformat == V4L2_PIX_FMT_RGB24) {
1488 mutex_unlock(&vout->lock);
1489 ret = -EINVAL;
1490 break;
1491 }
1492 vout->mirror = mirror;
1493 vout->control[2].value = mirror;
1494 mutex_unlock(&vout->lock);
1495 break;
1496 }
1497 default:
1498 ret = -EINVAL;
1499 }
1500 return ret;
1501}
1502
1503static int vidioc_reqbufs(struct file *file, void *fh,
1504 struct v4l2_requestbuffers *req)
1505{
1506 int ret = 0;
1507 unsigned int i, num_buffers = 0;
1508 struct omap_vout_device *vout = fh;
1509 struct videobuf_queue *q = &vout->vbq;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001510
1511 if ((req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) || (req->count < 0))
1512 return -EINVAL;
1513 /* if memory is not mmp or userptr
1514 return error */
1515 if ((V4L2_MEMORY_MMAP != req->memory) &&
1516 (V4L2_MEMORY_USERPTR != req->memory))
1517 return -EINVAL;
1518
1519 mutex_lock(&vout->lock);
1520 /* Cannot be requested when streaming is on */
1521 if (vout->streaming) {
1522 ret = -EBUSY;
1523 goto reqbuf_err;
1524 }
1525
1526 /* If buffers are already allocated free them */
1527 if (q->bufs[0] && (V4L2_MEMORY_MMAP == q->bufs[0]->memory)) {
1528 if (vout->mmap_count) {
1529 ret = -EBUSY;
1530 goto reqbuf_err;
1531 }
1532 num_buffers = (vout->vid == OMAP_VIDEO1) ?
1533 video1_numbuffers : video2_numbuffers;
1534 for (i = num_buffers; i < vout->buffer_allocated; i++) {
Vaibhav Hiremathdd880dd2010-05-27 08:17:08 -03001535 omap_vout_free_buffer(vout->buf_virt_addr[i],
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001536 vout->buffer_size);
1537 vout->buf_virt_addr[i] = 0;
1538 vout->buf_phy_addr[i] = 0;
1539 }
1540 vout->buffer_allocated = num_buffers;
1541 videobuf_mmap_free(q);
1542 } else if (q->bufs[0] && (V4L2_MEMORY_USERPTR == q->bufs[0]->memory)) {
1543 if (vout->buffer_allocated) {
1544 videobuf_mmap_free(q);
1545 for (i = 0; i < vout->buffer_allocated; i++) {
1546 kfree(q->bufs[i]);
1547 q->bufs[i] = NULL;
1548 }
1549 vout->buffer_allocated = 0;
1550 }
1551 }
1552
1553 /*store the memory type in data structure */
1554 vout->memory = req->memory;
1555
1556 INIT_LIST_HEAD(&vout->dma_queue);
1557
1558 /* call videobuf_reqbufs api */
1559 ret = videobuf_reqbufs(q, req);
1560 if (ret < 0)
1561 goto reqbuf_err;
1562
1563 vout->buffer_allocated = req->count;
Vaibhav Hiremathdd880dd2010-05-27 08:17:08 -03001564
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001565reqbuf_err:
1566 mutex_unlock(&vout->lock);
1567 return ret;
1568}
1569
1570static int vidioc_querybuf(struct file *file, void *fh,
1571 struct v4l2_buffer *b)
1572{
1573 struct omap_vout_device *vout = fh;
1574
1575 return videobuf_querybuf(&vout->vbq, b);
1576}
1577
1578static int vidioc_qbuf(struct file *file, void *fh,
1579 struct v4l2_buffer *buffer)
1580{
1581 struct omap_vout_device *vout = fh;
1582 struct videobuf_queue *q = &vout->vbq;
1583
1584 if ((V4L2_BUF_TYPE_VIDEO_OUTPUT != buffer->type) ||
1585 (buffer->index >= vout->buffer_allocated) ||
1586 (q->bufs[buffer->index]->memory != buffer->memory)) {
1587 return -EINVAL;
1588 }
1589 if (V4L2_MEMORY_USERPTR == buffer->memory) {
1590 if ((buffer->length < vout->pix.sizeimage) ||
1591 (0 == buffer->m.userptr)) {
1592 return -EINVAL;
1593 }
1594 }
1595
archit tanejab3668882011-06-14 03:54:46 -03001596 if ((is_rotation_enabled(vout)) &&
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001597 vout->vrfb_dma_tx.req_status == DMA_CHAN_NOT_ALLOTED) {
1598 v4l2_warn(&vout->vid_dev->v4l2_dev,
1599 "DMA Channel not allocated for Rotation\n");
1600 return -EINVAL;
1601 }
1602
1603 return videobuf_qbuf(q, buffer);
1604}
1605
1606static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
1607{
1608 struct omap_vout_device *vout = fh;
1609 struct videobuf_queue *q = &vout->vbq;
1610
Amber Jain72915e82011-07-07 06:03:25 -03001611 int ret;
1612 u32 addr;
1613 unsigned long size;
1614 struct videobuf_buffer *vb;
1615
1616 vb = q->bufs[b->index];
1617
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001618 if (!vout->streaming)
1619 return -EINVAL;
1620
1621 if (file->f_flags & O_NONBLOCK)
1622 /* Call videobuf_dqbuf for non blocking mode */
Amber Jain72915e82011-07-07 06:03:25 -03001623 ret = videobuf_dqbuf(q, (struct v4l2_buffer *)b, 1);
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001624 else
1625 /* Call videobuf_dqbuf for blocking mode */
Amber Jain72915e82011-07-07 06:03:25 -03001626 ret = videobuf_dqbuf(q, (struct v4l2_buffer *)b, 0);
1627
1628 addr = (unsigned long) vout->buf_phy_addr[vb->i];
1629 size = (unsigned long) vb->size;
1630 dma_unmap_single(vout->vid_dev->v4l2_dev.dev, addr,
1631 size, DMA_TO_DEVICE);
1632 return ret;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001633}
1634
1635static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
1636{
1637 int ret = 0, j;
1638 u32 addr = 0, mask = 0;
1639 struct omap_vout_device *vout = fh;
1640 struct videobuf_queue *q = &vout->vbq;
1641 struct omapvideo_info *ovid = &vout->vid_info;
1642
1643 mutex_lock(&vout->lock);
1644
1645 if (vout->streaming) {
1646 ret = -EBUSY;
1647 goto streamon_err;
1648 }
1649
1650 ret = videobuf_streamon(q);
1651 if (ret)
1652 goto streamon_err;
1653
1654 if (list_empty(&vout->dma_queue)) {
1655 ret = -EIO;
1656 goto streamon_err1;
1657 }
1658
1659 /* Get the next frame from the buffer queue */
1660 vout->next_frm = vout->cur_frm = list_entry(vout->dma_queue.next,
1661 struct videobuf_buffer, queue);
1662 /* Remove buffer from the buffer queue */
1663 list_del(&vout->cur_frm->queue);
1664 /* Mark state of the current frame to active */
1665 vout->cur_frm->state = VIDEOBUF_ACTIVE;
1666 /* Initialize field_id and started member */
1667 vout->field_id = 0;
1668
1669 /* set flag here. Next QBUF will start DMA */
1670 vout->streaming = 1;
1671
1672 vout->first_int = 1;
1673
1674 if (omap_vout_calculate_offset(vout)) {
1675 ret = -EINVAL;
1676 goto streamon_err1;
1677 }
1678 addr = (unsigned long) vout->queued_buf_addr[vout->cur_frm->i]
1679 + vout->cropped_offset;
1680
Amber Jain5251dd62011-06-02 02:30:10 -03001681 mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD
1682 | DISPC_IRQ_VSYNC2;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001683
1684 omap_dispc_register_isr(omap_vout_isr, vout, mask);
1685
1686 for (j = 0; j < ovid->num_overlays; j++) {
1687 struct omap_overlay *ovl = ovid->overlays[j];
1688
Linus Torvalds5f769452012-10-12 10:21:02 +09001689 if (ovl->get_device(ovl)) {
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001690 struct omap_overlay_info info;
1691 ovl->get_overlay_info(ovl, &info);
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001692 info.paddr = addr;
1693 if (ovl->set_overlay_info(ovl, &info)) {
1694 ret = -EINVAL;
1695 goto streamon_err1;
1696 }
1697 }
1698 }
1699
1700 /* First save the configuration in ovelray structure */
1701 ret = omapvid_init(vout, addr);
1702 if (ret)
1703 v4l2_err(&vout->vid_dev->v4l2_dev,
1704 "failed to set overlay info\n");
1705 /* Enable the pipeline and set the Go bit */
1706 ret = omapvid_apply_changes(vout);
1707 if (ret)
1708 v4l2_err(&vout->vid_dev->v4l2_dev, "failed to change mode\n");
1709
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001710 for (j = 0; j < ovid->num_overlays; j++) {
1711 struct omap_overlay *ovl = ovid->overlays[j];
Linus Torvalds5f769452012-10-12 10:21:02 +09001712 struct omap_dss_device *dssdev = ovl->get_device(ovl);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001713
Linus Torvalds5f769452012-10-12 10:21:02 +09001714 if (dssdev) {
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001715 ret = ovl->enable(ovl);
1716 if (ret)
1717 goto streamon_err1;
1718 }
1719 }
1720
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001721 ret = 0;
1722
1723streamon_err1:
1724 if (ret)
1725 ret = videobuf_streamoff(q);
1726streamon_err:
1727 mutex_unlock(&vout->lock);
1728 return ret;
1729}
1730
1731static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
1732{
1733 u32 mask = 0;
1734 int ret = 0, j;
1735 struct omap_vout_device *vout = fh;
1736 struct omapvideo_info *ovid = &vout->vid_info;
1737
1738 if (!vout->streaming)
1739 return -EINVAL;
1740
1741 vout->streaming = 0;
Amber Jain5251dd62011-06-02 02:30:10 -03001742 mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD
1743 | DISPC_IRQ_VSYNC2;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001744
1745 omap_dispc_unregister_isr(omap_vout_isr, vout, mask);
1746
1747 for (j = 0; j < ovid->num_overlays; j++) {
1748 struct omap_overlay *ovl = ovid->overlays[j];
Linus Torvalds5f769452012-10-12 10:21:02 +09001749 struct omap_dss_device *dssdev = ovl->get_device(ovl);
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001750
Linus Torvalds5f769452012-10-12 10:21:02 +09001751 if (dssdev)
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001752 ovl->disable(ovl);
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001753 }
1754
1755 /* Turn of the pipeline */
1756 ret = omapvid_apply_changes(vout);
1757 if (ret)
1758 v4l2_err(&vout->vid_dev->v4l2_dev, "failed to change mode in"
1759 " streamoff\n");
1760
1761 INIT_LIST_HEAD(&vout->dma_queue);
1762 ret = videobuf_streamoff(&vout->vbq);
1763
1764 return ret;
1765}
1766
1767static int vidioc_s_fbuf(struct file *file, void *fh,
Hans Verkuile6eb28c2012-09-04 10:26:45 -03001768 const struct v4l2_framebuffer *a)
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001769{
1770 int enable = 0;
1771 struct omap_overlay *ovl;
1772 struct omapvideo_info *ovid;
1773 struct omap_vout_device *vout = fh;
1774 struct omap_overlay_manager_info info;
1775 enum omap_dss_trans_key_type key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
1776
1777 ovid = &vout->vid_info;
1778 ovl = ovid->overlays[0];
1779
1780 /* OMAP DSS doesn't support Source and Destination color
1781 key together */
1782 if ((a->flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY) &&
1783 (a->flags & V4L2_FBUF_FLAG_CHROMAKEY))
1784 return -EINVAL;
1785 /* OMAP DSS Doesn't support the Destination color key
1786 and alpha blending together */
1787 if ((a->flags & V4L2_FBUF_FLAG_CHROMAKEY) &&
1788 (a->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA))
1789 return -EINVAL;
1790
1791 if ((a->flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY)) {
1792 vout->fbuf.flags |= V4L2_FBUF_FLAG_SRC_CHROMAKEY;
1793 key_type = OMAP_DSS_COLOR_KEY_VID_SRC;
1794 } else
1795 vout->fbuf.flags &= ~V4L2_FBUF_FLAG_SRC_CHROMAKEY;
1796
1797 if ((a->flags & V4L2_FBUF_FLAG_CHROMAKEY)) {
1798 vout->fbuf.flags |= V4L2_FBUF_FLAG_CHROMAKEY;
1799 key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
1800 } else
1801 vout->fbuf.flags &= ~V4L2_FBUF_FLAG_CHROMAKEY;
1802
1803 if (a->flags & (V4L2_FBUF_FLAG_CHROMAKEY |
1804 V4L2_FBUF_FLAG_SRC_CHROMAKEY))
1805 enable = 1;
1806 else
1807 enable = 0;
1808 if (ovl->manager && ovl->manager->get_manager_info &&
1809 ovl->manager->set_manager_info) {
1810
1811 ovl->manager->get_manager_info(ovl->manager, &info);
1812 info.trans_enabled = enable;
1813 info.trans_key_type = key_type;
1814 info.trans_key = vout->win.chromakey;
1815
1816 if (ovl->manager->set_manager_info(ovl->manager, &info))
1817 return -EINVAL;
1818 }
1819 if (a->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) {
1820 vout->fbuf.flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
1821 enable = 1;
1822 } else {
1823 vout->fbuf.flags &= ~V4L2_FBUF_FLAG_LOCAL_ALPHA;
1824 enable = 0;
1825 }
1826 if (ovl->manager && ovl->manager->get_manager_info &&
1827 ovl->manager->set_manager_info) {
1828 ovl->manager->get_manager_info(ovl->manager, &info);
Archit Taneja11354dd2011-09-26 11:47:29 +05301829 /* enable this only if there is no zorder cap */
1830 if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)
1831 info.partial_alpha_enabled = enable;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001832 if (ovl->manager->set_manager_info(ovl->manager, &info))
1833 return -EINVAL;
1834 }
1835
1836 return 0;
1837}
1838
1839static int vidioc_g_fbuf(struct file *file, void *fh,
1840 struct v4l2_framebuffer *a)
1841{
1842 struct omap_overlay *ovl;
1843 struct omapvideo_info *ovid;
1844 struct omap_vout_device *vout = fh;
1845 struct omap_overlay_manager_info info;
1846
1847 ovid = &vout->vid_info;
1848 ovl = ovid->overlays[0];
1849
Hans Verkuil047a01f2011-11-22 08:23:19 -03001850 /* The video overlay must stay within the framebuffer and can't be
1851 positioned independently. */
1852 a->flags = V4L2_FBUF_FLAG_OVERLAY;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001853 a->capability = V4L2_FBUF_CAP_LOCAL_ALPHA | V4L2_FBUF_CAP_CHROMAKEY
1854 | V4L2_FBUF_CAP_SRC_CHROMAKEY;
1855
1856 if (ovl->manager && ovl->manager->get_manager_info) {
1857 ovl->manager->get_manager_info(ovl->manager, &info);
1858 if (info.trans_key_type == OMAP_DSS_COLOR_KEY_VID_SRC)
1859 a->flags |= V4L2_FBUF_FLAG_SRC_CHROMAKEY;
1860 if (info.trans_key_type == OMAP_DSS_COLOR_KEY_GFX_DST)
1861 a->flags |= V4L2_FBUF_FLAG_CHROMAKEY;
1862 }
1863 if (ovl->manager && ovl->manager->get_manager_info) {
1864 ovl->manager->get_manager_info(ovl->manager, &info);
Archit Taneja11354dd2011-09-26 11:47:29 +05301865 if (info.partial_alpha_enabled)
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001866 a->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
1867 }
1868
1869 return 0;
1870}
1871
1872static const struct v4l2_ioctl_ops vout_ioctl_ops = {
1873 .vidioc_querycap = vidioc_querycap,
1874 .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
1875 .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out,
1876 .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
1877 .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out,
1878 .vidioc_queryctrl = vidioc_queryctrl,
1879 .vidioc_g_ctrl = vidioc_g_ctrl,
1880 .vidioc_s_fbuf = vidioc_s_fbuf,
1881 .vidioc_g_fbuf = vidioc_g_fbuf,
1882 .vidioc_s_ctrl = vidioc_s_ctrl,
1883 .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_vid_overlay,
1884 .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_vid_overlay,
1885 .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt_vid_overlay,
1886 .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_vid_overlay,
1887 .vidioc_cropcap = vidioc_cropcap,
1888 .vidioc_g_crop = vidioc_g_crop,
1889 .vidioc_s_crop = vidioc_s_crop,
1890 .vidioc_reqbufs = vidioc_reqbufs,
1891 .vidioc_querybuf = vidioc_querybuf,
1892 .vidioc_qbuf = vidioc_qbuf,
1893 .vidioc_dqbuf = vidioc_dqbuf,
1894 .vidioc_streamon = vidioc_streamon,
1895 .vidioc_streamoff = vidioc_streamoff,
1896};
1897
1898static const struct v4l2_file_operations omap_vout_fops = {
1899 .owner = THIS_MODULE,
Laurent Pinchart94f3f482011-01-20 21:15:42 -03001900 .poll = omap_vout_poll,
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001901 .unlocked_ioctl = video_ioctl2,
1902 .mmap = omap_vout_mmap,
1903 .open = omap_vout_open,
1904 .release = omap_vout_release,
1905};
1906
1907/* Init functions used during driver initialization */
1908/* Initial setup of video_data */
1909static int __init omap_vout_setup_video_data(struct omap_vout_device *vout)
1910{
1911 struct video_device *vfd;
1912 struct v4l2_pix_format *pix;
1913 struct v4l2_control *control;
Linus Torvalds5f769452012-10-12 10:21:02 +09001914 struct omap_overlay *ovl = vout->vid_info.overlays[0];
1915 struct omap_dss_device *display = ovl->get_device(ovl);
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001916
1917 /* set the default pix */
1918 pix = &vout->pix;
1919
1920 /* Set the default picture of QVGA */
1921 pix->width = QQVGA_WIDTH;
1922 pix->height = QQVGA_HEIGHT;
1923
1924 /* Default pixel format is RGB 5-6-5 */
1925 pix->pixelformat = V4L2_PIX_FMT_RGB565;
1926 pix->field = V4L2_FIELD_ANY;
1927 pix->bytesperline = pix->width * 2;
1928 pix->sizeimage = pix->bytesperline * pix->height;
1929 pix->priv = 0;
1930 pix->colorspace = V4L2_COLORSPACE_JPEG;
1931
1932 vout->bpp = RGB565_BPP;
1933 vout->fbuf.fmt.width = display->panel.timings.x_res;
1934 vout->fbuf.fmt.height = display->panel.timings.y_res;
1935
1936 /* Set the data structures for the overlay parameters*/
1937 vout->win.global_alpha = 255;
1938 vout->fbuf.flags = 0;
1939 vout->fbuf.capability = V4L2_FBUF_CAP_LOCAL_ALPHA |
1940 V4L2_FBUF_CAP_SRC_CHROMAKEY | V4L2_FBUF_CAP_CHROMAKEY;
1941 vout->win.chromakey = 0;
1942
1943 omap_vout_new_format(pix, &vout->fbuf, &vout->crop, &vout->win);
1944
1945 /*Initialize the control variables for
1946 rotation, flipping and background color. */
1947 control = vout->control;
1948 control[0].id = V4L2_CID_ROTATE;
1949 control[0].value = 0;
1950 vout->rotation = 0;
1951 vout->mirror = 0;
1952 vout->control[2].id = V4L2_CID_HFLIP;
1953 vout->control[2].value = 0;
archit taneja445e2582011-06-14 03:54:47 -03001954 if (vout->vid_info.rotation_type == VOUT_ROT_VRFB)
1955 vout->vrfb_bpp = 2;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001956
1957 control[1].id = V4L2_CID_BG_COLOR;
1958 control[1].value = 0;
1959
1960 /* initialize the video_device struct */
1961 vfd = vout->vfd = video_device_alloc();
1962
1963 if (!vfd) {
1964 printk(KERN_ERR VOUT_NAME ": could not allocate"
1965 " video device struct\n");
1966 return -ENOMEM;
1967 }
1968 vfd->release = video_device_release;
1969 vfd->ioctl_ops = &vout_ioctl_ops;
1970
1971 strlcpy(vfd->name, VOUT_NAME, sizeof(vfd->name));
1972
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001973 vfd->fops = &omap_vout_fops;
1974 vfd->v4l2_dev = &vout->vid_dev->v4l2_dev;
Hans Verkuil954f3402012-09-05 06:05:50 -03001975 vfd->vfl_dir = VFL_DIR_TX;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001976 mutex_init(&vout->lock);
1977
1978 vfd->minor = -1;
1979 return 0;
1980
1981}
1982
1983/* Setup video buffers */
1984static int __init omap_vout_setup_video_bufs(struct platform_device *pdev,
1985 int vid_num)
1986{
1987 u32 numbuffers;
archit taneja445e2582011-06-14 03:54:47 -03001988 int ret = 0, i;
1989 struct omapvideo_info *ovid;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001990 struct omap_vout_device *vout;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001991 struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
1992 struct omap2video_device *vid_dev =
1993 container_of(v4l2_dev, struct omap2video_device, v4l2_dev);
1994
1995 vout = vid_dev->vouts[vid_num];
archit taneja445e2582011-06-14 03:54:47 -03001996 ovid = &vout->vid_info;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001997
1998 numbuffers = (vid_num == 0) ? video1_numbuffers : video2_numbuffers;
1999 vout->buffer_size = (vid_num == 0) ? video1_bufsize : video2_bufsize;
2000 dev_info(&pdev->dev, "Buffer Size = %d\n", vout->buffer_size);
2001
2002 for (i = 0; i < numbuffers; i++) {
2003 vout->buf_virt_addr[i] =
2004 omap_vout_alloc_buffer(vout->buffer_size,
2005 (u32 *) &vout->buf_phy_addr[i]);
2006 if (!vout->buf_virt_addr[i]) {
2007 numbuffers = i;
2008 ret = -ENOMEM;
2009 goto free_buffers;
2010 }
2011 }
2012
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002013 vout->cropped_offset = 0;
2014
archit taneja445e2582011-06-14 03:54:47 -03002015 if (ovid->rotation_type == VOUT_ROT_VRFB) {
2016 int static_vrfb_allocation = (vid_num == 0) ?
2017 vid1_static_vrfb_alloc : vid2_static_vrfb_alloc;
2018 ret = omap_vout_setup_vrfb_bufs(pdev, vid_num,
2019 static_vrfb_allocation);
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002020 }
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002021
archit taneja445e2582011-06-14 03:54:47 -03002022 return ret;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002023
2024free_buffers:
2025 for (i = 0; i < numbuffers; i++) {
2026 omap_vout_free_buffer(vout->buf_virt_addr[i],
2027 vout->buffer_size);
2028 vout->buf_virt_addr[i] = 0;
2029 vout->buf_phy_addr[i] = 0;
2030 }
2031 return ret;
2032
2033}
2034
2035/* Create video out devices */
2036static int __init omap_vout_create_video_devices(struct platform_device *pdev)
2037{
2038 int ret = 0, k;
2039 struct omap_vout_device *vout;
2040 struct video_device *vfd = NULL;
2041 struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
2042 struct omap2video_device *vid_dev = container_of(v4l2_dev,
2043 struct omap2video_device, v4l2_dev);
2044
2045 for (k = 0; k < pdev->num_resources; k++) {
2046
Julia Lawall2ef17c92010-05-13 16:59:15 -03002047 vout = kzalloc(sizeof(struct omap_vout_device), GFP_KERNEL);
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002048 if (!vout) {
2049 dev_err(&pdev->dev, ": could not allocate memory\n");
2050 return -ENOMEM;
2051 }
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002052
2053 vout->vid = k;
2054 vid_dev->vouts[k] = vout;
2055 vout->vid_dev = vid_dev;
2056 /* Select video2 if only 1 overlay is controlled by V4L2 */
2057 if (pdev->num_resources == 1)
2058 vout->vid_info.overlays[0] = vid_dev->overlays[k + 2];
2059 else
2060 /* Else select video1 and video2 one by one. */
2061 vout->vid_info.overlays[0] = vid_dev->overlays[k + 1];
2062 vout->vid_info.num_overlays = 1;
2063 vout->vid_info.id = k + 1;
2064
archit taneja445e2582011-06-14 03:54:47 -03002065 /* Set VRFB as rotation_type for omap2 and omap3 */
Tomi Valkeinen950e2fb2012-11-12 15:17:39 +02002066 if (omap_vout_dss_omap24xx() || omap_vout_dss_omap34xx())
archit taneja445e2582011-06-14 03:54:47 -03002067 vout->vid_info.rotation_type = VOUT_ROT_VRFB;
2068
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002069 /* Setup the default configuration for the video devices
2070 */
2071 if (omap_vout_setup_video_data(vout) != 0) {
2072 ret = -ENOMEM;
2073 goto error;
2074 }
2075
2076 /* Allocate default number of buffers for the video streaming
2077 * and reserve the VRFB space for rotation
2078 */
2079 if (omap_vout_setup_video_bufs(pdev, k) != 0) {
2080 ret = -ENOMEM;
2081 goto error1;
2082 }
2083
2084 /* Register the Video device with V4L2
2085 */
2086 vfd = vout->vfd;
Vaibhav Hiremath8f3a3072011-06-16 15:32:07 -03002087 if (video_register_device(vfd, VFL_TYPE_GRABBER, -1) < 0) {
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002088 dev_err(&pdev->dev, ": Could not register "
2089 "Video for Linux device\n");
2090 vfd->minor = -1;
2091 ret = -ENODEV;
2092 goto error2;
2093 }
2094 video_set_drvdata(vfd, vout);
2095
2096 /* Configure the overlay structure */
2097 ret = omapvid_init(vid_dev->vouts[k], 0);
2098 if (!ret)
2099 goto success;
2100
2101error2:
archit taneja445e2582011-06-14 03:54:47 -03002102 if (vout->vid_info.rotation_type == VOUT_ROT_VRFB)
2103 omap_vout_release_vrfb(vout);
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002104 omap_vout_free_buffers(vout);
2105error1:
2106 video_device_release(vfd);
2107error:
2108 kfree(vout);
2109 return ret;
2110
2111success:
2112 dev_info(&pdev->dev, ": registered and initialized"
2113 " video device %d\n", vfd->minor);
2114 if (k == (pdev->num_resources - 1))
2115 return 0;
2116 }
2117
2118 return -ENODEV;
2119}
2120/* Driver functions */
2121static void omap_vout_cleanup_device(struct omap_vout_device *vout)
2122{
2123 struct video_device *vfd;
archit taneja445e2582011-06-14 03:54:47 -03002124 struct omapvideo_info *ovid;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002125
2126 if (!vout)
2127 return;
2128
2129 vfd = vout->vfd;
archit taneja445e2582011-06-14 03:54:47 -03002130 ovid = &vout->vid_info;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002131 if (vfd) {
2132 if (!video_is_registered(vfd)) {
2133 /*
2134 * The device was never registered, so release the
2135 * video_device struct directly.
2136 */
2137 video_device_release(vfd);
2138 } else {
2139 /*
2140 * The unregister function will release the video_device
2141 * struct as well as unregistering it.
2142 */
2143 video_unregister_device(vfd);
2144 }
2145 }
archit taneja445e2582011-06-14 03:54:47 -03002146 if (ovid->rotation_type == VOUT_ROT_VRFB) {
2147 omap_vout_release_vrfb(vout);
2148 /* Free the VRFB buffer if allocated
2149 * init time
2150 */
2151 if (vout->vrfb_static_allocation)
2152 omap_vout_free_vrfb_buffers(vout);
2153 }
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002154 omap_vout_free_buffers(vout);
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002155
2156 kfree(vout);
2157}
2158
2159static int omap_vout_remove(struct platform_device *pdev)
2160{
2161 int k;
2162 struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
2163 struct omap2video_device *vid_dev = container_of(v4l2_dev, struct
2164 omap2video_device, v4l2_dev);
2165
2166 v4l2_device_unregister(v4l2_dev);
2167 for (k = 0; k < pdev->num_resources; k++)
2168 omap_vout_cleanup_device(vid_dev->vouts[k]);
2169
2170 for (k = 0; k < vid_dev->num_displays; k++) {
2171 if (vid_dev->displays[k]->state != OMAP_DSS_DISPLAY_DISABLED)
Vaibhav Hiremath5ba9bb02010-05-27 08:17:07 -03002172 vid_dev->displays[k]->driver->disable(vid_dev->displays[k]);
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002173
2174 omap_dss_put_device(vid_dev->displays[k]);
2175 }
2176 kfree(vid_dev);
2177 return 0;
2178}
2179
2180static int __init omap_vout_probe(struct platform_device *pdev)
2181{
2182 int ret = 0, i;
2183 struct omap_overlay *ovl;
2184 struct omap_dss_device *dssdev = NULL;
2185 struct omap_dss_device *def_display;
2186 struct omap2video_device *vid_dev = NULL;
2187
2188 if (pdev->num_resources == 0) {
2189 dev_err(&pdev->dev, "probed for an unknown device\n");
2190 return -ENODEV;
2191 }
2192
2193 vid_dev = kzalloc(sizeof(struct omap2video_device), GFP_KERNEL);
2194 if (vid_dev == NULL)
2195 return -ENOMEM;
2196
2197 vid_dev->num_displays = 0;
2198 for_each_dss_dev(dssdev) {
2199 omap_dss_get_device(dssdev);
Tomi Valkeinen71c7a972011-11-14 04:28:59 -03002200
2201 if (!dssdev->driver) {
2202 dev_warn(&pdev->dev, "no driver for display: %s\n",
2203 dssdev->name);
2204 omap_dss_put_device(dssdev);
2205 continue;
2206 }
2207
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002208 vid_dev->displays[vid_dev->num_displays++] = dssdev;
2209 }
2210
2211 if (vid_dev->num_displays == 0) {
2212 dev_err(&pdev->dev, "no displays\n");
2213 ret = -EINVAL;
2214 goto probe_err0;
2215 }
2216
2217 vid_dev->num_overlays = omap_dss_get_num_overlays();
2218 for (i = 0; i < vid_dev->num_overlays; i++)
2219 vid_dev->overlays[i] = omap_dss_get_overlay(i);
2220
2221 vid_dev->num_managers = omap_dss_get_num_overlay_managers();
2222 for (i = 0; i < vid_dev->num_managers; i++)
2223 vid_dev->managers[i] = omap_dss_get_overlay_manager(i);
2224
2225 /* Get the Video1 overlay and video2 overlay.
2226 * Setup the Display attached to that overlays
2227 */
2228 for (i = 1; i < vid_dev->num_overlays; i++) {
2229 ovl = omap_dss_get_overlay(i);
Linus Torvalds5f769452012-10-12 10:21:02 +09002230 dssdev = ovl->get_device(ovl);
2231
2232 if (dssdev) {
2233 def_display = dssdev;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002234 } else {
2235 dev_warn(&pdev->dev, "cannot find display\n");
2236 def_display = NULL;
2237 }
2238 if (def_display) {
Vaibhav Hiremath5ba9bb02010-05-27 08:17:07 -03002239 struct omap_dss_driver *dssdrv = def_display->driver;
2240
2241 ret = dssdrv->enable(def_display);
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002242 if (ret) {
2243 /* Here we are not considering a error
2244 * as display may be enabled by frame
2245 * buffer driver
2246 */
2247 dev_warn(&pdev->dev,
2248 "'%s' Display already enabled\n",
2249 def_display->name);
2250 }
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002251 }
2252 }
2253
2254 if (v4l2_device_register(&pdev->dev, &vid_dev->v4l2_dev) < 0) {
2255 dev_err(&pdev->dev, "v4l2_device_register failed\n");
2256 ret = -ENODEV;
2257 goto probe_err1;
2258 }
2259
2260 ret = omap_vout_create_video_devices(pdev);
2261 if (ret)
2262 goto probe_err2;
2263
2264 for (i = 0; i < vid_dev->num_displays; i++) {
2265 struct omap_dss_device *display = vid_dev->displays[i];
2266
Vaibhav Hiremath5ba9bb02010-05-27 08:17:07 -03002267 if (display->driver->update)
2268 display->driver->update(display, 0, 0,
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002269 display->panel.timings.x_res,
2270 display->panel.timings.y_res);
2271 }
2272 return 0;
2273
2274probe_err2:
2275 v4l2_device_unregister(&vid_dev->v4l2_dev);
2276probe_err1:
2277 for (i = 1; i < vid_dev->num_overlays; i++) {
2278 def_display = NULL;
2279 ovl = omap_dss_get_overlay(i);
Linus Torvalds5f769452012-10-12 10:21:02 +09002280 dssdev = ovl->get_device(ovl);
2281
2282 if (dssdev)
2283 def_display = dssdev;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002284
Vaibhav Hiremath5ba9bb02010-05-27 08:17:07 -03002285 if (def_display && def_display->driver)
2286 def_display->driver->disable(def_display);
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002287 }
2288probe_err0:
2289 kfree(vid_dev);
2290 return ret;
2291}
2292
2293static struct platform_driver omap_vout_driver = {
2294 .driver = {
2295 .name = VOUT_NAME,
2296 },
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002297 .remove = omap_vout_remove,
2298};
2299
2300static int __init omap_vout_init(void)
2301{
Tomi Valkeinen93596ef2011-11-08 05:47:08 -03002302 if (platform_driver_probe(&omap_vout_driver, omap_vout_probe) != 0) {
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002303 printk(KERN_ERR VOUT_NAME ":Could not register Video driver\n");
2304 return -EINVAL;
2305 }
2306 return 0;
2307}
2308
2309static void omap_vout_cleanup(void)
2310{
2311 platform_driver_unregister(&omap_vout_driver);
2312}
2313
2314late_initcall(omap_vout_init);
2315module_exit(omap_vout_cleanup);