diff options
author | Andrzej Hajda <a.hajda@samsung.com> | 2012-08-21 07:05:32 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-10-02 12:58:04 -0400 |
commit | f9f715a95d07d3868bb30aeb20252b6b05d35d8f (patch) | |
tree | 53a684372a77a28412e06ad66855a6f9c747f000 /drivers/media | |
parent | 5565a2ad47cdd8e697a28137bd8379455667bc1c (diff) |
[media] s5p-mfc: added support for end of stream handling in MFC encoder
s5p-mfc encoder after receiving V4L2_ENC_CMD_STOP command
will instruct MFC device to release all encoded frames.
After dequeuing last encoded frame driver will generate
V4L2_EVENT_EOS event.
Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/platform/s5p-mfc/s5p_mfc.c | 43 | ||||
-rw-r--r-- | drivers/media/platform/s5p-mfc/s5p_mfc_common.h | 5 | ||||
-rw-r--r-- | drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c | 6 | ||||
-rw-r--r-- | drivers/media/platform/s5p-mfc/s5p_mfc_dec.c | 4 | ||||
-rw-r--r-- | drivers/media/platform/s5p-mfc/s5p_mfc_enc.c | 106 | ||||
-rw-r--r-- | drivers/media/platform/s5p-mfc/s5p_mfc_opr.c | 48 |
6 files changed, 177 insertions, 35 deletions
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 9360d5771823..776e6bc241fc 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/sched.h> | 19 | #include <linux/sched.h> |
20 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
21 | #include <linux/videodev2.h> | 21 | #include <linux/videodev2.h> |
22 | #include <media/v4l2-event.h> | ||
22 | #include <linux/workqueue.h> | 23 | #include <linux/workqueue.h> |
23 | #include <media/videobuf2-core.h> | 24 | #include <media/videobuf2-core.h> |
24 | #include "regs-mfc.h" | 25 | #include "regs-mfc.h" |
@@ -539,6 +540,40 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx, | |||
539 | } | 540 | } |
540 | } | 541 | } |
541 | 542 | ||
543 | static void s5p_mfc_handle_stream_complete(struct s5p_mfc_ctx *ctx, | ||
544 | unsigned int reason, unsigned int err) | ||
545 | { | ||
546 | struct s5p_mfc_dev *dev = ctx->dev; | ||
547 | struct s5p_mfc_buf *mb_entry; | ||
548 | |||
549 | mfc_debug(2, "Stream completed"); | ||
550 | |||
551 | s5p_mfc_clear_int_flags(dev); | ||
552 | ctx->int_type = reason; | ||
553 | ctx->int_err = err; | ||
554 | ctx->state = MFCINST_FINISHED; | ||
555 | |||
556 | spin_lock(&dev->irqlock); | ||
557 | if (!list_empty(&ctx->dst_queue)) { | ||
558 | mb_entry = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, | ||
559 | list); | ||
560 | list_del(&mb_entry->list); | ||
561 | ctx->dst_queue_cnt--; | ||
562 | vb2_set_plane_payload(mb_entry->b, 0, 0); | ||
563 | vb2_buffer_done(mb_entry->b, VB2_BUF_STATE_DONE); | ||
564 | } | ||
565 | spin_unlock(&dev->irqlock); | ||
566 | |||
567 | clear_work_bit(ctx); | ||
568 | |||
569 | if (test_and_clear_bit(0, &dev->hw_lock) == 0) | ||
570 | WARN_ON(1); | ||
571 | |||
572 | s5p_mfc_clock_off(); | ||
573 | wake_up(&ctx->queue); | ||
574 | s5p_mfc_try_run(dev); | ||
575 | } | ||
576 | |||
542 | /* Interrupt processing */ | 577 | /* Interrupt processing */ |
543 | static irqreturn_t s5p_mfc_irq(int irq, void *priv) | 578 | static irqreturn_t s5p_mfc_irq(int irq, void *priv) |
544 | { | 579 | { |
@@ -614,6 +649,11 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv) | |||
614 | case S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET: | 649 | case S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET: |
615 | s5p_mfc_handle_init_buffers(ctx, reason, err); | 650 | s5p_mfc_handle_init_buffers(ctx, reason, err); |
616 | break; | 651 | break; |
652 | |||
653 | case S5P_FIMV_R2H_CMD_ENC_COMPLETE_RET: | ||
654 | s5p_mfc_handle_stream_complete(ctx, reason, err); | ||
655 | break; | ||
656 | |||
617 | default: | 657 | default: |
618 | mfc_debug(2, "Unknown int reason\n"); | 658 | mfc_debug(2, "Unknown int reason\n"); |
619 | s5p_mfc_clear_int_flags(dev); | 659 | s5p_mfc_clear_int_flags(dev); |
@@ -889,9 +929,12 @@ static unsigned int s5p_mfc_poll(struct file *file, | |||
889 | goto end; | 929 | goto end; |
890 | } | 930 | } |
891 | mutex_unlock(&dev->mfc_mutex); | 931 | mutex_unlock(&dev->mfc_mutex); |
932 | poll_wait(file, &ctx->fh.wait, wait); | ||
892 | poll_wait(file, &src_q->done_wq, wait); | 933 | poll_wait(file, &src_q->done_wq, wait); |
893 | poll_wait(file, &dst_q->done_wq, wait); | 934 | poll_wait(file, &dst_q->done_wq, wait); |
894 | mutex_lock(&dev->mfc_mutex); | 935 | mutex_lock(&dev->mfc_mutex); |
936 | if (v4l2_event_pending(&ctx->fh)) | ||
937 | rc |= POLLPRI; | ||
895 | spin_lock_irqsave(&src_q->done_lock, flags); | 938 | spin_lock_irqsave(&src_q->done_lock, flags); |
896 | if (!list_empty(&src_q->done_list)) | 939 | if (!list_empty(&src_q->done_list)) |
897 | src_vb = list_first_entry(&src_q->done_list, struct vb2_buffer, | 940 | src_vb = list_first_entry(&src_q->done_list, struct vb2_buffer, |
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index bd5706a6bad1..8871f0de6efd 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h | |||
@@ -146,6 +146,9 @@ enum s5p_mfc_decode_arg { | |||
146 | MFC_DEC_RES_CHANGE, | 146 | MFC_DEC_RES_CHANGE, |
147 | }; | 147 | }; |
148 | 148 | ||
149 | #define MFC_BUF_FLAG_USED (1 << 0) | ||
150 | #define MFC_BUF_FLAG_EOS (1 << 1) | ||
151 | |||
149 | struct s5p_mfc_ctx; | 152 | struct s5p_mfc_ctx; |
150 | 153 | ||
151 | /** | 154 | /** |
@@ -161,7 +164,7 @@ struct s5p_mfc_buf { | |||
161 | } raw; | 164 | } raw; |
162 | size_t stream; | 165 | size_t stream; |
163 | } cookie; | 166 | } cookie; |
164 | int used; | 167 | int flags; |
165 | }; | 168 | }; |
166 | 169 | ||
167 | /** | 170 | /** |
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c index 992303d76b11..0deba6bc687c 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c | |||
@@ -98,7 +98,11 @@ int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev) | |||
98 | release_firmware(fw_blob); | 98 | release_firmware(fw_blob); |
99 | return -EIO; | 99 | return -EIO; |
100 | } | 100 | } |
101 | dev->bank2 = bank2_base_phys; | 101 | /* Valid buffers passed to MFC encoder with LAST_FRAME command |
102 | * should not have address of bank2 - MFC will treat it as a null frame. | ||
103 | * To avoid such situation we set bank2 address below the pool address. | ||
104 | */ | ||
105 | dev->bank2 = bank2_base_phys - (1 << MFC_BASE_ALIGN_ORDER); | ||
102 | memcpy(s5p_mfc_bitproc_virt, fw_blob->data, fw_blob->size); | 106 | memcpy(s5p_mfc_bitproc_virt, fw_blob->data, fw_blob->size); |
103 | wmb(); | 107 | wmb(); |
104 | release_firmware(fw_blob); | 108 | release_firmware(fw_blob); |
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index 456f5df6b179..aef83d13182c 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c | |||
@@ -936,14 +936,14 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb) | |||
936 | 936 | ||
937 | if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | 937 | if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { |
938 | mfc_buf = &ctx->src_bufs[vb->v4l2_buf.index]; | 938 | mfc_buf = &ctx->src_bufs[vb->v4l2_buf.index]; |
939 | mfc_buf->used = 0; | 939 | mfc_buf->flags &= ~MFC_BUF_FLAG_USED; |
940 | spin_lock_irqsave(&dev->irqlock, flags); | 940 | spin_lock_irqsave(&dev->irqlock, flags); |
941 | list_add_tail(&mfc_buf->list, &ctx->src_queue); | 941 | list_add_tail(&mfc_buf->list, &ctx->src_queue); |
942 | ctx->src_queue_cnt++; | 942 | ctx->src_queue_cnt++; |
943 | spin_unlock_irqrestore(&dev->irqlock, flags); | 943 | spin_unlock_irqrestore(&dev->irqlock, flags); |
944 | } else if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | 944 | } else if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { |
945 | mfc_buf = &ctx->dst_bufs[vb->v4l2_buf.index]; | 945 | mfc_buf = &ctx->dst_bufs[vb->v4l2_buf.index]; |
946 | mfc_buf->used = 0; | 946 | mfc_buf->flags &= ~MFC_BUF_FLAG_USED; |
947 | /* Mark destination as available for use by MFC */ | 947 | /* Mark destination as available for use by MFC */ |
948 | spin_lock_irqsave(&dev->irqlock, flags); | 948 | spin_lock_irqsave(&dev->irqlock, flags); |
949 | set_bit(vb->v4l2_buf.index, &ctx->dec_dst_flag); | 949 | set_bit(vb->v4l2_buf.index, &ctx->dec_dst_flag); |
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index fdeebb031b45..075cc5c5f9bc 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/sched.h> | 21 | #include <linux/sched.h> |
22 | #include <linux/version.h> | 22 | #include <linux/version.h> |
23 | #include <linux/videodev2.h> | 23 | #include <linux/videodev2.h> |
24 | #include <media/v4l2-event.h> | ||
24 | #include <linux/workqueue.h> | 25 | #include <linux/workqueue.h> |
25 | #include <media/v4l2-ctrls.h> | 26 | #include <media/v4l2-ctrls.h> |
26 | #include <media/videobuf2-core.h> | 27 | #include <media/videobuf2-core.h> |
@@ -576,9 +577,9 @@ static int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx) | |||
576 | if (ctx->state == MFCINST_RUNNING && | 577 | if (ctx->state == MFCINST_RUNNING && |
577 | ctx->src_queue_cnt >= 1 && ctx->dst_queue_cnt >= 1) | 578 | ctx->src_queue_cnt >= 1 && ctx->dst_queue_cnt >= 1) |
578 | return 1; | 579 | return 1; |
579 | /* context is ready to encode remain frames */ | 580 | /* context is ready to encode remaining frames */ |
580 | if (ctx->state == MFCINST_FINISHING && | 581 | if (ctx->state == MFCINST_FINISHING && |
581 | ctx->src_queue_cnt >= 1 && ctx->dst_queue_cnt >= 1) | 582 | ctx->dst_queue_cnt >= 1) |
582 | return 1; | 583 | return 1; |
583 | mfc_debug(2, "ctx is not ready\n"); | 584 | mfc_debug(2, "ctx is not ready\n"); |
584 | return 0; | 585 | return 0; |
@@ -724,7 +725,7 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx) | |||
724 | if ((ctx->src_queue_cnt > 0) && (ctx->state == MFCINST_RUNNING)) { | 725 | if ((ctx->src_queue_cnt > 0) && (ctx->state == MFCINST_RUNNING)) { |
725 | mb_entry = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, | 726 | mb_entry = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, |
726 | list); | 727 | list); |
727 | if (mb_entry->used) { | 728 | if (mb_entry->flags & MFC_BUF_FLAG_USED) { |
728 | list_del(&mb_entry->list); | 729 | list_del(&mb_entry->list); |
729 | ctx->src_queue_cnt--; | 730 | ctx->src_queue_cnt--; |
730 | list_add_tail(&mb_entry->list, &ctx->ref_queue); | 731 | list_add_tail(&mb_entry->list, &ctx->ref_queue); |
@@ -1119,27 +1120,43 @@ static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) | |||
1119 | mfc_err("Call on QBUF after unrecoverable error\n"); | 1120 | mfc_err("Call on QBUF after unrecoverable error\n"); |
1120 | return -EIO; | 1121 | return -EIO; |
1121 | } | 1122 | } |
1122 | if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) | 1123 | if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { |
1124 | if (ctx->state == MFCINST_FINISHING) { | ||
1125 | mfc_err("Call on QBUF after EOS command\n"); | ||
1126 | return -EIO; | ||
1127 | } | ||
1123 | return vb2_qbuf(&ctx->vq_src, buf); | 1128 | return vb2_qbuf(&ctx->vq_src, buf); |
1124 | else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) | 1129 | } else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { |
1125 | return vb2_qbuf(&ctx->vq_dst, buf); | 1130 | return vb2_qbuf(&ctx->vq_dst, buf); |
1131 | } | ||
1126 | return -EINVAL; | 1132 | return -EINVAL; |
1127 | } | 1133 | } |
1128 | 1134 | ||
1129 | /* Dequeue a buffer */ | 1135 | /* Dequeue a buffer */ |
1130 | static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) | 1136 | static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) |
1131 | { | 1137 | { |
1138 | const struct v4l2_event ev = { | ||
1139 | .type = V4L2_EVENT_EOS | ||
1140 | }; | ||
1132 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | 1141 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); |
1142 | int ret; | ||
1133 | 1143 | ||
1134 | if (ctx->state == MFCINST_ERROR) { | 1144 | if (ctx->state == MFCINST_ERROR) { |
1135 | mfc_err("Call on DQBUF after unrecoverable error\n"); | 1145 | mfc_err("Call on DQBUF after unrecoverable error\n"); |
1136 | return -EIO; | 1146 | return -EIO; |
1137 | } | 1147 | } |
1138 | if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) | 1148 | if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { |
1139 | return vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK); | 1149 | ret = vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK); |
1140 | else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) | 1150 | } else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { |
1141 | return vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK); | 1151 | ret = vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK); |
1142 | return -EINVAL; | 1152 | if (ret == 0 && ctx->state == MFCINST_FINISHED |
1153 | && list_empty(&ctx->vq_dst.done_list)) | ||
1154 | v4l2_event_queue_fh(&ctx->fh, &ev); | ||
1155 | } else { | ||
1156 | ret = -EINVAL; | ||
1157 | } | ||
1158 | |||
1159 | return ret; | ||
1143 | } | 1160 | } |
1144 | 1161 | ||
1145 | /* Stream on */ | 1162 | /* Stream on */ |
@@ -1471,6 +1488,57 @@ static int vidioc_g_parm(struct file *file, void *priv, | |||
1471 | return 0; | 1488 | return 0; |
1472 | } | 1489 | } |
1473 | 1490 | ||
1491 | int vidioc_encoder_cmd(struct file *file, void *priv, | ||
1492 | struct v4l2_encoder_cmd *cmd) | ||
1493 | { | ||
1494 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | ||
1495 | struct s5p_mfc_dev *dev = ctx->dev; | ||
1496 | struct s5p_mfc_buf *buf; | ||
1497 | unsigned long flags; | ||
1498 | |||
1499 | switch (cmd->cmd) { | ||
1500 | case V4L2_ENC_CMD_STOP: | ||
1501 | if (cmd->flags != 0) | ||
1502 | return -EINVAL; | ||
1503 | |||
1504 | if (!ctx->vq_src.streaming) | ||
1505 | return -EINVAL; | ||
1506 | |||
1507 | spin_lock_irqsave(&dev->irqlock, flags); | ||
1508 | if (list_empty(&ctx->src_queue)) { | ||
1509 | mfc_debug(2, "EOS: empty src queue, entering finishing state"); | ||
1510 | ctx->state = MFCINST_FINISHING; | ||
1511 | spin_unlock_irqrestore(&dev->irqlock, flags); | ||
1512 | s5p_mfc_try_run(dev); | ||
1513 | } else { | ||
1514 | mfc_debug(2, "EOS: marking last buffer of stream"); | ||
1515 | buf = list_entry(ctx->src_queue.prev, | ||
1516 | struct s5p_mfc_buf, list); | ||
1517 | if (buf->flags & MFC_BUF_FLAG_USED) | ||
1518 | ctx->state = MFCINST_FINISHING; | ||
1519 | else | ||
1520 | buf->flags |= MFC_BUF_FLAG_EOS; | ||
1521 | spin_unlock_irqrestore(&dev->irqlock, flags); | ||
1522 | } | ||
1523 | break; | ||
1524 | default: | ||
1525 | return -EINVAL; | ||
1526 | |||
1527 | } | ||
1528 | return 0; | ||
1529 | } | ||
1530 | |||
1531 | static int vidioc_subscribe_event(struct v4l2_fh *fh, | ||
1532 | struct v4l2_event_subscription *sub) | ||
1533 | { | ||
1534 | switch (sub->type) { | ||
1535 | case V4L2_EVENT_EOS: | ||
1536 | return v4l2_event_subscribe(fh, sub, 2, NULL); | ||
1537 | default: | ||
1538 | return -EINVAL; | ||
1539 | } | ||
1540 | } | ||
1541 | |||
1474 | static const struct v4l2_ioctl_ops s5p_mfc_enc_ioctl_ops = { | 1542 | static const struct v4l2_ioctl_ops s5p_mfc_enc_ioctl_ops = { |
1475 | .vidioc_querycap = vidioc_querycap, | 1543 | .vidioc_querycap = vidioc_querycap, |
1476 | .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, | 1544 | .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, |
@@ -1491,6 +1559,9 @@ static const struct v4l2_ioctl_ops s5p_mfc_enc_ioctl_ops = { | |||
1491 | .vidioc_streamoff = vidioc_streamoff, | 1559 | .vidioc_streamoff = vidioc_streamoff, |
1492 | .vidioc_s_parm = vidioc_s_parm, | 1560 | .vidioc_s_parm = vidioc_s_parm, |
1493 | .vidioc_g_parm = vidioc_g_parm, | 1561 | .vidioc_g_parm = vidioc_g_parm, |
1562 | .vidioc_encoder_cmd = vidioc_encoder_cmd, | ||
1563 | .vidioc_subscribe_event = vidioc_subscribe_event, | ||
1564 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | ||
1494 | }; | 1565 | }; |
1495 | 1566 | ||
1496 | static int check_vb_with_fmt(struct s5p_mfc_fmt *fmt, struct vb2_buffer *vb) | 1567 | static int check_vb_with_fmt(struct s5p_mfc_fmt *fmt, struct vb2_buffer *vb) |
@@ -1706,7 +1777,7 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb) | |||
1706 | } | 1777 | } |
1707 | if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | 1778 | if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { |
1708 | mfc_buf = &ctx->dst_bufs[vb->v4l2_buf.index]; | 1779 | mfc_buf = &ctx->dst_bufs[vb->v4l2_buf.index]; |
1709 | mfc_buf->used = 0; | 1780 | mfc_buf->flags &= ~MFC_BUF_FLAG_USED; |
1710 | /* Mark destination as available for use by MFC */ | 1781 | /* Mark destination as available for use by MFC */ |
1711 | spin_lock_irqsave(&dev->irqlock, flags); | 1782 | spin_lock_irqsave(&dev->irqlock, flags); |
1712 | list_add_tail(&mfc_buf->list, &ctx->dst_queue); | 1783 | list_add_tail(&mfc_buf->list, &ctx->dst_queue); |
@@ -1714,17 +1785,10 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb) | |||
1714 | spin_unlock_irqrestore(&dev->irqlock, flags); | 1785 | spin_unlock_irqrestore(&dev->irqlock, flags); |
1715 | } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | 1786 | } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { |
1716 | mfc_buf = &ctx->src_bufs[vb->v4l2_buf.index]; | 1787 | mfc_buf = &ctx->src_bufs[vb->v4l2_buf.index]; |
1717 | mfc_buf->used = 0; | 1788 | mfc_buf->flags &= ~MFC_BUF_FLAG_USED; |
1718 | spin_lock_irqsave(&dev->irqlock, flags); | 1789 | spin_lock_irqsave(&dev->irqlock, flags); |
1719 | if (vb->v4l2_planes[0].bytesused == 0) { | 1790 | list_add_tail(&mfc_buf->list, &ctx->src_queue); |
1720 | mfc_debug(1, "change state to FINISHING\n"); | 1791 | ctx->src_queue_cnt++; |
1721 | ctx->state = MFCINST_FINISHING; | ||
1722 | vb2_buffer_done(vb, VB2_BUF_STATE_DONE); | ||
1723 | cleanup_ref_queue(ctx); | ||
1724 | } else { | ||
1725 | list_add_tail(&mfc_buf->list, &ctx->src_queue); | ||
1726 | ctx->src_queue_cnt++; | ||
1727 | } | ||
1728 | spin_unlock_irqrestore(&dev->irqlock, flags); | 1792 | spin_unlock_irqrestore(&dev->irqlock, flags); |
1729 | } else { | 1793 | } else { |
1730 | mfc_err("unsupported buffer type (%d)\n", vq->type); | 1794 | mfc_err("unsupported buffer type (%d)\n", vq->type); |
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c index b5fd3d4d5a7b..767a51271dc2 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c | |||
@@ -1075,14 +1075,21 @@ int s5p_mfc_init_encode(struct s5p_mfc_ctx *ctx) | |||
1075 | int s5p_mfc_encode_one_frame(struct s5p_mfc_ctx *ctx) | 1075 | int s5p_mfc_encode_one_frame(struct s5p_mfc_ctx *ctx) |
1076 | { | 1076 | { |
1077 | struct s5p_mfc_dev *dev = ctx->dev; | 1077 | struct s5p_mfc_dev *dev = ctx->dev; |
1078 | int cmd; | ||
1078 | /* memory structure cur. frame */ | 1079 | /* memory structure cur. frame */ |
1079 | if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) | 1080 | if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) |
1080 | mfc_write(dev, 0, S5P_FIMV_ENC_MAP_FOR_CUR); | 1081 | mfc_write(dev, 0, S5P_FIMV_ENC_MAP_FOR_CUR); |
1081 | else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT) | 1082 | else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT) |
1082 | mfc_write(dev, 3, S5P_FIMV_ENC_MAP_FOR_CUR); | 1083 | mfc_write(dev, 3, S5P_FIMV_ENC_MAP_FOR_CUR); |
1083 | s5p_mfc_set_shared_buffer(ctx); | 1084 | s5p_mfc_set_shared_buffer(ctx); |
1084 | mfc_write(dev, (S5P_FIMV_CH_FRAME_START << 16 & 0x70000) | | 1085 | |
1085 | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); | 1086 | if (ctx->state == MFCINST_FINISHING) |
1087 | cmd = S5P_FIMV_CH_LAST_FRAME; | ||
1088 | else | ||
1089 | cmd = S5P_FIMV_CH_FRAME_START; | ||
1090 | mfc_write(dev, ((cmd & S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT) | ||
1091 | | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); | ||
1092 | |||
1086 | return 0; | 1093 | return 0; |
1087 | } | 1094 | } |
1088 | 1095 | ||
@@ -1133,7 +1140,7 @@ static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame) | |||
1133 | } | 1140 | } |
1134 | /* Get the next source buffer */ | 1141 | /* Get the next source buffer */ |
1135 | temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); | 1142 | temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); |
1136 | temp_vb->used = 1; | 1143 | temp_vb->flags |= MFC_BUF_FLAG_USED; |
1137 | s5p_mfc_set_dec_stream_buffer(ctx, | 1144 | s5p_mfc_set_dec_stream_buffer(ctx, |
1138 | vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), ctx->consumed_stream, | 1145 | vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), ctx->consumed_stream, |
1139 | temp_vb->b->v4l2_planes[0].bytesused); | 1146 | temp_vb->b->v4l2_planes[0].bytesused); |
@@ -1160,7 +1167,7 @@ static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx) | |||
1160 | unsigned int dst_size; | 1167 | unsigned int dst_size; |
1161 | 1168 | ||
1162 | spin_lock_irqsave(&dev->irqlock, flags); | 1169 | spin_lock_irqsave(&dev->irqlock, flags); |
1163 | if (list_empty(&ctx->src_queue)) { | 1170 | if (list_empty(&ctx->src_queue) && ctx->state != MFCINST_FINISHING) { |
1164 | mfc_debug(2, "no src buffers\n"); | 1171 | mfc_debug(2, "no src buffers\n"); |
1165 | spin_unlock_irqrestore(&dev->irqlock, flags); | 1172 | spin_unlock_irqrestore(&dev->irqlock, flags); |
1166 | return -EAGAIN; | 1173 | return -EAGAIN; |
@@ -1170,19 +1177,40 @@ static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx) | |||
1170 | spin_unlock_irqrestore(&dev->irqlock, flags); | 1177 | spin_unlock_irqrestore(&dev->irqlock, flags); |
1171 | return -EAGAIN; | 1178 | return -EAGAIN; |
1172 | } | 1179 | } |
1173 | src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); | 1180 | if (list_empty(&ctx->src_queue)) { |
1174 | src_mb->used = 1; | 1181 | /* send null frame */ |
1175 | src_y_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 0); | 1182 | s5p_mfc_set_enc_frame_buffer(ctx, dev->bank2, dev->bank2); |
1176 | src_c_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 1); | 1183 | src_mb = NULL; |
1177 | s5p_mfc_set_enc_frame_buffer(ctx, src_y_addr, src_c_addr); | 1184 | } else { |
1185 | src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, | ||
1186 | list); | ||
1187 | src_mb->flags |= MFC_BUF_FLAG_USED; | ||
1188 | if (src_mb->b->v4l2_planes[0].bytesused == 0) { | ||
1189 | /* send null frame */ | ||
1190 | s5p_mfc_set_enc_frame_buffer(ctx, dev->bank2, | ||
1191 | dev->bank2); | ||
1192 | ctx->state = MFCINST_FINISHING; | ||
1193 | } else { | ||
1194 | src_y_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, | ||
1195 | 0); | ||
1196 | src_c_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, | ||
1197 | 1); | ||
1198 | s5p_mfc_set_enc_frame_buffer(ctx, src_y_addr, | ||
1199 | src_c_addr); | ||
1200 | if (src_mb->flags & MFC_BUF_FLAG_EOS) | ||
1201 | ctx->state = MFCINST_FINISHING; | ||
1202 | } | ||
1203 | } | ||
1178 | dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); | 1204 | dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); |
1179 | dst_mb->used = 1; | 1205 | dst_mb->flags |= MFC_BUF_FLAG_USED; |
1180 | dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0); | 1206 | dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0); |
1181 | dst_size = vb2_plane_size(dst_mb->b, 0); | 1207 | dst_size = vb2_plane_size(dst_mb->b, 0); |
1182 | s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size); | 1208 | s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size); |
1183 | spin_unlock_irqrestore(&dev->irqlock, flags); | 1209 | spin_unlock_irqrestore(&dev->irqlock, flags); |
1184 | dev->curr_ctx = ctx->num; | 1210 | dev->curr_ctx = ctx->num; |
1185 | s5p_mfc_clean_ctx_int_flags(ctx); | 1211 | s5p_mfc_clean_ctx_int_flags(ctx); |
1212 | mfc_debug(2, "encoding buffer with index=%d state=%d", | ||
1213 | src_mb ? src_mb->b->v4l2_buf.index : -1, ctx->state); | ||
1186 | s5p_mfc_encode_one_frame(ctx); | 1214 | s5p_mfc_encode_one_frame(ctx); |
1187 | return 0; | 1215 | return 0; |
1188 | } | 1216 | } |