aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSylwester Nawrocki <s.nawrocki@samsung.com>2011-08-24 19:35:30 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-09-06 16:48:45 -0400
commit237e026559b7cd03fc575b6007cea11aef9e0aa6 (patch)
tree0d810b1d4a52973c497682fec2c9b817ecfca19e
parent4db5e27ed9401a635b3c10994f2971c0441e3c90 (diff)
[media] s5p-fimc: Add subdev for the FIMC processing block
Add a subdev to expose the host's scaling and composition functions. The camera frame composition onto an output buffer may be configured through set/get_crop at FIMC.{n} source pad. Additionally allow crop, composition and controls to be modified during streaming. Make sure the default format is set when opening the video capture node. Rename struct fimc_vid_cap::fmt to more relevant 'mf' to avoid confusion. Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/video/s5p-fimc/fimc-capture.c734
-rw-r--r--drivers/media/video/s5p-fimc/fimc-core.c30
-rw-r--r--drivers/media/video/s5p-fimc/fimc-core.h53
-rw-r--r--drivers/media/video/s5p-fimc/fimc-mdevice.c47
-rw-r--r--drivers/media/video/s5p-fimc/fimc-reg.c8
5 files changed, 751 insertions, 121 deletions
diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c
index f0fed6124dc0..62fd8a17fd5f 100644
--- a/drivers/media/video/s5p-fimc/fimc-capture.c
+++ b/drivers/media/video/s5p-fimc/fimc-capture.c
@@ -63,6 +63,7 @@ static int fimc_init_capture(struct fimc_dev *fimc)
63 fimc_hw_set_effect(ctx); 63 fimc_hw_set_effect(ctx);
64 fimc_hw_set_output_path(ctx); 64 fimc_hw_set_output_path(ctx);
65 fimc_hw_set_out_dma(ctx); 65 fimc_hw_set_out_dma(ctx);
66 clear_bit(ST_CAPT_APPLY_CFG, &fimc->state);
66 } 67 }
67 spin_unlock_irqrestore(&fimc->slock, flags); 68 spin_unlock_irqrestore(&fimc->slock, flags);
68 return ret; 69 return ret;
@@ -120,6 +121,36 @@ static int fimc_stop_capture(struct fimc_dev *fimc)
120 return fimc_capture_state_cleanup(fimc); 121 return fimc_capture_state_cleanup(fimc);
121} 122}
122 123
124/**
125 * fimc_capture_config_update - apply the camera interface configuration
126 *
127 * To be called from within the interrupt handler with fimc.slock
128 * spinlock held. It updates the camera pixel crop, rotation and
129 * image flip in H/W.
130 */
131int fimc_capture_config_update(struct fimc_ctx *ctx)
132{
133 struct fimc_dev *fimc = ctx->fimc_dev;
134 int ret;
135
136 if (test_bit(ST_CAPT_APPLY_CFG, &fimc->state))
137 return 0;
138
139 spin_lock(&ctx->slock);
140 fimc_hw_set_camera_offset(fimc, &ctx->s_frame);
141 ret = fimc_set_scaler_info(ctx);
142 if (ret == 0) {
143 fimc_hw_set_prescaler(ctx);
144 fimc_hw_set_mainscaler(ctx);
145 fimc_hw_set_target_format(ctx);
146 fimc_hw_set_rotation(ctx);
147 fimc_prepare_dma_offset(ctx, &ctx->d_frame);
148 fimc_hw_set_out_dma(ctx);
149 set_bit(ST_CAPT_APPLY_CFG, &fimc->state);
150 }
151 spin_unlock(&ctx->slock);
152 return ret;
153}
123 154
124static int start_streaming(struct vb2_queue *q, unsigned int count) 155static int start_streaming(struct vb2_queue *q, unsigned int count)
125{ 156{
@@ -319,6 +350,8 @@ int fimc_capture_ctrls_create(struct fimc_dev *fimc)
319 fimc->pipeline.sensor->ctrl_handler); 350 fimc->pipeline.sensor->ctrl_handler);
320} 351}
321 352
353static int fimc_capture_set_default_format(struct fimc_dev *fimc);
354
322static int fimc_capture_open(struct file *file) 355static int fimc_capture_open(struct file *file)
323{ 356{
324 struct fimc_dev *fimc = video_drvdata(file); 357 struct fimc_dev *fimc = video_drvdata(file);
@@ -347,6 +380,9 @@ static int fimc_capture_open(struct file *file)
347 return ret; 380 return ret;
348 } 381 }
349 ret = fimc_capture_ctrls_create(fimc); 382 ret = fimc_capture_ctrls_create(fimc);
383
384 if (!ret && !fimc->vid_cap.user_subdev_api)
385 ret = fimc_capture_set_default_format(fimc);
350 } 386 }
351 return ret; 387 return ret;
352} 388}
@@ -384,7 +420,6 @@ static int fimc_capture_mmap(struct file *file, struct vm_area_struct *vma)
384 return vb2_mmap(&fimc->vid_cap.vbq, vma); 420 return vb2_mmap(&fimc->vid_cap.vbq, vma);
385} 421}
386 422
387/* video device file operations */
388static const struct v4l2_file_operations fimc_capture_fops = { 423static const struct v4l2_file_operations fimc_capture_fops = {
389 .owner = THIS_MODULE, 424 .owner = THIS_MODULE,
390 .open = fimc_capture_open, 425 .open = fimc_capture_open,
@@ -394,6 +429,147 @@ static const struct v4l2_file_operations fimc_capture_fops = {
394 .mmap = fimc_capture_mmap, 429 .mmap = fimc_capture_mmap,
395}; 430};
396 431
432/*
433 * Format and crop negotiation helpers
434 */
435
436static struct fimc_fmt *fimc_capture_try_format(struct fimc_ctx *ctx,
437 u32 *width, u32 *height,
438 u32 *code, u32 *fourcc, int pad)
439{
440 bool rotation = ctx->rotation == 90 || ctx->rotation == 270;
441 struct fimc_dev *fimc = ctx->fimc_dev;
442 struct samsung_fimc_variant *var = fimc->variant;
443 struct fimc_pix_limit *pl = var->pix_limit;
444 struct fimc_frame *dst = &ctx->d_frame;
445 u32 depth, min_w, max_w, min_h, align_h = 3;
446 u32 mask = FMT_FLAGS_CAM;
447 struct fimc_fmt *ffmt;
448
449 /* Color conversion from/to JPEG is not supported */
450 if (code && ctx->s_frame.fmt && pad == FIMC_SD_PAD_SOURCE &&
451 fimc_fmt_is_jpeg(ctx->s_frame.fmt->color))
452 *code = V4L2_MBUS_FMT_JPEG_1X8;
453
454 if (fourcc && *fourcc != V4L2_PIX_FMT_JPEG && pad != FIMC_SD_PAD_SINK)
455 mask |= FMT_FLAGS_M2M;
456
457 ffmt = fimc_find_format(fourcc, code, mask, 0);
458 if (WARN_ON(!ffmt))
459 return NULL;
460 if (code)
461 *code = ffmt->mbus_code;
462 if (fourcc)
463 *fourcc = ffmt->fourcc;
464
465 if (pad == FIMC_SD_PAD_SINK) {
466 max_w = fimc_fmt_is_jpeg(ffmt->color) ?
467 pl->scaler_dis_w : pl->scaler_en_w;
468 /* Apply the camera input interface pixel constraints */
469 v4l_bound_align_image(width, max_t(u32, *width, 32), max_w, 4,
470 height, max_t(u32, *height, 32),
471 FIMC_CAMIF_MAX_HEIGHT,
472 fimc_fmt_is_jpeg(ffmt->color) ? 3 : 1,
473 0);
474 return ffmt;
475 }
476 /* Can't scale or crop in transparent (JPEG) transfer mode */
477 if (fimc_fmt_is_jpeg(ffmt->color)) {
478 *width = ctx->s_frame.f_width;
479 *height = ctx->s_frame.f_height;
480 return ffmt;
481 }
482 /* Apply the scaler and the output DMA constraints */
483 max_w = rotation ? pl->out_rot_en_w : pl->out_rot_dis_w;
484 min_w = ctx->state & FIMC_DST_CROP ? dst->width : var->min_out_pixsize;
485 min_h = ctx->state & FIMC_DST_CROP ? dst->height : var->min_out_pixsize;
486 if (fimc->id == 1 && var->pix_hoff)
487 align_h = fimc_fmt_is_rgb(ffmt->color) ? 0 : 1;
488
489 depth = fimc_get_format_depth(ffmt);
490 v4l_bound_align_image(width, min_w, max_w,
491 ffs(var->min_out_pixsize) - 1,
492 height, min_h, FIMC_CAMIF_MAX_HEIGHT,
493 align_h,
494 64/(ALIGN(depth, 8)));
495
496 dbg("pad%d: code: 0x%x, %dx%d. dst fmt: %dx%d",
497 pad, code ? *code : 0, *width, *height,
498 dst->f_width, dst->f_height);
499
500 return ffmt;
501}
502
503static void fimc_capture_try_crop(struct fimc_ctx *ctx, struct v4l2_rect *r,
504 int pad)
505{
506 bool rotate = ctx->rotation == 90 || ctx->rotation == 270;
507 struct fimc_dev *fimc = ctx->fimc_dev;
508 struct samsung_fimc_variant *var = fimc->variant;
509 struct fimc_pix_limit *pl = var->pix_limit;
510 struct fimc_frame *sink = &ctx->s_frame;
511 u32 max_w, max_h, min_w = 0, min_h = 0, min_sz;
512 u32 align_sz = 0, align_h = 4;
513 u32 max_sc_h, max_sc_v;
514
515 /* In JPEG transparent transfer mode cropping is not supported */
516 if (fimc_fmt_is_jpeg(ctx->d_frame.fmt->color)) {
517 r->width = sink->f_width;
518 r->height = sink->f_height;
519 r->left = r->top = 0;
520 return;
521 }
522 if (pad == FIMC_SD_PAD_SOURCE) {
523 if (ctx->rotation != 90 && ctx->rotation != 270)
524 align_h = 1;
525 max_sc_h = min(SCALER_MAX_HRATIO, 1 << (ffs(sink->width) - 3));
526 max_sc_v = min(SCALER_MAX_VRATIO, 1 << (ffs(sink->height) - 1));
527 min_sz = var->min_out_pixsize;
528 } else {
529 u32 depth = fimc_get_format_depth(sink->fmt);
530 align_sz = 64/ALIGN(depth, 8);
531 min_sz = var->min_inp_pixsize;
532 min_w = min_h = min_sz;
533 max_sc_h = max_sc_v = 1;
534 }
535 /*
536 * For the crop rectangle at source pad the following constraints
537 * must be met:
538 * - it must fit in the sink pad format rectangle (f_width/f_height);
539 * - maximum downscaling ratio is 64;
540 * - maximum crop size depends if the rotator is used or not;
541 * - the sink pad format width/height must be 4 multiple of the
542 * prescaler ratios determined by sink pad size and source pad crop,
543 * the prescaler ratio is returned by fimc_get_scaler_factor().
544 */
545 max_w = min_t(u32,
546 rotate ? pl->out_rot_en_w : pl->out_rot_dis_w,
547 rotate ? sink->f_height : sink->f_width);
548 max_h = min_t(u32, FIMC_CAMIF_MAX_HEIGHT, sink->f_height);
549 if (pad == FIMC_SD_PAD_SOURCE) {
550 min_w = min_t(u32, max_w, sink->f_width / max_sc_h);
551 min_h = min_t(u32, max_h, sink->f_height / max_sc_v);
552 if (rotate) {
553 swap(max_sc_h, max_sc_v);
554 swap(min_w, min_h);
555 }
556 }
557 v4l_bound_align_image(&r->width, min_w, max_w, ffs(min_sz) - 1,
558 &r->height, min_h, max_h, align_h,
559 align_sz);
560 /* Adjust left/top if cropping rectangle is out of bounds */
561 r->left = clamp_t(u32, r->left, 0, sink->f_width - r->width);
562 r->top = clamp_t(u32, r->top, 0, sink->f_height - r->height);
563 r->left = round_down(r->left, var->hor_offs_align);
564
565 dbg("pad%d: (%d,%d)/%dx%d, sink fmt: %dx%d",
566 pad, r->left, r->top, r->width, r->height,
567 sink->f_width, sink->f_height);
568}
569
570/*
571 * The video node ioctl operations
572 */
397static int fimc_vidioc_querycap_capture(struct file *file, void *priv, 573static int fimc_vidioc_querycap_capture(struct file *file, void *priv,
398 struct v4l2_capability *cap) 574 struct v4l2_capability *cap)
399{ 575{
@@ -424,11 +600,81 @@ static int fimc_cap_enum_fmt_mplane(struct file *file, void *priv,
424 return 0; 600 return 0;
425} 601}
426 602
603/**
604 * fimc_pipeline_try_format - negotiate and/or set formats at pipeline
605 * elements
606 * @ctx: FIMC capture context
607 * @tfmt: media bus format to try/set on subdevs
608 * @fmt_id: fimc pixel format id corresponding to returned @tfmt (output)
609 * @set: true to set format on subdevs, false to try only
610 */
611static int fimc_pipeline_try_format(struct fimc_ctx *ctx,
612 struct v4l2_mbus_framefmt *tfmt,
613 struct fimc_fmt **fmt_id,
614 bool set)
615{
616 struct fimc_dev *fimc = ctx->fimc_dev;
617 struct v4l2_subdev *sd = fimc->pipeline.sensor;
618 struct v4l2_subdev *csis = fimc->pipeline.csis;
619 struct v4l2_subdev_format sfmt;
620 struct v4l2_mbus_framefmt *mf = &sfmt.format;
621 struct fimc_fmt *ffmt = NULL;
622 int ret, i = 0;
623
624 if (WARN_ON(!sd || !tfmt))
625 return -EINVAL;
427 626
627 memset(&sfmt, 0, sizeof(sfmt));
628 sfmt.format = *tfmt;
629
630 sfmt.which = set ? V4L2_SUBDEV_FORMAT_ACTIVE : V4L2_SUBDEV_FORMAT_TRY;
631 while (1) {
632 ffmt = fimc_find_format(NULL, mf->code != 0 ? &mf->code : NULL,
633 FMT_FLAGS_CAM, i++);
634 if (ffmt == NULL) {
635 /*
636 * Notify user-space if common pixel code for
637 * host and sensor does not exist.
638 */
639 return -EINVAL;
640 }
641 mf->code = tfmt->code = ffmt->mbus_code;
428 642
643 ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &sfmt);
644 if (ret)
645 return ret;
646 if (mf->code != tfmt->code) {
647 mf->code = 0;
648 continue;
649 }
650 if (mf->width != tfmt->width || mf->width != tfmt->width) {
651 u32 fcc = ffmt->fourcc;
652 tfmt->width = mf->width;
653 tfmt->height = mf->height;
654 ffmt = fimc_capture_try_format(ctx,
655 &tfmt->width, &tfmt->height,
656 NULL, &fcc, FIMC_SD_PAD_SOURCE);
657 if (ffmt && ffmt->mbus_code)
658 mf->code = ffmt->mbus_code;
659 if (mf->width != tfmt->width || mf->width != tfmt->width)
660 continue;
661 tfmt->code = mf->code;
662 }
663 if (csis)
664 ret = v4l2_subdev_call(csis, pad, set_fmt, NULL, &sfmt);
429 665
666 if (mf->code == tfmt->code &&
667 mf->width == tfmt->width && mf->width == tfmt->width)
668 break;
669 }
430 670
671 if (fmt_id && ffmt)
672 *fmt_id = ffmt;
673 *tfmt = *mf;
431 674
675 dbg("code: 0x%x, %dx%d, %p", mf->code, mf->width, mf->height, ffmt);
676 return 0;
677}
432 678
433static int fimc_cap_g_fmt_mplane(struct file *file, void *fh, 679static int fimc_cap_g_fmt_mplane(struct file *file, void *fh,
434 struct v4l2_format *f) 680 struct v4l2_format *f)
@@ -445,55 +691,114 @@ static int fimc_cap_g_fmt_mplane(struct file *file, void *fh,
445static int fimc_cap_try_fmt_mplane(struct file *file, void *fh, 691static int fimc_cap_try_fmt_mplane(struct file *file, void *fh,
446 struct v4l2_format *f) 692 struct v4l2_format *f)
447{ 693{
694 struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
448 struct fimc_dev *fimc = video_drvdata(file); 695 struct fimc_dev *fimc = video_drvdata(file);
449 struct fimc_ctx *ctx = fimc->vid_cap.ctx; 696 struct fimc_ctx *ctx = fimc->vid_cap.ctx;
697 struct v4l2_mbus_framefmt mf;
698 struct fimc_fmt *ffmt = NULL;
699
700 if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
701 return -EINVAL;
702
703 if (pix->pixelformat == V4L2_PIX_FMT_JPEG) {
704 fimc_capture_try_format(ctx, &pix->width, &pix->height,
705 NULL, &pix->pixelformat,
706 FIMC_SD_PAD_SINK);
707 ctx->s_frame.f_width = pix->width;
708 ctx->s_frame.f_height = pix->height;
709 }
710 ffmt = fimc_capture_try_format(ctx, &pix->width, &pix->height,
711 NULL, &pix->pixelformat,
712 FIMC_SD_PAD_SOURCE);
713 if (!ffmt)
714 return -EINVAL;
715
716 if (!fimc->vid_cap.user_subdev_api) {
717 mf.width = pix->width;
718 mf.height = pix->height;
719 mf.code = ffmt->mbus_code;
720 fimc_md_graph_lock(fimc);
721 fimc_pipeline_try_format(ctx, &mf, &ffmt, false);
722 fimc_md_graph_unlock(fimc);
723
724 pix->width = mf.width;
725 pix->height = mf.height;
726 if (ffmt)
727 pix->pixelformat = ffmt->fourcc;
728 }
450 729
730 fimc_adjust_mplane_format(ffmt, pix->width, pix->height, pix);
451 return 0; 731 return 0;
452} 732}
453 733
454static int fimc_cap_s_fmt_mplane(struct file *file, void *priv, 734static int fimc_capture_set_format(struct fimc_dev *fimc, struct v4l2_format *f)
455 struct v4l2_format *f)
456{ 735{
457 struct fimc_dev *fimc = video_drvdata(file);
458 struct fimc_ctx *ctx = fimc->vid_cap.ctx; 736 struct fimc_ctx *ctx = fimc->vid_cap.ctx;
459 struct v4l2_pix_format_mplane *pix; 737 struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
460 struct fimc_frame *frame; 738 struct v4l2_mbus_framefmt *mf = &fimc->vid_cap.mf;
461 int ret; 739 struct fimc_frame *ff = &ctx->d_frame;
462 int i; 740 struct fimc_fmt *s_fmt = NULL;
741 int ret, i;
463 742
464 if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) 743 if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
465 return -EINVAL; 744 return -EINVAL;
466 745 if (vb2_is_busy(&fimc->vid_cap.vbq))
467 if (vb2_is_busy(&fimc->vid_cap.vbq) || fimc_capture_active(fimc))
468 return -EBUSY; 746 return -EBUSY;
469 747
470 frame = &ctx->d_frame; 748 /* Pre-configure format at camera interface input, for JPEG only */
471 749 if (pix->pixelformat == V4L2_PIX_FMT_JPEG) {
472 pix = &f->fmt.pix_mp; 750 fimc_capture_try_format(ctx, &pix->width, &pix->height,
473 frame->fmt = fimc_find_format(&pix->pixelformat, NULL, 751 NULL, &pix->pixelformat,
474 FMT_FLAGS_M2M | FMT_FLAGS_CAM, 0); 752 FIMC_SD_PAD_SINK);
475 if (WARN(frame->fmt == NULL, "Pixel format lookup failed\n")) 753 ctx->s_frame.f_width = pix->width;
754 ctx->s_frame.f_height = pix->height;
755 }
756 /* Try the format at the scaler and the DMA output */
757 ff->fmt = fimc_capture_try_format(ctx, &pix->width, &pix->height,
758 NULL, &pix->pixelformat,
759 FIMC_SD_PAD_SOURCE);
760 if (!ff->fmt)
476 return -EINVAL; 761 return -EINVAL;
477 762 /* Try to match format at the host and the sensor */
478 for (i = 0; i < frame->fmt->colplanes; i++) { 763 if (!fimc->vid_cap.user_subdev_api) {
479 frame->payload[i] = 764 mf->code = ff->fmt->mbus_code;
480 (pix->width * pix->height * frame->fmt->depth[i]) >> 3; 765 mf->width = pix->width;
766 mf->height = pix->height;
767
768 fimc_md_graph_lock(fimc);
769 ret = fimc_pipeline_try_format(ctx, mf, &s_fmt, true);
770 fimc_md_graph_unlock(fimc);
771 if (ret)
772 return ret;
773 pix->width = mf->width;
774 pix->height = mf->height;
775 }
776 fimc_adjust_mplane_format(ff->fmt, pix->width, pix->height, pix);
777 for (i = 0; i < ff->fmt->colplanes; i++)
778 ff->payload[i] =
779 (pix->width * pix->height * ff->fmt->depth[i]) / 8;
780
781 set_frame_bounds(ff, pix->width, pix->height);
782 /* Reset the composition rectangle if not yet configured */
783 if (!(ctx->state & FIMC_DST_CROP))
784 set_frame_crop(ff, 0, 0, pix->width, pix->height);
785
786 /* Reset cropping and set format at the camera interface input */
787 if (!fimc->vid_cap.user_subdev_api) {
788 ctx->s_frame.fmt = s_fmt;
789 set_frame_bounds(&ctx->s_frame, pix->width, pix->height);
790 set_frame_crop(&ctx->s_frame, 0, 0, pix->width, pix->height);
481 } 791 }
482 792
483 /* Output DMA frame pixel size and offsets. */ 793 return ret;
484 frame->f_width = pix->plane_fmt[0].bytesperline * 8 794}
485 / frame->fmt->depth[0];
486 frame->f_height = pix->height;
487 frame->width = pix->width;
488 frame->height = pix->height;
489 frame->o_width = pix->width;
490 frame->o_height = pix->height;
491 frame->offs_h = 0;
492 frame->offs_v = 0;
493 795
494 ctx->state |= (FIMC_PARAMS | FIMC_DST_FMT); 796static int fimc_cap_s_fmt_mplane(struct file *file, void *priv,
797 struct v4l2_format *f)
798{
799 struct fimc_dev *fimc = video_drvdata(file);
495 800
496 return ret; 801 return fimc_capture_set_format(fimc, f);
497} 802}
498 803
499static int fimc_cap_enum_input(struct file *file, void *priv, 804static int fimc_cap_enum_input(struct file *file, void *priv,
@@ -522,22 +827,83 @@ static int fimc_cap_g_input(struct file *file, void *priv, unsigned int *i)
522 return 0; 827 return 0;
523} 828}
524 829
830/**
831 * fimc_pipeline_validate - check for formats inconsistencies
832 * between source and sink pad of each link
833 *
834 * Return 0 if all formats match or -EPIPE otherwise.
835 */
836static int fimc_pipeline_validate(struct fimc_dev *fimc)
837{
838 struct v4l2_subdev_format sink_fmt, src_fmt;
839 struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
840 struct v4l2_subdev *sd;
841 struct media_pad *pad;
842 int ret;
843
844 /* Start with the video capture node pad */
845 pad = media_entity_remote_source(&vid_cap->vd_pad);
846 if (pad == NULL)
847 return -EPIPE;
848 /* FIMC.{N} subdevice */
849 sd = media_entity_to_v4l2_subdev(pad->entity);
850
851 while (1) {
852 /* Retrieve format at the sink pad */
853 pad = &sd->entity.pads[0];
854 if (!(pad->flags & MEDIA_PAD_FL_SINK))
855 break;
856 /* Don't call FIMC subdev operation to avoid nested locking */
857 if (sd == fimc->vid_cap.subdev) {
858 struct fimc_frame *ff = &vid_cap->ctx->s_frame;
859 sink_fmt.format.width = ff->f_width;
860 sink_fmt.format.height = ff->f_height;
861 sink_fmt.format.code = ff->fmt ? ff->fmt->mbus_code : 0;
862 } else {
863 sink_fmt.pad = pad->index;
864 sink_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
865 ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sink_fmt);
866 if (ret < 0 && ret != -ENOIOCTLCMD)
867 return -EPIPE;
868 }
869 /* Retrieve format at the source pad */
870 pad = media_entity_remote_source(pad);
871 if (pad == NULL ||
872 media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
873 break;
874
875 sd = media_entity_to_v4l2_subdev(pad->entity);
876 src_fmt.pad = pad->index;
877 src_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
878 ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &src_fmt);
879 if (ret < 0 && ret != -ENOIOCTLCMD)
880 return -EPIPE;
881
882 if (src_fmt.format.width != sink_fmt.format.width ||
883 src_fmt.format.height != sink_fmt.format.height ||
884 src_fmt.format.code != sink_fmt.format.code)
885 return -EPIPE;
886 }
887 return 0;
888}
889
525static int fimc_cap_streamon(struct file *file, void *priv, 890static int fimc_cap_streamon(struct file *file, void *priv,
526 enum v4l2_buf_type type) 891 enum v4l2_buf_type type)
527{ 892{
528 struct fimc_dev *fimc = video_drvdata(file); 893 struct fimc_dev *fimc = video_drvdata(file);
529 struct fimc_ctx *ctx = fimc->vid_cap.ctx;
530 struct fimc_pipeline *p = &fimc->pipeline; 894 struct fimc_pipeline *p = &fimc->pipeline;
895 int ret;
531 896
532 if (fimc_capture_active(fimc)) 897 if (fimc_capture_active(fimc))
533 return -EBUSY; 898 return -EBUSY;
534 899
535 if (!(ctx->state & FIMC_DST_FMT)) {
536 v4l2_err(fimc->vid_cap.vfd, "Format is not set\n");
537 return -EINVAL;
538 }
539 media_entity_pipeline_start(&p->sensor->entity, p->pipe); 900 media_entity_pipeline_start(&p->sensor->entity, p->pipe);
540 901
902 if (fimc->vid_cap.user_subdev_api) {
903 ret = fimc_pipeline_validate(fimc);
904 if (ret)
905 return ret;
906 }
541 return vb2_streamon(&fimc->vid_cap.vbq, type); 907 return vb2_streamon(&fimc->vid_cap.vbq, type);
542} 908}
543 909
@@ -624,35 +990,16 @@ static int fimc_cap_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
624{ 990{
625 struct fimc_dev *fimc = video_drvdata(file); 991 struct fimc_dev *fimc = video_drvdata(file);
626 struct fimc_ctx *ctx = fimc->vid_cap.ctx; 992 struct fimc_ctx *ctx = fimc->vid_cap.ctx;
627 struct fimc_frame *f; 993 struct fimc_frame *ff;
628 int ret = -EINVAL; 994 unsigned long flags;
629
630 if (fimc_capture_active(fimc))
631 return -EBUSY;
632
633 ret = fimc_try_crop(ctx, cr);
634 if (ret)
635 return ret;
636
637 if (!(ctx->state & FIMC_DST_FMT)) {
638 v4l2_err(fimc->vid_cap.vfd, "Capture format is not set\n");
639 return -EINVAL;
640 }
641 995
642 f = &ctx->s_frame; 996 fimc_capture_try_crop(ctx, &cr->c, FIMC_SD_PAD_SINK);
643 /* Check for the pixel scaling ratio when cropping input image. */ 997 ff = &ctx->s_frame;
644 ret = fimc_check_scaler_ratio(cr->c.width, cr->c.height,
645 ctx->d_frame.width, ctx->d_frame.height,
646 ctx->rotation);
647 if (ret) {
648 v4l2_err(fimc->vid_cap.vfd, "Out of the scaler range\n");
649 return ret;
650 }
651 998
652 f->offs_h = cr->c.left; 999 spin_lock_irqsave(&fimc->slock, flags);
653 f->offs_v = cr->c.top; 1000 set_frame_crop(ff, cr->c.left, cr->c.top, cr->c.width, cr->c.height);
654 f->width = cr->c.width; 1001 set_bit(ST_CAPT_APPLY_CFG, &fimc->state);
655 f->height = cr->c.height; 1002 spin_unlock_irqrestore(&fimc->slock, flags);
656 1003
657 return 0; 1004 return 0;
658} 1005}
@@ -683,14 +1030,16 @@ static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = {
683 .vidioc_g_input = fimc_cap_g_input, 1030 .vidioc_g_input = fimc_cap_g_input,
684}; 1031};
685 1032
686/* Media operations */ 1033/* Capture subdev media entity operations */
687static int fimc_link_setup(struct media_entity *entity, 1034static int fimc_link_setup(struct media_entity *entity,
688 const struct media_pad *local, 1035 const struct media_pad *local,
689 const struct media_pad *remote, u32 flags) 1036 const struct media_pad *remote, u32 flags)
690{ 1037{
691 struct video_device *vd = media_entity_to_video_device(entity); 1038 struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
692 struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(remote->entity); 1039 struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
693 struct fimc_dev *fimc = video_get_drvdata(vd); 1040
1041 if (media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
1042 return -EINVAL;
694 1043
695 if (WARN_ON(fimc == NULL)) 1044 if (WARN_ON(fimc == NULL))
696 return 0; 1045 return 0;
@@ -710,10 +1059,241 @@ static int fimc_link_setup(struct media_entity *entity,
710 return 0; 1059 return 0;
711} 1060}
712 1061
713static const struct media_entity_operations fimc_media_ops = { 1062static const struct media_entity_operations fimc_sd_media_ops = {
714 .link_setup = fimc_link_setup, 1063 .link_setup = fimc_link_setup,
715}; 1064};
716 1065
1066static int fimc_subdev_enum_mbus_code(struct v4l2_subdev *sd,
1067 struct v4l2_subdev_fh *fh,
1068 struct v4l2_subdev_mbus_code_enum *code)
1069{
1070 struct fimc_fmt *fmt;
1071
1072 fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_CAM, code->index);
1073 if (!fmt)
1074 return -EINVAL;
1075 code->code = fmt->mbus_code;
1076 return 0;
1077}
1078
1079static int fimc_subdev_get_fmt(struct v4l2_subdev *sd,
1080 struct v4l2_subdev_fh *fh,
1081 struct v4l2_subdev_format *fmt)
1082{
1083 struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
1084 struct fimc_ctx *ctx = fimc->vid_cap.ctx;
1085 struct v4l2_mbus_framefmt *mf;
1086 struct fimc_frame *ff;
1087
1088 if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
1089 mf = v4l2_subdev_get_try_format(fh, fmt->pad);
1090 fmt->format = *mf;
1091 return 0;
1092 }
1093 mf = &fmt->format;
1094 mf->colorspace = V4L2_COLORSPACE_JPEG;
1095 ff = fmt->pad == FIMC_SD_PAD_SINK ? &ctx->s_frame : &ctx->d_frame;
1096
1097 mutex_lock(&fimc->lock);
1098 /* The pixel code is same on both input and output pad */
1099 if (!WARN_ON(ctx->s_frame.fmt == NULL))
1100 mf->code = ctx->s_frame.fmt->mbus_code;
1101 mf->width = ff->f_width;
1102 mf->height = ff->f_height;
1103 mutex_unlock(&fimc->lock);
1104
1105 return 0;
1106}
1107
1108static int fimc_subdev_set_fmt(struct v4l2_subdev *sd,
1109 struct v4l2_subdev_fh *fh,
1110 struct v4l2_subdev_format *fmt)
1111{
1112 struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
1113 struct v4l2_mbus_framefmt *mf = &fmt->format;
1114 struct fimc_ctx *ctx = fimc->vid_cap.ctx;
1115 struct fimc_frame *ff;
1116 struct fimc_fmt *ffmt;
1117
1118 dbg("pad%d: code: 0x%x, %dx%d",
1119 fmt->pad, mf->code, mf->width, mf->height);
1120
1121 if (fmt->pad == FIMC_SD_PAD_SOURCE &&
1122 vb2_is_busy(&fimc->vid_cap.vbq))
1123 return -EBUSY;
1124
1125 mutex_lock(&fimc->lock);
1126 ffmt = fimc_capture_try_format(ctx, &mf->width, &mf->height,
1127 &mf->code, NULL, fmt->pad);
1128 mutex_unlock(&fimc->lock);
1129 mf->colorspace = V4L2_COLORSPACE_JPEG;
1130
1131 if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
1132 mf = v4l2_subdev_get_try_format(fh, fmt->pad);
1133 *mf = fmt->format;
1134 return 0;
1135 }
1136 ff = fmt->pad == FIMC_SD_PAD_SINK ?
1137 &ctx->s_frame : &ctx->d_frame;
1138
1139 mutex_lock(&fimc->lock);
1140 set_frame_bounds(ff, mf->width, mf->height);
1141 ff->fmt = ffmt;
1142
1143 /* Reset the crop rectangle if required. */
1144 if (!(fmt->pad == FIMC_SD_PAD_SOURCE && (ctx->state & FIMC_DST_CROP)))
1145 set_frame_crop(ff, 0, 0, mf->width, mf->height);
1146
1147 if (fmt->pad == FIMC_SD_PAD_SINK)
1148 ctx->state &= ~FIMC_DST_CROP;
1149 mutex_unlock(&fimc->lock);
1150 return 0;
1151}
1152
1153static int fimc_subdev_get_crop(struct v4l2_subdev *sd,
1154 struct v4l2_subdev_fh *fh,
1155 struct v4l2_subdev_crop *crop)
1156{
1157 struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
1158 struct fimc_ctx *ctx = fimc->vid_cap.ctx;
1159 struct v4l2_rect *r = &crop->rect;
1160 struct fimc_frame *ff;
1161
1162 if (crop->which == V4L2_SUBDEV_FORMAT_TRY) {
1163 crop->rect = *v4l2_subdev_get_try_crop(fh, crop->pad);
1164 return 0;
1165 }
1166 ff = crop->pad == FIMC_SD_PAD_SINK ?
1167 &ctx->s_frame : &ctx->d_frame;
1168
1169 mutex_lock(&fimc->lock);
1170 r->left = ff->offs_h;
1171 r->top = ff->offs_v;
1172 r->width = ff->width;
1173 r->height = ff->height;
1174 mutex_unlock(&fimc->lock);
1175
1176 dbg("ff:%p, pad%d: l:%d, t:%d, %dx%d, f_w: %d, f_h: %d",
1177 ff, crop->pad, r->left, r->top, r->width, r->height,
1178 ff->f_width, ff->f_height);
1179
1180 return 0;
1181}
1182
1183static int fimc_subdev_set_crop(struct v4l2_subdev *sd,
1184 struct v4l2_subdev_fh *fh,
1185 struct v4l2_subdev_crop *crop)
1186{
1187 struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
1188 struct fimc_ctx *ctx = fimc->vid_cap.ctx;
1189 struct v4l2_rect *r = &crop->rect;
1190 struct fimc_frame *ff;
1191 unsigned long flags;
1192
1193 dbg("(%d,%d)/%dx%d", r->left, r->top, r->width, r->height);
1194
1195 ff = crop->pad == FIMC_SD_PAD_SOURCE ?
1196 &ctx->d_frame : &ctx->s_frame;
1197
1198 mutex_lock(&fimc->lock);
1199 fimc_capture_try_crop(ctx, r, crop->pad);
1200
1201 if (crop->which == V4L2_SUBDEV_FORMAT_TRY) {
1202 mutex_lock(&fimc->lock);
1203 *v4l2_subdev_get_try_crop(fh, crop->pad) = *r;
1204 return 0;
1205 }
1206 spin_lock_irqsave(&fimc->slock, flags);
1207 set_frame_crop(ff, r->left, r->top, r->width, r->height);
1208 if (crop->pad == FIMC_SD_PAD_SOURCE)
1209 ctx->state |= FIMC_DST_CROP;
1210
1211 set_bit(ST_CAPT_APPLY_CFG, &fimc->state);
1212 spin_unlock_irqrestore(&fimc->slock, flags);
1213
1214 dbg("pad%d: (%d,%d)/%dx%d", crop->pad, r->left, r->top,
1215 r->width, r->height);
1216
1217 mutex_unlock(&fimc->lock);
1218 return 0;
1219}
1220
1221static struct v4l2_subdev_pad_ops fimc_subdev_pad_ops = {
1222 .enum_mbus_code = fimc_subdev_enum_mbus_code,
1223 .get_fmt = fimc_subdev_get_fmt,
1224 .set_fmt = fimc_subdev_set_fmt,
1225 .get_crop = fimc_subdev_get_crop,
1226 .set_crop = fimc_subdev_set_crop,
1227};
1228
1229static struct v4l2_subdev_ops fimc_subdev_ops = {
1230 .pad = &fimc_subdev_pad_ops,
1231};
1232
1233static int fimc_create_capture_subdev(struct fimc_dev *fimc,
1234 struct v4l2_device *v4l2_dev)
1235{
1236 struct v4l2_subdev *sd;
1237 int ret;
1238
1239 sd = kzalloc(sizeof(*sd), GFP_KERNEL);
1240 if (!sd)
1241 return -ENOMEM;
1242
1243 v4l2_subdev_init(sd, &fimc_subdev_ops);
1244 sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
1245 snprintf(sd->name, sizeof(sd->name), "FIMC.%d", fimc->pdev->id);
1246
1247 fimc->vid_cap.sd_pads[FIMC_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
1248 fimc->vid_cap.sd_pads[FIMC_SD_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
1249 ret = media_entity_init(&sd->entity, FIMC_SD_PADS_NUM,
1250 fimc->vid_cap.sd_pads, 0);
1251 if (ret)
1252 goto me_err;
1253 ret = v4l2_device_register_subdev(v4l2_dev, sd);
1254 if (ret)
1255 goto sd_err;
1256
1257 fimc->vid_cap.subdev = sd;
1258 v4l2_set_subdevdata(sd, fimc);
1259 sd->entity.ops = &fimc_sd_media_ops;
1260 return 0;
1261sd_err:
1262 media_entity_cleanup(&sd->entity);
1263me_err:
1264 kfree(sd);
1265 return ret;
1266}
1267
1268static void fimc_destroy_capture_subdev(struct fimc_dev *fimc)
1269{
1270 struct v4l2_subdev *sd = fimc->vid_cap.subdev;
1271
1272 if (!sd)
1273 return;
1274 media_entity_cleanup(&sd->entity);
1275 v4l2_device_unregister_subdev(sd);
1276 kfree(sd);
1277 sd = NULL;
1278}
1279
1280/* Set default format at the sensor and host interface */
1281static int fimc_capture_set_default_format(struct fimc_dev *fimc)
1282{
1283 struct v4l2_format fmt = {
1284 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
1285 .fmt.pix_mp = {
1286 .width = 640,
1287 .height = 480,
1288 .pixelformat = V4L2_PIX_FMT_YUYV,
1289 .field = V4L2_FIELD_NONE,
1290 .colorspace = V4L2_COLORSPACE_JPEG,
1291 },
1292 };
1293
1294 return fimc_capture_set_format(fimc, &fmt);
1295}
1296
717/* fimc->lock must be already initialized */ 1297/* fimc->lock must be already initialized */
718int fimc_register_capture_device(struct fimc_dev *fimc, 1298int fimc_register_capture_device(struct fimc_dev *fimc,
719 struct v4l2_device *v4l2_dev) 1299 struct v4l2_device *v4l2_dev)
@@ -721,7 +1301,6 @@ int fimc_register_capture_device(struct fimc_dev *fimc,
721 struct video_device *vfd; 1301 struct video_device *vfd;
722 struct fimc_vid_cap *vid_cap; 1302 struct fimc_vid_cap *vid_cap;
723 struct fimc_ctx *ctx; 1303 struct fimc_ctx *ctx;
724 struct fimc_frame *fr;
725 struct vb2_queue *q; 1304 struct vb2_queue *q;
726 int ret = -ENOMEM; 1305 int ret = -ENOMEM;
727 1306
@@ -733,12 +1312,8 @@ int fimc_register_capture_device(struct fimc_dev *fimc,
733 ctx->in_path = FIMC_CAMERA; 1312 ctx->in_path = FIMC_CAMERA;
734 ctx->out_path = FIMC_DMA; 1313 ctx->out_path = FIMC_DMA;
735 ctx->state = FIMC_CTX_CAP; 1314 ctx->state = FIMC_CTX_CAP;
736 1315 ctx->s_frame.fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_CAM, 0);
737 /* Default format of the output frames */ 1316 ctx->d_frame.fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_CAM, 0);
738 fr = &ctx->d_frame;
739 fr->fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_CAM, 0);
740 fr->width = fr->f_width = fr->o_width = 640;
741 fr->height = fr->f_height = fr->o_height = 480;
742 1317
743 vfd = video_device_alloc(); 1318 vfd = video_device_alloc();
744 if (!vfd) { 1319 if (!vfd) {
@@ -783,11 +1358,15 @@ int fimc_register_capture_device(struct fimc_dev *fimc,
783 ret = media_entity_init(&vfd->entity, 1, &fimc->vid_cap.vd_pad, 0); 1358 ret = media_entity_init(&vfd->entity, 1, &fimc->vid_cap.vd_pad, 0);
784 if (ret) 1359 if (ret)
785 goto err_ent; 1360 goto err_ent;
1361 ret = fimc_create_capture_subdev(fimc, v4l2_dev);
1362 if (ret)
1363 goto err_sd_reg;
786 1364
787 vfd->entity.ops = &fimc_media_ops;
788 vfd->ctrl_handler = &ctx->ctrl_handler; 1365 vfd->ctrl_handler = &ctx->ctrl_handler;
789 return 0; 1366 return 0;
790 1367
1368err_sd_reg:
1369 media_entity_cleanup(&vfd->entity);
791err_ent: 1370err_ent:
792 video_device_release(vfd); 1371 video_device_release(vfd);
793err_vd_alloc: 1372err_vd_alloc:
@@ -805,6 +1384,7 @@ void fimc_unregister_capture_device(struct fimc_dev *fimc)
805 not registered */ 1384 not registered */
806 video_unregister_device(vfd); 1385 video_unregister_device(vfd);
807 } 1386 }
1387 fimc_destroy_capture_subdev(fimc);
808 kfree(fimc->vid_cap.ctx); 1388 kfree(fimc->vid_cap.ctx);
809 fimc->vid_cap.ctx = NULL; 1389 fimc->vid_cap.ctx = NULL;
810} 1390}
diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c
index 605eb46e44d5..1a479a23cefb 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.c
+++ b/drivers/media/video/s5p-fimc/fimc-core.c
@@ -372,6 +372,8 @@ static void fimc_capture_irq_handler(struct fimc_dev *fimc)
372 set_bit(ST_CAPT_RUN, &fimc->state); 372 set_bit(ST_CAPT_RUN, &fimc->state);
373 } 373 }
374 374
375 fimc_capture_config_update(cap->ctx);
376
375 dbg("frame: %d, active_buf_cnt: %d", 377 dbg("frame: %d, active_buf_cnt: %d",
376 fimc_hw_get_frame_index(fimc), cap->active_buf_cnt); 378 fimc_hw_get_frame_index(fimc), cap->active_buf_cnt);
377} 379}
@@ -1198,12 +1200,11 @@ static int fimc_m2m_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
1198 return 0; 1200 return 0;
1199} 1201}
1200 1202
1201int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr) 1203static int fimc_m2m_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr)
1202{ 1204{
1203 struct fimc_dev *fimc = ctx->fimc_dev; 1205 struct fimc_dev *fimc = ctx->fimc_dev;
1204 struct fimc_frame *f; 1206 struct fimc_frame *f;
1205 u32 min_size, halign, depth = 0; 1207 u32 min_size, halign, depth = 0;
1206 bool is_capture_ctx;
1207 int i; 1208 int i;
1208 1209
1209 if (cr->c.top < 0 || cr->c.left < 0) { 1210 if (cr->c.top < 0 || cr->c.left < 0) {
@@ -1211,13 +1212,9 @@ int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr)
1211 "doesn't support negative values for top & left\n"); 1212 "doesn't support negative values for top & left\n");
1212 return -EINVAL; 1213 return -EINVAL;
1213 } 1214 }
1214
1215 is_capture_ctx = fimc_ctx_state_is_set(FIMC_CTX_CAP, ctx);
1216
1217 if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) 1215 if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
1218 f = is_capture_ctx ? &ctx->s_frame : &ctx->d_frame; 1216 f = &ctx->d_frame;
1219 else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && 1217 else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
1220 !is_capture_ctx)
1221 f = &ctx->s_frame; 1218 f = &ctx->s_frame;
1222 else 1219 else
1223 return -EINVAL; 1220 return -EINVAL;
@@ -1226,15 +1223,10 @@ int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr)
1226 fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize; 1223 fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize;
1227 1224
1228 /* Get pixel alignment constraints. */ 1225 /* Get pixel alignment constraints. */
1229 if (is_capture_ctx) { 1226 if (fimc->id == 1 && fimc->variant->pix_hoff)
1230 min_size = 16; 1227 halign = fimc_fmt_is_rgb(f->fmt->color) ? 0 : 1;
1231 halign = 4; 1228 else
1232 } else { 1229 halign = ffs(min_size) - 1;
1233 if (fimc->id == 1 && fimc->variant->pix_hoff)
1234 halign = fimc_fmt_is_rgb(f->fmt->color) ? 0 : 1;
1235 else
1236 halign = ffs(min_size) - 1;
1237 }
1238 1230
1239 for (i = 0; i < f->fmt->colplanes; i++) 1231 for (i = 0; i < f->fmt->colplanes; i++)
1240 depth += f->fmt->depth[i]; 1232 depth += f->fmt->depth[i];
@@ -1251,7 +1243,7 @@ int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr)
1251 cr->c.top = f->o_height - cr->c.height; 1243 cr->c.top = f->o_height - cr->c.height;
1252 1244
1253 cr->c.left = round_down(cr->c.left, min_size); 1245 cr->c.left = round_down(cr->c.left, min_size);
1254 cr->c.top = round_down(cr->c.top, is_capture_ctx ? 16 : 8); 1246 cr->c.top = round_down(cr->c.top, fimc->variant->hor_offs_align);
1255 1247
1256 dbg("l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d", 1248 dbg("l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d",
1257 cr->c.left, cr->c.top, cr->c.width, cr->c.height, 1249 cr->c.left, cr->c.top, cr->c.width, cr->c.height,
@@ -1267,7 +1259,7 @@ static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
1267 struct fimc_frame *f; 1259 struct fimc_frame *f;
1268 int ret; 1260 int ret;
1269 1261
1270 ret = fimc_try_crop(ctx, cr); 1262 ret = fimc_m2m_try_crop(ctx, cr);
1271 if (ret) 1263 if (ret)
1272 return ret; 1264 return ret;
1273 1265
diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h
index 2935068fda2d..e4520b2dde43 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.h
+++ b/drivers/media/video/s5p-fimc/fimc-core.h
@@ -43,6 +43,7 @@
43#define SCALER_MAX_HRATIO 64 43#define SCALER_MAX_HRATIO 64
44#define SCALER_MAX_VRATIO 64 44#define SCALER_MAX_VRATIO 64
45#define DMA_MIN_SIZE 8 45#define DMA_MIN_SIZE 8
46#define FIMC_CAMIF_MAX_HEIGHT 0x2000
46 47
47/* indices to the clocks array */ 48/* indices to the clocks array */
48enum { 49enum {
@@ -92,9 +93,11 @@ enum fimc_color_fmt {
92 S5P_FIMC_CBYCRY422, 93 S5P_FIMC_CBYCRY422,
93 S5P_FIMC_CRYCBY422, 94 S5P_FIMC_CRYCBY422,
94 S5P_FIMC_YCBCR444_LOCAL, 95 S5P_FIMC_YCBCR444_LOCAL,
96 S5P_FIMC_JPEG = 0x40,
95}; 97};
96 98
97#define fimc_fmt_is_rgb(x) ((x) & 0x10) 99#define fimc_fmt_is_rgb(x) (!!((x) & 0x10))
100#define fimc_fmt_is_jpeg(x) (!!((x) & 0x40))
98 101
99#define IS_M2M(__strt) ((__strt) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE || \ 102#define IS_M2M(__strt) ((__strt) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE || \
100 __strt == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) 103 __strt == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
@@ -116,9 +119,10 @@ enum fimc_color_fmt {
116#define FIMC_DST_ADDR (1 << 2) 119#define FIMC_DST_ADDR (1 << 2)
117#define FIMC_SRC_FMT (1 << 3) 120#define FIMC_SRC_FMT (1 << 3)
118#define FIMC_DST_FMT (1 << 4) 121#define FIMC_DST_FMT (1 << 4)
119#define FIMC_CTX_M2M (1 << 5) 122#define FIMC_DST_CROP (1 << 5)
120#define FIMC_CTX_CAP (1 << 6) 123#define FIMC_CTX_M2M (1 << 16)
121#define FIMC_CTX_SHUT (1 << 7) 124#define FIMC_CTX_CAP (1 << 17)
125#define FIMC_CTX_SHUT (1 << 18)
122 126
123/* Image conversion flags */ 127/* Image conversion flags */
124#define FIMC_IN_DMA_ACCESS_TILED (1 << 0) 128#define FIMC_IN_DMA_ACCESS_TILED (1 << 0)
@@ -293,12 +297,18 @@ struct fimc_m2m_device {
293 int refcnt; 297 int refcnt;
294}; 298};
295 299
300#define FIMC_SD_PAD_SINK 0
301#define FIMC_SD_PAD_SOURCE 1
302#define FIMC_SD_PADS_NUM 2
303
296/** 304/**
297 * struct fimc_vid_cap - camera capture device information 305 * struct fimc_vid_cap - camera capture device information
298 * @ctx: hardware context data 306 * @ctx: hardware context data
299 * @vfd: video device node for camera capture mode 307 * @vfd: video device node for camera capture mode
308 * @subdev: subdev exposing the FIMC processing block
300 * @vd_pad: fimc video capture node pad 309 * @vd_pad: fimc video capture node pad
301 * @fmt: Media Bus format configured at selected image sensor 310 * @sd_pads: fimc video processing block pads
311 * @mf: media bus format at the FIMC camera input (and the scaler output) pad
302 * @pending_buf_q: the pending buffer queue head 312 * @pending_buf_q: the pending buffer queue head
303 * @active_buf_q: the queue head of buffers scheduled in hardware 313 * @active_buf_q: the queue head of buffers scheduled in hardware
304 * @vbq: the capture am video buffer queue 314 * @vbq: the capture am video buffer queue
@@ -315,8 +325,10 @@ struct fimc_vid_cap {
315 struct fimc_ctx *ctx; 325 struct fimc_ctx *ctx;
316 struct vb2_alloc_ctx *alloc_ctx; 326 struct vb2_alloc_ctx *alloc_ctx;
317 struct video_device *vfd; 327 struct video_device *vfd;
328 struct v4l2_subdev *subdev;
318 struct media_pad vd_pad; 329 struct media_pad vd_pad;
319 struct v4l2_mbus_framefmt fmt; 330 struct v4l2_mbus_framefmt mf;
331 struct media_pad sd_pads[FIMC_SD_PADS_NUM];
320 struct list_head pending_buf_q; 332 struct list_head pending_buf_q;
321 struct list_head active_buf_q; 333 struct list_head active_buf_q;
322 struct vb2_queue vbq; 334 struct vb2_queue vbq;
@@ -498,6 +510,33 @@ struct fimc_ctx {
498 510
499#define fh_to_ctx(__fh) container_of(__fh, struct fimc_ctx, fh) 511#define fh_to_ctx(__fh) container_of(__fh, struct fimc_ctx, fh)
500 512
513static inline void set_frame_bounds(struct fimc_frame *f, u32 width, u32 height)
514{
515 f->o_width = width;
516 f->o_height = height;
517 f->f_width = width;
518 f->f_height = height;
519}
520
521static inline void set_frame_crop(struct fimc_frame *f,
522 u32 left, u32 top, u32 width, u32 height)
523{
524 f->offs_h = left;
525 f->offs_v = top;
526 f->width = width;
527 f->height = height;
528}
529
530static inline u32 fimc_get_format_depth(struct fimc_fmt *ff)
531{
532 u32 i, depth = 0;
533
534 if (ff != NULL)
535 for (i = 0; i < ff->colplanes; i++)
536 depth += ff->depth[i];
537 return depth;
538}
539
501static inline bool fimc_capture_active(struct fimc_dev *fimc) 540static inline bool fimc_capture_active(struct fimc_dev *fimc)
502{ 541{
503 unsigned long flags; 542 unsigned long flags;
@@ -649,7 +688,6 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc,
649/* fimc-core.c */ 688/* fimc-core.c */
650int fimc_vidioc_enum_fmt_mplane(struct file *file, void *priv, 689int fimc_vidioc_enum_fmt_mplane(struct file *file, void *priv,
651 struct v4l2_fmtdesc *f); 690 struct v4l2_fmtdesc *f);
652int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr);
653int fimc_ctrls_create(struct fimc_ctx *ctx); 691int fimc_ctrls_create(struct fimc_ctx *ctx);
654void fimc_ctrls_delete(struct fimc_ctx *ctx); 692void fimc_ctrls_delete(struct fimc_ctx *ctx);
655void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active); 693void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active);
@@ -684,6 +722,7 @@ int fimc_vid_cap_buf_queue(struct fimc_dev *fimc,
684 struct fimc_vid_buffer *fimc_vb); 722 struct fimc_vid_buffer *fimc_vb);
685int fimc_capture_suspend(struct fimc_dev *fimc); 723int fimc_capture_suspend(struct fimc_dev *fimc);
686int fimc_capture_resume(struct fimc_dev *fimc); 724int fimc_capture_resume(struct fimc_dev *fimc);
725int fimc_capture_config_update(struct fimc_ctx *ctx);
687 726
688/* Locking: the caller holds fimc->slock */ 727/* Locking: the caller holds fimc->slock */
689static inline void fimc_activate_capture(struct fimc_ctx *ctx) 728static inline void fimc_activate_capture(struct fimc_ctx *ctx)
diff --git a/drivers/media/video/s5p-fimc/fimc-mdevice.c b/drivers/media/video/s5p-fimc/fimc-mdevice.c
index 5bb2c0de2cdc..db17a6fad3e0 100644
--- a/drivers/media/video/s5p-fimc/fimc-mdevice.c
+++ b/drivers/media/video/s5p-fimc/fimc-mdevice.c
@@ -416,7 +416,7 @@ static int __fimc_md_create_fimc_links(struct fimc_md *fmd,
416 struct fimc_sensor_info *s_info; 416 struct fimc_sensor_info *s_info;
417 struct media_entity *sink; 417 struct media_entity *sink;
418 unsigned int flags; 418 unsigned int flags;
419 int ret, i, src_pad; 419 int ret, i;
420 420
421 for (i = 0; i < FIMC_MAX_DEVS; i++) { 421 for (i = 0; i < FIMC_MAX_DEVS; i++) {
422 if (!fmd->fimc[i]) 422 if (!fmd->fimc[i])
@@ -425,20 +425,27 @@ static int __fimc_md_create_fimc_links(struct fimc_md *fmd,
425 * Some FIMC variants are not fitted with camera capture 425 * Some FIMC variants are not fitted with camera capture
426 * interface. Skip creating a link from sensor for those. 426 * interface. Skip creating a link from sensor for those.
427 */ 427 */
428 if (sensor && sensor->grp_id == SENSOR_GROUP_ID && 428 if (sensor->grp_id == SENSOR_GROUP_ID &&
429 !fmd->fimc[i]->variant->has_cam_if) 429 !fmd->fimc[i]->variant->has_cam_if)
430 continue; 430 continue;
431 431
432 flags = (i == fimc_id) ? MEDIA_LNK_FL_ENABLED : 0; 432 flags = (i == fimc_id) ? MEDIA_LNK_FL_ENABLED : 0;
433 sink = &fmd->fimc[i]->vid_cap.vfd->entity; 433 sink = &fmd->fimc[i]->vid_cap.subdev->entity;
434 ret = media_entity_create_link(source, 0, sink, 0, flags); 434 ret = media_entity_create_link(source, pad, sink,
435 FIMC_SD_PAD_SINK, flags);
435 if (ret) 436 if (ret)
436 return ret; 437 return ret;
437 438
439 /* Notify FIMC capture subdev entity */
440 ret = media_entity_call(sink, link_setup, &sink->pads[0],
441 &source->pads[pad], flags);
442 if (ret)
443 break;
444
438 v4l2_info(&fmd->v4l2_dev, "created link [%s] %c> [%s]", 445 v4l2_info(&fmd->v4l2_dev, "created link [%s] %c> [%s]",
439 source->name, flags ? '=' : '-', sink->name); 446 source->name, flags ? '=' : '-', sink->name);
440 447
441 if (flags == 0 || sensor == NULL) 448 if (flags == 0)
442 continue; 449 continue;
443 s_info = v4l2_get_subdev_hostdata(sensor); 450 s_info = v4l2_get_subdev_hostdata(sensor);
444 if (!WARN_ON(s_info == NULL)) { 451 if (!WARN_ON(s_info == NULL)) {
@@ -468,10 +475,10 @@ static int fimc_md_create_links(struct fimc_md *fmd)
468 struct v4l2_subdev *sensor, *csis; 475 struct v4l2_subdev *sensor, *csis;
469 struct s5p_fimc_isp_info *pdata; 476 struct s5p_fimc_isp_info *pdata;
470 struct fimc_sensor_info *s_info; 477 struct fimc_sensor_info *s_info;
471 struct media_entity *source; 478 struct media_entity *source, *sink;
472 int fimc_id = 0; 479 int i, pad, fimc_id = 0;
473 int i, pad;
474 int ret = 0; 480 int ret = 0;
481 u32 flags;
475 482
476 for (i = 0; i < fmd->num_sensors; i++) { 483 for (i = 0; i < fmd->num_sensors; i++) {
477 if (fmd->sensor[i].subdev == NULL) 484 if (fmd->sensor[i].subdev == NULL)
@@ -507,7 +514,6 @@ static int fimc_md_create_links(struct fimc_md *fmd)
507 v4l2_info(&fmd->v4l2_dev, "created link [%s] => [%s]", 514 v4l2_info(&fmd->v4l2_dev, "created link [%s] => [%s]",
508 sensor->entity.name, csis->entity.name); 515 sensor->entity.name, csis->entity.name);
509 516
510 sensor = NULL;
511 source = &csis->entity; 517 source = &csis->entity;
512 pad = CSIS_PAD_SOURCE; 518 pad = CSIS_PAD_SOURCE;
513 break; 519 break;
@@ -526,8 +532,21 @@ static int fimc_md_create_links(struct fimc_md *fmd)
526 continue; 532 continue;
527 533
528 ret = __fimc_md_create_fimc_links(fmd, source, sensor, pad, 534 ret = __fimc_md_create_fimc_links(fmd, source, sensor, pad,
529 fimc_id++); 535 fimc_id++);
530 } 536 }
537 /* Create immutable links between each FIMC's subdev and video node */
538 flags = MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED;
539 for (i = 0; i < FIMC_MAX_DEVS; i++) {
540 if (!fmd->fimc[i])
541 continue;
542 source = &fmd->fimc[i]->vid_cap.subdev->entity;
543 sink = &fmd->fimc[i]->vid_cap.vfd->entity;
544 ret = media_entity_create_link(source, FIMC_SD_PAD_SOURCE,
545 sink, 0, flags);
546 if (ret)
547 break;
548 }
549
531 return ret; 550 return ret;
532} 551}
533 552
@@ -636,15 +655,15 @@ int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on)
636static int fimc_md_link_notify(struct media_pad *source, 655static int fimc_md_link_notify(struct media_pad *source,
637 struct media_pad *sink, u32 flags) 656 struct media_pad *sink, u32 flags)
638{ 657{
639 struct video_device *vid_dev; 658 struct v4l2_subdev *sd;
640 struct fimc_dev *fimc; 659 struct fimc_dev *fimc;
641 int ret = 0; 660 int ret = 0;
642 661
643 if (WARN_ON(media_entity_type(sink->entity) != MEDIA_ENT_T_DEVNODE)) 662 if (media_entity_type(sink->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
644 return 0; 663 return 0;
645 664
646 vid_dev = media_entity_to_video_device(sink->entity); 665 sd = media_entity_to_v4l2_subdev(sink->entity);
647 fimc = video_get_drvdata(vid_dev); 666 fimc = v4l2_get_subdevdata(sd);
648 667
649 if (!(flags & MEDIA_LNK_FL_ENABLED)) { 668 if (!(flags & MEDIA_LNK_FL_ENABLED)) {
650 ret = __fimc_pipeline_shutdown(fimc); 669 ret = __fimc_pipeline_shutdown(fimc);
diff --git a/drivers/media/video/s5p-fimc/fimc-reg.c b/drivers/media/video/s5p-fimc/fimc-reg.c
index 50937b40854f..a1fff022c5b4 100644
--- a/drivers/media/video/s5p-fimc/fimc-reg.c
+++ b/drivers/media/video/s5p-fimc/fimc-reg.c
@@ -572,7 +572,7 @@ int fimc_hw_set_camera_source(struct fimc_dev *fimc,
572 572
573 if (cam->bus_type == FIMC_ITU_601 || cam->bus_type == FIMC_ITU_656) { 573 if (cam->bus_type == FIMC_ITU_601 || cam->bus_type == FIMC_ITU_656) {
574 for (i = 0; i < ARRAY_SIZE(pix_desc); i++) { 574 for (i = 0; i < ARRAY_SIZE(pix_desc); i++) {
575 if (fimc->vid_cap.fmt.code == pix_desc[i].pixelcode) { 575 if (fimc->vid_cap.mf.code == pix_desc[i].pixelcode) {
576 cfg = pix_desc[i].cisrcfmt; 576 cfg = pix_desc[i].cisrcfmt;
577 bus_width = pix_desc[i].bus_width; 577 bus_width = pix_desc[i].bus_width;
578 break; 578 break;
@@ -582,7 +582,7 @@ int fimc_hw_set_camera_source(struct fimc_dev *fimc,
582 if (i == ARRAY_SIZE(pix_desc)) { 582 if (i == ARRAY_SIZE(pix_desc)) {
583 v4l2_err(fimc->vid_cap.vfd, 583 v4l2_err(fimc->vid_cap.vfd,
584 "Camera color format not supported: %d\n", 584 "Camera color format not supported: %d\n",
585 fimc->vid_cap.fmt.code); 585 fimc->vid_cap.mf.code);
586 return -EINVAL; 586 return -EINVAL;
587 } 587 }
588 588
@@ -642,12 +642,12 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc,
642 cfg |= S5P_CIGCTRL_SELCAM_MIPI_A; 642 cfg |= S5P_CIGCTRL_SELCAM_MIPI_A;
643 643
644 /* TODO: add remaining supported formats. */ 644 /* TODO: add remaining supported formats. */
645 if (vid_cap->fmt.code == V4L2_MBUS_FMT_VYUY8_2X8) { 645 if (vid_cap->mf.code == V4L2_MBUS_FMT_VYUY8_2X8) {
646 tmp = S5P_CSIIMGFMT_YCBCR422_8BIT; 646 tmp = S5P_CSIIMGFMT_YCBCR422_8BIT;
647 } else { 647 } else {
648 v4l2_err(fimc->vid_cap.vfd, 648 v4l2_err(fimc->vid_cap.vfd,
649 "Not supported camera pixel format: %d", 649 "Not supported camera pixel format: %d",
650 vid_cap->fmt.code); 650 vid_cap->mf.code);
651 return -EINVAL; 651 return -EINVAL;
652 } 652 }
653 tmp |= (cam->csi_data_align == 32) << 8; 653 tmp |= (cam->csi_data_align == 32) << 8;