diff options
-rw-r--r-- | drivers/media/video/s5p-fimc/fimc-capture.c | 9 | ||||
-rw-r--r-- | drivers/media/video/s5p-fimc/fimc-core.c | 197 | ||||
-rw-r--r-- | drivers/media/video/s5p-fimc/fimc-core.h | 44 |
3 files changed, 136 insertions, 114 deletions
diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 423931c0cfe5..8312ce465f16 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c | |||
@@ -252,14 +252,9 @@ static int stop_streaming(struct vb2_queue *q) | |||
252 | { | 252 | { |
253 | struct fimc_ctx *ctx = q->drv_priv; | 253 | struct fimc_ctx *ctx = q->drv_priv; |
254 | struct fimc_dev *fimc = ctx->fimc_dev; | 254 | struct fimc_dev *fimc = ctx->fimc_dev; |
255 | unsigned long flags; | ||
256 | 255 | ||
257 | spin_lock_irqsave(&fimc->slock, flags); | 256 | if (!fimc_capture_active(fimc)) |
258 | if (!fimc_capture_running(fimc) && !fimc_capture_pending(fimc)) { | ||
259 | spin_unlock_irqrestore(&fimc->slock, flags); | ||
260 | return -EINVAL; | 257 | return -EINVAL; |
261 | } | ||
262 | spin_unlock_irqrestore(&fimc->slock, flags); | ||
263 | 258 | ||
264 | return fimc_stop_capture(fimc); | 259 | return fimc_stop_capture(fimc); |
265 | } | 260 | } |
@@ -773,7 +768,7 @@ static int fimc_cap_s_crop(struct file *file, void *fh, | |||
773 | ctx->d_frame.width, ctx->d_frame.height, | 768 | ctx->d_frame.width, ctx->d_frame.height, |
774 | ctx->rotation); | 769 | ctx->rotation); |
775 | if (ret) { | 770 | if (ret) { |
776 | v4l2_err(&fimc->vid_cap.v4l2_dev, "Out of the scaler range"); | 771 | v4l2_err(&fimc->vid_cap.v4l2_dev, "Out of the scaler range\n"); |
777 | return ret; | 772 | return ret; |
778 | } | 773 | } |
779 | 774 | ||
diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index fdf4270fcb62..f506197201c8 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c | |||
@@ -307,24 +307,57 @@ int fimc_set_scaler_info(struct fimc_ctx *ctx) | |||
307 | return 0; | 307 | return 0; |
308 | } | 308 | } |
309 | 309 | ||
310 | static int stop_streaming(struct vb2_queue *q) | 310 | static void fimc_m2m_job_finish(struct fimc_ctx *ctx, int vb_state) |
311 | { | 311 | { |
312 | struct fimc_ctx *ctx = q->drv_priv; | 312 | struct vb2_buffer *src_vb, *dst_vb; |
313 | struct fimc_dev *fimc = ctx->fimc_dev; | 313 | struct fimc_dev *fimc = ctx->fimc_dev; |
314 | 314 | ||
315 | if (!ctx || !ctx->m2m_ctx) | ||
316 | return; | ||
317 | |||
318 | src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); | ||
319 | dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); | ||
320 | |||
321 | if (src_vb && dst_vb) { | ||
322 | v4l2_m2m_buf_done(src_vb, vb_state); | ||
323 | v4l2_m2m_buf_done(dst_vb, vb_state); | ||
324 | v4l2_m2m_job_finish(fimc->m2m.m2m_dev, ctx->m2m_ctx); | ||
325 | } | ||
326 | } | ||
327 | |||
328 | /* Complete the transaction which has been scheduled for execution. */ | ||
329 | static void fimc_m2m_shutdown(struct fimc_ctx *ctx) | ||
330 | { | ||
331 | struct fimc_dev *fimc = ctx->fimc_dev; | ||
332 | int ret; | ||
333 | |||
315 | if (!fimc_m2m_pending(fimc)) | 334 | if (!fimc_m2m_pending(fimc)) |
316 | return 0; | 335 | return; |
317 | 336 | ||
318 | set_bit(ST_M2M_SHUT, &fimc->state); | 337 | fimc_ctx_state_lock_set(FIMC_CTX_SHUT, ctx); |
319 | 338 | ||
320 | wait_event_timeout(fimc->irq_queue, | 339 | ret = wait_event_timeout(fimc->irq_queue, |
321 | !test_bit(ST_M2M_SHUT, &fimc->state), | 340 | !fimc_ctx_state_is_set(FIMC_CTX_SHUT, ctx), |
322 | FIMC_SHUTDOWN_TIMEOUT); | 341 | FIMC_SHUTDOWN_TIMEOUT); |
342 | /* | ||
343 | * In case of a timeout the buffers are not released in the interrupt | ||
344 | * handler so return them here with the error flag set, if there are | ||
345 | * any on the queue. | ||
346 | */ | ||
347 | if (ret == 0) | ||
348 | fimc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR); | ||
349 | } | ||
350 | |||
351 | static int stop_streaming(struct vb2_queue *q) | ||
352 | { | ||
353 | struct fimc_ctx *ctx = q->drv_priv; | ||
354 | |||
355 | fimc_m2m_shutdown(ctx); | ||
323 | 356 | ||
324 | return 0; | 357 | return 0; |
325 | } | 358 | } |
326 | 359 | ||
327 | static void fimc_capture_handler(struct fimc_dev *fimc) | 360 | static void fimc_capture_irq_handler(struct fimc_dev *fimc) |
328 | { | 361 | { |
329 | struct fimc_vid_cap *cap = &fimc->vid_cap; | 362 | struct fimc_vid_cap *cap = &fimc->vid_cap; |
330 | struct fimc_vid_buffer *v_buf; | 363 | struct fimc_vid_buffer *v_buf; |
@@ -373,33 +406,28 @@ static irqreturn_t fimc_isr(int irq, void *priv) | |||
373 | { | 406 | { |
374 | struct fimc_dev *fimc = priv; | 407 | struct fimc_dev *fimc = priv; |
375 | struct fimc_vid_cap *cap = &fimc->vid_cap; | 408 | struct fimc_vid_cap *cap = &fimc->vid_cap; |
409 | struct fimc_ctx *ctx; | ||
376 | 410 | ||
377 | BUG_ON(!fimc); | ||
378 | fimc_hw_clear_irq(fimc); | 411 | fimc_hw_clear_irq(fimc); |
379 | 412 | ||
380 | spin_lock(&fimc->slock); | 413 | if (test_and_clear_bit(ST_M2M_PEND, &fimc->state)) { |
414 | ctx = v4l2_m2m_get_curr_priv(fimc->m2m.m2m_dev); | ||
415 | if (ctx != NULL) { | ||
416 | fimc_m2m_job_finish(ctx, VB2_BUF_STATE_DONE); | ||
381 | 417 | ||
382 | if (test_and_clear_bit(ST_M2M_SHUT, &fimc->state)) { | 418 | spin_lock(&ctx->slock); |
383 | wake_up(&fimc->irq_queue); | 419 | if (ctx->state & FIMC_CTX_SHUT) { |
384 | goto isr_unlock; | 420 | ctx->state &= ~FIMC_CTX_SHUT; |
385 | } else if (test_and_clear_bit(ST_M2M_PEND, &fimc->state)) { | 421 | wake_up(&fimc->irq_queue); |
386 | struct vb2_buffer *src_vb, *dst_vb; | 422 | } |
387 | struct fimc_ctx *ctx = v4l2_m2m_get_curr_priv(fimc->m2m.m2m_dev); | 423 | spin_unlock(&ctx->slock); |
388 | |||
389 | if (!ctx || !ctx->m2m_ctx) | ||
390 | goto isr_unlock; | ||
391 | |||
392 | src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); | ||
393 | dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); | ||
394 | if (src_vb && dst_vb) { | ||
395 | v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE); | ||
396 | v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE); | ||
397 | v4l2_m2m_job_finish(fimc->m2m.m2m_dev, ctx->m2m_ctx); | ||
398 | } | 424 | } |
399 | goto isr_unlock; | ||
400 | 425 | ||
426 | return IRQ_HANDLED; | ||
401 | } | 427 | } |
402 | 428 | ||
429 | spin_lock(&fimc->slock); | ||
430 | |||
403 | if (test_bit(ST_CAPT_PEND, &fimc->state)) { | 431 | if (test_bit(ST_CAPT_PEND, &fimc->state)) { |
404 | fimc_capture_irq_handler(fimc); | 432 | fimc_capture_irq_handler(fimc); |
405 | 433 | ||
@@ -409,7 +437,6 @@ static irqreturn_t fimc_isr(int irq, void *priv) | |||
409 | } | 437 | } |
410 | } | 438 | } |
411 | 439 | ||
412 | isr_unlock: | ||
413 | spin_unlock(&fimc->slock); | 440 | spin_unlock(&fimc->slock); |
414 | return IRQ_HANDLED; | 441 | return IRQ_HANDLED; |
415 | } | 442 | } |
@@ -613,26 +640,26 @@ static void fimc_dma_run(void *priv) | |||
613 | 640 | ||
614 | ctx->state |= (FIMC_SRC_ADDR | FIMC_DST_ADDR); | 641 | ctx->state |= (FIMC_SRC_ADDR | FIMC_DST_ADDR); |
615 | ret = fimc_prepare_config(ctx, ctx->state); | 642 | ret = fimc_prepare_config(ctx, ctx->state); |
616 | if (ret) { | 643 | if (ret) |
617 | err("Wrong parameters"); | ||
618 | goto dma_unlock; | 644 | goto dma_unlock; |
619 | } | 645 | |
620 | /* Reconfigure hardware if the context has changed. */ | 646 | /* Reconfigure hardware if the context has changed. */ |
621 | if (fimc->m2m.ctx != ctx) { | 647 | if (fimc->m2m.ctx != ctx) { |
622 | ctx->state |= FIMC_PARAMS; | 648 | ctx->state |= FIMC_PARAMS; |
623 | fimc->m2m.ctx = ctx; | 649 | fimc->m2m.ctx = ctx; |
624 | } | 650 | } |
625 | 651 | ||
652 | spin_lock(&fimc->slock); | ||
626 | fimc_hw_set_input_addr(fimc, &ctx->s_frame.paddr); | 653 | fimc_hw_set_input_addr(fimc, &ctx->s_frame.paddr); |
627 | 654 | ||
628 | if (ctx->state & FIMC_PARAMS) { | 655 | if (ctx->state & FIMC_PARAMS) { |
629 | fimc_hw_set_input_path(ctx); | 656 | fimc_hw_set_input_path(ctx); |
630 | fimc_hw_set_in_dma(ctx); | 657 | fimc_hw_set_in_dma(ctx); |
631 | if (fimc_set_scaler_info(ctx)) { | 658 | ret = fimc_set_scaler_info(ctx); |
632 | err("Scaler setup error"); | 659 | if (ret) { |
660 | spin_unlock(&fimc->slock); | ||
633 | goto dma_unlock; | 661 | goto dma_unlock; |
634 | } | 662 | } |
635 | |||
636 | fimc_hw_set_prescaler(ctx); | 663 | fimc_hw_set_prescaler(ctx); |
637 | fimc_hw_set_mainscaler(ctx); | 664 | fimc_hw_set_mainscaler(ctx); |
638 | fimc_hw_set_target_format(ctx); | 665 | fimc_hw_set_target_format(ctx); |
@@ -652,6 +679,7 @@ static void fimc_dma_run(void *priv) | |||
652 | ctx->state &= (FIMC_CTX_M2M | FIMC_CTX_CAP | | 679 | ctx->state &= (FIMC_CTX_M2M | FIMC_CTX_CAP | |
653 | FIMC_SRC_FMT | FIMC_DST_FMT); | 680 | FIMC_SRC_FMT | FIMC_DST_FMT); |
654 | fimc_hw_activate_input_dma(fimc, true); | 681 | fimc_hw_activate_input_dma(fimc, true); |
682 | spin_unlock(&fimc->slock); | ||
655 | 683 | ||
656 | dma_unlock: | 684 | dma_unlock: |
657 | spin_unlock_irqrestore(&ctx->slock, flags); | 685 | spin_unlock_irqrestore(&ctx->slock, flags); |
@@ -659,17 +687,7 @@ dma_unlock: | |||
659 | 687 | ||
660 | static void fimc_job_abort(void *priv) | 688 | static void fimc_job_abort(void *priv) |
661 | { | 689 | { |
662 | struct fimc_ctx *ctx = priv; | 690 | fimc_m2m_shutdown(priv); |
663 | struct fimc_dev *fimc = ctx->fimc_dev; | ||
664 | |||
665 | if (!fimc_m2m_pending(fimc)) | ||
666 | return; | ||
667 | |||
668 | set_bit(ST_M2M_SHUT, &fimc->state); | ||
669 | |||
670 | wait_event_timeout(fimc->irq_queue, | ||
671 | !test_bit(ST_M2M_SHUT, &fimc->state), | ||
672 | FIMC_SHUTDOWN_TIMEOUT); | ||
673 | } | 691 | } |
674 | 692 | ||
675 | static int fimc_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, | 693 | static int fimc_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, |
@@ -843,7 +861,7 @@ int fimc_vidioc_try_fmt_mplane(struct file *file, void *priv, | |||
843 | 861 | ||
844 | 862 | ||
845 | if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | 863 | if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { |
846 | if (ctx->state & FIMC_CTX_CAP) | 864 | if (fimc_ctx_state_is_set(FIMC_CTX_CAP, ctx)) |
847 | return -EINVAL; | 865 | return -EINVAL; |
848 | is_output = 1; | 866 | is_output = 1; |
849 | } else if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | 867 | } else if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { |
@@ -920,9 +938,7 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *priv, | |||
920 | struct vb2_queue *vq; | 938 | struct vb2_queue *vq; |
921 | struct fimc_frame *frame; | 939 | struct fimc_frame *frame; |
922 | struct v4l2_pix_format_mplane *pix; | 940 | struct v4l2_pix_format_mplane *pix; |
923 | unsigned long flags; | ||
924 | int i, ret = 0; | 941 | int i, ret = 0; |
925 | u32 tmp; | ||
926 | 942 | ||
927 | ret = fimc_vidioc_try_fmt_mplane(file, priv, f); | 943 | ret = fimc_vidioc_try_fmt_mplane(file, priv, f); |
928 | if (ret) | 944 | if (ret) |
@@ -963,10 +979,10 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *priv, | |||
963 | frame->offs_h = 0; | 979 | frame->offs_h = 0; |
964 | frame->offs_v = 0; | 980 | frame->offs_v = 0; |
965 | 981 | ||
966 | spin_lock_irqsave(&ctx->slock, flags); | 982 | if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) |
967 | tmp = (frame == &ctx->d_frame) ? FIMC_DST_FMT : FIMC_SRC_FMT; | 983 | fimc_ctx_state_lock_set(FIMC_PARAMS | FIMC_DST_FMT, ctx); |
968 | ctx->state |= FIMC_PARAMS | tmp; | 984 | else |
969 | spin_unlock_irqrestore(&ctx->slock, flags); | 985 | fimc_ctx_state_lock_set(FIMC_PARAMS | FIMC_SRC_FMT, ctx); |
970 | 986 | ||
971 | dbg("f_w: %d, f_h: %d", frame->f_width, frame->f_height); | 987 | dbg("f_w: %d, f_h: %d", frame->f_width, frame->f_height); |
972 | 988 | ||
@@ -1009,9 +1025,9 @@ static int fimc_m2m_streamon(struct file *file, void *priv, | |||
1009 | 1025 | ||
1010 | /* The source and target color format need to be set */ | 1026 | /* The source and target color format need to be set */ |
1011 | if (V4L2_TYPE_IS_OUTPUT(type)) { | 1027 | if (V4L2_TYPE_IS_OUTPUT(type)) { |
1012 | if (~ctx->state & FIMC_SRC_FMT) | 1028 | if (!fimc_ctx_state_is_set(FIMC_SRC_FMT, ctx)) |
1013 | return -EINVAL; | 1029 | return -EINVAL; |
1014 | } else if (~ctx->state & FIMC_DST_FMT) { | 1030 | } else if (!fimc_ctx_state_is_set(FIMC_DST_FMT, ctx)) { |
1015 | return -EINVAL; | 1031 | return -EINVAL; |
1016 | } | 1032 | } |
1017 | 1033 | ||
@@ -1038,7 +1054,7 @@ int fimc_vidioc_queryctrl(struct file *file, void *priv, | |||
1038 | return 0; | 1054 | return 0; |
1039 | } | 1055 | } |
1040 | 1056 | ||
1041 | if (ctx->state & FIMC_CTX_CAP) { | 1057 | if (fimc_ctx_state_is_set(FIMC_CTX_CAP, ctx)) { |
1042 | return v4l2_subdev_call(ctx->fimc_dev->vid_cap.sd, | 1058 | return v4l2_subdev_call(ctx->fimc_dev->vid_cap.sd, |
1043 | core, queryctrl, qc); | 1059 | core, queryctrl, qc); |
1044 | } | 1060 | } |
@@ -1062,12 +1078,11 @@ int fimc_vidioc_g_ctrl(struct file *file, void *priv, | |||
1062 | ctrl->value = ctx->rotation; | 1078 | ctrl->value = ctx->rotation; |
1063 | break; | 1079 | break; |
1064 | default: | 1080 | default: |
1065 | if (ctx->state & FIMC_CTX_CAP) { | 1081 | if (fimc_ctx_state_is_set(FIMC_CTX_CAP, ctx)) { |
1066 | return v4l2_subdev_call(fimc->vid_cap.sd, core, | 1082 | return v4l2_subdev_call(fimc->vid_cap.sd, core, |
1067 | g_ctrl, ctrl); | 1083 | g_ctrl, ctrl); |
1068 | } else { | 1084 | } else { |
1069 | v4l2_err(&fimc->m2m.v4l2_dev, | 1085 | v4l2_err(&fimc->m2m.v4l2_dev, "Invalid control\n"); |
1070 | "Invalid control\n"); | ||
1071 | return -EINVAL; | 1086 | return -EINVAL; |
1072 | } | 1087 | } |
1073 | } | 1088 | } |
@@ -1097,11 +1112,8 @@ int fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_control *ctrl) | |||
1097 | { | 1112 | { |
1098 | struct samsung_fimc_variant *variant = ctx->fimc_dev->variant; | 1113 | struct samsung_fimc_variant *variant = ctx->fimc_dev->variant; |
1099 | struct fimc_dev *fimc = ctx->fimc_dev; | 1114 | struct fimc_dev *fimc = ctx->fimc_dev; |
1100 | unsigned long flags; | ||
1101 | int ret = 0; | 1115 | int ret = 0; |
1102 | 1116 | ||
1103 | spin_lock_irqsave(&ctx->slock, flags); | ||
1104 | |||
1105 | switch (ctrl->id) { | 1117 | switch (ctrl->id) { |
1106 | case V4L2_CID_HFLIP: | 1118 | case V4L2_CID_HFLIP: |
1107 | if (ctrl->value) | 1119 | if (ctrl->value) |
@@ -1118,37 +1130,30 @@ int fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_control *ctrl) | |||
1118 | break; | 1130 | break; |
1119 | 1131 | ||
1120 | case V4L2_CID_ROTATE: | 1132 | case V4L2_CID_ROTATE: |
1121 | if (!(~ctx->state & (FIMC_DST_FMT | FIMC_SRC_FMT))) { | 1133 | if (fimc_ctx_state_is_set(FIMC_DST_FMT | FIMC_SRC_FMT, ctx)) { |
1122 | ret = fimc_check_scaler_ratio(ctx->s_frame.width, | 1134 | ret = fimc_check_scaler_ratio(ctx->s_frame.width, |
1123 | ctx->s_frame.height, | 1135 | ctx->s_frame.height, ctx->d_frame.width, |
1124 | ctx->d_frame.width, | 1136 | ctx->d_frame.height, ctrl->value); |
1125 | ctx->d_frame.height, | 1137 | } |
1126 | ctrl->value); | 1138 | |
1127 | if (ret) { | 1139 | if (ret) { |
1128 | v4l2_err(&fimc->m2m.v4l2_dev, | 1140 | v4l2_err(&fimc->m2m.v4l2_dev, "Out of scaler range\n"); |
1129 | "Out of scaler range"); | 1141 | return -EINVAL; |
1130 | spin_unlock_irqrestore(&ctx->slock, flags); | ||
1131 | return -EINVAL; | ||
1132 | } | ||
1133 | } | 1142 | } |
1134 | 1143 | ||
1135 | /* Check for the output rotator availability */ | 1144 | /* Check for the output rotator availability */ |
1136 | if ((ctrl->value == 90 || ctrl->value == 270) && | 1145 | if ((ctrl->value == 90 || ctrl->value == 270) && |
1137 | (ctx->in_path == FIMC_DMA && !variant->has_out_rot)) { | 1146 | (ctx->in_path == FIMC_DMA && !variant->has_out_rot)) |
1138 | spin_unlock_irqrestore(&ctx->slock, flags); | ||
1139 | return -EINVAL; | 1147 | return -EINVAL; |
1140 | } else { | 1148 | ctx->rotation = ctrl->value; |
1141 | ctx->rotation = ctrl->value; | ||
1142 | } | ||
1143 | break; | 1149 | break; |
1144 | 1150 | ||
1145 | default: | 1151 | default: |
1146 | spin_unlock_irqrestore(&ctx->slock, flags); | ||
1147 | v4l2_err(&fimc->m2m.v4l2_dev, "Invalid control\n"); | 1152 | v4l2_err(&fimc->m2m.v4l2_dev, "Invalid control\n"); |
1148 | return -EINVAL; | 1153 | return -EINVAL; |
1149 | } | 1154 | } |
1150 | ctx->state |= FIMC_PARAMS; | 1155 | |
1151 | spin_unlock_irqrestore(&ctx->slock, flags); | 1156 | fimc_ctx_state_lock_set(FIMC_PARAMS, ctx); |
1152 | 1157 | ||
1153 | return 0; | 1158 | return 0; |
1154 | } | 1159 | } |
@@ -1208,6 +1213,7 @@ int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr) | |||
1208 | struct fimc_dev *fimc = ctx->fimc_dev; | 1213 | struct fimc_dev *fimc = ctx->fimc_dev; |
1209 | struct fimc_frame *f; | 1214 | struct fimc_frame *f; |
1210 | u32 min_size, halign, depth = 0; | 1215 | u32 min_size, halign, depth = 0; |
1216 | bool is_capture_ctx; | ||
1211 | int i; | 1217 | int i; |
1212 | 1218 | ||
1213 | if (cr->c.top < 0 || cr->c.left < 0) { | 1219 | if (cr->c.top < 0 || cr->c.left < 0) { |
@@ -1216,10 +1222,12 @@ int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr) | |||
1216 | return -EINVAL; | 1222 | return -EINVAL; |
1217 | } | 1223 | } |
1218 | 1224 | ||
1225 | is_capture_ctx = fimc_ctx_state_is_set(FIMC_CTX_CAP, ctx); | ||
1226 | |||
1219 | if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) | 1227 | if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) |
1220 | f = (ctx->state & FIMC_CTX_CAP) ? &ctx->s_frame : &ctx->d_frame; | 1228 | f = is_capture_ctx ? &ctx->s_frame : &ctx->d_frame; |
1221 | else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && | 1229 | else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && |
1222 | ctx->state & FIMC_CTX_M2M) | 1230 | !is_capture_ctx) |
1223 | f = &ctx->s_frame; | 1231 | f = &ctx->s_frame; |
1224 | else | 1232 | else |
1225 | return -EINVAL; | 1233 | return -EINVAL; |
@@ -1227,15 +1235,15 @@ int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr) | |||
1227 | min_size = (f == &ctx->s_frame) ? | 1235 | min_size = (f == &ctx->s_frame) ? |
1228 | fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize; | 1236 | fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize; |
1229 | 1237 | ||
1230 | if (ctx->state & FIMC_CTX_M2M) { | 1238 | /* Get pixel alignment constraints. */ |
1239 | if (is_capture_ctx) { | ||
1240 | min_size = 16; | ||
1241 | halign = 4; | ||
1242 | } else { | ||
1231 | if (fimc->id == 1 && fimc->variant->pix_hoff) | 1243 | if (fimc->id == 1 && fimc->variant->pix_hoff) |
1232 | halign = fimc_fmt_is_rgb(f->fmt->color) ? 0 : 1; | 1244 | halign = fimc_fmt_is_rgb(f->fmt->color) ? 0 : 1; |
1233 | else | 1245 | else |
1234 | halign = ffs(min_size) - 1; | 1246 | halign = ffs(min_size) - 1; |
1235 | /* there are more strict aligment requirements at camera interface */ | ||
1236 | } else { | ||
1237 | min_size = 16; | ||
1238 | halign = 4; | ||
1239 | } | 1247 | } |
1240 | 1248 | ||
1241 | for (i = 0; i < f->fmt->colplanes; i++) | 1249 | for (i = 0; i < f->fmt->colplanes; i++) |
@@ -1253,8 +1261,7 @@ int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr) | |||
1253 | cr->c.top = f->o_height - cr->c.height; | 1261 | cr->c.top = f->o_height - cr->c.height; |
1254 | 1262 | ||
1255 | cr->c.left = round_down(cr->c.left, min_size); | 1263 | cr->c.left = round_down(cr->c.left, min_size); |
1256 | cr->c.top = round_down(cr->c.top, | 1264 | cr->c.top = round_down(cr->c.top, is_capture_ctx ? 16 : 8); |
1257 | ctx->state & FIMC_CTX_M2M ? 8 : 16); | ||
1258 | 1265 | ||
1259 | dbg("l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d", | 1266 | dbg("l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d", |
1260 | cr->c.left, cr->c.top, cr->c.width, cr->c.height, | 1267 | cr->c.left, cr->c.top, cr->c.width, cr->c.height, |
@@ -1263,12 +1270,10 @@ int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr) | |||
1263 | return 0; | 1270 | return 0; |
1264 | } | 1271 | } |
1265 | 1272 | ||
1266 | |||
1267 | static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr) | 1273 | static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr) |
1268 | { | 1274 | { |
1269 | struct fimc_ctx *ctx = file->private_data; | 1275 | struct fimc_ctx *ctx = file->private_data; |
1270 | struct fimc_dev *fimc = ctx->fimc_dev; | 1276 | struct fimc_dev *fimc = ctx->fimc_dev; |
1271 | unsigned long flags; | ||
1272 | struct fimc_frame *f; | 1277 | struct fimc_frame *f; |
1273 | int ret; | 1278 | int ret; |
1274 | 1279 | ||
@@ -1279,9 +1284,8 @@ static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr) | |||
1279 | f = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ? | 1284 | f = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ? |
1280 | &ctx->s_frame : &ctx->d_frame; | 1285 | &ctx->s_frame : &ctx->d_frame; |
1281 | 1286 | ||
1282 | spin_lock_irqsave(&ctx->slock, flags); | ||
1283 | /* Check to see if scaling ratio is within supported range */ | 1287 | /* Check to see if scaling ratio is within supported range */ |
1284 | if (!(~ctx->state & (FIMC_DST_FMT | FIMC_SRC_FMT))) { | 1288 | if (fimc_ctx_state_is_set(FIMC_DST_FMT | FIMC_SRC_FMT, ctx)) { |
1285 | if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | 1289 | if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { |
1286 | ret = fimc_check_scaler_ratio(cr->c.width, cr->c.height, | 1290 | ret = fimc_check_scaler_ratio(cr->c.width, cr->c.height, |
1287 | ctx->d_frame.width, | 1291 | ctx->d_frame.width, |
@@ -1293,22 +1297,19 @@ static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr) | |||
1293 | cr->c.width, cr->c.height, | 1297 | cr->c.width, cr->c.height, |
1294 | ctx->rotation); | 1298 | ctx->rotation); |
1295 | } | 1299 | } |
1296 | |||
1297 | if (ret) { | 1300 | if (ret) { |
1298 | v4l2_err(&fimc->m2m.v4l2_dev, "Out of scaler range"); | 1301 | v4l2_err(&fimc->m2m.v4l2_dev, "Out of scaler range\n"); |
1299 | spin_unlock_irqrestore(&ctx->slock, flags); | ||
1300 | return -EINVAL; | 1302 | return -EINVAL; |
1301 | } | 1303 | } |
1302 | } | 1304 | } |
1303 | 1305 | ||
1304 | ctx->state |= FIMC_PARAMS; | ||
1305 | |||
1306 | f->offs_h = cr->c.left; | 1306 | f->offs_h = cr->c.left; |
1307 | f->offs_v = cr->c.top; | 1307 | f->offs_v = cr->c.top; |
1308 | f->width = cr->c.width; | 1308 | f->width = cr->c.width; |
1309 | f->height = cr->c.height; | 1309 | f->height = cr->c.height; |
1310 | 1310 | ||
1311 | spin_unlock_irqrestore(&ctx->slock, flags); | 1311 | fimc_ctx_state_lock_set(FIMC_PARAMS, ctx); |
1312 | |||
1312 | return 0; | 1313 | return 0; |
1313 | } | 1314 | } |
1314 | 1315 | ||
diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index 4829a2515076..41b135249d1f 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h | |||
@@ -14,6 +14,7 @@ | |||
14 | /*#define DEBUG*/ | 14 | /*#define DEBUG*/ |
15 | 15 | ||
16 | #include <linux/sched.h> | 16 | #include <linux/sched.h> |
17 | #include <linux/spinlock.h> | ||
17 | #include <linux/types.h> | 18 | #include <linux/types.h> |
18 | #include <linux/videodev2.h> | 19 | #include <linux/videodev2.h> |
19 | #include <linux/io.h> | 20 | #include <linux/io.h> |
@@ -57,7 +58,6 @@ enum fimc_dev_flags { | |||
57 | ST_IDLE, | 58 | ST_IDLE, |
58 | ST_OUTDMA_RUN, | 59 | ST_OUTDMA_RUN, |
59 | ST_M2M_PEND, | 60 | ST_M2M_PEND, |
60 | ST_M2M_SHUT, | ||
61 | /* for capture node */ | 61 | /* for capture node */ |
62 | ST_CAPT_PEND, | 62 | ST_CAPT_PEND, |
63 | ST_CAPT_RUN, | 63 | ST_CAPT_RUN, |
@@ -71,13 +71,6 @@ enum fimc_dev_flags { | |||
71 | #define fimc_capture_running(dev) test_bit(ST_CAPT_RUN, &(dev)->state) | 71 | #define fimc_capture_running(dev) test_bit(ST_CAPT_RUN, &(dev)->state) |
72 | #define fimc_capture_pending(dev) test_bit(ST_CAPT_PEND, &(dev)->state) | 72 | #define fimc_capture_pending(dev) test_bit(ST_CAPT_PEND, &(dev)->state) |
73 | 73 | ||
74 | #define fimc_capture_active(dev) \ | ||
75 | (test_bit(ST_CAPT_RUN, &(dev)->state) || \ | ||
76 | test_bit(ST_CAPT_PEND, &(dev)->state)) | ||
77 | |||
78 | #define fimc_capture_streaming(dev) \ | ||
79 | test_bit(ST_CAPT_STREAM, &(dev)->state) | ||
80 | |||
81 | enum fimc_datapath { | 74 | enum fimc_datapath { |
82 | FIMC_CAMERA, | 75 | FIMC_CAMERA, |
83 | FIMC_DMA, | 76 | FIMC_DMA, |
@@ -119,6 +112,7 @@ enum fimc_color_fmt { | |||
119 | #define FIMC_DST_FMT (1 << 4) | 112 | #define FIMC_DST_FMT (1 << 4) |
120 | #define FIMC_CTX_M2M (1 << 5) | 113 | #define FIMC_CTX_M2M (1 << 5) |
121 | #define FIMC_CTX_CAP (1 << 6) | 114 | #define FIMC_CTX_CAP (1 << 6) |
115 | #define FIMC_CTX_SHUT (1 << 7) | ||
122 | 116 | ||
123 | /* Image conversion flags */ | 117 | /* Image conversion flags */ |
124 | #define FIMC_IN_DMA_ACCESS_TILED (1 << 0) | 118 | #define FIMC_IN_DMA_ACCESS_TILED (1 << 0) |
@@ -476,6 +470,38 @@ struct fimc_ctx { | |||
476 | struct v4l2_m2m_ctx *m2m_ctx; | 470 | struct v4l2_m2m_ctx *m2m_ctx; |
477 | }; | 471 | }; |
478 | 472 | ||
473 | static inline bool fimc_capture_active(struct fimc_dev *fimc) | ||
474 | { | ||
475 | unsigned long flags; | ||
476 | bool ret; | ||
477 | |||
478 | spin_lock_irqsave(&fimc->slock, flags); | ||
479 | ret = !!(fimc->state & (1 << ST_CAPT_RUN) || | ||
480 | fimc->state & (1 << ST_CAPT_PEND)); | ||
481 | spin_unlock_irqrestore(&fimc->slock, flags); | ||
482 | return ret; | ||
483 | } | ||
484 | |||
485 | static inline void fimc_ctx_state_lock_set(u32 state, struct fimc_ctx *ctx) | ||
486 | { | ||
487 | unsigned long flags; | ||
488 | |||
489 | spin_lock_irqsave(&ctx->slock, flags); | ||
490 | ctx->state |= state; | ||
491 | spin_unlock_irqrestore(&ctx->slock, flags); | ||
492 | } | ||
493 | |||
494 | static inline bool fimc_ctx_state_is_set(u32 mask, struct fimc_ctx *ctx) | ||
495 | { | ||
496 | unsigned long flags; | ||
497 | bool ret; | ||
498 | |||
499 | spin_lock_irqsave(&ctx->slock, flags); | ||
500 | ret = (ctx->state & mask) == mask; | ||
501 | spin_unlock_irqrestore(&ctx->slock, flags); | ||
502 | return ret; | ||
503 | } | ||
504 | |||
479 | static inline int tiled_fmt(struct fimc_fmt *fmt) | 505 | static inline int tiled_fmt(struct fimc_fmt *fmt) |
480 | { | 506 | { |
481 | return fmt->fourcc == V4L2_PIX_FMT_NV12MT; | 507 | return fmt->fourcc == V4L2_PIX_FMT_NV12MT; |
@@ -535,7 +561,7 @@ static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx, | |||
535 | struct fimc_frame *frame; | 561 | struct fimc_frame *frame; |
536 | 562 | ||
537 | if (V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE == type) { | 563 | if (V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE == type) { |
538 | if (ctx->state & FIMC_CTX_M2M) | 564 | if (fimc_ctx_state_is_set(FIMC_CTX_M2M, ctx)) |
539 | frame = &ctx->s_frame; | 565 | frame = &ctx->s_frame; |
540 | else | 566 | else |
541 | return ERR_PTR(-EINVAL); | 567 | return ERR_PTR(-EINVAL); |