diff options
Diffstat (limited to 'drivers/media/platform/s5p-fimc/fimc-capture.c')
-rw-r--r-- | drivers/media/platform/s5p-fimc/fimc-capture.c | 135 |
1 files changed, 117 insertions, 18 deletions
diff --git a/drivers/media/platform/s5p-fimc/fimc-capture.c b/drivers/media/platform/s5p-fimc/fimc-capture.c index dded98815220..367efd164d0f 100644 --- a/drivers/media/platform/s5p-fimc/fimc-capture.c +++ b/drivers/media/platform/s5p-fimc/fimc-capture.c | |||
@@ -177,7 +177,9 @@ static int fimc_capture_config_update(struct fimc_ctx *ctx) | |||
177 | 177 | ||
178 | void fimc_capture_irq_handler(struct fimc_dev *fimc, int deq_buf) | 178 | void fimc_capture_irq_handler(struct fimc_dev *fimc, int deq_buf) |
179 | { | 179 | { |
180 | struct v4l2_subdev *csis = fimc->pipeline.subdevs[IDX_CSIS]; | ||
180 | struct fimc_vid_cap *cap = &fimc->vid_cap; | 181 | struct fimc_vid_cap *cap = &fimc->vid_cap; |
182 | struct fimc_frame *f = &cap->ctx->d_frame; | ||
181 | struct fimc_vid_buffer *v_buf; | 183 | struct fimc_vid_buffer *v_buf; |
182 | struct timeval *tv; | 184 | struct timeval *tv; |
183 | struct timespec ts; | 185 | struct timespec ts; |
@@ -216,6 +218,25 @@ void fimc_capture_irq_handler(struct fimc_dev *fimc, int deq_buf) | |||
216 | if (++cap->buf_index >= FIMC_MAX_OUT_BUFS) | 218 | if (++cap->buf_index >= FIMC_MAX_OUT_BUFS) |
217 | cap->buf_index = 0; | 219 | cap->buf_index = 0; |
218 | } | 220 | } |
221 | /* | ||
222 | * Set up a buffer at MIPI-CSIS if current image format | ||
223 | * requires the frame embedded data capture. | ||
224 | */ | ||
225 | if (f->fmt->mdataplanes && !list_empty(&cap->active_buf_q)) { | ||
226 | unsigned int plane = ffs(f->fmt->mdataplanes) - 1; | ||
227 | unsigned int size = f->payload[plane]; | ||
228 | s32 index = fimc_hw_get_frame_index(fimc); | ||
229 | void *vaddr; | ||
230 | |||
231 | list_for_each_entry(v_buf, &cap->active_buf_q, list) { | ||
232 | if (v_buf->index != index) | ||
233 | continue; | ||
234 | vaddr = vb2_plane_vaddr(&v_buf->vb, plane); | ||
235 | v4l2_subdev_call(csis, video, s_rx_buffer, | ||
236 | vaddr, &size); | ||
237 | break; | ||
238 | } | ||
239 | } | ||
219 | 240 | ||
220 | if (cap->active_buf_cnt == 0) { | 241 | if (cap->active_buf_cnt == 0) { |
221 | if (deq_buf) | 242 | if (deq_buf) |
@@ -351,6 +372,8 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt, | |||
351 | unsigned int size = (wh * fmt->depth[i]) / 8; | 372 | unsigned int size = (wh * fmt->depth[i]) / 8; |
352 | if (pixm) | 373 | if (pixm) |
353 | sizes[i] = max(size, pixm->plane_fmt[i].sizeimage); | 374 | sizes[i] = max(size, pixm->plane_fmt[i].sizeimage); |
375 | else if (fimc_fmt_is_user_defined(fmt->color)) | ||
376 | sizes[i] = frame->payload[i]; | ||
354 | else | 377 | else |
355 | sizes[i] = max_t(u32, size, frame->payload[i]); | 378 | sizes[i] = max_t(u32, size, frame->payload[i]); |
356 | 379 | ||
@@ -611,10 +634,10 @@ static struct fimc_fmt *fimc_capture_try_format(struct fimc_ctx *ctx, | |||
611 | u32 mask = FMT_FLAGS_CAM; | 634 | u32 mask = FMT_FLAGS_CAM; |
612 | struct fimc_fmt *ffmt; | 635 | struct fimc_fmt *ffmt; |
613 | 636 | ||
614 | /* Color conversion from/to JPEG is not supported */ | 637 | /* Conversion from/to JPEG or User Defined format is not supported */ |
615 | if (code && ctx->s_frame.fmt && pad == FIMC_SD_PAD_SOURCE && | 638 | if (code && ctx->s_frame.fmt && pad == FIMC_SD_PAD_SOURCE && |
616 | fimc_fmt_is_jpeg(ctx->s_frame.fmt->color)) | 639 | fimc_fmt_is_user_defined(ctx->s_frame.fmt->color)) |
617 | *code = V4L2_MBUS_FMT_JPEG_1X8; | 640 | *code = ctx->s_frame.fmt->mbus_code; |
618 | 641 | ||
619 | if (fourcc && *fourcc != V4L2_PIX_FMT_JPEG && pad != FIMC_SD_PAD_SINK) | 642 | if (fourcc && *fourcc != V4L2_PIX_FMT_JPEG && pad != FIMC_SD_PAD_SINK) |
620 | mask |= FMT_FLAGS_M2M; | 643 | mask |= FMT_FLAGS_M2M; |
@@ -628,18 +651,19 @@ static struct fimc_fmt *fimc_capture_try_format(struct fimc_ctx *ctx, | |||
628 | *fourcc = ffmt->fourcc; | 651 | *fourcc = ffmt->fourcc; |
629 | 652 | ||
630 | if (pad == FIMC_SD_PAD_SINK) { | 653 | if (pad == FIMC_SD_PAD_SINK) { |
631 | max_w = fimc_fmt_is_jpeg(ffmt->color) ? | 654 | max_w = fimc_fmt_is_user_defined(ffmt->color) ? |
632 | pl->scaler_dis_w : pl->scaler_en_w; | 655 | pl->scaler_dis_w : pl->scaler_en_w; |
633 | /* Apply the camera input interface pixel constraints */ | 656 | /* Apply the camera input interface pixel constraints */ |
634 | v4l_bound_align_image(width, max_t(u32, *width, 32), max_w, 4, | 657 | v4l_bound_align_image(width, max_t(u32, *width, 32), max_w, 4, |
635 | height, max_t(u32, *height, 32), | 658 | height, max_t(u32, *height, 32), |
636 | FIMC_CAMIF_MAX_HEIGHT, | 659 | FIMC_CAMIF_MAX_HEIGHT, |
637 | fimc_fmt_is_jpeg(ffmt->color) ? 3 : 1, | 660 | fimc_fmt_is_user_defined(ffmt->color) ? |
661 | 3 : 1, | ||
638 | 0); | 662 | 0); |
639 | return ffmt; | 663 | return ffmt; |
640 | } | 664 | } |
641 | /* Can't scale or crop in transparent (JPEG) transfer mode */ | 665 | /* Can't scale or crop in transparent (JPEG) transfer mode */ |
642 | if (fimc_fmt_is_jpeg(ffmt->color)) { | 666 | if (fimc_fmt_is_user_defined(ffmt->color)) { |
643 | *width = ctx->s_frame.f_width; | 667 | *width = ctx->s_frame.f_width; |
644 | *height = ctx->s_frame.f_height; | 668 | *height = ctx->s_frame.f_height; |
645 | return ffmt; | 669 | return ffmt; |
@@ -684,7 +708,7 @@ static void fimc_capture_try_selection(struct fimc_ctx *ctx, | |||
684 | u32 max_sc_h, max_sc_v; | 708 | u32 max_sc_h, max_sc_v; |
685 | 709 | ||
686 | /* In JPEG transparent transfer mode cropping is not supported */ | 710 | /* In JPEG transparent transfer mode cropping is not supported */ |
687 | if (fimc_fmt_is_jpeg(ctx->d_frame.fmt->color)) { | 711 | if (fimc_fmt_is_user_defined(ctx->d_frame.fmt->color)) { |
688 | r->width = sink->f_width; | 712 | r->width = sink->f_width; |
689 | r->height = sink->f_height; | 713 | r->height = sink->f_height; |
690 | r->left = r->top = 0; | 714 | r->left = r->top = 0; |
@@ -847,6 +871,48 @@ static int fimc_pipeline_try_format(struct fimc_ctx *ctx, | |||
847 | return 0; | 871 | return 0; |
848 | } | 872 | } |
849 | 873 | ||
874 | /** | ||
875 | * fimc_get_sensor_frame_desc - query the sensor for media bus frame parameters | ||
876 | * @sensor: pointer to the sensor subdev | ||
877 | * @plane_fmt: provides plane sizes corresponding to the frame layout entries | ||
878 | * @try: true to set the frame parameters, false to query only | ||
879 | * | ||
880 | * This function is used by this driver only for compressed/blob data formats. | ||
881 | */ | ||
882 | static int fimc_get_sensor_frame_desc(struct v4l2_subdev *sensor, | ||
883 | struct v4l2_plane_pix_format *plane_fmt, | ||
884 | unsigned int num_planes, bool try) | ||
885 | { | ||
886 | struct v4l2_mbus_frame_desc fd; | ||
887 | int i, ret; | ||
888 | |||
889 | for (i = 0; i < num_planes; i++) | ||
890 | fd.entry[i].length = plane_fmt[i].sizeimage; | ||
891 | |||
892 | if (try) | ||
893 | ret = v4l2_subdev_call(sensor, pad, set_frame_desc, 0, &fd); | ||
894 | else | ||
895 | ret = v4l2_subdev_call(sensor, pad, get_frame_desc, 0, &fd); | ||
896 | |||
897 | if (ret < 0) | ||
898 | return ret; | ||
899 | |||
900 | if (num_planes != fd.num_entries) | ||
901 | return -EINVAL; | ||
902 | |||
903 | for (i = 0; i < num_planes; i++) | ||
904 | plane_fmt[i].sizeimage = fd.entry[i].length; | ||
905 | |||
906 | if (fd.entry[0].length > FIMC_MAX_JPEG_BUF_SIZE) { | ||
907 | v4l2_err(sensor->v4l2_dev, "Unsupported buffer size: %u\n", | ||
908 | fd.entry[0].length); | ||
909 | |||
910 | return -EINVAL; | ||
911 | } | ||
912 | |||
913 | return 0; | ||
914 | } | ||
915 | |||
850 | static int fimc_cap_g_fmt_mplane(struct file *file, void *fh, | 916 | static int fimc_cap_g_fmt_mplane(struct file *file, void *fh, |
851 | struct v4l2_format *f) | 917 | struct v4l2_format *f) |
852 | { | 918 | { |
@@ -865,7 +931,7 @@ static int fimc_cap_try_fmt_mplane(struct file *file, void *fh, | |||
865 | struct v4l2_mbus_framefmt mf; | 931 | struct v4l2_mbus_framefmt mf; |
866 | struct fimc_fmt *ffmt = NULL; | 932 | struct fimc_fmt *ffmt = NULL; |
867 | 933 | ||
868 | if (pix->pixelformat == V4L2_PIX_FMT_JPEG) { | 934 | if (fimc_jpeg_fourcc(pix->pixelformat)) { |
869 | fimc_capture_try_format(ctx, &pix->width, &pix->height, | 935 | fimc_capture_try_format(ctx, &pix->width, &pix->height, |
870 | NULL, &pix->pixelformat, | 936 | NULL, &pix->pixelformat, |
871 | FIMC_SD_PAD_SINK); | 937 | FIMC_SD_PAD_SINK); |
@@ -879,25 +945,32 @@ static int fimc_cap_try_fmt_mplane(struct file *file, void *fh, | |||
879 | return -EINVAL; | 945 | return -EINVAL; |
880 | 946 | ||
881 | if (!fimc->vid_cap.user_subdev_api) { | 947 | if (!fimc->vid_cap.user_subdev_api) { |
882 | mf.width = pix->width; | 948 | mf.width = pix->width; |
883 | mf.height = pix->height; | 949 | mf.height = pix->height; |
884 | mf.code = ffmt->mbus_code; | 950 | mf.code = ffmt->mbus_code; |
885 | fimc_md_graph_lock(fimc); | 951 | fimc_md_graph_lock(fimc); |
886 | fimc_pipeline_try_format(ctx, &mf, &ffmt, false); | 952 | fimc_pipeline_try_format(ctx, &mf, &ffmt, false); |
887 | fimc_md_graph_unlock(fimc); | 953 | fimc_md_graph_unlock(fimc); |
888 | 954 | pix->width = mf.width; | |
889 | pix->width = mf.width; | 955 | pix->height = mf.height; |
890 | pix->height = mf.height; | ||
891 | if (ffmt) | 956 | if (ffmt) |
892 | pix->pixelformat = ffmt->fourcc; | 957 | pix->pixelformat = ffmt->fourcc; |
893 | } | 958 | } |
894 | 959 | ||
895 | fimc_adjust_mplane_format(ffmt, pix->width, pix->height, pix); | 960 | fimc_adjust_mplane_format(ffmt, pix->width, pix->height, pix); |
961 | |||
962 | if (ffmt->flags & FMT_FLAGS_COMPRESSED) | ||
963 | fimc_get_sensor_frame_desc(fimc->pipeline.subdevs[IDX_SENSOR], | ||
964 | pix->plane_fmt, ffmt->memplanes, true); | ||
965 | |||
896 | return 0; | 966 | return 0; |
897 | } | 967 | } |
898 | 968 | ||
899 | static void fimc_capture_mark_jpeg_xfer(struct fimc_ctx *ctx, bool jpeg) | 969 | static void fimc_capture_mark_jpeg_xfer(struct fimc_ctx *ctx, |
970 | enum fimc_color_fmt color) | ||
900 | { | 971 | { |
972 | bool jpeg = fimc_fmt_is_user_defined(color); | ||
973 | |||
901 | ctx->scaler.enabled = !jpeg; | 974 | ctx->scaler.enabled = !jpeg; |
902 | fimc_ctrls_activate(ctx, !jpeg); | 975 | fimc_ctrls_activate(ctx, !jpeg); |
903 | 976 | ||
@@ -920,7 +993,7 @@ static int fimc_capture_set_format(struct fimc_dev *fimc, struct v4l2_format *f) | |||
920 | return -EBUSY; | 993 | return -EBUSY; |
921 | 994 | ||
922 | /* Pre-configure format at camera interface input, for JPEG only */ | 995 | /* Pre-configure format at camera interface input, for JPEG only */ |
923 | if (pix->pixelformat == V4L2_PIX_FMT_JPEG) { | 996 | if (fimc_jpeg_fourcc(pix->pixelformat)) { |
924 | fimc_capture_try_format(ctx, &pix->width, &pix->height, | 997 | fimc_capture_try_format(ctx, &pix->width, &pix->height, |
925 | NULL, &pix->pixelformat, | 998 | NULL, &pix->pixelformat, |
926 | FIMC_SD_PAD_SINK); | 999 | FIMC_SD_PAD_SINK); |
@@ -953,7 +1026,16 @@ static int fimc_capture_set_format(struct fimc_dev *fimc, struct v4l2_format *f) | |||
953 | } | 1026 | } |
954 | 1027 | ||
955 | fimc_adjust_mplane_format(ff->fmt, pix->width, pix->height, pix); | 1028 | fimc_adjust_mplane_format(ff->fmt, pix->width, pix->height, pix); |
956 | for (i = 0; i < ff->fmt->colplanes; i++) | 1029 | |
1030 | if (ff->fmt->flags & FMT_FLAGS_COMPRESSED) { | ||
1031 | ret = fimc_get_sensor_frame_desc(fimc->pipeline.subdevs[IDX_SENSOR], | ||
1032 | pix->plane_fmt, ff->fmt->memplanes, | ||
1033 | true); | ||
1034 | if (ret < 0) | ||
1035 | return ret; | ||
1036 | } | ||
1037 | |||
1038 | for (i = 0; i < ff->fmt->memplanes; i++) | ||
957 | ff->payload[i] = pix->plane_fmt[i].sizeimage; | 1039 | ff->payload[i] = pix->plane_fmt[i].sizeimage; |
958 | 1040 | ||
959 | set_frame_bounds(ff, pix->width, pix->height); | 1041 | set_frame_bounds(ff, pix->width, pix->height); |
@@ -961,7 +1043,7 @@ static int fimc_capture_set_format(struct fimc_dev *fimc, struct v4l2_format *f) | |||
961 | if (!(ctx->state & FIMC_COMPOSE)) | 1043 | if (!(ctx->state & FIMC_COMPOSE)) |
962 | set_frame_crop(ff, 0, 0, pix->width, pix->height); | 1044 | set_frame_crop(ff, 0, 0, pix->width, pix->height); |
963 | 1045 | ||
964 | fimc_capture_mark_jpeg_xfer(ctx, fimc_fmt_is_jpeg(ff->fmt->color)); | 1046 | fimc_capture_mark_jpeg_xfer(ctx, ff->fmt->color); |
965 | 1047 | ||
966 | /* Reset cropping and set format at the camera interface input */ | 1048 | /* Reset cropping and set format at the camera interface input */ |
967 | if (!fimc->vid_cap.user_subdev_api) { | 1049 | if (!fimc->vid_cap.user_subdev_api) { |
@@ -1063,6 +1145,23 @@ static int fimc_pipeline_validate(struct fimc_dev *fimc) | |||
1063 | src_fmt.format.height != sink_fmt.format.height || | 1145 | src_fmt.format.height != sink_fmt.format.height || |
1064 | src_fmt.format.code != sink_fmt.format.code) | 1146 | src_fmt.format.code != sink_fmt.format.code) |
1065 | return -EPIPE; | 1147 | return -EPIPE; |
1148 | |||
1149 | if (sd == fimc->pipeline.subdevs[IDX_SENSOR] && | ||
1150 | fimc_user_defined_mbus_fmt(src_fmt.format.code)) { | ||
1151 | struct v4l2_plane_pix_format plane_fmt[FIMC_MAX_PLANES]; | ||
1152 | struct fimc_frame *frame = &vid_cap->ctx->d_frame; | ||
1153 | unsigned int i; | ||
1154 | |||
1155 | ret = fimc_get_sensor_frame_desc(sd, plane_fmt, | ||
1156 | frame->fmt->memplanes, | ||
1157 | false); | ||
1158 | if (ret < 0) | ||
1159 | return -EPIPE; | ||
1160 | |||
1161 | for (i = 0; i < frame->fmt->memplanes; i++) | ||
1162 | if (frame->payload[i] < plane_fmt[i].sizeimage) | ||
1163 | return -EPIPE; | ||
1164 | } | ||
1066 | } | 1165 | } |
1067 | return 0; | 1166 | return 0; |
1068 | } | 1167 | } |
@@ -1424,7 +1523,7 @@ static int fimc_subdev_set_fmt(struct v4l2_subdev *sd, | |||
1424 | /* Update RGB Alpha control state and value range */ | 1523 | /* Update RGB Alpha control state and value range */ |
1425 | fimc_alpha_ctrl_update(ctx); | 1524 | fimc_alpha_ctrl_update(ctx); |
1426 | 1525 | ||
1427 | fimc_capture_mark_jpeg_xfer(ctx, fimc_fmt_is_jpeg(ffmt->color)); | 1526 | fimc_capture_mark_jpeg_xfer(ctx, ffmt->color); |
1428 | 1527 | ||
1429 | ff = fmt->pad == FIMC_SD_PAD_SINK ? | 1528 | ff = fmt->pad == FIMC_SD_PAD_SINK ? |
1430 | &ctx->s_frame : &ctx->d_frame; | 1529 | &ctx->s_frame : &ctx->d_frame; |