blob: ba2d8f973d580aca85e4195dd9d9eb68cf86568e [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
Tomi Valkeinen6a1c9f62012-10-08 14:52:24 +030047#include <video/omapvrfb.h>
Tomi Valkeinena0b38cc2011-05-11 14:05:07 +030048#include <video/omapdss.h>
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -030049
50#include "omap_voutlib.h"
51#include "omap_voutdef.h"
archit taneja445e2582011-06-14 03:54:47 -030052#include "omap_vout_vrfb.h"
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -030053
54MODULE_AUTHOR("Texas Instruments");
55MODULE_DESCRIPTION("OMAP Video for Linux Video out driver");
56MODULE_LICENSE("GPL");
57
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -030058/* Driver Configuration macros */
59#define VOUT_NAME "omap_vout"
60
61enum omap_vout_channels {
62 OMAP_VIDEO1,
63 OMAP_VIDEO2,
64};
65
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -030066static struct videobuf_queue_ops video_vbq_ops;
67/* Variables configurable through module params*/
68static u32 video1_numbuffers = 3;
69static u32 video2_numbuffers = 3;
70static u32 video1_bufsize = OMAP_VOUT_MAX_BUF_SIZE;
71static u32 video2_bufsize = OMAP_VOUT_MAX_BUF_SIZE;
Rusty Russell90ab5ee2012-01-13 09:32:20 +103072static bool vid1_static_vrfb_alloc;
73static bool vid2_static_vrfb_alloc;
74static bool debug;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -030075
76/* Module parameters */
77module_param(video1_numbuffers, uint, S_IRUGO);
78MODULE_PARM_DESC(video1_numbuffers,
79 "Number of buffers to be allocated at init time for Video1 device.");
80
81module_param(video2_numbuffers, uint, S_IRUGO);
82MODULE_PARM_DESC(video2_numbuffers,
83 "Number of buffers to be allocated at init time for Video2 device.");
84
85module_param(video1_bufsize, uint, S_IRUGO);
86MODULE_PARM_DESC(video1_bufsize,
87 "Size of the buffer to be allocated for video1 device");
88
89module_param(video2_bufsize, uint, S_IRUGO);
90MODULE_PARM_DESC(video2_bufsize,
91 "Size of the buffer to be allocated for video2 device");
92
93module_param(vid1_static_vrfb_alloc, bool, S_IRUGO);
94MODULE_PARM_DESC(vid1_static_vrfb_alloc,
95 "Static allocation of the VRFB buffer for video1 device");
96
97module_param(vid2_static_vrfb_alloc, bool, S_IRUGO);
98MODULE_PARM_DESC(vid2_static_vrfb_alloc,
99 "Static allocation of the VRFB buffer for video2 device");
100
101module_param(debug, bool, S_IRUGO);
102MODULE_PARM_DESC(debug, "Debug level (0-1)");
103
104/* list of image formats supported by OMAP2 video pipelines */
Jesper Juhl0d334f72011-07-09 18:22:17 -0300105static const struct v4l2_fmtdesc omap_formats[] = {
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300106 {
107 /* Note: V4L2 defines RGB565 as:
108 *
109 * Byte 0 Byte 1
110 * g2 g1 g0 r4 r3 r2 r1 r0 b4 b3 b2 b1 b0 g5 g4 g3
111 *
112 * We interpret RGB565 as:
113 *
114 * Byte 0 Byte 1
115 * g2 g1 g0 b4 b3 b2 b1 b0 r4 r3 r2 r1 r0 g5 g4 g3
116 */
117 .description = "RGB565, le",
118 .pixelformat = V4L2_PIX_FMT_RGB565,
119 },
120 {
121 /* Note: V4L2 defines RGB32 as: RGB-8-8-8-8 we use
122 * this for RGB24 unpack mode, the last 8 bits are ignored
123 * */
124 .description = "RGB32, le",
125 .pixelformat = V4L2_PIX_FMT_RGB32,
126 },
127 {
128 /* Note: V4L2 defines RGB24 as: RGB-8-8-8 we use
129 * this for RGB24 packed mode
130 *
131 */
132 .description = "RGB24, le",
133 .pixelformat = V4L2_PIX_FMT_RGB24,
134 },
135 {
136 .description = "YUYV (YUV 4:2:2), packed",
137 .pixelformat = V4L2_PIX_FMT_YUYV,
138 },
139 {
140 .description = "UYVY, packed",
141 .pixelformat = V4L2_PIX_FMT_UYVY,
142 },
143};
144
145#define NUM_OUTPUT_FORMATS (ARRAY_SIZE(omap_formats))
146
147/*
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300148 * Try format
149 */
150static int omap_vout_try_format(struct v4l2_pix_format *pix)
151{
152 int ifmt, bpp = 0;
153
154 pix->height = clamp(pix->height, (u32)VID_MIN_HEIGHT,
155 (u32)VID_MAX_HEIGHT);
156 pix->width = clamp(pix->width, (u32)VID_MIN_WIDTH, (u32)VID_MAX_WIDTH);
157
158 for (ifmt = 0; ifmt < NUM_OUTPUT_FORMATS; ifmt++) {
159 if (pix->pixelformat == omap_formats[ifmt].pixelformat)
160 break;
161 }
162
163 if (ifmt == NUM_OUTPUT_FORMATS)
164 ifmt = 0;
165
166 pix->pixelformat = omap_formats[ifmt].pixelformat;
167 pix->field = V4L2_FIELD_ANY;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300168
169 switch (pix->pixelformat) {
170 case V4L2_PIX_FMT_YUYV:
171 case V4L2_PIX_FMT_UYVY:
172 default:
173 pix->colorspace = V4L2_COLORSPACE_JPEG;
174 bpp = YUYV_BPP;
175 break;
176 case V4L2_PIX_FMT_RGB565:
177 case V4L2_PIX_FMT_RGB565X:
178 pix->colorspace = V4L2_COLORSPACE_SRGB;
179 bpp = RGB565_BPP;
180 break;
181 case V4L2_PIX_FMT_RGB24:
182 pix->colorspace = V4L2_COLORSPACE_SRGB;
183 bpp = RGB24_BPP;
184 break;
185 case V4L2_PIX_FMT_RGB32:
186 case V4L2_PIX_FMT_BGR32:
187 pix->colorspace = V4L2_COLORSPACE_SRGB;
188 bpp = RGB32_BPP;
189 break;
190 }
191 pix->bytesperline = pix->width * bpp;
192 pix->sizeimage = pix->bytesperline * pix->height;
193
194 return bpp;
195}
196
197/*
198 * omap_vout_uservirt_to_phys: This inline function is used to convert user
199 * space virtual address to physical address.
200 */
Hans Verkuile8bd8882014-12-01 08:32:54 -0300201static unsigned long omap_vout_uservirt_to_phys(unsigned long virtp)
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300202{
203 unsigned long physp = 0;
204 struct vm_area_struct *vma;
205 struct mm_struct *mm = current->mm;
206
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300207 /* For kernel direct-mapped memory, take the easy way */
Al Viro55ee64b2012-12-16 16:04:46 -0300208 if (virtp >= PAGE_OFFSET)
209 return virt_to_phys((void *) virtp);
210
211 down_read(&current->mm->mmap_sem);
212 vma = find_vma(mm, virtp);
213 if (vma && (vma->vm_flags & VM_IO) && vma->vm_pgoff) {
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300214 /* this will catch, kernel-allocated, mmaped-to-usermode
215 addresses */
216 physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start);
Al Viro55ee64b2012-12-16 16:04:46 -0300217 up_read(&current->mm->mmap_sem);
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300218 } else {
219 /* otherwise, use get_user_pages() for general userland pages */
220 int res, nr_pages = 1;
221 struct page *pages;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300222
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) {
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300337 case V4L2_PIX_FMT_YUYV:
338 mode = OMAP_DSS_COLOR_YUV2;
339 break;
340 case V4L2_PIX_FMT_UYVY:
341 mode = OMAP_DSS_COLOR_UYVY;
342 break;
343 case V4L2_PIX_FMT_RGB565:
344 mode = OMAP_DSS_COLOR_RGB16;
345 break;
346 case V4L2_PIX_FMT_RGB24:
347 mode = OMAP_DSS_COLOR_RGB24P;
348 break;
349 case V4L2_PIX_FMT_RGB32:
350 mode = (ovl->id == OMAP_DSS_VIDEO1) ?
351 OMAP_DSS_COLOR_RGB24U : OMAP_DSS_COLOR_ARGB32;
352 break;
353 case V4L2_PIX_FMT_BGR32:
354 mode = OMAP_DSS_COLOR_RGBX32;
355 break;
356 default:
357 mode = -EINVAL;
Hans Verkuilfe653782013-06-20 16:28:16 -0300358 break;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300359 }
360 return mode;
361}
362
363/*
364 * Setup the overlay
365 */
archit tanejaa137ac82011-06-14 03:54:45 -0300366static int omapvid_setup_overlay(struct omap_vout_device *vout,
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300367 struct omap_overlay *ovl, int posx, int posy, int outw,
368 int outh, u32 addr)
369{
370 int ret = 0;
371 struct omap_overlay_info info;
Mauro Carvalho Chehab52334bb2014-08-26 10:46:49 -0300372 int cropheight, cropwidth, pixwidth;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300373
374 if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0 &&
375 (outw != vout->pix.width || outh != vout->pix.height)) {
376 ret = -EINVAL;
377 goto setup_ovl_err;
378 }
379
380 vout->dss_mode = video_mode_to_dss_mode(vout);
381 if (vout->dss_mode == -EINVAL) {
382 ret = -EINVAL;
383 goto setup_ovl_err;
384 }
385
386 /* Setup the input plane parameters according to
387 * rotation value selected.
388 */
archit tanejab3668882011-06-14 03:54:46 -0300389 if (is_rotation_90_or_270(vout)) {
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300390 cropheight = vout->crop.width;
391 cropwidth = vout->crop.height;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300392 pixwidth = vout->pix.height;
393 } else {
394 cropheight = vout->crop.height;
395 cropwidth = vout->crop.width;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300396 pixwidth = vout->pix.width;
397 }
398
399 ovl->get_overlay_info(ovl, &info);
400 info.paddr = addr;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300401 info.width = cropwidth;
402 info.height = cropheight;
403 info.color_mode = vout->dss_mode;
404 info.mirror = vout->mirror;
405 info.pos_x = posx;
406 info.pos_y = posy;
407 info.out_width = outw;
408 info.out_height = outh;
409 info.global_alpha = vout->win.global_alpha;
archit tanejab3668882011-06-14 03:54:46 -0300410 if (!is_rotation_enabled(vout)) {
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300411 info.rotation = 0;
412 info.rotation_type = OMAP_DSS_ROT_DMA;
413 info.screen_width = pixwidth;
414 } else {
415 info.rotation = vout->rotation;
416 info.rotation_type = OMAP_DSS_ROT_VRFB;
417 info.screen_width = 2048;
418 }
419
420 v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev,
Hans Verkuile8bd8882014-12-01 08:32:54 -0300421 "%s enable=%d addr=%pad width=%d\n height=%d color_mode=%d\n"
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300422 "rotation=%d mirror=%d posx=%d posy=%d out_width = %d \n"
423 "out_height=%d rotation_type=%d screen_width=%d\n",
Hans Verkuile8bd8882014-12-01 08:32:54 -0300424 __func__, ovl->is_enabled(ovl), &info.paddr, info.width, info.height,
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300425 info.color_mode, info.rotation, info.mirror, info.pos_x,
426 info.pos_y, info.out_width, info.out_height, info.rotation_type,
427 info.screen_width);
428
429 ret = ovl->set_overlay_info(ovl, &info);
430 if (ret)
431 goto setup_ovl_err;
432
433 return 0;
434
435setup_ovl_err:
436 v4l2_warn(&vout->vid_dev->v4l2_dev, "setup_overlay failed\n");
437 return ret;
438}
439
440/*
441 * Initialize the overlay structure
442 */
archit tanejaa137ac82011-06-14 03:54:45 -0300443static int omapvid_init(struct omap_vout_device *vout, u32 addr)
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300444{
445 int ret = 0, i;
446 struct v4l2_window *win;
447 struct omap_overlay *ovl;
448 int posx, posy, outw, outh, temp;
449 struct omap_video_timings *timing;
450 struct omapvideo_info *ovid = &vout->vid_info;
451
452 win = &vout->win;
453 for (i = 0; i < ovid->num_overlays; i++) {
Linus Torvalds5f769452012-10-12 10:21:02 +0900454 struct omap_dss_device *dssdev;
455
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300456 ovl = ovid->overlays[i];
Linus Torvalds5f769452012-10-12 10:21:02 +0900457 dssdev = ovl->get_device(ovl);
458
459 if (!dssdev)
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300460 return -EINVAL;
461
Linus Torvalds5f769452012-10-12 10:21:02 +0900462 timing = &dssdev->panel.timings;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300463
464 outw = win->w.width;
465 outh = win->w.height;
466 switch (vout->rotation) {
467 case dss_rotation_90_degree:
468 /* Invert the height and width for 90
469 * and 270 degree rotation
470 */
471 temp = outw;
472 outw = outh;
473 outh = temp;
474 posy = (timing->y_res - win->w.width) - win->w.left;
475 posx = win->w.top;
476 break;
477
478 case dss_rotation_180_degree:
479 posx = (timing->x_res - win->w.width) - win->w.left;
480 posy = (timing->y_res - win->w.height) - win->w.top;
481 break;
482
483 case dss_rotation_270_degree:
484 temp = outw;
485 outw = outh;
486 outh = temp;
487 posy = win->w.left;
488 posx = (timing->x_res - win->w.height) - win->w.top;
489 break;
490
491 default:
492 posx = win->w.left;
493 posy = win->w.top;
494 break;
495 }
496
497 ret = omapvid_setup_overlay(vout, ovl, posx, posy,
498 outw, outh, addr);
499 if (ret)
500 goto omapvid_init_err;
501 }
502 return 0;
503
504omapvid_init_err:
505 v4l2_warn(&vout->vid_dev->v4l2_dev, "apply_changes failed\n");
506 return ret;
507}
508
509/*
510 * Apply the changes set the go bit of DSS
511 */
archit tanejaa137ac82011-06-14 03:54:45 -0300512static int omapvid_apply_changes(struct omap_vout_device *vout)
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300513{
514 int i;
515 struct omap_overlay *ovl;
516 struct omapvideo_info *ovid = &vout->vid_info;
517
518 for (i = 0; i < ovid->num_overlays; i++) {
Linus Torvalds5f769452012-10-12 10:21:02 +0900519 struct omap_dss_device *dssdev;
520
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300521 ovl = ovid->overlays[i];
Linus Torvalds5f769452012-10-12 10:21:02 +0900522 dssdev = ovl->get_device(ovl);
523 if (!dssdev)
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300524 return -EINVAL;
525 ovl->manager->apply(ovl->manager);
526 }
527
528 return 0;
529}
530
Archit Taneja27801682011-09-28 10:49:25 -0300531static int omapvid_handle_interlace_display(struct omap_vout_device *vout,
532 unsigned int irqstatus, struct timeval timevalue)
533{
534 u32 fid;
535
536 if (vout->first_int) {
537 vout->first_int = 0;
538 goto err;
539 }
540
541 if (irqstatus & DISPC_IRQ_EVSYNC_ODD)
542 fid = 1;
543 else if (irqstatus & DISPC_IRQ_EVSYNC_EVEN)
544 fid = 0;
545 else
546 goto err;
547
548 vout->field_id ^= 1;
549 if (fid != vout->field_id) {
550 if (fid == 0)
551 vout->field_id = fid;
552 } else if (0 == fid) {
553 if (vout->cur_frm == vout->next_frm)
554 goto err;
555
556 vout->cur_frm->ts = timevalue;
557 vout->cur_frm->state = VIDEOBUF_DONE;
558 wake_up_interruptible(&vout->cur_frm->done);
559 vout->cur_frm = vout->next_frm;
560 } else {
561 if (list_empty(&vout->dma_queue) ||
562 (vout->cur_frm != vout->next_frm))
563 goto err;
564 }
565
566 return vout->field_id;
567err:
568 return 0;
569}
570
archit tanejaa137ac82011-06-14 03:54:45 -0300571static void omap_vout_isr(void *arg, unsigned int irqstatus)
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300572{
Archit Tanejae144ca62011-09-28 10:49:26 -0300573 int ret, fid, mgr_id;
574 u32 addr, irq;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300575 struct omap_overlay *ovl;
576 struct timeval timevalue;
577 struct omapvideo_info *ovid;
578 struct omap_dss_device *cur_display;
579 struct omap_vout_device *vout = (struct omap_vout_device *)arg;
580
581 if (!vout->streaming)
582 return;
583
584 ovid = &vout->vid_info;
585 ovl = ovid->overlays[0];
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300586
Archit Tanejae144ca62011-09-28 10:49:26 -0300587 mgr_id = ovl->manager->id;
Linus Torvalds5f769452012-10-12 10:21:02 +0900588
589 /* get the display device attached to the overlay */
590 cur_display = ovl->get_device(ovl);
591
592 if (!cur_display)
593 return;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300594
595 spin_lock(&vout->vbq_lock);
Sakari Ailus8e6057b2012-09-15 15:14:42 -0300596 v4l2_get_timestamp(&timevalue);
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300597
Archit Taneja27801682011-09-28 10:49:25 -0300598 switch (cur_display->type) {
Archit Taneja881a9642011-09-28 10:49:27 -0300599 case OMAP_DISPLAY_TYPE_DSI:
Archit Taneja27801682011-09-28 10:49:25 -0300600 case OMAP_DISPLAY_TYPE_DPI:
Laurent Pinchartc6a328a2014-02-08 11:32:15 -0300601 case OMAP_DISPLAY_TYPE_DVI:
Archit Tanejae144ca62011-09-28 10:49:26 -0300602 if (mgr_id == OMAP_DSS_CHANNEL_LCD)
603 irq = DISPC_IRQ_VSYNC;
604 else if (mgr_id == OMAP_DSS_CHANNEL_LCD2)
605 irq = DISPC_IRQ_VSYNC2;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300606 else
607 goto vout_isr_err;
608
Archit Tanejae144ca62011-09-28 10:49:26 -0300609 if (!(irqstatus & irq))
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300610 goto vout_isr_err;
Archit Taneja27801682011-09-28 10:49:25 -0300611 break;
612 case OMAP_DISPLAY_TYPE_VENC:
613 fid = omapvid_handle_interlace_display(vout, irqstatus,
614 timevalue);
615 if (!fid)
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300616 goto vout_isr_err;
Archit Taneja27801682011-09-28 10:49:25 -0300617 break;
618 case OMAP_DISPLAY_TYPE_HDMI:
619 if (!(irqstatus & DISPC_IRQ_EVSYNC_EVEN))
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300620 goto vout_isr_err;
Archit Taneja27801682011-09-28 10:49:25 -0300621 break;
622 default:
623 goto vout_isr_err;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300624 }
625
Archit Taneja27801682011-09-28 10:49:25 -0300626 if (!vout->first_int && (vout->cur_frm != vout->next_frm)) {
627 vout->cur_frm->ts = timevalue;
628 vout->cur_frm->state = VIDEOBUF_DONE;
629 wake_up_interruptible(&vout->cur_frm->done);
630 vout->cur_frm = vout->next_frm;
631 }
632
633 vout->first_int = 0;
634 if (list_empty(&vout->dma_queue))
635 goto vout_isr_err;
636
637 vout->next_frm = list_entry(vout->dma_queue.next,
638 struct videobuf_buffer, queue);
639 list_del(&vout->next_frm->queue);
640
641 vout->next_frm->state = VIDEOBUF_ACTIVE;
642
643 addr = (unsigned long) vout->queued_buf_addr[vout->next_frm->i]
644 + vout->cropped_offset;
645
646 /* First save the configuration in ovelray structure */
647 ret = omapvid_init(vout, addr);
Federico Fuga15170022012-08-24 11:54:11 -0300648 if (ret) {
Archit Taneja27801682011-09-28 10:49:25 -0300649 printk(KERN_ERR VOUT_NAME
650 "failed to set overlay info\n");
Federico Fuga15170022012-08-24 11:54:11 -0300651 goto vout_isr_err;
652 }
653
Archit Taneja27801682011-09-28 10:49:25 -0300654 /* Enable the pipeline and set the Go bit */
655 ret = omapvid_apply_changes(vout);
656 if (ret)
657 printk(KERN_ERR VOUT_NAME "failed to change mode\n");
658
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300659vout_isr_err:
660 spin_unlock(&vout->vbq_lock);
661}
662
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300663/* Video buffer call backs */
664
665/*
666 * Buffer setup function is called by videobuf layer when REQBUF ioctl is
667 * called. This is used to setup buffers and return size and count of
668 * buffers allocated. After the call to this buffer, videobuf layer will
669 * setup buffer queue depending on the size and count of buffers
670 */
671static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count,
672 unsigned int *size)
673{
674 int startindex = 0, i, j;
675 u32 phy_addr = 0, virt_addr = 0;
676 struct omap_vout_device *vout = q->priv_data;
archit taneja445e2582011-06-14 03:54:47 -0300677 struct omapvideo_info *ovid = &vout->vid_info;
Archit Tanejad06db7e2011-09-28 10:49:24 -0300678 int vid_max_buf_size;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300679
680 if (!vout)
681 return -EINVAL;
682
Archit Tanejad06db7e2011-09-28 10:49:24 -0300683 vid_max_buf_size = vout->vid == OMAP_VIDEO1 ? video1_bufsize :
684 video2_bufsize;
685
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300686 if (V4L2_BUF_TYPE_VIDEO_OUTPUT != q->type)
687 return -EINVAL;
688
689 startindex = (vout->vid == OMAP_VIDEO1) ?
690 video1_numbuffers : video2_numbuffers;
691 if (V4L2_MEMORY_MMAP == vout->memory && *count < startindex)
692 *count = startindex;
693
archit taneja445e2582011-06-14 03:54:47 -0300694 if (ovid->rotation_type == VOUT_ROT_VRFB) {
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300695 if (omap_vout_vrfb_buffer_setup(vout, count, startindex))
696 return -ENOMEM;
archit taneja445e2582011-06-14 03:54:47 -0300697 }
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300698
699 if (V4L2_MEMORY_MMAP != vout->memory)
700 return 0;
701
702 /* Now allocated the V4L2 buffers */
703 *size = PAGE_ALIGN(vout->pix.width * vout->pix.height * vout->bpp);
704 startindex = (vout->vid == OMAP_VIDEO1) ?
705 video1_numbuffers : video2_numbuffers;
706
Vaibhav Hiremath383e4f62011-04-14 13:42:34 -0300707 /* Check the size of the buffer */
Archit Tanejad06db7e2011-09-28 10:49:24 -0300708 if (*size > vid_max_buf_size) {
Vaibhav Hiremath383e4f62011-04-14 13:42:34 -0300709 v4l2_err(&vout->vid_dev->v4l2_dev,
710 "buffer allocation mismatch [%u] [%u]\n",
711 *size, vout->buffer_size);
712 return -ENOMEM;
713 }
714
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300715 for (i = startindex; i < *count; i++) {
716 vout->buffer_size = *size;
717
718 virt_addr = omap_vout_alloc_buffer(vout->buffer_size,
719 &phy_addr);
720 if (!virt_addr) {
archit taneja445e2582011-06-14 03:54:47 -0300721 if (ovid->rotation_type == VOUT_ROT_NONE) {
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300722 break;
archit taneja445e2582011-06-14 03:54:47 -0300723 } else {
724 if (!is_rotation_enabled(vout))
725 break;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300726 /* Free the VRFB buffers if no space for V4L2 buffers */
727 for (j = i; j < *count; j++) {
728 omap_vout_free_buffer(
729 vout->smsshado_virt_addr[j],
730 vout->smsshado_size);
731 vout->smsshado_virt_addr[j] = 0;
732 vout->smsshado_phy_addr[j] = 0;
archit taneja445e2582011-06-14 03:54:47 -0300733 }
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300734 }
735 }
736 vout->buf_virt_addr[i] = virt_addr;
737 vout->buf_phy_addr[i] = phy_addr;
738 }
739 *count = vout->buffer_allocated = i;
740
741 return 0;
742}
743
744/*
745 * Free the V4L2 buffers additionally allocated than default
archit taneja445e2582011-06-14 03:54:47 -0300746 * number of buffers
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300747 */
archit taneja445e2582011-06-14 03:54:47 -0300748static void omap_vout_free_extra_buffers(struct omap_vout_device *vout)
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300749{
750 int num_buffers = 0, i;
751
752 num_buffers = (vout->vid == OMAP_VIDEO1) ?
753 video1_numbuffers : video2_numbuffers;
754
755 for (i = num_buffers; i < vout->buffer_allocated; i++) {
756 if (vout->buf_virt_addr[i])
757 omap_vout_free_buffer(vout->buf_virt_addr[i],
758 vout->buffer_size);
759
760 vout->buf_virt_addr[i] = 0;
761 vout->buf_phy_addr[i] = 0;
762 }
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300763 vout->buffer_allocated = num_buffers;
764}
765
766/*
767 * This function will be called when VIDIOC_QBUF ioctl is called.
768 * It prepare buffers before give out for the display. This function
769 * converts user space virtual address into physical address if userptr memory
770 * exchange mechanism is used. If rotation is enabled, it copies entire
771 * buffer into VRFB memory space before giving it to the DSS.
772 */
773static int omap_vout_buffer_prepare(struct videobuf_queue *q,
archit taneja445e2582011-06-14 03:54:47 -0300774 struct videobuf_buffer *vb,
775 enum v4l2_field field)
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300776{
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300777 struct omap_vout_device *vout = q->priv_data;
archit taneja445e2582011-06-14 03:54:47 -0300778 struct omapvideo_info *ovid = &vout->vid_info;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300779
780 if (VIDEOBUF_NEEDS_INIT == vb->state) {
781 vb->width = vout->pix.width;
782 vb->height = vout->pix.height;
783 vb->size = vb->width * vb->height * vout->bpp;
784 vb->field = field;
785 }
786 vb->state = VIDEOBUF_PREPARED;
787 /* if user pointer memory mechanism is used, get the physical
788 * address of the buffer
789 */
790 if (V4L2_MEMORY_USERPTR == vb->memory) {
791 if (0 == vb->baddr)
792 return -EINVAL;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300793 /* Physical address */
Vaibhav Hiremathdd880dd2010-05-27 08:17:08 -0300794 vout->queued_buf_addr[vb->i] = (u8 *)
795 omap_vout_uservirt_to_phys(vb->baddr);
796 } else {
Hans Verkuile8bd8882014-12-01 08:32:54 -0300797 unsigned long addr, dma_addr;
Amber Jain72915e82011-07-07 06:03:25 -0300798 unsigned long size;
799
800 addr = (unsigned long) vout->buf_virt_addr[vb->i];
801 size = (unsigned long) vb->size;
802
803 dma_addr = dma_map_single(vout->vid_dev->v4l2_dev.dev, (void *) addr,
804 size, DMA_TO_DEVICE);
805 if (dma_mapping_error(vout->vid_dev->v4l2_dev.dev, dma_addr))
806 v4l2_err(&vout->vid_dev->v4l2_dev, "dma_map_single failed\n");
807
Vaibhav Hiremathdd880dd2010-05-27 08:17:08 -0300808 vout->queued_buf_addr[vb->i] = (u8 *)vout->buf_phy_addr[vb->i];
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300809 }
810
archit taneja445e2582011-06-14 03:54:47 -0300811 if (ovid->rotation_type == VOUT_ROT_VRFB)
812 return omap_vout_prepare_vrfb(vout, vb);
813 else
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300814 return 0;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300815}
816
817/*
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300818 * Buffer queue function will be called from the videobuf layer when _QBUF
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300819 * ioctl is called. It is used to enqueue buffer, which is ready to be
820 * displayed.
821 */
822static void omap_vout_buffer_queue(struct videobuf_queue *q,
823 struct videobuf_buffer *vb)
824{
825 struct omap_vout_device *vout = q->priv_data;
826
827 /* Driver is also maintainig a queue. So enqueue buffer in the driver
828 * queue */
829 list_add_tail(&vb->queue, &vout->dma_queue);
830
831 vb->state = VIDEOBUF_QUEUED;
832}
833
834/*
835 * Buffer release function is called from videobuf layer to release buffer
836 * which are already allocated
837 */
838static void omap_vout_buffer_release(struct videobuf_queue *q,
839 struct videobuf_buffer *vb)
840{
841 struct omap_vout_device *vout = q->priv_data;
842
843 vb->state = VIDEOBUF_NEEDS_INIT;
844
845 if (V4L2_MEMORY_MMAP != vout->memory)
846 return;
847}
848
849/*
850 * File operations
851 */
Laurent Pinchart94f3f482011-01-20 21:15:42 -0300852static unsigned int omap_vout_poll(struct file *file,
853 struct poll_table_struct *wait)
854{
855 struct omap_vout_device *vout = file->private_data;
856 struct videobuf_queue *q = &vout->vbq;
857
858 return videobuf_poll_stream(file, q, wait);
859}
860
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300861static void omap_vout_vm_open(struct vm_area_struct *vma)
862{
863 struct omap_vout_device *vout = vma->vm_private_data;
864
865 v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev,
866 "vm_open [vma=%08lx-%08lx]\n", vma->vm_start, vma->vm_end);
867 vout->mmap_count++;
868}
869
870static void omap_vout_vm_close(struct vm_area_struct *vma)
871{
872 struct omap_vout_device *vout = vma->vm_private_data;
873
874 v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev,
875 "vm_close [vma=%08lx-%08lx]\n", vma->vm_start, vma->vm_end);
876 vout->mmap_count--;
877}
878
879static struct vm_operations_struct omap_vout_vm_ops = {
880 .open = omap_vout_vm_open,
881 .close = omap_vout_vm_close,
882};
883
884static int omap_vout_mmap(struct file *file, struct vm_area_struct *vma)
885{
886 int i;
887 void *pos;
888 unsigned long start = vma->vm_start;
889 unsigned long size = (vma->vm_end - vma->vm_start);
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300890 struct omap_vout_device *vout = file->private_data;
891 struct videobuf_queue *q = &vout->vbq;
892
893 v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev,
894 " %s pgoff=0x%lx, start=0x%lx, end=0x%lx\n", __func__,
895 vma->vm_pgoff, vma->vm_start, vma->vm_end);
896
897 /* look for the buffer to map */
898 for (i = 0; i < VIDEO_MAX_FRAME; i++) {
899 if (NULL == q->bufs[i])
900 continue;
901 if (V4L2_MEMORY_MMAP != q->bufs[i]->memory)
902 continue;
903 if (q->bufs[i]->boff == (vma->vm_pgoff << PAGE_SHIFT))
904 break;
905 }
906
907 if (VIDEO_MAX_FRAME == i) {
908 v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev,
909 "offset invalid [offset=0x%lx]\n",
910 (vma->vm_pgoff << PAGE_SHIFT));
911 return -EINVAL;
912 }
Vaibhav Hiremath383e4f62011-04-14 13:42:34 -0300913 /* Check the size of the buffer */
914 if (size > vout->buffer_size) {
915 v4l2_err(&vout->vid_dev->v4l2_dev,
916 "insufficient memory [%lu] [%u]\n",
917 size, vout->buffer_size);
918 return -ENOMEM;
919 }
920
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300921 q->bufs[i]->baddr = vma->vm_start;
922
Konstantin Khlebnikov314e51b2012-10-08 16:29:02 -0700923 vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300924 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
925 vma->vm_ops = &omap_vout_vm_ops;
926 vma->vm_private_data = (void *) vout;
Vaibhav Hiremathdd880dd2010-05-27 08:17:08 -0300927 pos = (void *)vout->buf_virt_addr[i];
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300928 vma->vm_pgoff = virt_to_phys((void *)pos) >> PAGE_SHIFT;
929 while (size > 0) {
930 unsigned long pfn;
931 pfn = virt_to_phys((void *) pos) >> PAGE_SHIFT;
932 if (remap_pfn_range(vma, start, pfn, PAGE_SIZE, PAGE_SHARED))
933 return -EAGAIN;
934 start += PAGE_SIZE;
935 pos += PAGE_SIZE;
936 size -= PAGE_SIZE;
937 }
938 vout->mmap_count++;
939 v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Exiting %s\n", __func__);
940
941 return 0;
942}
943
944static int omap_vout_release(struct file *file)
945{
946 unsigned int ret, i;
947 struct videobuf_queue *q;
948 struct omapvideo_info *ovid;
949 struct omap_vout_device *vout = file->private_data;
950
951 v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Entering %s\n", __func__);
952 ovid = &vout->vid_info;
953
954 if (!vout)
955 return 0;
956
957 q = &vout->vbq;
958 /* Disable all the overlay managers connected with this interface */
959 for (i = 0; i < ovid->num_overlays; i++) {
960 struct omap_overlay *ovl = ovid->overlays[i];
Linus Torvalds5f769452012-10-12 10:21:02 +0900961 struct omap_dss_device *dssdev = ovl->get_device(ovl);
962
963 if (dssdev)
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +0200964 ovl->disable(ovl);
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300965 }
966 /* Turn off the pipeline */
967 ret = omapvid_apply_changes(vout);
968 if (ret)
969 v4l2_warn(&vout->vid_dev->v4l2_dev,
970 "Unable to apply changes\n");
971
972 /* Free all buffers */
archit taneja445e2582011-06-14 03:54:47 -0300973 omap_vout_free_extra_buffers(vout);
974
975 /* Free the VRFB buffers only if they are allocated
976 * during reqbufs. Don't free if init time allocated
977 */
978 if (ovid->rotation_type == VOUT_ROT_VRFB) {
979 if (!vout->vrfb_static_allocation)
980 omap_vout_free_vrfb_buffers(vout);
981 }
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300982 videobuf_mmap_free(q);
983
984 /* Even if apply changes fails we should continue
Uwe Kleine-Königb5950762010-11-01 15:38:34 -0400985 freeing allocated memory */
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300986 if (vout->streaming) {
987 u32 mask = 0;
988
989 mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN |
Amber Jain5251dd62011-06-02 02:30:10 -0300990 DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_VSYNC2;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300991 omap_dispc_unregister_isr(omap_vout_isr, vout, mask);
Mauro Carvalho Chehab160ac0b2014-09-03 15:46:32 -0300992 vout->streaming = false;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -0300993
994 videobuf_streamoff(q);
995 videobuf_queue_cancel(q);
996 }
997
998 if (vout->mmap_count != 0)
999 vout->mmap_count = 0;
1000
1001 vout->opened -= 1;
1002 file->private_data = NULL;
1003
1004 if (vout->buffer_allocated)
1005 videobuf_mmap_free(q);
1006
1007 v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Exiting %s\n", __func__);
1008 return ret;
1009}
1010
1011static int omap_vout_open(struct file *file)
1012{
1013 struct videobuf_queue *q;
1014 struct omap_vout_device *vout = NULL;
1015
1016 vout = video_drvdata(file);
1017 v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Entering %s\n", __func__);
1018
1019 if (vout == NULL)
1020 return -ENODEV;
1021
1022 /* for now, we only support single open */
1023 if (vout->opened)
1024 return -EBUSY;
1025
1026 vout->opened += 1;
1027
1028 file->private_data = vout;
1029 vout->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
1030
1031 q = &vout->vbq;
1032 video_vbq_ops.buf_setup = omap_vout_buffer_setup;
1033 video_vbq_ops.buf_prepare = omap_vout_buffer_prepare;
1034 video_vbq_ops.buf_release = omap_vout_buffer_release;
1035 video_vbq_ops.buf_queue = omap_vout_buffer_queue;
1036 spin_lock_init(&vout->vbq_lock);
1037
Vaibhav Hiremathdd880dd2010-05-27 08:17:08 -03001038 videobuf_queue_dma_contig_init(q, &video_vbq_ops, q->dev,
1039 &vout->vbq_lock, vout->type, V4L2_FIELD_NONE,
Hans Verkuile3cfd442010-09-30 09:18:52 -03001040 sizeof(struct videobuf_buffer), vout, NULL);
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001041
1042 v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Exiting %s\n", __func__);
1043 return 0;
1044}
1045
1046/*
1047 * V4L2 ioctls
1048 */
1049static int vidioc_querycap(struct file *file, void *fh,
1050 struct v4l2_capability *cap)
1051{
1052 struct omap_vout_device *vout = fh;
1053
1054 strlcpy(cap->driver, VOUT_NAME, sizeof(cap->driver));
1055 strlcpy(cap->card, vout->vfd->name, sizeof(cap->card));
1056 cap->bus_info[0] = '\0';
Hans Verkuila020c742014-11-24 06:37:25 -03001057 cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT |
Hans Verkuil047a01f2011-11-22 08:23:19 -03001058 V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
Hans Verkuila020c742014-11-24 06:37:25 -03001059 cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001060
1061 return 0;
1062}
1063
1064static int vidioc_enum_fmt_vid_out(struct file *file, void *fh,
1065 struct v4l2_fmtdesc *fmt)
1066{
1067 int index = fmt->index;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001068
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001069 if (index >= NUM_OUTPUT_FORMATS)
1070 return -EINVAL;
1071
1072 fmt->flags = omap_formats[index].flags;
1073 strlcpy(fmt->description, omap_formats[index].description,
1074 sizeof(fmt->description));
1075 fmt->pixelformat = omap_formats[index].pixelformat;
1076
1077 return 0;
1078}
1079
1080static int vidioc_g_fmt_vid_out(struct file *file, void *fh,
1081 struct v4l2_format *f)
1082{
1083 struct omap_vout_device *vout = fh;
1084
1085 f->fmt.pix = vout->pix;
1086 return 0;
1087
1088}
1089
1090static int vidioc_try_fmt_vid_out(struct file *file, void *fh,
1091 struct v4l2_format *f)
1092{
1093 struct omap_overlay *ovl;
1094 struct omapvideo_info *ovid;
1095 struct omap_video_timings *timing;
1096 struct omap_vout_device *vout = fh;
Linus Torvalds5f769452012-10-12 10:21:02 +09001097 struct omap_dss_device *dssdev;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001098
1099 ovid = &vout->vid_info;
1100 ovl = ovid->overlays[0];
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001101 /* get the display device attached to the overlay */
Linus Torvalds5f769452012-10-12 10:21:02 +09001102 dssdev = ovl->get_device(ovl);
1103
1104 if (!dssdev)
1105 return -EINVAL;
1106
1107 timing = &dssdev->panel.timings;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001108
1109 vout->fbuf.fmt.height = timing->y_res;
1110 vout->fbuf.fmt.width = timing->x_res;
1111
1112 omap_vout_try_format(&f->fmt.pix);
1113 return 0;
1114}
1115
1116static int vidioc_s_fmt_vid_out(struct file *file, void *fh,
1117 struct v4l2_format *f)
1118{
1119 int ret, bpp;
1120 struct omap_overlay *ovl;
1121 struct omapvideo_info *ovid;
1122 struct omap_video_timings *timing;
1123 struct omap_vout_device *vout = fh;
Linus Torvalds5f769452012-10-12 10:21:02 +09001124 struct omap_dss_device *dssdev;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001125
1126 if (vout->streaming)
1127 return -EBUSY;
1128
1129 mutex_lock(&vout->lock);
1130
1131 ovid = &vout->vid_info;
1132 ovl = ovid->overlays[0];
Linus Torvalds5f769452012-10-12 10:21:02 +09001133 dssdev = ovl->get_device(ovl);
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001134
1135 /* get the display device attached to the overlay */
Linus Torvalds5f769452012-10-12 10:21:02 +09001136 if (!dssdev) {
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001137 ret = -EINVAL;
1138 goto s_fmt_vid_out_exit;
1139 }
Linus Torvalds5f769452012-10-12 10:21:02 +09001140 timing = &dssdev->panel.timings;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001141
1142 /* We dont support RGB24-packed mode if vrfb rotation
1143 * is enabled*/
archit tanejab3668882011-06-14 03:54:46 -03001144 if ((is_rotation_enabled(vout)) &&
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001145 f->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24) {
1146 ret = -EINVAL;
1147 goto s_fmt_vid_out_exit;
1148 }
1149
1150 /* get the framebuffer parameters */
1151
archit tanejab3668882011-06-14 03:54:46 -03001152 if (is_rotation_90_or_270(vout)) {
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001153 vout->fbuf.fmt.height = timing->x_res;
1154 vout->fbuf.fmt.width = timing->y_res;
1155 } else {
1156 vout->fbuf.fmt.height = timing->y_res;
1157 vout->fbuf.fmt.width = timing->x_res;
1158 }
1159
1160 /* change to samller size is OK */
1161
1162 bpp = omap_vout_try_format(&f->fmt.pix);
1163 f->fmt.pix.sizeimage = f->fmt.pix.width * f->fmt.pix.height * bpp;
1164
1165 /* try & set the new output format */
1166 vout->bpp = bpp;
1167 vout->pix = f->fmt.pix;
1168 vout->vrfb_bpp = 1;
1169
1170 /* If YUYV then vrfb bpp is 2, for others its 1 */
1171 if (V4L2_PIX_FMT_YUYV == vout->pix.pixelformat ||
1172 V4L2_PIX_FMT_UYVY == vout->pix.pixelformat)
1173 vout->vrfb_bpp = 2;
1174
1175 /* set default crop and win */
1176 omap_vout_new_format(&vout->pix, &vout->fbuf, &vout->crop, &vout->win);
1177
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001178 ret = 0;
1179
1180s_fmt_vid_out_exit:
1181 mutex_unlock(&vout->lock);
1182 return ret;
1183}
1184
1185static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh,
1186 struct v4l2_format *f)
1187{
1188 int ret = 0;
1189 struct omap_vout_device *vout = fh;
Archit Taneja11354dd2011-09-26 11:47:29 +05301190 struct omap_overlay *ovl;
1191 struct omapvideo_info *ovid;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001192 struct v4l2_window *win = &f->fmt.win;
1193
Archit Taneja11354dd2011-09-26 11:47:29 +05301194 ovid = &vout->vid_info;
1195 ovl = ovid->overlays[0];
1196
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001197 ret = omap_vout_try_window(&vout->fbuf, win);
1198
1199 if (!ret) {
Archit Taneja11354dd2011-09-26 11:47:29 +05301200 if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001201 win->global_alpha = 255;
1202 else
1203 win->global_alpha = f->fmt.win.global_alpha;
1204 }
1205
1206 return ret;
1207}
1208
1209static int vidioc_s_fmt_vid_overlay(struct file *file, void *fh,
1210 struct v4l2_format *f)
1211{
1212 int ret = 0;
1213 struct omap_overlay *ovl;
1214 struct omapvideo_info *ovid;
1215 struct omap_vout_device *vout = fh;
1216 struct v4l2_window *win = &f->fmt.win;
1217
1218 mutex_lock(&vout->lock);
1219 ovid = &vout->vid_info;
1220 ovl = ovid->overlays[0];
1221
1222 ret = omap_vout_new_window(&vout->crop, &vout->win, &vout->fbuf, win);
1223 if (!ret) {
Archit Taneja11354dd2011-09-26 11:47:29 +05301224 /* Video1 plane does not support global alpha on OMAP3 */
1225 if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001226 vout->win.global_alpha = 255;
1227 else
1228 vout->win.global_alpha = f->fmt.win.global_alpha;
1229
1230 vout->win.chromakey = f->fmt.win.chromakey;
1231 }
1232 mutex_unlock(&vout->lock);
1233 return ret;
1234}
1235
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001236static int vidioc_g_fmt_vid_overlay(struct file *file, void *fh,
1237 struct v4l2_format *f)
1238{
1239 u32 key_value = 0;
1240 struct omap_overlay *ovl;
1241 struct omapvideo_info *ovid;
1242 struct omap_vout_device *vout = fh;
1243 struct omap_overlay_manager_info info;
1244 struct v4l2_window *win = &f->fmt.win;
1245
1246 ovid = &vout->vid_info;
1247 ovl = ovid->overlays[0];
1248
1249 win->w = vout->win.w;
1250 win->field = vout->win.field;
1251 win->global_alpha = vout->win.global_alpha;
1252
1253 if (ovl->manager && ovl->manager->get_manager_info) {
1254 ovl->manager->get_manager_info(ovl->manager, &info);
1255 key_value = info.trans_key;
1256 }
1257 win->chromakey = key_value;
1258 return 0;
1259}
1260
1261static int vidioc_cropcap(struct file *file, void *fh,
1262 struct v4l2_cropcap *cropcap)
1263{
1264 struct omap_vout_device *vout = fh;
1265 struct v4l2_pix_format *pix = &vout->pix;
1266
1267 if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
1268 return -EINVAL;
1269
1270 /* Width and height are always even */
1271 cropcap->bounds.width = pix->width & ~1;
1272 cropcap->bounds.height = pix->height & ~1;
1273
1274 omap_vout_default_crop(&vout->pix, &vout->fbuf, &cropcap->defrect);
1275 cropcap->pixelaspect.numerator = 1;
1276 cropcap->pixelaspect.denominator = 1;
1277 return 0;
1278}
1279
1280static int vidioc_g_crop(struct file *file, void *fh, struct v4l2_crop *crop)
1281{
1282 struct omap_vout_device *vout = fh;
1283
1284 if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
1285 return -EINVAL;
1286 crop->c = vout->crop;
1287 return 0;
1288}
1289
Hans Verkuil4f996592012-09-05 05:10:48 -03001290static int vidioc_s_crop(struct file *file, void *fh, const struct v4l2_crop *crop)
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001291{
1292 int ret = -EINVAL;
1293 struct omap_vout_device *vout = fh;
1294 struct omapvideo_info *ovid;
1295 struct omap_overlay *ovl;
1296 struct omap_video_timings *timing;
Linus Torvalds5f769452012-10-12 10:21:02 +09001297 struct omap_dss_device *dssdev;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001298
1299 if (vout->streaming)
1300 return -EBUSY;
1301
1302 mutex_lock(&vout->lock);
1303 ovid = &vout->vid_info;
1304 ovl = ovid->overlays[0];
Linus Torvalds5f769452012-10-12 10:21:02 +09001305 /* get the display device attached to the overlay */
1306 dssdev = ovl->get_device(ovl);
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001307
Linus Torvalds5f769452012-10-12 10:21:02 +09001308 if (!dssdev) {
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001309 ret = -EINVAL;
1310 goto s_crop_err;
1311 }
Linus Torvalds5f769452012-10-12 10:21:02 +09001312
1313 timing = &dssdev->panel.timings;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001314
archit tanejab3668882011-06-14 03:54:46 -03001315 if (is_rotation_90_or_270(vout)) {
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001316 vout->fbuf.fmt.height = timing->x_res;
1317 vout->fbuf.fmt.width = timing->y_res;
1318 } else {
1319 vout->fbuf.fmt.height = timing->y_res;
1320 vout->fbuf.fmt.width = timing->x_res;
1321 }
1322
1323 if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
1324 ret = omap_vout_new_crop(&vout->pix, &vout->crop, &vout->win,
1325 &vout->fbuf, &crop->c);
1326
1327s_crop_err:
1328 mutex_unlock(&vout->lock);
1329 return ret;
1330}
1331
1332static int vidioc_queryctrl(struct file *file, void *fh,
1333 struct v4l2_queryctrl *ctrl)
1334{
1335 int ret = 0;
1336
1337 switch (ctrl->id) {
1338 case V4L2_CID_ROTATE:
1339 ret = v4l2_ctrl_query_fill(ctrl, 0, 270, 90, 0);
1340 break;
1341 case V4L2_CID_BG_COLOR:
1342 ret = v4l2_ctrl_query_fill(ctrl, 0, 0xFFFFFF, 1, 0);
1343 break;
1344 case V4L2_CID_VFLIP:
1345 ret = v4l2_ctrl_query_fill(ctrl, 0, 1, 1, 0);
1346 break;
1347 default:
1348 ctrl->name[0] = '\0';
1349 ret = -EINVAL;
1350 }
1351 return ret;
1352}
1353
1354static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *ctrl)
1355{
1356 int ret = 0;
1357 struct omap_vout_device *vout = fh;
1358
1359 switch (ctrl->id) {
1360 case V4L2_CID_ROTATE:
1361 ctrl->value = vout->control[0].value;
1362 break;
1363 case V4L2_CID_BG_COLOR:
1364 {
1365 struct omap_overlay_manager_info info;
1366 struct omap_overlay *ovl;
1367
1368 ovl = vout->vid_info.overlays[0];
1369 if (!ovl->manager || !ovl->manager->get_manager_info) {
1370 ret = -EINVAL;
1371 break;
1372 }
1373
1374 ovl->manager->get_manager_info(ovl->manager, &info);
1375 ctrl->value = info.default_color;
1376 break;
1377 }
1378 case V4L2_CID_VFLIP:
1379 ctrl->value = vout->control[2].value;
1380 break;
1381 default:
1382 ret = -EINVAL;
1383 }
1384 return ret;
1385}
1386
1387static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *a)
1388{
1389 int ret = 0;
1390 struct omap_vout_device *vout = fh;
1391
1392 switch (a->id) {
1393 case V4L2_CID_ROTATE:
1394 {
archit taneja445e2582011-06-14 03:54:47 -03001395 struct omapvideo_info *ovid;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001396 int rotation = a->value;
1397
archit taneja445e2582011-06-14 03:54:47 -03001398 ovid = &vout->vid_info;
1399
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001400 mutex_lock(&vout->lock);
archit taneja445e2582011-06-14 03:54:47 -03001401 if (rotation && ovid->rotation_type == VOUT_ROT_NONE) {
1402 mutex_unlock(&vout->lock);
1403 ret = -ERANGE;
1404 break;
1405 }
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001406
1407 if (rotation && vout->pix.pixelformat == V4L2_PIX_FMT_RGB24) {
1408 mutex_unlock(&vout->lock);
1409 ret = -EINVAL;
1410 break;
1411 }
1412
1413 if (v4l2_rot_to_dss_rot(rotation, &vout->rotation,
1414 vout->mirror)) {
1415 mutex_unlock(&vout->lock);
1416 ret = -EINVAL;
1417 break;
1418 }
1419
1420 vout->control[0].value = rotation;
1421 mutex_unlock(&vout->lock);
1422 break;
1423 }
1424 case V4L2_CID_BG_COLOR:
1425 {
1426 struct omap_overlay *ovl;
1427 unsigned int color = a->value;
1428 struct omap_overlay_manager_info info;
1429
1430 ovl = vout->vid_info.overlays[0];
1431
1432 mutex_lock(&vout->lock);
1433 if (!ovl->manager || !ovl->manager->get_manager_info) {
1434 mutex_unlock(&vout->lock);
1435 ret = -EINVAL;
1436 break;
1437 }
1438
1439 ovl->manager->get_manager_info(ovl->manager, &info);
1440 info.default_color = color;
1441 if (ovl->manager->set_manager_info(ovl->manager, &info)) {
1442 mutex_unlock(&vout->lock);
1443 ret = -EINVAL;
1444 break;
1445 }
1446
1447 vout->control[1].value = color;
1448 mutex_unlock(&vout->lock);
1449 break;
1450 }
1451 case V4L2_CID_VFLIP:
1452 {
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001453 struct omapvideo_info *ovid;
1454 unsigned int mirror = a->value;
1455
1456 ovid = &vout->vid_info;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001457
1458 mutex_lock(&vout->lock);
archit taneja445e2582011-06-14 03:54:47 -03001459 if (mirror && ovid->rotation_type == VOUT_ROT_NONE) {
1460 mutex_unlock(&vout->lock);
1461 ret = -ERANGE;
1462 break;
1463 }
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001464
1465 if (mirror && vout->pix.pixelformat == V4L2_PIX_FMT_RGB24) {
1466 mutex_unlock(&vout->lock);
1467 ret = -EINVAL;
1468 break;
1469 }
1470 vout->mirror = mirror;
1471 vout->control[2].value = mirror;
1472 mutex_unlock(&vout->lock);
1473 break;
1474 }
1475 default:
1476 ret = -EINVAL;
1477 }
1478 return ret;
1479}
1480
1481static int vidioc_reqbufs(struct file *file, void *fh,
1482 struct v4l2_requestbuffers *req)
1483{
1484 int ret = 0;
1485 unsigned int i, num_buffers = 0;
1486 struct omap_vout_device *vout = fh;
1487 struct videobuf_queue *q = &vout->vbq;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001488
Mauro Carvalho Chehab52334bb2014-08-26 10:46:49 -03001489 if (req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001490 return -EINVAL;
1491 /* if memory is not mmp or userptr
1492 return error */
1493 if ((V4L2_MEMORY_MMAP != req->memory) &&
1494 (V4L2_MEMORY_USERPTR != req->memory))
1495 return -EINVAL;
1496
1497 mutex_lock(&vout->lock);
1498 /* Cannot be requested when streaming is on */
1499 if (vout->streaming) {
1500 ret = -EBUSY;
1501 goto reqbuf_err;
1502 }
1503
1504 /* If buffers are already allocated free them */
1505 if (q->bufs[0] && (V4L2_MEMORY_MMAP == q->bufs[0]->memory)) {
1506 if (vout->mmap_count) {
1507 ret = -EBUSY;
1508 goto reqbuf_err;
1509 }
1510 num_buffers = (vout->vid == OMAP_VIDEO1) ?
1511 video1_numbuffers : video2_numbuffers;
1512 for (i = num_buffers; i < vout->buffer_allocated; i++) {
Vaibhav Hiremathdd880dd2010-05-27 08:17:08 -03001513 omap_vout_free_buffer(vout->buf_virt_addr[i],
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001514 vout->buffer_size);
1515 vout->buf_virt_addr[i] = 0;
1516 vout->buf_phy_addr[i] = 0;
1517 }
1518 vout->buffer_allocated = num_buffers;
1519 videobuf_mmap_free(q);
1520 } else if (q->bufs[0] && (V4L2_MEMORY_USERPTR == q->bufs[0]->memory)) {
1521 if (vout->buffer_allocated) {
1522 videobuf_mmap_free(q);
1523 for (i = 0; i < vout->buffer_allocated; i++) {
1524 kfree(q->bufs[i]);
1525 q->bufs[i] = NULL;
1526 }
1527 vout->buffer_allocated = 0;
1528 }
1529 }
1530
1531 /*store the memory type in data structure */
1532 vout->memory = req->memory;
1533
1534 INIT_LIST_HEAD(&vout->dma_queue);
1535
1536 /* call videobuf_reqbufs api */
1537 ret = videobuf_reqbufs(q, req);
1538 if (ret < 0)
1539 goto reqbuf_err;
1540
1541 vout->buffer_allocated = req->count;
Vaibhav Hiremathdd880dd2010-05-27 08:17:08 -03001542
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001543reqbuf_err:
1544 mutex_unlock(&vout->lock);
1545 return ret;
1546}
1547
1548static int vidioc_querybuf(struct file *file, void *fh,
1549 struct v4l2_buffer *b)
1550{
1551 struct omap_vout_device *vout = fh;
1552
1553 return videobuf_querybuf(&vout->vbq, b);
1554}
1555
1556static int vidioc_qbuf(struct file *file, void *fh,
1557 struct v4l2_buffer *buffer)
1558{
1559 struct omap_vout_device *vout = fh;
1560 struct videobuf_queue *q = &vout->vbq;
1561
1562 if ((V4L2_BUF_TYPE_VIDEO_OUTPUT != buffer->type) ||
1563 (buffer->index >= vout->buffer_allocated) ||
1564 (q->bufs[buffer->index]->memory != buffer->memory)) {
1565 return -EINVAL;
1566 }
1567 if (V4L2_MEMORY_USERPTR == buffer->memory) {
1568 if ((buffer->length < vout->pix.sizeimage) ||
1569 (0 == buffer->m.userptr)) {
1570 return -EINVAL;
1571 }
1572 }
1573
archit tanejab3668882011-06-14 03:54:46 -03001574 if ((is_rotation_enabled(vout)) &&
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001575 vout->vrfb_dma_tx.req_status == DMA_CHAN_NOT_ALLOTED) {
1576 v4l2_warn(&vout->vid_dev->v4l2_dev,
1577 "DMA Channel not allocated for Rotation\n");
1578 return -EINVAL;
1579 }
1580
1581 return videobuf_qbuf(q, buffer);
1582}
1583
1584static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
1585{
1586 struct omap_vout_device *vout = fh;
1587 struct videobuf_queue *q = &vout->vbq;
1588
Amber Jain72915e82011-07-07 06:03:25 -03001589 int ret;
1590 u32 addr;
1591 unsigned long size;
1592 struct videobuf_buffer *vb;
1593
1594 vb = q->bufs[b->index];
1595
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001596 if (!vout->streaming)
1597 return -EINVAL;
1598
1599 if (file->f_flags & O_NONBLOCK)
1600 /* Call videobuf_dqbuf for non blocking mode */
Amber Jain72915e82011-07-07 06:03:25 -03001601 ret = videobuf_dqbuf(q, (struct v4l2_buffer *)b, 1);
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001602 else
1603 /* Call videobuf_dqbuf for blocking mode */
Amber Jain72915e82011-07-07 06:03:25 -03001604 ret = videobuf_dqbuf(q, (struct v4l2_buffer *)b, 0);
1605
1606 addr = (unsigned long) vout->buf_phy_addr[vb->i];
1607 size = (unsigned long) vb->size;
1608 dma_unmap_single(vout->vid_dev->v4l2_dev.dev, addr,
1609 size, DMA_TO_DEVICE);
1610 return ret;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001611}
1612
1613static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
1614{
1615 int ret = 0, j;
1616 u32 addr = 0, mask = 0;
1617 struct omap_vout_device *vout = fh;
1618 struct videobuf_queue *q = &vout->vbq;
1619 struct omapvideo_info *ovid = &vout->vid_info;
1620
1621 mutex_lock(&vout->lock);
1622
1623 if (vout->streaming) {
1624 ret = -EBUSY;
1625 goto streamon_err;
1626 }
1627
1628 ret = videobuf_streamon(q);
1629 if (ret)
1630 goto streamon_err;
1631
1632 if (list_empty(&vout->dma_queue)) {
1633 ret = -EIO;
1634 goto streamon_err1;
1635 }
1636
1637 /* Get the next frame from the buffer queue */
1638 vout->next_frm = vout->cur_frm = list_entry(vout->dma_queue.next,
1639 struct videobuf_buffer, queue);
1640 /* Remove buffer from the buffer queue */
1641 list_del(&vout->cur_frm->queue);
1642 /* Mark state of the current frame to active */
1643 vout->cur_frm->state = VIDEOBUF_ACTIVE;
1644 /* Initialize field_id and started member */
1645 vout->field_id = 0;
1646
1647 /* set flag here. Next QBUF will start DMA */
Mauro Carvalho Chehab160ac0b2014-09-03 15:46:32 -03001648 vout->streaming = true;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001649
1650 vout->first_int = 1;
1651
1652 if (omap_vout_calculate_offset(vout)) {
1653 ret = -EINVAL;
1654 goto streamon_err1;
1655 }
1656 addr = (unsigned long) vout->queued_buf_addr[vout->cur_frm->i]
1657 + vout->cropped_offset;
1658
Amber Jain5251dd62011-06-02 02:30:10 -03001659 mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD
1660 | DISPC_IRQ_VSYNC2;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001661
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001662 /* First save the configuration in ovelray structure */
1663 ret = omapvid_init(vout, addr);
Federico Fuga15170022012-08-24 11:54:11 -03001664 if (ret) {
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001665 v4l2_err(&vout->vid_dev->v4l2_dev,
1666 "failed to set overlay info\n");
Federico Fuga15170022012-08-24 11:54:11 -03001667 goto streamon_err1;
1668 }
1669
1670 omap_dispc_register_isr(omap_vout_isr, vout, mask);
1671
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001672 /* Enable the pipeline and set the Go bit */
1673 ret = omapvid_apply_changes(vout);
1674 if (ret)
1675 v4l2_err(&vout->vid_dev->v4l2_dev, "failed to change mode\n");
1676
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001677 for (j = 0; j < ovid->num_overlays; j++) {
1678 struct omap_overlay *ovl = ovid->overlays[j];
Linus Torvalds5f769452012-10-12 10:21:02 +09001679 struct omap_dss_device *dssdev = ovl->get_device(ovl);
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001680
Linus Torvalds5f769452012-10-12 10:21:02 +09001681 if (dssdev) {
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001682 ret = ovl->enable(ovl);
1683 if (ret)
1684 goto streamon_err1;
1685 }
1686 }
1687
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001688 ret = 0;
1689
1690streamon_err1:
1691 if (ret)
1692 ret = videobuf_streamoff(q);
1693streamon_err:
1694 mutex_unlock(&vout->lock);
1695 return ret;
1696}
1697
1698static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
1699{
1700 u32 mask = 0;
1701 int ret = 0, j;
1702 struct omap_vout_device *vout = fh;
1703 struct omapvideo_info *ovid = &vout->vid_info;
1704
1705 if (!vout->streaming)
1706 return -EINVAL;
1707
Mauro Carvalho Chehab160ac0b2014-09-03 15:46:32 -03001708 vout->streaming = false;
Amber Jain5251dd62011-06-02 02:30:10 -03001709 mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD
1710 | DISPC_IRQ_VSYNC2;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001711
1712 omap_dispc_unregister_isr(omap_vout_isr, vout, mask);
1713
1714 for (j = 0; j < ovid->num_overlays; j++) {
1715 struct omap_overlay *ovl = ovid->overlays[j];
Linus Torvalds5f769452012-10-12 10:21:02 +09001716 struct omap_dss_device *dssdev = ovl->get_device(ovl);
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001717
Linus Torvalds5f769452012-10-12 10:21:02 +09001718 if (dssdev)
Tomi Valkeinenaaa874a2011-11-15 16:37:53 +02001719 ovl->disable(ovl);
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001720 }
1721
1722 /* Turn of the pipeline */
1723 ret = omapvid_apply_changes(vout);
1724 if (ret)
1725 v4l2_err(&vout->vid_dev->v4l2_dev, "failed to change mode in"
1726 " streamoff\n");
1727
1728 INIT_LIST_HEAD(&vout->dma_queue);
1729 ret = videobuf_streamoff(&vout->vbq);
1730
1731 return ret;
1732}
1733
1734static int vidioc_s_fbuf(struct file *file, void *fh,
Hans Verkuile6eb28c2012-09-04 10:26:45 -03001735 const struct v4l2_framebuffer *a)
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001736{
1737 int enable = 0;
1738 struct omap_overlay *ovl;
1739 struct omapvideo_info *ovid;
1740 struct omap_vout_device *vout = fh;
1741 struct omap_overlay_manager_info info;
1742 enum omap_dss_trans_key_type key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
1743
1744 ovid = &vout->vid_info;
1745 ovl = ovid->overlays[0];
1746
1747 /* OMAP DSS doesn't support Source and Destination color
1748 key together */
1749 if ((a->flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY) &&
1750 (a->flags & V4L2_FBUF_FLAG_CHROMAKEY))
1751 return -EINVAL;
1752 /* OMAP DSS Doesn't support the Destination color key
1753 and alpha blending together */
1754 if ((a->flags & V4L2_FBUF_FLAG_CHROMAKEY) &&
1755 (a->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA))
1756 return -EINVAL;
1757
1758 if ((a->flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY)) {
1759 vout->fbuf.flags |= V4L2_FBUF_FLAG_SRC_CHROMAKEY;
1760 key_type = OMAP_DSS_COLOR_KEY_VID_SRC;
1761 } else
1762 vout->fbuf.flags &= ~V4L2_FBUF_FLAG_SRC_CHROMAKEY;
1763
1764 if ((a->flags & V4L2_FBUF_FLAG_CHROMAKEY)) {
1765 vout->fbuf.flags |= V4L2_FBUF_FLAG_CHROMAKEY;
1766 key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
1767 } else
1768 vout->fbuf.flags &= ~V4L2_FBUF_FLAG_CHROMAKEY;
1769
1770 if (a->flags & (V4L2_FBUF_FLAG_CHROMAKEY |
1771 V4L2_FBUF_FLAG_SRC_CHROMAKEY))
1772 enable = 1;
1773 else
1774 enable = 0;
1775 if (ovl->manager && ovl->manager->get_manager_info &&
1776 ovl->manager->set_manager_info) {
1777
1778 ovl->manager->get_manager_info(ovl->manager, &info);
1779 info.trans_enabled = enable;
1780 info.trans_key_type = key_type;
1781 info.trans_key = vout->win.chromakey;
1782
1783 if (ovl->manager->set_manager_info(ovl->manager, &info))
1784 return -EINVAL;
1785 }
1786 if (a->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) {
1787 vout->fbuf.flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
1788 enable = 1;
1789 } else {
1790 vout->fbuf.flags &= ~V4L2_FBUF_FLAG_LOCAL_ALPHA;
1791 enable = 0;
1792 }
1793 if (ovl->manager && ovl->manager->get_manager_info &&
1794 ovl->manager->set_manager_info) {
1795 ovl->manager->get_manager_info(ovl->manager, &info);
Archit Taneja11354dd2011-09-26 11:47:29 +05301796 /* enable this only if there is no zorder cap */
1797 if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)
1798 info.partial_alpha_enabled = enable;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001799 if (ovl->manager->set_manager_info(ovl->manager, &info))
1800 return -EINVAL;
1801 }
1802
1803 return 0;
1804}
1805
1806static int vidioc_g_fbuf(struct file *file, void *fh,
1807 struct v4l2_framebuffer *a)
1808{
1809 struct omap_overlay *ovl;
1810 struct omapvideo_info *ovid;
1811 struct omap_vout_device *vout = fh;
1812 struct omap_overlay_manager_info info;
1813
1814 ovid = &vout->vid_info;
1815 ovl = ovid->overlays[0];
1816
Hans Verkuil047a01f2011-11-22 08:23:19 -03001817 /* The video overlay must stay within the framebuffer and can't be
1818 positioned independently. */
1819 a->flags = V4L2_FBUF_FLAG_OVERLAY;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001820 a->capability = V4L2_FBUF_CAP_LOCAL_ALPHA | V4L2_FBUF_CAP_CHROMAKEY
1821 | V4L2_FBUF_CAP_SRC_CHROMAKEY;
1822
1823 if (ovl->manager && ovl->manager->get_manager_info) {
1824 ovl->manager->get_manager_info(ovl->manager, &info);
1825 if (info.trans_key_type == OMAP_DSS_COLOR_KEY_VID_SRC)
1826 a->flags |= V4L2_FBUF_FLAG_SRC_CHROMAKEY;
1827 if (info.trans_key_type == OMAP_DSS_COLOR_KEY_GFX_DST)
1828 a->flags |= V4L2_FBUF_FLAG_CHROMAKEY;
1829 }
1830 if (ovl->manager && ovl->manager->get_manager_info) {
1831 ovl->manager->get_manager_info(ovl->manager, &info);
Archit Taneja11354dd2011-09-26 11:47:29 +05301832 if (info.partial_alpha_enabled)
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001833 a->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
1834 }
1835
1836 return 0;
1837}
1838
1839static const struct v4l2_ioctl_ops vout_ioctl_ops = {
1840 .vidioc_querycap = vidioc_querycap,
1841 .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
1842 .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out,
1843 .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
1844 .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out,
1845 .vidioc_queryctrl = vidioc_queryctrl,
1846 .vidioc_g_ctrl = vidioc_g_ctrl,
1847 .vidioc_s_fbuf = vidioc_s_fbuf,
1848 .vidioc_g_fbuf = vidioc_g_fbuf,
1849 .vidioc_s_ctrl = vidioc_s_ctrl,
Laurent Pinchart7b2607c2012-11-13 10:00:22 -03001850 .vidioc_try_fmt_vid_out_overlay = vidioc_try_fmt_vid_overlay,
1851 .vidioc_s_fmt_vid_out_overlay = vidioc_s_fmt_vid_overlay,
1852 .vidioc_g_fmt_vid_out_overlay = vidioc_g_fmt_vid_overlay,
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001853 .vidioc_cropcap = vidioc_cropcap,
1854 .vidioc_g_crop = vidioc_g_crop,
1855 .vidioc_s_crop = vidioc_s_crop,
1856 .vidioc_reqbufs = vidioc_reqbufs,
1857 .vidioc_querybuf = vidioc_querybuf,
1858 .vidioc_qbuf = vidioc_qbuf,
1859 .vidioc_dqbuf = vidioc_dqbuf,
1860 .vidioc_streamon = vidioc_streamon,
1861 .vidioc_streamoff = vidioc_streamoff,
1862};
1863
1864static const struct v4l2_file_operations omap_vout_fops = {
1865 .owner = THIS_MODULE,
Laurent Pinchart94f3f482011-01-20 21:15:42 -03001866 .poll = omap_vout_poll,
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001867 .unlocked_ioctl = video_ioctl2,
1868 .mmap = omap_vout_mmap,
1869 .open = omap_vout_open,
1870 .release = omap_vout_release,
1871};
1872
1873/* Init functions used during driver initialization */
1874/* Initial setup of video_data */
1875static int __init omap_vout_setup_video_data(struct omap_vout_device *vout)
1876{
1877 struct video_device *vfd;
1878 struct v4l2_pix_format *pix;
1879 struct v4l2_control *control;
Linus Torvalds5f769452012-10-12 10:21:02 +09001880 struct omap_overlay *ovl = vout->vid_info.overlays[0];
1881 struct omap_dss_device *display = ovl->get_device(ovl);
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001882
1883 /* set the default pix */
1884 pix = &vout->pix;
1885
1886 /* Set the default picture of QVGA */
1887 pix->width = QQVGA_WIDTH;
1888 pix->height = QQVGA_HEIGHT;
1889
1890 /* Default pixel format is RGB 5-6-5 */
1891 pix->pixelformat = V4L2_PIX_FMT_RGB565;
1892 pix->field = V4L2_FIELD_ANY;
1893 pix->bytesperline = pix->width * 2;
1894 pix->sizeimage = pix->bytesperline * pix->height;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001895 pix->colorspace = V4L2_COLORSPACE_JPEG;
1896
1897 vout->bpp = RGB565_BPP;
1898 vout->fbuf.fmt.width = display->panel.timings.x_res;
1899 vout->fbuf.fmt.height = display->panel.timings.y_res;
1900
1901 /* Set the data structures for the overlay parameters*/
1902 vout->win.global_alpha = 255;
1903 vout->fbuf.flags = 0;
1904 vout->fbuf.capability = V4L2_FBUF_CAP_LOCAL_ALPHA |
1905 V4L2_FBUF_CAP_SRC_CHROMAKEY | V4L2_FBUF_CAP_CHROMAKEY;
1906 vout->win.chromakey = 0;
1907
1908 omap_vout_new_format(pix, &vout->fbuf, &vout->crop, &vout->win);
1909
1910 /*Initialize the control variables for
1911 rotation, flipping and background color. */
1912 control = vout->control;
1913 control[0].id = V4L2_CID_ROTATE;
1914 control[0].value = 0;
1915 vout->rotation = 0;
Mauro Carvalho Chehab160ac0b2014-09-03 15:46:32 -03001916 vout->mirror = false;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001917 vout->control[2].id = V4L2_CID_HFLIP;
1918 vout->control[2].value = 0;
archit taneja445e2582011-06-14 03:54:47 -03001919 if (vout->vid_info.rotation_type == VOUT_ROT_VRFB)
1920 vout->vrfb_bpp = 2;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001921
1922 control[1].id = V4L2_CID_BG_COLOR;
1923 control[1].value = 0;
1924
1925 /* initialize the video_device struct */
1926 vfd = vout->vfd = video_device_alloc();
1927
1928 if (!vfd) {
1929 printk(KERN_ERR VOUT_NAME ": could not allocate"
1930 " video device struct\n");
1931 return -ENOMEM;
1932 }
1933 vfd->release = video_device_release;
1934 vfd->ioctl_ops = &vout_ioctl_ops;
1935
1936 strlcpy(vfd->name, VOUT_NAME, sizeof(vfd->name));
1937
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001938 vfd->fops = &omap_vout_fops;
1939 vfd->v4l2_dev = &vout->vid_dev->v4l2_dev;
Hans Verkuil954f3402012-09-05 06:05:50 -03001940 vfd->vfl_dir = VFL_DIR_TX;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001941 mutex_init(&vout->lock);
1942
1943 vfd->minor = -1;
1944 return 0;
1945
1946}
1947
1948/* Setup video buffers */
1949static int __init omap_vout_setup_video_bufs(struct platform_device *pdev,
1950 int vid_num)
1951{
1952 u32 numbuffers;
archit taneja445e2582011-06-14 03:54:47 -03001953 int ret = 0, i;
1954 struct omapvideo_info *ovid;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001955 struct omap_vout_device *vout;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001956 struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
1957 struct omap2video_device *vid_dev =
1958 container_of(v4l2_dev, struct omap2video_device, v4l2_dev);
1959
1960 vout = vid_dev->vouts[vid_num];
archit taneja445e2582011-06-14 03:54:47 -03001961 ovid = &vout->vid_info;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001962
1963 numbuffers = (vid_num == 0) ? video1_numbuffers : video2_numbuffers;
1964 vout->buffer_size = (vid_num == 0) ? video1_bufsize : video2_bufsize;
1965 dev_info(&pdev->dev, "Buffer Size = %d\n", vout->buffer_size);
1966
1967 for (i = 0; i < numbuffers; i++) {
1968 vout->buf_virt_addr[i] =
1969 omap_vout_alloc_buffer(vout->buffer_size,
1970 (u32 *) &vout->buf_phy_addr[i]);
1971 if (!vout->buf_virt_addr[i]) {
1972 numbuffers = i;
1973 ret = -ENOMEM;
1974 goto free_buffers;
1975 }
1976 }
1977
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001978 vout->cropped_offset = 0;
1979
archit taneja445e2582011-06-14 03:54:47 -03001980 if (ovid->rotation_type == VOUT_ROT_VRFB) {
1981 int static_vrfb_allocation = (vid_num == 0) ?
1982 vid1_static_vrfb_alloc : vid2_static_vrfb_alloc;
1983 ret = omap_vout_setup_vrfb_bufs(pdev, vid_num,
1984 static_vrfb_allocation);
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001985 }
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001986
archit taneja445e2582011-06-14 03:54:47 -03001987 return ret;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03001988
1989free_buffers:
1990 for (i = 0; i < numbuffers; i++) {
1991 omap_vout_free_buffer(vout->buf_virt_addr[i],
1992 vout->buffer_size);
1993 vout->buf_virt_addr[i] = 0;
1994 vout->buf_phy_addr[i] = 0;
1995 }
1996 return ret;
1997
1998}
1999
2000/* Create video out devices */
2001static int __init omap_vout_create_video_devices(struct platform_device *pdev)
2002{
2003 int ret = 0, k;
2004 struct omap_vout_device *vout;
2005 struct video_device *vfd = NULL;
2006 struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
2007 struct omap2video_device *vid_dev = container_of(v4l2_dev,
2008 struct omap2video_device, v4l2_dev);
2009
2010 for (k = 0; k < pdev->num_resources; k++) {
2011
Julia Lawall2ef17c92010-05-13 16:59:15 -03002012 vout = kzalloc(sizeof(struct omap_vout_device), GFP_KERNEL);
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002013 if (!vout) {
2014 dev_err(&pdev->dev, ": could not allocate memory\n");
2015 return -ENOMEM;
2016 }
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002017
2018 vout->vid = k;
2019 vid_dev->vouts[k] = vout;
2020 vout->vid_dev = vid_dev;
2021 /* Select video2 if only 1 overlay is controlled by V4L2 */
2022 if (pdev->num_resources == 1)
2023 vout->vid_info.overlays[0] = vid_dev->overlays[k + 2];
2024 else
2025 /* Else select video1 and video2 one by one. */
2026 vout->vid_info.overlays[0] = vid_dev->overlays[k + 1];
2027 vout->vid_info.num_overlays = 1;
2028 vout->vid_info.id = k + 1;
2029
archit taneja445e2582011-06-14 03:54:47 -03002030 /* Set VRFB as rotation_type for omap2 and omap3 */
Tomi Valkeinen950e2fb2012-11-12 15:17:39 +02002031 if (omap_vout_dss_omap24xx() || omap_vout_dss_omap34xx())
archit taneja445e2582011-06-14 03:54:47 -03002032 vout->vid_info.rotation_type = VOUT_ROT_VRFB;
2033
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002034 /* Setup the default configuration for the video devices
2035 */
2036 if (omap_vout_setup_video_data(vout) != 0) {
2037 ret = -ENOMEM;
2038 goto error;
2039 }
2040
2041 /* Allocate default number of buffers for the video streaming
2042 * and reserve the VRFB space for rotation
2043 */
2044 if (omap_vout_setup_video_bufs(pdev, k) != 0) {
2045 ret = -ENOMEM;
2046 goto error1;
2047 }
2048
2049 /* Register the Video device with V4L2
2050 */
2051 vfd = vout->vfd;
Vaibhav Hiremath8f3a3072011-06-16 15:32:07 -03002052 if (video_register_device(vfd, VFL_TYPE_GRABBER, -1) < 0) {
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002053 dev_err(&pdev->dev, ": Could not register "
2054 "Video for Linux device\n");
2055 vfd->minor = -1;
2056 ret = -ENODEV;
2057 goto error2;
2058 }
2059 video_set_drvdata(vfd, vout);
2060
Archit Taneja32d640d2012-03-07 05:01:16 -03002061 dev_info(&pdev->dev, ": registered and initialized"
2062 " video device %d\n", vfd->minor);
2063 if (k == (pdev->num_resources - 1))
2064 return 0;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002065
Archit Taneja32d640d2012-03-07 05:01:16 -03002066 continue;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002067error2:
archit taneja445e2582011-06-14 03:54:47 -03002068 if (vout->vid_info.rotation_type == VOUT_ROT_VRFB)
2069 omap_vout_release_vrfb(vout);
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002070 omap_vout_free_buffers(vout);
2071error1:
2072 video_device_release(vfd);
2073error:
2074 kfree(vout);
2075 return ret;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002076 }
2077
2078 return -ENODEV;
2079}
2080/* Driver functions */
2081static void omap_vout_cleanup_device(struct omap_vout_device *vout)
2082{
2083 struct video_device *vfd;
archit taneja445e2582011-06-14 03:54:47 -03002084 struct omapvideo_info *ovid;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002085
2086 if (!vout)
2087 return;
2088
2089 vfd = vout->vfd;
archit taneja445e2582011-06-14 03:54:47 -03002090 ovid = &vout->vid_info;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002091 if (vfd) {
2092 if (!video_is_registered(vfd)) {
2093 /*
2094 * The device was never registered, so release the
2095 * video_device struct directly.
2096 */
2097 video_device_release(vfd);
2098 } else {
2099 /*
2100 * The unregister function will release the video_device
2101 * struct as well as unregistering it.
2102 */
2103 video_unregister_device(vfd);
2104 }
2105 }
archit taneja445e2582011-06-14 03:54:47 -03002106 if (ovid->rotation_type == VOUT_ROT_VRFB) {
2107 omap_vout_release_vrfb(vout);
2108 /* Free the VRFB buffer if allocated
2109 * init time
2110 */
2111 if (vout->vrfb_static_allocation)
2112 omap_vout_free_vrfb_buffers(vout);
2113 }
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002114 omap_vout_free_buffers(vout);
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002115
2116 kfree(vout);
2117}
2118
2119static int omap_vout_remove(struct platform_device *pdev)
2120{
2121 int k;
2122 struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
2123 struct omap2video_device *vid_dev = container_of(v4l2_dev, struct
2124 omap2video_device, v4l2_dev);
2125
2126 v4l2_device_unregister(v4l2_dev);
2127 for (k = 0; k < pdev->num_resources; k++)
2128 omap_vout_cleanup_device(vid_dev->vouts[k]);
2129
2130 for (k = 0; k < vid_dev->num_displays; k++) {
2131 if (vid_dev->displays[k]->state != OMAP_DSS_DISPLAY_DISABLED)
Vaibhav Hiremath5ba9bb02010-05-27 08:17:07 -03002132 vid_dev->displays[k]->driver->disable(vid_dev->displays[k]);
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002133
2134 omap_dss_put_device(vid_dev->displays[k]);
2135 }
2136 kfree(vid_dev);
2137 return 0;
2138}
2139
2140static int __init omap_vout_probe(struct platform_device *pdev)
2141{
2142 int ret = 0, i;
2143 struct omap_overlay *ovl;
2144 struct omap_dss_device *dssdev = NULL;
2145 struct omap_dss_device *def_display;
2146 struct omap2video_device *vid_dev = NULL;
2147
Tomi Valkeinen591a0ac2013-05-23 12:07:50 +03002148 if (omapdss_is_initialized() == false)
2149 return -EPROBE_DEFER;
2150
Tomi Valkeinena9ee9f02012-10-10 10:26:45 +03002151 ret = omapdss_compat_init();
2152 if (ret) {
2153 dev_err(&pdev->dev, "failed to init dss\n");
2154 return ret;
2155 }
2156
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002157 if (pdev->num_resources == 0) {
2158 dev_err(&pdev->dev, "probed for an unknown device\n");
Tomi Valkeinena9ee9f02012-10-10 10:26:45 +03002159 ret = -ENODEV;
2160 goto err_dss_init;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002161 }
2162
2163 vid_dev = kzalloc(sizeof(struct omap2video_device), GFP_KERNEL);
Tomi Valkeinena9ee9f02012-10-10 10:26:45 +03002164 if (vid_dev == NULL) {
2165 ret = -ENOMEM;
2166 goto err_dss_init;
2167 }
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002168
2169 vid_dev->num_displays = 0;
2170 for_each_dss_dev(dssdev) {
2171 omap_dss_get_device(dssdev);
Tomi Valkeinen71c7a972011-11-14 04:28:59 -03002172
2173 if (!dssdev->driver) {
2174 dev_warn(&pdev->dev, "no driver for display: %s\n",
2175 dssdev->name);
2176 omap_dss_put_device(dssdev);
2177 continue;
2178 }
2179
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002180 vid_dev->displays[vid_dev->num_displays++] = dssdev;
2181 }
2182
2183 if (vid_dev->num_displays == 0) {
2184 dev_err(&pdev->dev, "no displays\n");
2185 ret = -EINVAL;
2186 goto probe_err0;
2187 }
2188
2189 vid_dev->num_overlays = omap_dss_get_num_overlays();
2190 for (i = 0; i < vid_dev->num_overlays; i++)
2191 vid_dev->overlays[i] = omap_dss_get_overlay(i);
2192
2193 vid_dev->num_managers = omap_dss_get_num_overlay_managers();
2194 for (i = 0; i < vid_dev->num_managers; i++)
2195 vid_dev->managers[i] = omap_dss_get_overlay_manager(i);
2196
2197 /* Get the Video1 overlay and video2 overlay.
2198 * Setup the Display attached to that overlays
2199 */
2200 for (i = 1; i < vid_dev->num_overlays; i++) {
2201 ovl = omap_dss_get_overlay(i);
Linus Torvalds5f769452012-10-12 10:21:02 +09002202 dssdev = ovl->get_device(ovl);
2203
2204 if (dssdev) {
2205 def_display = dssdev;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002206 } else {
2207 dev_warn(&pdev->dev, "cannot find display\n");
2208 def_display = NULL;
2209 }
2210 if (def_display) {
Vaibhav Hiremath5ba9bb02010-05-27 08:17:07 -03002211 struct omap_dss_driver *dssdrv = def_display->driver;
2212
2213 ret = dssdrv->enable(def_display);
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002214 if (ret) {
2215 /* Here we are not considering a error
2216 * as display may be enabled by frame
2217 * buffer driver
2218 */
2219 dev_warn(&pdev->dev,
2220 "'%s' Display already enabled\n",
2221 def_display->name);
2222 }
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002223 }
2224 }
2225
2226 if (v4l2_device_register(&pdev->dev, &vid_dev->v4l2_dev) < 0) {
2227 dev_err(&pdev->dev, "v4l2_device_register failed\n");
2228 ret = -ENODEV;
2229 goto probe_err1;
2230 }
2231
2232 ret = omap_vout_create_video_devices(pdev);
2233 if (ret)
2234 goto probe_err2;
2235
2236 for (i = 0; i < vid_dev->num_displays; i++) {
2237 struct omap_dss_device *display = vid_dev->displays[i];
2238
Vaibhav Hiremath5ba9bb02010-05-27 08:17:07 -03002239 if (display->driver->update)
2240 display->driver->update(display, 0, 0,
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002241 display->panel.timings.x_res,
2242 display->panel.timings.y_res);
2243 }
2244 return 0;
2245
2246probe_err2:
2247 v4l2_device_unregister(&vid_dev->v4l2_dev);
2248probe_err1:
2249 for (i = 1; i < vid_dev->num_overlays; i++) {
2250 def_display = NULL;
2251 ovl = omap_dss_get_overlay(i);
Linus Torvalds5f769452012-10-12 10:21:02 +09002252 dssdev = ovl->get_device(ovl);
2253
2254 if (dssdev)
2255 def_display = dssdev;
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002256
Vaibhav Hiremath5ba9bb02010-05-27 08:17:07 -03002257 if (def_display && def_display->driver)
2258 def_display->driver->disable(def_display);
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002259 }
2260probe_err0:
2261 kfree(vid_dev);
Tomi Valkeinena9ee9f02012-10-10 10:26:45 +03002262err_dss_init:
2263 omapdss_compat_uninit();
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002264 return ret;
2265}
2266
2267static struct platform_driver omap_vout_driver = {
2268 .driver = {
2269 .name = VOUT_NAME,
2270 },
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002271 .remove = omap_vout_remove,
2272};
2273
2274static int __init omap_vout_init(void)
2275{
Tomi Valkeinen93596ef2011-11-08 05:47:08 -03002276 if (platform_driver_probe(&omap_vout_driver, omap_vout_probe) != 0) {
Vaibhav Hiremath5c7ab632010-04-11 10:41:49 -03002277 printk(KERN_ERR VOUT_NAME ":Could not register Video driver\n");
2278 return -EINVAL;
2279 }
2280 return 0;
2281}
2282
2283static void omap_vout_cleanup(void)
2284{
2285 platform_driver_unregister(&omap_vout_driver);
2286}
2287
2288late_initcall(omap_vout_init);
2289module_exit(omap_vout_cleanup);