.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Samsung S5P/EXYNOS4 SoC series FIMC (video postprocessor) driver |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd. |
---|
5 | 6 | * 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 | 7 | */ |
---|
12 | 8 | |
---|
13 | 9 | #include <linux/module.h> |
---|
.. | .. |
---|
77 | 73 | static int start_streaming(struct vb2_queue *q, unsigned int count) |
---|
78 | 74 | { |
---|
79 | 75 | struct fimc_ctx *ctx = q->drv_priv; |
---|
80 | | - int ret; |
---|
81 | 76 | |
---|
82 | | - ret = pm_runtime_get_sync(&ctx->fimc_dev->pdev->dev); |
---|
83 | | - return ret > 0 ? 0 : ret; |
---|
| 77 | + return pm_runtime_resume_and_get(&ctx->fimc_dev->pdev->dev); |
---|
84 | 78 | } |
---|
85 | 79 | |
---|
86 | 80 | static void stop_streaming(struct vb2_queue *q) |
---|
87 | 81 | { |
---|
88 | 82 | struct fimc_ctx *ctx = q->drv_priv; |
---|
89 | | - |
---|
90 | 83 | |
---|
91 | 84 | fimc_m2m_shutdown(ctx); |
---|
92 | 85 | fimc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR); |
---|
.. | .. |
---|
236 | 229 | struct v4l2_capability *cap) |
---|
237 | 230 | { |
---|
238 | 231 | struct fimc_dev *fimc = video_drvdata(file); |
---|
239 | | - unsigned int caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE; |
---|
240 | 232 | |
---|
241 | | - __fimc_vidioc_querycap(&fimc->pdev->dev, cap, caps); |
---|
| 233 | + __fimc_vidioc_querycap(&fimc->pdev->dev, cap); |
---|
242 | 234 | return 0; |
---|
243 | 235 | } |
---|
244 | 236 | |
---|
245 | | -static int fimc_m2m_enum_fmt_mplane(struct file *file, void *priv, |
---|
246 | | - struct v4l2_fmtdesc *f) |
---|
| 237 | +static int fimc_m2m_enum_fmt(struct file *file, void *priv, |
---|
| 238 | + struct v4l2_fmtdesc *f) |
---|
247 | 239 | { |
---|
248 | 240 | struct fimc_fmt *fmt; |
---|
249 | 241 | |
---|
.. | .. |
---|
252 | 244 | if (!fmt) |
---|
253 | 245 | return -EINVAL; |
---|
254 | 246 | |
---|
255 | | - strncpy(f->description, fmt->name, sizeof(f->description) - 1); |
---|
256 | 247 | f->pixelformat = fmt->fourcc; |
---|
257 | 248 | return 0; |
---|
258 | 249 | } |
---|
.. | .. |
---|
383 | 374 | return 0; |
---|
384 | 375 | } |
---|
385 | 376 | |
---|
386 | | -static int fimc_m2m_cropcap(struct file *file, void *fh, |
---|
387 | | - struct v4l2_cropcap *cr) |
---|
| 377 | +static int fimc_m2m_g_selection(struct file *file, void *fh, |
---|
| 378 | + struct v4l2_selection *s) |
---|
388 | 379 | { |
---|
389 | 380 | struct fimc_ctx *ctx = fh_to_ctx(fh); |
---|
390 | 381 | struct fimc_frame *frame; |
---|
391 | 382 | |
---|
392 | | - frame = ctx_get_frame(ctx, cr->type); |
---|
| 383 | + frame = ctx_get_frame(ctx, s->type); |
---|
393 | 384 | if (IS_ERR(frame)) |
---|
394 | 385 | return PTR_ERR(frame); |
---|
395 | 386 | |
---|
396 | | - cr->bounds.left = 0; |
---|
397 | | - cr->bounds.top = 0; |
---|
398 | | - cr->bounds.width = frame->o_width; |
---|
399 | | - cr->bounds.height = frame->o_height; |
---|
400 | | - cr->defrect = cr->bounds; |
---|
| 387 | + switch (s->target) { |
---|
| 388 | + case V4L2_SEL_TGT_CROP: |
---|
| 389 | + case V4L2_SEL_TGT_CROP_DEFAULT: |
---|
| 390 | + case V4L2_SEL_TGT_CROP_BOUNDS: |
---|
| 391 | + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) |
---|
| 392 | + return -EINVAL; |
---|
| 393 | + break; |
---|
| 394 | + case V4L2_SEL_TGT_COMPOSE: |
---|
| 395 | + case V4L2_SEL_TGT_COMPOSE_DEFAULT: |
---|
| 396 | + case V4L2_SEL_TGT_COMPOSE_BOUNDS: |
---|
| 397 | + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
---|
| 398 | + return -EINVAL; |
---|
| 399 | + break; |
---|
| 400 | + default: |
---|
| 401 | + return -EINVAL; |
---|
| 402 | + } |
---|
401 | 403 | |
---|
| 404 | + switch (s->target) { |
---|
| 405 | + case V4L2_SEL_TGT_CROP: |
---|
| 406 | + case V4L2_SEL_TGT_COMPOSE: |
---|
| 407 | + s->r.left = frame->offs_h; |
---|
| 408 | + s->r.top = frame->offs_v; |
---|
| 409 | + s->r.width = frame->width; |
---|
| 410 | + s->r.height = frame->height; |
---|
| 411 | + break; |
---|
| 412 | + case V4L2_SEL_TGT_CROP_DEFAULT: |
---|
| 413 | + case V4L2_SEL_TGT_CROP_BOUNDS: |
---|
| 414 | + case V4L2_SEL_TGT_COMPOSE_DEFAULT: |
---|
| 415 | + case V4L2_SEL_TGT_COMPOSE_BOUNDS: |
---|
| 416 | + s->r.left = 0; |
---|
| 417 | + s->r.top = 0; |
---|
| 418 | + s->r.width = frame->o_width; |
---|
| 419 | + s->r.height = frame->o_height; |
---|
| 420 | + break; |
---|
| 421 | + default: |
---|
| 422 | + return -EINVAL; |
---|
| 423 | + } |
---|
402 | 424 | return 0; |
---|
403 | 425 | } |
---|
404 | 426 | |
---|
405 | | -static int fimc_m2m_g_crop(struct file *file, void *fh, struct v4l2_crop *cr) |
---|
406 | | -{ |
---|
407 | | - struct fimc_ctx *ctx = fh_to_ctx(fh); |
---|
408 | | - struct fimc_frame *frame; |
---|
409 | | - |
---|
410 | | - frame = ctx_get_frame(ctx, cr->type); |
---|
411 | | - if (IS_ERR(frame)) |
---|
412 | | - return PTR_ERR(frame); |
---|
413 | | - |
---|
414 | | - cr->c.left = frame->offs_h; |
---|
415 | | - cr->c.top = frame->offs_v; |
---|
416 | | - cr->c.width = frame->width; |
---|
417 | | - cr->c.height = frame->height; |
---|
418 | | - |
---|
419 | | - return 0; |
---|
420 | | -} |
---|
421 | | - |
---|
422 | | -static int fimc_m2m_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr) |
---|
| 427 | +static int fimc_m2m_try_selection(struct fimc_ctx *ctx, |
---|
| 428 | + struct v4l2_selection *s) |
---|
423 | 429 | { |
---|
424 | 430 | struct fimc_dev *fimc = ctx->fimc_dev; |
---|
425 | 431 | struct fimc_frame *f; |
---|
426 | 432 | u32 min_size, halign, depth = 0; |
---|
427 | 433 | int i; |
---|
428 | 434 | |
---|
429 | | - if (cr->c.top < 0 || cr->c.left < 0) { |
---|
| 435 | + if (s->r.top < 0 || s->r.left < 0) { |
---|
430 | 436 | v4l2_err(&fimc->m2m.vfd, |
---|
431 | 437 | "doesn't support negative values for top & left\n"); |
---|
432 | 438 | return -EINVAL; |
---|
433 | 439 | } |
---|
434 | | - if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) |
---|
| 440 | + if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { |
---|
435 | 441 | f = &ctx->d_frame; |
---|
436 | | - else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) |
---|
| 442 | + if (s->target != V4L2_SEL_TGT_COMPOSE) |
---|
| 443 | + return -EINVAL; |
---|
| 444 | + } else if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { |
---|
437 | 445 | f = &ctx->s_frame; |
---|
438 | | - else |
---|
| 446 | + if (s->target != V4L2_SEL_TGT_CROP) |
---|
| 447 | + return -EINVAL; |
---|
| 448 | + } else { |
---|
439 | 449 | return -EINVAL; |
---|
| 450 | + } |
---|
440 | 451 | |
---|
441 | 452 | min_size = (f == &ctx->s_frame) ? |
---|
442 | 453 | fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize; |
---|
.. | .. |
---|
450 | 461 | for (i = 0; i < f->fmt->memplanes; i++) |
---|
451 | 462 | depth += f->fmt->depth[i]; |
---|
452 | 463 | |
---|
453 | | - v4l_bound_align_image(&cr->c.width, min_size, f->o_width, |
---|
| 464 | + v4l_bound_align_image(&s->r.width, min_size, f->o_width, |
---|
454 | 465 | ffs(min_size) - 1, |
---|
455 | | - &cr->c.height, min_size, f->o_height, |
---|
| 466 | + &s->r.height, min_size, f->o_height, |
---|
456 | 467 | halign, 64/(ALIGN(depth, 8))); |
---|
457 | 468 | |
---|
458 | 469 | /* adjust left/top if cropping rectangle is out of bounds */ |
---|
459 | | - if (cr->c.left + cr->c.width > f->o_width) |
---|
460 | | - cr->c.left = f->o_width - cr->c.width; |
---|
461 | | - if (cr->c.top + cr->c.height > f->o_height) |
---|
462 | | - cr->c.top = f->o_height - cr->c.height; |
---|
| 470 | + if (s->r.left + s->r.width > f->o_width) |
---|
| 471 | + s->r.left = f->o_width - s->r.width; |
---|
| 472 | + if (s->r.top + s->r.height > f->o_height) |
---|
| 473 | + s->r.top = f->o_height - s->r.height; |
---|
463 | 474 | |
---|
464 | | - cr->c.left = round_down(cr->c.left, min_size); |
---|
465 | | - cr->c.top = round_down(cr->c.top, fimc->variant->hor_offs_align); |
---|
| 475 | + s->r.left = round_down(s->r.left, min_size); |
---|
| 476 | + s->r.top = round_down(s->r.top, fimc->variant->hor_offs_align); |
---|
466 | 477 | |
---|
467 | 478 | dbg("l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d", |
---|
468 | | - cr->c.left, cr->c.top, cr->c.width, cr->c.height, |
---|
| 479 | + s->r.left, s->r.top, s->r.width, s->r.height, |
---|
469 | 480 | f->f_width, f->f_height); |
---|
470 | 481 | |
---|
471 | 482 | return 0; |
---|
472 | 483 | } |
---|
473 | 484 | |
---|
474 | | -static int fimc_m2m_s_crop(struct file *file, void *fh, const struct v4l2_crop *crop) |
---|
| 485 | +static int fimc_m2m_s_selection(struct file *file, void *fh, |
---|
| 486 | + struct v4l2_selection *s) |
---|
475 | 487 | { |
---|
476 | 488 | struct fimc_ctx *ctx = fh_to_ctx(fh); |
---|
477 | 489 | struct fimc_dev *fimc = ctx->fimc_dev; |
---|
478 | | - struct v4l2_crop cr = *crop; |
---|
479 | 490 | struct fimc_frame *f; |
---|
480 | 491 | int ret; |
---|
481 | 492 | |
---|
482 | | - ret = fimc_m2m_try_crop(ctx, &cr); |
---|
| 493 | + ret = fimc_m2m_try_selection(ctx, s); |
---|
483 | 494 | if (ret) |
---|
484 | 495 | return ret; |
---|
485 | 496 | |
---|
486 | | - f = (cr.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ? |
---|
| 497 | + f = (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ? |
---|
487 | 498 | &ctx->s_frame : &ctx->d_frame; |
---|
488 | 499 | |
---|
489 | 500 | /* Check to see if scaling ratio is within supported range */ |
---|
490 | | - if (cr.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { |
---|
491 | | - ret = fimc_check_scaler_ratio(ctx, cr.c.width, |
---|
492 | | - cr.c.height, ctx->d_frame.width, |
---|
| 501 | + if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { |
---|
| 502 | + ret = fimc_check_scaler_ratio(ctx, s->r.width, |
---|
| 503 | + s->r.height, ctx->d_frame.width, |
---|
493 | 504 | ctx->d_frame.height, ctx->rotation); |
---|
494 | 505 | } else { |
---|
495 | 506 | ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width, |
---|
496 | | - ctx->s_frame.height, cr.c.width, |
---|
497 | | - cr.c.height, ctx->rotation); |
---|
| 507 | + ctx->s_frame.height, s->r.width, |
---|
| 508 | + s->r.height, ctx->rotation); |
---|
498 | 509 | } |
---|
499 | 510 | if (ret) { |
---|
500 | 511 | v4l2_err(&fimc->m2m.vfd, "Out of scaler range\n"); |
---|
501 | 512 | return -EINVAL; |
---|
502 | 513 | } |
---|
503 | 514 | |
---|
504 | | - f->offs_h = cr.c.left; |
---|
505 | | - f->offs_v = cr.c.top; |
---|
506 | | - f->width = cr.c.width; |
---|
507 | | - f->height = cr.c.height; |
---|
| 515 | + f->offs_h = s->r.left; |
---|
| 516 | + f->offs_v = s->r.top; |
---|
| 517 | + f->width = s->r.width; |
---|
| 518 | + f->height = s->r.height; |
---|
508 | 519 | |
---|
509 | 520 | fimc_ctx_state_set(FIMC_PARAMS, ctx); |
---|
510 | 521 | |
---|
.. | .. |
---|
513 | 524 | |
---|
514 | 525 | static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = { |
---|
515 | 526 | .vidioc_querycap = fimc_m2m_querycap, |
---|
516 | | - .vidioc_enum_fmt_vid_cap_mplane = fimc_m2m_enum_fmt_mplane, |
---|
517 | | - .vidioc_enum_fmt_vid_out_mplane = fimc_m2m_enum_fmt_mplane, |
---|
| 527 | + .vidioc_enum_fmt_vid_cap = fimc_m2m_enum_fmt, |
---|
| 528 | + .vidioc_enum_fmt_vid_out = fimc_m2m_enum_fmt, |
---|
518 | 529 | .vidioc_g_fmt_vid_cap_mplane = fimc_m2m_g_fmt_mplane, |
---|
519 | 530 | .vidioc_g_fmt_vid_out_mplane = fimc_m2m_g_fmt_mplane, |
---|
520 | 531 | .vidioc_try_fmt_vid_cap_mplane = fimc_m2m_try_fmt_mplane, |
---|
.. | .. |
---|
528 | 539 | .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, |
---|
529 | 540 | .vidioc_streamon = v4l2_m2m_ioctl_streamon, |
---|
530 | 541 | .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, |
---|
531 | | - .vidioc_g_crop = fimc_m2m_g_crop, |
---|
532 | | - .vidioc_s_crop = fimc_m2m_s_crop, |
---|
533 | | - .vidioc_cropcap = fimc_m2m_cropcap |
---|
| 542 | + .vidioc_g_selection = fimc_m2m_g_selection, |
---|
| 543 | + .vidioc_s_selection = fimc_m2m_s_selection, |
---|
534 | 544 | |
---|
535 | 545 | }; |
---|
536 | 546 | |
---|
.. | .. |
---|
717 | 727 | vfd->release = video_device_release_empty; |
---|
718 | 728 | vfd->lock = &fimc->lock; |
---|
719 | 729 | vfd->vfl_dir = VFL_DIR_M2M; |
---|
| 730 | + vfd->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE; |
---|
| 731 | + set_bit(V4L2_FL_QUIRK_INVERTED_CROP, &vfd->flags); |
---|
720 | 732 | |
---|
721 | 733 | snprintf(vfd->name, sizeof(vfd->name), "fimc.%d.m2m", fimc->id); |
---|
722 | 734 | video_set_drvdata(vfd, fimc); |
---|
.. | .. |
---|
731 | 743 | if (ret) |
---|
732 | 744 | goto err_me; |
---|
733 | 745 | |
---|
734 | | - ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); |
---|
| 746 | + ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1); |
---|
735 | 747 | if (ret) |
---|
736 | 748 | goto err_vd; |
---|
737 | 749 | |
---|