omap_vout.c (44356B)
1/* 2 * omap_vout.c 3 * 4 * Copyright (C) 2005-2010 Texas Instruments. 5 * 6 * This file is licensed under the terms of the GNU General Public License 7 * version 2. This program is licensed "as is" without any warranty of any 8 * kind, whether express or implied. 9 * 10 * Leveraged code from the OMAP2 camera driver 11 * Video-for-Linux (Version 2) camera capture driver for 12 * the OMAP24xx camera controller. 13 * 14 * Author: Andy Lowe (source@mvista.com) 15 * 16 * Copyright (C) 2004 MontaVista Software, Inc. 17 * Copyright (C) 2010 Texas Instruments. 18 * 19 * History: 20 * 20-APR-2006 Khasim Modified VRFB based Rotation, 21 * The image data is always read from 0 degree 22 * view and written 23 * to the virtual space of desired rotation angle 24 * 4-DEC-2006 Jian Changed to support better memory management 25 * 26 * 17-Nov-2008 Hardik Changed driver to use video_ioctl2 27 * 28 * 23-Feb-2010 Vaibhav H Modified to use new DSS2 interface 29 * 30 */ 31 32#include <linux/init.h> 33#include <linux/module.h> 34#include <linux/vmalloc.h> 35#include <linux/sched.h> 36#include <linux/types.h> 37#include <linux/platform_device.h> 38#include <linux/irq.h> 39#include <linux/videodev2.h> 40#include <linux/dma-mapping.h> 41#include <linux/slab.h> 42 43#include <media/v4l2-device.h> 44#include <media/v4l2-ioctl.h> 45#include <media/v4l2-event.h> 46 47#include <video/omapvrfb.h> 48#include <video/omapfb_dss.h> 49 50#include "omap_voutlib.h" 51#include "omap_voutdef.h" 52#include "omap_vout_vrfb.h" 53 54MODULE_AUTHOR("Texas Instruments"); 55MODULE_DESCRIPTION("OMAP Video for Linux Video out driver"); 56MODULE_LICENSE("GPL"); 57 58/* Driver Configuration macros */ 59#define VOUT_NAME "omap_vout" 60 61enum omap_vout_channels { 62 OMAP_VIDEO1, 63 OMAP_VIDEO2, 64}; 65 66/* Variables configurable through module params*/ 67static bool vid1_static_vrfb_alloc; 68static bool vid2_static_vrfb_alloc; 69static bool debug; 70 71/* Module parameters */ 72module_param(vid1_static_vrfb_alloc, bool, S_IRUGO); 73MODULE_PARM_DESC(vid1_static_vrfb_alloc, 74 "Static allocation of the VRFB buffer for video1 device"); 75 76module_param(vid2_static_vrfb_alloc, bool, S_IRUGO); 77MODULE_PARM_DESC(vid2_static_vrfb_alloc, 78 "Static allocation of the VRFB buffer for video2 device"); 79 80module_param(debug, bool, S_IRUGO); 81MODULE_PARM_DESC(debug, "Debug level (0-1)"); 82 83/* list of image formats supported by OMAP2 video pipelines */ 84static const struct v4l2_fmtdesc omap_formats[] = { 85 { 86 /* Note: V4L2 defines RGB565 as: 87 * 88 * Byte 0 Byte 1 89 * g2 g1 g0 r4 r3 r2 r1 r0 b4 b3 b2 b1 b0 g5 g4 g3 90 * 91 * We interpret RGB565 as: 92 * 93 * Byte 0 Byte 1 94 * g2 g1 g0 b4 b3 b2 b1 b0 r4 r3 r2 r1 r0 g5 g4 g3 95 */ 96 .pixelformat = V4L2_PIX_FMT_RGB565, 97 }, 98 { 99 /* Note: V4L2 defines RGB32 as: RGB-8-8-8-8 we use 100 * this for RGB24 unpack mode, the last 8 bits are ignored 101 * */ 102 .pixelformat = V4L2_PIX_FMT_RGB32, 103 }, 104 { 105 /* Note: V4L2 defines RGB24 as: RGB-8-8-8 we use 106 * this for RGB24 packed mode 107 * 108 */ 109 .pixelformat = V4L2_PIX_FMT_RGB24, 110 }, 111 { 112 .pixelformat = V4L2_PIX_FMT_YUYV, 113 }, 114 { 115 .pixelformat = V4L2_PIX_FMT_UYVY, 116 }, 117}; 118 119#define NUM_OUTPUT_FORMATS (ARRAY_SIZE(omap_formats)) 120 121/* 122 * Try format 123 */ 124static int omap_vout_try_format(struct v4l2_pix_format *pix) 125{ 126 int ifmt, bpp = 0; 127 128 pix->height = clamp(pix->height, (u32)VID_MIN_HEIGHT, 129 (u32)VID_MAX_HEIGHT); 130 pix->width = clamp(pix->width, (u32)VID_MIN_WIDTH, (u32)VID_MAX_WIDTH); 131 132 for (ifmt = 0; ifmt < NUM_OUTPUT_FORMATS; ifmt++) { 133 if (pix->pixelformat == omap_formats[ifmt].pixelformat) 134 break; 135 } 136 137 if (ifmt == NUM_OUTPUT_FORMATS) 138 ifmt = 0; 139 140 pix->pixelformat = omap_formats[ifmt].pixelformat; 141 pix->field = V4L2_FIELD_NONE; 142 143 switch (pix->pixelformat) { 144 case V4L2_PIX_FMT_YUYV: 145 case V4L2_PIX_FMT_UYVY: 146 default: 147 pix->colorspace = V4L2_COLORSPACE_SRGB; 148 bpp = YUYV_BPP; 149 break; 150 case V4L2_PIX_FMT_RGB565: 151 case V4L2_PIX_FMT_RGB565X: 152 pix->colorspace = V4L2_COLORSPACE_SRGB; 153 bpp = RGB565_BPP; 154 break; 155 case V4L2_PIX_FMT_RGB24: 156 pix->colorspace = V4L2_COLORSPACE_SRGB; 157 bpp = RGB24_BPP; 158 break; 159 case V4L2_PIX_FMT_RGB32: 160 case V4L2_PIX_FMT_BGR32: 161 pix->colorspace = V4L2_COLORSPACE_SRGB; 162 bpp = RGB32_BPP; 163 break; 164 } 165 pix->bytesperline = pix->width * bpp; 166 pix->sizeimage = pix->bytesperline * pix->height; 167 168 return bpp; 169} 170 171/* 172 * Convert V4L2 rotation to DSS rotation 173 * V4L2 understand 0, 90, 180, 270. 174 * Convert to 0, 1, 2 and 3 respectively for DSS 175 */ 176static int v4l2_rot_to_dss_rot(int v4l2_rotation, 177 enum dss_rotation *rotation, bool mirror) 178{ 179 int ret = 0; 180 181 switch (v4l2_rotation) { 182 case 90: 183 *rotation = dss_rotation_90_degree; 184 break; 185 case 180: 186 *rotation = dss_rotation_180_degree; 187 break; 188 case 270: 189 *rotation = dss_rotation_270_degree; 190 break; 191 case 0: 192 *rotation = dss_rotation_0_degree; 193 break; 194 default: 195 ret = -EINVAL; 196 } 197 return ret; 198} 199 200static int omap_vout_calculate_offset(struct omap_vout_device *vout) 201{ 202 struct omapvideo_info *ovid; 203 struct v4l2_rect *crop = &vout->crop; 204 struct v4l2_pix_format *pix = &vout->pix; 205 int *cropped_offset = &vout->cropped_offset; 206 int ps = 2, line_length = 0; 207 208 ovid = &vout->vid_info; 209 210 if (ovid->rotation_type == VOUT_ROT_VRFB) { 211 omap_vout_calculate_vrfb_offset(vout); 212 } else { 213 vout->line_length = line_length = pix->width; 214 215 if (V4L2_PIX_FMT_YUYV == pix->pixelformat || 216 V4L2_PIX_FMT_UYVY == pix->pixelformat) 217 ps = 2; 218 else if (V4L2_PIX_FMT_RGB32 == pix->pixelformat) 219 ps = 4; 220 else if (V4L2_PIX_FMT_RGB24 == pix->pixelformat) 221 ps = 3; 222 223 vout->ps = ps; 224 225 *cropped_offset = (line_length * ps) * 226 crop->top + crop->left * ps; 227 } 228 229 v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "%s Offset:%x\n", 230 __func__, vout->cropped_offset); 231 232 return 0; 233} 234 235/* 236 * Convert V4L2 pixel format to DSS pixel format 237 */ 238static int video_mode_to_dss_mode(struct omap_vout_device *vout) 239{ 240 struct omap_overlay *ovl; 241 struct omapvideo_info *ovid; 242 struct v4l2_pix_format *pix = &vout->pix; 243 enum omap_color_mode mode; 244 245 ovid = &vout->vid_info; 246 ovl = ovid->overlays[0]; 247 248 switch (pix->pixelformat) { 249 case V4L2_PIX_FMT_YUYV: 250 mode = OMAP_DSS_COLOR_YUV2; 251 break; 252 case V4L2_PIX_FMT_UYVY: 253 mode = OMAP_DSS_COLOR_UYVY; 254 break; 255 case V4L2_PIX_FMT_RGB565: 256 mode = OMAP_DSS_COLOR_RGB16; 257 break; 258 case V4L2_PIX_FMT_RGB24: 259 mode = OMAP_DSS_COLOR_RGB24P; 260 break; 261 case V4L2_PIX_FMT_RGB32: 262 mode = (ovl->id == OMAP_DSS_VIDEO1) ? 263 OMAP_DSS_COLOR_RGB24U : OMAP_DSS_COLOR_ARGB32; 264 break; 265 case V4L2_PIX_FMT_BGR32: 266 mode = OMAP_DSS_COLOR_RGBX32; 267 break; 268 default: 269 mode = -EINVAL; 270 break; 271 } 272 return mode; 273} 274 275/* 276 * Setup the overlay 277 */ 278static int omapvid_setup_overlay(struct omap_vout_device *vout, 279 struct omap_overlay *ovl, int posx, int posy, int outw, 280 int outh, dma_addr_t addr) 281{ 282 int ret = 0; 283 struct omap_overlay_info info; 284 int cropheight, cropwidth, pixwidth; 285 286 if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0 && 287 (outw != vout->pix.width || outh != vout->pix.height)) { 288 ret = -EINVAL; 289 goto setup_ovl_err; 290 } 291 292 vout->dss_mode = video_mode_to_dss_mode(vout); 293 if (vout->dss_mode == -EINVAL) { 294 ret = -EINVAL; 295 goto setup_ovl_err; 296 } 297 298 /* Setup the input plane parameters according to 299 * rotation value selected. 300 */ 301 if (is_rotation_90_or_270(vout)) { 302 cropheight = vout->crop.width; 303 cropwidth = vout->crop.height; 304 pixwidth = vout->pix.height; 305 } else { 306 cropheight = vout->crop.height; 307 cropwidth = vout->crop.width; 308 pixwidth = vout->pix.width; 309 } 310 311 ovl->get_overlay_info(ovl, &info); 312 info.paddr = addr; 313 info.width = cropwidth; 314 info.height = cropheight; 315 info.color_mode = vout->dss_mode; 316 info.mirror = vout->mirror; 317 info.pos_x = posx; 318 info.pos_y = posy; 319 info.out_width = outw; 320 info.out_height = outh; 321 info.global_alpha = vout->win.global_alpha; 322 if (!is_rotation_enabled(vout)) { 323 info.rotation = 0; 324 info.rotation_type = OMAP_DSS_ROT_DMA; 325 info.screen_width = pixwidth; 326 } else { 327 info.rotation = vout->rotation; 328 info.rotation_type = OMAP_DSS_ROT_VRFB; 329 info.screen_width = 2048; 330 } 331 332 v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, 333 "%s enable=%d addr=%pad width=%d\n height=%d color_mode=%d\n" 334 "rotation=%d mirror=%d posx=%d posy=%d out_width = %d \n" 335 "out_height=%d rotation_type=%d screen_width=%d\n", __func__, 336 ovl->is_enabled(ovl), &info.paddr, info.width, info.height, 337 info.color_mode, info.rotation, info.mirror, info.pos_x, 338 info.pos_y, info.out_width, info.out_height, info.rotation_type, 339 info.screen_width); 340 341 ret = ovl->set_overlay_info(ovl, &info); 342 if (ret) 343 goto setup_ovl_err; 344 345 return 0; 346 347setup_ovl_err: 348 v4l2_warn(&vout->vid_dev->v4l2_dev, "setup_overlay failed\n"); 349 return ret; 350} 351 352/* 353 * Initialize the overlay structure 354 */ 355static int omapvid_init(struct omap_vout_device *vout, dma_addr_t addr) 356{ 357 int ret = 0, i; 358 struct v4l2_window *win; 359 struct omap_overlay *ovl; 360 int posx, posy, outw, outh; 361 struct omap_video_timings *timing; 362 struct omapvideo_info *ovid = &vout->vid_info; 363 364 win = &vout->win; 365 for (i = 0; i < ovid->num_overlays; i++) { 366 struct omap_dss_device *dssdev; 367 368 ovl = ovid->overlays[i]; 369 dssdev = ovl->get_device(ovl); 370 371 if (!dssdev) 372 return -EINVAL; 373 374 timing = &dssdev->panel.timings; 375 376 outw = win->w.width; 377 outh = win->w.height; 378 switch (vout->rotation) { 379 case dss_rotation_90_degree: 380 /* Invert the height and width for 90 381 * and 270 degree rotation 382 */ 383 swap(outw, outh); 384 posy = (timing->y_res - win->w.width) - win->w.left; 385 posx = win->w.top; 386 break; 387 388 case dss_rotation_180_degree: 389 posx = (timing->x_res - win->w.width) - win->w.left; 390 posy = (timing->y_res - win->w.height) - win->w.top; 391 break; 392 393 case dss_rotation_270_degree: 394 swap(outw, outh); 395 posy = win->w.left; 396 posx = (timing->x_res - win->w.height) - win->w.top; 397 break; 398 399 default: 400 posx = win->w.left; 401 posy = win->w.top; 402 break; 403 } 404 405 ret = omapvid_setup_overlay(vout, ovl, posx, posy, 406 outw, outh, addr); 407 if (ret) 408 goto omapvid_init_err; 409 } 410 return 0; 411 412omapvid_init_err: 413 v4l2_warn(&vout->vid_dev->v4l2_dev, "apply_changes failed\n"); 414 return ret; 415} 416 417/* 418 * Apply the changes set the go bit of DSS 419 */ 420static int omapvid_apply_changes(struct omap_vout_device *vout) 421{ 422 int i; 423 struct omap_overlay *ovl; 424 struct omapvideo_info *ovid = &vout->vid_info; 425 426 for (i = 0; i < ovid->num_overlays; i++) { 427 struct omap_dss_device *dssdev; 428 429 ovl = ovid->overlays[i]; 430 dssdev = ovl->get_device(ovl); 431 if (!dssdev) 432 return -EINVAL; 433 ovl->manager->apply(ovl->manager); 434 } 435 436 return 0; 437} 438 439static int omapvid_handle_interlace_display(struct omap_vout_device *vout, 440 unsigned int irqstatus, u64 ts) 441{ 442 u32 fid; 443 444 if (vout->first_int) { 445 vout->first_int = 0; 446 goto err; 447 } 448 449 if (irqstatus & DISPC_IRQ_EVSYNC_ODD) 450 fid = 1; 451 else if (irqstatus & DISPC_IRQ_EVSYNC_EVEN) 452 fid = 0; 453 else 454 goto err; 455 456 vout->field_id ^= 1; 457 if (fid != vout->field_id) { 458 if (fid == 0) 459 vout->field_id = fid; 460 } else if (0 == fid) { 461 if (vout->cur_frm == vout->next_frm) 462 goto err; 463 464 vout->cur_frm->vbuf.vb2_buf.timestamp = ts; 465 vout->cur_frm->vbuf.sequence = vout->sequence++; 466 vb2_buffer_done(&vout->cur_frm->vbuf.vb2_buf, VB2_BUF_STATE_DONE); 467 vout->cur_frm = vout->next_frm; 468 } else { 469 if (list_empty(&vout->dma_queue) || 470 (vout->cur_frm != vout->next_frm)) 471 goto err; 472 } 473 474 return vout->field_id; 475err: 476 return 0; 477} 478 479static void omap_vout_isr(void *arg, unsigned int irqstatus) 480{ 481 int ret, fid, mgr_id; 482 dma_addr_t addr; 483 u32 irq; 484 struct omap_overlay *ovl; 485 u64 ts; 486 struct omapvideo_info *ovid; 487 struct omap_dss_device *cur_display; 488 struct omap_vout_device *vout = (struct omap_vout_device *)arg; 489 490 ovid = &vout->vid_info; 491 ovl = ovid->overlays[0]; 492 493 mgr_id = ovl->manager->id; 494 495 /* get the display device attached to the overlay */ 496 cur_display = ovl->get_device(ovl); 497 498 if (!cur_display) 499 return; 500 501 spin_lock(&vout->vbq_lock); 502 ts = ktime_get_ns(); 503 504 switch (cur_display->type) { 505 case OMAP_DISPLAY_TYPE_DSI: 506 case OMAP_DISPLAY_TYPE_DPI: 507 case OMAP_DISPLAY_TYPE_DVI: 508 if (mgr_id == OMAP_DSS_CHANNEL_LCD) 509 irq = DISPC_IRQ_VSYNC; 510 else if (mgr_id == OMAP_DSS_CHANNEL_LCD2) 511 irq = DISPC_IRQ_VSYNC2; 512 else 513 goto vout_isr_err; 514 515 if (!(irqstatus & irq)) 516 goto vout_isr_err; 517 break; 518 case OMAP_DISPLAY_TYPE_VENC: 519 fid = omapvid_handle_interlace_display(vout, irqstatus, 520 ts); 521 if (!fid) 522 goto vout_isr_err; 523 break; 524 case OMAP_DISPLAY_TYPE_HDMI: 525 if (!(irqstatus & DISPC_IRQ_EVSYNC_EVEN)) 526 goto vout_isr_err; 527 break; 528 default: 529 goto vout_isr_err; 530 } 531 532 if (!vout->first_int && (vout->cur_frm != vout->next_frm)) { 533 vout->cur_frm->vbuf.vb2_buf.timestamp = ts; 534 vout->cur_frm->vbuf.sequence = vout->sequence++; 535 vb2_buffer_done(&vout->cur_frm->vbuf.vb2_buf, VB2_BUF_STATE_DONE); 536 vout->cur_frm = vout->next_frm; 537 } 538 539 vout->first_int = 0; 540 if (list_empty(&vout->dma_queue)) 541 goto vout_isr_err; 542 543 vout->next_frm = list_entry(vout->dma_queue.next, 544 struct omap_vout_buffer, queue); 545 list_del(&vout->next_frm->queue); 546 547 addr = vout->queued_buf_addr[vout->next_frm->vbuf.vb2_buf.index] 548 + vout->cropped_offset; 549 550 /* First save the configuration in ovelray structure */ 551 ret = omapvid_init(vout, addr); 552 if (ret) { 553 printk(KERN_ERR VOUT_NAME 554 "failed to set overlay info\n"); 555 goto vout_isr_err; 556 } 557 558 /* Enable the pipeline and set the Go bit */ 559 ret = omapvid_apply_changes(vout); 560 if (ret) 561 printk(KERN_ERR VOUT_NAME "failed to change mode\n"); 562 563vout_isr_err: 564 spin_unlock(&vout->vbq_lock); 565} 566 567 568/* 569 * V4L2 ioctls 570 */ 571static int vidioc_querycap(struct file *file, void *fh, 572 struct v4l2_capability *cap) 573{ 574 struct omap_vout_device *vout = video_drvdata(file); 575 576 strscpy(cap->driver, VOUT_NAME, sizeof(cap->driver)); 577 strscpy(cap->card, vout->vfd->name, sizeof(cap->card)); 578 snprintf(cap->bus_info, sizeof(cap->bus_info), 579 "platform:%s.%d", VOUT_NAME, vout->vid); 580 return 0; 581} 582 583static int vidioc_enum_fmt_vid_out(struct file *file, void *fh, 584 struct v4l2_fmtdesc *fmt) 585{ 586 int index = fmt->index; 587 588 if (index >= NUM_OUTPUT_FORMATS) 589 return -EINVAL; 590 591 fmt->flags = omap_formats[index].flags; 592 fmt->pixelformat = omap_formats[index].pixelformat; 593 594 return 0; 595} 596 597static int vidioc_g_fmt_vid_out(struct file *file, void *fh, 598 struct v4l2_format *f) 599{ 600 struct omap_vout_device *vout = video_drvdata(file); 601 602 f->fmt.pix = vout->pix; 603 return 0; 604 605} 606 607static int vidioc_try_fmt_vid_out(struct file *file, void *fh, 608 struct v4l2_format *f) 609{ 610 struct omap_overlay *ovl; 611 struct omapvideo_info *ovid; 612 struct omap_video_timings *timing; 613 struct omap_vout_device *vout = video_drvdata(file); 614 struct omap_dss_device *dssdev; 615 616 ovid = &vout->vid_info; 617 ovl = ovid->overlays[0]; 618 /* get the display device attached to the overlay */ 619 dssdev = ovl->get_device(ovl); 620 621 if (!dssdev) 622 return -EINVAL; 623 624 timing = &dssdev->panel.timings; 625 626 vout->fbuf.fmt.height = timing->y_res; 627 vout->fbuf.fmt.width = timing->x_res; 628 629 omap_vout_try_format(&f->fmt.pix); 630 return 0; 631} 632 633static int vidioc_s_fmt_vid_out(struct file *file, void *fh, 634 struct v4l2_format *f) 635{ 636 int ret, bpp; 637 struct omap_overlay *ovl; 638 struct omapvideo_info *ovid; 639 struct omap_video_timings *timing; 640 struct omap_vout_device *vout = video_drvdata(file); 641 struct omap_dss_device *dssdev; 642 643 if (vb2_is_busy(&vout->vq)) 644 return -EBUSY; 645 646 ovid = &vout->vid_info; 647 ovl = ovid->overlays[0]; 648 dssdev = ovl->get_device(ovl); 649 650 /* get the display device attached to the overlay */ 651 if (!dssdev) { 652 ret = -EINVAL; 653 goto s_fmt_vid_out_exit; 654 } 655 timing = &dssdev->panel.timings; 656 657 /* We don't support RGB24-packed mode if vrfb rotation 658 * is enabled*/ 659 if ((is_rotation_enabled(vout)) && 660 f->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24) { 661 ret = -EINVAL; 662 goto s_fmt_vid_out_exit; 663 } 664 665 /* get the framebuffer parameters */ 666 667 if (is_rotation_90_or_270(vout)) { 668 vout->fbuf.fmt.height = timing->x_res; 669 vout->fbuf.fmt.width = timing->y_res; 670 } else { 671 vout->fbuf.fmt.height = timing->y_res; 672 vout->fbuf.fmt.width = timing->x_res; 673 } 674 675 /* change to smaller size is OK */ 676 677 bpp = omap_vout_try_format(&f->fmt.pix); 678 f->fmt.pix.sizeimage = f->fmt.pix.width * f->fmt.pix.height * bpp; 679 680 /* try & set the new output format */ 681 vout->bpp = bpp; 682 vout->pix = f->fmt.pix; 683 vout->vrfb_bpp = 1; 684 685 /* If YUYV then vrfb bpp is 2, for others its 1 */ 686 if (V4L2_PIX_FMT_YUYV == vout->pix.pixelformat || 687 V4L2_PIX_FMT_UYVY == vout->pix.pixelformat) 688 vout->vrfb_bpp = 2; 689 690 /* set default crop and win */ 691 omap_vout_new_format(&vout->pix, &vout->fbuf, &vout->crop, &vout->win); 692 693 ret = 0; 694 695s_fmt_vid_out_exit: 696 return ret; 697} 698 699static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, 700 struct v4l2_format *f) 701{ 702 int ret = 0; 703 struct omap_vout_device *vout = video_drvdata(file); 704 struct omap_overlay *ovl; 705 struct omapvideo_info *ovid; 706 struct v4l2_window *win = &f->fmt.win; 707 708 ovid = &vout->vid_info; 709 ovl = ovid->overlays[0]; 710 711 ret = omap_vout_try_window(&vout->fbuf, win); 712 713 if (!ret && !(ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA)) 714 win->global_alpha = 0; 715 716 return ret; 717} 718 719static int vidioc_s_fmt_vid_overlay(struct file *file, void *fh, 720 struct v4l2_format *f) 721{ 722 int ret = 0; 723 struct omap_overlay *ovl; 724 struct omapvideo_info *ovid; 725 struct omap_vout_device *vout = video_drvdata(file); 726 struct v4l2_window *win = &f->fmt.win; 727 728 ovid = &vout->vid_info; 729 ovl = ovid->overlays[0]; 730 731 ret = omap_vout_new_window(&vout->crop, &vout->win, &vout->fbuf, win); 732 if (!ret) { 733 enum omap_dss_trans_key_type key_type = 734 OMAP_DSS_COLOR_KEY_GFX_DST; 735 int enable; 736 737 /* Video1 plane does not support global alpha on OMAP3 */ 738 if (ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) 739 vout->win.global_alpha = win->global_alpha; 740 else 741 win->global_alpha = 0; 742 if (vout->fbuf.flags & (V4L2_FBUF_FLAG_CHROMAKEY | 743 V4L2_FBUF_FLAG_SRC_CHROMAKEY)) 744 enable = 1; 745 else 746 enable = 0; 747 if (vout->fbuf.flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY) 748 key_type = OMAP_DSS_COLOR_KEY_VID_SRC; 749 750 if (ovl->manager && ovl->manager->get_manager_info && 751 ovl->manager->set_manager_info) { 752 struct omap_overlay_manager_info info; 753 754 ovl->manager->get_manager_info(ovl->manager, &info); 755 info.trans_enabled = enable; 756 info.trans_key_type = key_type; 757 info.trans_key = vout->win.chromakey; 758 759 if (ovl->manager->set_manager_info(ovl->manager, &info)) 760 return -EINVAL; 761 } 762 } 763 return ret; 764} 765 766static int vidioc_g_fmt_vid_overlay(struct file *file, void *fh, 767 struct v4l2_format *f) 768{ 769 struct omap_overlay *ovl; 770 struct omapvideo_info *ovid; 771 struct omap_vout_device *vout = video_drvdata(file); 772 struct v4l2_window *win = &f->fmt.win; 773 774 ovid = &vout->vid_info; 775 ovl = ovid->overlays[0]; 776 777 win->w = vout->win.w; 778 win->field = vout->win.field; 779 win->chromakey = vout->win.chromakey; 780 if (ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) 781 win->global_alpha = vout->win.global_alpha; 782 else 783 win->global_alpha = 0; 784 win->clips = NULL; 785 win->clipcount = 0; 786 win->bitmap = NULL; 787 return 0; 788} 789 790static int vidioc_g_selection(struct file *file, void *fh, struct v4l2_selection *sel) 791{ 792 struct omap_vout_device *vout = video_drvdata(file); 793 struct v4l2_pix_format *pix = &vout->pix; 794 795 if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) 796 return -EINVAL; 797 798 switch (sel->target) { 799 case V4L2_SEL_TGT_CROP: 800 sel->r = vout->crop; 801 break; 802 case V4L2_SEL_TGT_CROP_DEFAULT: 803 omap_vout_default_crop(&vout->pix, &vout->fbuf, &sel->r); 804 break; 805 case V4L2_SEL_TGT_CROP_BOUNDS: 806 /* Width and height are always even */ 807 sel->r.width = pix->width & ~1; 808 sel->r.height = pix->height & ~1; 809 break; 810 default: 811 return -EINVAL; 812 } 813 return 0; 814} 815 816static int vidioc_s_selection(struct file *file, void *fh, struct v4l2_selection *sel) 817{ 818 int ret = -EINVAL; 819 struct omap_vout_device *vout = video_drvdata(file); 820 struct omapvideo_info *ovid; 821 struct omap_overlay *ovl; 822 struct omap_video_timings *timing; 823 struct omap_dss_device *dssdev; 824 825 if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) 826 return -EINVAL; 827 828 if (sel->target != V4L2_SEL_TGT_CROP) 829 return -EINVAL; 830 831 if (vb2_is_busy(&vout->vq)) 832 return -EBUSY; 833 834 ovid = &vout->vid_info; 835 ovl = ovid->overlays[0]; 836 /* get the display device attached to the overlay */ 837 dssdev = ovl->get_device(ovl); 838 839 if (!dssdev) { 840 ret = -EINVAL; 841 goto s_crop_err; 842 } 843 844 timing = &dssdev->panel.timings; 845 846 if (is_rotation_90_or_270(vout)) { 847 vout->fbuf.fmt.height = timing->x_res; 848 vout->fbuf.fmt.width = timing->y_res; 849 } else { 850 vout->fbuf.fmt.height = timing->y_res; 851 vout->fbuf.fmt.width = timing->x_res; 852 } 853 854 ret = omap_vout_new_crop(&vout->pix, &vout->crop, &vout->win, 855 &vout->fbuf, &sel->r); 856 857s_crop_err: 858 return ret; 859} 860 861static int omap_vout_s_ctrl(struct v4l2_ctrl *ctrl) 862{ 863 struct omap_vout_device *vout = 864 container_of(ctrl->handler, struct omap_vout_device, ctrl_handler); 865 int ret = 0; 866 867 switch (ctrl->id) { 868 case V4L2_CID_ROTATE: { 869 struct omapvideo_info *ovid; 870 int rotation = ctrl->val; 871 872 ovid = &vout->vid_info; 873 874 if (rotation && ovid->rotation_type == VOUT_ROT_NONE) { 875 ret = -ERANGE; 876 break; 877 } 878 879 if (rotation && vout->pix.pixelformat == V4L2_PIX_FMT_RGB24) { 880 ret = -EINVAL; 881 break; 882 } 883 884 if (v4l2_rot_to_dss_rot(rotation, &vout->rotation, 885 vout->mirror)) { 886 ret = -EINVAL; 887 break; 888 } 889 break; 890 } 891 case V4L2_CID_BG_COLOR: 892 { 893 struct omap_overlay *ovl; 894 unsigned int color = ctrl->val; 895 struct omap_overlay_manager_info info; 896 897 ovl = vout->vid_info.overlays[0]; 898 899 if (!ovl->manager || !ovl->manager->get_manager_info) { 900 ret = -EINVAL; 901 break; 902 } 903 904 ovl->manager->get_manager_info(ovl->manager, &info); 905 info.default_color = color; 906 if (ovl->manager->set_manager_info(ovl->manager, &info)) { 907 ret = -EINVAL; 908 break; 909 } 910 break; 911 } 912 case V4L2_CID_VFLIP: 913 { 914 struct omapvideo_info *ovid; 915 unsigned int mirror = ctrl->val; 916 917 ovid = &vout->vid_info; 918 919 if (mirror && ovid->rotation_type == VOUT_ROT_NONE) { 920 ret = -ERANGE; 921 break; 922 } 923 924 if (mirror && vout->pix.pixelformat == V4L2_PIX_FMT_RGB24) { 925 ret = -EINVAL; 926 break; 927 } 928 vout->mirror = mirror; 929 break; 930 } 931 default: 932 return -EINVAL; 933 } 934 return ret; 935} 936 937static const struct v4l2_ctrl_ops omap_vout_ctrl_ops = { 938 .s_ctrl = omap_vout_s_ctrl, 939}; 940 941static int omap_vout_vb2_queue_setup(struct vb2_queue *vq, 942 unsigned int *nbufs, 943 unsigned int *num_planes, unsigned int sizes[], 944 struct device *alloc_devs[]) 945{ 946 struct omap_vout_device *vout = vb2_get_drv_priv(vq); 947 int size = vout->pix.sizeimage; 948 949 if (is_rotation_enabled(vout) && vq->num_buffers + *nbufs > VRFB_NUM_BUFS) { 950 *nbufs = VRFB_NUM_BUFS - vq->num_buffers; 951 if (*nbufs == 0) 952 return -EINVAL; 953 } 954 955 if (*num_planes) 956 return sizes[0] < size ? -EINVAL : 0; 957 958 *num_planes = 1; 959 sizes[0] = size; 960 return 0; 961} 962 963static int omap_vout_vb2_prepare(struct vb2_buffer *vb) 964{ 965 struct omap_vout_device *vout = vb2_get_drv_priv(vb->vb2_queue); 966 struct omapvideo_info *ovid = &vout->vid_info; 967 struct omap_vout_buffer *voutbuf = vb2_to_omap_vout_buffer(vb); 968 dma_addr_t buf_phy_addr = vb2_dma_contig_plane_dma_addr(vb, 0); 969 970 if (vb2_plane_size(vb, 0) < vout->pix.sizeimage) { 971 v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, 972 "%s data will not fit into plane (%lu < %u)\n", 973 __func__, vb2_plane_size(vb, 0), vout->pix.sizeimage); 974 return -EINVAL; 975 } 976 977 vb2_set_plane_payload(vb, 0, vout->pix.sizeimage); 978 voutbuf->vbuf.field = V4L2_FIELD_NONE; 979 980 vout->queued_buf_addr[vb->index] = buf_phy_addr; 981 if (ovid->rotation_type == VOUT_ROT_VRFB) 982 return omap_vout_prepare_vrfb(vout, vb); 983 return 0; 984} 985 986static void omap_vout_vb2_queue(struct vb2_buffer *vb) 987{ 988 struct omap_vout_device *vout = vb2_get_drv_priv(vb->vb2_queue); 989 struct omap_vout_buffer *voutbuf = vb2_to_omap_vout_buffer(vb); 990 991 list_add_tail(&voutbuf->queue, &vout->dma_queue); 992} 993 994static int omap_vout_vb2_start_streaming(struct vb2_queue *vq, unsigned int count) 995{ 996 struct omap_vout_device *vout = vb2_get_drv_priv(vq); 997 struct omapvideo_info *ovid = &vout->vid_info; 998 struct omap_vout_buffer *buf, *tmp; 999 dma_addr_t addr = 0; 1000 u32 mask = 0; 1001 int ret, j; 1002 1003 /* Get the next frame from the buffer queue */ 1004 vout->next_frm = vout->cur_frm = list_entry(vout->dma_queue.next, 1005 struct omap_vout_buffer, queue); 1006 /* Remove buffer from the buffer queue */ 1007 list_del(&vout->cur_frm->queue); 1008 /* Initialize field_id and started member */ 1009 vout->field_id = 0; 1010 vout->first_int = 1; 1011 vout->sequence = 0; 1012 1013 if (omap_vout_calculate_offset(vout)) { 1014 ret = -EINVAL; 1015 goto out; 1016 } 1017 if (ovid->rotation_type == VOUT_ROT_VRFB) 1018 if (omap_vout_vrfb_buffer_setup(vout, &count, 0)) { 1019 ret = -ENOMEM; 1020 goto out; 1021 } 1022 1023 addr = vout->queued_buf_addr[vout->cur_frm->vbuf.vb2_buf.index] 1024 + vout->cropped_offset; 1025 1026 mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD 1027 | DISPC_IRQ_VSYNC2; 1028 1029 /* First save the configuration in overlay structure */ 1030 ret = omapvid_init(vout, addr); 1031 if (ret) { 1032 v4l2_err(&vout->vid_dev->v4l2_dev, 1033 "failed to set overlay info\n"); 1034 goto streamon_err1; 1035 } 1036 1037 omap_dispc_register_isr(omap_vout_isr, vout, mask); 1038 1039 /* Enable the pipeline and set the Go bit */ 1040 ret = omapvid_apply_changes(vout); 1041 if (ret) 1042 v4l2_err(&vout->vid_dev->v4l2_dev, "failed to change mode\n"); 1043 1044 for (j = 0; j < ovid->num_overlays; j++) { 1045 struct omap_overlay *ovl = ovid->overlays[j]; 1046 struct omap_dss_device *dssdev = ovl->get_device(ovl); 1047 1048 if (dssdev) { 1049 ret = ovl->enable(ovl); 1050 if (ret) 1051 goto streamon_err1; 1052 } 1053 } 1054 return 0; 1055 1056streamon_err1: 1057 mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD 1058 | DISPC_IRQ_VSYNC2; 1059 1060 omap_dispc_unregister_isr(omap_vout_isr, vout, mask); 1061 1062 for (j = 0; j < ovid->num_overlays; j++) { 1063 struct omap_overlay *ovl = ovid->overlays[j]; 1064 struct omap_dss_device *dssdev = ovl->get_device(ovl); 1065 1066 if (dssdev) 1067 ovl->disable(ovl); 1068 } 1069 /* Turn of the pipeline */ 1070 if (omapvid_apply_changes(vout)) 1071 v4l2_err(&vout->vid_dev->v4l2_dev, 1072 "failed to change mode in streamoff\n"); 1073 1074out: 1075 vb2_buffer_done(&vout->cur_frm->vbuf.vb2_buf, VB2_BUF_STATE_QUEUED); 1076 list_for_each_entry_safe(buf, tmp, &vout->dma_queue, queue) { 1077 list_del(&buf->queue); 1078 vb2_buffer_done(&buf->vbuf.vb2_buf, VB2_BUF_STATE_QUEUED); 1079 } 1080 return ret; 1081} 1082 1083static void omap_vout_vb2_stop_streaming(struct vb2_queue *vq) 1084{ 1085 struct omap_vout_device *vout = vb2_get_drv_priv(vq); 1086 struct omapvideo_info *ovid = &vout->vid_info; 1087 struct omap_vout_buffer *buf, *tmp; 1088 u32 mask = 0; 1089 int j; 1090 1091 mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD 1092 | DISPC_IRQ_VSYNC2; 1093 1094 omap_dispc_unregister_isr(omap_vout_isr, vout, mask); 1095 1096 for (j = 0; j < ovid->num_overlays; j++) { 1097 struct omap_overlay *ovl = ovid->overlays[j]; 1098 struct omap_dss_device *dssdev = ovl->get_device(ovl); 1099 1100 if (dssdev) 1101 ovl->disable(ovl); 1102 } 1103 /* Turn of the pipeline */ 1104 if (omapvid_apply_changes(vout)) 1105 v4l2_err(&vout->vid_dev->v4l2_dev, 1106 "failed to change mode in streamoff\n"); 1107 1108 if (vout->next_frm != vout->cur_frm) 1109 vb2_buffer_done(&vout->next_frm->vbuf.vb2_buf, VB2_BUF_STATE_ERROR); 1110 vb2_buffer_done(&vout->cur_frm->vbuf.vb2_buf, VB2_BUF_STATE_ERROR); 1111 list_for_each_entry_safe(buf, tmp, &vout->dma_queue, queue) { 1112 list_del(&buf->queue); 1113 vb2_buffer_done(&buf->vbuf.vb2_buf, VB2_BUF_STATE_ERROR); 1114 } 1115} 1116 1117static int vidioc_s_fbuf(struct file *file, void *fh, 1118 const struct v4l2_framebuffer *a) 1119{ 1120 int enable = 0; 1121 struct omap_overlay *ovl; 1122 struct omapvideo_info *ovid; 1123 struct omap_vout_device *vout = video_drvdata(file); 1124 struct omap_overlay_manager_info info; 1125 enum omap_dss_trans_key_type key_type = OMAP_DSS_COLOR_KEY_GFX_DST; 1126 1127 ovid = &vout->vid_info; 1128 ovl = ovid->overlays[0]; 1129 1130 /* OMAP DSS doesn't support Source and Destination color 1131 key together */ 1132 if ((a->flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY) && 1133 (a->flags & V4L2_FBUF_FLAG_CHROMAKEY)) 1134 return -EINVAL; 1135 /* OMAP DSS Doesn't support the Destination color key 1136 and alpha blending together */ 1137 if ((a->flags & V4L2_FBUF_FLAG_CHROMAKEY) && 1138 (a->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA)) 1139 return -EINVAL; 1140 1141 if ((a->flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY)) { 1142 vout->fbuf.flags |= V4L2_FBUF_FLAG_SRC_CHROMAKEY; 1143 key_type = OMAP_DSS_COLOR_KEY_VID_SRC; 1144 } else 1145 vout->fbuf.flags &= ~V4L2_FBUF_FLAG_SRC_CHROMAKEY; 1146 1147 if ((a->flags & V4L2_FBUF_FLAG_CHROMAKEY)) { 1148 vout->fbuf.flags |= V4L2_FBUF_FLAG_CHROMAKEY; 1149 key_type = OMAP_DSS_COLOR_KEY_GFX_DST; 1150 } else 1151 vout->fbuf.flags &= ~V4L2_FBUF_FLAG_CHROMAKEY; 1152 1153 if (a->flags & (V4L2_FBUF_FLAG_CHROMAKEY | 1154 V4L2_FBUF_FLAG_SRC_CHROMAKEY)) 1155 enable = 1; 1156 else 1157 enable = 0; 1158 if (ovl->manager && ovl->manager->get_manager_info && 1159 ovl->manager->set_manager_info) { 1160 1161 ovl->manager->get_manager_info(ovl->manager, &info); 1162 info.trans_enabled = enable; 1163 info.trans_key_type = key_type; 1164 info.trans_key = vout->win.chromakey; 1165 1166 if (ovl->manager->set_manager_info(ovl->manager, &info)) 1167 return -EINVAL; 1168 } 1169 if (a->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) { 1170 vout->fbuf.flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA; 1171 enable = 1; 1172 } else { 1173 vout->fbuf.flags &= ~V4L2_FBUF_FLAG_LOCAL_ALPHA; 1174 enable = 0; 1175 } 1176 if (ovl->manager && ovl->manager->get_manager_info && 1177 ovl->manager->set_manager_info) { 1178 ovl->manager->get_manager_info(ovl->manager, &info); 1179 /* enable this only if there is no zorder cap */ 1180 if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0) 1181 info.partial_alpha_enabled = enable; 1182 if (ovl->manager->set_manager_info(ovl->manager, &info)) 1183 return -EINVAL; 1184 } 1185 1186 return 0; 1187} 1188 1189static int vidioc_g_fbuf(struct file *file, void *fh, 1190 struct v4l2_framebuffer *a) 1191{ 1192 struct omap_overlay *ovl; 1193 struct omapvideo_info *ovid; 1194 struct omap_vout_device *vout = video_drvdata(file); 1195 struct omap_overlay_manager_info info; 1196 struct omap_video_timings *timing; 1197 struct omap_dss_device *dssdev; 1198 1199 ovid = &vout->vid_info; 1200 ovl = ovid->overlays[0]; 1201 /* get the display device attached to the overlay */ 1202 dssdev = ovl->get_device(ovl); 1203 1204 if (!dssdev) 1205 return -EINVAL; 1206 1207 timing = &dssdev->panel.timings; 1208 1209 vout->fbuf.fmt.height = timing->y_res; 1210 vout->fbuf.fmt.width = timing->x_res; 1211 a->fmt.field = V4L2_FIELD_NONE; 1212 a->fmt.colorspace = V4L2_COLORSPACE_SRGB; 1213 a->fmt.pixelformat = V4L2_PIX_FMT_RGBA32; 1214 a->fmt.height = vout->fbuf.fmt.height; 1215 a->fmt.width = vout->fbuf.fmt.width; 1216 a->fmt.bytesperline = vout->fbuf.fmt.width * 4; 1217 a->fmt.sizeimage = a->fmt.height * a->fmt.bytesperline; 1218 a->base = vout->fbuf.base; 1219 1220 a->flags = vout->fbuf.flags; 1221 a->capability = vout->fbuf.capability; 1222 a->flags &= ~(V4L2_FBUF_FLAG_SRC_CHROMAKEY | V4L2_FBUF_FLAG_CHROMAKEY | 1223 V4L2_FBUF_FLAG_LOCAL_ALPHA); 1224 1225 if (ovl->manager && ovl->manager->get_manager_info) { 1226 ovl->manager->get_manager_info(ovl->manager, &info); 1227 if (info.trans_key_type == OMAP_DSS_COLOR_KEY_VID_SRC) 1228 a->flags |= V4L2_FBUF_FLAG_SRC_CHROMAKEY; 1229 if (info.trans_key_type == OMAP_DSS_COLOR_KEY_GFX_DST) 1230 a->flags |= V4L2_FBUF_FLAG_CHROMAKEY; 1231 if (info.partial_alpha_enabled) 1232 a->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA; 1233 } 1234 1235 return 0; 1236} 1237 1238static int vidioc_enum_output(struct file *file, void *priv_fh, 1239 struct v4l2_output *out) 1240{ 1241 if (out->index) 1242 return -EINVAL; 1243 snprintf(out->name, sizeof(out->name), "Overlay"); 1244 out->type = V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY; 1245 return 0; 1246} 1247 1248static int vidioc_g_output(struct file *file, void *priv_fh, unsigned int *i) 1249{ 1250 *i = 0; 1251 return 0; 1252} 1253 1254static int vidioc_s_output(struct file *file, void *priv_fh, unsigned int i) 1255{ 1256 return i ? -EINVAL : 0; 1257} 1258 1259static const struct v4l2_ioctl_ops vout_ioctl_ops = { 1260 .vidioc_querycap = vidioc_querycap, 1261 .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, 1262 .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out, 1263 .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out, 1264 .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, 1265 .vidioc_s_fbuf = vidioc_s_fbuf, 1266 .vidioc_g_fbuf = vidioc_g_fbuf, 1267 .vidioc_try_fmt_vid_out_overlay = vidioc_try_fmt_vid_overlay, 1268 .vidioc_s_fmt_vid_out_overlay = vidioc_s_fmt_vid_overlay, 1269 .vidioc_g_fmt_vid_out_overlay = vidioc_g_fmt_vid_overlay, 1270 .vidioc_g_selection = vidioc_g_selection, 1271 .vidioc_s_selection = vidioc_s_selection, 1272 .vidioc_enum_output = vidioc_enum_output, 1273 .vidioc_g_output = vidioc_g_output, 1274 .vidioc_s_output = vidioc_s_output, 1275 .vidioc_reqbufs = vb2_ioctl_reqbufs, 1276 .vidioc_create_bufs = vb2_ioctl_create_bufs, 1277 .vidioc_querybuf = vb2_ioctl_querybuf, 1278 .vidioc_qbuf = vb2_ioctl_qbuf, 1279 .vidioc_dqbuf = vb2_ioctl_dqbuf, 1280 .vidioc_expbuf = vb2_ioctl_expbuf, 1281 .vidioc_streamon = vb2_ioctl_streamon, 1282 .vidioc_streamoff = vb2_ioctl_streamoff, 1283 .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, 1284 .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 1285}; 1286 1287static const struct v4l2_file_operations omap_vout_fops = { 1288 .owner = THIS_MODULE, 1289 .unlocked_ioctl = video_ioctl2, 1290 .poll = vb2_fop_poll, 1291 .mmap = vb2_fop_mmap, 1292 .open = v4l2_fh_open, 1293 .release = vb2_fop_release, 1294}; 1295 1296static const struct vb2_ops omap_vout_vb2_ops = { 1297 .queue_setup = omap_vout_vb2_queue_setup, 1298 .buf_queue = omap_vout_vb2_queue, 1299 .buf_prepare = omap_vout_vb2_prepare, 1300 .start_streaming = omap_vout_vb2_start_streaming, 1301 .stop_streaming = omap_vout_vb2_stop_streaming, 1302 .wait_prepare = vb2_ops_wait_prepare, 1303 .wait_finish = vb2_ops_wait_finish, 1304}; 1305 1306/* Init functions used during driver initialization */ 1307/* Initial setup of video_data */ 1308static int __init omap_vout_setup_video_data(struct omap_vout_device *vout) 1309{ 1310 struct video_device *vfd; 1311 struct v4l2_pix_format *pix; 1312 struct omap_overlay *ovl = vout->vid_info.overlays[0]; 1313 struct omap_dss_device *display = ovl->get_device(ovl); 1314 struct v4l2_ctrl_handler *hdl; 1315 struct vb2_queue *vq; 1316 int ret; 1317 1318 /* set the default pix */ 1319 pix = &vout->pix; 1320 1321 /* Set the default picture of QVGA */ 1322 pix->width = QQVGA_WIDTH; 1323 pix->height = QQVGA_HEIGHT; 1324 1325 /* Default pixel format is RGB 5-6-5 */ 1326 pix->pixelformat = V4L2_PIX_FMT_RGB565; 1327 pix->field = V4L2_FIELD_NONE; 1328 pix->bytesperline = pix->width * 2; 1329 pix->sizeimage = pix->bytesperline * pix->height; 1330 pix->colorspace = V4L2_COLORSPACE_SRGB; 1331 1332 vout->bpp = RGB565_BPP; 1333 vout->fbuf.fmt.width = display->panel.timings.x_res; 1334 vout->fbuf.fmt.height = display->panel.timings.y_res; 1335 vout->cropped_offset = 0; 1336 1337 /* Set the data structures for the overlay parameters*/ 1338 vout->fbuf.flags = V4L2_FBUF_FLAG_OVERLAY; 1339 vout->fbuf.capability = V4L2_FBUF_CAP_LOCAL_ALPHA | 1340 V4L2_FBUF_CAP_SRC_CHROMAKEY | V4L2_FBUF_CAP_CHROMAKEY | 1341 V4L2_FBUF_CAP_EXTERNOVERLAY; 1342 if (ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) { 1343 vout->win.global_alpha = 255; 1344 vout->fbuf.capability |= V4L2_FBUF_CAP_GLOBAL_ALPHA; 1345 vout->fbuf.flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA; 1346 } else { 1347 vout->win.global_alpha = 0; 1348 } 1349 vout->win.field = V4L2_FIELD_NONE; 1350 1351 omap_vout_new_format(pix, &vout->fbuf, &vout->crop, &vout->win); 1352 1353 hdl = &vout->ctrl_handler; 1354 v4l2_ctrl_handler_init(hdl, 3); 1355 if (vout->vid_info.rotation_type == VOUT_ROT_VRFB) { 1356 v4l2_ctrl_new_std(hdl, &omap_vout_ctrl_ops, 1357 V4L2_CID_ROTATE, 0, 270, 90, 0); 1358 v4l2_ctrl_new_std(hdl, &omap_vout_ctrl_ops, 1359 V4L2_CID_VFLIP, 0, 1, 1, 0); 1360 } 1361 v4l2_ctrl_new_std(hdl, &omap_vout_ctrl_ops, 1362 V4L2_CID_BG_COLOR, 0, 0xffffff, 1, 0); 1363 if (hdl->error) 1364 return hdl->error; 1365 1366 vout->rotation = 0; 1367 vout->mirror = false; 1368 INIT_LIST_HEAD(&vout->dma_queue); 1369 if (vout->vid_info.rotation_type == VOUT_ROT_VRFB) 1370 vout->vrfb_bpp = 2; 1371 1372 /* initialize the video_device struct */ 1373 vfd = vout->vfd = video_device_alloc(); 1374 1375 if (!vfd) { 1376 printk(KERN_ERR VOUT_NAME 1377 ": could not allocate video device struct\n"); 1378 v4l2_ctrl_handler_free(hdl); 1379 return -ENOMEM; 1380 } 1381 vfd->ctrl_handler = hdl; 1382 vfd->release = video_device_release; 1383 vfd->ioctl_ops = &vout_ioctl_ops; 1384 1385 strscpy(vfd->name, VOUT_NAME, sizeof(vfd->name)); 1386 1387 vfd->fops = &omap_vout_fops; 1388 vfd->v4l2_dev = &vout->vid_dev->v4l2_dev; 1389 vfd->vfl_dir = VFL_DIR_TX; 1390 vfd->minor = -1; 1391 vfd->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT | 1392 V4L2_CAP_VIDEO_OUTPUT_OVERLAY; 1393 mutex_init(&vout->lock); 1394 1395 vq = &vout->vq; 1396 vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; 1397 vq->io_modes = VB2_MMAP | VB2_DMABUF; 1398 vq->drv_priv = vout; 1399 vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; 1400 vq->buf_struct_size = sizeof(struct omap_vout_buffer); 1401 vq->dev = vfd->v4l2_dev->dev; 1402 1403 vq->ops = &omap_vout_vb2_ops; 1404 vq->mem_ops = &vb2_dma_contig_memops; 1405 vq->lock = &vout->lock; 1406 vq->min_buffers_needed = 1; 1407 vfd->queue = vq; 1408 1409 ret = vb2_queue_init(vq); 1410 if (ret) { 1411 v4l2_ctrl_handler_free(hdl); 1412 video_device_release(vfd); 1413 } 1414 return ret; 1415} 1416 1417/* Setup video buffers */ 1418static int __init omap_vout_setup_video_bufs(struct platform_device *pdev, 1419 int vid_num) 1420{ 1421 struct omapvideo_info *ovid; 1422 struct omap_vout_device *vout; 1423 struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev); 1424 struct omap2video_device *vid_dev = 1425 container_of(v4l2_dev, struct omap2video_device, v4l2_dev); 1426 int ret = 0; 1427 1428 vout = vid_dev->vouts[vid_num]; 1429 ovid = &vout->vid_info; 1430 1431 if (ovid->rotation_type == VOUT_ROT_VRFB) { 1432 bool static_vrfb_allocation = (vid_num == 0) ? 1433 vid1_static_vrfb_alloc : vid2_static_vrfb_alloc; 1434 ret = omap_vout_setup_vrfb_bufs(pdev, vid_num, 1435 static_vrfb_allocation); 1436 } 1437 return ret; 1438} 1439 1440/* Create video out devices */ 1441static int __init omap_vout_create_video_devices(struct platform_device *pdev) 1442{ 1443 int ret = 0, k; 1444 struct omap_vout_device *vout; 1445 struct video_device *vfd = NULL; 1446 struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev); 1447 struct omap2video_device *vid_dev = container_of(v4l2_dev, 1448 struct omap2video_device, v4l2_dev); 1449 struct omap_overlay *ovl = vid_dev->overlays[0]; 1450 struct omap_overlay_info info; 1451 1452 ovl->get_overlay_info(ovl, &info); 1453 1454 for (k = 0; k < pdev->num_resources; k++) { 1455 1456 vout = kzalloc(sizeof(struct omap_vout_device), GFP_KERNEL); 1457 if (!vout) { 1458 dev_err(&pdev->dev, ": could not allocate memory\n"); 1459 return -ENOMEM; 1460 } 1461 1462 vout->vid = k; 1463 vid_dev->vouts[k] = vout; 1464 vout->vid_dev = vid_dev; 1465 /* Select video2 if only 1 overlay is controlled by V4L2 */ 1466 if (pdev->num_resources == 1) 1467 vout->vid_info.overlays[0] = vid_dev->overlays[k + 2]; 1468 else 1469 /* Else select video1 and video2 one by one. */ 1470 vout->vid_info.overlays[0] = vid_dev->overlays[k + 1]; 1471 vout->vid_info.num_overlays = 1; 1472 vout->vid_info.id = k + 1; 1473 spin_lock_init(&vout->vbq_lock); 1474 /* 1475 * Set the framebuffer base, this allows applications to find 1476 * the fb corresponding to this overlay. 1477 * 1478 * To be precise: fbuf.base should match smem_start of 1479 * struct fb_fix_screeninfo. 1480 */ 1481 vout->fbuf.base = (void *)(uintptr_t)info.paddr; 1482 1483 /* Set VRFB as rotation_type for omap2 and omap3 */ 1484 if (omap_vout_dss_omap24xx() || omap_vout_dss_omap34xx()) 1485 vout->vid_info.rotation_type = VOUT_ROT_VRFB; 1486 1487 /* Setup the default configuration for the video devices 1488 */ 1489 if (omap_vout_setup_video_data(vout) != 0) { 1490 ret = -ENOMEM; 1491 goto error; 1492 } 1493 1494 /* Allocate default number of buffers for the video streaming 1495 * and reserve the VRFB space for rotation 1496 */ 1497 if (omap_vout_setup_video_bufs(pdev, k) != 0) { 1498 ret = -ENOMEM; 1499 goto error1; 1500 } 1501 1502 /* Register the Video device with V4L2 1503 */ 1504 vfd = vout->vfd; 1505 if (video_register_device(vfd, VFL_TYPE_VIDEO, -1) < 0) { 1506 dev_err(&pdev->dev, 1507 ": Could not register Video for Linux device\n"); 1508 vfd->minor = -1; 1509 ret = -ENODEV; 1510 goto error2; 1511 } 1512 video_set_drvdata(vfd, vout); 1513 1514 dev_info(&pdev->dev, 1515 ": registered and initialized video device %d\n", 1516 vfd->minor); 1517 if (k == (pdev->num_resources - 1)) 1518 return 0; 1519 1520 continue; 1521error2: 1522 if (vout->vid_info.rotation_type == VOUT_ROT_VRFB) 1523 omap_vout_release_vrfb(vout); 1524error1: 1525 video_device_release(vfd); 1526error: 1527 kfree(vout); 1528 return ret; 1529 } 1530 1531 return -ENODEV; 1532} 1533/* Driver functions */ 1534static void omap_vout_cleanup_device(struct omap_vout_device *vout) 1535{ 1536 struct video_device *vfd; 1537 struct omapvideo_info *ovid; 1538 1539 if (!vout) 1540 return; 1541 1542 vfd = vout->vfd; 1543 ovid = &vout->vid_info; 1544 if (vfd) { 1545 if (!video_is_registered(vfd)) { 1546 /* 1547 * The device was never registered, so release the 1548 * video_device struct directly. 1549 */ 1550 video_device_release(vfd); 1551 } else { 1552 /* 1553 * The unregister function will release the video_device 1554 * struct as well as unregistering it. 1555 */ 1556 video_unregister_device(vfd); 1557 } 1558 } 1559 v4l2_ctrl_handler_free(&vout->ctrl_handler); 1560 if (ovid->rotation_type == VOUT_ROT_VRFB) { 1561 omap_vout_release_vrfb(vout); 1562 /* Free the VRFB buffer if allocated 1563 * init time 1564 */ 1565 if (vout->vrfb_static_allocation) 1566 omap_vout_free_vrfb_buffers(vout); 1567 } 1568 1569 kfree(vout); 1570} 1571 1572static int omap_vout_remove(struct platform_device *pdev) 1573{ 1574 int k; 1575 struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev); 1576 struct omap2video_device *vid_dev = container_of(v4l2_dev, struct 1577 omap2video_device, v4l2_dev); 1578 1579 v4l2_device_unregister(v4l2_dev); 1580 for (k = 0; k < pdev->num_resources; k++) 1581 omap_vout_cleanup_device(vid_dev->vouts[k]); 1582 1583 for (k = 0; k < vid_dev->num_displays; k++) { 1584 if (vid_dev->displays[k]->state != OMAP_DSS_DISPLAY_DISABLED) 1585 vid_dev->displays[k]->driver->disable(vid_dev->displays[k]); 1586 1587 omap_dss_put_device(vid_dev->displays[k]); 1588 } 1589 kfree(vid_dev); 1590 return 0; 1591} 1592 1593static int __init omap_vout_probe(struct platform_device *pdev) 1594{ 1595 int ret = 0, i; 1596 struct omap_overlay *ovl; 1597 struct omap_dss_device *dssdev = NULL; 1598 struct omap_dss_device *def_display; 1599 struct omap2video_device *vid_dev = NULL; 1600 1601 if (omapdss_is_initialized() == false) 1602 return -EPROBE_DEFER; 1603 1604 ret = omapdss_compat_init(); 1605 if (ret) { 1606 dev_err(&pdev->dev, "failed to init dss\n"); 1607 return ret; 1608 } 1609 1610 if (pdev->num_resources == 0) { 1611 dev_err(&pdev->dev, "probed for an unknown device\n"); 1612 ret = -ENODEV; 1613 goto err_dss_init; 1614 } 1615 1616 vid_dev = kzalloc(sizeof(struct omap2video_device), GFP_KERNEL); 1617 if (vid_dev == NULL) { 1618 ret = -ENOMEM; 1619 goto err_dss_init; 1620 } 1621 1622 vid_dev->num_displays = 0; 1623 for_each_dss_dev(dssdev) { 1624 omap_dss_get_device(dssdev); 1625 1626 if (!dssdev->driver) { 1627 dev_warn(&pdev->dev, "no driver for display: %s\n", 1628 dssdev->name); 1629 omap_dss_put_device(dssdev); 1630 continue; 1631 } 1632 1633 vid_dev->displays[vid_dev->num_displays++] = dssdev; 1634 } 1635 1636 if (vid_dev->num_displays == 0) { 1637 dev_err(&pdev->dev, "no displays\n"); 1638 ret = -EINVAL; 1639 goto probe_err0; 1640 } 1641 1642 vid_dev->num_overlays = omap_dss_get_num_overlays(); 1643 for (i = 0; i < vid_dev->num_overlays; i++) 1644 vid_dev->overlays[i] = omap_dss_get_overlay(i); 1645 1646 vid_dev->num_managers = omap_dss_get_num_overlay_managers(); 1647 for (i = 0; i < vid_dev->num_managers; i++) 1648 vid_dev->managers[i] = omap_dss_get_overlay_manager(i); 1649 1650 /* Get the Video1 overlay and video2 overlay. 1651 * Setup the Display attached to that overlays 1652 */ 1653 for (i = 1; i < vid_dev->num_overlays; i++) { 1654 ovl = omap_dss_get_overlay(i); 1655 dssdev = ovl->get_device(ovl); 1656 1657 if (dssdev) { 1658 def_display = dssdev; 1659 } else { 1660 dev_warn(&pdev->dev, "cannot find display\n"); 1661 def_display = NULL; 1662 } 1663 if (def_display) { 1664 struct omap_dss_driver *dssdrv = def_display->driver; 1665 1666 ret = dssdrv->enable(def_display); 1667 if (ret) { 1668 /* Here we are not considering a error 1669 * as display may be enabled by frame 1670 * buffer driver 1671 */ 1672 dev_warn(&pdev->dev, 1673 "'%s' Display already enabled\n", 1674 def_display->name); 1675 } 1676 } 1677 } 1678 1679 if (v4l2_device_register(&pdev->dev, &vid_dev->v4l2_dev) < 0) { 1680 dev_err(&pdev->dev, "v4l2_device_register failed\n"); 1681 ret = -ENODEV; 1682 goto probe_err1; 1683 } 1684 1685 ret = omap_vout_create_video_devices(pdev); 1686 if (ret) 1687 goto probe_err2; 1688 1689 for (i = 0; i < vid_dev->num_displays; i++) { 1690 struct omap_dss_device *display = vid_dev->displays[i]; 1691 1692 if (display->driver->update) 1693 display->driver->update(display, 0, 0, 1694 display->panel.timings.x_res, 1695 display->panel.timings.y_res); 1696 } 1697 return 0; 1698 1699probe_err2: 1700 v4l2_device_unregister(&vid_dev->v4l2_dev); 1701probe_err1: 1702 for (i = 1; i < vid_dev->num_overlays; i++) { 1703 def_display = NULL; 1704 ovl = omap_dss_get_overlay(i); 1705 dssdev = ovl->get_device(ovl); 1706 1707 if (dssdev) 1708 def_display = dssdev; 1709 1710 if (def_display && def_display->driver) 1711 def_display->driver->disable(def_display); 1712 } 1713probe_err0: 1714 kfree(vid_dev); 1715err_dss_init: 1716 omapdss_compat_uninit(); 1717 return ret; 1718} 1719 1720static struct platform_driver omap_vout_driver = { 1721 .driver = { 1722 .name = VOUT_NAME, 1723 }, 1724 .remove = omap_vout_remove, 1725}; 1726 1727static int __init omap_vout_init(void) 1728{ 1729 if (platform_driver_probe(&omap_vout_driver, omap_vout_probe) != 0) { 1730 printk(KERN_ERR VOUT_NAME ":Could not register Video driver\n"); 1731 return -EINVAL; 1732 } 1733 return 0; 1734} 1735 1736static void omap_vout_cleanup(void) 1737{ 1738 platform_driver_unregister(&omap_vout_driver); 1739} 1740 1741late_initcall(omap_vout_init); 1742module_exit(omap_vout_cleanup);