Add support for dynamic encoding parameter changes in MFCv6.  Parameters
set are applied with the next OUTPUT buffer queued to the device with
VIDIOC_QBUF.

Supported parameters are:

* GOP size (V4L2_CID_MPEG_VIDEO_GOP_SIZE)
* framerate (from VIDIOC_S_PARM)
* VBR target bitrate (V4L2_CID_MPEG_VIDEO_BITRATE)
* (h264) frame type (V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE)

Signed-off-by: John Sheu <s...@google.com>
---
 drivers/media/platform/s5p-mfc/regs-mfc-v6.h    |  4 ++
 drivers/media/platform/s5p-mfc/s5p_mfc_common.h | 32 +++++++--
 drivers/media/platform/s5p-mfc/s5p_mfc_enc.c    | 53 +++++++++++---
 drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c | 29 ++++----
 drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c | 94 ++++++++++++++-----------
 5 files changed, 140 insertions(+), 72 deletions(-)

diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v6.h 
b/drivers/media/platform/s5p-mfc/regs-mfc-v6.h
index 2398cdf..495ed21 100644
--- a/drivers/media/platform/s5p-mfc/regs-mfc-v6.h
+++ b/drivers/media/platform/s5p-mfc/regs-mfc-v6.h
@@ -330,6 +330,10 @@
 #define S5P_FIMV_E_MVC_RC_RPARA_VIEW1_V6               0xfd50
 #define S5P_FIMV_E_MVC_INTER_VIEW_PREDICTION_ON_V6     0xfd80
 
+#define S5P_FIMV_E_GOP_CONFIG_CHANGE_SHIFT_V6          0
+#define S5P_FIMV_E_FRAME_RATE_CHANGE_SHIFT_V6          1
+#define S5P_FIMV_E_BIT_RATE_CHANGE_SHIFT_V6            2
+
 /* Codec numbers  */
 #define S5P_FIMV_CODEC_NONE_V6         -1
 
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h 
b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h
index 48f706f..af134fd 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h
@@ -173,12 +173,35 @@ enum s5p_mfc_decode_arg {
        MFC_DEC_RES_CHANGE,
 };
 
+
+/**
+ * enum s5p_mfc_encoder_param_change - indicates runtime parameter change
+ */
+enum s5p_mfc_encode_param_change {
+       MFC_ENC_GOP_CONFIG_CHANGE,
+       MFC_ENC_FRAME_RATE_CHANGE,
+       MFC_ENC_BIT_RATE_CHANGE,
+       MFC_ENC_FRAME_INSERTION,
+};
+
 #define MFC_BUF_FLAG_USED      (1 << 0)
 #define MFC_BUF_FLAG_EOS       (1 << 1)
 
 struct s5p_mfc_ctx;
 
 /**
+ * struct s5p_mfc_enc_params - runtime modifiable encoding parameters
+ */
+struct s5p_mfc_runtime_enc_params {
+       u32 params_changed;
+       u16 gop_size;
+       u32 rc_framerate_num;
+       u32 rc_framerate_denom;
+       u32 rc_bitrate;
+       enum v4l2_mpeg_mfc51_video_force_frame_type force_frame_type;
+};
+
+/**
  * struct s5p_mfc_buf - MFC buffer
  */
 struct s5p_mfc_buf {
@@ -192,6 +215,7 @@ struct s5p_mfc_buf {
                size_t stream;
        } cookie;
        int flags;
+       struct s5p_mfc_runtime_enc_params runtime_enc_params;
 };
 
 /**
@@ -433,7 +457,6 @@ struct s5p_mfc_enc_params {
        u16 crop_top_offset;
        u16 crop_bottom_offset;
 
-       u16 gop_size;
        enum v4l2_mpeg_video_multi_slice_mode slice_mode;
        u16 slice_mb;
        u32 slice_bit;
@@ -444,7 +467,6 @@ struct s5p_mfc_enc_params {
        u8 pad_cr;
        int rc_frame;
        int rc_mb;
-       u32 rc_bitrate;
        u16 rc_reaction_coeff;
        u16 vbv_size;
        u32 vbv_delay;
@@ -454,15 +476,13 @@ struct s5p_mfc_enc_params {
        int fixed_target_bit;
 
        u8 num_b_frame;
-       u32 rc_framerate_num;
-       u32 rc_framerate_denom;
 
        struct {
+               struct s5p_mfc_runtime_enc_params runtime;
                struct s5p_mfc_h264_enc_params h264;
                struct s5p_mfc_mpeg4_enc_params mpeg4;
                struct s5p_mfc_vp8_enc_params vp8;
        } codec;
-
 };
 
 /**
@@ -638,8 +658,6 @@ struct s5p_mfc_ctx {
        size_t me_buffer_size;
        size_t tmv_buffer_size;
 
-       enum v4l2_mpeg_mfc51_video_force_frame_type force_frame_type;
-
        struct list_head ref_queue;
        unsigned int ref_queue_cnt;
 
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c 
b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
index 4ad9349..0898dee 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
@@ -1342,7 +1342,9 @@ static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl)
 
        switch (ctrl->id) {
        case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
-               p->gop_size = ctrl->val;
+               p->codec.runtime.params_changed |=
+                       (1 << MFC_ENC_GOP_CONFIG_CHANGE);
+               p->codec.runtime.gop_size = ctrl->val;
                break;
        case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
                p->slice_mode = ctrl->val;
@@ -1368,13 +1370,17 @@ static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl)
                p->rc_frame = ctrl->val;
                break;
        case V4L2_CID_MPEG_VIDEO_BITRATE:
-               p->rc_bitrate = ctrl->val;
+               p->codec.runtime.params_changed |=
+                       (1 << MFC_ENC_BIT_RATE_CHANGE);
+               p->codec.runtime.rc_bitrate = ctrl->val;
                break;
        case V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF:
                p->rc_reaction_coeff = ctrl->val;
                break;
        case V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE:
-               ctx->force_frame_type = ctrl->val;
+               p->codec.runtime.params_changed |=
+                       (1 << MFC_ENC_FRAME_INSERTION);
+               p->codec.runtime.force_frame_type = ctrl->val;
                break;
        case V4L2_CID_MPEG_VIDEO_VBV_SIZE:
                p->vbv_size = ctrl->val;
@@ -1575,12 +1581,29 @@ static int vidioc_s_parm(struct file *file, void *priv,
                         struct v4l2_streamparm *a)
 {
        struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+       struct s5p_mfc_runtime_enc_params *runtime_params =
+               &ctx->enc_params.codec.runtime;
 
+       /*
+        * Note that MFC hardware specifies framerate but the V4L2 API specifies
+        * timeperframe. Take the reciprocal of one to get the other.
+        */
        if (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-               ctx->enc_params.rc_framerate_num =
-                                       a->parm.output.timeperframe.denominator;
-               ctx->enc_params.rc_framerate_denom =
-                                       a->parm.output.timeperframe.numerator;
+               if ((runtime_params->rc_framerate_num !=
+                       a->parm.output.timeperframe.denominator) ||
+                       (runtime_params->rc_framerate_denom !=
+                       a->parm.output.timeperframe.numerator)) {
+                       if (a->parm.output.timeperframe.numerator == 0) {
+                               mfc_err("Cannot set an infinite FPS\n");
+                               return -EINVAL;
+                       }
+                       runtime_params->params_changed |=
+                               (1 << MFC_ENC_FRAME_RATE_CHANGE);
+                       runtime_params->rc_framerate_num =
+                               a->parm.output.timeperframe.denominator;
+                       runtime_params->rc_framerate_denom =
+                               a->parm.output.timeperframe.numerator;
+               }
        } else {
                mfc_err("Setting FPS is only possible for the output queue\n");
                return -EINVAL;
@@ -1595,9 +1618,9 @@ static int vidioc_g_parm(struct file *file, void *priv,
 
        if (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
                a->parm.output.timeperframe.denominator =
-                                       ctx->enc_params.rc_framerate_num;
+                       ctx->enc_params.codec.runtime.rc_framerate_num;
                a->parm.output.timeperframe.numerator =
-                                       ctx->enc_params.rc_framerate_denom;
+                       ctx->enc_params.codec.runtime.rc_framerate_denom;
        } else {
                mfc_err("Getting FPS is only possible for the output queue\n");
                return -EINVAL;
@@ -1983,7 +2006,19 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb)
                ctx->dst_queue_cnt++;
                spin_unlock_irqrestore(&dev->irqlock, flags);
        } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               struct s5p_mfc_runtime_enc_params *runtime_params =
+                       &ctx->enc_params.codec.runtime;
                mfc_buf = &ctx->src_bufs[vb->v4l2_buf.index];
+               /* Tag buffer with runtime encoding parameters */
+               memcpy(&mfc_buf->runtime_enc_params, runtime_params,
+                       sizeof(mfc_buf->runtime_enc_params));
+               runtime_params->params_changed = 0;
+               /* force_frame_type needs to revert to 0 after being sent. */
+               if (runtime_params->force_frame_type != 0) {
+                       v4l2_ctrl_s_ctrl(v4l2_ctrl_find(&ctx->ctrl_handler,
+                               V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE),
+                               
V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_DISABLED);
+               }
                mfc_buf->flags &= ~MFC_BUF_FLAG_USED;
                spin_lock_irqsave(&dev->irqlock, flags);
                list_add_tail(&mfc_buf->list, &ctx->src_queue);
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c 
b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c
index 368582b..428cbb8 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c
@@ -688,7 +688,7 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
        reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL);
        reg |= (1 << 18);
        reg &= ~(0xFFFF);
-       reg |= p->gop_size;
+       reg |= p->codec.runtime.gop_size;
        mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL);
        mfc_write(dev, 0, S5P_FIMV_ENC_B_RECON_WRITE_ON);
        /* multi-slice control */
@@ -736,7 +736,7 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
        mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG);
        /* bit rate */
        if (p->rc_frame)
-               mfc_write(dev, p->rc_bitrate,
+               mfc_write(dev, p->codec.runtime.rc_bitrate,
                        S5P_FIMV_ENC_RC_BIT_RATE);
        else
                mfc_write(dev, 0, S5P_FIMV_ENC_RC_BIT_RATE);
@@ -831,9 +831,10 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx 
*ctx)
        reg |= p_264->rc_frame_qp;
        mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG);
        /* frame rate */
-       if (p->rc_frame && p->rc_framerate_denom)
-               mfc_write(dev, p->rc_framerate_num * 1000
-                       / p->rc_framerate_denom, S5P_FIMV_ENC_RC_FRAME_RATE);
+       if (p->rc_frame && p->codec.runtime.rc_framerate_denom)
+               mfc_write(dev, p->codec.runtime.rc_framerate_num * 1000
+                       / p->codec.runtime.rc_framerate_denom,
+                       S5P_FIMV_ENC_RC_FRAME_RATE);
        else
                mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE);
        /* max & min value of QP */
@@ -950,16 +951,17 @@ static int s5p_mfc_set_enc_params_mpeg4(struct 
s5p_mfc_ctx *ctx)
        }
        /* frame rate */
        if (p->rc_frame) {
-               if (p->rc_framerate_denom > 0) {
-                       framerate = p->rc_framerate_num * 1000 /
-                                               p->rc_framerate_denom;
+               if (p->codec.runtime.rc_framerate_denom > 0) {
+                       framerate = p->codec.runtime.rc_framerate_num * 1000 /
+                               p->codec.runtime.rc_framerate_denom;
                        mfc_write(dev, framerate,
                                S5P_FIMV_ENC_RC_FRAME_RATE);
                        shm = s5p_mfc_read_info_v5(ctx, RC_VOP_TIMING);
                        shm &= ~(0xFFFFFFFF);
                        shm |= (1 << 31);
-                       shm |= ((p->rc_framerate_num & 0x7FFF) << 16);
-                       shm |= (p->rc_framerate_denom & 0xFFFF);
+                       shm |= ((p->codec.runtime.rc_framerate_num & 0x7FFF)
+                               << 16);
+                       shm |= (p->codec.runtime.rc_framerate_denom & 0xFFFF);
                        s5p_mfc_write_info_v5(ctx, shm, RC_VOP_TIMING);
                }
        } else {
@@ -1009,9 +1011,10 @@ static int s5p_mfc_set_enc_params_h263(struct 
s5p_mfc_ctx *ctx)
                s5p_mfc_write_info_v5(ctx, shm, P_B_FRAME_QP);
        }
        /* frame rate */
-       if (p->rc_frame && p->rc_framerate_denom)
-               mfc_write(dev, p->rc_framerate_num * 1000
-                       / p->rc_framerate_denom, S5P_FIMV_ENC_RC_FRAME_RATE);
+       if (p->rc_frame && p->codec.runtime.rc_framerate_denom)
+               mfc_write(dev, p->codec.runtime.rc_framerate_num * 1000
+               / p->codec.runtime.rc_framerate_denom,
+               S5P_FIMV_ENC_RC_FRAME_RATE);
        else
                mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE);
        /* rate control config. */
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c 
b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
index 1bb487c..4b82338 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
@@ -587,6 +587,52 @@ static int s5p_mfc_set_slice_mode(struct s5p_mfc_ctx *ctx)
        return 0;
 }
 
+static int s5p_mfc_set_runtime_enc_params(struct s5p_mfc_ctx *ctx,
+               struct s5p_mfc_runtime_enc_params *runtime_p)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       struct s5p_mfc_enc_params *p = &ctx->enc_params;
+       unsigned int params_changed = 0;
+
+       if (runtime_p->params_changed & (1 << MFC_ENC_GOP_CONFIG_CHANGE)) {
+               params_changed |= (1 << S5P_FIMV_E_GOP_CONFIG_CHANGE_SHIFT_V6);
+               /* pictype: IDR period */
+               WRITEL((runtime_p->gop_size & 0xFFFF),
+                       S5P_FIMV_E_GOP_CONFIG_V6);
+       }
+       if (runtime_p->params_changed & (1 << MFC_ENC_FRAME_RATE_CHANGE)) {
+               /* frame rate */
+               if (p->rc_frame && runtime_p->rc_framerate_num &&
+                       runtime_p->rc_framerate_denom) {
+                       params_changed |=
+                               (1 << S5P_FIMV_E_FRAME_RATE_CHANGE_SHIFT_V6);
+                       WRITEL((((runtime_p->rc_framerate_num & 0xFFFF) << 16) |
+                               (runtime_p->rc_framerate_denom & 0xFFFF)),
+                               S5P_FIMV_E_RC_FRAME_RATE_V6);
+               }
+       }
+       if (runtime_p->params_changed & (1 << MFC_ENC_BIT_RATE_CHANGE)) {
+               /* bit rate */
+               if (p->rc_frame) {
+                       params_changed |=
+                               (1 << S5P_FIMV_E_BIT_RATE_CHANGE_SHIFT_V6);
+                       WRITEL(runtime_p->rc_bitrate,
+                               S5P_FIMV_E_RC_BIT_RATE_V6);
+               }
+       }
+       if (runtime_p->params_changed & (1 << MFC_ENC_FRAME_INSERTION)) {
+               unsigned int reg = READL(S5P_FIMV_E_FRAME_INSERTION_V6);
+               reg &= ~0x3;
+               reg |= runtime_p->force_frame_type & 0x3;
+               WRITEL(reg, S5P_FIMV_E_FRAME_INSERTION_V6);
+       }
+
+       if (params_changed)
+               WRITEL(params_changed, S5P_FIMV_E_PARAM_CHANGE_V6);
+
+       return 0;
+}
+
 static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
 {
        struct s5p_mfc_dev *dev = ctx->dev;
@@ -611,10 +657,10 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
                (((p->crop_top_offset / 16) & 0x2FF) << 10),
                S5P_FIMV_E_FRAME_CROP_OFFSET_V6);
 
-       /* pictype : IDR period */
-       reg = 0;
-       reg |= p->gop_size & 0xFFFF;
-       WRITEL(reg, S5P_FIMV_E_GOP_CONFIG_V6);
+       /* send all runtime encoder parameters. */
+       p->codec.runtime.params_changed = ~0;
+       s5p_mfc_set_runtime_enc_params(ctx, &p->codec.runtime);
+       p->codec.runtime.params_changed = 0;
 
        /* multi-slice control */
        /* multi-slice MB number or bit size */
@@ -700,13 +746,6 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
        reg |= ((p->rc_frame & 0x1) << 9);
        WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6);
 
-       /* bit rate */
-       if (p->rc_frame)
-               WRITEL(p->rc_bitrate,
-                       S5P_FIMV_E_RC_BIT_RATE_V6);
-       else
-               WRITEL(1, S5P_FIMV_E_RC_BIT_RATE_V6);
-
        /* reaction coefficient */
        if (p->rc_frame) {
                if (p->rc_reaction_coeff < TIGHT_CBR_MAX) /* tight CBR */
@@ -814,14 +853,6 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx 
*ctx)
                WRITEL(reg, S5P_FIMV_E_FIXED_PICTURE_QP_V6);
        }
 
-       /* frame rate */
-       if (p->rc_frame && p->rc_framerate_num && p->rc_framerate_denom) {
-               reg = 0;
-               reg |= ((p->rc_framerate_num & 0xFFFF) << 16);
-               reg |= p->rc_framerate_denom & 0xFFFF;
-               WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE_V6);
-       }
-
        /* vbv buffer size */
        if (p->frame_skip_mode ==
                        V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
@@ -1089,14 +1120,6 @@ static int s5p_mfc_set_enc_params_mpeg4(struct 
s5p_mfc_ctx *ctx)
                WRITEL(reg, S5P_FIMV_E_FIXED_PICTURE_QP_V6);
        }
 
-       /* frame rate */
-       if (p->rc_frame && p->rc_framerate_num && p->rc_framerate_denom) {
-               reg = 0;
-               reg |= ((p->rc_framerate_num & 0xFFFF) << 16);
-               reg |= p->rc_framerate_denom & 0xFFFF;
-               WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE_V6);
-       }
-
        /* vbv buffer size */
        if (p->frame_skip_mode ==
                        V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
@@ -1161,14 +1184,6 @@ static int s5p_mfc_set_enc_params_h263(struct 
s5p_mfc_ctx *ctx)
                WRITEL(reg, S5P_FIMV_E_FIXED_PICTURE_QP_V6);
        }
 
-       /* frame rate */
-       if (p->rc_frame && p->rc_framerate_num && p->rc_framerate_denom) {
-               reg = 0;
-               reg |= ((p->rc_framerate_num & 0xFFFF) << 16);
-               reg |= p->rc_framerate_denom & 0xFFFF;
-               WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE_V6);
-       }
-
        /* vbv buffer size */
        if (p->frame_skip_mode ==
                        V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
@@ -1214,14 +1229,6 @@ static int s5p_mfc_set_enc_params_vp8(struct s5p_mfc_ctx 
*ctx)
        reg |= ((p->rc_mb & 0x1) << 8);
        WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6);
 
-       /* frame rate */
-       if (p->rc_frame && p->rc_framerate_num && p->rc_framerate_denom) {
-               reg = 0;
-               reg |= ((p->rc_framerate_num & 0xFFFF) << 16);
-               reg |= p->rc_framerate_denom & 0xFFFF;
-               WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE_V6);
-       }
-
        /* vbv buffer size */
        if (p->frame_skip_mode ==
                        V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
@@ -1560,6 +1567,7 @@ static inline int s5p_mfc_run_enc_frame(struct 
s5p_mfc_ctx *ctx)
        mfc_debug(2, "enc src c addr: 0x%08lx\n", src_c_addr);
 
        s5p_mfc_set_enc_frame_buffer_v6(ctx, src_y_addr, src_c_addr);
+       s5p_mfc_set_runtime_enc_params(ctx, &src_mb->runtime_enc_params);
 
        dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
        dst_mb->flags |= MFC_BUF_FLAG_USED;
-- 
1.8.4

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to