1/* 2 * Samsung S5P/EXYNOS4 SoC series FIMC (video postprocessor) driver 3 * 4 * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd. 5 * Sylwester Nawrocki <s.nawrocki@samsung.com> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published 9 * by the Free Software Foundation, either version 2 of the License, 10 * or (at your option) any later version. 11 */ 12 13#include <linux/module.h> 14#include <linux/kernel.h> 15#include <linux/types.h> 16#include <linux/errno.h> 17#include <linux/bug.h> 18#include <linux/interrupt.h> 19#include <linux/device.h> 20#include <linux/platform_device.h> 21#include <linux/pm_runtime.h> 22#include <linux/list.h> 23#include <linux/io.h> 24#include <linux/slab.h> 25#include <linux/clk.h> 26#include <media/v4l2-ioctl.h> 27#include <media/videobuf2-core.h> 28#include <media/videobuf2-dma-contig.h> 29 30#include "common.h" 31#include "fimc-core.h" 32#include "fimc-reg.h" 33#include "media-dev.h" 34 35static unsigned int get_m2m_fmt_flags(unsigned int stream_type) 36{ 37 if (stream_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) 38 return FMT_FLAGS_M2M_IN; 39 else 40 return FMT_FLAGS_M2M_OUT; 41} 42 43void fimc_m2m_job_finish(struct fimc_ctx *ctx, int vb_state) 44{ 45 struct vb2_buffer *src_vb, *dst_vb; 46 47 if (!ctx || !ctx->fh.m2m_ctx) 48 return; 49 50 src_vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); 51 dst_vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); 52 53 if (src_vb && dst_vb) { 54 v4l2_m2m_buf_done(src_vb, vb_state); 55 v4l2_m2m_buf_done(dst_vb, vb_state); 56 v4l2_m2m_job_finish(ctx->fimc_dev->m2m.m2m_dev, 57 ctx->fh.m2m_ctx); 58 } 59} 60 61/* Complete the transaction which has been scheduled for execution. */ 62static int fimc_m2m_shutdown(struct fimc_ctx *ctx) 63{ 64 struct fimc_dev *fimc = ctx->fimc_dev; 65 int ret; 66 67 if (!fimc_m2m_pending(fimc)) 68 return 0; 69 70 fimc_ctx_state_set(FIMC_CTX_SHUT, ctx); 71 72 ret = wait_event_timeout(fimc->irq_queue, 73 !fimc_ctx_state_is_set(FIMC_CTX_SHUT, ctx), 74 FIMC_SHUTDOWN_TIMEOUT); 75 76 return ret == 0 ? -ETIMEDOUT : ret; 77} 78 79static int start_streaming(struct vb2_queue *q, unsigned int count) 80{ 81 struct fimc_ctx *ctx = q->drv_priv; 82 int ret; 83 84 ret = pm_runtime_get_sync(&ctx->fimc_dev->pdev->dev); 85 return ret > 0 ? 0 : ret; 86} 87 88static void stop_streaming(struct vb2_queue *q) 89{ 90 struct fimc_ctx *ctx = q->drv_priv; 91 int ret; 92 93 ret = fimc_m2m_shutdown(ctx); 94 if (ret == -ETIMEDOUT) 95 fimc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR); 96 97 pm_runtime_put(&ctx->fimc_dev->pdev->dev); 98} 99 100static void fimc_device_run(void *priv) 101{ 102 struct vb2_buffer *src_vb, *dst_vb; 103 struct fimc_ctx *ctx = priv; 104 struct fimc_frame *sf, *df; 105 struct fimc_dev *fimc; 106 unsigned long flags; 107 int ret; 108 109 if (WARN(!ctx, "Null context\n")) 110 return; 111 112 fimc = ctx->fimc_dev; 113 spin_lock_irqsave(&fimc->slock, flags); 114 115 set_bit(ST_M2M_PEND, &fimc->state); 116 sf = &ctx->s_frame; 117 df = &ctx->d_frame; 118 119 if (ctx->state & FIMC_PARAMS) { 120 /* Prepare the DMA offsets for scaler */ 121 fimc_prepare_dma_offset(ctx, sf); 122 fimc_prepare_dma_offset(ctx, df); 123 } 124 125 src_vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); 126 ret = fimc_prepare_addr(ctx, src_vb, sf, &sf->paddr); 127 if (ret) 128 goto dma_unlock; 129 130 dst_vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); 131 ret = fimc_prepare_addr(ctx, dst_vb, df, &df->paddr); 132 if (ret) 133 goto dma_unlock; 134 135 dst_vb->v4l2_buf.timestamp = src_vb->v4l2_buf.timestamp; 136 dst_vb->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; 137 dst_vb->v4l2_buf.flags |= 138 src_vb->v4l2_buf.flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; 139 140 /* Reconfigure hardware if the context has changed. */ 141 if (fimc->m2m.ctx != ctx) { 142 ctx->state |= FIMC_PARAMS; 143 fimc->m2m.ctx = ctx; 144 } 145 146 if (ctx->state & FIMC_PARAMS) { 147 fimc_set_yuv_order(ctx); 148 fimc_hw_set_input_path(ctx); 149 fimc_hw_set_in_dma(ctx); 150 ret = fimc_set_scaler_info(ctx); 151 if (ret) 152 goto dma_unlock; 153 fimc_hw_set_prescaler(ctx); 154 fimc_hw_set_mainscaler(ctx); 155 fimc_hw_set_target_format(ctx); 156 fimc_hw_set_rotation(ctx); 157 fimc_hw_set_effect(ctx); 158 fimc_hw_set_out_dma(ctx); 159 if (fimc->drv_data->alpha_color) 160 fimc_hw_set_rgb_alpha(ctx); 161 fimc_hw_set_output_path(ctx); 162 } 163 fimc_hw_set_input_addr(fimc, &sf->paddr); 164 fimc_hw_set_output_addr(fimc, &df->paddr, -1); 165 166 fimc_activate_capture(ctx); 167 ctx->state &= (FIMC_CTX_M2M | FIMC_CTX_CAP); 168 fimc_hw_activate_input_dma(fimc, true); 169 170dma_unlock: 171 spin_unlock_irqrestore(&fimc->slock, flags); 172} 173 174static void fimc_job_abort(void *priv) 175{ 176 fimc_m2m_shutdown(priv); 177} 178 179static int fimc_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, 180 unsigned int *num_buffers, unsigned int *num_planes, 181 unsigned int sizes[], void *allocators[]) 182{ 183 struct fimc_ctx *ctx = vb2_get_drv_priv(vq); 184 struct fimc_frame *f; 185 int i; 186 187 f = ctx_get_frame(ctx, vq->type); 188 if (IS_ERR(f)) 189 return PTR_ERR(f); 190 /* 191 * Return number of non-contigous planes (plane buffers) 192 * depending on the configured color format. 193 */ 194 if (!f->fmt) 195 return -EINVAL; 196 197 *num_planes = f->fmt->memplanes; 198 for (i = 0; i < f->fmt->memplanes; i++) { 199 sizes[i] = f->payload[i]; 200 allocators[i] = ctx->fimc_dev->alloc_ctx; 201 } 202 return 0; 203} 204 205static int fimc_buf_prepare(struct vb2_buffer *vb) 206{ 207 struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); 208 struct fimc_frame *frame; 209 int i; 210 211 frame = ctx_get_frame(ctx, vb->vb2_queue->type); 212 if (IS_ERR(frame)) 213 return PTR_ERR(frame); 214 215 for (i = 0; i < frame->fmt->memplanes; i++) 216 vb2_set_plane_payload(vb, i, frame->payload[i]); 217 218 return 0; 219} 220 221static void fimc_buf_queue(struct vb2_buffer *vb) 222{ 223 struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); 224 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb); 225} 226 227static struct vb2_ops fimc_qops = { 228 .queue_setup = fimc_queue_setup, 229 .buf_prepare = fimc_buf_prepare, 230 .buf_queue = fimc_buf_queue, 231 .wait_prepare = vb2_ops_wait_prepare, 232 .wait_finish = vb2_ops_wait_finish, 233 .stop_streaming = stop_streaming, 234 .start_streaming = start_streaming, 235}; 236 237/* 238 * V4L2 ioctl handlers 239 */ 240static int fimc_m2m_querycap(struct file *file, void *fh, 241 struct v4l2_capability *cap) 242{ 243 struct fimc_dev *fimc = video_drvdata(file); 244 unsigned int caps; 245 246 /* 247 * This is only a mem-to-mem video device. The capture and output 248 * device capability flags are left only for backward compatibility 249 * and are scheduled for removal. 250 */ 251 caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE | 252 V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE; 253 254 __fimc_vidioc_querycap(&fimc->pdev->dev, cap, caps); 255 return 0; 256} 257 258static int fimc_m2m_enum_fmt_mplane(struct file *file, void *priv, 259 struct v4l2_fmtdesc *f) 260{ 261 struct fimc_fmt *fmt; 262 263 fmt = fimc_find_format(NULL, NULL, get_m2m_fmt_flags(f->type), 264 f->index); 265 if (!fmt) 266 return -EINVAL; 267 268 strncpy(f->description, fmt->name, sizeof(f->description) - 1); 269 f->pixelformat = fmt->fourcc; 270 return 0; 271} 272 273static int fimc_m2m_g_fmt_mplane(struct file *file, void *fh, 274 struct v4l2_format *f) 275{ 276 struct fimc_ctx *ctx = fh_to_ctx(fh); 277 struct fimc_frame *frame = ctx_get_frame(ctx, f->type); 278 279 if (IS_ERR(frame)) 280 return PTR_ERR(frame); 281 282 __fimc_get_format(frame, f); 283 return 0; 284} 285 286static int fimc_try_fmt_mplane(struct fimc_ctx *ctx, struct v4l2_format *f) 287{ 288 struct fimc_dev *fimc = ctx->fimc_dev; 289 const struct fimc_variant *variant = fimc->variant; 290 struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; 291 struct fimc_fmt *fmt; 292 u32 max_w, mod_x, mod_y; 293 294 if (!IS_M2M(f->type)) 295 return -EINVAL; 296 297 fmt = fimc_find_format(&pix->pixelformat, NULL, 298 get_m2m_fmt_flags(f->type), 0); 299 if (WARN(fmt == NULL, "Pixel format lookup failed")) 300 return -EINVAL; 301 302 if (pix->field == V4L2_FIELD_ANY) 303 pix->field = V4L2_FIELD_NONE; 304 else if (pix->field != V4L2_FIELD_NONE) 305 return -EINVAL; 306 307 if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { 308 max_w = variant->pix_limit->scaler_dis_w; 309 mod_x = ffs(variant->min_inp_pixsize) - 1; 310 } else { 311 max_w = variant->pix_limit->out_rot_dis_w; 312 mod_x = ffs(variant->min_out_pixsize) - 1; 313 } 314 315 if (tiled_fmt(fmt)) { 316 mod_x = 6; /* 64 x 32 pixels tile */ 317 mod_y = 5; 318 } else { 319 if (variant->min_vsize_align == 1) 320 mod_y = fimc_fmt_is_rgb(fmt->color) ? 0 : 1; 321 else 322 mod_y = ffs(variant->min_vsize_align) - 1; 323 } 324 325 v4l_bound_align_image(&pix->width, 16, max_w, mod_x, 326 &pix->height, 8, variant->pix_limit->scaler_dis_w, mod_y, 0); 327 328 fimc_adjust_mplane_format(fmt, pix->width, pix->height, &f->fmt.pix_mp); 329 return 0; 330} 331 332static int fimc_m2m_try_fmt_mplane(struct file *file, void *fh, 333 struct v4l2_format *f) 334{ 335 struct fimc_ctx *ctx = fh_to_ctx(fh); 336 return fimc_try_fmt_mplane(ctx, f); 337} 338 339static void __set_frame_format(struct fimc_frame *frame, struct fimc_fmt *fmt, 340 struct v4l2_pix_format_mplane *pixm) 341{ 342 int i; 343 344 for (i = 0; i < fmt->memplanes; i++) { 345 frame->bytesperline[i] = pixm->plane_fmt[i].bytesperline; 346 frame->payload[i] = pixm->plane_fmt[i].sizeimage; 347 } 348 349 frame->f_width = pixm->width; 350 frame->f_height = pixm->height; 351 frame->o_width = pixm->width; 352 frame->o_height = pixm->height; 353 frame->width = pixm->width; 354 frame->height = pixm->height; 355 frame->offs_h = 0; 356 frame->offs_v = 0; 357 frame->fmt = fmt; 358} 359 360static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh, 361 struct v4l2_format *f) 362{ 363 struct fimc_ctx *ctx = fh_to_ctx(fh); 364 struct fimc_dev *fimc = ctx->fimc_dev; 365 struct fimc_fmt *fmt; 366 struct vb2_queue *vq; 367 struct fimc_frame *frame; 368 int ret; 369 370 ret = fimc_try_fmt_mplane(ctx, f); 371 if (ret) 372 return ret; 373 374 vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); 375 376 if (vb2_is_busy(vq)) { 377 v4l2_err(&fimc->m2m.vfd, "queue (%d) busy\n", f->type); 378 return -EBUSY; 379 } 380 381 if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) 382 frame = &ctx->s_frame; 383 else 384 frame = &ctx->d_frame; 385 386 fmt = fimc_find_format(&f->fmt.pix_mp.pixelformat, NULL, 387 get_m2m_fmt_flags(f->type), 0); 388 if (!fmt) 389 return -EINVAL; 390 391 __set_frame_format(frame, fmt, &f->fmt.pix_mp); 392 393 /* Update RGB Alpha control state and value range */ 394 fimc_alpha_ctrl_update(ctx); 395 396 return 0; 397} 398 399static int fimc_m2m_cropcap(struct file *file, void *fh, 400 struct v4l2_cropcap *cr) 401{ 402 struct fimc_ctx *ctx = fh_to_ctx(fh); 403 struct fimc_frame *frame; 404 405 frame = ctx_get_frame(ctx, cr->type); 406 if (IS_ERR(frame)) 407 return PTR_ERR(frame); 408 409 cr->bounds.left = 0; 410 cr->bounds.top = 0; 411 cr->bounds.width = frame->o_width; 412 cr->bounds.height = frame->o_height; 413 cr->defrect = cr->bounds; 414 415 return 0; 416} 417 418static int fimc_m2m_g_crop(struct file *file, void *fh, struct v4l2_crop *cr) 419{ 420 struct fimc_ctx *ctx = fh_to_ctx(fh); 421 struct fimc_frame *frame; 422 423 frame = ctx_get_frame(ctx, cr->type); 424 if (IS_ERR(frame)) 425 return PTR_ERR(frame); 426 427 cr->c.left = frame->offs_h; 428 cr->c.top = frame->offs_v; 429 cr->c.width = frame->width; 430 cr->c.height = frame->height; 431 432 return 0; 433} 434 435static int fimc_m2m_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr) 436{ 437 struct fimc_dev *fimc = ctx->fimc_dev; 438 struct fimc_frame *f; 439 u32 min_size, halign, depth = 0; 440 int i; 441 442 if (cr->c.top < 0 || cr->c.left < 0) { 443 v4l2_err(&fimc->m2m.vfd, 444 "doesn't support negative values for top & left\n"); 445 return -EINVAL; 446 } 447 if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) 448 f = &ctx->d_frame; 449 else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) 450 f = &ctx->s_frame; 451 else 452 return -EINVAL; 453 454 min_size = (f == &ctx->s_frame) ? 455 fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize; 456 457 /* Get pixel alignment constraints. */ 458 if (fimc->variant->min_vsize_align == 1) 459 halign = fimc_fmt_is_rgb(f->fmt->color) ? 0 : 1; 460 else 461 halign = ffs(fimc->variant->min_vsize_align) - 1; 462 463 for (i = 0; i < f->fmt->memplanes; i++) 464 depth += f->fmt->depth[i]; 465 466 v4l_bound_align_image(&cr->c.width, min_size, f->o_width, 467 ffs(min_size) - 1, 468 &cr->c.height, min_size, f->o_height, 469 halign, 64/(ALIGN(depth, 8))); 470 471 /* adjust left/top if cropping rectangle is out of bounds */ 472 if (cr->c.left + cr->c.width > f->o_width) 473 cr->c.left = f->o_width - cr->c.width; 474 if (cr->c.top + cr->c.height > f->o_height) 475 cr->c.top = f->o_height - cr->c.height; 476 477 cr->c.left = round_down(cr->c.left, min_size); 478 cr->c.top = round_down(cr->c.top, fimc->variant->hor_offs_align); 479 480 dbg("l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d", 481 cr->c.left, cr->c.top, cr->c.width, cr->c.height, 482 f->f_width, f->f_height); 483 484 return 0; 485} 486 487static int fimc_m2m_s_crop(struct file *file, void *fh, const struct v4l2_crop *crop) 488{ 489 struct fimc_ctx *ctx = fh_to_ctx(fh); 490 struct fimc_dev *fimc = ctx->fimc_dev; 491 struct v4l2_crop cr = *crop; 492 struct fimc_frame *f; 493 int ret; 494 495 ret = fimc_m2m_try_crop(ctx, &cr); 496 if (ret) 497 return ret; 498 499 f = (cr.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ? 500 &ctx->s_frame : &ctx->d_frame; 501 502 /* Check to see if scaling ratio is within supported range */ 503 if (cr.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { 504 ret = fimc_check_scaler_ratio(ctx, cr.c.width, 505 cr.c.height, ctx->d_frame.width, 506 ctx->d_frame.height, ctx->rotation); 507 } else { 508 ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width, 509 ctx->s_frame.height, cr.c.width, 510 cr.c.height, ctx->rotation); 511 } 512 if (ret) { 513 v4l2_err(&fimc->m2m.vfd, "Out of scaler range\n"); 514 return -EINVAL; 515 } 516 517 f->offs_h = cr.c.left; 518 f->offs_v = cr.c.top; 519 f->width = cr.c.width; 520 f->height = cr.c.height; 521 522 fimc_ctx_state_set(FIMC_PARAMS, ctx); 523 524 return 0; 525} 526 527static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = { 528 .vidioc_querycap = fimc_m2m_querycap, 529 .vidioc_enum_fmt_vid_cap_mplane = fimc_m2m_enum_fmt_mplane, 530 .vidioc_enum_fmt_vid_out_mplane = fimc_m2m_enum_fmt_mplane, 531 .vidioc_g_fmt_vid_cap_mplane = fimc_m2m_g_fmt_mplane, 532 .vidioc_g_fmt_vid_out_mplane = fimc_m2m_g_fmt_mplane, 533 .vidioc_try_fmt_vid_cap_mplane = fimc_m2m_try_fmt_mplane, 534 .vidioc_try_fmt_vid_out_mplane = fimc_m2m_try_fmt_mplane, 535 .vidioc_s_fmt_vid_cap_mplane = fimc_m2m_s_fmt_mplane, 536 .vidioc_s_fmt_vid_out_mplane = fimc_m2m_s_fmt_mplane, 537 .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, 538 .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, 539 .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, 540 .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, 541 .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, 542 .vidioc_streamon = v4l2_m2m_ioctl_streamon, 543 .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, 544 .vidioc_g_crop = fimc_m2m_g_crop, 545 .vidioc_s_crop = fimc_m2m_s_crop, 546 .vidioc_cropcap = fimc_m2m_cropcap 547 548}; 549 550static int queue_init(void *priv, struct vb2_queue *src_vq, 551 struct vb2_queue *dst_vq) 552{ 553 struct fimc_ctx *ctx = priv; 554 int ret; 555 556 src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; 557 src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; 558 src_vq->drv_priv = ctx; 559 src_vq->ops = &fimc_qops; 560 src_vq->mem_ops = &vb2_dma_contig_memops; 561 src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); 562 src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; 563 src_vq->lock = &ctx->fimc_dev->lock; 564 565 ret = vb2_queue_init(src_vq); 566 if (ret) 567 return ret; 568 569 dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; 570 dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; 571 dst_vq->drv_priv = ctx; 572 dst_vq->ops = &fimc_qops; 573 dst_vq->mem_ops = &vb2_dma_contig_memops; 574 dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); 575 dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; 576 dst_vq->lock = &ctx->fimc_dev->lock; 577 578 return vb2_queue_init(dst_vq); 579} 580 581static int fimc_m2m_set_default_format(struct fimc_ctx *ctx) 582{ 583 struct v4l2_pix_format_mplane pixm = { 584 .pixelformat = V4L2_PIX_FMT_RGB32, 585 .width = 800, 586 .height = 600, 587 .plane_fmt[0] = { 588 .bytesperline = 800 * 4, 589 .sizeimage = 800 * 4 * 600, 590 }, 591 }; 592 struct fimc_fmt *fmt; 593 594 fmt = fimc_find_format(&pixm.pixelformat, NULL, FMT_FLAGS_M2M, 0); 595 if (!fmt) 596 return -EINVAL; 597 598 __set_frame_format(&ctx->s_frame, fmt, &pixm); 599 __set_frame_format(&ctx->d_frame, fmt, &pixm); 600 601 return 0; 602} 603 604static int fimc_m2m_open(struct file *file) 605{ 606 struct fimc_dev *fimc = video_drvdata(file); 607 struct fimc_ctx *ctx; 608 int ret = -EBUSY; 609 610 pr_debug("pid: %d, state: %#lx\n", task_pid_nr(current), fimc->state); 611 612 if (mutex_lock_interruptible(&fimc->lock)) 613 return -ERESTARTSYS; 614 /* 615 * Don't allow simultaneous open() of the mem-to-mem and the 616 * capture video node that belong to same FIMC IP instance. 617 */ 618 if (test_bit(ST_CAPT_BUSY, &fimc->state)) 619 goto unlock; 620 621 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 622 if (!ctx) { 623 ret = -ENOMEM; 624 goto unlock; 625 } 626 v4l2_fh_init(&ctx->fh, &fimc->m2m.vfd); 627 ctx->fimc_dev = fimc; 628 629 /* Default color format */ 630 ctx->s_frame.fmt = fimc_get_format(0); 631 ctx->d_frame.fmt = fimc_get_format(0); 632 633 ret = fimc_ctrls_create(ctx); 634 if (ret) 635 goto error_fh; 636 637 /* Use separate control handler per file handle */ 638 ctx->fh.ctrl_handler = &ctx->ctrls.handler; 639 file->private_data = &ctx->fh; 640 v4l2_fh_add(&ctx->fh); 641 642 /* Setup the device context for memory-to-memory mode */ 643 ctx->state = FIMC_CTX_M2M; 644 ctx->flags = 0; 645 ctx->in_path = FIMC_IO_DMA; 646 ctx->out_path = FIMC_IO_DMA; 647 ctx->scaler.enabled = 1; 648 649 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(fimc->m2m.m2m_dev, ctx, queue_init); 650 if (IS_ERR(ctx->fh.m2m_ctx)) { 651 ret = PTR_ERR(ctx->fh.m2m_ctx); 652 goto error_c; 653 } 654 655 if (fimc->m2m.refcnt++ == 0) 656 set_bit(ST_M2M_RUN, &fimc->state); 657 658 ret = fimc_m2m_set_default_format(ctx); 659 if (ret < 0) 660 goto error_m2m_ctx; 661 662 mutex_unlock(&fimc->lock); 663 return 0; 664 665error_m2m_ctx: 666 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); 667error_c: 668 fimc_ctrls_delete(ctx); 669error_fh: 670 v4l2_fh_del(&ctx->fh); 671 v4l2_fh_exit(&ctx->fh); 672 kfree(ctx); 673unlock: 674 mutex_unlock(&fimc->lock); 675 return ret; 676} 677 678static int fimc_m2m_release(struct file *file) 679{ 680 struct fimc_ctx *ctx = fh_to_ctx(file->private_data); 681 struct fimc_dev *fimc = ctx->fimc_dev; 682 683 dbg("pid: %d, state: 0x%lx, refcnt= %d", 684 task_pid_nr(current), fimc->state, fimc->m2m.refcnt); 685 686 mutex_lock(&fimc->lock); 687 688 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); 689 fimc_ctrls_delete(ctx); 690 v4l2_fh_del(&ctx->fh); 691 v4l2_fh_exit(&ctx->fh); 692 693 if (--fimc->m2m.refcnt <= 0) 694 clear_bit(ST_M2M_RUN, &fimc->state); 695 kfree(ctx); 696 697 mutex_unlock(&fimc->lock); 698 return 0; 699} 700 701static const struct v4l2_file_operations fimc_m2m_fops = { 702 .owner = THIS_MODULE, 703 .open = fimc_m2m_open, 704 .release = fimc_m2m_release, 705 .poll = v4l2_m2m_fop_poll, 706 .unlocked_ioctl = video_ioctl2, 707 .mmap = v4l2_m2m_fop_mmap, 708}; 709 710static struct v4l2_m2m_ops m2m_ops = { 711 .device_run = fimc_device_run, 712 .job_abort = fimc_job_abort, 713}; 714 715int fimc_register_m2m_device(struct fimc_dev *fimc, 716 struct v4l2_device *v4l2_dev) 717{ 718 struct video_device *vfd = &fimc->m2m.vfd; 719 int ret; 720 721 fimc->v4l2_dev = v4l2_dev; 722 723 memset(vfd, 0, sizeof(*vfd)); 724 vfd->fops = &fimc_m2m_fops; 725 vfd->ioctl_ops = &fimc_m2m_ioctl_ops; 726 vfd->v4l2_dev = v4l2_dev; 727 vfd->minor = -1; 728 vfd->release = video_device_release_empty; 729 vfd->lock = &fimc->lock; 730 vfd->vfl_dir = VFL_DIR_M2M; 731 732 snprintf(vfd->name, sizeof(vfd->name), "fimc.%d.m2m", fimc->id); 733 video_set_drvdata(vfd, fimc); 734 735 fimc->m2m.m2m_dev = v4l2_m2m_init(&m2m_ops); 736 if (IS_ERR(fimc->m2m.m2m_dev)) { 737 v4l2_err(v4l2_dev, "failed to initialize v4l2-m2m device\n"); 738 return PTR_ERR(fimc->m2m.m2m_dev); 739 } 740 741 ret = media_entity_init(&vfd->entity, 0, NULL, 0); 742 if (ret) 743 goto err_me; 744 745 ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); 746 if (ret) 747 goto err_vd; 748 749 v4l2_info(v4l2_dev, "Registered %s as /dev/%s\n", 750 vfd->name, video_device_node_name(vfd)); 751 return 0; 752 753err_vd: 754 media_entity_cleanup(&vfd->entity); 755err_me: 756 v4l2_m2m_release(fimc->m2m.m2m_dev); 757 return ret; 758} 759 760void fimc_unregister_m2m_device(struct fimc_dev *fimc) 761{ 762 if (!fimc) 763 return; 764 765 if (fimc->m2m.m2m_dev) 766 v4l2_m2m_release(fimc->m2m.m2m_dev); 767 768 if (video_is_registered(&fimc->m2m.vfd)) { 769 video_unregister_device(&fimc->m2m.vfd); 770 media_entity_cleanup(&fimc->m2m.vfd.entity); 771 } 772} 773