aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSylwester Nawrocki <s.nawrocki@samsung.com>2011-02-23 06:24:33 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-03-22 03:54:15 -0400
commit4ecbf5d1d2bb7d1e3882de79e512c1a0a2816581 (patch)
tree42270272224cdc3532f0923a8317adfecd0d6dcc
parenta0f8caefaf3295721ef00415c7d63ec10af253ab (diff)
[media] s5p-fimc: Prevent hanging on device close and fix the locking
Rework the locking in m2m driver to assure proper operation on SMP systems. When job_abort or stop_streaming was called to immediately shutdown a memory-to-memory transaction video buffers scheduled for processing were never returned to vb2 and v4l2_m2m_job_finish was not called which led to hanging. Correct this and also return the unprocessed buffers to vb2 marking them as erroneous, in case the end of frame interrupt do not occur. Reported-by: Sewoon Park <seuni.park@samsung.com> 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.c9
-rw-r--r--drivers/media/video/s5p-fimc/fimc-core.c197
-rw-r--r--drivers/media/video/s5p-fimc/fimc-core.h44
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
310static int stop_streaming(struct vb2_queue *q) 310static 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. */
329static 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
351static 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
327static void fimc_capture_handler(struct fimc_dev *fimc) 360static 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
412isr_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
656dma_unlock: 684dma_unlock:
657 spin_unlock_irqrestore(&ctx->slock, flags); 685 spin_unlock_irqrestore(&ctx->slock, flags);
@@ -659,17 +687,7 @@ dma_unlock:
659 687
660static void fimc_job_abort(void *priv) 688static 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
675static int fimc_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, 693static 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
1267static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr) 1273static 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
81enum fimc_datapath { 74enum 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
473static 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
485static 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
494static 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
479static inline int tiled_fmt(struct fimc_fmt *fmt) 505static 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);