media: platform: rename mtk-vcodec/ to mediatek/mtk-vcodec/
authorMauro Carvalho Chehab <mchehab@kernel.org>
Sun, 13 Mar 2022 10:18:13 +0000 (11:18 +0100)
committerMauro Carvalho Chehab <mchehab@kernel.org>
Fri, 18 Mar 2022 04:56:51 +0000 (05:56 +0100)
As the end goal is to have platform drivers split by vendor,
rename mtk-vcodec/ to mediatek/mtk-vcodec/.

Acked-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
95 files changed:
MAINTAINERS
drivers/media/platform/Kconfig
drivers/media/platform/Makefile
drivers/media/platform/mediatek/mtk-vcodec/Kconfig [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/Makefile [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_dec.c [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_dec.h [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_dec_drv.c [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_dec_hw.c [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_dec_hw.h [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_dec_pm.c [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_dec_pm.h [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_dec_stateful.c [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_dec_stateless.c [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_drv.h [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_enc.c [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_enc.h [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_enc_drv.c [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_enc_pm.c [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_enc_pm.h [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_fw.c [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_fw.h [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_fw_priv.h [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_fw_scp.c [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_fw_vpu.c [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_intr.c [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_intr.h [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_util.c [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_util.h [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/vdec/vdec_h264_if.c [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/vdec/vdec_h264_req_if.c [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/vdec/vdec_vp8_if.c [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/vdec/vdec_vp9_if.c [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/vdec_drv_base.h [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/vdec_drv_if.c [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/vdec_drv_if.h [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/vdec_ipi_msg.h [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/vdec_msg_queue.c [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/vdec_msg_queue.h [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/vdec_vpu_if.c [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/vdec_vpu_if.h [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/venc/venc_h264_if.c [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/venc/venc_vp8_if.c [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/venc_drv_base.h [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/venc_drv_if.c [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/venc_drv_if.h [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/venc_ipi_msg.h [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/venc_vpu_if.c [new file with mode: 0644]
drivers/media/platform/mediatek/mtk-vcodec/venc_vpu_if.h [new file with mode: 0644]
drivers/media/platform/mtk-vcodec/Kconfig [deleted file]
drivers/media/platform/mtk-vcodec/Makefile [deleted file]
drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c [deleted file]
drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h [deleted file]
drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c [deleted file]
drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_hw.c [deleted file]
drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_hw.h [deleted file]
drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c [deleted file]
drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h [deleted file]
drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateful.c [deleted file]
drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateless.c [deleted file]
drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h [deleted file]
drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c [deleted file]
drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.h [deleted file]
drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c [deleted file]
drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c [deleted file]
drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.h [deleted file]
drivers/media/platform/mtk-vcodec/mtk_vcodec_fw.c [deleted file]
drivers/media/platform/mtk-vcodec/mtk_vcodec_fw.h [deleted file]
drivers/media/platform/mtk-vcodec/mtk_vcodec_fw_priv.h [deleted file]
drivers/media/platform/mtk-vcodec/mtk_vcodec_fw_scp.c [deleted file]
drivers/media/platform/mtk-vcodec/mtk_vcodec_fw_vpu.c [deleted file]
drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.c [deleted file]
drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.h [deleted file]
drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c [deleted file]
drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h [deleted file]
drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c [deleted file]
drivers/media/platform/mtk-vcodec/vdec/vdec_h264_req_if.c [deleted file]
drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c [deleted file]
drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c [deleted file]
drivers/media/platform/mtk-vcodec/vdec_drv_base.h [deleted file]
drivers/media/platform/mtk-vcodec/vdec_drv_if.c [deleted file]
drivers/media/platform/mtk-vcodec/vdec_drv_if.h [deleted file]
drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h [deleted file]
drivers/media/platform/mtk-vcodec/vdec_msg_queue.c [deleted file]
drivers/media/platform/mtk-vcodec/vdec_msg_queue.h [deleted file]
drivers/media/platform/mtk-vcodec/vdec_vpu_if.c [deleted file]
drivers/media/platform/mtk-vcodec/vdec_vpu_if.h [deleted file]
drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c [deleted file]
drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c [deleted file]
drivers/media/platform/mtk-vcodec/venc_drv_base.h [deleted file]
drivers/media/platform/mtk-vcodec/venc_drv_if.c [deleted file]
drivers/media/platform/mtk-vcodec/venc_drv_if.h [deleted file]
drivers/media/platform/mtk-vcodec/venc_ipi_msg.h [deleted file]
drivers/media/platform/mtk-vcodec/venc_vpu_if.c [deleted file]
drivers/media/platform/mtk-vcodec/venc_vpu_if.h [deleted file]

index 2203d98bbcf1b76a10c3230ef906f82a6c83270a..bfe014870a77884b0e2a666a93230fbbada32bf5 100644 (file)
@@ -12147,7 +12147,7 @@ M:      Andrew-CT Chen <andrew-ct.chen@mediatek.com>
 S:     Supported
 F:     Documentation/devicetree/bindings/media/mediatek-vcodec.txt
 F:     Documentation/devicetree/bindings/media/mediatek-vpu.txt
-F:     drivers/media/platform/mtk-vcodec/
+F:     drivers/media/platform/mediatek/mtk-vcodec/
 F:     drivers/media/platform/mtk-vpu/
 
 MEDIATEK MMC/SD/SDIO DRIVER
index 8a7ac0b8e09f8250a7a28f163c9db714a43aa575..10055af0c7f827b57d5e3f2fdc93e9a00373d80e 100644 (file)
@@ -80,7 +80,7 @@ source "drivers/media/platform/intel/Kconfig"
 source "drivers/media/platform/marvell/Kconfig"
 source "drivers/media/platform/mediatek/mtk-jpeg/Kconfig"
 source "drivers/media/platform/mediatek/mtk-mdp/Kconfig"
-source "drivers/media/platform/mtk-vcodec/Kconfig"
+source "drivers/media/platform/mediatek/mtk-vcodec/Kconfig"
 source "drivers/media/platform/mtk-vpu/Kconfig"
 source "drivers/media/platform/nxp/Kconfig"
 source "drivers/media/platform/omap/Kconfig"
index 6f5d09cd8f9beee16febf685972faf73d4dead5e..637a3a7ac03648b9e528dcb08f559f97e83e5644 100644 (file)
@@ -20,7 +20,7 @@ obj-y += intel/
 obj-y += marvell/
 obj-y += mediatek/mtk-jpeg/
 obj-y += mediatek/mtk-mdp/
-obj-y += mtk-vcodec/
+obj-y += mediatek/mtk-vcodec/
 obj-y += mtk-vpu/
 obj-y += nxp/
 obj-y += omap/
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/Kconfig b/drivers/media/platform/mediatek/mtk-vcodec/Kconfig
new file mode 100644 (file)
index 0000000..635801a
--- /dev/null
@@ -0,0 +1,36 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config VIDEO_MEDIATEK_VCODEC_SCP
+       bool
+
+config VIDEO_MEDIATEK_VCODEC_VPU
+       bool
+
+config VIDEO_MEDIATEK_VCODEC
+       tristate "Mediatek Video Codec driver"
+       depends on V4L_MEM2MEM_DRIVERS
+       depends on MTK_IOMMU || COMPILE_TEST
+       depends on VIDEO_DEV && VIDEO_V4L2
+       depends on ARCH_MEDIATEK || COMPILE_TEST
+       depends on VIDEO_MEDIATEK_VPU || MTK_SCP
+       # The two following lines ensure we have the same state ("m" or "y") as
+       # our dependencies, to avoid missing symbols during link.
+       depends on VIDEO_MEDIATEK_VPU || !VIDEO_MEDIATEK_VPU
+       depends on MTK_SCP || !MTK_SCP
+       depends on MTK_SMI || (COMPILE_TEST && MTK_SMI=n)
+       select VIDEOBUF2_DMA_CONTIG
+       select V4L2_MEM2MEM_DEV
+       select VIDEO_MEDIATEK_VCODEC_VPU if VIDEO_MEDIATEK_VPU
+       select VIDEO_MEDIATEK_VCODEC_SCP if MTK_SCP
+       select V4L2_H264
+       select MEDIA_CONTROLLER
+       select MEDIA_CONTROLLER_REQUEST_API
+       help
+         Mediatek video codec driver provides HW capability to
+         encode and decode in a range of video formats on MT8173
+         and MT8183.
+
+         Note that support for MT8173 requires VIDEO_MEDIATEK_VPU to
+         also be selected. Support for MT8183 depends on MTK_SCP.
+
+         To compile this driver as modules, choose M here: the
+         modules will be called mtk-vcodec-dec and mtk-vcodec-enc.
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/Makefile b/drivers/media/platform/mediatek/mtk-vcodec/Makefile
new file mode 100644 (file)
index 0000000..3596196
--- /dev/null
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC) += mtk-vcodec-dec.o \
+                                      mtk-vcodec-enc.o \
+                                      mtk-vcodec-common.o \
+                                      mtk-vcodec-dec-hw.o
+
+mtk-vcodec-dec-y := vdec/vdec_h264_if.o \
+               vdec/vdec_vp8_if.o \
+               vdec/vdec_vp9_if.o \
+               vdec/vdec_h264_req_if.o \
+               mtk_vcodec_dec_drv.o \
+               vdec_drv_if.o \
+               vdec_vpu_if.o \
+               vdec_msg_queue.o \
+               mtk_vcodec_dec.o \
+               mtk_vcodec_dec_stateful.o \
+               mtk_vcodec_dec_stateless.o \
+               mtk_vcodec_dec_pm.o \
+
+mtk-vcodec-dec-hw-y := mtk_vcodec_dec_hw.o
+
+mtk-vcodec-enc-y := venc/venc_vp8_if.o \
+               venc/venc_h264_if.o \
+               mtk_vcodec_enc.o \
+               mtk_vcodec_enc_drv.o \
+               mtk_vcodec_enc_pm.o \
+               venc_drv_if.o \
+               venc_vpu_if.o \
+
+
+mtk-vcodec-common-y := mtk_vcodec_intr.o \
+               mtk_vcodec_util.o \
+               mtk_vcodec_fw.o \
+
+ifneq ($(CONFIG_VIDEO_MEDIATEK_VCODEC_VPU),)
+mtk-vcodec-common-y += mtk_vcodec_fw_vpu.o
+endif
+
+ifneq ($(CONFIG_VIDEO_MEDIATEK_VCODEC_SCP),)
+mtk-vcodec-common-y += mtk_vcodec_fw_scp.o
+endif
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_dec.c
new file mode 100644 (file)
index 0000000..130ecef
--- /dev/null
@@ -0,0 +1,961 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: PC Chen <pc.chen@mediatek.com>
+ *         Tiffany Lin <tiffany.lin@mediatek.com>
+ */
+
+#include <media/v4l2-event.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "mtk_vcodec_drv.h"
+#include "mtk_vcodec_dec.h"
+#include "mtk_vcodec_intr.h"
+#include "mtk_vcodec_util.h"
+#include "vdec_drv_if.h"
+#include "mtk_vcodec_dec_pm.h"
+
+#define DFT_CFG_WIDTH  MTK_VDEC_MIN_W
+#define DFT_CFG_HEIGHT MTK_VDEC_MIN_H
+
+static const struct mtk_video_fmt *
+mtk_vdec_find_format(struct v4l2_format *f,
+                    const struct mtk_vcodec_dec_pdata *dec_pdata)
+{
+       const struct mtk_video_fmt *fmt;
+       unsigned int k;
+
+       for (k = 0; k < dec_pdata->num_formats; k++) {
+               fmt = &dec_pdata->vdec_formats[k];
+               if (fmt->fourcc == f->fmt.pix_mp.pixelformat)
+                       return fmt;
+       }
+
+       return NULL;
+}
+
+static struct mtk_q_data *mtk_vdec_get_q_data(struct mtk_vcodec_ctx *ctx,
+                                             enum v4l2_buf_type type)
+{
+       if (V4L2_TYPE_IS_OUTPUT(type))
+               return &ctx->q_data[MTK_Q_DATA_SRC];
+
+       return &ctx->q_data[MTK_Q_DATA_DST];
+}
+
+static int vidioc_try_decoder_cmd(struct file *file, void *priv,
+                               struct v4l2_decoder_cmd *cmd)
+{
+       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+
+       /* Use M2M stateless helper if relevant */
+       if (ctx->dev->vdec_pdata->uses_stateless_api)
+               return v4l2_m2m_ioctl_stateless_try_decoder_cmd(file, priv,
+                                                               cmd);
+       else
+               return v4l2_m2m_ioctl_try_decoder_cmd(file, priv, cmd);
+}
+
+
+static int vidioc_decoder_cmd(struct file *file, void *priv,
+                               struct v4l2_decoder_cmd *cmd)
+{
+       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+       struct vb2_queue *src_vq, *dst_vq;
+       int ret;
+
+       ret = vidioc_try_decoder_cmd(file, priv, cmd);
+       if (ret)
+               return ret;
+
+       /* Use M2M stateless helper if relevant */
+       if (ctx->dev->vdec_pdata->uses_stateless_api)
+               return v4l2_m2m_ioctl_stateless_decoder_cmd(file, priv, cmd);
+
+       mtk_v4l2_debug(1, "decoder cmd=%u", cmd->cmd);
+       dst_vq = v4l2_m2m_get_vq(ctx->m2m_ctx,
+                               V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+       switch (cmd->cmd) {
+       case V4L2_DEC_CMD_STOP:
+               src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx,
+                               V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+               if (!vb2_is_streaming(src_vq)) {
+                       mtk_v4l2_debug(1, "Output stream is off. No need to flush.");
+                       return 0;
+               }
+               if (!vb2_is_streaming(dst_vq)) {
+                       mtk_v4l2_debug(1, "Capture stream is off. No need to flush.");
+                       return 0;
+               }
+               v4l2_m2m_buf_queue(ctx->m2m_ctx, &ctx->empty_flush_buf.vb);
+               v4l2_m2m_try_schedule(ctx->m2m_ctx);
+               break;
+
+       case V4L2_DEC_CMD_START:
+               vb2_clear_last_buffer_dequeued(dst_vq);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+void mtk_vdec_unlock(struct mtk_vcodec_ctx *ctx)
+{
+       mutex_unlock(&ctx->dev->dec_mutex[ctx->hw_id]);
+}
+
+void mtk_vdec_lock(struct mtk_vcodec_ctx *ctx)
+{
+       mutex_lock(&ctx->dev->dec_mutex[ctx->hw_id]);
+}
+
+void mtk_vcodec_dec_release(struct mtk_vcodec_ctx *ctx)
+{
+       vdec_if_deinit(ctx);
+       ctx->state = MTK_STATE_FREE;
+}
+
+void mtk_vcodec_dec_set_default_params(struct mtk_vcodec_ctx *ctx)
+{
+       struct mtk_q_data *q_data;
+
+       ctx->dev->vdec_pdata->init_vdec_params(ctx);
+
+       ctx->m2m_ctx->q_lock = &ctx->dev->dev_mutex;
+       ctx->fh.m2m_ctx = ctx->m2m_ctx;
+       ctx->fh.ctrl_handler = &ctx->ctrl_hdl;
+       INIT_WORK(&ctx->decode_work, ctx->dev->vdec_pdata->worker);
+       ctx->colorspace = V4L2_COLORSPACE_REC709;
+       ctx->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+       ctx->quantization = V4L2_QUANTIZATION_DEFAULT;
+       ctx->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+
+       q_data = &ctx->q_data[MTK_Q_DATA_SRC];
+       memset(q_data, 0, sizeof(struct mtk_q_data));
+       q_data->visible_width = DFT_CFG_WIDTH;
+       q_data->visible_height = DFT_CFG_HEIGHT;
+       q_data->fmt = ctx->dev->vdec_pdata->default_out_fmt;
+       q_data->field = V4L2_FIELD_NONE;
+
+       q_data->sizeimage[0] = DFT_CFG_WIDTH * DFT_CFG_HEIGHT;
+       q_data->bytesperline[0] = 0;
+
+       q_data = &ctx->q_data[MTK_Q_DATA_DST];
+       memset(q_data, 0, sizeof(struct mtk_q_data));
+       q_data->visible_width = DFT_CFG_WIDTH;
+       q_data->visible_height = DFT_CFG_HEIGHT;
+       q_data->coded_width = DFT_CFG_WIDTH;
+       q_data->coded_height = DFT_CFG_HEIGHT;
+       q_data->fmt = ctx->dev->vdec_pdata->default_cap_fmt;
+       q_data->field = V4L2_FIELD_NONE;
+
+       v4l_bound_align_image(&q_data->coded_width,
+                               MTK_VDEC_MIN_W,
+                               MTK_VDEC_MAX_W, 4,
+                               &q_data->coded_height,
+                               MTK_VDEC_MIN_H,
+                               MTK_VDEC_MAX_H, 5, 6);
+
+       q_data->sizeimage[0] = q_data->coded_width * q_data->coded_height;
+       q_data->bytesperline[0] = q_data->coded_width;
+       q_data->sizeimage[1] = q_data->sizeimage[0] / 2;
+       q_data->bytesperline[1] = q_data->coded_width;
+}
+
+static int vidioc_vdec_qbuf(struct file *file, void *priv,
+                           struct v4l2_buffer *buf)
+{
+       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+
+       if (ctx->state == MTK_STATE_ABORT) {
+               mtk_v4l2_err("[%d] Call on QBUF after unrecoverable error",
+                               ctx->id);
+               return -EIO;
+       }
+
+       return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_vdec_dqbuf(struct file *file, void *priv,
+                            struct v4l2_buffer *buf)
+{
+       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+
+       if (ctx->state == MTK_STATE_ABORT) {
+               mtk_v4l2_err("[%d] Call on DQBUF after unrecoverable error",
+                               ctx->id);
+               return -EIO;
+       }
+
+       return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_vdec_querycap(struct file *file, void *priv,
+                               struct v4l2_capability *cap)
+{
+       strscpy(cap->driver, MTK_VCODEC_DEC_NAME, sizeof(cap->driver));
+       strscpy(cap->bus_info, MTK_PLATFORM_STR, sizeof(cap->bus_info));
+       strscpy(cap->card, MTK_PLATFORM_STR, sizeof(cap->card));
+
+       return 0;
+}
+
+static int vidioc_vdec_subscribe_evt(struct v4l2_fh *fh,
+                                    const struct v4l2_event_subscription *sub)
+{
+       switch (sub->type) {
+       case V4L2_EVENT_EOS:
+               return v4l2_event_subscribe(fh, sub, 2, NULL);
+       case V4L2_EVENT_SOURCE_CHANGE:
+               return v4l2_src_change_event_subscribe(fh, sub);
+       default:
+               return v4l2_ctrl_subscribe_event(fh, sub);
+       }
+}
+
+static int vidioc_try_fmt(struct v4l2_format *f,
+                         const struct mtk_video_fmt *fmt)
+{
+       struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
+
+       pix_fmt_mp->field = V4L2_FIELD_NONE;
+
+       pix_fmt_mp->width =
+               clamp(pix_fmt_mp->width, MTK_VDEC_MIN_W, MTK_VDEC_MAX_W);
+       pix_fmt_mp->height =
+               clamp(pix_fmt_mp->height, MTK_VDEC_MIN_H, MTK_VDEC_MAX_H);
+
+       if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               pix_fmt_mp->num_planes = 1;
+               pix_fmt_mp->plane_fmt[0].bytesperline = 0;
+       } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               int tmp_w, tmp_h;
+
+               /*
+                * Find next closer width align 64, heign align 64, size align
+                * 64 rectangle
+                * Note: This only get default value, the real HW needed value
+                *       only available when ctx in MTK_STATE_HEADER state
+                */
+               tmp_w = pix_fmt_mp->width;
+               tmp_h = pix_fmt_mp->height;
+               v4l_bound_align_image(&pix_fmt_mp->width,
+                                       MTK_VDEC_MIN_W,
+                                       MTK_VDEC_MAX_W, 6,
+                                       &pix_fmt_mp->height,
+                                       MTK_VDEC_MIN_H,
+                                       MTK_VDEC_MAX_H, 6, 9);
+
+               if (pix_fmt_mp->width < tmp_w &&
+                       (pix_fmt_mp->width + 64) <= MTK_VDEC_MAX_W)
+                       pix_fmt_mp->width += 64;
+               if (pix_fmt_mp->height < tmp_h &&
+                       (pix_fmt_mp->height + 64) <= MTK_VDEC_MAX_H)
+                       pix_fmt_mp->height += 64;
+
+               mtk_v4l2_debug(0,
+                       "before resize width=%d, height=%d, after resize width=%d, height=%d, sizeimage=%d",
+                       tmp_w, tmp_h, pix_fmt_mp->width,
+                       pix_fmt_mp->height,
+                       pix_fmt_mp->width * pix_fmt_mp->height);
+
+               pix_fmt_mp->num_planes = fmt->num_planes;
+               pix_fmt_mp->plane_fmt[0].sizeimage =
+                               pix_fmt_mp->width * pix_fmt_mp->height;
+               pix_fmt_mp->plane_fmt[0].bytesperline = pix_fmt_mp->width;
+
+               if (pix_fmt_mp->num_planes == 2) {
+                       pix_fmt_mp->plane_fmt[1].sizeimage =
+                               (pix_fmt_mp->width * pix_fmt_mp->height) / 2;
+                       pix_fmt_mp->plane_fmt[1].bytesperline =
+                               pix_fmt_mp->width;
+               }
+       }
+
+       pix_fmt_mp->flags = 0;
+       return 0;
+}
+
+static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       const struct mtk_video_fmt *fmt;
+       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+       const struct mtk_vcodec_dec_pdata *dec_pdata = ctx->dev->vdec_pdata;
+
+       fmt = mtk_vdec_find_format(f, dec_pdata);
+       if (!fmt) {
+               f->fmt.pix.pixelformat =
+                       ctx->q_data[MTK_Q_DATA_DST].fmt->fourcc;
+               fmt = mtk_vdec_find_format(f, dec_pdata);
+       }
+
+       return vidioc_try_fmt(f, fmt);
+}
+
+static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
+       const struct mtk_video_fmt *fmt;
+       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+       const struct mtk_vcodec_dec_pdata *dec_pdata = ctx->dev->vdec_pdata;
+
+       fmt = mtk_vdec_find_format(f, dec_pdata);
+       if (!fmt) {
+               f->fmt.pix.pixelformat =
+                       ctx->q_data[MTK_Q_DATA_SRC].fmt->fourcc;
+               fmt = mtk_vdec_find_format(f, dec_pdata);
+       }
+
+       if (pix_fmt_mp->plane_fmt[0].sizeimage == 0) {
+               mtk_v4l2_err("sizeimage of output format must be given");
+               return -EINVAL;
+       }
+
+       return vidioc_try_fmt(f, fmt);
+}
+
+static int vidioc_vdec_g_selection(struct file *file, void *priv,
+                       struct v4l2_selection *s)
+{
+       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+       struct mtk_q_data *q_data;
+
+       if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       q_data = &ctx->q_data[MTK_Q_DATA_DST];
+
+       switch (s->target) {
+       case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+               s->r.left = 0;
+               s->r.top = 0;
+               s->r.width = ctx->picinfo.pic_w;
+               s->r.height = ctx->picinfo.pic_h;
+               break;
+       case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+               s->r.left = 0;
+               s->r.top = 0;
+               s->r.width = ctx->picinfo.buf_w;
+               s->r.height = ctx->picinfo.buf_h;
+               break;
+       case V4L2_SEL_TGT_COMPOSE:
+               if (vdec_if_get_param(ctx, GET_PARAM_CROP_INFO, &(s->r))) {
+                       /* set to default value if header info not ready yet*/
+                       s->r.left = 0;
+                       s->r.top = 0;
+                       s->r.width = q_data->visible_width;
+                       s->r.height = q_data->visible_height;
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (ctx->state < MTK_STATE_HEADER) {
+               /* set to default value if header info not ready yet*/
+               s->r.left = 0;
+               s->r.top = 0;
+               s->r.width = q_data->visible_width;
+               s->r.height = q_data->visible_height;
+               return 0;
+       }
+
+       return 0;
+}
+
+static int vidioc_vdec_s_selection(struct file *file, void *priv,
+                               struct v4l2_selection *s)
+{
+       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+
+       if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       switch (s->target) {
+       case V4L2_SEL_TGT_COMPOSE:
+               s->r.left = 0;
+               s->r.top = 0;
+               s->r.width = ctx->picinfo.pic_w;
+               s->r.height = ctx->picinfo.pic_h;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int vidioc_vdec_s_fmt(struct file *file, void *priv,
+                            struct v4l2_format *f)
+{
+       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+       struct v4l2_pix_format_mplane *pix_mp;
+       struct mtk_q_data *q_data;
+       int ret = 0;
+       const struct mtk_video_fmt *fmt;
+       const struct mtk_vcodec_dec_pdata *dec_pdata = ctx->dev->vdec_pdata;
+
+       mtk_v4l2_debug(3, "[%d]", ctx->id);
+
+       q_data = mtk_vdec_get_q_data(ctx, f->type);
+       if (!q_data)
+               return -EINVAL;
+
+       pix_mp = &f->fmt.pix_mp;
+       /*
+        * Setting OUTPUT format after OUTPUT buffers are allocated is invalid
+        * if using the stateful API.
+        */
+       if (!dec_pdata->uses_stateless_api &&
+           f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
+           vb2_is_busy(&ctx->m2m_ctx->out_q_ctx.q)) {
+               mtk_v4l2_err("out_q_ctx buffers already requested");
+               ret = -EBUSY;
+       }
+
+       /*
+        * Setting CAPTURE format after CAPTURE buffers are allocated is
+        * invalid.
+        */
+       if ((f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) &&
+           vb2_is_busy(&ctx->m2m_ctx->cap_q_ctx.q)) {
+               mtk_v4l2_err("cap_q_ctx buffers already requested");
+               ret = -EBUSY;
+       }
+
+       fmt = mtk_vdec_find_format(f, dec_pdata);
+       if (fmt == NULL) {
+               if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+                       f->fmt.pix.pixelformat =
+                               dec_pdata->default_out_fmt->fourcc;
+                       fmt = mtk_vdec_find_format(f, dec_pdata);
+               } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+                       f->fmt.pix.pixelformat =
+                               dec_pdata->default_cap_fmt->fourcc;
+                       fmt = mtk_vdec_find_format(f, dec_pdata);
+               }
+       }
+       if (fmt == NULL)
+               return -EINVAL;
+
+       q_data->fmt = fmt;
+       vidioc_try_fmt(f, q_data->fmt);
+       if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               q_data->sizeimage[0] = pix_mp->plane_fmt[0].sizeimage;
+               q_data->coded_width = pix_mp->width;
+               q_data->coded_height = pix_mp->height;
+
+               ctx->colorspace = pix_mp->colorspace;
+               ctx->ycbcr_enc = pix_mp->ycbcr_enc;
+               ctx->quantization = pix_mp->quantization;
+               ctx->xfer_func = pix_mp->xfer_func;
+
+               ctx->current_codec = fmt->fourcc;
+               if (ctx->state == MTK_STATE_FREE) {
+                       ret = vdec_if_init(ctx, q_data->fmt->fourcc);
+                       if (ret) {
+                               mtk_v4l2_err("[%d]: vdec_if_init() fail ret=%d",
+                                       ctx->id, ret);
+                               return -EINVAL;
+                       }
+                       ctx->state = MTK_STATE_INIT;
+               }
+       }
+
+       /*
+        * If using the stateless API, S_FMT should have the effect of setting
+        * the CAPTURE queue resolution no matter which queue it was called on.
+        */
+       if (dec_pdata->uses_stateless_api) {
+               ctx->picinfo.pic_w = pix_mp->width;
+               ctx->picinfo.pic_h = pix_mp->height;
+
+               ret = vdec_if_get_param(ctx, GET_PARAM_PIC_INFO, &ctx->picinfo);
+               if (ret) {
+                       mtk_v4l2_err("[%d]Error!! Get GET_PARAM_PICTURE_INFO Fail",
+                                    ctx->id);
+                       return -EINVAL;
+               }
+
+               ctx->last_decoded_picinfo = ctx->picinfo;
+
+               if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 1) {
+                       ctx->q_data[MTK_Q_DATA_DST].sizeimage[0] =
+                               ctx->picinfo.fb_sz[0] +
+                               ctx->picinfo.fb_sz[1];
+                       ctx->q_data[MTK_Q_DATA_DST].bytesperline[0] =
+                               ctx->picinfo.buf_w;
+               } else {
+                       ctx->q_data[MTK_Q_DATA_DST].sizeimage[0] =
+                               ctx->picinfo.fb_sz[0];
+                       ctx->q_data[MTK_Q_DATA_DST].bytesperline[0] =
+                               ctx->picinfo.buf_w;
+                       ctx->q_data[MTK_Q_DATA_DST].sizeimage[1] =
+                               ctx->picinfo.fb_sz[1];
+                       ctx->q_data[MTK_Q_DATA_DST].bytesperline[1] =
+                               ctx->picinfo.buf_w;
+               }
+
+               ctx->q_data[MTK_Q_DATA_DST].coded_width = ctx->picinfo.buf_w;
+               ctx->q_data[MTK_Q_DATA_DST].coded_height = ctx->picinfo.buf_h;
+               mtk_v4l2_debug(2, "[%d] vdec_if_init() num_plane = %d wxh=%dx%d pic wxh=%dx%d sz[0]=0x%x sz[1]=0x%x",
+                              ctx->id, pix_mp->num_planes, ctx->picinfo.buf_w, ctx->picinfo.buf_h,
+                              ctx->picinfo.pic_w, ctx->picinfo.pic_h,
+                              ctx->q_data[MTK_Q_DATA_DST].sizeimage[0],
+                              ctx->q_data[MTK_Q_DATA_DST].sizeimage[1]);
+       }
+       return 0;
+}
+
+static int vidioc_enum_framesizes(struct file *file, void *priv,
+                               struct v4l2_frmsizeenum *fsize)
+{
+       int i = 0;
+       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+       const struct mtk_vcodec_dec_pdata *dec_pdata = ctx->dev->vdec_pdata;
+
+       if (fsize->index != 0)
+               return -EINVAL;
+
+       for (i = 0; i < dec_pdata->num_framesizes; ++i) {
+               if (fsize->pixel_format != dec_pdata->vdec_framesizes[i].fourcc)
+                       continue;
+
+               fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+               fsize->stepwise = dec_pdata->vdec_framesizes[i].stepwise;
+               if (!(ctx->dev->dec_capability &
+                               VCODEC_CAPABILITY_4K_DISABLED)) {
+                       mtk_v4l2_debug(3, "4K is enabled");
+                       fsize->stepwise.max_width =
+                                       VCODEC_DEC_4K_CODED_WIDTH;
+                       fsize->stepwise.max_height =
+                                       VCODEC_DEC_4K_CODED_HEIGHT;
+               }
+               mtk_v4l2_debug(1, "%x, %d %d %d %d %d %d",
+                               ctx->dev->dec_capability,
+                               fsize->stepwise.min_width,
+                               fsize->stepwise.max_width,
+                               fsize->stepwise.step_width,
+                               fsize->stepwise.min_height,
+                               fsize->stepwise.max_height,
+                               fsize->stepwise.step_height);
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, void *priv,
+                          bool output_queue)
+{
+       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+       const struct mtk_vcodec_dec_pdata *dec_pdata = ctx->dev->vdec_pdata;
+       const struct mtk_video_fmt *fmt;
+       int i, j = 0;
+
+       for (i = 0; i < dec_pdata->num_formats; i++) {
+               if (output_queue &&
+                   dec_pdata->vdec_formats[i].type != MTK_FMT_DEC)
+                       continue;
+               if (!output_queue &&
+                   dec_pdata->vdec_formats[i].type != MTK_FMT_FRAME)
+                       continue;
+
+               if (j == f->index)
+                       break;
+               ++j;
+       }
+
+       if (i == dec_pdata->num_formats)
+               return -EINVAL;
+
+       fmt = &dec_pdata->vdec_formats[i];
+       f->pixelformat = fmt->fourcc;
+       f->flags = fmt->flags;
+
+       return 0;
+}
+
+static int vidioc_vdec_enum_fmt_vid_cap(struct file *file, void *priv,
+                                       struct v4l2_fmtdesc *f)
+{
+       return vidioc_enum_fmt(f, priv, false);
+}
+
+static int vidioc_vdec_enum_fmt_vid_out(struct file *file, void *priv,
+                                       struct v4l2_fmtdesc *f)
+{
+       return vidioc_enum_fmt(f, priv, true);
+}
+
+static int vidioc_vdec_g_fmt(struct file *file, void *priv,
+                            struct v4l2_format *f)
+{
+       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+       struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+       struct vb2_queue *vq;
+       struct mtk_q_data *q_data;
+
+       vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+       if (!vq) {
+               mtk_v4l2_err("no vb2 queue for type=%d", f->type);
+               return -EINVAL;
+       }
+
+       q_data = mtk_vdec_get_q_data(ctx, f->type);
+
+       pix_mp->field = V4L2_FIELD_NONE;
+       pix_mp->colorspace = ctx->colorspace;
+       pix_mp->ycbcr_enc = ctx->ycbcr_enc;
+       pix_mp->quantization = ctx->quantization;
+       pix_mp->xfer_func = ctx->xfer_func;
+
+       if ((f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) &&
+           (ctx->state >= MTK_STATE_HEADER)) {
+               /* Until STREAMOFF is called on the CAPTURE queue
+                * (acknowledging the event), the driver operates as if
+                * the resolution hasn't changed yet.
+                * So we just return picinfo yet, and update picinfo in
+                * stop_streaming hook function
+                */
+               q_data->sizeimage[0] = ctx->picinfo.fb_sz[0];
+               q_data->sizeimage[1] = ctx->picinfo.fb_sz[1];
+               q_data->bytesperline[0] = ctx->last_decoded_picinfo.buf_w;
+               q_data->bytesperline[1] = ctx->last_decoded_picinfo.buf_w;
+               q_data->coded_width = ctx->picinfo.buf_w;
+               q_data->coded_height = ctx->picinfo.buf_h;
+               ctx->last_decoded_picinfo.cap_fourcc = q_data->fmt->fourcc;
+
+               /*
+                * Width and height are set to the dimensions
+                * of the movie, the buffer is bigger and
+                * further processing stages should crop to this
+                * rectangle.
+                */
+               pix_mp->width = q_data->coded_width;
+               pix_mp->height = q_data->coded_height;
+
+               /*
+                * Set pixelformat to the format in which mt vcodec
+                * outputs the decoded frame
+                */
+               pix_mp->num_planes = q_data->fmt->num_planes;
+               pix_mp->pixelformat = q_data->fmt->fourcc;
+               pix_mp->plane_fmt[0].bytesperline = q_data->bytesperline[0];
+               pix_mp->plane_fmt[0].sizeimage = q_data->sizeimage[0];
+               pix_mp->plane_fmt[1].bytesperline = q_data->bytesperline[1];
+               pix_mp->plane_fmt[1].sizeimage = q_data->sizeimage[1];
+
+       } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               /*
+                * This is run on OUTPUT
+                * The buffer contains compressed image
+                * so width and height have no meaning.
+                * Assign value here to pass v4l2-compliance test
+                */
+               pix_mp->width = q_data->visible_width;
+               pix_mp->height = q_data->visible_height;
+               pix_mp->plane_fmt[0].bytesperline = q_data->bytesperline[0];
+               pix_mp->plane_fmt[0].sizeimage = q_data->sizeimage[0];
+               pix_mp->pixelformat = q_data->fmt->fourcc;
+               pix_mp->num_planes = q_data->fmt->num_planes;
+       } else {
+               pix_mp->width = q_data->coded_width;
+               pix_mp->height = q_data->coded_height;
+               pix_mp->num_planes = q_data->fmt->num_planes;
+               pix_mp->pixelformat = q_data->fmt->fourcc;
+               pix_mp->plane_fmt[0].bytesperline = q_data->bytesperline[0];
+               pix_mp->plane_fmt[0].sizeimage = q_data->sizeimage[0];
+               pix_mp->plane_fmt[1].bytesperline = q_data->bytesperline[1];
+               pix_mp->plane_fmt[1].sizeimage = q_data->sizeimage[1];
+
+               mtk_v4l2_debug(1, "[%d] type=%d state=%d Format information could not be read, not ready yet!",
+                               ctx->id, f->type, ctx->state);
+       }
+
+       return 0;
+}
+
+int vb2ops_vdec_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
+                           unsigned int *nplanes, unsigned int sizes[],
+                           struct device *alloc_devs[])
+{
+       struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vq);
+       struct mtk_q_data *q_data;
+       unsigned int i;
+
+       q_data = mtk_vdec_get_q_data(ctx, vq->type);
+
+       if (q_data == NULL) {
+               mtk_v4l2_err("vq->type=%d err\n", vq->type);
+               return -EINVAL;
+       }
+
+       if (*nplanes) {
+               for (i = 0; i < *nplanes; i++) {
+                       if (sizes[i] < q_data->sizeimage[i])
+                               return -EINVAL;
+               }
+       } else {
+               if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+                       *nplanes = q_data->fmt->num_planes;
+               else
+                       *nplanes = 1;
+
+               for (i = 0; i < *nplanes; i++)
+                       sizes[i] = q_data->sizeimage[i];
+       }
+
+       mtk_v4l2_debug(1,
+                       "[%d]\t type = %d, get %d plane(s), %d buffer(s) of size 0x%x 0x%x ",
+                       ctx->id, vq->type, *nplanes, *nbuffers,
+                       sizes[0], sizes[1]);
+
+       return 0;
+}
+
+int vb2ops_vdec_buf_prepare(struct vb2_buffer *vb)
+{
+       struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+       struct mtk_q_data *q_data;
+       int i;
+
+       mtk_v4l2_debug(3, "[%d] (%d) id=%d",
+                       ctx->id, vb->vb2_queue->type, vb->index);
+
+       q_data = mtk_vdec_get_q_data(ctx, vb->vb2_queue->type);
+
+       for (i = 0; i < q_data->fmt->num_planes; i++) {
+               if (vb2_plane_size(vb, i) < q_data->sizeimage[i]) {
+                       mtk_v4l2_err("data will not fit into plane %d (%lu < %d)",
+                               i, vb2_plane_size(vb, i),
+                               q_data->sizeimage[i]);
+               }
+       }
+
+       return 0;
+}
+
+void vb2ops_vdec_buf_finish(struct vb2_buffer *vb)
+{
+       struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+       struct vb2_v4l2_buffer *vb2_v4l2;
+       struct mtk_video_dec_buf *buf;
+       bool buf_error;
+
+       vb2_v4l2 = container_of(vb, struct vb2_v4l2_buffer, vb2_buf);
+       buf = container_of(vb2_v4l2, struct mtk_video_dec_buf, m2m_buf.vb);
+       mutex_lock(&ctx->lock);
+       if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               buf->queued_in_v4l2 = false;
+               buf->queued_in_vb2 = false;
+       }
+       buf_error = buf->error;
+       mutex_unlock(&ctx->lock);
+
+       if (buf_error) {
+               mtk_v4l2_err("Unrecoverable error on buffer.");
+               ctx->state = MTK_STATE_ABORT;
+       }
+}
+
+int vb2ops_vdec_buf_init(struct vb2_buffer *vb)
+{
+       struct vb2_v4l2_buffer *vb2_v4l2 = container_of(vb,
+                                       struct vb2_v4l2_buffer, vb2_buf);
+       struct mtk_video_dec_buf *buf = container_of(vb2_v4l2,
+                                       struct mtk_video_dec_buf, m2m_buf.vb);
+
+       if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               buf->used = false;
+               buf->queued_in_v4l2 = false;
+       }
+
+       return 0;
+}
+
+int vb2ops_vdec_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+       struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(q);
+
+       if (ctx->state == MTK_STATE_FLUSH)
+               ctx->state = MTK_STATE_HEADER;
+
+       return 0;
+}
+
+void vb2ops_vdec_stop_streaming(struct vb2_queue *q)
+{
+       struct vb2_v4l2_buffer *src_buf = NULL, *dst_buf = NULL;
+       struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(q);
+       int ret;
+
+       mtk_v4l2_debug(3, "[%d] (%d) state=(%x) ctx->decoded_frame_cnt=%d",
+                       ctx->id, q->type, ctx->state, ctx->decoded_frame_cnt);
+
+       if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               while ((src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx))) {
+                       if (src_buf != &ctx->empty_flush_buf.vb) {
+                               struct media_request *req =
+                                       src_buf->vb2_buf.req_obj.req;
+                               v4l2_m2m_buf_done(src_buf,
+                                               VB2_BUF_STATE_ERROR);
+                               if (req)
+                                       v4l2_ctrl_request_complete(req, &ctx->ctrl_hdl);
+                       }
+               }
+               return;
+       }
+
+       if (ctx->state >= MTK_STATE_HEADER) {
+
+               /* Until STREAMOFF is called on the CAPTURE queue
+                * (acknowledging the event), the driver operates
+                * as if the resolution hasn't changed yet, i.e.
+                * VIDIOC_G_FMT< etc. return previous resolution.
+                * So we update picinfo here
+                */
+               ctx->picinfo = ctx->last_decoded_picinfo;
+
+               mtk_v4l2_debug(2,
+                               "[%d]-> new(%d,%d), old(%d,%d), real(%d,%d)",
+                               ctx->id, ctx->last_decoded_picinfo.pic_w,
+                               ctx->last_decoded_picinfo.pic_h,
+                               ctx->picinfo.pic_w, ctx->picinfo.pic_h,
+                               ctx->last_decoded_picinfo.buf_w,
+                               ctx->last_decoded_picinfo.buf_h);
+
+               ret = ctx->dev->vdec_pdata->flush_decoder(ctx);
+               if (ret)
+                       mtk_v4l2_err("DecodeFinal failed, ret=%d", ret);
+       }
+       ctx->state = MTK_STATE_FLUSH;
+
+       while ((dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx))) {
+               vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0);
+               if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2)
+                       vb2_set_plane_payload(&dst_buf->vb2_buf, 1, 0);
+               v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);
+       }
+
+}
+
+static void m2mops_vdec_device_run(void *priv)
+{
+       struct mtk_vcodec_ctx *ctx = priv;
+       struct mtk_vcodec_dev *dev = ctx->dev;
+
+       queue_work(dev->decode_workqueue, &ctx->decode_work);
+}
+
+static int m2mops_vdec_job_ready(void *m2m_priv)
+{
+       struct mtk_vcodec_ctx *ctx = m2m_priv;
+
+       mtk_v4l2_debug(3, "[%d]", ctx->id);
+
+       if (ctx->state == MTK_STATE_ABORT)
+               return 0;
+
+       if ((ctx->last_decoded_picinfo.pic_w != ctx->picinfo.pic_w) ||
+           (ctx->last_decoded_picinfo.pic_h != ctx->picinfo.pic_h))
+               return 0;
+
+       if (ctx->state != MTK_STATE_HEADER)
+               return 0;
+
+       return 1;
+}
+
+static void m2mops_vdec_job_abort(void *priv)
+{
+       struct mtk_vcodec_ctx *ctx = priv;
+
+       ctx->state = MTK_STATE_ABORT;
+}
+
+const struct v4l2_m2m_ops mtk_vdec_m2m_ops = {
+       .device_run     = m2mops_vdec_device_run,
+       .job_ready      = m2mops_vdec_job_ready,
+       .job_abort      = m2mops_vdec_job_abort,
+};
+
+const struct v4l2_ioctl_ops mtk_vdec_ioctl_ops = {
+       .vidioc_streamon        = v4l2_m2m_ioctl_streamon,
+       .vidioc_streamoff       = v4l2_m2m_ioctl_streamoff,
+       .vidioc_reqbufs         = v4l2_m2m_ioctl_reqbufs,
+       .vidioc_querybuf        = v4l2_m2m_ioctl_querybuf,
+       .vidioc_expbuf          = v4l2_m2m_ioctl_expbuf,
+
+       .vidioc_qbuf            = vidioc_vdec_qbuf,
+       .vidioc_dqbuf           = vidioc_vdec_dqbuf,
+
+       .vidioc_try_fmt_vid_cap_mplane  = vidioc_try_fmt_vid_cap_mplane,
+       .vidioc_try_fmt_vid_out_mplane  = vidioc_try_fmt_vid_out_mplane,
+
+       .vidioc_s_fmt_vid_cap_mplane    = vidioc_vdec_s_fmt,
+       .vidioc_s_fmt_vid_out_mplane    = vidioc_vdec_s_fmt,
+       .vidioc_g_fmt_vid_cap_mplane    = vidioc_vdec_g_fmt,
+       .vidioc_g_fmt_vid_out_mplane    = vidioc_vdec_g_fmt,
+
+       .vidioc_create_bufs             = v4l2_m2m_ioctl_create_bufs,
+
+       .vidioc_enum_fmt_vid_cap        = vidioc_vdec_enum_fmt_vid_cap,
+       .vidioc_enum_fmt_vid_out        = vidioc_vdec_enum_fmt_vid_out,
+       .vidioc_enum_framesizes = vidioc_enum_framesizes,
+
+       .vidioc_querycap                = vidioc_vdec_querycap,
+       .vidioc_subscribe_event         = vidioc_vdec_subscribe_evt,
+       .vidioc_unsubscribe_event       = v4l2_event_unsubscribe,
+       .vidioc_g_selection             = vidioc_vdec_g_selection,
+       .vidioc_s_selection             = vidioc_vdec_s_selection,
+
+       .vidioc_decoder_cmd = vidioc_decoder_cmd,
+       .vidioc_try_decoder_cmd = vidioc_try_decoder_cmd,
+};
+
+int mtk_vcodec_dec_queue_init(void *priv, struct vb2_queue *src_vq,
+                          struct vb2_queue *dst_vq)
+{
+       struct mtk_vcodec_ctx *ctx = priv;
+       int ret = 0;
+
+       mtk_v4l2_debug(3, "[%d]", ctx->id);
+
+       src_vq->type            = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+       src_vq->io_modes        = VB2_DMABUF | VB2_MMAP;
+       src_vq->drv_priv        = ctx;
+       src_vq->buf_struct_size = sizeof(struct mtk_video_dec_buf);
+       src_vq->ops             = ctx->dev->vdec_pdata->vdec_vb2_ops;
+       src_vq->mem_ops         = &vb2_dma_contig_memops;
+       src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+       src_vq->lock            = &ctx->dev->dev_mutex;
+       src_vq->dev             = &ctx->dev->plat_dev->dev;
+
+       ret = vb2_queue_init(src_vq);
+       if (ret) {
+               mtk_v4l2_err("Failed to initialize videobuf2 queue(output)");
+               return ret;
+       }
+       dst_vq->type            = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+       dst_vq->io_modes        = VB2_DMABUF | VB2_MMAP;
+       dst_vq->drv_priv        = ctx;
+       dst_vq->buf_struct_size = sizeof(struct mtk_video_dec_buf);
+       dst_vq->ops             = ctx->dev->vdec_pdata->vdec_vb2_ops;
+       dst_vq->mem_ops         = &vb2_dma_contig_memops;
+       dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+       dst_vq->lock            = &ctx->dev->dev_mutex;
+       dst_vq->dev             = &ctx->dev->plat_dev->dev;
+
+       ret = vb2_queue_init(dst_vq);
+       if (ret)
+               mtk_v4l2_err("Failed to initialize videobuf2 queue(capture)");
+
+       return ret;
+}
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_dec.h b/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_dec.h
new file mode 100644 (file)
index 0000000..66cd6d2
--- /dev/null
@@ -0,0 +1,100 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: PC Chen <pc.chen@mediatek.com>
+ *         Tiffany Lin <tiffany.lin@mediatek.com>
+ */
+
+#ifndef _MTK_VCODEC_DEC_H_
+#define _MTK_VCODEC_DEC_H_
+
+#include <media/videobuf2-core.h>
+#include <media/v4l2-mem2mem.h>
+
+#define VCODEC_DEC_ALIGNED_64 64
+#define VCODEC_CAPABILITY_4K_DISABLED  0x10
+#define VCODEC_DEC_4K_CODED_WIDTH      4096U
+#define VCODEC_DEC_4K_CODED_HEIGHT     2304U
+#define MTK_VDEC_MAX_W 2048U
+#define MTK_VDEC_MAX_H 1088U
+#define MTK_VDEC_MIN_W 64U
+#define MTK_VDEC_MIN_H 64U
+
+#define MTK_VDEC_IRQ_STATUS_DEC_SUCCESS        0x10000
+
+/**
+ * struct vdec_fb  - decoder frame buffer
+ * @base_y     : Y plane memory info
+ * @base_c     : C plane memory info
+ * @status      : frame buffer status (vdec_fb_status)
+ */
+struct vdec_fb {
+       struct mtk_vcodec_mem   base_y;
+       struct mtk_vcodec_mem   base_c;
+       unsigned int    status;
+};
+
+/**
+ * struct mtk_video_dec_buf - Private data related to each VB2 buffer.
+ * @m2m_buf:   M2M buffer
+ * @list:      link list
+ * @used:      Capture buffer contain decoded frame data and keep in
+ *                     codec data structure
+ * @queued_in_vb2:     Capture buffer is queue in vb2
+ * @queued_in_v4l2:    Capture buffer is in v4l2 driver, but not in vb2
+ *                     queue yet
+ * @error:             An unrecoverable error occurs on this buffer.
+ * @frame_buffer:      Decode status, and buffer information of Capture buffer
+ * @bs_buffer: Output buffer info
+ *
+ * Note : These status information help us track and debug buffer state
+ */
+struct mtk_video_dec_buf {
+       struct v4l2_m2m_buffer  m2m_buf;
+
+       bool    used;
+       bool    queued_in_vb2;
+       bool    queued_in_v4l2;
+       bool    error;
+
+       union {
+               struct vdec_fb  frame_buffer;
+               struct mtk_vcodec_mem   bs_buffer;
+       };
+};
+
+extern const struct v4l2_ioctl_ops mtk_vdec_ioctl_ops;
+extern const struct v4l2_m2m_ops mtk_vdec_m2m_ops;
+extern const struct media_device_ops mtk_vcodec_media_ops;
+extern const struct mtk_vcodec_dec_pdata mtk_vdec_8173_pdata;
+extern const struct mtk_vcodec_dec_pdata mtk_vdec_8183_pdata;
+extern const struct mtk_vcodec_dec_pdata mtk_lat_sig_core_pdata;
+
+
+/*
+ * mtk_vdec_lock/mtk_vdec_unlock are for ctx instance to
+ * get/release lock before/after access decoder hw.
+ * mtk_vdec_lock get decoder hw lock and set curr_ctx
+ * to ctx instance that get lock
+ */
+void mtk_vdec_unlock(struct mtk_vcodec_ctx *ctx);
+void mtk_vdec_lock(struct mtk_vcodec_ctx *ctx);
+int mtk_vcodec_dec_queue_init(void *priv, struct vb2_queue *src_vq,
+                          struct vb2_queue *dst_vq);
+void mtk_vcodec_dec_set_default_params(struct mtk_vcodec_ctx *ctx);
+void mtk_vcodec_dec_release(struct mtk_vcodec_ctx *ctx);
+
+/*
+ * VB2 ops
+ */
+int vb2ops_vdec_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
+                           unsigned int *nplanes, unsigned int sizes[],
+                           struct device *alloc_devs[]);
+int vb2ops_vdec_buf_prepare(struct vb2_buffer *vb);
+void vb2ops_vdec_buf_finish(struct vb2_buffer *vb);
+int vb2ops_vdec_buf_init(struct vb2_buffer *vb);
+int vb2ops_vdec_start_streaming(struct vb2_queue *q, unsigned int count);
+void vb2ops_vdec_stop_streaming(struct vb2_queue *q);
+
+
+#endif /* _MTK_VCODEC_DEC_H_ */
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_dec_drv.c
new file mode 100644 (file)
index 0000000..48dad9b
--- /dev/null
@@ -0,0 +1,509 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: PC Chen <pc.chen@mediatek.com>
+ *         Tiffany Lin <tiffany.lin@mediatek.com>
+ */
+
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/pm_runtime.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/v4l2-device.h>
+
+#include "mtk_vcodec_drv.h"
+#include "mtk_vcodec_dec.h"
+#include "mtk_vcodec_dec_hw.h"
+#include "mtk_vcodec_dec_pm.h"
+#include "mtk_vcodec_intr.h"
+#include "mtk_vcodec_util.h"
+#include "mtk_vcodec_fw.h"
+
+static int mtk_vcodec_get_hw_count(struct mtk_vcodec_dev *dev)
+{
+       switch (dev->vdec_pdata->hw_arch) {
+       case MTK_VDEC_PURE_SINGLE_CORE:
+               return MTK_VDEC_ONE_CORE;
+       case MTK_VDEC_LAT_SINGLE_CORE:
+               return MTK_VDEC_ONE_LAT_ONE_CORE;
+       default:
+               mtk_v4l2_err("hw arch %d not supported", dev->vdec_pdata->hw_arch);
+               return MTK_VDEC_NO_HW;
+       }
+}
+
+static irqreturn_t mtk_vcodec_dec_irq_handler(int irq, void *priv)
+{
+       struct mtk_vcodec_dev *dev = priv;
+       struct mtk_vcodec_ctx *ctx;
+       u32 cg_status = 0;
+       unsigned int dec_done_status = 0;
+       void __iomem *vdec_misc_addr = dev->reg_base[VDEC_MISC] +
+                                       VDEC_IRQ_CFG_REG;
+
+       ctx = mtk_vcodec_get_curr_ctx(dev, MTK_VDEC_CORE);
+
+       /* check if HW active or not */
+       cg_status = readl(dev->reg_base[0]);
+       if ((cg_status & VDEC_HW_ACTIVE) != 0) {
+               mtk_v4l2_err("DEC ISR, VDEC active is not 0x0 (0x%08x)",
+                            cg_status);
+               return IRQ_HANDLED;
+       }
+
+       dec_done_status = readl(vdec_misc_addr);
+       ctx->irq_status = dec_done_status;
+       if ((dec_done_status & MTK_VDEC_IRQ_STATUS_DEC_SUCCESS) !=
+               MTK_VDEC_IRQ_STATUS_DEC_SUCCESS)
+               return IRQ_HANDLED;
+
+       /* clear interrupt */
+       writel((readl(vdec_misc_addr) | VDEC_IRQ_CFG),
+               dev->reg_base[VDEC_MISC] + VDEC_IRQ_CFG_REG);
+       writel((readl(vdec_misc_addr) & ~VDEC_IRQ_CLR),
+               dev->reg_base[VDEC_MISC] + VDEC_IRQ_CFG_REG);
+
+       wake_up_ctx(ctx, MTK_INST_IRQ_RECEIVED, 0);
+
+       mtk_v4l2_debug(3,
+                       "mtk_vcodec_dec_irq_handler :wake up ctx %d, dec_done_status=%x",
+                       ctx->id, dec_done_status);
+
+       return IRQ_HANDLED;
+}
+
+static int mtk_vcodec_get_reg_bases(struct mtk_vcodec_dev *dev)
+{
+       struct platform_device *pdev = dev->plat_dev;
+       int reg_num, i;
+
+       /* Sizeof(u32) * 4 bytes for each register base. */
+       reg_num = of_property_count_elems_of_size(pdev->dev.of_node, "reg",
+                                                 sizeof(u32) * 4);
+       if (reg_num <= 0 || reg_num > NUM_MAX_VDEC_REG_BASE) {
+               dev_err(&pdev->dev, "Invalid register property size: %d\n", reg_num);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < reg_num; i++) {
+               dev->reg_base[i] = devm_platform_ioremap_resource(pdev, i);
+               if (IS_ERR(dev->reg_base[i]))
+                       return PTR_ERR(dev->reg_base[i]);
+
+               mtk_v4l2_debug(2, "reg[%d] base=%p", i, dev->reg_base[i]);
+       }
+
+       return 0;
+}
+
+static int mtk_vcodec_init_dec_resources(struct mtk_vcodec_dev *dev)
+{
+       struct platform_device *pdev = dev->plat_dev;
+       int ret;
+
+       ret = mtk_vcodec_get_reg_bases(dev);
+       if (ret)
+               return ret;
+
+       if (dev->vdec_pdata->is_subdev_supported)
+               return 0;
+
+       dev->dec_irq = platform_get_irq(pdev, 0);
+       if (dev->dec_irq < 0) {
+               dev_err(&pdev->dev, "failed to get irq number");
+               return dev->dec_irq;
+       }
+
+       irq_set_status_flags(dev->dec_irq, IRQ_NOAUTOEN);
+       ret = devm_request_irq(&pdev->dev, dev->dec_irq,
+                              mtk_vcodec_dec_irq_handler, 0, pdev->name, dev);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to install dev->dec_irq %d (%d)",
+                       dev->dec_irq, ret);
+               return ret;
+       }
+
+       ret = mtk_vcodec_init_dec_clk(pdev, &dev->pm);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to get mt vcodec clock source");
+               return ret;
+       }
+
+       pm_runtime_enable(&pdev->dev);
+       return 0;
+}
+
+static int fops_vcodec_open(struct file *file)
+{
+       struct mtk_vcodec_dev *dev = video_drvdata(file);
+       struct mtk_vcodec_ctx *ctx = NULL;
+       int ret = 0, i, hw_count;
+       struct vb2_queue *src_vq;
+
+       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+
+       mutex_lock(&dev->dev_mutex);
+       ctx->id = dev->id_counter++;
+       v4l2_fh_init(&ctx->fh, video_devdata(file));
+       file->private_data = &ctx->fh;
+       v4l2_fh_add(&ctx->fh);
+       INIT_LIST_HEAD(&ctx->list);
+       ctx->dev = dev;
+       if (ctx->dev->vdec_pdata->is_subdev_supported) {
+               hw_count = mtk_vcodec_get_hw_count(dev);
+               if (!hw_count || !dev->subdev_prob_done) {
+                       ret = -EINVAL;
+                       goto err_ctrls_setup;
+               }
+
+               ret = dev->subdev_prob_done(dev);
+               if (ret)
+                       goto err_ctrls_setup;
+
+               for (i = 0; i < hw_count; i++)
+                       init_waitqueue_head(&ctx->queue[i]);
+       } else {
+               init_waitqueue_head(&ctx->queue[0]);
+       }
+       mutex_init(&ctx->lock);
+
+       ctx->type = MTK_INST_DECODER;
+       ret = dev->vdec_pdata->ctrls_setup(ctx);
+       if (ret) {
+               mtk_v4l2_err("Failed to setup mt vcodec controls");
+               goto err_ctrls_setup;
+       }
+       ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev_dec, ctx,
+               &mtk_vcodec_dec_queue_init);
+       if (IS_ERR((__force void *)ctx->m2m_ctx)) {
+               ret = PTR_ERR((__force void *)ctx->m2m_ctx);
+               mtk_v4l2_err("Failed to v4l2_m2m_ctx_init() (%d)",
+                       ret);
+               goto err_m2m_ctx_init;
+       }
+       src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx,
+                               V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+       ctx->empty_flush_buf.vb.vb2_buf.vb2_queue = src_vq;
+       mtk_vcodec_dec_set_default_params(ctx);
+
+       if (v4l2_fh_is_singular(&ctx->fh)) {
+               ret = mtk_vcodec_dec_pw_on(dev, MTK_VDEC_LAT0);
+               if (ret < 0)
+                       goto err_load_fw;
+               /*
+                * Does nothing if firmware was already loaded.
+                */
+               ret = mtk_vcodec_fw_load_firmware(dev->fw_handler);
+               if (ret < 0) {
+                       /*
+                        * Return 0 if downloading firmware successfully,
+                        * otherwise it is failed
+                        */
+                       mtk_v4l2_err("failed to load firmware!");
+                       goto err_load_fw;
+               }
+
+               dev->dec_capability =
+                       mtk_vcodec_fw_get_vdec_capa(dev->fw_handler);
+               mtk_v4l2_debug(0, "decoder capability %x", dev->dec_capability);
+       }
+
+       list_add(&ctx->list, &dev->ctx_list);
+
+       mutex_unlock(&dev->dev_mutex);
+       mtk_v4l2_debug(0, "%s decoder [%d]", dev_name(&dev->plat_dev->dev),
+                       ctx->id);
+       return ret;
+
+       /* Deinit when failure occurred */
+err_load_fw:
+       v4l2_m2m_ctx_release(ctx->m2m_ctx);
+err_m2m_ctx_init:
+       v4l2_ctrl_handler_free(&ctx->ctrl_hdl);
+err_ctrls_setup:
+       v4l2_fh_del(&ctx->fh);
+       v4l2_fh_exit(&ctx->fh);
+       kfree(ctx);
+       mutex_unlock(&dev->dev_mutex);
+
+       return ret;
+}
+
+static int fops_vcodec_release(struct file *file)
+{
+       struct mtk_vcodec_dev *dev = video_drvdata(file);
+       struct mtk_vcodec_ctx *ctx = fh_to_ctx(file->private_data);
+
+       mtk_v4l2_debug(0, "[%d] decoder", ctx->id);
+       mutex_lock(&dev->dev_mutex);
+
+       /*
+        * Call v4l2_m2m_ctx_release before mtk_vcodec_dec_release. First, it
+        * makes sure the worker thread is not running after vdec_if_deinit.
+        * Second, the decoder will be flushed and all the buffers will be
+        * returned in stop_streaming.
+        */
+       v4l2_m2m_ctx_release(ctx->m2m_ctx);
+       mtk_vcodec_dec_release(ctx);
+
+       if (v4l2_fh_is_singular(&ctx->fh))
+               mtk_vcodec_dec_pw_off(dev, MTK_VDEC_LAT0);
+       v4l2_fh_del(&ctx->fh);
+       v4l2_fh_exit(&ctx->fh);
+       v4l2_ctrl_handler_free(&ctx->ctrl_hdl);
+
+       list_del_init(&ctx->list);
+       kfree(ctx);
+       mutex_unlock(&dev->dev_mutex);
+       return 0;
+}
+
+static const struct v4l2_file_operations mtk_vcodec_fops = {
+       .owner          = THIS_MODULE,
+       .open           = fops_vcodec_open,
+       .release        = fops_vcodec_release,
+       .poll           = v4l2_m2m_fop_poll,
+       .unlocked_ioctl = video_ioctl2,
+       .mmap           = v4l2_m2m_fop_mmap,
+};
+
+static int mtk_vcodec_probe(struct platform_device *pdev)
+{
+       struct mtk_vcodec_dev *dev;
+       struct video_device *vfd_dec;
+       phandle rproc_phandle;
+       enum mtk_vcodec_fw_type fw_type;
+       int i, ret;
+
+       dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&dev->ctx_list);
+       dev->plat_dev = pdev;
+
+       dev->vdec_pdata = of_device_get_match_data(&pdev->dev);
+       if (!of_property_read_u32(pdev->dev.of_node, "mediatek,vpu",
+                                 &rproc_phandle)) {
+               fw_type = VPU;
+       } else if (!of_property_read_u32(pdev->dev.of_node, "mediatek,scp",
+                                        &rproc_phandle)) {
+               fw_type = SCP;
+       } else {
+               mtk_v4l2_err("Could not get vdec IPI device");
+               return -ENODEV;
+       }
+       dma_set_max_seg_size(&pdev->dev, UINT_MAX);
+
+       dev->fw_handler = mtk_vcodec_fw_select(dev, fw_type, DECODER);
+       if (IS_ERR(dev->fw_handler))
+               return PTR_ERR(dev->fw_handler);
+
+       ret = mtk_vcodec_init_dec_resources(dev);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to init dec resources");
+               goto err_dec_pm;
+       }
+
+       if (IS_VDEC_LAT_ARCH(dev->vdec_pdata->hw_arch)) {
+               vdec_msg_queue_init_ctx(&dev->msg_queue_core_ctx, MTK_VDEC_CORE);
+               dev->core_workqueue =
+                       alloc_ordered_workqueue("core-decoder",
+                                               WQ_MEM_RECLAIM | WQ_FREEZABLE);
+               if (!dev->core_workqueue) {
+                       mtk_v4l2_err("Failed to create core workqueue");
+                       ret = -EINVAL;
+                       goto err_res;
+               }
+       }
+
+       if (of_get_property(pdev->dev.of_node, "dma-ranges", NULL)) {
+               ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34));
+               if (ret) {
+                       mtk_v4l2_err("Failed to set mask");
+                       goto err_core_workq;
+               }
+       }
+
+       for (i = 0; i < MTK_VDEC_HW_MAX; i++)
+               mutex_init(&dev->dec_mutex[i]);
+       mutex_init(&dev->dev_mutex);
+       spin_lock_init(&dev->irqlock);
+
+       snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), "%s",
+               "[/MTK_V4L2_VDEC]");
+
+       ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+       if (ret) {
+               mtk_v4l2_err("v4l2_device_register err=%d", ret);
+               goto err_core_workq;
+       }
+
+       init_waitqueue_head(&dev->queue);
+
+       vfd_dec = video_device_alloc();
+       if (!vfd_dec) {
+               mtk_v4l2_err("Failed to allocate video device");
+               ret = -ENOMEM;
+               goto err_dec_alloc;
+       }
+       vfd_dec->fops           = &mtk_vcodec_fops;
+       vfd_dec->ioctl_ops      = &mtk_vdec_ioctl_ops;
+       vfd_dec->release        = video_device_release;
+       vfd_dec->lock           = &dev->dev_mutex;
+       vfd_dec->v4l2_dev       = &dev->v4l2_dev;
+       vfd_dec->vfl_dir        = VFL_DIR_M2M;
+       vfd_dec->device_caps    = V4L2_CAP_VIDEO_M2M_MPLANE |
+                       V4L2_CAP_STREAMING;
+
+       snprintf(vfd_dec->name, sizeof(vfd_dec->name), "%s",
+               MTK_VCODEC_DEC_NAME);
+       video_set_drvdata(vfd_dec, dev);
+       dev->vfd_dec = vfd_dec;
+       platform_set_drvdata(pdev, dev);
+
+       dev->m2m_dev_dec = v4l2_m2m_init(&mtk_vdec_m2m_ops);
+       if (IS_ERR((__force void *)dev->m2m_dev_dec)) {
+               mtk_v4l2_err("Failed to init mem2mem dec device");
+               ret = PTR_ERR((__force void *)dev->m2m_dev_dec);
+               goto err_dec_alloc;
+       }
+
+       dev->decode_workqueue =
+               alloc_ordered_workqueue(MTK_VCODEC_DEC_NAME,
+                       WQ_MEM_RECLAIM | WQ_FREEZABLE);
+       if (!dev->decode_workqueue) {
+               mtk_v4l2_err("Failed to create decode workqueue");
+               ret = -EINVAL;
+               goto err_event_workq;
+       }
+
+       if (dev->vdec_pdata->is_subdev_supported) {
+               ret = of_platform_populate(pdev->dev.of_node, NULL, NULL,
+                                          &pdev->dev);
+               if (ret) {
+                       mtk_v4l2_err("Main device of_platform_populate failed.");
+                       goto err_reg_cont;
+               }
+       }
+
+       ret = video_register_device(vfd_dec, VFL_TYPE_VIDEO, -1);
+       if (ret) {
+               mtk_v4l2_err("Failed to register video device");
+               goto err_reg_cont;
+       }
+
+       if (dev->vdec_pdata->uses_stateless_api) {
+               dev->mdev_dec.dev = &pdev->dev;
+               strscpy(dev->mdev_dec.model, MTK_VCODEC_DEC_NAME,
+                       sizeof(dev->mdev_dec.model));
+
+               media_device_init(&dev->mdev_dec);
+               dev->mdev_dec.ops = &mtk_vcodec_media_ops;
+               dev->v4l2_dev.mdev = &dev->mdev_dec;
+
+               ret = v4l2_m2m_register_media_controller(dev->m2m_dev_dec, dev->vfd_dec,
+                                                        MEDIA_ENT_F_PROC_VIDEO_DECODER);
+               if (ret) {
+                       mtk_v4l2_err("Failed to register media controller");
+                       goto err_dec_mem_init;
+               }
+
+               ret = media_device_register(&dev->mdev_dec);
+               if (ret) {
+                       mtk_v4l2_err("Failed to register media device");
+                       goto err_media_reg;
+               }
+
+               mtk_v4l2_debug(0, "media registered as /dev/media%d", vfd_dec->minor);
+       }
+
+       mtk_v4l2_debug(0, "decoder registered as /dev/video%d", vfd_dec->minor);
+
+       return 0;
+
+err_media_reg:
+       v4l2_m2m_unregister_media_controller(dev->m2m_dev_dec);
+err_dec_mem_init:
+       video_unregister_device(vfd_dec);
+err_reg_cont:
+       if (dev->vdec_pdata->uses_stateless_api)
+               media_device_cleanup(&dev->mdev_dec);
+       destroy_workqueue(dev->decode_workqueue);
+err_event_workq:
+       v4l2_m2m_release(dev->m2m_dev_dec);
+err_dec_alloc:
+       v4l2_device_unregister(&dev->v4l2_dev);
+err_core_workq:
+       if (IS_VDEC_LAT_ARCH(dev->vdec_pdata->hw_arch))
+               destroy_workqueue(dev->core_workqueue);
+err_res:
+       pm_runtime_disable(dev->pm.dev);
+err_dec_pm:
+       mtk_vcodec_fw_release(dev->fw_handler);
+       return ret;
+}
+
+static const struct of_device_id mtk_vcodec_match[] = {
+       {
+               .compatible = "mediatek,mt8173-vcodec-dec",
+               .data = &mtk_vdec_8173_pdata,
+       },
+       {
+               .compatible = "mediatek,mt8183-vcodec-dec",
+               .data = &mtk_vdec_8183_pdata,
+       },
+       {
+               .compatible = "mediatek,mt8192-vcodec-dec",
+               .data = &mtk_lat_sig_core_pdata,
+       },
+       {},
+};
+
+MODULE_DEVICE_TABLE(of, mtk_vcodec_match);
+
+static int mtk_vcodec_dec_remove(struct platform_device *pdev)
+{
+       struct mtk_vcodec_dev *dev = platform_get_drvdata(pdev);
+
+       destroy_workqueue(dev->decode_workqueue);
+
+       if (media_devnode_is_registered(dev->mdev_dec.devnode)) {
+               media_device_unregister(&dev->mdev_dec);
+               v4l2_m2m_unregister_media_controller(dev->m2m_dev_dec);
+               media_device_cleanup(&dev->mdev_dec);
+       }
+
+       if (dev->m2m_dev_dec)
+               v4l2_m2m_release(dev->m2m_dev_dec);
+
+       if (dev->vfd_dec)
+               video_unregister_device(dev->vfd_dec);
+
+       v4l2_device_unregister(&dev->v4l2_dev);
+       pm_runtime_disable(dev->pm.dev);
+       mtk_vcodec_fw_release(dev->fw_handler);
+       return 0;
+}
+
+static struct platform_driver mtk_vcodec_dec_driver = {
+       .probe  = mtk_vcodec_probe,
+       .remove = mtk_vcodec_dec_remove,
+       .driver = {
+               .name   = MTK_VCODEC_DEC_NAME,
+               .of_match_table = mtk_vcodec_match,
+       },
+};
+
+module_platform_driver(mtk_vcodec_dec_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Mediatek video codec V4L2 decoder driver");
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_dec_hw.c b/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_dec_hw.c
new file mode 100644 (file)
index 0000000..8d2a641
--- /dev/null
@@ -0,0 +1,200 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ * Author: Yunfei Dong <yunfei.dong@mediatek.com>
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+
+#include "mtk_vcodec_drv.h"
+#include "mtk_vcodec_dec.h"
+#include "mtk_vcodec_dec_hw.h"
+#include "mtk_vcodec_dec_pm.h"
+#include "mtk_vcodec_intr.h"
+#include "mtk_vcodec_util.h"
+
+static const struct of_device_id mtk_vdec_hw_match[] = {
+       {
+               .compatible = "mediatek,mtk-vcodec-lat",
+               .data = (void *)MTK_VDEC_LAT0,
+       },
+       {
+               .compatible = "mediatek,mtk-vcodec-core",
+               .data = (void *)MTK_VDEC_CORE,
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, mtk_vdec_hw_match);
+
+static int mtk_vdec_hw_prob_done(struct mtk_vcodec_dev *vdec_dev)
+{
+       struct platform_device *pdev = vdec_dev->plat_dev;
+       struct device_node *subdev_node;
+       enum mtk_vdec_hw_id hw_idx;
+       const struct of_device_id *of_id;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(mtk_vdec_hw_match); i++) {
+               of_id = &mtk_vdec_hw_match[i];
+               subdev_node = of_find_compatible_node(NULL, NULL,
+                                                     of_id->compatible);
+               if (!subdev_node)
+                       continue;
+
+               hw_idx = (enum mtk_vdec_hw_id)(uintptr_t)of_id->data;
+               if (!test_bit(hw_idx, vdec_dev->subdev_bitmap)) {
+                       dev_err(&pdev->dev, "vdec %d is not ready", hw_idx);
+                       return -EAGAIN;
+               }
+       }
+
+       return 0;
+}
+
+static irqreturn_t mtk_vdec_hw_irq_handler(int irq, void *priv)
+{
+       struct mtk_vdec_hw_dev *dev = priv;
+       struct mtk_vcodec_ctx *ctx;
+       u32 cg_status;
+       unsigned int dec_done_status;
+       void __iomem *vdec_misc_addr = dev->reg_base[VDEC_HW_MISC] +
+                                       VDEC_IRQ_CFG_REG;
+
+       ctx = mtk_vcodec_get_curr_ctx(dev->main_dev, dev->hw_idx);
+
+       /* check if HW active or not */
+       cg_status = readl(dev->reg_base[VDEC_HW_SYS]);
+       if (cg_status & VDEC_HW_ACTIVE) {
+               mtk_v4l2_err("vdec active is not 0x0 (0x%08x)",
+                            cg_status);
+               return IRQ_HANDLED;
+       }
+
+       dec_done_status = readl(vdec_misc_addr);
+       if ((dec_done_status & MTK_VDEC_IRQ_STATUS_DEC_SUCCESS) !=
+           MTK_VDEC_IRQ_STATUS_DEC_SUCCESS)
+               return IRQ_HANDLED;
+
+       /* clear interrupt */
+       writel(dec_done_status | VDEC_IRQ_CFG, vdec_misc_addr);
+       writel(dec_done_status & ~VDEC_IRQ_CLR, vdec_misc_addr);
+
+       wake_up_ctx(ctx, MTK_INST_IRQ_RECEIVED, dev->hw_idx);
+
+       mtk_v4l2_debug(3, "wake up ctx %d, dec_done_status=%x",
+                      ctx->id, dec_done_status);
+
+       return IRQ_HANDLED;
+}
+
+static int mtk_vdec_hw_init_irq(struct mtk_vdec_hw_dev *dev)
+{
+       struct platform_device *pdev = dev->plat_dev;
+       int ret;
+
+       dev->dec_irq = platform_get_irq(pdev, 0);
+       if (dev->dec_irq < 0) {
+               dev_err(&pdev->dev, "Failed to get irq resource");
+               return dev->dec_irq;
+       }
+
+       irq_set_status_flags(dev->dec_irq, IRQ_NOAUTOEN);
+       ret = devm_request_irq(&pdev->dev, dev->dec_irq,
+                              mtk_vdec_hw_irq_handler, 0, pdev->name, dev);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to install dev->dec_irq %d (%d)",
+                       dev->dec_irq, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int mtk_vdec_hw_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct mtk_vdec_hw_dev *subdev_dev;
+       struct mtk_vcodec_dev *main_dev;
+       const struct of_device_id *of_id;
+       int hw_idx;
+       int ret;
+
+       if (!dev->parent) {
+               dev_err(dev, "no parent for hardware devices.\n");
+               return -ENODEV;
+       }
+
+       main_dev = dev_get_drvdata(dev->parent);
+       if (!main_dev) {
+               dev_err(dev, "failed to get parent driver data");
+               return -EINVAL;
+       }
+
+       subdev_dev = devm_kzalloc(dev, sizeof(*subdev_dev), GFP_KERNEL);
+       if (!subdev_dev)
+               return -ENOMEM;
+
+       subdev_dev->plat_dev = pdev;
+       ret = mtk_vcodec_init_dec_clk(pdev, &subdev_dev->pm);
+       if (ret)
+               return ret;
+       pm_runtime_enable(&pdev->dev);
+
+       of_id = of_match_device(mtk_vdec_hw_match, dev);
+       if (!of_id) {
+               dev_err(dev, "Can't get vdec subdev id.\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       hw_idx = (enum mtk_vdec_hw_id)(uintptr_t)of_id->data;
+       if (hw_idx >= MTK_VDEC_HW_MAX) {
+               dev_err(dev, "Hardware index %d not correct.\n", hw_idx);
+               ret = -EINVAL;
+               goto err;
+       }
+
+       main_dev->subdev_dev[hw_idx] = subdev_dev;
+       subdev_dev->hw_idx = hw_idx;
+       subdev_dev->main_dev = main_dev;
+       subdev_dev->reg_base[VDEC_HW_SYS] = main_dev->reg_base[VDEC_HW_SYS];
+       set_bit(subdev_dev->hw_idx, main_dev->subdev_bitmap);
+
+       ret = mtk_vdec_hw_init_irq(subdev_dev);
+       if (ret)
+               goto err;
+
+       subdev_dev->reg_base[VDEC_HW_MISC] =
+               devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR((__force void *)subdev_dev->reg_base[VDEC_HW_MISC])) {
+               ret = PTR_ERR((__force void *)subdev_dev->reg_base[VDEC_HW_MISC]);
+               goto err;
+       }
+
+       if (!main_dev->subdev_prob_done)
+               main_dev->subdev_prob_done = mtk_vdec_hw_prob_done;
+
+       platform_set_drvdata(pdev, subdev_dev);
+       return 0;
+err:
+       pm_runtime_disable(subdev_dev->pm.dev);
+       return ret;
+}
+
+static struct platform_driver mtk_vdec_driver = {
+       .probe  = mtk_vdec_hw_probe,
+       .driver = {
+               .name   = "mtk-vdec-comp",
+               .of_match_table = mtk_vdec_hw_match,
+       },
+};
+module_platform_driver(mtk_vdec_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Mediatek video decoder hardware driver");
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_dec_hw.h b/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_dec_hw.h
new file mode 100644 (file)
index 0000000..a63e4b1
--- /dev/null
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ * Author: Yunfei Dong <yunfei.dong@mediatek.com>
+ */
+
+#ifndef _MTK_VCODEC_DEC_HW_H_
+#define _MTK_VCODEC_DEC_HW_H_
+
+#include <linux/io.h>
+#include <linux/platform_device.h>
+
+#include "mtk_vcodec_drv.h"
+
+#define VDEC_HW_ACTIVE 0x10
+#define VDEC_IRQ_CFG 0x11
+#define VDEC_IRQ_CLR 0x10
+#define VDEC_IRQ_CFG_REG 0xa4
+
+/**
+ * enum mtk_vdec_hw_reg_idx - subdev hardware register base index
+ * @VDEC_HW_SYS : vdec soc register index
+ * @VDEC_HW_MISC: vdec misc register index
+ * @VDEC_HW_MAX : vdec supported max register index
+ */
+enum mtk_vdec_hw_reg_idx {
+       VDEC_HW_SYS,
+       VDEC_HW_MISC,
+       VDEC_HW_MAX
+};
+
+/**
+ * struct mtk_vdec_hw_dev - vdec hardware driver data
+ * @plat_dev: platform device
+ * @main_dev: main device
+ * @reg_base: mapped address of MTK Vcodec registers.
+ *
+ * @curr_ctx: the context that is waiting for codec hardware
+ *
+ * @dec_irq : decoder irq resource
+ * @pm      : power management control
+ * @hw_idx  : each hardware index
+ */
+struct mtk_vdec_hw_dev {
+       struct platform_device *plat_dev;
+       struct mtk_vcodec_dev *main_dev;
+       void __iomem *reg_base[VDEC_HW_MAX];
+
+       struct mtk_vcodec_ctx *curr_ctx;
+
+       int dec_irq;
+       struct mtk_vcodec_pm pm;
+       int hw_idx;
+};
+
+#endif /* _MTK_VCODEC_DEC_HW_H_ */
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_dec_pm.c b/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_dec_pm.c
new file mode 100644 (file)
index 0000000..7e0c264
--- /dev/null
@@ -0,0 +1,169 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Tiffany Lin <tiffany.lin@mediatek.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/pm_runtime.h>
+
+#include "mtk_vcodec_dec_hw.h"
+#include "mtk_vcodec_dec_pm.h"
+#include "mtk_vcodec_util.h"
+
+int mtk_vcodec_init_dec_clk(struct platform_device *pdev, struct mtk_vcodec_pm *pm)
+{
+       struct mtk_vcodec_clk *dec_clk;
+       struct mtk_vcodec_clk_info *clk_info;
+       int i = 0, ret;
+
+       dec_clk = &pm->vdec_clk;
+       pm->dev = &pdev->dev;
+
+       dec_clk->clk_num =
+               of_property_count_strings(pdev->dev.of_node, "clock-names");
+       if (dec_clk->clk_num > 0) {
+               dec_clk->clk_info = devm_kcalloc(&pdev->dev,
+                       dec_clk->clk_num, sizeof(*clk_info),
+                       GFP_KERNEL);
+               if (!dec_clk->clk_info)
+                       return -ENOMEM;
+       } else {
+               mtk_v4l2_err("Failed to get vdec clock count");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < dec_clk->clk_num; i++) {
+               clk_info = &dec_clk->clk_info[i];
+               ret = of_property_read_string_index(pdev->dev.of_node,
+                       "clock-names", i, &clk_info->clk_name);
+               if (ret) {
+                       mtk_v4l2_err("Failed to get clock name id = %d", i);
+                       return ret;
+               }
+               clk_info->vcodec_clk = devm_clk_get(&pdev->dev,
+                       clk_info->clk_name);
+               if (IS_ERR(clk_info->vcodec_clk)) {
+                       mtk_v4l2_err("devm_clk_get (%d)%s fail", i,
+                               clk_info->clk_name);
+                       return PTR_ERR(clk_info->vcodec_clk);
+               }
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_vcodec_init_dec_clk);
+
+int mtk_vcodec_dec_pw_on(struct mtk_vcodec_dev *vdec_dev, int hw_idx)
+{
+       struct mtk_vdec_hw_dev *subdev_dev;
+       struct mtk_vcodec_pm *pm;
+       int ret;
+
+       if (vdec_dev->vdec_pdata->is_subdev_supported) {
+               subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx);
+               if (!subdev_dev) {
+                       mtk_v4l2_err("Failed to get hw dev\n");
+                       return -EINVAL;
+               }
+               pm = &subdev_dev->pm;
+       } else {
+               pm = &vdec_dev->pm;
+       }
+
+       ret = pm_runtime_resume_and_get(pm->dev);
+       if (ret)
+               mtk_v4l2_err("pm_runtime_resume_and_get fail %d", ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(mtk_vcodec_dec_pw_on);
+
+void mtk_vcodec_dec_pw_off(struct mtk_vcodec_dev *vdec_dev, int hw_idx)
+{
+       struct mtk_vdec_hw_dev *subdev_dev;
+       struct mtk_vcodec_pm *pm;
+       int ret;
+
+       if (vdec_dev->vdec_pdata->is_subdev_supported) {
+               subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx);
+               if (!subdev_dev) {
+                       mtk_v4l2_err("Failed to get hw dev\n");
+                       return;
+               }
+               pm = &subdev_dev->pm;
+       } else {
+               pm = &vdec_dev->pm;
+       }
+
+       ret = pm_runtime_put_sync(pm->dev);
+       if (ret)
+               mtk_v4l2_err("pm_runtime_put_sync fail %d", ret);
+}
+EXPORT_SYMBOL_GPL(mtk_vcodec_dec_pw_off);
+
+void mtk_vcodec_dec_clock_on(struct mtk_vcodec_dev *vdec_dev, int hw_idx)
+{
+       struct mtk_vdec_hw_dev *subdev_dev;
+       struct mtk_vcodec_pm *pm;
+       struct mtk_vcodec_clk *dec_clk;
+       int ret, i;
+
+       if (vdec_dev->vdec_pdata->is_subdev_supported) {
+               subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx);
+               if (!subdev_dev) {
+                       mtk_v4l2_err("Failed to get hw dev\n");
+                       return;
+               }
+               pm = &subdev_dev->pm;
+               enable_irq(subdev_dev->dec_irq);
+       } else {
+               pm = &vdec_dev->pm;
+               enable_irq(vdec_dev->dec_irq);
+       }
+
+       dec_clk = &pm->vdec_clk;
+       for (i = 0; i < dec_clk->clk_num; i++) {
+               ret = clk_prepare_enable(dec_clk->clk_info[i].vcodec_clk);
+               if (ret) {
+                       mtk_v4l2_err("clk_prepare_enable %d %s fail %d", i,
+                               dec_clk->clk_info[i].clk_name, ret);
+                       goto error;
+               }
+       }
+
+       return;
+error:
+       for (i -= 1; i >= 0; i--)
+               clk_disable_unprepare(dec_clk->clk_info[i].vcodec_clk);
+}
+EXPORT_SYMBOL_GPL(mtk_vcodec_dec_clock_on);
+
+void mtk_vcodec_dec_clock_off(struct mtk_vcodec_dev *vdec_dev, int hw_idx)
+{
+       struct mtk_vdec_hw_dev *subdev_dev;
+       struct mtk_vcodec_pm *pm;
+       struct mtk_vcodec_clk *dec_clk;
+       int i;
+
+       if (vdec_dev->vdec_pdata->is_subdev_supported) {
+               subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx);
+               if (!subdev_dev) {
+                       mtk_v4l2_err("Failed to get hw dev\n");
+                       return;
+               }
+               pm = &subdev_dev->pm;
+               disable_irq(subdev_dev->dec_irq);
+       } else {
+               pm = &vdec_dev->pm;
+               disable_irq(vdec_dev->dec_irq);
+       }
+
+       dec_clk = &pm->vdec_clk;
+       for (i = dec_clk->clk_num - 1; i >= 0; i--)
+               clk_disable_unprepare(dec_clk->clk_info[i].vcodec_clk);
+}
+EXPORT_SYMBOL_GPL(mtk_vcodec_dec_clock_off);
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_dec_pm.h b/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_dec_pm.h
new file mode 100644 (file)
index 0000000..3cc721b
--- /dev/null
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Tiffany Lin <tiffany.lin@mediatek.com>
+ */
+
+#ifndef _MTK_VCODEC_DEC_PM_H_
+#define _MTK_VCODEC_DEC_PM_H_
+
+#include "mtk_vcodec_drv.h"
+
+int mtk_vcodec_init_dec_clk(struct platform_device *pdev, struct mtk_vcodec_pm *pm);
+
+int mtk_vcodec_dec_pw_on(struct mtk_vcodec_dev *vdec_dev, int hw_idx);
+void mtk_vcodec_dec_pw_off(struct mtk_vcodec_dev *vdec_dev, int hw_idx);
+void mtk_vcodec_dec_clock_on(struct mtk_vcodec_dev *vdec_dev, int hw_idx);
+void mtk_vcodec_dec_clock_off(struct mtk_vcodec_dev *vdec_dev, int hw_idx);
+
+#endif /* _MTK_VCODEC_DEC_PM_H_ */
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_dec_stateful.c b/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_dec_stateful.c
new file mode 100644 (file)
index 0000000..04ca43c
--- /dev/null
@@ -0,0 +1,630 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <media/v4l2-event.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "mtk_vcodec_drv.h"
+#include "mtk_vcodec_dec.h"
+#include "mtk_vcodec_intr.h"
+#include "mtk_vcodec_util.h"
+#include "mtk_vcodec_dec_pm.h"
+#include "vdec_drv_if.h"
+
+static const struct mtk_video_fmt mtk_video_formats[] = {
+       {
+               .fourcc = V4L2_PIX_FMT_H264,
+               .type = MTK_FMT_DEC,
+               .num_planes = 1,
+               .flags = V4L2_FMT_FLAG_DYN_RESOLUTION,
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_VP8,
+               .type = MTK_FMT_DEC,
+               .num_planes = 1,
+               .flags = V4L2_FMT_FLAG_DYN_RESOLUTION,
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_VP9,
+               .type = MTK_FMT_DEC,
+               .num_planes = 1,
+               .flags = V4L2_FMT_FLAG_DYN_RESOLUTION,
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_MT21C,
+               .type = MTK_FMT_FRAME,
+               .num_planes = 2,
+       },
+};
+
+#define NUM_FORMATS ARRAY_SIZE(mtk_video_formats)
+#define DEFAULT_OUT_FMT_IDX 0
+#define DEFAULT_CAP_FMT_IDX 3
+
+static const struct mtk_codec_framesizes mtk_vdec_framesizes[] = {
+       {
+               .fourcc = V4L2_PIX_FMT_H264,
+               .stepwise = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16,
+                             MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 },
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_VP8,
+               .stepwise = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16,
+                             MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 },
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_VP9,
+               .stepwise = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16,
+                             MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 },
+       },
+};
+
+#define NUM_SUPPORTED_FRAMESIZE ARRAY_SIZE(mtk_vdec_framesizes)
+
+/*
+ * This function tries to clean all display buffers, the buffers will return
+ * in display order.
+ * Note the buffers returned from codec driver may still be in driver's
+ * reference list.
+ */
+static struct vb2_buffer *get_display_buffer(struct mtk_vcodec_ctx *ctx)
+{
+       struct vdec_fb *disp_frame_buffer = NULL;
+       struct mtk_video_dec_buf *dstbuf;
+       struct vb2_v4l2_buffer *vb;
+
+       mtk_v4l2_debug(3, "[%d]", ctx->id);
+       if (vdec_if_get_param(ctx, GET_PARAM_DISP_FRAME_BUFFER,
+                             &disp_frame_buffer)) {
+               mtk_v4l2_err("[%d]Cannot get param : GET_PARAM_DISP_FRAME_BUFFER", ctx->id);
+               return NULL;
+       }
+
+       if (!disp_frame_buffer) {
+               mtk_v4l2_debug(3, "No display frame buffer");
+               return NULL;
+       }
+
+       dstbuf = container_of(disp_frame_buffer, struct mtk_video_dec_buf,
+                             frame_buffer);
+       vb = &dstbuf->m2m_buf.vb;
+       mutex_lock(&ctx->lock);
+       if (dstbuf->used) {
+               vb2_set_plane_payload(&vb->vb2_buf, 0, ctx->picinfo.fb_sz[0]);
+               if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2)
+                       vb2_set_plane_payload(&vb->vb2_buf, 1,
+                                             ctx->picinfo.fb_sz[1]);
+
+               mtk_v4l2_debug(2, "[%d]status=%x queue id=%d to done_list %d",
+                              ctx->id, disp_frame_buffer->status,
+                              vb->vb2_buf.index, dstbuf->queued_in_vb2);
+
+               v4l2_m2m_buf_done(vb, VB2_BUF_STATE_DONE);
+               ctx->decoded_frame_cnt++;
+       }
+       mutex_unlock(&ctx->lock);
+       return &vb->vb2_buf;
+}
+
+/*
+ * This function tries to clean all capture buffers that are not used as
+ * reference buffers by codec driver any more
+ * In this case, we need re-queue buffer to vb2 buffer if user space
+ * already returns this buffer to v4l2 or this buffer is just the output of
+ * previous sps/pps/resolution change decode, or do nothing if user
+ * space still owns this buffer
+ */
+static struct vb2_buffer *get_free_buffer(struct mtk_vcodec_ctx *ctx)
+{
+       struct mtk_video_dec_buf *dstbuf;
+       struct vdec_fb *free_frame_buffer = NULL;
+       struct vb2_v4l2_buffer *vb;
+
+       if (vdec_if_get_param(ctx, GET_PARAM_FREE_FRAME_BUFFER,
+                             &free_frame_buffer)) {
+               mtk_v4l2_err("[%d] Error!! Cannot get param", ctx->id);
+               return NULL;
+       }
+       if (!free_frame_buffer) {
+               mtk_v4l2_debug(3, " No free frame buffer");
+               return NULL;
+       }
+
+       mtk_v4l2_debug(3, "[%d] tmp_frame_addr = 0x%p", ctx->id,
+                      free_frame_buffer);
+
+       dstbuf = container_of(free_frame_buffer, struct mtk_video_dec_buf,
+                             frame_buffer);
+       vb = &dstbuf->m2m_buf.vb;
+
+       mutex_lock(&ctx->lock);
+       if (dstbuf->used) {
+               if (dstbuf->queued_in_vb2 && dstbuf->queued_in_v4l2 &&
+                   free_frame_buffer->status == FB_ST_FREE) {
+                       /*
+                        * After decode sps/pps or non-display buffer, we don't
+                        * need to return capture buffer to user space, but
+                        * just re-queue this capture buffer to vb2 queue.
+                        * This reduce overheads that dq/q unused capture
+                        * buffer. In this case, queued_in_vb2 = true.
+                        */
+                       mtk_v4l2_debug(2, "[%d]status=%x queue id=%d to rdy_queue %d",
+                                      ctx->id, free_frame_buffer->status,
+                                      vb->vb2_buf.index, dstbuf->queued_in_vb2);
+                       v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
+               } else if (!dstbuf->queued_in_vb2 && dstbuf->queued_in_v4l2) {
+                       /*
+                        * If buffer in v4l2 driver but not in vb2 queue yet,
+                        * and we get this buffer from free_list, it means
+                        * that codec driver do not use this buffer as
+                        * reference buffer anymore. We should q buffer to vb2
+                        * queue, so later work thread could get this buffer
+                        * for decode. In this case, queued_in_vb2 = false
+                        * means this buffer is not from previous decode
+                        * output.
+                        */
+                       mtk_v4l2_debug(2,
+                                      "[%d]status=%x queue id=%d to rdy_queue",
+                                      ctx->id, free_frame_buffer->status,
+                                      vb->vb2_buf.index);
+                       v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
+                       dstbuf->queued_in_vb2 = true;
+               } else {
+                       /*
+                        * Codec driver do not need to reference this capture
+                        * buffer and this buffer is not in v4l2 driver.
+                        * Then we don't need to do any thing, just add log when
+                        * we need to debug buffer flow.
+                        * When this buffer q from user space, it could
+                        * directly q to vb2 buffer
+                        */
+                       mtk_v4l2_debug(3, "[%d]status=%x err queue id=%d %d %d",
+                                      ctx->id, free_frame_buffer->status,
+                                      vb->vb2_buf.index, dstbuf->queued_in_vb2,
+                                      dstbuf->queued_in_v4l2);
+               }
+               dstbuf->used = false;
+       }
+       mutex_unlock(&ctx->lock);
+       return &vb->vb2_buf;
+}
+
+static void clean_display_buffer(struct mtk_vcodec_ctx *ctx)
+{
+       while (get_display_buffer(ctx))
+               ;
+}
+
+static void clean_free_buffer(struct mtk_vcodec_ctx *ctx)
+{
+       while (get_free_buffer(ctx))
+               ;
+}
+
+static void mtk_vdec_queue_res_chg_event(struct mtk_vcodec_ctx *ctx)
+{
+       static const struct v4l2_event ev_src_ch = {
+               .type = V4L2_EVENT_SOURCE_CHANGE,
+               .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
+       };
+
+       mtk_v4l2_debug(1, "[%d]", ctx->id);
+       v4l2_event_queue_fh(&ctx->fh, &ev_src_ch);
+}
+
+static int mtk_vdec_flush_decoder(struct mtk_vcodec_ctx *ctx)
+{
+       bool res_chg;
+       int ret;
+
+       ret = vdec_if_decode(ctx, NULL, NULL, &res_chg);
+       if (ret)
+               mtk_v4l2_err("DecodeFinal failed, ret=%d", ret);
+
+       clean_display_buffer(ctx);
+       clean_free_buffer(ctx);
+
+       return 0;
+}
+
+static void mtk_vdec_update_fmt(struct mtk_vcodec_ctx *ctx,
+                               unsigned int pixelformat)
+{
+       const struct mtk_video_fmt *fmt;
+       struct mtk_q_data *dst_q_data;
+       unsigned int k;
+
+       dst_q_data = &ctx->q_data[MTK_Q_DATA_DST];
+       for (k = 0; k < NUM_FORMATS; k++) {
+               fmt = &mtk_video_formats[k];
+               if (fmt->fourcc == pixelformat) {
+                       mtk_v4l2_debug(1, "Update cap fourcc(%d -> %d)",
+                                      dst_q_data->fmt->fourcc, pixelformat);
+                       dst_q_data->fmt = fmt;
+                       return;
+               }
+       }
+
+       mtk_v4l2_err("Cannot get fourcc(%d), using init value", pixelformat);
+}
+
+static int mtk_vdec_pic_info_update(struct mtk_vcodec_ctx *ctx)
+{
+       unsigned int dpbsize = 0;
+       int ret;
+
+       if (vdec_if_get_param(ctx, GET_PARAM_PIC_INFO,
+                             &ctx->last_decoded_picinfo)) {
+               mtk_v4l2_err("[%d]Error!! Cannot get param : GET_PARAM_PICTURE_INFO ERR", ctx->id);
+               return -EINVAL;
+       }
+
+       if (ctx->last_decoded_picinfo.pic_w == 0 ||
+           ctx->last_decoded_picinfo.pic_h == 0 ||
+           ctx->last_decoded_picinfo.buf_w == 0 ||
+           ctx->last_decoded_picinfo.buf_h == 0) {
+               mtk_v4l2_err("Cannot get correct pic info");
+               return -EINVAL;
+       }
+
+       if (ctx->last_decoded_picinfo.cap_fourcc != ctx->picinfo.cap_fourcc &&
+           ctx->picinfo.cap_fourcc != 0)
+               mtk_vdec_update_fmt(ctx, ctx->picinfo.cap_fourcc);
+
+       if (ctx->last_decoded_picinfo.pic_w == ctx->picinfo.pic_w ||
+           ctx->last_decoded_picinfo.pic_h == ctx->picinfo.pic_h)
+               return 0;
+
+       mtk_v4l2_debug(1, "[%d]-> new(%d,%d), old(%d,%d), real(%d,%d)", ctx->id,
+                      ctx->last_decoded_picinfo.pic_w,
+                      ctx->last_decoded_picinfo.pic_h, ctx->picinfo.pic_w,
+                      ctx->picinfo.pic_h, ctx->last_decoded_picinfo.buf_w,
+                      ctx->last_decoded_picinfo.buf_h);
+
+       ret = vdec_if_get_param(ctx, GET_PARAM_DPB_SIZE, &dpbsize);
+       if (dpbsize == 0)
+               mtk_v4l2_err("Incorrect dpb size, ret=%d", ret);
+
+       ctx->dpb_size = dpbsize;
+
+       return ret;
+}
+
+static void mtk_vdec_worker(struct work_struct *work)
+{
+       struct mtk_vcodec_ctx *ctx =
+               container_of(work, struct mtk_vcodec_ctx, decode_work);
+       struct mtk_vcodec_dev *dev = ctx->dev;
+       struct vb2_v4l2_buffer *src_buf, *dst_buf;
+       struct mtk_vcodec_mem buf;
+       struct vdec_fb *pfb;
+       bool res_chg = false;
+       int ret;
+       struct mtk_video_dec_buf *dst_buf_info, *src_buf_info;
+
+       src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+       if (!src_buf) {
+               v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
+               mtk_v4l2_debug(1, "[%d] src_buf empty!!", ctx->id);
+               return;
+       }
+
+       dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+       if (!dst_buf) {
+               v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
+               mtk_v4l2_debug(1, "[%d] dst_buf empty!!", ctx->id);
+               return;
+       }
+
+       dst_buf_info =
+               container_of(dst_buf, struct mtk_video_dec_buf, m2m_buf.vb);
+
+       pfb = &dst_buf_info->frame_buffer;
+       pfb->base_y.va = vb2_plane_vaddr(&dst_buf->vb2_buf, 0);
+       pfb->base_y.dma_addr =
+               vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
+       pfb->base_y.size = ctx->picinfo.fb_sz[0];
+
+       pfb->base_c.va = vb2_plane_vaddr(&dst_buf->vb2_buf, 1);
+       pfb->base_c.dma_addr =
+               vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 1);
+       pfb->base_c.size = ctx->picinfo.fb_sz[1];
+       pfb->status = 0;
+       mtk_v4l2_debug(3, "===>[%d] vdec_if_decode() ===>", ctx->id);
+
+       mtk_v4l2_debug(3,
+                      "id=%d Framebuf  pfb=%p VA=%p Y_DMA=%pad C_DMA=%pad Size=%zx",
+                      dst_buf->vb2_buf.index, pfb, pfb->base_y.va,
+                      &pfb->base_y.dma_addr, &pfb->base_c.dma_addr, pfb->base_y.size);
+
+       if (src_buf == &ctx->empty_flush_buf.vb) {
+               mtk_v4l2_debug(1, "Got empty flush input buffer.");
+               src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+
+               /* update dst buf status */
+               dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+               mutex_lock(&ctx->lock);
+               dst_buf_info->used = false;
+               mutex_unlock(&ctx->lock);
+
+               vdec_if_decode(ctx, NULL, NULL, &res_chg);
+               clean_display_buffer(ctx);
+               vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0);
+               if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2)
+                       vb2_set_plane_payload(&dst_buf->vb2_buf, 1, 0);
+               dst_buf->flags |= V4L2_BUF_FLAG_LAST;
+               v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
+               clean_free_buffer(ctx);
+               v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
+               return;
+       }
+
+       src_buf_info =
+               container_of(src_buf, struct mtk_video_dec_buf, m2m_buf.vb);
+
+       buf.va = vb2_plane_vaddr(&src_buf->vb2_buf, 0);
+       buf.dma_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
+       buf.size = (size_t)src_buf->vb2_buf.planes[0].bytesused;
+       if (!buf.va) {
+               v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
+               mtk_v4l2_err("[%d] id=%d src_addr is NULL!!", ctx->id,
+                            src_buf->vb2_buf.index);
+               return;
+       }
+       mtk_v4l2_debug(3, "[%d] Bitstream VA=%p DMA=%pad Size=%zx vb=%p",
+                      ctx->id, buf.va, &buf.dma_addr, buf.size, src_buf);
+       dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp;
+       dst_buf->timecode = src_buf->timecode;
+       mutex_lock(&ctx->lock);
+       dst_buf_info->used = true;
+       mutex_unlock(&ctx->lock);
+       src_buf_info->used = true;
+
+       ret = vdec_if_decode(ctx, &buf, pfb, &res_chg);
+
+       if (ret) {
+               mtk_v4l2_err(" <===[%d], src_buf[%d] sz=0x%zx pts=%llu dst_buf[%d] vdec_if_decode() ret=%d res_chg=%d===>",
+                            ctx->id, src_buf->vb2_buf.index, buf.size,
+                            src_buf->vb2_buf.timestamp, dst_buf->vb2_buf.index, ret, res_chg);
+               src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+               if (ret == -EIO) {
+                       mutex_lock(&ctx->lock);
+                       src_buf_info->error = true;
+                       mutex_unlock(&ctx->lock);
+               }
+               v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
+       } else if (!res_chg) {
+               /*
+                * we only return src buffer with VB2_BUF_STATE_DONE
+                * when decode success without resolution change
+                */
+               src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+               v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
+       }
+
+       dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+       clean_display_buffer(ctx);
+       clean_free_buffer(ctx);
+
+       if (!ret && res_chg) {
+               mtk_vdec_pic_info_update(ctx);
+               /*
+                * On encountering a resolution change in the stream.
+                * The driver must first process and decode all
+                * remaining buffers from before the resolution change
+                * point, so call flush decode here
+                */
+               mtk_vdec_flush_decoder(ctx);
+               /*
+                * After all buffers containing decoded frames from
+                * before the resolution change point ready to be
+                * dequeued on the CAPTURE queue, the driver sends a
+                * V4L2_EVENT_SOURCE_CHANGE event for source change
+                * type V4L2_EVENT_SRC_CH_RESOLUTION
+                */
+               mtk_vdec_queue_res_chg_event(ctx);
+       }
+       v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
+}
+
+static void vb2ops_vdec_stateful_buf_queue(struct vb2_buffer *vb)
+{
+       struct vb2_v4l2_buffer *src_buf;
+       struct mtk_vcodec_mem src_mem;
+       bool res_chg = false;
+       int ret;
+       unsigned int dpbsize = 1, i;
+       struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+       struct vb2_v4l2_buffer *vb2_v4l2;
+       struct mtk_q_data *dst_q_data;
+
+       mtk_v4l2_debug(3, "[%d] (%d) id=%d, vb=%p", ctx->id,
+                      vb->vb2_queue->type, vb->index, vb);
+       /*
+        * check if this buffer is ready to be used after decode
+        */
+       if (vb->vb2_queue->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               struct mtk_video_dec_buf *buf;
+
+               vb2_v4l2 = to_vb2_v4l2_buffer(vb);
+               buf = container_of(vb2_v4l2, struct mtk_video_dec_buf,
+                                  m2m_buf.vb);
+               mutex_lock(&ctx->lock);
+               if (!buf->used) {
+                       v4l2_m2m_buf_queue(ctx->m2m_ctx, vb2_v4l2);
+                       buf->queued_in_vb2 = true;
+                       buf->queued_in_v4l2 = true;
+               } else {
+                       buf->queued_in_vb2 = false;
+                       buf->queued_in_v4l2 = true;
+               }
+               mutex_unlock(&ctx->lock);
+               return;
+       }
+
+       v4l2_m2m_buf_queue(ctx->m2m_ctx, to_vb2_v4l2_buffer(vb));
+
+       if (ctx->state != MTK_STATE_INIT) {
+               mtk_v4l2_debug(3, "[%d] already init driver %d", ctx->id,
+                              ctx->state);
+               return;
+       }
+
+       src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+       if (!src_buf) {
+               mtk_v4l2_err("No src buffer");
+               return;
+       }
+
+       if (src_buf == &ctx->empty_flush_buf.vb) {
+               /* This shouldn't happen. Just in case. */
+               mtk_v4l2_err("Invalid flush buffer.");
+               v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+               return;
+       }
+
+       src_mem.va = vb2_plane_vaddr(&src_buf->vb2_buf, 0);
+       src_mem.dma_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
+       src_mem.size = (size_t)src_buf->vb2_buf.planes[0].bytesused;
+       mtk_v4l2_debug(2, "[%d] buf id=%d va=%p dma=%pad size=%zx", ctx->id,
+                      src_buf->vb2_buf.index, src_mem.va, &src_mem.dma_addr,
+                      src_mem.size);
+
+       ret = vdec_if_decode(ctx, &src_mem, NULL, &res_chg);
+       if (ret || !res_chg) {
+               /*
+                * fb == NULL means to parse SPS/PPS header or
+                * resolution info in src_mem. Decode can fail
+                * if there is no SPS header or picture info
+                * in bs
+                */
+
+               src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+               if (ret == -EIO) {
+                       mtk_v4l2_err("[%d] Unrecoverable error in vdec_if_decode.", ctx->id);
+                       ctx->state = MTK_STATE_ABORT;
+                       v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
+               } else {
+                       v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
+               }
+               mtk_v4l2_debug(ret ? 0 : 1,
+                              "[%d] vdec_if_decode() src_buf=%d, size=%zu, fail=%d, res_chg=%d",
+                              ctx->id, src_buf->vb2_buf.index, src_mem.size, ret, res_chg);
+               return;
+       }
+
+       if (vdec_if_get_param(ctx, GET_PARAM_PIC_INFO, &ctx->picinfo)) {
+               mtk_v4l2_err("[%d]Error!! Cannot get param : GET_PARAM_PICTURE_INFO ERR", ctx->id);
+               return;
+       }
+
+       ctx->last_decoded_picinfo = ctx->picinfo;
+       dst_q_data = &ctx->q_data[MTK_Q_DATA_DST];
+       for (i = 0; i < dst_q_data->fmt->num_planes; i++) {
+               dst_q_data->sizeimage[i] = ctx->picinfo.fb_sz[i];
+               dst_q_data->bytesperline[i] = ctx->picinfo.buf_w;
+       }
+
+       mtk_v4l2_debug(2, "[%d] vdec_if_init() OK wxh=%dx%d pic wxh=%dx%d sz[0]=0x%x sz[1]=0x%x",
+                      ctx->id, ctx->picinfo.buf_w, ctx->picinfo.buf_h, ctx->picinfo.pic_w,
+                      ctx->picinfo.pic_h, dst_q_data->sizeimage[0], dst_q_data->sizeimage[1]);
+
+       ret = vdec_if_get_param(ctx, GET_PARAM_DPB_SIZE, &dpbsize);
+       if (dpbsize == 0)
+               mtk_v4l2_err("[%d] GET_PARAM_DPB_SIZE fail=%d", ctx->id, ret);
+
+       ctx->dpb_size = dpbsize;
+       ctx->state = MTK_STATE_HEADER;
+       mtk_v4l2_debug(1, "[%d] dpbsize=%d", ctx->id, ctx->dpb_size);
+
+       mtk_vdec_queue_res_chg_event(ctx);
+}
+
+static int mtk_vdec_g_v_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct mtk_vcodec_ctx *ctx = ctrl_to_ctx(ctrl);
+       int ret = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
+               if (ctx->state >= MTK_STATE_HEADER) {
+                       ctrl->val = ctx->dpb_size;
+               } else {
+                       mtk_v4l2_debug(0, "Seqinfo not ready");
+                       ctrl->val = 0;
+               }
+               break;
+       default:
+               ret = -EINVAL;
+       }
+       return ret;
+}
+
+static const struct v4l2_ctrl_ops mtk_vcodec_dec_ctrl_ops = {
+       .g_volatile_ctrl = mtk_vdec_g_v_ctrl,
+};
+
+static int mtk_vcodec_dec_ctrls_setup(struct mtk_vcodec_ctx *ctx)
+{
+       struct v4l2_ctrl *ctrl;
+
+       v4l2_ctrl_handler_init(&ctx->ctrl_hdl, 1);
+
+       ctrl = v4l2_ctrl_new_std(&ctx->ctrl_hdl, &mtk_vcodec_dec_ctrl_ops,
+                                V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 0, 32, 1, 1);
+       ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
+       v4l2_ctrl_new_std_menu(&ctx->ctrl_hdl, &mtk_vcodec_dec_ctrl_ops,
+                              V4L2_CID_MPEG_VIDEO_VP9_PROFILE,
+                              V4L2_MPEG_VIDEO_VP9_PROFILE_0, 0,
+                              V4L2_MPEG_VIDEO_VP9_PROFILE_0);
+       /*
+        * H264. Baseline / Extended decoding is not supported.
+        */
+       v4l2_ctrl_new_std_menu(&ctx->ctrl_hdl, &mtk_vcodec_dec_ctrl_ops,
+                              V4L2_CID_MPEG_VIDEO_H264_PROFILE, V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
+                              BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
+                              BIT(V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED),
+                              V4L2_MPEG_VIDEO_H264_PROFILE_MAIN);
+
+       if (ctx->ctrl_hdl.error) {
+               mtk_v4l2_err("Adding control failed %d", ctx->ctrl_hdl.error);
+               return ctx->ctrl_hdl.error;
+       }
+
+       v4l2_ctrl_handler_setup(&ctx->ctrl_hdl);
+       return 0;
+}
+
+static void mtk_init_vdec_params(struct mtk_vcodec_ctx *ctx)
+{
+}
+
+static struct vb2_ops mtk_vdec_frame_vb2_ops = {
+       .queue_setup = vb2ops_vdec_queue_setup,
+       .buf_prepare = vb2ops_vdec_buf_prepare,
+       .wait_prepare = vb2_ops_wait_prepare,
+       .wait_finish = vb2_ops_wait_finish,
+       .start_streaming = vb2ops_vdec_start_streaming,
+
+       .buf_queue = vb2ops_vdec_stateful_buf_queue,
+       .buf_init = vb2ops_vdec_buf_init,
+       .buf_finish = vb2ops_vdec_buf_finish,
+       .stop_streaming = vb2ops_vdec_stop_streaming,
+};
+
+const struct mtk_vcodec_dec_pdata mtk_vdec_8173_pdata = {
+       .chip = MTK_MT8173,
+       .init_vdec_params = mtk_init_vdec_params,
+       .ctrls_setup = mtk_vcodec_dec_ctrls_setup,
+       .vdec_vb2_ops = &mtk_vdec_frame_vb2_ops,
+       .vdec_formats = mtk_video_formats,
+       .num_formats = NUM_FORMATS,
+       .default_out_fmt = &mtk_video_formats[DEFAULT_OUT_FMT_IDX],
+       .default_cap_fmt = &mtk_video_formats[DEFAULT_CAP_FMT_IDX],
+       .vdec_framesizes = mtk_vdec_framesizes,
+       .num_framesizes = NUM_SUPPORTED_FRAMESIZE,
+       .worker = mtk_vdec_worker,
+       .flush_decoder = mtk_vdec_flush_decoder,
+       .is_subdev_supported = false,
+       .hw_arch = MTK_VDEC_PURE_SINGLE_CORE,
+};
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_dec_stateless.c b/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_dec_stateless.c
new file mode 100644 (file)
index 0000000..23d997a
--- /dev/null
@@ -0,0 +1,380 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <media/videobuf2-v4l2.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-mem2mem.h>
+#include <linux/module.h>
+
+#include "mtk_vcodec_drv.h"
+#include "mtk_vcodec_dec.h"
+#include "mtk_vcodec_intr.h"
+#include "mtk_vcodec_util.h"
+#include "mtk_vcodec_dec_pm.h"
+#include "vdec_drv_if.h"
+
+/**
+ * struct mtk_stateless_control  - CID control type
+ * @cfg: control configuration
+ * @codec_type: codec type (V4L2 pixel format) for CID control type
+ */
+struct mtk_stateless_control {
+       struct v4l2_ctrl_config cfg;
+       int codec_type;
+};
+
+static const struct mtk_stateless_control mtk_stateless_controls[] = {
+       {
+               .cfg = {
+                       .id = V4L2_CID_STATELESS_H264_SPS,
+               },
+               .codec_type = V4L2_PIX_FMT_H264_SLICE,
+       },
+       {
+               .cfg = {
+                       .id = V4L2_CID_STATELESS_H264_PPS,
+               },
+               .codec_type = V4L2_PIX_FMT_H264_SLICE,
+       },
+       {
+               .cfg = {
+                       .id = V4L2_CID_STATELESS_H264_SCALING_MATRIX,
+               },
+               .codec_type = V4L2_PIX_FMT_H264_SLICE,
+       },
+       {
+               .cfg = {
+                       .id = V4L2_CID_STATELESS_H264_DECODE_PARAMS,
+               },
+               .codec_type = V4L2_PIX_FMT_H264_SLICE,
+       },
+       {
+               .cfg = {
+                       .id = V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+                       .def = V4L2_MPEG_VIDEO_H264_PROFILE_MAIN,
+                       .max = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
+                       .menu_skip_mask =
+                               BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
+                               BIT(V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED),
+               },
+               .codec_type = V4L2_PIX_FMT_H264_SLICE,
+       },
+       {
+               .cfg = {
+                       .id = V4L2_CID_STATELESS_H264_DECODE_MODE,
+                       .min = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED,
+                       .def = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED,
+                       .max = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED,
+               },
+               .codec_type = V4L2_PIX_FMT_H264_SLICE,
+       },
+       {
+               .cfg = {
+                       .id = V4L2_CID_STATELESS_H264_START_CODE,
+                       .min = V4L2_STATELESS_H264_START_CODE_ANNEX_B,
+                       .def = V4L2_STATELESS_H264_START_CODE_ANNEX_B,
+                       .max = V4L2_STATELESS_H264_START_CODE_ANNEX_B,
+               },
+               .codec_type = V4L2_PIX_FMT_H264_SLICE,
+       }
+};
+
+#define NUM_CTRLS ARRAY_SIZE(mtk_stateless_controls)
+
+static const struct mtk_video_fmt mtk_video_formats[] = {
+       {
+               .fourcc = V4L2_PIX_FMT_H264_SLICE,
+               .type = MTK_FMT_DEC,
+               .num_planes = 1,
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_MM21,
+               .type = MTK_FMT_FRAME,
+               .num_planes = 2,
+       },
+};
+
+#define NUM_FORMATS ARRAY_SIZE(mtk_video_formats)
+#define DEFAULT_OUT_FMT_IDX    0
+#define DEFAULT_CAP_FMT_IDX    1
+
+static const struct mtk_codec_framesizes mtk_vdec_framesizes[] = {
+       {
+               .fourcc = V4L2_PIX_FMT_H264_SLICE,
+               .stepwise = {  MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16,
+                               MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 },
+       },
+};
+
+#define NUM_SUPPORTED_FRAMESIZE ARRAY_SIZE(mtk_vdec_framesizes)
+
+static void mtk_vdec_stateless_set_dst_payload(struct mtk_vcodec_ctx *ctx,
+                                              struct vdec_fb *fb)
+{
+       struct mtk_video_dec_buf *vdec_frame_buf =
+               container_of(fb, struct mtk_video_dec_buf, frame_buffer);
+       struct vb2_v4l2_buffer *vb = &vdec_frame_buf->m2m_buf.vb;
+       unsigned int cap_y_size = ctx->q_data[MTK_Q_DATA_DST].sizeimage[0];
+
+       vb2_set_plane_payload(&vb->vb2_buf, 0, cap_y_size);
+       if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) {
+               unsigned int cap_c_size =
+                       ctx->q_data[MTK_Q_DATA_DST].sizeimage[1];
+
+               vb2_set_plane_payload(&vb->vb2_buf, 1, cap_c_size);
+       }
+}
+
+static struct vdec_fb *vdec_get_cap_buffer(struct mtk_vcodec_ctx *ctx,
+                                          struct vb2_v4l2_buffer *vb2_v4l2)
+{
+       struct mtk_video_dec_buf *framebuf =
+               container_of(vb2_v4l2, struct mtk_video_dec_buf, m2m_buf.vb);
+       struct vdec_fb *pfb = &framebuf->frame_buffer;
+       struct vb2_buffer *dst_buf = &vb2_v4l2->vb2_buf;
+
+       pfb->base_y.va = NULL;
+       pfb->base_y.dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
+       pfb->base_y.size = ctx->q_data[MTK_Q_DATA_DST].sizeimage[0];
+
+       if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) {
+               pfb->base_c.va = NULL;
+               pfb->base_c.dma_addr =
+                       vb2_dma_contig_plane_dma_addr(dst_buf, 1);
+               pfb->base_c.size = ctx->q_data[MTK_Q_DATA_DST].sizeimage[1];
+       }
+       mtk_v4l2_debug(1, "id=%d Framebuf  pfb=%p VA=%p Y_DMA=%pad C_DMA=%pad Size=%zx frame_count = %d",
+                      dst_buf->index, pfb, pfb->base_y.va, &pfb->base_y.dma_addr,
+                      &pfb->base_c.dma_addr, pfb->base_y.size, ctx->decoded_frame_cnt);
+
+       return pfb;
+}
+
+static void vb2ops_vdec_buf_request_complete(struct vb2_buffer *vb)
+{
+       struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+       v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->ctrl_hdl);
+}
+
+static void mtk_vdec_worker(struct work_struct *work)
+{
+       struct mtk_vcodec_ctx *ctx =
+               container_of(work, struct mtk_vcodec_ctx, decode_work);
+       struct mtk_vcodec_dev *dev = ctx->dev;
+       struct vb2_v4l2_buffer *vb2_v4l2_src, *vb2_v4l2_dst;
+       struct vb2_buffer *vb2_src;
+       struct mtk_vcodec_mem *bs_src;
+       struct mtk_video_dec_buf *dec_buf_src;
+       struct media_request *src_buf_req;
+       struct vdec_fb *dst_buf;
+       bool res_chg = false;
+       int ret;
+
+       vb2_v4l2_src = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+       if (!vb2_v4l2_src) {
+               v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
+               mtk_v4l2_debug(1, "[%d] no available source buffer", ctx->id);
+               return;
+       }
+
+       vb2_v4l2_dst = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+       if (!vb2_v4l2_dst) {
+               v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
+               mtk_v4l2_debug(1, "[%d] no available destination buffer", ctx->id);
+               return;
+       }
+
+       vb2_src = &vb2_v4l2_src->vb2_buf;
+       dec_buf_src = container_of(vb2_v4l2_src, struct mtk_video_dec_buf,
+                                  m2m_buf.vb);
+       bs_src = &dec_buf_src->bs_buffer;
+
+       mtk_v4l2_debug(3, "[%d] (%d) id=%d, vb=%p", ctx->id,
+                      vb2_src->vb2_queue->type, vb2_src->index, vb2_src);
+
+       bs_src->va = NULL;
+       bs_src->dma_addr = vb2_dma_contig_plane_dma_addr(vb2_src, 0);
+       bs_src->size = (size_t)vb2_src->planes[0].bytesused;
+
+       mtk_v4l2_debug(3, "[%d] Bitstream VA=%p DMA=%pad Size=%zx vb=%p",
+                      ctx->id, bs_src->va, &bs_src->dma_addr, bs_src->size, vb2_src);
+       /* Apply request controls. */
+       src_buf_req = vb2_src->req_obj.req;
+       if (src_buf_req)
+               v4l2_ctrl_request_setup(src_buf_req, &ctx->ctrl_hdl);
+       else
+               mtk_v4l2_err("vb2 buffer media request is NULL");
+
+       dst_buf = vdec_get_cap_buffer(ctx, vb2_v4l2_dst);
+       v4l2_m2m_buf_copy_metadata(vb2_v4l2_src, vb2_v4l2_dst, true);
+       ret = vdec_if_decode(ctx, bs_src, dst_buf, &res_chg);
+       if (ret) {
+               mtk_v4l2_err(" <===[%d], src_buf[%d] sz=0x%zx pts=%llu vdec_if_decode() ret=%d res_chg=%d===>",
+                            ctx->id, vb2_src->index, bs_src->size,
+                            vb2_src->timestamp, ret, res_chg);
+               if (ret == -EIO) {
+                       mutex_lock(&ctx->lock);
+                       dec_buf_src->error = true;
+                       mutex_unlock(&ctx->lock);
+               }
+       }
+
+       mtk_vdec_stateless_set_dst_payload(ctx, dst_buf);
+
+       v4l2_m2m_buf_done_and_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx,
+                                        ret ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+
+       v4l2_ctrl_request_complete(src_buf_req, &ctx->ctrl_hdl);
+}
+
+static void vb2ops_vdec_stateless_buf_queue(struct vb2_buffer *vb)
+{
+       struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+       struct vb2_v4l2_buffer *vb2_v4l2 = to_vb2_v4l2_buffer(vb);
+
+       mtk_v4l2_debug(3, "[%d] (%d) id=%d, vb=%p", ctx->id, vb->vb2_queue->type, vb->index, vb);
+
+       mutex_lock(&ctx->lock);
+       v4l2_m2m_buf_queue(ctx->m2m_ctx, vb2_v4l2);
+       mutex_unlock(&ctx->lock);
+       if (vb->vb2_queue->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               return;
+
+       /* If an OUTPUT buffer, we may need to update the state */
+       if (ctx->state == MTK_STATE_INIT) {
+               ctx->state = MTK_STATE_HEADER;
+               mtk_v4l2_debug(1, "Init driver from init to header.");
+       } else {
+               mtk_v4l2_debug(3, "[%d] already init driver %d", ctx->id, ctx->state);
+       }
+}
+
+static int mtk_vdec_flush_decoder(struct mtk_vcodec_ctx *ctx)
+{
+       bool res_chg;
+
+       return vdec_if_decode(ctx, NULL, NULL, &res_chg);
+}
+
+static int mtk_vcodec_dec_ctrls_setup(struct mtk_vcodec_ctx *ctx)
+{
+       unsigned int i;
+
+       v4l2_ctrl_handler_init(&ctx->ctrl_hdl, NUM_CTRLS);
+       if (ctx->ctrl_hdl.error) {
+               mtk_v4l2_err("v4l2_ctrl_handler_init failed\n");
+               return ctx->ctrl_hdl.error;
+       }
+
+       for (i = 0; i < NUM_CTRLS; i++) {
+               struct v4l2_ctrl_config cfg = mtk_stateless_controls[i].cfg;
+
+               v4l2_ctrl_new_custom(&ctx->ctrl_hdl, &cfg, NULL);
+               if (ctx->ctrl_hdl.error) {
+                       mtk_v4l2_err("Adding control %d failed %d", i, ctx->ctrl_hdl.error);
+                       return ctx->ctrl_hdl.error;
+               }
+       }
+
+       v4l2_ctrl_handler_setup(&ctx->ctrl_hdl);
+
+       return 0;
+}
+
+static int fops_media_request_validate(struct media_request *mreq)
+{
+       const unsigned int buffer_cnt = vb2_request_buffer_cnt(mreq);
+
+       switch (buffer_cnt) {
+       case 1:
+               /* We expect exactly one buffer with the request */
+               break;
+       case 0:
+               mtk_v4l2_debug(1, "No buffer provided with the request");
+               return -ENOENT;
+       default:
+               mtk_v4l2_debug(1, "Too many buffers (%d) provided with the request",
+                              buffer_cnt);
+               return -EINVAL;
+       }
+
+       return vb2_request_validate(mreq);
+}
+
+const struct media_device_ops mtk_vcodec_media_ops = {
+       .req_validate   = fops_media_request_validate,
+       .req_queue      = v4l2_m2m_request_queue,
+};
+
+static void mtk_init_vdec_params(struct mtk_vcodec_ctx *ctx)
+{
+       struct vb2_queue *src_vq;
+
+       src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx,
+                                V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+
+       /* Support request api for output plane */
+       src_vq->supports_requests = true;
+       src_vq->requires_requests = true;
+}
+
+static int vb2ops_vdec_out_buf_validate(struct vb2_buffer *vb)
+{
+       struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+       vbuf->field = V4L2_FIELD_NONE;
+       return 0;
+}
+
+static struct vb2_ops mtk_vdec_request_vb2_ops = {
+       .queue_setup    = vb2ops_vdec_queue_setup,
+       .wait_prepare   = vb2_ops_wait_prepare,
+       .wait_finish    = vb2_ops_wait_finish,
+       .start_streaming        = vb2ops_vdec_start_streaming,
+       .stop_streaming = vb2ops_vdec_stop_streaming,
+
+       .buf_queue      = vb2ops_vdec_stateless_buf_queue,
+       .buf_out_validate = vb2ops_vdec_out_buf_validate,
+       .buf_init       = vb2ops_vdec_buf_init,
+       .buf_prepare    = vb2ops_vdec_buf_prepare,
+       .buf_finish     = vb2ops_vdec_buf_finish,
+       .buf_request_complete = vb2ops_vdec_buf_request_complete,
+};
+
+const struct mtk_vcodec_dec_pdata mtk_vdec_8183_pdata = {
+       .chip = MTK_MT8183,
+       .init_vdec_params = mtk_init_vdec_params,
+       .ctrls_setup = mtk_vcodec_dec_ctrls_setup,
+       .vdec_vb2_ops = &mtk_vdec_request_vb2_ops,
+       .vdec_formats = mtk_video_formats,
+       .num_formats = NUM_FORMATS,
+       .default_out_fmt = &mtk_video_formats[DEFAULT_OUT_FMT_IDX],
+       .default_cap_fmt = &mtk_video_formats[DEFAULT_CAP_FMT_IDX],
+       .vdec_framesizes = mtk_vdec_framesizes,
+       .num_framesizes = NUM_SUPPORTED_FRAMESIZE,
+       .uses_stateless_api = true,
+       .worker = mtk_vdec_worker,
+       .flush_decoder = mtk_vdec_flush_decoder,
+       .is_subdev_supported = false,
+       .hw_arch = MTK_VDEC_PURE_SINGLE_CORE,
+};
+
+/* This platform data is used for one lat and one core architecture. */
+const struct mtk_vcodec_dec_pdata mtk_lat_sig_core_pdata = {
+       .chip = MTK_MT8192,
+       .init_vdec_params = mtk_init_vdec_params,
+       .ctrls_setup = mtk_vcodec_dec_ctrls_setup,
+       .vdec_vb2_ops = &mtk_vdec_request_vb2_ops,
+       .vdec_formats = mtk_video_formats,
+       .num_formats = NUM_FORMATS,
+       .default_out_fmt = &mtk_video_formats[DEFAULT_OUT_FMT_IDX],
+       .default_cap_fmt = &mtk_video_formats[DEFAULT_CAP_FMT_IDX],
+       .vdec_framesizes = mtk_vdec_framesizes,
+       .num_framesizes = NUM_SUPPORTED_FRAMESIZE,
+       .uses_stateless_api = true,
+       .worker = mtk_vdec_worker,
+       .flush_decoder = mtk_vdec_flush_decoder,
+       .is_subdev_supported = true,
+       .hw_arch = MTK_VDEC_LAT_SINGLE_CORE,
+};
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_drv.h
new file mode 100644 (file)
index 0000000..813901c
--- /dev/null
@@ -0,0 +1,537 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+* Copyright (c) 2016 MediaTek Inc.
+* Author: PC Chen <pc.chen@mediatek.com>
+*         Tiffany Lin <tiffany.lin@mediatek.com>
+*/
+
+#ifndef _MTK_VCODEC_DRV_H_
+#define _MTK_VCODEC_DRV_H_
+
+#include <linux/platform_device.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-core.h>
+
+#include "mtk_vcodec_util.h"
+#include "vdec_msg_queue.h"
+
+#define MTK_VCODEC_DRV_NAME    "mtk_vcodec_drv"
+#define MTK_VCODEC_DEC_NAME    "mtk-vcodec-dec"
+#define MTK_VCODEC_ENC_NAME    "mtk-vcodec-enc"
+#define MTK_PLATFORM_STR       "platform:mt8173"
+
+#define MTK_VCODEC_MAX_PLANES  3
+#define MTK_V4L2_BENCHMARK     0
+#define WAIT_INTR_TIMEOUT_MS   1000
+#define IS_VDEC_LAT_ARCH(hw_arch) ((hw_arch) >= MTK_VDEC_LAT_SINGLE_CORE)
+
+/*
+ * enum mtk_hw_reg_idx - MTK hw register base index
+ */
+enum mtk_hw_reg_idx {
+       VDEC_SYS,
+       VDEC_MISC,
+       VDEC_LD,
+       VDEC_TOP,
+       VDEC_CM,
+       VDEC_AD,
+       VDEC_AV,
+       VDEC_PP,
+       VDEC_HWD,
+       VDEC_HWQ,
+       VDEC_HWB,
+       VDEC_HWG,
+       NUM_MAX_VDEC_REG_BASE,
+       /* h264 encoder */
+       VENC_SYS = NUM_MAX_VDEC_REG_BASE,
+       /* vp8 encoder */
+       VENC_LT_SYS,
+       NUM_MAX_VCODEC_REG_BASE
+};
+
+/*
+ * enum mtk_instance_type - The type of an MTK Vcodec instance.
+ */
+enum mtk_instance_type {
+       MTK_INST_DECODER                = 0,
+       MTK_INST_ENCODER                = 1,
+};
+
+/**
+ * enum mtk_instance_state - The state of an MTK Vcodec instance.
+ * @MTK_STATE_FREE: default state when instance is created
+ * @MTK_STATE_INIT: vcodec instance is initialized
+ * @MTK_STATE_HEADER: vdec had sps/pps header parsed or venc
+ *                     had sps/pps header encoded
+ * @MTK_STATE_FLUSH: vdec is flushing. Only used by decoder
+ * @MTK_STATE_ABORT: vcodec should be aborted
+ */
+enum mtk_instance_state {
+       MTK_STATE_FREE = 0,
+       MTK_STATE_INIT = 1,
+       MTK_STATE_HEADER = 2,
+       MTK_STATE_FLUSH = 3,
+       MTK_STATE_ABORT = 4,
+};
+
+/*
+ * enum mtk_encode_param - General encoding parameters type
+ */
+enum mtk_encode_param {
+       MTK_ENCODE_PARAM_NONE = 0,
+       MTK_ENCODE_PARAM_BITRATE = (1 << 0),
+       MTK_ENCODE_PARAM_FRAMERATE = (1 << 1),
+       MTK_ENCODE_PARAM_INTRA_PERIOD = (1 << 2),
+       MTK_ENCODE_PARAM_FORCE_INTRA = (1 << 3),
+       MTK_ENCODE_PARAM_GOP_SIZE = (1 << 4),
+};
+
+enum mtk_fmt_type {
+       MTK_FMT_DEC = 0,
+       MTK_FMT_ENC = 1,
+       MTK_FMT_FRAME = 2,
+};
+
+/*
+ * enum mtk_vdec_hw_id - Hardware index used to separate
+ *                         different hardware
+ */
+enum mtk_vdec_hw_id {
+       MTK_VDEC_CORE,
+       MTK_VDEC_LAT0,
+       MTK_VDEC_LAT1,
+       MTK_VDEC_HW_MAX,
+};
+
+/*
+ * enum mtk_vdec_hw_count - Supported hardware count
+ */
+enum mtk_vdec_hw_count {
+       MTK_VDEC_NO_HW = 0,
+       MTK_VDEC_ONE_CORE,
+       MTK_VDEC_ONE_LAT_ONE_CORE,
+       MTK_VDEC_MAX_HW_COUNT,
+};
+
+/*
+ * struct mtk_video_fmt - Structure used to store information about pixelformats
+ */
+struct mtk_video_fmt {
+       u32     fourcc;
+       enum mtk_fmt_type       type;
+       u32     num_planes;
+       u32     flags;
+};
+
+/*
+ * struct mtk_codec_framesizes - Structure used to store information about
+ *                                                     framesizes
+ */
+struct mtk_codec_framesizes {
+       u32     fourcc;
+       struct  v4l2_frmsize_stepwise   stepwise;
+};
+
+/*
+ * enum mtk_q_type - Type of queue
+ */
+enum mtk_q_type {
+       MTK_Q_DATA_SRC = 0,
+       MTK_Q_DATA_DST = 1,
+};
+
+/*
+ * struct mtk_q_data - Structure used to store information about queue
+ */
+struct mtk_q_data {
+       unsigned int    visible_width;
+       unsigned int    visible_height;
+       unsigned int    coded_width;
+       unsigned int    coded_height;
+       enum v4l2_field field;
+       unsigned int    bytesperline[MTK_VCODEC_MAX_PLANES];
+       unsigned int    sizeimage[MTK_VCODEC_MAX_PLANES];
+       const struct mtk_video_fmt      *fmt;
+};
+
+/**
+ * struct mtk_enc_params - General encoding parameters
+ * @bitrate: target bitrate in bits per second
+ * @num_b_frame: number of b frames between p-frame
+ * @rc_frame: frame based rate control
+ * @rc_mb: macroblock based rate control
+ * @seq_hdr_mode: H.264 sequence header is encoded separately or joined
+ *               with the first frame
+ * @intra_period: I frame period
+ * @gop_size: group of picture size, it's used as the intra frame period
+ * @framerate_num: frame rate numerator. ex: framerate_num=30 and
+ *                framerate_denom=1 means FPS is 30
+ * @framerate_denom: frame rate denominator. ex: framerate_num=30 and
+ *                  framerate_denom=1 means FPS is 30
+ * @h264_max_qp: Max value for H.264 quantization parameter
+ * @h264_profile: V4L2 defined H.264 profile
+ * @h264_level: V4L2 defined H.264 level
+ * @force_intra: force/insert intra frame
+ */
+struct mtk_enc_params {
+       unsigned int    bitrate;
+       unsigned int    num_b_frame;
+       unsigned int    rc_frame;
+       unsigned int    rc_mb;
+       unsigned int    seq_hdr_mode;
+       unsigned int    intra_period;
+       unsigned int    gop_size;
+       unsigned int    framerate_num;
+       unsigned int    framerate_denom;
+       unsigned int    h264_max_qp;
+       unsigned int    h264_profile;
+       unsigned int    h264_level;
+       unsigned int    force_intra;
+};
+
+/*
+ * struct mtk_vcodec_clk_info - Structure used to store clock name
+ */
+struct mtk_vcodec_clk_info {
+       const char      *clk_name;
+       struct clk      *vcodec_clk;
+};
+
+/*
+ * struct mtk_vcodec_clk - Structure used to store vcodec clock information
+ */
+struct mtk_vcodec_clk {
+       struct mtk_vcodec_clk_info      *clk_info;
+       int     clk_num;
+};
+
+/*
+ * struct mtk_vcodec_pm - Power management data structure
+ */
+struct mtk_vcodec_pm {
+       struct mtk_vcodec_clk   vdec_clk;
+       struct mtk_vcodec_clk   venc_clk;
+       struct device   *dev;
+};
+
+/**
+ * struct vdec_pic_info  - picture size information
+ * @pic_w: picture width
+ * @pic_h: picture height
+ * @buf_w: picture buffer width (64 aligned up from pic_w)
+ * @buf_h: picture buffer heiht (64 aligned up from pic_h)
+ * @fb_sz: bitstream size of each plane
+ * E.g. suppose picture size is 176x144,
+ *      buffer size will be aligned to 176x160.
+ * @cap_fourcc: fourcc number(may changed when resolution change)
+ * @reserved: align struct to 64-bit in order to adjust 32-bit and 64-bit os.
+ */
+struct vdec_pic_info {
+       unsigned int pic_w;
+       unsigned int pic_h;
+       unsigned int buf_w;
+       unsigned int buf_h;
+       unsigned int fb_sz[VIDEO_MAX_PLANES];
+       unsigned int cap_fourcc;
+       unsigned int reserved;
+};
+
+/**
+ * struct mtk_vcodec_ctx - Context (instance) private data.
+ *
+ * @type: type of the instance - decoder or encoder
+ * @dev: pointer to the mtk_vcodec_dev of the device
+ * @list: link to ctx_list of mtk_vcodec_dev
+ * @fh: struct v4l2_fh
+ * @m2m_ctx: pointer to the v4l2_m2m_ctx of the context
+ * @q_data: store information of input and output queue
+ *         of the context
+ * @id: index of the context that this structure describes
+ * @state: state of the context
+ * @param_change: indicate encode parameter type
+ * @enc_params: encoding parameters
+ * @dec_if: hooked decoder driver interface
+ * @enc_if: hoooked encoder driver interface
+ * @drv_handle: driver handle for specific decode/encode instance
+ *
+ * @picinfo: store picture info after header parsing
+ * @dpb_size: store dpb count after header parsing
+ * @int_cond: variable used by the waitqueue
+ * @int_type: type of the last interrupt
+ * @queue: waitqueue that can be used to wait for this context to
+ *        finish
+ * @irq_status: irq status
+ *
+ * @ctrl_hdl: handler for v4l2 framework
+ * @decode_work: worker for the decoding
+ * @encode_work: worker for the encoding
+ * @last_decoded_picinfo: pic information get from latest decode
+ * @empty_flush_buf: a fake size-0 capture buffer that indicates flush. Only
+ *                  to be used with encoder and stateful decoder.
+ * @is_flushing: set to true if flushing is in progress.
+ * @current_codec: current set input codec, in V4L2 pixel format
+ *
+ * @colorspace: enum v4l2_colorspace; supplemental to pixelformat
+ * @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding
+ * @quantization: enum v4l2_quantization, colorspace quantization
+ * @xfer_func: enum v4l2_xfer_func, colorspace transfer function
+ * @decoded_frame_cnt: number of decoded frames
+ * @lock: protect variables accessed by V4L2 threads and worker thread such as
+ *       mtk_video_dec_buf.
+ * @hw_id: hardware index used to identify different hardware.
+ *
+ * @msg_queue: msg queue used to store lat buffer information.
+ */
+struct mtk_vcodec_ctx {
+       enum mtk_instance_type type;
+       struct mtk_vcodec_dev *dev;
+       struct list_head list;
+
+       struct v4l2_fh fh;
+       struct v4l2_m2m_ctx *m2m_ctx;
+       struct mtk_q_data q_data[2];
+       int id;
+       enum mtk_instance_state state;
+       enum mtk_encode_param param_change;
+       struct mtk_enc_params enc_params;
+
+       const struct vdec_common_if *dec_if;
+       const struct venc_common_if *enc_if;
+       void *drv_handle;
+
+       struct vdec_pic_info picinfo;
+       int dpb_size;
+
+       int int_cond[MTK_VDEC_HW_MAX];
+       int int_type[MTK_VDEC_HW_MAX];
+       wait_queue_head_t queue[MTK_VDEC_HW_MAX];
+       unsigned int irq_status;
+
+       struct v4l2_ctrl_handler ctrl_hdl;
+       struct work_struct decode_work;
+       struct work_struct encode_work;
+       struct vdec_pic_info last_decoded_picinfo;
+       struct v4l2_m2m_buffer empty_flush_buf;
+       bool is_flushing;
+
+       u32 current_codec;
+
+       enum v4l2_colorspace colorspace;
+       enum v4l2_ycbcr_encoding ycbcr_enc;
+       enum v4l2_quantization quantization;
+       enum v4l2_xfer_func xfer_func;
+
+       int decoded_frame_cnt;
+       struct mutex lock;
+       int hw_id;
+
+       struct vdec_msg_queue msg_queue;
+};
+
+enum mtk_chip {
+       MTK_MT8173,
+       MTK_MT8183,
+       MTK_MT8192,
+       MTK_MT8195,
+};
+
+/*
+ * enum mtk_vdec_hw_arch - Used to separate different hardware architecture
+ */
+enum mtk_vdec_hw_arch {
+       MTK_VDEC_PURE_SINGLE_CORE,
+       MTK_VDEC_LAT_SINGLE_CORE,
+};
+
+/**
+ * struct mtk_vcodec_dec_pdata - compatible data for each IC
+ * @init_vdec_params: init vdec params
+ * @ctrls_setup: init vcodec dec ctrls
+ * @worker: worker to start a decode job
+ * @flush_decoder: function that flushes the decoder
+ *
+ * @vdec_vb2_ops: struct vb2_ops
+ *
+ * @vdec_formats: supported video decoder formats
+ * @num_formats: count of video decoder formats
+ * @default_out_fmt: default output buffer format
+ * @default_cap_fmt: default capture buffer format
+ *
+ * @vdec_framesizes: supported video decoder frame sizes
+ * @num_framesizes: count of video decoder frame sizes
+ *
+ * @chip: chip this decoder is compatible with
+ * @hw_arch: hardware arch is used to separate pure_sin_core and lat_sin_core
+ *
+ * @is_subdev_supported: whether support parent-node architecture(subdev)
+ * @uses_stateless_api: whether the decoder uses the stateless API with requests
+ */
+
+struct mtk_vcodec_dec_pdata {
+       void (*init_vdec_params)(struct mtk_vcodec_ctx *ctx);
+       int (*ctrls_setup)(struct mtk_vcodec_ctx *ctx);
+       void (*worker)(struct work_struct *work);
+       int (*flush_decoder)(struct mtk_vcodec_ctx *ctx);
+
+       struct vb2_ops *vdec_vb2_ops;
+
+       const struct mtk_video_fmt *vdec_formats;
+       const int num_formats;
+       const struct mtk_video_fmt *default_out_fmt;
+       const struct mtk_video_fmt *default_cap_fmt;
+
+       const struct mtk_codec_framesizes *vdec_framesizes;
+       const int num_framesizes;
+
+       enum mtk_chip chip;
+       enum mtk_vdec_hw_arch hw_arch;
+
+       bool is_subdev_supported;
+       bool uses_stateless_api;
+};
+
+/**
+ * struct mtk_vcodec_enc_pdata - compatible data for each IC
+ *
+ * @chip: chip this encoder is compatible with
+ *
+ * @uses_ext: whether the encoder uses the extended firmware messaging format
+ * @min_bitrate: minimum supported encoding bitrate
+ * @max_bitrate: maximum supported encoding bitrate
+ * @capture_formats: array of supported capture formats
+ * @num_capture_formats: number of entries in capture_formats
+ * @output_formats: array of supported output formats
+ * @num_output_formats: number of entries in output_formats
+ * @core_id: stand for h264 or vp8 encode index
+ */
+struct mtk_vcodec_enc_pdata {
+       enum mtk_chip chip;
+
+       bool uses_ext;
+       unsigned long min_bitrate;
+       unsigned long max_bitrate;
+       const struct mtk_video_fmt *capture_formats;
+       size_t num_capture_formats;
+       const struct mtk_video_fmt *output_formats;
+       size_t num_output_formats;
+       int core_id;
+};
+
+#define MTK_ENC_CTX_IS_EXT(ctx) ((ctx)->dev->venc_pdata->uses_ext)
+
+/**
+ * struct mtk_vcodec_dev - driver data
+ * @v4l2_dev: V4L2 device to register video devices for.
+ * @vfd_dec: Video device for decoder
+ * @mdev_dec: Media device for decoder
+ * @vfd_enc: Video device for encoder.
+ *
+ * @m2m_dev_dec: m2m device for decoder
+ * @m2m_dev_enc: m2m device for encoder.
+ * @plat_dev: platform device
+ * @ctx_list: list of struct mtk_vcodec_ctx
+ * @irqlock: protect data access by irq handler and work thread
+ * @curr_ctx: The context that is waiting for codec hardware
+ *
+ * @reg_base: Mapped address of MTK Vcodec registers.
+ * @vdec_pdata: decoder IC-specific data
+ * @venc_pdata: encoder IC-specific data
+ *
+ * @fw_handler: used to communicate with the firmware.
+ * @id_counter: used to identify current opened instance
+ *
+ * @decode_workqueue: decode work queue
+ * @encode_workqueue: encode work queue
+ *
+ * @int_cond: used to identify interrupt condition happen
+ * @int_type: used to identify what kind of interrupt condition happen
+ * @dev_mutex: video_device lock
+ * @queue: waitqueue for waiting for completion of device commands
+ *
+ * @dec_irq: decoder irq resource
+ * @enc_irq: h264 encoder irq resource
+ *
+ * @dec_mutex: decoder hardware lock
+ * @enc_mutex: encoder hardware lock.
+ *
+ * @pm: power management control
+ * @dec_capability: used to identify decode capability, ex: 4k
+ * @enc_capability: used to identify encode capability
+ *
+ * @core_workqueue: queue used for core hardware decode
+ * @msg_queue_core_ctx: msg queue context used for core workqueue
+ *
+ * @subdev_dev: subdev hardware device
+ * @subdev_prob_done: check whether all used hw device is prob done
+ * @subdev_bitmap: used to record hardware is ready or not
+ */
+struct mtk_vcodec_dev {
+       struct v4l2_device v4l2_dev;
+       struct video_device *vfd_dec;
+       struct media_device mdev_dec;
+       struct video_device *vfd_enc;
+
+       struct v4l2_m2m_dev *m2m_dev_dec;
+       struct v4l2_m2m_dev *m2m_dev_enc;
+       struct platform_device *plat_dev;
+       struct list_head ctx_list;
+       spinlock_t irqlock;
+       struct mtk_vcodec_ctx *curr_ctx;
+       void __iomem *reg_base[NUM_MAX_VCODEC_REG_BASE];
+       const struct mtk_vcodec_dec_pdata *vdec_pdata;
+       const struct mtk_vcodec_enc_pdata *venc_pdata;
+
+       struct mtk_vcodec_fw *fw_handler;
+
+       unsigned long id_counter;
+
+       struct workqueue_struct *decode_workqueue;
+       struct workqueue_struct *encode_workqueue;
+       int int_cond;
+       int int_type;
+       struct mutex dev_mutex;
+       wait_queue_head_t queue;
+
+       int dec_irq;
+       int enc_irq;
+
+       /* decoder hardware mutex lock */
+       struct mutex dec_mutex[MTK_VDEC_HW_MAX];
+       struct mutex enc_mutex;
+
+       struct mtk_vcodec_pm pm;
+       unsigned int dec_capability;
+       unsigned int enc_capability;
+
+       struct workqueue_struct *core_workqueue;
+       struct vdec_msg_queue_ctx msg_queue_core_ctx;
+
+       void *subdev_dev[MTK_VDEC_HW_MAX];
+       int (*subdev_prob_done)(struct mtk_vcodec_dev *vdec_dev);
+       DECLARE_BITMAP(subdev_bitmap, MTK_VDEC_HW_MAX);
+};
+
+static inline struct mtk_vcodec_ctx *fh_to_ctx(struct v4l2_fh *fh)
+{
+       return container_of(fh, struct mtk_vcodec_ctx, fh);
+}
+
+static inline struct mtk_vcodec_ctx *ctrl_to_ctx(struct v4l2_ctrl *ctrl)
+{
+       return container_of(ctrl->handler, struct mtk_vcodec_ctx, ctrl_hdl);
+}
+
+/* Wake up context wait_queue */
+static inline void
+wake_up_ctx(struct mtk_vcodec_ctx *ctx, unsigned int reason, unsigned int hw_id)
+{
+       ctx->int_cond[hw_id] = 1;
+       ctx->int_type[hw_id] = reason;
+       wake_up_interruptible(&ctx->queue[hw_id]);
+}
+
+#endif /* _MTK_VCODEC_DRV_H_ */
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_enc.c
new file mode 100644 (file)
index 0000000..c213670
--- /dev/null
@@ -0,0 +1,1451 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+* Copyright (c) 2016 MediaTek Inc.
+* Author: PC Chen <pc.chen@mediatek.com>
+*         Tiffany Lin <tiffany.lin@mediatek.com>
+*/
+
+#include <media/v4l2-event.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-dma-contig.h>
+#include <linux/pm_runtime.h>
+
+#include "mtk_vcodec_drv.h"
+#include "mtk_vcodec_enc.h"
+#include "mtk_vcodec_intr.h"
+#include "mtk_vcodec_util.h"
+#include "venc_drv_if.h"
+
+#define MTK_VENC_MIN_W 160U
+#define MTK_VENC_MIN_H 128U
+#define MTK_VENC_HD_MAX_W      1920U
+#define MTK_VENC_HD_MAX_H      1088U
+#define MTK_VENC_4K_MAX_W      3840U
+#define MTK_VENC_4K_MAX_H      2176U
+
+#define DFT_CFG_WIDTH  MTK_VENC_MIN_W
+#define DFT_CFG_HEIGHT MTK_VENC_MIN_H
+#define MTK_MAX_CTRLS_HINT     20
+
+#define MTK_DEFAULT_FRAMERATE_NUM 1001
+#define MTK_DEFAULT_FRAMERATE_DENOM 30000
+#define MTK_VENC_4K_CAPABILITY_ENABLE BIT(0)
+
+static void mtk_venc_worker(struct work_struct *work);
+
+static const struct v4l2_frmsize_stepwise mtk_venc_hd_framesizes = {
+       MTK_VENC_MIN_W, MTK_VENC_HD_MAX_W, 16,
+       MTK_VENC_MIN_H, MTK_VENC_HD_MAX_H, 16,
+};
+
+static const struct v4l2_frmsize_stepwise mtk_venc_4k_framesizes = {
+       MTK_VENC_MIN_W, MTK_VENC_4K_MAX_W, 16,
+       MTK_VENC_MIN_H, MTK_VENC_4K_MAX_H, 16,
+};
+
+static int vidioc_venc_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct mtk_vcodec_ctx *ctx = ctrl_to_ctx(ctrl);
+       struct mtk_enc_params *p = &ctx->enc_params;
+       int ret = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_MPEG_VIDEO_BITRATE:
+               mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_BITRATE val = %d",
+                              ctrl->val);
+               p->bitrate = ctrl->val;
+               ctx->param_change |= MTK_ENCODE_PARAM_BITRATE;
+               break;
+       case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+               mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_B_FRAMES val = %d",
+                              ctrl->val);
+               p->num_b_frame = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE:
+               mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE val = %d",
+                              ctrl->val);
+               p->rc_frame = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
+               mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_H264_MAX_QP val = %d",
+                              ctrl->val);
+               p->h264_max_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
+               mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_HEADER_MODE val = %d",
+                              ctrl->val);
+               p->seq_hdr_mode = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE:
+               mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE val = %d",
+                              ctrl->val);
+               p->rc_mb = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+               mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_H264_PROFILE val = %d",
+                              ctrl->val);
+               p->h264_profile = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+               mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_H264_LEVEL val = %d",
+                              ctrl->val);
+               p->h264_level = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD:
+               mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_H264_I_PERIOD val = %d",
+                              ctrl->val);
+               p->intra_period = ctrl->val;
+               ctx->param_change |= MTK_ENCODE_PARAM_INTRA_PERIOD;
+               break;
+       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+               mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_GOP_SIZE val = %d",
+                              ctrl->val);
+               p->gop_size = ctrl->val;
+               ctx->param_change |= MTK_ENCODE_PARAM_GOP_SIZE;
+               break;
+       case V4L2_CID_MPEG_VIDEO_VP8_PROFILE:
+               /*
+                * FIXME - what vp8 profiles are actually supported?
+                * The ctrl is added (with only profile 0 supported) for now.
+                */
+               mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_VP8_PROFILE val = %d", ctrl->val);
+               break;
+       case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME:
+               mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME");
+               p->force_intra = 1;
+               ctx->param_change |= MTK_ENCODE_PARAM_FORCE_INTRA;
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+static const struct v4l2_ctrl_ops mtk_vcodec_enc_ctrl_ops = {
+       .s_ctrl = vidioc_venc_s_ctrl,
+};
+
+static int vidioc_enum_fmt(struct v4l2_fmtdesc *f,
+                          const struct mtk_video_fmt *formats,
+                          size_t num_formats)
+{
+       if (f->index >= num_formats)
+               return -EINVAL;
+
+       f->pixelformat = formats[f->index].fourcc;
+
+       return 0;
+}
+
+static const struct mtk_video_fmt *
+mtk_venc_find_format(u32 fourcc, const struct mtk_vcodec_enc_pdata *pdata)
+{
+       const struct mtk_video_fmt *fmt;
+       unsigned int k;
+
+       for (k = 0; k < pdata->num_capture_formats; k++) {
+               fmt = &pdata->capture_formats[k];
+               if (fmt->fourcc == fourcc)
+                       return fmt;
+       }
+
+       for (k = 0; k < pdata->num_output_formats; k++) {
+               fmt = &pdata->output_formats[k];
+               if (fmt->fourcc == fourcc)
+                       return fmt;
+       }
+
+       return NULL;
+}
+
+static int vidioc_enum_framesizes(struct file *file, void *fh,
+                                 struct v4l2_frmsizeenum *fsize)
+{
+       const struct mtk_video_fmt *fmt;
+       struct mtk_vcodec_ctx *ctx = fh_to_ctx(fh);
+
+       if (fsize->index != 0)
+               return -EINVAL;
+
+       fmt = mtk_venc_find_format(fsize->pixel_format,
+                                  ctx->dev->venc_pdata);
+       if (!fmt)
+               return -EINVAL;
+
+       fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+
+       if (ctx->dev->enc_capability & MTK_VENC_4K_CAPABILITY_ENABLE)
+               fsize->stepwise = mtk_venc_4k_framesizes;
+       else
+               fsize->stepwise = mtk_venc_hd_framesizes;
+
+       return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+                                  struct v4l2_fmtdesc *f)
+{
+       const struct mtk_vcodec_enc_pdata *pdata =
+               fh_to_ctx(priv)->dev->venc_pdata;
+
+       return vidioc_enum_fmt(f, pdata->capture_formats,
+                              pdata->num_capture_formats);
+}
+
+static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
+                                  struct v4l2_fmtdesc *f)
+{
+       const struct mtk_vcodec_enc_pdata *pdata =
+               fh_to_ctx(priv)->dev->venc_pdata;
+
+       return vidioc_enum_fmt(f, pdata->output_formats,
+                              pdata->num_output_formats);
+}
+
+static int vidioc_venc_querycap(struct file *file, void *priv,
+                               struct v4l2_capability *cap)
+{
+       strscpy(cap->driver, MTK_VCODEC_ENC_NAME, sizeof(cap->driver));
+       strscpy(cap->bus_info, MTK_PLATFORM_STR, sizeof(cap->bus_info));
+       strscpy(cap->card, MTK_PLATFORM_STR, sizeof(cap->card));
+
+       return 0;
+}
+
+static int vidioc_venc_s_parm(struct file *file, void *priv,
+                             struct v4l2_streamparm *a)
+{
+       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+       struct v4l2_fract *timeperframe = &a->parm.output.timeperframe;
+
+       if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               return -EINVAL;
+
+       if (timeperframe->numerator == 0 || timeperframe->denominator == 0) {
+               timeperframe->numerator = MTK_DEFAULT_FRAMERATE_NUM;
+               timeperframe->denominator = MTK_DEFAULT_FRAMERATE_DENOM;
+       }
+
+       ctx->enc_params.framerate_num = timeperframe->denominator;
+       ctx->enc_params.framerate_denom = timeperframe->numerator;
+       ctx->param_change |= MTK_ENCODE_PARAM_FRAMERATE;
+
+       a->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
+
+       return 0;
+}
+
+static int vidioc_venc_g_parm(struct file *file, void *priv,
+                             struct v4l2_streamparm *a)
+{
+       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+
+       if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               return -EINVAL;
+
+       a->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
+       a->parm.output.timeperframe.denominator =
+                       ctx->enc_params.framerate_num;
+       a->parm.output.timeperframe.numerator =
+                       ctx->enc_params.framerate_denom;
+
+       return 0;
+}
+
+static struct mtk_q_data *mtk_venc_get_q_data(struct mtk_vcodec_ctx *ctx,
+                                             enum v4l2_buf_type type)
+{
+       if (V4L2_TYPE_IS_OUTPUT(type))
+               return &ctx->q_data[MTK_Q_DATA_SRC];
+
+       return &ctx->q_data[MTK_Q_DATA_DST];
+}
+
+static void vidioc_try_fmt_cap(struct v4l2_format *f)
+{
+       f->fmt.pix_mp.field = V4L2_FIELD_NONE;
+       f->fmt.pix_mp.num_planes = 1;
+       f->fmt.pix_mp.plane_fmt[0].bytesperline = 0;
+       f->fmt.pix_mp.flags = 0;
+}
+
+/* V4L2 specification suggests the driver corrects the format struct if any of
+ * the dimensions is unsupported
+ */
+static int vidioc_try_fmt_out(struct mtk_vcodec_ctx *ctx, struct v4l2_format *f,
+                             const struct mtk_video_fmt *fmt)
+{
+       struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
+       int tmp_w, tmp_h;
+       unsigned int max_width, max_height;
+
+       pix_fmt_mp->field = V4L2_FIELD_NONE;
+
+       if (ctx->dev->enc_capability & MTK_VENC_4K_CAPABILITY_ENABLE) {
+               max_width = MTK_VENC_4K_MAX_W;
+               max_height = MTK_VENC_4K_MAX_H;
+       } else {
+               max_width = MTK_VENC_HD_MAX_W;
+               max_height = MTK_VENC_HD_MAX_H;
+       }
+
+       pix_fmt_mp->height = clamp(pix_fmt_mp->height, MTK_VENC_MIN_H, max_height);
+       pix_fmt_mp->width = clamp(pix_fmt_mp->width, MTK_VENC_MIN_W, max_width);
+
+       /* find next closer width align 16, heign align 32, size align
+        * 64 rectangle
+        */
+       tmp_w = pix_fmt_mp->width;
+       tmp_h = pix_fmt_mp->height;
+       v4l_bound_align_image(&pix_fmt_mp->width,
+                             MTK_VENC_MIN_W,
+                             max_width, 4,
+                             &pix_fmt_mp->height,
+                             MTK_VENC_MIN_H,
+                             max_height, 5, 6);
+
+       if (pix_fmt_mp->width < tmp_w && (pix_fmt_mp->width + 16) <= max_width)
+               pix_fmt_mp->width += 16;
+       if (pix_fmt_mp->height < tmp_h && (pix_fmt_mp->height + 32) <= max_height)
+               pix_fmt_mp->height += 32;
+
+       mtk_v4l2_debug(0, "before resize w=%d, h=%d, after resize w=%d, h=%d, sizeimage=%d %d",
+                      tmp_w, tmp_h, pix_fmt_mp->width,
+                      pix_fmt_mp->height,
+                      pix_fmt_mp->plane_fmt[0].sizeimage,
+                      pix_fmt_mp->plane_fmt[1].sizeimage);
+
+       pix_fmt_mp->num_planes = fmt->num_planes;
+       pix_fmt_mp->plane_fmt[0].sizeimage =
+                       pix_fmt_mp->width * pix_fmt_mp->height +
+                       ((ALIGN(pix_fmt_mp->width, 16) * 2) * 16);
+       pix_fmt_mp->plane_fmt[0].bytesperline = pix_fmt_mp->width;
+
+       if (pix_fmt_mp->num_planes == 2) {
+               pix_fmt_mp->plane_fmt[1].sizeimage =
+                       (pix_fmt_mp->width * pix_fmt_mp->height) / 2 +
+                       (ALIGN(pix_fmt_mp->width, 16) * 16);
+               pix_fmt_mp->plane_fmt[2].sizeimage = 0;
+               pix_fmt_mp->plane_fmt[1].bytesperline =
+                                               pix_fmt_mp->width;
+               pix_fmt_mp->plane_fmt[2].bytesperline = 0;
+       } else if (pix_fmt_mp->num_planes == 3) {
+               pix_fmt_mp->plane_fmt[1].sizeimage =
+               pix_fmt_mp->plane_fmt[2].sizeimage =
+                       (pix_fmt_mp->width * pix_fmt_mp->height) / 4 +
+                       ((ALIGN(pix_fmt_mp->width, 16) / 2) * 16);
+               pix_fmt_mp->plane_fmt[1].bytesperline =
+                       pix_fmt_mp->plane_fmt[2].bytesperline =
+                       pix_fmt_mp->width / 2;
+       }
+
+       pix_fmt_mp->flags = 0;
+
+       return 0;
+}
+
+static void mtk_venc_set_param(struct mtk_vcodec_ctx *ctx,
+                               struct venc_enc_param *param)
+{
+       struct mtk_q_data *q_data_src = &ctx->q_data[MTK_Q_DATA_SRC];
+       struct mtk_enc_params *enc_params = &ctx->enc_params;
+
+       switch (q_data_src->fmt->fourcc) {
+       case V4L2_PIX_FMT_YUV420M:
+               param->input_yuv_fmt = VENC_YUV_FORMAT_I420;
+               break;
+       case V4L2_PIX_FMT_YVU420M:
+               param->input_yuv_fmt = VENC_YUV_FORMAT_YV12;
+               break;
+       case V4L2_PIX_FMT_NV12M:
+               param->input_yuv_fmt = VENC_YUV_FORMAT_NV12;
+               break;
+       case V4L2_PIX_FMT_NV21M:
+               param->input_yuv_fmt = VENC_YUV_FORMAT_NV21;
+               break;
+       default:
+               mtk_v4l2_err("Unsupported fourcc =%d", q_data_src->fmt->fourcc);
+               break;
+       }
+       param->h264_profile = enc_params->h264_profile;
+       param->h264_level = enc_params->h264_level;
+
+       /* Config visible resolution */
+       param->width = q_data_src->visible_width;
+       param->height = q_data_src->visible_height;
+       /* Config coded resolution */
+       param->buf_width = q_data_src->coded_width;
+       param->buf_height = q_data_src->coded_height;
+       param->frm_rate = enc_params->framerate_num /
+                       enc_params->framerate_denom;
+       param->intra_period = enc_params->intra_period;
+       param->gop_size = enc_params->gop_size;
+       param->bitrate = enc_params->bitrate;
+
+       mtk_v4l2_debug(0,
+               "fmt 0x%x, P/L %d/%d, w/h %d/%d, buf %d/%d, fps/bps %d/%d, gop %d, i_period %d",
+               param->input_yuv_fmt, param->h264_profile,
+               param->h264_level, param->width, param->height,
+               param->buf_width, param->buf_height,
+               param->frm_rate, param->bitrate,
+               param->gop_size, param->intra_period);
+}
+
+static int vidioc_venc_s_fmt_cap(struct file *file, void *priv,
+                            struct v4l2_format *f)
+{
+       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+       const struct mtk_vcodec_enc_pdata *pdata = ctx->dev->venc_pdata;
+       struct vb2_queue *vq;
+       struct mtk_q_data *q_data = mtk_venc_get_q_data(ctx, f->type);
+       int i, ret;
+       const struct mtk_video_fmt *fmt;
+
+       vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+       if (!vq) {
+               mtk_v4l2_err("fail to get vq");
+               return -EINVAL;
+       }
+
+       if (vb2_is_busy(vq)) {
+               mtk_v4l2_err("queue busy");
+               return -EBUSY;
+       }
+
+       fmt = mtk_venc_find_format(f->fmt.pix.pixelformat, pdata);
+       if (!fmt) {
+               fmt = &ctx->dev->venc_pdata->capture_formats[0];
+               f->fmt.pix.pixelformat = fmt->fourcc;
+       }
+
+       q_data->fmt = fmt;
+       vidioc_try_fmt_cap(f);
+
+       q_data->coded_width = f->fmt.pix_mp.width;
+       q_data->coded_height = f->fmt.pix_mp.height;
+       q_data->field = f->fmt.pix_mp.field;
+
+       for (i = 0; i < f->fmt.pix_mp.num_planes; i++) {
+               struct v4l2_plane_pix_format    *plane_fmt;
+
+               plane_fmt = &f->fmt.pix_mp.plane_fmt[i];
+               q_data->bytesperline[i] = plane_fmt->bytesperline;
+               q_data->sizeimage[i] = plane_fmt->sizeimage;
+       }
+
+       if (ctx->state == MTK_STATE_FREE) {
+               ret = venc_if_init(ctx, q_data->fmt->fourcc);
+               if (ret) {
+                       mtk_v4l2_err("venc_if_init failed=%d, codec type=%x",
+                                       ret, q_data->fmt->fourcc);
+                       return -EBUSY;
+               }
+               ctx->state = MTK_STATE_INIT;
+       }
+
+       return 0;
+}
+
+static int vidioc_venc_s_fmt_out(struct file *file, void *priv,
+                            struct v4l2_format *f)
+{
+       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+       const struct mtk_vcodec_enc_pdata *pdata = ctx->dev->venc_pdata;
+       struct vb2_queue *vq;
+       struct mtk_q_data *q_data = mtk_venc_get_q_data(ctx, f->type);
+       int ret, i;
+       const struct mtk_video_fmt *fmt;
+
+       vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+       if (!vq) {
+               mtk_v4l2_err("fail to get vq");
+               return -EINVAL;
+       }
+
+       if (vb2_is_busy(vq)) {
+               mtk_v4l2_err("queue busy");
+               return -EBUSY;
+       }
+
+       fmt = mtk_venc_find_format(f->fmt.pix.pixelformat, pdata);
+       if (!fmt) {
+               fmt = &ctx->dev->venc_pdata->output_formats[0];
+               f->fmt.pix.pixelformat = fmt->fourcc;
+       }
+
+       ret = vidioc_try_fmt_out(ctx, f, fmt);
+       if (ret)
+               return ret;
+
+       q_data->fmt = fmt;
+       q_data->visible_width = f->fmt.pix_mp.width;
+       q_data->visible_height = f->fmt.pix_mp.height;
+       q_data->coded_width = f->fmt.pix_mp.width;
+       q_data->coded_height = f->fmt.pix_mp.height;
+
+       q_data->field = f->fmt.pix_mp.field;
+       ctx->colorspace = f->fmt.pix_mp.colorspace;
+       ctx->ycbcr_enc = f->fmt.pix_mp.ycbcr_enc;
+       ctx->quantization = f->fmt.pix_mp.quantization;
+       ctx->xfer_func = f->fmt.pix_mp.xfer_func;
+
+       for (i = 0; i < f->fmt.pix_mp.num_planes; i++) {
+               struct v4l2_plane_pix_format *plane_fmt;
+
+               plane_fmt = &f->fmt.pix_mp.plane_fmt[i];
+               q_data->bytesperline[i] = plane_fmt->bytesperline;
+               q_data->sizeimage[i] = plane_fmt->sizeimage;
+       }
+
+       return 0;
+}
+
+static int vidioc_venc_g_fmt(struct file *file, void *priv,
+                            struct v4l2_format *f)
+{
+       struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
+       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+       struct vb2_queue *vq;
+       struct mtk_q_data *q_data = mtk_venc_get_q_data(ctx, f->type);
+       int i;
+
+       vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+       if (!vq)
+               return -EINVAL;
+
+
+       pix->width = q_data->coded_width;
+       pix->height = q_data->coded_height;
+       pix->pixelformat = q_data->fmt->fourcc;
+       pix->field = q_data->field;
+       pix->num_planes = q_data->fmt->num_planes;
+       for (i = 0; i < pix->num_planes; i++) {
+               pix->plane_fmt[i].bytesperline = q_data->bytesperline[i];
+               pix->plane_fmt[i].sizeimage = q_data->sizeimage[i];
+       }
+
+       pix->flags = 0;
+       pix->colorspace = ctx->colorspace;
+       pix->ycbcr_enc = ctx->ycbcr_enc;
+       pix->quantization = ctx->quantization;
+       pix->xfer_func = ctx->xfer_func;
+
+       return 0;
+}
+
+static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv,
+                                        struct v4l2_format *f)
+{
+       const struct mtk_video_fmt *fmt;
+       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+       const struct mtk_vcodec_enc_pdata *pdata = ctx->dev->venc_pdata;
+
+       fmt = mtk_venc_find_format(f->fmt.pix.pixelformat, pdata);
+       if (!fmt) {
+               fmt = &ctx->dev->venc_pdata->capture_formats[0];
+               f->fmt.pix.pixelformat = fmt->fourcc;
+       }
+       f->fmt.pix_mp.colorspace = ctx->colorspace;
+       f->fmt.pix_mp.ycbcr_enc = ctx->ycbcr_enc;
+       f->fmt.pix_mp.quantization = ctx->quantization;
+       f->fmt.pix_mp.xfer_func = ctx->xfer_func;
+
+       vidioc_try_fmt_cap(f);
+
+       return 0;
+}
+
+static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv,
+                                        struct v4l2_format *f)
+{
+       const struct mtk_video_fmt *fmt;
+       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+       const struct mtk_vcodec_enc_pdata *pdata = ctx->dev->venc_pdata;
+
+       fmt = mtk_venc_find_format(f->fmt.pix.pixelformat, pdata);
+       if (!fmt) {
+               fmt = &ctx->dev->venc_pdata->output_formats[0];
+               f->fmt.pix.pixelformat = fmt->fourcc;
+       }
+       if (!f->fmt.pix_mp.colorspace) {
+               f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_REC709;
+               f->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+               f->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT;
+               f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT;
+       }
+
+       return vidioc_try_fmt_out(ctx, f, fmt);
+}
+
+static int vidioc_venc_g_selection(struct file *file, void *priv,
+                                    struct v4l2_selection *s)
+{
+       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+       struct mtk_q_data *q_data = mtk_venc_get_q_data(ctx, s->type);
+
+       if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+               return -EINVAL;
+
+       switch (s->target) {
+       case V4L2_SEL_TGT_CROP_DEFAULT:
+       case V4L2_SEL_TGT_CROP_BOUNDS:
+               s->r.top = 0;
+               s->r.left = 0;
+               s->r.width = q_data->coded_width;
+               s->r.height = q_data->coded_height;
+               break;
+       case V4L2_SEL_TGT_CROP:
+               s->r.top = 0;
+               s->r.left = 0;
+               s->r.width = q_data->visible_width;
+               s->r.height = q_data->visible_height;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int vidioc_venc_s_selection(struct file *file, void *priv,
+                                    struct v4l2_selection *s)
+{
+       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+       struct mtk_q_data *q_data = mtk_venc_get_q_data(ctx, s->type);
+
+       if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+               return -EINVAL;
+
+       switch (s->target) {
+       case V4L2_SEL_TGT_CROP:
+               /* Only support crop from (0,0) */
+               s->r.top = 0;
+               s->r.left = 0;
+               s->r.width = min(s->r.width, q_data->coded_width);
+               s->r.height = min(s->r.height, q_data->coded_height);
+               q_data->visible_width = s->r.width;
+               q_data->visible_height = s->r.height;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int vidioc_venc_qbuf(struct file *file, void *priv,
+                           struct v4l2_buffer *buf)
+{
+       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+
+       if (ctx->state == MTK_STATE_ABORT) {
+               mtk_v4l2_err("[%d] Call on QBUF after unrecoverable error",
+                               ctx->id);
+               return -EIO;
+       }
+
+       return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_venc_dqbuf(struct file *file, void *priv,
+                            struct v4l2_buffer *buf)
+{
+       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+       int ret;
+
+       if (ctx->state == MTK_STATE_ABORT) {
+               mtk_v4l2_err("[%d] Call on QBUF after unrecoverable error",
+                               ctx->id);
+               return -EIO;
+       }
+
+       ret = v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
+       if (ret)
+               return ret;
+
+       /*
+        * Complete flush if the user dequeued the 0-payload LAST buffer.
+        * We check the payload because a buffer with the LAST flag can also
+        * be seen during resolution changes. If we happen to be flushing at
+        * that time, the last buffer before the resolution changes could be
+        * misinterpreted for the buffer generated by the flush and terminate
+        * it earlier than we want.
+        */
+       if (!V4L2_TYPE_IS_OUTPUT(buf->type) &&
+           buf->flags & V4L2_BUF_FLAG_LAST &&
+           buf->m.planes[0].bytesused == 0 &&
+           ctx->is_flushing) {
+               /*
+                * Last CAPTURE buffer is dequeued, we can allow another flush
+                * to take place.
+                */
+               ctx->is_flushing = false;
+       }
+
+       return 0;
+}
+
+static int vidioc_encoder_cmd(struct file *file, void *priv,
+                             struct v4l2_encoder_cmd *cmd)
+{
+       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+       struct vb2_queue *src_vq, *dst_vq;
+       int ret;
+
+       if (ctx->state == MTK_STATE_ABORT) {
+               mtk_v4l2_err("[%d] Call to CMD after unrecoverable error",
+                            ctx->id);
+               return -EIO;
+       }
+
+       ret = v4l2_m2m_ioctl_try_encoder_cmd(file, priv, cmd);
+       if (ret)
+               return ret;
+
+       /* Calling START or STOP is invalid if a flush is in progress */
+       if (ctx->is_flushing)
+               return -EBUSY;
+
+       mtk_v4l2_debug(1, "encoder cmd=%u", cmd->cmd);
+
+       dst_vq = v4l2_m2m_get_vq(ctx->m2m_ctx,
+                                V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+       switch (cmd->cmd) {
+       case V4L2_ENC_CMD_STOP:
+               src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx,
+                                        V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+               if (!vb2_is_streaming(src_vq)) {
+                       mtk_v4l2_debug(1, "Output stream is off. No need to flush.");
+                       return 0;
+               }
+               if (!vb2_is_streaming(dst_vq)) {
+                       mtk_v4l2_debug(1, "Capture stream is off. No need to flush.");
+                       return 0;
+               }
+               ctx->is_flushing = true;
+               v4l2_m2m_buf_queue(ctx->m2m_ctx, &ctx->empty_flush_buf.vb);
+               v4l2_m2m_try_schedule(ctx->m2m_ctx);
+               break;
+
+       case V4L2_ENC_CMD_START:
+               vb2_clear_last_buffer_dequeued(dst_vq);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+const struct v4l2_ioctl_ops mtk_venc_ioctl_ops = {
+       .vidioc_streamon                = v4l2_m2m_ioctl_streamon,
+       .vidioc_streamoff               = v4l2_m2m_ioctl_streamoff,
+
+       .vidioc_reqbufs                 = v4l2_m2m_ioctl_reqbufs,
+       .vidioc_querybuf                = v4l2_m2m_ioctl_querybuf,
+       .vidioc_qbuf                    = vidioc_venc_qbuf,
+       .vidioc_dqbuf                   = vidioc_venc_dqbuf,
+
+       .vidioc_querycap                = vidioc_venc_querycap,
+       .vidioc_enum_fmt_vid_cap        = vidioc_enum_fmt_vid_cap,
+       .vidioc_enum_fmt_vid_out        = vidioc_enum_fmt_vid_out,
+       .vidioc_enum_framesizes         = vidioc_enum_framesizes,
+
+       .vidioc_try_fmt_vid_cap_mplane  = vidioc_try_fmt_vid_cap_mplane,
+       .vidioc_try_fmt_vid_out_mplane  = vidioc_try_fmt_vid_out_mplane,
+       .vidioc_expbuf                  = v4l2_m2m_ioctl_expbuf,
+       .vidioc_subscribe_event         = v4l2_ctrl_subscribe_event,
+       .vidioc_unsubscribe_event       = v4l2_event_unsubscribe,
+
+       .vidioc_s_parm                  = vidioc_venc_s_parm,
+       .vidioc_g_parm                  = vidioc_venc_g_parm,
+       .vidioc_s_fmt_vid_cap_mplane    = vidioc_venc_s_fmt_cap,
+       .vidioc_s_fmt_vid_out_mplane    = vidioc_venc_s_fmt_out,
+
+       .vidioc_g_fmt_vid_cap_mplane    = vidioc_venc_g_fmt,
+       .vidioc_g_fmt_vid_out_mplane    = vidioc_venc_g_fmt,
+
+       .vidioc_create_bufs             = v4l2_m2m_ioctl_create_bufs,
+       .vidioc_prepare_buf             = v4l2_m2m_ioctl_prepare_buf,
+
+       .vidioc_g_selection             = vidioc_venc_g_selection,
+       .vidioc_s_selection             = vidioc_venc_s_selection,
+
+       .vidioc_encoder_cmd             = vidioc_encoder_cmd,
+       .vidioc_try_encoder_cmd         = v4l2_m2m_ioctl_try_encoder_cmd,
+};
+
+static int vb2ops_venc_queue_setup(struct vb2_queue *vq,
+                                  unsigned int *nbuffers,
+                                  unsigned int *nplanes,
+                                  unsigned int sizes[],
+                                  struct device *alloc_devs[])
+{
+       struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vq);
+       struct mtk_q_data *q_data = mtk_venc_get_q_data(ctx, vq->type);
+       unsigned int i;
+
+       if (q_data == NULL)
+               return -EINVAL;
+
+       if (*nplanes) {
+               for (i = 0; i < *nplanes; i++)
+                       if (sizes[i] < q_data->sizeimage[i])
+                               return -EINVAL;
+       } else {
+               *nplanes = q_data->fmt->num_planes;
+               for (i = 0; i < *nplanes; i++)
+                       sizes[i] = q_data->sizeimage[i];
+       }
+
+       return 0;
+}
+
+static int vb2ops_venc_buf_prepare(struct vb2_buffer *vb)
+{
+       struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+       struct mtk_q_data *q_data = mtk_venc_get_q_data(ctx, vb->vb2_queue->type);
+       int i;
+
+       for (i = 0; i < q_data->fmt->num_planes; i++) {
+               if (vb2_plane_size(vb, i) < q_data->sizeimage[i]) {
+                       mtk_v4l2_err("data will not fit into plane %d (%lu < %d)",
+                               i, vb2_plane_size(vb, i),
+                               q_data->sizeimage[i]);
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+static void vb2ops_venc_buf_queue(struct vb2_buffer *vb)
+{
+       struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+       struct vb2_v4l2_buffer *vb2_v4l2 =
+                       container_of(vb, struct vb2_v4l2_buffer, vb2_buf);
+
+       struct mtk_video_enc_buf *mtk_buf =
+                       container_of(vb2_v4l2, struct mtk_video_enc_buf,
+                                    m2m_buf.vb);
+
+       if ((vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) &&
+           (ctx->param_change != MTK_ENCODE_PARAM_NONE)) {
+               mtk_v4l2_debug(1, "[%d] Before id=%d encode parameter change %x",
+                              ctx->id,
+                              vb2_v4l2->vb2_buf.index,
+                              ctx->param_change);
+               mtk_buf->param_change = ctx->param_change;
+               mtk_buf->enc_params = ctx->enc_params;
+               ctx->param_change = MTK_ENCODE_PARAM_NONE;
+       }
+
+       v4l2_m2m_buf_queue(ctx->m2m_ctx, to_vb2_v4l2_buffer(vb));
+}
+
+static int vb2ops_venc_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+       struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(q);
+       struct venc_enc_param param;
+       int ret, pm_ret;
+       int i;
+
+       /* Once state turn into MTK_STATE_ABORT, we need stop_streaming
+         * to clear it
+         */
+       if ((ctx->state == MTK_STATE_ABORT) || (ctx->state == MTK_STATE_FREE)) {
+               ret = -EIO;
+               goto err_start_stream;
+       }
+
+       /* Do the initialization when both start_streaming have been called */
+       if (V4L2_TYPE_IS_OUTPUT(q->type)) {
+               if (!vb2_start_streaming_called(&ctx->m2m_ctx->cap_q_ctx.q))
+                       return 0;
+       } else {
+               if (!vb2_start_streaming_called(&ctx->m2m_ctx->out_q_ctx.q))
+                       return 0;
+       }
+
+       ret = pm_runtime_resume_and_get(&ctx->dev->plat_dev->dev);
+       if (ret < 0) {
+               mtk_v4l2_err("pm_runtime_resume_and_get fail %d", ret);
+               goto err_start_stream;
+       }
+
+       mtk_venc_set_param(ctx, &param);
+       ret = venc_if_set_param(ctx, VENC_SET_PARAM_ENC, &param);
+       if (ret) {
+               mtk_v4l2_err("venc_if_set_param failed=%d", ret);
+               ctx->state = MTK_STATE_ABORT;
+               goto err_set_param;
+       }
+       ctx->param_change = MTK_ENCODE_PARAM_NONE;
+
+       if ((ctx->q_data[MTK_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_H264) &&
+           (ctx->enc_params.seq_hdr_mode !=
+                               V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE)) {
+               ret = venc_if_set_param(ctx,
+                                       VENC_SET_PARAM_PREPEND_HEADER,
+                                       NULL);
+               if (ret) {
+                       mtk_v4l2_err("venc_if_set_param failed=%d", ret);
+                       ctx->state = MTK_STATE_ABORT;
+                       goto err_set_param;
+               }
+               ctx->state = MTK_STATE_HEADER;
+       }
+
+       return 0;
+
+err_set_param:
+       pm_ret = pm_runtime_put(&ctx->dev->plat_dev->dev);
+       if (pm_ret < 0)
+               mtk_v4l2_err("pm_runtime_put fail %d", pm_ret);
+
+err_start_stream:
+       for (i = 0; i < q->num_buffers; ++i) {
+               struct vb2_buffer *buf = vb2_get_buffer(q, i);
+
+               /*
+                * FIXME: This check is not needed as only active buffers
+                * can be marked as done.
+                */
+               if (buf->state == VB2_BUF_STATE_ACTIVE) {
+                       mtk_v4l2_debug(0, "[%d] id=%d, type=%d, %d -> VB2_BUF_STATE_QUEUED",
+                                       ctx->id, i, q->type,
+                                       (int)buf->state);
+                       v4l2_m2m_buf_done(to_vb2_v4l2_buffer(buf),
+                                         VB2_BUF_STATE_QUEUED);
+               }
+       }
+
+       return ret;
+}
+
+static void vb2ops_venc_stop_streaming(struct vb2_queue *q)
+{
+       struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(q);
+       struct vb2_v4l2_buffer *src_buf, *dst_buf;
+       int ret;
+
+       mtk_v4l2_debug(2, "[%d]-> type=%d", ctx->id, q->type);
+
+       if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               while ((dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx))) {
+                       vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0);
+                       v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);
+               }
+               /* STREAMOFF on the CAPTURE queue completes any ongoing flush */
+               if (ctx->is_flushing) {
+                       struct v4l2_m2m_buffer *b, *n;
+
+                       mtk_v4l2_debug(1, "STREAMOFF called while flushing");
+                       /*
+                        * STREAMOFF could be called before the flush buffer is
+                        * dequeued. Check whether empty flush buf is still in
+                        * queue before removing it.
+                        */
+                       v4l2_m2m_for_each_src_buf_safe(ctx->m2m_ctx, b, n) {
+                               if (b == &ctx->empty_flush_buf) {
+                                       v4l2_m2m_src_buf_remove_by_buf(ctx->m2m_ctx, &b->vb);
+                                       break;
+                               }
+                       }
+                       ctx->is_flushing = false;
+               }
+       } else {
+               while ((src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx))) {
+                       if (src_buf != &ctx->empty_flush_buf.vb)
+                               v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
+               }
+               if (ctx->is_flushing) {
+                       /*
+                        * If we are in the middle of a flush, put the flush
+                        * buffer back into the queue so the next CAPTURE
+                        * buffer gets returned with the LAST flag set.
+                        */
+                       v4l2_m2m_buf_queue(ctx->m2m_ctx,
+                                          &ctx->empty_flush_buf.vb);
+               }
+       }
+
+       if ((q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
+            vb2_is_streaming(&ctx->m2m_ctx->out_q_ctx.q)) ||
+           (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
+            vb2_is_streaming(&ctx->m2m_ctx->cap_q_ctx.q))) {
+               mtk_v4l2_debug(1, "[%d]-> q type %d out=%d cap=%d",
+                              ctx->id, q->type,
+                              vb2_is_streaming(&ctx->m2m_ctx->out_q_ctx.q),
+                              vb2_is_streaming(&ctx->m2m_ctx->cap_q_ctx.q));
+               return;
+       }
+
+       /* Release the encoder if both streams are stopped. */
+       ret = venc_if_deinit(ctx);
+       if (ret)
+               mtk_v4l2_err("venc_if_deinit failed=%d", ret);
+
+       ret = pm_runtime_put(&ctx->dev->plat_dev->dev);
+       if (ret < 0)
+               mtk_v4l2_err("pm_runtime_put fail %d", ret);
+
+       ctx->state = MTK_STATE_FREE;
+}
+
+static int vb2ops_venc_buf_out_validate(struct vb2_buffer *vb)
+{
+       struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+       vbuf->field = V4L2_FIELD_NONE;
+       return 0;
+}
+
+static const struct vb2_ops mtk_venc_vb2_ops = {
+       .queue_setup            = vb2ops_venc_queue_setup,
+       .buf_out_validate       = vb2ops_venc_buf_out_validate,
+       .buf_prepare            = vb2ops_venc_buf_prepare,
+       .buf_queue              = vb2ops_venc_buf_queue,
+       .wait_prepare           = vb2_ops_wait_prepare,
+       .wait_finish            = vb2_ops_wait_finish,
+       .start_streaming        = vb2ops_venc_start_streaming,
+       .stop_streaming         = vb2ops_venc_stop_streaming,
+};
+
+static int mtk_venc_encode_header(void *priv)
+{
+       struct mtk_vcodec_ctx *ctx = priv;
+       int ret;
+       struct vb2_v4l2_buffer *src_buf, *dst_buf;
+       struct mtk_vcodec_mem bs_buf;
+       struct venc_done_result enc_result;
+
+       dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+       if (!dst_buf) {
+               mtk_v4l2_debug(1, "No dst buffer");
+               return -EINVAL;
+       }
+
+       bs_buf.va = vb2_plane_vaddr(&dst_buf->vb2_buf, 0);
+       bs_buf.dma_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
+       bs_buf.size = (size_t)dst_buf->vb2_buf.planes[0].length;
+
+       mtk_v4l2_debug(1,
+                       "[%d] buf id=%d va=0x%p dma_addr=0x%llx size=%zu",
+                       ctx->id,
+                       dst_buf->vb2_buf.index, bs_buf.va,
+                       (u64)bs_buf.dma_addr,
+                       bs_buf.size);
+
+       ret = venc_if_encode(ctx,
+                       VENC_START_OPT_ENCODE_SEQUENCE_HEADER,
+                       NULL, &bs_buf, &enc_result);
+
+       if (ret) {
+               vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0);
+               ctx->state = MTK_STATE_ABORT;
+               v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);
+               mtk_v4l2_err("venc_if_encode failed=%d", ret);
+               return -EINVAL;
+       }
+       src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+       if (src_buf) {
+               dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp;
+               dst_buf->timecode = src_buf->timecode;
+       } else {
+               mtk_v4l2_err("No timestamp for the header buffer.");
+       }
+
+       ctx->state = MTK_STATE_HEADER;
+       vb2_set_plane_payload(&dst_buf->vb2_buf, 0, enc_result.bs_size);
+       v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
+
+       return 0;
+}
+
+static int mtk_venc_param_change(struct mtk_vcodec_ctx *ctx)
+{
+       struct venc_enc_param enc_prm;
+       struct vb2_v4l2_buffer *vb2_v4l2 = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+       struct mtk_video_enc_buf *mtk_buf;
+       int ret = 0;
+
+       /* Don't upcast the empty flush buffer */
+       if (vb2_v4l2 == &ctx->empty_flush_buf.vb)
+               return 0;
+
+       mtk_buf = container_of(vb2_v4l2, struct mtk_video_enc_buf, m2m_buf.vb);
+
+       memset(&enc_prm, 0, sizeof(enc_prm));
+       if (mtk_buf->param_change == MTK_ENCODE_PARAM_NONE)
+               return 0;
+
+       if (mtk_buf->param_change & MTK_ENCODE_PARAM_BITRATE) {
+               enc_prm.bitrate = mtk_buf->enc_params.bitrate;
+               mtk_v4l2_debug(1, "[%d] id=%d, change param br=%d",
+                               ctx->id,
+                               vb2_v4l2->vb2_buf.index,
+                               enc_prm.bitrate);
+               ret |= venc_if_set_param(ctx,
+                                        VENC_SET_PARAM_ADJUST_BITRATE,
+                                        &enc_prm);
+       }
+       if (!ret && mtk_buf->param_change & MTK_ENCODE_PARAM_FRAMERATE) {
+               enc_prm.frm_rate = mtk_buf->enc_params.framerate_num /
+                                  mtk_buf->enc_params.framerate_denom;
+               mtk_v4l2_debug(1, "[%d] id=%d, change param fr=%d",
+                              ctx->id,
+                              vb2_v4l2->vb2_buf.index,
+                              enc_prm.frm_rate);
+               ret |= venc_if_set_param(ctx,
+                                        VENC_SET_PARAM_ADJUST_FRAMERATE,
+                                        &enc_prm);
+       }
+       if (!ret && mtk_buf->param_change & MTK_ENCODE_PARAM_GOP_SIZE) {
+               enc_prm.gop_size = mtk_buf->enc_params.gop_size;
+               mtk_v4l2_debug(1, "change param intra period=%d",
+                              enc_prm.gop_size);
+               ret |= venc_if_set_param(ctx,
+                                        VENC_SET_PARAM_GOP_SIZE,
+                                        &enc_prm);
+       }
+       if (!ret && mtk_buf->param_change & MTK_ENCODE_PARAM_FORCE_INTRA) {
+               mtk_v4l2_debug(1, "[%d] id=%d, change param force I=%d",
+                               ctx->id,
+                               vb2_v4l2->vb2_buf.index,
+                               mtk_buf->enc_params.force_intra);
+               if (mtk_buf->enc_params.force_intra)
+                       ret |= venc_if_set_param(ctx,
+                                                VENC_SET_PARAM_FORCE_INTRA,
+                                                NULL);
+       }
+
+       mtk_buf->param_change = MTK_ENCODE_PARAM_NONE;
+
+       if (ret) {
+               ctx->state = MTK_STATE_ABORT;
+               mtk_v4l2_err("venc_if_set_param %d failed=%d",
+                               mtk_buf->param_change, ret);
+               return -1;
+       }
+
+       return 0;
+}
+
+/*
+ * v4l2_m2m_streamoff() holds dev_mutex and waits mtk_venc_worker()
+ * to call v4l2_m2m_job_finish().
+ * If mtk_venc_worker() tries to acquire dev_mutex, it will deadlock.
+ * So this function must not try to acquire dev->dev_mutex.
+ * This means v4l2 ioctls and mtk_venc_worker() can run at the same time.
+ * mtk_venc_worker() should be carefully implemented to avoid bugs.
+ */
+static void mtk_venc_worker(struct work_struct *work)
+{
+       struct mtk_vcodec_ctx *ctx = container_of(work, struct mtk_vcodec_ctx,
+                                   encode_work);
+       struct vb2_v4l2_buffer *src_buf, *dst_buf;
+       struct venc_frm_buf frm_buf;
+       struct mtk_vcodec_mem bs_buf;
+       struct venc_done_result enc_result;
+       int ret, i;
+
+       /* check dst_buf, dst_buf may be removed in device_run
+        * to stored encdoe header so we need check dst_buf and
+        * call job_finish here to prevent recursion
+        */
+       dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+       if (!dst_buf) {
+               v4l2_m2m_job_finish(ctx->dev->m2m_dev_enc, ctx->m2m_ctx);
+               return;
+       }
+
+       src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+
+       /*
+        * If we see the flush buffer, send an empty buffer with the LAST flag
+        * to the client. is_flushing will be reset at the time the buffer
+        * is dequeued.
+        */
+       if (src_buf == &ctx->empty_flush_buf.vb) {
+               vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0);
+               dst_buf->flags |= V4L2_BUF_FLAG_LAST;
+               v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
+               v4l2_m2m_job_finish(ctx->dev->m2m_dev_enc, ctx->m2m_ctx);
+               return;
+       }
+
+       memset(&frm_buf, 0, sizeof(frm_buf));
+       for (i = 0; i < src_buf->vb2_buf.num_planes ; i++) {
+               frm_buf.fb_addr[i].dma_addr =
+                               vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, i);
+               frm_buf.fb_addr[i].size =
+                               (size_t)src_buf->vb2_buf.planes[i].length;
+       }
+       bs_buf.va = vb2_plane_vaddr(&dst_buf->vb2_buf, 0);
+       bs_buf.dma_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
+       bs_buf.size = (size_t)dst_buf->vb2_buf.planes[0].length;
+
+       mtk_v4l2_debug(2,
+                       "Framebuf PA=%llx Size=0x%zx;PA=0x%llx Size=0x%zx;PA=0x%llx Size=%zu",
+                       (u64)frm_buf.fb_addr[0].dma_addr,
+                       frm_buf.fb_addr[0].size,
+                       (u64)frm_buf.fb_addr[1].dma_addr,
+                       frm_buf.fb_addr[1].size,
+                       (u64)frm_buf.fb_addr[2].dma_addr,
+                       frm_buf.fb_addr[2].size);
+
+       ret = venc_if_encode(ctx, VENC_START_OPT_ENCODE_FRAME,
+                            &frm_buf, &bs_buf, &enc_result);
+
+       dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp;
+       dst_buf->timecode = src_buf->timecode;
+
+       if (enc_result.is_key_frm)
+               dst_buf->flags |= V4L2_BUF_FLAG_KEYFRAME;
+
+       if (ret) {
+               v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
+               vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0);
+               v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);
+               mtk_v4l2_err("venc_if_encode failed=%d", ret);
+       } else {
+               v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
+               vb2_set_plane_payload(&dst_buf->vb2_buf, 0, enc_result.bs_size);
+               v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
+               mtk_v4l2_debug(2, "venc_if_encode bs size=%d",
+                                enc_result.bs_size);
+       }
+
+       v4l2_m2m_job_finish(ctx->dev->m2m_dev_enc, ctx->m2m_ctx);
+
+       mtk_v4l2_debug(1, "<=== src_buf[%d] dst_buf[%d] venc_if_encode ret=%d Size=%u===>",
+                       src_buf->vb2_buf.index, dst_buf->vb2_buf.index, ret,
+                       enc_result.bs_size);
+}
+
+static void m2mops_venc_device_run(void *priv)
+{
+       struct mtk_vcodec_ctx *ctx = priv;
+
+       if ((ctx->q_data[MTK_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_H264) &&
+           (ctx->state != MTK_STATE_HEADER)) {
+               /* encode h264 sps/pps header */
+               mtk_venc_encode_header(ctx);
+               queue_work(ctx->dev->encode_workqueue, &ctx->encode_work);
+               return;
+       }
+
+       mtk_venc_param_change(ctx);
+       queue_work(ctx->dev->encode_workqueue, &ctx->encode_work);
+}
+
+static int m2mops_venc_job_ready(void *m2m_priv)
+{
+       struct mtk_vcodec_ctx *ctx = m2m_priv;
+
+       if (ctx->state == MTK_STATE_ABORT || ctx->state == MTK_STATE_FREE) {
+               mtk_v4l2_debug(3, "[%d]Not ready: state=0x%x.",
+                              ctx->id, ctx->state);
+               return 0;
+       }
+
+       return 1;
+}
+
+static void m2mops_venc_job_abort(void *priv)
+{
+       struct mtk_vcodec_ctx *ctx = priv;
+
+       ctx->state = MTK_STATE_ABORT;
+}
+
+const struct v4l2_m2m_ops mtk_venc_m2m_ops = {
+       .device_run     = m2mops_venc_device_run,
+       .job_ready      = m2mops_venc_job_ready,
+       .job_abort      = m2mops_venc_job_abort,
+};
+
+void mtk_vcodec_enc_set_default_params(struct mtk_vcodec_ctx *ctx)
+{
+       struct mtk_q_data *q_data;
+
+       ctx->m2m_ctx->q_lock = &ctx->dev->dev_mutex;
+       ctx->fh.m2m_ctx = ctx->m2m_ctx;
+       ctx->fh.ctrl_handler = &ctx->ctrl_hdl;
+       INIT_WORK(&ctx->encode_work, mtk_venc_worker);
+
+       ctx->colorspace = V4L2_COLORSPACE_REC709;
+       ctx->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+       ctx->quantization = V4L2_QUANTIZATION_DEFAULT;
+       ctx->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+
+       q_data = &ctx->q_data[MTK_Q_DATA_SRC];
+       memset(q_data, 0, sizeof(struct mtk_q_data));
+       q_data->visible_width = DFT_CFG_WIDTH;
+       q_data->visible_height = DFT_CFG_HEIGHT;
+       q_data->coded_width = DFT_CFG_WIDTH;
+       q_data->coded_height = DFT_CFG_HEIGHT;
+       q_data->field = V4L2_FIELD_NONE;
+
+       q_data->fmt = &ctx->dev->venc_pdata->output_formats[0];
+
+       v4l_bound_align_image(&q_data->coded_width,
+                               MTK_VENC_MIN_W,
+                               MTK_VENC_HD_MAX_W, 4,
+                               &q_data->coded_height,
+                               MTK_VENC_MIN_H,
+                               MTK_VENC_HD_MAX_H, 5, 6);
+
+       if (q_data->coded_width < DFT_CFG_WIDTH &&
+               (q_data->coded_width + 16) <= MTK_VENC_HD_MAX_W)
+               q_data->coded_width += 16;
+       if (q_data->coded_height < DFT_CFG_HEIGHT &&
+               (q_data->coded_height + 32) <= MTK_VENC_HD_MAX_H)
+               q_data->coded_height += 32;
+
+       q_data->sizeimage[0] =
+               q_data->coded_width * q_data->coded_height+
+               ((ALIGN(q_data->coded_width, 16) * 2) * 16);
+       q_data->bytesperline[0] = q_data->coded_width;
+       q_data->sizeimage[1] =
+               (q_data->coded_width * q_data->coded_height) / 2 +
+               (ALIGN(q_data->coded_width, 16) * 16);
+       q_data->bytesperline[1] = q_data->coded_width;
+
+       q_data = &ctx->q_data[MTK_Q_DATA_DST];
+       memset(q_data, 0, sizeof(struct mtk_q_data));
+       q_data->coded_width = DFT_CFG_WIDTH;
+       q_data->coded_height = DFT_CFG_HEIGHT;
+       q_data->fmt = &ctx->dev->venc_pdata->capture_formats[0];
+       q_data->field = V4L2_FIELD_NONE;
+       ctx->q_data[MTK_Q_DATA_DST].sizeimage[0] =
+               DFT_CFG_WIDTH * DFT_CFG_HEIGHT;
+       ctx->q_data[MTK_Q_DATA_DST].bytesperline[0] = 0;
+
+       ctx->enc_params.framerate_num = MTK_DEFAULT_FRAMERATE_NUM;
+       ctx->enc_params.framerate_denom = MTK_DEFAULT_FRAMERATE_DENOM;
+}
+
+int mtk_vcodec_enc_ctrls_setup(struct mtk_vcodec_ctx *ctx)
+{
+       const struct v4l2_ctrl_ops *ops = &mtk_vcodec_enc_ctrl_ops;
+       struct v4l2_ctrl_handler *handler = &ctx->ctrl_hdl;
+       u8 h264_max_level;
+
+       if (ctx->dev->enc_capability & MTK_VENC_4K_CAPABILITY_ENABLE)
+               h264_max_level = V4L2_MPEG_VIDEO_H264_LEVEL_5_1;
+       else
+               h264_max_level = V4L2_MPEG_VIDEO_H264_LEVEL_4_2;
+
+       v4l2_ctrl_handler_init(handler, MTK_MAX_CTRLS_HINT);
+
+       v4l2_ctrl_new_std(handler, ops, V4L2_CID_MIN_BUFFERS_FOR_OUTPUT,
+                         1, 1, 1, 1);
+       v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_BITRATE,
+                         ctx->dev->venc_pdata->min_bitrate,
+                         ctx->dev->venc_pdata->max_bitrate, 1, 4000000);
+       v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_B_FRAMES,
+                       0, 2, 1, 0);
+       v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE,
+                       0, 1, 1, 1);
+       v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_H264_MAX_QP,
+                       0, 51, 1, 51);
+       v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_H264_I_PERIOD,
+                       0, 65535, 1, 0);
+       v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_GOP_SIZE,
+                       0, 65535, 1, 0);
+       v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE,
+                       0, 1, 1, 0);
+       v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME,
+                       0, 0, 0, 0);
+       v4l2_ctrl_new_std_menu(handler, ops,
+                       V4L2_CID_MPEG_VIDEO_HEADER_MODE,
+                       V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME,
+                       0, V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE);
+       v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+                       V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
+                       0, V4L2_MPEG_VIDEO_H264_PROFILE_HIGH);
+       v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+                              h264_max_level,
+                              0, V4L2_MPEG_VIDEO_H264_LEVEL_4_0);
+       v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_MPEG_VIDEO_VP8_PROFILE,
+                              V4L2_MPEG_VIDEO_VP8_PROFILE_0, 0, V4L2_MPEG_VIDEO_VP8_PROFILE_0);
+
+
+       if (handler->error) {
+               mtk_v4l2_err("Init control handler fail %d",
+                               handler->error);
+               return handler->error;
+       }
+
+       v4l2_ctrl_handler_setup(&ctx->ctrl_hdl);
+
+       return 0;
+}
+
+int mtk_vcodec_enc_queue_init(void *priv, struct vb2_queue *src_vq,
+                             struct vb2_queue *dst_vq)
+{
+       struct mtk_vcodec_ctx *ctx = priv;
+       int ret;
+
+       /* Note: VB2_USERPTR works with dma-contig because mt8173
+        * support iommu
+        * https://patchwork.kernel.org/patch/8335461/
+        * https://patchwork.kernel.org/patch/7596181/
+        */
+       src_vq->type            = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+       src_vq->io_modes        = VB2_DMABUF | VB2_MMAP | VB2_USERPTR;
+       src_vq->drv_priv        = ctx;
+       src_vq->buf_struct_size = sizeof(struct mtk_video_enc_buf);
+       src_vq->ops             = &mtk_venc_vb2_ops;
+       src_vq->mem_ops         = &vb2_dma_contig_memops;
+       src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+       src_vq->lock            = &ctx->dev->dev_mutex;
+       src_vq->dev             = &ctx->dev->plat_dev->dev;
+
+       ret = vb2_queue_init(src_vq);
+       if (ret)
+               return ret;
+
+       dst_vq->type            = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+       dst_vq->io_modes        = VB2_DMABUF | VB2_MMAP | VB2_USERPTR;
+       dst_vq->drv_priv        = ctx;
+       dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+       dst_vq->ops             = &mtk_venc_vb2_ops;
+       dst_vq->mem_ops         = &vb2_dma_contig_memops;
+       dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+       dst_vq->lock            = &ctx->dev->dev_mutex;
+       dst_vq->dev             = &ctx->dev->plat_dev->dev;
+
+       return vb2_queue_init(dst_vq);
+}
+
+int mtk_venc_unlock(struct mtk_vcodec_ctx *ctx)
+{
+       struct mtk_vcodec_dev *dev = ctx->dev;
+
+       mutex_unlock(&dev->enc_mutex);
+       return 0;
+}
+
+int mtk_venc_lock(struct mtk_vcodec_ctx *ctx)
+{
+       struct mtk_vcodec_dev *dev = ctx->dev;
+
+       mutex_lock(&dev->enc_mutex);
+       return 0;
+}
+
+void mtk_vcodec_enc_release(struct mtk_vcodec_ctx *ctx)
+{
+       int ret = venc_if_deinit(ctx);
+
+       if (ret)
+               mtk_v4l2_err("venc_if_deinit failed=%d", ret);
+
+       ctx->state = MTK_STATE_FREE;
+}
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_enc.h b/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_enc.h
new file mode 100644 (file)
index 0000000..513ee79
--- /dev/null
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+* Copyright (c) 2016 MediaTek Inc.
+* Author: PC Chen <pc.chen@mediatek.com>
+*         Tiffany Lin <tiffany.lin@mediatek.com>
+*/
+
+#ifndef _MTK_VCODEC_ENC_H_
+#define _MTK_VCODEC_ENC_H_
+
+#include <media/videobuf2-core.h>
+#include <media/v4l2-mem2mem.h>
+
+#define MTK_VENC_IRQ_STATUS_SPS        0x1
+#define MTK_VENC_IRQ_STATUS_PPS        0x2
+#define MTK_VENC_IRQ_STATUS_FRM        0x4
+#define MTK_VENC_IRQ_STATUS_DRAM       0x8
+#define MTK_VENC_IRQ_STATUS_PAUSE      0x10
+#define MTK_VENC_IRQ_STATUS_SWITCH     0x20
+
+#define MTK_VENC_IRQ_STATUS_OFFSET     0x05C
+#define MTK_VENC_IRQ_ACK_OFFSET        0x060
+
+/**
+ * struct mtk_video_enc_buf - Private data related to each VB2 buffer.
+ * @m2m_buf:   M2M buffer
+ * @list:      list that buffer link to
+ * @param_change: Types of encode parameter change before encoding this
+ *                             buffer
+ * @enc_params: Encode parameters changed before encode this buffer
+ */
+struct mtk_video_enc_buf {
+       struct v4l2_m2m_buffer m2m_buf;
+
+       u32 param_change;
+       struct mtk_enc_params enc_params;
+};
+
+extern const struct v4l2_ioctl_ops mtk_venc_ioctl_ops;
+extern const struct v4l2_m2m_ops mtk_venc_m2m_ops;
+
+int mtk_venc_unlock(struct mtk_vcodec_ctx *ctx);
+int mtk_venc_lock(struct mtk_vcodec_ctx *ctx);
+int mtk_vcodec_enc_queue_init(void *priv, struct vb2_queue *src_vq,
+                             struct vb2_queue *dst_vq);
+void mtk_vcodec_enc_release(struct mtk_vcodec_ctx *ctx);
+int mtk_vcodec_enc_ctrls_setup(struct mtk_vcodec_ctx *ctx);
+void mtk_vcodec_enc_set_default_params(struct mtk_vcodec_ctx *ctx);
+
+#endif /* _MTK_VCODEC_ENC_H_ */
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_enc_drv.c b/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_enc_drv.c
new file mode 100644 (file)
index 0000000..5172cfe
--- /dev/null
@@ -0,0 +1,479 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+* Copyright (c) 2016 MediaTek Inc.
+* Author: PC Chen <pc.chen@mediatek.com>
+*      Tiffany Lin <tiffany.lin@mediatek.com>
+*/
+
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/pm_runtime.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "mtk_vcodec_drv.h"
+#include "mtk_vcodec_enc.h"
+#include "mtk_vcodec_enc_pm.h"
+#include "mtk_vcodec_intr.h"
+#include "mtk_vcodec_util.h"
+#include "mtk_vcodec_fw.h"
+
+static const struct mtk_video_fmt mtk_video_formats_output[] = {
+       {
+               .fourcc = V4L2_PIX_FMT_NV12M,
+               .type = MTK_FMT_FRAME,
+               .num_planes = 2,
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_NV21M,
+               .type = MTK_FMT_FRAME,
+               .num_planes = 2,
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_YUV420M,
+               .type = MTK_FMT_FRAME,
+               .num_planes = 3,
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_YVU420M,
+               .type = MTK_FMT_FRAME,
+               .num_planes = 3,
+       },
+};
+
+static const struct mtk_video_fmt mtk_video_formats_capture_h264[] =  {
+       {
+               .fourcc = V4L2_PIX_FMT_H264,
+               .type = MTK_FMT_ENC,
+               .num_planes = 1,
+       },
+};
+
+static const struct mtk_video_fmt mtk_video_formats_capture_vp8[] =  {
+       {
+               .fourcc = V4L2_PIX_FMT_VP8,
+               .type = MTK_FMT_ENC,
+               .num_planes = 1,
+       },
+};
+
+static void clean_irq_status(unsigned int irq_status, void __iomem *addr)
+{
+       if (irq_status & MTK_VENC_IRQ_STATUS_PAUSE)
+               writel(MTK_VENC_IRQ_STATUS_PAUSE, addr);
+
+       if (irq_status & MTK_VENC_IRQ_STATUS_SWITCH)
+               writel(MTK_VENC_IRQ_STATUS_SWITCH, addr);
+
+       if (irq_status & MTK_VENC_IRQ_STATUS_DRAM)
+               writel(MTK_VENC_IRQ_STATUS_DRAM, addr);
+
+       if (irq_status & MTK_VENC_IRQ_STATUS_SPS)
+               writel(MTK_VENC_IRQ_STATUS_SPS, addr);
+
+       if (irq_status & MTK_VENC_IRQ_STATUS_PPS)
+               writel(MTK_VENC_IRQ_STATUS_PPS, addr);
+
+       if (irq_status & MTK_VENC_IRQ_STATUS_FRM)
+               writel(MTK_VENC_IRQ_STATUS_FRM, addr);
+
+}
+static irqreturn_t mtk_vcodec_enc_irq_handler(int irq, void *priv)
+{
+       struct mtk_vcodec_dev *dev = priv;
+       struct mtk_vcodec_ctx *ctx;
+       unsigned long flags;
+       void __iomem *addr;
+
+       spin_lock_irqsave(&dev->irqlock, flags);
+       ctx = dev->curr_ctx;
+       spin_unlock_irqrestore(&dev->irqlock, flags);
+
+       mtk_v4l2_debug(1, "id=%d coreid:%d", ctx->id, dev->venc_pdata->core_id);
+       addr = dev->reg_base[dev->venc_pdata->core_id] +
+                               MTK_VENC_IRQ_ACK_OFFSET;
+
+       ctx->irq_status = readl(dev->reg_base[dev->venc_pdata->core_id] +
+                               (MTK_VENC_IRQ_STATUS_OFFSET));
+
+       clean_irq_status(ctx->irq_status, addr);
+
+       wake_up_ctx(ctx, MTK_INST_IRQ_RECEIVED, 0);
+       return IRQ_HANDLED;
+}
+
+static int fops_vcodec_open(struct file *file)
+{
+       struct mtk_vcodec_dev *dev = video_drvdata(file);
+       struct mtk_vcodec_ctx *ctx = NULL;
+       int ret = 0;
+       struct vb2_queue *src_vq;
+
+       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+
+       mutex_lock(&dev->dev_mutex);
+       /*
+        * Use simple counter to uniquely identify this context. Only
+        * used for logging.
+        */
+       ctx->id = dev->id_counter++;
+       v4l2_fh_init(&ctx->fh, video_devdata(file));
+       file->private_data = &ctx->fh;
+       v4l2_fh_add(&ctx->fh);
+       INIT_LIST_HEAD(&ctx->list);
+       ctx->dev = dev;
+       init_waitqueue_head(&ctx->queue[0]);
+
+       ctx->type = MTK_INST_ENCODER;
+       ret = mtk_vcodec_enc_ctrls_setup(ctx);
+       if (ret) {
+               mtk_v4l2_err("Failed to setup controls() (%d)",
+                               ret);
+               goto err_ctrls_setup;
+       }
+       ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev_enc, ctx,
+                                        &mtk_vcodec_enc_queue_init);
+       if (IS_ERR((__force void *)ctx->m2m_ctx)) {
+               ret = PTR_ERR((__force void *)ctx->m2m_ctx);
+               mtk_v4l2_err("Failed to v4l2_m2m_ctx_init() (%d)",
+                               ret);
+               goto err_m2m_ctx_init;
+       }
+       src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx,
+                                V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+       ctx->empty_flush_buf.vb.vb2_buf.vb2_queue = src_vq;
+       mtk_vcodec_enc_set_default_params(ctx);
+
+       if (v4l2_fh_is_singular(&ctx->fh)) {
+               /*
+                * load fireware to checks if it was loaded already and
+                * does nothing in that case
+                */
+               ret = mtk_vcodec_fw_load_firmware(dev->fw_handler);
+               if (ret < 0) {
+                       /*
+                        * Return 0 if downloading firmware successfully,
+                        * otherwise it is failed
+                        */
+                       mtk_v4l2_err("vpu_load_firmware failed!");
+                       goto err_load_fw;
+               }
+
+               dev->enc_capability =
+                       mtk_vcodec_fw_get_venc_capa(dev->fw_handler);
+               mtk_v4l2_debug(0, "encoder capability %x", dev->enc_capability);
+       }
+
+       mtk_v4l2_debug(2, "Create instance [%d]@%p m2m_ctx=%p ",
+                       ctx->id, ctx, ctx->m2m_ctx);
+
+       list_add(&ctx->list, &dev->ctx_list);
+
+       mutex_unlock(&dev->dev_mutex);
+       mtk_v4l2_debug(0, "%s encoder [%d]", dev_name(&dev->plat_dev->dev),
+                       ctx->id);
+       return ret;
+
+       /* Deinit when failure occurred */
+err_load_fw:
+       v4l2_m2m_ctx_release(ctx->m2m_ctx);
+err_m2m_ctx_init:
+       v4l2_ctrl_handler_free(&ctx->ctrl_hdl);
+err_ctrls_setup:
+       v4l2_fh_del(&ctx->fh);
+       v4l2_fh_exit(&ctx->fh);
+       kfree(ctx);
+       mutex_unlock(&dev->dev_mutex);
+
+       return ret;
+}
+
+static int fops_vcodec_release(struct file *file)
+{
+       struct mtk_vcodec_dev *dev = video_drvdata(file);
+       struct mtk_vcodec_ctx *ctx = fh_to_ctx(file->private_data);
+
+       mtk_v4l2_debug(1, "[%d] encoder", ctx->id);
+       mutex_lock(&dev->dev_mutex);
+
+       v4l2_m2m_ctx_release(ctx->m2m_ctx);
+       mtk_vcodec_enc_release(ctx);
+       v4l2_fh_del(&ctx->fh);
+       v4l2_fh_exit(&ctx->fh);
+       v4l2_ctrl_handler_free(&ctx->ctrl_hdl);
+
+       list_del_init(&ctx->list);
+       kfree(ctx);
+       mutex_unlock(&dev->dev_mutex);
+       return 0;
+}
+
+static const struct v4l2_file_operations mtk_vcodec_fops = {
+       .owner          = THIS_MODULE,
+       .open           = fops_vcodec_open,
+       .release        = fops_vcodec_release,
+       .poll           = v4l2_m2m_fop_poll,
+       .unlocked_ioctl = video_ioctl2,
+       .mmap           = v4l2_m2m_fop_mmap,
+};
+
+static int mtk_vcodec_probe(struct platform_device *pdev)
+{
+       struct mtk_vcodec_dev *dev;
+       struct video_device *vfd_enc;
+       struct resource *res;
+       phandle rproc_phandle;
+       enum mtk_vcodec_fw_type fw_type;
+       int ret;
+
+       dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&dev->ctx_list);
+       dev->plat_dev = pdev;
+
+       if (!of_property_read_u32(pdev->dev.of_node, "mediatek,vpu",
+                                 &rproc_phandle)) {
+               fw_type = VPU;
+       } else if (!of_property_read_u32(pdev->dev.of_node, "mediatek,scp",
+                                        &rproc_phandle)) {
+               fw_type = SCP;
+       } else {
+               mtk_v4l2_err("Could not get venc IPI device");
+               return -ENODEV;
+       }
+       dma_set_max_seg_size(&pdev->dev, UINT_MAX);
+
+       dev->fw_handler = mtk_vcodec_fw_select(dev, fw_type, ENCODER);
+       if (IS_ERR(dev->fw_handler))
+               return PTR_ERR(dev->fw_handler);
+
+       dev->venc_pdata = of_device_get_match_data(&pdev->dev);
+       ret = mtk_vcodec_init_enc_clk(dev);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to get mtk vcodec clock source!");
+               goto err_enc_pm;
+       }
+
+       pm_runtime_enable(&pdev->dev);
+
+       dev->reg_base[dev->venc_pdata->core_id] =
+               devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(dev->reg_base[dev->venc_pdata->core_id])) {
+               ret = PTR_ERR(dev->reg_base[dev->venc_pdata->core_id]);
+               goto err_res;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (res == NULL) {
+               dev_err(&pdev->dev, "failed to get irq resource");
+               ret = -ENOENT;
+               goto err_res;
+       }
+
+       dev->enc_irq = platform_get_irq(pdev, 0);
+       irq_set_status_flags(dev->enc_irq, IRQ_NOAUTOEN);
+       ret = devm_request_irq(&pdev->dev, dev->enc_irq,
+                              mtk_vcodec_enc_irq_handler,
+                              0, pdev->name, dev);
+       if (ret) {
+               dev_err(&pdev->dev,
+                       "Failed to install dev->enc_irq %d (%d) core_id (%d)",
+                       dev->enc_irq, ret, dev->venc_pdata->core_id);
+               ret = -EINVAL;
+               goto err_res;
+       }
+
+       mutex_init(&dev->enc_mutex);
+       mutex_init(&dev->dev_mutex);
+       spin_lock_init(&dev->irqlock);
+
+       snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), "%s",
+                "[MTK_V4L2_VENC]");
+
+       ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+       if (ret) {
+               mtk_v4l2_err("v4l2_device_register err=%d", ret);
+               goto err_res;
+       }
+
+       init_waitqueue_head(&dev->queue);
+
+       /* allocate video device for encoder and register it */
+       vfd_enc = video_device_alloc();
+       if (!vfd_enc) {
+               mtk_v4l2_err("Failed to allocate video device");
+               ret = -ENOMEM;
+               goto err_enc_alloc;
+       }
+       vfd_enc->fops           = &mtk_vcodec_fops;
+       vfd_enc->ioctl_ops      = &mtk_venc_ioctl_ops;
+       vfd_enc->release        = video_device_release;
+       vfd_enc->lock           = &dev->dev_mutex;
+       vfd_enc->v4l2_dev       = &dev->v4l2_dev;
+       vfd_enc->vfl_dir        = VFL_DIR_M2M;
+       vfd_enc->device_caps    = V4L2_CAP_VIDEO_M2M_MPLANE |
+                                       V4L2_CAP_STREAMING;
+
+       snprintf(vfd_enc->name, sizeof(vfd_enc->name), "%s",
+                MTK_VCODEC_ENC_NAME);
+       video_set_drvdata(vfd_enc, dev);
+       dev->vfd_enc = vfd_enc;
+       platform_set_drvdata(pdev, dev);
+
+       dev->m2m_dev_enc = v4l2_m2m_init(&mtk_venc_m2m_ops);
+       if (IS_ERR((__force void *)dev->m2m_dev_enc)) {
+               mtk_v4l2_err("Failed to init mem2mem enc device");
+               ret = PTR_ERR((__force void *)dev->m2m_dev_enc);
+               goto err_enc_mem_init;
+       }
+
+       dev->encode_workqueue =
+                       alloc_ordered_workqueue(MTK_VCODEC_ENC_NAME,
+                                               WQ_MEM_RECLAIM |
+                                               WQ_FREEZABLE);
+       if (!dev->encode_workqueue) {
+               mtk_v4l2_err("Failed to create encode workqueue");
+               ret = -EINVAL;
+               goto err_event_workq;
+       }
+
+       if (of_get_property(pdev->dev.of_node, "dma-ranges", NULL))
+               dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34));
+
+       ret = video_register_device(vfd_enc, VFL_TYPE_VIDEO, -1);
+       if (ret) {
+               mtk_v4l2_err("Failed to register video device");
+               goto err_enc_reg;
+       }
+
+       mtk_v4l2_debug(0, "encoder %d registered as /dev/video%d",
+                      dev->venc_pdata->core_id, vfd_enc->num);
+
+       return 0;
+
+err_enc_reg:
+       destroy_workqueue(dev->encode_workqueue);
+err_event_workq:
+       v4l2_m2m_release(dev->m2m_dev_enc);
+err_enc_mem_init:
+       video_unregister_device(vfd_enc);
+err_enc_alloc:
+       v4l2_device_unregister(&dev->v4l2_dev);
+err_res:
+       pm_runtime_disable(dev->pm.dev);
+err_enc_pm:
+       mtk_vcodec_fw_release(dev->fw_handler);
+       return ret;
+}
+
+static const struct mtk_vcodec_enc_pdata mt8173_avc_pdata = {
+       .chip = MTK_MT8173,
+       .capture_formats = mtk_video_formats_capture_h264,
+       .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_h264),
+       .output_formats = mtk_video_formats_output,
+       .num_output_formats = ARRAY_SIZE(mtk_video_formats_output),
+       .min_bitrate = 64,
+       .max_bitrate = 60000000,
+       .core_id = VENC_SYS,
+};
+
+static const struct mtk_vcodec_enc_pdata mt8173_vp8_pdata = {
+       .chip = MTK_MT8173,
+       .capture_formats = mtk_video_formats_capture_vp8,
+       .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_vp8),
+       .output_formats = mtk_video_formats_output,
+       .num_output_formats = ARRAY_SIZE(mtk_video_formats_output),
+       .min_bitrate = 64,
+       .max_bitrate = 9000000,
+       .core_id = VENC_LT_SYS,
+};
+
+static const struct mtk_vcodec_enc_pdata mt8183_pdata = {
+       .chip = MTK_MT8183,
+       .uses_ext = true,
+       .capture_formats = mtk_video_formats_capture_h264,
+       .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_h264),
+       .output_formats = mtk_video_formats_output,
+       .num_output_formats = ARRAY_SIZE(mtk_video_formats_output),
+       .min_bitrate = 64,
+       .max_bitrate = 40000000,
+       .core_id = VENC_SYS,
+};
+
+static const struct mtk_vcodec_enc_pdata mt8192_pdata = {
+       .chip = MTK_MT8192,
+       .uses_ext = true,
+       .capture_formats = mtk_video_formats_capture_h264,
+       .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_h264),
+       .output_formats = mtk_video_formats_output,
+       .num_output_formats = ARRAY_SIZE(mtk_video_formats_output),
+       .min_bitrate = 64,
+       .max_bitrate = 100000000,
+       .core_id = VENC_SYS,
+};
+
+static const struct mtk_vcodec_enc_pdata mt8195_pdata = {
+       .chip = MTK_MT8195,
+       .uses_ext = true,
+       .capture_formats = mtk_video_formats_capture_h264,
+       .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_h264),
+       .output_formats = mtk_video_formats_output,
+       .num_output_formats = ARRAY_SIZE(mtk_video_formats_output),
+       .min_bitrate = 64,
+       .max_bitrate = 100000000,
+       .core_id = VENC_SYS,
+};
+
+static const struct of_device_id mtk_vcodec_enc_match[] = {
+       {.compatible = "mediatek,mt8173-vcodec-enc",
+                       .data = &mt8173_avc_pdata},
+       {.compatible = "mediatek,mt8173-vcodec-enc-vp8",
+                       .data = &mt8173_vp8_pdata},
+       {.compatible = "mediatek,mt8183-vcodec-enc", .data = &mt8183_pdata},
+       {.compatible = "mediatek,mt8192-vcodec-enc", .data = &mt8192_pdata},
+       {.compatible = "mediatek,mt8195-vcodec-enc", .data = &mt8195_pdata},
+       {},
+};
+MODULE_DEVICE_TABLE(of, mtk_vcodec_enc_match);
+
+static int mtk_vcodec_enc_remove(struct platform_device *pdev)
+{
+       struct mtk_vcodec_dev *dev = platform_get_drvdata(pdev);
+
+       mtk_v4l2_debug_enter();
+       destroy_workqueue(dev->encode_workqueue);
+       if (dev->m2m_dev_enc)
+               v4l2_m2m_release(dev->m2m_dev_enc);
+
+       if (dev->vfd_enc)
+               video_unregister_device(dev->vfd_enc);
+
+       v4l2_device_unregister(&dev->v4l2_dev);
+       pm_runtime_disable(dev->pm.dev);
+       mtk_vcodec_fw_release(dev->fw_handler);
+       return 0;
+}
+
+static struct platform_driver mtk_vcodec_enc_driver = {
+       .probe  = mtk_vcodec_probe,
+       .remove = mtk_vcodec_enc_remove,
+       .driver = {
+               .name   = MTK_VCODEC_ENC_NAME,
+               .of_match_table = mtk_vcodec_enc_match,
+       },
+};
+
+module_platform_driver(mtk_vcodec_enc_driver);
+
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Mediatek video codec V4L2 encoder driver");
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_enc_pm.c b/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_enc_pm.c
new file mode 100644 (file)
index 0000000..7055954
--- /dev/null
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+* Copyright (c) 2016 MediaTek Inc.
+* Author: Tiffany Lin <tiffany.lin@mediatek.com>
+*/
+
+#include <linux/clk.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/pm_runtime.h>
+
+#include "mtk_vcodec_enc_pm.h"
+#include "mtk_vcodec_util.h"
+
+int mtk_vcodec_init_enc_clk(struct mtk_vcodec_dev *mtkdev)
+{
+       struct platform_device *pdev;
+       struct mtk_vcodec_pm *pm;
+       struct mtk_vcodec_clk *enc_clk;
+       struct mtk_vcodec_clk_info *clk_info;
+       int ret, i;
+
+       pdev = mtkdev->plat_dev;
+       pm = &mtkdev->pm;
+       memset(pm, 0, sizeof(struct mtk_vcodec_pm));
+       pm->dev = &pdev->dev;
+       enc_clk = &pm->venc_clk;
+
+       enc_clk->clk_num = of_property_count_strings(pdev->dev.of_node,
+               "clock-names");
+       if (enc_clk->clk_num > 0) {
+               enc_clk->clk_info = devm_kcalloc(&pdev->dev,
+                       enc_clk->clk_num, sizeof(*clk_info),
+                       GFP_KERNEL);
+               if (!enc_clk->clk_info)
+                       return -ENOMEM;
+       } else {
+               mtk_v4l2_err("Failed to get venc clock count");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < enc_clk->clk_num; i++) {
+               clk_info = &enc_clk->clk_info[i];
+               ret = of_property_read_string_index(pdev->dev.of_node,
+                       "clock-names", i, &clk_info->clk_name);
+               if (ret) {
+                       mtk_v4l2_err("venc failed to get clk name %d", i);
+                       return ret;
+               }
+               clk_info->vcodec_clk = devm_clk_get(&pdev->dev,
+                       clk_info->clk_name);
+               if (IS_ERR(clk_info->vcodec_clk)) {
+                       mtk_v4l2_err("venc devm_clk_get (%d)%s fail", i,
+                               clk_info->clk_name);
+                       return PTR_ERR(clk_info->vcodec_clk);
+               }
+       }
+
+       return 0;
+}
+
+void mtk_vcodec_enc_clock_on(struct mtk_vcodec_pm *pm)
+{
+       struct mtk_vcodec_clk *enc_clk = &pm->venc_clk;
+       int ret, i = 0;
+
+       for (i = 0; i < enc_clk->clk_num; i++) {
+               ret = clk_prepare_enable(enc_clk->clk_info[i].vcodec_clk);
+               if (ret) {
+                       mtk_v4l2_err("venc clk_prepare_enable %d %s fail %d", i,
+                               enc_clk->clk_info[i].clk_name, ret);
+                       goto clkerr;
+               }
+       }
+
+       return;
+
+clkerr:
+       for (i -= 1; i >= 0; i--)
+               clk_disable_unprepare(enc_clk->clk_info[i].vcodec_clk);
+}
+
+void mtk_vcodec_enc_clock_off(struct mtk_vcodec_pm *pm)
+{
+       struct mtk_vcodec_clk *enc_clk = &pm->venc_clk;
+       int i = 0;
+
+       for (i = enc_clk->clk_num - 1; i >= 0; i--)
+               clk_disable_unprepare(enc_clk->clk_info[i].vcodec_clk);
+}
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_enc_pm.h b/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_enc_pm.h
new file mode 100644 (file)
index 0000000..bc455ce
--- /dev/null
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+* Copyright (c) 2016 MediaTek Inc.
+* Author: Tiffany Lin <tiffany.lin@mediatek.com>
+*/
+
+#ifndef _MTK_VCODEC_ENC_PM_H_
+#define _MTK_VCODEC_ENC_PM_H_
+
+#include "mtk_vcodec_drv.h"
+
+int mtk_vcodec_init_enc_clk(struct mtk_vcodec_dev *dev);
+
+void mtk_vcodec_enc_clock_on(struct mtk_vcodec_pm *pm);
+void mtk_vcodec_enc_clock_off(struct mtk_vcodec_pm *pm);
+
+#endif /* _MTK_VCODEC_ENC_PM_H_ */
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_fw.c b/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_fw.c
new file mode 100644 (file)
index 0000000..94b39ae
--- /dev/null
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "mtk_vcodec_fw.h"
+#include "mtk_vcodec_fw_priv.h"
+#include "mtk_vcodec_util.h"
+#include "mtk_vcodec_drv.h"
+
+struct mtk_vcodec_fw *mtk_vcodec_fw_select(struct mtk_vcodec_dev *dev,
+                                          enum mtk_vcodec_fw_type type,
+                                          enum mtk_vcodec_fw_use fw_use)
+{
+       switch (type) {
+       case VPU:
+               return mtk_vcodec_fw_vpu_init(dev, fw_use);
+       case SCP:
+               return mtk_vcodec_fw_scp_init(dev);
+       default:
+               mtk_v4l2_err("invalid vcodec fw type");
+               return ERR_PTR(-EINVAL);
+       }
+}
+EXPORT_SYMBOL_GPL(mtk_vcodec_fw_select);
+
+void mtk_vcodec_fw_release(struct mtk_vcodec_fw *fw)
+{
+       fw->ops->release(fw);
+}
+EXPORT_SYMBOL_GPL(mtk_vcodec_fw_release);
+
+int mtk_vcodec_fw_load_firmware(struct mtk_vcodec_fw *fw)
+{
+       return fw->ops->load_firmware(fw);
+}
+EXPORT_SYMBOL_GPL(mtk_vcodec_fw_load_firmware);
+
+unsigned int mtk_vcodec_fw_get_vdec_capa(struct mtk_vcodec_fw *fw)
+{
+       return fw->ops->get_vdec_capa(fw);
+}
+EXPORT_SYMBOL_GPL(mtk_vcodec_fw_get_vdec_capa);
+
+unsigned int mtk_vcodec_fw_get_venc_capa(struct mtk_vcodec_fw *fw)
+{
+       return fw->ops->get_venc_capa(fw);
+}
+EXPORT_SYMBOL_GPL(mtk_vcodec_fw_get_venc_capa);
+
+void *mtk_vcodec_fw_map_dm_addr(struct mtk_vcodec_fw *fw, u32 mem_addr)
+{
+       return fw->ops->map_dm_addr(fw, mem_addr);
+}
+EXPORT_SYMBOL_GPL(mtk_vcodec_fw_map_dm_addr);
+
+int mtk_vcodec_fw_ipi_register(struct mtk_vcodec_fw *fw, int id,
+                              mtk_vcodec_ipi_handler handler,
+                              const char *name, void *priv)
+{
+       return fw->ops->ipi_register(fw, id, handler, name, priv);
+}
+EXPORT_SYMBOL_GPL(mtk_vcodec_fw_ipi_register);
+
+int mtk_vcodec_fw_ipi_send(struct mtk_vcodec_fw *fw, int id, void *buf,
+                          unsigned int len, unsigned int wait)
+{
+       return fw->ops->ipi_send(fw, id, buf, len, wait);
+}
+EXPORT_SYMBOL_GPL(mtk_vcodec_fw_ipi_send);
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_fw.h b/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_fw.h
new file mode 100644 (file)
index 0000000..539bb62
--- /dev/null
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _MTK_VCODEC_FW_H_
+#define _MTK_VCODEC_FW_H_
+
+#include <linux/remoteproc.h>
+#include <linux/remoteproc/mtk_scp.h>
+
+#include "../mtk-vpu/mtk_vpu.h"
+
+struct mtk_vcodec_dev;
+
+enum mtk_vcodec_fw_type {
+       VPU,
+       SCP,
+};
+
+enum mtk_vcodec_fw_use {
+       DECODER,
+       ENCODER,
+};
+
+struct mtk_vcodec_fw;
+
+typedef void (*mtk_vcodec_ipi_handler) (void *data,
+       unsigned int len, void *priv);
+
+struct mtk_vcodec_fw *mtk_vcodec_fw_select(struct mtk_vcodec_dev *dev,
+                                          enum mtk_vcodec_fw_type type,
+                                          enum mtk_vcodec_fw_use fw_use);
+void mtk_vcodec_fw_release(struct mtk_vcodec_fw *fw);
+
+int mtk_vcodec_fw_load_firmware(struct mtk_vcodec_fw *fw);
+unsigned int mtk_vcodec_fw_get_vdec_capa(struct mtk_vcodec_fw *fw);
+unsigned int mtk_vcodec_fw_get_venc_capa(struct mtk_vcodec_fw *fw);
+void *mtk_vcodec_fw_map_dm_addr(struct mtk_vcodec_fw *fw, u32 mem_addr);
+int mtk_vcodec_fw_ipi_register(struct mtk_vcodec_fw *fw, int id,
+                              mtk_vcodec_ipi_handler handler,
+                              const char *name, void *priv);
+int mtk_vcodec_fw_ipi_send(struct mtk_vcodec_fw *fw, int id,
+                          void *buf, unsigned int len, unsigned int wait);
+
+#endif /* _MTK_VCODEC_FW_H_ */
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_fw_priv.h b/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_fw_priv.h
new file mode 100644 (file)
index 0000000..b41e661
--- /dev/null
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _MTK_VCODEC_FW_PRIV_H_
+#define _MTK_VCODEC_FW_PRIV_H_
+
+#include "mtk_vcodec_fw.h"
+
+struct mtk_vcodec_dev;
+
+struct mtk_vcodec_fw {
+       enum mtk_vcodec_fw_type type;
+       const struct mtk_vcodec_fw_ops *ops;
+       struct platform_device *pdev;
+       struct mtk_scp *scp;
+};
+
+struct mtk_vcodec_fw_ops {
+       int (*load_firmware)(struct mtk_vcodec_fw *fw);
+       unsigned int (*get_vdec_capa)(struct mtk_vcodec_fw *fw);
+       unsigned int (*get_venc_capa)(struct mtk_vcodec_fw *fw);
+       void *(*map_dm_addr)(struct mtk_vcodec_fw *fw, u32 dtcm_dmem_addr);
+       int (*ipi_register)(struct mtk_vcodec_fw *fw, int id,
+                           mtk_vcodec_ipi_handler handler, const char *name,
+                           void *priv);
+       int (*ipi_send)(struct mtk_vcodec_fw *fw, int id, void *buf,
+                       unsigned int len, unsigned int wait);
+       void (*release)(struct mtk_vcodec_fw *fw);
+};
+
+#if IS_ENABLED(CONFIG_VIDEO_MEDIATEK_VCODEC_VPU)
+struct mtk_vcodec_fw *mtk_vcodec_fw_vpu_init(struct mtk_vcodec_dev *dev,
+                                            enum mtk_vcodec_fw_use fw_use);
+#else
+static inline struct mtk_vcodec_fw *
+mtk_vcodec_fw_vpu_init(struct mtk_vcodec_dev *dev,
+                      enum mtk_vcodec_fw_use fw_use)
+{
+       return ERR_PTR(-ENODEV);
+}
+#endif /* CONFIG_VIDEO_MEDIATEK_VCODEC_VPU */
+
+#if IS_ENABLED(CONFIG_VIDEO_MEDIATEK_VCODEC_SCP)
+struct mtk_vcodec_fw *mtk_vcodec_fw_scp_init(struct mtk_vcodec_dev *dev);
+#else
+static inline struct mtk_vcodec_fw *
+mtk_vcodec_fw_scp_init(struct mtk_vcodec_dev *dev)
+{
+       return ERR_PTR(-ENODEV);
+}
+#endif /* CONFIG_VIDEO_MEDIATEK_VCODEC_SCP */
+
+#endif /* _MTK_VCODEC_FW_PRIV_H_ */
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_fw_scp.c b/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_fw_scp.c
new file mode 100644 (file)
index 0000000..d8e66b6
--- /dev/null
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "mtk_vcodec_fw_priv.h"
+#include "mtk_vcodec_util.h"
+#include "mtk_vcodec_drv.h"
+
+static int mtk_vcodec_scp_load_firmware(struct mtk_vcodec_fw *fw)
+{
+       return rproc_boot(scp_get_rproc(fw->scp));
+}
+
+static unsigned int mtk_vcodec_scp_get_vdec_capa(struct mtk_vcodec_fw *fw)
+{
+       return scp_get_vdec_hw_capa(fw->scp);
+}
+
+static unsigned int mtk_vcodec_scp_get_venc_capa(struct mtk_vcodec_fw *fw)
+{
+       return scp_get_venc_hw_capa(fw->scp);
+}
+
+static void *mtk_vcodec_vpu_scp_dm_addr(struct mtk_vcodec_fw *fw,
+                                       u32 dtcm_dmem_addr)
+{
+       return scp_mapping_dm_addr(fw->scp, dtcm_dmem_addr);
+}
+
+static int mtk_vcodec_scp_set_ipi_register(struct mtk_vcodec_fw *fw, int id,
+                                          mtk_vcodec_ipi_handler handler,
+                                          const char *name, void *priv)
+{
+       return scp_ipi_register(fw->scp, id, handler, priv);
+}
+
+static int mtk_vcodec_scp_ipi_send(struct mtk_vcodec_fw *fw, int id, void *buf,
+                                  unsigned int len, unsigned int wait)
+{
+       return scp_ipi_send(fw->scp, id, buf, len, wait);
+}
+
+static void mtk_vcodec_scp_release(struct mtk_vcodec_fw *fw)
+{
+       scp_put(fw->scp);
+}
+
+static const struct mtk_vcodec_fw_ops mtk_vcodec_rproc_msg = {
+       .load_firmware = mtk_vcodec_scp_load_firmware,
+       .get_vdec_capa = mtk_vcodec_scp_get_vdec_capa,
+       .get_venc_capa = mtk_vcodec_scp_get_venc_capa,
+       .map_dm_addr = mtk_vcodec_vpu_scp_dm_addr,
+       .ipi_register = mtk_vcodec_scp_set_ipi_register,
+       .ipi_send = mtk_vcodec_scp_ipi_send,
+       .release = mtk_vcodec_scp_release,
+};
+
+struct mtk_vcodec_fw *mtk_vcodec_fw_scp_init(struct mtk_vcodec_dev *dev)
+{
+       struct mtk_vcodec_fw *fw;
+       struct mtk_scp *scp;
+
+       scp = scp_get(dev->plat_dev);
+       if (!scp) {
+               mtk_v4l2_err("could not get vdec scp handle");
+               return ERR_PTR(-EPROBE_DEFER);
+       }
+
+       fw = devm_kzalloc(&dev->plat_dev->dev, sizeof(*fw), GFP_KERNEL);
+       fw->type = SCP;
+       fw->ops = &mtk_vcodec_rproc_msg;
+       fw->scp = scp;
+
+       return fw;
+}
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_fw_vpu.c b/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_fw_vpu.c
new file mode 100644 (file)
index 0000000..cfc7ebe
--- /dev/null
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "mtk_vcodec_fw_priv.h"
+#include "mtk_vcodec_util.h"
+#include "mtk_vcodec_drv.h"
+
+static int mtk_vcodec_vpu_load_firmware(struct mtk_vcodec_fw *fw)
+{
+       return vpu_load_firmware(fw->pdev);
+}
+
+static unsigned int mtk_vcodec_vpu_get_vdec_capa(struct mtk_vcodec_fw *fw)
+{
+       return vpu_get_vdec_hw_capa(fw->pdev);
+}
+
+static unsigned int mtk_vcodec_vpu_get_venc_capa(struct mtk_vcodec_fw *fw)
+{
+       return vpu_get_venc_hw_capa(fw->pdev);
+}
+
+static void *mtk_vcodec_vpu_map_dm_addr(struct mtk_vcodec_fw *fw,
+                                       u32 dtcm_dmem_addr)
+{
+       return vpu_mapping_dm_addr(fw->pdev, dtcm_dmem_addr);
+}
+
+static int mtk_vcodec_vpu_set_ipi_register(struct mtk_vcodec_fw *fw, int id,
+                                          mtk_vcodec_ipi_handler handler,
+                                          const char *name, void *priv)
+{
+       /*
+        * The handler we receive takes a void * as its first argument. We
+        * cannot change this because it needs to be passed down to the rproc
+        * subsystem when SCP is used. VPU takes a const argument, which is
+        * more constrained, so the conversion below is safe.
+        */
+       ipi_handler_t handler_const = (ipi_handler_t)handler;
+
+       return vpu_ipi_register(fw->pdev, id, handler_const, name, priv);
+}
+
+static int mtk_vcodec_vpu_ipi_send(struct mtk_vcodec_fw *fw, int id, void *buf,
+                                  unsigned int len, unsigned int wait)
+{
+       return vpu_ipi_send(fw->pdev, id, buf, len);
+}
+
+static void mtk_vcodec_vpu_release(struct mtk_vcodec_fw *fw)
+{
+       put_device(&fw->pdev->dev);
+}
+
+static void mtk_vcodec_vpu_reset_handler(void *priv)
+{
+       struct mtk_vcodec_dev *dev = priv;
+       struct mtk_vcodec_ctx *ctx;
+
+       mtk_v4l2_err("Watchdog timeout!!");
+
+       mutex_lock(&dev->dev_mutex);
+       list_for_each_entry(ctx, &dev->ctx_list, list) {
+               ctx->state = MTK_STATE_ABORT;
+               mtk_v4l2_debug(0, "[%d] Change to state MTK_STATE_ABORT",
+                              ctx->id);
+       }
+       mutex_unlock(&dev->dev_mutex);
+}
+
+static const struct mtk_vcodec_fw_ops mtk_vcodec_vpu_msg = {
+       .load_firmware = mtk_vcodec_vpu_load_firmware,
+       .get_vdec_capa = mtk_vcodec_vpu_get_vdec_capa,
+       .get_venc_capa = mtk_vcodec_vpu_get_venc_capa,
+       .map_dm_addr = mtk_vcodec_vpu_map_dm_addr,
+       .ipi_register = mtk_vcodec_vpu_set_ipi_register,
+       .ipi_send = mtk_vcodec_vpu_ipi_send,
+       .release = mtk_vcodec_vpu_release,
+};
+
+struct mtk_vcodec_fw *mtk_vcodec_fw_vpu_init(struct mtk_vcodec_dev *dev,
+                                            enum mtk_vcodec_fw_use fw_use)
+{
+       struct platform_device *fw_pdev;
+       struct mtk_vcodec_fw *fw;
+       enum rst_id rst_id;
+
+       switch (fw_use) {
+       case ENCODER:
+               rst_id = VPU_RST_ENC;
+               break;
+       case DECODER:
+       default:
+               rst_id = VPU_RST_DEC;
+               break;
+       }
+
+       fw_pdev = vpu_get_plat_device(dev->plat_dev);
+       if (!fw_pdev) {
+               mtk_v4l2_err("firmware device is not ready");
+               return ERR_PTR(-EINVAL);
+       }
+       vpu_wdt_reg_handler(fw_pdev, mtk_vcodec_vpu_reset_handler, dev, rst_id);
+
+       fw = devm_kzalloc(&dev->plat_dev->dev, sizeof(*fw), GFP_KERNEL);
+       if (!fw)
+               return ERR_PTR(-ENOMEM);
+       fw->type = VPU;
+       fw->ops = &mtk_vcodec_vpu_msg;
+       fw->pdev = fw_pdev;
+
+       return fw;
+}
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_intr.c b/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_intr.c
new file mode 100644 (file)
index 0000000..552b4c9
--- /dev/null
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+* Copyright (c) 2016 MediaTek Inc.
+* Author: Tiffany Lin <tiffany.lin@mediatek.com>
+*/
+
+#include <linux/errno.h>
+#include <linux/wait.h>
+
+#include "mtk_vcodec_drv.h"
+#include "mtk_vcodec_intr.h"
+#include "mtk_vcodec_util.h"
+
+int mtk_vcodec_wait_for_done_ctx(struct mtk_vcodec_ctx *ctx,
+                                int command, unsigned int timeout_ms,
+                                unsigned int hw_id)
+{
+       long timeout_jiff, ret;
+       int status = 0;
+
+       timeout_jiff = msecs_to_jiffies(timeout_ms);
+       ret = wait_event_interruptible_timeout(ctx->queue[hw_id],
+                                              ctx->int_cond[hw_id],
+                                              timeout_jiff);
+
+       if (!ret) {
+               status = -1;    /* timeout */
+               mtk_v4l2_err("[%d] cmd=%d, type=%d, dec timeout=%ums (%d %d)",
+                            ctx->id, command, ctx->type, timeout_ms,
+                            ctx->int_cond[hw_id], ctx->int_type[hw_id]);
+       } else if (-ERESTARTSYS == ret) {
+               status = -1;
+               mtk_v4l2_err("[%d] cmd=%d, type=%d, dec inter fail (%d %d)",
+                            ctx->id, command, ctx->type,
+                            ctx->int_cond[hw_id], ctx->int_type[hw_id]);
+       }
+
+       ctx->int_cond[hw_id] = 0;
+       ctx->int_type[hw_id] = 0;
+
+       return status;
+}
+EXPORT_SYMBOL(mtk_vcodec_wait_for_done_ctx);
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_intr.h b/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_intr.h
new file mode 100644 (file)
index 0000000..9681f49
--- /dev/null
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+* Copyright (c) 2016 MediaTek Inc.
+* Author: Tiffany Lin <tiffany.lin@mediatek.com>
+*/
+
+#ifndef _MTK_VCODEC_INTR_H_
+#define _MTK_VCODEC_INTR_H_
+
+#define MTK_INST_IRQ_RECEIVED          0x1
+
+struct mtk_vcodec_ctx;
+
+/* timeout is ms */
+int mtk_vcodec_wait_for_done_ctx(struct mtk_vcodec_ctx *ctx,
+                                int command, unsigned int timeout_ms,
+                                unsigned int hw_id);
+
+#endif /* _MTK_VCODEC_INTR_H_ */
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_util.c b/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_util.c
new file mode 100644 (file)
index 0000000..ace78c4
--- /dev/null
@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+* Copyright (c) 2016 MediaTek Inc.
+* Author: PC Chen <pc.chen@mediatek.com>
+*      Tiffany Lin <tiffany.lin@mediatek.com>
+*/
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+#include "mtk_vcodec_dec_hw.h"
+#include "mtk_vcodec_drv.h"
+#include "mtk_vcodec_util.h"
+
+void __iomem *mtk_vcodec_get_reg_addr(struct mtk_vcodec_ctx *data,
+                                       unsigned int reg_idx)
+{
+       struct mtk_vcodec_ctx *ctx = (struct mtk_vcodec_ctx *)data;
+
+       if (!data || reg_idx >= NUM_MAX_VCODEC_REG_BASE) {
+               mtk_v4l2_err("Invalid arguments, reg_idx=%d", reg_idx);
+               return NULL;
+       }
+       return ctx->dev->reg_base[reg_idx];
+}
+EXPORT_SYMBOL(mtk_vcodec_get_reg_addr);
+
+int mtk_vcodec_mem_alloc(struct mtk_vcodec_ctx *data,
+                       struct mtk_vcodec_mem *mem)
+{
+       unsigned long size = mem->size;
+       struct mtk_vcodec_ctx *ctx = (struct mtk_vcodec_ctx *)data;
+       struct device *dev = &ctx->dev->plat_dev->dev;
+
+       mem->va = dma_alloc_coherent(dev, size, &mem->dma_addr, GFP_KERNEL);
+       if (!mem->va) {
+               mtk_v4l2_err("%s dma_alloc size=%ld failed!", dev_name(dev),
+                            size);
+               return -ENOMEM;
+       }
+
+       mtk_v4l2_debug(3, "[%d]  - va      = %p", ctx->id, mem->va);
+       mtk_v4l2_debug(3, "[%d]  - dma     = 0x%lx", ctx->id,
+                      (unsigned long)mem->dma_addr);
+       mtk_v4l2_debug(3, "[%d]    size = 0x%lx", ctx->id, size);
+
+       return 0;
+}
+EXPORT_SYMBOL(mtk_vcodec_mem_alloc);
+
+void mtk_vcodec_mem_free(struct mtk_vcodec_ctx *data,
+                       struct mtk_vcodec_mem *mem)
+{
+       unsigned long size = mem->size;
+       struct mtk_vcodec_ctx *ctx = (struct mtk_vcodec_ctx *)data;
+       struct device *dev = &ctx->dev->plat_dev->dev;
+
+       if (!mem->va) {
+               mtk_v4l2_err("%s dma_free size=%ld failed!", dev_name(dev),
+                            size);
+               return;
+       }
+
+       mtk_v4l2_debug(3, "[%d]  - va      = %p", ctx->id, mem->va);
+       mtk_v4l2_debug(3, "[%d]  - dma     = 0x%lx", ctx->id,
+                      (unsigned long)mem->dma_addr);
+       mtk_v4l2_debug(3, "[%d]    size = 0x%lx", ctx->id, size);
+
+       dma_free_coherent(dev, size, mem->va, mem->dma_addr);
+       mem->va = NULL;
+       mem->dma_addr = 0;
+       mem->size = 0;
+}
+EXPORT_SYMBOL(mtk_vcodec_mem_free);
+
+void *mtk_vcodec_get_hw_dev(struct mtk_vcodec_dev *dev, int hw_idx)
+{
+       if (hw_idx >= MTK_VDEC_HW_MAX || hw_idx < 0 || !dev->subdev_dev[hw_idx]) {
+               mtk_v4l2_err("hw idx is out of range:%d", hw_idx);
+               return NULL;
+       }
+
+       return dev->subdev_dev[hw_idx];
+}
+EXPORT_SYMBOL(mtk_vcodec_get_hw_dev);
+
+void mtk_vcodec_set_curr_ctx(struct mtk_vcodec_dev *vdec_dev,
+                            struct mtk_vcodec_ctx *ctx, int hw_idx)
+{
+       unsigned long flags;
+       struct mtk_vdec_hw_dev *subdev_dev;
+
+       spin_lock_irqsave(&vdec_dev->irqlock, flags);
+       if (vdec_dev->vdec_pdata->is_subdev_supported) {
+               subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx);
+               if (!subdev_dev) {
+                       mtk_v4l2_err("Failed to get hw dev");
+                       spin_unlock_irqrestore(&vdec_dev->irqlock, flags);
+                       return;
+               }
+               subdev_dev->curr_ctx = ctx;
+       } else {
+               vdec_dev->curr_ctx = ctx;
+       }
+       spin_unlock_irqrestore(&vdec_dev->irqlock, flags);
+}
+EXPORT_SYMBOL(mtk_vcodec_set_curr_ctx);
+
+struct mtk_vcodec_ctx *mtk_vcodec_get_curr_ctx(struct mtk_vcodec_dev *vdec_dev,
+                                              unsigned int hw_idx)
+{
+       unsigned long flags;
+       struct mtk_vcodec_ctx *ctx;
+       struct mtk_vdec_hw_dev *subdev_dev;
+
+       spin_lock_irqsave(&vdec_dev->irqlock, flags);
+       if (vdec_dev->vdec_pdata->is_subdev_supported) {
+               subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx);
+               if (!subdev_dev) {
+                       mtk_v4l2_err("Failed to get hw dev");
+                       spin_unlock_irqrestore(&vdec_dev->irqlock, flags);
+                       return NULL;
+               }
+               ctx = subdev_dev->curr_ctx;
+       } else {
+               ctx = vdec_dev->curr_ctx;
+       }
+       spin_unlock_irqrestore(&vdec_dev->irqlock, flags);
+       return ctx;
+}
+EXPORT_SYMBOL(mtk_vcodec_get_curr_ctx);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Mediatek video codec driver");
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_util.h b/drivers/media/platform/mediatek/mtk-vcodec/mtk_vcodec_util.h
new file mode 100644 (file)
index 0000000..7195662
--- /dev/null
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+* Copyright (c) 2016 MediaTek Inc.
+* Author: PC Chen <pc.chen@mediatek.com>
+*      Tiffany Lin <tiffany.lin@mediatek.com>
+*/
+
+#ifndef _MTK_VCODEC_UTIL_H_
+#define _MTK_VCODEC_UTIL_H_
+
+#include <linux/types.h>
+#include <linux/dma-direction.h>
+
+struct mtk_vcodec_mem {
+       size_t size;
+       void *va;
+       dma_addr_t dma_addr;
+};
+
+struct mtk_vcodec_fb {
+       size_t size;
+       dma_addr_t dma_addr;
+};
+
+struct mtk_vcodec_ctx;
+struct mtk_vcodec_dev;
+
+#undef pr_fmt
+#define pr_fmt(fmt) "%s(),%d: " fmt, __func__, __LINE__
+
+#define mtk_v4l2_err(fmt, args...)                \
+       pr_err("[MTK_V4L2][ERROR] " fmt "\n", ##args)
+
+#define mtk_vcodec_err(h, fmt, args...)                                \
+       pr_err("[MTK_VCODEC][ERROR][%d]: " fmt "\n",            \
+              ((struct mtk_vcodec_ctx *)(h)->ctx)->id, ##args)
+
+
+#define mtk_v4l2_debug(level, fmt, args...) pr_debug(fmt, ##args)
+
+#define mtk_v4l2_debug_enter()  mtk_v4l2_debug(3, "+")
+#define mtk_v4l2_debug_leave()  mtk_v4l2_debug(3, "-")
+
+#define mtk_vcodec_debug(h, fmt, args...)                      \
+       pr_debug("[MTK_VCODEC][%d]: " fmt "\n",                 \
+               ((struct mtk_vcodec_ctx *)(h)->ctx)->id, ##args)
+
+#define mtk_vcodec_debug_enter(h)  mtk_vcodec_debug(h, "+")
+#define mtk_vcodec_debug_leave(h)  mtk_vcodec_debug(h, "-")
+
+void __iomem *mtk_vcodec_get_reg_addr(struct mtk_vcodec_ctx *data,
+                               unsigned int reg_idx);
+int mtk_vcodec_mem_alloc(struct mtk_vcodec_ctx *data,
+                               struct mtk_vcodec_mem *mem);
+void mtk_vcodec_mem_free(struct mtk_vcodec_ctx *data,
+                               struct mtk_vcodec_mem *mem);
+void mtk_vcodec_set_curr_ctx(struct mtk_vcodec_dev *vdec_dev,
+                            struct mtk_vcodec_ctx *ctx, int hw_idx);
+struct mtk_vcodec_ctx *mtk_vcodec_get_curr_ctx(struct mtk_vcodec_dev *vdec_dev,
+                                              unsigned int hw_idx);
+void *mtk_vcodec_get_hw_dev(struct mtk_vcodec_dev *dev, int hw_idx);
+
+#endif /* _MTK_VCODEC_UTIL_H_ */
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/vdec/vdec_h264_if.c b/drivers/media/platform/mediatek/mtk-vcodec/vdec/vdec_h264_if.c
new file mode 100644 (file)
index 0000000..481655b
--- /dev/null
@@ -0,0 +1,503 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: PC Chen <pc.chen@mediatek.com>
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include "../vdec_drv_if.h"
+#include "../mtk_vcodec_util.h"
+#include "../mtk_vcodec_dec.h"
+#include "../mtk_vcodec_intr.h"
+#include "../vdec_vpu_if.h"
+#include "../vdec_drv_base.h"
+
+#define NAL_NON_IDR_SLICE                      0x01
+#define NAL_IDR_SLICE                          0x05
+#define NAL_H264_PPS                           0x08
+#define NAL_TYPE(value)                                ((value) & 0x1F)
+
+#define BUF_PREDICTION_SZ                      (32 * 1024)
+
+#define MB_UNIT_LEN                            16
+
+/* motion vector size (bytes) for every macro block */
+#define HW_MB_STORE_SZ                         64
+
+#define H264_MAX_FB_NUM                                17
+#define HDR_PARSING_BUF_SZ                     1024
+
+#define DEC_ERR_RET(ret)                       ((ret) >> 16)
+#define H264_ERR_NOT_VALID                     3
+
+/**
+ * struct h264_fb - h264 decode frame buffer information
+ * @vdec_fb_va  : virtual address of struct vdec_fb
+ * @y_fb_dma    : dma address of Y frame buffer (luma)
+ * @c_fb_dma    : dma address of C frame buffer (chroma)
+ * @poc         : picture order count of frame buffer
+ * @reserved    : for 8 bytes alignment
+ */
+struct h264_fb {
+       uint64_t vdec_fb_va;
+       uint64_t y_fb_dma;
+       uint64_t c_fb_dma;
+       int32_t poc;
+       uint32_t reserved;
+};
+
+/**
+ * struct h264_ring_fb_list - ring frame buffer list
+ * @fb_list   : frame buffer array
+ * @read_idx  : read index
+ * @write_idx : write index
+ * @count     : buffer count in list
+ * @reserved  : for 8 bytes alignment
+ */
+struct h264_ring_fb_list {
+       struct h264_fb fb_list[H264_MAX_FB_NUM];
+       unsigned int read_idx;
+       unsigned int write_idx;
+       unsigned int count;
+       unsigned int reserved;
+};
+
+/**
+ * struct vdec_h264_dec_info - decode information
+ * @dpb_sz             : decoding picture buffer size
+ * @resolution_changed  : resolution change happen
+ * @realloc_mv_buf     : flag to notify driver to re-allocate mv buffer
+ * @reserved           : for 8 bytes alignment
+ * @bs_dma             : Input bit-stream buffer dma address
+ * @y_fb_dma           : Y frame buffer dma address
+ * @c_fb_dma           : C frame buffer dma address
+ * @vdec_fb_va         : VDEC frame buffer struct virtual address
+ */
+struct vdec_h264_dec_info {
+       uint32_t dpb_sz;
+       uint32_t resolution_changed;
+       uint32_t realloc_mv_buf;
+       uint32_t reserved;
+       uint64_t bs_dma;
+       uint64_t y_fb_dma;
+       uint64_t c_fb_dma;
+       uint64_t vdec_fb_va;
+};
+
+/**
+ * struct vdec_h264_vsi - shared memory for decode information exchange
+ *                        between VPU and Host.
+ *                        The memory is allocated by VPU then mapping to Host
+ *                        in vpu_dec_init() and freed in vpu_dec_deinit()
+ *                        by VPU.
+ *                        AP-W/R : AP is writer/reader on this item
+ *                        VPU-W/R: VPU is write/reader on this item
+ * @hdr_buf      : Header parsing buffer (AP-W, VPU-R)
+ * @pred_buf_dma : HW working predication buffer dma address (AP-W, VPU-R)
+ * @mv_buf_dma   : HW working motion vector buffer dma address (AP-W, VPU-R)
+ * @list_free    : free frame buffer ring list (AP-W/R, VPU-W)
+ * @list_disp    : display frame buffer ring list (AP-R, VPU-W)
+ * @dec          : decode information (AP-R, VPU-W)
+ * @pic          : picture information (AP-R, VPU-W)
+ * @crop         : crop information (AP-R, VPU-W)
+ */
+struct vdec_h264_vsi {
+       unsigned char hdr_buf[HDR_PARSING_BUF_SZ];
+       uint64_t pred_buf_dma;
+       uint64_t mv_buf_dma[H264_MAX_FB_NUM];
+       struct h264_ring_fb_list list_free;
+       struct h264_ring_fb_list list_disp;
+       struct vdec_h264_dec_info dec;
+       struct vdec_pic_info pic;
+       struct v4l2_rect crop;
+};
+
+/**
+ * struct vdec_h264_inst - h264 decoder instance
+ * @num_nalu : how many nalus be decoded
+ * @ctx      : point to mtk_vcodec_ctx
+ * @pred_buf : HW working predication buffer
+ * @mv_buf   : HW working motion vector buffer
+ * @vpu      : VPU instance
+ * @vsi      : VPU shared information
+ */
+struct vdec_h264_inst {
+       unsigned int num_nalu;
+       struct mtk_vcodec_ctx *ctx;
+       struct mtk_vcodec_mem pred_buf;
+       struct mtk_vcodec_mem mv_buf[H264_MAX_FB_NUM];
+       struct vdec_vpu_inst vpu;
+       struct vdec_h264_vsi *vsi;
+};
+
+static unsigned int get_mv_buf_size(unsigned int width, unsigned int height)
+{
+       return HW_MB_STORE_SZ * (width/MB_UNIT_LEN) * (height/MB_UNIT_LEN);
+}
+
+static int allocate_predication_buf(struct vdec_h264_inst *inst)
+{
+       int err = 0;
+
+       inst->pred_buf.size = BUF_PREDICTION_SZ;
+       err = mtk_vcodec_mem_alloc(inst->ctx, &inst->pred_buf);
+       if (err) {
+               mtk_vcodec_err(inst, "failed to allocate ppl buf");
+               return err;
+       }
+
+       inst->vsi->pred_buf_dma = inst->pred_buf.dma_addr;
+       return 0;
+}
+
+static void free_predication_buf(struct vdec_h264_inst *inst)
+{
+       struct mtk_vcodec_mem *mem = NULL;
+
+       mtk_vcodec_debug_enter(inst);
+
+       inst->vsi->pred_buf_dma = 0;
+       mem = &inst->pred_buf;
+       if (mem->va)
+               mtk_vcodec_mem_free(inst->ctx, mem);
+}
+
+static int alloc_mv_buf(struct vdec_h264_inst *inst, struct vdec_pic_info *pic)
+{
+       int i;
+       int err;
+       struct mtk_vcodec_mem *mem = NULL;
+       unsigned int buf_sz = get_mv_buf_size(pic->buf_w, pic->buf_h);
+
+       for (i = 0; i < H264_MAX_FB_NUM; i++) {
+               mem = &inst->mv_buf[i];
+               if (mem->va)
+                       mtk_vcodec_mem_free(inst->ctx, mem);
+               mem->size = buf_sz;
+               err = mtk_vcodec_mem_alloc(inst->ctx, mem);
+               if (err) {
+                       mtk_vcodec_err(inst, "failed to allocate mv buf");
+                       return err;
+               }
+               inst->vsi->mv_buf_dma[i] = mem->dma_addr;
+       }
+
+       return 0;
+}
+
+static void free_mv_buf(struct vdec_h264_inst *inst)
+{
+       int i;
+       struct mtk_vcodec_mem *mem = NULL;
+
+       for (i = 0; i < H264_MAX_FB_NUM; i++) {
+               inst->vsi->mv_buf_dma[i] = 0;
+               mem = &inst->mv_buf[i];
+               if (mem->va)
+                       mtk_vcodec_mem_free(inst->ctx, mem);
+       }
+}
+
+static int check_list_validity(struct vdec_h264_inst *inst, bool disp_list)
+{
+       struct h264_ring_fb_list *list;
+
+       list = disp_list ? &inst->vsi->list_disp : &inst->vsi->list_free;
+
+       if (list->count > H264_MAX_FB_NUM ||
+           list->read_idx >= H264_MAX_FB_NUM ||
+           list->write_idx >= H264_MAX_FB_NUM) {
+               mtk_vcodec_err(inst, "%s list err: cnt=%d r_idx=%d w_idx=%d",
+                              disp_list ? "disp" : "free", list->count,
+                              list->read_idx, list->write_idx);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void put_fb_to_free(struct vdec_h264_inst *inst, struct vdec_fb *fb)
+{
+       struct h264_ring_fb_list *list;
+
+       if (fb) {
+               if (check_list_validity(inst, false))
+                       return;
+
+               list = &inst->vsi->list_free;
+               if (list->count == H264_MAX_FB_NUM) {
+                       mtk_vcodec_err(inst, "[FB] put fb free_list full");
+                       return;
+               }
+
+               mtk_vcodec_debug(inst, "[FB] put fb into free_list @(%p, %llx)",
+                                fb->base_y.va, (u64)fb->base_y.dma_addr);
+
+               list->fb_list[list->write_idx].vdec_fb_va = (u64)(uintptr_t)fb;
+               list->write_idx = (list->write_idx == H264_MAX_FB_NUM - 1) ?
+                                 0 : list->write_idx + 1;
+               list->count++;
+       }
+}
+
+static void get_pic_info(struct vdec_h264_inst *inst,
+                        struct vdec_pic_info *pic)
+{
+       *pic = inst->vsi->pic;
+       mtk_vcodec_debug(inst, "pic(%d, %d), buf(%d, %d)",
+                        pic->pic_w, pic->pic_h, pic->buf_w, pic->buf_h);
+       mtk_vcodec_debug(inst, "fb size: Y(%d), C(%d)",
+                        pic->fb_sz[0], pic->fb_sz[1]);
+}
+
+static void get_crop_info(struct vdec_h264_inst *inst, struct v4l2_rect *cr)
+{
+       cr->left = inst->vsi->crop.left;
+       cr->top = inst->vsi->crop.top;
+       cr->width = inst->vsi->crop.width;
+       cr->height = inst->vsi->crop.height;
+
+       mtk_vcodec_debug(inst, "l=%d, t=%d, w=%d, h=%d",
+                        cr->left, cr->top, cr->width, cr->height);
+}
+
+static void get_dpb_size(struct vdec_h264_inst *inst, unsigned int *dpb_sz)
+{
+       *dpb_sz = inst->vsi->dec.dpb_sz;
+       mtk_vcodec_debug(inst, "sz=%d", *dpb_sz);
+}
+
+static int vdec_h264_init(struct mtk_vcodec_ctx *ctx)
+{
+       struct vdec_h264_inst *inst = NULL;
+       int err;
+
+       inst = kzalloc(sizeof(*inst), GFP_KERNEL);
+       if (!inst)
+               return -ENOMEM;
+
+       inst->ctx = ctx;
+
+       inst->vpu.id = IPI_VDEC_H264;
+       inst->vpu.ctx = ctx;
+
+       err = vpu_dec_init(&inst->vpu);
+       if (err) {
+               mtk_vcodec_err(inst, "vdec_h264 init err=%d", err);
+               goto error_free_inst;
+       }
+
+       inst->vsi = (struct vdec_h264_vsi *)inst->vpu.vsi;
+       err = allocate_predication_buf(inst);
+       if (err)
+               goto error_deinit;
+
+       mtk_vcodec_debug(inst, "H264 Instance >> %p", inst);
+
+       ctx->drv_handle = inst;
+       return 0;
+
+error_deinit:
+       vpu_dec_deinit(&inst->vpu);
+
+error_free_inst:
+       kfree(inst);
+       return err;
+}
+
+static void vdec_h264_deinit(void *h_vdec)
+{
+       struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec;
+
+       mtk_vcodec_debug_enter(inst);
+
+       vpu_dec_deinit(&inst->vpu);
+       free_predication_buf(inst);
+       free_mv_buf(inst);
+
+       kfree(inst);
+}
+
+static int find_start_code(unsigned char *data, unsigned int data_sz)
+{
+       if (data_sz > 3 && data[0] == 0 && data[1] == 0 && data[2] == 1)
+               return 3;
+
+       if (data_sz > 4 && data[0] == 0 && data[1] == 0 && data[2] == 0 &&
+           data[3] == 1)
+               return 4;
+
+       return -1;
+}
+
+static int vdec_h264_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
+                           struct vdec_fb *fb, bool *res_chg)
+{
+       struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec;
+       struct vdec_vpu_inst *vpu = &inst->vpu;
+       int nal_start_idx = 0;
+       int err = 0;
+       unsigned int nal_start;
+       unsigned int nal_type;
+       unsigned char *buf;
+       unsigned int buf_sz;
+       unsigned int data[2];
+       uint64_t vdec_fb_va = (u64)(uintptr_t)fb;
+       uint64_t y_fb_dma = fb ? (u64)fb->base_y.dma_addr : 0;
+       uint64_t c_fb_dma = fb ? (u64)fb->base_c.dma_addr : 0;
+
+       mtk_vcodec_debug(inst, "+ [%d] FB y_dma=%llx c_dma=%llx va=%p",
+                        ++inst->num_nalu, y_fb_dma, c_fb_dma, fb);
+
+       /* bs NULL means flush decoder */
+       if (bs == NULL)
+               return vpu_dec_reset(vpu);
+
+       buf = (unsigned char *)bs->va;
+       buf_sz = bs->size;
+       nal_start_idx = find_start_code(buf, buf_sz);
+       if (nal_start_idx < 0) {
+               mtk_vcodec_err(inst, "invalid nal start code");
+               err = -EIO;
+               goto err_free_fb_out;
+       }
+
+       nal_start = buf[nal_start_idx];
+       nal_type = NAL_TYPE(buf[nal_start_idx]);
+       mtk_vcodec_debug(inst, "\n + NALU[%d] type %d +\n", inst->num_nalu,
+                        nal_type);
+
+       if (nal_type == NAL_H264_PPS) {
+               buf_sz -= nal_start_idx;
+               if (buf_sz > HDR_PARSING_BUF_SZ) {
+                       err = -EILSEQ;
+                       goto err_free_fb_out;
+               }
+               memcpy(inst->vsi->hdr_buf, buf + nal_start_idx, buf_sz);
+       }
+
+       inst->vsi->dec.bs_dma = (uint64_t)bs->dma_addr;
+       inst->vsi->dec.y_fb_dma = y_fb_dma;
+       inst->vsi->dec.c_fb_dma = c_fb_dma;
+       inst->vsi->dec.vdec_fb_va = vdec_fb_va;
+
+       data[0] = buf_sz;
+       data[1] = nal_start;
+       err = vpu_dec_start(vpu, data, 2);
+       if (err) {
+               if (err > 0 && (DEC_ERR_RET(err) == H264_ERR_NOT_VALID)) {
+                       mtk_vcodec_err(inst, "- error bitstream - err = %d -",
+                                      err);
+                       err = -EIO;
+               }
+               goto err_free_fb_out;
+       }
+
+       *res_chg = inst->vsi->dec.resolution_changed;
+       if (*res_chg) {
+               struct vdec_pic_info pic;
+
+               mtk_vcodec_debug(inst, "- resolution changed -");
+               get_pic_info(inst, &pic);
+
+               if (inst->vsi->dec.realloc_mv_buf) {
+                       err = alloc_mv_buf(inst, &pic);
+                       if (err)
+                               goto err_free_fb_out;
+               }
+       }
+
+       if (nal_type == NAL_NON_IDR_SLICE || nal_type == NAL_IDR_SLICE) {
+               /* wait decoder done interrupt */
+               err = mtk_vcodec_wait_for_done_ctx(inst->ctx,
+                                                  MTK_INST_IRQ_RECEIVED,
+                                                  WAIT_INTR_TIMEOUT_MS, 0);
+               if (err)
+                       goto err_free_fb_out;
+
+               vpu_dec_end(vpu);
+       }
+
+       mtk_vcodec_debug(inst, "\n - NALU[%d] type=%d -\n", inst->num_nalu,
+                        nal_type);
+       return 0;
+
+err_free_fb_out:
+       put_fb_to_free(inst, fb);
+       mtk_vcodec_err(inst, "\n - NALU[%d] err=%d -\n", inst->num_nalu, err);
+       return err;
+}
+
+static void vdec_h264_get_fb(struct vdec_h264_inst *inst,
+                            struct h264_ring_fb_list *list,
+                            bool disp_list, struct vdec_fb **out_fb)
+{
+       struct vdec_fb *fb;
+
+       if (check_list_validity(inst, disp_list))
+               return;
+
+       if (list->count == 0) {
+               mtk_vcodec_debug(inst, "[FB] there is no %s fb",
+                                disp_list ? "disp" : "free");
+               *out_fb = NULL;
+               return;
+       }
+
+       fb = (struct vdec_fb *)
+               (uintptr_t)list->fb_list[list->read_idx].vdec_fb_va;
+       fb->status |= (disp_list ? FB_ST_DISPLAY : FB_ST_FREE);
+
+       *out_fb = fb;
+       mtk_vcodec_debug(inst, "[FB] get %s fb st=%d poc=%d %llx",
+                        disp_list ? "disp" : "free",
+                        fb->status, list->fb_list[list->read_idx].poc,
+                        list->fb_list[list->read_idx].vdec_fb_va);
+
+       list->read_idx = (list->read_idx == H264_MAX_FB_NUM - 1) ?
+                        0 : list->read_idx + 1;
+       list->count--;
+}
+
+static int vdec_h264_get_param(void *h_vdec, enum vdec_get_param_type type,
+                              void *out)
+{
+       struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec;
+
+       switch (type) {
+       case GET_PARAM_DISP_FRAME_BUFFER:
+               vdec_h264_get_fb(inst, &inst->vsi->list_disp, true, out);
+               break;
+
+       case GET_PARAM_FREE_FRAME_BUFFER:
+               vdec_h264_get_fb(inst, &inst->vsi->list_free, false, out);
+               break;
+
+       case GET_PARAM_PIC_INFO:
+               get_pic_info(inst, out);
+               break;
+
+       case GET_PARAM_DPB_SIZE:
+               get_dpb_size(inst, out);
+               break;
+
+       case GET_PARAM_CROP_INFO:
+               get_crop_info(inst, out);
+               break;
+
+       default:
+               mtk_vcodec_err(inst, "invalid get parameter type=%d", type);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+const struct vdec_common_if vdec_h264_if = {
+       .init           = vdec_h264_init,
+       .decode         = vdec_h264_decode,
+       .get_param      = vdec_h264_get_param,
+       .deinit         = vdec_h264_deinit,
+};
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/vdec/vdec_h264_req_if.c b/drivers/media/platform/mediatek/mtk-vcodec/vdec/vdec_h264_req_if.c
new file mode 100644 (file)
index 0000000..43542de
--- /dev/null
@@ -0,0 +1,774 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-h264.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "../mtk_vcodec_util.h"
+#include "../mtk_vcodec_dec.h"
+#include "../mtk_vcodec_intr.h"
+#include "../vdec_drv_base.h"
+#include "../vdec_drv_if.h"
+#include "../vdec_vpu_if.h"
+
+#define BUF_PREDICTION_SZ                      (64 * 4096)
+#define MB_UNIT_LEN                            16
+
+/* get used parameters for sps/pps */
+#define GET_MTK_VDEC_FLAG(cond, flag) \
+       { dst_param->cond = ((src_param->flags & (flag)) ? (1) : (0)); }
+#define GET_MTK_VDEC_PARAM(param) \
+       { dst_param->param = src_param->param; }
+/* motion vector size (bytes) for every macro block */
+#define HW_MB_STORE_SZ                         64
+
+#define H264_MAX_FB_NUM                                17
+#define H264_MAX_MV_NUM                                32
+#define HDR_PARSING_BUF_SZ                     1024
+
+/**
+ * struct mtk_h264_dpb_info  - h264 dpb information
+ * @y_dma_addr: Y bitstream physical address
+ * @c_dma_addr: CbCr bitstream physical address
+ * @reference_flag: reference picture flag (short/long term reference picture)
+ * @field: field picture flag
+ */
+struct mtk_h264_dpb_info {
+       dma_addr_t y_dma_addr;
+       dma_addr_t c_dma_addr;
+       int reference_flag;
+       int field;
+};
+
+/*
+ * struct mtk_h264_sps_param  - parameters for sps
+ */
+struct mtk_h264_sps_param {
+       unsigned char chroma_format_idc;
+       unsigned char bit_depth_luma_minus8;
+       unsigned char bit_depth_chroma_minus8;
+       unsigned char log2_max_frame_num_minus4;
+       unsigned char pic_order_cnt_type;
+       unsigned char log2_max_pic_order_cnt_lsb_minus4;
+       unsigned char max_num_ref_frames;
+       unsigned char separate_colour_plane_flag;
+       unsigned short pic_width_in_mbs_minus1;
+       unsigned short pic_height_in_map_units_minus1;
+       unsigned int max_frame_nums;
+       unsigned char qpprime_y_zero_transform_bypass_flag;
+       unsigned char delta_pic_order_always_zero_flag;
+       unsigned char frame_mbs_only_flag;
+       unsigned char mb_adaptive_frame_field_flag;
+       unsigned char direct_8x8_inference_flag;
+       unsigned char reserved[3];
+};
+
+/*
+ * struct mtk_h264_pps_param  - parameters for pps
+ */
+struct mtk_h264_pps_param {
+       unsigned char num_ref_idx_l0_default_active_minus1;
+       unsigned char num_ref_idx_l1_default_active_minus1;
+       unsigned char weighted_bipred_idc;
+       char pic_init_qp_minus26;
+       char chroma_qp_index_offset;
+       char second_chroma_qp_index_offset;
+       unsigned char entropy_coding_mode_flag;
+       unsigned char pic_order_present_flag;
+       unsigned char deblocking_filter_control_present_flag;
+       unsigned char constrained_intra_pred_flag;
+       unsigned char weighted_pred_flag;
+       unsigned char redundant_pic_cnt_present_flag;
+       unsigned char transform_8x8_mode_flag;
+       unsigned char scaling_matrix_present_flag;
+       unsigned char reserved[2];
+};
+
+struct slice_api_h264_scaling_matrix {
+       unsigned char scaling_list_4x4[6][16];
+       unsigned char scaling_list_8x8[6][64];
+};
+
+struct slice_h264_dpb_entry {
+       unsigned long long reference_ts;
+       unsigned short frame_num;
+       unsigned short pic_num;
+       /* Note that field is indicated by v4l2_buffer.field */
+       int top_field_order_cnt;
+       int bottom_field_order_cnt;
+       unsigned int flags; /* V4L2_H264_DPB_ENTRY_FLAG_* */
+};
+
+/*
+ * struct slice_api_h264_decode_param - parameters for decode.
+ */
+struct slice_api_h264_decode_param {
+       struct slice_h264_dpb_entry dpb[16];
+       unsigned short num_slices;
+       unsigned short nal_ref_idc;
+       unsigned char ref_pic_list_p0[32];
+       unsigned char ref_pic_list_b0[32];
+       unsigned char ref_pic_list_b1[32];
+       int top_field_order_cnt;
+       int bottom_field_order_cnt;
+       unsigned int flags; /* V4L2_H264_DECODE_PARAM_FLAG_* */
+};
+
+/*
+ * struct mtk_h264_dec_slice_param  - parameters for decode current frame
+ */
+struct mtk_h264_dec_slice_param {
+       struct mtk_h264_sps_param                       sps;
+       struct mtk_h264_pps_param                       pps;
+       struct slice_api_h264_scaling_matrix            scaling_matrix;
+       struct slice_api_h264_decode_param              decode_params;
+       struct mtk_h264_dpb_info h264_dpb_info[16];
+};
+
+/**
+ * struct h264_fb - h264 decode frame buffer information
+ * @vdec_fb_va  : virtual address of struct vdec_fb
+ * @y_fb_dma    : dma address of Y frame buffer (luma)
+ * @c_fb_dma    : dma address of C frame buffer (chroma)
+ * @poc         : picture order count of frame buffer
+ * @reserved    : for 8 bytes alignment
+ */
+struct h264_fb {
+       u64 vdec_fb_va;
+       u64 y_fb_dma;
+       u64 c_fb_dma;
+       s32 poc;
+       u32 reserved;
+};
+
+/**
+ * struct vdec_h264_dec_info - decode information
+ * @dpb_sz             : decoding picture buffer size
+ * @resolution_changed  : resoltion change happen
+ * @realloc_mv_buf     : flag to notify driver to re-allocate mv buffer
+ * @cap_num_planes     : number planes of capture buffer
+ * @bs_dma             : Input bit-stream buffer dma address
+ * @y_fb_dma           : Y frame buffer dma address
+ * @c_fb_dma           : C frame buffer dma address
+ * @vdec_fb_va         : VDEC frame buffer struct virtual address
+ */
+struct vdec_h264_dec_info {
+       u32 dpb_sz;
+       u32 resolution_changed;
+       u32 realloc_mv_buf;
+       u32 cap_num_planes;
+       u64 bs_dma;
+       u64 y_fb_dma;
+       u64 c_fb_dma;
+       u64 vdec_fb_va;
+};
+
+/**
+ * struct vdec_h264_vsi - shared memory for decode information exchange
+ *                        between VPU and Host.
+ *                        The memory is allocated by VPU then mapping to Host
+ *                        in vpu_dec_init() and freed in vpu_dec_deinit()
+ *                        by VPU.
+ *                        AP-W/R : AP is writer/reader on this item
+ *                        VPU-W/R: VPU is write/reader on this item
+ * @pred_buf_dma : HW working predication buffer dma address (AP-W, VPU-R)
+ * @mv_buf_dma   : HW working motion vector buffer dma address (AP-W, VPU-R)
+ * @dec          : decode information (AP-R, VPU-W)
+ * @pic          : picture information (AP-R, VPU-W)
+ * @crop         : crop information (AP-R, VPU-W)
+ * @h264_slice_params : the parameters that hardware use to decode
+ */
+struct vdec_h264_vsi {
+       u64 pred_buf_dma;
+       u64 mv_buf_dma[H264_MAX_MV_NUM];
+       struct vdec_h264_dec_info dec;
+       struct vdec_pic_info pic;
+       struct v4l2_rect crop;
+       struct mtk_h264_dec_slice_param h264_slice_params;
+};
+
+/**
+ * struct vdec_h264_slice_inst - h264 decoder instance
+ * @num_nalu : how many nalus be decoded
+ * @ctx      : point to mtk_vcodec_ctx
+ * @pred_buf : HW working predication buffer
+ * @mv_buf   : HW working motion vector buffer
+ * @vpu      : VPU instance
+ * @vsi_ctx  : Local VSI data for this decoding context
+ * @h264_slice_param : the parameters that hardware use to decode
+ * @dpb : decoded picture buffer used to store reference buffer information
+ */
+struct vdec_h264_slice_inst {
+       unsigned int num_nalu;
+       struct mtk_vcodec_ctx *ctx;
+       struct mtk_vcodec_mem pred_buf;
+       struct mtk_vcodec_mem mv_buf[H264_MAX_MV_NUM];
+       struct vdec_vpu_inst vpu;
+       struct vdec_h264_vsi vsi_ctx;
+       struct mtk_h264_dec_slice_param h264_slice_param;
+
+       struct v4l2_h264_dpb_entry dpb[16];
+};
+
+static void *get_ctrl_ptr(struct mtk_vcodec_ctx *ctx, int id)
+{
+       struct v4l2_ctrl *ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, id);
+
+       return ctrl->p_cur.p;
+}
+
+static void get_h264_dpb_list(struct vdec_h264_slice_inst *inst,
+                             struct mtk_h264_dec_slice_param *slice_param)
+{
+       struct vb2_queue *vq;
+       struct vb2_buffer *vb;
+       struct vb2_v4l2_buffer *vb2_v4l2;
+       u64 index;
+
+       vq = v4l2_m2m_get_vq(inst->ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+
+       for (index = 0; index < ARRAY_SIZE(slice_param->decode_params.dpb); index++) {
+               const struct slice_h264_dpb_entry *dpb;
+               int vb2_index;
+
+               dpb = &slice_param->decode_params.dpb[index];
+               if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) {
+                       slice_param->h264_dpb_info[index].reference_flag = 0;
+                       continue;
+               }
+
+               vb2_index = vb2_find_timestamp(vq, dpb->reference_ts, 0);
+               if (vb2_index < 0) {
+                       mtk_vcodec_err(inst, "Reference invalid: dpb_index(%lld) reference_ts(%lld)",
+                                      index, dpb->reference_ts);
+                       continue;
+               }
+               /* 1 for short term reference, 2 for long term reference */
+               if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM))
+                       slice_param->h264_dpb_info[index].reference_flag = 1;
+               else
+                       slice_param->h264_dpb_info[index].reference_flag = 2;
+
+               vb = vq->bufs[vb2_index];
+               vb2_v4l2 = container_of(vb, struct vb2_v4l2_buffer, vb2_buf);
+               slice_param->h264_dpb_info[index].field = vb2_v4l2->field;
+
+               slice_param->h264_dpb_info[index].y_dma_addr =
+                       vb2_dma_contig_plane_dma_addr(vb, 0);
+               if (inst->ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) {
+                       slice_param->h264_dpb_info[index].c_dma_addr =
+                               vb2_dma_contig_plane_dma_addr(vb, 1);
+               }
+       }
+}
+
+static void get_h264_sps_parameters(struct mtk_h264_sps_param *dst_param,
+                                   const struct v4l2_ctrl_h264_sps *src_param)
+{
+       GET_MTK_VDEC_PARAM(chroma_format_idc);
+       GET_MTK_VDEC_PARAM(bit_depth_luma_minus8);
+       GET_MTK_VDEC_PARAM(bit_depth_chroma_minus8);
+       GET_MTK_VDEC_PARAM(log2_max_frame_num_minus4);
+       GET_MTK_VDEC_PARAM(pic_order_cnt_type);
+       GET_MTK_VDEC_PARAM(log2_max_pic_order_cnt_lsb_minus4);
+       GET_MTK_VDEC_PARAM(max_num_ref_frames);
+       GET_MTK_VDEC_PARAM(pic_width_in_mbs_minus1);
+       GET_MTK_VDEC_PARAM(pic_height_in_map_units_minus1);
+
+       GET_MTK_VDEC_FLAG(separate_colour_plane_flag,
+                         V4L2_H264_SPS_FLAG_SEPARATE_COLOUR_PLANE);
+       GET_MTK_VDEC_FLAG(qpprime_y_zero_transform_bypass_flag,
+                         V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS);
+       GET_MTK_VDEC_FLAG(delta_pic_order_always_zero_flag,
+                         V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO);
+       GET_MTK_VDEC_FLAG(frame_mbs_only_flag,
+                         V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY);
+       GET_MTK_VDEC_FLAG(mb_adaptive_frame_field_flag,
+                         V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD);
+       GET_MTK_VDEC_FLAG(direct_8x8_inference_flag,
+                         V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE);
+}
+
+static void get_h264_pps_parameters(struct mtk_h264_pps_param *dst_param,
+                                   const struct v4l2_ctrl_h264_pps *src_param)
+{
+       GET_MTK_VDEC_PARAM(num_ref_idx_l0_default_active_minus1);
+       GET_MTK_VDEC_PARAM(num_ref_idx_l1_default_active_minus1);
+       GET_MTK_VDEC_PARAM(weighted_bipred_idc);
+       GET_MTK_VDEC_PARAM(pic_init_qp_minus26);
+       GET_MTK_VDEC_PARAM(chroma_qp_index_offset);
+       GET_MTK_VDEC_PARAM(second_chroma_qp_index_offset);
+
+       GET_MTK_VDEC_FLAG(entropy_coding_mode_flag,
+                         V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE);
+       GET_MTK_VDEC_FLAG(pic_order_present_flag,
+                         V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT);
+       GET_MTK_VDEC_FLAG(weighted_pred_flag,
+                         V4L2_H264_PPS_FLAG_WEIGHTED_PRED);
+       GET_MTK_VDEC_FLAG(deblocking_filter_control_present_flag,
+                         V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT);
+       GET_MTK_VDEC_FLAG(constrained_intra_pred_flag,
+                         V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED);
+       GET_MTK_VDEC_FLAG(redundant_pic_cnt_present_flag,
+                         V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT);
+       GET_MTK_VDEC_FLAG(transform_8x8_mode_flag,
+                         V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE);
+       GET_MTK_VDEC_FLAG(scaling_matrix_present_flag,
+                         V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT);
+}
+
+static void
+get_h264_scaling_matrix(struct slice_api_h264_scaling_matrix *dst_matrix,
+                       const struct v4l2_ctrl_h264_scaling_matrix *src_matrix)
+{
+       memcpy(dst_matrix->scaling_list_4x4, src_matrix->scaling_list_4x4,
+              sizeof(dst_matrix->scaling_list_4x4));
+
+       memcpy(dst_matrix->scaling_list_8x8, src_matrix->scaling_list_8x8,
+              sizeof(dst_matrix->scaling_list_8x8));
+}
+
+static void
+get_h264_decode_parameters(struct slice_api_h264_decode_param *dst_params,
+                          const struct v4l2_ctrl_h264_decode_params *src_params,
+                          const struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES])
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(dst_params->dpb); i++) {
+               struct slice_h264_dpb_entry *dst_entry = &dst_params->dpb[i];
+               const struct v4l2_h264_dpb_entry *src_entry = &dpb[i];
+
+               dst_entry->reference_ts = src_entry->reference_ts;
+               dst_entry->frame_num = src_entry->frame_num;
+               dst_entry->pic_num = src_entry->pic_num;
+               dst_entry->top_field_order_cnt = src_entry->top_field_order_cnt;
+               dst_entry->bottom_field_order_cnt =
+                       src_entry->bottom_field_order_cnt;
+               dst_entry->flags = src_entry->flags;
+       }
+
+       /*
+        * num_slices is a leftover from the old H.264 support and is ignored
+        * by the firmware.
+        */
+       dst_params->num_slices = 0;
+       dst_params->nal_ref_idc = src_params->nal_ref_idc;
+       dst_params->top_field_order_cnt = src_params->top_field_order_cnt;
+       dst_params->bottom_field_order_cnt = src_params->bottom_field_order_cnt;
+       dst_params->flags = src_params->flags;
+}
+
+static bool dpb_entry_match(const struct v4l2_h264_dpb_entry *a,
+                           const struct v4l2_h264_dpb_entry *b)
+{
+       return a->top_field_order_cnt == b->top_field_order_cnt &&
+              a->bottom_field_order_cnt == b->bottom_field_order_cnt;
+}
+
+/*
+ * Move DPB entries of dec_param that refer to a frame already existing in dpb
+ * into the already existing slot in dpb, and move other entries into new slots.
+ *
+ * This function is an adaptation of the similarly-named function in
+ * hantro_h264.c.
+ */
+static void update_dpb(const struct v4l2_ctrl_h264_decode_params *dec_param,
+                      struct v4l2_h264_dpb_entry *dpb)
+{
+       DECLARE_BITMAP(new, ARRAY_SIZE(dec_param->dpb)) = { 0, };
+       DECLARE_BITMAP(in_use, ARRAY_SIZE(dec_param->dpb)) = { 0, };
+       DECLARE_BITMAP(used, ARRAY_SIZE(dec_param->dpb)) = { 0, };
+       unsigned int i, j;
+
+       /* Disable all entries by default, and mark the ones in use. */
+       for (i = 0; i < ARRAY_SIZE(dec_param->dpb); i++) {
+               if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)
+                       set_bit(i, in_use);
+               dpb[i].flags &= ~V4L2_H264_DPB_ENTRY_FLAG_ACTIVE;
+       }
+
+       /* Try to match new DPB entries with existing ones by their POCs. */
+       for (i = 0; i < ARRAY_SIZE(dec_param->dpb); i++) {
+               const struct v4l2_h264_dpb_entry *ndpb = &dec_param->dpb[i];
+
+               if (!(ndpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE))
+                       continue;
+
+               /*
+                * To cut off some comparisons, iterate only on target DPB
+                * entries were already used.
+                */
+               for_each_set_bit(j, in_use, ARRAY_SIZE(dec_param->dpb)) {
+                       struct v4l2_h264_dpb_entry *cdpb;
+
+                       cdpb = &dpb[j];
+                       if (!dpb_entry_match(cdpb, ndpb))
+                               continue;
+
+                       *cdpb = *ndpb;
+                       set_bit(j, used);
+                       /* Don't reiterate on this one. */
+                       clear_bit(j, in_use);
+                       break;
+               }
+
+               if (j == ARRAY_SIZE(dec_param->dpb))
+                       set_bit(i, new);
+       }
+
+       /* For entries that could not be matched, use remaining free slots. */
+       for_each_set_bit(i, new, ARRAY_SIZE(dec_param->dpb)) {
+               const struct v4l2_h264_dpb_entry *ndpb = &dec_param->dpb[i];
+               struct v4l2_h264_dpb_entry *cdpb;
+
+               /*
+                * Both arrays are of the same sizes, so there is no way
+                * we can end up with no space in target array, unless
+                * something is buggy.
+                */
+               j = find_first_zero_bit(used, ARRAY_SIZE(dec_param->dpb));
+               if (WARN_ON(j >= ARRAY_SIZE(dec_param->dpb)))
+                       return;
+
+               cdpb = &dpb[j];
+               *cdpb = *ndpb;
+               set_bit(j, used);
+       }
+}
+
+/*
+ * The firmware expects unused reflist entries to have the value 0x20.
+ */
+static void fixup_ref_list(u8 *ref_list, size_t num_valid)
+{
+       memset(&ref_list[num_valid], 0x20, 32 - num_valid);
+}
+
+static void get_vdec_decode_parameters(struct vdec_h264_slice_inst *inst)
+{
+       const struct v4l2_ctrl_h264_decode_params *dec_params =
+               get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_DECODE_PARAMS);
+       const struct v4l2_ctrl_h264_sps *sps =
+               get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_SPS);
+       const struct v4l2_ctrl_h264_pps *pps =
+               get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_PPS);
+       const struct v4l2_ctrl_h264_scaling_matrix *scaling_matrix =
+               get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_SCALING_MATRIX);
+       struct mtk_h264_dec_slice_param *slice_param = &inst->h264_slice_param;
+       struct v4l2_h264_reflist_builder reflist_builder;
+       u8 *p0_reflist = slice_param->decode_params.ref_pic_list_p0;
+       u8 *b0_reflist = slice_param->decode_params.ref_pic_list_b0;
+       u8 *b1_reflist = slice_param->decode_params.ref_pic_list_b1;
+
+       update_dpb(dec_params, inst->dpb);
+
+       get_h264_sps_parameters(&slice_param->sps, sps);
+       get_h264_pps_parameters(&slice_param->pps, pps);
+       get_h264_scaling_matrix(&slice_param->scaling_matrix, scaling_matrix);
+       get_h264_decode_parameters(&slice_param->decode_params, dec_params,
+                                  inst->dpb);
+       get_h264_dpb_list(inst, slice_param);
+
+       /* Build the reference lists */
+       v4l2_h264_init_reflist_builder(&reflist_builder, dec_params, sps,
+                                      inst->dpb);
+       v4l2_h264_build_p_ref_list(&reflist_builder, p0_reflist);
+       v4l2_h264_build_b_ref_lists(&reflist_builder, b0_reflist, b1_reflist);
+       /* Adapt the built lists to the firmware's expectations */
+       fixup_ref_list(p0_reflist, reflist_builder.num_valid);
+       fixup_ref_list(b0_reflist, reflist_builder.num_valid);
+       fixup_ref_list(b1_reflist, reflist_builder.num_valid);
+
+       memcpy(&inst->vsi_ctx.h264_slice_params, slice_param,
+              sizeof(inst->vsi_ctx.h264_slice_params));
+}
+
+static unsigned int get_mv_buf_size(unsigned int width, unsigned int height)
+{
+       int unit_size = (width / MB_UNIT_LEN) * (height / MB_UNIT_LEN) + 8;
+
+       return HW_MB_STORE_SZ * unit_size;
+}
+
+static int allocate_predication_buf(struct vdec_h264_slice_inst *inst)
+{
+       int err;
+
+       inst->pred_buf.size = BUF_PREDICTION_SZ;
+       err = mtk_vcodec_mem_alloc(inst->ctx, &inst->pred_buf);
+       if (err) {
+               mtk_vcodec_err(inst, "failed to allocate ppl buf");
+               return err;
+       }
+
+       inst->vsi_ctx.pred_buf_dma = inst->pred_buf.dma_addr;
+       return 0;
+}
+
+static void free_predication_buf(struct vdec_h264_slice_inst *inst)
+{
+       struct mtk_vcodec_mem *mem = &inst->pred_buf;
+
+       mtk_vcodec_debug_enter(inst);
+
+       inst->vsi_ctx.pred_buf_dma = 0;
+       if (mem->va)
+               mtk_vcodec_mem_free(inst->ctx, mem);
+}
+
+static int alloc_mv_buf(struct vdec_h264_slice_inst *inst,
+                       struct vdec_pic_info *pic)
+{
+       int i;
+       int err;
+       struct mtk_vcodec_mem *mem = NULL;
+       unsigned int buf_sz = get_mv_buf_size(pic->buf_w, pic->buf_h);
+
+       mtk_v4l2_debug(3, "size = 0x%x", buf_sz);
+       for (i = 0; i < H264_MAX_MV_NUM; i++) {
+               mem = &inst->mv_buf[i];
+               if (mem->va)
+                       mtk_vcodec_mem_free(inst->ctx, mem);
+               mem->size = buf_sz;
+               err = mtk_vcodec_mem_alloc(inst->ctx, mem);
+               if (err) {
+                       mtk_vcodec_err(inst, "failed to allocate mv buf");
+                       return err;
+               }
+               inst->vsi_ctx.mv_buf_dma[i] = mem->dma_addr;
+       }
+
+       return 0;
+}
+
+static void free_mv_buf(struct vdec_h264_slice_inst *inst)
+{
+       int i;
+       struct mtk_vcodec_mem *mem;
+
+       for (i = 0; i < H264_MAX_MV_NUM; i++) {
+               inst->vsi_ctx.mv_buf_dma[i] = 0;
+               mem = &inst->mv_buf[i];
+               if (mem->va)
+                       mtk_vcodec_mem_free(inst->ctx, mem);
+       }
+}
+
+static void get_pic_info(struct vdec_h264_slice_inst *inst,
+                        struct vdec_pic_info *pic)
+{
+       struct mtk_vcodec_ctx *ctx = inst->ctx;
+
+       ctx->picinfo.buf_w = ALIGN(ctx->picinfo.pic_w, VCODEC_DEC_ALIGNED_64);
+       ctx->picinfo.buf_h = ALIGN(ctx->picinfo.pic_h, VCODEC_DEC_ALIGNED_64);
+       ctx->picinfo.fb_sz[0] = ctx->picinfo.buf_w * ctx->picinfo.buf_h;
+       ctx->picinfo.fb_sz[1] = ctx->picinfo.fb_sz[0] >> 1;
+       inst->vsi_ctx.dec.cap_num_planes =
+               ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes;
+
+       *pic = ctx->picinfo;
+       mtk_vcodec_debug(inst, "pic(%d, %d), buf(%d, %d)",
+                        ctx->picinfo.pic_w, ctx->picinfo.pic_h,
+                        ctx->picinfo.buf_w, ctx->picinfo.buf_h);
+       mtk_vcodec_debug(inst, "Y/C(%d, %d)", ctx->picinfo.fb_sz[0],
+                        ctx->picinfo.fb_sz[1]);
+
+       if (ctx->last_decoded_picinfo.pic_w != ctx->picinfo.pic_w ||
+           ctx->last_decoded_picinfo.pic_h != ctx->picinfo.pic_h) {
+               inst->vsi_ctx.dec.resolution_changed = true;
+               if (ctx->last_decoded_picinfo.buf_w != ctx->picinfo.buf_w ||
+                   ctx->last_decoded_picinfo.buf_h != ctx->picinfo.buf_h)
+                       inst->vsi_ctx.dec.realloc_mv_buf = true;
+
+               mtk_v4l2_debug(1, "ResChg: (%d %d) : old(%d, %d) -> new(%d, %d)",
+                              inst->vsi_ctx.dec.resolution_changed,
+                              inst->vsi_ctx.dec.realloc_mv_buf,
+                              ctx->last_decoded_picinfo.pic_w,
+                              ctx->last_decoded_picinfo.pic_h,
+                              ctx->picinfo.pic_w, ctx->picinfo.pic_h);
+       }
+}
+
+static void get_crop_info(struct vdec_h264_slice_inst *inst, struct v4l2_rect *cr)
+{
+       cr->left = inst->vsi_ctx.crop.left;
+       cr->top = inst->vsi_ctx.crop.top;
+       cr->width = inst->vsi_ctx.crop.width;
+       cr->height = inst->vsi_ctx.crop.height;
+
+       mtk_vcodec_debug(inst, "l=%d, t=%d, w=%d, h=%d",
+                        cr->left, cr->top, cr->width, cr->height);
+}
+
+static void get_dpb_size(struct vdec_h264_slice_inst *inst, unsigned int *dpb_sz)
+{
+       *dpb_sz = inst->vsi_ctx.dec.dpb_sz;
+       mtk_vcodec_debug(inst, "sz=%d", *dpb_sz);
+}
+
+static int vdec_h264_slice_init(struct mtk_vcodec_ctx *ctx)
+{
+       struct vdec_h264_slice_inst *inst;
+       int err;
+
+       inst = kzalloc(sizeof(*inst), GFP_KERNEL);
+       if (!inst)
+               return -ENOMEM;
+
+       inst->ctx = ctx;
+
+       inst->vpu.id = SCP_IPI_VDEC_H264;
+       inst->vpu.ctx = ctx;
+
+       err = vpu_dec_init(&inst->vpu);
+       if (err) {
+               mtk_vcodec_err(inst, "vdec_h264 init err=%d", err);
+               goto error_free_inst;
+       }
+
+       memcpy(&inst->vsi_ctx, inst->vpu.vsi, sizeof(inst->vsi_ctx));
+       inst->vsi_ctx.dec.resolution_changed = true;
+       inst->vsi_ctx.dec.realloc_mv_buf = true;
+
+       err = allocate_predication_buf(inst);
+       if (err)
+               goto error_deinit;
+
+       mtk_vcodec_debug(inst, "struct size = %zu,%zu,%zu,%zu\n",
+                        sizeof(struct mtk_h264_sps_param),
+                        sizeof(struct mtk_h264_pps_param),
+                        sizeof(struct mtk_h264_dec_slice_param),
+                        sizeof(struct mtk_h264_dpb_info));
+
+       mtk_vcodec_debug(inst, "H264 Instance >> %p", inst);
+
+       ctx->drv_handle = inst;
+       return 0;
+
+error_deinit:
+       vpu_dec_deinit(&inst->vpu);
+
+error_free_inst:
+       kfree(inst);
+       return err;
+}
+
+static void vdec_h264_slice_deinit(void *h_vdec)
+{
+       struct vdec_h264_slice_inst *inst = h_vdec;
+
+       mtk_vcodec_debug_enter(inst);
+
+       vpu_dec_deinit(&inst->vpu);
+       free_predication_buf(inst);
+       free_mv_buf(inst);
+
+       kfree(inst);
+}
+
+static int vdec_h264_slice_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
+                                 struct vdec_fb *fb, bool *res_chg)
+{
+       struct vdec_h264_slice_inst *inst = h_vdec;
+       const struct v4l2_ctrl_h264_decode_params *dec_params =
+               get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_DECODE_PARAMS);
+       struct vdec_vpu_inst *vpu = &inst->vpu;
+       u32 data[2];
+       u64 y_fb_dma;
+       u64 c_fb_dma;
+       int err;
+
+       /* bs NULL means flush decoder */
+       if (!bs)
+               return vpu_dec_reset(vpu);
+
+       y_fb_dma = fb ? (u64)fb->base_y.dma_addr : 0;
+       c_fb_dma = fb ? (u64)fb->base_c.dma_addr : 0;
+
+       mtk_vcodec_debug(inst, "+ [%d] FB y_dma=%llx c_dma=%llx va=%p",
+                        ++inst->num_nalu, y_fb_dma, c_fb_dma, fb);
+
+       inst->vsi_ctx.dec.bs_dma = (uint64_t)bs->dma_addr;
+       inst->vsi_ctx.dec.y_fb_dma = y_fb_dma;
+       inst->vsi_ctx.dec.c_fb_dma = c_fb_dma;
+       inst->vsi_ctx.dec.vdec_fb_va = (u64)(uintptr_t)fb;
+
+       get_vdec_decode_parameters(inst);
+       data[0] = bs->size;
+       /*
+        * Reconstruct the first byte of the NAL unit, as the firmware requests
+        * that information to be passed even though it is present in the stream
+        * itself...
+        */
+       data[1] = (dec_params->nal_ref_idc << 5) |
+                 ((dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC)
+                       ? 0x5 : 0x1);
+
+       *res_chg = inst->vsi_ctx.dec.resolution_changed;
+       if (*res_chg) {
+               mtk_vcodec_debug(inst, "- resolution changed -");
+               if (inst->vsi_ctx.dec.realloc_mv_buf) {
+                       err = alloc_mv_buf(inst, &inst->ctx->picinfo);
+                       inst->vsi_ctx.dec.realloc_mv_buf = false;
+                       if (err)
+                               goto err_free_fb_out;
+               }
+               *res_chg = false;
+       }
+
+       memcpy(inst->vpu.vsi, &inst->vsi_ctx, sizeof(inst->vsi_ctx));
+       err = vpu_dec_start(vpu, data, 2);
+       if (err)
+               goto err_free_fb_out;
+
+       /* wait decoder done interrupt */
+       err = mtk_vcodec_wait_for_done_ctx(inst->ctx,
+                                          MTK_INST_IRQ_RECEIVED,
+                                          WAIT_INTR_TIMEOUT_MS, 0);
+       if (err)
+               goto err_free_fb_out;
+       vpu_dec_end(vpu);
+
+       memcpy(&inst->vsi_ctx, inst->vpu.vsi, sizeof(inst->vsi_ctx));
+       mtk_vcodec_debug(inst, "\n - NALU[%d]", inst->num_nalu);
+       return 0;
+
+err_free_fb_out:
+       mtk_vcodec_err(inst, "\n - NALU[%d] err=%d -\n", inst->num_nalu, err);
+       return err;
+}
+
+static int vdec_h264_slice_get_param(void *h_vdec, enum vdec_get_param_type type, void *out)
+{
+       struct vdec_h264_slice_inst *inst = h_vdec;
+
+       switch (type) {
+       case GET_PARAM_PIC_INFO:
+               get_pic_info(inst, out);
+               break;
+
+       case GET_PARAM_DPB_SIZE:
+               get_dpb_size(inst, out);
+               break;
+
+       case GET_PARAM_CROP_INFO:
+               get_crop_info(inst, out);
+               break;
+
+       default:
+               mtk_vcodec_err(inst, "invalid get parameter type=%d", type);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+const struct vdec_common_if vdec_h264_slice_if = {
+       .init           = vdec_h264_slice_init,
+       .decode         = vdec_h264_slice_decode,
+       .get_param      = vdec_h264_slice_get_param,
+       .deinit         = vdec_h264_slice_deinit,
+};
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/vdec/vdec_vp8_if.c b/drivers/media/platform/mediatek/mtk-vcodec/vdec/vdec_vp8_if.c
new file mode 100644 (file)
index 0000000..88c0467
--- /dev/null
@@ -0,0 +1,616 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Jungchang Tsao <jungchang.tsao@mediatek.com>
+ *        PC Chen <pc.chen@mediatek.com>
+ */
+
+#include <linux/slab.h>
+#include "../vdec_drv_if.h"
+#include "../mtk_vcodec_util.h"
+#include "../mtk_vcodec_dec.h"
+#include "../mtk_vcodec_intr.h"
+#include "../vdec_vpu_if.h"
+#include "../vdec_drv_base.h"
+
+/* Decoding picture buffer size (3 reference frames plus current frame) */
+#define VP8_DPB_SIZE                   4
+
+/* HW working buffer size (bytes) */
+#define VP8_WORKING_BUF_SZ             (45 * 4096)
+
+/* HW control register address */
+#define VP8_SEGID_DRAM_ADDR            0x3c
+#define VP8_HW_VLD_ADDR                        0x93C
+#define VP8_HW_VLD_VALUE               0x940
+#define VP8_BSASET                     0x100
+#define VP8_BSDSET                     0x104
+#define VP8_RW_CKEN_SET                        0x0
+#define VP8_RW_DCM_CON                 0x18
+#define VP8_WO_VLD_SRST                        0x108
+#define VP8_RW_MISC_SYS_SEL            0x84
+#define VP8_RW_MISC_SPEC_CON           0xC8
+#define VP8_WO_VLD_SRST                        0x108
+#define VP8_RW_VP8_CTRL                        0xA4
+#define VP8_RW_MISC_DCM_CON            0xEC
+#define VP8_RW_MISC_SRST               0xF4
+#define VP8_RW_MISC_FUNC_CON           0xCC
+
+#define VP8_MAX_FRM_BUF_NUM            5
+#define VP8_MAX_FRM_BUF_NODE_NUM       (VP8_MAX_FRM_BUF_NUM * 2)
+
+/* required buffer size (bytes) to store decode information */
+#define VP8_HW_SEGMENT_DATA_SZ         272
+#define VP8_HW_SEGMENT_UINT            4
+
+#define VP8_DEC_TABLE_PROC_LOOP                96
+#define VP8_DEC_TABLE_UNIT             3
+#define VP8_DEC_TABLE_SZ               300
+#define VP8_DEC_TABLE_OFFSET           2
+#define VP8_DEC_TABLE_RW_UNIT          4
+
+/**
+ * struct vdec_vp8_dec_info - decode misc information
+ * @working_buf_dma   : working buffer dma address
+ * @prev_y_dma        : previous decoded frame buffer Y plane address
+ * @cur_y_fb_dma      : current plane Y frame buffer dma address
+ * @cur_c_fb_dma      : current plane C frame buffer dma address
+ * @bs_dma           : bitstream dma address
+ * @bs_sz            : bitstream size
+ * @resolution_changed: resolution change flag 1 - changed,  0 - not change
+ * @show_frame       : display this frame or not
+ * @wait_key_frame    : wait key frame coming
+ */
+struct vdec_vp8_dec_info {
+       uint64_t working_buf_dma;
+       uint64_t prev_y_dma;
+       uint64_t cur_y_fb_dma;
+       uint64_t cur_c_fb_dma;
+       uint64_t bs_dma;
+       uint32_t bs_sz;
+       uint32_t resolution_changed;
+       uint32_t show_frame;
+       uint32_t wait_key_frame;
+};
+
+/**
+ * struct vdec_vp8_vsi - VPU shared information
+ * @dec                        : decoding information
+ * @pic                        : picture information
+ * @dec_table          : decoder coefficient table
+ * @segment_buf                : segmentation buffer
+ * @load_data          : flag to indicate reload decode data
+ */
+struct vdec_vp8_vsi {
+       struct vdec_vp8_dec_info dec;
+       struct vdec_pic_info pic;
+       uint32_t dec_table[VP8_DEC_TABLE_SZ];
+       uint32_t segment_buf[VP8_HW_SEGMENT_DATA_SZ][VP8_HW_SEGMENT_UINT];
+       uint32_t load_data;
+};
+
+/**
+ * struct vdec_vp8_hw_reg_base - HW register base
+ * @sys                : base address for sys
+ * @misc       : base address for misc
+ * @ld         : base address for ld
+ * @top                : base address for top
+ * @cm         : base address for cm
+ * @hwd                : base address for hwd
+ * @hwb                : base address for hwb
+ */
+struct vdec_vp8_hw_reg_base {
+       void __iomem *sys;
+       void __iomem *misc;
+       void __iomem *ld;
+       void __iomem *top;
+       void __iomem *cm;
+       void __iomem *hwd;
+       void __iomem *hwb;
+};
+
+/**
+ * struct vdec_vp8_vpu_inst - VPU instance for VP8 decode
+ * @wq_hd      : Wait queue to wait VPU message ack
+ * @signaled   : 1 - Host has received ack message from VPU, 0 - not receive
+ * @failure    : VPU execution result status 0 - success, others - fail
+ * @inst_addr  : VPU decoder instance address
+ */
+struct vdec_vp8_vpu_inst {
+       wait_queue_head_t wq_hd;
+       int signaled;
+       int failure;
+       uint32_t inst_addr;
+};
+
+/* frame buffer (fb) list
+ * [available_fb_node_list]  - decode fb are initialized to 0 and populated in
+ * [fb_use_list]  - fb is set after decode and is moved to this list
+ * [fb_free_list] - fb is not needed for reference will be moved from
+ *                  [fb_use_list] to [fb_free_list] and
+ *                  once user remove fb from [fb_free_list],
+ *                  it is circulated back to [available_fb_node_list]
+ * [fb_disp_list] - fb is set after decode and is moved to this list
+ *                   once user remove fb from [fb_disp_list] it is
+ *                   circulated back to [available_fb_node_list]
+ */
+
+/**
+ * struct vdec_vp8_inst - VP8 decoder instance
+ * @cur_fb                : current frame buffer
+ * @dec_fb                : decode frame buffer node
+ * @available_fb_node_list : list to store available frame buffer node
+ * @fb_use_list                   : list to store frame buffer in use
+ * @fb_free_list          : list to store free frame buffer
+ * @fb_disp_list          : list to store display ready frame buffer
+ * @working_buf                   : HW decoder working buffer
+ * @reg_base              : HW register base address
+ * @frm_cnt               : decode frame count
+ * @ctx                           : V4L2 context
+ * @vpu                           : VPU instance for decoder
+ * @vsi                           : VPU share information
+ */
+struct vdec_vp8_inst {
+       struct vdec_fb *cur_fb;
+       struct vdec_fb_node dec_fb[VP8_MAX_FRM_BUF_NODE_NUM];
+       struct list_head available_fb_node_list;
+       struct list_head fb_use_list;
+       struct list_head fb_free_list;
+       struct list_head fb_disp_list;
+       struct mtk_vcodec_mem working_buf;
+       struct vdec_vp8_hw_reg_base reg_base;
+       unsigned int frm_cnt;
+       struct mtk_vcodec_ctx *ctx;
+       struct vdec_vpu_inst vpu;
+       struct vdec_vp8_vsi *vsi;
+};
+
+static void get_hw_reg_base(struct vdec_vp8_inst *inst)
+{
+       inst->reg_base.top = mtk_vcodec_get_reg_addr(inst->ctx, VDEC_TOP);
+       inst->reg_base.cm = mtk_vcodec_get_reg_addr(inst->ctx, VDEC_CM);
+       inst->reg_base.hwd = mtk_vcodec_get_reg_addr(inst->ctx, VDEC_HWD);
+       inst->reg_base.sys = mtk_vcodec_get_reg_addr(inst->ctx, VDEC_SYS);
+       inst->reg_base.misc = mtk_vcodec_get_reg_addr(inst->ctx, VDEC_MISC);
+       inst->reg_base.ld = mtk_vcodec_get_reg_addr(inst->ctx, VDEC_LD);
+       inst->reg_base.hwb = mtk_vcodec_get_reg_addr(inst->ctx, VDEC_HWB);
+}
+
+static void write_hw_segmentation_data(struct vdec_vp8_inst *inst)
+{
+       int i, j;
+       u32 seg_id_addr;
+       u32 val;
+       void __iomem *cm = inst->reg_base.cm;
+       struct vdec_vp8_vsi *vsi = inst->vsi;
+
+       seg_id_addr = readl(inst->reg_base.top + VP8_SEGID_DRAM_ADDR) >> 4;
+
+       for (i = 0; i < ARRAY_SIZE(vsi->segment_buf); i++) {
+               for (j = ARRAY_SIZE(vsi->segment_buf[i]) - 1; j >= 0; j--) {
+                       val = (1 << 16) + ((seg_id_addr + i) << 2) + j;
+                       writel(val, cm + VP8_HW_VLD_ADDR);
+
+                       val = vsi->segment_buf[i][j];
+                       writel(val, cm + VP8_HW_VLD_VALUE);
+               }
+       }
+}
+
+static void read_hw_segmentation_data(struct vdec_vp8_inst *inst)
+{
+       int i, j;
+       u32 seg_id_addr;
+       u32 val;
+       void __iomem *cm = inst->reg_base.cm;
+       struct vdec_vp8_vsi *vsi = inst->vsi;
+
+       seg_id_addr = readl(inst->reg_base.top + VP8_SEGID_DRAM_ADDR) >> 4;
+
+       for (i = 0; i < ARRAY_SIZE(vsi->segment_buf); i++) {
+               for (j = ARRAY_SIZE(vsi->segment_buf[i]) - 1; j >= 0; j--) {
+                       val = ((seg_id_addr + i) << 2) + j;
+                       writel(val, cm + VP8_HW_VLD_ADDR);
+
+                       val = readl(cm + VP8_HW_VLD_VALUE);
+                       vsi->segment_buf[i][j] = val;
+               }
+       }
+}
+
+/* reset HW and enable HW read/write data function */
+static void enable_hw_rw_function(struct vdec_vp8_inst *inst)
+{
+       u32 val = 0;
+       void __iomem *sys = inst->reg_base.sys;
+       void __iomem *misc = inst->reg_base.misc;
+       void __iomem *ld = inst->reg_base.ld;
+       void __iomem *hwb = inst->reg_base.hwb;
+       void __iomem *hwd = inst->reg_base.hwd;
+
+       writel(0x1, sys + VP8_RW_CKEN_SET);
+       writel(0x101, ld + VP8_WO_VLD_SRST);
+       writel(0x101, hwb + VP8_WO_VLD_SRST);
+
+       writel(1, sys);
+       val = readl(misc + VP8_RW_MISC_SRST);
+       writel((val & 0xFFFFFFFE), misc + VP8_RW_MISC_SRST);
+
+       writel(0x1, misc + VP8_RW_MISC_SYS_SEL);
+       writel(0x17F, misc + VP8_RW_MISC_SPEC_CON);
+       writel(0x71201100, misc + VP8_RW_MISC_FUNC_CON);
+       writel(0x0, ld + VP8_WO_VLD_SRST);
+       writel(0x0, hwb + VP8_WO_VLD_SRST);
+       writel(0x1, sys + VP8_RW_DCM_CON);
+       writel(0x1, misc + VP8_RW_MISC_DCM_CON);
+       writel(0x1, hwd + VP8_RW_VP8_CTRL);
+}
+
+static void store_dec_table(struct vdec_vp8_inst *inst)
+{
+       int i, j;
+       u32 addr = 0, val = 0;
+       void __iomem *hwd = inst->reg_base.hwd;
+       u32 *p = &inst->vsi->dec_table[VP8_DEC_TABLE_OFFSET];
+
+       for (i = 0; i < VP8_DEC_TABLE_PROC_LOOP; i++) {
+               writel(addr, hwd + VP8_BSASET);
+               for (j = 0; j < VP8_DEC_TABLE_UNIT ; j++) {
+                       val = *p++;
+                       writel(val, hwd + VP8_BSDSET);
+               }
+               addr += VP8_DEC_TABLE_RW_UNIT;
+       }
+}
+
+static void load_dec_table(struct vdec_vp8_inst *inst)
+{
+       int i;
+       u32 addr = 0;
+       u32 *p = &inst->vsi->dec_table[VP8_DEC_TABLE_OFFSET];
+       void __iomem *hwd = inst->reg_base.hwd;
+
+       for (i = 0; i < VP8_DEC_TABLE_PROC_LOOP; i++) {
+               writel(addr, hwd + VP8_BSASET);
+               /* read total 11 bytes */
+               *p++ = readl(hwd + VP8_BSDSET);
+               *p++ = readl(hwd + VP8_BSDSET);
+               *p++ = readl(hwd + VP8_BSDSET) & 0xFFFFFF;
+               addr += VP8_DEC_TABLE_RW_UNIT;
+       }
+}
+
+static void get_pic_info(struct vdec_vp8_inst *inst, struct vdec_pic_info *pic)
+{
+       *pic = inst->vsi->pic;
+
+       mtk_vcodec_debug(inst, "pic(%d, %d), buf(%d, %d)",
+                        pic->pic_w, pic->pic_h, pic->buf_w, pic->buf_h);
+       mtk_vcodec_debug(inst, "fb size: Y(%d), C(%d)",
+                        pic->fb_sz[0], pic->fb_sz[1]);
+}
+
+static void vp8_dec_finish(struct vdec_vp8_inst *inst)
+{
+       struct vdec_fb_node *node;
+       uint64_t prev_y_dma = inst->vsi->dec.prev_y_dma;
+
+       mtk_vcodec_debug(inst, "prev fb base dma=%llx", prev_y_dma);
+
+       /* put last decode ok frame to fb_free_list */
+       if (prev_y_dma != 0) {
+               list_for_each_entry(node, &inst->fb_use_list, list) {
+                       struct vdec_fb *fb = (struct vdec_fb *)node->fb;
+
+                       if (prev_y_dma == (uint64_t)fb->base_y.dma_addr) {
+                               list_move_tail(&node->list,
+                                              &inst->fb_free_list);
+                               break;
+                       }
+               }
+       }
+
+       /* available_fb_node_list -> fb_use_list */
+       node = list_first_entry(&inst->available_fb_node_list,
+                               struct vdec_fb_node, list);
+       node->fb = inst->cur_fb;
+       list_move_tail(&node->list, &inst->fb_use_list);
+
+       /* available_fb_node_list -> fb_disp_list */
+       if (inst->vsi->dec.show_frame) {
+               node = list_first_entry(&inst->available_fb_node_list,
+                                       struct vdec_fb_node, list);
+               node->fb = inst->cur_fb;
+               list_move_tail(&node->list, &inst->fb_disp_list);
+       }
+}
+
+static void move_fb_list_use_to_free(struct vdec_vp8_inst *inst)
+{
+       struct vdec_fb_node *node, *tmp;
+
+       list_for_each_entry_safe(node, tmp, &inst->fb_use_list, list)
+               list_move_tail(&node->list, &inst->fb_free_list);
+}
+
+static void init_list(struct vdec_vp8_inst *inst)
+{
+       int i;
+
+       INIT_LIST_HEAD(&inst->available_fb_node_list);
+       INIT_LIST_HEAD(&inst->fb_use_list);
+       INIT_LIST_HEAD(&inst->fb_free_list);
+       INIT_LIST_HEAD(&inst->fb_disp_list);
+
+       for (i = 0; i < ARRAY_SIZE(inst->dec_fb); i++) {
+               INIT_LIST_HEAD(&inst->dec_fb[i].list);
+               inst->dec_fb[i].fb = NULL;
+               list_add_tail(&inst->dec_fb[i].list,
+                             &inst->available_fb_node_list);
+       }
+}
+
+static void add_fb_to_free_list(struct vdec_vp8_inst *inst, void *fb)
+{
+       struct vdec_fb_node *node;
+
+       if (fb) {
+               node = list_first_entry(&inst->available_fb_node_list,
+                                       struct vdec_fb_node, list);
+               node->fb = fb;
+               list_move_tail(&node->list, &inst->fb_free_list);
+       }
+}
+
+static int alloc_working_buf(struct vdec_vp8_inst *inst)
+{
+       int err;
+       struct mtk_vcodec_mem *mem = &inst->working_buf;
+
+       mem->size = VP8_WORKING_BUF_SZ;
+       err = mtk_vcodec_mem_alloc(inst->ctx, mem);
+       if (err) {
+               mtk_vcodec_err(inst, "Cannot allocate working buffer");
+               return err;
+       }
+
+       inst->vsi->dec.working_buf_dma = (uint64_t)mem->dma_addr;
+       return 0;
+}
+
+static void free_working_buf(struct vdec_vp8_inst *inst)
+{
+       struct mtk_vcodec_mem *mem = &inst->working_buf;
+
+       if (mem->va)
+               mtk_vcodec_mem_free(inst->ctx, mem);
+
+       inst->vsi->dec.working_buf_dma = 0;
+}
+
+static int vdec_vp8_init(struct mtk_vcodec_ctx *ctx)
+{
+       struct vdec_vp8_inst *inst;
+       int err;
+
+       inst = kzalloc(sizeof(*inst), GFP_KERNEL);
+       if (!inst)
+               return  -ENOMEM;
+
+       inst->ctx = ctx;
+
+       inst->vpu.id = IPI_VDEC_VP8;
+       inst->vpu.ctx = ctx;
+
+       err = vpu_dec_init(&inst->vpu);
+       if (err) {
+               mtk_vcodec_err(inst, "vdec_vp8 init err=%d", err);
+               goto error_free_inst;
+       }
+
+       inst->vsi = (struct vdec_vp8_vsi *)inst->vpu.vsi;
+       init_list(inst);
+       err = alloc_working_buf(inst);
+       if (err)
+               goto error_deinit;
+
+       get_hw_reg_base(inst);
+       mtk_vcodec_debug(inst, "VP8 Instance >> %p", inst);
+
+       ctx->drv_handle = inst;
+       return 0;
+
+error_deinit:
+       vpu_dec_deinit(&inst->vpu);
+error_free_inst:
+       kfree(inst);
+       return err;
+}
+
+static int vdec_vp8_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
+                          struct vdec_fb *fb, bool *res_chg)
+{
+       struct vdec_vp8_inst *inst = (struct vdec_vp8_inst *)h_vdec;
+       struct vdec_vp8_dec_info *dec = &inst->vsi->dec;
+       struct vdec_vpu_inst *vpu = &inst->vpu;
+       unsigned char *bs_va;
+       unsigned int data;
+       int err = 0;
+       uint64_t y_fb_dma;
+       uint64_t c_fb_dma;
+
+       /* bs NULL means flush decoder */
+       if (bs == NULL) {
+               move_fb_list_use_to_free(inst);
+               return vpu_dec_reset(vpu);
+       }
+
+       y_fb_dma = fb ? (u64)fb->base_y.dma_addr : 0;
+       c_fb_dma = fb ? (u64)fb->base_c.dma_addr : 0;
+
+       mtk_vcodec_debug(inst, "+ [%d] FB y_dma=%llx c_dma=%llx fb=%p",
+                        inst->frm_cnt, y_fb_dma, c_fb_dma, fb);
+
+       inst->cur_fb = fb;
+       dec->bs_dma = (unsigned long)bs->dma_addr;
+       dec->bs_sz = bs->size;
+       dec->cur_y_fb_dma = y_fb_dma;
+       dec->cur_c_fb_dma = c_fb_dma;
+
+       mtk_vcodec_debug(inst, "\n + FRAME[%d] +\n", inst->frm_cnt);
+
+       write_hw_segmentation_data(inst);
+       enable_hw_rw_function(inst);
+       store_dec_table(inst);
+
+       bs_va = (unsigned char *)bs->va;
+
+       /* retrieve width/hight and scale info from header */
+       data = (*(bs_va + 9) << 24) | (*(bs_va + 8) << 16) |
+              (*(bs_va + 7) << 8) | *(bs_va + 6);
+       err = vpu_dec_start(vpu, &data, 1);
+       if (err) {
+               add_fb_to_free_list(inst, fb);
+               if (dec->wait_key_frame) {
+                       mtk_vcodec_debug(inst, "wait key frame !");
+                       return 0;
+               }
+
+               goto error;
+       }
+
+       if (dec->resolution_changed) {
+               mtk_vcodec_debug(inst, "- resolution_changed -");
+               *res_chg = true;
+               add_fb_to_free_list(inst, fb);
+               return 0;
+       }
+
+       /* wait decoder done interrupt */
+       mtk_vcodec_wait_for_done_ctx(inst->ctx, MTK_INST_IRQ_RECEIVED,
+                                    WAIT_INTR_TIMEOUT_MS, 0);
+
+       if (inst->vsi->load_data)
+               load_dec_table(inst);
+
+       vp8_dec_finish(inst);
+       read_hw_segmentation_data(inst);
+
+       err = vpu_dec_end(vpu);
+       if (err)
+               goto error;
+
+       mtk_vcodec_debug(inst, "\n - FRAME[%d] - show=%d\n", inst->frm_cnt,
+                        dec->show_frame);
+       inst->frm_cnt++;
+       *res_chg = false;
+       return 0;
+
+error:
+       mtk_vcodec_err(inst, "\n - FRAME[%d] - err=%d\n", inst->frm_cnt, err);
+       return err;
+}
+
+static void get_disp_fb(struct vdec_vp8_inst *inst, struct vdec_fb **out_fb)
+{
+       struct vdec_fb_node *node;
+       struct vdec_fb *fb;
+
+       node = list_first_entry_or_null(&inst->fb_disp_list,
+                                       struct vdec_fb_node, list);
+       if (node) {
+               list_move_tail(&node->list, &inst->available_fb_node_list);
+               fb = (struct vdec_fb *)node->fb;
+               fb->status |= FB_ST_DISPLAY;
+               mtk_vcodec_debug(inst, "[FB] get disp fb %p st=%d",
+                                node->fb, fb->status);
+       } else {
+               fb = NULL;
+               mtk_vcodec_debug(inst, "[FB] there is no disp fb");
+       }
+
+       *out_fb = fb;
+}
+
+static void get_free_fb(struct vdec_vp8_inst *inst, struct vdec_fb **out_fb)
+{
+       struct vdec_fb_node *node;
+       struct vdec_fb *fb;
+
+       node = list_first_entry_or_null(&inst->fb_free_list,
+                                       struct vdec_fb_node, list);
+       if (node) {
+               list_move_tail(&node->list, &inst->available_fb_node_list);
+               fb = (struct vdec_fb *)node->fb;
+               fb->status |= FB_ST_FREE;
+               mtk_vcodec_debug(inst, "[FB] get free fb %p st=%d",
+                                node->fb, fb->status);
+       } else {
+               fb = NULL;
+               mtk_vcodec_debug(inst, "[FB] there is no free fb");
+       }
+
+       *out_fb = fb;
+}
+
+static void get_crop_info(struct vdec_vp8_inst *inst, struct v4l2_rect *cr)
+{
+       cr->left = 0;
+       cr->top = 0;
+       cr->width = inst->vsi->pic.pic_w;
+       cr->height = inst->vsi->pic.pic_h;
+       mtk_vcodec_debug(inst, "get crop info l=%d, t=%d, w=%d, h=%d",
+                        cr->left, cr->top, cr->width, cr->height);
+}
+
+static int vdec_vp8_get_param(void *h_vdec, enum vdec_get_param_type type,
+                             void *out)
+{
+       struct vdec_vp8_inst *inst = (struct vdec_vp8_inst *)h_vdec;
+
+       switch (type) {
+       case GET_PARAM_DISP_FRAME_BUFFER:
+               get_disp_fb(inst, out);
+               break;
+
+       case GET_PARAM_FREE_FRAME_BUFFER:
+               get_free_fb(inst, out);
+               break;
+
+       case GET_PARAM_PIC_INFO:
+               get_pic_info(inst, out);
+               break;
+
+       case GET_PARAM_CROP_INFO:
+               get_crop_info(inst, out);
+               break;
+
+       case GET_PARAM_DPB_SIZE:
+               *((unsigned int *)out) = VP8_DPB_SIZE;
+               break;
+
+       default:
+               mtk_vcodec_err(inst, "invalid get parameter type=%d", type);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void vdec_vp8_deinit(void *h_vdec)
+{
+       struct vdec_vp8_inst *inst = (struct vdec_vp8_inst *)h_vdec;
+
+       mtk_vcodec_debug_enter(inst);
+
+       vpu_dec_deinit(&inst->vpu);
+       free_working_buf(inst);
+       kfree(inst);
+}
+
+const struct vdec_common_if vdec_vp8_if = {
+       .init           = vdec_vp8_init,
+       .decode         = vdec_vp8_decode,
+       .get_param      = vdec_vp8_get_param,
+       .deinit         = vdec_vp8_deinit,
+};
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/vdec/vdec_vp9_if.c b/drivers/media/platform/mediatek/mtk-vcodec/vdec/vdec_vp9_if.c
new file mode 100644 (file)
index 0000000..70b8383
--- /dev/null
@@ -0,0 +1,1028 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Daniel Hsiao <daniel.hsiao@mediatek.com>
+ *     Kai-Sean Yang <kai-sean.yang@mediatek.com>
+ *     Tiffany Lin <tiffany.lin@mediatek.com>
+ */
+
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/syscalls.h>
+#include <linux/delay.h>
+#include <linux/time.h>
+
+#include "../mtk_vcodec_intr.h"
+#include "../vdec_drv_base.h"
+#include "../vdec_vpu_if.h"
+
+#define VP9_SUPER_FRAME_BS_SZ 64
+#define MAX_VP9_DPB_SIZE       9
+
+#define REFS_PER_FRAME 3
+#define MAX_NUM_REF_FRAMES 8
+#define VP9_MAX_FRM_BUF_NUM 9
+#define VP9_MAX_FRM_BUF_NODE_NUM (VP9_MAX_FRM_BUF_NUM * 2)
+#define VP9_SEG_ID_SZ 0x12000
+
+/**
+ * struct vp9_dram_buf - contains buffer info for vpu
+ * @va : cpu address
+ * @pa : iova address
+ * @sz : buffer size
+ * @padding : for 64 bytes alignment
+ */
+struct vp9_dram_buf {
+       unsigned long va;
+       unsigned long pa;
+       unsigned int sz;
+       unsigned int padding;
+};
+
+/**
+ * struct vp9_fb_info - contains frame buffer info
+ * @fb : frmae buffer
+ * @reserved : reserved field used by vpu
+ */
+struct vp9_fb_info {
+       struct vdec_fb *fb;
+       unsigned int reserved[32];
+};
+
+/**
+ * struct vp9_ref_cnt_buf - contains reference buffer information
+ * @buf : referenced frame buffer
+ * @ref_cnt : referenced frame buffer's reference count.
+ *     When reference count=0, remove it from reference list
+ */
+struct vp9_ref_cnt_buf {
+       struct vp9_fb_info buf;
+       unsigned int ref_cnt;
+};
+
+/**
+ * struct vp9_ref_buf - contains current frame's reference buffer information
+ * @buf : reference buffer
+ * @idx : reference buffer index to frm_bufs
+ * @reserved : reserved field used by vpu
+ */
+struct vp9_ref_buf {
+       struct vp9_fb_info *buf;
+       unsigned int idx;
+       unsigned int reserved[6];
+};
+
+/**
+ * struct vp9_sf_ref_fb - contains frame buffer info
+ * @fb : super frame reference frame buffer
+ * @used : this reference frame info entry is used
+ * @padding : for 64 bytes size align
+ */
+struct vp9_sf_ref_fb {
+       struct vdec_fb fb;
+       int used;
+       int padding;
+};
+
+/*
+ * struct vdec_vp9_vsi - shared buffer between host and VPU firmware
+ *     AP-W/R : AP is writer/reader on this item
+ *     VPU-W/R: VPU is write/reader on this item
+ * @sf_bs_buf : super frame backup buffer (AP-W, VPU-R)
+ * @sf_ref_fb : record supoer frame reference buffer information
+ *     (AP-R/W, VPU-R/W)
+ * @sf_next_ref_fb_idx : next available super frame (AP-W, VPU-R)
+ * @sf_frm_cnt : super frame count, filled by vpu (AP-R, VPU-W)
+ * @sf_frm_offset : super frame offset, filled by vpu (AP-R, VPU-W)
+ * @sf_frm_sz : super frame size, filled by vpu (AP-R, VPU-W)
+ * @sf_frm_idx : current super frame (AP-R, VPU-W)
+ * @sf_init : inform super frame info already parsed by vpu (AP-R, VPU-W)
+ * @fb : capture buffer (AP-W, VPU-R)
+ * @bs : bs buffer (AP-W, VPU-R)
+ * @cur_fb : current show capture buffer (AP-R/W, VPU-R/W)
+ * @pic_w : picture width (AP-R, VPU-W)
+ * @pic_h : picture height (AP-R, VPU-W)
+ * @buf_w : codec width (AP-R, VPU-W)
+ * @buf_h : coded height (AP-R, VPU-W)
+ * @buf_sz_y_bs : ufo compressed y plane size (AP-R, VPU-W)
+ * @buf_sz_c_bs : ufo compressed cbcr plane size (AP-R, VPU-W)
+ * @buf_len_sz_y : size used to store y plane ufo info (AP-R, VPU-W)
+ * @buf_len_sz_c : size used to store cbcr plane ufo info (AP-R, VPU-W)
+
+ * @profile : profile sparsed from vpu (AP-R, VPU-W)
+ * @show_frame : [BIT(0)] display this frame or not (AP-R, VPU-W)
+ *     [BIT(1)] reset segment data or not (AP-R, VPU-W)
+ *     [BIT(2)] trig decoder hardware or not (AP-R, VPU-W)
+ *     [BIT(3)] ask VPU to set bits(0~4) accordingly (AP-W, VPU-R)
+ *     [BIT(4)] do not reset segment data before every frame (AP-R, VPU-W)
+ * @show_existing_frame : inform this frame is show existing frame
+ *     (AP-R, VPU-W)
+ * @frm_to_show_idx : index to show frame (AP-R, VPU-W)
+
+ * @refresh_frm_flags : indicate when frame need to refine reference count
+ *     (AP-R, VPU-W)
+ * @resolution_changed : resolution change in this frame (AP-R, VPU-W)
+
+ * @frm_bufs : maintain reference buffer info (AP-R/W, VPU-R/W)
+ * @ref_frm_map : maintain reference buffer map info (AP-R/W, VPU-R/W)
+ * @new_fb_idx : index to frm_bufs array (AP-R, VPU-W)
+ * @frm_num : decoded frame number, include sub-frame count (AP-R, VPU-W)
+ * @mv_buf : motion vector working buffer (AP-W, VPU-R)
+ * @frm_refs : maintain three reference buffer info (AP-R/W, VPU-R/W)
+ * @seg_id_buf : segmentation map working buffer (AP-W, VPU-R)
+ */
+struct vdec_vp9_vsi {
+       unsigned char sf_bs_buf[VP9_SUPER_FRAME_BS_SZ];
+       struct vp9_sf_ref_fb sf_ref_fb[VP9_MAX_FRM_BUF_NUM-1];
+       int sf_next_ref_fb_idx;
+       unsigned int sf_frm_cnt;
+       unsigned int sf_frm_offset[VP9_MAX_FRM_BUF_NUM-1];
+       unsigned int sf_frm_sz[VP9_MAX_FRM_BUF_NUM-1];
+       unsigned int sf_frm_idx;
+       unsigned int sf_init;
+       struct vdec_fb fb;
+       struct mtk_vcodec_mem bs;
+       struct vdec_fb cur_fb;
+       unsigned int pic_w;
+       unsigned int pic_h;
+       unsigned int buf_w;
+       unsigned int buf_h;
+       unsigned int buf_sz_y_bs;
+       unsigned int buf_sz_c_bs;
+       unsigned int buf_len_sz_y;
+       unsigned int buf_len_sz_c;
+       unsigned int profile;
+       unsigned int show_frame;
+       unsigned int show_existing_frame;
+       unsigned int frm_to_show_idx;
+       unsigned int refresh_frm_flags;
+       unsigned int resolution_changed;
+
+       struct vp9_ref_cnt_buf frm_bufs[VP9_MAX_FRM_BUF_NUM];
+       int ref_frm_map[MAX_NUM_REF_FRAMES];
+       unsigned int new_fb_idx;
+       unsigned int frm_num;
+       struct vp9_dram_buf mv_buf;
+
+       struct vp9_ref_buf frm_refs[REFS_PER_FRAME];
+       struct vp9_dram_buf seg_id_buf;
+
+};
+
+/*
+ * struct vdec_vp9_inst - vp9 decode instance
+ * @mv_buf : working buffer for mv
+ * @seg_id_buf : working buffer for segmentation map
+ * @dec_fb : vdec_fb node to link fb to different fb_xxx_list
+ * @available_fb_node_list : current available vdec_fb node
+ * @fb_use_list : current used or referenced vdec_fb
+ * @fb_free_list : current available to free vdec_fb
+ * @fb_disp_list : current available to display vdec_fb
+ * @cur_fb : current frame buffer
+ * @ctx : current decode context
+ * @vpu : vpu instance information
+ * @vsi : shared buffer between host and VPU firmware
+ * @total_frm_cnt : total frame count, it do not include sub-frames in super
+ *         frame
+ * @mem : instance memory information
+ */
+struct vdec_vp9_inst {
+       struct mtk_vcodec_mem mv_buf;
+       struct mtk_vcodec_mem seg_id_buf;
+
+       struct vdec_fb_node dec_fb[VP9_MAX_FRM_BUF_NODE_NUM];
+       struct list_head available_fb_node_list;
+       struct list_head fb_use_list;
+       struct list_head fb_free_list;
+       struct list_head fb_disp_list;
+       struct vdec_fb *cur_fb;
+       struct mtk_vcodec_ctx *ctx;
+       struct vdec_vpu_inst vpu;
+       struct vdec_vp9_vsi *vsi;
+       unsigned int total_frm_cnt;
+       struct mtk_vcodec_mem mem;
+};
+
+static bool vp9_is_sf_ref_fb(struct vdec_vp9_inst *inst, struct vdec_fb *fb)
+{
+       int i;
+       struct vdec_vp9_vsi *vsi = inst->vsi;
+
+       for (i = 0; i < ARRAY_SIZE(vsi->sf_ref_fb); i++) {
+               if (fb == &vsi->sf_ref_fb[i].fb)
+                       return true;
+       }
+       return false;
+}
+
+static struct vdec_fb *vp9_rm_from_fb_use_list(struct vdec_vp9_inst
+                                       *inst, void *addr)
+{
+       struct vdec_fb *fb = NULL;
+       struct vdec_fb_node *node;
+
+       list_for_each_entry(node, &inst->fb_use_list, list) {
+               fb = (struct vdec_fb *)node->fb;
+               if (fb->base_y.va == addr) {
+                       list_move_tail(&node->list,
+                                      &inst->available_fb_node_list);
+                       break;
+               }
+       }
+       return fb;
+}
+
+static void vp9_add_to_fb_free_list(struct vdec_vp9_inst *inst,
+                            struct vdec_fb *fb)
+{
+       struct vdec_fb_node *node;
+
+       if (fb) {
+               node = list_first_entry_or_null(&inst->available_fb_node_list,
+                                       struct vdec_fb_node, list);
+
+               if (node) {
+                       node->fb = fb;
+                       list_move_tail(&node->list, &inst->fb_free_list);
+               }
+       } else {
+               mtk_vcodec_debug(inst, "No free fb node");
+       }
+}
+
+static void vp9_free_sf_ref_fb(struct vdec_fb *fb)
+{
+       struct vp9_sf_ref_fb *sf_ref_fb =
+               container_of(fb, struct vp9_sf_ref_fb, fb);
+
+       sf_ref_fb->used = 0;
+}
+
+static void vp9_ref_cnt_fb(struct vdec_vp9_inst *inst, int *idx,
+                          int new_idx)
+{
+       struct vdec_vp9_vsi *vsi = inst->vsi;
+       int ref_idx = *idx;
+
+       if (ref_idx >= 0 && vsi->frm_bufs[ref_idx].ref_cnt > 0) {
+               vsi->frm_bufs[ref_idx].ref_cnt--;
+
+               if (vsi->frm_bufs[ref_idx].ref_cnt == 0) {
+                       if (!vp9_is_sf_ref_fb(inst,
+                                             vsi->frm_bufs[ref_idx].buf.fb)) {
+                               struct vdec_fb *fb;
+
+                               fb = vp9_rm_from_fb_use_list(inst,
+                                    vsi->frm_bufs[ref_idx].buf.fb->base_y.va);
+                               vp9_add_to_fb_free_list(inst, fb);
+                       } else
+                               vp9_free_sf_ref_fb(
+                                       vsi->frm_bufs[ref_idx].buf.fb);
+               }
+       }
+
+       *idx = new_idx;
+       vsi->frm_bufs[new_idx].ref_cnt++;
+}
+
+static void vp9_free_all_sf_ref_fb(struct vdec_vp9_inst *inst)
+{
+       int i;
+       struct vdec_vp9_vsi *vsi = inst->vsi;
+
+       for (i = 0; i < ARRAY_SIZE(vsi->sf_ref_fb); i++) {
+               if (vsi->sf_ref_fb[i].fb.base_y.va) {
+                       mtk_vcodec_mem_free(inst->ctx,
+                               &vsi->sf_ref_fb[i].fb.base_y);
+                       mtk_vcodec_mem_free(inst->ctx,
+                               &vsi->sf_ref_fb[i].fb.base_c);
+                       vsi->sf_ref_fb[i].used = 0;
+               }
+       }
+}
+
+/* For each sub-frame except the last one, the driver will dynamically
+ * allocate reference buffer by calling vp9_get_sf_ref_fb()
+ * The last sub-frame will use the original fb provided by the
+ * vp9_dec_decode() interface
+ */
+static int vp9_get_sf_ref_fb(struct vdec_vp9_inst *inst)
+{
+       int idx;
+       struct mtk_vcodec_mem *mem_basy_y;
+       struct mtk_vcodec_mem *mem_basy_c;
+       struct vdec_vp9_vsi *vsi = inst->vsi;
+
+       for (idx = 0;
+               idx < ARRAY_SIZE(vsi->sf_ref_fb);
+               idx++) {
+               if (vsi->sf_ref_fb[idx].fb.base_y.va &&
+                   vsi->sf_ref_fb[idx].used == 0) {
+                       return idx;
+               }
+       }
+
+       for (idx = 0;
+               idx < ARRAY_SIZE(vsi->sf_ref_fb);
+               idx++) {
+               if (vsi->sf_ref_fb[idx].fb.base_y.va == NULL)
+                       break;
+       }
+
+       if (idx == ARRAY_SIZE(vsi->sf_ref_fb)) {
+               mtk_vcodec_err(inst, "List Full");
+               return -1;
+       }
+
+       mem_basy_y = &vsi->sf_ref_fb[idx].fb.base_y;
+       mem_basy_y->size = vsi->buf_sz_y_bs +
+               vsi->buf_len_sz_y;
+
+       if (mtk_vcodec_mem_alloc(inst->ctx, mem_basy_y)) {
+               mtk_vcodec_err(inst, "Cannot allocate sf_ref_buf y_buf");
+               return -1;
+       }
+
+       mem_basy_c = &vsi->sf_ref_fb[idx].fb.base_c;
+       mem_basy_c->size = vsi->buf_sz_c_bs +
+               vsi->buf_len_sz_c;
+
+       if (mtk_vcodec_mem_alloc(inst->ctx, mem_basy_c)) {
+               mtk_vcodec_err(inst, "Cannot allocate sf_ref_fb c_buf");
+               return -1;
+       }
+       vsi->sf_ref_fb[idx].used = 0;
+
+       return idx;
+}
+
+static bool vp9_alloc_work_buf(struct vdec_vp9_inst *inst)
+{
+       struct vdec_vp9_vsi *vsi = inst->vsi;
+       int result;
+       struct mtk_vcodec_mem *mem;
+
+       unsigned int max_pic_w;
+       unsigned int max_pic_h;
+
+
+       if (!(inst->ctx->dev->dec_capability &
+               VCODEC_CAPABILITY_4K_DISABLED)) {
+               max_pic_w = VCODEC_DEC_4K_CODED_WIDTH;
+               max_pic_h = VCODEC_DEC_4K_CODED_HEIGHT;
+       } else {
+               max_pic_w = MTK_VDEC_MAX_W;
+               max_pic_h = MTK_VDEC_MAX_H;
+       }
+
+       if ((vsi->pic_w > max_pic_w) ||
+               (vsi->pic_h > max_pic_h)) {
+               mtk_vcodec_err(inst, "Invalid w/h %d/%d",
+                               vsi->pic_w, vsi->pic_h);
+               return false;
+       }
+
+       mtk_vcodec_debug(inst, "BUF CHG(%d): w/h/sb_w/sb_h=%d/%d/%d/%d",
+                       vsi->resolution_changed,
+                       vsi->pic_w,
+                       vsi->pic_h,
+                       vsi->buf_w,
+                       vsi->buf_h);
+
+       mem = &inst->mv_buf;
+       if (mem->va)
+               mtk_vcodec_mem_free(inst->ctx, mem);
+
+       mem->size = ((vsi->buf_w / 64) *
+                   (vsi->buf_h / 64) + 2) * 36 * 16;
+       result = mtk_vcodec_mem_alloc(inst->ctx, mem);
+       if (result) {
+               mem->size = 0;
+               mtk_vcodec_err(inst, "Cannot allocate mv_buf");
+               return false;
+       }
+       /* Set the va again */
+       vsi->mv_buf.va = (unsigned long)mem->va;
+       vsi->mv_buf.pa = (unsigned long)mem->dma_addr;
+       vsi->mv_buf.sz = (unsigned int)mem->size;
+
+
+       mem = &inst->seg_id_buf;
+       if (mem->va)
+               mtk_vcodec_mem_free(inst->ctx, mem);
+
+       mem->size = VP9_SEG_ID_SZ;
+       result = mtk_vcodec_mem_alloc(inst->ctx, mem);
+       if (result) {
+               mem->size = 0;
+               mtk_vcodec_err(inst, "Cannot allocate seg_id_buf");
+               return false;
+       }
+       /* Set the va again */
+       vsi->seg_id_buf.va = (unsigned long)mem->va;
+       vsi->seg_id_buf.pa = (unsigned long)mem->dma_addr;
+       vsi->seg_id_buf.sz = (unsigned int)mem->size;
+
+
+       vp9_free_all_sf_ref_fb(inst);
+       vsi->sf_next_ref_fb_idx = vp9_get_sf_ref_fb(inst);
+
+       return true;
+}
+
+static bool vp9_add_to_fb_disp_list(struct vdec_vp9_inst *inst,
+                            struct vdec_fb *fb)
+{
+       struct vdec_fb_node *node;
+
+       if (!fb) {
+               mtk_vcodec_err(inst, "fb == NULL");
+               return false;
+       }
+
+       node = list_first_entry_or_null(&inst->available_fb_node_list,
+                                       struct vdec_fb_node, list);
+       if (node) {
+               node->fb = fb;
+               list_move_tail(&node->list, &inst->fb_disp_list);
+       } else {
+               mtk_vcodec_err(inst, "No available fb node");
+               return false;
+       }
+
+       return true;
+}
+
+/* If any buffer updating is signaled it should be done here. */
+static void vp9_swap_frm_bufs(struct vdec_vp9_inst *inst)
+{
+       struct vdec_vp9_vsi *vsi = inst->vsi;
+       struct vp9_fb_info *frm_to_show;
+       int ref_index = 0, mask;
+
+       for (mask = vsi->refresh_frm_flags; mask; mask >>= 1) {
+               if (mask & 1)
+                       vp9_ref_cnt_fb(inst, &vsi->ref_frm_map[ref_index],
+                                      vsi->new_fb_idx);
+               ++ref_index;
+       }
+
+       frm_to_show = &vsi->frm_bufs[vsi->new_fb_idx].buf;
+       vsi->frm_bufs[vsi->new_fb_idx].ref_cnt--;
+
+       if (frm_to_show->fb != inst->cur_fb) {
+               /* This frame is show exist frame and no decode output
+                * copy frame data from frm_to_show to current CAPTURE
+                * buffer
+                */
+               if ((frm_to_show->fb != NULL) &&
+                       (inst->cur_fb->base_y.size >=
+                       frm_to_show->fb->base_y.size) &&
+                       (inst->cur_fb->base_c.size >=
+                       frm_to_show->fb->base_c.size)) {
+                       memcpy((void *)inst->cur_fb->base_y.va,
+                               (void *)frm_to_show->fb->base_y.va,
+                               frm_to_show->fb->base_y.size);
+                       memcpy((void *)inst->cur_fb->base_c.va,
+                               (void *)frm_to_show->fb->base_c.va,
+                               frm_to_show->fb->base_c.size);
+               } else {
+                       /* After resolution change case, current CAPTURE buffer
+                        * may have less buffer size than frm_to_show buffer
+                        * size
+                        */
+                       if (frm_to_show->fb != NULL)
+                               mtk_vcodec_err(inst,
+                                       "inst->cur_fb->base_y.size=%zu, frm_to_show->fb.base_y.size=%zu",
+                                       inst->cur_fb->base_y.size,
+                                       frm_to_show->fb->base_y.size);
+               }
+               if (!vp9_is_sf_ref_fb(inst, inst->cur_fb)) {
+                       if (vsi->show_frame & BIT(0))
+                               vp9_add_to_fb_disp_list(inst, inst->cur_fb);
+               }
+       } else {
+               if (!vp9_is_sf_ref_fb(inst, inst->cur_fb)) {
+                       if (vsi->show_frame & BIT(0))
+                               vp9_add_to_fb_disp_list(inst, frm_to_show->fb);
+               }
+       }
+
+       /* when ref_cnt ==0, move this fb to fb_free_list. v4l2 driver will
+        * clean fb_free_list
+        */
+       if (vsi->frm_bufs[vsi->new_fb_idx].ref_cnt == 0) {
+               if (!vp9_is_sf_ref_fb(
+                       inst, vsi->frm_bufs[vsi->new_fb_idx].buf.fb)) {
+                       struct vdec_fb *fb;
+
+                       fb = vp9_rm_from_fb_use_list(inst,
+                       vsi->frm_bufs[vsi->new_fb_idx].buf.fb->base_y.va);
+
+                       vp9_add_to_fb_free_list(inst, fb);
+               } else {
+                       vp9_free_sf_ref_fb(
+                               vsi->frm_bufs[vsi->new_fb_idx].buf.fb);
+               }
+       }
+
+       /* if this super frame and it is not last sub-frame, get next fb for
+        * sub-frame decode
+        */
+       if (vsi->sf_frm_cnt > 0 && vsi->sf_frm_idx != vsi->sf_frm_cnt - 1)
+               vsi->sf_next_ref_fb_idx = vp9_get_sf_ref_fb(inst);
+}
+
+static bool vp9_wait_dec_end(struct vdec_vp9_inst *inst)
+{
+       struct mtk_vcodec_ctx *ctx = inst->ctx;
+
+       mtk_vcodec_wait_for_done_ctx(inst->ctx,
+                       MTK_INST_IRQ_RECEIVED,
+                       WAIT_INTR_TIMEOUT_MS, 0);
+
+       if (ctx->irq_status & MTK_VDEC_IRQ_STATUS_DEC_SUCCESS)
+               return true;
+       else
+               return false;
+}
+
+static struct vdec_vp9_inst *vp9_alloc_inst(struct mtk_vcodec_ctx *ctx)
+{
+       int result;
+       struct mtk_vcodec_mem mem;
+       struct vdec_vp9_inst *inst;
+
+       memset(&mem, 0, sizeof(mem));
+       mem.size = sizeof(struct vdec_vp9_inst);
+       result = mtk_vcodec_mem_alloc(ctx, &mem);
+       if (result)
+               return NULL;
+
+       inst = mem.va;
+       inst->mem = mem;
+
+       return inst;
+}
+
+static void vp9_free_inst(struct vdec_vp9_inst *inst)
+{
+       struct mtk_vcodec_mem mem;
+
+       mem = inst->mem;
+       if (mem.va)
+               mtk_vcodec_mem_free(inst->ctx, &mem);
+}
+
+static bool vp9_decode_end_proc(struct vdec_vp9_inst *inst)
+{
+       struct vdec_vp9_vsi *vsi = inst->vsi;
+       bool ret = false;
+
+       if (!vsi->show_existing_frame) {
+               ret = vp9_wait_dec_end(inst);
+               if (!ret) {
+                       mtk_vcodec_err(inst, "Decode failed, Decode Timeout @[%d]",
+                               vsi->frm_num);
+                       return false;
+               }
+
+               if (vpu_dec_end(&inst->vpu)) {
+                       mtk_vcodec_err(inst, "vp9_dec_vpu_end failed");
+                       return false;
+               }
+               mtk_vcodec_debug(inst, "Decode Ok @%d (%d/%d)", vsi->frm_num,
+                               vsi->pic_w, vsi->pic_h);
+       } else {
+               mtk_vcodec_debug(inst, "Decode Ok @%d (show_existing_frame)",
+                               vsi->frm_num);
+       }
+
+       vp9_swap_frm_bufs(inst);
+       vsi->frm_num++;
+       return true;
+}
+
+static bool vp9_is_last_sub_frm(struct vdec_vp9_inst *inst)
+{
+       struct vdec_vp9_vsi *vsi = inst->vsi;
+
+       if (vsi->sf_frm_cnt <= 0 || vsi->sf_frm_idx == vsi->sf_frm_cnt)
+               return true;
+
+       return false;
+}
+
+static struct vdec_fb *vp9_rm_from_fb_disp_list(struct vdec_vp9_inst *inst)
+{
+       struct vdec_fb_node *node;
+       struct vdec_fb *fb = NULL;
+
+       node = list_first_entry_or_null(&inst->fb_disp_list,
+                                       struct vdec_fb_node, list);
+       if (node) {
+               fb = (struct vdec_fb *)node->fb;
+               fb->status |= FB_ST_DISPLAY;
+               list_move_tail(&node->list, &inst->available_fb_node_list);
+               mtk_vcodec_debug(inst, "[FB] get disp fb %p st=%d",
+                                node->fb, fb->status);
+       } else
+               mtk_vcodec_debug(inst, "[FB] there is no disp fb");
+
+       return fb;
+}
+
+static bool vp9_add_to_fb_use_list(struct vdec_vp9_inst *inst,
+                           struct vdec_fb *fb)
+{
+       struct vdec_fb_node *node;
+
+       if (!fb) {
+               mtk_vcodec_debug(inst, "fb == NULL");
+               return false;
+       }
+
+       node = list_first_entry_or_null(&inst->available_fb_node_list,
+                                       struct vdec_fb_node, list);
+       if (node) {
+               node->fb = fb;
+               list_move_tail(&node->list, &inst->fb_use_list);
+       } else {
+               mtk_vcodec_err(inst, "No free fb node");
+               return false;
+       }
+       return true;
+}
+
+static void vp9_reset(struct vdec_vp9_inst *inst)
+{
+       struct vdec_fb_node *node, *tmp;
+
+       list_for_each_entry_safe(node, tmp, &inst->fb_use_list, list)
+               list_move_tail(&node->list, &inst->fb_free_list);
+
+       vp9_free_all_sf_ref_fb(inst);
+       inst->vsi->sf_next_ref_fb_idx = vp9_get_sf_ref_fb(inst);
+
+       if (vpu_dec_reset(&inst->vpu))
+               mtk_vcodec_err(inst, "vp9_dec_vpu_reset failed");
+
+       /* Set the va again, since vpu_dec_reset will clear mv_buf in vpu */
+       inst->vsi->mv_buf.va = (unsigned long)inst->mv_buf.va;
+       inst->vsi->mv_buf.pa = (unsigned long)inst->mv_buf.dma_addr;
+       inst->vsi->mv_buf.sz = (unsigned long)inst->mv_buf.size;
+
+       /* Set the va again, since vpu_dec_reset will clear seg_id_buf in vpu */
+       inst->vsi->seg_id_buf.va = (unsigned long)inst->seg_id_buf.va;
+       inst->vsi->seg_id_buf.pa = (unsigned long)inst->seg_id_buf.dma_addr;
+       inst->vsi->seg_id_buf.sz = (unsigned long)inst->seg_id_buf.size;
+
+}
+
+static void init_all_fb_lists(struct vdec_vp9_inst *inst)
+{
+       int i;
+
+       INIT_LIST_HEAD(&inst->available_fb_node_list);
+       INIT_LIST_HEAD(&inst->fb_use_list);
+       INIT_LIST_HEAD(&inst->fb_free_list);
+       INIT_LIST_HEAD(&inst->fb_disp_list);
+
+       for (i = 0; i < ARRAY_SIZE(inst->dec_fb); i++) {
+               INIT_LIST_HEAD(&inst->dec_fb[i].list);
+               inst->dec_fb[i].fb = NULL;
+               list_add_tail(&inst->dec_fb[i].list,
+                             &inst->available_fb_node_list);
+       }
+}
+
+static void get_pic_info(struct vdec_vp9_inst *inst, struct vdec_pic_info *pic)
+{
+       pic->fb_sz[0] = inst->vsi->buf_sz_y_bs + inst->vsi->buf_len_sz_y;
+       pic->fb_sz[1] = inst->vsi->buf_sz_c_bs + inst->vsi->buf_len_sz_c;
+
+       pic->pic_w = inst->vsi->pic_w;
+       pic->pic_h = inst->vsi->pic_h;
+       pic->buf_w = inst->vsi->buf_w;
+       pic->buf_h = inst->vsi->buf_h;
+
+       mtk_vcodec_debug(inst, "pic(%d, %d), buf(%d, %d)",
+                pic->pic_w, pic->pic_h, pic->buf_w, pic->buf_h);
+       mtk_vcodec_debug(inst, "fb size: Y(%d), C(%d)",
+               pic->fb_sz[0],
+               pic->fb_sz[1]);
+}
+
+static void get_disp_fb(struct vdec_vp9_inst *inst, struct vdec_fb **out_fb)
+{
+
+       *out_fb = vp9_rm_from_fb_disp_list(inst);
+       if (*out_fb)
+               (*out_fb)->status |= FB_ST_DISPLAY;
+}
+
+static void get_free_fb(struct vdec_vp9_inst *inst, struct vdec_fb **out_fb)
+{
+       struct vdec_fb_node *node;
+       struct vdec_fb *fb = NULL;
+
+       node = list_first_entry_or_null(&inst->fb_free_list,
+                                       struct vdec_fb_node, list);
+       if (node) {
+               list_move_tail(&node->list, &inst->available_fb_node_list);
+               fb = (struct vdec_fb *)node->fb;
+               fb->status |= FB_ST_FREE;
+               mtk_vcodec_debug(inst, "[FB] get free fb %p st=%d",
+                                node->fb, fb->status);
+       } else {
+               mtk_vcodec_debug(inst, "[FB] there is no free fb");
+       }
+
+       *out_fb = fb;
+}
+
+static int validate_vsi_array_indexes(struct vdec_vp9_inst *inst,
+               struct vdec_vp9_vsi *vsi) {
+       if (vsi->sf_frm_idx >= VP9_MAX_FRM_BUF_NUM - 1) {
+               mtk_vcodec_err(inst, "Invalid vsi->sf_frm_idx=%u.",
+                               vsi->sf_frm_idx);
+               return -EIO;
+       }
+       if (vsi->frm_to_show_idx >= VP9_MAX_FRM_BUF_NUM) {
+               mtk_vcodec_err(inst, "Invalid vsi->frm_to_show_idx=%u.",
+                               vsi->frm_to_show_idx);
+               return -EIO;
+       }
+       if (vsi->new_fb_idx >= VP9_MAX_FRM_BUF_NUM) {
+               mtk_vcodec_err(inst, "Invalid vsi->new_fb_idx=%u.",
+                               vsi->new_fb_idx);
+               return -EIO;
+       }
+       return 0;
+}
+
+static void vdec_vp9_deinit(void *h_vdec)
+{
+       struct vdec_vp9_inst *inst = (struct vdec_vp9_inst *)h_vdec;
+       struct mtk_vcodec_mem *mem;
+       int ret = 0;
+
+       ret = vpu_dec_deinit(&inst->vpu);
+       if (ret)
+               mtk_vcodec_err(inst, "vpu_dec_deinit failed");
+
+       mem = &inst->mv_buf;
+       if (mem->va)
+               mtk_vcodec_mem_free(inst->ctx, mem);
+
+       mem = &inst->seg_id_buf;
+       if (mem->va)
+               mtk_vcodec_mem_free(inst->ctx, mem);
+
+       vp9_free_all_sf_ref_fb(inst);
+       vp9_free_inst(inst);
+}
+
+static int vdec_vp9_init(struct mtk_vcodec_ctx *ctx)
+{
+       struct vdec_vp9_inst *inst;
+
+       inst = vp9_alloc_inst(ctx);
+       if (!inst)
+               return -ENOMEM;
+
+       inst->total_frm_cnt = 0;
+       inst->ctx = ctx;
+
+       inst->vpu.id = IPI_VDEC_VP9;
+       inst->vpu.ctx = ctx;
+
+       if (vpu_dec_init(&inst->vpu)) {
+               mtk_vcodec_err(inst, "vp9_dec_vpu_init failed");
+               goto err_deinit_inst;
+       }
+
+       inst->vsi = (struct vdec_vp9_vsi *)inst->vpu.vsi;
+
+       inst->vsi->show_frame |= BIT(3);
+
+       init_all_fb_lists(inst);
+
+       ctx->drv_handle = inst;
+       return 0;
+
+err_deinit_inst:
+       vp9_free_inst(inst);
+
+       return -EINVAL;
+}
+
+static int vdec_vp9_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
+                          struct vdec_fb *fb, bool *res_chg)
+{
+       int ret = 0;
+       struct vdec_vp9_inst *inst = (struct vdec_vp9_inst *)h_vdec;
+       struct vdec_vp9_vsi *vsi = inst->vsi;
+       u32 data[3];
+       int i;
+
+       *res_chg = false;
+
+       if ((bs == NULL) && (fb == NULL)) {
+               mtk_vcodec_debug(inst, "[EOS]");
+               vp9_reset(inst);
+               return ret;
+       }
+
+       if (bs == NULL) {
+               mtk_vcodec_err(inst, "bs == NULL");
+               return -EINVAL;
+       }
+
+       mtk_vcodec_debug(inst, "Input BS Size = %zu", bs->size);
+
+       while (1) {
+               struct vdec_fb *cur_fb = NULL;
+
+               data[0] = *((unsigned int *)bs->va);
+               data[1] = *((unsigned int *)(bs->va + 4));
+               data[2] = *((unsigned int *)(bs->va + 8));
+
+               vsi->bs = *bs;
+
+               if (fb)
+                       vsi->fb = *fb;
+
+               if (!vsi->sf_init) {
+                       unsigned int sf_bs_sz;
+                       unsigned int sf_bs_off;
+                       unsigned char *sf_bs_src;
+                       unsigned char *sf_bs_dst;
+
+                       sf_bs_sz = bs->size > VP9_SUPER_FRAME_BS_SZ ?
+                                       VP9_SUPER_FRAME_BS_SZ : bs->size;
+                       sf_bs_off = VP9_SUPER_FRAME_BS_SZ - sf_bs_sz;
+                       sf_bs_src = bs->va + bs->size - sf_bs_sz;
+                       sf_bs_dst = vsi->sf_bs_buf + sf_bs_off;
+                       memcpy(sf_bs_dst, sf_bs_src, sf_bs_sz);
+               } else {
+                       if ((vsi->sf_frm_cnt > 0) &&
+                               (vsi->sf_frm_idx < vsi->sf_frm_cnt)) {
+                               unsigned int idx = vsi->sf_frm_idx;
+
+                               memcpy((void *)bs->va,
+                                       (void *)(bs->va +
+                                       vsi->sf_frm_offset[idx]),
+                                       vsi->sf_frm_sz[idx]);
+                       }
+               }
+
+               if (!(vsi->show_frame & BIT(4)))
+                       memset(inst->seg_id_buf.va, 0, inst->seg_id_buf.size);
+
+               ret = vpu_dec_start(&inst->vpu, data, 3);
+               if (ret) {
+                       mtk_vcodec_err(inst, "vpu_dec_start failed");
+                       goto DECODE_ERROR;
+               }
+
+               if (vsi->show_frame & BIT(1)) {
+                       memset(inst->seg_id_buf.va, 0, inst->seg_id_buf.size);
+
+                       if (vsi->show_frame & BIT(2)) {
+                               ret = vpu_dec_start(&inst->vpu, NULL, 0);
+                               if (ret) {
+                                       mtk_vcodec_err(inst, "vpu trig decoder failed");
+                                       goto DECODE_ERROR;
+                               }
+                       }
+               }
+
+               ret = validate_vsi_array_indexes(inst, vsi);
+               if (ret) {
+                       mtk_vcodec_err(inst, "Invalid values from VPU.");
+                       goto DECODE_ERROR;
+               }
+
+               if (vsi->resolution_changed) {
+                       if (!vp9_alloc_work_buf(inst)) {
+                               ret = -EIO;
+                               goto DECODE_ERROR;
+                       }
+               }
+
+               if (vsi->sf_frm_cnt > 0) {
+                       cur_fb = &vsi->sf_ref_fb[vsi->sf_next_ref_fb_idx].fb;
+
+                       if (vsi->sf_frm_idx < vsi->sf_frm_cnt)
+                               inst->cur_fb = cur_fb;
+                       else
+                               inst->cur_fb = fb;
+               } else {
+                       inst->cur_fb = fb;
+               }
+
+               vsi->frm_bufs[vsi->new_fb_idx].buf.fb = inst->cur_fb;
+               if (!vp9_is_sf_ref_fb(inst, inst->cur_fb))
+                       vp9_add_to_fb_use_list(inst, inst->cur_fb);
+
+               mtk_vcodec_debug(inst, "[#pic %d]", vsi->frm_num);
+
+               if (vsi->show_existing_frame)
+                       mtk_vcodec_debug(inst,
+                               "drv->new_fb_idx=%d, drv->frm_to_show_idx=%d",
+                               vsi->new_fb_idx, vsi->frm_to_show_idx);
+
+               if (vsi->show_existing_frame && (vsi->frm_to_show_idx <
+                                       VP9_MAX_FRM_BUF_NUM)) {
+                       mtk_vcodec_debug(inst,
+                               "Skip Decode drv->new_fb_idx=%d, drv->frm_to_show_idx=%d",
+                               vsi->new_fb_idx, vsi->frm_to_show_idx);
+
+                       vp9_ref_cnt_fb(inst, &vsi->new_fb_idx,
+                                       vsi->frm_to_show_idx);
+               }
+
+               /* VPU assign the buffer pointer in its address space,
+                * reassign here
+                */
+               for (i = 0; i < ARRAY_SIZE(vsi->frm_refs); i++) {
+                       unsigned int idx = vsi->frm_refs[i].idx;
+
+                       vsi->frm_refs[i].buf = &vsi->frm_bufs[idx].buf;
+               }
+
+               if (vsi->resolution_changed) {
+                       *res_chg = true;
+                       mtk_vcodec_debug(inst, "VDEC_ST_RESOLUTION_CHANGED");
+
+                       ret = 0;
+                       goto DECODE_ERROR;
+               }
+
+               if (!vp9_decode_end_proc(inst)) {
+                       mtk_vcodec_err(inst, "vp9_decode_end_proc");
+                       ret = -EINVAL;
+                       goto DECODE_ERROR;
+               }
+
+               if (vp9_is_last_sub_frm(inst))
+                       break;
+
+       }
+       inst->total_frm_cnt++;
+
+DECODE_ERROR:
+       if (ret < 0)
+               vp9_add_to_fb_free_list(inst, fb);
+
+       return ret;
+}
+
+static void get_crop_info(struct vdec_vp9_inst *inst, struct v4l2_rect *cr)
+{
+       cr->left = 0;
+       cr->top = 0;
+       cr->width = inst->vsi->pic_w;
+       cr->height = inst->vsi->pic_h;
+       mtk_vcodec_debug(inst, "get crop info l=%d, t=%d, w=%d, h=%d\n",
+                        cr->left, cr->top, cr->width, cr->height);
+}
+
+static int vdec_vp9_get_param(void *h_vdec, enum vdec_get_param_type type,
+                             void *out)
+{
+       struct vdec_vp9_inst *inst = (struct vdec_vp9_inst *)h_vdec;
+       int ret = 0;
+
+       switch (type) {
+       case GET_PARAM_DISP_FRAME_BUFFER:
+               get_disp_fb(inst, out);
+               break;
+       case GET_PARAM_FREE_FRAME_BUFFER:
+               get_free_fb(inst, out);
+               break;
+       case GET_PARAM_PIC_INFO:
+               get_pic_info(inst, out);
+               break;
+       case GET_PARAM_DPB_SIZE:
+               *((unsigned int *)out) = MAX_VP9_DPB_SIZE;
+               break;
+       case GET_PARAM_CROP_INFO:
+               get_crop_info(inst, out);
+               break;
+       default:
+               mtk_vcodec_err(inst, "not supported param type %d", type);
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+const struct vdec_common_if vdec_vp9_if = {
+       .init           = vdec_vp9_init,
+       .decode         = vdec_vp9_decode,
+       .get_param      = vdec_vp9_get_param,
+       .deinit         = vdec_vp9_deinit,
+};
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/vdec_drv_base.h b/drivers/media/platform/mediatek/mtk-vcodec/vdec_drv_base.h
new file mode 100644 (file)
index 0000000..e913f96
--- /dev/null
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: PC Chen <pc.chen@mediatek.com>
+ */
+
+#ifndef _VDEC_DRV_BASE_
+#define _VDEC_DRV_BASE_
+
+#include "vdec_drv_if.h"
+
+struct vdec_common_if {
+       /**
+        * (*init)() - initialize decode driver
+        * @ctx     : [in] mtk v4l2 context
+        * @h_vdec  : [out] driver handle
+        */
+       int (*init)(struct mtk_vcodec_ctx *ctx);
+
+       /**
+        * (*decode)() - trigger decode
+        * @h_vdec  : [in] driver handle
+        * @bs      : [in] input bitstream
+        * @fb      : [in] frame buffer to store decoded frame
+        * @res_chg : [out] resolution change happen
+        */
+       int (*decode)(void *h_vdec, struct mtk_vcodec_mem *bs,
+                     struct vdec_fb *fb, bool *res_chg);
+
+       /**
+        * (*get_param)() - get driver's parameter
+        * @h_vdec : [in] driver handle
+        * @type   : [in] input parameter type
+        * @out    : [out] buffer to store query result
+        */
+       int (*get_param)(void *h_vdec, enum vdec_get_param_type type,
+                        void *out);
+
+       /**
+        * (*deinit)() - deinitialize driver.
+        * @h_vdec : [in] driver handle to be deinit
+        */
+       void (*deinit)(void *h_vdec);
+};
+
+#endif
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/vdec_drv_if.c b/drivers/media/platform/mediatek/mtk-vcodec/vdec_drv_if.c
new file mode 100644 (file)
index 0000000..05a5b24
--- /dev/null
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: PC Chen <pc.chen@mediatek.com>
+ *         Tiffany Lin <tiffany.lin@mediatek.com>
+ */
+
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include "vdec_drv_if.h"
+#include "mtk_vcodec_dec.h"
+#include "vdec_drv_base.h"
+#include "mtk_vcodec_dec_pm.h"
+
+int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc)
+{
+       int ret = 0;
+
+       switch (fourcc) {
+       case V4L2_PIX_FMT_H264_SLICE:
+               ctx->dec_if = &vdec_h264_slice_if;
+               break;
+       case V4L2_PIX_FMT_H264:
+               ctx->dec_if = &vdec_h264_if;
+               ctx->hw_id = MTK_VDEC_CORE;
+               break;
+       case V4L2_PIX_FMT_VP8:
+               ctx->dec_if = &vdec_vp8_if;
+               ctx->hw_id = MTK_VDEC_CORE;
+               break;
+       case V4L2_PIX_FMT_VP9:
+               ctx->dec_if = &vdec_vp9_if;
+               ctx->hw_id = MTK_VDEC_CORE;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       mtk_vdec_lock(ctx);
+       mtk_vcodec_dec_clock_on(ctx->dev, ctx->hw_id);
+       ret = ctx->dec_if->init(ctx);
+       mtk_vcodec_dec_clock_off(ctx->dev, ctx->hw_id);
+       mtk_vdec_unlock(ctx);
+
+       return ret;
+}
+
+int vdec_if_decode(struct mtk_vcodec_ctx *ctx, struct mtk_vcodec_mem *bs,
+                  struct vdec_fb *fb, bool *res_chg)
+{
+       int ret = 0;
+
+       if (bs) {
+               if ((bs->dma_addr & 63) != 0) {
+                       mtk_v4l2_err("bs dma_addr should 64 byte align");
+                       return -EINVAL;
+               }
+       }
+
+       if (fb) {
+               if (((fb->base_y.dma_addr & 511) != 0) ||
+                   ((fb->base_c.dma_addr & 511) != 0)) {
+                       mtk_v4l2_err("frame buffer dma_addr should 512 byte align");
+                       return -EINVAL;
+               }
+       }
+
+       if (!ctx->drv_handle)
+               return -EIO;
+
+       mtk_vdec_lock(ctx);
+
+       mtk_vcodec_set_curr_ctx(ctx->dev, ctx, ctx->hw_id);
+       mtk_vcodec_dec_clock_on(ctx->dev, ctx->hw_id);
+       ret = ctx->dec_if->decode(ctx->drv_handle, bs, fb, res_chg);
+       mtk_vcodec_dec_clock_off(ctx->dev, ctx->hw_id);
+       mtk_vcodec_set_curr_ctx(ctx->dev, NULL, ctx->hw_id);
+
+       mtk_vdec_unlock(ctx);
+
+       return ret;
+}
+
+int vdec_if_get_param(struct mtk_vcodec_ctx *ctx, enum vdec_get_param_type type,
+                     void *out)
+{
+       int ret = 0;
+
+       if (!ctx->drv_handle)
+               return -EIO;
+
+       mtk_vdec_lock(ctx);
+       ret = ctx->dec_if->get_param(ctx->drv_handle, type, out);
+       mtk_vdec_unlock(ctx);
+
+       return ret;
+}
+
+void vdec_if_deinit(struct mtk_vcodec_ctx *ctx)
+{
+       if (!ctx->drv_handle)
+               return;
+
+       mtk_vdec_lock(ctx);
+       mtk_vcodec_dec_clock_on(ctx->dev, ctx->hw_id);
+       ctx->dec_if->deinit(ctx->drv_handle);
+       mtk_vcodec_dec_clock_off(ctx->dev, ctx->hw_id);
+       mtk_vdec_unlock(ctx);
+
+       ctx->drv_handle = NULL;
+}
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/vdec_drv_if.h b/drivers/media/platform/mediatek/mtk-vcodec/vdec_drv_if.h
new file mode 100644 (file)
index 0000000..d467e8a
--- /dev/null
@@ -0,0 +1,100 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: PC Chen <pc.chen@mediatek.com>
+ *                Tiffany Lin <tiffany.lin@mediatek.com>
+ */
+
+#ifndef _VDEC_DRV_IF_H_
+#define _VDEC_DRV_IF_H_
+
+#include "mtk_vcodec_drv.h"
+#include "mtk_vcodec_dec.h"
+#include "mtk_vcodec_util.h"
+
+
+/**
+ * enum vdec_fb_status  - decoder frame buffer status
+ * @FB_ST_NORMAL: initial state
+ * @FB_ST_DISPLAY: frame buffer is ready to be displayed
+ * @FB_ST_FREE: frame buffer is not used by decoder any more
+ */
+enum vdec_fb_status {
+       FB_ST_NORMAL            = 0,
+       FB_ST_DISPLAY           = (1 << 0),
+       FB_ST_FREE              = (1 << 1)
+};
+
+/* For GET_PARAM_DISP_FRAME_BUFFER and GET_PARAM_FREE_FRAME_BUFFER,
+ * the caller does not own the returned buffer. The buffer will not be
+ *                             released before vdec_if_deinit.
+ * GET_PARAM_DISP_FRAME_BUFFER : get next displayable frame buffer,
+ *                             struct vdec_fb**
+ * GET_PARAM_FREE_FRAME_BUFFER : get non-referenced framebuffer, vdec_fb**
+ * GET_PARAM_PIC_INFO          : get picture info, struct vdec_pic_info*
+ * GET_PARAM_CROP_INFO         : get crop info, struct v4l2_crop*
+ * GET_PARAM_DPB_SIZE          : get dpb size, unsigned int*
+ */
+enum vdec_get_param_type {
+       GET_PARAM_DISP_FRAME_BUFFER,
+       GET_PARAM_FREE_FRAME_BUFFER,
+       GET_PARAM_PIC_INFO,
+       GET_PARAM_CROP_INFO,
+       GET_PARAM_DPB_SIZE
+};
+
+/**
+ * struct vdec_fb_node  - decoder frame buffer node
+ * @list       : list to hold this node
+ * @fb : point to frame buffer (vdec_fb), fb could point to frame buffer and
+ *     working buffer this is for maintain buffers in different state
+ */
+struct vdec_fb_node {
+       struct list_head list;
+       struct vdec_fb *fb;
+};
+
+extern const struct vdec_common_if vdec_h264_if;
+extern const struct vdec_common_if vdec_h264_slice_if;
+extern const struct vdec_common_if vdec_vp8_if;
+extern const struct vdec_common_if vdec_vp9_if;
+
+/**
+ * vdec_if_init() - initialize decode driver
+ * @ctx        : [in] v4l2 context
+ * @fourcc     : [in] video format fourcc, V4L2_PIX_FMT_H264/VP8/VP9..
+ */
+int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc);
+
+/**
+ * vdec_if_deinit() - deinitialize decode driver
+ * @ctx        : [in] v4l2 context
+ *
+ */
+void vdec_if_deinit(struct mtk_vcodec_ctx *ctx);
+
+/**
+ * vdec_if_decode() - trigger decode
+ * @ctx        : [in] v4l2 context
+ * @bs : [in] input bitstream
+ * @fb : [in] frame buffer to store decoded frame, when null means parse
+ *     header only
+ * @res_chg    : [out] resolution change happens if current bs have different
+ *     picture width/height
+ * Note: To flush the decoder when reaching EOF, set input bitstream as NULL.
+ *
+ * Return: 0 on success. -EIO on unrecoverable error.
+ */
+int vdec_if_decode(struct mtk_vcodec_ctx *ctx, struct mtk_vcodec_mem *bs,
+                  struct vdec_fb *fb, bool *res_chg);
+
+/**
+ * vdec_if_get_param() - get driver's parameter
+ * @ctx        : [in] v4l2 context
+ * @type       : [in] input parameter type
+ * @out        : [out] buffer to store query result
+ */
+int vdec_if_get_param(struct mtk_vcodec_ctx *ctx, enum vdec_get_param_type type,
+                     void *out);
+
+#endif
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/vdec_ipi_msg.h b/drivers/media/platform/mediatek/mtk-vcodec/vdec_ipi_msg.h
new file mode 100644 (file)
index 0000000..bf54d6d
--- /dev/null
@@ -0,0 +1,117 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: PC Chen <pc.chen@mediatek.com>
+ */
+
+#ifndef _VDEC_IPI_MSG_H_
+#define _VDEC_IPI_MSG_H_
+
+/*
+ * enum vdec_ipi_msgid - message id between AP and VPU
+ * @AP_IPIMSG_XXX      : AP to VPU cmd message id
+ * @VPU_IPIMSG_XXX_ACK : VPU ack AP cmd message id
+ */
+enum vdec_ipi_msgid {
+       AP_IPIMSG_DEC_INIT = 0xA000,
+       AP_IPIMSG_DEC_START = 0xA001,
+       AP_IPIMSG_DEC_END = 0xA002,
+       AP_IPIMSG_DEC_DEINIT = 0xA003,
+       AP_IPIMSG_DEC_RESET = 0xA004,
+       AP_IPIMSG_DEC_CORE = 0xA005,
+       AP_IPIMSG_DEC_CORE_END = 0xA006,
+
+       VPU_IPIMSG_DEC_INIT_ACK = 0xB000,
+       VPU_IPIMSG_DEC_START_ACK = 0xB001,
+       VPU_IPIMSG_DEC_END_ACK = 0xB002,
+       VPU_IPIMSG_DEC_DEINIT_ACK = 0xB003,
+       VPU_IPIMSG_DEC_RESET_ACK = 0xB004,
+       VPU_IPIMSG_DEC_CORE_ACK = 0xB005,
+       VPU_IPIMSG_DEC_CORE_END_ACK = 0xB006,
+};
+
+/**
+ * struct vdec_ap_ipi_cmd - generic AP to VPU ipi command format
+ * @msg_id     : vdec_ipi_msgid
+ * @vpu_inst_addr : VPU decoder instance address. Used if ABI version < 2.
+ * @inst_id     : instance ID. Used if the ABI version >= 2.
+ * @codec_type : codec fourcc
+ * @reserved   : reserved param
+ */
+struct vdec_ap_ipi_cmd {
+       uint32_t msg_id;
+       union {
+               uint32_t vpu_inst_addr;
+               uint32_t inst_id;
+       };
+       u32 codec_type;
+       u32 reserved;
+};
+
+/**
+ * struct vdec_vpu_ipi_ack - generic VPU to AP ipi command format
+ * @msg_id     : vdec_ipi_msgid
+ * @status     : VPU exeuction result
+ * @ap_inst_addr       : AP video decoder instance address
+ */
+struct vdec_vpu_ipi_ack {
+       uint32_t msg_id;
+       int32_t status;
+       uint64_t ap_inst_addr;
+};
+
+/**
+ * struct vdec_ap_ipi_init - for AP_IPIMSG_DEC_INIT
+ * @msg_id     : AP_IPIMSG_DEC_INIT
+ * @codec_type : codec fourcc
+ * @ap_inst_addr       : AP video decoder instance address
+ */
+struct vdec_ap_ipi_init {
+       uint32_t msg_id;
+       u32 codec_type;
+       uint64_t ap_inst_addr;
+};
+
+/**
+ * struct vdec_ap_ipi_dec_start - for AP_IPIMSG_DEC_START
+ * @msg_id     : AP_IPIMSG_DEC_START
+ * @vpu_inst_addr : VPU decoder instance address. Used if ABI version < 2.
+ * @inst_id     : instance ID. Used if the ABI version >= 2.
+ * @data       : Header info
+ *     H264 decoder [0]:buf_sz [1]:nal_start
+ *     VP8 decoder  [0]:width/height
+ *     VP9 decoder  [0]:profile, [1][2] width/height
+ * @codec_type : codec fourcc
+ */
+struct vdec_ap_ipi_dec_start {
+       uint32_t msg_id;
+       union {
+               uint32_t vpu_inst_addr;
+               uint32_t inst_id;
+       };
+       uint32_t data[3];
+       u32 codec_type;
+};
+
+/**
+ * struct vdec_vpu_ipi_init_ack - for VPU_IPIMSG_DEC_INIT_ACK
+ * @msg_id     : VPU_IPIMSG_DEC_INIT_ACK
+ * @status     : VPU exeuction result
+ * @ap_inst_addr       : AP vcodec_vpu_inst instance address
+ * @vpu_inst_addr      : VPU decoder instance address
+ * @vdec_abi_version:  ABI version of the firmware. Kernel can use it to
+ *                     ensure that it is compatible with the firmware.
+ *                     This field is not valid for MT8173 and must not be
+ *                     accessed for this chip.
+ * @inst_id     : instance ID. Valid only if the ABI version >= 2.
+ */
+struct vdec_vpu_ipi_init_ack {
+       uint32_t msg_id;
+       int32_t status;
+       uint64_t ap_inst_addr;
+       uint32_t vpu_inst_addr;
+       uint32_t vdec_abi_version;
+       uint32_t inst_id;
+};
+
+#endif
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/vdec_msg_queue.c b/drivers/media/platform/mediatek/mtk-vcodec/vdec_msg_queue.c
new file mode 100644 (file)
index 0000000..4b062a8
--- /dev/null
@@ -0,0 +1,290 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ * Author: Yunfei Dong <yunfei.dong@mediatek.com>
+ */
+
+#include <linux/freezer.h>
+#include <linux/interrupt.h>
+#include <linux/kthread.h>
+
+#include "mtk_vcodec_dec_pm.h"
+#include "mtk_vcodec_drv.h"
+#include "vdec_msg_queue.h"
+
+#define VDEC_MSG_QUEUE_TIMEOUT_MS 1500
+
+/* the size used to store lat slice header information */
+#define VDEC_LAT_SLICE_HEADER_SZ    (640 * SZ_1K)
+
+/* the size used to store avc error information */
+#define VDEC_ERR_MAP_SZ_AVC         (17 * SZ_1K)
+
+/* core will read the trans buffer which decoded by lat to decode again.
+ * The trans buffer size of FHD and 4K bitstreams are different.
+ */
+static int vde_msg_queue_get_trans_size(int width, int height)
+{
+       if (width > 1920 || height > 1088)
+               return 30 * SZ_1M;
+       else
+               return 6 * SZ_1M;
+}
+
+void vdec_msg_queue_init_ctx(struct vdec_msg_queue_ctx *ctx, int hardware_index)
+{
+       init_waitqueue_head(&ctx->ready_to_use);
+       INIT_LIST_HEAD(&ctx->ready_queue);
+       spin_lock_init(&ctx->ready_lock);
+       ctx->ready_num = 0;
+       ctx->hardware_index = hardware_index;
+}
+
+static struct list_head *vdec_get_buf_list(int hardware_index, struct vdec_lat_buf *buf)
+{
+       switch (hardware_index) {
+       case MTK_VDEC_CORE:
+               return &buf->core_list;
+       case MTK_VDEC_LAT0:
+               return &buf->lat_list;
+       default:
+               return NULL;
+       }
+}
+
+int vdec_msg_queue_qbuf(struct vdec_msg_queue_ctx *msg_ctx, struct vdec_lat_buf *buf)
+{
+       struct list_head *head;
+
+       head = vdec_get_buf_list(msg_ctx->hardware_index, buf);
+       if (!head) {
+               mtk_v4l2_err("fail to qbuf: %d", msg_ctx->hardware_index);
+               return -EINVAL;
+       }
+
+       spin_lock(&msg_ctx->ready_lock);
+       list_add_tail(head, &msg_ctx->ready_queue);
+       msg_ctx->ready_num++;
+
+       if (msg_ctx->hardware_index != MTK_VDEC_CORE)
+               wake_up_all(&msg_ctx->ready_to_use);
+       else
+               queue_work(buf->ctx->dev->core_workqueue,
+                          &buf->ctx->msg_queue.core_work);
+
+       mtk_v4l2_debug(3, "enqueue buf type: %d addr: 0x%p num: %d",
+                      msg_ctx->hardware_index, buf, msg_ctx->ready_num);
+       spin_unlock(&msg_ctx->ready_lock);
+
+       return 0;
+}
+
+static bool vdec_msg_queue_wait_event(struct vdec_msg_queue_ctx *msg_ctx)
+{
+       int ret;
+
+       ret = wait_event_timeout(msg_ctx->ready_to_use,
+                                !list_empty(&msg_ctx->ready_queue),
+                                msecs_to_jiffies(VDEC_MSG_QUEUE_TIMEOUT_MS));
+       if (!ret)
+               return false;
+
+       return true;
+}
+
+struct vdec_lat_buf *vdec_msg_queue_dqbuf(struct vdec_msg_queue_ctx *msg_ctx)
+{
+       struct vdec_lat_buf *buf;
+       struct list_head *head;
+       int ret;
+
+       spin_lock(&msg_ctx->ready_lock);
+       if (list_empty(&msg_ctx->ready_queue)) {
+               mtk_v4l2_debug(3, "queue is NULL, type:%d num: %d",
+                              msg_ctx->hardware_index, msg_ctx->ready_num);
+               spin_unlock(&msg_ctx->ready_lock);
+
+               if (msg_ctx->hardware_index == MTK_VDEC_CORE)
+                       return NULL;
+
+               ret = vdec_msg_queue_wait_event(msg_ctx);
+               if (!ret)
+                       return NULL;
+               spin_lock(&msg_ctx->ready_lock);
+       }
+
+       if (msg_ctx->hardware_index == MTK_VDEC_CORE)
+               buf = list_first_entry(&msg_ctx->ready_queue,
+                                      struct vdec_lat_buf, core_list);
+       else
+               buf = list_first_entry(&msg_ctx->ready_queue,
+                                      struct vdec_lat_buf, lat_list);
+
+       head = vdec_get_buf_list(msg_ctx->hardware_index, buf);
+       if (!head) {
+               spin_unlock(&msg_ctx->ready_lock);
+               mtk_v4l2_err("fail to dqbuf: %d", msg_ctx->hardware_index);
+               return NULL;
+       }
+       list_del(head);
+
+       msg_ctx->ready_num--;
+       mtk_v4l2_debug(3, "dqueue buf type:%d addr: 0x%p num: %d",
+                      msg_ctx->hardware_index, buf, msg_ctx->ready_num);
+       spin_unlock(&msg_ctx->ready_lock);
+
+       return buf;
+}
+
+void vdec_msg_queue_update_ube_rptr(struct vdec_msg_queue *msg_queue, uint64_t ube_rptr)
+{
+       spin_lock(&msg_queue->lat_ctx.ready_lock);
+       msg_queue->wdma_rptr_addr = ube_rptr;
+       mtk_v4l2_debug(3, "update ube rprt (0x%llx)", ube_rptr);
+       spin_unlock(&msg_queue->lat_ctx.ready_lock);
+}
+
+void vdec_msg_queue_update_ube_wptr(struct vdec_msg_queue *msg_queue, uint64_t ube_wptr)
+{
+       spin_lock(&msg_queue->lat_ctx.ready_lock);
+       msg_queue->wdma_wptr_addr = ube_wptr;
+       mtk_v4l2_debug(3, "update ube wprt: (0x%llx 0x%llx) offset: 0x%llx",
+                      msg_queue->wdma_rptr_addr, msg_queue->wdma_wptr_addr,
+                      ube_wptr);
+       spin_unlock(&msg_queue->lat_ctx.ready_lock);
+}
+
+bool vdec_msg_queue_wait_lat_buf_full(struct vdec_msg_queue *msg_queue)
+{
+       long timeout_jiff;
+       int ret;
+
+       timeout_jiff = msecs_to_jiffies(1000 * (NUM_BUFFER_COUNT + 2));
+       ret = wait_event_timeout(msg_queue->lat_ctx.ready_to_use,
+                                msg_queue->lat_ctx.ready_num == NUM_BUFFER_COUNT,
+                                timeout_jiff);
+       if (ret) {
+               mtk_v4l2_debug(3, "success to get lat buf: %d",
+                              msg_queue->lat_ctx.ready_num);
+               return true;
+       }
+       mtk_v4l2_err("failed with lat buf isn't full: %d",
+                    msg_queue->lat_ctx.ready_num);
+       return false;
+}
+
+void vdec_msg_queue_deinit(struct vdec_msg_queue *msg_queue,
+                          struct mtk_vcodec_ctx *ctx)
+{
+       struct vdec_lat_buf *lat_buf;
+       struct mtk_vcodec_mem *mem;
+       int i;
+
+       mem = &msg_queue->wdma_addr;
+       if (mem->va)
+               mtk_vcodec_mem_free(ctx, mem);
+       for (i = 0; i < NUM_BUFFER_COUNT; i++) {
+               lat_buf = &msg_queue->lat_buf[i];
+
+               mem = &lat_buf->wdma_err_addr;
+               if (mem->va)
+                       mtk_vcodec_mem_free(ctx, mem);
+
+               mem = &lat_buf->slice_bc_addr;
+               if (mem->va)
+                       mtk_vcodec_mem_free(ctx, mem);
+
+               kfree(lat_buf->private_data);
+       }
+}
+
+static void vdec_msg_queue_core_work(struct work_struct *work)
+{
+       struct vdec_msg_queue *msg_queue =
+               container_of(work, struct vdec_msg_queue, core_work);
+       struct mtk_vcodec_ctx *ctx =
+               container_of(msg_queue, struct mtk_vcodec_ctx, msg_queue);
+       struct mtk_vcodec_dev *dev = ctx->dev;
+       struct vdec_lat_buf *lat_buf;
+
+       lat_buf = vdec_msg_queue_dqbuf(&dev->msg_queue_core_ctx);
+       if (!lat_buf)
+               return;
+
+       ctx = lat_buf->ctx;
+       mtk_vcodec_set_curr_ctx(dev, ctx, MTK_VDEC_CORE);
+
+       lat_buf->core_decode(lat_buf);
+
+       mtk_vcodec_set_curr_ctx(dev, NULL, MTK_VDEC_CORE);
+       vdec_msg_queue_qbuf(&ctx->msg_queue.lat_ctx, lat_buf);
+
+       if (!list_empty(&ctx->msg_queue.lat_ctx.ready_queue)) {
+               mtk_v4l2_debug(3, "re-schedule to decode for core: %d",
+                              dev->msg_queue_core_ctx.ready_num);
+               queue_work(dev->core_workqueue, &msg_queue->core_work);
+       }
+}
+
+int vdec_msg_queue_init(struct vdec_msg_queue *msg_queue,
+                       struct mtk_vcodec_ctx *ctx, core_decode_cb_t core_decode,
+                       int private_size)
+{
+       struct vdec_lat_buf *lat_buf;
+       int i, err;
+
+       /* already init msg queue */
+       if (msg_queue->wdma_addr.size)
+               return 0;
+
+       vdec_msg_queue_init_ctx(&msg_queue->lat_ctx, MTK_VDEC_LAT0);
+       INIT_WORK(&msg_queue->core_work, vdec_msg_queue_core_work);
+       msg_queue->wdma_addr.size =
+               vde_msg_queue_get_trans_size(ctx->picinfo.buf_w,
+                                            ctx->picinfo.buf_h);
+
+       err = mtk_vcodec_mem_alloc(ctx, &msg_queue->wdma_addr);
+       if (err) {
+               mtk_v4l2_err("failed to allocate wdma_addr buf");
+               return -ENOMEM;
+       }
+       msg_queue->wdma_rptr_addr = msg_queue->wdma_addr.dma_addr;
+       msg_queue->wdma_wptr_addr = msg_queue->wdma_addr.dma_addr;
+
+       for (i = 0; i < NUM_BUFFER_COUNT; i++) {
+               lat_buf = &msg_queue->lat_buf[i];
+
+               lat_buf->wdma_err_addr.size = VDEC_ERR_MAP_SZ_AVC;
+               err = mtk_vcodec_mem_alloc(ctx, &lat_buf->wdma_err_addr);
+               if (err) {
+                       mtk_v4l2_err("failed to allocate wdma_err_addr buf[%d]", i);
+                       goto mem_alloc_err;
+               }
+
+               lat_buf->slice_bc_addr.size = VDEC_LAT_SLICE_HEADER_SZ;
+               err = mtk_vcodec_mem_alloc(ctx, &lat_buf->slice_bc_addr);
+               if (err) {
+                       mtk_v4l2_err("failed to allocate wdma_addr buf[%d]", i);
+                       goto mem_alloc_err;
+               }
+
+               lat_buf->private_data = kzalloc(private_size, GFP_KERNEL);
+               if (!lat_buf->private_data) {
+                       err = -ENOMEM;
+                       goto mem_alloc_err;
+               }
+
+               lat_buf->ctx = ctx;
+               lat_buf->core_decode = core_decode;
+               err = vdec_msg_queue_qbuf(&msg_queue->lat_ctx, lat_buf);
+               if (err) {
+                       mtk_v4l2_err("failed to qbuf buf[%d]", i);
+                       goto mem_alloc_err;
+               }
+       }
+       return 0;
+
+mem_alloc_err:
+       vdec_msg_queue_deinit(msg_queue, ctx);
+       return err;
+}
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/vdec_msg_queue.h b/drivers/media/platform/mediatek/mtk-vcodec/vdec_msg_queue.h
new file mode 100644 (file)
index 0000000..b6ba66d
--- /dev/null
@@ -0,0 +1,153 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ * Author: Yunfei Dong <yunfei.dong@mediatek.com>
+ */
+
+#ifndef _VDEC_MSG_QUEUE_H_
+#define _VDEC_MSG_QUEUE_H_
+
+#include <linux/sched.h>
+#include <linux/semaphore.h>
+#include <linux/slab.h>
+#include <media/videobuf2-v4l2.h>
+
+#include "mtk_vcodec_util.h"
+
+#define NUM_BUFFER_COUNT 3
+
+struct vdec_lat_buf;
+struct mtk_vcodec_ctx;
+struct mtk_vcodec_dev;
+typedef int (*core_decode_cb_t)(struct vdec_lat_buf *lat_buf);
+
+/**
+ * struct vdec_msg_queue_ctx - represents a queue for buffers ready to be processed
+ * @ready_to_use: ready used queue used to signalize when get a job queue
+ * @ready_queue: list of ready lat buffer queues
+ * @ready_lock: spin lock to protect the lat buffer usage
+ * @ready_num: number of buffers ready to be processed
+ * @hardware_index: hardware id that this queue is used for
+ */
+struct vdec_msg_queue_ctx {
+       wait_queue_head_t ready_to_use;
+       struct list_head ready_queue;
+       /* protect lat buffer */
+       spinlock_t ready_lock;
+       int ready_num;
+       int hardware_index;
+};
+
+/**
+ * struct vdec_lat_buf - lat buffer message used to store lat info for core decode
+ * @wdma_err_addr: wdma error address used for lat hardware
+ * @slice_bc_addr: slice bc address used for lat hardware
+ * @ts_info: need to set timestamp from output to capture
+ *
+ * @private_data: shared information used to lat and core hardware
+ * @ctx: mtk vcodec context information
+ * @core_decode: different codec use different decode callback function
+ * @lat_list: add lat buffer to lat head list
+ * @core_list: add lat buffer to core head list
+ */
+struct vdec_lat_buf {
+       struct mtk_vcodec_mem wdma_err_addr;
+       struct mtk_vcodec_mem slice_bc_addr;
+       struct vb2_v4l2_buffer ts_info;
+
+       void *private_data;
+       struct mtk_vcodec_ctx *ctx;
+       core_decode_cb_t core_decode;
+       struct list_head lat_list;
+       struct list_head core_list;
+};
+
+/**
+ * struct vdec_msg_queue - used to store lat buffer message
+ * @lat_buf: lat buffer used to store lat buffer information
+ * @wdma_addr: wdma address used for ube
+ * @wdma_rptr_addr: ube read point
+ * @wdma_wptr_addr: ube write point
+ * @core_work: core hardware work
+ * @lat_ctx: used to store lat buffer list
+ */
+struct vdec_msg_queue {
+       struct vdec_lat_buf lat_buf[NUM_BUFFER_COUNT];
+
+       struct mtk_vcodec_mem wdma_addr;
+       u64 wdma_rptr_addr;
+       u64 wdma_wptr_addr;
+
+       struct work_struct core_work;
+       struct vdec_msg_queue_ctx lat_ctx;
+};
+
+/**
+ * vdec_msg_queue_init - init lat buffer information.
+ * @msg_queue: used to store the lat buffer information
+ * @ctx: v4l2 ctx
+ * @core_decode: core decode callback for each codec
+ * @private_size: the private data size used to share with core
+ *
+ * Return: returns 0 if init successfully, or fail.
+ */
+int vdec_msg_queue_init(struct vdec_msg_queue *msg_queue,
+                       struct mtk_vcodec_ctx *ctx, core_decode_cb_t core_decode,
+                       int private_size);
+
+/**
+ * vdec_msg_queue_init_ctx - used to init msg queue context information.
+ * @ctx: message queue context
+ * @hardware_index: hardware index
+ */
+void vdec_msg_queue_init_ctx(struct vdec_msg_queue_ctx *ctx, int hardware_index);
+
+/**
+ * vdec_msg_queue_qbuf - enqueue lat buffer to queue list.
+ * @ctx: message queue context
+ * @buf: current lat buffer
+ *
+ * Return: returns 0 if qbuf successfully, or fail.
+ */
+int vdec_msg_queue_qbuf(struct vdec_msg_queue_ctx *ctx, struct vdec_lat_buf *buf);
+
+/**
+ * vdec_msg_queue_dqbuf - dequeue lat buffer from queue list.
+ * @ctx: message queue context
+ *
+ * Return: returns not null if dq successfully, or fail.
+ */
+struct vdec_lat_buf *vdec_msg_queue_dqbuf(struct vdec_msg_queue_ctx *ctx);
+
+/**
+ * vdec_msg_queue_update_ube_rptr - used to updata the ube read point.
+ * @msg_queue: used to store the lat buffer information
+ * @ube_rptr: current ube read point
+ */
+void vdec_msg_queue_update_ube_rptr(struct vdec_msg_queue *msg_queue, uint64_t ube_rptr);
+
+/**
+ * vdec_msg_queue_update_ube_wptr - used to updata the ube write point.
+ * @msg_queue: used to store the lat buffer information
+ * @ube_wptr: current ube write point
+ */
+void vdec_msg_queue_update_ube_wptr(struct vdec_msg_queue *msg_queue, uint64_t ube_wptr);
+
+/**
+ * vdec_msg_queue_wait_lat_buf_full - used to check whether all lat buffer
+ *                                    in lat list.
+ * @msg_queue: used to store the lat buffer information
+ *
+ * Return: returns true if successfully, or fail.
+ */
+bool vdec_msg_queue_wait_lat_buf_full(struct vdec_msg_queue *msg_queue);
+
+/**
+ * vdec_msg_queue_deinit - deinit lat buffer information.
+ * @msg_queue: used to store the lat buffer information
+ * @ctx: v4l2 ctx
+ */
+void vdec_msg_queue_deinit(struct vdec_msg_queue *msg_queue,
+                          struct mtk_vcodec_ctx *ctx);
+
+#endif
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/vdec_vpu_if.c b/drivers/media/platform/mediatek/mtk-vcodec/vdec_vpu_if.c
new file mode 100644 (file)
index 0000000..dd35d2c
--- /dev/null
@@ -0,0 +1,243 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: PC Chen <pc.chen@mediatek.com>
+ */
+
+#include "mtk_vcodec_drv.h"
+#include "mtk_vcodec_util.h"
+#include "vdec_ipi_msg.h"
+#include "vdec_vpu_if.h"
+#include "mtk_vcodec_fw.h"
+
+static void handle_init_ack_msg(const struct vdec_vpu_ipi_init_ack *msg)
+{
+       struct vdec_vpu_inst *vpu = (struct vdec_vpu_inst *)
+                                       (unsigned long)msg->ap_inst_addr;
+
+       mtk_vcodec_debug(vpu, "+ ap_inst_addr = 0x%llx", msg->ap_inst_addr);
+
+       /* mapping VPU address to kernel virtual address */
+       /* the content in vsi is initialized to 0 in VPU */
+       vpu->vsi = mtk_vcodec_fw_map_dm_addr(vpu->ctx->dev->fw_handler,
+                                            msg->vpu_inst_addr);
+       vpu->inst_addr = msg->vpu_inst_addr;
+
+       mtk_vcodec_debug(vpu, "- vpu_inst_addr = 0x%x", vpu->inst_addr);
+
+       /* Set default ABI version if dealing with unversioned firmware. */
+       vpu->fw_abi_version = 0;
+       /*
+        * Instance ID is only used if ABI version >= 2. Initialize it with
+        * garbage by default.
+        */
+       vpu->inst_id = 0xdeadbeef;
+
+       /* Firmware version field does not exist on MT8173. */
+       if (vpu->ctx->dev->vdec_pdata->chip == MTK_MT8173)
+               return;
+
+       /* Check firmware version. */
+       vpu->fw_abi_version = msg->vdec_abi_version;
+       mtk_vcodec_debug(vpu, "firmware version 0x%x\n", vpu->fw_abi_version);
+       switch (vpu->fw_abi_version) {
+       case 1:
+               break;
+       case 2:
+               vpu->inst_id = msg->inst_id;
+               break;
+       default:
+               mtk_vcodec_err(vpu, "unhandled firmware version 0x%x\n",
+                              vpu->fw_abi_version);
+               vpu->failure = 1;
+               break;
+       }
+}
+
+/*
+ * vpu_dec_ipi_handler - Handler for VPU ipi message.
+ *
+ * @data: ipi message
+ * @len : length of ipi message
+ * @priv: callback private data which is passed by decoder when register.
+ *
+ * This function runs in interrupt context and it means there's an IPI MSG
+ * from VPU.
+ */
+static void vpu_dec_ipi_handler(void *data, unsigned int len, void *priv)
+{
+       const struct vdec_vpu_ipi_ack *msg = data;
+       struct vdec_vpu_inst *vpu = (struct vdec_vpu_inst *)
+                                       (unsigned long)msg->ap_inst_addr;
+
+       mtk_vcodec_debug(vpu, "+ id=%X", msg->msg_id);
+
+       vpu->failure = msg->status;
+       vpu->signaled = 1;
+
+       if (msg->status == 0) {
+               switch (msg->msg_id) {
+               case VPU_IPIMSG_DEC_INIT_ACK:
+                       handle_init_ack_msg(data);
+                       break;
+
+               case VPU_IPIMSG_DEC_START_ACK:
+               case VPU_IPIMSG_DEC_END_ACK:
+               case VPU_IPIMSG_DEC_DEINIT_ACK:
+               case VPU_IPIMSG_DEC_RESET_ACK:
+               case VPU_IPIMSG_DEC_CORE_ACK:
+               case VPU_IPIMSG_DEC_CORE_END_ACK:
+                       break;
+
+               default:
+                       mtk_vcodec_err(vpu, "invalid msg=%X", msg->msg_id);
+                       break;
+               }
+       }
+
+       mtk_vcodec_debug(vpu, "- id=%X", msg->msg_id);
+}
+
+static int vcodec_vpu_send_msg(struct vdec_vpu_inst *vpu, void *msg, int len)
+{
+       int err, id, msgid;
+
+       msgid = *(uint32_t *)msg;
+       mtk_vcodec_debug(vpu, "id=%X", msgid);
+
+       vpu->failure = 0;
+       vpu->signaled = 0;
+
+       if (vpu->ctx->dev->vdec_pdata->hw_arch == MTK_VDEC_LAT_SINGLE_CORE) {
+               if (msgid == AP_IPIMSG_DEC_CORE ||
+                   msgid == AP_IPIMSG_DEC_CORE_END)
+                       id = vpu->core_id;
+               else
+                       id = vpu->id;
+       } else {
+               id = vpu->id;
+       }
+
+       err = mtk_vcodec_fw_ipi_send(vpu->ctx->dev->fw_handler, id, msg,
+                                    len, 2000);
+       if (err) {
+               mtk_vcodec_err(vpu, "send fail vpu_id=%d msg_id=%X status=%d",
+                              id, msgid, err);
+               return err;
+       }
+
+       return vpu->failure;
+}
+
+static int vcodec_send_ap_ipi(struct vdec_vpu_inst *vpu, unsigned int msg_id)
+{
+       struct vdec_ap_ipi_cmd msg;
+       int err = 0;
+
+       mtk_vcodec_debug(vpu, "+ id=%X", msg_id);
+
+       memset(&msg, 0, sizeof(msg));
+       msg.msg_id = msg_id;
+       if (vpu->fw_abi_version < 2)
+               msg.vpu_inst_addr = vpu->inst_addr;
+       else
+               msg.inst_id = vpu->inst_id;
+       msg.codec_type = vpu->codec_type;
+
+       err = vcodec_vpu_send_msg(vpu, &msg, sizeof(msg));
+       mtk_vcodec_debug(vpu, "- id=%X ret=%d", msg_id, err);
+       return err;
+}
+
+int vpu_dec_init(struct vdec_vpu_inst *vpu)
+{
+       struct vdec_ap_ipi_init msg;
+       int err;
+
+       mtk_vcodec_debug_enter(vpu);
+
+       init_waitqueue_head(&vpu->wq);
+       vpu->handler = vpu_dec_ipi_handler;
+
+       err = mtk_vcodec_fw_ipi_register(vpu->ctx->dev->fw_handler, vpu->id,
+                                        vpu->handler, "vdec", NULL);
+       if (err) {
+               mtk_vcodec_err(vpu, "vpu_ipi_register fail status=%d", err);
+               return err;
+       }
+
+       if (vpu->ctx->dev->vdec_pdata->hw_arch == MTK_VDEC_LAT_SINGLE_CORE) {
+               err = mtk_vcodec_fw_ipi_register(vpu->ctx->dev->fw_handler,
+                                                vpu->core_id, vpu->handler,
+                                                "vdec", NULL);
+               if (err) {
+                       mtk_vcodec_err(vpu, "vpu_ipi_register core fail status=%d", err);
+                       return err;
+               }
+       }
+
+       memset(&msg, 0, sizeof(msg));
+       msg.msg_id = AP_IPIMSG_DEC_INIT;
+       msg.ap_inst_addr = (unsigned long)vpu;
+       msg.codec_type = vpu->codec_type;
+
+       mtk_vcodec_debug(vpu, "vdec_inst=%p", vpu);
+
+       err = vcodec_vpu_send_msg(vpu, (void *)&msg, sizeof(msg));
+       mtk_vcodec_debug(vpu, "- ret=%d", err);
+       return err;
+}
+
+int vpu_dec_start(struct vdec_vpu_inst *vpu, uint32_t *data, unsigned int len)
+{
+       struct vdec_ap_ipi_dec_start msg;
+       int i;
+       int err = 0;
+
+       mtk_vcodec_debug_enter(vpu);
+
+       if (len > ARRAY_SIZE(msg.data)) {
+               mtk_vcodec_err(vpu, "invalid len = %d\n", len);
+               return -EINVAL;
+       }
+
+       memset(&msg, 0, sizeof(msg));
+       msg.msg_id = AP_IPIMSG_DEC_START;
+       if (vpu->fw_abi_version < 2)
+               msg.vpu_inst_addr = vpu->inst_addr;
+       else
+               msg.inst_id = vpu->inst_id;
+
+       for (i = 0; i < len; i++)
+               msg.data[i] = data[i];
+       msg.codec_type = vpu->codec_type;
+
+       err = vcodec_vpu_send_msg(vpu, (void *)&msg, sizeof(msg));
+       mtk_vcodec_debug(vpu, "- ret=%d", err);
+       return err;
+}
+
+int vpu_dec_core(struct vdec_vpu_inst *vpu)
+{
+       return vcodec_send_ap_ipi(vpu, AP_IPIMSG_DEC_CORE);
+}
+
+int vpu_dec_end(struct vdec_vpu_inst *vpu)
+{
+       return vcodec_send_ap_ipi(vpu, AP_IPIMSG_DEC_END);
+}
+
+int vpu_dec_core_end(struct vdec_vpu_inst *vpu)
+{
+       return vcodec_send_ap_ipi(vpu, AP_IPIMSG_DEC_CORE_END);
+}
+
+int vpu_dec_deinit(struct vdec_vpu_inst *vpu)
+{
+       return vcodec_send_ap_ipi(vpu, AP_IPIMSG_DEC_DEINIT);
+}
+
+int vpu_dec_reset(struct vdec_vpu_inst *vpu)
+{
+       return vcodec_send_ap_ipi(vpu, AP_IPIMSG_DEC_RESET);
+}
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/vdec_vpu_if.h b/drivers/media/platform/mediatek/mtk-vcodec/vdec_vpu_if.h
new file mode 100644 (file)
index 0000000..4cb3c7f
--- /dev/null
@@ -0,0 +1,107 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: PC Chen <pc.chen@mediatek.com>
+ */
+
+#ifndef _VDEC_VPU_IF_H_
+#define _VDEC_VPU_IF_H_
+
+#include "mtk_vcodec_fw.h"
+
+struct mtk_vcodec_ctx;
+
+/**
+ * struct vdec_vpu_inst - VPU instance for video codec
+ * @id          : ipi msg id for each decoder
+ * @core_id     : core id used to separate different hardware
+ * @vsi         : driver structure allocated by VPU side and shared to AP side
+ *                for control and info share
+ * @failure     : VPU execution result status, 0: success, others: fail
+ * @inst_addr  : VPU decoder instance address
+ * @fw_abi_version : ABI version of the firmware.
+ * @inst_id    : if fw_abi_version >= 2, contains the instance ID to be given
+ *                in place of inst_addr in messages.
+ * @signaled    : 1 - Host has received ack message from VPU, 0 - not received
+ * @ctx         : context for v4l2 layer integration
+ * @dev                : platform device of VPU
+ * @wq          : wait queue to wait VPU message ack
+ * @handler     : ipi handler for each decoder
+ * @codec_type     : use codec type to separate different codecs
+ */
+struct vdec_vpu_inst {
+       int id;
+       int core_id;
+       void *vsi;
+       int32_t failure;
+       uint32_t inst_addr;
+       uint32_t fw_abi_version;
+       uint32_t inst_id;
+       unsigned int signaled;
+       struct mtk_vcodec_ctx *ctx;
+       wait_queue_head_t wq;
+       mtk_vcodec_ipi_handler handler;
+       unsigned int codec_type;
+};
+
+/**
+ * vpu_dec_init - init decoder instance and allocate required resource in VPU.
+ *
+ * @vpu: instance for vdec_vpu_inst
+ */
+int vpu_dec_init(struct vdec_vpu_inst *vpu);
+
+/**
+ * vpu_dec_start - start decoding, basically the function will be invoked once
+ *                 every frame.
+ *
+ * @vpu : instance for vdec_vpu_inst
+ * @data: meta data to pass bitstream info to VPU decoder
+ * @len : meta data length
+ */
+int vpu_dec_start(struct vdec_vpu_inst *vpu, uint32_t *data, unsigned int len);
+
+/**
+ * vpu_dec_end - end decoding, basically the function will be invoked once
+ *               when HW decoding done interrupt received successfully. The
+ *               decoder in VPU will continue to do reference frame management
+ *               and check if there is a new decoded frame available to display.
+ *
+ * @vpu : instance for vdec_vpu_inst
+ */
+int vpu_dec_end(struct vdec_vpu_inst *vpu);
+
+/**
+ * vpu_dec_deinit - deinit decoder instance and resource freed in VPU.
+ *
+ * @vpu: instance for vdec_vpu_inst
+ */
+int vpu_dec_deinit(struct vdec_vpu_inst *vpu);
+
+/**
+ * vpu_dec_reset - reset decoder, use for flush decoder when end of stream or
+ *                 seek. Remainig non displayed frame will be pushed to display.
+ *
+ * @vpu: instance for vdec_vpu_inst
+ */
+int vpu_dec_reset(struct vdec_vpu_inst *vpu);
+
+/**
+ * vpu_dec_core - core start decoding, basically the function will be invoked once
+ *                 every frame.
+ *
+ * @vpu : instance for vdec_vpu_inst
+ */
+int vpu_dec_core(struct vdec_vpu_inst *vpu);
+
+/**
+ * vpu_dec_core_end - core end decoding, basically the function will be invoked once
+ *               when core HW decoding done and receive interrupt successfully. The
+ *               decoder in VPU will updata hardware information and deinit hardware
+ *               and check if there is a new decoded frame available to display.
+ *
+ * @vpu : instance for vdec_vpu_inst
+ */
+int vpu_dec_core_end(struct vdec_vpu_inst *vpu);
+
+#endif
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/venc/venc_h264_if.c b/drivers/media/platform/mediatek/mtk-vcodec/venc/venc_h264_if.c
new file mode 100644 (file)
index 0000000..4d9b879
--- /dev/null
@@ -0,0 +1,708 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Jungchang Tsao <jungchang.tsao@mediatek.com>
+ *         Daniel Hsiao <daniel.hsiao@mediatek.com>
+ *         PoChun Lin <pochun.lin@mediatek.com>
+ */
+
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include "../mtk_vcodec_drv.h"
+#include "../mtk_vcodec_util.h"
+#include "../mtk_vcodec_intr.h"
+#include "../mtk_vcodec_enc.h"
+#include "../mtk_vcodec_enc_pm.h"
+#include "../venc_drv_base.h"
+#include "../venc_ipi_msg.h"
+#include "../venc_vpu_if.h"
+
+static const char h264_filler_marker[] = {0x0, 0x0, 0x0, 0x1, 0xc};
+
+#define H264_FILLER_MARKER_SIZE ARRAY_SIZE(h264_filler_marker)
+#define VENC_PIC_BITSTREAM_BYTE_CNT 0x0098
+
+/*
+ * enum venc_h264_frame_type - h264 encoder output bitstream frame type
+ */
+enum venc_h264_frame_type {
+       VENC_H264_IDR_FRM,
+       VENC_H264_I_FRM,
+       VENC_H264_P_FRM,
+       VENC_H264_B_FRM,
+};
+
+/*
+ * enum venc_h264_vpu_work_buf - h264 encoder buffer index
+ */
+enum venc_h264_vpu_work_buf {
+       VENC_H264_VPU_WORK_BUF_RC_INFO,
+       VENC_H264_VPU_WORK_BUF_RC_CODE,
+       VENC_H264_VPU_WORK_BUF_REC_LUMA,
+       VENC_H264_VPU_WORK_BUF_REC_CHROMA,
+       VENC_H264_VPU_WORK_BUF_REF_LUMA,
+       VENC_H264_VPU_WORK_BUF_REF_CHROMA,
+       VENC_H264_VPU_WORK_BUF_MV_INFO_1,
+       VENC_H264_VPU_WORK_BUF_MV_INFO_2,
+       VENC_H264_VPU_WORK_BUF_SKIP_FRAME,
+       VENC_H264_VPU_WORK_BUF_MAX,
+};
+
+/*
+ * enum venc_h264_bs_mode - for bs_mode argument in h264_enc_vpu_encode
+ */
+enum venc_h264_bs_mode {
+       H264_BS_MODE_SPS,
+       H264_BS_MODE_PPS,
+       H264_BS_MODE_FRAME,
+};
+
+/*
+ * struct venc_h264_vpu_config - Structure for h264 encoder configuration
+ *                               AP-W/R : AP is writer/reader on this item
+ *                               VPU-W/R: VPU is write/reader on this item
+ * @input_fourcc: input fourcc
+ * @bitrate: target bitrate (in bps)
+ * @pic_w: picture width. Picture size is visible stream resolution, in pixels,
+ *         to be used for display purposes; must be smaller or equal to buffer
+ *         size.
+ * @pic_h: picture height
+ * @buf_w: buffer width. Buffer size is stream resolution in pixels aligned to
+ *         hardware requirements.
+ * @buf_h: buffer height
+ * @gop_size: group of picture size (idr frame)
+ * @intra_period: intra frame period
+ * @framerate: frame rate in fps
+ * @profile: as specified in standard
+ * @level: as specified in standard
+ * @wfd: WFD mode 1:on, 0:off
+ */
+struct venc_h264_vpu_config {
+       u32 input_fourcc;
+       u32 bitrate;
+       u32 pic_w;
+       u32 pic_h;
+       u32 buf_w;
+       u32 buf_h;
+       u32 gop_size;
+       u32 intra_period;
+       u32 framerate;
+       u32 profile;
+       u32 level;
+       u32 wfd;
+};
+
+/*
+ * struct venc_h264_vpu_buf - Structure for buffer information
+ *                            AP-W/R : AP is writer/reader on this item
+ *                            VPU-W/R: VPU is write/reader on this item
+ * @iova: IO virtual address
+ * @vpua: VPU side memory addr which is used by RC_CODE
+ * @size: buffer size (in bytes)
+ */
+struct venc_h264_vpu_buf {
+       u32 iova;
+       u32 vpua;
+       u32 size;
+};
+
+/*
+ * struct venc_h264_vsi - Structure for VPU driver control and info share
+ *                        AP-W/R : AP is writer/reader on this item
+ *                        VPU-W/R: VPU is write/reader on this item
+ * This structure is allocated in VPU side and shared to AP side.
+ * @config: h264 encoder configuration
+ * @work_bufs: working buffer information in VPU side
+ * The work_bufs here is for storing the 'size' info shared to AP side.
+ * The similar item in struct venc_h264_inst is for memory allocation
+ * in AP side. The AP driver will copy the 'size' from here to the one in
+ * struct mtk_vcodec_mem, then invoke mtk_vcodec_mem_alloc to allocate
+ * the buffer. After that, bypass the 'dma_addr' to the 'iova' field here for
+ * register setting in VPU side.
+ */
+struct venc_h264_vsi {
+       struct venc_h264_vpu_config config;
+       struct venc_h264_vpu_buf work_bufs[VENC_H264_VPU_WORK_BUF_MAX];
+};
+
+/*
+ * struct venc_h264_inst - h264 encoder AP driver instance
+ * @hw_base: h264 encoder hardware register base
+ * @work_bufs: working buffer
+ * @pps_buf: buffer to store the pps bitstream
+ * @work_buf_allocated: working buffer allocated flag
+ * @frm_cnt: encoded frame count
+ * @prepend_hdr: when the v4l2 layer send VENC_SET_PARAM_PREPEND_HEADER cmd
+ *  through h264_enc_set_param interface, it will set this flag and prepend the
+ *  sps/pps in h264_enc_encode function.
+ * @vpu_inst: VPU instance to exchange information between AP and VPU
+ * @vsi: driver structure allocated by VPU side and shared to AP side for
+ *      control and info share
+ * @ctx: context for v4l2 layer integration
+ */
+struct venc_h264_inst {
+       void __iomem *hw_base;
+       struct mtk_vcodec_mem work_bufs[VENC_H264_VPU_WORK_BUF_MAX];
+       struct mtk_vcodec_mem pps_buf;
+       bool work_buf_allocated;
+       unsigned int frm_cnt;
+       unsigned int skip_frm_cnt;
+       unsigned int prepend_hdr;
+       struct venc_vpu_inst vpu_inst;
+       struct venc_h264_vsi *vsi;
+       struct mtk_vcodec_ctx *ctx;
+};
+
+static inline u32 h264_read_reg(struct venc_h264_inst *inst, u32 addr)
+{
+       return readl(inst->hw_base + addr);
+}
+
+static unsigned int h264_get_profile(struct venc_h264_inst *inst,
+                                    unsigned int profile)
+{
+       switch (profile) {
+       case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
+               return 66;
+       case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
+               return 77;
+       case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
+               return 100;
+       case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
+               mtk_vcodec_err(inst, "unsupported CONSTRAINED_BASELINE");
+               return 0;
+       case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED:
+               mtk_vcodec_err(inst, "unsupported EXTENDED");
+               return 0;
+       default:
+               mtk_vcodec_debug(inst, "unsupported profile %d", profile);
+               return 100;
+       }
+}
+
+static unsigned int h264_get_level(struct venc_h264_inst *inst,
+                                  unsigned int level)
+{
+       switch (level) {
+       case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
+               mtk_vcodec_err(inst, "unsupported 1B");
+               return 0;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
+               return 10;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
+               return 11;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
+               return 12;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
+               return 13;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
+               return 20;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
+               return 21;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
+               return 22;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
+               return 30;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
+               return 31;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
+               return 32;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
+               return 40;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_4_1:
+               return 41;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
+               return 42;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
+               return 50;
+       case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
+               return 51;
+       default:
+               mtk_vcodec_debug(inst, "unsupported level %d", level);
+               return 31;
+       }
+}
+
+static void h264_enc_free_work_buf(struct venc_h264_inst *inst)
+{
+       int i;
+
+       mtk_vcodec_debug_enter(inst);
+
+       /* Except the SKIP_FRAME buffers,
+        * other buffers need to be freed by AP.
+        */
+       for (i = 0; i < VENC_H264_VPU_WORK_BUF_MAX; i++) {
+               if (i != VENC_H264_VPU_WORK_BUF_SKIP_FRAME)
+                       mtk_vcodec_mem_free(inst->ctx, &inst->work_bufs[i]);
+       }
+
+       mtk_vcodec_mem_free(inst->ctx, &inst->pps_buf);
+
+       mtk_vcodec_debug_leave(inst);
+}
+
+static int h264_enc_alloc_work_buf(struct venc_h264_inst *inst)
+{
+       int i;
+       int ret = 0;
+       struct venc_h264_vpu_buf *wb = inst->vsi->work_bufs;
+
+       mtk_vcodec_debug_enter(inst);
+
+       for (i = 0; i < VENC_H264_VPU_WORK_BUF_MAX; i++) {
+               /*
+                * This 'wb' structure is set by VPU side and shared to AP for
+                * buffer allocation and IO virtual addr mapping. For most of
+                * the buffers, AP will allocate the buffer according to 'size'
+                * field and store the IO virtual addr in 'iova' field. There
+                * are two exceptions:
+                * (1) RC_CODE buffer, it's pre-allocated in the VPU side, and
+                * save the VPU addr in the 'vpua' field. The AP will translate
+                * the VPU addr to the corresponding IO virtual addr and store
+                * in 'iova' field for reg setting in VPU side.
+                * (2) SKIP_FRAME buffer, it's pre-allocated in the VPU side,
+                * and save the VPU addr in the 'vpua' field. The AP will
+                * translate the VPU addr to the corresponding AP side virtual
+                * address and do some memcpy access to move to bitstream buffer
+                * assigned by v4l2 layer.
+                */
+               inst->work_bufs[i].size = wb[i].size;
+               if (i == VENC_H264_VPU_WORK_BUF_SKIP_FRAME) {
+                       struct mtk_vcodec_fw *handler;
+
+                       handler = inst->vpu_inst.ctx->dev->fw_handler;
+                       inst->work_bufs[i].va =
+                               mtk_vcodec_fw_map_dm_addr(handler, wb[i].vpua);
+                       inst->work_bufs[i].dma_addr = 0;
+               } else {
+                       ret = mtk_vcodec_mem_alloc(inst->ctx,
+                                                  &inst->work_bufs[i]);
+                       if (ret) {
+                               mtk_vcodec_err(inst,
+                                              "cannot allocate buf %d", i);
+                               goto err_alloc;
+                       }
+                       /*
+                        * This RC_CODE is pre-allocated by VPU and saved in VPU
+                        * addr. So we need use memcpy to copy RC_CODE from VPU
+                        * addr into IO virtual addr in 'iova' field for reg
+                        * setting in VPU side.
+                        */
+                       if (i == VENC_H264_VPU_WORK_BUF_RC_CODE) {
+                               struct mtk_vcodec_fw *handler;
+                               void *tmp_va;
+
+                               handler = inst->vpu_inst.ctx->dev->fw_handler;
+                               tmp_va = mtk_vcodec_fw_map_dm_addr(handler,
+                                                                  wb[i].vpua);
+                               memcpy(inst->work_bufs[i].va, tmp_va,
+                                      wb[i].size);
+                       }
+               }
+               wb[i].iova = inst->work_bufs[i].dma_addr;
+
+               mtk_vcodec_debug(inst,
+                                "work_buf[%d] va=0x%p iova=%pad size=%zu",
+                                i, inst->work_bufs[i].va,
+                                &inst->work_bufs[i].dma_addr,
+                                inst->work_bufs[i].size);
+       }
+
+       /* the pps_buf is used by AP side only */
+       inst->pps_buf.size = 128;
+       ret = mtk_vcodec_mem_alloc(inst->ctx, &inst->pps_buf);
+       if (ret) {
+               mtk_vcodec_err(inst, "cannot allocate pps_buf");
+               goto err_alloc;
+       }
+
+       mtk_vcodec_debug_leave(inst);
+
+       return ret;
+
+err_alloc:
+       h264_enc_free_work_buf(inst);
+
+       return ret;
+}
+
+static unsigned int h264_enc_wait_venc_done(struct venc_h264_inst *inst)
+{
+       unsigned int irq_status = 0;
+       struct mtk_vcodec_ctx *ctx = (struct mtk_vcodec_ctx *)inst->ctx;
+
+       if (!mtk_vcodec_wait_for_done_ctx(ctx, MTK_INST_IRQ_RECEIVED,
+                                         WAIT_INTR_TIMEOUT_MS, 0)) {
+               irq_status = ctx->irq_status;
+               mtk_vcodec_debug(inst, "irq_status %x <-", irq_status);
+       }
+       return irq_status;
+}
+
+static int h264_frame_type(struct venc_h264_inst *inst)
+{
+       if ((inst->vsi->config.gop_size != 0 &&
+            (inst->frm_cnt % inst->vsi->config.gop_size) == 0) ||
+           (inst->frm_cnt == 0 && inst->vsi->config.gop_size == 0)) {
+               /* IDR frame */
+               return VENC_H264_IDR_FRM;
+       } else if ((inst->vsi->config.intra_period != 0 &&
+                   (inst->frm_cnt % inst->vsi->config.intra_period) == 0) ||
+                  (inst->frm_cnt == 0 && inst->vsi->config.intra_period == 0)) {
+               /* I frame */
+               return VENC_H264_I_FRM;
+       } else {
+               return VENC_H264_P_FRM;  /* Note: B frames are not supported */
+       }
+}
+static int h264_encode_sps(struct venc_h264_inst *inst,
+                          struct mtk_vcodec_mem *bs_buf,
+                          unsigned int *bs_size)
+{
+       int ret = 0;
+       unsigned int irq_status;
+
+       mtk_vcodec_debug_enter(inst);
+
+       ret = vpu_enc_encode(&inst->vpu_inst, H264_BS_MODE_SPS, NULL, bs_buf, NULL);
+       if (ret)
+               return ret;
+
+       irq_status = h264_enc_wait_venc_done(inst);
+       if (irq_status != MTK_VENC_IRQ_STATUS_SPS) {
+               mtk_vcodec_err(inst, "expect irq status %d",
+                              MTK_VENC_IRQ_STATUS_SPS);
+               return -EINVAL;
+       }
+
+       *bs_size = h264_read_reg(inst, VENC_PIC_BITSTREAM_BYTE_CNT);
+       mtk_vcodec_debug(inst, "bs size %d <-", *bs_size);
+
+       return ret;
+}
+
+static int h264_encode_pps(struct venc_h264_inst *inst,
+                          struct mtk_vcodec_mem *bs_buf,
+                          unsigned int *bs_size)
+{
+       int ret = 0;
+       unsigned int irq_status;
+
+       mtk_vcodec_debug_enter(inst);
+
+       ret = vpu_enc_encode(&inst->vpu_inst, H264_BS_MODE_PPS, NULL, bs_buf, NULL);
+       if (ret)
+               return ret;
+
+       irq_status = h264_enc_wait_venc_done(inst);
+       if (irq_status != MTK_VENC_IRQ_STATUS_PPS) {
+               mtk_vcodec_err(inst, "expect irq status %d",
+                              MTK_VENC_IRQ_STATUS_PPS);
+               return -EINVAL;
+       }
+
+       *bs_size = h264_read_reg(inst, VENC_PIC_BITSTREAM_BYTE_CNT);
+       mtk_vcodec_debug(inst, "bs size %d <-", *bs_size);
+
+       return ret;
+}
+
+static int h264_encode_header(struct venc_h264_inst *inst,
+                             struct mtk_vcodec_mem *bs_buf,
+                             unsigned int *bs_size)
+{
+       int ret = 0;
+       unsigned int bs_size_sps;
+       unsigned int bs_size_pps;
+
+       ret = h264_encode_sps(inst, bs_buf, &bs_size_sps);
+       if (ret)
+               return ret;
+
+       ret = h264_encode_pps(inst, &inst->pps_buf, &bs_size_pps);
+       if (ret)
+               return ret;
+
+       memcpy(bs_buf->va + bs_size_sps, inst->pps_buf.va, bs_size_pps);
+       *bs_size = bs_size_sps + bs_size_pps;
+
+       return ret;
+}
+
+static int h264_encode_frame(struct venc_h264_inst *inst,
+                            struct venc_frm_buf *frm_buf,
+                            struct mtk_vcodec_mem *bs_buf,
+                            unsigned int *bs_size)
+{
+       int ret = 0;
+       unsigned int irq_status;
+       struct venc_frame_info frame_info;
+
+       mtk_vcodec_debug_enter(inst);
+       mtk_vcodec_debug(inst, "frm_cnt = %d\n ", inst->frm_cnt);
+       frame_info.frm_count = inst->frm_cnt;
+       frame_info.skip_frm_count = inst->skip_frm_cnt;
+       frame_info.frm_type = h264_frame_type(inst);
+       mtk_vcodec_debug(inst, "frm_count = %d,skip_frm_count =%d,frm_type=%d.\n",
+                        frame_info.frm_count, frame_info.skip_frm_count,
+                        frame_info.frm_type);
+       ret = vpu_enc_encode(&inst->vpu_inst, H264_BS_MODE_FRAME, frm_buf, bs_buf, &frame_info);
+       if (ret)
+               return ret;
+
+       /*
+        * skip frame case: The skip frame buffer is composed by vpu side only,
+        * it does not trigger the hw, so skip the wait interrupt operation.
+        */
+       if (inst->vpu_inst.state == VEN_IPI_MSG_ENC_STATE_SKIP) {
+               *bs_size = inst->vpu_inst.bs_size;
+               memcpy(bs_buf->va,
+                      inst->work_bufs[VENC_H264_VPU_WORK_BUF_SKIP_FRAME].va,
+                      *bs_size);
+               ++inst->frm_cnt;
+               ++inst->skip_frm_cnt;
+               return ret;
+       }
+
+       irq_status = h264_enc_wait_venc_done(inst);
+       if (irq_status != MTK_VENC_IRQ_STATUS_FRM) {
+               mtk_vcodec_err(inst, "irq_status=%d failed", irq_status);
+               return -EIO;
+       }
+
+       *bs_size = h264_read_reg(inst, VENC_PIC_BITSTREAM_BYTE_CNT);
+
+       ++inst->frm_cnt;
+       mtk_vcodec_debug(inst, "frm %d bs_size %d key_frm %d <-",
+                        inst->frm_cnt, *bs_size, inst->vpu_inst.is_key_frm);
+
+       return ret;
+}
+
+static void h264_encode_filler(struct venc_h264_inst *inst, void *buf,
+                              int size)
+{
+       unsigned char *p = buf;
+
+       if (size < H264_FILLER_MARKER_SIZE) {
+               mtk_vcodec_err(inst, "filler size too small %d", size);
+               return;
+       }
+
+       memcpy(p, h264_filler_marker, ARRAY_SIZE(h264_filler_marker));
+       size -= H264_FILLER_MARKER_SIZE;
+       p += H264_FILLER_MARKER_SIZE;
+       memset(p, 0xff, size);
+}
+
+static int h264_enc_init(struct mtk_vcodec_ctx *ctx)
+{
+       const bool is_ext = MTK_ENC_CTX_IS_EXT(ctx);
+       int ret = 0;
+       struct venc_h264_inst *inst;
+
+       inst = kzalloc(sizeof(*inst), GFP_KERNEL);
+       if (!inst)
+               return -ENOMEM;
+
+       inst->ctx = ctx;
+       inst->vpu_inst.ctx = ctx;
+       inst->vpu_inst.id = is_ext ? SCP_IPI_VENC_H264 : IPI_VENC_H264;
+       inst->hw_base = mtk_vcodec_get_reg_addr(inst->ctx, VENC_SYS);
+
+       mtk_vcodec_debug_enter(inst);
+
+       ret = vpu_enc_init(&inst->vpu_inst);
+
+       inst->vsi = (struct venc_h264_vsi *)inst->vpu_inst.vsi;
+
+       mtk_vcodec_debug_leave(inst);
+
+       if (ret)
+               kfree(inst);
+       else
+               ctx->drv_handle = inst;
+
+       return ret;
+}
+
+static int h264_enc_encode(void *handle,
+                          enum venc_start_opt opt,
+                          struct venc_frm_buf *frm_buf,
+                          struct mtk_vcodec_mem *bs_buf,
+                          struct venc_done_result *result)
+{
+       int ret = 0;
+       struct venc_h264_inst *inst = (struct venc_h264_inst *)handle;
+       struct mtk_vcodec_ctx *ctx = inst->ctx;
+
+       mtk_vcodec_debug(inst, "opt %d ->", opt);
+
+       enable_irq(ctx->dev->enc_irq);
+
+       switch (opt) {
+       case VENC_START_OPT_ENCODE_SEQUENCE_HEADER: {
+               unsigned int bs_size_hdr;
+
+               ret = h264_encode_header(inst, bs_buf, &bs_size_hdr);
+               if (ret)
+                       goto encode_err;
+
+               result->bs_size = bs_size_hdr;
+               result->is_key_frm = false;
+               break;
+       }
+
+       case VENC_START_OPT_ENCODE_FRAME: {
+               int hdr_sz;
+               int hdr_sz_ext;
+               int filler_sz = 0;
+               const int bs_alignment = 128;
+               struct mtk_vcodec_mem tmp_bs_buf;
+               unsigned int bs_size_hdr;
+               unsigned int bs_size_frm;
+
+               if (!inst->prepend_hdr) {
+                       ret = h264_encode_frame(inst, frm_buf, bs_buf,
+                                               &result->bs_size);
+                       if (ret)
+                               goto encode_err;
+                       result->is_key_frm = inst->vpu_inst.is_key_frm;
+                       break;
+               }
+
+               mtk_vcodec_debug(inst, "h264_encode_frame prepend SPS/PPS");
+
+               ret = h264_encode_header(inst, bs_buf, &bs_size_hdr);
+               if (ret)
+                       goto encode_err;
+
+               hdr_sz = bs_size_hdr;
+               hdr_sz_ext = (hdr_sz & (bs_alignment - 1));
+               if (hdr_sz_ext) {
+                       filler_sz = bs_alignment - hdr_sz_ext;
+                       if (hdr_sz_ext + H264_FILLER_MARKER_SIZE > bs_alignment)
+                               filler_sz += bs_alignment;
+                       h264_encode_filler(inst, bs_buf->va + hdr_sz,
+                                          filler_sz);
+               }
+
+               tmp_bs_buf.va = bs_buf->va + hdr_sz + filler_sz;
+               tmp_bs_buf.dma_addr = bs_buf->dma_addr + hdr_sz + filler_sz;
+               tmp_bs_buf.size = bs_buf->size - (hdr_sz + filler_sz);
+
+               ret = h264_encode_frame(inst, frm_buf, &tmp_bs_buf,
+                                       &bs_size_frm);
+               if (ret)
+                       goto encode_err;
+
+               result->bs_size = hdr_sz + filler_sz + bs_size_frm;
+
+               mtk_vcodec_debug(inst, "hdr %d filler %d frame %d bs %d",
+                                hdr_sz, filler_sz, bs_size_frm,
+                                result->bs_size);
+
+               inst->prepend_hdr = 0;
+               result->is_key_frm = inst->vpu_inst.is_key_frm;
+               break;
+       }
+
+       default:
+               mtk_vcodec_err(inst, "venc_start_opt %d not supported", opt);
+               ret = -EINVAL;
+               break;
+       }
+
+encode_err:
+
+       disable_irq(ctx->dev->enc_irq);
+       mtk_vcodec_debug(inst, "opt %d <-", opt);
+
+       return ret;
+}
+
+static int h264_enc_set_param(void *handle,
+                             enum venc_set_param_type type,
+                             struct venc_enc_param *enc_prm)
+{
+       int ret = 0;
+       struct venc_h264_inst *inst = (struct venc_h264_inst *)handle;
+
+       mtk_vcodec_debug(inst, "->type=%d", type);
+
+       switch (type) {
+       case VENC_SET_PARAM_ENC:
+               inst->vsi->config.input_fourcc = enc_prm->input_yuv_fmt;
+               inst->vsi->config.bitrate = enc_prm->bitrate;
+               inst->vsi->config.pic_w = enc_prm->width;
+               inst->vsi->config.pic_h = enc_prm->height;
+               inst->vsi->config.buf_w = enc_prm->buf_width;
+               inst->vsi->config.buf_h = enc_prm->buf_height;
+               inst->vsi->config.gop_size = enc_prm->gop_size;
+               inst->vsi->config.framerate = enc_prm->frm_rate;
+               inst->vsi->config.intra_period = enc_prm->intra_period;
+               inst->vsi->config.profile =
+                       h264_get_profile(inst, enc_prm->h264_profile);
+               inst->vsi->config.level =
+                       h264_get_level(inst, enc_prm->h264_level);
+               inst->vsi->config.wfd = 0;
+               ret = vpu_enc_set_param(&inst->vpu_inst, type, enc_prm);
+               if (ret)
+                       break;
+               if (inst->work_buf_allocated) {
+                       h264_enc_free_work_buf(inst);
+                       inst->work_buf_allocated = false;
+               }
+               ret = h264_enc_alloc_work_buf(inst);
+               if (ret)
+                       break;
+               inst->work_buf_allocated = true;
+               break;
+
+       case VENC_SET_PARAM_PREPEND_HEADER:
+               inst->prepend_hdr = 1;
+               mtk_vcodec_debug(inst, "set prepend header mode");
+               break;
+       case VENC_SET_PARAM_FORCE_INTRA:
+       case VENC_SET_PARAM_GOP_SIZE:
+       case VENC_SET_PARAM_INTRA_PERIOD:
+               inst->frm_cnt = 0;
+               inst->skip_frm_cnt = 0;
+               fallthrough;
+       default:
+               ret = vpu_enc_set_param(&inst->vpu_inst, type, enc_prm);
+               break;
+       }
+
+       mtk_vcodec_debug_leave(inst);
+
+       return ret;
+}
+
+static int h264_enc_deinit(void *handle)
+{
+       int ret = 0;
+       struct venc_h264_inst *inst = (struct venc_h264_inst *)handle;
+
+       mtk_vcodec_debug_enter(inst);
+
+       ret = vpu_enc_deinit(&inst->vpu_inst);
+
+       if (inst->work_buf_allocated)
+               h264_enc_free_work_buf(inst);
+
+       mtk_vcodec_debug_leave(inst);
+       kfree(inst);
+
+       return ret;
+}
+
+const struct venc_common_if venc_h264_if = {
+       .init = h264_enc_init,
+       .encode = h264_enc_encode,
+       .set_param = h264_enc_set_param,
+       .deinit = h264_enc_deinit,
+};
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/venc/venc_vp8_if.c b/drivers/media/platform/mediatek/mtk-vcodec/venc/venc_vp8_if.c
new file mode 100644 (file)
index 0000000..56ce58f
--- /dev/null
@@ -0,0 +1,468 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Daniel Hsiao <daniel.hsiao@mediatek.com>
+ *         PoChun Lin <pochun.lin@mediatek.com>
+ */
+
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include "../mtk_vcodec_drv.h"
+#include "../mtk_vcodec_util.h"
+#include "../mtk_vcodec_intr.h"
+#include "../mtk_vcodec_enc.h"
+#include "../mtk_vcodec_enc_pm.h"
+#include "../venc_drv_base.h"
+#include "../venc_ipi_msg.h"
+#include "../venc_vpu_if.h"
+
+#define VENC_BITSTREAM_FRAME_SIZE 0x0098
+#define VENC_BITSTREAM_HEADER_LEN 0x00e8
+
+/* This ac_tag is vp8 frame tag. */
+#define MAX_AC_TAG_SIZE 10
+
+/*
+ * enum venc_vp8_vpu_work_buf - vp8 encoder buffer index
+ */
+enum venc_vp8_vpu_work_buf {
+       VENC_VP8_VPU_WORK_BUF_LUMA,
+       VENC_VP8_VPU_WORK_BUF_LUMA2,
+       VENC_VP8_VPU_WORK_BUF_LUMA3,
+       VENC_VP8_VPU_WORK_BUF_CHROMA,
+       VENC_VP8_VPU_WORK_BUF_CHROMA2,
+       VENC_VP8_VPU_WORK_BUF_CHROMA3,
+       VENC_VP8_VPU_WORK_BUF_MV_INFO,
+       VENC_VP8_VPU_WORK_BUF_BS_HEADER,
+       VENC_VP8_VPU_WORK_BUF_PROB_BUF,
+       VENC_VP8_VPU_WORK_BUF_RC_INFO,
+       VENC_VP8_VPU_WORK_BUF_RC_CODE,
+       VENC_VP8_VPU_WORK_BUF_RC_CODE2,
+       VENC_VP8_VPU_WORK_BUF_RC_CODE3,
+       VENC_VP8_VPU_WORK_BUF_MAX,
+};
+
+/*
+ * struct venc_vp8_vpu_config - Structure for vp8 encoder configuration
+ *                              AP-W/R : AP is writer/reader on this item
+ *                              VPU-W/R: VPU is write/reader on this item
+ * @input_fourcc: input fourcc
+ * @bitrate: target bitrate (in bps)
+ * @pic_w: picture width. Picture size is visible stream resolution, in pixels,
+ *         to be used for display purposes; must be smaller or equal to buffer
+ *         size.
+ * @pic_h: picture height
+ * @buf_w: buffer width (with 16 alignment). Buffer size is stream resolution
+ *         in pixels aligned to hardware requirements.
+ * @buf_h: buffer height (with 16 alignment)
+ * @gop_size: group of picture size (key frame)
+ * @framerate: frame rate in fps
+ * @ts_mode: temporal scalability mode (0: disable, 1: enable)
+ *          support three temporal layers - 0: 7.5fps 1: 7.5fps 2: 15fps.
+ */
+struct venc_vp8_vpu_config {
+       u32 input_fourcc;
+       u32 bitrate;
+       u32 pic_w;
+       u32 pic_h;
+       u32 buf_w;
+       u32 buf_h;
+       u32 gop_size;
+       u32 framerate;
+       u32 ts_mode;
+};
+
+/*
+ * struct venc_vp8_vpu_buf - Structure for buffer information
+ *                           AP-W/R : AP is writer/reader on this item
+ *                           VPU-W/R: VPU is write/reader on this item
+ * @iova: IO virtual address
+ * @vpua: VPU side memory addr which is used by RC_CODE
+ * @size: buffer size (in bytes)
+ */
+struct venc_vp8_vpu_buf {
+       u32 iova;
+       u32 vpua;
+       u32 size;
+};
+
+/*
+ * struct venc_vp8_vsi - Structure for VPU driver control and info share
+ *                       AP-W/R : AP is writer/reader on this item
+ *                       VPU-W/R: VPU is write/reader on this item
+ * This structure is allocated in VPU side and shared to AP side.
+ * @config: vp8 encoder configuration
+ * @work_bufs: working buffer information in VPU side
+ * The work_bufs here is for storing the 'size' info shared to AP side.
+ * The similar item in struct venc_vp8_inst is for memory allocation
+ * in AP side. The AP driver will copy the 'size' from here to the one in
+ * struct mtk_vcodec_mem, then invoke mtk_vcodec_mem_alloc to allocate
+ * the buffer. After that, bypass the 'dma_addr' to the 'iova' field here for
+ * register setting in VPU side.
+ */
+struct venc_vp8_vsi {
+       struct venc_vp8_vpu_config config;
+       struct venc_vp8_vpu_buf work_bufs[VENC_VP8_VPU_WORK_BUF_MAX];
+};
+
+/*
+ * struct venc_vp8_inst - vp8 encoder AP driver instance
+ * @hw_base: vp8 encoder hardware register base
+ * @work_bufs: working buffer
+ * @work_buf_allocated: working buffer allocated flag
+ * @frm_cnt: encoded frame count, it's used for I-frame judgement and
+ *          reset when force intra cmd received.
+ * @ts_mode: temporal scalability mode (0: disable, 1: enable)
+ *          support three temporal layers - 0: 7.5fps 1: 7.5fps 2: 15fps.
+ * @vpu_inst: VPU instance to exchange information between AP and VPU
+ * @vsi: driver structure allocated by VPU side and shared to AP side for
+ *      control and info share
+ * @ctx: context for v4l2 layer integration
+ */
+struct venc_vp8_inst {
+       void __iomem *hw_base;
+       struct mtk_vcodec_mem work_bufs[VENC_VP8_VPU_WORK_BUF_MAX];
+       bool work_buf_allocated;
+       unsigned int frm_cnt;
+       unsigned int ts_mode;
+       struct venc_vpu_inst vpu_inst;
+       struct venc_vp8_vsi *vsi;
+       struct mtk_vcodec_ctx *ctx;
+};
+
+static inline u32 vp8_enc_read_reg(struct venc_vp8_inst *inst, u32 addr)
+{
+       return readl(inst->hw_base + addr);
+}
+
+static void vp8_enc_free_work_buf(struct venc_vp8_inst *inst)
+{
+       int i;
+
+       mtk_vcodec_debug_enter(inst);
+
+       /* Buffers need to be freed by AP. */
+       for (i = 0; i < VENC_VP8_VPU_WORK_BUF_MAX; i++) {
+               if (inst->work_bufs[i].size == 0)
+                       continue;
+               mtk_vcodec_mem_free(inst->ctx, &inst->work_bufs[i]);
+       }
+
+       mtk_vcodec_debug_leave(inst);
+}
+
+static int vp8_enc_alloc_work_buf(struct venc_vp8_inst *inst)
+{
+       int i;
+       int ret = 0;
+       struct venc_vp8_vpu_buf *wb = inst->vsi->work_bufs;
+
+       mtk_vcodec_debug_enter(inst);
+
+       for (i = 0; i < VENC_VP8_VPU_WORK_BUF_MAX; i++) {
+               if (wb[i].size == 0)
+                       continue;
+               /*
+                * This 'wb' structure is set by VPU side and shared to AP for
+                * buffer allocation and IO virtual addr mapping. For most of
+                * the buffers, AP will allocate the buffer according to 'size'
+                * field and store the IO virtual addr in 'iova' field. For the
+                * RC_CODEx buffers, they are pre-allocated in the VPU side
+                * because they are inside VPU SRAM, and save the VPU addr in
+                * the 'vpua' field. The AP will translate the VPU addr to the
+                * corresponding IO virtual addr and store in 'iova' field.
+                */
+               inst->work_bufs[i].size = wb[i].size;
+               ret = mtk_vcodec_mem_alloc(inst->ctx, &inst->work_bufs[i]);
+               if (ret) {
+                       mtk_vcodec_err(inst,
+                                      "cannot alloc work_bufs[%d]", i);
+                       goto err_alloc;
+               }
+               /*
+                * This RC_CODEx is pre-allocated by VPU and saved in VPU addr.
+                * So we need use memcpy to copy RC_CODEx from VPU addr into IO
+                * virtual addr in 'iova' field for reg setting in VPU side.
+                */
+               if (i == VENC_VP8_VPU_WORK_BUF_RC_CODE ||
+                   i == VENC_VP8_VPU_WORK_BUF_RC_CODE2 ||
+                   i == VENC_VP8_VPU_WORK_BUF_RC_CODE3) {
+                       struct mtk_vcodec_fw *handler;
+                       void *tmp_va;
+
+                       handler = inst->vpu_inst.ctx->dev->fw_handler;
+                       tmp_va = mtk_vcodec_fw_map_dm_addr(handler,
+                                                          wb[i].vpua);
+                       memcpy(inst->work_bufs[i].va, tmp_va, wb[i].size);
+               }
+               wb[i].iova = inst->work_bufs[i].dma_addr;
+
+               mtk_vcodec_debug(inst,
+                                "work_bufs[%d] va=0x%p,iova=%pad,size=%zu",
+                                i, inst->work_bufs[i].va,
+                                &inst->work_bufs[i].dma_addr,
+                                inst->work_bufs[i].size);
+       }
+
+       mtk_vcodec_debug_leave(inst);
+
+       return ret;
+
+err_alloc:
+       vp8_enc_free_work_buf(inst);
+
+       return ret;
+}
+
+static unsigned int vp8_enc_wait_venc_done(struct venc_vp8_inst *inst)
+{
+       unsigned int irq_status = 0;
+       struct mtk_vcodec_ctx *ctx = (struct mtk_vcodec_ctx *)inst->ctx;
+
+       if (!mtk_vcodec_wait_for_done_ctx(ctx, MTK_INST_IRQ_RECEIVED,
+                                         WAIT_INTR_TIMEOUT_MS, 0)) {
+               irq_status = ctx->irq_status;
+               mtk_vcodec_debug(inst, "isr return %x", irq_status);
+       }
+       return irq_status;
+}
+
+/*
+ * Compose ac_tag, bitstream header and bitstream payload into
+ * one bitstream buffer.
+ */
+static int vp8_enc_compose_one_frame(struct venc_vp8_inst *inst,
+                                    struct mtk_vcodec_mem *bs_buf,
+                                    unsigned int *bs_size)
+{
+       unsigned int not_key;
+       u32 bs_frm_size;
+       u32 bs_hdr_len;
+       unsigned int ac_tag_size;
+       u8 ac_tag[MAX_AC_TAG_SIZE];
+       u32 tag;
+
+       bs_frm_size = vp8_enc_read_reg(inst, VENC_BITSTREAM_FRAME_SIZE);
+       bs_hdr_len = vp8_enc_read_reg(inst, VENC_BITSTREAM_HEADER_LEN);
+
+       /* if a frame is key frame, not_key is 0 */
+       not_key = !inst->vpu_inst.is_key_frm;
+       tag = (bs_hdr_len << 5) | 0x10 | not_key;
+       ac_tag[0] = tag & 0xff;
+       ac_tag[1] = (tag >> 8) & 0xff;
+       ac_tag[2] = (tag >> 16) & 0xff;
+
+       /* key frame */
+       if (not_key == 0) {
+               ac_tag_size = MAX_AC_TAG_SIZE;
+               ac_tag[3] = 0x9d;
+               ac_tag[4] = 0x01;
+               ac_tag[5] = 0x2a;
+               ac_tag[6] = inst->vsi->config.pic_w;
+               ac_tag[7] = inst->vsi->config.pic_w >> 8;
+               ac_tag[8] = inst->vsi->config.pic_h;
+               ac_tag[9] = inst->vsi->config.pic_h >> 8;
+       } else {
+               ac_tag_size = 3;
+       }
+
+       if (bs_buf->size < bs_hdr_len + bs_frm_size + ac_tag_size) {
+               mtk_vcodec_err(inst, "bitstream buf size is too small(%zu)",
+                              bs_buf->size);
+               return -EINVAL;
+       }
+
+       /*
+       * (1) The vp8 bitstream header and body are generated by the HW vp8
+       * encoder separately at the same time. We cannot know the bitstream
+       * header length in advance.
+       * (2) From the vp8 spec, there is no stuffing byte allowed between the
+       * ac tag, bitstream header and bitstream body.
+       */
+       memmove(bs_buf->va + bs_hdr_len + ac_tag_size,
+               bs_buf->va, bs_frm_size);
+       memcpy(bs_buf->va + ac_tag_size,
+              inst->work_bufs[VENC_VP8_VPU_WORK_BUF_BS_HEADER].va,
+              bs_hdr_len);
+       memcpy(bs_buf->va, ac_tag, ac_tag_size);
+       *bs_size = bs_frm_size + bs_hdr_len + ac_tag_size;
+
+       return 0;
+}
+
+static int vp8_enc_encode_frame(struct venc_vp8_inst *inst,
+                               struct venc_frm_buf *frm_buf,
+                               struct mtk_vcodec_mem *bs_buf,
+                               unsigned int *bs_size)
+{
+       int ret = 0;
+       unsigned int irq_status;
+
+       mtk_vcodec_debug(inst, "->frm_cnt=%d", inst->frm_cnt);
+
+       ret = vpu_enc_encode(&inst->vpu_inst, 0, frm_buf, bs_buf, NULL);
+       if (ret)
+               return ret;
+
+       irq_status = vp8_enc_wait_venc_done(inst);
+       if (irq_status != MTK_VENC_IRQ_STATUS_FRM) {
+               mtk_vcodec_err(inst, "irq_status=%d failed", irq_status);
+               return -EIO;
+       }
+
+       if (vp8_enc_compose_one_frame(inst, bs_buf, bs_size)) {
+               mtk_vcodec_err(inst, "vp8_enc_compose_one_frame failed");
+               return -EINVAL;
+       }
+
+       inst->frm_cnt++;
+       mtk_vcodec_debug(inst, "<-size=%d key_frm=%d", *bs_size,
+                        inst->vpu_inst.is_key_frm);
+
+       return ret;
+}
+
+static int vp8_enc_init(struct mtk_vcodec_ctx *ctx)
+{
+       int ret = 0;
+       struct venc_vp8_inst *inst;
+
+       inst = kzalloc(sizeof(*inst), GFP_KERNEL);
+       if (!inst)
+               return -ENOMEM;
+
+       inst->ctx = ctx;
+       inst->vpu_inst.ctx = ctx;
+       inst->vpu_inst.id = IPI_VENC_VP8;
+       inst->hw_base = mtk_vcodec_get_reg_addr(inst->ctx, VENC_LT_SYS);
+
+       mtk_vcodec_debug_enter(inst);
+
+       ret = vpu_enc_init(&inst->vpu_inst);
+
+       inst->vsi = (struct venc_vp8_vsi *)inst->vpu_inst.vsi;
+
+       mtk_vcodec_debug_leave(inst);
+
+       if (ret)
+               kfree(inst);
+       else
+               ctx->drv_handle = inst;
+
+       return ret;
+}
+
+static int vp8_enc_encode(void *handle,
+                         enum venc_start_opt opt,
+                         struct venc_frm_buf *frm_buf,
+                         struct mtk_vcodec_mem *bs_buf,
+                         struct venc_done_result *result)
+{
+       int ret = 0;
+       struct venc_vp8_inst *inst = (struct venc_vp8_inst *)handle;
+       struct mtk_vcodec_ctx *ctx = inst->ctx;
+
+       mtk_vcodec_debug_enter(inst);
+
+       enable_irq(ctx->dev->enc_irq);
+
+       switch (opt) {
+       case VENC_START_OPT_ENCODE_FRAME:
+               ret = vp8_enc_encode_frame(inst, frm_buf, bs_buf,
+                                          &result->bs_size);
+               if (ret)
+                       goto encode_err;
+               result->is_key_frm = inst->vpu_inst.is_key_frm;
+               break;
+
+       default:
+               mtk_vcodec_err(inst, "opt not support:%d", opt);
+               ret = -EINVAL;
+               break;
+       }
+
+encode_err:
+
+       disable_irq(ctx->dev->enc_irq);
+       mtk_vcodec_debug_leave(inst);
+
+       return ret;
+}
+
+static int vp8_enc_set_param(void *handle,
+                            enum venc_set_param_type type,
+                            struct venc_enc_param *enc_prm)
+{
+       int ret = 0;
+       struct venc_vp8_inst *inst = (struct venc_vp8_inst *)handle;
+
+       mtk_vcodec_debug(inst, "->type=%d", type);
+
+       switch (type) {
+       case VENC_SET_PARAM_ENC:
+               inst->vsi->config.input_fourcc = enc_prm->input_yuv_fmt;
+               inst->vsi->config.bitrate = enc_prm->bitrate;
+               inst->vsi->config.pic_w = enc_prm->width;
+               inst->vsi->config.pic_h = enc_prm->height;
+               inst->vsi->config.buf_w = enc_prm->buf_width;
+               inst->vsi->config.buf_h = enc_prm->buf_height;
+               inst->vsi->config.gop_size = enc_prm->gop_size;
+               inst->vsi->config.framerate = enc_prm->frm_rate;
+               inst->vsi->config.ts_mode = inst->ts_mode;
+               ret = vpu_enc_set_param(&inst->vpu_inst, type, enc_prm);
+               if (ret)
+                       break;
+               if (inst->work_buf_allocated) {
+                       vp8_enc_free_work_buf(inst);
+                       inst->work_buf_allocated = false;
+               }
+               ret = vp8_enc_alloc_work_buf(inst);
+               if (ret)
+                       break;
+               inst->work_buf_allocated = true;
+               break;
+
+       /*
+        * VENC_SET_PARAM_TS_MODE must be called before VENC_SET_PARAM_ENC
+        */
+       case VENC_SET_PARAM_TS_MODE:
+               inst->ts_mode = 1;
+               mtk_vcodec_debug(inst, "set ts_mode");
+               break;
+
+       default:
+               ret = vpu_enc_set_param(&inst->vpu_inst, type, enc_prm);
+               break;
+       }
+
+       mtk_vcodec_debug_leave(inst);
+
+       return ret;
+}
+
+static int vp8_enc_deinit(void *handle)
+{
+       int ret = 0;
+       struct venc_vp8_inst *inst = (struct venc_vp8_inst *)handle;
+
+       mtk_vcodec_debug_enter(inst);
+
+       ret = vpu_enc_deinit(&inst->vpu_inst);
+
+       if (inst->work_buf_allocated)
+               vp8_enc_free_work_buf(inst);
+
+       mtk_vcodec_debug_leave(inst);
+       kfree(inst);
+
+       return ret;
+}
+
+const struct venc_common_if venc_vp8_if = {
+       .init = vp8_enc_init,
+       .encode = vp8_enc_encode,
+       .set_param = vp8_enc_set_param,
+       .deinit = vp8_enc_deinit,
+};
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/venc_drv_base.h b/drivers/media/platform/mediatek/mtk-vcodec/venc_drv_base.h
new file mode 100644 (file)
index 0000000..3d71841
--- /dev/null
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Daniel Hsiao <daniel.hsiao@mediatek.com>
+ *     Jungchang Tsao <jungchang.tsao@mediatek.com>
+ *     Tiffany Lin <tiffany.lin@mediatek.com>
+ */
+
+#ifndef _VENC_DRV_BASE_
+#define _VENC_DRV_BASE_
+
+#include "mtk_vcodec_drv.h"
+
+#include "venc_drv_if.h"
+
+struct venc_common_if {
+       /**
+        * (*init)() - initialize driver
+        * @ctx:        [in] mtk v4l2 context
+        * @handle: [out] driver handle
+        */
+       int (*init)(struct mtk_vcodec_ctx *ctx);
+
+       /**
+        * (*encode)() - trigger encode
+        * @handle: [in] driver handle
+        * @opt: [in] encode option
+        * @frm_buf: [in] frame buffer to store input frame
+        * @bs_buf: [in] bitstream buffer to store output bitstream
+        * @result: [out] encode result
+        */
+       int (*encode)(void *handle, enum venc_start_opt opt,
+                     struct venc_frm_buf *frm_buf,
+                     struct mtk_vcodec_mem *bs_buf,
+                     struct venc_done_result *result);
+
+       /**
+        * (*set_param)() - set driver's parameter
+        * @handle: [in] driver handle
+        * @type: [in] parameter type
+        * @in: [in] buffer to store the parameter
+        */
+       int (*set_param)(void *handle, enum venc_set_param_type type,
+                        struct venc_enc_param *in);
+
+       /**
+        * (*deinit)() - deinitialize driver.
+        * @handle: [in] driver handle
+        */
+       int (*deinit)(void *handle);
+};
+
+#endif
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/venc_drv_if.c b/drivers/media/platform/mediatek/mtk-vcodec/venc_drv_if.c
new file mode 100644 (file)
index 0000000..ce0bce8
--- /dev/null
@@ -0,0 +1,100 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Daniel Hsiao <daniel.hsiao@mediatek.com>
+ *     Jungchang Tsao <jungchang.tsao@mediatek.com>
+ *     Tiffany Lin <tiffany.lin@mediatek.com>
+ */
+
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include "venc_drv_base.h"
+#include "venc_drv_if.h"
+
+#include "mtk_vcodec_enc.h"
+#include "mtk_vcodec_enc_pm.h"
+
+int venc_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc)
+{
+       int ret = 0;
+
+       switch (fourcc) {
+       case V4L2_PIX_FMT_VP8:
+               ctx->enc_if = &venc_vp8_if;
+               break;
+       case V4L2_PIX_FMT_H264:
+               ctx->enc_if = &venc_h264_if;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       mtk_venc_lock(ctx);
+       mtk_vcodec_enc_clock_on(&ctx->dev->pm);
+       ret = ctx->enc_if->init(ctx);
+       mtk_vcodec_enc_clock_off(&ctx->dev->pm);
+       mtk_venc_unlock(ctx);
+
+       return ret;
+}
+
+int venc_if_set_param(struct mtk_vcodec_ctx *ctx,
+               enum venc_set_param_type type, struct venc_enc_param *in)
+{
+       int ret = 0;
+
+       mtk_venc_lock(ctx);
+       mtk_vcodec_enc_clock_on(&ctx->dev->pm);
+       ret = ctx->enc_if->set_param(ctx->drv_handle, type, in);
+       mtk_vcodec_enc_clock_off(&ctx->dev->pm);
+       mtk_venc_unlock(ctx);
+
+       return ret;
+}
+
+int venc_if_encode(struct mtk_vcodec_ctx *ctx,
+                  enum venc_start_opt opt, struct venc_frm_buf *frm_buf,
+                  struct mtk_vcodec_mem *bs_buf,
+                  struct venc_done_result *result)
+{
+       int ret = 0;
+       unsigned long flags;
+
+       mtk_venc_lock(ctx);
+
+       spin_lock_irqsave(&ctx->dev->irqlock, flags);
+       ctx->dev->curr_ctx = ctx;
+       spin_unlock_irqrestore(&ctx->dev->irqlock, flags);
+
+       mtk_vcodec_enc_clock_on(&ctx->dev->pm);
+       ret = ctx->enc_if->encode(ctx->drv_handle, opt, frm_buf,
+                                 bs_buf, result);
+       mtk_vcodec_enc_clock_off(&ctx->dev->pm);
+
+       spin_lock_irqsave(&ctx->dev->irqlock, flags);
+       ctx->dev->curr_ctx = NULL;
+       spin_unlock_irqrestore(&ctx->dev->irqlock, flags);
+
+       mtk_venc_unlock(ctx);
+       return ret;
+}
+
+int venc_if_deinit(struct mtk_vcodec_ctx *ctx)
+{
+       int ret = 0;
+
+       if (!ctx->drv_handle)
+               return 0;
+
+       mtk_venc_lock(ctx);
+       mtk_vcodec_enc_clock_on(&ctx->dev->pm);
+       ret = ctx->enc_if->deinit(ctx->drv_handle);
+       mtk_vcodec_enc_clock_off(&ctx->dev->pm);
+       mtk_venc_unlock(ctx);
+
+       ctx->drv_handle = NULL;
+
+       return ret;
+}
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/venc_drv_if.h b/drivers/media/platform/mediatek/mtk-vcodec/venc_drv_if.h
new file mode 100644 (file)
index 0000000..0b04a10
--- /dev/null
@@ -0,0 +1,170 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Daniel Hsiao <daniel.hsiao@mediatek.com>
+ *             Jungchang Tsao <jungchang.tsao@mediatek.com>
+ *             Tiffany Lin <tiffany.lin@mediatek.com>
+ */
+
+#ifndef _VENC_DRV_IF_H_
+#define _VENC_DRV_IF_H_
+
+#include "mtk_vcodec_drv.h"
+#include "mtk_vcodec_util.h"
+
+/*
+ * enum venc_yuv_fmt - The type of input yuv format
+ * (VPU related: If you change the order, you must also update the VPU codes.)
+ * @VENC_YUV_FORMAT_I420: I420 YUV format
+ * @VENC_YUV_FORMAT_YV12: YV12 YUV format
+ * @VENC_YUV_FORMAT_NV12: NV12 YUV format
+ * @VENC_YUV_FORMAT_NV21: NV21 YUV format
+ */
+enum venc_yuv_fmt {
+       VENC_YUV_FORMAT_I420 = 3,
+       VENC_YUV_FORMAT_YV12 = 5,
+       VENC_YUV_FORMAT_NV12 = 6,
+       VENC_YUV_FORMAT_NV21 = 7,
+};
+
+/*
+ * enum venc_start_opt - encode frame option used in venc_if_encode()
+ * @VENC_START_OPT_ENCODE_SEQUENCE_HEADER: encode SPS/PPS for H264
+ * @VENC_START_OPT_ENCODE_FRAME: encode normal frame
+ */
+enum venc_start_opt {
+       VENC_START_OPT_ENCODE_SEQUENCE_HEADER,
+       VENC_START_OPT_ENCODE_FRAME,
+};
+
+/*
+ * enum venc_set_param_type - The type of set parameter used in
+ *                                                   venc_if_set_param()
+ * (VPU related: If you change the order, you must also update the VPU codes.)
+ * @VENC_SET_PARAM_ENC: set encoder parameters
+ * @VENC_SET_PARAM_FORCE_INTRA: force an intra frame
+ * @VENC_SET_PARAM_ADJUST_BITRATE: adjust bitrate (in bps)
+ * @VENC_SET_PARAM_ADJUST_FRAMERATE: set frame rate
+ * @VENC_SET_PARAM_GOP_SIZE: set IDR interval
+ * @VENC_SET_PARAM_INTRA_PERIOD: set I frame interval
+ * @VENC_SET_PARAM_SKIP_FRAME: set H264 skip one frame
+ * @VENC_SET_PARAM_PREPEND_HEADER: set H264 prepend SPS/PPS before IDR
+ * @VENC_SET_PARAM_TS_MODE: set VP8 temporal scalability mode
+ */
+enum venc_set_param_type {
+       VENC_SET_PARAM_ENC,
+       VENC_SET_PARAM_FORCE_INTRA,
+       VENC_SET_PARAM_ADJUST_BITRATE,
+       VENC_SET_PARAM_ADJUST_FRAMERATE,
+       VENC_SET_PARAM_GOP_SIZE,
+       VENC_SET_PARAM_INTRA_PERIOD,
+       VENC_SET_PARAM_SKIP_FRAME,
+       VENC_SET_PARAM_PREPEND_HEADER,
+       VENC_SET_PARAM_TS_MODE,
+};
+
+/*
+ * struct venc_enc_prm - encoder settings for VENC_SET_PARAM_ENC used in
+ *                                       venc_if_set_param()
+ * @input_fourcc: input yuv format
+ * @h264_profile: V4L2 defined H.264 profile
+ * @h264_level: V4L2 defined H.264 level
+ * @width: image width
+ * @height: image height
+ * @buf_width: buffer width
+ * @buf_height: buffer height
+ * @frm_rate: frame rate in fps
+ * @intra_period: intra frame period
+ * @bitrate: target bitrate in bps
+ * @gop_size: group of picture size
+ */
+struct venc_enc_param {
+       enum venc_yuv_fmt input_yuv_fmt;
+       unsigned int h264_profile;
+       unsigned int h264_level;
+       unsigned int width;
+       unsigned int height;
+       unsigned int buf_width;
+       unsigned int buf_height;
+       unsigned int frm_rate;
+       unsigned int intra_period;
+       unsigned int bitrate;
+       unsigned int gop_size;
+};
+
+/**
+ * struct venc_frame_info - per-frame information to pass to the firmware.
+ *
+ * @frm_count:         sequential number for this frame
+ * @skip_frm_count:    number of frames skipped so far while decoding
+ * @frm_type:          type of the frame, from enum venc_h264_frame_type
+ */
+struct venc_frame_info {
+       unsigned int frm_count;         /* per frame update */
+       unsigned int skip_frm_count;    /* per frame update */
+       unsigned int frm_type;          /* per frame update */
+};
+
+/*
+ * struct venc_frm_buf - frame buffer information used in venc_if_encode()
+ * @fb_addr: plane frame buffer addresses
+ */
+struct venc_frm_buf {
+       struct mtk_vcodec_fb fb_addr[MTK_VCODEC_MAX_PLANES];
+};
+
+/*
+ * struct venc_done_result - This is return information used in venc_if_encode()
+ * @bs_size: output bitstream size
+ * @is_key_frm: output is key frame or not
+ */
+struct venc_done_result {
+       unsigned int bs_size;
+       bool is_key_frm;
+};
+
+extern const struct venc_common_if venc_h264_if;
+extern const struct venc_common_if venc_vp8_if;
+
+/*
+ * venc_if_init - Create the driver handle
+ * @ctx: device context
+ * @fourcc: encoder input format
+ * Return: 0 if creating handle successfully, otherwise it is failed.
+ */
+int venc_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc);
+
+/*
+ * venc_if_deinit - Release the driver handle
+ * @ctx: device context
+ * Return: 0 if releasing handle successfully, otherwise it is failed.
+ */
+int venc_if_deinit(struct mtk_vcodec_ctx *ctx);
+
+/*
+ * venc_if_set_param - Set parameter to driver
+ * @ctx: device context
+ * @type: parameter type
+ * @in: input parameter
+ * Return: 0 if setting param successfully, otherwise it is failed.
+ */
+int venc_if_set_param(struct mtk_vcodec_ctx *ctx,
+                     enum venc_set_param_type type,
+                     struct venc_enc_param *in);
+
+/*
+ * venc_if_encode - Encode one frame
+ * @ctx: device context
+ * @opt: encode frame option
+ * @frm_buf: input frame buffer information
+ * @bs_buf: output bitstream buffer infomraiton
+ * @result: encode result
+ * Return: 0 if encoding frame successfully, otherwise it is failed.
+ */
+int venc_if_encode(struct mtk_vcodec_ctx *ctx,
+                  enum venc_start_opt opt,
+                  struct venc_frm_buf *frm_buf,
+                  struct mtk_vcodec_mem *bs_buf,
+                  struct venc_done_result *result);
+
+#endif /* _VENC_DRV_IF_H_ */
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/venc_ipi_msg.h b/drivers/media/platform/mediatek/mtk-vcodec/venc_ipi_msg.h
new file mode 100644 (file)
index 0000000..587a2cf
--- /dev/null
@@ -0,0 +1,220 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Jungchang Tsao <jungchang.tsao@mediatek.com>
+ *        Daniel Hsiao <daniel.hsiao@mediatek.com>
+ *        Tiffany Lin <tiffany.lin@mediatek.com>
+ */
+
+#ifndef _VENC_IPI_MSG_H_
+#define _VENC_IPI_MSG_H_
+
+#define AP_IPIMSG_VENC_BASE 0xC000
+#define VPU_IPIMSG_VENC_BASE 0xD000
+
+/*
+ * enum venc_ipi_msg_id - message id between AP and VPU
+ * (ipi stands for inter-processor interrupt)
+ * @AP_IPIMSG_ENC_XXX:         AP to VPU cmd message id
+ * @VPU_IPIMSG_ENC_XXX_DONE:   VPU ack AP cmd message id
+ */
+enum venc_ipi_msg_id {
+       AP_IPIMSG_ENC_INIT = AP_IPIMSG_VENC_BASE,
+       AP_IPIMSG_ENC_SET_PARAM,
+       AP_IPIMSG_ENC_ENCODE,
+       AP_IPIMSG_ENC_DEINIT,
+
+       VPU_IPIMSG_ENC_INIT_DONE = VPU_IPIMSG_VENC_BASE,
+       VPU_IPIMSG_ENC_SET_PARAM_DONE,
+       VPU_IPIMSG_ENC_ENCODE_DONE,
+       VPU_IPIMSG_ENC_DEINIT_DONE,
+};
+
+/**
+ * struct venc_ap_ipi_msg_init - AP to VPU init cmd structure
+ * @msg_id:    message id (AP_IPIMSG_XXX_ENC_INIT)
+ * @reserved:  reserved for future use. vpu is running in 32bit. Without
+ *             this reserved field, if kernel run in 64bit. this struct size
+ *             will be different between kernel and vpu
+ * @venc_inst: AP encoder instance
+ *             (struct venc_vp8_inst/venc_h264_inst *)
+ */
+struct venc_ap_ipi_msg_init {
+       uint32_t msg_id;
+       uint32_t reserved;
+       uint64_t venc_inst;
+};
+
+/**
+ * struct venc_ap_ipi_msg_set_param - AP to VPU set_param cmd structure
+ * @msg_id:    message id (AP_IPIMSG_XXX_ENC_SET_PARAM)
+ * @vpu_inst_addr:     VPU encoder instance addr
+ *                     (struct venc_vp8_vsi/venc_h264_vsi *)
+ * @param_id:  parameter id (venc_set_param_type)
+ * @data_item: number of items in the data array
+ * @data:      data array to store the set parameters
+ */
+struct venc_ap_ipi_msg_set_param {
+       uint32_t msg_id;
+       uint32_t vpu_inst_addr;
+       uint32_t param_id;
+       uint32_t data_item;
+       uint32_t data[8];
+};
+
+struct venc_ap_ipi_msg_set_param_ext {
+       struct venc_ap_ipi_msg_set_param base;
+       uint32_t data_ext[24];
+};
+
+/**
+ * struct venc_ap_ipi_msg_enc - AP to VPU enc cmd structure
+ * @msg_id:    message id (AP_IPIMSG_XXX_ENC_ENCODE)
+ * @vpu_inst_addr:     VPU encoder instance addr
+ *                     (struct venc_vp8_vsi/venc_h264_vsi *)
+ * @bs_mode:   bitstream mode for h264
+ *             (H264_BS_MODE_SPS/H264_BS_MODE_PPS/H264_BS_MODE_FRAME)
+ * @input_addr:        pointer to input image buffer plane
+ * @bs_addr:   pointer to output bit stream buffer
+ * @bs_size:   bit stream buffer size
+ */
+struct venc_ap_ipi_msg_enc {
+       uint32_t msg_id;
+       uint32_t vpu_inst_addr;
+       uint32_t bs_mode;
+       uint32_t input_addr[3];
+       uint32_t bs_addr;
+       uint32_t bs_size;
+};
+
+/**
+ * struct venc_ap_ipi_msg_enc_ext - AP to SCP extended enc cmd structure
+ *
+ * @base:      base msg structure
+ * @data_item: number of items in the data array
+ * @data:      data array to store the set parameters
+ */
+struct venc_ap_ipi_msg_enc_ext {
+       struct venc_ap_ipi_msg_enc base;
+       uint32_t data_item;
+       uint32_t data[32];
+};
+
+/**
+ * struct venc_ap_ipi_msg_deinit - AP to VPU deinit cmd structure
+ * @msg_id:    message id (AP_IPIMSG_XXX_ENC_DEINIT)
+ * @vpu_inst_addr:     VPU encoder instance addr
+ *                     (struct venc_vp8_vsi/venc_h264_vsi *)
+ */
+struct venc_ap_ipi_msg_deinit {
+       uint32_t msg_id;
+       uint32_t vpu_inst_addr;
+};
+
+/*
+ * enum venc_ipi_msg_status - VPU ack AP cmd status
+ */
+enum venc_ipi_msg_status {
+       VENC_IPI_MSG_STATUS_OK,
+       VENC_IPI_MSG_STATUS_FAIL,
+};
+
+/**
+ * struct venc_vpu_ipi_msg_common - VPU ack AP cmd common structure
+ * @msg_id:    message id (VPU_IPIMSG_XXX_DONE)
+ * @status:    cmd status (venc_ipi_msg_status)
+ * @venc_inst: AP encoder instance (struct venc_vp8_inst/venc_h264_inst *)
+ */
+struct venc_vpu_ipi_msg_common {
+       uint32_t msg_id;
+       uint32_t status;
+       uint64_t venc_inst;
+};
+
+/**
+ * struct venc_vpu_ipi_msg_init - VPU ack AP init cmd structure
+ * @msg_id:    message id (VPU_IPIMSG_XXX_ENC_SET_PARAM_DONE)
+ * @status:    cmd status (venc_ipi_msg_status)
+ * @venc_inst: AP encoder instance (struct venc_vp8_inst/venc_h264_inst *)
+ * @vpu_inst_addr:     VPU encoder instance addr
+ *                     (struct venc_vp8_vsi/venc_h264_vsi *)
+ * @venc_abi_version:  ABI version of the firmware. Kernel can use it to
+ *                     ensure that it is compatible with the firmware.
+ *                     For MT8173 the value of this field is undefined and
+ *                     should not be used.
+ */
+struct venc_vpu_ipi_msg_init {
+       uint32_t msg_id;
+       uint32_t status;
+       uint64_t venc_inst;
+       uint32_t vpu_inst_addr;
+       uint32_t venc_abi_version;
+};
+
+/**
+ * struct venc_vpu_ipi_msg_set_param - VPU ack AP set_param cmd structure
+ * @msg_id:    message id (VPU_IPIMSG_XXX_ENC_SET_PARAM_DONE)
+ * @status:    cmd status (venc_ipi_msg_status)
+ * @venc_inst: AP encoder instance (struct venc_vp8_inst/venc_h264_inst *)
+ * @param_id:  parameter id (venc_set_param_type)
+ * @data_item: number of items in the data array
+ * @data:      data array to store the return result
+ */
+struct venc_vpu_ipi_msg_set_param {
+       uint32_t msg_id;
+       uint32_t status;
+       uint64_t venc_inst;
+       uint32_t param_id;
+       uint32_t data_item;
+       uint32_t data[6];
+};
+
+/**
+ * enum venc_ipi_msg_enc_state - Type of encode state
+ * @VEN_IPI_MSG_ENC_STATE_FRAME:       one frame being encoded
+ * @VEN_IPI_MSG_ENC_STATE_PART:                bit stream buffer full
+ * @VEN_IPI_MSG_ENC_STATE_SKIP:                encoded skip frame
+ * @VEN_IPI_MSG_ENC_STATE_ERROR:       encounter error
+ */
+enum venc_ipi_msg_enc_state {
+       VEN_IPI_MSG_ENC_STATE_FRAME,
+       VEN_IPI_MSG_ENC_STATE_PART,
+       VEN_IPI_MSG_ENC_STATE_SKIP,
+       VEN_IPI_MSG_ENC_STATE_ERROR,
+};
+
+/**
+ * struct venc_vpu_ipi_msg_enc - VPU ack AP enc cmd structure
+ * @msg_id:    message id (VPU_IPIMSG_XXX_ENC_ENCODE_DONE)
+ * @status:    cmd status (venc_ipi_msg_status)
+ * @venc_inst: AP encoder instance (struct venc_vp8_inst/venc_h264_inst *)
+ * @state:     encode state (venc_ipi_msg_enc_state)
+ * @is_key_frm:        whether the encoded frame is key frame
+ * @bs_size:   encoded bitstream size
+ * @reserved:  reserved for future use. vpu is running in 32bit. Without
+ *             this reserved field, if kernel run in 64bit. this struct size
+ *             will be different between kernel and vpu
+ */
+struct venc_vpu_ipi_msg_enc {
+       uint32_t msg_id;
+       uint32_t status;
+       uint64_t venc_inst;
+       uint32_t state;
+       uint32_t is_key_frm;
+       uint32_t bs_size;
+       uint32_t reserved;
+};
+
+/**
+ * struct venc_vpu_ipi_msg_deinit - VPU ack AP deinit cmd structure
+ * @msg_id:   message id (VPU_IPIMSG_XXX_ENC_DEINIT_DONE)
+ * @status:   cmd status (venc_ipi_msg_status)
+ * @venc_inst: AP encoder instance (struct venc_vp8_inst/venc_h264_inst *)
+ */
+struct venc_vpu_ipi_msg_deinit {
+       uint32_t msg_id;
+       uint32_t status;
+       uint64_t venc_inst;
+};
+
+#endif /* _VENC_IPI_MSG_H_ */
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/venc_vpu_if.c b/drivers/media/platform/mediatek/mtk-vcodec/venc_vpu_if.c
new file mode 100644 (file)
index 0000000..e7899d8
--- /dev/null
@@ -0,0 +1,293 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: PoChun Lin <pochun.lin@mediatek.com>
+ */
+
+#include "mtk_vcodec_drv.h"
+#include "mtk_vcodec_fw.h"
+#include "venc_ipi_msg.h"
+#include "venc_vpu_if.h"
+
+static void handle_enc_init_msg(struct venc_vpu_inst *vpu, const void *data)
+{
+       const struct venc_vpu_ipi_msg_init *msg = data;
+
+       vpu->inst_addr = msg->vpu_inst_addr;
+       vpu->vsi = mtk_vcodec_fw_map_dm_addr(vpu->ctx->dev->fw_handler,
+                                            msg->vpu_inst_addr);
+
+       /* Firmware version field value is unspecified on MT8173. */
+       if (vpu->ctx->dev->venc_pdata->chip == MTK_MT8173)
+               return;
+
+       /* Check firmware version. */
+       mtk_vcodec_debug(vpu, "firmware version: 0x%x\n",
+                        msg->venc_abi_version);
+       switch (msg->venc_abi_version) {
+       case 1:
+               break;
+       default:
+               mtk_vcodec_err(vpu, "unhandled firmware version 0x%x\n",
+                              msg->venc_abi_version);
+               vpu->failure = 1;
+               break;
+       }
+}
+
+static void handle_enc_encode_msg(struct venc_vpu_inst *vpu, const void *data)
+{
+       const struct venc_vpu_ipi_msg_enc *msg = data;
+
+       vpu->state = msg->state;
+       vpu->bs_size = msg->bs_size;
+       vpu->is_key_frm = msg->is_key_frm;
+}
+
+static void vpu_enc_ipi_handler(void *data, unsigned int len, void *priv)
+{
+       const struct venc_vpu_ipi_msg_common *msg = data;
+       struct venc_vpu_inst *vpu =
+               (struct venc_vpu_inst *)(unsigned long)msg->venc_inst;
+
+       mtk_vcodec_debug(vpu, "msg_id %x inst %p status %d",
+                        msg->msg_id, vpu, msg->status);
+
+       vpu->signaled = 1;
+       vpu->failure = (msg->status != VENC_IPI_MSG_STATUS_OK);
+       if (vpu->failure)
+               goto failure;
+
+       switch (msg->msg_id) {
+       case VPU_IPIMSG_ENC_INIT_DONE:
+               handle_enc_init_msg(vpu, data);
+               break;
+       case VPU_IPIMSG_ENC_SET_PARAM_DONE:
+               break;
+       case VPU_IPIMSG_ENC_ENCODE_DONE:
+               handle_enc_encode_msg(vpu, data);
+               break;
+       case VPU_IPIMSG_ENC_DEINIT_DONE:
+               break;
+       default:
+               mtk_vcodec_err(vpu, "unknown msg id %x", msg->msg_id);
+               break;
+       }
+
+failure:
+       mtk_vcodec_debug_leave(vpu);
+}
+
+static int vpu_enc_send_msg(struct venc_vpu_inst *vpu, void *msg,
+                           int len)
+{
+       int status;
+
+       mtk_vcodec_debug_enter(vpu);
+
+       if (!vpu->ctx->dev->fw_handler) {
+               mtk_vcodec_err(vpu, "inst dev is NULL");
+               return -EINVAL;
+       }
+
+       status = mtk_vcodec_fw_ipi_send(vpu->ctx->dev->fw_handler, vpu->id, msg,
+                                       len, 2000);
+       if (status) {
+               mtk_vcodec_err(vpu, "vpu_ipi_send msg_id %x len %d fail %d",
+                              *(uint32_t *)msg, len, status);
+               return -EINVAL;
+       }
+       if (vpu->failure)
+               return -EINVAL;
+
+       mtk_vcodec_debug_leave(vpu);
+
+       return 0;
+}
+
+int vpu_enc_init(struct venc_vpu_inst *vpu)
+{
+       int status;
+       struct venc_ap_ipi_msg_init out;
+
+       mtk_vcodec_debug_enter(vpu);
+
+       init_waitqueue_head(&vpu->wq_hd);
+       vpu->signaled = 0;
+       vpu->failure = 0;
+
+       status = mtk_vcodec_fw_ipi_register(vpu->ctx->dev->fw_handler, vpu->id,
+                                           vpu_enc_ipi_handler, "venc", NULL);
+
+       if (status) {
+               mtk_vcodec_err(vpu, "vpu_ipi_register fail %d", status);
+               return -EINVAL;
+       }
+
+       memset(&out, 0, sizeof(out));
+       out.msg_id = AP_IPIMSG_ENC_INIT;
+       out.venc_inst = (unsigned long)vpu;
+       if (vpu_enc_send_msg(vpu, &out, sizeof(out))) {
+               mtk_vcodec_err(vpu, "AP_IPIMSG_ENC_INIT fail");
+               return -EINVAL;
+       }
+
+       mtk_vcodec_debug_leave(vpu);
+
+       return 0;
+}
+
+static unsigned int venc_enc_param_crop_right(struct venc_vpu_inst *vpu,
+                                             struct venc_enc_param *enc_prm)
+{
+       unsigned int img_crop_right = enc_prm->buf_width - enc_prm->width;
+
+       return img_crop_right % 16;
+}
+
+static unsigned int venc_enc_param_crop_bottom(struct venc_enc_param *enc_prm)
+{
+       return round_up(enc_prm->height, 16) - enc_prm->height;
+}
+
+static unsigned int venc_enc_param_num_mb(struct venc_enc_param *enc_prm)
+{
+       return DIV_ROUND_UP(enc_prm->width, 16) *
+              DIV_ROUND_UP(enc_prm->height, 16);
+}
+
+int vpu_enc_set_param(struct venc_vpu_inst *vpu,
+                     enum venc_set_param_type id,
+                     struct venc_enc_param *enc_param)
+{
+       const bool is_ext = MTK_ENC_CTX_IS_EXT(vpu->ctx);
+       size_t msg_size = is_ext ?
+               sizeof(struct venc_ap_ipi_msg_set_param_ext) :
+               sizeof(struct venc_ap_ipi_msg_set_param);
+       struct venc_ap_ipi_msg_set_param_ext out;
+
+       mtk_vcodec_debug(vpu, "id %d ->", id);
+
+       memset(&out, 0, sizeof(out));
+       out.base.msg_id = AP_IPIMSG_ENC_SET_PARAM;
+       out.base.vpu_inst_addr = vpu->inst_addr;
+       out.base.param_id = id;
+       switch (id) {
+       case VENC_SET_PARAM_ENC:
+               if (is_ext) {
+                       out.base.data_item = 3;
+                       out.base.data[0] =
+                               venc_enc_param_crop_right(vpu, enc_param);
+                       out.base.data[1] =
+                               venc_enc_param_crop_bottom(enc_param);
+                       out.base.data[2] = venc_enc_param_num_mb(enc_param);
+               } else {
+                       out.base.data_item = 0;
+               }
+               break;
+       case VENC_SET_PARAM_FORCE_INTRA:
+               out.base.data_item = 0;
+               break;
+       case VENC_SET_PARAM_ADJUST_BITRATE:
+               out.base.data_item = 1;
+               out.base.data[0] = enc_param->bitrate;
+               break;
+       case VENC_SET_PARAM_ADJUST_FRAMERATE:
+               out.base.data_item = 1;
+               out.base.data[0] = enc_param->frm_rate;
+               break;
+       case VENC_SET_PARAM_GOP_SIZE:
+               out.base.data_item = 1;
+               out.base.data[0] = enc_param->gop_size;
+               break;
+       case VENC_SET_PARAM_INTRA_PERIOD:
+               out.base.data_item = 1;
+               out.base.data[0] = enc_param->intra_period;
+               break;
+       case VENC_SET_PARAM_SKIP_FRAME:
+               out.base.data_item = 0;
+               break;
+       default:
+               mtk_vcodec_err(vpu, "id %d not supported", id);
+               return -EINVAL;
+       }
+       if (vpu_enc_send_msg(vpu, &out, msg_size)) {
+               mtk_vcodec_err(vpu,
+                              "AP_IPIMSG_ENC_SET_PARAM %d fail", id);
+               return -EINVAL;
+       }
+
+       mtk_vcodec_debug(vpu, "id %d <-", id);
+
+       return 0;
+}
+
+int vpu_enc_encode(struct venc_vpu_inst *vpu, unsigned int bs_mode,
+                  struct venc_frm_buf *frm_buf,
+                  struct mtk_vcodec_mem *bs_buf,
+                  struct venc_frame_info *frame_info)
+{
+       const bool is_ext = MTK_ENC_CTX_IS_EXT(vpu->ctx);
+       size_t msg_size = is_ext ?
+               sizeof(struct venc_ap_ipi_msg_enc_ext) :
+               sizeof(struct venc_ap_ipi_msg_enc);
+       struct venc_ap_ipi_msg_enc_ext out;
+
+       mtk_vcodec_debug(vpu, "bs_mode %d ->", bs_mode);
+
+       memset(&out, 0, sizeof(out));
+       out.base.msg_id = AP_IPIMSG_ENC_ENCODE;
+       out.base.vpu_inst_addr = vpu->inst_addr;
+       out.base.bs_mode = bs_mode;
+       if (frm_buf) {
+               if ((frm_buf->fb_addr[0].dma_addr % 16 == 0) &&
+                   (frm_buf->fb_addr[1].dma_addr % 16 == 0) &&
+                   (frm_buf->fb_addr[2].dma_addr % 16 == 0)) {
+                       out.base.input_addr[0] = frm_buf->fb_addr[0].dma_addr;
+                       out.base.input_addr[1] = frm_buf->fb_addr[1].dma_addr;
+                       out.base.input_addr[2] = frm_buf->fb_addr[2].dma_addr;
+               } else {
+                       mtk_vcodec_err(vpu, "dma_addr not align to 16");
+                       return -EINVAL;
+               }
+       }
+       if (bs_buf) {
+               out.base.bs_addr = bs_buf->dma_addr;
+               out.base.bs_size = bs_buf->size;
+       }
+       if (is_ext && frame_info) {
+               out.data_item = 3;
+               out.data[0] = frame_info->frm_count;
+               out.data[1] = frame_info->skip_frm_count;
+               out.data[2] = frame_info->frm_type;
+       }
+       if (vpu_enc_send_msg(vpu, &out, msg_size)) {
+               mtk_vcodec_err(vpu, "AP_IPIMSG_ENC_ENCODE %d fail",
+                              bs_mode);
+               return -EINVAL;
+       }
+
+       mtk_vcodec_debug(vpu, "bs_mode %d state %d size %d key_frm %d <-",
+                        bs_mode, vpu->state, vpu->bs_size, vpu->is_key_frm);
+
+       return 0;
+}
+
+int vpu_enc_deinit(struct venc_vpu_inst *vpu)
+{
+       struct venc_ap_ipi_msg_deinit out;
+
+       mtk_vcodec_debug_enter(vpu);
+
+       memset(&out, 0, sizeof(out));
+       out.msg_id = AP_IPIMSG_ENC_DEINIT;
+       out.vpu_inst_addr = vpu->inst_addr;
+       if (vpu_enc_send_msg(vpu, &out, sizeof(out))) {
+               mtk_vcodec_err(vpu, "AP_IPIMSG_ENC_DEINIT fail");
+               return -EINVAL;
+       }
+
+       mtk_vcodec_debug_leave(vpu);
+
+       return 0;
+}
diff --git a/drivers/media/platform/mediatek/mtk-vcodec/venc_vpu_if.h b/drivers/media/platform/mediatek/mtk-vcodec/venc_vpu_if.h
new file mode 100644 (file)
index 0000000..f83bc1b
--- /dev/null
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: PoChun Lin <pochun.lin@mediatek.com>
+ */
+
+#ifndef _VENC_VPU_IF_H_
+#define _VENC_VPU_IF_H_
+
+#include "mtk_vcodec_fw.h"
+#include "venc_drv_if.h"
+
+/*
+ * struct venc_vpu_inst - encoder VPU driver instance
+ * @wq_hd: wait queue used for vpu cmd trigger then wait vpu interrupt done
+ * @signaled: flag used for checking vpu interrupt done
+ * @failure: flag to show vpu cmd succeeds or not
+ * @state: enum venc_ipi_msg_enc_state
+ * @bs_size: bitstream size for skip frame case usage
+ * @is_key_frm: key frame flag
+ * @inst_addr: VPU instance addr
+ * @vsi: driver structure allocated by VPU side and shared to AP side for
+ *      control and info share
+ * @id: the id of inter-processor interrupt
+ * @ctx: context for v4l2 layer integration
+ * @dev: device for v4l2 layer integration
+ */
+struct venc_vpu_inst {
+       wait_queue_head_t wq_hd;
+       int signaled;
+       int failure;
+       int state;
+       int bs_size;
+       int is_key_frm;
+       unsigned int inst_addr;
+       void *vsi;
+       int id;
+       struct mtk_vcodec_ctx *ctx;
+};
+
+int vpu_enc_init(struct venc_vpu_inst *vpu);
+int vpu_enc_set_param(struct venc_vpu_inst *vpu,
+                     enum venc_set_param_type id,
+                     struct venc_enc_param *param);
+int vpu_enc_encode(struct venc_vpu_inst *vpu, unsigned int bs_mode,
+                  struct venc_frm_buf *frm_buf,
+                  struct mtk_vcodec_mem *bs_buf,
+                  struct venc_frame_info *frame_info);
+int vpu_enc_deinit(struct venc_vpu_inst *vpu);
+
+#endif
diff --git a/drivers/media/platform/mtk-vcodec/Kconfig b/drivers/media/platform/mtk-vcodec/Kconfig
deleted file mode 100644 (file)
index 635801a..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-config VIDEO_MEDIATEK_VCODEC_SCP
-       bool
-
-config VIDEO_MEDIATEK_VCODEC_VPU
-       bool
-
-config VIDEO_MEDIATEK_VCODEC
-       tristate "Mediatek Video Codec driver"
-       depends on V4L_MEM2MEM_DRIVERS
-       depends on MTK_IOMMU || COMPILE_TEST
-       depends on VIDEO_DEV && VIDEO_V4L2
-       depends on ARCH_MEDIATEK || COMPILE_TEST
-       depends on VIDEO_MEDIATEK_VPU || MTK_SCP
-       # The two following lines ensure we have the same state ("m" or "y") as
-       # our dependencies, to avoid missing symbols during link.
-       depends on VIDEO_MEDIATEK_VPU || !VIDEO_MEDIATEK_VPU
-       depends on MTK_SCP || !MTK_SCP
-       depends on MTK_SMI || (COMPILE_TEST && MTK_SMI=n)
-       select VIDEOBUF2_DMA_CONTIG
-       select V4L2_MEM2MEM_DEV
-       select VIDEO_MEDIATEK_VCODEC_VPU if VIDEO_MEDIATEK_VPU
-       select VIDEO_MEDIATEK_VCODEC_SCP if MTK_SCP
-       select V4L2_H264
-       select MEDIA_CONTROLLER
-       select MEDIA_CONTROLLER_REQUEST_API
-       help
-         Mediatek video codec driver provides HW capability to
-         encode and decode in a range of video formats on MT8173
-         and MT8183.
-
-         Note that support for MT8173 requires VIDEO_MEDIATEK_VPU to
-         also be selected. Support for MT8183 depends on MTK_SCP.
-
-         To compile this driver as modules, choose M here: the
-         modules will be called mtk-vcodec-dec and mtk-vcodec-enc.
diff --git a/drivers/media/platform/mtk-vcodec/Makefile b/drivers/media/platform/mtk-vcodec/Makefile
deleted file mode 100644 (file)
index 3596196..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-
-obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC) += mtk-vcodec-dec.o \
-                                      mtk-vcodec-enc.o \
-                                      mtk-vcodec-common.o \
-                                      mtk-vcodec-dec-hw.o
-
-mtk-vcodec-dec-y := vdec/vdec_h264_if.o \
-               vdec/vdec_vp8_if.o \
-               vdec/vdec_vp9_if.o \
-               vdec/vdec_h264_req_if.o \
-               mtk_vcodec_dec_drv.o \
-               vdec_drv_if.o \
-               vdec_vpu_if.o \
-               vdec_msg_queue.o \
-               mtk_vcodec_dec.o \
-               mtk_vcodec_dec_stateful.o \
-               mtk_vcodec_dec_stateless.o \
-               mtk_vcodec_dec_pm.o \
-
-mtk-vcodec-dec-hw-y := mtk_vcodec_dec_hw.o
-
-mtk-vcodec-enc-y := venc/venc_vp8_if.o \
-               venc/venc_h264_if.o \
-               mtk_vcodec_enc.o \
-               mtk_vcodec_enc_drv.o \
-               mtk_vcodec_enc_pm.o \
-               venc_drv_if.o \
-               venc_vpu_if.o \
-
-
-mtk-vcodec-common-y := mtk_vcodec_intr.o \
-               mtk_vcodec_util.o \
-               mtk_vcodec_fw.o \
-
-ifneq ($(CONFIG_VIDEO_MEDIATEK_VCODEC_VPU),)
-mtk-vcodec-common-y += mtk_vcodec_fw_vpu.o
-endif
-
-ifneq ($(CONFIG_VIDEO_MEDIATEK_VCODEC_SCP),)
-mtk-vcodec-common-y += mtk_vcodec_fw_scp.o
-endif
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c
deleted file mode 100644 (file)
index 130ecef..0000000
+++ /dev/null
@@ -1,961 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2016 MediaTek Inc.
- * Author: PC Chen <pc.chen@mediatek.com>
- *         Tiffany Lin <tiffany.lin@mediatek.com>
- */
-
-#include <media/v4l2-event.h>
-#include <media/v4l2-mem2mem.h>
-#include <media/videobuf2-dma-contig.h>
-
-#include "mtk_vcodec_drv.h"
-#include "mtk_vcodec_dec.h"
-#include "mtk_vcodec_intr.h"
-#include "mtk_vcodec_util.h"
-#include "vdec_drv_if.h"
-#include "mtk_vcodec_dec_pm.h"
-
-#define DFT_CFG_WIDTH  MTK_VDEC_MIN_W
-#define DFT_CFG_HEIGHT MTK_VDEC_MIN_H
-
-static const struct mtk_video_fmt *
-mtk_vdec_find_format(struct v4l2_format *f,
-                    const struct mtk_vcodec_dec_pdata *dec_pdata)
-{
-       const struct mtk_video_fmt *fmt;
-       unsigned int k;
-
-       for (k = 0; k < dec_pdata->num_formats; k++) {
-               fmt = &dec_pdata->vdec_formats[k];
-               if (fmt->fourcc == f->fmt.pix_mp.pixelformat)
-                       return fmt;
-       }
-
-       return NULL;
-}
-
-static struct mtk_q_data *mtk_vdec_get_q_data(struct mtk_vcodec_ctx *ctx,
-                                             enum v4l2_buf_type type)
-{
-       if (V4L2_TYPE_IS_OUTPUT(type))
-               return &ctx->q_data[MTK_Q_DATA_SRC];
-
-       return &ctx->q_data[MTK_Q_DATA_DST];
-}
-
-static int vidioc_try_decoder_cmd(struct file *file, void *priv,
-                               struct v4l2_decoder_cmd *cmd)
-{
-       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
-
-       /* Use M2M stateless helper if relevant */
-       if (ctx->dev->vdec_pdata->uses_stateless_api)
-               return v4l2_m2m_ioctl_stateless_try_decoder_cmd(file, priv,
-                                                               cmd);
-       else
-               return v4l2_m2m_ioctl_try_decoder_cmd(file, priv, cmd);
-}
-
-
-static int vidioc_decoder_cmd(struct file *file, void *priv,
-                               struct v4l2_decoder_cmd *cmd)
-{
-       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
-       struct vb2_queue *src_vq, *dst_vq;
-       int ret;
-
-       ret = vidioc_try_decoder_cmd(file, priv, cmd);
-       if (ret)
-               return ret;
-
-       /* Use M2M stateless helper if relevant */
-       if (ctx->dev->vdec_pdata->uses_stateless_api)
-               return v4l2_m2m_ioctl_stateless_decoder_cmd(file, priv, cmd);
-
-       mtk_v4l2_debug(1, "decoder cmd=%u", cmd->cmd);
-       dst_vq = v4l2_m2m_get_vq(ctx->m2m_ctx,
-                               V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
-       switch (cmd->cmd) {
-       case V4L2_DEC_CMD_STOP:
-               src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx,
-                               V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
-               if (!vb2_is_streaming(src_vq)) {
-                       mtk_v4l2_debug(1, "Output stream is off. No need to flush.");
-                       return 0;
-               }
-               if (!vb2_is_streaming(dst_vq)) {
-                       mtk_v4l2_debug(1, "Capture stream is off. No need to flush.");
-                       return 0;
-               }
-               v4l2_m2m_buf_queue(ctx->m2m_ctx, &ctx->empty_flush_buf.vb);
-               v4l2_m2m_try_schedule(ctx->m2m_ctx);
-               break;
-
-       case V4L2_DEC_CMD_START:
-               vb2_clear_last_buffer_dequeued(dst_vq);
-               break;
-
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-void mtk_vdec_unlock(struct mtk_vcodec_ctx *ctx)
-{
-       mutex_unlock(&ctx->dev->dec_mutex[ctx->hw_id]);
-}
-
-void mtk_vdec_lock(struct mtk_vcodec_ctx *ctx)
-{
-       mutex_lock(&ctx->dev->dec_mutex[ctx->hw_id]);
-}
-
-void mtk_vcodec_dec_release(struct mtk_vcodec_ctx *ctx)
-{
-       vdec_if_deinit(ctx);
-       ctx->state = MTK_STATE_FREE;
-}
-
-void mtk_vcodec_dec_set_default_params(struct mtk_vcodec_ctx *ctx)
-{
-       struct mtk_q_data *q_data;
-
-       ctx->dev->vdec_pdata->init_vdec_params(ctx);
-
-       ctx->m2m_ctx->q_lock = &ctx->dev->dev_mutex;
-       ctx->fh.m2m_ctx = ctx->m2m_ctx;
-       ctx->fh.ctrl_handler = &ctx->ctrl_hdl;
-       INIT_WORK(&ctx->decode_work, ctx->dev->vdec_pdata->worker);
-       ctx->colorspace = V4L2_COLORSPACE_REC709;
-       ctx->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
-       ctx->quantization = V4L2_QUANTIZATION_DEFAULT;
-       ctx->xfer_func = V4L2_XFER_FUNC_DEFAULT;
-
-       q_data = &ctx->q_data[MTK_Q_DATA_SRC];
-       memset(q_data, 0, sizeof(struct mtk_q_data));
-       q_data->visible_width = DFT_CFG_WIDTH;
-       q_data->visible_height = DFT_CFG_HEIGHT;
-       q_data->fmt = ctx->dev->vdec_pdata->default_out_fmt;
-       q_data->field = V4L2_FIELD_NONE;
-
-       q_data->sizeimage[0] = DFT_CFG_WIDTH * DFT_CFG_HEIGHT;
-       q_data->bytesperline[0] = 0;
-
-       q_data = &ctx->q_data[MTK_Q_DATA_DST];
-       memset(q_data, 0, sizeof(struct mtk_q_data));
-       q_data->visible_width = DFT_CFG_WIDTH;
-       q_data->visible_height = DFT_CFG_HEIGHT;
-       q_data->coded_width = DFT_CFG_WIDTH;
-       q_data->coded_height = DFT_CFG_HEIGHT;
-       q_data->fmt = ctx->dev->vdec_pdata->default_cap_fmt;
-       q_data->field = V4L2_FIELD_NONE;
-
-       v4l_bound_align_image(&q_data->coded_width,
-                               MTK_VDEC_MIN_W,
-                               MTK_VDEC_MAX_W, 4,
-                               &q_data->coded_height,
-                               MTK_VDEC_MIN_H,
-                               MTK_VDEC_MAX_H, 5, 6);
-
-       q_data->sizeimage[0] = q_data->coded_width * q_data->coded_height;
-       q_data->bytesperline[0] = q_data->coded_width;
-       q_data->sizeimage[1] = q_data->sizeimage[0] / 2;
-       q_data->bytesperline[1] = q_data->coded_width;
-}
-
-static int vidioc_vdec_qbuf(struct file *file, void *priv,
-                           struct v4l2_buffer *buf)
-{
-       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
-
-       if (ctx->state == MTK_STATE_ABORT) {
-               mtk_v4l2_err("[%d] Call on QBUF after unrecoverable error",
-                               ctx->id);
-               return -EIO;
-       }
-
-       return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
-}
-
-static int vidioc_vdec_dqbuf(struct file *file, void *priv,
-                            struct v4l2_buffer *buf)
-{
-       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
-
-       if (ctx->state == MTK_STATE_ABORT) {
-               mtk_v4l2_err("[%d] Call on DQBUF after unrecoverable error",
-                               ctx->id);
-               return -EIO;
-       }
-
-       return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
-}
-
-static int vidioc_vdec_querycap(struct file *file, void *priv,
-                               struct v4l2_capability *cap)
-{
-       strscpy(cap->driver, MTK_VCODEC_DEC_NAME, sizeof(cap->driver));
-       strscpy(cap->bus_info, MTK_PLATFORM_STR, sizeof(cap->bus_info));
-       strscpy(cap->card, MTK_PLATFORM_STR, sizeof(cap->card));
-
-       return 0;
-}
-
-static int vidioc_vdec_subscribe_evt(struct v4l2_fh *fh,
-                                    const struct v4l2_event_subscription *sub)
-{
-       switch (sub->type) {
-       case V4L2_EVENT_EOS:
-               return v4l2_event_subscribe(fh, sub, 2, NULL);
-       case V4L2_EVENT_SOURCE_CHANGE:
-               return v4l2_src_change_event_subscribe(fh, sub);
-       default:
-               return v4l2_ctrl_subscribe_event(fh, sub);
-       }
-}
-
-static int vidioc_try_fmt(struct v4l2_format *f,
-                         const struct mtk_video_fmt *fmt)
-{
-       struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
-
-       pix_fmt_mp->field = V4L2_FIELD_NONE;
-
-       pix_fmt_mp->width =
-               clamp(pix_fmt_mp->width, MTK_VDEC_MIN_W, MTK_VDEC_MAX_W);
-       pix_fmt_mp->height =
-               clamp(pix_fmt_mp->height, MTK_VDEC_MIN_H, MTK_VDEC_MAX_H);
-
-       if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-               pix_fmt_mp->num_planes = 1;
-               pix_fmt_mp->plane_fmt[0].bytesperline = 0;
-       } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
-               int tmp_w, tmp_h;
-
-               /*
-                * Find next closer width align 64, heign align 64, size align
-                * 64 rectangle
-                * Note: This only get default value, the real HW needed value
-                *       only available when ctx in MTK_STATE_HEADER state
-                */
-               tmp_w = pix_fmt_mp->width;
-               tmp_h = pix_fmt_mp->height;
-               v4l_bound_align_image(&pix_fmt_mp->width,
-                                       MTK_VDEC_MIN_W,
-                                       MTK_VDEC_MAX_W, 6,
-                                       &pix_fmt_mp->height,
-                                       MTK_VDEC_MIN_H,
-                                       MTK_VDEC_MAX_H, 6, 9);
-
-               if (pix_fmt_mp->width < tmp_w &&
-                       (pix_fmt_mp->width + 64) <= MTK_VDEC_MAX_W)
-                       pix_fmt_mp->width += 64;
-               if (pix_fmt_mp->height < tmp_h &&
-                       (pix_fmt_mp->height + 64) <= MTK_VDEC_MAX_H)
-                       pix_fmt_mp->height += 64;
-
-               mtk_v4l2_debug(0,
-                       "before resize width=%d, height=%d, after resize width=%d, height=%d, sizeimage=%d",
-                       tmp_w, tmp_h, pix_fmt_mp->width,
-                       pix_fmt_mp->height,
-                       pix_fmt_mp->width * pix_fmt_mp->height);
-
-               pix_fmt_mp->num_planes = fmt->num_planes;
-               pix_fmt_mp->plane_fmt[0].sizeimage =
-                               pix_fmt_mp->width * pix_fmt_mp->height;
-               pix_fmt_mp->plane_fmt[0].bytesperline = pix_fmt_mp->width;
-
-               if (pix_fmt_mp->num_planes == 2) {
-                       pix_fmt_mp->plane_fmt[1].sizeimage =
-                               (pix_fmt_mp->width * pix_fmt_mp->height) / 2;
-                       pix_fmt_mp->plane_fmt[1].bytesperline =
-                               pix_fmt_mp->width;
-               }
-       }
-
-       pix_fmt_mp->flags = 0;
-       return 0;
-}
-
-static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv,
-                               struct v4l2_format *f)
-{
-       const struct mtk_video_fmt *fmt;
-       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
-       const struct mtk_vcodec_dec_pdata *dec_pdata = ctx->dev->vdec_pdata;
-
-       fmt = mtk_vdec_find_format(f, dec_pdata);
-       if (!fmt) {
-               f->fmt.pix.pixelformat =
-                       ctx->q_data[MTK_Q_DATA_DST].fmt->fourcc;
-               fmt = mtk_vdec_find_format(f, dec_pdata);
-       }
-
-       return vidioc_try_fmt(f, fmt);
-}
-
-static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv,
-                               struct v4l2_format *f)
-{
-       struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
-       const struct mtk_video_fmt *fmt;
-       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
-       const struct mtk_vcodec_dec_pdata *dec_pdata = ctx->dev->vdec_pdata;
-
-       fmt = mtk_vdec_find_format(f, dec_pdata);
-       if (!fmt) {
-               f->fmt.pix.pixelformat =
-                       ctx->q_data[MTK_Q_DATA_SRC].fmt->fourcc;
-               fmt = mtk_vdec_find_format(f, dec_pdata);
-       }
-
-       if (pix_fmt_mp->plane_fmt[0].sizeimage == 0) {
-               mtk_v4l2_err("sizeimage of output format must be given");
-               return -EINVAL;
-       }
-
-       return vidioc_try_fmt(f, fmt);
-}
-
-static int vidioc_vdec_g_selection(struct file *file, void *priv,
-                       struct v4l2_selection *s)
-{
-       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
-       struct mtk_q_data *q_data;
-
-       if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       q_data = &ctx->q_data[MTK_Q_DATA_DST];
-
-       switch (s->target) {
-       case V4L2_SEL_TGT_COMPOSE_DEFAULT:
-               s->r.left = 0;
-               s->r.top = 0;
-               s->r.width = ctx->picinfo.pic_w;
-               s->r.height = ctx->picinfo.pic_h;
-               break;
-       case V4L2_SEL_TGT_COMPOSE_BOUNDS:
-               s->r.left = 0;
-               s->r.top = 0;
-               s->r.width = ctx->picinfo.buf_w;
-               s->r.height = ctx->picinfo.buf_h;
-               break;
-       case V4L2_SEL_TGT_COMPOSE:
-               if (vdec_if_get_param(ctx, GET_PARAM_CROP_INFO, &(s->r))) {
-                       /* set to default value if header info not ready yet*/
-                       s->r.left = 0;
-                       s->r.top = 0;
-                       s->r.width = q_data->visible_width;
-                       s->r.height = q_data->visible_height;
-               }
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       if (ctx->state < MTK_STATE_HEADER) {
-               /* set to default value if header info not ready yet*/
-               s->r.left = 0;
-               s->r.top = 0;
-               s->r.width = q_data->visible_width;
-               s->r.height = q_data->visible_height;
-               return 0;
-       }
-
-       return 0;
-}
-
-static int vidioc_vdec_s_selection(struct file *file, void *priv,
-                               struct v4l2_selection *s)
-{
-       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
-
-       if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       switch (s->target) {
-       case V4L2_SEL_TGT_COMPOSE:
-               s->r.left = 0;
-               s->r.top = 0;
-               s->r.width = ctx->picinfo.pic_w;
-               s->r.height = ctx->picinfo.pic_h;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int vidioc_vdec_s_fmt(struct file *file, void *priv,
-                            struct v4l2_format *f)
-{
-       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
-       struct v4l2_pix_format_mplane *pix_mp;
-       struct mtk_q_data *q_data;
-       int ret = 0;
-       const struct mtk_video_fmt *fmt;
-       const struct mtk_vcodec_dec_pdata *dec_pdata = ctx->dev->vdec_pdata;
-
-       mtk_v4l2_debug(3, "[%d]", ctx->id);
-
-       q_data = mtk_vdec_get_q_data(ctx, f->type);
-       if (!q_data)
-               return -EINVAL;
-
-       pix_mp = &f->fmt.pix_mp;
-       /*
-        * Setting OUTPUT format after OUTPUT buffers are allocated is invalid
-        * if using the stateful API.
-        */
-       if (!dec_pdata->uses_stateless_api &&
-           f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
-           vb2_is_busy(&ctx->m2m_ctx->out_q_ctx.q)) {
-               mtk_v4l2_err("out_q_ctx buffers already requested");
-               ret = -EBUSY;
-       }
-
-       /*
-        * Setting CAPTURE format after CAPTURE buffers are allocated is
-        * invalid.
-        */
-       if ((f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) &&
-           vb2_is_busy(&ctx->m2m_ctx->cap_q_ctx.q)) {
-               mtk_v4l2_err("cap_q_ctx buffers already requested");
-               ret = -EBUSY;
-       }
-
-       fmt = mtk_vdec_find_format(f, dec_pdata);
-       if (fmt == NULL) {
-               if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-                       f->fmt.pix.pixelformat =
-                               dec_pdata->default_out_fmt->fourcc;
-                       fmt = mtk_vdec_find_format(f, dec_pdata);
-               } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
-                       f->fmt.pix.pixelformat =
-                               dec_pdata->default_cap_fmt->fourcc;
-                       fmt = mtk_vdec_find_format(f, dec_pdata);
-               }
-       }
-       if (fmt == NULL)
-               return -EINVAL;
-
-       q_data->fmt = fmt;
-       vidioc_try_fmt(f, q_data->fmt);
-       if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-               q_data->sizeimage[0] = pix_mp->plane_fmt[0].sizeimage;
-               q_data->coded_width = pix_mp->width;
-               q_data->coded_height = pix_mp->height;
-
-               ctx->colorspace = pix_mp->colorspace;
-               ctx->ycbcr_enc = pix_mp->ycbcr_enc;
-               ctx->quantization = pix_mp->quantization;
-               ctx->xfer_func = pix_mp->xfer_func;
-
-               ctx->current_codec = fmt->fourcc;
-               if (ctx->state == MTK_STATE_FREE) {
-                       ret = vdec_if_init(ctx, q_data->fmt->fourcc);
-                       if (ret) {
-                               mtk_v4l2_err("[%d]: vdec_if_init() fail ret=%d",
-                                       ctx->id, ret);
-                               return -EINVAL;
-                       }
-                       ctx->state = MTK_STATE_INIT;
-               }
-       }
-
-       /*
-        * If using the stateless API, S_FMT should have the effect of setting
-        * the CAPTURE queue resolution no matter which queue it was called on.
-        */
-       if (dec_pdata->uses_stateless_api) {
-               ctx->picinfo.pic_w = pix_mp->width;
-               ctx->picinfo.pic_h = pix_mp->height;
-
-               ret = vdec_if_get_param(ctx, GET_PARAM_PIC_INFO, &ctx->picinfo);
-               if (ret) {
-                       mtk_v4l2_err("[%d]Error!! Get GET_PARAM_PICTURE_INFO Fail",
-                                    ctx->id);
-                       return -EINVAL;
-               }
-
-               ctx->last_decoded_picinfo = ctx->picinfo;
-
-               if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 1) {
-                       ctx->q_data[MTK_Q_DATA_DST].sizeimage[0] =
-                               ctx->picinfo.fb_sz[0] +
-                               ctx->picinfo.fb_sz[1];
-                       ctx->q_data[MTK_Q_DATA_DST].bytesperline[0] =
-                               ctx->picinfo.buf_w;
-               } else {
-                       ctx->q_data[MTK_Q_DATA_DST].sizeimage[0] =
-                               ctx->picinfo.fb_sz[0];
-                       ctx->q_data[MTK_Q_DATA_DST].bytesperline[0] =
-                               ctx->picinfo.buf_w;
-                       ctx->q_data[MTK_Q_DATA_DST].sizeimage[1] =
-                               ctx->picinfo.fb_sz[1];
-                       ctx->q_data[MTK_Q_DATA_DST].bytesperline[1] =
-                               ctx->picinfo.buf_w;
-               }
-
-               ctx->q_data[MTK_Q_DATA_DST].coded_width = ctx->picinfo.buf_w;
-               ctx->q_data[MTK_Q_DATA_DST].coded_height = ctx->picinfo.buf_h;
-               mtk_v4l2_debug(2, "[%d] vdec_if_init() num_plane = %d wxh=%dx%d pic wxh=%dx%d sz[0]=0x%x sz[1]=0x%x",
-                              ctx->id, pix_mp->num_planes, ctx->picinfo.buf_w, ctx->picinfo.buf_h,
-                              ctx->picinfo.pic_w, ctx->picinfo.pic_h,
-                              ctx->q_data[MTK_Q_DATA_DST].sizeimage[0],
-                              ctx->q_data[MTK_Q_DATA_DST].sizeimage[1]);
-       }
-       return 0;
-}
-
-static int vidioc_enum_framesizes(struct file *file, void *priv,
-                               struct v4l2_frmsizeenum *fsize)
-{
-       int i = 0;
-       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
-       const struct mtk_vcodec_dec_pdata *dec_pdata = ctx->dev->vdec_pdata;
-
-       if (fsize->index != 0)
-               return -EINVAL;
-
-       for (i = 0; i < dec_pdata->num_framesizes; ++i) {
-               if (fsize->pixel_format != dec_pdata->vdec_framesizes[i].fourcc)
-                       continue;
-
-               fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
-               fsize->stepwise = dec_pdata->vdec_framesizes[i].stepwise;
-               if (!(ctx->dev->dec_capability &
-                               VCODEC_CAPABILITY_4K_DISABLED)) {
-                       mtk_v4l2_debug(3, "4K is enabled");
-                       fsize->stepwise.max_width =
-                                       VCODEC_DEC_4K_CODED_WIDTH;
-                       fsize->stepwise.max_height =
-                                       VCODEC_DEC_4K_CODED_HEIGHT;
-               }
-               mtk_v4l2_debug(1, "%x, %d %d %d %d %d %d",
-                               ctx->dev->dec_capability,
-                               fsize->stepwise.min_width,
-                               fsize->stepwise.max_width,
-                               fsize->stepwise.step_width,
-                               fsize->stepwise.min_height,
-                               fsize->stepwise.max_height,
-                               fsize->stepwise.step_height);
-               return 0;
-       }
-
-       return -EINVAL;
-}
-
-static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, void *priv,
-                          bool output_queue)
-{
-       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
-       const struct mtk_vcodec_dec_pdata *dec_pdata = ctx->dev->vdec_pdata;
-       const struct mtk_video_fmt *fmt;
-       int i, j = 0;
-
-       for (i = 0; i < dec_pdata->num_formats; i++) {
-               if (output_queue &&
-                   dec_pdata->vdec_formats[i].type != MTK_FMT_DEC)
-                       continue;
-               if (!output_queue &&
-                   dec_pdata->vdec_formats[i].type != MTK_FMT_FRAME)
-                       continue;
-
-               if (j == f->index)
-                       break;
-               ++j;
-       }
-
-       if (i == dec_pdata->num_formats)
-               return -EINVAL;
-
-       fmt = &dec_pdata->vdec_formats[i];
-       f->pixelformat = fmt->fourcc;
-       f->flags = fmt->flags;
-
-       return 0;
-}
-
-static int vidioc_vdec_enum_fmt_vid_cap(struct file *file, void *priv,
-                                       struct v4l2_fmtdesc *f)
-{
-       return vidioc_enum_fmt(f, priv, false);
-}
-
-static int vidioc_vdec_enum_fmt_vid_out(struct file *file, void *priv,
-                                       struct v4l2_fmtdesc *f)
-{
-       return vidioc_enum_fmt(f, priv, true);
-}
-
-static int vidioc_vdec_g_fmt(struct file *file, void *priv,
-                            struct v4l2_format *f)
-{
-       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
-       struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
-       struct vb2_queue *vq;
-       struct mtk_q_data *q_data;
-
-       vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
-       if (!vq) {
-               mtk_v4l2_err("no vb2 queue for type=%d", f->type);
-               return -EINVAL;
-       }
-
-       q_data = mtk_vdec_get_q_data(ctx, f->type);
-
-       pix_mp->field = V4L2_FIELD_NONE;
-       pix_mp->colorspace = ctx->colorspace;
-       pix_mp->ycbcr_enc = ctx->ycbcr_enc;
-       pix_mp->quantization = ctx->quantization;
-       pix_mp->xfer_func = ctx->xfer_func;
-
-       if ((f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) &&
-           (ctx->state >= MTK_STATE_HEADER)) {
-               /* Until STREAMOFF is called on the CAPTURE queue
-                * (acknowledging the event), the driver operates as if
-                * the resolution hasn't changed yet.
-                * So we just return picinfo yet, and update picinfo in
-                * stop_streaming hook function
-                */
-               q_data->sizeimage[0] = ctx->picinfo.fb_sz[0];
-               q_data->sizeimage[1] = ctx->picinfo.fb_sz[1];
-               q_data->bytesperline[0] = ctx->last_decoded_picinfo.buf_w;
-               q_data->bytesperline[1] = ctx->last_decoded_picinfo.buf_w;
-               q_data->coded_width = ctx->picinfo.buf_w;
-               q_data->coded_height = ctx->picinfo.buf_h;
-               ctx->last_decoded_picinfo.cap_fourcc = q_data->fmt->fourcc;
-
-               /*
-                * Width and height are set to the dimensions
-                * of the movie, the buffer is bigger and
-                * further processing stages should crop to this
-                * rectangle.
-                */
-               pix_mp->width = q_data->coded_width;
-               pix_mp->height = q_data->coded_height;
-
-               /*
-                * Set pixelformat to the format in which mt vcodec
-                * outputs the decoded frame
-                */
-               pix_mp->num_planes = q_data->fmt->num_planes;
-               pix_mp->pixelformat = q_data->fmt->fourcc;
-               pix_mp->plane_fmt[0].bytesperline = q_data->bytesperline[0];
-               pix_mp->plane_fmt[0].sizeimage = q_data->sizeimage[0];
-               pix_mp->plane_fmt[1].bytesperline = q_data->bytesperline[1];
-               pix_mp->plane_fmt[1].sizeimage = q_data->sizeimage[1];
-
-       } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-               /*
-                * This is run on OUTPUT
-                * The buffer contains compressed image
-                * so width and height have no meaning.
-                * Assign value here to pass v4l2-compliance test
-                */
-               pix_mp->width = q_data->visible_width;
-               pix_mp->height = q_data->visible_height;
-               pix_mp->plane_fmt[0].bytesperline = q_data->bytesperline[0];
-               pix_mp->plane_fmt[0].sizeimage = q_data->sizeimage[0];
-               pix_mp->pixelformat = q_data->fmt->fourcc;
-               pix_mp->num_planes = q_data->fmt->num_planes;
-       } else {
-               pix_mp->width = q_data->coded_width;
-               pix_mp->height = q_data->coded_height;
-               pix_mp->num_planes = q_data->fmt->num_planes;
-               pix_mp->pixelformat = q_data->fmt->fourcc;
-               pix_mp->plane_fmt[0].bytesperline = q_data->bytesperline[0];
-               pix_mp->plane_fmt[0].sizeimage = q_data->sizeimage[0];
-               pix_mp->plane_fmt[1].bytesperline = q_data->bytesperline[1];
-               pix_mp->plane_fmt[1].sizeimage = q_data->sizeimage[1];
-
-               mtk_v4l2_debug(1, "[%d] type=%d state=%d Format information could not be read, not ready yet!",
-                               ctx->id, f->type, ctx->state);
-       }
-
-       return 0;
-}
-
-int vb2ops_vdec_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
-                           unsigned int *nplanes, unsigned int sizes[],
-                           struct device *alloc_devs[])
-{
-       struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vq);
-       struct mtk_q_data *q_data;
-       unsigned int i;
-
-       q_data = mtk_vdec_get_q_data(ctx, vq->type);
-
-       if (q_data == NULL) {
-               mtk_v4l2_err("vq->type=%d err\n", vq->type);
-               return -EINVAL;
-       }
-
-       if (*nplanes) {
-               for (i = 0; i < *nplanes; i++) {
-                       if (sizes[i] < q_data->sizeimage[i])
-                               return -EINVAL;
-               }
-       } else {
-               if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
-                       *nplanes = q_data->fmt->num_planes;
-               else
-                       *nplanes = 1;
-
-               for (i = 0; i < *nplanes; i++)
-                       sizes[i] = q_data->sizeimage[i];
-       }
-
-       mtk_v4l2_debug(1,
-                       "[%d]\t type = %d, get %d plane(s), %d buffer(s) of size 0x%x 0x%x ",
-                       ctx->id, vq->type, *nplanes, *nbuffers,
-                       sizes[0], sizes[1]);
-
-       return 0;
-}
-
-int vb2ops_vdec_buf_prepare(struct vb2_buffer *vb)
-{
-       struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
-       struct mtk_q_data *q_data;
-       int i;
-
-       mtk_v4l2_debug(3, "[%d] (%d) id=%d",
-                       ctx->id, vb->vb2_queue->type, vb->index);
-
-       q_data = mtk_vdec_get_q_data(ctx, vb->vb2_queue->type);
-
-       for (i = 0; i < q_data->fmt->num_planes; i++) {
-               if (vb2_plane_size(vb, i) < q_data->sizeimage[i]) {
-                       mtk_v4l2_err("data will not fit into plane %d (%lu < %d)",
-                               i, vb2_plane_size(vb, i),
-                               q_data->sizeimage[i]);
-               }
-       }
-
-       return 0;
-}
-
-void vb2ops_vdec_buf_finish(struct vb2_buffer *vb)
-{
-       struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
-       struct vb2_v4l2_buffer *vb2_v4l2;
-       struct mtk_video_dec_buf *buf;
-       bool buf_error;
-
-       vb2_v4l2 = container_of(vb, struct vb2_v4l2_buffer, vb2_buf);
-       buf = container_of(vb2_v4l2, struct mtk_video_dec_buf, m2m_buf.vb);
-       mutex_lock(&ctx->lock);
-       if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
-               buf->queued_in_v4l2 = false;
-               buf->queued_in_vb2 = false;
-       }
-       buf_error = buf->error;
-       mutex_unlock(&ctx->lock);
-
-       if (buf_error) {
-               mtk_v4l2_err("Unrecoverable error on buffer.");
-               ctx->state = MTK_STATE_ABORT;
-       }
-}
-
-int vb2ops_vdec_buf_init(struct vb2_buffer *vb)
-{
-       struct vb2_v4l2_buffer *vb2_v4l2 = container_of(vb,
-                                       struct vb2_v4l2_buffer, vb2_buf);
-       struct mtk_video_dec_buf *buf = container_of(vb2_v4l2,
-                                       struct mtk_video_dec_buf, m2m_buf.vb);
-
-       if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
-               buf->used = false;
-               buf->queued_in_v4l2 = false;
-       }
-
-       return 0;
-}
-
-int vb2ops_vdec_start_streaming(struct vb2_queue *q, unsigned int count)
-{
-       struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(q);
-
-       if (ctx->state == MTK_STATE_FLUSH)
-               ctx->state = MTK_STATE_HEADER;
-
-       return 0;
-}
-
-void vb2ops_vdec_stop_streaming(struct vb2_queue *q)
-{
-       struct vb2_v4l2_buffer *src_buf = NULL, *dst_buf = NULL;
-       struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(q);
-       int ret;
-
-       mtk_v4l2_debug(3, "[%d] (%d) state=(%x) ctx->decoded_frame_cnt=%d",
-                       ctx->id, q->type, ctx->state, ctx->decoded_frame_cnt);
-
-       if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-               while ((src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx))) {
-                       if (src_buf != &ctx->empty_flush_buf.vb) {
-                               struct media_request *req =
-                                       src_buf->vb2_buf.req_obj.req;
-                               v4l2_m2m_buf_done(src_buf,
-                                               VB2_BUF_STATE_ERROR);
-                               if (req)
-                                       v4l2_ctrl_request_complete(req, &ctx->ctrl_hdl);
-                       }
-               }
-               return;
-       }
-
-       if (ctx->state >= MTK_STATE_HEADER) {
-
-               /* Until STREAMOFF is called on the CAPTURE queue
-                * (acknowledging the event), the driver operates
-                * as if the resolution hasn't changed yet, i.e.
-                * VIDIOC_G_FMT< etc. return previous resolution.
-                * So we update picinfo here
-                */
-               ctx->picinfo = ctx->last_decoded_picinfo;
-
-               mtk_v4l2_debug(2,
-                               "[%d]-> new(%d,%d), old(%d,%d), real(%d,%d)",
-                               ctx->id, ctx->last_decoded_picinfo.pic_w,
-                               ctx->last_decoded_picinfo.pic_h,
-                               ctx->picinfo.pic_w, ctx->picinfo.pic_h,
-                               ctx->last_decoded_picinfo.buf_w,
-                               ctx->last_decoded_picinfo.buf_h);
-
-               ret = ctx->dev->vdec_pdata->flush_decoder(ctx);
-               if (ret)
-                       mtk_v4l2_err("DecodeFinal failed, ret=%d", ret);
-       }
-       ctx->state = MTK_STATE_FLUSH;
-
-       while ((dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx))) {
-               vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0);
-               if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2)
-                       vb2_set_plane_payload(&dst_buf->vb2_buf, 1, 0);
-               v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);
-       }
-
-}
-
-static void m2mops_vdec_device_run(void *priv)
-{
-       struct mtk_vcodec_ctx *ctx = priv;
-       struct mtk_vcodec_dev *dev = ctx->dev;
-
-       queue_work(dev->decode_workqueue, &ctx->decode_work);
-}
-
-static int m2mops_vdec_job_ready(void *m2m_priv)
-{
-       struct mtk_vcodec_ctx *ctx = m2m_priv;
-
-       mtk_v4l2_debug(3, "[%d]", ctx->id);
-
-       if (ctx->state == MTK_STATE_ABORT)
-               return 0;
-
-       if ((ctx->last_decoded_picinfo.pic_w != ctx->picinfo.pic_w) ||
-           (ctx->last_decoded_picinfo.pic_h != ctx->picinfo.pic_h))
-               return 0;
-
-       if (ctx->state != MTK_STATE_HEADER)
-               return 0;
-
-       return 1;
-}
-
-static void m2mops_vdec_job_abort(void *priv)
-{
-       struct mtk_vcodec_ctx *ctx = priv;
-
-       ctx->state = MTK_STATE_ABORT;
-}
-
-const struct v4l2_m2m_ops mtk_vdec_m2m_ops = {
-       .device_run     = m2mops_vdec_device_run,
-       .job_ready      = m2mops_vdec_job_ready,
-       .job_abort      = m2mops_vdec_job_abort,
-};
-
-const struct v4l2_ioctl_ops mtk_vdec_ioctl_ops = {
-       .vidioc_streamon        = v4l2_m2m_ioctl_streamon,
-       .vidioc_streamoff       = v4l2_m2m_ioctl_streamoff,
-       .vidioc_reqbufs         = v4l2_m2m_ioctl_reqbufs,
-       .vidioc_querybuf        = v4l2_m2m_ioctl_querybuf,
-       .vidioc_expbuf          = v4l2_m2m_ioctl_expbuf,
-
-       .vidioc_qbuf            = vidioc_vdec_qbuf,
-       .vidioc_dqbuf           = vidioc_vdec_dqbuf,
-
-       .vidioc_try_fmt_vid_cap_mplane  = vidioc_try_fmt_vid_cap_mplane,
-       .vidioc_try_fmt_vid_out_mplane  = vidioc_try_fmt_vid_out_mplane,
-
-       .vidioc_s_fmt_vid_cap_mplane    = vidioc_vdec_s_fmt,
-       .vidioc_s_fmt_vid_out_mplane    = vidioc_vdec_s_fmt,
-       .vidioc_g_fmt_vid_cap_mplane    = vidioc_vdec_g_fmt,
-       .vidioc_g_fmt_vid_out_mplane    = vidioc_vdec_g_fmt,
-
-       .vidioc_create_bufs             = v4l2_m2m_ioctl_create_bufs,
-
-       .vidioc_enum_fmt_vid_cap        = vidioc_vdec_enum_fmt_vid_cap,
-       .vidioc_enum_fmt_vid_out        = vidioc_vdec_enum_fmt_vid_out,
-       .vidioc_enum_framesizes = vidioc_enum_framesizes,
-
-       .vidioc_querycap                = vidioc_vdec_querycap,
-       .vidioc_subscribe_event         = vidioc_vdec_subscribe_evt,
-       .vidioc_unsubscribe_event       = v4l2_event_unsubscribe,
-       .vidioc_g_selection             = vidioc_vdec_g_selection,
-       .vidioc_s_selection             = vidioc_vdec_s_selection,
-
-       .vidioc_decoder_cmd = vidioc_decoder_cmd,
-       .vidioc_try_decoder_cmd = vidioc_try_decoder_cmd,
-};
-
-int mtk_vcodec_dec_queue_init(void *priv, struct vb2_queue *src_vq,
-                          struct vb2_queue *dst_vq)
-{
-       struct mtk_vcodec_ctx *ctx = priv;
-       int ret = 0;
-
-       mtk_v4l2_debug(3, "[%d]", ctx->id);
-
-       src_vq->type            = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
-       src_vq->io_modes        = VB2_DMABUF | VB2_MMAP;
-       src_vq->drv_priv        = ctx;
-       src_vq->buf_struct_size = sizeof(struct mtk_video_dec_buf);
-       src_vq->ops             = ctx->dev->vdec_pdata->vdec_vb2_ops;
-       src_vq->mem_ops         = &vb2_dma_contig_memops;
-       src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
-       src_vq->lock            = &ctx->dev->dev_mutex;
-       src_vq->dev             = &ctx->dev->plat_dev->dev;
-
-       ret = vb2_queue_init(src_vq);
-       if (ret) {
-               mtk_v4l2_err("Failed to initialize videobuf2 queue(output)");
-               return ret;
-       }
-       dst_vq->type            = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
-       dst_vq->io_modes        = VB2_DMABUF | VB2_MMAP;
-       dst_vq->drv_priv        = ctx;
-       dst_vq->buf_struct_size = sizeof(struct mtk_video_dec_buf);
-       dst_vq->ops             = ctx->dev->vdec_pdata->vdec_vb2_ops;
-       dst_vq->mem_ops         = &vb2_dma_contig_memops;
-       dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
-       dst_vq->lock            = &ctx->dev->dev_mutex;
-       dst_vq->dev             = &ctx->dev->plat_dev->dev;
-
-       ret = vb2_queue_init(dst_vq);
-       if (ret)
-               mtk_v4l2_err("Failed to initialize videobuf2 queue(capture)");
-
-       return ret;
-}
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h
deleted file mode 100644 (file)
index 66cd6d2..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (c) 2016 MediaTek Inc.
- * Author: PC Chen <pc.chen@mediatek.com>
- *         Tiffany Lin <tiffany.lin@mediatek.com>
- */
-
-#ifndef _MTK_VCODEC_DEC_H_
-#define _MTK_VCODEC_DEC_H_
-
-#include <media/videobuf2-core.h>
-#include <media/v4l2-mem2mem.h>
-
-#define VCODEC_DEC_ALIGNED_64 64
-#define VCODEC_CAPABILITY_4K_DISABLED  0x10
-#define VCODEC_DEC_4K_CODED_WIDTH      4096U
-#define VCODEC_DEC_4K_CODED_HEIGHT     2304U
-#define MTK_VDEC_MAX_W 2048U
-#define MTK_VDEC_MAX_H 1088U
-#define MTK_VDEC_MIN_W 64U
-#define MTK_VDEC_MIN_H 64U
-
-#define MTK_VDEC_IRQ_STATUS_DEC_SUCCESS        0x10000
-
-/**
- * struct vdec_fb  - decoder frame buffer
- * @base_y     : Y plane memory info
- * @base_c     : C plane memory info
- * @status      : frame buffer status (vdec_fb_status)
- */
-struct vdec_fb {
-       struct mtk_vcodec_mem   base_y;
-       struct mtk_vcodec_mem   base_c;
-       unsigned int    status;
-};
-
-/**
- * struct mtk_video_dec_buf - Private data related to each VB2 buffer.
- * @m2m_buf:   M2M buffer
- * @list:      link list
- * @used:      Capture buffer contain decoded frame data and keep in
- *                     codec data structure
- * @queued_in_vb2:     Capture buffer is queue in vb2
- * @queued_in_v4l2:    Capture buffer is in v4l2 driver, but not in vb2
- *                     queue yet
- * @error:             An unrecoverable error occurs on this buffer.
- * @frame_buffer:      Decode status, and buffer information of Capture buffer
- * @bs_buffer: Output buffer info
- *
- * Note : These status information help us track and debug buffer state
- */
-struct mtk_video_dec_buf {
-       struct v4l2_m2m_buffer  m2m_buf;
-
-       bool    used;
-       bool    queued_in_vb2;
-       bool    queued_in_v4l2;
-       bool    error;
-
-       union {
-               struct vdec_fb  frame_buffer;
-               struct mtk_vcodec_mem   bs_buffer;
-       };
-};
-
-extern const struct v4l2_ioctl_ops mtk_vdec_ioctl_ops;
-extern const struct v4l2_m2m_ops mtk_vdec_m2m_ops;
-extern const struct media_device_ops mtk_vcodec_media_ops;
-extern const struct mtk_vcodec_dec_pdata mtk_vdec_8173_pdata;
-extern const struct mtk_vcodec_dec_pdata mtk_vdec_8183_pdata;
-extern const struct mtk_vcodec_dec_pdata mtk_lat_sig_core_pdata;
-
-
-/*
- * mtk_vdec_lock/mtk_vdec_unlock are for ctx instance to
- * get/release lock before/after access decoder hw.
- * mtk_vdec_lock get decoder hw lock and set curr_ctx
- * to ctx instance that get lock
- */
-void mtk_vdec_unlock(struct mtk_vcodec_ctx *ctx);
-void mtk_vdec_lock(struct mtk_vcodec_ctx *ctx);
-int mtk_vcodec_dec_queue_init(void *priv, struct vb2_queue *src_vq,
-                          struct vb2_queue *dst_vq);
-void mtk_vcodec_dec_set_default_params(struct mtk_vcodec_ctx *ctx);
-void mtk_vcodec_dec_release(struct mtk_vcodec_ctx *ctx);
-
-/*
- * VB2 ops
- */
-int vb2ops_vdec_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
-                           unsigned int *nplanes, unsigned int sizes[],
-                           struct device *alloc_devs[]);
-int vb2ops_vdec_buf_prepare(struct vb2_buffer *vb);
-void vb2ops_vdec_buf_finish(struct vb2_buffer *vb);
-int vb2ops_vdec_buf_init(struct vb2_buffer *vb);
-int vb2ops_vdec_start_streaming(struct vb2_queue *q, unsigned int count);
-void vb2ops_vdec_stop_streaming(struct vb2_queue *q);
-
-
-#endif /* _MTK_VCODEC_DEC_H_ */
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
deleted file mode 100644 (file)
index 48dad9b..0000000
+++ /dev/null
@@ -1,509 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2016 MediaTek Inc.
- * Author: PC Chen <pc.chen@mediatek.com>
- *         Tiffany Lin <tiffany.lin@mediatek.com>
- */
-
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/of.h>
-#include <linux/pm_runtime.h>
-#include <media/v4l2-event.h>
-#include <media/v4l2-mem2mem.h>
-#include <media/videobuf2-dma-contig.h>
-#include <media/v4l2-device.h>
-
-#include "mtk_vcodec_drv.h"
-#include "mtk_vcodec_dec.h"
-#include "mtk_vcodec_dec_hw.h"
-#include "mtk_vcodec_dec_pm.h"
-#include "mtk_vcodec_intr.h"
-#include "mtk_vcodec_util.h"
-#include "mtk_vcodec_fw.h"
-
-static int mtk_vcodec_get_hw_count(struct mtk_vcodec_dev *dev)
-{
-       switch (dev->vdec_pdata->hw_arch) {
-       case MTK_VDEC_PURE_SINGLE_CORE:
-               return MTK_VDEC_ONE_CORE;
-       case MTK_VDEC_LAT_SINGLE_CORE:
-               return MTK_VDEC_ONE_LAT_ONE_CORE;
-       default:
-               mtk_v4l2_err("hw arch %d not supported", dev->vdec_pdata->hw_arch);
-               return MTK_VDEC_NO_HW;
-       }
-}
-
-static irqreturn_t mtk_vcodec_dec_irq_handler(int irq, void *priv)
-{
-       struct mtk_vcodec_dev *dev = priv;
-       struct mtk_vcodec_ctx *ctx;
-       u32 cg_status = 0;
-       unsigned int dec_done_status = 0;
-       void __iomem *vdec_misc_addr = dev->reg_base[VDEC_MISC] +
-                                       VDEC_IRQ_CFG_REG;
-
-       ctx = mtk_vcodec_get_curr_ctx(dev, MTK_VDEC_CORE);
-
-       /* check if HW active or not */
-       cg_status = readl(dev->reg_base[0]);
-       if ((cg_status & VDEC_HW_ACTIVE) != 0) {
-               mtk_v4l2_err("DEC ISR, VDEC active is not 0x0 (0x%08x)",
-                            cg_status);
-               return IRQ_HANDLED;
-       }
-
-       dec_done_status = readl(vdec_misc_addr);
-       ctx->irq_status = dec_done_status;
-       if ((dec_done_status & MTK_VDEC_IRQ_STATUS_DEC_SUCCESS) !=
-               MTK_VDEC_IRQ_STATUS_DEC_SUCCESS)
-               return IRQ_HANDLED;
-
-       /* clear interrupt */
-       writel((readl(vdec_misc_addr) | VDEC_IRQ_CFG),
-               dev->reg_base[VDEC_MISC] + VDEC_IRQ_CFG_REG);
-       writel((readl(vdec_misc_addr) & ~VDEC_IRQ_CLR),
-               dev->reg_base[VDEC_MISC] + VDEC_IRQ_CFG_REG);
-
-       wake_up_ctx(ctx, MTK_INST_IRQ_RECEIVED, 0);
-
-       mtk_v4l2_debug(3,
-                       "mtk_vcodec_dec_irq_handler :wake up ctx %d, dec_done_status=%x",
-                       ctx->id, dec_done_status);
-
-       return IRQ_HANDLED;
-}
-
-static int mtk_vcodec_get_reg_bases(struct mtk_vcodec_dev *dev)
-{
-       struct platform_device *pdev = dev->plat_dev;
-       int reg_num, i;
-
-       /* Sizeof(u32) * 4 bytes for each register base. */
-       reg_num = of_property_count_elems_of_size(pdev->dev.of_node, "reg",
-                                                 sizeof(u32) * 4);
-       if (reg_num <= 0 || reg_num > NUM_MAX_VDEC_REG_BASE) {
-               dev_err(&pdev->dev, "Invalid register property size: %d\n", reg_num);
-               return -EINVAL;
-       }
-
-       for (i = 0; i < reg_num; i++) {
-               dev->reg_base[i] = devm_platform_ioremap_resource(pdev, i);
-               if (IS_ERR(dev->reg_base[i]))
-                       return PTR_ERR(dev->reg_base[i]);
-
-               mtk_v4l2_debug(2, "reg[%d] base=%p", i, dev->reg_base[i]);
-       }
-
-       return 0;
-}
-
-static int mtk_vcodec_init_dec_resources(struct mtk_vcodec_dev *dev)
-{
-       struct platform_device *pdev = dev->plat_dev;
-       int ret;
-
-       ret = mtk_vcodec_get_reg_bases(dev);
-       if (ret)
-               return ret;
-
-       if (dev->vdec_pdata->is_subdev_supported)
-               return 0;
-
-       dev->dec_irq = platform_get_irq(pdev, 0);
-       if (dev->dec_irq < 0) {
-               dev_err(&pdev->dev, "failed to get irq number");
-               return dev->dec_irq;
-       }
-
-       irq_set_status_flags(dev->dec_irq, IRQ_NOAUTOEN);
-       ret = devm_request_irq(&pdev->dev, dev->dec_irq,
-                              mtk_vcodec_dec_irq_handler, 0, pdev->name, dev);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to install dev->dec_irq %d (%d)",
-                       dev->dec_irq, ret);
-               return ret;
-       }
-
-       ret = mtk_vcodec_init_dec_clk(pdev, &dev->pm);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "failed to get mt vcodec clock source");
-               return ret;
-       }
-
-       pm_runtime_enable(&pdev->dev);
-       return 0;
-}
-
-static int fops_vcodec_open(struct file *file)
-{
-       struct mtk_vcodec_dev *dev = video_drvdata(file);
-       struct mtk_vcodec_ctx *ctx = NULL;
-       int ret = 0, i, hw_count;
-       struct vb2_queue *src_vq;
-
-       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
-       if (!ctx)
-               return -ENOMEM;
-
-       mutex_lock(&dev->dev_mutex);
-       ctx->id = dev->id_counter++;
-       v4l2_fh_init(&ctx->fh, video_devdata(file));
-       file->private_data = &ctx->fh;
-       v4l2_fh_add(&ctx->fh);
-       INIT_LIST_HEAD(&ctx->list);
-       ctx->dev = dev;
-       if (ctx->dev->vdec_pdata->is_subdev_supported) {
-               hw_count = mtk_vcodec_get_hw_count(dev);
-               if (!hw_count || !dev->subdev_prob_done) {
-                       ret = -EINVAL;
-                       goto err_ctrls_setup;
-               }
-
-               ret = dev->subdev_prob_done(dev);
-               if (ret)
-                       goto err_ctrls_setup;
-
-               for (i = 0; i < hw_count; i++)
-                       init_waitqueue_head(&ctx->queue[i]);
-       } else {
-               init_waitqueue_head(&ctx->queue[0]);
-       }
-       mutex_init(&ctx->lock);
-
-       ctx->type = MTK_INST_DECODER;
-       ret = dev->vdec_pdata->ctrls_setup(ctx);
-       if (ret) {
-               mtk_v4l2_err("Failed to setup mt vcodec controls");
-               goto err_ctrls_setup;
-       }
-       ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev_dec, ctx,
-               &mtk_vcodec_dec_queue_init);
-       if (IS_ERR((__force void *)ctx->m2m_ctx)) {
-               ret = PTR_ERR((__force void *)ctx->m2m_ctx);
-               mtk_v4l2_err("Failed to v4l2_m2m_ctx_init() (%d)",
-                       ret);
-               goto err_m2m_ctx_init;
-       }
-       src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx,
-                               V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
-       ctx->empty_flush_buf.vb.vb2_buf.vb2_queue = src_vq;
-       mtk_vcodec_dec_set_default_params(ctx);
-
-       if (v4l2_fh_is_singular(&ctx->fh)) {
-               ret = mtk_vcodec_dec_pw_on(dev, MTK_VDEC_LAT0);
-               if (ret < 0)
-                       goto err_load_fw;
-               /*
-                * Does nothing if firmware was already loaded.
-                */
-               ret = mtk_vcodec_fw_load_firmware(dev->fw_handler);
-               if (ret < 0) {
-                       /*
-                        * Return 0 if downloading firmware successfully,
-                        * otherwise it is failed
-                        */
-                       mtk_v4l2_err("failed to load firmware!");
-                       goto err_load_fw;
-               }
-
-               dev->dec_capability =
-                       mtk_vcodec_fw_get_vdec_capa(dev->fw_handler);
-               mtk_v4l2_debug(0, "decoder capability %x", dev->dec_capability);
-       }
-
-       list_add(&ctx->list, &dev->ctx_list);
-
-       mutex_unlock(&dev->dev_mutex);
-       mtk_v4l2_debug(0, "%s decoder [%d]", dev_name(&dev->plat_dev->dev),
-                       ctx->id);
-       return ret;
-
-       /* Deinit when failure occurred */
-err_load_fw:
-       v4l2_m2m_ctx_release(ctx->m2m_ctx);
-err_m2m_ctx_init:
-       v4l2_ctrl_handler_free(&ctx->ctrl_hdl);
-err_ctrls_setup:
-       v4l2_fh_del(&ctx->fh);
-       v4l2_fh_exit(&ctx->fh);
-       kfree(ctx);
-       mutex_unlock(&dev->dev_mutex);
-
-       return ret;
-}
-
-static int fops_vcodec_release(struct file *file)
-{
-       struct mtk_vcodec_dev *dev = video_drvdata(file);
-       struct mtk_vcodec_ctx *ctx = fh_to_ctx(file->private_data);
-
-       mtk_v4l2_debug(0, "[%d] decoder", ctx->id);
-       mutex_lock(&dev->dev_mutex);
-
-       /*
-        * Call v4l2_m2m_ctx_release before mtk_vcodec_dec_release. First, it
-        * makes sure the worker thread is not running after vdec_if_deinit.
-        * Second, the decoder will be flushed and all the buffers will be
-        * returned in stop_streaming.
-        */
-       v4l2_m2m_ctx_release(ctx->m2m_ctx);
-       mtk_vcodec_dec_release(ctx);
-
-       if (v4l2_fh_is_singular(&ctx->fh))
-               mtk_vcodec_dec_pw_off(dev, MTK_VDEC_LAT0);
-       v4l2_fh_del(&ctx->fh);
-       v4l2_fh_exit(&ctx->fh);
-       v4l2_ctrl_handler_free(&ctx->ctrl_hdl);
-
-       list_del_init(&ctx->list);
-       kfree(ctx);
-       mutex_unlock(&dev->dev_mutex);
-       return 0;
-}
-
-static const struct v4l2_file_operations mtk_vcodec_fops = {
-       .owner          = THIS_MODULE,
-       .open           = fops_vcodec_open,
-       .release        = fops_vcodec_release,
-       .poll           = v4l2_m2m_fop_poll,
-       .unlocked_ioctl = video_ioctl2,
-       .mmap           = v4l2_m2m_fop_mmap,
-};
-
-static int mtk_vcodec_probe(struct platform_device *pdev)
-{
-       struct mtk_vcodec_dev *dev;
-       struct video_device *vfd_dec;
-       phandle rproc_phandle;
-       enum mtk_vcodec_fw_type fw_type;
-       int i, ret;
-
-       dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
-       if (!dev)
-               return -ENOMEM;
-
-       INIT_LIST_HEAD(&dev->ctx_list);
-       dev->plat_dev = pdev;
-
-       dev->vdec_pdata = of_device_get_match_data(&pdev->dev);
-       if (!of_property_read_u32(pdev->dev.of_node, "mediatek,vpu",
-                                 &rproc_phandle)) {
-               fw_type = VPU;
-       } else if (!of_property_read_u32(pdev->dev.of_node, "mediatek,scp",
-                                        &rproc_phandle)) {
-               fw_type = SCP;
-       } else {
-               mtk_v4l2_err("Could not get vdec IPI device");
-               return -ENODEV;
-       }
-       dma_set_max_seg_size(&pdev->dev, UINT_MAX);
-
-       dev->fw_handler = mtk_vcodec_fw_select(dev, fw_type, DECODER);
-       if (IS_ERR(dev->fw_handler))
-               return PTR_ERR(dev->fw_handler);
-
-       ret = mtk_vcodec_init_dec_resources(dev);
-       if (ret) {
-               dev_err(&pdev->dev, "Failed to init dec resources");
-               goto err_dec_pm;
-       }
-
-       if (IS_VDEC_LAT_ARCH(dev->vdec_pdata->hw_arch)) {
-               vdec_msg_queue_init_ctx(&dev->msg_queue_core_ctx, MTK_VDEC_CORE);
-               dev->core_workqueue =
-                       alloc_ordered_workqueue("core-decoder",
-                                               WQ_MEM_RECLAIM | WQ_FREEZABLE);
-               if (!dev->core_workqueue) {
-                       mtk_v4l2_err("Failed to create core workqueue");
-                       ret = -EINVAL;
-                       goto err_res;
-               }
-       }
-
-       if (of_get_property(pdev->dev.of_node, "dma-ranges", NULL)) {
-               ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34));
-               if (ret) {
-                       mtk_v4l2_err("Failed to set mask");
-                       goto err_core_workq;
-               }
-       }
-
-       for (i = 0; i < MTK_VDEC_HW_MAX; i++)
-               mutex_init(&dev->dec_mutex[i]);
-       mutex_init(&dev->dev_mutex);
-       spin_lock_init(&dev->irqlock);
-
-       snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), "%s",
-               "[/MTK_V4L2_VDEC]");
-
-       ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
-       if (ret) {
-               mtk_v4l2_err("v4l2_device_register err=%d", ret);
-               goto err_core_workq;
-       }
-
-       init_waitqueue_head(&dev->queue);
-
-       vfd_dec = video_device_alloc();
-       if (!vfd_dec) {
-               mtk_v4l2_err("Failed to allocate video device");
-               ret = -ENOMEM;
-               goto err_dec_alloc;
-       }
-       vfd_dec->fops           = &mtk_vcodec_fops;
-       vfd_dec->ioctl_ops      = &mtk_vdec_ioctl_ops;
-       vfd_dec->release        = video_device_release;
-       vfd_dec->lock           = &dev->dev_mutex;
-       vfd_dec->v4l2_dev       = &dev->v4l2_dev;
-       vfd_dec->vfl_dir        = VFL_DIR_M2M;
-       vfd_dec->device_caps    = V4L2_CAP_VIDEO_M2M_MPLANE |
-                       V4L2_CAP_STREAMING;
-
-       snprintf(vfd_dec->name, sizeof(vfd_dec->name), "%s",
-               MTK_VCODEC_DEC_NAME);
-       video_set_drvdata(vfd_dec, dev);
-       dev->vfd_dec = vfd_dec;
-       platform_set_drvdata(pdev, dev);
-
-       dev->m2m_dev_dec = v4l2_m2m_init(&mtk_vdec_m2m_ops);
-       if (IS_ERR((__force void *)dev->m2m_dev_dec)) {
-               mtk_v4l2_err("Failed to init mem2mem dec device");
-               ret = PTR_ERR((__force void *)dev->m2m_dev_dec);
-               goto err_dec_alloc;
-       }
-
-       dev->decode_workqueue =
-               alloc_ordered_workqueue(MTK_VCODEC_DEC_NAME,
-                       WQ_MEM_RECLAIM | WQ_FREEZABLE);
-       if (!dev->decode_workqueue) {
-               mtk_v4l2_err("Failed to create decode workqueue");
-               ret = -EINVAL;
-               goto err_event_workq;
-       }
-
-       if (dev->vdec_pdata->is_subdev_supported) {
-               ret = of_platform_populate(pdev->dev.of_node, NULL, NULL,
-                                          &pdev->dev);
-               if (ret) {
-                       mtk_v4l2_err("Main device of_platform_populate failed.");
-                       goto err_reg_cont;
-               }
-       }
-
-       ret = video_register_device(vfd_dec, VFL_TYPE_VIDEO, -1);
-       if (ret) {
-               mtk_v4l2_err("Failed to register video device");
-               goto err_reg_cont;
-       }
-
-       if (dev->vdec_pdata->uses_stateless_api) {
-               dev->mdev_dec.dev = &pdev->dev;
-               strscpy(dev->mdev_dec.model, MTK_VCODEC_DEC_NAME,
-                       sizeof(dev->mdev_dec.model));
-
-               media_device_init(&dev->mdev_dec);
-               dev->mdev_dec.ops = &mtk_vcodec_media_ops;
-               dev->v4l2_dev.mdev = &dev->mdev_dec;
-
-               ret = v4l2_m2m_register_media_controller(dev->m2m_dev_dec, dev->vfd_dec,
-                                                        MEDIA_ENT_F_PROC_VIDEO_DECODER);
-               if (ret) {
-                       mtk_v4l2_err("Failed to register media controller");
-                       goto err_dec_mem_init;
-               }
-
-               ret = media_device_register(&dev->mdev_dec);
-               if (ret) {
-                       mtk_v4l2_err("Failed to register media device");
-                       goto err_media_reg;
-               }
-
-               mtk_v4l2_debug(0, "media registered as /dev/media%d", vfd_dec->minor);
-       }
-
-       mtk_v4l2_debug(0, "decoder registered as /dev/video%d", vfd_dec->minor);
-
-       return 0;
-
-err_media_reg:
-       v4l2_m2m_unregister_media_controller(dev->m2m_dev_dec);
-err_dec_mem_init:
-       video_unregister_device(vfd_dec);
-err_reg_cont:
-       if (dev->vdec_pdata->uses_stateless_api)
-               media_device_cleanup(&dev->mdev_dec);
-       destroy_workqueue(dev->decode_workqueue);
-err_event_workq:
-       v4l2_m2m_release(dev->m2m_dev_dec);
-err_dec_alloc:
-       v4l2_device_unregister(&dev->v4l2_dev);
-err_core_workq:
-       if (IS_VDEC_LAT_ARCH(dev->vdec_pdata->hw_arch))
-               destroy_workqueue(dev->core_workqueue);
-err_res:
-       pm_runtime_disable(dev->pm.dev);
-err_dec_pm:
-       mtk_vcodec_fw_release(dev->fw_handler);
-       return ret;
-}
-
-static const struct of_device_id mtk_vcodec_match[] = {
-       {
-               .compatible = "mediatek,mt8173-vcodec-dec",
-               .data = &mtk_vdec_8173_pdata,
-       },
-       {
-               .compatible = "mediatek,mt8183-vcodec-dec",
-               .data = &mtk_vdec_8183_pdata,
-       },
-       {
-               .compatible = "mediatek,mt8192-vcodec-dec",
-               .data = &mtk_lat_sig_core_pdata,
-       },
-       {},
-};
-
-MODULE_DEVICE_TABLE(of, mtk_vcodec_match);
-
-static int mtk_vcodec_dec_remove(struct platform_device *pdev)
-{
-       struct mtk_vcodec_dev *dev = platform_get_drvdata(pdev);
-
-       destroy_workqueue(dev->decode_workqueue);
-
-       if (media_devnode_is_registered(dev->mdev_dec.devnode)) {
-               media_device_unregister(&dev->mdev_dec);
-               v4l2_m2m_unregister_media_controller(dev->m2m_dev_dec);
-               media_device_cleanup(&dev->mdev_dec);
-       }
-
-       if (dev->m2m_dev_dec)
-               v4l2_m2m_release(dev->m2m_dev_dec);
-
-       if (dev->vfd_dec)
-               video_unregister_device(dev->vfd_dec);
-
-       v4l2_device_unregister(&dev->v4l2_dev);
-       pm_runtime_disable(dev->pm.dev);
-       mtk_vcodec_fw_release(dev->fw_handler);
-       return 0;
-}
-
-static struct platform_driver mtk_vcodec_dec_driver = {
-       .probe  = mtk_vcodec_probe,
-       .remove = mtk_vcodec_dec_remove,
-       .driver = {
-               .name   = MTK_VCODEC_DEC_NAME,
-               .of_match_table = mtk_vcodec_match,
-       },
-};
-
-module_platform_driver(mtk_vcodec_dec_driver);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Mediatek video codec V4L2 decoder driver");
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_hw.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_hw.c
deleted file mode 100644 (file)
index 8d2a641..0000000
+++ /dev/null
@@ -1,200 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2021 MediaTek Inc.
- * Author: Yunfei Dong <yunfei.dong@mediatek.com>
- */
-
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/pm_runtime.h>
-#include <linux/slab.h>
-
-#include "mtk_vcodec_drv.h"
-#include "mtk_vcodec_dec.h"
-#include "mtk_vcodec_dec_hw.h"
-#include "mtk_vcodec_dec_pm.h"
-#include "mtk_vcodec_intr.h"
-#include "mtk_vcodec_util.h"
-
-static const struct of_device_id mtk_vdec_hw_match[] = {
-       {
-               .compatible = "mediatek,mtk-vcodec-lat",
-               .data = (void *)MTK_VDEC_LAT0,
-       },
-       {
-               .compatible = "mediatek,mtk-vcodec-core",
-               .data = (void *)MTK_VDEC_CORE,
-       },
-       {},
-};
-MODULE_DEVICE_TABLE(of, mtk_vdec_hw_match);
-
-static int mtk_vdec_hw_prob_done(struct mtk_vcodec_dev *vdec_dev)
-{
-       struct platform_device *pdev = vdec_dev->plat_dev;
-       struct device_node *subdev_node;
-       enum mtk_vdec_hw_id hw_idx;
-       const struct of_device_id *of_id;
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(mtk_vdec_hw_match); i++) {
-               of_id = &mtk_vdec_hw_match[i];
-               subdev_node = of_find_compatible_node(NULL, NULL,
-                                                     of_id->compatible);
-               if (!subdev_node)
-                       continue;
-
-               hw_idx = (enum mtk_vdec_hw_id)(uintptr_t)of_id->data;
-               if (!test_bit(hw_idx, vdec_dev->subdev_bitmap)) {
-                       dev_err(&pdev->dev, "vdec %d is not ready", hw_idx);
-                       return -EAGAIN;
-               }
-       }
-
-       return 0;
-}
-
-static irqreturn_t mtk_vdec_hw_irq_handler(int irq, void *priv)
-{
-       struct mtk_vdec_hw_dev *dev = priv;
-       struct mtk_vcodec_ctx *ctx;
-       u32 cg_status;
-       unsigned int dec_done_status;
-       void __iomem *vdec_misc_addr = dev->reg_base[VDEC_HW_MISC] +
-                                       VDEC_IRQ_CFG_REG;
-
-       ctx = mtk_vcodec_get_curr_ctx(dev->main_dev, dev->hw_idx);
-
-       /* check if HW active or not */
-       cg_status = readl(dev->reg_base[VDEC_HW_SYS]);
-       if (cg_status & VDEC_HW_ACTIVE) {
-               mtk_v4l2_err("vdec active is not 0x0 (0x%08x)",
-                            cg_status);
-               return IRQ_HANDLED;
-       }
-
-       dec_done_status = readl(vdec_misc_addr);
-       if ((dec_done_status & MTK_VDEC_IRQ_STATUS_DEC_SUCCESS) !=
-           MTK_VDEC_IRQ_STATUS_DEC_SUCCESS)
-               return IRQ_HANDLED;
-
-       /* clear interrupt */
-       writel(dec_done_status | VDEC_IRQ_CFG, vdec_misc_addr);
-       writel(dec_done_status & ~VDEC_IRQ_CLR, vdec_misc_addr);
-
-       wake_up_ctx(ctx, MTK_INST_IRQ_RECEIVED, dev->hw_idx);
-
-       mtk_v4l2_debug(3, "wake up ctx %d, dec_done_status=%x",
-                      ctx->id, dec_done_status);
-
-       return IRQ_HANDLED;
-}
-
-static int mtk_vdec_hw_init_irq(struct mtk_vdec_hw_dev *dev)
-{
-       struct platform_device *pdev = dev->plat_dev;
-       int ret;
-
-       dev->dec_irq = platform_get_irq(pdev, 0);
-       if (dev->dec_irq < 0) {
-               dev_err(&pdev->dev, "Failed to get irq resource");
-               return dev->dec_irq;
-       }
-
-       irq_set_status_flags(dev->dec_irq, IRQ_NOAUTOEN);
-       ret = devm_request_irq(&pdev->dev, dev->dec_irq,
-                              mtk_vdec_hw_irq_handler, 0, pdev->name, dev);
-       if (ret) {
-               dev_err(&pdev->dev, "Failed to install dev->dec_irq %d (%d)",
-                       dev->dec_irq, ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-static int mtk_vdec_hw_probe(struct platform_device *pdev)
-{
-       struct device *dev = &pdev->dev;
-       struct mtk_vdec_hw_dev *subdev_dev;
-       struct mtk_vcodec_dev *main_dev;
-       const struct of_device_id *of_id;
-       int hw_idx;
-       int ret;
-
-       if (!dev->parent) {
-               dev_err(dev, "no parent for hardware devices.\n");
-               return -ENODEV;
-       }
-
-       main_dev = dev_get_drvdata(dev->parent);
-       if (!main_dev) {
-               dev_err(dev, "failed to get parent driver data");
-               return -EINVAL;
-       }
-
-       subdev_dev = devm_kzalloc(dev, sizeof(*subdev_dev), GFP_KERNEL);
-       if (!subdev_dev)
-               return -ENOMEM;
-
-       subdev_dev->plat_dev = pdev;
-       ret = mtk_vcodec_init_dec_clk(pdev, &subdev_dev->pm);
-       if (ret)
-               return ret;
-       pm_runtime_enable(&pdev->dev);
-
-       of_id = of_match_device(mtk_vdec_hw_match, dev);
-       if (!of_id) {
-               dev_err(dev, "Can't get vdec subdev id.\n");
-               ret = -EINVAL;
-               goto err;
-       }
-
-       hw_idx = (enum mtk_vdec_hw_id)(uintptr_t)of_id->data;
-       if (hw_idx >= MTK_VDEC_HW_MAX) {
-               dev_err(dev, "Hardware index %d not correct.\n", hw_idx);
-               ret = -EINVAL;
-               goto err;
-       }
-
-       main_dev->subdev_dev[hw_idx] = subdev_dev;
-       subdev_dev->hw_idx = hw_idx;
-       subdev_dev->main_dev = main_dev;
-       subdev_dev->reg_base[VDEC_HW_SYS] = main_dev->reg_base[VDEC_HW_SYS];
-       set_bit(subdev_dev->hw_idx, main_dev->subdev_bitmap);
-
-       ret = mtk_vdec_hw_init_irq(subdev_dev);
-       if (ret)
-               goto err;
-
-       subdev_dev->reg_base[VDEC_HW_MISC] =
-               devm_platform_ioremap_resource(pdev, 0);
-       if (IS_ERR((__force void *)subdev_dev->reg_base[VDEC_HW_MISC])) {
-               ret = PTR_ERR((__force void *)subdev_dev->reg_base[VDEC_HW_MISC]);
-               goto err;
-       }
-
-       if (!main_dev->subdev_prob_done)
-               main_dev->subdev_prob_done = mtk_vdec_hw_prob_done;
-
-       platform_set_drvdata(pdev, subdev_dev);
-       return 0;
-err:
-       pm_runtime_disable(subdev_dev->pm.dev);
-       return ret;
-}
-
-static struct platform_driver mtk_vdec_driver = {
-       .probe  = mtk_vdec_hw_probe,
-       .driver = {
-               .name   = "mtk-vdec-comp",
-               .of_match_table = mtk_vdec_hw_match,
-       },
-};
-module_platform_driver(mtk_vdec_driver);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Mediatek video decoder hardware driver");
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_hw.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_hw.h
deleted file mode 100644 (file)
index a63e4b1..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (c) 2021 MediaTek Inc.
- * Author: Yunfei Dong <yunfei.dong@mediatek.com>
- */
-
-#ifndef _MTK_VCODEC_DEC_HW_H_
-#define _MTK_VCODEC_DEC_HW_H_
-
-#include <linux/io.h>
-#include <linux/platform_device.h>
-
-#include "mtk_vcodec_drv.h"
-
-#define VDEC_HW_ACTIVE 0x10
-#define VDEC_IRQ_CFG 0x11
-#define VDEC_IRQ_CLR 0x10
-#define VDEC_IRQ_CFG_REG 0xa4
-
-/**
- * enum mtk_vdec_hw_reg_idx - subdev hardware register base index
- * @VDEC_HW_SYS : vdec soc register index
- * @VDEC_HW_MISC: vdec misc register index
- * @VDEC_HW_MAX : vdec supported max register index
- */
-enum mtk_vdec_hw_reg_idx {
-       VDEC_HW_SYS,
-       VDEC_HW_MISC,
-       VDEC_HW_MAX
-};
-
-/**
- * struct mtk_vdec_hw_dev - vdec hardware driver data
- * @plat_dev: platform device
- * @main_dev: main device
- * @reg_base: mapped address of MTK Vcodec registers.
- *
- * @curr_ctx: the context that is waiting for codec hardware
- *
- * @dec_irq : decoder irq resource
- * @pm      : power management control
- * @hw_idx  : each hardware index
- */
-struct mtk_vdec_hw_dev {
-       struct platform_device *plat_dev;
-       struct mtk_vcodec_dev *main_dev;
-       void __iomem *reg_base[VDEC_HW_MAX];
-
-       struct mtk_vcodec_ctx *curr_ctx;
-
-       int dec_irq;
-       struct mtk_vcodec_pm pm;
-       int hw_idx;
-};
-
-#endif /* _MTK_VCODEC_DEC_HW_H_ */
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c
deleted file mode 100644 (file)
index 7e0c264..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2016 MediaTek Inc.
- * Author: Tiffany Lin <tiffany.lin@mediatek.com>
- */
-
-#include <linux/clk.h>
-#include <linux/interrupt.h>
-#include <linux/of_address.h>
-#include <linux/of_platform.h>
-#include <linux/pm_runtime.h>
-
-#include "mtk_vcodec_dec_hw.h"
-#include "mtk_vcodec_dec_pm.h"
-#include "mtk_vcodec_util.h"
-
-int mtk_vcodec_init_dec_clk(struct platform_device *pdev, struct mtk_vcodec_pm *pm)
-{
-       struct mtk_vcodec_clk *dec_clk;
-       struct mtk_vcodec_clk_info *clk_info;
-       int i = 0, ret;
-
-       dec_clk = &pm->vdec_clk;
-       pm->dev = &pdev->dev;
-
-       dec_clk->clk_num =
-               of_property_count_strings(pdev->dev.of_node, "clock-names");
-       if (dec_clk->clk_num > 0) {
-               dec_clk->clk_info = devm_kcalloc(&pdev->dev,
-                       dec_clk->clk_num, sizeof(*clk_info),
-                       GFP_KERNEL);
-               if (!dec_clk->clk_info)
-                       return -ENOMEM;
-       } else {
-               mtk_v4l2_err("Failed to get vdec clock count");
-               return -EINVAL;
-       }
-
-       for (i = 0; i < dec_clk->clk_num; i++) {
-               clk_info = &dec_clk->clk_info[i];
-               ret = of_property_read_string_index(pdev->dev.of_node,
-                       "clock-names", i, &clk_info->clk_name);
-               if (ret) {
-                       mtk_v4l2_err("Failed to get clock name id = %d", i);
-                       return ret;
-               }
-               clk_info->vcodec_clk = devm_clk_get(&pdev->dev,
-                       clk_info->clk_name);
-               if (IS_ERR(clk_info->vcodec_clk)) {
-                       mtk_v4l2_err("devm_clk_get (%d)%s fail", i,
-                               clk_info->clk_name);
-                       return PTR_ERR(clk_info->vcodec_clk);
-               }
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(mtk_vcodec_init_dec_clk);
-
-int mtk_vcodec_dec_pw_on(struct mtk_vcodec_dev *vdec_dev, int hw_idx)
-{
-       struct mtk_vdec_hw_dev *subdev_dev;
-       struct mtk_vcodec_pm *pm;
-       int ret;
-
-       if (vdec_dev->vdec_pdata->is_subdev_supported) {
-               subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx);
-               if (!subdev_dev) {
-                       mtk_v4l2_err("Failed to get hw dev\n");
-                       return -EINVAL;
-               }
-               pm = &subdev_dev->pm;
-       } else {
-               pm = &vdec_dev->pm;
-       }
-
-       ret = pm_runtime_resume_and_get(pm->dev);
-       if (ret)
-               mtk_v4l2_err("pm_runtime_resume_and_get fail %d", ret);
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(mtk_vcodec_dec_pw_on);
-
-void mtk_vcodec_dec_pw_off(struct mtk_vcodec_dev *vdec_dev, int hw_idx)
-{
-       struct mtk_vdec_hw_dev *subdev_dev;
-       struct mtk_vcodec_pm *pm;
-       int ret;
-
-       if (vdec_dev->vdec_pdata->is_subdev_supported) {
-               subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx);
-               if (!subdev_dev) {
-                       mtk_v4l2_err("Failed to get hw dev\n");
-                       return;
-               }
-               pm = &subdev_dev->pm;
-       } else {
-               pm = &vdec_dev->pm;
-       }
-
-       ret = pm_runtime_put_sync(pm->dev);
-       if (ret)
-               mtk_v4l2_err("pm_runtime_put_sync fail %d", ret);
-}
-EXPORT_SYMBOL_GPL(mtk_vcodec_dec_pw_off);
-
-void mtk_vcodec_dec_clock_on(struct mtk_vcodec_dev *vdec_dev, int hw_idx)
-{
-       struct mtk_vdec_hw_dev *subdev_dev;
-       struct mtk_vcodec_pm *pm;
-       struct mtk_vcodec_clk *dec_clk;
-       int ret, i;
-
-       if (vdec_dev->vdec_pdata->is_subdev_supported) {
-               subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx);
-               if (!subdev_dev) {
-                       mtk_v4l2_err("Failed to get hw dev\n");
-                       return;
-               }
-               pm = &subdev_dev->pm;
-               enable_irq(subdev_dev->dec_irq);
-       } else {
-               pm = &vdec_dev->pm;
-               enable_irq(vdec_dev->dec_irq);
-       }
-
-       dec_clk = &pm->vdec_clk;
-       for (i = 0; i < dec_clk->clk_num; i++) {
-               ret = clk_prepare_enable(dec_clk->clk_info[i].vcodec_clk);
-               if (ret) {
-                       mtk_v4l2_err("clk_prepare_enable %d %s fail %d", i,
-                               dec_clk->clk_info[i].clk_name, ret);
-                       goto error;
-               }
-       }
-
-       return;
-error:
-       for (i -= 1; i >= 0; i--)
-               clk_disable_unprepare(dec_clk->clk_info[i].vcodec_clk);
-}
-EXPORT_SYMBOL_GPL(mtk_vcodec_dec_clock_on);
-
-void mtk_vcodec_dec_clock_off(struct mtk_vcodec_dev *vdec_dev, int hw_idx)
-{
-       struct mtk_vdec_hw_dev *subdev_dev;
-       struct mtk_vcodec_pm *pm;
-       struct mtk_vcodec_clk *dec_clk;
-       int i;
-
-       if (vdec_dev->vdec_pdata->is_subdev_supported) {
-               subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx);
-               if (!subdev_dev) {
-                       mtk_v4l2_err("Failed to get hw dev\n");
-                       return;
-               }
-               pm = &subdev_dev->pm;
-               disable_irq(subdev_dev->dec_irq);
-       } else {
-               pm = &vdec_dev->pm;
-               disable_irq(vdec_dev->dec_irq);
-       }
-
-       dec_clk = &pm->vdec_clk;
-       for (i = dec_clk->clk_num - 1; i >= 0; i--)
-               clk_disable_unprepare(dec_clk->clk_info[i].vcodec_clk);
-}
-EXPORT_SYMBOL_GPL(mtk_vcodec_dec_clock_off);
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h
deleted file mode 100644 (file)
index 3cc721b..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (c) 2016 MediaTek Inc.
- * Author: Tiffany Lin <tiffany.lin@mediatek.com>
- */
-
-#ifndef _MTK_VCODEC_DEC_PM_H_
-#define _MTK_VCODEC_DEC_PM_H_
-
-#include "mtk_vcodec_drv.h"
-
-int mtk_vcodec_init_dec_clk(struct platform_device *pdev, struct mtk_vcodec_pm *pm);
-
-int mtk_vcodec_dec_pw_on(struct mtk_vcodec_dev *vdec_dev, int hw_idx);
-void mtk_vcodec_dec_pw_off(struct mtk_vcodec_dev *vdec_dev, int hw_idx);
-void mtk_vcodec_dec_clock_on(struct mtk_vcodec_dev *vdec_dev, int hw_idx);
-void mtk_vcodec_dec_clock_off(struct mtk_vcodec_dev *vdec_dev, int hw_idx);
-
-#endif /* _MTK_VCODEC_DEC_PM_H_ */
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateful.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateful.c
deleted file mode 100644 (file)
index 04ca43c..0000000
+++ /dev/null
@@ -1,630 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-#include <media/v4l2-event.h>
-#include <media/v4l2-mem2mem.h>
-#include <media/videobuf2-dma-contig.h>
-
-#include "mtk_vcodec_drv.h"
-#include "mtk_vcodec_dec.h"
-#include "mtk_vcodec_intr.h"
-#include "mtk_vcodec_util.h"
-#include "mtk_vcodec_dec_pm.h"
-#include "vdec_drv_if.h"
-
-static const struct mtk_video_fmt mtk_video_formats[] = {
-       {
-               .fourcc = V4L2_PIX_FMT_H264,
-               .type = MTK_FMT_DEC,
-               .num_planes = 1,
-               .flags = V4L2_FMT_FLAG_DYN_RESOLUTION,
-       },
-       {
-               .fourcc = V4L2_PIX_FMT_VP8,
-               .type = MTK_FMT_DEC,
-               .num_planes = 1,
-               .flags = V4L2_FMT_FLAG_DYN_RESOLUTION,
-       },
-       {
-               .fourcc = V4L2_PIX_FMT_VP9,
-               .type = MTK_FMT_DEC,
-               .num_planes = 1,
-               .flags = V4L2_FMT_FLAG_DYN_RESOLUTION,
-       },
-       {
-               .fourcc = V4L2_PIX_FMT_MT21C,
-               .type = MTK_FMT_FRAME,
-               .num_planes = 2,
-       },
-};
-
-#define NUM_FORMATS ARRAY_SIZE(mtk_video_formats)
-#define DEFAULT_OUT_FMT_IDX 0
-#define DEFAULT_CAP_FMT_IDX 3
-
-static const struct mtk_codec_framesizes mtk_vdec_framesizes[] = {
-       {
-               .fourcc = V4L2_PIX_FMT_H264,
-               .stepwise = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16,
-                             MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 },
-       },
-       {
-               .fourcc = V4L2_PIX_FMT_VP8,
-               .stepwise = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16,
-                             MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 },
-       },
-       {
-               .fourcc = V4L2_PIX_FMT_VP9,
-               .stepwise = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16,
-                             MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 },
-       },
-};
-
-#define NUM_SUPPORTED_FRAMESIZE ARRAY_SIZE(mtk_vdec_framesizes)
-
-/*
- * This function tries to clean all display buffers, the buffers will return
- * in display order.
- * Note the buffers returned from codec driver may still be in driver's
- * reference list.
- */
-static struct vb2_buffer *get_display_buffer(struct mtk_vcodec_ctx *ctx)
-{
-       struct vdec_fb *disp_frame_buffer = NULL;
-       struct mtk_video_dec_buf *dstbuf;
-       struct vb2_v4l2_buffer *vb;
-
-       mtk_v4l2_debug(3, "[%d]", ctx->id);
-       if (vdec_if_get_param(ctx, GET_PARAM_DISP_FRAME_BUFFER,
-                             &disp_frame_buffer)) {
-               mtk_v4l2_err("[%d]Cannot get param : GET_PARAM_DISP_FRAME_BUFFER", ctx->id);
-               return NULL;
-       }
-
-       if (!disp_frame_buffer) {
-               mtk_v4l2_debug(3, "No display frame buffer");
-               return NULL;
-       }
-
-       dstbuf = container_of(disp_frame_buffer, struct mtk_video_dec_buf,
-                             frame_buffer);
-       vb = &dstbuf->m2m_buf.vb;
-       mutex_lock(&ctx->lock);
-       if (dstbuf->used) {
-               vb2_set_plane_payload(&vb->vb2_buf, 0, ctx->picinfo.fb_sz[0]);
-               if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2)
-                       vb2_set_plane_payload(&vb->vb2_buf, 1,
-                                             ctx->picinfo.fb_sz[1]);
-
-               mtk_v4l2_debug(2, "[%d]status=%x queue id=%d to done_list %d",
-                              ctx->id, disp_frame_buffer->status,
-                              vb->vb2_buf.index, dstbuf->queued_in_vb2);
-
-               v4l2_m2m_buf_done(vb, VB2_BUF_STATE_DONE);
-               ctx->decoded_frame_cnt++;
-       }
-       mutex_unlock(&ctx->lock);
-       return &vb->vb2_buf;
-}
-
-/*
- * This function tries to clean all capture buffers that are not used as
- * reference buffers by codec driver any more
- * In this case, we need re-queue buffer to vb2 buffer if user space
- * already returns this buffer to v4l2 or this buffer is just the output of
- * previous sps/pps/resolution change decode, or do nothing if user
- * space still owns this buffer
- */
-static struct vb2_buffer *get_free_buffer(struct mtk_vcodec_ctx *ctx)
-{
-       struct mtk_video_dec_buf *dstbuf;
-       struct vdec_fb *free_frame_buffer = NULL;
-       struct vb2_v4l2_buffer *vb;
-
-       if (vdec_if_get_param(ctx, GET_PARAM_FREE_FRAME_BUFFER,
-                             &free_frame_buffer)) {
-               mtk_v4l2_err("[%d] Error!! Cannot get param", ctx->id);
-               return NULL;
-       }
-       if (!free_frame_buffer) {
-               mtk_v4l2_debug(3, " No free frame buffer");
-               return NULL;
-       }
-
-       mtk_v4l2_debug(3, "[%d] tmp_frame_addr = 0x%p", ctx->id,
-                      free_frame_buffer);
-
-       dstbuf = container_of(free_frame_buffer, struct mtk_video_dec_buf,
-                             frame_buffer);
-       vb = &dstbuf->m2m_buf.vb;
-
-       mutex_lock(&ctx->lock);
-       if (dstbuf->used) {
-               if (dstbuf->queued_in_vb2 && dstbuf->queued_in_v4l2 &&
-                   free_frame_buffer->status == FB_ST_FREE) {
-                       /*
-                        * After decode sps/pps or non-display buffer, we don't
-                        * need to return capture buffer to user space, but
-                        * just re-queue this capture buffer to vb2 queue.
-                        * This reduce overheads that dq/q unused capture
-                        * buffer. In this case, queued_in_vb2 = true.
-                        */
-                       mtk_v4l2_debug(2, "[%d]status=%x queue id=%d to rdy_queue %d",
-                                      ctx->id, free_frame_buffer->status,
-                                      vb->vb2_buf.index, dstbuf->queued_in_vb2);
-                       v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
-               } else if (!dstbuf->queued_in_vb2 && dstbuf->queued_in_v4l2) {
-                       /*
-                        * If buffer in v4l2 driver but not in vb2 queue yet,
-                        * and we get this buffer from free_list, it means
-                        * that codec driver do not use this buffer as
-                        * reference buffer anymore. We should q buffer to vb2
-                        * queue, so later work thread could get this buffer
-                        * for decode. In this case, queued_in_vb2 = false
-                        * means this buffer is not from previous decode
-                        * output.
-                        */
-                       mtk_v4l2_debug(2,
-                                      "[%d]status=%x queue id=%d to rdy_queue",
-                                      ctx->id, free_frame_buffer->status,
-                                      vb->vb2_buf.index);
-                       v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
-                       dstbuf->queued_in_vb2 = true;
-               } else {
-                       /*
-                        * Codec driver do not need to reference this capture
-                        * buffer and this buffer is not in v4l2 driver.
-                        * Then we don't need to do any thing, just add log when
-                        * we need to debug buffer flow.
-                        * When this buffer q from user space, it could
-                        * directly q to vb2 buffer
-                        */
-                       mtk_v4l2_debug(3, "[%d]status=%x err queue id=%d %d %d",
-                                      ctx->id, free_frame_buffer->status,
-                                      vb->vb2_buf.index, dstbuf->queued_in_vb2,
-                                      dstbuf->queued_in_v4l2);
-               }
-               dstbuf->used = false;
-       }
-       mutex_unlock(&ctx->lock);
-       return &vb->vb2_buf;
-}
-
-static void clean_display_buffer(struct mtk_vcodec_ctx *ctx)
-{
-       while (get_display_buffer(ctx))
-               ;
-}
-
-static void clean_free_buffer(struct mtk_vcodec_ctx *ctx)
-{
-       while (get_free_buffer(ctx))
-               ;
-}
-
-static void mtk_vdec_queue_res_chg_event(struct mtk_vcodec_ctx *ctx)
-{
-       static const struct v4l2_event ev_src_ch = {
-               .type = V4L2_EVENT_SOURCE_CHANGE,
-               .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
-       };
-
-       mtk_v4l2_debug(1, "[%d]", ctx->id);
-       v4l2_event_queue_fh(&ctx->fh, &ev_src_ch);
-}
-
-static int mtk_vdec_flush_decoder(struct mtk_vcodec_ctx *ctx)
-{
-       bool res_chg;
-       int ret;
-
-       ret = vdec_if_decode(ctx, NULL, NULL, &res_chg);
-       if (ret)
-               mtk_v4l2_err("DecodeFinal failed, ret=%d", ret);
-
-       clean_display_buffer(ctx);
-       clean_free_buffer(ctx);
-
-       return 0;
-}
-
-static void mtk_vdec_update_fmt(struct mtk_vcodec_ctx *ctx,
-                               unsigned int pixelformat)
-{
-       const struct mtk_video_fmt *fmt;
-       struct mtk_q_data *dst_q_data;
-       unsigned int k;
-
-       dst_q_data = &ctx->q_data[MTK_Q_DATA_DST];
-       for (k = 0; k < NUM_FORMATS; k++) {
-               fmt = &mtk_video_formats[k];
-               if (fmt->fourcc == pixelformat) {
-                       mtk_v4l2_debug(1, "Update cap fourcc(%d -> %d)",
-                                      dst_q_data->fmt->fourcc, pixelformat);
-                       dst_q_data->fmt = fmt;
-                       return;
-               }
-       }
-
-       mtk_v4l2_err("Cannot get fourcc(%d), using init value", pixelformat);
-}
-
-static int mtk_vdec_pic_info_update(struct mtk_vcodec_ctx *ctx)
-{
-       unsigned int dpbsize = 0;
-       int ret;
-
-       if (vdec_if_get_param(ctx, GET_PARAM_PIC_INFO,
-                             &ctx->last_decoded_picinfo)) {
-               mtk_v4l2_err("[%d]Error!! Cannot get param : GET_PARAM_PICTURE_INFO ERR", ctx->id);
-               return -EINVAL;
-       }
-
-       if (ctx->last_decoded_picinfo.pic_w == 0 ||
-           ctx->last_decoded_picinfo.pic_h == 0 ||
-           ctx->last_decoded_picinfo.buf_w == 0 ||
-           ctx->last_decoded_picinfo.buf_h == 0) {
-               mtk_v4l2_err("Cannot get correct pic info");
-               return -EINVAL;
-       }
-
-       if (ctx->last_decoded_picinfo.cap_fourcc != ctx->picinfo.cap_fourcc &&
-           ctx->picinfo.cap_fourcc != 0)
-               mtk_vdec_update_fmt(ctx, ctx->picinfo.cap_fourcc);
-
-       if (ctx->last_decoded_picinfo.pic_w == ctx->picinfo.pic_w ||
-           ctx->last_decoded_picinfo.pic_h == ctx->picinfo.pic_h)
-               return 0;
-
-       mtk_v4l2_debug(1, "[%d]-> new(%d,%d), old(%d,%d), real(%d,%d)", ctx->id,
-                      ctx->last_decoded_picinfo.pic_w,
-                      ctx->last_decoded_picinfo.pic_h, ctx->picinfo.pic_w,
-                      ctx->picinfo.pic_h, ctx->last_decoded_picinfo.buf_w,
-                      ctx->last_decoded_picinfo.buf_h);
-
-       ret = vdec_if_get_param(ctx, GET_PARAM_DPB_SIZE, &dpbsize);
-       if (dpbsize == 0)
-               mtk_v4l2_err("Incorrect dpb size, ret=%d", ret);
-
-       ctx->dpb_size = dpbsize;
-
-       return ret;
-}
-
-static void mtk_vdec_worker(struct work_struct *work)
-{
-       struct mtk_vcodec_ctx *ctx =
-               container_of(work, struct mtk_vcodec_ctx, decode_work);
-       struct mtk_vcodec_dev *dev = ctx->dev;
-       struct vb2_v4l2_buffer *src_buf, *dst_buf;
-       struct mtk_vcodec_mem buf;
-       struct vdec_fb *pfb;
-       bool res_chg = false;
-       int ret;
-       struct mtk_video_dec_buf *dst_buf_info, *src_buf_info;
-
-       src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
-       if (!src_buf) {
-               v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
-               mtk_v4l2_debug(1, "[%d] src_buf empty!!", ctx->id);
-               return;
-       }
-
-       dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
-       if (!dst_buf) {
-               v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
-               mtk_v4l2_debug(1, "[%d] dst_buf empty!!", ctx->id);
-               return;
-       }
-
-       dst_buf_info =
-               container_of(dst_buf, struct mtk_video_dec_buf, m2m_buf.vb);
-
-       pfb = &dst_buf_info->frame_buffer;
-       pfb->base_y.va = vb2_plane_vaddr(&dst_buf->vb2_buf, 0);
-       pfb->base_y.dma_addr =
-               vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
-       pfb->base_y.size = ctx->picinfo.fb_sz[0];
-
-       pfb->base_c.va = vb2_plane_vaddr(&dst_buf->vb2_buf, 1);
-       pfb->base_c.dma_addr =
-               vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 1);
-       pfb->base_c.size = ctx->picinfo.fb_sz[1];
-       pfb->status = 0;
-       mtk_v4l2_debug(3, "===>[%d] vdec_if_decode() ===>", ctx->id);
-
-       mtk_v4l2_debug(3,
-                      "id=%d Framebuf  pfb=%p VA=%p Y_DMA=%pad C_DMA=%pad Size=%zx",
-                      dst_buf->vb2_buf.index, pfb, pfb->base_y.va,
-                      &pfb->base_y.dma_addr, &pfb->base_c.dma_addr, pfb->base_y.size);
-
-       if (src_buf == &ctx->empty_flush_buf.vb) {
-               mtk_v4l2_debug(1, "Got empty flush input buffer.");
-               src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
-
-               /* update dst buf status */
-               dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
-               mutex_lock(&ctx->lock);
-               dst_buf_info->used = false;
-               mutex_unlock(&ctx->lock);
-
-               vdec_if_decode(ctx, NULL, NULL, &res_chg);
-               clean_display_buffer(ctx);
-               vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0);
-               if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2)
-                       vb2_set_plane_payload(&dst_buf->vb2_buf, 1, 0);
-               dst_buf->flags |= V4L2_BUF_FLAG_LAST;
-               v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
-               clean_free_buffer(ctx);
-               v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
-               return;
-       }
-
-       src_buf_info =
-               container_of(src_buf, struct mtk_video_dec_buf, m2m_buf.vb);
-
-       buf.va = vb2_plane_vaddr(&src_buf->vb2_buf, 0);
-       buf.dma_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
-       buf.size = (size_t)src_buf->vb2_buf.planes[0].bytesused;
-       if (!buf.va) {
-               v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
-               mtk_v4l2_err("[%d] id=%d src_addr is NULL!!", ctx->id,
-                            src_buf->vb2_buf.index);
-               return;
-       }
-       mtk_v4l2_debug(3, "[%d] Bitstream VA=%p DMA=%pad Size=%zx vb=%p",
-                      ctx->id, buf.va, &buf.dma_addr, buf.size, src_buf);
-       dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp;
-       dst_buf->timecode = src_buf->timecode;
-       mutex_lock(&ctx->lock);
-       dst_buf_info->used = true;
-       mutex_unlock(&ctx->lock);
-       src_buf_info->used = true;
-
-       ret = vdec_if_decode(ctx, &buf, pfb, &res_chg);
-
-       if (ret) {
-               mtk_v4l2_err(" <===[%d], src_buf[%d] sz=0x%zx pts=%llu dst_buf[%d] vdec_if_decode() ret=%d res_chg=%d===>",
-                            ctx->id, src_buf->vb2_buf.index, buf.size,
-                            src_buf->vb2_buf.timestamp, dst_buf->vb2_buf.index, ret, res_chg);
-               src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
-               if (ret == -EIO) {
-                       mutex_lock(&ctx->lock);
-                       src_buf_info->error = true;
-                       mutex_unlock(&ctx->lock);
-               }
-               v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
-       } else if (!res_chg) {
-               /*
-                * we only return src buffer with VB2_BUF_STATE_DONE
-                * when decode success without resolution change
-                */
-               src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
-               v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
-       }
-
-       dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
-       clean_display_buffer(ctx);
-       clean_free_buffer(ctx);
-
-       if (!ret && res_chg) {
-               mtk_vdec_pic_info_update(ctx);
-               /*
-                * On encountering a resolution change in the stream.
-                * The driver must first process and decode all
-                * remaining buffers from before the resolution change
-                * point, so call flush decode here
-                */
-               mtk_vdec_flush_decoder(ctx);
-               /*
-                * After all buffers containing decoded frames from
-                * before the resolution change point ready to be
-                * dequeued on the CAPTURE queue, the driver sends a
-                * V4L2_EVENT_SOURCE_CHANGE event for source change
-                * type V4L2_EVENT_SRC_CH_RESOLUTION
-                */
-               mtk_vdec_queue_res_chg_event(ctx);
-       }
-       v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
-}
-
-static void vb2ops_vdec_stateful_buf_queue(struct vb2_buffer *vb)
-{
-       struct vb2_v4l2_buffer *src_buf;
-       struct mtk_vcodec_mem src_mem;
-       bool res_chg = false;
-       int ret;
-       unsigned int dpbsize = 1, i;
-       struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
-       struct vb2_v4l2_buffer *vb2_v4l2;
-       struct mtk_q_data *dst_q_data;
-
-       mtk_v4l2_debug(3, "[%d] (%d) id=%d, vb=%p", ctx->id,
-                      vb->vb2_queue->type, vb->index, vb);
-       /*
-        * check if this buffer is ready to be used after decode
-        */
-       if (vb->vb2_queue->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-               struct mtk_video_dec_buf *buf;
-
-               vb2_v4l2 = to_vb2_v4l2_buffer(vb);
-               buf = container_of(vb2_v4l2, struct mtk_video_dec_buf,
-                                  m2m_buf.vb);
-               mutex_lock(&ctx->lock);
-               if (!buf->used) {
-                       v4l2_m2m_buf_queue(ctx->m2m_ctx, vb2_v4l2);
-                       buf->queued_in_vb2 = true;
-                       buf->queued_in_v4l2 = true;
-               } else {
-                       buf->queued_in_vb2 = false;
-                       buf->queued_in_v4l2 = true;
-               }
-               mutex_unlock(&ctx->lock);
-               return;
-       }
-
-       v4l2_m2m_buf_queue(ctx->m2m_ctx, to_vb2_v4l2_buffer(vb));
-
-       if (ctx->state != MTK_STATE_INIT) {
-               mtk_v4l2_debug(3, "[%d] already init driver %d", ctx->id,
-                              ctx->state);
-               return;
-       }
-
-       src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
-       if (!src_buf) {
-               mtk_v4l2_err("No src buffer");
-               return;
-       }
-
-       if (src_buf == &ctx->empty_flush_buf.vb) {
-               /* This shouldn't happen. Just in case. */
-               mtk_v4l2_err("Invalid flush buffer.");
-               v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
-               return;
-       }
-
-       src_mem.va = vb2_plane_vaddr(&src_buf->vb2_buf, 0);
-       src_mem.dma_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
-       src_mem.size = (size_t)src_buf->vb2_buf.planes[0].bytesused;
-       mtk_v4l2_debug(2, "[%d] buf id=%d va=%p dma=%pad size=%zx", ctx->id,
-                      src_buf->vb2_buf.index, src_mem.va, &src_mem.dma_addr,
-                      src_mem.size);
-
-       ret = vdec_if_decode(ctx, &src_mem, NULL, &res_chg);
-       if (ret || !res_chg) {
-               /*
-                * fb == NULL means to parse SPS/PPS header or
-                * resolution info in src_mem. Decode can fail
-                * if there is no SPS header or picture info
-                * in bs
-                */
-
-               src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
-               if (ret == -EIO) {
-                       mtk_v4l2_err("[%d] Unrecoverable error in vdec_if_decode.", ctx->id);
-                       ctx->state = MTK_STATE_ABORT;
-                       v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
-               } else {
-                       v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
-               }
-               mtk_v4l2_debug(ret ? 0 : 1,
-                              "[%d] vdec_if_decode() src_buf=%d, size=%zu, fail=%d, res_chg=%d",
-                              ctx->id, src_buf->vb2_buf.index, src_mem.size, ret, res_chg);
-               return;
-       }
-
-       if (vdec_if_get_param(ctx, GET_PARAM_PIC_INFO, &ctx->picinfo)) {
-               mtk_v4l2_err("[%d]Error!! Cannot get param : GET_PARAM_PICTURE_INFO ERR", ctx->id);
-               return;
-       }
-
-       ctx->last_decoded_picinfo = ctx->picinfo;
-       dst_q_data = &ctx->q_data[MTK_Q_DATA_DST];
-       for (i = 0; i < dst_q_data->fmt->num_planes; i++) {
-               dst_q_data->sizeimage[i] = ctx->picinfo.fb_sz[i];
-               dst_q_data->bytesperline[i] = ctx->picinfo.buf_w;
-       }
-
-       mtk_v4l2_debug(2, "[%d] vdec_if_init() OK wxh=%dx%d pic wxh=%dx%d sz[0]=0x%x sz[1]=0x%x",
-                      ctx->id, ctx->picinfo.buf_w, ctx->picinfo.buf_h, ctx->picinfo.pic_w,
-                      ctx->picinfo.pic_h, dst_q_data->sizeimage[0], dst_q_data->sizeimage[1]);
-
-       ret = vdec_if_get_param(ctx, GET_PARAM_DPB_SIZE, &dpbsize);
-       if (dpbsize == 0)
-               mtk_v4l2_err("[%d] GET_PARAM_DPB_SIZE fail=%d", ctx->id, ret);
-
-       ctx->dpb_size = dpbsize;
-       ctx->state = MTK_STATE_HEADER;
-       mtk_v4l2_debug(1, "[%d] dpbsize=%d", ctx->id, ctx->dpb_size);
-
-       mtk_vdec_queue_res_chg_event(ctx);
-}
-
-static int mtk_vdec_g_v_ctrl(struct v4l2_ctrl *ctrl)
-{
-       struct mtk_vcodec_ctx *ctx = ctrl_to_ctx(ctrl);
-       int ret = 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
-               if (ctx->state >= MTK_STATE_HEADER) {
-                       ctrl->val = ctx->dpb_size;
-               } else {
-                       mtk_v4l2_debug(0, "Seqinfo not ready");
-                       ctrl->val = 0;
-               }
-               break;
-       default:
-               ret = -EINVAL;
-       }
-       return ret;
-}
-
-static const struct v4l2_ctrl_ops mtk_vcodec_dec_ctrl_ops = {
-       .g_volatile_ctrl = mtk_vdec_g_v_ctrl,
-};
-
-static int mtk_vcodec_dec_ctrls_setup(struct mtk_vcodec_ctx *ctx)
-{
-       struct v4l2_ctrl *ctrl;
-
-       v4l2_ctrl_handler_init(&ctx->ctrl_hdl, 1);
-
-       ctrl = v4l2_ctrl_new_std(&ctx->ctrl_hdl, &mtk_vcodec_dec_ctrl_ops,
-                                V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 0, 32, 1, 1);
-       ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
-       v4l2_ctrl_new_std_menu(&ctx->ctrl_hdl, &mtk_vcodec_dec_ctrl_ops,
-                              V4L2_CID_MPEG_VIDEO_VP9_PROFILE,
-                              V4L2_MPEG_VIDEO_VP9_PROFILE_0, 0,
-                              V4L2_MPEG_VIDEO_VP9_PROFILE_0);
-       /*
-        * H264. Baseline / Extended decoding is not supported.
-        */
-       v4l2_ctrl_new_std_menu(&ctx->ctrl_hdl, &mtk_vcodec_dec_ctrl_ops,
-                              V4L2_CID_MPEG_VIDEO_H264_PROFILE, V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
-                              BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
-                              BIT(V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED),
-                              V4L2_MPEG_VIDEO_H264_PROFILE_MAIN);
-
-       if (ctx->ctrl_hdl.error) {
-               mtk_v4l2_err("Adding control failed %d", ctx->ctrl_hdl.error);
-               return ctx->ctrl_hdl.error;
-       }
-
-       v4l2_ctrl_handler_setup(&ctx->ctrl_hdl);
-       return 0;
-}
-
-static void mtk_init_vdec_params(struct mtk_vcodec_ctx *ctx)
-{
-}
-
-static struct vb2_ops mtk_vdec_frame_vb2_ops = {
-       .queue_setup = vb2ops_vdec_queue_setup,
-       .buf_prepare = vb2ops_vdec_buf_prepare,
-       .wait_prepare = vb2_ops_wait_prepare,
-       .wait_finish = vb2_ops_wait_finish,
-       .start_streaming = vb2ops_vdec_start_streaming,
-
-       .buf_queue = vb2ops_vdec_stateful_buf_queue,
-       .buf_init = vb2ops_vdec_buf_init,
-       .buf_finish = vb2ops_vdec_buf_finish,
-       .stop_streaming = vb2ops_vdec_stop_streaming,
-};
-
-const struct mtk_vcodec_dec_pdata mtk_vdec_8173_pdata = {
-       .chip = MTK_MT8173,
-       .init_vdec_params = mtk_init_vdec_params,
-       .ctrls_setup = mtk_vcodec_dec_ctrls_setup,
-       .vdec_vb2_ops = &mtk_vdec_frame_vb2_ops,
-       .vdec_formats = mtk_video_formats,
-       .num_formats = NUM_FORMATS,
-       .default_out_fmt = &mtk_video_formats[DEFAULT_OUT_FMT_IDX],
-       .default_cap_fmt = &mtk_video_formats[DEFAULT_CAP_FMT_IDX],
-       .vdec_framesizes = mtk_vdec_framesizes,
-       .num_framesizes = NUM_SUPPORTED_FRAMESIZE,
-       .worker = mtk_vdec_worker,
-       .flush_decoder = mtk_vdec_flush_decoder,
-       .is_subdev_supported = false,
-       .hw_arch = MTK_VDEC_PURE_SINGLE_CORE,
-};
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateless.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateless.c
deleted file mode 100644 (file)
index 23d997a..0000000
+++ /dev/null
@@ -1,380 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-#include <media/videobuf2-v4l2.h>
-#include <media/videobuf2-dma-contig.h>
-#include <media/v4l2-event.h>
-#include <media/v4l2-mem2mem.h>
-#include <linux/module.h>
-
-#include "mtk_vcodec_drv.h"
-#include "mtk_vcodec_dec.h"
-#include "mtk_vcodec_intr.h"
-#include "mtk_vcodec_util.h"
-#include "mtk_vcodec_dec_pm.h"
-#include "vdec_drv_if.h"
-
-/**
- * struct mtk_stateless_control  - CID control type
- * @cfg: control configuration
- * @codec_type: codec type (V4L2 pixel format) for CID control type
- */
-struct mtk_stateless_control {
-       struct v4l2_ctrl_config cfg;
-       int codec_type;
-};
-
-static const struct mtk_stateless_control mtk_stateless_controls[] = {
-       {
-               .cfg = {
-                       .id = V4L2_CID_STATELESS_H264_SPS,
-               },
-               .codec_type = V4L2_PIX_FMT_H264_SLICE,
-       },
-       {
-               .cfg = {
-                       .id = V4L2_CID_STATELESS_H264_PPS,
-               },
-               .codec_type = V4L2_PIX_FMT_H264_SLICE,
-       },
-       {
-               .cfg = {
-                       .id = V4L2_CID_STATELESS_H264_SCALING_MATRIX,
-               },
-               .codec_type = V4L2_PIX_FMT_H264_SLICE,
-       },
-       {
-               .cfg = {
-                       .id = V4L2_CID_STATELESS_H264_DECODE_PARAMS,
-               },
-               .codec_type = V4L2_PIX_FMT_H264_SLICE,
-       },
-       {
-               .cfg = {
-                       .id = V4L2_CID_MPEG_VIDEO_H264_PROFILE,
-                       .def = V4L2_MPEG_VIDEO_H264_PROFILE_MAIN,
-                       .max = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
-                       .menu_skip_mask =
-                               BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
-                               BIT(V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED),
-               },
-               .codec_type = V4L2_PIX_FMT_H264_SLICE,
-       },
-       {
-               .cfg = {
-                       .id = V4L2_CID_STATELESS_H264_DECODE_MODE,
-                       .min = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED,
-                       .def = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED,
-                       .max = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED,
-               },
-               .codec_type = V4L2_PIX_FMT_H264_SLICE,
-       },
-       {
-               .cfg = {
-                       .id = V4L2_CID_STATELESS_H264_START_CODE,
-                       .min = V4L2_STATELESS_H264_START_CODE_ANNEX_B,
-                       .def = V4L2_STATELESS_H264_START_CODE_ANNEX_B,
-                       .max = V4L2_STATELESS_H264_START_CODE_ANNEX_B,
-               },
-               .codec_type = V4L2_PIX_FMT_H264_SLICE,
-       }
-};
-
-#define NUM_CTRLS ARRAY_SIZE(mtk_stateless_controls)
-
-static const struct mtk_video_fmt mtk_video_formats[] = {
-       {
-               .fourcc = V4L2_PIX_FMT_H264_SLICE,
-               .type = MTK_FMT_DEC,
-               .num_planes = 1,
-       },
-       {
-               .fourcc = V4L2_PIX_FMT_MM21,
-               .type = MTK_FMT_FRAME,
-               .num_planes = 2,
-       },
-};
-
-#define NUM_FORMATS ARRAY_SIZE(mtk_video_formats)
-#define DEFAULT_OUT_FMT_IDX    0
-#define DEFAULT_CAP_FMT_IDX    1
-
-static const struct mtk_codec_framesizes mtk_vdec_framesizes[] = {
-       {
-               .fourcc = V4L2_PIX_FMT_H264_SLICE,
-               .stepwise = {  MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16,
-                               MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 },
-       },
-};
-
-#define NUM_SUPPORTED_FRAMESIZE ARRAY_SIZE(mtk_vdec_framesizes)
-
-static void mtk_vdec_stateless_set_dst_payload(struct mtk_vcodec_ctx *ctx,
-                                              struct vdec_fb *fb)
-{
-       struct mtk_video_dec_buf *vdec_frame_buf =
-               container_of(fb, struct mtk_video_dec_buf, frame_buffer);
-       struct vb2_v4l2_buffer *vb = &vdec_frame_buf->m2m_buf.vb;
-       unsigned int cap_y_size = ctx->q_data[MTK_Q_DATA_DST].sizeimage[0];
-
-       vb2_set_plane_payload(&vb->vb2_buf, 0, cap_y_size);
-       if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) {
-               unsigned int cap_c_size =
-                       ctx->q_data[MTK_Q_DATA_DST].sizeimage[1];
-
-               vb2_set_plane_payload(&vb->vb2_buf, 1, cap_c_size);
-       }
-}
-
-static struct vdec_fb *vdec_get_cap_buffer(struct mtk_vcodec_ctx *ctx,
-                                          struct vb2_v4l2_buffer *vb2_v4l2)
-{
-       struct mtk_video_dec_buf *framebuf =
-               container_of(vb2_v4l2, struct mtk_video_dec_buf, m2m_buf.vb);
-       struct vdec_fb *pfb = &framebuf->frame_buffer;
-       struct vb2_buffer *dst_buf = &vb2_v4l2->vb2_buf;
-
-       pfb->base_y.va = NULL;
-       pfb->base_y.dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
-       pfb->base_y.size = ctx->q_data[MTK_Q_DATA_DST].sizeimage[0];
-
-       if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) {
-               pfb->base_c.va = NULL;
-               pfb->base_c.dma_addr =
-                       vb2_dma_contig_plane_dma_addr(dst_buf, 1);
-               pfb->base_c.size = ctx->q_data[MTK_Q_DATA_DST].sizeimage[1];
-       }
-       mtk_v4l2_debug(1, "id=%d Framebuf  pfb=%p VA=%p Y_DMA=%pad C_DMA=%pad Size=%zx frame_count = %d",
-                      dst_buf->index, pfb, pfb->base_y.va, &pfb->base_y.dma_addr,
-                      &pfb->base_c.dma_addr, pfb->base_y.size, ctx->decoded_frame_cnt);
-
-       return pfb;
-}
-
-static void vb2ops_vdec_buf_request_complete(struct vb2_buffer *vb)
-{
-       struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
-
-       v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->ctrl_hdl);
-}
-
-static void mtk_vdec_worker(struct work_struct *work)
-{
-       struct mtk_vcodec_ctx *ctx =
-               container_of(work, struct mtk_vcodec_ctx, decode_work);
-       struct mtk_vcodec_dev *dev = ctx->dev;
-       struct vb2_v4l2_buffer *vb2_v4l2_src, *vb2_v4l2_dst;
-       struct vb2_buffer *vb2_src;
-       struct mtk_vcodec_mem *bs_src;
-       struct mtk_video_dec_buf *dec_buf_src;
-       struct media_request *src_buf_req;
-       struct vdec_fb *dst_buf;
-       bool res_chg = false;
-       int ret;
-
-       vb2_v4l2_src = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
-       if (!vb2_v4l2_src) {
-               v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
-               mtk_v4l2_debug(1, "[%d] no available source buffer", ctx->id);
-               return;
-       }
-
-       vb2_v4l2_dst = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
-       if (!vb2_v4l2_dst) {
-               v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
-               mtk_v4l2_debug(1, "[%d] no available destination buffer", ctx->id);
-               return;
-       }
-
-       vb2_src = &vb2_v4l2_src->vb2_buf;
-       dec_buf_src = container_of(vb2_v4l2_src, struct mtk_video_dec_buf,
-                                  m2m_buf.vb);
-       bs_src = &dec_buf_src->bs_buffer;
-
-       mtk_v4l2_debug(3, "[%d] (%d) id=%d, vb=%p", ctx->id,
-                      vb2_src->vb2_queue->type, vb2_src->index, vb2_src);
-
-       bs_src->va = NULL;
-       bs_src->dma_addr = vb2_dma_contig_plane_dma_addr(vb2_src, 0);
-       bs_src->size = (size_t)vb2_src->planes[0].bytesused;
-
-       mtk_v4l2_debug(3, "[%d] Bitstream VA=%p DMA=%pad Size=%zx vb=%p",
-                      ctx->id, bs_src->va, &bs_src->dma_addr, bs_src->size, vb2_src);
-       /* Apply request controls. */
-       src_buf_req = vb2_src->req_obj.req;
-       if (src_buf_req)
-               v4l2_ctrl_request_setup(src_buf_req, &ctx->ctrl_hdl);
-       else
-               mtk_v4l2_err("vb2 buffer media request is NULL");
-
-       dst_buf = vdec_get_cap_buffer(ctx, vb2_v4l2_dst);
-       v4l2_m2m_buf_copy_metadata(vb2_v4l2_src, vb2_v4l2_dst, true);
-       ret = vdec_if_decode(ctx, bs_src, dst_buf, &res_chg);
-       if (ret) {
-               mtk_v4l2_err(" <===[%d], src_buf[%d] sz=0x%zx pts=%llu vdec_if_decode() ret=%d res_chg=%d===>",
-                            ctx->id, vb2_src->index, bs_src->size,
-                            vb2_src->timestamp, ret, res_chg);
-               if (ret == -EIO) {
-                       mutex_lock(&ctx->lock);
-                       dec_buf_src->error = true;
-                       mutex_unlock(&ctx->lock);
-               }
-       }
-
-       mtk_vdec_stateless_set_dst_payload(ctx, dst_buf);
-
-       v4l2_m2m_buf_done_and_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx,
-                                        ret ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
-
-       v4l2_ctrl_request_complete(src_buf_req, &ctx->ctrl_hdl);
-}
-
-static void vb2ops_vdec_stateless_buf_queue(struct vb2_buffer *vb)
-{
-       struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
-       struct vb2_v4l2_buffer *vb2_v4l2 = to_vb2_v4l2_buffer(vb);
-
-       mtk_v4l2_debug(3, "[%d] (%d) id=%d, vb=%p", ctx->id, vb->vb2_queue->type, vb->index, vb);
-
-       mutex_lock(&ctx->lock);
-       v4l2_m2m_buf_queue(ctx->m2m_ctx, vb2_v4l2);
-       mutex_unlock(&ctx->lock);
-       if (vb->vb2_queue->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
-               return;
-
-       /* If an OUTPUT buffer, we may need to update the state */
-       if (ctx->state == MTK_STATE_INIT) {
-               ctx->state = MTK_STATE_HEADER;
-               mtk_v4l2_debug(1, "Init driver from init to header.");
-       } else {
-               mtk_v4l2_debug(3, "[%d] already init driver %d", ctx->id, ctx->state);
-       }
-}
-
-static int mtk_vdec_flush_decoder(struct mtk_vcodec_ctx *ctx)
-{
-       bool res_chg;
-
-       return vdec_if_decode(ctx, NULL, NULL, &res_chg);
-}
-
-static int mtk_vcodec_dec_ctrls_setup(struct mtk_vcodec_ctx *ctx)
-{
-       unsigned int i;
-
-       v4l2_ctrl_handler_init(&ctx->ctrl_hdl, NUM_CTRLS);
-       if (ctx->ctrl_hdl.error) {
-               mtk_v4l2_err("v4l2_ctrl_handler_init failed\n");
-               return ctx->ctrl_hdl.error;
-       }
-
-       for (i = 0; i < NUM_CTRLS; i++) {
-               struct v4l2_ctrl_config cfg = mtk_stateless_controls[i].cfg;
-
-               v4l2_ctrl_new_custom(&ctx->ctrl_hdl, &cfg, NULL);
-               if (ctx->ctrl_hdl.error) {
-                       mtk_v4l2_err("Adding control %d failed %d", i, ctx->ctrl_hdl.error);
-                       return ctx->ctrl_hdl.error;
-               }
-       }
-
-       v4l2_ctrl_handler_setup(&ctx->ctrl_hdl);
-
-       return 0;
-}
-
-static int fops_media_request_validate(struct media_request *mreq)
-{
-       const unsigned int buffer_cnt = vb2_request_buffer_cnt(mreq);
-
-       switch (buffer_cnt) {
-       case 1:
-               /* We expect exactly one buffer with the request */
-               break;
-       case 0:
-               mtk_v4l2_debug(1, "No buffer provided with the request");
-               return -ENOENT;
-       default:
-               mtk_v4l2_debug(1, "Too many buffers (%d) provided with the request",
-                              buffer_cnt);
-               return -EINVAL;
-       }
-
-       return vb2_request_validate(mreq);
-}
-
-const struct media_device_ops mtk_vcodec_media_ops = {
-       .req_validate   = fops_media_request_validate,
-       .req_queue      = v4l2_m2m_request_queue,
-};
-
-static void mtk_init_vdec_params(struct mtk_vcodec_ctx *ctx)
-{
-       struct vb2_queue *src_vq;
-
-       src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx,
-                                V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
-
-       /* Support request api for output plane */
-       src_vq->supports_requests = true;
-       src_vq->requires_requests = true;
-}
-
-static int vb2ops_vdec_out_buf_validate(struct vb2_buffer *vb)
-{
-       struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
-
-       vbuf->field = V4L2_FIELD_NONE;
-       return 0;
-}
-
-static struct vb2_ops mtk_vdec_request_vb2_ops = {
-       .queue_setup    = vb2ops_vdec_queue_setup,
-       .wait_prepare   = vb2_ops_wait_prepare,
-       .wait_finish    = vb2_ops_wait_finish,
-       .start_streaming        = vb2ops_vdec_start_streaming,
-       .stop_streaming = vb2ops_vdec_stop_streaming,
-
-       .buf_queue      = vb2ops_vdec_stateless_buf_queue,
-       .buf_out_validate = vb2ops_vdec_out_buf_validate,
-       .buf_init       = vb2ops_vdec_buf_init,
-       .buf_prepare    = vb2ops_vdec_buf_prepare,
-       .buf_finish     = vb2ops_vdec_buf_finish,
-       .buf_request_complete = vb2ops_vdec_buf_request_complete,
-};
-
-const struct mtk_vcodec_dec_pdata mtk_vdec_8183_pdata = {
-       .chip = MTK_MT8183,
-       .init_vdec_params = mtk_init_vdec_params,
-       .ctrls_setup = mtk_vcodec_dec_ctrls_setup,
-       .vdec_vb2_ops = &mtk_vdec_request_vb2_ops,
-       .vdec_formats = mtk_video_formats,
-       .num_formats = NUM_FORMATS,
-       .default_out_fmt = &mtk_video_formats[DEFAULT_OUT_FMT_IDX],
-       .default_cap_fmt = &mtk_video_formats[DEFAULT_CAP_FMT_IDX],
-       .vdec_framesizes = mtk_vdec_framesizes,
-       .num_framesizes = NUM_SUPPORTED_FRAMESIZE,
-       .uses_stateless_api = true,
-       .worker = mtk_vdec_worker,
-       .flush_decoder = mtk_vdec_flush_decoder,
-       .is_subdev_supported = false,
-       .hw_arch = MTK_VDEC_PURE_SINGLE_CORE,
-};
-
-/* This platform data is used for one lat and one core architecture. */
-const struct mtk_vcodec_dec_pdata mtk_lat_sig_core_pdata = {
-       .chip = MTK_MT8192,
-       .init_vdec_params = mtk_init_vdec_params,
-       .ctrls_setup = mtk_vcodec_dec_ctrls_setup,
-       .vdec_vb2_ops = &mtk_vdec_request_vb2_ops,
-       .vdec_formats = mtk_video_formats,
-       .num_formats = NUM_FORMATS,
-       .default_out_fmt = &mtk_video_formats[DEFAULT_OUT_FMT_IDX],
-       .default_cap_fmt = &mtk_video_formats[DEFAULT_CAP_FMT_IDX],
-       .vdec_framesizes = mtk_vdec_framesizes,
-       .num_framesizes = NUM_SUPPORTED_FRAMESIZE,
-       .uses_stateless_api = true,
-       .worker = mtk_vdec_worker,
-       .flush_decoder = mtk_vdec_flush_decoder,
-       .is_subdev_supported = true,
-       .hw_arch = MTK_VDEC_LAT_SINGLE_CORE,
-};
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
deleted file mode 100644 (file)
index 813901c..0000000
+++ /dev/null
@@ -1,537 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
-* Copyright (c) 2016 MediaTek Inc.
-* Author: PC Chen <pc.chen@mediatek.com>
-*         Tiffany Lin <tiffany.lin@mediatek.com>
-*/
-
-#ifndef _MTK_VCODEC_DRV_H_
-#define _MTK_VCODEC_DRV_H_
-
-#include <linux/platform_device.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-mem2mem.h>
-#include <media/videobuf2-core.h>
-
-#include "mtk_vcodec_util.h"
-#include "vdec_msg_queue.h"
-
-#define MTK_VCODEC_DRV_NAME    "mtk_vcodec_drv"
-#define MTK_VCODEC_DEC_NAME    "mtk-vcodec-dec"
-#define MTK_VCODEC_ENC_NAME    "mtk-vcodec-enc"
-#define MTK_PLATFORM_STR       "platform:mt8173"
-
-#define MTK_VCODEC_MAX_PLANES  3
-#define MTK_V4L2_BENCHMARK     0
-#define WAIT_INTR_TIMEOUT_MS   1000
-#define IS_VDEC_LAT_ARCH(hw_arch) ((hw_arch) >= MTK_VDEC_LAT_SINGLE_CORE)
-
-/*
- * enum mtk_hw_reg_idx - MTK hw register base index
- */
-enum mtk_hw_reg_idx {
-       VDEC_SYS,
-       VDEC_MISC,
-       VDEC_LD,
-       VDEC_TOP,
-       VDEC_CM,
-       VDEC_AD,
-       VDEC_AV,
-       VDEC_PP,
-       VDEC_HWD,
-       VDEC_HWQ,
-       VDEC_HWB,
-       VDEC_HWG,
-       NUM_MAX_VDEC_REG_BASE,
-       /* h264 encoder */
-       VENC_SYS = NUM_MAX_VDEC_REG_BASE,
-       /* vp8 encoder */
-       VENC_LT_SYS,
-       NUM_MAX_VCODEC_REG_BASE
-};
-
-/*
- * enum mtk_instance_type - The type of an MTK Vcodec instance.
- */
-enum mtk_instance_type {
-       MTK_INST_DECODER                = 0,
-       MTK_INST_ENCODER                = 1,
-};
-
-/**
- * enum mtk_instance_state - The state of an MTK Vcodec instance.
- * @MTK_STATE_FREE: default state when instance is created
- * @MTK_STATE_INIT: vcodec instance is initialized
- * @MTK_STATE_HEADER: vdec had sps/pps header parsed or venc
- *                     had sps/pps header encoded
- * @MTK_STATE_FLUSH: vdec is flushing. Only used by decoder
- * @MTK_STATE_ABORT: vcodec should be aborted
- */
-enum mtk_instance_state {
-       MTK_STATE_FREE = 0,
-       MTK_STATE_INIT = 1,
-       MTK_STATE_HEADER = 2,
-       MTK_STATE_FLUSH = 3,
-       MTK_STATE_ABORT = 4,
-};
-
-/*
- * enum mtk_encode_param - General encoding parameters type
- */
-enum mtk_encode_param {
-       MTK_ENCODE_PARAM_NONE = 0,
-       MTK_ENCODE_PARAM_BITRATE = (1 << 0),
-       MTK_ENCODE_PARAM_FRAMERATE = (1 << 1),
-       MTK_ENCODE_PARAM_INTRA_PERIOD = (1 << 2),
-       MTK_ENCODE_PARAM_FORCE_INTRA = (1 << 3),
-       MTK_ENCODE_PARAM_GOP_SIZE = (1 << 4),
-};
-
-enum mtk_fmt_type {
-       MTK_FMT_DEC = 0,
-       MTK_FMT_ENC = 1,
-       MTK_FMT_FRAME = 2,
-};
-
-/*
- * enum mtk_vdec_hw_id - Hardware index used to separate
- *                         different hardware
- */
-enum mtk_vdec_hw_id {
-       MTK_VDEC_CORE,
-       MTK_VDEC_LAT0,
-       MTK_VDEC_LAT1,
-       MTK_VDEC_HW_MAX,
-};
-
-/*
- * enum mtk_vdec_hw_count - Supported hardware count
- */
-enum mtk_vdec_hw_count {
-       MTK_VDEC_NO_HW = 0,
-       MTK_VDEC_ONE_CORE,
-       MTK_VDEC_ONE_LAT_ONE_CORE,
-       MTK_VDEC_MAX_HW_COUNT,
-};
-
-/*
- * struct mtk_video_fmt - Structure used to store information about pixelformats
- */
-struct mtk_video_fmt {
-       u32     fourcc;
-       enum mtk_fmt_type       type;
-       u32     num_planes;
-       u32     flags;
-};
-
-/*
- * struct mtk_codec_framesizes - Structure used to store information about
- *                                                     framesizes
- */
-struct mtk_codec_framesizes {
-       u32     fourcc;
-       struct  v4l2_frmsize_stepwise   stepwise;
-};
-
-/*
- * enum mtk_q_type - Type of queue
- */
-enum mtk_q_type {
-       MTK_Q_DATA_SRC = 0,
-       MTK_Q_DATA_DST = 1,
-};
-
-/*
- * struct mtk_q_data - Structure used to store information about queue
- */
-struct mtk_q_data {
-       unsigned int    visible_width;
-       unsigned int    visible_height;
-       unsigned int    coded_width;
-       unsigned int    coded_height;
-       enum v4l2_field field;
-       unsigned int    bytesperline[MTK_VCODEC_MAX_PLANES];
-       unsigned int    sizeimage[MTK_VCODEC_MAX_PLANES];
-       const struct mtk_video_fmt      *fmt;
-};
-
-/**
- * struct mtk_enc_params - General encoding parameters
- * @bitrate: target bitrate in bits per second
- * @num_b_frame: number of b frames between p-frame
- * @rc_frame: frame based rate control
- * @rc_mb: macroblock based rate control
- * @seq_hdr_mode: H.264 sequence header is encoded separately or joined
- *               with the first frame
- * @intra_period: I frame period
- * @gop_size: group of picture size, it's used as the intra frame period
- * @framerate_num: frame rate numerator. ex: framerate_num=30 and
- *                framerate_denom=1 means FPS is 30
- * @framerate_denom: frame rate denominator. ex: framerate_num=30 and
- *                  framerate_denom=1 means FPS is 30
- * @h264_max_qp: Max value for H.264 quantization parameter
- * @h264_profile: V4L2 defined H.264 profile
- * @h264_level: V4L2 defined H.264 level
- * @force_intra: force/insert intra frame
- */
-struct mtk_enc_params {
-       unsigned int    bitrate;
-       unsigned int    num_b_frame;
-       unsigned int    rc_frame;
-       unsigned int    rc_mb;
-       unsigned int    seq_hdr_mode;
-       unsigned int    intra_period;
-       unsigned int    gop_size;
-       unsigned int    framerate_num;
-       unsigned int    framerate_denom;
-       unsigned int    h264_max_qp;
-       unsigned int    h264_profile;
-       unsigned int    h264_level;
-       unsigned int    force_intra;
-};
-
-/*
- * struct mtk_vcodec_clk_info - Structure used to store clock name
- */
-struct mtk_vcodec_clk_info {
-       const char      *clk_name;
-       struct clk      *vcodec_clk;
-};
-
-/*
- * struct mtk_vcodec_clk - Structure used to store vcodec clock information
- */
-struct mtk_vcodec_clk {
-       struct mtk_vcodec_clk_info      *clk_info;
-       int     clk_num;
-};
-
-/*
- * struct mtk_vcodec_pm - Power management data structure
- */
-struct mtk_vcodec_pm {
-       struct mtk_vcodec_clk   vdec_clk;
-       struct mtk_vcodec_clk   venc_clk;
-       struct device   *dev;
-};
-
-/**
- * struct vdec_pic_info  - picture size information
- * @pic_w: picture width
- * @pic_h: picture height
- * @buf_w: picture buffer width (64 aligned up from pic_w)
- * @buf_h: picture buffer heiht (64 aligned up from pic_h)
- * @fb_sz: bitstream size of each plane
- * E.g. suppose picture size is 176x144,
- *      buffer size will be aligned to 176x160.
- * @cap_fourcc: fourcc number(may changed when resolution change)
- * @reserved: align struct to 64-bit in order to adjust 32-bit and 64-bit os.
- */
-struct vdec_pic_info {
-       unsigned int pic_w;
-       unsigned int pic_h;
-       unsigned int buf_w;
-       unsigned int buf_h;
-       unsigned int fb_sz[VIDEO_MAX_PLANES];
-       unsigned int cap_fourcc;
-       unsigned int reserved;
-};
-
-/**
- * struct mtk_vcodec_ctx - Context (instance) private data.
- *
- * @type: type of the instance - decoder or encoder
- * @dev: pointer to the mtk_vcodec_dev of the device
- * @list: link to ctx_list of mtk_vcodec_dev
- * @fh: struct v4l2_fh
- * @m2m_ctx: pointer to the v4l2_m2m_ctx of the context
- * @q_data: store information of input and output queue
- *         of the context
- * @id: index of the context that this structure describes
- * @state: state of the context
- * @param_change: indicate encode parameter type
- * @enc_params: encoding parameters
- * @dec_if: hooked decoder driver interface
- * @enc_if: hoooked encoder driver interface
- * @drv_handle: driver handle for specific decode/encode instance
- *
- * @picinfo: store picture info after header parsing
- * @dpb_size: store dpb count after header parsing
- * @int_cond: variable used by the waitqueue
- * @int_type: type of the last interrupt
- * @queue: waitqueue that can be used to wait for this context to
- *        finish
- * @irq_status: irq status
- *
- * @ctrl_hdl: handler for v4l2 framework
- * @decode_work: worker for the decoding
- * @encode_work: worker for the encoding
- * @last_decoded_picinfo: pic information get from latest decode
- * @empty_flush_buf: a fake size-0 capture buffer that indicates flush. Only
- *                  to be used with encoder and stateful decoder.
- * @is_flushing: set to true if flushing is in progress.
- * @current_codec: current set input codec, in V4L2 pixel format
- *
- * @colorspace: enum v4l2_colorspace; supplemental to pixelformat
- * @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding
- * @quantization: enum v4l2_quantization, colorspace quantization
- * @xfer_func: enum v4l2_xfer_func, colorspace transfer function
- * @decoded_frame_cnt: number of decoded frames
- * @lock: protect variables accessed by V4L2 threads and worker thread such as
- *       mtk_video_dec_buf.
- * @hw_id: hardware index used to identify different hardware.
- *
- * @msg_queue: msg queue used to store lat buffer information.
- */
-struct mtk_vcodec_ctx {
-       enum mtk_instance_type type;
-       struct mtk_vcodec_dev *dev;
-       struct list_head list;
-
-       struct v4l2_fh fh;
-       struct v4l2_m2m_ctx *m2m_ctx;
-       struct mtk_q_data q_data[2];
-       int id;
-       enum mtk_instance_state state;
-       enum mtk_encode_param param_change;
-       struct mtk_enc_params enc_params;
-
-       const struct vdec_common_if *dec_if;
-       const struct venc_common_if *enc_if;
-       void *drv_handle;
-
-       struct vdec_pic_info picinfo;
-       int dpb_size;
-
-       int int_cond[MTK_VDEC_HW_MAX];
-       int int_type[MTK_VDEC_HW_MAX];
-       wait_queue_head_t queue[MTK_VDEC_HW_MAX];
-       unsigned int irq_status;
-
-       struct v4l2_ctrl_handler ctrl_hdl;
-       struct work_struct decode_work;
-       struct work_struct encode_work;
-       struct vdec_pic_info last_decoded_picinfo;
-       struct v4l2_m2m_buffer empty_flush_buf;
-       bool is_flushing;
-
-       u32 current_codec;
-
-       enum v4l2_colorspace colorspace;
-       enum v4l2_ycbcr_encoding ycbcr_enc;
-       enum v4l2_quantization quantization;
-       enum v4l2_xfer_func xfer_func;
-
-       int decoded_frame_cnt;
-       struct mutex lock;
-       int hw_id;
-
-       struct vdec_msg_queue msg_queue;
-};
-
-enum mtk_chip {
-       MTK_MT8173,
-       MTK_MT8183,
-       MTK_MT8192,
-       MTK_MT8195,
-};
-
-/*
- * enum mtk_vdec_hw_arch - Used to separate different hardware architecture
- */
-enum mtk_vdec_hw_arch {
-       MTK_VDEC_PURE_SINGLE_CORE,
-       MTK_VDEC_LAT_SINGLE_CORE,
-};
-
-/**
- * struct mtk_vcodec_dec_pdata - compatible data for each IC
- * @init_vdec_params: init vdec params
- * @ctrls_setup: init vcodec dec ctrls
- * @worker: worker to start a decode job
- * @flush_decoder: function that flushes the decoder
- *
- * @vdec_vb2_ops: struct vb2_ops
- *
- * @vdec_formats: supported video decoder formats
- * @num_formats: count of video decoder formats
- * @default_out_fmt: default output buffer format
- * @default_cap_fmt: default capture buffer format
- *
- * @vdec_framesizes: supported video decoder frame sizes
- * @num_framesizes: count of video decoder frame sizes
- *
- * @chip: chip this decoder is compatible with
- * @hw_arch: hardware arch is used to separate pure_sin_core and lat_sin_core
- *
- * @is_subdev_supported: whether support parent-node architecture(subdev)
- * @uses_stateless_api: whether the decoder uses the stateless API with requests
- */
-
-struct mtk_vcodec_dec_pdata {
-       void (*init_vdec_params)(struct mtk_vcodec_ctx *ctx);
-       int (*ctrls_setup)(struct mtk_vcodec_ctx *ctx);
-       void (*worker)(struct work_struct *work);
-       int (*flush_decoder)(struct mtk_vcodec_ctx *ctx);
-
-       struct vb2_ops *vdec_vb2_ops;
-
-       const struct mtk_video_fmt *vdec_formats;
-       const int num_formats;
-       const struct mtk_video_fmt *default_out_fmt;
-       const struct mtk_video_fmt *default_cap_fmt;
-
-       const struct mtk_codec_framesizes *vdec_framesizes;
-       const int num_framesizes;
-
-       enum mtk_chip chip;
-       enum mtk_vdec_hw_arch hw_arch;
-
-       bool is_subdev_supported;
-       bool uses_stateless_api;
-};
-
-/**
- * struct mtk_vcodec_enc_pdata - compatible data for each IC
- *
- * @chip: chip this encoder is compatible with
- *
- * @uses_ext: whether the encoder uses the extended firmware messaging format
- * @min_bitrate: minimum supported encoding bitrate
- * @max_bitrate: maximum supported encoding bitrate
- * @capture_formats: array of supported capture formats
- * @num_capture_formats: number of entries in capture_formats
- * @output_formats: array of supported output formats
- * @num_output_formats: number of entries in output_formats
- * @core_id: stand for h264 or vp8 encode index
- */
-struct mtk_vcodec_enc_pdata {
-       enum mtk_chip chip;
-
-       bool uses_ext;
-       unsigned long min_bitrate;
-       unsigned long max_bitrate;
-       const struct mtk_video_fmt *capture_formats;
-       size_t num_capture_formats;
-       const struct mtk_video_fmt *output_formats;
-       size_t num_output_formats;
-       int core_id;
-};
-
-#define MTK_ENC_CTX_IS_EXT(ctx) ((ctx)->dev->venc_pdata->uses_ext)
-
-/**
- * struct mtk_vcodec_dev - driver data
- * @v4l2_dev: V4L2 device to register video devices for.
- * @vfd_dec: Video device for decoder
- * @mdev_dec: Media device for decoder
- * @vfd_enc: Video device for encoder.
- *
- * @m2m_dev_dec: m2m device for decoder
- * @m2m_dev_enc: m2m device for encoder.
- * @plat_dev: platform device
- * @ctx_list: list of struct mtk_vcodec_ctx
- * @irqlock: protect data access by irq handler and work thread
- * @curr_ctx: The context that is waiting for codec hardware
- *
- * @reg_base: Mapped address of MTK Vcodec registers.
- * @vdec_pdata: decoder IC-specific data
- * @venc_pdata: encoder IC-specific data
- *
- * @fw_handler: used to communicate with the firmware.
- * @id_counter: used to identify current opened instance
- *
- * @decode_workqueue: decode work queue
- * @encode_workqueue: encode work queue
- *
- * @int_cond: used to identify interrupt condition happen
- * @int_type: used to identify what kind of interrupt condition happen
- * @dev_mutex: video_device lock
- * @queue: waitqueue for waiting for completion of device commands
- *
- * @dec_irq: decoder irq resource
- * @enc_irq: h264 encoder irq resource
- *
- * @dec_mutex: decoder hardware lock
- * @enc_mutex: encoder hardware lock.
- *
- * @pm: power management control
- * @dec_capability: used to identify decode capability, ex: 4k
- * @enc_capability: used to identify encode capability
- *
- * @core_workqueue: queue used for core hardware decode
- * @msg_queue_core_ctx: msg queue context used for core workqueue
- *
- * @subdev_dev: subdev hardware device
- * @subdev_prob_done: check whether all used hw device is prob done
- * @subdev_bitmap: used to record hardware is ready or not
- */
-struct mtk_vcodec_dev {
-       struct v4l2_device v4l2_dev;
-       struct video_device *vfd_dec;
-       struct media_device mdev_dec;
-       struct video_device *vfd_enc;
-
-       struct v4l2_m2m_dev *m2m_dev_dec;
-       struct v4l2_m2m_dev *m2m_dev_enc;
-       struct platform_device *plat_dev;
-       struct list_head ctx_list;
-       spinlock_t irqlock;
-       struct mtk_vcodec_ctx *curr_ctx;
-       void __iomem *reg_base[NUM_MAX_VCODEC_REG_BASE];
-       const struct mtk_vcodec_dec_pdata *vdec_pdata;
-       const struct mtk_vcodec_enc_pdata *venc_pdata;
-
-       struct mtk_vcodec_fw *fw_handler;
-
-       unsigned long id_counter;
-
-       struct workqueue_struct *decode_workqueue;
-       struct workqueue_struct *encode_workqueue;
-       int int_cond;
-       int int_type;
-       struct mutex dev_mutex;
-       wait_queue_head_t queue;
-
-       int dec_irq;
-       int enc_irq;
-
-       /* decoder hardware mutex lock */
-       struct mutex dec_mutex[MTK_VDEC_HW_MAX];
-       struct mutex enc_mutex;
-
-       struct mtk_vcodec_pm pm;
-       unsigned int dec_capability;
-       unsigned int enc_capability;
-
-       struct workqueue_struct *core_workqueue;
-       struct vdec_msg_queue_ctx msg_queue_core_ctx;
-
-       void *subdev_dev[MTK_VDEC_HW_MAX];
-       int (*subdev_prob_done)(struct mtk_vcodec_dev *vdec_dev);
-       DECLARE_BITMAP(subdev_bitmap, MTK_VDEC_HW_MAX);
-};
-
-static inline struct mtk_vcodec_ctx *fh_to_ctx(struct v4l2_fh *fh)
-{
-       return container_of(fh, struct mtk_vcodec_ctx, fh);
-}
-
-static inline struct mtk_vcodec_ctx *ctrl_to_ctx(struct v4l2_ctrl *ctrl)
-{
-       return container_of(ctrl->handler, struct mtk_vcodec_ctx, ctrl_hdl);
-}
-
-/* Wake up context wait_queue */
-static inline void
-wake_up_ctx(struct mtk_vcodec_ctx *ctx, unsigned int reason, unsigned int hw_id)
-{
-       ctx->int_cond[hw_id] = 1;
-       ctx->int_type[hw_id] = reason;
-       wake_up_interruptible(&ctx->queue[hw_id]);
-}
-
-#endif /* _MTK_VCODEC_DRV_H_ */
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
deleted file mode 100644 (file)
index c213670..0000000
+++ /dev/null
@@ -1,1451 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
-* Copyright (c) 2016 MediaTek Inc.
-* Author: PC Chen <pc.chen@mediatek.com>
-*         Tiffany Lin <tiffany.lin@mediatek.com>
-*/
-
-#include <media/v4l2-event.h>
-#include <media/v4l2-mem2mem.h>
-#include <media/videobuf2-dma-contig.h>
-#include <linux/pm_runtime.h>
-
-#include "mtk_vcodec_drv.h"
-#include "mtk_vcodec_enc.h"
-#include "mtk_vcodec_intr.h"
-#include "mtk_vcodec_util.h"
-#include "venc_drv_if.h"
-
-#define MTK_VENC_MIN_W 160U
-#define MTK_VENC_MIN_H 128U
-#define MTK_VENC_HD_MAX_W      1920U
-#define MTK_VENC_HD_MAX_H      1088U
-#define MTK_VENC_4K_MAX_W      3840U
-#define MTK_VENC_4K_MAX_H      2176U
-
-#define DFT_CFG_WIDTH  MTK_VENC_MIN_W
-#define DFT_CFG_HEIGHT MTK_VENC_MIN_H
-#define MTK_MAX_CTRLS_HINT     20
-
-#define MTK_DEFAULT_FRAMERATE_NUM 1001
-#define MTK_DEFAULT_FRAMERATE_DENOM 30000
-#define MTK_VENC_4K_CAPABILITY_ENABLE BIT(0)
-
-static void mtk_venc_worker(struct work_struct *work);
-
-static const struct v4l2_frmsize_stepwise mtk_venc_hd_framesizes = {
-       MTK_VENC_MIN_W, MTK_VENC_HD_MAX_W, 16,
-       MTK_VENC_MIN_H, MTK_VENC_HD_MAX_H, 16,
-};
-
-static const struct v4l2_frmsize_stepwise mtk_venc_4k_framesizes = {
-       MTK_VENC_MIN_W, MTK_VENC_4K_MAX_W, 16,
-       MTK_VENC_MIN_H, MTK_VENC_4K_MAX_H, 16,
-};
-
-static int vidioc_venc_s_ctrl(struct v4l2_ctrl *ctrl)
-{
-       struct mtk_vcodec_ctx *ctx = ctrl_to_ctx(ctrl);
-       struct mtk_enc_params *p = &ctx->enc_params;
-       int ret = 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_MPEG_VIDEO_BITRATE:
-               mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_BITRATE val = %d",
-                              ctrl->val);
-               p->bitrate = ctrl->val;
-               ctx->param_change |= MTK_ENCODE_PARAM_BITRATE;
-               break;
-       case V4L2_CID_MPEG_VIDEO_B_FRAMES:
-               mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_B_FRAMES val = %d",
-                              ctrl->val);
-               p->num_b_frame = ctrl->val;
-               break;
-       case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE:
-               mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE val = %d",
-                              ctrl->val);
-               p->rc_frame = ctrl->val;
-               break;
-       case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
-               mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_H264_MAX_QP val = %d",
-                              ctrl->val);
-               p->h264_max_qp = ctrl->val;
-               break;
-       case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
-               mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_HEADER_MODE val = %d",
-                              ctrl->val);
-               p->seq_hdr_mode = ctrl->val;
-               break;
-       case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE:
-               mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE val = %d",
-                              ctrl->val);
-               p->rc_mb = ctrl->val;
-               break;
-       case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
-               mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_H264_PROFILE val = %d",
-                              ctrl->val);
-               p->h264_profile = ctrl->val;
-               break;
-       case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
-               mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_H264_LEVEL val = %d",
-                              ctrl->val);
-               p->h264_level = ctrl->val;
-               break;
-       case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD:
-               mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_H264_I_PERIOD val = %d",
-                              ctrl->val);
-               p->intra_period = ctrl->val;
-               ctx->param_change |= MTK_ENCODE_PARAM_INTRA_PERIOD;
-               break;
-       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
-               mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_GOP_SIZE val = %d",
-                              ctrl->val);
-               p->gop_size = ctrl->val;
-               ctx->param_change |= MTK_ENCODE_PARAM_GOP_SIZE;
-               break;
-       case V4L2_CID_MPEG_VIDEO_VP8_PROFILE:
-               /*
-                * FIXME - what vp8 profiles are actually supported?
-                * The ctrl is added (with only profile 0 supported) for now.
-                */
-               mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_VP8_PROFILE val = %d", ctrl->val);
-               break;
-       case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME:
-               mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME");
-               p->force_intra = 1;
-               ctx->param_change |= MTK_ENCODE_PARAM_FORCE_INTRA;
-               break;
-       default:
-               ret = -EINVAL;
-               break;
-       }
-
-       return ret;
-}
-
-static const struct v4l2_ctrl_ops mtk_vcodec_enc_ctrl_ops = {
-       .s_ctrl = vidioc_venc_s_ctrl,
-};
-
-static int vidioc_enum_fmt(struct v4l2_fmtdesc *f,
-                          const struct mtk_video_fmt *formats,
-                          size_t num_formats)
-{
-       if (f->index >= num_formats)
-               return -EINVAL;
-
-       f->pixelformat = formats[f->index].fourcc;
-
-       return 0;
-}
-
-static const struct mtk_video_fmt *
-mtk_venc_find_format(u32 fourcc, const struct mtk_vcodec_enc_pdata *pdata)
-{
-       const struct mtk_video_fmt *fmt;
-       unsigned int k;
-
-       for (k = 0; k < pdata->num_capture_formats; k++) {
-               fmt = &pdata->capture_formats[k];
-               if (fmt->fourcc == fourcc)
-                       return fmt;
-       }
-
-       for (k = 0; k < pdata->num_output_formats; k++) {
-               fmt = &pdata->output_formats[k];
-               if (fmt->fourcc == fourcc)
-                       return fmt;
-       }
-
-       return NULL;
-}
-
-static int vidioc_enum_framesizes(struct file *file, void *fh,
-                                 struct v4l2_frmsizeenum *fsize)
-{
-       const struct mtk_video_fmt *fmt;
-       struct mtk_vcodec_ctx *ctx = fh_to_ctx(fh);
-
-       if (fsize->index != 0)
-               return -EINVAL;
-
-       fmt = mtk_venc_find_format(fsize->pixel_format,
-                                  ctx->dev->venc_pdata);
-       if (!fmt)
-               return -EINVAL;
-
-       fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
-
-       if (ctx->dev->enc_capability & MTK_VENC_4K_CAPABILITY_ENABLE)
-               fsize->stepwise = mtk_venc_4k_framesizes;
-       else
-               fsize->stepwise = mtk_venc_hd_framesizes;
-
-       return 0;
-}
-
-static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
-                                  struct v4l2_fmtdesc *f)
-{
-       const struct mtk_vcodec_enc_pdata *pdata =
-               fh_to_ctx(priv)->dev->venc_pdata;
-
-       return vidioc_enum_fmt(f, pdata->capture_formats,
-                              pdata->num_capture_formats);
-}
-
-static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
-                                  struct v4l2_fmtdesc *f)
-{
-       const struct mtk_vcodec_enc_pdata *pdata =
-               fh_to_ctx(priv)->dev->venc_pdata;
-
-       return vidioc_enum_fmt(f, pdata->output_formats,
-                              pdata->num_output_formats);
-}
-
-static int vidioc_venc_querycap(struct file *file, void *priv,
-                               struct v4l2_capability *cap)
-{
-       strscpy(cap->driver, MTK_VCODEC_ENC_NAME, sizeof(cap->driver));
-       strscpy(cap->bus_info, MTK_PLATFORM_STR, sizeof(cap->bus_info));
-       strscpy(cap->card, MTK_PLATFORM_STR, sizeof(cap->card));
-
-       return 0;
-}
-
-static int vidioc_venc_s_parm(struct file *file, void *priv,
-                             struct v4l2_streamparm *a)
-{
-       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
-       struct v4l2_fract *timeperframe = &a->parm.output.timeperframe;
-
-       if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
-               return -EINVAL;
-
-       if (timeperframe->numerator == 0 || timeperframe->denominator == 0) {
-               timeperframe->numerator = MTK_DEFAULT_FRAMERATE_NUM;
-               timeperframe->denominator = MTK_DEFAULT_FRAMERATE_DENOM;
-       }
-
-       ctx->enc_params.framerate_num = timeperframe->denominator;
-       ctx->enc_params.framerate_denom = timeperframe->numerator;
-       ctx->param_change |= MTK_ENCODE_PARAM_FRAMERATE;
-
-       a->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
-
-       return 0;
-}
-
-static int vidioc_venc_g_parm(struct file *file, void *priv,
-                             struct v4l2_streamparm *a)
-{
-       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
-
-       if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
-               return -EINVAL;
-
-       a->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
-       a->parm.output.timeperframe.denominator =
-                       ctx->enc_params.framerate_num;
-       a->parm.output.timeperframe.numerator =
-                       ctx->enc_params.framerate_denom;
-
-       return 0;
-}
-
-static struct mtk_q_data *mtk_venc_get_q_data(struct mtk_vcodec_ctx *ctx,
-                                             enum v4l2_buf_type type)
-{
-       if (V4L2_TYPE_IS_OUTPUT(type))
-               return &ctx->q_data[MTK_Q_DATA_SRC];
-
-       return &ctx->q_data[MTK_Q_DATA_DST];
-}
-
-static void vidioc_try_fmt_cap(struct v4l2_format *f)
-{
-       f->fmt.pix_mp.field = V4L2_FIELD_NONE;
-       f->fmt.pix_mp.num_planes = 1;
-       f->fmt.pix_mp.plane_fmt[0].bytesperline = 0;
-       f->fmt.pix_mp.flags = 0;
-}
-
-/* V4L2 specification suggests the driver corrects the format struct if any of
- * the dimensions is unsupported
- */
-static int vidioc_try_fmt_out(struct mtk_vcodec_ctx *ctx, struct v4l2_format *f,
-                             const struct mtk_video_fmt *fmt)
-{
-       struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
-       int tmp_w, tmp_h;
-       unsigned int max_width, max_height;
-
-       pix_fmt_mp->field = V4L2_FIELD_NONE;
-
-       if (ctx->dev->enc_capability & MTK_VENC_4K_CAPABILITY_ENABLE) {
-               max_width = MTK_VENC_4K_MAX_W;
-               max_height = MTK_VENC_4K_MAX_H;
-       } else {
-               max_width = MTK_VENC_HD_MAX_W;
-               max_height = MTK_VENC_HD_MAX_H;
-       }
-
-       pix_fmt_mp->height = clamp(pix_fmt_mp->height, MTK_VENC_MIN_H, max_height);
-       pix_fmt_mp->width = clamp(pix_fmt_mp->width, MTK_VENC_MIN_W, max_width);
-
-       /* find next closer width align 16, heign align 32, size align
-        * 64 rectangle
-        */
-       tmp_w = pix_fmt_mp->width;
-       tmp_h = pix_fmt_mp->height;
-       v4l_bound_align_image(&pix_fmt_mp->width,
-                             MTK_VENC_MIN_W,
-                             max_width, 4,
-                             &pix_fmt_mp->height,
-                             MTK_VENC_MIN_H,
-                             max_height, 5, 6);
-
-       if (pix_fmt_mp->width < tmp_w && (pix_fmt_mp->width + 16) <= max_width)
-               pix_fmt_mp->width += 16;
-       if (pix_fmt_mp->height < tmp_h && (pix_fmt_mp->height + 32) <= max_height)
-               pix_fmt_mp->height += 32;
-
-       mtk_v4l2_debug(0, "before resize w=%d, h=%d, after resize w=%d, h=%d, sizeimage=%d %d",
-                      tmp_w, tmp_h, pix_fmt_mp->width,
-                      pix_fmt_mp->height,
-                      pix_fmt_mp->plane_fmt[0].sizeimage,
-                      pix_fmt_mp->plane_fmt[1].sizeimage);
-
-       pix_fmt_mp->num_planes = fmt->num_planes;
-       pix_fmt_mp->plane_fmt[0].sizeimage =
-                       pix_fmt_mp->width * pix_fmt_mp->height +
-                       ((ALIGN(pix_fmt_mp->width, 16) * 2) * 16);
-       pix_fmt_mp->plane_fmt[0].bytesperline = pix_fmt_mp->width;
-
-       if (pix_fmt_mp->num_planes == 2) {
-               pix_fmt_mp->plane_fmt[1].sizeimage =
-                       (pix_fmt_mp->width * pix_fmt_mp->height) / 2 +
-                       (ALIGN(pix_fmt_mp->width, 16) * 16);
-               pix_fmt_mp->plane_fmt[2].sizeimage = 0;
-               pix_fmt_mp->plane_fmt[1].bytesperline =
-                                               pix_fmt_mp->width;
-               pix_fmt_mp->plane_fmt[2].bytesperline = 0;
-       } else if (pix_fmt_mp->num_planes == 3) {
-               pix_fmt_mp->plane_fmt[1].sizeimage =
-               pix_fmt_mp->plane_fmt[2].sizeimage =
-                       (pix_fmt_mp->width * pix_fmt_mp->height) / 4 +
-                       ((ALIGN(pix_fmt_mp->width, 16) / 2) * 16);
-               pix_fmt_mp->plane_fmt[1].bytesperline =
-                       pix_fmt_mp->plane_fmt[2].bytesperline =
-                       pix_fmt_mp->width / 2;
-       }
-
-       pix_fmt_mp->flags = 0;
-
-       return 0;
-}
-
-static void mtk_venc_set_param(struct mtk_vcodec_ctx *ctx,
-                               struct venc_enc_param *param)
-{
-       struct mtk_q_data *q_data_src = &ctx->q_data[MTK_Q_DATA_SRC];
-       struct mtk_enc_params *enc_params = &ctx->enc_params;
-
-       switch (q_data_src->fmt->fourcc) {
-       case V4L2_PIX_FMT_YUV420M:
-               param->input_yuv_fmt = VENC_YUV_FORMAT_I420;
-               break;
-       case V4L2_PIX_FMT_YVU420M:
-               param->input_yuv_fmt = VENC_YUV_FORMAT_YV12;
-               break;
-       case V4L2_PIX_FMT_NV12M:
-               param->input_yuv_fmt = VENC_YUV_FORMAT_NV12;
-               break;
-       case V4L2_PIX_FMT_NV21M:
-               param->input_yuv_fmt = VENC_YUV_FORMAT_NV21;
-               break;
-       default:
-               mtk_v4l2_err("Unsupported fourcc =%d", q_data_src->fmt->fourcc);
-               break;
-       }
-       param->h264_profile = enc_params->h264_profile;
-       param->h264_level = enc_params->h264_level;
-
-       /* Config visible resolution */
-       param->width = q_data_src->visible_width;
-       param->height = q_data_src->visible_height;
-       /* Config coded resolution */
-       param->buf_width = q_data_src->coded_width;
-       param->buf_height = q_data_src->coded_height;
-       param->frm_rate = enc_params->framerate_num /
-                       enc_params->framerate_denom;
-       param->intra_period = enc_params->intra_period;
-       param->gop_size = enc_params->gop_size;
-       param->bitrate = enc_params->bitrate;
-
-       mtk_v4l2_debug(0,
-               "fmt 0x%x, P/L %d/%d, w/h %d/%d, buf %d/%d, fps/bps %d/%d, gop %d, i_period %d",
-               param->input_yuv_fmt, param->h264_profile,
-               param->h264_level, param->width, param->height,
-               param->buf_width, param->buf_height,
-               param->frm_rate, param->bitrate,
-               param->gop_size, param->intra_period);
-}
-
-static int vidioc_venc_s_fmt_cap(struct file *file, void *priv,
-                            struct v4l2_format *f)
-{
-       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
-       const struct mtk_vcodec_enc_pdata *pdata = ctx->dev->venc_pdata;
-       struct vb2_queue *vq;
-       struct mtk_q_data *q_data = mtk_venc_get_q_data(ctx, f->type);
-       int i, ret;
-       const struct mtk_video_fmt *fmt;
-
-       vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
-       if (!vq) {
-               mtk_v4l2_err("fail to get vq");
-               return -EINVAL;
-       }
-
-       if (vb2_is_busy(vq)) {
-               mtk_v4l2_err("queue busy");
-               return -EBUSY;
-       }
-
-       fmt = mtk_venc_find_format(f->fmt.pix.pixelformat, pdata);
-       if (!fmt) {
-               fmt = &ctx->dev->venc_pdata->capture_formats[0];
-               f->fmt.pix.pixelformat = fmt->fourcc;
-       }
-
-       q_data->fmt = fmt;
-       vidioc_try_fmt_cap(f);
-
-       q_data->coded_width = f->fmt.pix_mp.width;
-       q_data->coded_height = f->fmt.pix_mp.height;
-       q_data->field = f->fmt.pix_mp.field;
-
-       for (i = 0; i < f->fmt.pix_mp.num_planes; i++) {
-               struct v4l2_plane_pix_format    *plane_fmt;
-
-               plane_fmt = &f->fmt.pix_mp.plane_fmt[i];
-               q_data->bytesperline[i] = plane_fmt->bytesperline;
-               q_data->sizeimage[i] = plane_fmt->sizeimage;
-       }
-
-       if (ctx->state == MTK_STATE_FREE) {
-               ret = venc_if_init(ctx, q_data->fmt->fourcc);
-               if (ret) {
-                       mtk_v4l2_err("venc_if_init failed=%d, codec type=%x",
-                                       ret, q_data->fmt->fourcc);
-                       return -EBUSY;
-               }
-               ctx->state = MTK_STATE_INIT;
-       }
-
-       return 0;
-}
-
-static int vidioc_venc_s_fmt_out(struct file *file, void *priv,
-                            struct v4l2_format *f)
-{
-       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
-       const struct mtk_vcodec_enc_pdata *pdata = ctx->dev->venc_pdata;
-       struct vb2_queue *vq;
-       struct mtk_q_data *q_data = mtk_venc_get_q_data(ctx, f->type);
-       int ret, i;
-       const struct mtk_video_fmt *fmt;
-
-       vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
-       if (!vq) {
-               mtk_v4l2_err("fail to get vq");
-               return -EINVAL;
-       }
-
-       if (vb2_is_busy(vq)) {
-               mtk_v4l2_err("queue busy");
-               return -EBUSY;
-       }
-
-       fmt = mtk_venc_find_format(f->fmt.pix.pixelformat, pdata);
-       if (!fmt) {
-               fmt = &ctx->dev->venc_pdata->output_formats[0];
-               f->fmt.pix.pixelformat = fmt->fourcc;
-       }
-
-       ret = vidioc_try_fmt_out(ctx, f, fmt);
-       if (ret)
-               return ret;
-
-       q_data->fmt = fmt;
-       q_data->visible_width = f->fmt.pix_mp.width;
-       q_data->visible_height = f->fmt.pix_mp.height;
-       q_data->coded_width = f->fmt.pix_mp.width;
-       q_data->coded_height = f->fmt.pix_mp.height;
-
-       q_data->field = f->fmt.pix_mp.field;
-       ctx->colorspace = f->fmt.pix_mp.colorspace;
-       ctx->ycbcr_enc = f->fmt.pix_mp.ycbcr_enc;
-       ctx->quantization = f->fmt.pix_mp.quantization;
-       ctx->xfer_func = f->fmt.pix_mp.xfer_func;
-
-       for (i = 0; i < f->fmt.pix_mp.num_planes; i++) {
-               struct v4l2_plane_pix_format *plane_fmt;
-
-               plane_fmt = &f->fmt.pix_mp.plane_fmt[i];
-               q_data->bytesperline[i] = plane_fmt->bytesperline;
-               q_data->sizeimage[i] = plane_fmt->sizeimage;
-       }
-
-       return 0;
-}
-
-static int vidioc_venc_g_fmt(struct file *file, void *priv,
-                            struct v4l2_format *f)
-{
-       struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
-       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
-       struct vb2_queue *vq;
-       struct mtk_q_data *q_data = mtk_venc_get_q_data(ctx, f->type);
-       int i;
-
-       vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
-       if (!vq)
-               return -EINVAL;
-
-
-       pix->width = q_data->coded_width;
-       pix->height = q_data->coded_height;
-       pix->pixelformat = q_data->fmt->fourcc;
-       pix->field = q_data->field;
-       pix->num_planes = q_data->fmt->num_planes;
-       for (i = 0; i < pix->num_planes; i++) {
-               pix->plane_fmt[i].bytesperline = q_data->bytesperline[i];
-               pix->plane_fmt[i].sizeimage = q_data->sizeimage[i];
-       }
-
-       pix->flags = 0;
-       pix->colorspace = ctx->colorspace;
-       pix->ycbcr_enc = ctx->ycbcr_enc;
-       pix->quantization = ctx->quantization;
-       pix->xfer_func = ctx->xfer_func;
-
-       return 0;
-}
-
-static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv,
-                                        struct v4l2_format *f)
-{
-       const struct mtk_video_fmt *fmt;
-       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
-       const struct mtk_vcodec_enc_pdata *pdata = ctx->dev->venc_pdata;
-
-       fmt = mtk_venc_find_format(f->fmt.pix.pixelformat, pdata);
-       if (!fmt) {
-               fmt = &ctx->dev->venc_pdata->capture_formats[0];
-               f->fmt.pix.pixelformat = fmt->fourcc;
-       }
-       f->fmt.pix_mp.colorspace = ctx->colorspace;
-       f->fmt.pix_mp.ycbcr_enc = ctx->ycbcr_enc;
-       f->fmt.pix_mp.quantization = ctx->quantization;
-       f->fmt.pix_mp.xfer_func = ctx->xfer_func;
-
-       vidioc_try_fmt_cap(f);
-
-       return 0;
-}
-
-static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv,
-                                        struct v4l2_format *f)
-{
-       const struct mtk_video_fmt *fmt;
-       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
-       const struct mtk_vcodec_enc_pdata *pdata = ctx->dev->venc_pdata;
-
-       fmt = mtk_venc_find_format(f->fmt.pix.pixelformat, pdata);
-       if (!fmt) {
-               fmt = &ctx->dev->venc_pdata->output_formats[0];
-               f->fmt.pix.pixelformat = fmt->fourcc;
-       }
-       if (!f->fmt.pix_mp.colorspace) {
-               f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_REC709;
-               f->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
-               f->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT;
-               f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT;
-       }
-
-       return vidioc_try_fmt_out(ctx, f, fmt);
-}
-
-static int vidioc_venc_g_selection(struct file *file, void *priv,
-                                    struct v4l2_selection *s)
-{
-       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
-       struct mtk_q_data *q_data = mtk_venc_get_q_data(ctx, s->type);
-
-       if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
-               return -EINVAL;
-
-       switch (s->target) {
-       case V4L2_SEL_TGT_CROP_DEFAULT:
-       case V4L2_SEL_TGT_CROP_BOUNDS:
-               s->r.top = 0;
-               s->r.left = 0;
-               s->r.width = q_data->coded_width;
-               s->r.height = q_data->coded_height;
-               break;
-       case V4L2_SEL_TGT_CROP:
-               s->r.top = 0;
-               s->r.left = 0;
-               s->r.width = q_data->visible_width;
-               s->r.height = q_data->visible_height;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int vidioc_venc_s_selection(struct file *file, void *priv,
-                                    struct v4l2_selection *s)
-{
-       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
-       struct mtk_q_data *q_data = mtk_venc_get_q_data(ctx, s->type);
-
-       if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
-               return -EINVAL;
-
-       switch (s->target) {
-       case V4L2_SEL_TGT_CROP:
-               /* Only support crop from (0,0) */
-               s->r.top = 0;
-               s->r.left = 0;
-               s->r.width = min(s->r.width, q_data->coded_width);
-               s->r.height = min(s->r.height, q_data->coded_height);
-               q_data->visible_width = s->r.width;
-               q_data->visible_height = s->r.height;
-               break;
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
-
-static int vidioc_venc_qbuf(struct file *file, void *priv,
-                           struct v4l2_buffer *buf)
-{
-       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
-
-       if (ctx->state == MTK_STATE_ABORT) {
-               mtk_v4l2_err("[%d] Call on QBUF after unrecoverable error",
-                               ctx->id);
-               return -EIO;
-       }
-
-       return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
-}
-
-static int vidioc_venc_dqbuf(struct file *file, void *priv,
-                            struct v4l2_buffer *buf)
-{
-       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
-       int ret;
-
-       if (ctx->state == MTK_STATE_ABORT) {
-               mtk_v4l2_err("[%d] Call on QBUF after unrecoverable error",
-                               ctx->id);
-               return -EIO;
-       }
-
-       ret = v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
-       if (ret)
-               return ret;
-
-       /*
-        * Complete flush if the user dequeued the 0-payload LAST buffer.
-        * We check the payload because a buffer with the LAST flag can also
-        * be seen during resolution changes. If we happen to be flushing at
-        * that time, the last buffer before the resolution changes could be
-        * misinterpreted for the buffer generated by the flush and terminate
-        * it earlier than we want.
-        */
-       if (!V4L2_TYPE_IS_OUTPUT(buf->type) &&
-           buf->flags & V4L2_BUF_FLAG_LAST &&
-           buf->m.planes[0].bytesused == 0 &&
-           ctx->is_flushing) {
-               /*
-                * Last CAPTURE buffer is dequeued, we can allow another flush
-                * to take place.
-                */
-               ctx->is_flushing = false;
-       }
-
-       return 0;
-}
-
-static int vidioc_encoder_cmd(struct file *file, void *priv,
-                             struct v4l2_encoder_cmd *cmd)
-{
-       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
-       struct vb2_queue *src_vq, *dst_vq;
-       int ret;
-
-       if (ctx->state == MTK_STATE_ABORT) {
-               mtk_v4l2_err("[%d] Call to CMD after unrecoverable error",
-                            ctx->id);
-               return -EIO;
-       }
-
-       ret = v4l2_m2m_ioctl_try_encoder_cmd(file, priv, cmd);
-       if (ret)
-               return ret;
-
-       /* Calling START or STOP is invalid if a flush is in progress */
-       if (ctx->is_flushing)
-               return -EBUSY;
-
-       mtk_v4l2_debug(1, "encoder cmd=%u", cmd->cmd);
-
-       dst_vq = v4l2_m2m_get_vq(ctx->m2m_ctx,
-                                V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
-       switch (cmd->cmd) {
-       case V4L2_ENC_CMD_STOP:
-               src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx,
-                                        V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
-               if (!vb2_is_streaming(src_vq)) {
-                       mtk_v4l2_debug(1, "Output stream is off. No need to flush.");
-                       return 0;
-               }
-               if (!vb2_is_streaming(dst_vq)) {
-                       mtk_v4l2_debug(1, "Capture stream is off. No need to flush.");
-                       return 0;
-               }
-               ctx->is_flushing = true;
-               v4l2_m2m_buf_queue(ctx->m2m_ctx, &ctx->empty_flush_buf.vb);
-               v4l2_m2m_try_schedule(ctx->m2m_ctx);
-               break;
-
-       case V4L2_ENC_CMD_START:
-               vb2_clear_last_buffer_dequeued(dst_vq);
-               break;
-
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-const struct v4l2_ioctl_ops mtk_venc_ioctl_ops = {
-       .vidioc_streamon                = v4l2_m2m_ioctl_streamon,
-       .vidioc_streamoff               = v4l2_m2m_ioctl_streamoff,
-
-       .vidioc_reqbufs                 = v4l2_m2m_ioctl_reqbufs,
-       .vidioc_querybuf                = v4l2_m2m_ioctl_querybuf,
-       .vidioc_qbuf                    = vidioc_venc_qbuf,
-       .vidioc_dqbuf                   = vidioc_venc_dqbuf,
-
-       .vidioc_querycap                = vidioc_venc_querycap,
-       .vidioc_enum_fmt_vid_cap        = vidioc_enum_fmt_vid_cap,
-       .vidioc_enum_fmt_vid_out        = vidioc_enum_fmt_vid_out,
-       .vidioc_enum_framesizes         = vidioc_enum_framesizes,
-
-       .vidioc_try_fmt_vid_cap_mplane  = vidioc_try_fmt_vid_cap_mplane,
-       .vidioc_try_fmt_vid_out_mplane  = vidioc_try_fmt_vid_out_mplane,
-       .vidioc_expbuf                  = v4l2_m2m_ioctl_expbuf,
-       .vidioc_subscribe_event         = v4l2_ctrl_subscribe_event,
-       .vidioc_unsubscribe_event       = v4l2_event_unsubscribe,
-
-       .vidioc_s_parm                  = vidioc_venc_s_parm,
-       .vidioc_g_parm                  = vidioc_venc_g_parm,
-       .vidioc_s_fmt_vid_cap_mplane    = vidioc_venc_s_fmt_cap,
-       .vidioc_s_fmt_vid_out_mplane    = vidioc_venc_s_fmt_out,
-
-       .vidioc_g_fmt_vid_cap_mplane    = vidioc_venc_g_fmt,
-       .vidioc_g_fmt_vid_out_mplane    = vidioc_venc_g_fmt,
-
-       .vidioc_create_bufs             = v4l2_m2m_ioctl_create_bufs,
-       .vidioc_prepare_buf             = v4l2_m2m_ioctl_prepare_buf,
-
-       .vidioc_g_selection             = vidioc_venc_g_selection,
-       .vidioc_s_selection             = vidioc_venc_s_selection,
-
-       .vidioc_encoder_cmd             = vidioc_encoder_cmd,
-       .vidioc_try_encoder_cmd         = v4l2_m2m_ioctl_try_encoder_cmd,
-};
-
-static int vb2ops_venc_queue_setup(struct vb2_queue *vq,
-                                  unsigned int *nbuffers,
-                                  unsigned int *nplanes,
-                                  unsigned int sizes[],
-                                  struct device *alloc_devs[])
-{
-       struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vq);
-       struct mtk_q_data *q_data = mtk_venc_get_q_data(ctx, vq->type);
-       unsigned int i;
-
-       if (q_data == NULL)
-               return -EINVAL;
-
-       if (*nplanes) {
-               for (i = 0; i < *nplanes; i++)
-                       if (sizes[i] < q_data->sizeimage[i])
-                               return -EINVAL;
-       } else {
-               *nplanes = q_data->fmt->num_planes;
-               for (i = 0; i < *nplanes; i++)
-                       sizes[i] = q_data->sizeimage[i];
-       }
-
-       return 0;
-}
-
-static int vb2ops_venc_buf_prepare(struct vb2_buffer *vb)
-{
-       struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
-       struct mtk_q_data *q_data = mtk_venc_get_q_data(ctx, vb->vb2_queue->type);
-       int i;
-
-       for (i = 0; i < q_data->fmt->num_planes; i++) {
-               if (vb2_plane_size(vb, i) < q_data->sizeimage[i]) {
-                       mtk_v4l2_err("data will not fit into plane %d (%lu < %d)",
-                               i, vb2_plane_size(vb, i),
-                               q_data->sizeimage[i]);
-                       return -EINVAL;
-               }
-       }
-
-       return 0;
-}
-
-static void vb2ops_venc_buf_queue(struct vb2_buffer *vb)
-{
-       struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
-       struct vb2_v4l2_buffer *vb2_v4l2 =
-                       container_of(vb, struct vb2_v4l2_buffer, vb2_buf);
-
-       struct mtk_video_enc_buf *mtk_buf =
-                       container_of(vb2_v4l2, struct mtk_video_enc_buf,
-                                    m2m_buf.vb);
-
-       if ((vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) &&
-           (ctx->param_change != MTK_ENCODE_PARAM_NONE)) {
-               mtk_v4l2_debug(1, "[%d] Before id=%d encode parameter change %x",
-                              ctx->id,
-                              vb2_v4l2->vb2_buf.index,
-                              ctx->param_change);
-               mtk_buf->param_change = ctx->param_change;
-               mtk_buf->enc_params = ctx->enc_params;
-               ctx->param_change = MTK_ENCODE_PARAM_NONE;
-       }
-
-       v4l2_m2m_buf_queue(ctx->m2m_ctx, to_vb2_v4l2_buffer(vb));
-}
-
-static int vb2ops_venc_start_streaming(struct vb2_queue *q, unsigned int count)
-{
-       struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(q);
-       struct venc_enc_param param;
-       int ret, pm_ret;
-       int i;
-
-       /* Once state turn into MTK_STATE_ABORT, we need stop_streaming
-         * to clear it
-         */
-       if ((ctx->state == MTK_STATE_ABORT) || (ctx->state == MTK_STATE_FREE)) {
-               ret = -EIO;
-               goto err_start_stream;
-       }
-
-       /* Do the initialization when both start_streaming have been called */
-       if (V4L2_TYPE_IS_OUTPUT(q->type)) {
-               if (!vb2_start_streaming_called(&ctx->m2m_ctx->cap_q_ctx.q))
-                       return 0;
-       } else {
-               if (!vb2_start_streaming_called(&ctx->m2m_ctx->out_q_ctx.q))
-                       return 0;
-       }
-
-       ret = pm_runtime_resume_and_get(&ctx->dev->plat_dev->dev);
-       if (ret < 0) {
-               mtk_v4l2_err("pm_runtime_resume_and_get fail %d", ret);
-               goto err_start_stream;
-       }
-
-       mtk_venc_set_param(ctx, &param);
-       ret = venc_if_set_param(ctx, VENC_SET_PARAM_ENC, &param);
-       if (ret) {
-               mtk_v4l2_err("venc_if_set_param failed=%d", ret);
-               ctx->state = MTK_STATE_ABORT;
-               goto err_set_param;
-       }
-       ctx->param_change = MTK_ENCODE_PARAM_NONE;
-
-       if ((ctx->q_data[MTK_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_H264) &&
-           (ctx->enc_params.seq_hdr_mode !=
-                               V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE)) {
-               ret = venc_if_set_param(ctx,
-                                       VENC_SET_PARAM_PREPEND_HEADER,
-                                       NULL);
-               if (ret) {
-                       mtk_v4l2_err("venc_if_set_param failed=%d", ret);
-                       ctx->state = MTK_STATE_ABORT;
-                       goto err_set_param;
-               }
-               ctx->state = MTK_STATE_HEADER;
-       }
-
-       return 0;
-
-err_set_param:
-       pm_ret = pm_runtime_put(&ctx->dev->plat_dev->dev);
-       if (pm_ret < 0)
-               mtk_v4l2_err("pm_runtime_put fail %d", pm_ret);
-
-err_start_stream:
-       for (i = 0; i < q->num_buffers; ++i) {
-               struct vb2_buffer *buf = vb2_get_buffer(q, i);
-
-               /*
-                * FIXME: This check is not needed as only active buffers
-                * can be marked as done.
-                */
-               if (buf->state == VB2_BUF_STATE_ACTIVE) {
-                       mtk_v4l2_debug(0, "[%d] id=%d, type=%d, %d -> VB2_BUF_STATE_QUEUED",
-                                       ctx->id, i, q->type,
-                                       (int)buf->state);
-                       v4l2_m2m_buf_done(to_vb2_v4l2_buffer(buf),
-                                         VB2_BUF_STATE_QUEUED);
-               }
-       }
-
-       return ret;
-}
-
-static void vb2ops_venc_stop_streaming(struct vb2_queue *q)
-{
-       struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(q);
-       struct vb2_v4l2_buffer *src_buf, *dst_buf;
-       int ret;
-
-       mtk_v4l2_debug(2, "[%d]-> type=%d", ctx->id, q->type);
-
-       if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
-               while ((dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx))) {
-                       vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0);
-                       v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);
-               }
-               /* STREAMOFF on the CAPTURE queue completes any ongoing flush */
-               if (ctx->is_flushing) {
-                       struct v4l2_m2m_buffer *b, *n;
-
-                       mtk_v4l2_debug(1, "STREAMOFF called while flushing");
-                       /*
-                        * STREAMOFF could be called before the flush buffer is
-                        * dequeued. Check whether empty flush buf is still in
-                        * queue before removing it.
-                        */
-                       v4l2_m2m_for_each_src_buf_safe(ctx->m2m_ctx, b, n) {
-                               if (b == &ctx->empty_flush_buf) {
-                                       v4l2_m2m_src_buf_remove_by_buf(ctx->m2m_ctx, &b->vb);
-                                       break;
-                               }
-                       }
-                       ctx->is_flushing = false;
-               }
-       } else {
-               while ((src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx))) {
-                       if (src_buf != &ctx->empty_flush_buf.vb)
-                               v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
-               }
-               if (ctx->is_flushing) {
-                       /*
-                        * If we are in the middle of a flush, put the flush
-                        * buffer back into the queue so the next CAPTURE
-                        * buffer gets returned with the LAST flag set.
-                        */
-                       v4l2_m2m_buf_queue(ctx->m2m_ctx,
-                                          &ctx->empty_flush_buf.vb);
-               }
-       }
-
-       if ((q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
-            vb2_is_streaming(&ctx->m2m_ctx->out_q_ctx.q)) ||
-           (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
-            vb2_is_streaming(&ctx->m2m_ctx->cap_q_ctx.q))) {
-               mtk_v4l2_debug(1, "[%d]-> q type %d out=%d cap=%d",
-                              ctx->id, q->type,
-                              vb2_is_streaming(&ctx->m2m_ctx->out_q_ctx.q),
-                              vb2_is_streaming(&ctx->m2m_ctx->cap_q_ctx.q));
-               return;
-       }
-
-       /* Release the encoder if both streams are stopped. */
-       ret = venc_if_deinit(ctx);
-       if (ret)
-               mtk_v4l2_err("venc_if_deinit failed=%d", ret);
-
-       ret = pm_runtime_put(&ctx->dev->plat_dev->dev);
-       if (ret < 0)
-               mtk_v4l2_err("pm_runtime_put fail %d", ret);
-
-       ctx->state = MTK_STATE_FREE;
-}
-
-static int vb2ops_venc_buf_out_validate(struct vb2_buffer *vb)
-{
-       struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
-
-       vbuf->field = V4L2_FIELD_NONE;
-       return 0;
-}
-
-static const struct vb2_ops mtk_venc_vb2_ops = {
-       .queue_setup            = vb2ops_venc_queue_setup,
-       .buf_out_validate       = vb2ops_venc_buf_out_validate,
-       .buf_prepare            = vb2ops_venc_buf_prepare,
-       .buf_queue              = vb2ops_venc_buf_queue,
-       .wait_prepare           = vb2_ops_wait_prepare,
-       .wait_finish            = vb2_ops_wait_finish,
-       .start_streaming        = vb2ops_venc_start_streaming,
-       .stop_streaming         = vb2ops_venc_stop_streaming,
-};
-
-static int mtk_venc_encode_header(void *priv)
-{
-       struct mtk_vcodec_ctx *ctx = priv;
-       int ret;
-       struct vb2_v4l2_buffer *src_buf, *dst_buf;
-       struct mtk_vcodec_mem bs_buf;
-       struct venc_done_result enc_result;
-
-       dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
-       if (!dst_buf) {
-               mtk_v4l2_debug(1, "No dst buffer");
-               return -EINVAL;
-       }
-
-       bs_buf.va = vb2_plane_vaddr(&dst_buf->vb2_buf, 0);
-       bs_buf.dma_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
-       bs_buf.size = (size_t)dst_buf->vb2_buf.planes[0].length;
-
-       mtk_v4l2_debug(1,
-                       "[%d] buf id=%d va=0x%p dma_addr=0x%llx size=%zu",
-                       ctx->id,
-                       dst_buf->vb2_buf.index, bs_buf.va,
-                       (u64)bs_buf.dma_addr,
-                       bs_buf.size);
-
-       ret = venc_if_encode(ctx,
-                       VENC_START_OPT_ENCODE_SEQUENCE_HEADER,
-                       NULL, &bs_buf, &enc_result);
-
-       if (ret) {
-               vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0);
-               ctx->state = MTK_STATE_ABORT;
-               v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);
-               mtk_v4l2_err("venc_if_encode failed=%d", ret);
-               return -EINVAL;
-       }
-       src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
-       if (src_buf) {
-               dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp;
-               dst_buf->timecode = src_buf->timecode;
-       } else {
-               mtk_v4l2_err("No timestamp for the header buffer.");
-       }
-
-       ctx->state = MTK_STATE_HEADER;
-       vb2_set_plane_payload(&dst_buf->vb2_buf, 0, enc_result.bs_size);
-       v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
-
-       return 0;
-}
-
-static int mtk_venc_param_change(struct mtk_vcodec_ctx *ctx)
-{
-       struct venc_enc_param enc_prm;
-       struct vb2_v4l2_buffer *vb2_v4l2 = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
-       struct mtk_video_enc_buf *mtk_buf;
-       int ret = 0;
-
-       /* Don't upcast the empty flush buffer */
-       if (vb2_v4l2 == &ctx->empty_flush_buf.vb)
-               return 0;
-
-       mtk_buf = container_of(vb2_v4l2, struct mtk_video_enc_buf, m2m_buf.vb);
-
-       memset(&enc_prm, 0, sizeof(enc_prm));
-       if (mtk_buf->param_change == MTK_ENCODE_PARAM_NONE)
-               return 0;
-
-       if (mtk_buf->param_change & MTK_ENCODE_PARAM_BITRATE) {
-               enc_prm.bitrate = mtk_buf->enc_params.bitrate;
-               mtk_v4l2_debug(1, "[%d] id=%d, change param br=%d",
-                               ctx->id,
-                               vb2_v4l2->vb2_buf.index,
-                               enc_prm.bitrate);
-               ret |= venc_if_set_param(ctx,
-                                        VENC_SET_PARAM_ADJUST_BITRATE,
-                                        &enc_prm);
-       }
-       if (!ret && mtk_buf->param_change & MTK_ENCODE_PARAM_FRAMERATE) {
-               enc_prm.frm_rate = mtk_buf->enc_params.framerate_num /
-                                  mtk_buf->enc_params.framerate_denom;
-               mtk_v4l2_debug(1, "[%d] id=%d, change param fr=%d",
-                              ctx->id,
-                              vb2_v4l2->vb2_buf.index,
-                              enc_prm.frm_rate);
-               ret |= venc_if_set_param(ctx,
-                                        VENC_SET_PARAM_ADJUST_FRAMERATE,
-                                        &enc_prm);
-       }
-       if (!ret && mtk_buf->param_change & MTK_ENCODE_PARAM_GOP_SIZE) {
-               enc_prm.gop_size = mtk_buf->enc_params.gop_size;
-               mtk_v4l2_debug(1, "change param intra period=%d",
-                              enc_prm.gop_size);
-               ret |= venc_if_set_param(ctx,
-                                        VENC_SET_PARAM_GOP_SIZE,
-                                        &enc_prm);
-       }
-       if (!ret && mtk_buf->param_change & MTK_ENCODE_PARAM_FORCE_INTRA) {
-               mtk_v4l2_debug(1, "[%d] id=%d, change param force I=%d",
-                               ctx->id,
-                               vb2_v4l2->vb2_buf.index,
-                               mtk_buf->enc_params.force_intra);
-               if (mtk_buf->enc_params.force_intra)
-                       ret |= venc_if_set_param(ctx,
-                                                VENC_SET_PARAM_FORCE_INTRA,
-                                                NULL);
-       }
-
-       mtk_buf->param_change = MTK_ENCODE_PARAM_NONE;
-
-       if (ret) {
-               ctx->state = MTK_STATE_ABORT;
-               mtk_v4l2_err("venc_if_set_param %d failed=%d",
-                               mtk_buf->param_change, ret);
-               return -1;
-       }
-
-       return 0;
-}
-
-/*
- * v4l2_m2m_streamoff() holds dev_mutex and waits mtk_venc_worker()
- * to call v4l2_m2m_job_finish().
- * If mtk_venc_worker() tries to acquire dev_mutex, it will deadlock.
- * So this function must not try to acquire dev->dev_mutex.
- * This means v4l2 ioctls and mtk_venc_worker() can run at the same time.
- * mtk_venc_worker() should be carefully implemented to avoid bugs.
- */
-static void mtk_venc_worker(struct work_struct *work)
-{
-       struct mtk_vcodec_ctx *ctx = container_of(work, struct mtk_vcodec_ctx,
-                                   encode_work);
-       struct vb2_v4l2_buffer *src_buf, *dst_buf;
-       struct venc_frm_buf frm_buf;
-       struct mtk_vcodec_mem bs_buf;
-       struct venc_done_result enc_result;
-       int ret, i;
-
-       /* check dst_buf, dst_buf may be removed in device_run
-        * to stored encdoe header so we need check dst_buf and
-        * call job_finish here to prevent recursion
-        */
-       dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
-       if (!dst_buf) {
-               v4l2_m2m_job_finish(ctx->dev->m2m_dev_enc, ctx->m2m_ctx);
-               return;
-       }
-
-       src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
-
-       /*
-        * If we see the flush buffer, send an empty buffer with the LAST flag
-        * to the client. is_flushing will be reset at the time the buffer
-        * is dequeued.
-        */
-       if (src_buf == &ctx->empty_flush_buf.vb) {
-               vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0);
-               dst_buf->flags |= V4L2_BUF_FLAG_LAST;
-               v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
-               v4l2_m2m_job_finish(ctx->dev->m2m_dev_enc, ctx->m2m_ctx);
-               return;
-       }
-
-       memset(&frm_buf, 0, sizeof(frm_buf));
-       for (i = 0; i < src_buf->vb2_buf.num_planes ; i++) {
-               frm_buf.fb_addr[i].dma_addr =
-                               vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, i);
-               frm_buf.fb_addr[i].size =
-                               (size_t)src_buf->vb2_buf.planes[i].length;
-       }
-       bs_buf.va = vb2_plane_vaddr(&dst_buf->vb2_buf, 0);
-       bs_buf.dma_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
-       bs_buf.size = (size_t)dst_buf->vb2_buf.planes[0].length;
-
-       mtk_v4l2_debug(2,
-                       "Framebuf PA=%llx Size=0x%zx;PA=0x%llx Size=0x%zx;PA=0x%llx Size=%zu",
-                       (u64)frm_buf.fb_addr[0].dma_addr,
-                       frm_buf.fb_addr[0].size,
-                       (u64)frm_buf.fb_addr[1].dma_addr,
-                       frm_buf.fb_addr[1].size,
-                       (u64)frm_buf.fb_addr[2].dma_addr,
-                       frm_buf.fb_addr[2].size);
-
-       ret = venc_if_encode(ctx, VENC_START_OPT_ENCODE_FRAME,
-                            &frm_buf, &bs_buf, &enc_result);
-
-       dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp;
-       dst_buf->timecode = src_buf->timecode;
-
-       if (enc_result.is_key_frm)
-               dst_buf->flags |= V4L2_BUF_FLAG_KEYFRAME;
-
-       if (ret) {
-               v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
-               vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0);
-               v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);
-               mtk_v4l2_err("venc_if_encode failed=%d", ret);
-       } else {
-               v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
-               vb2_set_plane_payload(&dst_buf->vb2_buf, 0, enc_result.bs_size);
-               v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
-               mtk_v4l2_debug(2, "venc_if_encode bs size=%d",
-                                enc_result.bs_size);
-       }
-
-       v4l2_m2m_job_finish(ctx->dev->m2m_dev_enc, ctx->m2m_ctx);
-
-       mtk_v4l2_debug(1, "<=== src_buf[%d] dst_buf[%d] venc_if_encode ret=%d Size=%u===>",
-                       src_buf->vb2_buf.index, dst_buf->vb2_buf.index, ret,
-                       enc_result.bs_size);
-}
-
-static void m2mops_venc_device_run(void *priv)
-{
-       struct mtk_vcodec_ctx *ctx = priv;
-
-       if ((ctx->q_data[MTK_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_H264) &&
-           (ctx->state != MTK_STATE_HEADER)) {
-               /* encode h264 sps/pps header */
-               mtk_venc_encode_header(ctx);
-               queue_work(ctx->dev->encode_workqueue, &ctx->encode_work);
-               return;
-       }
-
-       mtk_venc_param_change(ctx);
-       queue_work(ctx->dev->encode_workqueue, &ctx->encode_work);
-}
-
-static int m2mops_venc_job_ready(void *m2m_priv)
-{
-       struct mtk_vcodec_ctx *ctx = m2m_priv;
-
-       if (ctx->state == MTK_STATE_ABORT || ctx->state == MTK_STATE_FREE) {
-               mtk_v4l2_debug(3, "[%d]Not ready: state=0x%x.",
-                              ctx->id, ctx->state);
-               return 0;
-       }
-
-       return 1;
-}
-
-static void m2mops_venc_job_abort(void *priv)
-{
-       struct mtk_vcodec_ctx *ctx = priv;
-
-       ctx->state = MTK_STATE_ABORT;
-}
-
-const struct v4l2_m2m_ops mtk_venc_m2m_ops = {
-       .device_run     = m2mops_venc_device_run,
-       .job_ready      = m2mops_venc_job_ready,
-       .job_abort      = m2mops_venc_job_abort,
-};
-
-void mtk_vcodec_enc_set_default_params(struct mtk_vcodec_ctx *ctx)
-{
-       struct mtk_q_data *q_data;
-
-       ctx->m2m_ctx->q_lock = &ctx->dev->dev_mutex;
-       ctx->fh.m2m_ctx = ctx->m2m_ctx;
-       ctx->fh.ctrl_handler = &ctx->ctrl_hdl;
-       INIT_WORK(&ctx->encode_work, mtk_venc_worker);
-
-       ctx->colorspace = V4L2_COLORSPACE_REC709;
-       ctx->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
-       ctx->quantization = V4L2_QUANTIZATION_DEFAULT;
-       ctx->xfer_func = V4L2_XFER_FUNC_DEFAULT;
-
-       q_data = &ctx->q_data[MTK_Q_DATA_SRC];
-       memset(q_data, 0, sizeof(struct mtk_q_data));
-       q_data->visible_width = DFT_CFG_WIDTH;
-       q_data->visible_height = DFT_CFG_HEIGHT;
-       q_data->coded_width = DFT_CFG_WIDTH;
-       q_data->coded_height = DFT_CFG_HEIGHT;
-       q_data->field = V4L2_FIELD_NONE;
-
-       q_data->fmt = &ctx->dev->venc_pdata->output_formats[0];
-
-       v4l_bound_align_image(&q_data->coded_width,
-                               MTK_VENC_MIN_W,
-                               MTK_VENC_HD_MAX_W, 4,
-                               &q_data->coded_height,
-                               MTK_VENC_MIN_H,
-                               MTK_VENC_HD_MAX_H, 5, 6);
-
-       if (q_data->coded_width < DFT_CFG_WIDTH &&
-               (q_data->coded_width + 16) <= MTK_VENC_HD_MAX_W)
-               q_data->coded_width += 16;
-       if (q_data->coded_height < DFT_CFG_HEIGHT &&
-               (q_data->coded_height + 32) <= MTK_VENC_HD_MAX_H)
-               q_data->coded_height += 32;
-
-       q_data->sizeimage[0] =
-               q_data->coded_width * q_data->coded_height+
-               ((ALIGN(q_data->coded_width, 16) * 2) * 16);
-       q_data->bytesperline[0] = q_data->coded_width;
-       q_data->sizeimage[1] =
-               (q_data->coded_width * q_data->coded_height) / 2 +
-               (ALIGN(q_data->coded_width, 16) * 16);
-       q_data->bytesperline[1] = q_data->coded_width;
-
-       q_data = &ctx->q_data[MTK_Q_DATA_DST];
-       memset(q_data, 0, sizeof(struct mtk_q_data));
-       q_data->coded_width = DFT_CFG_WIDTH;
-       q_data->coded_height = DFT_CFG_HEIGHT;
-       q_data->fmt = &ctx->dev->venc_pdata->capture_formats[0];
-       q_data->field = V4L2_FIELD_NONE;
-       ctx->q_data[MTK_Q_DATA_DST].sizeimage[0] =
-               DFT_CFG_WIDTH * DFT_CFG_HEIGHT;
-       ctx->q_data[MTK_Q_DATA_DST].bytesperline[0] = 0;
-
-       ctx->enc_params.framerate_num = MTK_DEFAULT_FRAMERATE_NUM;
-       ctx->enc_params.framerate_denom = MTK_DEFAULT_FRAMERATE_DENOM;
-}
-
-int mtk_vcodec_enc_ctrls_setup(struct mtk_vcodec_ctx *ctx)
-{
-       const struct v4l2_ctrl_ops *ops = &mtk_vcodec_enc_ctrl_ops;
-       struct v4l2_ctrl_handler *handler = &ctx->ctrl_hdl;
-       u8 h264_max_level;
-
-       if (ctx->dev->enc_capability & MTK_VENC_4K_CAPABILITY_ENABLE)
-               h264_max_level = V4L2_MPEG_VIDEO_H264_LEVEL_5_1;
-       else
-               h264_max_level = V4L2_MPEG_VIDEO_H264_LEVEL_4_2;
-
-       v4l2_ctrl_handler_init(handler, MTK_MAX_CTRLS_HINT);
-
-       v4l2_ctrl_new_std(handler, ops, V4L2_CID_MIN_BUFFERS_FOR_OUTPUT,
-                         1, 1, 1, 1);
-       v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_BITRATE,
-                         ctx->dev->venc_pdata->min_bitrate,
-                         ctx->dev->venc_pdata->max_bitrate, 1, 4000000);
-       v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_B_FRAMES,
-                       0, 2, 1, 0);
-       v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE,
-                       0, 1, 1, 1);
-       v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_H264_MAX_QP,
-                       0, 51, 1, 51);
-       v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_H264_I_PERIOD,
-                       0, 65535, 1, 0);
-       v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_GOP_SIZE,
-                       0, 65535, 1, 0);
-       v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE,
-                       0, 1, 1, 0);
-       v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME,
-                       0, 0, 0, 0);
-       v4l2_ctrl_new_std_menu(handler, ops,
-                       V4L2_CID_MPEG_VIDEO_HEADER_MODE,
-                       V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME,
-                       0, V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE);
-       v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_MPEG_VIDEO_H264_PROFILE,
-                       V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
-                       0, V4L2_MPEG_VIDEO_H264_PROFILE_HIGH);
-       v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_MPEG_VIDEO_H264_LEVEL,
-                              h264_max_level,
-                              0, V4L2_MPEG_VIDEO_H264_LEVEL_4_0);
-       v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_MPEG_VIDEO_VP8_PROFILE,
-                              V4L2_MPEG_VIDEO_VP8_PROFILE_0, 0, V4L2_MPEG_VIDEO_VP8_PROFILE_0);
-
-
-       if (handler->error) {
-               mtk_v4l2_err("Init control handler fail %d",
-                               handler->error);
-               return handler->error;
-       }
-
-       v4l2_ctrl_handler_setup(&ctx->ctrl_hdl);
-
-       return 0;
-}
-
-int mtk_vcodec_enc_queue_init(void *priv, struct vb2_queue *src_vq,
-                             struct vb2_queue *dst_vq)
-{
-       struct mtk_vcodec_ctx *ctx = priv;
-       int ret;
-
-       /* Note: VB2_USERPTR works with dma-contig because mt8173
-        * support iommu
-        * https://patchwork.kernel.org/patch/8335461/
-        * https://patchwork.kernel.org/patch/7596181/
-        */
-       src_vq->type            = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
-       src_vq->io_modes        = VB2_DMABUF | VB2_MMAP | VB2_USERPTR;
-       src_vq->drv_priv        = ctx;
-       src_vq->buf_struct_size = sizeof(struct mtk_video_enc_buf);
-       src_vq->ops             = &mtk_venc_vb2_ops;
-       src_vq->mem_ops         = &vb2_dma_contig_memops;
-       src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
-       src_vq->lock            = &ctx->dev->dev_mutex;
-       src_vq->dev             = &ctx->dev->plat_dev->dev;
-
-       ret = vb2_queue_init(src_vq);
-       if (ret)
-               return ret;
-
-       dst_vq->type            = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
-       dst_vq->io_modes        = VB2_DMABUF | VB2_MMAP | VB2_USERPTR;
-       dst_vq->drv_priv        = ctx;
-       dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
-       dst_vq->ops             = &mtk_venc_vb2_ops;
-       dst_vq->mem_ops         = &vb2_dma_contig_memops;
-       dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
-       dst_vq->lock            = &ctx->dev->dev_mutex;
-       dst_vq->dev             = &ctx->dev->plat_dev->dev;
-
-       return vb2_queue_init(dst_vq);
-}
-
-int mtk_venc_unlock(struct mtk_vcodec_ctx *ctx)
-{
-       struct mtk_vcodec_dev *dev = ctx->dev;
-
-       mutex_unlock(&dev->enc_mutex);
-       return 0;
-}
-
-int mtk_venc_lock(struct mtk_vcodec_ctx *ctx)
-{
-       struct mtk_vcodec_dev *dev = ctx->dev;
-
-       mutex_lock(&dev->enc_mutex);
-       return 0;
-}
-
-void mtk_vcodec_enc_release(struct mtk_vcodec_ctx *ctx)
-{
-       int ret = venc_if_deinit(ctx);
-
-       if (ret)
-               mtk_v4l2_err("venc_if_deinit failed=%d", ret);
-
-       ctx->state = MTK_STATE_FREE;
-}
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.h
deleted file mode 100644 (file)
index 513ee79..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
-* Copyright (c) 2016 MediaTek Inc.
-* Author: PC Chen <pc.chen@mediatek.com>
-*         Tiffany Lin <tiffany.lin@mediatek.com>
-*/
-
-#ifndef _MTK_VCODEC_ENC_H_
-#define _MTK_VCODEC_ENC_H_
-
-#include <media/videobuf2-core.h>
-#include <media/v4l2-mem2mem.h>
-
-#define MTK_VENC_IRQ_STATUS_SPS        0x1
-#define MTK_VENC_IRQ_STATUS_PPS        0x2
-#define MTK_VENC_IRQ_STATUS_FRM        0x4
-#define MTK_VENC_IRQ_STATUS_DRAM       0x8
-#define MTK_VENC_IRQ_STATUS_PAUSE      0x10
-#define MTK_VENC_IRQ_STATUS_SWITCH     0x20
-
-#define MTK_VENC_IRQ_STATUS_OFFSET     0x05C
-#define MTK_VENC_IRQ_ACK_OFFSET        0x060
-
-/**
- * struct mtk_video_enc_buf - Private data related to each VB2 buffer.
- * @m2m_buf:   M2M buffer
- * @list:      list that buffer link to
- * @param_change: Types of encode parameter change before encoding this
- *                             buffer
- * @enc_params: Encode parameters changed before encode this buffer
- */
-struct mtk_video_enc_buf {
-       struct v4l2_m2m_buffer m2m_buf;
-
-       u32 param_change;
-       struct mtk_enc_params enc_params;
-};
-
-extern const struct v4l2_ioctl_ops mtk_venc_ioctl_ops;
-extern const struct v4l2_m2m_ops mtk_venc_m2m_ops;
-
-int mtk_venc_unlock(struct mtk_vcodec_ctx *ctx);
-int mtk_venc_lock(struct mtk_vcodec_ctx *ctx);
-int mtk_vcodec_enc_queue_init(void *priv, struct vb2_queue *src_vq,
-                             struct vb2_queue *dst_vq);
-void mtk_vcodec_enc_release(struct mtk_vcodec_ctx *ctx);
-int mtk_vcodec_enc_ctrls_setup(struct mtk_vcodec_ctx *ctx);
-void mtk_vcodec_enc_set_default_params(struct mtk_vcodec_ctx *ctx);
-
-#endif /* _MTK_VCODEC_ENC_H_ */
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c
deleted file mode 100644 (file)
index 5172cfe..0000000
+++ /dev/null
@@ -1,479 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
-* Copyright (c) 2016 MediaTek Inc.
-* Author: PC Chen <pc.chen@mediatek.com>
-*      Tiffany Lin <tiffany.lin@mediatek.com>
-*/
-
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/of.h>
-#include <linux/pm_runtime.h>
-#include <media/v4l2-event.h>
-#include <media/v4l2-mem2mem.h>
-#include <media/videobuf2-dma-contig.h>
-
-#include "mtk_vcodec_drv.h"
-#include "mtk_vcodec_enc.h"
-#include "mtk_vcodec_enc_pm.h"
-#include "mtk_vcodec_intr.h"
-#include "mtk_vcodec_util.h"
-#include "mtk_vcodec_fw.h"
-
-static const struct mtk_video_fmt mtk_video_formats_output[] = {
-       {
-               .fourcc = V4L2_PIX_FMT_NV12M,
-               .type = MTK_FMT_FRAME,
-               .num_planes = 2,
-       },
-       {
-               .fourcc = V4L2_PIX_FMT_NV21M,
-               .type = MTK_FMT_FRAME,
-               .num_planes = 2,
-       },
-       {
-               .fourcc = V4L2_PIX_FMT_YUV420M,
-               .type = MTK_FMT_FRAME,
-               .num_planes = 3,
-       },
-       {
-               .fourcc = V4L2_PIX_FMT_YVU420M,
-               .type = MTK_FMT_FRAME,
-               .num_planes = 3,
-       },
-};
-
-static const struct mtk_video_fmt mtk_video_formats_capture_h264[] =  {
-       {
-               .fourcc = V4L2_PIX_FMT_H264,
-               .type = MTK_FMT_ENC,
-               .num_planes = 1,
-       },
-};
-
-static const struct mtk_video_fmt mtk_video_formats_capture_vp8[] =  {
-       {
-               .fourcc = V4L2_PIX_FMT_VP8,
-               .type = MTK_FMT_ENC,
-               .num_planes = 1,
-       },
-};
-
-static void clean_irq_status(unsigned int irq_status, void __iomem *addr)
-{
-       if (irq_status & MTK_VENC_IRQ_STATUS_PAUSE)
-               writel(MTK_VENC_IRQ_STATUS_PAUSE, addr);
-
-       if (irq_status & MTK_VENC_IRQ_STATUS_SWITCH)
-               writel(MTK_VENC_IRQ_STATUS_SWITCH, addr);
-
-       if (irq_status & MTK_VENC_IRQ_STATUS_DRAM)
-               writel(MTK_VENC_IRQ_STATUS_DRAM, addr);
-
-       if (irq_status & MTK_VENC_IRQ_STATUS_SPS)
-               writel(MTK_VENC_IRQ_STATUS_SPS, addr);
-
-       if (irq_status & MTK_VENC_IRQ_STATUS_PPS)
-               writel(MTK_VENC_IRQ_STATUS_PPS, addr);
-
-       if (irq_status & MTK_VENC_IRQ_STATUS_FRM)
-               writel(MTK_VENC_IRQ_STATUS_FRM, addr);
-
-}
-static irqreturn_t mtk_vcodec_enc_irq_handler(int irq, void *priv)
-{
-       struct mtk_vcodec_dev *dev = priv;
-       struct mtk_vcodec_ctx *ctx;
-       unsigned long flags;
-       void __iomem *addr;
-
-       spin_lock_irqsave(&dev->irqlock, flags);
-       ctx = dev->curr_ctx;
-       spin_unlock_irqrestore(&dev->irqlock, flags);
-
-       mtk_v4l2_debug(1, "id=%d coreid:%d", ctx->id, dev->venc_pdata->core_id);
-       addr = dev->reg_base[dev->venc_pdata->core_id] +
-                               MTK_VENC_IRQ_ACK_OFFSET;
-
-       ctx->irq_status = readl(dev->reg_base[dev->venc_pdata->core_id] +
-                               (MTK_VENC_IRQ_STATUS_OFFSET));
-
-       clean_irq_status(ctx->irq_status, addr);
-
-       wake_up_ctx(ctx, MTK_INST_IRQ_RECEIVED, 0);
-       return IRQ_HANDLED;
-}
-
-static int fops_vcodec_open(struct file *file)
-{
-       struct mtk_vcodec_dev *dev = video_drvdata(file);
-       struct mtk_vcodec_ctx *ctx = NULL;
-       int ret = 0;
-       struct vb2_queue *src_vq;
-
-       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
-       if (!ctx)
-               return -ENOMEM;
-
-       mutex_lock(&dev->dev_mutex);
-       /*
-        * Use simple counter to uniquely identify this context. Only
-        * used for logging.
-        */
-       ctx->id = dev->id_counter++;
-       v4l2_fh_init(&ctx->fh, video_devdata(file));
-       file->private_data = &ctx->fh;
-       v4l2_fh_add(&ctx->fh);
-       INIT_LIST_HEAD(&ctx->list);
-       ctx->dev = dev;
-       init_waitqueue_head(&ctx->queue[0]);
-
-       ctx->type = MTK_INST_ENCODER;
-       ret = mtk_vcodec_enc_ctrls_setup(ctx);
-       if (ret) {
-               mtk_v4l2_err("Failed to setup controls() (%d)",
-                               ret);
-               goto err_ctrls_setup;
-       }
-       ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev_enc, ctx,
-                                        &mtk_vcodec_enc_queue_init);
-       if (IS_ERR((__force void *)ctx->m2m_ctx)) {
-               ret = PTR_ERR((__force void *)ctx->m2m_ctx);
-               mtk_v4l2_err("Failed to v4l2_m2m_ctx_init() (%d)",
-                               ret);
-               goto err_m2m_ctx_init;
-       }
-       src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx,
-                                V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
-       ctx->empty_flush_buf.vb.vb2_buf.vb2_queue = src_vq;
-       mtk_vcodec_enc_set_default_params(ctx);
-
-       if (v4l2_fh_is_singular(&ctx->fh)) {
-               /*
-                * load fireware to checks if it was loaded already and
-                * does nothing in that case
-                */
-               ret = mtk_vcodec_fw_load_firmware(dev->fw_handler);
-               if (ret < 0) {
-                       /*
-                        * Return 0 if downloading firmware successfully,
-                        * otherwise it is failed
-                        */
-                       mtk_v4l2_err("vpu_load_firmware failed!");
-                       goto err_load_fw;
-               }
-
-               dev->enc_capability =
-                       mtk_vcodec_fw_get_venc_capa(dev->fw_handler);
-               mtk_v4l2_debug(0, "encoder capability %x", dev->enc_capability);
-       }
-
-       mtk_v4l2_debug(2, "Create instance [%d]@%p m2m_ctx=%p ",
-                       ctx->id, ctx, ctx->m2m_ctx);
-
-       list_add(&ctx->list, &dev->ctx_list);
-
-       mutex_unlock(&dev->dev_mutex);
-       mtk_v4l2_debug(0, "%s encoder [%d]", dev_name(&dev->plat_dev->dev),
-                       ctx->id);
-       return ret;
-
-       /* Deinit when failure occurred */
-err_load_fw:
-       v4l2_m2m_ctx_release(ctx->m2m_ctx);
-err_m2m_ctx_init:
-       v4l2_ctrl_handler_free(&ctx->ctrl_hdl);
-err_ctrls_setup:
-       v4l2_fh_del(&ctx->fh);
-       v4l2_fh_exit(&ctx->fh);
-       kfree(ctx);
-       mutex_unlock(&dev->dev_mutex);
-
-       return ret;
-}
-
-static int fops_vcodec_release(struct file *file)
-{
-       struct mtk_vcodec_dev *dev = video_drvdata(file);
-       struct mtk_vcodec_ctx *ctx = fh_to_ctx(file->private_data);
-
-       mtk_v4l2_debug(1, "[%d] encoder", ctx->id);
-       mutex_lock(&dev->dev_mutex);
-
-       v4l2_m2m_ctx_release(ctx->m2m_ctx);
-       mtk_vcodec_enc_release(ctx);
-       v4l2_fh_del(&ctx->fh);
-       v4l2_fh_exit(&ctx->fh);
-       v4l2_ctrl_handler_free(&ctx->ctrl_hdl);
-
-       list_del_init(&ctx->list);
-       kfree(ctx);
-       mutex_unlock(&dev->dev_mutex);
-       return 0;
-}
-
-static const struct v4l2_file_operations mtk_vcodec_fops = {
-       .owner          = THIS_MODULE,
-       .open           = fops_vcodec_open,
-       .release        = fops_vcodec_release,
-       .poll           = v4l2_m2m_fop_poll,
-       .unlocked_ioctl = video_ioctl2,
-       .mmap           = v4l2_m2m_fop_mmap,
-};
-
-static int mtk_vcodec_probe(struct platform_device *pdev)
-{
-       struct mtk_vcodec_dev *dev;
-       struct video_device *vfd_enc;
-       struct resource *res;
-       phandle rproc_phandle;
-       enum mtk_vcodec_fw_type fw_type;
-       int ret;
-
-       dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
-       if (!dev)
-               return -ENOMEM;
-
-       INIT_LIST_HEAD(&dev->ctx_list);
-       dev->plat_dev = pdev;
-
-       if (!of_property_read_u32(pdev->dev.of_node, "mediatek,vpu",
-                                 &rproc_phandle)) {
-               fw_type = VPU;
-       } else if (!of_property_read_u32(pdev->dev.of_node, "mediatek,scp",
-                                        &rproc_phandle)) {
-               fw_type = SCP;
-       } else {
-               mtk_v4l2_err("Could not get venc IPI device");
-               return -ENODEV;
-       }
-       dma_set_max_seg_size(&pdev->dev, UINT_MAX);
-
-       dev->fw_handler = mtk_vcodec_fw_select(dev, fw_type, ENCODER);
-       if (IS_ERR(dev->fw_handler))
-               return PTR_ERR(dev->fw_handler);
-
-       dev->venc_pdata = of_device_get_match_data(&pdev->dev);
-       ret = mtk_vcodec_init_enc_clk(dev);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "Failed to get mtk vcodec clock source!");
-               goto err_enc_pm;
-       }
-
-       pm_runtime_enable(&pdev->dev);
-
-       dev->reg_base[dev->venc_pdata->core_id] =
-               devm_platform_ioremap_resource(pdev, 0);
-       if (IS_ERR(dev->reg_base[dev->venc_pdata->core_id])) {
-               ret = PTR_ERR(dev->reg_base[dev->venc_pdata->core_id]);
-               goto err_res;
-       }
-
-       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (res == NULL) {
-               dev_err(&pdev->dev, "failed to get irq resource");
-               ret = -ENOENT;
-               goto err_res;
-       }
-
-       dev->enc_irq = platform_get_irq(pdev, 0);
-       irq_set_status_flags(dev->enc_irq, IRQ_NOAUTOEN);
-       ret = devm_request_irq(&pdev->dev, dev->enc_irq,
-                              mtk_vcodec_enc_irq_handler,
-                              0, pdev->name, dev);
-       if (ret) {
-               dev_err(&pdev->dev,
-                       "Failed to install dev->enc_irq %d (%d) core_id (%d)",
-                       dev->enc_irq, ret, dev->venc_pdata->core_id);
-               ret = -EINVAL;
-               goto err_res;
-       }
-
-       mutex_init(&dev->enc_mutex);
-       mutex_init(&dev->dev_mutex);
-       spin_lock_init(&dev->irqlock);
-
-       snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), "%s",
-                "[MTK_V4L2_VENC]");
-
-       ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
-       if (ret) {
-               mtk_v4l2_err("v4l2_device_register err=%d", ret);
-               goto err_res;
-       }
-
-       init_waitqueue_head(&dev->queue);
-
-       /* allocate video device for encoder and register it */
-       vfd_enc = video_device_alloc();
-       if (!vfd_enc) {
-               mtk_v4l2_err("Failed to allocate video device");
-               ret = -ENOMEM;
-               goto err_enc_alloc;
-       }
-       vfd_enc->fops           = &mtk_vcodec_fops;
-       vfd_enc->ioctl_ops      = &mtk_venc_ioctl_ops;
-       vfd_enc->release        = video_device_release;
-       vfd_enc->lock           = &dev->dev_mutex;
-       vfd_enc->v4l2_dev       = &dev->v4l2_dev;
-       vfd_enc->vfl_dir        = VFL_DIR_M2M;
-       vfd_enc->device_caps    = V4L2_CAP_VIDEO_M2M_MPLANE |
-                                       V4L2_CAP_STREAMING;
-
-       snprintf(vfd_enc->name, sizeof(vfd_enc->name), "%s",
-                MTK_VCODEC_ENC_NAME);
-       video_set_drvdata(vfd_enc, dev);
-       dev->vfd_enc = vfd_enc;
-       platform_set_drvdata(pdev, dev);
-
-       dev->m2m_dev_enc = v4l2_m2m_init(&mtk_venc_m2m_ops);
-       if (IS_ERR((__force void *)dev->m2m_dev_enc)) {
-               mtk_v4l2_err("Failed to init mem2mem enc device");
-               ret = PTR_ERR((__force void *)dev->m2m_dev_enc);
-               goto err_enc_mem_init;
-       }
-
-       dev->encode_workqueue =
-                       alloc_ordered_workqueue(MTK_VCODEC_ENC_NAME,
-                                               WQ_MEM_RECLAIM |
-                                               WQ_FREEZABLE);
-       if (!dev->encode_workqueue) {
-               mtk_v4l2_err("Failed to create encode workqueue");
-               ret = -EINVAL;
-               goto err_event_workq;
-       }
-
-       if (of_get_property(pdev->dev.of_node, "dma-ranges", NULL))
-               dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34));
-
-       ret = video_register_device(vfd_enc, VFL_TYPE_VIDEO, -1);
-       if (ret) {
-               mtk_v4l2_err("Failed to register video device");
-               goto err_enc_reg;
-       }
-
-       mtk_v4l2_debug(0, "encoder %d registered as /dev/video%d",
-                      dev->venc_pdata->core_id, vfd_enc->num);
-
-       return 0;
-
-err_enc_reg:
-       destroy_workqueue(dev->encode_workqueue);
-err_event_workq:
-       v4l2_m2m_release(dev->m2m_dev_enc);
-err_enc_mem_init:
-       video_unregister_device(vfd_enc);
-err_enc_alloc:
-       v4l2_device_unregister(&dev->v4l2_dev);
-err_res:
-       pm_runtime_disable(dev->pm.dev);
-err_enc_pm:
-       mtk_vcodec_fw_release(dev->fw_handler);
-       return ret;
-}
-
-static const struct mtk_vcodec_enc_pdata mt8173_avc_pdata = {
-       .chip = MTK_MT8173,
-       .capture_formats = mtk_video_formats_capture_h264,
-       .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_h264),
-       .output_formats = mtk_video_formats_output,
-       .num_output_formats = ARRAY_SIZE(mtk_video_formats_output),
-       .min_bitrate = 64,
-       .max_bitrate = 60000000,
-       .core_id = VENC_SYS,
-};
-
-static const struct mtk_vcodec_enc_pdata mt8173_vp8_pdata = {
-       .chip = MTK_MT8173,
-       .capture_formats = mtk_video_formats_capture_vp8,
-       .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_vp8),
-       .output_formats = mtk_video_formats_output,
-       .num_output_formats = ARRAY_SIZE(mtk_video_formats_output),
-       .min_bitrate = 64,
-       .max_bitrate = 9000000,
-       .core_id = VENC_LT_SYS,
-};
-
-static const struct mtk_vcodec_enc_pdata mt8183_pdata = {
-       .chip = MTK_MT8183,
-       .uses_ext = true,
-       .capture_formats = mtk_video_formats_capture_h264,
-       .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_h264),
-       .output_formats = mtk_video_formats_output,
-       .num_output_formats = ARRAY_SIZE(mtk_video_formats_output),
-       .min_bitrate = 64,
-       .max_bitrate = 40000000,
-       .core_id = VENC_SYS,
-};
-
-static const struct mtk_vcodec_enc_pdata mt8192_pdata = {
-       .chip = MTK_MT8192,
-       .uses_ext = true,
-       .capture_formats = mtk_video_formats_capture_h264,
-       .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_h264),
-       .output_formats = mtk_video_formats_output,
-       .num_output_formats = ARRAY_SIZE(mtk_video_formats_output),
-       .min_bitrate = 64,
-       .max_bitrate = 100000000,
-       .core_id = VENC_SYS,
-};
-
-static const struct mtk_vcodec_enc_pdata mt8195_pdata = {
-       .chip = MTK_MT8195,
-       .uses_ext = true,
-       .capture_formats = mtk_video_formats_capture_h264,
-       .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_h264),
-       .output_formats = mtk_video_formats_output,
-       .num_output_formats = ARRAY_SIZE(mtk_video_formats_output),
-       .min_bitrate = 64,
-       .max_bitrate = 100000000,
-       .core_id = VENC_SYS,
-};
-
-static const struct of_device_id mtk_vcodec_enc_match[] = {
-       {.compatible = "mediatek,mt8173-vcodec-enc",
-                       .data = &mt8173_avc_pdata},
-       {.compatible = "mediatek,mt8173-vcodec-enc-vp8",
-                       .data = &mt8173_vp8_pdata},
-       {.compatible = "mediatek,mt8183-vcodec-enc", .data = &mt8183_pdata},
-       {.compatible = "mediatek,mt8192-vcodec-enc", .data = &mt8192_pdata},
-       {.compatible = "mediatek,mt8195-vcodec-enc", .data = &mt8195_pdata},
-       {},
-};
-MODULE_DEVICE_TABLE(of, mtk_vcodec_enc_match);
-
-static int mtk_vcodec_enc_remove(struct platform_device *pdev)
-{
-       struct mtk_vcodec_dev *dev = platform_get_drvdata(pdev);
-
-       mtk_v4l2_debug_enter();
-       destroy_workqueue(dev->encode_workqueue);
-       if (dev->m2m_dev_enc)
-               v4l2_m2m_release(dev->m2m_dev_enc);
-
-       if (dev->vfd_enc)
-               video_unregister_device(dev->vfd_enc);
-
-       v4l2_device_unregister(&dev->v4l2_dev);
-       pm_runtime_disable(dev->pm.dev);
-       mtk_vcodec_fw_release(dev->fw_handler);
-       return 0;
-}
-
-static struct platform_driver mtk_vcodec_enc_driver = {
-       .probe  = mtk_vcodec_probe,
-       .remove = mtk_vcodec_enc_remove,
-       .driver = {
-               .name   = MTK_VCODEC_ENC_NAME,
-               .of_match_table = mtk_vcodec_enc_match,
-       },
-};
-
-module_platform_driver(mtk_vcodec_enc_driver);
-
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Mediatek video codec V4L2 encoder driver");
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c
deleted file mode 100644 (file)
index 7055954..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
-* Copyright (c) 2016 MediaTek Inc.
-* Author: Tiffany Lin <tiffany.lin@mediatek.com>
-*/
-
-#include <linux/clk.h>
-#include <linux/of_address.h>
-#include <linux/of_platform.h>
-#include <linux/pm_runtime.h>
-
-#include "mtk_vcodec_enc_pm.h"
-#include "mtk_vcodec_util.h"
-
-int mtk_vcodec_init_enc_clk(struct mtk_vcodec_dev *mtkdev)
-{
-       struct platform_device *pdev;
-       struct mtk_vcodec_pm *pm;
-       struct mtk_vcodec_clk *enc_clk;
-       struct mtk_vcodec_clk_info *clk_info;
-       int ret, i;
-
-       pdev = mtkdev->plat_dev;
-       pm = &mtkdev->pm;
-       memset(pm, 0, sizeof(struct mtk_vcodec_pm));
-       pm->dev = &pdev->dev;
-       enc_clk = &pm->venc_clk;
-
-       enc_clk->clk_num = of_property_count_strings(pdev->dev.of_node,
-               "clock-names");
-       if (enc_clk->clk_num > 0) {
-               enc_clk->clk_info = devm_kcalloc(&pdev->dev,
-                       enc_clk->clk_num, sizeof(*clk_info),
-                       GFP_KERNEL);
-               if (!enc_clk->clk_info)
-                       return -ENOMEM;
-       } else {
-               mtk_v4l2_err("Failed to get venc clock count");
-               return -EINVAL;
-       }
-
-       for (i = 0; i < enc_clk->clk_num; i++) {
-               clk_info = &enc_clk->clk_info[i];
-               ret = of_property_read_string_index(pdev->dev.of_node,
-                       "clock-names", i, &clk_info->clk_name);
-               if (ret) {
-                       mtk_v4l2_err("venc failed to get clk name %d", i);
-                       return ret;
-               }
-               clk_info->vcodec_clk = devm_clk_get(&pdev->dev,
-                       clk_info->clk_name);
-               if (IS_ERR(clk_info->vcodec_clk)) {
-                       mtk_v4l2_err("venc devm_clk_get (%d)%s fail", i,
-                               clk_info->clk_name);
-                       return PTR_ERR(clk_info->vcodec_clk);
-               }
-       }
-
-       return 0;
-}
-
-void mtk_vcodec_enc_clock_on(struct mtk_vcodec_pm *pm)
-{
-       struct mtk_vcodec_clk *enc_clk = &pm->venc_clk;
-       int ret, i = 0;
-
-       for (i = 0; i < enc_clk->clk_num; i++) {
-               ret = clk_prepare_enable(enc_clk->clk_info[i].vcodec_clk);
-               if (ret) {
-                       mtk_v4l2_err("venc clk_prepare_enable %d %s fail %d", i,
-                               enc_clk->clk_info[i].clk_name, ret);
-                       goto clkerr;
-               }
-       }
-
-       return;
-
-clkerr:
-       for (i -= 1; i >= 0; i--)
-               clk_disable_unprepare(enc_clk->clk_info[i].vcodec_clk);
-}
-
-void mtk_vcodec_enc_clock_off(struct mtk_vcodec_pm *pm)
-{
-       struct mtk_vcodec_clk *enc_clk = &pm->venc_clk;
-       int i = 0;
-
-       for (i = enc_clk->clk_num - 1; i >= 0; i--)
-               clk_disable_unprepare(enc_clk->clk_info[i].vcodec_clk);
-}
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.h
deleted file mode 100644 (file)
index bc455ce..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
-* Copyright (c) 2016 MediaTek Inc.
-* Author: Tiffany Lin <tiffany.lin@mediatek.com>
-*/
-
-#ifndef _MTK_VCODEC_ENC_PM_H_
-#define _MTK_VCODEC_ENC_PM_H_
-
-#include "mtk_vcodec_drv.h"
-
-int mtk_vcodec_init_enc_clk(struct mtk_vcodec_dev *dev);
-
-void mtk_vcodec_enc_clock_on(struct mtk_vcodec_pm *pm);
-void mtk_vcodec_enc_clock_off(struct mtk_vcodec_pm *pm);
-
-#endif /* _MTK_VCODEC_ENC_PM_H_ */
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw.c
deleted file mode 100644 (file)
index 94b39ae..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-#include "mtk_vcodec_fw.h"
-#include "mtk_vcodec_fw_priv.h"
-#include "mtk_vcodec_util.h"
-#include "mtk_vcodec_drv.h"
-
-struct mtk_vcodec_fw *mtk_vcodec_fw_select(struct mtk_vcodec_dev *dev,
-                                          enum mtk_vcodec_fw_type type,
-                                          enum mtk_vcodec_fw_use fw_use)
-{
-       switch (type) {
-       case VPU:
-               return mtk_vcodec_fw_vpu_init(dev, fw_use);
-       case SCP:
-               return mtk_vcodec_fw_scp_init(dev);
-       default:
-               mtk_v4l2_err("invalid vcodec fw type");
-               return ERR_PTR(-EINVAL);
-       }
-}
-EXPORT_SYMBOL_GPL(mtk_vcodec_fw_select);
-
-void mtk_vcodec_fw_release(struct mtk_vcodec_fw *fw)
-{
-       fw->ops->release(fw);
-}
-EXPORT_SYMBOL_GPL(mtk_vcodec_fw_release);
-
-int mtk_vcodec_fw_load_firmware(struct mtk_vcodec_fw *fw)
-{
-       return fw->ops->load_firmware(fw);
-}
-EXPORT_SYMBOL_GPL(mtk_vcodec_fw_load_firmware);
-
-unsigned int mtk_vcodec_fw_get_vdec_capa(struct mtk_vcodec_fw *fw)
-{
-       return fw->ops->get_vdec_capa(fw);
-}
-EXPORT_SYMBOL_GPL(mtk_vcodec_fw_get_vdec_capa);
-
-unsigned int mtk_vcodec_fw_get_venc_capa(struct mtk_vcodec_fw *fw)
-{
-       return fw->ops->get_venc_capa(fw);
-}
-EXPORT_SYMBOL_GPL(mtk_vcodec_fw_get_venc_capa);
-
-void *mtk_vcodec_fw_map_dm_addr(struct mtk_vcodec_fw *fw, u32 mem_addr)
-{
-       return fw->ops->map_dm_addr(fw, mem_addr);
-}
-EXPORT_SYMBOL_GPL(mtk_vcodec_fw_map_dm_addr);
-
-int mtk_vcodec_fw_ipi_register(struct mtk_vcodec_fw *fw, int id,
-                              mtk_vcodec_ipi_handler handler,
-                              const char *name, void *priv)
-{
-       return fw->ops->ipi_register(fw, id, handler, name, priv);
-}
-EXPORT_SYMBOL_GPL(mtk_vcodec_fw_ipi_register);
-
-int mtk_vcodec_fw_ipi_send(struct mtk_vcodec_fw *fw, int id, void *buf,
-                          unsigned int len, unsigned int wait)
-{
-       return fw->ops->ipi_send(fw, id, buf, len, wait);
-}
-EXPORT_SYMBOL_GPL(mtk_vcodec_fw_ipi_send);
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw.h
deleted file mode 100644 (file)
index 539bb62..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-
-#ifndef _MTK_VCODEC_FW_H_
-#define _MTK_VCODEC_FW_H_
-
-#include <linux/remoteproc.h>
-#include <linux/remoteproc/mtk_scp.h>
-
-#include "../mtk-vpu/mtk_vpu.h"
-
-struct mtk_vcodec_dev;
-
-enum mtk_vcodec_fw_type {
-       VPU,
-       SCP,
-};
-
-enum mtk_vcodec_fw_use {
-       DECODER,
-       ENCODER,
-};
-
-struct mtk_vcodec_fw;
-
-typedef void (*mtk_vcodec_ipi_handler) (void *data,
-       unsigned int len, void *priv);
-
-struct mtk_vcodec_fw *mtk_vcodec_fw_select(struct mtk_vcodec_dev *dev,
-                                          enum mtk_vcodec_fw_type type,
-                                          enum mtk_vcodec_fw_use fw_use);
-void mtk_vcodec_fw_release(struct mtk_vcodec_fw *fw);
-
-int mtk_vcodec_fw_load_firmware(struct mtk_vcodec_fw *fw);
-unsigned int mtk_vcodec_fw_get_vdec_capa(struct mtk_vcodec_fw *fw);
-unsigned int mtk_vcodec_fw_get_venc_capa(struct mtk_vcodec_fw *fw);
-void *mtk_vcodec_fw_map_dm_addr(struct mtk_vcodec_fw *fw, u32 mem_addr);
-int mtk_vcodec_fw_ipi_register(struct mtk_vcodec_fw *fw, int id,
-                              mtk_vcodec_ipi_handler handler,
-                              const char *name, void *priv);
-int mtk_vcodec_fw_ipi_send(struct mtk_vcodec_fw *fw, int id,
-                          void *buf, unsigned int len, unsigned int wait);
-
-#endif /* _MTK_VCODEC_FW_H_ */
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw_priv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw_priv.h
deleted file mode 100644 (file)
index b41e661..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-
-#ifndef _MTK_VCODEC_FW_PRIV_H_
-#define _MTK_VCODEC_FW_PRIV_H_
-
-#include "mtk_vcodec_fw.h"
-
-struct mtk_vcodec_dev;
-
-struct mtk_vcodec_fw {
-       enum mtk_vcodec_fw_type type;
-       const struct mtk_vcodec_fw_ops *ops;
-       struct platform_device *pdev;
-       struct mtk_scp *scp;
-};
-
-struct mtk_vcodec_fw_ops {
-       int (*load_firmware)(struct mtk_vcodec_fw *fw);
-       unsigned int (*get_vdec_capa)(struct mtk_vcodec_fw *fw);
-       unsigned int (*get_venc_capa)(struct mtk_vcodec_fw *fw);
-       void *(*map_dm_addr)(struct mtk_vcodec_fw *fw, u32 dtcm_dmem_addr);
-       int (*ipi_register)(struct mtk_vcodec_fw *fw, int id,
-                           mtk_vcodec_ipi_handler handler, const char *name,
-                           void *priv);
-       int (*ipi_send)(struct mtk_vcodec_fw *fw, int id, void *buf,
-                       unsigned int len, unsigned int wait);
-       void (*release)(struct mtk_vcodec_fw *fw);
-};
-
-#if IS_ENABLED(CONFIG_VIDEO_MEDIATEK_VCODEC_VPU)
-struct mtk_vcodec_fw *mtk_vcodec_fw_vpu_init(struct mtk_vcodec_dev *dev,
-                                            enum mtk_vcodec_fw_use fw_use);
-#else
-static inline struct mtk_vcodec_fw *
-mtk_vcodec_fw_vpu_init(struct mtk_vcodec_dev *dev,
-                      enum mtk_vcodec_fw_use fw_use)
-{
-       return ERR_PTR(-ENODEV);
-}
-#endif /* CONFIG_VIDEO_MEDIATEK_VCODEC_VPU */
-
-#if IS_ENABLED(CONFIG_VIDEO_MEDIATEK_VCODEC_SCP)
-struct mtk_vcodec_fw *mtk_vcodec_fw_scp_init(struct mtk_vcodec_dev *dev);
-#else
-static inline struct mtk_vcodec_fw *
-mtk_vcodec_fw_scp_init(struct mtk_vcodec_dev *dev)
-{
-       return ERR_PTR(-ENODEV);
-}
-#endif /* CONFIG_VIDEO_MEDIATEK_VCODEC_SCP */
-
-#endif /* _MTK_VCODEC_FW_PRIV_H_ */
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw_scp.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw_scp.c
deleted file mode 100644 (file)
index d8e66b6..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-#include "mtk_vcodec_fw_priv.h"
-#include "mtk_vcodec_util.h"
-#include "mtk_vcodec_drv.h"
-
-static int mtk_vcodec_scp_load_firmware(struct mtk_vcodec_fw *fw)
-{
-       return rproc_boot(scp_get_rproc(fw->scp));
-}
-
-static unsigned int mtk_vcodec_scp_get_vdec_capa(struct mtk_vcodec_fw *fw)
-{
-       return scp_get_vdec_hw_capa(fw->scp);
-}
-
-static unsigned int mtk_vcodec_scp_get_venc_capa(struct mtk_vcodec_fw *fw)
-{
-       return scp_get_venc_hw_capa(fw->scp);
-}
-
-static void *mtk_vcodec_vpu_scp_dm_addr(struct mtk_vcodec_fw *fw,
-                                       u32 dtcm_dmem_addr)
-{
-       return scp_mapping_dm_addr(fw->scp, dtcm_dmem_addr);
-}
-
-static int mtk_vcodec_scp_set_ipi_register(struct mtk_vcodec_fw *fw, int id,
-                                          mtk_vcodec_ipi_handler handler,
-                                          const char *name, void *priv)
-{
-       return scp_ipi_register(fw->scp, id, handler, priv);
-}
-
-static int mtk_vcodec_scp_ipi_send(struct mtk_vcodec_fw *fw, int id, void *buf,
-                                  unsigned int len, unsigned int wait)
-{
-       return scp_ipi_send(fw->scp, id, buf, len, wait);
-}
-
-static void mtk_vcodec_scp_release(struct mtk_vcodec_fw *fw)
-{
-       scp_put(fw->scp);
-}
-
-static const struct mtk_vcodec_fw_ops mtk_vcodec_rproc_msg = {
-       .load_firmware = mtk_vcodec_scp_load_firmware,
-       .get_vdec_capa = mtk_vcodec_scp_get_vdec_capa,
-       .get_venc_capa = mtk_vcodec_scp_get_venc_capa,
-       .map_dm_addr = mtk_vcodec_vpu_scp_dm_addr,
-       .ipi_register = mtk_vcodec_scp_set_ipi_register,
-       .ipi_send = mtk_vcodec_scp_ipi_send,
-       .release = mtk_vcodec_scp_release,
-};
-
-struct mtk_vcodec_fw *mtk_vcodec_fw_scp_init(struct mtk_vcodec_dev *dev)
-{
-       struct mtk_vcodec_fw *fw;
-       struct mtk_scp *scp;
-
-       scp = scp_get(dev->plat_dev);
-       if (!scp) {
-               mtk_v4l2_err("could not get vdec scp handle");
-               return ERR_PTR(-EPROBE_DEFER);
-       }
-
-       fw = devm_kzalloc(&dev->plat_dev->dev, sizeof(*fw), GFP_KERNEL);
-       fw->type = SCP;
-       fw->ops = &mtk_vcodec_rproc_msg;
-       fw->scp = scp;
-
-       return fw;
-}
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw_vpu.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw_vpu.c
deleted file mode 100644 (file)
index cfc7ebe..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-#include "mtk_vcodec_fw_priv.h"
-#include "mtk_vcodec_util.h"
-#include "mtk_vcodec_drv.h"
-
-static int mtk_vcodec_vpu_load_firmware(struct mtk_vcodec_fw *fw)
-{
-       return vpu_load_firmware(fw->pdev);
-}
-
-static unsigned int mtk_vcodec_vpu_get_vdec_capa(struct mtk_vcodec_fw *fw)
-{
-       return vpu_get_vdec_hw_capa(fw->pdev);
-}
-
-static unsigned int mtk_vcodec_vpu_get_venc_capa(struct mtk_vcodec_fw *fw)
-{
-       return vpu_get_venc_hw_capa(fw->pdev);
-}
-
-static void *mtk_vcodec_vpu_map_dm_addr(struct mtk_vcodec_fw *fw,
-                                       u32 dtcm_dmem_addr)
-{
-       return vpu_mapping_dm_addr(fw->pdev, dtcm_dmem_addr);
-}
-
-static int mtk_vcodec_vpu_set_ipi_register(struct mtk_vcodec_fw *fw, int id,
-                                          mtk_vcodec_ipi_handler handler,
-                                          const char *name, void *priv)
-{
-       /*
-        * The handler we receive takes a void * as its first argument. We
-        * cannot change this because it needs to be passed down to the rproc
-        * subsystem when SCP is used. VPU takes a const argument, which is
-        * more constrained, so the conversion below is safe.
-        */
-       ipi_handler_t handler_const = (ipi_handler_t)handler;
-
-       return vpu_ipi_register(fw->pdev, id, handler_const, name, priv);
-}
-
-static int mtk_vcodec_vpu_ipi_send(struct mtk_vcodec_fw *fw, int id, void *buf,
-                                  unsigned int len, unsigned int wait)
-{
-       return vpu_ipi_send(fw->pdev, id, buf, len);
-}
-
-static void mtk_vcodec_vpu_release(struct mtk_vcodec_fw *fw)
-{
-       put_device(&fw->pdev->dev);
-}
-
-static void mtk_vcodec_vpu_reset_handler(void *priv)
-{
-       struct mtk_vcodec_dev *dev = priv;
-       struct mtk_vcodec_ctx *ctx;
-
-       mtk_v4l2_err("Watchdog timeout!!");
-
-       mutex_lock(&dev->dev_mutex);
-       list_for_each_entry(ctx, &dev->ctx_list, list) {
-               ctx->state = MTK_STATE_ABORT;
-               mtk_v4l2_debug(0, "[%d] Change to state MTK_STATE_ABORT",
-                              ctx->id);
-       }
-       mutex_unlock(&dev->dev_mutex);
-}
-
-static const struct mtk_vcodec_fw_ops mtk_vcodec_vpu_msg = {
-       .load_firmware = mtk_vcodec_vpu_load_firmware,
-       .get_vdec_capa = mtk_vcodec_vpu_get_vdec_capa,
-       .get_venc_capa = mtk_vcodec_vpu_get_venc_capa,
-       .map_dm_addr = mtk_vcodec_vpu_map_dm_addr,
-       .ipi_register = mtk_vcodec_vpu_set_ipi_register,
-       .ipi_send = mtk_vcodec_vpu_ipi_send,
-       .release = mtk_vcodec_vpu_release,
-};
-
-struct mtk_vcodec_fw *mtk_vcodec_fw_vpu_init(struct mtk_vcodec_dev *dev,
-                                            enum mtk_vcodec_fw_use fw_use)
-{
-       struct platform_device *fw_pdev;
-       struct mtk_vcodec_fw *fw;
-       enum rst_id rst_id;
-
-       switch (fw_use) {
-       case ENCODER:
-               rst_id = VPU_RST_ENC;
-               break;
-       case DECODER:
-       default:
-               rst_id = VPU_RST_DEC;
-               break;
-       }
-
-       fw_pdev = vpu_get_plat_device(dev->plat_dev);
-       if (!fw_pdev) {
-               mtk_v4l2_err("firmware device is not ready");
-               return ERR_PTR(-EINVAL);
-       }
-       vpu_wdt_reg_handler(fw_pdev, mtk_vcodec_vpu_reset_handler, dev, rst_id);
-
-       fw = devm_kzalloc(&dev->plat_dev->dev, sizeof(*fw), GFP_KERNEL);
-       if (!fw)
-               return ERR_PTR(-ENOMEM);
-       fw->type = VPU;
-       fw->ops = &mtk_vcodec_vpu_msg;
-       fw->pdev = fw_pdev;
-
-       return fw;
-}
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.c
deleted file mode 100644 (file)
index 552b4c9..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
-* Copyright (c) 2016 MediaTek Inc.
-* Author: Tiffany Lin <tiffany.lin@mediatek.com>
-*/
-
-#include <linux/errno.h>
-#include <linux/wait.h>
-
-#include "mtk_vcodec_drv.h"
-#include "mtk_vcodec_intr.h"
-#include "mtk_vcodec_util.h"
-
-int mtk_vcodec_wait_for_done_ctx(struct mtk_vcodec_ctx *ctx,
-                                int command, unsigned int timeout_ms,
-                                unsigned int hw_id)
-{
-       long timeout_jiff, ret;
-       int status = 0;
-
-       timeout_jiff = msecs_to_jiffies(timeout_ms);
-       ret = wait_event_interruptible_timeout(ctx->queue[hw_id],
-                                              ctx->int_cond[hw_id],
-                                              timeout_jiff);
-
-       if (!ret) {
-               status = -1;    /* timeout */
-               mtk_v4l2_err("[%d] cmd=%d, type=%d, dec timeout=%ums (%d %d)",
-                            ctx->id, command, ctx->type, timeout_ms,
-                            ctx->int_cond[hw_id], ctx->int_type[hw_id]);
-       } else if (-ERESTARTSYS == ret) {
-               status = -1;
-               mtk_v4l2_err("[%d] cmd=%d, type=%d, dec inter fail (%d %d)",
-                            ctx->id, command, ctx->type,
-                            ctx->int_cond[hw_id], ctx->int_type[hw_id]);
-       }
-
-       ctx->int_cond[hw_id] = 0;
-       ctx->int_type[hw_id] = 0;
-
-       return status;
-}
-EXPORT_SYMBOL(mtk_vcodec_wait_for_done_ctx);
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.h
deleted file mode 100644 (file)
index 9681f49..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
-* Copyright (c) 2016 MediaTek Inc.
-* Author: Tiffany Lin <tiffany.lin@mediatek.com>
-*/
-
-#ifndef _MTK_VCODEC_INTR_H_
-#define _MTK_VCODEC_INTR_H_
-
-#define MTK_INST_IRQ_RECEIVED          0x1
-
-struct mtk_vcodec_ctx;
-
-/* timeout is ms */
-int mtk_vcodec_wait_for_done_ctx(struct mtk_vcodec_ctx *ctx,
-                                int command, unsigned int timeout_ms,
-                                unsigned int hw_id);
-
-#endif /* _MTK_VCODEC_INTR_H_ */
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c
deleted file mode 100644 (file)
index ace78c4..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
-* Copyright (c) 2016 MediaTek Inc.
-* Author: PC Chen <pc.chen@mediatek.com>
-*      Tiffany Lin <tiffany.lin@mediatek.com>
-*/
-
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-
-#include "mtk_vcodec_dec_hw.h"
-#include "mtk_vcodec_drv.h"
-#include "mtk_vcodec_util.h"
-
-void __iomem *mtk_vcodec_get_reg_addr(struct mtk_vcodec_ctx *data,
-                                       unsigned int reg_idx)
-{
-       struct mtk_vcodec_ctx *ctx = (struct mtk_vcodec_ctx *)data;
-
-       if (!data || reg_idx >= NUM_MAX_VCODEC_REG_BASE) {
-               mtk_v4l2_err("Invalid arguments, reg_idx=%d", reg_idx);
-               return NULL;
-       }
-       return ctx->dev->reg_base[reg_idx];
-}
-EXPORT_SYMBOL(mtk_vcodec_get_reg_addr);
-
-int mtk_vcodec_mem_alloc(struct mtk_vcodec_ctx *data,
-                       struct mtk_vcodec_mem *mem)
-{
-       unsigned long size = mem->size;
-       struct mtk_vcodec_ctx *ctx = (struct mtk_vcodec_ctx *)data;
-       struct device *dev = &ctx->dev->plat_dev->dev;
-
-       mem->va = dma_alloc_coherent(dev, size, &mem->dma_addr, GFP_KERNEL);
-       if (!mem->va) {
-               mtk_v4l2_err("%s dma_alloc size=%ld failed!", dev_name(dev),
-                            size);
-               return -ENOMEM;
-       }
-
-       mtk_v4l2_debug(3, "[%d]  - va      = %p", ctx->id, mem->va);
-       mtk_v4l2_debug(3, "[%d]  - dma     = 0x%lx", ctx->id,
-                      (unsigned long)mem->dma_addr);
-       mtk_v4l2_debug(3, "[%d]    size = 0x%lx", ctx->id, size);
-
-       return 0;
-}
-EXPORT_SYMBOL(mtk_vcodec_mem_alloc);
-
-void mtk_vcodec_mem_free(struct mtk_vcodec_ctx *data,
-                       struct mtk_vcodec_mem *mem)
-{
-       unsigned long size = mem->size;
-       struct mtk_vcodec_ctx *ctx = (struct mtk_vcodec_ctx *)data;
-       struct device *dev = &ctx->dev->plat_dev->dev;
-
-       if (!mem->va) {
-               mtk_v4l2_err("%s dma_free size=%ld failed!", dev_name(dev),
-                            size);
-               return;
-       }
-
-       mtk_v4l2_debug(3, "[%d]  - va      = %p", ctx->id, mem->va);
-       mtk_v4l2_debug(3, "[%d]  - dma     = 0x%lx", ctx->id,
-                      (unsigned long)mem->dma_addr);
-       mtk_v4l2_debug(3, "[%d]    size = 0x%lx", ctx->id, size);
-
-       dma_free_coherent(dev, size, mem->va, mem->dma_addr);
-       mem->va = NULL;
-       mem->dma_addr = 0;
-       mem->size = 0;
-}
-EXPORT_SYMBOL(mtk_vcodec_mem_free);
-
-void *mtk_vcodec_get_hw_dev(struct mtk_vcodec_dev *dev, int hw_idx)
-{
-       if (hw_idx >= MTK_VDEC_HW_MAX || hw_idx < 0 || !dev->subdev_dev[hw_idx]) {
-               mtk_v4l2_err("hw idx is out of range:%d", hw_idx);
-               return NULL;
-       }
-
-       return dev->subdev_dev[hw_idx];
-}
-EXPORT_SYMBOL(mtk_vcodec_get_hw_dev);
-
-void mtk_vcodec_set_curr_ctx(struct mtk_vcodec_dev *vdec_dev,
-                            struct mtk_vcodec_ctx *ctx, int hw_idx)
-{
-       unsigned long flags;
-       struct mtk_vdec_hw_dev *subdev_dev;
-
-       spin_lock_irqsave(&vdec_dev->irqlock, flags);
-       if (vdec_dev->vdec_pdata->is_subdev_supported) {
-               subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx);
-               if (!subdev_dev) {
-                       mtk_v4l2_err("Failed to get hw dev");
-                       spin_unlock_irqrestore(&vdec_dev->irqlock, flags);
-                       return;
-               }
-               subdev_dev->curr_ctx = ctx;
-       } else {
-               vdec_dev->curr_ctx = ctx;
-       }
-       spin_unlock_irqrestore(&vdec_dev->irqlock, flags);
-}
-EXPORT_SYMBOL(mtk_vcodec_set_curr_ctx);
-
-struct mtk_vcodec_ctx *mtk_vcodec_get_curr_ctx(struct mtk_vcodec_dev *vdec_dev,
-                                              unsigned int hw_idx)
-{
-       unsigned long flags;
-       struct mtk_vcodec_ctx *ctx;
-       struct mtk_vdec_hw_dev *subdev_dev;
-
-       spin_lock_irqsave(&vdec_dev->irqlock, flags);
-       if (vdec_dev->vdec_pdata->is_subdev_supported) {
-               subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx);
-               if (!subdev_dev) {
-                       mtk_v4l2_err("Failed to get hw dev");
-                       spin_unlock_irqrestore(&vdec_dev->irqlock, flags);
-                       return NULL;
-               }
-               ctx = subdev_dev->curr_ctx;
-       } else {
-               ctx = vdec_dev->curr_ctx;
-       }
-       spin_unlock_irqrestore(&vdec_dev->irqlock, flags);
-       return ctx;
-}
-EXPORT_SYMBOL(mtk_vcodec_get_curr_ctx);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Mediatek video codec driver");
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h
deleted file mode 100644 (file)
index 7195662..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
-* Copyright (c) 2016 MediaTek Inc.
-* Author: PC Chen <pc.chen@mediatek.com>
-*      Tiffany Lin <tiffany.lin@mediatek.com>
-*/
-
-#ifndef _MTK_VCODEC_UTIL_H_
-#define _MTK_VCODEC_UTIL_H_
-
-#include <linux/types.h>
-#include <linux/dma-direction.h>
-
-struct mtk_vcodec_mem {
-       size_t size;
-       void *va;
-       dma_addr_t dma_addr;
-};
-
-struct mtk_vcodec_fb {
-       size_t size;
-       dma_addr_t dma_addr;
-};
-
-struct mtk_vcodec_ctx;
-struct mtk_vcodec_dev;
-
-#undef pr_fmt
-#define pr_fmt(fmt) "%s(),%d: " fmt, __func__, __LINE__
-
-#define mtk_v4l2_err(fmt, args...)                \
-       pr_err("[MTK_V4L2][ERROR] " fmt "\n", ##args)
-
-#define mtk_vcodec_err(h, fmt, args...)                                \
-       pr_err("[MTK_VCODEC][ERROR][%d]: " fmt "\n",            \
-              ((struct mtk_vcodec_ctx *)(h)->ctx)->id, ##args)
-
-
-#define mtk_v4l2_debug(level, fmt, args...) pr_debug(fmt, ##args)
-
-#define mtk_v4l2_debug_enter()  mtk_v4l2_debug(3, "+")
-#define mtk_v4l2_debug_leave()  mtk_v4l2_debug(3, "-")
-
-#define mtk_vcodec_debug(h, fmt, args...)                      \
-       pr_debug("[MTK_VCODEC][%d]: " fmt "\n",                 \
-               ((struct mtk_vcodec_ctx *)(h)->ctx)->id, ##args)
-
-#define mtk_vcodec_debug_enter(h)  mtk_vcodec_debug(h, "+")
-#define mtk_vcodec_debug_leave(h)  mtk_vcodec_debug(h, "-")
-
-void __iomem *mtk_vcodec_get_reg_addr(struct mtk_vcodec_ctx *data,
-                               unsigned int reg_idx);
-int mtk_vcodec_mem_alloc(struct mtk_vcodec_ctx *data,
-                               struct mtk_vcodec_mem *mem);
-void mtk_vcodec_mem_free(struct mtk_vcodec_ctx *data,
-                               struct mtk_vcodec_mem *mem);
-void mtk_vcodec_set_curr_ctx(struct mtk_vcodec_dev *vdec_dev,
-                            struct mtk_vcodec_ctx *ctx, int hw_idx);
-struct mtk_vcodec_ctx *mtk_vcodec_get_curr_ctx(struct mtk_vcodec_dev *vdec_dev,
-                                              unsigned int hw_idx);
-void *mtk_vcodec_get_hw_dev(struct mtk_vcodec_dev *dev, int hw_idx);
-
-#endif /* _MTK_VCODEC_UTIL_H_ */
diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c
deleted file mode 100644 (file)
index 481655b..0000000
+++ /dev/null
@@ -1,503 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2016 MediaTek Inc.
- * Author: PC Chen <pc.chen@mediatek.com>
- */
-
-#include <linux/module.h>
-#include <linux/slab.h>
-
-#include "../vdec_drv_if.h"
-#include "../mtk_vcodec_util.h"
-#include "../mtk_vcodec_dec.h"
-#include "../mtk_vcodec_intr.h"
-#include "../vdec_vpu_if.h"
-#include "../vdec_drv_base.h"
-
-#define NAL_NON_IDR_SLICE                      0x01
-#define NAL_IDR_SLICE                          0x05
-#define NAL_H264_PPS                           0x08
-#define NAL_TYPE(value)                                ((value) & 0x1F)
-
-#define BUF_PREDICTION_SZ                      (32 * 1024)
-
-#define MB_UNIT_LEN                            16
-
-/* motion vector size (bytes) for every macro block */
-#define HW_MB_STORE_SZ                         64
-
-#define H264_MAX_FB_NUM                                17
-#define HDR_PARSING_BUF_SZ                     1024
-
-#define DEC_ERR_RET(ret)                       ((ret) >> 16)
-#define H264_ERR_NOT_VALID                     3
-
-/**
- * struct h264_fb - h264 decode frame buffer information
- * @vdec_fb_va  : virtual address of struct vdec_fb
- * @y_fb_dma    : dma address of Y frame buffer (luma)
- * @c_fb_dma    : dma address of C frame buffer (chroma)
- * @poc         : picture order count of frame buffer
- * @reserved    : for 8 bytes alignment
- */
-struct h264_fb {
-       uint64_t vdec_fb_va;
-       uint64_t y_fb_dma;
-       uint64_t c_fb_dma;
-       int32_t poc;
-       uint32_t reserved;
-};
-
-/**
- * struct h264_ring_fb_list - ring frame buffer list
- * @fb_list   : frame buffer array
- * @read_idx  : read index
- * @write_idx : write index
- * @count     : buffer count in list
- * @reserved  : for 8 bytes alignment
- */
-struct h264_ring_fb_list {
-       struct h264_fb fb_list[H264_MAX_FB_NUM];
-       unsigned int read_idx;
-       unsigned int write_idx;
-       unsigned int count;
-       unsigned int reserved;
-};
-
-/**
- * struct vdec_h264_dec_info - decode information
- * @dpb_sz             : decoding picture buffer size
- * @resolution_changed  : resolution change happen
- * @realloc_mv_buf     : flag to notify driver to re-allocate mv buffer
- * @reserved           : for 8 bytes alignment
- * @bs_dma             : Input bit-stream buffer dma address
- * @y_fb_dma           : Y frame buffer dma address
- * @c_fb_dma           : C frame buffer dma address
- * @vdec_fb_va         : VDEC frame buffer struct virtual address
- */
-struct vdec_h264_dec_info {
-       uint32_t dpb_sz;
-       uint32_t resolution_changed;
-       uint32_t realloc_mv_buf;
-       uint32_t reserved;
-       uint64_t bs_dma;
-       uint64_t y_fb_dma;
-       uint64_t c_fb_dma;
-       uint64_t vdec_fb_va;
-};
-
-/**
- * struct vdec_h264_vsi - shared memory for decode information exchange
- *                        between VPU and Host.
- *                        The memory is allocated by VPU then mapping to Host
- *                        in vpu_dec_init() and freed in vpu_dec_deinit()
- *                        by VPU.
- *                        AP-W/R : AP is writer/reader on this item
- *                        VPU-W/R: VPU is write/reader on this item
- * @hdr_buf      : Header parsing buffer (AP-W, VPU-R)
- * @pred_buf_dma : HW working predication buffer dma address (AP-W, VPU-R)
- * @mv_buf_dma   : HW working motion vector buffer dma address (AP-W, VPU-R)
- * @list_free    : free frame buffer ring list (AP-W/R, VPU-W)
- * @list_disp    : display frame buffer ring list (AP-R, VPU-W)
- * @dec          : decode information (AP-R, VPU-W)
- * @pic          : picture information (AP-R, VPU-W)
- * @crop         : crop information (AP-R, VPU-W)
- */
-struct vdec_h264_vsi {
-       unsigned char hdr_buf[HDR_PARSING_BUF_SZ];
-       uint64_t pred_buf_dma;
-       uint64_t mv_buf_dma[H264_MAX_FB_NUM];
-       struct h264_ring_fb_list list_free;
-       struct h264_ring_fb_list list_disp;
-       struct vdec_h264_dec_info dec;
-       struct vdec_pic_info pic;
-       struct v4l2_rect crop;
-};
-
-/**
- * struct vdec_h264_inst - h264 decoder instance
- * @num_nalu : how many nalus be decoded
- * @ctx      : point to mtk_vcodec_ctx
- * @pred_buf : HW working predication buffer
- * @mv_buf   : HW working motion vector buffer
- * @vpu      : VPU instance
- * @vsi      : VPU shared information
- */
-struct vdec_h264_inst {
-       unsigned int num_nalu;
-       struct mtk_vcodec_ctx *ctx;
-       struct mtk_vcodec_mem pred_buf;
-       struct mtk_vcodec_mem mv_buf[H264_MAX_FB_NUM];
-       struct vdec_vpu_inst vpu;
-       struct vdec_h264_vsi *vsi;
-};
-
-static unsigned int get_mv_buf_size(unsigned int width, unsigned int height)
-{
-       return HW_MB_STORE_SZ * (width/MB_UNIT_LEN) * (height/MB_UNIT_LEN);
-}
-
-static int allocate_predication_buf(struct vdec_h264_inst *inst)
-{
-       int err = 0;
-
-       inst->pred_buf.size = BUF_PREDICTION_SZ;
-       err = mtk_vcodec_mem_alloc(inst->ctx, &inst->pred_buf);
-       if (err) {
-               mtk_vcodec_err(inst, "failed to allocate ppl buf");
-               return err;
-       }
-
-       inst->vsi->pred_buf_dma = inst->pred_buf.dma_addr;
-       return 0;
-}
-
-static void free_predication_buf(struct vdec_h264_inst *inst)
-{
-       struct mtk_vcodec_mem *mem = NULL;
-
-       mtk_vcodec_debug_enter(inst);
-
-       inst->vsi->pred_buf_dma = 0;
-       mem = &inst->pred_buf;
-       if (mem->va)
-               mtk_vcodec_mem_free(inst->ctx, mem);
-}
-
-static int alloc_mv_buf(struct vdec_h264_inst *inst, struct vdec_pic_info *pic)
-{
-       int i;
-       int err;
-       struct mtk_vcodec_mem *mem = NULL;
-       unsigned int buf_sz = get_mv_buf_size(pic->buf_w, pic->buf_h);
-
-       for (i = 0; i < H264_MAX_FB_NUM; i++) {
-               mem = &inst->mv_buf[i];
-               if (mem->va)
-                       mtk_vcodec_mem_free(inst->ctx, mem);
-               mem->size = buf_sz;
-               err = mtk_vcodec_mem_alloc(inst->ctx, mem);
-               if (err) {
-                       mtk_vcodec_err(inst, "failed to allocate mv buf");
-                       return err;
-               }
-               inst->vsi->mv_buf_dma[i] = mem->dma_addr;
-       }
-
-       return 0;
-}
-
-static void free_mv_buf(struct vdec_h264_inst *inst)
-{
-       int i;
-       struct mtk_vcodec_mem *mem = NULL;
-
-       for (i = 0; i < H264_MAX_FB_NUM; i++) {
-               inst->vsi->mv_buf_dma[i] = 0;
-               mem = &inst->mv_buf[i];
-               if (mem->va)
-                       mtk_vcodec_mem_free(inst->ctx, mem);
-       }
-}
-
-static int check_list_validity(struct vdec_h264_inst *inst, bool disp_list)
-{
-       struct h264_ring_fb_list *list;
-
-       list = disp_list ? &inst->vsi->list_disp : &inst->vsi->list_free;
-
-       if (list->count > H264_MAX_FB_NUM ||
-           list->read_idx >= H264_MAX_FB_NUM ||
-           list->write_idx >= H264_MAX_FB_NUM) {
-               mtk_vcodec_err(inst, "%s list err: cnt=%d r_idx=%d w_idx=%d",
-                              disp_list ? "disp" : "free", list->count,
-                              list->read_idx, list->write_idx);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static void put_fb_to_free(struct vdec_h264_inst *inst, struct vdec_fb *fb)
-{
-       struct h264_ring_fb_list *list;
-
-       if (fb) {
-               if (check_list_validity(inst, false))
-                       return;
-
-               list = &inst->vsi->list_free;
-               if (list->count == H264_MAX_FB_NUM) {
-                       mtk_vcodec_err(inst, "[FB] put fb free_list full");
-                       return;
-               }
-
-               mtk_vcodec_debug(inst, "[FB] put fb into free_list @(%p, %llx)",
-                                fb->base_y.va, (u64)fb->base_y.dma_addr);
-
-               list->fb_list[list->write_idx].vdec_fb_va = (u64)(uintptr_t)fb;
-               list->write_idx = (list->write_idx == H264_MAX_FB_NUM - 1) ?
-                                 0 : list->write_idx + 1;
-               list->count++;
-       }
-}
-
-static void get_pic_info(struct vdec_h264_inst *inst,
-                        struct vdec_pic_info *pic)
-{
-       *pic = inst->vsi->pic;
-       mtk_vcodec_debug(inst, "pic(%d, %d), buf(%d, %d)",
-                        pic->pic_w, pic->pic_h, pic->buf_w, pic->buf_h);
-       mtk_vcodec_debug(inst, "fb size: Y(%d), C(%d)",
-                        pic->fb_sz[0], pic->fb_sz[1]);
-}
-
-static void get_crop_info(struct vdec_h264_inst *inst, struct v4l2_rect *cr)
-{
-       cr->left = inst->vsi->crop.left;
-       cr->top = inst->vsi->crop.top;
-       cr->width = inst->vsi->crop.width;
-       cr->height = inst->vsi->crop.height;
-
-       mtk_vcodec_debug(inst, "l=%d, t=%d, w=%d, h=%d",
-                        cr->left, cr->top, cr->width, cr->height);
-}
-
-static void get_dpb_size(struct vdec_h264_inst *inst, unsigned int *dpb_sz)
-{
-       *dpb_sz = inst->vsi->dec.dpb_sz;
-       mtk_vcodec_debug(inst, "sz=%d", *dpb_sz);
-}
-
-static int vdec_h264_init(struct mtk_vcodec_ctx *ctx)
-{
-       struct vdec_h264_inst *inst = NULL;
-       int err;
-
-       inst = kzalloc(sizeof(*inst), GFP_KERNEL);
-       if (!inst)
-               return -ENOMEM;
-
-       inst->ctx = ctx;
-
-       inst->vpu.id = IPI_VDEC_H264;
-       inst->vpu.ctx = ctx;
-
-       err = vpu_dec_init(&inst->vpu);
-       if (err) {
-               mtk_vcodec_err(inst, "vdec_h264 init err=%d", err);
-               goto error_free_inst;
-       }
-
-       inst->vsi = (struct vdec_h264_vsi *)inst->vpu.vsi;
-       err = allocate_predication_buf(inst);
-       if (err)
-               goto error_deinit;
-
-       mtk_vcodec_debug(inst, "H264 Instance >> %p", inst);
-
-       ctx->drv_handle = inst;
-       return 0;
-
-error_deinit:
-       vpu_dec_deinit(&inst->vpu);
-
-error_free_inst:
-       kfree(inst);
-       return err;
-}
-
-static void vdec_h264_deinit(void *h_vdec)
-{
-       struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec;
-
-       mtk_vcodec_debug_enter(inst);
-
-       vpu_dec_deinit(&inst->vpu);
-       free_predication_buf(inst);
-       free_mv_buf(inst);
-
-       kfree(inst);
-}
-
-static int find_start_code(unsigned char *data, unsigned int data_sz)
-{
-       if (data_sz > 3 && data[0] == 0 && data[1] == 0 && data[2] == 1)
-               return 3;
-
-       if (data_sz > 4 && data[0] == 0 && data[1] == 0 && data[2] == 0 &&
-           data[3] == 1)
-               return 4;
-
-       return -1;
-}
-
-static int vdec_h264_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
-                           struct vdec_fb *fb, bool *res_chg)
-{
-       struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec;
-       struct vdec_vpu_inst *vpu = &inst->vpu;
-       int nal_start_idx = 0;
-       int err = 0;
-       unsigned int nal_start;
-       unsigned int nal_type;
-       unsigned char *buf;
-       unsigned int buf_sz;
-       unsigned int data[2];
-       uint64_t vdec_fb_va = (u64)(uintptr_t)fb;
-       uint64_t y_fb_dma = fb ? (u64)fb->base_y.dma_addr : 0;
-       uint64_t c_fb_dma = fb ? (u64)fb->base_c.dma_addr : 0;
-
-       mtk_vcodec_debug(inst, "+ [%d] FB y_dma=%llx c_dma=%llx va=%p",
-                        ++inst->num_nalu, y_fb_dma, c_fb_dma, fb);
-
-       /* bs NULL means flush decoder */
-       if (bs == NULL)
-               return vpu_dec_reset(vpu);
-
-       buf = (unsigned char *)bs->va;
-       buf_sz = bs->size;
-       nal_start_idx = find_start_code(buf, buf_sz);
-       if (nal_start_idx < 0) {
-               mtk_vcodec_err(inst, "invalid nal start code");
-               err = -EIO;
-               goto err_free_fb_out;
-       }
-
-       nal_start = buf[nal_start_idx];
-       nal_type = NAL_TYPE(buf[nal_start_idx]);
-       mtk_vcodec_debug(inst, "\n + NALU[%d] type %d +\n", inst->num_nalu,
-                        nal_type);
-
-       if (nal_type == NAL_H264_PPS) {
-               buf_sz -= nal_start_idx;
-               if (buf_sz > HDR_PARSING_BUF_SZ) {
-                       err = -EILSEQ;
-                       goto err_free_fb_out;
-               }
-               memcpy(inst->vsi->hdr_buf, buf + nal_start_idx, buf_sz);
-       }
-
-       inst->vsi->dec.bs_dma = (uint64_t)bs->dma_addr;
-       inst->vsi->dec.y_fb_dma = y_fb_dma;
-       inst->vsi->dec.c_fb_dma = c_fb_dma;
-       inst->vsi->dec.vdec_fb_va = vdec_fb_va;
-
-       data[0] = buf_sz;
-       data[1] = nal_start;
-       err = vpu_dec_start(vpu, data, 2);
-       if (err) {
-               if (err > 0 && (DEC_ERR_RET(err) == H264_ERR_NOT_VALID)) {
-                       mtk_vcodec_err(inst, "- error bitstream - err = %d -",
-                                      err);
-                       err = -EIO;
-               }
-               goto err_free_fb_out;
-       }
-
-       *res_chg = inst->vsi->dec.resolution_changed;
-       if (*res_chg) {
-               struct vdec_pic_info pic;
-
-               mtk_vcodec_debug(inst, "- resolution changed -");
-               get_pic_info(inst, &pic);
-
-               if (inst->vsi->dec.realloc_mv_buf) {
-                       err = alloc_mv_buf(inst, &pic);
-                       if (err)
-                               goto err_free_fb_out;
-               }
-       }
-
-       if (nal_type == NAL_NON_IDR_SLICE || nal_type == NAL_IDR_SLICE) {
-               /* wait decoder done interrupt */
-               err = mtk_vcodec_wait_for_done_ctx(inst->ctx,
-                                                  MTK_INST_IRQ_RECEIVED,
-                                                  WAIT_INTR_TIMEOUT_MS, 0);
-               if (err)
-                       goto err_free_fb_out;
-
-               vpu_dec_end(vpu);
-       }
-
-       mtk_vcodec_debug(inst, "\n - NALU[%d] type=%d -\n", inst->num_nalu,
-                        nal_type);
-       return 0;
-
-err_free_fb_out:
-       put_fb_to_free(inst, fb);
-       mtk_vcodec_err(inst, "\n - NALU[%d] err=%d -\n", inst->num_nalu, err);
-       return err;
-}
-
-static void vdec_h264_get_fb(struct vdec_h264_inst *inst,
-                            struct h264_ring_fb_list *list,
-                            bool disp_list, struct vdec_fb **out_fb)
-{
-       struct vdec_fb *fb;
-
-       if (check_list_validity(inst, disp_list))
-               return;
-
-       if (list->count == 0) {
-               mtk_vcodec_debug(inst, "[FB] there is no %s fb",
-                                disp_list ? "disp" : "free");
-               *out_fb = NULL;
-               return;
-       }
-
-       fb = (struct vdec_fb *)
-               (uintptr_t)list->fb_list[list->read_idx].vdec_fb_va;
-       fb->status |= (disp_list ? FB_ST_DISPLAY : FB_ST_FREE);
-
-       *out_fb = fb;
-       mtk_vcodec_debug(inst, "[FB] get %s fb st=%d poc=%d %llx",
-                        disp_list ? "disp" : "free",
-                        fb->status, list->fb_list[list->read_idx].poc,
-                        list->fb_list[list->read_idx].vdec_fb_va);
-
-       list->read_idx = (list->read_idx == H264_MAX_FB_NUM - 1) ?
-                        0 : list->read_idx + 1;
-       list->count--;
-}
-
-static int vdec_h264_get_param(void *h_vdec, enum vdec_get_param_type type,
-                              void *out)
-{
-       struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec;
-
-       switch (type) {
-       case GET_PARAM_DISP_FRAME_BUFFER:
-               vdec_h264_get_fb(inst, &inst->vsi->list_disp, true, out);
-               break;
-
-       case GET_PARAM_FREE_FRAME_BUFFER:
-               vdec_h264_get_fb(inst, &inst->vsi->list_free, false, out);
-               break;
-
-       case GET_PARAM_PIC_INFO:
-               get_pic_info(inst, out);
-               break;
-
-       case GET_PARAM_DPB_SIZE:
-               get_dpb_size(inst, out);
-               break;
-
-       case GET_PARAM_CROP_INFO:
-               get_crop_info(inst, out);
-               break;
-
-       default:
-               mtk_vcodec_err(inst, "invalid get parameter type=%d", type);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-const struct vdec_common_if vdec_h264_if = {
-       .init           = vdec_h264_init,
-       .decode         = vdec_h264_decode,
-       .get_param      = vdec_h264_get_param,
-       .deinit         = vdec_h264_deinit,
-};
diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_req_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_req_if.c
deleted file mode 100644 (file)
index 43542de..0000000
+++ /dev/null
@@ -1,774 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <media/v4l2-mem2mem.h>
-#include <media/v4l2-h264.h>
-#include <media/videobuf2-dma-contig.h>
-
-#include "../mtk_vcodec_util.h"
-#include "../mtk_vcodec_dec.h"
-#include "../mtk_vcodec_intr.h"
-#include "../vdec_drv_base.h"
-#include "../vdec_drv_if.h"
-#include "../vdec_vpu_if.h"
-
-#define BUF_PREDICTION_SZ                      (64 * 4096)
-#define MB_UNIT_LEN                            16
-
-/* get used parameters for sps/pps */
-#define GET_MTK_VDEC_FLAG(cond, flag) \
-       { dst_param->cond = ((src_param->flags & (flag)) ? (1) : (0)); }
-#define GET_MTK_VDEC_PARAM(param) \
-       { dst_param->param = src_param->param; }
-/* motion vector size (bytes) for every macro block */
-#define HW_MB_STORE_SZ                         64
-
-#define H264_MAX_FB_NUM                                17
-#define H264_MAX_MV_NUM                                32
-#define HDR_PARSING_BUF_SZ                     1024
-
-/**
- * struct mtk_h264_dpb_info  - h264 dpb information
- * @y_dma_addr: Y bitstream physical address
- * @c_dma_addr: CbCr bitstream physical address
- * @reference_flag: reference picture flag (short/long term reference picture)
- * @field: field picture flag
- */
-struct mtk_h264_dpb_info {
-       dma_addr_t y_dma_addr;
-       dma_addr_t c_dma_addr;
-       int reference_flag;
-       int field;
-};
-
-/*
- * struct mtk_h264_sps_param  - parameters for sps
- */
-struct mtk_h264_sps_param {
-       unsigned char chroma_format_idc;
-       unsigned char bit_depth_luma_minus8;
-       unsigned char bit_depth_chroma_minus8;
-       unsigned char log2_max_frame_num_minus4;
-       unsigned char pic_order_cnt_type;
-       unsigned char log2_max_pic_order_cnt_lsb_minus4;
-       unsigned char max_num_ref_frames;
-       unsigned char separate_colour_plane_flag;
-       unsigned short pic_width_in_mbs_minus1;
-       unsigned short pic_height_in_map_units_minus1;
-       unsigned int max_frame_nums;
-       unsigned char qpprime_y_zero_transform_bypass_flag;
-       unsigned char delta_pic_order_always_zero_flag;
-       unsigned char frame_mbs_only_flag;
-       unsigned char mb_adaptive_frame_field_flag;
-       unsigned char direct_8x8_inference_flag;
-       unsigned char reserved[3];
-};
-
-/*
- * struct mtk_h264_pps_param  - parameters for pps
- */
-struct mtk_h264_pps_param {
-       unsigned char num_ref_idx_l0_default_active_minus1;
-       unsigned char num_ref_idx_l1_default_active_minus1;
-       unsigned char weighted_bipred_idc;
-       char pic_init_qp_minus26;
-       char chroma_qp_index_offset;
-       char second_chroma_qp_index_offset;
-       unsigned char entropy_coding_mode_flag;
-       unsigned char pic_order_present_flag;
-       unsigned char deblocking_filter_control_present_flag;
-       unsigned char constrained_intra_pred_flag;
-       unsigned char weighted_pred_flag;
-       unsigned char redundant_pic_cnt_present_flag;
-       unsigned char transform_8x8_mode_flag;
-       unsigned char scaling_matrix_present_flag;
-       unsigned char reserved[2];
-};
-
-struct slice_api_h264_scaling_matrix {
-       unsigned char scaling_list_4x4[6][16];
-       unsigned char scaling_list_8x8[6][64];
-};
-
-struct slice_h264_dpb_entry {
-       unsigned long long reference_ts;
-       unsigned short frame_num;
-       unsigned short pic_num;
-       /* Note that field is indicated by v4l2_buffer.field */
-       int top_field_order_cnt;
-       int bottom_field_order_cnt;
-       unsigned int flags; /* V4L2_H264_DPB_ENTRY_FLAG_* */
-};
-
-/*
- * struct slice_api_h264_decode_param - parameters for decode.
- */
-struct slice_api_h264_decode_param {
-       struct slice_h264_dpb_entry dpb[16];
-       unsigned short num_slices;
-       unsigned short nal_ref_idc;
-       unsigned char ref_pic_list_p0[32];
-       unsigned char ref_pic_list_b0[32];
-       unsigned char ref_pic_list_b1[32];
-       int top_field_order_cnt;
-       int bottom_field_order_cnt;
-       unsigned int flags; /* V4L2_H264_DECODE_PARAM_FLAG_* */
-};
-
-/*
- * struct mtk_h264_dec_slice_param  - parameters for decode current frame
- */
-struct mtk_h264_dec_slice_param {
-       struct mtk_h264_sps_param                       sps;
-       struct mtk_h264_pps_param                       pps;
-       struct slice_api_h264_scaling_matrix            scaling_matrix;
-       struct slice_api_h264_decode_param              decode_params;
-       struct mtk_h264_dpb_info h264_dpb_info[16];
-};
-
-/**
- * struct h264_fb - h264 decode frame buffer information
- * @vdec_fb_va  : virtual address of struct vdec_fb
- * @y_fb_dma    : dma address of Y frame buffer (luma)
- * @c_fb_dma    : dma address of C frame buffer (chroma)
- * @poc         : picture order count of frame buffer
- * @reserved    : for 8 bytes alignment
- */
-struct h264_fb {
-       u64 vdec_fb_va;
-       u64 y_fb_dma;
-       u64 c_fb_dma;
-       s32 poc;
-       u32 reserved;
-};
-
-/**
- * struct vdec_h264_dec_info - decode information
- * @dpb_sz             : decoding picture buffer size
- * @resolution_changed  : resoltion change happen
- * @realloc_mv_buf     : flag to notify driver to re-allocate mv buffer
- * @cap_num_planes     : number planes of capture buffer
- * @bs_dma             : Input bit-stream buffer dma address
- * @y_fb_dma           : Y frame buffer dma address
- * @c_fb_dma           : C frame buffer dma address
- * @vdec_fb_va         : VDEC frame buffer struct virtual address
- */
-struct vdec_h264_dec_info {
-       u32 dpb_sz;
-       u32 resolution_changed;
-       u32 realloc_mv_buf;
-       u32 cap_num_planes;
-       u64 bs_dma;
-       u64 y_fb_dma;
-       u64 c_fb_dma;
-       u64 vdec_fb_va;
-};
-
-/**
- * struct vdec_h264_vsi - shared memory for decode information exchange
- *                        between VPU and Host.
- *                        The memory is allocated by VPU then mapping to Host
- *                        in vpu_dec_init() and freed in vpu_dec_deinit()
- *                        by VPU.
- *                        AP-W/R : AP is writer/reader on this item
- *                        VPU-W/R: VPU is write/reader on this item
- * @pred_buf_dma : HW working predication buffer dma address (AP-W, VPU-R)
- * @mv_buf_dma   : HW working motion vector buffer dma address (AP-W, VPU-R)
- * @dec          : decode information (AP-R, VPU-W)
- * @pic          : picture information (AP-R, VPU-W)
- * @crop         : crop information (AP-R, VPU-W)
- * @h264_slice_params : the parameters that hardware use to decode
- */
-struct vdec_h264_vsi {
-       u64 pred_buf_dma;
-       u64 mv_buf_dma[H264_MAX_MV_NUM];
-       struct vdec_h264_dec_info dec;
-       struct vdec_pic_info pic;
-       struct v4l2_rect crop;
-       struct mtk_h264_dec_slice_param h264_slice_params;
-};
-
-/**
- * struct vdec_h264_slice_inst - h264 decoder instance
- * @num_nalu : how many nalus be decoded
- * @ctx      : point to mtk_vcodec_ctx
- * @pred_buf : HW working predication buffer
- * @mv_buf   : HW working motion vector buffer
- * @vpu      : VPU instance
- * @vsi_ctx  : Local VSI data for this decoding context
- * @h264_slice_param : the parameters that hardware use to decode
- * @dpb : decoded picture buffer used to store reference buffer information
- */
-struct vdec_h264_slice_inst {
-       unsigned int num_nalu;
-       struct mtk_vcodec_ctx *ctx;
-       struct mtk_vcodec_mem pred_buf;
-       struct mtk_vcodec_mem mv_buf[H264_MAX_MV_NUM];
-       struct vdec_vpu_inst vpu;
-       struct vdec_h264_vsi vsi_ctx;
-       struct mtk_h264_dec_slice_param h264_slice_param;
-
-       struct v4l2_h264_dpb_entry dpb[16];
-};
-
-static void *get_ctrl_ptr(struct mtk_vcodec_ctx *ctx, int id)
-{
-       struct v4l2_ctrl *ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, id);
-
-       return ctrl->p_cur.p;
-}
-
-static void get_h264_dpb_list(struct vdec_h264_slice_inst *inst,
-                             struct mtk_h264_dec_slice_param *slice_param)
-{
-       struct vb2_queue *vq;
-       struct vb2_buffer *vb;
-       struct vb2_v4l2_buffer *vb2_v4l2;
-       u64 index;
-
-       vq = v4l2_m2m_get_vq(inst->ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
-
-       for (index = 0; index < ARRAY_SIZE(slice_param->decode_params.dpb); index++) {
-               const struct slice_h264_dpb_entry *dpb;
-               int vb2_index;
-
-               dpb = &slice_param->decode_params.dpb[index];
-               if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) {
-                       slice_param->h264_dpb_info[index].reference_flag = 0;
-                       continue;
-               }
-
-               vb2_index = vb2_find_timestamp(vq, dpb->reference_ts, 0);
-               if (vb2_index < 0) {
-                       mtk_vcodec_err(inst, "Reference invalid: dpb_index(%lld) reference_ts(%lld)",
-                                      index, dpb->reference_ts);
-                       continue;
-               }
-               /* 1 for short term reference, 2 for long term reference */
-               if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM))
-                       slice_param->h264_dpb_info[index].reference_flag = 1;
-               else
-                       slice_param->h264_dpb_info[index].reference_flag = 2;
-
-               vb = vq->bufs[vb2_index];
-               vb2_v4l2 = container_of(vb, struct vb2_v4l2_buffer, vb2_buf);
-               slice_param->h264_dpb_info[index].field = vb2_v4l2->field;
-
-               slice_param->h264_dpb_info[index].y_dma_addr =
-                       vb2_dma_contig_plane_dma_addr(vb, 0);
-               if (inst->ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) {
-                       slice_param->h264_dpb_info[index].c_dma_addr =
-                               vb2_dma_contig_plane_dma_addr(vb, 1);
-               }
-       }
-}
-
-static void get_h264_sps_parameters(struct mtk_h264_sps_param *dst_param,
-                                   const struct v4l2_ctrl_h264_sps *src_param)
-{
-       GET_MTK_VDEC_PARAM(chroma_format_idc);
-       GET_MTK_VDEC_PARAM(bit_depth_luma_minus8);
-       GET_MTK_VDEC_PARAM(bit_depth_chroma_minus8);
-       GET_MTK_VDEC_PARAM(log2_max_frame_num_minus4);
-       GET_MTK_VDEC_PARAM(pic_order_cnt_type);
-       GET_MTK_VDEC_PARAM(log2_max_pic_order_cnt_lsb_minus4);
-       GET_MTK_VDEC_PARAM(max_num_ref_frames);
-       GET_MTK_VDEC_PARAM(pic_width_in_mbs_minus1);
-       GET_MTK_VDEC_PARAM(pic_height_in_map_units_minus1);
-
-       GET_MTK_VDEC_FLAG(separate_colour_plane_flag,
-                         V4L2_H264_SPS_FLAG_SEPARATE_COLOUR_PLANE);
-       GET_MTK_VDEC_FLAG(qpprime_y_zero_transform_bypass_flag,
-                         V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS);
-       GET_MTK_VDEC_FLAG(delta_pic_order_always_zero_flag,
-                         V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO);
-       GET_MTK_VDEC_FLAG(frame_mbs_only_flag,
-                         V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY);
-       GET_MTK_VDEC_FLAG(mb_adaptive_frame_field_flag,
-                         V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD);
-       GET_MTK_VDEC_FLAG(direct_8x8_inference_flag,
-                         V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE);
-}
-
-static void get_h264_pps_parameters(struct mtk_h264_pps_param *dst_param,
-                                   const struct v4l2_ctrl_h264_pps *src_param)
-{
-       GET_MTK_VDEC_PARAM(num_ref_idx_l0_default_active_minus1);
-       GET_MTK_VDEC_PARAM(num_ref_idx_l1_default_active_minus1);
-       GET_MTK_VDEC_PARAM(weighted_bipred_idc);
-       GET_MTK_VDEC_PARAM(pic_init_qp_minus26);
-       GET_MTK_VDEC_PARAM(chroma_qp_index_offset);
-       GET_MTK_VDEC_PARAM(second_chroma_qp_index_offset);
-
-       GET_MTK_VDEC_FLAG(entropy_coding_mode_flag,
-                         V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE);
-       GET_MTK_VDEC_FLAG(pic_order_present_flag,
-                         V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT);
-       GET_MTK_VDEC_FLAG(weighted_pred_flag,
-                         V4L2_H264_PPS_FLAG_WEIGHTED_PRED);
-       GET_MTK_VDEC_FLAG(deblocking_filter_control_present_flag,
-                         V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT);
-       GET_MTK_VDEC_FLAG(constrained_intra_pred_flag,
-                         V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED);
-       GET_MTK_VDEC_FLAG(redundant_pic_cnt_present_flag,
-                         V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT);
-       GET_MTK_VDEC_FLAG(transform_8x8_mode_flag,
-                         V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE);
-       GET_MTK_VDEC_FLAG(scaling_matrix_present_flag,
-                         V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT);
-}
-
-static void
-get_h264_scaling_matrix(struct slice_api_h264_scaling_matrix *dst_matrix,
-                       const struct v4l2_ctrl_h264_scaling_matrix *src_matrix)
-{
-       memcpy(dst_matrix->scaling_list_4x4, src_matrix->scaling_list_4x4,
-              sizeof(dst_matrix->scaling_list_4x4));
-
-       memcpy(dst_matrix->scaling_list_8x8, src_matrix->scaling_list_8x8,
-              sizeof(dst_matrix->scaling_list_8x8));
-}
-
-static void
-get_h264_decode_parameters(struct slice_api_h264_decode_param *dst_params,
-                          const struct v4l2_ctrl_h264_decode_params *src_params,
-                          const struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES])
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(dst_params->dpb); i++) {
-               struct slice_h264_dpb_entry *dst_entry = &dst_params->dpb[i];
-               const struct v4l2_h264_dpb_entry *src_entry = &dpb[i];
-
-               dst_entry->reference_ts = src_entry->reference_ts;
-               dst_entry->frame_num = src_entry->frame_num;
-               dst_entry->pic_num = src_entry->pic_num;
-               dst_entry->top_field_order_cnt = src_entry->top_field_order_cnt;
-               dst_entry->bottom_field_order_cnt =
-                       src_entry->bottom_field_order_cnt;
-               dst_entry->flags = src_entry->flags;
-       }
-
-       /*
-        * num_slices is a leftover from the old H.264 support and is ignored
-        * by the firmware.
-        */
-       dst_params->num_slices = 0;
-       dst_params->nal_ref_idc = src_params->nal_ref_idc;
-       dst_params->top_field_order_cnt = src_params->top_field_order_cnt;
-       dst_params->bottom_field_order_cnt = src_params->bottom_field_order_cnt;
-       dst_params->flags = src_params->flags;
-}
-
-static bool dpb_entry_match(const struct v4l2_h264_dpb_entry *a,
-                           const struct v4l2_h264_dpb_entry *b)
-{
-       return a->top_field_order_cnt == b->top_field_order_cnt &&
-              a->bottom_field_order_cnt == b->bottom_field_order_cnt;
-}
-
-/*
- * Move DPB entries of dec_param that refer to a frame already existing in dpb
- * into the already existing slot in dpb, and move other entries into new slots.
- *
- * This function is an adaptation of the similarly-named function in
- * hantro_h264.c.
- */
-static void update_dpb(const struct v4l2_ctrl_h264_decode_params *dec_param,
-                      struct v4l2_h264_dpb_entry *dpb)
-{
-       DECLARE_BITMAP(new, ARRAY_SIZE(dec_param->dpb)) = { 0, };
-       DECLARE_BITMAP(in_use, ARRAY_SIZE(dec_param->dpb)) = { 0, };
-       DECLARE_BITMAP(used, ARRAY_SIZE(dec_param->dpb)) = { 0, };
-       unsigned int i, j;
-
-       /* Disable all entries by default, and mark the ones in use. */
-       for (i = 0; i < ARRAY_SIZE(dec_param->dpb); i++) {
-               if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)
-                       set_bit(i, in_use);
-               dpb[i].flags &= ~V4L2_H264_DPB_ENTRY_FLAG_ACTIVE;
-       }
-
-       /* Try to match new DPB entries with existing ones by their POCs. */
-       for (i = 0; i < ARRAY_SIZE(dec_param->dpb); i++) {
-               const struct v4l2_h264_dpb_entry *ndpb = &dec_param->dpb[i];
-
-               if (!(ndpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE))
-                       continue;
-
-               /*
-                * To cut off some comparisons, iterate only on target DPB
-                * entries were already used.
-                */
-               for_each_set_bit(j, in_use, ARRAY_SIZE(dec_param->dpb)) {
-                       struct v4l2_h264_dpb_entry *cdpb;
-
-                       cdpb = &dpb[j];
-                       if (!dpb_entry_match(cdpb, ndpb))
-                               continue;
-
-                       *cdpb = *ndpb;
-                       set_bit(j, used);
-                       /* Don't reiterate on this one. */
-                       clear_bit(j, in_use);
-                       break;
-               }
-
-               if (j == ARRAY_SIZE(dec_param->dpb))
-                       set_bit(i, new);
-       }
-
-       /* For entries that could not be matched, use remaining free slots. */
-       for_each_set_bit(i, new, ARRAY_SIZE(dec_param->dpb)) {
-               const struct v4l2_h264_dpb_entry *ndpb = &dec_param->dpb[i];
-               struct v4l2_h264_dpb_entry *cdpb;
-
-               /*
-                * Both arrays are of the same sizes, so there is no way
-                * we can end up with no space in target array, unless
-                * something is buggy.
-                */
-               j = find_first_zero_bit(used, ARRAY_SIZE(dec_param->dpb));
-               if (WARN_ON(j >= ARRAY_SIZE(dec_param->dpb)))
-                       return;
-
-               cdpb = &dpb[j];
-               *cdpb = *ndpb;
-               set_bit(j, used);
-       }
-}
-
-/*
- * The firmware expects unused reflist entries to have the value 0x20.
- */
-static void fixup_ref_list(u8 *ref_list, size_t num_valid)
-{
-       memset(&ref_list[num_valid], 0x20, 32 - num_valid);
-}
-
-static void get_vdec_decode_parameters(struct vdec_h264_slice_inst *inst)
-{
-       const struct v4l2_ctrl_h264_decode_params *dec_params =
-               get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_DECODE_PARAMS);
-       const struct v4l2_ctrl_h264_sps *sps =
-               get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_SPS);
-       const struct v4l2_ctrl_h264_pps *pps =
-               get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_PPS);
-       const struct v4l2_ctrl_h264_scaling_matrix *scaling_matrix =
-               get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_SCALING_MATRIX);
-       struct mtk_h264_dec_slice_param *slice_param = &inst->h264_slice_param;
-       struct v4l2_h264_reflist_builder reflist_builder;
-       u8 *p0_reflist = slice_param->decode_params.ref_pic_list_p0;
-       u8 *b0_reflist = slice_param->decode_params.ref_pic_list_b0;
-       u8 *b1_reflist = slice_param->decode_params.ref_pic_list_b1;
-
-       update_dpb(dec_params, inst->dpb);
-
-       get_h264_sps_parameters(&slice_param->sps, sps);
-       get_h264_pps_parameters(&slice_param->pps, pps);
-       get_h264_scaling_matrix(&slice_param->scaling_matrix, scaling_matrix);
-       get_h264_decode_parameters(&slice_param->decode_params, dec_params,
-                                  inst->dpb);
-       get_h264_dpb_list(inst, slice_param);
-
-       /* Build the reference lists */
-       v4l2_h264_init_reflist_builder(&reflist_builder, dec_params, sps,
-                                      inst->dpb);
-       v4l2_h264_build_p_ref_list(&reflist_builder, p0_reflist);
-       v4l2_h264_build_b_ref_lists(&reflist_builder, b0_reflist, b1_reflist);
-       /* Adapt the built lists to the firmware's expectations */
-       fixup_ref_list(p0_reflist, reflist_builder.num_valid);
-       fixup_ref_list(b0_reflist, reflist_builder.num_valid);
-       fixup_ref_list(b1_reflist, reflist_builder.num_valid);
-
-       memcpy(&inst->vsi_ctx.h264_slice_params, slice_param,
-              sizeof(inst->vsi_ctx.h264_slice_params));
-}
-
-static unsigned int get_mv_buf_size(unsigned int width, unsigned int height)
-{
-       int unit_size = (width / MB_UNIT_LEN) * (height / MB_UNIT_LEN) + 8;
-
-       return HW_MB_STORE_SZ * unit_size;
-}
-
-static int allocate_predication_buf(struct vdec_h264_slice_inst *inst)
-{
-       int err;
-
-       inst->pred_buf.size = BUF_PREDICTION_SZ;
-       err = mtk_vcodec_mem_alloc(inst->ctx, &inst->pred_buf);
-       if (err) {
-               mtk_vcodec_err(inst, "failed to allocate ppl buf");
-               return err;
-       }
-
-       inst->vsi_ctx.pred_buf_dma = inst->pred_buf.dma_addr;
-       return 0;
-}
-
-static void free_predication_buf(struct vdec_h264_slice_inst *inst)
-{
-       struct mtk_vcodec_mem *mem = &inst->pred_buf;
-
-       mtk_vcodec_debug_enter(inst);
-
-       inst->vsi_ctx.pred_buf_dma = 0;
-       if (mem->va)
-               mtk_vcodec_mem_free(inst->ctx, mem);
-}
-
-static int alloc_mv_buf(struct vdec_h264_slice_inst *inst,
-                       struct vdec_pic_info *pic)
-{
-       int i;
-       int err;
-       struct mtk_vcodec_mem *mem = NULL;
-       unsigned int buf_sz = get_mv_buf_size(pic->buf_w, pic->buf_h);
-
-       mtk_v4l2_debug(3, "size = 0x%x", buf_sz);
-       for (i = 0; i < H264_MAX_MV_NUM; i++) {
-               mem = &inst->mv_buf[i];
-               if (mem->va)
-                       mtk_vcodec_mem_free(inst->ctx, mem);
-               mem->size = buf_sz;
-               err = mtk_vcodec_mem_alloc(inst->ctx, mem);
-               if (err) {
-                       mtk_vcodec_err(inst, "failed to allocate mv buf");
-                       return err;
-               }
-               inst->vsi_ctx.mv_buf_dma[i] = mem->dma_addr;
-       }
-
-       return 0;
-}
-
-static void free_mv_buf(struct vdec_h264_slice_inst *inst)
-{
-       int i;
-       struct mtk_vcodec_mem *mem;
-
-       for (i = 0; i < H264_MAX_MV_NUM; i++) {
-               inst->vsi_ctx.mv_buf_dma[i] = 0;
-               mem = &inst->mv_buf[i];
-               if (mem->va)
-                       mtk_vcodec_mem_free(inst->ctx, mem);
-       }
-}
-
-static void get_pic_info(struct vdec_h264_slice_inst *inst,
-                        struct vdec_pic_info *pic)
-{
-       struct mtk_vcodec_ctx *ctx = inst->ctx;
-
-       ctx->picinfo.buf_w = ALIGN(ctx->picinfo.pic_w, VCODEC_DEC_ALIGNED_64);
-       ctx->picinfo.buf_h = ALIGN(ctx->picinfo.pic_h, VCODEC_DEC_ALIGNED_64);
-       ctx->picinfo.fb_sz[0] = ctx->picinfo.buf_w * ctx->picinfo.buf_h;
-       ctx->picinfo.fb_sz[1] = ctx->picinfo.fb_sz[0] >> 1;
-       inst->vsi_ctx.dec.cap_num_planes =
-               ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes;
-
-       *pic = ctx->picinfo;
-       mtk_vcodec_debug(inst, "pic(%d, %d), buf(%d, %d)",
-                        ctx->picinfo.pic_w, ctx->picinfo.pic_h,
-                        ctx->picinfo.buf_w, ctx->picinfo.buf_h);
-       mtk_vcodec_debug(inst, "Y/C(%d, %d)", ctx->picinfo.fb_sz[0],
-                        ctx->picinfo.fb_sz[1]);
-
-       if (ctx->last_decoded_picinfo.pic_w != ctx->picinfo.pic_w ||
-           ctx->last_decoded_picinfo.pic_h != ctx->picinfo.pic_h) {
-               inst->vsi_ctx.dec.resolution_changed = true;
-               if (ctx->last_decoded_picinfo.buf_w != ctx->picinfo.buf_w ||
-                   ctx->last_decoded_picinfo.buf_h != ctx->picinfo.buf_h)
-                       inst->vsi_ctx.dec.realloc_mv_buf = true;
-
-               mtk_v4l2_debug(1, "ResChg: (%d %d) : old(%d, %d) -> new(%d, %d)",
-                              inst->vsi_ctx.dec.resolution_changed,
-                              inst->vsi_ctx.dec.realloc_mv_buf,
-                              ctx->last_decoded_picinfo.pic_w,
-                              ctx->last_decoded_picinfo.pic_h,
-                              ctx->picinfo.pic_w, ctx->picinfo.pic_h);
-       }
-}
-
-static void get_crop_info(struct vdec_h264_slice_inst *inst, struct v4l2_rect *cr)
-{
-       cr->left = inst->vsi_ctx.crop.left;
-       cr->top = inst->vsi_ctx.crop.top;
-       cr->width = inst->vsi_ctx.crop.width;
-       cr->height = inst->vsi_ctx.crop.height;
-
-       mtk_vcodec_debug(inst, "l=%d, t=%d, w=%d, h=%d",
-                        cr->left, cr->top, cr->width, cr->height);
-}
-
-static void get_dpb_size(struct vdec_h264_slice_inst *inst, unsigned int *dpb_sz)
-{
-       *dpb_sz = inst->vsi_ctx.dec.dpb_sz;
-       mtk_vcodec_debug(inst, "sz=%d", *dpb_sz);
-}
-
-static int vdec_h264_slice_init(struct mtk_vcodec_ctx *ctx)
-{
-       struct vdec_h264_slice_inst *inst;
-       int err;
-
-       inst = kzalloc(sizeof(*inst), GFP_KERNEL);
-       if (!inst)
-               return -ENOMEM;
-
-       inst->ctx = ctx;
-
-       inst->vpu.id = SCP_IPI_VDEC_H264;
-       inst->vpu.ctx = ctx;
-
-       err = vpu_dec_init(&inst->vpu);
-       if (err) {
-               mtk_vcodec_err(inst, "vdec_h264 init err=%d", err);
-               goto error_free_inst;
-       }
-
-       memcpy(&inst->vsi_ctx, inst->vpu.vsi, sizeof(inst->vsi_ctx));
-       inst->vsi_ctx.dec.resolution_changed = true;
-       inst->vsi_ctx.dec.realloc_mv_buf = true;
-
-       err = allocate_predication_buf(inst);
-       if (err)
-               goto error_deinit;
-
-       mtk_vcodec_debug(inst, "struct size = %zu,%zu,%zu,%zu\n",
-                        sizeof(struct mtk_h264_sps_param),
-                        sizeof(struct mtk_h264_pps_param),
-                        sizeof(struct mtk_h264_dec_slice_param),
-                        sizeof(struct mtk_h264_dpb_info));
-
-       mtk_vcodec_debug(inst, "H264 Instance >> %p", inst);
-
-       ctx->drv_handle = inst;
-       return 0;
-
-error_deinit:
-       vpu_dec_deinit(&inst->vpu);
-
-error_free_inst:
-       kfree(inst);
-       return err;
-}
-
-static void vdec_h264_slice_deinit(void *h_vdec)
-{
-       struct vdec_h264_slice_inst *inst = h_vdec;
-
-       mtk_vcodec_debug_enter(inst);
-
-       vpu_dec_deinit(&inst->vpu);
-       free_predication_buf(inst);
-       free_mv_buf(inst);
-
-       kfree(inst);
-}
-
-static int vdec_h264_slice_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
-                                 struct vdec_fb *fb, bool *res_chg)
-{
-       struct vdec_h264_slice_inst *inst = h_vdec;
-       const struct v4l2_ctrl_h264_decode_params *dec_params =
-               get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_DECODE_PARAMS);
-       struct vdec_vpu_inst *vpu = &inst->vpu;
-       u32 data[2];
-       u64 y_fb_dma;
-       u64 c_fb_dma;
-       int err;
-
-       /* bs NULL means flush decoder */
-       if (!bs)
-               return vpu_dec_reset(vpu);
-
-       y_fb_dma = fb ? (u64)fb->base_y.dma_addr : 0;
-       c_fb_dma = fb ? (u64)fb->base_c.dma_addr : 0;
-
-       mtk_vcodec_debug(inst, "+ [%d] FB y_dma=%llx c_dma=%llx va=%p",
-                        ++inst->num_nalu, y_fb_dma, c_fb_dma, fb);
-
-       inst->vsi_ctx.dec.bs_dma = (uint64_t)bs->dma_addr;
-       inst->vsi_ctx.dec.y_fb_dma = y_fb_dma;
-       inst->vsi_ctx.dec.c_fb_dma = c_fb_dma;
-       inst->vsi_ctx.dec.vdec_fb_va = (u64)(uintptr_t)fb;
-
-       get_vdec_decode_parameters(inst);
-       data[0] = bs->size;
-       /*
-        * Reconstruct the first byte of the NAL unit, as the firmware requests
-        * that information to be passed even though it is present in the stream
-        * itself...
-        */
-       data[1] = (dec_params->nal_ref_idc << 5) |
-                 ((dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC)
-                       ? 0x5 : 0x1);
-
-       *res_chg = inst->vsi_ctx.dec.resolution_changed;
-       if (*res_chg) {
-               mtk_vcodec_debug(inst, "- resolution changed -");
-               if (inst->vsi_ctx.dec.realloc_mv_buf) {
-                       err = alloc_mv_buf(inst, &inst->ctx->picinfo);
-                       inst->vsi_ctx.dec.realloc_mv_buf = false;
-                       if (err)
-                               goto err_free_fb_out;
-               }
-               *res_chg = false;
-       }
-
-       memcpy(inst->vpu.vsi, &inst->vsi_ctx, sizeof(inst->vsi_ctx));
-       err = vpu_dec_start(vpu, data, 2);
-       if (err)
-               goto err_free_fb_out;
-
-       /* wait decoder done interrupt */
-       err = mtk_vcodec_wait_for_done_ctx(inst->ctx,
-                                          MTK_INST_IRQ_RECEIVED,
-                                          WAIT_INTR_TIMEOUT_MS, 0);
-       if (err)
-               goto err_free_fb_out;
-       vpu_dec_end(vpu);
-
-       memcpy(&inst->vsi_ctx, inst->vpu.vsi, sizeof(inst->vsi_ctx));
-       mtk_vcodec_debug(inst, "\n - NALU[%d]", inst->num_nalu);
-       return 0;
-
-err_free_fb_out:
-       mtk_vcodec_err(inst, "\n - NALU[%d] err=%d -\n", inst->num_nalu, err);
-       return err;
-}
-
-static int vdec_h264_slice_get_param(void *h_vdec, enum vdec_get_param_type type, void *out)
-{
-       struct vdec_h264_slice_inst *inst = h_vdec;
-
-       switch (type) {
-       case GET_PARAM_PIC_INFO:
-               get_pic_info(inst, out);
-               break;
-
-       case GET_PARAM_DPB_SIZE:
-               get_dpb_size(inst, out);
-               break;
-
-       case GET_PARAM_CROP_INFO:
-               get_crop_info(inst, out);
-               break;
-
-       default:
-               mtk_vcodec_err(inst, "invalid get parameter type=%d", type);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-const struct vdec_common_if vdec_h264_slice_if = {
-       .init           = vdec_h264_slice_init,
-       .decode         = vdec_h264_slice_decode,
-       .get_param      = vdec_h264_slice_get_param,
-       .deinit         = vdec_h264_slice_deinit,
-};
diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c
deleted file mode 100644 (file)
index 88c0467..0000000
+++ /dev/null
@@ -1,616 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2016 MediaTek Inc.
- * Author: Jungchang Tsao <jungchang.tsao@mediatek.com>
- *        PC Chen <pc.chen@mediatek.com>
- */
-
-#include <linux/slab.h>
-#include "../vdec_drv_if.h"
-#include "../mtk_vcodec_util.h"
-#include "../mtk_vcodec_dec.h"
-#include "../mtk_vcodec_intr.h"
-#include "../vdec_vpu_if.h"
-#include "../vdec_drv_base.h"
-
-/* Decoding picture buffer size (3 reference frames plus current frame) */
-#define VP8_DPB_SIZE                   4
-
-/* HW working buffer size (bytes) */
-#define VP8_WORKING_BUF_SZ             (45 * 4096)
-
-/* HW control register address */
-#define VP8_SEGID_DRAM_ADDR            0x3c
-#define VP8_HW_VLD_ADDR                        0x93C
-#define VP8_HW_VLD_VALUE               0x940
-#define VP8_BSASET                     0x100
-#define VP8_BSDSET                     0x104
-#define VP8_RW_CKEN_SET                        0x0
-#define VP8_RW_DCM_CON                 0x18
-#define VP8_WO_VLD_SRST                        0x108
-#define VP8_RW_MISC_SYS_SEL            0x84
-#define VP8_RW_MISC_SPEC_CON           0xC8
-#define VP8_WO_VLD_SRST                        0x108
-#define VP8_RW_VP8_CTRL                        0xA4
-#define VP8_RW_MISC_DCM_CON            0xEC
-#define VP8_RW_MISC_SRST               0xF4
-#define VP8_RW_MISC_FUNC_CON           0xCC
-
-#define VP8_MAX_FRM_BUF_NUM            5
-#define VP8_MAX_FRM_BUF_NODE_NUM       (VP8_MAX_FRM_BUF_NUM * 2)
-
-/* required buffer size (bytes) to store decode information */
-#define VP8_HW_SEGMENT_DATA_SZ         272
-#define VP8_HW_SEGMENT_UINT            4
-
-#define VP8_DEC_TABLE_PROC_LOOP                96
-#define VP8_DEC_TABLE_UNIT             3
-#define VP8_DEC_TABLE_SZ               300
-#define VP8_DEC_TABLE_OFFSET           2
-#define VP8_DEC_TABLE_RW_UNIT          4
-
-/**
- * struct vdec_vp8_dec_info - decode misc information
- * @working_buf_dma   : working buffer dma address
- * @prev_y_dma        : previous decoded frame buffer Y plane address
- * @cur_y_fb_dma      : current plane Y frame buffer dma address
- * @cur_c_fb_dma      : current plane C frame buffer dma address
- * @bs_dma           : bitstream dma address
- * @bs_sz            : bitstream size
- * @resolution_changed: resolution change flag 1 - changed,  0 - not change
- * @show_frame       : display this frame or not
- * @wait_key_frame    : wait key frame coming
- */
-struct vdec_vp8_dec_info {
-       uint64_t working_buf_dma;
-       uint64_t prev_y_dma;
-       uint64_t cur_y_fb_dma;
-       uint64_t cur_c_fb_dma;
-       uint64_t bs_dma;
-       uint32_t bs_sz;
-       uint32_t resolution_changed;
-       uint32_t show_frame;
-       uint32_t wait_key_frame;
-};
-
-/**
- * struct vdec_vp8_vsi - VPU shared information
- * @dec                        : decoding information
- * @pic                        : picture information
- * @dec_table          : decoder coefficient table
- * @segment_buf                : segmentation buffer
- * @load_data          : flag to indicate reload decode data
- */
-struct vdec_vp8_vsi {
-       struct vdec_vp8_dec_info dec;
-       struct vdec_pic_info pic;
-       uint32_t dec_table[VP8_DEC_TABLE_SZ];
-       uint32_t segment_buf[VP8_HW_SEGMENT_DATA_SZ][VP8_HW_SEGMENT_UINT];
-       uint32_t load_data;
-};
-
-/**
- * struct vdec_vp8_hw_reg_base - HW register base
- * @sys                : base address for sys
- * @misc       : base address for misc
- * @ld         : base address for ld
- * @top                : base address for top
- * @cm         : base address for cm
- * @hwd                : base address for hwd
- * @hwb                : base address for hwb
- */
-struct vdec_vp8_hw_reg_base {
-       void __iomem *sys;
-       void __iomem *misc;
-       void __iomem *ld;
-       void __iomem *top;
-       void __iomem *cm;
-       void __iomem *hwd;
-       void __iomem *hwb;
-};
-
-/**
- * struct vdec_vp8_vpu_inst - VPU instance for VP8 decode
- * @wq_hd      : Wait queue to wait VPU message ack
- * @signaled   : 1 - Host has received ack message from VPU, 0 - not receive
- * @failure    : VPU execution result status 0 - success, others - fail
- * @inst_addr  : VPU decoder instance address
- */
-struct vdec_vp8_vpu_inst {
-       wait_queue_head_t wq_hd;
-       int signaled;
-       int failure;
-       uint32_t inst_addr;
-};
-
-/* frame buffer (fb) list
- * [available_fb_node_list]  - decode fb are initialized to 0 and populated in
- * [fb_use_list]  - fb is set after decode and is moved to this list
- * [fb_free_list] - fb is not needed for reference will be moved from
- *                  [fb_use_list] to [fb_free_list] and
- *                  once user remove fb from [fb_free_list],
- *                  it is circulated back to [available_fb_node_list]
- * [fb_disp_list] - fb is set after decode and is moved to this list
- *                   once user remove fb from [fb_disp_list] it is
- *                   circulated back to [available_fb_node_list]
- */
-
-/**
- * struct vdec_vp8_inst - VP8 decoder instance
- * @cur_fb                : current frame buffer
- * @dec_fb                : decode frame buffer node
- * @available_fb_node_list : list to store available frame buffer node
- * @fb_use_list                   : list to store frame buffer in use
- * @fb_free_list          : list to store free frame buffer
- * @fb_disp_list          : list to store display ready frame buffer
- * @working_buf                   : HW decoder working buffer
- * @reg_base              : HW register base address
- * @frm_cnt               : decode frame count
- * @ctx                           : V4L2 context
- * @vpu                           : VPU instance for decoder
- * @vsi                           : VPU share information
- */
-struct vdec_vp8_inst {
-       struct vdec_fb *cur_fb;
-       struct vdec_fb_node dec_fb[VP8_MAX_FRM_BUF_NODE_NUM];
-       struct list_head available_fb_node_list;
-       struct list_head fb_use_list;
-       struct list_head fb_free_list;
-       struct list_head fb_disp_list;
-       struct mtk_vcodec_mem working_buf;
-       struct vdec_vp8_hw_reg_base reg_base;
-       unsigned int frm_cnt;
-       struct mtk_vcodec_ctx *ctx;
-       struct vdec_vpu_inst vpu;
-       struct vdec_vp8_vsi *vsi;
-};
-
-static void get_hw_reg_base(struct vdec_vp8_inst *inst)
-{
-       inst->reg_base.top = mtk_vcodec_get_reg_addr(inst->ctx, VDEC_TOP);
-       inst->reg_base.cm = mtk_vcodec_get_reg_addr(inst->ctx, VDEC_CM);
-       inst->reg_base.hwd = mtk_vcodec_get_reg_addr(inst->ctx, VDEC_HWD);
-       inst->reg_base.sys = mtk_vcodec_get_reg_addr(inst->ctx, VDEC_SYS);
-       inst->reg_base.misc = mtk_vcodec_get_reg_addr(inst->ctx, VDEC_MISC);
-       inst->reg_base.ld = mtk_vcodec_get_reg_addr(inst->ctx, VDEC_LD);
-       inst->reg_base.hwb = mtk_vcodec_get_reg_addr(inst->ctx, VDEC_HWB);
-}
-
-static void write_hw_segmentation_data(struct vdec_vp8_inst *inst)
-{
-       int i, j;
-       u32 seg_id_addr;
-       u32 val;
-       void __iomem *cm = inst->reg_base.cm;
-       struct vdec_vp8_vsi *vsi = inst->vsi;
-
-       seg_id_addr = readl(inst->reg_base.top + VP8_SEGID_DRAM_ADDR) >> 4;
-
-       for (i = 0; i < ARRAY_SIZE(vsi->segment_buf); i++) {
-               for (j = ARRAY_SIZE(vsi->segment_buf[i]) - 1; j >= 0; j--) {
-                       val = (1 << 16) + ((seg_id_addr + i) << 2) + j;
-                       writel(val, cm + VP8_HW_VLD_ADDR);
-
-                       val = vsi->segment_buf[i][j];
-                       writel(val, cm + VP8_HW_VLD_VALUE);
-               }
-       }
-}
-
-static void read_hw_segmentation_data(struct vdec_vp8_inst *inst)
-{
-       int i, j;
-       u32 seg_id_addr;
-       u32 val;
-       void __iomem *cm = inst->reg_base.cm;
-       struct vdec_vp8_vsi *vsi = inst->vsi;
-
-       seg_id_addr = readl(inst->reg_base.top + VP8_SEGID_DRAM_ADDR) >> 4;
-
-       for (i = 0; i < ARRAY_SIZE(vsi->segment_buf); i++) {
-               for (j = ARRAY_SIZE(vsi->segment_buf[i]) - 1; j >= 0; j--) {
-                       val = ((seg_id_addr + i) << 2) + j;
-                       writel(val, cm + VP8_HW_VLD_ADDR);
-
-                       val = readl(cm + VP8_HW_VLD_VALUE);
-                       vsi->segment_buf[i][j] = val;
-               }
-       }
-}
-
-/* reset HW and enable HW read/write data function */
-static void enable_hw_rw_function(struct vdec_vp8_inst *inst)
-{
-       u32 val = 0;
-       void __iomem *sys = inst->reg_base.sys;
-       void __iomem *misc = inst->reg_base.misc;
-       void __iomem *ld = inst->reg_base.ld;
-       void __iomem *hwb = inst->reg_base.hwb;
-       void __iomem *hwd = inst->reg_base.hwd;
-
-       writel(0x1, sys + VP8_RW_CKEN_SET);
-       writel(0x101, ld + VP8_WO_VLD_SRST);
-       writel(0x101, hwb + VP8_WO_VLD_SRST);
-
-       writel(1, sys);
-       val = readl(misc + VP8_RW_MISC_SRST);
-       writel((val & 0xFFFFFFFE), misc + VP8_RW_MISC_SRST);
-
-       writel(0x1, misc + VP8_RW_MISC_SYS_SEL);
-       writel(0x17F, misc + VP8_RW_MISC_SPEC_CON);
-       writel(0x71201100, misc + VP8_RW_MISC_FUNC_CON);
-       writel(0x0, ld + VP8_WO_VLD_SRST);
-       writel(0x0, hwb + VP8_WO_VLD_SRST);
-       writel(0x1, sys + VP8_RW_DCM_CON);
-       writel(0x1, misc + VP8_RW_MISC_DCM_CON);
-       writel(0x1, hwd + VP8_RW_VP8_CTRL);
-}
-
-static void store_dec_table(struct vdec_vp8_inst *inst)
-{
-       int i, j;
-       u32 addr = 0, val = 0;
-       void __iomem *hwd = inst->reg_base.hwd;
-       u32 *p = &inst->vsi->dec_table[VP8_DEC_TABLE_OFFSET];
-
-       for (i = 0; i < VP8_DEC_TABLE_PROC_LOOP; i++) {
-               writel(addr, hwd + VP8_BSASET);
-               for (j = 0; j < VP8_DEC_TABLE_UNIT ; j++) {
-                       val = *p++;
-                       writel(val, hwd + VP8_BSDSET);
-               }
-               addr += VP8_DEC_TABLE_RW_UNIT;
-       }
-}
-
-static void load_dec_table(struct vdec_vp8_inst *inst)
-{
-       int i;
-       u32 addr = 0;
-       u32 *p = &inst->vsi->dec_table[VP8_DEC_TABLE_OFFSET];
-       void __iomem *hwd = inst->reg_base.hwd;
-
-       for (i = 0; i < VP8_DEC_TABLE_PROC_LOOP; i++) {
-               writel(addr, hwd + VP8_BSASET);
-               /* read total 11 bytes */
-               *p++ = readl(hwd + VP8_BSDSET);
-               *p++ = readl(hwd + VP8_BSDSET);
-               *p++ = readl(hwd + VP8_BSDSET) & 0xFFFFFF;
-               addr += VP8_DEC_TABLE_RW_UNIT;
-       }
-}
-
-static void get_pic_info(struct vdec_vp8_inst *inst, struct vdec_pic_info *pic)
-{
-       *pic = inst->vsi->pic;
-
-       mtk_vcodec_debug(inst, "pic(%d, %d), buf(%d, %d)",
-                        pic->pic_w, pic->pic_h, pic->buf_w, pic->buf_h);
-       mtk_vcodec_debug(inst, "fb size: Y(%d), C(%d)",
-                        pic->fb_sz[0], pic->fb_sz[1]);
-}
-
-static void vp8_dec_finish(struct vdec_vp8_inst *inst)
-{
-       struct vdec_fb_node *node;
-       uint64_t prev_y_dma = inst->vsi->dec.prev_y_dma;
-
-       mtk_vcodec_debug(inst, "prev fb base dma=%llx", prev_y_dma);
-
-       /* put last decode ok frame to fb_free_list */
-       if (prev_y_dma != 0) {
-               list_for_each_entry(node, &inst->fb_use_list, list) {
-                       struct vdec_fb *fb = (struct vdec_fb *)node->fb;
-
-                       if (prev_y_dma == (uint64_t)fb->base_y.dma_addr) {
-                               list_move_tail(&node->list,
-                                              &inst->fb_free_list);
-                               break;
-                       }
-               }
-       }
-
-       /* available_fb_node_list -> fb_use_list */
-       node = list_first_entry(&inst->available_fb_node_list,
-                               struct vdec_fb_node, list);
-       node->fb = inst->cur_fb;
-       list_move_tail(&node->list, &inst->fb_use_list);
-
-       /* available_fb_node_list -> fb_disp_list */
-       if (inst->vsi->dec.show_frame) {
-               node = list_first_entry(&inst->available_fb_node_list,
-                                       struct vdec_fb_node, list);
-               node->fb = inst->cur_fb;
-               list_move_tail(&node->list, &inst->fb_disp_list);
-       }
-}
-
-static void move_fb_list_use_to_free(struct vdec_vp8_inst *inst)
-{
-       struct vdec_fb_node *node, *tmp;
-
-       list_for_each_entry_safe(node, tmp, &inst->fb_use_list, list)
-               list_move_tail(&node->list, &inst->fb_free_list);
-}
-
-static void init_list(struct vdec_vp8_inst *inst)
-{
-       int i;
-
-       INIT_LIST_HEAD(&inst->available_fb_node_list);
-       INIT_LIST_HEAD(&inst->fb_use_list);
-       INIT_LIST_HEAD(&inst->fb_free_list);
-       INIT_LIST_HEAD(&inst->fb_disp_list);
-
-       for (i = 0; i < ARRAY_SIZE(inst->dec_fb); i++) {
-               INIT_LIST_HEAD(&inst->dec_fb[i].list);
-               inst->dec_fb[i].fb = NULL;
-               list_add_tail(&inst->dec_fb[i].list,
-                             &inst->available_fb_node_list);
-       }
-}
-
-static void add_fb_to_free_list(struct vdec_vp8_inst *inst, void *fb)
-{
-       struct vdec_fb_node *node;
-
-       if (fb) {
-               node = list_first_entry(&inst->available_fb_node_list,
-                                       struct vdec_fb_node, list);
-               node->fb = fb;
-               list_move_tail(&node->list, &inst->fb_free_list);
-       }
-}
-
-static int alloc_working_buf(struct vdec_vp8_inst *inst)
-{
-       int err;
-       struct mtk_vcodec_mem *mem = &inst->working_buf;
-
-       mem->size = VP8_WORKING_BUF_SZ;
-       err = mtk_vcodec_mem_alloc(inst->ctx, mem);
-       if (err) {
-               mtk_vcodec_err(inst, "Cannot allocate working buffer");
-               return err;
-       }
-
-       inst->vsi->dec.working_buf_dma = (uint64_t)mem->dma_addr;
-       return 0;
-}
-
-static void free_working_buf(struct vdec_vp8_inst *inst)
-{
-       struct mtk_vcodec_mem *mem = &inst->working_buf;
-
-       if (mem->va)
-               mtk_vcodec_mem_free(inst->ctx, mem);
-
-       inst->vsi->dec.working_buf_dma = 0;
-}
-
-static int vdec_vp8_init(struct mtk_vcodec_ctx *ctx)
-{
-       struct vdec_vp8_inst *inst;
-       int err;
-
-       inst = kzalloc(sizeof(*inst), GFP_KERNEL);
-       if (!inst)
-               return  -ENOMEM;
-
-       inst->ctx = ctx;
-
-       inst->vpu.id = IPI_VDEC_VP8;
-       inst->vpu.ctx = ctx;
-
-       err = vpu_dec_init(&inst->vpu);
-       if (err) {
-               mtk_vcodec_err(inst, "vdec_vp8 init err=%d", err);
-               goto error_free_inst;
-       }
-
-       inst->vsi = (struct vdec_vp8_vsi *)inst->vpu.vsi;
-       init_list(inst);
-       err = alloc_working_buf(inst);
-       if (err)
-               goto error_deinit;
-
-       get_hw_reg_base(inst);
-       mtk_vcodec_debug(inst, "VP8 Instance >> %p", inst);
-
-       ctx->drv_handle = inst;
-       return 0;
-
-error_deinit:
-       vpu_dec_deinit(&inst->vpu);
-error_free_inst:
-       kfree(inst);
-       return err;
-}
-
-static int vdec_vp8_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
-                          struct vdec_fb *fb, bool *res_chg)
-{
-       struct vdec_vp8_inst *inst = (struct vdec_vp8_inst *)h_vdec;
-       struct vdec_vp8_dec_info *dec = &inst->vsi->dec;
-       struct vdec_vpu_inst *vpu = &inst->vpu;
-       unsigned char *bs_va;
-       unsigned int data;
-       int err = 0;
-       uint64_t y_fb_dma;
-       uint64_t c_fb_dma;
-
-       /* bs NULL means flush decoder */
-       if (bs == NULL) {
-               move_fb_list_use_to_free(inst);
-               return vpu_dec_reset(vpu);
-       }
-
-       y_fb_dma = fb ? (u64)fb->base_y.dma_addr : 0;
-       c_fb_dma = fb ? (u64)fb->base_c.dma_addr : 0;
-
-       mtk_vcodec_debug(inst, "+ [%d] FB y_dma=%llx c_dma=%llx fb=%p",
-                        inst->frm_cnt, y_fb_dma, c_fb_dma, fb);
-
-       inst->cur_fb = fb;
-       dec->bs_dma = (unsigned long)bs->dma_addr;
-       dec->bs_sz = bs->size;
-       dec->cur_y_fb_dma = y_fb_dma;
-       dec->cur_c_fb_dma = c_fb_dma;
-
-       mtk_vcodec_debug(inst, "\n + FRAME[%d] +\n", inst->frm_cnt);
-
-       write_hw_segmentation_data(inst);
-       enable_hw_rw_function(inst);
-       store_dec_table(inst);
-
-       bs_va = (unsigned char *)bs->va;
-
-       /* retrieve width/hight and scale info from header */
-       data = (*(bs_va + 9) << 24) | (*(bs_va + 8) << 16) |
-              (*(bs_va + 7) << 8) | *(bs_va + 6);
-       err = vpu_dec_start(vpu, &data, 1);
-       if (err) {
-               add_fb_to_free_list(inst, fb);
-               if (dec->wait_key_frame) {
-                       mtk_vcodec_debug(inst, "wait key frame !");
-                       return 0;
-               }
-
-               goto error;
-       }
-
-       if (dec->resolution_changed) {
-               mtk_vcodec_debug(inst, "- resolution_changed -");
-               *res_chg = true;
-               add_fb_to_free_list(inst, fb);
-               return 0;
-       }
-
-       /* wait decoder done interrupt */
-       mtk_vcodec_wait_for_done_ctx(inst->ctx, MTK_INST_IRQ_RECEIVED,
-                                    WAIT_INTR_TIMEOUT_MS, 0);
-
-       if (inst->vsi->load_data)
-               load_dec_table(inst);
-
-       vp8_dec_finish(inst);
-       read_hw_segmentation_data(inst);
-
-       err = vpu_dec_end(vpu);
-       if (err)
-               goto error;
-
-       mtk_vcodec_debug(inst, "\n - FRAME[%d] - show=%d\n", inst->frm_cnt,
-                        dec->show_frame);
-       inst->frm_cnt++;
-       *res_chg = false;
-       return 0;
-
-error:
-       mtk_vcodec_err(inst, "\n - FRAME[%d] - err=%d\n", inst->frm_cnt, err);
-       return err;
-}
-
-static void get_disp_fb(struct vdec_vp8_inst *inst, struct vdec_fb **out_fb)
-{
-       struct vdec_fb_node *node;
-       struct vdec_fb *fb;
-
-       node = list_first_entry_or_null(&inst->fb_disp_list,
-                                       struct vdec_fb_node, list);
-       if (node) {
-               list_move_tail(&node->list, &inst->available_fb_node_list);
-               fb = (struct vdec_fb *)node->fb;
-               fb->status |= FB_ST_DISPLAY;
-               mtk_vcodec_debug(inst, "[FB] get disp fb %p st=%d",
-                                node->fb, fb->status);
-       } else {
-               fb = NULL;
-               mtk_vcodec_debug(inst, "[FB] there is no disp fb");
-       }
-
-       *out_fb = fb;
-}
-
-static void get_free_fb(struct vdec_vp8_inst *inst, struct vdec_fb **out_fb)
-{
-       struct vdec_fb_node *node;
-       struct vdec_fb *fb;
-
-       node = list_first_entry_or_null(&inst->fb_free_list,
-                                       struct vdec_fb_node, list);
-       if (node) {
-               list_move_tail(&node->list, &inst->available_fb_node_list);
-               fb = (struct vdec_fb *)node->fb;
-               fb->status |= FB_ST_FREE;
-               mtk_vcodec_debug(inst, "[FB] get free fb %p st=%d",
-                                node->fb, fb->status);
-       } else {
-               fb = NULL;
-               mtk_vcodec_debug(inst, "[FB] there is no free fb");
-       }
-
-       *out_fb = fb;
-}
-
-static void get_crop_info(struct vdec_vp8_inst *inst, struct v4l2_rect *cr)
-{
-       cr->left = 0;
-       cr->top = 0;
-       cr->width = inst->vsi->pic.pic_w;
-       cr->height = inst->vsi->pic.pic_h;
-       mtk_vcodec_debug(inst, "get crop info l=%d, t=%d, w=%d, h=%d",
-                        cr->left, cr->top, cr->width, cr->height);
-}
-
-static int vdec_vp8_get_param(void *h_vdec, enum vdec_get_param_type type,
-                             void *out)
-{
-       struct vdec_vp8_inst *inst = (struct vdec_vp8_inst *)h_vdec;
-
-       switch (type) {
-       case GET_PARAM_DISP_FRAME_BUFFER:
-               get_disp_fb(inst, out);
-               break;
-
-       case GET_PARAM_FREE_FRAME_BUFFER:
-               get_free_fb(inst, out);
-               break;
-
-       case GET_PARAM_PIC_INFO:
-               get_pic_info(inst, out);
-               break;
-
-       case GET_PARAM_CROP_INFO:
-               get_crop_info(inst, out);
-               break;
-
-       case GET_PARAM_DPB_SIZE:
-               *((unsigned int *)out) = VP8_DPB_SIZE;
-               break;
-
-       default:
-               mtk_vcodec_err(inst, "invalid get parameter type=%d", type);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static void vdec_vp8_deinit(void *h_vdec)
-{
-       struct vdec_vp8_inst *inst = (struct vdec_vp8_inst *)h_vdec;
-
-       mtk_vcodec_debug_enter(inst);
-
-       vpu_dec_deinit(&inst->vpu);
-       free_working_buf(inst);
-       kfree(inst);
-}
-
-const struct vdec_common_if vdec_vp8_if = {
-       .init           = vdec_vp8_init,
-       .decode         = vdec_vp8_decode,
-       .get_param      = vdec_vp8_get_param,
-       .deinit         = vdec_vp8_deinit,
-};
diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c
deleted file mode 100644 (file)
index 70b8383..0000000
+++ /dev/null
@@ -1,1028 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2016 MediaTek Inc.
- * Author: Daniel Hsiao <daniel.hsiao@mediatek.com>
- *     Kai-Sean Yang <kai-sean.yang@mediatek.com>
- *     Tiffany Lin <tiffany.lin@mediatek.com>
- */
-
-#include <linux/fs.h>
-#include <linux/slab.h>
-#include <linux/syscalls.h>
-#include <linux/delay.h>
-#include <linux/time.h>
-
-#include "../mtk_vcodec_intr.h"
-#include "../vdec_drv_base.h"
-#include "../vdec_vpu_if.h"
-
-#define VP9_SUPER_FRAME_BS_SZ 64
-#define MAX_VP9_DPB_SIZE       9
-
-#define REFS_PER_FRAME 3
-#define MAX_NUM_REF_FRAMES 8
-#define VP9_MAX_FRM_BUF_NUM 9
-#define VP9_MAX_FRM_BUF_NODE_NUM (VP9_MAX_FRM_BUF_NUM * 2)
-#define VP9_SEG_ID_SZ 0x12000
-
-/**
- * struct vp9_dram_buf - contains buffer info for vpu
- * @va : cpu address
- * @pa : iova address
- * @sz : buffer size
- * @padding : for 64 bytes alignment
- */
-struct vp9_dram_buf {
-       unsigned long va;
-       unsigned long pa;
-       unsigned int sz;
-       unsigned int padding;
-};
-
-/**
- * struct vp9_fb_info - contains frame buffer info
- * @fb : frmae buffer
- * @reserved : reserved field used by vpu
- */
-struct vp9_fb_info {
-       struct vdec_fb *fb;
-       unsigned int reserved[32];
-};
-
-/**
- * struct vp9_ref_cnt_buf - contains reference buffer information
- * @buf : referenced frame buffer
- * @ref_cnt : referenced frame buffer's reference count.
- *     When reference count=0, remove it from reference list
- */
-struct vp9_ref_cnt_buf {
-       struct vp9_fb_info buf;
-       unsigned int ref_cnt;
-};
-
-/**
- * struct vp9_ref_buf - contains current frame's reference buffer information
- * @buf : reference buffer
- * @idx : reference buffer index to frm_bufs
- * @reserved : reserved field used by vpu
- */
-struct vp9_ref_buf {
-       struct vp9_fb_info *buf;
-       unsigned int idx;
-       unsigned int reserved[6];
-};
-
-/**
- * struct vp9_sf_ref_fb - contains frame buffer info
- * @fb : super frame reference frame buffer
- * @used : this reference frame info entry is used
- * @padding : for 64 bytes size align
- */
-struct vp9_sf_ref_fb {
-       struct vdec_fb fb;
-       int used;
-       int padding;
-};
-
-/*
- * struct vdec_vp9_vsi - shared buffer between host and VPU firmware
- *     AP-W/R : AP is writer/reader on this item
- *     VPU-W/R: VPU is write/reader on this item
- * @sf_bs_buf : super frame backup buffer (AP-W, VPU-R)
- * @sf_ref_fb : record supoer frame reference buffer information
- *     (AP-R/W, VPU-R/W)
- * @sf_next_ref_fb_idx : next available super frame (AP-W, VPU-R)
- * @sf_frm_cnt : super frame count, filled by vpu (AP-R, VPU-W)
- * @sf_frm_offset : super frame offset, filled by vpu (AP-R, VPU-W)
- * @sf_frm_sz : super frame size, filled by vpu (AP-R, VPU-W)
- * @sf_frm_idx : current super frame (AP-R, VPU-W)
- * @sf_init : inform super frame info already parsed by vpu (AP-R, VPU-W)
- * @fb : capture buffer (AP-W, VPU-R)
- * @bs : bs buffer (AP-W, VPU-R)
- * @cur_fb : current show capture buffer (AP-R/W, VPU-R/W)
- * @pic_w : picture width (AP-R, VPU-W)
- * @pic_h : picture height (AP-R, VPU-W)
- * @buf_w : codec width (AP-R, VPU-W)
- * @buf_h : coded height (AP-R, VPU-W)
- * @buf_sz_y_bs : ufo compressed y plane size (AP-R, VPU-W)
- * @buf_sz_c_bs : ufo compressed cbcr plane size (AP-R, VPU-W)
- * @buf_len_sz_y : size used to store y plane ufo info (AP-R, VPU-W)
- * @buf_len_sz_c : size used to store cbcr plane ufo info (AP-R, VPU-W)
-
- * @profile : profile sparsed from vpu (AP-R, VPU-W)
- * @show_frame : [BIT(0)] display this frame or not (AP-R, VPU-W)
- *     [BIT(1)] reset segment data or not (AP-R, VPU-W)
- *     [BIT(2)] trig decoder hardware or not (AP-R, VPU-W)
- *     [BIT(3)] ask VPU to set bits(0~4) accordingly (AP-W, VPU-R)
- *     [BIT(4)] do not reset segment data before every frame (AP-R, VPU-W)
- * @show_existing_frame : inform this frame is show existing frame
- *     (AP-R, VPU-W)
- * @frm_to_show_idx : index to show frame (AP-R, VPU-W)
-
- * @refresh_frm_flags : indicate when frame need to refine reference count
- *     (AP-R, VPU-W)
- * @resolution_changed : resolution change in this frame (AP-R, VPU-W)
-
- * @frm_bufs : maintain reference buffer info (AP-R/W, VPU-R/W)
- * @ref_frm_map : maintain reference buffer map info (AP-R/W, VPU-R/W)
- * @new_fb_idx : index to frm_bufs array (AP-R, VPU-W)
- * @frm_num : decoded frame number, include sub-frame count (AP-R, VPU-W)
- * @mv_buf : motion vector working buffer (AP-W, VPU-R)
- * @frm_refs : maintain three reference buffer info (AP-R/W, VPU-R/W)
- * @seg_id_buf : segmentation map working buffer (AP-W, VPU-R)
- */
-struct vdec_vp9_vsi {
-       unsigned char sf_bs_buf[VP9_SUPER_FRAME_BS_SZ];
-       struct vp9_sf_ref_fb sf_ref_fb[VP9_MAX_FRM_BUF_NUM-1];
-       int sf_next_ref_fb_idx;
-       unsigned int sf_frm_cnt;
-       unsigned int sf_frm_offset[VP9_MAX_FRM_BUF_NUM-1];
-       unsigned int sf_frm_sz[VP9_MAX_FRM_BUF_NUM-1];
-       unsigned int sf_frm_idx;
-       unsigned int sf_init;
-       struct vdec_fb fb;
-       struct mtk_vcodec_mem bs;
-       struct vdec_fb cur_fb;
-       unsigned int pic_w;
-       unsigned int pic_h;
-       unsigned int buf_w;
-       unsigned int buf_h;
-       unsigned int buf_sz_y_bs;
-       unsigned int buf_sz_c_bs;
-       unsigned int buf_len_sz_y;
-       unsigned int buf_len_sz_c;
-       unsigned int profile;
-       unsigned int show_frame;
-       unsigned int show_existing_frame;
-       unsigned int frm_to_show_idx;
-       unsigned int refresh_frm_flags;
-       unsigned int resolution_changed;
-
-       struct vp9_ref_cnt_buf frm_bufs[VP9_MAX_FRM_BUF_NUM];
-       int ref_frm_map[MAX_NUM_REF_FRAMES];
-       unsigned int new_fb_idx;
-       unsigned int frm_num;
-       struct vp9_dram_buf mv_buf;
-
-       struct vp9_ref_buf frm_refs[REFS_PER_FRAME];
-       struct vp9_dram_buf seg_id_buf;
-
-};
-
-/*
- * struct vdec_vp9_inst - vp9 decode instance
- * @mv_buf : working buffer for mv
- * @seg_id_buf : working buffer for segmentation map
- * @dec_fb : vdec_fb node to link fb to different fb_xxx_list
- * @available_fb_node_list : current available vdec_fb node
- * @fb_use_list : current used or referenced vdec_fb
- * @fb_free_list : current available to free vdec_fb
- * @fb_disp_list : current available to display vdec_fb
- * @cur_fb : current frame buffer
- * @ctx : current decode context
- * @vpu : vpu instance information
- * @vsi : shared buffer between host and VPU firmware
- * @total_frm_cnt : total frame count, it do not include sub-frames in super
- *         frame
- * @mem : instance memory information
- */
-struct vdec_vp9_inst {
-       struct mtk_vcodec_mem mv_buf;
-       struct mtk_vcodec_mem seg_id_buf;
-
-       struct vdec_fb_node dec_fb[VP9_MAX_FRM_BUF_NODE_NUM];
-       struct list_head available_fb_node_list;
-       struct list_head fb_use_list;
-       struct list_head fb_free_list;
-       struct list_head fb_disp_list;
-       struct vdec_fb *cur_fb;
-       struct mtk_vcodec_ctx *ctx;
-       struct vdec_vpu_inst vpu;
-       struct vdec_vp9_vsi *vsi;
-       unsigned int total_frm_cnt;
-       struct mtk_vcodec_mem mem;
-};
-
-static bool vp9_is_sf_ref_fb(struct vdec_vp9_inst *inst, struct vdec_fb *fb)
-{
-       int i;
-       struct vdec_vp9_vsi *vsi = inst->vsi;
-
-       for (i = 0; i < ARRAY_SIZE(vsi->sf_ref_fb); i++) {
-               if (fb == &vsi->sf_ref_fb[i].fb)
-                       return true;
-       }
-       return false;
-}
-
-static struct vdec_fb *vp9_rm_from_fb_use_list(struct vdec_vp9_inst
-                                       *inst, void *addr)
-{
-       struct vdec_fb *fb = NULL;
-       struct vdec_fb_node *node;
-
-       list_for_each_entry(node, &inst->fb_use_list, list) {
-               fb = (struct vdec_fb *)node->fb;
-               if (fb->base_y.va == addr) {
-                       list_move_tail(&node->list,
-                                      &inst->available_fb_node_list);
-                       break;
-               }
-       }
-       return fb;
-}
-
-static void vp9_add_to_fb_free_list(struct vdec_vp9_inst *inst,
-                            struct vdec_fb *fb)
-{
-       struct vdec_fb_node *node;
-
-       if (fb) {
-               node = list_first_entry_or_null(&inst->available_fb_node_list,
-                                       struct vdec_fb_node, list);
-
-               if (node) {
-                       node->fb = fb;
-                       list_move_tail(&node->list, &inst->fb_free_list);
-               }
-       } else {
-               mtk_vcodec_debug(inst, "No free fb node");
-       }
-}
-
-static void vp9_free_sf_ref_fb(struct vdec_fb *fb)
-{
-       struct vp9_sf_ref_fb *sf_ref_fb =
-               container_of(fb, struct vp9_sf_ref_fb, fb);
-
-       sf_ref_fb->used = 0;
-}
-
-static void vp9_ref_cnt_fb(struct vdec_vp9_inst *inst, int *idx,
-                          int new_idx)
-{
-       struct vdec_vp9_vsi *vsi = inst->vsi;
-       int ref_idx = *idx;
-
-       if (ref_idx >= 0 && vsi->frm_bufs[ref_idx].ref_cnt > 0) {
-               vsi->frm_bufs[ref_idx].ref_cnt--;
-
-               if (vsi->frm_bufs[ref_idx].ref_cnt == 0) {
-                       if (!vp9_is_sf_ref_fb(inst,
-                                             vsi->frm_bufs[ref_idx].buf.fb)) {
-                               struct vdec_fb *fb;
-
-                               fb = vp9_rm_from_fb_use_list(inst,
-                                    vsi->frm_bufs[ref_idx].buf.fb->base_y.va);
-                               vp9_add_to_fb_free_list(inst, fb);
-                       } else
-                               vp9_free_sf_ref_fb(
-                                       vsi->frm_bufs[ref_idx].buf.fb);
-               }
-       }
-
-       *idx = new_idx;
-       vsi->frm_bufs[new_idx].ref_cnt++;
-}
-
-static void vp9_free_all_sf_ref_fb(struct vdec_vp9_inst *inst)
-{
-       int i;
-       struct vdec_vp9_vsi *vsi = inst->vsi;
-
-       for (i = 0; i < ARRAY_SIZE(vsi->sf_ref_fb); i++) {
-               if (vsi->sf_ref_fb[i].fb.base_y.va) {
-                       mtk_vcodec_mem_free(inst->ctx,
-                               &vsi->sf_ref_fb[i].fb.base_y);
-                       mtk_vcodec_mem_free(inst->ctx,
-                               &vsi->sf_ref_fb[i].fb.base_c);
-                       vsi->sf_ref_fb[i].used = 0;
-               }
-       }
-}
-
-/* For each sub-frame except the last one, the driver will dynamically
- * allocate reference buffer by calling vp9_get_sf_ref_fb()
- * The last sub-frame will use the original fb provided by the
- * vp9_dec_decode() interface
- */
-static int vp9_get_sf_ref_fb(struct vdec_vp9_inst *inst)
-{
-       int idx;
-       struct mtk_vcodec_mem *mem_basy_y;
-       struct mtk_vcodec_mem *mem_basy_c;
-       struct vdec_vp9_vsi *vsi = inst->vsi;
-
-       for (idx = 0;
-               idx < ARRAY_SIZE(vsi->sf_ref_fb);
-               idx++) {
-               if (vsi->sf_ref_fb[idx].fb.base_y.va &&
-                   vsi->sf_ref_fb[idx].used == 0) {
-                       return idx;
-               }
-       }
-
-       for (idx = 0;
-               idx < ARRAY_SIZE(vsi->sf_ref_fb);
-               idx++) {
-               if (vsi->sf_ref_fb[idx].fb.base_y.va == NULL)
-                       break;
-       }
-
-       if (idx == ARRAY_SIZE(vsi->sf_ref_fb)) {
-               mtk_vcodec_err(inst, "List Full");
-               return -1;
-       }
-
-       mem_basy_y = &vsi->sf_ref_fb[idx].fb.base_y;
-       mem_basy_y->size = vsi->buf_sz_y_bs +
-               vsi->buf_len_sz_y;
-
-       if (mtk_vcodec_mem_alloc(inst->ctx, mem_basy_y)) {
-               mtk_vcodec_err(inst, "Cannot allocate sf_ref_buf y_buf");
-               return -1;
-       }
-
-       mem_basy_c = &vsi->sf_ref_fb[idx].fb.base_c;
-       mem_basy_c->size = vsi->buf_sz_c_bs +
-               vsi->buf_len_sz_c;
-
-       if (mtk_vcodec_mem_alloc(inst->ctx, mem_basy_c)) {
-               mtk_vcodec_err(inst, "Cannot allocate sf_ref_fb c_buf");
-               return -1;
-       }
-       vsi->sf_ref_fb[idx].used = 0;
-
-       return idx;
-}
-
-static bool vp9_alloc_work_buf(struct vdec_vp9_inst *inst)
-{
-       struct vdec_vp9_vsi *vsi = inst->vsi;
-       int result;
-       struct mtk_vcodec_mem *mem;
-
-       unsigned int max_pic_w;
-       unsigned int max_pic_h;
-
-
-       if (!(inst->ctx->dev->dec_capability &
-               VCODEC_CAPABILITY_4K_DISABLED)) {
-               max_pic_w = VCODEC_DEC_4K_CODED_WIDTH;
-               max_pic_h = VCODEC_DEC_4K_CODED_HEIGHT;
-       } else {
-               max_pic_w = MTK_VDEC_MAX_W;
-               max_pic_h = MTK_VDEC_MAX_H;
-       }
-
-       if ((vsi->pic_w > max_pic_w) ||
-               (vsi->pic_h > max_pic_h)) {
-               mtk_vcodec_err(inst, "Invalid w/h %d/%d",
-                               vsi->pic_w, vsi->pic_h);
-               return false;
-       }
-
-       mtk_vcodec_debug(inst, "BUF CHG(%d): w/h/sb_w/sb_h=%d/%d/%d/%d",
-                       vsi->resolution_changed,
-                       vsi->pic_w,
-                       vsi->pic_h,
-                       vsi->buf_w,
-                       vsi->buf_h);
-
-       mem = &inst->mv_buf;
-       if (mem->va)
-               mtk_vcodec_mem_free(inst->ctx, mem);
-
-       mem->size = ((vsi->buf_w / 64) *
-                   (vsi->buf_h / 64) + 2) * 36 * 16;
-       result = mtk_vcodec_mem_alloc(inst->ctx, mem);
-       if (result) {
-               mem->size = 0;
-               mtk_vcodec_err(inst, "Cannot allocate mv_buf");
-               return false;
-       }
-       /* Set the va again */
-       vsi->mv_buf.va = (unsigned long)mem->va;
-       vsi->mv_buf.pa = (unsigned long)mem->dma_addr;
-       vsi->mv_buf.sz = (unsigned int)mem->size;
-
-
-       mem = &inst->seg_id_buf;
-       if (mem->va)
-               mtk_vcodec_mem_free(inst->ctx, mem);
-
-       mem->size = VP9_SEG_ID_SZ;
-       result = mtk_vcodec_mem_alloc(inst->ctx, mem);
-       if (result) {
-               mem->size = 0;
-               mtk_vcodec_err(inst, "Cannot allocate seg_id_buf");
-               return false;
-       }
-       /* Set the va again */
-       vsi->seg_id_buf.va = (unsigned long)mem->va;
-       vsi->seg_id_buf.pa = (unsigned long)mem->dma_addr;
-       vsi->seg_id_buf.sz = (unsigned int)mem->size;
-
-
-       vp9_free_all_sf_ref_fb(inst);
-       vsi->sf_next_ref_fb_idx = vp9_get_sf_ref_fb(inst);
-
-       return true;
-}
-
-static bool vp9_add_to_fb_disp_list(struct vdec_vp9_inst *inst,
-                            struct vdec_fb *fb)
-{
-       struct vdec_fb_node *node;
-
-       if (!fb) {
-               mtk_vcodec_err(inst, "fb == NULL");
-               return false;
-       }
-
-       node = list_first_entry_or_null(&inst->available_fb_node_list,
-                                       struct vdec_fb_node, list);
-       if (node) {
-               node->fb = fb;
-               list_move_tail(&node->list, &inst->fb_disp_list);
-       } else {
-               mtk_vcodec_err(inst, "No available fb node");
-               return false;
-       }
-
-       return true;
-}
-
-/* If any buffer updating is signaled it should be done here. */
-static void vp9_swap_frm_bufs(struct vdec_vp9_inst *inst)
-{
-       struct vdec_vp9_vsi *vsi = inst->vsi;
-       struct vp9_fb_info *frm_to_show;
-       int ref_index = 0, mask;
-
-       for (mask = vsi->refresh_frm_flags; mask; mask >>= 1) {
-               if (mask & 1)
-                       vp9_ref_cnt_fb(inst, &vsi->ref_frm_map[ref_index],
-                                      vsi->new_fb_idx);
-               ++ref_index;
-       }
-
-       frm_to_show = &vsi->frm_bufs[vsi->new_fb_idx].buf;
-       vsi->frm_bufs[vsi->new_fb_idx].ref_cnt--;
-
-       if (frm_to_show->fb != inst->cur_fb) {
-               /* This frame is show exist frame and no decode output
-                * copy frame data from frm_to_show to current CAPTURE
-                * buffer
-                */
-               if ((frm_to_show->fb != NULL) &&
-                       (inst->cur_fb->base_y.size >=
-                       frm_to_show->fb->base_y.size) &&
-                       (inst->cur_fb->base_c.size >=
-                       frm_to_show->fb->base_c.size)) {
-                       memcpy((void *)inst->cur_fb->base_y.va,
-                               (void *)frm_to_show->fb->base_y.va,
-                               frm_to_show->fb->base_y.size);
-                       memcpy((void *)inst->cur_fb->base_c.va,
-                               (void *)frm_to_show->fb->base_c.va,
-                               frm_to_show->fb->base_c.size);
-               } else {
-                       /* After resolution change case, current CAPTURE buffer
-                        * may have less buffer size than frm_to_show buffer
-                        * size
-                        */
-                       if (frm_to_show->fb != NULL)
-                               mtk_vcodec_err(inst,
-                                       "inst->cur_fb->base_y.size=%zu, frm_to_show->fb.base_y.size=%zu",
-                                       inst->cur_fb->base_y.size,
-                                       frm_to_show->fb->base_y.size);
-               }
-               if (!vp9_is_sf_ref_fb(inst, inst->cur_fb)) {
-                       if (vsi->show_frame & BIT(0))
-                               vp9_add_to_fb_disp_list(inst, inst->cur_fb);
-               }
-       } else {
-               if (!vp9_is_sf_ref_fb(inst, inst->cur_fb)) {
-                       if (vsi->show_frame & BIT(0))
-                               vp9_add_to_fb_disp_list(inst, frm_to_show->fb);
-               }
-       }
-
-       /* when ref_cnt ==0, move this fb to fb_free_list. v4l2 driver will
-        * clean fb_free_list
-        */
-       if (vsi->frm_bufs[vsi->new_fb_idx].ref_cnt == 0) {
-               if (!vp9_is_sf_ref_fb(
-                       inst, vsi->frm_bufs[vsi->new_fb_idx].buf.fb)) {
-                       struct vdec_fb *fb;
-
-                       fb = vp9_rm_from_fb_use_list(inst,
-                       vsi->frm_bufs[vsi->new_fb_idx].buf.fb->base_y.va);
-
-                       vp9_add_to_fb_free_list(inst, fb);
-               } else {
-                       vp9_free_sf_ref_fb(
-                               vsi->frm_bufs[vsi->new_fb_idx].buf.fb);
-               }
-       }
-
-       /* if this super frame and it is not last sub-frame, get next fb for
-        * sub-frame decode
-        */
-       if (vsi->sf_frm_cnt > 0 && vsi->sf_frm_idx != vsi->sf_frm_cnt - 1)
-               vsi->sf_next_ref_fb_idx = vp9_get_sf_ref_fb(inst);
-}
-
-static bool vp9_wait_dec_end(struct vdec_vp9_inst *inst)
-{
-       struct mtk_vcodec_ctx *ctx = inst->ctx;
-
-       mtk_vcodec_wait_for_done_ctx(inst->ctx,
-                       MTK_INST_IRQ_RECEIVED,
-                       WAIT_INTR_TIMEOUT_MS, 0);
-
-       if (ctx->irq_status & MTK_VDEC_IRQ_STATUS_DEC_SUCCESS)
-               return true;
-       else
-               return false;
-}
-
-static struct vdec_vp9_inst *vp9_alloc_inst(struct mtk_vcodec_ctx *ctx)
-{
-       int result;
-       struct mtk_vcodec_mem mem;
-       struct vdec_vp9_inst *inst;
-
-       memset(&mem, 0, sizeof(mem));
-       mem.size = sizeof(struct vdec_vp9_inst);
-       result = mtk_vcodec_mem_alloc(ctx, &mem);
-       if (result)
-               return NULL;
-
-       inst = mem.va;
-       inst->mem = mem;
-
-       return inst;
-}
-
-static void vp9_free_inst(struct vdec_vp9_inst *inst)
-{
-       struct mtk_vcodec_mem mem;
-
-       mem = inst->mem;
-       if (mem.va)
-               mtk_vcodec_mem_free(inst->ctx, &mem);
-}
-
-static bool vp9_decode_end_proc(struct vdec_vp9_inst *inst)
-{
-       struct vdec_vp9_vsi *vsi = inst->vsi;
-       bool ret = false;
-
-       if (!vsi->show_existing_frame) {
-               ret = vp9_wait_dec_end(inst);
-               if (!ret) {
-                       mtk_vcodec_err(inst, "Decode failed, Decode Timeout @[%d]",
-                               vsi->frm_num);
-                       return false;
-               }
-
-               if (vpu_dec_end(&inst->vpu)) {
-                       mtk_vcodec_err(inst, "vp9_dec_vpu_end failed");
-                       return false;
-               }
-               mtk_vcodec_debug(inst, "Decode Ok @%d (%d/%d)", vsi->frm_num,
-                               vsi->pic_w, vsi->pic_h);
-       } else {
-               mtk_vcodec_debug(inst, "Decode Ok @%d (show_existing_frame)",
-                               vsi->frm_num);
-       }
-
-       vp9_swap_frm_bufs(inst);
-       vsi->frm_num++;
-       return true;
-}
-
-static bool vp9_is_last_sub_frm(struct vdec_vp9_inst *inst)
-{
-       struct vdec_vp9_vsi *vsi = inst->vsi;
-
-       if (vsi->sf_frm_cnt <= 0 || vsi->sf_frm_idx == vsi->sf_frm_cnt)
-               return true;
-
-       return false;
-}
-
-static struct vdec_fb *vp9_rm_from_fb_disp_list(struct vdec_vp9_inst *inst)
-{
-       struct vdec_fb_node *node;
-       struct vdec_fb *fb = NULL;
-
-       node = list_first_entry_or_null(&inst->fb_disp_list,
-                                       struct vdec_fb_node, list);
-       if (node) {
-               fb = (struct vdec_fb *)node->fb;
-               fb->status |= FB_ST_DISPLAY;
-               list_move_tail(&node->list, &inst->available_fb_node_list);
-               mtk_vcodec_debug(inst, "[FB] get disp fb %p st=%d",
-                                node->fb, fb->status);
-       } else
-               mtk_vcodec_debug(inst, "[FB] there is no disp fb");
-
-       return fb;
-}
-
-static bool vp9_add_to_fb_use_list(struct vdec_vp9_inst *inst,
-                           struct vdec_fb *fb)
-{
-       struct vdec_fb_node *node;
-
-       if (!fb) {
-               mtk_vcodec_debug(inst, "fb == NULL");
-               return false;
-       }
-
-       node = list_first_entry_or_null(&inst->available_fb_node_list,
-                                       struct vdec_fb_node, list);
-       if (node) {
-               node->fb = fb;
-               list_move_tail(&node->list, &inst->fb_use_list);
-       } else {
-               mtk_vcodec_err(inst, "No free fb node");
-               return false;
-       }
-       return true;
-}
-
-static void vp9_reset(struct vdec_vp9_inst *inst)
-{
-       struct vdec_fb_node *node, *tmp;
-
-       list_for_each_entry_safe(node, tmp, &inst->fb_use_list, list)
-               list_move_tail(&node->list, &inst->fb_free_list);
-
-       vp9_free_all_sf_ref_fb(inst);
-       inst->vsi->sf_next_ref_fb_idx = vp9_get_sf_ref_fb(inst);
-
-       if (vpu_dec_reset(&inst->vpu))
-               mtk_vcodec_err(inst, "vp9_dec_vpu_reset failed");
-
-       /* Set the va again, since vpu_dec_reset will clear mv_buf in vpu */
-       inst->vsi->mv_buf.va = (unsigned long)inst->mv_buf.va;
-       inst->vsi->mv_buf.pa = (unsigned long)inst->mv_buf.dma_addr;
-       inst->vsi->mv_buf.sz = (unsigned long)inst->mv_buf.size;
-
-       /* Set the va again, since vpu_dec_reset will clear seg_id_buf in vpu */
-       inst->vsi->seg_id_buf.va = (unsigned long)inst->seg_id_buf.va;
-       inst->vsi->seg_id_buf.pa = (unsigned long)inst->seg_id_buf.dma_addr;
-       inst->vsi->seg_id_buf.sz = (unsigned long)inst->seg_id_buf.size;
-
-}
-
-static void init_all_fb_lists(struct vdec_vp9_inst *inst)
-{
-       int i;
-
-       INIT_LIST_HEAD(&inst->available_fb_node_list);
-       INIT_LIST_HEAD(&inst->fb_use_list);
-       INIT_LIST_HEAD(&inst->fb_free_list);
-       INIT_LIST_HEAD(&inst->fb_disp_list);
-
-       for (i = 0; i < ARRAY_SIZE(inst->dec_fb); i++) {
-               INIT_LIST_HEAD(&inst->dec_fb[i].list);
-               inst->dec_fb[i].fb = NULL;
-               list_add_tail(&inst->dec_fb[i].list,
-                             &inst->available_fb_node_list);
-       }
-}
-
-static void get_pic_info(struct vdec_vp9_inst *inst, struct vdec_pic_info *pic)
-{
-       pic->fb_sz[0] = inst->vsi->buf_sz_y_bs + inst->vsi->buf_len_sz_y;
-       pic->fb_sz[1] = inst->vsi->buf_sz_c_bs + inst->vsi->buf_len_sz_c;
-
-       pic->pic_w = inst->vsi->pic_w;
-       pic->pic_h = inst->vsi->pic_h;
-       pic->buf_w = inst->vsi->buf_w;
-       pic->buf_h = inst->vsi->buf_h;
-
-       mtk_vcodec_debug(inst, "pic(%d, %d), buf(%d, %d)",
-                pic->pic_w, pic->pic_h, pic->buf_w, pic->buf_h);
-       mtk_vcodec_debug(inst, "fb size: Y(%d), C(%d)",
-               pic->fb_sz[0],
-               pic->fb_sz[1]);
-}
-
-static void get_disp_fb(struct vdec_vp9_inst *inst, struct vdec_fb **out_fb)
-{
-
-       *out_fb = vp9_rm_from_fb_disp_list(inst);
-       if (*out_fb)
-               (*out_fb)->status |= FB_ST_DISPLAY;
-}
-
-static void get_free_fb(struct vdec_vp9_inst *inst, struct vdec_fb **out_fb)
-{
-       struct vdec_fb_node *node;
-       struct vdec_fb *fb = NULL;
-
-       node = list_first_entry_or_null(&inst->fb_free_list,
-                                       struct vdec_fb_node, list);
-       if (node) {
-               list_move_tail(&node->list, &inst->available_fb_node_list);
-               fb = (struct vdec_fb *)node->fb;
-               fb->status |= FB_ST_FREE;
-               mtk_vcodec_debug(inst, "[FB] get free fb %p st=%d",
-                                node->fb, fb->status);
-       } else {
-               mtk_vcodec_debug(inst, "[FB] there is no free fb");
-       }
-
-       *out_fb = fb;
-}
-
-static int validate_vsi_array_indexes(struct vdec_vp9_inst *inst,
-               struct vdec_vp9_vsi *vsi) {
-       if (vsi->sf_frm_idx >= VP9_MAX_FRM_BUF_NUM - 1) {
-               mtk_vcodec_err(inst, "Invalid vsi->sf_frm_idx=%u.",
-                               vsi->sf_frm_idx);
-               return -EIO;
-       }
-       if (vsi->frm_to_show_idx >= VP9_MAX_FRM_BUF_NUM) {
-               mtk_vcodec_err(inst, "Invalid vsi->frm_to_show_idx=%u.",
-                               vsi->frm_to_show_idx);
-               return -EIO;
-       }
-       if (vsi->new_fb_idx >= VP9_MAX_FRM_BUF_NUM) {
-               mtk_vcodec_err(inst, "Invalid vsi->new_fb_idx=%u.",
-                               vsi->new_fb_idx);
-               return -EIO;
-       }
-       return 0;
-}
-
-static void vdec_vp9_deinit(void *h_vdec)
-{
-       struct vdec_vp9_inst *inst = (struct vdec_vp9_inst *)h_vdec;
-       struct mtk_vcodec_mem *mem;
-       int ret = 0;
-
-       ret = vpu_dec_deinit(&inst->vpu);
-       if (ret)
-               mtk_vcodec_err(inst, "vpu_dec_deinit failed");
-
-       mem = &inst->mv_buf;
-       if (mem->va)
-               mtk_vcodec_mem_free(inst->ctx, mem);
-
-       mem = &inst->seg_id_buf;
-       if (mem->va)
-               mtk_vcodec_mem_free(inst->ctx, mem);
-
-       vp9_free_all_sf_ref_fb(inst);
-       vp9_free_inst(inst);
-}
-
-static int vdec_vp9_init(struct mtk_vcodec_ctx *ctx)
-{
-       struct vdec_vp9_inst *inst;
-
-       inst = vp9_alloc_inst(ctx);
-       if (!inst)
-               return -ENOMEM;
-
-       inst->total_frm_cnt = 0;
-       inst->ctx = ctx;
-
-       inst->vpu.id = IPI_VDEC_VP9;
-       inst->vpu.ctx = ctx;
-
-       if (vpu_dec_init(&inst->vpu)) {
-               mtk_vcodec_err(inst, "vp9_dec_vpu_init failed");
-               goto err_deinit_inst;
-       }
-
-       inst->vsi = (struct vdec_vp9_vsi *)inst->vpu.vsi;
-
-       inst->vsi->show_frame |= BIT(3);
-
-       init_all_fb_lists(inst);
-
-       ctx->drv_handle = inst;
-       return 0;
-
-err_deinit_inst:
-       vp9_free_inst(inst);
-
-       return -EINVAL;
-}
-
-static int vdec_vp9_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
-                          struct vdec_fb *fb, bool *res_chg)
-{
-       int ret = 0;
-       struct vdec_vp9_inst *inst = (struct vdec_vp9_inst *)h_vdec;
-       struct vdec_vp9_vsi *vsi = inst->vsi;
-       u32 data[3];
-       int i;
-
-       *res_chg = false;
-
-       if ((bs == NULL) && (fb == NULL)) {
-               mtk_vcodec_debug(inst, "[EOS]");
-               vp9_reset(inst);
-               return ret;
-       }
-
-       if (bs == NULL) {
-               mtk_vcodec_err(inst, "bs == NULL");
-               return -EINVAL;
-       }
-
-       mtk_vcodec_debug(inst, "Input BS Size = %zu", bs->size);
-
-       while (1) {
-               struct vdec_fb *cur_fb = NULL;
-
-               data[0] = *((unsigned int *)bs->va);
-               data[1] = *((unsigned int *)(bs->va + 4));
-               data[2] = *((unsigned int *)(bs->va + 8));
-
-               vsi->bs = *bs;
-
-               if (fb)
-                       vsi->fb = *fb;
-
-               if (!vsi->sf_init) {
-                       unsigned int sf_bs_sz;
-                       unsigned int sf_bs_off;
-                       unsigned char *sf_bs_src;
-                       unsigned char *sf_bs_dst;
-
-                       sf_bs_sz = bs->size > VP9_SUPER_FRAME_BS_SZ ?
-                                       VP9_SUPER_FRAME_BS_SZ : bs->size;
-                       sf_bs_off = VP9_SUPER_FRAME_BS_SZ - sf_bs_sz;
-                       sf_bs_src = bs->va + bs->size - sf_bs_sz;
-                       sf_bs_dst = vsi->sf_bs_buf + sf_bs_off;
-                       memcpy(sf_bs_dst, sf_bs_src, sf_bs_sz);
-               } else {
-                       if ((vsi->sf_frm_cnt > 0) &&
-                               (vsi->sf_frm_idx < vsi->sf_frm_cnt)) {
-                               unsigned int idx = vsi->sf_frm_idx;
-
-                               memcpy((void *)bs->va,
-                                       (void *)(bs->va +
-                                       vsi->sf_frm_offset[idx]),
-                                       vsi->sf_frm_sz[idx]);
-                       }
-               }
-
-               if (!(vsi->show_frame & BIT(4)))
-                       memset(inst->seg_id_buf.va, 0, inst->seg_id_buf.size);
-
-               ret = vpu_dec_start(&inst->vpu, data, 3);
-               if (ret) {
-                       mtk_vcodec_err(inst, "vpu_dec_start failed");
-                       goto DECODE_ERROR;
-               }
-
-               if (vsi->show_frame & BIT(1)) {
-                       memset(inst->seg_id_buf.va, 0, inst->seg_id_buf.size);
-
-                       if (vsi->show_frame & BIT(2)) {
-                               ret = vpu_dec_start(&inst->vpu, NULL, 0);
-                               if (ret) {
-                                       mtk_vcodec_err(inst, "vpu trig decoder failed");
-                                       goto DECODE_ERROR;
-                               }
-                       }
-               }
-
-               ret = validate_vsi_array_indexes(inst, vsi);
-               if (ret) {
-                       mtk_vcodec_err(inst, "Invalid values from VPU.");
-                       goto DECODE_ERROR;
-               }
-
-               if (vsi->resolution_changed) {
-                       if (!vp9_alloc_work_buf(inst)) {
-                               ret = -EIO;
-                               goto DECODE_ERROR;
-                       }
-               }
-
-               if (vsi->sf_frm_cnt > 0) {
-                       cur_fb = &vsi->sf_ref_fb[vsi->sf_next_ref_fb_idx].fb;
-
-                       if (vsi->sf_frm_idx < vsi->sf_frm_cnt)
-                               inst->cur_fb = cur_fb;
-                       else
-                               inst->cur_fb = fb;
-               } else {
-                       inst->cur_fb = fb;
-               }
-
-               vsi->frm_bufs[vsi->new_fb_idx].buf.fb = inst->cur_fb;
-               if (!vp9_is_sf_ref_fb(inst, inst->cur_fb))
-                       vp9_add_to_fb_use_list(inst, inst->cur_fb);
-
-               mtk_vcodec_debug(inst, "[#pic %d]", vsi->frm_num);
-
-               if (vsi->show_existing_frame)
-                       mtk_vcodec_debug(inst,
-                               "drv->new_fb_idx=%d, drv->frm_to_show_idx=%d",
-                               vsi->new_fb_idx, vsi->frm_to_show_idx);
-
-               if (vsi->show_existing_frame && (vsi->frm_to_show_idx <
-                                       VP9_MAX_FRM_BUF_NUM)) {
-                       mtk_vcodec_debug(inst,
-                               "Skip Decode drv->new_fb_idx=%d, drv->frm_to_show_idx=%d",
-                               vsi->new_fb_idx, vsi->frm_to_show_idx);
-
-                       vp9_ref_cnt_fb(inst, &vsi->new_fb_idx,
-                                       vsi->frm_to_show_idx);
-               }
-
-               /* VPU assign the buffer pointer in its address space,
-                * reassign here
-                */
-               for (i = 0; i < ARRAY_SIZE(vsi->frm_refs); i++) {
-                       unsigned int idx = vsi->frm_refs[i].idx;
-
-                       vsi->frm_refs[i].buf = &vsi->frm_bufs[idx].buf;
-               }
-
-               if (vsi->resolution_changed) {
-                       *res_chg = true;
-                       mtk_vcodec_debug(inst, "VDEC_ST_RESOLUTION_CHANGED");
-
-                       ret = 0;
-                       goto DECODE_ERROR;
-               }
-
-               if (!vp9_decode_end_proc(inst)) {
-                       mtk_vcodec_err(inst, "vp9_decode_end_proc");
-                       ret = -EINVAL;
-                       goto DECODE_ERROR;
-               }
-
-               if (vp9_is_last_sub_frm(inst))
-                       break;
-
-       }
-       inst->total_frm_cnt++;
-
-DECODE_ERROR:
-       if (ret < 0)
-               vp9_add_to_fb_free_list(inst, fb);
-
-       return ret;
-}
-
-static void get_crop_info(struct vdec_vp9_inst *inst, struct v4l2_rect *cr)
-{
-       cr->left = 0;
-       cr->top = 0;
-       cr->width = inst->vsi->pic_w;
-       cr->height = inst->vsi->pic_h;
-       mtk_vcodec_debug(inst, "get crop info l=%d, t=%d, w=%d, h=%d\n",
-                        cr->left, cr->top, cr->width, cr->height);
-}
-
-static int vdec_vp9_get_param(void *h_vdec, enum vdec_get_param_type type,
-                             void *out)
-{
-       struct vdec_vp9_inst *inst = (struct vdec_vp9_inst *)h_vdec;
-       int ret = 0;
-
-       switch (type) {
-       case GET_PARAM_DISP_FRAME_BUFFER:
-               get_disp_fb(inst, out);
-               break;
-       case GET_PARAM_FREE_FRAME_BUFFER:
-               get_free_fb(inst, out);
-               break;
-       case GET_PARAM_PIC_INFO:
-               get_pic_info(inst, out);
-               break;
-       case GET_PARAM_DPB_SIZE:
-               *((unsigned int *)out) = MAX_VP9_DPB_SIZE;
-               break;
-       case GET_PARAM_CROP_INFO:
-               get_crop_info(inst, out);
-               break;
-       default:
-               mtk_vcodec_err(inst, "not supported param type %d", type);
-               ret = -EINVAL;
-               break;
-       }
-
-       return ret;
-}
-
-const struct vdec_common_if vdec_vp9_if = {
-       .init           = vdec_vp9_init,
-       .decode         = vdec_vp9_decode,
-       .get_param      = vdec_vp9_get_param,
-       .deinit         = vdec_vp9_deinit,
-};
diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_base.h b/drivers/media/platform/mtk-vcodec/vdec_drv_base.h
deleted file mode 100644 (file)
index e913f96..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (c) 2016 MediaTek Inc.
- * Author: PC Chen <pc.chen@mediatek.com>
- */
-
-#ifndef _VDEC_DRV_BASE_
-#define _VDEC_DRV_BASE_
-
-#include "vdec_drv_if.h"
-
-struct vdec_common_if {
-       /**
-        * (*init)() - initialize decode driver
-        * @ctx     : [in] mtk v4l2 context
-        * @h_vdec  : [out] driver handle
-        */
-       int (*init)(struct mtk_vcodec_ctx *ctx);
-
-       /**
-        * (*decode)() - trigger decode
-        * @h_vdec  : [in] driver handle
-        * @bs      : [in] input bitstream
-        * @fb      : [in] frame buffer to store decoded frame
-        * @res_chg : [out] resolution change happen
-        */
-       int (*decode)(void *h_vdec, struct mtk_vcodec_mem *bs,
-                     struct vdec_fb *fb, bool *res_chg);
-
-       /**
-        * (*get_param)() - get driver's parameter
-        * @h_vdec : [in] driver handle
-        * @type   : [in] input parameter type
-        * @out    : [out] buffer to store query result
-        */
-       int (*get_param)(void *h_vdec, enum vdec_get_param_type type,
-                        void *out);
-
-       /**
-        * (*deinit)() - deinitialize driver.
-        * @h_vdec : [in] driver handle to be deinit
-        */
-       void (*deinit)(void *h_vdec);
-};
-
-#endif
diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_if.c b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c
deleted file mode 100644 (file)
index 05a5b24..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2016 MediaTek Inc.
- * Author: PC Chen <pc.chen@mediatek.com>
- *         Tiffany Lin <tiffany.lin@mediatek.com>
- */
-
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-
-#include "vdec_drv_if.h"
-#include "mtk_vcodec_dec.h"
-#include "vdec_drv_base.h"
-#include "mtk_vcodec_dec_pm.h"
-
-int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc)
-{
-       int ret = 0;
-
-       switch (fourcc) {
-       case V4L2_PIX_FMT_H264_SLICE:
-               ctx->dec_if = &vdec_h264_slice_if;
-               break;
-       case V4L2_PIX_FMT_H264:
-               ctx->dec_if = &vdec_h264_if;
-               ctx->hw_id = MTK_VDEC_CORE;
-               break;
-       case V4L2_PIX_FMT_VP8:
-               ctx->dec_if = &vdec_vp8_if;
-               ctx->hw_id = MTK_VDEC_CORE;
-               break;
-       case V4L2_PIX_FMT_VP9:
-               ctx->dec_if = &vdec_vp9_if;
-               ctx->hw_id = MTK_VDEC_CORE;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       mtk_vdec_lock(ctx);
-       mtk_vcodec_dec_clock_on(ctx->dev, ctx->hw_id);
-       ret = ctx->dec_if->init(ctx);
-       mtk_vcodec_dec_clock_off(ctx->dev, ctx->hw_id);
-       mtk_vdec_unlock(ctx);
-
-       return ret;
-}
-
-int vdec_if_decode(struct mtk_vcodec_ctx *ctx, struct mtk_vcodec_mem *bs,
-                  struct vdec_fb *fb, bool *res_chg)
-{
-       int ret = 0;
-
-       if (bs) {
-               if ((bs->dma_addr & 63) != 0) {
-                       mtk_v4l2_err("bs dma_addr should 64 byte align");
-                       return -EINVAL;
-               }
-       }
-
-       if (fb) {
-               if (((fb->base_y.dma_addr & 511) != 0) ||
-                   ((fb->base_c.dma_addr & 511) != 0)) {
-                       mtk_v4l2_err("frame buffer dma_addr should 512 byte align");
-                       return -EINVAL;
-               }
-       }
-
-       if (!ctx->drv_handle)
-               return -EIO;
-
-       mtk_vdec_lock(ctx);
-
-       mtk_vcodec_set_curr_ctx(ctx->dev, ctx, ctx->hw_id);
-       mtk_vcodec_dec_clock_on(ctx->dev, ctx->hw_id);
-       ret = ctx->dec_if->decode(ctx->drv_handle, bs, fb, res_chg);
-       mtk_vcodec_dec_clock_off(ctx->dev, ctx->hw_id);
-       mtk_vcodec_set_curr_ctx(ctx->dev, NULL, ctx->hw_id);
-
-       mtk_vdec_unlock(ctx);
-
-       return ret;
-}
-
-int vdec_if_get_param(struct mtk_vcodec_ctx *ctx, enum vdec_get_param_type type,
-                     void *out)
-{
-       int ret = 0;
-
-       if (!ctx->drv_handle)
-               return -EIO;
-
-       mtk_vdec_lock(ctx);
-       ret = ctx->dec_if->get_param(ctx->drv_handle, type, out);
-       mtk_vdec_unlock(ctx);
-
-       return ret;
-}
-
-void vdec_if_deinit(struct mtk_vcodec_ctx *ctx)
-{
-       if (!ctx->drv_handle)
-               return;
-
-       mtk_vdec_lock(ctx);
-       mtk_vcodec_dec_clock_on(ctx->dev, ctx->hw_id);
-       ctx->dec_if->deinit(ctx->drv_handle);
-       mtk_vcodec_dec_clock_off(ctx->dev, ctx->hw_id);
-       mtk_vdec_unlock(ctx);
-
-       ctx->drv_handle = NULL;
-}
diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_if.h b/drivers/media/platform/mtk-vcodec/vdec_drv_if.h
deleted file mode 100644 (file)
index d467e8a..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (c) 2016 MediaTek Inc.
- * Author: PC Chen <pc.chen@mediatek.com>
- *                Tiffany Lin <tiffany.lin@mediatek.com>
- */
-
-#ifndef _VDEC_DRV_IF_H_
-#define _VDEC_DRV_IF_H_
-
-#include "mtk_vcodec_drv.h"
-#include "mtk_vcodec_dec.h"
-#include "mtk_vcodec_util.h"
-
-
-/**
- * enum vdec_fb_status  - decoder frame buffer status
- * @FB_ST_NORMAL: initial state
- * @FB_ST_DISPLAY: frame buffer is ready to be displayed
- * @FB_ST_FREE: frame buffer is not used by decoder any more
- */
-enum vdec_fb_status {
-       FB_ST_NORMAL            = 0,
-       FB_ST_DISPLAY           = (1 << 0),
-       FB_ST_FREE              = (1 << 1)
-};
-
-/* For GET_PARAM_DISP_FRAME_BUFFER and GET_PARAM_FREE_FRAME_BUFFER,
- * the caller does not own the returned buffer. The buffer will not be
- *                             released before vdec_if_deinit.
- * GET_PARAM_DISP_FRAME_BUFFER : get next displayable frame buffer,
- *                             struct vdec_fb**
- * GET_PARAM_FREE_FRAME_BUFFER : get non-referenced framebuffer, vdec_fb**
- * GET_PARAM_PIC_INFO          : get picture info, struct vdec_pic_info*
- * GET_PARAM_CROP_INFO         : get crop info, struct v4l2_crop*
- * GET_PARAM_DPB_SIZE          : get dpb size, unsigned int*
- */
-enum vdec_get_param_type {
-       GET_PARAM_DISP_FRAME_BUFFER,
-       GET_PARAM_FREE_FRAME_BUFFER,
-       GET_PARAM_PIC_INFO,
-       GET_PARAM_CROP_INFO,
-       GET_PARAM_DPB_SIZE
-};
-
-/**
- * struct vdec_fb_node  - decoder frame buffer node
- * @list       : list to hold this node
- * @fb : point to frame buffer (vdec_fb), fb could point to frame buffer and
- *     working buffer this is for maintain buffers in different state
- */
-struct vdec_fb_node {
-       struct list_head list;
-       struct vdec_fb *fb;
-};
-
-extern const struct vdec_common_if vdec_h264_if;
-extern const struct vdec_common_if vdec_h264_slice_if;
-extern const struct vdec_common_if vdec_vp8_if;
-extern const struct vdec_common_if vdec_vp9_if;
-
-/**
- * vdec_if_init() - initialize decode driver
- * @ctx        : [in] v4l2 context
- * @fourcc     : [in] video format fourcc, V4L2_PIX_FMT_H264/VP8/VP9..
- */
-int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc);
-
-/**
- * vdec_if_deinit() - deinitialize decode driver
- * @ctx        : [in] v4l2 context
- *
- */
-void vdec_if_deinit(struct mtk_vcodec_ctx *ctx);
-
-/**
- * vdec_if_decode() - trigger decode
- * @ctx        : [in] v4l2 context
- * @bs : [in] input bitstream
- * @fb : [in] frame buffer to store decoded frame, when null means parse
- *     header only
- * @res_chg    : [out] resolution change happens if current bs have different
- *     picture width/height
- * Note: To flush the decoder when reaching EOF, set input bitstream as NULL.
- *
- * Return: 0 on success. -EIO on unrecoverable error.
- */
-int vdec_if_decode(struct mtk_vcodec_ctx *ctx, struct mtk_vcodec_mem *bs,
-                  struct vdec_fb *fb, bool *res_chg);
-
-/**
- * vdec_if_get_param() - get driver's parameter
- * @ctx        : [in] v4l2 context
- * @type       : [in] input parameter type
- * @out        : [out] buffer to store query result
- */
-int vdec_if_get_param(struct mtk_vcodec_ctx *ctx, enum vdec_get_param_type type,
-                     void *out);
-
-#endif
diff --git a/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h b/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h
deleted file mode 100644 (file)
index bf54d6d..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (c) 2016 MediaTek Inc.
- * Author: PC Chen <pc.chen@mediatek.com>
- */
-
-#ifndef _VDEC_IPI_MSG_H_
-#define _VDEC_IPI_MSG_H_
-
-/*
- * enum vdec_ipi_msgid - message id between AP and VPU
- * @AP_IPIMSG_XXX      : AP to VPU cmd message id
- * @VPU_IPIMSG_XXX_ACK : VPU ack AP cmd message id
- */
-enum vdec_ipi_msgid {
-       AP_IPIMSG_DEC_INIT = 0xA000,
-       AP_IPIMSG_DEC_START = 0xA001,
-       AP_IPIMSG_DEC_END = 0xA002,
-       AP_IPIMSG_DEC_DEINIT = 0xA003,
-       AP_IPIMSG_DEC_RESET = 0xA004,
-       AP_IPIMSG_DEC_CORE = 0xA005,
-       AP_IPIMSG_DEC_CORE_END = 0xA006,
-
-       VPU_IPIMSG_DEC_INIT_ACK = 0xB000,
-       VPU_IPIMSG_DEC_START_ACK = 0xB001,
-       VPU_IPIMSG_DEC_END_ACK = 0xB002,
-       VPU_IPIMSG_DEC_DEINIT_ACK = 0xB003,
-       VPU_IPIMSG_DEC_RESET_ACK = 0xB004,
-       VPU_IPIMSG_DEC_CORE_ACK = 0xB005,
-       VPU_IPIMSG_DEC_CORE_END_ACK = 0xB006,
-};
-
-/**
- * struct vdec_ap_ipi_cmd - generic AP to VPU ipi command format
- * @msg_id     : vdec_ipi_msgid
- * @vpu_inst_addr : VPU decoder instance address. Used if ABI version < 2.
- * @inst_id     : instance ID. Used if the ABI version >= 2.
- * @codec_type : codec fourcc
- * @reserved   : reserved param
- */
-struct vdec_ap_ipi_cmd {
-       uint32_t msg_id;
-       union {
-               uint32_t vpu_inst_addr;
-               uint32_t inst_id;
-       };
-       u32 codec_type;
-       u32 reserved;
-};
-
-/**
- * struct vdec_vpu_ipi_ack - generic VPU to AP ipi command format
- * @msg_id     : vdec_ipi_msgid
- * @status     : VPU exeuction result
- * @ap_inst_addr       : AP video decoder instance address
- */
-struct vdec_vpu_ipi_ack {
-       uint32_t msg_id;
-       int32_t status;
-       uint64_t ap_inst_addr;
-};
-
-/**
- * struct vdec_ap_ipi_init - for AP_IPIMSG_DEC_INIT
- * @msg_id     : AP_IPIMSG_DEC_INIT
- * @codec_type : codec fourcc
- * @ap_inst_addr       : AP video decoder instance address
- */
-struct vdec_ap_ipi_init {
-       uint32_t msg_id;
-       u32 codec_type;
-       uint64_t ap_inst_addr;
-};
-
-/**
- * struct vdec_ap_ipi_dec_start - for AP_IPIMSG_DEC_START
- * @msg_id     : AP_IPIMSG_DEC_START
- * @vpu_inst_addr : VPU decoder instance address. Used if ABI version < 2.
- * @inst_id     : instance ID. Used if the ABI version >= 2.
- * @data       : Header info
- *     H264 decoder [0]:buf_sz [1]:nal_start
- *     VP8 decoder  [0]:width/height
- *     VP9 decoder  [0]:profile, [1][2] width/height
- * @codec_type : codec fourcc
- */
-struct vdec_ap_ipi_dec_start {
-       uint32_t msg_id;
-       union {
-               uint32_t vpu_inst_addr;
-               uint32_t inst_id;
-       };
-       uint32_t data[3];
-       u32 codec_type;
-};
-
-/**
- * struct vdec_vpu_ipi_init_ack - for VPU_IPIMSG_DEC_INIT_ACK
- * @msg_id     : VPU_IPIMSG_DEC_INIT_ACK
- * @status     : VPU exeuction result
- * @ap_inst_addr       : AP vcodec_vpu_inst instance address
- * @vpu_inst_addr      : VPU decoder instance address
- * @vdec_abi_version:  ABI version of the firmware. Kernel can use it to
- *                     ensure that it is compatible with the firmware.
- *                     This field is not valid for MT8173 and must not be
- *                     accessed for this chip.
- * @inst_id     : instance ID. Valid only if the ABI version >= 2.
- */
-struct vdec_vpu_ipi_init_ack {
-       uint32_t msg_id;
-       int32_t status;
-       uint64_t ap_inst_addr;
-       uint32_t vpu_inst_addr;
-       uint32_t vdec_abi_version;
-       uint32_t inst_id;
-};
-
-#endif
diff --git a/drivers/media/platform/mtk-vcodec/vdec_msg_queue.c b/drivers/media/platform/mtk-vcodec/vdec_msg_queue.c
deleted file mode 100644 (file)
index 4b062a8..0000000
+++ /dev/null
@@ -1,290 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2021 MediaTek Inc.
- * Author: Yunfei Dong <yunfei.dong@mediatek.com>
- */
-
-#include <linux/freezer.h>
-#include <linux/interrupt.h>
-#include <linux/kthread.h>
-
-#include "mtk_vcodec_dec_pm.h"
-#include "mtk_vcodec_drv.h"
-#include "vdec_msg_queue.h"
-
-#define VDEC_MSG_QUEUE_TIMEOUT_MS 1500
-
-/* the size used to store lat slice header information */
-#define VDEC_LAT_SLICE_HEADER_SZ    (640 * SZ_1K)
-
-/* the size used to store avc error information */
-#define VDEC_ERR_MAP_SZ_AVC         (17 * SZ_1K)
-
-/* core will read the trans buffer which decoded by lat to decode again.
- * The trans buffer size of FHD and 4K bitstreams are different.
- */
-static int vde_msg_queue_get_trans_size(int width, int height)
-{
-       if (width > 1920 || height > 1088)
-               return 30 * SZ_1M;
-       else
-               return 6 * SZ_1M;
-}
-
-void vdec_msg_queue_init_ctx(struct vdec_msg_queue_ctx *ctx, int hardware_index)
-{
-       init_waitqueue_head(&ctx->ready_to_use);
-       INIT_LIST_HEAD(&ctx->ready_queue);
-       spin_lock_init(&ctx->ready_lock);
-       ctx->ready_num = 0;
-       ctx->hardware_index = hardware_index;
-}
-
-static struct list_head *vdec_get_buf_list(int hardware_index, struct vdec_lat_buf *buf)
-{
-       switch (hardware_index) {
-       case MTK_VDEC_CORE:
-               return &buf->core_list;
-       case MTK_VDEC_LAT0:
-               return &buf->lat_list;
-       default:
-               return NULL;
-       }
-}
-
-int vdec_msg_queue_qbuf(struct vdec_msg_queue_ctx *msg_ctx, struct vdec_lat_buf *buf)
-{
-       struct list_head *head;
-
-       head = vdec_get_buf_list(msg_ctx->hardware_index, buf);
-       if (!head) {
-               mtk_v4l2_err("fail to qbuf: %d", msg_ctx->hardware_index);
-               return -EINVAL;
-       }
-
-       spin_lock(&msg_ctx->ready_lock);
-       list_add_tail(head, &msg_ctx->ready_queue);
-       msg_ctx->ready_num++;
-
-       if (msg_ctx->hardware_index != MTK_VDEC_CORE)
-               wake_up_all(&msg_ctx->ready_to_use);
-       else
-               queue_work(buf->ctx->dev->core_workqueue,
-                          &buf->ctx->msg_queue.core_work);
-
-       mtk_v4l2_debug(3, "enqueue buf type: %d addr: 0x%p num: %d",
-                      msg_ctx->hardware_index, buf, msg_ctx->ready_num);
-       spin_unlock(&msg_ctx->ready_lock);
-
-       return 0;
-}
-
-static bool vdec_msg_queue_wait_event(struct vdec_msg_queue_ctx *msg_ctx)
-{
-       int ret;
-
-       ret = wait_event_timeout(msg_ctx->ready_to_use,
-                                !list_empty(&msg_ctx->ready_queue),
-                                msecs_to_jiffies(VDEC_MSG_QUEUE_TIMEOUT_MS));
-       if (!ret)
-               return false;
-
-       return true;
-}
-
-struct vdec_lat_buf *vdec_msg_queue_dqbuf(struct vdec_msg_queue_ctx *msg_ctx)
-{
-       struct vdec_lat_buf *buf;
-       struct list_head *head;
-       int ret;
-
-       spin_lock(&msg_ctx->ready_lock);
-       if (list_empty(&msg_ctx->ready_queue)) {
-               mtk_v4l2_debug(3, "queue is NULL, type:%d num: %d",
-                              msg_ctx->hardware_index, msg_ctx->ready_num);
-               spin_unlock(&msg_ctx->ready_lock);
-
-               if (msg_ctx->hardware_index == MTK_VDEC_CORE)
-                       return NULL;
-
-               ret = vdec_msg_queue_wait_event(msg_ctx);
-               if (!ret)
-                       return NULL;
-               spin_lock(&msg_ctx->ready_lock);
-       }
-
-       if (msg_ctx->hardware_index == MTK_VDEC_CORE)
-               buf = list_first_entry(&msg_ctx->ready_queue,
-                                      struct vdec_lat_buf, core_list);
-       else
-               buf = list_first_entry(&msg_ctx->ready_queue,
-                                      struct vdec_lat_buf, lat_list);
-
-       head = vdec_get_buf_list(msg_ctx->hardware_index, buf);
-       if (!head) {
-               spin_unlock(&msg_ctx->ready_lock);
-               mtk_v4l2_err("fail to dqbuf: %d", msg_ctx->hardware_index);
-               return NULL;
-       }
-       list_del(head);
-
-       msg_ctx->ready_num--;
-       mtk_v4l2_debug(3, "dqueue buf type:%d addr: 0x%p num: %d",
-                      msg_ctx->hardware_index, buf, msg_ctx->ready_num);
-       spin_unlock(&msg_ctx->ready_lock);
-
-       return buf;
-}
-
-void vdec_msg_queue_update_ube_rptr(struct vdec_msg_queue *msg_queue, uint64_t ube_rptr)
-{
-       spin_lock(&msg_queue->lat_ctx.ready_lock);
-       msg_queue->wdma_rptr_addr = ube_rptr;
-       mtk_v4l2_debug(3, "update ube rprt (0x%llx)", ube_rptr);
-       spin_unlock(&msg_queue->lat_ctx.ready_lock);
-}
-
-void vdec_msg_queue_update_ube_wptr(struct vdec_msg_queue *msg_queue, uint64_t ube_wptr)
-{
-       spin_lock(&msg_queue->lat_ctx.ready_lock);
-       msg_queue->wdma_wptr_addr = ube_wptr;
-       mtk_v4l2_debug(3, "update ube wprt: (0x%llx 0x%llx) offset: 0x%llx",
-                      msg_queue->wdma_rptr_addr, msg_queue->wdma_wptr_addr,
-                      ube_wptr);
-       spin_unlock(&msg_queue->lat_ctx.ready_lock);
-}
-
-bool vdec_msg_queue_wait_lat_buf_full(struct vdec_msg_queue *msg_queue)
-{
-       long timeout_jiff;
-       int ret;
-
-       timeout_jiff = msecs_to_jiffies(1000 * (NUM_BUFFER_COUNT + 2));
-       ret = wait_event_timeout(msg_queue->lat_ctx.ready_to_use,
-                                msg_queue->lat_ctx.ready_num == NUM_BUFFER_COUNT,
-                                timeout_jiff);
-       if (ret) {
-               mtk_v4l2_debug(3, "success to get lat buf: %d",
-                              msg_queue->lat_ctx.ready_num);
-               return true;
-       }
-       mtk_v4l2_err("failed with lat buf isn't full: %d",
-                    msg_queue->lat_ctx.ready_num);
-       return false;
-}
-
-void vdec_msg_queue_deinit(struct vdec_msg_queue *msg_queue,
-                          struct mtk_vcodec_ctx *ctx)
-{
-       struct vdec_lat_buf *lat_buf;
-       struct mtk_vcodec_mem *mem;
-       int i;
-
-       mem = &msg_queue->wdma_addr;
-       if (mem->va)
-               mtk_vcodec_mem_free(ctx, mem);
-       for (i = 0; i < NUM_BUFFER_COUNT; i++) {
-               lat_buf = &msg_queue->lat_buf[i];
-
-               mem = &lat_buf->wdma_err_addr;
-               if (mem->va)
-                       mtk_vcodec_mem_free(ctx, mem);
-
-               mem = &lat_buf->slice_bc_addr;
-               if (mem->va)
-                       mtk_vcodec_mem_free(ctx, mem);
-
-               kfree(lat_buf->private_data);
-       }
-}
-
-static void vdec_msg_queue_core_work(struct work_struct *work)
-{
-       struct vdec_msg_queue *msg_queue =
-               container_of(work, struct vdec_msg_queue, core_work);
-       struct mtk_vcodec_ctx *ctx =
-               container_of(msg_queue, struct mtk_vcodec_ctx, msg_queue);
-       struct mtk_vcodec_dev *dev = ctx->dev;
-       struct vdec_lat_buf *lat_buf;
-
-       lat_buf = vdec_msg_queue_dqbuf(&dev->msg_queue_core_ctx);
-       if (!lat_buf)
-               return;
-
-       ctx = lat_buf->ctx;
-       mtk_vcodec_set_curr_ctx(dev, ctx, MTK_VDEC_CORE);
-
-       lat_buf->core_decode(lat_buf);
-
-       mtk_vcodec_set_curr_ctx(dev, NULL, MTK_VDEC_CORE);
-       vdec_msg_queue_qbuf(&ctx->msg_queue.lat_ctx, lat_buf);
-
-       if (!list_empty(&ctx->msg_queue.lat_ctx.ready_queue)) {
-               mtk_v4l2_debug(3, "re-schedule to decode for core: %d",
-                              dev->msg_queue_core_ctx.ready_num);
-               queue_work(dev->core_workqueue, &msg_queue->core_work);
-       }
-}
-
-int vdec_msg_queue_init(struct vdec_msg_queue *msg_queue,
-                       struct mtk_vcodec_ctx *ctx, core_decode_cb_t core_decode,
-                       int private_size)
-{
-       struct vdec_lat_buf *lat_buf;
-       int i, err;
-
-       /* already init msg queue */
-       if (msg_queue->wdma_addr.size)
-               return 0;
-
-       vdec_msg_queue_init_ctx(&msg_queue->lat_ctx, MTK_VDEC_LAT0);
-       INIT_WORK(&msg_queue->core_work, vdec_msg_queue_core_work);
-       msg_queue->wdma_addr.size =
-               vde_msg_queue_get_trans_size(ctx->picinfo.buf_w,
-                                            ctx->picinfo.buf_h);
-
-       err = mtk_vcodec_mem_alloc(ctx, &msg_queue->wdma_addr);
-       if (err) {
-               mtk_v4l2_err("failed to allocate wdma_addr buf");
-               return -ENOMEM;
-       }
-       msg_queue->wdma_rptr_addr = msg_queue->wdma_addr.dma_addr;
-       msg_queue->wdma_wptr_addr = msg_queue->wdma_addr.dma_addr;
-
-       for (i = 0; i < NUM_BUFFER_COUNT; i++) {
-               lat_buf = &msg_queue->lat_buf[i];
-
-               lat_buf->wdma_err_addr.size = VDEC_ERR_MAP_SZ_AVC;
-               err = mtk_vcodec_mem_alloc(ctx, &lat_buf->wdma_err_addr);
-               if (err) {
-                       mtk_v4l2_err("failed to allocate wdma_err_addr buf[%d]", i);
-                       goto mem_alloc_err;
-               }
-
-               lat_buf->slice_bc_addr.size = VDEC_LAT_SLICE_HEADER_SZ;
-               err = mtk_vcodec_mem_alloc(ctx, &lat_buf->slice_bc_addr);
-               if (err) {
-                       mtk_v4l2_err("failed to allocate wdma_addr buf[%d]", i);
-                       goto mem_alloc_err;
-               }
-
-               lat_buf->private_data = kzalloc(private_size, GFP_KERNEL);
-               if (!lat_buf->private_data) {
-                       err = -ENOMEM;
-                       goto mem_alloc_err;
-               }
-
-               lat_buf->ctx = ctx;
-               lat_buf->core_decode = core_decode;
-               err = vdec_msg_queue_qbuf(&msg_queue->lat_ctx, lat_buf);
-               if (err) {
-                       mtk_v4l2_err("failed to qbuf buf[%d]", i);
-                       goto mem_alloc_err;
-               }
-       }
-       return 0;
-
-mem_alloc_err:
-       vdec_msg_queue_deinit(msg_queue, ctx);
-       return err;
-}
diff --git a/drivers/media/platform/mtk-vcodec/vdec_msg_queue.h b/drivers/media/platform/mtk-vcodec/vdec_msg_queue.h
deleted file mode 100644 (file)
index b6ba66d..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (c) 2021 MediaTek Inc.
- * Author: Yunfei Dong <yunfei.dong@mediatek.com>
- */
-
-#ifndef _VDEC_MSG_QUEUE_H_
-#define _VDEC_MSG_QUEUE_H_
-
-#include <linux/sched.h>
-#include <linux/semaphore.h>
-#include <linux/slab.h>
-#include <media/videobuf2-v4l2.h>
-
-#include "mtk_vcodec_util.h"
-
-#define NUM_BUFFER_COUNT 3
-
-struct vdec_lat_buf;
-struct mtk_vcodec_ctx;
-struct mtk_vcodec_dev;
-typedef int (*core_decode_cb_t)(struct vdec_lat_buf *lat_buf);
-
-/**
- * struct vdec_msg_queue_ctx - represents a queue for buffers ready to be processed
- * @ready_to_use: ready used queue used to signalize when get a job queue
- * @ready_queue: list of ready lat buffer queues
- * @ready_lock: spin lock to protect the lat buffer usage
- * @ready_num: number of buffers ready to be processed
- * @hardware_index: hardware id that this queue is used for
- */
-struct vdec_msg_queue_ctx {
-       wait_queue_head_t ready_to_use;
-       struct list_head ready_queue;
-       /* protect lat buffer */
-       spinlock_t ready_lock;
-       int ready_num;
-       int hardware_index;
-};
-
-/**
- * struct vdec_lat_buf - lat buffer message used to store lat info for core decode
- * @wdma_err_addr: wdma error address used for lat hardware
- * @slice_bc_addr: slice bc address used for lat hardware
- * @ts_info: need to set timestamp from output to capture
- *
- * @private_data: shared information used to lat and core hardware
- * @ctx: mtk vcodec context information
- * @core_decode: different codec use different decode callback function
- * @lat_list: add lat buffer to lat head list
- * @core_list: add lat buffer to core head list
- */
-struct vdec_lat_buf {
-       struct mtk_vcodec_mem wdma_err_addr;
-       struct mtk_vcodec_mem slice_bc_addr;
-       struct vb2_v4l2_buffer ts_info;
-
-       void *private_data;
-       struct mtk_vcodec_ctx *ctx;
-       core_decode_cb_t core_decode;
-       struct list_head lat_list;
-       struct list_head core_list;
-};
-
-/**
- * struct vdec_msg_queue - used to store lat buffer message
- * @lat_buf: lat buffer used to store lat buffer information
- * @wdma_addr: wdma address used for ube
- * @wdma_rptr_addr: ube read point
- * @wdma_wptr_addr: ube write point
- * @core_work: core hardware work
- * @lat_ctx: used to store lat buffer list
- */
-struct vdec_msg_queue {
-       struct vdec_lat_buf lat_buf[NUM_BUFFER_COUNT];
-
-       struct mtk_vcodec_mem wdma_addr;
-       u64 wdma_rptr_addr;
-       u64 wdma_wptr_addr;
-
-       struct work_struct core_work;
-       struct vdec_msg_queue_ctx lat_ctx;
-};
-
-/**
- * vdec_msg_queue_init - init lat buffer information.
- * @msg_queue: used to store the lat buffer information
- * @ctx: v4l2 ctx
- * @core_decode: core decode callback for each codec
- * @private_size: the private data size used to share with core
- *
- * Return: returns 0 if init successfully, or fail.
- */
-int vdec_msg_queue_init(struct vdec_msg_queue *msg_queue,
-                       struct mtk_vcodec_ctx *ctx, core_decode_cb_t core_decode,
-                       int private_size);
-
-/**
- * vdec_msg_queue_init_ctx - used to init msg queue context information.
- * @ctx: message queue context
- * @hardware_index: hardware index
- */
-void vdec_msg_queue_init_ctx(struct vdec_msg_queue_ctx *ctx, int hardware_index);
-
-/**
- * vdec_msg_queue_qbuf - enqueue lat buffer to queue list.
- * @ctx: message queue context
- * @buf: current lat buffer
- *
- * Return: returns 0 if qbuf successfully, or fail.
- */
-int vdec_msg_queue_qbuf(struct vdec_msg_queue_ctx *ctx, struct vdec_lat_buf *buf);
-
-/**
- * vdec_msg_queue_dqbuf - dequeue lat buffer from queue list.
- * @ctx: message queue context
- *
- * Return: returns not null if dq successfully, or fail.
- */
-struct vdec_lat_buf *vdec_msg_queue_dqbuf(struct vdec_msg_queue_ctx *ctx);
-
-/**
- * vdec_msg_queue_update_ube_rptr - used to updata the ube read point.
- * @msg_queue: used to store the lat buffer information
- * @ube_rptr: current ube read point
- */
-void vdec_msg_queue_update_ube_rptr(struct vdec_msg_queue *msg_queue, uint64_t ube_rptr);
-
-/**
- * vdec_msg_queue_update_ube_wptr - used to updata the ube write point.
- * @msg_queue: used to store the lat buffer information
- * @ube_wptr: current ube write point
- */
-void vdec_msg_queue_update_ube_wptr(struct vdec_msg_queue *msg_queue, uint64_t ube_wptr);
-
-/**
- * vdec_msg_queue_wait_lat_buf_full - used to check whether all lat buffer
- *                                    in lat list.
- * @msg_queue: used to store the lat buffer information
- *
- * Return: returns true if successfully, or fail.
- */
-bool vdec_msg_queue_wait_lat_buf_full(struct vdec_msg_queue *msg_queue);
-
-/**
- * vdec_msg_queue_deinit - deinit lat buffer information.
- * @msg_queue: used to store the lat buffer information
- * @ctx: v4l2 ctx
- */
-void vdec_msg_queue_deinit(struct vdec_msg_queue *msg_queue,
-                          struct mtk_vcodec_ctx *ctx);
-
-#endif
diff --git a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c
deleted file mode 100644 (file)
index dd35d2c..0000000
+++ /dev/null
@@ -1,243 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2016 MediaTek Inc.
- * Author: PC Chen <pc.chen@mediatek.com>
- */
-
-#include "mtk_vcodec_drv.h"
-#include "mtk_vcodec_util.h"
-#include "vdec_ipi_msg.h"
-#include "vdec_vpu_if.h"
-#include "mtk_vcodec_fw.h"
-
-static void handle_init_ack_msg(const struct vdec_vpu_ipi_init_ack *msg)
-{
-       struct vdec_vpu_inst *vpu = (struct vdec_vpu_inst *)
-                                       (unsigned long)msg->ap_inst_addr;
-
-       mtk_vcodec_debug(vpu, "+ ap_inst_addr = 0x%llx", msg->ap_inst_addr);
-
-       /* mapping VPU address to kernel virtual address */
-       /* the content in vsi is initialized to 0 in VPU */
-       vpu->vsi = mtk_vcodec_fw_map_dm_addr(vpu->ctx->dev->fw_handler,
-                                            msg->vpu_inst_addr);
-       vpu->inst_addr = msg->vpu_inst_addr;
-
-       mtk_vcodec_debug(vpu, "- vpu_inst_addr = 0x%x", vpu->inst_addr);
-
-       /* Set default ABI version if dealing with unversioned firmware. */
-       vpu->fw_abi_version = 0;
-       /*
-        * Instance ID is only used if ABI version >= 2. Initialize it with
-        * garbage by default.
-        */
-       vpu->inst_id = 0xdeadbeef;
-
-       /* Firmware version field does not exist on MT8173. */
-       if (vpu->ctx->dev->vdec_pdata->chip == MTK_MT8173)
-               return;
-
-       /* Check firmware version. */
-       vpu->fw_abi_version = msg->vdec_abi_version;
-       mtk_vcodec_debug(vpu, "firmware version 0x%x\n", vpu->fw_abi_version);
-       switch (vpu->fw_abi_version) {
-       case 1:
-               break;
-       case 2:
-               vpu->inst_id = msg->inst_id;
-               break;
-       default:
-               mtk_vcodec_err(vpu, "unhandled firmware version 0x%x\n",
-                              vpu->fw_abi_version);
-               vpu->failure = 1;
-               break;
-       }
-}
-
-/*
- * vpu_dec_ipi_handler - Handler for VPU ipi message.
- *
- * @data: ipi message
- * @len : length of ipi message
- * @priv: callback private data which is passed by decoder when register.
- *
- * This function runs in interrupt context and it means there's an IPI MSG
- * from VPU.
- */
-static void vpu_dec_ipi_handler(void *data, unsigned int len, void *priv)
-{
-       const struct vdec_vpu_ipi_ack *msg = data;
-       struct vdec_vpu_inst *vpu = (struct vdec_vpu_inst *)
-                                       (unsigned long)msg->ap_inst_addr;
-
-       mtk_vcodec_debug(vpu, "+ id=%X", msg->msg_id);
-
-       vpu->failure = msg->status;
-       vpu->signaled = 1;
-
-       if (msg->status == 0) {
-               switch (msg->msg_id) {
-               case VPU_IPIMSG_DEC_INIT_ACK:
-                       handle_init_ack_msg(data);
-                       break;
-
-               case VPU_IPIMSG_DEC_START_ACK:
-               case VPU_IPIMSG_DEC_END_ACK:
-               case VPU_IPIMSG_DEC_DEINIT_ACK:
-               case VPU_IPIMSG_DEC_RESET_ACK:
-               case VPU_IPIMSG_DEC_CORE_ACK:
-               case VPU_IPIMSG_DEC_CORE_END_ACK:
-                       break;
-
-               default:
-                       mtk_vcodec_err(vpu, "invalid msg=%X", msg->msg_id);
-                       break;
-               }
-       }
-
-       mtk_vcodec_debug(vpu, "- id=%X", msg->msg_id);
-}
-
-static int vcodec_vpu_send_msg(struct vdec_vpu_inst *vpu, void *msg, int len)
-{
-       int err, id, msgid;
-
-       msgid = *(uint32_t *)msg;
-       mtk_vcodec_debug(vpu, "id=%X", msgid);
-
-       vpu->failure = 0;
-       vpu->signaled = 0;
-
-       if (vpu->ctx->dev->vdec_pdata->hw_arch == MTK_VDEC_LAT_SINGLE_CORE) {
-               if (msgid == AP_IPIMSG_DEC_CORE ||
-                   msgid == AP_IPIMSG_DEC_CORE_END)
-                       id = vpu->core_id;
-               else
-                       id = vpu->id;
-       } else {
-               id = vpu->id;
-       }
-
-       err = mtk_vcodec_fw_ipi_send(vpu->ctx->dev->fw_handler, id, msg,
-                                    len, 2000);
-       if (err) {
-               mtk_vcodec_err(vpu, "send fail vpu_id=%d msg_id=%X status=%d",
-                              id, msgid, err);
-               return err;
-       }
-
-       return vpu->failure;
-}
-
-static int vcodec_send_ap_ipi(struct vdec_vpu_inst *vpu, unsigned int msg_id)
-{
-       struct vdec_ap_ipi_cmd msg;
-       int err = 0;
-
-       mtk_vcodec_debug(vpu, "+ id=%X", msg_id);
-
-       memset(&msg, 0, sizeof(msg));
-       msg.msg_id = msg_id;
-       if (vpu->fw_abi_version < 2)
-               msg.vpu_inst_addr = vpu->inst_addr;
-       else
-               msg.inst_id = vpu->inst_id;
-       msg.codec_type = vpu->codec_type;
-
-       err = vcodec_vpu_send_msg(vpu, &msg, sizeof(msg));
-       mtk_vcodec_debug(vpu, "- id=%X ret=%d", msg_id, err);
-       return err;
-}
-
-int vpu_dec_init(struct vdec_vpu_inst *vpu)
-{
-       struct vdec_ap_ipi_init msg;
-       int err;
-
-       mtk_vcodec_debug_enter(vpu);
-
-       init_waitqueue_head(&vpu->wq);
-       vpu->handler = vpu_dec_ipi_handler;
-
-       err = mtk_vcodec_fw_ipi_register(vpu->ctx->dev->fw_handler, vpu->id,
-                                        vpu->handler, "vdec", NULL);
-       if (err) {
-               mtk_vcodec_err(vpu, "vpu_ipi_register fail status=%d", err);
-               return err;
-       }
-
-       if (vpu->ctx->dev->vdec_pdata->hw_arch == MTK_VDEC_LAT_SINGLE_CORE) {
-               err = mtk_vcodec_fw_ipi_register(vpu->ctx->dev->fw_handler,
-                                                vpu->core_id, vpu->handler,
-                                                "vdec", NULL);
-               if (err) {
-                       mtk_vcodec_err(vpu, "vpu_ipi_register core fail status=%d", err);
-                       return err;
-               }
-       }
-
-       memset(&msg, 0, sizeof(msg));
-       msg.msg_id = AP_IPIMSG_DEC_INIT;
-       msg.ap_inst_addr = (unsigned long)vpu;
-       msg.codec_type = vpu->codec_type;
-
-       mtk_vcodec_debug(vpu, "vdec_inst=%p", vpu);
-
-       err = vcodec_vpu_send_msg(vpu, (void *)&msg, sizeof(msg));
-       mtk_vcodec_debug(vpu, "- ret=%d", err);
-       return err;
-}
-
-int vpu_dec_start(struct vdec_vpu_inst *vpu, uint32_t *data, unsigned int len)
-{
-       struct vdec_ap_ipi_dec_start msg;
-       int i;
-       int err = 0;
-
-       mtk_vcodec_debug_enter(vpu);
-
-       if (len > ARRAY_SIZE(msg.data)) {
-               mtk_vcodec_err(vpu, "invalid len = %d\n", len);
-               return -EINVAL;
-       }
-
-       memset(&msg, 0, sizeof(msg));
-       msg.msg_id = AP_IPIMSG_DEC_START;
-       if (vpu->fw_abi_version < 2)
-               msg.vpu_inst_addr = vpu->inst_addr;
-       else
-               msg.inst_id = vpu->inst_id;
-
-       for (i = 0; i < len; i++)
-               msg.data[i] = data[i];
-       msg.codec_type = vpu->codec_type;
-
-       err = vcodec_vpu_send_msg(vpu, (void *)&msg, sizeof(msg));
-       mtk_vcodec_debug(vpu, "- ret=%d", err);
-       return err;
-}
-
-int vpu_dec_core(struct vdec_vpu_inst *vpu)
-{
-       return vcodec_send_ap_ipi(vpu, AP_IPIMSG_DEC_CORE);
-}
-
-int vpu_dec_end(struct vdec_vpu_inst *vpu)
-{
-       return vcodec_send_ap_ipi(vpu, AP_IPIMSG_DEC_END);
-}
-
-int vpu_dec_core_end(struct vdec_vpu_inst *vpu)
-{
-       return vcodec_send_ap_ipi(vpu, AP_IPIMSG_DEC_CORE_END);
-}
-
-int vpu_dec_deinit(struct vdec_vpu_inst *vpu)
-{
-       return vcodec_send_ap_ipi(vpu, AP_IPIMSG_DEC_DEINIT);
-}
-
-int vpu_dec_reset(struct vdec_vpu_inst *vpu)
-{
-       return vcodec_send_ap_ipi(vpu, AP_IPIMSG_DEC_RESET);
-}
diff --git a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h
deleted file mode 100644 (file)
index 4cb3c7f..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (c) 2016 MediaTek Inc.
- * Author: PC Chen <pc.chen@mediatek.com>
- */
-
-#ifndef _VDEC_VPU_IF_H_
-#define _VDEC_VPU_IF_H_
-
-#include "mtk_vcodec_fw.h"
-
-struct mtk_vcodec_ctx;
-
-/**
- * struct vdec_vpu_inst - VPU instance for video codec
- * @id          : ipi msg id for each decoder
- * @core_id     : core id used to separate different hardware
- * @vsi         : driver structure allocated by VPU side and shared to AP side
- *                for control and info share
- * @failure     : VPU execution result status, 0: success, others: fail
- * @inst_addr  : VPU decoder instance address
- * @fw_abi_version : ABI version of the firmware.
- * @inst_id    : if fw_abi_version >= 2, contains the instance ID to be given
- *                in place of inst_addr in messages.
- * @signaled    : 1 - Host has received ack message from VPU, 0 - not received
- * @ctx         : context for v4l2 layer integration
- * @dev                : platform device of VPU
- * @wq          : wait queue to wait VPU message ack
- * @handler     : ipi handler for each decoder
- * @codec_type     : use codec type to separate different codecs
- */
-struct vdec_vpu_inst {
-       int id;
-       int core_id;
-       void *vsi;
-       int32_t failure;
-       uint32_t inst_addr;
-       uint32_t fw_abi_version;
-       uint32_t inst_id;
-       unsigned int signaled;
-       struct mtk_vcodec_ctx *ctx;
-       wait_queue_head_t wq;
-       mtk_vcodec_ipi_handler handler;
-       unsigned int codec_type;
-};
-
-/**
- * vpu_dec_init - init decoder instance and allocate required resource in VPU.
- *
- * @vpu: instance for vdec_vpu_inst
- */
-int vpu_dec_init(struct vdec_vpu_inst *vpu);
-
-/**
- * vpu_dec_start - start decoding, basically the function will be invoked once
- *                 every frame.
- *
- * @vpu : instance for vdec_vpu_inst
- * @data: meta data to pass bitstream info to VPU decoder
- * @len : meta data length
- */
-int vpu_dec_start(struct vdec_vpu_inst *vpu, uint32_t *data, unsigned int len);
-
-/**
- * vpu_dec_end - end decoding, basically the function will be invoked once
- *               when HW decoding done interrupt received successfully. The
- *               decoder in VPU will continue to do reference frame management
- *               and check if there is a new decoded frame available to display.
- *
- * @vpu : instance for vdec_vpu_inst
- */
-int vpu_dec_end(struct vdec_vpu_inst *vpu);
-
-/**
- * vpu_dec_deinit - deinit decoder instance and resource freed in VPU.
- *
- * @vpu: instance for vdec_vpu_inst
- */
-int vpu_dec_deinit(struct vdec_vpu_inst *vpu);
-
-/**
- * vpu_dec_reset - reset decoder, use for flush decoder when end of stream or
- *                 seek. Remainig non displayed frame will be pushed to display.
- *
- * @vpu: instance for vdec_vpu_inst
- */
-int vpu_dec_reset(struct vdec_vpu_inst *vpu);
-
-/**
- * vpu_dec_core - core start decoding, basically the function will be invoked once
- *                 every frame.
- *
- * @vpu : instance for vdec_vpu_inst
- */
-int vpu_dec_core(struct vdec_vpu_inst *vpu);
-
-/**
- * vpu_dec_core_end - core end decoding, basically the function will be invoked once
- *               when core HW decoding done and receive interrupt successfully. The
- *               decoder in VPU will updata hardware information and deinit hardware
- *               and check if there is a new decoded frame available to display.
- *
- * @vpu : instance for vdec_vpu_inst
- */
-int vpu_dec_core_end(struct vdec_vpu_inst *vpu);
-
-#endif
diff --git a/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c b/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c
deleted file mode 100644 (file)
index 4d9b879..0000000
+++ /dev/null
@@ -1,708 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2016 MediaTek Inc.
- * Author: Jungchang Tsao <jungchang.tsao@mediatek.com>
- *         Daniel Hsiao <daniel.hsiao@mediatek.com>
- *         PoChun Lin <pochun.lin@mediatek.com>
- */
-
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-
-#include "../mtk_vcodec_drv.h"
-#include "../mtk_vcodec_util.h"
-#include "../mtk_vcodec_intr.h"
-#include "../mtk_vcodec_enc.h"
-#include "../mtk_vcodec_enc_pm.h"
-#include "../venc_drv_base.h"
-#include "../venc_ipi_msg.h"
-#include "../venc_vpu_if.h"
-
-static const char h264_filler_marker[] = {0x0, 0x0, 0x0, 0x1, 0xc};
-
-#define H264_FILLER_MARKER_SIZE ARRAY_SIZE(h264_filler_marker)
-#define VENC_PIC_BITSTREAM_BYTE_CNT 0x0098
-
-/*
- * enum venc_h264_frame_type - h264 encoder output bitstream frame type
- */
-enum venc_h264_frame_type {
-       VENC_H264_IDR_FRM,
-       VENC_H264_I_FRM,
-       VENC_H264_P_FRM,
-       VENC_H264_B_FRM,
-};
-
-/*
- * enum venc_h264_vpu_work_buf - h264 encoder buffer index
- */
-enum venc_h264_vpu_work_buf {
-       VENC_H264_VPU_WORK_BUF_RC_INFO,
-       VENC_H264_VPU_WORK_BUF_RC_CODE,
-       VENC_H264_VPU_WORK_BUF_REC_LUMA,
-       VENC_H264_VPU_WORK_BUF_REC_CHROMA,
-       VENC_H264_VPU_WORK_BUF_REF_LUMA,
-       VENC_H264_VPU_WORK_BUF_REF_CHROMA,
-       VENC_H264_VPU_WORK_BUF_MV_INFO_1,
-       VENC_H264_VPU_WORK_BUF_MV_INFO_2,
-       VENC_H264_VPU_WORK_BUF_SKIP_FRAME,
-       VENC_H264_VPU_WORK_BUF_MAX,
-};
-
-/*
- * enum venc_h264_bs_mode - for bs_mode argument in h264_enc_vpu_encode
- */
-enum venc_h264_bs_mode {
-       H264_BS_MODE_SPS,
-       H264_BS_MODE_PPS,
-       H264_BS_MODE_FRAME,
-};
-
-/*
- * struct venc_h264_vpu_config - Structure for h264 encoder configuration
- *                               AP-W/R : AP is writer/reader on this item
- *                               VPU-W/R: VPU is write/reader on this item
- * @input_fourcc: input fourcc
- * @bitrate: target bitrate (in bps)
- * @pic_w: picture width. Picture size is visible stream resolution, in pixels,
- *         to be used for display purposes; must be smaller or equal to buffer
- *         size.
- * @pic_h: picture height
- * @buf_w: buffer width. Buffer size is stream resolution in pixels aligned to
- *         hardware requirements.
- * @buf_h: buffer height
- * @gop_size: group of picture size (idr frame)
- * @intra_period: intra frame period
- * @framerate: frame rate in fps
- * @profile: as specified in standard
- * @level: as specified in standard
- * @wfd: WFD mode 1:on, 0:off
- */
-struct venc_h264_vpu_config {
-       u32 input_fourcc;
-       u32 bitrate;
-       u32 pic_w;
-       u32 pic_h;
-       u32 buf_w;
-       u32 buf_h;
-       u32 gop_size;
-       u32 intra_period;
-       u32 framerate;
-       u32 profile;
-       u32 level;
-       u32 wfd;
-};
-
-/*
- * struct venc_h264_vpu_buf - Structure for buffer information
- *                            AP-W/R : AP is writer/reader on this item
- *                            VPU-W/R: VPU is write/reader on this item
- * @iova: IO virtual address
- * @vpua: VPU side memory addr which is used by RC_CODE
- * @size: buffer size (in bytes)
- */
-struct venc_h264_vpu_buf {
-       u32 iova;
-       u32 vpua;
-       u32 size;
-};
-
-/*
- * struct venc_h264_vsi - Structure for VPU driver control and info share
- *                        AP-W/R : AP is writer/reader on this item
- *                        VPU-W/R: VPU is write/reader on this item
- * This structure is allocated in VPU side and shared to AP side.
- * @config: h264 encoder configuration
- * @work_bufs: working buffer information in VPU side
- * The work_bufs here is for storing the 'size' info shared to AP side.
- * The similar item in struct venc_h264_inst is for memory allocation
- * in AP side. The AP driver will copy the 'size' from here to the one in
- * struct mtk_vcodec_mem, then invoke mtk_vcodec_mem_alloc to allocate
- * the buffer. After that, bypass the 'dma_addr' to the 'iova' field here for
- * register setting in VPU side.
- */
-struct venc_h264_vsi {
-       struct venc_h264_vpu_config config;
-       struct venc_h264_vpu_buf work_bufs[VENC_H264_VPU_WORK_BUF_MAX];
-};
-
-/*
- * struct venc_h264_inst - h264 encoder AP driver instance
- * @hw_base: h264 encoder hardware register base
- * @work_bufs: working buffer
- * @pps_buf: buffer to store the pps bitstream
- * @work_buf_allocated: working buffer allocated flag
- * @frm_cnt: encoded frame count
- * @prepend_hdr: when the v4l2 layer send VENC_SET_PARAM_PREPEND_HEADER cmd
- *  through h264_enc_set_param interface, it will set this flag and prepend the
- *  sps/pps in h264_enc_encode function.
- * @vpu_inst: VPU instance to exchange information between AP and VPU
- * @vsi: driver structure allocated by VPU side and shared to AP side for
- *      control and info share
- * @ctx: context for v4l2 layer integration
- */
-struct venc_h264_inst {
-       void __iomem *hw_base;
-       struct mtk_vcodec_mem work_bufs[VENC_H264_VPU_WORK_BUF_MAX];
-       struct mtk_vcodec_mem pps_buf;
-       bool work_buf_allocated;
-       unsigned int frm_cnt;
-       unsigned int skip_frm_cnt;
-       unsigned int prepend_hdr;
-       struct venc_vpu_inst vpu_inst;
-       struct venc_h264_vsi *vsi;
-       struct mtk_vcodec_ctx *ctx;
-};
-
-static inline u32 h264_read_reg(struct venc_h264_inst *inst, u32 addr)
-{
-       return readl(inst->hw_base + addr);
-}
-
-static unsigned int h264_get_profile(struct venc_h264_inst *inst,
-                                    unsigned int profile)
-{
-       switch (profile) {
-       case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
-               return 66;
-       case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
-               return 77;
-       case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
-               return 100;
-       case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
-               mtk_vcodec_err(inst, "unsupported CONSTRAINED_BASELINE");
-               return 0;
-       case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED:
-               mtk_vcodec_err(inst, "unsupported EXTENDED");
-               return 0;
-       default:
-               mtk_vcodec_debug(inst, "unsupported profile %d", profile);
-               return 100;
-       }
-}
-
-static unsigned int h264_get_level(struct venc_h264_inst *inst,
-                                  unsigned int level)
-{
-       switch (level) {
-       case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
-               mtk_vcodec_err(inst, "unsupported 1B");
-               return 0;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
-               return 10;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
-               return 11;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
-               return 12;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
-               return 13;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
-               return 20;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
-               return 21;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
-               return 22;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
-               return 30;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
-               return 31;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
-               return 32;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
-               return 40;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_4_1:
-               return 41;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
-               return 42;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
-               return 50;
-       case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
-               return 51;
-       default:
-               mtk_vcodec_debug(inst, "unsupported level %d", level);
-               return 31;
-       }
-}
-
-static void h264_enc_free_work_buf(struct venc_h264_inst *inst)
-{
-       int i;
-
-       mtk_vcodec_debug_enter(inst);
-
-       /* Except the SKIP_FRAME buffers,
-        * other buffers need to be freed by AP.
-        */
-       for (i = 0; i < VENC_H264_VPU_WORK_BUF_MAX; i++) {
-               if (i != VENC_H264_VPU_WORK_BUF_SKIP_FRAME)
-                       mtk_vcodec_mem_free(inst->ctx, &inst->work_bufs[i]);
-       }
-
-       mtk_vcodec_mem_free(inst->ctx, &inst->pps_buf);
-
-       mtk_vcodec_debug_leave(inst);
-}
-
-static int h264_enc_alloc_work_buf(struct venc_h264_inst *inst)
-{
-       int i;
-       int ret = 0;
-       struct venc_h264_vpu_buf *wb = inst->vsi->work_bufs;
-
-       mtk_vcodec_debug_enter(inst);
-
-       for (i = 0; i < VENC_H264_VPU_WORK_BUF_MAX; i++) {
-               /*
-                * This 'wb' structure is set by VPU side and shared to AP for
-                * buffer allocation and IO virtual addr mapping. For most of
-                * the buffers, AP will allocate the buffer according to 'size'
-                * field and store the IO virtual addr in 'iova' field. There
-                * are two exceptions:
-                * (1) RC_CODE buffer, it's pre-allocated in the VPU side, and
-                * save the VPU addr in the 'vpua' field. The AP will translate
-                * the VPU addr to the corresponding IO virtual addr and store
-                * in 'iova' field for reg setting in VPU side.
-                * (2) SKIP_FRAME buffer, it's pre-allocated in the VPU side,
-                * and save the VPU addr in the 'vpua' field. The AP will
-                * translate the VPU addr to the corresponding AP side virtual
-                * address and do some memcpy access to move to bitstream buffer
-                * assigned by v4l2 layer.
-                */
-               inst->work_bufs[i].size = wb[i].size;
-               if (i == VENC_H264_VPU_WORK_BUF_SKIP_FRAME) {
-                       struct mtk_vcodec_fw *handler;
-
-                       handler = inst->vpu_inst.ctx->dev->fw_handler;
-                       inst->work_bufs[i].va =
-                               mtk_vcodec_fw_map_dm_addr(handler, wb[i].vpua);
-                       inst->work_bufs[i].dma_addr = 0;
-               } else {
-                       ret = mtk_vcodec_mem_alloc(inst->ctx,
-                                                  &inst->work_bufs[i]);
-                       if (ret) {
-                               mtk_vcodec_err(inst,
-                                              "cannot allocate buf %d", i);
-                               goto err_alloc;
-                       }
-                       /*
-                        * This RC_CODE is pre-allocated by VPU and saved in VPU
-                        * addr. So we need use memcpy to copy RC_CODE from VPU
-                        * addr into IO virtual addr in 'iova' field for reg
-                        * setting in VPU side.
-                        */
-                       if (i == VENC_H264_VPU_WORK_BUF_RC_CODE) {
-                               struct mtk_vcodec_fw *handler;
-                               void *tmp_va;
-
-                               handler = inst->vpu_inst.ctx->dev->fw_handler;
-                               tmp_va = mtk_vcodec_fw_map_dm_addr(handler,
-                                                                  wb[i].vpua);
-                               memcpy(inst->work_bufs[i].va, tmp_va,
-                                      wb[i].size);
-                       }
-               }
-               wb[i].iova = inst->work_bufs[i].dma_addr;
-
-               mtk_vcodec_debug(inst,
-                                "work_buf[%d] va=0x%p iova=%pad size=%zu",
-                                i, inst->work_bufs[i].va,
-                                &inst->work_bufs[i].dma_addr,
-                                inst->work_bufs[i].size);
-       }
-
-       /* the pps_buf is used by AP side only */
-       inst->pps_buf.size = 128;
-       ret = mtk_vcodec_mem_alloc(inst->ctx, &inst->pps_buf);
-       if (ret) {
-               mtk_vcodec_err(inst, "cannot allocate pps_buf");
-               goto err_alloc;
-       }
-
-       mtk_vcodec_debug_leave(inst);
-
-       return ret;
-
-err_alloc:
-       h264_enc_free_work_buf(inst);
-
-       return ret;
-}
-
-static unsigned int h264_enc_wait_venc_done(struct venc_h264_inst *inst)
-{
-       unsigned int irq_status = 0;
-       struct mtk_vcodec_ctx *ctx = (struct mtk_vcodec_ctx *)inst->ctx;
-
-       if (!mtk_vcodec_wait_for_done_ctx(ctx, MTK_INST_IRQ_RECEIVED,
-                                         WAIT_INTR_TIMEOUT_MS, 0)) {
-               irq_status = ctx->irq_status;
-               mtk_vcodec_debug(inst, "irq_status %x <-", irq_status);
-       }
-       return irq_status;
-}
-
-static int h264_frame_type(struct venc_h264_inst *inst)
-{
-       if ((inst->vsi->config.gop_size != 0 &&
-            (inst->frm_cnt % inst->vsi->config.gop_size) == 0) ||
-           (inst->frm_cnt == 0 && inst->vsi->config.gop_size == 0)) {
-               /* IDR frame */
-               return VENC_H264_IDR_FRM;
-       } else if ((inst->vsi->config.intra_period != 0 &&
-                   (inst->frm_cnt % inst->vsi->config.intra_period) == 0) ||
-                  (inst->frm_cnt == 0 && inst->vsi->config.intra_period == 0)) {
-               /* I frame */
-               return VENC_H264_I_FRM;
-       } else {
-               return VENC_H264_P_FRM;  /* Note: B frames are not supported */
-       }
-}
-static int h264_encode_sps(struct venc_h264_inst *inst,
-                          struct mtk_vcodec_mem *bs_buf,
-                          unsigned int *bs_size)
-{
-       int ret = 0;
-       unsigned int irq_status;
-
-       mtk_vcodec_debug_enter(inst);
-
-       ret = vpu_enc_encode(&inst->vpu_inst, H264_BS_MODE_SPS, NULL, bs_buf, NULL);
-       if (ret)
-               return ret;
-
-       irq_status = h264_enc_wait_venc_done(inst);
-       if (irq_status != MTK_VENC_IRQ_STATUS_SPS) {
-               mtk_vcodec_err(inst, "expect irq status %d",
-                              MTK_VENC_IRQ_STATUS_SPS);
-               return -EINVAL;
-       }
-
-       *bs_size = h264_read_reg(inst, VENC_PIC_BITSTREAM_BYTE_CNT);
-       mtk_vcodec_debug(inst, "bs size %d <-", *bs_size);
-
-       return ret;
-}
-
-static int h264_encode_pps(struct venc_h264_inst *inst,
-                          struct mtk_vcodec_mem *bs_buf,
-                          unsigned int *bs_size)
-{
-       int ret = 0;
-       unsigned int irq_status;
-
-       mtk_vcodec_debug_enter(inst);
-
-       ret = vpu_enc_encode(&inst->vpu_inst, H264_BS_MODE_PPS, NULL, bs_buf, NULL);
-       if (ret)
-               return ret;
-
-       irq_status = h264_enc_wait_venc_done(inst);
-       if (irq_status != MTK_VENC_IRQ_STATUS_PPS) {
-               mtk_vcodec_err(inst, "expect irq status %d",
-                              MTK_VENC_IRQ_STATUS_PPS);
-               return -EINVAL;
-       }
-
-       *bs_size = h264_read_reg(inst, VENC_PIC_BITSTREAM_BYTE_CNT);
-       mtk_vcodec_debug(inst, "bs size %d <-", *bs_size);
-
-       return ret;
-}
-
-static int h264_encode_header(struct venc_h264_inst *inst,
-                             struct mtk_vcodec_mem *bs_buf,
-                             unsigned int *bs_size)
-{
-       int ret = 0;
-       unsigned int bs_size_sps;
-       unsigned int bs_size_pps;
-
-       ret = h264_encode_sps(inst, bs_buf, &bs_size_sps);
-       if (ret)
-               return ret;
-
-       ret = h264_encode_pps(inst, &inst->pps_buf, &bs_size_pps);
-       if (ret)
-               return ret;
-
-       memcpy(bs_buf->va + bs_size_sps, inst->pps_buf.va, bs_size_pps);
-       *bs_size = bs_size_sps + bs_size_pps;
-
-       return ret;
-}
-
-static int h264_encode_frame(struct venc_h264_inst *inst,
-                            struct venc_frm_buf *frm_buf,
-                            struct mtk_vcodec_mem *bs_buf,
-                            unsigned int *bs_size)
-{
-       int ret = 0;
-       unsigned int irq_status;
-       struct venc_frame_info frame_info;
-
-       mtk_vcodec_debug_enter(inst);
-       mtk_vcodec_debug(inst, "frm_cnt = %d\n ", inst->frm_cnt);
-       frame_info.frm_count = inst->frm_cnt;
-       frame_info.skip_frm_count = inst->skip_frm_cnt;
-       frame_info.frm_type = h264_frame_type(inst);
-       mtk_vcodec_debug(inst, "frm_count = %d,skip_frm_count =%d,frm_type=%d.\n",
-                        frame_info.frm_count, frame_info.skip_frm_count,
-                        frame_info.frm_type);
-       ret = vpu_enc_encode(&inst->vpu_inst, H264_BS_MODE_FRAME, frm_buf, bs_buf, &frame_info);
-       if (ret)
-               return ret;
-
-       /*
-        * skip frame case: The skip frame buffer is composed by vpu side only,
-        * it does not trigger the hw, so skip the wait interrupt operation.
-        */
-       if (inst->vpu_inst.state == VEN_IPI_MSG_ENC_STATE_SKIP) {
-               *bs_size = inst->vpu_inst.bs_size;
-               memcpy(bs_buf->va,
-                      inst->work_bufs[VENC_H264_VPU_WORK_BUF_SKIP_FRAME].va,
-                      *bs_size);
-               ++inst->frm_cnt;
-               ++inst->skip_frm_cnt;
-               return ret;
-       }
-
-       irq_status = h264_enc_wait_venc_done(inst);
-       if (irq_status != MTK_VENC_IRQ_STATUS_FRM) {
-               mtk_vcodec_err(inst, "irq_status=%d failed", irq_status);
-               return -EIO;
-       }
-
-       *bs_size = h264_read_reg(inst, VENC_PIC_BITSTREAM_BYTE_CNT);
-
-       ++inst->frm_cnt;
-       mtk_vcodec_debug(inst, "frm %d bs_size %d key_frm %d <-",
-                        inst->frm_cnt, *bs_size, inst->vpu_inst.is_key_frm);
-
-       return ret;
-}
-
-static void h264_encode_filler(struct venc_h264_inst *inst, void *buf,
-                              int size)
-{
-       unsigned char *p = buf;
-
-       if (size < H264_FILLER_MARKER_SIZE) {
-               mtk_vcodec_err(inst, "filler size too small %d", size);
-               return;
-       }
-
-       memcpy(p, h264_filler_marker, ARRAY_SIZE(h264_filler_marker));
-       size -= H264_FILLER_MARKER_SIZE;
-       p += H264_FILLER_MARKER_SIZE;
-       memset(p, 0xff, size);
-}
-
-static int h264_enc_init(struct mtk_vcodec_ctx *ctx)
-{
-       const bool is_ext = MTK_ENC_CTX_IS_EXT(ctx);
-       int ret = 0;
-       struct venc_h264_inst *inst;
-
-       inst = kzalloc(sizeof(*inst), GFP_KERNEL);
-       if (!inst)
-               return -ENOMEM;
-
-       inst->ctx = ctx;
-       inst->vpu_inst.ctx = ctx;
-       inst->vpu_inst.id = is_ext ? SCP_IPI_VENC_H264 : IPI_VENC_H264;
-       inst->hw_base = mtk_vcodec_get_reg_addr(inst->ctx, VENC_SYS);
-
-       mtk_vcodec_debug_enter(inst);
-
-       ret = vpu_enc_init(&inst->vpu_inst);
-
-       inst->vsi = (struct venc_h264_vsi *)inst->vpu_inst.vsi;
-
-       mtk_vcodec_debug_leave(inst);
-
-       if (ret)
-               kfree(inst);
-       else
-               ctx->drv_handle = inst;
-
-       return ret;
-}
-
-static int h264_enc_encode(void *handle,
-                          enum venc_start_opt opt,
-                          struct venc_frm_buf *frm_buf,
-                          struct mtk_vcodec_mem *bs_buf,
-                          struct venc_done_result *result)
-{
-       int ret = 0;
-       struct venc_h264_inst *inst = (struct venc_h264_inst *)handle;
-       struct mtk_vcodec_ctx *ctx = inst->ctx;
-
-       mtk_vcodec_debug(inst, "opt %d ->", opt);
-
-       enable_irq(ctx->dev->enc_irq);
-
-       switch (opt) {
-       case VENC_START_OPT_ENCODE_SEQUENCE_HEADER: {
-               unsigned int bs_size_hdr;
-
-               ret = h264_encode_header(inst, bs_buf, &bs_size_hdr);
-               if (ret)
-                       goto encode_err;
-
-               result->bs_size = bs_size_hdr;
-               result->is_key_frm = false;
-               break;
-       }
-
-       case VENC_START_OPT_ENCODE_FRAME: {
-               int hdr_sz;
-               int hdr_sz_ext;
-               int filler_sz = 0;
-               const int bs_alignment = 128;
-               struct mtk_vcodec_mem tmp_bs_buf;
-               unsigned int bs_size_hdr;
-               unsigned int bs_size_frm;
-
-               if (!inst->prepend_hdr) {
-                       ret = h264_encode_frame(inst, frm_buf, bs_buf,
-                                               &result->bs_size);
-                       if (ret)
-                               goto encode_err;
-                       result->is_key_frm = inst->vpu_inst.is_key_frm;
-                       break;
-               }
-
-               mtk_vcodec_debug(inst, "h264_encode_frame prepend SPS/PPS");
-
-               ret = h264_encode_header(inst, bs_buf, &bs_size_hdr);
-               if (ret)
-                       goto encode_err;
-
-               hdr_sz = bs_size_hdr;
-               hdr_sz_ext = (hdr_sz & (bs_alignment - 1));
-               if (hdr_sz_ext) {
-                       filler_sz = bs_alignment - hdr_sz_ext;
-                       if (hdr_sz_ext + H264_FILLER_MARKER_SIZE > bs_alignment)
-                               filler_sz += bs_alignment;
-                       h264_encode_filler(inst, bs_buf->va + hdr_sz,
-                                          filler_sz);
-               }
-
-               tmp_bs_buf.va = bs_buf->va + hdr_sz + filler_sz;
-               tmp_bs_buf.dma_addr = bs_buf->dma_addr + hdr_sz + filler_sz;
-               tmp_bs_buf.size = bs_buf->size - (hdr_sz + filler_sz);
-
-               ret = h264_encode_frame(inst, frm_buf, &tmp_bs_buf,
-                                       &bs_size_frm);
-               if (ret)
-                       goto encode_err;
-
-               result->bs_size = hdr_sz + filler_sz + bs_size_frm;
-
-               mtk_vcodec_debug(inst, "hdr %d filler %d frame %d bs %d",
-                                hdr_sz, filler_sz, bs_size_frm,
-                                result->bs_size);
-
-               inst->prepend_hdr = 0;
-               result->is_key_frm = inst->vpu_inst.is_key_frm;
-               break;
-       }
-
-       default:
-               mtk_vcodec_err(inst, "venc_start_opt %d not supported", opt);
-               ret = -EINVAL;
-               break;
-       }
-
-encode_err:
-
-       disable_irq(ctx->dev->enc_irq);
-       mtk_vcodec_debug(inst, "opt %d <-", opt);
-
-       return ret;
-}
-
-static int h264_enc_set_param(void *handle,
-                             enum venc_set_param_type type,
-                             struct venc_enc_param *enc_prm)
-{
-       int ret = 0;
-       struct venc_h264_inst *inst = (struct venc_h264_inst *)handle;
-
-       mtk_vcodec_debug(inst, "->type=%d", type);
-
-       switch (type) {
-       case VENC_SET_PARAM_ENC:
-               inst->vsi->config.input_fourcc = enc_prm->input_yuv_fmt;
-               inst->vsi->config.bitrate = enc_prm->bitrate;
-               inst->vsi->config.pic_w = enc_prm->width;
-               inst->vsi->config.pic_h = enc_prm->height;
-               inst->vsi->config.buf_w = enc_prm->buf_width;
-               inst->vsi->config.buf_h = enc_prm->buf_height;
-               inst->vsi->config.gop_size = enc_prm->gop_size;
-               inst->vsi->config.framerate = enc_prm->frm_rate;
-               inst->vsi->config.intra_period = enc_prm->intra_period;
-               inst->vsi->config.profile =
-                       h264_get_profile(inst, enc_prm->h264_profile);
-               inst->vsi->config.level =
-                       h264_get_level(inst, enc_prm->h264_level);
-               inst->vsi->config.wfd = 0;
-               ret = vpu_enc_set_param(&inst->vpu_inst, type, enc_prm);
-               if (ret)
-                       break;
-               if (inst->work_buf_allocated) {
-                       h264_enc_free_work_buf(inst);
-                       inst->work_buf_allocated = false;
-               }
-               ret = h264_enc_alloc_work_buf(inst);
-               if (ret)
-                       break;
-               inst->work_buf_allocated = true;
-               break;
-
-       case VENC_SET_PARAM_PREPEND_HEADER:
-               inst->prepend_hdr = 1;
-               mtk_vcodec_debug(inst, "set prepend header mode");
-               break;
-       case VENC_SET_PARAM_FORCE_INTRA:
-       case VENC_SET_PARAM_GOP_SIZE:
-       case VENC_SET_PARAM_INTRA_PERIOD:
-               inst->frm_cnt = 0;
-               inst->skip_frm_cnt = 0;
-               fallthrough;
-       default:
-               ret = vpu_enc_set_param(&inst->vpu_inst, type, enc_prm);
-               break;
-       }
-
-       mtk_vcodec_debug_leave(inst);
-
-       return ret;
-}
-
-static int h264_enc_deinit(void *handle)
-{
-       int ret = 0;
-       struct venc_h264_inst *inst = (struct venc_h264_inst *)handle;
-
-       mtk_vcodec_debug_enter(inst);
-
-       ret = vpu_enc_deinit(&inst->vpu_inst);
-
-       if (inst->work_buf_allocated)
-               h264_enc_free_work_buf(inst);
-
-       mtk_vcodec_debug_leave(inst);
-       kfree(inst);
-
-       return ret;
-}
-
-const struct venc_common_if venc_h264_if = {
-       .init = h264_enc_init,
-       .encode = h264_enc_encode,
-       .set_param = h264_enc_set_param,
-       .deinit = h264_enc_deinit,
-};
diff --git a/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c b/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c
deleted file mode 100644 (file)
index 56ce58f..0000000
+++ /dev/null
@@ -1,468 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2016 MediaTek Inc.
- * Author: Daniel Hsiao <daniel.hsiao@mediatek.com>
- *         PoChun Lin <pochun.lin@mediatek.com>
- */
-
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-
-#include "../mtk_vcodec_drv.h"
-#include "../mtk_vcodec_util.h"
-#include "../mtk_vcodec_intr.h"
-#include "../mtk_vcodec_enc.h"
-#include "../mtk_vcodec_enc_pm.h"
-#include "../venc_drv_base.h"
-#include "../venc_ipi_msg.h"
-#include "../venc_vpu_if.h"
-
-#define VENC_BITSTREAM_FRAME_SIZE 0x0098
-#define VENC_BITSTREAM_HEADER_LEN 0x00e8
-
-/* This ac_tag is vp8 frame tag. */
-#define MAX_AC_TAG_SIZE 10
-
-/*
- * enum venc_vp8_vpu_work_buf - vp8 encoder buffer index
- */
-enum venc_vp8_vpu_work_buf {
-       VENC_VP8_VPU_WORK_BUF_LUMA,
-       VENC_VP8_VPU_WORK_BUF_LUMA2,
-       VENC_VP8_VPU_WORK_BUF_LUMA3,
-       VENC_VP8_VPU_WORK_BUF_CHROMA,
-       VENC_VP8_VPU_WORK_BUF_CHROMA2,
-       VENC_VP8_VPU_WORK_BUF_CHROMA3,
-       VENC_VP8_VPU_WORK_BUF_MV_INFO,
-       VENC_VP8_VPU_WORK_BUF_BS_HEADER,
-       VENC_VP8_VPU_WORK_BUF_PROB_BUF,
-       VENC_VP8_VPU_WORK_BUF_RC_INFO,
-       VENC_VP8_VPU_WORK_BUF_RC_CODE,
-       VENC_VP8_VPU_WORK_BUF_RC_CODE2,
-       VENC_VP8_VPU_WORK_BUF_RC_CODE3,
-       VENC_VP8_VPU_WORK_BUF_MAX,
-};
-
-/*
- * struct venc_vp8_vpu_config - Structure for vp8 encoder configuration
- *                              AP-W/R : AP is writer/reader on this item
- *                              VPU-W/R: VPU is write/reader on this item
- * @input_fourcc: input fourcc
- * @bitrate: target bitrate (in bps)
- * @pic_w: picture width. Picture size is visible stream resolution, in pixels,
- *         to be used for display purposes; must be smaller or equal to buffer
- *         size.
- * @pic_h: picture height
- * @buf_w: buffer width (with 16 alignment). Buffer size is stream resolution
- *         in pixels aligned to hardware requirements.
- * @buf_h: buffer height (with 16 alignment)
- * @gop_size: group of picture size (key frame)
- * @framerate: frame rate in fps
- * @ts_mode: temporal scalability mode (0: disable, 1: enable)
- *          support three temporal layers - 0: 7.5fps 1: 7.5fps 2: 15fps.
- */
-struct venc_vp8_vpu_config {
-       u32 input_fourcc;
-       u32 bitrate;
-       u32 pic_w;
-       u32 pic_h;
-       u32 buf_w;
-       u32 buf_h;
-       u32 gop_size;
-       u32 framerate;
-       u32 ts_mode;
-};
-
-/*
- * struct venc_vp8_vpu_buf - Structure for buffer information
- *                           AP-W/R : AP is writer/reader on this item
- *                           VPU-W/R: VPU is write/reader on this item
- * @iova: IO virtual address
- * @vpua: VPU side memory addr which is used by RC_CODE
- * @size: buffer size (in bytes)
- */
-struct venc_vp8_vpu_buf {
-       u32 iova;
-       u32 vpua;
-       u32 size;
-};
-
-/*
- * struct venc_vp8_vsi - Structure for VPU driver control and info share
- *                       AP-W/R : AP is writer/reader on this item
- *                       VPU-W/R: VPU is write/reader on this item
- * This structure is allocated in VPU side and shared to AP side.
- * @config: vp8 encoder configuration
- * @work_bufs: working buffer information in VPU side
- * The work_bufs here is for storing the 'size' info shared to AP side.
- * The similar item in struct venc_vp8_inst is for memory allocation
- * in AP side. The AP driver will copy the 'size' from here to the one in
- * struct mtk_vcodec_mem, then invoke mtk_vcodec_mem_alloc to allocate
- * the buffer. After that, bypass the 'dma_addr' to the 'iova' field here for
- * register setting in VPU side.
- */
-struct venc_vp8_vsi {
-       struct venc_vp8_vpu_config config;
-       struct venc_vp8_vpu_buf work_bufs[VENC_VP8_VPU_WORK_BUF_MAX];
-};
-
-/*
- * struct venc_vp8_inst - vp8 encoder AP driver instance
- * @hw_base: vp8 encoder hardware register base
- * @work_bufs: working buffer
- * @work_buf_allocated: working buffer allocated flag
- * @frm_cnt: encoded frame count, it's used for I-frame judgement and
- *          reset when force intra cmd received.
- * @ts_mode: temporal scalability mode (0: disable, 1: enable)
- *          support three temporal layers - 0: 7.5fps 1: 7.5fps 2: 15fps.
- * @vpu_inst: VPU instance to exchange information between AP and VPU
- * @vsi: driver structure allocated by VPU side and shared to AP side for
- *      control and info share
- * @ctx: context for v4l2 layer integration
- */
-struct venc_vp8_inst {
-       void __iomem *hw_base;
-       struct mtk_vcodec_mem work_bufs[VENC_VP8_VPU_WORK_BUF_MAX];
-       bool work_buf_allocated;
-       unsigned int frm_cnt;
-       unsigned int ts_mode;
-       struct venc_vpu_inst vpu_inst;
-       struct venc_vp8_vsi *vsi;
-       struct mtk_vcodec_ctx *ctx;
-};
-
-static inline u32 vp8_enc_read_reg(struct venc_vp8_inst *inst, u32 addr)
-{
-       return readl(inst->hw_base + addr);
-}
-
-static void vp8_enc_free_work_buf(struct venc_vp8_inst *inst)
-{
-       int i;
-
-       mtk_vcodec_debug_enter(inst);
-
-       /* Buffers need to be freed by AP. */
-       for (i = 0; i < VENC_VP8_VPU_WORK_BUF_MAX; i++) {
-               if (inst->work_bufs[i].size == 0)
-                       continue;
-               mtk_vcodec_mem_free(inst->ctx, &inst->work_bufs[i]);
-       }
-
-       mtk_vcodec_debug_leave(inst);
-}
-
-static int vp8_enc_alloc_work_buf(struct venc_vp8_inst *inst)
-{
-       int i;
-       int ret = 0;
-       struct venc_vp8_vpu_buf *wb = inst->vsi->work_bufs;
-
-       mtk_vcodec_debug_enter(inst);
-
-       for (i = 0; i < VENC_VP8_VPU_WORK_BUF_MAX; i++) {
-               if (wb[i].size == 0)
-                       continue;
-               /*
-                * This 'wb' structure is set by VPU side and shared to AP for
-                * buffer allocation and IO virtual addr mapping. For most of
-                * the buffers, AP will allocate the buffer according to 'size'
-                * field and store the IO virtual addr in 'iova' field. For the
-                * RC_CODEx buffers, they are pre-allocated in the VPU side
-                * because they are inside VPU SRAM, and save the VPU addr in
-                * the 'vpua' field. The AP will translate the VPU addr to the
-                * corresponding IO virtual addr and store in 'iova' field.
-                */
-               inst->work_bufs[i].size = wb[i].size;
-               ret = mtk_vcodec_mem_alloc(inst->ctx, &inst->work_bufs[i]);
-               if (ret) {
-                       mtk_vcodec_err(inst,
-                                      "cannot alloc work_bufs[%d]", i);
-                       goto err_alloc;
-               }
-               /*
-                * This RC_CODEx is pre-allocated by VPU and saved in VPU addr.
-                * So we need use memcpy to copy RC_CODEx from VPU addr into IO
-                * virtual addr in 'iova' field for reg setting in VPU side.
-                */
-               if (i == VENC_VP8_VPU_WORK_BUF_RC_CODE ||
-                   i == VENC_VP8_VPU_WORK_BUF_RC_CODE2 ||
-                   i == VENC_VP8_VPU_WORK_BUF_RC_CODE3) {
-                       struct mtk_vcodec_fw *handler;
-                       void *tmp_va;
-
-                       handler = inst->vpu_inst.ctx->dev->fw_handler;
-                       tmp_va = mtk_vcodec_fw_map_dm_addr(handler,
-                                                          wb[i].vpua);
-                       memcpy(inst->work_bufs[i].va, tmp_va, wb[i].size);
-               }
-               wb[i].iova = inst->work_bufs[i].dma_addr;
-
-               mtk_vcodec_debug(inst,
-                                "work_bufs[%d] va=0x%p,iova=%pad,size=%zu",
-                                i, inst->work_bufs[i].va,
-                                &inst->work_bufs[i].dma_addr,
-                                inst->work_bufs[i].size);
-       }
-
-       mtk_vcodec_debug_leave(inst);
-
-       return ret;
-
-err_alloc:
-       vp8_enc_free_work_buf(inst);
-
-       return ret;
-}
-
-static unsigned int vp8_enc_wait_venc_done(struct venc_vp8_inst *inst)
-{
-       unsigned int irq_status = 0;
-       struct mtk_vcodec_ctx *ctx = (struct mtk_vcodec_ctx *)inst->ctx;
-
-       if (!mtk_vcodec_wait_for_done_ctx(ctx, MTK_INST_IRQ_RECEIVED,
-                                         WAIT_INTR_TIMEOUT_MS, 0)) {
-               irq_status = ctx->irq_status;
-               mtk_vcodec_debug(inst, "isr return %x", irq_status);
-       }
-       return irq_status;
-}
-
-/*
- * Compose ac_tag, bitstream header and bitstream payload into
- * one bitstream buffer.
- */
-static int vp8_enc_compose_one_frame(struct venc_vp8_inst *inst,
-                                    struct mtk_vcodec_mem *bs_buf,
-                                    unsigned int *bs_size)
-{
-       unsigned int not_key;
-       u32 bs_frm_size;
-       u32 bs_hdr_len;
-       unsigned int ac_tag_size;
-       u8 ac_tag[MAX_AC_TAG_SIZE];
-       u32 tag;
-
-       bs_frm_size = vp8_enc_read_reg(inst, VENC_BITSTREAM_FRAME_SIZE);
-       bs_hdr_len = vp8_enc_read_reg(inst, VENC_BITSTREAM_HEADER_LEN);
-
-       /* if a frame is key frame, not_key is 0 */
-       not_key = !inst->vpu_inst.is_key_frm;
-       tag = (bs_hdr_len << 5) | 0x10 | not_key;
-       ac_tag[0] = tag & 0xff;
-       ac_tag[1] = (tag >> 8) & 0xff;
-       ac_tag[2] = (tag >> 16) & 0xff;
-
-       /* key frame */
-       if (not_key == 0) {
-               ac_tag_size = MAX_AC_TAG_SIZE;
-               ac_tag[3] = 0x9d;
-               ac_tag[4] = 0x01;
-               ac_tag[5] = 0x2a;
-               ac_tag[6] = inst->vsi->config.pic_w;
-               ac_tag[7] = inst->vsi->config.pic_w >> 8;
-               ac_tag[8] = inst->vsi->config.pic_h;
-               ac_tag[9] = inst->vsi->config.pic_h >> 8;
-       } else {
-               ac_tag_size = 3;
-       }
-
-       if (bs_buf->size < bs_hdr_len + bs_frm_size + ac_tag_size) {
-               mtk_vcodec_err(inst, "bitstream buf size is too small(%zu)",
-                              bs_buf->size);
-               return -EINVAL;
-       }
-
-       /*
-       * (1) The vp8 bitstream header and body are generated by the HW vp8
-       * encoder separately at the same time. We cannot know the bitstream
-       * header length in advance.
-       * (2) From the vp8 spec, there is no stuffing byte allowed between the
-       * ac tag, bitstream header and bitstream body.
-       */
-       memmove(bs_buf->va + bs_hdr_len + ac_tag_size,
-               bs_buf->va, bs_frm_size);
-       memcpy(bs_buf->va + ac_tag_size,
-              inst->work_bufs[VENC_VP8_VPU_WORK_BUF_BS_HEADER].va,
-              bs_hdr_len);
-       memcpy(bs_buf->va, ac_tag, ac_tag_size);
-       *bs_size = bs_frm_size + bs_hdr_len + ac_tag_size;
-
-       return 0;
-}
-
-static int vp8_enc_encode_frame(struct venc_vp8_inst *inst,
-                               struct venc_frm_buf *frm_buf,
-                               struct mtk_vcodec_mem *bs_buf,
-                               unsigned int *bs_size)
-{
-       int ret = 0;
-       unsigned int irq_status;
-
-       mtk_vcodec_debug(inst, "->frm_cnt=%d", inst->frm_cnt);
-
-       ret = vpu_enc_encode(&inst->vpu_inst, 0, frm_buf, bs_buf, NULL);
-       if (ret)
-               return ret;
-
-       irq_status = vp8_enc_wait_venc_done(inst);
-       if (irq_status != MTK_VENC_IRQ_STATUS_FRM) {
-               mtk_vcodec_err(inst, "irq_status=%d failed", irq_status);
-               return -EIO;
-       }
-
-       if (vp8_enc_compose_one_frame(inst, bs_buf, bs_size)) {
-               mtk_vcodec_err(inst, "vp8_enc_compose_one_frame failed");
-               return -EINVAL;
-       }
-
-       inst->frm_cnt++;
-       mtk_vcodec_debug(inst, "<-size=%d key_frm=%d", *bs_size,
-                        inst->vpu_inst.is_key_frm);
-
-       return ret;
-}
-
-static int vp8_enc_init(struct mtk_vcodec_ctx *ctx)
-{
-       int ret = 0;
-       struct venc_vp8_inst *inst;
-
-       inst = kzalloc(sizeof(*inst), GFP_KERNEL);
-       if (!inst)
-               return -ENOMEM;
-
-       inst->ctx = ctx;
-       inst->vpu_inst.ctx = ctx;
-       inst->vpu_inst.id = IPI_VENC_VP8;
-       inst->hw_base = mtk_vcodec_get_reg_addr(inst->ctx, VENC_LT_SYS);
-
-       mtk_vcodec_debug_enter(inst);
-
-       ret = vpu_enc_init(&inst->vpu_inst);
-
-       inst->vsi = (struct venc_vp8_vsi *)inst->vpu_inst.vsi;
-
-       mtk_vcodec_debug_leave(inst);
-
-       if (ret)
-               kfree(inst);
-       else
-               ctx->drv_handle = inst;
-
-       return ret;
-}
-
-static int vp8_enc_encode(void *handle,
-                         enum venc_start_opt opt,
-                         struct venc_frm_buf *frm_buf,
-                         struct mtk_vcodec_mem *bs_buf,
-                         struct venc_done_result *result)
-{
-       int ret = 0;
-       struct venc_vp8_inst *inst = (struct venc_vp8_inst *)handle;
-       struct mtk_vcodec_ctx *ctx = inst->ctx;
-
-       mtk_vcodec_debug_enter(inst);
-
-       enable_irq(ctx->dev->enc_irq);
-
-       switch (opt) {
-       case VENC_START_OPT_ENCODE_FRAME:
-               ret = vp8_enc_encode_frame(inst, frm_buf, bs_buf,
-                                          &result->bs_size);
-               if (ret)
-                       goto encode_err;
-               result->is_key_frm = inst->vpu_inst.is_key_frm;
-               break;
-
-       default:
-               mtk_vcodec_err(inst, "opt not support:%d", opt);
-               ret = -EINVAL;
-               break;
-       }
-
-encode_err:
-
-       disable_irq(ctx->dev->enc_irq);
-       mtk_vcodec_debug_leave(inst);
-
-       return ret;
-}
-
-static int vp8_enc_set_param(void *handle,
-                            enum venc_set_param_type type,
-                            struct venc_enc_param *enc_prm)
-{
-       int ret = 0;
-       struct venc_vp8_inst *inst = (struct venc_vp8_inst *)handle;
-
-       mtk_vcodec_debug(inst, "->type=%d", type);
-
-       switch (type) {
-       case VENC_SET_PARAM_ENC:
-               inst->vsi->config.input_fourcc = enc_prm->input_yuv_fmt;
-               inst->vsi->config.bitrate = enc_prm->bitrate;
-               inst->vsi->config.pic_w = enc_prm->width;
-               inst->vsi->config.pic_h = enc_prm->height;
-               inst->vsi->config.buf_w = enc_prm->buf_width;
-               inst->vsi->config.buf_h = enc_prm->buf_height;
-               inst->vsi->config.gop_size = enc_prm->gop_size;
-               inst->vsi->config.framerate = enc_prm->frm_rate;
-               inst->vsi->config.ts_mode = inst->ts_mode;
-               ret = vpu_enc_set_param(&inst->vpu_inst, type, enc_prm);
-               if (ret)
-                       break;
-               if (inst->work_buf_allocated) {
-                       vp8_enc_free_work_buf(inst);
-                       inst->work_buf_allocated = false;
-               }
-               ret = vp8_enc_alloc_work_buf(inst);
-               if (ret)
-                       break;
-               inst->work_buf_allocated = true;
-               break;
-
-       /*
-        * VENC_SET_PARAM_TS_MODE must be called before VENC_SET_PARAM_ENC
-        */
-       case VENC_SET_PARAM_TS_MODE:
-               inst->ts_mode = 1;
-               mtk_vcodec_debug(inst, "set ts_mode");
-               break;
-
-       default:
-               ret = vpu_enc_set_param(&inst->vpu_inst, type, enc_prm);
-               break;
-       }
-
-       mtk_vcodec_debug_leave(inst);
-
-       return ret;
-}
-
-static int vp8_enc_deinit(void *handle)
-{
-       int ret = 0;
-       struct venc_vp8_inst *inst = (struct venc_vp8_inst *)handle;
-
-       mtk_vcodec_debug_enter(inst);
-
-       ret = vpu_enc_deinit(&inst->vpu_inst);
-
-       if (inst->work_buf_allocated)
-               vp8_enc_free_work_buf(inst);
-
-       mtk_vcodec_debug_leave(inst);
-       kfree(inst);
-
-       return ret;
-}
-
-const struct venc_common_if venc_vp8_if = {
-       .init = vp8_enc_init,
-       .encode = vp8_enc_encode,
-       .set_param = vp8_enc_set_param,
-       .deinit = vp8_enc_deinit,
-};
diff --git a/drivers/media/platform/mtk-vcodec/venc_drv_base.h b/drivers/media/platform/mtk-vcodec/venc_drv_base.h
deleted file mode 100644 (file)
index 3d71841..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (c) 2016 MediaTek Inc.
- * Author: Daniel Hsiao <daniel.hsiao@mediatek.com>
- *     Jungchang Tsao <jungchang.tsao@mediatek.com>
- *     Tiffany Lin <tiffany.lin@mediatek.com>
- */
-
-#ifndef _VENC_DRV_BASE_
-#define _VENC_DRV_BASE_
-
-#include "mtk_vcodec_drv.h"
-
-#include "venc_drv_if.h"
-
-struct venc_common_if {
-       /**
-        * (*init)() - initialize driver
-        * @ctx:        [in] mtk v4l2 context
-        * @handle: [out] driver handle
-        */
-       int (*init)(struct mtk_vcodec_ctx *ctx);
-
-       /**
-        * (*encode)() - trigger encode
-        * @handle: [in] driver handle
-        * @opt: [in] encode option
-        * @frm_buf: [in] frame buffer to store input frame
-        * @bs_buf: [in] bitstream buffer to store output bitstream
-        * @result: [out] encode result
-        */
-       int (*encode)(void *handle, enum venc_start_opt opt,
-                     struct venc_frm_buf *frm_buf,
-                     struct mtk_vcodec_mem *bs_buf,
-                     struct venc_done_result *result);
-
-       /**
-        * (*set_param)() - set driver's parameter
-        * @handle: [in] driver handle
-        * @type: [in] parameter type
-        * @in: [in] buffer to store the parameter
-        */
-       int (*set_param)(void *handle, enum venc_set_param_type type,
-                        struct venc_enc_param *in);
-
-       /**
-        * (*deinit)() - deinitialize driver.
-        * @handle: [in] driver handle
-        */
-       int (*deinit)(void *handle);
-};
-
-#endif
diff --git a/drivers/media/platform/mtk-vcodec/venc_drv_if.c b/drivers/media/platform/mtk-vcodec/venc_drv_if.c
deleted file mode 100644 (file)
index ce0bce8..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2016 MediaTek Inc.
- * Author: Daniel Hsiao <daniel.hsiao@mediatek.com>
- *     Jungchang Tsao <jungchang.tsao@mediatek.com>
- *     Tiffany Lin <tiffany.lin@mediatek.com>
- */
-
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-
-#include "venc_drv_base.h"
-#include "venc_drv_if.h"
-
-#include "mtk_vcodec_enc.h"
-#include "mtk_vcodec_enc_pm.h"
-
-int venc_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc)
-{
-       int ret = 0;
-
-       switch (fourcc) {
-       case V4L2_PIX_FMT_VP8:
-               ctx->enc_if = &venc_vp8_if;
-               break;
-       case V4L2_PIX_FMT_H264:
-               ctx->enc_if = &venc_h264_if;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       mtk_venc_lock(ctx);
-       mtk_vcodec_enc_clock_on(&ctx->dev->pm);
-       ret = ctx->enc_if->init(ctx);
-       mtk_vcodec_enc_clock_off(&ctx->dev->pm);
-       mtk_venc_unlock(ctx);
-
-       return ret;
-}
-
-int venc_if_set_param(struct mtk_vcodec_ctx *ctx,
-               enum venc_set_param_type type, struct venc_enc_param *in)
-{
-       int ret = 0;
-
-       mtk_venc_lock(ctx);
-       mtk_vcodec_enc_clock_on(&ctx->dev->pm);
-       ret = ctx->enc_if->set_param(ctx->drv_handle, type, in);
-       mtk_vcodec_enc_clock_off(&ctx->dev->pm);
-       mtk_venc_unlock(ctx);
-
-       return ret;
-}
-
-int venc_if_encode(struct mtk_vcodec_ctx *ctx,
-                  enum venc_start_opt opt, struct venc_frm_buf *frm_buf,
-                  struct mtk_vcodec_mem *bs_buf,
-                  struct venc_done_result *result)
-{
-       int ret = 0;
-       unsigned long flags;
-
-       mtk_venc_lock(ctx);
-
-       spin_lock_irqsave(&ctx->dev->irqlock, flags);
-       ctx->dev->curr_ctx = ctx;
-       spin_unlock_irqrestore(&ctx->dev->irqlock, flags);
-
-       mtk_vcodec_enc_clock_on(&ctx->dev->pm);
-       ret = ctx->enc_if->encode(ctx->drv_handle, opt, frm_buf,
-                                 bs_buf, result);
-       mtk_vcodec_enc_clock_off(&ctx->dev->pm);
-
-       spin_lock_irqsave(&ctx->dev->irqlock, flags);
-       ctx->dev->curr_ctx = NULL;
-       spin_unlock_irqrestore(&ctx->dev->irqlock, flags);
-
-       mtk_venc_unlock(ctx);
-       return ret;
-}
-
-int venc_if_deinit(struct mtk_vcodec_ctx *ctx)
-{
-       int ret = 0;
-
-       if (!ctx->drv_handle)
-               return 0;
-
-       mtk_venc_lock(ctx);
-       mtk_vcodec_enc_clock_on(&ctx->dev->pm);
-       ret = ctx->enc_if->deinit(ctx->drv_handle);
-       mtk_vcodec_enc_clock_off(&ctx->dev->pm);
-       mtk_venc_unlock(ctx);
-
-       ctx->drv_handle = NULL;
-
-       return ret;
-}
diff --git a/drivers/media/platform/mtk-vcodec/venc_drv_if.h b/drivers/media/platform/mtk-vcodec/venc_drv_if.h
deleted file mode 100644 (file)
index 0b04a10..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (c) 2016 MediaTek Inc.
- * Author: Daniel Hsiao <daniel.hsiao@mediatek.com>
- *             Jungchang Tsao <jungchang.tsao@mediatek.com>
- *             Tiffany Lin <tiffany.lin@mediatek.com>
- */
-
-#ifndef _VENC_DRV_IF_H_
-#define _VENC_DRV_IF_H_
-
-#include "mtk_vcodec_drv.h"
-#include "mtk_vcodec_util.h"
-
-/*
- * enum venc_yuv_fmt - The type of input yuv format
- * (VPU related: If you change the order, you must also update the VPU codes.)
- * @VENC_YUV_FORMAT_I420: I420 YUV format
- * @VENC_YUV_FORMAT_YV12: YV12 YUV format
- * @VENC_YUV_FORMAT_NV12: NV12 YUV format
- * @VENC_YUV_FORMAT_NV21: NV21 YUV format
- */
-enum venc_yuv_fmt {
-       VENC_YUV_FORMAT_I420 = 3,
-       VENC_YUV_FORMAT_YV12 = 5,
-       VENC_YUV_FORMAT_NV12 = 6,
-       VENC_YUV_FORMAT_NV21 = 7,
-};
-
-/*
- * enum venc_start_opt - encode frame option used in venc_if_encode()
- * @VENC_START_OPT_ENCODE_SEQUENCE_HEADER: encode SPS/PPS for H264
- * @VENC_START_OPT_ENCODE_FRAME: encode normal frame
- */
-enum venc_start_opt {
-       VENC_START_OPT_ENCODE_SEQUENCE_HEADER,
-       VENC_START_OPT_ENCODE_FRAME,
-};
-
-/*
- * enum venc_set_param_type - The type of set parameter used in
- *                                                   venc_if_set_param()
- * (VPU related: If you change the order, you must also update the VPU codes.)
- * @VENC_SET_PARAM_ENC: set encoder parameters
- * @VENC_SET_PARAM_FORCE_INTRA: force an intra frame
- * @VENC_SET_PARAM_ADJUST_BITRATE: adjust bitrate (in bps)
- * @VENC_SET_PARAM_ADJUST_FRAMERATE: set frame rate
- * @VENC_SET_PARAM_GOP_SIZE: set IDR interval
- * @VENC_SET_PARAM_INTRA_PERIOD: set I frame interval
- * @VENC_SET_PARAM_SKIP_FRAME: set H264 skip one frame
- * @VENC_SET_PARAM_PREPEND_HEADER: set H264 prepend SPS/PPS before IDR
- * @VENC_SET_PARAM_TS_MODE: set VP8 temporal scalability mode
- */
-enum venc_set_param_type {
-       VENC_SET_PARAM_ENC,
-       VENC_SET_PARAM_FORCE_INTRA,
-       VENC_SET_PARAM_ADJUST_BITRATE,
-       VENC_SET_PARAM_ADJUST_FRAMERATE,
-       VENC_SET_PARAM_GOP_SIZE,
-       VENC_SET_PARAM_INTRA_PERIOD,
-       VENC_SET_PARAM_SKIP_FRAME,
-       VENC_SET_PARAM_PREPEND_HEADER,
-       VENC_SET_PARAM_TS_MODE,
-};
-
-/*
- * struct venc_enc_prm - encoder settings for VENC_SET_PARAM_ENC used in
- *                                       venc_if_set_param()
- * @input_fourcc: input yuv format
- * @h264_profile: V4L2 defined H.264 profile
- * @h264_level: V4L2 defined H.264 level
- * @width: image width
- * @height: image height
- * @buf_width: buffer width
- * @buf_height: buffer height
- * @frm_rate: frame rate in fps
- * @intra_period: intra frame period
- * @bitrate: target bitrate in bps
- * @gop_size: group of picture size
- */
-struct venc_enc_param {
-       enum venc_yuv_fmt input_yuv_fmt;
-       unsigned int h264_profile;
-       unsigned int h264_level;
-       unsigned int width;
-       unsigned int height;
-       unsigned int buf_width;
-       unsigned int buf_height;
-       unsigned int frm_rate;
-       unsigned int intra_period;
-       unsigned int bitrate;
-       unsigned int gop_size;
-};
-
-/**
- * struct venc_frame_info - per-frame information to pass to the firmware.
- *
- * @frm_count:         sequential number for this frame
- * @skip_frm_count:    number of frames skipped so far while decoding
- * @frm_type:          type of the frame, from enum venc_h264_frame_type
- */
-struct venc_frame_info {
-       unsigned int frm_count;         /* per frame update */
-       unsigned int skip_frm_count;    /* per frame update */
-       unsigned int frm_type;          /* per frame update */
-};
-
-/*
- * struct venc_frm_buf - frame buffer information used in venc_if_encode()
- * @fb_addr: plane frame buffer addresses
- */
-struct venc_frm_buf {
-       struct mtk_vcodec_fb fb_addr[MTK_VCODEC_MAX_PLANES];
-};
-
-/*
- * struct venc_done_result - This is return information used in venc_if_encode()
- * @bs_size: output bitstream size
- * @is_key_frm: output is key frame or not
- */
-struct venc_done_result {
-       unsigned int bs_size;
-       bool is_key_frm;
-};
-
-extern const struct venc_common_if venc_h264_if;
-extern const struct venc_common_if venc_vp8_if;
-
-/*
- * venc_if_init - Create the driver handle
- * @ctx: device context
- * @fourcc: encoder input format
- * Return: 0 if creating handle successfully, otherwise it is failed.
- */
-int venc_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc);
-
-/*
- * venc_if_deinit - Release the driver handle
- * @ctx: device context
- * Return: 0 if releasing handle successfully, otherwise it is failed.
- */
-int venc_if_deinit(struct mtk_vcodec_ctx *ctx);
-
-/*
- * venc_if_set_param - Set parameter to driver
- * @ctx: device context
- * @type: parameter type
- * @in: input parameter
- * Return: 0 if setting param successfully, otherwise it is failed.
- */
-int venc_if_set_param(struct mtk_vcodec_ctx *ctx,
-                     enum venc_set_param_type type,
-                     struct venc_enc_param *in);
-
-/*
- * venc_if_encode - Encode one frame
- * @ctx: device context
- * @opt: encode frame option
- * @frm_buf: input frame buffer information
- * @bs_buf: output bitstream buffer infomraiton
- * @result: encode result
- * Return: 0 if encoding frame successfully, otherwise it is failed.
- */
-int venc_if_encode(struct mtk_vcodec_ctx *ctx,
-                  enum venc_start_opt opt,
-                  struct venc_frm_buf *frm_buf,
-                  struct mtk_vcodec_mem *bs_buf,
-                  struct venc_done_result *result);
-
-#endif /* _VENC_DRV_IF_H_ */
diff --git a/drivers/media/platform/mtk-vcodec/venc_ipi_msg.h b/drivers/media/platform/mtk-vcodec/venc_ipi_msg.h
deleted file mode 100644 (file)
index 587a2cf..0000000
+++ /dev/null
@@ -1,220 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (c) 2016 MediaTek Inc.
- * Author: Jungchang Tsao <jungchang.tsao@mediatek.com>
- *        Daniel Hsiao <daniel.hsiao@mediatek.com>
- *        Tiffany Lin <tiffany.lin@mediatek.com>
- */
-
-#ifndef _VENC_IPI_MSG_H_
-#define _VENC_IPI_MSG_H_
-
-#define AP_IPIMSG_VENC_BASE 0xC000
-#define VPU_IPIMSG_VENC_BASE 0xD000
-
-/*
- * enum venc_ipi_msg_id - message id between AP and VPU
- * (ipi stands for inter-processor interrupt)
- * @AP_IPIMSG_ENC_XXX:         AP to VPU cmd message id
- * @VPU_IPIMSG_ENC_XXX_DONE:   VPU ack AP cmd message id
- */
-enum venc_ipi_msg_id {
-       AP_IPIMSG_ENC_INIT = AP_IPIMSG_VENC_BASE,
-       AP_IPIMSG_ENC_SET_PARAM,
-       AP_IPIMSG_ENC_ENCODE,
-       AP_IPIMSG_ENC_DEINIT,
-
-       VPU_IPIMSG_ENC_INIT_DONE = VPU_IPIMSG_VENC_BASE,
-       VPU_IPIMSG_ENC_SET_PARAM_DONE,
-       VPU_IPIMSG_ENC_ENCODE_DONE,
-       VPU_IPIMSG_ENC_DEINIT_DONE,
-};
-
-/**
- * struct venc_ap_ipi_msg_init - AP to VPU init cmd structure
- * @msg_id:    message id (AP_IPIMSG_XXX_ENC_INIT)
- * @reserved:  reserved for future use. vpu is running in 32bit. Without
- *             this reserved field, if kernel run in 64bit. this struct size
- *             will be different between kernel and vpu
- * @venc_inst: AP encoder instance
- *             (struct venc_vp8_inst/venc_h264_inst *)
- */
-struct venc_ap_ipi_msg_init {
-       uint32_t msg_id;
-       uint32_t reserved;
-       uint64_t venc_inst;
-};
-
-/**
- * struct venc_ap_ipi_msg_set_param - AP to VPU set_param cmd structure
- * @msg_id:    message id (AP_IPIMSG_XXX_ENC_SET_PARAM)
- * @vpu_inst_addr:     VPU encoder instance addr
- *                     (struct venc_vp8_vsi/venc_h264_vsi *)
- * @param_id:  parameter id (venc_set_param_type)
- * @data_item: number of items in the data array
- * @data:      data array to store the set parameters
- */
-struct venc_ap_ipi_msg_set_param {
-       uint32_t msg_id;
-       uint32_t vpu_inst_addr;
-       uint32_t param_id;
-       uint32_t data_item;
-       uint32_t data[8];
-};
-
-struct venc_ap_ipi_msg_set_param_ext {
-       struct venc_ap_ipi_msg_set_param base;
-       uint32_t data_ext[24];
-};
-
-/**
- * struct venc_ap_ipi_msg_enc - AP to VPU enc cmd structure
- * @msg_id:    message id (AP_IPIMSG_XXX_ENC_ENCODE)
- * @vpu_inst_addr:     VPU encoder instance addr
- *                     (struct venc_vp8_vsi/venc_h264_vsi *)
- * @bs_mode:   bitstream mode for h264
- *             (H264_BS_MODE_SPS/H264_BS_MODE_PPS/H264_BS_MODE_FRAME)
- * @input_addr:        pointer to input image buffer plane
- * @bs_addr:   pointer to output bit stream buffer
- * @bs_size:   bit stream buffer size
- */
-struct venc_ap_ipi_msg_enc {
-       uint32_t msg_id;
-       uint32_t vpu_inst_addr;
-       uint32_t bs_mode;
-       uint32_t input_addr[3];
-       uint32_t bs_addr;
-       uint32_t bs_size;
-};
-
-/**
- * struct venc_ap_ipi_msg_enc_ext - AP to SCP extended enc cmd structure
- *
- * @base:      base msg structure
- * @data_item: number of items in the data array
- * @data:      data array to store the set parameters
- */
-struct venc_ap_ipi_msg_enc_ext {
-       struct venc_ap_ipi_msg_enc base;
-       uint32_t data_item;
-       uint32_t data[32];
-};
-
-/**
- * struct venc_ap_ipi_msg_deinit - AP to VPU deinit cmd structure
- * @msg_id:    message id (AP_IPIMSG_XXX_ENC_DEINIT)
- * @vpu_inst_addr:     VPU encoder instance addr
- *                     (struct venc_vp8_vsi/venc_h264_vsi *)
- */
-struct venc_ap_ipi_msg_deinit {
-       uint32_t msg_id;
-       uint32_t vpu_inst_addr;
-};
-
-/*
- * enum venc_ipi_msg_status - VPU ack AP cmd status
- */
-enum venc_ipi_msg_status {
-       VENC_IPI_MSG_STATUS_OK,
-       VENC_IPI_MSG_STATUS_FAIL,
-};
-
-/**
- * struct venc_vpu_ipi_msg_common - VPU ack AP cmd common structure
- * @msg_id:    message id (VPU_IPIMSG_XXX_DONE)
- * @status:    cmd status (venc_ipi_msg_status)
- * @venc_inst: AP encoder instance (struct venc_vp8_inst/venc_h264_inst *)
- */
-struct venc_vpu_ipi_msg_common {
-       uint32_t msg_id;
-       uint32_t status;
-       uint64_t venc_inst;
-};
-
-/**
- * struct venc_vpu_ipi_msg_init - VPU ack AP init cmd structure
- * @msg_id:    message id (VPU_IPIMSG_XXX_ENC_SET_PARAM_DONE)
- * @status:    cmd status (venc_ipi_msg_status)
- * @venc_inst: AP encoder instance (struct venc_vp8_inst/venc_h264_inst *)
- * @vpu_inst_addr:     VPU encoder instance addr
- *                     (struct venc_vp8_vsi/venc_h264_vsi *)
- * @venc_abi_version:  ABI version of the firmware. Kernel can use it to
- *                     ensure that it is compatible with the firmware.
- *                     For MT8173 the value of this field is undefined and
- *                     should not be used.
- */
-struct venc_vpu_ipi_msg_init {
-       uint32_t msg_id;
-       uint32_t status;
-       uint64_t venc_inst;
-       uint32_t vpu_inst_addr;
-       uint32_t venc_abi_version;
-};
-
-/**
- * struct venc_vpu_ipi_msg_set_param - VPU ack AP set_param cmd structure
- * @msg_id:    message id (VPU_IPIMSG_XXX_ENC_SET_PARAM_DONE)
- * @status:    cmd status (venc_ipi_msg_status)
- * @venc_inst: AP encoder instance (struct venc_vp8_inst/venc_h264_inst *)
- * @param_id:  parameter id (venc_set_param_type)
- * @data_item: number of items in the data array
- * @data:      data array to store the return result
- */
-struct venc_vpu_ipi_msg_set_param {
-       uint32_t msg_id;
-       uint32_t status;
-       uint64_t venc_inst;
-       uint32_t param_id;
-       uint32_t data_item;
-       uint32_t data[6];
-};
-
-/**
- * enum venc_ipi_msg_enc_state - Type of encode state
- * @VEN_IPI_MSG_ENC_STATE_FRAME:       one frame being encoded
- * @VEN_IPI_MSG_ENC_STATE_PART:                bit stream buffer full
- * @VEN_IPI_MSG_ENC_STATE_SKIP:                encoded skip frame
- * @VEN_IPI_MSG_ENC_STATE_ERROR:       encounter error
- */
-enum venc_ipi_msg_enc_state {
-       VEN_IPI_MSG_ENC_STATE_FRAME,
-       VEN_IPI_MSG_ENC_STATE_PART,
-       VEN_IPI_MSG_ENC_STATE_SKIP,
-       VEN_IPI_MSG_ENC_STATE_ERROR,
-};
-
-/**
- * struct venc_vpu_ipi_msg_enc - VPU ack AP enc cmd structure
- * @msg_id:    message id (VPU_IPIMSG_XXX_ENC_ENCODE_DONE)
- * @status:    cmd status (venc_ipi_msg_status)
- * @venc_inst: AP encoder instance (struct venc_vp8_inst/venc_h264_inst *)
- * @state:     encode state (venc_ipi_msg_enc_state)
- * @is_key_frm:        whether the encoded frame is key frame
- * @bs_size:   encoded bitstream size
- * @reserved:  reserved for future use. vpu is running in 32bit. Without
- *             this reserved field, if kernel run in 64bit. this struct size
- *             will be different between kernel and vpu
- */
-struct venc_vpu_ipi_msg_enc {
-       uint32_t msg_id;
-       uint32_t status;
-       uint64_t venc_inst;
-       uint32_t state;
-       uint32_t is_key_frm;
-       uint32_t bs_size;
-       uint32_t reserved;
-};
-
-/**
- * struct venc_vpu_ipi_msg_deinit - VPU ack AP deinit cmd structure
- * @msg_id:   message id (VPU_IPIMSG_XXX_ENC_DEINIT_DONE)
- * @status:   cmd status (venc_ipi_msg_status)
- * @venc_inst: AP encoder instance (struct venc_vp8_inst/venc_h264_inst *)
- */
-struct venc_vpu_ipi_msg_deinit {
-       uint32_t msg_id;
-       uint32_t status;
-       uint64_t venc_inst;
-};
-
-#endif /* _VENC_IPI_MSG_H_ */
diff --git a/drivers/media/platform/mtk-vcodec/venc_vpu_if.c b/drivers/media/platform/mtk-vcodec/venc_vpu_if.c
deleted file mode 100644 (file)
index e7899d8..0000000
+++ /dev/null
@@ -1,293 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2016 MediaTek Inc.
- * Author: PoChun Lin <pochun.lin@mediatek.com>
- */
-
-#include "mtk_vcodec_drv.h"
-#include "mtk_vcodec_fw.h"
-#include "venc_ipi_msg.h"
-#include "venc_vpu_if.h"
-
-static void handle_enc_init_msg(struct venc_vpu_inst *vpu, const void *data)
-{
-       const struct venc_vpu_ipi_msg_init *msg = data;
-
-       vpu->inst_addr = msg->vpu_inst_addr;
-       vpu->vsi = mtk_vcodec_fw_map_dm_addr(vpu->ctx->dev->fw_handler,
-                                            msg->vpu_inst_addr);
-
-       /* Firmware version field value is unspecified on MT8173. */
-       if (vpu->ctx->dev->venc_pdata->chip == MTK_MT8173)
-               return;
-
-       /* Check firmware version. */
-       mtk_vcodec_debug(vpu, "firmware version: 0x%x\n",
-                        msg->venc_abi_version);
-       switch (msg->venc_abi_version) {
-       case 1:
-               break;
-       default:
-               mtk_vcodec_err(vpu, "unhandled firmware version 0x%x\n",
-                              msg->venc_abi_version);
-               vpu->failure = 1;
-               break;
-       }
-}
-
-static void handle_enc_encode_msg(struct venc_vpu_inst *vpu, const void *data)
-{
-       const struct venc_vpu_ipi_msg_enc *msg = data;
-
-       vpu->state = msg->state;
-       vpu->bs_size = msg->bs_size;
-       vpu->is_key_frm = msg->is_key_frm;
-}
-
-static void vpu_enc_ipi_handler(void *data, unsigned int len, void *priv)
-{
-       const struct venc_vpu_ipi_msg_common *msg = data;
-       struct venc_vpu_inst *vpu =
-               (struct venc_vpu_inst *)(unsigned long)msg->venc_inst;
-
-       mtk_vcodec_debug(vpu, "msg_id %x inst %p status %d",
-                        msg->msg_id, vpu, msg->status);
-
-       vpu->signaled = 1;
-       vpu->failure = (msg->status != VENC_IPI_MSG_STATUS_OK);
-       if (vpu->failure)
-               goto failure;
-
-       switch (msg->msg_id) {
-       case VPU_IPIMSG_ENC_INIT_DONE:
-               handle_enc_init_msg(vpu, data);
-               break;
-       case VPU_IPIMSG_ENC_SET_PARAM_DONE:
-               break;
-       case VPU_IPIMSG_ENC_ENCODE_DONE:
-               handle_enc_encode_msg(vpu, data);
-               break;
-       case VPU_IPIMSG_ENC_DEINIT_DONE:
-               break;
-       default:
-               mtk_vcodec_err(vpu, "unknown msg id %x", msg->msg_id);
-               break;
-       }
-
-failure:
-       mtk_vcodec_debug_leave(vpu);
-}
-
-static int vpu_enc_send_msg(struct venc_vpu_inst *vpu, void *msg,
-                           int len)
-{
-       int status;
-
-       mtk_vcodec_debug_enter(vpu);
-
-       if (!vpu->ctx->dev->fw_handler) {
-               mtk_vcodec_err(vpu, "inst dev is NULL");
-               return -EINVAL;
-       }
-
-       status = mtk_vcodec_fw_ipi_send(vpu->ctx->dev->fw_handler, vpu->id, msg,
-                                       len, 2000);
-       if (status) {
-               mtk_vcodec_err(vpu, "vpu_ipi_send msg_id %x len %d fail %d",
-                              *(uint32_t *)msg, len, status);
-               return -EINVAL;
-       }
-       if (vpu->failure)
-               return -EINVAL;
-
-       mtk_vcodec_debug_leave(vpu);
-
-       return 0;
-}
-
-int vpu_enc_init(struct venc_vpu_inst *vpu)
-{
-       int status;
-       struct venc_ap_ipi_msg_init out;
-
-       mtk_vcodec_debug_enter(vpu);
-
-       init_waitqueue_head(&vpu->wq_hd);
-       vpu->signaled = 0;
-       vpu->failure = 0;
-
-       status = mtk_vcodec_fw_ipi_register(vpu->ctx->dev->fw_handler, vpu->id,
-                                           vpu_enc_ipi_handler, "venc", NULL);
-
-       if (status) {
-               mtk_vcodec_err(vpu, "vpu_ipi_register fail %d", status);
-               return -EINVAL;
-       }
-
-       memset(&out, 0, sizeof(out));
-       out.msg_id = AP_IPIMSG_ENC_INIT;
-       out.venc_inst = (unsigned long)vpu;
-       if (vpu_enc_send_msg(vpu, &out, sizeof(out))) {
-               mtk_vcodec_err(vpu, "AP_IPIMSG_ENC_INIT fail");
-               return -EINVAL;
-       }
-
-       mtk_vcodec_debug_leave(vpu);
-
-       return 0;
-}
-
-static unsigned int venc_enc_param_crop_right(struct venc_vpu_inst *vpu,
-                                             struct venc_enc_param *enc_prm)
-{
-       unsigned int img_crop_right = enc_prm->buf_width - enc_prm->width;
-
-       return img_crop_right % 16;
-}
-
-static unsigned int venc_enc_param_crop_bottom(struct venc_enc_param *enc_prm)
-{
-       return round_up(enc_prm->height, 16) - enc_prm->height;
-}
-
-static unsigned int venc_enc_param_num_mb(struct venc_enc_param *enc_prm)
-{
-       return DIV_ROUND_UP(enc_prm->width, 16) *
-              DIV_ROUND_UP(enc_prm->height, 16);
-}
-
-int vpu_enc_set_param(struct venc_vpu_inst *vpu,
-                     enum venc_set_param_type id,
-                     struct venc_enc_param *enc_param)
-{
-       const bool is_ext = MTK_ENC_CTX_IS_EXT(vpu->ctx);
-       size_t msg_size = is_ext ?
-               sizeof(struct venc_ap_ipi_msg_set_param_ext) :
-               sizeof(struct venc_ap_ipi_msg_set_param);
-       struct venc_ap_ipi_msg_set_param_ext out;
-
-       mtk_vcodec_debug(vpu, "id %d ->", id);
-
-       memset(&out, 0, sizeof(out));
-       out.base.msg_id = AP_IPIMSG_ENC_SET_PARAM;
-       out.base.vpu_inst_addr = vpu->inst_addr;
-       out.base.param_id = id;
-       switch (id) {
-       case VENC_SET_PARAM_ENC:
-               if (is_ext) {
-                       out.base.data_item = 3;
-                       out.base.data[0] =
-                               venc_enc_param_crop_right(vpu, enc_param);
-                       out.base.data[1] =
-                               venc_enc_param_crop_bottom(enc_param);
-                       out.base.data[2] = venc_enc_param_num_mb(enc_param);
-               } else {
-                       out.base.data_item = 0;
-               }
-               break;
-       case VENC_SET_PARAM_FORCE_INTRA:
-               out.base.data_item = 0;
-               break;
-       case VENC_SET_PARAM_ADJUST_BITRATE:
-               out.base.data_item = 1;
-               out.base.data[0] = enc_param->bitrate;
-               break;
-       case VENC_SET_PARAM_ADJUST_FRAMERATE:
-               out.base.data_item = 1;
-               out.base.data[0] = enc_param->frm_rate;
-               break;
-       case VENC_SET_PARAM_GOP_SIZE:
-               out.base.data_item = 1;
-               out.base.data[0] = enc_param->gop_size;
-               break;
-       case VENC_SET_PARAM_INTRA_PERIOD:
-               out.base.data_item = 1;
-               out.base.data[0] = enc_param->intra_period;
-               break;
-       case VENC_SET_PARAM_SKIP_FRAME:
-               out.base.data_item = 0;
-               break;
-       default:
-               mtk_vcodec_err(vpu, "id %d not supported", id);
-               return -EINVAL;
-       }
-       if (vpu_enc_send_msg(vpu, &out, msg_size)) {
-               mtk_vcodec_err(vpu,
-                              "AP_IPIMSG_ENC_SET_PARAM %d fail", id);
-               return -EINVAL;
-       }
-
-       mtk_vcodec_debug(vpu, "id %d <-", id);
-
-       return 0;
-}
-
-int vpu_enc_encode(struct venc_vpu_inst *vpu, unsigned int bs_mode,
-                  struct venc_frm_buf *frm_buf,
-                  struct mtk_vcodec_mem *bs_buf,
-                  struct venc_frame_info *frame_info)
-{
-       const bool is_ext = MTK_ENC_CTX_IS_EXT(vpu->ctx);
-       size_t msg_size = is_ext ?
-               sizeof(struct venc_ap_ipi_msg_enc_ext) :
-               sizeof(struct venc_ap_ipi_msg_enc);
-       struct venc_ap_ipi_msg_enc_ext out;
-
-       mtk_vcodec_debug(vpu, "bs_mode %d ->", bs_mode);
-
-       memset(&out, 0, sizeof(out));
-       out.base.msg_id = AP_IPIMSG_ENC_ENCODE;
-       out.base.vpu_inst_addr = vpu->inst_addr;
-       out.base.bs_mode = bs_mode;
-       if (frm_buf) {
-               if ((frm_buf->fb_addr[0].dma_addr % 16 == 0) &&
-                   (frm_buf->fb_addr[1].dma_addr % 16 == 0) &&
-                   (frm_buf->fb_addr[2].dma_addr % 16 == 0)) {
-                       out.base.input_addr[0] = frm_buf->fb_addr[0].dma_addr;
-                       out.base.input_addr[1] = frm_buf->fb_addr[1].dma_addr;
-                       out.base.input_addr[2] = frm_buf->fb_addr[2].dma_addr;
-               } else {
-                       mtk_vcodec_err(vpu, "dma_addr not align to 16");
-                       return -EINVAL;
-               }
-       }
-       if (bs_buf) {
-               out.base.bs_addr = bs_buf->dma_addr;
-               out.base.bs_size = bs_buf->size;
-       }
-       if (is_ext && frame_info) {
-               out.data_item = 3;
-               out.data[0] = frame_info->frm_count;
-               out.data[1] = frame_info->skip_frm_count;
-               out.data[2] = frame_info->frm_type;
-       }
-       if (vpu_enc_send_msg(vpu, &out, msg_size)) {
-               mtk_vcodec_err(vpu, "AP_IPIMSG_ENC_ENCODE %d fail",
-                              bs_mode);
-               return -EINVAL;
-       }
-
-       mtk_vcodec_debug(vpu, "bs_mode %d state %d size %d key_frm %d <-",
-                        bs_mode, vpu->state, vpu->bs_size, vpu->is_key_frm);
-
-       return 0;
-}
-
-int vpu_enc_deinit(struct venc_vpu_inst *vpu)
-{
-       struct venc_ap_ipi_msg_deinit out;
-
-       mtk_vcodec_debug_enter(vpu);
-
-       memset(&out, 0, sizeof(out));
-       out.msg_id = AP_IPIMSG_ENC_DEINIT;
-       out.vpu_inst_addr = vpu->inst_addr;
-       if (vpu_enc_send_msg(vpu, &out, sizeof(out))) {
-               mtk_vcodec_err(vpu, "AP_IPIMSG_ENC_DEINIT fail");
-               return -EINVAL;
-       }
-
-       mtk_vcodec_debug_leave(vpu);
-
-       return 0;
-}
diff --git a/drivers/media/platform/mtk-vcodec/venc_vpu_if.h b/drivers/media/platform/mtk-vcodec/venc_vpu_if.h
deleted file mode 100644 (file)
index f83bc1b..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (c) 2016 MediaTek Inc.
- * Author: PoChun Lin <pochun.lin@mediatek.com>
- */
-
-#ifndef _VENC_VPU_IF_H_
-#define _VENC_VPU_IF_H_
-
-#include "mtk_vcodec_fw.h"
-#include "venc_drv_if.h"
-
-/*
- * struct venc_vpu_inst - encoder VPU driver instance
- * @wq_hd: wait queue used for vpu cmd trigger then wait vpu interrupt done
- * @signaled: flag used for checking vpu interrupt done
- * @failure: flag to show vpu cmd succeeds or not
- * @state: enum venc_ipi_msg_enc_state
- * @bs_size: bitstream size for skip frame case usage
- * @is_key_frm: key frame flag
- * @inst_addr: VPU instance addr
- * @vsi: driver structure allocated by VPU side and shared to AP side for
- *      control and info share
- * @id: the id of inter-processor interrupt
- * @ctx: context for v4l2 layer integration
- * @dev: device for v4l2 layer integration
- */
-struct venc_vpu_inst {
-       wait_queue_head_t wq_hd;
-       int signaled;
-       int failure;
-       int state;
-       int bs_size;
-       int is_key_frm;
-       unsigned int inst_addr;
-       void *vsi;
-       int id;
-       struct mtk_vcodec_ctx *ctx;
-};
-
-int vpu_enc_init(struct venc_vpu_inst *vpu);
-int vpu_enc_set_param(struct venc_vpu_inst *vpu,
-                     enum venc_set_param_type id,
-                     struct venc_enc_param *param);
-int vpu_enc_encode(struct venc_vpu_inst *vpu, unsigned int bs_mode,
-                  struct venc_frm_buf *frm_buf,
-                  struct mtk_vcodec_mem *bs_buf,
-                  struct venc_frame_info *frame_info);
-int vpu_enc_deinit(struct venc_vpu_inst *vpu);
-
-#endif