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-v4l2.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_v4l2_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_v4l2_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->vb2_buf, 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->vb2_buf, df, &df->paddr); 132 if (ret) 133 goto dma_unlock; 134 135 dst_vb->timestamp = src_vb->timestamp; 136 dst_vb->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; 137 dst_vb->flags |= 138 src_vb->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 void *parg, 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-contiguous 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 vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 224 struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); 225 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); 226} 227 228static struct vb2_ops fimc_qops = { 229 .queue_setup = fimc_queue_setup, 230 .buf_prepare = fimc_buf_prepare, 231 .buf_queue = fimc_buf_queue, 232 .wait_prepare = vb2_ops_wait_prepare, 233 .wait_finish = vb2_ops_wait_finish, 234 .stop_streaming = stop_streaming, 235 .start_streaming = start_streaming, 236}; 237 238/* 239 * V4L2 ioctl handlers 240 */ 241static int fimc_m2m_querycap(struct file *file, void *fh, 242 struct v4l2_capability *cap) 243{ 244 struct fimc_dev *fimc = video_drvdata(file); 245 unsigned int caps; 246 247 /* 248 * This is only a mem-to-mem video device. The capture and output 249 * device capability flags are left only for backward compatibility 250 * and are scheduled for removal. 251 */ 252 caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE | 253 V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE; 254 255 __fimc_vidioc_querycap(&fimc->pdev->dev, cap, caps); 256 return 0; 257} 258 259static int fimc_m2m_enum_fmt_mplane(struct file *file, void *priv, 260 struct v4l2_fmtdesc *f) 261{ 262 struct fimc_fmt *fmt; 263 264 fmt = fimc_find_format(NULL, NULL, get_m2m_fmt_flags(f->type), 265 f->index); 266 if (!fmt) 267 return -EINVAL; 268 269 strncpy(f->description, fmt->name, sizeof(f->description) - 1); 270 f->pixelformat = fmt->fourcc; 271 return 0; 272} 273 274static int fimc_m2m_g_fmt_mplane(struct file *file, void *fh, 275 struct v4l2_format *f) 276{ 277 struct fimc_ctx *ctx = fh_to_ctx(fh); 278 struct fimc_frame *frame = ctx_get_frame(ctx, f->type); 279 280 if (IS_ERR(frame)) 281 return PTR_ERR(frame); 282 283 __fimc_get_format(frame, f); 284 return 0; 285} 286 287static int fimc_try_fmt_mplane(struct fimc_ctx *ctx, struct v4l2_format *f) 288{ 289 struct fimc_dev *fimc = ctx->fimc_dev; 290 const struct fimc_variant *variant = fimc->variant; 291 struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; 292 struct fimc_fmt *fmt; 293 u32 max_w, mod_x, mod_y; 294 295 if (!IS_M2M(f->type)) 296 return -EINVAL; 297 298 fmt = fimc_find_format(&pix->pixelformat, NULL, 299 get_m2m_fmt_flags(f->type), 0); 300 if (WARN(fmt == NULL, "Pixel format lookup failed")) 301 return -EINVAL; 302 303 if (pix->field == V4L2_FIELD_ANY) 304 pix->field = V4L2_FIELD_NONE; 305 else if (pix->field != V4L2_FIELD_NONE) 306 return -EINVAL; 307 308 if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { 309 max_w = variant->pix_limit->scaler_dis_w; 310 mod_x = ffs(variant->min_inp_pixsize) - 1; 311 } else { 312 max_w = variant->pix_limit->out_rot_dis_w; 313 mod_x = ffs(variant->min_out_pixsize) - 1; 314 } 315 316 if (tiled_fmt(fmt)) { 317 mod_x = 6; /* 64 x 32 pixels tile */ 318 mod_y = 5; 319 } else { 320 if (variant->min_vsize_align == 1) 321 mod_y = fimc_fmt_is_rgb(fmt->color) ? 0 : 1; 322 else 323 mod_y = ffs(variant->min_vsize_align) - 1; 324 } 325 326 v4l_bound_align_image(&pix->width, 16, max_w, mod_x, 327 &pix->height, 8, variant->pix_limit->scaler_dis_w, mod_y, 0); 328 329 fimc_adjust_mplane_format(fmt, pix->width, pix->height, &f->fmt.pix_mp); 330 return 0; 331} 332 333static int fimc_m2m_try_fmt_mplane(struct file *file, void *fh, 334 struct v4l2_format *f) 335{ 336 struct fimc_ctx *ctx = fh_to_ctx(fh); 337 return fimc_try_fmt_mplane(ctx, f); 338} 339 340static void __set_frame_format(struct fimc_frame *frame, struct fimc_fmt *fmt, 341 struct v4l2_pix_format_mplane *pixm) 342{ 343 int i; 344 345 for (i = 0; i < fmt->memplanes; i++) { 346 frame->bytesperline[i] = pixm->plane_fmt[i].bytesperline; 347 frame->payload[i] = pixm->plane_fmt[i].sizeimage; 348 } 349 350 frame->f_width = pixm->width; 351 frame->f_height = pixm->height; 352 frame->o_width = pixm->width; 353 frame->o_height = pixm->height; 354 frame->width = pixm->width; 355 frame->height = pixm->height; 356 frame->offs_h = 0; 357 frame->offs_v = 0; 358 frame->fmt = fmt; 359} 360 361static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh, 362 struct v4l2_format *f) 363{ 364 struct fimc_ctx *ctx = fh_to_ctx(fh); 365 struct fimc_dev *fimc = ctx->fimc_dev; 366 struct fimc_fmt *fmt; 367 struct vb2_queue *vq; 368 struct fimc_frame *frame; 369 int ret; 370 371 ret = fimc_try_fmt_mplane(ctx, f); 372 if (ret) 373 return ret; 374 375 vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); 376 377 if (vb2_is_busy(vq)) { 378 v4l2_err(&fimc->m2m.vfd, "queue (%d) busy\n", f->type); 379 return -EBUSY; 380 } 381 382 if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) 383 frame = &ctx->s_frame; 384 else 385 frame = &ctx->d_frame; 386 387 fmt = fimc_find_format(&f->fmt.pix_mp.pixelformat, NULL, 388 get_m2m_fmt_flags(f->type), 0); 389 if (!fmt) 390 return -EINVAL; 391 392 __set_frame_format(frame, fmt, &f->fmt.pix_mp); 393 394 /* Update RGB Alpha control state and value range */ 395 fimc_alpha_ctrl_update(ctx); 396 397 return 0; 398} 399 400static int fimc_m2m_cropcap(struct file *file, void *fh, 401 struct v4l2_cropcap *cr) 402{ 403 struct fimc_ctx *ctx = fh_to_ctx(fh); 404 struct fimc_frame *frame; 405 406 frame = ctx_get_frame(ctx, cr->type); 407 if (IS_ERR(frame)) 408 return PTR_ERR(frame); 409 410 cr->bounds.left = 0; 411 cr->bounds.top = 0; 412 cr->bounds.width = frame->o_width; 413 cr->bounds.height = frame->o_height; 414 cr->defrect = cr->bounds; 415 416 return 0; 417} 418 419static int fimc_m2m_g_crop(struct file *file, void *fh, struct v4l2_crop *cr) 420{ 421 struct fimc_ctx *ctx = fh_to_ctx(fh); 422 struct fimc_frame *frame; 423 424 frame = ctx_get_frame(ctx, cr->type); 425 if (IS_ERR(frame)) 426 return PTR_ERR(frame); 427 428 cr->c.left = frame->offs_h; 429 cr->c.top = frame->offs_v; 430 cr->c.width = frame->width; 431 cr->c.height = frame->height; 432 433 return 0; 434} 435 436static int fimc_m2m_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr) 437{ 438 struct fimc_dev *fimc = ctx->fimc_dev; 439 struct fimc_frame *f; 440 u32 min_size, halign, depth = 0; 441 int i; 442 443 if (cr->c.top < 0 || cr->c.left < 0) { 444 v4l2_err(&fimc->m2m.vfd, 445 "doesn't support negative values for top & left\n"); 446 return -EINVAL; 447 } 448 if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) 449 f = &ctx->d_frame; 450 else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) 451 f = &ctx->s_frame; 452 else 453 return -EINVAL; 454 455 min_size = (f == &ctx->s_frame) ? 456 fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize; 457 458 /* Get pixel alignment constraints. */ 459 if (fimc->variant->min_vsize_align == 1) 460 halign = fimc_fmt_is_rgb(f->fmt->color) ? 0 : 1; 461 else 462 halign = ffs(fimc->variant->min_vsize_align) - 1; 463 464 for (i = 0; i < f->fmt->memplanes; i++) 465 depth += f->fmt->depth[i]; 466 467 v4l_bound_align_image(&cr->c.width, min_size, f->o_width, 468 ffs(min_size) - 1, 469 &cr->c.height, min_size, f->o_height, 470 halign, 64/(ALIGN(depth, 8))); 471 472 /* adjust left/top if cropping rectangle is out of bounds */ 473 if (cr->c.left + cr->c.width > f->o_width) 474 cr->c.left = f->o_width - cr->c.width; 475 if (cr->c.top + cr->c.height > f->o_height) 476 cr->c.top = f->o_height - cr->c.height; 477 478 cr->c.left = round_down(cr->c.left, min_size); 479 cr->c.top = round_down(cr->c.top, fimc->variant->hor_offs_align); 480 481 dbg("l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d", 482 cr->c.left, cr->c.top, cr->c.width, cr->c.height, 483 f->f_width, f->f_height); 484 485 return 0; 486} 487 488static int fimc_m2m_s_crop(struct file *file, void *fh, const struct v4l2_crop *crop) 489{ 490 struct fimc_ctx *ctx = fh_to_ctx(fh); 491 struct fimc_dev *fimc = ctx->fimc_dev; 492 struct v4l2_crop cr = *crop; 493 struct fimc_frame *f; 494 int ret; 495 496 ret = fimc_m2m_try_crop(ctx, &cr); 497 if (ret) 498 return ret; 499 500 f = (cr.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ? 501 &ctx->s_frame : &ctx->d_frame; 502 503 /* Check to see if scaling ratio is within supported range */ 504 if (cr.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { 505 ret = fimc_check_scaler_ratio(ctx, cr.c.width, 506 cr.c.height, ctx->d_frame.width, 507 ctx->d_frame.height, ctx->rotation); 508 } else { 509 ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width, 510 ctx->s_frame.height, cr.c.width, 511 cr.c.height, ctx->rotation); 512 } 513 if (ret) { 514 v4l2_err(&fimc->m2m.vfd, "Out of scaler range\n"); 515 return -EINVAL; 516 } 517 518 f->offs_h = cr.c.left; 519 f->offs_v = cr.c.top; 520 f->width = cr.c.width; 521 f->height = cr.c.height; 522 523 fimc_ctx_state_set(FIMC_PARAMS, ctx); 524 525 return 0; 526} 527 528static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = { 529 .vidioc_querycap = fimc_m2m_querycap, 530 .vidioc_enum_fmt_vid_cap_mplane = fimc_m2m_enum_fmt_mplane, 531 .vidioc_enum_fmt_vid_out_mplane = fimc_m2m_enum_fmt_mplane, 532 .vidioc_g_fmt_vid_cap_mplane = fimc_m2m_g_fmt_mplane, 533 .vidioc_g_fmt_vid_out_mplane = fimc_m2m_g_fmt_mplane, 534 .vidioc_try_fmt_vid_cap_mplane = fimc_m2m_try_fmt_mplane, 535 .vidioc_try_fmt_vid_out_mplane = fimc_m2m_try_fmt_mplane, 536 .vidioc_s_fmt_vid_cap_mplane = fimc_m2m_s_fmt_mplane, 537 .vidioc_s_fmt_vid_out_mplane = fimc_m2m_s_fmt_mplane, 538 .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, 539 .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, 540 .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, 541 .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, 542 .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, 543 .vidioc_streamon = v4l2_m2m_ioctl_streamon, 544 .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, 545 .vidioc_g_crop = fimc_m2m_g_crop, 546 .vidioc_s_crop = fimc_m2m_s_crop, 547 .vidioc_cropcap = fimc_m2m_cropcap 548 549}; 550 551static int queue_init(void *priv, struct vb2_queue *src_vq, 552 struct vb2_queue *dst_vq) 553{ 554 struct fimc_ctx *ctx = priv; 555 int ret; 556 557 src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; 558 src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; 559 src_vq->drv_priv = ctx; 560 src_vq->ops = &fimc_qops; 561 src_vq->mem_ops = &vb2_dma_contig_memops; 562 src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); 563 src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; 564 src_vq->lock = &ctx->fimc_dev->lock; 565 566 ret = vb2_queue_init(src_vq); 567 if (ret) 568 return ret; 569 570 dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; 571 dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; 572 dst_vq->drv_priv = ctx; 573 dst_vq->ops = &fimc_qops; 574 dst_vq->mem_ops = &vb2_dma_contig_memops; 575 dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); 576 dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; 577 dst_vq->lock = &ctx->fimc_dev->lock; 578 579 return vb2_queue_init(dst_vq); 580} 581 582static int fimc_m2m_set_default_format(struct fimc_ctx *ctx) 583{ 584 struct v4l2_pix_format_mplane pixm = { 585 .pixelformat = V4L2_PIX_FMT_RGB32, 586 .width = 800, 587 .height = 600, 588 .plane_fmt[0] = { 589 .bytesperline = 800 * 4, 590 .sizeimage = 800 * 4 * 600, 591 }, 592 }; 593 struct fimc_fmt *fmt; 594 595 fmt = fimc_find_format(&pixm.pixelformat, NULL, FMT_FLAGS_M2M, 0); 596 if (!fmt) 597 return -EINVAL; 598 599 __set_frame_format(&ctx->s_frame, fmt, &pixm); 600 __set_frame_format(&ctx->d_frame, fmt, &pixm); 601 602 return 0; 603} 604 605static int fimc_m2m_open(struct file *file) 606{ 607 struct fimc_dev *fimc = video_drvdata(file); 608 struct fimc_ctx *ctx; 609 int ret = -EBUSY; 610 611 pr_debug("pid: %d, state: %#lx\n", task_pid_nr(current), fimc->state); 612 613 if (mutex_lock_interruptible(&fimc->lock)) 614 return -ERESTARTSYS; 615 /* 616 * Don't allow simultaneous open() of the mem-to-mem and the 617 * capture video node that belong to same FIMC IP instance. 618 */ 619 if (test_bit(ST_CAPT_BUSY, &fimc->state)) 620 goto unlock; 621 622 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 623 if (!ctx) { 624 ret = -ENOMEM; 625 goto unlock; 626 } 627 v4l2_fh_init(&ctx->fh, &fimc->m2m.vfd); 628 ctx->fimc_dev = fimc; 629 630 /* Default color format */ 631 ctx->s_frame.fmt = fimc_get_format(0); 632 ctx->d_frame.fmt = fimc_get_format(0); 633 634 ret = fimc_ctrls_create(ctx); 635 if (ret) 636 goto error_fh; 637 638 /* Use separate control handler per file handle */ 639 ctx->fh.ctrl_handler = &ctx->ctrls.handler; 640 file->private_data = &ctx->fh; 641 v4l2_fh_add(&ctx->fh); 642 643 /* Setup the device context for memory-to-memory mode */ 644 ctx->state = FIMC_CTX_M2M; 645 ctx->flags = 0; 646 ctx->in_path = FIMC_IO_DMA; 647 ctx->out_path = FIMC_IO_DMA; 648 ctx->scaler.enabled = 1; 649 650 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(fimc->m2m.m2m_dev, ctx, queue_init); 651 if (IS_ERR(ctx->fh.m2m_ctx)) { 652 ret = PTR_ERR(ctx->fh.m2m_ctx); 653 goto error_c; 654 } 655 656 if (fimc->m2m.refcnt++ == 0) 657 set_bit(ST_M2M_RUN, &fimc->state); 658 659 ret = fimc_m2m_set_default_format(ctx); 660 if (ret < 0) 661 goto error_m2m_ctx; 662 663 mutex_unlock(&fimc->lock); 664 return 0; 665 666error_m2m_ctx: 667 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); 668error_c: 669 fimc_ctrls_delete(ctx); 670error_fh: 671 v4l2_fh_del(&ctx->fh); 672 v4l2_fh_exit(&ctx->fh); 673 kfree(ctx); 674unlock: 675 mutex_unlock(&fimc->lock); 676 return ret; 677} 678 679static int fimc_m2m_release(struct file *file) 680{ 681 struct fimc_ctx *ctx = fh_to_ctx(file->private_data); 682 struct fimc_dev *fimc = ctx->fimc_dev; 683 684 dbg("pid: %d, state: 0x%lx, refcnt= %d", 685 task_pid_nr(current), fimc->state, fimc->m2m.refcnt); 686 687 mutex_lock(&fimc->lock); 688 689 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); 690 fimc_ctrls_delete(ctx); 691 v4l2_fh_del(&ctx->fh); 692 v4l2_fh_exit(&ctx->fh); 693 694 if (--fimc->m2m.refcnt <= 0) 695 clear_bit(ST_M2M_RUN, &fimc->state); 696 kfree(ctx); 697 698 mutex_unlock(&fimc->lock); 699 return 0; 700} 701 702static const struct v4l2_file_operations fimc_m2m_fops = { 703 .owner = THIS_MODULE, 704 .open = fimc_m2m_open, 705 .release = fimc_m2m_release, 706 .poll = v4l2_m2m_fop_poll, 707 .unlocked_ioctl = video_ioctl2, 708 .mmap = v4l2_m2m_fop_mmap, 709}; 710 711static struct v4l2_m2m_ops m2m_ops = { 712 .device_run = fimc_device_run, 713 .job_abort = fimc_job_abort, 714}; 715 716int fimc_register_m2m_device(struct fimc_dev *fimc, 717 struct v4l2_device *v4l2_dev) 718{ 719 struct video_device *vfd = &fimc->m2m.vfd; 720 int ret; 721 722 fimc->v4l2_dev = v4l2_dev; 723 724 memset(vfd, 0, sizeof(*vfd)); 725 vfd->fops = &fimc_m2m_fops; 726 vfd->ioctl_ops = &fimc_m2m_ioctl_ops; 727 vfd->v4l2_dev = v4l2_dev; 728 vfd->minor = -1; 729 vfd->release = video_device_release_empty; 730 vfd->lock = &fimc->lock; 731 vfd->vfl_dir = VFL_DIR_M2M; 732 733 snprintf(vfd->name, sizeof(vfd->name), "fimc.%d.m2m", fimc->id); 734 video_set_drvdata(vfd, fimc); 735 736 fimc->m2m.m2m_dev = v4l2_m2m_init(&m2m_ops); 737 if (IS_ERR(fimc->m2m.m2m_dev)) { 738 v4l2_err(v4l2_dev, "failed to initialize v4l2-m2m device\n"); 739 return PTR_ERR(fimc->m2m.m2m_dev); 740 } 741 742 ret = media_entity_init(&vfd->entity, 0, NULL, 0); 743 if (ret) 744 goto err_me; 745 746 ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); 747 if (ret) 748 goto err_vd; 749 750 v4l2_info(v4l2_dev, "Registered %s as /dev/%s\n", 751 vfd->name, video_device_node_name(vfd)); 752 return 0; 753 754err_vd: 755 media_entity_cleanup(&vfd->entity); 756err_me: 757 v4l2_m2m_release(fimc->m2m.m2m_dev); 758 return ret; 759} 760 761void fimc_unregister_m2m_device(struct fimc_dev *fimc) 762{ 763 if (!fimc) 764 return; 765 766 if (fimc->m2m.m2m_dev) 767 v4l2_m2m_release(fimc->m2m.m2m_dev); 768 769 if (video_is_registered(&fimc->m2m.vfd)) { 770 video_unregister_device(&fimc->m2m.vfd); 771 media_entity_cleanup(&fimc->m2m.vfd.entity); 772 } 773} 774