-obj-$(CONFIG_VIDEO_EXYNOS_MFC) := s5p-mfc.o
-s5p-mfc-y += s5p_mfc.o s5p_mfc_irq.o s5p_mfc_dec.o s5p_mfc_dec_vb2_ops.o s5p_mfc_enc.o s5p_mfc_enc_vb2_ops.o
-s5p-mfc-y += s5p_mfc_ctrl.o s5p_mfc_hwlock.o s5p_mfc_nal_q.o s5p_mfc_watchdog.o s5p_mfc_opr.o s5p_mfc_sync.o
-s5p-mfc-y += s5p_mfc_pm.o s5p_mfc_inst.o s5p_mfc_cmd.o s5p_mfc_cal.o s5p_mfc_reg.o s5p_mfc_perf_measure.o
-s5p-mfc-y += s5p_mfc_dec_ops.o s5p_mfc_enc_ops.o s5p_mfc_enc_param.o
-s5p-mfc-y += s5p_mfc_queue.o s5p_mfc_buf.o s5p_mfc_utils.o s5p_mfc_qos.o s5p_mfc_mem.o
-s5p-mfc-y += s5p_mfc_debugfs.o s5p_mfc_otf.o
-s5p-mfc-y += s5p_mfc_mmcache.o
+obj-$(CONFIG_VIDEO_EXYNOS_MFC) := exynos_mfc.o
+exynos_mfc-y += mfc.o mfc_irq.o mfc_dec.o mfc_dec_vb2_ops.o mfc_enc.o mfc_enc_vb2_ops.o
+exynos_mfc-y += mfc_ctrl.o mfc_hwlock.o mfc_nal_q.o mfc_watchdog.o mfc_opr.o mfc_sync.o
+exynos_mfc-y += mfc_pm.o mfc_inst.o mfc_cmd.o mfc_cal.o mfc_reg.o mfc_perf_measure.o
+exynos_mfc-y += mfc_dec_ops.o mfc_enc_ops.o mfc_enc_param.o
+exynos_mfc-y += mfc_queue.o mfc_buf.o mfc_utils.o mfc_qos.o mfc_mem.o
+exynos_mfc-y += mfc_debugfs.o mfc_otf.o
+exynos_mfc-y += mfc_mmcache.o
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc.c
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of_address.h>
+#include <linux/proc_fs.h>
+#include <video/videonode.h>
+#include <linux/of.h>
+#include <linux/smc.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/poll.h>
+
+#include "mfc_common.h"
+
+#include "mfc_irq.h"
+#include "mfc_dec.h"
+#include "mfc_enc.h"
+
+#include "mfc_ctrl.h"
+#include "mfc_hwlock.h"
+#include "mfc_nal_q.h"
+#include "mfc_otf.h"
+#include "mfc_watchdog.h"
+#include "mfc_debugfs.h"
+#include "mfc_opr.h"
+#include "mfc_sync.h"
+
+#include "mfc_inst.h"
+#include "mfc_pm.h"
+#include "mfc_cal.h"
+#include "mfc_perf_measure.h"
+#include "mfc_reg.h"
+#include "mfc_mmcache.h"
+
+#include "mfc_qos.h"
+#include "mfc_queue.h"
+#include "mfc_utils.h"
+#include "mfc_buf.h"
+#include "mfc_mem.h"
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/mfc.h>
+
+#define S5P_MFC_NAME "s5p-mfc"
+#define S5P_MFC_DEC_NAME "s5p-mfc-dec"
+#define S5P_MFC_ENC_NAME "s5p-mfc-enc"
+#define S5P_MFC_DEC_DRM_NAME "s5p-mfc-dec-secure"
+#define S5P_MFC_ENC_DRM_NAME "s5p-mfc-enc-secure"
+#define S5P_MFC_ENC_OTF_NAME "s5p-mfc-enc-otf"
+#define S5P_MFC_ENC_OTF_DRM_NAME "s5p-mfc-enc-otf-secure"
+
+struct _mfc_trace g_mfc_trace[MFC_TRACE_COUNT_MAX];
+struct _mfc_trace g_mfc_trace_hwlock[MFC_TRACE_COUNT_MAX];
+struct s5p_mfc_dev *g_mfc_dev;
+
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+static struct proc_dir_entry *mfc_proc_entry;
+
+#define MFC_PROC_ROOT "mfc"
+#define MFC_PROC_INSTANCE_NUMBER "instance_number"
+#define MFC_PROC_DRM_INSTANCE_NUMBER "drm_instance_number"
+#define MFC_PROC_FW_STATUS "fw_status"
+#endif
+
+#define DEF_DEC_SRC_FMT 9
+#define DEF_DEC_DST_FMT 5
+
+#define DEF_ENC_SRC_FMT 5
+#define DEF_ENC_DST_FMT 13
+
+void s5p_mfc_butler_worker(struct work_struct *work)
+{
+ struct s5p_mfc_dev *dev;
+
+ dev = container_of(work, struct s5p_mfc_dev, butler_work);
+
+ s5p_mfc_try_run(dev);
+}
+
+extern struct s5p_mfc_ctrls_ops decoder_ctrls_ops;
+extern struct vb2_ops s5p_mfc_dec_qops;
+extern struct s5p_mfc_fmt dec_formats[];
+
+static void mfc_deinit_dec_ctx(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+
+ s5p_mfc_delete_queue(&ctx->src_buf_queue);
+ s5p_mfc_delete_queue(&ctx->dst_buf_queue);
+ s5p_mfc_delete_queue(&ctx->src_buf_nal_queue);
+ s5p_mfc_delete_queue(&ctx->dst_buf_nal_queue);
+ s5p_mfc_delete_queue(&ctx->ref_buf_queue);
+
+ s5p_mfc_mem_cleanup_user_shared_handle(ctx, &dec->sh_handle);
+ kfree(dec->ref_info);
+ kfree(dec);
+}
+
+static int mfc_init_dec_ctx(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dec *dec;
+ int ret = 0;
+ int i;
+
+ dec = kzalloc(sizeof(struct s5p_mfc_dec), GFP_KERNEL);
+ if (!dec) {
+ mfc_err_dev("failed to allocate decoder private data\n");
+ return -ENOMEM;
+ }
+ ctx->dec_priv = dec;
+
+ ctx->inst_no = MFC_NO_INSTANCE_SET;
+
+ s5p_mfc_create_queue(&ctx->src_buf_queue);
+ s5p_mfc_create_queue(&ctx->dst_buf_queue);
+ s5p_mfc_create_queue(&ctx->src_buf_nal_queue);
+ s5p_mfc_create_queue(&ctx->dst_buf_nal_queue);
+ s5p_mfc_create_queue(&ctx->ref_buf_queue);
+
+ for (i = 0; i < MFC_MAX_BUFFERS; i++) {
+ INIT_LIST_HEAD(&ctx->src_ctrls[i]);
+ INIT_LIST_HEAD(&ctx->dst_ctrls[i]);
+ }
+ ctx->src_ctrls_avail = 0;
+ ctx->dst_ctrls_avail = 0;
+
+ ctx->capture_state = QUEUE_FREE;
+ ctx->output_state = QUEUE_FREE;
+
+ s5p_mfc_change_state(ctx, MFCINST_INIT);
+ ctx->type = MFCINST_DECODER;
+ ctx->c_ops = &decoder_ctrls_ops;
+ ctx->src_fmt = &dec_formats[DEF_DEC_SRC_FMT];
+ ctx->dst_fmt = &dec_formats[DEF_DEC_DST_FMT];
+
+ s5p_mfc_qos_reset_framerate(ctx);
+
+ ctx->qos_ratio = 100;
+#ifdef CONFIG_MFC_USE_BUS_DEVFREQ
+ INIT_LIST_HEAD(&ctx->qos_list);
+#endif
+ INIT_LIST_HEAD(&ctx->ts_list);
+
+ dec->display_delay = -1;
+ dec->is_interlaced = 0;
+ dec->immediate_display = 0;
+ dec->is_dts_mode = 0;
+ dec->err_reuse_flag = 0;
+ dec->dec_only_release_flag = 0;
+
+ dec->is_dynamic_dpb = 1;
+ dec->dynamic_used = 0;
+ dec->is_dpb_full = 0;
+ s5p_mfc_cleanup_assigned_fd(ctx);
+ s5p_mfc_clear_assigned_dpb(ctx);
+ dec->sh_handle.fd = -1;
+ dec->ref_info = kzalloc(
+ (sizeof(struct dec_dpb_ref_info) * MFC_MAX_DPBS), GFP_KERNEL);
+ if (!dec->ref_info) {
+ mfc_err_dev("failed to allocate decoder information data\n");
+ ret = -ENOMEM;
+ goto fail_dec_init;
+ }
+ for (i = 0; i < MFC_MAX_BUFFERS; i++)
+ dec->ref_info[i].dpb[0].fd[0] = MFC_INFO_INIT_FD;
+
+ /* Init videobuf2 queue for OUTPUT */
+ ctx->vq_src.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ ctx->vq_src.drv_priv = ctx;
+ ctx->vq_src.buf_struct_size = sizeof(struct s5p_mfc_buf);
+ ctx->vq_src.io_modes = VB2_USERPTR | VB2_DMABUF;
+ ctx->vq_src.ops = &s5p_mfc_dec_qops;
+ ctx->vq_src.mem_ops = s5p_mfc_mem_ops();
+ ctx->vq_src.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ ret = vb2_queue_init(&ctx->vq_src);
+ if (ret) {
+ mfc_err_dev("Failed to initialize videobuf2 queue(output)\n");
+ goto fail_dec_init;
+ }
+ /* Init videobuf2 queue for CAPTURE */
+ ctx->vq_dst.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ ctx->vq_dst.drv_priv = ctx;
+ ctx->vq_dst.buf_struct_size = sizeof(struct s5p_mfc_buf);
+ ctx->vq_dst.io_modes = VB2_USERPTR | VB2_DMABUF;
+ ctx->vq_dst.ops = &s5p_mfc_dec_qops;
+ ctx->vq_dst.mem_ops = s5p_mfc_mem_ops();
+ ctx->vq_dst.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ ret = vb2_queue_init(&ctx->vq_dst);
+ if (ret) {
+ mfc_err_dev("Failed to initialize videobuf2 queue(capture)\n");
+ goto fail_dec_init;
+ }
+
+ return ret;
+
+fail_dec_init:
+ mfc_deinit_dec_ctx(ctx);
+ return ret;
+}
+
+extern struct s5p_mfc_ctrls_ops encoder_ctrls_ops;
+extern struct vb2_ops s5p_mfc_enc_qops;
+extern struct s5p_mfc_fmt enc_formats[];
+
+static void mfc_deinit_enc_ctx(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+
+ s5p_mfc_delete_queue(&ctx->src_buf_queue);
+ s5p_mfc_delete_queue(&ctx->dst_buf_queue);
+ s5p_mfc_delete_queue(&ctx->src_buf_nal_queue);
+ s5p_mfc_delete_queue(&ctx->dst_buf_nal_queue);
+ s5p_mfc_delete_queue(&ctx->ref_buf_queue);
+
+ s5p_mfc_mem_cleanup_user_shared_handle(ctx, &enc->sh_handle_svc);
+ s5p_mfc_mem_cleanup_user_shared_handle(ctx, &enc->sh_handle_roi);
+ s5p_mfc_release_enc_roi_buffer(ctx);
+ kfree(enc);
+}
+
+static int mfc_init_enc_ctx(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_enc *enc;
+ struct s5p_mfc_enc_params *p;
+ int ret = 0;
+ int i;
+
+ enc = kzalloc(sizeof(struct s5p_mfc_enc), GFP_KERNEL);
+ if (!enc) {
+ mfc_err_dev("failed to allocate encoder private data\n");
+ return -ENOMEM;
+ }
+ ctx->enc_priv = enc;
+
+ ctx->inst_no = MFC_NO_INSTANCE_SET;
+
+ s5p_mfc_create_queue(&ctx->src_buf_queue);
+ s5p_mfc_create_queue(&ctx->dst_buf_queue);
+ s5p_mfc_create_queue(&ctx->src_buf_nal_queue);
+ s5p_mfc_create_queue(&ctx->dst_buf_nal_queue);
+ s5p_mfc_create_queue(&ctx->ref_buf_queue);
+
+ for (i = 0; i < MFC_MAX_BUFFERS; i++) {
+ INIT_LIST_HEAD(&ctx->src_ctrls[i]);
+ INIT_LIST_HEAD(&ctx->dst_ctrls[i]);
+ }
+ ctx->src_ctrls_avail = 0;
+ ctx->dst_ctrls_avail = 0;
+
+ ctx->type = MFCINST_ENCODER;
+ ctx->c_ops = &encoder_ctrls_ops;
+ ctx->src_fmt = &enc_formats[DEF_ENC_SRC_FMT];
+ ctx->dst_fmt = &enc_formats[DEF_ENC_DST_FMT];
+
+ s5p_mfc_qos_reset_framerate(ctx);
+
+ ctx->qos_ratio = 100;
+
+ /* disable IVF header by default (VP8, VP9) */
+ p = &enc->params;
+ p->ivf_header_disable = 1;
+
+#ifdef CONFIG_MFC_USE_BUS_DEVFREQ
+ INIT_LIST_HEAD(&ctx->qos_list);
+#endif
+ INIT_LIST_HEAD(&ctx->ts_list);
+
+ enc->sh_handle_svc.fd = -1;
+ enc->sh_handle_roi.fd = -1;
+
+ /* Init videobuf2 queue for OUTPUT */
+ ctx->vq_src.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ ctx->vq_src.drv_priv = ctx;
+ ctx->vq_src.buf_struct_size = sizeof(struct s5p_mfc_buf);
+ ctx->vq_src.io_modes = VB2_USERPTR | VB2_DMABUF;
+ ctx->vq_src.ops = &s5p_mfc_enc_qops;
+ ctx->vq_src.mem_ops = s5p_mfc_mem_ops();
+ ctx->vq_src.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ ret = vb2_queue_init(&ctx->vq_src);
+ if (ret) {
+ mfc_err_dev("Failed to initialize videobuf2 queue(output)\n");
+ goto fail_enc_init;
+ }
+
+ /* Init videobuf2 queue for CAPTURE */
+ ctx->vq_dst.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ ctx->vq_dst.drv_priv = ctx;
+ ctx->vq_dst.buf_struct_size = sizeof(struct s5p_mfc_buf);
+ ctx->vq_dst.io_modes = VB2_USERPTR | VB2_DMABUF;
+ ctx->vq_dst.ops = &s5p_mfc_enc_qops;
+ ctx->vq_dst.mem_ops = s5p_mfc_mem_ops();
+ ctx->vq_dst.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ ret = vb2_queue_init(&ctx->vq_dst);
+ if (ret) {
+ mfc_err_dev("Failed to initialize videobuf2 queue(capture)\n");
+ goto fail_enc_init;
+ }
+
+ return 0;
+
+fail_enc_init:
+ mfc_deinit_enc_ctx(ctx);
+ return 0;
+}
+
+static int mfc_init_instance(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx)
+{
+ int ret = 0;
+
+ dev->watchdog_timer.expires = jiffies +
+ msecs_to_jiffies(WATCHDOG_TICK_INTERVAL);
+ add_timer(&dev->watchdog_timer);
+
+ /* Load the FW */
+ if (!dev->fw.status) {
+ ret = s5p_mfc_alloc_firmware(dev);
+ if (ret)
+ goto err_fw_alloc;
+ dev->fw.status = 1;
+ }
+
+ ret = s5p_mfc_load_firmware(dev);
+ if (ret)
+ goto err_fw_load;
+
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+ trace_mfc_dcpp_start(ctx->num, 1, dev->fw.drm_status);
+ if (!dev->drm_fw_buf.daddr) {
+ mfc_err_ctx("DRM F/W buffer is not allocated\n");
+ dev->fw.drm_status = 0;
+ } else {
+ /* Request buffer protection for DRM F/W */
+ ret = exynos_smc(SMC_DRM_PPMP_MFCFW_PROT,
+ dev->drm_fw_buf.daddr, 0, 0);
+ if (ret != DRMDRV_OK) {
+ mfc_err_ctx("failed MFC DRM F/W prot(%#x)\n", ret);
+ call_dop(dev, dump_and_stop_debug_mode, dev);
+ dev->fw.drm_status = 0;
+ } else {
+ dev->fw.drm_status = 1;
+ }
+ }
+#endif
+ trace_mfc_dcpp_end(ctx->num, 1, dev->fw.drm_status);
+
+ ret = s5p_mfc_alloc_common_context(dev);
+ if (ret)
+ goto err_context_alloc;
+
+ if (dbg_enable)
+ s5p_mfc_alloc_dbg_info_buffer(dev);
+
+ MFC_TRACE_DEV_HWLOCK("**open\n");
+ ret = s5p_mfc_get_hwlock_dev(dev);
+ if (ret < 0) {
+ mfc_err_dev("Failed to get hwlock\n");
+ mfc_err_dev("dev.hwlock.dev = 0x%lx, bits = 0x%lx, owned_by_irq = %d, wl_count = %d, transfer_owner = %d\n",
+ dev->hwlock.dev, dev->hwlock.bits, dev->hwlock.owned_by_irq,
+ dev->hwlock.wl_count, dev->hwlock.transfer_owner);
+ goto err_hw_lock;
+ }
+
+ mfc_debug(2, "power on\n");
+ ret = s5p_mfc_pm_power_on(dev);
+ if (ret < 0) {
+ mfc_err_ctx("power on failed\n");
+ goto err_pwr_enable;
+ }
+
+ dev->curr_ctx = ctx->num;
+ dev->preempt_ctx = MFC_NO_INSTANCE_SET;
+ dev->curr_ctx_is_drm = ctx->is_drm;
+
+ ret = s5p_mfc_init_hw(dev);
+ if (ret) {
+ mfc_err_ctx("Failed to init mfc h/w\n");
+ goto err_hw_init;
+ }
+
+ if (dev->has_mmcache && (dev->mmcache.is_on_status == 0))
+ s5p_mfc_mmcache_enable(dev);
+
+
+ s5p_mfc_release_hwlock_dev(dev);
+
+ if (MFC_FEATURE_SUPPORT(dev, dev->pdata->nal_q)) {
+ dev->nal_q_handle = s5p_mfc_nal_q_create(dev);
+ if (dev->nal_q_handle == NULL)
+ mfc_err_dev("[NALQ] Can't create nal q\n");
+ }
+
+ return ret;
+
+err_hw_init:
+ s5p_mfc_pm_power_off(dev);
+
+err_pwr_enable:
+ s5p_mfc_release_hwlock_dev(dev);
+
+err_hw_lock:
+ s5p_mfc_release_common_context(dev);
+
+err_context_alloc:
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+ if (dev->fw.drm_status) {
+ int smc_ret = 0;
+ dev->fw.drm_status = 0;
+ /* Request buffer unprotection for DRM F/W */
+ smc_ret = exynos_smc(SMC_DRM_PPMP_MFCFW_UNPROT,
+ dev->drm_fw_buf.daddr, 0, 0);
+ if (smc_ret != DRMDRV_OK) {
+ mfc_err_ctx("failed MFC DRM F/W unprot(%#x)\n", smc_ret);
+ call_dop(dev, dump_and_stop_debug_mode, dev);
+ }
+ }
+#endif
+
+err_fw_load:
+err_fw_alloc:
+ del_timer_sync(&dev->watchdog_timer);
+
+ mfc_err_dev("failed to init first instance\n");
+ return ret;
+}
+
+/* Open an MFC node */
+static int s5p_mfc_open(struct file *file)
+{
+ struct s5p_mfc_ctx *ctx = NULL;
+ struct s5p_mfc_dev *dev = video_drvdata(file);
+ int ret = 0;
+ enum s5p_mfc_node_type node;
+ struct video_device *vdev = NULL;
+
+ mfc_debug(2, "mfc driver open called\n");
+
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ goto err_no_device;
+ }
+
+ if (mutex_lock_interruptible(&dev->mfc_mutex))
+ return -ERESTARTSYS;
+
+ node = s5p_mfc_get_node_type(file);
+ if (node == MFCNODE_INVALID) {
+ mfc_err_dev("cannot specify node type\n");
+ ret = -ENOENT;
+ goto err_node_type;
+ }
+
+ dev->num_inst++; /* It is guarded by mfc_mutex in vfd */
+
+ /* Allocate memory for context */
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx) {
+ mfc_err_dev("Not enough memory\n");
+ ret = -ENOMEM;
+ goto err_ctx_alloc;
+ }
+
+ switch (node) {
+ case MFCNODE_DECODER:
+ vdev = dev->vfd_dec;
+ break;
+ case MFCNODE_ENCODER:
+ vdev = dev->vfd_enc;
+ break;
+ case MFCNODE_DECODER_DRM:
+ vdev = dev->vfd_dec_drm;
+ break;
+ case MFCNODE_ENCODER_DRM:
+ vdev = dev->vfd_enc_drm;
+ break;
+ case MFCNODE_ENCODER_OTF:
+ vdev = dev->vfd_enc_otf;
+ break;
+ case MFCNODE_ENCODER_OTF_DRM:
+ vdev = dev->vfd_enc_otf_drm;
+ break;
+ default:
+ mfc_err_dev("Invalid node(%d)\n", node);
+ break;
+ }
+
+ if (!vdev)
+ goto err_vdev;
+
+ v4l2_fh_init(&ctx->fh, vdev);
+ file->private_data = &ctx->fh;
+ v4l2_fh_add(&ctx->fh);
+
+ ctx->dev = dev;
+
+ /* Get context number */
+ ctx->num = 0;
+ while (dev->ctx[ctx->num]) {
+ ctx->num++;
+ if (ctx->num >= MFC_NUM_CONTEXTS) {
+ mfc_err_dev("Too many open contexts\n");
+ ret = -EBUSY;
+ goto err_ctx_num;
+ }
+ }
+
+ init_waitqueue_head(&ctx->cmd_wq);
+ s5p_mfc_init_listable_wq_ctx(ctx);
+ spin_lock_init(&ctx->buf_queue_lock);
+
+ if (s5p_mfc_is_decoder_node(node))
+ ret = mfc_init_dec_ctx(ctx);
+ else
+ ret = mfc_init_enc_ctx(ctx);
+ if (ret)
+ goto err_ctx_init;
+
+ ret = call_cop(ctx, init_ctx_ctrls, ctx);
+ if (ret) {
+ mfc_err_ctx("failed in init_ctx_ctrls\n");
+ goto err_ctx_ctrls;
+ }
+
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+ if (s5p_mfc_is_drm_node(node)) {
+ if (dev->num_drm_inst < MFC_MAX_DRM_CTX) {
+ if (ctx->raw_protect_flag || ctx->stream_protect_flag) {
+ mfc_err_ctx("protect_flag(%#lx/%#lx) remained\n",
+ ctx->raw_protect_flag,
+ ctx->stream_protect_flag);
+ ret = -EINVAL;
+ goto err_drm_start;
+ }
+ dev->num_drm_inst++;
+ ctx->is_drm = 1;
+
+ mfc_info_ctx("DRM instance is opened [%d:%d]\n",
+ dev->num_drm_inst, dev->num_inst);
+ } else {
+ mfc_err_ctx("Too many instance are opened for DRM\n");
+ ret = -EINVAL;
+ goto err_drm_start;
+ }
+ } else {
+ mfc_info_ctx("NORMAL instance is opened [%d:%d]\n",
+ dev->num_drm_inst, dev->num_inst);
+ }
+#endif
+
+ /* Mark context as idle */
+ s5p_mfc_clear_bit(ctx->num, &dev->work_bits);
+ dev->ctx[ctx->num] = ctx;
+
+ /* Load firmware if this is the first instance */
+ if (dev->num_inst == 1) {
+ ret = mfc_init_instance(dev, ctx);
+ if (ret)
+ goto err_init_inst;
+
+ if (perf_boost_mode)
+ s5p_mfc_perf_boost_enable(dev);
+ }
+
+#ifdef CONFIG_VIDEO_EXYNOS_REPEATER
+ if (s5p_mfc_is_encoder_otf_node(node)) {
+ ret = s5p_mfc_otf_create(ctx);
+ if (ret)
+ mfc_err_ctx("[OTF] otf_create failed\n");
+ }
+#endif
+
+ s5p_mfc_perf_init(dev);
+ trace_mfc_node_open(ctx->num, dev->num_inst, ctx->type, ctx->is_drm);
+ mfc_info_ctx("MFC open completed [%d:%d] dev = 0x%p, ctx = 0x%p, version = %d\n",
+ dev->num_drm_inst, dev->num_inst, dev, ctx, MFC_DRIVER_INFO);
+ mutex_unlock(&dev->mfc_mutex);
+ return ret;
+
+ /* Deinit when failure occured */
+err_init_inst:
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+ if (ctx->is_drm)
+ dev->num_drm_inst--;
+
+err_drm_start:
+#endif
+ call_cop(ctx, cleanup_ctx_ctrls, ctx);
+
+err_ctx_ctrls:
+err_ctx_init:
+ dev->ctx[ctx->num] = 0;
+
+err_ctx_num:
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+
+err_vdev:
+ kfree(ctx);
+
+err_ctx_alloc:
+ dev->num_inst--;
+
+err_node_type:
+ mfc_info_dev("MFC driver open is failed [%d:%d]\n",
+ dev->num_drm_inst, dev->num_inst);
+ mutex_unlock(&dev->mfc_mutex);
+
+err_no_device:
+
+ return ret;
+}
+
+static int mfc_wait_close_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx)
+{
+ if (atomic_read(&dev->watchdog_run)) {
+ mfc_err_ctx("watchdog already running!\n");
+ return 0;
+ }
+
+ if (ctx->inst_no == MFC_NO_INSTANCE_SET) {
+ mfc_debug(2, "mfc no instance already\n");
+ return 0;
+ }
+
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ s5p_mfc_change_state(ctx, MFCINST_RETURN_INST);
+ s5p_mfc_set_bit(ctx->num, &dev->work_bits);
+
+ /* To issue the command 'CLOSE_INSTANCE' */
+ if (s5p_mfc_just_run(dev, ctx->num)) {
+ mfc_err_ctx("Failed to run MFC\n");
+ return -EIO;
+ }
+
+ /* Wait until instance is returned or timeout occured */
+ if (s5p_mfc_wait_for_done_ctx(ctx,
+ S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET) == 1) {
+ mfc_err_ctx("Waiting for CLOSE_INSTANCE timed out\n");
+ if (s5p_mfc_wait_for_done_ctx(ctx,
+ S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET)) {
+ mfc_err_ctx("waiting once more but timed out\n");
+ dev->logging_data->cause |= (1 << MFC_CAUSE_FAIL_CLOSE_INST);
+ call_dop(dev, dump_and_stop_always, dev);
+ }
+ }
+
+ ctx->inst_no = MFC_NO_INSTANCE_SET;
+
+ return 0;
+}
+
+/* Release MFC context */
+static int s5p_mfc_release(struct file *file)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ struct s5p_mfc_dev *dev = NULL;
+ int ret = 0;
+
+ dev = ctx->dev;
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&dev->mfc_mutex);
+
+ mfc_info_ctx("MFC driver release is called [%d:%d], is_drm(%d)\n",
+ dev->num_drm_inst, dev->num_inst, ctx->is_drm);
+
+ s5p_mfc_clear_bit(ctx->num, &dev->work_bits);
+
+ /* If a H/W operation is in progress, wait for it complete */
+ if (need_to_wait_nal_abort(ctx)) {
+ if (s5p_mfc_wait_for_done_ctx(ctx, S5P_FIMV_R2H_CMD_NAL_ABORT_RET)) {
+ mfc_err_ctx("Failed to wait nal abort\n");
+ s5p_mfc_cleanup_work_bit_and_try_run(ctx);
+ }
+ }
+ MFC_TRACE_CTX_HWLOCK("**release\n");
+ ret = s5p_mfc_get_hwlock_ctx(ctx);
+ if (ret < 0) {
+ mfc_err_dev("Failed to get hwlock\n");
+ mutex_unlock(&dev->mfc_mutex);
+ return -EBUSY;
+ }
+
+ if (call_cop(ctx, cleanup_ctx_ctrls, ctx) < 0)
+ mfc_err_ctx("failed in cleanup_ctx_ctrl\n");
+
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+
+ /* Mark context as idle */
+ s5p_mfc_clear_bit(ctx->num, &dev->work_bits);
+
+ /* If instance was initialised then
+ * return instance and free reosurces */
+ ret = mfc_wait_close_inst(dev, ctx);
+ if (ret)
+ goto err_release_try;
+
+ if (ctx->is_drm)
+ dev->num_drm_inst--;
+ dev->num_inst--;
+
+ if (dev->num_inst == 0) {
+ s5p_mfc_deinit_hw(dev);
+
+ if (perf_boost_mode)
+ s5p_mfc_perf_boost_disable(dev);
+
+ del_timer_sync(&dev->watchdog_timer);
+
+ flush_workqueue(dev->butler_wq);
+
+ mfc_debug(2, "power off\n");
+ s5p_mfc_pm_power_off(dev);
+
+ if (dbg_enable)
+ s5p_mfc_release_dbg_info_buffer(dev);
+
+ s5p_mfc_release_common_context(dev);
+
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+ if (dev->fw.drm_status) {
+ dev->fw.drm_status = 0;
+ /* Request buffer unprotection for DRM F/W */
+ ret = exynos_smc(SMC_DRM_PPMP_MFCFW_UNPROT,
+ dev->drm_fw_buf.daddr, 0, 0);
+ if (ret != DRMDRV_OK) {
+ mfc_err_ctx("failed MFC DRM F/W unprot(%#x)\n", ret);
+ call_dop(dev, dump_and_stop_debug_mode, dev);
+ goto err_release;
+ }
+ }
+#endif
+
+ if (dev->nal_q_handle) {
+ ret = s5p_mfc_nal_q_destroy(dev, dev->nal_q_handle);
+ if (ret) {
+ mfc_err_ctx("failed nal_q destroy\n");
+ goto err_release;
+ }
+ }
+ }
+
+ s5p_mfc_qos_off(ctx);
+
+ if (dev->has_mmcache && dev->mmcache.is_on_status) {
+ s5p_mfc_invalidate_mmcache(dev);
+
+ if (dev->num_inst == 0)
+ s5p_mfc_mmcache_disable(dev);
+ }
+
+ s5p_mfc_release_codec_buffers(ctx);
+ s5p_mfc_release_instance_context(ctx);
+
+ s5p_mfc_release_hwlock_ctx(ctx);
+
+ /* Free resources */
+ vb2_queue_release(&ctx->vq_src);
+ vb2_queue_release(&ctx->vq_dst);
+
+ if (ctx->type == MFCINST_DECODER)
+ mfc_deinit_dec_ctx(ctx);
+ else if (ctx->type == MFCINST_ENCODER)
+ mfc_deinit_enc_ctx(ctx);
+
+#ifdef CONFIG_VIDEO_EXYNOS_REPEATER
+ if (ctx->otf_handle) {
+ s5p_mfc_otf_deinit(ctx);
+ s5p_mfc_otf_destroy(ctx);
+ }
+#endif
+
+ s5p_mfc_destroy_listable_wq_ctx(ctx);
+
+ trace_mfc_node_close(ctx->num, dev->num_inst, ctx->type, ctx->is_drm);
+
+ dev->ctx[ctx->num] = 0;
+ kfree(ctx);
+
+ s5p_mfc_perf_print();
+
+ mfc_info_dev("mfc driver release finished [%d:%d], dev = 0x%p\n",
+ dev->num_drm_inst, dev->num_inst, dev);
+
+ if (s5p_mfc_is_work_to_do(dev))
+ queue_work(dev->butler_wq, &dev->butler_work);
+
+ mutex_unlock(&dev->mfc_mutex);
+ return ret;
+
+err_release:
+ s5p_mfc_release_hwlock_ctx(ctx);
+ mutex_unlock(&dev->mfc_mutex);
+ return ret;
+
+err_release_try:
+ s5p_mfc_release_hwlock_ctx(ctx);
+ s5p_mfc_cleanup_work_bit_and_try_run(ctx);
+ mutex_unlock(&dev->mfc_mutex);
+ return ret;
+}
+
+/* Poll */
+static unsigned int s5p_mfc_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ unsigned long req_events = poll_requested_events(wait);
+ unsigned int ret = 0;
+
+ mfc_debug_enter();
+
+ if (req_events & (POLLOUT | POLLWRNORM)) {
+ mfc_debug(2, "wait source buffer\n");
+ ret = vb2_poll(&ctx->vq_src, file, wait);
+ } else if (req_events & (POLLIN | POLLRDNORM)) {
+ mfc_debug(2, "wait destination buffer\n");
+ ret = vb2_poll(&ctx->vq_dst, file, wait);
+ }
+
+ mfc_debug_leave();
+ return ret;
+}
+
+/* Mmap */
+static int s5p_mfc_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+ int ret;
+
+ mfc_debug_enter();
+
+ if (offset < DST_QUEUE_OFF_BASE) {
+ mfc_debug(2, "mmaping source\n");
+ ret = vb2_mmap(&ctx->vq_src, vma);
+ } else { /* capture */
+ mfc_debug(2, "mmaping destination\n");
+ vma->vm_pgoff -= (DST_QUEUE_OFF_BASE >> PAGE_SHIFT);
+ ret = vb2_mmap(&ctx->vq_dst, vma);
+ }
+ mfc_debug_leave();
+ return ret;
+}
+
+/* v4l2 ops */
+static const struct v4l2_file_operations s5p_mfc_fops = {
+ .owner = THIS_MODULE,
+ .open = s5p_mfc_open,
+ .release = s5p_mfc_release,
+ .poll = s5p_mfc_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = s5p_mfc_mmap,
+};
+
+#ifdef CONFIG_MFC_USE_BUS_DEVFREQ
+static int mfc_parse_mfc_qos_platdata(struct device_node *np, char *node_name,
+ struct s5p_mfc_qos *qosdata)
+{
+ int ret = 0;
+ struct device_node *np_qos;
+
+ np_qos = of_find_node_by_name(np, node_name);
+ if (!np_qos) {
+ pr_err("%s: could not find mfc_qos_platdata node\n",
+ node_name);
+ return -EINVAL;
+ }
+
+ of_property_read_u32(np_qos, "thrd_mb", &qosdata->threshold_mb);
+ of_property_read_u32(np_qos, "freq_mfc", &qosdata->freq_mfc);
+ of_property_read_u32(np_qos, "freq_int", &qosdata->freq_int);
+ of_property_read_u32(np_qos, "freq_mif", &qosdata->freq_mif);
+ of_property_read_u32(np_qos, "mo_value", &qosdata->mo_value);
+ of_property_read_u32(np_qos, "mo_10bit_value", &qosdata->mo_10bit_value);
+ of_property_read_u32(np_qos, "mo_uhd_enc60_value", &qosdata->mo_uhd_enc60_value);
+ of_property_read_u32(np_qos, "time_fw", &qosdata->time_fw);
+
+ return ret;
+}
+#endif
+
+int s5p_mfc_sysmmu_fault_handler(struct iommu_domain *iodmn, struct device *device,
+ unsigned long addr, int id, void *param)
+{
+ struct s5p_mfc_dev *dev;
+
+ dev = (struct s5p_mfc_dev *)param;
+
+ /* [OTF] If AxID is 1 in SYSMMU1 fault info, it is TS-MUX fault */
+ if (dev->has_hwfc && dev->has_2sysmmu) {
+ if (MFC_MMU1_READL(MFC_MMU_INTERRUPT_STATUS) &&
+ ((MFC_MMU1_READL(MFC_MMU_FAULT_TRANS_INFO) &
+ MFC_MMU_FAULT_TRANS_INFO_AXID_MASK) == 1)) {
+ mfc_err_dev("There is TS-MUX page fault. skip SFR dump\n");
+ return 0;
+ }
+ }
+
+ /* If sysmmu is used with other IPs, it should be checked whether it's an MFC fault */
+ if (dev->pdata->share_sysmmu) {
+ if ((MFC_MMU0_READL(MFC_MMU_FAULT_TRANS_INFO) & dev->pdata->axid_mask)
+ != dev->pdata->mfc_fault_num) {
+ mfc_err_dev("This is not a MFC page fault\n");
+ return 0;
+ }
+ }
+
+ if (MFC_MMU0_READL(MFC_MMU_INTERRUPT_STATUS)) {
+ if (MFC_MMU0_READL(MFC_MMU_FAULT_TRANS_INFO) & MFC_MMU_FAULT_TRANS_INFO_RW_MASK)
+ dev->logging_data->cause |= (1 << MFC_CAUSE_0WRITE_PAGE_FAULT);
+ else
+ dev->logging_data->cause |= (1 << MFC_CAUSE_0READ_PAGE_FAULT);
+ dev->logging_data->fault_status = MFC_MMU0_READL(MFC_MMU_INTERRUPT_STATUS);
+ dev->logging_data->fault_trans_info = MFC_MMU0_READL(MFC_MMU_FAULT_TRANS_INFO);
+ }
+
+ if (dev->has_2sysmmu) {
+ if (MFC_MMU1_READL(MFC_MMU_INTERRUPT_STATUS)) {
+ if (MFC_MMU1_READL(MFC_MMU_FAULT_TRANS_INFO) & MFC_MMU_FAULT_TRANS_INFO_RW_MASK)
+ dev->logging_data->cause |= (1 << MFC_CAUSE_1WRITE_PAGE_FAULT);
+ else
+ dev->logging_data->cause |= (1 << MFC_CAUSE_1READ_PAGE_FAULT);
+ dev->logging_data->fault_status = MFC_MMU1_READL(MFC_MMU_INTERRUPT_STATUS);
+ dev->logging_data->fault_trans_info = MFC_MMU1_READL(MFC_MMU_FAULT_TRANS_INFO);
+ }
+ }
+ dev->logging_data->fault_addr = (unsigned int)addr;
+
+ call_dop(dev, dump_info, dev);
+
+ return 0;
+}
+
+static void mfc_parse_dt(struct device_node *np, struct s5p_mfc_dev *mfc)
+{
+ struct s5p_mfc_platdata *pdata = mfc->pdata;
+#ifdef CONFIG_MFC_USE_BUS_DEVFREQ
+ struct device_node *np_qos;
+ char node_name[50];
+ int i;
+#endif
+
+ if (!np)
+ return;
+
+ /* MFC version */
+ of_property_read_u32(np, "ip_ver", &pdata->ip_ver);
+
+ /* Debug mode */
+ of_property_read_u32(np, "debug_mode", &pdata->debug_mode);
+
+ /* Sysmmu check */
+ of_property_read_u32(np, "share_sysmmu", &pdata->share_sysmmu);
+ of_property_read_u32(np, "axid_mask", &pdata->axid_mask);
+ of_property_read_u32(np, "mfc_fault_num", &pdata->mfc_fault_num);
+
+ /* Features */
+ of_property_read_u32_array(np, "nal_q", &pdata->nal_q.support, 2);
+ of_property_read_u32_array(np, "skype", &pdata->skype.support, 2);
+ of_property_read_u32_array(np, "black_bar", &pdata->black_bar.support, 2);
+ of_property_read_u32_array(np, "color_aspect_dec", &pdata->color_aspect_dec.support, 2);
+ of_property_read_u32_array(np, "static_info_dec", &pdata->static_info_dec.support, 2);
+ of_property_read_u32_array(np, "color_aspect_enc", &pdata->color_aspect_enc.support, 2);
+ of_property_read_u32_array(np, "static_info_enc", &pdata->static_info_enc.support, 2);
+
+ /* Default 10bit format for decoding */
+ of_property_read_u32(np, "P010_decoding", &pdata->P010_decoding);
+
+ /* Formats */
+ of_property_read_u32(np, "support_10bit", &pdata->support_10bit);
+ of_property_read_u32(np, "support_422", &pdata->support_422);
+ of_property_read_u32(np, "support_rgb", &pdata->support_rgb);
+
+ /* Encoder default parameter */
+ of_property_read_u32(np, "enc_param_num", &pdata->enc_param_num);
+ if (pdata->enc_param_num) {
+ of_property_read_u32_array(np, "enc_param_addr",
+ pdata->enc_param_addr, pdata->enc_param_num);
+ of_property_read_u32_array(np, "enc_param_val",
+ pdata->enc_param_val, pdata->enc_param_num);
+ }
+
+#ifdef CONFIG_MFC_USE_BUS_DEVFREQ
+ /* QoS */
+ of_property_read_u32(np, "num_qos_steps", &pdata->num_qos_steps);
+ of_property_read_u32(np, "max_qos_steps", &pdata->max_qos_steps);
+ of_property_read_u32(np, "max_mb", &pdata->max_mb);
+ of_property_read_u32(np, "mfc_freq_control", &pdata->mfc_freq_control);
+ of_property_read_u32(np, "mo_control", &pdata->mo_control);
+ of_property_read_u32(np, "bw_control", &pdata->bw_control);
+
+ pdata->qos_table = devm_kzalloc(mfc->device,
+ sizeof(struct s5p_mfc_qos) * pdata->max_qos_steps, GFP_KERNEL);
+
+ for (i = 0; i < pdata->max_qos_steps; i++) {
+ snprintf(node_name, sizeof(node_name), "mfc_qos_variant_%d", i);
+ mfc_parse_mfc_qos_platdata(np, node_name, &pdata->qos_table[i]);
+ }
+
+ /* performance boost mode */
+ pdata->qos_boost_table = devm_kzalloc(mfc->device,
+ sizeof(struct s5p_mfc_qos_boost), GFP_KERNEL);
+ np_qos = of_find_node_by_name(np, "mfc_perf_boost_table");
+ if (!np_qos) {
+ pr_err("%s:[QoS] could not find mfc_perf_boost_table node\n", node_name);
+ return;
+ }
+ of_property_read_u32(np_qos, "num_cluster", &pdata->qos_boost_table->num_cluster);
+ of_property_read_u32(np_qos, "freq_mfc", &pdata->qos_boost_table->freq_mfc);
+ of_property_read_u32(np_qos, "freq_int", &pdata->qos_boost_table->freq_int);
+ of_property_read_u32(np_qos, "freq_mif", &pdata->qos_boost_table->freq_mif);
+ of_property_read_u32_array(np_qos, "freq_cluster", &pdata->qos_boost_table->freq_cluster[0],
+ pdata->qos_boost_table->num_cluster);
+#endif
+}
+
+static void *mfc_get_drv_data(struct platform_device *pdev);
+
+static struct video_device *mfc_video_device_register(struct s5p_mfc_dev *dev,
+ char *name, int node_num)
+{
+ struct video_device *vfd;
+ int ret = 0;
+
+ vfd = video_device_alloc();
+ if (!vfd) {
+ v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n");
+ return NULL;
+ }
+ strncpy(vfd->name, name, sizeof(vfd->name) - 1);
+ vfd->fops = &s5p_mfc_fops;
+ vfd->minor = -1;
+ vfd->release = video_device_release;
+
+ if (IS_DEC_NODE(node_num))
+ vfd->ioctl_ops = s5p_mfc_get_dec_v4l2_ioctl_ops();
+ else if(IS_ENC_NODE(node_num))
+ vfd->ioctl_ops = s5p_mfc_get_enc_v4l2_ioctl_ops();
+
+ vfd->lock = &dev->mfc_mutex;
+ vfd->v4l2_dev = &dev->v4l2_dev;
+ vfd->vfl_dir = VFL_DIR_M2M;
+
+ snprintf(vfd->name, sizeof(vfd->name), "%s%d", vfd->name, dev->id);
+
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER, node_num + 60 * dev->id);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev, "Failed to register video device /dev/video%d\n", node_num);
+ video_device_release(vfd);
+ return NULL;
+ }
+ v4l2_info(&dev->v4l2_dev, "video device registered as /dev/video%d\n",
+ vfd->num);
+ video_set_drvdata(vfd, dev);
+
+ return vfd;
+}
+
+static int mfc_register_resource(struct platform_device *pdev, struct s5p_mfc_dev *dev)
+{
+ struct device_node *np = dev->device->of_node;
+ struct device_node *iommu;
+ struct device_node *hwfc;
+ struct device_node *mmcache;
+ struct resource *res;
+ int ret;
+
+ s5p_mfc_perf_register(dev);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "failed to get memory region resource\n");
+ return -ENOENT;
+ }
+ dev->mfc_mem = request_mem_region(res->start, resource_size(res), pdev->name);
+ if (dev->mfc_mem == NULL) {
+ dev_err(&pdev->dev, "failed to get memory region\n");
+ return -ENOENT;
+ }
+ dev->regs_base = ioremap(dev->mfc_mem->start, resource_size(dev->mfc_mem));
+ if (dev->regs_base == NULL) {
+ dev_err(&pdev->dev, "failed to ioremap address region\n");
+ goto err_ioremap;
+ }
+
+ iommu = of_get_child_by_name(np, "iommu");
+ if (!iommu) {
+ dev_err(&pdev->dev, "failed to get iommu node\n");
+ goto err_ioremap_mmu0;
+ }
+
+ dev->sysmmu0_base = of_iomap(iommu, 0);
+ if (dev->sysmmu0_base == NULL) {
+ dev_err(&pdev->dev, "failed to ioremap sysmmu0 address region\n");
+ goto err_ioremap_mmu0;
+ }
+
+ dev->sysmmu1_base = of_iomap(iommu, 1);
+ if (dev->sysmmu1_base == NULL) {
+ pr_debug("there is only one MFC sysmmu\n");
+ } else {
+ dev->has_2sysmmu = 1;
+ }
+
+ hwfc = of_get_child_by_name(np, "hwfc");
+ if (hwfc) {
+ dev->hwfc_base = of_iomap(hwfc, 0);
+ if (dev->hwfc_base == NULL) {
+ dev->has_hwfc = 0;
+ dev_err(&pdev->dev, "failed to iomap hwfc address region\n");
+ goto err_ioremap_hwfc;
+ } else {
+ dev->has_hwfc = 1;
+ }
+ }
+
+ mmcache = of_get_child_by_name(np, "mmcache");
+ if (mmcache) {
+ dev->mmcache.base = of_iomap(mmcache, 0);
+ if (dev->mmcache.base == NULL) {
+ dev->has_mmcache = 0;
+ dev_err(&pdev->dev, "failed to iomap mmcache address region\n");
+ goto err_ioremap_mmcache;
+ } else {
+ dev->has_mmcache = 1;
+ }
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "failed to get irq resource\n");
+ goto err_res_irq;
+ }
+ dev->irq = res->start;
+ ret = request_threaded_irq(dev->irq, s5p_mfc_top_half_irq, s5p_mfc_irq,
+ IRQF_ONESHOT, pdev->name, dev);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "failed to install irq (%d)\n", ret);
+ goto err_res_irq;
+ }
+
+ return 0;
+
+err_res_irq:
+ if (dev->has_mmcache)
+ iounmap(dev->mmcache.base);
+err_ioremap_mmcache:
+ if (dev->has_hwfc)
+ iounmap(dev->hwfc_base);
+err_ioremap_hwfc:
+ if (dev->has_2sysmmu)
+ iounmap(dev->sysmmu1_base);
+ iounmap(dev->sysmmu0_base);
+err_ioremap_mmu0:
+ iounmap(dev->regs_base);
+err_ioremap:
+ release_mem_region(dev->mfc_mem->start, resource_size(dev->mfc_mem));
+ return -ENOENT;
+}
+
+#ifdef CONFIG_EXYNOS_ITMON
+static int mfc_itmon_notifier(struct notifier_block *nb, unsigned long action, void *nb_data)
+{
+ struct s5p_mfc_dev *dev;
+ struct itmon_notifier *itmon_info = nb_data;
+ int is_mfc_itmon = 0, is_master = 0;
+
+ dev = container_of(nb, struct s5p_mfc_dev, itmon_nb);
+
+ if (IS_ERR_OR_NULL(itmon_info))
+ return NOTIFY_DONE;
+
+ if (!itmon_info->master)
+ return NOTIFY_DONE;
+
+ /* print dump if it is an MFC ITMON error */
+ if ((strncmp("MFC", itmon_info->port, sizeof("MFC") - 1) == 0) &&
+ (strncmp("MFC", itmon_info->master, sizeof("MFC") - 1) == 0)) {
+ is_mfc_itmon = 1;
+ is_master = 1;
+ } else if (strncmp("MFC", itmon_info->dest, sizeof("MFC") - 1) == 0) {
+ is_mfc_itmon = 1;
+ is_master = 0;
+ }
+
+ if (is_mfc_itmon) {
+ pr_err("mfc_itmon_notifier: MFC +\n");
+ pr_err("MFC is %s\n", is_master ? "master" : "dest");
+ if (!dev->itmon_notified) {
+ pr_err("dump MFC information\n");
+ if (is_master || (!is_master && itmon_info->onoff))
+ call_dop(dev, dump_info, dev);
+ else
+ call_dop(dev, dump_info_without_regs, dev);
+ } else {
+ pr_err("MFC notifier has already been called. skip MFC information\n");
+ }
+ pr_err("mfc_itmon_notifier: MFC -\n");
+ dev->itmon_notified = 1;
+ }
+ return NOTIFY_DONE;
+}
+#endif
+
+/* MFC probe function */
+static int s5p_mfc_probe(struct platform_device *pdev)
+{
+ struct s5p_mfc_dev *dev;
+ int ret = -ENOENT;
+#ifdef CONFIG_MFC_USE_BUS_DEVFREQ
+ int i;
+#endif
+
+ dev_dbg(&pdev->dev, "%s()\n", __func__);
+ dev = devm_kzalloc(&pdev->dev, sizeof(struct s5p_mfc_dev), GFP_KERNEL);
+ if (!dev) {
+ dev_err(&pdev->dev, "Not enough memory for MFC device\n");
+ return -ENOMEM;
+ }
+
+ dev->device = &pdev->dev;
+ dev->pdata = pdev->dev.platform_data;
+
+ dev->variant = mfc_get_drv_data(pdev);
+
+ if (dev->device->of_node)
+ dev->id = of_alias_get_id(pdev->dev.of_node, "mfc");
+
+ dev_dbg(&pdev->dev, "of alias get id : mfc-%d \n", dev->id);
+
+ if (dev->id < 0 || dev->id >= dev->variant->num_entities) {
+ dev_err(&pdev->dev, "Invalid platform device id: %d\n", dev->id);
+ ret = -EINVAL;
+ goto err_pm;
+ }
+
+ dev->pdata = devm_kzalloc(&pdev->dev, sizeof(struct s5p_mfc_platdata), GFP_KERNEL);
+ if (!dev->pdata) {
+ dev_err(&pdev->dev, "no memory for state\n");
+ ret = -ENOMEM;
+ goto err_pm;
+ }
+
+ mfc_parse_dt(dev->device->of_node, dev);
+
+ atomic_set(&dev->trace_ref, 0);
+ atomic_set(&dev->trace_ref_hwlock, 0);
+ dev->mfc_trace = g_mfc_trace;
+ dev->mfc_trace_hwlock = g_mfc_trace_hwlock;
+
+ dma_set_mask(&pdev->dev, DMA_BIT_MASK(36));
+
+ s5p_mfc_pm_init(dev);
+ ret = mfc_register_resource(pdev, dev);
+ if (ret)
+ goto err_res_mem;
+
+ mutex_init(&dev->mfc_mutex);
+
+ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+ if (ret)
+ goto err_v4l2_dev;
+
+ init_waitqueue_head(&dev->cmd_wq);
+ s5p_mfc_init_listable_wq_dev(dev);
+
+ /* decoder */
+ dev->vfd_dec = mfc_video_device_register(dev, S5P_MFC_DEC_NAME,
+ EXYNOS_VIDEONODE_MFC_DEC);
+ if (!dev->vfd_dec) {
+ ret = -ENOMEM;
+ goto alloc_vdev_dec;
+ }
+
+ /* encoder */
+ dev->vfd_enc = mfc_video_device_register(dev, S5P_MFC_ENC_NAME,
+ EXYNOS_VIDEONODE_MFC_ENC);
+ if (!dev->vfd_enc) {
+ ret = -ENOMEM;
+ goto alloc_vdev_enc;
+ }
+
+ /* secure decoder */
+ dev->vfd_dec_drm = mfc_video_device_register(dev, S5P_MFC_DEC_DRM_NAME,
+ EXYNOS_VIDEONODE_MFC_DEC_DRM);
+ if (!dev->vfd_dec_drm) {
+ ret = -ENOMEM;
+ goto alloc_vdev_dec_drm;
+ }
+
+ /* secure encoder */
+ dev->vfd_enc_drm = mfc_video_device_register(dev, S5P_MFC_ENC_DRM_NAME,
+ EXYNOS_VIDEONODE_MFC_ENC_DRM);
+ if (!dev->vfd_enc_drm) {
+ ret = -ENOMEM;
+ goto alloc_vdev_enc_drm;
+ }
+
+ /* OTF encoder */
+ dev->vfd_enc_otf = mfc_video_device_register(dev, S5P_MFC_ENC_OTF_NAME,
+ EXYNOS_VIDEONODE_MFC_ENC_OTF);
+ if (!dev->vfd_enc_otf) {
+ ret = -ENOMEM;
+ goto alloc_vdev_enc_otf;
+ }
+
+ /* OTF secure encoder */
+ dev->vfd_enc_otf_drm = mfc_video_device_register(dev, S5P_MFC_ENC_OTF_DRM_NAME,
+ EXYNOS_VIDEONODE_MFC_ENC_OTF_DRM);
+ if (!dev->vfd_enc_otf_drm) {
+ ret = -ENOMEM;
+ goto alloc_vdev_enc_otf_drm;
+ }
+ /* end of node setting*/
+
+ platform_set_drvdata(pdev, dev);
+
+ s5p_mfc_init_hwlock(dev);
+ s5p_mfc_create_bits(&dev->work_bits);
+
+ dev->watchdog_wq =
+ create_singlethread_workqueue("s5p_mfc/watchdog");
+ if (!dev->watchdog_wq) {
+ dev_err(&pdev->dev, "failed to create workqueue for watchdog\n");
+ goto err_wq_watchdog;
+ }
+ INIT_WORK(&dev->watchdog_work, s5p_mfc_watchdog_worker);
+ atomic_set(&dev->watchdog_tick_running, 0);
+ atomic_set(&dev->watchdog_tick_cnt, 0);
+ atomic_set(&dev->watchdog_run, 0);
+ init_timer(&dev->watchdog_timer);
+ dev->watchdog_timer.data = (unsigned long)dev;
+ dev->watchdog_timer.function = s5p_mfc_watchdog_tick;
+
+#ifdef CONFIG_MFC_USE_BUS_DEVFREQ
+ INIT_LIST_HEAD(&dev->qos_queue);
+#endif
+
+ /* default FW alloc is added */
+ dev->butler_wq = alloc_workqueue("s5p_mfc/butler", WQ_UNBOUND
+ | WQ_MEM_RECLAIM | WQ_HIGHPRI, 1);
+ if (dev->butler_wq == NULL) {
+ dev_err(&pdev->dev, "failed to create workqueue for butler\n");
+ goto err_butler_wq;
+ }
+ INIT_WORK(&dev->butler_work, s5p_mfc_butler_worker);
+
+ /* dump information call-back function */
+ dev->dump_ops = &mfc_dump_ops;
+
+#ifdef CONFIG_MFC_USE_BUS_DEVFREQ
+ atomic_set(&dev->qos_req_cur, 0);
+
+ mfc_info_dev("[QoS] control: mfc_freq(%d), mo(%d), bw(%d)\n",
+ dev->pdata->mfc_freq_control, dev->pdata->mo_control, dev->pdata->bw_control);
+ for (i = 0; i < dev->pdata->num_qos_steps; i++) {
+ mfc_info_dev("[QoS] table[%d] mfc: %d, int : %d, mif : %d\n",
+ i,
+ dev->pdata->qos_table[i].freq_mfc,
+ dev->pdata->qos_table[i].freq_int,
+ dev->pdata->qos_table[i].freq_mif);
+ }
+#endif
+
+ iovmm_set_fault_handler(dev->device,
+ s5p_mfc_sysmmu_fault_handler, dev);
+
+ g_mfc_dev = dev;
+
+ ret = iovmm_activate(&pdev->dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to activate iommu\n");
+ goto err_iovmm_active;
+ }
+
+ dev->logging_data = devm_kzalloc(&pdev->dev, sizeof(struct s5p_mfc_debug), GFP_KERNEL);
+ if (!dev->logging_data) {
+ dev_err(&pdev->dev, "no memory for logging data\n");
+ ret = -ENOMEM;
+ goto err_alloc_debug;
+ }
+
+#ifdef CONFIG_EXYNOS_ITMON
+ dev->itmon_nb.notifier_call = mfc_itmon_notifier;
+ itmon_notifier_chain_register(&dev->itmon_nb);
+#endif
+
+ s5p_mfc_init_debugfs(dev);
+
+ pr_debug("%s--\n", __func__);
+ return 0;
+
+/* Deinit MFC if probe had failed */
+err_alloc_debug:
+ iovmm_deactivate(&pdev->dev);
+err_iovmm_active:
+ destroy_workqueue(dev->butler_wq);
+err_butler_wq:
+ destroy_workqueue(dev->watchdog_wq);
+err_wq_watchdog:
+ video_unregister_device(dev->vfd_enc_otf_drm);
+alloc_vdev_enc_otf_drm:
+ video_unregister_device(dev->vfd_enc_otf);
+alloc_vdev_enc_otf:
+ video_unregister_device(dev->vfd_enc_drm);
+alloc_vdev_enc_drm:
+ video_unregister_device(dev->vfd_dec_drm);
+alloc_vdev_dec_drm:
+ video_unregister_device(dev->vfd_enc);
+alloc_vdev_enc:
+ video_unregister_device(dev->vfd_dec);
+alloc_vdev_dec:
+ v4l2_device_unregister(&dev->v4l2_dev);
+err_v4l2_dev:
+ mutex_destroy(&dev->mfc_mutex);
+ free_irq(dev->irq, dev);
+ if (dev->has_mmcache)
+ iounmap(dev->mmcache.base);
+ if (dev->has_hwfc)
+ iounmap(dev->hwfc_base);
+ if (dev->has_2sysmmu)
+ iounmap(dev->sysmmu1_base);
+ iounmap(dev->sysmmu0_base);
+ iounmap(dev->regs_base);
+ release_mem_region(dev->mfc_mem->start, resource_size(dev->mfc_mem));
+err_res_mem:
+ s5p_mfc_pm_final(dev);
+err_pm:
+ return ret;
+}
+
+/* Remove the driver */
+static int s5p_mfc_remove(struct platform_device *pdev)
+{
+ struct s5p_mfc_dev *dev = platform_get_drvdata(pdev);
+
+ dev_dbg(&pdev->dev, "%s++\n", __func__);
+ v4l2_info(&dev->v4l2_dev, "Removing %s\n", pdev->name);
+ del_timer_sync(&dev->watchdog_timer);
+ flush_workqueue(dev->watchdog_wq);
+ destroy_workqueue(dev->watchdog_wq);
+ flush_workqueue(dev->butler_wq);
+ destroy_workqueue(dev->butler_wq);
+ video_unregister_device(dev->vfd_enc);
+ video_unregister_device(dev->vfd_dec);
+ video_unregister_device(dev->vfd_enc_otf);
+ video_unregister_device(dev->vfd_enc_otf_drm);
+ v4l2_device_unregister(&dev->v4l2_dev);
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+ remove_proc_entry(MFC_PROC_FW_STATUS, mfc_proc_entry);
+ remove_proc_entry(MFC_PROC_DRM_INSTANCE_NUMBER, mfc_proc_entry);
+ remove_proc_entry(MFC_PROC_INSTANCE_NUMBER, mfc_proc_entry);
+ remove_proc_entry(MFC_PROC_ROOT, NULL);
+#endif
+ s5p_mfc_destroy_listable_wq_dev(dev);
+ iovmm_deactivate(&pdev->dev);
+ mfc_debug(2, "Will now deinit HW\n");
+ s5p_mfc_deinit_hw(dev);
+ free_irq(dev->irq, dev);
+ if (dev->has_mmcache)
+ iounmap(dev->mmcache.base);
+ if (dev->has_hwfc)
+ iounmap(dev->hwfc_base);
+ if (dev->has_2sysmmu)
+ iounmap(dev->sysmmu1_base);
+ iounmap(dev->sysmmu0_base);
+ iounmap(dev->regs_base);
+ release_mem_region(dev->mfc_mem->start, resource_size(dev->mfc_mem));
+ s5p_mfc_pm_final(dev);
+ kfree(dev);
+ dev_dbg(&pdev->dev, "%s--\n", __func__);
+ return 0;
+}
+
+static void s5p_mfc_shutdown(struct platform_device *pdev)
+{
+ struct s5p_mfc_dev *dev = platform_get_drvdata(pdev);
+ int ret;
+
+ mfc_info_dev("MFC shutdown is called\n");
+ MFC_TRACE_DEV_HWLOCK("**shutdown \n");
+
+ if (!s5p_mfc_pm_get_pwr_ref_cnt(dev)) {
+ dev->shutdown = 1;
+ mfc_info_dev("MFC is not running\n");
+ return;
+ }
+
+ ret = s5p_mfc_get_hwlock_dev(dev);
+ if (ret < 0)
+ mfc_err_dev("Failed to get hwlock\n");
+
+ if (!dev->shutdown) {
+ s5p_mfc_risc_off(dev);
+ dev->shutdown = 1;
+ s5p_mfc_clear_all_bits(&dev->work_bits);
+ iovmm_deactivate(&pdev->dev);
+ }
+ s5p_mfc_release_hwlock_dev(dev);
+ mfc_info_dev("MFC shutdown completed\n");
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int s5p_mfc_suspend(struct device *dev)
+{
+ struct s5p_mfc_dev *m_dev = platform_get_drvdata(to_platform_device(dev));
+ int ret;
+
+ if (!m_dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ if (m_dev->num_inst == 0)
+ return 0;
+
+ ret = s5p_mfc_sleep(m_dev);
+
+ return ret;
+}
+
+static int s5p_mfc_resume(struct device *dev)
+{
+ struct s5p_mfc_dev *m_dev = platform_get_drvdata(to_platform_device(dev));
+ int ret;
+
+ if (!m_dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ if (m_dev->num_inst == 0)
+ return 0;
+
+ ret = s5p_mfc_wakeup(m_dev);
+
+ return ret;
+}
+#endif
+
+#ifdef CONFIG_PM
+static int s5p_mfc_runtime_suspend(struct device *dev)
+{
+ mfc_debug(3, "mfc runtime suspend\n");
+
+ return 0;
+}
+
+static int s5p_mfc_runtime_idle(struct device *dev)
+{
+ return 0;
+}
+
+static int s5p_mfc_runtime_resume(struct device *dev)
+{
+ mfc_debug(3, "mfc runtime resume\n");
+
+ return 0;
+}
+#endif
+
+/* Power management */
+static const struct dev_pm_ops s5p_mfc_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(s5p_mfc_suspend, s5p_mfc_resume)
+ SET_RUNTIME_PM_OPS(
+ s5p_mfc_runtime_suspend,
+ s5p_mfc_runtime_resume,
+ s5p_mfc_runtime_idle
+ )
+};
+
+struct s5p_mfc_ctx_buf_size mfc_ctx_buf_size = {
+ .dev_ctx = PAGE_ALIGN(0x7800), /* 30KB */
+ .h264_dec_ctx = PAGE_ALIGN(0x200000), /* 1.6MB */
+ .other_dec_ctx = PAGE_ALIGN(0x7800), /* 30KB */
+ .h264_enc_ctx = PAGE_ALIGN(0x19000), /* 100KB */
+ .hevc_enc_ctx = PAGE_ALIGN(0xA000), /* 40KB */
+ .other_enc_ctx = PAGE_ALIGN(0x6400), /* 25KB */
+ .shared_buf = PAGE_ALIGN(0x2000), /* 8KB */
+ .dbg_info_buf = PAGE_ALIGN(0x1000), /* 4KB for DEBUG INFO */
+};
+
+struct s5p_mfc_buf_size mfc_buf_size = {
+ .firmware_code = PAGE_ALIGN(0x100000), /* 1MB */
+ .cpb_buf = PAGE_ALIGN(0x300000), /* 3MB */
+ .ctx_buf = &mfc_ctx_buf_size,
+};
+
+static struct s5p_mfc_variant mfc_drvdata = {
+ .buf_size = &mfc_buf_size,
+ .num_entities = 2,
+};
+
+static const struct of_device_id exynos_mfc_match[] = {
+ {
+ .compatible = "samsung,exynos-mfc",
+ .data = &mfc_drvdata,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, exynos_mfc_match);
+
+static void *mfc_get_drv_data(struct platform_device *pdev)
+{
+ struct s5p_mfc_variant *driver_data = NULL;
+
+ if (pdev->dev.of_node) {
+ const struct of_device_id *match;
+ match = of_match_node(of_match_ptr(exynos_mfc_match),
+ pdev->dev.of_node);
+ if (match)
+ driver_data = (struct s5p_mfc_variant *)match->data;
+ } else {
+ driver_data = (struct s5p_mfc_variant *)
+ platform_get_device_id(pdev)->driver_data;
+ }
+ return driver_data;
+}
+
+static struct platform_driver s5p_mfc_driver = {
+ .probe = s5p_mfc_probe,
+ .remove = s5p_mfc_remove,
+ .shutdown = s5p_mfc_shutdown,
+ .driver = {
+ .name = S5P_MFC_NAME,
+ .owner = THIS_MODULE,
+ .pm = &s5p_mfc_pm_ops,
+ .of_match_table = exynos_mfc_match,
+ .suppress_bind_attrs = true,
+ },
+};
+
+module_platform_driver(s5p_mfc_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>");
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_buf.c
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/smc.h>
+#include <linux/firmware.h>
+#include <trace/events/mfc.h>
+
+#include "mfc_buf.h"
+
+#include "mfc_mem.h"
+
+static int mfc_alloc_common_context(struct s5p_mfc_dev *dev,
+ enum mfc_buf_usage_type buf_type)
+{
+ struct s5p_mfc_special_buf *ctx_buf;
+ int firmware_size;
+ unsigned long fw_daddr;
+
+ mfc_debug_enter();
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ ctx_buf = &dev->common_ctx_buf;
+ fw_daddr = dev->fw_buf.daddr;
+
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+ if (buf_type == MFCBUF_DRM) {
+ ctx_buf = &dev->drm_common_ctx_buf;
+ fw_daddr = dev->drm_fw_buf.daddr;
+ }
+#endif
+
+ firmware_size = dev->variant->buf_size->firmware_code;
+
+ ctx_buf->dma_buf = NULL;
+ ctx_buf->vaddr = NULL;
+ ctx_buf->daddr = fw_daddr + firmware_size;
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+/* Wrapper : allocate context buffers for SYS_INIT */
+int s5p_mfc_alloc_common_context(struct s5p_mfc_dev *dev)
+{
+ int ret = 0;
+
+ ret = mfc_alloc_common_context(dev, MFCBUF_NORMAL);
+ if (ret)
+ return ret;
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+ if (dev->fw.drm_status) {
+ ret = mfc_alloc_common_context(dev, MFCBUF_DRM);
+ if (ret)
+ return ret;
+ }
+#endif
+
+ return ret;
+}
+
+/* Release context buffers for SYS_INIT */
+static void mfc_release_common_context(struct s5p_mfc_dev *dev,
+ enum mfc_buf_usage_type buf_type)
+{
+ struct s5p_mfc_special_buf *ctx_buf;
+
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return;
+ }
+
+ ctx_buf = &dev->common_ctx_buf;
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+ if (buf_type == MFCBUF_DRM)
+ ctx_buf = &dev->drm_common_ctx_buf;
+#endif
+
+ ctx_buf->dma_buf = NULL;
+ ctx_buf->vaddr = NULL;
+ ctx_buf->daddr = 0;
+}
+
+/* Release context buffers for SYS_INIT */
+void s5p_mfc_release_common_context(struct s5p_mfc_dev *dev)
+{
+ mfc_release_common_context(dev, MFCBUF_NORMAL);
+
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+ mfc_release_common_context(dev, MFCBUF_DRM);
+#endif
+}
+
+/* Allocate memory for instance data buffer */
+int s5p_mfc_alloc_instance_context(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev;
+ struct s5p_mfc_ctx_buf_size *buf_size;
+
+ mfc_debug_enter();
+ if (!ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return -EINVAL;
+ }
+ dev = ctx->dev;
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+ buf_size = dev->variant->buf_size->ctx_buf;
+
+ switch (ctx->codec_mode) {
+ case S5P_FIMV_CODEC_H264_DEC:
+ case S5P_FIMV_CODEC_H264_MVC_DEC:
+ case S5P_FIMV_CODEC_HEVC_DEC:
+ case S5P_FIMV_CODEC_BPG_DEC:
+ ctx->instance_ctx_buf.size = buf_size->h264_dec_ctx;
+ break;
+ case S5P_FIMV_CODEC_MPEG4_DEC:
+ case S5P_FIMV_CODEC_H263_DEC:
+ case S5P_FIMV_CODEC_VC1_RCV_DEC:
+ case S5P_FIMV_CODEC_VC1_DEC:
+ case S5P_FIMV_CODEC_MPEG2_DEC:
+ case S5P_FIMV_CODEC_VP8_DEC:
+ case S5P_FIMV_CODEC_VP9_DEC:
+ case S5P_FIMV_CODEC_FIMV1_DEC:
+ case S5P_FIMV_CODEC_FIMV2_DEC:
+ case S5P_FIMV_CODEC_FIMV3_DEC:
+ case S5P_FIMV_CODEC_FIMV4_DEC:
+ ctx->instance_ctx_buf.size = buf_size->other_dec_ctx;
+ break;
+ case S5P_FIMV_CODEC_H264_ENC:
+ ctx->instance_ctx_buf.size = buf_size->h264_enc_ctx;
+ break;
+ case S5P_FIMV_CODEC_HEVC_ENC:
+ case S5P_FIMV_CODEC_BPG_ENC:
+ ctx->instance_ctx_buf.size = buf_size->hevc_enc_ctx;
+ break;
+ case S5P_FIMV_CODEC_MPEG4_ENC:
+ case S5P_FIMV_CODEC_H263_ENC:
+ case S5P_FIMV_CODEC_VP8_ENC:
+ case S5P_FIMV_CODEC_VP9_ENC:
+ ctx->instance_ctx_buf.size = buf_size->other_enc_ctx;
+ break;
+ default:
+ ctx->instance_ctx_buf.size = 0;
+ mfc_err_ctx("Codec type(%d) should be checked!\n", ctx->codec_mode);
+ return -ENOMEM;
+ }
+
+ if (ctx->is_drm)
+ ctx->instance_ctx_buf.buftype = MFCBUF_DRM;
+ else
+ ctx->instance_ctx_buf.buftype = MFCBUF_NORMAL;
+
+ if (s5p_mfc_mem_ion_alloc(dev, &ctx->instance_ctx_buf)) {
+ mfc_err_ctx("Allocating context buffer failed\n");
+ return -ENOMEM;
+ }
+
+ mfc_debug(2, "[MEMINFO] Instance buf ctx[%d] size: %ld, daddr: 0x%08llx\n",
+ ctx->num, ctx->instance_ctx_buf.size, ctx->instance_ctx_buf.daddr);
+
+ return 0;
+}
+
+/* Release instance buffer */
+void s5p_mfc_release_instance_context(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev;
+
+ mfc_debug_enter();
+ if (!ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return;
+ }
+
+ dev = ctx->dev;
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return;
+ }
+
+ s5p_mfc_mem_ion_free(dev, &ctx->instance_ctx_buf);
+ mfc_debug(2, "[MEMINFO] Release the instance buffer ctx[%d]\n", ctx->num);
+
+ mfc_debug_leave();
+}
+
+static void mfc_calc_dec_codec_buffer_size(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dec *dec;
+ int i;
+
+ dec = ctx->dec_priv;
+
+ /* Codecs have different memory requirements */
+ switch (ctx->codec_mode) {
+ case S5P_FIMV_CODEC_H264_DEC:
+ case S5P_FIMV_CODEC_H264_MVC_DEC:
+ ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256);
+ ctx->codec_buf.size =
+ ctx->scratch_buf_size +
+ (dec->mv_count * ctx->mv_size);
+ break;
+ case S5P_FIMV_CODEC_MPEG4_DEC:
+ case S5P_FIMV_CODEC_FIMV1_DEC:
+ case S5P_FIMV_CODEC_FIMV2_DEC:
+ case S5P_FIMV_CODEC_FIMV3_DEC:
+ case S5P_FIMV_CODEC_FIMV4_DEC:
+ ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256);
+ if (dec->loop_filter_mpeg4) {
+ ctx->loopfilter_luma_size = ALIGN(ctx->raw_buf.plane_size[0], 256);
+ ctx->loopfilter_chroma_size = ALIGN(ctx->raw_buf.plane_size[1] +
+ ctx->raw_buf.plane_size[2], 256);
+ ctx->codec_buf.size = ctx->scratch_buf_size +
+ (NUM_MPEG4_LF_BUF * (ctx->loopfilter_luma_size +
+ ctx->loopfilter_chroma_size));
+ } else {
+ ctx->codec_buf.size = ctx->scratch_buf_size;
+ }
+ break;
+ case S5P_FIMV_CODEC_VC1_RCV_DEC:
+ case S5P_FIMV_CODEC_VC1_DEC:
+ ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256);
+ ctx->codec_buf.size = ctx->scratch_buf_size;
+ break;
+ case S5P_FIMV_CODEC_MPEG2_DEC:
+ ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256);
+ ctx->codec_buf.size = ctx->scratch_buf_size;
+ break;
+ case S5P_FIMV_CODEC_H263_DEC:
+ ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256);
+ ctx->codec_buf.size = ctx->scratch_buf_size;
+ break;
+ case S5P_FIMV_CODEC_VP8_DEC:
+ ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256);
+ ctx->codec_buf.size = ctx->scratch_buf_size;
+ break;
+ case S5P_FIMV_CODEC_VP9_DEC:
+ ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256);
+ ctx->codec_buf.size =
+ ctx->scratch_buf_size +
+ DEC_STATIC_BUFFER_SIZE;
+ break;
+ case S5P_FIMV_CODEC_HEVC_DEC:
+ case S5P_FIMV_CODEC_BPG_DEC:
+ ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256);
+ ctx->codec_buf.size =
+ ctx->scratch_buf_size +
+ (dec->mv_count * ctx->mv_size);
+ break;
+ default:
+ ctx->codec_buf.size = 0;
+ mfc_err_ctx("invalid codec type: %d\n", ctx->codec_mode);
+ break;
+ }
+
+ mfc_debug(2, "[MEMINFO] scratch: %zu, MV: %zu x count %d\n",
+ ctx->scratch_buf_size, ctx->mv_size, dec->mv_count);
+ if (dec->loop_filter_mpeg4)
+ mfc_debug(2, "[MEMINFO] (loopfilter luma: %zu, chroma: %zu) x count %d\n",
+ ctx->loopfilter_luma_size, ctx->loopfilter_chroma_size,
+ NUM_MPEG4_LF_BUF);
+}
+
+static void mfc_calc_enc_codec_buffer_size(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_enc *enc;
+ unsigned int mb_width, mb_height;
+ unsigned int lcu_width = 0, lcu_height = 0;
+
+ enc = ctx->enc_priv;
+ enc->tmv_buffer_size = 0;
+
+ mb_width = WIDTH_MB(ctx->crop_width);
+ mb_height = HEIGHT_MB(ctx->crop_height);
+
+ lcu_width = ENC_LCU_WIDTH(ctx->crop_width);
+ lcu_height = ENC_LCU_HEIGHT(ctx->crop_height);
+
+ /* default recon buffer size, it can be changed in case of 422, 10bit */
+ enc->luma_dpb_size =
+ ALIGN(ENC_LUMA_DPB_SIZE(ctx->crop_width, ctx->crop_height), 64);
+ enc->chroma_dpb_size =
+ ALIGN(ENC_CHROMA_DPB_SIZE(ctx->crop_width, ctx->crop_height), 64);
+
+ /* Codecs have different memory requirements */
+ switch (ctx->codec_mode) {
+ case S5P_FIMV_CODEC_H264_ENC:
+ enc->me_buffer_size =
+ ALIGN(ENC_V100_H264_ME_SIZE(mb_width, mb_height), 256);
+
+ ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256);
+ ctx->codec_buf.size =
+ ctx->scratch_buf_size + enc->tmv_buffer_size +
+ (ctx->dpb_count * (enc->luma_dpb_size +
+ enc->chroma_dpb_size + enc->me_buffer_size));
+ break;
+ case S5P_FIMV_CODEC_MPEG4_ENC:
+ case S5P_FIMV_CODEC_H263_ENC:
+ enc->me_buffer_size =
+ ALIGN(ENC_V100_MPEG4_ME_SIZE(mb_width, mb_height), 256);
+
+ ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256);
+ ctx->codec_buf.size =
+ ctx->scratch_buf_size + enc->tmv_buffer_size +
+ (ctx->dpb_count * (enc->luma_dpb_size +
+ enc->chroma_dpb_size + enc->me_buffer_size));
+ break;
+ case S5P_FIMV_CODEC_VP8_ENC:
+ enc->me_buffer_size =
+ ALIGN(ENC_V100_VP8_ME_SIZE(mb_width, mb_height), 256);
+
+ ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256);
+ ctx->codec_buf.size =
+ ctx->scratch_buf_size + enc->tmv_buffer_size +
+ (ctx->dpb_count * (enc->luma_dpb_size +
+ enc->chroma_dpb_size + enc->me_buffer_size));
+ break;
+ case S5P_FIMV_CODEC_VP9_ENC:
+ if (ctx->is_10bit || ctx->is_422) {
+ enc->luma_dpb_size =
+ ALIGN(ENC_VP9_LUMA_DPB_10B_SIZE(ctx->crop_width, ctx->crop_height), 64);
+ enc->chroma_dpb_size =
+ ALIGN(ENC_VP9_CHROMA_DPB_10B_SIZE(ctx->crop_width, ctx->crop_height), 64);
+ mfc_debug(2, "[10BIT] VP9 10bit or 422 recon luma size: %zu chroma size: %zu\n",
+ enc->luma_dpb_size, enc->chroma_dpb_size);
+ }
+ enc->me_buffer_size =
+ ALIGN(ENC_V100_VP9_ME_SIZE(lcu_width, lcu_height), 256);
+
+ ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256);
+ ctx->codec_buf.size =
+ ctx->scratch_buf_size + enc->tmv_buffer_size +
+ (ctx->dpb_count * (enc->luma_dpb_size +
+ enc->chroma_dpb_size + enc->me_buffer_size));
+ break;
+ case S5P_FIMV_CODEC_HEVC_ENC:
+ case S5P_FIMV_CODEC_BPG_ENC:
+ if (ctx->is_10bit || ctx->is_422) {
+ enc->luma_dpb_size =
+ ALIGN(ENC_HEVC_LUMA_DPB_10B_SIZE(ctx->crop_width, ctx->crop_height), 64);
+ enc->chroma_dpb_size =
+ ALIGN(ENC_HEVC_CHROMA_DPB_10B_SIZE(ctx->crop_width, ctx->crop_height), 64);
+ mfc_debug(2, "[10BIT] HEVC 10bit or 422 recon luma size: %zu chroma size: %zu\n",
+ enc->luma_dpb_size, enc->chroma_dpb_size);
+ }
+ enc->me_buffer_size =
+ ALIGN(ENC_V100_HEVC_ME_SIZE(lcu_width, lcu_height), 256);
+
+ ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256);
+ ctx->codec_buf.size =
+ ctx->scratch_buf_size + enc->tmv_buffer_size +
+ (ctx->dpb_count * (enc->luma_dpb_size +
+ enc->chroma_dpb_size + enc->me_buffer_size));
+ break;
+ default:
+ ctx->codec_buf.size = 0;
+ mfc_err_ctx("invalid codec type: %d\n", ctx->codec_mode);
+ break;
+ }
+
+ mfc_debug(2, "[MEMINFO] scratch: %zu, TMV: %zu, (recon luma: %zu, chroma: %zu, me: %zu) x count %d\n",
+ ctx->scratch_buf_size, enc->tmv_buffer_size,
+ enc->luma_dpb_size, enc->chroma_dpb_size, enc->me_buffer_size,
+ ctx->dpb_count);
+}
+
+/* Allocate codec buffers */
+int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev;
+
+ mfc_debug_enter();
+ if (!ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return -EINVAL;
+ }
+ dev = ctx->dev;
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ if (ctx->type == MFCINST_DECODER) {
+ mfc_calc_dec_codec_buffer_size(ctx);
+ } else if (ctx->type == MFCINST_ENCODER) {
+ mfc_calc_enc_codec_buffer_size(ctx);
+ } else {
+ mfc_err_ctx("invalid type: %d\n", ctx->type);
+ return -EINVAL;
+ }
+
+ if (ctx->is_drm)
+ ctx->codec_buf.buftype = MFCBUF_DRM;
+ else
+ ctx->codec_buf.buftype = MFCBUF_NORMAL;
+
+ if (ctx->codec_buf.size > 0) {
+ if (s5p_mfc_mem_ion_alloc(dev, &ctx->codec_buf)) {
+ mfc_err_ctx("Allocating codec buffer failed\n");
+ return -ENOMEM;
+ }
+ ctx->codec_buffer_allocated = 1;
+ } else if (ctx->codec_mode == S5P_FIMV_CODEC_MPEG2_DEC) {
+ ctx->codec_buffer_allocated = 1;
+ }
+
+ mfc_debug(2, "[MEMINFO] Codec buf ctx[%d] size: %ld, addr: 0x%08llx\n",
+ ctx->num, ctx->codec_buf.size, ctx->codec_buf.daddr);
+
+ return 0;
+}
+
+/* Release buffers allocated for codec */
+void s5p_mfc_release_codec_buffers(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev;
+
+ if (!ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return;
+ }
+
+ dev = ctx->dev;
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return;
+ }
+
+ s5p_mfc_mem_ion_free(dev, &ctx->codec_buf);
+ ctx->codec_buffer_allocated = 0;
+ mfc_debug(2, "[MEMINFO] Release the codec buffer ctx[%d]\n", ctx->num);
+}
+
+/* Allocation buffer of debug infor memory for FW debugging */
+int s5p_mfc_alloc_dbg_info_buffer(struct s5p_mfc_dev *dev)
+{
+ struct s5p_mfc_ctx_buf_size *buf_size = dev->variant->buf_size->ctx_buf;
+
+ mfc_debug(2, "Allocate a debug-info buffer\n");
+
+ dev->dbg_info_buf.buftype = MFCBUF_NORMAL;
+ dev->dbg_info_buf.size = buf_size->dbg_info_buf;
+ if (s5p_mfc_mem_ion_alloc(dev, &dev->dbg_info_buf)) {
+ mfc_err_dev("Allocating debug info buffer failed\n");
+ return -ENOMEM;
+ }
+ mfc_debug(2, "[MEMINFO] debug info buf size: %ld, daddr: 0x%08llx, vaddr: 0x%p\n",
+ dev->dbg_info_buf.size, dev->dbg_info_buf.daddr, dev->dbg_info_buf.vaddr);
+
+ return 0;
+}
+
+/* Release buffer of debug infor memory for FW debugging */
+int s5p_mfc_release_dbg_info_buffer(struct s5p_mfc_dev *dev)
+{
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ if (!dev->dbg_info_buf.dma_buf) {
+ mfc_debug(2, "debug info buffer is already freed\n");
+ return 0;
+ }
+
+ s5p_mfc_mem_ion_free(dev, &dev->dbg_info_buf);
+ mfc_debug(2, "[MEMINFO] Release the debug info buffer\n");
+
+ return 0;
+}
+
+/* Allocation buffer of ROI macroblock information */
+static int mfc_alloc_enc_roi_buffer(struct s5p_mfc_ctx *ctx, struct s5p_mfc_special_buf *roi_buf)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_ctx_buf_size *buf_size = dev->variant->buf_size->ctx_buf;
+
+ roi_buf->buftype = MFCBUF_NORMAL;
+ roi_buf->size = buf_size->shared_buf;
+ if (s5p_mfc_mem_ion_alloc(dev, roi_buf)) {
+ mfc_err_ctx("[ROI] Allocating ROI buffer failed\n");
+ return -ENOMEM;
+ }
+ mfc_debug(2, "[MEMINFO][ROI] roi buf ctx[%d] size: %ld, daddr: 0x%08llx, vaddr: 0x%p\n",
+ ctx->num, roi_buf->size, roi_buf->daddr, roi_buf->vaddr);
+
+ memset(roi_buf->vaddr, 0, buf_size->shared_buf);
+
+ return 0;
+}
+
+/* Wrapper : allocation ROI buffers */
+int s5p_mfc_alloc_enc_roi_buffer(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ int i;
+
+ for (i = 0; i < MFC_MAX_EXTRA_BUF; i++) {
+ if (mfc_alloc_enc_roi_buffer(ctx, &enc->roi_buf[i]) < 0) {
+ mfc_err_dev("[ROI] Allocating remapping buffer[%d] failed\n", i);
+ return -ENOMEM;
+ }
+ }
+
+ return 0;
+}
+
+/* Release buffer of ROI macroblock information */
+void s5p_mfc_release_enc_roi_buffer(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ int i;
+
+ for (i = 0; i < MFC_MAX_EXTRA_BUF; i++)
+ if (enc->roi_buf[i].dma_buf)
+ s5p_mfc_mem_ion_free(ctx->dev, &enc->roi_buf[i]);
+
+ mfc_debug(2, "[MEMINFO][ROI] Release the ROI buffer\n");
+}
+
+int s5p_mfc_otf_alloc_stream_buf(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct _otf_handle *handle = ctx->otf_handle;
+ struct _otf_debug *debug = &handle->otf_debug;
+ struct s5p_mfc_special_buf *buf;
+ struct s5p_mfc_raw_info *raw = &ctx->raw_buf;
+ int i;
+
+ mfc_debug_enter();
+
+ for (i = 0; i < OTF_MAX_BUF; i++) {
+ buf = &debug->stream_buf[i];
+ buf->buftype = MFCBUF_NORMAL;
+ buf->size = raw->total_plane_size;
+ if (s5p_mfc_mem_ion_alloc(dev, buf)) {
+ mfc_err_ctx("[OTF] Allocating stream buffer failed\n");
+ return -EINVAL;
+ }
+ mfc_debug(2, "[OTF][MEMINFO] OTF stream buf[%d] size: %ld, daddr: 0x%08llx, vaddr: 0x%p\n",
+ i, buf->size, buf->daddr, buf->vaddr);
+ memset(buf->vaddr, 0, raw->total_plane_size);
+ }
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+void s5p_mfc_otf_release_stream_buf(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct _otf_handle *handle = ctx->otf_handle;
+ struct _otf_debug *debug = &handle->otf_debug;
+ struct s5p_mfc_special_buf *buf;
+ int i;
+
+ mfc_debug_enter();
+
+ for (i = 0; i < OTF_MAX_BUF; i++) {
+ buf = &debug->stream_buf[i];
+ if (buf->dma_buf)
+ s5p_mfc_mem_ion_free(dev, buf);
+ }
+
+ mfc_debug(2, "[OTF][MEMINFO] Release the OTF stream buffer\n");
+ mfc_debug_leave();
+}
+
+/* Allocate firmware */
+int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev)
+{
+ size_t firmware_size;
+ struct s5p_mfc_ctx_buf_size *buf_size;
+
+ mfc_debug_enter();
+
+ if (!dev) {
+ mfc_err_dev("[F/W] no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ buf_size = dev->variant->buf_size->ctx_buf;
+ firmware_size = dev->variant->buf_size->firmware_code;
+ dev->fw.size = firmware_size + buf_size->dev_ctx;
+
+ if (dev->fw_buf.dma_buf)
+ return 0;
+
+ mfc_debug(4, "[F/W] Allocating memory for firmware\n");
+ trace_mfc_loadfw_start(dev->fw.size, firmware_size);
+
+ dev->fw_buf.buftype = MFCBUF_NORMAL;
+ dev->fw_buf.size = dev->fw.size;
+ if (s5p_mfc_mem_ion_alloc(dev, &dev->fw_buf)) {
+ mfc_err_dev("[F/W] Allocating normal firmware buffer failed\n");
+ return -ENOMEM;
+ }
+
+ mfc_debug(2, "[MEMINFO][F/W] FW normal: 0x%08llx (vaddr: 0x%p), size: %08zu\n",
+ dev->fw_buf.daddr, dev->fw_buf.vaddr,
+ dev->fw_buf.size);
+
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+ dev->drm_fw_buf.buftype = MFCBUF_DRM_FW;
+ dev->drm_fw_buf.size = dev->fw.size;
+ if (s5p_mfc_mem_ion_alloc(dev, &dev->drm_fw_buf)) {
+ mfc_err_dev("[F/W] Allocating DRM firmware buffer failed\n");
+ return -ENOMEM;
+ }
+
+ mfc_debug(2, "[MEMINFO][F/W] FW DRM: 0x%08llx (vaddr: 0x%p), size: %08zu\n",
+ dev->drm_fw_buf.daddr, dev->drm_fw_buf.vaddr,
+ dev->drm_fw_buf.size);
+#endif
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+/* Load firmware to MFC */
+int s5p_mfc_load_firmware(struct s5p_mfc_dev *dev)
+{
+ struct firmware *fw_blob;
+ size_t firmware_size;
+ int err;
+
+ if (!dev) {
+ mfc_err_dev("[F/W] no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ firmware_size = dev->variant->buf_size->firmware_code;
+
+ /* Firmare has to be present as a separate file or compiled
+ * into kernel. */
+ mfc_debug_enter();
+ mfc_debug(4, "[F/W] Requesting F/W\n");
+ err = request_firmware((const struct firmware **)&fw_blob,
+ MFC_FW_NAME, dev->v4l2_dev.dev);
+
+ if (err != 0) {
+ mfc_err_dev("[F/W] Couldn't find the F/W invalid path\n");
+ return -EINVAL;
+ }
+
+ mfc_debug(2, "[MEMINFO][F/W] loaded F/W Size: %zu\n", fw_blob->size);
+
+ if (fw_blob->size > firmware_size) {
+ mfc_err_dev("[MEMINFO][F/W] MFC firmware(%zu) is too big to be loaded in memory(%zu)\n",
+ fw_blob->size, firmware_size);
+ release_firmware(fw_blob);
+ return -ENOMEM;
+ }
+
+ if (dev->fw_buf.dma_buf == NULL || dev->fw_buf.daddr == 0) {
+ mfc_err_dev("[F/W] MFC firmware is not allocated or was not mapped correctly\n");
+ release_firmware(fw_blob);
+ return -EINVAL;
+ }
+
+ memcpy(dev->fw_buf.vaddr, fw_blob->data, fw_blob->size);
+ if (dev->drm_fw_buf.vaddr) {
+ memcpy(dev->drm_fw_buf.vaddr, fw_blob->data, fw_blob->size);
+ mfc_debug(4, "[F/W] copy firmware to secure region\n");
+ }
+ release_firmware(fw_blob);
+ trace_mfc_loadfw_end(dev->fw.size, firmware_size);
+ mfc_debug_leave();
+ return 0;
+}
+
+/* Release firmware memory */
+int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev)
+{
+ /* Before calling this function one has to make sure
+ * that MFC is no longer processing */
+ if (!dev) {
+ mfc_err_dev("[F/W] no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ if (!dev->fw_buf.dma_buf) {
+ mfc_err_dev("[F/W] firmware memory is already freed\n");
+ return -EINVAL;
+ }
+
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+ s5p_mfc_mem_ion_free(dev, &dev->drm_fw_buf);
+#endif
+
+ s5p_mfc_mem_ion_free(dev, &dev->fw_buf);
+
+ return 0;
+}
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_buf.h
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __MFC_BUF_H
+#define __MFC_BUF_H __FILE__
+
+#include "mfc_common.h"
+
+/* Memory allocation */
+int s5p_mfc_alloc_common_context(struct s5p_mfc_dev *dev);
+void s5p_mfc_release_common_context(struct s5p_mfc_dev *dev);
+
+int s5p_mfc_alloc_instance_context(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_release_instance_context(struct s5p_mfc_ctx *ctx);
+
+int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_release_codec_buffers(struct s5p_mfc_ctx *ctx);
+
+int s5p_mfc_alloc_enc_roi_buffer(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_release_enc_roi_buffer(struct s5p_mfc_ctx *ctx);
+
+int s5p_mfc_otf_alloc_stream_buf(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_otf_release_stream_buf(struct s5p_mfc_ctx *ctx);
+
+int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev);
+int s5p_mfc_load_firmware(struct s5p_mfc_dev *dev);
+int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev);
+
+int s5p_mfc_alloc_dbg_info_buffer(struct s5p_mfc_dev *dev);
+int s5p_mfc_release_dbg_info_buffer(struct s5p_mfc_dev *dev);
+
+#endif /* __MFC_BUF_H */
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_cal.c
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <trace/events/mfc.h>
+
+#include "mfc_cal.h"
+#include "mfc_pm.h"
+
+/* Reset the device */
+int s5p_mfc_reset_mfc(struct s5p_mfc_dev *dev)
+{
+ int i;
+
+ mfc_debug_enter();
+
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ /* Zero Initialization of MFC registers */
+ MFC_WRITEL(0, S5P_FIMV_RISC2HOST_CMD);
+ MFC_WRITEL(0, S5P_FIMV_HOST2RISC_CMD);
+ MFC_WRITEL(0, S5P_FIMV_FW_VERSION);
+
+ for (i = 0; i < S5P_FIMV_REG_CLEAR_COUNT; i++)
+ MFC_WRITEL(0, S5P_FIMV_REG_CLEAR_BEGIN + (i*4));
+
+ MFC_WRITEL(0x1FFF, S5P_FIMV_MFC_RESET);
+ MFC_WRITEL(0, S5P_FIMV_MFC_RESET);
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+void s5p_mfc_set_risc_base_addr(struct s5p_mfc_dev *dev,
+ enum mfc_buf_usage_type buf_type)
+{
+ struct s5p_mfc_special_buf *fw_buf;
+
+ fw_buf = &dev->fw_buf;
+
+ if (buf_type == MFCBUF_DRM)
+ fw_buf = &dev->drm_fw_buf;
+
+ MFC_WRITEL(fw_buf->daddr, S5P_FIMV_RISC_BASE_ADDRESS);
+ mfc_debug(2, "[MEMINFO][F/W] %s Base Address : %#x\n",
+ buf_type == MFCBUF_DRM ? "DRM" : "NORMAL", fw_buf->daddr);
+ MFC_TRACE_DEV("%s F/W Base Address : %#x\n",
+ buf_type == MFCBUF_DRM ? "DRM" : "NORMAL", fw_buf->daddr);
+}
+
+void s5p_mfc_cmd_host2risc(struct s5p_mfc_dev *dev, int cmd)
+{
+ mfc_debug(1, "Issue the command: %d\n", cmd);
+ MFC_TRACE_DEV(">> CMD : %d, (dev:0x%lx, bits:%lx, owned:%d, wl:%d, trans:%d)\n",
+ cmd, dev->hwlock.dev, dev->hwlock.bits, dev->hwlock.owned_by_irq,
+ dev->hwlock.wl_count, dev->hwlock.transfer_owner);
+
+ trace_mfc_frame_start(dev->curr_ctx, cmd, 0, 0);
+ /* Reset RISC2HOST command except nal q stop command */
+ if (cmd != S5P_FIMV_H2R_CMD_STOP_QUEUE)
+ MFC_WRITEL(0x0, S5P_FIMV_RISC2HOST_CMD);
+
+ /* Start the timeout watchdog */
+ if ((cmd != S5P_FIMV_H2R_CMD_NAL_QUEUE) && (cmd != S5P_FIMV_H2R_CMD_STOP_QUEUE))
+ s5p_mfc_watchdog_start_tick(dev);
+
+ if (dbg_enable) {
+ /* For FW debugging */
+ s5p_mfc_dbg_set_addr(dev);
+ s5p_mfc_dbg_enable(dev);
+ }
+
+ /* Issue the command */
+ MFC_WRITEL(cmd, S5P_FIMV_HOST2RISC_CMD);
+ MFC_WRITEL(0x1, S5P_FIMV_HOST2RISC_INT);
+}
+
+/* Check whether HW interrupt has occurred or not */
+int s5p_mfc_check_risc2host(struct s5p_mfc_dev *dev)
+{
+ if (s5p_mfc_pm_get_pwr_ref_cnt(dev) && s5p_mfc_pm_get_clk_ref_cnt(dev)) {
+ if (MFC_READL(S5P_FIMV_RISC2HOST_INT))
+ return MFC_READL(S5P_FIMV_RISC2HOST_CMD);
+ else
+ return 0;
+ }
+
+ return 0;
+}
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_cal.h
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __MFC_CAL_H
+#define __MFC_CAL_H __FILE__
+
+#include "mfc_reg.h"
+
+#include "mfc_common.h"
+
+#include "mfc_utils.h"
+
+
+#define s5p_mfc_get_int_reason() (MFC_READL(S5P_FIMV_RISC2HOST_CMD) \
+ & S5P_FIMV_RISC2HOST_CMD_MASK)
+#define s5p_mfc_clear_int_sfr() \
+ do { \
+ MFC_WRITEL(0, S5P_FIMV_RISC2HOST_CMD); \
+ MFC_WRITEL(0, S5P_FIMV_RISC2HOST_INT); \
+ } while (0)
+
+static inline int s5p_mfc_stop_bus(struct s5p_mfc_dev *dev)
+{
+ unsigned int status;
+ unsigned long timeout;
+
+ /* Reset */
+ MFC_WRITEL(0x1, S5P_FIMV_MFC_BUS_RESET_CTRL);
+
+ timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT);
+ /* Check bus status */
+ do {
+ if (time_after(jiffies, timeout)) {
+ mfc_err_dev("Timeout while resetting MFC.\n");
+ return -EIO;
+ }
+ status = MFC_READL(S5P_FIMV_MFC_BUS_RESET_CTRL);
+ } while ((status & 0x2) == 0);
+
+ return 0;
+}
+
+static inline void s5p_mfc_start_bus(struct s5p_mfc_dev *dev)
+{
+ int val;
+
+ val = MFC_READL(S5P_FIMV_MFC_BUS_RESET_CTRL);
+ val &= ~(0x1);
+ MFC_WRITEL(val, S5P_FIMV_MFC_BUS_RESET_CTRL);
+}
+
+static inline void s5p_mfc_risc_on(struct s5p_mfc_dev *dev)
+{
+ s5p_mfc_clean_dev_int_flags(dev);
+
+ MFC_WRITEL(0x1, S5P_FIMV_RISC_ON);
+ MFC_WRITEL(0x0, S5P_FIMV_MFC_OFF);
+ mfc_debug(1, "RISC_ON\n");
+ MFC_TRACE_DEV(">> RISC ON\n");
+}
+
+static inline void s5p_mfc_risc_off(struct s5p_mfc_dev *dev)
+{
+ unsigned int status;
+ unsigned long timeout;
+
+ timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT);
+ /* Check pending status */
+ do {
+ if (time_after(jiffies, timeout)) {
+ mfc_err_dev("Timeout while pendng clear\n");
+ mfc_err_dev("MFC access pending state: %#x\n", status);
+ mfc_err_dev("MFC access pending R: %#x, W: %#x\n",
+ MFC_READL(S5P_FIMV_MFC_RPEND),
+ MFC_READL(S5P_FIMV_MFC_WPEND));
+ break;
+ }
+ status = MFC_READL(S5P_FIMV_MFC_BUS_STATUS);
+ } while (status != 0);
+
+ MFC_WRITEL(0x0, S5P_FIMV_RISC_ON);
+}
+
+static inline void s5p_mfc_mfc_off(struct s5p_mfc_dev *dev)
+{
+ mfc_info_dev("MFC h/w state: %d\n",
+ MFC_READL(S5P_FIMV_MFC_STATE) & 0x7);
+ MFC_WRITEL(0x1, S5P_FIMV_MFC_OFF);
+}
+
+static inline void s5p_mfc_enable_all_clocks(struct s5p_mfc_dev *dev)
+{
+ /* Enable all FW clock gating */
+ MFC_WRITEL(0xFFFFFFFF, S5P_FIMV_MFC_FW_CLOCK);
+}
+
+int s5p_mfc_reset_mfc(struct s5p_mfc_dev *dev);
+void s5p_mfc_set_risc_base_addr(struct s5p_mfc_dev *dev,
+ enum mfc_buf_usage_type buf_type);
+void s5p_mfc_cmd_host2risc(struct s5p_mfc_dev *dev, int cmd);
+int s5p_mfc_check_risc2host(struct s5p_mfc_dev *dev);
+
+#endif /* __MFC_CAL_H */
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_cmd.c
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <trace/events/mfc.h>
+
+#include "mfc_cmd.h"
+
+#include "mfc_cal.h"
+#include "mfc_reg.h"
+#include "mfc_mmcache.h"
+
+#include "mfc_utils.h"
+#include "mfc_buf.h"
+
+int s5p_mfc_cmd_sys_init(struct s5p_mfc_dev *dev,
+ enum mfc_buf_usage_type buf_type)
+{
+ struct s5p_mfc_ctx_buf_size *buf_size;
+ struct s5p_mfc_special_buf *ctx_buf;
+
+ mfc_debug_enter();
+
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ s5p_mfc_clean_dev_int_flags(dev);
+
+ buf_size = dev->variant->buf_size->ctx_buf;
+ ctx_buf = &dev->common_ctx_buf;
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+ if (buf_type == MFCBUF_DRM)
+ ctx_buf = &dev->drm_common_ctx_buf;
+#endif
+ MFC_WRITEL(ctx_buf->daddr, S5P_FIMV_CONTEXT_MEM_ADDR);
+ MFC_WRITEL(buf_size->dev_ctx, S5P_FIMV_CONTEXT_MEM_SIZE);
+
+ s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_SYS_INIT);
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+void s5p_mfc_cmd_sleep(struct s5p_mfc_dev *dev)
+{
+ mfc_debug_enter();
+
+ s5p_mfc_clean_dev_int_flags(dev);
+ s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_SLEEP);
+
+ mfc_debug_leave();
+}
+
+void s5p_mfc_cmd_wakeup(struct s5p_mfc_dev *dev)
+{
+ mfc_debug_enter();
+
+ s5p_mfc_clean_dev_int_flags(dev);
+ s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_WAKEUP);
+
+ mfc_debug_leave();
+}
+
+/* Open a new instance and get its number */
+int s5p_mfc_cmd_open_inst(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev;
+
+ mfc_debug_enter();
+
+ if (!ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return -EINVAL;
+ }
+ dev = ctx->dev;
+ mfc_debug(2, "Requested codec mode: %d\n", ctx->codec_mode);
+
+ MFC_WRITEL(ctx->codec_mode, S5P_FIMV_CODEC_TYPE);
+ MFC_WRITEL(ctx->instance_ctx_buf.daddr, S5P_FIMV_CONTEXT_MEM_ADDR);
+ MFC_WRITEL(ctx->instance_ctx_buf.size, S5P_FIMV_CONTEXT_MEM_SIZE);
+ if (ctx->type == MFCINST_DECODER)
+ MFC_WRITEL(ctx->dec_priv->crc_enable, S5P_FIMV_D_CRC_CTRL);
+
+ s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_OPEN_INSTANCE);
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+/* Close instance */
+int s5p_mfc_cmd_close_inst(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev;
+
+ mfc_debug_enter();
+
+ if (!ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return -EINVAL;
+ }
+ dev = ctx->dev;
+
+ MFC_WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID);
+
+ s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_CLOSE_INSTANCE);
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+int s5p_mfc_cmd_dpb_flush(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ if (ON_RES_CHANGE(ctx))
+ mfc_err_ctx("dpb flush on res change(state:%d)\n", ctx->state);
+
+ s5p_mfc_clean_ctx_int_flags(ctx);
+
+ MFC_WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID);
+ s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_DPB_FLUSH);
+
+ return 0;
+}
+
+int s5p_mfc_cmd_cache_flush(struct s5p_mfc_dev *dev)
+{
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ s5p_mfc_clean_dev_int_flags(dev);
+ s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_CACHE_FLUSH);
+
+ return 0;
+}
+
+int s5p_mfc_cmd_dec_init_buffers(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev;
+ struct s5p_mfc_dec *dec;
+ unsigned int reg = 0, pix_val;
+ int ret;
+
+ if (!ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return -EINVAL;
+ }
+ dec = ctx->dec_priv;
+ dev = ctx->dev;
+ if (!dev) {
+ mfc_err_ctx("no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ switch (ctx->dst_fmt->fourcc) {
+ case V4L2_PIX_FMT_NV12M:
+ case V4L2_PIX_FMT_NV12N:
+ case V4L2_PIX_FMT_NV12MT_16X16:
+ case V4L2_PIX_FMT_NV16M:
+ case V4L2_PIX_FMT_NV12N_10B:
+ case V4L2_PIX_FMT_NV12M_S10B:
+ case V4L2_PIX_FMT_NV16M_S10B:
+ case V4L2_PIX_FMT_NV12M_P010:
+ case V4L2_PIX_FMT_NV16M_P210:
+ pix_val = 0;
+ break;
+ case V4L2_PIX_FMT_NV21M:
+ case V4L2_PIX_FMT_NV61M:
+ case V4L2_PIX_FMT_NV21M_S10B:
+ case V4L2_PIX_FMT_NV61M_S10B:
+ case V4L2_PIX_FMT_NV21M_P010:
+ case V4L2_PIX_FMT_NV61M_P210:
+ pix_val = 1;
+ break;
+ case V4L2_PIX_FMT_YVU420M:
+ pix_val = 2;
+ break;
+ case V4L2_PIX_FMT_YUV420M:
+ case V4L2_PIX_FMT_YUV420N:
+ pix_val = 3;
+ break;
+ default:
+ pix_val = 0;
+ break;
+ }
+ reg = MFC_READL(S5P_FIMV_PIXEL_FORMAT);
+ reg &= ~(0xF);
+ reg |= pix_val & 0xF;
+ MFC_WRITEL(reg, S5P_FIMV_PIXEL_FORMAT);
+ mfc_debug(2, "[FRAME] pixel format: %d, mem_type_10bit should be fixed on SEQ_START(reg: %#x)\n",
+ pix_val, reg);
+
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ ret = s5p_mfc_set_dec_codec_buffers(ctx);
+ if (ret) {
+ mfc_info_ctx("isn't enough codec buffer size, re-alloc!\n");
+
+ if (dev->has_mmcache && dev->mmcache.is_on_status)
+ s5p_mfc_invalidate_mmcache(dev);
+
+ s5p_mfc_release_codec_buffers(ctx);
+ ret = s5p_mfc_alloc_codec_buffers(ctx);
+ if (ret) {
+ mfc_err_ctx("Failed to allocate decoding buffers\n");
+ return ret;
+ }
+ ret = s5p_mfc_set_dec_codec_buffers(ctx);
+ if (ret) {
+ mfc_err_ctx("Failed to alloc frame mem\n");
+ return ret;
+ }
+ }
+
+ MFC_WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID);
+
+ if (sfr_dump & MFC_DUMP_DEC_INIT_BUFS)
+ call_dop(dev, dump_regs, dev);
+
+ s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_INIT_BUFFERS);
+
+ return ret;
+}
+
+int s5p_mfc_cmd_enc_init_buffers(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev;
+ int ret;
+
+ dev = ctx->dev;
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Header was generated now starting processing
+ * First set the reference frame buffers
+ */
+ if (!ctx->codec_buffer_allocated) {
+ mfc_info_ctx("there isn't codec buffer, re-alloc!\n");
+ ret = s5p_mfc_alloc_codec_buffers(ctx);
+ if (ret) {
+ mfc_err_ctx("Failed to allocate encoding buffers\n");
+ return ret;
+ }
+ }
+
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ ret = s5p_mfc_set_enc_codec_buffers(ctx);
+ if (ret) {
+ mfc_info_ctx("isn't enough codec buffer size, re-alloc!\n");
+
+ if (dev->has_mmcache && dev->mmcache.is_on_status)
+ s5p_mfc_invalidate_mmcache(dev);
+
+ s5p_mfc_release_codec_buffers(ctx);
+ ret = s5p_mfc_alloc_codec_buffers(ctx);
+ if (ret) {
+ mfc_err_ctx("Failed to allocate encoding buffers\n");
+ return ret;
+ }
+ ret = s5p_mfc_set_enc_codec_buffers(ctx);
+ if (ret) {
+ mfc_err_ctx("Failed to set enc codec buffers\n");
+ return ret;
+ }
+ }
+
+ MFC_WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID);
+
+ if (sfr_dump & MFC_DUMP_ENC_INIT_BUFS)
+ call_dop(dev, dump_regs, dev);
+
+ s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_INIT_BUFFERS);
+
+ return ret;
+}
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_cmd.h
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __MFC_CMD_H
+#define __MFC_CMD_H __FILE__
+
+#include "mfc_common.h"
+
+int s5p_mfc_cmd_sys_init(struct s5p_mfc_dev *dev,
+ enum mfc_buf_usage_type buf_type);
+void s5p_mfc_cmd_sleep(struct s5p_mfc_dev *dev);
+void s5p_mfc_cmd_wakeup(struct s5p_mfc_dev *dev);
+int s5p_mfc_cmd_open_inst(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_cmd_close_inst(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_cmd_dpb_flush(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_cmd_cache_flush(struct s5p_mfc_dev *dev);
+int s5p_mfc_cmd_dec_init_buffers(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_cmd_enc_init_buffers(struct s5p_mfc_ctx *ctx);
+
+#endif /* __MFC_CMD_H */
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_common.h
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __MFC_COMMON_H
+#define __MFC_COMMON_H __FILE__
+
+#include <linux/exynos_iovmm.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/sched/clock.h>
+#include <linux/ion_exynos.h>
+#include <linux/dma-buf-container.h>
+#include <media/videobuf2-dma-sg.h>
+#include <asm/cacheflush.h>
+
+#include "mfc_regs_v10.h"
+#include "mfc_macros.h"
+#include "mfc_debug.h"
+#include "exynos_mfc_media.h"
+#include "mfc_data_struct.h"
+
+#define MFC_DRIVER_INFO 180315
+
+#define MFC_MAX_REF_BUFS 2
+#define MFC_FRAME_PLANES 2
+#define MFC_INFO_INIT_FD -1
+
+#define MFC_MAX_DRM_CTX 2
+
+/* Interrupt timeout */
+#define MFC_INT_TIMEOUT 4000
+/* Interrupt short timeout */
+#define MFC_INT_SHORT_TIMEOUT 800
+/* hwlock timeout */
+#define MFC_HWLOCK_TIMEOUT 5000
+/* Busy wait timeout */
+#define MFC_BW_TIMEOUT 500
+/* MMCache invalidation timeout */
+#define MMCACHE_INVAL_TIMEOUT 1000
+/* Interrupt timeout count*/
+#define MFC_INT_TIMEOUT_CNT 2
+
+/* This value guarantees 299.4msec ~ 2.25sec according to MFC clock (668MHz ~ 89MHz)
+ * releated with S5P_FIMV_DEC_TIMEOUT_VALUE */
+#define MFC_TIMEOUT_VALUE 200000000
+
+#define NUM_MPEG4_LF_BUF 2
+
+#define DEFAULT_TAG (0xE05)
+
+#define MFC_NO_INSTANCE_SET -1
+
+#define MFC_ENC_CAP_PLANE_COUNT 1
+#define MFC_ENC_OUT_PLANE_COUNT 2
+
+#define MFC_NAME_LEN 16
+#define MFC_FW_NAME "mfc_fw.bin"
+
+#define STUFF_BYTE 4
+
+#define MFC_BASE_MASK ((1 << 17) - 1)
+
+#define FLAG_LAST_FRAME 0x80000000
+#define FLAG_EMPTY_DATA 0x40000000
+#define FLAG_CSD 0x20000000
+
+/* MFC conceal color is black */
+#define MFC_CONCEAL_COLOR 0x8020000
+
+#define vb_to_mfc_buf(x) \
+ container_of(x, struct s5p_mfc_buf, vb.vb2_buf)
+
+#define fh_to_mfc_ctx(x) \
+ container_of(x, struct s5p_mfc_ctx, fh)
+
+#define call_bop(b, op, args...) \
+ (b->op ? b->op(args) : 0)
+
+#define call_cop(c, op, args...) \
+ (((c)->c_ops->op) ? \
+ ((c)->c_ops->op(args)) : 0)
+
+#define call_dop(d, op, args...) \
+ (((d)->dump_ops->op) ? \
+ ((d)->dump_ops->op(args)) : 0)
+
+#define MFC_CTRL_TYPE_GET (MFC_CTRL_TYPE_GET_SRC | MFC_CTRL_TYPE_GET_DST)
+#define MFC_CTRL_TYPE_SRC (MFC_CTRL_TYPE_SET | MFC_CTRL_TYPE_GET_SRC)
+#define MFC_CTRL_TYPE_DST (MFC_CTRL_TYPE_GET_DST)
+
+#define MFC_FMT_STREAM (1 << 0)
+#define MFC_FMT_FRAME (1 << 1)
+#define MFC_FMT_10BIT (1 << 2)
+#define MFC_FMT_422 (1 << 3)
+#define MFC_FMT_RGB (1 << 4)
+
+/* node check */
+#define IS_DEC_NODE(n) ((n == EXYNOS_VIDEONODE_MFC_DEC) || \
+ (n == EXYNOS_VIDEONODE_MFC_DEC_DRM))
+#define IS_ENC_NODE(n) ((n == EXYNOS_VIDEONODE_MFC_ENC) || \
+ (n == EXYNOS_VIDEONODE_MFC_ENC_DRM) || \
+ (n == EXYNOS_VIDEONODE_MFC_ENC_OTF) || \
+ (n == EXYNOS_VIDEONODE_MFC_ENC_OTF_DRM))
+
+/* Decoder codec mode check */
+#define IS_H264_DEC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_H264_DEC)
+#define IS_H264_MVC_DEC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_H264_MVC_DEC)
+#define IS_MPEG4_DEC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_MPEG4_DEC)
+#define IS_FIMV1_DEC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_FIMV1_DEC)
+#define IS_FIMV2_DEC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_FIMV2_DEC)
+#define IS_FIMV3_DEC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_FIMV3_DEC)
+#define IS_FIMV4_DEC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_FIMV4_DEC)
+#define IS_VC1_DEC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_VC1_DEC)
+#define IS_VC1_RCV_DEC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_VC1_RCV_DEC)
+#define IS_MPEG2_DEC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_MPEG2_DEC)
+#define IS_HEVC_DEC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_HEVC_DEC)
+#define IS_VP9_DEC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_VP9_DEC)
+#define IS_BPG_DEC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_BPG_DEC)
+
+/* Encoder codec mode check */
+#define IS_H264_ENC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_H264_ENC)
+#define IS_MPEG4_ENC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_MPEG4_ENC)
+#define IS_H263_ENC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_H263_ENC)
+#define IS_VP8_ENC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_VP8_ENC)
+#define IS_HEVC_ENC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_HEVC_ENC)
+#define IS_VP9_ENC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_VP9_ENC)
+#define IS_BPG_ENC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_BPG_ENC)
+
+#define CODEC_NOT_CODED(ctx) (IS_MPEG4_DEC(ctx) || IS_VC1_DEC(ctx) || IS_VC1_RCV_DEC(ctx))
+#define CODEC_INTERLACED(ctx) (IS_H264_DEC(ctx) || IS_H264_MVC_DEC(ctx) || \
+ IS_MPEG2_DEC(ctx) || IS_MPEG4_DEC(ctx) || \
+ IS_VC1_DEC(ctx) || IS_VC1_RCV_DEC(ctx))
+#define CODEC_MBAFF(ctx) (IS_H264_DEC(ctx) || IS_H264_MVC_DEC(ctx))
+#define CODEC_MULTIFRAME(ctx) (IS_MPEG4_DEC(ctx) || IS_VP9_DEC(ctx) || \
+ IS_FIMV2_DEC(ctx) || IS_FIMV3_DEC(ctx) || IS_FIMV4_DEC(ctx))
+#define CODEC_10BIT(ctx) (IS_HEVC_DEC(ctx) || IS_HEVC_ENC(ctx) || \
+ IS_VP9_DEC(ctx) || IS_VP9_ENC(ctx) || \
+ IS_BPG_DEC(ctx) || IS_BPG_ENC(ctx))
+#define CODEC_422FORMAT(ctx) (IS_HEVC_DEC(ctx) || IS_HEVC_ENC(ctx) || \
+ IS_VP9_DEC(ctx) || IS_VP9_ENC(ctx) || \
+ IS_BPG_DEC(ctx) || IS_BPG_ENC(ctx))
+#define ON_RES_CHANGE(ctx) (((ctx)->state >= MFCINST_RES_CHANGE_INIT) && \
+ ((ctx)->state <= MFCINST_RES_CHANGE_END))
+
+#define IS_BUFFER_BATCH_MODE(ctx) ((ctx)->batch_mode == 1)
+
+/* UHD resoluition */
+#define MFC_UHD_RES (3840 * 2160)
+#define IS_UHD_RES(ctx) (((ctx)->crop_width * (ctx)->crop_height) == MFC_UHD_RES)
+#define OVER_UHD_ENC60(ctx) ((((ctx)->crop_width * (ctx)->crop_height) == MFC_UHD_RES) && \
+ ((ctx)->type == MFCINST_ENCODER) && \
+ ((ctx)->framerate / 1000) >= 60)
+
+/* Extra information for Decoder */
+#define DEC_SET_DUAL_DPB (1 << 0)
+#define DEC_SET_DYNAMIC_DPB (1 << 1)
+#define DEC_SET_LAST_FRAME_INFO (1 << 2)
+#define DEC_SET_SKYPE_FLAG (1 << 3)
+
+/* Extra information for Encoder */
+#define ENC_SET_RGB_INPUT (1 << 0)
+#define ENC_SET_SPARE_SIZE (1 << 1)
+#define ENC_SET_TEMP_SVC_CH (1 << 2)
+#define ENC_SET_SKYPE_FLAG (1 << 3)
+#define ENC_SET_ROI_CONTROL (1 << 4)
+#define ENC_SET_QP_BOUND_PB (1 << 5)
+#define ENC_SET_FIXED_SLICE (1 << 6)
+#define ENC_SET_PVC_MODE (1 << 7)
+#define ENC_SET_RATIO_OF_INTRA (1 << 8)
+#define ENC_SET_COLOR_ASPECT (1 << 9)
+#define ENC_SET_HP_BITRATE_CONTROL (1 << 10)
+#define ENC_SET_STATIC_INFO (1 << 11)
+
+#define MFC_VER_MAJOR(dev) ((dev->pdata->ip_ver >> 8) & 0xFF)
+#define MFC_VER_MINOR(dev) (dev->pdata->ip_ver & 0xFF)
+
+#define MFC_FEATURE_SUPPORT(dev, f) ((f).support && ((dev)->fw.date >= (f).version))
+
+/* Low memory check */
+#define IS_LOW_MEM (totalram_pages <= ((SZ_1G + SZ_512M) >> PAGE_SHIFT))
+#define SZ_600M (6 * 1024 * 1024)
+
+#endif /* __MFC_COMMON_H */
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_ctrl.c
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "mfc_ctrl.h"
+
+#include "mfc_hwlock.h"
+#include "mfc_nal_q.h"
+#include "mfc_sync.h"
+
+#include "mfc_pm.h"
+#include "mfc_cmd.h"
+#include "mfc_cal.h"
+#include "mfc_reg.h"
+
+#include "mfc_utils.h"
+
+/* Initialize hardware */
+static int mfc_init_hw(struct s5p_mfc_dev *dev, enum mfc_buf_usage_type buf_type)
+{
+ int fw_ver;
+ int ret = 0;
+ int curr_ctx_is_drm_backup;
+
+ mfc_debug_enter();
+
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ curr_ctx_is_drm_backup = dev->curr_ctx_is_drm;
+
+ if (!dev->fw_buf.dma_buf)
+ return -EINVAL;
+
+ /* 0. MFC reset */
+ mfc_debug(2, "MFC reset...\n");
+
+ /* At init time, do not call secure API */
+ if (buf_type == MFCBUF_NORMAL)
+ dev->curr_ctx_is_drm = 0;
+ else if (buf_type == MFCBUF_DRM)
+ dev->curr_ctx_is_drm = 1;
+
+ ret = s5p_mfc_pm_clock_on(dev);
+ if (ret) {
+ mfc_err_dev("Failed to enable clock before reset(%d)\n", ret);
+ dev->curr_ctx_is_drm = curr_ctx_is_drm_backup;
+ return ret;
+ }
+
+ ret = s5p_mfc_reset_mfc(dev);
+ if (ret) {
+ mfc_err_dev("Failed to reset MFC - timeout\n");
+ goto err_init_hw;
+ }
+ mfc_debug(2, "Done MFC reset...\n");
+
+ /* 1. Set DRAM base Addr */
+ s5p_mfc_set_risc_base_addr(dev, buf_type);
+
+ /* 2. Release reset signal to the RISC */
+ s5p_mfc_risc_on(dev);
+
+ mfc_debug(2, "Will now wait for completion of firmware transfer\n");
+ if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_FW_STATUS_RET)) {
+ mfc_err_dev("Failed to RISC_ON\n");
+ s5p_mfc_clean_dev_int_flags(dev);
+ ret = -EIO;
+ goto err_init_hw;
+ }
+
+ /* 3. Initialize firmware */
+ ret = s5p_mfc_cmd_sys_init(dev, buf_type);
+ if (ret) {
+ mfc_err_dev("Failed to send command to MFC - timeout\n");
+ goto err_init_hw;
+ }
+
+ mfc_debug(2, "Ok, now will write a command to init the system\n");
+ if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_SYS_INIT_RET)) {
+ mfc_err_dev("Failed to SYS_INIT\n");
+ s5p_mfc_clean_dev_int_flags(dev);
+ ret = -EIO;
+ goto err_init_hw;
+ }
+
+ dev->int_condition = 0;
+ if (dev->int_err != 0 || dev->int_reason != S5P_FIMV_R2H_CMD_SYS_INIT_RET) {
+ /* Failure. */
+ mfc_err_dev("Failed to init firmware - error: %d, int: %d\n",
+ dev->int_err, dev->int_reason);
+ ret = -EIO;
+ goto err_init_hw;
+ }
+
+ dev->fw.fimv_info = s5p_mfc_get_fimv_info();
+ if (dev->fw.fimv_info != 'D' && dev->fw.fimv_info != 'E')
+ dev->fw.fimv_info = 'N';
+
+ mfc_info_dev("[F/W] MFC v%x.%x, %02xyy %02xmm %02xdd (%c)\n",
+ MFC_VER_MAJOR(dev),
+ MFC_VER_MINOR(dev),
+ s5p_mfc_get_fw_ver_year(),
+ s5p_mfc_get_fw_ver_month(),
+ s5p_mfc_get_fw_ver_date(),
+ dev->fw.fimv_info);
+
+ dev->fw.date = s5p_mfc_get_fw_ver_all();
+ /* Check MFC version and F/W version */
+ fw_ver = s5p_mfc_get_mfc_version();
+ if (fw_ver != dev->pdata->ip_ver) {
+ mfc_err_dev("Invalid F/W version(0x%x) for MFC H/W(0x%x)\n",
+ fw_ver, dev->pdata->ip_ver);
+ ret = -EIO;
+ goto err_init_hw;
+ }
+
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+ /* Cache flush for base address change */
+ s5p_mfc_cmd_cache_flush(dev);
+ if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_CACHE_FLUSH_RET)) {
+ mfc_err_dev("Failed to CACHE_FLUSH\n");
+ s5p_mfc_clean_dev_int_flags(dev);
+ ret = -EIO;
+ goto err_init_hw;
+ }
+
+ if (buf_type == MFCBUF_DRM && !curr_ctx_is_drm_backup) {
+ s5p_mfc_pm_clock_off(dev);
+ dev->curr_ctx_is_drm = curr_ctx_is_drm_backup;
+ s5p_mfc_pm_clock_on_with_base(dev, MFCBUF_NORMAL);
+ }
+#endif
+
+err_init_hw:
+ s5p_mfc_pm_clock_off(dev);
+ dev->curr_ctx_is_drm = curr_ctx_is_drm_backup;
+ mfc_debug_leave();
+
+ return ret;
+}
+
+/* Wrapper : Initialize hardware */
+int s5p_mfc_init_hw(struct s5p_mfc_dev *dev)
+{
+ int ret;
+
+ ret = mfc_init_hw(dev, MFCBUF_NORMAL);
+ if (ret)
+ return ret;
+
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+ if (dev->fw.drm_status) {
+ ret = mfc_init_hw(dev, MFCBUF_DRM);
+ if (ret)
+ return ret;
+ }
+#endif
+
+ return ret;
+}
+
+/* Deinitialize hardware */
+void s5p_mfc_deinit_hw(struct s5p_mfc_dev *dev)
+{
+ int ret;
+
+ mfc_debug(2, "mfc deinit start\n");
+
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return;
+ }
+
+ ret = s5p_mfc_pm_clock_on(dev);
+ if (ret) {
+ mfc_err_dev("Failed to enable clock before reset(%d)\n", ret);
+ return;
+ }
+
+ s5p_mfc_mfc_off(dev);
+
+ s5p_mfc_pm_clock_off(dev);
+
+ mfc_debug(2, "mfc deinit completed\n");
+}
+
+int s5p_mfc_sleep(struct s5p_mfc_dev *dev)
+{
+ struct s5p_mfc_ctx *ctx;
+ int ret;
+ int old_state, i;
+ int need_cache_flush = 0;
+
+ mfc_debug_enter();
+
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ ctx = dev->ctx[dev->curr_ctx];
+ if (!ctx) {
+ for (i = 0; i < MFC_NUM_CONTEXTS; i++) {
+ if (dev->ctx[i]) {
+ ctx = dev->ctx[i];
+ break;
+ }
+ }
+ if (!ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return -EINVAL;
+ } else {
+ mfc_info_dev("ctx is changed %d -> %d\n",
+ dev->curr_ctx, ctx->num);
+ dev->curr_ctx = ctx->num;
+ if (dev->curr_ctx_is_drm != ctx->is_drm) {
+ need_cache_flush = 1;
+ mfc_info_dev("DRM attribute is changed %d->%d\n",
+ dev->curr_ctx_is_drm, ctx->is_drm);
+ }
+ }
+ }
+ old_state = ctx->state;
+ s5p_mfc_change_state(ctx, MFCINST_ABORT);
+ MFC_TRACE_DEV_HWLOCK("**sleep (ctx:%d)\n", ctx->num);
+ ret = s5p_mfc_get_hwlock_dev(dev);
+ if (ret < 0) {
+ mfc_err_dev("Failed to get hwlock\n");
+ mfc_err_dev("dev.hwlock.dev = 0x%lx, bits = 0x%lx, owned_by_irq = %d, wl_count = %d, transfer_owner = %d\n",
+ dev->hwlock.dev, dev->hwlock.bits, dev->hwlock.owned_by_irq,
+ dev->hwlock.wl_count, dev->hwlock.transfer_owner);
+ return -EBUSY;
+ }
+
+ mfc_info_dev("curr_ctx_is_drm:%d, hwlock.bits:%lu, hwlock.dev:%lu\n",
+ dev->curr_ctx_is_drm, dev->hwlock.bits, dev->hwlock.dev);
+
+ s5p_mfc_change_state(ctx, old_state);
+ s5p_mfc_pm_clock_on(dev);
+
+ if (need_cache_flush)
+ s5p_mfc_cache_flush(dev, ctx->is_drm);
+
+ s5p_mfc_cmd_sleep(dev);
+
+ if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_SLEEP_RET)) {
+ mfc_err_dev("Failed to SLEEP\n");
+ dev->logging_data->cause |= (1 << MFC_CAUSE_FAIL_SLEEP);
+ call_dop(dev, dump_and_stop_always, dev);
+ return -EIO;
+ }
+
+ dev->int_condition = 0;
+ if (dev->int_err != 0 || dev->int_reason != S5P_FIMV_R2H_CMD_SLEEP_RET) {
+ /* Failure. */
+ mfc_err_dev("Failed to sleep - error: %d, int: %d\n",
+ dev->int_err, dev->int_reason);
+ ret = -EIO;
+ goto err_mfc_sleep;
+ }
+
+ dev->sleep = 1;
+
+err_mfc_sleep:
+ s5p_mfc_mfc_off(dev);
+ s5p_mfc_pm_clock_off(dev);
+ s5p_mfc_release_hwlock_dev(dev);
+ mfc_debug_leave();
+
+ return ret;
+}
+
+int s5p_mfc_wakeup(struct s5p_mfc_dev *dev)
+{
+ enum mfc_buf_usage_type buf_type;
+ int ret = 0;
+
+ mfc_debug_enter();
+
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+ mfc_info_dev("curr_ctx_is_drm:%d\n", dev->curr_ctx_is_drm);
+
+ MFC_TRACE_DEV_HWLOCK("**wakeup\n");
+ ret = s5p_mfc_get_hwlock_dev(dev);
+ if (ret < 0) {
+ mfc_err_dev("Failed to get hwlock\n");
+ mfc_err_dev("dev.hwlock.dev = 0x%lx, bits = 0x%lx, owned_by_irq = %d, wl_count = %d, transfer_owner = %d\n",
+ dev->hwlock.dev, dev->hwlock.bits, dev->hwlock.owned_by_irq,
+ dev->hwlock.wl_count, dev->hwlock.transfer_owner);
+ return -EBUSY;
+ }
+
+ dev->sleep = 0;
+
+ /* 0. MFC reset */
+ mfc_debug(2, "MFC reset...\n");
+
+ s5p_mfc_pm_clock_on(dev);
+
+ ret = s5p_mfc_reset_mfc(dev);
+ if (ret) {
+ mfc_err_dev("Failed to reset MFC - timeout\n");
+ goto err_mfc_wakeup;
+ }
+ mfc_debug(2, "Done MFC reset...\n");
+ if (dev->curr_ctx_is_drm)
+ buf_type = MFCBUF_DRM;
+ else
+ buf_type = MFCBUF_NORMAL;
+
+ /* 1. Set DRAM base Addr */
+ s5p_mfc_set_risc_base_addr(dev, buf_type);
+
+ /* 2. Release reset signal to the RISC */
+ s5p_mfc_risc_on(dev);
+
+ mfc_debug(2, "Will now wait for completion of firmware transfer\n");
+ if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_FW_STATUS_RET)) {
+ mfc_err_dev("Failed to RISC_ON\n");
+ dev->logging_data->cause |= (1 << MFC_CAUSE_FAIL_RISC_ON);
+ call_dop(dev, dump_and_stop_always, dev);
+ return -EIO;
+ }
+
+ mfc_debug(2, "Ok, now will write a command to wakeup the system\n");
+ s5p_mfc_cmd_wakeup(dev);
+
+ mfc_debug(2, "Will now wait for completion of firmware wake up\n");
+ if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_WAKEUP_RET)) {
+ mfc_err_dev("Failed to WAKEUP\n");
+ dev->logging_data->cause |= (1 << MFC_CAUSE_FAIL_WAKEUP);
+ call_dop(dev, dump_and_stop_always, dev);
+ return -EIO;
+ }
+
+ dev->int_condition = 0;
+ if (dev->int_err != 0 || dev->int_reason != S5P_FIMV_R2H_CMD_WAKEUP_RET) {
+ /* Failure. */
+ mfc_err_dev("Failed to wakeup - error: %d, int: %d\n",
+ dev->int_err, dev->int_reason);
+ ret = -EIO;
+ goto err_mfc_wakeup;
+ }
+
+err_mfc_wakeup:
+ s5p_mfc_pm_clock_off(dev);
+
+ s5p_mfc_release_hwlock_dev(dev);
+
+ mfc_debug_leave();
+
+ return ret;
+}
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_ctrl.h
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __MFC_CTRL_H
+#define __MFC_CTRL_H __FILE__
+
+#include "mfc_common.h"
+
+int s5p_mfc_init_hw(struct s5p_mfc_dev *dev);
+void s5p_mfc_deinit_hw(struct s5p_mfc_dev *dev);
+
+int s5p_mfc_sleep(struct s5p_mfc_dev *dev);
+int s5p_mfc_wakeup(struct s5p_mfc_dev *dev);
+
+#endif /* __MFC_CTRL_H */
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_data_struct.h
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __MFC_DATA_STRUCT_H
+#define __MFC_DATA_STRUCT_H __FILE__
+
+#ifdef CONFIG_ARM_EXYNOS_DEVFREQ
+#define CONFIG_MFC_USE_BUS_DEVFREQ
+#endif
+
+#ifdef CONFIG_MFC_USE_BUS_DEVFREQ
+#include <linux/pm_qos.h>
+#endif
+#ifdef CONFIG_EXYNOS_BTS
+#include <soc/samsung/bts.h>
+#endif
+#include <linux/videodev2.h>
+#ifdef CONFIG_EXYNOS_ITMON
+#include <soc/samsung/exynos-itmon.h>
+#endif
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-v4l2.h>
+
+#include "exynos_mfc_media.h"
+
+#define MFC_NUM_CONTEXTS 32
+#define MFC_MAX_PLANES 3
+#define MFC_MAX_DPBS 32
+#define MFC_MAX_BUFFERS 32
+#define MFC_MAX_EXTRA_BUF 10
+#define MFC_TIME_INDEX 15
+#define MFC_SFR_LOGGING_COUNT_SET1 4
+#define MFC_SFR_LOGGING_COUNT_SET2 23
+#define MFC_LOGGING_DATA_SIZE 256
+#define MFC_MAX_DEFAULT_PARAM 100
+
+#define HWFC_MAX_BUF 10
+#define OTF_MAX_BUF 30
+
+/* Maximum number of temporal layers */
+#define VIDEO_MAX_TEMPORAL_LAYERS 7
+
+#define MAX_NUM_IMAGES_IN_VB 8
+#define MAX_NUM_BUFCON_BUFS 32
+#define MAX_NUM_CLUSTER 3
+
+/*
+ * MFC region id for smc
+ */
+enum {
+ FC_MFC_EXYNOS_ID_MFC_SH = 0,
+ FC_MFC_EXYNOS_ID_VIDEO = 1,
+ FC_MFC_EXYNOS_ID_MFC_FW = 2,
+ FC_MFC_EXYNOS_ID_SECTBL = 3,
+ FC_MFC_EXYNOS_ID_G2D_WFD = 4,
+ FC_MFC_EXYNOS_ID_MFC_NFW = 5,
+ FC_MFC_EXYNOS_ID_VIDEO_EXT = 6,
+};
+
+/**
+ * enum s5p_mfc_inst_type - The type of an MFC device node.
+ */
+enum s5p_mfc_node_type {
+ MFCNODE_INVALID = -1,
+ MFCNODE_DECODER = 0,
+ MFCNODE_ENCODER = 1,
+ MFCNODE_DECODER_DRM = 2,
+ MFCNODE_ENCODER_DRM = 3,
+ MFCNODE_ENCODER_OTF = 4,
+ MFCNODE_ENCODER_OTF_DRM = 5,
+};
+
+/**
+ * enum s5p_mfc_inst_type - The type of an MFC instance.
+ */
+enum s5p_mfc_inst_type {
+ MFCINST_INVALID = 0,
+ MFCINST_DECODER = 1,
+ MFCINST_ENCODER = 2,
+};
+
+/**
+ * enum s5p_mfc_inst_state - The state of an MFC instance.
+ */
+enum s5p_mfc_inst_state {
+ MFCINST_FREE = 0,
+ MFCINST_INIT = 100,
+ MFCINST_GOT_INST,
+ MFCINST_HEAD_PARSED,
+ MFCINST_RUNNING_BUF_FULL,
+ MFCINST_RUNNING,
+ MFCINST_FINISHING,
+ MFCINST_RETURN_INST,
+ MFCINST_ERROR,
+ MFCINST_ABORT,
+ MFCINST_RES_CHANGE_INIT,
+ MFCINST_RES_CHANGE_FLUSH,
+ MFCINST_RES_CHANGE_END,
+ MFCINST_RUNNING_NO_OUTPUT, // Unused
+ MFCINST_ABORT_INST,
+ MFCINST_DPB_FLUSHING,
+ MFCINST_SPECIAL_PARSING,
+ MFCINST_SPECIAL_PARSING_NAL,
+};
+
+/**
+ * enum s5p_mfc_queue_state - The state of buffer queue.
+ */
+enum s5p_mfc_queue_state {
+ QUEUE_FREE = 0,
+ QUEUE_BUFS_REQUESTED,
+ QUEUE_BUFS_QUERIED,
+ QUEUE_BUFS_MMAPED,
+};
+
+enum mfc_dec_wait_state {
+ WAIT_NONE = 0,
+ WAIT_DECODING,
+ WAIT_INITBUF_DONE,
+};
+
+/**
+ * enum s5p_mfc_check_state - The state for user notification
+ */
+enum s5p_mfc_check_state {
+ MFCSTATE_PROCESSING = 0,
+ MFCSTATE_DEC_RES_DETECT,
+ MFCSTATE_DEC_TERMINATING,
+ MFCSTATE_ENC_NO_OUTPUT,
+ MFCSTATE_DEC_S3D_REALLOC,
+};
+
+enum mfc_buf_usage_type {
+ MFCBUF_INVALID = 0,
+ MFCBUF_NORMAL,
+ MFCBUF_DRM,
+ MFCBUF_NORMAL_FW,
+ MFCBUF_DRM_FW,
+};
+
+enum mfc_buf_process_type {
+ MFCBUFPROC_DEFAULT = 0x0,
+ MFCBUFPROC_COPY = (1 << 0),
+ MFCBUFPROC_SHARE = (1 << 1),
+ MFCBUFPROC_META = (1 << 2),
+ MFCBUFPROC_ANBSHARE = (1 << 3),
+ MFCBUFPROC_ANBSHARE_NV12L = (1 << 4),
+};
+
+enum s5p_mfc_ctrl_type {
+ MFC_CTRL_TYPE_GET_SRC = 0x1,
+ MFC_CTRL_TYPE_GET_DST = 0x2,
+ MFC_CTRL_TYPE_SET = 0x4,
+};
+
+enum s5p_mfc_ctrl_mode {
+ MFC_CTRL_MODE_NONE = 0x0,
+ MFC_CTRL_MODE_SFR = 0x1,
+ MFC_CTRL_MODE_CST = 0x2,
+};
+
+struct s5p_mfc_ctx;
+
+enum s5p_mfc_debug_cause {
+ MFC_CAUSE_0WRITE_PAGE_FAULT = 0,
+ MFC_CAUSE_0READ_PAGE_FAULT = 1,
+ MFC_CAUSE_1WRITE_PAGE_FAULT = 2,
+ MFC_CAUSE_1READ_PAGE_FAULT = 3,
+ MFC_CAUSE_NO_INTERRUPT = 4,
+ MFC_CAUSE_NO_SCHEDULING = 5,
+ MFC_CAUSE_FAIL_STOP_NAL_Q = 6,
+ MFC_CAUSE_FAIL_STOP_NAL_Q_FOR_OTHER = 7,
+ MFC_CAUSE_FAIL_CLOSE_INST = 8,
+ MFC_CAUSE_FAIL_SLEEP = 9,
+ MFC_CAUSE_FAIL_WAKEUP = 10,
+ MFC_CAUSE_FAIL_RISC_ON = 11,
+ MFC_CAUSE_FAIL_DPB_FLUSH = 12,
+ MFC_CAUSE_FAIL_CHACHE_FLUSH = 13,
+};
+
+struct s5p_mfc_debug {
+ u32 cause;
+ u8 fault_status;
+ u32 fault_trans_info;
+ u32 fault_addr;
+ u8 SFRs_set1[MFC_SFR_LOGGING_COUNT_SET1];
+ u32 SFRs_set2[MFC_SFR_LOGGING_COUNT_SET2];
+ char errorinfo[MFC_LOGGING_DATA_SIZE];
+};
+
+/**
+ * struct s5p_mfc_buf - MFC buffer
+ *
+ */
+struct s5p_mfc_buf {
+ struct vb2_v4l2_buffer vb;
+ struct list_head list;
+ dma_addr_t addr[MAX_NUM_IMAGES_IN_VB][MFC_MAX_PLANES];
+ struct dma_buf *dmabufs[MAX_NUM_IMAGES_IN_VB][MFC_MAX_PLANES];
+ struct dma_buf_attachment *attachments[MAX_NUM_IMAGES_IN_VB][MFC_MAX_PLANES];
+ int next_index;
+ int done_index;
+ int used;
+ int num_bufs_in_batch;
+ int num_valid_bufs;
+ unsigned char *vir_addr;
+};
+
+struct s5p_mfc_buf_queue {
+ struct list_head head;
+ unsigned int count;
+};
+
+struct s5p_mfc_bits {
+ unsigned long bits;
+ spinlock_t lock;
+};
+
+struct s5p_mfc_hwlock {
+ struct list_head waiting_list;
+ unsigned int wl_count;
+ unsigned long bits;
+ unsigned long dev;
+ unsigned int owned_by_irq;
+ unsigned int transfer_owner;
+ spinlock_t lock;
+};
+
+struct s5p_mfc_listable_wq {
+ struct list_head list;
+ wait_queue_head_t wait_queue;
+ struct mutex wait_mutex;
+ struct s5p_mfc_dev *dev;
+ struct s5p_mfc_ctx *ctx;
+};
+
+struct s5p_mfc_pm {
+ struct clk *clock;
+ atomic_t pwr_ref;
+ struct device *device;
+ spinlock_t clklock;
+
+ int clock_on_steps;
+ int clock_off_steps;
+ enum mfc_buf_usage_type base_type;
+};
+
+struct s5p_mfc_fw {
+ int date;
+ int fimv_info;
+ size_t size;
+ int status;
+ int drm_status;
+};
+
+struct s5p_mfc_ctx_buf_size {
+ size_t dev_ctx;
+ size_t h264_dec_ctx;
+ size_t other_dec_ctx;
+ size_t h264_enc_ctx;
+ size_t hevc_enc_ctx;
+ size_t other_enc_ctx;
+ size_t shared_buf;
+ size_t dbg_info_buf;
+};
+
+struct s5p_mfc_buf_size {
+ size_t firmware_code;
+ unsigned int cpb_buf;
+ void *ctx_buf;
+};
+
+struct s5p_mfc_variant {
+ struct s5p_mfc_buf_size *buf_size;
+ int num_entities;
+};
+
+enum mfc_sfr_dump_type {
+ MFC_DUMP_NONE = 0,
+ MFC_DUMP_DEC_SEQ_START = (1 << 0),
+ MFC_DUMP_DEC_INIT_BUFS = (1 << 1),
+ MFC_DUMP_DEC_NAL_START = (1 << 2),
+ MFC_DUMP_ENC_SEQ_START = (1 << 3),
+ MFC_DUMP_ENC_INIT_BUFS = (1 << 4),
+ MFC_DUMP_ENC_NAL_START = (1 << 5),
+ MFC_DUMP_ERR_INT = (1 << 6),
+ MFC_DUMP_WARN_INT = (1 << 7),
+};
+
+struct s5p_mfc_debugfs {
+ struct dentry *root;
+ struct dentry *mfc_info;
+ struct dentry *debug_info;
+ struct dentry *debug_level;
+ struct dentry *debug_ts;
+ struct dentry *dbg_enable;
+ struct dentry *nal_q_dump;
+ struct dentry *nal_q_disable;
+ struct dentry *nal_q_parallel_disable;
+ struct dentry *otf_dump;
+ struct dentry *perf_measure_option;
+ struct dentry *sfr_dump;
+ struct dentry *mmcache_dump;
+ struct dentry *mmcache_disable;
+ struct dentry *perf_boost_mode;
+};
+
+/**
+ * struct s5p_mfc_special_buf - represents internal used buffer
+ * @daddr: device virtual address
+ * @virt: kernel virtual address, only valid when the
+ * buffer accessed by driver
+ */
+struct s5p_mfc_special_buf {
+ enum mfc_buf_usage_type buftype;
+ struct dma_buf *dma_buf;
+ struct dma_buf_attachment *attachment;
+ struct sg_table *sgt;
+ dma_addr_t daddr;
+ void *vaddr;
+ size_t size;
+};
+
+#ifdef CONFIG_MFC_USE_BUS_DEVFREQ
+struct mfc_qos_bw_data {
+ unsigned long peak;
+ unsigned long read;
+ unsigned long write;
+};
+
+struct s5p_mfc_qos_bw {
+ struct mfc_qos_bw_data h264_dec_uhd_bw;
+ struct mfc_qos_bw_data hevc_dec_uhd_bw;
+ struct mfc_qos_bw_data hevc_dec_uhd_10bit_bw;
+ struct mfc_qos_bw_data vp8_dec_uhd_bw;
+ struct mfc_qos_bw_data vp9_dec_uhd_bw;
+ struct mfc_qos_bw_data mpeg4_dec_uhd_bw;
+ struct mfc_qos_bw_data h264_enc_uhd_bw;
+ struct mfc_qos_bw_data hevc_enc_uhd_bw;
+ struct mfc_qos_bw_data hevc_enc_uhd_10bit_bw;
+ struct mfc_qos_bw_data vp8_enc_uhd_bw;
+ struct mfc_qos_bw_data vp9_enc_uhd_bw;
+ struct mfc_qos_bw_data mpeg4_enc_uhd_bw;
+};
+
+/*
+ * threshold_mb - threshold of total MB(macroblock) count
+ * Total MB count can be calculated by
+ * (MB of width) * (MB of height) * fps
+ */
+struct s5p_mfc_qos {
+ unsigned int threshold_mb;
+ unsigned int freq_mfc;
+ unsigned int freq_int;
+ unsigned int freq_mif;
+ unsigned int mo_value;
+ unsigned int mo_10bit_value;
+ unsigned int mo_uhd_enc60_value;
+ unsigned int time_fw;
+};
+
+struct s5p_mfc_qos_boost {
+ unsigned int num_cluster;
+ unsigned int freq_mfc;
+ unsigned int freq_int;
+ unsigned int freq_mif;
+ unsigned int freq_cluster[MAX_NUM_CLUSTER];
+};
+#endif
+
+struct s5p_mfc_feature {
+ unsigned int support;
+ unsigned int version;
+};
+
+struct s5p_mfc_platdata {
+ /* MFC version */
+ unsigned int ip_ver;
+ /* Debug mode */
+ unsigned int debug_mode;
+ /* Sysmmu check */
+ unsigned int share_sysmmu;
+ unsigned int axid_mask;
+ unsigned int mfc_fault_num;
+ /* Features */
+ struct s5p_mfc_feature nal_q;
+ struct s5p_mfc_feature skype;
+ struct s5p_mfc_feature black_bar;
+ struct s5p_mfc_feature color_aspect_dec;
+ struct s5p_mfc_feature static_info_dec;
+ struct s5p_mfc_feature color_aspect_enc;
+ struct s5p_mfc_feature static_info_enc;
+ /* Default 10bit format for decoding */
+ unsigned int P010_decoding;
+ /* Formats */
+ unsigned int support_10bit;
+ unsigned int support_422;
+ unsigned int support_rgb;
+ /* Encoder default parameter */
+ unsigned int enc_param_num;
+ unsigned int enc_param_addr[MFC_MAX_DEFAULT_PARAM];
+ unsigned int enc_param_val[MFC_MAX_DEFAULT_PARAM];
+#ifdef CONFIG_MFC_USE_BUS_DEVFREQ
+ /* QoS */
+ unsigned int num_qos_steps;
+ unsigned int max_qos_steps;
+ unsigned int max_mb;
+ unsigned int mfc_freq_control;
+ unsigned int mo_control;
+ unsigned int bw_control;
+ struct s5p_mfc_qos *qos_table;
+ struct s5p_mfc_qos_boost *qos_boost_table;
+#endif
+};
+
+/************************ NAL_Q data structure ************************/
+#define NAL_Q_IN_ENTRY_SIZE 256
+#define NAL_Q_OUT_ENTRY_SIZE 256
+
+#define NAL_Q_IN_DEC_STR_SIZE 112
+#define NAL_Q_IN_ENC_STR_SIZE 204
+#define NAL_Q_OUT_DEC_STR_SIZE 248
+#define NAL_Q_OUT_ENC_STR_SIZE 64
+
+/* 256*128(max instance 32 * slot 4) = 32 kbytes */
+#define NAL_Q_IN_QUEUE_SIZE 128
+#define NAL_Q_OUT_QUEUE_SIZE 128
+
+typedef struct __DecoderInputStr {
+ int StartCode; /* = 0xAAAAAAAA; Decoder input structure marker */
+ int CommandId;
+ int InstanceId;
+ int PictureTag;
+ unsigned int CpbBufferAddr;
+ int CpbBufferSize;
+ int CpbBufferOffset;
+ int StreamDataSize;
+ int AvailableDpbFlagUpper;
+ int AvailableDpbFlagLower;
+ int DynamicDpbFlagUpper;
+ int DynamicDpbFlagLower;
+ unsigned int FrameAddr[3];
+ int FrameSize[3];
+ int NalStartOptions;
+ int FrameStrideSize[3];
+ int Frame2BitSize[2];
+ int Frame2BitStrideSize[2];
+ unsigned int ScratchBufAddr;
+ int ScratchBufSize;
+ char reserved[NAL_Q_IN_ENTRY_SIZE - NAL_Q_IN_DEC_STR_SIZE];
+} DecoderInputStr; /* 28*4 = 112 bytes */
+
+typedef struct __EncoderInputStr {
+ int StartCode; /* 0xBBBBBBBB; Encoder input structure marker */
+ int CommandId;
+ int InstanceId;
+ int PictureTag;
+ unsigned int FrameAddr[3];
+ unsigned int StreamBufferAddr;
+ int StreamBufferSize;
+ int StreamBufferOffset;
+ int RcRoiCtrl;
+ unsigned int RoiBufferAddr;
+ int ParamChange;
+ int IrSize;
+ int GopConfig;
+ int RcFrameRate;
+ int RcBitRate;
+ int MsliceMode;
+ int MsliceSizeMb;
+ int MsliceSizeBits;
+ int FrameInsertion;
+ int HierarchicalBitRateLayer[7];
+ int H264RefreshPeriod;
+ int HevcRefreshPeriod;
+ int RcQpBound;
+ int RcQpBoundPb;
+ int FixedPictureQp;
+ int PictureProfile;
+ int BitCountEnable;
+ int MaxBitCount;
+ int MinBitCount;
+ int NumTLayer;
+ int H264NalControl;
+ int HevcNalControl;
+ int Vp8NalControl;
+ int Vp9NalControl;
+ int H264HDSvcExtension0;
+ int H264HDSvcExtension1;
+ int GopConfig2;
+ int Frame2bitAddr[2];
+ int Weight;
+ int ExtCtbQpAddr;
+ int WeightUpper;
+ int RcMode;
+ char reserved[NAL_Q_IN_ENTRY_SIZE - NAL_Q_IN_ENC_STR_SIZE];
+} EncoderInputStr; /* 51*4 = 204 bytes */
+
+typedef struct __DecoderOutputStr {
+ int StartCode; /* 0xAAAAAAAA; Decoder output structure marker */
+ int CommandId;
+ int InstanceId;
+ int ErrorCode;
+ int PictureTagTop;
+ int PictureTimeTop;
+ int DisplayFrameWidth;
+ int DisplayFrameHeight;
+ int DisplayStatus;
+ unsigned int DisplayAddr[3];
+ int DisplayFrameType;
+ int DisplayCropInfo1;
+ int DisplayCropInfo2;
+ int DisplayPictureProfile;
+ int DisplayAspectRatio;
+ int DisplayExtendedAr;
+ int DecodedNalSize;
+ int UsedDpbFlagUpper;
+ int UsedDpbFlagLower;
+ int SeiAvail;
+ int FramePackArrgmentId;
+ int FramePackSeiInfo;
+ int FramePackGridPos;
+ int DisplayRecoverySeiInfo;
+ int H264Info;
+ int DisplayFirstCrc;
+ int DisplaySecondCrc;
+ int DisplayThirdCrc;
+ int DisplayFirst2BitCrc;
+ int DisplaySecond2BitCrc;
+ int DecodedFrameWidth;
+ int DecodedFrameHeight;
+ int DecodedStatus;
+ unsigned int DecodedAddr[3];
+ int DecodedFrameType;
+ int DecodedCropInfo1;
+ int DecodedCropInfo2;
+ int DecodedPictureProfile;
+ int DecodedRecoverySeiInfo;
+ int DecodedFirstCrc;
+ int DecodedSecondCrc;
+ int DecodedThirdCrc;
+ int DecodedFirst2BitCrc;
+ int DecodedSecond2BitCrc;
+ int PictureTagBot;
+ int PictureTimeBot;
+ int ChromaFormat;
+ int Mpeg4Info;
+ int HevcInfo;
+ int Vc1Info;
+ int VideoSignalType;
+ int ContentLightLevelInfoSei;
+ int MasteringDisplayColourVolumeSei0;
+ int MasteringDisplayColourVolumeSei1;
+ int MasteringDisplayColourVolumeSei2;
+ int MasteringDisplayColourVolumeSei3;
+ int MasteringDisplayColourVolumeSei4;
+ int MasteringDisplayColourVolumeSei5;
+ char reserved[NAL_Q_OUT_ENTRY_SIZE - NAL_Q_OUT_DEC_STR_SIZE];
+} DecoderOutputStr; /* 62*4 = 248 bytes */
+
+typedef struct __EncoderOutputStr {
+ int StartCode; /* 0xBBBBBBBB; Encoder output structure marker */
+ int CommandId;
+ int InstanceId;
+ int ErrorCode;
+ int PictureTag;
+ unsigned int EncodedFrameAddr[3];
+ unsigned int StreamBufferAddr;
+ int StreamBufferOffset;
+ int StreamSize;
+ int SliceType;
+ int NalDoneInfo;
+ unsigned int ReconLumaDpbAddr;
+ unsigned int ReconChromaDpbAddr;
+ int EncCnt;
+ char reserved[NAL_Q_OUT_ENTRY_SIZE - NAL_Q_OUT_ENC_STR_SIZE];
+} EncoderOutputStr; /* 16*4 = 64 bytes */
+
+/**
+ * enum nal_queue_state - The state for nal queue operation.
+ */
+typedef enum _nal_queue_state {
+ NAL_Q_STATE_CREATED = 0,
+ NAL_Q_STATE_STARTED, /* when s5p_mfc_nal_q_start() is called */
+ NAL_Q_STATE_STOPPED, /* when s5p_mfc_nal_q_stop() is called */
+} nal_queue_state;
+
+typedef struct _nal_in_queue {
+ union {
+ DecoderInputStr dec;
+ EncoderInputStr enc;
+ } entry[NAL_Q_IN_QUEUE_SIZE];
+} nal_in_queue;
+
+typedef struct _nal_out_queue {
+ union {
+ DecoderOutputStr dec;
+ EncoderOutputStr enc;
+ } entry[NAL_Q_OUT_QUEUE_SIZE];
+} nal_out_queue;
+
+struct _nal_queue_handle;
+typedef struct _nal_queue_in_handle {
+ struct _nal_queue_handle *nal_q_handle;
+ struct s5p_mfc_special_buf in_buf;
+ unsigned int in_exe_count;
+ nal_in_queue *nal_q_in_addr;
+} nal_queue_in_handle;
+
+typedef struct _nal_queue_out_handle {
+ struct _nal_queue_handle *nal_q_handle;
+ struct s5p_mfc_special_buf out_buf;
+ unsigned int out_exe_count;
+ nal_out_queue *nal_q_out_addr;
+ int nal_q_ctx;
+} nal_queue_out_handle;
+
+typedef struct _nal_queue_handle {
+ nal_queue_in_handle *nal_q_in_handle;
+ nal_queue_out_handle *nal_q_out_handle;
+ nal_queue_state nal_q_state;
+ unsigned int nal_q_clk_cnt;
+ spinlock_t lock;
+ int nal_q_exception;
+} nal_queue_handle;
+
+/************************ OTF data structure ************************/
+struct _otf_buf_addr {
+ dma_addr_t otf_daddr[HWFC_MAX_BUF][3];
+ struct dma_buf_attachment *otf_buf_attach[HWFC_MAX_BUF];
+};
+
+struct _otf_buf_info {
+ int pixel_format;
+ int width;
+ int height;
+ int buffer_count;
+ struct dma_buf *bufs[HWFC_MAX_BUF];
+};
+
+struct _otf_debug {
+ struct s5p_mfc_special_buf stream_buf[OTF_MAX_BUF];
+ unsigned int stream_size[OTF_MAX_BUF];
+ unsigned char frame_cnt;
+};
+
+struct _otf_handle {
+ int otf_work_bit;
+ int otf_buf_index;
+ int otf_job_id;
+ u64 otf_time_stamp;
+ struct _otf_buf_addr otf_buf_addr;
+ struct _otf_buf_info otf_buf_info;
+ struct _otf_debug otf_debug;
+};
+/********************************************************************/
+
+struct s5p_mfc_perf {
+ void __iomem *regs_base0;
+ void __iomem *regs_base1;
+
+ struct timeval begin;
+ struct timeval end;
+
+ int new_start;
+ int count;
+ int drv_margin;
+};
+
+extern struct s5p_mfc_dump_ops mfc_dump_ops;
+struct s5p_mfc_dump_ops {
+ void (*dump_regs)(struct s5p_mfc_dev *dev);
+ void (*dump_info)(struct s5p_mfc_dev *dev);
+ void (*dump_info_without_regs)(struct s5p_mfc_dev *dev);
+ void (*dump_and_stop_always)(struct s5p_mfc_dev *dev);
+ void (*dump_and_stop_debug_mode)(struct s5p_mfc_dev *dev);
+};
+
+struct s5p_mfc_mmcache {
+ void __iomem *base;
+ int is_on_status;
+};
+
+/**
+ * struct s5p_mfc_dev - The struct containing driver internal parameters.
+ */
+struct s5p_mfc_dev {
+ struct v4l2_device v4l2_dev;
+ struct video_device *vfd_dec;
+ struct video_device *vfd_enc;
+ struct video_device *vfd_dec_drm;
+ struct video_device *vfd_enc_drm;
+ struct video_device *vfd_enc_otf;
+ struct video_device *vfd_enc_otf_drm;
+ struct device *device;
+
+ void __iomem *regs_base;
+ void __iomem *sysmmu0_base;
+ void __iomem *sysmmu1_base;
+ void __iomem *hwfc_base;
+
+ int irq;
+ struct resource *mfc_mem;
+
+ struct s5p_mfc_pm pm;
+ struct s5p_mfc_fw fw;
+ struct s5p_mfc_variant *variant;
+ struct s5p_mfc_platdata *pdata;
+ struct s5p_mfc_debug *logging_data;
+
+ int num_inst;
+
+ struct mutex mfc_mutex;
+
+ int int_condition;
+ int int_reason;
+ unsigned int int_err;
+
+ wait_queue_head_t cmd_wq;
+ struct s5p_mfc_listable_wq hwlock_wq;
+
+ bool has_2sysmmu;
+ bool has_hwfc;
+ bool has_mmcache;
+
+ struct s5p_mfc_special_buf common_ctx_buf;
+ struct s5p_mfc_special_buf drm_common_ctx_buf;
+
+ struct s5p_mfc_ctx *ctx[MFC_NUM_CONTEXTS];
+ int curr_ctx;
+ int preempt_ctx;
+
+ struct s5p_mfc_bits work_bits;
+
+ struct s5p_mfc_hwlock hwlock;
+
+ atomic_t sched_wait_cnt;
+ atomic_t watchdog_tick_running;
+ atomic_t watchdog_tick_cnt;
+ atomic_t watchdog_run;
+ struct timer_list watchdog_timer;
+ struct workqueue_struct *watchdog_wq;
+ struct work_struct watchdog_work;
+
+ /* for DRM */
+ int curr_ctx_is_drm;
+ int num_drm_inst;
+ struct s5p_mfc_special_buf fw_buf;
+ struct s5p_mfc_special_buf drm_fw_buf;
+
+ struct workqueue_struct *butler_wq;
+ struct work_struct butler_work;
+
+#ifdef CONFIG_MFC_USE_BUS_DEVFREQ
+ struct list_head qos_queue;
+ atomic_t qos_req_cur;
+ struct pm_qos_request qos_req_mfc;
+ struct pm_qos_request qos_req_int;
+ struct pm_qos_request qos_req_mif;
+ struct pm_qos_request qos_req_cluster[MAX_NUM_CLUSTER];
+ int qos_has_enc_ctx;
+#endif
+ int id;
+ atomic_t clk_ref;
+
+ atomic_t trace_ref;
+ struct _mfc_trace *mfc_trace;
+ atomic_t trace_ref_hwlock;
+ struct _mfc_trace *mfc_trace_hwlock;
+ bool continue_clock_on;
+
+ bool shutdown;
+ bool sleep;
+
+ nal_queue_handle *nal_q_handle;
+
+ struct s5p_mfc_special_buf dbg_info_buf;
+
+#ifdef CONFIG_EXYNOS_BTS
+ struct bts_bw mfc_bw;
+#endif
+
+ struct s5p_mfc_debugfs debugfs;
+ struct s5p_mfc_dump_ops *dump_ops;
+
+ struct s5p_mfc_perf perf;
+
+ struct s5p_mfc_mmcache mmcache;
+
+#ifdef CONFIG_EXYNOS_ITMON
+ struct notifier_block itmon_nb;
+ int itmon_notified;
+#endif
+};
+
+/**
+ *
+ */
+struct s5p_mfc_h264_enc_params {
+ enum v4l2_mpeg_video_h264_profile profile;
+ u8 level;
+ u8 interlace;
+ enum v4l2_mpeg_video_h264_loop_filter_mode loop_filter_mode;
+ s8 loop_filter_alpha;
+ s8 loop_filter_beta;
+ enum v4l2_mpeg_video_h264_entropy_mode entropy_mode;
+ u8 _8x8_transform;
+ u8 rc_frame_qp;
+ u8 rc_min_qp;
+ u8 rc_max_qp;
+ u8 rc_min_qp_p;
+ u8 rc_max_qp_p;
+ u8 rc_min_qp_b;
+ u8 rc_max_qp_b;
+ u8 rc_mb_dark;
+ u8 rc_mb_smooth;
+ u8 rc_mb_static;
+ u8 rc_mb_activity;
+ u8 rc_p_frame_qp;
+ u8 rc_b_frame_qp;
+ u8 ar_vui;
+ enum v4l2_mpeg_video_h264_vui_sar_idc ar_vui_idc;
+ u16 ext_sar_width;
+ u16 ext_sar_height;
+ u8 open_gop;
+ u16 open_gop_size;
+ u8 hier_qp_enable;
+ enum v4l2_mpeg_video_h264_hierarchical_coding_type hier_qp_type;
+ u8 num_hier_layer;
+ u8 hier_ref_type;
+ u8 hier_qp_layer[7];
+ u32 hier_bit_layer[7];
+ u8 sei_gen_enable;
+ u8 sei_fp_curr_frame_0;
+ enum v4l2_mpeg_video_h264_sei_fp_arrangement_type sei_fp_arrangement_type;
+ u32 fmo_enable;
+ u32 fmo_slice_map_type;
+ u32 fmo_slice_num_grp;
+ u32 fmo_run_length[4];
+ u32 fmo_sg_dir;
+ u32 fmo_sg_rate;
+ u32 aso_enable;
+ u32 aso_slice_order[8];
+
+ u32 prepend_sps_pps_to_idr;
+ u8 enable_ltr;
+ u8 num_of_ltr;
+ u32 set_priority;
+ u32 base_priority;
+ u32 vui_enable;
+};
+
+/**
+ *
+ */
+struct s5p_mfc_mpeg4_enc_params {
+ /* MPEG4 Only */
+ enum v4l2_mpeg_video_mpeg4_profile profile;
+ u8 level;
+ u8 quarter_pixel;
+ u16 vop_time_res;
+ u16 vop_frm_delta;
+ u8 rc_b_frame_qp;
+ /* Common for MPEG4, H263 */
+ u8 rc_frame_qp;
+ u8 rc_min_qp;
+ u8 rc_max_qp;
+ u8 rc_min_qp_p;
+ u8 rc_max_qp_p;
+ u8 rc_min_qp_b;
+ u8 rc_max_qp_b;
+ u8 rc_p_frame_qp;
+};
+
+/**
+ *
+ */
+struct s5p_mfc_vp9_enc_params {
+ /* VP9 Only */
+ u8 vp9_version;
+ u8 rc_min_qp;
+ u8 rc_max_qp;
+ u8 rc_min_qp_p;
+ u8 rc_max_qp_p;
+ u8 rc_frame_qp;
+ u8 rc_p_frame_qp;
+ u8 vp9_goldenframesel;
+ u16 vp9_gfrefreshperiod;
+ u8 hier_qp_enable;
+ u8 hier_qp_layer[3];
+ u32 hier_bit_layer[3];
+ u8 num_hier_layer;
+ u8 max_partition_depth;
+ u8 intra_pu_split_disable;
+ u8 profile;
+};
+
+/**
+ *
+ */
+struct s5p_mfc_vp8_enc_params {
+ /* VP8 Only */
+ u8 vp8_version;
+ u8 rc_min_qp;
+ u8 rc_max_qp;
+ u8 rc_min_qp_p;
+ u8 rc_max_qp_p;
+ u8 rc_frame_qp;
+ u8 rc_p_frame_qp;
+ u8 vp8_numberofpartitions;
+ u8 vp8_filterlevel;
+ u8 vp8_filtersharpness;
+ u8 vp8_goldenframesel;
+ u16 vp8_gfrefreshperiod;
+ u8 hier_qp_enable;
+ u8 hier_qp_layer[3];
+ u32 hier_bit_layer[3];
+ u8 intra_4x4mode_disable;
+ u8 num_hier_layer;
+};
+
+/**
+ *
+ */
+struct s5p_mfc_hevc_enc_params {
+ u8 profile;
+ u8 level;
+ u8 tier_flag;
+ /* HEVC Only */
+ u8 rc_min_qp;
+ u8 rc_max_qp;
+ u8 rc_min_qp_p;
+ u8 rc_max_qp_p;
+ u8 rc_min_qp_b;
+ u8 rc_max_qp_b;
+ u8 rc_lcu_dark;
+ u8 rc_lcu_smooth;
+ u8 rc_lcu_static;
+ u8 rc_lcu_activity;
+ u8 rc_frame_qp;
+ u8 rc_p_frame_qp;
+ u8 rc_b_frame_qp;
+ u8 max_partition_depth;
+ u8 refreshtype;
+ u16 refreshperiod;
+ s32 lf_beta_offset_div2;
+ s32 lf_tc_offset_div2;
+ u8 loopfilter_disable;
+ u8 loopfilter_across;
+ u8 nal_control_length_filed;
+ u8 nal_control_user_ref;
+ u8 nal_control_store_ref;
+ u8 const_intra_period_enable;
+ u8 lossless_cu_enable;
+ u8 wavefront_enable;
+ u8 enable_ltr;
+ u8 hier_qp_enable;
+ enum v4l2_mpeg_video_hevc_hierarchical_coding_type hier_qp_type;
+ u8 hier_ref_type;
+ u8 num_hier_layer;
+ u8 hier_qp_layer[7];
+ u32 hier_bit_layer[7];
+ u8 general_pb_enable;
+ u8 temporal_id_enable;
+ u8 strong_intra_smooth;
+ u8 intra_pu_split_disable;
+ u8 tmv_prediction_disable;
+ u8 max_num_merge_mv;
+ u8 eco_mode_enable;
+ u8 encoding_nostartcode_enable;
+ u8 size_of_length_field;
+ u8 user_ref;
+ u8 store_ref;
+ u8 prepend_sps_pps_to_idr;
+};
+
+/**
+ *
+ */
+struct s5p_mfc_bpg_enc_params {
+ u32 thumb_size;
+ u32 exif_size;
+};
+
+/**
+ *
+ */
+struct s5p_mfc_enc_params {
+ u16 width;
+ u16 height;
+
+ u32 gop_size;
+ enum v4l2_mpeg_video_multi_slice_mode slice_mode;
+ u32 slice_mb;
+ u32 slice_bit;
+ u32 slice_mb_row;
+ u32 intra_refresh_mb;
+ u8 pad;
+ u8 pad_luma;
+ u8 pad_cb;
+ u8 pad_cr;
+ u8 rc_frame;
+ u32 rc_bitrate;
+ u32 rc_framerate;
+ u16 rc_reaction_coeff;
+ u32 config_qp;
+ u32 dynamic_qp;
+ u8 frame_tag;
+ u8 ratio_intra;
+
+ u8 num_b_frame; /* H.264, HEVC, MPEG4 */
+ u8 num_refs_for_p; /* H.264, HEVC, VP8, VP9 */
+ u8 rc_mb; /* H.264: MFCv5, MPEG4/H.263: MFCv6 */
+ u8 rc_pvc;
+ u16 vbv_buf_size;
+ enum v4l2_mpeg_video_header_mode seq_hdr_mode;
+ enum v4l2_mpeg_mfc51_video_frame_skip_mode frame_skip_mode;
+ u8 fixed_target_bit;
+ u8 num_hier_max_layer;
+ u8 hier_bitrate_ctrl;
+ u8 weighted_enable;
+ u8 roi_enable;
+ u8 ivf_header_disable; /* VP8, VP9 */
+
+ u16 rc_frame_delta; /* MFC6.1 Only */
+
+ u32 i_frm_ctrl_mode;
+ u32 i_frm_ctrl;
+
+ u32 check_color_range;
+ u32 color_range;
+ u32 colour_primaries;
+ u32 transfer_characteristics;
+ u32 matrix_coefficients;
+
+ u32 static_info_enable;
+ u32 max_pic_average_light;
+ u32 max_content_light;
+ u32 max_display_luminance;
+ u32 min_display_luminance;
+ u32 white_point;
+ u32 display_primaries_0;
+ u32 display_primaries_1;
+ u32 display_primaries_2;
+
+ union {
+ struct s5p_mfc_h264_enc_params h264;
+ struct s5p_mfc_mpeg4_enc_params mpeg4;
+ struct s5p_mfc_vp8_enc_params vp8;
+ struct s5p_mfc_vp9_enc_params vp9;
+ struct s5p_mfc_hevc_enc_params hevc;
+ struct s5p_mfc_bpg_enc_params bpg;
+ } codec;
+};
+
+struct s5p_mfc_ctx_ctrl {
+ struct list_head list;
+ enum s5p_mfc_ctrl_type type;
+ unsigned int id;
+ unsigned int addr;
+ int has_new;
+ int val;
+};
+
+struct s5p_mfc_buf_ctrl {
+ struct list_head list;
+ unsigned int id;
+ enum s5p_mfc_ctrl_type type;
+ int has_new;
+ int val;
+ unsigned int old_val; /* only for MFC_CTRL_TYPE_SET */
+ unsigned int old_val2; /* only for MFC_CTRL_TYPE_SET */
+ unsigned int is_volatile; /* only for MFC_CTRL_TYPE_SET */
+ unsigned int updated;
+ unsigned int mode;
+ unsigned int addr;
+ unsigned int mask;
+ unsigned int shft;
+ unsigned int flag_mode; /* only for MFC_CTRL_TYPE_SET */
+ unsigned int flag_addr; /* only for MFC_CTRL_TYPE_SET */
+ unsigned int flag_shft; /* only for MFC_CTRL_TYPE_SET */
+ int (*read_cst) (struct s5p_mfc_ctx *ctx,
+ struct s5p_mfc_buf_ctrl *buf_ctrl);
+ void (*write_cst) (struct s5p_mfc_ctx *ctx,
+ struct s5p_mfc_buf_ctrl *buf_ctrl);
+};
+
+struct s5p_mfc_ctrl_cfg {
+ enum s5p_mfc_ctrl_type type;
+ unsigned int id;
+ unsigned int is_volatile; /* only for MFC_CTRL_TYPE_SET */
+ unsigned int mode;
+ unsigned int addr;
+ unsigned int mask;
+ unsigned int shft;
+ unsigned int flag_mode; /* only for MFC_CTRL_TYPE_SET */
+ unsigned int flag_addr; /* only for MFC_CTRL_TYPE_SET */
+ unsigned int flag_shft; /* only for MFC_CTRL_TYPE_SET */
+ int (*read_cst) (struct s5p_mfc_ctx *ctx,
+ struct s5p_mfc_buf_ctrl *buf_ctrl);
+ void (*write_cst) (struct s5p_mfc_ctx *ctx,
+ struct s5p_mfc_buf_ctrl *buf_ctrl);
+};
+
+/* per buffer contol */
+struct s5p_mfc_ctrls_ops {
+ /* controls per buffer */
+ int (*init_ctx_ctrls) (struct s5p_mfc_ctx *ctx);
+ int (*cleanup_ctx_ctrls) (struct s5p_mfc_ctx *ctx);
+ int (*init_buf_ctrls) (struct s5p_mfc_ctx *ctx,
+ enum s5p_mfc_ctrl_type type, unsigned int index);
+ void (*reset_buf_ctrls) (struct list_head *head);
+ int (*cleanup_buf_ctrls) (struct s5p_mfc_ctx *ctx,
+ enum s5p_mfc_ctrl_type type, unsigned int index);
+ int (*to_buf_ctrls) (struct s5p_mfc_ctx *ctx, struct list_head *head);
+ int (*to_ctx_ctrls) (struct s5p_mfc_ctx *ctx, struct list_head *head);
+ int (*set_buf_ctrls_val) (struct s5p_mfc_ctx *ctx,
+ struct list_head *head);
+ int (*get_buf_ctrls_val) (struct s5p_mfc_ctx *ctx,
+ struct list_head *head);
+ int (*recover_buf_ctrls_val) (struct s5p_mfc_ctx *ctx,
+ struct list_head *head);
+ int (*get_buf_update_val) (struct s5p_mfc_ctx *ctx,
+ struct list_head *head, unsigned int id, int value);
+ int (*set_buf_ctrls_val_nal_q_dec) (struct s5p_mfc_ctx *ctx,
+ struct list_head *head, DecoderInputStr *pInStr);
+ int (*get_buf_ctrls_val_nal_q_dec) (struct s5p_mfc_ctx *ctx,
+ struct list_head *head, DecoderOutputStr *pOutStr);
+ int (*set_buf_ctrls_val_nal_q_enc) (struct s5p_mfc_ctx *ctx,
+ struct list_head *head, EncoderInputStr *pInStr);
+ int (*get_buf_ctrls_val_nal_q_enc) (struct s5p_mfc_ctx *ctx,
+ struct list_head *head, EncoderOutputStr *pOutStr);
+ int (*recover_buf_ctrls_nal_q) (struct s5p_mfc_ctx *ctx,
+ struct list_head *head);
+};
+
+struct stored_dpb_info {
+ int fd[MFC_MAX_PLANES];
+};
+
+struct dec_dpb_ref_info {
+ int index;
+ struct stored_dpb_info dpb[MFC_MAX_DPBS];
+};
+
+struct temporal_layer_info {
+ unsigned int temporal_layer_count;
+ unsigned int temporal_layer_bitrate[VIDEO_MAX_TEMPORAL_LAYERS];
+};
+
+struct mfc_enc_roi_info {
+ char *addr;
+ int size;
+ int upper_qp;
+ int lower_qp;
+ bool enable;
+};
+
+struct mfc_user_shared_handle {
+ int fd;
+ struct dma_buf *dma_buf;
+ void *vaddr;
+};
+
+struct s5p_mfc_raw_info {
+ int num_planes;
+ int stride[3];
+ int plane_size[3];
+ int stride_2bits[3];
+ int plane_size_2bits[3];
+ unsigned int total_plane_size;
+};
+
+struct mfc_timestamp {
+ struct list_head list;
+ struct timeval timestamp;
+ int index;
+ int interval;
+};
+
+struct s5p_mfc_dec {
+ int total_dpb_count;
+
+ unsigned int src_buf_size;
+
+ int loop_filter_mpeg4;
+ int display_delay;
+ int immediate_display;
+ int slice_enable;
+ int mv_count;
+ int idr_decoding;
+ int is_interlaced;
+ int is_dts_mode;
+
+ int crc_enable;
+ int crc_luma0;
+ int crc_chroma0;
+ int crc_luma1;
+ int crc_chroma1;
+
+ unsigned long consumed;
+ unsigned long remained_size;
+
+ enum v4l2_memory dst_memtype;
+ int sei_parse;
+ int stored_tag;
+ dma_addr_t y_addr_for_pb;
+
+ int cr_left, cr_right, cr_top, cr_bot;
+
+ int detect_black_bar;
+ bool black_bar_updated;
+ struct v4l2_rect black_bar;
+
+ /* For dynamic DPB */
+ int is_dynamic_dpb;
+ unsigned long available_dpb;
+ unsigned int dynamic_set;
+ unsigned int dynamic_used;
+
+ struct dec_dpb_ref_info *ref_info;
+ int assigned_fd[MFC_MAX_DPBS];
+ struct mfc_user_shared_handle sh_handle;
+ struct s5p_mfc_buf *assigned_dpb[MFC_MAX_DPBS];
+
+ int has_multiframe;
+ int is_dpb_full;
+
+ unsigned int err_reuse_flag;
+ unsigned int dec_only_release_flag;
+
+ /* for debugging about black bar detection */
+ void *frame_vaddr[3][30];
+ dma_addr_t frame_daddr[3][30];
+ int index[3][30];
+ int fd[3][30];
+ unsigned int frame_size[3][30];
+ unsigned char frame_cnt;
+
+ unsigned int num_of_tile_over_4;
+
+ unsigned int color_range;
+ unsigned int color_space;
+};
+
+struct s5p_mfc_enc {
+ struct s5p_mfc_enc_params params;
+
+ unsigned int dst_buf_size;
+ unsigned int header_size;
+
+ enum v4l2_mpeg_mfc51_video_frame_type frame_type;
+ enum v4l2_mpeg_mfc51_video_force_frame_type force_frame_type;
+
+ size_t luma_dpb_size;
+ size_t chroma_dpb_size;
+ size_t me_buffer_size;
+ size_t tmv_buffer_size;
+
+ unsigned int slice_mode;
+ union {
+ unsigned int mb;
+ unsigned int bits;
+ } slice_size;
+ unsigned int in_slice;
+ unsigned int buf_full;
+
+ int stored_tag;
+ struct mfc_user_shared_handle sh_handle_svc;
+ struct mfc_user_shared_handle sh_handle_roi;
+ int roi_index;
+ struct s5p_mfc_special_buf roi_buf[MFC_MAX_EXTRA_BUF];
+ struct mfc_enc_roi_info roi_info[MFC_MAX_EXTRA_BUF];
+};
+
+struct s5p_mfc_fmt {
+ char *name;
+ u32 fourcc;
+ u32 codec_mode;
+ u32 type;
+ u32 num_planes;
+ u32 mem_planes;
+};
+
+/**
+ * struct s5p_mfc_ctx - This struct contains the instance context
+ */
+struct s5p_mfc_ctx {
+ struct s5p_mfc_dev *dev;
+ struct v4l2_fh fh;
+ int num;
+
+ int int_condition;
+ int int_reason;
+ unsigned int int_err;
+
+ wait_queue_head_t cmd_wq;
+ struct s5p_mfc_listable_wq hwlock_wq;
+
+ struct s5p_mfc_fmt *src_fmt;
+ struct s5p_mfc_fmt *dst_fmt;
+
+ struct vb2_queue vq_src;
+ struct vb2_queue vq_dst;
+
+ struct s5p_mfc_buf_queue src_buf_queue;
+ struct s5p_mfc_buf_queue dst_buf_queue;
+ struct s5p_mfc_buf_queue src_buf_nal_queue;
+ struct s5p_mfc_buf_queue dst_buf_nal_queue;
+ struct s5p_mfc_buf_queue ref_buf_queue;
+ spinlock_t buf_queue_lock;
+
+ enum s5p_mfc_inst_type type;
+ enum s5p_mfc_inst_state state;
+ int inst_no;
+
+ int img_width;
+ int img_height;
+ int crop_width;
+ int crop_height;
+ int crop_left;
+ int crop_top;
+ int dpb_count;
+ int buf_stride;
+
+ int min_dpb_size[3];
+
+ struct s5p_mfc_raw_info raw_buf;
+ size_t mv_size;
+
+ struct s5p_mfc_special_buf codec_buf;
+ int codec_buffer_allocated;
+
+ enum s5p_mfc_queue_state capture_state;
+ enum s5p_mfc_queue_state output_state;
+
+ struct list_head ctrls;
+
+ struct list_head src_ctrls[MFC_MAX_BUFFERS];
+ struct list_head dst_ctrls[MFC_MAX_BUFFERS];
+
+ unsigned long src_ctrls_avail;
+ unsigned long dst_ctrls_avail;
+
+ unsigned int sequence;
+
+ /* Control values */
+ int codec_mode;
+ __u32 pix_format;
+
+ /* Extra Buffers */
+ struct s5p_mfc_special_buf instance_ctx_buf;
+
+ struct s5p_mfc_dec *dec_priv;
+ struct s5p_mfc_enc *enc_priv;
+
+ struct s5p_mfc_ctrls_ops *c_ops;
+
+ size_t scratch_buf_size;
+ size_t loopfilter_luma_size;
+ size_t loopfilter_chroma_size;
+
+ /* Profile infomation */
+ int is_10bit;
+ int is_422;
+
+ /* for DRM */
+ int is_drm;
+
+ int is_dpb_realloc;
+ enum mfc_dec_wait_state wait_state;
+ int clear_work_bit;
+
+#ifdef CONFIG_MFC_USE_BUS_DEVFREQ
+ int qos_req_step;
+ struct list_head qos_list;
+#endif
+ unsigned int qos_ratio;
+ unsigned long framerate;
+ unsigned long last_framerate;
+
+ struct mfc_timestamp ts_array[MFC_TIME_INDEX];
+ struct list_head ts_list;
+ int ts_count;
+ int ts_is_full;
+
+ int buf_process_type;
+
+ unsigned long raw_protect_flag;
+ unsigned long stream_protect_flag;
+ struct _otf_handle *otf_handle;
+
+ int batch_mode;
+ bool check_dump;
+};
+
+#endif /* __MFC_DATA_STRUCT_H */
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_debug.h
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __MFC_DEBUG_H
+#define __MFC_DEBUG_H __FILE__
+
+#define DEBUG
+
+#ifdef DEBUG
+
+extern unsigned int debug_level;
+extern unsigned int debug_ts;
+extern unsigned int dbg_enable;
+extern unsigned int nal_q_dump;
+extern unsigned int nal_q_disable;
+extern unsigned int nal_q_parallel_disable;
+extern unsigned int otf_dump;
+extern unsigned int sfr_dump;
+extern unsigned int mmcache_dump;
+extern unsigned int mmcache_disable;
+extern unsigned int perf_boost_mode;
+
+#define mfc_debug(level, fmt, args...) \
+ do { \
+ if (debug_level >= level) \
+ printk(KERN_DEBUG "%s:%d: " fmt, \
+ __func__, __LINE__, ##args); \
+ } while (0)
+#else
+#define mfc_debug(fmt, args...)
+#endif
+
+#define mfc_debug_enter() mfc_debug(5, "enter\n")
+#define mfc_debug_leave() mfc_debug(5, "leave\n")
+
+#define mfc_err_dev(fmt, args...) \
+ do { \
+ printk(KERN_ERR "%s:%d: " fmt, \
+ __func__, __LINE__, ##args); \
+ } while (0)
+
+#define mfc_err_ctx(fmt, args...) \
+ do { \
+ printk(KERN_ERR "[c:%d] %s:%d: " fmt, \
+ ctx->num, \
+ __func__, __LINE__, ##args); \
+ } while (0)
+
+#define mfc_info_dev(fmt, args...) \
+ do { \
+ printk(KERN_INFO "%s:%d: " fmt, \
+ __func__, __LINE__, ##args); \
+ } while (0)
+
+#define mfc_info_ctx(fmt, args...) \
+ do { \
+ printk(KERN_INFO "[c:%d] %s:%d: " fmt, \
+ ctx->num, \
+ __func__, __LINE__, ##args); \
+ } while (0)
+
+#define MFC_TRACE_STR_LEN 80
+#define MFC_TRACE_COUNT_MAX 1024
+#define MFC_TRACE_COUNT_PRINT 30
+
+struct _mfc_trace {
+ unsigned long long time;
+ char str[MFC_TRACE_STR_LEN];
+};
+
+/* If there is no ctx structure */
+#define MFC_TRACE_DEV(fmt, args...) \
+ do { \
+ int cpu = raw_smp_processor_id(); \
+ int cnt; \
+ cnt = atomic_inc_return(&dev->trace_ref) & (MFC_TRACE_COUNT_MAX - 1); \
+ dev->mfc_trace[cnt].time = cpu_clock(cpu); \
+ snprintf(dev->mfc_trace[cnt].str, MFC_TRACE_STR_LEN, \
+ fmt, ##args); \
+ } while (0)
+
+/* If there is ctx structure */
+#define MFC_TRACE_CTX(fmt, args...) \
+ do { \
+ int cpu = raw_smp_processor_id(); \
+ int cnt; \
+ cnt = atomic_inc_return(&dev->trace_ref) & (MFC_TRACE_COUNT_MAX - 1); \
+ dev->mfc_trace[cnt].time = cpu_clock(cpu); \
+ snprintf(dev->mfc_trace[cnt].str, MFC_TRACE_STR_LEN, \
+ "[c:%d] " fmt, ctx->num, ##args); \
+ } while (0)
+
+
+/* If there is no ctx structure */
+#define MFC_TRACE_DEV_HWLOCK(fmt, args...) \
+ do { \
+ int cpu = raw_smp_processor_id(); \
+ int cnt; \
+ cnt = atomic_inc_return(&dev->trace_ref_hwlock) & (MFC_TRACE_COUNT_MAX - 1); \
+ dev->mfc_trace_hwlock[cnt].time = cpu_clock(cpu); \
+ snprintf(dev->mfc_trace_hwlock[cnt].str, MFC_TRACE_STR_LEN, \
+ fmt, ##args); \
+ } while (0)
+
+/* If there is ctx structure */
+#define MFC_TRACE_CTX_HWLOCK(fmt, args...) \
+ do { \
+ int cpu = raw_smp_processor_id(); \
+ int cnt; \
+ cnt = atomic_inc_return(&dev->trace_ref_hwlock) & (MFC_TRACE_COUNT_MAX - 1); \
+ dev->mfc_trace_hwlock[cnt].time = cpu_clock(cpu); \
+ snprintf(dev->mfc_trace_hwlock[cnt].str, MFC_TRACE_STR_LEN, \
+ "[c:%d] " fmt, ctx->num, ##args); \
+ } while (0)
+
+
+#endif /* __MFC_DEBUG_H */
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_debug.c
+ *
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+#include "mfc_debugfs.h"
+#include "mfc_sync.h"
+
+#include "mfc_pm.h"
+
+#include "mfc_queue.h"
+
+unsigned int debug_level;
+unsigned int debug_ts;
+unsigned int dbg_enable;
+unsigned int nal_q_dump;
+unsigned int nal_q_disable;
+unsigned int nal_q_parallel_disable;
+unsigned int otf_dump;
+unsigned int perf_measure_option;
+unsigned int sfr_dump;
+unsigned int mmcache_dump;
+unsigned int mmcache_disable;
+unsigned int perf_boost_mode;
+
+static int mfc_info_show(struct seq_file *s, void *unused)
+{
+ struct s5p_mfc_dev *dev = s->private;
+ struct s5p_mfc_ctx *ctx = NULL;
+ int i;
+ char *codec_name = NULL;
+
+ seq_puts(s, ">> MFC device information(common)\n");
+ seq_printf(s, "[VERSION] H/W: v%x.%x, F/W: %06x(%c), DRV: %d\n",
+ MFC_VER_MAJOR(dev), MFC_VER_MINOR(dev), dev->fw.date,
+ dev->fw.fimv_info, MFC_DRIVER_INFO);
+ seq_printf(s, "[PM] power: %d, clock: %d\n",
+ s5p_mfc_pm_get_pwr_ref_cnt(dev), s5p_mfc_pm_get_clk_ref_cnt(dev));
+ seq_printf(s, "[CTX] num_inst: %d, num_drm_inst: %d, curr_ctx: %d(is_drm: %d)\n",
+ dev->num_inst, dev->num_drm_inst, dev->curr_ctx, dev->curr_ctx_is_drm);
+ seq_printf(s, "[HWLOCK] bits: %#lx, dev: %#lx, owned_by_irq = %d, wl_count = %d\n",
+ dev->hwlock.bits, dev->hwlock.dev,
+ dev->hwlock.owned_by_irq, dev->hwlock.wl_count);
+ seq_printf(s, "[DEBUG MODE] %s\n", dev->pdata->debug_mode ? "enabled" : "disabled");
+ seq_printf(s, "[MMCACHE] %s(%s)\n",
+ dev->has_mmcache ? "supported" : "not supported",
+ dev->mmcache.is_on_status ? "enabled" : "disabled");
+ seq_printf(s, "[PERF BOOST] %s\n", perf_boost_mode ? "enabled" : "disabled");
+ seq_printf(s, "[FEATURES] nal_q: %d(0x%x), skype: %d(0x%x), black_bar: %d(0x%x)\n",
+ dev->pdata->nal_q.support, dev->pdata->nal_q.version,
+ dev->pdata->skype.support, dev->pdata->skype.version,
+ dev->pdata->black_bar.support, dev->pdata->black_bar.version);
+ seq_printf(s, " color_aspect_dec: %d(0x%x), enc: %d(0x%x)\n",
+ dev->pdata->color_aspect_dec.support, dev->pdata->color_aspect_dec.version,
+ dev->pdata->color_aspect_enc.support, dev->pdata->color_aspect_enc.version);
+ seq_printf(s, " static_info_dec: %d(0x%x), enc: %d(0x%x)\n",
+ dev->pdata->static_info_dec.support, dev->pdata->static_info_dec.version,
+ dev->pdata->static_info_enc.support, dev->pdata->static_info_enc.version);
+ seq_printf(s, "[FORMATS] 10bit: %s, 422: %s, RGB: %s\n",
+ dev->pdata->support_10bit ? "supported" : "not supported",
+ dev->pdata->support_422 ? "supported" : "not supported",
+ dev->pdata->support_rgb ? "supported" : "not supported");
+ seq_printf(s, "[LOWMEM] is_low_mem: %d\n", IS_LOW_MEM);
+ if (dev->nal_q_handle)
+ seq_printf(s, "[NAL-Q] state: %d\n", dev->nal_q_handle->nal_q_state);
+
+ seq_puts(s, ">> MFC device information(instance)\n");
+ for (i = 0; i < MFC_NUM_CONTEXTS; i++) {
+ ctx = dev->ctx[i];
+ if (ctx) {
+ if (ctx->type == MFCINST_DECODER)
+ codec_name = ctx->src_fmt->name;
+ else
+ codec_name = ctx->dst_fmt->name;
+
+ seq_printf(s, "[CTX:%d] codec: %s(%s), width: %d, height: %d, crop: %d %d %d %d, state: %d\n",
+ ctx->num, ctx->type == MFCINST_DECODER ? "DEC" : "ENC", codec_name,
+ ctx->img_width, ctx->img_height, ctx->crop_width, ctx->crop_height,
+ ctx->crop_left, ctx->crop_top, ctx->state);
+ seq_printf(s, " queue(src: %d, dst: %d, src_nal: %d, dst_nal: %d, ref: %d)\n",
+ s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->src_buf_queue),
+ s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->dst_buf_queue),
+ s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->src_buf_nal_queue),
+ s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->dst_buf_nal_queue),
+ s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->ref_buf_queue));
+ }
+ }
+
+ return 0;
+}
+
+static int mfc_debug_info_show(struct seq_file *s, void *unused)
+{
+ seq_puts(s, ">> MFC debug information\n");
+
+ seq_puts(s, "-----SFR dump options (bit setting)\n");
+ seq_puts(s, "ex) echo 0xff > /d/mfc/sfr_dump (all dump mode)\n");
+ seq_puts(s, "1 (1 << 0): dec SEQ_START\n");
+ seq_puts(s, "2 (1 << 1): dec INIT_BUFS\n");
+ seq_puts(s, "4 (1 << 2): dec NAL_START\n");
+ seq_puts(s, "8 (1 << 3): enc SEQ_START\n");
+ seq_puts(s, "16 (1 << 4): enc INIT_BUFS\n");
+ seq_puts(s, "32 (1 << 5): enc NAL_START\n");
+ seq_puts(s, "64 (1 << 6): ERR interrupt\n");
+ seq_puts(s, "128 (1 << 7): WARN interrupt\n");
+
+ seq_puts(s, "-----Performance boost options (bit setting)\n");
+ seq_puts(s, "ex) echo 7 > /d/mfc/perf_boost_mode (max freq)\n");
+ seq_puts(s, "1 (1 << 0): DVFS (INT/MFC/MIF)\n");
+ seq_puts(s, "2 (1 << 1): MO value\n");
+ seq_puts(s, "4 (1 << 2): CPU frequency\n");
+
+ return 0;
+}
+
+static int mfc_info_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, mfc_info_show, inode->i_private);
+}
+
+static int mfc_debug_info_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, mfc_debug_info_show, inode->i_private);
+}
+
+static const struct file_operations mfc_info_fops = {
+ .open = mfc_info_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations debug_info_fops = {
+ .open = mfc_debug_info_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+void s5p_mfc_init_debugfs(struct s5p_mfc_dev *dev)
+{
+ struct s5p_mfc_debugfs *debugfs = &dev->debugfs;
+
+ debugfs->root = debugfs_create_dir("mfc", NULL);
+ if (!debugfs->root) {
+ mfc_err_dev("debugfs: failed to create root derectory\n");
+ return;
+ }
+
+ debugfs->mfc_info = debugfs_create_file("mfc_info",
+ 0444, debugfs->root, dev, &mfc_info_fops);
+ debugfs->debug_info = debugfs_create_file("debug_info",
+ 0444, debugfs->root, dev, &debug_info_fops);
+ debugfs->debug_level = debugfs_create_u32("debug",
+ 0644, debugfs->root, &debug_level);
+ debugfs->debug_ts = debugfs_create_u32("debug_ts",
+ 0644, debugfs->root, &debug_ts);
+ debugfs->dbg_enable = debugfs_create_u32("dbg_enable",
+ 0644, debugfs->root, &dbg_enable);
+ debugfs->nal_q_dump = debugfs_create_u32("nal_q_dump",
+ 0644, debugfs->root, &nal_q_dump);
+ debugfs->nal_q_disable = debugfs_create_u32("nal_q_disable",
+ 0644, debugfs->root, &nal_q_disable);
+ debugfs->nal_q_parallel_disable = debugfs_create_u32("nal_q_parallel_disable",
+ 0644, debugfs->root, &nal_q_parallel_disable);
+ debugfs->otf_dump = debugfs_create_u32("otf_dump",
+ 0644, debugfs->root, &otf_dump);
+ debugfs->perf_measure_option = debugfs_create_u32("perf_measure_option",
+ 0644, debugfs->root, &perf_measure_option);
+ debugfs->sfr_dump = debugfs_create_u32("sfr_dump",
+ 0644, debugfs->root, &sfr_dump);
+ debugfs->mmcache_dump = debugfs_create_u32("mmcache_dump",
+ 0644, debugfs->root, &mmcache_dump);
+ debugfs->mmcache_disable = debugfs_create_u32("mmcache_disable",
+ 0644, debugfs->root, &mmcache_disable);
+ debugfs->perf_boost_mode = debugfs_create_u32("perf_boost_mode",
+ 0644, debugfs->root, &perf_boost_mode);
+}
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_debugfs.h
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __MFC_DEBUGFS_H
+#define __MFC_DEBUGFS_H __FILE__
+
+#include "mfc_common.h"
+
+void s5p_mfc_init_debugfs(struct s5p_mfc_dev *dev);
+
+#endif /* __MFC_DEBUGFS_H */
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_dec.c
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "mfc_dec.h"
+#include "mfc_dec_internal.h"
+
+#include "mfc_hwlock.h"
+#include "mfc_opr.h"
+#include "mfc_sync.h"
+#include "mfc_mmcache.h"
+
+#include "mfc_qos.h"
+#include "mfc_queue.h"
+#include "mfc_utils.h"
+#include "mfc_buf.h"
+#include "mfc_mem.h"
+
+#define MAX_FRAME_SIZE (2*1024*1024)
+
+/* Find selected format description */
+static struct s5p_mfc_fmt *mfc_dec_find_format(struct s5p_mfc_ctx *ctx,
+ unsigned int pixelformat)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_fmt *fmt = NULL;
+ unsigned long i;
+
+ for (i = 0; i < NUM_FORMATS; i++) {
+ if (dec_formats[i].fourcc == pixelformat) {
+ fmt = (struct s5p_mfc_fmt *)&dec_formats[i];
+ break;
+ }
+ }
+
+ if (!dev->pdata->support_10bit && (fmt->type & MFC_FMT_10BIT)) {
+ mfc_err_ctx("[FRAME] 10bit is not supported\n");
+ fmt = NULL;
+ }
+ if (!dev->pdata->support_422 && (fmt->type & MFC_FMT_422)) {
+ mfc_err_ctx("[FRAME] 422 is not supported\n");
+ fmt = NULL;
+ }
+
+ return fmt;
+}
+
+static struct v4l2_queryctrl *mfc_dec_get_ctrl(int id)
+{
+ unsigned long i;
+
+ for (i = 0; i < NUM_CTRLS; ++i)
+ if (id == controls[i].id)
+ return &controls[i];
+
+ return NULL;
+}
+
+/* Check whether a ctrl value if correct */
+static int mfc_dec_check_ctrl_val(struct s5p_mfc_ctx *ctx, struct v4l2_control *ctrl)
+{
+ struct v4l2_queryctrl *c;
+
+ c = mfc_dec_get_ctrl(ctrl->id);
+ if (!c) {
+ mfc_err_ctx("[CTRLS] not supported control id (%#x)\n", ctrl->id);
+ return -EINVAL;
+ }
+
+ if (ctrl->value < c->minimum || ctrl->value > c->maximum
+ || (c->step != 0 && ctrl->value % c->step != 0)) {
+ mfc_err_ctx("[CTRLS] Invalid control value (%#x)\n", ctrl->value);
+ return -ERANGE;
+ }
+
+ return 0;
+}
+
+/* Query capabilities of the device */
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ strncpy(cap->driver, "MFC", sizeof(cap->driver) - 1);
+ strncpy(cap->card, "decoder", sizeof(cap->card) - 1);
+ cap->bus_info[0] = 0;
+ cap->version = KERNEL_VERSION(1, 0, 0);
+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE
+ | V4L2_CAP_VIDEO_OUTPUT
+ | V4L2_CAP_VIDEO_CAPTURE_MPLANE
+ | V4L2_CAP_VIDEO_OUTPUT_MPLANE
+ | V4L2_CAP_STREAMING
+ | V4L2_CAP_DEVICE_CAPS;
+
+ cap->capabilities = cap->device_caps;
+
+ return 0;
+}
+
+static int mfc_dec_enum_fmt(struct s5p_mfc_dev *dev, struct v4l2_fmtdesc *f,
+ unsigned int type)
+{
+ struct s5p_mfc_fmt *fmt;
+ unsigned long i, j = 0;
+
+ for (i = 0; i < NUM_FORMATS; ++i) {
+ if (!(dec_formats[i].type & type))
+ continue;
+ if (!dev->pdata->support_10bit && (dec_formats[i].type & MFC_FMT_10BIT))
+ continue;
+ if (!dev->pdata->support_422 && (dec_formats[i].type & MFC_FMT_422))
+ continue;
+
+ if (j == f->index) {
+ fmt = &dec_formats[i];
+ strlcpy(f->description, fmt->name,
+ sizeof(f->description));
+ f->pixelformat = fmt->fourcc;
+
+ return 0;
+ }
+
+ ++j;
+ }
+
+ return -EINVAL;
+}
+
+static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv,
+ struct v4l2_fmtdesc *f)
+{
+ struct s5p_mfc_dev *dev = video_drvdata(file);
+
+ return mfc_dec_enum_fmt(dev, f, MFC_FMT_FRAME);
+}
+
+static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *prov,
+ struct v4l2_fmtdesc *f)
+{
+ struct s5p_mfc_dev *dev = video_drvdata(file);
+
+ return mfc_dec_enum_fmt(dev, f, MFC_FMT_STREAM);
+}
+
+static void mfc_dec_change_format(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ u32 org_fmt = ctx->dst_fmt->fourcc;
+
+ if (ctx->is_10bit && ctx->is_422) {
+ switch (org_fmt) {
+ case V4L2_PIX_FMT_NV16M_S10B:
+ case V4L2_PIX_FMT_NV61M_S10B:
+ case V4L2_PIX_FMT_NV16M_P210:
+ case V4L2_PIX_FMT_NV61M_P210:
+ /* It is right format */
+ break;
+ case V4L2_PIX_FMT_NV12M:
+ case V4L2_PIX_FMT_NV16M:
+ case V4L2_PIX_FMT_NV12M_S10B:
+ case V4L2_PIX_FMT_NV12M_P010:
+ ctx->dst_fmt = mfc_dec_find_format(ctx, V4L2_PIX_FMT_NV16M_S10B);
+ break;
+ case V4L2_PIX_FMT_NV21M:
+ case V4L2_PIX_FMT_NV61M:
+ case V4L2_PIX_FMT_NV21M_S10B:
+ case V4L2_PIX_FMT_NV21M_P010:
+ ctx->dst_fmt = mfc_dec_find_format(ctx, V4L2_PIX_FMT_NV61M_S10B);
+ break;
+ default:
+ ctx->dst_fmt = mfc_dec_find_format(ctx, V4L2_PIX_FMT_NV16M_S10B);
+ break;
+ }
+ ctx->raw_buf.num_planes = 2;
+ } else if (ctx->is_10bit && !ctx->is_422) {
+ if (ctx->dst_fmt->mem_planes == 1) {
+ /* YUV420 only supports the single plane */
+ ctx->dst_fmt = mfc_dec_find_format(ctx, V4L2_PIX_FMT_NV12N_10B);
+ } else {
+ switch (org_fmt) {
+ case V4L2_PIX_FMT_NV12M_S10B:
+ case V4L2_PIX_FMT_NV21M_S10B:
+ case V4L2_PIX_FMT_NV12M_P010:
+ case V4L2_PIX_FMT_NV21M_P010:
+ /* It is right format */
+ break;
+ case V4L2_PIX_FMT_NV12M:
+ case V4L2_PIX_FMT_NV16M:
+ case V4L2_PIX_FMT_NV16M_S10B:
+ case V4L2_PIX_FMT_NV16M_P210:
+ if (dev->pdata->P010_decoding)
+ ctx->dst_fmt = mfc_dec_find_format(ctx, V4L2_PIX_FMT_NV12M_P010);
+ else
+ ctx->dst_fmt = mfc_dec_find_format(ctx, V4L2_PIX_FMT_NV12M_S10B);
+ break;
+ case V4L2_PIX_FMT_NV21M:
+ case V4L2_PIX_FMT_NV61M:
+ case V4L2_PIX_FMT_NV61M_S10B:
+ case V4L2_PIX_FMT_NV61M_P210:
+ ctx->dst_fmt = mfc_dec_find_format(ctx, V4L2_PIX_FMT_NV21M_S10B);
+ break;
+ default:
+ if (dev->pdata->P010_decoding)
+ ctx->dst_fmt = mfc_dec_find_format(ctx, V4L2_PIX_FMT_NV12M_P010);
+ else
+ ctx->dst_fmt = mfc_dec_find_format(ctx, V4L2_PIX_FMT_NV12M_S10B);
+ break;
+ }
+ }
+ ctx->raw_buf.num_planes = 2;
+ } else if (!ctx->is_10bit && ctx->is_422) {
+ switch (org_fmt) {
+ case V4L2_PIX_FMT_NV16M:
+ case V4L2_PIX_FMT_NV61M:
+ /* It is right format */
+ break;
+ case V4L2_PIX_FMT_NV12M:
+ case V4L2_PIX_FMT_NV12M_S10B:
+ case V4L2_PIX_FMT_NV16M_S10B:
+ case V4L2_PIX_FMT_NV12M_P010:
+ case V4L2_PIX_FMT_NV16M_P210:
+ ctx->dst_fmt = mfc_dec_find_format(ctx, V4L2_PIX_FMT_NV16M);
+ break;
+ case V4L2_PIX_FMT_NV21M:
+ case V4L2_PIX_FMT_NV21M_S10B:
+ case V4L2_PIX_FMT_NV61M_S10B:
+ case V4L2_PIX_FMT_NV21M_P010:
+ case V4L2_PIX_FMT_NV61M_P210:
+ ctx->dst_fmt = mfc_dec_find_format(ctx, V4L2_PIX_FMT_NV61M);
+ break;
+ default:
+ ctx->dst_fmt = mfc_dec_find_format(ctx, V4L2_PIX_FMT_NV16M);
+ break;
+ }
+ ctx->raw_buf.num_planes = 2;
+ } else {
+ /* YUV420 8bit */
+ switch (org_fmt) {
+ case V4L2_PIX_FMT_NV16M:
+ case V4L2_PIX_FMT_NV12M_S10B:
+ case V4L2_PIX_FMT_NV16M_S10B:
+ case V4L2_PIX_FMT_NV12M_P010:
+ case V4L2_PIX_FMT_NV16M_P210:
+ ctx->dst_fmt = mfc_dec_find_format(ctx, V4L2_PIX_FMT_NV12M);
+ break;
+ case V4L2_PIX_FMT_NV61M:
+ case V4L2_PIX_FMT_NV21M_S10B:
+ case V4L2_PIX_FMT_NV61M_S10B:
+ case V4L2_PIX_FMT_NV21M_P010:
+ case V4L2_PIX_FMT_NV61M_P210:
+ ctx->dst_fmt = mfc_dec_find_format(ctx, V4L2_PIX_FMT_NV21M);
+ break;
+ default:
+ /* It is right format */
+ break;
+ }
+ }
+
+ if (org_fmt != ctx->dst_fmt->fourcc)
+ mfc_info_ctx("[FRAME] format is changed to %s\n", ctx->dst_fmt->name);
+}
+
+/* Get format */
+static int vidioc_g_fmt_vid_cap_mplane(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ struct s5p_mfc_dec *dec;
+ struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
+ struct s5p_mfc_raw_info *raw;
+ int i;
+
+ mfc_debug_enter();
+
+ dec = ctx->dec_priv;
+ if (!dec) {
+ mfc_err_dev("no mfc decoder to run\n");
+ return -EINVAL;
+ }
+
+ mfc_debug(2, "dec dst g_fmt, state: %d\n", ctx->state);
+
+ if (ctx->state == MFCINST_GOT_INST ||
+ ctx->state == MFCINST_RES_CHANGE_FLUSH ||
+ ctx->state == MFCINST_RES_CHANGE_END) {
+ /* If the MFC is parsing the header,
+ * so wait until it is finished */
+ if (s5p_mfc_wait_for_done_ctx(ctx,
+ S5P_FIMV_R2H_CMD_SEQ_DONE_RET)) {
+ mfc_err_dev("header parsing failed\n");
+ return -EAGAIN;
+ }
+ }
+
+ if (ctx->state >= MFCINST_HEAD_PARSED &&
+ ctx->state < MFCINST_ABORT) {
+ /* This is run on CAPTURE (deocde output) */
+
+ /* only NV16(61) format is supported for 422 format */
+ /* only 2 plane is supported for 10bit */
+ mfc_dec_change_format(ctx);
+
+ raw = &ctx->raw_buf;
+ /* Width and height are set to the dimensions
+ of the movie, the buffer is bigger and
+ further processing stages should crop to this
+ rectangle. */
+ s5p_mfc_dec_calc_dpb_size(ctx);
+
+ if (IS_LOW_MEM) {
+ unsigned int dpb_size;
+ /*
+ * If total memory requirement is too big for this device,
+ * then it returns error.
+ * DPB size : Total plane size * the number of DPBs
+ * 5: the number of extra DPBs
+ * 3: the number of DPBs for Android framework
+ * 600MB: being used to return an error,
+ * when 8K resolution video clip is being tried to be decoded
+ */
+ dpb_size = (ctx->raw_buf.total_plane_size * (ctx->dpb_count + 5 + 3));
+ if (dpb_size > SZ_600M) {
+ mfc_info_ctx("required memory size is too big (%dx%d, dpb: %d)\n",
+ ctx->img_width, ctx->img_height, ctx->dpb_count);
+ return -EINVAL;
+ }
+ }
+
+ pix_fmt_mp->width = ctx->img_width;
+ pix_fmt_mp->height = ctx->img_height;
+ pix_fmt_mp->num_planes = ctx->dst_fmt->mem_planes;
+
+ if (dec->is_interlaced)
+ pix_fmt_mp->field = V4L2_FIELD_INTERLACED;
+ else
+ pix_fmt_mp->field = V4L2_FIELD_NONE;
+
+ /* Set pixelformat to the format in which MFC
+ outputs the decoded frame */
+ pix_fmt_mp->pixelformat = ctx->dst_fmt->fourcc;
+ for (i = 0; i < ctx->dst_fmt->mem_planes; i++) {
+ pix_fmt_mp->plane_fmt[i].bytesperline = raw->stride[i];
+ if (ctx->dst_fmt->mem_planes == 1) {
+ pix_fmt_mp->plane_fmt[i].sizeimage = raw->total_plane_size;
+ } else {
+ if (ctx->is_10bit)
+ pix_fmt_mp->plane_fmt[i].sizeimage = raw->plane_size[i]
+ + raw->plane_size_2bits[i];
+ else
+ pix_fmt_mp->plane_fmt[i].sizeimage = raw->plane_size[i];
+ }
+ }
+ }
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+static int vidioc_g_fmt_vid_out_mplane(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ struct s5p_mfc_dec *dec;
+ struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
+
+ mfc_debug_enter();
+
+ dec = ctx->dec_priv;
+ if (!dec) {
+ mfc_err_dev("no mfc decoder to run\n");
+ return -EINVAL;
+ }
+
+ mfc_debug(4, "dec src g_fmt, state: %d\n", ctx->state);
+
+ /* This is run on OUTPUT
+ The buffer contains compressed image
+ so width and height have no meaning */
+ pix_fmt_mp->width = 0;
+ pix_fmt_mp->height = 0;
+ pix_fmt_mp->field = V4L2_FIELD_NONE;
+ pix_fmt_mp->plane_fmt[0].bytesperline = dec->src_buf_size;
+ pix_fmt_mp->plane_fmt[0].sizeimage = dec->src_buf_size;
+ pix_fmt_mp->pixelformat = ctx->src_fmt->fourcc;
+ pix_fmt_mp->num_planes = ctx->src_fmt->mem_planes;
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+/* Try format */
+static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ struct s5p_mfc_fmt *fmt;
+ struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
+
+ fmt = mfc_dec_find_format(ctx, pix_fmt_mp->pixelformat);
+ if (!fmt) {
+ mfc_err_dev("Unsupported format for %s\n",
+ V4L2_TYPE_IS_OUTPUT(f->type) ? "source" : "destination");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* Set format */
+static int vidioc_s_fmt_vid_cap_mplane(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
+
+ mfc_debug_enter();
+
+ if (ctx->vq_dst.streaming) {
+ mfc_err_ctx("queue busy\n");
+ return -EBUSY;
+ }
+
+ ctx->dst_fmt = mfc_dec_find_format(ctx, pix_fmt_mp->pixelformat);
+ if (!ctx->dst_fmt) {
+ mfc_err_ctx("Unsupported format for destination\n");
+ return -EINVAL;
+ }
+ ctx->raw_buf.num_planes = ctx->dst_fmt->num_planes;
+ mfc_info_ctx("[FRAME] dec dst pixelformat : %s\n", ctx->dst_fmt->name);
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+static int mfc_force_close_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx)
+{
+ if (ctx->inst_no == MFC_NO_INSTANCE_SET)
+ return 0;
+
+ s5p_mfc_change_state(ctx, MFCINST_RETURN_INST);
+ s5p_mfc_set_bit(ctx->num, &dev->work_bits);
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ if (s5p_mfc_just_run(dev, ctx->num)) {
+ mfc_err_ctx("Failed to run MFC\n");
+ s5p_mfc_release_hwlock_ctx(ctx);
+ s5p_mfc_cleanup_work_bit_and_try_run(ctx);
+ return -EIO;
+ }
+
+ /* Wait until instance is returned or timeout occured */
+ if (s5p_mfc_wait_for_done_ctx(ctx,
+ S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET)) {
+ mfc_err_ctx("Waiting for CLOSE_INSTANCE timed out\n");
+ s5p_mfc_release_hwlock_ctx(ctx);
+ s5p_mfc_cleanup_work_bit_and_try_run(ctx);
+ return -EIO;
+ }
+
+ /* Free resources */
+ s5p_mfc_release_instance_context(ctx);
+ s5p_mfc_change_state(ctx, MFCINST_INIT);
+
+ return 0;
+}
+
+static int vidioc_s_fmt_vid_out_mplane(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct s5p_mfc_dev *dev = video_drvdata(file);
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
+ int ret = 0;
+
+ mfc_debug_enter();
+
+ if (ctx->vq_src.streaming) {
+ mfc_err_ctx("queue busy\n");
+ return -EBUSY;
+ }
+
+ ctx->src_fmt = mfc_dec_find_format(ctx, pix_fmt_mp->pixelformat);
+ if (!ctx->src_fmt) {
+ mfc_err_ctx("Unsupported format for source\n");
+ return -EINVAL;
+ }
+
+ ctx->codec_mode = ctx->src_fmt->codec_mode;
+ mfc_info_ctx("[STREAM] Dec src codec(%d): %s\n",
+ ctx->codec_mode, ctx->src_fmt->name);
+
+ ctx->pix_format = pix_fmt_mp->pixelformat;
+ if ((pix_fmt_mp->width > 0) && (pix_fmt_mp->height > 0)) {
+ ctx->img_height = pix_fmt_mp->height;
+ ctx->img_width = pix_fmt_mp->width;
+ }
+
+ /* As this buffer will contain compressed data, the size is set
+ * to the maximum size. */
+ if (pix_fmt_mp->plane_fmt[0].sizeimage)
+ dec->src_buf_size = pix_fmt_mp->plane_fmt[0].sizeimage;
+ else
+ dec->src_buf_size = MAX_FRAME_SIZE;
+ mfc_debug(2, "[STREAM] sizeimage: %d\n", pix_fmt_mp->plane_fmt[0].sizeimage);
+ pix_fmt_mp->plane_fmt[0].bytesperline = 0;
+
+ MFC_TRACE_CTX_HWLOCK("**DEC s_fmt\n");
+ ret = s5p_mfc_get_hwlock_ctx(ctx);
+ if (ret < 0) {
+ mfc_err_ctx("Failed to get hwlock\n");
+ return -EBUSY;
+ }
+
+ /* In case of calling s_fmt twice or more */
+ ret = mfc_force_close_inst(dev, ctx);
+ if (ret) {
+ mfc_err_ctx("Failed to close already opening instance\n");
+ return -EIO;
+ }
+
+ ret = s5p_mfc_alloc_instance_context(ctx);
+ if (ret) {
+ mfc_err_ctx("Failed to allocate dec instance[%d] buffers\n",
+ ctx->num);
+ s5p_mfc_release_hwlock_ctx(ctx);
+ return -ENOMEM;
+ }
+
+ s5p_mfc_set_bit(ctx->num, &dev->work_bits);
+ ret = s5p_mfc_just_run(dev, ctx->num);
+ if (ret) {
+ mfc_err_ctx("Failed to run MFC\n");
+ s5p_mfc_release_hwlock_ctx(ctx);
+ s5p_mfc_cleanup_work_bit_and_try_run(ctx);
+ s5p_mfc_release_instance_context(ctx);
+ return -EIO;
+ }
+
+ if (s5p_mfc_wait_for_done_ctx(ctx,
+ S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET)) {
+ s5p_mfc_release_hwlock_ctx(ctx);
+ s5p_mfc_cleanup_work_bit_and_try_run(ctx);
+ s5p_mfc_release_instance_context(ctx);
+ return -EIO;
+ }
+
+ s5p_mfc_release_hwlock_ctx(ctx);
+
+ mfc_debug(2, "Got instance number: %d\n", ctx->inst_no);
+
+ if (s5p_mfc_dec_ctx_ready(ctx))
+ s5p_mfc_set_bit(ctx->num, &dev->work_bits);
+ if (s5p_mfc_is_work_to_do(dev))
+ queue_work(dev->butler_wq, &dev->butler_work);
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+/* Reqeust buffers */
+static int vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *reqbufs)
+{
+ struct s5p_mfc_dev *dev = video_drvdata(file);
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ struct s5p_mfc_dec *dec;
+ int ret = 0;
+
+ mfc_debug_enter();
+
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ dec = ctx->dec_priv;
+ if (!dec) {
+ mfc_err_dev("no mfc decoder to run\n");
+ return -EINVAL;
+ }
+
+ if (reqbufs->memory == V4L2_MEMORY_MMAP) {
+ mfc_err_ctx("Not supported memory type (%d)\n", reqbufs->memory);
+ return -EINVAL;
+ }
+
+ if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ mfc_debug(4, "dec src reqbuf(%d)\n", reqbufs->count);
+ /* Can only request buffers after
+ an instance has been opened.*/
+ if (ctx->state == MFCINST_GOT_INST) {
+ if (reqbufs->count == 0) {
+ ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
+ ctx->output_state = QUEUE_FREE;
+ return ret;
+ }
+
+ /* Decoding */
+ if (ctx->output_state != QUEUE_FREE) {
+ mfc_err_ctx("Bufs have already been requested\n");
+ return -EINVAL;
+ }
+
+ ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
+ if (ret) {
+ mfc_err_ctx("vb2_reqbufs on src failed\n");
+ return ret;
+ }
+
+ ctx->output_state = QUEUE_BUFS_REQUESTED;
+ }
+ } else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ mfc_debug(4, "dec dst reqbuf(%d)\n", reqbufs->count);
+ if (reqbufs->count == 0) {
+ ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+
+ if (dev->has_mmcache && dev->mmcache.is_on_status)
+ s5p_mfc_invalidate_mmcache(dev);
+
+ s5p_mfc_release_codec_buffers(ctx);
+ ctx->capture_state = QUEUE_FREE;
+ return ret;
+ }
+
+ dec->dst_memtype = reqbufs->memory;
+
+ if (ctx->capture_state != QUEUE_FREE) {
+ mfc_err_ctx("Bufs have already been requested\n");
+ return -EINVAL;
+ }
+
+ ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+ if (ret) {
+ mfc_err_ctx("vb2_reqbufs on capture failed\n");
+ return ret;
+ }
+
+ if (reqbufs->count < ctx->dpb_count) {
+ mfc_err_ctx("Not enough buffers allocated\n");
+ reqbufs->count = 0;
+ vb2_reqbufs(&ctx->vq_dst, reqbufs);
+ return -ENOMEM;
+ }
+
+ dec->total_dpb_count = reqbufs->count;
+
+ ret = s5p_mfc_alloc_codec_buffers(ctx);
+ if (ret) {
+ mfc_err_ctx("Failed to allocate decoding buffers\n");
+ reqbufs->count = 0;
+ vb2_reqbufs(&ctx->vq_dst, reqbufs);
+ return -ENOMEM;
+ }
+
+ ctx->capture_state = QUEUE_BUFS_REQUESTED;
+
+ if (s5p_mfc_dec_ctx_ready(ctx))
+ s5p_mfc_set_bit(ctx->num, &dev->work_bits);
+
+ s5p_mfc_try_run(dev);
+ }
+
+ mfc_debug_leave();
+
+ return ret;
+}
+
+/* Query buffer */
+static int vidioc_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ int ret;
+
+ mfc_debug_enter();
+
+ if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ mfc_debug(4, "dec dst querybuf, state: %d\n", ctx->state);
+ ret = vb2_querybuf(&ctx->vq_dst, buf);
+ if (ret != 0) {
+ mfc_err_dev("dec dst: error in vb2_querybuf()\n");
+ return ret;
+ }
+ } else if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ mfc_debug(4, "dec src querybuf, state: %d\n", ctx->state);
+ ret = vb2_querybuf(&ctx->vq_src, buf);
+ if (ret != 0) {
+ mfc_err_dev("dec src: error in vb2_querybuf()\n");
+ return ret;
+ }
+ } else {
+ mfc_err_dev("invalid buf type (%d)\n", buf->type);
+ return -EINVAL;
+ }
+
+ mfc_debug_leave();
+
+ return ret;
+}
+
+/* Queue a buffer */
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ int ret = -EINVAL;
+
+ mfc_debug_enter();
+
+ if (ctx->state == MFCINST_ERROR) {
+ mfc_err_ctx("Call on QBUF after unrecoverable error\n");
+ return -EIO;
+ }
+
+ if (V4L2_TYPE_IS_MULTIPLANAR(buf->type) && !buf->length) {
+ mfc_err_ctx("multiplanar but length is zero\n");
+ return -EIO;
+ }
+
+ if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ mfc_debug(4, "dec src buf[%d] Q\n", buf->index);
+ if (buf->m.planes[0].bytesused > buf->m.planes[0].length) {
+ mfc_err_ctx("data size (%d) must be less than "
+ "buffer size(%d)\n",
+ buf->m.planes[0].bytesused,
+ buf->m.planes[0].length);
+ return -EIO;
+ }
+
+ s5p_mfc_qos_update_framerate(ctx);
+
+ if (!buf->m.planes[0].bytesused) {
+ buf->m.planes[0].bytesused = buf->m.planes[0].length;
+ mfc_debug(2, "Src size zero, changed to buf size %d\n",
+ buf->m.planes[0].bytesused);
+ } else {
+ mfc_debug(2, "Src size = %d\n", buf->m.planes[0].bytesused);
+ }
+ ret = vb2_qbuf(&ctx->vq_src, buf);
+ } else {
+ mfc_debug(4, "dec dst buf[%d] Q\n", buf->index);
+ ret = vb2_qbuf(&ctx->vq_dst, buf);
+ }
+
+ mfc_debug_leave();
+ return ret;
+}
+
+/* Dequeue a buffer */
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ struct dec_dpb_ref_info *dstBuf, *srcBuf;
+ int ret;
+ int ncount = 0;
+
+ mfc_debug_enter();
+
+ if (ctx->state == MFCINST_ERROR) {
+ mfc_err_ctx("Call on DQBUF after unrecoverable error\n");
+ return -EIO;
+ }
+ if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ mfc_debug(4, "dec src buf[%d] DQ\n", buf->index);
+ ret = vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK);
+ } else {
+ mfc_debug(4, "dec dst buf[%d] DQ\n", buf->index);
+ ret = vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK);
+
+ if (buf->index >= MFC_MAX_DPBS) {
+ mfc_err_ctx("buffer index[%d] range over\n", buf->index);
+ return -EINVAL;
+ }
+
+ /* Memcpy from dec->ref_info to shared memory */
+ srcBuf = &dec->ref_info[buf->index];
+ for (ncount = 0; ncount < MFC_MAX_DPBS; ncount++) {
+ if (srcBuf->dpb[ncount].fd[0] == MFC_INFO_INIT_FD)
+ break;
+ mfc_debug(2, "[DPB] DQ index[%d] Released FD = %d\n",
+ buf->index, srcBuf->dpb[ncount].fd[0]);
+ }
+
+ if (dec->sh_handle.vaddr != NULL) {
+ dstBuf = (struct dec_dpb_ref_info *)
+ dec->sh_handle.vaddr + buf->index;
+ memcpy(dstBuf, srcBuf, sizeof(struct dec_dpb_ref_info));
+ dstBuf->index = buf->index;
+ }
+ }
+ mfc_debug_leave();
+ return ret;
+}
+
+/* Stream on */
+static int vidioc_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ int ret = -EINVAL;
+
+ mfc_debug_enter();
+
+ if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ mfc_debug(4, "dec src streamon\n");
+ ret = vb2_streamon(&ctx->vq_src, type);
+ } else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ mfc_debug(4, "dec dst streamon\n");
+ ret = vb2_streamon(&ctx->vq_dst, type);
+
+ if (!ret)
+ s5p_mfc_qos_on(ctx);
+ } else {
+ mfc_err_ctx("unknown v4l2 buffer type\n");
+ }
+
+ mfc_debug(2, "src: %d, dst: %d, state = %d, dpb_count = %d\n",
+ s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->src_buf_queue),
+ s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->dst_buf_queue),
+ ctx->state, ctx->dpb_count);
+
+ mfc_debug_leave();
+
+ return ret;
+}
+
+/* Stream off, which equals to a pause */
+static int vidioc_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ int ret = -EINVAL;
+
+ mfc_debug_enter();
+
+ if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ mfc_debug(4, "dec src streamoff\n");
+ s5p_mfc_qos_reset_last_framerate(ctx);
+
+ ret = vb2_streamoff(&ctx->vq_src, type);
+ } else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ mfc_debug(4, "dec dst streamoff\n");
+ ret = vb2_streamoff(&ctx->vq_dst, type);
+ if (!ret)
+ s5p_mfc_qos_off(ctx);
+ } else {
+ mfc_err_ctx("unknown v4l2 buffer type\n");
+ }
+
+ mfc_debug_leave();
+
+ return ret;
+}
+
+/* Query a ctrl */
+static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ struct v4l2_queryctrl *c;
+
+ c = mfc_dec_get_ctrl(qc->id);
+ if (!c) {
+ mfc_err_dev("[CTRLS] not supported control id (%#x)\n", qc->id);
+ return -EINVAL;
+ }
+
+ *qc = *c;
+ return 0;
+}
+
+static int mfc_dec_ext_info(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ int val = 0;
+
+ val |= DEC_SET_DYNAMIC_DPB;
+ if (MFC_FEATURE_SUPPORT(dev, dev->pdata->skype))
+ val |= DEC_SET_SKYPE_FLAG;
+
+ mfc_debug(5, "[CTRLS] ext info val: %#x\n", val);
+
+ return val;
+}
+
+/* Get ctrl */
+static int mfc_dec_get_ctrl_val(struct s5p_mfc_ctx *ctx, struct v4l2_control *ctrl)
+{
+ struct s5p_mfc_dev *dev;
+ struct s5p_mfc_dec *dec;
+ struct s5p_mfc_ctx_ctrl *ctx_ctrl;
+ int found = 0;
+
+ if (!ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return -EINVAL;
+ }
+ dev = ctx->dev;
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+ dec = ctx->dec_priv;
+ if (!dec) {
+ mfc_err_dev("no mfc decoder to run\n");
+ return -EINVAL;
+ }
+
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER:
+ ctrl->value = dec->loop_filter_mpeg4;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY:
+ ctrl->value = dec->display_delay;
+ break;
+ case V4L2_CID_CACHEABLE:
+ mfc_debug(5, "it is supported only V4L2_MEMORY_MMAP\n");
+ break;
+ case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
+ if (ctx->state >= MFCINST_HEAD_PARSED &&
+ ctx->state < MFCINST_ABORT) {
+ ctrl->value = ctx->dpb_count;
+ break;
+ } else if (ctx->state != MFCINST_INIT) {
+ mfc_err_ctx("Decoding not initialised\n");
+ return -EINVAL;
+ }
+
+ /* Should wait for the header to be parsed */
+ if (s5p_mfc_wait_for_done_ctx(ctx,
+ S5P_FIMV_R2H_CMD_SEQ_DONE_RET)) {
+ s5p_mfc_cleanup_work_bit_and_try_run(ctx);
+ return -EIO;
+ }
+
+ if (ctx->state >= MFCINST_HEAD_PARSED &&
+ ctx->state < MFCINST_ABORT) {
+ ctrl->value = ctx->dpb_count;
+ } else {
+ mfc_err_ctx("Decoding not initialised\n");
+ return -EINVAL;
+ }
+ break;
+ case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE:
+ ctrl->value = dec->slice_enable;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_PACKED_PB:
+ /* Not used */
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_CRC_ENABLE:
+ ctrl->value = dec->crc_enable;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_CHECK_STATE:
+ if (ctx->is_dpb_realloc && ctx->state == MFCINST_HEAD_PARSED)
+ ctrl->value = MFCSTATE_DEC_S3D_REALLOC;
+ else if (ctx->state == MFCINST_RES_CHANGE_FLUSH
+ || ctx->state == MFCINST_RES_CHANGE_END
+ || ctx->state == MFCINST_HEAD_PARSED)
+ ctrl->value = MFCSTATE_DEC_RES_DETECT;
+ else if (ctx->state == MFCINST_FINISHING)
+ ctrl->value = MFCSTATE_DEC_TERMINATING;
+ else
+ ctrl->value = MFCSTATE_PROCESSING;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING:
+ ctrl->value = dec->sei_parse;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_I_FRAME_DECODING:
+ ctrl->value = dec->idr_decoding;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_RATE:
+ ctrl->value = s5p_mfc_qos_get_framerate(ctx);
+ break;
+ case V4L2_CID_MPEG_MFC_GET_VERSION_INFO:
+ ctrl->value = dev->pdata->ip_ver;
+ break;
+ case V4L2_CID_MPEG_VIDEO_QOS_RATIO:
+ ctrl->value = ctx->qos_ratio;
+ break;
+ case V4L2_CID_MPEG_MFC_SET_DYNAMIC_DPB_MODE:
+ ctrl->value = dec->is_dynamic_dpb;
+ break;
+ case V4L2_CID_MPEG_MFC_GET_EXT_INFO:
+ ctrl->value = mfc_dec_ext_info(ctx);
+ break;
+ case V4L2_CID_MPEG_MFC_GET_10BIT_INFO:
+ ctrl->value = ctx->is_10bit;
+ break;
+ case V4L2_CID_MPEG_MFC_GET_DRIVER_INFO:
+ ctrl->value = MFC_DRIVER_INFO;
+ break;
+ default:
+ list_for_each_entry(ctx_ctrl, &ctx->ctrls, list) {
+ if (!(ctx_ctrl->type & MFC_CTRL_TYPE_GET))
+ continue;
+
+ if (ctx_ctrl->id == ctrl->id) {
+ if (ctx_ctrl->has_new) {
+ ctx_ctrl->has_new = 0;
+ ctrl->value = ctx_ctrl->val;
+ } else {
+ mfc_debug(5, "[CTRLS] Control value "\
+ "is not up to date: "\
+ "0x%08x\n", ctrl->id);
+ return -EINVAL;
+ }
+
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ mfc_err_ctx("Invalid control: 0x%08x\n", ctrl->id);
+ return -EINVAL;
+ }
+ break;
+ }
+
+ mfc_debug(5, "[CTRLS] get id: %#x, value: %d\n", ctrl->id, ctrl->value);
+
+ return 0;
+}
+
+/* Get a ctrl */
+static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ int ret = 0;
+
+ mfc_debug_enter();
+ ret = mfc_dec_get_ctrl_val(ctx, ctrl);
+ mfc_debug_leave();
+
+ return ret;
+}
+
+/* Set a ctrl */
+static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct s5p_mfc_dev *dev = video_drvdata(file);
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ struct s5p_mfc_dec *dec;
+ struct s5p_mfc_ctx_ctrl *ctx_ctrl;
+ int ret = 0;
+ int found = 0;
+
+ mfc_debug_enter();
+
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ dec = ctx->dec_priv;
+ if (!dec) {
+ mfc_err_dev("no mfc decoder to run\n");
+ return -EINVAL;
+ }
+
+ ret = mfc_dec_check_ctrl_val(ctx, ctrl);
+ if (ret)
+ return ret;
+
+ mfc_debug(5, "[CTRLS] set id: %#x, value: %d\n", ctrl->id, ctrl->value);
+
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER:
+ dec->loop_filter_mpeg4 = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY:
+ dec->display_delay = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE:
+ dec->slice_enable = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_PACKED_PB:
+ /* Not used */
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_CRC_ENABLE:
+ dec->crc_enable = ctrl->value;
+ break;
+ case V4L2_CID_CACHEABLE:
+ mfc_debug(5, "it is supported only V4L2_MEMORY_MMAP\n");
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING:
+ dec->sei_parse = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_I_FRAME_DECODING:
+ dec->idr_decoding = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_DECODER_IMMEDIATE_DISPLAY:
+ dec->immediate_display = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_DECODER_DECODING_TIMESTAMP_MODE:
+ dec->is_dts_mode = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_DECODER_WAIT_DECODING_START:
+ ctx->wait_state = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC_SET_DUAL_DPB_MODE:
+ mfc_err_dev("[DPB] not supported CID: 0x%x\n",ctrl->id);
+ break;
+ case V4L2_CID_MPEG_VIDEO_QOS_RATIO:
+ ctx->qos_ratio = ctrl->value;
+ mfc_info_ctx("[QoS] set %d qos_ratio\n", ctrl->value);
+ break;
+ case V4L2_CID_MPEG_MFC_SET_DYNAMIC_DPB_MODE:
+ dec->is_dynamic_dpb = ctrl->value;
+ if (dec->is_dynamic_dpb == 0)
+ mfc_err_dev("[DPB] is_dynamic_dpb is 0. it has to be enabled\n");
+ break;
+ case V4L2_CID_MPEG_MFC_SET_USER_SHARED_HANDLE:
+ if (dec->sh_handle.fd == -1) {
+ dec->sh_handle.fd = ctrl->value;
+ if (s5p_mfc_mem_get_user_shared_handle(ctx, &dec->sh_handle))
+ return -EINVAL;
+ else
+ mfc_debug(2, "[MEMINFO][DPB] shared handle fd: %d, vaddr: 0x%p\n",
+ dec->sh_handle.fd, dec->sh_handle.vaddr);
+ }
+ break;
+ case V4L2_CID_MPEG_MFC_SET_BUF_PROCESS_TYPE:
+ ctx->buf_process_type = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BLACK_BAR_DETECT:
+ dec->detect_black_bar = ctrl->value;
+ break;
+ default:
+ list_for_each_entry(ctx_ctrl, &ctx->ctrls, list) {
+ if (!(ctx_ctrl->type & MFC_CTRL_TYPE_SET))
+ continue;
+
+ if (ctx_ctrl->id == ctrl->id) {
+ ctx_ctrl->has_new = 1;
+ ctx_ctrl->val = ctrl->value;
+
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ mfc_err_ctx("Invalid control: 0x%08x\n", ctrl->id);
+ return -EINVAL;
+ }
+ break;
+ }
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+/* Get cropping information */
+static int vidioc_g_crop(struct file *file, void *priv,
+ struct v4l2_crop *cr)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+
+ mfc_debug_enter();
+
+ if (!ready_to_get_crop(ctx)) {
+ mfc_debug(2, "ready to get crop failed\n");
+ return -EINVAL;
+ }
+
+ if (ctx->state == MFCINST_RUNNING && dec->detect_black_bar
+ && dec->black_bar_updated) {
+ cr->c.left = dec->black_bar.left;
+ cr->c.top = dec->black_bar.top;
+ cr->c.width = dec->black_bar.width;
+ cr->c.height = dec->black_bar.height;
+ mfc_debug(2, "[FRAME][BLACKBAR] Cropping info: l=%d t=%d w=%d h=%d\n",
+ dec->black_bar.left,
+ dec->black_bar.top,
+ dec->black_bar.width,
+ dec->black_bar.height);
+ } else {
+ if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_H264 ||
+ ctx->src_fmt->fourcc == V4L2_PIX_FMT_HEVC ||
+ ctx->src_fmt->fourcc == V4L2_PIX_FMT_BPG) {
+ cr->c.left = dec->cr_left;
+ cr->c.top = dec->cr_top;
+ cr->c.width = ctx->img_width - dec->cr_left - dec->cr_right;
+ cr->c.height = ctx->img_height - dec->cr_top - dec->cr_bot;
+ mfc_debug(2, "[FRAME] Cropping info: l=%d t=%d " \
+ "w=%d h=%d (r=%d b=%d fw=%d fh=%d)\n",
+ dec->cr_left, dec->cr_top,
+ cr->c.width, cr->c.height,
+ dec->cr_right, dec->cr_bot,
+ ctx->img_width, ctx->img_height);
+ } else {
+ cr->c.left = 0;
+ cr->c.top = 0;
+ cr->c.width = ctx->img_width;
+ cr->c.height = ctx->img_height;
+ mfc_debug(2, "[FRAME] Cropping info: w=%d h=%d fw=%d fh=%d\n",
+ cr->c.width, cr->c.height,
+ ctx->img_width, ctx->img_height);
+ }
+ }
+
+ mfc_debug_leave();
+ return 0;
+}
+
+static int vidioc_g_ext_ctrls(struct file *file, void *priv,
+ struct v4l2_ext_controls *f)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ struct v4l2_ext_control *ext_ctrl;
+ struct v4l2_control ctrl;
+ int i;
+ int ret = 0;
+
+ if (f->which != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+
+ for (i = 0; i < f->count; i++) {
+ ext_ctrl = (f->controls + i);
+
+ ctrl.id = ext_ctrl->id;
+
+ ret = mfc_dec_get_ctrl_val(ctx, &ctrl);
+ if (ret == 0) {
+ ext_ctrl->value = ctrl.value;
+ } else {
+ f->error_idx = i;
+ break;
+ }
+
+ mfc_debug(5, "[CTRLS][%d] id: %#x, value: %d\n",
+ i, ext_ctrl->id, ext_ctrl->value);
+ }
+
+ return ret;
+}
+
+/* v4l2_ioctl_ops */
+static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = {
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane,
+ .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane,
+ .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_vid_cap_mplane,
+ .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_vid_out_mplane,
+ .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt,
+ .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt,
+ .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_vid_cap_mplane,
+ .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_vid_out_mplane,
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_g_crop = vidioc_g_crop,
+ .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls,
+};
+
+const struct v4l2_ioctl_ops *s5p_mfc_get_dec_v4l2_ioctl_ops(void)
+{
+ return &s5p_mfc_dec_ioctl_ops;
+}
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_dec.h
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __MFC_DEC_H
+#define __MFC_DEC_H __FILE__
+
+#include "mfc_common.h"
+
+const struct v4l2_ioctl_ops *s5p_mfc_get_dec_v4l2_ioctl_ops(void);
+
+#endif /* __MFC_DEC_H */
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_dec_internal.h
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __MFC_DEC_INTERNAL_H
+#define __MFC_DEC_INTERNAL_H __FILE__
+
+#include "mfc_common.h"
+
+struct s5p_mfc_fmt dec_formats[] = {
+ {
+ .name = "4:2:0 3 Planes Y/Cb/Cr",
+ .fourcc = V4L2_PIX_FMT_YUV420M,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME,
+ .num_planes = 3,
+ .mem_planes = 3,
+ },
+ {
+ .name = "4:2:0 3 Planes Y/Cb/Cr single",
+ .fourcc = V4L2_PIX_FMT_YUV420N,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME,
+ .num_planes = 3,
+ .mem_planes = 1,
+ },
+ {
+ .name = "4:2:0 3 Planes Y/Cr/Cb",
+ .fourcc = V4L2_PIX_FMT_YVU420M,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME,
+ .num_planes = 3,
+ .mem_planes = 3,
+ },
+ {
+ .name = "4:2:0 2 Planes Y/CbCr",
+ .fourcc = V4L2_PIX_FMT_NV12M,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME,
+ .num_planes = 2,
+ .mem_planes = 2,
+ },
+ {
+ .name = "4:2:0 2 Planes Y/CbCr single",
+ .fourcc = V4L2_PIX_FMT_NV12N,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME,
+ .num_planes = 2,
+ .mem_planes = 1,
+ },
+ {
+ .name = "4:2:0 2 Planes Y/CbCr 8+2 10bit",
+ .fourcc = V4L2_PIX_FMT_NV12M_S10B,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME | MFC_FMT_10BIT,
+ .num_planes = 2,
+ .mem_planes = 2,
+ },
+ {
+ .name = "4:2:0 2 Planes Y/CbCr 10bit single",
+ .fourcc = V4L2_PIX_FMT_NV12N_10B,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME | MFC_FMT_10BIT,
+ .num_planes = 2,
+ .mem_planes = 1,
+ },
+ {
+ .name = "4:2:0 2 Planes Y/CbCr P010 10bit",
+ .fourcc = V4L2_PIX_FMT_NV12M_P010,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME | MFC_FMT_10BIT,
+ .num_planes = 2,
+ .mem_planes = 2,
+ },
+ {
+ .name = "4:2:0 2 Planes Y/CrCb",
+ .fourcc = V4L2_PIX_FMT_NV21M,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME,
+ .num_planes = 2,
+ .mem_planes = 2,
+ },
+ {
+ .name = "4:2:0 2 Planes Y/CrCb 8+2 10bit",
+ .fourcc = V4L2_PIX_FMT_NV21M_S10B,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME | MFC_FMT_10BIT,
+ .num_planes = 2,
+ .mem_planes = 2,
+ },
+ {
+ .name = "4:2:0 2 Planes Y/CrCb P010 10bit",
+ .fourcc = V4L2_PIX_FMT_NV21M_P010,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME | MFC_FMT_10BIT,
+ .num_planes = 2,
+ .mem_planes = 2,
+ },
+ {
+ .name = "4:2:2 2 Planes Y/CbCr",
+ .fourcc = V4L2_PIX_FMT_NV16M,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME | MFC_FMT_422,
+ .num_planes = 2,
+ .mem_planes = 2,
+ },
+ {
+ .name = "4:2:2 2 Planes Y/CbCr 8+2 10bit",
+ .fourcc = V4L2_PIX_FMT_NV16M_S10B,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME | MFC_FMT_10BIT | MFC_FMT_422,
+ .num_planes = 2,
+ .mem_planes = 2,
+ },
+ {
+ .name = "4:2:2 2 Planes Y/CbCr P210 10bit",
+ .fourcc = V4L2_PIX_FMT_NV16M_P210,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME | MFC_FMT_10BIT | MFC_FMT_422,
+ .num_planes = 2,
+ .mem_planes = 2,
+ },
+ {
+ .name = "4:2:2 2 Planes Y/CrCb",
+ .fourcc = V4L2_PIX_FMT_NV61M,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME | MFC_FMT_422,
+ .num_planes = 2,
+ .mem_planes = 2,
+ },
+ {
+ .name = "4:2:2 2 Planes Y/CrCb 8+2 10bit",
+ .fourcc = V4L2_PIX_FMT_NV61M_S10B,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME | MFC_FMT_10BIT | MFC_FMT_422,
+ .num_planes = 2,
+ .mem_planes = 2,
+ },
+ {
+ .name = "4:2:2 2 Planes Y/CrCb P210 10bit",
+ .fourcc = V4L2_PIX_FMT_NV61M_P210,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME | MFC_FMT_10BIT | MFC_FMT_422,
+ .num_planes = 2,
+ .mem_planes = 2,
+ },
+ {
+ .name = "H264 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_H264,
+ .codec_mode = S5P_FIMV_CODEC_H264_DEC,
+ .type = MFC_FMT_STREAM,
+ .num_planes = 1,
+ .mem_planes = 1,
+ },
+ {
+ .name = "H264/MVC Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_H264_MVC,
+ .codec_mode = S5P_FIMV_CODEC_H264_MVC_DEC,
+ .type = MFC_FMT_STREAM,
+ .num_planes = 1,
+ .mem_planes = 1,
+ },
+ {
+ .name = "H263 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_H263,
+ .codec_mode = S5P_FIMV_CODEC_H263_DEC,
+ .type = MFC_FMT_STREAM,
+ .num_planes = 1,
+ .mem_planes = 1,
+ },
+ {
+ .name = "MPEG1 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_MPEG1,
+ .codec_mode = S5P_FIMV_CODEC_MPEG2_DEC,
+ .type = MFC_FMT_STREAM,
+ .num_planes = 1,
+ .mem_planes = 1,
+ },
+ {
+ .name = "MPEG2 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_MPEG2,
+ .codec_mode = S5P_FIMV_CODEC_MPEG2_DEC,
+ .type = MFC_FMT_STREAM,
+ .num_planes = 1,
+ .mem_planes = 1,
+ },
+ {
+ .name = "MPEG4 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_MPEG4,
+ .codec_mode = S5P_FIMV_CODEC_MPEG4_DEC,
+ .type = MFC_FMT_STREAM,
+ .num_planes = 1,
+ .mem_planes = 1,
+ },
+ {
+ .name = "FIMV Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_FIMV,
+ .codec_mode = S5P_FIMV_CODEC_MPEG4_DEC,
+ .type = MFC_FMT_STREAM,
+ .num_planes = 1,
+ .mem_planes = 1,
+ },
+ {
+ .name = "FIMV1 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_FIMV1,
+ .codec_mode = S5P_FIMV_CODEC_FIMV1_DEC,
+ .type = MFC_FMT_STREAM,
+ .num_planes = 1,
+ .mem_planes = 1,
+ },
+ {
+ .name = "FIMV2 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_FIMV2,
+ .codec_mode = S5P_FIMV_CODEC_FIMV2_DEC,
+ .type = MFC_FMT_STREAM,
+ .num_planes = 1,
+ .mem_planes = 1,
+ },
+ {
+ .name = "FIMV3 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_FIMV3,
+ .codec_mode = S5P_FIMV_CODEC_FIMV3_DEC,
+ .type = MFC_FMT_STREAM,
+ .num_planes = 1,
+ .mem_planes = 1,
+ },
+ {
+ .name = "FIMV4 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_FIMV4,
+ .codec_mode = S5P_FIMV_CODEC_FIMV4_DEC,
+ .type = MFC_FMT_STREAM,
+ .num_planes = 1,
+ .mem_planes = 1,
+ },
+ {
+ .name = "XviD Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_XVID,
+ .codec_mode = S5P_FIMV_CODEC_MPEG4_DEC,
+ .type = MFC_FMT_STREAM,
+ .num_planes = 1,
+ .mem_planes = 1,
+ },
+ {
+ .name = "VC1 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_VC1_ANNEX_G,
+ .codec_mode = S5P_FIMV_CODEC_VC1_DEC,
+ .type = MFC_FMT_STREAM,
+ .num_planes = 1,
+ .mem_planes = 1,
+ },
+ {
+ .name = "VC1 RCV Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_VC1_ANNEX_L,
+ .codec_mode = S5P_FIMV_CODEC_VC1_RCV_DEC,
+ .type = MFC_FMT_STREAM,
+ .num_planes = 1,
+ .mem_planes = 1,
+ },
+ {
+ .name = "VP8 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_VP8,
+ .codec_mode = S5P_FIMV_CODEC_VP8_DEC,
+ .type = MFC_FMT_STREAM,
+ .num_planes = 1,
+ .mem_planes = 1,
+ },
+ {
+ .name = "VP9 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_VP9,
+ .codec_mode = S5P_FIMV_CODEC_VP9_DEC,
+ .type = MFC_FMT_STREAM,
+ .num_planes = 1,
+ .mem_planes = 1,
+ },
+ {
+ .name = "HEVC Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_HEVC,
+ .codec_mode = S5P_FIMV_CODEC_HEVC_DEC,
+ .type = MFC_FMT_STREAM,
+ .num_planes = 1,
+ .mem_planes = 1,
+ },
+ {
+ .name = "BPG Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_BPG,
+ .codec_mode = S5P_FIMV_CODEC_BPG_DEC,
+ .type = MFC_FMT_STREAM,
+ .num_planes = 1,
+ .mem_planes = 1,
+ },
+};
+
+#define NUM_FORMATS ARRAY_SIZE(dec_formats)
+
+static struct v4l2_queryctrl controls[] = {
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H.264 Display Delay",
+ .minimum = -1,
+ .maximum = 32,
+ .step = 1,
+ .default_value = -1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Mpeg4 Loop Filter Enable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Slice Interface Enable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_PACKED_PB,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Packed PB Enable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Frame Tag",
+ .minimum = 0,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_CACHEABLE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Cacheable flag",
+ .minimum = 0,
+ .maximum = 3,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_CRC_ENABLE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "CRC enable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_LUMA,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "CRC data",
+ .minimum = 0,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_CHROMA,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "CRC data",
+ .minimum = 0,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_DISPLAY_STATUS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Display status",
+ .minimum = 0,
+ .maximum = 3,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TYPE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Frame type",
+ .minimum = 0,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Frame pack sei parse flag",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_I_FRAME_DECODING,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "I frame decoding mode",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_RATE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Frames per second in 1000x scale",
+ .minimum = 1,
+ .maximum = 480000,
+ .step = 1,
+ .default_value = 60000,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_DECODER_IMMEDIATE_DISPLAY,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Immediate Display Enable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_DECODER_DECODING_TIMESTAMP_MODE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Decoding Timestamp Mode Enable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_DECODER_WAIT_DECODING_START,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Wait until buffer setting done",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC_GET_VERSION_INFO,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Get MFC version information",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC_SET_DUAL_DPB_MODE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Set Dual DPB mode",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_QOS_RATIO,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "QoS ratio value",
+ .minimum = 20,
+ .maximum = 1000,
+ .step = 10,
+ .default_value = 100,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC_SET_DYNAMIC_DPB_MODE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Set dynamic DPB",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC_SET_USER_SHARED_HANDLE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Set dynamic DPB",
+ .minimum = 0,
+ .maximum = 65535,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC_GET_EXT_INFO,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Get extra information",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC_SET_BUF_PROCESS_TYPE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Set buffer process type",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC_GET_10BIT_INFO,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "10 bit contents information",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_BLACK_BAR_DETECT,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Set black bar detection option",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+};
+
+#define NUM_CTRLS ARRAY_SIZE(controls)
+
+#endif /* __MFC_DEC_INTERNAL_H */
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_dec_ops.c
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "mfc_common.h"
+
+#include "mfc_reg.h"
+
+#define NUM_CTRL_CFGS ARRAY_SIZE(mfc_ctrl_list)
+
+struct s5p_mfc_ctrl_cfg mfc_ctrl_list[] = {
+ {
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_D_PICTURE_TAG,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_D_RET_PICTURE_TAG_TOP,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_DISPLAY_STATUS,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_D_DISPLAY_STATUS,
+ .mask = 0x7,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ /* CRC related definitions are based on non-H.264 type */
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_LUMA,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_D_DISPLAY_FIRST_PLANE_CRC,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_CHROMA,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_D_DISPLAY_SECOND_PLANE_CRC,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_CHROMA1,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_D_DISPLAY_THIRD_PLANE_CRC,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_2BIT_LUMA,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_D_DISPLAY_FIRST_PLANE_2BIT_CRC,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_2BIT_CHROMA,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_D_DISPLAY_SECOND_PLANE_2BIT_CRC,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_CRC_GENERATED,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_D_DISPLAY_STATUS,
+ .mask = 0x1,
+ .shft = 6,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_H264_SEI_FP_AVAIL,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_D_SEI_AVAIL,
+ .mask = 0x1,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRGMENT_ID,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_D_FRAME_PACK_ARRGMENT_ID,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_H264_SEI_FP_INFO,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_D_FRAME_PACK_SEI_INFO,
+ .mask = 0x3FFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_H264_SEI_FP_GRID_POS,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_D_FRAME_PACK_GRID_POS,
+ .mask = 0xFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_H264_MVC_VIEW_ID,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_D_MVC_VIEW_ID,
+ .mask = 0xFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_SEI_MAX_PIC_AVERAGE_LIGHT,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_D_CONTENT_LIGHT_LEVEL_INFO_SEI,
+ .mask = 0xFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_SEI_MAX_CONTENT_LIGHT,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_D_CONTENT_LIGHT_LEVEL_INFO_SEI,
+ .mask = 0xFFFF,
+ .shft = 16,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_SEI_MAX_DISPLAY_LUMINANCE,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_0,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_SEI_MIN_DISPLAY_LUMINANCE,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_1,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_MATRIX_COEFFICIENTS,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_D_VIDEO_SIGNAL_TYPE,
+ .mask = 0xFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_FORMAT,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_D_VIDEO_SIGNAL_TYPE,
+ .mask = 0x7,
+ .shft = 26,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_FULL_RANGE_FLAG,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_D_VIDEO_SIGNAL_TYPE,
+ .mask = 0x1,
+ .shft = 25,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_COLOUR_PRIMARIES,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_D_VIDEO_SIGNAL_TYPE,
+ .mask = 0xFF,
+ .shft = 16,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_TRANSFER_CHARACTERISTICS,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_D_VIDEO_SIGNAL_TYPE,
+ .mask = 0xFF,
+ .shft = 8,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_SEI_WHITE_POINT,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_2,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_SEI_DISPLAY_PRIMARIES_0,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_3,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_SEI_DISPLAY_PRIMARIES_1,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_4,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_SEI_DISPLAY_PRIMARIES_2,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_5,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+};
+
+static int s5p_mfc_dec_cleanup_ctx_ctrls(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_ctx_ctrl *ctx_ctrl;
+
+ while (!list_empty(&ctx->ctrls)) {
+ ctx_ctrl = list_entry((&ctx->ctrls)->next,
+ struct s5p_mfc_ctx_ctrl, list);
+ list_del(&ctx_ctrl->list);
+ kfree(ctx_ctrl);
+ }
+
+ INIT_LIST_HEAD(&ctx->ctrls);
+
+ return 0;
+}
+
+static int s5p_mfc_dec_init_ctx_ctrls(struct s5p_mfc_ctx *ctx)
+{
+ unsigned long i;
+ struct s5p_mfc_ctx_ctrl *ctx_ctrl;
+
+ INIT_LIST_HEAD(&ctx->ctrls);
+
+ for (i = 0; i < NUM_CTRL_CFGS; i++) {
+ ctx_ctrl = kzalloc(sizeof(struct s5p_mfc_ctx_ctrl), GFP_KERNEL);
+ if (ctx_ctrl == NULL) {
+ mfc_err_dev("Failed to allocate context control "\
+ "id: 0x%08x, type: %d\n",
+ mfc_ctrl_list[i].id,
+ mfc_ctrl_list[i].type);
+
+ s5p_mfc_dec_cleanup_ctx_ctrls(ctx);
+
+ return -ENOMEM;
+ }
+
+ ctx_ctrl->type = mfc_ctrl_list[i].type;
+ ctx_ctrl->id = mfc_ctrl_list[i].id;
+ ctx_ctrl->addr = mfc_ctrl_list[i].addr;
+ ctx_ctrl->has_new = 0;
+ ctx_ctrl->val = 0;
+
+ list_add_tail(&ctx_ctrl->list, &ctx->ctrls);
+ }
+
+ return 0;
+}
+
+static void mfc_dec_remove_buf_ctrls(struct list_head *head)
+{
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+
+ while (!list_empty(head)) {
+ buf_ctrl = list_entry(head->next,
+ struct s5p_mfc_buf_ctrl, list);
+ list_del(&buf_ctrl->list);
+ kfree(buf_ctrl);
+ }
+
+ INIT_LIST_HEAD(head);
+}
+
+static void s5p_mfc_dec_reset_buf_ctrls(struct list_head *head)
+{
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ buf_ctrl->has_new = 0;
+ buf_ctrl->val = 0;
+ buf_ctrl->old_val = 0;
+ buf_ctrl->updated = 0;
+ }
+}
+
+static int s5p_mfc_dec_init_buf_ctrls(struct s5p_mfc_ctx *ctx,
+ enum s5p_mfc_ctrl_type type, unsigned int index)
+{
+ unsigned long i;
+ struct s5p_mfc_ctx_ctrl *ctx_ctrl;
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+ struct list_head *head;
+
+ if (index >= MFC_MAX_BUFFERS) {
+ mfc_err_dev("Per-buffer control index is out of range\n");
+ return -EINVAL;
+ }
+
+ if (type & MFC_CTRL_TYPE_SRC) {
+ if (test_bit(index, &ctx->src_ctrls_avail)) {
+ s5p_mfc_dec_reset_buf_ctrls(&ctx->src_ctrls[index]);
+
+ return 0;
+ }
+
+ head = &ctx->src_ctrls[index];
+ } else if (type & MFC_CTRL_TYPE_DST) {
+ if (test_bit(index, &ctx->dst_ctrls_avail)) {
+ s5p_mfc_dec_reset_buf_ctrls(&ctx->dst_ctrls[index]);
+
+ return 0;
+ }
+
+ head = &ctx->dst_ctrls[index];
+ } else {
+ mfc_err_dev("Control type mismatch. type : %d\n", type);
+ return -EINVAL;
+ }
+
+ INIT_LIST_HEAD(head);
+
+ list_for_each_entry(ctx_ctrl, &ctx->ctrls, list) {
+ if (!(type & ctx_ctrl->type))
+ continue;
+
+ /* find matched control configuration index */
+ for (i = 0; i < NUM_CTRL_CFGS; i++) {
+ if (ctx_ctrl->id == mfc_ctrl_list[i].id)
+ break;
+ }
+
+ if (i == NUM_CTRL_CFGS) {
+ mfc_err_dev("Failed to find buffer control "\
+ "id: 0x%08x, type: %d\n",
+ ctx_ctrl->id, ctx_ctrl->type);
+ continue;
+ }
+
+ buf_ctrl = kzalloc(sizeof(struct s5p_mfc_buf_ctrl), GFP_KERNEL);
+ if (buf_ctrl == NULL) {
+ mfc_err_dev("Failed to allocate buffer control "\
+ "id: 0x%08x, type: %d\n",
+ mfc_ctrl_list[i].id,
+ mfc_ctrl_list[i].type);
+
+ mfc_dec_remove_buf_ctrls(head);
+
+ return -ENOMEM;
+ }
+
+ buf_ctrl->id = ctx_ctrl->id;
+ buf_ctrl->type = ctx_ctrl->type;
+ buf_ctrl->addr = ctx_ctrl->addr;
+
+ buf_ctrl->is_volatile = mfc_ctrl_list[i].is_volatile;
+ buf_ctrl->mode = mfc_ctrl_list[i].mode;
+ buf_ctrl->mask = mfc_ctrl_list[i].mask;
+ buf_ctrl->shft = mfc_ctrl_list[i].shft;
+ buf_ctrl->flag_mode = mfc_ctrl_list[i].flag_mode;
+ buf_ctrl->flag_addr = mfc_ctrl_list[i].flag_addr;
+ buf_ctrl->flag_shft = mfc_ctrl_list[i].flag_shft;
+
+ list_add_tail(&buf_ctrl->list, head);
+ }
+
+ s5p_mfc_dec_reset_buf_ctrls(head);
+
+ if (type & MFC_CTRL_TYPE_SRC)
+ set_bit(index, &ctx->src_ctrls_avail);
+ else
+ set_bit(index, &ctx->dst_ctrls_avail);
+
+ return 0;
+}
+
+static int s5p_mfc_dec_cleanup_buf_ctrls(struct s5p_mfc_ctx *ctx,
+ enum s5p_mfc_ctrl_type type, unsigned int index)
+{
+ struct list_head *head;
+
+ if (index >= MFC_MAX_BUFFERS) {
+ mfc_err_dev("Per-buffer control index is out of range\n");
+ return -EINVAL;
+ }
+
+ if (type & MFC_CTRL_TYPE_SRC) {
+ if (!(test_and_clear_bit(index, &ctx->src_ctrls_avail))) {
+ return 0;
+ }
+
+ head = &ctx->src_ctrls[index];
+ } else if (type & MFC_CTRL_TYPE_DST) {
+ if (!(test_and_clear_bit(index, &ctx->dst_ctrls_avail))) {
+ return 0;
+ }
+
+ head = &ctx->dst_ctrls[index];
+ } else {
+ mfc_err_dev("Control type mismatch. type : %d\n", type);
+ return -EINVAL;
+ }
+
+ mfc_dec_remove_buf_ctrls(head);
+
+ return 0;
+}
+
+static int s5p_mfc_dec_to_buf_ctrls(struct s5p_mfc_ctx *ctx, struct list_head *head)
+{
+ struct s5p_mfc_ctx_ctrl *ctx_ctrl;
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+
+ list_for_each_entry(ctx_ctrl, &ctx->ctrls, list) {
+ if (!(ctx_ctrl->type & MFC_CTRL_TYPE_SET) || !ctx_ctrl->has_new)
+ continue;
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if (!(buf_ctrl->type & MFC_CTRL_TYPE_SET))
+ continue;
+
+ if (buf_ctrl->id == ctx_ctrl->id) {
+ buf_ctrl->has_new = 1;
+ buf_ctrl->val = ctx_ctrl->val;
+ if (buf_ctrl->is_volatile)
+ buf_ctrl->updated = 0;
+
+ ctx_ctrl->has_new = 0;
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int s5p_mfc_dec_to_ctx_ctrls(struct s5p_mfc_ctx *ctx, struct list_head *head)
+{
+ struct s5p_mfc_ctx_ctrl *ctx_ctrl;
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if (!(buf_ctrl->type & MFC_CTRL_TYPE_GET) || !buf_ctrl->has_new)
+ continue;
+
+ list_for_each_entry(ctx_ctrl, &ctx->ctrls, list) {
+ if (!(ctx_ctrl->type & MFC_CTRL_TYPE_GET))
+ continue;
+
+ if (ctx_ctrl->id == buf_ctrl->id) {
+ ctx_ctrl->has_new = 1;
+ ctx_ctrl->val = buf_ctrl->val;
+
+ buf_ctrl->has_new = 0;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int s5p_mfc_dec_set_buf_ctrls_val(struct s5p_mfc_ctx *ctx, struct list_head *head)
+{
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ struct s5p_mfc_dev *dev = ctx->dev;
+ unsigned int value = 0;
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if (!(buf_ctrl->type & MFC_CTRL_TYPE_SET) || !buf_ctrl->has_new)
+ continue;
+
+ /* read old vlaue */
+ value = MFC_READL(buf_ctrl->addr);
+
+ /* save old vlaue for recovery */
+ if (buf_ctrl->is_volatile)
+ buf_ctrl->old_val = (value >> buf_ctrl->shft) & buf_ctrl->mask;
+
+ /* write new value */
+ value &= ~(buf_ctrl->mask << buf_ctrl->shft);
+ value |= ((buf_ctrl->val & buf_ctrl->mask) << buf_ctrl->shft);
+ MFC_WRITEL(value, buf_ctrl->addr);
+
+ /* set change flag bit */
+ if (buf_ctrl->flag_mode == MFC_CTRL_MODE_SFR) {
+ value = MFC_READL(buf_ctrl->flag_addr);
+ value |= (1 << buf_ctrl->flag_shft);
+ MFC_WRITEL(value, buf_ctrl->flag_addr);
+ }
+
+ buf_ctrl->has_new = 0;
+ buf_ctrl->updated = 1;
+
+ if (buf_ctrl->id == V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG)
+ dec->stored_tag = buf_ctrl->val;
+
+ mfc_debug(6, "[CTRLS] Set buffer control id: 0x%08x, val: %d\n",
+ buf_ctrl->id, buf_ctrl->val);
+ }
+
+ return 0;
+}
+
+static int s5p_mfc_dec_get_buf_ctrls_val(struct s5p_mfc_ctx *ctx, struct list_head *head)
+{
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ unsigned int value = 0;
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if (!(buf_ctrl->type & MFC_CTRL_TYPE_GET))
+ continue;
+
+ value = MFC_READL(buf_ctrl->addr);
+ value = (value >> buf_ctrl->shft) & buf_ctrl->mask;
+
+ buf_ctrl->val = value;
+ buf_ctrl->has_new = 1;
+
+ if (IS_VP9_DEC(ctx)) {
+ if (buf_ctrl->id == V4L2_CID_MPEG_VIDEO_FULL_RANGE_FLAG)
+ buf_ctrl->val = dec->color_range;
+ else if (buf_ctrl->id == V4L2_CID_MPEG_VIDEO_COLOUR_PRIMARIES)
+ buf_ctrl->val = dec->color_space;
+ }
+
+ mfc_debug(6, "[CTRLS] Get buffer control id: 0x%08x, val: %d\n",
+ buf_ctrl->id, buf_ctrl->val);
+ }
+
+ return 0;
+}
+
+static int s5p_mfc_dec_set_buf_ctrls_val_nal_q_dec(struct s5p_mfc_ctx *ctx,
+ struct list_head *head, DecoderInputStr *pInStr)
+{
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+
+ mfc_debug_enter();
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if (!(buf_ctrl->type & MFC_CTRL_TYPE_SET) || !buf_ctrl->has_new)
+ continue;
+ switch (buf_ctrl->id) {
+ case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG:
+ pInStr->PictureTag &= ~(buf_ctrl->mask << buf_ctrl->shft);
+ pInStr->PictureTag |=
+ (buf_ctrl->val & buf_ctrl->mask) << buf_ctrl->shft;
+ dec->stored_tag = buf_ctrl->val;
+ break;
+ /* If new dynamic controls are added, insert here */
+ default:
+ mfc_info_ctx("[NALQ] can't find control, id: 0x%x\n",
+ buf_ctrl->id);
+ }
+ buf_ctrl->has_new = 0;
+ buf_ctrl->updated = 1;
+
+ mfc_debug(6, "[NALQ][CTRLS] Set buffer control id: 0x%08x, val: %d\n",
+ buf_ctrl->id, buf_ctrl->val);
+ }
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+static int s5p_mfc_dec_get_buf_ctrls_val_nal_q_dec(struct s5p_mfc_ctx *ctx,
+ struct list_head *head, DecoderOutputStr *pOutStr)
+{
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+ unsigned int value = 0;
+
+ mfc_debug_enter();
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if (!(buf_ctrl->type & MFC_CTRL_TYPE_GET))
+ continue;
+ switch (buf_ctrl->id) {
+ case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG:
+ value = pOutStr->PictureTagTop;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_DISPLAY_STATUS:
+ value = pOutStr->DisplayStatus;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_LUMA:
+ value = pOutStr->DisplayFirstCrc;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_CHROMA:
+ value = pOutStr->DisplaySecondCrc;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_CHROMA1:
+ value = pOutStr->DisplayThirdCrc;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_2BIT_LUMA:
+ value = pOutStr->DisplayFirst2BitCrc;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_2BIT_CHROMA:
+ value = pOutStr->DisplaySecond2BitCrc;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_CRC_GENERATED:
+ value = pOutStr->DisplayStatus;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_AVAIL:
+ value = pOutStr->SeiAvail;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRGMENT_ID:
+ value = pOutStr->FramePackArrgmentId;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_INFO:
+ value = pOutStr->FramePackSeiInfo;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_GRID_POS:
+ value = pOutStr->FramePackGridPos;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_MVC_VIEW_ID:
+ value = 0;
+ break;
+ /* TO-DO: SEI information has to be added in NAL-Q */
+ case V4L2_CID_MPEG_VIDEO_SEI_MAX_PIC_AVERAGE_LIGHT:
+ case V4L2_CID_MPEG_VIDEO_SEI_MAX_CONTENT_LIGHT:
+ value = pOutStr->ContentLightLevelInfoSei;
+ break;
+ case V4L2_CID_MPEG_VIDEO_SEI_MAX_DISPLAY_LUMINANCE:
+ value = pOutStr->MasteringDisplayColourVolumeSei0;
+ break;
+ case V4L2_CID_MPEG_VIDEO_SEI_MIN_DISPLAY_LUMINANCE:
+ value = pOutStr->MasteringDisplayColourVolumeSei1;
+ break;
+ case V4L2_CID_MPEG_VIDEO_FULL_RANGE_FLAG:
+ case V4L2_CID_MPEG_VIDEO_COLOUR_PRIMARIES:
+ case V4L2_CID_MPEG_VIDEO_FORMAT:
+ case V4L2_CID_MPEG_VIDEO_TRANSFER_CHARACTERISTICS:
+ case V4L2_CID_MPEG_VIDEO_MATRIX_COEFFICIENTS:
+ value = pOutStr->VideoSignalType;
+ break;
+ case V4L2_CID_MPEG_VIDEO_SEI_WHITE_POINT:
+ value = pOutStr->MasteringDisplayColourVolumeSei2;
+ break;
+ case V4L2_CID_MPEG_VIDEO_SEI_DISPLAY_PRIMARIES_0:
+ value = pOutStr->MasteringDisplayColourVolumeSei3;
+ break;
+ case V4L2_CID_MPEG_VIDEO_SEI_DISPLAY_PRIMARIES_1:
+ value = pOutStr->MasteringDisplayColourVolumeSei4;
+ break;
+ case V4L2_CID_MPEG_VIDEO_SEI_DISPLAY_PRIMARIES_2:
+ value = pOutStr->MasteringDisplayColourVolumeSei5;
+ break;
+ /* If new dynamic controls are added, insert here */
+ default:
+ mfc_info_ctx("[NALQ] can't find control, id: 0x%x\n",
+ buf_ctrl->id);
+ }
+ value = (value >> buf_ctrl->shft) & buf_ctrl->mask;
+
+ buf_ctrl->val = value;
+ buf_ctrl->has_new = 1;
+
+ if (IS_VP9_DEC(ctx)) {
+ if (buf_ctrl->id == V4L2_CID_MPEG_VIDEO_FULL_RANGE_FLAG)
+ buf_ctrl->val = dec->color_range;
+ else if (buf_ctrl->id == V4L2_CID_MPEG_VIDEO_COLOUR_PRIMARIES)
+ buf_ctrl->val = dec->color_space;
+ }
+
+ mfc_debug(6, "[NALQ][CTRLS] Get buffer control id: 0x%08x, val: %d\n",
+ buf_ctrl->id, buf_ctrl->val);
+ }
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+static int s5p_mfc_dec_recover_buf_ctrls_val(struct s5p_mfc_ctx *ctx, struct list_head *head)
+{
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+ struct s5p_mfc_dev *dev = ctx->dev;
+ unsigned int value = 0;
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if (!(buf_ctrl->type & MFC_CTRL_TYPE_SET)
+ || !buf_ctrl->is_volatile
+ || !buf_ctrl->updated)
+ continue;
+
+ value = MFC_READL(buf_ctrl->addr);
+ value &= ~(buf_ctrl->mask << buf_ctrl->shft);
+ value |= ((buf_ctrl->old_val & buf_ctrl->mask) << buf_ctrl->shft);
+ MFC_WRITEL(value, buf_ctrl->addr);
+
+ /* clear change flag bit */
+ if (buf_ctrl->flag_mode == MFC_CTRL_MODE_SFR) {
+ value = MFC_READL(buf_ctrl->flag_addr);
+ value &= ~(1 << buf_ctrl->flag_shft);
+ MFC_WRITEL(value, buf_ctrl->flag_addr);
+ }
+
+ buf_ctrl->updated = 0;
+ mfc_debug(6, "[CTRLS] Recover buffer control id: 0x%08x, old val: %d\n",
+ buf_ctrl->id, buf_ctrl->old_val);
+ }
+
+ return 0;
+}
+
+static int s5p_mfc_dec_get_buf_update_val(struct s5p_mfc_ctx *ctx,
+ struct list_head *head, unsigned int id, int value)
+{
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if (buf_ctrl->id == id) {
+ buf_ctrl->val = value;
+ mfc_debug(6, "[CTRLS] Update buffer control id: 0x%08x, val: %d\n",
+ buf_ctrl->id, buf_ctrl->val);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int s5p_mfc_dec_recover_buf_ctrls_nal_q(struct s5p_mfc_ctx *ctx,
+ struct list_head *head)
+{
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if (!(buf_ctrl->type & MFC_CTRL_TYPE_SET)
+ || !(buf_ctrl->updated))
+ continue;
+
+ buf_ctrl->has_new = 1;
+ buf_ctrl->updated = 0;
+ mfc_debug(6, "[NALQ][CTRLS] Recover buffer control id: 0x%08x, val: %d\n",
+ buf_ctrl->id, buf_ctrl->val);
+ }
+
+ return 0;
+}
+
+struct s5p_mfc_ctrls_ops decoder_ctrls_ops = {
+ .init_ctx_ctrls = s5p_mfc_dec_init_ctx_ctrls,
+ .cleanup_ctx_ctrls = s5p_mfc_dec_cleanup_ctx_ctrls,
+ .init_buf_ctrls = s5p_mfc_dec_init_buf_ctrls,
+ .reset_buf_ctrls = s5p_mfc_dec_reset_buf_ctrls,
+ .cleanup_buf_ctrls = s5p_mfc_dec_cleanup_buf_ctrls,
+ .to_buf_ctrls = s5p_mfc_dec_to_buf_ctrls,
+ .to_ctx_ctrls = s5p_mfc_dec_to_ctx_ctrls,
+ .set_buf_ctrls_val = s5p_mfc_dec_set_buf_ctrls_val,
+ .get_buf_ctrls_val = s5p_mfc_dec_get_buf_ctrls_val,
+ .set_buf_ctrls_val_nal_q_dec = s5p_mfc_dec_set_buf_ctrls_val_nal_q_dec,
+ .get_buf_ctrls_val_nal_q_dec = s5p_mfc_dec_get_buf_ctrls_val_nal_q_dec,
+ .recover_buf_ctrls_val = s5p_mfc_dec_recover_buf_ctrls_val,
+ .get_buf_update_val = s5p_mfc_dec_get_buf_update_val,
+ .recover_buf_ctrls_nal_q = s5p_mfc_dec_recover_buf_ctrls_nal_q,
+};
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_dec_vb2_ops.c
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "mfc_common.h"
+
+#include "mfc_hwlock.h"
+#include "mfc_nal_q.h"
+#include "mfc_opr.h"
+#include "mfc_sync.h"
+
+#include "mfc_queue.h"
+#include "mfc_utils.h"
+#include "mfc_buf.h"
+#include "mfc_mem.h"
+
+static int s5p_mfc_dec_queue_setup(struct vb2_queue *vq,
+ unsigned int *buf_count, unsigned int *plane_count,
+ unsigned int psize[], struct device *alloc_devs[])
+{
+ struct s5p_mfc_ctx *ctx;
+ struct s5p_mfc_dev *dev;
+ struct s5p_mfc_dec *dec;
+ struct s5p_mfc_raw_info *raw;
+ int i;
+
+ mfc_debug_enter();
+
+ if (!vq) {
+ mfc_err_dev("no vb2_queue info\n");
+ return -EINVAL;
+ }
+
+ ctx = vq->drv_priv;
+ if (!ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return -EINVAL;
+ }
+ dev = ctx->dev;
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+ dec = ctx->dec_priv;
+ if (!dec) {
+ mfc_err_dev("no mfc decoder to run\n");
+ return -EINVAL;
+ }
+
+ raw = &ctx->raw_buf;
+
+ /* Video output for decoding (source)
+ * this can be set after getting an instance */
+ if (ctx->state == MFCINST_GOT_INST &&
+ vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ mfc_debug(4, "dec src\n");
+ /* A single plane is required for input */
+ *plane_count = 1;
+ if (*buf_count < 1)
+ *buf_count = 1;
+ if (*buf_count > MFC_MAX_BUFFERS)
+ *buf_count = MFC_MAX_BUFFERS;
+
+ psize[0] = dec->src_buf_size;
+ alloc_devs[0] = dev->device;
+ /* Video capture for decoding (destination)
+ * this can be set after the header was parsed */
+ } else if (ctx->state == MFCINST_HEAD_PARSED &&
+ vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ mfc_debug(4, "dec dst\n");
+ /* Output plane count is different by the pixel format */
+ *plane_count = ctx->dst_fmt->mem_planes;
+ /* Setup buffer count */
+ if (*buf_count < ctx->dpb_count)
+ *buf_count = ctx->dpb_count;
+ if (*buf_count > MFC_MAX_BUFFERS)
+ *buf_count = MFC_MAX_BUFFERS;
+
+ if (ctx->dst_fmt->mem_planes == 1) {
+ psize[0] = raw->total_plane_size;
+ alloc_devs[0] = dev->device;
+ } else {
+ for (i = 0; i < ctx->dst_fmt->num_planes; i++) {
+ psize[i] = raw->plane_size[i];
+ alloc_devs[i] = dev->device;
+ }
+ }
+ } else {
+ mfc_err_ctx("State seems invalid. State = %d, vq->type = %d\n",
+ ctx->state, vq->type);
+ return -EINVAL;
+ }
+
+ mfc_debug(2, "buf_count: %d, plane_count: %d, type: %#x\n",
+ *buf_count, *plane_count, vq->type);
+ for (i = 0; i < *plane_count; i++)
+ mfc_debug(2, "plane[%d] size: %d\n", i, psize[i]);
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+static void s5p_mfc_dec_unlock(struct vb2_queue *q)
+{
+ struct s5p_mfc_ctx *ctx = q->drv_priv;
+ struct s5p_mfc_dev *dev;
+
+ if (!ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return;
+ }
+ dev = ctx->dev;
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return;
+ }
+
+ mutex_unlock(&dev->mfc_mutex);
+}
+
+static void s5p_mfc_dec_lock(struct vb2_queue *q)
+{
+ struct s5p_mfc_ctx *ctx = q->drv_priv;
+ struct s5p_mfc_dev *dev;
+
+ if (!ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return;
+ }
+ dev = ctx->dev;
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return;
+ }
+
+ mutex_lock(&dev->mfc_mutex);
+}
+
+static int s5p_mfc_dec_buf_init(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct s5p_mfc_ctx *ctx = vq->drv_priv;
+ struct s5p_mfc_dev *dev;
+ struct s5p_mfc_dec *dec;
+ struct s5p_mfc_buf *buf = vb_to_mfc_buf(vb);
+ dma_addr_t start_raw;
+ int i, ret;
+
+ mfc_debug_enter();
+ if (!ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return -EINVAL;
+ }
+ dev = ctx->dev;
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+ dec = ctx->dec_priv;
+ if (!dec) {
+ mfc_err_dev("no mfc decoder to run\n");
+ return -EINVAL;
+ }
+
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ ret = s5p_mfc_check_vb_with_fmt(ctx->dst_fmt, vb);
+ if (ret < 0)
+ return ret;
+
+ start_raw = s5p_mfc_mem_get_daddr_vb(vb, 0);
+ if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV12N) {
+ buf->addr[0][0] = start_raw;
+ buf->addr[0][1] = NV12N_CBCR_BASE(start_raw,
+ ctx->img_width,
+ ctx->img_height);
+ } else if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV12N_10B) {
+ buf->addr[0][0] = start_raw;
+ buf->addr[0][1] = NV12N_10B_CBCR_BASE(start_raw,
+ ctx->img_width,
+ ctx->img_height);
+ } else if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420N) {
+ buf->addr[0][0] = start_raw;
+ buf->addr[0][1] = YUV420N_CB_BASE(start_raw,
+ ctx->img_width,
+ ctx->img_height);
+ buf->addr[0][2] = YUV420N_CR_BASE(start_raw,
+ ctx->img_width,
+ ctx->img_height);
+ } else {
+ for (i = 0; i < ctx->dst_fmt->mem_planes; i++)
+ buf->addr[0][i] = s5p_mfc_mem_get_daddr_vb(vb, i);
+ }
+
+ if (call_cop(ctx, init_buf_ctrls, ctx, MFC_CTRL_TYPE_DST,
+ vb->index) < 0)
+ mfc_err_ctx("failed in init_buf_ctrls\n");
+ } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ ret = s5p_mfc_check_vb_with_fmt(ctx->src_fmt, vb);
+ if (ret < 0)
+ return ret;
+
+ buf->addr[0][0] = s5p_mfc_mem_get_daddr_vb(vb, 0);
+
+ if (call_cop(ctx, init_buf_ctrls, ctx, MFC_CTRL_TYPE_SRC,
+ vb->index) < 0)
+ mfc_err_ctx("failed in init_buf_ctrls\n");
+ } else {
+ mfc_err_ctx("s5p_mfc_dec_buf_init: unknown queue type\n");
+ return -EINVAL;
+ }
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+static int s5p_mfc_dec_buf_prepare(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct s5p_mfc_ctx *ctx = vq->drv_priv;
+ struct s5p_mfc_dec *dec;
+ struct s5p_mfc_raw_info *raw;
+ unsigned int index = vb->index;
+ size_t buf_size;
+ int i;
+
+ if (!ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return -EINVAL;
+ }
+ dec = ctx->dec_priv;
+ if (!dec) {
+ mfc_err_dev("no mfc decoder to run\n");
+ return -EINVAL;
+ }
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ raw = &ctx->raw_buf;
+ /* check the size per plane */
+ if (ctx->dst_fmt->mem_planes == 1) {
+ buf_size = vb2_plane_size(vb, 0);
+ mfc_debug(2, "[FRAME] single plane vb size: %lu, calc size: %d\n",
+ buf_size, raw->total_plane_size);
+ if (buf_size < raw->total_plane_size) {
+ mfc_err_ctx("[FRAME] single plane size(%d) is smaller than (%d)\n",
+ buf_size, raw->total_plane_size);
+ return -EINVAL;
+ }
+ } else {
+ for (i = 0; i < ctx->dst_fmt->mem_planes; i++) {
+ buf_size = vb2_plane_size(vb, i);
+ mfc_debug(2, "[FRAME] plane[%d] vb size: %lu, calc size: %d\n",
+ i, buf_size, raw->plane_size[i]);
+ if (buf_size < raw->plane_size[i]) {
+ mfc_err_ctx("[FRAME] plane[%d] size(%d) is smaller than (%d)\n",
+ i, buf_size, raw->plane_size[i]);
+ return -EINVAL;
+ }
+ }
+ }
+ } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ buf_size = vb2_plane_size(vb, 0);
+ mfc_debug(2, "[STREAM] vb size: %lu, calc size: %d\n",
+ buf_size, dec->src_buf_size);
+
+ if (buf_size < dec->src_buf_size) {
+ mfc_err_ctx("[STREAM] size(%d) is smaller than (%d)\n",
+ buf_size, dec->src_buf_size);
+ return -EINVAL;
+ }
+
+ if (call_cop(ctx, to_buf_ctrls, ctx, &ctx->src_ctrls[index]) < 0)
+ mfc_err_ctx("failed in to_buf_ctrls\n");
+ }
+
+ return 0;
+}
+
+static void s5p_mfc_dec_buf_finish(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct s5p_mfc_ctx *ctx = vq->drv_priv;
+ unsigned int index = vb->index;
+
+ if (!ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return;
+ }
+
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ if (call_cop(ctx, to_ctx_ctrls, ctx, &ctx->dst_ctrls[index]) < 0)
+ mfc_err_ctx("failed in to_ctx_ctrls\n");
+ } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ if (call_cop(ctx, to_ctx_ctrls, ctx, &ctx->src_ctrls[index]) < 0)
+ mfc_err_ctx("failed in to_ctx_ctrls\n");
+ }
+}
+
+static void s5p_mfc_dec_buf_cleanup(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct s5p_mfc_ctx *ctx = vq->drv_priv;
+ unsigned int index = vb->index;
+
+ mfc_debug_enter();
+ if (!ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return;
+ }
+
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ if (call_cop(ctx, cleanup_buf_ctrls, ctx,
+ MFC_CTRL_TYPE_DST, index) < 0)
+ mfc_err_ctx("failed in cleanup_buf_ctrls\n");
+ } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ if (call_cop(ctx, cleanup_buf_ctrls, ctx,
+ MFC_CTRL_TYPE_SRC, index) < 0)
+ mfc_err_ctx("failed in cleanup_buf_ctrls\n");
+ } else {
+ mfc_err_ctx("s5p_mfc_dec_buf_cleanup: unknown queue type\n");
+ }
+
+ mfc_debug_leave();
+}
+
+static int s5p_mfc_dec_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct s5p_mfc_ctx *ctx = q->drv_priv;
+ struct s5p_mfc_dev *dev;
+
+ if (!ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return -EINVAL;
+ }
+
+ dev = ctx->dev;
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ if (ctx->state == MFCINST_FINISHING)
+ s5p_mfc_change_state(ctx, MFCINST_RUNNING);
+
+ /* If context is ready then dev = work->data;schedule it to run */
+ if (s5p_mfc_dec_ctx_ready(ctx)) {
+ s5p_mfc_set_bit(ctx->num, &dev->work_bits);
+ }
+
+ s5p_mfc_try_run(dev);
+
+ return 0;
+}
+
+static void mfc_dec_src_stop_streaming(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev;
+ struct s5p_mfc_dec *dec;
+ struct s5p_mfc_buf *src_mb;
+ int index, csd, condition = 0;
+ int ret = 0;
+
+ dev = ctx->dev;
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return;
+ }
+
+ dec = ctx->dec_priv;
+ if (!dec) {
+ mfc_err_dev("no mfc decoder to run\n");
+ return;
+ }
+
+ while (1) {
+ csd = s5p_mfc_peek_buf_csd(&ctx->buf_queue_lock, &ctx->src_buf_queue);
+
+ if (csd == 1) {
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ if (need_to_special_parsing(ctx)) {
+ s5p_mfc_change_state(ctx, MFCINST_SPECIAL_PARSING);
+ condition = S5P_FIMV_R2H_CMD_SEQ_DONE_RET;
+ mfc_info_ctx("try to special parsing! (before NAL_START)\n");
+ } else if (need_to_special_parsing_nal(ctx)) {
+ s5p_mfc_change_state(ctx, MFCINST_SPECIAL_PARSING_NAL);
+ condition = S5P_FIMV_R2H_CMD_FRAME_DONE_RET;
+ mfc_info_ctx("try to special parsing! (after NAL_START)\n");
+ } else {
+ mfc_info_ctx("can't parsing CSD!, state = %d\n", ctx->state);
+ }
+
+ if (condition) {
+ s5p_mfc_set_bit(ctx->num, &dev->work_bits);
+
+ ret = s5p_mfc_just_run(dev, ctx->num);
+ if (ret) {
+ mfc_err_ctx("Failed to run MFC\n");
+ } else {
+ if (s5p_mfc_wait_for_done_ctx(ctx, condition))
+ mfc_err_ctx("special parsing time out\n");
+ }
+ }
+ }
+
+ src_mb = s5p_mfc_get_del_buf(&ctx->buf_queue_lock, &ctx->src_buf_queue, MFC_BUF_NO_TOUCH_USED);
+ if (!src_mb)
+ break;
+
+ index = src_mb->vb.vb2_buf.index;
+
+ if (ctx->is_drm)
+ s5p_mfc_stream_unprotect(ctx, src_mb, index);
+ vb2_set_plane_payload(&src_mb->vb.vb2_buf, 0, 0);
+ vb2_buffer_done(&src_mb->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+ }
+
+ dec->consumed = 0;
+ dec->remained_size = 0;
+ ctx->check_dump = 0;
+
+ s5p_mfc_init_queue(&ctx->src_buf_queue);
+
+ index = 0;
+ while (index < MFC_MAX_BUFFERS) {
+ index = find_next_bit(&ctx->src_ctrls_avail,
+ MFC_MAX_BUFFERS, index);
+ if (index < MFC_MAX_BUFFERS)
+ call_cop(ctx, reset_buf_ctrls, &ctx->src_ctrls[index]);
+ index++;
+ }
+}
+
+static void mfc_dec_dst_stop_streaming(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dec *dec;
+ int index = 0;
+
+ dec = ctx->dec_priv;
+ if (!dec) {
+ mfc_err_dev("no mfc decoder to run\n");
+ return;
+ }
+
+ s5p_mfc_cleanup_assigned_fd(ctx);
+ s5p_mfc_cleanup_queue(&ctx->buf_queue_lock, &ctx->ref_buf_queue);
+
+ dec->dynamic_used = 0;
+ dec->err_reuse_flag = 0;
+ dec->dec_only_release_flag = 0;
+
+ s5p_mfc_cleanup_queue(&ctx->buf_queue_lock, &ctx->dst_buf_queue);
+
+ ctx->is_dpb_realloc = 0;
+ dec->available_dpb = 0;
+
+ dec->y_addr_for_pb = 0;
+
+ s5p_mfc_cleanup_assigned_dpb(ctx);
+
+ while (index < MFC_MAX_BUFFERS) {
+ index = find_next_bit(&ctx->dst_ctrls_avail,
+ MFC_MAX_BUFFERS, index);
+ if (index < MFC_MAX_BUFFERS)
+ call_cop(ctx, reset_buf_ctrls, &ctx->dst_ctrls[index]);
+ index++;
+ }
+
+ if (ctx->wait_state == WAIT_INITBUF_DONE ||
+ ctx->wait_state == WAIT_DECODING) {
+ ctx->wait_state = WAIT_NONE;
+ mfc_debug(2, "Decoding can be started now\n");
+ }
+}
+
+static void s5p_mfc_dec_stop_streaming(struct vb2_queue *q)
+{
+ struct s5p_mfc_ctx *ctx = q->drv_priv;
+ struct s5p_mfc_dev *dev;
+ int ret = 0;
+ int prev_state;
+
+ if (!ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return;
+ }
+
+ dev = ctx->dev;
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return;
+ }
+
+ mfc_info_ctx("dec stop_streaming is called, hwlock : %d, type : %d\n",
+ test_bit(ctx->num, &dev->hwlock.bits), q->type);
+ MFC_TRACE_CTX("** DEC streamoff(type:%d)\n", q->type);
+
+ MFC_TRACE_CTX_HWLOCK("**DEC streamoff(type:%d)\n", q->type);
+ /* If a H/W operation is in progress, wait for it complete */
+ ret = s5p_mfc_get_hwlock_ctx(ctx);
+ if (ret < 0) {
+ mfc_err_ctx("Failed to get hwlock\n");
+ return;
+ }
+
+ if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ mfc_dec_dst_stop_streaming(ctx);
+ else if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ mfc_dec_src_stop_streaming(ctx);
+
+ if (ctx->state == MFCINST_FINISHING)
+ s5p_mfc_change_state(ctx, MFCINST_RUNNING);
+
+ if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && need_to_dpb_flush(ctx)) {
+ prev_state = ctx->state;
+ s5p_mfc_change_state(ctx, MFCINST_DPB_FLUSHING);
+ s5p_mfc_set_bit(ctx->num, &dev->work_bits);
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ mfc_info_ctx("try to DPB flush\n");
+ ret = s5p_mfc_just_run(dev, ctx->num);
+ if (ret) {
+ mfc_err_ctx("Failed to run MFC\n");
+ s5p_mfc_release_hwlock_ctx(ctx);
+ s5p_mfc_cleanup_work_bit_and_try_run(ctx);
+ return;
+ }
+
+ if (s5p_mfc_wait_for_done_ctx(ctx, S5P_FIMV_R2H_CMD_DPB_FLUSH_RET)) {
+ mfc_err_ctx("time out during DPB flush\n");
+ dev->logging_data->cause |= (1 << MFC_CAUSE_FAIL_DPB_FLUSH);
+ call_dop(dev, dump_and_stop_always, dev);
+ }
+
+ s5p_mfc_change_state(ctx, prev_state);
+ }
+
+ mfc_debug(2, "buffer cleanup & flush is done in stop_streaming, type : %d\n", q->type);
+
+ s5p_mfc_clear_bit(ctx->num, &dev->work_bits);
+ s5p_mfc_release_hwlock_ctx(ctx);
+
+ if (s5p_mfc_dec_ctx_ready(ctx))
+ s5p_mfc_set_bit(ctx->num, &dev->work_bits);
+ if (s5p_mfc_is_work_to_do(dev))
+ queue_work(dev->butler_wq, &dev->butler_work);
+}
+
+static void s5p_mfc_dec_buf_queue(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct s5p_mfc_ctx *ctx = vq->drv_priv;
+ struct s5p_mfc_dev *dev;
+ struct s5p_mfc_dec *dec;
+ struct s5p_mfc_buf *buf = vb_to_mfc_buf(vb);
+ int i;
+ unsigned char *stream_vir = NULL;
+
+ mfc_debug_enter();
+ if (!ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return;
+ }
+
+ dev = ctx->dev;
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return;
+ }
+
+ dec = ctx->dec_priv;
+ if (!dec) {
+ mfc_err_dev("no mfc decoder to run\n");
+ return;
+ }
+
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ mfc_debug(2, "[BUFINFO] ctx[%d] add src index:%d, addr: 0x%08llx\n",
+ ctx->num, vb->index, buf->addr[0][0]);
+ if (dec->dst_memtype == V4L2_MEMORY_DMABUF &&
+ ctx->state < MFCINST_HEAD_PARSED && !ctx->is_drm)
+ stream_vir = vb2_plane_vaddr(vb, 0);
+
+ buf->vir_addr = stream_vir;
+
+ s5p_mfc_add_tail_buf(&ctx->buf_queue_lock, &ctx->src_buf_queue, buf);
+
+ MFC_TRACE_CTX("Q src[%d] fd: %d, %#llx\n",
+ vb->index, vb->planes[0].m.fd, buf->addr[0][0]);
+ } else if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ for (i = 0; i < ctx->dst_fmt->mem_planes; i++)
+ mfc_debug(2, "[BUFINFO] ctx[%d] add dst index: %d, addr[%d]: 0x%08llx\n",
+ ctx->num, vb->index, i, buf->addr[0][i]);
+ s5p_mfc_store_dpb(ctx, vb);
+
+ if ((dec->dst_memtype == V4L2_MEMORY_USERPTR || dec->dst_memtype == V4L2_MEMORY_DMABUF) &&
+ s5p_mfc_is_queue_count_same(&ctx->buf_queue_lock,
+ &ctx->dst_buf_queue, dec->total_dpb_count))
+ ctx->capture_state = QUEUE_BUFS_MMAPED;
+
+ MFC_TRACE_CTX("Q dst[%d] fd: %d, %#llx / avail %#lx used %#x\n",
+ vb->index, vb->planes[0].m.fd, buf->addr[0][0],
+ dec->available_dpb, dec->dynamic_used);
+ } else {
+ mfc_err_ctx("Unsupported buffer type (%d)\n", vq->type);
+ }
+
+ if (s5p_mfc_dec_ctx_ready(ctx)) {
+ s5p_mfc_set_bit(ctx->num, &dev->work_bits);
+ s5p_mfc_try_run(dev);
+ }
+
+ mfc_debug_leave();
+}
+
+struct vb2_ops s5p_mfc_dec_qops = {
+ .queue_setup = s5p_mfc_dec_queue_setup,
+ .wait_prepare = s5p_mfc_dec_unlock,
+ .wait_finish = s5p_mfc_dec_lock,
+ .buf_init = s5p_mfc_dec_buf_init,
+ .buf_prepare = s5p_mfc_dec_buf_prepare,
+ .buf_finish = s5p_mfc_dec_buf_finish,
+ .buf_cleanup = s5p_mfc_dec_buf_cleanup,
+ .start_streaming = s5p_mfc_dec_start_streaming,
+ .stop_streaming = s5p_mfc_dec_stop_streaming,
+ .buf_queue = s5p_mfc_dec_buf_queue,
+};
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_enc.c
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "mfc_enc.h"
+#include "mfc_enc_internal.h"
+
+#include "mfc_hwlock.h"
+#include "mfc_otf.h"
+#include "mfc_opr.h"
+#include "mfc_sync.h"
+
+#include "mfc_qos.h"
+#include "mfc_queue.h"
+#include "mfc_utils.h"
+#include "mfc_buf.h"
+#include "mfc_mem.h"
+
+static struct s5p_mfc_fmt *mfc_enc_find_format(struct s5p_mfc_ctx *ctx,
+ unsigned int pixelformat)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_fmt *fmt = NULL;
+ unsigned long i;
+
+ for (i = 0; i < NUM_FORMATS; i++) {
+ if (enc_formats[i].fourcc == pixelformat) {
+ fmt = (struct s5p_mfc_fmt *)&enc_formats[i];
+ break;
+ }
+ }
+
+ if (!dev->pdata->support_10bit && (fmt->type & MFC_FMT_10BIT)) {
+ mfc_err_ctx("[FRAME] 10bit is not supported\n");
+ fmt = NULL;
+ }
+ if (!dev->pdata->support_422 && (fmt->type & MFC_FMT_422)) {
+ mfc_err_ctx("[FRAME] 422 is not supported\n");
+ fmt = NULL;
+ }
+ if (!dev->pdata->support_rgb && (fmt->type & MFC_FMT_RGB)) {
+ mfc_err_ctx("[FRAME] RGB is not supported\n");
+ fmt = NULL;
+ }
+
+ return fmt;
+}
+
+static struct v4l2_queryctrl *mfc_enc_get_ctrl(int id)
+{
+ unsigned long i;
+
+ for (i = 0; i < NUM_CTRLS; ++i)
+ if (id == controls[i].id)
+ return &controls[i];
+ return NULL;
+}
+
+static int mfc_enc_check_ctrl_val(struct s5p_mfc_ctx *ctx, struct v4l2_control *ctrl)
+{
+ struct v4l2_queryctrl *c;
+
+ c = mfc_enc_get_ctrl(ctrl->id);
+ if (!c) {
+ mfc_err_ctx("[CTRLS] not supported control id (%#x)\n", ctrl->id);
+ return -EINVAL;
+ }
+
+ if (ctrl->id == V4L2_CID_MPEG_VIDEO_GOP_SIZE
+ && ctrl->value > c->maximum) {
+ mfc_info_ctx("GOP_SIZE is changed to max(%d -> %d)\n",
+ ctrl->value, c->maximum);
+ ctrl->value = c->maximum;
+ }
+
+ if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER) {
+ if ((ctrl->value & ~(1 << 16)) < c->minimum || (ctrl->value & ~(1 << 16)) > c->maximum
+ || (c->step != 0 && (ctrl->value & ~(1 << 16)) % c->step != 0)) {
+ mfc_err_ctx("[CTRLS][HIERARCHICAL] Invalid control value for %#x (%#x)\n",
+ ctrl->id, ctrl->value);
+ return -ERANGE;
+ } else {
+ return 0;
+ }
+ }
+
+ if (ctrl->value < c->minimum || ctrl->value > c->maximum
+ || (c->step != 0 && ctrl->value % c->step != 0)) {
+ mfc_err_ctx("[CTRLS] Invalid control value for %#x (%#x)\n",
+ ctrl->id, ctrl->value);
+ return -ERANGE;
+ }
+
+ return 0;
+}
+
+static inline int mfc_enc_h264_profile(struct s5p_mfc_ctx *ctx, int profile)
+{
+ int ret = 0;
+
+ switch (profile) {
+ case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
+ ret = S5P_FIMV_E_PROFILE_H264_MAIN;
+ break;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
+ ret = S5P_FIMV_E_PROFILE_H264_HIGH;
+ break;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
+ ret = S5P_FIMV_E_PROFILE_H264_BASELINE;
+ break;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
+ ret = S5P_FIMV_E_PROFILE_H264_CONSTRAINED_BASELINE;
+ break;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH:
+ ret = S5P_FIMV_E_PROFILE_H264_CONSTRAINED_HIGH;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+/* Query capabilities of the device */
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ strncpy(cap->driver, "MFC", sizeof(cap->driver) - 1);
+ strncpy(cap->card, "encoder", sizeof(cap->card) - 1);
+ cap->bus_info[0] = 0;
+ cap->version = KERNEL_VERSION(1, 0, 0);
+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE
+ | V4L2_CAP_VIDEO_OUTPUT
+ | V4L2_CAP_VIDEO_CAPTURE_MPLANE
+ | V4L2_CAP_VIDEO_OUTPUT_MPLANE
+ | V4L2_CAP_STREAMING
+ | V4L2_CAP_DEVICE_CAPS;
+
+ cap->capabilities = cap->device_caps;
+
+ return 0;
+}
+
+static int mfc_enc_enum_fmt(struct s5p_mfc_dev *dev, struct v4l2_fmtdesc *f,
+ unsigned int type)
+{
+ struct s5p_mfc_fmt *fmt;
+ unsigned long i, j = 0;
+
+ for (i = 0; i < NUM_FORMATS; ++i) {
+ if (!(enc_formats[i].type & type))
+ continue;
+ if (!dev->pdata->support_10bit && (enc_formats[i].type & MFC_FMT_10BIT))
+ continue;
+ if (!dev->pdata->support_422 && (enc_formats[i].type & MFC_FMT_422))
+ continue;
+ if (!dev->pdata->support_rgb && (enc_formats[i].type & MFC_FMT_RGB))
+ continue;
+
+ if (j == f->index) {
+ fmt = &enc_formats[i];
+ strlcpy(f->description, fmt->name,
+ sizeof(f->description));
+ f->pixelformat = fmt->fourcc;
+
+ return 0;
+ }
+
+ ++j;
+ }
+
+ return -EINVAL;
+}
+
+static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv,
+ struct v4l2_fmtdesc *f)
+{
+ struct s5p_mfc_dev *dev = video_drvdata(file);
+
+ return mfc_enc_enum_fmt(dev, f, MFC_FMT_STREAM);
+}
+
+static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *prov,
+ struct v4l2_fmtdesc *f)
+{
+ struct s5p_mfc_dev *dev = video_drvdata(file);
+
+ return mfc_enc_enum_fmt(dev, f, MFC_FMT_FRAME);
+}
+
+static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
+ struct s5p_mfc_raw_info *raw;
+ int i;
+
+ mfc_debug_enter();
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ mfc_debug(4, "enc dst g_fmt\n");
+ /* This is run on output (encoder dest) */
+ pix_fmt_mp->width = 0;
+ pix_fmt_mp->height = 0;
+ pix_fmt_mp->field = V4L2_FIELD_NONE;
+ pix_fmt_mp->pixelformat = ctx->dst_fmt->fourcc;
+ pix_fmt_mp->num_planes = ctx->dst_fmt->mem_planes;
+
+ pix_fmt_mp->plane_fmt[0].bytesperline = enc->dst_buf_size;
+ pix_fmt_mp->plane_fmt[0].sizeimage = enc->dst_buf_size;
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ mfc_debug(4, "enc src g_fmt\n");
+ /* This is run on capture (encoder src) */
+ raw = &ctx->raw_buf;
+
+ pix_fmt_mp->width = ctx->img_width;
+ pix_fmt_mp->height = ctx->img_height;
+ pix_fmt_mp->field = V4L2_FIELD_NONE;
+ pix_fmt_mp->pixelformat = ctx->src_fmt->fourcc;
+ pix_fmt_mp->num_planes = ctx->src_fmt->mem_planes;
+ for (i = 0; i < ctx->src_fmt->mem_planes; i++) {
+ pix_fmt_mp->plane_fmt[i].bytesperline = raw->stride[i];
+ pix_fmt_mp->plane_fmt[i].sizeimage = raw->plane_size[i];
+ }
+ } else {
+ mfc_err_dev("invalid buf type (%d)\n", f->type);
+ return -EINVAL;
+ }
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ struct s5p_mfc_fmt *fmt;
+ struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
+
+ fmt = mfc_enc_find_format(ctx, pix_fmt_mp->pixelformat);
+ if (!fmt) {
+ mfc_err_dev("Unsupported format for %s\n",
+ V4L2_TYPE_IS_OUTPUT(f->type) ? "source" : "destination");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void mfc_enc_check_format(struct s5p_mfc_ctx *ctx)
+{
+ switch (ctx->src_fmt->fourcc) {
+ case V4L2_PIX_FMT_NV16M_S10B:
+ case V4L2_PIX_FMT_NV61M_S10B:
+ case V4L2_PIX_FMT_NV16M_P210:
+ case V4L2_PIX_FMT_NV61M_P210:
+ mfc_debug(2, "[FRAME][10BIT] is 422 and 10bit format\n");
+ ctx->is_10bit = 1;
+ ctx->is_422 = 1;
+ break;
+ case V4L2_PIX_FMT_NV16M:
+ case V4L2_PIX_FMT_NV61M:
+ mfc_debug(2, "[FRAME] is 422 format\n");
+ ctx->is_10bit = 0;
+ ctx->is_422 = 1;
+ break;
+ case V4L2_PIX_FMT_NV12M_S10B:
+ case V4L2_PIX_FMT_NV12M_P010:
+ case V4L2_PIX_FMT_NV21M_S10B:
+ case V4L2_PIX_FMT_NV21M_P010:
+ mfc_debug(2, "[FRAME][10BIT] is 10bit format\n");
+ ctx->is_10bit = 1;
+ ctx->is_422 = 0;
+ break;
+ default:
+ ctx->is_10bit = 0;
+ ctx->is_422 = 0;
+ break;
+ }
+ mfc_debug(2, "[FRAME] 10bit: %d, 422: %d\n", ctx->is_10bit, ctx->is_422);
+}
+
+static int mfc_enc_check_resolution(struct s5p_mfc_ctx *ctx)
+{
+ int max_width = 0, max_height = 0, min_width = 0, min_height = 0, swap_check = 0;
+
+ /* Check max resolution */
+ switch (ctx->codec_mode) {
+ case S5P_FIMV_CODEC_HEVC_ENC:
+ if (ctx->is_422) {
+ max_width = 65536;
+ max_height = 8192;
+ swap_check = 1;
+ } else {
+ max_width = 8192;
+ max_height = 8192;
+ }
+ break;
+ case S5P_FIMV_CODEC_BPG_ENC:
+ max_width = 65536;
+ max_height = 8192;
+ swap_check = 1;
+ break;
+ case S5P_FIMV_CODEC_H264_ENC:
+ case S5P_FIMV_CODEC_VP8_ENC:
+ max_width = 8192;
+ max_height = 8192;
+ break;
+ case S5P_FIMV_CODEC_VP9_ENC:
+ max_width = 4096;
+ max_height = 8192;
+ break;
+ case S5P_FIMV_CODEC_MPEG4_ENC:
+ max_width = 2048;
+ max_height = 2048;
+ break;
+ case S5P_FIMV_CODEC_H263_ENC:
+ max_width = 2048;
+ max_height = 1152;
+ break;
+ default:
+ mfc_err_ctx("Not supported codec(%d)\n", ctx->codec_mode);
+ return -EINVAL;
+ }
+
+ if (swap_check) {
+ if (!((ctx->crop_width < max_width && ctx->crop_height < max_height) ||
+ (ctx->crop_width < max_height && ctx->crop_height < max_width))) {
+ mfc_err_ctx("Resolution is too big(%dx%d > %dxi%d or %dx%d\n",
+ ctx->crop_width, ctx->crop_height, max_width, max_height,
+ max_height, max_width);
+ return -EINVAL;
+ }
+ } else {
+ if (ctx->crop_width > max_width || ctx->crop_height > max_height) {
+ mfc_err_ctx("Resolution is too big(%dx%d > %dx%d)\n",
+ ctx->crop_width, ctx->crop_height, max_width, max_height);
+ return -EINVAL;
+ }
+ }
+
+ /* Check min resolution */
+ switch (ctx->codec_mode) {
+ case S5P_FIMV_CODEC_HEVC_ENC:
+ case S5P_FIMV_CODEC_BPG_ENC:
+ case S5P_FIMV_CODEC_VP9_ENC:
+ min_width = 64;
+ min_height = 64;
+ break;
+ case S5P_FIMV_CODEC_H264_ENC:
+ case S5P_FIMV_CODEC_VP8_ENC:
+ case S5P_FIMV_CODEC_MPEG4_ENC:
+ case S5P_FIMV_CODEC_H263_ENC:
+ min_width = 32;
+ min_height = 32;
+ break;
+ default:
+ mfc_err_ctx("Not supported codec(%d)\n", ctx->codec_mode);
+ return -EINVAL;
+ }
+
+ if (ctx->crop_width < min_width || ctx->crop_height < min_height) {
+ mfc_err_ctx("Resolution is too small(%dx%d < %dx%d)\n",
+ ctx->crop_width, ctx->crop_height, min_width, min_height);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vidioc_s_fmt_vid_cap_mplane(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct s5p_mfc_dev *dev = video_drvdata(file);
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
+ int ret = 0;
+
+ mfc_debug_enter();
+
+ if (ctx->vq_dst.streaming) {
+ mfc_err_ctx("dst queue busy\n");
+ return -EBUSY;
+ }
+
+ ctx->dst_fmt = mfc_enc_find_format(ctx, pix_fmt_mp->pixelformat);
+ if (!ctx->dst_fmt) {
+ mfc_err_ctx("Unsupported format for destination\n");
+ return -EINVAL;
+ }
+
+ ctx->codec_mode = ctx->dst_fmt->codec_mode;
+ mfc_info_ctx("[STREAM] Enc dst codec(%d) : %s\n",
+ ctx->codec_mode, ctx->dst_fmt->name);
+
+ if (mfc_enc_check_resolution(ctx)) {
+ mfc_err_ctx("Unsupported resolution\n");
+ return -EINVAL;
+ }
+
+ if (ctx->otf_handle) {
+ if (ctx->dst_fmt->fourcc != V4L2_PIX_FMT_H264 &&
+ ctx->dst_fmt->fourcc != V4L2_PIX_FMT_HEVC) {
+ mfc_err_ctx("[OTF] only H.264 and HEVC is supported\n");
+ return -EINVAL;
+ }
+ if (s5p_mfc_otf_init(ctx)) {
+ mfc_err_ctx("[OTF] otf_init failed\n");
+ s5p_mfc_otf_destroy(ctx);
+ return -EINVAL;
+ }
+ }
+
+ enc->dst_buf_size = pix_fmt_mp->plane_fmt[0].sizeimage;
+ pix_fmt_mp->plane_fmt[0].bytesperline = 0;
+
+ ret = s5p_mfc_alloc_instance_context(ctx);
+ if (ret) {
+ mfc_err_ctx("Failed to allocate enc instance[%d] buffers\n",
+ ctx->num);
+ return -ENOMEM;
+ }
+
+ s5p_mfc_change_state(ctx, MFCINST_INIT);
+
+ ctx->capture_state = QUEUE_FREE;
+
+ ret = s5p_mfc_alloc_enc_roi_buffer(ctx);
+ if (ret) {
+ mfc_err_ctx("[ROI] Failed to allocate ROI buffers\n");
+ s5p_mfc_release_instance_context(ctx);
+ return -ENOMEM;
+ }
+
+ MFC_TRACE_CTX_HWLOCK("**ENC s_fmt\n");
+
+ ret = s5p_mfc_get_hwlock_ctx(ctx);
+ if (ret < 0) {
+ mfc_err_dev("Failed to get hwlock\n");
+ s5p_mfc_release_instance_context(ctx);
+ s5p_mfc_release_enc_roi_buffer(ctx);
+ return -EBUSY;
+ }
+
+ s5p_mfc_set_bit(ctx->num, &dev->work_bits);
+ ret = s5p_mfc_just_run(dev, ctx->num);
+ if (ret) {
+ mfc_err_ctx("Failed to run MFC\n");
+ s5p_mfc_release_hwlock_ctx(ctx);
+ s5p_mfc_cleanup_work_bit_and_try_run(ctx);
+ s5p_mfc_release_instance_context(ctx);
+ s5p_mfc_release_enc_roi_buffer(ctx);
+ return -EIO;
+ }
+
+ if (s5p_mfc_wait_for_done_ctx(ctx,
+ S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET)) {
+ mfc_err_ctx("time out during open instance\n");
+ s5p_mfc_release_hwlock_ctx(ctx);
+ s5p_mfc_cleanup_work_bit_and_try_run(ctx);
+ s5p_mfc_release_instance_context(ctx);
+ s5p_mfc_release_enc_roi_buffer(ctx);
+ return -EIO;
+ }
+ s5p_mfc_release_hwlock_ctx(ctx);
+
+ mfc_debug(2, "Got instance number: %d\n", ctx->inst_no);
+
+ if (s5p_mfc_enc_ctx_ready(ctx))
+ s5p_mfc_set_bit(ctx->num, &dev->work_bits);
+ if (ctx->otf_handle && s5p_mfc_otf_ctx_ready(ctx))
+ s5p_mfc_set_bit(ctx->num, &dev->work_bits);
+ if (s5p_mfc_is_work_to_do(dev))
+ queue_work(dev->butler_wq, &dev->butler_work);
+
+ mfc_debug_leave();
+ return 0;
+}
+
+static int vidioc_s_fmt_vid_out_mplane(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
+
+ mfc_debug_enter();
+
+ if (ctx->vq_src.streaming) {
+ mfc_err_ctx("src queue busy\n");
+ return -EBUSY;
+ }
+
+ if (ctx->otf_handle) {
+ mfc_info_ctx("[OTF] skip source s_fmt\n");
+ return 0;
+ }
+
+ ctx->src_fmt = mfc_enc_find_format(ctx, pix_fmt_mp->pixelformat);
+ if (!ctx->src_fmt) {
+ mfc_err_ctx("Unsupported format for source\n");
+ return -EINVAL;
+ }
+
+ if (ctx->src_fmt->mem_planes != pix_fmt_mp->num_planes) {
+ mfc_err_ctx("[FRAME] enc src plane number is different (%d != %d)\n",
+ ctx->src_fmt->mem_planes, pix_fmt_mp->num_planes);
+ return -EINVAL;
+ }
+
+ ctx->raw_buf.num_planes = ctx->src_fmt->num_planes;
+ ctx->img_width = pix_fmt_mp->width;
+ ctx->img_height = pix_fmt_mp->height;
+ ctx->buf_stride = pix_fmt_mp->plane_fmt[0].bytesperline;
+
+ mfc_enc_check_format(ctx);
+
+ if (ctx->state == MFCINST_RUNNING) {
+ s5p_mfc_change_state(ctx, MFCINST_GOT_INST);
+ mfc_info_ctx("[DRC] Enc resolution is changed\n");
+ }
+
+ mfc_info_ctx("[FRAME] enc src pixelformat : %s\n", ctx->src_fmt->name);
+ mfc_info_ctx("[FRAME] resolution w: %d, h: %d, stride: %d\n",
+ pix_fmt_mp->width, pix_fmt_mp->height, ctx->buf_stride);
+
+ /*
+ * It should be keep till buffer size and stride was calculated.
+ * And it can be changed to real encoding size, if user call the s_crop.
+ */
+ ctx->crop_width = ctx->img_width;
+ ctx->crop_height = ctx->img_height;
+ s5p_mfc_enc_calc_src_size(ctx);
+
+ ctx->output_state = QUEUE_FREE;
+
+ mfc_debug_leave();
+ return 0;
+}
+
+static int vidioc_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+
+ mfc_debug_enter();
+
+ cr->c.left = ctx->crop_left;
+ cr->c.top = ctx->crop_top;
+ cr->c.width = ctx->crop_width;
+ cr->c.height = ctx->crop_height;
+
+ mfc_debug(2, "[FRAME] enc crop w: %d, h: %d, offset l: %d t: %d\n",
+ ctx->crop_width, ctx->crop_height, ctx->crop_left, ctx->crop_top);
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+static int vidioc_s_crop(struct file *file, void *priv, const struct v4l2_crop *cr)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+
+ mfc_debug_enter();
+
+ if (cr->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ mfc_err_ctx("not supported type (It can only in the source)\n");
+ return -EINVAL;
+ }
+
+ if (cr->c.left < 0 || cr->c.top < 0) {
+ mfc_err_ctx("[FRAME] crop position is negative\n");
+ return -EINVAL;
+ }
+
+ if ((cr->c.height > ctx->img_height) || (cr->c.top > ctx->img_height) ||
+ (cr->c.width > ctx->img_width) || (cr->c.left > ctx->img_width) ||
+ (cr->c.left <= (ctx->img_width - cr->c.width)) ||
+ (cr->c.top <= (ctx->img_height - cr->c.height))) {
+ mfc_err_ctx("[FRAME] Out of crop range: (%d,%d,%d,%d) from %dx%d\n",
+ cr->c.left, cr->c.top, cr->c.width, cr->c.height,
+ ctx->img_width, ctx->img_height);
+ return -EINVAL;
+ }
+
+ ctx->crop_top = cr->c.top;
+ ctx->crop_left = cr->c.left;
+ ctx->crop_height = cr->c.height;
+ ctx->crop_width = cr->c.width;
+
+ mfc_debug(3, "[FRAME] enc original: %dx%d, crop: %dx%d, offset l: %d t: %d\n",
+ ctx->img_width, ctx->img_height,
+ ctx->crop_width, ctx->crop_height,
+ ctx->crop_left, ctx->crop_top);
+
+ return 0;
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *reqbufs)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ int ret = 0;
+
+ mfc_debug_enter();
+
+ if (reqbufs->memory == V4L2_MEMORY_MMAP) {
+ mfc_err_ctx("Not supported memory type (%d)\n", reqbufs->memory);
+ return -EINVAL;
+ }
+
+ if (ctx->otf_handle) {
+ mfc_info_ctx("[OTF] skip reqbufs\n");
+ return 0;
+ }
+
+ if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ mfc_debug(4, "enc dst reqbuf(%d)\n", reqbufs->count);
+ if (reqbufs->count == 0) {
+ ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+ ctx->capture_state = QUEUE_FREE;
+ return ret;
+ }
+
+ if (ctx->capture_state != QUEUE_FREE) {
+ mfc_err_ctx("invalid capture state: %d\n", ctx->capture_state);
+ return -EINVAL;
+ }
+
+ ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+ if (ret) {
+ mfc_err_ctx("error in vb2_reqbufs() for E(D)\n");
+ return ret;
+ }
+
+ ctx->capture_state = QUEUE_BUFS_REQUESTED;
+ } else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ mfc_debug(4, "enc src reqbuf(%d)\n", reqbufs->count);
+ if (reqbufs->count == 0) {
+ ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
+ ctx->output_state = QUEUE_FREE;
+ return ret;
+ }
+
+ if (ctx->output_state != QUEUE_FREE) {
+ mfc_err_ctx("invalid output state: %d\n", ctx->output_state);
+ return -EINVAL;
+ }
+
+ ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
+ if (ret) {
+ mfc_err_ctx("error in vb2_reqbufs() for E(S)\n");
+ return ret;
+ }
+
+ ctx->output_state = QUEUE_BUFS_REQUESTED;
+ } else {
+ mfc_err_ctx("invalid buf type (%d)\n", reqbufs->type);
+ return -EINVAL;
+ }
+
+ mfc_debug_leave();
+
+ return ret;
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ int ret = 0;
+
+ mfc_debug_enter();
+
+ if (ctx->otf_handle) {
+ mfc_info_ctx("[OTF] skip source querybuf\n");
+ return 0;
+ }
+
+ if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ mfc_debug(4, "enc dst querybuf, state: %d\n", ctx->state);
+ ret = vb2_querybuf(&ctx->vq_dst, buf);
+ if (ret != 0) {
+ mfc_err_dev("enc dst: error in vb2_querybuf()\n");
+ return ret;
+ }
+ } else if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ mfc_debug(4, "enc src querybuf, state: %d\n", ctx->state);
+ ret = vb2_querybuf(&ctx->vq_src, buf);
+ if (ret != 0) {
+ mfc_err_dev("enc src: error in vb2_querybuf()\n");
+ return ret;
+ }
+ } else {
+ mfc_err_dev("invalid buf type (%d)\n", buf->type);
+ return -EINVAL;
+ }
+
+ mfc_debug_leave();
+
+ return ret;
+}
+
+/* Queue a buffer */
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ int i, ret = -EINVAL;
+
+ mfc_debug_enter();
+
+ if (ctx->otf_handle) {
+ mfc_info_ctx("[OTF] skip qbuf\n");
+ return 0;
+ }
+
+ if (ctx->state == MFCINST_ERROR) {
+ mfc_err_ctx("Call on QBUF after unrecoverable error\n");
+ return -EIO;
+ }
+
+ if (V4L2_TYPE_IS_MULTIPLANAR(buf->type) && !buf->length) {
+ mfc_err_ctx("multiplanar but length is zero\n");
+ return -EIO;
+ }
+
+ if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ mfc_debug(4, "enc src buf[%d] Q\n", buf->index);
+ for (i = 0; i < ctx->src_fmt->num_planes; i++) {
+ if (!buf->m.planes[i].bytesused) {
+ mfc_debug(2, "[FRAME] enc src[%d] size zero, "
+ "changed to buf size %d\n",
+ i, buf->m.planes[i].length);
+ buf->m.planes[i].bytesused = buf->m.planes[i].length;
+ } else {
+ mfc_debug(2, "[FRAME] enc src[%d] size %d\n",
+ i, buf->m.planes[i].bytesused);
+ }
+ }
+ ret = vb2_qbuf(&ctx->vq_src, buf);
+ } else {
+ mfc_debug(4, "enc dst buf[%d] Q\n", buf->index);
+ ret = vb2_qbuf(&ctx->vq_dst, buf);
+ }
+
+ mfc_debug_leave();
+ return ret;
+}
+
+/* Dequeue a buffer */
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ int ret;
+
+ mfc_debug_enter();
+
+ if (ctx->otf_handle) {
+ mfc_info_ctx("[OTF] skip dqbuf\n");
+ return 0;
+ }
+
+ if (ctx->state == MFCINST_ERROR) {
+ mfc_err_ctx("Call on DQBUF after unrecoverable error\n");
+ return -EIO;
+ }
+ if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ mfc_debug(4, "enc src buf[%d] DQ\n", buf->index);
+ ret = vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK);
+ } else {
+ mfc_debug(4, "enc dst buf[%d] DQ\n", buf->index);
+ ret = vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK);
+ }
+ mfc_debug_leave();
+ return ret;
+}
+
+/* Stream on */
+static int vidioc_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ int ret = -EINVAL;
+
+ mfc_debug_enter();
+
+ if (ctx->otf_handle) {
+ mfc_info_ctx("[OTF] skip streamon\n");
+ return 0;
+ }
+
+ if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ mfc_debug(4, "enc src streamon\n");
+ ret = vb2_streamon(&ctx->vq_src, type);
+
+ if (!ret) {
+ s5p_mfc_qos_on(ctx);
+ }
+ } else {
+ mfc_debug(4, "enc dst streamon\n");
+ ret = vb2_streamon(&ctx->vq_dst, type);
+ }
+
+ mfc_debug(2, "src: %d, dst: %d, state = %d, dpb_count = %d\n",
+ s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->src_buf_queue),
+ s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->dst_buf_queue),
+ ctx->state, ctx->dpb_count);
+ mfc_debug_leave();
+ return ret;
+}
+
+/* Stream off, which equals to a pause */
+static int vidioc_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ int ret;
+
+ mfc_debug_enter();
+
+ if (ctx->otf_handle) {
+ mfc_info_ctx("[OTF] skip streamoff\n");
+ return 0;
+ }
+
+ ret = -EINVAL;
+ if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ mfc_debug(4, "enc src streamoff\n");
+ s5p_mfc_qos_reset_last_framerate(ctx);
+
+ ret = vb2_streamoff(&ctx->vq_src, type);
+ if (!ret)
+ s5p_mfc_qos_off(ctx);
+ } else {
+ mfc_debug(4, "enc dst streamoff\n");
+ ret = vb2_streamoff(&ctx->vq_dst, type);
+ }
+
+ mfc_debug_leave();
+
+ return ret;
+}
+
+/* Query a ctrl */
+static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ struct v4l2_queryctrl *c;
+
+ c = mfc_enc_get_ctrl(qc->id);
+ if (!c) {
+ mfc_err_dev("[CTRLS] not supported control id (%#x)\n", qc->id);
+ return -EINVAL;
+ }
+
+ *qc = *c;
+ return 0;
+}
+
+static int mfc_enc_ext_info(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ int val = 0;
+
+ val |= ENC_SET_SPARE_SIZE;
+ val |= ENC_SET_TEMP_SVC_CH;
+
+ if (MFC_FEATURE_SUPPORT(dev, dev->pdata->skype))
+ val |= ENC_SET_SKYPE_FLAG;
+
+ val |= ENC_SET_ROI_CONTROL;
+ val |= ENC_SET_QP_BOUND_PB;
+ val |= ENC_SET_FIXED_SLICE;
+ val |= ENC_SET_PVC_MODE;
+ val |= ENC_SET_RATIO_OF_INTRA;
+
+ if (MFC_FEATURE_SUPPORT(dev, dev->pdata->color_aspect_enc))
+ val |= ENC_SET_COLOR_ASPECT;
+
+ val |= ENC_SET_HP_BITRATE_CONTROL;
+
+ if (MFC_FEATURE_SUPPORT(dev, dev->pdata->static_info_enc))
+ val |= ENC_SET_STATIC_INFO;
+
+ mfc_debug(5, "[CTRLS] ext info val: %#x\n", val);
+
+ return val;
+}
+
+static int mfc_enc_get_ctrl_val(struct s5p_mfc_ctx *ctx, struct v4l2_control *ctrl)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_ctx_ctrl *ctx_ctrl;
+ int ret = 0;
+ int found = 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_CACHEABLE:
+ mfc_debug(5, "it is supported only V4L2_MEMORY_MMAP\n");
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_STREAM_SIZE:
+ ctrl->value = enc->dst_buf_size;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TYPE:
+ ctrl->value = enc->frame_type;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_CHECK_STATE:
+ ctrl->value = MFCSTATE_PROCESSING;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG:
+ case V4L2_CID_MPEG_MFC51_VIDEO_LUMA_ADDR:
+ case V4L2_CID_MPEG_MFC51_VIDEO_CHROMA_ADDR:
+ case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_STATUS:
+ list_for_each_entry(ctx_ctrl, &ctx->ctrls, list) {
+ if (!(ctx_ctrl->type & MFC_CTRL_TYPE_GET))
+ continue;
+
+ if (ctx_ctrl->id == ctrl->id) {
+ if (ctx_ctrl->has_new) {
+ ctx_ctrl->has_new = 0;
+ ctrl->value = ctx_ctrl->val;
+ } else {
+ mfc_debug(5, "[CTRLS] Control value "\
+ "is not up to date: "\
+ "0x%08x\n", ctrl->id);
+ return -EINVAL;
+ }
+
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ mfc_err_ctx("Invalid control: 0x%08x\n", ctrl->id);
+ return -EINVAL;
+ }
+ break;
+ case V4L2_CID_MPEG_MFC_GET_VERSION_INFO:
+ ctrl->value = dev->pdata->ip_ver;
+ break;
+ case V4L2_CID_MPEG_MFC_GET_DRIVER_INFO:
+ ctrl->value = MFC_DRIVER_INFO;
+ break;
+ case V4L2_CID_MPEG_MFC_GET_EXTRA_BUFFER_SIZE:
+ ctrl->value = MFC_LINEAR_BUF_SIZE;
+ break;
+ case V4L2_CID_MPEG_VIDEO_QOS_RATIO:
+ ctrl->value = ctx->qos_ratio;
+ break;
+ case V4L2_CID_MPEG_MFC_GET_EXT_INFO:
+ ctrl->value = mfc_enc_ext_info(ctx);
+ break;
+ case V4L2_CID_MPEG_VIDEO_BPG_HEADER_SIZE:
+ ctrl->value = enc->header_size;
+ break;
+ default:
+ mfc_err_ctx("Invalid control: 0x%08x\n", ctrl->id);
+ ret = -EINVAL;
+ break;
+ }
+
+ mfc_debug(5, "[CTRLS] get id: %#x, value: %d\n", ctrl->id, ctrl->value);
+
+ return ret;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ int ret = 0;
+
+ mfc_debug_enter();
+ ret = mfc_enc_get_ctrl_val(ctx, ctrl);
+ mfc_debug_leave();
+
+ return ret;
+}
+
+static inline int mfc_enc_h264_level(enum v4l2_mpeg_video_h264_level lvl)
+{
+ static unsigned int t[V4L2_MPEG_VIDEO_H264_LEVEL_5_1 + 1] = {
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_1_0 */ 10,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_1B */ 9,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_1_1 */ 11,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_1_2 */ 12,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_1_3 */ 13,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_2_0 */ 20,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_2_1 */ 21,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_2_2 */ 22,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_3_0 */ 30,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_3_1 */ 31,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_3_2 */ 32,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_4_0 */ 40,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_4_1 */ 41,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_4_2 */ 42,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_5_0 */ 50,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_5_1 */ 51,
+ };
+ return t[lvl];
+}
+
+static inline int mfc_enc_mpeg4_level(enum v4l2_mpeg_video_mpeg4_level lvl)
+{
+ static unsigned int t[V4L2_MPEG_VIDEO_MPEG4_LEVEL_6 + 1] = {
+ /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_0 */ 0,
+ /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B, Simple */ 9,
+ /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_1 */ 1,
+ /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_2 */ 2,
+ /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_3 */ 3,
+ /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_3B, Advanced */ 7,
+ /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_4 */ 4,
+ /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_5 */ 5,
+ /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_6, Simple */ 6,
+ };
+ return t[lvl];
+}
+
+static inline int mfc_enc_vui_sar_idc(enum v4l2_mpeg_video_h264_vui_sar_idc sar)
+{
+ static unsigned int t[V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED + 1] = {
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED */ 0,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_1x1 */ 1,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_12x11 */ 2,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_10x11 */ 3,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_16x11 */ 4,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_40x33 */ 5,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_24x11 */ 6,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_20x11 */ 7,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_32x11 */ 8,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_80x33 */ 9,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_18x11 */ 10,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_15x11 */ 11,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_64x33 */ 12,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_160x99 */ 13,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_4x3 */ 14,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_3x2 */ 15,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_2x1 */ 16,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED */ 255,
+ };
+ return t[sar];
+}
+
+static int mfc_enc_set_param(struct s5p_mfc_ctx *ctx, struct v4l2_control *ctrl)
+{
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_enc_params *p = &enc->params;
+ int ret = 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+ p->gop_size = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
+ p->slice_mode =
+ (enum v4l2_mpeg_video_multi_slice_mode)ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
+ p->slice_mb = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
+ p->slice_bit = ctrl->value * 8;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB_ROW:
+ p->slice_mb_row = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB:
+ p->intra_refresh_mb = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_PADDING:
+ p->pad = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV:
+ p->pad_luma = (ctrl->value >> 16) & 0xff;
+ p->pad_cb = (ctrl->value >> 8) & 0xff;
+ p->pad_cr = (ctrl->value >> 0) & 0xff;
+ break;
+ case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE:
+ p->rc_frame = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ p->rc_bitrate = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF:
+ p->rc_reaction_coeff = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE:
+ enc->force_frame_type = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_VBV_SIZE:
+ p->vbv_buf_size = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
+ p->seq_hdr_mode =
+ (enum v4l2_mpeg_video_header_mode)(ctrl->value);
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE:
+ p->frame_skip_mode =
+ (enum v4l2_mpeg_mfc51_video_frame_skip_mode)
+ (ctrl->value);
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT:
+ p->fixed_target_bit = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+ p->num_b_frame = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+ p->codec.h264.profile =
+ mfc_enc_h264_profile(ctx, (enum v4l2_mpeg_video_h264_profile)(ctrl->value));
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+ p->codec.h264.level =
+ mfc_enc_h264_level((enum v4l2_mpeg_video_h264_level)(ctrl->value));
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_H264_INTERLACE:
+ p->codec.h264.interlace = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
+ p->codec.h264.loop_filter_mode =
+ (enum v4l2_mpeg_video_h264_loop_filter_mode)(ctrl->value);
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:
+ p->codec.h264.loop_filter_alpha = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:
+ p->codec.h264.loop_filter_beta = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
+ p->codec.h264.entropy_mode =
+ (enum v4l2_mpeg_video_h264_entropy_mode)(ctrl->value);
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P:
+ p->num_refs_for_p = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM:
+ p->codec.h264._8x8_transform = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE:
+ p->rc_mb = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_H264_RC_FRAME_RATE:
+ p->rc_framerate = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
+ p->codec.h264.rc_frame_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
+ p->codec.h264.rc_min_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
+ p->codec.h264.rc_max_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_MIN_QP_P:
+ p->codec.h264.rc_min_qp_p = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_MAX_QP_P:
+ p->codec.h264.rc_max_qp_p = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_MIN_QP_B:
+ p->codec.h264.rc_min_qp_b = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_MAX_QP_B:
+ p->codec.h264.rc_max_qp_b = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK:
+ p->codec.h264.rc_mb_dark = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH:
+ p->codec.h264.rc_mb_smooth = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC:
+ p->codec.h264.rc_mb_static = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY:
+ p->codec.h264.rc_mb_activity = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
+ p->codec.h264.rc_p_frame_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:
+ p->codec.h264.rc_b_frame_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE:
+ p->codec.h264.ar_vui = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC:
+ p->codec.h264.ar_vui_idc =
+ mfc_enc_vui_sar_idc((enum v4l2_mpeg_video_h264_vui_sar_idc)(ctrl->value));
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH:
+ p->codec.h264.ext_sar_width = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT:
+ p->codec.h264.ext_sar_height = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+ p->codec.h264.open_gop = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD:
+ p->codec.h264.open_gop_size = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING:
+ p->codec.h264.hier_qp_enable = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE:
+ p->codec.h264.hier_qp_type =
+ (enum v4l2_mpeg_video_h264_hierarchical_coding_type)(ctrl->value);
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER:
+ p->codec.h264.num_hier_layer = ctrl->value & 0x7;
+ p->codec.h264.hier_ref_type = (ctrl->value >> 16) & 0x1;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_QP:
+ p->codec.h264.hier_qp_layer[(ctrl->value >> 16) & 0x7]
+ = ctrl->value & 0xFF;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_BIT0:
+ p->codec.h264.hier_bit_layer[0] = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_BIT1:
+ p->codec.h264.hier_bit_layer[1] = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_BIT2:
+ p->codec.h264.hier_bit_layer[2] = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_BIT3:
+ p->codec.h264.hier_bit_layer[3] = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_BIT4:
+ p->codec.h264.hier_bit_layer[4] = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_BIT5:
+ p->codec.h264.hier_bit_layer[5] = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_BIT6:
+ p->codec.h264.hier_bit_layer[6] = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING:
+ p->codec.h264.sei_gen_enable = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_CURRENT_FRAME_0:
+ p->codec.h264.sei_fp_curr_frame_0 = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE:
+ p->codec.h264.sei_fp_arrangement_type = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_FMO:
+ p->codec.h264.fmo_enable = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE:
+ switch ((enum v4l2_mpeg_video_h264_fmo_map_type)(ctrl->value)) {
+ case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_INTERLEAVED_SLICES:
+ case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_SCATTERED_SLICES:
+ case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_RASTER_SCAN:
+ case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_WIPE_SCAN:
+ p->codec.h264.fmo_slice_map_type = ctrl->value;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_FMO_SLICE_GROUP:
+ p->codec.h264.fmo_slice_num_grp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_FMO_RUN_LENGTH:
+ p->codec.h264.fmo_run_length[(ctrl->value >> 30) & 0x3]
+ = ctrl->value & 0x3FFFFFFF;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_DIRECTION:
+ p->codec.h264.fmo_sg_dir = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_RATE:
+ p->codec.h264.fmo_sg_rate = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_ASO:
+ p->codec.h264.aso_enable = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_ASO_SLICE_ORDER:
+ p->codec.h264.aso_slice_order[(ctrl->value >> 18) & 0x7]
+ &= ~(0xFF << (((ctrl->value >> 16) & 0x3) << 3));
+ p->codec.h264.aso_slice_order[(ctrl->value >> 18) & 0x7]
+ |= (ctrl->value & 0xFF) << \
+ (((ctrl->value >> 16) & 0x3) << 3);
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_PREPEND_SPSPPS_TO_IDR:
+ p->codec.h264.prepend_sps_pps_to_idr = ctrl->value ? 1 : 0;
+ break;
+ case V4L2_CID_MPEG_MFC_H264_ENABLE_LTR:
+ p->codec.h264.enable_ltr = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC_H264_NUM_OF_LTR:
+ p->codec.h264.num_of_ltr = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC_H264_BASE_PRIORITY:
+ p->codec.h264.base_priority = ctrl->value;
+ p->codec.h264.set_priority = 1;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
+ switch ((enum v4l2_mpeg_video_mpeg4_profile)(ctrl->value)) {
+ case V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE:
+ p->codec.mpeg4.profile =
+ S5P_FIMV_E_PROFILE_MPEG4_SIMPLE;
+ break;
+ case V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE:
+ p->codec.mpeg4.profile =
+ S5P_FIMV_E_PROFILE_MPEG4_ADVANCED_SIMPLE;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ break;
+ case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
+ p->codec.mpeg4.level =
+ mfc_enc_mpeg4_level((enum v4l2_mpeg_video_mpeg4_level)(ctrl->value));
+ break;
+ case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP:
+ p->codec.mpeg4.rc_frame_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP:
+ p->codec.mpeg4.rc_min_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP:
+ p->codec.mpeg4.rc_max_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP_P:
+ p->codec.mpeg4.rc_min_qp_p = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP_P:
+ p->codec.mpeg4.rc_max_qp_p = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP_B:
+ p->codec.mpeg4.rc_min_qp_b = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP_B:
+ p->codec.mpeg4.rc_max_qp_b = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL:
+ p->codec.mpeg4.quarter_pixel = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP:
+ p->codec.mpeg4.rc_p_frame_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP:
+ p->codec.mpeg4.rc_b_frame_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_MPEG4_VOP_TIME_RES:
+ p->codec.mpeg4.vop_time_res = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_MPEG4_VOP_FRM_DELTA:
+ p->codec.mpeg4.vop_frm_delta = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_H263_RC_FRAME_RATE:
+ p->rc_framerate = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP:
+ p->codec.mpeg4.rc_frame_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H263_MIN_QP:
+ p->codec.mpeg4.rc_min_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H263_MAX_QP:
+ p->codec.mpeg4.rc_max_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H263_MIN_QP_P:
+ p->codec.mpeg4.rc_min_qp_p = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H263_MAX_QP_P:
+ p->codec.mpeg4.rc_max_qp_p = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP:
+ p->codec.mpeg4.rc_p_frame_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC70_VIDEO_VP8_VERSION:
+ p->codec.vp8.vp8_version = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC70_VIDEO_VP8_RC_FRAME_RATE:
+ p->rc_framerate = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_VP8_MIN_QP:
+ p->codec.vp8.rc_min_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_VP8_MAX_QP:
+ p->codec.vp8.rc_max_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_VP8_MIN_QP_P:
+ p->codec.vp8.rc_min_qp_p = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_VP8_MAX_QP_P:
+ p->codec.vp8.rc_max_qp_p = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_VP8_I_FRAME_QP:
+ p->codec.vp8.rc_frame_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_VP8_P_FRAME_QP:
+ p->codec.vp8.rc_p_frame_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC70_VIDEO_VP8_NUM_OF_PARTITIONS:
+ p->codec.vp8.vp8_numberofpartitions = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC70_VIDEO_VP8_FILTER_LEVEL:
+ p->codec.vp8.vp8_filterlevel = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC70_VIDEO_VP8_FILTER_SHARPNESS:
+ p->codec.vp8.vp8_filtersharpness = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC70_VIDEO_VP8_GOLDEN_FRAMESEL:
+ p->codec.vp8.vp8_goldenframesel = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC70_VIDEO_VP8_GF_REFRESH_PERIOD:
+ p->codec.vp8.vp8_gfrefreshperiod = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC70_VIDEO_VP8_HIERARCHY_QP_ENABLE:
+ p->codec.vp8.hier_qp_enable = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC70_VIDEO_VP8_HIERARCHY_QP_LAYER0:
+ p->codec.vp8.hier_qp_layer[(ctrl->value >> 16) & 0x3]
+ = ctrl->value & 0xFF;
+ break;
+ case V4L2_CID_MPEG_MFC70_VIDEO_VP8_HIERARCHY_QP_LAYER1:
+ p->codec.vp8.hier_qp_layer[(ctrl->value >> 16) & 0x3]
+ = ctrl->value & 0xFF;
+ break;
+ case V4L2_CID_MPEG_MFC70_VIDEO_VP8_HIERARCHY_QP_LAYER2:
+ p->codec.vp8.hier_qp_layer[(ctrl->value >> 16) & 0x3]
+ = ctrl->value & 0xFF;
+ break;
+ case V4L2_CID_MPEG_VIDEO_VP8_HIERARCHICAL_CODING_LAYER_BIT0:
+ p->codec.vp8.hier_bit_layer[0] = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_VP8_HIERARCHICAL_CODING_LAYER_BIT1:
+ p->codec.vp8.hier_bit_layer[1] = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_VP8_HIERARCHICAL_CODING_LAYER_BIT2:
+ p->codec.vp8.hier_bit_layer[2] = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC70_VIDEO_VP8_REF_NUMBER_FOR_PFRAMES:
+ p->num_refs_for_p = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC70_VIDEO_VP8_DISABLE_INTRA_MD4X4:
+ p->codec.vp8.intra_4x4mode_disable = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC70_VIDEO_VP8_NUM_TEMPORAL_LAYER:
+ p->codec.vp8.num_hier_layer = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_VP9_VERSION:
+ p->codec.vp9.vp9_version = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_VP9_RC_FRAME_RATE:
+ p->rc_framerate = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_VP9_MIN_QP:
+ p->codec.vp9.rc_min_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_VP9_MAX_QP:
+ p->codec.vp9.rc_max_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_VP9_MIN_QP_P:
+ p->codec.vp9.rc_min_qp_p = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_VP9_MAX_QP_P:
+ p->codec.vp9.rc_max_qp_p = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_VP9_I_FRAME_QP:
+ p->codec.vp9.rc_frame_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_VP9_P_FRAME_QP:
+ p->codec.vp9.rc_p_frame_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_VP9_GOLDEN_FRAMESEL:
+ p->codec.vp9.vp9_goldenframesel = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_VP9_GF_REFRESH_PERIOD:
+ p->codec.vp9.vp9_gfrefreshperiod = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_VP9_HIERARCHY_QP_ENABLE:
+ p->codec.vp9.hier_qp_enable = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER_QP:
+ p->codec.vp9.hier_qp_layer[(ctrl->value >> 16) & 0x3]
+ = ctrl->value & 0xFF;
+ break;
+ case V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER_BIT0:
+ p->codec.vp9.hier_bit_layer[0] = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER_BIT1:
+ p->codec.vp9.hier_bit_layer[1] = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER_BIT2:
+ p->codec.vp9.hier_bit_layer[2] = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_VP9_REF_NUMBER_FOR_PFRAMES:
+ p->num_refs_for_p = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER:
+ p->codec.vp9.num_hier_layer = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_VP9_MAX_PARTITION_DEPTH:
+ p->codec.vp9.max_partition_depth = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_VP9_DISABLE_INTRA_PU_SPLIT:
+ p->codec.vp9.intra_pu_split_disable = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_DISABLE_IVF_HEADER:
+ p->ivf_header_disable = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_VP9_PROFILE:
+ p->codec.vp9.profile = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP:
+ p->codec.hevc.rc_frame_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP:
+ p->codec.hevc.rc_p_frame_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP:
+ p->codec.hevc.rc_b_frame_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_RC_FRAME_RATE:
+ p->rc_framerate = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP:
+ p->codec.hevc.rc_min_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP:
+ p->codec.hevc.rc_max_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP_P:
+ p->codec.hevc.rc_min_qp_p = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP_P:
+ p->codec.hevc.rc_max_qp_p = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP_B:
+ p->codec.hevc.rc_min_qp_b = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP_B:
+ p->codec.hevc.rc_max_qp_b = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL:
+ p->codec.hevc.level = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE:
+ p->codec.hevc.profile = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_ADAPTIVE_RC_DARK:
+ p->codec.hevc.rc_lcu_dark = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_ADAPTIVE_RC_SMOOTH:
+ p->codec.hevc.rc_lcu_smooth = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_ADAPTIVE_RC_STATIC:
+ p->codec.hevc.rc_lcu_static = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_ADAPTIVE_RC_ACTIVITY:
+ p->codec.hevc.rc_lcu_activity = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_TIER_FLAG:
+ p->codec.hevc.tier_flag = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_MAX_PARTITION_DEPTH:
+ p->codec.hevc.max_partition_depth = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_REF_NUMBER_FOR_PFRAMES:
+ p->num_refs_for_p = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_REFRESH_TYPE:
+ p->codec.hevc.refreshtype = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_CONST_INTRA_PRED_ENABLE:
+ p->codec.hevc.const_intra_period_enable = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_LOSSLESS_CU_ENABLE:
+ p->codec.hevc.lossless_cu_enable = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_WAVEFRONT_ENABLE:
+ p->codec.hevc.wavefront_enable = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_LF_DISABLE:
+ p->codec.hevc.loopfilter_disable = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_LF_SLICE_BOUNDARY:
+ p->codec.hevc.loopfilter_across = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_LTR_ENABLE:
+ p->codec.hevc.enable_ltr = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_QP_ENABLE:
+ p->codec.hevc.hier_qp_enable = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_TYPE:
+ p->codec.hevc.hier_qp_type =
+ (enum v4l2_mpeg_video_hevc_hierarchical_coding_type)(ctrl->value);
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER:
+ p->codec.hevc.num_hier_layer = ctrl->value & 0x7;
+ p->codec.hevc.hier_ref_type = (ctrl->value >> 16) & 0x1;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_QP:
+ p->codec.hevc.hier_qp_layer[(ctrl->value >> 16) & 0x7]
+ = ctrl->value & 0xFF;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_BIT0:
+ p->codec.hevc.hier_bit_layer[0] = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_BIT1:
+ p->codec.hevc.hier_bit_layer[1] = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_BIT2:
+ p->codec.hevc.hier_bit_layer[2] = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_BIT3:
+ p->codec.hevc.hier_bit_layer[3] = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_BIT4:
+ p->codec.hevc.hier_bit_layer[4] = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_BIT5:
+ p->codec.hevc.hier_bit_layer[5] = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_BIT6:
+ p->codec.hevc.hier_bit_layer[6] = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_GENERAL_PB_ENABLE:
+ p->codec.hevc.general_pb_enable = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_TEMPORAL_ID_ENABLE:
+ p->codec.hevc.temporal_id_enable = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_STRONG_SMOTHING_FLAG:
+ p->codec.hevc.strong_intra_smooth = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_DISABLE_INTRA_PU_SPLIT:
+ p->codec.hevc.intra_pu_split_disable = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_DISABLE_TMV_PREDICTION:
+ p->codec.hevc.tmv_prediction_disable = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1:
+ p->codec.hevc.max_num_merge_mv = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_WITHOUT_STARTCODE_ENABLE:
+ p->codec.hevc.encoding_nostartcode_enable = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_REFRESH_PERIOD:
+ p->codec.hevc.refreshperiod = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_LF_BETA_OFFSET_DIV2:
+ p->codec.hevc.lf_beta_offset_div2 = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_LF_TC_OFFSET_DIV2:
+ p->codec.hevc.lf_tc_offset_div2 = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD:
+ p->codec.hevc.size_of_length_field = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_USER_REF:
+ p->codec.hevc.user_ref = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_STORE_REF:
+ p->codec.hevc.store_ref = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_ROI_ENABLE:
+ p->roi_enable = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC_H264_VUI_RESTRICTION_ENABLE:
+ p->codec.h264.vui_enable = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_PREPEND_SPSPPS_TO_IDR:
+ p->codec.hevc.prepend_sps_pps_to_idr = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC_CONFIG_QP_ENABLE:
+ p->dynamic_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC_CONFIG_QP:
+ p->config_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_RC_PVC_ENABLE:
+ /* It is valid for H.264, HEVC, VP8, VP9 */
+ p->rc_pvc = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_TEMPORAL_SHORTTERM_MAX_LAYER:
+ p->num_hier_max_layer = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_SIGN_DATA_HIDING:
+ break;
+ case V4L2_CID_MPEG_VIDEO_WEIGHTED_ENABLE:
+ p->weighted_enable = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BPG_THUMBNAIL_SIZE:
+ /* It should be included when NAL_START */
+ p->codec.bpg.thumb_size = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BPG_EXIF_SIZE:
+ /* It should be included when NAL_START */
+ p->codec.bpg.exif_size = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_RATIO_OF_INTRA:
+ p->ratio_intra = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_FULL_RANGE_FLAG:
+ p->check_color_range = 1;
+ p->color_range = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_COLOUR_PRIMARIES:
+ p->colour_primaries = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_TRANSFER_CHARACTERISTICS:
+ p->transfer_characteristics = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MATRIX_COEFFICIENTS:
+ p->matrix_coefficients = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HIERARCHICAL_BITRATE_CTRL:
+ p->hier_bitrate_ctrl = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_STATIC_INFO_ENABLE:
+ p->static_info_enable = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_SEI_MAX_PIC_AVERAGE_LIGHT:
+ p->max_pic_average_light = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_SEI_MAX_CONTENT_LIGHT:
+ p->max_content_light = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_SEI_MAX_DISPLAY_LUMINANCE:
+ p->max_display_luminance = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_SEI_MIN_DISPLAY_LUMINANCE:
+ p->min_display_luminance = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_SEI_WHITE_POINT:
+ p->white_point = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_SEI_DISPLAY_PRIMARIES_0:
+ p->display_primaries_0 = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_SEI_DISPLAY_PRIMARIES_1:
+ p->display_primaries_1 = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_SEI_DISPLAY_PRIMARIES_2:
+ p->display_primaries_2 = ctrl->value;
+ break;
+ default:
+ mfc_err_ctx("Invalid control: 0x%08x\n", ctrl->id);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int mfc_enc_set_ctrl_val(struct s5p_mfc_ctx *ctx, struct v4l2_control *ctrl)
+{
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_enc_params *p = &enc->params;
+ struct s5p_mfc_ctx_ctrl *ctx_ctrl;
+ int ret = 0;
+ int found = 0;
+ int index = 0;
+
+ mfc_debug(5, "[CTRLS] id: %#x, value: %d\n", ctrl->id, ctrl->value);
+
+ switch (ctrl->id) {
+ case V4L2_CID_CACHEABLE:
+ mfc_debug(5, "it is supported only V4L2_MEMORY_MMAP\n");
+ break;
+ case V4L2_CID_MPEG_VIDEO_QOS_RATIO:
+ ctx->qos_ratio = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
+ case V4L2_CID_MPEG_VIDEO_H263_MAX_QP:
+ case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP:
+ case V4L2_CID_MPEG_VIDEO_VP8_MAX_QP:
+ case V4L2_CID_MPEG_VIDEO_VP9_MAX_QP:
+ case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP:
+ case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
+ case V4L2_CID_MPEG_VIDEO_H263_MIN_QP:
+ case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP:
+ case V4L2_CID_MPEG_VIDEO_VP8_MIN_QP:
+ case V4L2_CID_MPEG_VIDEO_VP9_MIN_QP:
+ case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP:
+ case V4L2_CID_MPEG_VIDEO_H264_MAX_QP_P:
+ case V4L2_CID_MPEG_VIDEO_H263_MAX_QP_P:
+ case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP_P:
+ case V4L2_CID_MPEG_VIDEO_VP8_MAX_QP_P:
+ case V4L2_CID_MPEG_VIDEO_VP9_MAX_QP_P:
+ case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP_P:
+ case V4L2_CID_MPEG_VIDEO_H264_MIN_QP_P:
+ case V4L2_CID_MPEG_VIDEO_H263_MIN_QP_P:
+ case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP_P:
+ case V4L2_CID_MPEG_VIDEO_VP8_MIN_QP_P:
+ case V4L2_CID_MPEG_VIDEO_VP9_MIN_QP_P:
+ case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP_P:
+ case V4L2_CID_MPEG_VIDEO_H264_MAX_QP_B:
+ case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP_B:
+ case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP_B:
+ case V4L2_CID_MPEG_VIDEO_H264_MIN_QP_B:
+ case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP_B:
+ case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP_B:
+ case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG:
+ case V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE:
+ case V4L2_CID_MPEG_MFC51_VIDEO_I_PERIOD_CH:
+ case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_RATE_CH:
+ case V4L2_CID_MPEG_MFC51_VIDEO_BIT_RATE_CH:
+ case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_CH:
+ case V4L2_CID_MPEG_VIDEO_VP8_HIERARCHICAL_CODING_LAYER_CH:
+ case V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER_CH:
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_CH:
+ case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+ case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+ case V4L2_CID_MPEG_MFC_H264_MARK_LTR:
+ case V4L2_CID_MPEG_MFC_H264_USE_LTR:
+ case V4L2_CID_MPEG_MFC_H264_BASE_PRIORITY:
+ case V4L2_CID_MPEG_MFC_CONFIG_QP:
+ case V4L2_CID_MPEG_VIDEO_ROI_CONTROL:
+ case V4L2_CID_MPEG_VIDEO_YSUM:
+ case V4L2_CID_MPEG_VIDEO_RATIO_OF_INTRA:
+ list_for_each_entry(ctx_ctrl, &ctx->ctrls, list) {
+ if (!(ctx_ctrl->type & MFC_CTRL_TYPE_SET))
+ continue;
+
+ if (ctx_ctrl->id == ctrl->id) {
+ ctx_ctrl->has_new = 1;
+ ctx_ctrl->val = ctrl->value;
+ if (ctx_ctrl->id == \
+ V4L2_CID_MPEG_MFC51_VIDEO_FRAME_RATE_CH) {
+ ctx_ctrl->val &= ~(0xFFFF << 16);
+ ctx_ctrl->val |= ctx_ctrl->val << 16;
+ ctx_ctrl->val &= ~(0xFFFF);
+ ctx_ctrl->val |= p->rc_frame_delta & 0xFFFF;
+ }
+ if (((ctx_ctrl->id == \
+ V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_CH) ||
+ (ctx_ctrl->id == \
+ V4L2_CID_MPEG_VIDEO_VP8_HIERARCHICAL_CODING_LAYER_CH) ||
+ (ctx_ctrl->id == \
+ V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER_CH) ||
+ (ctx_ctrl->id == \
+ V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_CH)) &&
+ (enc->sh_handle_svc.fd == -1)) {
+ enc->sh_handle_svc.fd = ctrl->value;
+ if (s5p_mfc_mem_get_user_shared_handle(ctx,
+ &enc->sh_handle_svc))
+ return -EINVAL;
+ else
+ mfc_debug(2, "[MEMINFO][HIERARCHICAL] shared handle fd: %d, vaddr: 0x%p\n",
+ enc->sh_handle_svc.fd,
+ enc->sh_handle_svc.vaddr);
+ }
+ if (ctx_ctrl->id == V4L2_CID_MPEG_MFC51_VIDEO_I_PERIOD_CH &&
+ p->i_frm_ctrl_mode) {
+ ctx_ctrl->val = ctx_ctrl->val * (p->num_b_frame + 1);
+ if (ctx_ctrl->val >= 0x3FFFFFFF) {
+ mfc_info_ctx("I frame interval is bigger than max: %d\n",
+ ctx_ctrl->val);
+ ctx_ctrl->val = 0x3FFFFFFF;
+ }
+ }
+ if (ctx_ctrl->id == V4L2_CID_MPEG_VIDEO_H264_LEVEL)
+ ctx_ctrl->val = mfc_enc_h264_level((enum v4l2_mpeg_video_h264_level)(ctrl->value));
+ if (ctx_ctrl->id == V4L2_CID_MPEG_VIDEO_H264_PROFILE)
+ ctx_ctrl->val = mfc_enc_h264_profile(ctx, (enum v4l2_mpeg_video_h264_profile)(ctrl->value));
+ if (ctx_ctrl->id == V4L2_CID_MPEG_VIDEO_ROI_CONTROL) {
+ if (enc->sh_handle_roi.fd == -1) {
+ enc->sh_handle_roi.fd = ctrl->value;
+ if (s5p_mfc_mem_get_user_shared_handle(ctx,
+ &enc->sh_handle_roi))
+ return -EINVAL;
+ else
+ mfc_debug(2, "[MEMINFO][ROI] shared handle fd: %d, vaddr: 0x%p\n",
+ enc->sh_handle_roi.fd,
+ enc->sh_handle_roi.vaddr);
+ }
+ index = enc->roi_index;
+ memcpy(&enc->roi_info[index],
+ enc->sh_handle_roi.vaddr,
+ sizeof(struct mfc_enc_roi_info));
+ if (copy_from_user(enc->roi_buf[index].vaddr,
+ enc->roi_info[index].addr,
+ enc->roi_info[index].size))
+ return -EFAULT;
+ }
+
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ mfc_err_ctx("Invalid control: 0x%08x\n", ctrl->id);
+ return -EINVAL;
+ }
+ break;
+ default:
+ ret = mfc_enc_set_param(ctx, ctrl);
+ break;
+ }
+
+ return ret;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ int ret = 0;
+
+ mfc_debug_enter();
+
+ ret = mfc_enc_check_ctrl_val(ctx, ctrl);
+ if (ret != 0)
+ return ret;
+
+ ret = mfc_enc_set_ctrl_val(ctx, ctrl);
+
+ mfc_debug_leave();
+
+ return ret;
+}
+
+static int vidioc_g_ext_ctrls(struct file *file, void *priv,
+ struct v4l2_ext_controls *f)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ struct v4l2_ext_control *ext_ctrl;
+ struct v4l2_control ctrl;
+ int i;
+ int ret = 0;
+
+ if (f->which != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+
+ for (i = 0; i < f->count; i++) {
+ ext_ctrl = (f->controls + i);
+
+ ctrl.id = ext_ctrl->id;
+
+ ret = mfc_enc_get_ctrl_val(ctx, &ctrl);
+ if (ret == 0) {
+ ext_ctrl->value = ctrl.value;
+ } else {
+ f->error_idx = i;
+ break;
+ }
+
+ mfc_debug(5, "[CTRLS][%d] id: %#x, value: %d\n",
+ i, ext_ctrl->id, ext_ctrl->value);
+ }
+
+ return ret;
+}
+
+static int vidioc_s_ext_ctrls(struct file *file, void *priv,
+ struct v4l2_ext_controls *f)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ struct v4l2_ext_control *ext_ctrl;
+ struct v4l2_control ctrl;
+ int i;
+ int ret = 0;
+
+ if (f->which != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+
+ for (i = 0; i < f->count; i++) {
+ ext_ctrl = (f->controls + i);
+
+ ctrl.id = ext_ctrl->id;
+ ctrl.value = ext_ctrl->value;
+
+ ret = mfc_enc_check_ctrl_val(ctx, &ctrl);
+ if (ret != 0) {
+ f->error_idx = i;
+ break;
+ }
+
+ ret = mfc_enc_set_param(ctx, &ctrl);
+ if (ret != 0) {
+ f->error_idx = i;
+ break;
+ }
+
+ mfc_debug(5, "[CTRLS][%d] id: %#x, value: %d\n",
+ i, ext_ctrl->id, ext_ctrl->value);
+ }
+
+ return ret;
+}
+
+static int vidioc_try_ext_ctrls(struct file *file, void *priv,
+ struct v4l2_ext_controls *f)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ struct v4l2_ext_control *ext_ctrl;
+ struct v4l2_control ctrl;
+ int i;
+ int ret = 0;
+
+ if (f->which != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+
+ for (i = 0; i < f->count; i++) {
+ ext_ctrl = (f->controls + i);
+
+ ctrl.id = ext_ctrl->id;
+ ctrl.value = ext_ctrl->value;
+
+ ret = mfc_enc_check_ctrl_val(ctx, &ctrl);
+ if (ret != 0) {
+ f->error_idx = i;
+ break;
+ }
+
+ mfc_debug(2, "[%d] id: 0x%08x, value: %d\n", i, ext_ctrl->id, ext_ctrl->value);
+ }
+
+ return ret;
+}
+
+static const struct v4l2_ioctl_ops s5p_mfc_enc_ioctl_ops = {
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane,
+ .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane,
+ .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt,
+ .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt,
+ .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt,
+ .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt,
+ .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_vid_cap_mplane,
+ .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_vid_out_mplane,
+ .vidioc_g_crop = vidioc_g_crop,
+ .vidioc_s_crop = vidioc_s_crop,
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls,
+ .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls,
+ .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls,
+};
+
+const struct v4l2_ioctl_ops *s5p_mfc_get_enc_v4l2_ioctl_ops(void)
+{
+ return &s5p_mfc_enc_ioctl_ops;
+}
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_enc.h
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __MFC_ENC_H
+#define __MFC_ENC_H __FILE__
+
+#include "mfc_common.h"
+
+const struct v4l2_ioctl_ops *s5p_mfc_get_enc_v4l2_ioctl_ops(void);
+
+#endif /* __MFC_ENC_H */
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_enc_internal.h
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __MFC_ENC_INTERNAL_H
+#define __MFC_ENC_INTERNAL_H __FILE__
+
+#include "mfc_common.h"
+
+/*
+ * RGB encoding information to avoid confusion.
+ *
+ * V4L2_PIX_FMT_ARGB32 takes ARGB data like below.
+ * MSB LSB
+ * 3 2 1
+ * 2 4 6 8 0
+ * |B......BG......GR......RA......A|
+ */
+struct s5p_mfc_fmt enc_formats[] = {
+ {
+ .name = "4:2:0 3 Planes Y/Cb/Cr",
+ .fourcc = V4L2_PIX_FMT_YUV420M,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME,
+ .num_planes = 3,
+ .mem_planes = 3,
+ },
+ {
+ .name = "4:2:0 3 Planes Y/Cb/Cr single",
+ .fourcc = V4L2_PIX_FMT_YUV420N,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME,
+ .num_planes = 3,
+ .mem_planes = 1,
+ },
+ {
+ .name = "4:2:0 3 Planes Y/Cr/Cb",
+ .fourcc = V4L2_PIX_FMT_YVU420M,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME,
+ .num_planes = 3,
+ .mem_planes = 3,
+ },
+ {
+ .name = "4:2:0 2 Planes",
+ .fourcc = V4L2_PIX_FMT_NV12M,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME,
+ .num_planes = 2,
+ .mem_planes = 2,
+ },
+ {
+ .name = "4:2:0 2 Planes Y/CbCr single",
+ .fourcc = V4L2_PIX_FMT_NV12N,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME,
+ .num_planes = 2,
+ .mem_planes = 1,
+ },
+ {
+ .name = "4:2:0 2 Planes Y/CbCr 8+2 10bit",
+ .fourcc = V4L2_PIX_FMT_NV12M_S10B,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME | MFC_FMT_10BIT,
+ .num_planes = 2,
+ .mem_planes = 2,
+ },
+ {
+ .name = "4:2:0 2 Planes Y/CbCr P010 10bit",
+ .fourcc = V4L2_PIX_FMT_NV12M_P010,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME | MFC_FMT_10BIT,
+ .num_planes = 2,
+ .mem_planes = 2,
+ },
+ {
+ .name = "4:2:0 2 Planes Y/CrCb",
+ .fourcc = V4L2_PIX_FMT_NV21M,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME,
+ .num_planes = 2,
+ .mem_planes = 2,
+ },
+ {
+ .name = "4:2:0 2 Planes Y/CrCb 8+2 10bit",
+ .fourcc = V4L2_PIX_FMT_NV21M_S10B,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME | MFC_FMT_10BIT,
+ .num_planes = 2,
+ .mem_planes = 2,
+ },
+ {
+ .name = "4:2:0 2 Planes Y/CrCb P010 10bit",
+ .fourcc = V4L2_PIX_FMT_NV21M_P010,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME | MFC_FMT_10BIT,
+ .num_planes = 2,
+ .mem_planes = 2,
+ },
+ {
+ .name = "4:2:2 2 Planes Y/CbCr",
+ .fourcc = V4L2_PIX_FMT_NV16M,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME | MFC_FMT_422,
+ .num_planes = 2,
+ .mem_planes = 2,
+ },
+ {
+ .name = "4:2:2 2 Planes Y/CbCr 8+2 10bit",
+ .fourcc = V4L2_PIX_FMT_NV16M_S10B,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME | MFC_FMT_10BIT | MFC_FMT_422,
+ .num_planes = 2,
+ .mem_planes = 2,
+ },
+ {
+ .name = "4:2:2 2 Planes Y/CrCb 8+2 10bit",
+ .fourcc = V4L2_PIX_FMT_NV61M_S10B,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME | MFC_FMT_10BIT | MFC_FMT_422,
+ .num_planes = 2,
+ .mem_planes = 2,
+ },
+ {
+ .name = "4:2:2 2 Planes Y/CbCr P210 10bit",
+ .fourcc = V4L2_PIX_FMT_NV16M_P210,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME | MFC_FMT_10BIT | MFC_FMT_422,
+ .num_planes = 2,
+ .mem_planes = 2,
+ },
+ {
+ .name = "4:2:2 2 Planes Y/CrCb P210 10bit",
+ .fourcc = V4L2_PIX_FMT_NV61M_P210,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME | MFC_FMT_10BIT | MFC_FMT_422,
+ .num_planes = 2,
+ .mem_planes = 2,
+ },
+ {
+ .name = "4:2:2 2 Planes Y/CrCb",
+ .fourcc = V4L2_PIX_FMT_NV61M,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME | MFC_FMT_422,
+ .num_planes = 2,
+ .mem_planes = 2,
+ },
+ {
+ .name = "RGB888 1 Plane 24bpp",
+ .fourcc = V4L2_PIX_FMT_RGB24,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME | MFC_FMT_RGB,
+ .num_planes = 1,
+ .mem_planes = 1,
+ },
+ {
+ .name = "RGB565 1 Plane 16bpp",
+ .fourcc = V4L2_PIX_FMT_RGB565,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME | MFC_FMT_RGB,
+ .num_planes = 1,
+ .mem_planes = 1,
+ },
+ {
+ .name = "RGBX8888 1 Plane 32bpp",
+ .fourcc = V4L2_PIX_FMT_RGB32X,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME | MFC_FMT_RGB,
+ .num_planes = 1,
+ .mem_planes = 1,
+ },
+ {
+ .name = "BGRA8888 1 Plane 32bpp",
+ .fourcc = V4L2_PIX_FMT_BGR32,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME | MFC_FMT_RGB,
+ .num_planes = 1,
+ .mem_planes = 1,
+ },
+ {
+ .name = "ARGB8888 1 Plane 32bpp",
+ .fourcc = V4L2_PIX_FMT_ARGB32,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME | MFC_FMT_RGB,
+ .num_planes = 1,
+ .mem_planes = 1,
+ },
+ {
+ .name = "H264 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_H264,
+ .codec_mode = S5P_FIMV_CODEC_H264_ENC,
+ .type = MFC_FMT_STREAM,
+ .num_planes = 1,
+ .mem_planes = 1,
+ },
+ {
+ .name = "MPEG4 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_MPEG4,
+ .codec_mode = S5P_FIMV_CODEC_MPEG4_ENC,
+ .type = MFC_FMT_STREAM,
+ .num_planes = 1,
+ .mem_planes = 1,
+ },
+ {
+ .name = "H263 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_H263,
+ .codec_mode = S5P_FIMV_CODEC_H263_ENC,
+ .type = MFC_FMT_STREAM,
+ .num_planes = 1,
+ .mem_planes = 1,
+ },
+ {
+ .name = "VP8 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_VP8,
+ .codec_mode = S5P_FIMV_CODEC_VP8_ENC,
+ .type = MFC_FMT_STREAM,
+ .num_planes = 1,
+ .mem_planes = 1,
+ },
+ {
+ .name = "VP9 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_VP9,
+ .codec_mode = S5P_FIMV_CODEC_VP9_ENC,
+ .type = MFC_FMT_STREAM,
+ .num_planes = 1,
+ .mem_planes = 1,
+ },
+ {
+ .name = "HEVC Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_HEVC,
+ .codec_mode = S5P_FIMV_CODEC_HEVC_ENC,
+ .type = MFC_FMT_STREAM,
+ .num_planes = 1,
+ .mem_planes = 1,
+ },
+ {
+ .name = "BPG Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_BPG,
+ .codec_mode = S5P_FIMV_CODEC_BPG_ENC,
+ .type = MFC_FMT_STREAM,
+ .num_planes = 1,
+ .mem_planes = 1,
+ },
+};
+
+#define NUM_FORMATS ARRAY_SIZE(enc_formats)
+
+static struct v4l2_queryctrl controls[] = {
+ {
+ .id = V4L2_CID_CACHEABLE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Cacheable flag",
+ .minimum = 0,
+ .maximum = 3,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_GOP_SIZE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "The period of intra frame",
+ .minimum = 0,
+ .maximum = (1 << 30) - 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "The slice partitioning method",
+ .minimum = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
+ .maximum = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_FIXED_BYTES,
+ .step = 1,
+ .default_value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "The number of MB in a slice",
+ .minimum = 1,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "The maximum bits per slices",
+ .minimum = 350,
+ .maximum = INT_MAX / 8,
+ .step = 1,
+ .default_value = 350,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB_ROW,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "The number of MB row in a slice",
+ .minimum = 1,
+ .maximum = INT_MAX / 256,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "The number of intra refresh MBs",
+ .minimum = 0,
+ .maximum = (1 << 18) - 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_PADDING,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Padding control enable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Padding Color YUV Value",
+ .minimum = 0,
+ .maximum = (1 << 24) - 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Frame level rate control enable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_BITRATE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Target bit rate rate-control",
+ .minimum = 1,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Rate control reaction coeff.",
+ .minimum = 1,
+ .maximum = (1 << 16) - 1,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_STREAM_SIZE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Encoded stream size",
+ .minimum = 0,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ .flags = V4L2_CTRL_FLAG_READ_ONLY,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_COUNT,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Encoded frame count",
+ .minimum = 0,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ .flags = V4L2_CTRL_FLAG_READ_ONLY,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TYPE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Encoded frame type",
+ .minimum = 0,
+ .maximum = 5,
+ .step = 1,
+ .default_value = 0,
+ .flags = V4L2_CTRL_FLAG_READ_ONLY,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Force frame type",
+ .minimum = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_DISABLED,
+ .maximum = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_NOT_CODED,
+ .step = 1,
+ .default_value = \
+ V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_DISABLED,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_VBV_SIZE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "VBV buffer size (1Kbits)",
+ .minimum = 0,
+ .maximum = (1 << 16) - 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEADER_MODE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Sequence header mode",
+ .minimum = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE,
+ .maximum = V4L2_MPEG_VIDEO_HEADER_MODE_AT_THE_READY,
+ .step = 1,
+ .default_value = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Frame skip enable",
+ .minimum = V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_DISABLED,
+ .maximum = V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT,
+ .step = 1,
+ .default_value = V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_DISABLED,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Fixed target bit enable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_B_FRAMES,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "The number of B frames",
+ .minimum = 0,
+ .maximum = 2,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H264 profile",
+ .minimum = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
+ .maximum = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH,
+ .step = 1,
+ .default_value = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H264 level",
+ .minimum = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
+ .maximum = V4L2_MPEG_VIDEO_H264_LEVEL_5_1,
+ .step = 1,
+ .default_value = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_INTERLACE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "H264 interlace mode",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H264 loop filter mode",
+ .minimum = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED,
+ .maximum = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_S_B,
+ .step = 1,
+ .default_value = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H264 loop filter alpha offset",
+ .minimum = -12,
+ .maximum = 12,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H264 loop filter beta offset",
+ .minimum = -12,
+ .maximum = 12,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H264 entorpy mode",
+ .minimum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
+ .maximum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC,
+ .step = 1,
+ .default_value = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "The number of ref. picture of P",
+ .minimum = 1,
+ .maximum = 2,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "H264 8x8 transform enable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "MB level rate control",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_RC_FRAME_RATE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H264 Frame rate",
+ .minimum = 1,
+ .maximum = (1 << 16) - 1,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H264 Frame QP value",
+ .minimum = 0,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "H264 dark region adaptive",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "H264 smooth region adaptive",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "H264 static region adaptive",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "H264 MB activity adaptive",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H264 P frame QP value",
+ .minimum = 0,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H264 B frame QP value",
+ .minimum = 0,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Aspect ratio VUI enable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "VUI aspect ratio IDC",
+ .minimum = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED,
+ .maximum = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Horizontal size of SAR",
+ .minimum = 0,
+ .maximum = (1 << 16) - 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Vertical size of SAR",
+ .minimum = 0,
+ .maximum = (1 << 16) - 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "GOP closure",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_I_PERIOD,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H264 I period",
+ .minimum = 0,
+ .maximum = (1 << 16) - 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Hierarchical Coding",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hierarchical Coding Type",
+ .minimum = V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B,
+ .maximum = V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P,
+ .step = 1,
+ .default_value = V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hierarchical Coding Layer",
+ .minimum = 0,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hierarchical Coding Layer QP",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "frame pack sei generation flag",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_SEI_FP_CURRENT_FRAME_0,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Current frame is frame 0 flag",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Frame packing arrangement type",
+ .minimum = V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_SIDE_BY_SIDE,
+ .maximum = V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_TEMPORAL,
+ .step = 1,
+ .default_value = V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_SIDE_BY_SIDE,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_FMO,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Flexible Macroblock Order",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Map type for FMO",
+ .minimum = V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_INTERLEAVED_SLICES,
+ .maximum = V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_WIPE_SCAN,
+ .step = 1,
+ .default_value = \
+ V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_INTERLEAVED_SLICES,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_FMO_SLICE_GROUP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Number of slice groups for FMO",
+ .minimum = 1,
+ .maximum = 4,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_FMO_RUN_LENGTH,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "FMO Run Length",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_DIRECTION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Direction of the slice group",
+ .minimum = V4L2_MPEG_VIDEO_H264_FMO_CHANGE_DIR_RIGHT,
+ .maximum = V4L2_MPEG_VIDEO_H264_FMO_CHANGE_DIR_LEFT,
+ .step = 1,
+ .default_value = V4L2_MPEG_VIDEO_H264_FMO_CHANGE_DIR_RIGHT,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_RATE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Size of the first slice group",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_ASO,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Arbitrary Slice Order",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_ASO_SLICE_ORDER,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "ASO Slice order",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_PREPEND_SPSPPS_TO_IDR,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Prepend SPS/PPS to every IDR",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "MPEG4 profile",
+ .minimum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
+ .maximum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE,
+ .step = 1,
+ .default_value = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "MPEG4 level",
+ .minimum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
+ .maximum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_6,
+ .step = 1,
+ .default_value = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "MPEG4 Frame QP value",
+ .minimum = 1,
+ .maximum = 31,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_QPEL,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Quarter pixel search enable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "MPEG4 P frame QP value",
+ .minimum = 1,
+ .maximum = 31,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "MPEG4 B frame QP value",
+ .minimum = 1,
+ .maximum = 31,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_MPEG4_VOP_TIME_RES,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "MPEG4 vop time resolution",
+ .minimum = 0,
+ .maximum = (1 << 16) - 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_MPEG4_VOP_FRM_DELTA,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "MPEG4 frame delta",
+ .minimum = 1,
+ .maximum = (1 << 16) - 1,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_H263_RC_FRAME_RATE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H263 Frame rate",
+ .minimum = 1,
+ .maximum = (1 << 8) - 1,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H263 Frame QP value",
+ .minimum = 1,
+ .maximum = 31,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H263 P frame QP value",
+ .minimum = 1,
+ .maximum = 31,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Frame Tag",
+ .minimum = 0,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_STATUS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Frame Status",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_QOS_RATIO,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "QoS ratio value",
+ .minimum = 20,
+ .maximum = 1000,
+ .step = 10,
+ .default_value = 100,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC70_VIDEO_VP8_VERSION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "VP8 version",
+ .minimum = 0,
+ .maximum = 3,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_VP8_I_FRAME_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "VP8 Frame QP value",
+ .minimum = 0,
+ .maximum = 127,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_VP8_P_FRAME_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "VP8 Frame QP value",
+ .minimum = 0,
+ .maximum = 127,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC70_VIDEO_VP8_RC_FRAME_RATE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "VP8 Frame rate",
+ .minimum = 1,
+ .maximum = (1 << 16) - 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC70_VIDEO_VP8_NUM_OF_PARTITIONS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "VP8 number of partitions",
+ .minimum = 0,
+ .maximum = 8,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC70_VIDEO_VP8_FILTER_LEVEL,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "VP8 loop filter level",
+ .minimum = 0,
+ .maximum = 63,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC70_VIDEO_VP8_FILTER_SHARPNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "VP8 loop filter sharpness",
+ .minimum = 0,
+ .maximum = 7,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC70_VIDEO_VP8_GOLDEN_FRAMESEL,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "VP8 indication of golden frame",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC70_VIDEO_VP8_GF_REFRESH_PERIOD,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "VP8 indication of golden frame",
+ .minimum = 0,
+ .maximum = (1 << 16) - 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC70_VIDEO_VP8_HIERARCHY_QP_ENABLE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "VP8 hierarchy QP enable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC70_VIDEO_VP8_HIERARCHY_QP_LAYER0,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "VP8 layer0 QP value",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC70_VIDEO_VP8_HIERARCHY_QP_LAYER1,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "VP8 layer1 QP value",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC70_VIDEO_VP8_HIERARCHY_QP_LAYER2,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "VP8 layer2 QP value",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC70_VIDEO_VP8_REF_NUMBER_FOR_PFRAMES,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "VP8 Number of reference picture",
+ .minimum = 1,
+ .maximum = 2,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC70_VIDEO_VP8_DISABLE_INTRA_MD4X4,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "VP8 intra 4x4 mode disable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC70_VIDEO_VP8_NUM_TEMPORAL_LAYER,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "VP8 number of hierarchical layer",
+ .minimum = 0,
+ .maximum = 3,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_VP9_VERSION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "VP9 version",
+ .minimum = 0,
+ .maximum = 3,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_VP9_I_FRAME_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "VP9 Frame QP value",
+ .minimum = 1,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_VP9_P_FRAME_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "VP9 Frame QP value",
+ .minimum = 1,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_VP9_RC_FRAME_RATE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "VP9 Frame rate",
+ .minimum = 1,
+ .maximum = (1 << 16) - 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_VP9_GOLDEN_FRAMESEL,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "VP9 indication of golden frame",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_VP9_GF_REFRESH_PERIOD,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "VP9 indication of golden frame",
+ .minimum = 0,
+ .maximum = ((1 << 16) - 1),
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_VP9_HIERARCHY_QP_ENABLE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "VP9 hierarchy QP enable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "VP9 layer0 QP value",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_VP9_REF_NUMBER_FOR_PFRAMES,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "VP9 Number of reference picture",
+ .minimum = 1,
+ .maximum = 2,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "VP9 number of hierarchical layer",
+ .minimum = 0,
+ .maximum = 3,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_VP9_MAX_PARTITION_DEPTH,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "VP9 Maximum coding unit depth",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_VP9_DISABLE_INTRA_PU_SPLIT,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "VP9 disable intra pu split",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER_BIT0,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hierarchical Coding Layer Bit0",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER_BIT1,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hierarchical Coding Layer Bit1",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER_BIT2,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hierarchical Coding Layer Bit2",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER_CH,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hierarchical Coding Layer Change",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_DISABLE_IVF_HEADER,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "IVF header generation",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "HEVC Frame QP value",
+ .minimum = -12,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "HEVC P frame QP value",
+ .minimum = -12,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "HEVC B frame QP value",
+ .minimum = -12,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_ADAPTIVE_RC_DARK,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "HEVC dark region adaptive",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_ADAPTIVE_RC_SMOOTH,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "HEVC smooth region adaptive",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_ADAPTIVE_RC_STATIC,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "HEVC static region adaptive",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_ADAPTIVE_RC_ACTIVITY,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "HEVC activity adaptive",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "HEVC Profile",
+ .minimum = 0,
+ .maximum = 4,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "HEVC level",
+ .minimum = 10,
+ .maximum = 62,
+ .step = 1,
+ .default_value = 10,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_TIER_FLAG,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "HEVC tier_flag default is Main",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_RC_FRAME_RATE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "HEVC Frame rate",
+ .minimum = 1,
+ .maximum = (1 << 16) - 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_MAX_PARTITION_DEPTH,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "HEVC Maximum coding unit depth",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0, /* need to check defualt value */
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_REF_NUMBER_FOR_PFRAMES,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "HEVC Number of reference picture",
+ .minimum = 1,
+ .maximum = 2,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_REFRESH_TYPE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "HEVC Number of reference picture",
+ .minimum = 0,
+ .maximum = 2,
+ .step = 1,
+ .default_value = 0, /* need to check defualt value */
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_CONST_INTRA_PRED_ENABLE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "HEVC refresh type",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0, /* need to check defualt value */
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_LOSSLESS_CU_ENABLE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "HEVC lossless encoding select",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0, /* need to check defualt value */
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_WAVEFRONT_ENABLE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "HEVC Wavefront enable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0, /* need to check defualt value */
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_LF_DISABLE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "HEVC Filter disable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0, /* need to check defualt value */
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_LF_SLICE_BOUNDARY,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "across or not slice boundary",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0, /* need to check defualt value */
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_LTR_ENABLE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "long term reference enable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0, /* need to check defualt value */
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_QP_ENABLE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "QP values for temporal layer",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0, /* need to check defualt value */
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_TYPE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Hierarchical Coding Type",
+ .minimum = V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B,
+ .maximum = V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P,
+ .step = 1,
+ .default_value = 0, /* need to check defualt value */
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hierarchical Coding Layer",
+ .minimum = 0,
+ .maximum = 7,
+ .step = 1,
+ .default_value = 0, /* need to check defualt value */
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hierarchical Coding Layer QP",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0, /* need to check defualt value */
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_BIT0,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hierarchical Coding Layer BIT0",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_BIT1,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hierarchical Coding Layer BIT1",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_BIT2,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hierarchical Coding Layer BIT2",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_BIT3,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hierarchical Coding Layer BIT3",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_BIT4,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hierarchical Coding Layer BIT4",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_BIT5,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hierarchical Coding Layer BIT5",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_BIT6,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hierarchical Coding Layer BIT6",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_CH,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hierarchical Coding Layer Change",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_SIGN_DATA_HIDING,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "HEVC Sign data hiding",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0, /* need to check defualt value */
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_GENERAL_PB_ENABLE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "HEVC General pb enable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0, /* need to check defualt value */
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_TEMPORAL_ID_ENABLE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "HEVC Temporal id enable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0, /* need to check defualt value */
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_STRONG_SMOTHING_FLAG,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "HEVC Strong intra smoothing flag",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0, /* need to check defualt value */
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_DISABLE_INTRA_PU_SPLIT,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "HEVC disable intra pu split",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0, /* need to check defualt value */
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_DISABLE_TMV_PREDICTION,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "HEVC disable tmv prediction",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0, /* need to check defualt value */
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "max number of candidate MVs",
+ .minimum = 0,
+ .maximum = 4,
+ .step = 1,
+ .default_value = 0, /* need to check defualt value */
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_WITHOUT_STARTCODE_ENABLE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "ENC without startcode enable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0, /* need to check defualt value */
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_REFRESH_PERIOD,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "HEVC Number of reference picture",
+ .minimum = 0,
+ .maximum = (1 << 16) - 1,
+ .step = 1,
+ .default_value = 0, /* need to check defualt value */
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_LF_BETA_OFFSET_DIV2,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "HEVC loop filter beta offset",
+ .minimum = -6,
+ .maximum = 6,
+ .step = 1,
+ .default_value = 0, /* need to check defualt value */
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_LF_TC_OFFSET_DIV2,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "HEVC loop filter tc offset",
+ .minimum = -6,
+ .maximum = 6,
+ .step = 1,
+ .default_value = 0, /* need to check defualt value */
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "HEVC size of length field",
+ .minimum = 0,
+ .maximum = 3,
+ .step = 1,
+ .default_value = 0, /* need to check defualt value */
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_USER_REF,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "user long term reference frame",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0, /* need to check defualt value */
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_STORE_REF,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "store long term reference frame",
+ .minimum = 0,
+ .maximum = 2,
+ .step = 1,
+ .default_value = 0, /* need to check defualt value */
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC_GET_VERSION_INFO,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Get MFC version information",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC_GET_EXTRA_BUFFER_SIZE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Get extra buffer size",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC_GET_EXT_INFO,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Get extra information",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_BIT0,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hierarchical Coding Layer Bit0",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_BIT1,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hierarchical Coding Layer Bit1",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_BIT2,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hierarchical Coding Layer Bit2",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_BIT3,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hierarchical Coding Layer Bit3",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_BIT4,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hierarchical Coding Layer Bit4",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_BIT5,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hierarchical Coding Layer Bit5",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_BIT6,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hierarchical Coding Layer Bit6",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_CH,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hierarchical Coding Layer Change",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_VP8_HIERARCHICAL_CODING_LAYER_BIT0,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hierarchical Coding Layer Bit0",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_VP8_HIERARCHICAL_CODING_LAYER_BIT1,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hierarchical Coding Layer Bit1",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_VP8_HIERARCHICAL_CODING_LAYER_BIT2,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hierarchical Coding Layer Bit2",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_VP8_HIERARCHICAL_CODING_LAYER_CH,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hierarchical Coding Layer Change",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC_H264_ENABLE_LTR,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Enable LTR",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC_H264_NUM_OF_LTR,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Number of LTR",
+ .minimum = 0,
+ .maximum = 4,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC_H264_MARK_LTR,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Set the frame as a LTRP",
+ .minimum = 0,
+ .maximum = 4,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC_H264_USE_LTR,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Specify a LTRP for encoding",
+ .minimum = 0,
+ .maximum = 0xF,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC_H264_BASE_PRIORITY,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hierarchical Base Layer Priority",
+ .minimum = 0,
+ .maximum = (1 << 6) - 1 - 6,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC_CONFIG_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "QP control per each frame",
+ .minimum = -12,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC_H264_VUI_RESTRICTION_ENABLE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H264 vui generation enable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_PREPEND_SPSPPS_TO_IDR,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Prepend SPS/PPS to every IDR",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC_CONFIG_QP_ENABLE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "set dynamic qp controls",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_ROI_CONTROL,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Region-Of-Interest control",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_ROI_ENABLE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Region-Of-Interest enable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_MIN_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H264 Min QP value for I frame",
+ .minimum = 0,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H264 Max QP value for I frame",
+ .minimum = 0,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "HEVC Min QP value for I frame",
+ .minimum = -12,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "HEVC Max QP value for I frame",
+ .minimum = 0,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "MPEG4 Min QP value for I frame",
+ .minimum = 1,
+ .maximum = 31,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "MPEG4 Max QP value for I frame",
+ .minimum = 1,
+ .maximum = 31,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H263_MIN_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H263 Min QP value for I frame",
+ .minimum = 1,
+ .maximum = 31,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H263_MAX_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H263 Max QP value for I frame",
+ .minimum = 1,
+ .maximum = 31,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_VP8_MIN_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "VP8 Min QP value for I frame",
+ .minimum = 0,
+ .maximum = 127,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_VP8_MAX_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "VP8 Max QP value for I frame",
+ .minimum = 0,
+ .maximum = 127,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_VP9_MIN_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "VP9 Min QP value for I frame",
+ .minimum = 1,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_VP9_MAX_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "VP9 Max QP value for I frame",
+ .minimum = 1,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_MIN_QP_P,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H264 Min QP value for P frame",
+ .minimum = 0,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP_P,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H264 Max QP value for P frame",
+ .minimum = 0,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP_P,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "HEVC Min QP value for P frame",
+ .minimum = -12,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP_P,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "HEVC Max QP value for P frame",
+ .minimum = 0,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP_P,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "MPEG4 Min QP value for P frame",
+ .minimum = 1,
+ .maximum = 31,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP_P,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "MPEG4 Max QP value for P frame",
+ .minimum = 1,
+ .maximum = 31,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H263_MIN_QP_P,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H263 Min QP value for P frame",
+ .minimum = 1,
+ .maximum = 31,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H263_MAX_QP_P,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H263 Max QP value for P frame",
+ .minimum = 1,
+ .maximum = 31,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_VP8_MIN_QP_P,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "VP8 Min QP value for P frame",
+ .minimum = 0,
+ .maximum = 127,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_VP8_MAX_QP_P,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "VP8 Max QP value for P frame",
+ .minimum = 0,
+ .maximum = 127,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_VP9_MIN_QP_P,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "VP9 Min QP value for P frame",
+ .minimum = 1,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_VP9_MAX_QP_P,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "VP9 Max QP value for P frame",
+ .minimum = 1,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_MIN_QP_B,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H264 Min QP value for B frame",
+ .minimum = 0,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP_B,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H264 Max QP value for B frame",
+ .minimum = 0,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP_B,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "HEVC Min QP value for B frame",
+ .minimum = -12,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP_B,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "HEVC Max QP value for B frame",
+ .minimum = 0,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP_B,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "MPEG4 Min QP value for B frame",
+ .minimum = 1,
+ .maximum = 31,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP_B,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "MPEG4 Max QP value for B frame",
+ .minimum = 1,
+ .maximum = 31,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_RC_PVC_ENABLE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Perceptual Video Coding enable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_TEMPORAL_SHORTTERM_MAX_LAYER,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hierarchical Coding max layer",
+ .minimum = 0,
+ .maximum = 3,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_WEIGHTED_ENABLE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Weighted Prediction enable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_YSUM,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "YSUM for weighted Prediction",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_BPG_THUMBNAIL_SIZE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "BPG thumbnail size",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_BPG_EXIF_SIZE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "BPG EXIF data size",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_BPG_HEADER_SIZE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "BPG header size",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_RATIO_OF_INTRA,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "ratio of intra encoded size",
+ .minimum = 15,
+ .maximum = 50,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_FULL_RANGE_FLAG,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Color range",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_COLOUR_PRIMARIES,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Colour primaries",
+ .minimum = 0,
+ .maximum = 10,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_TRANSFER_CHARACTERISTICS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Transfer characteristics",
+ .minimum = 0,
+ .maximum = 17,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MATRIX_COEFFICIENTS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Matrix coefficients",
+ .minimum = 0,
+ .maximum = 10,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HIERARCHICAL_BITRATE_CTRL,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Hierarchical bitrate control",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_STATIC_INFO_ENABLE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Static info enable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_SEI_MAX_PIC_AVERAGE_LIGHT,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Max pic average light",
+ .minimum = 0,
+ .maximum = 0xFFFF,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_SEI_MAX_CONTENT_LIGHT,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Max content light",
+ .minimum = 0,
+ .maximum = 0xFFFF,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_SEI_MAX_DISPLAY_LUMINANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Max display luminance",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_SEI_MIN_DISPLAY_LUMINANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Min display luminance",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_SEI_WHITE_POINT,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "White point",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_SEI_DISPLAY_PRIMARIES_0,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Display primaries 0",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_SEI_DISPLAY_PRIMARIES_1,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Display primaries 1",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_SEI_DISPLAY_PRIMARIES_2,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Display primaries 2",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+};
+
+#define NUM_CTRLS ARRAY_SIZE(controls)
+
+#endif /* __MFC_ENC_INTERNAL_H */
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_enc_ops.c
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "mfc_common.h"
+
+#include "mfc_reg.h"
+
+static int mfc_enc_ctrl_read_cst(struct s5p_mfc_ctx *ctx,
+ struct s5p_mfc_buf_ctrl *buf_ctrl)
+{
+ int ret;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+
+ switch (buf_ctrl->id) {
+ case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_STATUS:
+ ret = !enc->in_slice;
+ break;
+ default:
+ mfc_err_ctx("not support custom per-buffer control\n");
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static struct s5p_mfc_ctrl_cfg mfc_ctrl_list[] = {
+ { /* set frame tag */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_PICTURE_TAG,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ { /* get frame tag */
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_RET_PICTURE_TAG,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ { /* encoded y physical addr */
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_LUMA_ADDR,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_ENCODED_SOURCE_FIRST_ADDR,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ { /* encoded c physical addr */
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_CHROMA_ADDR,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_ENCODED_SOURCE_SECOND_ADDR,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ { /* I, not coded frame insertion */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_FRAME_INSERTION,
+ .mask = 0x3,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ { /* I period change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_I_PERIOD_CH,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_GOP_CONFIG,
+ .mask = 0xFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 0,
+ },
+ { /* frame rate change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_RATE_CH,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_RC_FRAME_RATE,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 1,
+ },
+ { /* bit rate change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_BIT_RATE_CH,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_RC_BIT_RATE,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 2,
+ },
+ { /* frame status (in slice or not) */
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_STATUS,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_CST,
+ .addr = 0,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ .read_cst = mfc_enc_ctrl_read_cst,
+ .write_cst = NULL,
+ },
+ { /* H.264 I frame QP Max change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_RC_QP_BOUND,
+ .mask = 0xFF,
+ .shft = 8,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 4,
+ },
+ { /* H.264 I frame QP Min change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_H264_MIN_QP,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_RC_QP_BOUND,
+ .mask = 0xFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 4,
+ },
+ { /* H.263 I frame QP Max change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_H263_MAX_QP,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_RC_QP_BOUND,
+ .mask = 0xFF,
+ .shft = 8,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 4,
+ },
+ { /* H.263 I frame QP Min change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_H263_MIN_QP,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_RC_QP_BOUND,
+ .mask = 0xFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 4,
+ },
+ { /* MPEG4 I frame QP Max change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_RC_QP_BOUND,
+ .mask = 0xFF,
+ .shft = 8,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 4,
+ },
+ { /* MPEG4 I frame QP Min change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_RC_QP_BOUND,
+ .mask = 0xFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 4,
+ },
+ { /* VP8 I frame QP Max change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_VP8_MAX_QP,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_RC_QP_BOUND,
+ .mask = 0xFF,
+ .shft = 8,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 4,
+ },
+ { /* VP8 I frame QP Min change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_VP8_MIN_QP,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_RC_QP_BOUND,
+ .mask = 0xFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 4,
+ },
+ { /* VP9 I frame QP Max change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_VP9_MAX_QP,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_RC_QP_BOUND,
+ .mask = 0xFF,
+ .shft = 8,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 4,
+ },
+ { /* VP9 I frame QP Min change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_VP9_MIN_QP,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_RC_QP_BOUND,
+ .mask = 0xFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 4,
+ },
+ { /* HEVC I frame QP Max change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_RC_QP_BOUND,
+ .mask = 0xFF,
+ .shft = 8,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 4,
+ },
+ { /* HEVC I frame QP Min change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_RC_QP_BOUND,
+ .mask = 0xFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 4,
+ },
+ { /* H.264 P frame QP Max change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP_P,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_RC_QP_BOUND_PB,
+ .mask = 0xFF,
+ .shft = 8,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 4,
+ },
+ { /* H.264 P frame QP Min change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_H264_MIN_QP_P,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_RC_QP_BOUND_PB,
+ .mask = 0xFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 4,
+ },
+ { /* H.263 P frame QP Max change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_H263_MAX_QP_P,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_RC_QP_BOUND_PB,
+ .mask = 0xFF,
+ .shft = 8,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 4,
+ },
+ { /* H.263 P frame QP Min change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_H263_MIN_QP_P,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_RC_QP_BOUND_PB,
+ .mask = 0xFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 4,
+ },
+ { /* MPEG4 P frame QP Max change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP_P,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_RC_QP_BOUND_PB,
+ .mask = 0xFF,
+ .shft = 8,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 4,
+ },
+ { /* MPEG4 P frame QP Min change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP_P,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_RC_QP_BOUND_PB,
+ .mask = 0xFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 4,
+ },
+ { /* VP8 P frame QP Max change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_VP8_MAX_QP_P,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_RC_QP_BOUND_PB,
+ .mask = 0xFF,
+ .shft = 8,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 4,
+ },
+ { /* VP8 P frame QP Min change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_VP8_MIN_QP_P,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_RC_QP_BOUND_PB,
+ .mask = 0xFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 4,
+ },
+ { /* VP9 P frame QP Max change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_VP9_MAX_QP_P,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_RC_QP_BOUND_PB,
+ .mask = 0xFF,
+ .shft = 8,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 4,
+ },
+ { /* VP9 P frame QP Min change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_VP9_MIN_QP_P,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_RC_QP_BOUND_PB,
+ .mask = 0xFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 4,
+ },
+ { /* HEVC P frame QP Max change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP_P,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_RC_QP_BOUND_PB,
+ .mask = 0xFF,
+ .shft = 8,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 4,
+ },
+ { /* HEVC P frame QP Min change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP_P,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_RC_QP_BOUND_PB,
+ .mask = 0xFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 4,
+ },
+ { /* H.264 B frame QP Max change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP_B,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_RC_QP_BOUND_PB,
+ .mask = 0xFF,
+ .shft = 24,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 4,
+ },
+ { /* H.264 B frame QP Min change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_H264_MIN_QP_B,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_RC_QP_BOUND_PB,
+ .mask = 0xFF,
+ .shft = 16,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 4,
+ },
+ { /* MPEG4 B frame QP Max change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP_B,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_RC_QP_BOUND_PB,
+ .mask = 0xFF,
+ .shft = 24,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 4,
+ },
+ { /* MPEG4 B frame QP Min change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP_B,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_RC_QP_BOUND_PB,
+ .mask = 0xFF,
+ .shft = 16,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 4,
+ },
+ { /* HEVC B frame QP Max change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP_B,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_RC_QP_BOUND_PB,
+ .mask = 0xFF,
+ .shft = 24,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 4,
+ },
+ { /* HEVC B frame QP Min change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP_B,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_RC_QP_BOUND_PB,
+ .mask = 0xFF,
+ .shft = 16,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 4,
+ },
+ { /* H.264 Dynamic Temporal Layer & bitrate change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_CH,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER0,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 10,
+ },
+ { /* HEVC Dynamic Temporal Layer & bitrate change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_CH,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER0,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 10,
+ },
+ { /* VP8 Dynamic Temporal Layer change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_VP8_HIERARCHICAL_CODING_LAYER_CH,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER0,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 10,
+ },
+ { /* VP9 Dynamic Temporal Layer change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER_CH,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER0,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 10,
+ },
+ { /* set level */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_PICTURE_PROFILE,
+ .mask = 0x000000FF,
+ .shft = 8,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 5,
+ },
+ { /* set profile */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_PICTURE_PROFILE,
+ .mask = 0x0000000F,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 5,
+ },
+ { /* set store LTR */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_MFC_H264_MARK_LTR,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_H264_NAL_CONTROL,
+ .mask = 0x00000003,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ { /* set use LTR */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_MFC_H264_USE_LTR,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_H264_NAL_CONTROL,
+ .mask = 0x00000003,
+ .shft = 2,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ { /* set base layer priority */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_MFC_H264_BASE_PRIORITY,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_H264_HD_SVC_EXTENSION_0,
+ .mask = 0x0000003F,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 12,
+ },
+ { /* set QP per each frame */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_MFC_CONFIG_QP,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_FIXED_PICTURE_QP,
+ .mask = 0x000000FF,
+ .shft = 24,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ { /* Region-Of-Interest control */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_ROI_CONTROL,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_RC_ROI_CTRL,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ { /* set YSUM for weighted prediction */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_YSUM,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_WEIGHT_FOR_WEIGHTED_PREDICTION,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_mode = 0,
+ .flag_shft = 0,
+ },
+ { /* set base layer priority */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_VIDEO_RATIO_OF_INTRA,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_E_RC_MODE,
+ .mask = 0x000000FF,
+ .shft = 8,
+ .flag_mode = MFC_CTRL_MODE_SFR,
+ .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
+ .flag_shft = 13,
+ }
+};
+
+#define NUM_CTRL_CFGS ARRAY_SIZE(mfc_ctrl_list)
+
+static int s5p_mfc_enc_cleanup_ctx_ctrls(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_ctx_ctrl *ctx_ctrl;
+
+ while (!list_empty(&ctx->ctrls)) {
+ ctx_ctrl = list_entry((&ctx->ctrls)->next,
+ struct s5p_mfc_ctx_ctrl, list);
+ list_del(&ctx_ctrl->list);
+ kfree(ctx_ctrl);
+ }
+
+ INIT_LIST_HEAD(&ctx->ctrls);
+
+ return 0;
+}
+
+static int s5p_mfc_enc_get_buf_update_val(struct s5p_mfc_ctx *ctx,
+ struct list_head *head, unsigned int id, int value)
+{
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if (buf_ctrl->id == id) {
+ buf_ctrl->val = value;
+ mfc_debug(6, "[CTRLS] Update buffer control id: 0x%08x, val: %d\n",
+ buf_ctrl->id, buf_ctrl->val);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int s5p_mfc_enc_init_ctx_ctrls(struct s5p_mfc_ctx *ctx)
+{
+ unsigned long i;
+ struct s5p_mfc_ctx_ctrl *ctx_ctrl;
+
+ INIT_LIST_HEAD(&ctx->ctrls);
+
+ for (i = 0; i < NUM_CTRL_CFGS; i++) {
+ ctx_ctrl = kzalloc(sizeof(struct s5p_mfc_ctx_ctrl), GFP_KERNEL);
+ if (ctx_ctrl == NULL) {
+ mfc_err_dev("Failed to allocate context control "\
+ "id: 0x%08x, type: %d\n",
+ mfc_ctrl_list[i].id,
+ mfc_ctrl_list[i].type);
+
+ s5p_mfc_enc_cleanup_ctx_ctrls(ctx);
+
+ return -ENOMEM;
+ }
+
+ ctx_ctrl->type = mfc_ctrl_list[i].type;
+ ctx_ctrl->id = mfc_ctrl_list[i].id;
+ ctx_ctrl->has_new = 0;
+ ctx_ctrl->val = 0;
+
+ list_add_tail(&ctx_ctrl->list, &ctx->ctrls);
+ }
+
+ return 0;
+}
+
+static void s5p_mfc_enc_reset_buf_ctrls(struct list_head *head)
+{
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ buf_ctrl->has_new = 0;
+ buf_ctrl->val = 0;
+ buf_ctrl->old_val = 0;
+ buf_ctrl->updated = 0;
+ }
+}
+
+static void mfc_enc_remove_buf_ctrls(struct list_head *head)
+{
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+
+ while (!list_empty(head)) {
+ buf_ctrl = list_entry(head->next,
+ struct s5p_mfc_buf_ctrl, list);
+ list_del(&buf_ctrl->list);
+ kfree(buf_ctrl);
+ }
+
+ INIT_LIST_HEAD(head);
+}
+
+static int s5p_mfc_enc_init_buf_ctrls(struct s5p_mfc_ctx *ctx,
+ enum s5p_mfc_ctrl_type type, unsigned int index)
+{
+ unsigned long i;
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+ struct list_head *head;
+
+ if (index >= MFC_MAX_BUFFERS) {
+ mfc_err_dev("Per-buffer control index is out of range\n");
+ return -EINVAL;
+ }
+
+ if (type & MFC_CTRL_TYPE_SRC) {
+ if (test_bit(index, &ctx->src_ctrls_avail)) {
+ s5p_mfc_enc_reset_buf_ctrls(&ctx->src_ctrls[index]);
+
+ return 0;
+ }
+
+ head = &ctx->src_ctrls[index];
+ } else if (type & MFC_CTRL_TYPE_DST) {
+ if (test_bit(index, &ctx->dst_ctrls_avail)) {
+ s5p_mfc_enc_reset_buf_ctrls(&ctx->dst_ctrls[index]);
+
+ return 0;
+ }
+
+ head = &ctx->dst_ctrls[index];
+ } else {
+ mfc_err_dev("Control type mismatch. type : %d\n", type);
+ return -EINVAL;
+ }
+
+ INIT_LIST_HEAD(head);
+
+ for (i = 0; i < NUM_CTRL_CFGS; i++) {
+ if (!(type & mfc_ctrl_list[i].type))
+ continue;
+
+ buf_ctrl = kzalloc(sizeof(struct s5p_mfc_buf_ctrl), GFP_KERNEL);
+ if (buf_ctrl == NULL) {
+ mfc_err_dev("Failed to allocate buffer control "\
+ "id: 0x%08x, type: %d\n",
+ mfc_ctrl_list[i].id,
+ mfc_ctrl_list[i].type);
+
+ mfc_enc_remove_buf_ctrls(head);
+
+ return -ENOMEM;
+ }
+
+ buf_ctrl->type = mfc_ctrl_list[i].type;
+ buf_ctrl->id = mfc_ctrl_list[i].id;
+ buf_ctrl->is_volatile = mfc_ctrl_list[i].is_volatile;
+ buf_ctrl->mode = mfc_ctrl_list[i].mode;
+ buf_ctrl->addr = mfc_ctrl_list[i].addr;
+ buf_ctrl->mask = mfc_ctrl_list[i].mask;
+ buf_ctrl->shft = mfc_ctrl_list[i].shft;
+ buf_ctrl->flag_mode = mfc_ctrl_list[i].flag_mode;
+ buf_ctrl->flag_addr = mfc_ctrl_list[i].flag_addr;
+ buf_ctrl->flag_shft = mfc_ctrl_list[i].flag_shft;
+ if (buf_ctrl->mode == MFC_CTRL_MODE_CST) {
+ buf_ctrl->read_cst = mfc_ctrl_list[i].read_cst;
+ buf_ctrl->write_cst = mfc_ctrl_list[i].write_cst;
+ }
+
+ list_add_tail(&buf_ctrl->list, head);
+ }
+
+ s5p_mfc_enc_reset_buf_ctrls(head);
+
+ if (type & MFC_CTRL_TYPE_SRC)
+ set_bit(index, &ctx->src_ctrls_avail);
+ else
+ set_bit(index, &ctx->dst_ctrls_avail);
+
+ return 0;
+}
+
+static int s5p_mfc_enc_cleanup_buf_ctrls(struct s5p_mfc_ctx *ctx,
+ enum s5p_mfc_ctrl_type type, unsigned int index)
+{
+ struct list_head *head;
+
+ if (index >= MFC_MAX_BUFFERS) {
+ mfc_err_dev("Per-buffer control index is out of range\n");
+ return -EINVAL;
+ }
+
+ if (type & MFC_CTRL_TYPE_SRC) {
+ if (!(test_and_clear_bit(index, &ctx->src_ctrls_avail))) {
+ return 0;
+ }
+
+ head = &ctx->src_ctrls[index];
+ } else if (type & MFC_CTRL_TYPE_DST) {
+ if (!(test_and_clear_bit(index, &ctx->dst_ctrls_avail))) {
+ return 0;
+ }
+
+ head = &ctx->dst_ctrls[index];
+ } else {
+ mfc_err_dev("Control type mismatch. type : %d\n", type);
+ return -EINVAL;
+ }
+
+ mfc_enc_remove_buf_ctrls(head);
+
+ return 0;
+}
+
+static int s5p_mfc_enc_to_buf_ctrls(struct s5p_mfc_ctx *ctx, struct list_head *head)
+{
+ struct s5p_mfc_ctx_ctrl *ctx_ctrl;
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ int index = 0;
+ unsigned int reg = 0;
+
+ list_for_each_entry(ctx_ctrl, &ctx->ctrls, list) {
+ if (!(ctx_ctrl->type & MFC_CTRL_TYPE_SET) || !ctx_ctrl->has_new)
+ continue;
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if (!(buf_ctrl->type & MFC_CTRL_TYPE_SET))
+ continue;
+
+ if (buf_ctrl->id == ctx_ctrl->id) {
+ buf_ctrl->has_new = 1;
+ buf_ctrl->val = ctx_ctrl->val;
+ if (buf_ctrl->is_volatile)
+ buf_ctrl->updated = 0;
+
+ ctx_ctrl->has_new = 0;
+ if (buf_ctrl->id == V4L2_CID_MPEG_VIDEO_ROI_CONTROL) {
+ index = enc->roi_index;
+ if (enc->roi_info[index].enable) {
+ enc->roi_index =
+ (index + 1) % MFC_MAX_EXTRA_BUF;
+ reg |= enc->roi_info[index].enable;
+ reg &= ~(0xFF << 8);
+ reg |= (enc->roi_info[index].lower_qp << 8);
+ reg &= ~(0xFFFF << 16);
+ reg |= (enc->roi_info[index].upper_qp << 16);
+ mfc_debug(3, "[ROI] buffer[%d] en %d, "\
+ "QP lower %d upper %d reg %#x\n",
+ index, enc->roi_info[index].enable,
+ enc->roi_info[index].lower_qp,
+ enc->roi_info[index].upper_qp,
+ reg);
+ } else {
+ mfc_debug(3, "[ROI] buffer[%d] is not enabled\n", index);
+ }
+ buf_ctrl->val = reg;
+ buf_ctrl->old_val2 = index;
+ }
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int s5p_mfc_enc_to_ctx_ctrls(struct s5p_mfc_ctx *ctx, struct list_head *head)
+{
+ struct s5p_mfc_ctx_ctrl *ctx_ctrl;
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if (!(buf_ctrl->type & MFC_CTRL_TYPE_GET) || !buf_ctrl->has_new)
+ continue;
+
+ list_for_each_entry(ctx_ctrl, &ctx->ctrls, list) {
+ if (!(ctx_ctrl->type & MFC_CTRL_TYPE_GET))
+ continue;
+
+ if (ctx_ctrl->id == buf_ctrl->id) {
+ if (ctx_ctrl->has_new)
+ mfc_debug(8,
+ "Overwrite context control "\
+ "value id: 0x%08x, val: %d\n",
+ ctx_ctrl->id, ctx_ctrl->val);
+
+ ctx_ctrl->has_new = 1;
+ ctx_ctrl->val = buf_ctrl->val;
+
+ buf_ctrl->has_new = 0;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void mfc_enc_set_buf_ctrls_temporal_svc(struct s5p_mfc_ctx *ctx,
+ struct s5p_mfc_buf_ctrl *buf_ctrl)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ unsigned int value = 0, value2 = 0;
+ struct temporal_layer_info temporal_LC;
+ unsigned int i;
+ struct s5p_mfc_enc_params *p = &enc->params;
+
+ if (buf_ctrl->id
+ == V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_CH ||
+ buf_ctrl->id
+ == V4L2_CID_MPEG_VIDEO_VP8_HIERARCHICAL_CODING_LAYER_CH ||
+ buf_ctrl->id
+ == V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER_CH ||
+ buf_ctrl->id
+ == V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_CH) {
+ memcpy(&temporal_LC,
+ enc->sh_handle_svc.vaddr, sizeof(struct temporal_layer_info));
+
+ if(((temporal_LC.temporal_layer_count & 0x7) < 1) ||
+ ((temporal_LC.temporal_layer_count > 3) && IS_VP8_ENC(ctx)) ||
+ ((temporal_LC.temporal_layer_count > 3) && IS_VP9_ENC(ctx))) {
+ /* clear NUM_T_LAYER_CHANGE */
+ value = MFC_READL(buf_ctrl->flag_addr);
+ value &= ~(1 << 10);
+ MFC_WRITEL(value, buf_ctrl->flag_addr);
+ mfc_err_ctx("[HIERARCHICAL] layer count is invalid : %d\n",
+ temporal_LC.temporal_layer_count);
+ return;
+ }
+
+ if (IS_H264_ENC(ctx))
+ p->codec.h264.num_hier_layer = temporal_LC.temporal_layer_count & 0x7;
+
+ /* enable RC_BIT_RATE_CHANGE */
+ value = MFC_READL(buf_ctrl->flag_addr);
+ if (temporal_LC.temporal_layer_bitrate[0] > 0 || p->hier_bitrate_ctrl)
+ /* set RC_BIT_RATE_CHANGE */
+ value |= (1 << 2);
+ else
+ /* clear RC_BIT_RATE_CHANGE */
+ value &= ~(1 << 2);
+ MFC_WRITEL(value, buf_ctrl->flag_addr);
+
+ mfc_debug(3, "[HIERARCHICAL] layer count %d, E_PARAM_CHANGE %#x\n",
+ temporal_LC.temporal_layer_count & 0x7, value);
+
+ value = MFC_READL(S5P_FIMV_E_NUM_T_LAYER);
+ buf_ctrl->old_val2 = value;
+ value &= ~(0x7);
+ value |= (temporal_LC.temporal_layer_count & 0x7);
+ value &= ~(0x1 << 8);
+ value |= (p->hier_bitrate_ctrl & 0x1) << 8;
+ MFC_WRITEL(value, S5P_FIMV_E_NUM_T_LAYER);
+ mfc_debug(3, "[HIERARCHICAL] E_NUM_T_LAYER %#x\n", value);
+ for (i = 0; i < (temporal_LC.temporal_layer_count & 0x7); i++) {
+ mfc_debug(3, "[HIERARCHICAL] layer bitrate[%d] %d (FW ctrl: %d)\n",
+ i, temporal_LC.temporal_layer_bitrate[i], p->hier_bitrate_ctrl);
+ MFC_WRITEL(temporal_LC.temporal_layer_bitrate[i],
+ buf_ctrl->addr + i * 4);
+ }
+ /* priority change */
+ if (IS_H264_ENC(ctx)) {
+ value = 0;
+ value2 = 0;
+ for (i = 0; i < (p->codec.h264.num_hier_layer & 0x07); i++) {
+ if (i <= 4)
+ value |= ((p->codec.h264.base_priority & 0x3F) + i)
+ << (6 * i);
+ else
+ value2 |= ((p->codec.h264.base_priority & 0x3F) + i)
+ << (6 * (i - 5));
+ }
+ MFC_WRITEL(value, S5P_FIMV_E_H264_HD_SVC_EXTENSION_0);
+ MFC_WRITEL(value2, S5P_FIMV_E_H264_HD_SVC_EXTENSION_1);
+ mfc_debug(3, "[HIERARCHICAL] EXTENSION0 %#x, EXTENSION1 %#x\n",
+ value, value2);
+
+ value = MFC_READL(buf_ctrl->flag_addr);
+ value |= (1 << 12);
+ MFC_WRITEL(value, buf_ctrl->flag_addr);
+ mfc_debug(3, "[HIERARCHICAL] E_PARAM_CHANGE %#x\n", value);
+ }
+
+ }
+
+ /* temproral layer priority */
+ if (buf_ctrl->id == V4L2_CID_MPEG_MFC_H264_BASE_PRIORITY) {
+ value = MFC_READL(S5P_FIMV_E_H264_HD_SVC_EXTENSION_0);
+ buf_ctrl->old_val |= value & 0x3FFFFFC0;
+ value &= ~(0x3FFFFFC0);
+ value2 = MFC_READL(S5P_FIMV_E_H264_HD_SVC_EXTENSION_1);
+ buf_ctrl->old_val2 = value2 & 0x0FFF;
+ value2 &= ~(0x0FFF);
+ for (i = 0; i < (p->codec.h264.num_hier_layer & 0x07); i++) {
+ if (i <= 4)
+ value |= ((buf_ctrl->val & 0x3F) + i) << (6 * i);
+ else
+ value2 |= ((buf_ctrl->val & 0x3F) + i) << (6 * (i - 5));
+ }
+ MFC_WRITEL(value, S5P_FIMV_E_H264_HD_SVC_EXTENSION_0);
+ MFC_WRITEL(value2, S5P_FIMV_E_H264_HD_SVC_EXTENSION_1);
+ p->codec.h264.base_priority = buf_ctrl->val;
+ mfc_debug(3, "[HIERARCHICAL] EXTENSION0 %#x, EXTENSION1 %#x\n",
+ value, value2);
+ }
+}
+
+static void mfc_enc_set_buf_ctrls_exception(struct s5p_mfc_ctx *ctx,
+ struct s5p_mfc_buf_ctrl *buf_ctrl)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_enc_params *p = &enc->params;
+ unsigned int value = 0;
+
+ if (buf_ctrl->id == V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG)
+ enc->stored_tag = buf_ctrl->val;
+
+ /* temporal layer setting */
+ mfc_enc_set_buf_ctrls_temporal_svc(ctx, buf_ctrl);
+
+ if (buf_ctrl->id == V4L2_CID_MPEG_MFC_H264_MARK_LTR) {
+ value = MFC_READL(S5P_FIMV_E_H264_NAL_CONTROL);
+ buf_ctrl->old_val2 = (value >> 8) & 0x7;
+ value &= ~(0x7 << 8);
+ value |= (buf_ctrl->val & 0x7) << 8;
+ MFC_WRITEL(value, S5P_FIMV_E_H264_NAL_CONTROL);
+ }
+ if (buf_ctrl->id == V4L2_CID_MPEG_MFC_H264_USE_LTR) {
+ value = MFC_READL(S5P_FIMV_E_H264_NAL_CONTROL);
+ buf_ctrl->old_val2 = (value >> 11) & 0xF;
+ value &= ~(0xF << 11);
+ value |= (buf_ctrl->val & 0xF) << 11;
+ MFC_WRITEL(value, S5P_FIMV_E_H264_NAL_CONTROL);
+ }
+
+ if (buf_ctrl->id == V4L2_CID_MPEG_MFC51_VIDEO_I_PERIOD_CH) {
+ value = MFC_READL(S5P_FIMV_E_GOP_CONFIG2);
+ buf_ctrl->old_val |= (value << 16) & 0x3FFF0000;
+ value &= ~(0x3FFF);
+ value |= (buf_ctrl->val >> 16) & 0x3FFF;
+ MFC_WRITEL(value, S5P_FIMV_E_GOP_CONFIG2);
+ }
+
+ /* PROFILE & LEVEL have to be set up together */
+ if (buf_ctrl->id == V4L2_CID_MPEG_VIDEO_H264_LEVEL) {
+ value = MFC_READL(S5P_FIMV_E_PICTURE_PROFILE);
+ buf_ctrl->old_val |= (value & 0x000F) << 8;
+ value &= ~(0x000F);
+ value |= p->codec.h264.profile & 0x000F;
+ MFC_WRITEL(value, S5P_FIMV_E_PICTURE_PROFILE);
+ p->codec.h264.level = buf_ctrl->val;
+ }
+
+ if (buf_ctrl->id == V4L2_CID_MPEG_VIDEO_H264_PROFILE) {
+ value = MFC_READL(S5P_FIMV_E_PICTURE_PROFILE);
+ buf_ctrl->old_val |= value & 0xFF00;
+ value &= ~(0x00FF << 8);
+ value |= (p->codec.h264.level << 8) & 0xFF00;
+ MFC_WRITEL(value, S5P_FIMV_E_PICTURE_PROFILE);
+ p->codec.h264.profile = buf_ctrl->val;
+ }
+
+ /* per buffer QP setting change */
+ if (buf_ctrl->id == V4L2_CID_MPEG_MFC_CONFIG_QP)
+ p->config_qp = buf_ctrl->val;
+
+ /* set the ROI buffer DVA */
+ if (buf_ctrl->id == V4L2_CID_MPEG_VIDEO_ROI_CONTROL) {
+ MFC_WRITEL(enc->roi_buf[buf_ctrl->old_val2].daddr,
+ S5P_FIMV_E_ROI_BUFFER_ADDR);
+ mfc_debug(3, "[ROI] buffer[%d] addr %#llx, QP val: %#x\n",
+ buf_ctrl->old_val2,
+ enc->roi_buf[buf_ctrl->old_val2].daddr,
+ buf_ctrl->val);
+ }
+}
+
+static int s5p_mfc_enc_set_buf_ctrls_val(struct s5p_mfc_ctx *ctx, struct list_head *head)
+{
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ unsigned int value = 0;
+ struct s5p_mfc_enc_params *p = &enc->params;
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if (!(buf_ctrl->type & MFC_CTRL_TYPE_SET) || !buf_ctrl->has_new)
+ continue;
+
+ /* read old vlaue */
+ value = MFC_READL(buf_ctrl->addr);
+
+ /* save old value for recovery */
+ if (buf_ctrl->is_volatile)
+ buf_ctrl->old_val = (value >> buf_ctrl->shft) & buf_ctrl->mask;
+
+ /* write new value */
+ value &= ~(buf_ctrl->mask << buf_ctrl->shft);
+ value |= ((buf_ctrl->val & buf_ctrl->mask) << buf_ctrl->shft);
+ MFC_WRITEL(value, buf_ctrl->addr);
+
+ /* set change flag bit */
+ if (buf_ctrl->flag_mode == MFC_CTRL_MODE_SFR) {
+ value = MFC_READL(buf_ctrl->flag_addr);
+ value |= (1 << buf_ctrl->flag_shft);
+ MFC_WRITEL(value, buf_ctrl->flag_addr);
+ }
+
+ buf_ctrl->has_new = 0;
+ buf_ctrl->updated = 1;
+
+ mfc_enc_set_buf_ctrls_exception(ctx, buf_ctrl);
+
+ mfc_debug(6, "[CTRLS] Set buffer control id: 0x%08x, val: %d\n",
+ buf_ctrl->id, buf_ctrl->val);
+ }
+
+ if (!p->rc_frame && !p->rc_mb && p->dynamic_qp) {
+ value = MFC_READL(S5P_FIMV_E_FIXED_PICTURE_QP);
+ value &= ~(0xFF000000);
+ value |= (p->config_qp & 0xFF) << 24;
+ MFC_WRITEL(value, S5P_FIMV_E_FIXED_PICTURE_QP);
+ mfc_debug(6, "[CTRLS] Dynamic QP changed %#x\n",
+ MFC_READL(S5P_FIMV_E_FIXED_PICTURE_QP));
+ }
+
+ return 0;
+}
+
+static int s5p_mfc_enc_get_buf_ctrls_val(struct s5p_mfc_ctx *ctx, struct list_head *head)
+{
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+ struct s5p_mfc_dev *dev = ctx->dev;
+ unsigned int value = 0;
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if (!(buf_ctrl->type & MFC_CTRL_TYPE_GET))
+ continue;
+
+ if (buf_ctrl->mode == MFC_CTRL_MODE_SFR)
+ value = MFC_READL(buf_ctrl->addr);
+ else if (buf_ctrl->mode == MFC_CTRL_MODE_CST)
+ value = call_bop(buf_ctrl, read_cst, ctx, buf_ctrl);
+
+ value = (value >> buf_ctrl->shft) & buf_ctrl->mask;
+
+ buf_ctrl->val = value;
+ buf_ctrl->has_new = 1;
+
+ mfc_debug(6, "[CTRLS] Get buffer control id: 0x%08x, val: %d\n",
+ buf_ctrl->id, buf_ctrl->val);
+ }
+
+ return 0;
+}
+
+static int s5p_mfc_enc_set_buf_ctrls_val_nal_q_enc(struct s5p_mfc_ctx *ctx,
+ struct list_head *head, EncoderInputStr *pInStr)
+{
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct temporal_layer_info temporal_LC;
+ unsigned int i, param_change;
+ struct s5p_mfc_enc_params *p = &enc->params;
+
+ mfc_debug_enter();
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if (!(buf_ctrl->type & MFC_CTRL_TYPE_SET) || !buf_ctrl->has_new)
+ continue;
+ param_change = 0;
+ switch (buf_ctrl->id) {
+ case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG:
+ pInStr->PictureTag &= ~(buf_ctrl->mask << buf_ctrl->shft);
+ pInStr->PictureTag |=
+ (buf_ctrl->val & buf_ctrl->mask) << buf_ctrl->shft;
+ enc->stored_tag = buf_ctrl->val;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE:
+ pInStr->FrameInsertion &= ~(buf_ctrl->mask << buf_ctrl->shft);
+ pInStr->FrameInsertion |=
+ (buf_ctrl->val & buf_ctrl->mask) << buf_ctrl->shft;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_I_PERIOD_CH:
+ pInStr->GopConfig &= ~(buf_ctrl->mask << buf_ctrl->shft);
+ pInStr->GopConfig |=
+ (buf_ctrl->val & buf_ctrl->mask) << buf_ctrl->shft;
+ pInStr->GopConfig2 &= ~(0x3FFF);
+ pInStr->GopConfig2 |= (buf_ctrl->val >> 16) & 0x3FFF;
+ param_change = 1;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_RATE_CH:
+ pInStr->RcFrameRate &= ~(buf_ctrl->mask << buf_ctrl->shft);
+ pInStr->RcFrameRate |=
+ (buf_ctrl->val & buf_ctrl->mask) << buf_ctrl->shft;
+ param_change = 1;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_BIT_RATE_CH:
+ pInStr->RcBitRate &= ~(buf_ctrl->mask << buf_ctrl->shft);
+ pInStr->RcBitRate |=
+ (buf_ctrl->val & buf_ctrl->mask) << buf_ctrl->shft;
+ param_change = 1;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
+ case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP:
+ case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP:
+ case V4L2_CID_MPEG_VIDEO_H263_MAX_QP:
+ case V4L2_CID_MPEG_VIDEO_VP8_MAX_QP:
+ case V4L2_CID_MPEG_VIDEO_VP9_MAX_QP:
+ case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
+ case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP:
+ case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP:
+ case V4L2_CID_MPEG_VIDEO_H263_MIN_QP:
+ case V4L2_CID_MPEG_VIDEO_VP8_MIN_QP:
+ case V4L2_CID_MPEG_VIDEO_VP9_MIN_QP:
+ pInStr->RcQpBound &= ~(buf_ctrl->mask << buf_ctrl->shft);
+ pInStr->RcQpBound |=
+ (buf_ctrl->val & buf_ctrl->mask) << buf_ctrl->shft;
+ param_change = 1;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_MAX_QP_P:
+ case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP_P:
+ case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP_P:
+ case V4L2_CID_MPEG_VIDEO_H263_MAX_QP_P:
+ case V4L2_CID_MPEG_VIDEO_VP8_MAX_QP_P:
+ case V4L2_CID_MPEG_VIDEO_VP9_MAX_QP_P:
+ case V4L2_CID_MPEG_VIDEO_H264_MIN_QP_P:
+ case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP_P:
+ case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP_P:
+ case V4L2_CID_MPEG_VIDEO_H263_MIN_QP_P:
+ case V4L2_CID_MPEG_VIDEO_VP8_MIN_QP_P:
+ case V4L2_CID_MPEG_VIDEO_VP9_MIN_QP_P:
+ case V4L2_CID_MPEG_VIDEO_H264_MAX_QP_B:
+ case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP_B:
+ case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP_B:
+ case V4L2_CID_MPEG_VIDEO_H264_MIN_QP_B:
+ case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP_B:
+ case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP_B:
+ pInStr->RcQpBoundPb &= ~(buf_ctrl->mask << buf_ctrl->shft);
+ pInStr->RcQpBoundPb |=
+ (buf_ctrl->val & buf_ctrl->mask) << buf_ctrl->shft;
+ param_change = 1;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_CH:
+ case V4L2_CID_MPEG_VIDEO_VP8_HIERARCHICAL_CODING_LAYER_CH:
+ case V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER_CH:
+ case V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_CH:
+ memcpy(&temporal_LC,
+ enc->sh_handle_svc.vaddr, sizeof(struct temporal_layer_info));
+
+ if (((temporal_LC.temporal_layer_count & 0x7) < 1) ||
+ ((temporal_LC.temporal_layer_count > 3) && IS_VP8_ENC(ctx)) ||
+ ((temporal_LC.temporal_layer_count > 3) && IS_VP9_ENC(ctx))) {
+ /* claer NUM_T_LAYER_CHANGE */
+ mfc_err_ctx("[NALQ][HIERARCHICAL] layer count(%d) is invalid\n",
+ temporal_LC.temporal_layer_count);
+ return 0;
+ }
+
+ if (IS_H264_ENC(ctx))
+ p->codec.h264.num_hier_layer =
+ temporal_LC.temporal_layer_count & 0x7;
+
+ /* enable RC_BIT_RATE_CHANGE */
+ if (temporal_LC.temporal_layer_bitrate[0] > 0 || p->hier_bitrate_ctrl)
+ pInStr->ParamChange |= (1 << 2);
+ else
+ pInStr->ParamChange &= ~(1 << 2);
+
+ /* enalbe NUM_T_LAYER_CHANGE */
+ if (temporal_LC.temporal_layer_count & 0x7)
+ pInStr->ParamChange |= (1 << 10);
+ else
+ pInStr->ParamChange &= ~(1 << 10);
+ mfc_debug(3, "[NALQ][HIERARCHICAL] layer count %d\n",
+ temporal_LC.temporal_layer_count & 0x7);
+
+ pInStr->NumTLayer &= ~(0x7);
+ pInStr->NumTLayer |= (temporal_LC.temporal_layer_count & 0x7);
+ pInStr->NumTLayer &= ~(0x1 << 8);
+ pInStr->NumTLayer |= (p->hier_bitrate_ctrl & 0x1) << 8;
+ for (i = 0; i < (temporal_LC.temporal_layer_count & 0x7); i++) {
+ mfc_debug(3, "[NALQ][HIERARCHICAL] layer bitrate[%d] %d (FW ctrl: %d)\n",
+ i, temporal_LC.temporal_layer_bitrate[i], p->hier_bitrate_ctrl);
+ pInStr->HierarchicalBitRateLayer[i] =
+ temporal_LC.temporal_layer_bitrate[i];
+ }
+
+ /* priority change */
+ if (IS_H264_ENC(ctx)) {
+ for (i = 0; i < (temporal_LC.temporal_layer_count & 0x7); i++) {
+ if (i <= 4)
+ pInStr->H264HDSvcExtension0 |=
+ ((p->codec.h264.base_priority & 0x3f) + i) << (6 * i);
+ else
+ pInStr->H264HDSvcExtension1 |=
+ ((p->codec.h264.base_priority & 0x3f) + i) << (6 * (i - 5));
+ }
+ mfc_debug(3, "[NALQ][HIERARCHICAL] EXTENSION0 %#x, EXTENSION1 %#x\n",
+ pInStr->H264HDSvcExtension0, pInStr->H264HDSvcExtension1);
+
+ pInStr->ParamChange |= (1 << 12);
+ }
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+ pInStr->PictureProfile &= ~(buf_ctrl->mask << buf_ctrl->shft);
+ pInStr->PictureProfile |=
+ (buf_ctrl->val & buf_ctrl->mask) << buf_ctrl->shft;
+ pInStr->PictureProfile &= ~(0xf);
+ pInStr->PictureProfile |= p->codec.h264.profile & 0xf;
+ p->codec.h264.level = buf_ctrl->val;
+ param_change = 1;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+ pInStr->PictureProfile &= ~(buf_ctrl->mask << buf_ctrl->shft);
+ pInStr->PictureProfile |=
+ (buf_ctrl->val & buf_ctrl->mask) << buf_ctrl->shft;
+ pInStr->PictureProfile &= ~(0xff << 8);
+ pInStr->PictureProfile |= (p->codec.h264.level << 8) & 0xff00;
+ p->codec.h264.profile = buf_ctrl->val;
+ param_change = 1;
+ break;
+ case V4L2_CID_MPEG_MFC_H264_MARK_LTR:
+ pInStr->H264NalControl &= ~(buf_ctrl->mask << buf_ctrl->shft);
+ pInStr->H264NalControl |=
+ (buf_ctrl->val & buf_ctrl->mask) << buf_ctrl->shft;
+ pInStr->H264NalControl &= ~(0x7 << 8);
+ pInStr->H264NalControl |= (buf_ctrl->val & 0x7) << 8;
+ break;
+ case V4L2_CID_MPEG_MFC_H264_USE_LTR:
+ pInStr->H264NalControl &= ~(buf_ctrl->mask << buf_ctrl->shft);
+ pInStr->H264NalControl |=
+ (buf_ctrl->val & buf_ctrl->mask) << buf_ctrl->shft;
+ pInStr->H264NalControl &= ~(0xF << 11);
+ pInStr->H264NalControl |= (buf_ctrl->val & 0xF) << 11;
+ break;
+ case V4L2_CID_MPEG_MFC_H264_BASE_PRIORITY:
+ for (i = 0; i < (p->codec.h264.num_hier_layer & 0x7); i++)
+ if (i <= 4)
+ pInStr->H264HDSvcExtension0 |=
+ ((buf_ctrl->val & 0x3f) + i) << (6 * i);
+ else
+ pInStr->H264HDSvcExtension1 |=
+ ((buf_ctrl->val & 0x3f) + i) << (6 * (i - 5));
+ p->codec.h264.base_priority = buf_ctrl->val;
+ param_change = 1;
+ break;
+ case V4L2_CID_MPEG_MFC_CONFIG_QP:
+ pInStr->FixedPictureQp &= ~(buf_ctrl->mask << buf_ctrl->shft);
+ pInStr->FixedPictureQp |=
+ (buf_ctrl->val & buf_ctrl->mask) << buf_ctrl->shft;
+ p->config_qp = buf_ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_ROI_CONTROL:
+ pInStr->RcRoiCtrl &= ~(buf_ctrl->mask << buf_ctrl->shft);
+ pInStr->RcRoiCtrl |=
+ (buf_ctrl->val & buf_ctrl->mask) << buf_ctrl->shft;
+ pInStr->RoiBufferAddr = enc->roi_buf[buf_ctrl->old_val2].daddr;
+ mfc_debug(3, "[NALQ][ROI] buffer[%d] addr %#llx, QP val: %#x\n",
+ buf_ctrl->old_val2,
+ enc->roi_buf[buf_ctrl->old_val2].daddr,
+ buf_ctrl->val);
+ break;
+ case V4L2_CID_MPEG_VIDEO_YSUM:
+ pInStr->Weight &= ~(buf_ctrl->mask << buf_ctrl->shft);
+ pInStr->Weight |=
+ (buf_ctrl->val & buf_ctrl->mask) << buf_ctrl->shft;
+ break;
+ case V4L2_CID_MPEG_VIDEO_RATIO_OF_INTRA:
+ pInStr->RcMode &= ~(buf_ctrl->mask << buf_ctrl->shft);
+ pInStr->RcMode |=
+ (buf_ctrl->val & buf_ctrl->mask) << buf_ctrl->shft;
+ param_change = 1;
+ break;
+ /* If new dynamic controls are added, insert here */
+ default:
+ mfc_info_ctx("[NALQ] can't find control, id: 0x%x\n",
+ buf_ctrl->id);
+ }
+
+ if (param_change)
+ pInStr->ParamChange |= (1 << buf_ctrl->flag_shft);
+
+ buf_ctrl->has_new = 0;
+ buf_ctrl->updated = 1;
+
+ mfc_debug(6, "[NALQ][CTRLS] Set buffer control id: 0x%08x, val: %d\n",
+ buf_ctrl->id, buf_ctrl->val);
+ }
+
+ if (!p->rc_frame && !p->rc_mb && p->dynamic_qp) {
+ pInStr->FixedPictureQp &= ~(0xFF000000);
+ pInStr->FixedPictureQp |= (p->config_qp & 0xFF) << 24;
+ mfc_debug(6, "[NALQ][CTRLS] Dynamic QP changed %#x\n",
+ pInStr->FixedPictureQp);
+ }
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+static int s5p_mfc_enc_get_buf_ctrls_val_nal_q_enc(struct s5p_mfc_ctx *ctx,
+ struct list_head *head, EncoderOutputStr *pOutStr)
+{
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ unsigned int value = 0;
+
+ mfc_debug_enter();
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if (!(buf_ctrl->type & MFC_CTRL_TYPE_GET))
+ continue;
+ switch (buf_ctrl->id) {
+ case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG:
+ value = pOutStr->PictureTag;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_LUMA_ADDR:
+ value = pOutStr->EncodedFrameAddr[0];
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_CHROMA_ADDR:
+ value = pOutStr->EncodedFrameAddr[1];
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_STATUS:
+ value = !enc->in_slice;
+ break;
+ /* If new dynamic controls are added, insert here */
+ default:
+ mfc_info_ctx("[NALQ] can't find control, id: 0x%x\n",
+ buf_ctrl->id);
+ }
+ value = (value >> buf_ctrl->shft) & buf_ctrl->mask;
+
+ buf_ctrl->val = value;
+ buf_ctrl->has_new = 1;
+
+ mfc_debug(6, "[NALQ][CTRLS] Get buffer control id: 0x%08x, val: %d\n",
+ buf_ctrl->id, buf_ctrl->val);
+ }
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+static int s5p_mfc_enc_recover_buf_ctrls_val(struct s5p_mfc_ctx *ctx,
+ struct list_head *head)
+{
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+ struct s5p_mfc_dev *dev = ctx->dev;
+ unsigned int value = 0;
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if (!(buf_ctrl->type & MFC_CTRL_TYPE_SET)
+ || !buf_ctrl->is_volatile
+ || !buf_ctrl->updated)
+ continue;
+
+ if (buf_ctrl->mode == MFC_CTRL_MODE_SFR)
+ value = MFC_READL(buf_ctrl->addr);
+
+ value &= ~(buf_ctrl->mask << buf_ctrl->shft);
+ value |= ((buf_ctrl->old_val & buf_ctrl->mask)
+ << buf_ctrl->shft);
+
+ if (buf_ctrl->mode == MFC_CTRL_MODE_SFR)
+ MFC_WRITEL(value, buf_ctrl->addr);
+
+ /* clear change flag bit */
+ if (buf_ctrl->flag_mode == MFC_CTRL_MODE_SFR) {
+ value = MFC_READL(buf_ctrl->flag_addr);
+ value &= ~(1 << buf_ctrl->flag_shft);
+ MFC_WRITEL(value, buf_ctrl->flag_addr);
+ }
+
+ mfc_debug(6, "[CTRLS] Recover buffer control id: 0x%08x, old val: %d\n",
+ buf_ctrl->id, buf_ctrl->old_val);
+
+ if (buf_ctrl->id == V4L2_CID_MPEG_MFC51_VIDEO_I_PERIOD_CH) {
+ value = MFC_READL(S5P_FIMV_E_GOP_CONFIG2);
+ value &= ~(0x3FFF);
+ value |= (buf_ctrl->old_val >> 16) & 0x3FFF;
+ MFC_WRITEL(value, S5P_FIMV_E_GOP_CONFIG2);
+ }
+ if (buf_ctrl->id == V4L2_CID_MPEG_VIDEO_H264_LEVEL) {
+ value = MFC_READL(S5P_FIMV_E_PICTURE_PROFILE);
+ value &= ~(0x000F);
+ value |= (buf_ctrl->old_val >> 8) & 0x000F;
+ MFC_WRITEL(value, S5P_FIMV_E_PICTURE_PROFILE);
+ }
+ if (buf_ctrl->id == V4L2_CID_MPEG_VIDEO_H264_PROFILE) {
+ value = MFC_READL(S5P_FIMV_E_PICTURE_PROFILE);
+ value &= ~(0xFF00);
+ value |= buf_ctrl->old_val & 0xFF00;
+ MFC_WRITEL(value, S5P_FIMV_E_PICTURE_PROFILE);
+ }
+ if (buf_ctrl->id == V4L2_CID_MPEG_MFC_H264_BASE_PRIORITY) {
+ MFC_WRITEL(buf_ctrl->old_val, S5P_FIMV_E_H264_HD_SVC_EXTENSION_0);
+ MFC_WRITEL(buf_ctrl->old_val2, S5P_FIMV_E_H264_HD_SVC_EXTENSION_1);
+ }
+ if (buf_ctrl->id
+ == V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_CH ||
+ buf_ctrl->id
+ == V4L2_CID_MPEG_VIDEO_VP8_HIERARCHICAL_CODING_LAYER_CH ||
+ buf_ctrl->id
+ == V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_CH) {
+ MFC_WRITEL(buf_ctrl->old_val2, S5P_FIMV_E_NUM_T_LAYER);
+ /* clear RC_BIT_RATE_CHANGE */
+ value = MFC_READL(buf_ctrl->flag_addr);
+ value &= ~(1 << 2);
+ MFC_WRITEL(value, buf_ctrl->flag_addr);
+ }
+ if (buf_ctrl->id == V4L2_CID_MPEG_MFC_H264_MARK_LTR) {
+ value = MFC_READL(S5P_FIMV_E_H264_NAL_CONTROL);
+ value &= ~(0x7 << 8);
+ value |= (buf_ctrl->old_val2 & 0x7) << 8;
+ MFC_WRITEL(value, S5P_FIMV_E_H264_NAL_CONTROL);
+ }
+ if (buf_ctrl->id == V4L2_CID_MPEG_MFC_H264_USE_LTR) {
+ value = MFC_READL(S5P_FIMV_E_H264_NAL_CONTROL);
+ value &= ~(0xF << 11);
+ value |= (buf_ctrl->old_val2 & 0xF) << 11;
+ MFC_WRITEL(value, S5P_FIMV_E_H264_NAL_CONTROL);
+ }
+ buf_ctrl->updated = 0;
+ }
+
+ return 0;
+}
+
+static int s5p_mfc_enc_recover_buf_ctrls_nal_q(struct s5p_mfc_ctx *ctx,
+ struct list_head *head)
+{
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if (!(buf_ctrl->type & MFC_CTRL_TYPE_SET)
+ || !(buf_ctrl->updated))
+ continue;
+
+ buf_ctrl->has_new = 1;
+ buf_ctrl->updated = 0;
+
+ mfc_debug(6, "[NALQ][CTRLS] Recover buffer control id: 0x%08x, val: %d\n",
+ buf_ctrl->id, buf_ctrl->val);
+ }
+
+ return 0;
+}
+
+struct s5p_mfc_ctrls_ops encoder_ctrls_ops = {
+ .init_ctx_ctrls = s5p_mfc_enc_init_ctx_ctrls,
+ .cleanup_ctx_ctrls = s5p_mfc_enc_cleanup_ctx_ctrls,
+ .init_buf_ctrls = s5p_mfc_enc_init_buf_ctrls,
+ .reset_buf_ctrls = s5p_mfc_enc_reset_buf_ctrls,
+ .cleanup_buf_ctrls = s5p_mfc_enc_cleanup_buf_ctrls,
+ .to_buf_ctrls = s5p_mfc_enc_to_buf_ctrls,
+ .to_ctx_ctrls = s5p_mfc_enc_to_ctx_ctrls,
+ .set_buf_ctrls_val = s5p_mfc_enc_set_buf_ctrls_val,
+ .get_buf_ctrls_val = s5p_mfc_enc_get_buf_ctrls_val,
+ .recover_buf_ctrls_val = s5p_mfc_enc_recover_buf_ctrls_val,
+ .get_buf_update_val = s5p_mfc_enc_get_buf_update_val,
+ .set_buf_ctrls_val_nal_q_enc = s5p_mfc_enc_set_buf_ctrls_val_nal_q_enc,
+ .get_buf_ctrls_val_nal_q_enc = s5p_mfc_enc_get_buf_ctrls_val_nal_q_enc,
+ .recover_buf_ctrls_nal_q = s5p_mfc_enc_recover_buf_ctrls_nal_q,
+};
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_enc_param.c
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "mfc_enc_param.h"
+
+#include "mfc_reg.h"
+
+/* Definition */
+#define FRAME_DELTA_DEFAULT 1
+#define CBR_FIX_MAX 10
+#define CBR_I_LIMIT_MAX 5
+#define BPG_EXTENSION_TAG_SIZE 5
+
+void s5p_mfc_set_slice_mode(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+
+ /* multi-slice control */
+ if (enc->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES)
+ MFC_WRITEL((enc->slice_mode + 0x4), S5P_FIMV_E_MSLICE_MODE);
+ else if (enc->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB_ROW)
+ MFC_WRITEL((enc->slice_mode - 0x2), S5P_FIMV_E_MSLICE_MODE);
+ else if (enc->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_FIXED_BYTES)
+ MFC_WRITEL((enc->slice_mode + 0x3), S5P_FIMV_E_MSLICE_MODE);
+ else
+ MFC_WRITEL(enc->slice_mode, S5P_FIMV_E_MSLICE_MODE);
+
+ /* multi-slice MB number or bit size */
+ if ((enc->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) ||
+ (enc->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB_ROW)) {
+ MFC_WRITEL(enc->slice_size.mb, S5P_FIMV_E_MSLICE_SIZE_MB);
+ } else if ((enc->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) ||
+ (enc->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_FIXED_BYTES)){
+ MFC_WRITEL(enc->slice_size.bits, S5P_FIMV_E_MSLICE_SIZE_BITS);
+ } else {
+ MFC_WRITEL(0x0, S5P_FIMV_E_MSLICE_SIZE_MB);
+ MFC_WRITEL(0x0, S5P_FIMV_E_MSLICE_SIZE_BITS);
+ }
+}
+
+static void mfc_set_gop_size(struct s5p_mfc_ctx *ctx, int ctrl_mode)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_enc_params *p = &enc->params;
+ unsigned int reg = 0;
+
+ if (ctrl_mode) {
+ p->i_frm_ctrl_mode = 1;
+ p->i_frm_ctrl = p->gop_size * (p->num_b_frame + 1);
+ if (p->i_frm_ctrl >= 0x3FFFFFFF) {
+ mfc_info_ctx("I frame interval is bigger than max: %d\n",
+ p->i_frm_ctrl);
+ p->i_frm_ctrl = 0x3FFFFFFF;
+ }
+ } else {
+ p->i_frm_ctrl_mode = 0;
+ p->i_frm_ctrl = p->gop_size;
+ }
+
+ mfc_debug(2, "I frame interval: %d, (P: %d, B: %d), ctrl mode: %d\n",
+ p->i_frm_ctrl, p->gop_size,
+ p->num_b_frame, p->i_frm_ctrl_mode);
+
+ /* pictype : IDR period, number of B */
+ reg = MFC_READL(S5P_FIMV_E_GOP_CONFIG);
+ reg &= ~(0xFFFF);
+ reg |= p->i_frm_ctrl & 0xFFFF;
+ reg &= ~(0x1 << 19);
+ reg |= p->i_frm_ctrl_mode << 19;
+ reg &= ~(0x3 << 16);
+ /* if B frame is used, the performance falls by half */
+ reg |= (p->num_b_frame << 16);
+ MFC_WRITEL(reg, S5P_FIMV_E_GOP_CONFIG);
+
+ reg = MFC_READL(S5P_FIMV_E_GOP_CONFIG2);
+ reg &= ~(0x3FFF);
+ reg |= (p->i_frm_ctrl >> 16) & 0x3FFF;
+ MFC_WRITEL(reg, S5P_FIMV_E_GOP_CONFIG2);
+}
+
+static void mfc_set_default_params(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ int i;
+
+ mfc_debug(2, "Set default param - enc_param_num: %d\n", dev->pdata->enc_param_num);
+ for (i = 0; i < dev->pdata->enc_param_num; i++) {
+ if (i >= MFC_MAX_DEFAULT_PARAM) {
+ mfc_err_dev("enc_param_num(%d) is over max number(%d)\n",
+ dev->pdata->enc_param_num, MFC_MAX_DEFAULT_PARAM);
+ break;
+ }
+ MFC_WRITEL(dev->pdata->enc_param_val[i], dev->pdata->enc_param_addr[i]);
+ mfc_debug(2, "Set default param[%d] - addr:0x%x, val:0x%x\n",
+ i, dev->pdata->enc_param_addr[i], dev->pdata->enc_param_val[i]);
+ }
+}
+
+static void mfc_init_regs(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ /* Register initialization */
+ MFC_WRITEL(0x0, S5P_FIMV_E_FRAME_INSERTION);
+ MFC_WRITEL(0x0, S5P_FIMV_E_ROI_BUFFER_ADDR);
+ MFC_WRITEL(0x0, S5P_FIMV_E_PARAM_CHANGE);
+ MFC_WRITEL(0x0, S5P_FIMV_E_PICTURE_TAG);
+ MFC_WRITEL(0x0, S5P_FIMV_E_METADATA_BUFFER_ADDR);
+ MFC_WRITEL(0x0, S5P_FIMV_E_METADATA_BUFFER_SIZE);
+}
+
+static void mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_enc_params *p = &enc->params;
+ unsigned int reg = 0;
+
+ mfc_debug_enter();
+
+ mfc_init_regs(ctx);
+ mfc_set_default_params(ctx);
+
+ /* width */
+ MFC_WRITEL(ctx->crop_width, S5P_FIMV_E_CROPPED_FRAME_WIDTH);
+ /* height */
+ MFC_WRITEL(ctx->crop_height, S5P_FIMV_E_CROPPED_FRAME_HEIGHT);
+ /* cropped offset */
+ reg |= (ctx->crop_left & S5P_FIMV_E_FRAME_CROP_OFFSET_MASK)
+ << S5P_FIMV_E_FRAME_CROP_OFFSET_LEFT;
+ reg |= (ctx->crop_top & S5P_FIMV_E_FRAME_CROP_OFFSET_MASK)
+ << S5P_FIMV_E_FRAME_CROP_OFFSET_TOP;
+ MFC_WRITEL(reg, S5P_FIMV_E_FRAME_CROP_OFFSET);
+
+ /* multi-slice control */
+ /* multi-slice MB number or bit size */
+ enc->slice_mode = p->slice_mode;
+
+ if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) {
+ enc->slice_size.mb = p->slice_mb;
+ } else if ((p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) ||
+ (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_FIXED_BYTES)){
+ enc->slice_size.bits = p->slice_bit;
+ } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB_ROW) {
+ enc->slice_size.mb = p->slice_mb_row * ((ctx->crop_width + 15) / 16);
+ } else {
+ enc->slice_size.mb = 0;
+ enc->slice_size.bits = 0;
+ }
+
+ s5p_mfc_set_slice_mode(ctx);
+
+ /* cyclic intra refresh */
+ MFC_WRITEL(p->intra_refresh_mb, S5P_FIMV_E_IR_SIZE);
+
+ reg = MFC_READL(S5P_FIMV_E_ENC_OPTIONS);
+ /* frame skip mode */
+ reg &= ~(0x3);
+ reg |= (p->frame_skip_mode & 0x3);
+ /* seq header ctrl */
+ reg &= ~(0x1 << 2);
+ reg |= ((p->seq_hdr_mode & 0x1) << 2);
+ /* cyclic intra refresh */
+ reg &= ~(0x1 << 4);
+ if (p->intra_refresh_mb)
+ reg |= (0x1 << 4);
+ /* disable seq header generation if OTF mode */
+ reg &= ~(0x1 << 6);
+ if (ctx->otf_handle) {
+ reg |= (0x1 << 6);
+ mfc_debug(2, "[OTF] SEQ_HEADER_GENERATION is disabled\n");
+ }
+ /* 'NON_REFERENCE_STORE_ENABLE' for debugging */
+ reg &= ~(0x1 << 9);
+ /* Disable parallel processing if nal_q_parallel_disable was set */
+ reg &= ~(0x1 << 18);
+ if (nal_q_parallel_disable)
+ reg |= (0x1 << 18);
+ MFC_WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS);
+
+ s5p_mfc_set_pixel_format(dev, ctx->src_fmt->fourcc);
+
+ /* padding control & value */
+ MFC_WRITEL(0x0, S5P_FIMV_E_PADDING_CTRL);
+ if (p->pad) {
+ reg = 0;
+ /** enable */
+ reg |= (1 << 31);
+ /** cr value */
+ reg &= ~(0xFF << 16);
+ reg |= (p->pad_cr << 16);
+ /** cb value */
+ reg &= ~(0xFF << 8);
+ reg |= (p->pad_cb << 8);
+ /** y value */
+ reg &= ~(0xFF);
+ reg |= (p->pad_luma);
+ MFC_WRITEL(reg, S5P_FIMV_E_PADDING_CTRL);
+ }
+
+ /* rate control config. */
+ reg = MFC_READL(S5P_FIMV_E_RC_CONFIG);
+ /* macroblock level rate control */
+ reg &= ~(0x1 << 8);
+ reg |= ((p->rc_mb & 0x1) << 8);
+ /* frame-level rate control */
+ reg &= ~(0x1 << 9);
+ reg |= ((p->rc_frame & 0x1) << 9);
+ /* 'DROP_CONTROL_ENABLE', disable */
+ reg &= ~(0x1 << 10);
+ MFC_WRITEL(reg, S5P_FIMV_E_RC_CONFIG);
+
+ /* bit rate */
+ MFC_WRITEL(p->rc_bitrate, S5P_FIMV_E_RC_BIT_RATE);
+
+
+ reg = MFC_READL(S5P_FIMV_E_RC_MODE);
+ reg &= ~(0x3 | (0x3 << 4) | (0xFF << 8));
+ if (p->rc_frame) {
+ if (p->rc_reaction_coeff <= CBR_I_LIMIT_MAX) {
+ reg |= S5P_FIMV_E_RC_CBR_I_LIMIT;
+ /*
+ * Ratio of intra for max frame size
+ * is controled when only CBR_I_LIMIT mode.
+ * And CBR_I_LIMIT mode is valid for H.264, HEVC codec
+ */
+ if (p->ratio_intra)
+ reg |= ((p->ratio_intra & 0xFF) << 8);
+ } else if (p->rc_reaction_coeff <= CBR_FIX_MAX) {
+ reg |= S5P_FIMV_E_RC_CBR_FIX;
+ } else {
+ reg |= S5P_FIMV_E_RC_VBR;
+ }
+
+ if (p->rc_mb)
+ reg |= ((p->rc_pvc & 0x3) << 4);
+ }
+ MFC_WRITEL(reg, S5P_FIMV_E_RC_MODE);
+
+ /* extended encoder ctrl */
+ /** vbv buffer size */
+ reg = MFC_READL(S5P_FIMV_E_VBV_BUFFER_SIZE);
+ reg &= ~(0xFF);
+ if (p->frame_skip_mode == V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT)
+ reg |= p->vbv_buf_size & 0xFF;
+ MFC_WRITEL(reg, S5P_FIMV_E_VBV_BUFFER_SIZE);
+
+ mfc_debug_leave();
+}
+
+static void mfc_set_temporal_svc_h264(struct s5p_mfc_ctx *ctx, struct s5p_mfc_h264_enc_params *p_264)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_enc_params *p = &enc->params;
+ unsigned int reg = 0, reg2 = 0;
+ int i;
+
+ reg = MFC_READL(S5P_FIMV_E_H264_OPTIONS_2);
+ /* pic_order_cnt_type = 0 for backward compatibilities */
+ reg &= ~(0x3);
+ /* Enable LTR */
+ reg &= ~(0x1 << 2);
+ if ((p_264->enable_ltr & 0x1) || (p_264->num_of_ltr > 0))
+ reg |= (0x1 << 2);
+ /* Number of LTR */
+ reg &= ~(0x3 << 7);
+ if (p_264->num_of_ltr > 2)
+ reg |= (((p_264->num_of_ltr - 2) & 0x3) << 7);
+ MFC_WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_2);
+
+ /* Temporal SVC - qp type, layer number */
+ reg = MFC_READL(S5P_FIMV_E_NUM_T_LAYER);
+ reg &= ~(0x1 << 3);
+ reg |= (p_264->hier_qp_type & 0x1) << 3;
+ reg &= ~(0x7);
+ reg |= p_264->num_hier_layer & 0x7;
+ reg &= ~(0x7 << 4);
+ if (p_264->hier_ref_type) {
+ reg |= 0x1 << 7;
+ reg |= (p->num_hier_max_layer & 0x7) << 4;
+ } else {
+ reg &= ~(0x1 << 7);
+ reg |= 0x7 << 4;
+ }
+ reg &= ~(0x1 << 8);
+ reg |= (p->hier_bitrate_ctrl & 0x1) << 8;
+ MFC_WRITEL(reg, S5P_FIMV_E_NUM_T_LAYER);
+ mfc_debug(3, "[HIERARCHICAL] hier_qp_enable %d, enable_ltr %d, "
+ "num_hier_layer %d, max_layer %d, hier_ref_type %d, NUM_T_LAYER 0x%x\n",
+ p_264->hier_qp_enable, p_264->enable_ltr, p_264->num_hier_layer,
+ p->num_hier_max_layer, p_264->hier_ref_type, reg);
+ /* QP & Bitrate for each layer */
+ for (i = 0; i < 7; i++) {
+ MFC_WRITEL(p_264->hier_qp_layer[i],
+ S5P_FIMV_E_HIERARCHICAL_QP_LAYER0 + i * 4);
+ /* If hier_bitrate_ctrl is set to 1, this is meaningless */
+ MFC_WRITEL(p_264->hier_bit_layer[i],
+ S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER0 + i * 4);
+ mfc_debug(3, "[HIERARCHICAL] layer[%d] QP: %#x, bitrate: %d(FW ctrl: %d)\n",
+ i, p_264->hier_qp_layer[i],
+ p_264->hier_bit_layer[i], p->hier_bitrate_ctrl);
+ }
+ if (p_264->set_priority) {
+ reg = 0;
+ reg2 = 0;
+ for (i = 0; i < (p_264->num_hier_layer & 0x7); i++) {
+ if (i <= 4)
+ reg |= ((p_264->base_priority & 0x3F) + i) << (6 * i);
+ else
+ reg2 |= ((p_264->base_priority & 0x3F) + i) << (6 * (i - 5));
+ }
+ MFC_WRITEL(reg, S5P_FIMV_E_H264_HD_SVC_EXTENSION_0);
+ MFC_WRITEL(reg2, S5P_FIMV_E_H264_HD_SVC_EXTENSION_1);
+ mfc_debug(3, "[HIERARCHICAL] priority EXTENSION0: %#x, EXTENSION1: %#x\n",
+ reg, reg2);
+ }
+}
+
+static void mfc_set_fmo_slice_map_h264(struct s5p_mfc_ctx *ctx, struct s5p_mfc_h264_enc_params *p_264)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ int i;
+
+ if (p_264->fmo_enable) {
+ switch (p_264->fmo_slice_map_type) {
+ case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_INTERLEAVED_SLICES:
+ if (p_264->fmo_slice_num_grp > 4)
+ p_264->fmo_slice_num_grp = 4;
+ for (i = 0; i < (p_264->fmo_slice_num_grp & 0xF); i++)
+ MFC_WRITEL(p_264->fmo_run_length[i] - 1,
+ S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_0 + i*4);
+ break;
+ case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_SCATTERED_SLICES:
+ if (p_264->fmo_slice_num_grp > 4)
+ p_264->fmo_slice_num_grp = 4;
+ break;
+ case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_RASTER_SCAN:
+ case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_WIPE_SCAN:
+ if (p_264->fmo_slice_num_grp > 2)
+ p_264->fmo_slice_num_grp = 2;
+ MFC_WRITEL(p_264->fmo_sg_dir & 0x1,
+ S5P_FIMV_E_H264_FMO_SLICE_GRP_CHANGE_DIR);
+ /* the valid range is 0 ~ number of macroblocks -1 */
+ MFC_WRITEL(p_264->fmo_sg_rate, S5P_FIMV_E_H264_FMO_SLICE_GRP_CHANGE_RATE_MINUS1);
+ break;
+ default:
+ mfc_err_ctx("Unsupported map type for FMO: %d\n",
+ p_264->fmo_slice_map_type);
+ p_264->fmo_slice_map_type = 0;
+ p_264->fmo_slice_num_grp = 1;
+ break;
+ }
+
+ MFC_WRITEL(p_264->fmo_slice_map_type, S5P_FIMV_E_H264_FMO_SLICE_GRP_MAP_TYPE);
+ MFC_WRITEL(p_264->fmo_slice_num_grp - 1, S5P_FIMV_E_H264_FMO_NUM_SLICE_GRP_MINUS1);
+ } else {
+ MFC_WRITEL(0, S5P_FIMV_E_H264_FMO_NUM_SLICE_GRP_MINUS1);
+ }
+}
+
+void s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_enc_params *p = &enc->params;
+ struct s5p_mfc_h264_enc_params *p_264 = &p->codec.h264;
+ unsigned int reg = 0;
+
+ mfc_debug_enter();
+
+ mfc_set_enc_params(ctx);
+
+ if (p_264->num_hier_layer & 0x7) {
+ /* set gop_size without i_frm_ctrl mode */
+ mfc_set_gop_size(ctx, 0);
+ } else {
+ /* set gop_size with i_frm_ctrl mode */
+ mfc_set_gop_size(ctx, 1);
+ }
+
+ /* UHD encoding case */
+ if(IS_UHD_RES(ctx)) {
+ if (p_264->level < 51) {
+ mfc_info_ctx("Set Level 5.1 for UHD\n");
+ p_264->level = 51;
+ }
+ if (p_264->profile != 0x2) {
+ mfc_info_ctx("Set High profile for UHD\n");
+ p_264->profile = 0x2;
+ }
+ }
+
+ /* profile & level */
+ reg = 0;
+ /** level */
+ reg &= ~(0xFF << 8);
+ reg |= (p_264->level << 8);
+ /** profile - 0 ~ 3 */
+ reg &= ~(0x3F);
+ reg |= p_264->profile;
+ MFC_WRITEL(reg, S5P_FIMV_E_PICTURE_PROFILE);
+
+ reg = MFC_READL(S5P_FIMV_E_H264_OPTIONS);
+ /* entropy coding mode */
+ reg &= ~(0x1);
+ reg |= (p_264->entropy_mode & 0x1);
+ /* loop filter ctrl */
+ reg &= ~(0x3 << 1);
+ reg |= ((p_264->loop_filter_mode & 0x3) << 1);
+ /* interlace */
+ reg &= ~(0x1 << 3);
+ reg |= ((p_264->interlace & 0x1) << 3);
+ /* intra picture period for H.264 open GOP */
+ reg &= ~(0x1 << 4);
+ reg |= ((p_264->open_gop & 0x1) << 4);
+ /* extended encoder ctrl */
+ reg &= ~(0x1 << 5);
+ reg |= ((p_264->ar_vui & 0x1) << 5);
+ /* ASO enable */
+ reg &= ~(0x1 << 6);
+ reg |= ((p_264->aso_enable & 0x1) << 6);
+ /* if num_refs_for_p is 2, the performance falls by half */
+ reg &= ~(0x1 << 7);
+ reg |= (((p->num_refs_for_p - 1) & 0x1) << 7);
+ /* Temporal SVC - hier qp enable */
+ reg &= ~(0x1 << 8);
+ reg |= ((p_264->hier_qp_enable & 0x1) << 8);
+ /* Weighted Prediction enable */
+ reg &= ~(0x3 << 9);
+ reg |= ((p->weighted_enable & 0x1) << 9);
+ /* 8x8 transform enable */
+ reg &= ~(0x1 << 12);
+ reg &= ~(0x1 << 13);
+ reg |= ((p_264->_8x8_transform & 0x1) << 12);
+ reg |= ((p_264->_8x8_transform & 0x1) << 13);
+ /* 'CONSTRAINED_INTRA_PRED_ENABLE' is disable */
+ reg &= ~(0x1 << 14);
+ /*
+ * CONSTRAINT_SET0_FLAG: all constraints specified in
+ * Baseline Profile
+ */
+ reg |= (0x1 << 26);
+ /* sps pps control */
+ reg &= ~(0x1 << 29);
+ reg |= ((p_264->prepend_sps_pps_to_idr & 0x1) << 29);
+ /* enable sps pps control in OTF scenario */
+ if (ctx->otf_handle) {
+ reg |= (0x1 << 29);
+ mfc_debug(2, "[OTF] SPS_PPS_CONTROL enabled\n");
+ }
+ /* VUI parameter disable */
+ reg &= ~(0x1 << 30);
+ reg |= ((p_264->vui_enable & 0x1) << 30);
+ MFC_WRITEL(reg, S5P_FIMV_E_H264_OPTIONS);
+
+ /* cropped height */
+ if (p_264->interlace)
+ MFC_WRITEL(ctx->crop_height >> 1, S5P_FIMV_E_CROPPED_FRAME_HEIGHT);
+
+ /* loopfilter alpha offset */
+ reg = MFC_READL(S5P_FIMV_E_H264_LF_ALPHA_OFFSET);
+ reg &= ~(0x1F);
+ reg |= (p_264->loop_filter_alpha & 0x1F);
+ MFC_WRITEL(reg, S5P_FIMV_E_H264_LF_ALPHA_OFFSET);
+
+ /* loopfilter beta offset */
+ reg = MFC_READL(S5P_FIMV_E_H264_LF_BETA_OFFSET);
+ reg &= ~(0x1F);
+ reg |= (p_264->loop_filter_beta & 0x1F);
+ MFC_WRITEL(reg, S5P_FIMV_E_H264_LF_BETA_OFFSET);
+
+ /* rate control config. */
+ reg = MFC_READL(S5P_FIMV_E_RC_CONFIG);
+ /** frame QP */
+ reg &= ~(0xFF);
+ reg |= (p_264->rc_frame_qp & 0xFF);
+ reg &= ~(0x1 << 11);
+ if (!p->rc_frame && !p->rc_mb && p->dynamic_qp)
+ reg |= (0x1 << 11);
+ MFC_WRITEL(reg, S5P_FIMV_E_RC_CONFIG);
+
+ /* frame rate */
+ /* Fix value for H.264, H.263 in the driver */
+ p->rc_frame_delta = FRAME_DELTA_DEFAULT;
+ reg = MFC_READL(S5P_FIMV_E_RC_FRAME_RATE);
+ reg &= ~(0xFFFF << 16);
+ reg |= (p->rc_framerate << 16);
+ reg &= ~(0xFFFF);
+ reg |= p->rc_frame_delta & 0xFFFF;
+ MFC_WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE);
+
+ /* max & min value of QP for I frame */
+ reg = MFC_READL(S5P_FIMV_E_RC_QP_BOUND);
+ /** max I frame QP */
+ reg &= ~(0xFF << 8);
+ reg |= ((p_264->rc_max_qp & 0xFF) << 8);
+ /** min I frame QP */
+ reg &= ~(0xFF);
+ reg |= p_264->rc_min_qp & 0xFF;
+ MFC_WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND);
+
+ /* max & min value of QP for P/B frame */
+ reg = MFC_READL(S5P_FIMV_E_RC_QP_BOUND_PB);
+ /** max B frame QP */
+ reg &= ~(0xFF << 24);
+ reg |= ((p_264->rc_max_qp_b & 0xFF) << 24);
+ /** min B frame QP */
+ reg &= ~(0xFF << 16);
+ reg |= ((p_264->rc_min_qp_b & 0xFF) << 16);
+ /** max P frame QP */
+ reg &= ~(0xFF << 8);
+ reg |= ((p_264->rc_max_qp_p & 0xFF) << 8);
+ /** min P frame QP */
+ reg &= ~(0xFF);
+ reg |= p_264->rc_min_qp_p & 0xFF;
+ MFC_WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND_PB);
+
+ reg = MFC_READL(S5P_FIMV_E_FIXED_PICTURE_QP);
+ reg &= ~(0xFF << 24);
+ reg |= ((p->config_qp & 0xFF) << 24);
+ reg &= ~(0xFF << 16);
+ reg |= ((p_264->rc_b_frame_qp & 0xFF) << 16);
+ reg &= ~(0xFF << 8);
+ reg |= ((p_264->rc_p_frame_qp & 0xFF) << 8);
+ reg &= ~(0xFF);
+ reg |= (p_264->rc_frame_qp & 0xFF);
+ MFC_WRITEL(reg, S5P_FIMV_E_FIXED_PICTURE_QP);
+
+ MFC_WRITEL(0x0, S5P_FIMV_E_ASPECT_RATIO);
+ MFC_WRITEL(0x0, S5P_FIMV_E_EXTENDED_SAR);
+ if (p_264->ar_vui) {
+ /* aspect ration IDC */
+ reg = 0;
+ reg &= ~(0xff);
+ reg |= p_264->ar_vui_idc;
+ MFC_WRITEL(reg, S5P_FIMV_E_ASPECT_RATIO);
+ if (p_264->ar_vui_idc == 0xFF) {
+ /* sample AR info. */
+ reg = 0;
+ reg &= ~(0xffffffff);
+ reg |= p_264->ext_sar_width << 16;
+ reg |= p_264->ext_sar_height;
+ MFC_WRITEL(reg, S5P_FIMV_E_EXTENDED_SAR);
+ }
+ }
+ /* intra picture period for H.264 open GOP, value */
+ reg = MFC_READL(S5P_FIMV_E_H264_REFRESH_PERIOD);
+ reg &= ~(0xFFFF);
+ if (p_264->open_gop)
+ reg |= (p_264->open_gop_size & 0xFFFF);
+ MFC_WRITEL(reg, S5P_FIMV_E_H264_REFRESH_PERIOD);
+
+ /* Temporal SVC */
+ mfc_set_temporal_svc_h264(ctx, p_264);
+
+ /* set frame pack sei generation */
+ if (p_264->sei_gen_enable) {
+ /* frame packing enable */
+ reg = MFC_READL(S5P_FIMV_E_H264_OPTIONS);
+ reg |= (1 << 25);
+ MFC_WRITEL(reg, S5P_FIMV_E_H264_OPTIONS);
+
+ /* set current frame0 flag & arrangement type */
+ reg = 0;
+ /** current frame0 flag */
+ reg |= ((p_264->sei_fp_curr_frame_0 & 0x1) << 2);
+ /** arrangement type */
+ reg |= (p_264->sei_fp_arrangement_type - 3) & 0x3;
+ MFC_WRITEL(reg, S5P_FIMV_E_H264_FRAME_PACKING_SEI_INFO);
+ }
+
+ if (MFC_FEATURE_SUPPORT(dev, dev->pdata->color_aspect_enc) && p->check_color_range) {
+ reg = MFC_READL(S5P_FIMV_E_VIDEO_SIGNAL_TYPE);
+ /* VIDEO_SIGNAL_TYPE_FLAG */
+ reg |= 0x1 << 31;
+ /* COLOR_RANGE */
+ reg &= ~(0x1 << 25);
+ reg |= p->color_range << 25;
+ if ((p->colour_primaries != 0) && (p->transfer_characteristics != 0) &&
+ (p->matrix_coefficients != 3)) {
+ /* COLOUR_DESCRIPTION_PRESENT_FLAG */
+ reg |= 0x1 << 24;
+ /* COLOUR_PRIMARIES */
+ reg &= ~(0xFF << 16);
+ reg |= p->colour_primaries << 16;
+ /* TRANSFER_CHARACTERISTICS */
+ reg &= ~(0xFF << 8);
+ reg |= p->transfer_characteristics << 8;
+ /* MATRIX_COEFFICIENTS */
+ reg &= ~(0xFF);
+ reg |= p->matrix_coefficients;
+ } else {
+ reg &= ~(0x1 << 24);
+ }
+ MFC_WRITEL(reg, S5P_FIMV_E_VIDEO_SIGNAL_TYPE);
+ mfc_debug(2, "[HDR] H264 ENC Color aspect: range(%s), pri(%d), trans(%d), mat(%d)\n",
+ p->color_range ? "Full" : "Limited", p->colour_primaries,
+ p->transfer_characteristics, p->matrix_coefficients);
+ } else {
+ MFC_WRITEL(0, S5P_FIMV_E_VIDEO_SIGNAL_TYPE);
+ }
+
+ mfc_set_fmo_slice_map_h264(ctx, p_264);
+
+ mfc_debug_leave();
+}
+
+void s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_enc_params *p = &enc->params;
+ struct s5p_mfc_mpeg4_enc_params *p_mpeg4 = &p->codec.mpeg4;
+ unsigned int reg = 0;
+
+ mfc_debug_enter();
+
+ mfc_set_enc_params(ctx);
+
+ /* set gop_size with I_FRM_CTRL mode */
+ mfc_set_gop_size(ctx, 1);
+
+ /* profile & level */
+ reg = 0;
+ /** level */
+ reg &= ~(0xFF << 8);
+ reg |= (p_mpeg4->level << 8);
+ /** profile - 0 ~ 1 */
+ reg &= ~(0x3F);
+ reg |= p_mpeg4->profile;
+ MFC_WRITEL(reg, S5P_FIMV_E_PICTURE_PROFILE);
+
+ /* quarter_pixel */
+ /* MFC_WRITEL(p_mpeg4->quarter_pixel, S5P_FIMV_ENC_MPEG4_QUART_PXL); */
+
+ /* qp */
+ reg = MFC_READL(S5P_FIMV_E_FIXED_PICTURE_QP);
+ reg &= ~(0xFF << 24);
+ reg |= ((p->config_qp & 0xFF) << 24);
+ reg &= ~(0xFF << 16);
+ reg |= ((p_mpeg4->rc_b_frame_qp & 0xFF) << 16);
+ reg &= ~(0xFF << 8);
+ reg |= ((p_mpeg4->rc_p_frame_qp & 0xFF) << 8);
+ reg &= ~(0xFF);
+ reg |= (p_mpeg4->rc_frame_qp & 0xFF);
+ MFC_WRITEL(reg, S5P_FIMV_E_FIXED_PICTURE_QP);
+
+ /* frame rate */
+ p->rc_frame_delta = p_mpeg4->vop_frm_delta;
+ reg = MFC_READL(S5P_FIMV_E_RC_FRAME_RATE);
+ reg &= ~(0xFFFF << 16);
+ reg |= (p_mpeg4->vop_time_res << 16);
+ reg &= ~(0xFFFF);
+ reg |= (p_mpeg4->vop_frm_delta & 0xFFFF);
+ MFC_WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE);
+
+ /* rate control config. */
+ reg = MFC_READL(S5P_FIMV_E_RC_CONFIG);
+ /** frame QP */
+ reg &= ~(0xFF);
+ reg |= (p_mpeg4->rc_frame_qp & 0xFF);
+ MFC_WRITEL(reg, S5P_FIMV_E_RC_CONFIG);
+
+ /* max & min value of QP for I frame */
+ reg = MFC_READL(S5P_FIMV_E_RC_QP_BOUND);
+ /** max I frame QP */
+ reg &= ~(0xFF << 8);
+ reg |= ((p_mpeg4->rc_max_qp & 0xFF) << 8);
+ /** min I frame QP */
+ reg &= ~(0xFF);
+ reg |= (p_mpeg4->rc_min_qp & 0xFF);
+ MFC_WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND);
+
+ /* max & min value of QP for P/B frame */
+ reg = MFC_READL(S5P_FIMV_E_RC_QP_BOUND_PB);
+ /** max B frame QP */
+ reg &= ~(0xFF << 24);
+ reg |= ((p_mpeg4->rc_max_qp_b & 0xFF) << 24);
+ /** min B frame QP */
+ reg &= ~(0xFF << 16);
+ reg |= ((p_mpeg4->rc_min_qp_b & 0xFF) << 16);
+ /** max P frame QP */
+ reg &= ~(0xFF << 8);
+ reg |= ((p_mpeg4->rc_max_qp_p & 0xFF) << 8);
+ /** min P frame QP */
+ reg &= ~(0xFF);
+ reg |= p_mpeg4->rc_min_qp_p & 0xFF;
+ MFC_WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND_PB);
+
+ /* initialize for '0' only setting*/
+ MFC_WRITEL(0x0, S5P_FIMV_E_MPEG4_OPTIONS); /* SEQ_start only */
+ MFC_WRITEL(0x0, S5P_FIMV_E_MPEG4_HEC_PERIOD); /* SEQ_start only */
+
+ mfc_debug_leave();
+}
+
+void s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_enc_params *p = &enc->params;
+ struct s5p_mfc_mpeg4_enc_params *p_mpeg4 = &p->codec.mpeg4;
+ unsigned int reg = 0;
+
+ mfc_debug_enter();
+
+ mfc_set_enc_params(ctx);
+
+ /* set gop_size with I_FRM_CTRL mode */
+ mfc_set_gop_size(ctx, 1);
+
+ /* profile & level: supports only baseline profile Level 70 */
+
+ /* qp */
+ reg = MFC_READL(S5P_FIMV_E_FIXED_PICTURE_QP);
+ reg &= ~(0xFF << 24);
+ reg |= ((p->config_qp & 0xFF) << 24);
+ reg &= ~(0xFF << 8);
+ reg |= ((p_mpeg4->rc_p_frame_qp & 0xFF) << 8);
+ reg &= ~(0xFF);
+ reg |= (p_mpeg4->rc_frame_qp & 0xFF);
+ MFC_WRITEL(reg, S5P_FIMV_E_FIXED_PICTURE_QP);
+
+ /* frame rate */
+ /* Fix value for H.264, H.263 in the driver */
+ p->rc_frame_delta = FRAME_DELTA_DEFAULT;
+ reg = MFC_READL(S5P_FIMV_E_RC_FRAME_RATE);
+ reg &= ~(0xFFFF << 16);
+ reg |= (p->rc_framerate << 16);
+ reg &= ~(0xFFFF);
+ reg |= (p->rc_frame_delta & 0xFFFF);
+ MFC_WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE);
+
+ /* rate control config. */
+ reg = MFC_READL(S5P_FIMV_E_RC_CONFIG);
+ /** frame QP */
+ reg &= ~(0xFF);
+ reg |= (p_mpeg4->rc_frame_qp & 0xFF);
+ MFC_WRITEL(reg, S5P_FIMV_E_RC_CONFIG);
+
+ /* max & min value of QP for I frame */
+ reg = MFC_READL(S5P_FIMV_E_RC_QP_BOUND);
+ /** max I frame QP */
+ reg &= ~(0xFF << 8);
+ reg |= ((p_mpeg4->rc_max_qp & 0xFF) << 8);
+ /** min I frame QP */
+ reg &= ~(0xFF);
+ reg |= (p_mpeg4->rc_min_qp & 0xFF);
+ MFC_WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND);
+
+ /* max & min value of QP for P/B frame */
+ reg = MFC_READL(S5P_FIMV_E_RC_QP_BOUND_PB);
+ /** max P frame QP */
+ reg &= ~(0xFF << 8);
+ reg |= ((p_mpeg4->rc_max_qp_p & 0xFF) << 8);
+ /** min P frame QP */
+ reg &= ~(0xFF);
+ reg |= p_mpeg4->rc_min_qp_p & 0xFF;
+ MFC_WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND_PB);
+
+ mfc_debug_leave();
+}
+
+void s5p_mfc_set_enc_params_vp8(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_enc_params *p = &enc->params;
+ struct s5p_mfc_vp8_enc_params *p_vp8 = &p->codec.vp8;
+ unsigned int reg = 0;
+ int i;
+
+ mfc_debug_enter();
+
+ mfc_set_enc_params(ctx);
+
+ if (p_vp8->num_hier_layer & 0x3) {
+ /* set gop_size without i_frm_ctrl mode */
+ mfc_set_gop_size(ctx, 0);
+ } else {
+ /* set gop_size with i_frm_ctrl mode */
+ mfc_set_gop_size(ctx, 1);
+ }
+
+ /* profile*/
+ reg = 0;
+ reg |= (p_vp8->vp8_version) ;
+ MFC_WRITEL(reg, S5P_FIMV_E_PICTURE_PROFILE);
+
+ reg = MFC_READL(S5P_FIMV_E_VP8_OPTION);
+ /* if num_refs_for_p is 2, the performance falls by half */
+ reg &= ~(0x1);
+ reg |= (p->num_refs_for_p - 1) & 0x1;
+ /* vp8 partition is possible as below value: 1/2/4/8 */
+ if (p_vp8->vp8_numberofpartitions & 0x1) {
+ if (p_vp8->vp8_numberofpartitions > 1)
+ mfc_err_ctx("partition should be even num (%d)\n",
+ p_vp8->vp8_numberofpartitions);
+ p_vp8->vp8_numberofpartitions = (p_vp8->vp8_numberofpartitions & ~0x1);
+ }
+ reg &= ~(0xF << 3);
+ reg |= (p_vp8->vp8_numberofpartitions & 0xF) << 3;
+ reg &= ~(0x1 << 10);
+ reg |= (p_vp8->intra_4x4mode_disable & 0x1) << 10;
+ /* Temporal SVC - hier qp enable */
+ reg &= ~(0x1 << 11);
+ reg |= (p_vp8->hier_qp_enable & 0x1) << 11;
+ /* Disable IVF header */
+ reg &= ~(0x1 << 12);
+ reg |= ((p->ivf_header_disable & 0x1) << 12);
+ MFC_WRITEL(reg, S5P_FIMV_E_VP8_OPTION);
+
+ reg = MFC_READL(S5P_FIMV_E_VP8_GOLDEN_FRAME_OPTION);
+ reg &= ~(0x1);
+ reg |= (p_vp8->vp8_goldenframesel & 0x1);
+ reg &= ~(0xFFFF << 1);
+ reg |= (p_vp8->vp8_gfrefreshperiod & 0xFFFF) << 1;
+ MFC_WRITEL(reg, S5P_FIMV_E_VP8_GOLDEN_FRAME_OPTION);
+
+ /* Temporal SVC - layer number */
+ reg = MFC_READL(S5P_FIMV_E_NUM_T_LAYER);
+ reg &= ~(0x7);
+ reg |= p_vp8->num_hier_layer & 0x3;
+ reg &= ~(0x7 << 4);
+ reg |= 0x3 << 4;
+ reg &= ~(0x1 << 8);
+ reg |= (p->hier_bitrate_ctrl & 0x1) << 8;
+ MFC_WRITEL(reg, S5P_FIMV_E_NUM_T_LAYER);
+ mfc_debug(3, "[HIERARCHICAL] hier_qp_enable %d, num_hier_layer %d, NUM_T_LAYER 0x%x\n",
+ p_vp8->hier_qp_enable, p_vp8->num_hier_layer, reg);
+
+ /* QP & Bitrate for each layer */
+ for (i = 0; i < 3; i++) {
+ MFC_WRITEL(p_vp8->hier_qp_layer[i],
+ S5P_FIMV_E_HIERARCHICAL_QP_LAYER0 + i * 4);
+ /* If hier_bitrate_ctrl is set to 1, this is meaningless */
+ MFC_WRITEL(p_vp8->hier_bit_layer[i],
+ S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER0 + i * 4);
+ mfc_debug(3, "[HIERARCHICAL] layer[%d] QP: %#x, bitrate: %#x(FW ctrl: %d)\n",
+ i, p_vp8->hier_qp_layer[i],
+ p_vp8->hier_bit_layer[i], p->hier_bitrate_ctrl);
+ }
+
+ reg = 0;
+ reg |= (p_vp8->vp8_filtersharpness & 0x7);
+ reg |= (p_vp8->vp8_filterlevel & 0x3f) << 8;
+ MFC_WRITEL(reg, S5P_FIMV_E_VP8_FILTER_OPTION);
+
+ /* qp */
+ reg = MFC_READL(S5P_FIMV_E_FIXED_PICTURE_QP);
+ reg &= ~(0xFF << 24);
+ reg |= ((p->config_qp & 0xFF) << 24);
+ reg &= ~(0xFF << 8);
+ reg |= ((p_vp8->rc_p_frame_qp & 0xFF) << 8);
+ reg &= ~(0xFF);
+ reg |= (p_vp8->rc_frame_qp & 0xFF);
+ MFC_WRITEL(reg, S5P_FIMV_E_FIXED_PICTURE_QP);
+
+ /* frame rate */
+ p->rc_frame_delta = FRAME_DELTA_DEFAULT;
+ reg = MFC_READL(S5P_FIMV_E_RC_FRAME_RATE);
+ reg &= ~(0xFFFF << 16);
+ reg |= (p->rc_framerate << 16);
+ reg &= ~(0xFFFF);
+ reg |= (p->rc_frame_delta & 0xFFFF);
+ MFC_WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE);
+
+ /* rate control config. */
+ reg = MFC_READL(S5P_FIMV_E_RC_CONFIG);
+ /** frame QP */
+ reg &= ~(0xFF);
+ reg |= (p_vp8->rc_frame_qp & 0xFF);
+ MFC_WRITEL(reg, S5P_FIMV_E_RC_CONFIG);
+
+ /* max & min value of QP for I frame */
+ reg = MFC_READL(S5P_FIMV_E_RC_QP_BOUND);
+ /** max I frame QP */
+ reg &= ~(0xFF << 8);
+ reg |= ((p_vp8->rc_max_qp & 0xFF) << 8);
+ /** min I frame QP */
+ reg &= ~(0xFF);
+ reg |= (p_vp8->rc_min_qp & 0xFF);
+ MFC_WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND);
+
+ /* max & min value of QP for P/B frame */
+ reg = MFC_READL(S5P_FIMV_E_RC_QP_BOUND_PB);
+ /** max P frame QP */
+ reg &= ~(0xFF << 8);
+ reg |= ((p_vp8->rc_max_qp_p & 0xFF) << 8);
+ /** min P frame QP */
+ reg &= ~(0xFF);
+ reg |= p_vp8->rc_min_qp_p & 0xFF;
+ MFC_WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND_PB);
+
+ mfc_debug_leave();
+}
+
+void s5p_mfc_set_enc_params_vp9(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_enc_params *p = &enc->params;
+ struct s5p_mfc_vp9_enc_params *p_vp9 = &p->codec.vp9;
+ unsigned int reg = 0;
+ int i;
+
+ mfc_debug_enter();
+
+ mfc_set_enc_params(ctx);
+
+ if (p_vp9->num_hier_layer & 0x3) {
+ /* set gop_size without i_frm_ctrl mode */
+ mfc_set_gop_size(ctx, 0);
+ } else {
+ /* set gop_size with i_frm_ctrl mode */
+ mfc_set_gop_size(ctx, 1);
+ }
+
+ /* profile*/
+ reg = 0;
+ reg |= p_vp9->vp9_version;
+ /* bit depth minus8 */
+ if (ctx->is_10bit) {
+ reg &= ~(0x3F << 17);
+ reg |= (0x2 << 17);
+ reg |= (0x2 << 20);
+ }
+ MFC_WRITEL(reg, S5P_FIMV_E_PICTURE_PROFILE);
+
+ /* for only information about wrong setting */
+ if (ctx->is_422) {
+ if ((p_vp9->vp9_version != S5P_FIMV_E_PROFILE_VP9_PROFILE1) &&
+ (p_vp9->vp9_version != S5P_FIMV_E_PROFILE_VP9_PROFILE3)) {
+ mfc_err_ctx("4:2:2 format is not matched with profile(%d)\n",
+ p_vp9->vp9_version);
+ }
+ }
+ if (ctx->is_10bit) {
+ if ((p_vp9->vp9_version != S5P_FIMV_E_PROFILE_VP9_PROFILE2) &&
+ (p_vp9->vp9_version != S5P_FIMV_E_PROFILE_VP9_PROFILE3)) {
+ mfc_err_ctx("[10BIT] format is not matched with profile(%d)\n",
+ p_vp9->vp9_version);
+ }
+ }
+
+ reg = MFC_READL(S5P_FIMV_E_VP9_OPTION);
+ /* if num_refs_for_p is 2, the performance falls by half */
+ reg &= ~(0x1);
+ reg |= (p->num_refs_for_p - 1) & 0x1;
+ reg &= ~(0x1 << 1);
+ reg |= (p_vp9->intra_pu_split_disable & 0x1) << 1;
+ reg &= ~(0x1 << 3);
+ reg |= (p_vp9->max_partition_depth & 0x1) << 3;
+ /* Temporal SVC - hier qp enable */
+ reg &= ~(0x1 << 11);
+ reg |= ((p_vp9->hier_qp_enable & 0x1) << 11);
+ /* Disable IVF header */
+ reg &= ~(0x1 << 12);
+ reg |= ((p->ivf_header_disable & 0x1) << 12);
+ MFC_WRITEL(reg, S5P_FIMV_E_VP9_OPTION);
+
+ reg = MFC_READL(S5P_FIMV_E_VP9_GOLDEN_FRAME_OPTION);
+ reg &= ~(0x1);
+ reg |= (p_vp9->vp9_goldenframesel & 0x1);
+ reg &= ~(0xFFFF << 1);
+ reg |= (p_vp9->vp9_gfrefreshperiod & 0xFFFF) << 1;
+ MFC_WRITEL(reg, S5P_FIMV_E_VP9_GOLDEN_FRAME_OPTION);
+
+ /* Temporal SVC - layer number */
+ reg = MFC_READL(S5P_FIMV_E_NUM_T_LAYER);
+ reg &= ~(0x7);
+ reg |= p_vp9->num_hier_layer & 0x3;
+ reg &= ~(0x7 << 4);
+ reg |= 0x3 << 4;
+ reg &= ~(0x1 << 8);
+ reg |= (p->hier_bitrate_ctrl & 0x1) << 8;
+ MFC_WRITEL(reg, S5P_FIMV_E_NUM_T_LAYER);
+ mfc_debug(3, "[HIERARCHICAL] hier_qp_enable %d, num_hier_layer %d, NUM_T_LAYER 0x%x\n",
+ p_vp9->hier_qp_enable, p_vp9->num_hier_layer, reg);
+
+ /* QP & Bitrate for each layer */
+ for (i = 0; i < 3; i++) {
+ MFC_WRITEL(p_vp9->hier_qp_layer[i],
+ S5P_FIMV_E_HIERARCHICAL_QP_LAYER0 + i * 4);
+ /* If hier_bitrate_ctrl is set to 1, this is meaningless */
+ MFC_WRITEL(p_vp9->hier_bit_layer[i],
+ S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER0 + i * 4);
+ mfc_debug(3, "[HIERARCHICAL] layer[%d] QP: %#x, bitrate: %#x (FW ctrl: %d)\n",
+ i, p_vp9->hier_qp_layer[i],
+ p_vp9->hier_bit_layer[i], p->hier_bitrate_ctrl);
+ }
+
+ /* qp */
+ reg = MFC_READL(S5P_FIMV_E_FIXED_PICTURE_QP);
+ reg &= ~(0xFF << 24);
+ reg |= ((p->config_qp & 0xFF) << 24);
+ reg &= ~(0xFF << 8);
+ reg |= ((p_vp9->rc_p_frame_qp & 0xFF) << 8);
+ reg &= ~(0xFF);
+ reg |= (p_vp9->rc_frame_qp & 0xFF);
+ MFC_WRITEL(reg, S5P_FIMV_E_FIXED_PICTURE_QP);
+
+ /* frame rate */
+ p->rc_frame_delta = FRAME_DELTA_DEFAULT;
+ reg = MFC_READL(S5P_FIMV_E_RC_FRAME_RATE);
+ reg &= ~(0xFFFF << 16);
+ reg |= (p->rc_framerate << 16);
+ reg &= ~(0xFFFF);
+ reg |= (p->rc_frame_delta & 0xFFFF);
+ MFC_WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE);
+
+ /* rate control config. */
+ reg = MFC_READL(S5P_FIMV_E_RC_CONFIG);
+ /** frame QP */
+ reg &= ~(0xFF);
+ reg |= (p_vp9->rc_frame_qp & 0xFF);
+ MFC_WRITEL(reg, S5P_FIMV_E_RC_CONFIG);
+
+ /* max & min value of QP for I frame */
+ reg = MFC_READL(S5P_FIMV_E_RC_QP_BOUND);
+ /** max I frame QP */
+ reg &= ~(0xFF << 8);
+ reg |= ((p_vp9->rc_max_qp & 0xFF) << 8);
+ /** min I frame QP */
+ reg &= ~(0xFF);
+ reg |= (p_vp9->rc_min_qp & 0xFF);
+ MFC_WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND);
+
+ /* max & min value of QP for P/B frame */
+ reg = MFC_READL(S5P_FIMV_E_RC_QP_BOUND_PB);
+ /** max P frame QP */
+ reg &= ~(0xFF << 8);
+ reg |= ((p_vp9->rc_max_qp_p & 0xFF) << 8);
+ /** min P frame QP */
+ reg &= ~(0xFF);
+ reg |= p_vp9->rc_min_qp_p & 0xFF;
+ MFC_WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND_PB);
+
+ if (MFC_FEATURE_SUPPORT(dev, dev->pdata->color_aspect_enc) && p->check_color_range) {
+ reg = MFC_READL(S5P_FIMV_E_VIDEO_SIGNAL_TYPE);
+ /* VIDEO_SIGNAL_TYPE_FLAG */
+ reg |= 0x1 << 31;
+ /* COLOR_SPACE: VP9 uses colour_primaries interface for color space */
+ reg &= ~(0x1F << 26);
+ reg |= p->colour_primaries << 26;
+ /* COLOR_RANGE */
+ reg &= ~(0x1 << 25);
+ reg |= p->color_range << 25;
+ MFC_WRITEL(reg, S5P_FIMV_E_VIDEO_SIGNAL_TYPE);
+ mfc_debug(2, "[HDR] VP9 ENC Color aspect: range(%s), space(%d)\n",
+ p->color_range ? "Full" : "Limited", p->colour_primaries);
+ } else {
+ MFC_WRITEL(0, S5P_FIMV_E_VIDEO_SIGNAL_TYPE);
+ }
+
+ mfc_debug_leave();
+}
+
+void s5p_mfc_set_enc_params_hevc(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_enc_params *p = &enc->params;
+ struct s5p_mfc_hevc_enc_params *p_hevc = &p->codec.hevc;
+ unsigned int reg = 0;
+ int i;
+
+ mfc_debug_enter();
+
+ mfc_set_enc_params(ctx);
+
+ if (p_hevc->num_hier_layer & 0x7) {
+ /* set gop_size without i_frm_ctrl mode */
+ mfc_set_gop_size(ctx, 0);
+ } else {
+ /* set gop_size with i_frm_ctrl mode */
+ mfc_set_gop_size(ctx, 1);
+ }
+
+ /* UHD encoding case */
+ if (IS_UHD_RES(ctx)) {
+ p_hevc->level = 51;
+ p_hevc->tier_flag = 0;
+ /* this tier_flag can be changed */
+ }
+
+ /* tier_flag & level & profile */
+ reg = 0;
+ /* profile */
+ reg |= p_hevc->profile & 0xf;
+ /* level */
+ reg &= ~(0xFF << 8);
+ reg |= (p_hevc->level << 8);
+ /* tier_flag - 0 ~ 1 */
+ reg |= (p_hevc->tier_flag << 16);
+ /* bit depth minus8 */
+ if (ctx->is_10bit) {
+ reg &= ~(0x3F << 17);
+ reg |= (0x2 << 17);
+ reg |= (0x2 << 20);
+ }
+ MFC_WRITEL(reg, S5P_FIMV_E_PICTURE_PROFILE);
+
+ /* for only information about wrong setting */
+ if (ctx->is_422) {
+ if ((p_hevc->profile != S5P_FIMV_E_PROFILE_HEVC_MAIN_422_10_INTRA) &&
+ (p_hevc->profile != S5P_FIMV_E_PROFILE_HEVC_MAIN_422_10)) {
+ mfc_err_ctx("4:2:2 format is not matched with profile(%d)\n",
+ p_hevc->profile);
+ }
+ }
+ if (ctx->is_10bit) {
+ if ((p_hevc->profile != S5P_FIMV_E_PROFILE_HEVC_MAIN_422_10_INTRA) &&
+ (p_hevc->profile != S5P_FIMV_E_PROFILE_HEVC_MAIN_10) &&
+ (p_hevc->profile != S5P_FIMV_E_PROFILE_HEVC_MAIN_422_10)) {
+ mfc_err_ctx("[10BIT] format is not matched with profile(%d)\n",
+ p_hevc->profile);
+ }
+ }
+
+ /* max partition depth */
+ reg = MFC_READL(S5P_FIMV_E_HEVC_OPTIONS);
+ reg &= ~(0x3);
+ reg |= (p_hevc->max_partition_depth & 0x1);
+ /* if num_refs_for_p is 2, the performance falls by half */
+ reg &= ~(0x1 << 2);
+ reg |= (p->num_refs_for_p - 1) << 2;
+ reg &= ~(0x3 << 3);
+ reg |= (p_hevc->refreshtype & 0x3) << 3;
+ reg &= ~(0x1 << 5);
+ reg |= (p_hevc->const_intra_period_enable & 0x1) << 5;
+ reg &= ~(0x1 << 6);
+ reg |= (p_hevc->lossless_cu_enable & 0x1) << 6;
+ reg &= ~(0x1 << 7);
+ reg |= (p_hevc->wavefront_enable & 0x1) << 7;
+ reg &= ~(0x1 << 8);
+ reg |= (p_hevc->loopfilter_disable & 0x1) << 8;
+ reg &= ~(0x1 << 9);
+ reg |= (p_hevc->loopfilter_across & 0x1) << 9;
+ reg &= ~(0x1 << 10);
+ reg |= (p_hevc->enable_ltr & 0x1) << 10;
+ reg &= ~(0x1 << 11);
+ reg |= (p_hevc->hier_qp_enable & 0x1) << 11;
+ reg &= ~(0x1 << 13);
+ reg |= (p_hevc->general_pb_enable & 0x1) << 13;
+ reg &= ~(0x1 << 14);
+ reg |= (p_hevc->temporal_id_enable & 0x1) << 14;
+ reg &= ~(0x1 << 15);
+ reg |= (p_hevc->strong_intra_smooth & 0x1) << 15;
+ reg &= ~(0x1 << 16);
+ reg |= (p_hevc->intra_pu_split_disable & 0x1) << 16;
+ reg &= ~(0x1 << 17);
+ reg |= (p_hevc->tmv_prediction_disable & 0x1) << 17;
+ reg &= ~(0x7 << 18);
+ reg |= (p_hevc->max_num_merge_mv & 0x7) << 18;
+ reg &= ~(0x1 << 23);
+ reg |= (p_hevc->encoding_nostartcode_enable & 0x1) << 23;
+ reg &= ~(0x1 << 26);
+ reg |= (p_hevc->prepend_sps_pps_to_idr & 0x1) << 26;
+ /* enable sps pps control in OTF scenario */
+ if (ctx->otf_handle) {
+ reg |= (0x1 << 26);
+ mfc_debug(2, "[OTF] SPS_PPS_CONTROL enabled\n");
+ }
+ /* Weighted Prediction enable */
+ reg &= ~(0x1 << 28);
+ reg |= ((p->weighted_enable & 0x1) << 28);
+ /* 30bit is 32x32 transform. If it is enabled, the performance falls by half */
+ reg &= ~(0x1 << 30);
+ MFC_WRITEL(reg, S5P_FIMV_E_HEVC_OPTIONS);
+ /* refresh period */
+ reg = MFC_READL(S5P_FIMV_E_HEVC_REFRESH_PERIOD);
+ reg &= ~(0xFFFF);
+ reg |= (p_hevc->refreshperiod & 0xFFFF);
+ MFC_WRITEL(reg, S5P_FIMV_E_HEVC_REFRESH_PERIOD);
+ /* loop filter setting */
+ MFC_WRITEL(0, S5P_FIMV_E_HEVC_LF_BETA_OFFSET_DIV2);
+ MFC_WRITEL(0, S5P_FIMV_E_HEVC_LF_TC_OFFSET_DIV2);
+ if (!p_hevc->loopfilter_disable) {
+ MFC_WRITEL(p_hevc->lf_beta_offset_div2, S5P_FIMV_E_HEVC_LF_BETA_OFFSET_DIV2);
+ MFC_WRITEL(p_hevc->lf_tc_offset_div2, S5P_FIMV_E_HEVC_LF_TC_OFFSET_DIV2);
+ }
+ /* long term reference */
+ if (p_hevc->enable_ltr) {
+ reg = 0;
+ reg |= (p_hevc->store_ref & 0x3);
+ reg &= ~(0x3 << 2);
+ reg |= (p_hevc->user_ref & 0x3) << 2;
+ MFC_WRITEL(reg, S5P_FIMV_E_HEVC_NAL_CONTROL);
+ }
+
+ /* Temporal SVC - qp type, layer number */
+ reg = MFC_READL(S5P_FIMV_E_NUM_T_LAYER);
+ reg &= ~(0x1 << 3);
+ reg |= (p_hevc->hier_qp_type & 0x1) << 3;
+ reg &= ~(0x7);
+ reg |= p_hevc->num_hier_layer & 0x7;
+ reg &= ~(0x7 << 4);
+ if (p_hevc->hier_ref_type) {
+ reg |= 0x1 << 7;
+ reg |= (p->num_hier_max_layer & 0x7) << 4;
+ } else {
+ reg &= ~(0x1 << 7);
+ reg |= 0x7 << 4;
+ }
+ reg &= ~(0x1 << 8);
+ reg |= (p->hier_bitrate_ctrl & 0x1) << 8;
+ MFC_WRITEL(reg, S5P_FIMV_E_NUM_T_LAYER);
+ mfc_debug(3, "[HIERARCHICAL] hier_qp_enable %d, enable_ltr %d, "
+ "num_hier_layer %d, max_layer %d, hier_ref_type %d, NUM_T_LAYER 0x%x\n",
+ p_hevc->hier_qp_enable, p_hevc->enable_ltr, p_hevc->num_hier_layer,
+ p->num_hier_max_layer, p_hevc->hier_ref_type, reg);
+
+ /* QP & Bitrate for each layer */
+ for (i = 0; i < 7; i++) {
+ MFC_WRITEL(p_hevc->hier_qp_layer[i],
+ S5P_FIMV_E_HIERARCHICAL_QP_LAYER0 + i * 4);
+ MFC_WRITEL(p_hevc->hier_bit_layer[i],
+ S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER0 + i * 4);
+ mfc_debug(3, "[HIERARCHICAL] layer[%d] QP: %#x, bitrate: %d(FW ctrl: %d)\n",
+ i, p_hevc->hier_qp_layer[i],
+ p_hevc->hier_bit_layer[i], p->hier_bitrate_ctrl);
+ }
+
+ /* rate control config. */
+ reg = MFC_READL(S5P_FIMV_E_RC_CONFIG);
+ /** frame QP */
+ reg &= ~(0xFF);
+ reg |= (p_hevc->rc_frame_qp & 0xFF);
+ MFC_WRITEL(reg, S5P_FIMV_E_RC_CONFIG);
+
+ /* frame rate */
+ p->rc_frame_delta = FRAME_DELTA_DEFAULT;
+ reg = MFC_READL(S5P_FIMV_E_RC_FRAME_RATE);
+ reg &= ~(0xFFFF << 16);
+ reg |= (p->rc_framerate << 16);
+ reg &= ~(0xFFFF);
+ reg |= (p->rc_frame_delta & 0xFFFF);
+ MFC_WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE);
+
+ /* max & min value of QP for I frame */
+ reg = MFC_READL(S5P_FIMV_E_RC_QP_BOUND);
+ /** max I frame QP */
+ reg &= ~(0xFF << 8);
+ reg |= ((p_hevc->rc_max_qp & 0xFF) << 8);
+ /** min I frame QP */
+ reg &= ~(0xFF);
+ reg |= (p_hevc->rc_min_qp & 0xFF);
+ MFC_WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND);
+
+ /* max & min value of QP for P/B frame */
+ reg = MFC_READL(S5P_FIMV_E_RC_QP_BOUND_PB);
+ /** max B frame QP */
+ reg &= ~(0xFF << 24);
+ reg |= ((p_hevc->rc_max_qp_b & 0xFF) << 24);
+ /** min B frame QP */
+ reg &= ~(0xFF << 16);
+ reg |= ((p_hevc->rc_min_qp_b & 0xFF) << 16);
+ /** max P frame QP */
+ reg &= ~(0xFF << 8);
+ reg |= ((p_hevc->rc_max_qp_p & 0xFF) << 8);
+ /** min P frame QP */
+ reg &= ~(0xFF);
+ reg |= p_hevc->rc_min_qp_p & 0xFF;
+ MFC_WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND_PB);
+
+ reg = MFC_READL(S5P_FIMV_E_FIXED_PICTURE_QP);
+ reg &= ~(0xFF << 24);
+ reg |= ((p->config_qp & 0xFF) << 24);
+ reg &= ~(0xFF << 16);
+ reg |= ((p_hevc->rc_b_frame_qp & 0xFF) << 16);
+ reg &= ~(0xFF << 8);
+ reg |= ((p_hevc->rc_p_frame_qp & 0xFF) << 8);
+ reg &= ~(0xFF);
+ reg |= (p_hevc->rc_frame_qp & 0xFF);
+ MFC_WRITEL(reg, S5P_FIMV_E_FIXED_PICTURE_QP);
+
+ /* ROI enable: it must set on SEQ_START only for HEVC encoder */
+ reg = MFC_READL(S5P_FIMV_E_RC_ROI_CTRL);
+ reg &= ~(0x1);
+ reg |= (p->roi_enable);
+ MFC_WRITEL(reg, S5P_FIMV_E_RC_ROI_CTRL);
+ mfc_debug(3, "[ROI] HEVC ROI enable\n");
+
+ if (MFC_FEATURE_SUPPORT(dev, dev->pdata->color_aspect_enc) && p->check_color_range) {
+ reg = MFC_READL(S5P_FIMV_E_VIDEO_SIGNAL_TYPE);
+ /* VIDEO_SIGNAL_TYPE_FLAG */
+ reg |= 0x1 << 31;
+ /* COLOR_RANGE */
+ reg &= ~(0x1 << 25);
+ reg |= p->color_range << 25;
+ if ((p->colour_primaries != 0) && (p->transfer_characteristics != 0) &&
+ (p->matrix_coefficients != 3)) {
+ /* COLOUR_DESCRIPTION_PRESENT_FLAG */
+ reg |= 0x1 << 24;
+ /* COLOUR_PRIMARIES */
+ reg &= ~(0xFF << 16);
+ reg |= p->colour_primaries << 16;
+ /* TRANSFER_CHARACTERISTICS */
+ reg &= ~(0xFF << 8);
+ reg |= p->transfer_characteristics << 8;
+ /* MATRIX_COEFFICIENTS */
+ reg &= ~(0xFF);
+ reg |= p->matrix_coefficients;
+ } else {
+ reg &= ~(0x1 << 24);
+ }
+ MFC_WRITEL(reg, S5P_FIMV_E_VIDEO_SIGNAL_TYPE);
+ mfc_debug(2, "[HDR] HEVC ENC Color aspect: range(%s), pri(%d), trans(%d), mat(%d)\n",
+ p->color_range ? "Full" : "Limited", p->colour_primaries,
+ p->transfer_characteristics, p->matrix_coefficients);
+ } else {
+ MFC_WRITEL(0, S5P_FIMV_E_VIDEO_SIGNAL_TYPE);
+ }
+
+ if (MFC_FEATURE_SUPPORT(dev, dev->pdata->static_info_enc) &&
+ p->static_info_enable && ctx->is_10bit) {
+ reg = MFC_READL(S5P_FIMV_E_HEVC_OPTIONS_2);
+ /* HDR_STATIC_INFO_ENABLE */
+ reg |= p->static_info_enable;
+ MFC_WRITEL(reg, S5P_FIMV_E_HEVC_OPTIONS_2);
+ /* MAX_PIC_AVERAGE_LIGHT & MAX_CONTENT_LIGHT */
+ reg = p->max_pic_average_light;
+ reg |= (p->max_content_light << 16);
+ MFC_WRITEL(reg, S5P_FIMV_E_CONTENT_LIGHT_LEVEL_INFO_SEI);
+ /* MAX_DISPLAY_LUMINANCE */
+ MFC_WRITEL(p->max_display_luminance, S5P_FIMV_E_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_0);
+ /* MIN DISPLAY LUMINANCE */
+ MFC_WRITEL(p->min_display_luminance, S5P_FIMV_E_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_1);
+ /* WHITE_POINT */
+ MFC_WRITEL(p->white_point, S5P_FIMV_E_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_2);
+ /* DISPLAY PRIMARIES_0 */
+ MFC_WRITEL(p->display_primaries_0, S5P_FIMV_E_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_3);
+ /* DISPLAY PRIMARIES_1 */
+ MFC_WRITEL(p->display_primaries_1, S5P_FIMV_E_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_4);
+ /* DISPLAY PRIMARIES_2 */
+ MFC_WRITEL(p->display_primaries_2, S5P_FIMV_E_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_5);
+
+ mfc_debug(2, "[HDR] HEVC ENC static info: enable(%d), max_pic(0x%x), max_content(0x%x)\n",
+ p->static_info_enable, p->max_pic_average_light, p->max_content_light);
+ mfc_debug(2, "[HDR] max_disp(0x%x), min_disp(0x%x), white_point(0x%x)\n",
+ p->max_display_luminance, p->min_display_luminance, p->white_point);
+ mfc_debug(2, "[HDR] disp_pri_0(0x%x), disp_pri_1(0x%x), disp_pri_2(0x%x)\n",
+ p->display_primaries_0, p->display_primaries_1, p->display_primaries_2);
+ } else {
+ reg = MFC_READL(S5P_FIMV_E_HEVC_OPTIONS_2);
+ /* HDR_STATIC_INFO_ENABLE */
+ reg &= ~(0x1);
+ MFC_WRITEL(reg, S5P_FIMV_E_HEVC_OPTIONS_2);
+ }
+
+ mfc_debug_leave();
+}
+
+void s5p_mfc_set_enc_params_bpg(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_enc_params *p = &enc->params;
+ struct s5p_mfc_bpg_enc_params *p_bpg = &p->codec.bpg;
+ unsigned int reg = 0;
+
+ mfc_set_enc_params(ctx);
+
+ /* extension tag */
+ reg = p_bpg->thumb_size + p_bpg->exif_size;
+ MFC_WRITEL(reg, S5P_FIMV_E_BPG_EXTENSION_DATA_SIZE);
+ mfc_debug(3, "main image extension size %d (thumbnail: %d, exif: %d)\n",
+ reg, p_bpg->thumb_size, p_bpg->exif_size);
+
+ /* profile & level */
+ reg = 0;
+ /** profile */
+ reg &= ~(0xF);
+ /* bit depth minus8 */
+ if (ctx->is_10bit) {
+ reg &= ~(0x3F << 17);
+ reg |= (0x2 << 17);
+ reg |= (0x2 << 20);
+ /* fixed profile */
+ if (ctx->is_422)
+ reg |= 0x1;
+ }
+ MFC_WRITEL(reg, S5P_FIMV_E_PICTURE_PROFILE);
+}
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_enc_param.h
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __MFC_ENC_PARAM_H
+#define __MFC_ENC_PARAM_H __FILE__
+
+#include "mfc_common.h"
+
+void s5p_mfc_set_slice_mode(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_set_enc_params_vp8(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_set_enc_params_vp9(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_set_enc_params_hevc(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_set_enc_params_bpg(struct s5p_mfc_ctx *ctx);
+
+#endif /* __MFC_ENC_PARAM_H */
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_enc_vb2_ops.c
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "mfc_common.h"
+
+#include "mfc_hwlock.h"
+#include "mfc_nal_q.h"
+#include "mfc_opr.h"
+#include "mfc_sync.h"
+
+#include "mfc_qos.h"
+#include "mfc_queue.h"
+#include "mfc_utils.h"
+#include "mfc_buf.h"
+#include "mfc_mem.h"
+
+static int s5p_mfc_enc_queue_setup(struct vb2_queue *vq,
+ unsigned int *buf_count, unsigned int *plane_count,
+ unsigned int psize[], struct device *alloc_devs[])
+{
+ struct s5p_mfc_dev *dev;
+ struct s5p_mfc_ctx *ctx = vq->drv_priv;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_raw_info *raw;
+ int i;
+
+ mfc_debug_enter();
+
+ dev = ctx->dev;
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ if (ctx->state != MFCINST_GOT_INST &&
+ vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ mfc_err_ctx("invalid state: %d\n", ctx->state);
+ return -EINVAL;
+ }
+ if (ctx->state >= MFCINST_FINISHING &&
+ vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ mfc_err_ctx("invalid state: %d\n", ctx->state);
+ return -EINVAL;
+ }
+
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ mfc_debug(4, "enc dst\n");
+ if (ctx->dst_fmt)
+ *plane_count = ctx->dst_fmt->mem_planes;
+ else
+ *plane_count = MFC_ENC_CAP_PLANE_COUNT;
+
+ if (*buf_count < 1)
+ *buf_count = 1;
+ if (*buf_count > MFC_MAX_BUFFERS)
+ *buf_count = MFC_MAX_BUFFERS;
+
+ psize[0] = enc->dst_buf_size;
+ alloc_devs[0] = dev->device;
+ } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ mfc_debug(4, "enc src\n");
+ raw = &ctx->raw_buf;
+
+ if (ctx->src_fmt)
+ *plane_count = ctx->src_fmt->mem_planes;
+ else
+ *plane_count = MFC_ENC_OUT_PLANE_COUNT;
+
+ if (*buf_count < 1)
+ *buf_count = 1;
+ if (*buf_count > MFC_MAX_BUFFERS)
+ *buf_count = MFC_MAX_BUFFERS;
+
+ if (*plane_count == 1) {
+ psize[0] = raw->total_plane_size;
+ alloc_devs[0] = dev->device;
+ } else {
+ for (i = 0; i < *plane_count; i++) {
+ psize[i] = raw->plane_size[i];
+ alloc_devs[i] = dev->device;
+ }
+ }
+ } else {
+ mfc_err_ctx("invalid queue type: %d\n", vq->type);
+ return -EINVAL;
+ }
+
+ mfc_debug(2, "buf_count: %d, plane_count: %d, type: %#x\n",
+ *buf_count, *plane_count, vq->type);
+ for (i = 0; i < *plane_count; i++)
+ mfc_debug(2, "plane[%d] size: %d\n", i, psize[i]);
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+static void s5p_mfc_enc_unlock(struct vb2_queue *q)
+{
+ struct s5p_mfc_ctx *ctx = q->drv_priv;
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ mutex_unlock(&dev->mfc_mutex);
+}
+
+static void s5p_mfc_enc_lock(struct vb2_queue *q)
+{
+ struct s5p_mfc_ctx *ctx = q->drv_priv;
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ mutex_lock(&dev->mfc_mutex);
+}
+
+static int s5p_mfc_enc_buf_init(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct s5p_mfc_ctx *ctx = vq->drv_priv;
+ int ret;
+
+ mfc_debug_enter();
+
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ ret = s5p_mfc_check_vb_with_fmt(ctx->dst_fmt, vb);
+ if (ret < 0)
+ return ret;
+
+ if (call_cop(ctx, init_buf_ctrls, ctx, MFC_CTRL_TYPE_DST,
+ vb->index) < 0)
+ mfc_err_ctx("failed in init_buf_ctrls\n");
+
+ } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ ret = s5p_mfc_check_vb_with_fmt(ctx->src_fmt, vb);
+ if (ret < 0)
+ return ret;
+
+ if (call_cop(ctx, init_buf_ctrls, ctx, MFC_CTRL_TYPE_SRC,
+ vb->index) < 0)
+ mfc_err_ctx("failed in init_buf_ctrls\n");
+ } else {
+ mfc_err_ctx("inavlid queue type: %d\n", vq->type);
+ return -EINVAL;
+ }
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+static int s5p_mfc_enc_buf_prepare(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct s5p_mfc_ctx *ctx = vq->drv_priv;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_raw_info *raw;
+ unsigned int index = vb->index;
+ struct s5p_mfc_buf *buf = vb_to_mfc_buf(vb);
+ struct dma_buf *bufcon_dmabuf[MFC_MAX_PLANES];
+ int i, mem_get_count = 0;
+ size_t buf_size;
+
+ mfc_debug_enter();
+
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ buf_size = vb2_plane_size(vb, 0);
+ mfc_debug(2, "[STREAM] vb size: %lu, calc size: %u\n",
+ buf_size, enc->dst_buf_size);
+
+ if (buf_size < enc->dst_buf_size) {
+ mfc_err_ctx("[STREAM] size(%d) is smaller than (%d)\n",
+ buf_size, enc->dst_buf_size);
+ return -EINVAL;
+ }
+
+ buf->addr[0][0] = s5p_mfc_mem_get_daddr_vb(vb, 0);
+ } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ raw = &ctx->raw_buf;
+ if (ctx->src_fmt->mem_planes == 1) {
+ buf_size = vb2_plane_size(vb, 0);
+ mfc_debug(2, "[FRAME] single plane vb size: %lu, calc size: %d\n",
+ buf_size, raw->total_plane_size);
+ if (buf_size < raw->total_plane_size) {
+ mfc_err_ctx("[FRAME] single plane size(%d) is smaller than (%d)\n",
+ buf_size, raw->total_plane_size);
+ return -EINVAL;
+ }
+ } else {
+ for (i = 0; i < ctx->src_fmt->mem_planes; i++) {
+ buf_size = vb2_plane_size(vb, i);
+ mfc_debug(2, "[FRAME] plane[%d] vb size: %lu, calc size: %d\n",
+ i, buf_size, raw->plane_size[i]);
+ if (buf_size < raw->plane_size[i]) {
+ mfc_err_ctx("[FRAME] plane[%d] size(%d) is smaller than (%d)\n",
+ i, buf_size, raw->plane_size[i]);
+ return -EINVAL;
+ }
+ }
+ }
+
+ for (i = 0; i < ctx->src_fmt->mem_planes; i++) {
+ bufcon_dmabuf[i] = dma_buf_get(vb->planes[i].m.fd);
+ if (IS_ERR(bufcon_dmabuf[i])) {
+ mfc_err_ctx("failed to get bufcon dmabuf\n");
+ goto err_mem_put;
+ }
+
+ mem_get_count++;
+ buf->num_bufs_in_batch = s5p_mfc_bufcon_get_buf_count(bufcon_dmabuf[i]);
+ mfc_debug(3, "[BUFCON] num bufs in batch: %d\n", buf->num_bufs_in_batch);
+ if (buf->num_bufs_in_batch == 0) {
+ mfc_err_ctx("[BUFCON] bufs count couldn't be zero\n");
+ goto err_mem_put;
+ }
+
+ if (buf->num_bufs_in_batch < 0)
+ buf->num_bufs_in_batch = 0;
+
+ if (!ctx->batch_mode && buf->num_bufs_in_batch > 0) {
+ ctx->batch_mode = 1;
+ mfc_debug(2, "[BUFCON] buffer batch mode enable\n");
+ }
+
+ if (buf->num_bufs_in_batch > 0) {
+ if (s5p_mfc_bufcon_get_daddr(ctx, buf, bufcon_dmabuf[i], i)) {
+ mfc_err_ctx("[BUFCON] failed to get daddr[%d] in buffer container\n", i);
+ goto err_mem_put;
+ }
+
+ ctx->framerate = buf->num_valid_bufs * ENC_DEFAULT_CAM_CAPTURE_FPS;
+ mfc_debug(3, "[BUFCON] framerate: %ld\n", ctx->framerate);
+
+ dma_buf_put(bufcon_dmabuf[i]);
+ } else {
+ dma_addr_t start_raw;
+
+ dma_buf_put(bufcon_dmabuf[i]);
+ start_raw = s5p_mfc_mem_get_daddr_vb(vb, 0);
+ if (start_raw == 0) {
+ mfc_err_ctx("Plane mem not allocated\n");
+ return -ENOMEM;
+ }
+ if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12N) {
+ buf->addr[0][0] = start_raw;
+ buf->addr[0][1] = NV12N_CBCR_BASE(start_raw,
+ ctx->img_width,
+ ctx->img_height);
+ } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420N) {
+ buf->addr[0][0] = start_raw;
+ buf->addr[0][1] = YUV420N_CB_BASE(start_raw,
+ ctx->img_width,
+ ctx->img_height);
+ buf->addr[0][2] = YUV420N_CR_BASE(start_raw,
+ ctx->img_width,
+ ctx->img_height);
+ } else {
+ buf->addr[0][i] = s5p_mfc_mem_get_daddr_vb(vb, i);
+ }
+ }
+ }
+
+ if (call_cop(ctx, to_buf_ctrls, ctx, &ctx->src_ctrls[index]) < 0)
+ mfc_err_ctx("failed in to_buf_ctrls\n");
+ } else {
+ mfc_err_ctx("inavlid queue type: %d\n", vq->type);
+ return -EINVAL;
+ }
+
+ mfc_debug_leave();
+ return 0;
+
+err_mem_put:
+ for (i = 0; i < mem_get_count; i++)
+ dma_buf_put(bufcon_dmabuf[i]);
+
+ return -ENOMEM;
+}
+
+static void s5p_mfc_enc_buf_finish(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct s5p_mfc_ctx *ctx = vq->drv_priv;
+ unsigned int index = vb->index;
+
+
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ if (call_cop(ctx, to_ctx_ctrls, ctx, &ctx->dst_ctrls[index]) < 0)
+ mfc_err_ctx("failed in to_ctx_ctrls\n");
+ } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ if (call_cop(ctx, to_ctx_ctrls, ctx, &ctx->src_ctrls[index]) < 0)
+ mfc_err_ctx("failed in to_ctx_ctrls\n");
+ }
+}
+
+static void s5p_mfc_enc_buf_cleanup(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct s5p_mfc_ctx *ctx = vq->drv_priv;
+ unsigned int index = vb->index;
+
+ mfc_debug_enter();
+
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ if (call_cop(ctx, cleanup_buf_ctrls, ctx,
+ MFC_CTRL_TYPE_DST, index) < 0)
+ mfc_err_ctx("failed in cleanup_buf_ctrls\n");
+ } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ if (call_cop(ctx, cleanup_buf_ctrls, ctx,
+ MFC_CTRL_TYPE_SRC, index) < 0)
+ mfc_err_ctx("failed in cleanup_buf_ctrls\n");
+ } else {
+ mfc_err_ctx("s5p_mfc_enc_buf_cleanup: unknown queue type\n");
+ }
+
+ mfc_debug_leave();
+}
+
+static int s5p_mfc_enc_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct s5p_mfc_ctx *ctx = q->drv_priv;
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ /* If context is ready then dev = work->data;schedule it to run */
+ if (s5p_mfc_enc_ctx_ready(ctx)) {
+ s5p_mfc_set_bit(ctx->num, &dev->work_bits);
+ }
+
+ s5p_mfc_try_run(dev);
+
+ return 0;
+}
+
+static void s5p_mfc_enc_stop_streaming(struct vb2_queue *q)
+{
+ struct s5p_mfc_ctx *ctx = q->drv_priv;
+ struct s5p_mfc_dev *dev = ctx->dev;
+ int index = 0;
+ int aborted = 0;
+ int ret = 0;
+
+ mfc_info_ctx("enc stop_streaming is called, hwlock : %d, type : %d\n",
+ test_bit(ctx->num, &dev->hwlock.bits), q->type);
+ MFC_TRACE_CTX("** ENC streamoff(type:%d)\n", q->type);
+
+ /* If a H/W operation is in progress, wait for it complete */
+ if (need_to_wait_nal_abort(ctx)) {
+ if (s5p_mfc_wait_for_done_ctx(ctx, S5P_FIMV_R2H_CMD_NAL_ABORT_RET)) {
+ mfc_err_ctx("time out during nal abort\n");
+ s5p_mfc_cleanup_work_bit_and_try_run(ctx);
+ }
+ aborted = 1;
+ }
+ MFC_TRACE_CTX_HWLOCK("**ENC streamoff(type:%d)\n", q->type);
+ ret = s5p_mfc_get_hwlock_ctx(ctx);
+ if (ret < 0) {
+ mfc_err_ctx("Failed to get hwlock\n");
+ return;
+ }
+
+ if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ s5p_mfc_cleanup_enc_dst_queue(ctx);
+
+ while (index < MFC_MAX_BUFFERS) {
+ index = find_next_bit(&ctx->dst_ctrls_avail,
+ MFC_MAX_BUFFERS, index);
+ if (index < MFC_MAX_BUFFERS)
+ call_cop(ctx, reset_buf_ctrls, &ctx->dst_ctrls[index]);
+ index++;
+ }
+ } else if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ if (ctx->state == MFCINST_RUNNING) {
+ s5p_mfc_change_state(ctx, MFCINST_FINISHING);
+ s5p_mfc_set_bit(ctx->num, &dev->work_bits);
+
+ while (s5p_mfc_get_buf(&ctx->buf_queue_lock, &ctx->dst_buf_queue, MFC_BUF_NO_TOUCH_USED)) {
+ ret = s5p_mfc_just_run(dev, ctx->num);
+ if (ret) {
+ mfc_err_ctx("Failed to run MFC\n");
+ break;
+ }
+ if (s5p_mfc_wait_for_done_ctx(ctx, S5P_FIMV_R2H_CMD_FRAME_DONE_RET)) {
+ mfc_err_ctx("Waiting for LAST_SEQ timed out\n");
+ break;
+ }
+ if (ctx->state == MFCINST_RUNNING) {
+ mfc_debug(2, "all encoded buffers out\n");
+ break;
+ }
+ }
+ }
+
+ s5p_mfc_move_all_bufs(&ctx->buf_queue_lock, &ctx->src_buf_queue,
+ &ctx->ref_buf_queue, MFC_QUEUE_ADD_BOTTOM);
+ s5p_mfc_cleanup_enc_src_queue(ctx);
+
+ while (index < MFC_MAX_BUFFERS) {
+ index = find_next_bit(&ctx->src_ctrls_avail,
+ MFC_MAX_BUFFERS, index);
+ if (index < MFC_MAX_BUFFERS)
+ call_cop(ctx, reset_buf_ctrls, &ctx->src_ctrls[index]);
+ index++;
+ }
+ }
+
+ if (aborted || ctx->state == MFCINST_FINISHING)
+ s5p_mfc_change_state(ctx, MFCINST_RUNNING);
+
+ mfc_debug(2, "buffer cleanup is done in stop_streaming, type : %d\n", q->type);
+
+ s5p_mfc_clear_bit(ctx->num, &dev->work_bits);
+ s5p_mfc_release_hwlock_ctx(ctx);
+
+ if (s5p_mfc_is_work_to_do(dev))
+ queue_work(dev->butler_wq, &dev->butler_work);
+}
+
+static void s5p_mfc_enc_buf_queue(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct s5p_mfc_ctx *ctx = vq->drv_priv;
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_buf *buf = vb_to_mfc_buf(vb);
+ int i;
+
+ mfc_debug_enter();
+
+ buf->next_index = 0;
+ buf->done_index = 0;
+
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ mfc_debug(2, "[BUFINFO] ctx[%d] add dst index: %d, addr: 0x%08llx\n",
+ ctx->num, vb->index, buf->addr[0][0]);
+
+ /* Mark destination as available for use by MFC */
+ s5p_mfc_add_tail_buf(&ctx->buf_queue_lock, &ctx->dst_buf_queue, buf);
+ } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ for (i = 0; i < ctx->src_fmt->mem_planes; i++)
+ mfc_debug(2, "[BUFINFO] ctx[%d] add src index: %d, addr[%d]: 0x%08llx\n",
+ ctx->num, vb->index, i, buf->addr[0][i]);
+ s5p_mfc_add_tail_buf(&ctx->buf_queue_lock, &ctx->src_buf_queue, buf);
+
+ if (debug_ts == 1)
+ mfc_info_ctx("[TS] framerate: %ld, timestamp: %lld\n",
+ ctx->framerate, buf->vb.vb2_buf.timestamp);
+
+ s5p_mfc_qos_update_last_framerate(ctx, buf->vb.vb2_buf.timestamp);
+ s5p_mfc_qos_update_framerate(ctx);
+ } else {
+ mfc_err_ctx("unsupported buffer type (%d)\n", vq->type);
+ }
+
+ if (s5p_mfc_enc_ctx_ready(ctx)) {
+ s5p_mfc_set_bit(ctx->num, &dev->work_bits);
+ }
+ s5p_mfc_try_run(dev);
+
+ mfc_debug_leave();
+}
+
+struct vb2_ops s5p_mfc_enc_qops = {
+ .queue_setup = s5p_mfc_enc_queue_setup,
+ .wait_prepare = s5p_mfc_enc_unlock,
+ .wait_finish = s5p_mfc_enc_lock,
+ .buf_init = s5p_mfc_enc_buf_init,
+ .buf_prepare = s5p_mfc_enc_buf_prepare,
+ .buf_finish = s5p_mfc_enc_buf_finish,
+ .buf_cleanup = s5p_mfc_enc_buf_cleanup,
+ .start_streaming = s5p_mfc_enc_start_streaming,
+ .stop_streaming = s5p_mfc_enc_stop_streaming,
+ .buf_queue = s5p_mfc_enc_buf_queue,
+};
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_hwfc_internal.h
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __MFC_HWFC_INTERNAL_H
+#define __MFC_HWFC_INTERNAL_H __FILE__
+
+#include "mfc_common.h"
+
+/*
+ * RGB encoding information to avoid confusion.
+ *
+ * V4L2_PIX_FMT_ARGB32 takes ARGB data like below.
+ * MSB LSB
+ * 3 2 1
+ * 2 4 6 8 0
+ * |B......BG......GR......RA......A|
+ */
+struct s5p_mfc_fmt enc_hwfc_formats[] = {
+ {
+ .name = "4:2:0 2 Planes Y/CbCr single",
+ .fourcc = V4L2_PIX_FMT_NV12N,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_FRAME,
+ .num_planes = 2,
+ .mem_planes = 1,
+ },
+ {
+ .name = "H264 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_H264,
+ .codec_mode = S5P_FIMV_CODEC_H264_ENC,
+ .type = MFC_FMT_STREAM,
+ .num_planes = 1,
+ .mem_planes = 1,
+ },
+ {
+ .name = "HEVC Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_HEVC,
+ .codec_mode = S5P_FIMV_CODEC_HEVC_ENC,
+ .type = MFC_FMT_STREAM,
+ .num_planes = 1,
+ .mem_planes = 1,
+ },
+};
+
+#define NUM_FORMATS ARRAY_SIZE(enc_hwfc_formats)
+
+#endif /* __MFC_HWFC_INTERNAL_H */
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_hwlock.c
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "mfc_hwlock.h"
+
+#include "mfc_nal_q.h"
+#include "mfc_otf.h"
+#include "mfc_opr.h"
+#include "mfc_sync.h"
+
+#include "mfc_inst.h"
+#include "mfc_pm.h"
+#include "mfc_cmd.h"
+#include "mfc_cal.h"
+#include "mfc_reg.h"
+
+#include "mfc_queue.h"
+#include "mfc_utils.h"
+
+static inline void mfc_print_hwlock(struct s5p_mfc_dev *dev)
+{
+ mfc_debug(2, "dev.hwlock.dev = 0x%lx, bits = 0x%lx, owned_by_irq = %d, wl_count = %d, transfer_owner = %d\n",
+ dev->hwlock.dev, dev->hwlock.bits, dev->hwlock.owned_by_irq,
+ dev->hwlock.wl_count, dev->hwlock.transfer_owner);
+}
+
+void s5p_mfc_init_hwlock(struct s5p_mfc_dev *dev)
+{
+ unsigned long flags;
+
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return;
+ }
+
+ spin_lock_init(&dev->hwlock.lock);
+ spin_lock_irqsave(&dev->hwlock.lock, flags);
+
+ INIT_LIST_HEAD(&dev->hwlock.waiting_list);
+ dev->hwlock.wl_count = 0;
+ dev->hwlock.bits = 0;
+ dev->hwlock.dev = 0;
+ dev->hwlock.owned_by_irq = 0;
+ dev->hwlock.transfer_owner = 0;
+
+ spin_unlock_irqrestore(&dev->hwlock.lock, flags);
+}
+
+static int mfc_remove_listable_wq_dev(struct s5p_mfc_dev *dev)
+{
+ struct s5p_mfc_listable_wq *listable_wq;
+ unsigned long flags;
+ int ret = -1;
+
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&dev->hwlock.lock, flags);
+ mfc_print_hwlock(dev);
+
+ list_for_each_entry(listable_wq, &dev->hwlock.waiting_list, list) {
+ if (!listable_wq->dev)
+ continue;
+
+ mfc_debug(2, "Found dev and will delete it!\n");
+
+ list_del(&listable_wq->list);
+ dev->hwlock.wl_count--;
+
+ ret = 0;
+ break;
+ }
+
+ mfc_print_hwlock(dev);
+ spin_unlock_irqrestore(&dev->hwlock.lock, flags);
+
+ return ret;
+}
+
+static int mfc_remove_listable_wq_ctx(struct s5p_mfc_ctx *curr_ctx)
+{
+ struct s5p_mfc_dev *dev;
+ struct s5p_mfc_listable_wq *listable_wq;
+ unsigned long flags;
+ int ret = -1;
+
+ if (!curr_ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return -EINVAL;
+ }
+
+ dev = curr_ctx->dev;
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&dev->hwlock.lock, flags);
+ mfc_print_hwlock(dev);
+
+ list_for_each_entry(listable_wq, &dev->hwlock.waiting_list, list) {
+ if (!listable_wq->ctx)
+ continue;
+
+ if (listable_wq->ctx->num == curr_ctx->num) {
+ mfc_debug(2, "Found ctx and will delete it (%d)!\n", curr_ctx->num);
+
+ list_del(&listable_wq->list);
+ dev->hwlock.wl_count--;
+ ret = 0;
+ break;
+ }
+ }
+
+ mfc_print_hwlock(dev);
+ spin_unlock_irqrestore(&dev->hwlock.lock, flags);
+
+ return ret;
+}
+
+/*
+ * Return value description
+ * 0: succeeded to get hwlock
+ * -EIO: failed to get hwlock (time out)
+ */
+int s5p_mfc_get_hwlock_dev(struct s5p_mfc_dev *dev)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&dev->hwlock_wq.wait_mutex);
+
+ spin_lock_irqsave(&dev->hwlock.lock, flags);
+ mfc_print_hwlock(dev);
+
+ if (dev->shutdown) {
+ mfc_info_dev("Couldn't lock HW. Shutdown was called\n");
+ spin_unlock_irqrestore(&dev->hwlock.lock, flags);
+ mutex_unlock(&dev->hwlock_wq.wait_mutex);
+ return -EINVAL;
+ }
+
+ if ((dev->hwlock.bits != 0) || (dev->hwlock.dev != 0)) {
+ list_add_tail(&dev->hwlock_wq.list, &dev->hwlock.waiting_list);
+ dev->hwlock.wl_count++;
+
+ spin_unlock_irqrestore(&dev->hwlock.lock, flags);
+
+ mfc_debug(2, "Waiting for hwlock to be released\n");
+
+ ret = wait_event_timeout(dev->hwlock_wq.wait_queue,
+ ((dev->hwlock.transfer_owner == 1) && (dev->hwlock.dev == 1)),
+ msecs_to_jiffies(MFC_HWLOCK_TIMEOUT));
+
+ MFC_TRACE_DEV_HWLOCK("get_hwlock_dev: before waiting\n");
+ MFC_TRACE_DEV_HWLOCK(">>dev:0x%lx, bits:0x%lx, owned:%d, wl:%d, trans:%d\n",
+ dev->hwlock.dev, dev->hwlock.bits, dev->hwlock.owned_by_irq,
+ dev->hwlock.wl_count, dev->hwlock.transfer_owner);
+
+ dev->hwlock.transfer_owner = 0;
+ mfc_remove_listable_wq_dev(dev);
+ if (ret == 0) {
+ mfc_err_dev("Woken up but timed out\n");
+ mfc_print_hwlock(dev);
+ mutex_unlock(&dev->hwlock_wq.wait_mutex);
+ return -EIO;
+ } else {
+ mfc_debug(2, "Woken up and got hwlock\n");
+ mfc_print_hwlock(dev);
+ mutex_unlock(&dev->hwlock_wq.wait_mutex);
+ }
+ } else {
+ dev->hwlock.bits = 0;
+ dev->hwlock.dev = 1;
+ dev->hwlock.owned_by_irq = 0;
+
+ MFC_TRACE_DEV_HWLOCK("get_hwlock_dev: no waiting\n");
+ MFC_TRACE_DEV_HWLOCK(">>dev:0x%lx, bits:0x%lx, owned:%d, wl:%d, trans:%d\n",
+ dev->hwlock.dev, dev->hwlock.bits, dev->hwlock.owned_by_irq,
+ dev->hwlock.wl_count, dev->hwlock.transfer_owner);
+
+ mfc_print_hwlock(dev);
+ spin_unlock_irqrestore(&dev->hwlock.lock, flags);
+ mutex_unlock(&dev->hwlock_wq.wait_mutex);
+ }
+
+ /* Stop NAL-Q after getting hwlock */
+ if (dev->nal_q_handle)
+ s5p_mfc_nal_q_stop_if_started(dev);
+
+ return 0;
+}
+
+/*
+ * Return value description
+ * 0: succeeded to get hwlock
+ * -EIO: failed to get hwlock (time out)
+ */
+int s5p_mfc_get_hwlock_ctx(struct s5p_mfc_ctx *curr_ctx)
+{
+ struct s5p_mfc_dev *dev;
+ struct s5p_mfc_ctx *ctx = curr_ctx;
+ int ret = 0;
+ unsigned long flags;
+
+ if (!curr_ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return -EINVAL;
+ }
+
+ dev = curr_ctx->dev;
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&curr_ctx->hwlock_wq.wait_mutex);
+
+ spin_lock_irqsave(&dev->hwlock.lock, flags);
+ mfc_print_hwlock(dev);
+
+ if (dev->shutdown) {
+ mfc_info_dev("Couldn't lock HW. Shutdown was called\n");
+ spin_unlock_irqrestore(&dev->hwlock.lock, flags);
+ mutex_unlock(&curr_ctx->hwlock_wq.wait_mutex);
+ return -EINVAL;
+ }
+
+ if ((dev->hwlock.bits != 0) || (dev->hwlock.dev != 0)) {
+ list_add_tail(&curr_ctx->hwlock_wq.list, &dev->hwlock.waiting_list);
+ dev->hwlock.wl_count++;
+
+ spin_unlock_irqrestore(&dev->hwlock.lock, flags);
+
+ MFC_TRACE_CTX_HWLOCK("get_hwlock_ctx: before waiting\n");
+ MFC_TRACE_CTX_HWLOCK(">>dev:0x%lx, bits:0x%lx, owned:%d, wl:%d, trans:%d\n",
+ dev->hwlock.dev, dev->hwlock.bits, dev->hwlock.owned_by_irq,
+ dev->hwlock.wl_count, dev->hwlock.transfer_owner);
+
+ mfc_debug(2, "Waiting for hwlock to be released\n");
+
+ ret = wait_event_timeout(curr_ctx->hwlock_wq.wait_queue,
+ ((dev->hwlock.transfer_owner == 1) && (test_bit(curr_ctx->num, &dev->hwlock.bits))),
+ msecs_to_jiffies(MFC_HWLOCK_TIMEOUT));
+
+ MFC_TRACE_CTX_HWLOCK("get_hwlock_ctx: after waiting, ret:%d\n", ret);
+ MFC_TRACE_CTX_HWLOCK(">>dev:0x%lx, bits:0x%lx, owned:%d, wl:%d, trans:%d\n",
+ dev->hwlock.dev, dev->hwlock.bits, dev->hwlock.owned_by_irq,
+ dev->hwlock.wl_count, dev->hwlock.transfer_owner);
+
+ dev->hwlock.transfer_owner = 0;
+ mfc_remove_listable_wq_ctx(curr_ctx);
+ if (ret == 0) {
+ mfc_err_dev("Woken up but timed out\n");
+ mfc_print_hwlock(dev);
+ mutex_unlock(&curr_ctx->hwlock_wq.wait_mutex);
+ return -EIO;
+ } else {
+ mfc_debug(2, "Woken up and got hwlock\n");
+ mfc_print_hwlock(dev);
+ mutex_unlock(&curr_ctx->hwlock_wq.wait_mutex);
+ }
+ } else {
+ dev->hwlock.bits = 0;
+ dev->hwlock.dev = 0;
+ set_bit(curr_ctx->num, &dev->hwlock.bits);
+ dev->hwlock.owned_by_irq = 0;
+
+ MFC_TRACE_CTX_HWLOCK("get_hwlock_ctx: no waiting\n");
+ MFC_TRACE_CTX_HWLOCK(">>dev:0x%lx, bits:0x%lx, owned:%d, wl:%d, trans:%d\n",
+ dev->hwlock.dev, dev->hwlock.bits, dev->hwlock.owned_by_irq,
+ dev->hwlock.wl_count, dev->hwlock.transfer_owner);
+
+ mfc_print_hwlock(dev);
+ spin_unlock_irqrestore(&dev->hwlock.lock, flags);
+ mutex_unlock(&curr_ctx->hwlock_wq.wait_mutex);
+ }
+
+ /* Stop NAL-Q after getting hwlock */
+ if (dev->nal_q_handle)
+ s5p_mfc_nal_q_stop_if_started(dev);
+
+ return 0;
+}
+
+/*
+ * Return value description
+ * 0: succeeded to release hwlock
+ * 1: succeeded to release hwlock, hwlock is captured by another module
+ * -1: error since device is waiting again.
+ */
+int s5p_mfc_release_hwlock_dev(struct s5p_mfc_dev *dev)
+{
+ struct s5p_mfc_listable_wq *listable_wq;
+ unsigned long flags;
+ int ret = -1;
+
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&dev->hwlock.lock, flags);
+ mfc_print_hwlock(dev);
+
+ dev->hwlock.dev = 0;
+ dev->hwlock.owned_by_irq = 0;
+
+ if (dev->shutdown) {
+ mfc_debug(2, "Couldn't wakeup module. Shutdown was called\n");
+ ret = 0;
+ } else if (list_empty(&dev->hwlock.waiting_list)) {
+ mfc_debug(2, "No waiting module\n");
+ ret = 0;
+ } else {
+ mfc_debug(2, "There is a waiting module\n");
+ listable_wq = list_entry(dev->hwlock.waiting_list.next, struct s5p_mfc_listable_wq, list);
+ list_del(&listable_wq->list);
+ dev->hwlock.wl_count--;
+
+ if (listable_wq->dev) {
+ mfc_debug(2, "Waking up dev\n");
+ dev->hwlock.dev = 1;
+ } else {
+ mfc_debug(2, "Waking up another ctx\n");
+ set_bit(listable_wq->ctx->num, &dev->hwlock.bits);
+ }
+
+ dev->hwlock.transfer_owner = 1;
+
+ MFC_TRACE_DEV_HWLOCK("release_hwlock_dev: wakeup\n");
+ MFC_TRACE_DEV_HWLOCK(">>dev:0x%lx, bits:0x%lx, owned:%d, wl:%d, trans:%d\n",
+ dev->hwlock.dev, dev->hwlock.bits, dev->hwlock.owned_by_irq,
+ dev->hwlock.wl_count, dev->hwlock.transfer_owner);
+
+ wake_up(&listable_wq->wait_queue);
+ ret = 1;
+ }
+
+ mfc_print_hwlock(dev);
+ spin_unlock_irqrestore(&dev->hwlock.lock, flags);
+ return ret;
+}
+
+/*
+ * Should be called with hwlock.lock
+ *
+ * Return value description
+ * 0: succeeded to release hwlock
+ * 1: succeeded to release hwlock, hwlock is captured by another module
+ */
+static int mfc_release_hwlock_ctx_protected(struct s5p_mfc_ctx *curr_ctx)
+{
+ struct s5p_mfc_dev *dev;
+ struct s5p_mfc_ctx *ctx = curr_ctx;
+ struct s5p_mfc_listable_wq *listable_wq;
+ int ret = -1;
+
+ if (!curr_ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return -EINVAL;
+ }
+
+ dev = curr_ctx->dev;
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ mfc_print_hwlock(dev);
+ clear_bit(curr_ctx->num, &dev->hwlock.bits);
+ dev->hwlock.owned_by_irq = 0;
+
+ if (dev->shutdown) {
+ mfc_debug(2, "Couldn't wakeup module. Shutdown was called\n");
+ ret = 0;
+ } else if (list_empty(&dev->hwlock.waiting_list)) {
+ mfc_debug(2, "No waiting module\n");
+ ret = 0;
+ } else {
+ mfc_debug(2, "There is a waiting module\n");
+ listable_wq = list_entry(dev->hwlock.waiting_list.next, struct s5p_mfc_listable_wq, list);
+ list_del(&listable_wq->list);
+ dev->hwlock.wl_count--;
+
+ if (listable_wq->dev) {
+ mfc_debug(2, "Waking up dev\n");
+ dev->hwlock.dev = 1;
+ } else {
+ mfc_debug(2, "Waking up another ctx\n");
+ set_bit(listable_wq->ctx->num, &dev->hwlock.bits);
+ }
+
+ dev->hwlock.transfer_owner = 1;
+
+ MFC_TRACE_CTX_HWLOCK("release_hwlock_ctx: wakeup\n");
+ MFC_TRACE_CTX_HWLOCK(">>dev:0x%lx, bits:0x%lx, owned:%d, wl:%d, trans:%d\n",
+ dev->hwlock.dev, dev->hwlock.bits, dev->hwlock.owned_by_irq,
+ dev->hwlock.wl_count, dev->hwlock.transfer_owner);
+
+ wake_up(&listable_wq->wait_queue);
+ ret = 1;
+ }
+
+ mfc_print_hwlock(dev);
+ return ret;
+}
+
+/*
+ * Return value description
+ * 0: succeeded to release hwlock
+ * 1: succeeded to release hwlock, hwlock is captured by another module
+ */
+int s5p_mfc_release_hwlock_ctx(struct s5p_mfc_ctx *curr_ctx)
+{
+ struct s5p_mfc_dev *dev;
+ unsigned long flags;
+ int ret = -1;
+
+ if (!curr_ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return -EINVAL;
+ }
+
+ dev = curr_ctx->dev;
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&dev->hwlock.lock, flags);
+ ret = mfc_release_hwlock_ctx_protected(curr_ctx);
+ spin_unlock_irqrestore(&dev->hwlock.lock, flags);
+ return ret;
+}
+
+static inline int mfc_yield_hwlock(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *curr_ctx)
+{
+ unsigned long flags;
+
+ if (!curr_ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return -EINVAL;
+ }
+
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&dev->hwlock.lock, flags);
+
+ mfc_release_hwlock_ctx_protected(curr_ctx);
+
+ spin_unlock_irqrestore(&dev->hwlock.lock, flags);
+
+ /* Trigger again if other instance's work is waiting */
+ if (s5p_mfc_is_work_to_do(dev))
+ queue_work(dev->butler_wq, &dev->butler_work);
+
+ return 0;
+}
+
+/*
+ * Should be called with hwlock.lock
+ */
+static inline void mfc_transfer_hwlock_ctx_protected(struct s5p_mfc_dev *dev, int curr_ctx_index)
+{
+ dev->hwlock.dev = 0;
+ dev->hwlock.bits = 0;
+ set_bit(curr_ctx_index, &dev->hwlock.bits);
+}
+
+/*
+ * Should be called with hwlock.lock
+ *
+ * Return value description
+ * >=0: succeeded to get hwlock_bit for the context, index of new context
+ * -1, -EINVAL: failed to get hwlock_bit for a context
+ */
+static int mfc_try_to_get_new_ctx_protected(struct s5p_mfc_dev *dev)
+{
+ int ret = 0;
+ int index;
+ struct s5p_mfc_ctx *new_ctx;
+
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ if (dev->shutdown) {
+ mfc_info_dev("Couldn't lock HW. Shutdown was called\n");
+ return -EINVAL;
+ }
+
+ if (dev->sleep) {
+ mfc_info_dev("Couldn't lock HW. Sleep was called\n");
+ return -EINVAL;
+ }
+
+ /* Check whether hardware is not running */
+ if ((dev->hwlock.bits != 0) || (dev->hwlock.dev != 0)) {
+ /* This is perfectly ok, the scheduled ctx should wait */
+ mfc_debug(2, "Couldn't lock HW\n");
+ return -1;
+ }
+
+ /* Choose the context to run */
+ index = s5p_mfc_get_new_ctx(dev);
+ if (index < 0) {
+ /* This is perfectly ok, the scheduled ctx should wait
+ * No contexts to run
+ */
+ mfc_debug(2, "No ctx is scheduled to be run\n");
+ ret = -1;
+ return ret;
+ }
+
+ new_ctx = dev->ctx[index];
+ if (!new_ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ ret = -1;
+ return ret;
+ }
+
+ set_bit(new_ctx->num, &dev->hwlock.bits);
+ ret = index;
+
+ return ret;
+}
+
+/*
+ * Should be called without hwlock holding
+ *
+ * Try to run an operation on hardware
+ */
+void s5p_mfc_try_run(struct s5p_mfc_dev *dev)
+{
+ int new_ctx_index;
+ int ret;
+ unsigned long flags;
+
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return;
+ }
+
+ spin_lock_irqsave(&dev->hwlock.lock, flags);
+ mfc_print_hwlock(dev);
+
+ new_ctx_index = mfc_try_to_get_new_ctx_protected(dev);
+ if (new_ctx_index < 0) {
+ mfc_debug(2, "Failed to get new context to run\n");
+ mfc_print_hwlock(dev);
+ spin_unlock_irqrestore(&dev->hwlock.lock, flags);
+ return;
+ }
+
+ dev->hwlock.owned_by_irq = 1;
+
+ mfc_print_hwlock(dev);
+ spin_unlock_irqrestore(&dev->hwlock.lock, flags);
+
+ ret = s5p_mfc_just_run(dev, new_ctx_index);
+ if (ret)
+ mfc_yield_hwlock(dev, dev->ctx[new_ctx_index]);
+}
+
+/*
+ * Should be called without hwlock holding
+ *
+ */
+void s5p_mfc_cleanup_work_bit_and_try_run(struct s5p_mfc_ctx *curr_ctx)
+{
+ struct s5p_mfc_dev *dev;
+
+ if (!curr_ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return;
+ }
+
+ dev = curr_ctx->dev;
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return;
+ }
+
+ s5p_mfc_clear_bit(curr_ctx->num, &dev->work_bits);
+
+ s5p_mfc_try_run(dev);
+}
+
+void s5p_mfc_cache_flush(struct s5p_mfc_dev *dev, int is_drm)
+{
+ s5p_mfc_cmd_cache_flush(dev);
+ if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_CACHE_FLUSH_RET)) {
+ mfc_err_dev("Failed to CACHE_FLUSH\n");
+ dev->logging_data->cause |= (1 << MFC_CAUSE_FAIL_CHACHE_FLUSH);
+ call_dop(dev, dump_and_stop_always, dev);
+ }
+
+ s5p_mfc_pm_clock_off(dev);
+ dev->curr_ctx_is_drm = is_drm;
+ s5p_mfc_pm_clock_on_with_base(dev, (is_drm ? MFCBUF_DRM : MFCBUF_NORMAL));
+}
+
+/*
+ * Return value description
+ * 0: NAL-Q is handled successfully
+ * 1: NAL_START command should be handled
+ * -1: Error
+*/
+static int mfc_nal_q_just_run(struct s5p_mfc_ctx *ctx, int need_cache_flush)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ unsigned int ret = -1;
+
+ nal_queue_handle *nal_q_handle = dev->nal_q_handle;
+
+ if (!nal_q_handle) {
+ mfc_err_dev("nal_q_handle is NULL\n");
+ return ret;
+ }
+
+ switch (nal_q_handle->nal_q_state) {
+ case NAL_Q_STATE_CREATED:
+ if (s5p_mfc_nal_q_check_enable(dev) == 0) {
+ /* NAL START */
+ ret = 1;
+ } else {
+ s5p_mfc_nal_q_clock_on(dev, nal_q_handle);
+
+ s5p_mfc_nal_q_init(dev, nal_q_handle);
+
+ /* enable NAL QUEUE */
+ if (need_cache_flush)
+ s5p_mfc_cache_flush(dev, ctx->is_drm);
+
+ mfc_info_ctx("[NALQ] start NAL QUEUE\n");
+ s5p_mfc_nal_q_start(dev, nal_q_handle);
+
+ if (s5p_mfc_nal_q_enqueue_in_buf(dev, ctx, nal_q_handle->nal_q_in_handle)) {
+ mfc_debug(2, "[NALQ] Failed to enqueue input data\n");
+ s5p_mfc_nal_q_clock_off(dev, nal_q_handle);
+ }
+
+ s5p_mfc_clear_bit(ctx->num, &dev->work_bits);
+ if ((s5p_mfc_ctx_ready(ctx) && !ctx->clear_work_bit) ||
+ nal_q_handle->nal_q_exception)
+ s5p_mfc_set_bit(ctx->num, &dev->work_bits);
+ ctx->clear_work_bit = 0;
+
+ s5p_mfc_release_hwlock_ctx(ctx);
+
+ if (s5p_mfc_is_work_to_do(dev))
+ queue_work(dev->butler_wq, &dev->butler_work);
+
+ ret = 0;
+ }
+ break;
+ case NAL_Q_STATE_STARTED:
+ s5p_mfc_nal_q_clock_on(dev, nal_q_handle);
+
+ if (s5p_mfc_nal_q_check_enable(dev) == 0 ||
+ nal_q_handle->nal_q_exception) {
+ /* disable NAL QUEUE */
+ s5p_mfc_nal_q_stop(dev, nal_q_handle);
+ mfc_info_ctx("[NALQ] stop NAL QUEUE\n");
+ if (s5p_mfc_wait_for_done_dev(dev,
+ S5P_FIMV_R2H_CMD_COMPLETE_QUEUE_RET)) {
+ mfc_err_dev("[NALQ] Failed to stop queue\n");
+ dev->logging_data->cause |= (1 << MFC_CAUSE_FAIL_STOP_NAL_Q);
+ call_dop(dev, dump_and_stop_always, dev);
+ }
+ ret = 1;
+ break;
+ } else {
+ /* NAL QUEUE */
+ if (s5p_mfc_nal_q_enqueue_in_buf(dev, ctx, nal_q_handle->nal_q_in_handle)) {
+ mfc_debug(2, "[NALQ] Failed to enqueue input data\n");
+ s5p_mfc_nal_q_clock_off(dev, nal_q_handle);
+ }
+
+ s5p_mfc_clear_bit(ctx->num, &dev->work_bits);
+
+ if ((s5p_mfc_ctx_ready(ctx) && !ctx->clear_work_bit) ||
+ nal_q_handle->nal_q_exception)
+ s5p_mfc_set_bit(ctx->num, &dev->work_bits);
+ ctx->clear_work_bit = 0;
+
+ s5p_mfc_release_hwlock_ctx(ctx);
+
+ if (s5p_mfc_is_work_to_do(dev))
+ queue_work(dev->butler_wq, &dev->butler_work);
+ ret = 0;
+ }
+ break;
+ default:
+ mfc_info_ctx("[NALQ] can't try command, nal_q_state : %d\n",
+ nal_q_handle->nal_q_state);
+ ret = -1;
+ break;
+ }
+
+ return ret;
+}
+
+static int mfc_just_run_dec(struct s5p_mfc_ctx *ctx)
+{
+ int ret = 0;
+
+ switch (ctx->state) {
+ case MFCINST_FINISHING:
+ ret = s5p_mfc_run_dec_last_frames(ctx);
+ break;
+ case MFCINST_RUNNING:
+ case MFCINST_SPECIAL_PARSING_NAL:
+ ret = s5p_mfc_run_dec_frame(ctx);
+ break;
+ case MFCINST_INIT:
+ ret = s5p_mfc_open_inst(ctx);
+ break;
+ case MFCINST_RETURN_INST:
+ ret = s5p_mfc_close_inst(ctx);
+ break;
+ case MFCINST_GOT_INST:
+ case MFCINST_SPECIAL_PARSING:
+ ret = s5p_mfc_run_dec_init(ctx);
+ break;
+ case MFCINST_HEAD_PARSED:
+ if (ctx->codec_buffer_allocated == 0) {
+ ctx->clear_work_bit = 1;
+ mfc_err_ctx("codec buffer is not allocated\n");
+ ret = -EAGAIN;
+ break;
+ }
+ ret = s5p_mfc_cmd_dec_init_buffers(ctx);
+ break;
+ case MFCINST_RES_CHANGE_INIT:
+ ret = s5p_mfc_run_dec_last_frames(ctx);
+ break;
+ case MFCINST_RES_CHANGE_FLUSH:
+ ret = s5p_mfc_run_dec_last_frames(ctx);
+ break;
+ case MFCINST_RES_CHANGE_END:
+ mfc_debug(2, "[DRC] Finished remaining frames after resolution change\n");
+ ctx->capture_state = QUEUE_FREE;
+ mfc_debug(2, "[DRC] Will re-init the codec\n");
+ ret = s5p_mfc_run_dec_init(ctx);
+ break;
+ case MFCINST_DPB_FLUSHING:
+ ret = s5p_mfc_cmd_dpb_flush(ctx);
+ break;
+ default:
+ mfc_info_ctx("can't try command(decoder just_run), state : %d\n", ctx->state);
+ ret = -EAGAIN;
+ }
+
+ return ret;
+}
+
+static int mfc_just_run_enc(struct s5p_mfc_ctx *ctx)
+{
+ int ret = 0;
+
+ switch (ctx->state) {
+ case MFCINST_FINISHING:
+ ret = s5p_mfc_run_enc_last_frames(ctx);
+ break;
+ case MFCINST_RUNNING:
+ if (ctx->otf_handle) {
+ ret = s5p_mfc_otf_run_enc_frame(ctx);
+ break;
+ }
+ ret = s5p_mfc_run_enc_frame(ctx);
+ break;
+ case MFCINST_INIT:
+ ret = s5p_mfc_open_inst(ctx);
+ break;
+ case MFCINST_RETURN_INST:
+ ret = s5p_mfc_close_inst(ctx);
+ break;
+ case MFCINST_GOT_INST:
+ if (ctx->otf_handle) {
+ ret = s5p_mfc_otf_run_enc_init(ctx);
+ break;
+ }
+ ret = s5p_mfc_run_enc_init(ctx);
+ break;
+ case MFCINST_HEAD_PARSED:
+ ret = s5p_mfc_cmd_enc_init_buffers(ctx);
+ break;
+ case MFCINST_ABORT_INST:
+ ret = s5p_mfc_abort_inst(ctx);
+ break;
+ default:
+ mfc_info_ctx("can't try command(encoder just_run), state : %d\n", ctx->state);
+ ret = -EAGAIN;
+ }
+
+ return ret;
+}
+
+/* Run an operation on hardware */
+int s5p_mfc_just_run(struct s5p_mfc_dev *dev, int new_ctx_index)
+{
+ struct s5p_mfc_ctx *ctx;
+ unsigned int ret = 0;
+ int need_cache_flush = 0;
+
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ ctx = dev->ctx[new_ctx_index];
+ if (!ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return -EINVAL;
+ }
+
+ if (ctx->state == MFCINST_RUNNING)
+ s5p_mfc_clean_ctx_int_flags(ctx);
+
+ mfc_debug(2, "New context: %d\n", new_ctx_index);
+ dev->curr_ctx = ctx->num;
+
+ /* Got context to run in ctx */
+ mfc_debug(2, "src: %d, dst: %d, state: %d, dpb_count = %d\n",
+ s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->src_buf_queue),
+ s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->dst_buf_queue),
+ ctx->state, ctx->dpb_count);
+ mfc_debug(2, "ctx->state = %d\n", ctx->state);
+ /* Last frame has already been sent to MFC
+ * Now obtaining frames from MFC buffer */
+
+ /* Check if cache flush command is needed */
+ if (dev->curr_ctx_is_drm != ctx->is_drm)
+ need_cache_flush = 1;
+ else
+ dev->curr_ctx_is_drm = ctx->is_drm;
+
+ mfc_debug(2, "need_cache_flush = %d, is_drm = %d\n", need_cache_flush, ctx->is_drm);
+
+ if (dev->nal_q_handle) {
+ ret = mfc_nal_q_just_run(ctx, need_cache_flush);
+ if (ret == 0) {
+ mfc_debug(2, "NAL_Q was handled\n");
+ return ret;
+ } else if (ret == 1){
+ /* Path through */
+ mfc_debug(2, "NAL_START will be handled\n");
+ } else {
+ return ret;
+ }
+ }
+
+ mfc_debug(2, "continue_clock_on = %d\n", dev->continue_clock_on);
+ if (!dev->continue_clock_on) {
+ s5p_mfc_pm_clock_on(dev);
+ } else {
+ dev->continue_clock_on = false;
+ }
+
+ if (need_cache_flush)
+ s5p_mfc_cache_flush(dev, ctx->is_drm);
+
+ if (ctx->type == MFCINST_DECODER) {
+ ret = mfc_just_run_dec(ctx);
+ } else if (ctx->type == MFCINST_ENCODER) {
+ ret = mfc_just_run_enc(ctx);
+ } else {
+ mfc_err_ctx("invalid context type: %d\n", ctx->type);
+ ret = -EAGAIN;
+ }
+
+ if (ret) {
+ /* Check again the ctx condition and clear work bits
+ * if ctx is not available. */
+ if (s5p_mfc_ctx_ready(ctx) == 0 || ctx->clear_work_bit) {
+ s5p_mfc_clear_bit(ctx->num, &dev->work_bits);
+ ctx->clear_work_bit = 0;
+ }
+
+ s5p_mfc_pm_clock_off(dev);
+ }
+
+ return ret;
+}
+
+void s5p_mfc_hwlock_handler_irq(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *curr_ctx,
+ unsigned int reason, unsigned int err)
+{
+ int new_ctx_index;
+ unsigned long flags;
+ int ret;
+
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return;
+ }
+
+ if (!curr_ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return;
+ }
+
+ spin_lock_irqsave(&dev->hwlock.lock, flags);
+ mfc_print_hwlock(dev);
+
+ if (dev->hwlock.owned_by_irq) {
+ if (dev->preempt_ctx > MFC_NO_INSTANCE_SET) {
+ mfc_debug(2, "There is a preempt_ctx\n");
+ dev->continue_clock_on = true;
+ s5p_mfc_wake_up_ctx(curr_ctx, reason, err);
+ new_ctx_index = dev->preempt_ctx;
+ mfc_debug(2, "preempt_ctx is : %d\n", new_ctx_index);
+
+ spin_unlock_irqrestore(&dev->hwlock.lock, flags);
+
+ ret = s5p_mfc_just_run(dev, new_ctx_index);
+ if (ret) {
+ dev->continue_clock_on = false;
+ mfc_yield_hwlock(dev, dev->ctx[new_ctx_index]);
+ }
+ } else if (!list_empty(&dev->hwlock.waiting_list)) {
+ mfc_debug(2, "There is a waiting module for hwlock\n");
+ dev->continue_clock_on = false;
+ s5p_mfc_pm_clock_off(dev);
+
+ spin_unlock_irqrestore(&dev->hwlock.lock, flags);
+
+ s5p_mfc_release_hwlock_ctx(curr_ctx);
+ s5p_mfc_wake_up_ctx(curr_ctx, reason, err);
+ queue_work(dev->butler_wq, &dev->butler_work);
+ } else {
+ mfc_debug(2, "No preempt_ctx and no waiting module\n");
+ new_ctx_index = s5p_mfc_get_new_ctx(dev);
+ if (new_ctx_index < 0) {
+ mfc_debug(2, "No ctx to run\n");
+ /* No contexts to run */
+ dev->continue_clock_on = false;
+ s5p_mfc_pm_clock_off(dev);
+
+ spin_unlock_irqrestore(&dev->hwlock.lock, flags);
+
+ s5p_mfc_release_hwlock_ctx(curr_ctx);
+ s5p_mfc_wake_up_ctx(curr_ctx, reason, err);
+ queue_work(dev->butler_wq, &dev->butler_work);
+ } else {
+ mfc_debug(2, "There is a ctx to run\n");
+ dev->continue_clock_on = true;
+ s5p_mfc_wake_up_ctx(curr_ctx, reason, err);
+
+ /* If cache flush command is needed or there is OTF handle, handler should stop */
+ if ((dev->curr_ctx_is_drm != dev->ctx[new_ctx_index]->is_drm) ||
+ dev->ctx[new_ctx_index]->otf_handle) {
+ mfc_debug(2, "Secure and nomal switching or OTF mode\n");
+ mfc_debug(2, "DRM attribute %d->%d\n",
+ dev->curr_ctx_is_drm, dev->ctx[new_ctx_index]->is_drm);
+
+ spin_unlock_irqrestore(&dev->hwlock.lock, flags);
+
+ s5p_mfc_release_hwlock_ctx(curr_ctx);
+ queue_work(dev->butler_wq, &dev->butler_work);
+ } else {
+ mfc_debug(2, "Work to do successively (next ctx: %d)\n", new_ctx_index);
+ mfc_transfer_hwlock_ctx_protected(dev, new_ctx_index);
+
+ spin_unlock_irqrestore(&dev->hwlock.lock, flags);
+
+ ret = s5p_mfc_just_run(dev, new_ctx_index);
+ if (ret) {
+ dev->continue_clock_on = false;
+ mfc_yield_hwlock(dev, dev->ctx[new_ctx_index]);
+ }
+ }
+ }
+ }
+ } else {
+ mfc_debug(2, "hwlock is NOT owned by irq\n");
+ dev->continue_clock_on = false;
+ s5p_mfc_pm_clock_off(dev);
+ s5p_mfc_wake_up_ctx(curr_ctx, reason, err);
+ queue_work(dev->butler_wq, &dev->butler_work);
+
+ spin_unlock_irqrestore(&dev->hwlock.lock, flags);
+ }
+ mfc_print_hwlock(dev);
+}
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_hwlock.h
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __MFC_HWLOCK_H
+#define __MFC_HWLOCK_H __FILE__
+
+#include "mfc_common.h"
+
+static inline void s5p_mfc_init_listable_wq_dev(struct s5p_mfc_dev *dev)
+{
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return;
+ }
+
+ INIT_LIST_HEAD(&dev->hwlock_wq.list);
+ init_waitqueue_head(&dev->hwlock_wq.wait_queue);
+ mutex_init(&dev->hwlock_wq.wait_mutex);
+ dev->hwlock_wq.ctx = NULL;
+ dev->hwlock_wq.dev = dev;
+}
+
+static inline void s5p_mfc_init_listable_wq_ctx(struct s5p_mfc_ctx *curr_ctx)
+{
+ if (!curr_ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return;
+ }
+
+ INIT_LIST_HEAD(&curr_ctx->hwlock_wq.list);
+ init_waitqueue_head(&curr_ctx->hwlock_wq.wait_queue);
+ mutex_init(&curr_ctx->hwlock_wq.wait_mutex);
+ curr_ctx->hwlock_wq.ctx = curr_ctx;
+ curr_ctx->hwlock_wq.dev = NULL;
+}
+
+static inline void s5p_mfc_destroy_listable_wq_dev(struct s5p_mfc_dev *dev)
+{
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return;
+ }
+
+ mutex_destroy(&dev->hwlock_wq.wait_mutex);
+}
+
+static inline void s5p_mfc_destroy_listable_wq_ctx(struct s5p_mfc_ctx *curr_ctx)
+{
+ if (!curr_ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return;
+ }
+
+ mutex_destroy(&curr_ctx->hwlock_wq.wait_mutex);
+}
+
+void s5p_mfc_init_hwlock(struct s5p_mfc_dev *dev);
+
+int s5p_mfc_get_hwlock_dev(struct s5p_mfc_dev *dev);
+int s5p_mfc_get_hwlock_ctx(struct s5p_mfc_ctx *curr_ctx);
+
+int s5p_mfc_release_hwlock_dev(struct s5p_mfc_dev *dev);
+int s5p_mfc_release_hwlock_ctx(struct s5p_mfc_ctx *curr_ctx);
+
+void s5p_mfc_cache_flush(struct s5p_mfc_dev *dev, int is_drm);
+
+void s5p_mfc_try_run(struct s5p_mfc_dev *dev);
+void s5p_mfc_cleanup_work_bit_and_try_run(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_just_run(struct s5p_mfc_dev *dev, int new_ctx_index);
+
+void s5p_mfc_hwlock_handler_irq(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx,
+ unsigned int reason, unsigned int err);
+
+#endif /* __MFC_HWLOCK_H */
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_inst.c
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "mfc_inst.h"
+
+#include "mfc_cmd.h"
+#include "mfc_enc_param.h"
+#include "mfc_cal.h"
+#include "mfc_perf_measure.h"
+#include "mfc_reg.h"
+
+#include "mfc_utils.h"
+
+int s5p_mfc_open_inst(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ unsigned int reg;
+ int ret;
+
+ /* Preparing decoding - getting instance number */
+ mfc_debug(2, "Getting instance number\n");
+ s5p_mfc_clean_ctx_int_flags(ctx);
+
+ reg = MFC_READL(S5P_FIMV_CODEC_CONTROL);
+ /* Clear OTF_CONTROL[2:1] & OTF_DEBUG[3] */
+ reg &= ~(0x7 << 1);
+ if (ctx->otf_handle) {
+ /* Set OTF_CONTROL[2:1], 0: Non-OTF, 1: OTF+HWFC, 2: OTF only */
+ reg |= (0x1 << 1);
+ mfc_info_ctx("HWFC + OTF enabled\n");
+ if (otf_dump && !ctx->is_drm) {
+ /* Set OTF_DEBUG[3] for OTF path dump */
+ reg |= (0x1 << 3);
+ mfc_info_ctx("Debugging mode enabled\n");
+ }
+ }
+ MFC_WRITEL(reg, S5P_FIMV_CODEC_CONTROL);
+
+
+ ret = s5p_mfc_cmd_open_inst(ctx);
+ if (ret) {
+ mfc_err_ctx("Failed to create a new instance\n");
+ s5p_mfc_change_state(ctx, MFCINST_ERROR);
+ }
+
+ return ret;
+}
+
+int s5p_mfc_close_inst(struct s5p_mfc_ctx *ctx)
+{
+ int ret = -EINVAL;
+
+ /* Closing decoding instance */
+ mfc_debug(2, "Returning instance number\n");
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ if (ctx->state == MFCINST_FREE) {
+ mfc_err_ctx("ctx already free status\n");
+ return ret;
+ }
+
+ ret = s5p_mfc_cmd_close_inst(ctx);
+ if (ret) {
+ mfc_err_ctx("Failed to return an instance\n");
+ s5p_mfc_change_state(ctx, MFCINST_ERROR);
+ }
+
+ return ret;
+}
+
+int s5p_mfc_abort_inst(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev;
+
+ if (!ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return -EINVAL;
+ }
+
+ dev = ctx->dev;
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ s5p_mfc_clean_ctx_int_flags(ctx);
+
+ MFC_WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID);
+ s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_NAL_ABORT);
+
+ return 0;
+}
+
+/* Initialize decoding */
+int s5p_mfc_init_decode(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev;
+ struct s5p_mfc_dec *dec;
+ unsigned int reg = 0;
+ int fmo_aso_ctrl = 0;
+
+ mfc_debug_enter();
+ if (!ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return -EINVAL;
+ }
+
+ dev = ctx->dev;
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ dec = ctx->dec_priv;
+ if (!dec) {
+ mfc_err_dev("no mfc decoder to run\n");
+ return -EINVAL;
+ }
+ mfc_debug(2, "InstNo: %d/%d\n", ctx->inst_no, S5P_FIMV_H2R_CMD_SEQ_HEADER);
+ mfc_debug(2, "BUFs: %08x\n", MFC_READL(S5P_FIMV_D_CPB_BUFFER_ADDR));
+
+ /* When user sets desplay_delay to 0,
+ * It works as "display_delay enable" and delay set to 0.
+ * If user wants display_delay disable, It should be
+ * set to negative value. */
+ if (dec->display_delay >= 0) {
+ reg |= (0x1 << S5P_FIMV_D_DEC_OPT_DISPLAY_DELAY_EN_SHIFT);
+ MFC_WRITEL(dec->display_delay, S5P_FIMV_D_DISPLAY_DELAY);
+ }
+
+ /* FMO_ASO_CTRL - 0: Enable, 1: Disable */
+ reg |= ((fmo_aso_ctrl & S5P_FIMV_D_DEC_OPT_FMO_ASO_CTRL_MASK)
+ << S5P_FIMV_D_DEC_OPT_FMO_ASO_CTRL_SHIFT);
+
+ reg |= ((dec->idr_decoding & S5P_FIMV_D_DEC_OPT_IDR_DECODING_MASK)
+ << S5P_FIMV_D_DEC_OPT_IDR_DECODING_SHIFT);
+
+ /* VC1 RCV: Discard to parse additional header as default */
+ if (IS_VC1_RCV_DEC(ctx))
+ reg |= (0x1 << S5P_FIMV_D_DEC_OPT_DISCARD_RCV_HEADER_SHIFT);
+
+ /* conceal control to specific color */
+ reg |= (0x4 << S5P_FIMV_D_DEC_OPT_CONCEAL_CONTROL_SHIFT);
+
+ /* Disable parallel processing if nal_q_parallel_disable was set */
+ if (nal_q_parallel_disable)
+ reg |= (0x2 << S5P_FIMV_D_DEC_OPT_PARALLEL_DISABLE_SHIFT);
+
+ /* Realloc buffer for resolution decrease case in NAL QUEUE mode */
+ reg |= (0x1 << S5P_FIMV_D_DEC_OPT_REALLOC_CONTROL_SHIFT);
+
+ /* Parsing all including PPS */
+ reg |= (0x1 << S5P_FIMV_D_DEC_OPT_SPECIAL_PARSING_SHIFT);
+
+ MFC_WRITEL(reg, S5P_FIMV_D_DEC_OPTIONS);
+
+ MFC_WRITEL(MFC_CONCEAL_COLOR, S5P_FIMV_D_FORCE_PIXEL_VAL);
+
+ if (IS_FIMV1_DEC(ctx)) {
+ mfc_debug(2, "Setting FIMV1 resolution to %dx%d\n",
+ ctx->img_width, ctx->img_height);
+ MFC_WRITEL(ctx->img_width, S5P_FIMV_D_SET_FRAME_WIDTH);
+ MFC_WRITEL(ctx->img_height, S5P_FIMV_D_SET_FRAME_HEIGHT);
+ }
+
+ s5p_mfc_set_pixel_format(dev, ctx->dst_fmt->fourcc);
+
+ reg = 0;
+ /* Enable realloc interface if SEI is enabled */
+ if (dec->sei_parse)
+ reg |= (0x1 << S5P_FIMV_D_SEI_ENABLE_NEED_INIT_BUFFER_SHIFT);
+ if (MFC_FEATURE_SUPPORT(dev, dev->pdata->static_info_dec)) {
+ reg |= (0x1 << S5P_FIMV_D_SEI_ENABLE_CONTENT_LIGHT_SHIFT);
+ reg |= (0x1 << S5P_FIMV_D_SEI_ENABLE_MASTERING_DISPLAY_SHIFT);
+ }
+ reg |= (0x1 << S5P_FIMV_D_SEI_ENABLE_RECOVERY_PARSING_SHIFT);
+
+ MFC_WRITEL(reg, S5P_FIMV_D_SEI_ENABLE);
+ mfc_debug(2, "SEI enable was set, 0x%x\n", MFC_READL(S5P_FIMV_D_SEI_ENABLE));
+
+ MFC_WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID);
+
+ if (sfr_dump & MFC_DUMP_DEC_SEQ_START)
+ call_dop(dev, dump_regs, dev);
+
+ s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_SEQ_HEADER);
+
+ mfc_debug_leave();
+ return 0;
+}
+
+/* Decode a single frame */
+int s5p_mfc_decode_one_frame(struct s5p_mfc_ctx *ctx, int last_frame)
+{
+ struct s5p_mfc_dev *dev;
+ struct s5p_mfc_dec *dec;
+ u32 reg = 0;
+
+ if (!ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return -EINVAL;
+ }
+
+ dev = ctx->dev;
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ dec = ctx->dec_priv;
+ if (!dec) {
+ mfc_err_dev("no mfc decoder to run\n");
+ return -EINVAL;
+ }
+
+ mfc_debug(2, "Dynamic:0x%08x, Available:0x%lx\n",
+ dec->dynamic_set, dec->available_dpb);
+
+ reg = MFC_READL(S5P_FIMV_D_NAL_START_OPTIONS);
+ reg &= ~(0x1 << S5P_FIMV_D_NAL_START_OPT_BLACK_BAR_SHIFT);
+ reg |= ((dec->detect_black_bar & 0x1) << S5P_FIMV_D_NAL_START_OPT_BLACK_BAR_SHIFT);
+ MFC_WRITEL(reg, S5P_FIMV_D_NAL_START_OPTIONS);
+ mfc_debug(3, "[BLACKBAR] black bar detect set: %#x\n", reg);
+
+ MFC_WRITEL(dec->dynamic_set, S5P_FIMV_D_DYNAMIC_DPB_FLAG_LOWER);
+ MFC_WRITEL(0x0, S5P_FIMV_D_DYNAMIC_DPB_FLAG_UPPER);
+ MFC_WRITEL(dec->available_dpb, S5P_FIMV_D_AVAILABLE_DPB_FLAG_LOWER);
+ MFC_WRITEL(0x0, S5P_FIMV_D_AVAILABLE_DPB_FLAG_UPPER);
+ MFC_WRITEL(dec->slice_enable, S5P_FIMV_D_SLICE_IF_ENABLE);
+ MFC_WRITEL(MFC_TIMEOUT_VALUE, S5P_FIMV_DEC_TIMEOUT_VALUE);
+
+ MFC_WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID);
+
+ if ((sfr_dump & MFC_DUMP_DEC_NAL_START) && !ctx->check_dump) {
+ call_dop(dev, dump_regs, dev);
+ ctx->check_dump = 1;
+ }
+
+ /* Issue different commands to instance basing on whether it
+ * is the last frame or not. */
+ switch (last_frame) {
+ case 0:
+ s5p_mfc_perf_measure_on(dev);
+
+ s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_NAL_START);
+ break;
+ case 1:
+ s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_LAST_FRAME);
+ break;
+ }
+
+ mfc_debug(2, "Decoding a usual frame\n");
+ return 0;
+}
+
+int s5p_mfc_init_encode(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ mfc_debug(2, "++\n");
+
+ if (IS_H264_ENC(ctx))
+ s5p_mfc_set_enc_params_h264(ctx);
+ else if (IS_MPEG4_ENC(ctx))
+ s5p_mfc_set_enc_params_mpeg4(ctx);
+ else if (IS_H263_ENC(ctx))
+ s5p_mfc_set_enc_params_h263(ctx);
+ else if (IS_VP8_ENC(ctx))
+ s5p_mfc_set_enc_params_vp8(ctx);
+ else if (IS_VP9_ENC(ctx))
+ s5p_mfc_set_enc_params_vp9(ctx);
+ else if (IS_HEVC_ENC(ctx))
+ s5p_mfc_set_enc_params_hevc(ctx);
+ else if (IS_BPG_ENC(ctx))
+ s5p_mfc_set_enc_params_bpg(ctx);
+ else {
+ mfc_err_ctx("Unknown codec for encoding (%x)\n",
+ ctx->codec_mode);
+ return -EINVAL;
+ }
+
+ mfc_debug(5, "RC) Bitrate: %d / framerate: %#x / config %#x / mode %#x\n",
+ MFC_READL(S5P_FIMV_E_RC_BIT_RATE),
+ MFC_READL(S5P_FIMV_E_RC_FRAME_RATE),
+ MFC_READL(S5P_FIMV_E_RC_CONFIG),
+ MFC_READL(S5P_FIMV_E_RC_MODE));
+
+ MFC_WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID);
+
+ if (sfr_dump & MFC_DUMP_ENC_SEQ_START)
+ call_dop(dev, dump_regs, dev);
+
+ s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_SEQ_HEADER);
+
+ mfc_debug(2, "--\n");
+
+ return 0;
+}
+
+static int mfc_h264_set_aso_slice_order(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_enc_params *p = &enc->params;
+ struct s5p_mfc_h264_enc_params *p_264 = &p->codec.h264;
+ int i;
+
+ if (p_264->aso_enable) {
+ for (i = 0; i < 8; i++)
+ MFC_WRITEL(p_264->aso_slice_order[i],
+ S5P_FIMV_E_H264_ASO_SLICE_ORDER_0 + i * 4);
+ }
+ return 0;
+}
+
+/* Encode a single frame */
+int s5p_mfc_encode_one_frame(struct s5p_mfc_ctx *ctx, int last_frame)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ mfc_debug(2, "++\n");
+
+ if (IS_H264_ENC(ctx))
+ mfc_h264_set_aso_slice_order(ctx);
+
+ s5p_mfc_set_slice_mode(ctx);
+
+ MFC_WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID);
+
+ if ((sfr_dump & MFC_DUMP_ENC_NAL_START) && !ctx->check_dump) {
+ call_dop(dev, dump_regs, dev);
+ ctx->check_dump = 1;
+ }
+
+ /* Issue different commands to instance basing on whether it
+ * is the last frame or not. */
+ switch (last_frame) {
+ case 0:
+ s5p_mfc_perf_measure_on(dev);
+
+ s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_NAL_START);
+ break;
+ case 1:
+ s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_LAST_FRAME);
+ break;
+ }
+
+ mfc_debug(2, "--\n");
+
+ return 0;
+}
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_inst.h
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __MFC_INST_H
+#define __MFC_INST_H __FILE__
+
+#include "mfc_common.h"
+
+int s5p_mfc_open_inst(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_close_inst(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_abort_inst(struct s5p_mfc_ctx *ctx);
+
+int s5p_mfc_init_decode(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_decode_one_frame(struct s5p_mfc_ctx *ctx, int last_frame);
+
+int s5p_mfc_init_encode(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_encode_one_frame(struct s5p_mfc_ctx *ctx, int last_frame);
+
+#endif /* __MFC_INST_H */
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_irq.c
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "mfc_irq.h"
+
+#include "mfc_hwlock.h"
+#include "mfc_nal_q.h"
+#include "mfc_otf.h"
+#include "mfc_opr.h"
+#include "mfc_sync.h"
+
+#include "mfc_pm.h"
+#include "mfc_cal.h"
+#include "mfc_perf_measure.h"
+#include "mfc_reg.h"
+#include "mfc_mmcache.h"
+
+#include "mfc_qos.h"
+#include "mfc_queue.h"
+#include "mfc_buf.h"
+#include "mfc_mem.h"
+
+static void mfc_handle_black_bar_info(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx)
+{
+ struct v4l2_rect new_black_bar;
+ int black_bar_info;
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+
+ black_bar_info = s5p_mfc_get_black_bar_detection();
+ mfc_debug(3, "[BLACKBAR] type: %#x\n", black_bar_info);
+
+ if (black_bar_info == S5P_FIMV_DISP_STATUS_BLACK_BAR) {
+ new_black_bar.left = s5p_mfc_get_black_bar_pos_x();
+ new_black_bar.top = s5p_mfc_get_black_bar_pos_y();
+ new_black_bar.width = s5p_mfc_get_black_bar_image_w();
+ new_black_bar.height = s5p_mfc_get_black_bar_image_h();
+ } else if (black_bar_info == S5P_FIMV_DISP_STATUS_BLACK_SCREEN) {
+ new_black_bar.left = -1;
+ new_black_bar.top = -1;
+ new_black_bar.width = ctx->img_width;
+ new_black_bar.height = ctx->img_height;
+ } else if (black_bar_info == S5P_FIMV_DISP_STATUS_NOT_DETECTED) {
+ new_black_bar.left = 0;
+ new_black_bar.top = 0;
+ new_black_bar.width = ctx->img_width;
+ new_black_bar.height = ctx->img_height;
+ } else {
+ mfc_err_ctx("[BLACKBAR] Not supported type: %#x\n", black_bar_info);
+ dec->black_bar_updated = 0;
+ return;
+ }
+
+ if ((new_black_bar.left == dec->black_bar.left) &&
+ (new_black_bar.top == dec->black_bar.top) &&
+ (new_black_bar.width == dec->black_bar.width) &&
+ (new_black_bar.height == dec->black_bar.height)) {
+ mfc_debug(4, "[BLACKBAR] information was not changed\n");
+ dec->black_bar_updated = 0;
+ return;
+ }
+
+ dec->black_bar = new_black_bar;
+ dec->black_bar_updated = 1;
+}
+
+static unsigned int mfc_handle_frame_field(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ unsigned int interlace_type = 0, is_interlace = 0, is_mbaff = 0;
+ unsigned int field;
+
+ if (CODEC_INTERLACED(ctx))
+ is_interlace = s5p_mfc_is_interlace_picture();
+
+ if (CODEC_MBAFF(ctx))
+ is_mbaff = s5p_mfc_is_mbaff_picture();
+
+ if (is_interlace) {
+ interlace_type = s5p_mfc_get_interlace_type();
+ if (interlace_type)
+ field = V4L2_FIELD_INTERLACED_TB;
+ else
+ field = V4L2_FIELD_INTERLACED_BT;
+ } else if (is_mbaff) {
+ field = V4L2_FIELD_INTERLACED_TB;
+ } else {
+ field = V4L2_FIELD_NONE;
+ }
+
+ mfc_debug(2, "[INTERLACE] is_interlace: %d (type : %d), is_mbaff: %d, field: 0x%#x\n",
+ is_interlace, interlace_type, is_mbaff, field);
+
+ return field;
+}
+
+static void mfc_handle_frame_all_extracted(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ struct s5p_mfc_buf *dst_mb;
+ int index, i, is_first = 1;
+
+ mfc_debug(2, "Decided to finish\n");
+ ctx->sequence++;
+
+ while (1) {
+ dst_mb = s5p_mfc_get_del_buf(&ctx->buf_queue_lock, &ctx->dst_buf_queue, MFC_BUF_NO_TOUCH_USED);
+ if (!dst_mb)
+ break;
+
+ mfc_debug(2, "Cleaning up buffer: %d\n",
+ dst_mb->vb.vb2_buf.index);
+
+ index = dst_mb->vb.vb2_buf.index;
+
+ for (i = 0; i < ctx->dst_fmt->mem_planes; i++)
+ vb2_set_plane_payload(&dst_mb->vb.vb2_buf, i, 0);
+
+ dst_mb->vb.sequence = (ctx->sequence++);
+ dst_mb->vb.field = mfc_handle_frame_field(ctx);
+ dst_mb->vb.reserved2 = 0;
+
+ clear_bit(dst_mb->vb.vb2_buf.index, &dec->available_dpb);
+
+ if (call_cop(ctx, get_buf_ctrls_val, ctx, &ctx->dst_ctrls[index]) < 0)
+ mfc_err_ctx("failed in get_buf_ctrls_val\n");
+
+ if (is_first) {
+ call_cop(ctx, get_buf_update_val, ctx,
+ &ctx->dst_ctrls[index],
+ V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG,
+ dec->stored_tag);
+ is_first = 0;
+ } else {
+ call_cop(ctx, get_buf_update_val, ctx,
+ &ctx->dst_ctrls[index],
+ V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG,
+ DEFAULT_TAG);
+ call_cop(ctx, get_buf_update_val, ctx,
+ &ctx->dst_ctrls[index],
+ V4L2_CID_MPEG_VIDEO_H264_SEI_FP_AVAIL,
+ 0);
+ }
+
+ vb2_buffer_done(&dst_mb->vb.vb2_buf, VB2_BUF_STATE_DONE);
+
+ /* decoder dst buffer CFW UNPROT */
+ if (ctx->is_drm)
+ s5p_mfc_raw_unprotect(ctx, dst_mb, index);
+
+ mfc_debug(2, "Cleaned up buffer: %d\n", index);
+ }
+
+ s5p_mfc_handle_force_change_status(ctx);
+ mfc_debug(2, "After cleanup\n");
+}
+
+static void mfc_handle_frame_copy_timestamp(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_buf *ref_mb, *src_mb;
+ dma_addr_t dec_y_addr;
+
+ dec_y_addr = (dma_addr_t)s5p_mfc_get_dec_y_addr();
+
+ /* Get the source buffer */
+ src_mb = s5p_mfc_get_buf(&ctx->buf_queue_lock, &ctx->src_buf_queue, MFC_BUF_NO_TOUCH_USED);
+ if (!src_mb) {
+ mfc_err_dev("[TS] no src buffers\n");
+ return;
+ }
+
+ ref_mb = s5p_mfc_find_buf(&ctx->buf_queue_lock, &ctx->ref_buf_queue, dec_y_addr);
+ if (ref_mb)
+ ref_mb->vb.vb2_buf.timestamp = src_mb->vb.vb2_buf.timestamp;
+}
+
+static void mfc_handle_frame_output_move(struct s5p_mfc_ctx *ctx,
+ dma_addr_t dspl_y_addr, unsigned int released_flag)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ struct s5p_mfc_buf *ref_mb;
+ int index;
+
+ ref_mb = s5p_mfc_find_move_buf(&ctx->buf_queue_lock,
+ &ctx->dst_buf_queue, &ctx->ref_buf_queue, dspl_y_addr, released_flag);
+ if (ref_mb) {
+ index = ref_mb->vb.vb2_buf.index;
+
+ /* Check if this is the buffer we're looking for */
+ mfc_debug(2, "[DPB] Found buf[%d] 0x%08llx, looking for disp addr 0x%08llx\n",
+ index, ref_mb->addr[0][0], dspl_y_addr);
+
+ if (released_flag & (1 << index)) {
+ dec->available_dpb &= ~(1 << index);
+ released_flag &= ~(1 << index);
+ mfc_debug(2, "[DPB] Corrupted frame(%d), it will be re-used(release)\n",
+ s5p_mfc_get_warn(s5p_mfc_get_int_err()));
+ } else {
+ dec->err_reuse_flag |= 1 << index;
+ mfc_debug(2, "[DPB] Corrupted frame(%d), it will be re-used(not released)\n",
+ s5p_mfc_get_warn(s5p_mfc_get_int_err()));
+ }
+ dec->dynamic_used |= released_flag;
+ }
+}
+
+static void mfc_handle_frame_output_del(struct s5p_mfc_ctx *ctx,
+ unsigned int err, unsigned int released_flag)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ struct s5p_mfc_raw_info *raw = &ctx->raw_buf;
+ struct s5p_mfc_buf *ref_mb;
+ dma_addr_t dspl_y_addr;
+ unsigned int frame_type;
+ unsigned int dst_frame_status;
+ unsigned int is_video_signal_type = 0, is_colour_description = 0;
+ unsigned int is_content_light = 0, is_display_colour = 0;
+ unsigned int i, index;
+
+ if (MFC_FEATURE_SUPPORT(dev, dev->pdata->color_aspect_dec)) {
+ is_video_signal_type = s5p_mfc_get_video_signal_type();
+ is_colour_description = s5p_mfc_get_colour_description();
+ }
+
+ if (MFC_FEATURE_SUPPORT(dev, dev->pdata->static_info_dec)) {
+ is_content_light = s5p_mfc_get_sei_avail_content_light();
+ is_display_colour = s5p_mfc_get_sei_avail_mastering_display();
+ }
+
+ if (MFC_FEATURE_SUPPORT(dev, dev->pdata->black_bar) && dec->detect_black_bar)
+ mfc_handle_black_bar_info(dev, ctx);
+ else
+ dec->black_bar_updated = 0;
+
+ if (dec->immediate_display == 1) {
+ dspl_y_addr = (dma_addr_t)s5p_mfc_get_dec_y_addr();
+ frame_type = s5p_mfc_get_dec_frame_type();
+ } else {
+ dspl_y_addr = (dma_addr_t)s5p_mfc_get_disp_y_addr();
+ frame_type = s5p_mfc_get_disp_frame_type();
+ }
+
+ ref_mb = s5p_mfc_find_del_buf(&ctx->buf_queue_lock,
+ &ctx->ref_buf_queue, dspl_y_addr);
+ if (ref_mb) {
+ index = ref_mb->vb.vb2_buf.index;
+ /* Check if this is the buffer we're looking for */
+ mfc_debug(2, "[BUFINFO][DPB] ctx[%d] get dst index: %d, addr[0]: 0x%08llx\n",
+ ctx->num, index, ref_mb->addr[0][0]);
+
+ ref_mb->vb.sequence = ctx->sequence;
+ ref_mb->vb.field = mfc_handle_frame_field(ctx);
+
+ /* Set reserved2 bits in order to inform SEI information */
+ ref_mb->vb.reserved2 = 0;
+
+ if (is_content_light) {
+ ref_mb->vb.reserved2 |= (1 << 0);
+ mfc_debug(2, "[HDR] content light level parsed\n");
+ }
+
+ if (is_display_colour) {
+ ref_mb->vb.reserved2 |= (1 << 1);
+ mfc_debug(2, "[HDR] mastering display colour parsed\n");
+ }
+
+ if (is_video_signal_type) {
+ ref_mb->vb.reserved2 |= (1 << 4);
+ mfc_debug(2, "[HDR] video signal type parsed\n");
+ if (is_colour_description) {
+ ref_mb->vb.reserved2 |= (1 << 2);
+ mfc_debug(2, "[HDR] matrix coefficients parsed\n");
+ ref_mb->vb.reserved2 |= (1 << 3);
+ mfc_debug(2, "[HDR] colour description parsed\n");
+ }
+ }
+
+ if (IS_VP9_DEC(ctx) && MFC_FEATURE_SUPPORT(dev, dev->pdata->color_aspect_dec)) {
+ if (dec->color_space != S5P_FIMV_D_COLOR_UNKNOWN) {
+ ref_mb->vb.reserved2 |= (1 << 3);
+ mfc_debug(2, "[HDR] color space parsed\n");
+ }
+ ref_mb->vb.reserved2 |= (1 << 4);
+ mfc_debug(2, "[HDR] color range parsed\n");
+ }
+
+ if (dec->black_bar_updated) {
+ ref_mb->vb.reserved2 |= (1 << 5);
+ mfc_debug(3, "[BLACKBAR] black bar detected\n");
+ }
+
+ if (ctx->src_fmt->mem_planes == 1) {
+ vb2_set_plane_payload(&ref_mb->vb.vb2_buf, 0,
+ raw->total_plane_size);
+ mfc_debug(5, "single plane payload: %d\n",
+ raw->total_plane_size);
+ } else {
+ for (i = 0; i < ctx->src_fmt->mem_planes; i++) {
+ vb2_set_plane_payload(&ref_mb->vb.vb2_buf, i,
+ raw->plane_size[i]);
+ }
+ }
+
+ clear_bit(index, &dec->available_dpb);
+
+ ref_mb->vb.flags &= ~(V4L2_BUF_FLAG_KEYFRAME |
+ V4L2_BUF_FLAG_PFRAME |
+ V4L2_BUF_FLAG_BFRAME |
+ V4L2_BUF_FLAG_ERROR);
+
+ switch (frame_type) {
+ case S5P_FIMV_DISPLAY_FRAME_I:
+ ref_mb->vb.flags |= V4L2_BUF_FLAG_KEYFRAME;
+ break;
+ case S5P_FIMV_DISPLAY_FRAME_P:
+ ref_mb->vb.flags |= V4L2_BUF_FLAG_PFRAME;
+ break;
+ case S5P_FIMV_DISPLAY_FRAME_B:
+ ref_mb->vb.flags |= V4L2_BUF_FLAG_BFRAME;
+ break;
+ default:
+ break;
+ }
+
+ if (s5p_mfc_get_warn(err)) {
+ mfc_err_ctx("Warning for displayed frame: %d\n",
+ s5p_mfc_get_warn(err));
+ ref_mb->vb.flags |= V4L2_BUF_FLAG_ERROR;
+ }
+
+ if (call_cop(ctx, get_buf_ctrls_val, ctx, &ctx->dst_ctrls[index]) < 0)
+ mfc_err_ctx("failed in get_buf_ctrls_val\n");
+
+ s5p_mfc_handle_released_info(ctx, released_flag, index);
+
+ if (dec->immediate_display == 1) {
+ dst_frame_status = s5p_mfc_get_dec_status();
+
+ call_cop(ctx, get_buf_update_val, ctx,
+ &ctx->dst_ctrls[index],
+ V4L2_CID_MPEG_MFC51_VIDEO_DISPLAY_STATUS,
+ dst_frame_status);
+
+ call_cop(ctx, get_buf_update_val, ctx,
+ &ctx->dst_ctrls[index],
+ V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG,
+ dec->stored_tag);
+
+ dec->immediate_display = 0;
+ }
+
+ /* Update frame tag for packed PB */
+ if (CODEC_MULTIFRAME(ctx) && (dec->y_addr_for_pb == dspl_y_addr)) {
+ call_cop(ctx, get_buf_update_val, ctx,
+ &ctx->dst_ctrls[index],
+ V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG,
+ dec->stored_tag);
+ dec->y_addr_for_pb = 0;
+ }
+
+ s5p_mfc_qos_update_last_framerate(ctx, ref_mb->vb.vb2_buf.timestamp);
+ vb2_buffer_done(&ref_mb->vb.vb2_buf, s5p_mfc_get_warn(err) ?
+ VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+ }
+}
+
+static void mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err)
+{
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ struct s5p_mfc_dev *dev = ctx->dev;
+ dma_addr_t dspl_y_addr;
+ unsigned int frame_type;
+ int mvc_view_id;
+ unsigned int prev_flag, released_flag = 0;
+
+ frame_type = s5p_mfc_get_disp_frame_type();
+ mvc_view_id = s5p_mfc_get_mvc_disp_view_id();
+
+ if (IS_H264_MVC_DEC(ctx)) {
+ if (mvc_view_id == 0)
+ ctx->sequence++;
+ } else {
+ ctx->sequence++;
+ }
+
+ dspl_y_addr = s5p_mfc_get_disp_y_addr();
+
+ if (dec->immediate_display == 1) {
+ dspl_y_addr = (dma_addr_t)s5p_mfc_get_dec_y_addr();
+ frame_type = s5p_mfc_get_dec_frame_type();
+ }
+
+ mfc_debug(2, "[FRAME] frame type: %d\n", frame_type);
+
+ /* If frame is same as previous then skip and do not dequeue */
+ if (frame_type == S5P_FIMV_DISPLAY_FRAME_NOT_CODED)
+ if (!CODEC_NOT_CODED(ctx))
+ return;
+
+ prev_flag = dec->dynamic_used;
+ dec->dynamic_used = s5p_mfc_get_dec_used_flag();
+ released_flag = prev_flag & (~dec->dynamic_used);
+
+ mfc_debug(2, "[DPB] Used flag: old = %08x, new = %08x, Released buffer = %08x\n",
+ prev_flag, dec->dynamic_used, released_flag);
+
+ /* decoder dst buffer CFW UNPROT */
+ s5p_mfc_unprotect_released_dpb(ctx, released_flag);
+
+ if ((IS_VC1_RCV_DEC(ctx) &&
+ s5p_mfc_get_warn(err) == S5P_FIMV_ERR_SYNC_POINT_NOT_RECEIVED) ||
+ (s5p_mfc_get_warn(err) == S5P_FIMV_ERR_BROKEN_LINK))
+ mfc_handle_frame_output_move(ctx, dspl_y_addr, released_flag);
+ else
+ mfc_handle_frame_output_del(ctx, err, released_flag);
+}
+
+static void mfc_handle_frame_error(struct s5p_mfc_ctx *ctx,
+ unsigned int reason, unsigned int err)
+{
+ struct s5p_mfc_dec *dec;
+ struct s5p_mfc_buf *src_mb;
+ unsigned int index;
+
+ if (ctx->type == MFCINST_ENCODER) {
+ mfc_err_ctx("Encoder Interrupt Error: %d\n", err);
+ return;
+ }
+
+ dec = ctx->dec_priv;
+ if (!dec) {
+ mfc_err_dev("no mfc decoder to run\n");
+ return;
+ }
+
+ mfc_err_ctx("Interrupt Error: %d\n", err);
+
+ /* Get the source buffer */
+ src_mb = s5p_mfc_get_del_buf(&ctx->buf_queue_lock, &ctx->src_buf_queue, MFC_BUF_NO_TOUCH_USED);
+
+ if (!src_mb) {
+ mfc_err_dev("no src buffers\n");
+ } else {
+ index = src_mb->vb.vb2_buf.index;
+ if (call_cop(ctx, recover_buf_ctrls_val, ctx, &ctx->src_ctrls[index]) < 0)
+ mfc_err_ctx("failed in recover_buf_ctrls_val\n");
+
+ mfc_debug(2, "MFC needs next buffer\n");
+ dec->consumed = 0;
+
+ if (call_cop(ctx, get_buf_ctrls_val, ctx, &ctx->src_ctrls[index]) < 0)
+ mfc_err_ctx("failed in get_buf_ctrls_val\n");
+
+ /* decoder src buffer CFW UNPROT */
+ if (ctx->is_drm)
+ s5p_mfc_stream_unprotect(ctx, src_mb, index);
+
+ vb2_buffer_done(&src_mb->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+ }
+
+ mfc_debug(2, "Assesing whether this context should be run again\n");
+}
+
+static void mfc_handle_ref_frame(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ struct s5p_mfc_buf *dst_mb;
+ dma_addr_t dec_addr;
+
+ dec_addr = (dma_addr_t)s5p_mfc_get_dec_y_addr();
+
+ /* Try to search decoded address in whole dst queue */
+ dst_mb = s5p_mfc_find_move_buf_used(&ctx->buf_queue_lock,
+ &ctx->ref_buf_queue, &ctx->dst_buf_queue, dec_addr);
+ if (dst_mb) {
+ mfc_debug(2, "[DPB] Found in dst queue = 0x%08llx, buf = 0x%08llx\n",
+ dec_addr, dst_mb->addr[0][0]);
+
+ if (!(dec->dynamic_set & s5p_mfc_get_dec_used_flag()))
+ dec->dynamic_used |= dec->dynamic_set;
+ } else {
+ mfc_debug(2, "[DPB] Can't find buffer for addr = 0x%08llx\n", dec_addr);
+ }
+}
+
+static void mfc_handle_reuse_buffer(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ unsigned int prev_flag, released_flag = 0;
+ int i;
+
+ prev_flag = dec->dynamic_used;
+ dec->dynamic_used = s5p_mfc_get_dec_used_flag();
+ released_flag = prev_flag & (~dec->dynamic_used);
+
+ if (!released_flag)
+ return;
+
+ /* Reuse not referenced buf anymore */
+ for (i = 0; i < MFC_MAX_DPBS; i++)
+ if (released_flag & (1 << i))
+ if (s5p_mfc_move_reuse_buffer(ctx, i))
+ released_flag &= ~(1 << i);
+
+ /* Not reused buffer should be released when there is a display frame */
+ dec->dec_only_release_flag |= released_flag;
+ for (i = 0; i < MFC_MAX_DPBS; i++)
+ if (released_flag & (1 << i))
+ clear_bit(i, &dec->available_dpb);
+}
+
+static void mfc_handle_frame_input(struct s5p_mfc_ctx *ctx, unsigned int err)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ struct s5p_mfc_buf *src_mb;
+ unsigned int index;
+ int deleted = 0;
+ unsigned long consumed;
+
+ consumed = dec->consumed + s5p_mfc_get_consumed_stream();
+
+ if (s5p_mfc_get_err(err) == S5P_FIMV_ERR_NON_PAIRED_FIELD) {
+ /*
+ * For non-paired field, the same buffer need to be
+ * resubmitted and the consumed stream will be 0
+ */
+ mfc_debug(2, "Not paired field. Running again the same buffer\n");
+ return;
+ }
+
+ /* Get the source buffer */
+ src_mb = s5p_mfc_get_del_if_consumed(ctx, &ctx->src_buf_queue,
+ s5p_mfc_get_consumed_stream(), STUFF_BYTE, err, &deleted);
+ if (!src_mb) {
+ mfc_err_dev("no src buffers\n");
+ return;
+ }
+
+ index = src_mb->vb.vb2_buf.index;
+ mfc_debug(2, "[BUFINFO] ctx[%d] get src index: %d, addr: 0x%08llx\n",
+ ctx->num, index, src_mb->addr[0][0]);
+
+ if (!deleted) {
+ /* Run MFC again on the same buffer */
+ mfc_debug(2, "[MULTIFRAME] Running again the same buffer\n");
+
+ if (CODEC_MULTIFRAME(ctx))
+ dec->y_addr_for_pb = (dma_addr_t)s5p_mfc_get_dec_y_addr();
+
+ dec->consumed = consumed;
+ dec->remained_size = src_mb->vb.vb2_buf.planes[0].bytesused
+ - dec->consumed;
+ dec->has_multiframe = 1;
+
+ MFC_TRACE_CTX("** consumed:%ld, remained:%ld, addr:0x%08llx\n",
+ dec->consumed, dec->remained_size, dec->y_addr_for_pb);
+ /* Do not move src buffer to done_list */
+ return;
+ }
+
+ if (call_cop(ctx, recover_buf_ctrls_val, ctx, &ctx->src_ctrls[index]) < 0)
+ mfc_err_ctx("failed in recover_buf_ctrls_val\n");
+
+ dec->consumed = 0;
+ dec->remained_size = 0;
+
+ if (call_cop(ctx, get_buf_ctrls_val, ctx, &ctx->src_ctrls[index]) < 0)
+ mfc_err_ctx("failed in get_buf_ctrls_val\n");
+
+ /* decoder src buffer CFW UNPROT */
+ if (ctx->is_drm)
+ s5p_mfc_stream_unprotect(ctx, src_mb, index);
+
+ vb2_buffer_done(&src_mb->vb.vb2_buf, VB2_BUF_STATE_DONE);
+}
+
+/* Handle frame decoding interrupt */
+static void mfc_handle_frame(struct s5p_mfc_ctx *ctx,
+ unsigned int reason, unsigned int err)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ unsigned int dst_frame_status, sei_avail_frame_pack;
+ unsigned int res_change, need_dpb_change, need_scratch_change;
+
+ dst_frame_status = s5p_mfc_get_disp_status();
+ res_change = s5p_mfc_get_res_change();
+ need_dpb_change = s5p_mfc_get_dpb_change();
+ need_scratch_change = s5p_mfc_get_scratch_change();
+ sei_avail_frame_pack = s5p_mfc_get_sei_avail_frame_pack();
+
+ if (dec->immediate_display == 1)
+ dst_frame_status = s5p_mfc_get_dec_status();
+
+ mfc_debug(2, "[FRAME] frame status: %d\n", dst_frame_status);
+ mfc_debug(2, "[FRAME] display status: %d, type: %d, yaddr: %#x\n",
+ s5p_mfc_get_disp_status(), s5p_mfc_get_disp_frame_type(),
+ s5p_mfc_get_disp_y_addr());
+ mfc_debug(2, "[FRAME] decoded status: %d, type: %d, yaddr: %#x\n",
+ s5p_mfc_get_dec_status(), s5p_mfc_get_dec_frame_type(),
+ s5p_mfc_get_dec_y_addr());
+
+ mfc_debug(4, "[HDR] SEI available status: 0x%08x\n", s5p_mfc_get_sei_avail());
+ mfc_debug(4, "[HDR] SEI content light: 0x%08x\n", s5p_mfc_get_sei_content_light());
+ mfc_debug(4, "[HDR] SEI luminance: 0x%08x, 0x%08x white point: 0x%08x\n",
+ s5p_mfc_get_sei_mastering0(), s5p_mfc_get_sei_mastering1(),
+ s5p_mfc_get_sei_mastering2());
+ mfc_debug(4, "[HDR] SEI display primaries: 0x%08x, 0x%08x, 0x%08x\n",
+ s5p_mfc_get_sei_mastering3(), s5p_mfc_get_sei_mastering4(),
+ s5p_mfc_get_sei_mastering5());
+ mfc_debug(2, "[DPB] Used flag: old = %08x, new = %08x\n",
+ dec->dynamic_used, s5p_mfc_get_dec_used_flag());
+
+ if (ctx->state == MFCINST_RES_CHANGE_INIT)
+ s5p_mfc_change_state(ctx, MFCINST_RES_CHANGE_FLUSH);
+
+ if (res_change) {
+ mfc_debug(2, "[DRC] Resolution change set to %d\n", res_change);
+ s5p_mfc_change_state(ctx, MFCINST_RES_CHANGE_INIT);
+ ctx->wait_state = WAIT_DECODING;
+ mfc_debug(7, "[DRC] Decoding waiting! : %d\n", ctx->wait_state);
+ return;
+ }
+
+ if (need_dpb_change || need_scratch_change)
+ mfc_debug(2, "[DRC] Interframe resolution change is not supported\n");
+
+ if (s5p_mfc_is_queue_count_same(&ctx->buf_queue_lock, &ctx->src_buf_queue, 0) &&
+ s5p_mfc_is_queue_count_same(&ctx->buf_queue_lock, &ctx->dst_buf_queue, 0)) {
+ mfc_err_dev("Queue count is zero for src and dst\n");
+ goto leave_handle_frame;
+ }
+
+ if (IS_H264_DEC(ctx) && sei_avail_frame_pack &&
+ dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_ONLY) {
+ mfc_debug(2, "Frame packing SEI exists for a frame\n");
+ mfc_debug(2, "Reallocate DPBs and issue init_buffer\n");
+ ctx->is_dpb_realloc = 1;
+ s5p_mfc_change_state(ctx, MFCINST_HEAD_PARSED);
+ ctx->capture_state = QUEUE_FREE;
+ ctx->wait_state = WAIT_DECODING;
+ mfc_handle_frame_all_extracted(ctx);
+ goto leave_handle_frame;
+ }
+
+ /* All frames remaining in the buffer have been extracted */
+ if (dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_EMPTY) {
+ if (ctx->state == MFCINST_RES_CHANGE_FLUSH) {
+ struct mfc_timestamp *temp_ts = NULL;
+
+ mfc_debug(2, "[DRC] Last frame received after resolution change\n");
+ mfc_handle_frame_all_extracted(ctx);
+ s5p_mfc_change_state(ctx, MFCINST_RES_CHANGE_END);
+ /* If there is no display frame after resolution change,
+ * Some released frames can't be unprotected.
+ * So, check and request unprotection in the end of DRC.
+ */
+ s5p_mfc_cleanup_assigned_dpb(ctx);
+
+ /* empty the timestamp queue */
+ while (!list_empty(&ctx->ts_list)) {
+ temp_ts = list_entry((&ctx->ts_list)->next,
+ struct mfc_timestamp, list);
+ list_del(&temp_ts->list);
+ }
+ ctx->ts_count = 0;
+ ctx->ts_is_full = 0;
+ s5p_mfc_qos_reset_last_framerate(ctx);
+ s5p_mfc_qos_set_framerate(ctx, DEC_DEFAULT_FPS);
+
+ goto leave_handle_frame;
+ } else {
+ mfc_handle_frame_all_extracted(ctx);
+ }
+ }
+
+ if (s5p_mfc_get_num_of_tile() >= 4)
+ dec->num_of_tile_over_4 = 1;
+
+ switch (dst_frame_status) {
+ case S5P_FIMV_DEC_STATUS_DECODING_DISPLAY:
+ mfc_handle_ref_frame(ctx);
+ break;
+ case S5P_FIMV_DEC_STATUS_DECODING_ONLY:
+ mfc_handle_ref_frame(ctx);
+ /*
+ * Some cases can have many decoding only frames like VP9
+ * alt-ref frame. So need handling release buffer
+ * because of DPB full.
+ */
+ mfc_handle_reuse_buffer(ctx);
+ break;
+ default:
+ break;
+ }
+
+ if (s5p_mfc_dec_status_decoding(dst_frame_status))
+ mfc_handle_frame_copy_timestamp(ctx);
+
+ /* A frame has been decoded and is in the buffer */
+ if (s5p_mfc_dec_status_display(dst_frame_status))
+ mfc_handle_frame_new(ctx, err);
+ else
+ mfc_debug(2, "No frame decode\n");
+
+ /* Mark source buffer as complete */
+ if (dst_frame_status != S5P_FIMV_DEC_STATUS_DISPLAY_ONLY)
+ mfc_handle_frame_input(ctx, err);
+
+leave_handle_frame:
+ mfc_debug(2, "Assesing whether this context should be run again\n");
+}
+
+static void mfc_handle_stream_copy_timestamp(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *src_mb)
+{
+ struct s5p_mfc_dev *dev;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_enc_params *p = &enc->params;
+ struct s5p_mfc_buf *dst_mb;
+ u32 interval;
+ u64 start_timestamp;
+ u64 new_timestamp;
+
+ if (!ctx) {
+ mfc_err_dev("[BUFCON][TS] no mfc context to run\n");
+ return;
+ }
+
+ dev = ctx->dev;
+ if (!dev) {
+ mfc_err_dev("[BUFCON][TS] no device to run\n");
+ return;
+ }
+
+ start_timestamp = src_mb->vb.vb2_buf.timestamp;
+ interval = NSEC_PER_SEC / p->rc_framerate;
+ if (debug_ts == 1)
+ mfc_info_ctx("[BUFCON][TS] %dfps, start timestamp: %lld, base interval: %d\n",
+ p->rc_framerate, start_timestamp, interval);
+
+ new_timestamp = start_timestamp + (interval * src_mb->done_index);
+ if (debug_ts == 1)
+ mfc_info_ctx("[BUFCON][TS] new timestamp: %lld, interval: %d\n",
+ new_timestamp, interval * src_mb->done_index);
+
+ /* Get the destination buffer */
+ dst_mb = s5p_mfc_get_buf(&ctx->buf_queue_lock, &ctx->dst_buf_queue, MFC_BUF_NO_TOUCH_USED);
+ if (dst_mb)
+ dst_mb->vb.vb2_buf.timestamp = new_timestamp;
+}
+
+static void mfc_handle_stream_input(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_raw_info *raw;
+ struct s5p_mfc_buf *ref_mb, *src_mb;
+ dma_addr_t enc_addr[3] = { 0, 0, 0 };
+ int i, found_in_src_queue = 0;
+ unsigned int index;
+
+ raw = &ctx->raw_buf;
+
+ s5p_mfc_get_enc_frame_buffer(ctx, &enc_addr[0], raw->num_planes);
+ if (enc_addr[0] == 0) {
+ mfc_debug(3, "no encoded src\n");
+ goto move_buf;
+ }
+ for (i = 0; i < raw->num_planes; i++)
+ mfc_debug(2, "[BUFINFO] ctx[%d] get src addr[%d]: 0x%08llx\n",
+ ctx->num, i, enc_addr[i]);
+
+ if (IS_BUFFER_BATCH_MODE(ctx)) {
+ src_mb = s5p_mfc_find_first_buf(&ctx->buf_queue_lock,
+ &ctx->src_buf_queue, enc_addr[0]);
+ if (src_mb) {
+ found_in_src_queue = 1;
+
+ mfc_handle_stream_copy_timestamp(ctx, src_mb);
+ src_mb->done_index++;
+ mfc_debug(4, "[BUFCON] batch buf done_index: %d\n", src_mb->done_index);
+
+ index = src_mb->vb.vb2_buf.index;
+
+ if (call_cop(ctx, recover_buf_ctrls_val, ctx,
+ &ctx->src_ctrls[index]) < 0)
+ mfc_err_ctx("failed in recover_buf_ctrls_val\n");
+
+ /* single buffer || last image in a buffer container */
+ if (!src_mb->num_valid_bufs || src_mb->done_index == src_mb->num_valid_bufs) {
+ src_mb = s5p_mfc_find_del_buf(&ctx->buf_queue_lock,
+ &ctx->src_buf_queue, enc_addr[0]);
+ for (i = 0; i < raw->num_planes; i++)
+ s5p_mfc_bufcon_put_daddr(ctx, src_mb, i);
+ vb2_buffer_done(&src_mb->vb.vb2_buf, VB2_BUF_STATE_DONE);
+ }
+
+ /* encoder src buffer CFW UNPROT */
+ if (ctx->is_drm)
+ s5p_mfc_raw_unprotect(ctx, src_mb, index);
+ }
+ } else {
+ /* normal single buffer */
+ src_mb = s5p_mfc_find_del_buf(&ctx->buf_queue_lock,
+ &ctx->src_buf_queue, enc_addr[0]);
+ if (src_mb) {
+ found_in_src_queue = 1;
+ index = src_mb->vb.vb2_buf.index;
+ if (call_cop(ctx, recover_buf_ctrls_val, ctx,
+ &ctx->src_ctrls[index]) < 0)
+ mfc_err_ctx("failed in recover_buf_ctrls_val\n");
+
+ mfc_debug(3, "find src buf in src_queue\n");
+ vb2_buffer_done(&src_mb->vb.vb2_buf, VB2_BUF_STATE_DONE);
+
+ /* encoder src buffer CFW UNPROT */
+ if (ctx->is_drm)
+ s5p_mfc_raw_unprotect(ctx, src_mb, index);
+ } else {
+ mfc_debug(3, "no src buf in src_queue\n");
+ ref_mb = s5p_mfc_find_del_buf(&ctx->buf_queue_lock,
+ &ctx->ref_buf_queue, enc_addr[0]);
+ if (ref_mb) {
+ mfc_debug(3, "find src buf in ref_queue\n");
+ vb2_buffer_done(&ref_mb->vb.vb2_buf, VB2_BUF_STATE_DONE);
+
+ /* encoder src buffer CFW UNPROT */
+ if (ctx->is_drm) {
+ index = ref_mb->vb.vb2_buf.index;
+ s5p_mfc_raw_unprotect(ctx, ref_mb, index);
+ }
+ } else {
+ mfc_err_ctx("couldn't find src buffer\n");
+ }
+ }
+ }
+
+move_buf:
+ /* move enqueued src buffer: src queue -> ref queue */
+ if (!found_in_src_queue && ctx->state != MFCINST_FINISHING) {
+ s5p_mfc_move_first_buf_used(&ctx->buf_queue_lock,
+ &ctx->ref_buf_queue, &ctx->src_buf_queue, MFC_QUEUE_ADD_BOTTOM);
+
+ mfc_debug(2, "enc src_buf_queue(%d) -> ref_buf_queue(%d)\n",
+ s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->src_buf_queue),
+ s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->ref_buf_queue));
+ }
+}
+
+static void mfc_handle_stream_output(struct s5p_mfc_ctx *ctx, int slice_type,
+ unsigned int strm_size)
+{
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_buf *dst_mb;
+ unsigned int index;
+
+ if (strm_size == 0) {
+ mfc_debug(3, "no encoded dst (reuse)\n");
+ return;
+ } else if (strm_size < 0) {
+ mfc_err_ctx("invalid stream size: %d\n", strm_size);
+ return;
+ }
+
+ /* at least one more dest. buffers exist always */
+ dst_mb = s5p_mfc_get_del_buf(&ctx->buf_queue_lock,
+ &ctx->dst_buf_queue, MFC_BUF_NO_TOUCH_USED);
+ if (!dst_mb) {
+ mfc_err_ctx("no dst buffers\n");
+ return;
+ }
+
+ mfc_debug(2, "[BUFINFO] ctx[%d] get dst addr: 0x%08llx\n",
+ ctx->num, dst_mb->addr[0][0]);
+
+ dst_mb->vb.flags &= ~(V4L2_BUF_FLAG_KEYFRAME |
+ V4L2_BUF_FLAG_PFRAME |
+ V4L2_BUF_FLAG_BFRAME);
+ switch (slice_type) {
+ case S5P_FIMV_E_SLICE_TYPE_I:
+ dst_mb->vb.flags |= V4L2_BUF_FLAG_KEYFRAME;
+ break;
+ case S5P_FIMV_E_SLICE_TYPE_P:
+ dst_mb->vb.flags |= V4L2_BUF_FLAG_PFRAME;
+ break;
+ case S5P_FIMV_E_SLICE_TYPE_B:
+ dst_mb->vb.flags |= V4L2_BUF_FLAG_BFRAME;
+ break;
+ default:
+ dst_mb->vb.flags |= V4L2_BUF_FLAG_KEYFRAME;
+ break;
+ }
+ mfc_debug(2, "[STREAM] Slice type flag: %d\n", dst_mb->vb.flags);
+
+ if (IS_BPG_ENC(ctx)) {
+ strm_size += enc->header_size;
+ mfc_debug(2, "bpg total stream size: %d\n", strm_size);
+ }
+ vb2_set_plane_payload(&dst_mb->vb.vb2_buf, 0, strm_size);
+
+ index = dst_mb->vb.vb2_buf.index;
+ if (call_cop(ctx, get_buf_ctrls_val, ctx, &ctx->dst_ctrls[index]) < 0)
+ mfc_err_ctx("failed in get_buf_ctrls_val\n");
+
+ vb2_buffer_done(&dst_mb->vb.vb2_buf, VB2_BUF_STATE_DONE);
+
+ /* encoder dst buffer CFW UNPROT */
+ if (ctx->is_drm)
+ s5p_mfc_stream_unprotect(ctx, dst_mb, index);
+}
+
+/* Handle frame encoding interrupt */
+static int mfc_handle_stream(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ int slice_type;
+ unsigned int strm_size;
+ unsigned int pic_count;
+
+ slice_type = s5p_mfc_get_enc_slice_type();
+ strm_size = s5p_mfc_get_enc_strm_size();
+ pic_count = s5p_mfc_get_enc_pic_count();
+
+ mfc_debug(2, "[STREAM] encoded slice type: %d, size: %d, display order: %d\n",
+ slice_type, strm_size, pic_count);
+
+ /* buffer full handling */
+ if (enc->buf_full) {
+ s5p_mfc_change_state(ctx, MFCINST_ABORT_INST);
+ return 0;
+ }
+ if (ctx->state == MFCINST_RUNNING_BUF_FULL)
+ s5p_mfc_change_state(ctx, MFCINST_RUNNING);
+
+ /* set encoded frame type */
+ enc->frame_type = slice_type;
+ ctx->sequence++;
+
+ if (enc->in_slice) {
+ if (s5p_mfc_is_queue_count_same(&ctx->buf_queue_lock, &ctx->dst_buf_queue, 0)) {
+ s5p_mfc_clear_bit(ctx->num, &dev->work_bits);
+ }
+ return 0;
+ }
+
+ /* handle source buffer */
+ mfc_handle_stream_input(ctx);
+
+ /* handle destination buffer */
+ mfc_handle_stream_output(ctx, slice_type, strm_size);
+
+ return 0;
+}
+
+/* Error handling for interrupt */
+static inline void mfc_handle_error(struct s5p_mfc_ctx *ctx,
+ unsigned int reason, unsigned int err)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_buf *src_mb;
+ int index;
+
+ mfc_err_ctx("Interrupt Error: display: %d, decoded: %d\n",
+ s5p_mfc_get_warn(err), s5p_mfc_get_err(err));
+ err = s5p_mfc_get_err(err);
+
+ /* Error recovery is dependent on the state of context */
+ switch (ctx->state) {
+ case MFCINST_RES_CHANGE_END:
+ case MFCINST_GOT_INST:
+ /* This error had to happen while parsing the header */
+ if (!ctx->is_drm) {
+ unsigned char *stream_vir = NULL;
+ unsigned int strm_size = 0;
+
+ src_mb = s5p_mfc_get_del_buf(&ctx->buf_queue_lock, &ctx->src_buf_queue, MFC_BUF_NO_TOUCH_USED);
+ if (src_mb) {
+ stream_vir = src_mb->vir_addr;
+ strm_size = src_mb->vb.vb2_buf.planes[0].bytesused;
+ if (strm_size > 32)
+ strm_size = 32;
+
+ if (stream_vir && strm_size)
+ print_hex_dump(KERN_ERR, "No header: ",
+ DUMP_PREFIX_ADDRESS, strm_size, 0,
+ stream_vir, strm_size, false);
+
+ vb2_buffer_done(&src_mb->vb.vb2_buf, VB2_BUF_STATE_DONE);
+ }
+ } else {
+ src_mb = s5p_mfc_get_del_buf(&ctx->buf_queue_lock, &ctx->src_buf_queue, MFC_BUF_NO_TOUCH_USED);
+ if (src_mb) {
+ index = src_mb->vb.vb2_buf.index;
+ /* decoder src buffer CFW UNPROT */
+ s5p_mfc_stream_unprotect(ctx, src_mb, index);
+ vb2_buffer_done(&src_mb->vb.vb2_buf, VB2_BUF_STATE_DONE);
+ }
+ }
+ break;
+ case MFCINST_INIT:
+ /* This error had to happen while acquireing instance */
+ case MFCINST_RETURN_INST:
+ /* This error had to happen while releasing instance */
+ case MFCINST_DPB_FLUSHING:
+ /* This error had to happen while flushing DPB */
+ case MFCINST_SPECIAL_PARSING:
+ case MFCINST_SPECIAL_PARSING_NAL:
+ /* This error had to happen while special parsing */
+ break;
+ case MFCINST_HEAD_PARSED:
+ /* This error had to happen while setting dst buffers */
+ case MFCINST_RES_CHANGE_INIT:
+ case MFCINST_RES_CHANGE_FLUSH:
+ /* This error has to happen while resolution change */
+ case MFCINST_ABORT_INST:
+ /* This error has to happen while buffer full handling */
+ case MFCINST_FINISHING:
+ /* It is higly probable that an error occured
+ * while decoding a frame */
+ s5p_mfc_change_state(ctx, MFCINST_ERROR);
+ /* Mark all dst buffers as having an error */
+ s5p_mfc_cleanup_queue(&ctx->buf_queue_lock, &ctx->dst_buf_queue);
+ /* Mark all src buffers as having an error */
+ s5p_mfc_cleanup_queue(&ctx->buf_queue_lock, &ctx->src_buf_queue);
+ break;
+ default:
+ mfc_err_ctx("Encountered an error interrupt which had not been handled\n");
+ mfc_err_ctx("ctx->state = %d, ctx->inst_no = %d\n",
+ ctx->state, ctx->inst_no);
+ break;
+ }
+
+ s5p_mfc_wake_up_dev(dev, reason, err);
+
+ return;
+}
+
+/* Handle header decoder interrupt */
+static int mfc_handle_seq_dec(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ int i, is_interlace, is_mbaff;
+
+ if (ctx->src_fmt->fourcc != V4L2_PIX_FMT_FIMV1) {
+ ctx->img_width = s5p_mfc_get_img_width();
+ ctx->img_height = s5p_mfc_get_img_height();
+ ctx->crop_width = ctx->img_width;
+ ctx->crop_height = ctx->img_height;
+ mfc_info_ctx("[STREAM] resolution w: %d, h: %d\n", ctx->img_width, ctx->img_height);
+ }
+
+ ctx->dpb_count = s5p_mfc_get_dpb_count();
+ ctx->scratch_buf_size = s5p_mfc_get_scratch_size();
+ for (i = 0; i < ctx->dst_fmt->num_planes; i++)
+ ctx->min_dpb_size[i] = s5p_mfc_get_min_dpb_size(i);
+
+ s5p_mfc_dec_store_crop_info(ctx);
+ dec->mv_count = s5p_mfc_get_mv_count();
+ if (CODEC_10BIT(ctx) && dev->pdata->support_10bit) {
+ if (s5p_mfc_get_luma_bit_depth_minus8() ||
+ s5p_mfc_get_chroma_bit_depth_minus8() ||
+ s5p_mfc_get_profile() == S5P_FIMV_D_PROFILE_HEVC_MAIN_10) {
+ ctx->is_10bit = 1;
+ mfc_info_ctx("[STREAM][10BIT] 10bit contents, profile: %d, depth: %d/%d\n",
+ s5p_mfc_get_profile(),
+ s5p_mfc_get_luma_bit_depth_minus8() + 8,
+ s5p_mfc_get_chroma_bit_depth_minus8() + 8);
+ }
+ }
+ if (CODEC_422FORMAT(ctx) && dev->pdata->support_422) {
+ if (s5p_mfc_get_chroma_format() == S5P_FIMV_D_CHROMA_422) {
+ ctx->is_422 = 1;
+ mfc_info_ctx("[STREAM] 422 chroma format\n");
+ }
+ }
+
+ if (ctx->img_width == 0 || ctx->img_height == 0)
+ s5p_mfc_change_state(ctx, MFCINST_ERROR);
+ else
+ s5p_mfc_change_state(ctx, MFCINST_HEAD_PARSED);
+
+ if (ctx->state == MFCINST_HEAD_PARSED) {
+ is_interlace = s5p_mfc_is_interlace_picture();
+ is_mbaff = s5p_mfc_is_mbaff_picture();
+ if (is_interlace || is_mbaff)
+ dec->is_interlaced = 1;
+ mfc_debug(2, "[INTERLACE] interlace: %d, mbaff: %d\n", is_interlace, is_mbaff);
+ }
+
+ if (IS_H264_DEC(ctx) || IS_H264_MVC_DEC(ctx) || IS_HEVC_DEC(ctx)) {
+ struct s5p_mfc_buf *src_mb = s5p_mfc_get_buf(&ctx->buf_queue_lock, &ctx->src_buf_queue, MFC_BUF_NO_TOUCH_USED);
+ if (src_mb) {
+ dec->consumed += s5p_mfc_get_consumed_stream();
+ mfc_debug(2, "[STREAM] header total size : %d, consumed : %lu\n",
+ src_mb->vb.vb2_buf.planes[0].bytesused, dec->consumed);
+ if ((dec->consumed > 0) &&
+ (src_mb->vb.vb2_buf.planes[0].bytesused > dec->consumed)) {
+ dec->remained_size = src_mb->vb.vb2_buf.planes[0].bytesused -
+ dec->consumed;
+ mfc_debug(2, "[STREAM] there is remained bytes(%lu) after header parsing\n",
+ dec->remained_size);
+ } else {
+ dec->consumed = 0;
+ dec->remained_size = 0;
+ }
+ }
+ }
+
+ if (IS_VP9_DEC(ctx)) {
+ dec->color_range = s5p_mfc_get_color_range();
+ dec->color_space = s5p_mfc_get_color_space();
+ mfc_debug(2, "color range: %d, color space: %d, It's valid for VP9\n",
+ dec->color_range, dec->color_space);
+ }
+
+ return 0;
+}
+
+/* Handle header encoder interrupt */
+static int mfc_handle_seq_enc(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_enc_params *p = &enc->params;
+ struct s5p_mfc_buf *dst_mb;
+ int ret;
+
+ enc->header_size = s5p_mfc_get_enc_strm_size();
+ mfc_debug(2, "[STREAM] encoded slice type: %d, header size: %d, display order: %d\n",
+ s5p_mfc_get_enc_slice_type(), enc->header_size,
+ s5p_mfc_get_enc_pic_count());
+
+ if (IS_BPG_ENC(ctx)) {
+ dst_mb = s5p_mfc_get_buf(&ctx->buf_queue_lock, &ctx->dst_buf_queue, MFC_BUF_NO_TOUCH_USED);
+ if (!dst_mb) {
+ mfc_err_dev("no dst buffers\n");
+ return -EAGAIN;
+ }
+
+ dst_mb->vb.vb2_buf.planes[0].data_offset += (enc->header_size +
+ p->codec.bpg.thumb_size + p->codec.bpg.exif_size);
+ mfc_debug(2, "offset for NAL_START: %d (header: %d + thumb: %d + exif: %d)\n",
+ dst_mb->vb.vb2_buf.planes[0].data_offset,
+ enc->header_size,
+ p->codec.bpg.thumb_size,
+ p->codec.bpg.exif_size);
+ } else {
+ if ((p->seq_hdr_mode == V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) ||
+ (p->seq_hdr_mode == V4L2_MPEG_VIDEO_HEADER_MODE_AT_THE_READY)) {
+ dst_mb = s5p_mfc_get_del_buf(&ctx->buf_queue_lock,
+ &ctx->dst_buf_queue, MFC_BUF_NO_TOUCH_USED);
+ if (!dst_mb) {
+ mfc_err_dev("no dst buffers\n");
+ return -EAGAIN;
+ }
+
+ vb2_set_plane_payload(&dst_mb->vb.vb2_buf, 0, s5p_mfc_get_enc_strm_size());
+ vb2_buffer_done(&dst_mb->vb.vb2_buf, VB2_BUF_STATE_DONE);
+
+ /* encoder dst buffer CFW UNPROT */
+ if (ctx->is_drm) {
+ int index = dst_mb->vb.vb2_buf.index;
+
+ s5p_mfc_stream_unprotect(ctx, dst_mb, index);
+ }
+ }
+ }
+
+ ctx->dpb_count = s5p_mfc_get_enc_dpb_count();
+ ctx->scratch_buf_size = s5p_mfc_get_enc_scratch_size();
+
+ /* If the ROI is enabled at SEQ_START, clear ROI_ENABLE bit */
+ s5p_mfc_clear_roi_enable(dev);
+
+ if (!ctx->codec_buffer_allocated) {
+ mfc_debug(2, "[DRC] previous codec buffer is exist\n");
+
+ if (dev->has_mmcache && dev->mmcache.is_on_status)
+ s5p_mfc_invalidate_mmcache(dev);
+
+ s5p_mfc_release_codec_buffers(ctx);
+ }
+ ret = s5p_mfc_alloc_codec_buffers(ctx);
+ if (ret) {
+ mfc_err_ctx("Failed to allocate encoding buffers\n");
+ return ret;
+ }
+
+ s5p_mfc_change_state(ctx, MFCINST_HEAD_PARSED);
+
+ return 0;
+}
+
+static inline int is_err_condition(unsigned int err)
+{
+ if (err == S5P_FIMV_ERR_NO_AVAILABLE_DPB ||
+ err == S5P_FIMV_ERR_INSUFFICIENT_DPB_SIZE ||
+ err == S5P_FIMV_ERR_INSUFFICIENT_NUM_DPB ||
+ err == S5P_FIMV_ERR_INSUFFICIENT_MV_BUF_SIZE ||
+ err == S5P_FIMV_ERR_INSUFFICIENT_SCRATCH_BUF_SIZE)
+ return 1;
+
+ return 0;
+}
+
+irqreturn_t s5p_mfc_top_half_irq(int irq, void *priv)
+{
+ struct s5p_mfc_dev *dev = priv;
+ struct s5p_mfc_ctx *ctx;
+ unsigned int err;
+ unsigned int reason;
+
+ ctx = dev->ctx[dev->curr_ctx];
+ if (!ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return IRQ_WAKE_THREAD;
+ }
+
+ reason = s5p_mfc_get_int_reason();
+ err = s5p_mfc_get_int_err();
+ mfc_debug(2, "[c:%d] Int reason: %d (err: %d)\n",
+ dev->curr_ctx, reason, err);
+ MFC_TRACE_CTX("<< INT(top): %d\n", reason);
+
+ s5p_mfc_perf_measure_off(dev);
+
+ return IRQ_WAKE_THREAD;
+}
+
+/*
+ * Return value description
+ * 0: NAL-Q is handled successfully
+ * 1: NAL_START command
+ * -1: Error
+*/
+static inline int mfc_nal_q_irq(struct s5p_mfc_dev *dev,
+ unsigned int reason, unsigned int err)
+{
+ int ret = -1;
+ unsigned int errcode;
+
+ nal_queue_handle *nal_q_handle = dev->nal_q_handle;
+ EncoderOutputStr *pOutStr;
+
+ switch (reason) {
+ case S5P_FIMV_R2H_CMD_QUEUE_DONE_RET:
+ pOutStr = s5p_mfc_nal_q_dequeue_out_buf(dev,
+ nal_q_handle->nal_q_out_handle, &errcode);
+ if (pOutStr) {
+ if (s5p_mfc_nal_q_handle_out_buf(dev, pOutStr))
+ mfc_err_dev("[NALQ] Failed to handle out buf\n");
+ } else {
+ mfc_err_dev("[NALQ] pOutStr is NULL\n");
+ }
+
+ if (nal_q_handle->nal_q_exception)
+ s5p_mfc_set_bit(nal_q_handle->nal_q_out_handle->nal_q_ctx,
+ &dev->work_bits);
+ s5p_mfc_clear_int_sfr();
+
+ if (!nal_q_handle->nal_q_exception)
+ s5p_mfc_nal_q_clock_off(dev, nal_q_handle);
+
+ ret = 0;
+ break;
+ case S5P_FIMV_R2H_CMD_COMPLETE_QUEUE_RET:
+ s5p_mfc_watchdog_stop_tick(dev);
+ nal_q_handle->nal_q_state = NAL_Q_STATE_CREATED;
+ MFC_TRACE_DEV("** NAL Q state : %d\n", nal_q_handle->nal_q_state);
+ mfc_debug(2, "[NALQ] return to created state\n");
+ s5p_mfc_nal_q_cleanup_queue(dev);
+ s5p_mfc_nal_q_cleanup_clock(dev);
+ s5p_mfc_clear_int_sfr();
+ s5p_mfc_pm_clock_off(dev);
+ s5p_mfc_wake_up_dev(dev, reason, err);
+
+ ret = 0;
+ break;
+ default:
+ if (nal_q_handle->nal_q_state == NAL_Q_STATE_STARTED ||
+ nal_q_handle->nal_q_state == NAL_Q_STATE_STOPPED) {
+ mfc_err_dev("[NALQ] Should not be here! state: %d, int reason : %d\n",
+ nal_q_handle->nal_q_state, reason);
+ s5p_mfc_clear_int_sfr();
+
+ ret = -1;
+ } else {
+ /* NAL START */
+ ret = 1;
+ }
+
+ break;
+ }
+
+ if (ret == 0)
+ queue_work(dev->butler_wq, &dev->butler_work);
+
+ return ret;
+}
+
+static inline int mfc_handle_done_frame(struct s5p_mfc_ctx *ctx,
+ unsigned int reason, unsigned int err)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc *enc = NULL;
+
+ if (ctx->type == MFCINST_DECODER) {
+ if (ctx->state == MFCINST_SPECIAL_PARSING_NAL) {
+ s5p_mfc_clear_int_sfr();
+ s5p_mfc_pm_clock_off(dev);
+ s5p_mfc_clear_bit(ctx->num, &dev->work_bits);
+ s5p_mfc_change_state(ctx, MFCINST_RUNNING);
+ s5p_mfc_wake_up_ctx(ctx, reason, err);
+ return 0;
+ }
+ mfc_handle_frame(ctx, reason, err);
+ } else if (ctx->type == MFCINST_ENCODER) {
+ if (ctx->otf_handle) {
+ s5p_mfc_otf_handle_stream(ctx);
+ return 1;
+ }
+ enc = ctx->enc_priv;
+ if (reason == S5P_FIMV_R2H_CMD_SLICE_DONE_RET) {
+ dev->preempt_ctx = ctx->num;
+ enc->buf_full = 0;
+ enc->in_slice = 1;
+ } else if (reason == S5P_FIMV_R2H_CMD_ENC_BUFFER_FULL_RET) {
+ mfc_err_ctx("stream buffer size(%d) isn't enough\n",
+ s5p_mfc_get_enc_strm_size());
+ dev->preempt_ctx = ctx->num;
+ enc->buf_full = 1;
+ enc->in_slice = 0;
+ } else {
+ enc->buf_full = 0;
+ enc->in_slice = 0;
+ }
+ mfc_handle_stream(ctx);
+ }
+
+ return 1;
+}
+
+static inline void mfc_handle_nal_abort(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+
+ if (ctx->type == MFCINST_ENCODER) {
+ s5p_mfc_change_state(ctx, MFCINST_RUNNING_BUF_FULL);
+ enc->buf_full = 0;
+ if (IS_VP8_ENC(ctx))
+ mfc_err_ctx("stream buffer size isn't enough\n");
+ mfc_handle_stream(ctx);
+ } else {
+ s5p_mfc_change_state(ctx, MFCINST_ABORT);
+ }
+}
+
+static int mfc_irq_dev(struct s5p_mfc_dev *dev, unsigned int reason, unsigned int err)
+{
+ /* Stop the timeout watchdog */
+ if (reason != S5P_FIMV_R2H_CMD_FW_STATUS_RET)
+ s5p_mfc_watchdog_stop_tick(dev);
+
+ switch (reason) {
+ case S5P_FIMV_R2H_CMD_CACHE_FLUSH_RET:
+ case S5P_FIMV_R2H_CMD_SYS_INIT_RET:
+ case S5P_FIMV_R2H_CMD_FW_STATUS_RET:
+ case S5P_FIMV_R2H_CMD_SLEEP_RET:
+ case S5P_FIMV_R2H_CMD_WAKEUP_RET:
+ s5p_mfc_clear_int_sfr();
+ s5p_mfc_wake_up_dev(dev, reason, err);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int mfc_irq_ctx(struct s5p_mfc_ctx *ctx, unsigned int reason, unsigned int err)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ switch (reason) {
+ case S5P_FIMV_R2H_CMD_ERR_RET:
+ if (ctx->otf_handle) {
+ s5p_mfc_otf_handle_error(ctx, reason, err);
+ break;
+ }
+ /* An error has occured */
+ if (ctx->state == MFCINST_RUNNING || ctx->state == MFCINST_ABORT) {
+ if ((s5p_mfc_get_err(err) >= S5P_FIMV_ERR_WARNINGS_START) &&
+ (s5p_mfc_get_err(err) <= S5P_FIMV_ERR_WARNINGS_END))
+ mfc_handle_frame(ctx, reason, err);
+ else
+ mfc_handle_frame_error(ctx, reason, err);
+ } else {
+ mfc_handle_error(ctx, reason, err);
+ }
+ break;
+ case S5P_FIMV_R2H_CMD_SLICE_DONE_RET:
+ case S5P_FIMV_R2H_CMD_FIELD_DONE_RET:
+ case S5P_FIMV_R2H_CMD_FRAME_DONE_RET:
+ case S5P_FIMV_R2H_CMD_ENC_BUFFER_FULL_RET:
+ return mfc_handle_done_frame(ctx, reason, err);
+ case S5P_FIMV_R2H_CMD_COMPLETE_SEQ_RET:
+ if (ctx->type == MFCINST_ENCODER) {
+ mfc_handle_stream(ctx);
+ s5p_mfc_change_state(ctx, MFCINST_RUNNING);
+ } else if (ctx->type == MFCINST_DECODER) {
+ return mfc_handle_done_frame(ctx, reason, err);
+ }
+ break;
+ case S5P_FIMV_R2H_CMD_SEQ_DONE_RET:
+ if (ctx->type == MFCINST_ENCODER) {
+ if (ctx->otf_handle) {
+ s5p_mfc_otf_handle_seq(ctx);
+ break;
+ }
+ mfc_handle_seq_enc(ctx);
+ } else if (ctx->type == MFCINST_DECODER) {
+ mfc_handle_seq_dec(ctx);
+ }
+ break;
+ case S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET:
+ ctx->inst_no = s5p_mfc_get_inst_no();
+ s5p_mfc_change_state(ctx, MFCINST_GOT_INST);
+ break;
+ case S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET:
+ s5p_mfc_change_state(ctx, MFCINST_FREE);
+ break;
+ case S5P_FIMV_R2H_CMD_NAL_ABORT_RET:
+ mfc_handle_nal_abort(ctx);
+ break;
+ case S5P_FIMV_R2H_CMD_DPB_FLUSH_RET:
+ s5p_mfc_change_state(ctx, MFCINST_ABORT);
+ break;
+ case S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET:
+ if (err != 0) {
+ mfc_err_ctx("INIT_BUFFERS_RET error: %d\n", err);
+ break;
+ }
+
+ s5p_mfc_change_state(ctx, MFCINST_RUNNING);
+ if (ctx->type == MFCINST_DECODER) {
+ if (ctx->wait_state == WAIT_DECODING) {
+ ctx->wait_state = WAIT_INITBUF_DONE;
+ mfc_debug(2, "INIT_BUFFER has done, but can't start decoding\n");
+ }
+ if (ctx->is_dpb_realloc)
+ ctx->is_dpb_realloc = 0;
+ }
+ break;
+ default:
+ mfc_err_ctx("Unknown int reason: %d\n", reason);
+ }
+
+ return 1;
+}
+
+/* Interrupt processing */
+irqreturn_t s5p_mfc_irq(int irq, void *priv)
+{
+ struct s5p_mfc_dev *dev = priv;
+ struct s5p_mfc_ctx *ctx;
+ unsigned int reason;
+ unsigned int err;
+ int ret = -1;
+
+ mfc_debug_enter();
+
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ goto irq_end;
+ }
+
+ if (s5p_mfc_pm_get_pwr_ref_cnt(dev) == 0) {
+ mfc_err_dev("no mfc power on\n");
+ call_dop(dev, dump_and_stop_debug_mode, dev);
+ goto irq_end;
+ }
+
+ /* Get the reason of interrupt and the error code */
+ reason = s5p_mfc_get_int_reason();
+ err = s5p_mfc_get_int_err();
+ mfc_debug(1, "Int reason: %d (err: %d)\n", reason, err);
+ MFC_TRACE_DEV("<< INT: %d\n", reason);
+
+ dev->preempt_ctx = MFC_NO_INSTANCE_SET;
+
+ if (dbg_enable && (reason != S5P_FIMV_R2H_CMD_QUEUE_DONE_RET))
+ s5p_mfc_dbg_disable(dev);
+
+ if ((sfr_dump & MFC_DUMP_ERR_INT) && (reason == S5P_FIMV_R2H_CMD_ERR_RET))
+ call_dop(dev, dump_regs, dev);
+
+ if ((sfr_dump & MFC_DUMP_WARN_INT) &&
+ (err && (reason != S5P_FIMV_R2H_CMD_ERR_RET)))
+ call_dop(dev, dump_regs, dev);
+
+ if (is_err_condition(err))
+ call_dop(dev, dump_and_stop_debug_mode, dev);
+
+ if (dev->nal_q_handle) {
+ ret = mfc_nal_q_irq(dev, reason, err);
+ if (ret == 0) {
+ mfc_debug(2, "[NALQ] command was handled\n");
+ goto irq_end;
+ } else if (ret == 1){
+ /* Path through */
+ mfc_debug(2, "NAL_START command will be handled\n");
+ } else {
+ mfc_debug(2, "[NALQ] command handling Error\n");
+ goto irq_end;
+ }
+ }
+
+ ret = mfc_irq_dev(dev, reason, err);
+ if (!ret)
+ goto irq_end;
+
+ ctx = dev->ctx[dev->curr_ctx];
+ if (!ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ s5p_mfc_clear_int_sfr();
+ s5p_mfc_pm_clock_off(dev);
+ goto irq_end;
+ }
+
+ ret = mfc_irq_ctx(ctx, reason, err);
+ if (!ret)
+ goto irq_end;
+
+ /* clean-up interrupt */
+ s5p_mfc_clear_int_sfr();
+
+ if ((ctx->state != MFCINST_RES_CHANGE_INIT) && (s5p_mfc_ctx_ready(ctx) == 0))
+ s5p_mfc_clear_bit(ctx->num, &dev->work_bits);
+
+ if (ctx->otf_handle) {
+ if (s5p_mfc_otf_ctx_ready(ctx))
+ s5p_mfc_set_bit(ctx->num, &dev->work_bits);
+ else
+ s5p_mfc_clear_bit(ctx->num, &dev->work_bits);
+ }
+
+ s5p_mfc_hwlock_handler_irq(dev, ctx, reason, err);
+
+irq_end:
+ mfc_debug_leave();
+ return IRQ_HANDLED;
+}
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_irq.h
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __MFC_IRQ_H
+#define __MFC_IRQ_H __FILE__
+
+#include <linux/interrupt.h>
+
+#include "mfc_common.h"
+
+#include "mfc_utils.h"
+
+irqreturn_t s5p_mfc_top_half_irq(int irq, void *priv);
+irqreturn_t s5p_mfc_irq(int irq, void *priv);
+
+static inline void s5p_mfc_handle_force_change_status(struct s5p_mfc_ctx *ctx)
+{
+ if (ctx->state != MFCINST_ABORT && ctx->state != MFCINST_HEAD_PARSED &&
+ ctx->state != MFCINST_RES_CHANGE_FLUSH)
+ s5p_mfc_change_state(ctx, MFCINST_RUNNING);
+}
+
+#endif /* __MFC_IRQ_H */
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_macros.h
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __MFC_MACROS_H
+#define __MFC_MACROS_H __FILE__
+
+#define WIDTH_MB(x_size) ((x_size + 15) / 16)
+#define HEIGHT_MB(y_size) ((y_size + 15) / 16)
+
+/*
+ Note that lcu_width and lcu_height are defined as follows :
+ lcu_width = (frame_width + lcu_size - 1)/lcu_size
+ lcu_height = (frame_height + lcu_size - 1)/lcu_size.
+ (lcu_size is 32(encoder) or 64(decoder))
+*/
+#define DEC_LCU_WIDTH(x_size) ((x_size + 63) / 64)
+#define ENC_LCU_WIDTH(x_size) ((x_size + 31) / 32)
+#define DEC_LCU_HEIGHT(y_size) ((y_size + 63) / 64)
+#define ENC_LCU_HEIGHT(y_size) ((y_size + 31) / 32)
+
+#define STREAM_BUF_ALIGN 512
+#define MFC_LINEAR_BUF_SIZE 256
+#define set_strm_size_max(cpb_max) ((cpb_max) - STREAM_BUF_ALIGN)
+
+#define DEC_STATIC_BUFFER_SIZE 20480
+
+#define DEC_MV_SIZE_MB(x, y) (WIDTH_MB(x) * (((HEIGHT_MB(y)+1)/2)*2) * 64 + 1024)
+#define DEC_HEVC_MV_SIZE(x, y) (DEC_LCU_WIDTH(x) * DEC_LCU_HEIGHT(y) * 256 + 512)
+
+#define ENC_HEVC_LUMA_DPB_10B_SIZE(x, y) \
+ ((x + 63) / 64) * 64 * ((y + 31) / 32 ) * 32 + \
+ (((((ENC_LCU_WIDTH(x) * 32 + 3) / 4) + 15) / 16) * 16) * \
+ ((y + 31) / 32 ) * 32 + 64
+#define ENC_HEVC_CHROMA_DPB_10B_SIZE(x, y) \
+ ((x + 63) / 64) * 64 * ((y + 31) / 32 ) * 32 + \
+ (((((ENC_LCU_WIDTH(x) * 32 + 3) / 4) + 15) / 16) * 16) * \
+ ((y + 31) / 32 ) * 32 + 64
+#define ENC_VP9_LUMA_DPB_10B_SIZE(x, y) \
+ (((x * 2 + 127) / 128) * 128) * \
+ ((y + 31) / 32 ) * 32 + 64
+#define ENC_VP9_CHROMA_DPB_10B_SIZE(x, y) \
+ (((x * 2 + 127) / 128) * 128) * \
+ ((y + 31) / 32 ) * 32 + 64
+#define ENC_LUMA_DPB_SIZE(x, y) \
+ ((x + 63) / 64) * 64 * ((y + 31) / 32 ) * 32 + 64
+#define ENC_CHROMA_DPB_SIZE(x, y) \
+ ((x + 63) / 64) * 64 * ((((y + 31) / 32 ) * 32) / 2) + 64
+
+#define ENC_V100_H264_ME_SIZE(x, y) \
+ (((x + 3) * (y + 3) * 8) + ((((x * y) + 63) / 64) * 32) + (((y * 64) + 2304) * (x + 7) / 8))
+#define ENC_V100_MPEG4_ME_SIZE(x, y) \
+ (((x + 3) * (y + 3) * 8) + ((((x * y) + 127) / 128) * 16) + (((y * 64) + 2304) * (x + 7) / 8))
+#define ENC_V100_VP8_ME_SIZE(x, y) \
+ (((x + 3) * (y + 3) * 8) + (((y * 64) + 2304) * (x + 7) / 8))
+#define ENC_V100_VP9_ME_SIZE(x, y) \
+ ((((x * 2) + 3) * ((y * 2) + 3) * 128) + (((y * 256) + 2304) * (x + 1) / 2))
+#define ENC_V100_HEVC_ME_SIZE(x, y) \
+ (((x + 3) * (y + 3) * 32) + (((y * 128) + 2304) * (x + 3) / 4))
+
+#endif /* __MFC_MACROS_H */
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_mem.c
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "mfc_mem.h"
+
+struct vb2_mem_ops *s5p_mfc_mem_ops(void)
+{
+ return (struct vb2_mem_ops *)&vb2_dma_sg_memops;
+}
+
+void s5p_mfc_mem_clean(struct s5p_mfc_dev *dev,
+ struct s5p_mfc_special_buf *special_buf,
+ off_t offset, size_t size)
+{
+ __dma_map_area(special_buf->vaddr + offset, size, DMA_TO_DEVICE);
+ return;
+}
+
+void s5p_mfc_mem_invalidate(struct s5p_mfc_dev *dev,
+ struct s5p_mfc_special_buf *special_buf,
+ off_t offset, size_t size)
+{
+ __dma_map_area(special_buf->vaddr + offset, size, DMA_FROM_DEVICE);
+ return;
+}
+
+int s5p_mfc_mem_get_user_shared_handle(struct s5p_mfc_ctx *ctx,
+ struct mfc_user_shared_handle *handle)
+{
+ int ret = 0;
+
+ handle->dma_buf = dma_buf_get(handle->fd);
+ if (IS_ERR(handle->dma_buf)) {
+ mfc_err_ctx("Failed to import fd\n");
+ ret = PTR_ERR(handle->dma_buf);
+ goto import_dma_fail;
+ }
+
+ handle->vaddr = dma_buf_vmap(handle->dma_buf);
+ if (handle->vaddr == NULL) {
+ mfc_err_ctx("Failed to get kernel virtual address\n");
+ ret = -EINVAL;
+ goto map_kernel_fail;
+ }
+
+ return 0;
+
+map_kernel_fail:
+ handle->vaddr = NULL;
+ dma_buf_put(handle->dma_buf);
+
+import_dma_fail:
+ handle->dma_buf = NULL;
+ handle->fd = -1;
+ return ret;
+}
+
+void s5p_mfc_mem_cleanup_user_shared_handle(struct s5p_mfc_ctx *ctx,
+ struct mfc_user_shared_handle *handle)
+{
+ if (handle->vaddr)
+ dma_buf_vunmap(handle->dma_buf, handle->vaddr);
+ if (handle->dma_buf)
+ dma_buf_put(handle->dma_buf);
+
+ handle->dma_buf = NULL;
+ handle->vaddr = NULL;
+ handle->fd = -1;
+}
+
+int s5p_mfc_mem_ion_alloc(struct s5p_mfc_dev *dev,
+ struct s5p_mfc_special_buf *special_buf)
+{
+ struct s5p_mfc_ctx *ctx = dev->ctx[dev->curr_ctx];
+ int flag;
+ const char *heapname;
+
+ switch (special_buf->buftype) {
+ case MFCBUF_NORMAL:
+ heapname = "ion_system_heap";
+ flag = 0;
+ break;
+ case MFCBUF_NORMAL_FW:
+ heapname = "vnfw_heap";
+ flag = 0;
+ break;
+ case MFCBUF_DRM:
+ heapname = "vframe_heap";
+ flag = ION_FLAG_PROTECTED;
+ break;
+ case MFCBUF_DRM_FW:
+ heapname = "vfw_heap";
+ flag = ION_FLAG_PROTECTED;
+ break;
+ default:
+ mfc_err_ctx("not supported mfc mem type: %d, heapname: %s\n",
+ special_buf->buftype, heapname);
+ return -EINVAL;
+ }
+ special_buf->dma_buf =
+ ion_alloc_dmabuf(heapname, special_buf->size, flag);
+ if (IS_ERR(special_buf->dma_buf)) {
+ mfc_err_ctx("Failed to allocate buffer (err %ld)\n",
+ PTR_ERR(special_buf->dma_buf));
+ call_dop(dev, dump_and_stop_debug_mode, dev);
+ goto err_ion_alloc;
+ }
+
+ special_buf->attachment = dma_buf_attach(special_buf->dma_buf, dev->device);
+ if (IS_ERR(special_buf->attachment)) {
+ mfc_err_ctx("Failed to get dma_buf_attach (err %ld)\n",
+ PTR_ERR(special_buf->attachment));
+ call_dop(dev, dump_and_stop_debug_mode, dev);
+ goto err_attach;
+ }
+
+ special_buf->sgt = dma_buf_map_attachment(special_buf->attachment,
+ DMA_BIDIRECTIONAL);
+ if (IS_ERR(special_buf->sgt)) {
+ mfc_err_ctx("Failed to get sgt (err %ld)\n",
+ PTR_ERR(special_buf->sgt));
+ call_dop(dev, dump_and_stop_debug_mode, dev);
+ goto err_map;
+ }
+
+ special_buf->daddr = ion_iovmm_map(special_buf->attachment, 0,
+ special_buf->size, DMA_BIDIRECTIONAL, 0);
+ if (IS_ERR_VALUE(special_buf->daddr)) {
+ mfc_err_ctx("Failed to allocate iova (err 0x%p)\n",
+ &special_buf->daddr);
+ call_dop(dev, dump_and_stop_debug_mode, dev);
+ goto err_iovmm;
+ }
+
+ special_buf->vaddr = dma_buf_vmap(special_buf->dma_buf);
+ if (IS_ERR(special_buf->vaddr)) {
+ mfc_err_ctx("Failed to get vaddr (err 0x%p)\n",
+ &special_buf->vaddr);
+ call_dop(dev, dump_and_stop_debug_mode, dev);
+ goto err_vaddr;
+ }
+
+ return 0;
+err_vaddr:
+ special_buf->vaddr = NULL;
+ ion_iovmm_unmap(special_buf->attachment, special_buf->daddr);
+
+err_iovmm:
+ special_buf->daddr = 0;
+ dma_buf_unmap_attachment(special_buf->attachment, special_buf->sgt,
+ DMA_BIDIRECTIONAL);
+err_map:
+ special_buf->sgt = NULL;
+ dma_buf_detach(special_buf->dma_buf, special_buf->attachment);
+err_attach:
+ special_buf->attachment = NULL;
+ dma_buf_put(special_buf->dma_buf);
+err_ion_alloc:
+ special_buf->dma_buf = NULL;
+ return -ENOMEM;
+}
+
+void s5p_mfc_mem_ion_free(struct s5p_mfc_dev *dev,
+ struct s5p_mfc_special_buf *special_buf)
+{
+ if (special_buf->vaddr)
+ dma_buf_vunmap(special_buf->dma_buf, special_buf->vaddr);
+ if (special_buf->daddr)
+ ion_iovmm_unmap(special_buf->attachment, special_buf->daddr);
+ if (special_buf->sgt)
+ dma_buf_unmap_attachment(special_buf->attachment,
+ special_buf->sgt, DMA_BIDIRECTIONAL);
+ if (special_buf->attachment)
+ dma_buf_detach(special_buf->dma_buf, special_buf->attachment);
+ if (special_buf->dma_buf)
+ dma_buf_put(special_buf->dma_buf);
+
+ special_buf->dma_buf = NULL;
+ special_buf->attachment = NULL;
+ special_buf->sgt = NULL;
+ special_buf->daddr = 0;
+ special_buf->vaddr = NULL;
+}
+
+void s5p_mfc_bufcon_put_daddr(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *mfc_buf, int plane)
+{
+ int i;
+
+ for (i = 0; i < mfc_buf->num_valid_bufs; i++) {
+ if (mfc_buf->addr[i][plane]) {
+ mfc_debug(4, "[BUFCON] put batch buf addr[%d][%d]: 0x%08llx\n",
+ i, plane, mfc_buf->addr[i][plane]);
+ ion_iovmm_unmap(mfc_buf->attachments[i][plane], mfc_buf->addr[i][plane]);
+ }
+ if (mfc_buf->attachments[i][plane])
+ dma_buf_detach(mfc_buf->dmabufs[i][plane], mfc_buf->attachments[i][plane]);
+ if (mfc_buf->dmabufs[i][plane])
+ dma_buf_put(mfc_buf->dmabufs[i][plane]);
+
+ mfc_buf->addr[i][plane] = 0;
+ mfc_buf->attachments[i][plane] = NULL;
+ mfc_buf->dmabufs[i][plane] = NULL;
+ }
+}
+
+int s5p_mfc_bufcon_get_daddr(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *mfc_buf,
+ struct dma_buf *bufcon_dmabuf, int plane)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_raw_info *raw = &ctx->raw_buf;
+ int i, j = 0;
+ u32 mask;
+
+ if (dmabuf_container_get_mask(bufcon_dmabuf, &mask)) {
+ mfc_err_ctx("[BUFCON] it is not buffer container\n");
+ return -1;
+ } else {
+ mfc_debug(3, "[BUFCON] bufcon mask info %#x\n", mask);
+ }
+
+ for (i = 0; i < mfc_buf->num_bufs_in_batch; i++) {
+ if ((mask & (1 << i)) == 0) {
+ mfc_debug(4, "[BUFCON] unmasked buf[%d]\n", i);
+ continue;
+ }
+
+ mfc_buf->dmabufs[j][plane] = dmabuf_container_get_buffer(bufcon_dmabuf, i);
+ if (IS_ERR(mfc_buf->dmabufs[i][plane])) {
+ mfc_err_ctx("[BUFCON] Failed to get dma_buf (err %ld)",
+ PTR_ERR(mfc_buf->dmabufs[i][plane]));
+ call_dop(dev, dump_and_stop_debug_mode, dev);
+ goto err_get_daddr;
+ }
+
+ mfc_buf->attachments[j][plane] = dma_buf_attach(mfc_buf->dmabufs[i][plane], dev->device);
+ if (IS_ERR(mfc_buf->attachments[i][plane])) {
+ mfc_err_ctx("[BUFCON] Failed to get dma_buf_attach (err %ld)",
+ PTR_ERR(mfc_buf->attachments[i][plane]));
+ call_dop(dev, dump_and_stop_debug_mode, dev);
+ goto err_get_daddr;
+ }
+
+ mfc_buf->addr[j][plane] = ion_iovmm_map(mfc_buf->attachments[i][plane], 0,
+ raw->plane_size[plane], DMA_BIDIRECTIONAL, 0);
+ if (IS_ERR_VALUE(mfc_buf->addr[i][plane])) {
+ mfc_err_ctx("[BUFCON] Failed to allocate iova (err %pa)",
+ &mfc_buf->addr[i][plane]);
+ call_dop(dev, dump_and_stop_debug_mode, dev);
+ goto err_get_daddr;
+ }
+
+ mfc_debug(4, "[BUFCON] get batch buf addr[%d][%d]: 0x%08llx, size: %d\n",
+ j, plane, mfc_buf->addr[j][plane], raw->plane_size[plane]);
+ j++;
+ }
+
+ mfc_buf->num_valid_bufs = j;
+ mfc_debug(3, "[BUFCON] batch buffer has %d buffers\n", mfc_buf->num_valid_bufs);
+
+ return 0;
+
+err_get_daddr:
+ s5p_mfc_bufcon_put_daddr(ctx, mfc_buf, plane);
+ return -1;
+}
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_mem.h
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __MFC_MEM_H
+#define __MFC_MEM_H __FILE__
+
+#include "mfc_common.h"
+
+/* Offset base used to differentiate between CAPTURE and OUTPUT
+* while mmaping */
+#define DST_QUEUE_OFF_BASE (TASK_SIZE / 2)
+
+static inline dma_addr_t s5p_mfc_mem_get_daddr_vb(
+ struct vb2_buffer *vb, unsigned int n)
+{
+ dma_addr_t addr = 0;
+
+ addr = vb2_dma_sg_plane_dma_addr(vb, n);
+ WARN_ON((addr == 0) || IS_ERR_VALUE(addr));
+
+ return addr;
+}
+
+static inline int s5p_mfc_bufcon_get_buf_count(struct dma_buf *dmabuf)
+{
+ return dmabuf_container_get_count(dmabuf);
+}
+
+struct vb2_mem_ops *s5p_mfc_mem_ops(void);
+
+void s5p_mfc_mem_set_cacheable(bool cacheable);
+void s5p_mfc_mem_clean(struct s5p_mfc_dev *dev,
+ struct s5p_mfc_special_buf *specail_buf,
+ off_t offset, size_t size);
+void s5p_mfc_mem_invalidate(struct s5p_mfc_dev *dev,
+ struct s5p_mfc_special_buf *specail_buf,
+ off_t offset, size_t size);
+
+int s5p_mfc_mem_get_user_shared_handle(struct s5p_mfc_ctx *ctx,
+ struct mfc_user_shared_handle *handle);
+void s5p_mfc_mem_cleanup_user_shared_handle(struct s5p_mfc_ctx *ctx,
+ struct mfc_user_shared_handle *handle);
+
+int s5p_mfc_mem_ion_alloc(struct s5p_mfc_dev *dev,
+ struct s5p_mfc_special_buf *special_buf);
+void s5p_mfc_mem_ion_free(struct s5p_mfc_dev *dev,
+ struct s5p_mfc_special_buf *special_buf);
+
+void s5p_mfc_bufcon_put_daddr(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *mfc_buf, int plane);
+int s5p_mfc_bufcon_get_daddr(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *mfc_buf,
+ struct dma_buf *bufcon_dmabuf, int plane);
+#endif /* __MFC_MEM_H */
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_mmcache.c
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "mfc_mmcache.h"
+
+#include "mfc_reg.h"
+
+static const unsigned char mmcache_SFR_0x0010[] = {
+ 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x2A, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const unsigned char mmcache_SFR_0x0040[] = {
+ 0x0E, 0x00, 0x1E, 0x00, 0x0E, 0x00, 0x1E, 0x00, 0x0E, 0x00, 0x1E, 0x00, 0x0E, 0x00, 0x1E, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x10, 0x00, 0x1F, 0x00, 0x10, 0x00, 0x1F, 0x00, 0x10, 0x00, 0x1F, 0x00, 0x10, 0x00, 0x1F, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x0C, 0x00, 0x1F, 0x00, 0x0C, 0x00, 0x1F, 0x00, 0x0C, 0x00, 0x1F, 0x00, 0x0C, 0x00, 0x1F, 0x00,
+ 0x12, 0x00, 0x3F, 0x00, 0x08, 0x00, 0x3F, 0x00, 0x0C, 0x00, 0x3D, 0x00, 0x0C, 0x00, 0x3D, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static void mmcache_print_config(struct s5p_mfc_dev *dev)
+{
+ void __iomem *addr;
+ unsigned int size;
+
+ mfc_debug_enter();
+
+ if (!mmcache_dump)
+ return;
+
+ size = sizeof(mmcache_SFR_0x0010);
+ addr = dev->mmcache.base + MMCACHE_WAY0_CTRL;
+
+ print_hex_dump(KERN_ERR, "[MMCACHE] Config:", DUMP_PREFIX_ADDRESS, 32, 4, addr, size, false);
+
+ size = sizeof(mmcache_SFR_0x0040);
+ addr = dev->mmcache.base + MMCACHE_MASTER_GRP0_RPATH0;
+
+ print_hex_dump(KERN_ERR, "[MMCACHE] Config:", DUMP_PREFIX_ADDRESS, 32, 4, addr, size, false);
+
+ mfc_debug_leave();
+}
+
+static void mmcache_set_config(struct s5p_mfc_dev *dev)
+{
+ unsigned int data, i, size;
+ const unsigned int *sfr_dump;
+
+ mfc_debug_enter();
+
+ size = sizeof(mmcache_SFR_0x0010);
+ sfr_dump = (const unsigned int *)mmcache_SFR_0x0010;
+
+ for (i = 0; i < size; i += 4) {
+ data = sfr_dump[i / 4];
+ MMCACHE_WRITEL(data, MMCACHE_WAY0_CTRL + i);
+ }
+
+ size = sizeof(mmcache_SFR_0x0040);
+ sfr_dump = (const unsigned int *)mmcache_SFR_0x0040;
+
+ for (i = 0; i < size; i += 4) {
+ data = sfr_dump[i / 4];
+ MMCACHE_WRITEL(data, MMCACHE_MASTER_GRP0_RPATH0 + i);
+ }
+
+ mfc_debug(2, "[MMCACHE] mmcache config setting is done\n");
+
+ mfc_debug_leave();
+}
+
+static void mmcache_reset_config(struct s5p_mfc_dev *dev)
+{
+ void __iomem *addr;
+ unsigned int data;
+
+ mfc_debug_enter();
+
+ addr = dev->mmcache.base + MMCACHE_MASTER_GRP_CTRL2;
+ data = 0;
+
+ mfc_debug(2, "[MMCACHE] before write 0x%X: (0x%08llX) 0x%X\n",
+ data, (unsigned long long)(addr),
+ MMCACHE_READL(MMCACHE_MASTER_GRP_CTRL2));
+
+ MMCACHE_WRITEL(data, MMCACHE_MASTER_GRP_CTRL2);
+
+ mfc_debug(2, "[MMCACHE] after write 0x%X: (0x%08llX) 0x%X\n",
+ data, (unsigned long long)(addr),
+ MMCACHE_READL(MMCACHE_MASTER_GRP_CTRL2));
+
+ mfc_debug_leave();
+}
+
+static void mmcache_update_master_grp(struct s5p_mfc_dev *dev)
+{
+ void __iomem *addr;
+ unsigned int data;
+
+ mfc_debug_enter();
+
+ addr = dev->mmcache.base + MMCACHE_GLOBAL_CTRL;
+ data = MMCACHE_GLOBAL_CTRL_VALUE;
+
+ mfc_debug(2, "[MMCACHE] before write 0x%X: (0x%08llX) 0x%X\n",
+ data, (unsigned long long)(addr),
+ MMCACHE_READL(MMCACHE_GLOBAL_CTRL));
+
+ MMCACHE_WRITEL(data, MMCACHE_GLOBAL_CTRL);
+
+ mfc_debug(2, "[MMCACHE] after write 0x%X: (0x%08llX) 0x%X\n",
+ data, (unsigned long long)(addr),
+ MMCACHE_READL(MMCACHE_GLOBAL_CTRL));
+
+ mfc_debug_leave();
+}
+
+static void mmcache_enable_clock_gating(struct s5p_mfc_dev *dev)
+{
+ void __iomem *addr;
+ unsigned int data;
+
+ mfc_debug_enter();
+
+ addr = dev->mmcache.base + MMCACHE_CG_CONTROL;
+ data = MMCACHE_CG_CONTROL_VALUE;
+
+ mfc_debug(2, "[MMCACHE] before write 0x%X: (0x%08llX) 0x%X\n",
+ data, (unsigned long long)(addr),
+ MMCACHE_READL(MMCACHE_CG_CONTROL));
+
+ MMCACHE_WRITEL(data, MMCACHE_CG_CONTROL);
+
+ mfc_debug(2, "[MMCACHE] after write 0x%X: (0x%08llX) 0x%X\n",
+ data, (unsigned long long)(addr),
+ MMCACHE_READL(MMCACHE_CG_CONTROL));
+
+ mfc_debug_leave();
+}
+
+void s5p_mfc_mmcache_enable(struct s5p_mfc_dev *dev)
+{
+ mfc_debug_enter();
+
+ if (mmcache_disable)
+ return;
+
+ mmcache_set_config(dev);
+ mmcache_print_config(dev);
+ mmcache_update_master_grp(dev);
+ mmcache_enable_clock_gating(dev);
+
+ dev->mmcache.is_on_status = 1;
+ mfc_info_dev("[MMCACHE] enabled\n");
+ MFC_TRACE_DEV("[MMCACHE] enabled\n");
+
+ mfc_debug_leave();
+}
+
+void s5p_mfc_mmcache_disable(struct s5p_mfc_dev *dev)
+{
+ mfc_debug_enter();
+
+ mmcache_reset_config(dev);
+ mmcache_update_master_grp(dev);
+
+ dev->mmcache.is_on_status = 0;
+ mfc_info_dev("[MMCACHE] disabled\n");
+ MFC_TRACE_DEV("[MMCACHE] disabled\n");
+
+ mfc_debug_leave();
+}
+
+void s5p_mfc_invalidate_mmcache(struct s5p_mfc_dev *dev)
+{
+ void __iomem *addr;
+ unsigned int data;
+ unsigned long timeout;
+
+ mfc_debug_enter();
+
+ addr = dev->mmcache.base + MMCACHE_INVALIDATE;
+ data = MMCACHE_INVALIDATE_VALUE;
+
+ mfc_debug(2, "[MMCACHE] before write 0x%X: (0x%08llX) 0x%X\n",
+ data, (unsigned long long)(addr),
+ MMCACHE_READL(MMCACHE_INVALIDATE));
+
+ MMCACHE_WRITEL(data, MMCACHE_INVALIDATE);
+
+ mfc_debug(2, "[MMCACHE] after write 0x%X: (0x%08llX) 0x%X\n",
+ data, (unsigned long long)(addr),
+ MMCACHE_READL(MMCACHE_INVALIDATE));
+
+ addr = dev->mmcache.base + MMCACHE_INVALIDATE_STATUS;
+
+ timeout = jiffies + msecs_to_jiffies(MMCACHE_INVAL_TIMEOUT);
+ while (1) {
+ if (MMCACHE_READL(MMCACHE_INVALIDATE_STATUS) == 0) {
+ mfc_debug(2, "[MMCACHE] invalidate done: (0x%08llX) 0x%X\n",
+ (unsigned long long)(addr), __raw_readl(addr));
+ break;
+ }
+ if (time_after(jiffies, timeout)) {
+ mfc_err_dev("[MMCACHE] Timeout while invalidation\n");
+ call_dop(dev, dump_and_stop_debug_mode, dev);
+ break;
+ }
+ }
+
+ mfc_debug(2, "[MMCACHE] invalidated\n");
+ MFC_TRACE_DEV("[MMCACHE] invalidated\n");
+
+ mfc_debug_leave();
+}
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_mmcache.h
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __MFC_MMCACHE_H
+#define __MFC_MMCACHE_H __FILE__
+
+#include "mfc_common.h"
+
+#define MMCACHE_GLOBAL_CTRL 0x0000
+#define MMCACHE_INVALIDATE_STATUS 0x0008
+#define MMCACHE_WAY0_CTRL 0x0010
+#define MMCACHE_MASTER_GRP_CTRL2 0x0028
+#define MMCACHE_MASTER_GRP0_RPATH0 0x0040
+#define MMCACHE_CG_CONTROL 0x0400
+#define MMCACHE_INVALIDATE 0x0114
+
+#define MMCACHE_GLOBAL_CTRL_VALUE 0x2
+#define MMCACHE_CG_CONTROL_VALUE 0x7FF
+#define MMCACHE_INVALIDATE_VALUE 0x41
+
+/* Need HW lock to call this function */
+
+void s5p_mfc_mmcache_enable(struct s5p_mfc_dev *dev);
+void s5p_mfc_mmcache_disable(struct s5p_mfc_dev *dev);
+
+
+/* Need HW lock to call this function */
+void s5p_mfc_invalidate_mmcache(struct s5p_mfc_dev *dev);
+
+#endif /* __MFC_MMCACHE_H */
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_nal_q.c
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "mfc_nal_q.h"
+
+#include "mfc_sync.h"
+
+#include "mfc_pm.h"
+#include "mfc_cal.h"
+#include "mfc_reg.h"
+
+#include "mfc_qos.h"
+#include "mfc_queue.h"
+#include "mfc_utils.h"
+#include "mfc_buf.h"
+#include "mfc_mem.h"
+
+#define CBR_I_LIMIT_MAX 5
+int s5p_mfc_nal_q_check_enable(struct s5p_mfc_dev *dev)
+{
+ struct s5p_mfc_ctx *temp_ctx;
+ struct s5p_mfc_dec *dec = NULL;
+ struct s5p_mfc_enc *enc = NULL;
+ struct s5p_mfc_enc_params *p = NULL;
+ int i;
+
+ mfc_debug_enter();
+
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ if (nal_q_disable)
+ return 0;
+
+ for (i = 0; i < MFC_NUM_CONTEXTS; i++) {
+ temp_ctx = dev->ctx[i];
+ if (temp_ctx) {
+ /* NAL-Q doesn't support drm */
+ if (temp_ctx->is_drm) {
+ mfc_debug(2, "There is a drm ctx. Can't start NAL-Q\n");
+ return 0;
+ }
+ /* NAL-Q can be enabled when all ctx are in running state */
+ if (temp_ctx->state != MFCINST_RUNNING) {
+ mfc_debug(2, "There is a ctx which is not in running state. "
+ "index: %d, state: %d\n", i, temp_ctx->state);
+ return 0;
+ }
+ /* NAL-Q can't use the command about last frame */
+ if (s5p_mfc_is_last_frame(temp_ctx) == 1) {
+ mfc_debug(2, "There is a last frame. index: %d\n", i);
+ return 0;
+ }
+ /* NAL-Q doesn't support OTF mode */
+ if (temp_ctx->otf_handle) {
+ mfc_debug(2, "There is a OTF node\n");
+ return 0;
+ }
+ /* NAL-Q doesn't support BPG */
+ if (IS_BPG_DEC(temp_ctx) || IS_BPG_ENC(temp_ctx)) {
+ mfc_debug(2, "BPG codec type\n");
+ return 0;
+ }
+ /* NAL-Q doesn't support multi-frame, interlaced, black bar */
+ if (temp_ctx->type == MFCINST_DECODER) {
+ dec = temp_ctx->dec_priv;
+ if (!dec) {
+ mfc_debug(2, "There is no dec\n");
+ return 0;
+ }
+ if ((dec->has_multiframe && CODEC_MULTIFRAME(temp_ctx)) || dec->consumed) {
+ mfc_debug(2, "[MULTIFRAME] There is a multi frame or consumed header\n");
+ return 0;
+ }
+ if (dec->is_dpb_full) {
+ mfc_debug(2, "[DPB] All buffers are referenced\n");
+ return 0;
+ }
+ if (dec->is_interlaced) {
+ mfc_debug(2, "[INTERLACE] There is a interlaced stream\n");
+ return 0;
+ }
+ if (dec->detect_black_bar) {
+ mfc_debug(2, "[BLACKBAR] black bar detection is enabled\n");
+ return 0;
+ }
+ /* NAL-Q doesn't support fixed byte(slice mode), CBR_VT(rc mode) */
+ } else if (temp_ctx->type == MFCINST_ENCODER) {
+ enc = temp_ctx->enc_priv;
+ if (!enc) {
+ mfc_debug(2, "There is no enc\n");
+ return 0;
+ }
+ if (enc->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_FIXED_BYTES) {
+ mfc_debug(2, "There is fixed bytes option(slice mode)\n");
+ return 0;
+ }
+ p = &enc->params;
+ if (p->rc_reaction_coeff <= CBR_I_LIMIT_MAX) {
+ mfc_debug(2, "There is CBR_VT option(rc mode)\n");
+ return 0;
+ }
+ }
+ mfc_debug(2, "There is a ctx in running state. index: %d\n", i);
+ }
+ }
+
+ mfc_debug(2, "All working ctx are in running state!\n");
+
+ mfc_debug_leave();
+
+ return 1;
+}
+
+void s5p_mfc_nal_q_clock_on(struct s5p_mfc_dev *dev, nal_queue_handle *nal_q_handle)
+{
+ unsigned long flags;
+
+ mfc_debug_enter();
+
+ spin_lock_irqsave(&nal_q_handle->lock, flags);
+
+ mfc_debug(2, "[NALQ] continue_clock_on = %d, nal_q_clk_cnt = %d\n",
+ dev->continue_clock_on, nal_q_handle->nal_q_clk_cnt);
+
+ if (!dev->continue_clock_on && !nal_q_handle->nal_q_clk_cnt)
+ s5p_mfc_pm_clock_on(dev);
+
+ nal_q_handle->nal_q_clk_cnt++;
+ dev->continue_clock_on = false;
+
+ mfc_debug(2, "[NALQ] nal_q_clk_cnt = %d\n", nal_q_handle->nal_q_clk_cnt);
+
+ spin_unlock_irqrestore(&nal_q_handle->lock, flags);
+
+ mfc_debug_leave();
+}
+
+void s5p_mfc_nal_q_clock_off(struct s5p_mfc_dev *dev, nal_queue_handle *nal_q_handle)
+{
+ unsigned long flags;
+
+ mfc_debug_enter();
+
+ spin_lock_irqsave(&nal_q_handle->lock, flags);
+
+ mfc_debug(2, "[NALQ] nal_q_clk_cnt = %d\n", nal_q_handle->nal_q_clk_cnt);
+
+ if (!nal_q_handle->nal_q_clk_cnt) {
+ mfc_err_dev("[NALQ] nal_q_clk_cnt is already zero\n");
+ return;
+ }
+
+ nal_q_handle->nal_q_clk_cnt--;
+
+ if (!nal_q_handle->nal_q_clk_cnt)
+ s5p_mfc_pm_clock_off(dev);
+
+ mfc_debug(2, "[NALQ] nal_q_clk_cnt = %d\n", nal_q_handle->nal_q_clk_cnt);
+
+ spin_unlock_irqrestore(&nal_q_handle->lock, flags);
+
+ mfc_debug_leave();
+}
+
+void s5p_mfc_nal_q_cleanup_clock(struct s5p_mfc_dev *dev)
+{
+ unsigned long flags;
+
+ mfc_debug_enter();
+
+ spin_lock_irqsave(&dev->nal_q_handle->lock, flags);
+
+ dev->nal_q_handle->nal_q_clk_cnt = 0;
+
+ spin_unlock_irqrestore(&dev->nal_q_handle->lock, flags);
+
+ mfc_debug_leave();
+}
+
+static int mfc_nal_q_find_ctx(struct s5p_mfc_dev *dev, EncoderOutputStr *pOutputStr)
+{
+ int i;
+
+ if (!dev) {
+ mfc_err_dev("[NALQ] no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ for(i = 0; i < MFC_NUM_CONTEXTS; i++) {
+ if (dev->ctx[i] && dev->ctx[i]->inst_no == pOutputStr->InstanceId)
+ return i;
+ }
+ return -1;
+}
+
+static nal_queue_in_handle* mfc_nal_q_create_in_q(struct s5p_mfc_dev *dev,
+ nal_queue_handle *nal_q_handle)
+{
+ nal_queue_in_handle *nal_q_in_handle;
+
+ mfc_debug_enter();
+
+ if (!dev) {
+ mfc_err_dev("[NALQ] no mfc device to run\n");
+ return NULL;
+ }
+
+ nal_q_in_handle = kzalloc(sizeof(*nal_q_in_handle), GFP_KERNEL);
+ if (!nal_q_in_handle) {
+ mfc_err_dev("[NALQ] Failed to get memory for nal_queue_in_handle\n");
+ return NULL;
+ }
+
+ nal_q_in_handle->nal_q_handle = nal_q_handle;
+ nal_q_in_handle->in_buf.buftype = MFCBUF_NORMAL;
+ nal_q_in_handle->in_buf.size = NAL_Q_IN_ENTRY_SIZE * (NAL_Q_IN_QUEUE_SIZE + 2);
+ if (s5p_mfc_mem_ion_alloc(dev, &nal_q_in_handle->in_buf)) {
+ mfc_err_dev("[NALQ] failed to get memory\n");
+ kfree(nal_q_in_handle);
+ return NULL;
+ }
+ nal_q_in_handle->nal_q_in_addr = (nal_in_queue *)nal_q_in_handle->in_buf.vaddr;
+
+ mfc_debug_leave();
+
+ return nal_q_in_handle;
+}
+
+static nal_queue_out_handle* mfc_nal_q_create_out_q(struct s5p_mfc_dev *dev,
+ nal_queue_handle *nal_q_handle)
+{
+ nal_queue_out_handle *nal_q_out_handle;
+
+ mfc_debug_enter();
+
+ if (!dev) {
+ mfc_err_dev("[NALQ] no mfc device to run\n");
+ return NULL;
+ }
+
+ nal_q_out_handle = kzalloc(sizeof(*nal_q_out_handle), GFP_KERNEL);
+ if (!nal_q_out_handle) {
+ mfc_err_dev("[NALQ] failed to get memory for nal_queue_out_handle\n");
+ return NULL;
+ }
+
+ nal_q_out_handle->nal_q_handle = nal_q_handle;
+ nal_q_out_handle->out_buf.buftype = MFCBUF_NORMAL;
+ nal_q_out_handle->out_buf.size = NAL_Q_OUT_ENTRY_SIZE * (NAL_Q_OUT_QUEUE_SIZE + 2);
+ if (s5p_mfc_mem_ion_alloc(dev, &nal_q_out_handle->out_buf)) {
+ mfc_err_dev("[NALQ] failed to get memory\n");
+ kfree(nal_q_out_handle);
+ return NULL;
+ }
+ nal_q_out_handle->nal_q_out_addr = (nal_out_queue *)nal_q_out_handle->out_buf.vaddr;
+
+ mfc_debug_leave();
+
+ return nal_q_out_handle;
+}
+
+static int mfc_nal_q_destroy_in_q(struct s5p_mfc_dev *dev,
+ nal_queue_in_handle *nal_q_in_handle)
+{
+ mfc_debug_enter();
+
+ if (!nal_q_in_handle)
+ return -EINVAL;
+
+ s5p_mfc_mem_ion_free(dev, &nal_q_in_handle->in_buf);
+ if (nal_q_in_handle)
+ kfree(nal_q_in_handle);
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+static int mfc_nal_q_destroy_out_q(struct s5p_mfc_dev *dev,
+ nal_queue_out_handle *nal_q_out_handle)
+{
+ mfc_debug_enter();
+
+ if (!nal_q_out_handle)
+ return -EINVAL;
+
+ s5p_mfc_mem_ion_free(dev, &nal_q_out_handle->out_buf);
+ if (nal_q_out_handle)
+ kfree(nal_q_out_handle);
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+/*
+ * This function should be called after s5p_mfc_alloc_firmware() being called.
+ */
+nal_queue_handle *s5p_mfc_nal_q_create(struct s5p_mfc_dev *dev)
+{
+ nal_queue_handle *nal_q_handle;
+
+ mfc_debug_enter();
+
+ if (!dev) {
+ mfc_err_dev("[NALQ] no mfc device to run\n");
+ return NULL;
+ }
+
+ nal_q_handle = kzalloc(sizeof(*nal_q_handle), GFP_KERNEL);
+ if (!nal_q_handle) {
+ mfc_err_dev("[NALQ] no nal_q_handle\n");
+ return NULL;
+ }
+
+ nal_q_handle->nal_q_in_handle = mfc_nal_q_create_in_q(dev, nal_q_handle);
+ if (!nal_q_handle->nal_q_in_handle) {
+ kfree(nal_q_handle);
+ mfc_err_dev("[NALQ] no nal_q_in_handle\n");
+ return NULL;
+ }
+
+ spin_lock_init(&nal_q_handle->lock);
+
+ nal_q_handle->nal_q_out_handle = mfc_nal_q_create_out_q(dev, nal_q_handle);
+ if (!nal_q_handle->nal_q_out_handle) {
+ mfc_nal_q_destroy_in_q(dev, nal_q_handle->nal_q_in_handle);
+ kfree(nal_q_handle);
+ mfc_err_dev("[NALQ] no nal_q_out_handle\n");
+ return NULL;
+ }
+
+ nal_q_handle->nal_q_state = NAL_Q_STATE_CREATED;
+ MFC_TRACE_DEV("** NAL Q state : %d\n", nal_q_handle->nal_q_state);
+ mfc_debug(2, "[NALQ] handle created, state = %d\n", nal_q_handle->nal_q_state);
+
+ mfc_debug_leave();
+
+ return nal_q_handle;
+}
+
+int s5p_mfc_nal_q_destroy(struct s5p_mfc_dev *dev, nal_queue_handle *nal_q_handle)
+{
+ int ret = 0;
+
+ mfc_debug_enter();
+
+ if (!dev) {
+ mfc_err_dev("[NALQ] no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ if (!nal_q_handle) {
+ mfc_err_dev("[NALQ] there isn't nal_q_handle\n");
+ return -EINVAL;
+ }
+
+ ret = mfc_nal_q_destroy_out_q(dev, nal_q_handle->nal_q_out_handle);
+ if (ret) {
+ mfc_err_dev("[NALQ] failed nal_q_out_handle destroy\n");
+ return ret;
+ }
+
+ ret = mfc_nal_q_destroy_in_q(dev, nal_q_handle->nal_q_in_handle);
+ if (ret) {
+ mfc_err_dev("[NALQ] failed nal_q_in_handle destroy\n");
+ return ret;
+ }
+
+ kfree(nal_q_handle);
+ dev->nal_q_handle = NULL;
+
+ mfc_debug_leave();
+
+ return ret;
+}
+
+void s5p_mfc_nal_q_init(struct s5p_mfc_dev *dev, nal_queue_handle *nal_q_handle)
+{
+ mfc_debug_enter();
+
+ if (!dev) {
+ mfc_err_dev("[NALQ] no mfc device to run\n");
+ return;
+ }
+
+ if (!nal_q_handle) {
+ mfc_err_dev("[NALQ] There is no nal_q_handle\n");
+ return;
+ }
+
+ if ((nal_q_handle->nal_q_state != NAL_Q_STATE_CREATED)
+ && (nal_q_handle->nal_q_state != NAL_Q_STATE_STOPPED)) {
+ mfc_err_dev("[NALQ] State is wrong, state: %d\n", nal_q_handle->nal_q_state);
+ return;
+ }
+
+ s5p_mfc_reset_nal_queue_registers(dev);
+
+ nal_q_handle->nal_q_in_handle->in_exe_count = 0;
+ nal_q_handle->nal_q_out_handle->out_exe_count = 0;
+
+ mfc_debug(2, "[NALQ] S5P_FIMV_NAL_QUEUE_INPUT_COUNT=%d\n",
+ s5p_mfc_get_nal_q_input_count());
+ mfc_debug(2, "[NALQ] S5P_FIMV_NAL_QUEUE_OUTPUT_COUNT=%d\n",
+ s5p_mfc_get_nal_q_output_count());
+ mfc_debug(2, "[NALQ] S5P_FIMV_NAL_QUEUE_INPUT_EXE_COUNT=%d\n",
+ s5p_mfc_get_nal_q_input_exe_count());
+ mfc_debug(2, "[NALQ] S5P_FIMV_NAL_QUEUE_INFO=%d\n",
+ s5p_mfc_get_nal_q_info());
+
+ nal_q_handle->nal_q_exception = 0;
+
+ mfc_debug_leave();
+
+ return;
+}
+
+void s5p_mfc_nal_q_start(struct s5p_mfc_dev *dev, nal_queue_handle *nal_q_handle)
+{
+ dma_addr_t addr;
+
+ mfc_debug_enter();
+
+ if (!dev) {
+ mfc_err_dev("[NALQ] no mfc device to run\n");
+ return;
+ }
+
+ if (!nal_q_handle) {
+ mfc_err_dev("[NALQ] There is no nal_q_handle\n");
+ return;
+ }
+
+ if (nal_q_handle->nal_q_state != NAL_Q_STATE_CREATED) {
+ mfc_err_dev("[NALQ] State is wrong, state: %d\n", nal_q_handle->nal_q_state);
+ return;
+ }
+
+ addr = nal_q_handle->nal_q_in_handle->in_buf.daddr;
+
+ s5p_mfc_update_nal_queue_input(dev, addr, NAL_Q_IN_ENTRY_SIZE * NAL_Q_IN_QUEUE_SIZE);
+
+ mfc_debug(2, "[NALQ] S5P_FIMV_NAL_QUEUE_INPUT_ADDR=0x%x\n",
+ s5p_mfc_get_nal_q_input_addr());
+ mfc_debug(2, "[NALQ] S5P_FIMV_NAL_QUEUE_INPUT_SIZE=%d\n",
+ s5p_mfc_get_nal_q_input_size());
+
+ addr = nal_q_handle->nal_q_out_handle->out_buf.daddr;
+
+ s5p_mfc_update_nal_queue_output(dev, addr, NAL_Q_OUT_ENTRY_SIZE * NAL_Q_OUT_QUEUE_SIZE);
+
+ mfc_debug(2, "[NALQ] S5P_FIMV_NAL_QUEUE_OUTPUT_ADDR=0x%x\n",
+ s5p_mfc_get_nal_q_output_addr());
+ mfc_debug(2, "[NALQ] S5P_FIMV_NAL_QUEUE_OUTPUT_SIZE=%d\n",
+ s5p_mfc_get_nal_q_output_ize());
+
+ nal_q_handle->nal_q_state = NAL_Q_STATE_STARTED;
+ MFC_TRACE_DEV("** NAL Q state : %d\n", nal_q_handle->nal_q_state);
+ mfc_debug(2, "[NALQ] started, state = %d\n", nal_q_handle->nal_q_state);
+
+ MFC_WRITEL(MFC_TIMEOUT_VALUE, S5P_FIMV_DEC_TIMEOUT_VALUE);
+ s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_NAL_QUEUE);
+
+ mfc_debug_leave();
+
+ return;
+}
+
+void s5p_mfc_nal_q_stop(struct s5p_mfc_dev *dev, nal_queue_handle *nal_q_handle)
+{
+ mfc_debug_enter();
+
+ if (!dev) {
+ mfc_err_dev("[NALQ] no mfc device to run\n");
+ return;
+ }
+
+ if (!nal_q_handle) {
+ mfc_err_dev("[NALQ] There is no nal_q_handle\n");
+ return;
+ }
+
+ if (nal_q_handle->nal_q_state != NAL_Q_STATE_STARTED) {
+ mfc_err_dev("[NALQ] State is wrong, state: %d\n", nal_q_handle->nal_q_state);
+ return;
+ }
+
+ nal_q_handle->nal_q_state = NAL_Q_STATE_STOPPED;
+ MFC_TRACE_DEV("** NAL Q state : %d\n", nal_q_handle->nal_q_state);
+ mfc_debug(2, "[NALQ] stopped, state = %d\n", nal_q_handle->nal_q_state);
+
+ s5p_mfc_clean_dev_int_flags(dev);
+
+ s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_STOP_QUEUE);
+
+ mfc_debug_leave();
+
+ return;
+}
+
+void s5p_mfc_nal_q_stop_if_started(struct s5p_mfc_dev *dev)
+{
+ nal_queue_handle *nal_q_handle;
+
+ mfc_debug_enter();
+
+ if (!dev) {
+ mfc_err_dev("[NALQ] no mfc device to run\n");
+ return;
+ }
+
+ nal_q_handle = dev->nal_q_handle;
+ if (!nal_q_handle) {
+ mfc_err_dev("[NALQ] There is no nal_q_handle\n");
+ return;
+ }
+
+ if (nal_q_handle->nal_q_state != NAL_Q_STATE_STARTED) {
+ mfc_debug(2, "[NALQ] it is not running, state: %d\n",
+ nal_q_handle->nal_q_state);
+ return;
+ }
+
+ s5p_mfc_nal_q_clock_on(dev, nal_q_handle);
+
+ s5p_mfc_nal_q_stop(dev, nal_q_handle);
+ mfc_info_dev("[NALQ] stop NAL QUEUE during get hwlock\n");
+ if (s5p_mfc_wait_for_done_dev(dev,
+ S5P_FIMV_R2H_CMD_COMPLETE_QUEUE_RET)) {
+ mfc_err_dev("[NALQ] Failed to stop qeueue during get hwlock\n");
+ dev->logging_data->cause |= (1 << MFC_CAUSE_FAIL_STOP_NAL_Q_FOR_OTHER);
+ call_dop(dev, dump_and_stop_always, dev);
+ }
+
+ mfc_debug_leave();
+ return;
+}
+
+void s5p_mfc_nal_q_cleanup_queue(struct s5p_mfc_dev *dev)
+{
+ struct s5p_mfc_ctx *ctx;
+ int i;
+
+ mfc_debug_enter();
+
+ if (!dev) {
+ mfc_err_dev("[NALQ] no mfc device to run\n");
+ return;
+ }
+
+ for(i = 0; i < MFC_NUM_CONTEXTS; i++) {
+ ctx = dev->ctx[i];
+ if (ctx) {
+ s5p_mfc_cleanup_nal_queue(ctx);
+ if (s5p_mfc_ctx_ready(ctx)) {
+ s5p_mfc_set_bit(ctx->num, &dev->work_bits);
+ mfc_debug(2, "[NALQ] set work_bits after cleanup,"
+ " ctx: %d\n", ctx->num);
+ }
+ }
+ }
+
+ mfc_debug_leave();
+
+ return;
+}
+
+static void mfc_nal_q_set_slice_mode(struct s5p_mfc_ctx *ctx, EncoderInputStr *pInStr)
+{
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+
+ /* multi-slice control */
+ if (enc->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES)
+ pInStr->MsliceMode = enc->slice_mode + 0x4;
+ else if (enc->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB_ROW)
+ pInStr->MsliceMode = enc->slice_mode - 0x2;
+ else if (enc->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_FIXED_BYTES)
+ pInStr->MsliceMode = enc->slice_mode + 0x3;
+ else
+ pInStr->MsliceMode = enc->slice_mode;
+
+ /* multi-slice MB number or bit size */
+ if ((enc->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) ||
+ (enc->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB_ROW)) {
+ pInStr->MsliceSizeMb = enc->slice_size.mb;
+ } else if ((enc->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) ||
+ (enc->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_FIXED_BYTES)){
+ pInStr->MsliceSizeBits = enc->slice_size.bits;
+ } else {
+ pInStr->MsliceSizeMb = 0;
+ pInStr->MsliceSizeBits = 0;
+ }
+}
+
+static int mfc_nal_q_run_in_buf_enc(struct s5p_mfc_ctx *ctx, EncoderInputStr *pInStr)
+{
+ struct s5p_mfc_dev *dev;
+ struct s5p_mfc_buf *src_mb, *dst_mb;
+ struct s5p_mfc_raw_info *raw = NULL;
+ dma_addr_t src_addr[3] = {0, 0, 0};
+ dma_addr_t addr_2bit[2] = {0, 0};
+ unsigned int index, i;
+
+ mfc_debug_enter();
+
+ if (!ctx) {
+ mfc_err_dev("[NALQ] no mfc context to run\n");
+ return -EINVAL;
+ }
+ dev = ctx->dev;
+ if (!dev) {
+ mfc_err_dev("[NALQ] no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ pInStr->StartCode = 0xBBBBBBBB;
+ pInStr->CommandId = s5p_mfc_get_nal_q_input_count();
+ pInStr->InstanceId = ctx->inst_no;
+
+ raw = &ctx->raw_buf;
+
+ if (IS_BUFFER_BATCH_MODE(ctx)) {
+ src_mb = s5p_mfc_get_buf(&ctx->buf_queue_lock, &ctx->src_buf_queue, MFC_BUF_SET_USED);
+ if (!src_mb) {
+ mfc_err_dev("[NALQ][BUFCON] no src buffers\n");
+ return -EAGAIN;
+ }
+
+ /* last image in a buffer container */
+ /* move src_queue -> src_queue_nal_q */
+ if (src_mb->next_index == (src_mb->num_valid_bufs - 1)) {
+ src_mb = s5p_mfc_get_move_buf(&ctx->buf_queue_lock,
+ &ctx->src_buf_nal_queue, &ctx->src_buf_queue,
+ MFC_BUF_SET_USED, MFC_QUEUE_ADD_BOTTOM);
+ if (!src_mb) {
+ mfc_err_dev("[NALQ][BUFCON] no src buffers\n");
+ return -EAGAIN;
+ }
+ }
+
+ index = src_mb->vb.vb2_buf.index;
+ for (i = 0; i < raw->num_planes; i++) {
+ src_addr[i] = src_mb->addr[src_mb->next_index][i];
+ mfc_debug(2, "[NALQ][BUFCON][BUFINFO] ctx[%d] set src index:%d, batch[%d], addr[%d]: 0x%08llx\n",
+ ctx->num, index, src_mb->next_index, i, src_addr[i]);
+ }
+ src_mb->next_index++;
+ } else {
+ /* move src_queue -> src_queue_nal_q */
+ src_mb = s5p_mfc_get_move_buf(&ctx->buf_queue_lock,
+ &ctx->src_buf_nal_queue, &ctx->src_buf_queue,
+ MFC_BUF_SET_USED, MFC_QUEUE_ADD_BOTTOM);
+ if (!src_mb) {
+ mfc_err_dev("[NALQ] no src buffers\n");
+ return -EAGAIN;
+ }
+
+ index = src_mb->vb.vb2_buf.index;
+ for (i = 0; i < raw->num_planes; i++) {
+ src_addr[i] = src_mb->addr[0][i];
+ mfc_debug(2, "[NALQ][BUFINFO] ctx[%d] set src index:%d, addr[%d]: 0x%08llx\n",
+ ctx->num, index, i, src_addr[i]);
+ }
+ }
+
+ for (i = 0; i < raw->num_planes; i++)
+ pInStr->FrameAddr[i] = src_addr[i];
+
+ if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M_S10B ||
+ ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV21M_S10B) {
+ addr_2bit[0] = src_addr[0] + NV12N_Y_SIZE(ctx->img_width, ctx->img_height);
+ addr_2bit[1] = src_addr[1] + NV12N_CBCR_SIZE(ctx->img_width, ctx->img_height);
+
+ for (i = 0; i < raw->num_planes; i++) {
+ pInStr->Frame2bitAddr[i] = addr_2bit[i];
+ mfc_debug(2, "[NALQ][BUFINFO] ctx[%d] set src 2bit addr[%d]: 0x%08llx\n",
+ ctx->num, index, i, addr_2bit[i]);
+ }
+ } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV16M_S10B ||
+ ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV61M_S10B) {
+ addr_2bit[0] = src_addr[0] + NV16M_Y_SIZE(ctx->img_width, ctx->img_height);
+ addr_2bit[1] = src_addr[1] + NV16M_CBCR_SIZE(ctx->img_width, ctx->img_height);
+
+ for (i = 0; i < raw->num_planes; i++) {
+ pInStr->Frame2bitAddr[i] = addr_2bit[i];
+ mfc_debug(2, "[NALQ][BUFINFO] ctx[%d] set src 2bit addr[%d]: 0x%08llx\n",
+ ctx->num, index, i, addr_2bit[i]);
+ }
+ }
+
+ /* move dst_queue -> dst_queue_nal_q */
+ dst_mb = s5p_mfc_get_move_buf(&ctx->buf_queue_lock,
+ &ctx->dst_buf_nal_queue, &ctx->dst_buf_queue, MFC_BUF_SET_USED, MFC_QUEUE_ADD_BOTTOM);
+ if (!dst_mb) {
+ mfc_err_dev("[NALQ] no dst buffers\n");
+ return -EAGAIN;
+ }
+
+ pInStr->StreamBufferAddr = dst_mb->addr[0][0];
+ pInStr->StreamBufferSize = (unsigned int)vb2_plane_size(&dst_mb->vb.vb2_buf, 0);
+ pInStr->StreamBufferSize = ALIGN(pInStr->StreamBufferSize, 512);
+
+ if (call_cop(ctx, set_buf_ctrls_val_nal_q_enc, ctx, &ctx->src_ctrls[index], pInStr) < 0)
+ mfc_err_ctx("[NALQ] failed in set_buf_ctrals_val in nal q\n");
+
+ mfc_debug(2, "[NALQ][BUFINFO] ctx[%d] set dst index: %d, addr: 0x%08llx\n",
+ ctx->num, dst_mb->vb.vb2_buf.index, pInStr->StreamBufferAddr);
+ mfc_debug(2, "[NALQ] input queue, src_buf_queue -> src_buf_nal_queue, index:%d\n",
+ src_mb->vb.vb2_buf.index);
+ mfc_debug(2, "[NALQ] input queue, dst_buf_queue -> dst_buf_nal_queue, index:%d\n",
+ dst_mb->vb.vb2_buf.index);
+
+ mfc_nal_q_set_slice_mode(ctx, pInStr);
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+static int mfc_nal_q_run_in_buf_dec(struct s5p_mfc_ctx *ctx, DecoderInputStr *pInStr)
+{
+ struct s5p_mfc_dev *dev;
+ struct s5p_mfc_buf *src_mb, *dst_mb;
+ struct s5p_mfc_dec *dec;
+ struct s5p_mfc_raw_info *raw = &ctx->raw_buf;
+ dma_addr_t buf_addr;
+ unsigned int strm_size;
+ unsigned int cpb_buf_size;
+ int src_index, dst_index;
+ int i;
+
+ mfc_debug_enter();
+
+ if (!ctx) {
+ mfc_err_dev("[NALQ] no mfc context to run\n");
+ return -EINVAL;
+ }
+ dev = ctx->dev;
+ if (!dev) {
+ mfc_err_dev("[NALQ] no mfc device to run\n");
+ return -EINVAL;
+ }
+ dec = ctx->dec_priv;
+ if (!dec) {
+ mfc_err_dev("[NALQ] no mfc decoder to run\n");
+ return -EINVAL;
+ }
+
+ if (s5p_mfc_is_queue_count_same(&ctx->buf_queue_lock, &ctx->dst_buf_queue, 0) &&
+ s5p_mfc_is_queue_count_smaller(&ctx->buf_queue_lock,
+ &ctx->ref_buf_queue, (ctx->dpb_count + 5))) {
+ mfc_err_dev("[NALQ] no dst buffers\n");
+ return -EAGAIN;
+ }
+
+ if (s5p_mfc_is_queue_count_same(&ctx->buf_queue_lock, &ctx->src_buf_queue, 0)) {
+ mfc_err_dev("[NALQ] no src buffers\n");
+ return -EAGAIN;
+ }
+
+ pInStr->StartCode = 0xAAAAAAAA;
+ pInStr->CommandId = s5p_mfc_get_nal_q_input_count();
+ pInStr->InstanceId = ctx->inst_no;
+ pInStr->NalStartOptions = 0;
+
+ /* Try to use the non-referenced DPB on dst-queue */
+ dst_mb = s5p_mfc_search_move_dpb_nal_q(ctx, dec->dynamic_used);
+ if (!dst_mb) {
+ mfc_debug(2, "[NALQ][DPB] couldn't find dst buffers\n");
+ return -EAGAIN;
+ }
+
+ /* move src_queue -> src_queue_nal_q */
+ src_mb = s5p_mfc_get_move_buf(&ctx->buf_queue_lock,
+ &ctx->src_buf_nal_queue, &ctx->src_buf_queue,
+ MFC_BUF_SET_USED, MFC_QUEUE_ADD_BOTTOM);
+ if (!src_mb) {
+ mfc_err_dev("[NALQ] no src buffers\n");
+ return -EAGAIN;
+ }
+
+ /* src buffer setting */
+ src_index = src_mb->vb.vb2_buf.index;
+ buf_addr = src_mb->addr[0][0];
+ strm_size = src_mb->vb.vb2_buf.planes[0].bytesused;
+ cpb_buf_size = ALIGN(dec->src_buf_size, STREAM_BUF_ALIGN);
+
+ if (strm_size > set_strm_size_max(cpb_buf_size)) {
+ mfc_info_ctx("[NALQ] Decrease strm_size : %u -> %u, gap : %d\n",
+ strm_size, set_strm_size_max(cpb_buf_size), STREAM_BUF_ALIGN);
+ strm_size = set_strm_size_max(cpb_buf_size);
+ src_mb->vb.vb2_buf.planes[0].bytesused = strm_size;
+ }
+
+ mfc_debug(2, "[NALQ][BUFINFO] ctx[%d] set src index: %d, addr: 0x%08llx\n",
+ ctx->num, src_index, buf_addr);
+ mfc_debug(2, "[NALQ][STREAM] strm_size: %#lx(%d), buf_size: %u\n",
+ strm_size, strm_size, cpb_buf_size);
+
+ if (strm_size == 0)
+ mfc_info_ctx("stream size is 0\n");
+
+ pInStr->StreamDataSize = strm_size;
+ pInStr->CpbBufferAddr = buf_addr;
+ pInStr->CpbBufferSize = cpb_buf_size;
+ pInStr->CpbBufferOffset = 0;
+
+ MFC_TRACE_CTX("Set src[%d] fd: %d, %#llx\n",
+ src_index, src_mb->vb.vb2_buf.planes[0].m.fd, buf_addr);
+
+ /* dst buffer setting */
+ dst_index = dst_mb->vb.vb2_buf.index;
+ set_bit(dst_index, &dec->available_dpb);
+ dec->dynamic_set = 1 << dst_index;
+
+ for (i = 0; i < raw->num_planes; i++) {
+ pInStr->FrameSize[i] = raw->plane_size[i];
+ pInStr->FrameAddr[i] = dst_mb->addr[0][i];
+ if (ctx->is_10bit)
+ pInStr->Frame2BitSize[i] = raw->plane_size_2bits[i];
+ mfc_debug(2, "[NALQ][BUFINFO][DPB] ctx[%d] set dst index: %d, addr[%d]: 0x%08llx\n",
+ ctx->num, dst_index, i, dst_mb->addr[0][i]);
+ }
+
+ pInStr->ScratchBufAddr = ctx->codec_buf.daddr;
+ pInStr->ScratchBufSize = ctx->scratch_buf_size;
+
+ if (call_cop(ctx, set_buf_ctrls_val_nal_q_dec, ctx,
+ &ctx->src_ctrls[src_index], pInStr) < 0)
+ mfc_err_ctx("[NALQ] failed in set_buf_ctrls_val\n");
+
+ pInStr->DynamicDpbFlagLower = dec->dynamic_set;
+
+ /* use dynamic_set value to available dpb in NAL Q */
+ // pInStr->AvailableDpbFlagLower = dec->available_dpb;
+ pInStr->AvailableDpbFlagLower = dec->dynamic_set;
+
+ MFC_TRACE_CTX("Set dst[%d] fd: %d, %#llx / avail %#lx used %#x\n",
+ dst_index, dst_mb->vb.vb2_buf.planes[0].m.fd, dst_mb->addr[0][0],
+ dec->available_dpb, dec->dynamic_used);
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+static void mfc_nal_q_get_enc_frame_buffer(struct s5p_mfc_ctx *ctx,
+ dma_addr_t addr[], int num_planes, EncoderOutputStr *pOutStr)
+{
+ unsigned long enc_recon_y_addr, enc_recon_c_addr;
+ int i;
+
+ for (i = 0; i < num_planes; i++)
+ addr[i] = pOutStr->EncodedFrameAddr[i];
+
+ enc_recon_y_addr = pOutStr->ReconLumaDpbAddr;
+ enc_recon_c_addr = pOutStr->ReconChromaDpbAddr;
+
+ mfc_debug(2, "[NALQ][MEMINFO] recon y: 0x%08lx c: 0x%08lx\n",
+ enc_recon_y_addr, enc_recon_c_addr);
+}
+
+static void mfc_nal_q_handle_stream_copy_timestamp(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *src_mb)
+{
+ struct s5p_mfc_dev *dev;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_enc_params *p = &enc->params;
+ struct s5p_mfc_buf *dst_mb;
+ u32 interval;
+ u64 start_timestamp;
+ u64 new_timestamp;
+
+ if (!ctx) {
+ mfc_err_dev("[NALQ][BUFCON][TS] no mfc context to run\n");
+ return;
+ }
+
+ dev = ctx->dev;
+ if (!dev) {
+ mfc_err_dev("[NALQ][BUFCON][TS] no device to run\n");
+ return;
+ }
+
+ start_timestamp = src_mb->vb.vb2_buf.timestamp;
+ interval = NSEC_PER_SEC / p->rc_framerate;
+ if (debug_ts == 1)
+ mfc_info_ctx("[NALQ][BUFCON][TS] %dfps, start timestamp: %lld, base interval: %d\n",
+ p->rc_framerate, start_timestamp, interval);
+
+ new_timestamp = start_timestamp + (interval * src_mb->done_index);
+ if (debug_ts == 1)
+ mfc_info_ctx("[NALQ][BUFCON][TS] new timestamp: %lld, interval: %d\n",
+ new_timestamp, interval * src_mb->done_index);
+
+ /* Get the destination buffer */
+ dst_mb = s5p_mfc_get_buf(&ctx->buf_queue_lock, &ctx->dst_buf_nal_queue, MFC_BUF_NO_TOUCH_USED);
+ if (dst_mb)
+ dst_mb->vb.vb2_buf.timestamp = new_timestamp;
+}
+
+static void mfc_nal_q_handle_stream_input(struct s5p_mfc_ctx *ctx, EncoderOutputStr *pOutStr)
+{
+ struct s5p_mfc_buf *src_mb, *ref_mb;
+ dma_addr_t enc_addr[3] = { 0, 0, 0 };
+ struct s5p_mfc_raw_info *raw;
+ int found_in_src_queue = 0;
+ unsigned int i;
+
+ raw = &ctx->raw_buf;
+
+ mfc_nal_q_get_enc_frame_buffer(ctx, &enc_addr[0], raw->num_planes, pOutStr);
+ if (enc_addr[0] == 0) {
+ mfc_debug(3, "[NALQ] no encoded src\n");
+ goto move_buf;
+ }
+
+ for (i = 0; i < raw->num_planes; i++)
+ mfc_debug(2, "[NALQ][BUFINFO] ctx[%d] get src addr[%d]: 0x%08llx\n",
+ ctx->num, i, enc_addr[i]);
+
+ if (IS_BUFFER_BATCH_MODE(ctx)) {
+ src_mb = s5p_mfc_find_first_buf(&ctx->buf_queue_lock,
+ &ctx->src_buf_queue, enc_addr[0]);
+ if (src_mb) {
+ found_in_src_queue = 1;
+
+ mfc_nal_q_handle_stream_copy_timestamp(ctx, src_mb);
+ src_mb->done_index++;
+ mfc_debug(4, "[NALQ][BUFCON] batch buf done_index: %d\n", src_mb->done_index);
+ } else {
+ src_mb = s5p_mfc_find_first_buf(&ctx->buf_queue_lock,
+ &ctx->src_buf_nal_queue, enc_addr[0]);
+ if (src_mb) {
+ found_in_src_queue = 1;
+
+ mfc_nal_q_handle_stream_copy_timestamp(ctx, src_mb);
+ src_mb->done_index++;
+ mfc_debug(4, "[NALQ][BUFCON] batch buf done_index: %d\n", src_mb->done_index);
+
+ /* last image in a buffer container */
+ if (src_mb->done_index == src_mb->num_valid_bufs) {
+ src_mb = s5p_mfc_find_del_buf(&ctx->buf_queue_lock,
+ &ctx->src_buf_nal_queue, enc_addr[0]);
+ for (i = 0; i < raw->num_planes; i++)
+ s5p_mfc_bufcon_put_daddr(ctx, src_mb, i);
+ vb2_buffer_done(&src_mb->vb.vb2_buf, VB2_BUF_STATE_DONE);
+ }
+ }
+ }
+ } else {
+ src_mb = s5p_mfc_find_del_buf(&ctx->buf_queue_lock,
+ &ctx->src_buf_nal_queue, enc_addr[0]);
+ if (src_mb) {
+ mfc_debug(3, "[NALQ] find src buf in src_queue\n");
+ found_in_src_queue = 1;
+ vb2_buffer_done(&src_mb->vb.vb2_buf, VB2_BUF_STATE_DONE);
+ } else {
+ mfc_debug(3, "[NALQ] no src buf in src_queue\n");
+ ref_mb = s5p_mfc_find_del_buf(&ctx->buf_queue_lock,
+ &ctx->ref_buf_queue, enc_addr[0]);
+ if (ref_mb) {
+ mfc_debug(3, "[NALQ] find src buf in ref_queue\n");
+ vb2_buffer_done(&ref_mb->vb.vb2_buf, VB2_BUF_STATE_DONE);
+ } else {
+ mfc_err_ctx("[NALQ] couldn't find src buffer\n");
+ }
+ }
+ }
+
+move_buf:
+ /* move enqueued src buffer: src nal queue -> ref queue */
+ if (!found_in_src_queue) {
+ src_mb = s5p_mfc_get_move_buf_used(&ctx->buf_queue_lock,
+ &ctx->ref_buf_queue, &ctx->src_buf_nal_queue);
+ if (!src_mb)
+ mfc_err_dev("[NALQ] no src buffers\n");
+
+ mfc_debug(2, "[NALQ] enc src_buf_nal_queue(%d) -> ref_buf_queue(%d)\n",
+ s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->src_buf_nal_queue),
+ s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->ref_buf_queue));
+ }
+}
+
+static void mfc_nal_q_handle_stream_output(struct s5p_mfc_ctx *ctx, int slice_type,
+ unsigned int strm_size, EncoderOutputStr *pOutStr)
+{
+ struct s5p_mfc_buf *dst_mb;
+ unsigned int index;
+
+ if (strm_size == 0) {
+ mfc_debug(3, "[NALQ] no encoded dst (reuse)\n");
+ dst_mb = s5p_mfc_get_move_buf(&ctx->buf_queue_lock,
+ &ctx->dst_buf_queue, &ctx->dst_buf_nal_queue,
+ MFC_BUF_RESET_USED, MFC_QUEUE_ADD_TOP);
+ if (!dst_mb) {
+ mfc_err_dev("[NALQ] no dst buffers\n");
+ return;
+ }
+
+ mfc_debug(2, "[NALQ] no output, dst_buf_nal_queue(%d) -> dst_buf_queue(%d) index:%d\n",
+ s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->dst_buf_nal_queue),
+ s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->dst_buf_queue),
+ dst_mb->vb.vb2_buf.index);
+ return;
+ } else if (strm_size < 0) {
+ mfc_err_ctx("[NALQ] invalid stream size: %d\n", strm_size);
+ return;
+ }
+
+ /* at least one more dest. buffers exist always */
+ dst_mb = s5p_mfc_get_del_buf(&ctx->buf_queue_lock, &ctx->dst_buf_nal_queue, MFC_BUF_NO_TOUCH_USED);
+ if (!dst_mb) {
+ mfc_err_dev("[NALQ] no dst buffers\n");
+ return;
+ }
+
+ mfc_debug(2, "[NALQ][BUFINFO] ctx[%d] get dst addr: 0x%08llx\n",
+ ctx->num, dst_mb->addr[0][0]);
+
+ dst_mb->vb.flags &= ~(V4L2_BUF_FLAG_KEYFRAME |
+ V4L2_BUF_FLAG_PFRAME |
+ V4L2_BUF_FLAG_BFRAME);
+
+ switch (slice_type) {
+ case S5P_FIMV_E_SLICE_TYPE_I:
+ dst_mb->vb.flags |= V4L2_BUF_FLAG_KEYFRAME;
+ break;
+ case S5P_FIMV_E_SLICE_TYPE_P:
+ dst_mb->vb.flags |= V4L2_BUF_FLAG_PFRAME;
+ break;
+ case S5P_FIMV_E_SLICE_TYPE_B:
+ dst_mb->vb.flags |= V4L2_BUF_FLAG_BFRAME;
+ break;
+ default:
+ dst_mb->vb.flags |= V4L2_BUF_FLAG_KEYFRAME;
+ break;
+ }
+ mfc_debug(2, "[NALQ][STREAM] Slice type flag: %d\n", dst_mb->vb.flags);
+
+ vb2_set_plane_payload(&dst_mb->vb.vb2_buf, 0, strm_size);
+
+ index = dst_mb->vb.vb2_buf.index;
+ if (call_cop(ctx, get_buf_ctrls_val_nal_q_enc, ctx,
+ &ctx->dst_ctrls[index], pOutStr) < 0)
+ mfc_err_ctx("[NALQ] failed in get_buf_ctrls_val in nal q\n");
+
+ vb2_buffer_done(&dst_mb->vb.vb2_buf, VB2_BUF_STATE_DONE);
+}
+
+static void mfc_nal_q_handle_stream(struct s5p_mfc_ctx *ctx, EncoderOutputStr *pOutStr)
+{
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ int slice_type;
+ unsigned int strm_size;
+ unsigned int pic_count;
+
+ mfc_debug_enter();
+
+ slice_type = pOutStr->SliceType;
+ strm_size = pOutStr->StreamSize;
+ pic_count = pOutStr->EncCnt;
+
+ mfc_debug(2, "[NALQ][STREAM] encoded slice type: %d, size: %d, display order: %d\n",
+ slice_type, strm_size, pic_count);
+
+ /* buffer full handling */
+ if (ctx->state == MFCINST_RUNNING_BUF_FULL)
+ ctx->state = MFCINST_RUNNING;
+
+ /* set encoded frame type */
+ enc->frame_type = slice_type;
+ ctx->sequence++;
+
+ /* handle input buffer */
+ mfc_nal_q_handle_stream_input(ctx, pOutStr);
+
+ /* handle output buffer */
+ mfc_nal_q_handle_stream_output(ctx, slice_type, strm_size, pOutStr);
+
+ mfc_debug_leave();
+
+ return;
+}
+
+static void mfc_nal_q_handle_reuse_buffer(struct s5p_mfc_ctx *ctx, DecoderOutputStr *pOutStr)
+{
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ unsigned int prev_flag, released_flag = 0;
+ struct s5p_mfc_buf *dst_mb;
+ dma_addr_t disp_addr;
+ int i;
+
+ /* reuse not used buf: dst_buf_nal_queue -> dst_queue */
+ disp_addr = pOutStr->DisplayAddr[0];
+ if (disp_addr) {
+ mfc_debug(2, "[NALQ][DPB] decoding only but there is disp addr: 0x%llx\n", disp_addr);
+ dst_mb = s5p_mfc_get_move_buf_addr(&ctx->buf_queue_lock,
+ &ctx->dst_buf_queue, &ctx->dst_buf_nal_queue,
+ disp_addr);
+ if (dst_mb) {
+ mfc_debug(2, "[NALQ][DPB] buf[%d] will reused. addr: 0x%08llx\n",
+ dst_mb->vb.vb2_buf.index, disp_addr);
+ dst_mb->used = 0;
+ clear_bit(dst_mb->vb.vb2_buf.index, &dec->available_dpb);
+ }
+ }
+
+ /* reuse not referenced buf anymore: ref_queue -> dst_queue */
+ prev_flag = dec->dynamic_used;
+ dec->dynamic_used = pOutStr->UsedDpbFlagLower;
+ released_flag = prev_flag & (~dec->dynamic_used);
+
+ if (!released_flag)
+ return;
+
+ for (i = 0; i < MFC_MAX_DPBS; i++)
+ if (released_flag & (1 << i))
+ if (s5p_mfc_move_reuse_buffer(ctx, i))
+ released_flag &= ~(1 << i);
+
+ /* Not reused buffer should be released when there is a display frame */
+ dec->dec_only_release_flag |= released_flag;
+ for (i = 0; i < MFC_MAX_DPBS; i++)
+ if (released_flag & (1 << i))
+ clear_bit(i, &dec->available_dpb);
+}
+
+static void mfc_nal_q_handle_ref_frame(struct s5p_mfc_ctx *ctx, DecoderOutputStr *pOutStr)
+{
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ struct s5p_mfc_buf *dst_mb;
+ dma_addr_t dec_addr;
+ int index = 0;
+
+ mfc_debug_enter();
+
+ dec_addr = pOutStr->DecodedAddr[0];
+
+ dst_mb = s5p_mfc_find_move_buf_used(&ctx->buf_queue_lock,
+ &ctx->ref_buf_queue, &ctx->dst_buf_nal_queue, dec_addr);
+ if (dst_mb) {
+ mfc_debug(2, "[NALQ][DPB] Found in dst queue = 0x%08llx, buf = 0x%08llx\n",
+ dec_addr, dst_mb->addr[0][0]);
+
+ index = dst_mb->vb.vb2_buf.index;
+ if (!((1 << index) & pOutStr->UsedDpbFlagLower))
+ dec->dynamic_used |= 1 << index;
+ } else {
+ mfc_debug(2, "[NALQ][DPB] Can't find buffer for addr: 0x%08llx\n", dec_addr);
+ }
+
+ mfc_debug_leave();
+}
+
+static void mfc_nal_q_handle_frame_copy_timestamp(struct s5p_mfc_ctx *ctx, DecoderOutputStr *pOutStr)
+{
+ struct s5p_mfc_dec *dec;
+ struct s5p_mfc_dev *dev;
+ struct s5p_mfc_buf *ref_mb, *src_mb;
+ dma_addr_t dec_y_addr;
+
+ mfc_debug_enter();
+
+ if (!ctx) {
+ mfc_err_dev("[TS] no mfc context to run\n");
+ return;
+ }
+
+ dec = ctx->dec_priv;
+ dev = ctx->dev;
+
+ dec_y_addr = pOutStr->DecodedAddr[0];
+
+ /* Get the next source buffer */
+ src_mb = s5p_mfc_get_buf(&ctx->buf_queue_lock, &ctx->src_buf_nal_queue, MFC_BUF_NO_TOUCH_USED);
+ if (!src_mb) {
+ mfc_err_dev("[NALQ] no src buffers\n");
+ return;
+ }
+
+ ref_mb = s5p_mfc_find_buf(&ctx->buf_queue_lock, &ctx->ref_buf_queue, dec_y_addr);
+ if (ref_mb)
+ ref_mb->vb.vb2_buf.timestamp = src_mb->vb.vb2_buf.timestamp;
+
+ mfc_debug_leave();
+}
+
+static void mfc_nal_q_handle_frame_output_move(struct s5p_mfc_ctx *ctx,
+ dma_addr_t dspl_y_addr, unsigned int released_flag)
+{
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_buf *dst_mb;
+ unsigned int index;
+
+ dst_mb = s5p_mfc_find_move_buf(&ctx->buf_queue_lock,
+ &ctx->dst_buf_queue, &ctx->ref_buf_queue, dspl_y_addr, released_flag);
+ if (dst_mb) {
+ index = dst_mb->vb.vb2_buf.index;
+
+ /* Check if this is the buffer we're looking for */
+ mfc_debug(2, "[NALQ][DPB] Found buf[%d] 0x%08llx, looking for disp addr 0x%08llx\n",
+ index, dst_mb->addr[0][0], dspl_y_addr);
+
+ if (released_flag & (1 << index)) {
+ dec->available_dpb &= ~(1 << index);
+ released_flag &= ~(1 << index);
+ mfc_debug(2, "[NALQ][DPB] Corrupted frame(%d), it will be re-used(release)\n",
+ s5p_mfc_get_warn(s5p_mfc_get_int_err()));
+ } else {
+ dec->err_reuse_flag |= 1 << index;
+ mfc_debug(2, "[NALQ][DPB] Corrupted frame(%d), it will be re-used(not released)\n",
+ s5p_mfc_get_warn(s5p_mfc_get_int_err()));
+ }
+ dec->dynamic_used |= released_flag;
+ }
+}
+
+static void mfc_nal_q_handle_frame_output_del(struct s5p_mfc_ctx *ctx,
+ DecoderOutputStr *pOutStr, unsigned int err, unsigned int released_flag)
+{
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_raw_info *raw = &ctx->raw_buf;
+ struct s5p_mfc_buf *ref_mb;
+ dma_addr_t dspl_y_addr;
+ unsigned int frame_type;
+ unsigned int dst_frame_status;
+ unsigned int is_video_signal_type = 0, is_colour_description = 0;
+ unsigned int is_content_light = 0, is_display_colour = 0;
+ unsigned int disp_err;
+ int i, index;
+
+ if (MFC_FEATURE_SUPPORT(dev, dev->pdata->color_aspect_dec)) {
+ is_video_signal_type = ((pOutStr->VideoSignalType
+ >> S5P_FIMV_D_VIDEO_SIGNAL_TYPE_FLAG_SHIFT)
+ & S5P_FIMV_D_VIDEO_SIGNAL_TYPE_FLAG_MASK);
+ is_colour_description = ((pOutStr->VideoSignalType
+ >> S5P_FIMV_D_COLOUR_DESCRIPTION_FLAG_SHIFT)
+ & S5P_FIMV_D_COLOUR_DESCRIPTION_FLAG_MASK);
+ }
+
+ if (MFC_FEATURE_SUPPORT(dev, dev->pdata->static_info_dec)) {
+ is_content_light = ((pOutStr->SeiAvail >> S5P_FIMV_D_SEI_AVAIL_CONTENT_LIGHT_SHIFT)
+ & S5P_FIMV_D_SEI_AVAIL_CONTENT_LIGHT_MASK);
+ is_display_colour = ((pOutStr->SeiAvail >> S5P_FIMV_D_SEI_AVAIL_MASTERING_DISPLAY_SHIFT)
+ & S5P_FIMV_D_SEI_AVAIL_MASTERING_DISPLAY_MASK);
+ }
+
+ if (dec->immediate_display == 1) {
+ dspl_y_addr = pOutStr->DecodedAddr[0];
+ frame_type = pOutStr->DecodedFrameType & S5P_FIMV_DECODED_FRAME_MASK;
+ } else {
+ dspl_y_addr = pOutStr->DisplayAddr[0];
+ frame_type = pOutStr->DisplayFrameType & S5P_FIMV_DISPLAY_FRAME_MASK;
+ }
+
+ ref_mb = s5p_mfc_find_del_buf(&ctx->buf_queue_lock, &ctx->ref_buf_queue, dspl_y_addr);
+ if (ref_mb) {
+ index = ref_mb->vb.vb2_buf.index;
+
+ /* Check if this is the buffer we're looking for */
+ mfc_debug(2, "[NALQ][BUFINFO][DPB] ctx[%d] get dst index: %d, addr[0]: 0x%08llx\n",
+ ctx->num, index, ref_mb->addr[0][0]);
+
+ ref_mb->vb.sequence = ctx->sequence;
+
+ /* Set reserved2 bits in order to inform SEI information */
+ ref_mb->vb.reserved2 = 0;
+
+ if (is_content_light) {
+ ref_mb->vb.reserved2 |= (1 << 0);
+ mfc_debug(2, "[NALQ][HDR] content light level parsed\n");
+ }
+ if (is_display_colour) {
+ ref_mb->vb.reserved2 |= (1 << 1);
+ mfc_debug(2, "[NALQ][HDR] mastering display colour parsed\n");
+ }
+ if (is_video_signal_type) {
+ ref_mb->vb.reserved2 |= (1 << 4);
+ mfc_debug(2, "[NALQ][HDR] video signal type parsed\n");
+ if (is_colour_description) {
+ ref_mb->vb.reserved2 |= (1 << 2);
+ mfc_debug(2, "[NALQ][HDR] matrix coefficients parsed\n");
+ ref_mb->vb.reserved2 |= (1 << 3);
+ mfc_debug(2, "[NALQ][HDR] colour description parsed\n");
+ }
+ }
+
+ if (IS_VP9_DEC(ctx) && MFC_FEATURE_SUPPORT(dev, dev->pdata->color_aspect_dec)) {
+ if (dec->color_space != S5P_FIMV_D_COLOR_UNKNOWN) {
+ ref_mb->vb.reserved2 |= (1 << 3);
+ mfc_debug(2, "[NALQ][HDR] color space parsed\n");
+ }
+ ref_mb->vb.reserved2 |= (1 << 4);
+ mfc_debug(2, "[NALQ][HDR] color range parsed\n");
+ }
+
+ for (i = 0; i < raw->num_planes; i++)
+ vb2_set_plane_payload(&ref_mb->vb.vb2_buf, i,
+ raw->plane_size[i]);
+
+ clear_bit(index, &dec->available_dpb);
+
+ ref_mb->vb.flags &= ~(V4L2_BUF_FLAG_KEYFRAME |
+ V4L2_BUF_FLAG_PFRAME |
+ V4L2_BUF_FLAG_BFRAME |
+ V4L2_BUF_FLAG_ERROR);
+
+ switch (frame_type) {
+ case S5P_FIMV_DISPLAY_FRAME_I:
+ ref_mb->vb.flags |= V4L2_BUF_FLAG_KEYFRAME;
+ break;
+ case S5P_FIMV_DISPLAY_FRAME_P:
+ ref_mb->vb.flags |= V4L2_BUF_FLAG_PFRAME;
+ break;
+ case S5P_FIMV_DISPLAY_FRAME_B:
+ ref_mb->vb.flags |= V4L2_BUF_FLAG_BFRAME;
+ break;
+ default:
+ break;
+ }
+
+ disp_err = s5p_mfc_get_warn(pOutStr->ErrorCode);
+ if (disp_err) {
+ mfc_err_ctx("[NALQ] Warning for displayed frame: %d\n",
+ disp_err);
+ ref_mb->vb.flags |= V4L2_BUF_FLAG_ERROR;
+ }
+
+ if (call_cop(ctx, get_buf_ctrls_val_nal_q_dec, ctx,
+ &ctx->dst_ctrls[index], pOutStr) < 0)
+ mfc_err_ctx("[NALQ] failed in get_buf_ctrls_val\n");
+
+ s5p_mfc_handle_released_info(ctx, released_flag, index);
+
+ if (dec->immediate_display == 1) {
+ dst_frame_status = pOutStr->DecodedStatus
+ & S5P_FIMV_DEC_STATUS_DECODED_STATUS_MASK;
+
+ call_cop(ctx, get_buf_update_val, ctx,
+ &ctx->dst_ctrls[index],
+ V4L2_CID_MPEG_MFC51_VIDEO_DISPLAY_STATUS,
+ dst_frame_status);
+
+ call_cop(ctx, get_buf_update_val, ctx,
+ &ctx->dst_ctrls[index],
+ V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG,
+ dec->stored_tag);
+
+ dec->immediate_display = 0;
+ }
+
+ s5p_mfc_qos_update_last_framerate(ctx, ref_mb->vb.vb2_buf.timestamp);
+ vb2_buffer_done(&ref_mb->vb.vb2_buf, disp_err ?
+ VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+ }
+}
+
+static void mfc_nal_q_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err,
+ DecoderOutputStr *pOutStr)
+{
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ dma_addr_t dspl_y_addr;
+ unsigned int frame_type;
+ unsigned int prev_flag, released_flag = 0;
+ unsigned int disp_err;
+
+ mfc_debug_enter();
+
+ frame_type = pOutStr->DisplayFrameType & S5P_FIMV_DISPLAY_FRAME_MASK;
+ disp_err = s5p_mfc_get_warn(pOutStr->ErrorCode);
+
+ ctx->sequence++;
+
+ dspl_y_addr = pOutStr->DisplayAddr[0];
+
+ if (dec->immediate_display == 1) {
+ dspl_y_addr = pOutStr->DecodedAddr[0];
+ frame_type = pOutStr->DecodedFrameType & S5P_FIMV_DECODED_FRAME_MASK;
+ }
+
+ mfc_debug(2, "[NALQ][FRAME] frame type: %d\n", frame_type);
+
+ /* If frame is same as previous then skip and do not dequeue */
+ if (frame_type == S5P_FIMV_DISPLAY_FRAME_NOT_CODED) {
+ if (!CODEC_NOT_CODED(ctx))
+ return;
+ }
+
+ prev_flag = dec->dynamic_used;
+ dec->dynamic_used = pOutStr->UsedDpbFlagLower;
+ released_flag = prev_flag & (~dec->dynamic_used);
+
+ mfc_debug(2, "[NALQ][DPB] Used flag: old = %08x, new = %08x, Released buffer = %08x\n",
+ prev_flag, dec->dynamic_used, released_flag);
+
+ if ((IS_VC1_RCV_DEC(ctx) &&
+ (disp_err == S5P_FIMV_ERR_SYNC_POINT_NOT_RECEIVED)) ||
+ (disp_err == S5P_FIMV_ERR_BROKEN_LINK))
+ mfc_nal_q_handle_frame_output_move(ctx, dspl_y_addr, released_flag);
+ else
+ mfc_nal_q_handle_frame_output_del(ctx, pOutStr, err, released_flag);
+
+ mfc_debug_leave();
+}
+
+static void mfc_nal_q_handle_frame_input(struct s5p_mfc_ctx *ctx, unsigned int err,
+ DecoderOutputStr *pOutStr)
+{
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_buf *src_mb;
+ unsigned int index;
+ int deleted = 0;
+ unsigned long consumed;
+
+ /* If there is consumed byte, it is abnormal status,
+ * We have to return remained stream buffer
+ */
+ if (dec->consumed) {
+ mfc_err_dev("[NALQ] previous buffer was not fully consumed\n");
+ src_mb = s5p_mfc_get_del_buf(&ctx->buf_queue_lock, &ctx->src_buf_nal_queue,
+ MFC_BUF_NO_TOUCH_USED);
+ if (src_mb)
+ vb2_buffer_done(&src_mb->vb.vb2_buf, VB2_BUF_STATE_DONE);
+ }
+
+ /* Check multi-frame */
+ consumed = pOutStr->DecodedNalSize;
+ src_mb = s5p_mfc_get_del_if_consumed(ctx, &ctx->src_buf_nal_queue,
+ consumed, STUFF_BYTE, err, &deleted);
+ if (!src_mb) {
+ mfc_err_dev("[NALQ] no src buffers\n");
+ return;
+ }
+
+ index = src_mb->vb.vb2_buf.index;
+ mfc_debug(2, "[NALQ][BUFINFO] ctx[%d] get src index: %d, addr: 0x%08llx\n",
+ ctx->num, index, src_mb->addr[0][0]);
+
+ if (!deleted) {
+ /* Run MFC again on the same buffer */
+ mfc_debug(2, "[NALQ][MULTIFRAME] Running again the same buffer\n");
+
+ if (CODEC_MULTIFRAME(ctx))
+ dec->y_addr_for_pb = (dma_addr_t)pOutStr->DecodedAddr[0];
+
+ dec->consumed = consumed;
+ dec->remained_size = src_mb->vb.vb2_buf.planes[0].bytesused
+ - dec->consumed;
+ dec->has_multiframe = 1;
+ dev->nal_q_handle->nal_q_exception = 1;
+
+ MFC_TRACE_CTX("** consumed:%ld, remained:%ld, addr:0x%08llx\n",
+ dec->consumed, dec->remained_size, dec->y_addr_for_pb);
+ /* Do not move src buffer to done_list */
+ return;
+ }
+
+ if (call_cop(ctx, get_buf_ctrls_val_nal_q_dec, ctx,
+ &ctx->src_ctrls[index], pOutStr) < 0)
+ mfc_err_ctx("[NALQ] failed in get_buf_ctrls_val\n");
+
+ dec->consumed = 0;
+ dec->remained_size = 0;
+
+ vb2_buffer_done(&src_mb->vb.vb2_buf, VB2_BUF_STATE_DONE);
+}
+
+void mfc_nal_q_handle_frame(struct s5p_mfc_ctx *ctx, DecoderOutputStr *pOutStr)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ unsigned int dst_frame_status, sei_avail_status, need_empty_dpb;
+ unsigned int res_change, need_dpb_change, need_scratch_change;
+ unsigned int is_interlaced, err;
+
+ mfc_debug_enter();
+
+ dst_frame_status = pOutStr->DisplayStatus
+ & S5P_FIMV_DISP_STATUS_DISPLAY_STATUS_MASK;
+ need_empty_dpb = (pOutStr->DisplayStatus
+ >> S5P_FIMV_DISP_STATUS_NEED_EMPTY_DPB_SHIFT)
+ & S5P_FIMV_DISP_STATUS_NEED_EMPTY_DPB_MASK;
+ res_change = (pOutStr->DisplayStatus
+ >> S5P_FIMV_DISP_STATUS_RES_CHANGE_SHIFT)
+ & S5P_FIMV_DISP_STATUS_RES_CHANGE_MASK;
+ need_dpb_change = (pOutStr->DisplayStatus
+ >> S5P_FIMV_DISP_STATUS_NEED_DPB_CHANGE_SHIFT)
+ & S5P_FIMV_DISP_STATUS_NEED_DPB_CHANGE_MASK;
+ need_scratch_change = (pOutStr->DisplayStatus
+ >> S5P_FIMV_DISP_STATUS_NEED_SCRATCH_CHANGE_SHIFT)
+ & S5P_FIMV_DISP_STATUS_NEED_SCRATCH_CHANGE_MASK;
+ is_interlaced = (pOutStr->DisplayStatus
+ >> S5P_FIMV_DISP_STATUS_INTERLACE_SHIFT)
+ & S5P_FIMV_DISP_STATUS_INTERLACE_MASK;
+ sei_avail_status = pOutStr->SeiAvail;
+ err = pOutStr->ErrorCode;
+
+ if (dec->immediate_display == 1)
+ dst_frame_status = pOutStr->DecodedStatus
+ & S5P_FIMV_DEC_STATUS_DECODED_STATUS_MASK;
+
+ mfc_debug(2, "[NALQ][FRAME] frame status: %d\n", dst_frame_status);
+ mfc_debug(2, "[NALQ][FRAME] display status: %d, type: %d, yaddr: %#x\n",
+ pOutStr->DisplayStatus & S5P_FIMV_DISP_STATUS_DISPLAY_STATUS_MASK,
+ pOutStr->DisplayFrameType & S5P_FIMV_DISPLAY_FRAME_MASK,
+ pOutStr->DisplayAddr[0]);
+ mfc_debug(2, "[NALQ][FRAME] decoded status: %d, type: %d, yaddr: %#x\n",
+ pOutStr->DecodedStatus & S5P_FIMV_DEC_STATUS_DECODED_STATUS_MASK,
+ pOutStr->DecodedFrameType & S5P_FIMV_DECODED_FRAME_MASK,
+ pOutStr->DecodedAddr[0]);
+ mfc_debug(4, "[NALQ][HDR] SEI available status: %x\n", sei_avail_status);
+ mfc_debug(2, "[NALQ][DPB] Used flag: old = %08x, new = %08x\n",
+ dec->dynamic_used, pOutStr->UsedDpbFlagLower);
+
+ if (ctx->state == MFCINST_RES_CHANGE_INIT) {
+ mfc_debug(2, "[NALQ][DRC] return until NAL-Q stopped in try_run\n");
+ goto leave_handle_frame;
+ }
+ if (res_change) {
+ mfc_debug(2, "[NALQ][DRC] Resolution change set to %d\n", res_change);
+ s5p_mfc_change_state(ctx, MFCINST_RES_CHANGE_INIT);
+ ctx->wait_state = WAIT_DECODING;
+ dev->nal_q_handle->nal_q_exception = 1;
+ mfc_info_ctx("[NALQ][DRC] nal_q_exception is set (res change)\n");
+ goto leave_handle_frame;
+ }
+ if (need_empty_dpb) {
+ mfc_debug(2, "[NALQ][MULTIFRAME] There is multi-frame. consumed:%ld\n", dec->consumed);
+ dec->has_multiframe = 1;
+ dev->nal_q_handle->nal_q_exception = 1;
+ mfc_info_ctx("[NALQ][MULTIFRAME] nal_q_exception is set\n");
+ goto leave_handle_frame;
+ }
+ if (need_dpb_change || need_scratch_change) {
+ mfc_debug(2, "[NALQ][DRC] Interframe resolution change is not supported\n");
+ dev->nal_q_handle->nal_q_exception = 1;
+ mfc_info_ctx("[NALQ][DRC] nal_q_exception is set (interframe res change)\n");
+ goto leave_handle_frame;
+ }
+ if (is_interlaced) {
+ mfc_debug(2, "[NALQ][INTERLACE] Progressive -> Interlaced\n");
+ dec->is_interlaced = is_interlaced;
+ dev->nal_q_handle->nal_q_exception = 1;
+ mfc_info_ctx("[NALQ][INTERLACE] nal_q_exception is set\n");
+ goto leave_handle_frame;
+ }
+
+ if (s5p_mfc_is_queue_count_same(&ctx->buf_queue_lock, &ctx->src_buf_nal_queue, 0) &&
+ s5p_mfc_is_queue_count_same(&ctx->buf_queue_lock, &ctx->dst_buf_nal_queue, 0)) {
+ mfc_err_dev("[NALQ] Queue count is zero for src/dst\n");
+ goto leave_handle_frame;
+ }
+
+ switch (dst_frame_status) {
+ case S5P_FIMV_DEC_STATUS_DECODING_DISPLAY:
+ mfc_nal_q_handle_ref_frame(ctx, pOutStr);
+ mfc_nal_q_handle_frame_copy_timestamp(ctx, pOutStr);
+ break;
+ case S5P_FIMV_DEC_STATUS_DECODING_ONLY:
+ mfc_nal_q_handle_ref_frame(ctx, pOutStr);
+ mfc_nal_q_handle_reuse_buffer(ctx, pOutStr);
+ break;
+ default:
+ break;
+ }
+
+ /* A frame has been decoded and is in the buffer */
+ if (s5p_mfc_dec_status_display(dst_frame_status))
+ mfc_nal_q_handle_frame_new(ctx, err, pOutStr);
+ else
+ mfc_debug(2, "[NALQ] No display frame\n");
+
+ /* Mark source buffer as complete */
+ if (dst_frame_status != S5P_FIMV_DEC_STATUS_DISPLAY_ONLY)
+ mfc_nal_q_handle_frame_input(ctx, err, pOutStr);
+ else
+ mfc_debug(2, "[NALQ][DPB] can't support display only in NAL-Q, is_dpb_full: %d\n",
+ dec->is_dpb_full);
+
+leave_handle_frame:
+ mfc_debug_leave();
+}
+
+int mfc_nal_q_handle_error(struct s5p_mfc_ctx *ctx, EncoderOutputStr *pOutStr, int err)
+{
+ struct s5p_mfc_dev *dev;
+ struct s5p_mfc_dec *dec;
+ struct s5p_mfc_enc *enc;
+ struct s5p_mfc_buf *src_mb;
+ int stop_nal_q = 1;
+
+ mfc_debug_enter();
+
+ if (!ctx) {
+ mfc_err_dev("[NALQ] no mfc context to run\n");
+ goto end;
+ }
+
+ dev = ctx->dev;
+ if (!dev) {
+ mfc_err_dev("[NALQ] no mfc device to run\n");
+ goto end;
+ }
+
+ mfc_err_ctx("[NALQ] Interrupt Error: %d\n", pOutStr->ErrorCode);
+
+ dev->nal_q_handle->nal_q_exception = 1;
+ mfc_info_ctx("[NALQ] nal_q_exception is set (error)\n");
+
+ if (ctx->type == MFCINST_DECODER) {
+ dec = ctx->dec_priv;
+ if (!dec) {
+ mfc_err_dev("[NALQ] no mfc decoder to run\n");
+ goto end;
+ }
+ src_mb = s5p_mfc_get_del_buf(&ctx->buf_queue_lock,
+ &ctx->src_buf_nal_queue, MFC_BUF_NO_TOUCH_USED);
+
+ if (!src_mb) {
+ mfc_err_dev("[NALQ] no src buffers\n");
+ } else {
+ dec->consumed = 0;
+ vb2_buffer_done(&src_mb->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+ }
+ } else if (ctx->type == MFCINST_ENCODER) {
+ enc = ctx->enc_priv;
+ if (!enc) {
+ mfc_err_dev("[NALQ] no mfc encoder to run\n");
+ goto end;
+ }
+
+ /*
+ * If the buffer full error occurs in NAL-Q mode,
+ * one input buffer is returned and the NAL-Q mode continues.
+ */
+ if (err == S5P_FIMV_ERR_BUFFER_FULL) {
+ src_mb = s5p_mfc_get_del_buf(&ctx->buf_queue_lock,
+ &ctx->src_buf_nal_queue, MFC_BUF_NO_TOUCH_USED);
+
+ if (!src_mb)
+ mfc_err_dev("[NALQ] no src buffers\n");
+ else
+ vb2_buffer_done(&src_mb->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+
+ dev->nal_q_handle->nal_q_exception = 0;
+ stop_nal_q = 0;
+ }
+ }
+
+end:
+ mfc_debug_leave();
+
+ return stop_nal_q;
+}
+
+int s5p_mfc_nal_q_handle_out_buf(struct s5p_mfc_dev *dev, EncoderOutputStr *pOutStr)
+{
+ struct s5p_mfc_ctx *ctx;
+ struct s5p_mfc_enc *enc;
+ struct s5p_mfc_dec *dec;
+ int ctx_num;
+
+ mfc_debug_enter();
+
+ if (!dev) {
+ mfc_err_dev("[NALQ] no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ ctx_num = dev->nal_q_handle->nal_q_out_handle->nal_q_ctx;
+ if (ctx_num < 0) {
+ mfc_err_dev("[NALQ] Can't find ctx in nal q\n");
+ return -EINVAL;
+ }
+
+ ctx = dev->ctx[ctx_num];
+ if (!ctx) {
+ mfc_err_dev("[NALQ] no mfc context to run\n");
+ return -EINVAL;
+ }
+
+ mfc_debug(2, "[NALQ] Int ctx is %d(%s)\n", ctx_num,
+ ctx->type == MFCINST_ENCODER ? "enc" : "dec");
+
+ if (s5p_mfc_get_err(pOutStr->ErrorCode) &&
+ (s5p_mfc_get_err(pOutStr->ErrorCode) < S5P_FIMV_ERR_FRAME_CONCEAL)) {
+ if (mfc_nal_q_handle_error(ctx, pOutStr, s5p_mfc_get_err(pOutStr->ErrorCode)))
+ return 0;
+ }
+
+ if (ctx->type == MFCINST_ENCODER) {
+ enc = ctx->enc_priv;
+ if (!enc) {
+ mfc_err_dev("[NALQ] no mfc encoder to run\n");
+ return -EINVAL;
+ }
+ mfc_nal_q_handle_stream(ctx, pOutStr);
+ } else if (ctx->type == MFCINST_DECODER) {
+ dec = ctx->dec_priv;
+ if (!dec) {
+ mfc_err_dev("[NALQ] no mfc decoder to run\n");
+ return -EINVAL;
+ }
+ mfc_nal_q_handle_frame(ctx, (DecoderOutputStr *)pOutStr);
+ }
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+/*
+ * This function should be called in NAL_Q_STATE_STARTED state.
+ */
+int s5p_mfc_nal_q_enqueue_in_buf(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx,
+ nal_queue_in_handle *nal_q_in_handle)
+{
+ unsigned long flags;
+ unsigned int input_count = 0;
+ unsigned int input_exe_count = 0;
+ int input_diff = 0;
+ unsigned int index = 0;
+ EncoderInputStr *pStr = NULL;
+ int ret = 0;
+
+ mfc_debug_enter();
+
+ if (!nal_q_in_handle) {
+ mfc_err_dev("[NALQ] There is no nal_q_handle\n");
+ return -EINVAL;
+ }
+
+ if (nal_q_in_handle->nal_q_handle->nal_q_state != NAL_Q_STATE_STARTED) {
+ mfc_err_dev("[NALQ] State is wrong, state: %d\n",
+ nal_q_in_handle->nal_q_handle->nal_q_state);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&nal_q_in_handle->nal_q_handle->lock, flags);
+
+ input_count = s5p_mfc_get_nal_q_input_count();
+ input_exe_count = s5p_mfc_get_nal_q_input_exe_count();
+ input_diff = input_count - input_exe_count;
+
+ /*
+ * meaning of the variable input_diff
+ * 0: number of available slots = NAL_Q_IN_QUEUE_SIZE
+ * 1: number of available slots = NAL_Q_IN_QUEUE_SIZE - 1
+ * ...
+ * NAL_Q_IN_QUEUE_SIZE-1: number of available slots = 1
+ * NAL_Q_IN_QUEUE_SIZE: number of available slots = 0
+ */
+
+ mfc_debug(2, "[NALQ] input_diff = %d(in: %d, exe: %d)\n",
+ input_diff, input_count, input_exe_count);
+
+ if ((input_diff < 0) || (input_diff >= NAL_Q_IN_QUEUE_SIZE)) {
+ mfc_err_dev("[NALQ] No available input slot(%d)\n", input_diff);
+ spin_unlock_irqrestore(&nal_q_in_handle->nal_q_handle->lock, flags);
+ return -EINVAL;
+ }
+
+ index = input_count % NAL_Q_IN_QUEUE_SIZE;
+ pStr = &(nal_q_in_handle->nal_q_in_addr->entry[index].enc);
+
+ memset(pStr, 0, NAL_Q_IN_ENTRY_SIZE);
+
+ if (ctx->type == MFCINST_ENCODER)
+ ret = mfc_nal_q_run_in_buf_enc(ctx, pStr);
+ else if (ctx->type == MFCINST_DECODER)
+ ret = mfc_nal_q_run_in_buf_dec(ctx, (DecoderInputStr *)pStr);
+
+ if (ret != 0) {
+ mfc_debug(2, "[NALQ] Failed to set input queue\n");
+ spin_unlock_irqrestore(&nal_q_in_handle->nal_q_handle->lock, flags);
+ return ret;
+ }
+
+ if (nal_q_dump == 1) {
+ mfc_err_dev("[NAL-Q][DUMP][%s INPUT][c: %d] diff: %d, count: %d, exe: %d\n",
+ ctx->type == MFCINST_ENCODER ? "ENC" : "DEC", dev->curr_ctx,
+ input_diff, input_count, input_exe_count);
+ print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 32, 4, (int *)pStr, 256, false);
+ printk("...\n");
+ }
+ input_count++;
+
+ s5p_mfc_update_nal_queue_input_count(dev, input_count);
+
+ if (input_diff == 0)
+ s5p_mfc_watchdog_start_tick(dev);
+
+ spin_unlock_irqrestore(&nal_q_in_handle->nal_q_handle->lock, flags);
+
+ MFC_TRACE_CTX("NAL %s in: diff %d count %d exe %d\n",
+ ctx->type == MFCINST_ENCODER ? "ENC" : "DEC",
+ input_diff, input_count, input_exe_count);
+
+ mfc_debug_leave();
+
+ return ret;
+}
+
+/*
+ * This function should be called in NAL_Q_STATE_STARTED state.
+ */
+EncoderOutputStr *s5p_mfc_nal_q_dequeue_out_buf(struct s5p_mfc_dev *dev,
+ nal_queue_out_handle *nal_q_out_handle, unsigned int *reason)
+{
+ struct s5p_mfc_ctx *ctx;
+ unsigned long flags;
+ unsigned int output_count = 0;
+ unsigned int output_exe_count = 0;
+ int output_diff = 0;
+ unsigned int index = 0;
+ EncoderOutputStr *pStr = NULL;
+
+ int input_diff = 0;
+
+ mfc_debug_enter();
+
+ if (!nal_q_out_handle || !nal_q_out_handle->nal_q_out_addr) {
+ mfc_err_dev("[NALQ] There is no handle\n");
+ return pStr;
+ }
+
+ spin_lock_irqsave(&nal_q_out_handle->nal_q_handle->lock, flags);
+
+ output_count = s5p_mfc_get_nal_q_output_count();
+ output_exe_count = nal_q_out_handle->out_exe_count;
+ output_diff = output_count - output_exe_count;
+
+ /*
+ * meaning of the variable output_diff
+ * 0: number of output slots = 0
+ * 1: number of output slots = 1
+ * ...
+ * NAL_Q_OUT_QUEUE_SIZE-1: number of output slots = NAL_Q_OUT_QUEUE_SIZE - 1
+ * NAL_Q_OUT_QUEUE_SIZE: number of output slots = NAL_Q_OUT_QUEUE_SIZE
+ */
+
+ mfc_debug(2, "[NALQ] output_diff = %d(out: %d, exe: %d)\n",
+ output_diff, output_count, output_exe_count);
+ if ((output_diff <= 0) || (output_diff > NAL_Q_OUT_QUEUE_SIZE)) {
+ spin_unlock_irqrestore(&nal_q_out_handle->nal_q_handle->lock, flags);
+ mfc_debug(2, "[NALQ] No available output slot(%d)\n", output_diff);
+ return pStr;
+ }
+
+ index = output_exe_count % NAL_Q_OUT_QUEUE_SIZE;
+ pStr = &(nal_q_out_handle->nal_q_out_addr->entry[index].enc);
+
+ nal_q_out_handle->nal_q_ctx = mfc_nal_q_find_ctx(dev, pStr);
+ if (nal_q_out_handle->nal_q_ctx < 0) {
+ mfc_err_dev("[NALQ] Can't find ctx in nal q\n");
+ pStr = NULL;
+ return pStr;
+ }
+
+ ctx = dev->ctx[nal_q_out_handle->nal_q_ctx];
+ if (nal_q_dump == 1) {
+ mfc_err_dev("[NALQ][DUMP][%s OUTPUT][c: %d] diff: %d, count: %d, exe: %d\n",
+ ctx->type == MFCINST_ENCODER ? "ENC" : "DEC",
+ nal_q_out_handle->nal_q_ctx,
+ output_diff, output_count, output_exe_count);
+ print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 32, 4, (int *)pStr, 256, false);
+ printk("...\n");
+ }
+ nal_q_out_handle->out_exe_count++;
+
+ if (pStr->ErrorCode) {
+ *reason = S5P_FIMV_R2H_CMD_ERR_RET;
+ mfc_err_dev("[NALQ] Error : %d\n", pStr->ErrorCode);
+ }
+
+ input_diff = s5p_mfc_get_nal_q_input_count() - s5p_mfc_get_nal_q_input_exe_count();
+ if (input_diff == 0) {
+ s5p_mfc_watchdog_stop_tick(dev);
+ } else if (input_diff > 0) {
+ s5p_mfc_watchdog_reset_tick(dev);
+ }
+
+ spin_unlock_irqrestore(&nal_q_out_handle->nal_q_handle->lock, flags);
+
+ MFC_TRACE_CTX("NAL %s out: diff %d count %d exe %d\n",
+ ctx->type == MFCINST_ENCODER ? "ENC" : "DEC",
+ output_diff, output_count, output_exe_count);
+
+ mfc_debug_leave();
+
+ return pStr;
+}
+
+#if 0
+/* not used function - only for reference sfr <-> structure */
+void s5p_mfc_nal_q_fill_DecoderInputStr(struct s5p_mfc_dev *dev, DecoderInputStr *pStr)
+{
+ pStr->StartCode = 0xAAAAAAAA; // Decoder input start
+// pStr->CommandId = MFC_READL(S5P_FIMV_HOST2RISC_CMD); // 0x1100
+ pStr->InstanceId = MFC_READL(S5P_FIMV_INSTANCE_ID); // 0xF008
+ pStr->PictureTag = MFC_READL(S5P_FIMV_D_PICTURE_TAG); // 0xF5C8
+ pStr->CpbBufferAddr = MFC_READL(S5P_FIMV_D_CPB_BUFFER_ADDR); // 0xF5B0
+ pStr->CpbBufferSize = MFC_READL(S5P_FIMV_D_CPB_BUFFER_SIZE); // 0xF5B4
+ pStr->CpbBufferOffset = MFC_READL(S5P_FIMV_D_CPB_BUFFER_OFFSET); // 0xF5C0
+ pStr->StreamDataSize = MFC_READL(S5P_FIMV_D_STREAM_DATA_SIZE); // 0xF5D0
+ pStr->AvailableDpbFlagUpper = MFC_READL(S5P_FIMV_D_AVAILABLE_DPB_FLAG_UPPER);// 0xF5B8
+ pStr->AvailableDpbFlagLower = MFC_READL(S5P_FIMV_D_AVAILABLE_DPB_FLAG_LOWER);// 0xF5BC
+ pStr->DynamicDpbFlagUpper = MFC_READL(S5P_FIMV_D_DYNAMIC_DPB_FLAG_UPPER); // 0xF5D4
+ pStr->DynamicDpbFlagLower = MFC_READL(S5P_FIMV_D_DYNAMIC_DPB_FLAG_LOWER); // 0xF5D8
+ pStr->FirstPlaneDpb = MFC_READL(S5P_FIMV_D_FIRST_PLANE_DPB0); // 0xF160+(index*4)
+ pStr->SecondPlaneDpb = MFC_READL(S5P_FIMV_D_SECOND_PLANE_DPB0); // 0xF260+(index*4)
+ pStr->ThirdPlaneDpb = MFC_READL(S5P_FIMV_D_THIRD_PLANE_DPB0); // 0xF360+(index*4)
+ pStr->FirstPlaneDpbSize = MFC_READL(S5P_FIMV_D_FIRST_PLANE_DPB_SIZE); // 0xF144
+ pStr->SecondPlaneDpbSize = MFC_READL(S5P_FIMV_D_SECOND_PLANE_DPB_SIZE); // 0xF148
+ pStr->ThirdPlaneDpbSize = MFC_READL(S5P_FIMV_D_THIRD_PLANE_DPB_SIZE); // 0xF14C
+ pStr->NalStartOptions = MFC_READL(0xF5AC);// S5P_FIMV_D_NAL_START_OPTIONS 0xF5AC
+ pStr->FirstPlaneStrideSize = MFC_READL(S5P_FIMV_D_FIRST_PLANE_DPB_STRIDE_SIZE);// 0xF138
+ pStr->SecondPlaneStrideSize = MFC_READL(S5P_FIMV_D_SECOND_PLANE_DPB_STRIDE_SIZE);// 0xF13C
+ pStr->ThirdPlaneStrideSize = MFC_READL(S5P_FIMV_D_THIRD_PLANE_DPB_STRIDE_SIZE);// 0xF140
+ pStr->FirstPlane2BitDpbSize = MFC_READL(S5P_FIMV_D_FIRST_PLANE_2BIT_DPB_SIZE);// 0xF578
+ pStr->SecondPlane2BitDpbSize = MFC_READL(S5P_FIMV_D_SECOND_PLANE_2BIT_DPB_SIZE);// 0xF57C
+ pStr->FirstPlane2BitStrideSize = MFC_READL(S5P_FIMV_D_FIRST_PLANE_2BIT_DPB_STRIDE_SIZE);// 0xF580
+ pStr->SecondPlane2BitStrideSize = MFC_READL(S5P_FIMV_D_SECOND_PLANE_2BIT_DPB_STRIDE_SIZE);// 0xF584
+ pStr->ScratchBufAddr = MFC_READL(S5P_FIMV_D_SCRATCH_BUFFER_ADDR); // 0xF560
+ pStr->ScratchBufSize = MFC_READL(S5P_FIMV_D_SCRATCH_BUFFER_SIZE); // 0xF564
+}
+
+void s5p_mfc_nal_q_flush_DecoderOutputStr(struct s5p_mfc_dev *dev, DecoderOutputStr *pStr)
+{
+ //pStr->StartCode; // 0xAAAAAAAA; // Decoder output start
+// MFC_WRITEL(pStr->CommandId, S5P_FIMV_RISC2HOST_CMD); // 0x1104
+ MFC_WRITEL(pStr->InstanceId, S5P_FIMV_RET_INSTANCE_ID); // 0xF070
+ MFC_WRITEL(pStr->ErrorCode, S5P_FIMV_ERROR_CODE); // 0xF074
+ MFC_WRITEL(pStr->PictureTagTop, S5P_FIMV_D_RET_PICTURE_TAG_TOP); // 0xF674
+ MFC_WRITEL(pStr->PictureTimeTop, S5P_FIMV_D_RET_PICTURE_TIME_TOP); // 0xF67C
+ MFC_WRITEL(pStr->DisplayFrameWidth, S5P_FIMV_D_DISPLAY_FRAME_WIDTH); // 0xF600
+ MFC_WRITEL(pStr->DisplayFrameHeight, S5P_FIMV_D_DISPLAY_FRAME_HEIGHT); // 0xF604
+ MFC_WRITEL(pStr->DisplayStatus, S5P_FIMV_D_DISPLAY_STATUS); // 0xF608
+ MFC_WRITEL(pStr->DisplayFirstPlaneAddr, S5P_FIMV_D_DISPLAY_FIRST_PLANE_ADDR); // 0xF60C
+ MFC_WRITEL(pStr->DisplaySecondPlaneAddr, S5P_FIMV_D_DISPLAY_SECOND_PLANE_ADDR); // 0xF610
+ MFC_WRITEL(pStr->DisplayThirdPlaneAddr,S5P_FIMV_D_DISPLAY_THIRD_PLANE_ADDR); // 0xF614
+ MFC_WRITEL(pStr->DisplayFrameType, S5P_FIMV_D_DISPLAY_FRAME_TYPE); // 0xF618
+ MFC_WRITEL(pStr->DisplayCropInfo1, S5P_FIMV_D_DISPLAY_CROP_INFO1); // 0xF61C
+ MFC_WRITEL(pStr->DisplayCropInfo2, S5P_FIMV_D_DISPLAY_CROP_INFO2); // 0xF620
+ MFC_WRITEL(pStr->DisplayPictureProfile, S5P_FIMV_D_DISPLAY_PICTURE_PROFILE); // 0xF624
+ MFC_WRITEL(pStr->DisplayAspectRatio, S5P_FIMV_D_DISPLAY_ASPECT_RATIO); // 0xF634
+ MFC_WRITEL(pStr->DisplayExtendedAr, S5P_FIMV_D_DISPLAY_EXTENDED_AR); // 0xF638
+ MFC_WRITEL(pStr->DecodedNalSize, S5P_FIMV_D_DECODED_NAL_SIZE); // 0xF664
+ MFC_WRITEL(pStr->UsedDpbFlagUpper, S5P_FIMV_D_USED_DPB_FLAG_UPPER); // 0xF720
+ MFC_WRITEL(pStr->UsedDpbFlagLower, S5P_FIMV_D_USED_DPB_FLAG_LOWER); // 0xF724
+ MFC_WRITEL(pStr->SeiAvail, S5P_FIMV_D_SEI_AVAIL); // 0xF6DC
+ MFC_WRITEL(pStr->FramePackArrgmentId, S5P_FIMV_D_FRAME_PACK_ARRGMENT_ID); // 0xF6E0
+ MFC_WRITEL(pStr->FramePackSeiInfo, S5P_FIMV_D_FRAME_PACK_SEI_INFO); // 0xF6E4
+ MFC_WRITEL(pStr->FramePackGridPos, S5P_FIMV_D_FRAME_PACK_GRID_POS); // 0xF6E8
+ MFC_WRITEL(pStr->DisplayRecoverySeiInfo, S5P_FIMV_D_DISPLAY_RECOVERY_SEI_INFO); // 0xF6EC
+ MFC_WRITEL(pStr->H264Info, S5P_FIMV_D_H264_INFO); // 0xF690
+ MFC_WRITEL(pStr->DisplayFirstCrc, S5P_FIMV_D_DISPLAY_FIRST_PLANE_CRC); // 0xF628
+ MFC_WRITEL(pStr->DisplaySecondCrc, S5P_FIMV_D_DISPLAY_SECOND_PLANE_CRC); // 0xF62C
+ MFC_WRITEL(pStr->DisplayThirdCrc, S5P_FIMV_D_DISPLAY_THIRD_PLANE_CRC); // 0xF630
+ MFC_WRITEL(pStr->DisplayFirst2BitCrc, S5P_FIMV_D_DISPLAY_FIRST_PLANE_2BIT_CRC); // 0xF6FC
+ MFC_WRITEL(pStr->DisplaySecond2BitCrc, S5P_FIMV_D_DISPLAY_SECOND_PLANE_2BIT_CRC);// 0xF700
+ MFC_WRITEL(pStr->DecodedFrameWidth, S5P_FIMV_D_DECODED_FRAME_WIDTH); // 0xF63C
+ MFC_WRITEL(pStr->DecodedFrameHeight, S5P_FIMV_D_DECODED_FRAME_HEIGHT); // 0xF640
+ MFC_WRITEL(pStr->DecodedStatus, S5P_FIMV_D_DECODED_STATUS); // 0xF644
+ MFC_WRITEL(pStr->DecodedFirstPlaneAddr, S5P_FIMV_D_DECODED_FIRST_PLANE_ADDR); // 0xF648
+ MFC_WRITEL(pStr->DecodedSecondPlaneAddr, S5P_FIMV_D_DECODED_SECOND_PLANE_ADDR); // 0xF64C
+ MFC_WRITEL(pStr->DecodedThirdPlaneAddr, S5P_FIMV_D_DECODED_THIRD_PLANE_ADDR); // 0xF650
+ MFC_WRITEL(pStr->DecodedFrameType, S5P_FIMV_D_DECODED_FRAME_TYPE); // 0xF654
+ MFC_WRITEL(pStr->DecodedCropInfo1, S5P_FIMV_D_DECODED_CROP_INFO1); // 0xF658
+ MFC_WRITEL(pStr->DecodedCropInfo2, S5P_FIMV_D_DECODED_CROP_INFO2); // 0xF65C
+ MFC_WRITEL(pStr->DecodedPictureProfile, S5P_FIMV_D_DECODED_PICTURE_PROFILE); // 0xF660
+ MFC_WRITEL(pStr->DecodedRecoverySeiInfo, S5P_FIMV_D_DECODED_RECOVERY_SEI_INFO); // 0xF6F0
+ MFC_WRITEL(pStr->DecodedFirstCrc, S5P_FIMV_D_DECODED_FIRST_PLANE_CRC); // 0xF668
+ MFC_WRITEL(pStr->DecodedSecondCrc, S5P_FIMV_D_DECODED_SECOND_PLANE_CRC); // 0xF66C
+ MFC_WRITEL(pStr->DecodedThirdCrc, S5P_FIMV_D_DECODED_THIRD_PLANE_CRC); // 0xF670
+ MFC_WRITEL(pStr->DecodedFirst2BitCrc, S5P_FIMV_D_DECODED_FIRST_PLANE_2BIT_CRC); // 0xF704
+ MFC_WRITEL(pStr->DecodedSecond2BitCrc, S5P_FIMV_D_DECODED_SECOND_PLANE_2BIT_CRC);// 0xF708
+ MFC_WRITEL(pStr->PictureTagBot, S5P_FIMV_D_RET_PICTURE_TAG_BOT); // 0xF678
+ MFC_WRITEL(pStr->PictureTimeBot, S5P_FIMV_D_RET_PICTURE_TIME_BOT); // 0xF680
+}
+#endif
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_nal_q.h
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __MFC_NAL_Q_H
+#define __MFC_NAL_Q_H __FILE__
+
+#include "mfc_common.h"
+
+int s5p_mfc_nal_q_check_enable(struct s5p_mfc_dev *dev);
+
+void s5p_mfc_nal_q_clock_on(struct s5p_mfc_dev *dev, nal_queue_handle *nal_q_handle);
+void s5p_mfc_nal_q_clock_off(struct s5p_mfc_dev *dev, nal_queue_handle *nal_q_handle);
+void s5p_mfc_nal_q_cleanup_clock(struct s5p_mfc_dev *dev);
+
+nal_queue_handle *s5p_mfc_nal_q_create(struct s5p_mfc_dev *dev);
+int s5p_mfc_nal_q_destroy(struct s5p_mfc_dev *dev, nal_queue_handle *nal_q_handle);
+
+void s5p_mfc_nal_q_init(struct s5p_mfc_dev *dev, nal_queue_handle *nal_q_handle);
+void s5p_mfc_nal_q_start(struct s5p_mfc_dev *dev, nal_queue_handle *nal_q_handle);
+void s5p_mfc_nal_q_stop(struct s5p_mfc_dev *dev, nal_queue_handle *nal_q_handle);
+void s5p_mfc_nal_q_stop_if_started(struct s5p_mfc_dev *dev);
+void s5p_mfc_nal_q_cleanup_queue(struct s5p_mfc_dev *dev);
+
+int s5p_mfc_nal_q_handle_out_buf(struct s5p_mfc_dev *dev, EncoderOutputStr *pOutStr);
+int s5p_mfc_nal_q_enqueue_in_buf(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx,
+ nal_queue_in_handle *nal_q_in_handle);
+EncoderOutputStr *s5p_mfc_nal_q_dequeue_out_buf(struct s5p_mfc_dev *dev,
+ nal_queue_out_handle *nal_q_out_handle, unsigned int *reason);
+
+#endif /* __MFC_NAL_Q_H */
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_opr.c
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "mfc_opr.h"
+
+#include "mfc_inst.h"
+#include "mfc_reg.h"
+
+#include "mfc_queue.h"
+#include "mfc_utils.h"
+#include "mfc_mem.h"
+
+int s5p_mfc_run_dec_init(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev;
+ struct s5p_mfc_buf *src_mb;
+ struct s5p_mfc_dec *dec = NULL;
+
+ if (!ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return -EINVAL;
+ }
+ dev = ctx->dev;
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+ dec = ctx->dec_priv;
+ /* Initializing decoding - parsing header */
+
+ /* Get the next source buffer */
+ src_mb = s5p_mfc_get_buf(&ctx->buf_queue_lock, &ctx->src_buf_queue, MFC_BUF_NO_TOUCH_USED);
+ if (!src_mb) {
+ mfc_err_dev("no src buffers\n");
+ return -EAGAIN;
+ }
+
+ mfc_debug(2, "Preparing to init decoding\n");
+ mfc_debug(2, "Header size: %d, (offset: %lu)\n",
+ src_mb->vb.vb2_buf.planes[0].bytesused, dec->consumed);
+
+ if (dec->consumed) {
+ s5p_mfc_set_dec_stream_buffer(ctx, src_mb, dec->consumed, dec->remained_size);
+ } else {
+ /* decoder src buffer CFW PROT */
+ if (ctx->is_drm) {
+ int index = src_mb->vb.vb2_buf.index;
+
+ s5p_mfc_stream_protect(ctx, src_mb, index);
+ }
+
+ s5p_mfc_set_dec_stream_buffer(ctx, src_mb,
+ 0, src_mb->vb.vb2_buf.planes[0].bytesused);
+ }
+
+ mfc_debug(2, "Header addr: 0x%08llx\n", src_mb->addr[0][0]);
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ s5p_mfc_init_decode(ctx);
+
+ return 0;
+}
+
+static int mfc_check_last_frame(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *mfc_buf)
+{
+ if (mfc_buf->vb.reserved2 & FLAG_LAST_FRAME) {
+ mfc_debug(2, "Setting ctx->state to FINISHING\n");
+ s5p_mfc_change_state(ctx, MFCINST_FINISHING);
+ return 1;
+ }
+
+ return 0;
+}
+
+int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev;
+ struct s5p_mfc_buf *src_mb, *dst_mb;
+ struct s5p_mfc_dec *dec;
+ int last_frame = 0;
+ unsigned int index;
+
+ if (!ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return -EINVAL;
+ }
+ dec = ctx->dec_priv;
+ dev = ctx->dev;
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ if (s5p_mfc_is_queue_count_same(&ctx->buf_queue_lock, &ctx->dst_buf_queue, 0) &&
+ s5p_mfc_is_queue_count_smaller(&ctx->buf_queue_lock,
+ &ctx->ref_buf_queue, (ctx->dpb_count + 5))) {
+ return -EAGAIN;
+ }
+
+ /* Get the next source buffer */
+ src_mb = s5p_mfc_get_buf(&ctx->buf_queue_lock, &ctx->src_buf_queue, MFC_BUF_SET_USED);
+ if (!src_mb) {
+ mfc_debug(2, "no src buffers\n");
+ return -EAGAIN;
+ }
+
+ /* decoder src buffer CFW PROT */
+ if (ctx->is_drm) {
+ if (!dec->consumed) {
+ index = src_mb->vb.vb2_buf.index;
+ s5p_mfc_stream_protect(ctx, src_mb, index);
+ }
+ }
+
+ if (src_mb->vb.reserved2 & FLAG_EMPTY_DATA)
+ src_mb->vb.vb2_buf.planes[0].bytesused = 0;
+
+ if (dec->consumed)
+ s5p_mfc_set_dec_stream_buffer(ctx, src_mb, dec->consumed, dec->remained_size);
+ else
+ s5p_mfc_set_dec_stream_buffer(ctx, src_mb, 0, src_mb->vb.vb2_buf.planes[0].bytesused);
+
+ /* Try to use the non-referenced DPB on dst-queue */
+ dst_mb = s5p_mfc_search_for_dpb(ctx, dec->dynamic_used);
+ if (!dst_mb) {
+ mfc_debug(2, "[DPB] couldn't find dst buffers\n");
+ return -EAGAIN;
+ }
+
+ index = src_mb->vb.vb2_buf.index;
+ if (call_cop(ctx, set_buf_ctrls_val, ctx, &ctx->src_ctrls[index]) < 0)
+ mfc_err_ctx("failed in set_buf_ctrls_val\n");
+
+ s5p_mfc_set_dynamic_dpb(ctx, dst_mb);
+
+ s5p_mfc_clean_ctx_int_flags(ctx);
+
+ last_frame = mfc_check_last_frame(ctx, src_mb);
+ s5p_mfc_decode_one_frame(ctx, last_frame);
+
+ return 0;
+}
+
+int s5p_mfc_run_dec_last_frames(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev;
+ struct s5p_mfc_buf *src_mb, *dst_mb;
+ struct s5p_mfc_dec *dec;
+
+ if (!ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return -EINVAL;
+ }
+
+ dec = ctx->dec_priv;
+ if (!dec) {
+ mfc_err_dev("no decoder context to run\n");
+ return -EINVAL;
+ }
+
+ dev = ctx->dev;
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ if (s5p_mfc_is_queue_count_same(&ctx->buf_queue_lock, &ctx->dst_buf_queue, 0)) {
+ mfc_debug(2, "no dst buffer\n");
+ return -EAGAIN;
+ }
+
+ /* Get the next source buffer */
+ src_mb = s5p_mfc_get_buf(&ctx->buf_queue_lock, &ctx->src_buf_queue, MFC_BUF_SET_USED);
+
+ /* Frames are being decoded */
+ if (!src_mb) {
+ mfc_debug(2, "no src buffers\n");
+ s5p_mfc_set_dec_stream_buffer(ctx, 0, 0, 0);
+ } else {
+ if (dec->consumed) {
+ s5p_mfc_set_dec_stream_buffer(ctx, src_mb, dec->consumed, dec->remained_size);
+ } else {
+ /* decoder src buffer CFW PROT */
+ if (ctx->is_drm) {
+ int index = src_mb->vb.vb2_buf.index;
+
+ s5p_mfc_stream_protect(ctx, src_mb, index);
+ }
+
+ s5p_mfc_set_dec_stream_buffer(ctx, src_mb, 0, 0);
+ }
+ }
+
+ /* Try to use the non-referenced DPB on dst-queue */
+ dst_mb = s5p_mfc_search_for_dpb(ctx, dec->dynamic_used);
+ if (!dst_mb) {
+ mfc_debug(2, "[DPB] couldn't find dst buffers\n");
+ return -EAGAIN;
+ }
+
+ s5p_mfc_set_dynamic_dpb(ctx, dst_mb);
+
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ s5p_mfc_decode_one_frame(ctx, 1);
+
+ return 0;
+}
+
+int s5p_mfc_run_enc_init(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_buf *dst_mb;
+ int ret;
+
+ dst_mb = s5p_mfc_get_buf(&ctx->buf_queue_lock, &ctx->dst_buf_queue, MFC_BUF_NO_TOUCH_USED);
+ if (!dst_mb) {
+ mfc_debug(2, "no dst buffers\n");
+ return -EAGAIN;
+ }
+
+ /* encoder dst buffer CFW PROT */
+ if (ctx->is_drm) {
+ int index = dst_mb->vb.vb2_buf.index;
+
+ s5p_mfc_stream_protect(ctx, dst_mb, index);
+ }
+ s5p_mfc_set_enc_stream_buffer(ctx, dst_mb);
+
+ s5p_mfc_set_enc_stride(ctx);
+
+ mfc_debug(2, "Header addr: 0x%08llx\n", dst_mb->addr[0][0]);
+ s5p_mfc_clean_ctx_int_flags(ctx);
+
+ ret = s5p_mfc_init_encode(ctx);
+ return ret;
+}
+
+int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_buf *dst_mb;
+ struct s5p_mfc_buf *src_mb;
+ struct s5p_mfc_raw_info *raw;
+ unsigned int index, i;
+ int last_frame = 0;
+
+ raw = &ctx->raw_buf;
+
+ /* Get the next source buffer */
+ src_mb = s5p_mfc_get_buf(&ctx->buf_queue_lock, &ctx->src_buf_queue, MFC_BUF_SET_USED);
+ if (!src_mb) {
+ mfc_debug(2, "no src buffers\n");
+ return -EAGAIN;
+ }
+
+ if (src_mb->num_valid_bufs > 0) {
+ /* last image in a buffer container */
+ if (src_mb->next_index == (src_mb->num_valid_bufs - 1)) {
+ mfc_debug(4, "[BUFCON] last image in a container\n");
+ last_frame = mfc_check_last_frame(ctx, src_mb);
+ }
+ } else {
+ last_frame = mfc_check_last_frame(ctx, src_mb);
+ }
+
+ index = src_mb->vb.vb2_buf.index;
+
+ /* encoder src buffer CFW PROT */
+ if (ctx->is_drm)
+ s5p_mfc_raw_protect(ctx, src_mb, index);
+
+ s5p_mfc_set_enc_frame_buffer(ctx, src_mb, raw->num_planes);
+
+ dst_mb = s5p_mfc_get_buf(&ctx->buf_queue_lock, &ctx->dst_buf_queue, MFC_BUF_SET_USED);
+ if (!dst_mb) {
+ mfc_debug(2, "no dst buffers\n");
+ return -EAGAIN;
+ }
+
+ /* encoder dst buffer CFW PROT */
+ if (ctx->is_drm) {
+ i = dst_mb->vb.vb2_buf.index;
+ s5p_mfc_stream_protect(ctx, dst_mb, i);
+ }
+ mfc_debug(2, "nal start : src index from src_buf_queue:%d\n",
+ src_mb->vb.vb2_buf.index);
+ mfc_debug(2, "nal start : dst index from dst_buf_queue:%d\n",
+ dst_mb->vb.vb2_buf.index);
+
+ s5p_mfc_set_enc_stream_buffer(ctx, dst_mb);
+
+ if (call_cop(ctx, set_buf_ctrls_val, ctx, &ctx->src_ctrls[index]) < 0)
+ mfc_err_ctx("failed in set_buf_ctrls_val\n");
+
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ s5p_mfc_encode_one_frame(ctx, last_frame);
+
+ return 0;
+}
+
+int s5p_mfc_run_enc_last_frames(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_buf *dst_mb;
+ struct s5p_mfc_raw_info *raw;
+
+ raw = &ctx->raw_buf;
+
+ dst_mb = s5p_mfc_get_buf(&ctx->buf_queue_lock, &ctx->dst_buf_queue, MFC_BUF_SET_USED);
+ if (!dst_mb) {
+ mfc_debug(2, "no dst buffers\n");
+ return -EAGAIN;
+ }
+
+ mfc_debug(2, "Set address zero for all planes\n");
+ s5p_mfc_set_enc_frame_buffer(ctx, 0, raw->num_planes);
+
+ /* encoder dst buffer CFW PROT */
+ if (ctx->is_drm) {
+ int index = dst_mb->vb.vb2_buf.index;
+
+ s5p_mfc_stream_protect(ctx, dst_mb, index);
+ }
+
+ s5p_mfc_set_enc_stream_buffer(ctx, dst_mb);
+
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ s5p_mfc_encode_one_frame(ctx, 1);
+
+ return 0;
+}
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_opr.h
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __MFC_OPR_H
+#define __MFC_OPR_H __FILE__
+
+#include "mfc_common.h"
+
+int s5p_mfc_run_dec_init(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_run_dec_last_frames(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_run_enc_init(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_run_enc_last_frames(struct s5p_mfc_ctx *ctx);
+
+#endif /* __MFC_OPR_H */
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_otf.c
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifdef CONFIG_VIDEO_EXYNOS_REPEATER
+#include <media/exynos_repeater.h>
+#endif
+#ifdef CONFIG_VIDEO_EXYNOS_TSMUX
+#include <media/exynos_tsmux.h>
+#endif
+#include <media/s5p_mfc_hwfc.h>
+
+#include "mfc_otf.h"
+#include "mfc_hwfc_internal.h"
+
+#include "mfc_sync.h"
+
+#include "mfc_inst.h"
+#include "mfc_pm.h"
+#include "mfc_cmd.h"
+#include "mfc_reg.h"
+
+#include "mfc_qos.h"
+#include "mfc_queue.h"
+#include "mfc_utils.h"
+#include "mfc_buf.h"
+#include "mfc_mem.h"
+
+static struct s5p_mfc_fmt *mfc_enc_hwfc_find_format(unsigned int pixelformat)
+{
+ unsigned long i;
+
+ mfc_debug_enter();
+
+ for (i = 0; i < NUM_FORMATS; i++) {
+ if (enc_hwfc_formats[i].fourcc == pixelformat)
+ return (struct s5p_mfc_fmt *)&enc_hwfc_formats[i];
+ }
+
+ mfc_debug_leave();
+
+ return NULL;
+}
+
+static int mfc_otf_set_buf_info(struct s5p_mfc_ctx *ctx)
+{
+ struct _otf_handle *handle = ctx->otf_handle;
+ struct _otf_buf_info *buf_info = &handle->otf_buf_info;
+
+ mfc_debug_enter();
+
+ ctx->src_fmt = mfc_enc_hwfc_find_format(buf_info->pixel_format);
+ if (!ctx->src_fmt) {
+ mfc_err_ctx("[OTF] failed to set source format\n");
+ return -EINVAL;
+ }
+
+ mfc_debug(2, "[OTF][FRAME] resolution w: %d, h: %d, format: %s, bufcnt: %d\n",
+ buf_info->width, buf_info->height,
+ ctx->src_fmt->name, buf_info->buffer_count);
+
+ /* set source information */
+ ctx->raw_buf.num_planes = ctx->src_fmt->num_planes;
+ ctx->img_width = buf_info->width;
+ ctx->img_height = buf_info->height;
+ ctx->crop_width = buf_info->width;
+ ctx->crop_height = buf_info->height;
+ ctx->buf_stride = ALIGN(ctx->img_width, 16);
+
+ /* calculate source size */
+ s5p_mfc_enc_calc_src_size(ctx);
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+static int mfc_otf_map_buf(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct _otf_handle *handle = ctx->otf_handle;
+ struct _otf_buf_addr *buf_addr = &handle->otf_buf_addr;
+ struct _otf_buf_info *buf_info = &handle->otf_buf_info;
+ struct s5p_mfc_raw_info *raw = &ctx->raw_buf;
+ int i;
+
+ mfc_debug_enter();
+
+ mfc_debug(2, "[OTF] buffer count: %d\n", buf_info->buffer_count);
+ /* map buffers */
+ for (i = 0; i < buf_info->buffer_count; i++) {
+ mfc_debug(2, "[OTF] dma_buf: 0x%p\n", buf_info->bufs[i]);
+ buf_addr->otf_buf_attach[i] = dma_buf_attach(buf_info->bufs[i], dev->device);
+ if (IS_ERR(buf_addr->otf_buf_attach[i])) {
+ mfc_err_ctx("[OTF] Failed to get attachment (err %ld)",
+ PTR_ERR(buf_addr->otf_buf_attach[i]));
+ buf_addr->otf_buf_attach[i] = 0;
+ return -EINVAL;
+ }
+ buf_addr->otf_daddr[i][0] = ion_iovmm_map(buf_addr->otf_buf_attach[i], 0,
+ raw->total_plane_size, DMA_BIDIRECTIONAL, 0);
+ if (IS_ERR_VALUE(buf_addr->otf_daddr[i][0])) {
+ mfc_err_ctx("[OTF] Failed to get daddr (0x%08llx)",
+ buf_addr->otf_daddr[i][0]);
+ buf_addr->otf_daddr[i][0] = 0;
+ return -EINVAL;
+ }
+ if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12N) {
+ buf_addr->otf_daddr[i][1] = NV12N_CBCR_BASE(buf_addr->otf_daddr[i][0],
+ ctx->img_width, ctx->img_height);
+ } else {
+ mfc_err_ctx("[OTF] not supported format(0x%x)\n", ctx->src_fmt->fourcc);
+ return -EINVAL;
+ }
+ mfc_debug(2, "[OTF] index: %d, addr[0]: 0x%08llx, addr[1]: 0x%08llx\n",
+ i, buf_addr->otf_daddr[i][0], buf_addr->otf_daddr[i][1]);
+ }
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+static void mfc_otf_unmap_buf(struct s5p_mfc_ctx *ctx)
+{
+ struct _otf_handle *handle = ctx->otf_handle;
+ struct _otf_buf_addr *buf_addr = &handle->otf_buf_addr;
+ struct _otf_buf_info *buf_info = &handle->otf_buf_info;
+ int i;
+
+ mfc_debug_enter();
+
+ for (i = 0; i < buf_info->buffer_count; i++) {
+ if (buf_addr->otf_daddr[i][0]) {
+ ion_iovmm_unmap(buf_addr->otf_buf_attach[i], buf_addr->otf_daddr[i][0]);
+ buf_addr->otf_daddr[i][0] = 0;
+ }
+ if (buf_addr->otf_buf_attach[i]) {
+ dma_buf_detach(buf_info->bufs[i], buf_addr->otf_buf_attach[i]);
+ buf_addr->otf_buf_attach[i] = 0;
+ }
+ }
+
+ mfc_debug_leave();
+}
+
+static void mfc_otf_put_buf(struct s5p_mfc_ctx *ctx)
+{
+ struct _otf_handle *handle = ctx->otf_handle;
+ struct _otf_buf_info *buf_info = &handle->otf_buf_info;
+ int i;
+
+ mfc_debug_enter();
+
+ for (i = 0; i < buf_info->buffer_count; i++) {
+ if (buf_info->bufs[i]) {
+ dma_buf_put(buf_info->bufs[i]);
+ buf_info->bufs[i] = NULL;
+ }
+ }
+
+ mfc_debug_leave();
+
+}
+
+static int mfc_otf_init_hwfc_buf(struct s5p_mfc_ctx *ctx)
+{
+#ifdef CONFIG_VIDEO_EXYNOS_REPEATER
+ struct shared_buffer_info *shared_buf_info;
+#endif
+ struct _otf_handle *handle = ctx->otf_handle;
+ struct _otf_buf_info *buf_info = &handle->otf_buf_info;
+
+ mfc_debug_enter();
+
+#ifdef CONFIG_VIDEO_EXYNOS_REPEATER
+ shared_buf_info = (struct shared_buffer_info *)buf_info;
+ /* request buffers */
+ if (hwfc_request_buffer(shared_buf_info, 1)) {
+ mfc_err_dev("[OTF] request_buffer failed\n");
+ return -EINVAL;
+ }
+#endif
+ mfc_debug(2, "[OTF] recieved buffer information\n");
+
+ /* set buffer information to ctx, and calculate buffer size */
+ if (mfc_otf_set_buf_info(ctx)) {
+ mfc_err_ctx("[OTF] failed to set buffer information\n");
+ mfc_otf_put_buf(ctx);
+ return -EINVAL;
+ }
+
+ if (mfc_otf_map_buf(ctx)) {
+ mfc_err_ctx("[OTF] failed to map buffers\n");
+ mfc_otf_unmap_buf(ctx);
+ mfc_otf_put_buf(ctx);
+ return -EINVAL;
+ }
+ mfc_debug(2, "[OTF] HWFC buffer initialized\n");
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+static void mfc_otf_deinit_hwfc_buf(struct s5p_mfc_ctx *ctx)
+{
+ mfc_debug_enter();
+
+ mfc_otf_unmap_buf(ctx);
+ mfc_otf_put_buf(ctx);
+ mfc_debug(2, "[OTF] HWFC buffer de-initialized\n");
+
+ mfc_debug_leave();
+}
+
+static int mfc_otf_create_handle(struct s5p_mfc_ctx *ctx)
+{
+ struct _otf_handle *otf_handle;
+
+ mfc_debug_enter();
+
+ if (!ctx) {
+ mfc_err_dev("[OTF] no mfc context to run\n");
+ return -EINVAL;
+ }
+
+ ctx->otf_handle = kzalloc(sizeof(*otf_handle), GFP_KERNEL);
+ if (!ctx->otf_handle) {
+ mfc_err_dev("[OTF] no otf_handle\n");
+ return -EINVAL;
+ }
+ mfc_debug(2, "[OTF] otf_handle created\n");
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+static void mfc_otf_destroy_handle(struct s5p_mfc_ctx *ctx)
+{
+ mfc_debug_enter();
+
+ if (!ctx) {
+ mfc_err_dev("[OTF] no mfc context to run\n");
+ return;
+ }
+
+ kfree(ctx->otf_handle);
+ ctx->otf_handle = NULL;
+ mfc_debug(2, "[OTF] otf_handle destroyed\n");
+
+ mfc_debug_leave();
+}
+
+int s5p_mfc_otf_create(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev;
+ int i;
+
+ mfc_debug_enter();
+
+ if (!ctx) {
+ mfc_err_dev("[OTF] no mfc context to run\n");
+ return -EINVAL;
+ }
+
+ dev = ctx->dev;
+ if (!dev) {
+ mfc_err_dev("[OTF] no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < MFC_NUM_CONTEXTS; i++) {
+ if (dev->ctx[i] && dev->ctx[i]->otf_handle) {
+ mfc_err_dev("[OTF] otf_handle is already created, ctx: %d\n", i);
+ return -EINVAL;
+ }
+ }
+
+ if (mfc_otf_create_handle(ctx)) {
+ mfc_err_dev("[OTF] otf_handle is not created\n");
+ return -EINVAL;
+ }
+
+ if (otf_dump) {
+ /* It is for debugging. Do not return error */
+ if (s5p_mfc_otf_alloc_stream_buf(ctx)) {
+ mfc_err_dev("[OTF] stream buffer allocation failed\n");
+ s5p_mfc_otf_release_stream_buf(ctx);
+ }
+ }
+
+ mfc_debug(2, "[OTF] otf_create is completed\n");
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+void s5p_mfc_otf_destroy(struct s5p_mfc_ctx *ctx)
+{
+ mfc_debug_enter();
+
+ if (!ctx) {
+ mfc_err_dev("[OTF] no mfc context to run\n");
+ return;
+ }
+
+ s5p_mfc_otf_release_stream_buf(ctx);
+ mfc_otf_destroy_handle(ctx);
+ mfc_debug(2, "[OTF] otf_destroy is completed\n");
+
+ mfc_debug_leave();
+}
+
+int s5p_mfc_otf_init(struct s5p_mfc_ctx *ctx)
+{
+ mfc_debug_enter();
+
+ if (!ctx) {
+ mfc_err_dev("[OTF] no mfc context to run\n");
+ return -EINVAL;
+ }
+
+ if (!ctx->otf_handle) {
+ mfc_err_dev("[OTF] otf_handle was not created\n");
+ return -EINVAL;
+ }
+
+ if (mfc_otf_init_hwfc_buf(ctx)) {
+ mfc_err_dev("[OTF] HWFC init failed\n");
+ return -EINVAL;
+ }
+
+ mfc_debug(2, "[OTF] otf_init is completed\n");
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+void s5p_mfc_otf_deinit(struct s5p_mfc_ctx *ctx)
+{
+ mfc_debug_enter();
+
+ if (!ctx) {
+ mfc_err_dev("[OTF] no mfc context to run\n");
+ return;
+ }
+
+ mfc_otf_deinit_hwfc_buf(ctx);
+ mfc_debug(2, "[OTF] deinit_otf is completed\n");
+
+ mfc_debug_leave();
+}
+
+int s5p_mfc_otf_ctx_ready(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct _otf_handle *handle;
+
+ mfc_debug_enter();
+
+ if (!ctx->otf_handle)
+ return 0;
+
+ handle = ctx->otf_handle;
+
+ mfc_debug(1, "[OTF] [c:%d] state = %d, otf_work_bit = %d\n",
+ ctx->num, ctx->state, handle->otf_work_bit);
+ /* If shutdown is called, do not try any cmd */
+ if (dev->shutdown)
+ return 0;
+
+ /* Context is to parse header */
+ if (ctx->state == MFCINST_GOT_INST)
+ return 1;
+
+ /* Context is to set buffers */
+ if (ctx->state == MFCINST_HEAD_PARSED)
+ return 1;
+
+ if (ctx->state == MFCINST_RUNNING && handle->otf_work_bit)
+ return 1;
+ mfc_debug(2, "[OTF] ctx is not ready\n");
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+int s5p_mfc_otf_run_enc_init(struct s5p_mfc_ctx *ctx)
+{
+ int ret;
+
+ mfc_debug_enter();
+
+ s5p_mfc_set_enc_stride(ctx);
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ ret = s5p_mfc_init_encode(ctx);
+
+ mfc_debug_leave();
+
+ return ret;
+}
+
+int s5p_mfc_otf_run_enc_frame(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct _otf_handle *handle = ctx->otf_handle;
+ struct s5p_mfc_raw_info *raw;
+
+ mfc_debug_enter();
+
+ raw = &ctx->raw_buf;
+
+ if (!handle) {
+ mfc_err_ctx("[OTF] There is no otf_handle, handle: 0x%p\n", handle);
+ return -EINVAL;
+ }
+
+ if (!handle->otf_work_bit) {
+ mfc_err_ctx("[OTF] Can't run OTF encoder, otf_work_bit: %d\n",
+ handle->otf_work_bit);
+ return -EINVAL;
+ }
+
+ if (!dev->has_hwfc) {
+ mfc_err_ctx("[OTF] HWFC register didn't mapped\n");
+ return -EINVAL;
+ }
+
+ s5p_mfc_otf_set_frame_addr(ctx, raw->num_planes);
+ s5p_mfc_otf_set_stream_size(ctx, raw->total_plane_size);
+ s5p_mfc_otf_set_hwfc_index(ctx, handle->otf_job_id);
+
+ if (call_cop(ctx, init_buf_ctrls, ctx, MFC_CTRL_TYPE_SRC, handle->otf_buf_index) < 0)
+ mfc_err_ctx("failed in init_buf_ctrls\n");
+ if (call_cop(ctx, to_buf_ctrls, ctx, &ctx->src_ctrls[handle->otf_buf_index]) < 0)
+ mfc_err_ctx("failed in to_buf_ctrls\n");
+ if (call_cop(ctx, set_buf_ctrls_val, ctx, &ctx->src_ctrls[handle->otf_buf_index]) < 0)
+ mfc_err_ctx("[OTF] failed in set_buf_ctrls_val\n");
+
+ /* Change timestamp usec -> nsec */
+ s5p_mfc_qos_update_last_framerate(ctx, handle->otf_time_stamp * 1000);
+ s5p_mfc_qos_update_framerate(ctx);
+
+ /* Set stream buffer size to handle buffer full */
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ s5p_mfc_encode_one_frame(ctx, 0);
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+int s5p_mfc_otf_handle_seq(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+
+ mfc_debug_enter();
+
+ enc->header_size = s5p_mfc_get_enc_strm_size();
+ ctx->dpb_count = s5p_mfc_get_enc_dpb_count();
+ ctx->scratch_buf_size = s5p_mfc_get_enc_scratch_size();
+ mfc_debug(2, "[OTF][STREAM] encoded slice type: %d, header size: %d, display order: %d\n",
+ s5p_mfc_get_enc_slice_type(), enc->header_size,
+ s5p_mfc_get_enc_pic_count());
+ mfc_debug(2, "[OTF] cpb_count: %d, scratch size: %zu\n",
+ ctx->dpb_count, ctx->scratch_buf_size);
+
+ s5p_mfc_change_state(ctx, MFCINST_HEAD_PARSED);
+
+ if (s5p_mfc_alloc_codec_buffers(ctx)) {
+ mfc_err_ctx("[OTF] Failed to allocate encoding buffers\n");
+ return -EINVAL;
+ }
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+int s5p_mfc_otf_handle_stream(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct _otf_handle *handle = ctx->otf_handle;
+ struct _otf_debug *debug = &handle->otf_debug;
+ struct s5p_mfc_special_buf *buf;
+ struct _otf_buf_addr *buf_addr = &handle->otf_buf_addr;
+ struct s5p_mfc_raw_info *raw;
+ dma_addr_t enc_addr[3] = { 0, 0, 0 };
+ int slice_type, i;
+ unsigned int strm_size;
+ unsigned int pic_count;
+ int enc_ret = HWFC_ERR_NONE;
+ unsigned int print_size;
+
+ mfc_debug_enter();
+
+#ifdef CONFIG_VIDEO_EXYNOS_TSMUX
+ mfc_encoding_end();
+#endif
+
+ slice_type = s5p_mfc_get_enc_slice_type();
+ pic_count = s5p_mfc_get_enc_pic_count();
+ strm_size = s5p_mfc_get_enc_strm_size();
+
+ mfc_debug(2, "[OTF][STREAM] encoded slice type: %d, size: %d, display order: %d\n",
+ slice_type, strm_size, pic_count);
+
+ /* set encoded frame type */
+ enc->frame_type = slice_type;
+ raw = &ctx->raw_buf;
+
+ if (strm_size > 0) {
+ s5p_mfc_get_enc_frame_buffer(ctx, &enc_addr[0], raw->num_planes);
+
+ for (i = 0; i < raw->num_planes; i++)
+ mfc_debug(2, "[OTF][BUFINFO] ctx[%d] get src addr[%d]: 0x%08llx\n",
+ ctx->num, i, enc_addr[i]);
+ if (enc_addr[0] != buf_addr->otf_daddr[handle->otf_buf_index][0]) {
+ mfc_err_ctx("[OTF] address is not matched. 0x%08llx != 0x%08llx\n",
+ enc_addr[0], buf_addr->otf_daddr[handle->otf_buf_index][0]);
+ enc_ret = -HWFC_ERR_MFC;
+ }
+ } else {
+ mfc_err_ctx("[OTF] stream size is zero\n");
+ enc_ret = -HWFC_ERR_MFC;
+ }
+
+ if (otf_dump && !ctx->is_drm) {
+ buf = &debug->stream_buf[debug->frame_cnt];
+ debug->stream_size[debug->frame_cnt] = strm_size;
+ debug->frame_cnt++;
+ if (debug->frame_cnt >= OTF_MAX_BUF)
+ debug->frame_cnt = 0;
+ /* print stream dump */
+ print_size = (strm_size * 2) + 64;
+
+ if (buf->vaddr)
+ print_hex_dump(KERN_ERR, "OTF dump: ",
+ DUMP_PREFIX_ADDRESS, print_size, 0,
+ buf->vaddr, print_size, false);
+ }
+
+ if (call_cop(ctx, recover_buf_ctrls_val, ctx,
+ &ctx->src_ctrls[handle->otf_buf_index]) < 0)
+ mfc_err_ctx("[OTF] failed in recover_buf_ctrls_val\n");
+ if (call_cop(ctx, cleanup_buf_ctrls, ctx,
+ MFC_CTRL_TYPE_SRC, handle->otf_buf_index) < 0)
+ mfc_err_ctx("[OTF] failed in cleanup_buf_ctrls\n");
+
+ handle->otf_work_bit = 0;
+ handle->otf_buf_index = 0;
+ handle->otf_job_id = 0;
+
+#ifdef CONFIG_VIDEO_EXYNOS_REPEATER
+ hwfc_encoding_done(enc_ret);
+#endif
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+void s5p_mfc_otf_handle_error(struct s5p_mfc_ctx *ctx,
+ unsigned int reason, unsigned int err)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct _otf_handle *handle = ctx->otf_handle;
+ int enc_ret = -HWFC_ERR_MFC;
+
+ mfc_debug_enter();
+
+ mfc_err_ctx("[OTF] Interrupt Error: display: %d, decoded: %d\n",
+ s5p_mfc_get_warn(err), s5p_mfc_get_err(err));
+ err = s5p_mfc_get_err(err);
+
+ /* Error recovery is dependent on the state of context */
+ switch (ctx->state) {
+ case MFCINST_GOT_INST:
+ case MFCINST_INIT:
+ case MFCINST_RETURN_INST:
+ case MFCINST_HEAD_PARSED:
+ mfc_err_ctx("[OTF] error happened during init/de-init\n");
+ break;
+ case MFCINST_RUNNING:
+ if (err == S5P_FIMV_ERR_MFC_TIMEOUT) {
+ mfc_err_ctx("[OTF] MFC TIMEOUT. go to error state\n");
+ s5p_mfc_change_state(ctx, MFCINST_ERROR);
+ enc_ret = -HWFC_ERR_MFC_TIMEOUT;
+ } else if (err == S5P_FIMV_ERR_TS_MUX_TIMEOUT ||
+ err == S5P_FIMV_ERR_G2D_TIMEOUT) {
+ mfc_err_ctx("[OTF] TS-MUX or G2D TIMEOUT. skip this frame\n");
+ enc_ret = -HWFC_ERR_MFC_TIMEOUT;
+ } else {
+ mfc_err_ctx("[OTF] MFC ERROR. skip this frame\n");
+ enc_ret = -HWFC_ERR_MFC;
+ }
+
+ handle->otf_work_bit = 0;
+ handle->otf_buf_index = 0;
+ handle->otf_job_id = 0;
+
+ if (call_cop(ctx, recover_buf_ctrls_val, ctx,
+ &ctx->src_ctrls[handle->otf_buf_index]) < 0)
+ mfc_err_ctx("[OTF] failed in recover_buf_ctrls_val\n");
+ if (call_cop(ctx, cleanup_buf_ctrls, ctx,
+ MFC_CTRL_TYPE_SRC, handle->otf_buf_index) < 0)
+ mfc_err_ctx("[OTF] failed in cleanup_buf_ctrls\n");
+
+#ifdef CONFIG_VIDEO_EXYNOS_REPEATER
+ hwfc_encoding_done(enc_ret);
+#endif
+ break;
+ default:
+ mfc_err_ctx("Encountered an error interrupt which had not been handled\n");
+ mfc_err_ctx("ctx->state = %d, ctx->inst_no = %d\n",
+ ctx->state, ctx->inst_no);
+ break;
+ }
+
+ s5p_mfc_wake_up_dev(dev, reason, err);
+
+ mfc_debug_leave();
+}
+
+int mfc_hwfc_check_run(struct s5p_mfc_ctx *ctx)
+{
+ struct _otf_handle *handle = ctx->otf_handle;
+
+ mfc_debug_enter();
+
+ if (!handle) {
+ mfc_err_ctx("[OTF] there is no handle for OTF\n");
+ return -EINVAL;
+ }
+ if (handle->otf_work_bit) {
+ mfc_err_ctx("[OTF] OTF is already working\n");
+ return -EINVAL;
+ }
+ if (ctx->state != MFCINST_RUNNING) {
+ mfc_err_ctx("[OTF] mfc is not running state\n");
+ return -EINVAL;
+ }
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+int s5p_mfc_hwfc_encode(int buf_index, int job_id, struct encoding_param *param)
+{
+ struct s5p_mfc_dev *dev = g_mfc_dev;
+ struct _otf_handle *handle;
+ struct s5p_mfc_ctx *ctx = NULL;
+#ifdef CONFIG_VIDEO_EXYNOS_TSMUX
+ struct packetizing_param packet_param;
+#endif
+ int i;
+
+ mfc_debug_enter();
+
+#ifdef CONFIG_VIDEO_EXYNOS_TSMUX
+ mfc_encoding_start(buf_index);
+#endif
+
+ for (i = 0; i < MFC_NUM_CONTEXTS; i++) {
+ if (dev->ctx[i] && dev->ctx[i]->otf_handle) {
+ ctx = dev->ctx[i];
+ break;
+ }
+ }
+
+ if (!ctx) {
+ mfc_err_dev("[OTF] there is no context to run\n");
+ return -HWFC_ERR_MFC_NOT_PREPARED;
+ }
+
+ if (mfc_hwfc_check_run(ctx)) {
+ mfc_err_dev("[OTF] mfc is not prepared\n");
+ return -HWFC_ERR_MFC_NOT_PREPARED;
+ }
+
+#ifdef CONFIG_VIDEO_EXYNOS_TSMUX
+ packet_param.time_stamp = param->time_stamp;
+ if (debug_ts == 1)
+ mfc_info_ctx("[OTF][TS] timestamp: %llu\n", param->time_stamp);
+ if (packetize(&packet_param)) {
+ mfc_err_dev("[OTF] packetize failed\n");
+ return -HWFC_ERR_TSMUX;
+ }
+#endif
+
+ handle = ctx->otf_handle;
+ handle->otf_work_bit = 1;
+ handle->otf_buf_index = buf_index;
+ handle->otf_job_id = job_id;
+ handle->otf_time_stamp = param->time_stamp;
+
+ if (s5p_mfc_otf_ctx_ready(ctx))
+ s5p_mfc_set_bit(ctx->num, &dev->work_bits);
+ if (s5p_mfc_is_work_to_do(dev))
+ queue_work(dev->butler_wq, &dev->butler_work);
+
+ mfc_debug_leave();
+
+ return HWFC_ERR_NONE;
+}
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_otf.h
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __MFC_OTF_H
+#define __MFC_OTF_H __FILE__
+
+#include "mfc_common.h"
+
+extern struct s5p_mfc_dev *g_mfc_dev;
+
+int s5p_mfc_otf_create(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_otf_destroy(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_otf_init(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_otf_deinit(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_otf_ctx_ready(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_otf_run_enc_init(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_otf_run_enc_frame(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_otf_handle_seq(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_otf_handle_stream(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_otf_handle_error(struct s5p_mfc_ctx *ctx, unsigned int reason, unsigned int err);
+
+#endif /* __MFC_OTF_H */
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_perf_measure.c
+ *
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "mfc_perf_measure.h"
+
+#ifndef PERF_MEASURE
+
+void s5p_mfc_perf_register(struct s5p_mfc_dev *dev) {}
+void mfc_measure_init(void) {}
+void mfc_measure_on(struct s5p_mfc_dev *dev) {}
+void mfc_measure_off(struct s5p_mfc_dev *dev) {}
+void mfc_measure_store(struct s5p_mfc_dev *dev, int diff) {}
+void s5p_mfc_perf_print(void) {}
+
+#else
+
+#endif
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_perf_measure.h
+ *
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __MFC_PERF_MEASURE_H
+#define __MFC_PERF_MEASURE_H __FILE__
+
+#include <linux/clk.h>
+
+#include "mfc_reg.h"
+
+void s5p_mfc_perf_register(struct s5p_mfc_dev *dev);
+void mfc_measure_init(void);
+void mfc_measure_on(struct s5p_mfc_dev *dev);
+void mfc_measure_off(struct s5p_mfc_dev *dev);
+void mfc_measure_store(struct s5p_mfc_dev *dev, int diff);
+void s5p_mfc_perf_print(void);
+
+//#define PERF_MEASURE
+
+#ifndef PERF_MEASURE
+
+static inline void s5p_mfc_perf_init(struct s5p_mfc_dev *dev) {}
+static inline void s5p_mfc_perf_cancel_drv_margin(struct s5p_mfc_dev *dev) {}
+static inline void s5p_mfc_perf_measure_on(struct s5p_mfc_dev *dev) {}
+static inline void s5p_mfc_perf_measure_off(struct s5p_mfc_dev *dev) {}
+
+#else
+
+extern unsigned int perf_measure_option;
+
+static inline void s5p_mfc_perf_init(struct s5p_mfc_dev *dev)
+{
+ dev->perf.new_start = 0;
+ dev->perf.count = 0;
+ dev->perf.drv_margin = 0;
+
+ mfc_measure_init();
+
+ mfc_info_dev("MFC frequency : %ld\n", clk_get_rate(dev->pm.clock));
+}
+
+static inline void s5p_mfc_perf_cancel_drv_margin(struct s5p_mfc_dev *dev)
+{
+ dev->perf.drv_margin = 0;
+}
+
+static inline void s5p_mfc_perf_measure_on(struct s5p_mfc_dev *dev)
+{
+ int diff;
+
+ if (dev->perf.drv_margin) {
+ do_gettimeofday(&dev->perf.end);
+
+ diff = (dev->perf.end.tv_sec * 1000000 + dev->perf.end.tv_usec)
+ - (dev->perf.begin.tv_sec * 1000000 + dev->perf.begin.tv_usec);
+
+ mfc_info_dev("IRQ -> NAL_START time(ms) = %03d.%03d\n", diff / 1000, diff % 1000);
+
+ dev->perf.drv_margin = 0;
+ }
+
+ do_gettimeofday(&dev->perf.begin);
+
+ mfc_measure_on(dev);
+
+ dev->perf.new_start = 1;
+ dev->perf.count++;
+}
+
+static inline void s5p_mfc_perf_measure_off(struct s5p_mfc_dev *dev)
+{
+ unsigned int diff;
+
+ if ((dev->perf.new_start) && (dev->perf.count > 0)) {
+ mfc_measure_off(dev);
+
+ do_gettimeofday(&dev->perf.end);
+
+ diff = (dev->perf.end.tv_sec * 1000000 + dev->perf.end.tv_usec)
+ - (dev->perf.begin.tv_sec * 1000000 + dev->perf.begin.tv_usec);
+
+ mfc_measure_store(dev, diff);
+
+ mfc_debug(3, "uDECtype :%d, uENCtype :%d, codectype :%d\n",
+ s5p_mfc_get_dec_frame_type(), s5p_mfc_get_enc_slice_type(), MFC_READL(S5P_FIMV_CODEC_TYPE));
+
+ dev->perf.drv_margin = 1;
+
+ do_gettimeofday(&dev->perf.begin);
+ }
+
+ dev->perf.new_start = 0;
+}
+
+#endif
+
+#endif /* __MFC_PERF_MEASURE_H */
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_pm.c
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+#include <linux/smc.h>
+
+#include "mfc_pm.h"
+
+#include "mfc_cal.h"
+#include "mfc_reg.h"
+
+void s5p_mfc_pm_init(struct s5p_mfc_dev *dev)
+{
+ spin_lock_init(&dev->pm.clklock);
+ atomic_set(&dev->pm.pwr_ref, 0);
+ atomic_set(&dev->clk_ref, 0);
+
+ dev->pm.device = dev->device;
+ dev->pm.clock_on_steps = 0;
+ dev->pm.clock_off_steps = 0;
+ pm_runtime_enable(dev->pm.device);
+}
+
+void s5p_mfc_pm_final(struct s5p_mfc_dev *dev)
+{
+ pm_runtime_disable(dev->pm.device);
+}
+
+int s5p_mfc_pm_clock_on(struct s5p_mfc_dev *dev)
+{
+ int ret = 0;
+ int state;
+
+ dev->pm.clock_on_steps = 1;
+ state = atomic_read(&dev->clk_ref);
+
+ MFC_TRACE_DEV("** clock_on start: ref state(%d)\n", state);
+ ret = clk_enable(dev->pm.clock);
+ if (ret < 0) {
+ mfc_err_dev("clk_enable failed (%d)\n", ret);
+ call_dop(dev, dump_and_stop_debug_mode, dev);
+ return ret;
+ }
+ dev->pm.clock_on_steps |= 0x1 << 1;
+
+ if (dev->pm.base_type != MFCBUF_INVALID)
+ s5p_mfc_set_risc_base_addr(dev, dev->pm.base_type);
+
+ dev->pm.clock_on_steps |= 0x1 << 2;
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+ if (dev->curr_ctx_is_drm) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->pm.clklock, flags);
+ mfc_debug(3, "Begin: enable protection\n");
+ ret = exynos_smc(SMC_PROTECTION_SET, 0,
+ dev->id, SMC_PROTECTION_ENABLE);
+ dev->pm.clock_on_steps |= 0x1 << 3;
+ if (ret != DRMDRV_OK) {
+ mfc_err_dev("Protection Enable failed! ret(%u)\n", ret);
+ call_dop(dev, dump_and_stop_debug_mode, dev);
+ spin_unlock_irqrestore(&dev->pm.clklock, flags);
+ clk_disable(dev->pm.clock);
+ return -EACCES;
+ }
+ mfc_debug(3, "End: enable protection\n");
+ spin_unlock_irqrestore(&dev->pm.clklock, flags);
+ }
+#endif
+ dev->pm.clock_on_steps |= 0x1 << 4;
+ atomic_inc_return(&dev->clk_ref);
+
+ dev->pm.clock_on_steps |= 0x1 << 6;
+ state = atomic_read(&dev->clk_ref);
+ mfc_debug(2, "+ %d\n", state);
+ MFC_TRACE_DEV("** clock_on end: ref state(%d)\n", state);
+
+ return 0;
+}
+
+/* Use only in functions that first instance is guaranteed, like mfc_init_hw() */
+int s5p_mfc_pm_clock_on_with_base(struct s5p_mfc_dev *dev,
+ enum mfc_buf_usage_type buf_type)
+{
+ int ret;
+ dev->pm.base_type = buf_type;
+ ret = s5p_mfc_pm_clock_on(dev);
+ dev->pm.base_type = MFCBUF_INVALID;
+
+ return ret;
+}
+
+void s5p_mfc_pm_clock_off(struct s5p_mfc_dev *dev)
+{
+ int state;
+
+ dev->pm.clock_off_steps = 1;
+ atomic_dec_return(&dev->clk_ref);
+
+ dev->pm.clock_off_steps |= 0x1 << 1;
+ state = atomic_read(&dev->clk_ref);
+ MFC_TRACE_DEV("** clock_off start: ref state(%d)\n", state);
+ if (state < 0) {
+ mfc_err_dev("Clock state is wrong(%d)\n", state);
+ atomic_set(&dev->clk_ref, 0);
+ dev->pm.clock_off_steps |= 0x1 << 2;
+ } else {
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+ if (dev->curr_ctx_is_drm) {
+ unsigned long flags;
+ int ret = 0;
+
+ mfc_debug(3, "Begin: disable protection\n");
+ spin_lock_irqsave(&dev->pm.clklock, flags);
+ dev->pm.clock_off_steps |= 0x1 << 3;
+ ret = exynos_smc(SMC_PROTECTION_SET, 0,
+ dev->id, SMC_PROTECTION_DISABLE);
+ if (ret != DRMDRV_OK) {
+ mfc_err_dev("Protection Disable failed! ret(%u)\n", ret);
+ call_dop(dev, dump_and_stop_debug_mode, dev);
+ spin_unlock_irqrestore(&dev->pm.clklock, flags);
+ clk_disable(dev->pm.clock);
+ return;
+ }
+ mfc_debug(3, "End: disable protection\n");
+ dev->pm.clock_off_steps |= 0x1 << 4;
+ spin_unlock_irqrestore(&dev->pm.clklock, flags);
+ }
+#endif
+ dev->pm.clock_off_steps |= 0x1 << 5;
+ clk_disable(dev->pm.clock);
+ }
+
+ dev->pm.clock_off_steps |= 0x1 << 6;
+ state = atomic_read(&dev->clk_ref);
+ mfc_debug(2, "- %d\n", state);
+ MFC_TRACE_DEV("** clock_off end: ref state(%d)\n", state);
+}
+
+int s5p_mfc_pm_power_on(struct s5p_mfc_dev *dev)
+{
+ int ret;
+
+ MFC_TRACE_DEV("++ Power on\n");
+ ret = pm_runtime_get_sync(dev->pm.device);
+ if (ret < 0) {
+ mfc_err_dev("Failed to get power: ret(%d)\n", ret);
+ call_dop(dev, dump_and_stop_debug_mode, dev);
+ goto err_power_on;
+ }
+
+ dev->pm.clock = clk_get(dev->device, "aclk_mfc");
+ if (IS_ERR(dev->pm.clock)) {
+ mfc_err_dev("failed to get parent clock: ret(%d)\n", ret);
+ ret = -ENOENT;
+ goto err_clk_get;
+ }
+
+ ret = clk_prepare(dev->pm.clock);
+ if (ret) {
+ mfc_err_dev("clk_prepare() failed: ret(%d)\n", ret);
+ goto err_clk_prepare;
+ }
+
+ atomic_inc(&dev->pm.pwr_ref);
+
+ MFC_TRACE_DEV("-- Power on: ret(%d)\n", ret);
+
+ return 0;
+
+err_clk_prepare:
+ clk_put(dev->pm.clock);
+
+err_clk_get:
+ pm_runtime_put_sync(dev->pm.device);
+
+err_power_on:
+ return ret;
+}
+
+int s5p_mfc_pm_power_off(struct s5p_mfc_dev *dev)
+{
+ int ret;
+
+ MFC_TRACE_DEV("++ Power off\n");
+
+ clk_unprepare(dev->pm.clock);
+ clk_put(dev->pm.clock);
+
+ ret = pm_runtime_put_sync(dev->pm.device);
+ if (ret < 0) {
+ mfc_err_dev("Failed to put power: ret(%d)\n", ret);
+ call_dop(dev, dump_and_stop_debug_mode, dev);
+ return ret;
+ }
+
+ atomic_dec(&dev->pm.pwr_ref);
+
+ MFC_TRACE_DEV("-- Power off: ret(%d)\n", ret);
+
+ return ret;
+}
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_pm.h
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __MFC_PM_H
+#define __MFC_PM_H __FILE__
+
+#include "mfc_common.h"
+
+static inline int s5p_mfc_pm_get_pwr_ref_cnt(struct s5p_mfc_dev *dev)
+{
+ return atomic_read(&dev->pm.pwr_ref);
+}
+
+static inline int s5p_mfc_pm_get_clk_ref_cnt(struct s5p_mfc_dev *dev)
+{
+ return atomic_read(&dev->clk_ref);
+}
+
+void s5p_mfc_pm_init(struct s5p_mfc_dev *dev);
+void s5p_mfc_pm_final(struct s5p_mfc_dev *dev);
+
+int s5p_mfc_pm_clock_on(struct s5p_mfc_dev *dev);
+int s5p_mfc_pm_clock_on_with_base(struct s5p_mfc_dev *dev,
+ enum mfc_buf_usage_type buf_type);
+void s5p_mfc_pm_clock_off(struct s5p_mfc_dev *dev);
+int s5p_mfc_pm_power_on(struct s5p_mfc_dev *dev);
+int s5p_mfc_pm_power_off(struct s5p_mfc_dev *dev);
+
+#endif /* __MFC_PM_H */
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_qos.c
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/err.h>
+#ifdef CONFIG_EXYNOS_BTS
+#include <soc/samsung/bts.h>
+#endif
+
+#include "mfc_qos.h"
+
+#ifdef CONFIG_MFC_USE_BUS_DEVFREQ
+enum {
+ MFC_QOS_ADD,
+ MFC_QOS_UPDATE,
+ MFC_QOS_REMOVE,
+ MFC_QOS_BW,
+};
+
+enum {
+ MFC_PERF_BOOST_DVFS = (1 << 0),
+ MFC_PERF_BOOST_MO = (1 << 1),
+ MFC_PERF_BOOST_CPU = (1 << 2),
+};
+
+void s5p_mfc_perf_boost_enable(struct s5p_mfc_dev *dev)
+{
+ struct s5p_mfc_platdata *pdata = dev->pdata;
+ struct s5p_mfc_qos_boost *qos_boost_table = pdata->qos_boost_table;
+ int i;
+
+ if (perf_boost_mode & MFC_PERF_BOOST_DVFS) {
+ if (pdata->mfc_freq_control)
+ pm_qos_add_request(&dev->qos_req_mfc, PM_QOS_MFC_THROUGHPUT,
+ qos_boost_table->freq_mfc);
+ pm_qos_add_request(&dev->qos_req_int, PM_QOS_DEVICE_THROUGHPUT,
+ qos_boost_table->freq_int);
+ pm_qos_add_request(&dev->qos_req_mif, PM_QOS_BUS_THROUGHPUT,
+ qos_boost_table->freq_mif);
+ mfc_debug(3, "[QoS][BOOST] DVFS mfc: %d, int:%d, mif:%d\n",
+ qos_boost_table->freq_mfc, qos_boost_table->freq_int,
+ qos_boost_table->freq_mif);
+ }
+
+#ifdef CONFIG_EXYNOS_BTS
+ if (perf_boost_mode & MFC_PERF_BOOST_MO) {
+ if (pdata->mo_control) {
+ bts_update_scen(BS_MFC_UHD_10BIT, 1);
+ mfc_debug(3, "[QoS][BOOST] BTS(MO): UHD_10BIT\n");
+ }
+ }
+#endif
+
+ if (perf_boost_mode & MFC_PERF_BOOST_CPU) {
+ for (i = 0; i < qos_boost_table->num_cluster; i++) {
+ pm_qos_add_request(&dev->qos_req_cluster[i], PM_QOS_CLUSTER0_FREQ_MIN + (i * 2),
+ qos_boost_table->freq_cluster[i]);
+ mfc_debug(3, "[QoS][BOOST] CPU cluster[%d]: %d\n",
+ i, qos_boost_table->freq_cluster[i]);
+ }
+ }
+}
+
+void s5p_mfc_perf_boost_disable(struct s5p_mfc_dev *dev)
+{
+ struct s5p_mfc_platdata *pdata = dev->pdata;
+ int i;
+
+ if (perf_boost_mode & MFC_PERF_BOOST_DVFS) {
+ if (pdata->mfc_freq_control)
+ pm_qos_remove_request(&dev->qos_req_mfc);
+ pm_qos_remove_request(&dev->qos_req_int);
+ pm_qos_remove_request(&dev->qos_req_mif);
+ mfc_debug(3, "[QoS][BOOST] DVFS off\n");
+ }
+
+#ifdef CONFIG_EXYNOS_BTS
+ if (perf_boost_mode & MFC_PERF_BOOST_MO) {
+ if (pdata->mo_control) {
+ bts_update_scen(BS_MFC_UHD_10BIT, 0);
+ mfc_debug(3, "[QoS][BOOST] BTS(MO) off\n");
+ }
+ }
+#endif
+
+ if (perf_boost_mode & MFC_PERF_BOOST_CPU) {
+ for (i = 0; i < pdata->qos_boost_table->num_cluster; i++) {
+ pm_qos_remove_request(&dev->qos_req_cluster[i]);
+ mfc_debug(3, "[QoS][BOOST] CPU cluster[%d] off\n", i);
+ }
+ }
+}
+
+static void mfc_qos_operate(struct s5p_mfc_ctx *ctx, int opr_type, int idx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_platdata *pdata = dev->pdata;
+ struct s5p_mfc_qos *qos_table = pdata->qos_table;
+
+ switch (opr_type) {
+ case MFC_QOS_ADD:
+ if (pdata->mfc_freq_control)
+ pm_qos_add_request(&dev->qos_req_mfc,
+ PM_QOS_MFC_THROUGHPUT,
+ qos_table[idx].freq_mfc);
+ pm_qos_add_request(&dev->qos_req_int,
+ PM_QOS_DEVICE_THROUGHPUT,
+ qos_table[idx].freq_int);
+ pm_qos_add_request(&dev->qos_req_mif,
+ PM_QOS_BUS_THROUGHPUT,
+ qos_table[idx].freq_mif);
+
+#ifdef CONFIG_EXYNOS_BTS
+ if (pdata->mo_control) {
+ bts_update_scen(BS_MFC_UHD_ENC60, qos_table[idx].mo_uhd_enc60_value);
+ bts_update_scen(BS_MFC_UHD_10BIT, qos_table[idx].mo_10bit_value);
+ bts_update_scen(BS_MFC_UHD, qos_table[idx].mo_value);
+ MFC_TRACE_CTX("BTS(MO) update - uhd:%d, uhd_10bit:%d, uhd_enc60:%d\n",
+ qos_table[idx].mo_value, qos_table[idx].mo_10bit_value,
+ qos_table[idx].mo_uhd_enc60_value);
+ mfc_debug(2, "[QoS] BTS(MO) update - uhd:%d, uhd_10bit:%d, uhd_enc60:%d\n",
+ qos_table[idx].mo_value, qos_table[idx].mo_10bit_value,
+ qos_table[idx].mo_uhd_enc60_value);
+ }
+#endif
+
+ atomic_set(&dev->qos_req_cur, idx + 1);
+ MFC_TRACE_CTX("QoS add[%d] - mfc:%d(%s), int:%d, mif:%d\n",
+ idx, qos_table[idx].freq_mfc, pdata->mfc_freq_control ? "used" : "un-used",
+ qos_table[idx].freq_int, qos_table[idx].freq_mif);
+ mfc_debug(2, "[QoS] QoS add[%d] - mfc:%d(%s), int:%d, mif:%d\n",
+ idx, qos_table[idx].freq_mfc, pdata->mfc_freq_control ? "used" : "un-used",
+ qos_table[idx].freq_int, qos_table[idx].freq_mif);
+ break;
+ case MFC_QOS_UPDATE:
+ if (pdata->mfc_freq_control)
+ pm_qos_update_request(&dev->qos_req_mfc,
+ qos_table[idx].freq_mfc);
+ pm_qos_update_request(&dev->qos_req_int,
+ qos_table[idx].freq_int);
+ pm_qos_update_request(&dev->qos_req_mif,
+ qos_table[idx].freq_mif);
+
+#ifdef CONFIG_EXYNOS_BTS
+ if (pdata->mo_control) {
+ bts_update_scen(BS_MFC_UHD_ENC60, qos_table[idx].mo_uhd_enc60_value);
+ bts_update_scen(BS_MFC_UHD_10BIT, qos_table[idx].mo_10bit_value);
+ bts_update_scen(BS_MFC_UHD, qos_table[idx].mo_value);
+ MFC_TRACE_CTX("BTS(MO) update - uhd:%d, uhd_10bit:%d, uhd_enc60:%d\n",
+ qos_table[idx].mo_value, qos_table[idx].mo_10bit_value,
+ qos_table[idx].mo_uhd_enc60_value);
+ mfc_debug(2, "[QoS] BTS(MO) update - uhd:%d, uhd_10bit:%d, uhd_enc60:%d\n",
+ qos_table[idx].mo_value, qos_table[idx].mo_10bit_value,
+ qos_table[idx].mo_uhd_enc60_value);
+ }
+#endif
+
+ atomic_set(&dev->qos_req_cur, idx + 1);
+ MFC_TRACE_CTX("QoS update[%d] - mfc:%d(%s), int:%d, mif:%d\n",
+ idx, qos_table[idx].freq_mfc, pdata->mfc_freq_control ? "used" : "un-used",
+ qos_table[idx].freq_int, qos_table[idx].freq_mif);
+ mfc_debug(2, "[QoS] QoS update[%d] - mfc:%d(%s), int:%d, mif:%d\n",
+ idx, qos_table[idx].freq_mfc, pdata->mfc_freq_control ? "used" : "un-used",
+ qos_table[idx].freq_int, qos_table[idx].freq_mif);
+ break;
+ case MFC_QOS_REMOVE:
+ if (pdata->mfc_freq_control)
+ pm_qos_remove_request(&dev->qos_req_mfc);
+ pm_qos_remove_request(&dev->qos_req_int);
+ pm_qos_remove_request(&dev->qos_req_mif);
+
+#ifdef CONFIG_EXYNOS_BTS
+ if (pdata->mo_control) {
+ bts_update_scen(BS_MFC_UHD_ENC60, 0);
+ bts_update_scen(BS_MFC_UHD_10BIT, 0);
+ bts_update_scen(BS_MFC_UHD, 0);
+ }
+
+ if (pdata->bw_control) {
+ dev->mfc_bw.peak = 0;
+ dev->mfc_bw.read = 0;
+ dev->mfc_bw.write = 0;
+ bts_update_bw(BTS_BW_MFC, dev->mfc_bw);
+ }
+#endif
+
+ atomic_set(&dev->qos_req_cur, 0);
+ MFC_TRACE_CTX("QoS remove\n");
+ mfc_debug(2, "[QoS] QoS remove\n");
+ break;
+ case MFC_QOS_BW:
+#ifdef CONFIG_EXYNOS_BTS
+ if (pdata->bw_control) {
+ bts_update_bw(BTS_BW_MFC, dev->mfc_bw);
+ MFC_TRACE_CTX("BTS(BW) update (peak: %d, read: %d, write: %d)\n",
+ dev->mfc_bw.peak, dev->mfc_bw.read, dev->mfc_bw.write);
+ mfc_debug(2, "[QoS] BTS(BW) update (peak: %d, read: %d, write: %d)\n",
+ dev->mfc_bw.peak, dev->mfc_bw.read, dev->mfc_bw.write);
+ }
+#endif
+ break;
+ default:
+ mfc_err_ctx("[QoS] Unknown request for opr [%d]\n", opr_type);
+ break;
+ }
+}
+
+#ifdef CONFIG_EXYNOS_BTS
+static void mfc_qos_set(struct s5p_mfc_ctx *ctx, struct bts_bw *mfc_bw, int i)
+#else
+static void mfc_qos_set(struct s5p_mfc_ctx *ctx, int i)
+#endif
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_platdata *pdata = dev->pdata;
+ struct s5p_mfc_qos *qos_table = pdata->qos_table;
+
+ mfc_debug(2, "[QoS] table[%d] covered mb %d ~ %d (mfc: %d, int:%d, mif:%d)\n",
+ i, qos_table[i].threshold_mb,
+ i == pdata->num_qos_steps - 1 ?
+ pdata->max_mb : qos_table[i + 1].threshold_mb,
+ qos_table[i].freq_mfc, qos_table[i].freq_int,
+ qos_table[i].freq_mif);
+
+#ifdef CONFIG_EXYNOS_BTS
+ if (mfc_bw->peak != dev->mfc_bw.peak) {
+ dev->mfc_bw.peak = mfc_bw->peak;
+ dev->mfc_bw.read = mfc_bw->read;
+ dev->mfc_bw.write = mfc_bw->write;
+ mfc_qos_operate(ctx, MFC_QOS_BW, i);
+ }
+#endif
+
+ if (atomic_read(&dev->qos_req_cur) == 0)
+ mfc_qos_operate(ctx, MFC_QOS_ADD, i);
+ else if (atomic_read(&dev->qos_req_cur) != (i + 1))
+ mfc_qos_operate(ctx, MFC_QOS_UPDATE, i);
+}
+
+static inline unsigned long mfc_qos_get_weighted_mb(struct s5p_mfc_ctx *ctx,
+ unsigned long mb)
+{
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ struct s5p_mfc_enc_params *p;
+ u32 num_planes = ctx->dst_fmt->num_planes;
+ int weight = 1000;
+ unsigned long weighted_mb;
+
+ switch (ctx->codec_mode) {
+ case S5P_FIMV_CODEC_H264_DEC:
+ case S5P_FIMV_CODEC_H264_MVC_DEC:
+ case S5P_FIMV_CODEC_H264_ENC:
+ case S5P_FIMV_CODEC_H264_MVC_ENC:
+ case S5P_FIMV_CODEC_VP8_DEC:
+ case S5P_FIMV_CODEC_VP8_ENC:
+ if (num_planes == 3)
+ weight = (weight * 100) / MFC_QOS_WEIGHT_3PLANE;
+ break;
+
+ case S5P_FIMV_CODEC_HEVC_DEC:
+ case S5P_FIMV_CODEC_HEVC_ENC:
+ case S5P_FIMV_CODEC_VP9_DEC:
+ case S5P_FIMV_CODEC_VP9_ENC:
+ case S5P_FIMV_CODEC_BPG_DEC:
+ case S5P_FIMV_CODEC_BPG_ENC:
+ if (num_planes == 3) {
+ weight = (weight * 100) / MFC_QOS_WEIGHT_3PLANE;
+ } else {
+ if (ctx->is_10bit)
+ weight = (weight * 100) / MFC_QOS_WEIGHT_10BIT;
+ else if (ctx->is_422)
+ weight = (weight * 100) / MFC_QOS_WEIGHT_422_10INTRA;
+ }
+ break;
+
+ case S5P_FIMV_CODEC_MPEG4_DEC:
+ case S5P_FIMV_CODEC_FIMV1_DEC:
+ case S5P_FIMV_CODEC_FIMV2_DEC:
+ case S5P_FIMV_CODEC_FIMV3_DEC:
+ case S5P_FIMV_CODEC_FIMV4_DEC:
+ case S5P_FIMV_CODEC_H263_DEC:
+ case S5P_FIMV_CODEC_VC1_RCV_DEC:
+ case S5P_FIMV_CODEC_VC1_DEC:
+ case S5P_FIMV_CODEC_MPEG2_DEC:
+ case S5P_FIMV_CODEC_MPEG4_ENC:
+ case S5P_FIMV_CODEC_H263_ENC:
+ weight = (weight * 100) / MFC_QOS_WEIGHT_OTHER_CODEC;
+ break;
+
+ default:
+ mfc_err_ctx("[QoS] wrong codec_mode (%d), no weight\n", ctx->codec_mode);
+ }
+
+ if (enc) {
+ p = &enc->params;
+ if ((IS_H264_ENC(ctx) || IS_HEVC_ENC(ctx)) && p->num_b_frame) {
+ weight = (weight * 100) / MFC_QOS_WEIGHT_BFRAME;
+ mfc_debug(3, "[QoS] weight: B frame encoding\n");
+ }
+ if ((IS_H264_ENC(ctx) || IS_HEVC_ENC(ctx) || IS_VP8_ENC(ctx) ||
+ IS_VP9_ENC(ctx)) && (p->num_refs_for_p >= 2)) {
+ weight = (weight * 100) / MFC_QOS_WEIGHT_NUM_OF_REF;
+ mfc_debug(3, "[QoS] weight: num of ref >= 2\n");
+ }
+ }
+ if (dec) {
+ if (dec->num_of_tile_over_4) {
+ weight = (weight * 100) / MFC_QOS_WEIGHT_NUM_OF_TILE;
+ mfc_debug(3, "[QoS] weight: num of tile >= 4\n");
+ }
+ }
+
+ weighted_mb = (mb * weight) / 1000;
+ mfc_debug(3, "[QoS] weight: %d.%03d, codec: %d, num planes: %d, "
+ "10bit: %d, 422format: %d (mb: %ld)\n",
+ weight / 1000, weight % 1000, ctx->codec_mode,
+ num_planes, ctx->is_10bit, ctx->is_422,
+ weighted_mb);
+
+
+ return weighted_mb;
+}
+
+static inline unsigned long mfc_qos_get_mb_per_second(struct s5p_mfc_ctx *ctx)
+{
+ unsigned long mb_width, mb_height, fps, mb;
+
+ mb_width = (ctx->crop_width + 15) / 16;
+ mb_height = (ctx->crop_height + 15) / 16;
+ fps = ctx->framerate / 1000;
+
+ mb = mb_width * mb_height * fps;
+ mfc_debug(4, "[QoS] ctx[%d:%s] %d x %d @ %ld fps (mb: %ld)\n",
+ ctx->num, ctx->type == MFCINST_ENCODER ? "ENC" : "DEC",
+ ctx->crop_width, ctx->crop_height, fps, mb);
+
+ return mfc_qos_get_weighted_mb(ctx, mb);
+}
+
+#ifdef CONFIG_EXYNOS_BTS
+static struct s5p_mfc_qos_bw mfc_bw_info = {
+ /* peak read write (KB/UHD frame) */
+ .h264_dec_uhd_bw = { 38131, 40206, 24870 },
+ .hevc_dec_uhd_bw = { 35055, 33741, 20511 },
+ .hevc_dec_uhd_10bit_bw = { 38643, 36428, 25491 },
+ .vp8_dec_uhd_bw = { 28693, 30464, 22331 },
+ .vp9_dec_uhd_bw = { 21464, 22160, 19747 },
+ .mpeg4_dec_uhd_bw = { 31567, 25191, 15961 },
+ .h264_enc_uhd_bw = { 62543, 75230, 13080 },
+ .hevc_enc_uhd_bw = { 54863, 65417, 11422 },
+ .hevc_enc_uhd_10bit_bw = { 68011, 79367, 14688 },
+ .vp8_enc_uhd_bw = { 63970, 67281, 22508 },
+ .vp9_enc_uhd_bw = { 84443, 71588, 19337 },
+ .mpeg4_enc_uhd_bw = { 44633, 55310, 9599 },
+};
+
+static void mfc_qos_get_bw_per_second(struct s5p_mfc_ctx *ctx, struct bts_bw *mfc_bw)
+{
+ struct mfc_qos_bw_data bw_data;
+ unsigned long mb_width, mb_height, fps, mb;
+ unsigned long peak_bw_per_sec;
+ unsigned long read_bw_per_sec;
+ unsigned long write_bw_per_sec;
+ unsigned long mb_count_per_uhd_frame = MB_COUNT_PER_UHD_FRAME;
+ unsigned long max_fps_per_uhd_frame = MAX_FPS_PER_UHD_FRAME;
+
+ mb_width = (ctx->crop_width + 15) / 16;
+ mb_height = (ctx->crop_height + 15) / 16;
+ fps = ctx->framerate / 1000;
+
+ mb = mb_width * mb_height * fps;
+
+ switch (ctx->codec_mode) {
+ case S5P_FIMV_CODEC_H264_DEC:
+ case S5P_FIMV_CODEC_H264_MVC_DEC:
+ bw_data = mfc_bw_info.h264_dec_uhd_bw;
+ break;
+ case S5P_FIMV_CODEC_H264_ENC:
+ case S5P_FIMV_CODEC_H264_MVC_ENC:
+ bw_data = mfc_bw_info.h264_enc_uhd_bw;
+ break;
+ case S5P_FIMV_CODEC_HEVC_DEC:
+ case S5P_FIMV_CODEC_BPG_DEC:
+ if (ctx->is_10bit)
+ bw_data = mfc_bw_info.hevc_dec_uhd_10bit_bw;
+ else
+ bw_data = mfc_bw_info.hevc_dec_uhd_bw;
+ break;
+ case S5P_FIMV_CODEC_HEVC_ENC:
+ case S5P_FIMV_CODEC_BPG_ENC:
+ if (ctx->is_10bit)
+ bw_data = mfc_bw_info.hevc_enc_uhd_10bit_bw;
+ else
+ bw_data = mfc_bw_info.hevc_enc_uhd_bw;
+ break;
+ case S5P_FIMV_CODEC_MPEG4_DEC:
+ case S5P_FIMV_CODEC_FIMV1_DEC:
+ case S5P_FIMV_CODEC_FIMV2_DEC:
+ case S5P_FIMV_CODEC_FIMV3_DEC:
+ case S5P_FIMV_CODEC_FIMV4_DEC:
+ case S5P_FIMV_CODEC_H263_DEC:
+ case S5P_FIMV_CODEC_VC1_RCV_DEC:
+ case S5P_FIMV_CODEC_VC1_DEC:
+ case S5P_FIMV_CODEC_MPEG2_DEC:
+ bw_data = mfc_bw_info.mpeg4_dec_uhd_bw;
+ break;
+ case S5P_FIMV_CODEC_VP8_DEC:
+ bw_data = mfc_bw_info.vp8_dec_uhd_bw;
+ break;
+ case S5P_FIMV_CODEC_VP9_DEC:
+ bw_data = mfc_bw_info.vp9_dec_uhd_bw;
+ break;
+ case S5P_FIMV_CODEC_MPEG4_ENC:
+ case S5P_FIMV_CODEC_H263_ENC:
+ bw_data = mfc_bw_info.mpeg4_enc_uhd_bw;
+ break;
+ case S5P_FIMV_CODEC_VP8_ENC:
+ bw_data = mfc_bw_info.vp8_enc_uhd_bw;
+ break;
+ case S5P_FIMV_CODEC_VP9_ENC:
+ bw_data = mfc_bw_info.vp9_enc_uhd_bw;
+ break;
+ default:
+ bw_data.peak = 0;
+ bw_data.read = 0;
+ bw_data.write = 0;
+ mfc_err_ctx("[QoS] wrong codec_mode (%d)\n", ctx->codec_mode);
+ }
+
+ if (mb > (mb_count_per_uhd_frame * max_fps_per_uhd_frame)) {
+ mfc_debug(4, "[QoS] fix upper mb bound (mb: %ld, fps: %ld)\n", mb, fps);
+ mb = mb_count_per_uhd_frame * max_fps_per_uhd_frame;
+ }
+
+ peak_bw_per_sec = (bw_data.peak * mb) / mb_count_per_uhd_frame;
+ read_bw_per_sec = (bw_data.read * mb) / mb_count_per_uhd_frame;
+ write_bw_per_sec = (bw_data.write * mb) / mb_count_per_uhd_frame;
+
+ if (peak_bw_per_sec == 0) {
+ mfc_debug(4, "[QoS] fix lower peak bound (mb: %ld, fps: %ld)\n", mb, fps);
+ peak_bw_per_sec = MIN_BW_PER_SEC;
+ }
+ if (read_bw_per_sec == 0) {
+ mfc_debug(4, "[QoS] fix lower read bound (mb: %ld, fps: %ld)\n", mb, fps);
+ read_bw_per_sec = MIN_BW_PER_SEC;
+ }
+ if (write_bw_per_sec == 0) {
+ mfc_debug(4, "[QoS] fix lower write bound (mb: %ld, fps: %ld)\n", mb, fps);
+ write_bw_per_sec = MIN_BW_PER_SEC;
+ }
+
+ mfc_bw->peak = (unsigned int)peak_bw_per_sec;
+ mfc_bw->read = (unsigned int)read_bw_per_sec;
+ mfc_bw->write = (unsigned int)write_bw_per_sec;
+}
+#endif
+
+void s5p_mfc_qos_on(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_platdata *pdata = dev->pdata;
+ struct s5p_mfc_qos *qos_table = pdata->qos_table;
+ struct s5p_mfc_ctx *qos_ctx;
+ unsigned long hw_mb = 0, total_mb = 0, total_fps = 0;
+ unsigned int fw_time, sw_time;
+ int i, found = 0, enc_found = 0;
+ int start_qos_step;
+#ifdef CONFIG_EXYNOS_BTS
+ struct bts_bw mfc_bw, mfc_bw_ctx;
+#endif
+
+ if (perf_boost_mode) {
+ mfc_info_ctx("[QoS][BOOST] skip control\n");
+ return;
+ }
+
+ list_for_each_entry(qos_ctx, &dev->qos_queue, qos_list)
+ if (qos_ctx == ctx)
+ found = 1;
+
+ if (!found)
+ list_add_tail(&ctx->qos_list, &dev->qos_queue);
+
+#ifdef CONFIG_EXYNOS_BTS
+ mfc_bw.peak = 0;
+ mfc_bw.read = 0;
+ mfc_bw.write = 0;
+#endif
+ /* get the hw macroblock */
+ list_for_each_entry(qos_ctx, &dev->qos_queue, qos_list) {
+ if (OVER_UHD_ENC60(qos_ctx))
+ enc_found = 1;
+ hw_mb += mfc_qos_get_mb_per_second(qos_ctx);
+ total_fps += (qos_ctx->framerate / 1000);
+#ifdef CONFIG_EXYNOS_BTS
+ mfc_qos_get_bw_per_second(qos_ctx, &mfc_bw_ctx);
+ mfc_bw.peak += mfc_bw_ctx.peak;
+ mfc_bw.read += mfc_bw_ctx.read;
+ mfc_bw.write += mfc_bw_ctx.write;
+#endif
+ }
+
+ start_qos_step = pdata->num_qos_steps;
+ if (enc_found)
+ start_qos_step = pdata->max_qos_steps;
+
+ /* search the suitable qos table */
+ for (i = start_qos_step - 1; i >= 0; i--) {
+ fw_time = qos_table[i].time_fw;
+ sw_time = (MFC_DRV_TIME + fw_time);
+
+ if ((total_fps * sw_time) >= 1000000)
+ total_mb = pdata->max_mb;
+ else
+ total_mb = ((1000000 * hw_mb) / (1000000 - (total_fps * sw_time)));
+
+ mfc_debug(4, "[QoS] table[%d] fw_time: %dus, hw_mb: %ld, "
+ "sw_time: %d, total_fps: %ld, total_mb: %ld\n",
+ i, fw_time, hw_mb, sw_time, total_fps, total_mb);
+
+ if ((total_mb > qos_table[i].threshold_mb) || (i == 0))
+ break;
+ }
+
+ if (total_mb > pdata->max_mb)
+ mfc_debug(4, "[QoS] overspec mb %ld > %d\n", total_mb, pdata->max_mb);
+
+#ifdef CONFIG_EXYNOS_BTS
+ mfc_qos_set(ctx, &mfc_bw, i);
+#else
+ mfc_qos_set(ctx, i);
+#endif
+}
+
+void s5p_mfc_qos_off(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_platdata *pdata = dev->pdata;
+ struct s5p_mfc_qos *qos_table = pdata->qos_table;
+ struct s5p_mfc_ctx *qos_ctx;
+ unsigned long hw_mb = 0, total_mb = 0, total_fps = 0;
+ unsigned int fw_time, sw_time;
+ int i, found = 0, enc_found = 0;
+ int start_qos_step;
+#ifdef CONFIG_EXYNOS_BTS
+ struct bts_bw mfc_bw, mfc_bw_ctx;
+#endif
+
+ if (perf_boost_mode) {
+ mfc_info_ctx("[QoS][BOOST] skip control\n");
+ return;
+ }
+
+ if (list_empty(&dev->qos_queue)) {
+ if (atomic_read(&dev->qos_req_cur) != 0) {
+ mfc_err_ctx("[QoS] MFC request count is wrong!\n");
+ mfc_qos_operate(ctx, MFC_QOS_REMOVE, 0);
+ }
+ return;
+ }
+
+#ifdef CONFIG_EXYNOS_BTS
+ mfc_bw.peak = 0;
+ mfc_bw.read = 0;
+ mfc_bw.write = 0;
+#endif
+ /* get the hw macroblock */
+ list_for_each_entry(qos_ctx, &dev->qos_queue, qos_list) {
+ if (qos_ctx == ctx) {
+ found = 1;
+ continue;
+ }
+
+ if (OVER_UHD_ENC60(qos_ctx))
+ enc_found = 1;
+ hw_mb += mfc_qos_get_mb_per_second(qos_ctx);
+ total_fps += (qos_ctx->framerate / 1000);
+#ifdef CONFIG_EXYNOS_BTS
+ mfc_qos_get_bw_per_second(qos_ctx, &mfc_bw_ctx);
+ mfc_bw.peak += mfc_bw_ctx.peak;
+ mfc_bw.read += mfc_bw_ctx.read;
+ mfc_bw.write += mfc_bw_ctx.write;
+#endif
+ }
+
+ start_qos_step = pdata->num_qos_steps;
+ if (enc_found)
+ start_qos_step = pdata->max_qos_steps;
+
+ /* search the suitable qos table */
+ for (i = start_qos_step - 1; i >= 0; i--) {
+ fw_time = qos_table[i].time_fw;
+ sw_time = (MFC_DRV_TIME + fw_time);
+
+ if ((total_fps * sw_time) >= 1000000)
+ total_mb = pdata->max_mb;
+ else
+ total_mb = ((1000000 * hw_mb) / (1000000 - (total_fps * sw_time)));
+
+ mfc_debug(4, "[QoS] table[%d] fw_time: %dus, hw_mb: %ld, "
+ "sw_time: %d, total_fps: %ld, total_mb: %ld\n",
+ i, fw_time, hw_mb, sw_time, total_fps, total_mb);
+
+ if ((total_mb > qos_table[i].threshold_mb) || (total_mb == 0) || (i == 0))
+ break;
+ }
+
+ if (total_mb > pdata->max_mb)
+ mfc_debug(4, "[QoS] overspec mb %ld > %d\n", total_mb, pdata->max_mb);
+
+ if (found)
+ list_del(&ctx->qos_list);
+
+ if (list_empty(&dev->qos_queue) || total_mb == 0)
+ mfc_qos_operate(ctx, MFC_QOS_REMOVE, 0);
+ else
+#ifdef CONFIG_EXYNOS_BTS
+ mfc_qos_set(ctx, &mfc_bw, i);
+#else
+ mfc_qos_set(ctx, i);
+#endif
+}
+#endif
+
+#define COL_FRAME_RATE 0
+#define COL_FRAME_INTERVAL 1
+
+#define MFC_MAX_INTERVAL (2 * USEC_PER_SEC)
+
+/*
+ * A framerate table determines framerate by the interval(us) of each frame.
+ * Framerate is not accurate, just rough value to seperate overload section.
+ * Base line of each section are selected from middle value.
+ * 40fps(25000us), 80fps(12500us), 144fps(6940us)
+ * 205fps(4860us), 320fps(3125us)
+ *
+ * interval(us) | 0 3125 4860 6940 12500 25000 |
+ * framerate | 480fps | 240fps | 180fps | 120fps | 60fps | 30fps |
+ */
+static unsigned long framerate_table[][2] = {
+ { 30000, 25000 },
+ { 60000, 12500 },
+ { 120000, 6940 },
+ { 180000, 4860 },
+ { 240000, 3125 },
+ { 480000, 0 },
+};
+
+static inline unsigned long mfc_qos_timeval_diff(struct timeval *to,
+ struct timeval *from)
+{
+ return (to->tv_sec * USEC_PER_SEC + to->tv_usec)
+ - (from->tv_sec * USEC_PER_SEC + from->tv_usec);
+}
+
+static unsigned long mfc_qos_get_framerate_by_interval(int interval)
+{
+ unsigned long i;
+
+ /* if the interval is too big (2sec), framerate set to 0 */
+ if (interval > MFC_MAX_INTERVAL)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(framerate_table); i++) {
+ if (interval > framerate_table[i][COL_FRAME_INTERVAL])
+ return framerate_table[i][COL_FRAME_RATE];
+ }
+
+ return 0;
+}
+
+/* Return the minimum interval between previous and next entry */
+static int mfc_qos_get_interval(struct list_head *head, struct list_head *entry)
+{
+ int prev_interval = MFC_MAX_INTERVAL, next_interval = MFC_MAX_INTERVAL;
+ struct mfc_timestamp *prev_ts, *next_ts, *curr_ts;
+
+ curr_ts = list_entry(entry, struct mfc_timestamp, list);
+
+ if (entry->prev != head) {
+ prev_ts = list_entry(entry->prev, struct mfc_timestamp, list);
+ prev_interval = mfc_qos_timeval_diff(&curr_ts->timestamp, &prev_ts->timestamp);
+ }
+
+ if (entry->next != head) {
+ next_ts = list_entry(entry->next, struct mfc_timestamp, list);
+ next_interval = mfc_qos_timeval_diff(&next_ts->timestamp, &curr_ts->timestamp);
+ }
+
+ return (prev_interval < next_interval ? prev_interval : next_interval);
+}
+
+static int mfc_qos_add_timestamp(struct s5p_mfc_ctx *ctx,
+ struct timeval *time, struct list_head *head)
+{
+ int replace_entry = 0;
+ struct mfc_timestamp *curr_ts = &ctx->ts_array[ctx->ts_count];
+
+ if (ctx->ts_is_full) {
+ /* Replace the entry if list of array[ts_count] is same as entry */
+ if (&curr_ts->list == head)
+ replace_entry = 1;
+ else
+ list_del(&curr_ts->list);
+ }
+
+ memcpy(&curr_ts->timestamp, time, sizeof(struct timeval));
+ if (!replace_entry)
+ list_add(&curr_ts->list, head);
+ curr_ts->interval =
+ mfc_qos_get_interval(&ctx->ts_list, &curr_ts->list);
+ curr_ts->index = ctx->ts_count;
+ ctx->ts_count++;
+
+ if (ctx->ts_count == MFC_TIME_INDEX) {
+ ctx->ts_is_full = 1;
+ ctx->ts_count %= MFC_TIME_INDEX;
+ }
+
+ return 0;
+}
+
+static unsigned long mfc_qos_get_fps_by_timestamp(struct s5p_mfc_ctx *ctx, struct timeval *time)
+{
+ struct mfc_timestamp *temp_ts;
+ int found;
+ int index = 0;
+ int min_interval = MFC_MAX_INTERVAL;
+ int time_diff;
+ unsigned long max_framerate;
+
+ if (debug_ts == 1) {
+ /* Debug info */
+ mfc_info_ctx("===================[TS]===================\n");
+ mfc_info_ctx("[TS] New timestamp = %ld.%06ld, count = %d \n",
+ time->tv_sec, time->tv_usec, ctx->ts_count);
+ }
+
+ if (IS_BUFFER_BATCH_MODE(ctx)) {
+ if (debug_ts == 1)
+ mfc_info_ctx("[BUFCON][TS] Keep framerate if buffer batch mode is used, %ldfps\n",
+ ctx->framerate);
+ return ctx->framerate;
+ }
+
+ if (list_empty(&ctx->ts_list)) {
+ mfc_qos_add_timestamp(ctx, time, &ctx->ts_list);
+ return mfc_qos_get_framerate_by_interval(0);
+ } else {
+ found = 0;
+ list_for_each_entry_reverse(temp_ts, &ctx->ts_list, list) {
+ time_diff = timeval_compare(time, &temp_ts->timestamp);
+ if (time_diff == 0) {
+ /* Do not add if same timestamp already exists */
+ found = 1;
+ break;
+ } else if (time_diff > 0) {
+ /* Add this after temp_ts */
+ mfc_qos_add_timestamp(ctx, time, &temp_ts->list);
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) /* Add this at first entry */
+ mfc_qos_add_timestamp(ctx, time, &ctx->ts_list);
+ }
+
+ list_for_each_entry(temp_ts, &ctx->ts_list, list) {
+ if (temp_ts->interval < min_interval)
+ min_interval = temp_ts->interval;
+ }
+
+ max_framerate = mfc_qos_get_framerate_by_interval(min_interval);
+
+ if (debug_ts == 1) {
+ /* Debug info */
+ index = 0;
+ list_for_each_entry(temp_ts, &ctx->ts_list, list) {
+ mfc_info_ctx("[TS] [%d] timestamp [i:%d]: %ld.%06ld\n",
+ index, temp_ts->index,
+ temp_ts->timestamp.tv_sec,
+ temp_ts->timestamp.tv_usec);
+ index++;
+ }
+ mfc_info_ctx("[TS] Min interval = %d, It is %ld fps\n",
+ min_interval, max_framerate);
+ } else if (debug_ts == 2) {
+ mfc_info_ctx("[TS] Min interval = %d, It is %ld fps\n",
+ min_interval, max_framerate);
+ }
+
+ if (!ctx->ts_is_full) {
+ if (debug_ts == 1)
+ mfc_info_ctx("[TS] ts doesn't full, keep %ld fps\n", ctx->framerate);
+ return ctx->framerate;
+ }
+
+ return max_framerate;
+}
+
+void s5p_mfc_qos_update_framerate(struct s5p_mfc_ctx *ctx)
+{
+ if (ctx->last_framerate != 0 && ctx->last_framerate != ctx->framerate) {
+ mfc_debug(2, "[QoS] fps changed: %ld -> %ld, qos ratio: %d\n",
+ ctx->framerate, ctx->last_framerate, ctx->qos_ratio);
+ ctx->framerate = ctx->last_framerate;
+ s5p_mfc_qos_on(ctx);
+ }
+}
+
+void s5p_mfc_qos_update_last_framerate(struct s5p_mfc_ctx *ctx, u64 timestamp)
+{
+ struct timeval time;
+
+ time.tv_sec = timestamp / NSEC_PER_SEC;
+ time.tv_usec = (timestamp - (time.tv_sec * NSEC_PER_SEC)) / NSEC_PER_USEC;
+
+ ctx->last_framerate = mfc_qos_get_fps_by_timestamp(ctx, &time);
+ if (ctx->last_framerate > MFC_MAX_FPS)
+ ctx->last_framerate = MFC_MAX_FPS;
+ ctx->last_framerate = (ctx->qos_ratio * ctx->last_framerate) / 100;
+}
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_qos.h
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __MFC_QOS_H
+#define __MFC_QOS_H __FILE__
+
+#include "mfc_common.h"
+
+#define MFC_MAX_FPS (480000)
+#define DEC_DEFAULT_FPS (240000)
+#define ENC_DEFAULT_FPS (240000)
+#define ENC_DEFAULT_CAM_CAPTURE_FPS (60000)
+
+#define MB_COUNT_PER_UHD_FRAME 32400
+#define MAX_FPS_PER_UHD_FRAME 120
+#define MIN_BW_PER_SEC 1
+
+#define MFC_DRV_TIME 500
+
+#define MFC_QOS_WEIGHT_3PLANE 80
+#define MFC_QOS_WEIGHT_OTHER_CODEC 25
+#define MFC_QOS_WEIGHT_10BIT 75
+#define MFC_QOS_WEIGHT_422_10INTRA 70
+#define MFC_QOS_WEIGHT_BFRAME 50
+#define MFC_QOS_WEIGHT_NUM_OF_REF 50
+#define MFC_QOS_WEIGHT_NUM_OF_TILE 75
+
+#ifdef CONFIG_MFC_USE_BUS_DEVFREQ
+void s5p_mfc_perf_boost_enable(struct s5p_mfc_dev *dev);
+void s5p_mfc_perf_boost_disable(struct s5p_mfc_dev *dev);
+void s5p_mfc_qos_on(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_qos_off(struct s5p_mfc_ctx *ctx);
+#else
+#define s5p_mfc_perf_boost_enable(dev) do {} while (0)
+#define s5p_mfc_perf_boost_disable(dev) do {} while (0)
+#define s5p_mfc_qos_on(ctx) do {} while (0)
+#define s5p_mfc_qos_off(ctx) do {} while (0)
+#endif
+
+void s5p_mfc_qos_update_framerate(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_qos_update_last_framerate(struct s5p_mfc_ctx *ctx, u64 timestamp);
+
+static inline void s5p_mfc_qos_reset_framerate(struct s5p_mfc_ctx *ctx)
+{
+ if (ctx->type == MFCINST_DECODER)
+ ctx->framerate = DEC_DEFAULT_FPS;
+ else if (ctx->type == MFCINST_ENCODER)
+ ctx->framerate = ENC_DEFAULT_FPS;
+}
+
+static inline void s5p_mfc_qos_reset_last_framerate(struct s5p_mfc_ctx *ctx)
+{
+ ctx->last_framerate = 0;
+}
+
+static inline void s5p_mfc_qos_set_framerate(struct s5p_mfc_ctx *ctx, int rate)
+{
+ ctx->framerate = rate;
+}
+
+static inline int s5p_mfc_qos_get_framerate(struct s5p_mfc_ctx *ctx)
+{
+ return ctx->framerate;
+}
+
+#endif /* __MFC_QOS_H */
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_queue.c
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "mfc_queue.h"
+
+#include "mfc_utils.h"
+#include "mfc_mem.h"
+
+void s5p_mfc_add_tail_buf(spinlock_t *plock, struct s5p_mfc_buf_queue *queue,
+ struct s5p_mfc_buf *mfc_buf)
+{
+ unsigned long flags;
+
+ if (!mfc_buf) {
+ mfc_err_dev("mfc_buf is NULL!\n");
+ return;
+ }
+
+ spin_lock_irqsave(plock, flags);
+
+ mfc_buf->used = 0;
+ list_add_tail(&mfc_buf->list, &queue->head);
+ queue->count++;
+
+ spin_unlock_irqrestore(plock, flags);
+}
+
+int s5p_mfc_peek_buf_csd(spinlock_t *plock, struct s5p_mfc_buf_queue *queue)
+{
+ unsigned long flags;
+ int csd = -1;
+ struct s5p_mfc_buf *mfc_buf = NULL;
+
+ spin_lock_irqsave(plock, flags);
+
+ if (list_empty(&queue->head)) {
+ mfc_debug(2, "queue is empty\n");
+ spin_unlock_irqrestore(plock, flags);
+ return csd;
+ }
+
+ mfc_buf = list_entry(queue->head.next, struct s5p_mfc_buf, list);
+
+ csd = mfc_buf->vb.reserved2 & FLAG_CSD ? 1 : 0;
+
+ mfc_debug(2, "addr[0]: 0x%08llx\n", mfc_buf->addr[0][0]);
+
+ spin_unlock_irqrestore(plock, flags);
+ return csd;
+}
+
+struct s5p_mfc_buf *s5p_mfc_get_buf(spinlock_t *plock, struct s5p_mfc_buf_queue *queue,
+ enum s5p_mfc_queue_used_type used)
+{
+ unsigned long flags;
+ struct s5p_mfc_buf *mfc_buf = NULL;
+
+ spin_lock_irqsave(plock, flags);
+
+ if (list_empty(&queue->head)) {
+ mfc_debug(2, "queue is empty\n");
+ spin_unlock_irqrestore(plock, flags);
+ return NULL;
+ }
+
+ mfc_buf = list_entry(queue->head.next, struct s5p_mfc_buf, list);
+
+ if ((used == MFC_BUF_RESET_USED) || (used == MFC_BUF_SET_USED))
+ mfc_buf->used = used;
+
+ mfc_debug(2, "addr[0]: 0x%08llx\n", mfc_buf->addr[0][0]);
+
+ spin_unlock_irqrestore(plock, flags);
+ return mfc_buf;
+}
+
+struct s5p_mfc_buf *s5p_mfc_get_del_buf(spinlock_t *plock, struct s5p_mfc_buf_queue *queue,
+ enum s5p_mfc_queue_used_type used)
+{
+ unsigned long flags;
+ struct s5p_mfc_buf *mfc_buf = NULL;
+
+ spin_lock_irqsave(plock, flags);
+
+ if (list_empty(&queue->head)) {
+ mfc_debug(2, "queue is empty\n");
+ spin_unlock_irqrestore(plock, flags);
+ return NULL;
+ }
+
+ mfc_buf = list_entry(queue->head.next, struct s5p_mfc_buf, list);
+
+ if ((used == MFC_BUF_RESET_USED) || (used == MFC_BUF_SET_USED))
+ mfc_buf->used = used;
+
+ mfc_debug(2, "addr[0]: 0x%08llx\n", mfc_buf->addr[0][0]);
+
+ list_del(&mfc_buf->list);
+ queue->count--;
+
+ spin_unlock_irqrestore(plock, flags);
+ return mfc_buf;
+}
+
+struct s5p_mfc_buf *s5p_mfc_get_del_if_consumed(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf_queue *queue,
+ unsigned long consumed, unsigned int min_bytes, int error, int *deleted)
+{
+ unsigned long flags;
+ struct s5p_mfc_buf *mfc_buf = NULL;
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ unsigned long remained;
+
+ spin_lock_irqsave(&ctx->buf_queue_lock, flags);
+
+ if (list_empty(&queue->head)) {
+ mfc_debug(2, "queue is empty\n");
+ spin_unlock_irqrestore(&ctx->buf_queue_lock, flags);
+ return NULL;
+ }
+
+ mfc_buf = list_entry(queue->head.next, struct s5p_mfc_buf, list);
+
+ mfc_debug(2, "addr[0]: 0x%08llx\n", mfc_buf->addr[0][0]);
+
+ if (dec->remained_size)
+ remained = dec->remained_size - consumed;
+ else
+ remained = mfc_buf->vb.vb2_buf.planes[0].bytesused - consumed;
+
+ mfc_debug(2, "[MULTIFRAME] Total Size: %d, consumed: %ld, remained: %ld\n",
+ mfc_buf->vb.vb2_buf.planes[0].bytesused, consumed, remained);
+
+ if ((consumed > 0) && (remained > min_bytes) && (error == 0) &&
+ (mfc_buf->vb.vb2_buf.planes[0].bytesused > consumed)){
+ /* do not delete from queue */
+ *deleted = 0;
+ } else {
+ list_del(&mfc_buf->list);
+ queue->count--;
+
+ *deleted = 1;
+ }
+
+ spin_unlock_irqrestore(&ctx->buf_queue_lock, flags);
+ return mfc_buf;
+}
+
+struct s5p_mfc_buf *s5p_mfc_get_move_buf(spinlock_t *plock,
+ struct s5p_mfc_buf_queue *to_queue, struct s5p_mfc_buf_queue *from_queue,
+ enum s5p_mfc_queue_used_type used, enum s5p_mfc_queue_top_type top)
+{
+ unsigned long flags;
+ struct s5p_mfc_buf *mfc_buf = NULL;
+
+ spin_lock_irqsave(plock, flags);
+
+ if (list_empty(&from_queue->head)) {
+ mfc_debug(2, "from_queue is empty\n");
+ spin_unlock_irqrestore(plock, flags);
+ return NULL;
+ }
+
+ mfc_buf = list_entry(from_queue->head.next, struct s5p_mfc_buf, list);
+
+ if ((used == MFC_BUF_RESET_USED) || (used == MFC_BUF_SET_USED))
+ mfc_buf->used = used;
+
+ mfc_debug(2, "addr[0]: 0x%08llx\n", mfc_buf->addr[0][0]);
+
+ list_del(&mfc_buf->list);
+ from_queue->count--;
+
+ if (top == MFC_QUEUE_ADD_TOP)
+ list_add(&mfc_buf->list, &to_queue->head);
+ else
+ list_add_tail(&mfc_buf->list, &to_queue->head);
+
+ to_queue->count++;
+
+ spin_unlock_irqrestore(plock, flags);
+ return mfc_buf;
+}
+
+struct s5p_mfc_buf *s5p_mfc_get_move_buf_used(spinlock_t *plock,
+ struct s5p_mfc_buf_queue *to_queue, struct s5p_mfc_buf_queue *from_queue)
+{
+ unsigned long flags;
+ struct s5p_mfc_buf *mfc_buf = NULL;
+
+ spin_lock_irqsave(plock, flags);
+
+ if (list_empty(&from_queue->head)) {
+ mfc_debug(2, "from_queue is empty\n");
+ spin_unlock_irqrestore(plock, flags);
+ return NULL;
+ }
+
+ mfc_buf = list_entry(from_queue->head.next, struct s5p_mfc_buf, list);
+
+ if (mfc_buf->used) {
+ mfc_debug(2, "addr[0]: 0x%08llx\n", mfc_buf->addr[0][0]);
+
+ list_del(&mfc_buf->list);
+ from_queue->count--;
+
+ list_add_tail(&mfc_buf->list, &to_queue->head);
+ to_queue->count++;
+
+ spin_unlock_irqrestore(plock, flags);
+ return mfc_buf;
+ } else {
+ spin_unlock_irqrestore(plock, flags);
+ return NULL;
+ }
+}
+
+struct s5p_mfc_buf *s5p_mfc_get_move_buf_addr(spinlock_t *plock,
+ struct s5p_mfc_buf_queue *to_queue, struct s5p_mfc_buf_queue *from_queue,
+ dma_addr_t addr)
+{
+ unsigned long flags;
+ struct s5p_mfc_buf *mfc_buf = NULL;
+
+ spin_lock_irqsave(plock, flags);
+
+ if (list_empty(&from_queue->head)) {
+ mfc_debug(2, "[DPB] from_queue is empty\n");
+ spin_unlock_irqrestore(plock, flags);
+ return NULL;
+ }
+
+ mfc_buf = list_entry(from_queue->head.next, struct s5p_mfc_buf, list);
+
+ if (mfc_buf->addr[0][0] == addr) {
+ mfc_debug(2, "[DPB] addr[0]: 0x%08llx\n", mfc_buf->addr[0][0]);
+
+ list_del(&mfc_buf->list);
+ from_queue->count--;
+
+ list_add_tail(&mfc_buf->list, &to_queue->head);
+ to_queue->count++;
+
+ spin_unlock_irqrestore(plock, flags);
+ return mfc_buf;
+ } else {
+ spin_unlock_irqrestore(plock, flags);
+ return NULL;
+ }
+}
+
+struct s5p_mfc_buf *s5p_mfc_find_first_buf(spinlock_t *plock, struct s5p_mfc_buf_queue *queue,
+ dma_addr_t addr)
+{
+ unsigned long flags;
+ struct s5p_mfc_buf *mfc_buf = NULL;
+ dma_addr_t mb_addr;
+ int i;
+
+ spin_lock_irqsave(plock, flags);
+
+ if (list_empty(&queue->head)) {
+ mfc_debug(2, "queue is empty\n");
+ spin_unlock_irqrestore(plock, flags);
+ return mfc_buf;
+ }
+
+ mfc_debug(4, "Looking for this address: 0x%08llx\n", addr);
+ mfc_buf = list_entry(queue->head.next, struct s5p_mfc_buf, list);
+ if (mfc_buf->num_valid_bufs > 0) {
+ for (i = 0; i < mfc_buf->num_valid_bufs; i++) {
+ mb_addr = mfc_buf->addr[i][0];
+ mfc_debug(4, "[BUFCON] batch[%d] addr[0]: 0x%08llx\n", i, mb_addr);
+ if (addr == mb_addr) {
+ spin_unlock_irqrestore(plock, flags);
+ return mfc_buf;
+ }
+ }
+ } else {
+ mb_addr = mfc_buf->addr[0][0];
+ mfc_debug(4, "addr[0]: 0x%08llx\n", mb_addr);
+
+ if (addr == mb_addr) {
+ spin_unlock_irqrestore(plock, flags);
+ return mfc_buf;
+ }
+ }
+
+ spin_unlock_irqrestore(plock, flags);
+ return NULL;
+}
+
+struct s5p_mfc_buf *s5p_mfc_find_buf(spinlock_t *plock, struct s5p_mfc_buf_queue *queue,
+ dma_addr_t addr)
+{
+ unsigned long flags;
+ struct s5p_mfc_buf *mfc_buf = NULL;
+ dma_addr_t mb_addr;
+ int i;
+
+ spin_lock_irqsave(plock, flags);
+
+ mfc_debug(4, "Looking for this address: 0x%08llx\n", addr);
+ list_for_each_entry(mfc_buf, &queue->head, list) {
+ if (mfc_buf->num_valid_bufs > 0) {
+ for (i = 0; i < mfc_buf->num_valid_bufs; i++) {
+ mb_addr = mfc_buf->addr[i][0];
+ mfc_debug(4, "[BUFCON] batch[%d] addr[0]: 0x%08llx\n", i, mb_addr);
+ if (addr == mb_addr) {
+ spin_unlock_irqrestore(plock, flags);
+ return mfc_buf;
+ }
+ }
+ } else {
+ mb_addr = mfc_buf->addr[0][0];
+ mfc_debug(4, "addr[0]: 0x%08llx\n", mb_addr);
+
+ if (addr == mb_addr) {
+ spin_unlock_irqrestore(plock, flags);
+ return mfc_buf;
+ }
+ }
+ }
+
+ spin_unlock_irqrestore(plock, flags);
+ return NULL;
+}
+
+struct s5p_mfc_buf *s5p_mfc_find_del_buf(spinlock_t *plock, struct s5p_mfc_buf_queue *queue,
+ dma_addr_t addr)
+{
+ unsigned long flags;
+ struct s5p_mfc_buf *mfc_buf = NULL;
+ dma_addr_t mb_addr;
+ int found = 0, i;
+
+ spin_lock_irqsave(plock, flags);
+
+ mfc_debug(4, "Looking for this address: 0x%08llx\n", addr);
+ list_for_each_entry(mfc_buf, &queue->head, list) {
+ if (mfc_buf->num_valid_bufs > 0) {
+ for (i = 0; i < mfc_buf->num_valid_bufs; i++) {
+ mb_addr = mfc_buf->addr[i][0];
+ mfc_debug(4, "batch buf[%d] plane[0] addr: 0x%08llx\n", i, mb_addr);
+
+ if (addr == mb_addr) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (found)
+ break;
+ } else {
+ mb_addr = mfc_buf->addr[0][0];
+ mfc_debug(4, "addr[0]: 0x%08llx\n", mb_addr);
+
+ if (addr == mb_addr) {
+ found = 1;
+ break;
+ }
+ }
+ }
+
+ if (found == 1) {
+ list_del(&mfc_buf->list);
+ queue->count--;
+
+ spin_unlock_irqrestore(plock, flags);
+ return mfc_buf;
+ } else {
+ spin_unlock_irqrestore(plock, flags);
+ return NULL;
+ }
+}
+
+struct s5p_mfc_buf *s5p_mfc_find_move_buf(spinlock_t *plock,
+ struct s5p_mfc_buf_queue *to_queue, struct s5p_mfc_buf_queue *from_queue,
+ dma_addr_t addr, unsigned int released_flag)
+{
+ unsigned long flags;
+ struct s5p_mfc_buf *mfc_buf = NULL;
+ dma_addr_t mb_addr;
+ int found = 0;
+
+ spin_lock_irqsave(plock, flags);
+
+ mfc_debug(4, "[DPB] Looking for this address: 0x%08llx\n", addr);
+ list_for_each_entry(mfc_buf, &from_queue->head, list) {
+ mb_addr = mfc_buf->addr[0][0];
+ mfc_debug(4, "[DPB] addr[0]: 0x%08llx\n", mb_addr);
+
+ if (addr == mb_addr) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (found == 1) {
+ if (released_flag & (1 << mfc_buf->vb.vb2_buf.index)) {
+ list_del(&mfc_buf->list);
+ from_queue->count--;
+
+ list_add_tail(&mfc_buf->list, &to_queue->head);
+ to_queue->count++;
+ }
+
+ spin_unlock_irqrestore(plock, flags);
+ return mfc_buf;
+ } else {
+ spin_unlock_irqrestore(plock, flags);
+ return NULL;
+ }
+}
+
+struct s5p_mfc_buf *s5p_mfc_find_move_buf_used(spinlock_t *plock,
+ struct s5p_mfc_buf_queue *to_queue, struct s5p_mfc_buf_queue *from_queue,
+ dma_addr_t addr)
+{
+ unsigned long flags;
+ struct s5p_mfc_buf *mfc_buf = NULL;
+ dma_addr_t mb_addr;
+ int found = 0;
+
+ spin_lock_irqsave(plock, flags);
+
+ mfc_debug(4, "[DPB] Looking for this address: 0x%08llx\n", addr);
+ list_for_each_entry(mfc_buf, &from_queue->head, list) {
+ mb_addr = mfc_buf->addr[0][0];
+ mfc_debug(4, "[DPB] addr[0]: 0x%08llx, used: %d\n",
+ mb_addr, mfc_buf->used);
+
+ if ((addr == mb_addr) && (mfc_buf->used == 1)) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (found == 1) {
+ list_del(&mfc_buf->list);
+ from_queue->count--;
+
+ list_add_tail(&mfc_buf->list, &to_queue->head);
+ to_queue->count++;
+
+ spin_unlock_irqrestore(plock, flags);
+ return mfc_buf;
+ } else {
+ spin_unlock_irqrestore(plock, flags);
+ return NULL;
+ }
+}
+
+void s5p_mfc_move_first_buf_used(spinlock_t *plock, struct s5p_mfc_buf_queue *to_queue,
+ struct s5p_mfc_buf_queue *from_queue, enum s5p_mfc_queue_top_type top)
+{
+ unsigned long flags;
+ struct s5p_mfc_buf *mfc_buf = NULL;
+
+ spin_lock_irqsave(plock, flags);
+
+ if (list_empty(&from_queue->head)) {
+ mfc_err_dev("from_queue is empty\n");
+ spin_unlock_irqrestore(plock, flags);
+ return;
+ }
+ mfc_buf = list_entry(from_queue->head.next, struct s5p_mfc_buf, list);
+
+ if (mfc_buf->used) {
+ list_del(&mfc_buf->list);
+ from_queue->count--;
+
+ if (top == MFC_QUEUE_ADD_TOP)
+ list_add(&mfc_buf->list, &to_queue->head);
+ else
+ list_add_tail(&mfc_buf->list, &to_queue->head);
+
+ to_queue->count++;
+ }
+
+ spin_unlock_irqrestore(plock, flags);
+}
+
+void s5p_mfc_move_all_bufs(spinlock_t *plock, struct s5p_mfc_buf_queue *to_queue,
+ struct s5p_mfc_buf_queue *from_queue, enum s5p_mfc_queue_top_type top)
+{
+ unsigned long flags;
+ struct s5p_mfc_buf *mfc_buf = NULL;
+
+ spin_lock_irqsave(plock, flags);
+
+ if (top == MFC_QUEUE_ADD_TOP) {
+ while (!list_empty(&from_queue->head)) {
+ mfc_buf = list_entry(from_queue->head.prev, struct s5p_mfc_buf, list);
+
+ list_del(&mfc_buf->list);
+ from_queue->count--;
+
+ list_add(&mfc_buf->list, &to_queue->head);
+ to_queue->count++;
+ }
+ } else {
+ while (!list_empty(&from_queue->head)) {
+ mfc_buf = list_entry(from_queue->head.next, struct s5p_mfc_buf, list);
+
+ list_del(&mfc_buf->list);
+ from_queue->count--;
+
+ list_add_tail(&mfc_buf->list, &to_queue->head);
+ to_queue->count++;
+ }
+ }
+
+ INIT_LIST_HEAD(&from_queue->head);
+ from_queue->count = 0;
+
+ spin_unlock_irqrestore(plock, flags);
+}
+
+void s5p_mfc_cleanup_queue(spinlock_t *plock, struct s5p_mfc_buf_queue *queue)
+{
+ unsigned long flags;
+ struct s5p_mfc_buf *mfc_buf = NULL;
+ int i;
+
+ spin_lock_irqsave(plock, flags);
+
+ while (!list_empty(&queue->head)) {
+ mfc_buf = list_entry(queue->head.next, struct s5p_mfc_buf, list);
+
+ for (i = 0; i < mfc_buf->vb.vb2_buf.num_planes; i++)
+ vb2_set_plane_payload(&mfc_buf->vb.vb2_buf, i, 0);
+ vb2_buffer_done(&mfc_buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+ list_del(&mfc_buf->list);
+ queue->count--;
+ }
+
+ INIT_LIST_HEAD(&queue->head);
+ queue->count = 0;
+
+ spin_unlock_irqrestore(plock, flags);
+}
+
+static void mfc_cleanup_batch_queue(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf_queue *queue)
+{
+ unsigned long flags;
+ struct s5p_mfc_buf *mfc_buf = NULL;
+ int i;
+
+ spin_lock_irqsave(&ctx->buf_queue_lock, flags);
+
+ while (!list_empty(&queue->head)) {
+ mfc_buf = list_entry(queue->head.next, struct s5p_mfc_buf, list);
+
+ for (i = 0; i < mfc_buf->vb.vb2_buf.num_planes; i++) {
+ s5p_mfc_bufcon_put_daddr(ctx, mfc_buf, i);
+ vb2_set_plane_payload(&mfc_buf->vb.vb2_buf, i, 0);
+ }
+ vb2_buffer_done(&mfc_buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+ list_del(&mfc_buf->list);
+ queue->count--;
+ }
+
+ INIT_LIST_HEAD(&queue->head);
+ queue->count = 0;
+ ctx->batch_mode = 0;
+
+ spin_unlock_irqrestore(&ctx->buf_queue_lock, flags);
+}
+
+struct s5p_mfc_buf *mfc_find_buf_index(spinlock_t *plock, struct s5p_mfc_buf_queue *queue,
+ int index)
+{
+ unsigned long flags;
+ struct s5p_mfc_buf *mfc_buf = NULL;
+ int buf_index;
+
+ spin_lock_irqsave(plock, flags);
+
+ mfc_debug(4, "[DPB] Looking for index: %d\n", index);
+ list_for_each_entry(mfc_buf, &queue->head, list) {
+ buf_index = mfc_buf->vb.vb2_buf.index;
+
+ if (index == buf_index) {
+ mfc_debug(2, "[DPB] Found index: %d\n", buf_index);
+ spin_unlock_irqrestore(plock, flags);
+ return mfc_buf;
+ }
+ }
+
+ spin_unlock_irqrestore(plock, flags);
+ return NULL;
+}
+
+/*
+ * Check released and enqueued buffers. (dst queue)
+ * Check and move reuse buffers. (ref -> dst queue)
+ */
+static void mfc_check_ref_frame(spinlock_t *plock, struct s5p_mfc_buf_queue *dst_queue,
+ struct s5p_mfc_buf_queue *ref_queue,
+ struct s5p_mfc_ctx *ctx, int ref_index)
+{
+ unsigned long flags;
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ struct s5p_mfc_buf *ref_mb, *tmp_mb;
+ int index;
+ int found = 0;
+
+ spin_lock_irqsave(plock, flags);
+
+ /* reuse buffers : error frame, decoding only frame (ref -> dst queue) */
+ list_for_each_entry_safe(ref_mb, tmp_mb, &ref_queue->head, list) {
+ index = ref_mb->vb.vb2_buf.index;
+ if (index == ref_index) {
+ list_del(&ref_mb->list);
+ ref_queue->count--;
+
+ list_add_tail(&ref_mb->list, &dst_queue->head);
+ dst_queue->count++;
+
+ dec->assigned_fd[index] =
+ ref_mb->vb.vb2_buf.planes[0].m.fd;
+ clear_bit(index, &dec->available_dpb);
+ mfc_debug(2, "[DPB] Move buffer[%d], fd[%d] to dst queue\n",
+ index, dec->assigned_fd[index]);
+ found = 1;
+ break;
+ }
+ }
+
+ /* released and enqueued buffers (dst queue) */
+ if (!found) {
+ list_for_each_entry_safe(ref_mb, tmp_mb, &dst_queue->head, list) {
+ index = ref_mb->vb.vb2_buf.index;
+ if (index == ref_index) {
+ dec->assigned_fd[index] =
+ ref_mb->vb.vb2_buf.planes[0].m.fd;
+ clear_bit(index, &dec->available_dpb);
+ mfc_debug(2, "[DPB] re-assigned buffer[%d], fd[%d]\n",
+ index, dec->assigned_fd[index]);
+ break;
+ }
+ }
+ }
+
+ spin_unlock_irqrestore(plock, flags);
+}
+
+/* Process the released reference information */
+void s5p_mfc_handle_released_info(struct s5p_mfc_ctx *ctx,
+ unsigned int released_flag, int index)
+{
+ struct s5p_mfc_dec *dec;
+ struct dec_dpb_ref_info *refBuf;
+ int t, ncount = 0;
+
+ dec = ctx->dec_priv;
+ if (!dec) {
+ mfc_err_dev("[DPB] no decoder context to run\n");
+ return;
+ }
+ refBuf = &dec->ref_info[index];
+
+ if (dec->dec_only_release_flag) {
+ for (t = 0; t < MFC_MAX_DPBS; t++) {
+ if (dec->dec_only_release_flag & (1 << t)) {
+ mfc_debug(2, "[DPB] Release FD[%d] = %03d (already released in dec only)\n",
+ t, dec->assigned_fd[t]);
+ refBuf->dpb[ncount].fd[0] = dec->assigned_fd[t];
+ ncount++;
+ dec->dec_only_release_flag &= ~(1 << t);
+ }
+ }
+ }
+
+ if (released_flag) {
+ for (t = 0; t < MFC_MAX_DPBS; t++) {
+ if (released_flag & (1 << t)) {
+ if (dec->err_reuse_flag & (1 << t)) {
+ /* reuse buffer with error : do not update released info */
+ mfc_debug(2, "[DPB] Released, but reuse(error frame). FD[%d] = %03d\n",
+ t, dec->assigned_fd[t]);
+ dec->err_reuse_flag &= ~(1 << t);
+ } else if ((t != index) &&
+ mfc_find_buf_index(&ctx->buf_queue_lock, &ctx->ref_buf_queue, t)) {
+ /* decoding only frame: do not update released info */
+ mfc_debug(2, "[DPB] Released, but reuse(decoding only). FD[%d] = %03d\n",
+ t, dec->assigned_fd[t]);
+ } else {
+ /* displayed and released frame */
+ mfc_debug(2, "[DPB] Release FD[%d] = %03d\n",
+ t, dec->assigned_fd[t]);
+ refBuf->dpb[ncount].fd[0] = dec->assigned_fd[t];
+ ncount++;
+ }
+ dec->assigned_fd[t] = MFC_INFO_INIT_FD;
+ mfc_check_ref_frame(&ctx->buf_queue_lock, &ctx->dst_buf_queue,
+ &ctx->ref_buf_queue, ctx, t);
+ }
+ }
+ }
+
+ if (ncount != MFC_MAX_DPBS)
+ refBuf->dpb[ncount].fd[0] = MFC_INFO_INIT_FD;
+}
+
+struct s5p_mfc_buf *s5p_mfc_move_reuse_buffer(struct s5p_mfc_ctx *ctx, int release_index)
+{
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ struct s5p_mfc_buf_queue *dst_queue = &ctx->dst_buf_queue;
+ struct s5p_mfc_buf_queue *ref_queue = &ctx->ref_buf_queue;
+ struct s5p_mfc_buf *ref_mb, *tmp_mb;
+ spinlock_t *plock = &ctx->buf_queue_lock;
+ unsigned long flags;
+ int index;
+
+ spin_lock_irqsave(plock, flags);
+
+ list_for_each_entry_safe(ref_mb, tmp_mb, &ref_queue->head, list) {
+ index = ref_mb->vb.vb2_buf.index;
+ if (index == release_index) {
+ s5p_mfc_raw_unprotect(ctx, ref_mb, index);
+
+ ref_mb->used = 0;
+
+ list_del(&ref_mb->list);
+ ref_queue->count--;
+
+ list_add_tail(&ref_mb->list, &dst_queue->head);
+ dst_queue->count++;
+
+ clear_bit(index, &dec->available_dpb);
+ mfc_debug(2, "[DPB] buffer[%d] is moved to dst queue for reuse\n", index);
+
+ spin_unlock_irqrestore(plock, flags);
+ return ref_mb;
+ }
+ }
+
+ spin_unlock_irqrestore(plock, flags);
+ return NULL;
+}
+
+void s5p_mfc_cleanup_enc_src_queue(struct s5p_mfc_ctx *ctx)
+{
+ unsigned long flags;
+ struct s5p_mfc_buf *src_mb, *tmp_mb;
+ int i;
+
+ if (ctx->is_drm && ctx->raw_protect_flag) {
+ spin_lock_irqsave(&ctx->buf_queue_lock, flags);
+
+ mfc_debug(2, "raw_protect_flag(%#lx) will be released\n",
+ ctx->raw_protect_flag);
+
+ list_for_each_entry_safe(src_mb, tmp_mb, &ctx->src_buf_queue.head, list) {
+ i = src_mb->vb.vb2_buf.index;
+
+ s5p_mfc_raw_unprotect(ctx, src_mb, i);
+
+ for (i = 0; i < src_mb->vb.vb2_buf.num_planes; i++) {
+ s5p_mfc_bufcon_put_daddr(ctx, src_mb, i);
+ vb2_set_plane_payload(&src_mb->vb.vb2_buf, i, 0);
+ }
+
+ vb2_buffer_done(&src_mb->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+ list_del(&src_mb->list);
+ ctx->src_buf_queue.count--;
+ }
+
+ INIT_LIST_HEAD(&ctx->src_buf_queue.head);
+ ctx->src_buf_queue.count = 0;
+
+ spin_unlock_irqrestore(&ctx->buf_queue_lock, flags);
+ } else {
+ if (IS_BUFFER_BATCH_MODE(ctx))
+ mfc_cleanup_batch_queue(ctx, &ctx->src_buf_queue);
+ else
+ s5p_mfc_cleanup_queue(&ctx->buf_queue_lock, &ctx->src_buf_queue);
+ }
+}
+
+
+void s5p_mfc_cleanup_enc_dst_queue(struct s5p_mfc_ctx *ctx)
+{
+ unsigned long flags;
+ struct s5p_mfc_buf *dst_mb, *tmp_mb;
+ int i;
+
+ if (ctx->is_drm && ctx->stream_protect_flag) {
+ spin_lock_irqsave(&ctx->buf_queue_lock, flags);
+
+ mfc_debug(2, "stream_protect_flag(%#lx) will be released\n",
+ ctx->stream_protect_flag);
+
+ list_for_each_entry_safe(dst_mb, tmp_mb, &ctx->dst_buf_queue.head, list) {
+ i = dst_mb->vb.vb2_buf.index;
+
+ s5p_mfc_stream_unprotect(ctx, dst_mb, i);
+
+ for (i = 0; i < dst_mb->vb.vb2_buf.num_planes; i++)
+ vb2_set_plane_payload(&dst_mb->vb.vb2_buf, i, 0);
+ vb2_buffer_done(&dst_mb->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+ list_del(&dst_mb->list);
+ ctx->dst_buf_queue.count--;
+ }
+
+ INIT_LIST_HEAD(&ctx->dst_buf_queue.head);
+ ctx->dst_buf_queue.count = 0;
+
+ spin_unlock_irqrestore(&ctx->buf_queue_lock, flags);
+ } else {
+ s5p_mfc_cleanup_queue(&ctx->buf_queue_lock, &ctx->dst_buf_queue);
+ }
+}
+
+/* Check all buffers are referenced or not */
+struct s5p_mfc_buf *mfc_check_full_refered_dpb(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dec *dec = NULL;
+ struct s5p_mfc_buf *mfc_buf = NULL;
+ int sum_dpb;
+
+ dec = ctx->dec_priv;
+ if (!dec) {
+ mfc_err_dev("[DPB] no decoder context to run\n");
+ return NULL;
+ }
+
+ sum_dpb = ctx->dst_buf_queue.count + ctx->ref_buf_queue.count;
+
+ if ((ctx->dst_buf_queue.count > 1) && (sum_dpb >= (ctx->dpb_count + 5))) {
+ if (list_empty(&ctx->dst_buf_queue.head)) {
+ mfc_err_ctx("[DPB] dst_buf_queue is empty\n");
+ return NULL;
+ }
+ mfc_debug(3, "[DPB] We should use this buffer\n");
+ mfc_buf = list_entry(ctx->dst_buf_queue.head.next,
+ struct s5p_mfc_buf, list);
+ } else if ((ctx->dst_buf_queue.count == 0)
+ && ((ctx->ref_buf_queue.count) == (ctx->dpb_count + 5))) {
+ if (list_empty(&ctx->ref_buf_queue.head)) {
+ mfc_err_ctx("[DPB] ref_buf_queue is empty\n");
+ return NULL;
+ }
+ mfc_debug(3, "[DPB] All buffers are referenced\n");
+ mfc_buf = list_entry(ctx->ref_buf_queue.head.next,
+ struct s5p_mfc_buf, list);
+ } else {
+ mfc_debug(3, "[DPB] waiting for dst buffer, ref = %d, dst = %d\n",
+ ctx->ref_buf_queue.count, ctx->dst_buf_queue.count);
+ ctx->clear_work_bit = 1;
+ }
+
+ if (mfc_buf)
+ mfc_buf->used = 1;
+
+ return mfc_buf;
+}
+
+/* Try to search non-referenced DPB on dst-queue */
+struct s5p_mfc_buf *s5p_mfc_search_for_dpb(struct s5p_mfc_ctx *ctx, unsigned int dynamic_used)
+{
+ unsigned long flags;
+ struct s5p_mfc_buf *mfc_buf = NULL;
+
+ spin_lock_irqsave(&ctx->buf_queue_lock, flags);
+
+ mfc_debug(2, "[DPB] Try to find non-referenced DPB. dynamic_used: 0x%x\n", dynamic_used);
+ list_for_each_entry(mfc_buf, &ctx->dst_buf_queue.head, list) {
+ if ((dynamic_used & (1 << mfc_buf->vb.vb2_buf.index)) == 0) {
+ mfc_buf->used = 1;
+ spin_unlock_irqrestore(&ctx->buf_queue_lock, flags);
+ return mfc_buf;
+ }
+ }
+
+ mfc_buf = mfc_check_full_refered_dpb(ctx);
+
+ spin_unlock_irqrestore(&ctx->buf_queue_lock, flags);
+
+ return mfc_buf;
+}
+
+struct s5p_mfc_buf *s5p_mfc_search_move_dpb_nal_q(struct s5p_mfc_ctx *ctx, unsigned int dynamic_used)
+{
+ unsigned long flags;
+ struct s5p_mfc_buf *mfc_buf = NULL;
+ struct s5p_mfc_dec *dec = NULL;
+
+ dec = ctx->dec_priv;
+ if (!dec) {
+ mfc_err_dev("no mfc decoder to run\n");
+ return mfc_buf;
+ }
+
+ spin_lock_irqsave(&ctx->buf_queue_lock, flags);
+
+ mfc_debug(2, "[NALQ][DPB] Try to find non-referenced DPB. dynamic_used: 0x%x\n", dynamic_used);
+ list_for_each_entry(mfc_buf, &ctx->dst_buf_queue.head, list) {
+ if ((dynamic_used & (1 << mfc_buf->vb.vb2_buf.index)) == 0) {
+ mfc_buf->used = 1;
+
+ list_del(&mfc_buf->list);
+ ctx->dst_buf_queue.count--;
+
+ list_add_tail(&mfc_buf->list, &ctx->dst_buf_nal_queue.head);
+ ctx->dst_buf_nal_queue.count++;
+
+ spin_unlock_irqrestore(&ctx->buf_queue_lock, flags);
+ return mfc_buf;
+ }
+ }
+
+ mfc_buf = mfc_check_full_refered_dpb(ctx);
+
+ if (mfc_buf) {
+ mfc_debug(2, "[NALQ][DPB] DPB is full. stop NAL-Q if started\n");
+ dec->is_dpb_full = 1;
+ }
+
+ spin_unlock_irqrestore(&ctx->buf_queue_lock, flags);
+
+ return mfc_buf;
+}
+
+/* Add dst buffer in dst_buf_queue */
+void s5p_mfc_store_dpb(struct s5p_mfc_ctx *ctx, struct vb2_buffer *vb)
+{
+ unsigned long flags;
+ struct s5p_mfc_dec *dec;
+ struct s5p_mfc_buf *mfc_buf;
+ int index;
+
+ if (!ctx) {
+ mfc_err_dev("[DPB] no mfc context to run\n");
+ return;
+ }
+
+ dec = ctx->dec_priv;
+ if (!dec) {
+ mfc_err_dev("[DPB] no mfc decoder to run\n");
+ return;
+ }
+
+ spin_lock_irqsave(&ctx->buf_queue_lock, flags);
+
+ mfc_buf = vb_to_mfc_buf(vb);
+ mfc_buf->used = 0;
+ index = vb->index;
+
+ dec->assigned_fd[index] = vb->planes[0].m.fd;
+ mfc_debug(2, "[DPB] Assigned FD[%d] = %d (%s)\n", index, dec->assigned_fd[index],
+ (dec->dynamic_used & (1 << index) ? "used" : "non-used"));
+
+ list_add_tail(&mfc_buf->list, &ctx->dst_buf_queue.head);
+ ctx->dst_buf_queue.count++;
+
+ spin_unlock_irqrestore(&ctx->buf_queue_lock, flags);
+}
+
+void s5p_mfc_cleanup_nal_queue(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ struct s5p_mfc_buf *src_mb, *dst_mb;
+ unsigned long flags;
+ unsigned int index;
+
+ spin_lock_irqsave(&ctx->buf_queue_lock, flags);
+
+ while (!list_empty(&ctx->src_buf_nal_queue.head)) {
+ src_mb = list_entry(ctx->src_buf_nal_queue.head.prev, struct s5p_mfc_buf, list);
+
+ index = src_mb->vb.vb2_buf.index;
+ call_cop(ctx, recover_buf_ctrls_nal_q, ctx, &ctx->src_ctrls[index]);
+
+ src_mb->used = 0;
+
+ /* If it is not buffer batch mode, index is always zero */
+ if (src_mb->next_index > src_mb->done_index) {
+ mfc_debug(2, "[NALQ][BUFCON] batch buf next index[%d] recover to [%d]\n",
+ src_mb->next_index, src_mb->done_index);
+ src_mb->next_index = src_mb->done_index;
+ }
+
+ list_del(&src_mb->list);
+ ctx->src_buf_nal_queue.count--;
+
+ list_add(&src_mb->list, &ctx->src_buf_queue.head);
+ ctx->src_buf_queue.count++;
+
+ mfc_debug(2, "[NALQ] cleanup, src_buf_nal_queue -> src_buf_queue, index:%d\n",
+ src_mb->vb.vb2_buf.index);
+ }
+
+ while (!list_empty(&ctx->dst_buf_nal_queue.head)) {
+ dst_mb = list_entry(ctx->dst_buf_nal_queue.head.prev, struct s5p_mfc_buf, list);
+
+ dst_mb->used = 0;
+ if (ctx->type == MFCINST_DECODER)
+ clear_bit(dst_mb->vb.vb2_buf.index, &dec->available_dpb);
+ list_del(&dst_mb->list);
+ ctx->dst_buf_nal_queue.count--;
+
+ list_add(&dst_mb->list, &ctx->dst_buf_queue.head);
+ ctx->dst_buf_queue.count++;
+
+ mfc_debug(2, "[NALQ] cleanup, dst_buf_nal_queue -> dst_buf_queue, index:%d\n",
+ dst_mb->vb.vb2_buf.index);
+ }
+
+ spin_unlock_irqrestore(&ctx->buf_queue_lock, flags);
+}
+
+int s5p_mfc_is_last_frame(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_buf *src_mb;
+ struct s5p_mfc_dev *dev;
+ unsigned long flags;
+
+ mfc_debug_enter();
+
+ if (!ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return -EINVAL;
+ }
+
+ dev = ctx->dev;
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&ctx->buf_queue_lock, flags);
+
+ if (list_empty(&ctx->src_buf_queue.head)) {
+ mfc_debug(2, "src_buf_queue is empty\n");
+ spin_unlock_irqrestore(&ctx->buf_queue_lock, flags);
+ return -EINVAL;
+ }
+
+ src_mb = list_entry(ctx->src_buf_queue.head.next, struct s5p_mfc_buf, list);
+
+ mfc_debug(4, "addr[0]: 0x%08llx\n", src_mb->addr[0][0]);
+
+ if (src_mb->vb.reserved2 & FLAG_LAST_FRAME) {
+ mfc_debug(2, "last frame!\n");
+ spin_unlock_irqrestore(&ctx->buf_queue_lock, flags);
+ return 1;
+ }
+
+ mfc_debug(4, "not last frame!\n");
+ spin_unlock_irqrestore(&ctx->buf_queue_lock, flags);
+
+ mfc_debug_leave();
+
+ return 0;
+}
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_queue.h
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __MFC_QUEUE_H
+#define __MFC_QUEUE_H __FILE__
+
+#include "mfc_common.h"
+
+/**
+ * enum s5p_mfc_queue_used_type
+ */
+enum s5p_mfc_queue_used_type {
+ MFC_BUF_NO_TOUCH_USED = -1,
+ MFC_BUF_RESET_USED = 0,
+ MFC_BUF_SET_USED = 1,
+};
+
+/**
+ * enum s5p_mfc_queue_top_type
+ */
+enum s5p_mfc_queue_top_type {
+ MFC_QUEUE_ADD_BOTTOM = 0,
+ MFC_QUEUE_ADD_TOP = 1,
+};
+
+static inline unsigned int s5p_mfc_get_queue_count(spinlock_t *plock, struct s5p_mfc_buf_queue *queue)
+{
+ unsigned long flags;
+ unsigned int ret = 0;
+
+ spin_lock_irqsave(plock, flags);
+ ret = queue->count;
+ spin_unlock_irqrestore(plock, flags);
+
+ return ret;
+}
+
+static inline int s5p_mfc_is_queue_count_same(spinlock_t *plock, struct s5p_mfc_buf_queue *queue,
+ unsigned int value)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(plock, flags);
+ if (queue->count == value)
+ ret = 1;
+ spin_unlock_irqrestore(plock, flags);
+
+ return ret;
+}
+
+static inline int s5p_mfc_is_queue_count_greater(spinlock_t *plock, struct s5p_mfc_buf_queue *queue,
+ unsigned int value)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(plock, flags);
+ if (queue->count > value)
+ ret = 1;
+ spin_unlock_irqrestore(plock, flags);
+
+ return ret;
+}
+
+static inline int s5p_mfc_is_queue_count_smaller(spinlock_t *plock, struct s5p_mfc_buf_queue *queue,
+ unsigned int value)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(plock, flags);
+ if (queue->count < value)
+ ret = 1;
+ spin_unlock_irqrestore(plock, flags);
+
+ return ret;
+}
+
+static inline void s5p_mfc_init_queue(struct s5p_mfc_buf_queue *queue)
+{
+ INIT_LIST_HEAD(&queue->head);
+ queue->count = 0;
+}
+
+static inline void s5p_mfc_create_queue(struct s5p_mfc_buf_queue *queue)
+{
+ s5p_mfc_init_queue(queue);
+}
+
+static inline void s5p_mfc_delete_queue(struct s5p_mfc_buf_queue *queue)
+{
+ s5p_mfc_init_queue(queue);
+}
+
+void s5p_mfc_add_tail_buf(spinlock_t *plock, struct s5p_mfc_buf_queue *queue,
+ struct s5p_mfc_buf *mfc_buf);
+
+int s5p_mfc_peek_buf_csd(spinlock_t *plock, struct s5p_mfc_buf_queue *queue);
+
+struct s5p_mfc_buf *s5p_mfc_get_buf(spinlock_t *plock, struct s5p_mfc_buf_queue *queue,
+ enum s5p_mfc_queue_used_type used);
+struct s5p_mfc_buf *s5p_mfc_get_del_buf(spinlock_t *plock, struct s5p_mfc_buf_queue *queue,
+ enum s5p_mfc_queue_used_type used);
+struct s5p_mfc_buf *s5p_mfc_get_del_if_consumed(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf_queue *queue,
+ unsigned long consumed, unsigned int min_bytes, int err, int *deleted);
+struct s5p_mfc_buf *s5p_mfc_get_move_buf(spinlock_t *plock,
+ struct s5p_mfc_buf_queue *to_queue, struct s5p_mfc_buf_queue *from_queue,
+ enum s5p_mfc_queue_used_type used, enum s5p_mfc_queue_top_type top);
+struct s5p_mfc_buf *s5p_mfc_get_move_buf_used(spinlock_t *plock,
+ struct s5p_mfc_buf_queue *to_queue, struct s5p_mfc_buf_queue *from_queue);
+struct s5p_mfc_buf *s5p_mfc_get_move_buf_addr(spinlock_t *plock,
+ struct s5p_mfc_buf_queue *to_queue, struct s5p_mfc_buf_queue *from_queue,
+ dma_addr_t addr);
+
+struct s5p_mfc_buf *s5p_mfc_find_first_buf(spinlock_t *plock, struct s5p_mfc_buf_queue *queue,
+ dma_addr_t addr);
+struct s5p_mfc_buf *s5p_mfc_find_buf(spinlock_t *plock, struct s5p_mfc_buf_queue *queue,
+ dma_addr_t addr);
+struct s5p_mfc_buf *s5p_mfc_find_del_buf(spinlock_t *plock, struct s5p_mfc_buf_queue *queue,
+ dma_addr_t addr);
+struct s5p_mfc_buf *s5p_mfc_find_move_buf(spinlock_t *plock,
+ struct s5p_mfc_buf_queue *to_queue, struct s5p_mfc_buf_queue *from_queue,
+ dma_addr_t addr, unsigned int released_flag);
+struct s5p_mfc_buf *s5p_mfc_find_move_buf_used(spinlock_t *plock,
+ struct s5p_mfc_buf_queue *to_queue, struct s5p_mfc_buf_queue *from_queue,
+ dma_addr_t addr);
+
+void s5p_mfc_move_first_buf_used(spinlock_t *plock, struct s5p_mfc_buf_queue *to_queue,
+ struct s5p_mfc_buf_queue *from_queue, enum s5p_mfc_queue_top_type top);
+void s5p_mfc_move_all_bufs(spinlock_t *plock, struct s5p_mfc_buf_queue *to_queue,
+ struct s5p_mfc_buf_queue *from_queue, enum s5p_mfc_queue_top_type top);
+
+void s5p_mfc_cleanup_queue(spinlock_t *plock, struct s5p_mfc_buf_queue *queue);
+
+void s5p_mfc_handle_released_info(struct s5p_mfc_ctx *ctx,
+ unsigned int released_flag, int index);
+
+struct s5p_mfc_buf *s5p_mfc_move_reuse_buffer(struct s5p_mfc_ctx *ctx, int release_index);
+
+void s5p_mfc_cleanup_enc_src_queue(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_cleanup_enc_dst_queue(struct s5p_mfc_ctx *ctx);
+
+struct s5p_mfc_buf *s5p_mfc_search_for_dpb(struct s5p_mfc_ctx *ctx, unsigned int dynamic_used);
+struct s5p_mfc_buf *s5p_mfc_search_move_dpb_nal_q(struct s5p_mfc_ctx *ctx, unsigned int dynamic_used);
+void s5p_mfc_store_dpb(struct s5p_mfc_ctx *ctx, struct vb2_buffer *vb);
+
+void s5p_mfc_cleanup_nal_queue(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_is_last_frame(struct s5p_mfc_ctx *ctx);
+
+#endif /* __MFC_QUEUE_H */
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_reg.c
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/delay.h>
+
+#include "mfc_reg.h"
+
+void s5p_mfc_dbg_enable(struct s5p_mfc_dev *dev)
+{
+ mfc_debug(2, "MFC debug info enable\n");
+ MFC_WRITEL(0x1, S5P_FIMV_DBG_INFO_ENABLE);
+}
+
+void s5p_mfc_dbg_disable(struct s5p_mfc_dev *dev)
+{
+ mfc_debug(2, "MFC debug info disable\n");
+ MFC_WRITEL(0x0, S5P_FIMV_DBG_INFO_ENABLE);
+}
+
+void s5p_mfc_dbg_set_addr(struct s5p_mfc_dev *dev)
+{
+ struct s5p_mfc_ctx_buf_size *buf_size = dev->variant->buf_size->ctx_buf;
+
+ memset((void *)dev->dbg_info_buf.vaddr, 0, buf_size->dbg_info_buf);
+
+ MFC_WRITEL(dev->dbg_info_buf.daddr, S5P_FIMV_DBG_BUFFER_ADDR);
+ MFC_WRITEL(buf_size->dbg_info_buf, S5P_FIMV_DBG_BUFFER_SIZE);
+}
+
+void s5p_mfc_otf_set_frame_addr(struct s5p_mfc_ctx *ctx, int num_planes)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct _otf_handle *handle = ctx->otf_handle;
+ struct _otf_buf_addr *buf_addr = &handle->otf_buf_addr;
+ int index = handle->otf_buf_index;
+ int i;
+
+ for (i = 0; i < num_planes; i++) {
+ mfc_debug(2, "[OTF][FRAME] set frame buffer[%d], 0x%08llx)\n",
+ i, buf_addr->otf_daddr[index][i]);
+ MFC_WRITEL(buf_addr->otf_daddr[index][i],
+ S5P_FIMV_E_SOURCE_FIRST_ADDR + (i * 4));
+ }
+}
+
+void s5p_mfc_otf_set_stream_size(struct s5p_mfc_ctx *ctx, unsigned int size)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct _otf_handle *handle = ctx->otf_handle;
+ struct _otf_debug *debug = &handle->otf_debug;
+ struct s5p_mfc_special_buf *buf;
+
+ mfc_debug(2, "[OTF] set stream buffer full size, %u\n", size);
+ MFC_WRITEL(size, S5P_FIMV_E_STREAM_BUFFER_SIZE);
+
+ if (otf_dump && !ctx->is_drm) {
+ buf = &debug->stream_buf[debug->frame_cnt];
+ mfc_debug(2, "[OTF] set stream addr for debugging\n");
+ mfc_debug(2, "[OTF][STREAM] buf[%d] daddr: 0x%08llx\n",
+ debug->frame_cnt, buf->daddr);
+ MFC_WRITEL(buf->daddr, S5P_FIMV_E_STREAM_BUFFER_ADDR);
+ }
+}
+
+void s5p_mfc_otf_set_hwfc_index(struct s5p_mfc_ctx *ctx, int job_id)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ mfc_debug(2, "[OTF] set hwfc index, %d\n", job_id);
+ HWFC_WRITEL(job_id, HWFC_ENCODING_IDX);
+}
+
+/* Set decoding frame buffer */
+int s5p_mfc_set_dec_codec_buffers(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev;
+ struct s5p_mfc_dec *dec;
+ unsigned int i;
+ size_t frame_size_mv;
+ dma_addr_t buf_addr;
+ int buf_size;
+ int align_gap;
+ struct s5p_mfc_raw_info *raw;
+ unsigned int reg = 0;
+
+ if (!ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return -EINVAL;
+ }
+
+ dev = ctx->dev;
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ dec = ctx->dec_priv;
+ if (!dec) {
+ mfc_err_dev("no mfc decoder to run\n");
+ return -EINVAL;
+ }
+
+ raw = &ctx->raw_buf;
+ buf_addr = ctx->codec_buf.daddr;
+ buf_size = ctx->codec_buf.size;
+
+ mfc_debug(2, "[MEMINFO] codec buf 0x%llx size: %d\n", buf_addr, buf_size);
+ mfc_debug(2, "Total DPB COUNT: %d, display delay: %d\n",
+ dec->total_dpb_count, dec->display_delay);
+
+ /* set decoder DPB size, stride */
+ MFC_WRITEL(dec->total_dpb_count, S5P_FIMV_D_NUM_DPB);
+ for (i = 0; i < raw->num_planes; i++) {
+ mfc_debug(2, "[FRAME] buf[%d] size: %d, stride: %d\n",
+ i, raw->plane_size[i], raw->stride[i]);
+ MFC_WRITEL(raw->plane_size[i], S5P_FIMV_D_FIRST_PLANE_DPB_SIZE + (i * 4));
+ MFC_WRITEL(ctx->raw_buf.stride[i],
+ S5P_FIMV_D_FIRST_PLANE_DPB_STRIDE_SIZE + (i * 4));
+ if (ctx->is_10bit) {
+ MFC_WRITEL(raw->stride_2bits[i], S5P_FIMV_D_FIRST_PLANE_2BIT_DPB_STRIDE_SIZE + (i * 4));
+ MFC_WRITEL(raw->plane_size_2bits[i], S5P_FIMV_D_FIRST_PLANE_2BIT_DPB_SIZE + (i * 4));
+ mfc_debug(2, "[FRAME][10BIT] 2bits buf[%d] size: %d, stride: %d\n",
+ i, raw->plane_size_2bits[i], raw->stride_2bits[i]);
+ }
+ }
+
+ /* set codec buffers */
+ MFC_WRITEL(buf_addr, S5P_FIMV_D_SCRATCH_BUFFER_ADDR);
+ MFC_WRITEL(ctx->scratch_buf_size, S5P_FIMV_D_SCRATCH_BUFFER_SIZE);
+ buf_addr += ctx->scratch_buf_size;
+ buf_size -= ctx->scratch_buf_size;
+
+ if (IS_H264_DEC(ctx) || IS_H264_MVC_DEC(ctx) || IS_HEVC_DEC(ctx) || IS_BPG_DEC(ctx))
+ MFC_WRITEL(ctx->mv_size, S5P_FIMV_D_MV_BUFFER_SIZE);
+
+ if (IS_VP9_DEC(ctx)){
+ MFC_WRITEL(buf_addr, S5P_FIMV_D_STATIC_BUFFER_ADDR);
+ MFC_WRITEL(DEC_STATIC_BUFFER_SIZE, S5P_FIMV_D_STATIC_BUFFER_SIZE);
+ buf_addr += DEC_STATIC_BUFFER_SIZE;
+ buf_size -= DEC_STATIC_BUFFER_SIZE;
+ }
+
+ if (IS_MPEG4_DEC(ctx) && dec->loop_filter_mpeg4) {
+ mfc_debug(2, "Add DPB for loop filter of MPEG4\n");
+ for (i = 0; i < NUM_MPEG4_LF_BUF; i++) {
+ MFC_WRITEL(buf_addr, S5P_FIMV_D_POST_FILTER_LUMA_DPB0 + (4 * i));
+ buf_addr += ctx->loopfilter_luma_size;
+ buf_size -= ctx->loopfilter_luma_size;
+
+ MFC_WRITEL(buf_addr, S5P_FIMV_D_POST_FILTER_CHROMA_DPB0 + (4 * i));
+ buf_addr += ctx->loopfilter_chroma_size;
+ buf_size -= ctx->loopfilter_chroma_size;
+ }
+ reg |= ((dec->loop_filter_mpeg4 & S5P_FIMV_D_INIT_BUF_OPT_LF_CTRL_MASK)
+ << S5P_FIMV_D_INIT_BUF_OPT_LF_CTRL_SHIFT);
+ }
+
+ reg |= (0x1 << S5P_FIMV_D_INIT_BUF_OPT_DYNAMIC_DPB_SET_SHIFT);
+
+ if (CODEC_NOT_CODED(ctx)) {
+ reg |= (0x1 << S5P_FIMV_D_INIT_BUF_OPT_COPY_NOT_CODED_SHIFT);
+ mfc_debug(2, "Notcoded frame copy mode start\n");
+ }
+ /* Enable 10bit Dithering */
+ if (ctx->is_10bit) {
+ reg |= (0x1 << S5P_FIMV_D_INIT_BUF_OPT_DITHERING_EN_SHIFT);
+ /* 64byte align, It is vaid only for VP9 */
+ reg |= (0x1 << S5P_FIMV_D_INIT_BUF_OPT_STRIDE_SIZE_ALIGN);
+ } else {
+ /* 16byte align, It is vaid only for VP9 */
+ reg &= ~(0x1 << S5P_FIMV_D_INIT_BUF_OPT_STRIDE_SIZE_ALIGN);
+ }
+
+ MFC_WRITEL(reg, S5P_FIMV_D_INIT_BUFFER_OPTIONS);
+
+ frame_size_mv = ctx->mv_size;
+ MFC_WRITEL(dec->mv_count, S5P_FIMV_D_NUM_MV);
+ if (IS_H264_DEC(ctx) || IS_H264_MVC_DEC(ctx) || IS_HEVC_DEC(ctx) || IS_BPG_DEC(ctx)) {
+ for (i = 0; i < dec->mv_count; i++) {
+ /* To test alignment */
+ align_gap = buf_addr;
+ buf_addr = ALIGN(buf_addr, 16);
+ align_gap = buf_addr - align_gap;
+ buf_size -= align_gap;
+
+ MFC_WRITEL(buf_addr, S5P_FIMV_D_MV_BUFFER0 + i * 4);
+ buf_addr += frame_size_mv;
+ buf_size -= frame_size_mv;
+ }
+ }
+
+ mfc_debug(2, "[MEMINFO] codec buf 0x%llx, remained size: %d\n", buf_addr, buf_size);
+ if (buf_size < 0) {
+ mfc_debug(2, "[MEMINFO] Not enough memory has been allocated\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/* Set encoding ref & codec buffer */
+int s5p_mfc_set_enc_codec_buffers(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ dma_addr_t buf_addr;
+ int buf_size;
+ int i;
+
+ mfc_debug_enter();
+
+ buf_addr = ctx->codec_buf.daddr;
+ buf_size = ctx->codec_buf.size;
+
+ mfc_debug(2, "[MEMINFO] codec buf 0x%llx, size: %d\n", buf_addr, buf_size);
+ mfc_debug(2, "DPB COUNT: %d\n", ctx->dpb_count);
+
+ MFC_WRITEL(buf_addr, S5P_FIMV_E_SCRATCH_BUFFER_ADDR);
+ MFC_WRITEL(ctx->scratch_buf_size, S5P_FIMV_E_SCRATCH_BUFFER_SIZE);
+ buf_addr += ctx->scratch_buf_size;
+ buf_size -= ctx->scratch_buf_size;
+
+ /* start address of per buffer is aligned */
+ for (i = 0; i < ctx->dpb_count; i++) {
+ MFC_WRITEL(buf_addr, S5P_FIMV_E_LUMA_DPB + (4 * i));
+ buf_addr += enc->luma_dpb_size;
+ buf_size -= enc->luma_dpb_size;
+ }
+ for (i = 0; i < ctx->dpb_count; i++) {
+ MFC_WRITEL(buf_addr, S5P_FIMV_E_CHROMA_DPB + (4 * i));
+ buf_addr += enc->chroma_dpb_size;
+ buf_size -= enc->chroma_dpb_size;
+ }
+ for (i = 0; i < ctx->dpb_count; i++) {
+ MFC_WRITEL(buf_addr, S5P_FIMV_E_ME_BUFFER + (4 * i));
+ buf_addr += enc->me_buffer_size;
+ buf_size -= enc->me_buffer_size;
+ }
+
+ MFC_WRITEL(buf_addr, S5P_FIMV_E_TMV_BUFFER0);
+ buf_addr += enc->tmv_buffer_size >> 1;
+ MFC_WRITEL(buf_addr, S5P_FIMV_E_TMV_BUFFER1);
+ buf_addr += enc->tmv_buffer_size >> 1;
+ buf_size -= enc->tmv_buffer_size;
+
+ mfc_debug(2, "[MEMINFO] codec buf 0x%llx, remained size: %d\n", buf_addr, buf_size);
+ if (buf_size < 0) {
+ mfc_debug(2, "[MEMINFO] Not enough memory has been allocated\n");
+ return -ENOMEM;
+ }
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+/* Set registers for decoding stream buffer */
+int s5p_mfc_set_dec_stream_buffer(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *mfc_buf,
+ unsigned int start_num_byte, unsigned int strm_size)
+{
+ struct s5p_mfc_dev *dev;
+ struct s5p_mfc_dec *dec;
+ unsigned int cpb_buf_size;
+ dma_addr_t addr;
+ int index = -1;
+
+ mfc_debug_enter();
+ if (!ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return -EINVAL;
+ }
+ dev = ctx->dev;
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+ dec = ctx->dec_priv;
+ if (!dec) {
+ mfc_err_dev("no mfc decoder to run\n");
+ return -EINVAL;
+ }
+
+ cpb_buf_size = ALIGN(dec->src_buf_size, STREAM_BUF_ALIGN);
+
+ if (mfc_buf) {
+ index = mfc_buf->vb.vb2_buf.index;
+ addr = mfc_buf->addr[0][0];
+ if (strm_size > set_strm_size_max(cpb_buf_size)) {
+ mfc_info_ctx("Decrease strm_size because of %d align: %u -> %u\n",
+ STREAM_BUF_ALIGN, strm_size, set_strm_size_max(cpb_buf_size));
+ strm_size = set_strm_size_max(cpb_buf_size);
+ mfc_buf->vb.vb2_buf.planes[0].bytesused = strm_size;
+ }
+ } else {
+ addr = 0;
+ }
+
+ mfc_debug(2, "[BUFINFO] ctx[%d] set src index: %d, addr: 0x%08llx\n",
+ ctx->num, index, addr);
+ mfc_debug(2, "[STREAM] strm_size: %#lx(%d), buf_size: %u, offset: %u\n",
+ strm_size, strm_size, cpb_buf_size, start_num_byte);
+
+ if (strm_size == 0)
+ mfc_info_ctx("stream size is 0\n");
+
+ MFC_WRITEL(strm_size, S5P_FIMV_D_STREAM_DATA_SIZE);
+ MFC_WRITEL(addr, S5P_FIMV_D_CPB_BUFFER_ADDR);
+ MFC_WRITEL(cpb_buf_size, S5P_FIMV_D_CPB_BUFFER_SIZE);
+ MFC_WRITEL(start_num_byte, S5P_FIMV_D_CPB_BUFFER_OFFSET);
+
+ if (mfc_buf)
+ MFC_TRACE_CTX("Set src[%d] fd: %d, %#llx\n",
+ index, mfc_buf->vb.vb2_buf.planes[0].m.fd, addr);
+
+ mfc_debug_leave();
+ return 0;
+}
+
+void s5p_mfc_set_enc_frame_buffer(struct s5p_mfc_ctx *ctx,
+ struct s5p_mfc_buf *mfc_buf, int num_planes)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ dma_addr_t addr[3] = { 0, 0, 0 };
+ dma_addr_t addr_2bit[2] = { 0, 0 };
+ int index, i;
+
+ if (!mfc_buf) {
+ mfc_debug(3, "enc zero buffer set\n");
+ goto buffer_set;
+ }
+
+ index = mfc_buf->vb.vb2_buf.index;
+ if (mfc_buf->num_valid_bufs > 0) {
+ for (i = 0; i < num_planes; i++) {
+ addr[i] = mfc_buf->addr[mfc_buf->next_index][i];
+ mfc_debug(2, "[BUFCON][BUFINFO] ctx[%d] set src index:%d, batch[%d], addr[%d]: 0x%08llx\n",
+ ctx->num, index, mfc_buf->next_index, i, addr[i]);
+ }
+ mfc_buf->next_index++;
+ } else {
+ for (i = 0; i < num_planes; i++) {
+ addr[i] = mfc_buf->addr[0][i];
+ mfc_debug(2, "[BUFINFO] ctx[%d] set src index:%d, addr[%d]: 0x%08llx\n",
+ ctx->num, index, i, addr[i]);
+ }
+ }
+
+buffer_set:
+ for (i = 0; i < num_planes; i++)
+ MFC_WRITEL(addr[i], S5P_FIMV_E_SOURCE_FIRST_ADDR + (i * 4));
+
+ if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M_S10B ||
+ ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV21M_S10B) {
+ addr_2bit[0] = addr[0] + NV12N_10B_Y_8B_SIZE(ctx->img_width, ctx->img_height);
+ addr_2bit[1] = addr[1] + NV12N_10B_CBCR_8B_SIZE(ctx->img_width, ctx->img_height);
+
+ for (i = 0; i < num_planes; i++) {
+ MFC_WRITEL(addr_2bit[i], S5P_FIMV_E_SOURCE_FIRST_2BIT_ADDR + (i * 4));
+ mfc_debug(2, "[BUFINFO][10BIT] ctx[%d] set src 2bit addr[%d]: 0x%08llx\n",
+ ctx->num, i, addr_2bit[i]);
+ }
+ } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV16M_S10B ||
+ ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV61M_S10B) {
+ addr_2bit[0] = addr[0] + NV16M_Y_SIZE(ctx->img_width, ctx->img_height);
+ addr_2bit[1] = addr[1] + NV16M_CBCR_SIZE(ctx->img_width, ctx->img_height);
+
+ for (i = 0; i < num_planes; i++) {
+ MFC_WRITEL(addr_2bit[i], S5P_FIMV_E_SOURCE_FIRST_2BIT_ADDR + (i * 4));
+ mfc_debug(2, "[BUFINFO][10BIT] ctx[%d] set src 2bit addr[%d]: 0x%08llx\n",
+ ctx->num, i, addr_2bit[i]);
+ }
+ }
+}
+
+/* Set registers for encoding stream buffer */
+int s5p_mfc_set_enc_stream_buffer(struct s5p_mfc_ctx *ctx,
+ struct s5p_mfc_buf *mfc_buf)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ dma_addr_t addr;
+ unsigned int size, offset, index;
+
+ index = mfc_buf->vb.vb2_buf.index;
+ addr = mfc_buf->addr[0][0];
+ offset = mfc_buf->vb.vb2_buf.planes[0].data_offset;
+ size = (unsigned int)vb2_plane_size(&mfc_buf->vb.vb2_buf, 0);
+ size = ALIGN(size, 512);
+
+ MFC_WRITEL(addr, S5P_FIMV_E_STREAM_BUFFER_ADDR); /* 16B align */
+ MFC_WRITEL(size, S5P_FIMV_E_STREAM_BUFFER_SIZE);
+ MFC_WRITEL(offset, S5P_FIMV_E_STREAM_BUFFER_OFFSET);
+
+ mfc_debug(2, "[BUFINFO] ctx[%d] set dst index: %d, addr: 0x%08llx\n",
+ ctx->num, index, addr);
+ mfc_debug(2, "[STREAM] buf_size: %u, offset: %d\n", size, offset);
+
+ return 0;
+}
+
+void s5p_mfc_get_enc_frame_buffer(struct s5p_mfc_ctx *ctx,
+ dma_addr_t addr[], int num_planes)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ unsigned long enc_recon_y_addr, enc_recon_c_addr;
+ int i, addr_offset;
+
+ addr_offset = S5P_FIMV_E_ENCODED_SOURCE_FIRST_ADDR;
+
+ for (i = 0; i < num_planes; i++)
+ addr[i] = MFC_READL(addr_offset + (i * 4));
+
+ enc_recon_y_addr = MFC_READL(S5P_FIMV_E_RECON_LUMA_DPB_ADDR);
+ enc_recon_c_addr = MFC_READL(S5P_FIMV_E_RECON_CHROMA_DPB_ADDR);
+
+ mfc_debug(2, "[MEMINFO] recon y: 0x%08lx c: 0x%08lx\n",
+ enc_recon_y_addr, enc_recon_c_addr);
+}
+
+void s5p_mfc_set_enc_stride(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ int i;
+
+ for (i = 0; i < ctx->raw_buf.num_planes; i++) {
+ MFC_WRITEL(ctx->raw_buf.stride[i],
+ S5P_FIMV_E_SOURCE_FIRST_STRIDE + (i * 4));
+ mfc_debug(2, "[FRAME] enc src plane[%d] stride: %d\n",
+ i, ctx->raw_buf.stride[i]);
+ }
+}
+
+int s5p_mfc_set_dynamic_dpb(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *dst_mb)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ struct s5p_mfc_raw_info *raw = &ctx->raw_buf;
+ int dst_index;
+ int i;
+
+ dst_index = dst_mb->vb.vb2_buf.index;
+ set_bit(dst_index, &dec->available_dpb);
+ dec->dynamic_set = 1 << dst_index;
+ mfc_debug(2, "[DPB] ADDING Flag after: 0x%lx\n", dec->available_dpb);
+
+ /* for debugging about black bar detection */
+ if (MFC_FEATURE_SUPPORT(dev, dev->pdata->black_bar) && dec->detect_black_bar) {
+ for (i = 0; i < raw->num_planes; i++) {
+ dec->frame_vaddr[i][dec->frame_cnt] = vb2_plane_vaddr(&dst_mb->vb.vb2_buf, i);
+ dec->frame_daddr[i][dec->frame_cnt] = dst_mb->addr[0][i];
+ dec->frame_size[i][dec->frame_cnt] = raw->plane_size[i];
+ dec->index[i][dec->frame_cnt] = dst_index;
+ dec->fd[i][dec->frame_cnt] = dst_mb->vb.vb2_buf.planes[0].m.fd;
+ }
+ dec->frame_cnt++;
+ if (dec->frame_cnt >= 30)
+ dec->frame_cnt = 0;
+ }
+
+ /* decoder dst buffer CFW PROT */
+ s5p_mfc_protect_dpb(ctx, dst_mb);
+
+ for (i = 0; i < raw->num_planes; i++) {
+ MFC_WRITEL(raw->plane_size[i],
+ S5P_FIMV_D_FIRST_PLANE_DPB_SIZE + i * 4);
+ MFC_WRITEL(dst_mb->addr[0][i],
+ S5P_FIMV_D_FIRST_PLANE_DPB0 + (i * 0x100 + dst_index * 4));
+ if (ctx->is_10bit)
+ MFC_WRITEL(raw->plane_size_2bits[i],
+ S5P_FIMV_D_FIRST_PLANE_2BIT_DPB_SIZE + (i * 4));
+ mfc_debug(2, "[BUFINFO][DPB] ctx[%d] set dst index: %d, addr[%d]: 0x%08llx\n",
+ ctx->num, dst_index, i, dst_mb->addr[0][i]);
+ }
+
+ MFC_TRACE_CTX("Set dst[%d] fd: %d, %#llx / avail %#lx used %#x\n",
+ dst_index, dst_mb->vb.vb2_buf.planes[0].m.fd, dst_mb->addr[0][0],
+ dec->available_dpb, dec->dynamic_used);
+
+ return 0;
+}
+
+void s5p_mfc_set_pixel_format(struct s5p_mfc_dev *dev, unsigned int format)
+{
+ unsigned int reg = 0;
+ unsigned int pix_val, mem_type_10bit = 0;
+
+ if (dev->pdata->P010_decoding)
+ mem_type_10bit = 1;
+
+ switch (format) {
+ case V4L2_PIX_FMT_NV12M:
+ case V4L2_PIX_FMT_NV12N:
+ case V4L2_PIX_FMT_NV12MT_16X16:
+ case V4L2_PIX_FMT_NV16M:
+ pix_val = 0;
+ break;
+ case V4L2_PIX_FMT_NV21M:
+ case V4L2_PIX_FMT_NV61M:
+ pix_val = 1;
+ break;
+ case V4L2_PIX_FMT_YVU420M:
+ pix_val = 2;
+ break;
+ case V4L2_PIX_FMT_YUV420M:
+ case V4L2_PIX_FMT_YUV420N:
+ pix_val = 3;
+ break;
+ /* For 10bit direct set */
+ case V4L2_PIX_FMT_NV12N_10B:
+ case V4L2_PIX_FMT_NV12M_S10B:
+ case V4L2_PIX_FMT_NV16M_S10B:
+ mem_type_10bit = 0;
+ pix_val = 0;
+ break;
+ case V4L2_PIX_FMT_NV12M_P010:
+ case V4L2_PIX_FMT_NV16M_P210:
+ mem_type_10bit = 1;
+ pix_val = 0;
+ break;
+ case V4L2_PIX_FMT_NV21M_S10B:
+ case V4L2_PIX_FMT_NV61M_S10B:
+ mem_type_10bit = 0;
+ pix_val = 1;
+ break;
+ case V4L2_PIX_FMT_NV21M_P010:
+ case V4L2_PIX_FMT_NV61M_P210:
+ mem_type_10bit = 1;
+ pix_val = 1;
+ break;
+ default:
+ pix_val = 0;
+ break;
+ }
+ reg |= pix_val;
+ reg |= (mem_type_10bit << 4);
+ MFC_WRITEL(reg, S5P_FIMV_PIXEL_FORMAT);
+ mfc_debug(2, "[FRAME] pixel format: %d, mem_type_10bit for 10bit: %d (reg: %#x)\n",
+ pix_val, mem_type_10bit, reg);
+}
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_reg.h
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __MFC_REG_H
+#define __MFC_REG_H __FILE__
+
+#include "mfc_common.h"
+
+#include "mfc_utils.h"
+
+#define MFC_READL(offset) readl(dev->regs_base + (offset))
+#define MFC_WRITEL(data, offset) writel((data), dev->regs_base + (offset))
+
+#define MFC_MMU0_READL(offset) readl(dev->sysmmu0_base + (offset))
+#define MFC_MMU1_READL(offset) readl(dev->sysmmu1_base + (offset))
+
+#define HWFC_WRITEL(data, offset) writel((data), dev->hwfc_base + (offset))
+
+#define MMCACHE_READL(offset) readl(dev->mmcache.base + (offset))
+#define MMCACHE_WRITEL(data, offset) writel((data), dev->mmcache.base + (offset))
+
+/* version */
+#define s5p_mfc_get_fimv_info() ((MFC_READL(S5P_FIMV_FW_VERSION) \
+ >> S5P_FIMV_FW_VER_INFO_SHFT) \
+ & S5P_FIMV_FW_VER_INFO_MASK)
+#define s5p_mfc_get_fw_ver_year() ((MFC_READL(S5P_FIMV_FW_VERSION) \
+ >> S5P_FIMV_FW_VER_YEAR_SHFT) \
+ & S5P_FIMV_FW_VER_YEAR_MASK)
+#define s5p_mfc_get_fw_ver_month() ((MFC_READL(S5P_FIMV_FW_VERSION) \
+ >> S5P_FIMV_FW_VER_MONTH_SHFT) \
+ & S5P_FIMV_FW_VER_MONTH_MASK)
+#define s5p_mfc_get_fw_ver_date() ((MFC_READL(S5P_FIMV_FW_VERSION) \
+ >> S5P_FIMV_FW_VER_DATE_SHFT) \
+ & S5P_FIMV_FW_VER_DATE_MASK)
+#define s5p_mfc_get_fw_ver_all() ((MFC_READL(S5P_FIMV_FW_VERSION) \
+ >> S5P_FIMV_FW_VER_ALL_SHFT) \
+ & S5P_FIMV_FW_VER_ALL_MASK)
+#define s5p_mfc_get_mfc_version() ((MFC_READL(S5P_FIMV_MFC_VERSION) \
+ >> S5P_FIMV_MFC_VER_SHFT) \
+ & S5P_FIMV_MFC_VER_MASK)
+
+
+/* decoding & display information */
+#define s5p_mfc_get_dec_status() (MFC_READL(S5P_FIMV_D_DECODED_STATUS) \
+ & S5P_FIMV_DEC_STATUS_DECODED_STATUS_MASK)
+#define s5p_mfc_get_disp_status() (MFC_READL(S5P_FIMV_D_DISPLAY_STATUS) \
+ & S5P_FIMV_DISP_STATUS_DISPLAY_STATUS_MASK)
+#define s5p_mfc_get_res_change() ((MFC_READL(S5P_FIMV_D_DISPLAY_STATUS) \
+ >> S5P_FIMV_DISP_STATUS_RES_CHANGE_SHIFT) \
+ & S5P_FIMV_DISP_STATUS_RES_CHANGE_MASK)
+#define s5p_mfc_get_black_bar_detection() ((MFC_READL(S5P_FIMV_D_DISPLAY_STATUS) \
+ >> S5P_FIMV_DISP_STATUS_BLACK_BAR_DETECT_SHIFT) \
+ & S5P_FIMV_DISP_STATUS_BLACK_BAR_DETECT_MASK)
+#define s5p_mfc_get_dpb_change() ((MFC_READL(S5P_FIMV_D_DISPLAY_STATUS) \
+ >> S5P_FIMV_DISP_STATUS_NEED_DPB_CHANGE_SHIFT) \
+ & S5P_FIMV_DISP_STATUS_NEED_DPB_CHANGE_MASK)
+#define s5p_mfc_get_scratch_change() ((MFC_READL(S5P_FIMV_D_DISPLAY_STATUS) \
+ >> S5P_FIMV_DISP_STATUS_NEED_SCRATCH_CHANGE_SHIFT) \
+ & S5P_FIMV_DISP_STATUS_NEED_SCRATCH_CHANGE_MASK)
+#define s5p_mfc_get_disp_frame_type() (MFC_READL(S5P_FIMV_D_DISPLAY_FRAME_TYPE) \
+ & S5P_FIMV_DISPLAY_FRAME_MASK)
+#define s5p_mfc_get_dec_frame_type() (MFC_READL(S5P_FIMV_D_DECODED_FRAME_TYPE) \
+ & S5P_FIMV_DECODED_FRAME_MASK)
+#define s5p_mfc_get_interlace_type() ((MFC_READL(S5P_FIMV_D_DISPLAY_FRAME_TYPE) \
+ >> S5P_FIMV_DISPLAY_TEMP_INFO_SHIFT) \
+ & S5P_FIMV_DISPLAY_TEMP_INFO_MASK)
+#define s5p_mfc_is_interlace_picture() ((MFC_READL(S5P_FIMV_D_DISPLAY_STATUS) \
+ >> S5P_FIMV_DISP_STATUS_INTERLACE_SHIFT)\
+ & S5P_FIMV_DISP_STATUS_INTERLACE_MASK)
+#define s5p_mfc_is_mbaff_picture() ((MFC_READL(S5P_FIMV_D_H264_INFO) \
+ >> S5P_FIMV_D_H264_INFO_MBAFF_FRAME_FLAG_SHIFT)\
+ & S5P_FIMV_D_H264_INFO_MBAFF_FRAME_FLAG_MASK)
+#define s5p_mfc_get_img_width() MFC_READL(S5P_FIMV_D_DISPLAY_FRAME_WIDTH)
+#define s5p_mfc_get_img_height() MFC_READL(S5P_FIMV_D_DISPLAY_FRAME_HEIGHT)
+#define s5p_mfc_get_disp_y_addr() MFC_READL(S5P_FIMV_D_DISPLAY_LUMA_ADDR)
+#define s5p_mfc_get_dec_y_addr() MFC_READL(S5P_FIMV_D_DECODED_LUMA_ADDR)
+
+
+/* kind of interrupt */
+#define s5p_mfc_get_int_err() MFC_READL(S5P_FIMV_ERROR_CODE)
+#define s5p_mfc_get_err(x) (((x) >> S5P_FIMV_ERR_STATUS_SHIFT) \
+ & S5P_FIMV_ERR_STATUS_MASK)
+#define s5p_mfc_get_warn(x) (((x) >> S5P_FIMV_WARN_STATUS_SHIFT) \
+ & S5P_FIMV_WARN_STATUS_MASK)
+
+
+/* additional information */
+#define s5p_mfc_get_consumed_stream() MFC_READL(S5P_FIMV_D_DECODED_NAL_SIZE)
+#define s5p_mfc_get_dpb_count() MFC_READL(S5P_FIMV_D_MIN_NUM_DPB)
+#define s5p_mfc_get_min_dpb_size(x) MFC_READL(S5P_FIMV_D_MIN_FIRST_PLANE_DPB_SIZE + (x * 4))
+#define s5p_mfc_get_scratch_size() MFC_READL(S5P_FIMV_D_MIN_SCRATCH_BUFFER_SIZE)
+#define s5p_mfc_get_mv_count() MFC_READL(S5P_FIMV_D_MIN_NUM_MV)
+#define s5p_mfc_get_inst_no() MFC_READL(S5P_FIMV_RET_INSTANCE_ID)
+#define s5p_mfc_get_enc_dpb_count() MFC_READL(S5P_FIMV_E_NUM_DPB)
+#define s5p_mfc_get_enc_scratch_size() MFC_READL(S5P_FIMV_E_MIN_SCRATCH_BUFFER_SIZE)
+#define s5p_mfc_get_enc_strm_size() MFC_READL(S5P_FIMV_E_STREAM_SIZE)
+#define s5p_mfc_get_enc_slice_type() MFC_READL(S5P_FIMV_E_SLICE_TYPE)
+#define s5p_mfc_get_enc_pic_count() MFC_READL(S5P_FIMV_E_PICTURE_COUNT)
+#define s5p_mfc_get_sei_avail() MFC_READL(S5P_FIMV_D_SEI_AVAIL)
+#define s5p_mfc_get_sei_content_light() MFC_READL(S5P_FIMV_D_CONTENT_LIGHT_LEVEL_INFO_SEI)
+#define s5p_mfc_get_sei_mastering0() MFC_READL(S5P_FIMV_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_0)
+#define s5p_mfc_get_sei_mastering1() MFC_READL(S5P_FIMV_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_1)
+#define s5p_mfc_get_sei_mastering2() MFC_READL(S5P_FIMV_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_2)
+#define s5p_mfc_get_sei_mastering3() MFC_READL(S5P_FIMV_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_3)
+#define s5p_mfc_get_sei_mastering4() MFC_READL(S5P_FIMV_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_4)
+#define s5p_mfc_get_sei_mastering5() MFC_READL(S5P_FIMV_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_5)
+#define s5p_mfc_get_sei_avail_frame_pack() (MFC_READL(S5P_FIMV_D_SEI_AVAIL) \
+ & S5P_FIMV_D_SEI_AVAIL_FRAME_PACK_MASK)
+#define s5p_mfc_get_sei_avail_content_light() ((MFC_READL(S5P_FIMV_D_SEI_AVAIL) \
+ >> S5P_FIMV_D_SEI_AVAIL_CONTENT_LIGHT_SHIFT) \
+ & S5P_FIMV_D_SEI_AVAIL_CONTENT_LIGHT_MASK)
+#define s5p_mfc_get_sei_avail_mastering_display() ((MFC_READL(S5P_FIMV_D_SEI_AVAIL) \
+ >> S5P_FIMV_D_SEI_AVAIL_MASTERING_DISPLAY_SHIFT) \
+ & S5P_FIMV_D_SEI_AVAIL_MASTERING_DISPLAY_MASK)
+#define s5p_mfc_get_video_signal_type() ((MFC_READL(S5P_FIMV_D_VIDEO_SIGNAL_TYPE) \
+ >> S5P_FIMV_D_VIDEO_SIGNAL_TYPE_FLAG_SHIFT) \
+ & S5P_FIMV_D_VIDEO_SIGNAL_TYPE_FLAG_MASK)
+#define s5p_mfc_get_colour_description() ((MFC_READL(S5P_FIMV_D_VIDEO_SIGNAL_TYPE) \
+ >> S5P_FIMV_D_COLOUR_DESCRIPTION_FLAG_SHIFT) \
+ & S5P_FIMV_D_COLOUR_DESCRIPTION_FLAG_MASK)
+#define s5p_mfc_get_black_bar_pos_x() ((MFC_READL(S5P_FIMV_D_BLACK_BAR_START_POS) \
+ >> S5P_FIMV_D_BLACK_BAR_START_X_SHIFT) \
+ & S5P_FIMV_D_BLACK_BAR_START_X_MASK)
+#define s5p_mfc_get_black_bar_pos_y() ((MFC_READL(S5P_FIMV_D_BLACK_BAR_START_POS) \
+ >> S5P_FIMV_D_BLACK_BAR_START_Y_SHIFT) \
+ & S5P_FIMV_D_BLACK_BAR_START_Y_MASK)
+#define s5p_mfc_get_black_bar_image_w() ((MFC_READL(S5P_FIMV_D_BLACK_BAR_IMAGE_SIZE) \
+ >> S5P_FIMV_D_BLACK_BAR_IMAGE_W_SHIFT) \
+ & S5P_FIMV_D_BLACK_BAR_IMAGE_W_MASK)
+#define s5p_mfc_get_black_bar_image_h() ((MFC_READL(S5P_FIMV_D_BLACK_BAR_IMAGE_SIZE) \
+ >> S5P_FIMV_D_BLACK_BAR_IMAGE_H_SHIFT) \
+ & S5P_FIMV_D_BLACK_BAR_IMAGE_H_MASK)
+#define s5p_mfc_get_mvc_disp_view_id() (MFC_READL(S5P_FIMV_D_MVC_VIEW_ID) \
+ & S5P_FIMV_D_MVC_VIEW_ID_DISP_MASK)
+#define s5p_mfc_get_profile() (MFC_READL(S5P_FIMV_D_DECODED_PICTURE_PROFILE) \
+ & S5P_FIMV_D_DECODED_PIC_PROFILE_MASK)
+#define s5p_mfc_get_luma_bit_depth_minus8() ((MFC_READL(S5P_FIMV_D_DECODED_PICTURE_PROFILE) \
+ >> S5P_FIMV_D_BIT_DEPTH_LUMA_MINUS8_SHIFT) \
+ & S5P_FIMV_D_BIT_DEPTH_LUMA_MINUS8_MASK)
+#define s5p_mfc_get_chroma_bit_depth_minus8() ((MFC_READL(S5P_FIMV_D_DECODED_PICTURE_PROFILE) \
+ >> S5P_FIMV_D_BIT_DEPTH_CHROMA_MINUS8_SHIFT) \
+ & S5P_FIMV_D_BIT_DEPTH_CHROMA_MINUS8_MASK)
+#define s5p_mfc_get_dec_used_flag() MFC_READL(S5P_FIMV_D_USED_DPB_FLAG_LOWER)
+#define s5p_mfc_get_enc_nal_done_info() ((MFC_READL(S5P_FIMV_E_NAL_DONE_INFO) & (0x3 << 4)) >> 4)
+#define s5p_mfc_get_chroma_format() (MFC_READL(S5P_FIMV_D_CHROMA_FORMAT) \
+ & S5P_FIMV_D_CHROMA_FORMAT_MASK)
+#define s5p_mfc_get_color_range() ((MFC_READL(S5P_FIMV_D_CHROMA_FORMAT) \
+ >> S5P_FIMV_D_COLOR_RANGE_SHIFT) \
+ & S5P_FIMV_D_COLOR_RANGE_MASK)
+#define s5p_mfc_get_color_space() ((MFC_READL(S5P_FIMV_D_CHROMA_FORMAT) \
+ >> S5P_FIMV_D_COLOR_SPACE_SHIFT) \
+ & S5P_FIMV_D_COLOR_SPACE_MASK)
+#define s5p_mfc_get_num_of_tile() ((MFC_READL(S5P_FIMV_D_DECODED_STATUS) \
+ >> S5P_FIMV_DEC_STATUS_NUM_OF_TILE_SHIFT) \
+ & S5P_FIMV_DEC_STATUS_NUM_OF_TILE_MASK)
+
+
+/* nal queue information */
+#define s5p_mfc_get_nal_q_input_count() MFC_READL(S5P_FIMV_NAL_QUEUE_INPUT_COUNT)
+#define s5p_mfc_get_nal_q_output_count() MFC_READL(S5P_FIMV_NAL_QUEUE_OUTPUT_COUNT)
+#define s5p_mfc_get_nal_q_input_exe_count() MFC_READL(S5P_FIMV_NAL_QUEUE_INPUT_EXE_COUNT)
+#define s5p_mfc_get_nal_q_info() MFC_READL(S5P_FIMV_NAL_QUEUE_INFO)
+#define s5p_mfc_get_nal_q_input_addr() MFC_READL(S5P_FIMV_NAL_QUEUE_INPUT_ADDR)
+#define s5p_mfc_get_nal_q_input_size() MFC_READL(S5P_FIMV_NAL_QUEUE_INPUT_SIZE)
+#define s5p_mfc_get_nal_q_output_addr() MFC_READL(S5P_FIMV_NAL_QUEUE_OUTPUT_ADDR)
+#define s5p_mfc_get_nal_q_output_ize() MFC_READL(S5P_FIMV_NAL_QUEUE_OUTPUT_SIZE)
+
+static inline void s5p_mfc_reset_nal_queue_registers(struct s5p_mfc_dev *dev)
+{
+ MFC_WRITEL(0x0, S5P_FIMV_NAL_QUEUE_INPUT_COUNT);
+ MFC_WRITEL(0x0, S5P_FIMV_NAL_QUEUE_OUTPUT_COUNT);
+ MFC_WRITEL(0x0, S5P_FIMV_NAL_QUEUE_INPUT_EXE_COUNT);
+ MFC_WRITEL(0x0, S5P_FIMV_NAL_QUEUE_INFO);
+}
+
+static inline void s5p_mfc_update_nal_queue_input(struct s5p_mfc_dev *dev,
+ dma_addr_t addr, unsigned int size)
+{
+ MFC_WRITEL(addr, S5P_FIMV_NAL_QUEUE_INPUT_ADDR);
+ MFC_WRITEL(size, S5P_FIMV_NAL_QUEUE_INPUT_SIZE);
+}
+
+static inline void s5p_mfc_update_nal_queue_output(struct s5p_mfc_dev *dev,
+ dma_addr_t addr, unsigned int size)
+{
+ MFC_WRITEL(addr, S5P_FIMV_NAL_QUEUE_OUTPUT_ADDR);
+ MFC_WRITEL(size, S5P_FIMV_NAL_QUEUE_OUTPUT_SIZE);
+}
+
+static inline void s5p_mfc_update_nal_queue_input_count(struct s5p_mfc_dev *dev,
+ unsigned int input_count)
+{
+ MFC_WRITEL(input_count, S5P_FIMV_NAL_QUEUE_INPUT_COUNT);
+}
+
+static inline void s5p_mfc_dec_store_crop_info(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ u32 left, right, top, bottom;
+
+ left = MFC_READL(S5P_FIMV_D_DISPLAY_CROP_INFO1);
+ right = left >> S5P_FIMV_D_SHARED_CROP_RIGHT_SHIFT;
+ left = left & S5P_FIMV_D_SHARED_CROP_LEFT_MASK;
+ top = MFC_READL(S5P_FIMV_D_DISPLAY_CROP_INFO2);
+ bottom = top >> S5P_FIMV_D_SHARED_CROP_BOTTOM_SHIFT;
+ top = top & S5P_FIMV_D_SHARED_CROP_TOP_MASK;
+
+ dec->cr_left = left;
+ dec->cr_right = right;
+ dec->cr_top = top;
+ dec->cr_bot = bottom;
+}
+
+static inline void s5p_mfc_clear_enc_res_change(struct s5p_mfc_dev *dev)
+{
+ unsigned int reg = 0;
+
+ reg = MFC_READL(S5P_FIMV_E_PARAM_CHANGE);
+ reg &= ~(0x7 << 6);
+ MFC_WRITEL(reg, S5P_FIMV_E_PARAM_CHANGE);
+}
+
+static inline void s5p_mfc_clear_roi_enable(struct s5p_mfc_dev *dev)
+{
+ unsigned int reg = 0;
+
+ reg = MFC_READL(S5P_FIMV_E_RC_ROI_CTRL);
+ reg &= ~(0x1);
+ MFC_WRITEL(reg, S5P_FIMV_E_RC_ROI_CTRL);
+}
+
+void s5p_mfc_dbg_enable(struct s5p_mfc_dev *dev);
+void s5p_mfc_dbg_disable(struct s5p_mfc_dev *dev);
+void s5p_mfc_dbg_set_addr(struct s5p_mfc_dev *dev);
+
+void s5p_mfc_otf_set_frame_addr(struct s5p_mfc_ctx *ctx, int num_planes);
+void s5p_mfc_otf_set_stream_size(struct s5p_mfc_ctx *ctx, unsigned int size);
+void s5p_mfc_otf_set_hwfc_index(struct s5p_mfc_ctx *ctx, int job_id);
+
+int s5p_mfc_set_dec_codec_buffers(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_set_enc_codec_buffers(struct s5p_mfc_ctx *mfc_ctx);
+
+int s5p_mfc_set_dec_stream_buffer(struct s5p_mfc_ctx *ctx,
+ struct s5p_mfc_buf *mfc_buf,
+ unsigned int start_num_byte,
+ unsigned int buf_size);
+
+void s5p_mfc_set_enc_frame_buffer(struct s5p_mfc_ctx *ctx,
+ struct s5p_mfc_buf *mfc_buf, int num_planes);
+int s5p_mfc_set_enc_stream_buffer(struct s5p_mfc_ctx *ctx,
+ struct s5p_mfc_buf *mfc_buf);
+
+void s5p_mfc_get_enc_frame_buffer(struct s5p_mfc_ctx *ctx,
+ dma_addr_t addr[], int num_planes);
+void s5p_mfc_set_enc_stride(struct s5p_mfc_ctx *ctx);
+
+int s5p_mfc_set_dynamic_dpb(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *dst_vb);
+
+void s5p_mfc_set_pixel_format(struct s5p_mfc_dev *dev, unsigned int format);
+
+#endif /* __MFC_REG_H */
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/regs-mfc-v10.h
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __REGS_MFC_V10_H
+#define __REGS_MFC_V10_H __FILE__
+
+#define MFC_MMU_INTERRUPT_STATUS 0x0060
+#define MFC_MMU_FAULT_TRANS_INFO 0x0078
+#define MFC_MMU_FAULT_TRANS_INFO_RW_MASK 0x100000
+#define MFC_MMU_FAULT_TRANS_INFO_AXID_MASK 0xFFFF
+
+#define HWFC_ENCODING_IDX 0x4
+
+/* Codec Common Registers */
+#define S5P_FIMV_RISC_ON 0x0000
+#define S5P_FIMV_RISC2HOST_INT 0x003C
+#define S5P_FIMV_HOST2RISC_INT 0x0044
+#define S5P_FIMV_RISC_BASE_ADDRESS 0x0054
+
+#define S5P_FIMV_MFC_FW_CLOCK 0x1060
+#define S5P_FIMV_MFC_RESET 0x1070
+
+#define S5P_FIMV_HOST2RISC_CMD 0x1100
+#define S5P_FIMV_RISC2HOST_CMD 0x1104
+
+#define S5P_FIMV_MFC_BUS_STATUS 0x7018
+#define S5P_FIMV_MFC_RPEND 0x7028
+#define S5P_FIMV_MFC_WPEND 0x702C
+#define S5P_FIMV_MFC_BUS_RESET_CTRL 0x7110
+#define S5P_FIMV_MFC_OFF 0x7120
+#define S5P_FIMV_MFC_STATE 0x7124
+
+#define S5P_FIMV_FW_VERSION 0xF000
+#define S5P_FIMV_INSTANCE_ID 0xF008
+#define S5P_FIMV_CODEC_TYPE 0xF00C
+#define S5P_FIMV_CONTEXT_MEM_ADDR 0xF014
+#define S5P_FIMV_CONTEXT_MEM_SIZE 0xF018
+#define S5P_FIMV_SHARED_MEM_ADDR 0xF01C
+#define S5P_FIMV_PIXEL_FORMAT 0xF020
+
+#define S5P_FIMV_METADATA_ENABLE 0xF024
+#define S5P_FIMV_MFC_VERSION 0xF028
+#define S5P_FIMV_DBG_INFO_ENABLE 0xF02C
+#define S5P_FIMV_DBG_BUFFER_ADDR 0xF030
+#define S5P_FIMV_DBG_BUFFER_SIZE 0xF034
+
+#define S5P_FIMV_CODEC_CONTROL 0xF038
+#define S5P_FIMV_DEC_TIMEOUT_VALUE 0xF03C
+#define S5P_FIMV_HED_SHARED_MEM_ADDR 0xF040
+
+/* NAL QUEUE */
+#define S5P_FIMV_NAL_QUEUE_INPUT_ADDR 0xF044
+#define S5P_FIMV_NAL_QUEUE_INPUT_SIZE 0xF048
+#define S5P_FIMV_NAL_QUEUE_OUTPUT_ADDR 0xF04C
+#define S5P_FIMV_NAL_QUEUE_OUTPUT_SIZE 0xF050
+#define S5P_FIMV_NAL_QUEUE_INPUT_COUNT 0xF054
+
+#define S5P_FIMV_RET_INSTANCE_ID 0xF070
+#define S5P_FIMV_ERROR_CODE 0xF074
+#define S5P_FIMV_DBG_BUFFER_OUTPUT_SIZE 0xF078
+#define S5P_FIMV_METADATA_STATUS 0xF07C
+
+#define S5P_FIMV_DBG_INFO_STAGE_COUNTER 0xF088
+
+/* NAL QUEUE */
+#define S5P_FIMV_NAL_QUEUE_OUTPUT_COUNT 0xF08C
+#define S5P_FIMV_NAL_QUEUE_INPUT_EXE_COUNT 0xF090
+#define S5P_FIMV_NAL_QUEUE_INFO 0xF094
+
+/* Decoder Registers */
+#define S5P_FIMV_D_CRC_CTRL 0xF0B0
+#define S5P_FIMV_D_DEC_OPTIONS 0xF0B4
+
+#define S5P_FIMV_D_DISPLAY_DELAY 0xF0B8
+
+#define S5P_FIMV_D_SET_FRAME_WIDTH 0xF0BC
+#define S5P_FIMV_D_SET_FRAME_HEIGHT 0xF0C0
+
+#define S5P_FIMV_D_SEI_ENABLE 0xF0C4
+
+#define S5P_FIMV_D_FORCE_PIXEL_VAL 0xF0C8
+
+/* Buffer setting registers */
+/* Session return */
+#define S5P_FIMV_D_MIN_NUM_DPB 0xF0F0
+#define S5P_FIMV_D_MIN_FIRST_PLANE_DPB_SIZE 0xF0F4
+#define S5P_FIMV_D_MIN_SECOND_PLANE_DPB_SIZE 0xF0F8
+#define S5P_FIMV_D_MIN_THIRD_PLANE_DPB_SIZE 0xF0FC
+#define S5P_FIMV_D_MIN_NUM_MV 0xF100
+#define S5P_FIMV_D_MVC_NUM_VIEWS 0xF104
+#define S5P_FIMV_D_MIN_SCRATCH_BUFFER_SIZE 0xF108
+#define S5P_FIMV_D_MIN_FIRST_PLANE_2BIT_DPB_SIZE 0xF10C
+#define S5P_FIMV_D_MIN_SECOND_PLANE_2BIT_DPB_SIZE 0xF110
+#define S5P_FIMV_D_POST_FILTER_LUMA_DPB0 0xF120
+#define S5P_FIMV_D_POST_FILTER_LUMA_DPB1 0xF124
+#define S5P_FIMV_D_POST_FILTER_CHROMA_DPB0 0xF128
+#define S5P_FIMV_D_POST_FILTER_CHROMA_DPB1 0xF12C
+
+/* Buffers */
+#define S5P_FIMV_D_NUM_DPB 0xF130
+#define S5P_FIMV_D_NUM_MV 0xF134
+#define S5P_FIMV_D_FIRST_PLANE_DPB_STRIDE_SIZE 0xF138
+#define S5P_FIMV_D_SECOND_PLANE_DPB_STRIDE_SIZE 0xF13C
+#define S5P_FIMV_D_THIRD_PLANE_DPB_STRIDE_SIZE 0xF140
+#define S5P_FIMV_D_FIRST_PLANE_DPB_SIZE 0xF144
+#define S5P_FIMV_D_SECOND_PLANE_DPB_SIZE 0xF148
+#define S5P_FIMV_D_THIRD_PLANE_DPB_SIZE 0xF14C
+#define S5P_FIMV_D_MV_BUFFER_SIZE 0xF150
+#define S5P_FIMV_D_INIT_BUFFER_OPTIONS 0xF154
+#define S5P_FIMV_D_FIRST_PLANE_DPB0 0xF160
+#define S5P_FIMV_D_SECOND_PLANE_DPB0 0xF260
+#define S5P_FIMV_D_THIRD_PLANE_DPB0 0xF360
+#define S5P_FIMV_D_MV_BUFFER0 0xF460
+#define S5P_FIMV_D_SCRATCH_BUFFER_ADDR 0xF560
+#define S5P_FIMV_D_SCRATCH_BUFFER_SIZE 0xF564
+#define S5P_FIMV_D_METADATA_BUFFER_ADDR 0xF568
+#define S5P_FIMV_D_METADATA_BUFFER_SIZE 0xF56C
+
+#define S5P_FIMV_D_STATIC_BUFFER_ADDR 0xF570
+#define S5P_FIMV_D_STATIC_BUFFER_SIZE 0xF574
+#define S5P_FIMV_D_FIRST_PLANE_2BIT_DPB_SIZE 0xF578
+#define S5P_FIMV_D_SECOND_PLANE_2BIT_DPB_SIZE 0xF57C
+#define S5P_FIMV_D_FIRST_PLANE_2BIT_DPB_STRIDE_SIZE 0xF580
+#define S5P_FIMV_D_SECOND_PLANE_2BIT_DPB_STRIDE_SIZE 0xF584
+
+#define S5P_FIMV_D_NAL_START_OPTIONS 0xF5AC
+
+/* Nal cmd */
+#define S5P_FIMV_D_CPB_BUFFER_ADDR 0xF5B0
+#define S5P_FIMV_D_CPB_BUFFER_SIZE 0xF5B4
+#define S5P_FIMV_D_AVAILABLE_DPB_FLAG_UPPER 0xF5B8
+#define S5P_FIMV_D_AVAILABLE_DPB_FLAG_LOWER 0xF5BC
+#define S5P_FIMV_D_CPB_BUFFER_OFFSET 0xF5C0
+#define S5P_FIMV_D_SLICE_IF_ENABLE 0xF5C4
+#define S5P_FIMV_D_PICTURE_TAG 0xF5C8
+#define S5P_FIMV_D_STREAM_DATA_SIZE 0xF5D0
+#define S5P_FIMV_D_DYNAMIC_DPB_FLAG_UPPER 0xF5D4
+#define S5P_FIMV_D_DYNAMIC_DPB_FLAG_LOWER 0xF5D8
+
+/* Nal return */
+#define S5P_FIMV_D_DISPLAY_FRAME_WIDTH 0xF600
+#define S5P_FIMV_D_DISPLAY_FRAME_HEIGHT 0xF604
+#define S5P_FIMV_D_DISPLAY_STATUS 0xF608
+#define S5P_FIMV_D_DISPLAY_FIRST_PLANE_ADDR 0xF60C
+#define S5P_FIMV_D_DISPLAY_SECOND_PLANE_ADDR 0xF610
+#define S5P_FIMV_D_DISPLAY_THIRD_PLANE_ADDR 0xF614
+#define S5P_FIMV_D_DISPLAY_FRAME_TYPE 0xF618
+#define S5P_FIMV_D_DISPLAY_CROP_INFO1 0xF61C
+#define S5P_FIMV_D_DISPLAY_CROP_INFO2 0xF620
+#define S5P_FIMV_D_DISPLAY_PICTURE_PROFILE 0xF624
+#define S5P_FIMV_D_DISPLAY_FIRST_PLANE_CRC 0xF628
+#define S5P_FIMV_D_DISPLAY_SECOND_PLANE_CRC 0xF62C
+#define S5P_FIMV_D_DISPLAY_THIRD_PLANE_CRC 0xF630
+#define S5P_FIMV_D_DISPLAY_ASPECT_RATIO 0xF634
+#define S5P_FIMV_D_DISPLAY_EXTENDED_AR 0xF638
+#define S5P_FIMV_D_DECODED_FRAME_WIDTH 0xF63C
+#define S5P_FIMV_D_DECODED_FRAME_HEIGHT 0xF640
+#define S5P_FIMV_D_DECODED_STATUS 0xF644
+#define S5P_FIMV_D_DECODED_FIRST_PLANE_ADDR 0xF648
+#define S5P_FIMV_D_DECODED_SECOND_PLANE_ADDR 0xF64C
+#define S5P_FIMV_D_DECODED_THIRD_PLANE_ADDR 0xF650
+#define S5P_FIMV_D_DECODED_FRAME_TYPE 0xF654
+#define S5P_FIMV_D_DECODED_CROP_INFO1 0xF658
+#define S5P_FIMV_D_DECODED_CROP_INFO2 0xF65C
+#define S5P_FIMV_D_DECODED_PICTURE_PROFILE 0xF660
+#define S5P_FIMV_D_DECODED_NAL_SIZE 0xF664
+#define S5P_FIMV_D_DECODED_FIRST_PLANE_CRC 0xF668
+#define S5P_FIMV_D_DECODED_SECOND_PLANE_CRC 0xF66C
+#define S5P_FIMV_D_DECODED_THIRD_PLANE_CRC 0xF670
+#define S5P_FIMV_D_RET_PICTURE_TAG_TOP 0xF674
+#define S5P_FIMV_D_RET_PICTURE_TAG_BOT 0xF678
+#define S5P_FIMV_D_RET_PICTURE_TIME_TOP 0xF67C
+#define S5P_FIMV_D_RET_PICTURE_TIME_BOT 0xF680
+#define S5P_FIMV_D_CHROMA_FORMAT 0xF684
+
+#define S5P_FIMV_D_VC1_INFO 0xF688
+#define S5P_FIMV_D_MPEG4_INFO 0xF68C
+#define S5P_FIMV_D_H264_INFO 0xF690
+#define S5P_FIMV_D_HEVC_INFO 0xF6A0
+#define S5P_FIMV_D_BPG_INFO 0xF6A8
+
+#define S5P_FIMV_D_METADATA_ADDR_CONCEALED_MB 0xF6B0
+#define S5P_FIMV_D_METADATA_SIZE_CONCEALED_MB 0xF6B4
+#define S5P_FIMV_D_METADATA_ADDR_VC1_PARAM 0xF6B8
+#define S5P_FIMV_D_METADATA_SIZE_VC1_PARAM 0xF6BC
+#define S5P_FIMV_D_METADATA_ADDR_SEI_NAL 0xF6C0
+#define S5P_FIMV_D_METADATA_SIZE_SEI_NAL 0xF6C4
+#define S5P_FIMV_D_METADATA_ADDR_VUI 0xF6C8
+#define S5P_FIMV_D_METADATA_SIZE_VUI 0xF6CC
+#define S5P_FIMV_D_METADATA_ADDR_MVCVUI 0xF6D0
+#define S5P_FIMV_D_METADATA_SIZE_MVCVUI 0xF6D4
+
+#define S5P_FIMV_D_MVC_VIEW_ID 0xF6D8
+
+#define S5P_FIMV_D_SEI_AVAIL 0xF6DC
+#define S5P_FIMV_D_FRAME_PACK_ARRGMENT_ID 0xF6E0
+#define S5P_FIMV_D_FRAME_PACK_SEI_INFO 0xF6E4
+#define S5P_FIMV_D_FRAME_PACK_GRID_POS 0xF6E8
+
+#define S5P_FIMV_D_DISPLAY_RECOVERY_SEI_INFO 0xF6EC
+#define S5P_FIMV_D_DECODED_RECOVERY_SEI_INFO 0xF6F0
+
+#define S5P_FIMV_D_DISPLAY_FIRST_PLANE_2BIT_CRC 0xF6FC
+#define S5P_FIMV_D_DISPLAY_SECOND_PLANE_2BIT_CRC 0xF700
+#define S5P_FIMV_D_DECODED_FIRST_PLANE_2BIT_CRC 0xF704
+#define S5P_FIMV_D_DECODED_SECOND_PLANE_2BIT_CRC 0xF708
+
+#define S5P_FIMV_D_VIDEO_SIGNAL_TYPE 0xF70C
+#define S5P_FIMV_D_CONTENT_LIGHT_LEVEL_INFO_SEI 0xF710
+#define S5P_FIMV_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_0 0xF714
+#define S5P_FIMV_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_1 0xF718
+
+#define S5P_FIMV_D_USED_DPB_FLAG_UPPER 0xF720
+#define S5P_FIMV_D_USED_DPB_FLAG_LOWER 0xF724
+
+#define S5P_FIMV_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_2 0xF728
+#define S5P_FIMV_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_3 0xF72C
+#define S5P_FIMV_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_4 0xF730
+#define S5P_FIMV_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_5 0xF734
+
+#define S5P_FIMV_D_BLACK_BAR_START_POS 0xF738
+#define S5P_FIMV_D_BLACK_BAR_IMAGE_SIZE 0xF73C
+
+#define S5P_FIMV_D_DISPLAY_LUMA_ADDR 0xF60C
+#define S5P_FIMV_D_DISPLAY_CHROMA_ADDR 0xF610
+
+#define S5P_FIMV_D_DECODED_LUMA_ADDR 0xF648
+#define S5P_FIMV_D_DECODED_CHROMA_ADDR 0xF64C
+
+/* Encoder Registers */
+#define S5P_FIMV_E_CROPPED_FRAME_WIDTH 0xF778
+#define S5P_FIMV_E_CROPPED_FRAME_HEIGHT 0xF77C
+#define S5P_FIMV_E_FRAME_CROP_OFFSET 0xF780
+#define S5P_FIMV_E_ENC_OPTIONS 0xF784
+#define S5P_FIMV_E_PICTURE_PROFILE 0xF788
+#define S5P_FIMV_E_VBV_BUFFER_SIZE 0xF78C
+#define S5P_FIMV_E_VBV_INIT_DELAY 0xF790
+#define S5P_FIMV_E_FIXED_PICTURE_QP 0xF794
+#define S5P_FIMV_E_RC_CONFIG 0xF798
+#define S5P_FIMV_E_RC_QP_BOUND 0xF79C
+#define S5P_FIMV_E_RC_QP_BOUND_PB 0xF7A0
+#define S5P_FIMV_E_RC_MODE 0xF7A4
+
+#define S5P_FIMV_E_MB_RC_CONFIG 0xF7A8
+#define S5P_FIMV_E_PADDING_CTRL 0xF7AC
+#define S5P_FIMV_E_AIR_THRESHOLD 0xF7B0
+
+#define S5P_FIMV_E_MV_HOR_RANGE 0xF7B4
+#define S5P_FIMV_E_MV_VER_RANGE 0xF7B8
+
+#define S5P_FIMV_E_HIGH_QUALITY_MODE 0xF7C0
+#define S5P_FIMV_E_VIDEO_SIGNAL_TYPE 0xF7C4
+
+#define S5P_FIMV_E_SAO_WEIGHT0 0xF7C8
+#define S5P_FIMV_E_SAO_WEIGHT1 0xF7CC
+
+#define S5P_FIMV_E_NUM_DPB 0xF890
+#define S5P_FIMV_E_MIN_SCRATCH_BUFFER_SIZE 0xF894
+
+#define S5P_FIMV_E_LUMA_DPB 0xF8C0
+#define S5P_FIMV_E_CHROMA_DPB 0xF904
+#define S5P_FIMV_E_ME_BUFFER 0xF948
+
+#define S5P_FIMV_E_SCRATCH_BUFFER_ADDR 0xF98C
+#define S5P_FIMV_E_SCRATCH_BUFFER_SIZE 0xF990
+#define S5P_FIMV_E_TMV_BUFFER0 0xF994
+#define S5P_FIMV_E_TMV_BUFFER1 0xF998
+#define S5P_FIMV_E_IR_BUFFER_ADDR 0xF99C
+#define S5P_FIMV_E_SOURCE_FIRST_2BIT_ADDR 0xF9D0
+#define S5P_FIMV_E_SOURCE_SECOND_2BIT_ADDR 0xF9D4
+#define S5P_FIMV_E_SOURCE_FIRST_2BIT_STRIDE 0xF9D8
+#define S5P_FIMV_E_SOURCE_SECOND_2BIT_STRIDE 0xF9DC
+#define S5P_FIMV_E_SOURCE_FIRST_ADDR 0xF9E0
+#define S5P_FIMV_E_SOURCE_SECOND_ADDR 0xF9E4
+#define S5P_FIMV_E_SOURCE_THIRD_ADDR 0xF9E8
+#define S5P_FIMV_E_SOURCE_FIRST_STRIDE 0xF9EC
+#define S5P_FIMV_E_SOURCE_SECOND_STRIDE 0xF9F0
+#define S5P_FIMV_E_SOURCE_THIRD_STRIDE 0xF9F4
+#define S5P_FIMV_E_STREAM_BUFFER_ADDR 0xF9F8
+#define S5P_FIMV_E_STREAM_BUFFER_SIZE 0xF9FC
+#define S5P_FIMV_E_ROI_BUFFER_ADDR 0xFA00
+
+#define S5P_FIMV_E_PARAM_CHANGE 0xFA04
+#define S5P_FIMV_E_IR_SIZE 0xFA08
+#define S5P_FIMV_E_GOP_CONFIG 0xFA0C
+#define S5P_FIMV_E_MSLICE_MODE 0xFA10
+#define S5P_FIMV_E_MSLICE_SIZE_MB 0xFA14
+#define S5P_FIMV_E_MSLICE_SIZE_BITS 0xFA18
+#define S5P_FIMV_E_FRAME_INSERTION 0xFA1C
+
+#define S5P_FIMV_E_RC_FRAME_RATE 0xFA20
+#define S5P_FIMV_E_RC_BIT_RATE 0xFA24
+#define S5P_FIMV_E_RC_ROI_CTRL 0xFA2C
+#define S5P_FIMV_E_PICTURE_TAG 0xFA30
+#define S5P_FIMV_E_BIT_COUNT_ENABLE 0xFA34
+#define S5P_FIMV_E_MAX_BIT_COUNT 0xFA38
+#define S5P_FIMV_E_MIN_BIT_COUNT 0xFA3C
+
+#define S5P_FIMV_E_METADATA_BUFFER_ADDR 0xFA40
+#define S5P_FIMV_E_METADATA_BUFFER_SIZE 0xFA44
+
+#define S5P_FIMV_E_ENCODING_ORDER_TIME_INFO 0xFA50
+#define S5P_FIMV_E_ENCODING_ORDER_INFO 0xFA54
+#define S5P_FIMV_E_STREAM_BUFFER_OFFSET 0xFA58
+#define S5P_FIMV_E_GOP_CONFIG2 0xFA5C
+#define S5P_FIMV_E_WEIGHT_FOR_WEIGHTED_PREDICTION 0xFA60
+
+#define S5P_FIMV_E_ENCODED_SOURCE_FIRST_ADDR 0xFA70
+#define S5P_FIMV_E_ENCODED_SOURCE_SECOND_ADDR 0xFA74
+#define S5P_FIMV_E_ENCODED_SOURCE_THIRD_ADDR 0xFA78
+
+#define S5P_FIMV_E_STREAM_SIZE 0xFA80
+#define S5P_FIMV_E_SLICE_TYPE 0xFA84
+#define S5P_FIMV_E_PICTURE_COUNT 0xFA88
+#define S5P_FIMV_E_RET_PICTURE_TAG 0xFA8C
+
+#define S5P_FIMV_E_RECON_LUMA_DPB_ADDR 0xFA9C
+#define S5P_FIMV_E_RECON_CHROMA_DPB_ADDR 0xFAA0
+#define S5P_FIMV_E_METADATA_ADDR_ENC_SLICE 0xFAA4
+#define S5P_FIMV_E_METADATA_SIZE_ENC_SLICE 0xFAA8
+
+#define S5P_FIMV_E_NAL_DONE_INFO 0xFAEC
+
+#define S5P_FIMV_E_MPEG4_OPTIONS 0xFB10
+#define S5P_FIMV_E_MPEG4_HEC_PERIOD 0xFB14
+
+#define S5P_FIMV_E_BPG_OPTIONS 0xFB1C
+#define S5P_FIMV_E_BPG_EXT_CTB_QP_CTRL 0xFB20
+#define S5P_FIMV_E_BPG_CHROMA_QP_OFFSET 0xFB24
+#define S5P_FIMV_E_BPG_EXTENSION_DATA_SIZE 0xFB28
+
+#define S5P_FIMV_E_H264_HD_SVC_EXTENSION_0 0xFB44
+#define S5P_FIMV_E_H264_HD_SVC_EXTENSION_1 0xFB48
+#define S5P_FIMV_E_ASPECT_RATIO 0xFB4C
+#define S5P_FIMV_E_EXTENDED_SAR 0xFB50
+
+#define S5P_FIMV_E_H264_OPTIONS 0xFB54
+#define S5P_FIMV_E_H264_OPTIONS_2 0xFB58
+#define S5P_FIMV_E_H264_LF_ALPHA_OFFSET 0xFB5C
+#define S5P_FIMV_E_H264_LF_BETA_OFFSET 0xFB60
+#define S5P_FIMV_E_H264_REFRESH_PERIOD 0xFB64
+
+#define S5P_FIMV_E_H264_FMO_SLICE_GRP_MAP_TYPE 0xFB68
+#define S5P_FIMV_E_H264_FMO_NUM_SLICE_GRP_MINUS1 0xFB6C
+#define S5P_FIMV_E_H264_FMO_SLICE_GRP_CHANGE_DIR 0xFB70
+#define S5P_FIMV_E_H264_FMO_SLICE_GRP_CHANGE_RATE_MINUS1 0xFB74
+#define S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_0 0xFB78
+#define S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_1 0xFB7C
+#define S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_2 0xFB80
+#define S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_3 0xFB84
+
+#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_0 0xFB88
+#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_1 0xFB8C
+#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_2 0xFB90
+#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_3 0xFB94
+#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_4 0xFB98
+#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_5 0xFB9C
+#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_6 0xFBA0
+#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_7 0xFBA4
+#define S5P_FIMV_E_H264_CHROMA_QP_OFFSET 0xFBA8
+
+#define S5P_FIMV_E_NUM_T_LAYER 0xFBAC
+#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER0 0xFBB0
+#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER1 0xFBB4
+#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER2 0xFBB8
+#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER3 0xFBBC
+#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER4 0xFBC0
+#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER5 0xFBC4
+#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER6 0xFBC8
+
+/* For backward compatibility */
+#define S5P_FIMV_E_H264_FRAME_PACKING_SEI_INFO 0xFC4C
+
+#define S5P_FIMV_E_H264_NAL_CONTROL 0xFD14
+#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER0 0xFD18
+#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER1 0xFD1C
+#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER2 0xFD20
+#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER3 0xFD24
+#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER4 0xFD28
+#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER5 0xFD2C
+#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER6 0xFD30
+
+#define S5P_FIMV_E_MVC_FRAME_QP_VIEW1 0xFD40
+#define S5P_FIMV_E_MVC_RC_FRAME_RATE_VIEW1 0xFD44
+#define S5P_FIMV_E_MVC_RC_BIT_RATE_VIEW1 0xFD48
+#define S5P_FIMV_E_MVC_RC_QBOUND_VIEW1 0xFD4C
+#define S5P_FIMV_E_MVC_RC_MODE_VIEW1 0xFD50
+#define S5P_FIMV_E_MVC_INTER_VIEW_PREDICTION_ON 0xFD80
+
+#define S5P_FIMV_E_VP9_OPTION 0xFD90
+#define S5P_FIMV_E_VP9_FILTER_OPTION 0xFD94
+#define S5P_FIMV_E_VP9_GOLDEN_FRAME_OPTION 0xFD98
+#define S5P_FIMV_E_VP8_OPTION 0xFDB0
+#define S5P_FIMV_E_VP8_FILTER_OPTION 0xFDB4
+#define S5P_FIMV_E_VP8_GOLDEN_FRAME_OPTION 0xFDB8
+
+#define S5P_FIMV_E_HEVC_OPTIONS_2 0xFDC4
+
+#define S5P_FIMV_E_HEVC_OPTIONS 0xFDD4
+#define S5P_FIMV_E_HEVC_REFRESH_PERIOD 0xFDD8
+#define S5P_FIMV_E_HEVC_CHROMA_QP_OFFSET 0xFDDC
+#define S5P_FIMV_E_HEVC_LF_BETA_OFFSET_DIV2 0xFDE0
+#define S5P_FIMV_E_HEVC_LF_TC_OFFSET_DIV2 0xFDE4
+#define S5P_FIMV_E_HEVC_NAL_CONTROL 0xFDE8
+
+#define S5P_FIMV_E_VP8_NAL_CONTROL 0xFDF0
+#define S5P_FIMV_E_VP9_NAL_CONTROL 0xFDF4
+#define S5P_FIMV_E_CONTENT_LIGHT_LEVEL_INFO_SEI 0xFDF8
+#define S5P_FIMV_E_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_0 0xFDFC
+#define S5P_FIMV_E_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_1 0xFE00
+#define S5P_FIMV_E_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_2 0xFE04
+#define S5P_FIMV_E_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_3 0xFE08
+#define S5P_FIMV_E_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_4 0xFE0C
+#define S5P_FIMV_E_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_5 0xFE10
+
+
+#define S5P_FIMV_REG_CLEAR_BEGIN 0xf000
+#define S5P_FIMV_REG_CLEAR_COUNT 1024
+
+
+/* Bit Definitions */
+/* 0x1100: S5P_FIMV_HOST2RISC_CMD */
+#define S5P_FIMV_H2R_CMD_EMPTY 0
+#define S5P_FIMV_H2R_CMD_SYS_INIT 1
+#define S5P_FIMV_H2R_CMD_OPEN_INSTANCE 2
+#define S5P_FIMV_H2R_CMD_SEQ_HEADER 3
+#define S5P_FIMV_H2R_CMD_INIT_BUFFERS 4
+#define S5P_FIMV_H2R_CMD_NAL_START 5
+#define S5P_FIMV_H2R_CMD_CLOSE_INSTANCE 6
+#define S5P_FIMV_H2R_CMD_SLEEP 7
+#define S5P_FIMV_H2R_CMD_WAKEUP 8
+#define S5P_FIMV_H2R_CMD_LAST_FRAME 9
+#define S5P_FIMV_H2R_CMD_DPB_FLUSH 10
+#define S5P_FIMV_H2R_CMD_NAL_ABORT 11
+#define S5P_FIMV_H2R_CMD_CACHE_FLUSH 12
+#define S5P_FIMV_H2R_CMD_NAL_QUEUE 13
+#define S5P_FIMV_H2R_CMD_STOP_QUEUE 14
+
+
+/* 0x1104: S5P_FIMV_RISC2HOST_CMD */
+#define S5P_FIMV_RISC2HOST_CMD_MASK 0x1FFFF
+#define S5P_FIMV_R2H_CMD_EMPTY 0
+#define S5P_FIMV_R2H_CMD_SYS_INIT_RET 1
+#define S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET 2
+#define S5P_FIMV_R2H_CMD_SEQ_DONE_RET 3
+#define S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET 4
+#define S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET 6
+#define S5P_FIMV_R2H_CMD_SLEEP_RET 7
+#define S5P_FIMV_R2H_CMD_WAKEUP_RET 8
+#define S5P_FIMV_R2H_CMD_COMPLETE_SEQ_RET 9
+#define S5P_FIMV_R2H_CMD_DPB_FLUSH_RET 10
+#define S5P_FIMV_R2H_CMD_NAL_ABORT_RET 11
+#define S5P_FIMV_R2H_CMD_FW_STATUS_RET 12
+#define S5P_FIMV_R2H_CMD_FRAME_DONE_RET 13
+#define S5P_FIMV_R2H_CMD_FIELD_DONE_RET 14
+#define S5P_FIMV_R2H_CMD_SLICE_DONE_RET 15
+#define S5P_FIMV_R2H_CMD_ENC_BUFFER_FULL_RET 16
+#define S5P_FIMV_R2H_CMD_QUEUE_DONE_RET 17
+#define S5P_FIMV_R2H_CMD_COMPLETE_QUEUE_RET 18
+#define S5P_FIMV_R2H_CMD_CACHE_FLUSH_RET 20
+#define S5P_FIMV_R2H_CMD_ERR_RET 32
+
+
+/* 0xF000: S5P_FIMV_FW_VERSION */
+#define S5P_FIMV_FW_VER_INFO_MASK 0xFF
+#define S5P_FIMV_FW_VER_INFO_SHFT 24
+#define S5P_FIMV_FW_VER_YEAR_MASK 0xFF
+#define S5P_FIMV_FW_VER_YEAR_SHFT 16
+#define S5P_FIMV_FW_VER_MONTH_MASK 0xFF
+#define S5P_FIMV_FW_VER_MONTH_SHFT 8
+#define S5P_FIMV_FW_VER_DATE_MASK 0xFF
+#define S5P_FIMV_FW_VER_DATE_SHFT 0
+#define S5P_FIMV_FW_VER_ALL_MASK 0xFFFFFF
+#define S5P_FIMV_FW_VER_ALL_SHFT 0
+
+
+/* 0xF00C: S5P_FIMV_CODEC_TYPE */
+#define MFC_FORMATS_NO_CODEC -1
+/* Decoder */
+#define S5P_FIMV_CODEC_H264_DEC 0
+#define S5P_FIMV_CODEC_H264_MVC_DEC 1
+#define S5P_FIMV_CODEC_MPEG4_DEC 3
+#define S5P_FIMV_CODEC_FIMV1_DEC 4
+#define S5P_FIMV_CODEC_FIMV2_DEC 5
+#define S5P_FIMV_CODEC_FIMV3_DEC 6
+#define S5P_FIMV_CODEC_FIMV4_DEC 7
+#define S5P_FIMV_CODEC_H263_DEC 8
+#define S5P_FIMV_CODEC_VC1_RCV_DEC 9
+#define S5P_FIMV_CODEC_VC1_DEC 10
+#define S5P_FIMV_CODEC_MPEG2_DEC 13
+#define S5P_FIMV_CODEC_VP8_DEC 14
+#define S5P_FIMV_CODEC_HEVC_DEC 17
+#define S5P_FIMV_CODEC_VP9_DEC 18
+/* Encoder */
+#define S5P_FIMV_CODEC_H264_ENC 20
+#define S5P_FIMV_CODEC_H264_MVC_ENC 21
+#define S5P_FIMV_CODEC_MPEG4_ENC 23
+#define S5P_FIMV_CODEC_H263_ENC 24
+#define S5P_FIMV_CODEC_VP8_ENC 25
+#define S5P_FIMV_CODEC_HEVC_ENC 26
+#define S5P_FIMV_CODEC_VP9_ENC 27
+
+#define S5P_FIMV_CODEC_BPG_DEC 32
+#define S5P_FIMV_CODEC_BPG_ENC 33
+
+/* 0xF028: S5P_FIMV_MFC_VERSION */
+#define S5P_FIMV_MFC_VER_MASK 0xFFFFFFFF
+#define S5P_FIMV_MFC_VER_SHFT 0
+
+
+/* 0xF074: S5P_FIMV_ERROR_CODE */
+#define S5P_FIMV_ERR_STATUS_MASK 0xFFFF
+#define S5P_FIMV_ERR_STATUS_SHIFT 0
+#define S5P_FIMV_WARN_STATUS_MASK 0xFFFF
+#define S5P_FIMV_WARN_STATUS_SHIFT 16
+/* Error number */
+#define S5P_FIMV_ERR_BUFFER_FULL 18
+#define S5P_FIMV_ERR_NO_AVAILABLE_DPB 33
+#define S5P_FIMV_ERR_NO_KEY_FRAME 34
+#define S5P_FIMV_ERR_VPS_ONLY_ERROR 42
+#define S5P_FIMV_ERR_INSUFFICIENT_DPB_SIZE 57
+#define S5P_FIMV_ERR_INSUFFICIENT_NUM_DPB 58
+#define S5P_FIMV_ERR_INSUFFICIENT_MV_BUF_SIZE 60
+#define S5P_FIMV_ERR_NULL_SCRATCH 61
+#define S5P_FIMV_ERR_INSUFFICIENT_SCRATCH_BUF_SIZE 62
+
+#define S5P_FIMV_ERR_UNSUPPORTED_FEATURE 100
+#define S5P_FIMV_ERR_UNSUPPORTED_RESOLUTION 101
+#define S5P_FIMV_ERR_HEADER_NOT_FOUND 102
+#define S5P_FIMV_ERR_INVAILD_NAL_TYPE 103
+#define S5P_FIMV_ERR_SEQUENCE_HEADER 104
+#define S5P_FIMV_ERR_MFC_TIMEOUT 140
+#define S5P_FIMV_ERR_TS_MUX_TIMEOUT 141
+#define S5P_FIMV_ERR_G2D_TIMEOUT 142
+#define S5P_FIMV_ERR_FRAME_CONCEAL 150
+#define S5P_FIMV_ERR_WARNINGS_START 160
+#define S5P_FIMV_ERR_BROKEN_LINK 161
+#define S5P_FIMV_ERR_SYNC_POINT_NOT_RECEIVED 190
+#define S5P_FIMV_ERR_NON_PAIRED_FIELD 191
+#define S5P_FIMV_ERR_WARNINGS_END 222
+
+
+/* 0xF0B4: S5P_FIMV_D_DEC_OPTIONS */
+#define S5P_FIMV_D_DEC_OPT_DISPLAY_DELAY_EN_SHIFT 3
+#define S5P_FIMV_D_DEC_OPT_FMO_ASO_CTRL_MASK 0x1
+#define S5P_FIMV_D_DEC_OPT_FMO_ASO_CTRL_SHIFT 4
+#define S5P_FIMV_D_DEC_OPT_IDR_DECODING_MASK 0x1
+#define S5P_FIMV_D_DEC_OPT_IDR_DECODING_SHIFT 6
+#define S5P_FIMV_D_DEC_OPT_DISCARD_RCV_HEADER_SHIFT 7
+#define S5P_FIMV_D_DEC_OPT_CONCEAL_CONTROL_SHIFT 8
+#define S5P_FIMV_D_DEC_OPT_PARALLEL_DISABLE_SHIFT 11
+#define S5P_FIMV_D_DEC_OPT_REALLOC_CONTROL_SHIFT 13
+#define S5P_FIMV_D_DEC_OPT_SPECIAL_PARSING_SHIFT 15
+#define S5P_FIMV_D_DEC_OPT_THUMBNAIL_DECODING 16
+
+
+/* 0xF0C4: S5P_FIMV_D_SEI_ENABLE */
+#define S5P_FIMV_D_SEI_ENABLE_NEED_INIT_BUFFER_SHIFT 1
+#define S5P_FIMV_D_SEI_ENABLE_RECOVERY_PARSING_SHIFT 2
+#define S5P_FIMV_D_SEI_ENABLE_CONTENT_LIGHT_SHIFT 4
+#define S5P_FIMV_D_SEI_ENABLE_MASTERING_DISPLAY_SHIFT 5
+
+
+/* 0xF154: S5P_FIMV_D_INIT_BUFFER_OPTIONS */
+#define S5P_FIMV_D_INIT_BUF_OPT_LF_CTRL_MASK 0x3
+#define S5P_FIMV_D_INIT_BUF_OPT_LF_CTRL_SHIFT 1
+#define S5P_FIMV_D_INIT_BUF_OPT_DYNAMIC_DPB_SET_SHIFT 3
+#define S5P_FIMV_D_INIT_BUF_OPT_COPY_NOT_CODED_SHIFT 4
+#define S5P_FIMV_D_INIT_BUF_OPT_DITHERING_EN_SHIFT 6
+#define S5P_FIMV_D_INIT_BUF_OPT_STRIDE_SIZE_ALIGN 7
+
+
+/* 0xF5AC: S5P_FIMV_D_NAL_START_OPTIONS */
+#define S5P_FIMV_D_NAL_START_OPT_BLACK_BAR_SHIFT 3
+
+
+/* 0xF608: S5P_FIMV_D_DISPLAY_STATUS */
+#define S5P_FIMV_DISP_STATUS_DISPLAY_STATUS_MASK 0x7
+#define S5P_FIMV_DISP_STATUS_INTERLACE_MASK 0x1
+#define S5P_FIMV_DISP_STATUS_INTERLACE_SHIFT 3
+#define S5P_FIMV_DISP_STATUS_RES_CHANGE_MASK 0x3
+#define S5P_FIMV_DISP_STATUS_RES_CHANGE_SHIFT 4
+#define S5P_FIMV_DISP_STATUS_NEED_DPB_CHANGE_MASK 0x1
+#define S5P_FIMV_DISP_STATUS_NEED_DPB_CHANGE_SHIFT 9
+#define S5P_FIMV_DISP_STATUS_NEED_SCRATCH_CHANGE_MASK 0x1
+#define S5P_FIMV_DISP_STATUS_NEED_SCRATCH_CHANGE_SHIFT 10
+#define S5P_FIMV_DISP_STATUS_NEED_EMPTY_DPB_MASK 0x1
+#define S5P_FIMV_DISP_STATUS_NEED_EMPTY_DPB_SHIFT 12
+#define S5P_FIMV_DISP_STATUS_BLACK_BAR_DETECT_MASK 0x3
+#define S5P_FIMV_DISP_STATUS_BLACK_BAR_DETECT_SHIFT 13
+#define S5P_FIMV_DISP_STATUS_NOT_DETECTED 0x0
+#define S5P_FIMV_DISP_STATUS_BLACK_BAR 0x1
+#define S5P_FIMV_DISP_STATUS_BLACK_SCREEN 0x2
+
+
+/* 0xF618: S5P_FIMV_D_DISPLAY_FRAME_TYPE */
+#define S5P_FIMV_DISPLAY_FRAME_MASK 0x7
+#define S5P_FIMV_DISPLAY_TEMP_INFO_MASK 0x1
+#define S5P_FIMV_DISPLAY_TEMP_INFO_SHIFT 7
+#define S5P_FIMV_DISPLAY_FRAME_NOT_CODED 0
+#define S5P_FIMV_DISPLAY_FRAME_I 1
+#define S5P_FIMV_DISPLAY_FRAME_P 2
+#define S5P_FIMV_DISPLAY_FRAME_B 3
+
+
+/* 0xF61C: S5P_FIMV_D_DISPLAY_CROP_INFO1 */
+#define S5P_FIMV_D_SHARED_CROP_LEFT_MASK 0xFFFF
+#define S5P_FIMV_D_SHARED_CROP_RIGHT_SHIFT 16
+
+
+/* 0xF620: S5P_FIMV_D_DISPLAY_CROP_INFO2 */
+#define S5P_FIMV_D_SHARED_CROP_TOP_MASK 0xFFFF
+#define S5P_FIMV_D_SHARED_CROP_BOTTOM_SHIFT 16
+
+
+/* 0xF644: S5P_FIMV_D_DECODED_STATUS */
+#define S5P_FIMV_DEC_STATUS_DECODED_STATUS_MASK 0x7
+#define S5P_FIMV_DEC_STATUS_DECODING_ONLY 0
+#define S5P_FIMV_DEC_STATUS_DECODING_DISPLAY 1
+#define S5P_FIMV_DEC_STATUS_DISPLAY_ONLY 2
+#define S5P_FIMV_DEC_STATUS_DECODING_EMPTY 3
+#define S5P_FIMV_DEC_STATUS_NUM_OF_TILE_MASK 0xF
+#define S5P_FIMV_DEC_STATUS_NUM_OF_TILE_SHIFT 15
+
+
+/* 0xF654: S5P_FIMV_D_DECODED_FRAME_TYPE */
+#define S5P_FIMV_DECODED_FRAME_MASK 0x7
+#define S5P_FIMV_DECODED_FRAME_NOT_CODED 0
+#define S5P_FIMV_DECODED_FRAME_I 1
+#define S5P_FIMV_DECODED_FRAME_P 2
+#define S5P_FIMV_DECODED_FRAME_B 3
+
+
+/* 0xF660: S5P_FIMV_D_DECODED_PICTURE_PROFILE */
+#define S5P_FIMV_D_DECODED_PIC_PROFILE_MASK 0x1F
+#define S5P_FIMV_D_BIT_DEPTH_CHROMA_MINUS8_MASK 0x7
+#define S5P_FIMV_D_BIT_DEPTH_CHROMA_MINUS8_SHIFT 19
+#define S5P_FIMV_D_BIT_DEPTH_LUMA_MINUS8_MASK 0x7
+#define S5P_FIMV_D_BIT_DEPTH_LUMA_MINUS8_SHIFT 16
+#define S5P_FIMV_D_PROFILE_HEVC_MAIN 1
+#define S5P_FIMV_D_PROFILE_HEVC_MAIN_10 2
+#define S5P_FIMV_D_PROFILE_HEVC_RANGE_EXT 4
+
+
+/* 0xF684: S5P_FIMV_D_CHROMA_FORMAT */
+#define S5P_FIMV_D_CHROMA_FORMAT_MASK 0x3
+#define S5P_FIMV_D_COLOR_RANGE_MASK 0x1
+#define S5P_FIMV_D_COLOR_RANGE_SHIFT 3
+#define S5P_FIMV_D_COLOR_SPACE_MASK 0xF
+#define S5P_FIMV_D_COLOR_SPACE_SHIFT 4
+#define S5P_FIMV_D_COLOR_UNKNOWN 0
+#define S5P_FIMV_D_CHROMA_400 0
+#define S5P_FIMV_D_CHROMA_420 1
+#define S5P_FIMV_D_CHROMA_422 2
+#define S5P_FIMV_D_CHROMA_444 3
+
+
+/* 0xF690: S5P_FIMV_D_H264_INFO */
+#define S5P_FIMV_D_H264_INFO_MBAFF_FRAME_FLAG_SHIFT 9
+#define S5P_FIMV_D_H264_INFO_MBAFF_FRAME_FLAG_MASK 0x1
+
+
+/* 0xF6D8: S5P_FIMV_D_MVC_VIEW_ID */
+#define S5P_FIMV_D_MVC_VIEW_ID_DISP_MASK 0xFFFF
+
+
+/* 0xF6DC: S5P_FIMV_D_SEI_AVAIL */
+#define S5P_FIMV_D_SEI_AVAIL_FRAME_PACK_MASK 0x1
+#define S5P_FIMV_D_SEI_AVAIL_CONTENT_LIGHT_MASK 0x1
+#define S5P_FIMV_D_SEI_AVAIL_CONTENT_LIGHT_SHIFT 1
+#define S5P_FIMV_D_SEI_AVAIL_MASTERING_DISPLAY_MASK 0x1
+#define S5P_FIMV_D_SEI_AVAIL_MASTERING_DISPLAY_SHIFT 2
+
+
+/* 0xF70C: S5P_FIMV_D_VIDEO_SIGNAL_TYPE */
+#define S5P_FIMV_D_VIDEO_SIGNAL_TYPE_FLAG_MASK 0x1
+#define S5P_FIMV_D_VIDEO_SIGNAL_TYPE_FLAG_SHIFT 29
+#define S5P_FIMV_D_COLOUR_DESCRIPTION_FLAG_MASK 0x1
+#define S5P_FIMV_D_COLOUR_DESCRIPTION_FLAG_SHIFT 24
+
+
+/* 0xF738: S5P_FIMV_D_BLACK_BAR_START_POS */
+#define S5P_FIMV_D_BLACK_BAR_START_X_SHIFT 0
+#define S5P_FIMV_D_BLACK_BAR_START_X_MASK 0xFFFF
+#define S5P_FIMV_D_BLACK_BAR_START_Y_SHIFT 16
+#define S5P_FIMV_D_BLACK_BAR_START_Y_MASK 0xFFFF
+
+
+/* 0xF73C: S5P_FIMV_D_BLACK_BAR_IMAGE_SIZE */
+#define S5P_FIMV_D_BLACK_BAR_IMAGE_W_SHIFT 0
+#define S5P_FIMV_D_BLACK_BAR_IMAGE_W_MASK 0xFFFF
+#define S5P_FIMV_D_BLACK_BAR_IMAGE_H_SHIFT 16
+#define S5P_FIMV_D_BLACK_BAR_IMAGE_H_MASK 0xFFFF
+
+
+/* 0xF780: S5P_FIMV_E_FRAME_CROP_OFFSET */
+#define S5P_FIMV_E_FRAME_CROP_OFFSET_TOP 16
+#define S5P_FIMV_E_FRAME_CROP_OFFSET_LEFT 0
+#define S5P_FIMV_E_FRAME_CROP_OFFSET_MASK 0x3FFF
+
+
+/* 0xF788: S5P_FIMV_E_PICTURE_PROFILE */
+#define S5P_FIMV_E_PROFILE_H264_BASELINE 0
+#define S5P_FIMV_E_PROFILE_H264_MAIN 1
+#define S5P_FIMV_E_PROFILE_H264_HIGH 2
+#define S5P_FIMV_E_PROFILE_H264_CONSTRAINED_BASELINE 3
+#define S5P_FIMV_E_PROFILE_H264_CONSTRAINED_HIGH 5
+#define S5P_FIMV_E_PROFILE_MPEG4_SIMPLE 0
+#define S5P_FIMV_E_PROFILE_MPEG4_ADVANCED_SIMPLE 1
+#define S5P_FIMV_E_PROFILE_HEVC_MAIN_422_10_INTRA 2
+#define S5P_FIMV_E_PROFILE_HEVC_MAIN_10 3
+#define S5P_FIMV_E_PROFILE_HEVC_MAIN_422_10 4
+#define S5P_FIMV_E_PROFILE_VP9_PROFILE0 0
+#define S5P_FIMV_E_PROFILE_VP9_PROFILE1 1
+#define S5P_FIMV_E_PROFILE_VP9_PROFILE2 2
+#define S5P_FIMV_E_PROFILE_VP9_PROFILE3 3
+
+
+/* 0xF7A4: S5P_FIMV_E_RC_MODE */
+#define S5P_FIMV_E_RC_CBR_FIX 0
+#define S5P_FIMV_E_RC_CBR_VAR 1
+#define S5P_FIMV_E_RC_VBR 2
+#define S5P_FIMV_E_RC_CBR_I_LIMIT 3
+
+
+/* 0xFA84: S5P_FIMV_E_SLICE_TYPE */
+#define S5P_FIMV_E_SLICE_TYPE_NOT_CODED 0
+#define S5P_FIMV_E_SLICE_TYPE_I 1
+#define S5P_FIMV_E_SLICE_TYPE_P 2
+#define S5P_FIMV_E_SLICE_TYPE_B 3
+#define S5P_FIMV_E_SLICE_TYPE_SKIPPED 4
+
+
+#endif /* __REGS_MFC_V10_H */
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_intr.c
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "mfc_sync.h"
+
+#include "mfc_cal.h"
+#include "mfc_perf_measure.h"
+
+#include "mfc_queue.h"
+
+#define R2H_BIT(x) (((x) > 0) ? (1 << ((x) - 1)) : 0)
+
+static inline unsigned int mfc_r2h_bit_mask(int cmd)
+{
+ unsigned int mask = R2H_BIT(cmd);
+
+ if (cmd == S5P_FIMV_R2H_CMD_FRAME_DONE_RET)
+ mask |= (R2H_BIT(S5P_FIMV_R2H_CMD_FIELD_DONE_RET) |
+ R2H_BIT(S5P_FIMV_R2H_CMD_COMPLETE_SEQ_RET) |
+ R2H_BIT(S5P_FIMV_R2H_CMD_SLICE_DONE_RET) |
+ R2H_BIT(S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET) |
+ R2H_BIT(S5P_FIMV_R2H_CMD_ENC_BUFFER_FULL_RET));
+ /* FIXME: Temporal mask for S3D SEI processing */
+ else if (cmd == S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET)
+ mask |= (R2H_BIT(S5P_FIMV_R2H_CMD_FIELD_DONE_RET) |
+ R2H_BIT(S5P_FIMV_R2H_CMD_SLICE_DONE_RET) |
+ R2H_BIT(S5P_FIMV_R2H_CMD_FRAME_DONE_RET));
+
+ return (mask |= R2H_BIT(S5P_FIMV_R2H_CMD_ERR_RET));
+}
+
+#define wait_condition(x, c) (x->int_condition && \
+ (R2H_BIT(x->int_reason) & mfc_r2h_bit_mask(c)))
+#define is_err_cond(x) ((x->int_condition) && (x->int_reason == S5P_FIMV_R2H_CMD_ERR_RET))
+
+/*
+ * Return value description
+ * 0: waked up before timeout
+ * 1: failed to get the response for the command before timeout
+*/
+int s5p_mfc_wait_for_done_dev(struct s5p_mfc_dev *dev, int command)
+{
+ int ret;
+
+ ret = wait_event_timeout(dev->cmd_wq,
+ wait_condition(dev, command),
+ msecs_to_jiffies(MFC_INT_TIMEOUT));
+ if (ret == 0) {
+ mfc_err_dev("Interrupt (dev->int_reason:%d, command:%d) timed out\n",
+ dev->int_reason, command);
+ if (s5p_mfc_check_risc2host(dev)) {
+ ret = wait_event_timeout(dev->cmd_wq,
+ wait_condition(dev, command),
+ msecs_to_jiffies(MFC_INT_TIMEOUT * MFC_INT_TIMEOUT_CNT));
+ if (ret == 0) {
+ mfc_err_dev("Timeout: MFC driver waited for upward of %dsec\n",
+ 3 * MFC_INT_TIMEOUT);
+ } else {
+ goto wait_done;
+ }
+ }
+ call_dop(dev, dump_and_stop_debug_mode, dev);
+ return 1;
+ }
+
+wait_done:
+ mfc_debug(2, "Finished waiting (dev->int_reason:%d, command: %d)\n",
+ dev->int_reason, command);
+ return 0;
+}
+
+/*
+ * Return value description
+ * 0: waked up before timeout
+ * 1: failed to get the response for the command before timeout
+ * -1: got the error response for the command before timeout
+*/
+int s5p_mfc_wait_for_done_ctx(struct s5p_mfc_ctx *ctx, int command)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ int ret;
+ unsigned int timeout = MFC_INT_TIMEOUT;
+
+ if (command == S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET)
+ timeout = MFC_INT_SHORT_TIMEOUT;
+
+ ret = wait_event_timeout(ctx->cmd_wq,
+ wait_condition(ctx, command),
+ msecs_to_jiffies(timeout));
+ if (ret == 0) {
+ mfc_err_ctx("Interrupt (ctx->int_reason:%d, command:%d) timed out\n",
+ ctx->int_reason, command);
+ if (s5p_mfc_check_risc2host(dev)) {
+ ret = wait_event_timeout(ctx->cmd_wq,
+ wait_condition(ctx, command),
+ msecs_to_jiffies(MFC_INT_TIMEOUT * MFC_INT_TIMEOUT_CNT));
+ if (ret == 0) {
+ mfc_err_dev("Timeout: MFC driver waited for upward of %dsec\n",
+ 3 * MFC_INT_TIMEOUT);
+ } else {
+ goto wait_done;
+ }
+ }
+ call_dop(dev, dump_and_stop_debug_mode, dev);
+ return 1;
+ }
+
+wait_done:
+ if (is_err_cond(ctx)) {
+ mfc_err_ctx("Finished (ctx->int_reason:%d, command: %d)\n",
+ ctx->int_reason, command);
+ mfc_err_ctx("But error (ctx->int_err:%d)\n", ctx->int_err);
+ call_dop(dev, dump_and_stop_debug_mode, dev);
+ return -1;
+ }
+
+ mfc_debug(2, "Finished waiting (ctx->int_reason:%d, command: %d)\n",
+ ctx->int_reason, command);
+ return 0;
+}
+
+/* Wake up device wait_queue */
+void s5p_mfc_wake_up_dev(struct s5p_mfc_dev *dev, unsigned int reason,
+ unsigned int err)
+{
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return;
+ }
+
+ dev->int_condition = 1;
+ dev->int_reason = reason;
+ dev->int_err = err;
+ wake_up(&dev->cmd_wq);
+}
+
+/* Wake up context wait_queue */
+void s5p_mfc_wake_up_ctx(struct s5p_mfc_ctx *ctx, unsigned int reason,
+ unsigned int err)
+{
+ if (!ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return;
+ }
+
+ ctx->int_condition = 1;
+ ctx->int_reason = reason;
+ ctx->int_err = err;
+ wake_up(&ctx->cmd_wq);
+}
+
+int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev)
+{
+ unsigned long wflags;
+ int new_ctx_index = 0;
+ int cnt = 0;
+ int i;
+
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&dev->work_bits.lock, wflags);
+
+ mfc_debug(2, "Previous context: %d (bits %08lx)\n", dev->curr_ctx,
+ dev->work_bits.bits);
+
+ if (dev->preempt_ctx > MFC_NO_INSTANCE_SET) {
+ new_ctx_index = dev->preempt_ctx;
+ mfc_debug(2, "preempt_ctx is : %d\n", new_ctx_index);
+ } else {
+ for (i = 0; i < MFC_NUM_CONTEXTS; i++) {
+ if (dev->ctx[i] && dev->ctx[i]->otf_handle) {
+ if (test_bit(i, &dev->work_bits.bits)) {
+ spin_unlock_irqrestore(&dev->work_bits.lock, wflags);
+ return i;
+ }
+ break;
+ }
+ }
+
+ new_ctx_index = (dev->curr_ctx + 1) % MFC_NUM_CONTEXTS;
+ while (!test_bit(new_ctx_index, &dev->work_bits.bits)) {
+ new_ctx_index = (new_ctx_index + 1) % MFC_NUM_CONTEXTS;
+ cnt++;
+ if (cnt > MFC_NUM_CONTEXTS) {
+ /* No contexts to run */
+ spin_unlock_irqrestore(&dev->work_bits.lock, wflags);
+ return -EAGAIN;
+ }
+ }
+ }
+
+ spin_unlock_irqrestore(&dev->work_bits.lock, wflags);
+ return new_ctx_index;
+}
+
+/* Check whether a context should be run on hardware */
+int s5p_mfc_dec_ctx_ready(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ int src_buf_queue_greater_than_0 = 0;
+ int dst_buf_queue_greater_than_0 = 0;
+ int ref_buf_queue_same_dpb_count_plus_5 = 0;
+
+ mfc_debug(1, "[c:%d] src = %d, dst = %d, src_nal = %d, dst_nal = %d, ref = %d, state = %d, capstat = %d\n",
+ ctx->num, s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->src_buf_queue),
+ s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->dst_buf_queue),
+ s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->src_buf_nal_queue),
+ s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->dst_buf_nal_queue),
+ s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->ref_buf_queue),
+ ctx->state, ctx->capture_state);
+ mfc_debug(2, "wait_state = %d\n", ctx->wait_state);
+
+ src_buf_queue_greater_than_0
+ = s5p_mfc_is_queue_count_greater(&ctx->buf_queue_lock, &ctx->src_buf_queue, 0);
+ dst_buf_queue_greater_than_0
+ = s5p_mfc_is_queue_count_greater(&ctx->buf_queue_lock, &ctx->dst_buf_queue, 0);
+ ref_buf_queue_same_dpb_count_plus_5
+ = s5p_mfc_is_queue_count_same(&ctx->buf_queue_lock, &ctx->ref_buf_queue, (ctx->dpb_count + 5));
+
+ /* If shutdown is called, do not try any cmd */
+ if (dev->shutdown)
+ return 0;
+
+ /* Context is to parse header */
+ if (ctx->state == MFCINST_GOT_INST &&
+ src_buf_queue_greater_than_0)
+ return 1;
+
+ /* Context is to decode a frame */
+ if (ctx->state == MFCINST_RUNNING &&
+ ctx->wait_state == WAIT_NONE && src_buf_queue_greater_than_0 &&
+ (dst_buf_queue_greater_than_0 || ref_buf_queue_same_dpb_count_plus_5))
+ return 1;
+
+ /* Context is to return last frame */
+ if (ctx->state == MFCINST_FINISHING &&
+ (dst_buf_queue_greater_than_0 || ref_buf_queue_same_dpb_count_plus_5))
+ return 1;
+
+ /* Context is to set buffers */
+ if (ctx->state == MFCINST_HEAD_PARSED &&
+ (dst_buf_queue_greater_than_0 && ctx->wait_state == WAIT_NONE))
+ return 1;
+
+ /* Resolution change */
+ if ((ctx->state == MFCINST_RES_CHANGE_INIT || ctx->state == MFCINST_RES_CHANGE_FLUSH) &&
+ dst_buf_queue_greater_than_0)
+ return 1;
+
+ if (ctx->state == MFCINST_RES_CHANGE_END &&
+ src_buf_queue_greater_than_0)
+ return 1;
+
+ s5p_mfc_perf_cancel_drv_margin(dev);
+ mfc_debug(2, "ctx is not ready\n");
+
+ return 0;
+}
+
+int s5p_mfc_enc_ctx_ready(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc_params *p = &enc->params;
+ int src_buf_queue_greater_than_0 = 0;
+ int dst_buf_queue_greater_than_0 = 0;
+
+ mfc_debug(1, "[c:%d] src = %d, dst = %d, src_nal = %d, dst_nal = %d, ref = %d, state = %d\n",
+ ctx->num, s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->src_buf_queue),
+ s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->dst_buf_queue),
+ s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->src_buf_nal_queue),
+ s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->dst_buf_nal_queue),
+ s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->ref_buf_queue),
+ ctx->state);
+
+ src_buf_queue_greater_than_0
+ = s5p_mfc_is_queue_count_greater(&ctx->buf_queue_lock, &ctx->src_buf_queue, 0);
+ dst_buf_queue_greater_than_0
+ = s5p_mfc_is_queue_count_greater(&ctx->buf_queue_lock, &ctx->dst_buf_queue, 0);
+
+ /* If shutdown is called, do not try any cmd */
+ if (dev->shutdown)
+ return 0;
+
+ /* context is ready to make header */
+ if (ctx->state == MFCINST_GOT_INST &&
+ dst_buf_queue_greater_than_0) {
+ if (p->seq_hdr_mode == V4L2_MPEG_VIDEO_HEADER_MODE_AT_THE_READY) {
+ if (src_buf_queue_greater_than_0)
+ return 1;
+ } else {
+ return 1;
+ }
+ }
+
+ /* context is ready to allocate DPB */
+ if (ctx->state == MFCINST_HEAD_PARSED &&
+ dst_buf_queue_greater_than_0)
+ return 1;
+
+ /* context is ready to encode a frame */
+ if (ctx->state == MFCINST_RUNNING &&
+ src_buf_queue_greater_than_0 && dst_buf_queue_greater_than_0)
+ return 1;
+
+ /* context is ready to encode a frame for NAL_ABORT command */
+ if (ctx->state == MFCINST_ABORT_INST &&
+ src_buf_queue_greater_than_0 && dst_buf_queue_greater_than_0)
+ return 1;
+
+ /* context is ready to encode remain frames */
+ if (ctx->state == MFCINST_FINISHING &&
+ src_buf_queue_greater_than_0 && dst_buf_queue_greater_than_0)
+ return 1;
+
+ s5p_mfc_perf_cancel_drv_margin(dev);
+ mfc_debug(2, "ctx is not ready\n");
+
+ return 0;
+}
+
+int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx)
+{
+ if (ctx->type == MFCINST_DECODER)
+ return s5p_mfc_dec_ctx_ready(ctx);
+ else if (ctx->type == MFCINST_ENCODER)
+ return s5p_mfc_enc_ctx_ready(ctx);
+
+ return 0;
+}
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_intr.h
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __MFC_INTR_H
+#define __MFC_INTR_H __FILE__
+
+#include "mfc_common.h"
+
+#define need_to_dpb_flush(ctx) \
+ ((ctx->state == MFCINST_FINISHING) || \
+ (ctx->state == MFCINST_RUNNING))
+#define need_to_wait_nal_abort(ctx) \
+ (ctx->state == MFCINST_ABORT_INST)
+#define need_to_continue(ctx) \
+ ((ctx->state == MFCINST_DPB_FLUSHING) ||\
+ (ctx->state == MFCINST_ABORT_INST) || \
+ (ctx->state == MFCINST_RETURN_INST) || \
+ (ctx->state == MFCINST_SPECIAL_PARSING) || \
+ (ctx->state == MFCINST_SPECIAL_PARSING_NAL))
+#define need_to_special_parsing(ctx) \
+ ((ctx->state == MFCINST_GOT_INST) || \
+ (ctx->state == MFCINST_HEAD_PARSED))
+#define need_to_special_parsing_nal(ctx) \
+ (ctx->state == MFCINST_RUNNING)
+#define ready_to_get_crop(ctx) \
+ ((ctx->state == MFCINST_HEAD_PARSED) || \
+ (ctx->state == MFCINST_RUNNING) || \
+ (ctx->state == MFCINST_FINISHING))
+
+int s5p_mfc_wait_for_done_dev(struct s5p_mfc_dev *dev, int command);
+int s5p_mfc_wait_for_done_ctx(struct s5p_mfc_ctx *ctx, int command);
+void s5p_mfc_wake_up_dev(struct s5p_mfc_dev *dev, unsigned int reason,
+ unsigned int err);
+void s5p_mfc_wake_up_ctx(struct s5p_mfc_ctx *ctx, unsigned int reason,
+ unsigned int err);
+
+int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev);
+int s5p_mfc_dec_ctx_ready(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_enc_ctx_ready(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx);
+
+
+static inline void s5p_mfc_set_bit(int num, struct s5p_mfc_bits *data)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&data->lock, flags);
+ __set_bit(num, &data->bits);
+ spin_unlock_irqrestore(&data->lock, flags);
+}
+
+static inline void s5p_mfc_clear_bit(int num, struct s5p_mfc_bits *data)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&data->lock, flags);
+ __clear_bit(num, &data->bits);
+ spin_unlock_irqrestore(&data->lock, flags);
+}
+
+static inline int s5p_mfc_test_bit(int num, struct s5p_mfc_bits *data)
+{
+ unsigned long flags;
+ int ret;
+ spin_lock_irqsave(&data->lock, flags);
+ ret = test_bit(num, &data->bits);
+ spin_unlock_irqrestore(&data->lock, flags);
+ return ret;
+}
+
+static inline int s5p_mfc_is_all_bits_cleared(struct s5p_mfc_bits *data)
+{
+ unsigned long flags;
+ int ret;
+ spin_lock_irqsave(&data->lock, flags);
+ ret = ((data->bits) == 0) ? 1 : 0;
+ spin_unlock_irqrestore(&data->lock, flags);
+ return ret;
+}
+
+static inline void s5p_mfc_clear_all_bits(struct s5p_mfc_bits *data)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&data->lock, flags);
+ data->bits = 0;
+ spin_unlock_irqrestore(&data->lock, flags);
+}
+
+static inline unsigned long s5p_mfc_get_bits(struct s5p_mfc_bits *data)
+{
+ unsigned long flags;
+ unsigned long ret;
+ spin_lock_irqsave(&data->lock, flags);
+ ret = data->bits;
+ spin_unlock_irqrestore(&data->lock, flags);
+ return ret;
+}
+
+static inline void s5p_mfc_create_bits(struct s5p_mfc_bits *data)
+{
+ spin_lock_init(&data->lock);
+ s5p_mfc_clear_all_bits(data);
+}
+
+static inline void s5p_mfc_delete_bits(struct s5p_mfc_bits *data)
+{
+ s5p_mfc_clear_all_bits(data);
+}
+
+static inline int s5p_mfc_is_work_to_do(struct s5p_mfc_dev *dev)
+{
+ return (!s5p_mfc_is_all_bits_cleared(&dev->work_bits));
+}
+
+#endif /* __MFC_INTR_H */
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_utils.c
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/smc.h>
+
+#include "mfc_utils.h"
+
+int s5p_mfc_check_vb_with_fmt(struct s5p_mfc_fmt *fmt, struct vb2_buffer *vb)
+{
+ if (!fmt)
+ return -EINVAL;
+
+ if (fmt->mem_planes != vb->num_planes) {
+ mfc_err_dev("plane number is different (%d != %d)\n",
+ fmt->mem_planes, vb->num_planes);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int mfc_stream_buf_prot(struct s5p_mfc_ctx *ctx,
+ struct s5p_mfc_buf *buf, bool en)
+{
+ return 0;
+}
+
+int mfc_raw_buf_prot(struct s5p_mfc_ctx *ctx,
+ struct s5p_mfc_buf *buf, bool en)
+{
+ return 0;
+}
+
+void s5p_mfc_raw_protect(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *mfc_buf,
+ int index)
+{
+ if (!test_bit(index, &ctx->raw_protect_flag)) {
+ if (mfc_raw_buf_prot(ctx, mfc_buf, true)) {
+ mfc_err_ctx("failed to CFW_PROT\n");
+ } else {
+ set_bit(index, &ctx->raw_protect_flag);
+ mfc_debug(2, "[index:%d] raw protect, flag: %#lx\n",
+ index, ctx->raw_protect_flag);
+ }
+ }
+}
+
+void s5p_mfc_raw_unprotect(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *mfc_buf,
+ int index)
+{
+ if (test_bit(index, &ctx->raw_protect_flag)) {
+ if (mfc_raw_buf_prot(ctx, mfc_buf, false)) {
+ mfc_err_ctx("failed to CFW_UNPROT\n");
+ } else {
+ clear_bit(index, &ctx->raw_protect_flag);
+ mfc_debug(2, "[index:%d] raw unprotect, flag: %#lx\n",
+ index, ctx->raw_protect_flag);
+ }
+ }
+}
+
+void s5p_mfc_stream_protect(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *mfc_buf,
+ int index)
+{
+ if (!test_bit(index, &ctx->stream_protect_flag)) {
+ if (mfc_stream_buf_prot(ctx, mfc_buf, true)) {
+ mfc_err_ctx("failed to CFW_PROT\n");
+ } else {
+ set_bit(index, &ctx->stream_protect_flag);
+ mfc_debug(2, "[index:%d] stream protect, flag: %#lx\n",
+ index, ctx->stream_protect_flag);
+ }
+ }
+}
+
+void s5p_mfc_stream_unprotect(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *mfc_buf,
+ int index)
+{
+ if (test_bit(index, &ctx->stream_protect_flag)) {
+ if (mfc_stream_buf_prot(ctx, mfc_buf, false)) {
+ mfc_err_ctx("failed to CFW_UNPROT\n");
+ } else {
+ clear_bit(index, &ctx->stream_protect_flag);
+ mfc_debug(2, "[index:%d] stream unprotect, flag: %#lx\n",
+ index, ctx->stream_protect_flag);
+ }
+ }
+}
+
+static int mfc_calc_plane(int width, int height, int is_tiled)
+{
+ int mbX, mbY;
+
+ mbX = (width + 15)/16;
+ mbY = (height + 15)/16;
+
+ /* Alignment for interlaced processing */
+ if (is_tiled)
+ mbY = (mbY + 1) / 2 * 2;
+
+ return (mbX * 16) * (mbY * 16);
+}
+
+static void mfc_set_linear_stride_size(struct s5p_mfc_ctx *ctx,
+ struct s5p_mfc_fmt *fmt)
+{
+ struct s5p_mfc_raw_info *raw;
+ int i;
+
+ raw = &ctx->raw_buf;
+
+ switch (fmt->fourcc) {
+ case V4L2_PIX_FMT_YUV420M:
+ case V4L2_PIX_FMT_YUV420N:
+ case V4L2_PIX_FMT_YVU420M:
+ raw->stride[0] = ALIGN(ctx->img_width, 16);
+ raw->stride[1] = ALIGN(raw->stride[0] >> 1, 16);
+ raw->stride[2] = ALIGN(raw->stride[0] >> 1, 16);
+ break;
+ case V4L2_PIX_FMT_NV12MT_16X16:
+ case V4L2_PIX_FMT_NV12MT:
+ case V4L2_PIX_FMT_NV12M:
+ case V4L2_PIX_FMT_NV12N:
+ case V4L2_PIX_FMT_NV21M:
+ case V4L2_PIX_FMT_NV16M:
+ case V4L2_PIX_FMT_NV61M:
+ raw->stride[0] = ALIGN(ctx->img_width, 16);
+ raw->stride[1] = ALIGN(ctx->img_width, 16);
+ raw->stride[2] = 0;
+ break;
+ case V4L2_PIX_FMT_NV12M_S10B:
+ case V4L2_PIX_FMT_NV12N_10B:
+ case V4L2_PIX_FMT_NV21M_S10B:
+ case V4L2_PIX_FMT_NV16M_S10B:
+ case V4L2_PIX_FMT_NV61M_S10B:
+ raw->stride[0] = S10B_8B_STRIDE(ctx->img_width);
+ raw->stride[1] = S10B_8B_STRIDE(ctx->img_width);
+ raw->stride[2] = 0;
+ raw->stride_2bits[0] = S10B_2B_STRIDE(ctx->img_width);
+ raw->stride_2bits[1] = S10B_2B_STRIDE(ctx->img_width);
+ raw->stride_2bits[2] = 0;
+ break;
+ case V4L2_PIX_FMT_NV12M_P010:
+ case V4L2_PIX_FMT_NV21M_P010:
+ case V4L2_PIX_FMT_NV61M_P210:
+ case V4L2_PIX_FMT_NV16M_P210:
+ raw->stride[0] = ALIGN(ctx->img_width, 16) * 2;
+ raw->stride[1] = ALIGN(ctx->img_width, 16) * 2;
+ raw->stride[2] = 0;
+ raw->stride_2bits[0] = 0;
+ raw->stride_2bits[1] = 0;
+ raw->stride_2bits[2] = 0;
+ break;
+ case V4L2_PIX_FMT_RGB24:
+ ctx->raw_buf.stride[0] = ctx->img_width * 3;
+ ctx->raw_buf.stride[1] = 0;
+ ctx->raw_buf.stride[2] = 0;
+ break;
+ case V4L2_PIX_FMT_RGB565:
+ ctx->raw_buf.stride[0] = ctx->img_width * 2;
+ ctx->raw_buf.stride[1] = 0;
+ ctx->raw_buf.stride[2] = 0;
+ break;
+ case V4L2_PIX_FMT_RGB32X:
+ case V4L2_PIX_FMT_BGR32:
+ case V4L2_PIX_FMT_ARGB32:
+ ctx->raw_buf.stride[0] = (ctx->buf_stride > ctx->img_width) ?
+ (ALIGN(ctx->img_width, 16) * 4) : (ctx->img_width * 4);
+ ctx->raw_buf.stride[1] = 0;
+ ctx->raw_buf.stride[2] = 0;
+ break;
+ default:
+ break;
+ }
+
+ /* Decoder needs multiple of 16 alignment for stride */
+ if (ctx->type == MFCINST_DECODER) {
+ for (i = 0; i < 3; i++)
+ ctx->raw_buf.stride[i] =
+ ALIGN(ctx->raw_buf.stride[i], 16);
+ }
+}
+
+void s5p_mfc_dec_calc_dpb_size(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev;
+ struct s5p_mfc_dec *dec;
+ struct s5p_mfc_raw_info *raw;
+ int i;
+ int extra = MFC_LINEAR_BUF_SIZE;
+
+ if (!ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return;
+ }
+
+ dev = ctx->dev;
+ raw = &ctx->raw_buf;
+ raw->total_plane_size = 0;
+
+ dec = ctx->dec_priv;
+
+ for (i = 0; i < raw->num_planes; i++) {
+ raw->plane_size[i] = 0;
+ raw->plane_size_2bits[i] = 0;
+ }
+
+ switch (ctx->dst_fmt->fourcc) {
+ case V4L2_PIX_FMT_NV12M_S10B:
+ case V4L2_PIX_FMT_NV21M_S10B:
+ raw->plane_size[0] = NV12M_Y_SIZE(ctx->img_width, ctx->img_height);
+ raw->plane_size[1] = NV12M_CBCR_SIZE(ctx->img_width, ctx->img_height);
+ raw->plane_size_2bits[0] = NV12M_Y_2B_SIZE(ctx->img_width, ctx->img_height);
+ raw->plane_size_2bits[1] = NV12M_CBCR_2B_SIZE(ctx->img_width, ctx->img_height);
+ break;
+ case V4L2_PIX_FMT_NV12M:
+ case V4L2_PIX_FMT_NV21M:
+ raw->plane_size[0] = mfc_calc_plane(ctx->img_width, ctx->img_height, 0) + extra;
+ raw->plane_size[1] = mfc_calc_plane(ctx->img_width, ctx->img_height, 0) / 2 + extra;
+ break;
+ case V4L2_PIX_FMT_NV12M_P010:
+ case V4L2_PIX_FMT_NV21M_P010:
+ raw->plane_size[0] = mfc_calc_plane(ctx->img_width, ctx->img_height, 0) * 2 + extra;
+ raw->plane_size[1] = mfc_calc_plane(ctx->img_width, ctx->img_height, 0) + extra;
+ break;
+ case V4L2_PIX_FMT_YUV420M:
+ case V4L2_PIX_FMT_YVU420M:
+ raw->plane_size[0] = mfc_calc_plane(ctx->img_width, ctx->img_height, 0) + extra;
+ raw->plane_size[1] = mfc_calc_plane(ctx->img_width, ctx->img_height, 0) / 2 + extra;
+ raw->plane_size[2] = mfc_calc_plane(ctx->img_width, ctx->img_height, 0) / 2 + extra;
+ break;
+ case V4L2_PIX_FMT_NV16M_S10B:
+ case V4L2_PIX_FMT_NV61M_S10B:
+ raw->plane_size[0] = NV16M_Y_SIZE(ctx->img_width, ctx->img_height);
+ raw->plane_size[1] = NV16M_CBCR_SIZE(ctx->img_width, ctx->img_height);
+ raw->plane_size_2bits[0] = NV16M_Y_2B_SIZE(ctx->img_width, ctx->img_height);
+ raw->plane_size_2bits[1] = NV16M_CBCR_2B_SIZE(ctx->img_width, ctx->img_height);
+ break;
+ case V4L2_PIX_FMT_NV16M:
+ case V4L2_PIX_FMT_NV61M:
+ raw->plane_size[0] = mfc_calc_plane(ctx->img_width, ctx->img_height, 0) + extra;
+ raw->plane_size[1] = mfc_calc_plane(ctx->img_width, ctx->img_height, 0) + extra;
+ break;
+ case V4L2_PIX_FMT_NV16M_P210:
+ case V4L2_PIX_FMT_NV61M_P210:
+ raw->plane_size[0] = mfc_calc_plane(ctx->img_width, ctx->img_height, 0) * 2 + extra;
+ raw->plane_size[1] = mfc_calc_plane(ctx->img_width, ctx->img_height, 0) * 2 + extra;
+ break;
+ /* non-contiguous single fd format */
+ case V4L2_PIX_FMT_NV12N_10B:
+ raw->plane_size[0] = NV12N_10B_Y_8B_SIZE(ctx->img_width, ctx->img_height);
+ raw->plane_size[1] = NV12N_10B_CBCR_8B_SIZE(ctx->img_width, ctx->img_height);
+ raw->plane_size_2bits[0] = NV12N_10B_Y_2B_SIZE(ctx->img_width, ctx->img_height);
+ raw->plane_size_2bits[1] = NV12N_10B_CBCR_2B_SIZE(ctx->img_width, ctx->img_height);
+ break;
+ case V4L2_PIX_FMT_NV12N:
+ raw->plane_size[0] = NV12N_Y_SIZE(ctx->img_width, ctx->img_height);
+ raw->plane_size[1] = NV12N_CBCR_SIZE(ctx->img_width, ctx->img_height);
+ break;
+ case V4L2_PIX_FMT_YUV420N:
+ raw->plane_size[0] = YUV420N_Y_SIZE(ctx->img_width, ctx->img_height);
+ raw->plane_size[1] = YUV420N_CB_SIZE(ctx->img_width, ctx->img_height);
+ raw->plane_size[2] = YUV420N_CR_SIZE(ctx->img_width, ctx->img_height);
+ break;
+ default:
+ mfc_err_ctx("Invalid pixelformat : %s\n", ctx->dst_fmt->name);
+ break;
+ }
+
+ mfc_set_linear_stride_size(ctx, ctx->dst_fmt);
+
+ for (i = 0; i < raw->num_planes; i++) {
+ if (raw->plane_size[i] < ctx->min_dpb_size[i]) {
+ mfc_info_dev("[FRAME] plane[%d] size is changed %d -> %d\n",
+ i, raw->plane_size[i], ctx->min_dpb_size[i]);
+ raw->plane_size[i] = ctx->min_dpb_size[i];
+ }
+ }
+
+ for (i = 0; i < raw->num_planes; i++) {
+ raw->total_plane_size += raw->plane_size[i];
+ mfc_debug(2, "[FRAME] Plane[%d] size = %d, stride = %d\n",
+ i, raw->plane_size[i], raw->stride[i]);
+ }
+ if (ctx->is_10bit) {
+ for (i = 0; i < raw->num_planes; i++) {
+ raw->total_plane_size += raw->plane_size_2bits[i];
+ mfc_debug(2, "[FRAME][10BIT] Plane[%d] 2bit size = %d, stride = %d\n",
+ i, raw->plane_size_2bits[i],
+ raw->stride_2bits[i]);
+ }
+ }
+ mfc_debug(2, "[FRAME] total plane size: %d\n", raw->total_plane_size);
+
+ if (IS_H264_DEC(ctx) || IS_H264_MVC_DEC(ctx)) {
+ ctx->mv_size = DEC_MV_SIZE_MB(ctx->img_width, ctx->img_height);
+ ctx->mv_size = ALIGN(ctx->mv_size, 32);
+ } else if (IS_HEVC_DEC(ctx) || IS_BPG_DEC(ctx)) {
+ ctx->mv_size = DEC_HEVC_MV_SIZE(ctx->img_width, ctx->img_height);
+ ctx->mv_size = ALIGN(ctx->mv_size, 32);
+ } else {
+ ctx->mv_size = 0;
+ }
+}
+
+void s5p_mfc_enc_calc_src_size(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev;
+ struct s5p_mfc_raw_info *raw;
+ unsigned int mb_width, mb_height, default_size;
+ int i, extra;
+
+ if (!ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return;
+ }
+
+ dev = ctx->dev;
+ raw = &ctx->raw_buf;
+ raw->total_plane_size = 0;
+ mb_width = WIDTH_MB(ctx->img_width);
+ mb_height = HEIGHT_MB(ctx->img_height);
+ extra = MFC_LINEAR_BUF_SIZE;
+ default_size = mb_width * mb_height * 256;
+
+ for (i = 0; i < raw->num_planes; i++) {
+ raw->plane_size[i] = 0;
+ raw->plane_size_2bits[i] = 0;
+ }
+
+ switch (ctx->src_fmt->fourcc) {
+ case V4L2_PIX_FMT_YUV420M:
+ case V4L2_PIX_FMT_YUV420N:
+ case V4L2_PIX_FMT_YVU420M:
+ raw->plane_size[0] = ALIGN(default_size, 256) + extra;
+ raw->plane_size[1] = ALIGN(default_size >> 2, 256) + extra;
+ raw->plane_size[2] = ALIGN(default_size >> 2, 256) + extra;
+ break;
+ case V4L2_PIX_FMT_NV12M_S10B:
+ case V4L2_PIX_FMT_NV21M_S10B:
+ raw->plane_size[0] = NV12M_Y_SIZE(ctx->img_width, ctx->img_height);
+ raw->plane_size[1] = NV12M_CBCR_SIZE(ctx->img_width, ctx->img_height);
+ raw->plane_size_2bits[0] = NV12M_Y_2B_SIZE(ctx->img_width, ctx->img_height);
+ raw->plane_size_2bits[1] = NV12M_CBCR_2B_SIZE(ctx->img_width, ctx->img_height);
+ break;
+ case V4L2_PIX_FMT_NV12MT_16X16:
+ case V4L2_PIX_FMT_NV12M:
+ case V4L2_PIX_FMT_NV12N:
+ case V4L2_PIX_FMT_NV21M:
+ raw->plane_size[0] = ALIGN(default_size, 256) + extra;
+ raw->plane_size[1] = ALIGN(default_size / 2, 256) + extra;
+ break;
+ case V4L2_PIX_FMT_NV12M_P010:
+ case V4L2_PIX_FMT_NV21M_P010:
+ raw->plane_size[0] = ALIGN(default_size, 256) * 2 + extra;
+ raw->plane_size[1] = ALIGN(default_size, 256) + extra;
+ break;
+ case V4L2_PIX_FMT_NV16M_S10B:
+ case V4L2_PIX_FMT_NV61M_S10B:
+ raw->plane_size[0] = NV16M_Y_SIZE(ctx->img_width, ctx->img_height);
+ raw->plane_size[1] = NV16M_CBCR_SIZE(ctx->img_width, ctx->img_height);
+ raw->plane_size_2bits[0] = NV16M_Y_2B_SIZE(ctx->img_width, ctx->img_height);
+ raw->plane_size_2bits[1] = NV16M_CBCR_2B_SIZE(ctx->img_width, ctx->img_height);
+ break;
+ case V4L2_PIX_FMT_NV16M:
+ case V4L2_PIX_FMT_NV61M:
+ raw->plane_size[0] = ALIGN(default_size, 256) + extra;
+ raw->plane_size[1] = ALIGN(default_size, 256) + extra;
+ break;
+ case V4L2_PIX_FMT_NV16M_P210:
+ case V4L2_PIX_FMT_NV61M_P210:
+ raw->plane_size[0] = ALIGN(default_size, 256) * 2 + extra;
+ raw->plane_size[1] = ALIGN(default_size, 256) * 2 + extra;
+ break;
+ default:
+ mfc_err_ctx("Invalid pixel format(%d)\n", ctx->src_fmt->fourcc);
+ break;
+ }
+
+ mfc_set_linear_stride_size(ctx, ctx->src_fmt);
+
+ for (i = 0; i < raw->num_planes; i++) {
+ raw->total_plane_size += raw->plane_size[i];
+ mfc_debug(2, "[FRAME] Plane[%d] size = %d, stride = %d\n",
+ i, raw->plane_size[i], raw->stride[i]);
+ }
+ if (ctx->is_10bit) {
+ for (i = 0; i < raw->num_planes; i++) {
+ raw->total_plane_size += raw->plane_size_2bits[i];
+ mfc_debug(2, "[FRAME][10BIT] Plane[%d] 2bit size = %d, stride = %d\n",
+ i, raw->plane_size_2bits[i],
+ raw->stride_2bits[i]);
+ }
+ }
+
+ mfc_debug(2, "[FRAME] total plane size: %d\n", raw->total_plane_size);
+}
+
+void s5p_mfc_cleanup_assigned_dpb(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dec *dec;
+ struct s5p_mfc_buf *dst_mb;
+ int i;
+
+ if (!ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return;
+ }
+
+ dec = ctx->dec_priv;
+ if (!dec) {
+ mfc_err_dev("no mfc decoder to run\n");
+ return;
+ }
+
+ if (ctx->is_drm && ctx->raw_protect_flag) {
+ mfc_debug(2, "raw_protect_flag(%#lx) will be released\n",
+ ctx->raw_protect_flag);
+ for (i = 0; i < MFC_MAX_DPBS; i++) {
+ dst_mb = dec->assigned_dpb[i];
+
+ s5p_mfc_raw_unprotect(ctx, dst_mb, i);
+ }
+ s5p_mfc_clear_assigned_dpb(ctx);
+ }
+}
+
+void s5p_mfc_unprotect_released_dpb(struct s5p_mfc_ctx *ctx, unsigned int released_flag)
+{
+ struct s5p_mfc_dec *dec;
+ struct s5p_mfc_buf *dst_mb;
+ int i;
+
+ if (!ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return;
+ }
+
+ dec = ctx->dec_priv;
+ if (!dec) {
+ mfc_err_dev("no mfc decoder to run\n");
+ return;
+ }
+
+ if (ctx->is_drm) {
+ for (i = 0; i < MFC_MAX_DPBS; i++) {
+ if (released_flag & (1 << i)) {
+ dst_mb = dec->assigned_dpb[i];
+ s5p_mfc_raw_unprotect(ctx, dst_mb, i);
+ }
+ }
+ }
+
+}
+
+void s5p_mfc_protect_dpb(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *dst_mb)
+{
+ struct s5p_mfc_dec *dec;
+ int dst_index;
+
+ if (!ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return;
+ }
+
+ dec = ctx->dec_priv;
+ if (!dec) {
+ mfc_err_dev("no mfc decoder to run\n");
+ return;
+ }
+
+ dst_index = dst_mb->vb.vb2_buf.index;
+
+ if (ctx->is_drm) {
+ dec->assigned_dpb[dst_index] = dst_mb;
+ s5p_mfc_raw_protect(ctx, dst_mb, dst_index);
+ }
+}
+
+void s5p_mfc_watchdog_tick(unsigned long arg)
+{
+ struct s5p_mfc_dev *dev = (struct s5p_mfc_dev *)arg;
+
+ if (!dev) {
+ mfc_err_dev("no mfc device to run\n");
+ return;
+ }
+
+ mfc_debug(5, "watchdog is ticking!\n");
+
+ if (atomic_read(&dev->watchdog_tick_running))
+ atomic_inc(&dev->watchdog_tick_cnt);
+ else
+ atomic_set(&dev->watchdog_tick_cnt, 0);
+
+ if (atomic_read(&dev->watchdog_tick_cnt) >= WATCHDOG_TICK_CNT_TO_START_WATCHDOG) {
+ /* This means that hw is busy and no interrupts were
+ * generated by hw for the Nth time of running this
+ * watchdog timer. This usually means a serious hw
+ * error. Now it is time to kill all instances and
+ * reset the MFC. */
+ mfc_err_dev("[%d] Time out during waiting for HW\n",
+ atomic_read(&dev->watchdog_tick_cnt));
+ queue_work(dev->watchdog_wq, &dev->watchdog_work);
+ }
+
+ dev->watchdog_timer.expires = jiffies +
+ msecs_to_jiffies(WATCHDOG_TICK_INTERVAL);
+ add_timer(&dev->watchdog_timer);
+}
+
+void s5p_mfc_watchdog_start_tick(struct s5p_mfc_dev *dev)
+{
+ if (atomic_read(&dev->watchdog_tick_running)) {
+ mfc_debug(2, "watchdog timer was already started!\n");
+ } else {
+ mfc_debug(2, "watchdog timer is now started!\n");
+ atomic_set(&dev->watchdog_tick_running, 1);
+ }
+
+ /* Reset the timeout watchdog */
+ atomic_set(&dev->watchdog_tick_cnt, 0);
+}
+
+void s5p_mfc_watchdog_stop_tick(struct s5p_mfc_dev *dev)
+{
+ if (atomic_read(&dev->watchdog_tick_running)) {
+ mfc_debug(2, "watchdog timer is now stopped!\n");
+ atomic_set(&dev->watchdog_tick_running, 0);
+ } else {
+ mfc_debug(2, "watchdog timer was already stopped!\n");
+ }
+
+ /* Reset the timeout watchdog */
+ atomic_set(&dev->watchdog_tick_cnt, 0);
+}
+
+void s5p_mfc_watchdog_reset_tick(struct s5p_mfc_dev *dev)
+{
+ mfc_debug(2, "watchdog timer reset!\n");
+
+ /* Reset the timeout watchdog */
+ atomic_set(&dev->watchdog_tick_cnt, 0);
+}
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_utils.h
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __MFC_UTILS_H
+#define __MFC_UTILS_H __FILE__
+
+#include "mfc_common.h"
+
+static inline void s5p_mfc_clean_dev_int_flags(struct s5p_mfc_dev *dev)
+{
+ dev->int_condition = 0;
+ dev->int_reason = 0;
+ dev->int_err = 0;
+}
+
+static inline void s5p_mfc_clean_ctx_int_flags(struct s5p_mfc_ctx *ctx)
+{
+ ctx->int_condition = 0;
+ ctx->int_reason = 0;
+ ctx->int_err = 0;
+}
+
+static inline void s5p_mfc_change_state(struct s5p_mfc_ctx *ctx, enum s5p_mfc_inst_state state)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ MFC_TRACE_CTX("** state : %d\n", state);
+ ctx->state = state;
+}
+
+static inline enum s5p_mfc_node_type s5p_mfc_get_node_type(struct file *file)
+{
+ struct video_device *vdev = video_devdata(file);
+ enum s5p_mfc_node_type node_type;
+
+ if (!vdev) {
+ mfc_err_dev("failed to get video_device\n");
+ return MFCNODE_INVALID;
+ }
+
+ mfc_debug(2, "video_device index: %d\n", vdev->index);
+
+ switch (vdev->index) {
+ case 0:
+ node_type = MFCNODE_DECODER;
+ break;
+ case 1:
+ node_type = MFCNODE_ENCODER;
+ break;
+ case 2:
+ node_type = MFCNODE_DECODER_DRM;
+ break;
+ case 3:
+ node_type = MFCNODE_ENCODER_DRM;
+ break;
+ case 4:
+ node_type = MFCNODE_ENCODER_OTF;
+ break;
+ case 5:
+ node_type = MFCNODE_ENCODER_OTF_DRM;
+ break;
+ default:
+ node_type = MFCNODE_INVALID;
+ break;
+ }
+
+ return node_type;
+}
+
+static inline int s5p_mfc_is_decoder_node(enum s5p_mfc_node_type node)
+{
+ if (node == MFCNODE_DECODER || node == MFCNODE_DECODER_DRM)
+ return 1;
+
+ return 0;
+}
+
+static inline int s5p_mfc_is_drm_node(enum s5p_mfc_node_type node)
+{
+ if (node == MFCNODE_DECODER_DRM || node == MFCNODE_ENCODER_DRM ||
+ node == MFCNODE_ENCODER_OTF_DRM)
+ return 1;
+
+ return 0;
+}
+
+static inline int s5p_mfc_is_encoder_otf_node(enum s5p_mfc_node_type node)
+{
+ if (node == MFCNODE_ENCODER_OTF || node == MFCNODE_ENCODER_OTF_DRM)
+ return 1;
+
+ return 0;
+}
+
+int s5p_mfc_check_vb_with_fmt(struct s5p_mfc_fmt *fmt, struct vb2_buffer *vb);
+
+void s5p_mfc_raw_protect(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *mfc_buf,
+ int index);
+void s5p_mfc_raw_unprotect(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *mfc_buf,
+ int index);
+void s5p_mfc_stream_protect(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *mfc_buf,
+ int index);
+void s5p_mfc_stream_unprotect(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *mfc_buf,
+ int index);
+
+void s5p_mfc_dec_calc_dpb_size(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_enc_calc_src_size(struct s5p_mfc_ctx *ctx);
+
+static inline void s5p_mfc_cleanup_assigned_fd(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dec *dec;
+ int i;
+
+ dec = ctx->dec_priv;
+
+ for (i = 0; i < MFC_MAX_DPBS; i++)
+ dec->assigned_fd[i] = MFC_INFO_INIT_FD;
+}
+
+static inline void s5p_mfc_clear_assigned_dpb(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dec *dec;
+ int i;
+
+ if (!ctx) {
+ mfc_err_dev("no mfc context to run\n");
+ return;
+ }
+
+ dec = ctx->dec_priv;
+ if (!dec) {
+ mfc_err_dev("no mfc decoder to run\n");
+ return;
+ }
+
+ for (i = 0; i < MFC_MAX_DPBS; i++)
+ dec->assigned_dpb[i] = NULL;
+}
+
+static inline int s5p_mfc_dec_status_decoding(unsigned int dst_frame_status)
+{
+ if (dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_DISPLAY ||
+ dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_ONLY)
+ return 1;
+ return 0;
+}
+
+static inline int s5p_mfc_dec_status_display(unsigned int dst_frame_status)
+{
+ if (dst_frame_status == S5P_FIMV_DEC_STATUS_DISPLAY_ONLY ||
+ dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_DISPLAY)
+ return 1;
+
+ return 0;
+}
+
+void s5p_mfc_cleanup_assigned_dpb(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_unprotect_released_dpb(struct s5p_mfc_ctx *ctx, unsigned int released_flag);
+void s5p_mfc_protect_dpb(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *dst_mb);
+
+/* Watchdog interval */
+#define WATCHDOG_TICK_INTERVAL 1000
+/* After how many executions watchdog should assume lock up */
+#define WATCHDOG_TICK_CNT_TO_START_WATCHDOG 5
+
+void s5p_mfc_watchdog_tick(unsigned long arg);
+void s5p_mfc_watchdog_start_tick(struct s5p_mfc_dev *dev);
+void s5p_mfc_watchdog_stop_tick(struct s5p_mfc_dev *dev);
+void s5p_mfc_watchdog_reset_tick(struct s5p_mfc_dev *dev);
+
+#endif /* __MFC_UTILS_H */
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_watchdog.c
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#ifdef BIGDATA_LOGGING_ENABLE
+#include <linux/sec_debug.h>
+#endif
+
+#include "mfc_watchdog.h"
+
+#include "mfc_sync.h"
+
+#include "mfc_pm.h"
+#include "mfc_cmd.h"
+#include "mfc_cal.h"
+#include "mfc_reg.h"
+
+#include "mfc_queue.h"
+#include "mfc_utils.h"
+
+#define MFC_SFR_AREA_COUNT 21
+static void mfc_dump_regs(struct s5p_mfc_dev *dev)
+{
+ int i;
+ struct s5p_mfc_ctx_buf_size *buf_size = NULL;
+ int addr[MFC_SFR_AREA_COUNT][2] = {
+ { 0x0, 0x80 },
+ { 0x1000, 0xCD0 },
+ { 0xF000, 0xFF8 },
+ { 0x2000, 0xA00 },
+ { 0x2f00, 0x6C },
+ { 0x3000, 0x40 },
+ { 0x3094, 0x4 },
+ { 0x30b4, 0x8 },
+ { 0x3110, 0x10 },
+ { 0x5000, 0x100 },
+ { 0x5200, 0x300 },
+ { 0x5600, 0x100 },
+ { 0x5800, 0x100 },
+ { 0x5A00, 0x100 },
+ { 0x6000, 0xC4 },
+ { 0x7000, 0x21C },
+ { 0x8000, 0x20C },
+ { 0x9000, 0x10C },
+ { 0xA000, 0x20C },
+ { 0xB000, 0x444 },
+ { 0xC000, 0x84 },
+ };
+
+ pr_err("-----------dumping MFC registers (SFR base = 0x%p, dev = 0x%p)\n",
+ dev->regs_base, dev);
+
+ s5p_mfc_enable_all_clocks(dev);
+
+ for (i = 0; i < MFC_SFR_AREA_COUNT; i++) {
+ printk("[%04X .. %04X]\n", addr[i][0], addr[i][0] + addr[i][1]);
+ print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 32, 4, dev->regs_base + addr[i][0],
+ addr[i][1], false);
+ printk("...\n");
+ }
+
+ if (dbg_enable) {
+ buf_size = dev->variant->buf_size->ctx_buf;
+ printk("[DBG INFO dump]\n");
+ print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 32, 4, dev->dbg_info_buf.vaddr,
+ buf_size->dbg_info_buf, false);
+ printk("...\n");
+ }
+}
+
+const u32 s5p_mfc_logging_sfr_set1[MFC_SFR_LOGGING_COUNT_SET1] = {
+ 0x1000, 0x1004, 0x100C, 0x1010
+};
+
+const u32 s5p_mfc_logging_sfr_set2[MFC_SFR_LOGGING_COUNT_SET2] = {
+ 0x0070, 0x10B4, 0x2020, 0x2028,
+ 0x204C, 0x20B4, 0x3000, 0x3004,
+ 0x3010, 0x301C, 0x3110, 0x5A54,
+ 0x5A80, 0x5A88, 0x5A94, 0x6038,
+ 0x6050, 0x6168, 0x7018, 0x7110,
+ 0x7114, 0xF088, 0xFFD0
+};
+
+int mfc_change_hex_to_ascii(u32 hex, u32 byte, char *ascii, int idx)
+{
+ int i;
+ char tmp;
+
+ for (i = 0; i < byte; i++) {
+ if (idx >= MFC_LOGGING_DATA_SIZE) {
+ pr_err("logging data size exceed: %d\n", idx);
+ return idx;
+ }
+
+ tmp = (hex >> ((byte - 1 - i) * 4)) & 0xF;
+ if (tmp > 9)
+ ascii[idx] = tmp + 'a' - 0xa;
+ else if (tmp <= 9)
+ ascii[idx] = tmp + '0';
+ idx++;
+ }
+
+ /* space */
+ if (idx < MFC_LOGGING_DATA_SIZE)
+ ascii[idx] = ' ';
+
+ return ++idx;
+}
+
+static void mfc_save_logging_sfr(struct s5p_mfc_dev *dev)
+{
+ char *errorinfo;
+ int i, idx = 0;
+
+ pr_err("-----------logging MFC error info-----------\n");
+ errorinfo = dev->logging_data->errorinfo;
+ for (i = 0; i < MFC_SFR_LOGGING_COUNT_SET1; i++)
+ dev->logging_data->SFRs_set1[i] = MFC_READL(s5p_mfc_logging_sfr_set1[i]);
+ for (i = 0; i < MFC_SFR_LOGGING_COUNT_SET2; i++)
+ dev->logging_data->SFRs_set2[i] = MFC_READL(s5p_mfc_logging_sfr_set2[i]);
+
+ idx = mfc_change_hex_to_ascii(dev->logging_data->cause, 8, errorinfo, idx);
+ idx = mfc_change_hex_to_ascii(dev->logging_data->fault_status, 2, errorinfo, idx);
+ idx = mfc_change_hex_to_ascii(dev->logging_data->fault_trans_info, 8, errorinfo, idx);
+ idx = mfc_change_hex_to_ascii(dev->logging_data->fault_addr, 8, errorinfo, idx);
+ for (i = 0; i < MFC_SFR_LOGGING_COUNT_SET1; i++)
+ idx = mfc_change_hex_to_ascii(dev->logging_data->SFRs_set1[i], 2, errorinfo, idx);
+ for (i = 0; i < MFC_SFR_LOGGING_COUNT_SET2; i++)
+ idx = mfc_change_hex_to_ascii(dev->logging_data->SFRs_set2[i], 8, errorinfo, idx);
+
+ pr_err("%s\n", errorinfo);
+
+#ifdef BIGDATA_LOGGING_ENABLE
+ sec_debug_set_extra_info_mfc_error(errorinfo);
+#endif
+}
+
+static void mfc_display_state(struct s5p_mfc_dev *dev)
+{
+ nal_queue_handle *nal_q_handle = dev->nal_q_handle;
+ int i;
+
+ pr_err("-----------dumping MFC device info-----------\n");
+ pr_err("power:%d, clock:%d, num_inst:%d, num_drm_inst:%d, fw_status:%d\n",
+ s5p_mfc_pm_get_pwr_ref_cnt(dev), s5p_mfc_pm_get_clk_ref_cnt(dev),
+ dev->num_inst, dev->num_drm_inst, dev->fw.status);
+ pr_err("hwlock bits:%#lx / dev:%#lx, curr_ctx:%d (is_drm:%d),"
+ " preempt_ctx:%d, work_bits:%#lx\n",
+ dev->hwlock.bits, dev->hwlock.dev,
+ dev->curr_ctx, dev->curr_ctx_is_drm,
+ dev->preempt_ctx, s5p_mfc_get_bits(&dev->work_bits));
+ pr_err("options debug_level:%d, debug_mode:%d, mmcache:%d, perf_boost:%d\n",
+ debug_level, dev->pdata->debug_mode, dev->mmcache.is_on_status, perf_boost_mode);
+ pr_err("NAL-Q state:%d, exception:%d, in_exe_cnt: %d, out_exe_cnt: %d\n",
+ nal_q_handle->nal_q_state, nal_q_handle->nal_q_exception,
+ nal_q_handle->nal_q_in_handle->in_exe_count,
+ nal_q_handle->nal_q_out_handle->out_exe_count);
+
+ for (i = 0; i < MFC_NUM_CONTEXTS; i++)
+ if (dev->ctx[i])
+ pr_err("MFC ctx[%d] %s(%d) state:%d, queue_cnt(src:%d, dst:%d, ref:%d, qsrc:%d, qdst:%d)\n"
+ " interrupt(cond:%d, type:%d, err:%d)\n",
+ dev->ctx[i]->num,
+ dev->ctx[i]->type == MFCINST_DECODER ? "DEC" : "ENC",
+ dev->ctx[i]->codec_mode, dev->ctx[i]->state,
+ s5p_mfc_get_queue_count(&dev->ctx[i]->buf_queue_lock, &dev->ctx[i]->src_buf_queue),
+ s5p_mfc_get_queue_count(&dev->ctx[i]->buf_queue_lock, &dev->ctx[i]->dst_buf_queue),
+ s5p_mfc_get_queue_count(&dev->ctx[i]->buf_queue_lock, &dev->ctx[i]->ref_buf_queue),
+ s5p_mfc_get_queue_count(&dev->ctx[i]->buf_queue_lock, &dev->ctx[i]->src_buf_nal_queue),
+ s5p_mfc_get_queue_count(&dev->ctx[i]->buf_queue_lock, &dev->ctx[i]->dst_buf_nal_queue),
+ dev->ctx[i]->int_condition, dev->ctx[i]->int_reason,
+ dev->ctx[i]->int_err);
+}
+
+static void mfc_print_trace(struct s5p_mfc_dev *dev)
+{
+ int i, cnt, trace_cnt;
+
+ pr_err("-----------dumping MFC trace info-----------\n");
+
+ trace_cnt = atomic_read(&dev->trace_ref);
+ for (i = MFC_TRACE_COUNT_PRINT - 1; i >= 0; i--) {
+ cnt = ((trace_cnt + MFC_TRACE_COUNT_MAX) - i) % MFC_TRACE_COUNT_MAX;
+ pr_err("MFC trace[%d]: time=%llu, str=%s", cnt,
+ dev->mfc_trace[cnt].time, dev->mfc_trace[cnt].str);
+ }
+}
+
+void mfc_dump_buffer_info(struct s5p_mfc_dev *dev)
+{
+ struct s5p_mfc_ctx *ctx;
+
+ ctx = dev->ctx[dev->curr_ctx];
+ if (ctx) {
+ pr_err("-----------dumping MFC buffer info (fault at: %#x)\n",
+ dev->logging_data->fault_addr);
+ pr_err("common:%#llx~%#llx, instance:%#llx~%#llx, codec:%#llx~%#llx\n",
+ dev->common_ctx_buf.daddr,
+ dev->common_ctx_buf.daddr + PAGE_ALIGN(0x7800),
+ ctx->instance_ctx_buf.daddr,
+ ctx->instance_ctx_buf.daddr + ctx->instance_ctx_buf.size,
+ ctx->codec_buf.daddr,
+ ctx->codec_buf.daddr + ctx->codec_buf.size);
+ if (ctx->type == MFCINST_DECODER) {
+ pr_err("Decoder CPB:%#x++%#x, scratch:%#x++%#x, static(vp9):%#x++%#x\n",
+ MFC_READL(S5P_FIMV_D_CPB_BUFFER_ADDR),
+ MFC_READL(S5P_FIMV_D_CPB_BUFFER_SIZE),
+ MFC_READL(S5P_FIMV_D_SCRATCH_BUFFER_ADDR),
+ MFC_READL(S5P_FIMV_D_SCRATCH_BUFFER_SIZE),
+ MFC_READL(S5P_FIMV_D_STATIC_BUFFER_ADDR),
+ MFC_READL(S5P_FIMV_D_STATIC_BUFFER_SIZE));
+ pr_err("DPB [0]plane:++%#x, [1]plane:++%#x, [2]plane:++%#x, MV buffer:++%#lx\n",
+ ctx->raw_buf.plane_size[0],
+ ctx->raw_buf.plane_size[1],
+ ctx->raw_buf.plane_size[2],
+ ctx->mv_size);
+ print_hex_dump(KERN_ERR, "[0] plane ", DUMP_PREFIX_ADDRESS, 32, 4,
+ dev->regs_base + S5P_FIMV_D_FIRST_PLANE_DPB0,
+ 0x100, false);
+ print_hex_dump(KERN_ERR, "[1] plane ", DUMP_PREFIX_ADDRESS, 32, 4,
+ dev->regs_base + S5P_FIMV_D_SECOND_PLANE_DPB0,
+ 0x100, false);
+ if (ctx->dst_fmt->num_planes == 3)
+ print_hex_dump(KERN_ERR, "[2] plane ", DUMP_PREFIX_ADDRESS, 32, 4,
+ dev->regs_base + S5P_FIMV_D_THIRD_PLANE_DPB0,
+ 0x100, false);
+ print_hex_dump(KERN_ERR, "MV buffer ", DUMP_PREFIX_ADDRESS, 32, 4,
+ dev->regs_base + S5P_FIMV_D_MV_BUFFER0,
+ 0x100, false);
+ } else if (ctx->type == MFCINST_ENCODER) {
+ pr_err("Encoder SRC %dplane, [0]:%#x++%#x, [1]:%#x++%#x, [2]:%#x++%#x\n",
+ ctx->src_fmt->num_planes,
+ MFC_READL(S5P_FIMV_E_SOURCE_FIRST_ADDR),
+ ctx->raw_buf.plane_size[0],
+ MFC_READL(S5P_FIMV_E_SOURCE_SECOND_ADDR),
+ ctx->raw_buf.plane_size[1],
+ MFC_READL(S5P_FIMV_E_SOURCE_THIRD_ADDR),
+ ctx->raw_buf.plane_size[2]);
+ pr_err("DST:%#x++%#x, scratch:%#x++%#x\n",
+ MFC_READL(S5P_FIMV_E_STREAM_BUFFER_ADDR),
+ MFC_READL(S5P_FIMV_E_STREAM_BUFFER_SIZE),
+ MFC_READL(S5P_FIMV_E_SCRATCH_BUFFER_ADDR),
+ MFC_READL(S5P_FIMV_E_SCRATCH_BUFFER_SIZE));
+ pr_err("DPB [0] plane:++%#lx, [1] plane:++%#lx, ME buffer:++%#lx\n",
+ ctx->enc_priv->luma_dpb_size,
+ ctx->enc_priv->chroma_dpb_size,
+ ctx->enc_priv->me_buffer_size);
+ print_hex_dump(KERN_ERR, "[0] plane ", DUMP_PREFIX_ADDRESS, 32, 4,
+ dev->regs_base + S5P_FIMV_E_LUMA_DPB,
+ 0x44, false);
+ print_hex_dump(KERN_ERR, "[1] plane ", DUMP_PREFIX_ADDRESS, 32, 4,
+ dev->regs_base + S5P_FIMV_E_CHROMA_DPB,
+ 0x44, false);
+ print_hex_dump(KERN_ERR, "ME buffer ", DUMP_PREFIX_ADDRESS, 32, 4,
+ dev->regs_base + S5P_FIMV_E_ME_BUFFER,
+ 0x44, false);
+ } else {
+ pr_err("invalid MFC instnace type(%d)\n", ctx->type);
+ }
+ }
+}
+
+static void mfc_dump_info_without_regs(struct s5p_mfc_dev *dev)
+{
+ mfc_display_state(dev);
+ mfc_print_trace(dev);
+}
+
+static void mfc_dump_info(struct s5p_mfc_dev *dev)
+{
+ mfc_dump_info_without_regs(dev);
+ mfc_save_logging_sfr(dev);
+ mfc_dump_buffer_info(dev);
+ mfc_dump_regs(dev);
+ exynos_sysmmu_show_status(dev->device);
+}
+
+static void mfc_dump_info_and_stop_hw(struct s5p_mfc_dev *dev)
+{
+ MFC_TRACE_DEV("** mfc will stop!!!\n");
+ mfc_dump_info(dev);
+ BUG();
+}
+
+static void mfc_dump_info_and_stop_hw_debug(struct s5p_mfc_dev *dev)
+{
+ if (!dev->pdata->debug_mode)
+ return;
+
+ MFC_TRACE_DEV("** mfc will stop!!!\n");
+ mfc_dump_info(dev);
+ BUG();
+}
+
+void s5p_mfc_watchdog_worker(struct work_struct *work)
+{
+ struct s5p_mfc_dev *dev;
+ int cmd;
+
+ dev = container_of(work, struct s5p_mfc_dev, watchdog_work);
+
+ if (atomic_read(&dev->watchdog_run)) {
+ mfc_err_dev("watchdog already running???\n");
+ return;
+ }
+
+ if (!atomic_read(&dev->watchdog_tick_cnt)) {
+ mfc_err_dev("interrupt handler is called\n");
+ return;
+ }
+
+ cmd = s5p_mfc_check_risc2host(dev);
+ if (cmd) {
+ if (atomic_read(&dev->watchdog_tick_cnt) == (3 * WATCHDOG_TICK_CNT_TO_START_WATCHDOG)) {
+ mfc_err_dev("MFC driver waited for upward of %dsec\n",
+ 3 * WATCHDOG_TICK_CNT_TO_START_WATCHDOG);
+ dev->logging_data->cause |= (1 << MFC_CAUSE_NO_SCHEDULING);
+ } else {
+ mfc_err_dev("interrupt(%d) is occurred, wait scheduling\n", cmd);
+ return;
+ }
+ } else {
+ dev->logging_data->cause |= (1 << MFC_CAUSE_NO_INTERRUPT);
+ mfc_err_dev("Driver timeout error handling\n");
+ }
+
+ /* Run watchdog worker */
+ atomic_set(&dev->watchdog_run, 1);
+
+ /* Reset the timeout watchdog */
+ atomic_set(&dev->watchdog_tick_cnt, 0);
+
+ /* Stop after dumping information */
+ mfc_dump_info_and_stop_hw(dev);
+}
+
+struct s5p_mfc_dump_ops mfc_dump_ops = {
+ .dump_regs = mfc_dump_regs,
+ .dump_info = mfc_dump_info,
+ .dump_info_without_regs = mfc_dump_info_without_regs,
+ .dump_and_stop_always = mfc_dump_info_and_stop_hw,
+ .dump_and_stop_debug_mode = mfc_dump_info_and_stop_hw_debug,
+};
--- /dev/null
+/*
+ * drivers/media/platform/exynos/mfc/s5p_mfc_watchdog.h
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __MFC_WATCHDOG_H
+#define __MFC_WATCHDOG_H __FILE__
+
+#include "mfc_common.h"
+
+void s5p_mfc_watchdog_worker(struct work_struct *work);
+
+#endif /* __MFC_WATCHDOG_H */
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc.c
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/of_address.h>
-#include <linux/proc_fs.h>
-#include <video/videonode.h>
-#include <linux/of.h>
-#include <linux/smc.h>
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <linux/poll.h>
-
-#include "s5p_mfc_common.h"
-
-#include "s5p_mfc_irq.h"
-#include "s5p_mfc_dec.h"
-#include "s5p_mfc_enc.h"
-
-#include "s5p_mfc_ctrl.h"
-#include "s5p_mfc_hwlock.h"
-#include "s5p_mfc_nal_q.h"
-#include "s5p_mfc_otf.h"
-#include "s5p_mfc_watchdog.h"
-#include "s5p_mfc_debugfs.h"
-#include "s5p_mfc_opr.h"
-#include "s5p_mfc_sync.h"
-
-#include "s5p_mfc_inst.h"
-#include "s5p_mfc_pm.h"
-#include "s5p_mfc_cal.h"
-#include "s5p_mfc_perf_measure.h"
-#include "s5p_mfc_reg.h"
-#include "s5p_mfc_mmcache.h"
-
-#include "s5p_mfc_qos.h"
-#include "s5p_mfc_queue.h"
-#include "s5p_mfc_utils.h"
-#include "s5p_mfc_buf.h"
-#include "s5p_mfc_mem.h"
-
-#define CREATE_TRACE_POINTS
-#include <trace/events/mfc.h>
-
-#define S5P_MFC_NAME "s5p-mfc"
-#define S5P_MFC_DEC_NAME "s5p-mfc-dec"
-#define S5P_MFC_ENC_NAME "s5p-mfc-enc"
-#define S5P_MFC_DEC_DRM_NAME "s5p-mfc-dec-secure"
-#define S5P_MFC_ENC_DRM_NAME "s5p-mfc-enc-secure"
-#define S5P_MFC_ENC_OTF_NAME "s5p-mfc-enc-otf"
-#define S5P_MFC_ENC_OTF_DRM_NAME "s5p-mfc-enc-otf-secure"
-
-struct _mfc_trace g_mfc_trace[MFC_TRACE_COUNT_MAX];
-struct _mfc_trace g_mfc_trace_hwlock[MFC_TRACE_COUNT_MAX];
-struct s5p_mfc_dev *g_mfc_dev;
-
-#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
-static struct proc_dir_entry *mfc_proc_entry;
-
-#define MFC_PROC_ROOT "mfc"
-#define MFC_PROC_INSTANCE_NUMBER "instance_number"
-#define MFC_PROC_DRM_INSTANCE_NUMBER "drm_instance_number"
-#define MFC_PROC_FW_STATUS "fw_status"
-#endif
-
-#define DEF_DEC_SRC_FMT 9
-#define DEF_DEC_DST_FMT 5
-
-#define DEF_ENC_SRC_FMT 5
-#define DEF_ENC_DST_FMT 13
-
-void s5p_mfc_butler_worker(struct work_struct *work)
-{
- struct s5p_mfc_dev *dev;
-
- dev = container_of(work, struct s5p_mfc_dev, butler_work);
-
- s5p_mfc_try_run(dev);
-}
-
-extern struct s5p_mfc_ctrls_ops decoder_ctrls_ops;
-extern struct vb2_ops s5p_mfc_dec_qops;
-extern struct s5p_mfc_fmt dec_formats[];
-
-static void mfc_deinit_dec_ctx(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dec *dec = ctx->dec_priv;
-
- s5p_mfc_delete_queue(&ctx->src_buf_queue);
- s5p_mfc_delete_queue(&ctx->dst_buf_queue);
- s5p_mfc_delete_queue(&ctx->src_buf_nal_queue);
- s5p_mfc_delete_queue(&ctx->dst_buf_nal_queue);
- s5p_mfc_delete_queue(&ctx->ref_buf_queue);
-
- s5p_mfc_mem_cleanup_user_shared_handle(ctx, &dec->sh_handle);
- kfree(dec->ref_info);
- kfree(dec);
-}
-
-static int mfc_init_dec_ctx(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dec *dec;
- int ret = 0;
- int i;
-
- dec = kzalloc(sizeof(struct s5p_mfc_dec), GFP_KERNEL);
- if (!dec) {
- mfc_err_dev("failed to allocate decoder private data\n");
- return -ENOMEM;
- }
- ctx->dec_priv = dec;
-
- ctx->inst_no = MFC_NO_INSTANCE_SET;
-
- s5p_mfc_create_queue(&ctx->src_buf_queue);
- s5p_mfc_create_queue(&ctx->dst_buf_queue);
- s5p_mfc_create_queue(&ctx->src_buf_nal_queue);
- s5p_mfc_create_queue(&ctx->dst_buf_nal_queue);
- s5p_mfc_create_queue(&ctx->ref_buf_queue);
-
- for (i = 0; i < MFC_MAX_BUFFERS; i++) {
- INIT_LIST_HEAD(&ctx->src_ctrls[i]);
- INIT_LIST_HEAD(&ctx->dst_ctrls[i]);
- }
- ctx->src_ctrls_avail = 0;
- ctx->dst_ctrls_avail = 0;
-
- ctx->capture_state = QUEUE_FREE;
- ctx->output_state = QUEUE_FREE;
-
- s5p_mfc_change_state(ctx, MFCINST_INIT);
- ctx->type = MFCINST_DECODER;
- ctx->c_ops = &decoder_ctrls_ops;
- ctx->src_fmt = &dec_formats[DEF_DEC_SRC_FMT];
- ctx->dst_fmt = &dec_formats[DEF_DEC_DST_FMT];
-
- s5p_mfc_qos_reset_framerate(ctx);
-
- ctx->qos_ratio = 100;
-#ifdef CONFIG_MFC_USE_BUS_DEVFREQ
- INIT_LIST_HEAD(&ctx->qos_list);
-#endif
- INIT_LIST_HEAD(&ctx->ts_list);
-
- dec->display_delay = -1;
- dec->is_interlaced = 0;
- dec->immediate_display = 0;
- dec->is_dts_mode = 0;
- dec->err_reuse_flag = 0;
- dec->dec_only_release_flag = 0;
-
- dec->is_dynamic_dpb = 1;
- dec->dynamic_used = 0;
- dec->is_dpb_full = 0;
- s5p_mfc_cleanup_assigned_fd(ctx);
- s5p_mfc_clear_assigned_dpb(ctx);
- dec->sh_handle.fd = -1;
- dec->ref_info = kzalloc(
- (sizeof(struct dec_dpb_ref_info) * MFC_MAX_DPBS), GFP_KERNEL);
- if (!dec->ref_info) {
- mfc_err_dev("failed to allocate decoder information data\n");
- ret = -ENOMEM;
- goto fail_dec_init;
- }
- for (i = 0; i < MFC_MAX_BUFFERS; i++)
- dec->ref_info[i].dpb[0].fd[0] = MFC_INFO_INIT_FD;
-
- /* Init videobuf2 queue for OUTPUT */
- ctx->vq_src.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
- ctx->vq_src.drv_priv = ctx;
- ctx->vq_src.buf_struct_size = sizeof(struct s5p_mfc_buf);
- ctx->vq_src.io_modes = VB2_USERPTR | VB2_DMABUF;
- ctx->vq_src.ops = &s5p_mfc_dec_qops;
- ctx->vq_src.mem_ops = s5p_mfc_mem_ops();
- ctx->vq_src.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
- ret = vb2_queue_init(&ctx->vq_src);
- if (ret) {
- mfc_err_dev("Failed to initialize videobuf2 queue(output)\n");
- goto fail_dec_init;
- }
- /* Init videobuf2 queue for CAPTURE */
- ctx->vq_dst.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- ctx->vq_dst.drv_priv = ctx;
- ctx->vq_dst.buf_struct_size = sizeof(struct s5p_mfc_buf);
- ctx->vq_dst.io_modes = VB2_USERPTR | VB2_DMABUF;
- ctx->vq_dst.ops = &s5p_mfc_dec_qops;
- ctx->vq_dst.mem_ops = s5p_mfc_mem_ops();
- ctx->vq_dst.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
- ret = vb2_queue_init(&ctx->vq_dst);
- if (ret) {
- mfc_err_dev("Failed to initialize videobuf2 queue(capture)\n");
- goto fail_dec_init;
- }
-
- return ret;
-
-fail_dec_init:
- mfc_deinit_dec_ctx(ctx);
- return ret;
-}
-
-extern struct s5p_mfc_ctrls_ops encoder_ctrls_ops;
-extern struct vb2_ops s5p_mfc_enc_qops;
-extern struct s5p_mfc_fmt enc_formats[];
-
-static void mfc_deinit_enc_ctx(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_enc *enc = ctx->enc_priv;
-
- s5p_mfc_delete_queue(&ctx->src_buf_queue);
- s5p_mfc_delete_queue(&ctx->dst_buf_queue);
- s5p_mfc_delete_queue(&ctx->src_buf_nal_queue);
- s5p_mfc_delete_queue(&ctx->dst_buf_nal_queue);
- s5p_mfc_delete_queue(&ctx->ref_buf_queue);
-
- s5p_mfc_mem_cleanup_user_shared_handle(ctx, &enc->sh_handle_svc);
- s5p_mfc_mem_cleanup_user_shared_handle(ctx, &enc->sh_handle_roi);
- s5p_mfc_release_enc_roi_buffer(ctx);
- kfree(enc);
-}
-
-static int mfc_init_enc_ctx(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_enc *enc;
- struct s5p_mfc_enc_params *p;
- int ret = 0;
- int i;
-
- enc = kzalloc(sizeof(struct s5p_mfc_enc), GFP_KERNEL);
- if (!enc) {
- mfc_err_dev("failed to allocate encoder private data\n");
- return -ENOMEM;
- }
- ctx->enc_priv = enc;
-
- ctx->inst_no = MFC_NO_INSTANCE_SET;
-
- s5p_mfc_create_queue(&ctx->src_buf_queue);
- s5p_mfc_create_queue(&ctx->dst_buf_queue);
- s5p_mfc_create_queue(&ctx->src_buf_nal_queue);
- s5p_mfc_create_queue(&ctx->dst_buf_nal_queue);
- s5p_mfc_create_queue(&ctx->ref_buf_queue);
-
- for (i = 0; i < MFC_MAX_BUFFERS; i++) {
- INIT_LIST_HEAD(&ctx->src_ctrls[i]);
- INIT_LIST_HEAD(&ctx->dst_ctrls[i]);
- }
- ctx->src_ctrls_avail = 0;
- ctx->dst_ctrls_avail = 0;
-
- ctx->type = MFCINST_ENCODER;
- ctx->c_ops = &encoder_ctrls_ops;
- ctx->src_fmt = &enc_formats[DEF_ENC_SRC_FMT];
- ctx->dst_fmt = &enc_formats[DEF_ENC_DST_FMT];
-
- s5p_mfc_qos_reset_framerate(ctx);
-
- ctx->qos_ratio = 100;
-
- /* disable IVF header by default (VP8, VP9) */
- p = &enc->params;
- p->ivf_header_disable = 1;
-
-#ifdef CONFIG_MFC_USE_BUS_DEVFREQ
- INIT_LIST_HEAD(&ctx->qos_list);
-#endif
- INIT_LIST_HEAD(&ctx->ts_list);
-
- enc->sh_handle_svc.fd = -1;
- enc->sh_handle_roi.fd = -1;
-
- /* Init videobuf2 queue for OUTPUT */
- ctx->vq_src.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
- ctx->vq_src.drv_priv = ctx;
- ctx->vq_src.buf_struct_size = sizeof(struct s5p_mfc_buf);
- ctx->vq_src.io_modes = VB2_USERPTR | VB2_DMABUF;
- ctx->vq_src.ops = &s5p_mfc_enc_qops;
- ctx->vq_src.mem_ops = s5p_mfc_mem_ops();
- ctx->vq_src.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
- ret = vb2_queue_init(&ctx->vq_src);
- if (ret) {
- mfc_err_dev("Failed to initialize videobuf2 queue(output)\n");
- goto fail_enc_init;
- }
-
- /* Init videobuf2 queue for CAPTURE */
- ctx->vq_dst.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- ctx->vq_dst.drv_priv = ctx;
- ctx->vq_dst.buf_struct_size = sizeof(struct s5p_mfc_buf);
- ctx->vq_dst.io_modes = VB2_USERPTR | VB2_DMABUF;
- ctx->vq_dst.ops = &s5p_mfc_enc_qops;
- ctx->vq_dst.mem_ops = s5p_mfc_mem_ops();
- ctx->vq_dst.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
- ret = vb2_queue_init(&ctx->vq_dst);
- if (ret) {
- mfc_err_dev("Failed to initialize videobuf2 queue(capture)\n");
- goto fail_enc_init;
- }
-
- return 0;
-
-fail_enc_init:
- mfc_deinit_enc_ctx(ctx);
- return 0;
-}
-
-static int mfc_init_instance(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx)
-{
- int ret = 0;
-
- dev->watchdog_timer.expires = jiffies +
- msecs_to_jiffies(WATCHDOG_TICK_INTERVAL);
- add_timer(&dev->watchdog_timer);
-
- /* Load the FW */
- if (!dev->fw.status) {
- ret = s5p_mfc_alloc_firmware(dev);
- if (ret)
- goto err_fw_alloc;
- dev->fw.status = 1;
- }
-
- ret = s5p_mfc_load_firmware(dev);
- if (ret)
- goto err_fw_load;
-
-#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
- trace_mfc_dcpp_start(ctx->num, 1, dev->fw.drm_status);
- if (!dev->drm_fw_buf.daddr) {
- mfc_err_ctx("DRM F/W buffer is not allocated\n");
- dev->fw.drm_status = 0;
- } else {
- /* Request buffer protection for DRM F/W */
- ret = exynos_smc(SMC_DRM_PPMP_MFCFW_PROT,
- dev->drm_fw_buf.daddr, 0, 0);
- if (ret != DRMDRV_OK) {
- mfc_err_ctx("failed MFC DRM F/W prot(%#x)\n", ret);
- call_dop(dev, dump_and_stop_debug_mode, dev);
- dev->fw.drm_status = 0;
- } else {
- dev->fw.drm_status = 1;
- }
- }
-#endif
- trace_mfc_dcpp_end(ctx->num, 1, dev->fw.drm_status);
-
- ret = s5p_mfc_alloc_common_context(dev);
- if (ret)
- goto err_context_alloc;
-
- if (dbg_enable)
- s5p_mfc_alloc_dbg_info_buffer(dev);
-
- MFC_TRACE_DEV_HWLOCK("**open\n");
- ret = s5p_mfc_get_hwlock_dev(dev);
- if (ret < 0) {
- mfc_err_dev("Failed to get hwlock\n");
- mfc_err_dev("dev.hwlock.dev = 0x%lx, bits = 0x%lx, owned_by_irq = %d, wl_count = %d, transfer_owner = %d\n",
- dev->hwlock.dev, dev->hwlock.bits, dev->hwlock.owned_by_irq,
- dev->hwlock.wl_count, dev->hwlock.transfer_owner);
- goto err_hw_lock;
- }
-
- mfc_debug(2, "power on\n");
- ret = s5p_mfc_pm_power_on(dev);
- if (ret < 0) {
- mfc_err_ctx("power on failed\n");
- goto err_pwr_enable;
- }
-
- dev->curr_ctx = ctx->num;
- dev->preempt_ctx = MFC_NO_INSTANCE_SET;
- dev->curr_ctx_is_drm = ctx->is_drm;
-
- ret = s5p_mfc_init_hw(dev);
- if (ret) {
- mfc_err_ctx("Failed to init mfc h/w\n");
- goto err_hw_init;
- }
-
- if (dev->has_mmcache && (dev->mmcache.is_on_status == 0))
- s5p_mfc_mmcache_enable(dev);
-
-
- s5p_mfc_release_hwlock_dev(dev);
-
- if (MFC_FEATURE_SUPPORT(dev, dev->pdata->nal_q)) {
- dev->nal_q_handle = s5p_mfc_nal_q_create(dev);
- if (dev->nal_q_handle == NULL)
- mfc_err_dev("[NALQ] Can't create nal q\n");
- }
-
- return ret;
-
-err_hw_init:
- s5p_mfc_pm_power_off(dev);
-
-err_pwr_enable:
- s5p_mfc_release_hwlock_dev(dev);
-
-err_hw_lock:
- s5p_mfc_release_common_context(dev);
-
-err_context_alloc:
-#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
- if (dev->fw.drm_status) {
- int smc_ret = 0;
- dev->fw.drm_status = 0;
- /* Request buffer unprotection for DRM F/W */
- smc_ret = exynos_smc(SMC_DRM_PPMP_MFCFW_UNPROT,
- dev->drm_fw_buf.daddr, 0, 0);
- if (smc_ret != DRMDRV_OK) {
- mfc_err_ctx("failed MFC DRM F/W unprot(%#x)\n", smc_ret);
- call_dop(dev, dump_and_stop_debug_mode, dev);
- }
- }
-#endif
-
-err_fw_load:
-err_fw_alloc:
- del_timer_sync(&dev->watchdog_timer);
-
- mfc_err_dev("failed to init first instance\n");
- return ret;
-}
-
-/* Open an MFC node */
-static int s5p_mfc_open(struct file *file)
-{
- struct s5p_mfc_ctx *ctx = NULL;
- struct s5p_mfc_dev *dev = video_drvdata(file);
- int ret = 0;
- enum s5p_mfc_node_type node;
- struct video_device *vdev = NULL;
-
- mfc_debug(2, "mfc driver open called\n");
-
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- goto err_no_device;
- }
-
- if (mutex_lock_interruptible(&dev->mfc_mutex))
- return -ERESTARTSYS;
-
- node = s5p_mfc_get_node_type(file);
- if (node == MFCNODE_INVALID) {
- mfc_err_dev("cannot specify node type\n");
- ret = -ENOENT;
- goto err_node_type;
- }
-
- dev->num_inst++; /* It is guarded by mfc_mutex in vfd */
-
- /* Allocate memory for context */
- ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
- if (!ctx) {
- mfc_err_dev("Not enough memory\n");
- ret = -ENOMEM;
- goto err_ctx_alloc;
- }
-
- switch (node) {
- case MFCNODE_DECODER:
- vdev = dev->vfd_dec;
- break;
- case MFCNODE_ENCODER:
- vdev = dev->vfd_enc;
- break;
- case MFCNODE_DECODER_DRM:
- vdev = dev->vfd_dec_drm;
- break;
- case MFCNODE_ENCODER_DRM:
- vdev = dev->vfd_enc_drm;
- break;
- case MFCNODE_ENCODER_OTF:
- vdev = dev->vfd_enc_otf;
- break;
- case MFCNODE_ENCODER_OTF_DRM:
- vdev = dev->vfd_enc_otf_drm;
- break;
- default:
- mfc_err_dev("Invalid node(%d)\n", node);
- break;
- }
-
- if (!vdev)
- goto err_vdev;
-
- v4l2_fh_init(&ctx->fh, vdev);
- file->private_data = &ctx->fh;
- v4l2_fh_add(&ctx->fh);
-
- ctx->dev = dev;
-
- /* Get context number */
- ctx->num = 0;
- while (dev->ctx[ctx->num]) {
- ctx->num++;
- if (ctx->num >= MFC_NUM_CONTEXTS) {
- mfc_err_dev("Too many open contexts\n");
- ret = -EBUSY;
- goto err_ctx_num;
- }
- }
-
- init_waitqueue_head(&ctx->cmd_wq);
- s5p_mfc_init_listable_wq_ctx(ctx);
- spin_lock_init(&ctx->buf_queue_lock);
-
- if (s5p_mfc_is_decoder_node(node))
- ret = mfc_init_dec_ctx(ctx);
- else
- ret = mfc_init_enc_ctx(ctx);
- if (ret)
- goto err_ctx_init;
-
- ret = call_cop(ctx, init_ctx_ctrls, ctx);
- if (ret) {
- mfc_err_ctx("failed in init_ctx_ctrls\n");
- goto err_ctx_ctrls;
- }
-
-#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
- if (s5p_mfc_is_drm_node(node)) {
- if (dev->num_drm_inst < MFC_MAX_DRM_CTX) {
- if (ctx->raw_protect_flag || ctx->stream_protect_flag) {
- mfc_err_ctx("protect_flag(%#lx/%#lx) remained\n",
- ctx->raw_protect_flag,
- ctx->stream_protect_flag);
- ret = -EINVAL;
- goto err_drm_start;
- }
- dev->num_drm_inst++;
- ctx->is_drm = 1;
-
- mfc_info_ctx("DRM instance is opened [%d:%d]\n",
- dev->num_drm_inst, dev->num_inst);
- } else {
- mfc_err_ctx("Too many instance are opened for DRM\n");
- ret = -EINVAL;
- goto err_drm_start;
- }
- } else {
- mfc_info_ctx("NORMAL instance is opened [%d:%d]\n",
- dev->num_drm_inst, dev->num_inst);
- }
-#endif
-
- /* Mark context as idle */
- s5p_mfc_clear_bit(ctx->num, &dev->work_bits);
- dev->ctx[ctx->num] = ctx;
-
- /* Load firmware if this is the first instance */
- if (dev->num_inst == 1) {
- ret = mfc_init_instance(dev, ctx);
- if (ret)
- goto err_init_inst;
-
- if (perf_boost_mode)
- s5p_mfc_perf_boost_enable(dev);
- }
-
-#ifdef CONFIG_VIDEO_EXYNOS_REPEATER
- if (s5p_mfc_is_encoder_otf_node(node)) {
- ret = s5p_mfc_otf_create(ctx);
- if (ret)
- mfc_err_ctx("[OTF] otf_create failed\n");
- }
-#endif
-
- s5p_mfc_perf_init(dev);
- trace_mfc_node_open(ctx->num, dev->num_inst, ctx->type, ctx->is_drm);
- mfc_info_ctx("MFC open completed [%d:%d] dev = 0x%p, ctx = 0x%p, version = %d\n",
- dev->num_drm_inst, dev->num_inst, dev, ctx, MFC_DRIVER_INFO);
- mutex_unlock(&dev->mfc_mutex);
- return ret;
-
- /* Deinit when failure occured */
-err_init_inst:
-#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
- if (ctx->is_drm)
- dev->num_drm_inst--;
-
-err_drm_start:
-#endif
- call_cop(ctx, cleanup_ctx_ctrls, ctx);
-
-err_ctx_ctrls:
-err_ctx_init:
- dev->ctx[ctx->num] = 0;
-
-err_ctx_num:
- v4l2_fh_del(&ctx->fh);
- v4l2_fh_exit(&ctx->fh);
-
-err_vdev:
- kfree(ctx);
-
-err_ctx_alloc:
- dev->num_inst--;
-
-err_node_type:
- mfc_info_dev("MFC driver open is failed [%d:%d]\n",
- dev->num_drm_inst, dev->num_inst);
- mutex_unlock(&dev->mfc_mutex);
-
-err_no_device:
-
- return ret;
-}
-
-static int mfc_wait_close_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx)
-{
- if (atomic_read(&dev->watchdog_run)) {
- mfc_err_ctx("watchdog already running!\n");
- return 0;
- }
-
- if (ctx->inst_no == MFC_NO_INSTANCE_SET) {
- mfc_debug(2, "mfc no instance already\n");
- return 0;
- }
-
- s5p_mfc_clean_ctx_int_flags(ctx);
- s5p_mfc_change_state(ctx, MFCINST_RETURN_INST);
- s5p_mfc_set_bit(ctx->num, &dev->work_bits);
-
- /* To issue the command 'CLOSE_INSTANCE' */
- if (s5p_mfc_just_run(dev, ctx->num)) {
- mfc_err_ctx("Failed to run MFC\n");
- return -EIO;
- }
-
- /* Wait until instance is returned or timeout occured */
- if (s5p_mfc_wait_for_done_ctx(ctx,
- S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET) == 1) {
- mfc_err_ctx("Waiting for CLOSE_INSTANCE timed out\n");
- if (s5p_mfc_wait_for_done_ctx(ctx,
- S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET)) {
- mfc_err_ctx("waiting once more but timed out\n");
- dev->logging_data->cause |= (1 << MFC_CAUSE_FAIL_CLOSE_INST);
- call_dop(dev, dump_and_stop_always, dev);
- }
- }
-
- ctx->inst_no = MFC_NO_INSTANCE_SET;
-
- return 0;
-}
-
-/* Release MFC context */
-static int s5p_mfc_release(struct file *file)
-{
- struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
- struct s5p_mfc_dev *dev = NULL;
- int ret = 0;
-
- dev = ctx->dev;
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
-
- mutex_lock(&dev->mfc_mutex);
-
- mfc_info_ctx("MFC driver release is called [%d:%d], is_drm(%d)\n",
- dev->num_drm_inst, dev->num_inst, ctx->is_drm);
-
- s5p_mfc_clear_bit(ctx->num, &dev->work_bits);
-
- /* If a H/W operation is in progress, wait for it complete */
- if (need_to_wait_nal_abort(ctx)) {
- if (s5p_mfc_wait_for_done_ctx(ctx, S5P_FIMV_R2H_CMD_NAL_ABORT_RET)) {
- mfc_err_ctx("Failed to wait nal abort\n");
- s5p_mfc_cleanup_work_bit_and_try_run(ctx);
- }
- }
- MFC_TRACE_CTX_HWLOCK("**release\n");
- ret = s5p_mfc_get_hwlock_ctx(ctx);
- if (ret < 0) {
- mfc_err_dev("Failed to get hwlock\n");
- mutex_unlock(&dev->mfc_mutex);
- return -EBUSY;
- }
-
- if (call_cop(ctx, cleanup_ctx_ctrls, ctx) < 0)
- mfc_err_ctx("failed in cleanup_ctx_ctrl\n");
-
- v4l2_fh_del(&ctx->fh);
- v4l2_fh_exit(&ctx->fh);
-
- /* Mark context as idle */
- s5p_mfc_clear_bit(ctx->num, &dev->work_bits);
-
- /* If instance was initialised then
- * return instance and free reosurces */
- ret = mfc_wait_close_inst(dev, ctx);
- if (ret)
- goto err_release_try;
-
- if (ctx->is_drm)
- dev->num_drm_inst--;
- dev->num_inst--;
-
- if (dev->num_inst == 0) {
- s5p_mfc_deinit_hw(dev);
-
- if (perf_boost_mode)
- s5p_mfc_perf_boost_disable(dev);
-
- del_timer_sync(&dev->watchdog_timer);
-
- flush_workqueue(dev->butler_wq);
-
- mfc_debug(2, "power off\n");
- s5p_mfc_pm_power_off(dev);
-
- if (dbg_enable)
- s5p_mfc_release_dbg_info_buffer(dev);
-
- s5p_mfc_release_common_context(dev);
-
-#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
- if (dev->fw.drm_status) {
- dev->fw.drm_status = 0;
- /* Request buffer unprotection for DRM F/W */
- ret = exynos_smc(SMC_DRM_PPMP_MFCFW_UNPROT,
- dev->drm_fw_buf.daddr, 0, 0);
- if (ret != DRMDRV_OK) {
- mfc_err_ctx("failed MFC DRM F/W unprot(%#x)\n", ret);
- call_dop(dev, dump_and_stop_debug_mode, dev);
- goto err_release;
- }
- }
-#endif
-
- if (dev->nal_q_handle) {
- ret = s5p_mfc_nal_q_destroy(dev, dev->nal_q_handle);
- if (ret) {
- mfc_err_ctx("failed nal_q destroy\n");
- goto err_release;
- }
- }
- }
-
- s5p_mfc_qos_off(ctx);
-
- if (dev->has_mmcache && dev->mmcache.is_on_status) {
- s5p_mfc_invalidate_mmcache(dev);
-
- if (dev->num_inst == 0)
- s5p_mfc_mmcache_disable(dev);
- }
-
- s5p_mfc_release_codec_buffers(ctx);
- s5p_mfc_release_instance_context(ctx);
-
- s5p_mfc_release_hwlock_ctx(ctx);
-
- /* Free resources */
- vb2_queue_release(&ctx->vq_src);
- vb2_queue_release(&ctx->vq_dst);
-
- if (ctx->type == MFCINST_DECODER)
- mfc_deinit_dec_ctx(ctx);
- else if (ctx->type == MFCINST_ENCODER)
- mfc_deinit_enc_ctx(ctx);
-
-#ifdef CONFIG_VIDEO_EXYNOS_REPEATER
- if (ctx->otf_handle) {
- s5p_mfc_otf_deinit(ctx);
- s5p_mfc_otf_destroy(ctx);
- }
-#endif
-
- s5p_mfc_destroy_listable_wq_ctx(ctx);
-
- trace_mfc_node_close(ctx->num, dev->num_inst, ctx->type, ctx->is_drm);
-
- dev->ctx[ctx->num] = 0;
- kfree(ctx);
-
- s5p_mfc_perf_print();
-
- mfc_info_dev("mfc driver release finished [%d:%d], dev = 0x%p\n",
- dev->num_drm_inst, dev->num_inst, dev);
-
- if (s5p_mfc_is_work_to_do(dev))
- queue_work(dev->butler_wq, &dev->butler_work);
-
- mutex_unlock(&dev->mfc_mutex);
- return ret;
-
-err_release:
- s5p_mfc_release_hwlock_ctx(ctx);
- mutex_unlock(&dev->mfc_mutex);
- return ret;
-
-err_release_try:
- s5p_mfc_release_hwlock_ctx(ctx);
- s5p_mfc_cleanup_work_bit_and_try_run(ctx);
- mutex_unlock(&dev->mfc_mutex);
- return ret;
-}
-
-/* Poll */
-static unsigned int s5p_mfc_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
- unsigned long req_events = poll_requested_events(wait);
- unsigned int ret = 0;
-
- mfc_debug_enter();
-
- if (req_events & (POLLOUT | POLLWRNORM)) {
- mfc_debug(2, "wait source buffer\n");
- ret = vb2_poll(&ctx->vq_src, file, wait);
- } else if (req_events & (POLLIN | POLLRDNORM)) {
- mfc_debug(2, "wait destination buffer\n");
- ret = vb2_poll(&ctx->vq_dst, file, wait);
- }
-
- mfc_debug_leave();
- return ret;
-}
-
-/* Mmap */
-static int s5p_mfc_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
- unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
- int ret;
-
- mfc_debug_enter();
-
- if (offset < DST_QUEUE_OFF_BASE) {
- mfc_debug(2, "mmaping source\n");
- ret = vb2_mmap(&ctx->vq_src, vma);
- } else { /* capture */
- mfc_debug(2, "mmaping destination\n");
- vma->vm_pgoff -= (DST_QUEUE_OFF_BASE >> PAGE_SHIFT);
- ret = vb2_mmap(&ctx->vq_dst, vma);
- }
- mfc_debug_leave();
- return ret;
-}
-
-/* v4l2 ops */
-static const struct v4l2_file_operations s5p_mfc_fops = {
- .owner = THIS_MODULE,
- .open = s5p_mfc_open,
- .release = s5p_mfc_release,
- .poll = s5p_mfc_poll,
- .unlocked_ioctl = video_ioctl2,
- .mmap = s5p_mfc_mmap,
-};
-
-#ifdef CONFIG_MFC_USE_BUS_DEVFREQ
-static int mfc_parse_mfc_qos_platdata(struct device_node *np, char *node_name,
- struct s5p_mfc_qos *qosdata)
-{
- int ret = 0;
- struct device_node *np_qos;
-
- np_qos = of_find_node_by_name(np, node_name);
- if (!np_qos) {
- pr_err("%s: could not find mfc_qos_platdata node\n",
- node_name);
- return -EINVAL;
- }
-
- of_property_read_u32(np_qos, "thrd_mb", &qosdata->threshold_mb);
- of_property_read_u32(np_qos, "freq_mfc", &qosdata->freq_mfc);
- of_property_read_u32(np_qos, "freq_int", &qosdata->freq_int);
- of_property_read_u32(np_qos, "freq_mif", &qosdata->freq_mif);
- of_property_read_u32(np_qos, "mo_value", &qosdata->mo_value);
- of_property_read_u32(np_qos, "mo_10bit_value", &qosdata->mo_10bit_value);
- of_property_read_u32(np_qos, "mo_uhd_enc60_value", &qosdata->mo_uhd_enc60_value);
- of_property_read_u32(np_qos, "time_fw", &qosdata->time_fw);
-
- return ret;
-}
-#endif
-
-int s5p_mfc_sysmmu_fault_handler(struct iommu_domain *iodmn, struct device *device,
- unsigned long addr, int id, void *param)
-{
- struct s5p_mfc_dev *dev;
-
- dev = (struct s5p_mfc_dev *)param;
-
- /* [OTF] If AxID is 1 in SYSMMU1 fault info, it is TS-MUX fault */
- if (dev->has_hwfc && dev->has_2sysmmu) {
- if (MFC_MMU1_READL(MFC_MMU_INTERRUPT_STATUS) &&
- ((MFC_MMU1_READL(MFC_MMU_FAULT_TRANS_INFO) &
- MFC_MMU_FAULT_TRANS_INFO_AXID_MASK) == 1)) {
- mfc_err_dev("There is TS-MUX page fault. skip SFR dump\n");
- return 0;
- }
- }
-
- /* If sysmmu is used with other IPs, it should be checked whether it's an MFC fault */
- if (dev->pdata->share_sysmmu) {
- if ((MFC_MMU0_READL(MFC_MMU_FAULT_TRANS_INFO) & dev->pdata->axid_mask)
- != dev->pdata->mfc_fault_num) {
- mfc_err_dev("This is not a MFC page fault\n");
- return 0;
- }
- }
-
- if (MFC_MMU0_READL(MFC_MMU_INTERRUPT_STATUS)) {
- if (MFC_MMU0_READL(MFC_MMU_FAULT_TRANS_INFO) & MFC_MMU_FAULT_TRANS_INFO_RW_MASK)
- dev->logging_data->cause |= (1 << MFC_CAUSE_0WRITE_PAGE_FAULT);
- else
- dev->logging_data->cause |= (1 << MFC_CAUSE_0READ_PAGE_FAULT);
- dev->logging_data->fault_status = MFC_MMU0_READL(MFC_MMU_INTERRUPT_STATUS);
- dev->logging_data->fault_trans_info = MFC_MMU0_READL(MFC_MMU_FAULT_TRANS_INFO);
- }
-
- if (dev->has_2sysmmu) {
- if (MFC_MMU1_READL(MFC_MMU_INTERRUPT_STATUS)) {
- if (MFC_MMU1_READL(MFC_MMU_FAULT_TRANS_INFO) & MFC_MMU_FAULT_TRANS_INFO_RW_MASK)
- dev->logging_data->cause |= (1 << MFC_CAUSE_1WRITE_PAGE_FAULT);
- else
- dev->logging_data->cause |= (1 << MFC_CAUSE_1READ_PAGE_FAULT);
- dev->logging_data->fault_status = MFC_MMU1_READL(MFC_MMU_INTERRUPT_STATUS);
- dev->logging_data->fault_trans_info = MFC_MMU1_READL(MFC_MMU_FAULT_TRANS_INFO);
- }
- }
- dev->logging_data->fault_addr = (unsigned int)addr;
-
- call_dop(dev, dump_info, dev);
-
- return 0;
-}
-
-static void mfc_parse_dt(struct device_node *np, struct s5p_mfc_dev *mfc)
-{
- struct s5p_mfc_platdata *pdata = mfc->pdata;
-#ifdef CONFIG_MFC_USE_BUS_DEVFREQ
- struct device_node *np_qos;
- char node_name[50];
- int i;
-#endif
-
- if (!np)
- return;
-
- /* MFC version */
- of_property_read_u32(np, "ip_ver", &pdata->ip_ver);
-
- /* Debug mode */
- of_property_read_u32(np, "debug_mode", &pdata->debug_mode);
-
- /* Sysmmu check */
- of_property_read_u32(np, "share_sysmmu", &pdata->share_sysmmu);
- of_property_read_u32(np, "axid_mask", &pdata->axid_mask);
- of_property_read_u32(np, "mfc_fault_num", &pdata->mfc_fault_num);
-
- /* Features */
- of_property_read_u32_array(np, "nal_q", &pdata->nal_q.support, 2);
- of_property_read_u32_array(np, "skype", &pdata->skype.support, 2);
- of_property_read_u32_array(np, "black_bar", &pdata->black_bar.support, 2);
- of_property_read_u32_array(np, "color_aspect_dec", &pdata->color_aspect_dec.support, 2);
- of_property_read_u32_array(np, "static_info_dec", &pdata->static_info_dec.support, 2);
- of_property_read_u32_array(np, "color_aspect_enc", &pdata->color_aspect_enc.support, 2);
- of_property_read_u32_array(np, "static_info_enc", &pdata->static_info_enc.support, 2);
-
- /* Default 10bit format for decoding */
- of_property_read_u32(np, "P010_decoding", &pdata->P010_decoding);
-
- /* Formats */
- of_property_read_u32(np, "support_10bit", &pdata->support_10bit);
- of_property_read_u32(np, "support_422", &pdata->support_422);
- of_property_read_u32(np, "support_rgb", &pdata->support_rgb);
-
- /* Encoder default parameter */
- of_property_read_u32(np, "enc_param_num", &pdata->enc_param_num);
- if (pdata->enc_param_num) {
- of_property_read_u32_array(np, "enc_param_addr",
- pdata->enc_param_addr, pdata->enc_param_num);
- of_property_read_u32_array(np, "enc_param_val",
- pdata->enc_param_val, pdata->enc_param_num);
- }
-
-#ifdef CONFIG_MFC_USE_BUS_DEVFREQ
- /* QoS */
- of_property_read_u32(np, "num_qos_steps", &pdata->num_qos_steps);
- of_property_read_u32(np, "max_qos_steps", &pdata->max_qos_steps);
- of_property_read_u32(np, "max_mb", &pdata->max_mb);
- of_property_read_u32(np, "mfc_freq_control", &pdata->mfc_freq_control);
- of_property_read_u32(np, "mo_control", &pdata->mo_control);
- of_property_read_u32(np, "bw_control", &pdata->bw_control);
-
- pdata->qos_table = devm_kzalloc(mfc->device,
- sizeof(struct s5p_mfc_qos) * pdata->max_qos_steps, GFP_KERNEL);
-
- for (i = 0; i < pdata->max_qos_steps; i++) {
- snprintf(node_name, sizeof(node_name), "mfc_qos_variant_%d", i);
- mfc_parse_mfc_qos_platdata(np, node_name, &pdata->qos_table[i]);
- }
-
- /* performance boost mode */
- pdata->qos_boost_table = devm_kzalloc(mfc->device,
- sizeof(struct s5p_mfc_qos_boost), GFP_KERNEL);
- np_qos = of_find_node_by_name(np, "mfc_perf_boost_table");
- if (!np_qos) {
- pr_err("%s:[QoS] could not find mfc_perf_boost_table node\n", node_name);
- return;
- }
- of_property_read_u32(np_qos, "num_cluster", &pdata->qos_boost_table->num_cluster);
- of_property_read_u32(np_qos, "freq_mfc", &pdata->qos_boost_table->freq_mfc);
- of_property_read_u32(np_qos, "freq_int", &pdata->qos_boost_table->freq_int);
- of_property_read_u32(np_qos, "freq_mif", &pdata->qos_boost_table->freq_mif);
- of_property_read_u32_array(np_qos, "freq_cluster", &pdata->qos_boost_table->freq_cluster[0],
- pdata->qos_boost_table->num_cluster);
-#endif
-}
-
-static void *mfc_get_drv_data(struct platform_device *pdev);
-
-static struct video_device *mfc_video_device_register(struct s5p_mfc_dev *dev,
- char *name, int node_num)
-{
- struct video_device *vfd;
- int ret = 0;
-
- vfd = video_device_alloc();
- if (!vfd) {
- v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n");
- return NULL;
- }
- strncpy(vfd->name, name, sizeof(vfd->name) - 1);
- vfd->fops = &s5p_mfc_fops;
- vfd->minor = -1;
- vfd->release = video_device_release;
-
- if (IS_DEC_NODE(node_num))
- vfd->ioctl_ops = s5p_mfc_get_dec_v4l2_ioctl_ops();
- else if(IS_ENC_NODE(node_num))
- vfd->ioctl_ops = s5p_mfc_get_enc_v4l2_ioctl_ops();
-
- vfd->lock = &dev->mfc_mutex;
- vfd->v4l2_dev = &dev->v4l2_dev;
- vfd->vfl_dir = VFL_DIR_M2M;
-
- snprintf(vfd->name, sizeof(vfd->name), "%s%d", vfd->name, dev->id);
-
- ret = video_register_device(vfd, VFL_TYPE_GRABBER, node_num + 60 * dev->id);
- if (ret) {
- v4l2_err(&dev->v4l2_dev, "Failed to register video device /dev/video%d\n", node_num);
- video_device_release(vfd);
- return NULL;
- }
- v4l2_info(&dev->v4l2_dev, "video device registered as /dev/video%d\n",
- vfd->num);
- video_set_drvdata(vfd, dev);
-
- return vfd;
-}
-
-static int mfc_register_resource(struct platform_device *pdev, struct s5p_mfc_dev *dev)
-{
- struct device_node *np = dev->device->of_node;
- struct device_node *iommu;
- struct device_node *hwfc;
- struct device_node *mmcache;
- struct resource *res;
- int ret;
-
- s5p_mfc_perf_register(dev);
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res == NULL) {
- dev_err(&pdev->dev, "failed to get memory region resource\n");
- return -ENOENT;
- }
- dev->mfc_mem = request_mem_region(res->start, resource_size(res), pdev->name);
- if (dev->mfc_mem == NULL) {
- dev_err(&pdev->dev, "failed to get memory region\n");
- return -ENOENT;
- }
- dev->regs_base = ioremap(dev->mfc_mem->start, resource_size(dev->mfc_mem));
- if (dev->regs_base == NULL) {
- dev_err(&pdev->dev, "failed to ioremap address region\n");
- goto err_ioremap;
- }
-
- iommu = of_get_child_by_name(np, "iommu");
- if (!iommu) {
- dev_err(&pdev->dev, "failed to get iommu node\n");
- goto err_ioremap_mmu0;
- }
-
- dev->sysmmu0_base = of_iomap(iommu, 0);
- if (dev->sysmmu0_base == NULL) {
- dev_err(&pdev->dev, "failed to ioremap sysmmu0 address region\n");
- goto err_ioremap_mmu0;
- }
-
- dev->sysmmu1_base = of_iomap(iommu, 1);
- if (dev->sysmmu1_base == NULL) {
- pr_debug("there is only one MFC sysmmu\n");
- } else {
- dev->has_2sysmmu = 1;
- }
-
- hwfc = of_get_child_by_name(np, "hwfc");
- if (hwfc) {
- dev->hwfc_base = of_iomap(hwfc, 0);
- if (dev->hwfc_base == NULL) {
- dev->has_hwfc = 0;
- dev_err(&pdev->dev, "failed to iomap hwfc address region\n");
- goto err_ioremap_hwfc;
- } else {
- dev->has_hwfc = 1;
- }
- }
-
- mmcache = of_get_child_by_name(np, "mmcache");
- if (mmcache) {
- dev->mmcache.base = of_iomap(mmcache, 0);
- if (dev->mmcache.base == NULL) {
- dev->has_mmcache = 0;
- dev_err(&pdev->dev, "failed to iomap mmcache address region\n");
- goto err_ioremap_mmcache;
- } else {
- dev->has_mmcache = 1;
- }
- }
-
- res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (res == NULL) {
- dev_err(&pdev->dev, "failed to get irq resource\n");
- goto err_res_irq;
- }
- dev->irq = res->start;
- ret = request_threaded_irq(dev->irq, s5p_mfc_top_half_irq, s5p_mfc_irq,
- IRQF_ONESHOT, pdev->name, dev);
- if (ret != 0) {
- dev_err(&pdev->dev, "failed to install irq (%d)\n", ret);
- goto err_res_irq;
- }
-
- return 0;
-
-err_res_irq:
- if (dev->has_mmcache)
- iounmap(dev->mmcache.base);
-err_ioremap_mmcache:
- if (dev->has_hwfc)
- iounmap(dev->hwfc_base);
-err_ioremap_hwfc:
- if (dev->has_2sysmmu)
- iounmap(dev->sysmmu1_base);
- iounmap(dev->sysmmu0_base);
-err_ioremap_mmu0:
- iounmap(dev->regs_base);
-err_ioremap:
- release_mem_region(dev->mfc_mem->start, resource_size(dev->mfc_mem));
- return -ENOENT;
-}
-
-#ifdef CONFIG_EXYNOS_ITMON
-static int mfc_itmon_notifier(struct notifier_block *nb, unsigned long action, void *nb_data)
-{
- struct s5p_mfc_dev *dev;
- struct itmon_notifier *itmon_info = nb_data;
- int is_mfc_itmon = 0, is_master = 0;
-
- dev = container_of(nb, struct s5p_mfc_dev, itmon_nb);
-
- if (IS_ERR_OR_NULL(itmon_info))
- return NOTIFY_DONE;
-
- if (!itmon_info->master)
- return NOTIFY_DONE;
-
- /* print dump if it is an MFC ITMON error */
- if ((strncmp("MFC", itmon_info->port, sizeof("MFC") - 1) == 0) &&
- (strncmp("MFC", itmon_info->master, sizeof("MFC") - 1) == 0)) {
- is_mfc_itmon = 1;
- is_master = 1;
- } else if (strncmp("MFC", itmon_info->dest, sizeof("MFC") - 1) == 0) {
- is_mfc_itmon = 1;
- is_master = 0;
- }
-
- if (is_mfc_itmon) {
- pr_err("mfc_itmon_notifier: MFC +\n");
- pr_err("MFC is %s\n", is_master ? "master" : "dest");
- if (!dev->itmon_notified) {
- pr_err("dump MFC information\n");
- if (is_master || (!is_master && itmon_info->onoff))
- call_dop(dev, dump_info, dev);
- else
- call_dop(dev, dump_info_without_regs, dev);
- } else {
- pr_err("MFC notifier has already been called. skip MFC information\n");
- }
- pr_err("mfc_itmon_notifier: MFC -\n");
- dev->itmon_notified = 1;
- }
- return NOTIFY_DONE;
-}
-#endif
-
-/* MFC probe function */
-static int s5p_mfc_probe(struct platform_device *pdev)
-{
- struct s5p_mfc_dev *dev;
- int ret = -ENOENT;
-#ifdef CONFIG_MFC_USE_BUS_DEVFREQ
- int i;
-#endif
-
- dev_dbg(&pdev->dev, "%s()\n", __func__);
- dev = devm_kzalloc(&pdev->dev, sizeof(struct s5p_mfc_dev), GFP_KERNEL);
- if (!dev) {
- dev_err(&pdev->dev, "Not enough memory for MFC device\n");
- return -ENOMEM;
- }
-
- dev->device = &pdev->dev;
- dev->pdata = pdev->dev.platform_data;
-
- dev->variant = mfc_get_drv_data(pdev);
-
- if (dev->device->of_node)
- dev->id = of_alias_get_id(pdev->dev.of_node, "mfc");
-
- dev_dbg(&pdev->dev, "of alias get id : mfc-%d \n", dev->id);
-
- if (dev->id < 0 || dev->id >= dev->variant->num_entities) {
- dev_err(&pdev->dev, "Invalid platform device id: %d\n", dev->id);
- ret = -EINVAL;
- goto err_pm;
- }
-
- dev->pdata = devm_kzalloc(&pdev->dev, sizeof(struct s5p_mfc_platdata), GFP_KERNEL);
- if (!dev->pdata) {
- dev_err(&pdev->dev, "no memory for state\n");
- ret = -ENOMEM;
- goto err_pm;
- }
-
- mfc_parse_dt(dev->device->of_node, dev);
-
- atomic_set(&dev->trace_ref, 0);
- atomic_set(&dev->trace_ref_hwlock, 0);
- dev->mfc_trace = g_mfc_trace;
- dev->mfc_trace_hwlock = g_mfc_trace_hwlock;
-
- dma_set_mask(&pdev->dev, DMA_BIT_MASK(36));
-
- s5p_mfc_pm_init(dev);
- ret = mfc_register_resource(pdev, dev);
- if (ret)
- goto err_res_mem;
-
- mutex_init(&dev->mfc_mutex);
-
- ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
- if (ret)
- goto err_v4l2_dev;
-
- init_waitqueue_head(&dev->cmd_wq);
- s5p_mfc_init_listable_wq_dev(dev);
-
- /* decoder */
- dev->vfd_dec = mfc_video_device_register(dev, S5P_MFC_DEC_NAME,
- EXYNOS_VIDEONODE_MFC_DEC);
- if (!dev->vfd_dec) {
- ret = -ENOMEM;
- goto alloc_vdev_dec;
- }
-
- /* encoder */
- dev->vfd_enc = mfc_video_device_register(dev, S5P_MFC_ENC_NAME,
- EXYNOS_VIDEONODE_MFC_ENC);
- if (!dev->vfd_enc) {
- ret = -ENOMEM;
- goto alloc_vdev_enc;
- }
-
- /* secure decoder */
- dev->vfd_dec_drm = mfc_video_device_register(dev, S5P_MFC_DEC_DRM_NAME,
- EXYNOS_VIDEONODE_MFC_DEC_DRM);
- if (!dev->vfd_dec_drm) {
- ret = -ENOMEM;
- goto alloc_vdev_dec_drm;
- }
-
- /* secure encoder */
- dev->vfd_enc_drm = mfc_video_device_register(dev, S5P_MFC_ENC_DRM_NAME,
- EXYNOS_VIDEONODE_MFC_ENC_DRM);
- if (!dev->vfd_enc_drm) {
- ret = -ENOMEM;
- goto alloc_vdev_enc_drm;
- }
-
- /* OTF encoder */
- dev->vfd_enc_otf = mfc_video_device_register(dev, S5P_MFC_ENC_OTF_NAME,
- EXYNOS_VIDEONODE_MFC_ENC_OTF);
- if (!dev->vfd_enc_otf) {
- ret = -ENOMEM;
- goto alloc_vdev_enc_otf;
- }
-
- /* OTF secure encoder */
- dev->vfd_enc_otf_drm = mfc_video_device_register(dev, S5P_MFC_ENC_OTF_DRM_NAME,
- EXYNOS_VIDEONODE_MFC_ENC_OTF_DRM);
- if (!dev->vfd_enc_otf_drm) {
- ret = -ENOMEM;
- goto alloc_vdev_enc_otf_drm;
- }
- /* end of node setting*/
-
- platform_set_drvdata(pdev, dev);
-
- s5p_mfc_init_hwlock(dev);
- s5p_mfc_create_bits(&dev->work_bits);
-
- dev->watchdog_wq =
- create_singlethread_workqueue("s5p_mfc/watchdog");
- if (!dev->watchdog_wq) {
- dev_err(&pdev->dev, "failed to create workqueue for watchdog\n");
- goto err_wq_watchdog;
- }
- INIT_WORK(&dev->watchdog_work, s5p_mfc_watchdog_worker);
- atomic_set(&dev->watchdog_tick_running, 0);
- atomic_set(&dev->watchdog_tick_cnt, 0);
- atomic_set(&dev->watchdog_run, 0);
- init_timer(&dev->watchdog_timer);
- dev->watchdog_timer.data = (unsigned long)dev;
- dev->watchdog_timer.function = s5p_mfc_watchdog_tick;
-
-#ifdef CONFIG_MFC_USE_BUS_DEVFREQ
- INIT_LIST_HEAD(&dev->qos_queue);
-#endif
-
- /* default FW alloc is added */
- dev->butler_wq = alloc_workqueue("s5p_mfc/butler", WQ_UNBOUND
- | WQ_MEM_RECLAIM | WQ_HIGHPRI, 1);
- if (dev->butler_wq == NULL) {
- dev_err(&pdev->dev, "failed to create workqueue for butler\n");
- goto err_butler_wq;
- }
- INIT_WORK(&dev->butler_work, s5p_mfc_butler_worker);
-
- /* dump information call-back function */
- dev->dump_ops = &mfc_dump_ops;
-
-#ifdef CONFIG_MFC_USE_BUS_DEVFREQ
- atomic_set(&dev->qos_req_cur, 0);
-
- mfc_info_dev("[QoS] control: mfc_freq(%d), mo(%d), bw(%d)\n",
- dev->pdata->mfc_freq_control, dev->pdata->mo_control, dev->pdata->bw_control);
- for (i = 0; i < dev->pdata->num_qos_steps; i++) {
- mfc_info_dev("[QoS] table[%d] mfc: %d, int : %d, mif : %d\n",
- i,
- dev->pdata->qos_table[i].freq_mfc,
- dev->pdata->qos_table[i].freq_int,
- dev->pdata->qos_table[i].freq_mif);
- }
-#endif
-
- iovmm_set_fault_handler(dev->device,
- s5p_mfc_sysmmu_fault_handler, dev);
-
- g_mfc_dev = dev;
-
- ret = iovmm_activate(&pdev->dev);
- if (ret < 0) {
- dev_err(&pdev->dev, "Failed to activate iommu\n");
- goto err_iovmm_active;
- }
-
- dev->logging_data = devm_kzalloc(&pdev->dev, sizeof(struct s5p_mfc_debug), GFP_KERNEL);
- if (!dev->logging_data) {
- dev_err(&pdev->dev, "no memory for logging data\n");
- ret = -ENOMEM;
- goto err_alloc_debug;
- }
-
-#ifdef CONFIG_EXYNOS_ITMON
- dev->itmon_nb.notifier_call = mfc_itmon_notifier;
- itmon_notifier_chain_register(&dev->itmon_nb);
-#endif
-
- s5p_mfc_init_debugfs(dev);
-
- pr_debug("%s--\n", __func__);
- return 0;
-
-/* Deinit MFC if probe had failed */
-err_alloc_debug:
- iovmm_deactivate(&pdev->dev);
-err_iovmm_active:
- destroy_workqueue(dev->butler_wq);
-err_butler_wq:
- destroy_workqueue(dev->watchdog_wq);
-err_wq_watchdog:
- video_unregister_device(dev->vfd_enc_otf_drm);
-alloc_vdev_enc_otf_drm:
- video_unregister_device(dev->vfd_enc_otf);
-alloc_vdev_enc_otf:
- video_unregister_device(dev->vfd_enc_drm);
-alloc_vdev_enc_drm:
- video_unregister_device(dev->vfd_dec_drm);
-alloc_vdev_dec_drm:
- video_unregister_device(dev->vfd_enc);
-alloc_vdev_enc:
- video_unregister_device(dev->vfd_dec);
-alloc_vdev_dec:
- v4l2_device_unregister(&dev->v4l2_dev);
-err_v4l2_dev:
- mutex_destroy(&dev->mfc_mutex);
- free_irq(dev->irq, dev);
- if (dev->has_mmcache)
- iounmap(dev->mmcache.base);
- if (dev->has_hwfc)
- iounmap(dev->hwfc_base);
- if (dev->has_2sysmmu)
- iounmap(dev->sysmmu1_base);
- iounmap(dev->sysmmu0_base);
- iounmap(dev->regs_base);
- release_mem_region(dev->mfc_mem->start, resource_size(dev->mfc_mem));
-err_res_mem:
- s5p_mfc_pm_final(dev);
-err_pm:
- return ret;
-}
-
-/* Remove the driver */
-static int s5p_mfc_remove(struct platform_device *pdev)
-{
- struct s5p_mfc_dev *dev = platform_get_drvdata(pdev);
-
- dev_dbg(&pdev->dev, "%s++\n", __func__);
- v4l2_info(&dev->v4l2_dev, "Removing %s\n", pdev->name);
- del_timer_sync(&dev->watchdog_timer);
- flush_workqueue(dev->watchdog_wq);
- destroy_workqueue(dev->watchdog_wq);
- flush_workqueue(dev->butler_wq);
- destroy_workqueue(dev->butler_wq);
- video_unregister_device(dev->vfd_enc);
- video_unregister_device(dev->vfd_dec);
- video_unregister_device(dev->vfd_enc_otf);
- video_unregister_device(dev->vfd_enc_otf_drm);
- v4l2_device_unregister(&dev->v4l2_dev);
-#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
- remove_proc_entry(MFC_PROC_FW_STATUS, mfc_proc_entry);
- remove_proc_entry(MFC_PROC_DRM_INSTANCE_NUMBER, mfc_proc_entry);
- remove_proc_entry(MFC_PROC_INSTANCE_NUMBER, mfc_proc_entry);
- remove_proc_entry(MFC_PROC_ROOT, NULL);
-#endif
- s5p_mfc_destroy_listable_wq_dev(dev);
- iovmm_deactivate(&pdev->dev);
- mfc_debug(2, "Will now deinit HW\n");
- s5p_mfc_deinit_hw(dev);
- free_irq(dev->irq, dev);
- if (dev->has_mmcache)
- iounmap(dev->mmcache.base);
- if (dev->has_hwfc)
- iounmap(dev->hwfc_base);
- if (dev->has_2sysmmu)
- iounmap(dev->sysmmu1_base);
- iounmap(dev->sysmmu0_base);
- iounmap(dev->regs_base);
- release_mem_region(dev->mfc_mem->start, resource_size(dev->mfc_mem));
- s5p_mfc_pm_final(dev);
- kfree(dev);
- dev_dbg(&pdev->dev, "%s--\n", __func__);
- return 0;
-}
-
-static void s5p_mfc_shutdown(struct platform_device *pdev)
-{
- struct s5p_mfc_dev *dev = platform_get_drvdata(pdev);
- int ret;
-
- mfc_info_dev("MFC shutdown is called\n");
- MFC_TRACE_DEV_HWLOCK("**shutdown \n");
-
- if (!s5p_mfc_pm_get_pwr_ref_cnt(dev)) {
- dev->shutdown = 1;
- mfc_info_dev("MFC is not running\n");
- return;
- }
-
- ret = s5p_mfc_get_hwlock_dev(dev);
- if (ret < 0)
- mfc_err_dev("Failed to get hwlock\n");
-
- if (!dev->shutdown) {
- s5p_mfc_risc_off(dev);
- dev->shutdown = 1;
- s5p_mfc_clear_all_bits(&dev->work_bits);
- iovmm_deactivate(&pdev->dev);
- }
- s5p_mfc_release_hwlock_dev(dev);
- mfc_info_dev("MFC shutdown completed\n");
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int s5p_mfc_suspend(struct device *dev)
-{
- struct s5p_mfc_dev *m_dev = platform_get_drvdata(to_platform_device(dev));
- int ret;
-
- if (!m_dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
-
- if (m_dev->num_inst == 0)
- return 0;
-
- ret = s5p_mfc_sleep(m_dev);
-
- return ret;
-}
-
-static int s5p_mfc_resume(struct device *dev)
-{
- struct s5p_mfc_dev *m_dev = platform_get_drvdata(to_platform_device(dev));
- int ret;
-
- if (!m_dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
-
- if (m_dev->num_inst == 0)
- return 0;
-
- ret = s5p_mfc_wakeup(m_dev);
-
- return ret;
-}
-#endif
-
-#ifdef CONFIG_PM
-static int s5p_mfc_runtime_suspend(struct device *dev)
-{
- mfc_debug(3, "mfc runtime suspend\n");
-
- return 0;
-}
-
-static int s5p_mfc_runtime_idle(struct device *dev)
-{
- return 0;
-}
-
-static int s5p_mfc_runtime_resume(struct device *dev)
-{
- mfc_debug(3, "mfc runtime resume\n");
-
- return 0;
-}
-#endif
-
-/* Power management */
-static const struct dev_pm_ops s5p_mfc_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(s5p_mfc_suspend, s5p_mfc_resume)
- SET_RUNTIME_PM_OPS(
- s5p_mfc_runtime_suspend,
- s5p_mfc_runtime_resume,
- s5p_mfc_runtime_idle
- )
-};
-
-struct s5p_mfc_ctx_buf_size mfc_ctx_buf_size = {
- .dev_ctx = PAGE_ALIGN(0x7800), /* 30KB */
- .h264_dec_ctx = PAGE_ALIGN(0x200000), /* 1.6MB */
- .other_dec_ctx = PAGE_ALIGN(0x7800), /* 30KB */
- .h264_enc_ctx = PAGE_ALIGN(0x19000), /* 100KB */
- .hevc_enc_ctx = PAGE_ALIGN(0xA000), /* 40KB */
- .other_enc_ctx = PAGE_ALIGN(0x6400), /* 25KB */
- .shared_buf = PAGE_ALIGN(0x2000), /* 8KB */
- .dbg_info_buf = PAGE_ALIGN(0x1000), /* 4KB for DEBUG INFO */
-};
-
-struct s5p_mfc_buf_size mfc_buf_size = {
- .firmware_code = PAGE_ALIGN(0x100000), /* 1MB */
- .cpb_buf = PAGE_ALIGN(0x300000), /* 3MB */
- .ctx_buf = &mfc_ctx_buf_size,
-};
-
-static struct s5p_mfc_variant mfc_drvdata = {
- .buf_size = &mfc_buf_size,
- .num_entities = 2,
-};
-
-static const struct of_device_id exynos_mfc_match[] = {
- {
- .compatible = "samsung,exynos-mfc",
- .data = &mfc_drvdata,
- },
- {},
-};
-MODULE_DEVICE_TABLE(of, exynos_mfc_match);
-
-static void *mfc_get_drv_data(struct platform_device *pdev)
-{
- struct s5p_mfc_variant *driver_data = NULL;
-
- if (pdev->dev.of_node) {
- const struct of_device_id *match;
- match = of_match_node(of_match_ptr(exynos_mfc_match),
- pdev->dev.of_node);
- if (match)
- driver_data = (struct s5p_mfc_variant *)match->data;
- } else {
- driver_data = (struct s5p_mfc_variant *)
- platform_get_device_id(pdev)->driver_data;
- }
- return driver_data;
-}
-
-static struct platform_driver s5p_mfc_driver = {
- .probe = s5p_mfc_probe,
- .remove = s5p_mfc_remove,
- .shutdown = s5p_mfc_shutdown,
- .driver = {
- .name = S5P_MFC_NAME,
- .owner = THIS_MODULE,
- .pm = &s5p_mfc_pm_ops,
- .of_match_table = exynos_mfc_match,
- .suppress_bind_attrs = true,
- },
-};
-
-module_platform_driver(s5p_mfc_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>");
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_buf.c
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/smc.h>
-#include <linux/firmware.h>
-#include <trace/events/mfc.h>
-
-#include "s5p_mfc_buf.h"
-
-#include "s5p_mfc_mem.h"
-
-static int mfc_alloc_common_context(struct s5p_mfc_dev *dev,
- enum mfc_buf_usage_type buf_type)
-{
- struct s5p_mfc_special_buf *ctx_buf;
- int firmware_size;
- unsigned long fw_daddr;
-
- mfc_debug_enter();
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
-
- ctx_buf = &dev->common_ctx_buf;
- fw_daddr = dev->fw_buf.daddr;
-
-#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
- if (buf_type == MFCBUF_DRM) {
- ctx_buf = &dev->drm_common_ctx_buf;
- fw_daddr = dev->drm_fw_buf.daddr;
- }
-#endif
-
- firmware_size = dev->variant->buf_size->firmware_code;
-
- ctx_buf->dma_buf = NULL;
- ctx_buf->vaddr = NULL;
- ctx_buf->daddr = fw_daddr + firmware_size;
-
- mfc_debug_leave();
-
- return 0;
-}
-
-/* Wrapper : allocate context buffers for SYS_INIT */
-int s5p_mfc_alloc_common_context(struct s5p_mfc_dev *dev)
-{
- int ret = 0;
-
- ret = mfc_alloc_common_context(dev, MFCBUF_NORMAL);
- if (ret)
- return ret;
-#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
- if (dev->fw.drm_status) {
- ret = mfc_alloc_common_context(dev, MFCBUF_DRM);
- if (ret)
- return ret;
- }
-#endif
-
- return ret;
-}
-
-/* Release context buffers for SYS_INIT */
-static void mfc_release_common_context(struct s5p_mfc_dev *dev,
- enum mfc_buf_usage_type buf_type)
-{
- struct s5p_mfc_special_buf *ctx_buf;
-
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return;
- }
-
- ctx_buf = &dev->common_ctx_buf;
-#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
- if (buf_type == MFCBUF_DRM)
- ctx_buf = &dev->drm_common_ctx_buf;
-#endif
-
- ctx_buf->dma_buf = NULL;
- ctx_buf->vaddr = NULL;
- ctx_buf->daddr = 0;
-}
-
-/* Release context buffers for SYS_INIT */
-void s5p_mfc_release_common_context(struct s5p_mfc_dev *dev)
-{
- mfc_release_common_context(dev, MFCBUF_NORMAL);
-
-#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
- mfc_release_common_context(dev, MFCBUF_DRM);
-#endif
-}
-
-/* Allocate memory for instance data buffer */
-int s5p_mfc_alloc_instance_context(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev;
- struct s5p_mfc_ctx_buf_size *buf_size;
-
- mfc_debug_enter();
- if (!ctx) {
- mfc_err_dev("no mfc context to run\n");
- return -EINVAL;
- }
- dev = ctx->dev;
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
- buf_size = dev->variant->buf_size->ctx_buf;
-
- switch (ctx->codec_mode) {
- case S5P_FIMV_CODEC_H264_DEC:
- case S5P_FIMV_CODEC_H264_MVC_DEC:
- case S5P_FIMV_CODEC_HEVC_DEC:
- case S5P_FIMV_CODEC_BPG_DEC:
- ctx->instance_ctx_buf.size = buf_size->h264_dec_ctx;
- break;
- case S5P_FIMV_CODEC_MPEG4_DEC:
- case S5P_FIMV_CODEC_H263_DEC:
- case S5P_FIMV_CODEC_VC1_RCV_DEC:
- case S5P_FIMV_CODEC_VC1_DEC:
- case S5P_FIMV_CODEC_MPEG2_DEC:
- case S5P_FIMV_CODEC_VP8_DEC:
- case S5P_FIMV_CODEC_VP9_DEC:
- case S5P_FIMV_CODEC_FIMV1_DEC:
- case S5P_FIMV_CODEC_FIMV2_DEC:
- case S5P_FIMV_CODEC_FIMV3_DEC:
- case S5P_FIMV_CODEC_FIMV4_DEC:
- ctx->instance_ctx_buf.size = buf_size->other_dec_ctx;
- break;
- case S5P_FIMV_CODEC_H264_ENC:
- ctx->instance_ctx_buf.size = buf_size->h264_enc_ctx;
- break;
- case S5P_FIMV_CODEC_HEVC_ENC:
- case S5P_FIMV_CODEC_BPG_ENC:
- ctx->instance_ctx_buf.size = buf_size->hevc_enc_ctx;
- break;
- case S5P_FIMV_CODEC_MPEG4_ENC:
- case S5P_FIMV_CODEC_H263_ENC:
- case S5P_FIMV_CODEC_VP8_ENC:
- case S5P_FIMV_CODEC_VP9_ENC:
- ctx->instance_ctx_buf.size = buf_size->other_enc_ctx;
- break;
- default:
- ctx->instance_ctx_buf.size = 0;
- mfc_err_ctx("Codec type(%d) should be checked!\n", ctx->codec_mode);
- return -ENOMEM;
- }
-
- if (ctx->is_drm)
- ctx->instance_ctx_buf.buftype = MFCBUF_DRM;
- else
- ctx->instance_ctx_buf.buftype = MFCBUF_NORMAL;
-
- if (s5p_mfc_mem_ion_alloc(dev, &ctx->instance_ctx_buf)) {
- mfc_err_ctx("Allocating context buffer failed\n");
- return -ENOMEM;
- }
-
- mfc_debug(2, "[MEMINFO] Instance buf ctx[%d] size: %ld, daddr: 0x%08llx\n",
- ctx->num, ctx->instance_ctx_buf.size, ctx->instance_ctx_buf.daddr);
-
- return 0;
-}
-
-/* Release instance buffer */
-void s5p_mfc_release_instance_context(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev;
-
- mfc_debug_enter();
- if (!ctx) {
- mfc_err_dev("no mfc context to run\n");
- return;
- }
-
- dev = ctx->dev;
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return;
- }
-
- s5p_mfc_mem_ion_free(dev, &ctx->instance_ctx_buf);
- mfc_debug(2, "[MEMINFO] Release the instance buffer ctx[%d]\n", ctx->num);
-
- mfc_debug_leave();
-}
-
-static void mfc_calc_dec_codec_buffer_size(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dec *dec;
- int i;
-
- dec = ctx->dec_priv;
-
- /* Codecs have different memory requirements */
- switch (ctx->codec_mode) {
- case S5P_FIMV_CODEC_H264_DEC:
- case S5P_FIMV_CODEC_H264_MVC_DEC:
- ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256);
- ctx->codec_buf.size =
- ctx->scratch_buf_size +
- (dec->mv_count * ctx->mv_size);
- break;
- case S5P_FIMV_CODEC_MPEG4_DEC:
- case S5P_FIMV_CODEC_FIMV1_DEC:
- case S5P_FIMV_CODEC_FIMV2_DEC:
- case S5P_FIMV_CODEC_FIMV3_DEC:
- case S5P_FIMV_CODEC_FIMV4_DEC:
- ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256);
- if (dec->loop_filter_mpeg4) {
- ctx->loopfilter_luma_size = ALIGN(ctx->raw_buf.plane_size[0], 256);
- ctx->loopfilter_chroma_size = ALIGN(ctx->raw_buf.plane_size[1] +
- ctx->raw_buf.plane_size[2], 256);
- ctx->codec_buf.size = ctx->scratch_buf_size +
- (NUM_MPEG4_LF_BUF * (ctx->loopfilter_luma_size +
- ctx->loopfilter_chroma_size));
- } else {
- ctx->codec_buf.size = ctx->scratch_buf_size;
- }
- break;
- case S5P_FIMV_CODEC_VC1_RCV_DEC:
- case S5P_FIMV_CODEC_VC1_DEC:
- ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256);
- ctx->codec_buf.size = ctx->scratch_buf_size;
- break;
- case S5P_FIMV_CODEC_MPEG2_DEC:
- ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256);
- ctx->codec_buf.size = ctx->scratch_buf_size;
- break;
- case S5P_FIMV_CODEC_H263_DEC:
- ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256);
- ctx->codec_buf.size = ctx->scratch_buf_size;
- break;
- case S5P_FIMV_CODEC_VP8_DEC:
- ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256);
- ctx->codec_buf.size = ctx->scratch_buf_size;
- break;
- case S5P_FIMV_CODEC_VP9_DEC:
- ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256);
- ctx->codec_buf.size =
- ctx->scratch_buf_size +
- DEC_STATIC_BUFFER_SIZE;
- break;
- case S5P_FIMV_CODEC_HEVC_DEC:
- case S5P_FIMV_CODEC_BPG_DEC:
- ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256);
- ctx->codec_buf.size =
- ctx->scratch_buf_size +
- (dec->mv_count * ctx->mv_size);
- break;
- default:
- ctx->codec_buf.size = 0;
- mfc_err_ctx("invalid codec type: %d\n", ctx->codec_mode);
- break;
- }
-
- mfc_debug(2, "[MEMINFO] scratch: %zu, MV: %zu x count %d\n",
- ctx->scratch_buf_size, ctx->mv_size, dec->mv_count);
- if (dec->loop_filter_mpeg4)
- mfc_debug(2, "[MEMINFO] (loopfilter luma: %zu, chroma: %zu) x count %d\n",
- ctx->loopfilter_luma_size, ctx->loopfilter_chroma_size,
- NUM_MPEG4_LF_BUF);
-}
-
-static void mfc_calc_enc_codec_buffer_size(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_enc *enc;
- unsigned int mb_width, mb_height;
- unsigned int lcu_width = 0, lcu_height = 0;
-
- enc = ctx->enc_priv;
- enc->tmv_buffer_size = 0;
-
- mb_width = WIDTH_MB(ctx->crop_width);
- mb_height = HEIGHT_MB(ctx->crop_height);
-
- lcu_width = ENC_LCU_WIDTH(ctx->crop_width);
- lcu_height = ENC_LCU_HEIGHT(ctx->crop_height);
-
- /* default recon buffer size, it can be changed in case of 422, 10bit */
- enc->luma_dpb_size =
- ALIGN(ENC_LUMA_DPB_SIZE(ctx->crop_width, ctx->crop_height), 64);
- enc->chroma_dpb_size =
- ALIGN(ENC_CHROMA_DPB_SIZE(ctx->crop_width, ctx->crop_height), 64);
-
- /* Codecs have different memory requirements */
- switch (ctx->codec_mode) {
- case S5P_FIMV_CODEC_H264_ENC:
- enc->me_buffer_size =
- ALIGN(ENC_V100_H264_ME_SIZE(mb_width, mb_height), 256);
-
- ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256);
- ctx->codec_buf.size =
- ctx->scratch_buf_size + enc->tmv_buffer_size +
- (ctx->dpb_count * (enc->luma_dpb_size +
- enc->chroma_dpb_size + enc->me_buffer_size));
- break;
- case S5P_FIMV_CODEC_MPEG4_ENC:
- case S5P_FIMV_CODEC_H263_ENC:
- enc->me_buffer_size =
- ALIGN(ENC_V100_MPEG4_ME_SIZE(mb_width, mb_height), 256);
-
- ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256);
- ctx->codec_buf.size =
- ctx->scratch_buf_size + enc->tmv_buffer_size +
- (ctx->dpb_count * (enc->luma_dpb_size +
- enc->chroma_dpb_size + enc->me_buffer_size));
- break;
- case S5P_FIMV_CODEC_VP8_ENC:
- enc->me_buffer_size =
- ALIGN(ENC_V100_VP8_ME_SIZE(mb_width, mb_height), 256);
-
- ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256);
- ctx->codec_buf.size =
- ctx->scratch_buf_size + enc->tmv_buffer_size +
- (ctx->dpb_count * (enc->luma_dpb_size +
- enc->chroma_dpb_size + enc->me_buffer_size));
- break;
- case S5P_FIMV_CODEC_VP9_ENC:
- if (ctx->is_10bit || ctx->is_422) {
- enc->luma_dpb_size =
- ALIGN(ENC_VP9_LUMA_DPB_10B_SIZE(ctx->crop_width, ctx->crop_height), 64);
- enc->chroma_dpb_size =
- ALIGN(ENC_VP9_CHROMA_DPB_10B_SIZE(ctx->crop_width, ctx->crop_height), 64);
- mfc_debug(2, "[10BIT] VP9 10bit or 422 recon luma size: %zu chroma size: %zu\n",
- enc->luma_dpb_size, enc->chroma_dpb_size);
- }
- enc->me_buffer_size =
- ALIGN(ENC_V100_VP9_ME_SIZE(lcu_width, lcu_height), 256);
-
- ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256);
- ctx->codec_buf.size =
- ctx->scratch_buf_size + enc->tmv_buffer_size +
- (ctx->dpb_count * (enc->luma_dpb_size +
- enc->chroma_dpb_size + enc->me_buffer_size));
- break;
- case S5P_FIMV_CODEC_HEVC_ENC:
- case S5P_FIMV_CODEC_BPG_ENC:
- if (ctx->is_10bit || ctx->is_422) {
- enc->luma_dpb_size =
- ALIGN(ENC_HEVC_LUMA_DPB_10B_SIZE(ctx->crop_width, ctx->crop_height), 64);
- enc->chroma_dpb_size =
- ALIGN(ENC_HEVC_CHROMA_DPB_10B_SIZE(ctx->crop_width, ctx->crop_height), 64);
- mfc_debug(2, "[10BIT] HEVC 10bit or 422 recon luma size: %zu chroma size: %zu\n",
- enc->luma_dpb_size, enc->chroma_dpb_size);
- }
- enc->me_buffer_size =
- ALIGN(ENC_V100_HEVC_ME_SIZE(lcu_width, lcu_height), 256);
-
- ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256);
- ctx->codec_buf.size =
- ctx->scratch_buf_size + enc->tmv_buffer_size +
- (ctx->dpb_count * (enc->luma_dpb_size +
- enc->chroma_dpb_size + enc->me_buffer_size));
- break;
- default:
- ctx->codec_buf.size = 0;
- mfc_err_ctx("invalid codec type: %d\n", ctx->codec_mode);
- break;
- }
-
- mfc_debug(2, "[MEMINFO] scratch: %zu, TMV: %zu, (recon luma: %zu, chroma: %zu, me: %zu) x count %d\n",
- ctx->scratch_buf_size, enc->tmv_buffer_size,
- enc->luma_dpb_size, enc->chroma_dpb_size, enc->me_buffer_size,
- ctx->dpb_count);
-}
-
-/* Allocate codec buffers */
-int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev;
-
- mfc_debug_enter();
- if (!ctx) {
- mfc_err_dev("no mfc context to run\n");
- return -EINVAL;
- }
- dev = ctx->dev;
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
-
- if (ctx->type == MFCINST_DECODER) {
- mfc_calc_dec_codec_buffer_size(ctx);
- } else if (ctx->type == MFCINST_ENCODER) {
- mfc_calc_enc_codec_buffer_size(ctx);
- } else {
- mfc_err_ctx("invalid type: %d\n", ctx->type);
- return -EINVAL;
- }
-
- if (ctx->is_drm)
- ctx->codec_buf.buftype = MFCBUF_DRM;
- else
- ctx->codec_buf.buftype = MFCBUF_NORMAL;
-
- if (ctx->codec_buf.size > 0) {
- if (s5p_mfc_mem_ion_alloc(dev, &ctx->codec_buf)) {
- mfc_err_ctx("Allocating codec buffer failed\n");
- return -ENOMEM;
- }
- ctx->codec_buffer_allocated = 1;
- } else if (ctx->codec_mode == S5P_FIMV_CODEC_MPEG2_DEC) {
- ctx->codec_buffer_allocated = 1;
- }
-
- mfc_debug(2, "[MEMINFO] Codec buf ctx[%d] size: %ld, addr: 0x%08llx\n",
- ctx->num, ctx->codec_buf.size, ctx->codec_buf.daddr);
-
- return 0;
-}
-
-/* Release buffers allocated for codec */
-void s5p_mfc_release_codec_buffers(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev;
-
- if (!ctx) {
- mfc_err_dev("no mfc context to run\n");
- return;
- }
-
- dev = ctx->dev;
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return;
- }
-
- s5p_mfc_mem_ion_free(dev, &ctx->codec_buf);
- ctx->codec_buffer_allocated = 0;
- mfc_debug(2, "[MEMINFO] Release the codec buffer ctx[%d]\n", ctx->num);
-}
-
-/* Allocation buffer of debug infor memory for FW debugging */
-int s5p_mfc_alloc_dbg_info_buffer(struct s5p_mfc_dev *dev)
-{
- struct s5p_mfc_ctx_buf_size *buf_size = dev->variant->buf_size->ctx_buf;
-
- mfc_debug(2, "Allocate a debug-info buffer\n");
-
- dev->dbg_info_buf.buftype = MFCBUF_NORMAL;
- dev->dbg_info_buf.size = buf_size->dbg_info_buf;
- if (s5p_mfc_mem_ion_alloc(dev, &dev->dbg_info_buf)) {
- mfc_err_dev("Allocating debug info buffer failed\n");
- return -ENOMEM;
- }
- mfc_debug(2, "[MEMINFO] debug info buf size: %ld, daddr: 0x%08llx, vaddr: 0x%p\n",
- dev->dbg_info_buf.size, dev->dbg_info_buf.daddr, dev->dbg_info_buf.vaddr);
-
- return 0;
-}
-
-/* Release buffer of debug infor memory for FW debugging */
-int s5p_mfc_release_dbg_info_buffer(struct s5p_mfc_dev *dev)
-{
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
-
- if (!dev->dbg_info_buf.dma_buf) {
- mfc_debug(2, "debug info buffer is already freed\n");
- return 0;
- }
-
- s5p_mfc_mem_ion_free(dev, &dev->dbg_info_buf);
- mfc_debug(2, "[MEMINFO] Release the debug info buffer\n");
-
- return 0;
-}
-
-/* Allocation buffer of ROI macroblock information */
-static int mfc_alloc_enc_roi_buffer(struct s5p_mfc_ctx *ctx, struct s5p_mfc_special_buf *roi_buf)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_ctx_buf_size *buf_size = dev->variant->buf_size->ctx_buf;
-
- roi_buf->buftype = MFCBUF_NORMAL;
- roi_buf->size = buf_size->shared_buf;
- if (s5p_mfc_mem_ion_alloc(dev, roi_buf)) {
- mfc_err_ctx("[ROI] Allocating ROI buffer failed\n");
- return -ENOMEM;
- }
- mfc_debug(2, "[MEMINFO][ROI] roi buf ctx[%d] size: %ld, daddr: 0x%08llx, vaddr: 0x%p\n",
- ctx->num, roi_buf->size, roi_buf->daddr, roi_buf->vaddr);
-
- memset(roi_buf->vaddr, 0, buf_size->shared_buf);
-
- return 0;
-}
-
-/* Wrapper : allocation ROI buffers */
-int s5p_mfc_alloc_enc_roi_buffer(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_enc *enc = ctx->enc_priv;
- int i;
-
- for (i = 0; i < MFC_MAX_EXTRA_BUF; i++) {
- if (mfc_alloc_enc_roi_buffer(ctx, &enc->roi_buf[i]) < 0) {
- mfc_err_dev("[ROI] Allocating remapping buffer[%d] failed\n", i);
- return -ENOMEM;
- }
- }
-
- return 0;
-}
-
-/* Release buffer of ROI macroblock information */
-void s5p_mfc_release_enc_roi_buffer(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_enc *enc = ctx->enc_priv;
- int i;
-
- for (i = 0; i < MFC_MAX_EXTRA_BUF; i++)
- if (enc->roi_buf[i].dma_buf)
- s5p_mfc_mem_ion_free(ctx->dev, &enc->roi_buf[i]);
-
- mfc_debug(2, "[MEMINFO][ROI] Release the ROI buffer\n");
-}
-
-int s5p_mfc_otf_alloc_stream_buf(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct _otf_handle *handle = ctx->otf_handle;
- struct _otf_debug *debug = &handle->otf_debug;
- struct s5p_mfc_special_buf *buf;
- struct s5p_mfc_raw_info *raw = &ctx->raw_buf;
- int i;
-
- mfc_debug_enter();
-
- for (i = 0; i < OTF_MAX_BUF; i++) {
- buf = &debug->stream_buf[i];
- buf->buftype = MFCBUF_NORMAL;
- buf->size = raw->total_plane_size;
- if (s5p_mfc_mem_ion_alloc(dev, buf)) {
- mfc_err_ctx("[OTF] Allocating stream buffer failed\n");
- return -EINVAL;
- }
- mfc_debug(2, "[OTF][MEMINFO] OTF stream buf[%d] size: %ld, daddr: 0x%08llx, vaddr: 0x%p\n",
- i, buf->size, buf->daddr, buf->vaddr);
- memset(buf->vaddr, 0, raw->total_plane_size);
- }
-
- mfc_debug_leave();
-
- return 0;
-}
-
-void s5p_mfc_otf_release_stream_buf(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct _otf_handle *handle = ctx->otf_handle;
- struct _otf_debug *debug = &handle->otf_debug;
- struct s5p_mfc_special_buf *buf;
- int i;
-
- mfc_debug_enter();
-
- for (i = 0; i < OTF_MAX_BUF; i++) {
- buf = &debug->stream_buf[i];
- if (buf->dma_buf)
- s5p_mfc_mem_ion_free(dev, buf);
- }
-
- mfc_debug(2, "[OTF][MEMINFO] Release the OTF stream buffer\n");
- mfc_debug_leave();
-}
-
-/* Allocate firmware */
-int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev)
-{
- size_t firmware_size;
- struct s5p_mfc_ctx_buf_size *buf_size;
-
- mfc_debug_enter();
-
- if (!dev) {
- mfc_err_dev("[F/W] no mfc device to run\n");
- return -EINVAL;
- }
-
- buf_size = dev->variant->buf_size->ctx_buf;
- firmware_size = dev->variant->buf_size->firmware_code;
- dev->fw.size = firmware_size + buf_size->dev_ctx;
-
- if (dev->fw_buf.dma_buf)
- return 0;
-
- mfc_debug(4, "[F/W] Allocating memory for firmware\n");
- trace_mfc_loadfw_start(dev->fw.size, firmware_size);
-
- dev->fw_buf.buftype = MFCBUF_NORMAL;
- dev->fw_buf.size = dev->fw.size;
- if (s5p_mfc_mem_ion_alloc(dev, &dev->fw_buf)) {
- mfc_err_dev("[F/W] Allocating normal firmware buffer failed\n");
- return -ENOMEM;
- }
-
- mfc_debug(2, "[MEMINFO][F/W] FW normal: 0x%08llx (vaddr: 0x%p), size: %08zu\n",
- dev->fw_buf.daddr, dev->fw_buf.vaddr,
- dev->fw_buf.size);
-
-#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
- dev->drm_fw_buf.buftype = MFCBUF_DRM_FW;
- dev->drm_fw_buf.size = dev->fw.size;
- if (s5p_mfc_mem_ion_alloc(dev, &dev->drm_fw_buf)) {
- mfc_err_dev("[F/W] Allocating DRM firmware buffer failed\n");
- return -ENOMEM;
- }
-
- mfc_debug(2, "[MEMINFO][F/W] FW DRM: 0x%08llx (vaddr: 0x%p), size: %08zu\n",
- dev->drm_fw_buf.daddr, dev->drm_fw_buf.vaddr,
- dev->drm_fw_buf.size);
-#endif
-
- mfc_debug_leave();
-
- return 0;
-}
-
-/* Load firmware to MFC */
-int s5p_mfc_load_firmware(struct s5p_mfc_dev *dev)
-{
- struct firmware *fw_blob;
- size_t firmware_size;
- int err;
-
- if (!dev) {
- mfc_err_dev("[F/W] no mfc device to run\n");
- return -EINVAL;
- }
-
- firmware_size = dev->variant->buf_size->firmware_code;
-
- /* Firmare has to be present as a separate file or compiled
- * into kernel. */
- mfc_debug_enter();
- mfc_debug(4, "[F/W] Requesting F/W\n");
- err = request_firmware((const struct firmware **)&fw_blob,
- MFC_FW_NAME, dev->v4l2_dev.dev);
-
- if (err != 0) {
- mfc_err_dev("[F/W] Couldn't find the F/W invalid path\n");
- return -EINVAL;
- }
-
- mfc_debug(2, "[MEMINFO][F/W] loaded F/W Size: %zu\n", fw_blob->size);
-
- if (fw_blob->size > firmware_size) {
- mfc_err_dev("[MEMINFO][F/W] MFC firmware(%zu) is too big to be loaded in memory(%zu)\n",
- fw_blob->size, firmware_size);
- release_firmware(fw_blob);
- return -ENOMEM;
- }
-
- if (dev->fw_buf.dma_buf == NULL || dev->fw_buf.daddr == 0) {
- mfc_err_dev("[F/W] MFC firmware is not allocated or was not mapped correctly\n");
- release_firmware(fw_blob);
- return -EINVAL;
- }
-
- memcpy(dev->fw_buf.vaddr, fw_blob->data, fw_blob->size);
- if (dev->drm_fw_buf.vaddr) {
- memcpy(dev->drm_fw_buf.vaddr, fw_blob->data, fw_blob->size);
- mfc_debug(4, "[F/W] copy firmware to secure region\n");
- }
- release_firmware(fw_blob);
- trace_mfc_loadfw_end(dev->fw.size, firmware_size);
- mfc_debug_leave();
- return 0;
-}
-
-/* Release firmware memory */
-int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev)
-{
- /* Before calling this function one has to make sure
- * that MFC is no longer processing */
- if (!dev) {
- mfc_err_dev("[F/W] no mfc device to run\n");
- return -EINVAL;
- }
-
- if (!dev->fw_buf.dma_buf) {
- mfc_err_dev("[F/W] firmware memory is already freed\n");
- return -EINVAL;
- }
-
-#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
- s5p_mfc_mem_ion_free(dev, &dev->drm_fw_buf);
-#endif
-
- s5p_mfc_mem_ion_free(dev, &dev->fw_buf);
-
- return 0;
-}
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_buf.h
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __S5P_MFC_BUF_H
-#define __S5P_MFC_BUF_H __FILE__
-
-#include "s5p_mfc_common.h"
-
-/* Memory allocation */
-int s5p_mfc_alloc_common_context(struct s5p_mfc_dev *dev);
-void s5p_mfc_release_common_context(struct s5p_mfc_dev *dev);
-
-int s5p_mfc_alloc_instance_context(struct s5p_mfc_ctx *ctx);
-void s5p_mfc_release_instance_context(struct s5p_mfc_ctx *ctx);
-
-int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx);
-void s5p_mfc_release_codec_buffers(struct s5p_mfc_ctx *ctx);
-
-int s5p_mfc_alloc_enc_roi_buffer(struct s5p_mfc_ctx *ctx);
-void s5p_mfc_release_enc_roi_buffer(struct s5p_mfc_ctx *ctx);
-
-int s5p_mfc_otf_alloc_stream_buf(struct s5p_mfc_ctx *ctx);
-void s5p_mfc_otf_release_stream_buf(struct s5p_mfc_ctx *ctx);
-
-int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev);
-int s5p_mfc_load_firmware(struct s5p_mfc_dev *dev);
-int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev);
-
-int s5p_mfc_alloc_dbg_info_buffer(struct s5p_mfc_dev *dev);
-int s5p_mfc_release_dbg_info_buffer(struct s5p_mfc_dev *dev);
-
-#endif /* __S5P_MFC_BUF_H */
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_cal.c
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <trace/events/mfc.h>
-
-#include "s5p_mfc_cal.h"
-#include "s5p_mfc_pm.h"
-
-/* Reset the device */
-int s5p_mfc_reset_mfc(struct s5p_mfc_dev *dev)
-{
- int i;
-
- mfc_debug_enter();
-
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
-
- /* Zero Initialization of MFC registers */
- MFC_WRITEL(0, S5P_FIMV_RISC2HOST_CMD);
- MFC_WRITEL(0, S5P_FIMV_HOST2RISC_CMD);
- MFC_WRITEL(0, S5P_FIMV_FW_VERSION);
-
- for (i = 0; i < S5P_FIMV_REG_CLEAR_COUNT; i++)
- MFC_WRITEL(0, S5P_FIMV_REG_CLEAR_BEGIN + (i*4));
-
- MFC_WRITEL(0x1FFF, S5P_FIMV_MFC_RESET);
- MFC_WRITEL(0, S5P_FIMV_MFC_RESET);
-
- mfc_debug_leave();
-
- return 0;
-}
-
-void s5p_mfc_set_risc_base_addr(struct s5p_mfc_dev *dev,
- enum mfc_buf_usage_type buf_type)
-{
- struct s5p_mfc_special_buf *fw_buf;
-
- fw_buf = &dev->fw_buf;
-
- if (buf_type == MFCBUF_DRM)
- fw_buf = &dev->drm_fw_buf;
-
- MFC_WRITEL(fw_buf->daddr, S5P_FIMV_RISC_BASE_ADDRESS);
- mfc_debug(2, "[MEMINFO][F/W] %s Base Address : %#x\n",
- buf_type == MFCBUF_DRM ? "DRM" : "NORMAL", fw_buf->daddr);
- MFC_TRACE_DEV("%s F/W Base Address : %#x\n",
- buf_type == MFCBUF_DRM ? "DRM" : "NORMAL", fw_buf->daddr);
-}
-
-void s5p_mfc_cmd_host2risc(struct s5p_mfc_dev *dev, int cmd)
-{
- mfc_debug(1, "Issue the command: %d\n", cmd);
- MFC_TRACE_DEV(">> CMD : %d, (dev:0x%lx, bits:%lx, owned:%d, wl:%d, trans:%d)\n",
- cmd, dev->hwlock.dev, dev->hwlock.bits, dev->hwlock.owned_by_irq,
- dev->hwlock.wl_count, dev->hwlock.transfer_owner);
-
- trace_mfc_frame_start(dev->curr_ctx, cmd, 0, 0);
- /* Reset RISC2HOST command except nal q stop command */
- if (cmd != S5P_FIMV_H2R_CMD_STOP_QUEUE)
- MFC_WRITEL(0x0, S5P_FIMV_RISC2HOST_CMD);
-
- /* Start the timeout watchdog */
- if ((cmd != S5P_FIMV_H2R_CMD_NAL_QUEUE) && (cmd != S5P_FIMV_H2R_CMD_STOP_QUEUE))
- s5p_mfc_watchdog_start_tick(dev);
-
- if (dbg_enable) {
- /* For FW debugging */
- s5p_mfc_dbg_set_addr(dev);
- s5p_mfc_dbg_enable(dev);
- }
-
- /* Issue the command */
- MFC_WRITEL(cmd, S5P_FIMV_HOST2RISC_CMD);
- MFC_WRITEL(0x1, S5P_FIMV_HOST2RISC_INT);
-}
-
-/* Check whether HW interrupt has occurred or not */
-int s5p_mfc_check_risc2host(struct s5p_mfc_dev *dev)
-{
- if (s5p_mfc_pm_get_pwr_ref_cnt(dev) && s5p_mfc_pm_get_clk_ref_cnt(dev)) {
- if (MFC_READL(S5P_FIMV_RISC2HOST_INT))
- return MFC_READL(S5P_FIMV_RISC2HOST_CMD);
- else
- return 0;
- }
-
- return 0;
-}
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_cal.h
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __S5P_MFC_CAL_H
-#define __S5P_MFC_CAL_H __FILE__
-
-#include "s5p_mfc_reg.h"
-
-#include "s5p_mfc_common.h"
-
-#include "s5p_mfc_utils.h"
-
-
-#define s5p_mfc_get_int_reason() (MFC_READL(S5P_FIMV_RISC2HOST_CMD) \
- & S5P_FIMV_RISC2HOST_CMD_MASK)
-#define s5p_mfc_clear_int_sfr() \
- do { \
- MFC_WRITEL(0, S5P_FIMV_RISC2HOST_CMD); \
- MFC_WRITEL(0, S5P_FIMV_RISC2HOST_INT); \
- } while (0)
-
-static inline int s5p_mfc_stop_bus(struct s5p_mfc_dev *dev)
-{
- unsigned int status;
- unsigned long timeout;
-
- /* Reset */
- MFC_WRITEL(0x1, S5P_FIMV_MFC_BUS_RESET_CTRL);
-
- timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT);
- /* Check bus status */
- do {
- if (time_after(jiffies, timeout)) {
- mfc_err_dev("Timeout while resetting MFC.\n");
- return -EIO;
- }
- status = MFC_READL(S5P_FIMV_MFC_BUS_RESET_CTRL);
- } while ((status & 0x2) == 0);
-
- return 0;
-}
-
-static inline void s5p_mfc_start_bus(struct s5p_mfc_dev *dev)
-{
- int val;
-
- val = MFC_READL(S5P_FIMV_MFC_BUS_RESET_CTRL);
- val &= ~(0x1);
- MFC_WRITEL(val, S5P_FIMV_MFC_BUS_RESET_CTRL);
-}
-
-static inline void s5p_mfc_risc_on(struct s5p_mfc_dev *dev)
-{
- s5p_mfc_clean_dev_int_flags(dev);
-
- MFC_WRITEL(0x1, S5P_FIMV_RISC_ON);
- MFC_WRITEL(0x0, S5P_FIMV_MFC_OFF);
- mfc_debug(1, "RISC_ON\n");
- MFC_TRACE_DEV(">> RISC ON\n");
-}
-
-static inline void s5p_mfc_risc_off(struct s5p_mfc_dev *dev)
-{
- unsigned int status;
- unsigned long timeout;
-
- timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT);
- /* Check pending status */
- do {
- if (time_after(jiffies, timeout)) {
- mfc_err_dev("Timeout while pendng clear\n");
- mfc_err_dev("MFC access pending state: %#x\n", status);
- mfc_err_dev("MFC access pending R: %#x, W: %#x\n",
- MFC_READL(S5P_FIMV_MFC_RPEND),
- MFC_READL(S5P_FIMV_MFC_WPEND));
- break;
- }
- status = MFC_READL(S5P_FIMV_MFC_BUS_STATUS);
- } while (status != 0);
-
- MFC_WRITEL(0x0, S5P_FIMV_RISC_ON);
-}
-
-static inline void s5p_mfc_mfc_off(struct s5p_mfc_dev *dev)
-{
- mfc_info_dev("MFC h/w state: %d\n",
- MFC_READL(S5P_FIMV_MFC_STATE) & 0x7);
- MFC_WRITEL(0x1, S5P_FIMV_MFC_OFF);
-}
-
-static inline void s5p_mfc_enable_all_clocks(struct s5p_mfc_dev *dev)
-{
- /* Enable all FW clock gating */
- MFC_WRITEL(0xFFFFFFFF, S5P_FIMV_MFC_FW_CLOCK);
-}
-
-int s5p_mfc_reset_mfc(struct s5p_mfc_dev *dev);
-void s5p_mfc_set_risc_base_addr(struct s5p_mfc_dev *dev,
- enum mfc_buf_usage_type buf_type);
-void s5p_mfc_cmd_host2risc(struct s5p_mfc_dev *dev, int cmd);
-int s5p_mfc_check_risc2host(struct s5p_mfc_dev *dev);
-
-#endif /* __S5P_MFC_CAL_H */
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_cmd.c
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <trace/events/mfc.h>
-
-#include "s5p_mfc_cmd.h"
-
-#include "s5p_mfc_cal.h"
-#include "s5p_mfc_reg.h"
-#include "s5p_mfc_mmcache.h"
-
-#include "s5p_mfc_utils.h"
-#include "s5p_mfc_buf.h"
-
-int s5p_mfc_cmd_sys_init(struct s5p_mfc_dev *dev,
- enum mfc_buf_usage_type buf_type)
-{
- struct s5p_mfc_ctx_buf_size *buf_size;
- struct s5p_mfc_special_buf *ctx_buf;
-
- mfc_debug_enter();
-
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
-
- s5p_mfc_clean_dev_int_flags(dev);
-
- buf_size = dev->variant->buf_size->ctx_buf;
- ctx_buf = &dev->common_ctx_buf;
-#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
- if (buf_type == MFCBUF_DRM)
- ctx_buf = &dev->drm_common_ctx_buf;
-#endif
- MFC_WRITEL(ctx_buf->daddr, S5P_FIMV_CONTEXT_MEM_ADDR);
- MFC_WRITEL(buf_size->dev_ctx, S5P_FIMV_CONTEXT_MEM_SIZE);
-
- s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_SYS_INIT);
-
- mfc_debug_leave();
-
- return 0;
-}
-
-void s5p_mfc_cmd_sleep(struct s5p_mfc_dev *dev)
-{
- mfc_debug_enter();
-
- s5p_mfc_clean_dev_int_flags(dev);
- s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_SLEEP);
-
- mfc_debug_leave();
-}
-
-void s5p_mfc_cmd_wakeup(struct s5p_mfc_dev *dev)
-{
- mfc_debug_enter();
-
- s5p_mfc_clean_dev_int_flags(dev);
- s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_WAKEUP);
-
- mfc_debug_leave();
-}
-
-/* Open a new instance and get its number */
-int s5p_mfc_cmd_open_inst(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev;
-
- mfc_debug_enter();
-
- if (!ctx) {
- mfc_err_dev("no mfc context to run\n");
- return -EINVAL;
- }
- dev = ctx->dev;
- mfc_debug(2, "Requested codec mode: %d\n", ctx->codec_mode);
-
- MFC_WRITEL(ctx->codec_mode, S5P_FIMV_CODEC_TYPE);
- MFC_WRITEL(ctx->instance_ctx_buf.daddr, S5P_FIMV_CONTEXT_MEM_ADDR);
- MFC_WRITEL(ctx->instance_ctx_buf.size, S5P_FIMV_CONTEXT_MEM_SIZE);
- if (ctx->type == MFCINST_DECODER)
- MFC_WRITEL(ctx->dec_priv->crc_enable, S5P_FIMV_D_CRC_CTRL);
-
- s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_OPEN_INSTANCE);
-
- mfc_debug_leave();
-
- return 0;
-}
-
-/* Close instance */
-int s5p_mfc_cmd_close_inst(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev;
-
- mfc_debug_enter();
-
- if (!ctx) {
- mfc_err_dev("no mfc context to run\n");
- return -EINVAL;
- }
- dev = ctx->dev;
-
- MFC_WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID);
-
- s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_CLOSE_INSTANCE);
-
- mfc_debug_leave();
-
- return 0;
-}
-
-int s5p_mfc_cmd_dpb_flush(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
-
- if (ON_RES_CHANGE(ctx))
- mfc_err_ctx("dpb flush on res change(state:%d)\n", ctx->state);
-
- s5p_mfc_clean_ctx_int_flags(ctx);
-
- MFC_WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID);
- s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_DPB_FLUSH);
-
- return 0;
-}
-
-int s5p_mfc_cmd_cache_flush(struct s5p_mfc_dev *dev)
-{
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
-
- s5p_mfc_clean_dev_int_flags(dev);
- s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_CACHE_FLUSH);
-
- return 0;
-}
-
-int s5p_mfc_cmd_dec_init_buffers(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev;
- struct s5p_mfc_dec *dec;
- unsigned int reg = 0, pix_val;
- int ret;
-
- if (!ctx) {
- mfc_err_dev("no mfc context to run\n");
- return -EINVAL;
- }
- dec = ctx->dec_priv;
- dev = ctx->dev;
- if (!dev) {
- mfc_err_ctx("no mfc device to run\n");
- return -EINVAL;
- }
-
- switch (ctx->dst_fmt->fourcc) {
- case V4L2_PIX_FMT_NV12M:
- case V4L2_PIX_FMT_NV12N:
- case V4L2_PIX_FMT_NV12MT_16X16:
- case V4L2_PIX_FMT_NV16M:
- case V4L2_PIX_FMT_NV12N_10B:
- case V4L2_PIX_FMT_NV12M_S10B:
- case V4L2_PIX_FMT_NV16M_S10B:
- case V4L2_PIX_FMT_NV12M_P010:
- case V4L2_PIX_FMT_NV16M_P210:
- pix_val = 0;
- break;
- case V4L2_PIX_FMT_NV21M:
- case V4L2_PIX_FMT_NV61M:
- case V4L2_PIX_FMT_NV21M_S10B:
- case V4L2_PIX_FMT_NV61M_S10B:
- case V4L2_PIX_FMT_NV21M_P010:
- case V4L2_PIX_FMT_NV61M_P210:
- pix_val = 1;
- break;
- case V4L2_PIX_FMT_YVU420M:
- pix_val = 2;
- break;
- case V4L2_PIX_FMT_YUV420M:
- case V4L2_PIX_FMT_YUV420N:
- pix_val = 3;
- break;
- default:
- pix_val = 0;
- break;
- }
- reg = MFC_READL(S5P_FIMV_PIXEL_FORMAT);
- reg &= ~(0xF);
- reg |= pix_val & 0xF;
- MFC_WRITEL(reg, S5P_FIMV_PIXEL_FORMAT);
- mfc_debug(2, "[FRAME] pixel format: %d, mem_type_10bit should be fixed on SEQ_START(reg: %#x)\n",
- pix_val, reg);
-
- s5p_mfc_clean_ctx_int_flags(ctx);
- ret = s5p_mfc_set_dec_codec_buffers(ctx);
- if (ret) {
- mfc_info_ctx("isn't enough codec buffer size, re-alloc!\n");
-
- if (dev->has_mmcache && dev->mmcache.is_on_status)
- s5p_mfc_invalidate_mmcache(dev);
-
- s5p_mfc_release_codec_buffers(ctx);
- ret = s5p_mfc_alloc_codec_buffers(ctx);
- if (ret) {
- mfc_err_ctx("Failed to allocate decoding buffers\n");
- return ret;
- }
- ret = s5p_mfc_set_dec_codec_buffers(ctx);
- if (ret) {
- mfc_err_ctx("Failed to alloc frame mem\n");
- return ret;
- }
- }
-
- MFC_WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID);
-
- if (sfr_dump & MFC_DUMP_DEC_INIT_BUFS)
- call_dop(dev, dump_regs, dev);
-
- s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_INIT_BUFFERS);
-
- return ret;
-}
-
-int s5p_mfc_cmd_enc_init_buffers(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev;
- int ret;
-
- dev = ctx->dev;
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
-
- /*
- * Header was generated now starting processing
- * First set the reference frame buffers
- */
- if (!ctx->codec_buffer_allocated) {
- mfc_info_ctx("there isn't codec buffer, re-alloc!\n");
- ret = s5p_mfc_alloc_codec_buffers(ctx);
- if (ret) {
- mfc_err_ctx("Failed to allocate encoding buffers\n");
- return ret;
- }
- }
-
- s5p_mfc_clean_ctx_int_flags(ctx);
- ret = s5p_mfc_set_enc_codec_buffers(ctx);
- if (ret) {
- mfc_info_ctx("isn't enough codec buffer size, re-alloc!\n");
-
- if (dev->has_mmcache && dev->mmcache.is_on_status)
- s5p_mfc_invalidate_mmcache(dev);
-
- s5p_mfc_release_codec_buffers(ctx);
- ret = s5p_mfc_alloc_codec_buffers(ctx);
- if (ret) {
- mfc_err_ctx("Failed to allocate encoding buffers\n");
- return ret;
- }
- ret = s5p_mfc_set_enc_codec_buffers(ctx);
- if (ret) {
- mfc_err_ctx("Failed to set enc codec buffers\n");
- return ret;
- }
- }
-
- MFC_WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID);
-
- if (sfr_dump & MFC_DUMP_ENC_INIT_BUFS)
- call_dop(dev, dump_regs, dev);
-
- s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_INIT_BUFFERS);
-
- return ret;
-}
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_cmd.h
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __S5P_MFC_CMD_H
-#define __S5P_MFC_CMD_H __FILE__
-
-#include "s5p_mfc_common.h"
-
-int s5p_mfc_cmd_sys_init(struct s5p_mfc_dev *dev,
- enum mfc_buf_usage_type buf_type);
-void s5p_mfc_cmd_sleep(struct s5p_mfc_dev *dev);
-void s5p_mfc_cmd_wakeup(struct s5p_mfc_dev *dev);
-int s5p_mfc_cmd_open_inst(struct s5p_mfc_ctx *ctx);
-int s5p_mfc_cmd_close_inst(struct s5p_mfc_ctx *ctx);
-int s5p_mfc_cmd_dpb_flush(struct s5p_mfc_ctx *ctx);
-int s5p_mfc_cmd_cache_flush(struct s5p_mfc_dev *dev);
-int s5p_mfc_cmd_dec_init_buffers(struct s5p_mfc_ctx *ctx);
-int s5p_mfc_cmd_enc_init_buffers(struct s5p_mfc_ctx *ctx);
-
-#endif /* __S5P_MFC_CMD_H */
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_common.h
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __S5P_MFC_COMMON_H
-#define __S5P_MFC_COMMON_H __FILE__
-
-#include <linux/exynos_iovmm.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/sched/clock.h>
-#include <linux/ion_exynos.h>
-#include <linux/dma-buf-container.h>
-#include <media/videobuf2-dma-sg.h>
-#include <asm/cacheflush.h>
-
-#include "s5p_mfc_regs_v10.h"
-#include "s5p_mfc_macros.h"
-#include "s5p_mfc_debug.h"
-#include "exynos_mfc_media.h"
-#include "s5p_mfc_data_struct.h"
-
-#define MFC_DRIVER_INFO 180315
-
-#define MFC_MAX_REF_BUFS 2
-#define MFC_FRAME_PLANES 2
-#define MFC_INFO_INIT_FD -1
-
-#define MFC_MAX_DRM_CTX 2
-
-/* Interrupt timeout */
-#define MFC_INT_TIMEOUT 4000
-/* Interrupt short timeout */
-#define MFC_INT_SHORT_TIMEOUT 800
-/* hwlock timeout */
-#define MFC_HWLOCK_TIMEOUT 5000
-/* Busy wait timeout */
-#define MFC_BW_TIMEOUT 500
-/* MMCache invalidation timeout */
-#define MMCACHE_INVAL_TIMEOUT 1000
-/* Interrupt timeout count*/
-#define MFC_INT_TIMEOUT_CNT 2
-
-/* This value guarantees 299.4msec ~ 2.25sec according to MFC clock (668MHz ~ 89MHz)
- * releated with S5P_FIMV_DEC_TIMEOUT_VALUE */
-#define MFC_TIMEOUT_VALUE 200000000
-
-#define NUM_MPEG4_LF_BUF 2
-
-#define DEFAULT_TAG (0xE05)
-
-#define MFC_NO_INSTANCE_SET -1
-
-#define MFC_ENC_CAP_PLANE_COUNT 1
-#define MFC_ENC_OUT_PLANE_COUNT 2
-
-#define MFC_NAME_LEN 16
-#define MFC_FW_NAME "mfc_fw.bin"
-
-#define STUFF_BYTE 4
-
-#define MFC_BASE_MASK ((1 << 17) - 1)
-
-#define FLAG_LAST_FRAME 0x80000000
-#define FLAG_EMPTY_DATA 0x40000000
-#define FLAG_CSD 0x20000000
-
-/* MFC conceal color is black */
-#define MFC_CONCEAL_COLOR 0x8020000
-
-#define vb_to_mfc_buf(x) \
- container_of(x, struct s5p_mfc_buf, vb.vb2_buf)
-
-#define fh_to_mfc_ctx(x) \
- container_of(x, struct s5p_mfc_ctx, fh)
-
-#define call_bop(b, op, args...) \
- (b->op ? b->op(args) : 0)
-
-#define call_cop(c, op, args...) \
- (((c)->c_ops->op) ? \
- ((c)->c_ops->op(args)) : 0)
-
-#define call_dop(d, op, args...) \
- (((d)->dump_ops->op) ? \
- ((d)->dump_ops->op(args)) : 0)
-
-#define MFC_CTRL_TYPE_GET (MFC_CTRL_TYPE_GET_SRC | MFC_CTRL_TYPE_GET_DST)
-#define MFC_CTRL_TYPE_SRC (MFC_CTRL_TYPE_SET | MFC_CTRL_TYPE_GET_SRC)
-#define MFC_CTRL_TYPE_DST (MFC_CTRL_TYPE_GET_DST)
-
-#define MFC_FMT_STREAM (1 << 0)
-#define MFC_FMT_FRAME (1 << 1)
-#define MFC_FMT_10BIT (1 << 2)
-#define MFC_FMT_422 (1 << 3)
-#define MFC_FMT_RGB (1 << 4)
-
-/* node check */
-#define IS_DEC_NODE(n) ((n == EXYNOS_VIDEONODE_MFC_DEC) || \
- (n == EXYNOS_VIDEONODE_MFC_DEC_DRM))
-#define IS_ENC_NODE(n) ((n == EXYNOS_VIDEONODE_MFC_ENC) || \
- (n == EXYNOS_VIDEONODE_MFC_ENC_DRM) || \
- (n == EXYNOS_VIDEONODE_MFC_ENC_OTF) || \
- (n == EXYNOS_VIDEONODE_MFC_ENC_OTF_DRM))
-
-/* Decoder codec mode check */
-#define IS_H264_DEC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_H264_DEC)
-#define IS_H264_MVC_DEC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_H264_MVC_DEC)
-#define IS_MPEG4_DEC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_MPEG4_DEC)
-#define IS_FIMV1_DEC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_FIMV1_DEC)
-#define IS_FIMV2_DEC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_FIMV2_DEC)
-#define IS_FIMV3_DEC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_FIMV3_DEC)
-#define IS_FIMV4_DEC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_FIMV4_DEC)
-#define IS_VC1_DEC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_VC1_DEC)
-#define IS_VC1_RCV_DEC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_VC1_RCV_DEC)
-#define IS_MPEG2_DEC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_MPEG2_DEC)
-#define IS_HEVC_DEC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_HEVC_DEC)
-#define IS_VP9_DEC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_VP9_DEC)
-#define IS_BPG_DEC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_BPG_DEC)
-
-/* Encoder codec mode check */
-#define IS_H264_ENC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_H264_ENC)
-#define IS_MPEG4_ENC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_MPEG4_ENC)
-#define IS_H263_ENC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_H263_ENC)
-#define IS_VP8_ENC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_VP8_ENC)
-#define IS_HEVC_ENC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_HEVC_ENC)
-#define IS_VP9_ENC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_VP9_ENC)
-#define IS_BPG_ENC(ctx) ((ctx)->codec_mode == S5P_FIMV_CODEC_BPG_ENC)
-
-#define CODEC_NOT_CODED(ctx) (IS_MPEG4_DEC(ctx) || IS_VC1_DEC(ctx) || IS_VC1_RCV_DEC(ctx))
-#define CODEC_INTERLACED(ctx) (IS_H264_DEC(ctx) || IS_H264_MVC_DEC(ctx) || \
- IS_MPEG2_DEC(ctx) || IS_MPEG4_DEC(ctx) || \
- IS_VC1_DEC(ctx) || IS_VC1_RCV_DEC(ctx))
-#define CODEC_MBAFF(ctx) (IS_H264_DEC(ctx) || IS_H264_MVC_DEC(ctx))
-#define CODEC_MULTIFRAME(ctx) (IS_MPEG4_DEC(ctx) || IS_VP9_DEC(ctx) || \
- IS_FIMV2_DEC(ctx) || IS_FIMV3_DEC(ctx) || IS_FIMV4_DEC(ctx))
-#define CODEC_10BIT(ctx) (IS_HEVC_DEC(ctx) || IS_HEVC_ENC(ctx) || \
- IS_VP9_DEC(ctx) || IS_VP9_ENC(ctx) || \
- IS_BPG_DEC(ctx) || IS_BPG_ENC(ctx))
-#define CODEC_422FORMAT(ctx) (IS_HEVC_DEC(ctx) || IS_HEVC_ENC(ctx) || \
- IS_VP9_DEC(ctx) || IS_VP9_ENC(ctx) || \
- IS_BPG_DEC(ctx) || IS_BPG_ENC(ctx))
-#define ON_RES_CHANGE(ctx) (((ctx)->state >= MFCINST_RES_CHANGE_INIT) && \
- ((ctx)->state <= MFCINST_RES_CHANGE_END))
-
-#define IS_BUFFER_BATCH_MODE(ctx) ((ctx)->batch_mode == 1)
-
-/* UHD resoluition */
-#define MFC_UHD_RES (3840 * 2160)
-#define IS_UHD_RES(ctx) (((ctx)->crop_width * (ctx)->crop_height) == MFC_UHD_RES)
-#define OVER_UHD_ENC60(ctx) ((((ctx)->crop_width * (ctx)->crop_height) == MFC_UHD_RES) && \
- ((ctx)->type == MFCINST_ENCODER) && \
- ((ctx)->framerate / 1000) >= 60)
-
-/* Extra information for Decoder */
-#define DEC_SET_DUAL_DPB (1 << 0)
-#define DEC_SET_DYNAMIC_DPB (1 << 1)
-#define DEC_SET_LAST_FRAME_INFO (1 << 2)
-#define DEC_SET_SKYPE_FLAG (1 << 3)
-
-/* Extra information for Encoder */
-#define ENC_SET_RGB_INPUT (1 << 0)
-#define ENC_SET_SPARE_SIZE (1 << 1)
-#define ENC_SET_TEMP_SVC_CH (1 << 2)
-#define ENC_SET_SKYPE_FLAG (1 << 3)
-#define ENC_SET_ROI_CONTROL (1 << 4)
-#define ENC_SET_QP_BOUND_PB (1 << 5)
-#define ENC_SET_FIXED_SLICE (1 << 6)
-#define ENC_SET_PVC_MODE (1 << 7)
-#define ENC_SET_RATIO_OF_INTRA (1 << 8)
-#define ENC_SET_COLOR_ASPECT (1 << 9)
-#define ENC_SET_HP_BITRATE_CONTROL (1 << 10)
-#define ENC_SET_STATIC_INFO (1 << 11)
-
-#define MFC_VER_MAJOR(dev) ((dev->pdata->ip_ver >> 8) & 0xFF)
-#define MFC_VER_MINOR(dev) (dev->pdata->ip_ver & 0xFF)
-
-#define MFC_FEATURE_SUPPORT(dev, f) ((f).support && ((dev)->fw.date >= (f).version))
-
-/* Low memory check */
-#define IS_LOW_MEM (totalram_pages <= ((SZ_1G + SZ_512M) >> PAGE_SHIFT))
-#define SZ_600M (6 * 1024 * 1024)
-
-#endif /* __S5P_MFC_COMMON_H */
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_ctrl.c
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include "s5p_mfc_ctrl.h"
-
-#include "s5p_mfc_hwlock.h"
-#include "s5p_mfc_nal_q.h"
-#include "s5p_mfc_sync.h"
-
-#include "s5p_mfc_pm.h"
-#include "s5p_mfc_cmd.h"
-#include "s5p_mfc_cal.h"
-#include "s5p_mfc_reg.h"
-
-#include "s5p_mfc_utils.h"
-
-/* Initialize hardware */
-static int mfc_init_hw(struct s5p_mfc_dev *dev, enum mfc_buf_usage_type buf_type)
-{
- int fw_ver;
- int ret = 0;
- int curr_ctx_is_drm_backup;
-
- mfc_debug_enter();
-
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
-
- curr_ctx_is_drm_backup = dev->curr_ctx_is_drm;
-
- if (!dev->fw_buf.dma_buf)
- return -EINVAL;
-
- /* 0. MFC reset */
- mfc_debug(2, "MFC reset...\n");
-
- /* At init time, do not call secure API */
- if (buf_type == MFCBUF_NORMAL)
- dev->curr_ctx_is_drm = 0;
- else if (buf_type == MFCBUF_DRM)
- dev->curr_ctx_is_drm = 1;
-
- ret = s5p_mfc_pm_clock_on(dev);
- if (ret) {
- mfc_err_dev("Failed to enable clock before reset(%d)\n", ret);
- dev->curr_ctx_is_drm = curr_ctx_is_drm_backup;
- return ret;
- }
-
- ret = s5p_mfc_reset_mfc(dev);
- if (ret) {
- mfc_err_dev("Failed to reset MFC - timeout\n");
- goto err_init_hw;
- }
- mfc_debug(2, "Done MFC reset...\n");
-
- /* 1. Set DRAM base Addr */
- s5p_mfc_set_risc_base_addr(dev, buf_type);
-
- /* 2. Release reset signal to the RISC */
- s5p_mfc_risc_on(dev);
-
- mfc_debug(2, "Will now wait for completion of firmware transfer\n");
- if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_FW_STATUS_RET)) {
- mfc_err_dev("Failed to RISC_ON\n");
- s5p_mfc_clean_dev_int_flags(dev);
- ret = -EIO;
- goto err_init_hw;
- }
-
- /* 3. Initialize firmware */
- ret = s5p_mfc_cmd_sys_init(dev, buf_type);
- if (ret) {
- mfc_err_dev("Failed to send command to MFC - timeout\n");
- goto err_init_hw;
- }
-
- mfc_debug(2, "Ok, now will write a command to init the system\n");
- if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_SYS_INIT_RET)) {
- mfc_err_dev("Failed to SYS_INIT\n");
- s5p_mfc_clean_dev_int_flags(dev);
- ret = -EIO;
- goto err_init_hw;
- }
-
- dev->int_condition = 0;
- if (dev->int_err != 0 || dev->int_reason != S5P_FIMV_R2H_CMD_SYS_INIT_RET) {
- /* Failure. */
- mfc_err_dev("Failed to init firmware - error: %d, int: %d\n",
- dev->int_err, dev->int_reason);
- ret = -EIO;
- goto err_init_hw;
- }
-
- dev->fw.fimv_info = s5p_mfc_get_fimv_info();
- if (dev->fw.fimv_info != 'D' && dev->fw.fimv_info != 'E')
- dev->fw.fimv_info = 'N';
-
- mfc_info_dev("[F/W] MFC v%x.%x, %02xyy %02xmm %02xdd (%c)\n",
- MFC_VER_MAJOR(dev),
- MFC_VER_MINOR(dev),
- s5p_mfc_get_fw_ver_year(),
- s5p_mfc_get_fw_ver_month(),
- s5p_mfc_get_fw_ver_date(),
- dev->fw.fimv_info);
-
- dev->fw.date = s5p_mfc_get_fw_ver_all();
- /* Check MFC version and F/W version */
- fw_ver = s5p_mfc_get_mfc_version();
- if (fw_ver != dev->pdata->ip_ver) {
- mfc_err_dev("Invalid F/W version(0x%x) for MFC H/W(0x%x)\n",
- fw_ver, dev->pdata->ip_ver);
- ret = -EIO;
- goto err_init_hw;
- }
-
-#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
- /* Cache flush for base address change */
- s5p_mfc_cmd_cache_flush(dev);
- if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_CACHE_FLUSH_RET)) {
- mfc_err_dev("Failed to CACHE_FLUSH\n");
- s5p_mfc_clean_dev_int_flags(dev);
- ret = -EIO;
- goto err_init_hw;
- }
-
- if (buf_type == MFCBUF_DRM && !curr_ctx_is_drm_backup) {
- s5p_mfc_pm_clock_off(dev);
- dev->curr_ctx_is_drm = curr_ctx_is_drm_backup;
- s5p_mfc_pm_clock_on_with_base(dev, MFCBUF_NORMAL);
- }
-#endif
-
-err_init_hw:
- s5p_mfc_pm_clock_off(dev);
- dev->curr_ctx_is_drm = curr_ctx_is_drm_backup;
- mfc_debug_leave();
-
- return ret;
-}
-
-/* Wrapper : Initialize hardware */
-int s5p_mfc_init_hw(struct s5p_mfc_dev *dev)
-{
- int ret;
-
- ret = mfc_init_hw(dev, MFCBUF_NORMAL);
- if (ret)
- return ret;
-
-#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
- if (dev->fw.drm_status) {
- ret = mfc_init_hw(dev, MFCBUF_DRM);
- if (ret)
- return ret;
- }
-#endif
-
- return ret;
-}
-
-/* Deinitialize hardware */
-void s5p_mfc_deinit_hw(struct s5p_mfc_dev *dev)
-{
- int ret;
-
- mfc_debug(2, "mfc deinit start\n");
-
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return;
- }
-
- ret = s5p_mfc_pm_clock_on(dev);
- if (ret) {
- mfc_err_dev("Failed to enable clock before reset(%d)\n", ret);
- return;
- }
-
- s5p_mfc_mfc_off(dev);
-
- s5p_mfc_pm_clock_off(dev);
-
- mfc_debug(2, "mfc deinit completed\n");
-}
-
-int s5p_mfc_sleep(struct s5p_mfc_dev *dev)
-{
- struct s5p_mfc_ctx *ctx;
- int ret;
- int old_state, i;
- int need_cache_flush = 0;
-
- mfc_debug_enter();
-
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
-
- ctx = dev->ctx[dev->curr_ctx];
- if (!ctx) {
- for (i = 0; i < MFC_NUM_CONTEXTS; i++) {
- if (dev->ctx[i]) {
- ctx = dev->ctx[i];
- break;
- }
- }
- if (!ctx) {
- mfc_err_dev("no mfc context to run\n");
- return -EINVAL;
- } else {
- mfc_info_dev("ctx is changed %d -> %d\n",
- dev->curr_ctx, ctx->num);
- dev->curr_ctx = ctx->num;
- if (dev->curr_ctx_is_drm != ctx->is_drm) {
- need_cache_flush = 1;
- mfc_info_dev("DRM attribute is changed %d->%d\n",
- dev->curr_ctx_is_drm, ctx->is_drm);
- }
- }
- }
- old_state = ctx->state;
- s5p_mfc_change_state(ctx, MFCINST_ABORT);
- MFC_TRACE_DEV_HWLOCK("**sleep (ctx:%d)\n", ctx->num);
- ret = s5p_mfc_get_hwlock_dev(dev);
- if (ret < 0) {
- mfc_err_dev("Failed to get hwlock\n");
- mfc_err_dev("dev.hwlock.dev = 0x%lx, bits = 0x%lx, owned_by_irq = %d, wl_count = %d, transfer_owner = %d\n",
- dev->hwlock.dev, dev->hwlock.bits, dev->hwlock.owned_by_irq,
- dev->hwlock.wl_count, dev->hwlock.transfer_owner);
- return -EBUSY;
- }
-
- mfc_info_dev("curr_ctx_is_drm:%d, hwlock.bits:%lu, hwlock.dev:%lu\n",
- dev->curr_ctx_is_drm, dev->hwlock.bits, dev->hwlock.dev);
-
- s5p_mfc_change_state(ctx, old_state);
- s5p_mfc_pm_clock_on(dev);
-
- if (need_cache_flush)
- s5p_mfc_cache_flush(dev, ctx->is_drm);
-
- s5p_mfc_cmd_sleep(dev);
-
- if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_SLEEP_RET)) {
- mfc_err_dev("Failed to SLEEP\n");
- dev->logging_data->cause |= (1 << MFC_CAUSE_FAIL_SLEEP);
- call_dop(dev, dump_and_stop_always, dev);
- return -EIO;
- }
-
- dev->int_condition = 0;
- if (dev->int_err != 0 || dev->int_reason != S5P_FIMV_R2H_CMD_SLEEP_RET) {
- /* Failure. */
- mfc_err_dev("Failed to sleep - error: %d, int: %d\n",
- dev->int_err, dev->int_reason);
- ret = -EIO;
- goto err_mfc_sleep;
- }
-
- dev->sleep = 1;
-
-err_mfc_sleep:
- s5p_mfc_mfc_off(dev);
- s5p_mfc_pm_clock_off(dev);
- s5p_mfc_release_hwlock_dev(dev);
- mfc_debug_leave();
-
- return ret;
-}
-
-int s5p_mfc_wakeup(struct s5p_mfc_dev *dev)
-{
- enum mfc_buf_usage_type buf_type;
- int ret = 0;
-
- mfc_debug_enter();
-
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
- mfc_info_dev("curr_ctx_is_drm:%d\n", dev->curr_ctx_is_drm);
-
- MFC_TRACE_DEV_HWLOCK("**wakeup\n");
- ret = s5p_mfc_get_hwlock_dev(dev);
- if (ret < 0) {
- mfc_err_dev("Failed to get hwlock\n");
- mfc_err_dev("dev.hwlock.dev = 0x%lx, bits = 0x%lx, owned_by_irq = %d, wl_count = %d, transfer_owner = %d\n",
- dev->hwlock.dev, dev->hwlock.bits, dev->hwlock.owned_by_irq,
- dev->hwlock.wl_count, dev->hwlock.transfer_owner);
- return -EBUSY;
- }
-
- dev->sleep = 0;
-
- /* 0. MFC reset */
- mfc_debug(2, "MFC reset...\n");
-
- s5p_mfc_pm_clock_on(dev);
-
- ret = s5p_mfc_reset_mfc(dev);
- if (ret) {
- mfc_err_dev("Failed to reset MFC - timeout\n");
- goto err_mfc_wakeup;
- }
- mfc_debug(2, "Done MFC reset...\n");
- if (dev->curr_ctx_is_drm)
- buf_type = MFCBUF_DRM;
- else
- buf_type = MFCBUF_NORMAL;
-
- /* 1. Set DRAM base Addr */
- s5p_mfc_set_risc_base_addr(dev, buf_type);
-
- /* 2. Release reset signal to the RISC */
- s5p_mfc_risc_on(dev);
-
- mfc_debug(2, "Will now wait for completion of firmware transfer\n");
- if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_FW_STATUS_RET)) {
- mfc_err_dev("Failed to RISC_ON\n");
- dev->logging_data->cause |= (1 << MFC_CAUSE_FAIL_RISC_ON);
- call_dop(dev, dump_and_stop_always, dev);
- return -EIO;
- }
-
- mfc_debug(2, "Ok, now will write a command to wakeup the system\n");
- s5p_mfc_cmd_wakeup(dev);
-
- mfc_debug(2, "Will now wait for completion of firmware wake up\n");
- if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_WAKEUP_RET)) {
- mfc_err_dev("Failed to WAKEUP\n");
- dev->logging_data->cause |= (1 << MFC_CAUSE_FAIL_WAKEUP);
- call_dop(dev, dump_and_stop_always, dev);
- return -EIO;
- }
-
- dev->int_condition = 0;
- if (dev->int_err != 0 || dev->int_reason != S5P_FIMV_R2H_CMD_WAKEUP_RET) {
- /* Failure. */
- mfc_err_dev("Failed to wakeup - error: %d, int: %d\n",
- dev->int_err, dev->int_reason);
- ret = -EIO;
- goto err_mfc_wakeup;
- }
-
-err_mfc_wakeup:
- s5p_mfc_pm_clock_off(dev);
-
- s5p_mfc_release_hwlock_dev(dev);
-
- mfc_debug_leave();
-
- return ret;
-}
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_ctrl.h
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __S5P_MFC_CTRL_H
-#define __S5P_MFC_CTRL_H __FILE__
-
-#include "s5p_mfc_common.h"
-
-int s5p_mfc_init_hw(struct s5p_mfc_dev *dev);
-void s5p_mfc_deinit_hw(struct s5p_mfc_dev *dev);
-
-int s5p_mfc_sleep(struct s5p_mfc_dev *dev);
-int s5p_mfc_wakeup(struct s5p_mfc_dev *dev);
-
-#endif /* __S5P_MFC_CTRL_H */
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_data_struct.h
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __S5P_MFC_DATA_STRUCT_H
-#define __S5P_MFC_DATA_STRUCT_H __FILE__
-
-#ifdef CONFIG_ARM_EXYNOS_DEVFREQ
-#define CONFIG_MFC_USE_BUS_DEVFREQ
-#endif
-
-#ifdef CONFIG_MFC_USE_BUS_DEVFREQ
-#include <linux/pm_qos.h>
-#endif
-#ifdef CONFIG_EXYNOS_BTS
-#include <soc/samsung/bts.h>
-#endif
-#include <linux/videodev2.h>
-#ifdef CONFIG_EXYNOS_ITMON
-#include <soc/samsung/exynos-itmon.h>
-#endif
-
-#include <media/v4l2-device.h>
-#include <media/v4l2-ioctl.h>
-#include <media/videobuf2-v4l2.h>
-
-#include "exynos_mfc_media.h"
-
-#define MFC_NUM_CONTEXTS 32
-#define MFC_MAX_PLANES 3
-#define MFC_MAX_DPBS 32
-#define MFC_MAX_BUFFERS 32
-#define MFC_MAX_EXTRA_BUF 10
-#define MFC_TIME_INDEX 15
-#define MFC_SFR_LOGGING_COUNT_SET1 4
-#define MFC_SFR_LOGGING_COUNT_SET2 23
-#define MFC_LOGGING_DATA_SIZE 256
-#define MFC_MAX_DEFAULT_PARAM 100
-
-#define HWFC_MAX_BUF 10
-#define OTF_MAX_BUF 30
-
-/* Maximum number of temporal layers */
-#define VIDEO_MAX_TEMPORAL_LAYERS 7
-
-#define MAX_NUM_IMAGES_IN_VB 8
-#define MAX_NUM_BUFCON_BUFS 32
-#define MAX_NUM_CLUSTER 3
-
-/*
- * MFC region id for smc
- */
-enum {
- FC_MFC_EXYNOS_ID_MFC_SH = 0,
- FC_MFC_EXYNOS_ID_VIDEO = 1,
- FC_MFC_EXYNOS_ID_MFC_FW = 2,
- FC_MFC_EXYNOS_ID_SECTBL = 3,
- FC_MFC_EXYNOS_ID_G2D_WFD = 4,
- FC_MFC_EXYNOS_ID_MFC_NFW = 5,
- FC_MFC_EXYNOS_ID_VIDEO_EXT = 6,
-};
-
-/**
- * enum s5p_mfc_inst_type - The type of an MFC device node.
- */
-enum s5p_mfc_node_type {
- MFCNODE_INVALID = -1,
- MFCNODE_DECODER = 0,
- MFCNODE_ENCODER = 1,
- MFCNODE_DECODER_DRM = 2,
- MFCNODE_ENCODER_DRM = 3,
- MFCNODE_ENCODER_OTF = 4,
- MFCNODE_ENCODER_OTF_DRM = 5,
-};
-
-/**
- * enum s5p_mfc_inst_type - The type of an MFC instance.
- */
-enum s5p_mfc_inst_type {
- MFCINST_INVALID = 0,
- MFCINST_DECODER = 1,
- MFCINST_ENCODER = 2,
-};
-
-/**
- * enum s5p_mfc_inst_state - The state of an MFC instance.
- */
-enum s5p_mfc_inst_state {
- MFCINST_FREE = 0,
- MFCINST_INIT = 100,
- MFCINST_GOT_INST,
- MFCINST_HEAD_PARSED,
- MFCINST_RUNNING_BUF_FULL,
- MFCINST_RUNNING,
- MFCINST_FINISHING,
- MFCINST_RETURN_INST,
- MFCINST_ERROR,
- MFCINST_ABORT,
- MFCINST_RES_CHANGE_INIT,
- MFCINST_RES_CHANGE_FLUSH,
- MFCINST_RES_CHANGE_END,
- MFCINST_RUNNING_NO_OUTPUT, // Unused
- MFCINST_ABORT_INST,
- MFCINST_DPB_FLUSHING,
- MFCINST_SPECIAL_PARSING,
- MFCINST_SPECIAL_PARSING_NAL,
-};
-
-/**
- * enum s5p_mfc_queue_state - The state of buffer queue.
- */
-enum s5p_mfc_queue_state {
- QUEUE_FREE = 0,
- QUEUE_BUFS_REQUESTED,
- QUEUE_BUFS_QUERIED,
- QUEUE_BUFS_MMAPED,
-};
-
-enum mfc_dec_wait_state {
- WAIT_NONE = 0,
- WAIT_DECODING,
- WAIT_INITBUF_DONE,
-};
-
-/**
- * enum s5p_mfc_check_state - The state for user notification
- */
-enum s5p_mfc_check_state {
- MFCSTATE_PROCESSING = 0,
- MFCSTATE_DEC_RES_DETECT,
- MFCSTATE_DEC_TERMINATING,
- MFCSTATE_ENC_NO_OUTPUT,
- MFCSTATE_DEC_S3D_REALLOC,
-};
-
-enum mfc_buf_usage_type {
- MFCBUF_INVALID = 0,
- MFCBUF_NORMAL,
- MFCBUF_DRM,
- MFCBUF_NORMAL_FW,
- MFCBUF_DRM_FW,
-};
-
-enum mfc_buf_process_type {
- MFCBUFPROC_DEFAULT = 0x0,
- MFCBUFPROC_COPY = (1 << 0),
- MFCBUFPROC_SHARE = (1 << 1),
- MFCBUFPROC_META = (1 << 2),
- MFCBUFPROC_ANBSHARE = (1 << 3),
- MFCBUFPROC_ANBSHARE_NV12L = (1 << 4),
-};
-
-enum s5p_mfc_ctrl_type {
- MFC_CTRL_TYPE_GET_SRC = 0x1,
- MFC_CTRL_TYPE_GET_DST = 0x2,
- MFC_CTRL_TYPE_SET = 0x4,
-};
-
-enum s5p_mfc_ctrl_mode {
- MFC_CTRL_MODE_NONE = 0x0,
- MFC_CTRL_MODE_SFR = 0x1,
- MFC_CTRL_MODE_CST = 0x2,
-};
-
-struct s5p_mfc_ctx;
-
-enum s5p_mfc_debug_cause {
- MFC_CAUSE_0WRITE_PAGE_FAULT = 0,
- MFC_CAUSE_0READ_PAGE_FAULT = 1,
- MFC_CAUSE_1WRITE_PAGE_FAULT = 2,
- MFC_CAUSE_1READ_PAGE_FAULT = 3,
- MFC_CAUSE_NO_INTERRUPT = 4,
- MFC_CAUSE_NO_SCHEDULING = 5,
- MFC_CAUSE_FAIL_STOP_NAL_Q = 6,
- MFC_CAUSE_FAIL_STOP_NAL_Q_FOR_OTHER = 7,
- MFC_CAUSE_FAIL_CLOSE_INST = 8,
- MFC_CAUSE_FAIL_SLEEP = 9,
- MFC_CAUSE_FAIL_WAKEUP = 10,
- MFC_CAUSE_FAIL_RISC_ON = 11,
- MFC_CAUSE_FAIL_DPB_FLUSH = 12,
- MFC_CAUSE_FAIL_CHACHE_FLUSH = 13,
-};
-
-struct s5p_mfc_debug {
- u32 cause;
- u8 fault_status;
- u32 fault_trans_info;
- u32 fault_addr;
- u8 SFRs_set1[MFC_SFR_LOGGING_COUNT_SET1];
- u32 SFRs_set2[MFC_SFR_LOGGING_COUNT_SET2];
- char errorinfo[MFC_LOGGING_DATA_SIZE];
-};
-
-/**
- * struct s5p_mfc_buf - MFC buffer
- *
- */
-struct s5p_mfc_buf {
- struct vb2_v4l2_buffer vb;
- struct list_head list;
- dma_addr_t addr[MAX_NUM_IMAGES_IN_VB][MFC_MAX_PLANES];
- struct dma_buf *dmabufs[MAX_NUM_IMAGES_IN_VB][MFC_MAX_PLANES];
- struct dma_buf_attachment *attachments[MAX_NUM_IMAGES_IN_VB][MFC_MAX_PLANES];
- int next_index;
- int done_index;
- int used;
- int num_bufs_in_batch;
- int num_valid_bufs;
- unsigned char *vir_addr;
-};
-
-struct s5p_mfc_buf_queue {
- struct list_head head;
- unsigned int count;
-};
-
-struct s5p_mfc_bits {
- unsigned long bits;
- spinlock_t lock;
-};
-
-struct s5p_mfc_hwlock {
- struct list_head waiting_list;
- unsigned int wl_count;
- unsigned long bits;
- unsigned long dev;
- unsigned int owned_by_irq;
- unsigned int transfer_owner;
- spinlock_t lock;
-};
-
-struct s5p_mfc_listable_wq {
- struct list_head list;
- wait_queue_head_t wait_queue;
- struct mutex wait_mutex;
- struct s5p_mfc_dev *dev;
- struct s5p_mfc_ctx *ctx;
-};
-
-struct s5p_mfc_pm {
- struct clk *clock;
- atomic_t pwr_ref;
- struct device *device;
- spinlock_t clklock;
-
- int clock_on_steps;
- int clock_off_steps;
- enum mfc_buf_usage_type base_type;
-};
-
-struct s5p_mfc_fw {
- int date;
- int fimv_info;
- size_t size;
- int status;
- int drm_status;
-};
-
-struct s5p_mfc_ctx_buf_size {
- size_t dev_ctx;
- size_t h264_dec_ctx;
- size_t other_dec_ctx;
- size_t h264_enc_ctx;
- size_t hevc_enc_ctx;
- size_t other_enc_ctx;
- size_t shared_buf;
- size_t dbg_info_buf;
-};
-
-struct s5p_mfc_buf_size {
- size_t firmware_code;
- unsigned int cpb_buf;
- void *ctx_buf;
-};
-
-struct s5p_mfc_variant {
- struct s5p_mfc_buf_size *buf_size;
- int num_entities;
-};
-
-enum mfc_sfr_dump_type {
- MFC_DUMP_NONE = 0,
- MFC_DUMP_DEC_SEQ_START = (1 << 0),
- MFC_DUMP_DEC_INIT_BUFS = (1 << 1),
- MFC_DUMP_DEC_NAL_START = (1 << 2),
- MFC_DUMP_ENC_SEQ_START = (1 << 3),
- MFC_DUMP_ENC_INIT_BUFS = (1 << 4),
- MFC_DUMP_ENC_NAL_START = (1 << 5),
- MFC_DUMP_ERR_INT = (1 << 6),
- MFC_DUMP_WARN_INT = (1 << 7),
-};
-
-struct s5p_mfc_debugfs {
- struct dentry *root;
- struct dentry *mfc_info;
- struct dentry *debug_info;
- struct dentry *debug_level;
- struct dentry *debug_ts;
- struct dentry *dbg_enable;
- struct dentry *nal_q_dump;
- struct dentry *nal_q_disable;
- struct dentry *nal_q_parallel_disable;
- struct dentry *otf_dump;
- struct dentry *perf_measure_option;
- struct dentry *sfr_dump;
- struct dentry *mmcache_dump;
- struct dentry *mmcache_disable;
- struct dentry *perf_boost_mode;
-};
-
-/**
- * struct s5p_mfc_special_buf - represents internal used buffer
- * @daddr: device virtual address
- * @virt: kernel virtual address, only valid when the
- * buffer accessed by driver
- */
-struct s5p_mfc_special_buf {
- enum mfc_buf_usage_type buftype;
- struct dma_buf *dma_buf;
- struct dma_buf_attachment *attachment;
- struct sg_table *sgt;
- dma_addr_t daddr;
- void *vaddr;
- size_t size;
-};
-
-#ifdef CONFIG_MFC_USE_BUS_DEVFREQ
-struct mfc_qos_bw_data {
- unsigned long peak;
- unsigned long read;
- unsigned long write;
-};
-
-struct s5p_mfc_qos_bw {
- struct mfc_qos_bw_data h264_dec_uhd_bw;
- struct mfc_qos_bw_data hevc_dec_uhd_bw;
- struct mfc_qos_bw_data hevc_dec_uhd_10bit_bw;
- struct mfc_qos_bw_data vp8_dec_uhd_bw;
- struct mfc_qos_bw_data vp9_dec_uhd_bw;
- struct mfc_qos_bw_data mpeg4_dec_uhd_bw;
- struct mfc_qos_bw_data h264_enc_uhd_bw;
- struct mfc_qos_bw_data hevc_enc_uhd_bw;
- struct mfc_qos_bw_data hevc_enc_uhd_10bit_bw;
- struct mfc_qos_bw_data vp8_enc_uhd_bw;
- struct mfc_qos_bw_data vp9_enc_uhd_bw;
- struct mfc_qos_bw_data mpeg4_enc_uhd_bw;
-};
-
-/*
- * threshold_mb - threshold of total MB(macroblock) count
- * Total MB count can be calculated by
- * (MB of width) * (MB of height) * fps
- */
-struct s5p_mfc_qos {
- unsigned int threshold_mb;
- unsigned int freq_mfc;
- unsigned int freq_int;
- unsigned int freq_mif;
- unsigned int mo_value;
- unsigned int mo_10bit_value;
- unsigned int mo_uhd_enc60_value;
- unsigned int time_fw;
-};
-
-struct s5p_mfc_qos_boost {
- unsigned int num_cluster;
- unsigned int freq_mfc;
- unsigned int freq_int;
- unsigned int freq_mif;
- unsigned int freq_cluster[MAX_NUM_CLUSTER];
-};
-#endif
-
-struct s5p_mfc_feature {
- unsigned int support;
- unsigned int version;
-};
-
-struct s5p_mfc_platdata {
- /* MFC version */
- unsigned int ip_ver;
- /* Debug mode */
- unsigned int debug_mode;
- /* Sysmmu check */
- unsigned int share_sysmmu;
- unsigned int axid_mask;
- unsigned int mfc_fault_num;
- /* Features */
- struct s5p_mfc_feature nal_q;
- struct s5p_mfc_feature skype;
- struct s5p_mfc_feature black_bar;
- struct s5p_mfc_feature color_aspect_dec;
- struct s5p_mfc_feature static_info_dec;
- struct s5p_mfc_feature color_aspect_enc;
- struct s5p_mfc_feature static_info_enc;
- /* Default 10bit format for decoding */
- unsigned int P010_decoding;
- /* Formats */
- unsigned int support_10bit;
- unsigned int support_422;
- unsigned int support_rgb;
- /* Encoder default parameter */
- unsigned int enc_param_num;
- unsigned int enc_param_addr[MFC_MAX_DEFAULT_PARAM];
- unsigned int enc_param_val[MFC_MAX_DEFAULT_PARAM];
-#ifdef CONFIG_MFC_USE_BUS_DEVFREQ
- /* QoS */
- unsigned int num_qos_steps;
- unsigned int max_qos_steps;
- unsigned int max_mb;
- unsigned int mfc_freq_control;
- unsigned int mo_control;
- unsigned int bw_control;
- struct s5p_mfc_qos *qos_table;
- struct s5p_mfc_qos_boost *qos_boost_table;
-#endif
-};
-
-/************************ NAL_Q data structure ************************/
-#define NAL_Q_IN_ENTRY_SIZE 256
-#define NAL_Q_OUT_ENTRY_SIZE 256
-
-#define NAL_Q_IN_DEC_STR_SIZE 112
-#define NAL_Q_IN_ENC_STR_SIZE 204
-#define NAL_Q_OUT_DEC_STR_SIZE 248
-#define NAL_Q_OUT_ENC_STR_SIZE 64
-
-/* 256*128(max instance 32 * slot 4) = 32 kbytes */
-#define NAL_Q_IN_QUEUE_SIZE 128
-#define NAL_Q_OUT_QUEUE_SIZE 128
-
-typedef struct __DecoderInputStr {
- int StartCode; /* = 0xAAAAAAAA; Decoder input structure marker */
- int CommandId;
- int InstanceId;
- int PictureTag;
- unsigned int CpbBufferAddr;
- int CpbBufferSize;
- int CpbBufferOffset;
- int StreamDataSize;
- int AvailableDpbFlagUpper;
- int AvailableDpbFlagLower;
- int DynamicDpbFlagUpper;
- int DynamicDpbFlagLower;
- unsigned int FrameAddr[3];
- int FrameSize[3];
- int NalStartOptions;
- int FrameStrideSize[3];
- int Frame2BitSize[2];
- int Frame2BitStrideSize[2];
- unsigned int ScratchBufAddr;
- int ScratchBufSize;
- char reserved[NAL_Q_IN_ENTRY_SIZE - NAL_Q_IN_DEC_STR_SIZE];
-} DecoderInputStr; /* 28*4 = 112 bytes */
-
-typedef struct __EncoderInputStr {
- int StartCode; /* 0xBBBBBBBB; Encoder input structure marker */
- int CommandId;
- int InstanceId;
- int PictureTag;
- unsigned int FrameAddr[3];
- unsigned int StreamBufferAddr;
- int StreamBufferSize;
- int StreamBufferOffset;
- int RcRoiCtrl;
- unsigned int RoiBufferAddr;
- int ParamChange;
- int IrSize;
- int GopConfig;
- int RcFrameRate;
- int RcBitRate;
- int MsliceMode;
- int MsliceSizeMb;
- int MsliceSizeBits;
- int FrameInsertion;
- int HierarchicalBitRateLayer[7];
- int H264RefreshPeriod;
- int HevcRefreshPeriod;
- int RcQpBound;
- int RcQpBoundPb;
- int FixedPictureQp;
- int PictureProfile;
- int BitCountEnable;
- int MaxBitCount;
- int MinBitCount;
- int NumTLayer;
- int H264NalControl;
- int HevcNalControl;
- int Vp8NalControl;
- int Vp9NalControl;
- int H264HDSvcExtension0;
- int H264HDSvcExtension1;
- int GopConfig2;
- int Frame2bitAddr[2];
- int Weight;
- int ExtCtbQpAddr;
- int WeightUpper;
- int RcMode;
- char reserved[NAL_Q_IN_ENTRY_SIZE - NAL_Q_IN_ENC_STR_SIZE];
-} EncoderInputStr; /* 51*4 = 204 bytes */
-
-typedef struct __DecoderOutputStr {
- int StartCode; /* 0xAAAAAAAA; Decoder output structure marker */
- int CommandId;
- int InstanceId;
- int ErrorCode;
- int PictureTagTop;
- int PictureTimeTop;
- int DisplayFrameWidth;
- int DisplayFrameHeight;
- int DisplayStatus;
- unsigned int DisplayAddr[3];
- int DisplayFrameType;
- int DisplayCropInfo1;
- int DisplayCropInfo2;
- int DisplayPictureProfile;
- int DisplayAspectRatio;
- int DisplayExtendedAr;
- int DecodedNalSize;
- int UsedDpbFlagUpper;
- int UsedDpbFlagLower;
- int SeiAvail;
- int FramePackArrgmentId;
- int FramePackSeiInfo;
- int FramePackGridPos;
- int DisplayRecoverySeiInfo;
- int H264Info;
- int DisplayFirstCrc;
- int DisplaySecondCrc;
- int DisplayThirdCrc;
- int DisplayFirst2BitCrc;
- int DisplaySecond2BitCrc;
- int DecodedFrameWidth;
- int DecodedFrameHeight;
- int DecodedStatus;
- unsigned int DecodedAddr[3];
- int DecodedFrameType;
- int DecodedCropInfo1;
- int DecodedCropInfo2;
- int DecodedPictureProfile;
- int DecodedRecoverySeiInfo;
- int DecodedFirstCrc;
- int DecodedSecondCrc;
- int DecodedThirdCrc;
- int DecodedFirst2BitCrc;
- int DecodedSecond2BitCrc;
- int PictureTagBot;
- int PictureTimeBot;
- int ChromaFormat;
- int Mpeg4Info;
- int HevcInfo;
- int Vc1Info;
- int VideoSignalType;
- int ContentLightLevelInfoSei;
- int MasteringDisplayColourVolumeSei0;
- int MasteringDisplayColourVolumeSei1;
- int MasteringDisplayColourVolumeSei2;
- int MasteringDisplayColourVolumeSei3;
- int MasteringDisplayColourVolumeSei4;
- int MasteringDisplayColourVolumeSei5;
- char reserved[NAL_Q_OUT_ENTRY_SIZE - NAL_Q_OUT_DEC_STR_SIZE];
-} DecoderOutputStr; /* 62*4 = 248 bytes */
-
-typedef struct __EncoderOutputStr {
- int StartCode; /* 0xBBBBBBBB; Encoder output structure marker */
- int CommandId;
- int InstanceId;
- int ErrorCode;
- int PictureTag;
- unsigned int EncodedFrameAddr[3];
- unsigned int StreamBufferAddr;
- int StreamBufferOffset;
- int StreamSize;
- int SliceType;
- int NalDoneInfo;
- unsigned int ReconLumaDpbAddr;
- unsigned int ReconChromaDpbAddr;
- int EncCnt;
- char reserved[NAL_Q_OUT_ENTRY_SIZE - NAL_Q_OUT_ENC_STR_SIZE];
-} EncoderOutputStr; /* 16*4 = 64 bytes */
-
-/**
- * enum nal_queue_state - The state for nal queue operation.
- */
-typedef enum _nal_queue_state {
- NAL_Q_STATE_CREATED = 0,
- NAL_Q_STATE_STARTED, /* when s5p_mfc_nal_q_start() is called */
- NAL_Q_STATE_STOPPED, /* when s5p_mfc_nal_q_stop() is called */
-} nal_queue_state;
-
-typedef struct _nal_in_queue {
- union {
- DecoderInputStr dec;
- EncoderInputStr enc;
- } entry[NAL_Q_IN_QUEUE_SIZE];
-} nal_in_queue;
-
-typedef struct _nal_out_queue {
- union {
- DecoderOutputStr dec;
- EncoderOutputStr enc;
- } entry[NAL_Q_OUT_QUEUE_SIZE];
-} nal_out_queue;
-
-struct _nal_queue_handle;
-typedef struct _nal_queue_in_handle {
- struct _nal_queue_handle *nal_q_handle;
- struct s5p_mfc_special_buf in_buf;
- unsigned int in_exe_count;
- nal_in_queue *nal_q_in_addr;
-} nal_queue_in_handle;
-
-typedef struct _nal_queue_out_handle {
- struct _nal_queue_handle *nal_q_handle;
- struct s5p_mfc_special_buf out_buf;
- unsigned int out_exe_count;
- nal_out_queue *nal_q_out_addr;
- int nal_q_ctx;
-} nal_queue_out_handle;
-
-typedef struct _nal_queue_handle {
- nal_queue_in_handle *nal_q_in_handle;
- nal_queue_out_handle *nal_q_out_handle;
- nal_queue_state nal_q_state;
- unsigned int nal_q_clk_cnt;
- spinlock_t lock;
- int nal_q_exception;
-} nal_queue_handle;
-
-/************************ OTF data structure ************************/
-struct _otf_buf_addr {
- dma_addr_t otf_daddr[HWFC_MAX_BUF][3];
- struct dma_buf_attachment *otf_buf_attach[HWFC_MAX_BUF];
-};
-
-struct _otf_buf_info {
- int pixel_format;
- int width;
- int height;
- int buffer_count;
- struct dma_buf *bufs[HWFC_MAX_BUF];
-};
-
-struct _otf_debug {
- struct s5p_mfc_special_buf stream_buf[OTF_MAX_BUF];
- unsigned int stream_size[OTF_MAX_BUF];
- unsigned char frame_cnt;
-};
-
-struct _otf_handle {
- int otf_work_bit;
- int otf_buf_index;
- int otf_job_id;
- u64 otf_time_stamp;
- struct _otf_buf_addr otf_buf_addr;
- struct _otf_buf_info otf_buf_info;
- struct _otf_debug otf_debug;
-};
-/********************************************************************/
-
-struct s5p_mfc_perf {
- void __iomem *regs_base0;
- void __iomem *regs_base1;
-
- struct timeval begin;
- struct timeval end;
-
- int new_start;
- int count;
- int drv_margin;
-};
-
-extern struct s5p_mfc_dump_ops mfc_dump_ops;
-struct s5p_mfc_dump_ops {
- void (*dump_regs)(struct s5p_mfc_dev *dev);
- void (*dump_info)(struct s5p_mfc_dev *dev);
- void (*dump_info_without_regs)(struct s5p_mfc_dev *dev);
- void (*dump_and_stop_always)(struct s5p_mfc_dev *dev);
- void (*dump_and_stop_debug_mode)(struct s5p_mfc_dev *dev);
-};
-
-struct s5p_mfc_mmcache {
- void __iomem *base;
- int is_on_status;
-};
-
-/**
- * struct s5p_mfc_dev - The struct containing driver internal parameters.
- */
-struct s5p_mfc_dev {
- struct v4l2_device v4l2_dev;
- struct video_device *vfd_dec;
- struct video_device *vfd_enc;
- struct video_device *vfd_dec_drm;
- struct video_device *vfd_enc_drm;
- struct video_device *vfd_enc_otf;
- struct video_device *vfd_enc_otf_drm;
- struct device *device;
-
- void __iomem *regs_base;
- void __iomem *sysmmu0_base;
- void __iomem *sysmmu1_base;
- void __iomem *hwfc_base;
-
- int irq;
- struct resource *mfc_mem;
-
- struct s5p_mfc_pm pm;
- struct s5p_mfc_fw fw;
- struct s5p_mfc_variant *variant;
- struct s5p_mfc_platdata *pdata;
- struct s5p_mfc_debug *logging_data;
-
- int num_inst;
-
- struct mutex mfc_mutex;
-
- int int_condition;
- int int_reason;
- unsigned int int_err;
-
- wait_queue_head_t cmd_wq;
- struct s5p_mfc_listable_wq hwlock_wq;
-
- bool has_2sysmmu;
- bool has_hwfc;
- bool has_mmcache;
-
- struct s5p_mfc_special_buf common_ctx_buf;
- struct s5p_mfc_special_buf drm_common_ctx_buf;
-
- struct s5p_mfc_ctx *ctx[MFC_NUM_CONTEXTS];
- int curr_ctx;
- int preempt_ctx;
-
- struct s5p_mfc_bits work_bits;
-
- struct s5p_mfc_hwlock hwlock;
-
- atomic_t sched_wait_cnt;
- atomic_t watchdog_tick_running;
- atomic_t watchdog_tick_cnt;
- atomic_t watchdog_run;
- struct timer_list watchdog_timer;
- struct workqueue_struct *watchdog_wq;
- struct work_struct watchdog_work;
-
- /* for DRM */
- int curr_ctx_is_drm;
- int num_drm_inst;
- struct s5p_mfc_special_buf fw_buf;
- struct s5p_mfc_special_buf drm_fw_buf;
-
- struct workqueue_struct *butler_wq;
- struct work_struct butler_work;
-
-#ifdef CONFIG_MFC_USE_BUS_DEVFREQ
- struct list_head qos_queue;
- atomic_t qos_req_cur;
- struct pm_qos_request qos_req_mfc;
- struct pm_qos_request qos_req_int;
- struct pm_qos_request qos_req_mif;
- struct pm_qos_request qos_req_cluster[MAX_NUM_CLUSTER];
- int qos_has_enc_ctx;
-#endif
- int id;
- atomic_t clk_ref;
-
- atomic_t trace_ref;
- struct _mfc_trace *mfc_trace;
- atomic_t trace_ref_hwlock;
- struct _mfc_trace *mfc_trace_hwlock;
- bool continue_clock_on;
-
- bool shutdown;
- bool sleep;
-
- nal_queue_handle *nal_q_handle;
-
- struct s5p_mfc_special_buf dbg_info_buf;
-
-#ifdef CONFIG_EXYNOS_BTS
- struct bts_bw mfc_bw;
-#endif
-
- struct s5p_mfc_debugfs debugfs;
- struct s5p_mfc_dump_ops *dump_ops;
-
- struct s5p_mfc_perf perf;
-
- struct s5p_mfc_mmcache mmcache;
-
-#ifdef CONFIG_EXYNOS_ITMON
- struct notifier_block itmon_nb;
- int itmon_notified;
-#endif
-};
-
-/**
- *
- */
-struct s5p_mfc_h264_enc_params {
- enum v4l2_mpeg_video_h264_profile profile;
- u8 level;
- u8 interlace;
- enum v4l2_mpeg_video_h264_loop_filter_mode loop_filter_mode;
- s8 loop_filter_alpha;
- s8 loop_filter_beta;
- enum v4l2_mpeg_video_h264_entropy_mode entropy_mode;
- u8 _8x8_transform;
- u8 rc_frame_qp;
- u8 rc_min_qp;
- u8 rc_max_qp;
- u8 rc_min_qp_p;
- u8 rc_max_qp_p;
- u8 rc_min_qp_b;
- u8 rc_max_qp_b;
- u8 rc_mb_dark;
- u8 rc_mb_smooth;
- u8 rc_mb_static;
- u8 rc_mb_activity;
- u8 rc_p_frame_qp;
- u8 rc_b_frame_qp;
- u8 ar_vui;
- enum v4l2_mpeg_video_h264_vui_sar_idc ar_vui_idc;
- u16 ext_sar_width;
- u16 ext_sar_height;
- u8 open_gop;
- u16 open_gop_size;
- u8 hier_qp_enable;
- enum v4l2_mpeg_video_h264_hierarchical_coding_type hier_qp_type;
- u8 num_hier_layer;
- u8 hier_ref_type;
- u8 hier_qp_layer[7];
- u32 hier_bit_layer[7];
- u8 sei_gen_enable;
- u8 sei_fp_curr_frame_0;
- enum v4l2_mpeg_video_h264_sei_fp_arrangement_type sei_fp_arrangement_type;
- u32 fmo_enable;
- u32 fmo_slice_map_type;
- u32 fmo_slice_num_grp;
- u32 fmo_run_length[4];
- u32 fmo_sg_dir;
- u32 fmo_sg_rate;
- u32 aso_enable;
- u32 aso_slice_order[8];
-
- u32 prepend_sps_pps_to_idr;
- u8 enable_ltr;
- u8 num_of_ltr;
- u32 set_priority;
- u32 base_priority;
- u32 vui_enable;
-};
-
-/**
- *
- */
-struct s5p_mfc_mpeg4_enc_params {
- /* MPEG4 Only */
- enum v4l2_mpeg_video_mpeg4_profile profile;
- u8 level;
- u8 quarter_pixel;
- u16 vop_time_res;
- u16 vop_frm_delta;
- u8 rc_b_frame_qp;
- /* Common for MPEG4, H263 */
- u8 rc_frame_qp;
- u8 rc_min_qp;
- u8 rc_max_qp;
- u8 rc_min_qp_p;
- u8 rc_max_qp_p;
- u8 rc_min_qp_b;
- u8 rc_max_qp_b;
- u8 rc_p_frame_qp;
-};
-
-/**
- *
- */
-struct s5p_mfc_vp9_enc_params {
- /* VP9 Only */
- u8 vp9_version;
- u8 rc_min_qp;
- u8 rc_max_qp;
- u8 rc_min_qp_p;
- u8 rc_max_qp_p;
- u8 rc_frame_qp;
- u8 rc_p_frame_qp;
- u8 vp9_goldenframesel;
- u16 vp9_gfrefreshperiod;
- u8 hier_qp_enable;
- u8 hier_qp_layer[3];
- u32 hier_bit_layer[3];
- u8 num_hier_layer;
- u8 max_partition_depth;
- u8 intra_pu_split_disable;
- u8 profile;
-};
-
-/**
- *
- */
-struct s5p_mfc_vp8_enc_params {
- /* VP8 Only */
- u8 vp8_version;
- u8 rc_min_qp;
- u8 rc_max_qp;
- u8 rc_min_qp_p;
- u8 rc_max_qp_p;
- u8 rc_frame_qp;
- u8 rc_p_frame_qp;
- u8 vp8_numberofpartitions;
- u8 vp8_filterlevel;
- u8 vp8_filtersharpness;
- u8 vp8_goldenframesel;
- u16 vp8_gfrefreshperiod;
- u8 hier_qp_enable;
- u8 hier_qp_layer[3];
- u32 hier_bit_layer[3];
- u8 intra_4x4mode_disable;
- u8 num_hier_layer;
-};
-
-/**
- *
- */
-struct s5p_mfc_hevc_enc_params {
- u8 profile;
- u8 level;
- u8 tier_flag;
- /* HEVC Only */
- u8 rc_min_qp;
- u8 rc_max_qp;
- u8 rc_min_qp_p;
- u8 rc_max_qp_p;
- u8 rc_min_qp_b;
- u8 rc_max_qp_b;
- u8 rc_lcu_dark;
- u8 rc_lcu_smooth;
- u8 rc_lcu_static;
- u8 rc_lcu_activity;
- u8 rc_frame_qp;
- u8 rc_p_frame_qp;
- u8 rc_b_frame_qp;
- u8 max_partition_depth;
- u8 refreshtype;
- u16 refreshperiod;
- s32 lf_beta_offset_div2;
- s32 lf_tc_offset_div2;
- u8 loopfilter_disable;
- u8 loopfilter_across;
- u8 nal_control_length_filed;
- u8 nal_control_user_ref;
- u8 nal_control_store_ref;
- u8 const_intra_period_enable;
- u8 lossless_cu_enable;
- u8 wavefront_enable;
- u8 enable_ltr;
- u8 hier_qp_enable;
- enum v4l2_mpeg_video_hevc_hierarchical_coding_type hier_qp_type;
- u8 hier_ref_type;
- u8 num_hier_layer;
- u8 hier_qp_layer[7];
- u32 hier_bit_layer[7];
- u8 general_pb_enable;
- u8 temporal_id_enable;
- u8 strong_intra_smooth;
- u8 intra_pu_split_disable;
- u8 tmv_prediction_disable;
- u8 max_num_merge_mv;
- u8 eco_mode_enable;
- u8 encoding_nostartcode_enable;
- u8 size_of_length_field;
- u8 user_ref;
- u8 store_ref;
- u8 prepend_sps_pps_to_idr;
-};
-
-/**
- *
- */
-struct s5p_mfc_bpg_enc_params {
- u32 thumb_size;
- u32 exif_size;
-};
-
-/**
- *
- */
-struct s5p_mfc_enc_params {
- u16 width;
- u16 height;
-
- u32 gop_size;
- enum v4l2_mpeg_video_multi_slice_mode slice_mode;
- u32 slice_mb;
- u32 slice_bit;
- u32 slice_mb_row;
- u32 intra_refresh_mb;
- u8 pad;
- u8 pad_luma;
- u8 pad_cb;
- u8 pad_cr;
- u8 rc_frame;
- u32 rc_bitrate;
- u32 rc_framerate;
- u16 rc_reaction_coeff;
- u32 config_qp;
- u32 dynamic_qp;
- u8 frame_tag;
- u8 ratio_intra;
-
- u8 num_b_frame; /* H.264, HEVC, MPEG4 */
- u8 num_refs_for_p; /* H.264, HEVC, VP8, VP9 */
- u8 rc_mb; /* H.264: MFCv5, MPEG4/H.263: MFCv6 */
- u8 rc_pvc;
- u16 vbv_buf_size;
- enum v4l2_mpeg_video_header_mode seq_hdr_mode;
- enum v4l2_mpeg_mfc51_video_frame_skip_mode frame_skip_mode;
- u8 fixed_target_bit;
- u8 num_hier_max_layer;
- u8 hier_bitrate_ctrl;
- u8 weighted_enable;
- u8 roi_enable;
- u8 ivf_header_disable; /* VP8, VP9 */
-
- u16 rc_frame_delta; /* MFC6.1 Only */
-
- u32 i_frm_ctrl_mode;
- u32 i_frm_ctrl;
-
- u32 check_color_range;
- u32 color_range;
- u32 colour_primaries;
- u32 transfer_characteristics;
- u32 matrix_coefficients;
-
- u32 static_info_enable;
- u32 max_pic_average_light;
- u32 max_content_light;
- u32 max_display_luminance;
- u32 min_display_luminance;
- u32 white_point;
- u32 display_primaries_0;
- u32 display_primaries_1;
- u32 display_primaries_2;
-
- union {
- struct s5p_mfc_h264_enc_params h264;
- struct s5p_mfc_mpeg4_enc_params mpeg4;
- struct s5p_mfc_vp8_enc_params vp8;
- struct s5p_mfc_vp9_enc_params vp9;
- struct s5p_mfc_hevc_enc_params hevc;
- struct s5p_mfc_bpg_enc_params bpg;
- } codec;
-};
-
-struct s5p_mfc_ctx_ctrl {
- struct list_head list;
- enum s5p_mfc_ctrl_type type;
- unsigned int id;
- unsigned int addr;
- int has_new;
- int val;
-};
-
-struct s5p_mfc_buf_ctrl {
- struct list_head list;
- unsigned int id;
- enum s5p_mfc_ctrl_type type;
- int has_new;
- int val;
- unsigned int old_val; /* only for MFC_CTRL_TYPE_SET */
- unsigned int old_val2; /* only for MFC_CTRL_TYPE_SET */
- unsigned int is_volatile; /* only for MFC_CTRL_TYPE_SET */
- unsigned int updated;
- unsigned int mode;
- unsigned int addr;
- unsigned int mask;
- unsigned int shft;
- unsigned int flag_mode; /* only for MFC_CTRL_TYPE_SET */
- unsigned int flag_addr; /* only for MFC_CTRL_TYPE_SET */
- unsigned int flag_shft; /* only for MFC_CTRL_TYPE_SET */
- int (*read_cst) (struct s5p_mfc_ctx *ctx,
- struct s5p_mfc_buf_ctrl *buf_ctrl);
- void (*write_cst) (struct s5p_mfc_ctx *ctx,
- struct s5p_mfc_buf_ctrl *buf_ctrl);
-};
-
-struct s5p_mfc_ctrl_cfg {
- enum s5p_mfc_ctrl_type type;
- unsigned int id;
- unsigned int is_volatile; /* only for MFC_CTRL_TYPE_SET */
- unsigned int mode;
- unsigned int addr;
- unsigned int mask;
- unsigned int shft;
- unsigned int flag_mode; /* only for MFC_CTRL_TYPE_SET */
- unsigned int flag_addr; /* only for MFC_CTRL_TYPE_SET */
- unsigned int flag_shft; /* only for MFC_CTRL_TYPE_SET */
- int (*read_cst) (struct s5p_mfc_ctx *ctx,
- struct s5p_mfc_buf_ctrl *buf_ctrl);
- void (*write_cst) (struct s5p_mfc_ctx *ctx,
- struct s5p_mfc_buf_ctrl *buf_ctrl);
-};
-
-/* per buffer contol */
-struct s5p_mfc_ctrls_ops {
- /* controls per buffer */
- int (*init_ctx_ctrls) (struct s5p_mfc_ctx *ctx);
- int (*cleanup_ctx_ctrls) (struct s5p_mfc_ctx *ctx);
- int (*init_buf_ctrls) (struct s5p_mfc_ctx *ctx,
- enum s5p_mfc_ctrl_type type, unsigned int index);
- void (*reset_buf_ctrls) (struct list_head *head);
- int (*cleanup_buf_ctrls) (struct s5p_mfc_ctx *ctx,
- enum s5p_mfc_ctrl_type type, unsigned int index);
- int (*to_buf_ctrls) (struct s5p_mfc_ctx *ctx, struct list_head *head);
- int (*to_ctx_ctrls) (struct s5p_mfc_ctx *ctx, struct list_head *head);
- int (*set_buf_ctrls_val) (struct s5p_mfc_ctx *ctx,
- struct list_head *head);
- int (*get_buf_ctrls_val) (struct s5p_mfc_ctx *ctx,
- struct list_head *head);
- int (*recover_buf_ctrls_val) (struct s5p_mfc_ctx *ctx,
- struct list_head *head);
- int (*get_buf_update_val) (struct s5p_mfc_ctx *ctx,
- struct list_head *head, unsigned int id, int value);
- int (*set_buf_ctrls_val_nal_q_dec) (struct s5p_mfc_ctx *ctx,
- struct list_head *head, DecoderInputStr *pInStr);
- int (*get_buf_ctrls_val_nal_q_dec) (struct s5p_mfc_ctx *ctx,
- struct list_head *head, DecoderOutputStr *pOutStr);
- int (*set_buf_ctrls_val_nal_q_enc) (struct s5p_mfc_ctx *ctx,
- struct list_head *head, EncoderInputStr *pInStr);
- int (*get_buf_ctrls_val_nal_q_enc) (struct s5p_mfc_ctx *ctx,
- struct list_head *head, EncoderOutputStr *pOutStr);
- int (*recover_buf_ctrls_nal_q) (struct s5p_mfc_ctx *ctx,
- struct list_head *head);
-};
-
-struct stored_dpb_info {
- int fd[MFC_MAX_PLANES];
-};
-
-struct dec_dpb_ref_info {
- int index;
- struct stored_dpb_info dpb[MFC_MAX_DPBS];
-};
-
-struct temporal_layer_info {
- unsigned int temporal_layer_count;
- unsigned int temporal_layer_bitrate[VIDEO_MAX_TEMPORAL_LAYERS];
-};
-
-struct mfc_enc_roi_info {
- char *addr;
- int size;
- int upper_qp;
- int lower_qp;
- bool enable;
-};
-
-struct mfc_user_shared_handle {
- int fd;
- struct dma_buf *dma_buf;
- void *vaddr;
-};
-
-struct s5p_mfc_raw_info {
- int num_planes;
- int stride[3];
- int plane_size[3];
- int stride_2bits[3];
- int plane_size_2bits[3];
- unsigned int total_plane_size;
-};
-
-struct mfc_timestamp {
- struct list_head list;
- struct timeval timestamp;
- int index;
- int interval;
-};
-
-struct s5p_mfc_dec {
- int total_dpb_count;
-
- unsigned int src_buf_size;
-
- int loop_filter_mpeg4;
- int display_delay;
- int immediate_display;
- int slice_enable;
- int mv_count;
- int idr_decoding;
- int is_interlaced;
- int is_dts_mode;
-
- int crc_enable;
- int crc_luma0;
- int crc_chroma0;
- int crc_luma1;
- int crc_chroma1;
-
- unsigned long consumed;
- unsigned long remained_size;
-
- enum v4l2_memory dst_memtype;
- int sei_parse;
- int stored_tag;
- dma_addr_t y_addr_for_pb;
-
- int cr_left, cr_right, cr_top, cr_bot;
-
- int detect_black_bar;
- bool black_bar_updated;
- struct v4l2_rect black_bar;
-
- /* For dynamic DPB */
- int is_dynamic_dpb;
- unsigned long available_dpb;
- unsigned int dynamic_set;
- unsigned int dynamic_used;
-
- struct dec_dpb_ref_info *ref_info;
- int assigned_fd[MFC_MAX_DPBS];
- struct mfc_user_shared_handle sh_handle;
- struct s5p_mfc_buf *assigned_dpb[MFC_MAX_DPBS];
-
- int has_multiframe;
- int is_dpb_full;
-
- unsigned int err_reuse_flag;
- unsigned int dec_only_release_flag;
-
- /* for debugging about black bar detection */
- void *frame_vaddr[3][30];
- dma_addr_t frame_daddr[3][30];
- int index[3][30];
- int fd[3][30];
- unsigned int frame_size[3][30];
- unsigned char frame_cnt;
-
- unsigned int num_of_tile_over_4;
-
- unsigned int color_range;
- unsigned int color_space;
-};
-
-struct s5p_mfc_enc {
- struct s5p_mfc_enc_params params;
-
- unsigned int dst_buf_size;
- unsigned int header_size;
-
- enum v4l2_mpeg_mfc51_video_frame_type frame_type;
- enum v4l2_mpeg_mfc51_video_force_frame_type force_frame_type;
-
- size_t luma_dpb_size;
- size_t chroma_dpb_size;
- size_t me_buffer_size;
- size_t tmv_buffer_size;
-
- unsigned int slice_mode;
- union {
- unsigned int mb;
- unsigned int bits;
- } slice_size;
- unsigned int in_slice;
- unsigned int buf_full;
-
- int stored_tag;
- struct mfc_user_shared_handle sh_handle_svc;
- struct mfc_user_shared_handle sh_handle_roi;
- int roi_index;
- struct s5p_mfc_special_buf roi_buf[MFC_MAX_EXTRA_BUF];
- struct mfc_enc_roi_info roi_info[MFC_MAX_EXTRA_BUF];
-};
-
-struct s5p_mfc_fmt {
- char *name;
- u32 fourcc;
- u32 codec_mode;
- u32 type;
- u32 num_planes;
- u32 mem_planes;
-};
-
-/**
- * struct s5p_mfc_ctx - This struct contains the instance context
- */
-struct s5p_mfc_ctx {
- struct s5p_mfc_dev *dev;
- struct v4l2_fh fh;
- int num;
-
- int int_condition;
- int int_reason;
- unsigned int int_err;
-
- wait_queue_head_t cmd_wq;
- struct s5p_mfc_listable_wq hwlock_wq;
-
- struct s5p_mfc_fmt *src_fmt;
- struct s5p_mfc_fmt *dst_fmt;
-
- struct vb2_queue vq_src;
- struct vb2_queue vq_dst;
-
- struct s5p_mfc_buf_queue src_buf_queue;
- struct s5p_mfc_buf_queue dst_buf_queue;
- struct s5p_mfc_buf_queue src_buf_nal_queue;
- struct s5p_mfc_buf_queue dst_buf_nal_queue;
- struct s5p_mfc_buf_queue ref_buf_queue;
- spinlock_t buf_queue_lock;
-
- enum s5p_mfc_inst_type type;
- enum s5p_mfc_inst_state state;
- int inst_no;
-
- int img_width;
- int img_height;
- int crop_width;
- int crop_height;
- int crop_left;
- int crop_top;
- int dpb_count;
- int buf_stride;
-
- int min_dpb_size[3];
-
- struct s5p_mfc_raw_info raw_buf;
- size_t mv_size;
-
- struct s5p_mfc_special_buf codec_buf;
- int codec_buffer_allocated;
-
- enum s5p_mfc_queue_state capture_state;
- enum s5p_mfc_queue_state output_state;
-
- struct list_head ctrls;
-
- struct list_head src_ctrls[MFC_MAX_BUFFERS];
- struct list_head dst_ctrls[MFC_MAX_BUFFERS];
-
- unsigned long src_ctrls_avail;
- unsigned long dst_ctrls_avail;
-
- unsigned int sequence;
-
- /* Control values */
- int codec_mode;
- __u32 pix_format;
-
- /* Extra Buffers */
- struct s5p_mfc_special_buf instance_ctx_buf;
-
- struct s5p_mfc_dec *dec_priv;
- struct s5p_mfc_enc *enc_priv;
-
- struct s5p_mfc_ctrls_ops *c_ops;
-
- size_t scratch_buf_size;
- size_t loopfilter_luma_size;
- size_t loopfilter_chroma_size;
-
- /* Profile infomation */
- int is_10bit;
- int is_422;
-
- /* for DRM */
- int is_drm;
-
- int is_dpb_realloc;
- enum mfc_dec_wait_state wait_state;
- int clear_work_bit;
-
-#ifdef CONFIG_MFC_USE_BUS_DEVFREQ
- int qos_req_step;
- struct list_head qos_list;
-#endif
- unsigned int qos_ratio;
- unsigned long framerate;
- unsigned long last_framerate;
-
- struct mfc_timestamp ts_array[MFC_TIME_INDEX];
- struct list_head ts_list;
- int ts_count;
- int ts_is_full;
-
- int buf_process_type;
-
- unsigned long raw_protect_flag;
- unsigned long stream_protect_flag;
- struct _otf_handle *otf_handle;
-
- int batch_mode;
- bool check_dump;
-};
-
-#endif /* __S5P_MFC_DATA_STRUCT_H */
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_debug.h
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __S5P_MFC_DEBUG_H
-#define __S5P_MFC_DEBUG_H __FILE__
-
-#define DEBUG
-
-#ifdef DEBUG
-
-extern unsigned int debug_level;
-extern unsigned int debug_ts;
-extern unsigned int dbg_enable;
-extern unsigned int nal_q_dump;
-extern unsigned int nal_q_disable;
-extern unsigned int nal_q_parallel_disable;
-extern unsigned int otf_dump;
-extern unsigned int sfr_dump;
-extern unsigned int mmcache_dump;
-extern unsigned int mmcache_disable;
-extern unsigned int perf_boost_mode;
-
-#define mfc_debug(level, fmt, args...) \
- do { \
- if (debug_level >= level) \
- printk(KERN_DEBUG "%s:%d: " fmt, \
- __func__, __LINE__, ##args); \
- } while (0)
-#else
-#define mfc_debug(fmt, args...)
-#endif
-
-#define mfc_debug_enter() mfc_debug(5, "enter\n")
-#define mfc_debug_leave() mfc_debug(5, "leave\n")
-
-#define mfc_err_dev(fmt, args...) \
- do { \
- printk(KERN_ERR "%s:%d: " fmt, \
- __func__, __LINE__, ##args); \
- } while (0)
-
-#define mfc_err_ctx(fmt, args...) \
- do { \
- printk(KERN_ERR "[c:%d] %s:%d: " fmt, \
- ctx->num, \
- __func__, __LINE__, ##args); \
- } while (0)
-
-#define mfc_info_dev(fmt, args...) \
- do { \
- printk(KERN_INFO "%s:%d: " fmt, \
- __func__, __LINE__, ##args); \
- } while (0)
-
-#define mfc_info_ctx(fmt, args...) \
- do { \
- printk(KERN_INFO "[c:%d] %s:%d: " fmt, \
- ctx->num, \
- __func__, __LINE__, ##args); \
- } while (0)
-
-#define MFC_TRACE_STR_LEN 80
-#define MFC_TRACE_COUNT_MAX 1024
-#define MFC_TRACE_COUNT_PRINT 30
-
-struct _mfc_trace {
- unsigned long long time;
- char str[MFC_TRACE_STR_LEN];
-};
-
-/* If there is no ctx structure */
-#define MFC_TRACE_DEV(fmt, args...) \
- do { \
- int cpu = raw_smp_processor_id(); \
- int cnt; \
- cnt = atomic_inc_return(&dev->trace_ref) & (MFC_TRACE_COUNT_MAX - 1); \
- dev->mfc_trace[cnt].time = cpu_clock(cpu); \
- snprintf(dev->mfc_trace[cnt].str, MFC_TRACE_STR_LEN, \
- fmt, ##args); \
- } while (0)
-
-/* If there is ctx structure */
-#define MFC_TRACE_CTX(fmt, args...) \
- do { \
- int cpu = raw_smp_processor_id(); \
- int cnt; \
- cnt = atomic_inc_return(&dev->trace_ref) & (MFC_TRACE_COUNT_MAX - 1); \
- dev->mfc_trace[cnt].time = cpu_clock(cpu); \
- snprintf(dev->mfc_trace[cnt].str, MFC_TRACE_STR_LEN, \
- "[c:%d] " fmt, ctx->num, ##args); \
- } while (0)
-
-
-/* If there is no ctx structure */
-#define MFC_TRACE_DEV_HWLOCK(fmt, args...) \
- do { \
- int cpu = raw_smp_processor_id(); \
- int cnt; \
- cnt = atomic_inc_return(&dev->trace_ref_hwlock) & (MFC_TRACE_COUNT_MAX - 1); \
- dev->mfc_trace_hwlock[cnt].time = cpu_clock(cpu); \
- snprintf(dev->mfc_trace_hwlock[cnt].str, MFC_TRACE_STR_LEN, \
- fmt, ##args); \
- } while (0)
-
-/* If there is ctx structure */
-#define MFC_TRACE_CTX_HWLOCK(fmt, args...) \
- do { \
- int cpu = raw_smp_processor_id(); \
- int cnt; \
- cnt = atomic_inc_return(&dev->trace_ref_hwlock) & (MFC_TRACE_COUNT_MAX - 1); \
- dev->mfc_trace_hwlock[cnt].time = cpu_clock(cpu); \
- snprintf(dev->mfc_trace_hwlock[cnt].str, MFC_TRACE_STR_LEN, \
- "[c:%d] " fmt, ctx->num, ##args); \
- } while (0)
-
-
-#endif /* __S5P_MFC_DEBUG_H */
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_debug.c
- *
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-
-#include "s5p_mfc_debugfs.h"
-#include "s5p_mfc_sync.h"
-
-#include "s5p_mfc_pm.h"
-
-#include "s5p_mfc_queue.h"
-
-unsigned int debug_level;
-unsigned int debug_ts;
-unsigned int dbg_enable;
-unsigned int nal_q_dump;
-unsigned int nal_q_disable;
-unsigned int nal_q_parallel_disable;
-unsigned int otf_dump;
-unsigned int perf_measure_option;
-unsigned int sfr_dump;
-unsigned int mmcache_dump;
-unsigned int mmcache_disable;
-unsigned int perf_boost_mode;
-
-static int mfc_info_show(struct seq_file *s, void *unused)
-{
- struct s5p_mfc_dev *dev = s->private;
- struct s5p_mfc_ctx *ctx = NULL;
- int i;
- char *codec_name = NULL;
-
- seq_puts(s, ">> MFC device information(common)\n");
- seq_printf(s, "[VERSION] H/W: v%x.%x, F/W: %06x(%c), DRV: %d\n",
- MFC_VER_MAJOR(dev), MFC_VER_MINOR(dev), dev->fw.date,
- dev->fw.fimv_info, MFC_DRIVER_INFO);
- seq_printf(s, "[PM] power: %d, clock: %d\n",
- s5p_mfc_pm_get_pwr_ref_cnt(dev), s5p_mfc_pm_get_clk_ref_cnt(dev));
- seq_printf(s, "[CTX] num_inst: %d, num_drm_inst: %d, curr_ctx: %d(is_drm: %d)\n",
- dev->num_inst, dev->num_drm_inst, dev->curr_ctx, dev->curr_ctx_is_drm);
- seq_printf(s, "[HWLOCK] bits: %#lx, dev: %#lx, owned_by_irq = %d, wl_count = %d\n",
- dev->hwlock.bits, dev->hwlock.dev,
- dev->hwlock.owned_by_irq, dev->hwlock.wl_count);
- seq_printf(s, "[DEBUG MODE] %s\n", dev->pdata->debug_mode ? "enabled" : "disabled");
- seq_printf(s, "[MMCACHE] %s(%s)\n",
- dev->has_mmcache ? "supported" : "not supported",
- dev->mmcache.is_on_status ? "enabled" : "disabled");
- seq_printf(s, "[PERF BOOST] %s\n", perf_boost_mode ? "enabled" : "disabled");
- seq_printf(s, "[FEATURES] nal_q: %d(0x%x), skype: %d(0x%x), black_bar: %d(0x%x)\n",
- dev->pdata->nal_q.support, dev->pdata->nal_q.version,
- dev->pdata->skype.support, dev->pdata->skype.version,
- dev->pdata->black_bar.support, dev->pdata->black_bar.version);
- seq_printf(s, " color_aspect_dec: %d(0x%x), enc: %d(0x%x)\n",
- dev->pdata->color_aspect_dec.support, dev->pdata->color_aspect_dec.version,
- dev->pdata->color_aspect_enc.support, dev->pdata->color_aspect_enc.version);
- seq_printf(s, " static_info_dec: %d(0x%x), enc: %d(0x%x)\n",
- dev->pdata->static_info_dec.support, dev->pdata->static_info_dec.version,
- dev->pdata->static_info_enc.support, dev->pdata->static_info_enc.version);
- seq_printf(s, "[FORMATS] 10bit: %s, 422: %s, RGB: %s\n",
- dev->pdata->support_10bit ? "supported" : "not supported",
- dev->pdata->support_422 ? "supported" : "not supported",
- dev->pdata->support_rgb ? "supported" : "not supported");
- seq_printf(s, "[LOWMEM] is_low_mem: %d\n", IS_LOW_MEM);
- if (dev->nal_q_handle)
- seq_printf(s, "[NAL-Q] state: %d\n", dev->nal_q_handle->nal_q_state);
-
- seq_puts(s, ">> MFC device information(instance)\n");
- for (i = 0; i < MFC_NUM_CONTEXTS; i++) {
- ctx = dev->ctx[i];
- if (ctx) {
- if (ctx->type == MFCINST_DECODER)
- codec_name = ctx->src_fmt->name;
- else
- codec_name = ctx->dst_fmt->name;
-
- seq_printf(s, "[CTX:%d] codec: %s(%s), width: %d, height: %d, crop: %d %d %d %d, state: %d\n",
- ctx->num, ctx->type == MFCINST_DECODER ? "DEC" : "ENC", codec_name,
- ctx->img_width, ctx->img_height, ctx->crop_width, ctx->crop_height,
- ctx->crop_left, ctx->crop_top, ctx->state);
- seq_printf(s, " queue(src: %d, dst: %d, src_nal: %d, dst_nal: %d, ref: %d)\n",
- s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->src_buf_queue),
- s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->dst_buf_queue),
- s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->src_buf_nal_queue),
- s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->dst_buf_nal_queue),
- s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->ref_buf_queue));
- }
- }
-
- return 0;
-}
-
-static int mfc_debug_info_show(struct seq_file *s, void *unused)
-{
- seq_puts(s, ">> MFC debug information\n");
-
- seq_puts(s, "-----SFR dump options (bit setting)\n");
- seq_puts(s, "ex) echo 0xff > /d/mfc/sfr_dump (all dump mode)\n");
- seq_puts(s, "1 (1 << 0): dec SEQ_START\n");
- seq_puts(s, "2 (1 << 1): dec INIT_BUFS\n");
- seq_puts(s, "4 (1 << 2): dec NAL_START\n");
- seq_puts(s, "8 (1 << 3): enc SEQ_START\n");
- seq_puts(s, "16 (1 << 4): enc INIT_BUFS\n");
- seq_puts(s, "32 (1 << 5): enc NAL_START\n");
- seq_puts(s, "64 (1 << 6): ERR interrupt\n");
- seq_puts(s, "128 (1 << 7): WARN interrupt\n");
-
- seq_puts(s, "-----Performance boost options (bit setting)\n");
- seq_puts(s, "ex) echo 7 > /d/mfc/perf_boost_mode (max freq)\n");
- seq_puts(s, "1 (1 << 0): DVFS (INT/MFC/MIF)\n");
- seq_puts(s, "2 (1 << 1): MO value\n");
- seq_puts(s, "4 (1 << 2): CPU frequency\n");
-
- return 0;
-}
-
-static int mfc_info_open(struct inode *inode, struct file *file)
-{
- return single_open(file, mfc_info_show, inode->i_private);
-}
-
-static int mfc_debug_info_open(struct inode *inode, struct file *file)
-{
- return single_open(file, mfc_debug_info_show, inode->i_private);
-}
-
-static const struct file_operations mfc_info_fops = {
- .open = mfc_info_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static const struct file_operations debug_info_fops = {
- .open = mfc_debug_info_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-void s5p_mfc_init_debugfs(struct s5p_mfc_dev *dev)
-{
- struct s5p_mfc_debugfs *debugfs = &dev->debugfs;
-
- debugfs->root = debugfs_create_dir("mfc", NULL);
- if (!debugfs->root) {
- mfc_err_dev("debugfs: failed to create root derectory\n");
- return;
- }
-
- debugfs->mfc_info = debugfs_create_file("mfc_info",
- 0444, debugfs->root, dev, &mfc_info_fops);
- debugfs->debug_info = debugfs_create_file("debug_info",
- 0444, debugfs->root, dev, &debug_info_fops);
- debugfs->debug_level = debugfs_create_u32("debug",
- 0644, debugfs->root, &debug_level);
- debugfs->debug_ts = debugfs_create_u32("debug_ts",
- 0644, debugfs->root, &debug_ts);
- debugfs->dbg_enable = debugfs_create_u32("dbg_enable",
- 0644, debugfs->root, &dbg_enable);
- debugfs->nal_q_dump = debugfs_create_u32("nal_q_dump",
- 0644, debugfs->root, &nal_q_dump);
- debugfs->nal_q_disable = debugfs_create_u32("nal_q_disable",
- 0644, debugfs->root, &nal_q_disable);
- debugfs->nal_q_parallel_disable = debugfs_create_u32("nal_q_parallel_disable",
- 0644, debugfs->root, &nal_q_parallel_disable);
- debugfs->otf_dump = debugfs_create_u32("otf_dump",
- 0644, debugfs->root, &otf_dump);
- debugfs->perf_measure_option = debugfs_create_u32("perf_measure_option",
- 0644, debugfs->root, &perf_measure_option);
- debugfs->sfr_dump = debugfs_create_u32("sfr_dump",
- 0644, debugfs->root, &sfr_dump);
- debugfs->mmcache_dump = debugfs_create_u32("mmcache_dump",
- 0644, debugfs->root, &mmcache_dump);
- debugfs->mmcache_disable = debugfs_create_u32("mmcache_disable",
- 0644, debugfs->root, &mmcache_disable);
- debugfs->perf_boost_mode = debugfs_create_u32("perf_boost_mode",
- 0644, debugfs->root, &perf_boost_mode);
-}
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_debugfs.h
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __S5P_MFC_DEBUGFS_H
-#define __S5P_MFC_DEBUGFS_H __FILE__
-
-#include "s5p_mfc_common.h"
-
-void s5p_mfc_init_debugfs(struct s5p_mfc_dev *dev);
-
-#endif /* __S5P_MFC_DEBUGFS_H */
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_dec.c
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include "s5p_mfc_dec.h"
-#include "s5p_mfc_dec_internal.h"
-
-#include "s5p_mfc_hwlock.h"
-#include "s5p_mfc_opr.h"
-#include "s5p_mfc_sync.h"
-#include "s5p_mfc_mmcache.h"
-
-#include "s5p_mfc_qos.h"
-#include "s5p_mfc_queue.h"
-#include "s5p_mfc_utils.h"
-#include "s5p_mfc_buf.h"
-#include "s5p_mfc_mem.h"
-
-#define MAX_FRAME_SIZE (2*1024*1024)
-
-/* Find selected format description */
-static struct s5p_mfc_fmt *mfc_dec_find_format(struct s5p_mfc_ctx *ctx,
- unsigned int pixelformat)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_fmt *fmt = NULL;
- unsigned long i;
-
- for (i = 0; i < NUM_FORMATS; i++) {
- if (dec_formats[i].fourcc == pixelformat) {
- fmt = (struct s5p_mfc_fmt *)&dec_formats[i];
- break;
- }
- }
-
- if (!dev->pdata->support_10bit && (fmt->type & MFC_FMT_10BIT)) {
- mfc_err_ctx("[FRAME] 10bit is not supported\n");
- fmt = NULL;
- }
- if (!dev->pdata->support_422 && (fmt->type & MFC_FMT_422)) {
- mfc_err_ctx("[FRAME] 422 is not supported\n");
- fmt = NULL;
- }
-
- return fmt;
-}
-
-static struct v4l2_queryctrl *mfc_dec_get_ctrl(int id)
-{
- unsigned long i;
-
- for (i = 0; i < NUM_CTRLS; ++i)
- if (id == controls[i].id)
- return &controls[i];
-
- return NULL;
-}
-
-/* Check whether a ctrl value if correct */
-static int mfc_dec_check_ctrl_val(struct s5p_mfc_ctx *ctx, struct v4l2_control *ctrl)
-{
- struct v4l2_queryctrl *c;
-
- c = mfc_dec_get_ctrl(ctrl->id);
- if (!c) {
- mfc_err_ctx("[CTRLS] not supported control id (%#x)\n", ctrl->id);
- return -EINVAL;
- }
-
- if (ctrl->value < c->minimum || ctrl->value > c->maximum
- || (c->step != 0 && ctrl->value % c->step != 0)) {
- mfc_err_ctx("[CTRLS] Invalid control value (%#x)\n", ctrl->value);
- return -ERANGE;
- }
-
- return 0;
-}
-
-/* Query capabilities of the device */
-static int vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
- strncpy(cap->driver, "MFC", sizeof(cap->driver) - 1);
- strncpy(cap->card, "decoder", sizeof(cap->card) - 1);
- cap->bus_info[0] = 0;
- cap->version = KERNEL_VERSION(1, 0, 0);
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE
- | V4L2_CAP_VIDEO_OUTPUT
- | V4L2_CAP_VIDEO_CAPTURE_MPLANE
- | V4L2_CAP_VIDEO_OUTPUT_MPLANE
- | V4L2_CAP_STREAMING
- | V4L2_CAP_DEVICE_CAPS;
-
- cap->capabilities = cap->device_caps;
-
- return 0;
-}
-
-static int mfc_dec_enum_fmt(struct s5p_mfc_dev *dev, struct v4l2_fmtdesc *f,
- unsigned int type)
-{
- struct s5p_mfc_fmt *fmt;
- unsigned long i, j = 0;
-
- for (i = 0; i < NUM_FORMATS; ++i) {
- if (!(dec_formats[i].type & type))
- continue;
- if (!dev->pdata->support_10bit && (dec_formats[i].type & MFC_FMT_10BIT))
- continue;
- if (!dev->pdata->support_422 && (dec_formats[i].type & MFC_FMT_422))
- continue;
-
- if (j == f->index) {
- fmt = &dec_formats[i];
- strlcpy(f->description, fmt->name,
- sizeof(f->description));
- f->pixelformat = fmt->fourcc;
-
- return 0;
- }
-
- ++j;
- }
-
- return -EINVAL;
-}
-
-static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv,
- struct v4l2_fmtdesc *f)
-{
- struct s5p_mfc_dev *dev = video_drvdata(file);
-
- return mfc_dec_enum_fmt(dev, f, MFC_FMT_FRAME);
-}
-
-static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *prov,
- struct v4l2_fmtdesc *f)
-{
- struct s5p_mfc_dev *dev = video_drvdata(file);
-
- return mfc_dec_enum_fmt(dev, f, MFC_FMT_STREAM);
-}
-
-static void mfc_dec_change_format(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- u32 org_fmt = ctx->dst_fmt->fourcc;
-
- if (ctx->is_10bit && ctx->is_422) {
- switch (org_fmt) {
- case V4L2_PIX_FMT_NV16M_S10B:
- case V4L2_PIX_FMT_NV61M_S10B:
- case V4L2_PIX_FMT_NV16M_P210:
- case V4L2_PIX_FMT_NV61M_P210:
- /* It is right format */
- break;
- case V4L2_PIX_FMT_NV12M:
- case V4L2_PIX_FMT_NV16M:
- case V4L2_PIX_FMT_NV12M_S10B:
- case V4L2_PIX_FMT_NV12M_P010:
- ctx->dst_fmt = mfc_dec_find_format(ctx, V4L2_PIX_FMT_NV16M_S10B);
- break;
- case V4L2_PIX_FMT_NV21M:
- case V4L2_PIX_FMT_NV61M:
- case V4L2_PIX_FMT_NV21M_S10B:
- case V4L2_PIX_FMT_NV21M_P010:
- ctx->dst_fmt = mfc_dec_find_format(ctx, V4L2_PIX_FMT_NV61M_S10B);
- break;
- default:
- ctx->dst_fmt = mfc_dec_find_format(ctx, V4L2_PIX_FMT_NV16M_S10B);
- break;
- }
- ctx->raw_buf.num_planes = 2;
- } else if (ctx->is_10bit && !ctx->is_422) {
- if (ctx->dst_fmt->mem_planes == 1) {
- /* YUV420 only supports the single plane */
- ctx->dst_fmt = mfc_dec_find_format(ctx, V4L2_PIX_FMT_NV12N_10B);
- } else {
- switch (org_fmt) {
- case V4L2_PIX_FMT_NV12M_S10B:
- case V4L2_PIX_FMT_NV21M_S10B:
- case V4L2_PIX_FMT_NV12M_P010:
- case V4L2_PIX_FMT_NV21M_P010:
- /* It is right format */
- break;
- case V4L2_PIX_FMT_NV12M:
- case V4L2_PIX_FMT_NV16M:
- case V4L2_PIX_FMT_NV16M_S10B:
- case V4L2_PIX_FMT_NV16M_P210:
- if (dev->pdata->P010_decoding)
- ctx->dst_fmt = mfc_dec_find_format(ctx, V4L2_PIX_FMT_NV12M_P010);
- else
- ctx->dst_fmt = mfc_dec_find_format(ctx, V4L2_PIX_FMT_NV12M_S10B);
- break;
- case V4L2_PIX_FMT_NV21M:
- case V4L2_PIX_FMT_NV61M:
- case V4L2_PIX_FMT_NV61M_S10B:
- case V4L2_PIX_FMT_NV61M_P210:
- ctx->dst_fmt = mfc_dec_find_format(ctx, V4L2_PIX_FMT_NV21M_S10B);
- break;
- default:
- if (dev->pdata->P010_decoding)
- ctx->dst_fmt = mfc_dec_find_format(ctx, V4L2_PIX_FMT_NV12M_P010);
- else
- ctx->dst_fmt = mfc_dec_find_format(ctx, V4L2_PIX_FMT_NV12M_S10B);
- break;
- }
- }
- ctx->raw_buf.num_planes = 2;
- } else if (!ctx->is_10bit && ctx->is_422) {
- switch (org_fmt) {
- case V4L2_PIX_FMT_NV16M:
- case V4L2_PIX_FMT_NV61M:
- /* It is right format */
- break;
- case V4L2_PIX_FMT_NV12M:
- case V4L2_PIX_FMT_NV12M_S10B:
- case V4L2_PIX_FMT_NV16M_S10B:
- case V4L2_PIX_FMT_NV12M_P010:
- case V4L2_PIX_FMT_NV16M_P210:
- ctx->dst_fmt = mfc_dec_find_format(ctx, V4L2_PIX_FMT_NV16M);
- break;
- case V4L2_PIX_FMT_NV21M:
- case V4L2_PIX_FMT_NV21M_S10B:
- case V4L2_PIX_FMT_NV61M_S10B:
- case V4L2_PIX_FMT_NV21M_P010:
- case V4L2_PIX_FMT_NV61M_P210:
- ctx->dst_fmt = mfc_dec_find_format(ctx, V4L2_PIX_FMT_NV61M);
- break;
- default:
- ctx->dst_fmt = mfc_dec_find_format(ctx, V4L2_PIX_FMT_NV16M);
- break;
- }
- ctx->raw_buf.num_planes = 2;
- } else {
- /* YUV420 8bit */
- switch (org_fmt) {
- case V4L2_PIX_FMT_NV16M:
- case V4L2_PIX_FMT_NV12M_S10B:
- case V4L2_PIX_FMT_NV16M_S10B:
- case V4L2_PIX_FMT_NV12M_P010:
- case V4L2_PIX_FMT_NV16M_P210:
- ctx->dst_fmt = mfc_dec_find_format(ctx, V4L2_PIX_FMT_NV12M);
- break;
- case V4L2_PIX_FMT_NV61M:
- case V4L2_PIX_FMT_NV21M_S10B:
- case V4L2_PIX_FMT_NV61M_S10B:
- case V4L2_PIX_FMT_NV21M_P010:
- case V4L2_PIX_FMT_NV61M_P210:
- ctx->dst_fmt = mfc_dec_find_format(ctx, V4L2_PIX_FMT_NV21M);
- break;
- default:
- /* It is right format */
- break;
- }
- }
-
- if (org_fmt != ctx->dst_fmt->fourcc)
- mfc_info_ctx("[FRAME] format is changed to %s\n", ctx->dst_fmt->name);
-}
-
-/* Get format */
-static int vidioc_g_fmt_vid_cap_mplane(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
- struct s5p_mfc_dec *dec;
- struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
- struct s5p_mfc_raw_info *raw;
- int i;
-
- mfc_debug_enter();
-
- dec = ctx->dec_priv;
- if (!dec) {
- mfc_err_dev("no mfc decoder to run\n");
- return -EINVAL;
- }
-
- mfc_debug(2, "dec dst g_fmt, state: %d\n", ctx->state);
-
- if (ctx->state == MFCINST_GOT_INST ||
- ctx->state == MFCINST_RES_CHANGE_FLUSH ||
- ctx->state == MFCINST_RES_CHANGE_END) {
- /* If the MFC is parsing the header,
- * so wait until it is finished */
- if (s5p_mfc_wait_for_done_ctx(ctx,
- S5P_FIMV_R2H_CMD_SEQ_DONE_RET)) {
- mfc_err_dev("header parsing failed\n");
- return -EAGAIN;
- }
- }
-
- if (ctx->state >= MFCINST_HEAD_PARSED &&
- ctx->state < MFCINST_ABORT) {
- /* This is run on CAPTURE (deocde output) */
-
- /* only NV16(61) format is supported for 422 format */
- /* only 2 plane is supported for 10bit */
- mfc_dec_change_format(ctx);
-
- raw = &ctx->raw_buf;
- /* Width and height are set to the dimensions
- of the movie, the buffer is bigger and
- further processing stages should crop to this
- rectangle. */
- s5p_mfc_dec_calc_dpb_size(ctx);
-
- if (IS_LOW_MEM) {
- unsigned int dpb_size;
- /*
- * If total memory requirement is too big for this device,
- * then it returns error.
- * DPB size : Total plane size * the number of DPBs
- * 5: the number of extra DPBs
- * 3: the number of DPBs for Android framework
- * 600MB: being used to return an error,
- * when 8K resolution video clip is being tried to be decoded
- */
- dpb_size = (ctx->raw_buf.total_plane_size * (ctx->dpb_count + 5 + 3));
- if (dpb_size > SZ_600M) {
- mfc_info_ctx("required memory size is too big (%dx%d, dpb: %d)\n",
- ctx->img_width, ctx->img_height, ctx->dpb_count);
- return -EINVAL;
- }
- }
-
- pix_fmt_mp->width = ctx->img_width;
- pix_fmt_mp->height = ctx->img_height;
- pix_fmt_mp->num_planes = ctx->dst_fmt->mem_planes;
-
- if (dec->is_interlaced)
- pix_fmt_mp->field = V4L2_FIELD_INTERLACED;
- else
- pix_fmt_mp->field = V4L2_FIELD_NONE;
-
- /* Set pixelformat to the format in which MFC
- outputs the decoded frame */
- pix_fmt_mp->pixelformat = ctx->dst_fmt->fourcc;
- for (i = 0; i < ctx->dst_fmt->mem_planes; i++) {
- pix_fmt_mp->plane_fmt[i].bytesperline = raw->stride[i];
- if (ctx->dst_fmt->mem_planes == 1) {
- pix_fmt_mp->plane_fmt[i].sizeimage = raw->total_plane_size;
- } else {
- if (ctx->is_10bit)
- pix_fmt_mp->plane_fmt[i].sizeimage = raw->plane_size[i]
- + raw->plane_size_2bits[i];
- else
- pix_fmt_mp->plane_fmt[i].sizeimage = raw->plane_size[i];
- }
- }
- }
-
- mfc_debug_leave();
-
- return 0;
-}
-
-static int vidioc_g_fmt_vid_out_mplane(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
- struct s5p_mfc_dec *dec;
- struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
-
- mfc_debug_enter();
-
- dec = ctx->dec_priv;
- if (!dec) {
- mfc_err_dev("no mfc decoder to run\n");
- return -EINVAL;
- }
-
- mfc_debug(4, "dec src g_fmt, state: %d\n", ctx->state);
-
- /* This is run on OUTPUT
- The buffer contains compressed image
- so width and height have no meaning */
- pix_fmt_mp->width = 0;
- pix_fmt_mp->height = 0;
- pix_fmt_mp->field = V4L2_FIELD_NONE;
- pix_fmt_mp->plane_fmt[0].bytesperline = dec->src_buf_size;
- pix_fmt_mp->plane_fmt[0].sizeimage = dec->src_buf_size;
- pix_fmt_mp->pixelformat = ctx->src_fmt->fourcc;
- pix_fmt_mp->num_planes = ctx->src_fmt->mem_planes;
-
- mfc_debug_leave();
-
- return 0;
-}
-
-/* Try format */
-static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
-{
- struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
- struct s5p_mfc_fmt *fmt;
- struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
-
- fmt = mfc_dec_find_format(ctx, pix_fmt_mp->pixelformat);
- if (!fmt) {
- mfc_err_dev("Unsupported format for %s\n",
- V4L2_TYPE_IS_OUTPUT(f->type) ? "source" : "destination");
- return -EINVAL;
- }
-
- return 0;
-}
-
-/* Set format */
-static int vidioc_s_fmt_vid_cap_mplane(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
- struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
-
- mfc_debug_enter();
-
- if (ctx->vq_dst.streaming) {
- mfc_err_ctx("queue busy\n");
- return -EBUSY;
- }
-
- ctx->dst_fmt = mfc_dec_find_format(ctx, pix_fmt_mp->pixelformat);
- if (!ctx->dst_fmt) {
- mfc_err_ctx("Unsupported format for destination\n");
- return -EINVAL;
- }
- ctx->raw_buf.num_planes = ctx->dst_fmt->num_planes;
- mfc_info_ctx("[FRAME] dec dst pixelformat : %s\n", ctx->dst_fmt->name);
-
- mfc_debug_leave();
-
- return 0;
-}
-
-static int mfc_force_close_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx)
-{
- if (ctx->inst_no == MFC_NO_INSTANCE_SET)
- return 0;
-
- s5p_mfc_change_state(ctx, MFCINST_RETURN_INST);
- s5p_mfc_set_bit(ctx->num, &dev->work_bits);
- s5p_mfc_clean_ctx_int_flags(ctx);
- if (s5p_mfc_just_run(dev, ctx->num)) {
- mfc_err_ctx("Failed to run MFC\n");
- s5p_mfc_release_hwlock_ctx(ctx);
- s5p_mfc_cleanup_work_bit_and_try_run(ctx);
- return -EIO;
- }
-
- /* Wait until instance is returned or timeout occured */
- if (s5p_mfc_wait_for_done_ctx(ctx,
- S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET)) {
- mfc_err_ctx("Waiting for CLOSE_INSTANCE timed out\n");
- s5p_mfc_release_hwlock_ctx(ctx);
- s5p_mfc_cleanup_work_bit_and_try_run(ctx);
- return -EIO;
- }
-
- /* Free resources */
- s5p_mfc_release_instance_context(ctx);
- s5p_mfc_change_state(ctx, MFCINST_INIT);
-
- return 0;
-}
-
-static int vidioc_s_fmt_vid_out_mplane(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct s5p_mfc_dev *dev = video_drvdata(file);
- struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
- struct s5p_mfc_dec *dec = ctx->dec_priv;
- struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
- int ret = 0;
-
- mfc_debug_enter();
-
- if (ctx->vq_src.streaming) {
- mfc_err_ctx("queue busy\n");
- return -EBUSY;
- }
-
- ctx->src_fmt = mfc_dec_find_format(ctx, pix_fmt_mp->pixelformat);
- if (!ctx->src_fmt) {
- mfc_err_ctx("Unsupported format for source\n");
- return -EINVAL;
- }
-
- ctx->codec_mode = ctx->src_fmt->codec_mode;
- mfc_info_ctx("[STREAM] Dec src codec(%d): %s\n",
- ctx->codec_mode, ctx->src_fmt->name);
-
- ctx->pix_format = pix_fmt_mp->pixelformat;
- if ((pix_fmt_mp->width > 0) && (pix_fmt_mp->height > 0)) {
- ctx->img_height = pix_fmt_mp->height;
- ctx->img_width = pix_fmt_mp->width;
- }
-
- /* As this buffer will contain compressed data, the size is set
- * to the maximum size. */
- if (pix_fmt_mp->plane_fmt[0].sizeimage)
- dec->src_buf_size = pix_fmt_mp->plane_fmt[0].sizeimage;
- else
- dec->src_buf_size = MAX_FRAME_SIZE;
- mfc_debug(2, "[STREAM] sizeimage: %d\n", pix_fmt_mp->plane_fmt[0].sizeimage);
- pix_fmt_mp->plane_fmt[0].bytesperline = 0;
-
- MFC_TRACE_CTX_HWLOCK("**DEC s_fmt\n");
- ret = s5p_mfc_get_hwlock_ctx(ctx);
- if (ret < 0) {
- mfc_err_ctx("Failed to get hwlock\n");
- return -EBUSY;
- }
-
- /* In case of calling s_fmt twice or more */
- ret = mfc_force_close_inst(dev, ctx);
- if (ret) {
- mfc_err_ctx("Failed to close already opening instance\n");
- return -EIO;
- }
-
- ret = s5p_mfc_alloc_instance_context(ctx);
- if (ret) {
- mfc_err_ctx("Failed to allocate dec instance[%d] buffers\n",
- ctx->num);
- s5p_mfc_release_hwlock_ctx(ctx);
- return -ENOMEM;
- }
-
- s5p_mfc_set_bit(ctx->num, &dev->work_bits);
- ret = s5p_mfc_just_run(dev, ctx->num);
- if (ret) {
- mfc_err_ctx("Failed to run MFC\n");
- s5p_mfc_release_hwlock_ctx(ctx);
- s5p_mfc_cleanup_work_bit_and_try_run(ctx);
- s5p_mfc_release_instance_context(ctx);
- return -EIO;
- }
-
- if (s5p_mfc_wait_for_done_ctx(ctx,
- S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET)) {
- s5p_mfc_release_hwlock_ctx(ctx);
- s5p_mfc_cleanup_work_bit_and_try_run(ctx);
- s5p_mfc_release_instance_context(ctx);
- return -EIO;
- }
-
- s5p_mfc_release_hwlock_ctx(ctx);
-
- mfc_debug(2, "Got instance number: %d\n", ctx->inst_no);
-
- if (s5p_mfc_dec_ctx_ready(ctx))
- s5p_mfc_set_bit(ctx->num, &dev->work_bits);
- if (s5p_mfc_is_work_to_do(dev))
- queue_work(dev->butler_wq, &dev->butler_work);
-
- mfc_debug_leave();
-
- return 0;
-}
-
-/* Reqeust buffers */
-static int vidioc_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *reqbufs)
-{
- struct s5p_mfc_dev *dev = video_drvdata(file);
- struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
- struct s5p_mfc_dec *dec;
- int ret = 0;
-
- mfc_debug_enter();
-
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
-
- dec = ctx->dec_priv;
- if (!dec) {
- mfc_err_dev("no mfc decoder to run\n");
- return -EINVAL;
- }
-
- if (reqbufs->memory == V4L2_MEMORY_MMAP) {
- mfc_err_ctx("Not supported memory type (%d)\n", reqbufs->memory);
- return -EINVAL;
- }
-
- if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- mfc_debug(4, "dec src reqbuf(%d)\n", reqbufs->count);
- /* Can only request buffers after
- an instance has been opened.*/
- if (ctx->state == MFCINST_GOT_INST) {
- if (reqbufs->count == 0) {
- ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
- ctx->output_state = QUEUE_FREE;
- return ret;
- }
-
- /* Decoding */
- if (ctx->output_state != QUEUE_FREE) {
- mfc_err_ctx("Bufs have already been requested\n");
- return -EINVAL;
- }
-
- ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
- if (ret) {
- mfc_err_ctx("vb2_reqbufs on src failed\n");
- return ret;
- }
-
- ctx->output_state = QUEUE_BUFS_REQUESTED;
- }
- } else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- mfc_debug(4, "dec dst reqbuf(%d)\n", reqbufs->count);
- if (reqbufs->count == 0) {
- ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
-
- if (dev->has_mmcache && dev->mmcache.is_on_status)
- s5p_mfc_invalidate_mmcache(dev);
-
- s5p_mfc_release_codec_buffers(ctx);
- ctx->capture_state = QUEUE_FREE;
- return ret;
- }
-
- dec->dst_memtype = reqbufs->memory;
-
- if (ctx->capture_state != QUEUE_FREE) {
- mfc_err_ctx("Bufs have already been requested\n");
- return -EINVAL;
- }
-
- ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
- if (ret) {
- mfc_err_ctx("vb2_reqbufs on capture failed\n");
- return ret;
- }
-
- if (reqbufs->count < ctx->dpb_count) {
- mfc_err_ctx("Not enough buffers allocated\n");
- reqbufs->count = 0;
- vb2_reqbufs(&ctx->vq_dst, reqbufs);
- return -ENOMEM;
- }
-
- dec->total_dpb_count = reqbufs->count;
-
- ret = s5p_mfc_alloc_codec_buffers(ctx);
- if (ret) {
- mfc_err_ctx("Failed to allocate decoding buffers\n");
- reqbufs->count = 0;
- vb2_reqbufs(&ctx->vq_dst, reqbufs);
- return -ENOMEM;
- }
-
- ctx->capture_state = QUEUE_BUFS_REQUESTED;
-
- if (s5p_mfc_dec_ctx_ready(ctx))
- s5p_mfc_set_bit(ctx->num, &dev->work_bits);
-
- s5p_mfc_try_run(dev);
- }
-
- mfc_debug_leave();
-
- return ret;
-}
-
-/* Query buffer */
-static int vidioc_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *buf)
-{
- struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
- int ret;
-
- mfc_debug_enter();
-
- if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- mfc_debug(4, "dec dst querybuf, state: %d\n", ctx->state);
- ret = vb2_querybuf(&ctx->vq_dst, buf);
- if (ret != 0) {
- mfc_err_dev("dec dst: error in vb2_querybuf()\n");
- return ret;
- }
- } else if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- mfc_debug(4, "dec src querybuf, state: %d\n", ctx->state);
- ret = vb2_querybuf(&ctx->vq_src, buf);
- if (ret != 0) {
- mfc_err_dev("dec src: error in vb2_querybuf()\n");
- return ret;
- }
- } else {
- mfc_err_dev("invalid buf type (%d)\n", buf->type);
- return -EINVAL;
- }
-
- mfc_debug_leave();
-
- return ret;
-}
-
-/* Queue a buffer */
-static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
- struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
- int ret = -EINVAL;
-
- mfc_debug_enter();
-
- if (ctx->state == MFCINST_ERROR) {
- mfc_err_ctx("Call on QBUF after unrecoverable error\n");
- return -EIO;
- }
-
- if (V4L2_TYPE_IS_MULTIPLANAR(buf->type) && !buf->length) {
- mfc_err_ctx("multiplanar but length is zero\n");
- return -EIO;
- }
-
- if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- mfc_debug(4, "dec src buf[%d] Q\n", buf->index);
- if (buf->m.planes[0].bytesused > buf->m.planes[0].length) {
- mfc_err_ctx("data size (%d) must be less than "
- "buffer size(%d)\n",
- buf->m.planes[0].bytesused,
- buf->m.planes[0].length);
- return -EIO;
- }
-
- s5p_mfc_qos_update_framerate(ctx);
-
- if (!buf->m.planes[0].bytesused) {
- buf->m.planes[0].bytesused = buf->m.planes[0].length;
- mfc_debug(2, "Src size zero, changed to buf size %d\n",
- buf->m.planes[0].bytesused);
- } else {
- mfc_debug(2, "Src size = %d\n", buf->m.planes[0].bytesused);
- }
- ret = vb2_qbuf(&ctx->vq_src, buf);
- } else {
- mfc_debug(4, "dec dst buf[%d] Q\n", buf->index);
- ret = vb2_qbuf(&ctx->vq_dst, buf);
- }
-
- mfc_debug_leave();
- return ret;
-}
-
-/* Dequeue a buffer */
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
- struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
- struct s5p_mfc_dec *dec = ctx->dec_priv;
- struct dec_dpb_ref_info *dstBuf, *srcBuf;
- int ret;
- int ncount = 0;
-
- mfc_debug_enter();
-
- if (ctx->state == MFCINST_ERROR) {
- mfc_err_ctx("Call on DQBUF after unrecoverable error\n");
- return -EIO;
- }
- if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- mfc_debug(4, "dec src buf[%d] DQ\n", buf->index);
- ret = vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK);
- } else {
- mfc_debug(4, "dec dst buf[%d] DQ\n", buf->index);
- ret = vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK);
-
- if (buf->index >= MFC_MAX_DPBS) {
- mfc_err_ctx("buffer index[%d] range over\n", buf->index);
- return -EINVAL;
- }
-
- /* Memcpy from dec->ref_info to shared memory */
- srcBuf = &dec->ref_info[buf->index];
- for (ncount = 0; ncount < MFC_MAX_DPBS; ncount++) {
- if (srcBuf->dpb[ncount].fd[0] == MFC_INFO_INIT_FD)
- break;
- mfc_debug(2, "[DPB] DQ index[%d] Released FD = %d\n",
- buf->index, srcBuf->dpb[ncount].fd[0]);
- }
-
- if (dec->sh_handle.vaddr != NULL) {
- dstBuf = (struct dec_dpb_ref_info *)
- dec->sh_handle.vaddr + buf->index;
- memcpy(dstBuf, srcBuf, sizeof(struct dec_dpb_ref_info));
- dstBuf->index = buf->index;
- }
- }
- mfc_debug_leave();
- return ret;
-}
-
-/* Stream on */
-static int vidioc_streamon(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
- int ret = -EINVAL;
-
- mfc_debug_enter();
-
- if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- mfc_debug(4, "dec src streamon\n");
- ret = vb2_streamon(&ctx->vq_src, type);
- } else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- mfc_debug(4, "dec dst streamon\n");
- ret = vb2_streamon(&ctx->vq_dst, type);
-
- if (!ret)
- s5p_mfc_qos_on(ctx);
- } else {
- mfc_err_ctx("unknown v4l2 buffer type\n");
- }
-
- mfc_debug(2, "src: %d, dst: %d, state = %d, dpb_count = %d\n",
- s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->src_buf_queue),
- s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->dst_buf_queue),
- ctx->state, ctx->dpb_count);
-
- mfc_debug_leave();
-
- return ret;
-}
-
-/* Stream off, which equals to a pause */
-static int vidioc_streamoff(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
- int ret = -EINVAL;
-
- mfc_debug_enter();
-
- if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- mfc_debug(4, "dec src streamoff\n");
- s5p_mfc_qos_reset_last_framerate(ctx);
-
- ret = vb2_streamoff(&ctx->vq_src, type);
- } else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- mfc_debug(4, "dec dst streamoff\n");
- ret = vb2_streamoff(&ctx->vq_dst, type);
- if (!ret)
- s5p_mfc_qos_off(ctx);
- } else {
- mfc_err_ctx("unknown v4l2 buffer type\n");
- }
-
- mfc_debug_leave();
-
- return ret;
-}
-
-/* Query a ctrl */
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- struct v4l2_queryctrl *c;
-
- c = mfc_dec_get_ctrl(qc->id);
- if (!c) {
- mfc_err_dev("[CTRLS] not supported control id (%#x)\n", qc->id);
- return -EINVAL;
- }
-
- *qc = *c;
- return 0;
-}
-
-static int mfc_dec_ext_info(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- int val = 0;
-
- val |= DEC_SET_DYNAMIC_DPB;
- if (MFC_FEATURE_SUPPORT(dev, dev->pdata->skype))
- val |= DEC_SET_SKYPE_FLAG;
-
- mfc_debug(5, "[CTRLS] ext info val: %#x\n", val);
-
- return val;
-}
-
-/* Get ctrl */
-static int mfc_dec_get_ctrl_val(struct s5p_mfc_ctx *ctx, struct v4l2_control *ctrl)
-{
- struct s5p_mfc_dev *dev;
- struct s5p_mfc_dec *dec;
- struct s5p_mfc_ctx_ctrl *ctx_ctrl;
- int found = 0;
-
- if (!ctx) {
- mfc_err_dev("no mfc context to run\n");
- return -EINVAL;
- }
- dev = ctx->dev;
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
- dec = ctx->dec_priv;
- if (!dec) {
- mfc_err_dev("no mfc decoder to run\n");
- return -EINVAL;
- }
-
- switch (ctrl->id) {
- case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER:
- ctrl->value = dec->loop_filter_mpeg4;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY:
- ctrl->value = dec->display_delay;
- break;
- case V4L2_CID_CACHEABLE:
- mfc_debug(5, "it is supported only V4L2_MEMORY_MMAP\n");
- break;
- case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
- if (ctx->state >= MFCINST_HEAD_PARSED &&
- ctx->state < MFCINST_ABORT) {
- ctrl->value = ctx->dpb_count;
- break;
- } else if (ctx->state != MFCINST_INIT) {
- mfc_err_ctx("Decoding not initialised\n");
- return -EINVAL;
- }
-
- /* Should wait for the header to be parsed */
- if (s5p_mfc_wait_for_done_ctx(ctx,
- S5P_FIMV_R2H_CMD_SEQ_DONE_RET)) {
- s5p_mfc_cleanup_work_bit_and_try_run(ctx);
- return -EIO;
- }
-
- if (ctx->state >= MFCINST_HEAD_PARSED &&
- ctx->state < MFCINST_ABORT) {
- ctrl->value = ctx->dpb_count;
- } else {
- mfc_err_ctx("Decoding not initialised\n");
- return -EINVAL;
- }
- break;
- case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE:
- ctrl->value = dec->slice_enable;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_PACKED_PB:
- /* Not used */
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_CRC_ENABLE:
- ctrl->value = dec->crc_enable;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_CHECK_STATE:
- if (ctx->is_dpb_realloc && ctx->state == MFCINST_HEAD_PARSED)
- ctrl->value = MFCSTATE_DEC_S3D_REALLOC;
- else if (ctx->state == MFCINST_RES_CHANGE_FLUSH
- || ctx->state == MFCINST_RES_CHANGE_END
- || ctx->state == MFCINST_HEAD_PARSED)
- ctrl->value = MFCSTATE_DEC_RES_DETECT;
- else if (ctx->state == MFCINST_FINISHING)
- ctrl->value = MFCSTATE_DEC_TERMINATING;
- else
- ctrl->value = MFCSTATE_PROCESSING;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING:
- ctrl->value = dec->sei_parse;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_I_FRAME_DECODING:
- ctrl->value = dec->idr_decoding;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_RATE:
- ctrl->value = s5p_mfc_qos_get_framerate(ctx);
- break;
- case V4L2_CID_MPEG_MFC_GET_VERSION_INFO:
- ctrl->value = dev->pdata->ip_ver;
- break;
- case V4L2_CID_MPEG_VIDEO_QOS_RATIO:
- ctrl->value = ctx->qos_ratio;
- break;
- case V4L2_CID_MPEG_MFC_SET_DYNAMIC_DPB_MODE:
- ctrl->value = dec->is_dynamic_dpb;
- break;
- case V4L2_CID_MPEG_MFC_GET_EXT_INFO:
- ctrl->value = mfc_dec_ext_info(ctx);
- break;
- case V4L2_CID_MPEG_MFC_GET_10BIT_INFO:
- ctrl->value = ctx->is_10bit;
- break;
- case V4L2_CID_MPEG_MFC_GET_DRIVER_INFO:
- ctrl->value = MFC_DRIVER_INFO;
- break;
- default:
- list_for_each_entry(ctx_ctrl, &ctx->ctrls, list) {
- if (!(ctx_ctrl->type & MFC_CTRL_TYPE_GET))
- continue;
-
- if (ctx_ctrl->id == ctrl->id) {
- if (ctx_ctrl->has_new) {
- ctx_ctrl->has_new = 0;
- ctrl->value = ctx_ctrl->val;
- } else {
- mfc_debug(5, "[CTRLS] Control value "\
- "is not up to date: "\
- "0x%08x\n", ctrl->id);
- return -EINVAL;
- }
-
- found = 1;
- break;
- }
- }
-
- if (!found) {
- mfc_err_ctx("Invalid control: 0x%08x\n", ctrl->id);
- return -EINVAL;
- }
- break;
- }
-
- mfc_debug(5, "[CTRLS] get id: %#x, value: %d\n", ctrl->id, ctrl->value);
-
- return 0;
-}
-
-/* Get a ctrl */
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
- int ret = 0;
-
- mfc_debug_enter();
- ret = mfc_dec_get_ctrl_val(ctx, ctrl);
- mfc_debug_leave();
-
- return ret;
-}
-
-/* Set a ctrl */
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct s5p_mfc_dev *dev = video_drvdata(file);
- struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
- struct s5p_mfc_dec *dec;
- struct s5p_mfc_ctx_ctrl *ctx_ctrl;
- int ret = 0;
- int found = 0;
-
- mfc_debug_enter();
-
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
-
- dec = ctx->dec_priv;
- if (!dec) {
- mfc_err_dev("no mfc decoder to run\n");
- return -EINVAL;
- }
-
- ret = mfc_dec_check_ctrl_val(ctx, ctrl);
- if (ret)
- return ret;
-
- mfc_debug(5, "[CTRLS] set id: %#x, value: %d\n", ctrl->id, ctrl->value);
-
- switch (ctrl->id) {
- case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER:
- dec->loop_filter_mpeg4 = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY:
- dec->display_delay = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE:
- dec->slice_enable = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_PACKED_PB:
- /* Not used */
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_CRC_ENABLE:
- dec->crc_enable = ctrl->value;
- break;
- case V4L2_CID_CACHEABLE:
- mfc_debug(5, "it is supported only V4L2_MEMORY_MMAP\n");
- break;
- case V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING:
- dec->sei_parse = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_I_FRAME_DECODING:
- dec->idr_decoding = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_DECODER_IMMEDIATE_DISPLAY:
- dec->immediate_display = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_DECODER_DECODING_TIMESTAMP_MODE:
- dec->is_dts_mode = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_DECODER_WAIT_DECODING_START:
- ctx->wait_state = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC_SET_DUAL_DPB_MODE:
- mfc_err_dev("[DPB] not supported CID: 0x%x\n",ctrl->id);
- break;
- case V4L2_CID_MPEG_VIDEO_QOS_RATIO:
- ctx->qos_ratio = ctrl->value;
- mfc_info_ctx("[QoS] set %d qos_ratio\n", ctrl->value);
- break;
- case V4L2_CID_MPEG_MFC_SET_DYNAMIC_DPB_MODE:
- dec->is_dynamic_dpb = ctrl->value;
- if (dec->is_dynamic_dpb == 0)
- mfc_err_dev("[DPB] is_dynamic_dpb is 0. it has to be enabled\n");
- break;
- case V4L2_CID_MPEG_MFC_SET_USER_SHARED_HANDLE:
- if (dec->sh_handle.fd == -1) {
- dec->sh_handle.fd = ctrl->value;
- if (s5p_mfc_mem_get_user_shared_handle(ctx, &dec->sh_handle))
- return -EINVAL;
- else
- mfc_debug(2, "[MEMINFO][DPB] shared handle fd: %d, vaddr: 0x%p\n",
- dec->sh_handle.fd, dec->sh_handle.vaddr);
- }
- break;
- case V4L2_CID_MPEG_MFC_SET_BUF_PROCESS_TYPE:
- ctx->buf_process_type = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_BLACK_BAR_DETECT:
- dec->detect_black_bar = ctrl->value;
- break;
- default:
- list_for_each_entry(ctx_ctrl, &ctx->ctrls, list) {
- if (!(ctx_ctrl->type & MFC_CTRL_TYPE_SET))
- continue;
-
- if (ctx_ctrl->id == ctrl->id) {
- ctx_ctrl->has_new = 1;
- ctx_ctrl->val = ctrl->value;
-
- found = 1;
- break;
- }
- }
-
- if (!found) {
- mfc_err_ctx("Invalid control: 0x%08x\n", ctrl->id);
- return -EINVAL;
- }
- break;
- }
-
- mfc_debug_leave();
-
- return 0;
-}
-
-/* Get cropping information */
-static int vidioc_g_crop(struct file *file, void *priv,
- struct v4l2_crop *cr)
-{
- struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
- struct s5p_mfc_dec *dec = ctx->dec_priv;
-
- mfc_debug_enter();
-
- if (!ready_to_get_crop(ctx)) {
- mfc_debug(2, "ready to get crop failed\n");
- return -EINVAL;
- }
-
- if (ctx->state == MFCINST_RUNNING && dec->detect_black_bar
- && dec->black_bar_updated) {
- cr->c.left = dec->black_bar.left;
- cr->c.top = dec->black_bar.top;
- cr->c.width = dec->black_bar.width;
- cr->c.height = dec->black_bar.height;
- mfc_debug(2, "[FRAME][BLACKBAR] Cropping info: l=%d t=%d w=%d h=%d\n",
- dec->black_bar.left,
- dec->black_bar.top,
- dec->black_bar.width,
- dec->black_bar.height);
- } else {
- if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_H264 ||
- ctx->src_fmt->fourcc == V4L2_PIX_FMT_HEVC ||
- ctx->src_fmt->fourcc == V4L2_PIX_FMT_BPG) {
- cr->c.left = dec->cr_left;
- cr->c.top = dec->cr_top;
- cr->c.width = ctx->img_width - dec->cr_left - dec->cr_right;
- cr->c.height = ctx->img_height - dec->cr_top - dec->cr_bot;
- mfc_debug(2, "[FRAME] Cropping info: l=%d t=%d " \
- "w=%d h=%d (r=%d b=%d fw=%d fh=%d)\n",
- dec->cr_left, dec->cr_top,
- cr->c.width, cr->c.height,
- dec->cr_right, dec->cr_bot,
- ctx->img_width, ctx->img_height);
- } else {
- cr->c.left = 0;
- cr->c.top = 0;
- cr->c.width = ctx->img_width;
- cr->c.height = ctx->img_height;
- mfc_debug(2, "[FRAME] Cropping info: w=%d h=%d fw=%d fh=%d\n",
- cr->c.width, cr->c.height,
- ctx->img_width, ctx->img_height);
- }
- }
-
- mfc_debug_leave();
- return 0;
-}
-
-static int vidioc_g_ext_ctrls(struct file *file, void *priv,
- struct v4l2_ext_controls *f)
-{
- struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
- struct v4l2_ext_control *ext_ctrl;
- struct v4l2_control ctrl;
- int i;
- int ret = 0;
-
- if (f->which != V4L2_CTRL_CLASS_MPEG)
- return -EINVAL;
-
- for (i = 0; i < f->count; i++) {
- ext_ctrl = (f->controls + i);
-
- ctrl.id = ext_ctrl->id;
-
- ret = mfc_dec_get_ctrl_val(ctx, &ctrl);
- if (ret == 0) {
- ext_ctrl->value = ctrl.value;
- } else {
- f->error_idx = i;
- break;
- }
-
- mfc_debug(5, "[CTRLS][%d] id: %#x, value: %d\n",
- i, ext_ctrl->id, ext_ctrl->value);
- }
-
- return ret;
-}
-
-/* v4l2_ioctl_ops */
-static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = {
- .vidioc_querycap = vidioc_querycap,
- .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane,
- .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane,
- .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_vid_cap_mplane,
- .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_vid_out_mplane,
- .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt,
- .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt,
- .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_vid_cap_mplane,
- .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_vid_out_mplane,
- .vidioc_reqbufs = vidioc_reqbufs,
- .vidioc_querybuf = vidioc_querybuf,
- .vidioc_qbuf = vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_g_crop = vidioc_g_crop,
- .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls,
-};
-
-const struct v4l2_ioctl_ops *s5p_mfc_get_dec_v4l2_ioctl_ops(void)
-{
- return &s5p_mfc_dec_ioctl_ops;
-}
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_dec.h
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __S5P_MFC_DEC_H
-#define __S5P_MFC_DEC_H __FILE__
-
-#include "s5p_mfc_common.h"
-
-const struct v4l2_ioctl_ops *s5p_mfc_get_dec_v4l2_ioctl_ops(void);
-
-#endif /* __S5P_MFC_DEC_H */
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_dec_internal.h
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __S5P_MFC_DEC_INTERNAL_H
-#define __S5P_MFC_DEC_INTERNAL_H __FILE__
-
-#include "s5p_mfc_common.h"
-
-struct s5p_mfc_fmt dec_formats[] = {
- {
- .name = "4:2:0 3 Planes Y/Cb/Cr",
- .fourcc = V4L2_PIX_FMT_YUV420M,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME,
- .num_planes = 3,
- .mem_planes = 3,
- },
- {
- .name = "4:2:0 3 Planes Y/Cb/Cr single",
- .fourcc = V4L2_PIX_FMT_YUV420N,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME,
- .num_planes = 3,
- .mem_planes = 1,
- },
- {
- .name = "4:2:0 3 Planes Y/Cr/Cb",
- .fourcc = V4L2_PIX_FMT_YVU420M,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME,
- .num_planes = 3,
- .mem_planes = 3,
- },
- {
- .name = "4:2:0 2 Planes Y/CbCr",
- .fourcc = V4L2_PIX_FMT_NV12M,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME,
- .num_planes = 2,
- .mem_planes = 2,
- },
- {
- .name = "4:2:0 2 Planes Y/CbCr single",
- .fourcc = V4L2_PIX_FMT_NV12N,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME,
- .num_planes = 2,
- .mem_planes = 1,
- },
- {
- .name = "4:2:0 2 Planes Y/CbCr 8+2 10bit",
- .fourcc = V4L2_PIX_FMT_NV12M_S10B,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME | MFC_FMT_10BIT,
- .num_planes = 2,
- .mem_planes = 2,
- },
- {
- .name = "4:2:0 2 Planes Y/CbCr 10bit single",
- .fourcc = V4L2_PIX_FMT_NV12N_10B,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME | MFC_FMT_10BIT,
- .num_planes = 2,
- .mem_planes = 1,
- },
- {
- .name = "4:2:0 2 Planes Y/CbCr P010 10bit",
- .fourcc = V4L2_PIX_FMT_NV12M_P010,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME | MFC_FMT_10BIT,
- .num_planes = 2,
- .mem_planes = 2,
- },
- {
- .name = "4:2:0 2 Planes Y/CrCb",
- .fourcc = V4L2_PIX_FMT_NV21M,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME,
- .num_planes = 2,
- .mem_planes = 2,
- },
- {
- .name = "4:2:0 2 Planes Y/CrCb 8+2 10bit",
- .fourcc = V4L2_PIX_FMT_NV21M_S10B,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME | MFC_FMT_10BIT,
- .num_planes = 2,
- .mem_planes = 2,
- },
- {
- .name = "4:2:0 2 Planes Y/CrCb P010 10bit",
- .fourcc = V4L2_PIX_FMT_NV21M_P010,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME | MFC_FMT_10BIT,
- .num_planes = 2,
- .mem_planes = 2,
- },
- {
- .name = "4:2:2 2 Planes Y/CbCr",
- .fourcc = V4L2_PIX_FMT_NV16M,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME | MFC_FMT_422,
- .num_planes = 2,
- .mem_planes = 2,
- },
- {
- .name = "4:2:2 2 Planes Y/CbCr 8+2 10bit",
- .fourcc = V4L2_PIX_FMT_NV16M_S10B,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME | MFC_FMT_10BIT | MFC_FMT_422,
- .num_planes = 2,
- .mem_planes = 2,
- },
- {
- .name = "4:2:2 2 Planes Y/CbCr P210 10bit",
- .fourcc = V4L2_PIX_FMT_NV16M_P210,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME | MFC_FMT_10BIT | MFC_FMT_422,
- .num_planes = 2,
- .mem_planes = 2,
- },
- {
- .name = "4:2:2 2 Planes Y/CrCb",
- .fourcc = V4L2_PIX_FMT_NV61M,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME | MFC_FMT_422,
- .num_planes = 2,
- .mem_planes = 2,
- },
- {
- .name = "4:2:2 2 Planes Y/CrCb 8+2 10bit",
- .fourcc = V4L2_PIX_FMT_NV61M_S10B,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME | MFC_FMT_10BIT | MFC_FMT_422,
- .num_planes = 2,
- .mem_planes = 2,
- },
- {
- .name = "4:2:2 2 Planes Y/CrCb P210 10bit",
- .fourcc = V4L2_PIX_FMT_NV61M_P210,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME | MFC_FMT_10BIT | MFC_FMT_422,
- .num_planes = 2,
- .mem_planes = 2,
- },
- {
- .name = "H264 Encoded Stream",
- .fourcc = V4L2_PIX_FMT_H264,
- .codec_mode = S5P_FIMV_CODEC_H264_DEC,
- .type = MFC_FMT_STREAM,
- .num_planes = 1,
- .mem_planes = 1,
- },
- {
- .name = "H264/MVC Encoded Stream",
- .fourcc = V4L2_PIX_FMT_H264_MVC,
- .codec_mode = S5P_FIMV_CODEC_H264_MVC_DEC,
- .type = MFC_FMT_STREAM,
- .num_planes = 1,
- .mem_planes = 1,
- },
- {
- .name = "H263 Encoded Stream",
- .fourcc = V4L2_PIX_FMT_H263,
- .codec_mode = S5P_FIMV_CODEC_H263_DEC,
- .type = MFC_FMT_STREAM,
- .num_planes = 1,
- .mem_planes = 1,
- },
- {
- .name = "MPEG1 Encoded Stream",
- .fourcc = V4L2_PIX_FMT_MPEG1,
- .codec_mode = S5P_FIMV_CODEC_MPEG2_DEC,
- .type = MFC_FMT_STREAM,
- .num_planes = 1,
- .mem_planes = 1,
- },
- {
- .name = "MPEG2 Encoded Stream",
- .fourcc = V4L2_PIX_FMT_MPEG2,
- .codec_mode = S5P_FIMV_CODEC_MPEG2_DEC,
- .type = MFC_FMT_STREAM,
- .num_planes = 1,
- .mem_planes = 1,
- },
- {
- .name = "MPEG4 Encoded Stream",
- .fourcc = V4L2_PIX_FMT_MPEG4,
- .codec_mode = S5P_FIMV_CODEC_MPEG4_DEC,
- .type = MFC_FMT_STREAM,
- .num_planes = 1,
- .mem_planes = 1,
- },
- {
- .name = "FIMV Encoded Stream",
- .fourcc = V4L2_PIX_FMT_FIMV,
- .codec_mode = S5P_FIMV_CODEC_MPEG4_DEC,
- .type = MFC_FMT_STREAM,
- .num_planes = 1,
- .mem_planes = 1,
- },
- {
- .name = "FIMV1 Encoded Stream",
- .fourcc = V4L2_PIX_FMT_FIMV1,
- .codec_mode = S5P_FIMV_CODEC_FIMV1_DEC,
- .type = MFC_FMT_STREAM,
- .num_planes = 1,
- .mem_planes = 1,
- },
- {
- .name = "FIMV2 Encoded Stream",
- .fourcc = V4L2_PIX_FMT_FIMV2,
- .codec_mode = S5P_FIMV_CODEC_FIMV2_DEC,
- .type = MFC_FMT_STREAM,
- .num_planes = 1,
- .mem_planes = 1,
- },
- {
- .name = "FIMV3 Encoded Stream",
- .fourcc = V4L2_PIX_FMT_FIMV3,
- .codec_mode = S5P_FIMV_CODEC_FIMV3_DEC,
- .type = MFC_FMT_STREAM,
- .num_planes = 1,
- .mem_planes = 1,
- },
- {
- .name = "FIMV4 Encoded Stream",
- .fourcc = V4L2_PIX_FMT_FIMV4,
- .codec_mode = S5P_FIMV_CODEC_FIMV4_DEC,
- .type = MFC_FMT_STREAM,
- .num_planes = 1,
- .mem_planes = 1,
- },
- {
- .name = "XviD Encoded Stream",
- .fourcc = V4L2_PIX_FMT_XVID,
- .codec_mode = S5P_FIMV_CODEC_MPEG4_DEC,
- .type = MFC_FMT_STREAM,
- .num_planes = 1,
- .mem_planes = 1,
- },
- {
- .name = "VC1 Encoded Stream",
- .fourcc = V4L2_PIX_FMT_VC1_ANNEX_G,
- .codec_mode = S5P_FIMV_CODEC_VC1_DEC,
- .type = MFC_FMT_STREAM,
- .num_planes = 1,
- .mem_planes = 1,
- },
- {
- .name = "VC1 RCV Encoded Stream",
- .fourcc = V4L2_PIX_FMT_VC1_ANNEX_L,
- .codec_mode = S5P_FIMV_CODEC_VC1_RCV_DEC,
- .type = MFC_FMT_STREAM,
- .num_planes = 1,
- .mem_planes = 1,
- },
- {
- .name = "VP8 Encoded Stream",
- .fourcc = V4L2_PIX_FMT_VP8,
- .codec_mode = S5P_FIMV_CODEC_VP8_DEC,
- .type = MFC_FMT_STREAM,
- .num_planes = 1,
- .mem_planes = 1,
- },
- {
- .name = "VP9 Encoded Stream",
- .fourcc = V4L2_PIX_FMT_VP9,
- .codec_mode = S5P_FIMV_CODEC_VP9_DEC,
- .type = MFC_FMT_STREAM,
- .num_planes = 1,
- .mem_planes = 1,
- },
- {
- .name = "HEVC Encoded Stream",
- .fourcc = V4L2_PIX_FMT_HEVC,
- .codec_mode = S5P_FIMV_CODEC_HEVC_DEC,
- .type = MFC_FMT_STREAM,
- .num_planes = 1,
- .mem_planes = 1,
- },
- {
- .name = "BPG Encoded Stream",
- .fourcc = V4L2_PIX_FMT_BPG,
- .codec_mode = S5P_FIMV_CODEC_BPG_DEC,
- .type = MFC_FMT_STREAM,
- .num_planes = 1,
- .mem_planes = 1,
- },
-};
-
-#define NUM_FORMATS ARRAY_SIZE(dec_formats)
-
-static struct v4l2_queryctrl controls[] = {
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "H.264 Display Delay",
- .minimum = -1,
- .maximum = 32,
- .step = 1,
- .default_value = -1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Mpeg4 Loop Filter Enable",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Slice Interface Enable",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_PACKED_PB,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Packed PB Enable",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Frame Tag",
- .minimum = 0,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_CACHEABLE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Cacheable flag",
- .minimum = 0,
- .maximum = 3,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_CRC_ENABLE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "CRC enable",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_LUMA,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "CRC data",
- .minimum = 0,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_CHROMA,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "CRC data",
- .minimum = 0,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_DISPLAY_STATUS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Display status",
- .minimum = 0,
- .maximum = 3,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TYPE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Frame type",
- .minimum = 0,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Frame pack sei parse flag",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_I_FRAME_DECODING,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "I frame decoding mode",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_RATE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Frames per second in 1000x scale",
- .minimum = 1,
- .maximum = 480000,
- .step = 1,
- .default_value = 60000,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_DECODER_IMMEDIATE_DISPLAY,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Immediate Display Enable",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_DECODER_DECODING_TIMESTAMP_MODE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Decoding Timestamp Mode Enable",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_DECODER_WAIT_DECODING_START,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Wait until buffer setting done",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC_GET_VERSION_INFO,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Get MFC version information",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC_SET_DUAL_DPB_MODE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Set Dual DPB mode",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_QOS_RATIO,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "QoS ratio value",
- .minimum = 20,
- .maximum = 1000,
- .step = 10,
- .default_value = 100,
- },
- {
- .id = V4L2_CID_MPEG_MFC_SET_DYNAMIC_DPB_MODE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Set dynamic DPB",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC_SET_USER_SHARED_HANDLE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Set dynamic DPB",
- .minimum = 0,
- .maximum = 65535,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC_GET_EXT_INFO,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Get extra information",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC_SET_BUF_PROCESS_TYPE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Set buffer process type",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC_GET_10BIT_INFO,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "10 bit contents information",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_BLACK_BAR_DETECT,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Set black bar detection option",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
-};
-
-#define NUM_CTRLS ARRAY_SIZE(controls)
-
-#endif /* __S5P_MFC_DEC_INTERNAL_H */
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_dec_ops.c
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include "s5p_mfc_common.h"
-
-#include "s5p_mfc_reg.h"
-
-#define NUM_CTRL_CFGS ARRAY_SIZE(mfc_ctrl_list)
-
-struct s5p_mfc_ctrl_cfg mfc_ctrl_list[] = {
- {
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_D_PICTURE_TAG,
- .mask = 0xFFFFFFFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_NONE,
- .flag_addr = 0,
- .flag_shft = 0,
- },
- {
- .type = MFC_CTRL_TYPE_GET_DST,
- .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG,
- .is_volatile = 0,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_D_RET_PICTURE_TAG_TOP,
- .mask = 0xFFFFFFFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_NONE,
- .flag_addr = 0,
- .flag_shft = 0,
- },
- {
- .type = MFC_CTRL_TYPE_GET_DST,
- .id = V4L2_CID_MPEG_MFC51_VIDEO_DISPLAY_STATUS,
- .is_volatile = 0,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_D_DISPLAY_STATUS,
- .mask = 0x7,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_NONE,
- .flag_addr = 0,
- .flag_shft = 0,
- },
- /* CRC related definitions are based on non-H.264 type */
- {
- .type = MFC_CTRL_TYPE_GET_DST,
- .id = V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_LUMA,
- .is_volatile = 0,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_D_DISPLAY_FIRST_PLANE_CRC,
- .mask = 0xFFFFFFFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_NONE,
- .flag_addr = 0,
- .flag_shft = 0,
- },
- {
- .type = MFC_CTRL_TYPE_GET_DST,
- .id = V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_CHROMA,
- .is_volatile = 0,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_D_DISPLAY_SECOND_PLANE_CRC,
- .mask = 0xFFFFFFFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_NONE,
- .flag_addr = 0,
- .flag_shft = 0,
- },
- {
- .type = MFC_CTRL_TYPE_GET_DST,
- .id = V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_CHROMA1,
- .is_volatile = 0,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_D_DISPLAY_THIRD_PLANE_CRC,
- .mask = 0xFFFFFFFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_NONE,
- .flag_addr = 0,
- .flag_shft = 0,
- },
- {
- .type = MFC_CTRL_TYPE_GET_DST,
- .id = V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_2BIT_LUMA,
- .is_volatile = 0,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_D_DISPLAY_FIRST_PLANE_2BIT_CRC,
- .mask = 0xFFFFFFFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_NONE,
- .flag_addr = 0,
- .flag_shft = 0,
- },
- {
- .type = MFC_CTRL_TYPE_GET_DST,
- .id = V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_2BIT_CHROMA,
- .is_volatile = 0,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_D_DISPLAY_SECOND_PLANE_2BIT_CRC,
- .mask = 0xFFFFFFFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_NONE,
- .flag_addr = 0,
- .flag_shft = 0,
- },
- {
- .type = MFC_CTRL_TYPE_GET_DST,
- .id = V4L2_CID_MPEG_MFC51_VIDEO_CRC_GENERATED,
- .is_volatile = 0,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_D_DISPLAY_STATUS,
- .mask = 0x1,
- .shft = 6,
- .flag_mode = MFC_CTRL_MODE_NONE,
- .flag_addr = 0,
- .flag_shft = 0,
- },
- {
- .type = MFC_CTRL_TYPE_GET_DST,
- .id = V4L2_CID_MPEG_VIDEO_H264_SEI_FP_AVAIL,
- .is_volatile = 0,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_D_SEI_AVAIL,
- .mask = 0x1,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_NONE,
- .flag_addr = 0,
- .flag_shft = 0,
- },
- {
- .type = MFC_CTRL_TYPE_GET_DST,
- .id = V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRGMENT_ID,
- .is_volatile = 0,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_D_FRAME_PACK_ARRGMENT_ID,
- .mask = 0xFFFFFFFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_NONE,
- .flag_addr = 0,
- .flag_shft = 0,
- },
- {
- .type = MFC_CTRL_TYPE_GET_DST,
- .id = V4L2_CID_MPEG_VIDEO_H264_SEI_FP_INFO,
- .is_volatile = 0,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_D_FRAME_PACK_SEI_INFO,
- .mask = 0x3FFFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_NONE,
- .flag_addr = 0,
- .flag_shft = 0,
- },
- {
- .type = MFC_CTRL_TYPE_GET_DST,
- .id = V4L2_CID_MPEG_VIDEO_H264_SEI_FP_GRID_POS,
- .is_volatile = 0,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_D_FRAME_PACK_GRID_POS,
- .mask = 0xFFFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_NONE,
- .flag_addr = 0,
- .flag_shft = 0,
- },
- {
- .type = MFC_CTRL_TYPE_GET_DST,
- .id = V4L2_CID_MPEG_VIDEO_H264_MVC_VIEW_ID,
- .is_volatile = 0,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_D_MVC_VIEW_ID,
- .mask = 0xFFFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_NONE,
- .flag_addr = 0,
- .flag_shft = 0,
- },
- {
- .type = MFC_CTRL_TYPE_GET_DST,
- .id = V4L2_CID_MPEG_VIDEO_SEI_MAX_PIC_AVERAGE_LIGHT,
- .is_volatile = 0,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_D_CONTENT_LIGHT_LEVEL_INFO_SEI,
- .mask = 0xFFFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_NONE,
- .flag_addr = 0,
- .flag_shft = 0,
- },
- {
- .type = MFC_CTRL_TYPE_GET_DST,
- .id = V4L2_CID_MPEG_VIDEO_SEI_MAX_CONTENT_LIGHT,
- .is_volatile = 0,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_D_CONTENT_LIGHT_LEVEL_INFO_SEI,
- .mask = 0xFFFF,
- .shft = 16,
- .flag_mode = MFC_CTRL_MODE_NONE,
- .flag_addr = 0,
- .flag_shft = 0,
- },
- {
- .type = MFC_CTRL_TYPE_GET_DST,
- .id = V4L2_CID_MPEG_VIDEO_SEI_MAX_DISPLAY_LUMINANCE,
- .is_volatile = 0,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_0,
- .mask = 0xFFFFFFFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_NONE,
- .flag_addr = 0,
- .flag_shft = 0,
- },
- {
- .type = MFC_CTRL_TYPE_GET_DST,
- .id = V4L2_CID_MPEG_VIDEO_SEI_MIN_DISPLAY_LUMINANCE,
- .is_volatile = 0,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_1,
- .mask = 0xFFFFFFFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_NONE,
- .flag_addr = 0,
- .flag_shft = 0,
- },
- {
- .type = MFC_CTRL_TYPE_GET_DST,
- .id = V4L2_CID_MPEG_VIDEO_MATRIX_COEFFICIENTS,
- .is_volatile = 0,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_D_VIDEO_SIGNAL_TYPE,
- .mask = 0xFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_NONE,
- .flag_addr = 0,
- .flag_shft = 0,
- },
- {
- .type = MFC_CTRL_TYPE_GET_DST,
- .id = V4L2_CID_MPEG_VIDEO_FORMAT,
- .is_volatile = 0,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_D_VIDEO_SIGNAL_TYPE,
- .mask = 0x7,
- .shft = 26,
- .flag_mode = MFC_CTRL_MODE_NONE,
- .flag_addr = 0,
- .flag_shft = 0,
- },
- {
- .type = MFC_CTRL_TYPE_GET_DST,
- .id = V4L2_CID_MPEG_VIDEO_FULL_RANGE_FLAG,
- .is_volatile = 0,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_D_VIDEO_SIGNAL_TYPE,
- .mask = 0x1,
- .shft = 25,
- .flag_mode = MFC_CTRL_MODE_NONE,
- .flag_addr = 0,
- .flag_shft = 0,
- },
- {
- .type = MFC_CTRL_TYPE_GET_DST,
- .id = V4L2_CID_MPEG_VIDEO_COLOUR_PRIMARIES,
- .is_volatile = 0,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_D_VIDEO_SIGNAL_TYPE,
- .mask = 0xFF,
- .shft = 16,
- .flag_mode = MFC_CTRL_MODE_NONE,
- .flag_addr = 0,
- .flag_shft = 0,
- },
- {
- .type = MFC_CTRL_TYPE_GET_DST,
- .id = V4L2_CID_MPEG_VIDEO_TRANSFER_CHARACTERISTICS,
- .is_volatile = 0,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_D_VIDEO_SIGNAL_TYPE,
- .mask = 0xFF,
- .shft = 8,
- .flag_mode = MFC_CTRL_MODE_NONE,
- .flag_addr = 0,
- .flag_shft = 0,
- },
- {
- .type = MFC_CTRL_TYPE_GET_DST,
- .id = V4L2_CID_MPEG_VIDEO_SEI_WHITE_POINT,
- .is_volatile = 0,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_2,
- .mask = 0xFFFFFFFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_NONE,
- .flag_addr = 0,
- .flag_shft = 0,
- },
- {
- .type = MFC_CTRL_TYPE_GET_DST,
- .id = V4L2_CID_MPEG_VIDEO_SEI_DISPLAY_PRIMARIES_0,
- .is_volatile = 0,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_3,
- .mask = 0xFFFFFFFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_NONE,
- .flag_addr = 0,
- .flag_shft = 0,
- },
- {
- .type = MFC_CTRL_TYPE_GET_DST,
- .id = V4L2_CID_MPEG_VIDEO_SEI_DISPLAY_PRIMARIES_1,
- .is_volatile = 0,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_4,
- .mask = 0xFFFFFFFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_NONE,
- .flag_addr = 0,
- .flag_shft = 0,
- },
- {
- .type = MFC_CTRL_TYPE_GET_DST,
- .id = V4L2_CID_MPEG_VIDEO_SEI_DISPLAY_PRIMARIES_2,
- .is_volatile = 0,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_5,
- .mask = 0xFFFFFFFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_NONE,
- .flag_addr = 0,
- .flag_shft = 0,
- },
-};
-
-static int s5p_mfc_dec_cleanup_ctx_ctrls(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_ctx_ctrl *ctx_ctrl;
-
- while (!list_empty(&ctx->ctrls)) {
- ctx_ctrl = list_entry((&ctx->ctrls)->next,
- struct s5p_mfc_ctx_ctrl, list);
- list_del(&ctx_ctrl->list);
- kfree(ctx_ctrl);
- }
-
- INIT_LIST_HEAD(&ctx->ctrls);
-
- return 0;
-}
-
-static int s5p_mfc_dec_init_ctx_ctrls(struct s5p_mfc_ctx *ctx)
-{
- unsigned long i;
- struct s5p_mfc_ctx_ctrl *ctx_ctrl;
-
- INIT_LIST_HEAD(&ctx->ctrls);
-
- for (i = 0; i < NUM_CTRL_CFGS; i++) {
- ctx_ctrl = kzalloc(sizeof(struct s5p_mfc_ctx_ctrl), GFP_KERNEL);
- if (ctx_ctrl == NULL) {
- mfc_err_dev("Failed to allocate context control "\
- "id: 0x%08x, type: %d\n",
- mfc_ctrl_list[i].id,
- mfc_ctrl_list[i].type);
-
- s5p_mfc_dec_cleanup_ctx_ctrls(ctx);
-
- return -ENOMEM;
- }
-
- ctx_ctrl->type = mfc_ctrl_list[i].type;
- ctx_ctrl->id = mfc_ctrl_list[i].id;
- ctx_ctrl->addr = mfc_ctrl_list[i].addr;
- ctx_ctrl->has_new = 0;
- ctx_ctrl->val = 0;
-
- list_add_tail(&ctx_ctrl->list, &ctx->ctrls);
- }
-
- return 0;
-}
-
-static void mfc_dec_remove_buf_ctrls(struct list_head *head)
-{
- struct s5p_mfc_buf_ctrl *buf_ctrl;
-
- while (!list_empty(head)) {
- buf_ctrl = list_entry(head->next,
- struct s5p_mfc_buf_ctrl, list);
- list_del(&buf_ctrl->list);
- kfree(buf_ctrl);
- }
-
- INIT_LIST_HEAD(head);
-}
-
-static void s5p_mfc_dec_reset_buf_ctrls(struct list_head *head)
-{
- struct s5p_mfc_buf_ctrl *buf_ctrl;
-
- list_for_each_entry(buf_ctrl, head, list) {
- buf_ctrl->has_new = 0;
- buf_ctrl->val = 0;
- buf_ctrl->old_val = 0;
- buf_ctrl->updated = 0;
- }
-}
-
-static int s5p_mfc_dec_init_buf_ctrls(struct s5p_mfc_ctx *ctx,
- enum s5p_mfc_ctrl_type type, unsigned int index)
-{
- unsigned long i;
- struct s5p_mfc_ctx_ctrl *ctx_ctrl;
- struct s5p_mfc_buf_ctrl *buf_ctrl;
- struct list_head *head;
-
- if (index >= MFC_MAX_BUFFERS) {
- mfc_err_dev("Per-buffer control index is out of range\n");
- return -EINVAL;
- }
-
- if (type & MFC_CTRL_TYPE_SRC) {
- if (test_bit(index, &ctx->src_ctrls_avail)) {
- s5p_mfc_dec_reset_buf_ctrls(&ctx->src_ctrls[index]);
-
- return 0;
- }
-
- head = &ctx->src_ctrls[index];
- } else if (type & MFC_CTRL_TYPE_DST) {
- if (test_bit(index, &ctx->dst_ctrls_avail)) {
- s5p_mfc_dec_reset_buf_ctrls(&ctx->dst_ctrls[index]);
-
- return 0;
- }
-
- head = &ctx->dst_ctrls[index];
- } else {
- mfc_err_dev("Control type mismatch. type : %d\n", type);
- return -EINVAL;
- }
-
- INIT_LIST_HEAD(head);
-
- list_for_each_entry(ctx_ctrl, &ctx->ctrls, list) {
- if (!(type & ctx_ctrl->type))
- continue;
-
- /* find matched control configuration index */
- for (i = 0; i < NUM_CTRL_CFGS; i++) {
- if (ctx_ctrl->id == mfc_ctrl_list[i].id)
- break;
- }
-
- if (i == NUM_CTRL_CFGS) {
- mfc_err_dev("Failed to find buffer control "\
- "id: 0x%08x, type: %d\n",
- ctx_ctrl->id, ctx_ctrl->type);
- continue;
- }
-
- buf_ctrl = kzalloc(sizeof(struct s5p_mfc_buf_ctrl), GFP_KERNEL);
- if (buf_ctrl == NULL) {
- mfc_err_dev("Failed to allocate buffer control "\
- "id: 0x%08x, type: %d\n",
- mfc_ctrl_list[i].id,
- mfc_ctrl_list[i].type);
-
- mfc_dec_remove_buf_ctrls(head);
-
- return -ENOMEM;
- }
-
- buf_ctrl->id = ctx_ctrl->id;
- buf_ctrl->type = ctx_ctrl->type;
- buf_ctrl->addr = ctx_ctrl->addr;
-
- buf_ctrl->is_volatile = mfc_ctrl_list[i].is_volatile;
- buf_ctrl->mode = mfc_ctrl_list[i].mode;
- buf_ctrl->mask = mfc_ctrl_list[i].mask;
- buf_ctrl->shft = mfc_ctrl_list[i].shft;
- buf_ctrl->flag_mode = mfc_ctrl_list[i].flag_mode;
- buf_ctrl->flag_addr = mfc_ctrl_list[i].flag_addr;
- buf_ctrl->flag_shft = mfc_ctrl_list[i].flag_shft;
-
- list_add_tail(&buf_ctrl->list, head);
- }
-
- s5p_mfc_dec_reset_buf_ctrls(head);
-
- if (type & MFC_CTRL_TYPE_SRC)
- set_bit(index, &ctx->src_ctrls_avail);
- else
- set_bit(index, &ctx->dst_ctrls_avail);
-
- return 0;
-}
-
-static int s5p_mfc_dec_cleanup_buf_ctrls(struct s5p_mfc_ctx *ctx,
- enum s5p_mfc_ctrl_type type, unsigned int index)
-{
- struct list_head *head;
-
- if (index >= MFC_MAX_BUFFERS) {
- mfc_err_dev("Per-buffer control index is out of range\n");
- return -EINVAL;
- }
-
- if (type & MFC_CTRL_TYPE_SRC) {
- if (!(test_and_clear_bit(index, &ctx->src_ctrls_avail))) {
- return 0;
- }
-
- head = &ctx->src_ctrls[index];
- } else if (type & MFC_CTRL_TYPE_DST) {
- if (!(test_and_clear_bit(index, &ctx->dst_ctrls_avail))) {
- return 0;
- }
-
- head = &ctx->dst_ctrls[index];
- } else {
- mfc_err_dev("Control type mismatch. type : %d\n", type);
- return -EINVAL;
- }
-
- mfc_dec_remove_buf_ctrls(head);
-
- return 0;
-}
-
-static int s5p_mfc_dec_to_buf_ctrls(struct s5p_mfc_ctx *ctx, struct list_head *head)
-{
- struct s5p_mfc_ctx_ctrl *ctx_ctrl;
- struct s5p_mfc_buf_ctrl *buf_ctrl;
-
- list_for_each_entry(ctx_ctrl, &ctx->ctrls, list) {
- if (!(ctx_ctrl->type & MFC_CTRL_TYPE_SET) || !ctx_ctrl->has_new)
- continue;
-
- list_for_each_entry(buf_ctrl, head, list) {
- if (!(buf_ctrl->type & MFC_CTRL_TYPE_SET))
- continue;
-
- if (buf_ctrl->id == ctx_ctrl->id) {
- buf_ctrl->has_new = 1;
- buf_ctrl->val = ctx_ctrl->val;
- if (buf_ctrl->is_volatile)
- buf_ctrl->updated = 0;
-
- ctx_ctrl->has_new = 0;
- break;
- }
- }
- }
-
- return 0;
-}
-
-static int s5p_mfc_dec_to_ctx_ctrls(struct s5p_mfc_ctx *ctx, struct list_head *head)
-{
- struct s5p_mfc_ctx_ctrl *ctx_ctrl;
- struct s5p_mfc_buf_ctrl *buf_ctrl;
-
- list_for_each_entry(buf_ctrl, head, list) {
- if (!(buf_ctrl->type & MFC_CTRL_TYPE_GET) || !buf_ctrl->has_new)
- continue;
-
- list_for_each_entry(ctx_ctrl, &ctx->ctrls, list) {
- if (!(ctx_ctrl->type & MFC_CTRL_TYPE_GET))
- continue;
-
- if (ctx_ctrl->id == buf_ctrl->id) {
- ctx_ctrl->has_new = 1;
- ctx_ctrl->val = buf_ctrl->val;
-
- buf_ctrl->has_new = 0;
- }
- }
- }
-
- return 0;
-}
-
-static int s5p_mfc_dec_set_buf_ctrls_val(struct s5p_mfc_ctx *ctx, struct list_head *head)
-{
- struct s5p_mfc_buf_ctrl *buf_ctrl;
- struct s5p_mfc_dec *dec = ctx->dec_priv;
- struct s5p_mfc_dev *dev = ctx->dev;
- unsigned int value = 0;
-
- list_for_each_entry(buf_ctrl, head, list) {
- if (!(buf_ctrl->type & MFC_CTRL_TYPE_SET) || !buf_ctrl->has_new)
- continue;
-
- /* read old vlaue */
- value = MFC_READL(buf_ctrl->addr);
-
- /* save old vlaue for recovery */
- if (buf_ctrl->is_volatile)
- buf_ctrl->old_val = (value >> buf_ctrl->shft) & buf_ctrl->mask;
-
- /* write new value */
- value &= ~(buf_ctrl->mask << buf_ctrl->shft);
- value |= ((buf_ctrl->val & buf_ctrl->mask) << buf_ctrl->shft);
- MFC_WRITEL(value, buf_ctrl->addr);
-
- /* set change flag bit */
- if (buf_ctrl->flag_mode == MFC_CTRL_MODE_SFR) {
- value = MFC_READL(buf_ctrl->flag_addr);
- value |= (1 << buf_ctrl->flag_shft);
- MFC_WRITEL(value, buf_ctrl->flag_addr);
- }
-
- buf_ctrl->has_new = 0;
- buf_ctrl->updated = 1;
-
- if (buf_ctrl->id == V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG)
- dec->stored_tag = buf_ctrl->val;
-
- mfc_debug(6, "[CTRLS] Set buffer control id: 0x%08x, val: %d\n",
- buf_ctrl->id, buf_ctrl->val);
- }
-
- return 0;
-}
-
-static int s5p_mfc_dec_get_buf_ctrls_val(struct s5p_mfc_ctx *ctx, struct list_head *head)
-{
- struct s5p_mfc_buf_ctrl *buf_ctrl;
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_dec *dec = ctx->dec_priv;
- unsigned int value = 0;
-
- list_for_each_entry(buf_ctrl, head, list) {
- if (!(buf_ctrl->type & MFC_CTRL_TYPE_GET))
- continue;
-
- value = MFC_READL(buf_ctrl->addr);
- value = (value >> buf_ctrl->shft) & buf_ctrl->mask;
-
- buf_ctrl->val = value;
- buf_ctrl->has_new = 1;
-
- if (IS_VP9_DEC(ctx)) {
- if (buf_ctrl->id == V4L2_CID_MPEG_VIDEO_FULL_RANGE_FLAG)
- buf_ctrl->val = dec->color_range;
- else if (buf_ctrl->id == V4L2_CID_MPEG_VIDEO_COLOUR_PRIMARIES)
- buf_ctrl->val = dec->color_space;
- }
-
- mfc_debug(6, "[CTRLS] Get buffer control id: 0x%08x, val: %d\n",
- buf_ctrl->id, buf_ctrl->val);
- }
-
- return 0;
-}
-
-static int s5p_mfc_dec_set_buf_ctrls_val_nal_q_dec(struct s5p_mfc_ctx *ctx,
- struct list_head *head, DecoderInputStr *pInStr)
-{
- struct s5p_mfc_buf_ctrl *buf_ctrl;
- struct s5p_mfc_dec *dec = ctx->dec_priv;
-
- mfc_debug_enter();
-
- list_for_each_entry(buf_ctrl, head, list) {
- if (!(buf_ctrl->type & MFC_CTRL_TYPE_SET) || !buf_ctrl->has_new)
- continue;
- switch (buf_ctrl->id) {
- case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG:
- pInStr->PictureTag &= ~(buf_ctrl->mask << buf_ctrl->shft);
- pInStr->PictureTag |=
- (buf_ctrl->val & buf_ctrl->mask) << buf_ctrl->shft;
- dec->stored_tag = buf_ctrl->val;
- break;
- /* If new dynamic controls are added, insert here */
- default:
- mfc_info_ctx("[NALQ] can't find control, id: 0x%x\n",
- buf_ctrl->id);
- }
- buf_ctrl->has_new = 0;
- buf_ctrl->updated = 1;
-
- mfc_debug(6, "[NALQ][CTRLS] Set buffer control id: 0x%08x, val: %d\n",
- buf_ctrl->id, buf_ctrl->val);
- }
-
- mfc_debug_leave();
-
- return 0;
-}
-
-static int s5p_mfc_dec_get_buf_ctrls_val_nal_q_dec(struct s5p_mfc_ctx *ctx,
- struct list_head *head, DecoderOutputStr *pOutStr)
-{
- struct s5p_mfc_dec *dec = ctx->dec_priv;
- struct s5p_mfc_buf_ctrl *buf_ctrl;
- unsigned int value = 0;
-
- mfc_debug_enter();
-
- list_for_each_entry(buf_ctrl, head, list) {
- if (!(buf_ctrl->type & MFC_CTRL_TYPE_GET))
- continue;
- switch (buf_ctrl->id) {
- case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG:
- value = pOutStr->PictureTagTop;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_DISPLAY_STATUS:
- value = pOutStr->DisplayStatus;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_LUMA:
- value = pOutStr->DisplayFirstCrc;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_CHROMA:
- value = pOutStr->DisplaySecondCrc;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_CHROMA1:
- value = pOutStr->DisplayThirdCrc;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_2BIT_LUMA:
- value = pOutStr->DisplayFirst2BitCrc;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_2BIT_CHROMA:
- value = pOutStr->DisplaySecond2BitCrc;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_CRC_GENERATED:
- value = pOutStr->DisplayStatus;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_AVAIL:
- value = pOutStr->SeiAvail;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRGMENT_ID:
- value = pOutStr->FramePackArrgmentId;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_INFO:
- value = pOutStr->FramePackSeiInfo;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_GRID_POS:
- value = pOutStr->FramePackGridPos;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_MVC_VIEW_ID:
- value = 0;
- break;
- /* TO-DO: SEI information has to be added in NAL-Q */
- case V4L2_CID_MPEG_VIDEO_SEI_MAX_PIC_AVERAGE_LIGHT:
- case V4L2_CID_MPEG_VIDEO_SEI_MAX_CONTENT_LIGHT:
- value = pOutStr->ContentLightLevelInfoSei;
- break;
- case V4L2_CID_MPEG_VIDEO_SEI_MAX_DISPLAY_LUMINANCE:
- value = pOutStr->MasteringDisplayColourVolumeSei0;
- break;
- case V4L2_CID_MPEG_VIDEO_SEI_MIN_DISPLAY_LUMINANCE:
- value = pOutStr->MasteringDisplayColourVolumeSei1;
- break;
- case V4L2_CID_MPEG_VIDEO_FULL_RANGE_FLAG:
- case V4L2_CID_MPEG_VIDEO_COLOUR_PRIMARIES:
- case V4L2_CID_MPEG_VIDEO_FORMAT:
- case V4L2_CID_MPEG_VIDEO_TRANSFER_CHARACTERISTICS:
- case V4L2_CID_MPEG_VIDEO_MATRIX_COEFFICIENTS:
- value = pOutStr->VideoSignalType;
- break;
- case V4L2_CID_MPEG_VIDEO_SEI_WHITE_POINT:
- value = pOutStr->MasteringDisplayColourVolumeSei2;
- break;
- case V4L2_CID_MPEG_VIDEO_SEI_DISPLAY_PRIMARIES_0:
- value = pOutStr->MasteringDisplayColourVolumeSei3;
- break;
- case V4L2_CID_MPEG_VIDEO_SEI_DISPLAY_PRIMARIES_1:
- value = pOutStr->MasteringDisplayColourVolumeSei4;
- break;
- case V4L2_CID_MPEG_VIDEO_SEI_DISPLAY_PRIMARIES_2:
- value = pOutStr->MasteringDisplayColourVolumeSei5;
- break;
- /* If new dynamic controls are added, insert here */
- default:
- mfc_info_ctx("[NALQ] can't find control, id: 0x%x\n",
- buf_ctrl->id);
- }
- value = (value >> buf_ctrl->shft) & buf_ctrl->mask;
-
- buf_ctrl->val = value;
- buf_ctrl->has_new = 1;
-
- if (IS_VP9_DEC(ctx)) {
- if (buf_ctrl->id == V4L2_CID_MPEG_VIDEO_FULL_RANGE_FLAG)
- buf_ctrl->val = dec->color_range;
- else if (buf_ctrl->id == V4L2_CID_MPEG_VIDEO_COLOUR_PRIMARIES)
- buf_ctrl->val = dec->color_space;
- }
-
- mfc_debug(6, "[NALQ][CTRLS] Get buffer control id: 0x%08x, val: %d\n",
- buf_ctrl->id, buf_ctrl->val);
- }
-
- mfc_debug_leave();
-
- return 0;
-}
-
-static int s5p_mfc_dec_recover_buf_ctrls_val(struct s5p_mfc_ctx *ctx, struct list_head *head)
-{
- struct s5p_mfc_buf_ctrl *buf_ctrl;
- struct s5p_mfc_dev *dev = ctx->dev;
- unsigned int value = 0;
-
- list_for_each_entry(buf_ctrl, head, list) {
- if (!(buf_ctrl->type & MFC_CTRL_TYPE_SET)
- || !buf_ctrl->is_volatile
- || !buf_ctrl->updated)
- continue;
-
- value = MFC_READL(buf_ctrl->addr);
- value &= ~(buf_ctrl->mask << buf_ctrl->shft);
- value |= ((buf_ctrl->old_val & buf_ctrl->mask) << buf_ctrl->shft);
- MFC_WRITEL(value, buf_ctrl->addr);
-
- /* clear change flag bit */
- if (buf_ctrl->flag_mode == MFC_CTRL_MODE_SFR) {
- value = MFC_READL(buf_ctrl->flag_addr);
- value &= ~(1 << buf_ctrl->flag_shft);
- MFC_WRITEL(value, buf_ctrl->flag_addr);
- }
-
- buf_ctrl->updated = 0;
- mfc_debug(6, "[CTRLS] Recover buffer control id: 0x%08x, old val: %d\n",
- buf_ctrl->id, buf_ctrl->old_val);
- }
-
- return 0;
-}
-
-static int s5p_mfc_dec_get_buf_update_val(struct s5p_mfc_ctx *ctx,
- struct list_head *head, unsigned int id, int value)
-{
- struct s5p_mfc_buf_ctrl *buf_ctrl;
-
- list_for_each_entry(buf_ctrl, head, list) {
- if (buf_ctrl->id == id) {
- buf_ctrl->val = value;
- mfc_debug(6, "[CTRLS] Update buffer control id: 0x%08x, val: %d\n",
- buf_ctrl->id, buf_ctrl->val);
- break;
- }
- }
-
- return 0;
-}
-
-static int s5p_mfc_dec_recover_buf_ctrls_nal_q(struct s5p_mfc_ctx *ctx,
- struct list_head *head)
-{
- struct s5p_mfc_buf_ctrl *buf_ctrl;
-
- list_for_each_entry(buf_ctrl, head, list) {
- if (!(buf_ctrl->type & MFC_CTRL_TYPE_SET)
- || !(buf_ctrl->updated))
- continue;
-
- buf_ctrl->has_new = 1;
- buf_ctrl->updated = 0;
- mfc_debug(6, "[NALQ][CTRLS] Recover buffer control id: 0x%08x, val: %d\n",
- buf_ctrl->id, buf_ctrl->val);
- }
-
- return 0;
-}
-
-struct s5p_mfc_ctrls_ops decoder_ctrls_ops = {
- .init_ctx_ctrls = s5p_mfc_dec_init_ctx_ctrls,
- .cleanup_ctx_ctrls = s5p_mfc_dec_cleanup_ctx_ctrls,
- .init_buf_ctrls = s5p_mfc_dec_init_buf_ctrls,
- .reset_buf_ctrls = s5p_mfc_dec_reset_buf_ctrls,
- .cleanup_buf_ctrls = s5p_mfc_dec_cleanup_buf_ctrls,
- .to_buf_ctrls = s5p_mfc_dec_to_buf_ctrls,
- .to_ctx_ctrls = s5p_mfc_dec_to_ctx_ctrls,
- .set_buf_ctrls_val = s5p_mfc_dec_set_buf_ctrls_val,
- .get_buf_ctrls_val = s5p_mfc_dec_get_buf_ctrls_val,
- .set_buf_ctrls_val_nal_q_dec = s5p_mfc_dec_set_buf_ctrls_val_nal_q_dec,
- .get_buf_ctrls_val_nal_q_dec = s5p_mfc_dec_get_buf_ctrls_val_nal_q_dec,
- .recover_buf_ctrls_val = s5p_mfc_dec_recover_buf_ctrls_val,
- .get_buf_update_val = s5p_mfc_dec_get_buf_update_val,
- .recover_buf_ctrls_nal_q = s5p_mfc_dec_recover_buf_ctrls_nal_q,
-};
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_dec_vb2_ops.c
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include "s5p_mfc_common.h"
-
-#include "s5p_mfc_hwlock.h"
-#include "s5p_mfc_nal_q.h"
-#include "s5p_mfc_opr.h"
-#include "s5p_mfc_sync.h"
-
-#include "s5p_mfc_queue.h"
-#include "s5p_mfc_utils.h"
-#include "s5p_mfc_buf.h"
-#include "s5p_mfc_mem.h"
-
-static int s5p_mfc_dec_queue_setup(struct vb2_queue *vq,
- unsigned int *buf_count, unsigned int *plane_count,
- unsigned int psize[], struct device *alloc_devs[])
-{
- struct s5p_mfc_ctx *ctx;
- struct s5p_mfc_dev *dev;
- struct s5p_mfc_dec *dec;
- struct s5p_mfc_raw_info *raw;
- int i;
-
- mfc_debug_enter();
-
- if (!vq) {
- mfc_err_dev("no vb2_queue info\n");
- return -EINVAL;
- }
-
- ctx = vq->drv_priv;
- if (!ctx) {
- mfc_err_dev("no mfc context to run\n");
- return -EINVAL;
- }
- dev = ctx->dev;
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
- dec = ctx->dec_priv;
- if (!dec) {
- mfc_err_dev("no mfc decoder to run\n");
- return -EINVAL;
- }
-
- raw = &ctx->raw_buf;
-
- /* Video output for decoding (source)
- * this can be set after getting an instance */
- if (ctx->state == MFCINST_GOT_INST &&
- vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- mfc_debug(4, "dec src\n");
- /* A single plane is required for input */
- *plane_count = 1;
- if (*buf_count < 1)
- *buf_count = 1;
- if (*buf_count > MFC_MAX_BUFFERS)
- *buf_count = MFC_MAX_BUFFERS;
-
- psize[0] = dec->src_buf_size;
- alloc_devs[0] = dev->device;
- /* Video capture for decoding (destination)
- * this can be set after the header was parsed */
- } else if (ctx->state == MFCINST_HEAD_PARSED &&
- vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- mfc_debug(4, "dec dst\n");
- /* Output plane count is different by the pixel format */
- *plane_count = ctx->dst_fmt->mem_planes;
- /* Setup buffer count */
- if (*buf_count < ctx->dpb_count)
- *buf_count = ctx->dpb_count;
- if (*buf_count > MFC_MAX_BUFFERS)
- *buf_count = MFC_MAX_BUFFERS;
-
- if (ctx->dst_fmt->mem_planes == 1) {
- psize[0] = raw->total_plane_size;
- alloc_devs[0] = dev->device;
- } else {
- for (i = 0; i < ctx->dst_fmt->num_planes; i++) {
- psize[i] = raw->plane_size[i];
- alloc_devs[i] = dev->device;
- }
- }
- } else {
- mfc_err_ctx("State seems invalid. State = %d, vq->type = %d\n",
- ctx->state, vq->type);
- return -EINVAL;
- }
-
- mfc_debug(2, "buf_count: %d, plane_count: %d, type: %#x\n",
- *buf_count, *plane_count, vq->type);
- for (i = 0; i < *plane_count; i++)
- mfc_debug(2, "plane[%d] size: %d\n", i, psize[i]);
-
- mfc_debug_leave();
-
- return 0;
-}
-
-static void s5p_mfc_dec_unlock(struct vb2_queue *q)
-{
- struct s5p_mfc_ctx *ctx = q->drv_priv;
- struct s5p_mfc_dev *dev;
-
- if (!ctx) {
- mfc_err_dev("no mfc context to run\n");
- return;
- }
- dev = ctx->dev;
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return;
- }
-
- mutex_unlock(&dev->mfc_mutex);
-}
-
-static void s5p_mfc_dec_lock(struct vb2_queue *q)
-{
- struct s5p_mfc_ctx *ctx = q->drv_priv;
- struct s5p_mfc_dev *dev;
-
- if (!ctx) {
- mfc_err_dev("no mfc context to run\n");
- return;
- }
- dev = ctx->dev;
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return;
- }
-
- mutex_lock(&dev->mfc_mutex);
-}
-
-static int s5p_mfc_dec_buf_init(struct vb2_buffer *vb)
-{
- struct vb2_queue *vq = vb->vb2_queue;
- struct s5p_mfc_ctx *ctx = vq->drv_priv;
- struct s5p_mfc_dev *dev;
- struct s5p_mfc_dec *dec;
- struct s5p_mfc_buf *buf = vb_to_mfc_buf(vb);
- dma_addr_t start_raw;
- int i, ret;
-
- mfc_debug_enter();
- if (!ctx) {
- mfc_err_dev("no mfc context to run\n");
- return -EINVAL;
- }
- dev = ctx->dev;
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
- dec = ctx->dec_priv;
- if (!dec) {
- mfc_err_dev("no mfc decoder to run\n");
- return -EINVAL;
- }
-
- if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- ret = s5p_mfc_check_vb_with_fmt(ctx->dst_fmt, vb);
- if (ret < 0)
- return ret;
-
- start_raw = s5p_mfc_mem_get_daddr_vb(vb, 0);
- if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV12N) {
- buf->addr[0][0] = start_raw;
- buf->addr[0][1] = NV12N_CBCR_BASE(start_raw,
- ctx->img_width,
- ctx->img_height);
- } else if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV12N_10B) {
- buf->addr[0][0] = start_raw;
- buf->addr[0][1] = NV12N_10B_CBCR_BASE(start_raw,
- ctx->img_width,
- ctx->img_height);
- } else if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420N) {
- buf->addr[0][0] = start_raw;
- buf->addr[0][1] = YUV420N_CB_BASE(start_raw,
- ctx->img_width,
- ctx->img_height);
- buf->addr[0][2] = YUV420N_CR_BASE(start_raw,
- ctx->img_width,
- ctx->img_height);
- } else {
- for (i = 0; i < ctx->dst_fmt->mem_planes; i++)
- buf->addr[0][i] = s5p_mfc_mem_get_daddr_vb(vb, i);
- }
-
- if (call_cop(ctx, init_buf_ctrls, ctx, MFC_CTRL_TYPE_DST,
- vb->index) < 0)
- mfc_err_ctx("failed in init_buf_ctrls\n");
- } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- ret = s5p_mfc_check_vb_with_fmt(ctx->src_fmt, vb);
- if (ret < 0)
- return ret;
-
- buf->addr[0][0] = s5p_mfc_mem_get_daddr_vb(vb, 0);
-
- if (call_cop(ctx, init_buf_ctrls, ctx, MFC_CTRL_TYPE_SRC,
- vb->index) < 0)
- mfc_err_ctx("failed in init_buf_ctrls\n");
- } else {
- mfc_err_ctx("s5p_mfc_dec_buf_init: unknown queue type\n");
- return -EINVAL;
- }
-
- mfc_debug_leave();
-
- return 0;
-}
-
-static int s5p_mfc_dec_buf_prepare(struct vb2_buffer *vb)
-{
- struct vb2_queue *vq = vb->vb2_queue;
- struct s5p_mfc_ctx *ctx = vq->drv_priv;
- struct s5p_mfc_dec *dec;
- struct s5p_mfc_raw_info *raw;
- unsigned int index = vb->index;
- size_t buf_size;
- int i;
-
- if (!ctx) {
- mfc_err_dev("no mfc context to run\n");
- return -EINVAL;
- }
- dec = ctx->dec_priv;
- if (!dec) {
- mfc_err_dev("no mfc decoder to run\n");
- return -EINVAL;
- }
- if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- raw = &ctx->raw_buf;
- /* check the size per plane */
- if (ctx->dst_fmt->mem_planes == 1) {
- buf_size = vb2_plane_size(vb, 0);
- mfc_debug(2, "[FRAME] single plane vb size: %lu, calc size: %d\n",
- buf_size, raw->total_plane_size);
- if (buf_size < raw->total_plane_size) {
- mfc_err_ctx("[FRAME] single plane size(%d) is smaller than (%d)\n",
- buf_size, raw->total_plane_size);
- return -EINVAL;
- }
- } else {
- for (i = 0; i < ctx->dst_fmt->mem_planes; i++) {
- buf_size = vb2_plane_size(vb, i);
- mfc_debug(2, "[FRAME] plane[%d] vb size: %lu, calc size: %d\n",
- i, buf_size, raw->plane_size[i]);
- if (buf_size < raw->plane_size[i]) {
- mfc_err_ctx("[FRAME] plane[%d] size(%d) is smaller than (%d)\n",
- i, buf_size, raw->plane_size[i]);
- return -EINVAL;
- }
- }
- }
- } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- buf_size = vb2_plane_size(vb, 0);
- mfc_debug(2, "[STREAM] vb size: %lu, calc size: %d\n",
- buf_size, dec->src_buf_size);
-
- if (buf_size < dec->src_buf_size) {
- mfc_err_ctx("[STREAM] size(%d) is smaller than (%d)\n",
- buf_size, dec->src_buf_size);
- return -EINVAL;
- }
-
- if (call_cop(ctx, to_buf_ctrls, ctx, &ctx->src_ctrls[index]) < 0)
- mfc_err_ctx("failed in to_buf_ctrls\n");
- }
-
- return 0;
-}
-
-static void s5p_mfc_dec_buf_finish(struct vb2_buffer *vb)
-{
- struct vb2_queue *vq = vb->vb2_queue;
- struct s5p_mfc_ctx *ctx = vq->drv_priv;
- unsigned int index = vb->index;
-
- if (!ctx) {
- mfc_err_dev("no mfc context to run\n");
- return;
- }
-
- if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- if (call_cop(ctx, to_ctx_ctrls, ctx, &ctx->dst_ctrls[index]) < 0)
- mfc_err_ctx("failed in to_ctx_ctrls\n");
- } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- if (call_cop(ctx, to_ctx_ctrls, ctx, &ctx->src_ctrls[index]) < 0)
- mfc_err_ctx("failed in to_ctx_ctrls\n");
- }
-}
-
-static void s5p_mfc_dec_buf_cleanup(struct vb2_buffer *vb)
-{
- struct vb2_queue *vq = vb->vb2_queue;
- struct s5p_mfc_ctx *ctx = vq->drv_priv;
- unsigned int index = vb->index;
-
- mfc_debug_enter();
- if (!ctx) {
- mfc_err_dev("no mfc context to run\n");
- return;
- }
-
- if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- if (call_cop(ctx, cleanup_buf_ctrls, ctx,
- MFC_CTRL_TYPE_DST, index) < 0)
- mfc_err_ctx("failed in cleanup_buf_ctrls\n");
- } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- if (call_cop(ctx, cleanup_buf_ctrls, ctx,
- MFC_CTRL_TYPE_SRC, index) < 0)
- mfc_err_ctx("failed in cleanup_buf_ctrls\n");
- } else {
- mfc_err_ctx("s5p_mfc_dec_buf_cleanup: unknown queue type\n");
- }
-
- mfc_debug_leave();
-}
-
-static int s5p_mfc_dec_start_streaming(struct vb2_queue *q, unsigned int count)
-{
- struct s5p_mfc_ctx *ctx = q->drv_priv;
- struct s5p_mfc_dev *dev;
-
- if (!ctx) {
- mfc_err_dev("no mfc context to run\n");
- return -EINVAL;
- }
-
- dev = ctx->dev;
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
-
- if (ctx->state == MFCINST_FINISHING)
- s5p_mfc_change_state(ctx, MFCINST_RUNNING);
-
- /* If context is ready then dev = work->data;schedule it to run */
- if (s5p_mfc_dec_ctx_ready(ctx)) {
- s5p_mfc_set_bit(ctx->num, &dev->work_bits);
- }
-
- s5p_mfc_try_run(dev);
-
- return 0;
-}
-
-static void mfc_dec_src_stop_streaming(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev;
- struct s5p_mfc_dec *dec;
- struct s5p_mfc_buf *src_mb;
- int index, csd, condition = 0;
- int ret = 0;
-
- dev = ctx->dev;
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return;
- }
-
- dec = ctx->dec_priv;
- if (!dec) {
- mfc_err_dev("no mfc decoder to run\n");
- return;
- }
-
- while (1) {
- csd = s5p_mfc_peek_buf_csd(&ctx->buf_queue_lock, &ctx->src_buf_queue);
-
- if (csd == 1) {
- s5p_mfc_clean_ctx_int_flags(ctx);
- if (need_to_special_parsing(ctx)) {
- s5p_mfc_change_state(ctx, MFCINST_SPECIAL_PARSING);
- condition = S5P_FIMV_R2H_CMD_SEQ_DONE_RET;
- mfc_info_ctx("try to special parsing! (before NAL_START)\n");
- } else if (need_to_special_parsing_nal(ctx)) {
- s5p_mfc_change_state(ctx, MFCINST_SPECIAL_PARSING_NAL);
- condition = S5P_FIMV_R2H_CMD_FRAME_DONE_RET;
- mfc_info_ctx("try to special parsing! (after NAL_START)\n");
- } else {
- mfc_info_ctx("can't parsing CSD!, state = %d\n", ctx->state);
- }
-
- if (condition) {
- s5p_mfc_set_bit(ctx->num, &dev->work_bits);
-
- ret = s5p_mfc_just_run(dev, ctx->num);
- if (ret) {
- mfc_err_ctx("Failed to run MFC\n");
- } else {
- if (s5p_mfc_wait_for_done_ctx(ctx, condition))
- mfc_err_ctx("special parsing time out\n");
- }
- }
- }
-
- src_mb = s5p_mfc_get_del_buf(&ctx->buf_queue_lock, &ctx->src_buf_queue, MFC_BUF_NO_TOUCH_USED);
- if (!src_mb)
- break;
-
- index = src_mb->vb.vb2_buf.index;
-
- if (ctx->is_drm)
- s5p_mfc_stream_unprotect(ctx, src_mb, index);
- vb2_set_plane_payload(&src_mb->vb.vb2_buf, 0, 0);
- vb2_buffer_done(&src_mb->vb.vb2_buf, VB2_BUF_STATE_ERROR);
- }
-
- dec->consumed = 0;
- dec->remained_size = 0;
- ctx->check_dump = 0;
-
- s5p_mfc_init_queue(&ctx->src_buf_queue);
-
- index = 0;
- while (index < MFC_MAX_BUFFERS) {
- index = find_next_bit(&ctx->src_ctrls_avail,
- MFC_MAX_BUFFERS, index);
- if (index < MFC_MAX_BUFFERS)
- call_cop(ctx, reset_buf_ctrls, &ctx->src_ctrls[index]);
- index++;
- }
-}
-
-static void mfc_dec_dst_stop_streaming(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dec *dec;
- int index = 0;
-
- dec = ctx->dec_priv;
- if (!dec) {
- mfc_err_dev("no mfc decoder to run\n");
- return;
- }
-
- s5p_mfc_cleanup_assigned_fd(ctx);
- s5p_mfc_cleanup_queue(&ctx->buf_queue_lock, &ctx->ref_buf_queue);
-
- dec->dynamic_used = 0;
- dec->err_reuse_flag = 0;
- dec->dec_only_release_flag = 0;
-
- s5p_mfc_cleanup_queue(&ctx->buf_queue_lock, &ctx->dst_buf_queue);
-
- ctx->is_dpb_realloc = 0;
- dec->available_dpb = 0;
-
- dec->y_addr_for_pb = 0;
-
- s5p_mfc_cleanup_assigned_dpb(ctx);
-
- while (index < MFC_MAX_BUFFERS) {
- index = find_next_bit(&ctx->dst_ctrls_avail,
- MFC_MAX_BUFFERS, index);
- if (index < MFC_MAX_BUFFERS)
- call_cop(ctx, reset_buf_ctrls, &ctx->dst_ctrls[index]);
- index++;
- }
-
- if (ctx->wait_state == WAIT_INITBUF_DONE ||
- ctx->wait_state == WAIT_DECODING) {
- ctx->wait_state = WAIT_NONE;
- mfc_debug(2, "Decoding can be started now\n");
- }
-}
-
-static void s5p_mfc_dec_stop_streaming(struct vb2_queue *q)
-{
- struct s5p_mfc_ctx *ctx = q->drv_priv;
- struct s5p_mfc_dev *dev;
- int ret = 0;
- int prev_state;
-
- if (!ctx) {
- mfc_err_dev("no mfc context to run\n");
- return;
- }
-
- dev = ctx->dev;
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return;
- }
-
- mfc_info_ctx("dec stop_streaming is called, hwlock : %d, type : %d\n",
- test_bit(ctx->num, &dev->hwlock.bits), q->type);
- MFC_TRACE_CTX("** DEC streamoff(type:%d)\n", q->type);
-
- MFC_TRACE_CTX_HWLOCK("**DEC streamoff(type:%d)\n", q->type);
- /* If a H/W operation is in progress, wait for it complete */
- ret = s5p_mfc_get_hwlock_ctx(ctx);
- if (ret < 0) {
- mfc_err_ctx("Failed to get hwlock\n");
- return;
- }
-
- if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
- mfc_dec_dst_stop_streaming(ctx);
- else if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
- mfc_dec_src_stop_streaming(ctx);
-
- if (ctx->state == MFCINST_FINISHING)
- s5p_mfc_change_state(ctx, MFCINST_RUNNING);
-
- if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && need_to_dpb_flush(ctx)) {
- prev_state = ctx->state;
- s5p_mfc_change_state(ctx, MFCINST_DPB_FLUSHING);
- s5p_mfc_set_bit(ctx->num, &dev->work_bits);
- s5p_mfc_clean_ctx_int_flags(ctx);
- mfc_info_ctx("try to DPB flush\n");
- ret = s5p_mfc_just_run(dev, ctx->num);
- if (ret) {
- mfc_err_ctx("Failed to run MFC\n");
- s5p_mfc_release_hwlock_ctx(ctx);
- s5p_mfc_cleanup_work_bit_and_try_run(ctx);
- return;
- }
-
- if (s5p_mfc_wait_for_done_ctx(ctx, S5P_FIMV_R2H_CMD_DPB_FLUSH_RET)) {
- mfc_err_ctx("time out during DPB flush\n");
- dev->logging_data->cause |= (1 << MFC_CAUSE_FAIL_DPB_FLUSH);
- call_dop(dev, dump_and_stop_always, dev);
- }
-
- s5p_mfc_change_state(ctx, prev_state);
- }
-
- mfc_debug(2, "buffer cleanup & flush is done in stop_streaming, type : %d\n", q->type);
-
- s5p_mfc_clear_bit(ctx->num, &dev->work_bits);
- s5p_mfc_release_hwlock_ctx(ctx);
-
- if (s5p_mfc_dec_ctx_ready(ctx))
- s5p_mfc_set_bit(ctx->num, &dev->work_bits);
- if (s5p_mfc_is_work_to_do(dev))
- queue_work(dev->butler_wq, &dev->butler_work);
-}
-
-static void s5p_mfc_dec_buf_queue(struct vb2_buffer *vb)
-{
- struct vb2_queue *vq = vb->vb2_queue;
- struct s5p_mfc_ctx *ctx = vq->drv_priv;
- struct s5p_mfc_dev *dev;
- struct s5p_mfc_dec *dec;
- struct s5p_mfc_buf *buf = vb_to_mfc_buf(vb);
- int i;
- unsigned char *stream_vir = NULL;
-
- mfc_debug_enter();
- if (!ctx) {
- mfc_err_dev("no mfc context to run\n");
- return;
- }
-
- dev = ctx->dev;
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return;
- }
-
- dec = ctx->dec_priv;
- if (!dec) {
- mfc_err_dev("no mfc decoder to run\n");
- return;
- }
-
- if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- mfc_debug(2, "[BUFINFO] ctx[%d] add src index:%d, addr: 0x%08llx\n",
- ctx->num, vb->index, buf->addr[0][0]);
- if (dec->dst_memtype == V4L2_MEMORY_DMABUF &&
- ctx->state < MFCINST_HEAD_PARSED && !ctx->is_drm)
- stream_vir = vb2_plane_vaddr(vb, 0);
-
- buf->vir_addr = stream_vir;
-
- s5p_mfc_add_tail_buf(&ctx->buf_queue_lock, &ctx->src_buf_queue, buf);
-
- MFC_TRACE_CTX("Q src[%d] fd: %d, %#llx\n",
- vb->index, vb->planes[0].m.fd, buf->addr[0][0]);
- } else if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- for (i = 0; i < ctx->dst_fmt->mem_planes; i++)
- mfc_debug(2, "[BUFINFO] ctx[%d] add dst index: %d, addr[%d]: 0x%08llx\n",
- ctx->num, vb->index, i, buf->addr[0][i]);
- s5p_mfc_store_dpb(ctx, vb);
-
- if ((dec->dst_memtype == V4L2_MEMORY_USERPTR || dec->dst_memtype == V4L2_MEMORY_DMABUF) &&
- s5p_mfc_is_queue_count_same(&ctx->buf_queue_lock,
- &ctx->dst_buf_queue, dec->total_dpb_count))
- ctx->capture_state = QUEUE_BUFS_MMAPED;
-
- MFC_TRACE_CTX("Q dst[%d] fd: %d, %#llx / avail %#lx used %#x\n",
- vb->index, vb->planes[0].m.fd, buf->addr[0][0],
- dec->available_dpb, dec->dynamic_used);
- } else {
- mfc_err_ctx("Unsupported buffer type (%d)\n", vq->type);
- }
-
- if (s5p_mfc_dec_ctx_ready(ctx)) {
- s5p_mfc_set_bit(ctx->num, &dev->work_bits);
- s5p_mfc_try_run(dev);
- }
-
- mfc_debug_leave();
-}
-
-struct vb2_ops s5p_mfc_dec_qops = {
- .queue_setup = s5p_mfc_dec_queue_setup,
- .wait_prepare = s5p_mfc_dec_unlock,
- .wait_finish = s5p_mfc_dec_lock,
- .buf_init = s5p_mfc_dec_buf_init,
- .buf_prepare = s5p_mfc_dec_buf_prepare,
- .buf_finish = s5p_mfc_dec_buf_finish,
- .buf_cleanup = s5p_mfc_dec_buf_cleanup,
- .start_streaming = s5p_mfc_dec_start_streaming,
- .stop_streaming = s5p_mfc_dec_stop_streaming,
- .buf_queue = s5p_mfc_dec_buf_queue,
-};
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_enc.c
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include "s5p_mfc_enc.h"
-#include "s5p_mfc_enc_internal.h"
-
-#include "s5p_mfc_hwlock.h"
-#include "s5p_mfc_otf.h"
-#include "s5p_mfc_opr.h"
-#include "s5p_mfc_sync.h"
-
-#include "s5p_mfc_qos.h"
-#include "s5p_mfc_queue.h"
-#include "s5p_mfc_utils.h"
-#include "s5p_mfc_buf.h"
-#include "s5p_mfc_mem.h"
-
-static struct s5p_mfc_fmt *mfc_enc_find_format(struct s5p_mfc_ctx *ctx,
- unsigned int pixelformat)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_fmt *fmt = NULL;
- unsigned long i;
-
- for (i = 0; i < NUM_FORMATS; i++) {
- if (enc_formats[i].fourcc == pixelformat) {
- fmt = (struct s5p_mfc_fmt *)&enc_formats[i];
- break;
- }
- }
-
- if (!dev->pdata->support_10bit && (fmt->type & MFC_FMT_10BIT)) {
- mfc_err_ctx("[FRAME] 10bit is not supported\n");
- fmt = NULL;
- }
- if (!dev->pdata->support_422 && (fmt->type & MFC_FMT_422)) {
- mfc_err_ctx("[FRAME] 422 is not supported\n");
- fmt = NULL;
- }
- if (!dev->pdata->support_rgb && (fmt->type & MFC_FMT_RGB)) {
- mfc_err_ctx("[FRAME] RGB is not supported\n");
- fmt = NULL;
- }
-
- return fmt;
-}
-
-static struct v4l2_queryctrl *mfc_enc_get_ctrl(int id)
-{
- unsigned long i;
-
- for (i = 0; i < NUM_CTRLS; ++i)
- if (id == controls[i].id)
- return &controls[i];
- return NULL;
-}
-
-static int mfc_enc_check_ctrl_val(struct s5p_mfc_ctx *ctx, struct v4l2_control *ctrl)
-{
- struct v4l2_queryctrl *c;
-
- c = mfc_enc_get_ctrl(ctrl->id);
- if (!c) {
- mfc_err_ctx("[CTRLS] not supported control id (%#x)\n", ctrl->id);
- return -EINVAL;
- }
-
- if (ctrl->id == V4L2_CID_MPEG_VIDEO_GOP_SIZE
- && ctrl->value > c->maximum) {
- mfc_info_ctx("GOP_SIZE is changed to max(%d -> %d)\n",
- ctrl->value, c->maximum);
- ctrl->value = c->maximum;
- }
-
- if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER) {
- if ((ctrl->value & ~(1 << 16)) < c->minimum || (ctrl->value & ~(1 << 16)) > c->maximum
- || (c->step != 0 && (ctrl->value & ~(1 << 16)) % c->step != 0)) {
- mfc_err_ctx("[CTRLS][HIERARCHICAL] Invalid control value for %#x (%#x)\n",
- ctrl->id, ctrl->value);
- return -ERANGE;
- } else {
- return 0;
- }
- }
-
- if (ctrl->value < c->minimum || ctrl->value > c->maximum
- || (c->step != 0 && ctrl->value % c->step != 0)) {
- mfc_err_ctx("[CTRLS] Invalid control value for %#x (%#x)\n",
- ctrl->id, ctrl->value);
- return -ERANGE;
- }
-
- return 0;
-}
-
-static inline int mfc_enc_h264_profile(struct s5p_mfc_ctx *ctx, int profile)
-{
- int ret = 0;
-
- switch (profile) {
- case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
- ret = S5P_FIMV_E_PROFILE_H264_MAIN;
- break;
- case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
- ret = S5P_FIMV_E_PROFILE_H264_HIGH;
- break;
- case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
- ret = S5P_FIMV_E_PROFILE_H264_BASELINE;
- break;
- case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
- ret = S5P_FIMV_E_PROFILE_H264_CONSTRAINED_BASELINE;
- break;
- case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH:
- ret = S5P_FIMV_E_PROFILE_H264_CONSTRAINED_HIGH;
- break;
- default:
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-/* Query capabilities of the device */
-static int vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
- strncpy(cap->driver, "MFC", sizeof(cap->driver) - 1);
- strncpy(cap->card, "encoder", sizeof(cap->card) - 1);
- cap->bus_info[0] = 0;
- cap->version = KERNEL_VERSION(1, 0, 0);
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE
- | V4L2_CAP_VIDEO_OUTPUT
- | V4L2_CAP_VIDEO_CAPTURE_MPLANE
- | V4L2_CAP_VIDEO_OUTPUT_MPLANE
- | V4L2_CAP_STREAMING
- | V4L2_CAP_DEVICE_CAPS;
-
- cap->capabilities = cap->device_caps;
-
- return 0;
-}
-
-static int mfc_enc_enum_fmt(struct s5p_mfc_dev *dev, struct v4l2_fmtdesc *f,
- unsigned int type)
-{
- struct s5p_mfc_fmt *fmt;
- unsigned long i, j = 0;
-
- for (i = 0; i < NUM_FORMATS; ++i) {
- if (!(enc_formats[i].type & type))
- continue;
- if (!dev->pdata->support_10bit && (enc_formats[i].type & MFC_FMT_10BIT))
- continue;
- if (!dev->pdata->support_422 && (enc_formats[i].type & MFC_FMT_422))
- continue;
- if (!dev->pdata->support_rgb && (enc_formats[i].type & MFC_FMT_RGB))
- continue;
-
- if (j == f->index) {
- fmt = &enc_formats[i];
- strlcpy(f->description, fmt->name,
- sizeof(f->description));
- f->pixelformat = fmt->fourcc;
-
- return 0;
- }
-
- ++j;
- }
-
- return -EINVAL;
-}
-
-static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv,
- struct v4l2_fmtdesc *f)
-{
- struct s5p_mfc_dev *dev = video_drvdata(file);
-
- return mfc_enc_enum_fmt(dev, f, MFC_FMT_STREAM);
-}
-
-static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *prov,
- struct v4l2_fmtdesc *f)
-{
- struct s5p_mfc_dev *dev = video_drvdata(file);
-
- return mfc_enc_enum_fmt(dev, f, MFC_FMT_FRAME);
-}
-
-static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
-{
- struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
- struct s5p_mfc_enc *enc = ctx->enc_priv;
- struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
- struct s5p_mfc_raw_info *raw;
- int i;
-
- mfc_debug_enter();
-
- if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- mfc_debug(4, "enc dst g_fmt\n");
- /* This is run on output (encoder dest) */
- pix_fmt_mp->width = 0;
- pix_fmt_mp->height = 0;
- pix_fmt_mp->field = V4L2_FIELD_NONE;
- pix_fmt_mp->pixelformat = ctx->dst_fmt->fourcc;
- pix_fmt_mp->num_planes = ctx->dst_fmt->mem_planes;
-
- pix_fmt_mp->plane_fmt[0].bytesperline = enc->dst_buf_size;
- pix_fmt_mp->plane_fmt[0].sizeimage = enc->dst_buf_size;
- } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- mfc_debug(4, "enc src g_fmt\n");
- /* This is run on capture (encoder src) */
- raw = &ctx->raw_buf;
-
- pix_fmt_mp->width = ctx->img_width;
- pix_fmt_mp->height = ctx->img_height;
- pix_fmt_mp->field = V4L2_FIELD_NONE;
- pix_fmt_mp->pixelformat = ctx->src_fmt->fourcc;
- pix_fmt_mp->num_planes = ctx->src_fmt->mem_planes;
- for (i = 0; i < ctx->src_fmt->mem_planes; i++) {
- pix_fmt_mp->plane_fmt[i].bytesperline = raw->stride[i];
- pix_fmt_mp->plane_fmt[i].sizeimage = raw->plane_size[i];
- }
- } else {
- mfc_err_dev("invalid buf type (%d)\n", f->type);
- return -EINVAL;
- }
-
- mfc_debug_leave();
-
- return 0;
-}
-
-static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
-{
- struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
- struct s5p_mfc_fmt *fmt;
- struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
-
- fmt = mfc_enc_find_format(ctx, pix_fmt_mp->pixelformat);
- if (!fmt) {
- mfc_err_dev("Unsupported format for %s\n",
- V4L2_TYPE_IS_OUTPUT(f->type) ? "source" : "destination");
- return -EINVAL;
- }
-
- return 0;
-}
-
-static void mfc_enc_check_format(struct s5p_mfc_ctx *ctx)
-{
- switch (ctx->src_fmt->fourcc) {
- case V4L2_PIX_FMT_NV16M_S10B:
- case V4L2_PIX_FMT_NV61M_S10B:
- case V4L2_PIX_FMT_NV16M_P210:
- case V4L2_PIX_FMT_NV61M_P210:
- mfc_debug(2, "[FRAME][10BIT] is 422 and 10bit format\n");
- ctx->is_10bit = 1;
- ctx->is_422 = 1;
- break;
- case V4L2_PIX_FMT_NV16M:
- case V4L2_PIX_FMT_NV61M:
- mfc_debug(2, "[FRAME] is 422 format\n");
- ctx->is_10bit = 0;
- ctx->is_422 = 1;
- break;
- case V4L2_PIX_FMT_NV12M_S10B:
- case V4L2_PIX_FMT_NV12M_P010:
- case V4L2_PIX_FMT_NV21M_S10B:
- case V4L2_PIX_FMT_NV21M_P010:
- mfc_debug(2, "[FRAME][10BIT] is 10bit format\n");
- ctx->is_10bit = 1;
- ctx->is_422 = 0;
- break;
- default:
- ctx->is_10bit = 0;
- ctx->is_422 = 0;
- break;
- }
- mfc_debug(2, "[FRAME] 10bit: %d, 422: %d\n", ctx->is_10bit, ctx->is_422);
-}
-
-static int mfc_enc_check_resolution(struct s5p_mfc_ctx *ctx)
-{
- int max_width = 0, max_height = 0, min_width = 0, min_height = 0, swap_check = 0;
-
- /* Check max resolution */
- switch (ctx->codec_mode) {
- case S5P_FIMV_CODEC_HEVC_ENC:
- if (ctx->is_422) {
- max_width = 65536;
- max_height = 8192;
- swap_check = 1;
- } else {
- max_width = 8192;
- max_height = 8192;
- }
- break;
- case S5P_FIMV_CODEC_BPG_ENC:
- max_width = 65536;
- max_height = 8192;
- swap_check = 1;
- break;
- case S5P_FIMV_CODEC_H264_ENC:
- case S5P_FIMV_CODEC_VP8_ENC:
- max_width = 8192;
- max_height = 8192;
- break;
- case S5P_FIMV_CODEC_VP9_ENC:
- max_width = 4096;
- max_height = 8192;
- break;
- case S5P_FIMV_CODEC_MPEG4_ENC:
- max_width = 2048;
- max_height = 2048;
- break;
- case S5P_FIMV_CODEC_H263_ENC:
- max_width = 2048;
- max_height = 1152;
- break;
- default:
- mfc_err_ctx("Not supported codec(%d)\n", ctx->codec_mode);
- return -EINVAL;
- }
-
- if (swap_check) {
- if (!((ctx->crop_width < max_width && ctx->crop_height < max_height) ||
- (ctx->crop_width < max_height && ctx->crop_height < max_width))) {
- mfc_err_ctx("Resolution is too big(%dx%d > %dxi%d or %dx%d\n",
- ctx->crop_width, ctx->crop_height, max_width, max_height,
- max_height, max_width);
- return -EINVAL;
- }
- } else {
- if (ctx->crop_width > max_width || ctx->crop_height > max_height) {
- mfc_err_ctx("Resolution is too big(%dx%d > %dx%d)\n",
- ctx->crop_width, ctx->crop_height, max_width, max_height);
- return -EINVAL;
- }
- }
-
- /* Check min resolution */
- switch (ctx->codec_mode) {
- case S5P_FIMV_CODEC_HEVC_ENC:
- case S5P_FIMV_CODEC_BPG_ENC:
- case S5P_FIMV_CODEC_VP9_ENC:
- min_width = 64;
- min_height = 64;
- break;
- case S5P_FIMV_CODEC_H264_ENC:
- case S5P_FIMV_CODEC_VP8_ENC:
- case S5P_FIMV_CODEC_MPEG4_ENC:
- case S5P_FIMV_CODEC_H263_ENC:
- min_width = 32;
- min_height = 32;
- break;
- default:
- mfc_err_ctx("Not supported codec(%d)\n", ctx->codec_mode);
- return -EINVAL;
- }
-
- if (ctx->crop_width < min_width || ctx->crop_height < min_height) {
- mfc_err_ctx("Resolution is too small(%dx%d < %dx%d)\n",
- ctx->crop_width, ctx->crop_height, min_width, min_height);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int vidioc_s_fmt_vid_cap_mplane(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct s5p_mfc_dev *dev = video_drvdata(file);
- struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
- struct s5p_mfc_enc *enc = ctx->enc_priv;
- struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
- int ret = 0;
-
- mfc_debug_enter();
-
- if (ctx->vq_dst.streaming) {
- mfc_err_ctx("dst queue busy\n");
- return -EBUSY;
- }
-
- ctx->dst_fmt = mfc_enc_find_format(ctx, pix_fmt_mp->pixelformat);
- if (!ctx->dst_fmt) {
- mfc_err_ctx("Unsupported format for destination\n");
- return -EINVAL;
- }
-
- ctx->codec_mode = ctx->dst_fmt->codec_mode;
- mfc_info_ctx("[STREAM] Enc dst codec(%d) : %s\n",
- ctx->codec_mode, ctx->dst_fmt->name);
-
- if (mfc_enc_check_resolution(ctx)) {
- mfc_err_ctx("Unsupported resolution\n");
- return -EINVAL;
- }
-
- if (ctx->otf_handle) {
- if (ctx->dst_fmt->fourcc != V4L2_PIX_FMT_H264 &&
- ctx->dst_fmt->fourcc != V4L2_PIX_FMT_HEVC) {
- mfc_err_ctx("[OTF] only H.264 and HEVC is supported\n");
- return -EINVAL;
- }
- if (s5p_mfc_otf_init(ctx)) {
- mfc_err_ctx("[OTF] otf_init failed\n");
- s5p_mfc_otf_destroy(ctx);
- return -EINVAL;
- }
- }
-
- enc->dst_buf_size = pix_fmt_mp->plane_fmt[0].sizeimage;
- pix_fmt_mp->plane_fmt[0].bytesperline = 0;
-
- ret = s5p_mfc_alloc_instance_context(ctx);
- if (ret) {
- mfc_err_ctx("Failed to allocate enc instance[%d] buffers\n",
- ctx->num);
- return -ENOMEM;
- }
-
- s5p_mfc_change_state(ctx, MFCINST_INIT);
-
- ctx->capture_state = QUEUE_FREE;
-
- ret = s5p_mfc_alloc_enc_roi_buffer(ctx);
- if (ret) {
- mfc_err_ctx("[ROI] Failed to allocate ROI buffers\n");
- s5p_mfc_release_instance_context(ctx);
- return -ENOMEM;
- }
-
- MFC_TRACE_CTX_HWLOCK("**ENC s_fmt\n");
-
- ret = s5p_mfc_get_hwlock_ctx(ctx);
- if (ret < 0) {
- mfc_err_dev("Failed to get hwlock\n");
- s5p_mfc_release_instance_context(ctx);
- s5p_mfc_release_enc_roi_buffer(ctx);
- return -EBUSY;
- }
-
- s5p_mfc_set_bit(ctx->num, &dev->work_bits);
- ret = s5p_mfc_just_run(dev, ctx->num);
- if (ret) {
- mfc_err_ctx("Failed to run MFC\n");
- s5p_mfc_release_hwlock_ctx(ctx);
- s5p_mfc_cleanup_work_bit_and_try_run(ctx);
- s5p_mfc_release_instance_context(ctx);
- s5p_mfc_release_enc_roi_buffer(ctx);
- return -EIO;
- }
-
- if (s5p_mfc_wait_for_done_ctx(ctx,
- S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET)) {
- mfc_err_ctx("time out during open instance\n");
- s5p_mfc_release_hwlock_ctx(ctx);
- s5p_mfc_cleanup_work_bit_and_try_run(ctx);
- s5p_mfc_release_instance_context(ctx);
- s5p_mfc_release_enc_roi_buffer(ctx);
- return -EIO;
- }
- s5p_mfc_release_hwlock_ctx(ctx);
-
- mfc_debug(2, "Got instance number: %d\n", ctx->inst_no);
-
- if (s5p_mfc_enc_ctx_ready(ctx))
- s5p_mfc_set_bit(ctx->num, &dev->work_bits);
- if (ctx->otf_handle && s5p_mfc_otf_ctx_ready(ctx))
- s5p_mfc_set_bit(ctx->num, &dev->work_bits);
- if (s5p_mfc_is_work_to_do(dev))
- queue_work(dev->butler_wq, &dev->butler_work);
-
- mfc_debug_leave();
- return 0;
-}
-
-static int vidioc_s_fmt_vid_out_mplane(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
- struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
-
- mfc_debug_enter();
-
- if (ctx->vq_src.streaming) {
- mfc_err_ctx("src queue busy\n");
- return -EBUSY;
- }
-
- if (ctx->otf_handle) {
- mfc_info_ctx("[OTF] skip source s_fmt\n");
- return 0;
- }
-
- ctx->src_fmt = mfc_enc_find_format(ctx, pix_fmt_mp->pixelformat);
- if (!ctx->src_fmt) {
- mfc_err_ctx("Unsupported format for source\n");
- return -EINVAL;
- }
-
- if (ctx->src_fmt->mem_planes != pix_fmt_mp->num_planes) {
- mfc_err_ctx("[FRAME] enc src plane number is different (%d != %d)\n",
- ctx->src_fmt->mem_planes, pix_fmt_mp->num_planes);
- return -EINVAL;
- }
-
- ctx->raw_buf.num_planes = ctx->src_fmt->num_planes;
- ctx->img_width = pix_fmt_mp->width;
- ctx->img_height = pix_fmt_mp->height;
- ctx->buf_stride = pix_fmt_mp->plane_fmt[0].bytesperline;
-
- mfc_enc_check_format(ctx);
-
- if (ctx->state == MFCINST_RUNNING) {
- s5p_mfc_change_state(ctx, MFCINST_GOT_INST);
- mfc_info_ctx("[DRC] Enc resolution is changed\n");
- }
-
- mfc_info_ctx("[FRAME] enc src pixelformat : %s\n", ctx->src_fmt->name);
- mfc_info_ctx("[FRAME] resolution w: %d, h: %d, stride: %d\n",
- pix_fmt_mp->width, pix_fmt_mp->height, ctx->buf_stride);
-
- /*
- * It should be keep till buffer size and stride was calculated.
- * And it can be changed to real encoding size, if user call the s_crop.
- */
- ctx->crop_width = ctx->img_width;
- ctx->crop_height = ctx->img_height;
- s5p_mfc_enc_calc_src_size(ctx);
-
- ctx->output_state = QUEUE_FREE;
-
- mfc_debug_leave();
- return 0;
-}
-
-static int vidioc_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
-{
- struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
-
- mfc_debug_enter();
-
- cr->c.left = ctx->crop_left;
- cr->c.top = ctx->crop_top;
- cr->c.width = ctx->crop_width;
- cr->c.height = ctx->crop_height;
-
- mfc_debug(2, "[FRAME] enc crop w: %d, h: %d, offset l: %d t: %d\n",
- ctx->crop_width, ctx->crop_height, ctx->crop_left, ctx->crop_top);
-
- mfc_debug_leave();
-
- return 0;
-}
-
-static int vidioc_s_crop(struct file *file, void *priv, const struct v4l2_crop *cr)
-{
- struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
-
- mfc_debug_enter();
-
- if (cr->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- mfc_err_ctx("not supported type (It can only in the source)\n");
- return -EINVAL;
- }
-
- if (cr->c.left < 0 || cr->c.top < 0) {
- mfc_err_ctx("[FRAME] crop position is negative\n");
- return -EINVAL;
- }
-
- if ((cr->c.height > ctx->img_height) || (cr->c.top > ctx->img_height) ||
- (cr->c.width > ctx->img_width) || (cr->c.left > ctx->img_width) ||
- (cr->c.left <= (ctx->img_width - cr->c.width)) ||
- (cr->c.top <= (ctx->img_height - cr->c.height))) {
- mfc_err_ctx("[FRAME] Out of crop range: (%d,%d,%d,%d) from %dx%d\n",
- cr->c.left, cr->c.top, cr->c.width, cr->c.height,
- ctx->img_width, ctx->img_height);
- return -EINVAL;
- }
-
- ctx->crop_top = cr->c.top;
- ctx->crop_left = cr->c.left;
- ctx->crop_height = cr->c.height;
- ctx->crop_width = cr->c.width;
-
- mfc_debug(3, "[FRAME] enc original: %dx%d, crop: %dx%d, offset l: %d t: %d\n",
- ctx->img_width, ctx->img_height,
- ctx->crop_width, ctx->crop_height,
- ctx->crop_left, ctx->crop_top);
-
- return 0;
-}
-
-static int vidioc_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *reqbufs)
-{
- struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
- int ret = 0;
-
- mfc_debug_enter();
-
- if (reqbufs->memory == V4L2_MEMORY_MMAP) {
- mfc_err_ctx("Not supported memory type (%d)\n", reqbufs->memory);
- return -EINVAL;
- }
-
- if (ctx->otf_handle) {
- mfc_info_ctx("[OTF] skip reqbufs\n");
- return 0;
- }
-
- if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- mfc_debug(4, "enc dst reqbuf(%d)\n", reqbufs->count);
- if (reqbufs->count == 0) {
- ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
- ctx->capture_state = QUEUE_FREE;
- return ret;
- }
-
- if (ctx->capture_state != QUEUE_FREE) {
- mfc_err_ctx("invalid capture state: %d\n", ctx->capture_state);
- return -EINVAL;
- }
-
- ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
- if (ret) {
- mfc_err_ctx("error in vb2_reqbufs() for E(D)\n");
- return ret;
- }
-
- ctx->capture_state = QUEUE_BUFS_REQUESTED;
- } else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- mfc_debug(4, "enc src reqbuf(%d)\n", reqbufs->count);
- if (reqbufs->count == 0) {
- ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
- ctx->output_state = QUEUE_FREE;
- return ret;
- }
-
- if (ctx->output_state != QUEUE_FREE) {
- mfc_err_ctx("invalid output state: %d\n", ctx->output_state);
- return -EINVAL;
- }
-
- ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
- if (ret) {
- mfc_err_ctx("error in vb2_reqbufs() for E(S)\n");
- return ret;
- }
-
- ctx->output_state = QUEUE_BUFS_REQUESTED;
- } else {
- mfc_err_ctx("invalid buf type (%d)\n", reqbufs->type);
- return -EINVAL;
- }
-
- mfc_debug_leave();
-
- return ret;
-}
-
-static int vidioc_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *buf)
-{
- struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
- int ret = 0;
-
- mfc_debug_enter();
-
- if (ctx->otf_handle) {
- mfc_info_ctx("[OTF] skip source querybuf\n");
- return 0;
- }
-
- if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- mfc_debug(4, "enc dst querybuf, state: %d\n", ctx->state);
- ret = vb2_querybuf(&ctx->vq_dst, buf);
- if (ret != 0) {
- mfc_err_dev("enc dst: error in vb2_querybuf()\n");
- return ret;
- }
- } else if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- mfc_debug(4, "enc src querybuf, state: %d\n", ctx->state);
- ret = vb2_querybuf(&ctx->vq_src, buf);
- if (ret != 0) {
- mfc_err_dev("enc src: error in vb2_querybuf()\n");
- return ret;
- }
- } else {
- mfc_err_dev("invalid buf type (%d)\n", buf->type);
- return -EINVAL;
- }
-
- mfc_debug_leave();
-
- return ret;
-}
-
-/* Queue a buffer */
-static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
- struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
- int i, ret = -EINVAL;
-
- mfc_debug_enter();
-
- if (ctx->otf_handle) {
- mfc_info_ctx("[OTF] skip qbuf\n");
- return 0;
- }
-
- if (ctx->state == MFCINST_ERROR) {
- mfc_err_ctx("Call on QBUF after unrecoverable error\n");
- return -EIO;
- }
-
- if (V4L2_TYPE_IS_MULTIPLANAR(buf->type) && !buf->length) {
- mfc_err_ctx("multiplanar but length is zero\n");
- return -EIO;
- }
-
- if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- mfc_debug(4, "enc src buf[%d] Q\n", buf->index);
- for (i = 0; i < ctx->src_fmt->num_planes; i++) {
- if (!buf->m.planes[i].bytesused) {
- mfc_debug(2, "[FRAME] enc src[%d] size zero, "
- "changed to buf size %d\n",
- i, buf->m.planes[i].length);
- buf->m.planes[i].bytesused = buf->m.planes[i].length;
- } else {
- mfc_debug(2, "[FRAME] enc src[%d] size %d\n",
- i, buf->m.planes[i].bytesused);
- }
- }
- ret = vb2_qbuf(&ctx->vq_src, buf);
- } else {
- mfc_debug(4, "enc dst buf[%d] Q\n", buf->index);
- ret = vb2_qbuf(&ctx->vq_dst, buf);
- }
-
- mfc_debug_leave();
- return ret;
-}
-
-/* Dequeue a buffer */
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
- struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
- int ret;
-
- mfc_debug_enter();
-
- if (ctx->otf_handle) {
- mfc_info_ctx("[OTF] skip dqbuf\n");
- return 0;
- }
-
- if (ctx->state == MFCINST_ERROR) {
- mfc_err_ctx("Call on DQBUF after unrecoverable error\n");
- return -EIO;
- }
- if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- mfc_debug(4, "enc src buf[%d] DQ\n", buf->index);
- ret = vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK);
- } else {
- mfc_debug(4, "enc dst buf[%d] DQ\n", buf->index);
- ret = vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK);
- }
- mfc_debug_leave();
- return ret;
-}
-
-/* Stream on */
-static int vidioc_streamon(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
- int ret = -EINVAL;
-
- mfc_debug_enter();
-
- if (ctx->otf_handle) {
- mfc_info_ctx("[OTF] skip streamon\n");
- return 0;
- }
-
- if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- mfc_debug(4, "enc src streamon\n");
- ret = vb2_streamon(&ctx->vq_src, type);
-
- if (!ret) {
- s5p_mfc_qos_on(ctx);
- }
- } else {
- mfc_debug(4, "enc dst streamon\n");
- ret = vb2_streamon(&ctx->vq_dst, type);
- }
-
- mfc_debug(2, "src: %d, dst: %d, state = %d, dpb_count = %d\n",
- s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->src_buf_queue),
- s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->dst_buf_queue),
- ctx->state, ctx->dpb_count);
- mfc_debug_leave();
- return ret;
-}
-
-/* Stream off, which equals to a pause */
-static int vidioc_streamoff(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
- int ret;
-
- mfc_debug_enter();
-
- if (ctx->otf_handle) {
- mfc_info_ctx("[OTF] skip streamoff\n");
- return 0;
- }
-
- ret = -EINVAL;
- if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- mfc_debug(4, "enc src streamoff\n");
- s5p_mfc_qos_reset_last_framerate(ctx);
-
- ret = vb2_streamoff(&ctx->vq_src, type);
- if (!ret)
- s5p_mfc_qos_off(ctx);
- } else {
- mfc_debug(4, "enc dst streamoff\n");
- ret = vb2_streamoff(&ctx->vq_dst, type);
- }
-
- mfc_debug_leave();
-
- return ret;
-}
-
-/* Query a ctrl */
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- struct v4l2_queryctrl *c;
-
- c = mfc_enc_get_ctrl(qc->id);
- if (!c) {
- mfc_err_dev("[CTRLS] not supported control id (%#x)\n", qc->id);
- return -EINVAL;
- }
-
- *qc = *c;
- return 0;
-}
-
-static int mfc_enc_ext_info(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- int val = 0;
-
- val |= ENC_SET_SPARE_SIZE;
- val |= ENC_SET_TEMP_SVC_CH;
-
- if (MFC_FEATURE_SUPPORT(dev, dev->pdata->skype))
- val |= ENC_SET_SKYPE_FLAG;
-
- val |= ENC_SET_ROI_CONTROL;
- val |= ENC_SET_QP_BOUND_PB;
- val |= ENC_SET_FIXED_SLICE;
- val |= ENC_SET_PVC_MODE;
- val |= ENC_SET_RATIO_OF_INTRA;
-
- if (MFC_FEATURE_SUPPORT(dev, dev->pdata->color_aspect_enc))
- val |= ENC_SET_COLOR_ASPECT;
-
- val |= ENC_SET_HP_BITRATE_CONTROL;
-
- if (MFC_FEATURE_SUPPORT(dev, dev->pdata->static_info_enc))
- val |= ENC_SET_STATIC_INFO;
-
- mfc_debug(5, "[CTRLS] ext info val: %#x\n", val);
-
- return val;
-}
-
-static int mfc_enc_get_ctrl_val(struct s5p_mfc_ctx *ctx, struct v4l2_control *ctrl)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_enc *enc = ctx->enc_priv;
- struct s5p_mfc_ctx_ctrl *ctx_ctrl;
- int ret = 0;
- int found = 0;
-
- switch (ctrl->id) {
- case V4L2_CID_CACHEABLE:
- mfc_debug(5, "it is supported only V4L2_MEMORY_MMAP\n");
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_STREAM_SIZE:
- ctrl->value = enc->dst_buf_size;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TYPE:
- ctrl->value = enc->frame_type;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_CHECK_STATE:
- ctrl->value = MFCSTATE_PROCESSING;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG:
- case V4L2_CID_MPEG_MFC51_VIDEO_LUMA_ADDR:
- case V4L2_CID_MPEG_MFC51_VIDEO_CHROMA_ADDR:
- case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_STATUS:
- list_for_each_entry(ctx_ctrl, &ctx->ctrls, list) {
- if (!(ctx_ctrl->type & MFC_CTRL_TYPE_GET))
- continue;
-
- if (ctx_ctrl->id == ctrl->id) {
- if (ctx_ctrl->has_new) {
- ctx_ctrl->has_new = 0;
- ctrl->value = ctx_ctrl->val;
- } else {
- mfc_debug(5, "[CTRLS] Control value "\
- "is not up to date: "\
- "0x%08x\n", ctrl->id);
- return -EINVAL;
- }
-
- found = 1;
- break;
- }
- }
-
- if (!found) {
- mfc_err_ctx("Invalid control: 0x%08x\n", ctrl->id);
- return -EINVAL;
- }
- break;
- case V4L2_CID_MPEG_MFC_GET_VERSION_INFO:
- ctrl->value = dev->pdata->ip_ver;
- break;
- case V4L2_CID_MPEG_MFC_GET_DRIVER_INFO:
- ctrl->value = MFC_DRIVER_INFO;
- break;
- case V4L2_CID_MPEG_MFC_GET_EXTRA_BUFFER_SIZE:
- ctrl->value = MFC_LINEAR_BUF_SIZE;
- break;
- case V4L2_CID_MPEG_VIDEO_QOS_RATIO:
- ctrl->value = ctx->qos_ratio;
- break;
- case V4L2_CID_MPEG_MFC_GET_EXT_INFO:
- ctrl->value = mfc_enc_ext_info(ctx);
- break;
- case V4L2_CID_MPEG_VIDEO_BPG_HEADER_SIZE:
- ctrl->value = enc->header_size;
- break;
- default:
- mfc_err_ctx("Invalid control: 0x%08x\n", ctrl->id);
- ret = -EINVAL;
- break;
- }
-
- mfc_debug(5, "[CTRLS] get id: %#x, value: %d\n", ctrl->id, ctrl->value);
-
- return ret;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
- int ret = 0;
-
- mfc_debug_enter();
- ret = mfc_enc_get_ctrl_val(ctx, ctrl);
- mfc_debug_leave();
-
- return ret;
-}
-
-static inline int mfc_enc_h264_level(enum v4l2_mpeg_video_h264_level lvl)
-{
- static unsigned int t[V4L2_MPEG_VIDEO_H264_LEVEL_5_1 + 1] = {
- /* V4L2_MPEG_VIDEO_H264_LEVEL_1_0 */ 10,
- /* V4L2_MPEG_VIDEO_H264_LEVEL_1B */ 9,
- /* V4L2_MPEG_VIDEO_H264_LEVEL_1_1 */ 11,
- /* V4L2_MPEG_VIDEO_H264_LEVEL_1_2 */ 12,
- /* V4L2_MPEG_VIDEO_H264_LEVEL_1_3 */ 13,
- /* V4L2_MPEG_VIDEO_H264_LEVEL_2_0 */ 20,
- /* V4L2_MPEG_VIDEO_H264_LEVEL_2_1 */ 21,
- /* V4L2_MPEG_VIDEO_H264_LEVEL_2_2 */ 22,
- /* V4L2_MPEG_VIDEO_H264_LEVEL_3_0 */ 30,
- /* V4L2_MPEG_VIDEO_H264_LEVEL_3_1 */ 31,
- /* V4L2_MPEG_VIDEO_H264_LEVEL_3_2 */ 32,
- /* V4L2_MPEG_VIDEO_H264_LEVEL_4_0 */ 40,
- /* V4L2_MPEG_VIDEO_H264_LEVEL_4_1 */ 41,
- /* V4L2_MPEG_VIDEO_H264_LEVEL_4_2 */ 42,
- /* V4L2_MPEG_VIDEO_H264_LEVEL_5_0 */ 50,
- /* V4L2_MPEG_VIDEO_H264_LEVEL_5_1 */ 51,
- };
- return t[lvl];
-}
-
-static inline int mfc_enc_mpeg4_level(enum v4l2_mpeg_video_mpeg4_level lvl)
-{
- static unsigned int t[V4L2_MPEG_VIDEO_MPEG4_LEVEL_6 + 1] = {
- /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_0 */ 0,
- /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B, Simple */ 9,
- /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_1 */ 1,
- /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_2 */ 2,
- /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_3 */ 3,
- /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_3B, Advanced */ 7,
- /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_4 */ 4,
- /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_5 */ 5,
- /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_6, Simple */ 6,
- };
- return t[lvl];
-}
-
-static inline int mfc_enc_vui_sar_idc(enum v4l2_mpeg_video_h264_vui_sar_idc sar)
-{
- static unsigned int t[V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED + 1] = {
- /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED */ 0,
- /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_1x1 */ 1,
- /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_12x11 */ 2,
- /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_10x11 */ 3,
- /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_16x11 */ 4,
- /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_40x33 */ 5,
- /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_24x11 */ 6,
- /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_20x11 */ 7,
- /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_32x11 */ 8,
- /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_80x33 */ 9,
- /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_18x11 */ 10,
- /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_15x11 */ 11,
- /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_64x33 */ 12,
- /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_160x99 */ 13,
- /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_4x3 */ 14,
- /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_3x2 */ 15,
- /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_2x1 */ 16,
- /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED */ 255,
- };
- return t[sar];
-}
-
-static int mfc_enc_set_param(struct s5p_mfc_ctx *ctx, struct v4l2_control *ctrl)
-{
- struct s5p_mfc_enc *enc = ctx->enc_priv;
- struct s5p_mfc_enc_params *p = &enc->params;
- int ret = 0;
-
- switch (ctrl->id) {
- case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
- p->gop_size = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
- p->slice_mode =
- (enum v4l2_mpeg_video_multi_slice_mode)ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
- p->slice_mb = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
- p->slice_bit = ctrl->value * 8;
- break;
- case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB_ROW:
- p->slice_mb_row = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB:
- p->intra_refresh_mb = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_PADDING:
- p->pad = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV:
- p->pad_luma = (ctrl->value >> 16) & 0xff;
- p->pad_cb = (ctrl->value >> 8) & 0xff;
- p->pad_cr = (ctrl->value >> 0) & 0xff;
- break;
- case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE:
- p->rc_frame = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_BITRATE:
- p->rc_bitrate = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF:
- p->rc_reaction_coeff = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE:
- enc->force_frame_type = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_VBV_SIZE:
- p->vbv_buf_size = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
- p->seq_hdr_mode =
- (enum v4l2_mpeg_video_header_mode)(ctrl->value);
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE:
- p->frame_skip_mode =
- (enum v4l2_mpeg_mfc51_video_frame_skip_mode)
- (ctrl->value);
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT:
- p->fixed_target_bit = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_B_FRAMES:
- p->num_b_frame = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
- p->codec.h264.profile =
- mfc_enc_h264_profile(ctx, (enum v4l2_mpeg_video_h264_profile)(ctrl->value));
- break;
- case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
- p->codec.h264.level =
- mfc_enc_h264_level((enum v4l2_mpeg_video_h264_level)(ctrl->value));
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_H264_INTERLACE:
- p->codec.h264.interlace = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
- p->codec.h264.loop_filter_mode =
- (enum v4l2_mpeg_video_h264_loop_filter_mode)(ctrl->value);
- break;
- case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:
- p->codec.h264.loop_filter_alpha = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:
- p->codec.h264.loop_filter_beta = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
- p->codec.h264.entropy_mode =
- (enum v4l2_mpeg_video_h264_entropy_mode)(ctrl->value);
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P:
- p->num_refs_for_p = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM:
- p->codec.h264._8x8_transform = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE:
- p->rc_mb = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_H264_RC_FRAME_RATE:
- p->rc_framerate = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
- p->codec.h264.rc_frame_qp = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
- p->codec.h264.rc_min_qp = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
- p->codec.h264.rc_max_qp = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_MIN_QP_P:
- p->codec.h264.rc_min_qp_p = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_MAX_QP_P:
- p->codec.h264.rc_max_qp_p = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_MIN_QP_B:
- p->codec.h264.rc_min_qp_b = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_MAX_QP_B:
- p->codec.h264.rc_max_qp_b = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK:
- p->codec.h264.rc_mb_dark = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH:
- p->codec.h264.rc_mb_smooth = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC:
- p->codec.h264.rc_mb_static = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY:
- p->codec.h264.rc_mb_activity = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
- p->codec.h264.rc_p_frame_qp = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:
- p->codec.h264.rc_b_frame_qp = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE:
- p->codec.h264.ar_vui = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC:
- p->codec.h264.ar_vui_idc =
- mfc_enc_vui_sar_idc((enum v4l2_mpeg_video_h264_vui_sar_idc)(ctrl->value));
- break;
- case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH:
- p->codec.h264.ext_sar_width = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT:
- p->codec.h264.ext_sar_height = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
- p->codec.h264.open_gop = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD:
- p->codec.h264.open_gop_size = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING:
- p->codec.h264.hier_qp_enable = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE:
- p->codec.h264.hier_qp_type =
- (enum v4l2_mpeg_video_h264_hierarchical_coding_type)(ctrl->value);
- break;
- case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER:
- p->codec.h264.num_hier_layer = ctrl->value & 0x7;
- p->codec.h264.hier_ref_type = (ctrl->value >> 16) & 0x1;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_QP:
- p->codec.h264.hier_qp_layer[(ctrl->value >> 16) & 0x7]
- = ctrl->value & 0xFF;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_BIT0:
- p->codec.h264.hier_bit_layer[0] = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_BIT1:
- p->codec.h264.hier_bit_layer[1] = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_BIT2:
- p->codec.h264.hier_bit_layer[2] = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_BIT3:
- p->codec.h264.hier_bit_layer[3] = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_BIT4:
- p->codec.h264.hier_bit_layer[4] = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_BIT5:
- p->codec.h264.hier_bit_layer[5] = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_BIT6:
- p->codec.h264.hier_bit_layer[6] = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING:
- p->codec.h264.sei_gen_enable = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_CURRENT_FRAME_0:
- p->codec.h264.sei_fp_curr_frame_0 = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE:
- p->codec.h264.sei_fp_arrangement_type = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_FMO:
- p->codec.h264.fmo_enable = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE:
- switch ((enum v4l2_mpeg_video_h264_fmo_map_type)(ctrl->value)) {
- case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_INTERLEAVED_SLICES:
- case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_SCATTERED_SLICES:
- case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_RASTER_SCAN:
- case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_WIPE_SCAN:
- p->codec.h264.fmo_slice_map_type = ctrl->value;
- break;
- default:
- ret = -EINVAL;
- }
- break;
- case V4L2_CID_MPEG_VIDEO_H264_FMO_SLICE_GROUP:
- p->codec.h264.fmo_slice_num_grp = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_FMO_RUN_LENGTH:
- p->codec.h264.fmo_run_length[(ctrl->value >> 30) & 0x3]
- = ctrl->value & 0x3FFFFFFF;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_DIRECTION:
- p->codec.h264.fmo_sg_dir = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_RATE:
- p->codec.h264.fmo_sg_rate = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_ASO:
- p->codec.h264.aso_enable = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_ASO_SLICE_ORDER:
- p->codec.h264.aso_slice_order[(ctrl->value >> 18) & 0x7]
- &= ~(0xFF << (((ctrl->value >> 16) & 0x3) << 3));
- p->codec.h264.aso_slice_order[(ctrl->value >> 18) & 0x7]
- |= (ctrl->value & 0xFF) << \
- (((ctrl->value >> 16) & 0x3) << 3);
- break;
- case V4L2_CID_MPEG_VIDEO_H264_PREPEND_SPSPPS_TO_IDR:
- p->codec.h264.prepend_sps_pps_to_idr = ctrl->value ? 1 : 0;
- break;
- case V4L2_CID_MPEG_MFC_H264_ENABLE_LTR:
- p->codec.h264.enable_ltr = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC_H264_NUM_OF_LTR:
- p->codec.h264.num_of_ltr = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC_H264_BASE_PRIORITY:
- p->codec.h264.base_priority = ctrl->value;
- p->codec.h264.set_priority = 1;
- break;
- case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
- switch ((enum v4l2_mpeg_video_mpeg4_profile)(ctrl->value)) {
- case V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE:
- p->codec.mpeg4.profile =
- S5P_FIMV_E_PROFILE_MPEG4_SIMPLE;
- break;
- case V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE:
- p->codec.mpeg4.profile =
- S5P_FIMV_E_PROFILE_MPEG4_ADVANCED_SIMPLE;
- break;
- default:
- ret = -EINVAL;
- }
- break;
- case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
- p->codec.mpeg4.level =
- mfc_enc_mpeg4_level((enum v4l2_mpeg_video_mpeg4_level)(ctrl->value));
- break;
- case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP:
- p->codec.mpeg4.rc_frame_qp = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP:
- p->codec.mpeg4.rc_min_qp = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP:
- p->codec.mpeg4.rc_max_qp = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP_P:
- p->codec.mpeg4.rc_min_qp_p = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP_P:
- p->codec.mpeg4.rc_max_qp_p = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP_B:
- p->codec.mpeg4.rc_min_qp_b = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP_B:
- p->codec.mpeg4.rc_max_qp_b = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL:
- p->codec.mpeg4.quarter_pixel = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP:
- p->codec.mpeg4.rc_p_frame_qp = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP:
- p->codec.mpeg4.rc_b_frame_qp = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_MPEG4_VOP_TIME_RES:
- p->codec.mpeg4.vop_time_res = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_MPEG4_VOP_FRM_DELTA:
- p->codec.mpeg4.vop_frm_delta = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_H263_RC_FRAME_RATE:
- p->rc_framerate = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP:
- p->codec.mpeg4.rc_frame_qp = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H263_MIN_QP:
- p->codec.mpeg4.rc_min_qp = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H263_MAX_QP:
- p->codec.mpeg4.rc_max_qp = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H263_MIN_QP_P:
- p->codec.mpeg4.rc_min_qp_p = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H263_MAX_QP_P:
- p->codec.mpeg4.rc_max_qp_p = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP:
- p->codec.mpeg4.rc_p_frame_qp = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC70_VIDEO_VP8_VERSION:
- p->codec.vp8.vp8_version = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC70_VIDEO_VP8_RC_FRAME_RATE:
- p->rc_framerate = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_VP8_MIN_QP:
- p->codec.vp8.rc_min_qp = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_VP8_MAX_QP:
- p->codec.vp8.rc_max_qp = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_VP8_MIN_QP_P:
- p->codec.vp8.rc_min_qp_p = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_VP8_MAX_QP_P:
- p->codec.vp8.rc_max_qp_p = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_VP8_I_FRAME_QP:
- p->codec.vp8.rc_frame_qp = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_VP8_P_FRAME_QP:
- p->codec.vp8.rc_p_frame_qp = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC70_VIDEO_VP8_NUM_OF_PARTITIONS:
- p->codec.vp8.vp8_numberofpartitions = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC70_VIDEO_VP8_FILTER_LEVEL:
- p->codec.vp8.vp8_filterlevel = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC70_VIDEO_VP8_FILTER_SHARPNESS:
- p->codec.vp8.vp8_filtersharpness = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC70_VIDEO_VP8_GOLDEN_FRAMESEL:
- p->codec.vp8.vp8_goldenframesel = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC70_VIDEO_VP8_GF_REFRESH_PERIOD:
- p->codec.vp8.vp8_gfrefreshperiod = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC70_VIDEO_VP8_HIERARCHY_QP_ENABLE:
- p->codec.vp8.hier_qp_enable = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC70_VIDEO_VP8_HIERARCHY_QP_LAYER0:
- p->codec.vp8.hier_qp_layer[(ctrl->value >> 16) & 0x3]
- = ctrl->value & 0xFF;
- break;
- case V4L2_CID_MPEG_MFC70_VIDEO_VP8_HIERARCHY_QP_LAYER1:
- p->codec.vp8.hier_qp_layer[(ctrl->value >> 16) & 0x3]
- = ctrl->value & 0xFF;
- break;
- case V4L2_CID_MPEG_MFC70_VIDEO_VP8_HIERARCHY_QP_LAYER2:
- p->codec.vp8.hier_qp_layer[(ctrl->value >> 16) & 0x3]
- = ctrl->value & 0xFF;
- break;
- case V4L2_CID_MPEG_VIDEO_VP8_HIERARCHICAL_CODING_LAYER_BIT0:
- p->codec.vp8.hier_bit_layer[0] = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_VP8_HIERARCHICAL_CODING_LAYER_BIT1:
- p->codec.vp8.hier_bit_layer[1] = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_VP8_HIERARCHICAL_CODING_LAYER_BIT2:
- p->codec.vp8.hier_bit_layer[2] = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC70_VIDEO_VP8_REF_NUMBER_FOR_PFRAMES:
- p->num_refs_for_p = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC70_VIDEO_VP8_DISABLE_INTRA_MD4X4:
- p->codec.vp8.intra_4x4mode_disable = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC70_VIDEO_VP8_NUM_TEMPORAL_LAYER:
- p->codec.vp8.num_hier_layer = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_VP9_VERSION:
- p->codec.vp9.vp9_version = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_VP9_RC_FRAME_RATE:
- p->rc_framerate = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_VP9_MIN_QP:
- p->codec.vp9.rc_min_qp = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_VP9_MAX_QP:
- p->codec.vp9.rc_max_qp = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_VP9_MIN_QP_P:
- p->codec.vp9.rc_min_qp_p = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_VP9_MAX_QP_P:
- p->codec.vp9.rc_max_qp_p = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_VP9_I_FRAME_QP:
- p->codec.vp9.rc_frame_qp = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_VP9_P_FRAME_QP:
- p->codec.vp9.rc_p_frame_qp = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_VP9_GOLDEN_FRAMESEL:
- p->codec.vp9.vp9_goldenframesel = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_VP9_GF_REFRESH_PERIOD:
- p->codec.vp9.vp9_gfrefreshperiod = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_VP9_HIERARCHY_QP_ENABLE:
- p->codec.vp9.hier_qp_enable = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER_QP:
- p->codec.vp9.hier_qp_layer[(ctrl->value >> 16) & 0x3]
- = ctrl->value & 0xFF;
- break;
- case V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER_BIT0:
- p->codec.vp9.hier_bit_layer[0] = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER_BIT1:
- p->codec.vp9.hier_bit_layer[1] = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER_BIT2:
- p->codec.vp9.hier_bit_layer[2] = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_VP9_REF_NUMBER_FOR_PFRAMES:
- p->num_refs_for_p = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER:
- p->codec.vp9.num_hier_layer = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_VP9_MAX_PARTITION_DEPTH:
- p->codec.vp9.max_partition_depth = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_VP9_DISABLE_INTRA_PU_SPLIT:
- p->codec.vp9.intra_pu_split_disable = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_DISABLE_IVF_HEADER:
- p->ivf_header_disable = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_VP9_PROFILE:
- p->codec.vp9.profile = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP:
- p->codec.hevc.rc_frame_qp = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP:
- p->codec.hevc.rc_p_frame_qp = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP:
- p->codec.hevc.rc_b_frame_qp = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_RC_FRAME_RATE:
- p->rc_framerate = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP:
- p->codec.hevc.rc_min_qp = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP:
- p->codec.hevc.rc_max_qp = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP_P:
- p->codec.hevc.rc_min_qp_p = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP_P:
- p->codec.hevc.rc_max_qp_p = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP_B:
- p->codec.hevc.rc_min_qp_b = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP_B:
- p->codec.hevc.rc_max_qp_b = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL:
- p->codec.hevc.level = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE:
- p->codec.hevc.profile = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_ADAPTIVE_RC_DARK:
- p->codec.hevc.rc_lcu_dark = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_ADAPTIVE_RC_SMOOTH:
- p->codec.hevc.rc_lcu_smooth = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_ADAPTIVE_RC_STATIC:
- p->codec.hevc.rc_lcu_static = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_ADAPTIVE_RC_ACTIVITY:
- p->codec.hevc.rc_lcu_activity = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_TIER_FLAG:
- p->codec.hevc.tier_flag = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_MAX_PARTITION_DEPTH:
- p->codec.hevc.max_partition_depth = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_REF_NUMBER_FOR_PFRAMES:
- p->num_refs_for_p = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_REFRESH_TYPE:
- p->codec.hevc.refreshtype = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_CONST_INTRA_PRED_ENABLE:
- p->codec.hevc.const_intra_period_enable = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_LOSSLESS_CU_ENABLE:
- p->codec.hevc.lossless_cu_enable = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_WAVEFRONT_ENABLE:
- p->codec.hevc.wavefront_enable = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_LF_DISABLE:
- p->codec.hevc.loopfilter_disable = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_LF_SLICE_BOUNDARY:
- p->codec.hevc.loopfilter_across = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_LTR_ENABLE:
- p->codec.hevc.enable_ltr = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_QP_ENABLE:
- p->codec.hevc.hier_qp_enable = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_TYPE:
- p->codec.hevc.hier_qp_type =
- (enum v4l2_mpeg_video_hevc_hierarchical_coding_type)(ctrl->value);
- break;
- case V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER:
- p->codec.hevc.num_hier_layer = ctrl->value & 0x7;
- p->codec.hevc.hier_ref_type = (ctrl->value >> 16) & 0x1;
- break;
- case V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_QP:
- p->codec.hevc.hier_qp_layer[(ctrl->value >> 16) & 0x7]
- = ctrl->value & 0xFF;
- break;
- case V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_BIT0:
- p->codec.hevc.hier_bit_layer[0] = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_BIT1:
- p->codec.hevc.hier_bit_layer[1] = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_BIT2:
- p->codec.hevc.hier_bit_layer[2] = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_BIT3:
- p->codec.hevc.hier_bit_layer[3] = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_BIT4:
- p->codec.hevc.hier_bit_layer[4] = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_BIT5:
- p->codec.hevc.hier_bit_layer[5] = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_BIT6:
- p->codec.hevc.hier_bit_layer[6] = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_GENERAL_PB_ENABLE:
- p->codec.hevc.general_pb_enable = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_TEMPORAL_ID_ENABLE:
- p->codec.hevc.temporal_id_enable = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_STRONG_SMOTHING_FLAG:
- p->codec.hevc.strong_intra_smooth = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_DISABLE_INTRA_PU_SPLIT:
- p->codec.hevc.intra_pu_split_disable = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_DISABLE_TMV_PREDICTION:
- p->codec.hevc.tmv_prediction_disable = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1:
- p->codec.hevc.max_num_merge_mv = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_WITHOUT_STARTCODE_ENABLE:
- p->codec.hevc.encoding_nostartcode_enable = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_REFRESH_PERIOD:
- p->codec.hevc.refreshperiod = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_LF_BETA_OFFSET_DIV2:
- p->codec.hevc.lf_beta_offset_div2 = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_LF_TC_OFFSET_DIV2:
- p->codec.hevc.lf_tc_offset_div2 = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD:
- p->codec.hevc.size_of_length_field = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_USER_REF:
- p->codec.hevc.user_ref = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_STORE_REF:
- p->codec.hevc.store_ref = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_ROI_ENABLE:
- p->roi_enable = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC_H264_VUI_RESTRICTION_ENABLE:
- p->codec.h264.vui_enable = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_HEVC_PREPEND_SPSPPS_TO_IDR:
- p->codec.hevc.prepend_sps_pps_to_idr = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC_CONFIG_QP_ENABLE:
- p->dynamic_qp = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC_CONFIG_QP:
- p->config_qp = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_RC_PVC_ENABLE:
- /* It is valid for H.264, HEVC, VP8, VP9 */
- p->rc_pvc = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_TEMPORAL_SHORTTERM_MAX_LAYER:
- p->num_hier_max_layer = ctrl->value;
- break;
- case V4L2_CID_MPEG_MFC90_VIDEO_HEVC_SIGN_DATA_HIDING:
- break;
- case V4L2_CID_MPEG_VIDEO_WEIGHTED_ENABLE:
- p->weighted_enable = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_BPG_THUMBNAIL_SIZE:
- /* It should be included when NAL_START */
- p->codec.bpg.thumb_size = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_BPG_EXIF_SIZE:
- /* It should be included when NAL_START */
- p->codec.bpg.exif_size = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_RATIO_OF_INTRA:
- p->ratio_intra = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_FULL_RANGE_FLAG:
- p->check_color_range = 1;
- p->color_range = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_COLOUR_PRIMARIES:
- p->colour_primaries = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_TRANSFER_CHARACTERISTICS:
- p->transfer_characteristics = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_MATRIX_COEFFICIENTS:
- p->matrix_coefficients = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_HIERARCHICAL_BITRATE_CTRL:
- p->hier_bitrate_ctrl = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_STATIC_INFO_ENABLE:
- p->static_info_enable = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_SEI_MAX_PIC_AVERAGE_LIGHT:
- p->max_pic_average_light = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_SEI_MAX_CONTENT_LIGHT:
- p->max_content_light = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_SEI_MAX_DISPLAY_LUMINANCE:
- p->max_display_luminance = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_SEI_MIN_DISPLAY_LUMINANCE:
- p->min_display_luminance = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_SEI_WHITE_POINT:
- p->white_point = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_SEI_DISPLAY_PRIMARIES_0:
- p->display_primaries_0 = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_SEI_DISPLAY_PRIMARIES_1:
- p->display_primaries_1 = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_SEI_DISPLAY_PRIMARIES_2:
- p->display_primaries_2 = ctrl->value;
- break;
- default:
- mfc_err_ctx("Invalid control: 0x%08x\n", ctrl->id);
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-static int mfc_enc_set_ctrl_val(struct s5p_mfc_ctx *ctx, struct v4l2_control *ctrl)
-{
- struct s5p_mfc_enc *enc = ctx->enc_priv;
- struct s5p_mfc_enc_params *p = &enc->params;
- struct s5p_mfc_ctx_ctrl *ctx_ctrl;
- int ret = 0;
- int found = 0;
- int index = 0;
-
- mfc_debug(5, "[CTRLS] id: %#x, value: %d\n", ctrl->id, ctrl->value);
-
- switch (ctrl->id) {
- case V4L2_CID_CACHEABLE:
- mfc_debug(5, "it is supported only V4L2_MEMORY_MMAP\n");
- break;
- case V4L2_CID_MPEG_VIDEO_QOS_RATIO:
- ctx->qos_ratio = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
- case V4L2_CID_MPEG_VIDEO_H263_MAX_QP:
- case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP:
- case V4L2_CID_MPEG_VIDEO_VP8_MAX_QP:
- case V4L2_CID_MPEG_VIDEO_VP9_MAX_QP:
- case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP:
- case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
- case V4L2_CID_MPEG_VIDEO_H263_MIN_QP:
- case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP:
- case V4L2_CID_MPEG_VIDEO_VP8_MIN_QP:
- case V4L2_CID_MPEG_VIDEO_VP9_MIN_QP:
- case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP:
- case V4L2_CID_MPEG_VIDEO_H264_MAX_QP_P:
- case V4L2_CID_MPEG_VIDEO_H263_MAX_QP_P:
- case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP_P:
- case V4L2_CID_MPEG_VIDEO_VP8_MAX_QP_P:
- case V4L2_CID_MPEG_VIDEO_VP9_MAX_QP_P:
- case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP_P:
- case V4L2_CID_MPEG_VIDEO_H264_MIN_QP_P:
- case V4L2_CID_MPEG_VIDEO_H263_MIN_QP_P:
- case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP_P:
- case V4L2_CID_MPEG_VIDEO_VP8_MIN_QP_P:
- case V4L2_CID_MPEG_VIDEO_VP9_MIN_QP_P:
- case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP_P:
- case V4L2_CID_MPEG_VIDEO_H264_MAX_QP_B:
- case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP_B:
- case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP_B:
- case V4L2_CID_MPEG_VIDEO_H264_MIN_QP_B:
- case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP_B:
- case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP_B:
- case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG:
- case V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE:
- case V4L2_CID_MPEG_MFC51_VIDEO_I_PERIOD_CH:
- case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_RATE_CH:
- case V4L2_CID_MPEG_MFC51_VIDEO_BIT_RATE_CH:
- case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_CH:
- case V4L2_CID_MPEG_VIDEO_VP8_HIERARCHICAL_CODING_LAYER_CH:
- case V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER_CH:
- case V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_CH:
- case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
- case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
- case V4L2_CID_MPEG_MFC_H264_MARK_LTR:
- case V4L2_CID_MPEG_MFC_H264_USE_LTR:
- case V4L2_CID_MPEG_MFC_H264_BASE_PRIORITY:
- case V4L2_CID_MPEG_MFC_CONFIG_QP:
- case V4L2_CID_MPEG_VIDEO_ROI_CONTROL:
- case V4L2_CID_MPEG_VIDEO_YSUM:
- case V4L2_CID_MPEG_VIDEO_RATIO_OF_INTRA:
- list_for_each_entry(ctx_ctrl, &ctx->ctrls, list) {
- if (!(ctx_ctrl->type & MFC_CTRL_TYPE_SET))
- continue;
-
- if (ctx_ctrl->id == ctrl->id) {
- ctx_ctrl->has_new = 1;
- ctx_ctrl->val = ctrl->value;
- if (ctx_ctrl->id == \
- V4L2_CID_MPEG_MFC51_VIDEO_FRAME_RATE_CH) {
- ctx_ctrl->val &= ~(0xFFFF << 16);
- ctx_ctrl->val |= ctx_ctrl->val << 16;
- ctx_ctrl->val &= ~(0xFFFF);
- ctx_ctrl->val |= p->rc_frame_delta & 0xFFFF;
- }
- if (((ctx_ctrl->id == \
- V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_CH) ||
- (ctx_ctrl->id == \
- V4L2_CID_MPEG_VIDEO_VP8_HIERARCHICAL_CODING_LAYER_CH) ||
- (ctx_ctrl->id == \
- V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER_CH) ||
- (ctx_ctrl->id == \
- V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_CH)) &&
- (enc->sh_handle_svc.fd == -1)) {
- enc->sh_handle_svc.fd = ctrl->value;
- if (s5p_mfc_mem_get_user_shared_handle(ctx,
- &enc->sh_handle_svc))
- return -EINVAL;
- else
- mfc_debug(2, "[MEMINFO][HIERARCHICAL] shared handle fd: %d, vaddr: 0x%p\n",
- enc->sh_handle_svc.fd,
- enc->sh_handle_svc.vaddr);
- }
- if (ctx_ctrl->id == V4L2_CID_MPEG_MFC51_VIDEO_I_PERIOD_CH &&
- p->i_frm_ctrl_mode) {
- ctx_ctrl->val = ctx_ctrl->val * (p->num_b_frame + 1);
- if (ctx_ctrl->val >= 0x3FFFFFFF) {
- mfc_info_ctx("I frame interval is bigger than max: %d\n",
- ctx_ctrl->val);
- ctx_ctrl->val = 0x3FFFFFFF;
- }
- }
- if (ctx_ctrl->id == V4L2_CID_MPEG_VIDEO_H264_LEVEL)
- ctx_ctrl->val = mfc_enc_h264_level((enum v4l2_mpeg_video_h264_level)(ctrl->value));
- if (ctx_ctrl->id == V4L2_CID_MPEG_VIDEO_H264_PROFILE)
- ctx_ctrl->val = mfc_enc_h264_profile(ctx, (enum v4l2_mpeg_video_h264_profile)(ctrl->value));
- if (ctx_ctrl->id == V4L2_CID_MPEG_VIDEO_ROI_CONTROL) {
- if (enc->sh_handle_roi.fd == -1) {
- enc->sh_handle_roi.fd = ctrl->value;
- if (s5p_mfc_mem_get_user_shared_handle(ctx,
- &enc->sh_handle_roi))
- return -EINVAL;
- else
- mfc_debug(2, "[MEMINFO][ROI] shared handle fd: %d, vaddr: 0x%p\n",
- enc->sh_handle_roi.fd,
- enc->sh_handle_roi.vaddr);
- }
- index = enc->roi_index;
- memcpy(&enc->roi_info[index],
- enc->sh_handle_roi.vaddr,
- sizeof(struct mfc_enc_roi_info));
- if (copy_from_user(enc->roi_buf[index].vaddr,
- enc->roi_info[index].addr,
- enc->roi_info[index].size))
- return -EFAULT;
- }
-
- found = 1;
- break;
- }
- }
-
- if (!found) {
- mfc_err_ctx("Invalid control: 0x%08x\n", ctrl->id);
- return -EINVAL;
- }
- break;
- default:
- ret = mfc_enc_set_param(ctx, ctrl);
- break;
- }
-
- return ret;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
- int ret = 0;
-
- mfc_debug_enter();
-
- ret = mfc_enc_check_ctrl_val(ctx, ctrl);
- if (ret != 0)
- return ret;
-
- ret = mfc_enc_set_ctrl_val(ctx, ctrl);
-
- mfc_debug_leave();
-
- return ret;
-}
-
-static int vidioc_g_ext_ctrls(struct file *file, void *priv,
- struct v4l2_ext_controls *f)
-{
- struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
- struct v4l2_ext_control *ext_ctrl;
- struct v4l2_control ctrl;
- int i;
- int ret = 0;
-
- if (f->which != V4L2_CTRL_CLASS_MPEG)
- return -EINVAL;
-
- for (i = 0; i < f->count; i++) {
- ext_ctrl = (f->controls + i);
-
- ctrl.id = ext_ctrl->id;
-
- ret = mfc_enc_get_ctrl_val(ctx, &ctrl);
- if (ret == 0) {
- ext_ctrl->value = ctrl.value;
- } else {
- f->error_idx = i;
- break;
- }
-
- mfc_debug(5, "[CTRLS][%d] id: %#x, value: %d\n",
- i, ext_ctrl->id, ext_ctrl->value);
- }
-
- return ret;
-}
-
-static int vidioc_s_ext_ctrls(struct file *file, void *priv,
- struct v4l2_ext_controls *f)
-{
- struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
- struct v4l2_ext_control *ext_ctrl;
- struct v4l2_control ctrl;
- int i;
- int ret = 0;
-
- if (f->which != V4L2_CTRL_CLASS_MPEG)
- return -EINVAL;
-
- for (i = 0; i < f->count; i++) {
- ext_ctrl = (f->controls + i);
-
- ctrl.id = ext_ctrl->id;
- ctrl.value = ext_ctrl->value;
-
- ret = mfc_enc_check_ctrl_val(ctx, &ctrl);
- if (ret != 0) {
- f->error_idx = i;
- break;
- }
-
- ret = mfc_enc_set_param(ctx, &ctrl);
- if (ret != 0) {
- f->error_idx = i;
- break;
- }
-
- mfc_debug(5, "[CTRLS][%d] id: %#x, value: %d\n",
- i, ext_ctrl->id, ext_ctrl->value);
- }
-
- return ret;
-}
-
-static int vidioc_try_ext_ctrls(struct file *file, void *priv,
- struct v4l2_ext_controls *f)
-{
- struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
- struct v4l2_ext_control *ext_ctrl;
- struct v4l2_control ctrl;
- int i;
- int ret = 0;
-
- if (f->which != V4L2_CTRL_CLASS_MPEG)
- return -EINVAL;
-
- for (i = 0; i < f->count; i++) {
- ext_ctrl = (f->controls + i);
-
- ctrl.id = ext_ctrl->id;
- ctrl.value = ext_ctrl->value;
-
- ret = mfc_enc_check_ctrl_val(ctx, &ctrl);
- if (ret != 0) {
- f->error_idx = i;
- break;
- }
-
- mfc_debug(2, "[%d] id: 0x%08x, value: %d\n", i, ext_ctrl->id, ext_ctrl->value);
- }
-
- return ret;
-}
-
-static const struct v4l2_ioctl_ops s5p_mfc_enc_ioctl_ops = {
- .vidioc_querycap = vidioc_querycap,
- .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane,
- .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane,
- .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt,
- .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt,
- .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt,
- .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt,
- .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_vid_cap_mplane,
- .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_vid_out_mplane,
- .vidioc_g_crop = vidioc_g_crop,
- .vidioc_s_crop = vidioc_s_crop,
- .vidioc_reqbufs = vidioc_reqbufs,
- .vidioc_querybuf = vidioc_querybuf,
- .vidioc_qbuf = vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls,
- .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls,
- .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls,
-};
-
-const struct v4l2_ioctl_ops *s5p_mfc_get_enc_v4l2_ioctl_ops(void)
-{
- return &s5p_mfc_enc_ioctl_ops;
-}
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_enc.h
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __S5P_MFC_ENC_H
-#define __S5P_MFC_ENC_H __FILE__
-
-#include "s5p_mfc_common.h"
-
-const struct v4l2_ioctl_ops *s5p_mfc_get_enc_v4l2_ioctl_ops(void);
-
-#endif /* __S5P_MFC_ENC_H */
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_enc_internal.h
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __S5P_MFC_ENC_INTERNAL_H
-#define __S5P_MFC_ENC_INTERNAL_H __FILE__
-
-#include "s5p_mfc_common.h"
-
-/*
- * RGB encoding information to avoid confusion.
- *
- * V4L2_PIX_FMT_ARGB32 takes ARGB data like below.
- * MSB LSB
- * 3 2 1
- * 2 4 6 8 0
- * |B......BG......GR......RA......A|
- */
-struct s5p_mfc_fmt enc_formats[] = {
- {
- .name = "4:2:0 3 Planes Y/Cb/Cr",
- .fourcc = V4L2_PIX_FMT_YUV420M,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME,
- .num_planes = 3,
- .mem_planes = 3,
- },
- {
- .name = "4:2:0 3 Planes Y/Cb/Cr single",
- .fourcc = V4L2_PIX_FMT_YUV420N,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME,
- .num_planes = 3,
- .mem_planes = 1,
- },
- {
- .name = "4:2:0 3 Planes Y/Cr/Cb",
- .fourcc = V4L2_PIX_FMT_YVU420M,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME,
- .num_planes = 3,
- .mem_planes = 3,
- },
- {
- .name = "4:2:0 2 Planes",
- .fourcc = V4L2_PIX_FMT_NV12M,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME,
- .num_planes = 2,
- .mem_planes = 2,
- },
- {
- .name = "4:2:0 2 Planes Y/CbCr single",
- .fourcc = V4L2_PIX_FMT_NV12N,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME,
- .num_planes = 2,
- .mem_planes = 1,
- },
- {
- .name = "4:2:0 2 Planes Y/CbCr 8+2 10bit",
- .fourcc = V4L2_PIX_FMT_NV12M_S10B,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME | MFC_FMT_10BIT,
- .num_planes = 2,
- .mem_planes = 2,
- },
- {
- .name = "4:2:0 2 Planes Y/CbCr P010 10bit",
- .fourcc = V4L2_PIX_FMT_NV12M_P010,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME | MFC_FMT_10BIT,
- .num_planes = 2,
- .mem_planes = 2,
- },
- {
- .name = "4:2:0 2 Planes Y/CrCb",
- .fourcc = V4L2_PIX_FMT_NV21M,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME,
- .num_planes = 2,
- .mem_planes = 2,
- },
- {
- .name = "4:2:0 2 Planes Y/CrCb 8+2 10bit",
- .fourcc = V4L2_PIX_FMT_NV21M_S10B,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME | MFC_FMT_10BIT,
- .num_planes = 2,
- .mem_planes = 2,
- },
- {
- .name = "4:2:0 2 Planes Y/CrCb P010 10bit",
- .fourcc = V4L2_PIX_FMT_NV21M_P010,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME | MFC_FMT_10BIT,
- .num_planes = 2,
- .mem_planes = 2,
- },
- {
- .name = "4:2:2 2 Planes Y/CbCr",
- .fourcc = V4L2_PIX_FMT_NV16M,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME | MFC_FMT_422,
- .num_planes = 2,
- .mem_planes = 2,
- },
- {
- .name = "4:2:2 2 Planes Y/CbCr 8+2 10bit",
- .fourcc = V4L2_PIX_FMT_NV16M_S10B,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME | MFC_FMT_10BIT | MFC_FMT_422,
- .num_planes = 2,
- .mem_planes = 2,
- },
- {
- .name = "4:2:2 2 Planes Y/CrCb 8+2 10bit",
- .fourcc = V4L2_PIX_FMT_NV61M_S10B,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME | MFC_FMT_10BIT | MFC_FMT_422,
- .num_planes = 2,
- .mem_planes = 2,
- },
- {
- .name = "4:2:2 2 Planes Y/CbCr P210 10bit",
- .fourcc = V4L2_PIX_FMT_NV16M_P210,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME | MFC_FMT_10BIT | MFC_FMT_422,
- .num_planes = 2,
- .mem_planes = 2,
- },
- {
- .name = "4:2:2 2 Planes Y/CrCb P210 10bit",
- .fourcc = V4L2_PIX_FMT_NV61M_P210,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME | MFC_FMT_10BIT | MFC_FMT_422,
- .num_planes = 2,
- .mem_planes = 2,
- },
- {
- .name = "4:2:2 2 Planes Y/CrCb",
- .fourcc = V4L2_PIX_FMT_NV61M,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME | MFC_FMT_422,
- .num_planes = 2,
- .mem_planes = 2,
- },
- {
- .name = "RGB888 1 Plane 24bpp",
- .fourcc = V4L2_PIX_FMT_RGB24,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME | MFC_FMT_RGB,
- .num_planes = 1,
- .mem_planes = 1,
- },
- {
- .name = "RGB565 1 Plane 16bpp",
- .fourcc = V4L2_PIX_FMT_RGB565,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME | MFC_FMT_RGB,
- .num_planes = 1,
- .mem_planes = 1,
- },
- {
- .name = "RGBX8888 1 Plane 32bpp",
- .fourcc = V4L2_PIX_FMT_RGB32X,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME | MFC_FMT_RGB,
- .num_planes = 1,
- .mem_planes = 1,
- },
- {
- .name = "BGRA8888 1 Plane 32bpp",
- .fourcc = V4L2_PIX_FMT_BGR32,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME | MFC_FMT_RGB,
- .num_planes = 1,
- .mem_planes = 1,
- },
- {
- .name = "ARGB8888 1 Plane 32bpp",
- .fourcc = V4L2_PIX_FMT_ARGB32,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME | MFC_FMT_RGB,
- .num_planes = 1,
- .mem_planes = 1,
- },
- {
- .name = "H264 Encoded Stream",
- .fourcc = V4L2_PIX_FMT_H264,
- .codec_mode = S5P_FIMV_CODEC_H264_ENC,
- .type = MFC_FMT_STREAM,
- .num_planes = 1,
- .mem_planes = 1,
- },
- {
- .name = "MPEG4 Encoded Stream",
- .fourcc = V4L2_PIX_FMT_MPEG4,
- .codec_mode = S5P_FIMV_CODEC_MPEG4_ENC,
- .type = MFC_FMT_STREAM,
- .num_planes = 1,
- .mem_planes = 1,
- },
- {
- .name = "H263 Encoded Stream",
- .fourcc = V4L2_PIX_FMT_H263,
- .codec_mode = S5P_FIMV_CODEC_H263_ENC,
- .type = MFC_FMT_STREAM,
- .num_planes = 1,
- .mem_planes = 1,
- },
- {
- .name = "VP8 Encoded Stream",
- .fourcc = V4L2_PIX_FMT_VP8,
- .codec_mode = S5P_FIMV_CODEC_VP8_ENC,
- .type = MFC_FMT_STREAM,
- .num_planes = 1,
- .mem_planes = 1,
- },
- {
- .name = "VP9 Encoded Stream",
- .fourcc = V4L2_PIX_FMT_VP9,
- .codec_mode = S5P_FIMV_CODEC_VP9_ENC,
- .type = MFC_FMT_STREAM,
- .num_planes = 1,
- .mem_planes = 1,
- },
- {
- .name = "HEVC Encoded Stream",
- .fourcc = V4L2_PIX_FMT_HEVC,
- .codec_mode = S5P_FIMV_CODEC_HEVC_ENC,
- .type = MFC_FMT_STREAM,
- .num_planes = 1,
- .mem_planes = 1,
- },
- {
- .name = "BPG Encoded Stream",
- .fourcc = V4L2_PIX_FMT_BPG,
- .codec_mode = S5P_FIMV_CODEC_BPG_ENC,
- .type = MFC_FMT_STREAM,
- .num_planes = 1,
- .mem_planes = 1,
- },
-};
-
-#define NUM_FORMATS ARRAY_SIZE(enc_formats)
-
-static struct v4l2_queryctrl controls[] = {
- {
- .id = V4L2_CID_CACHEABLE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Cacheable flag",
- .minimum = 0,
- .maximum = 3,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_GOP_SIZE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "The period of intra frame",
- .minimum = 0,
- .maximum = (1 << 30) - 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "The slice partitioning method",
- .minimum = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
- .maximum = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_FIXED_BYTES,
- .step = 1,
- .default_value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "The number of MB in a slice",
- .minimum = 1,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "The maximum bits per slices",
- .minimum = 350,
- .maximum = INT_MAX / 8,
- .step = 1,
- .default_value = 350,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB_ROW,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "The number of MB row in a slice",
- .minimum = 1,
- .maximum = INT_MAX / 256,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "The number of intra refresh MBs",
- .minimum = 0,
- .maximum = (1 << 18) - 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_PADDING,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Padding control enable",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Padding Color YUV Value",
- .minimum = 0,
- .maximum = (1 << 24) - 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Frame level rate control enable",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_BITRATE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Target bit rate rate-control",
- .minimum = 1,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Rate control reaction coeff.",
- .minimum = 1,
- .maximum = (1 << 16) - 1,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_STREAM_SIZE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Encoded stream size",
- .minimum = 0,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- .flags = V4L2_CTRL_FLAG_READ_ONLY,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_COUNT,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Encoded frame count",
- .minimum = 0,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- .flags = V4L2_CTRL_FLAG_READ_ONLY,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TYPE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Encoded frame type",
- .minimum = 0,
- .maximum = 5,
- .step = 1,
- .default_value = 0,
- .flags = V4L2_CTRL_FLAG_READ_ONLY,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Force frame type",
- .minimum = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_DISABLED,
- .maximum = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_NOT_CODED,
- .step = 1,
- .default_value = \
- V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_DISABLED,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_VBV_SIZE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "VBV buffer size (1Kbits)",
- .minimum = 0,
- .maximum = (1 << 16) - 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_HEADER_MODE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Sequence header mode",
- .minimum = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE,
- .maximum = V4L2_MPEG_VIDEO_HEADER_MODE_AT_THE_READY,
- .step = 1,
- .default_value = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Frame skip enable",
- .minimum = V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_DISABLED,
- .maximum = V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT,
- .step = 1,
- .default_value = V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_DISABLED,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Fixed target bit enable",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_B_FRAMES,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "The number of B frames",
- .minimum = 0,
- .maximum = 2,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_PROFILE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "H264 profile",
- .minimum = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
- .maximum = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH,
- .step = 1,
- .default_value = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_LEVEL,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "H264 level",
- .minimum = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
- .maximum = V4L2_MPEG_VIDEO_H264_LEVEL_5_1,
- .step = 1,
- .default_value = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_INTERLACE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "H264 interlace mode",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "H264 loop filter mode",
- .minimum = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED,
- .maximum = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_S_B,
- .step = 1,
- .default_value = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "H264 loop filter alpha offset",
- .minimum = -12,
- .maximum = 12,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "H264 loop filter beta offset",
- .minimum = -12,
- .maximum = 12,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "H264 entorpy mode",
- .minimum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
- .maximum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC,
- .step = 1,
- .default_value = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "The number of ref. picture of P",
- .minimum = 1,
- .maximum = 2,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "H264 8x8 transform enable",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "MB level rate control",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_RC_FRAME_RATE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "H264 Frame rate",
- .minimum = 1,
- .maximum = (1 << 16) - 1,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "H264 Frame QP value",
- .minimum = 0,
- .maximum = 51,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "H264 dark region adaptive",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "H264 smooth region adaptive",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "H264 static region adaptive",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "H264 MB activity adaptive",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "H264 P frame QP value",
- .minimum = 0,
- .maximum = 51,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "H264 B frame QP value",
- .minimum = 0,
- .maximum = 51,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Aspect ratio VUI enable",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "VUI aspect ratio IDC",
- .minimum = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED,
- .maximum = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Horizontal size of SAR",
- .minimum = 0,
- .maximum = (1 << 16) - 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Vertical size of SAR",
- .minimum = 0,
- .maximum = (1 << 16) - 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "GOP closure",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_I_PERIOD,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "H264 I period",
- .minimum = 0,
- .maximum = (1 << 16) - 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Hierarchical Coding",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hierarchical Coding Type",
- .minimum = V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B,
- .maximum = V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P,
- .step = 1,
- .default_value = V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hierarchical Coding Layer",
- .minimum = 0,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hierarchical Coding Layer QP",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "frame pack sei generation flag",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_SEI_FP_CURRENT_FRAME_0,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Current frame is frame 0 flag",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Frame packing arrangement type",
- .minimum = V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_SIDE_BY_SIDE,
- .maximum = V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_TEMPORAL,
- .step = 1,
- .default_value = V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_SIDE_BY_SIDE,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_FMO,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Flexible Macroblock Order",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Map type for FMO",
- .minimum = V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_INTERLEAVED_SLICES,
- .maximum = V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_WIPE_SCAN,
- .step = 1,
- .default_value = \
- V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_INTERLEAVED_SLICES,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_FMO_SLICE_GROUP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Number of slice groups for FMO",
- .minimum = 1,
- .maximum = 4,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_FMO_RUN_LENGTH,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "FMO Run Length",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_DIRECTION,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Direction of the slice group",
- .minimum = V4L2_MPEG_VIDEO_H264_FMO_CHANGE_DIR_RIGHT,
- .maximum = V4L2_MPEG_VIDEO_H264_FMO_CHANGE_DIR_LEFT,
- .step = 1,
- .default_value = V4L2_MPEG_VIDEO_H264_FMO_CHANGE_DIR_RIGHT,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_RATE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Size of the first slice group",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_ASO,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Arbitrary Slice Order",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_ASO_SLICE_ORDER,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "ASO Slice order",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_PREPEND_SPSPPS_TO_IDR,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Prepend SPS/PPS to every IDR",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "MPEG4 profile",
- .minimum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
- .maximum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE,
- .step = 1,
- .default_value = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "MPEG4 level",
- .minimum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
- .maximum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_6,
- .step = 1,
- .default_value = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "MPEG4 Frame QP value",
- .minimum = 1,
- .maximum = 31,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_MPEG4_QPEL,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Quarter pixel search enable",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "MPEG4 P frame QP value",
- .minimum = 1,
- .maximum = 31,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "MPEG4 B frame QP value",
- .minimum = 1,
- .maximum = 31,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_MPEG4_VOP_TIME_RES,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "MPEG4 vop time resolution",
- .minimum = 0,
- .maximum = (1 << 16) - 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_MPEG4_VOP_FRM_DELTA,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "MPEG4 frame delta",
- .minimum = 1,
- .maximum = (1 << 16) - 1,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_H263_RC_FRAME_RATE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "H263 Frame rate",
- .minimum = 1,
- .maximum = (1 << 8) - 1,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "H263 Frame QP value",
- .minimum = 1,
- .maximum = 31,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "H263 P frame QP value",
- .minimum = 1,
- .maximum = 31,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Frame Tag",
- .minimum = 0,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_STATUS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Frame Status",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_QOS_RATIO,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "QoS ratio value",
- .minimum = 20,
- .maximum = 1000,
- .step = 10,
- .default_value = 100,
- },
- {
- .id = V4L2_CID_MPEG_MFC70_VIDEO_VP8_VERSION,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "VP8 version",
- .minimum = 0,
- .maximum = 3,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_VP8_I_FRAME_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "VP8 Frame QP value",
- .minimum = 0,
- .maximum = 127,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_VP8_P_FRAME_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "VP8 Frame QP value",
- .minimum = 0,
- .maximum = 127,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC70_VIDEO_VP8_RC_FRAME_RATE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "VP8 Frame rate",
- .minimum = 1,
- .maximum = (1 << 16) - 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC70_VIDEO_VP8_NUM_OF_PARTITIONS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "VP8 number of partitions",
- .minimum = 0,
- .maximum = 8,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC70_VIDEO_VP8_FILTER_LEVEL,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "VP8 loop filter level",
- .minimum = 0,
- .maximum = 63,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC70_VIDEO_VP8_FILTER_SHARPNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "VP8 loop filter sharpness",
- .minimum = 0,
- .maximum = 7,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC70_VIDEO_VP8_GOLDEN_FRAMESEL,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "VP8 indication of golden frame",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC70_VIDEO_VP8_GF_REFRESH_PERIOD,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "VP8 indication of golden frame",
- .minimum = 0,
- .maximum = (1 << 16) - 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC70_VIDEO_VP8_HIERARCHY_QP_ENABLE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "VP8 hierarchy QP enable",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC70_VIDEO_VP8_HIERARCHY_QP_LAYER0,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "VP8 layer0 QP value",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC70_VIDEO_VP8_HIERARCHY_QP_LAYER1,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "VP8 layer1 QP value",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC70_VIDEO_VP8_HIERARCHY_QP_LAYER2,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "VP8 layer2 QP value",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC70_VIDEO_VP8_REF_NUMBER_FOR_PFRAMES,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "VP8 Number of reference picture",
- .minimum = 1,
- .maximum = 2,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_MFC70_VIDEO_VP8_DISABLE_INTRA_MD4X4,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "VP8 intra 4x4 mode disable",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC70_VIDEO_VP8_NUM_TEMPORAL_LAYER,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "VP8 number of hierarchical layer",
- .minimum = 0,
- .maximum = 3,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_VP9_VERSION,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "VP9 version",
- .minimum = 0,
- .maximum = 3,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_VP9_I_FRAME_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "VP9 Frame QP value",
- .minimum = 1,
- .maximum = 255,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_VP9_P_FRAME_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "VP9 Frame QP value",
- .minimum = 1,
- .maximum = 255,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_VP9_RC_FRAME_RATE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "VP9 Frame rate",
- .minimum = 1,
- .maximum = (1 << 16) - 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_VP9_GOLDEN_FRAMESEL,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "VP9 indication of golden frame",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_VP9_GF_REFRESH_PERIOD,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "VP9 indication of golden frame",
- .minimum = 0,
- .maximum = ((1 << 16) - 1),
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_VP9_HIERARCHY_QP_ENABLE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "VP9 hierarchy QP enable",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "VP9 layer0 QP value",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_VP9_REF_NUMBER_FOR_PFRAMES,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "VP9 Number of reference picture",
- .minimum = 1,
- .maximum = 2,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "VP9 number of hierarchical layer",
- .minimum = 0,
- .maximum = 3,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_VP9_MAX_PARTITION_DEPTH,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "VP9 Maximum coding unit depth",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_VP9_DISABLE_INTRA_PU_SPLIT,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "VP9 disable intra pu split",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER_BIT0,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hierarchical Coding Layer Bit0",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER_BIT1,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hierarchical Coding Layer Bit1",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER_BIT2,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hierarchical Coding Layer Bit2",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER_CH,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hierarchical Coding Layer Change",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_DISABLE_IVF_HEADER,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "IVF header generation",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "HEVC Frame QP value",
- .minimum = -12,
- .maximum = 51,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "HEVC P frame QP value",
- .minimum = -12,
- .maximum = 51,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "HEVC B frame QP value",
- .minimum = -12,
- .maximum = 51,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_ADAPTIVE_RC_DARK,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "HEVC dark region adaptive",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_ADAPTIVE_RC_SMOOTH,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "HEVC smooth region adaptive",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_ADAPTIVE_RC_STATIC,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "HEVC static region adaptive",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_ADAPTIVE_RC_ACTIVITY,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "HEVC activity adaptive",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "HEVC Profile",
- .minimum = 0,
- .maximum = 4,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "HEVC level",
- .minimum = 10,
- .maximum = 62,
- .step = 1,
- .default_value = 10,
- },
- {
- .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_TIER_FLAG,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "HEVC tier_flag default is Main",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_RC_FRAME_RATE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "HEVC Frame rate",
- .minimum = 1,
- .maximum = (1 << 16) - 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_MAX_PARTITION_DEPTH,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "HEVC Maximum coding unit depth",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0, /* need to check defualt value */
- },
- {
- .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_REF_NUMBER_FOR_PFRAMES,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "HEVC Number of reference picture",
- .minimum = 1,
- .maximum = 2,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_REFRESH_TYPE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "HEVC Number of reference picture",
- .minimum = 0,
- .maximum = 2,
- .step = 1,
- .default_value = 0, /* need to check defualt value */
- },
- {
- .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_CONST_INTRA_PRED_ENABLE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "HEVC refresh type",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0, /* need to check defualt value */
- },
- {
- .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_LOSSLESS_CU_ENABLE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "HEVC lossless encoding select",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0, /* need to check defualt value */
- },
- {
- .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_WAVEFRONT_ENABLE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "HEVC Wavefront enable",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0, /* need to check defualt value */
- },
- {
- .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_LF_DISABLE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "HEVC Filter disable",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0, /* need to check defualt value */
- },
- {
- .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_LF_SLICE_BOUNDARY,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "across or not slice boundary",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0, /* need to check defualt value */
- },
- {
- .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_LTR_ENABLE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "long term reference enable",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0, /* need to check defualt value */
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_QP_ENABLE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "QP values for temporal layer",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0, /* need to check defualt value */
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_TYPE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Hierarchical Coding Type",
- .minimum = V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B,
- .maximum = V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P,
- .step = 1,
- .default_value = 0, /* need to check defualt value */
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hierarchical Coding Layer",
- .minimum = 0,
- .maximum = 7,
- .step = 1,
- .default_value = 0, /* need to check defualt value */
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hierarchical Coding Layer QP",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0, /* need to check defualt value */
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_BIT0,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hierarchical Coding Layer BIT0",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_BIT1,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hierarchical Coding Layer BIT1",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_BIT2,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hierarchical Coding Layer BIT2",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_BIT3,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hierarchical Coding Layer BIT3",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_BIT4,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hierarchical Coding Layer BIT4",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_BIT5,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hierarchical Coding Layer BIT5",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_BIT6,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hierarchical Coding Layer BIT6",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_CH,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hierarchical Coding Layer Change",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_SIGN_DATA_HIDING,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "HEVC Sign data hiding",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0, /* need to check defualt value */
- },
- {
- .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_GENERAL_PB_ENABLE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "HEVC General pb enable",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0, /* need to check defualt value */
- },
- {
- .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_TEMPORAL_ID_ENABLE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "HEVC Temporal id enable",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0, /* need to check defualt value */
- },
- {
- .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_STRONG_SMOTHING_FLAG,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "HEVC Strong intra smoothing flag",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0, /* need to check defualt value */
- },
- {
- .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_DISABLE_INTRA_PU_SPLIT,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "HEVC disable intra pu split",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0, /* need to check defualt value */
- },
- {
- .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_DISABLE_TMV_PREDICTION,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "HEVC disable tmv prediction",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0, /* need to check defualt value */
- },
- {
- .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "max number of candidate MVs",
- .minimum = 0,
- .maximum = 4,
- .step = 1,
- .default_value = 0, /* need to check defualt value */
- },
- {
- .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_WITHOUT_STARTCODE_ENABLE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "ENC without startcode enable",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0, /* need to check defualt value */
- },
- {
- .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_REFRESH_PERIOD,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "HEVC Number of reference picture",
- .minimum = 0,
- .maximum = (1 << 16) - 1,
- .step = 1,
- .default_value = 0, /* need to check defualt value */
- },
- {
- .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_LF_BETA_OFFSET_DIV2,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "HEVC loop filter beta offset",
- .minimum = -6,
- .maximum = 6,
- .step = 1,
- .default_value = 0, /* need to check defualt value */
- },
- {
- .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_LF_TC_OFFSET_DIV2,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "HEVC loop filter tc offset",
- .minimum = -6,
- .maximum = 6,
- .step = 1,
- .default_value = 0, /* need to check defualt value */
- },
- {
- .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "HEVC size of length field",
- .minimum = 0,
- .maximum = 3,
- .step = 1,
- .default_value = 0, /* need to check defualt value */
- },
- {
- .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_USER_REF,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "user long term reference frame",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0, /* need to check defualt value */
- },
- {
- .id = V4L2_CID_MPEG_MFC90_VIDEO_HEVC_STORE_REF,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "store long term reference frame",
- .minimum = 0,
- .maximum = 2,
- .step = 1,
- .default_value = 0, /* need to check defualt value */
- },
- {
- .id = V4L2_CID_MPEG_MFC_GET_VERSION_INFO,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Get MFC version information",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC_GET_EXTRA_BUFFER_SIZE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Get extra buffer size",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC_GET_EXT_INFO,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Get extra information",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_BIT0,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hierarchical Coding Layer Bit0",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_BIT1,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hierarchical Coding Layer Bit1",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_BIT2,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hierarchical Coding Layer Bit2",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_BIT3,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hierarchical Coding Layer Bit3",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_BIT4,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hierarchical Coding Layer Bit4",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_BIT5,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hierarchical Coding Layer Bit5",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_BIT6,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hierarchical Coding Layer Bit6",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_CH,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hierarchical Coding Layer Change",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_VP8_HIERARCHICAL_CODING_LAYER_BIT0,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hierarchical Coding Layer Bit0",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_VP8_HIERARCHICAL_CODING_LAYER_BIT1,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hierarchical Coding Layer Bit1",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_VP8_HIERARCHICAL_CODING_LAYER_BIT2,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hierarchical Coding Layer Bit2",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_VP8_HIERARCHICAL_CODING_LAYER_CH,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hierarchical Coding Layer Change",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC_H264_ENABLE_LTR,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Enable LTR",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC_H264_NUM_OF_LTR,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Number of LTR",
- .minimum = 0,
- .maximum = 4,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC_H264_MARK_LTR,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Set the frame as a LTRP",
- .minimum = 0,
- .maximum = 4,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC_H264_USE_LTR,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Specify a LTRP for encoding",
- .minimum = 0,
- .maximum = 0xF,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC_H264_BASE_PRIORITY,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hierarchical Base Layer Priority",
- .minimum = 0,
- .maximum = (1 << 6) - 1 - 6,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC_CONFIG_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "QP control per each frame",
- .minimum = -12,
- .maximum = 255,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC_H264_VUI_RESTRICTION_ENABLE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "H264 vui generation enable",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_HEVC_PREPEND_SPSPPS_TO_IDR,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Prepend SPS/PPS to every IDR",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_MFC_CONFIG_QP_ENABLE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "set dynamic qp controls",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_ROI_CONTROL,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Region-Of-Interest control",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_ROI_ENABLE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Region-Of-Interest enable",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_MIN_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "H264 Min QP value for I frame",
- .minimum = 0,
- .maximum = 51,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "H264 Max QP value for I frame",
- .minimum = 0,
- .maximum = 51,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "HEVC Min QP value for I frame",
- .minimum = -12,
- .maximum = 51,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "HEVC Max QP value for I frame",
- .minimum = 0,
- .maximum = 51,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "MPEG4 Min QP value for I frame",
- .minimum = 1,
- .maximum = 31,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "MPEG4 Max QP value for I frame",
- .minimum = 1,
- .maximum = 31,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H263_MIN_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "H263 Min QP value for I frame",
- .minimum = 1,
- .maximum = 31,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H263_MAX_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "H263 Max QP value for I frame",
- .minimum = 1,
- .maximum = 31,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_VP8_MIN_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "VP8 Min QP value for I frame",
- .minimum = 0,
- .maximum = 127,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_VP8_MAX_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "VP8 Max QP value for I frame",
- .minimum = 0,
- .maximum = 127,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_VP9_MIN_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "VP9 Min QP value for I frame",
- .minimum = 1,
- .maximum = 255,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_VP9_MAX_QP,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "VP9 Max QP value for I frame",
- .minimum = 1,
- .maximum = 255,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_MIN_QP_P,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "H264 Min QP value for P frame",
- .minimum = 0,
- .maximum = 51,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP_P,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "H264 Max QP value for P frame",
- .minimum = 0,
- .maximum = 51,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP_P,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "HEVC Min QP value for P frame",
- .minimum = -12,
- .maximum = 51,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP_P,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "HEVC Max QP value for P frame",
- .minimum = 0,
- .maximum = 51,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP_P,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "MPEG4 Min QP value for P frame",
- .minimum = 1,
- .maximum = 31,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP_P,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "MPEG4 Max QP value for P frame",
- .minimum = 1,
- .maximum = 31,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H263_MIN_QP_P,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "H263 Min QP value for P frame",
- .minimum = 1,
- .maximum = 31,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H263_MAX_QP_P,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "H263 Max QP value for P frame",
- .minimum = 1,
- .maximum = 31,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_VP8_MIN_QP_P,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "VP8 Min QP value for P frame",
- .minimum = 0,
- .maximum = 127,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_VP8_MAX_QP_P,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "VP8 Max QP value for P frame",
- .minimum = 0,
- .maximum = 127,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_VP9_MIN_QP_P,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "VP9 Min QP value for P frame",
- .minimum = 1,
- .maximum = 255,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_VP9_MAX_QP_P,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "VP9 Max QP value for P frame",
- .minimum = 1,
- .maximum = 255,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_MIN_QP_B,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "H264 Min QP value for B frame",
- .minimum = 0,
- .maximum = 51,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP_B,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "H264 Max QP value for B frame",
- .minimum = 0,
- .maximum = 51,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP_B,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "HEVC Min QP value for B frame",
- .minimum = -12,
- .maximum = 51,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP_B,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "HEVC Max QP value for B frame",
- .minimum = 0,
- .maximum = 51,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP_B,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "MPEG4 Min QP value for B frame",
- .minimum = 1,
- .maximum = 31,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP_B,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "MPEG4 Max QP value for B frame",
- .minimum = 1,
- .maximum = 31,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_RC_PVC_ENABLE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Perceptual Video Coding enable",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_TEMPORAL_SHORTTERM_MAX_LAYER,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hierarchical Coding max layer",
- .minimum = 0,
- .maximum = 3,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_WEIGHTED_ENABLE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Weighted Prediction enable",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_YSUM,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "YSUM for weighted Prediction",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_BPG_THUMBNAIL_SIZE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "BPG thumbnail size",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_BPG_EXIF_SIZE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "BPG EXIF data size",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_BPG_HEADER_SIZE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "BPG header size",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_RATIO_OF_INTRA,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "ratio of intra encoded size",
- .minimum = 15,
- .maximum = 50,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_FULL_RANGE_FLAG,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Color range",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_COLOUR_PRIMARIES,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Colour primaries",
- .minimum = 0,
- .maximum = 10,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_TRANSFER_CHARACTERISTICS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Transfer characteristics",
- .minimum = 0,
- .maximum = 17,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_MATRIX_COEFFICIENTS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Matrix coefficients",
- .minimum = 0,
- .maximum = 10,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_HIERARCHICAL_BITRATE_CTRL,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Hierarchical bitrate control",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_STATIC_INFO_ENABLE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Static info enable",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_SEI_MAX_PIC_AVERAGE_LIGHT,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Max pic average light",
- .minimum = 0,
- .maximum = 0xFFFF,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_SEI_MAX_CONTENT_LIGHT,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Max content light",
- .minimum = 0,
- .maximum = 0xFFFF,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_SEI_MAX_DISPLAY_LUMINANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Max display luminance",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_SEI_MIN_DISPLAY_LUMINANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Min display luminance",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_SEI_WHITE_POINT,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "White point",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_SEI_DISPLAY_PRIMARIES_0,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Display primaries 0",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_SEI_DISPLAY_PRIMARIES_1,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Display primaries 1",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_MPEG_VIDEO_SEI_DISPLAY_PRIMARIES_2,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Display primaries 2",
- .minimum = INT_MIN,
- .maximum = INT_MAX,
- .step = 1,
- .default_value = 0,
- },
-};
-
-#define NUM_CTRLS ARRAY_SIZE(controls)
-
-#endif /* __S5P_MFC_ENC_INTERNAL_H */
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_enc_ops.c
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include "s5p_mfc_common.h"
-
-#include "s5p_mfc_reg.h"
-
-static int mfc_enc_ctrl_read_cst(struct s5p_mfc_ctx *ctx,
- struct s5p_mfc_buf_ctrl *buf_ctrl)
-{
- int ret;
- struct s5p_mfc_enc *enc = ctx->enc_priv;
-
- switch (buf_ctrl->id) {
- case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_STATUS:
- ret = !enc->in_slice;
- break;
- default:
- mfc_err_ctx("not support custom per-buffer control\n");
- ret = -EINVAL;
- break;
- }
-
- return ret;
-}
-
-static struct s5p_mfc_ctrl_cfg mfc_ctrl_list[] = {
- { /* set frame tag */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_PICTURE_TAG,
- .mask = 0xFFFFFFFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_NONE,
- .flag_addr = 0,
- .flag_shft = 0,
- },
- { /* get frame tag */
- .type = MFC_CTRL_TYPE_GET_DST,
- .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG,
- .is_volatile = 0,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_RET_PICTURE_TAG,
- .mask = 0xFFFFFFFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_NONE,
- .flag_addr = 0,
- .flag_shft = 0,
- },
- { /* encoded y physical addr */
- .type = MFC_CTRL_TYPE_GET_DST,
- .id = V4L2_CID_MPEG_MFC51_VIDEO_LUMA_ADDR,
- .is_volatile = 0,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_ENCODED_SOURCE_FIRST_ADDR,
- .mask = 0xFFFFFFFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_NONE,
- .flag_addr = 0,
- .flag_shft = 0,
- },
- { /* encoded c physical addr */
- .type = MFC_CTRL_TYPE_GET_DST,
- .id = V4L2_CID_MPEG_MFC51_VIDEO_CHROMA_ADDR,
- .is_volatile = 0,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_ENCODED_SOURCE_SECOND_ADDR,
- .mask = 0xFFFFFFFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_NONE,
- .flag_addr = 0,
- .flag_shft = 0,
- },
- { /* I, not coded frame insertion */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_FRAME_INSERTION,
- .mask = 0x3,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_NONE,
- .flag_addr = 0,
- .flag_shft = 0,
- },
- { /* I period change */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_MFC51_VIDEO_I_PERIOD_CH,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_GOP_CONFIG,
- .mask = 0xFFFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 0,
- },
- { /* frame rate change */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_RATE_CH,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_RC_FRAME_RATE,
- .mask = 0xFFFFFFFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 1,
- },
- { /* bit rate change */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_MFC51_VIDEO_BIT_RATE_CH,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_RC_BIT_RATE,
- .mask = 0xFFFFFFFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 2,
- },
- { /* frame status (in slice or not) */
- .type = MFC_CTRL_TYPE_GET_DST,
- .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_STATUS,
- .is_volatile = 0,
- .mode = MFC_CTRL_MODE_CST,
- .addr = 0,
- .mask = 0xFFFFFFFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_NONE,
- .flag_addr = 0,
- .flag_shft = 0,
- .read_cst = mfc_enc_ctrl_read_cst,
- .write_cst = NULL,
- },
- { /* H.264 I frame QP Max change */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_RC_QP_BOUND,
- .mask = 0xFF,
- .shft = 8,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 4,
- },
- { /* H.264 I frame QP Min change */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_H264_MIN_QP,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_RC_QP_BOUND,
- .mask = 0xFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 4,
- },
- { /* H.263 I frame QP Max change */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_H263_MAX_QP,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_RC_QP_BOUND,
- .mask = 0xFF,
- .shft = 8,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 4,
- },
- { /* H.263 I frame QP Min change */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_H263_MIN_QP,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_RC_QP_BOUND,
- .mask = 0xFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 4,
- },
- { /* MPEG4 I frame QP Max change */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_RC_QP_BOUND,
- .mask = 0xFF,
- .shft = 8,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 4,
- },
- { /* MPEG4 I frame QP Min change */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_RC_QP_BOUND,
- .mask = 0xFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 4,
- },
- { /* VP8 I frame QP Max change */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_VP8_MAX_QP,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_RC_QP_BOUND,
- .mask = 0xFF,
- .shft = 8,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 4,
- },
- { /* VP8 I frame QP Min change */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_VP8_MIN_QP,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_RC_QP_BOUND,
- .mask = 0xFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 4,
- },
- { /* VP9 I frame QP Max change */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_VP9_MAX_QP,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_RC_QP_BOUND,
- .mask = 0xFF,
- .shft = 8,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 4,
- },
- { /* VP9 I frame QP Min change */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_VP9_MIN_QP,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_RC_QP_BOUND,
- .mask = 0xFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 4,
- },
- { /* HEVC I frame QP Max change */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_RC_QP_BOUND,
- .mask = 0xFF,
- .shft = 8,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 4,
- },
- { /* HEVC I frame QP Min change */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_RC_QP_BOUND,
- .mask = 0xFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 4,
- },
- { /* H.264 P frame QP Max change */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP_P,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_RC_QP_BOUND_PB,
- .mask = 0xFF,
- .shft = 8,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 4,
- },
- { /* H.264 P frame QP Min change */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_H264_MIN_QP_P,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_RC_QP_BOUND_PB,
- .mask = 0xFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 4,
- },
- { /* H.263 P frame QP Max change */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_H263_MAX_QP_P,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_RC_QP_BOUND_PB,
- .mask = 0xFF,
- .shft = 8,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 4,
- },
- { /* H.263 P frame QP Min change */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_H263_MIN_QP_P,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_RC_QP_BOUND_PB,
- .mask = 0xFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 4,
- },
- { /* MPEG4 P frame QP Max change */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP_P,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_RC_QP_BOUND_PB,
- .mask = 0xFF,
- .shft = 8,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 4,
- },
- { /* MPEG4 P frame QP Min change */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP_P,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_RC_QP_BOUND_PB,
- .mask = 0xFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 4,
- },
- { /* VP8 P frame QP Max change */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_VP8_MAX_QP_P,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_RC_QP_BOUND_PB,
- .mask = 0xFF,
- .shft = 8,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 4,
- },
- { /* VP8 P frame QP Min change */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_VP8_MIN_QP_P,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_RC_QP_BOUND_PB,
- .mask = 0xFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 4,
- },
- { /* VP9 P frame QP Max change */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_VP9_MAX_QP_P,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_RC_QP_BOUND_PB,
- .mask = 0xFF,
- .shft = 8,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 4,
- },
- { /* VP9 P frame QP Min change */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_VP9_MIN_QP_P,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_RC_QP_BOUND_PB,
- .mask = 0xFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 4,
- },
- { /* HEVC P frame QP Max change */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP_P,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_RC_QP_BOUND_PB,
- .mask = 0xFF,
- .shft = 8,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 4,
- },
- { /* HEVC P frame QP Min change */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP_P,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_RC_QP_BOUND_PB,
- .mask = 0xFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 4,
- },
- { /* H.264 B frame QP Max change */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP_B,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_RC_QP_BOUND_PB,
- .mask = 0xFF,
- .shft = 24,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 4,
- },
- { /* H.264 B frame QP Min change */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_H264_MIN_QP_B,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_RC_QP_BOUND_PB,
- .mask = 0xFF,
- .shft = 16,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 4,
- },
- { /* MPEG4 B frame QP Max change */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP_B,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_RC_QP_BOUND_PB,
- .mask = 0xFF,
- .shft = 24,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 4,
- },
- { /* MPEG4 B frame QP Min change */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP_B,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_RC_QP_BOUND_PB,
- .mask = 0xFF,
- .shft = 16,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 4,
- },
- { /* HEVC B frame QP Max change */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP_B,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_RC_QP_BOUND_PB,
- .mask = 0xFF,
- .shft = 24,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 4,
- },
- { /* HEVC B frame QP Min change */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP_B,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_RC_QP_BOUND_PB,
- .mask = 0xFF,
- .shft = 16,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 4,
- },
- { /* H.264 Dynamic Temporal Layer & bitrate change */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_CH,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER0,
- .mask = 0xFFFFFFFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 10,
- },
- { /* HEVC Dynamic Temporal Layer & bitrate change */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_CH,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER0,
- .mask = 0xFFFFFFFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 10,
- },
- { /* VP8 Dynamic Temporal Layer change */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_VP8_HIERARCHICAL_CODING_LAYER_CH,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER0,
- .mask = 0xFFFFFFFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 10,
- },
- { /* VP9 Dynamic Temporal Layer change */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER_CH,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER0,
- .mask = 0xFFFFFFFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 10,
- },
- { /* set level */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_H264_LEVEL,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_PICTURE_PROFILE,
- .mask = 0x000000FF,
- .shft = 8,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 5,
- },
- { /* set profile */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_H264_PROFILE,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_PICTURE_PROFILE,
- .mask = 0x0000000F,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 5,
- },
- { /* set store LTR */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_MFC_H264_MARK_LTR,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_H264_NAL_CONTROL,
- .mask = 0x00000003,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_NONE,
- .flag_addr = 0,
- .flag_shft = 0,
- },
- { /* set use LTR */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_MFC_H264_USE_LTR,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_H264_NAL_CONTROL,
- .mask = 0x00000003,
- .shft = 2,
- .flag_mode = MFC_CTRL_MODE_NONE,
- .flag_addr = 0,
- .flag_shft = 0,
- },
- { /* set base layer priority */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_MFC_H264_BASE_PRIORITY,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_H264_HD_SVC_EXTENSION_0,
- .mask = 0x0000003F,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 12,
- },
- { /* set QP per each frame */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_MFC_CONFIG_QP,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_FIXED_PICTURE_QP,
- .mask = 0x000000FF,
- .shft = 24,
- .flag_mode = MFC_CTRL_MODE_NONE,
- .flag_addr = 0,
- .flag_shft = 0,
- },
- { /* Region-Of-Interest control */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_ROI_CONTROL,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_RC_ROI_CTRL,
- .mask = 0xFFFFFFFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_NONE,
- .flag_addr = 0,
- .flag_shft = 0,
- },
- { /* set YSUM for weighted prediction */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_YSUM,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_WEIGHT_FOR_WEIGHTED_PREDICTION,
- .mask = 0xFFFFFFFF,
- .shft = 0,
- .flag_mode = MFC_CTRL_MODE_NONE,
- .flag_mode = 0,
- .flag_shft = 0,
- },
- { /* set base layer priority */
- .type = MFC_CTRL_TYPE_SET,
- .id = V4L2_CID_MPEG_VIDEO_RATIO_OF_INTRA,
- .is_volatile = 1,
- .mode = MFC_CTRL_MODE_SFR,
- .addr = S5P_FIMV_E_RC_MODE,
- .mask = 0x000000FF,
- .shft = 8,
- .flag_mode = MFC_CTRL_MODE_SFR,
- .flag_addr = S5P_FIMV_E_PARAM_CHANGE,
- .flag_shft = 13,
- }
-};
-
-#define NUM_CTRL_CFGS ARRAY_SIZE(mfc_ctrl_list)
-
-static int s5p_mfc_enc_cleanup_ctx_ctrls(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_ctx_ctrl *ctx_ctrl;
-
- while (!list_empty(&ctx->ctrls)) {
- ctx_ctrl = list_entry((&ctx->ctrls)->next,
- struct s5p_mfc_ctx_ctrl, list);
- list_del(&ctx_ctrl->list);
- kfree(ctx_ctrl);
- }
-
- INIT_LIST_HEAD(&ctx->ctrls);
-
- return 0;
-}
-
-static int s5p_mfc_enc_get_buf_update_val(struct s5p_mfc_ctx *ctx,
- struct list_head *head, unsigned int id, int value)
-{
- struct s5p_mfc_buf_ctrl *buf_ctrl;
-
- list_for_each_entry(buf_ctrl, head, list) {
- if (buf_ctrl->id == id) {
- buf_ctrl->val = value;
- mfc_debug(6, "[CTRLS] Update buffer control id: 0x%08x, val: %d\n",
- buf_ctrl->id, buf_ctrl->val);
- break;
- }
- }
-
- return 0;
-}
-
-static int s5p_mfc_enc_init_ctx_ctrls(struct s5p_mfc_ctx *ctx)
-{
- unsigned long i;
- struct s5p_mfc_ctx_ctrl *ctx_ctrl;
-
- INIT_LIST_HEAD(&ctx->ctrls);
-
- for (i = 0; i < NUM_CTRL_CFGS; i++) {
- ctx_ctrl = kzalloc(sizeof(struct s5p_mfc_ctx_ctrl), GFP_KERNEL);
- if (ctx_ctrl == NULL) {
- mfc_err_dev("Failed to allocate context control "\
- "id: 0x%08x, type: %d\n",
- mfc_ctrl_list[i].id,
- mfc_ctrl_list[i].type);
-
- s5p_mfc_enc_cleanup_ctx_ctrls(ctx);
-
- return -ENOMEM;
- }
-
- ctx_ctrl->type = mfc_ctrl_list[i].type;
- ctx_ctrl->id = mfc_ctrl_list[i].id;
- ctx_ctrl->has_new = 0;
- ctx_ctrl->val = 0;
-
- list_add_tail(&ctx_ctrl->list, &ctx->ctrls);
- }
-
- return 0;
-}
-
-static void s5p_mfc_enc_reset_buf_ctrls(struct list_head *head)
-{
- struct s5p_mfc_buf_ctrl *buf_ctrl;
-
- list_for_each_entry(buf_ctrl, head, list) {
- buf_ctrl->has_new = 0;
- buf_ctrl->val = 0;
- buf_ctrl->old_val = 0;
- buf_ctrl->updated = 0;
- }
-}
-
-static void mfc_enc_remove_buf_ctrls(struct list_head *head)
-{
- struct s5p_mfc_buf_ctrl *buf_ctrl;
-
- while (!list_empty(head)) {
- buf_ctrl = list_entry(head->next,
- struct s5p_mfc_buf_ctrl, list);
- list_del(&buf_ctrl->list);
- kfree(buf_ctrl);
- }
-
- INIT_LIST_HEAD(head);
-}
-
-static int s5p_mfc_enc_init_buf_ctrls(struct s5p_mfc_ctx *ctx,
- enum s5p_mfc_ctrl_type type, unsigned int index)
-{
- unsigned long i;
- struct s5p_mfc_buf_ctrl *buf_ctrl;
- struct list_head *head;
-
- if (index >= MFC_MAX_BUFFERS) {
- mfc_err_dev("Per-buffer control index is out of range\n");
- return -EINVAL;
- }
-
- if (type & MFC_CTRL_TYPE_SRC) {
- if (test_bit(index, &ctx->src_ctrls_avail)) {
- s5p_mfc_enc_reset_buf_ctrls(&ctx->src_ctrls[index]);
-
- return 0;
- }
-
- head = &ctx->src_ctrls[index];
- } else if (type & MFC_CTRL_TYPE_DST) {
- if (test_bit(index, &ctx->dst_ctrls_avail)) {
- s5p_mfc_enc_reset_buf_ctrls(&ctx->dst_ctrls[index]);
-
- return 0;
- }
-
- head = &ctx->dst_ctrls[index];
- } else {
- mfc_err_dev("Control type mismatch. type : %d\n", type);
- return -EINVAL;
- }
-
- INIT_LIST_HEAD(head);
-
- for (i = 0; i < NUM_CTRL_CFGS; i++) {
- if (!(type & mfc_ctrl_list[i].type))
- continue;
-
- buf_ctrl = kzalloc(sizeof(struct s5p_mfc_buf_ctrl), GFP_KERNEL);
- if (buf_ctrl == NULL) {
- mfc_err_dev("Failed to allocate buffer control "\
- "id: 0x%08x, type: %d\n",
- mfc_ctrl_list[i].id,
- mfc_ctrl_list[i].type);
-
- mfc_enc_remove_buf_ctrls(head);
-
- return -ENOMEM;
- }
-
- buf_ctrl->type = mfc_ctrl_list[i].type;
- buf_ctrl->id = mfc_ctrl_list[i].id;
- buf_ctrl->is_volatile = mfc_ctrl_list[i].is_volatile;
- buf_ctrl->mode = mfc_ctrl_list[i].mode;
- buf_ctrl->addr = mfc_ctrl_list[i].addr;
- buf_ctrl->mask = mfc_ctrl_list[i].mask;
- buf_ctrl->shft = mfc_ctrl_list[i].shft;
- buf_ctrl->flag_mode = mfc_ctrl_list[i].flag_mode;
- buf_ctrl->flag_addr = mfc_ctrl_list[i].flag_addr;
- buf_ctrl->flag_shft = mfc_ctrl_list[i].flag_shft;
- if (buf_ctrl->mode == MFC_CTRL_MODE_CST) {
- buf_ctrl->read_cst = mfc_ctrl_list[i].read_cst;
- buf_ctrl->write_cst = mfc_ctrl_list[i].write_cst;
- }
-
- list_add_tail(&buf_ctrl->list, head);
- }
-
- s5p_mfc_enc_reset_buf_ctrls(head);
-
- if (type & MFC_CTRL_TYPE_SRC)
- set_bit(index, &ctx->src_ctrls_avail);
- else
- set_bit(index, &ctx->dst_ctrls_avail);
-
- return 0;
-}
-
-static int s5p_mfc_enc_cleanup_buf_ctrls(struct s5p_mfc_ctx *ctx,
- enum s5p_mfc_ctrl_type type, unsigned int index)
-{
- struct list_head *head;
-
- if (index >= MFC_MAX_BUFFERS) {
- mfc_err_dev("Per-buffer control index is out of range\n");
- return -EINVAL;
- }
-
- if (type & MFC_CTRL_TYPE_SRC) {
- if (!(test_and_clear_bit(index, &ctx->src_ctrls_avail))) {
- return 0;
- }
-
- head = &ctx->src_ctrls[index];
- } else if (type & MFC_CTRL_TYPE_DST) {
- if (!(test_and_clear_bit(index, &ctx->dst_ctrls_avail))) {
- return 0;
- }
-
- head = &ctx->dst_ctrls[index];
- } else {
- mfc_err_dev("Control type mismatch. type : %d\n", type);
- return -EINVAL;
- }
-
- mfc_enc_remove_buf_ctrls(head);
-
- return 0;
-}
-
-static int s5p_mfc_enc_to_buf_ctrls(struct s5p_mfc_ctx *ctx, struct list_head *head)
-{
- struct s5p_mfc_ctx_ctrl *ctx_ctrl;
- struct s5p_mfc_buf_ctrl *buf_ctrl;
- struct s5p_mfc_enc *enc = ctx->enc_priv;
- int index = 0;
- unsigned int reg = 0;
-
- list_for_each_entry(ctx_ctrl, &ctx->ctrls, list) {
- if (!(ctx_ctrl->type & MFC_CTRL_TYPE_SET) || !ctx_ctrl->has_new)
- continue;
-
- list_for_each_entry(buf_ctrl, head, list) {
- if (!(buf_ctrl->type & MFC_CTRL_TYPE_SET))
- continue;
-
- if (buf_ctrl->id == ctx_ctrl->id) {
- buf_ctrl->has_new = 1;
- buf_ctrl->val = ctx_ctrl->val;
- if (buf_ctrl->is_volatile)
- buf_ctrl->updated = 0;
-
- ctx_ctrl->has_new = 0;
- if (buf_ctrl->id == V4L2_CID_MPEG_VIDEO_ROI_CONTROL) {
- index = enc->roi_index;
- if (enc->roi_info[index].enable) {
- enc->roi_index =
- (index + 1) % MFC_MAX_EXTRA_BUF;
- reg |= enc->roi_info[index].enable;
- reg &= ~(0xFF << 8);
- reg |= (enc->roi_info[index].lower_qp << 8);
- reg &= ~(0xFFFF << 16);
- reg |= (enc->roi_info[index].upper_qp << 16);
- mfc_debug(3, "[ROI] buffer[%d] en %d, "\
- "QP lower %d upper %d reg %#x\n",
- index, enc->roi_info[index].enable,
- enc->roi_info[index].lower_qp,
- enc->roi_info[index].upper_qp,
- reg);
- } else {
- mfc_debug(3, "[ROI] buffer[%d] is not enabled\n", index);
- }
- buf_ctrl->val = reg;
- buf_ctrl->old_val2 = index;
- }
- break;
- }
- }
- }
-
- return 0;
-}
-
-static int s5p_mfc_enc_to_ctx_ctrls(struct s5p_mfc_ctx *ctx, struct list_head *head)
-{
- struct s5p_mfc_ctx_ctrl *ctx_ctrl;
- struct s5p_mfc_buf_ctrl *buf_ctrl;
-
- list_for_each_entry(buf_ctrl, head, list) {
- if (!(buf_ctrl->type & MFC_CTRL_TYPE_GET) || !buf_ctrl->has_new)
- continue;
-
- list_for_each_entry(ctx_ctrl, &ctx->ctrls, list) {
- if (!(ctx_ctrl->type & MFC_CTRL_TYPE_GET))
- continue;
-
- if (ctx_ctrl->id == buf_ctrl->id) {
- if (ctx_ctrl->has_new)
- mfc_debug(8,
- "Overwrite context control "\
- "value id: 0x%08x, val: %d\n",
- ctx_ctrl->id, ctx_ctrl->val);
-
- ctx_ctrl->has_new = 1;
- ctx_ctrl->val = buf_ctrl->val;
-
- buf_ctrl->has_new = 0;
- }
- }
- }
-
- return 0;
-}
-
-static void mfc_enc_set_buf_ctrls_temporal_svc(struct s5p_mfc_ctx *ctx,
- struct s5p_mfc_buf_ctrl *buf_ctrl)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_enc *enc = ctx->enc_priv;
- unsigned int value = 0, value2 = 0;
- struct temporal_layer_info temporal_LC;
- unsigned int i;
- struct s5p_mfc_enc_params *p = &enc->params;
-
- if (buf_ctrl->id
- == V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_CH ||
- buf_ctrl->id
- == V4L2_CID_MPEG_VIDEO_VP8_HIERARCHICAL_CODING_LAYER_CH ||
- buf_ctrl->id
- == V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER_CH ||
- buf_ctrl->id
- == V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_CH) {
- memcpy(&temporal_LC,
- enc->sh_handle_svc.vaddr, sizeof(struct temporal_layer_info));
-
- if(((temporal_LC.temporal_layer_count & 0x7) < 1) ||
- ((temporal_LC.temporal_layer_count > 3) && IS_VP8_ENC(ctx)) ||
- ((temporal_LC.temporal_layer_count > 3) && IS_VP9_ENC(ctx))) {
- /* clear NUM_T_LAYER_CHANGE */
- value = MFC_READL(buf_ctrl->flag_addr);
- value &= ~(1 << 10);
- MFC_WRITEL(value, buf_ctrl->flag_addr);
- mfc_err_ctx("[HIERARCHICAL] layer count is invalid : %d\n",
- temporal_LC.temporal_layer_count);
- return;
- }
-
- if (IS_H264_ENC(ctx))
- p->codec.h264.num_hier_layer = temporal_LC.temporal_layer_count & 0x7;
-
- /* enable RC_BIT_RATE_CHANGE */
- value = MFC_READL(buf_ctrl->flag_addr);
- if (temporal_LC.temporal_layer_bitrate[0] > 0 || p->hier_bitrate_ctrl)
- /* set RC_BIT_RATE_CHANGE */
- value |= (1 << 2);
- else
- /* clear RC_BIT_RATE_CHANGE */
- value &= ~(1 << 2);
- MFC_WRITEL(value, buf_ctrl->flag_addr);
-
- mfc_debug(3, "[HIERARCHICAL] layer count %d, E_PARAM_CHANGE %#x\n",
- temporal_LC.temporal_layer_count & 0x7, value);
-
- value = MFC_READL(S5P_FIMV_E_NUM_T_LAYER);
- buf_ctrl->old_val2 = value;
- value &= ~(0x7);
- value |= (temporal_LC.temporal_layer_count & 0x7);
- value &= ~(0x1 << 8);
- value |= (p->hier_bitrate_ctrl & 0x1) << 8;
- MFC_WRITEL(value, S5P_FIMV_E_NUM_T_LAYER);
- mfc_debug(3, "[HIERARCHICAL] E_NUM_T_LAYER %#x\n", value);
- for (i = 0; i < (temporal_LC.temporal_layer_count & 0x7); i++) {
- mfc_debug(3, "[HIERARCHICAL] layer bitrate[%d] %d (FW ctrl: %d)\n",
- i, temporal_LC.temporal_layer_bitrate[i], p->hier_bitrate_ctrl);
- MFC_WRITEL(temporal_LC.temporal_layer_bitrate[i],
- buf_ctrl->addr + i * 4);
- }
- /* priority change */
- if (IS_H264_ENC(ctx)) {
- value = 0;
- value2 = 0;
- for (i = 0; i < (p->codec.h264.num_hier_layer & 0x07); i++) {
- if (i <= 4)
- value |= ((p->codec.h264.base_priority & 0x3F) + i)
- << (6 * i);
- else
- value2 |= ((p->codec.h264.base_priority & 0x3F) + i)
- << (6 * (i - 5));
- }
- MFC_WRITEL(value, S5P_FIMV_E_H264_HD_SVC_EXTENSION_0);
- MFC_WRITEL(value2, S5P_FIMV_E_H264_HD_SVC_EXTENSION_1);
- mfc_debug(3, "[HIERARCHICAL] EXTENSION0 %#x, EXTENSION1 %#x\n",
- value, value2);
-
- value = MFC_READL(buf_ctrl->flag_addr);
- value |= (1 << 12);
- MFC_WRITEL(value, buf_ctrl->flag_addr);
- mfc_debug(3, "[HIERARCHICAL] E_PARAM_CHANGE %#x\n", value);
- }
-
- }
-
- /* temproral layer priority */
- if (buf_ctrl->id == V4L2_CID_MPEG_MFC_H264_BASE_PRIORITY) {
- value = MFC_READL(S5P_FIMV_E_H264_HD_SVC_EXTENSION_0);
- buf_ctrl->old_val |= value & 0x3FFFFFC0;
- value &= ~(0x3FFFFFC0);
- value2 = MFC_READL(S5P_FIMV_E_H264_HD_SVC_EXTENSION_1);
- buf_ctrl->old_val2 = value2 & 0x0FFF;
- value2 &= ~(0x0FFF);
- for (i = 0; i < (p->codec.h264.num_hier_layer & 0x07); i++) {
- if (i <= 4)
- value |= ((buf_ctrl->val & 0x3F) + i) << (6 * i);
- else
- value2 |= ((buf_ctrl->val & 0x3F) + i) << (6 * (i - 5));
- }
- MFC_WRITEL(value, S5P_FIMV_E_H264_HD_SVC_EXTENSION_0);
- MFC_WRITEL(value2, S5P_FIMV_E_H264_HD_SVC_EXTENSION_1);
- p->codec.h264.base_priority = buf_ctrl->val;
- mfc_debug(3, "[HIERARCHICAL] EXTENSION0 %#x, EXTENSION1 %#x\n",
- value, value2);
- }
-}
-
-static void mfc_enc_set_buf_ctrls_exception(struct s5p_mfc_ctx *ctx,
- struct s5p_mfc_buf_ctrl *buf_ctrl)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_enc *enc = ctx->enc_priv;
- struct s5p_mfc_enc_params *p = &enc->params;
- unsigned int value = 0;
-
- if (buf_ctrl->id == V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG)
- enc->stored_tag = buf_ctrl->val;
-
- /* temporal layer setting */
- mfc_enc_set_buf_ctrls_temporal_svc(ctx, buf_ctrl);
-
- if (buf_ctrl->id == V4L2_CID_MPEG_MFC_H264_MARK_LTR) {
- value = MFC_READL(S5P_FIMV_E_H264_NAL_CONTROL);
- buf_ctrl->old_val2 = (value >> 8) & 0x7;
- value &= ~(0x7 << 8);
- value |= (buf_ctrl->val & 0x7) << 8;
- MFC_WRITEL(value, S5P_FIMV_E_H264_NAL_CONTROL);
- }
- if (buf_ctrl->id == V4L2_CID_MPEG_MFC_H264_USE_LTR) {
- value = MFC_READL(S5P_FIMV_E_H264_NAL_CONTROL);
- buf_ctrl->old_val2 = (value >> 11) & 0xF;
- value &= ~(0xF << 11);
- value |= (buf_ctrl->val & 0xF) << 11;
- MFC_WRITEL(value, S5P_FIMV_E_H264_NAL_CONTROL);
- }
-
- if (buf_ctrl->id == V4L2_CID_MPEG_MFC51_VIDEO_I_PERIOD_CH) {
- value = MFC_READL(S5P_FIMV_E_GOP_CONFIG2);
- buf_ctrl->old_val |= (value << 16) & 0x3FFF0000;
- value &= ~(0x3FFF);
- value |= (buf_ctrl->val >> 16) & 0x3FFF;
- MFC_WRITEL(value, S5P_FIMV_E_GOP_CONFIG2);
- }
-
- /* PROFILE & LEVEL have to be set up together */
- if (buf_ctrl->id == V4L2_CID_MPEG_VIDEO_H264_LEVEL) {
- value = MFC_READL(S5P_FIMV_E_PICTURE_PROFILE);
- buf_ctrl->old_val |= (value & 0x000F) << 8;
- value &= ~(0x000F);
- value |= p->codec.h264.profile & 0x000F;
- MFC_WRITEL(value, S5P_FIMV_E_PICTURE_PROFILE);
- p->codec.h264.level = buf_ctrl->val;
- }
-
- if (buf_ctrl->id == V4L2_CID_MPEG_VIDEO_H264_PROFILE) {
- value = MFC_READL(S5P_FIMV_E_PICTURE_PROFILE);
- buf_ctrl->old_val |= value & 0xFF00;
- value &= ~(0x00FF << 8);
- value |= (p->codec.h264.level << 8) & 0xFF00;
- MFC_WRITEL(value, S5P_FIMV_E_PICTURE_PROFILE);
- p->codec.h264.profile = buf_ctrl->val;
- }
-
- /* per buffer QP setting change */
- if (buf_ctrl->id == V4L2_CID_MPEG_MFC_CONFIG_QP)
- p->config_qp = buf_ctrl->val;
-
- /* set the ROI buffer DVA */
- if (buf_ctrl->id == V4L2_CID_MPEG_VIDEO_ROI_CONTROL) {
- MFC_WRITEL(enc->roi_buf[buf_ctrl->old_val2].daddr,
- S5P_FIMV_E_ROI_BUFFER_ADDR);
- mfc_debug(3, "[ROI] buffer[%d] addr %#llx, QP val: %#x\n",
- buf_ctrl->old_val2,
- enc->roi_buf[buf_ctrl->old_val2].daddr,
- buf_ctrl->val);
- }
-}
-
-static int s5p_mfc_enc_set_buf_ctrls_val(struct s5p_mfc_ctx *ctx, struct list_head *head)
-{
- struct s5p_mfc_buf_ctrl *buf_ctrl;
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_enc *enc = ctx->enc_priv;
- unsigned int value = 0;
- struct s5p_mfc_enc_params *p = &enc->params;
-
- list_for_each_entry(buf_ctrl, head, list) {
- if (!(buf_ctrl->type & MFC_CTRL_TYPE_SET) || !buf_ctrl->has_new)
- continue;
-
- /* read old vlaue */
- value = MFC_READL(buf_ctrl->addr);
-
- /* save old value for recovery */
- if (buf_ctrl->is_volatile)
- buf_ctrl->old_val = (value >> buf_ctrl->shft) & buf_ctrl->mask;
-
- /* write new value */
- value &= ~(buf_ctrl->mask << buf_ctrl->shft);
- value |= ((buf_ctrl->val & buf_ctrl->mask) << buf_ctrl->shft);
- MFC_WRITEL(value, buf_ctrl->addr);
-
- /* set change flag bit */
- if (buf_ctrl->flag_mode == MFC_CTRL_MODE_SFR) {
- value = MFC_READL(buf_ctrl->flag_addr);
- value |= (1 << buf_ctrl->flag_shft);
- MFC_WRITEL(value, buf_ctrl->flag_addr);
- }
-
- buf_ctrl->has_new = 0;
- buf_ctrl->updated = 1;
-
- mfc_enc_set_buf_ctrls_exception(ctx, buf_ctrl);
-
- mfc_debug(6, "[CTRLS] Set buffer control id: 0x%08x, val: %d\n",
- buf_ctrl->id, buf_ctrl->val);
- }
-
- if (!p->rc_frame && !p->rc_mb && p->dynamic_qp) {
- value = MFC_READL(S5P_FIMV_E_FIXED_PICTURE_QP);
- value &= ~(0xFF000000);
- value |= (p->config_qp & 0xFF) << 24;
- MFC_WRITEL(value, S5P_FIMV_E_FIXED_PICTURE_QP);
- mfc_debug(6, "[CTRLS] Dynamic QP changed %#x\n",
- MFC_READL(S5P_FIMV_E_FIXED_PICTURE_QP));
- }
-
- return 0;
-}
-
-static int s5p_mfc_enc_get_buf_ctrls_val(struct s5p_mfc_ctx *ctx, struct list_head *head)
-{
- struct s5p_mfc_buf_ctrl *buf_ctrl;
- struct s5p_mfc_dev *dev = ctx->dev;
- unsigned int value = 0;
-
- list_for_each_entry(buf_ctrl, head, list) {
- if (!(buf_ctrl->type & MFC_CTRL_TYPE_GET))
- continue;
-
- if (buf_ctrl->mode == MFC_CTRL_MODE_SFR)
- value = MFC_READL(buf_ctrl->addr);
- else if (buf_ctrl->mode == MFC_CTRL_MODE_CST)
- value = call_bop(buf_ctrl, read_cst, ctx, buf_ctrl);
-
- value = (value >> buf_ctrl->shft) & buf_ctrl->mask;
-
- buf_ctrl->val = value;
- buf_ctrl->has_new = 1;
-
- mfc_debug(6, "[CTRLS] Get buffer control id: 0x%08x, val: %d\n",
- buf_ctrl->id, buf_ctrl->val);
- }
-
- return 0;
-}
-
-static int s5p_mfc_enc_set_buf_ctrls_val_nal_q_enc(struct s5p_mfc_ctx *ctx,
- struct list_head *head, EncoderInputStr *pInStr)
-{
- struct s5p_mfc_buf_ctrl *buf_ctrl;
- struct s5p_mfc_enc *enc = ctx->enc_priv;
- struct temporal_layer_info temporal_LC;
- unsigned int i, param_change;
- struct s5p_mfc_enc_params *p = &enc->params;
-
- mfc_debug_enter();
-
- list_for_each_entry(buf_ctrl, head, list) {
- if (!(buf_ctrl->type & MFC_CTRL_TYPE_SET) || !buf_ctrl->has_new)
- continue;
- param_change = 0;
- switch (buf_ctrl->id) {
- case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG:
- pInStr->PictureTag &= ~(buf_ctrl->mask << buf_ctrl->shft);
- pInStr->PictureTag |=
- (buf_ctrl->val & buf_ctrl->mask) << buf_ctrl->shft;
- enc->stored_tag = buf_ctrl->val;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE:
- pInStr->FrameInsertion &= ~(buf_ctrl->mask << buf_ctrl->shft);
- pInStr->FrameInsertion |=
- (buf_ctrl->val & buf_ctrl->mask) << buf_ctrl->shft;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_I_PERIOD_CH:
- pInStr->GopConfig &= ~(buf_ctrl->mask << buf_ctrl->shft);
- pInStr->GopConfig |=
- (buf_ctrl->val & buf_ctrl->mask) << buf_ctrl->shft;
- pInStr->GopConfig2 &= ~(0x3FFF);
- pInStr->GopConfig2 |= (buf_ctrl->val >> 16) & 0x3FFF;
- param_change = 1;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_RATE_CH:
- pInStr->RcFrameRate &= ~(buf_ctrl->mask << buf_ctrl->shft);
- pInStr->RcFrameRate |=
- (buf_ctrl->val & buf_ctrl->mask) << buf_ctrl->shft;
- param_change = 1;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_BIT_RATE_CH:
- pInStr->RcBitRate &= ~(buf_ctrl->mask << buf_ctrl->shft);
- pInStr->RcBitRate |=
- (buf_ctrl->val & buf_ctrl->mask) << buf_ctrl->shft;
- param_change = 1;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
- case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP:
- case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP:
- case V4L2_CID_MPEG_VIDEO_H263_MAX_QP:
- case V4L2_CID_MPEG_VIDEO_VP8_MAX_QP:
- case V4L2_CID_MPEG_VIDEO_VP9_MAX_QP:
- case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
- case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP:
- case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP:
- case V4L2_CID_MPEG_VIDEO_H263_MIN_QP:
- case V4L2_CID_MPEG_VIDEO_VP8_MIN_QP:
- case V4L2_CID_MPEG_VIDEO_VP9_MIN_QP:
- pInStr->RcQpBound &= ~(buf_ctrl->mask << buf_ctrl->shft);
- pInStr->RcQpBound |=
- (buf_ctrl->val & buf_ctrl->mask) << buf_ctrl->shft;
- param_change = 1;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_MAX_QP_P:
- case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP_P:
- case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP_P:
- case V4L2_CID_MPEG_VIDEO_H263_MAX_QP_P:
- case V4L2_CID_MPEG_VIDEO_VP8_MAX_QP_P:
- case V4L2_CID_MPEG_VIDEO_VP9_MAX_QP_P:
- case V4L2_CID_MPEG_VIDEO_H264_MIN_QP_P:
- case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP_P:
- case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP_P:
- case V4L2_CID_MPEG_VIDEO_H263_MIN_QP_P:
- case V4L2_CID_MPEG_VIDEO_VP8_MIN_QP_P:
- case V4L2_CID_MPEG_VIDEO_VP9_MIN_QP_P:
- case V4L2_CID_MPEG_VIDEO_H264_MAX_QP_B:
- case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP_B:
- case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP_B:
- case V4L2_CID_MPEG_VIDEO_H264_MIN_QP_B:
- case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP_B:
- case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP_B:
- pInStr->RcQpBoundPb &= ~(buf_ctrl->mask << buf_ctrl->shft);
- pInStr->RcQpBoundPb |=
- (buf_ctrl->val & buf_ctrl->mask) << buf_ctrl->shft;
- param_change = 1;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_CH:
- case V4L2_CID_MPEG_VIDEO_VP8_HIERARCHICAL_CODING_LAYER_CH:
- case V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER_CH:
- case V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_CH:
- memcpy(&temporal_LC,
- enc->sh_handle_svc.vaddr, sizeof(struct temporal_layer_info));
-
- if (((temporal_LC.temporal_layer_count & 0x7) < 1) ||
- ((temporal_LC.temporal_layer_count > 3) && IS_VP8_ENC(ctx)) ||
- ((temporal_LC.temporal_layer_count > 3) && IS_VP9_ENC(ctx))) {
- /* claer NUM_T_LAYER_CHANGE */
- mfc_err_ctx("[NALQ][HIERARCHICAL] layer count(%d) is invalid\n",
- temporal_LC.temporal_layer_count);
- return 0;
- }
-
- if (IS_H264_ENC(ctx))
- p->codec.h264.num_hier_layer =
- temporal_LC.temporal_layer_count & 0x7;
-
- /* enable RC_BIT_RATE_CHANGE */
- if (temporal_LC.temporal_layer_bitrate[0] > 0 || p->hier_bitrate_ctrl)
- pInStr->ParamChange |= (1 << 2);
- else
- pInStr->ParamChange &= ~(1 << 2);
-
- /* enalbe NUM_T_LAYER_CHANGE */
- if (temporal_LC.temporal_layer_count & 0x7)
- pInStr->ParamChange |= (1 << 10);
- else
- pInStr->ParamChange &= ~(1 << 10);
- mfc_debug(3, "[NALQ][HIERARCHICAL] layer count %d\n",
- temporal_LC.temporal_layer_count & 0x7);
-
- pInStr->NumTLayer &= ~(0x7);
- pInStr->NumTLayer |= (temporal_LC.temporal_layer_count & 0x7);
- pInStr->NumTLayer &= ~(0x1 << 8);
- pInStr->NumTLayer |= (p->hier_bitrate_ctrl & 0x1) << 8;
- for (i = 0; i < (temporal_LC.temporal_layer_count & 0x7); i++) {
- mfc_debug(3, "[NALQ][HIERARCHICAL] layer bitrate[%d] %d (FW ctrl: %d)\n",
- i, temporal_LC.temporal_layer_bitrate[i], p->hier_bitrate_ctrl);
- pInStr->HierarchicalBitRateLayer[i] =
- temporal_LC.temporal_layer_bitrate[i];
- }
-
- /* priority change */
- if (IS_H264_ENC(ctx)) {
- for (i = 0; i < (temporal_LC.temporal_layer_count & 0x7); i++) {
- if (i <= 4)
- pInStr->H264HDSvcExtension0 |=
- ((p->codec.h264.base_priority & 0x3f) + i) << (6 * i);
- else
- pInStr->H264HDSvcExtension1 |=
- ((p->codec.h264.base_priority & 0x3f) + i) << (6 * (i - 5));
- }
- mfc_debug(3, "[NALQ][HIERARCHICAL] EXTENSION0 %#x, EXTENSION1 %#x\n",
- pInStr->H264HDSvcExtension0, pInStr->H264HDSvcExtension1);
-
- pInStr->ParamChange |= (1 << 12);
- }
- break;
- case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
- pInStr->PictureProfile &= ~(buf_ctrl->mask << buf_ctrl->shft);
- pInStr->PictureProfile |=
- (buf_ctrl->val & buf_ctrl->mask) << buf_ctrl->shft;
- pInStr->PictureProfile &= ~(0xf);
- pInStr->PictureProfile |= p->codec.h264.profile & 0xf;
- p->codec.h264.level = buf_ctrl->val;
- param_change = 1;
- break;
- case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
- pInStr->PictureProfile &= ~(buf_ctrl->mask << buf_ctrl->shft);
- pInStr->PictureProfile |=
- (buf_ctrl->val & buf_ctrl->mask) << buf_ctrl->shft;
- pInStr->PictureProfile &= ~(0xff << 8);
- pInStr->PictureProfile |= (p->codec.h264.level << 8) & 0xff00;
- p->codec.h264.profile = buf_ctrl->val;
- param_change = 1;
- break;
- case V4L2_CID_MPEG_MFC_H264_MARK_LTR:
- pInStr->H264NalControl &= ~(buf_ctrl->mask << buf_ctrl->shft);
- pInStr->H264NalControl |=
- (buf_ctrl->val & buf_ctrl->mask) << buf_ctrl->shft;
- pInStr->H264NalControl &= ~(0x7 << 8);
- pInStr->H264NalControl |= (buf_ctrl->val & 0x7) << 8;
- break;
- case V4L2_CID_MPEG_MFC_H264_USE_LTR:
- pInStr->H264NalControl &= ~(buf_ctrl->mask << buf_ctrl->shft);
- pInStr->H264NalControl |=
- (buf_ctrl->val & buf_ctrl->mask) << buf_ctrl->shft;
- pInStr->H264NalControl &= ~(0xF << 11);
- pInStr->H264NalControl |= (buf_ctrl->val & 0xF) << 11;
- break;
- case V4L2_CID_MPEG_MFC_H264_BASE_PRIORITY:
- for (i = 0; i < (p->codec.h264.num_hier_layer & 0x7); i++)
- if (i <= 4)
- pInStr->H264HDSvcExtension0 |=
- ((buf_ctrl->val & 0x3f) + i) << (6 * i);
- else
- pInStr->H264HDSvcExtension1 |=
- ((buf_ctrl->val & 0x3f) + i) << (6 * (i - 5));
- p->codec.h264.base_priority = buf_ctrl->val;
- param_change = 1;
- break;
- case V4L2_CID_MPEG_MFC_CONFIG_QP:
- pInStr->FixedPictureQp &= ~(buf_ctrl->mask << buf_ctrl->shft);
- pInStr->FixedPictureQp |=
- (buf_ctrl->val & buf_ctrl->mask) << buf_ctrl->shft;
- p->config_qp = buf_ctrl->val;
- break;
- case V4L2_CID_MPEG_VIDEO_ROI_CONTROL:
- pInStr->RcRoiCtrl &= ~(buf_ctrl->mask << buf_ctrl->shft);
- pInStr->RcRoiCtrl |=
- (buf_ctrl->val & buf_ctrl->mask) << buf_ctrl->shft;
- pInStr->RoiBufferAddr = enc->roi_buf[buf_ctrl->old_val2].daddr;
- mfc_debug(3, "[NALQ][ROI] buffer[%d] addr %#llx, QP val: %#x\n",
- buf_ctrl->old_val2,
- enc->roi_buf[buf_ctrl->old_val2].daddr,
- buf_ctrl->val);
- break;
- case V4L2_CID_MPEG_VIDEO_YSUM:
- pInStr->Weight &= ~(buf_ctrl->mask << buf_ctrl->shft);
- pInStr->Weight |=
- (buf_ctrl->val & buf_ctrl->mask) << buf_ctrl->shft;
- break;
- case V4L2_CID_MPEG_VIDEO_RATIO_OF_INTRA:
- pInStr->RcMode &= ~(buf_ctrl->mask << buf_ctrl->shft);
- pInStr->RcMode |=
- (buf_ctrl->val & buf_ctrl->mask) << buf_ctrl->shft;
- param_change = 1;
- break;
- /* If new dynamic controls are added, insert here */
- default:
- mfc_info_ctx("[NALQ] can't find control, id: 0x%x\n",
- buf_ctrl->id);
- }
-
- if (param_change)
- pInStr->ParamChange |= (1 << buf_ctrl->flag_shft);
-
- buf_ctrl->has_new = 0;
- buf_ctrl->updated = 1;
-
- mfc_debug(6, "[NALQ][CTRLS] Set buffer control id: 0x%08x, val: %d\n",
- buf_ctrl->id, buf_ctrl->val);
- }
-
- if (!p->rc_frame && !p->rc_mb && p->dynamic_qp) {
- pInStr->FixedPictureQp &= ~(0xFF000000);
- pInStr->FixedPictureQp |= (p->config_qp & 0xFF) << 24;
- mfc_debug(6, "[NALQ][CTRLS] Dynamic QP changed %#x\n",
- pInStr->FixedPictureQp);
- }
-
- mfc_debug_leave();
-
- return 0;
-}
-
-static int s5p_mfc_enc_get_buf_ctrls_val_nal_q_enc(struct s5p_mfc_ctx *ctx,
- struct list_head *head, EncoderOutputStr *pOutStr)
-{
- struct s5p_mfc_buf_ctrl *buf_ctrl;
- struct s5p_mfc_enc *enc = ctx->enc_priv;
- unsigned int value = 0;
-
- mfc_debug_enter();
-
- list_for_each_entry(buf_ctrl, head, list) {
- if (!(buf_ctrl->type & MFC_CTRL_TYPE_GET))
- continue;
- switch (buf_ctrl->id) {
- case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG:
- value = pOutStr->PictureTag;
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_LUMA_ADDR:
- value = pOutStr->EncodedFrameAddr[0];
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_CHROMA_ADDR:
- value = pOutStr->EncodedFrameAddr[1];
- break;
- case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_STATUS:
- value = !enc->in_slice;
- break;
- /* If new dynamic controls are added, insert here */
- default:
- mfc_info_ctx("[NALQ] can't find control, id: 0x%x\n",
- buf_ctrl->id);
- }
- value = (value >> buf_ctrl->shft) & buf_ctrl->mask;
-
- buf_ctrl->val = value;
- buf_ctrl->has_new = 1;
-
- mfc_debug(6, "[NALQ][CTRLS] Get buffer control id: 0x%08x, val: %d\n",
- buf_ctrl->id, buf_ctrl->val);
- }
-
- mfc_debug_leave();
-
- return 0;
-}
-
-static int s5p_mfc_enc_recover_buf_ctrls_val(struct s5p_mfc_ctx *ctx,
- struct list_head *head)
-{
- struct s5p_mfc_buf_ctrl *buf_ctrl;
- struct s5p_mfc_dev *dev = ctx->dev;
- unsigned int value = 0;
-
- list_for_each_entry(buf_ctrl, head, list) {
- if (!(buf_ctrl->type & MFC_CTRL_TYPE_SET)
- || !buf_ctrl->is_volatile
- || !buf_ctrl->updated)
- continue;
-
- if (buf_ctrl->mode == MFC_CTRL_MODE_SFR)
- value = MFC_READL(buf_ctrl->addr);
-
- value &= ~(buf_ctrl->mask << buf_ctrl->shft);
- value |= ((buf_ctrl->old_val & buf_ctrl->mask)
- << buf_ctrl->shft);
-
- if (buf_ctrl->mode == MFC_CTRL_MODE_SFR)
- MFC_WRITEL(value, buf_ctrl->addr);
-
- /* clear change flag bit */
- if (buf_ctrl->flag_mode == MFC_CTRL_MODE_SFR) {
- value = MFC_READL(buf_ctrl->flag_addr);
- value &= ~(1 << buf_ctrl->flag_shft);
- MFC_WRITEL(value, buf_ctrl->flag_addr);
- }
-
- mfc_debug(6, "[CTRLS] Recover buffer control id: 0x%08x, old val: %d\n",
- buf_ctrl->id, buf_ctrl->old_val);
-
- if (buf_ctrl->id == V4L2_CID_MPEG_MFC51_VIDEO_I_PERIOD_CH) {
- value = MFC_READL(S5P_FIMV_E_GOP_CONFIG2);
- value &= ~(0x3FFF);
- value |= (buf_ctrl->old_val >> 16) & 0x3FFF;
- MFC_WRITEL(value, S5P_FIMV_E_GOP_CONFIG2);
- }
- if (buf_ctrl->id == V4L2_CID_MPEG_VIDEO_H264_LEVEL) {
- value = MFC_READL(S5P_FIMV_E_PICTURE_PROFILE);
- value &= ~(0x000F);
- value |= (buf_ctrl->old_val >> 8) & 0x000F;
- MFC_WRITEL(value, S5P_FIMV_E_PICTURE_PROFILE);
- }
- if (buf_ctrl->id == V4L2_CID_MPEG_VIDEO_H264_PROFILE) {
- value = MFC_READL(S5P_FIMV_E_PICTURE_PROFILE);
- value &= ~(0xFF00);
- value |= buf_ctrl->old_val & 0xFF00;
- MFC_WRITEL(value, S5P_FIMV_E_PICTURE_PROFILE);
- }
- if (buf_ctrl->id == V4L2_CID_MPEG_MFC_H264_BASE_PRIORITY) {
- MFC_WRITEL(buf_ctrl->old_val, S5P_FIMV_E_H264_HD_SVC_EXTENSION_0);
- MFC_WRITEL(buf_ctrl->old_val2, S5P_FIMV_E_H264_HD_SVC_EXTENSION_1);
- }
- if (buf_ctrl->id
- == V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_CH ||
- buf_ctrl->id
- == V4L2_CID_MPEG_VIDEO_VP8_HIERARCHICAL_CODING_LAYER_CH ||
- buf_ctrl->id
- == V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_CH) {
- MFC_WRITEL(buf_ctrl->old_val2, S5P_FIMV_E_NUM_T_LAYER);
- /* clear RC_BIT_RATE_CHANGE */
- value = MFC_READL(buf_ctrl->flag_addr);
- value &= ~(1 << 2);
- MFC_WRITEL(value, buf_ctrl->flag_addr);
- }
- if (buf_ctrl->id == V4L2_CID_MPEG_MFC_H264_MARK_LTR) {
- value = MFC_READL(S5P_FIMV_E_H264_NAL_CONTROL);
- value &= ~(0x7 << 8);
- value |= (buf_ctrl->old_val2 & 0x7) << 8;
- MFC_WRITEL(value, S5P_FIMV_E_H264_NAL_CONTROL);
- }
- if (buf_ctrl->id == V4L2_CID_MPEG_MFC_H264_USE_LTR) {
- value = MFC_READL(S5P_FIMV_E_H264_NAL_CONTROL);
- value &= ~(0xF << 11);
- value |= (buf_ctrl->old_val2 & 0xF) << 11;
- MFC_WRITEL(value, S5P_FIMV_E_H264_NAL_CONTROL);
- }
- buf_ctrl->updated = 0;
- }
-
- return 0;
-}
-
-static int s5p_mfc_enc_recover_buf_ctrls_nal_q(struct s5p_mfc_ctx *ctx,
- struct list_head *head)
-{
- struct s5p_mfc_buf_ctrl *buf_ctrl;
-
- list_for_each_entry(buf_ctrl, head, list) {
- if (!(buf_ctrl->type & MFC_CTRL_TYPE_SET)
- || !(buf_ctrl->updated))
- continue;
-
- buf_ctrl->has_new = 1;
- buf_ctrl->updated = 0;
-
- mfc_debug(6, "[NALQ][CTRLS] Recover buffer control id: 0x%08x, val: %d\n",
- buf_ctrl->id, buf_ctrl->val);
- }
-
- return 0;
-}
-
-struct s5p_mfc_ctrls_ops encoder_ctrls_ops = {
- .init_ctx_ctrls = s5p_mfc_enc_init_ctx_ctrls,
- .cleanup_ctx_ctrls = s5p_mfc_enc_cleanup_ctx_ctrls,
- .init_buf_ctrls = s5p_mfc_enc_init_buf_ctrls,
- .reset_buf_ctrls = s5p_mfc_enc_reset_buf_ctrls,
- .cleanup_buf_ctrls = s5p_mfc_enc_cleanup_buf_ctrls,
- .to_buf_ctrls = s5p_mfc_enc_to_buf_ctrls,
- .to_ctx_ctrls = s5p_mfc_enc_to_ctx_ctrls,
- .set_buf_ctrls_val = s5p_mfc_enc_set_buf_ctrls_val,
- .get_buf_ctrls_val = s5p_mfc_enc_get_buf_ctrls_val,
- .recover_buf_ctrls_val = s5p_mfc_enc_recover_buf_ctrls_val,
- .get_buf_update_val = s5p_mfc_enc_get_buf_update_val,
- .set_buf_ctrls_val_nal_q_enc = s5p_mfc_enc_set_buf_ctrls_val_nal_q_enc,
- .get_buf_ctrls_val_nal_q_enc = s5p_mfc_enc_get_buf_ctrls_val_nal_q_enc,
- .recover_buf_ctrls_nal_q = s5p_mfc_enc_recover_buf_ctrls_nal_q,
-};
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_enc_param.c
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include "s5p_mfc_enc_param.h"
-
-#include "s5p_mfc_reg.h"
-
-/* Definition */
-#define FRAME_DELTA_DEFAULT 1
-#define CBR_FIX_MAX 10
-#define CBR_I_LIMIT_MAX 5
-#define BPG_EXTENSION_TAG_SIZE 5
-
-void s5p_mfc_set_slice_mode(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_enc *enc = ctx->enc_priv;
-
- /* multi-slice control */
- if (enc->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES)
- MFC_WRITEL((enc->slice_mode + 0x4), S5P_FIMV_E_MSLICE_MODE);
- else if (enc->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB_ROW)
- MFC_WRITEL((enc->slice_mode - 0x2), S5P_FIMV_E_MSLICE_MODE);
- else if (enc->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_FIXED_BYTES)
- MFC_WRITEL((enc->slice_mode + 0x3), S5P_FIMV_E_MSLICE_MODE);
- else
- MFC_WRITEL(enc->slice_mode, S5P_FIMV_E_MSLICE_MODE);
-
- /* multi-slice MB number or bit size */
- if ((enc->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) ||
- (enc->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB_ROW)) {
- MFC_WRITEL(enc->slice_size.mb, S5P_FIMV_E_MSLICE_SIZE_MB);
- } else if ((enc->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) ||
- (enc->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_FIXED_BYTES)){
- MFC_WRITEL(enc->slice_size.bits, S5P_FIMV_E_MSLICE_SIZE_BITS);
- } else {
- MFC_WRITEL(0x0, S5P_FIMV_E_MSLICE_SIZE_MB);
- MFC_WRITEL(0x0, S5P_FIMV_E_MSLICE_SIZE_BITS);
- }
-}
-
-static void mfc_set_gop_size(struct s5p_mfc_ctx *ctx, int ctrl_mode)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_enc *enc = ctx->enc_priv;
- struct s5p_mfc_enc_params *p = &enc->params;
- unsigned int reg = 0;
-
- if (ctrl_mode) {
- p->i_frm_ctrl_mode = 1;
- p->i_frm_ctrl = p->gop_size * (p->num_b_frame + 1);
- if (p->i_frm_ctrl >= 0x3FFFFFFF) {
- mfc_info_ctx("I frame interval is bigger than max: %d\n",
- p->i_frm_ctrl);
- p->i_frm_ctrl = 0x3FFFFFFF;
- }
- } else {
- p->i_frm_ctrl_mode = 0;
- p->i_frm_ctrl = p->gop_size;
- }
-
- mfc_debug(2, "I frame interval: %d, (P: %d, B: %d), ctrl mode: %d\n",
- p->i_frm_ctrl, p->gop_size,
- p->num_b_frame, p->i_frm_ctrl_mode);
-
- /* pictype : IDR period, number of B */
- reg = MFC_READL(S5P_FIMV_E_GOP_CONFIG);
- reg &= ~(0xFFFF);
- reg |= p->i_frm_ctrl & 0xFFFF;
- reg &= ~(0x1 << 19);
- reg |= p->i_frm_ctrl_mode << 19;
- reg &= ~(0x3 << 16);
- /* if B frame is used, the performance falls by half */
- reg |= (p->num_b_frame << 16);
- MFC_WRITEL(reg, S5P_FIMV_E_GOP_CONFIG);
-
- reg = MFC_READL(S5P_FIMV_E_GOP_CONFIG2);
- reg &= ~(0x3FFF);
- reg |= (p->i_frm_ctrl >> 16) & 0x3FFF;
- MFC_WRITEL(reg, S5P_FIMV_E_GOP_CONFIG2);
-}
-
-static void mfc_set_default_params(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- int i;
-
- mfc_debug(2, "Set default param - enc_param_num: %d\n", dev->pdata->enc_param_num);
- for (i = 0; i < dev->pdata->enc_param_num; i++) {
- if (i >= MFC_MAX_DEFAULT_PARAM) {
- mfc_err_dev("enc_param_num(%d) is over max number(%d)\n",
- dev->pdata->enc_param_num, MFC_MAX_DEFAULT_PARAM);
- break;
- }
- MFC_WRITEL(dev->pdata->enc_param_val[i], dev->pdata->enc_param_addr[i]);
- mfc_debug(2, "Set default param[%d] - addr:0x%x, val:0x%x\n",
- i, dev->pdata->enc_param_addr[i], dev->pdata->enc_param_val[i]);
- }
-}
-
-static void mfc_init_regs(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
-
- /* Register initialization */
- MFC_WRITEL(0x0, S5P_FIMV_E_FRAME_INSERTION);
- MFC_WRITEL(0x0, S5P_FIMV_E_ROI_BUFFER_ADDR);
- MFC_WRITEL(0x0, S5P_FIMV_E_PARAM_CHANGE);
- MFC_WRITEL(0x0, S5P_FIMV_E_PICTURE_TAG);
- MFC_WRITEL(0x0, S5P_FIMV_E_METADATA_BUFFER_ADDR);
- MFC_WRITEL(0x0, S5P_FIMV_E_METADATA_BUFFER_SIZE);
-}
-
-static void mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_enc *enc = ctx->enc_priv;
- struct s5p_mfc_enc_params *p = &enc->params;
- unsigned int reg = 0;
-
- mfc_debug_enter();
-
- mfc_init_regs(ctx);
- mfc_set_default_params(ctx);
-
- /* width */
- MFC_WRITEL(ctx->crop_width, S5P_FIMV_E_CROPPED_FRAME_WIDTH);
- /* height */
- MFC_WRITEL(ctx->crop_height, S5P_FIMV_E_CROPPED_FRAME_HEIGHT);
- /* cropped offset */
- reg |= (ctx->crop_left & S5P_FIMV_E_FRAME_CROP_OFFSET_MASK)
- << S5P_FIMV_E_FRAME_CROP_OFFSET_LEFT;
- reg |= (ctx->crop_top & S5P_FIMV_E_FRAME_CROP_OFFSET_MASK)
- << S5P_FIMV_E_FRAME_CROP_OFFSET_TOP;
- MFC_WRITEL(reg, S5P_FIMV_E_FRAME_CROP_OFFSET);
-
- /* multi-slice control */
- /* multi-slice MB number or bit size */
- enc->slice_mode = p->slice_mode;
-
- if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) {
- enc->slice_size.mb = p->slice_mb;
- } else if ((p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) ||
- (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_FIXED_BYTES)){
- enc->slice_size.bits = p->slice_bit;
- } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB_ROW) {
- enc->slice_size.mb = p->slice_mb_row * ((ctx->crop_width + 15) / 16);
- } else {
- enc->slice_size.mb = 0;
- enc->slice_size.bits = 0;
- }
-
- s5p_mfc_set_slice_mode(ctx);
-
- /* cyclic intra refresh */
- MFC_WRITEL(p->intra_refresh_mb, S5P_FIMV_E_IR_SIZE);
-
- reg = MFC_READL(S5P_FIMV_E_ENC_OPTIONS);
- /* frame skip mode */
- reg &= ~(0x3);
- reg |= (p->frame_skip_mode & 0x3);
- /* seq header ctrl */
- reg &= ~(0x1 << 2);
- reg |= ((p->seq_hdr_mode & 0x1) << 2);
- /* cyclic intra refresh */
- reg &= ~(0x1 << 4);
- if (p->intra_refresh_mb)
- reg |= (0x1 << 4);
- /* disable seq header generation if OTF mode */
- reg &= ~(0x1 << 6);
- if (ctx->otf_handle) {
- reg |= (0x1 << 6);
- mfc_debug(2, "[OTF] SEQ_HEADER_GENERATION is disabled\n");
- }
- /* 'NON_REFERENCE_STORE_ENABLE' for debugging */
- reg &= ~(0x1 << 9);
- /* Disable parallel processing if nal_q_parallel_disable was set */
- reg &= ~(0x1 << 18);
- if (nal_q_parallel_disable)
- reg |= (0x1 << 18);
- MFC_WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS);
-
- s5p_mfc_set_pixel_format(dev, ctx->src_fmt->fourcc);
-
- /* padding control & value */
- MFC_WRITEL(0x0, S5P_FIMV_E_PADDING_CTRL);
- if (p->pad) {
- reg = 0;
- /** enable */
- reg |= (1 << 31);
- /** cr value */
- reg &= ~(0xFF << 16);
- reg |= (p->pad_cr << 16);
- /** cb value */
- reg &= ~(0xFF << 8);
- reg |= (p->pad_cb << 8);
- /** y value */
- reg &= ~(0xFF);
- reg |= (p->pad_luma);
- MFC_WRITEL(reg, S5P_FIMV_E_PADDING_CTRL);
- }
-
- /* rate control config. */
- reg = MFC_READL(S5P_FIMV_E_RC_CONFIG);
- /* macroblock level rate control */
- reg &= ~(0x1 << 8);
- reg |= ((p->rc_mb & 0x1) << 8);
- /* frame-level rate control */
- reg &= ~(0x1 << 9);
- reg |= ((p->rc_frame & 0x1) << 9);
- /* 'DROP_CONTROL_ENABLE', disable */
- reg &= ~(0x1 << 10);
- MFC_WRITEL(reg, S5P_FIMV_E_RC_CONFIG);
-
- /* bit rate */
- MFC_WRITEL(p->rc_bitrate, S5P_FIMV_E_RC_BIT_RATE);
-
-
- reg = MFC_READL(S5P_FIMV_E_RC_MODE);
- reg &= ~(0x3 | (0x3 << 4) | (0xFF << 8));
- if (p->rc_frame) {
- if (p->rc_reaction_coeff <= CBR_I_LIMIT_MAX) {
- reg |= S5P_FIMV_E_RC_CBR_I_LIMIT;
- /*
- * Ratio of intra for max frame size
- * is controled when only CBR_I_LIMIT mode.
- * And CBR_I_LIMIT mode is valid for H.264, HEVC codec
- */
- if (p->ratio_intra)
- reg |= ((p->ratio_intra & 0xFF) << 8);
- } else if (p->rc_reaction_coeff <= CBR_FIX_MAX) {
- reg |= S5P_FIMV_E_RC_CBR_FIX;
- } else {
- reg |= S5P_FIMV_E_RC_VBR;
- }
-
- if (p->rc_mb)
- reg |= ((p->rc_pvc & 0x3) << 4);
- }
- MFC_WRITEL(reg, S5P_FIMV_E_RC_MODE);
-
- /* extended encoder ctrl */
- /** vbv buffer size */
- reg = MFC_READL(S5P_FIMV_E_VBV_BUFFER_SIZE);
- reg &= ~(0xFF);
- if (p->frame_skip_mode == V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT)
- reg |= p->vbv_buf_size & 0xFF;
- MFC_WRITEL(reg, S5P_FIMV_E_VBV_BUFFER_SIZE);
-
- mfc_debug_leave();
-}
-
-static void mfc_set_temporal_svc_h264(struct s5p_mfc_ctx *ctx, struct s5p_mfc_h264_enc_params *p_264)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_enc *enc = ctx->enc_priv;
- struct s5p_mfc_enc_params *p = &enc->params;
- unsigned int reg = 0, reg2 = 0;
- int i;
-
- reg = MFC_READL(S5P_FIMV_E_H264_OPTIONS_2);
- /* pic_order_cnt_type = 0 for backward compatibilities */
- reg &= ~(0x3);
- /* Enable LTR */
- reg &= ~(0x1 << 2);
- if ((p_264->enable_ltr & 0x1) || (p_264->num_of_ltr > 0))
- reg |= (0x1 << 2);
- /* Number of LTR */
- reg &= ~(0x3 << 7);
- if (p_264->num_of_ltr > 2)
- reg |= (((p_264->num_of_ltr - 2) & 0x3) << 7);
- MFC_WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_2);
-
- /* Temporal SVC - qp type, layer number */
- reg = MFC_READL(S5P_FIMV_E_NUM_T_LAYER);
- reg &= ~(0x1 << 3);
- reg |= (p_264->hier_qp_type & 0x1) << 3;
- reg &= ~(0x7);
- reg |= p_264->num_hier_layer & 0x7;
- reg &= ~(0x7 << 4);
- if (p_264->hier_ref_type) {
- reg |= 0x1 << 7;
- reg |= (p->num_hier_max_layer & 0x7) << 4;
- } else {
- reg &= ~(0x1 << 7);
- reg |= 0x7 << 4;
- }
- reg &= ~(0x1 << 8);
- reg |= (p->hier_bitrate_ctrl & 0x1) << 8;
- MFC_WRITEL(reg, S5P_FIMV_E_NUM_T_LAYER);
- mfc_debug(3, "[HIERARCHICAL] hier_qp_enable %d, enable_ltr %d, "
- "num_hier_layer %d, max_layer %d, hier_ref_type %d, NUM_T_LAYER 0x%x\n",
- p_264->hier_qp_enable, p_264->enable_ltr, p_264->num_hier_layer,
- p->num_hier_max_layer, p_264->hier_ref_type, reg);
- /* QP & Bitrate for each layer */
- for (i = 0; i < 7; i++) {
- MFC_WRITEL(p_264->hier_qp_layer[i],
- S5P_FIMV_E_HIERARCHICAL_QP_LAYER0 + i * 4);
- /* If hier_bitrate_ctrl is set to 1, this is meaningless */
- MFC_WRITEL(p_264->hier_bit_layer[i],
- S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER0 + i * 4);
- mfc_debug(3, "[HIERARCHICAL] layer[%d] QP: %#x, bitrate: %d(FW ctrl: %d)\n",
- i, p_264->hier_qp_layer[i],
- p_264->hier_bit_layer[i], p->hier_bitrate_ctrl);
- }
- if (p_264->set_priority) {
- reg = 0;
- reg2 = 0;
- for (i = 0; i < (p_264->num_hier_layer & 0x7); i++) {
- if (i <= 4)
- reg |= ((p_264->base_priority & 0x3F) + i) << (6 * i);
- else
- reg2 |= ((p_264->base_priority & 0x3F) + i) << (6 * (i - 5));
- }
- MFC_WRITEL(reg, S5P_FIMV_E_H264_HD_SVC_EXTENSION_0);
- MFC_WRITEL(reg2, S5P_FIMV_E_H264_HD_SVC_EXTENSION_1);
- mfc_debug(3, "[HIERARCHICAL] priority EXTENSION0: %#x, EXTENSION1: %#x\n",
- reg, reg2);
- }
-}
-
-static void mfc_set_fmo_slice_map_h264(struct s5p_mfc_ctx *ctx, struct s5p_mfc_h264_enc_params *p_264)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- int i;
-
- if (p_264->fmo_enable) {
- switch (p_264->fmo_slice_map_type) {
- case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_INTERLEAVED_SLICES:
- if (p_264->fmo_slice_num_grp > 4)
- p_264->fmo_slice_num_grp = 4;
- for (i = 0; i < (p_264->fmo_slice_num_grp & 0xF); i++)
- MFC_WRITEL(p_264->fmo_run_length[i] - 1,
- S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_0 + i*4);
- break;
- case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_SCATTERED_SLICES:
- if (p_264->fmo_slice_num_grp > 4)
- p_264->fmo_slice_num_grp = 4;
- break;
- case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_RASTER_SCAN:
- case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_WIPE_SCAN:
- if (p_264->fmo_slice_num_grp > 2)
- p_264->fmo_slice_num_grp = 2;
- MFC_WRITEL(p_264->fmo_sg_dir & 0x1,
- S5P_FIMV_E_H264_FMO_SLICE_GRP_CHANGE_DIR);
- /* the valid range is 0 ~ number of macroblocks -1 */
- MFC_WRITEL(p_264->fmo_sg_rate, S5P_FIMV_E_H264_FMO_SLICE_GRP_CHANGE_RATE_MINUS1);
- break;
- default:
- mfc_err_ctx("Unsupported map type for FMO: %d\n",
- p_264->fmo_slice_map_type);
- p_264->fmo_slice_map_type = 0;
- p_264->fmo_slice_num_grp = 1;
- break;
- }
-
- MFC_WRITEL(p_264->fmo_slice_map_type, S5P_FIMV_E_H264_FMO_SLICE_GRP_MAP_TYPE);
- MFC_WRITEL(p_264->fmo_slice_num_grp - 1, S5P_FIMV_E_H264_FMO_NUM_SLICE_GRP_MINUS1);
- } else {
- MFC_WRITEL(0, S5P_FIMV_E_H264_FMO_NUM_SLICE_GRP_MINUS1);
- }
-}
-
-void s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_enc *enc = ctx->enc_priv;
- struct s5p_mfc_enc_params *p = &enc->params;
- struct s5p_mfc_h264_enc_params *p_264 = &p->codec.h264;
- unsigned int reg = 0;
-
- mfc_debug_enter();
-
- mfc_set_enc_params(ctx);
-
- if (p_264->num_hier_layer & 0x7) {
- /* set gop_size without i_frm_ctrl mode */
- mfc_set_gop_size(ctx, 0);
- } else {
- /* set gop_size with i_frm_ctrl mode */
- mfc_set_gop_size(ctx, 1);
- }
-
- /* UHD encoding case */
- if(IS_UHD_RES(ctx)) {
- if (p_264->level < 51) {
- mfc_info_ctx("Set Level 5.1 for UHD\n");
- p_264->level = 51;
- }
- if (p_264->profile != 0x2) {
- mfc_info_ctx("Set High profile for UHD\n");
- p_264->profile = 0x2;
- }
- }
-
- /* profile & level */
- reg = 0;
- /** level */
- reg &= ~(0xFF << 8);
- reg |= (p_264->level << 8);
- /** profile - 0 ~ 3 */
- reg &= ~(0x3F);
- reg |= p_264->profile;
- MFC_WRITEL(reg, S5P_FIMV_E_PICTURE_PROFILE);
-
- reg = MFC_READL(S5P_FIMV_E_H264_OPTIONS);
- /* entropy coding mode */
- reg &= ~(0x1);
- reg |= (p_264->entropy_mode & 0x1);
- /* loop filter ctrl */
- reg &= ~(0x3 << 1);
- reg |= ((p_264->loop_filter_mode & 0x3) << 1);
- /* interlace */
- reg &= ~(0x1 << 3);
- reg |= ((p_264->interlace & 0x1) << 3);
- /* intra picture period for H.264 open GOP */
- reg &= ~(0x1 << 4);
- reg |= ((p_264->open_gop & 0x1) << 4);
- /* extended encoder ctrl */
- reg &= ~(0x1 << 5);
- reg |= ((p_264->ar_vui & 0x1) << 5);
- /* ASO enable */
- reg &= ~(0x1 << 6);
- reg |= ((p_264->aso_enable & 0x1) << 6);
- /* if num_refs_for_p is 2, the performance falls by half */
- reg &= ~(0x1 << 7);
- reg |= (((p->num_refs_for_p - 1) & 0x1) << 7);
- /* Temporal SVC - hier qp enable */
- reg &= ~(0x1 << 8);
- reg |= ((p_264->hier_qp_enable & 0x1) << 8);
- /* Weighted Prediction enable */
- reg &= ~(0x3 << 9);
- reg |= ((p->weighted_enable & 0x1) << 9);
- /* 8x8 transform enable */
- reg &= ~(0x1 << 12);
- reg &= ~(0x1 << 13);
- reg |= ((p_264->_8x8_transform & 0x1) << 12);
- reg |= ((p_264->_8x8_transform & 0x1) << 13);
- /* 'CONSTRAINED_INTRA_PRED_ENABLE' is disable */
- reg &= ~(0x1 << 14);
- /*
- * CONSTRAINT_SET0_FLAG: all constraints specified in
- * Baseline Profile
- */
- reg |= (0x1 << 26);
- /* sps pps control */
- reg &= ~(0x1 << 29);
- reg |= ((p_264->prepend_sps_pps_to_idr & 0x1) << 29);
- /* enable sps pps control in OTF scenario */
- if (ctx->otf_handle) {
- reg |= (0x1 << 29);
- mfc_debug(2, "[OTF] SPS_PPS_CONTROL enabled\n");
- }
- /* VUI parameter disable */
- reg &= ~(0x1 << 30);
- reg |= ((p_264->vui_enable & 0x1) << 30);
- MFC_WRITEL(reg, S5P_FIMV_E_H264_OPTIONS);
-
- /* cropped height */
- if (p_264->interlace)
- MFC_WRITEL(ctx->crop_height >> 1, S5P_FIMV_E_CROPPED_FRAME_HEIGHT);
-
- /* loopfilter alpha offset */
- reg = MFC_READL(S5P_FIMV_E_H264_LF_ALPHA_OFFSET);
- reg &= ~(0x1F);
- reg |= (p_264->loop_filter_alpha & 0x1F);
- MFC_WRITEL(reg, S5P_FIMV_E_H264_LF_ALPHA_OFFSET);
-
- /* loopfilter beta offset */
- reg = MFC_READL(S5P_FIMV_E_H264_LF_BETA_OFFSET);
- reg &= ~(0x1F);
- reg |= (p_264->loop_filter_beta & 0x1F);
- MFC_WRITEL(reg, S5P_FIMV_E_H264_LF_BETA_OFFSET);
-
- /* rate control config. */
- reg = MFC_READL(S5P_FIMV_E_RC_CONFIG);
- /** frame QP */
- reg &= ~(0xFF);
- reg |= (p_264->rc_frame_qp & 0xFF);
- reg &= ~(0x1 << 11);
- if (!p->rc_frame && !p->rc_mb && p->dynamic_qp)
- reg |= (0x1 << 11);
- MFC_WRITEL(reg, S5P_FIMV_E_RC_CONFIG);
-
- /* frame rate */
- /* Fix value for H.264, H.263 in the driver */
- p->rc_frame_delta = FRAME_DELTA_DEFAULT;
- reg = MFC_READL(S5P_FIMV_E_RC_FRAME_RATE);
- reg &= ~(0xFFFF << 16);
- reg |= (p->rc_framerate << 16);
- reg &= ~(0xFFFF);
- reg |= p->rc_frame_delta & 0xFFFF;
- MFC_WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE);
-
- /* max & min value of QP for I frame */
- reg = MFC_READL(S5P_FIMV_E_RC_QP_BOUND);
- /** max I frame QP */
- reg &= ~(0xFF << 8);
- reg |= ((p_264->rc_max_qp & 0xFF) << 8);
- /** min I frame QP */
- reg &= ~(0xFF);
- reg |= p_264->rc_min_qp & 0xFF;
- MFC_WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND);
-
- /* max & min value of QP for P/B frame */
- reg = MFC_READL(S5P_FIMV_E_RC_QP_BOUND_PB);
- /** max B frame QP */
- reg &= ~(0xFF << 24);
- reg |= ((p_264->rc_max_qp_b & 0xFF) << 24);
- /** min B frame QP */
- reg &= ~(0xFF << 16);
- reg |= ((p_264->rc_min_qp_b & 0xFF) << 16);
- /** max P frame QP */
- reg &= ~(0xFF << 8);
- reg |= ((p_264->rc_max_qp_p & 0xFF) << 8);
- /** min P frame QP */
- reg &= ~(0xFF);
- reg |= p_264->rc_min_qp_p & 0xFF;
- MFC_WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND_PB);
-
- reg = MFC_READL(S5P_FIMV_E_FIXED_PICTURE_QP);
- reg &= ~(0xFF << 24);
- reg |= ((p->config_qp & 0xFF) << 24);
- reg &= ~(0xFF << 16);
- reg |= ((p_264->rc_b_frame_qp & 0xFF) << 16);
- reg &= ~(0xFF << 8);
- reg |= ((p_264->rc_p_frame_qp & 0xFF) << 8);
- reg &= ~(0xFF);
- reg |= (p_264->rc_frame_qp & 0xFF);
- MFC_WRITEL(reg, S5P_FIMV_E_FIXED_PICTURE_QP);
-
- MFC_WRITEL(0x0, S5P_FIMV_E_ASPECT_RATIO);
- MFC_WRITEL(0x0, S5P_FIMV_E_EXTENDED_SAR);
- if (p_264->ar_vui) {
- /* aspect ration IDC */
- reg = 0;
- reg &= ~(0xff);
- reg |= p_264->ar_vui_idc;
- MFC_WRITEL(reg, S5P_FIMV_E_ASPECT_RATIO);
- if (p_264->ar_vui_idc == 0xFF) {
- /* sample AR info. */
- reg = 0;
- reg &= ~(0xffffffff);
- reg |= p_264->ext_sar_width << 16;
- reg |= p_264->ext_sar_height;
- MFC_WRITEL(reg, S5P_FIMV_E_EXTENDED_SAR);
- }
- }
- /* intra picture period for H.264 open GOP, value */
- reg = MFC_READL(S5P_FIMV_E_H264_REFRESH_PERIOD);
- reg &= ~(0xFFFF);
- if (p_264->open_gop)
- reg |= (p_264->open_gop_size & 0xFFFF);
- MFC_WRITEL(reg, S5P_FIMV_E_H264_REFRESH_PERIOD);
-
- /* Temporal SVC */
- mfc_set_temporal_svc_h264(ctx, p_264);
-
- /* set frame pack sei generation */
- if (p_264->sei_gen_enable) {
- /* frame packing enable */
- reg = MFC_READL(S5P_FIMV_E_H264_OPTIONS);
- reg |= (1 << 25);
- MFC_WRITEL(reg, S5P_FIMV_E_H264_OPTIONS);
-
- /* set current frame0 flag & arrangement type */
- reg = 0;
- /** current frame0 flag */
- reg |= ((p_264->sei_fp_curr_frame_0 & 0x1) << 2);
- /** arrangement type */
- reg |= (p_264->sei_fp_arrangement_type - 3) & 0x3;
- MFC_WRITEL(reg, S5P_FIMV_E_H264_FRAME_PACKING_SEI_INFO);
- }
-
- if (MFC_FEATURE_SUPPORT(dev, dev->pdata->color_aspect_enc) && p->check_color_range) {
- reg = MFC_READL(S5P_FIMV_E_VIDEO_SIGNAL_TYPE);
- /* VIDEO_SIGNAL_TYPE_FLAG */
- reg |= 0x1 << 31;
- /* COLOR_RANGE */
- reg &= ~(0x1 << 25);
- reg |= p->color_range << 25;
- if ((p->colour_primaries != 0) && (p->transfer_characteristics != 0) &&
- (p->matrix_coefficients != 3)) {
- /* COLOUR_DESCRIPTION_PRESENT_FLAG */
- reg |= 0x1 << 24;
- /* COLOUR_PRIMARIES */
- reg &= ~(0xFF << 16);
- reg |= p->colour_primaries << 16;
- /* TRANSFER_CHARACTERISTICS */
- reg &= ~(0xFF << 8);
- reg |= p->transfer_characteristics << 8;
- /* MATRIX_COEFFICIENTS */
- reg &= ~(0xFF);
- reg |= p->matrix_coefficients;
- } else {
- reg &= ~(0x1 << 24);
- }
- MFC_WRITEL(reg, S5P_FIMV_E_VIDEO_SIGNAL_TYPE);
- mfc_debug(2, "[HDR] H264 ENC Color aspect: range(%s), pri(%d), trans(%d), mat(%d)\n",
- p->color_range ? "Full" : "Limited", p->colour_primaries,
- p->transfer_characteristics, p->matrix_coefficients);
- } else {
- MFC_WRITEL(0, S5P_FIMV_E_VIDEO_SIGNAL_TYPE);
- }
-
- mfc_set_fmo_slice_map_h264(ctx, p_264);
-
- mfc_debug_leave();
-}
-
-void s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_enc *enc = ctx->enc_priv;
- struct s5p_mfc_enc_params *p = &enc->params;
- struct s5p_mfc_mpeg4_enc_params *p_mpeg4 = &p->codec.mpeg4;
- unsigned int reg = 0;
-
- mfc_debug_enter();
-
- mfc_set_enc_params(ctx);
-
- /* set gop_size with I_FRM_CTRL mode */
- mfc_set_gop_size(ctx, 1);
-
- /* profile & level */
- reg = 0;
- /** level */
- reg &= ~(0xFF << 8);
- reg |= (p_mpeg4->level << 8);
- /** profile - 0 ~ 1 */
- reg &= ~(0x3F);
- reg |= p_mpeg4->profile;
- MFC_WRITEL(reg, S5P_FIMV_E_PICTURE_PROFILE);
-
- /* quarter_pixel */
- /* MFC_WRITEL(p_mpeg4->quarter_pixel, S5P_FIMV_ENC_MPEG4_QUART_PXL); */
-
- /* qp */
- reg = MFC_READL(S5P_FIMV_E_FIXED_PICTURE_QP);
- reg &= ~(0xFF << 24);
- reg |= ((p->config_qp & 0xFF) << 24);
- reg &= ~(0xFF << 16);
- reg |= ((p_mpeg4->rc_b_frame_qp & 0xFF) << 16);
- reg &= ~(0xFF << 8);
- reg |= ((p_mpeg4->rc_p_frame_qp & 0xFF) << 8);
- reg &= ~(0xFF);
- reg |= (p_mpeg4->rc_frame_qp & 0xFF);
- MFC_WRITEL(reg, S5P_FIMV_E_FIXED_PICTURE_QP);
-
- /* frame rate */
- p->rc_frame_delta = p_mpeg4->vop_frm_delta;
- reg = MFC_READL(S5P_FIMV_E_RC_FRAME_RATE);
- reg &= ~(0xFFFF << 16);
- reg |= (p_mpeg4->vop_time_res << 16);
- reg &= ~(0xFFFF);
- reg |= (p_mpeg4->vop_frm_delta & 0xFFFF);
- MFC_WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE);
-
- /* rate control config. */
- reg = MFC_READL(S5P_FIMV_E_RC_CONFIG);
- /** frame QP */
- reg &= ~(0xFF);
- reg |= (p_mpeg4->rc_frame_qp & 0xFF);
- MFC_WRITEL(reg, S5P_FIMV_E_RC_CONFIG);
-
- /* max & min value of QP for I frame */
- reg = MFC_READL(S5P_FIMV_E_RC_QP_BOUND);
- /** max I frame QP */
- reg &= ~(0xFF << 8);
- reg |= ((p_mpeg4->rc_max_qp & 0xFF) << 8);
- /** min I frame QP */
- reg &= ~(0xFF);
- reg |= (p_mpeg4->rc_min_qp & 0xFF);
- MFC_WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND);
-
- /* max & min value of QP for P/B frame */
- reg = MFC_READL(S5P_FIMV_E_RC_QP_BOUND_PB);
- /** max B frame QP */
- reg &= ~(0xFF << 24);
- reg |= ((p_mpeg4->rc_max_qp_b & 0xFF) << 24);
- /** min B frame QP */
- reg &= ~(0xFF << 16);
- reg |= ((p_mpeg4->rc_min_qp_b & 0xFF) << 16);
- /** max P frame QP */
- reg &= ~(0xFF << 8);
- reg |= ((p_mpeg4->rc_max_qp_p & 0xFF) << 8);
- /** min P frame QP */
- reg &= ~(0xFF);
- reg |= p_mpeg4->rc_min_qp_p & 0xFF;
- MFC_WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND_PB);
-
- /* initialize for '0' only setting*/
- MFC_WRITEL(0x0, S5P_FIMV_E_MPEG4_OPTIONS); /* SEQ_start only */
- MFC_WRITEL(0x0, S5P_FIMV_E_MPEG4_HEC_PERIOD); /* SEQ_start only */
-
- mfc_debug_leave();
-}
-
-void s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_enc *enc = ctx->enc_priv;
- struct s5p_mfc_enc_params *p = &enc->params;
- struct s5p_mfc_mpeg4_enc_params *p_mpeg4 = &p->codec.mpeg4;
- unsigned int reg = 0;
-
- mfc_debug_enter();
-
- mfc_set_enc_params(ctx);
-
- /* set gop_size with I_FRM_CTRL mode */
- mfc_set_gop_size(ctx, 1);
-
- /* profile & level: supports only baseline profile Level 70 */
-
- /* qp */
- reg = MFC_READL(S5P_FIMV_E_FIXED_PICTURE_QP);
- reg &= ~(0xFF << 24);
- reg |= ((p->config_qp & 0xFF) << 24);
- reg &= ~(0xFF << 8);
- reg |= ((p_mpeg4->rc_p_frame_qp & 0xFF) << 8);
- reg &= ~(0xFF);
- reg |= (p_mpeg4->rc_frame_qp & 0xFF);
- MFC_WRITEL(reg, S5P_FIMV_E_FIXED_PICTURE_QP);
-
- /* frame rate */
- /* Fix value for H.264, H.263 in the driver */
- p->rc_frame_delta = FRAME_DELTA_DEFAULT;
- reg = MFC_READL(S5P_FIMV_E_RC_FRAME_RATE);
- reg &= ~(0xFFFF << 16);
- reg |= (p->rc_framerate << 16);
- reg &= ~(0xFFFF);
- reg |= (p->rc_frame_delta & 0xFFFF);
- MFC_WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE);
-
- /* rate control config. */
- reg = MFC_READL(S5P_FIMV_E_RC_CONFIG);
- /** frame QP */
- reg &= ~(0xFF);
- reg |= (p_mpeg4->rc_frame_qp & 0xFF);
- MFC_WRITEL(reg, S5P_FIMV_E_RC_CONFIG);
-
- /* max & min value of QP for I frame */
- reg = MFC_READL(S5P_FIMV_E_RC_QP_BOUND);
- /** max I frame QP */
- reg &= ~(0xFF << 8);
- reg |= ((p_mpeg4->rc_max_qp & 0xFF) << 8);
- /** min I frame QP */
- reg &= ~(0xFF);
- reg |= (p_mpeg4->rc_min_qp & 0xFF);
- MFC_WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND);
-
- /* max & min value of QP for P/B frame */
- reg = MFC_READL(S5P_FIMV_E_RC_QP_BOUND_PB);
- /** max P frame QP */
- reg &= ~(0xFF << 8);
- reg |= ((p_mpeg4->rc_max_qp_p & 0xFF) << 8);
- /** min P frame QP */
- reg &= ~(0xFF);
- reg |= p_mpeg4->rc_min_qp_p & 0xFF;
- MFC_WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND_PB);
-
- mfc_debug_leave();
-}
-
-void s5p_mfc_set_enc_params_vp8(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_enc *enc = ctx->enc_priv;
- struct s5p_mfc_enc_params *p = &enc->params;
- struct s5p_mfc_vp8_enc_params *p_vp8 = &p->codec.vp8;
- unsigned int reg = 0;
- int i;
-
- mfc_debug_enter();
-
- mfc_set_enc_params(ctx);
-
- if (p_vp8->num_hier_layer & 0x3) {
- /* set gop_size without i_frm_ctrl mode */
- mfc_set_gop_size(ctx, 0);
- } else {
- /* set gop_size with i_frm_ctrl mode */
- mfc_set_gop_size(ctx, 1);
- }
-
- /* profile*/
- reg = 0;
- reg |= (p_vp8->vp8_version) ;
- MFC_WRITEL(reg, S5P_FIMV_E_PICTURE_PROFILE);
-
- reg = MFC_READL(S5P_FIMV_E_VP8_OPTION);
- /* if num_refs_for_p is 2, the performance falls by half */
- reg &= ~(0x1);
- reg |= (p->num_refs_for_p - 1) & 0x1;
- /* vp8 partition is possible as below value: 1/2/4/8 */
- if (p_vp8->vp8_numberofpartitions & 0x1) {
- if (p_vp8->vp8_numberofpartitions > 1)
- mfc_err_ctx("partition should be even num (%d)\n",
- p_vp8->vp8_numberofpartitions);
- p_vp8->vp8_numberofpartitions = (p_vp8->vp8_numberofpartitions & ~0x1);
- }
- reg &= ~(0xF << 3);
- reg |= (p_vp8->vp8_numberofpartitions & 0xF) << 3;
- reg &= ~(0x1 << 10);
- reg |= (p_vp8->intra_4x4mode_disable & 0x1) << 10;
- /* Temporal SVC - hier qp enable */
- reg &= ~(0x1 << 11);
- reg |= (p_vp8->hier_qp_enable & 0x1) << 11;
- /* Disable IVF header */
- reg &= ~(0x1 << 12);
- reg |= ((p->ivf_header_disable & 0x1) << 12);
- MFC_WRITEL(reg, S5P_FIMV_E_VP8_OPTION);
-
- reg = MFC_READL(S5P_FIMV_E_VP8_GOLDEN_FRAME_OPTION);
- reg &= ~(0x1);
- reg |= (p_vp8->vp8_goldenframesel & 0x1);
- reg &= ~(0xFFFF << 1);
- reg |= (p_vp8->vp8_gfrefreshperiod & 0xFFFF) << 1;
- MFC_WRITEL(reg, S5P_FIMV_E_VP8_GOLDEN_FRAME_OPTION);
-
- /* Temporal SVC - layer number */
- reg = MFC_READL(S5P_FIMV_E_NUM_T_LAYER);
- reg &= ~(0x7);
- reg |= p_vp8->num_hier_layer & 0x3;
- reg &= ~(0x7 << 4);
- reg |= 0x3 << 4;
- reg &= ~(0x1 << 8);
- reg |= (p->hier_bitrate_ctrl & 0x1) << 8;
- MFC_WRITEL(reg, S5P_FIMV_E_NUM_T_LAYER);
- mfc_debug(3, "[HIERARCHICAL] hier_qp_enable %d, num_hier_layer %d, NUM_T_LAYER 0x%x\n",
- p_vp8->hier_qp_enable, p_vp8->num_hier_layer, reg);
-
- /* QP & Bitrate for each layer */
- for (i = 0; i < 3; i++) {
- MFC_WRITEL(p_vp8->hier_qp_layer[i],
- S5P_FIMV_E_HIERARCHICAL_QP_LAYER0 + i * 4);
- /* If hier_bitrate_ctrl is set to 1, this is meaningless */
- MFC_WRITEL(p_vp8->hier_bit_layer[i],
- S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER0 + i * 4);
- mfc_debug(3, "[HIERARCHICAL] layer[%d] QP: %#x, bitrate: %#x(FW ctrl: %d)\n",
- i, p_vp8->hier_qp_layer[i],
- p_vp8->hier_bit_layer[i], p->hier_bitrate_ctrl);
- }
-
- reg = 0;
- reg |= (p_vp8->vp8_filtersharpness & 0x7);
- reg |= (p_vp8->vp8_filterlevel & 0x3f) << 8;
- MFC_WRITEL(reg, S5P_FIMV_E_VP8_FILTER_OPTION);
-
- /* qp */
- reg = MFC_READL(S5P_FIMV_E_FIXED_PICTURE_QP);
- reg &= ~(0xFF << 24);
- reg |= ((p->config_qp & 0xFF) << 24);
- reg &= ~(0xFF << 8);
- reg |= ((p_vp8->rc_p_frame_qp & 0xFF) << 8);
- reg &= ~(0xFF);
- reg |= (p_vp8->rc_frame_qp & 0xFF);
- MFC_WRITEL(reg, S5P_FIMV_E_FIXED_PICTURE_QP);
-
- /* frame rate */
- p->rc_frame_delta = FRAME_DELTA_DEFAULT;
- reg = MFC_READL(S5P_FIMV_E_RC_FRAME_RATE);
- reg &= ~(0xFFFF << 16);
- reg |= (p->rc_framerate << 16);
- reg &= ~(0xFFFF);
- reg |= (p->rc_frame_delta & 0xFFFF);
- MFC_WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE);
-
- /* rate control config. */
- reg = MFC_READL(S5P_FIMV_E_RC_CONFIG);
- /** frame QP */
- reg &= ~(0xFF);
- reg |= (p_vp8->rc_frame_qp & 0xFF);
- MFC_WRITEL(reg, S5P_FIMV_E_RC_CONFIG);
-
- /* max & min value of QP for I frame */
- reg = MFC_READL(S5P_FIMV_E_RC_QP_BOUND);
- /** max I frame QP */
- reg &= ~(0xFF << 8);
- reg |= ((p_vp8->rc_max_qp & 0xFF) << 8);
- /** min I frame QP */
- reg &= ~(0xFF);
- reg |= (p_vp8->rc_min_qp & 0xFF);
- MFC_WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND);
-
- /* max & min value of QP for P/B frame */
- reg = MFC_READL(S5P_FIMV_E_RC_QP_BOUND_PB);
- /** max P frame QP */
- reg &= ~(0xFF << 8);
- reg |= ((p_vp8->rc_max_qp_p & 0xFF) << 8);
- /** min P frame QP */
- reg &= ~(0xFF);
- reg |= p_vp8->rc_min_qp_p & 0xFF;
- MFC_WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND_PB);
-
- mfc_debug_leave();
-}
-
-void s5p_mfc_set_enc_params_vp9(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_enc *enc = ctx->enc_priv;
- struct s5p_mfc_enc_params *p = &enc->params;
- struct s5p_mfc_vp9_enc_params *p_vp9 = &p->codec.vp9;
- unsigned int reg = 0;
- int i;
-
- mfc_debug_enter();
-
- mfc_set_enc_params(ctx);
-
- if (p_vp9->num_hier_layer & 0x3) {
- /* set gop_size without i_frm_ctrl mode */
- mfc_set_gop_size(ctx, 0);
- } else {
- /* set gop_size with i_frm_ctrl mode */
- mfc_set_gop_size(ctx, 1);
- }
-
- /* profile*/
- reg = 0;
- reg |= p_vp9->vp9_version;
- /* bit depth minus8 */
- if (ctx->is_10bit) {
- reg &= ~(0x3F << 17);
- reg |= (0x2 << 17);
- reg |= (0x2 << 20);
- }
- MFC_WRITEL(reg, S5P_FIMV_E_PICTURE_PROFILE);
-
- /* for only information about wrong setting */
- if (ctx->is_422) {
- if ((p_vp9->vp9_version != S5P_FIMV_E_PROFILE_VP9_PROFILE1) &&
- (p_vp9->vp9_version != S5P_FIMV_E_PROFILE_VP9_PROFILE3)) {
- mfc_err_ctx("4:2:2 format is not matched with profile(%d)\n",
- p_vp9->vp9_version);
- }
- }
- if (ctx->is_10bit) {
- if ((p_vp9->vp9_version != S5P_FIMV_E_PROFILE_VP9_PROFILE2) &&
- (p_vp9->vp9_version != S5P_FIMV_E_PROFILE_VP9_PROFILE3)) {
- mfc_err_ctx("[10BIT] format is not matched with profile(%d)\n",
- p_vp9->vp9_version);
- }
- }
-
- reg = MFC_READL(S5P_FIMV_E_VP9_OPTION);
- /* if num_refs_for_p is 2, the performance falls by half */
- reg &= ~(0x1);
- reg |= (p->num_refs_for_p - 1) & 0x1;
- reg &= ~(0x1 << 1);
- reg |= (p_vp9->intra_pu_split_disable & 0x1) << 1;
- reg &= ~(0x1 << 3);
- reg |= (p_vp9->max_partition_depth & 0x1) << 3;
- /* Temporal SVC - hier qp enable */
- reg &= ~(0x1 << 11);
- reg |= ((p_vp9->hier_qp_enable & 0x1) << 11);
- /* Disable IVF header */
- reg &= ~(0x1 << 12);
- reg |= ((p->ivf_header_disable & 0x1) << 12);
- MFC_WRITEL(reg, S5P_FIMV_E_VP9_OPTION);
-
- reg = MFC_READL(S5P_FIMV_E_VP9_GOLDEN_FRAME_OPTION);
- reg &= ~(0x1);
- reg |= (p_vp9->vp9_goldenframesel & 0x1);
- reg &= ~(0xFFFF << 1);
- reg |= (p_vp9->vp9_gfrefreshperiod & 0xFFFF) << 1;
- MFC_WRITEL(reg, S5P_FIMV_E_VP9_GOLDEN_FRAME_OPTION);
-
- /* Temporal SVC - layer number */
- reg = MFC_READL(S5P_FIMV_E_NUM_T_LAYER);
- reg &= ~(0x7);
- reg |= p_vp9->num_hier_layer & 0x3;
- reg &= ~(0x7 << 4);
- reg |= 0x3 << 4;
- reg &= ~(0x1 << 8);
- reg |= (p->hier_bitrate_ctrl & 0x1) << 8;
- MFC_WRITEL(reg, S5P_FIMV_E_NUM_T_LAYER);
- mfc_debug(3, "[HIERARCHICAL] hier_qp_enable %d, num_hier_layer %d, NUM_T_LAYER 0x%x\n",
- p_vp9->hier_qp_enable, p_vp9->num_hier_layer, reg);
-
- /* QP & Bitrate for each layer */
- for (i = 0; i < 3; i++) {
- MFC_WRITEL(p_vp9->hier_qp_layer[i],
- S5P_FIMV_E_HIERARCHICAL_QP_LAYER0 + i * 4);
- /* If hier_bitrate_ctrl is set to 1, this is meaningless */
- MFC_WRITEL(p_vp9->hier_bit_layer[i],
- S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER0 + i * 4);
- mfc_debug(3, "[HIERARCHICAL] layer[%d] QP: %#x, bitrate: %#x (FW ctrl: %d)\n",
- i, p_vp9->hier_qp_layer[i],
- p_vp9->hier_bit_layer[i], p->hier_bitrate_ctrl);
- }
-
- /* qp */
- reg = MFC_READL(S5P_FIMV_E_FIXED_PICTURE_QP);
- reg &= ~(0xFF << 24);
- reg |= ((p->config_qp & 0xFF) << 24);
- reg &= ~(0xFF << 8);
- reg |= ((p_vp9->rc_p_frame_qp & 0xFF) << 8);
- reg &= ~(0xFF);
- reg |= (p_vp9->rc_frame_qp & 0xFF);
- MFC_WRITEL(reg, S5P_FIMV_E_FIXED_PICTURE_QP);
-
- /* frame rate */
- p->rc_frame_delta = FRAME_DELTA_DEFAULT;
- reg = MFC_READL(S5P_FIMV_E_RC_FRAME_RATE);
- reg &= ~(0xFFFF << 16);
- reg |= (p->rc_framerate << 16);
- reg &= ~(0xFFFF);
- reg |= (p->rc_frame_delta & 0xFFFF);
- MFC_WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE);
-
- /* rate control config. */
- reg = MFC_READL(S5P_FIMV_E_RC_CONFIG);
- /** frame QP */
- reg &= ~(0xFF);
- reg |= (p_vp9->rc_frame_qp & 0xFF);
- MFC_WRITEL(reg, S5P_FIMV_E_RC_CONFIG);
-
- /* max & min value of QP for I frame */
- reg = MFC_READL(S5P_FIMV_E_RC_QP_BOUND);
- /** max I frame QP */
- reg &= ~(0xFF << 8);
- reg |= ((p_vp9->rc_max_qp & 0xFF) << 8);
- /** min I frame QP */
- reg &= ~(0xFF);
- reg |= (p_vp9->rc_min_qp & 0xFF);
- MFC_WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND);
-
- /* max & min value of QP for P/B frame */
- reg = MFC_READL(S5P_FIMV_E_RC_QP_BOUND_PB);
- /** max P frame QP */
- reg &= ~(0xFF << 8);
- reg |= ((p_vp9->rc_max_qp_p & 0xFF) << 8);
- /** min P frame QP */
- reg &= ~(0xFF);
- reg |= p_vp9->rc_min_qp_p & 0xFF;
- MFC_WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND_PB);
-
- if (MFC_FEATURE_SUPPORT(dev, dev->pdata->color_aspect_enc) && p->check_color_range) {
- reg = MFC_READL(S5P_FIMV_E_VIDEO_SIGNAL_TYPE);
- /* VIDEO_SIGNAL_TYPE_FLAG */
- reg |= 0x1 << 31;
- /* COLOR_SPACE: VP9 uses colour_primaries interface for color space */
- reg &= ~(0x1F << 26);
- reg |= p->colour_primaries << 26;
- /* COLOR_RANGE */
- reg &= ~(0x1 << 25);
- reg |= p->color_range << 25;
- MFC_WRITEL(reg, S5P_FIMV_E_VIDEO_SIGNAL_TYPE);
- mfc_debug(2, "[HDR] VP9 ENC Color aspect: range(%s), space(%d)\n",
- p->color_range ? "Full" : "Limited", p->colour_primaries);
- } else {
- MFC_WRITEL(0, S5P_FIMV_E_VIDEO_SIGNAL_TYPE);
- }
-
- mfc_debug_leave();
-}
-
-void s5p_mfc_set_enc_params_hevc(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_enc *enc = ctx->enc_priv;
- struct s5p_mfc_enc_params *p = &enc->params;
- struct s5p_mfc_hevc_enc_params *p_hevc = &p->codec.hevc;
- unsigned int reg = 0;
- int i;
-
- mfc_debug_enter();
-
- mfc_set_enc_params(ctx);
-
- if (p_hevc->num_hier_layer & 0x7) {
- /* set gop_size without i_frm_ctrl mode */
- mfc_set_gop_size(ctx, 0);
- } else {
- /* set gop_size with i_frm_ctrl mode */
- mfc_set_gop_size(ctx, 1);
- }
-
- /* UHD encoding case */
- if (IS_UHD_RES(ctx)) {
- p_hevc->level = 51;
- p_hevc->tier_flag = 0;
- /* this tier_flag can be changed */
- }
-
- /* tier_flag & level & profile */
- reg = 0;
- /* profile */
- reg |= p_hevc->profile & 0xf;
- /* level */
- reg &= ~(0xFF << 8);
- reg |= (p_hevc->level << 8);
- /* tier_flag - 0 ~ 1 */
- reg |= (p_hevc->tier_flag << 16);
- /* bit depth minus8 */
- if (ctx->is_10bit) {
- reg &= ~(0x3F << 17);
- reg |= (0x2 << 17);
- reg |= (0x2 << 20);
- }
- MFC_WRITEL(reg, S5P_FIMV_E_PICTURE_PROFILE);
-
- /* for only information about wrong setting */
- if (ctx->is_422) {
- if ((p_hevc->profile != S5P_FIMV_E_PROFILE_HEVC_MAIN_422_10_INTRA) &&
- (p_hevc->profile != S5P_FIMV_E_PROFILE_HEVC_MAIN_422_10)) {
- mfc_err_ctx("4:2:2 format is not matched with profile(%d)\n",
- p_hevc->profile);
- }
- }
- if (ctx->is_10bit) {
- if ((p_hevc->profile != S5P_FIMV_E_PROFILE_HEVC_MAIN_422_10_INTRA) &&
- (p_hevc->profile != S5P_FIMV_E_PROFILE_HEVC_MAIN_10) &&
- (p_hevc->profile != S5P_FIMV_E_PROFILE_HEVC_MAIN_422_10)) {
- mfc_err_ctx("[10BIT] format is not matched with profile(%d)\n",
- p_hevc->profile);
- }
- }
-
- /* max partition depth */
- reg = MFC_READL(S5P_FIMV_E_HEVC_OPTIONS);
- reg &= ~(0x3);
- reg |= (p_hevc->max_partition_depth & 0x1);
- /* if num_refs_for_p is 2, the performance falls by half */
- reg &= ~(0x1 << 2);
- reg |= (p->num_refs_for_p - 1) << 2;
- reg &= ~(0x3 << 3);
- reg |= (p_hevc->refreshtype & 0x3) << 3;
- reg &= ~(0x1 << 5);
- reg |= (p_hevc->const_intra_period_enable & 0x1) << 5;
- reg &= ~(0x1 << 6);
- reg |= (p_hevc->lossless_cu_enable & 0x1) << 6;
- reg &= ~(0x1 << 7);
- reg |= (p_hevc->wavefront_enable & 0x1) << 7;
- reg &= ~(0x1 << 8);
- reg |= (p_hevc->loopfilter_disable & 0x1) << 8;
- reg &= ~(0x1 << 9);
- reg |= (p_hevc->loopfilter_across & 0x1) << 9;
- reg &= ~(0x1 << 10);
- reg |= (p_hevc->enable_ltr & 0x1) << 10;
- reg &= ~(0x1 << 11);
- reg |= (p_hevc->hier_qp_enable & 0x1) << 11;
- reg &= ~(0x1 << 13);
- reg |= (p_hevc->general_pb_enable & 0x1) << 13;
- reg &= ~(0x1 << 14);
- reg |= (p_hevc->temporal_id_enable & 0x1) << 14;
- reg &= ~(0x1 << 15);
- reg |= (p_hevc->strong_intra_smooth & 0x1) << 15;
- reg &= ~(0x1 << 16);
- reg |= (p_hevc->intra_pu_split_disable & 0x1) << 16;
- reg &= ~(0x1 << 17);
- reg |= (p_hevc->tmv_prediction_disable & 0x1) << 17;
- reg &= ~(0x7 << 18);
- reg |= (p_hevc->max_num_merge_mv & 0x7) << 18;
- reg &= ~(0x1 << 23);
- reg |= (p_hevc->encoding_nostartcode_enable & 0x1) << 23;
- reg &= ~(0x1 << 26);
- reg |= (p_hevc->prepend_sps_pps_to_idr & 0x1) << 26;
- /* enable sps pps control in OTF scenario */
- if (ctx->otf_handle) {
- reg |= (0x1 << 26);
- mfc_debug(2, "[OTF] SPS_PPS_CONTROL enabled\n");
- }
- /* Weighted Prediction enable */
- reg &= ~(0x1 << 28);
- reg |= ((p->weighted_enable & 0x1) << 28);
- /* 30bit is 32x32 transform. If it is enabled, the performance falls by half */
- reg &= ~(0x1 << 30);
- MFC_WRITEL(reg, S5P_FIMV_E_HEVC_OPTIONS);
- /* refresh period */
- reg = MFC_READL(S5P_FIMV_E_HEVC_REFRESH_PERIOD);
- reg &= ~(0xFFFF);
- reg |= (p_hevc->refreshperiod & 0xFFFF);
- MFC_WRITEL(reg, S5P_FIMV_E_HEVC_REFRESH_PERIOD);
- /* loop filter setting */
- MFC_WRITEL(0, S5P_FIMV_E_HEVC_LF_BETA_OFFSET_DIV2);
- MFC_WRITEL(0, S5P_FIMV_E_HEVC_LF_TC_OFFSET_DIV2);
- if (!p_hevc->loopfilter_disable) {
- MFC_WRITEL(p_hevc->lf_beta_offset_div2, S5P_FIMV_E_HEVC_LF_BETA_OFFSET_DIV2);
- MFC_WRITEL(p_hevc->lf_tc_offset_div2, S5P_FIMV_E_HEVC_LF_TC_OFFSET_DIV2);
- }
- /* long term reference */
- if (p_hevc->enable_ltr) {
- reg = 0;
- reg |= (p_hevc->store_ref & 0x3);
- reg &= ~(0x3 << 2);
- reg |= (p_hevc->user_ref & 0x3) << 2;
- MFC_WRITEL(reg, S5P_FIMV_E_HEVC_NAL_CONTROL);
- }
-
- /* Temporal SVC - qp type, layer number */
- reg = MFC_READL(S5P_FIMV_E_NUM_T_LAYER);
- reg &= ~(0x1 << 3);
- reg |= (p_hevc->hier_qp_type & 0x1) << 3;
- reg &= ~(0x7);
- reg |= p_hevc->num_hier_layer & 0x7;
- reg &= ~(0x7 << 4);
- if (p_hevc->hier_ref_type) {
- reg |= 0x1 << 7;
- reg |= (p->num_hier_max_layer & 0x7) << 4;
- } else {
- reg &= ~(0x1 << 7);
- reg |= 0x7 << 4;
- }
- reg &= ~(0x1 << 8);
- reg |= (p->hier_bitrate_ctrl & 0x1) << 8;
- MFC_WRITEL(reg, S5P_FIMV_E_NUM_T_LAYER);
- mfc_debug(3, "[HIERARCHICAL] hier_qp_enable %d, enable_ltr %d, "
- "num_hier_layer %d, max_layer %d, hier_ref_type %d, NUM_T_LAYER 0x%x\n",
- p_hevc->hier_qp_enable, p_hevc->enable_ltr, p_hevc->num_hier_layer,
- p->num_hier_max_layer, p_hevc->hier_ref_type, reg);
-
- /* QP & Bitrate for each layer */
- for (i = 0; i < 7; i++) {
- MFC_WRITEL(p_hevc->hier_qp_layer[i],
- S5P_FIMV_E_HIERARCHICAL_QP_LAYER0 + i * 4);
- MFC_WRITEL(p_hevc->hier_bit_layer[i],
- S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER0 + i * 4);
- mfc_debug(3, "[HIERARCHICAL] layer[%d] QP: %#x, bitrate: %d(FW ctrl: %d)\n",
- i, p_hevc->hier_qp_layer[i],
- p_hevc->hier_bit_layer[i], p->hier_bitrate_ctrl);
- }
-
- /* rate control config. */
- reg = MFC_READL(S5P_FIMV_E_RC_CONFIG);
- /** frame QP */
- reg &= ~(0xFF);
- reg |= (p_hevc->rc_frame_qp & 0xFF);
- MFC_WRITEL(reg, S5P_FIMV_E_RC_CONFIG);
-
- /* frame rate */
- p->rc_frame_delta = FRAME_DELTA_DEFAULT;
- reg = MFC_READL(S5P_FIMV_E_RC_FRAME_RATE);
- reg &= ~(0xFFFF << 16);
- reg |= (p->rc_framerate << 16);
- reg &= ~(0xFFFF);
- reg |= (p->rc_frame_delta & 0xFFFF);
- MFC_WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE);
-
- /* max & min value of QP for I frame */
- reg = MFC_READL(S5P_FIMV_E_RC_QP_BOUND);
- /** max I frame QP */
- reg &= ~(0xFF << 8);
- reg |= ((p_hevc->rc_max_qp & 0xFF) << 8);
- /** min I frame QP */
- reg &= ~(0xFF);
- reg |= (p_hevc->rc_min_qp & 0xFF);
- MFC_WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND);
-
- /* max & min value of QP for P/B frame */
- reg = MFC_READL(S5P_FIMV_E_RC_QP_BOUND_PB);
- /** max B frame QP */
- reg &= ~(0xFF << 24);
- reg |= ((p_hevc->rc_max_qp_b & 0xFF) << 24);
- /** min B frame QP */
- reg &= ~(0xFF << 16);
- reg |= ((p_hevc->rc_min_qp_b & 0xFF) << 16);
- /** max P frame QP */
- reg &= ~(0xFF << 8);
- reg |= ((p_hevc->rc_max_qp_p & 0xFF) << 8);
- /** min P frame QP */
- reg &= ~(0xFF);
- reg |= p_hevc->rc_min_qp_p & 0xFF;
- MFC_WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND_PB);
-
- reg = MFC_READL(S5P_FIMV_E_FIXED_PICTURE_QP);
- reg &= ~(0xFF << 24);
- reg |= ((p->config_qp & 0xFF) << 24);
- reg &= ~(0xFF << 16);
- reg |= ((p_hevc->rc_b_frame_qp & 0xFF) << 16);
- reg &= ~(0xFF << 8);
- reg |= ((p_hevc->rc_p_frame_qp & 0xFF) << 8);
- reg &= ~(0xFF);
- reg |= (p_hevc->rc_frame_qp & 0xFF);
- MFC_WRITEL(reg, S5P_FIMV_E_FIXED_PICTURE_QP);
-
- /* ROI enable: it must set on SEQ_START only for HEVC encoder */
- reg = MFC_READL(S5P_FIMV_E_RC_ROI_CTRL);
- reg &= ~(0x1);
- reg |= (p->roi_enable);
- MFC_WRITEL(reg, S5P_FIMV_E_RC_ROI_CTRL);
- mfc_debug(3, "[ROI] HEVC ROI enable\n");
-
- if (MFC_FEATURE_SUPPORT(dev, dev->pdata->color_aspect_enc) && p->check_color_range) {
- reg = MFC_READL(S5P_FIMV_E_VIDEO_SIGNAL_TYPE);
- /* VIDEO_SIGNAL_TYPE_FLAG */
- reg |= 0x1 << 31;
- /* COLOR_RANGE */
- reg &= ~(0x1 << 25);
- reg |= p->color_range << 25;
- if ((p->colour_primaries != 0) && (p->transfer_characteristics != 0) &&
- (p->matrix_coefficients != 3)) {
- /* COLOUR_DESCRIPTION_PRESENT_FLAG */
- reg |= 0x1 << 24;
- /* COLOUR_PRIMARIES */
- reg &= ~(0xFF << 16);
- reg |= p->colour_primaries << 16;
- /* TRANSFER_CHARACTERISTICS */
- reg &= ~(0xFF << 8);
- reg |= p->transfer_characteristics << 8;
- /* MATRIX_COEFFICIENTS */
- reg &= ~(0xFF);
- reg |= p->matrix_coefficients;
- } else {
- reg &= ~(0x1 << 24);
- }
- MFC_WRITEL(reg, S5P_FIMV_E_VIDEO_SIGNAL_TYPE);
- mfc_debug(2, "[HDR] HEVC ENC Color aspect: range(%s), pri(%d), trans(%d), mat(%d)\n",
- p->color_range ? "Full" : "Limited", p->colour_primaries,
- p->transfer_characteristics, p->matrix_coefficients);
- } else {
- MFC_WRITEL(0, S5P_FIMV_E_VIDEO_SIGNAL_TYPE);
- }
-
- if (MFC_FEATURE_SUPPORT(dev, dev->pdata->static_info_enc) &&
- p->static_info_enable && ctx->is_10bit) {
- reg = MFC_READL(S5P_FIMV_E_HEVC_OPTIONS_2);
- /* HDR_STATIC_INFO_ENABLE */
- reg |= p->static_info_enable;
- MFC_WRITEL(reg, S5P_FIMV_E_HEVC_OPTIONS_2);
- /* MAX_PIC_AVERAGE_LIGHT & MAX_CONTENT_LIGHT */
- reg = p->max_pic_average_light;
- reg |= (p->max_content_light << 16);
- MFC_WRITEL(reg, S5P_FIMV_E_CONTENT_LIGHT_LEVEL_INFO_SEI);
- /* MAX_DISPLAY_LUMINANCE */
- MFC_WRITEL(p->max_display_luminance, S5P_FIMV_E_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_0);
- /* MIN DISPLAY LUMINANCE */
- MFC_WRITEL(p->min_display_luminance, S5P_FIMV_E_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_1);
- /* WHITE_POINT */
- MFC_WRITEL(p->white_point, S5P_FIMV_E_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_2);
- /* DISPLAY PRIMARIES_0 */
- MFC_WRITEL(p->display_primaries_0, S5P_FIMV_E_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_3);
- /* DISPLAY PRIMARIES_1 */
- MFC_WRITEL(p->display_primaries_1, S5P_FIMV_E_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_4);
- /* DISPLAY PRIMARIES_2 */
- MFC_WRITEL(p->display_primaries_2, S5P_FIMV_E_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_5);
-
- mfc_debug(2, "[HDR] HEVC ENC static info: enable(%d), max_pic(0x%x), max_content(0x%x)\n",
- p->static_info_enable, p->max_pic_average_light, p->max_content_light);
- mfc_debug(2, "[HDR] max_disp(0x%x), min_disp(0x%x), white_point(0x%x)\n",
- p->max_display_luminance, p->min_display_luminance, p->white_point);
- mfc_debug(2, "[HDR] disp_pri_0(0x%x), disp_pri_1(0x%x), disp_pri_2(0x%x)\n",
- p->display_primaries_0, p->display_primaries_1, p->display_primaries_2);
- } else {
- reg = MFC_READL(S5P_FIMV_E_HEVC_OPTIONS_2);
- /* HDR_STATIC_INFO_ENABLE */
- reg &= ~(0x1);
- MFC_WRITEL(reg, S5P_FIMV_E_HEVC_OPTIONS_2);
- }
-
- mfc_debug_leave();
-}
-
-void s5p_mfc_set_enc_params_bpg(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_enc *enc = ctx->enc_priv;
- struct s5p_mfc_enc_params *p = &enc->params;
- struct s5p_mfc_bpg_enc_params *p_bpg = &p->codec.bpg;
- unsigned int reg = 0;
-
- mfc_set_enc_params(ctx);
-
- /* extension tag */
- reg = p_bpg->thumb_size + p_bpg->exif_size;
- MFC_WRITEL(reg, S5P_FIMV_E_BPG_EXTENSION_DATA_SIZE);
- mfc_debug(3, "main image extension size %d (thumbnail: %d, exif: %d)\n",
- reg, p_bpg->thumb_size, p_bpg->exif_size);
-
- /* profile & level */
- reg = 0;
- /** profile */
- reg &= ~(0xF);
- /* bit depth minus8 */
- if (ctx->is_10bit) {
- reg &= ~(0x3F << 17);
- reg |= (0x2 << 17);
- reg |= (0x2 << 20);
- /* fixed profile */
- if (ctx->is_422)
- reg |= 0x1;
- }
- MFC_WRITEL(reg, S5P_FIMV_E_PICTURE_PROFILE);
-}
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_enc_param.h
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __S5P_MFC_ENC_PARAM_H
-#define __S5P_MFC_ENC_PARAM_H __FILE__
-
-#include "s5p_mfc_common.h"
-
-void s5p_mfc_set_slice_mode(struct s5p_mfc_ctx *ctx);
-void s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx);
-void s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx);
-void s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx);
-void s5p_mfc_set_enc_params_vp8(struct s5p_mfc_ctx *ctx);
-void s5p_mfc_set_enc_params_vp9(struct s5p_mfc_ctx *ctx);
-void s5p_mfc_set_enc_params_hevc(struct s5p_mfc_ctx *ctx);
-void s5p_mfc_set_enc_params_bpg(struct s5p_mfc_ctx *ctx);
-
-#endif /* __S5P_MFC_ENC_PARAM_H */
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_enc_vb2_ops.c
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include "s5p_mfc_common.h"
-
-#include "s5p_mfc_hwlock.h"
-#include "s5p_mfc_nal_q.h"
-#include "s5p_mfc_opr.h"
-#include "s5p_mfc_sync.h"
-
-#include "s5p_mfc_qos.h"
-#include "s5p_mfc_queue.h"
-#include "s5p_mfc_utils.h"
-#include "s5p_mfc_buf.h"
-#include "s5p_mfc_mem.h"
-
-static int s5p_mfc_enc_queue_setup(struct vb2_queue *vq,
- unsigned int *buf_count, unsigned int *plane_count,
- unsigned int psize[], struct device *alloc_devs[])
-{
- struct s5p_mfc_dev *dev;
- struct s5p_mfc_ctx *ctx = vq->drv_priv;
- struct s5p_mfc_enc *enc = ctx->enc_priv;
- struct s5p_mfc_raw_info *raw;
- int i;
-
- mfc_debug_enter();
-
- dev = ctx->dev;
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
-
- if (ctx->state != MFCINST_GOT_INST &&
- vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- mfc_err_ctx("invalid state: %d\n", ctx->state);
- return -EINVAL;
- }
- if (ctx->state >= MFCINST_FINISHING &&
- vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- mfc_err_ctx("invalid state: %d\n", ctx->state);
- return -EINVAL;
- }
-
- if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- mfc_debug(4, "enc dst\n");
- if (ctx->dst_fmt)
- *plane_count = ctx->dst_fmt->mem_planes;
- else
- *plane_count = MFC_ENC_CAP_PLANE_COUNT;
-
- if (*buf_count < 1)
- *buf_count = 1;
- if (*buf_count > MFC_MAX_BUFFERS)
- *buf_count = MFC_MAX_BUFFERS;
-
- psize[0] = enc->dst_buf_size;
- alloc_devs[0] = dev->device;
- } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- mfc_debug(4, "enc src\n");
- raw = &ctx->raw_buf;
-
- if (ctx->src_fmt)
- *plane_count = ctx->src_fmt->mem_planes;
- else
- *plane_count = MFC_ENC_OUT_PLANE_COUNT;
-
- if (*buf_count < 1)
- *buf_count = 1;
- if (*buf_count > MFC_MAX_BUFFERS)
- *buf_count = MFC_MAX_BUFFERS;
-
- if (*plane_count == 1) {
- psize[0] = raw->total_plane_size;
- alloc_devs[0] = dev->device;
- } else {
- for (i = 0; i < *plane_count; i++) {
- psize[i] = raw->plane_size[i];
- alloc_devs[i] = dev->device;
- }
- }
- } else {
- mfc_err_ctx("invalid queue type: %d\n", vq->type);
- return -EINVAL;
- }
-
- mfc_debug(2, "buf_count: %d, plane_count: %d, type: %#x\n",
- *buf_count, *plane_count, vq->type);
- for (i = 0; i < *plane_count; i++)
- mfc_debug(2, "plane[%d] size: %d\n", i, psize[i]);
-
- mfc_debug_leave();
-
- return 0;
-}
-
-static void s5p_mfc_enc_unlock(struct vb2_queue *q)
-{
- struct s5p_mfc_ctx *ctx = q->drv_priv;
- struct s5p_mfc_dev *dev = ctx->dev;
-
- mutex_unlock(&dev->mfc_mutex);
-}
-
-static void s5p_mfc_enc_lock(struct vb2_queue *q)
-{
- struct s5p_mfc_ctx *ctx = q->drv_priv;
- struct s5p_mfc_dev *dev = ctx->dev;
-
- mutex_lock(&dev->mfc_mutex);
-}
-
-static int s5p_mfc_enc_buf_init(struct vb2_buffer *vb)
-{
- struct vb2_queue *vq = vb->vb2_queue;
- struct s5p_mfc_ctx *ctx = vq->drv_priv;
- int ret;
-
- mfc_debug_enter();
-
- if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- ret = s5p_mfc_check_vb_with_fmt(ctx->dst_fmt, vb);
- if (ret < 0)
- return ret;
-
- if (call_cop(ctx, init_buf_ctrls, ctx, MFC_CTRL_TYPE_DST,
- vb->index) < 0)
- mfc_err_ctx("failed in init_buf_ctrls\n");
-
- } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- ret = s5p_mfc_check_vb_with_fmt(ctx->src_fmt, vb);
- if (ret < 0)
- return ret;
-
- if (call_cop(ctx, init_buf_ctrls, ctx, MFC_CTRL_TYPE_SRC,
- vb->index) < 0)
- mfc_err_ctx("failed in init_buf_ctrls\n");
- } else {
- mfc_err_ctx("inavlid queue type: %d\n", vq->type);
- return -EINVAL;
- }
-
- mfc_debug_leave();
-
- return 0;
-}
-
-static int s5p_mfc_enc_buf_prepare(struct vb2_buffer *vb)
-{
- struct vb2_queue *vq = vb->vb2_queue;
- struct s5p_mfc_ctx *ctx = vq->drv_priv;
- struct s5p_mfc_enc *enc = ctx->enc_priv;
- struct s5p_mfc_raw_info *raw;
- unsigned int index = vb->index;
- struct s5p_mfc_buf *buf = vb_to_mfc_buf(vb);
- struct dma_buf *bufcon_dmabuf[MFC_MAX_PLANES];
- int i, mem_get_count = 0;
- size_t buf_size;
-
- mfc_debug_enter();
-
- if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- buf_size = vb2_plane_size(vb, 0);
- mfc_debug(2, "[STREAM] vb size: %lu, calc size: %u\n",
- buf_size, enc->dst_buf_size);
-
- if (buf_size < enc->dst_buf_size) {
- mfc_err_ctx("[STREAM] size(%d) is smaller than (%d)\n",
- buf_size, enc->dst_buf_size);
- return -EINVAL;
- }
-
- buf->addr[0][0] = s5p_mfc_mem_get_daddr_vb(vb, 0);
- } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- raw = &ctx->raw_buf;
- if (ctx->src_fmt->mem_planes == 1) {
- buf_size = vb2_plane_size(vb, 0);
- mfc_debug(2, "[FRAME] single plane vb size: %lu, calc size: %d\n",
- buf_size, raw->total_plane_size);
- if (buf_size < raw->total_plane_size) {
- mfc_err_ctx("[FRAME] single plane size(%d) is smaller than (%d)\n",
- buf_size, raw->total_plane_size);
- return -EINVAL;
- }
- } else {
- for (i = 0; i < ctx->src_fmt->mem_planes; i++) {
- buf_size = vb2_plane_size(vb, i);
- mfc_debug(2, "[FRAME] plane[%d] vb size: %lu, calc size: %d\n",
- i, buf_size, raw->plane_size[i]);
- if (buf_size < raw->plane_size[i]) {
- mfc_err_ctx("[FRAME] plane[%d] size(%d) is smaller than (%d)\n",
- i, buf_size, raw->plane_size[i]);
- return -EINVAL;
- }
- }
- }
-
- for (i = 0; i < ctx->src_fmt->mem_planes; i++) {
- bufcon_dmabuf[i] = dma_buf_get(vb->planes[i].m.fd);
- if (IS_ERR(bufcon_dmabuf[i])) {
- mfc_err_ctx("failed to get bufcon dmabuf\n");
- goto err_mem_put;
- }
-
- mem_get_count++;
- buf->num_bufs_in_batch = s5p_mfc_bufcon_get_buf_count(bufcon_dmabuf[i]);
- mfc_debug(3, "[BUFCON] num bufs in batch: %d\n", buf->num_bufs_in_batch);
- if (buf->num_bufs_in_batch == 0) {
- mfc_err_ctx("[BUFCON] bufs count couldn't be zero\n");
- goto err_mem_put;
- }
-
- if (buf->num_bufs_in_batch < 0)
- buf->num_bufs_in_batch = 0;
-
- if (!ctx->batch_mode && buf->num_bufs_in_batch > 0) {
- ctx->batch_mode = 1;
- mfc_debug(2, "[BUFCON] buffer batch mode enable\n");
- }
-
- if (buf->num_bufs_in_batch > 0) {
- if (s5p_mfc_bufcon_get_daddr(ctx, buf, bufcon_dmabuf[i], i)) {
- mfc_err_ctx("[BUFCON] failed to get daddr[%d] in buffer container\n", i);
- goto err_mem_put;
- }
-
- ctx->framerate = buf->num_valid_bufs * ENC_DEFAULT_CAM_CAPTURE_FPS;
- mfc_debug(3, "[BUFCON] framerate: %ld\n", ctx->framerate);
-
- dma_buf_put(bufcon_dmabuf[i]);
- } else {
- dma_addr_t start_raw;
-
- dma_buf_put(bufcon_dmabuf[i]);
- start_raw = s5p_mfc_mem_get_daddr_vb(vb, 0);
- if (start_raw == 0) {
- mfc_err_ctx("Plane mem not allocated\n");
- return -ENOMEM;
- }
- if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12N) {
- buf->addr[0][0] = start_raw;
- buf->addr[0][1] = NV12N_CBCR_BASE(start_raw,
- ctx->img_width,
- ctx->img_height);
- } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420N) {
- buf->addr[0][0] = start_raw;
- buf->addr[0][1] = YUV420N_CB_BASE(start_raw,
- ctx->img_width,
- ctx->img_height);
- buf->addr[0][2] = YUV420N_CR_BASE(start_raw,
- ctx->img_width,
- ctx->img_height);
- } else {
- buf->addr[0][i] = s5p_mfc_mem_get_daddr_vb(vb, i);
- }
- }
- }
-
- if (call_cop(ctx, to_buf_ctrls, ctx, &ctx->src_ctrls[index]) < 0)
- mfc_err_ctx("failed in to_buf_ctrls\n");
- } else {
- mfc_err_ctx("inavlid queue type: %d\n", vq->type);
- return -EINVAL;
- }
-
- mfc_debug_leave();
- return 0;
-
-err_mem_put:
- for (i = 0; i < mem_get_count; i++)
- dma_buf_put(bufcon_dmabuf[i]);
-
- return -ENOMEM;
-}
-
-static void s5p_mfc_enc_buf_finish(struct vb2_buffer *vb)
-{
- struct vb2_queue *vq = vb->vb2_queue;
- struct s5p_mfc_ctx *ctx = vq->drv_priv;
- unsigned int index = vb->index;
-
-
- if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- if (call_cop(ctx, to_ctx_ctrls, ctx, &ctx->dst_ctrls[index]) < 0)
- mfc_err_ctx("failed in to_ctx_ctrls\n");
- } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- if (call_cop(ctx, to_ctx_ctrls, ctx, &ctx->src_ctrls[index]) < 0)
- mfc_err_ctx("failed in to_ctx_ctrls\n");
- }
-}
-
-static void s5p_mfc_enc_buf_cleanup(struct vb2_buffer *vb)
-{
- struct vb2_queue *vq = vb->vb2_queue;
- struct s5p_mfc_ctx *ctx = vq->drv_priv;
- unsigned int index = vb->index;
-
- mfc_debug_enter();
-
- if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- if (call_cop(ctx, cleanup_buf_ctrls, ctx,
- MFC_CTRL_TYPE_DST, index) < 0)
- mfc_err_ctx("failed in cleanup_buf_ctrls\n");
- } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- if (call_cop(ctx, cleanup_buf_ctrls, ctx,
- MFC_CTRL_TYPE_SRC, index) < 0)
- mfc_err_ctx("failed in cleanup_buf_ctrls\n");
- } else {
- mfc_err_ctx("s5p_mfc_enc_buf_cleanup: unknown queue type\n");
- }
-
- mfc_debug_leave();
-}
-
-static int s5p_mfc_enc_start_streaming(struct vb2_queue *q, unsigned int count)
-{
- struct s5p_mfc_ctx *ctx = q->drv_priv;
- struct s5p_mfc_dev *dev = ctx->dev;
-
- /* If context is ready then dev = work->data;schedule it to run */
- if (s5p_mfc_enc_ctx_ready(ctx)) {
- s5p_mfc_set_bit(ctx->num, &dev->work_bits);
- }
-
- s5p_mfc_try_run(dev);
-
- return 0;
-}
-
-static void s5p_mfc_enc_stop_streaming(struct vb2_queue *q)
-{
- struct s5p_mfc_ctx *ctx = q->drv_priv;
- struct s5p_mfc_dev *dev = ctx->dev;
- int index = 0;
- int aborted = 0;
- int ret = 0;
-
- mfc_info_ctx("enc stop_streaming is called, hwlock : %d, type : %d\n",
- test_bit(ctx->num, &dev->hwlock.bits), q->type);
- MFC_TRACE_CTX("** ENC streamoff(type:%d)\n", q->type);
-
- /* If a H/W operation is in progress, wait for it complete */
- if (need_to_wait_nal_abort(ctx)) {
- if (s5p_mfc_wait_for_done_ctx(ctx, S5P_FIMV_R2H_CMD_NAL_ABORT_RET)) {
- mfc_err_ctx("time out during nal abort\n");
- s5p_mfc_cleanup_work_bit_and_try_run(ctx);
- }
- aborted = 1;
- }
- MFC_TRACE_CTX_HWLOCK("**ENC streamoff(type:%d)\n", q->type);
- ret = s5p_mfc_get_hwlock_ctx(ctx);
- if (ret < 0) {
- mfc_err_ctx("Failed to get hwlock\n");
- return;
- }
-
- if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- s5p_mfc_cleanup_enc_dst_queue(ctx);
-
- while (index < MFC_MAX_BUFFERS) {
- index = find_next_bit(&ctx->dst_ctrls_avail,
- MFC_MAX_BUFFERS, index);
- if (index < MFC_MAX_BUFFERS)
- call_cop(ctx, reset_buf_ctrls, &ctx->dst_ctrls[index]);
- index++;
- }
- } else if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- if (ctx->state == MFCINST_RUNNING) {
- s5p_mfc_change_state(ctx, MFCINST_FINISHING);
- s5p_mfc_set_bit(ctx->num, &dev->work_bits);
-
- while (s5p_mfc_get_buf(&ctx->buf_queue_lock, &ctx->dst_buf_queue, MFC_BUF_NO_TOUCH_USED)) {
- ret = s5p_mfc_just_run(dev, ctx->num);
- if (ret) {
- mfc_err_ctx("Failed to run MFC\n");
- break;
- }
- if (s5p_mfc_wait_for_done_ctx(ctx, S5P_FIMV_R2H_CMD_FRAME_DONE_RET)) {
- mfc_err_ctx("Waiting for LAST_SEQ timed out\n");
- break;
- }
- if (ctx->state == MFCINST_RUNNING) {
- mfc_debug(2, "all encoded buffers out\n");
- break;
- }
- }
- }
-
- s5p_mfc_move_all_bufs(&ctx->buf_queue_lock, &ctx->src_buf_queue,
- &ctx->ref_buf_queue, MFC_QUEUE_ADD_BOTTOM);
- s5p_mfc_cleanup_enc_src_queue(ctx);
-
- while (index < MFC_MAX_BUFFERS) {
- index = find_next_bit(&ctx->src_ctrls_avail,
- MFC_MAX_BUFFERS, index);
- if (index < MFC_MAX_BUFFERS)
- call_cop(ctx, reset_buf_ctrls, &ctx->src_ctrls[index]);
- index++;
- }
- }
-
- if (aborted || ctx->state == MFCINST_FINISHING)
- s5p_mfc_change_state(ctx, MFCINST_RUNNING);
-
- mfc_debug(2, "buffer cleanup is done in stop_streaming, type : %d\n", q->type);
-
- s5p_mfc_clear_bit(ctx->num, &dev->work_bits);
- s5p_mfc_release_hwlock_ctx(ctx);
-
- if (s5p_mfc_is_work_to_do(dev))
- queue_work(dev->butler_wq, &dev->butler_work);
-}
-
-static void s5p_mfc_enc_buf_queue(struct vb2_buffer *vb)
-{
- struct vb2_queue *vq = vb->vb2_queue;
- struct s5p_mfc_ctx *ctx = vq->drv_priv;
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_buf *buf = vb_to_mfc_buf(vb);
- int i;
-
- mfc_debug_enter();
-
- buf->next_index = 0;
- buf->done_index = 0;
-
- if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- mfc_debug(2, "[BUFINFO] ctx[%d] add dst index: %d, addr: 0x%08llx\n",
- ctx->num, vb->index, buf->addr[0][0]);
-
- /* Mark destination as available for use by MFC */
- s5p_mfc_add_tail_buf(&ctx->buf_queue_lock, &ctx->dst_buf_queue, buf);
- } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- for (i = 0; i < ctx->src_fmt->mem_planes; i++)
- mfc_debug(2, "[BUFINFO] ctx[%d] add src index: %d, addr[%d]: 0x%08llx\n",
- ctx->num, vb->index, i, buf->addr[0][i]);
- s5p_mfc_add_tail_buf(&ctx->buf_queue_lock, &ctx->src_buf_queue, buf);
-
- if (debug_ts == 1)
- mfc_info_ctx("[TS] framerate: %ld, timestamp: %lld\n",
- ctx->framerate, buf->vb.vb2_buf.timestamp);
-
- s5p_mfc_qos_update_last_framerate(ctx, buf->vb.vb2_buf.timestamp);
- s5p_mfc_qos_update_framerate(ctx);
- } else {
- mfc_err_ctx("unsupported buffer type (%d)\n", vq->type);
- }
-
- if (s5p_mfc_enc_ctx_ready(ctx)) {
- s5p_mfc_set_bit(ctx->num, &dev->work_bits);
- }
- s5p_mfc_try_run(dev);
-
- mfc_debug_leave();
-}
-
-struct vb2_ops s5p_mfc_enc_qops = {
- .queue_setup = s5p_mfc_enc_queue_setup,
- .wait_prepare = s5p_mfc_enc_unlock,
- .wait_finish = s5p_mfc_enc_lock,
- .buf_init = s5p_mfc_enc_buf_init,
- .buf_prepare = s5p_mfc_enc_buf_prepare,
- .buf_finish = s5p_mfc_enc_buf_finish,
- .buf_cleanup = s5p_mfc_enc_buf_cleanup,
- .start_streaming = s5p_mfc_enc_start_streaming,
- .stop_streaming = s5p_mfc_enc_stop_streaming,
- .buf_queue = s5p_mfc_enc_buf_queue,
-};
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_hwfc_internal.h
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __S5P_MFC_HWFC_INTERNAL_H
-#define __S5P_MFC_HWFC_INTERNAL_H __FILE__
-
-#include "s5p_mfc_common.h"
-
-/*
- * RGB encoding information to avoid confusion.
- *
- * V4L2_PIX_FMT_ARGB32 takes ARGB data like below.
- * MSB LSB
- * 3 2 1
- * 2 4 6 8 0
- * |B......BG......GR......RA......A|
- */
-struct s5p_mfc_fmt enc_hwfc_formats[] = {
- {
- .name = "4:2:0 2 Planes Y/CbCr single",
- .fourcc = V4L2_PIX_FMT_NV12N,
- .codec_mode = MFC_FORMATS_NO_CODEC,
- .type = MFC_FMT_FRAME,
- .num_planes = 2,
- .mem_planes = 1,
- },
- {
- .name = "H264 Encoded Stream",
- .fourcc = V4L2_PIX_FMT_H264,
- .codec_mode = S5P_FIMV_CODEC_H264_ENC,
- .type = MFC_FMT_STREAM,
- .num_planes = 1,
- .mem_planes = 1,
- },
- {
- .name = "HEVC Encoded Stream",
- .fourcc = V4L2_PIX_FMT_HEVC,
- .codec_mode = S5P_FIMV_CODEC_HEVC_ENC,
- .type = MFC_FMT_STREAM,
- .num_planes = 1,
- .mem_planes = 1,
- },
-};
-
-#define NUM_FORMATS ARRAY_SIZE(enc_hwfc_formats)
-
-#endif /* __S5P_MFC_HWFC_INTERNAL_H */
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_hwlock.c
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include "s5p_mfc_hwlock.h"
-
-#include "s5p_mfc_nal_q.h"
-#include "s5p_mfc_otf.h"
-#include "s5p_mfc_opr.h"
-#include "s5p_mfc_sync.h"
-
-#include "s5p_mfc_inst.h"
-#include "s5p_mfc_pm.h"
-#include "s5p_mfc_cmd.h"
-#include "s5p_mfc_cal.h"
-#include "s5p_mfc_reg.h"
-
-#include "s5p_mfc_queue.h"
-#include "s5p_mfc_utils.h"
-
-static inline void mfc_print_hwlock(struct s5p_mfc_dev *dev)
-{
- mfc_debug(2, "dev.hwlock.dev = 0x%lx, bits = 0x%lx, owned_by_irq = %d, wl_count = %d, transfer_owner = %d\n",
- dev->hwlock.dev, dev->hwlock.bits, dev->hwlock.owned_by_irq,
- dev->hwlock.wl_count, dev->hwlock.transfer_owner);
-}
-
-void s5p_mfc_init_hwlock(struct s5p_mfc_dev *dev)
-{
- unsigned long flags;
-
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return;
- }
-
- spin_lock_init(&dev->hwlock.lock);
- spin_lock_irqsave(&dev->hwlock.lock, flags);
-
- INIT_LIST_HEAD(&dev->hwlock.waiting_list);
- dev->hwlock.wl_count = 0;
- dev->hwlock.bits = 0;
- dev->hwlock.dev = 0;
- dev->hwlock.owned_by_irq = 0;
- dev->hwlock.transfer_owner = 0;
-
- spin_unlock_irqrestore(&dev->hwlock.lock, flags);
-}
-
-static int mfc_remove_listable_wq_dev(struct s5p_mfc_dev *dev)
-{
- struct s5p_mfc_listable_wq *listable_wq;
- unsigned long flags;
- int ret = -1;
-
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
-
- spin_lock_irqsave(&dev->hwlock.lock, flags);
- mfc_print_hwlock(dev);
-
- list_for_each_entry(listable_wq, &dev->hwlock.waiting_list, list) {
- if (!listable_wq->dev)
- continue;
-
- mfc_debug(2, "Found dev and will delete it!\n");
-
- list_del(&listable_wq->list);
- dev->hwlock.wl_count--;
-
- ret = 0;
- break;
- }
-
- mfc_print_hwlock(dev);
- spin_unlock_irqrestore(&dev->hwlock.lock, flags);
-
- return ret;
-}
-
-static int mfc_remove_listable_wq_ctx(struct s5p_mfc_ctx *curr_ctx)
-{
- struct s5p_mfc_dev *dev;
- struct s5p_mfc_listable_wq *listable_wq;
- unsigned long flags;
- int ret = -1;
-
- if (!curr_ctx) {
- mfc_err_dev("no mfc context to run\n");
- return -EINVAL;
- }
-
- dev = curr_ctx->dev;
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
-
- spin_lock_irqsave(&dev->hwlock.lock, flags);
- mfc_print_hwlock(dev);
-
- list_for_each_entry(listable_wq, &dev->hwlock.waiting_list, list) {
- if (!listable_wq->ctx)
- continue;
-
- if (listable_wq->ctx->num == curr_ctx->num) {
- mfc_debug(2, "Found ctx and will delete it (%d)!\n", curr_ctx->num);
-
- list_del(&listable_wq->list);
- dev->hwlock.wl_count--;
- ret = 0;
- break;
- }
- }
-
- mfc_print_hwlock(dev);
- spin_unlock_irqrestore(&dev->hwlock.lock, flags);
-
- return ret;
-}
-
-/*
- * Return value description
- * 0: succeeded to get hwlock
- * -EIO: failed to get hwlock (time out)
- */
-int s5p_mfc_get_hwlock_dev(struct s5p_mfc_dev *dev)
-{
- int ret = 0;
- unsigned long flags;
-
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
-
- mutex_lock(&dev->hwlock_wq.wait_mutex);
-
- spin_lock_irqsave(&dev->hwlock.lock, flags);
- mfc_print_hwlock(dev);
-
- if (dev->shutdown) {
- mfc_info_dev("Couldn't lock HW. Shutdown was called\n");
- spin_unlock_irqrestore(&dev->hwlock.lock, flags);
- mutex_unlock(&dev->hwlock_wq.wait_mutex);
- return -EINVAL;
- }
-
- if ((dev->hwlock.bits != 0) || (dev->hwlock.dev != 0)) {
- list_add_tail(&dev->hwlock_wq.list, &dev->hwlock.waiting_list);
- dev->hwlock.wl_count++;
-
- spin_unlock_irqrestore(&dev->hwlock.lock, flags);
-
- mfc_debug(2, "Waiting for hwlock to be released\n");
-
- ret = wait_event_timeout(dev->hwlock_wq.wait_queue,
- ((dev->hwlock.transfer_owner == 1) && (dev->hwlock.dev == 1)),
- msecs_to_jiffies(MFC_HWLOCK_TIMEOUT));
-
- MFC_TRACE_DEV_HWLOCK("get_hwlock_dev: before waiting\n");
- MFC_TRACE_DEV_HWLOCK(">>dev:0x%lx, bits:0x%lx, owned:%d, wl:%d, trans:%d\n",
- dev->hwlock.dev, dev->hwlock.bits, dev->hwlock.owned_by_irq,
- dev->hwlock.wl_count, dev->hwlock.transfer_owner);
-
- dev->hwlock.transfer_owner = 0;
- mfc_remove_listable_wq_dev(dev);
- if (ret == 0) {
- mfc_err_dev("Woken up but timed out\n");
- mfc_print_hwlock(dev);
- mutex_unlock(&dev->hwlock_wq.wait_mutex);
- return -EIO;
- } else {
- mfc_debug(2, "Woken up and got hwlock\n");
- mfc_print_hwlock(dev);
- mutex_unlock(&dev->hwlock_wq.wait_mutex);
- }
- } else {
- dev->hwlock.bits = 0;
- dev->hwlock.dev = 1;
- dev->hwlock.owned_by_irq = 0;
-
- MFC_TRACE_DEV_HWLOCK("get_hwlock_dev: no waiting\n");
- MFC_TRACE_DEV_HWLOCK(">>dev:0x%lx, bits:0x%lx, owned:%d, wl:%d, trans:%d\n",
- dev->hwlock.dev, dev->hwlock.bits, dev->hwlock.owned_by_irq,
- dev->hwlock.wl_count, dev->hwlock.transfer_owner);
-
- mfc_print_hwlock(dev);
- spin_unlock_irqrestore(&dev->hwlock.lock, flags);
- mutex_unlock(&dev->hwlock_wq.wait_mutex);
- }
-
- /* Stop NAL-Q after getting hwlock */
- if (dev->nal_q_handle)
- s5p_mfc_nal_q_stop_if_started(dev);
-
- return 0;
-}
-
-/*
- * Return value description
- * 0: succeeded to get hwlock
- * -EIO: failed to get hwlock (time out)
- */
-int s5p_mfc_get_hwlock_ctx(struct s5p_mfc_ctx *curr_ctx)
-{
- struct s5p_mfc_dev *dev;
- struct s5p_mfc_ctx *ctx = curr_ctx;
- int ret = 0;
- unsigned long flags;
-
- if (!curr_ctx) {
- mfc_err_dev("no mfc context to run\n");
- return -EINVAL;
- }
-
- dev = curr_ctx->dev;
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
-
- mutex_lock(&curr_ctx->hwlock_wq.wait_mutex);
-
- spin_lock_irqsave(&dev->hwlock.lock, flags);
- mfc_print_hwlock(dev);
-
- if (dev->shutdown) {
- mfc_info_dev("Couldn't lock HW. Shutdown was called\n");
- spin_unlock_irqrestore(&dev->hwlock.lock, flags);
- mutex_unlock(&curr_ctx->hwlock_wq.wait_mutex);
- return -EINVAL;
- }
-
- if ((dev->hwlock.bits != 0) || (dev->hwlock.dev != 0)) {
- list_add_tail(&curr_ctx->hwlock_wq.list, &dev->hwlock.waiting_list);
- dev->hwlock.wl_count++;
-
- spin_unlock_irqrestore(&dev->hwlock.lock, flags);
-
- MFC_TRACE_CTX_HWLOCK("get_hwlock_ctx: before waiting\n");
- MFC_TRACE_CTX_HWLOCK(">>dev:0x%lx, bits:0x%lx, owned:%d, wl:%d, trans:%d\n",
- dev->hwlock.dev, dev->hwlock.bits, dev->hwlock.owned_by_irq,
- dev->hwlock.wl_count, dev->hwlock.transfer_owner);
-
- mfc_debug(2, "Waiting for hwlock to be released\n");
-
- ret = wait_event_timeout(curr_ctx->hwlock_wq.wait_queue,
- ((dev->hwlock.transfer_owner == 1) && (test_bit(curr_ctx->num, &dev->hwlock.bits))),
- msecs_to_jiffies(MFC_HWLOCK_TIMEOUT));
-
- MFC_TRACE_CTX_HWLOCK("get_hwlock_ctx: after waiting, ret:%d\n", ret);
- MFC_TRACE_CTX_HWLOCK(">>dev:0x%lx, bits:0x%lx, owned:%d, wl:%d, trans:%d\n",
- dev->hwlock.dev, dev->hwlock.bits, dev->hwlock.owned_by_irq,
- dev->hwlock.wl_count, dev->hwlock.transfer_owner);
-
- dev->hwlock.transfer_owner = 0;
- mfc_remove_listable_wq_ctx(curr_ctx);
- if (ret == 0) {
- mfc_err_dev("Woken up but timed out\n");
- mfc_print_hwlock(dev);
- mutex_unlock(&curr_ctx->hwlock_wq.wait_mutex);
- return -EIO;
- } else {
- mfc_debug(2, "Woken up and got hwlock\n");
- mfc_print_hwlock(dev);
- mutex_unlock(&curr_ctx->hwlock_wq.wait_mutex);
- }
- } else {
- dev->hwlock.bits = 0;
- dev->hwlock.dev = 0;
- set_bit(curr_ctx->num, &dev->hwlock.bits);
- dev->hwlock.owned_by_irq = 0;
-
- MFC_TRACE_CTX_HWLOCK("get_hwlock_ctx: no waiting\n");
- MFC_TRACE_CTX_HWLOCK(">>dev:0x%lx, bits:0x%lx, owned:%d, wl:%d, trans:%d\n",
- dev->hwlock.dev, dev->hwlock.bits, dev->hwlock.owned_by_irq,
- dev->hwlock.wl_count, dev->hwlock.transfer_owner);
-
- mfc_print_hwlock(dev);
- spin_unlock_irqrestore(&dev->hwlock.lock, flags);
- mutex_unlock(&curr_ctx->hwlock_wq.wait_mutex);
- }
-
- /* Stop NAL-Q after getting hwlock */
- if (dev->nal_q_handle)
- s5p_mfc_nal_q_stop_if_started(dev);
-
- return 0;
-}
-
-/*
- * Return value description
- * 0: succeeded to release hwlock
- * 1: succeeded to release hwlock, hwlock is captured by another module
- * -1: error since device is waiting again.
- */
-int s5p_mfc_release_hwlock_dev(struct s5p_mfc_dev *dev)
-{
- struct s5p_mfc_listable_wq *listable_wq;
- unsigned long flags;
- int ret = -1;
-
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
-
- spin_lock_irqsave(&dev->hwlock.lock, flags);
- mfc_print_hwlock(dev);
-
- dev->hwlock.dev = 0;
- dev->hwlock.owned_by_irq = 0;
-
- if (dev->shutdown) {
- mfc_debug(2, "Couldn't wakeup module. Shutdown was called\n");
- ret = 0;
- } else if (list_empty(&dev->hwlock.waiting_list)) {
- mfc_debug(2, "No waiting module\n");
- ret = 0;
- } else {
- mfc_debug(2, "There is a waiting module\n");
- listable_wq = list_entry(dev->hwlock.waiting_list.next, struct s5p_mfc_listable_wq, list);
- list_del(&listable_wq->list);
- dev->hwlock.wl_count--;
-
- if (listable_wq->dev) {
- mfc_debug(2, "Waking up dev\n");
- dev->hwlock.dev = 1;
- } else {
- mfc_debug(2, "Waking up another ctx\n");
- set_bit(listable_wq->ctx->num, &dev->hwlock.bits);
- }
-
- dev->hwlock.transfer_owner = 1;
-
- MFC_TRACE_DEV_HWLOCK("release_hwlock_dev: wakeup\n");
- MFC_TRACE_DEV_HWLOCK(">>dev:0x%lx, bits:0x%lx, owned:%d, wl:%d, trans:%d\n",
- dev->hwlock.dev, dev->hwlock.bits, dev->hwlock.owned_by_irq,
- dev->hwlock.wl_count, dev->hwlock.transfer_owner);
-
- wake_up(&listable_wq->wait_queue);
- ret = 1;
- }
-
- mfc_print_hwlock(dev);
- spin_unlock_irqrestore(&dev->hwlock.lock, flags);
- return ret;
-}
-
-/*
- * Should be called with hwlock.lock
- *
- * Return value description
- * 0: succeeded to release hwlock
- * 1: succeeded to release hwlock, hwlock is captured by another module
- */
-static int mfc_release_hwlock_ctx_protected(struct s5p_mfc_ctx *curr_ctx)
-{
- struct s5p_mfc_dev *dev;
- struct s5p_mfc_ctx *ctx = curr_ctx;
- struct s5p_mfc_listable_wq *listable_wq;
- int ret = -1;
-
- if (!curr_ctx) {
- mfc_err_dev("no mfc context to run\n");
- return -EINVAL;
- }
-
- dev = curr_ctx->dev;
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
-
- mfc_print_hwlock(dev);
- clear_bit(curr_ctx->num, &dev->hwlock.bits);
- dev->hwlock.owned_by_irq = 0;
-
- if (dev->shutdown) {
- mfc_debug(2, "Couldn't wakeup module. Shutdown was called\n");
- ret = 0;
- } else if (list_empty(&dev->hwlock.waiting_list)) {
- mfc_debug(2, "No waiting module\n");
- ret = 0;
- } else {
- mfc_debug(2, "There is a waiting module\n");
- listable_wq = list_entry(dev->hwlock.waiting_list.next, struct s5p_mfc_listable_wq, list);
- list_del(&listable_wq->list);
- dev->hwlock.wl_count--;
-
- if (listable_wq->dev) {
- mfc_debug(2, "Waking up dev\n");
- dev->hwlock.dev = 1;
- } else {
- mfc_debug(2, "Waking up another ctx\n");
- set_bit(listable_wq->ctx->num, &dev->hwlock.bits);
- }
-
- dev->hwlock.transfer_owner = 1;
-
- MFC_TRACE_CTX_HWLOCK("release_hwlock_ctx: wakeup\n");
- MFC_TRACE_CTX_HWLOCK(">>dev:0x%lx, bits:0x%lx, owned:%d, wl:%d, trans:%d\n",
- dev->hwlock.dev, dev->hwlock.bits, dev->hwlock.owned_by_irq,
- dev->hwlock.wl_count, dev->hwlock.transfer_owner);
-
- wake_up(&listable_wq->wait_queue);
- ret = 1;
- }
-
- mfc_print_hwlock(dev);
- return ret;
-}
-
-/*
- * Return value description
- * 0: succeeded to release hwlock
- * 1: succeeded to release hwlock, hwlock is captured by another module
- */
-int s5p_mfc_release_hwlock_ctx(struct s5p_mfc_ctx *curr_ctx)
-{
- struct s5p_mfc_dev *dev;
- unsigned long flags;
- int ret = -1;
-
- if (!curr_ctx) {
- mfc_err_dev("no mfc context to run\n");
- return -EINVAL;
- }
-
- dev = curr_ctx->dev;
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
-
- spin_lock_irqsave(&dev->hwlock.lock, flags);
- ret = mfc_release_hwlock_ctx_protected(curr_ctx);
- spin_unlock_irqrestore(&dev->hwlock.lock, flags);
- return ret;
-}
-
-static inline int mfc_yield_hwlock(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *curr_ctx)
-{
- unsigned long flags;
-
- if (!curr_ctx) {
- mfc_err_dev("no mfc context to run\n");
- return -EINVAL;
- }
-
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
-
- spin_lock_irqsave(&dev->hwlock.lock, flags);
-
- mfc_release_hwlock_ctx_protected(curr_ctx);
-
- spin_unlock_irqrestore(&dev->hwlock.lock, flags);
-
- /* Trigger again if other instance's work is waiting */
- if (s5p_mfc_is_work_to_do(dev))
- queue_work(dev->butler_wq, &dev->butler_work);
-
- return 0;
-}
-
-/*
- * Should be called with hwlock.lock
- */
-static inline void mfc_transfer_hwlock_ctx_protected(struct s5p_mfc_dev *dev, int curr_ctx_index)
-{
- dev->hwlock.dev = 0;
- dev->hwlock.bits = 0;
- set_bit(curr_ctx_index, &dev->hwlock.bits);
-}
-
-/*
- * Should be called with hwlock.lock
- *
- * Return value description
- * >=0: succeeded to get hwlock_bit for the context, index of new context
- * -1, -EINVAL: failed to get hwlock_bit for a context
- */
-static int mfc_try_to_get_new_ctx_protected(struct s5p_mfc_dev *dev)
-{
- int ret = 0;
- int index;
- struct s5p_mfc_ctx *new_ctx;
-
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
-
- if (dev->shutdown) {
- mfc_info_dev("Couldn't lock HW. Shutdown was called\n");
- return -EINVAL;
- }
-
- if (dev->sleep) {
- mfc_info_dev("Couldn't lock HW. Sleep was called\n");
- return -EINVAL;
- }
-
- /* Check whether hardware is not running */
- if ((dev->hwlock.bits != 0) || (dev->hwlock.dev != 0)) {
- /* This is perfectly ok, the scheduled ctx should wait */
- mfc_debug(2, "Couldn't lock HW\n");
- return -1;
- }
-
- /* Choose the context to run */
- index = s5p_mfc_get_new_ctx(dev);
- if (index < 0) {
- /* This is perfectly ok, the scheduled ctx should wait
- * No contexts to run
- */
- mfc_debug(2, "No ctx is scheduled to be run\n");
- ret = -1;
- return ret;
- }
-
- new_ctx = dev->ctx[index];
- if (!new_ctx) {
- mfc_err_dev("no mfc context to run\n");
- ret = -1;
- return ret;
- }
-
- set_bit(new_ctx->num, &dev->hwlock.bits);
- ret = index;
-
- return ret;
-}
-
-/*
- * Should be called without hwlock holding
- *
- * Try to run an operation on hardware
- */
-void s5p_mfc_try_run(struct s5p_mfc_dev *dev)
-{
- int new_ctx_index;
- int ret;
- unsigned long flags;
-
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return;
- }
-
- spin_lock_irqsave(&dev->hwlock.lock, flags);
- mfc_print_hwlock(dev);
-
- new_ctx_index = mfc_try_to_get_new_ctx_protected(dev);
- if (new_ctx_index < 0) {
- mfc_debug(2, "Failed to get new context to run\n");
- mfc_print_hwlock(dev);
- spin_unlock_irqrestore(&dev->hwlock.lock, flags);
- return;
- }
-
- dev->hwlock.owned_by_irq = 1;
-
- mfc_print_hwlock(dev);
- spin_unlock_irqrestore(&dev->hwlock.lock, flags);
-
- ret = s5p_mfc_just_run(dev, new_ctx_index);
- if (ret)
- mfc_yield_hwlock(dev, dev->ctx[new_ctx_index]);
-}
-
-/*
- * Should be called without hwlock holding
- *
- */
-void s5p_mfc_cleanup_work_bit_and_try_run(struct s5p_mfc_ctx *curr_ctx)
-{
- struct s5p_mfc_dev *dev;
-
- if (!curr_ctx) {
- mfc_err_dev("no mfc context to run\n");
- return;
- }
-
- dev = curr_ctx->dev;
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return;
- }
-
- s5p_mfc_clear_bit(curr_ctx->num, &dev->work_bits);
-
- s5p_mfc_try_run(dev);
-}
-
-void s5p_mfc_cache_flush(struct s5p_mfc_dev *dev, int is_drm)
-{
- s5p_mfc_cmd_cache_flush(dev);
- if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_CACHE_FLUSH_RET)) {
- mfc_err_dev("Failed to CACHE_FLUSH\n");
- dev->logging_data->cause |= (1 << MFC_CAUSE_FAIL_CHACHE_FLUSH);
- call_dop(dev, dump_and_stop_always, dev);
- }
-
- s5p_mfc_pm_clock_off(dev);
- dev->curr_ctx_is_drm = is_drm;
- s5p_mfc_pm_clock_on_with_base(dev, (is_drm ? MFCBUF_DRM : MFCBUF_NORMAL));
-}
-
-/*
- * Return value description
- * 0: NAL-Q is handled successfully
- * 1: NAL_START command should be handled
- * -1: Error
-*/
-static int mfc_nal_q_just_run(struct s5p_mfc_ctx *ctx, int need_cache_flush)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- unsigned int ret = -1;
-
- nal_queue_handle *nal_q_handle = dev->nal_q_handle;
-
- if (!nal_q_handle) {
- mfc_err_dev("nal_q_handle is NULL\n");
- return ret;
- }
-
- switch (nal_q_handle->nal_q_state) {
- case NAL_Q_STATE_CREATED:
- if (s5p_mfc_nal_q_check_enable(dev) == 0) {
- /* NAL START */
- ret = 1;
- } else {
- s5p_mfc_nal_q_clock_on(dev, nal_q_handle);
-
- s5p_mfc_nal_q_init(dev, nal_q_handle);
-
- /* enable NAL QUEUE */
- if (need_cache_flush)
- s5p_mfc_cache_flush(dev, ctx->is_drm);
-
- mfc_info_ctx("[NALQ] start NAL QUEUE\n");
- s5p_mfc_nal_q_start(dev, nal_q_handle);
-
- if (s5p_mfc_nal_q_enqueue_in_buf(dev, ctx, nal_q_handle->nal_q_in_handle)) {
- mfc_debug(2, "[NALQ] Failed to enqueue input data\n");
- s5p_mfc_nal_q_clock_off(dev, nal_q_handle);
- }
-
- s5p_mfc_clear_bit(ctx->num, &dev->work_bits);
- if ((s5p_mfc_ctx_ready(ctx) && !ctx->clear_work_bit) ||
- nal_q_handle->nal_q_exception)
- s5p_mfc_set_bit(ctx->num, &dev->work_bits);
- ctx->clear_work_bit = 0;
-
- s5p_mfc_release_hwlock_ctx(ctx);
-
- if (s5p_mfc_is_work_to_do(dev))
- queue_work(dev->butler_wq, &dev->butler_work);
-
- ret = 0;
- }
- break;
- case NAL_Q_STATE_STARTED:
- s5p_mfc_nal_q_clock_on(dev, nal_q_handle);
-
- if (s5p_mfc_nal_q_check_enable(dev) == 0 ||
- nal_q_handle->nal_q_exception) {
- /* disable NAL QUEUE */
- s5p_mfc_nal_q_stop(dev, nal_q_handle);
- mfc_info_ctx("[NALQ] stop NAL QUEUE\n");
- if (s5p_mfc_wait_for_done_dev(dev,
- S5P_FIMV_R2H_CMD_COMPLETE_QUEUE_RET)) {
- mfc_err_dev("[NALQ] Failed to stop queue\n");
- dev->logging_data->cause |= (1 << MFC_CAUSE_FAIL_STOP_NAL_Q);
- call_dop(dev, dump_and_stop_always, dev);
- }
- ret = 1;
- break;
- } else {
- /* NAL QUEUE */
- if (s5p_mfc_nal_q_enqueue_in_buf(dev, ctx, nal_q_handle->nal_q_in_handle)) {
- mfc_debug(2, "[NALQ] Failed to enqueue input data\n");
- s5p_mfc_nal_q_clock_off(dev, nal_q_handle);
- }
-
- s5p_mfc_clear_bit(ctx->num, &dev->work_bits);
-
- if ((s5p_mfc_ctx_ready(ctx) && !ctx->clear_work_bit) ||
- nal_q_handle->nal_q_exception)
- s5p_mfc_set_bit(ctx->num, &dev->work_bits);
- ctx->clear_work_bit = 0;
-
- s5p_mfc_release_hwlock_ctx(ctx);
-
- if (s5p_mfc_is_work_to_do(dev))
- queue_work(dev->butler_wq, &dev->butler_work);
- ret = 0;
- }
- break;
- default:
- mfc_info_ctx("[NALQ] can't try command, nal_q_state : %d\n",
- nal_q_handle->nal_q_state);
- ret = -1;
- break;
- }
-
- return ret;
-}
-
-static int mfc_just_run_dec(struct s5p_mfc_ctx *ctx)
-{
- int ret = 0;
-
- switch (ctx->state) {
- case MFCINST_FINISHING:
- ret = s5p_mfc_run_dec_last_frames(ctx);
- break;
- case MFCINST_RUNNING:
- case MFCINST_SPECIAL_PARSING_NAL:
- ret = s5p_mfc_run_dec_frame(ctx);
- break;
- case MFCINST_INIT:
- ret = s5p_mfc_open_inst(ctx);
- break;
- case MFCINST_RETURN_INST:
- ret = s5p_mfc_close_inst(ctx);
- break;
- case MFCINST_GOT_INST:
- case MFCINST_SPECIAL_PARSING:
- ret = s5p_mfc_run_dec_init(ctx);
- break;
- case MFCINST_HEAD_PARSED:
- if (ctx->codec_buffer_allocated == 0) {
- ctx->clear_work_bit = 1;
- mfc_err_ctx("codec buffer is not allocated\n");
- ret = -EAGAIN;
- break;
- }
- ret = s5p_mfc_cmd_dec_init_buffers(ctx);
- break;
- case MFCINST_RES_CHANGE_INIT:
- ret = s5p_mfc_run_dec_last_frames(ctx);
- break;
- case MFCINST_RES_CHANGE_FLUSH:
- ret = s5p_mfc_run_dec_last_frames(ctx);
- break;
- case MFCINST_RES_CHANGE_END:
- mfc_debug(2, "[DRC] Finished remaining frames after resolution change\n");
- ctx->capture_state = QUEUE_FREE;
- mfc_debug(2, "[DRC] Will re-init the codec\n");
- ret = s5p_mfc_run_dec_init(ctx);
- break;
- case MFCINST_DPB_FLUSHING:
- ret = s5p_mfc_cmd_dpb_flush(ctx);
- break;
- default:
- mfc_info_ctx("can't try command(decoder just_run), state : %d\n", ctx->state);
- ret = -EAGAIN;
- }
-
- return ret;
-}
-
-static int mfc_just_run_enc(struct s5p_mfc_ctx *ctx)
-{
- int ret = 0;
-
- switch (ctx->state) {
- case MFCINST_FINISHING:
- ret = s5p_mfc_run_enc_last_frames(ctx);
- break;
- case MFCINST_RUNNING:
- if (ctx->otf_handle) {
- ret = s5p_mfc_otf_run_enc_frame(ctx);
- break;
- }
- ret = s5p_mfc_run_enc_frame(ctx);
- break;
- case MFCINST_INIT:
- ret = s5p_mfc_open_inst(ctx);
- break;
- case MFCINST_RETURN_INST:
- ret = s5p_mfc_close_inst(ctx);
- break;
- case MFCINST_GOT_INST:
- if (ctx->otf_handle) {
- ret = s5p_mfc_otf_run_enc_init(ctx);
- break;
- }
- ret = s5p_mfc_run_enc_init(ctx);
- break;
- case MFCINST_HEAD_PARSED:
- ret = s5p_mfc_cmd_enc_init_buffers(ctx);
- break;
- case MFCINST_ABORT_INST:
- ret = s5p_mfc_abort_inst(ctx);
- break;
- default:
- mfc_info_ctx("can't try command(encoder just_run), state : %d\n", ctx->state);
- ret = -EAGAIN;
- }
-
- return ret;
-}
-
-/* Run an operation on hardware */
-int s5p_mfc_just_run(struct s5p_mfc_dev *dev, int new_ctx_index)
-{
- struct s5p_mfc_ctx *ctx;
- unsigned int ret = 0;
- int need_cache_flush = 0;
-
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
-
- ctx = dev->ctx[new_ctx_index];
- if (!ctx) {
- mfc_err_dev("no mfc context to run\n");
- return -EINVAL;
- }
-
- if (ctx->state == MFCINST_RUNNING)
- s5p_mfc_clean_ctx_int_flags(ctx);
-
- mfc_debug(2, "New context: %d\n", new_ctx_index);
- dev->curr_ctx = ctx->num;
-
- /* Got context to run in ctx */
- mfc_debug(2, "src: %d, dst: %d, state: %d, dpb_count = %d\n",
- s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->src_buf_queue),
- s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->dst_buf_queue),
- ctx->state, ctx->dpb_count);
- mfc_debug(2, "ctx->state = %d\n", ctx->state);
- /* Last frame has already been sent to MFC
- * Now obtaining frames from MFC buffer */
-
- /* Check if cache flush command is needed */
- if (dev->curr_ctx_is_drm != ctx->is_drm)
- need_cache_flush = 1;
- else
- dev->curr_ctx_is_drm = ctx->is_drm;
-
- mfc_debug(2, "need_cache_flush = %d, is_drm = %d\n", need_cache_flush, ctx->is_drm);
-
- if (dev->nal_q_handle) {
- ret = mfc_nal_q_just_run(ctx, need_cache_flush);
- if (ret == 0) {
- mfc_debug(2, "NAL_Q was handled\n");
- return ret;
- } else if (ret == 1){
- /* Path through */
- mfc_debug(2, "NAL_START will be handled\n");
- } else {
- return ret;
- }
- }
-
- mfc_debug(2, "continue_clock_on = %d\n", dev->continue_clock_on);
- if (!dev->continue_clock_on) {
- s5p_mfc_pm_clock_on(dev);
- } else {
- dev->continue_clock_on = false;
- }
-
- if (need_cache_flush)
- s5p_mfc_cache_flush(dev, ctx->is_drm);
-
- if (ctx->type == MFCINST_DECODER) {
- ret = mfc_just_run_dec(ctx);
- } else if (ctx->type == MFCINST_ENCODER) {
- ret = mfc_just_run_enc(ctx);
- } else {
- mfc_err_ctx("invalid context type: %d\n", ctx->type);
- ret = -EAGAIN;
- }
-
- if (ret) {
- /* Check again the ctx condition and clear work bits
- * if ctx is not available. */
- if (s5p_mfc_ctx_ready(ctx) == 0 || ctx->clear_work_bit) {
- s5p_mfc_clear_bit(ctx->num, &dev->work_bits);
- ctx->clear_work_bit = 0;
- }
-
- s5p_mfc_pm_clock_off(dev);
- }
-
- return ret;
-}
-
-void s5p_mfc_hwlock_handler_irq(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *curr_ctx,
- unsigned int reason, unsigned int err)
-{
- int new_ctx_index;
- unsigned long flags;
- int ret;
-
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return;
- }
-
- if (!curr_ctx) {
- mfc_err_dev("no mfc context to run\n");
- return;
- }
-
- spin_lock_irqsave(&dev->hwlock.lock, flags);
- mfc_print_hwlock(dev);
-
- if (dev->hwlock.owned_by_irq) {
- if (dev->preempt_ctx > MFC_NO_INSTANCE_SET) {
- mfc_debug(2, "There is a preempt_ctx\n");
- dev->continue_clock_on = true;
- s5p_mfc_wake_up_ctx(curr_ctx, reason, err);
- new_ctx_index = dev->preempt_ctx;
- mfc_debug(2, "preempt_ctx is : %d\n", new_ctx_index);
-
- spin_unlock_irqrestore(&dev->hwlock.lock, flags);
-
- ret = s5p_mfc_just_run(dev, new_ctx_index);
- if (ret) {
- dev->continue_clock_on = false;
- mfc_yield_hwlock(dev, dev->ctx[new_ctx_index]);
- }
- } else if (!list_empty(&dev->hwlock.waiting_list)) {
- mfc_debug(2, "There is a waiting module for hwlock\n");
- dev->continue_clock_on = false;
- s5p_mfc_pm_clock_off(dev);
-
- spin_unlock_irqrestore(&dev->hwlock.lock, flags);
-
- s5p_mfc_release_hwlock_ctx(curr_ctx);
- s5p_mfc_wake_up_ctx(curr_ctx, reason, err);
- queue_work(dev->butler_wq, &dev->butler_work);
- } else {
- mfc_debug(2, "No preempt_ctx and no waiting module\n");
- new_ctx_index = s5p_mfc_get_new_ctx(dev);
- if (new_ctx_index < 0) {
- mfc_debug(2, "No ctx to run\n");
- /* No contexts to run */
- dev->continue_clock_on = false;
- s5p_mfc_pm_clock_off(dev);
-
- spin_unlock_irqrestore(&dev->hwlock.lock, flags);
-
- s5p_mfc_release_hwlock_ctx(curr_ctx);
- s5p_mfc_wake_up_ctx(curr_ctx, reason, err);
- queue_work(dev->butler_wq, &dev->butler_work);
- } else {
- mfc_debug(2, "There is a ctx to run\n");
- dev->continue_clock_on = true;
- s5p_mfc_wake_up_ctx(curr_ctx, reason, err);
-
- /* If cache flush command is needed or there is OTF handle, handler should stop */
- if ((dev->curr_ctx_is_drm != dev->ctx[new_ctx_index]->is_drm) ||
- dev->ctx[new_ctx_index]->otf_handle) {
- mfc_debug(2, "Secure and nomal switching or OTF mode\n");
- mfc_debug(2, "DRM attribute %d->%d\n",
- dev->curr_ctx_is_drm, dev->ctx[new_ctx_index]->is_drm);
-
- spin_unlock_irqrestore(&dev->hwlock.lock, flags);
-
- s5p_mfc_release_hwlock_ctx(curr_ctx);
- queue_work(dev->butler_wq, &dev->butler_work);
- } else {
- mfc_debug(2, "Work to do successively (next ctx: %d)\n", new_ctx_index);
- mfc_transfer_hwlock_ctx_protected(dev, new_ctx_index);
-
- spin_unlock_irqrestore(&dev->hwlock.lock, flags);
-
- ret = s5p_mfc_just_run(dev, new_ctx_index);
- if (ret) {
- dev->continue_clock_on = false;
- mfc_yield_hwlock(dev, dev->ctx[new_ctx_index]);
- }
- }
- }
- }
- } else {
- mfc_debug(2, "hwlock is NOT owned by irq\n");
- dev->continue_clock_on = false;
- s5p_mfc_pm_clock_off(dev);
- s5p_mfc_wake_up_ctx(curr_ctx, reason, err);
- queue_work(dev->butler_wq, &dev->butler_work);
-
- spin_unlock_irqrestore(&dev->hwlock.lock, flags);
- }
- mfc_print_hwlock(dev);
-}
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_hwlock.h
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __S5P_MFC_HWLOCK_H
-#define __S5P_MFC_HWLOCK_H __FILE__
-
-#include "s5p_mfc_common.h"
-
-static inline void s5p_mfc_init_listable_wq_dev(struct s5p_mfc_dev *dev)
-{
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return;
- }
-
- INIT_LIST_HEAD(&dev->hwlock_wq.list);
- init_waitqueue_head(&dev->hwlock_wq.wait_queue);
- mutex_init(&dev->hwlock_wq.wait_mutex);
- dev->hwlock_wq.ctx = NULL;
- dev->hwlock_wq.dev = dev;
-}
-
-static inline void s5p_mfc_init_listable_wq_ctx(struct s5p_mfc_ctx *curr_ctx)
-{
- if (!curr_ctx) {
- mfc_err_dev("no mfc context to run\n");
- return;
- }
-
- INIT_LIST_HEAD(&curr_ctx->hwlock_wq.list);
- init_waitqueue_head(&curr_ctx->hwlock_wq.wait_queue);
- mutex_init(&curr_ctx->hwlock_wq.wait_mutex);
- curr_ctx->hwlock_wq.ctx = curr_ctx;
- curr_ctx->hwlock_wq.dev = NULL;
-}
-
-static inline void s5p_mfc_destroy_listable_wq_dev(struct s5p_mfc_dev *dev)
-{
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return;
- }
-
- mutex_destroy(&dev->hwlock_wq.wait_mutex);
-}
-
-static inline void s5p_mfc_destroy_listable_wq_ctx(struct s5p_mfc_ctx *curr_ctx)
-{
- if (!curr_ctx) {
- mfc_err_dev("no mfc context to run\n");
- return;
- }
-
- mutex_destroy(&curr_ctx->hwlock_wq.wait_mutex);
-}
-
-void s5p_mfc_init_hwlock(struct s5p_mfc_dev *dev);
-
-int s5p_mfc_get_hwlock_dev(struct s5p_mfc_dev *dev);
-int s5p_mfc_get_hwlock_ctx(struct s5p_mfc_ctx *curr_ctx);
-
-int s5p_mfc_release_hwlock_dev(struct s5p_mfc_dev *dev);
-int s5p_mfc_release_hwlock_ctx(struct s5p_mfc_ctx *curr_ctx);
-
-void s5p_mfc_cache_flush(struct s5p_mfc_dev *dev, int is_drm);
-
-void s5p_mfc_try_run(struct s5p_mfc_dev *dev);
-void s5p_mfc_cleanup_work_bit_and_try_run(struct s5p_mfc_ctx *ctx);
-int s5p_mfc_just_run(struct s5p_mfc_dev *dev, int new_ctx_index);
-
-void s5p_mfc_hwlock_handler_irq(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx,
- unsigned int reason, unsigned int err);
-
-#endif /* __S5P_MFC_HWLOCK_H */
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_inst.c
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include "s5p_mfc_inst.h"
-
-#include "s5p_mfc_cmd.h"
-#include "s5p_mfc_enc_param.h"
-#include "s5p_mfc_cal.h"
-#include "s5p_mfc_perf_measure.h"
-#include "s5p_mfc_reg.h"
-
-#include "s5p_mfc_utils.h"
-
-int s5p_mfc_open_inst(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- unsigned int reg;
- int ret;
-
- /* Preparing decoding - getting instance number */
- mfc_debug(2, "Getting instance number\n");
- s5p_mfc_clean_ctx_int_flags(ctx);
-
- reg = MFC_READL(S5P_FIMV_CODEC_CONTROL);
- /* Clear OTF_CONTROL[2:1] & OTF_DEBUG[3] */
- reg &= ~(0x7 << 1);
- if (ctx->otf_handle) {
- /* Set OTF_CONTROL[2:1], 0: Non-OTF, 1: OTF+HWFC, 2: OTF only */
- reg |= (0x1 << 1);
- mfc_info_ctx("HWFC + OTF enabled\n");
- if (otf_dump && !ctx->is_drm) {
- /* Set OTF_DEBUG[3] for OTF path dump */
- reg |= (0x1 << 3);
- mfc_info_ctx("Debugging mode enabled\n");
- }
- }
- MFC_WRITEL(reg, S5P_FIMV_CODEC_CONTROL);
-
-
- ret = s5p_mfc_cmd_open_inst(ctx);
- if (ret) {
- mfc_err_ctx("Failed to create a new instance\n");
- s5p_mfc_change_state(ctx, MFCINST_ERROR);
- }
-
- return ret;
-}
-
-int s5p_mfc_close_inst(struct s5p_mfc_ctx *ctx)
-{
- int ret = -EINVAL;
-
- /* Closing decoding instance */
- mfc_debug(2, "Returning instance number\n");
- s5p_mfc_clean_ctx_int_flags(ctx);
- if (ctx->state == MFCINST_FREE) {
- mfc_err_ctx("ctx already free status\n");
- return ret;
- }
-
- ret = s5p_mfc_cmd_close_inst(ctx);
- if (ret) {
- mfc_err_ctx("Failed to return an instance\n");
- s5p_mfc_change_state(ctx, MFCINST_ERROR);
- }
-
- return ret;
-}
-
-int s5p_mfc_abort_inst(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev;
-
- if (!ctx) {
- mfc_err_dev("no mfc context to run\n");
- return -EINVAL;
- }
-
- dev = ctx->dev;
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
-
- s5p_mfc_clean_ctx_int_flags(ctx);
-
- MFC_WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID);
- s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_NAL_ABORT);
-
- return 0;
-}
-
-/* Initialize decoding */
-int s5p_mfc_init_decode(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev;
- struct s5p_mfc_dec *dec;
- unsigned int reg = 0;
- int fmo_aso_ctrl = 0;
-
- mfc_debug_enter();
- if (!ctx) {
- mfc_err_dev("no mfc context to run\n");
- return -EINVAL;
- }
-
- dev = ctx->dev;
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
-
- dec = ctx->dec_priv;
- if (!dec) {
- mfc_err_dev("no mfc decoder to run\n");
- return -EINVAL;
- }
- mfc_debug(2, "InstNo: %d/%d\n", ctx->inst_no, S5P_FIMV_H2R_CMD_SEQ_HEADER);
- mfc_debug(2, "BUFs: %08x\n", MFC_READL(S5P_FIMV_D_CPB_BUFFER_ADDR));
-
- /* When user sets desplay_delay to 0,
- * It works as "display_delay enable" and delay set to 0.
- * If user wants display_delay disable, It should be
- * set to negative value. */
- if (dec->display_delay >= 0) {
- reg |= (0x1 << S5P_FIMV_D_DEC_OPT_DISPLAY_DELAY_EN_SHIFT);
- MFC_WRITEL(dec->display_delay, S5P_FIMV_D_DISPLAY_DELAY);
- }
-
- /* FMO_ASO_CTRL - 0: Enable, 1: Disable */
- reg |= ((fmo_aso_ctrl & S5P_FIMV_D_DEC_OPT_FMO_ASO_CTRL_MASK)
- << S5P_FIMV_D_DEC_OPT_FMO_ASO_CTRL_SHIFT);
-
- reg |= ((dec->idr_decoding & S5P_FIMV_D_DEC_OPT_IDR_DECODING_MASK)
- << S5P_FIMV_D_DEC_OPT_IDR_DECODING_SHIFT);
-
- /* VC1 RCV: Discard to parse additional header as default */
- if (IS_VC1_RCV_DEC(ctx))
- reg |= (0x1 << S5P_FIMV_D_DEC_OPT_DISCARD_RCV_HEADER_SHIFT);
-
- /* conceal control to specific color */
- reg |= (0x4 << S5P_FIMV_D_DEC_OPT_CONCEAL_CONTROL_SHIFT);
-
- /* Disable parallel processing if nal_q_parallel_disable was set */
- if (nal_q_parallel_disable)
- reg |= (0x2 << S5P_FIMV_D_DEC_OPT_PARALLEL_DISABLE_SHIFT);
-
- /* Realloc buffer for resolution decrease case in NAL QUEUE mode */
- reg |= (0x1 << S5P_FIMV_D_DEC_OPT_REALLOC_CONTROL_SHIFT);
-
- /* Parsing all including PPS */
- reg |= (0x1 << S5P_FIMV_D_DEC_OPT_SPECIAL_PARSING_SHIFT);
-
- MFC_WRITEL(reg, S5P_FIMV_D_DEC_OPTIONS);
-
- MFC_WRITEL(MFC_CONCEAL_COLOR, S5P_FIMV_D_FORCE_PIXEL_VAL);
-
- if (IS_FIMV1_DEC(ctx)) {
- mfc_debug(2, "Setting FIMV1 resolution to %dx%d\n",
- ctx->img_width, ctx->img_height);
- MFC_WRITEL(ctx->img_width, S5P_FIMV_D_SET_FRAME_WIDTH);
- MFC_WRITEL(ctx->img_height, S5P_FIMV_D_SET_FRAME_HEIGHT);
- }
-
- s5p_mfc_set_pixel_format(dev, ctx->dst_fmt->fourcc);
-
- reg = 0;
- /* Enable realloc interface if SEI is enabled */
- if (dec->sei_parse)
- reg |= (0x1 << S5P_FIMV_D_SEI_ENABLE_NEED_INIT_BUFFER_SHIFT);
- if (MFC_FEATURE_SUPPORT(dev, dev->pdata->static_info_dec)) {
- reg |= (0x1 << S5P_FIMV_D_SEI_ENABLE_CONTENT_LIGHT_SHIFT);
- reg |= (0x1 << S5P_FIMV_D_SEI_ENABLE_MASTERING_DISPLAY_SHIFT);
- }
- reg |= (0x1 << S5P_FIMV_D_SEI_ENABLE_RECOVERY_PARSING_SHIFT);
-
- MFC_WRITEL(reg, S5P_FIMV_D_SEI_ENABLE);
- mfc_debug(2, "SEI enable was set, 0x%x\n", MFC_READL(S5P_FIMV_D_SEI_ENABLE));
-
- MFC_WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID);
-
- if (sfr_dump & MFC_DUMP_DEC_SEQ_START)
- call_dop(dev, dump_regs, dev);
-
- s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_SEQ_HEADER);
-
- mfc_debug_leave();
- return 0;
-}
-
-/* Decode a single frame */
-int s5p_mfc_decode_one_frame(struct s5p_mfc_ctx *ctx, int last_frame)
-{
- struct s5p_mfc_dev *dev;
- struct s5p_mfc_dec *dec;
- u32 reg = 0;
-
- if (!ctx) {
- mfc_err_dev("no mfc context to run\n");
- return -EINVAL;
- }
-
- dev = ctx->dev;
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
-
- dec = ctx->dec_priv;
- if (!dec) {
- mfc_err_dev("no mfc decoder to run\n");
- return -EINVAL;
- }
-
- mfc_debug(2, "Dynamic:0x%08x, Available:0x%lx\n",
- dec->dynamic_set, dec->available_dpb);
-
- reg = MFC_READL(S5P_FIMV_D_NAL_START_OPTIONS);
- reg &= ~(0x1 << S5P_FIMV_D_NAL_START_OPT_BLACK_BAR_SHIFT);
- reg |= ((dec->detect_black_bar & 0x1) << S5P_FIMV_D_NAL_START_OPT_BLACK_BAR_SHIFT);
- MFC_WRITEL(reg, S5P_FIMV_D_NAL_START_OPTIONS);
- mfc_debug(3, "[BLACKBAR] black bar detect set: %#x\n", reg);
-
- MFC_WRITEL(dec->dynamic_set, S5P_FIMV_D_DYNAMIC_DPB_FLAG_LOWER);
- MFC_WRITEL(0x0, S5P_FIMV_D_DYNAMIC_DPB_FLAG_UPPER);
- MFC_WRITEL(dec->available_dpb, S5P_FIMV_D_AVAILABLE_DPB_FLAG_LOWER);
- MFC_WRITEL(0x0, S5P_FIMV_D_AVAILABLE_DPB_FLAG_UPPER);
- MFC_WRITEL(dec->slice_enable, S5P_FIMV_D_SLICE_IF_ENABLE);
- MFC_WRITEL(MFC_TIMEOUT_VALUE, S5P_FIMV_DEC_TIMEOUT_VALUE);
-
- MFC_WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID);
-
- if ((sfr_dump & MFC_DUMP_DEC_NAL_START) && !ctx->check_dump) {
- call_dop(dev, dump_regs, dev);
- ctx->check_dump = 1;
- }
-
- /* Issue different commands to instance basing on whether it
- * is the last frame or not. */
- switch (last_frame) {
- case 0:
- s5p_mfc_perf_measure_on(dev);
-
- s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_NAL_START);
- break;
- case 1:
- s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_LAST_FRAME);
- break;
- }
-
- mfc_debug(2, "Decoding a usual frame\n");
- return 0;
-}
-
-int s5p_mfc_init_encode(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
-
- mfc_debug(2, "++\n");
-
- if (IS_H264_ENC(ctx))
- s5p_mfc_set_enc_params_h264(ctx);
- else if (IS_MPEG4_ENC(ctx))
- s5p_mfc_set_enc_params_mpeg4(ctx);
- else if (IS_H263_ENC(ctx))
- s5p_mfc_set_enc_params_h263(ctx);
- else if (IS_VP8_ENC(ctx))
- s5p_mfc_set_enc_params_vp8(ctx);
- else if (IS_VP9_ENC(ctx))
- s5p_mfc_set_enc_params_vp9(ctx);
- else if (IS_HEVC_ENC(ctx))
- s5p_mfc_set_enc_params_hevc(ctx);
- else if (IS_BPG_ENC(ctx))
- s5p_mfc_set_enc_params_bpg(ctx);
- else {
- mfc_err_ctx("Unknown codec for encoding (%x)\n",
- ctx->codec_mode);
- return -EINVAL;
- }
-
- mfc_debug(5, "RC) Bitrate: %d / framerate: %#x / config %#x / mode %#x\n",
- MFC_READL(S5P_FIMV_E_RC_BIT_RATE),
- MFC_READL(S5P_FIMV_E_RC_FRAME_RATE),
- MFC_READL(S5P_FIMV_E_RC_CONFIG),
- MFC_READL(S5P_FIMV_E_RC_MODE));
-
- MFC_WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID);
-
- if (sfr_dump & MFC_DUMP_ENC_SEQ_START)
- call_dop(dev, dump_regs, dev);
-
- s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_SEQ_HEADER);
-
- mfc_debug(2, "--\n");
-
- return 0;
-}
-
-static int mfc_h264_set_aso_slice_order(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_enc *enc = ctx->enc_priv;
- struct s5p_mfc_enc_params *p = &enc->params;
- struct s5p_mfc_h264_enc_params *p_264 = &p->codec.h264;
- int i;
-
- if (p_264->aso_enable) {
- for (i = 0; i < 8; i++)
- MFC_WRITEL(p_264->aso_slice_order[i],
- S5P_FIMV_E_H264_ASO_SLICE_ORDER_0 + i * 4);
- }
- return 0;
-}
-
-/* Encode a single frame */
-int s5p_mfc_encode_one_frame(struct s5p_mfc_ctx *ctx, int last_frame)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
-
- mfc_debug(2, "++\n");
-
- if (IS_H264_ENC(ctx))
- mfc_h264_set_aso_slice_order(ctx);
-
- s5p_mfc_set_slice_mode(ctx);
-
- MFC_WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID);
-
- if ((sfr_dump & MFC_DUMP_ENC_NAL_START) && !ctx->check_dump) {
- call_dop(dev, dump_regs, dev);
- ctx->check_dump = 1;
- }
-
- /* Issue different commands to instance basing on whether it
- * is the last frame or not. */
- switch (last_frame) {
- case 0:
- s5p_mfc_perf_measure_on(dev);
-
- s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_NAL_START);
- break;
- case 1:
- s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_LAST_FRAME);
- break;
- }
-
- mfc_debug(2, "--\n");
-
- return 0;
-}
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_inst.h
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __S5P_MFC_INST_H
-#define __S5P_MFC_INST_H __FILE__
-
-#include "s5p_mfc_common.h"
-
-int s5p_mfc_open_inst(struct s5p_mfc_ctx *ctx);
-int s5p_mfc_close_inst(struct s5p_mfc_ctx *ctx);
-int s5p_mfc_abort_inst(struct s5p_mfc_ctx *ctx);
-
-int s5p_mfc_init_decode(struct s5p_mfc_ctx *ctx);
-int s5p_mfc_decode_one_frame(struct s5p_mfc_ctx *ctx, int last_frame);
-
-int s5p_mfc_init_encode(struct s5p_mfc_ctx *ctx);
-int s5p_mfc_encode_one_frame(struct s5p_mfc_ctx *ctx, int last_frame);
-
-#endif /* __S5P_MFC_INST_H */
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_irq.c
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include "s5p_mfc_irq.h"
-
-#include "s5p_mfc_hwlock.h"
-#include "s5p_mfc_nal_q.h"
-#include "s5p_mfc_otf.h"
-#include "s5p_mfc_opr.h"
-#include "s5p_mfc_sync.h"
-
-#include "s5p_mfc_pm.h"
-#include "s5p_mfc_cal.h"
-#include "s5p_mfc_perf_measure.h"
-#include "s5p_mfc_reg.h"
-#include "s5p_mfc_mmcache.h"
-
-#include "s5p_mfc_qos.h"
-#include "s5p_mfc_queue.h"
-#include "s5p_mfc_buf.h"
-#include "s5p_mfc_mem.h"
-
-static void mfc_handle_black_bar_info(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx)
-{
- struct v4l2_rect new_black_bar;
- int black_bar_info;
- struct s5p_mfc_dec *dec = ctx->dec_priv;
-
- black_bar_info = s5p_mfc_get_black_bar_detection();
- mfc_debug(3, "[BLACKBAR] type: %#x\n", black_bar_info);
-
- if (black_bar_info == S5P_FIMV_DISP_STATUS_BLACK_BAR) {
- new_black_bar.left = s5p_mfc_get_black_bar_pos_x();
- new_black_bar.top = s5p_mfc_get_black_bar_pos_y();
- new_black_bar.width = s5p_mfc_get_black_bar_image_w();
- new_black_bar.height = s5p_mfc_get_black_bar_image_h();
- } else if (black_bar_info == S5P_FIMV_DISP_STATUS_BLACK_SCREEN) {
- new_black_bar.left = -1;
- new_black_bar.top = -1;
- new_black_bar.width = ctx->img_width;
- new_black_bar.height = ctx->img_height;
- } else if (black_bar_info == S5P_FIMV_DISP_STATUS_NOT_DETECTED) {
- new_black_bar.left = 0;
- new_black_bar.top = 0;
- new_black_bar.width = ctx->img_width;
- new_black_bar.height = ctx->img_height;
- } else {
- mfc_err_ctx("[BLACKBAR] Not supported type: %#x\n", black_bar_info);
- dec->black_bar_updated = 0;
- return;
- }
-
- if ((new_black_bar.left == dec->black_bar.left) &&
- (new_black_bar.top == dec->black_bar.top) &&
- (new_black_bar.width == dec->black_bar.width) &&
- (new_black_bar.height == dec->black_bar.height)) {
- mfc_debug(4, "[BLACKBAR] information was not changed\n");
- dec->black_bar_updated = 0;
- return;
- }
-
- dec->black_bar = new_black_bar;
- dec->black_bar_updated = 1;
-}
-
-static unsigned int mfc_handle_frame_field(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- unsigned int interlace_type = 0, is_interlace = 0, is_mbaff = 0;
- unsigned int field;
-
- if (CODEC_INTERLACED(ctx))
- is_interlace = s5p_mfc_is_interlace_picture();
-
- if (CODEC_MBAFF(ctx))
- is_mbaff = s5p_mfc_is_mbaff_picture();
-
- if (is_interlace) {
- interlace_type = s5p_mfc_get_interlace_type();
- if (interlace_type)
- field = V4L2_FIELD_INTERLACED_TB;
- else
- field = V4L2_FIELD_INTERLACED_BT;
- } else if (is_mbaff) {
- field = V4L2_FIELD_INTERLACED_TB;
- } else {
- field = V4L2_FIELD_NONE;
- }
-
- mfc_debug(2, "[INTERLACE] is_interlace: %d (type : %d), is_mbaff: %d, field: 0x%#x\n",
- is_interlace, interlace_type, is_mbaff, field);
-
- return field;
-}
-
-static void mfc_handle_frame_all_extracted(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dec *dec = ctx->dec_priv;
- struct s5p_mfc_buf *dst_mb;
- int index, i, is_first = 1;
-
- mfc_debug(2, "Decided to finish\n");
- ctx->sequence++;
-
- while (1) {
- dst_mb = s5p_mfc_get_del_buf(&ctx->buf_queue_lock, &ctx->dst_buf_queue, MFC_BUF_NO_TOUCH_USED);
- if (!dst_mb)
- break;
-
- mfc_debug(2, "Cleaning up buffer: %d\n",
- dst_mb->vb.vb2_buf.index);
-
- index = dst_mb->vb.vb2_buf.index;
-
- for (i = 0; i < ctx->dst_fmt->mem_planes; i++)
- vb2_set_plane_payload(&dst_mb->vb.vb2_buf, i, 0);
-
- dst_mb->vb.sequence = (ctx->sequence++);
- dst_mb->vb.field = mfc_handle_frame_field(ctx);
- dst_mb->vb.reserved2 = 0;
-
- clear_bit(dst_mb->vb.vb2_buf.index, &dec->available_dpb);
-
- if (call_cop(ctx, get_buf_ctrls_val, ctx, &ctx->dst_ctrls[index]) < 0)
- mfc_err_ctx("failed in get_buf_ctrls_val\n");
-
- if (is_first) {
- call_cop(ctx, get_buf_update_val, ctx,
- &ctx->dst_ctrls[index],
- V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG,
- dec->stored_tag);
- is_first = 0;
- } else {
- call_cop(ctx, get_buf_update_val, ctx,
- &ctx->dst_ctrls[index],
- V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG,
- DEFAULT_TAG);
- call_cop(ctx, get_buf_update_val, ctx,
- &ctx->dst_ctrls[index],
- V4L2_CID_MPEG_VIDEO_H264_SEI_FP_AVAIL,
- 0);
- }
-
- vb2_buffer_done(&dst_mb->vb.vb2_buf, VB2_BUF_STATE_DONE);
-
- /* decoder dst buffer CFW UNPROT */
- if (ctx->is_drm)
- s5p_mfc_raw_unprotect(ctx, dst_mb, index);
-
- mfc_debug(2, "Cleaned up buffer: %d\n", index);
- }
-
- s5p_mfc_handle_force_change_status(ctx);
- mfc_debug(2, "After cleanup\n");
-}
-
-static void mfc_handle_frame_copy_timestamp(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_buf *ref_mb, *src_mb;
- dma_addr_t dec_y_addr;
-
- dec_y_addr = (dma_addr_t)s5p_mfc_get_dec_y_addr();
-
- /* Get the source buffer */
- src_mb = s5p_mfc_get_buf(&ctx->buf_queue_lock, &ctx->src_buf_queue, MFC_BUF_NO_TOUCH_USED);
- if (!src_mb) {
- mfc_err_dev("[TS] no src buffers\n");
- return;
- }
-
- ref_mb = s5p_mfc_find_buf(&ctx->buf_queue_lock, &ctx->ref_buf_queue, dec_y_addr);
- if (ref_mb)
- ref_mb->vb.vb2_buf.timestamp = src_mb->vb.vb2_buf.timestamp;
-}
-
-static void mfc_handle_frame_output_move(struct s5p_mfc_ctx *ctx,
- dma_addr_t dspl_y_addr, unsigned int released_flag)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_dec *dec = ctx->dec_priv;
- struct s5p_mfc_buf *ref_mb;
- int index;
-
- ref_mb = s5p_mfc_find_move_buf(&ctx->buf_queue_lock,
- &ctx->dst_buf_queue, &ctx->ref_buf_queue, dspl_y_addr, released_flag);
- if (ref_mb) {
- index = ref_mb->vb.vb2_buf.index;
-
- /* Check if this is the buffer we're looking for */
- mfc_debug(2, "[DPB] Found buf[%d] 0x%08llx, looking for disp addr 0x%08llx\n",
- index, ref_mb->addr[0][0], dspl_y_addr);
-
- if (released_flag & (1 << index)) {
- dec->available_dpb &= ~(1 << index);
- released_flag &= ~(1 << index);
- mfc_debug(2, "[DPB] Corrupted frame(%d), it will be re-used(release)\n",
- s5p_mfc_get_warn(s5p_mfc_get_int_err()));
- } else {
- dec->err_reuse_flag |= 1 << index;
- mfc_debug(2, "[DPB] Corrupted frame(%d), it will be re-used(not released)\n",
- s5p_mfc_get_warn(s5p_mfc_get_int_err()));
- }
- dec->dynamic_used |= released_flag;
- }
-}
-
-static void mfc_handle_frame_output_del(struct s5p_mfc_ctx *ctx,
- unsigned int err, unsigned int released_flag)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_dec *dec = ctx->dec_priv;
- struct s5p_mfc_raw_info *raw = &ctx->raw_buf;
- struct s5p_mfc_buf *ref_mb;
- dma_addr_t dspl_y_addr;
- unsigned int frame_type;
- unsigned int dst_frame_status;
- unsigned int is_video_signal_type = 0, is_colour_description = 0;
- unsigned int is_content_light = 0, is_display_colour = 0;
- unsigned int i, index;
-
- if (MFC_FEATURE_SUPPORT(dev, dev->pdata->color_aspect_dec)) {
- is_video_signal_type = s5p_mfc_get_video_signal_type();
- is_colour_description = s5p_mfc_get_colour_description();
- }
-
- if (MFC_FEATURE_SUPPORT(dev, dev->pdata->static_info_dec)) {
- is_content_light = s5p_mfc_get_sei_avail_content_light();
- is_display_colour = s5p_mfc_get_sei_avail_mastering_display();
- }
-
- if (MFC_FEATURE_SUPPORT(dev, dev->pdata->black_bar) && dec->detect_black_bar)
- mfc_handle_black_bar_info(dev, ctx);
- else
- dec->black_bar_updated = 0;
-
- if (dec->immediate_display == 1) {
- dspl_y_addr = (dma_addr_t)s5p_mfc_get_dec_y_addr();
- frame_type = s5p_mfc_get_dec_frame_type();
- } else {
- dspl_y_addr = (dma_addr_t)s5p_mfc_get_disp_y_addr();
- frame_type = s5p_mfc_get_disp_frame_type();
- }
-
- ref_mb = s5p_mfc_find_del_buf(&ctx->buf_queue_lock,
- &ctx->ref_buf_queue, dspl_y_addr);
- if (ref_mb) {
- index = ref_mb->vb.vb2_buf.index;
- /* Check if this is the buffer we're looking for */
- mfc_debug(2, "[BUFINFO][DPB] ctx[%d] get dst index: %d, addr[0]: 0x%08llx\n",
- ctx->num, index, ref_mb->addr[0][0]);
-
- ref_mb->vb.sequence = ctx->sequence;
- ref_mb->vb.field = mfc_handle_frame_field(ctx);
-
- /* Set reserved2 bits in order to inform SEI information */
- ref_mb->vb.reserved2 = 0;
-
- if (is_content_light) {
- ref_mb->vb.reserved2 |= (1 << 0);
- mfc_debug(2, "[HDR] content light level parsed\n");
- }
-
- if (is_display_colour) {
- ref_mb->vb.reserved2 |= (1 << 1);
- mfc_debug(2, "[HDR] mastering display colour parsed\n");
- }
-
- if (is_video_signal_type) {
- ref_mb->vb.reserved2 |= (1 << 4);
- mfc_debug(2, "[HDR] video signal type parsed\n");
- if (is_colour_description) {
- ref_mb->vb.reserved2 |= (1 << 2);
- mfc_debug(2, "[HDR] matrix coefficients parsed\n");
- ref_mb->vb.reserved2 |= (1 << 3);
- mfc_debug(2, "[HDR] colour description parsed\n");
- }
- }
-
- if (IS_VP9_DEC(ctx) && MFC_FEATURE_SUPPORT(dev, dev->pdata->color_aspect_dec)) {
- if (dec->color_space != S5P_FIMV_D_COLOR_UNKNOWN) {
- ref_mb->vb.reserved2 |= (1 << 3);
- mfc_debug(2, "[HDR] color space parsed\n");
- }
- ref_mb->vb.reserved2 |= (1 << 4);
- mfc_debug(2, "[HDR] color range parsed\n");
- }
-
- if (dec->black_bar_updated) {
- ref_mb->vb.reserved2 |= (1 << 5);
- mfc_debug(3, "[BLACKBAR] black bar detected\n");
- }
-
- if (ctx->src_fmt->mem_planes == 1) {
- vb2_set_plane_payload(&ref_mb->vb.vb2_buf, 0,
- raw->total_plane_size);
- mfc_debug(5, "single plane payload: %d\n",
- raw->total_plane_size);
- } else {
- for (i = 0; i < ctx->src_fmt->mem_planes; i++) {
- vb2_set_plane_payload(&ref_mb->vb.vb2_buf, i,
- raw->plane_size[i]);
- }
- }
-
- clear_bit(index, &dec->available_dpb);
-
- ref_mb->vb.flags &= ~(V4L2_BUF_FLAG_KEYFRAME |
- V4L2_BUF_FLAG_PFRAME |
- V4L2_BUF_FLAG_BFRAME |
- V4L2_BUF_FLAG_ERROR);
-
- switch (frame_type) {
- case S5P_FIMV_DISPLAY_FRAME_I:
- ref_mb->vb.flags |= V4L2_BUF_FLAG_KEYFRAME;
- break;
- case S5P_FIMV_DISPLAY_FRAME_P:
- ref_mb->vb.flags |= V4L2_BUF_FLAG_PFRAME;
- break;
- case S5P_FIMV_DISPLAY_FRAME_B:
- ref_mb->vb.flags |= V4L2_BUF_FLAG_BFRAME;
- break;
- default:
- break;
- }
-
- if (s5p_mfc_get_warn(err)) {
- mfc_err_ctx("Warning for displayed frame: %d\n",
- s5p_mfc_get_warn(err));
- ref_mb->vb.flags |= V4L2_BUF_FLAG_ERROR;
- }
-
- if (call_cop(ctx, get_buf_ctrls_val, ctx, &ctx->dst_ctrls[index]) < 0)
- mfc_err_ctx("failed in get_buf_ctrls_val\n");
-
- s5p_mfc_handle_released_info(ctx, released_flag, index);
-
- if (dec->immediate_display == 1) {
- dst_frame_status = s5p_mfc_get_dec_status();
-
- call_cop(ctx, get_buf_update_val, ctx,
- &ctx->dst_ctrls[index],
- V4L2_CID_MPEG_MFC51_VIDEO_DISPLAY_STATUS,
- dst_frame_status);
-
- call_cop(ctx, get_buf_update_val, ctx,
- &ctx->dst_ctrls[index],
- V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG,
- dec->stored_tag);
-
- dec->immediate_display = 0;
- }
-
- /* Update frame tag for packed PB */
- if (CODEC_MULTIFRAME(ctx) && (dec->y_addr_for_pb == dspl_y_addr)) {
- call_cop(ctx, get_buf_update_val, ctx,
- &ctx->dst_ctrls[index],
- V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG,
- dec->stored_tag);
- dec->y_addr_for_pb = 0;
- }
-
- s5p_mfc_qos_update_last_framerate(ctx, ref_mb->vb.vb2_buf.timestamp);
- vb2_buffer_done(&ref_mb->vb.vb2_buf, s5p_mfc_get_warn(err) ?
- VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
- }
-}
-
-static void mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err)
-{
- struct s5p_mfc_dec *dec = ctx->dec_priv;
- struct s5p_mfc_dev *dev = ctx->dev;
- dma_addr_t dspl_y_addr;
- unsigned int frame_type;
- int mvc_view_id;
- unsigned int prev_flag, released_flag = 0;
-
- frame_type = s5p_mfc_get_disp_frame_type();
- mvc_view_id = s5p_mfc_get_mvc_disp_view_id();
-
- if (IS_H264_MVC_DEC(ctx)) {
- if (mvc_view_id == 0)
- ctx->sequence++;
- } else {
- ctx->sequence++;
- }
-
- dspl_y_addr = s5p_mfc_get_disp_y_addr();
-
- if (dec->immediate_display == 1) {
- dspl_y_addr = (dma_addr_t)s5p_mfc_get_dec_y_addr();
- frame_type = s5p_mfc_get_dec_frame_type();
- }
-
- mfc_debug(2, "[FRAME] frame type: %d\n", frame_type);
-
- /* If frame is same as previous then skip and do not dequeue */
- if (frame_type == S5P_FIMV_DISPLAY_FRAME_NOT_CODED)
- if (!CODEC_NOT_CODED(ctx))
- return;
-
- prev_flag = dec->dynamic_used;
- dec->dynamic_used = s5p_mfc_get_dec_used_flag();
- released_flag = prev_flag & (~dec->dynamic_used);
-
- mfc_debug(2, "[DPB] Used flag: old = %08x, new = %08x, Released buffer = %08x\n",
- prev_flag, dec->dynamic_used, released_flag);
-
- /* decoder dst buffer CFW UNPROT */
- s5p_mfc_unprotect_released_dpb(ctx, released_flag);
-
- if ((IS_VC1_RCV_DEC(ctx) &&
- s5p_mfc_get_warn(err) == S5P_FIMV_ERR_SYNC_POINT_NOT_RECEIVED) ||
- (s5p_mfc_get_warn(err) == S5P_FIMV_ERR_BROKEN_LINK))
- mfc_handle_frame_output_move(ctx, dspl_y_addr, released_flag);
- else
- mfc_handle_frame_output_del(ctx, err, released_flag);
-}
-
-static void mfc_handle_frame_error(struct s5p_mfc_ctx *ctx,
- unsigned int reason, unsigned int err)
-{
- struct s5p_mfc_dec *dec;
- struct s5p_mfc_buf *src_mb;
- unsigned int index;
-
- if (ctx->type == MFCINST_ENCODER) {
- mfc_err_ctx("Encoder Interrupt Error: %d\n", err);
- return;
- }
-
- dec = ctx->dec_priv;
- if (!dec) {
- mfc_err_dev("no mfc decoder to run\n");
- return;
- }
-
- mfc_err_ctx("Interrupt Error: %d\n", err);
-
- /* Get the source buffer */
- src_mb = s5p_mfc_get_del_buf(&ctx->buf_queue_lock, &ctx->src_buf_queue, MFC_BUF_NO_TOUCH_USED);
-
- if (!src_mb) {
- mfc_err_dev("no src buffers\n");
- } else {
- index = src_mb->vb.vb2_buf.index;
- if (call_cop(ctx, recover_buf_ctrls_val, ctx, &ctx->src_ctrls[index]) < 0)
- mfc_err_ctx("failed in recover_buf_ctrls_val\n");
-
- mfc_debug(2, "MFC needs next buffer\n");
- dec->consumed = 0;
-
- if (call_cop(ctx, get_buf_ctrls_val, ctx, &ctx->src_ctrls[index]) < 0)
- mfc_err_ctx("failed in get_buf_ctrls_val\n");
-
- /* decoder src buffer CFW UNPROT */
- if (ctx->is_drm)
- s5p_mfc_stream_unprotect(ctx, src_mb, index);
-
- vb2_buffer_done(&src_mb->vb.vb2_buf, VB2_BUF_STATE_ERROR);
- }
-
- mfc_debug(2, "Assesing whether this context should be run again\n");
-}
-
-static void mfc_handle_ref_frame(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_dec *dec = ctx->dec_priv;
- struct s5p_mfc_buf *dst_mb;
- dma_addr_t dec_addr;
-
- dec_addr = (dma_addr_t)s5p_mfc_get_dec_y_addr();
-
- /* Try to search decoded address in whole dst queue */
- dst_mb = s5p_mfc_find_move_buf_used(&ctx->buf_queue_lock,
- &ctx->ref_buf_queue, &ctx->dst_buf_queue, dec_addr);
- if (dst_mb) {
- mfc_debug(2, "[DPB] Found in dst queue = 0x%08llx, buf = 0x%08llx\n",
- dec_addr, dst_mb->addr[0][0]);
-
- if (!(dec->dynamic_set & s5p_mfc_get_dec_used_flag()))
- dec->dynamic_used |= dec->dynamic_set;
- } else {
- mfc_debug(2, "[DPB] Can't find buffer for addr = 0x%08llx\n", dec_addr);
- }
-}
-
-static void mfc_handle_reuse_buffer(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_dec *dec = ctx->dec_priv;
- unsigned int prev_flag, released_flag = 0;
- int i;
-
- prev_flag = dec->dynamic_used;
- dec->dynamic_used = s5p_mfc_get_dec_used_flag();
- released_flag = prev_flag & (~dec->dynamic_used);
-
- if (!released_flag)
- return;
-
- /* Reuse not referenced buf anymore */
- for (i = 0; i < MFC_MAX_DPBS; i++)
- if (released_flag & (1 << i))
- if (s5p_mfc_move_reuse_buffer(ctx, i))
- released_flag &= ~(1 << i);
-
- /* Not reused buffer should be released when there is a display frame */
- dec->dec_only_release_flag |= released_flag;
- for (i = 0; i < MFC_MAX_DPBS; i++)
- if (released_flag & (1 << i))
- clear_bit(i, &dec->available_dpb);
-}
-
-static void mfc_handle_frame_input(struct s5p_mfc_ctx *ctx, unsigned int err)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_dec *dec = ctx->dec_priv;
- struct s5p_mfc_buf *src_mb;
- unsigned int index;
- int deleted = 0;
- unsigned long consumed;
-
- consumed = dec->consumed + s5p_mfc_get_consumed_stream();
-
- if (s5p_mfc_get_err(err) == S5P_FIMV_ERR_NON_PAIRED_FIELD) {
- /*
- * For non-paired field, the same buffer need to be
- * resubmitted and the consumed stream will be 0
- */
- mfc_debug(2, "Not paired field. Running again the same buffer\n");
- return;
- }
-
- /* Get the source buffer */
- src_mb = s5p_mfc_get_del_if_consumed(ctx, &ctx->src_buf_queue,
- s5p_mfc_get_consumed_stream(), STUFF_BYTE, err, &deleted);
- if (!src_mb) {
- mfc_err_dev("no src buffers\n");
- return;
- }
-
- index = src_mb->vb.vb2_buf.index;
- mfc_debug(2, "[BUFINFO] ctx[%d] get src index: %d, addr: 0x%08llx\n",
- ctx->num, index, src_mb->addr[0][0]);
-
- if (!deleted) {
- /* Run MFC again on the same buffer */
- mfc_debug(2, "[MULTIFRAME] Running again the same buffer\n");
-
- if (CODEC_MULTIFRAME(ctx))
- dec->y_addr_for_pb = (dma_addr_t)s5p_mfc_get_dec_y_addr();
-
- dec->consumed = consumed;
- dec->remained_size = src_mb->vb.vb2_buf.planes[0].bytesused
- - dec->consumed;
- dec->has_multiframe = 1;
-
- MFC_TRACE_CTX("** consumed:%ld, remained:%ld, addr:0x%08llx\n",
- dec->consumed, dec->remained_size, dec->y_addr_for_pb);
- /* Do not move src buffer to done_list */
- return;
- }
-
- if (call_cop(ctx, recover_buf_ctrls_val, ctx, &ctx->src_ctrls[index]) < 0)
- mfc_err_ctx("failed in recover_buf_ctrls_val\n");
-
- dec->consumed = 0;
- dec->remained_size = 0;
-
- if (call_cop(ctx, get_buf_ctrls_val, ctx, &ctx->src_ctrls[index]) < 0)
- mfc_err_ctx("failed in get_buf_ctrls_val\n");
-
- /* decoder src buffer CFW UNPROT */
- if (ctx->is_drm)
- s5p_mfc_stream_unprotect(ctx, src_mb, index);
-
- vb2_buffer_done(&src_mb->vb.vb2_buf, VB2_BUF_STATE_DONE);
-}
-
-/* Handle frame decoding interrupt */
-static void mfc_handle_frame(struct s5p_mfc_ctx *ctx,
- unsigned int reason, unsigned int err)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_dec *dec = ctx->dec_priv;
- unsigned int dst_frame_status, sei_avail_frame_pack;
- unsigned int res_change, need_dpb_change, need_scratch_change;
-
- dst_frame_status = s5p_mfc_get_disp_status();
- res_change = s5p_mfc_get_res_change();
- need_dpb_change = s5p_mfc_get_dpb_change();
- need_scratch_change = s5p_mfc_get_scratch_change();
- sei_avail_frame_pack = s5p_mfc_get_sei_avail_frame_pack();
-
- if (dec->immediate_display == 1)
- dst_frame_status = s5p_mfc_get_dec_status();
-
- mfc_debug(2, "[FRAME] frame status: %d\n", dst_frame_status);
- mfc_debug(2, "[FRAME] display status: %d, type: %d, yaddr: %#x\n",
- s5p_mfc_get_disp_status(), s5p_mfc_get_disp_frame_type(),
- s5p_mfc_get_disp_y_addr());
- mfc_debug(2, "[FRAME] decoded status: %d, type: %d, yaddr: %#x\n",
- s5p_mfc_get_dec_status(), s5p_mfc_get_dec_frame_type(),
- s5p_mfc_get_dec_y_addr());
-
- mfc_debug(4, "[HDR] SEI available status: 0x%08x\n", s5p_mfc_get_sei_avail());
- mfc_debug(4, "[HDR] SEI content light: 0x%08x\n", s5p_mfc_get_sei_content_light());
- mfc_debug(4, "[HDR] SEI luminance: 0x%08x, 0x%08x white point: 0x%08x\n",
- s5p_mfc_get_sei_mastering0(), s5p_mfc_get_sei_mastering1(),
- s5p_mfc_get_sei_mastering2());
- mfc_debug(4, "[HDR] SEI display primaries: 0x%08x, 0x%08x, 0x%08x\n",
- s5p_mfc_get_sei_mastering3(), s5p_mfc_get_sei_mastering4(),
- s5p_mfc_get_sei_mastering5());
- mfc_debug(2, "[DPB] Used flag: old = %08x, new = %08x\n",
- dec->dynamic_used, s5p_mfc_get_dec_used_flag());
-
- if (ctx->state == MFCINST_RES_CHANGE_INIT)
- s5p_mfc_change_state(ctx, MFCINST_RES_CHANGE_FLUSH);
-
- if (res_change) {
- mfc_debug(2, "[DRC] Resolution change set to %d\n", res_change);
- s5p_mfc_change_state(ctx, MFCINST_RES_CHANGE_INIT);
- ctx->wait_state = WAIT_DECODING;
- mfc_debug(7, "[DRC] Decoding waiting! : %d\n", ctx->wait_state);
- return;
- }
-
- if (need_dpb_change || need_scratch_change)
- mfc_debug(2, "[DRC] Interframe resolution change is not supported\n");
-
- if (s5p_mfc_is_queue_count_same(&ctx->buf_queue_lock, &ctx->src_buf_queue, 0) &&
- s5p_mfc_is_queue_count_same(&ctx->buf_queue_lock, &ctx->dst_buf_queue, 0)) {
- mfc_err_dev("Queue count is zero for src and dst\n");
- goto leave_handle_frame;
- }
-
- if (IS_H264_DEC(ctx) && sei_avail_frame_pack &&
- dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_ONLY) {
- mfc_debug(2, "Frame packing SEI exists for a frame\n");
- mfc_debug(2, "Reallocate DPBs and issue init_buffer\n");
- ctx->is_dpb_realloc = 1;
- s5p_mfc_change_state(ctx, MFCINST_HEAD_PARSED);
- ctx->capture_state = QUEUE_FREE;
- ctx->wait_state = WAIT_DECODING;
- mfc_handle_frame_all_extracted(ctx);
- goto leave_handle_frame;
- }
-
- /* All frames remaining in the buffer have been extracted */
- if (dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_EMPTY) {
- if (ctx->state == MFCINST_RES_CHANGE_FLUSH) {
- struct mfc_timestamp *temp_ts = NULL;
-
- mfc_debug(2, "[DRC] Last frame received after resolution change\n");
- mfc_handle_frame_all_extracted(ctx);
- s5p_mfc_change_state(ctx, MFCINST_RES_CHANGE_END);
- /* If there is no display frame after resolution change,
- * Some released frames can't be unprotected.
- * So, check and request unprotection in the end of DRC.
- */
- s5p_mfc_cleanup_assigned_dpb(ctx);
-
- /* empty the timestamp queue */
- while (!list_empty(&ctx->ts_list)) {
- temp_ts = list_entry((&ctx->ts_list)->next,
- struct mfc_timestamp, list);
- list_del(&temp_ts->list);
- }
- ctx->ts_count = 0;
- ctx->ts_is_full = 0;
- s5p_mfc_qos_reset_last_framerate(ctx);
- s5p_mfc_qos_set_framerate(ctx, DEC_DEFAULT_FPS);
-
- goto leave_handle_frame;
- } else {
- mfc_handle_frame_all_extracted(ctx);
- }
- }
-
- if (s5p_mfc_get_num_of_tile() >= 4)
- dec->num_of_tile_over_4 = 1;
-
- switch (dst_frame_status) {
- case S5P_FIMV_DEC_STATUS_DECODING_DISPLAY:
- mfc_handle_ref_frame(ctx);
- break;
- case S5P_FIMV_DEC_STATUS_DECODING_ONLY:
- mfc_handle_ref_frame(ctx);
- /*
- * Some cases can have many decoding only frames like VP9
- * alt-ref frame. So need handling release buffer
- * because of DPB full.
- */
- mfc_handle_reuse_buffer(ctx);
- break;
- default:
- break;
- }
-
- if (s5p_mfc_dec_status_decoding(dst_frame_status))
- mfc_handle_frame_copy_timestamp(ctx);
-
- /* A frame has been decoded and is in the buffer */
- if (s5p_mfc_dec_status_display(dst_frame_status))
- mfc_handle_frame_new(ctx, err);
- else
- mfc_debug(2, "No frame decode\n");
-
- /* Mark source buffer as complete */
- if (dst_frame_status != S5P_FIMV_DEC_STATUS_DISPLAY_ONLY)
- mfc_handle_frame_input(ctx, err);
-
-leave_handle_frame:
- mfc_debug(2, "Assesing whether this context should be run again\n");
-}
-
-static void mfc_handle_stream_copy_timestamp(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *src_mb)
-{
- struct s5p_mfc_dev *dev;
- struct s5p_mfc_enc *enc = ctx->enc_priv;
- struct s5p_mfc_enc_params *p = &enc->params;
- struct s5p_mfc_buf *dst_mb;
- u32 interval;
- u64 start_timestamp;
- u64 new_timestamp;
-
- if (!ctx) {
- mfc_err_dev("[BUFCON][TS] no mfc context to run\n");
- return;
- }
-
- dev = ctx->dev;
- if (!dev) {
- mfc_err_dev("[BUFCON][TS] no device to run\n");
- return;
- }
-
- start_timestamp = src_mb->vb.vb2_buf.timestamp;
- interval = NSEC_PER_SEC / p->rc_framerate;
- if (debug_ts == 1)
- mfc_info_ctx("[BUFCON][TS] %dfps, start timestamp: %lld, base interval: %d\n",
- p->rc_framerate, start_timestamp, interval);
-
- new_timestamp = start_timestamp + (interval * src_mb->done_index);
- if (debug_ts == 1)
- mfc_info_ctx("[BUFCON][TS] new timestamp: %lld, interval: %d\n",
- new_timestamp, interval * src_mb->done_index);
-
- /* Get the destination buffer */
- dst_mb = s5p_mfc_get_buf(&ctx->buf_queue_lock, &ctx->dst_buf_queue, MFC_BUF_NO_TOUCH_USED);
- if (dst_mb)
- dst_mb->vb.vb2_buf.timestamp = new_timestamp;
-}
-
-static void mfc_handle_stream_input(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_raw_info *raw;
- struct s5p_mfc_buf *ref_mb, *src_mb;
- dma_addr_t enc_addr[3] = { 0, 0, 0 };
- int i, found_in_src_queue = 0;
- unsigned int index;
-
- raw = &ctx->raw_buf;
-
- s5p_mfc_get_enc_frame_buffer(ctx, &enc_addr[0], raw->num_planes);
- if (enc_addr[0] == 0) {
- mfc_debug(3, "no encoded src\n");
- goto move_buf;
- }
- for (i = 0; i < raw->num_planes; i++)
- mfc_debug(2, "[BUFINFO] ctx[%d] get src addr[%d]: 0x%08llx\n",
- ctx->num, i, enc_addr[i]);
-
- if (IS_BUFFER_BATCH_MODE(ctx)) {
- src_mb = s5p_mfc_find_first_buf(&ctx->buf_queue_lock,
- &ctx->src_buf_queue, enc_addr[0]);
- if (src_mb) {
- found_in_src_queue = 1;
-
- mfc_handle_stream_copy_timestamp(ctx, src_mb);
- src_mb->done_index++;
- mfc_debug(4, "[BUFCON] batch buf done_index: %d\n", src_mb->done_index);
-
- index = src_mb->vb.vb2_buf.index;
-
- if (call_cop(ctx, recover_buf_ctrls_val, ctx,
- &ctx->src_ctrls[index]) < 0)
- mfc_err_ctx("failed in recover_buf_ctrls_val\n");
-
- /* single buffer || last image in a buffer container */
- if (!src_mb->num_valid_bufs || src_mb->done_index == src_mb->num_valid_bufs) {
- src_mb = s5p_mfc_find_del_buf(&ctx->buf_queue_lock,
- &ctx->src_buf_queue, enc_addr[0]);
- for (i = 0; i < raw->num_planes; i++)
- s5p_mfc_bufcon_put_daddr(ctx, src_mb, i);
- vb2_buffer_done(&src_mb->vb.vb2_buf, VB2_BUF_STATE_DONE);
- }
-
- /* encoder src buffer CFW UNPROT */
- if (ctx->is_drm)
- s5p_mfc_raw_unprotect(ctx, src_mb, index);
- }
- } else {
- /* normal single buffer */
- src_mb = s5p_mfc_find_del_buf(&ctx->buf_queue_lock,
- &ctx->src_buf_queue, enc_addr[0]);
- if (src_mb) {
- found_in_src_queue = 1;
- index = src_mb->vb.vb2_buf.index;
- if (call_cop(ctx, recover_buf_ctrls_val, ctx,
- &ctx->src_ctrls[index]) < 0)
- mfc_err_ctx("failed in recover_buf_ctrls_val\n");
-
- mfc_debug(3, "find src buf in src_queue\n");
- vb2_buffer_done(&src_mb->vb.vb2_buf, VB2_BUF_STATE_DONE);
-
- /* encoder src buffer CFW UNPROT */
- if (ctx->is_drm)
- s5p_mfc_raw_unprotect(ctx, src_mb, index);
- } else {
- mfc_debug(3, "no src buf in src_queue\n");
- ref_mb = s5p_mfc_find_del_buf(&ctx->buf_queue_lock,
- &ctx->ref_buf_queue, enc_addr[0]);
- if (ref_mb) {
- mfc_debug(3, "find src buf in ref_queue\n");
- vb2_buffer_done(&ref_mb->vb.vb2_buf, VB2_BUF_STATE_DONE);
-
- /* encoder src buffer CFW UNPROT */
- if (ctx->is_drm) {
- index = ref_mb->vb.vb2_buf.index;
- s5p_mfc_raw_unprotect(ctx, ref_mb, index);
- }
- } else {
- mfc_err_ctx("couldn't find src buffer\n");
- }
- }
- }
-
-move_buf:
- /* move enqueued src buffer: src queue -> ref queue */
- if (!found_in_src_queue && ctx->state != MFCINST_FINISHING) {
- s5p_mfc_move_first_buf_used(&ctx->buf_queue_lock,
- &ctx->ref_buf_queue, &ctx->src_buf_queue, MFC_QUEUE_ADD_BOTTOM);
-
- mfc_debug(2, "enc src_buf_queue(%d) -> ref_buf_queue(%d)\n",
- s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->src_buf_queue),
- s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->ref_buf_queue));
- }
-}
-
-static void mfc_handle_stream_output(struct s5p_mfc_ctx *ctx, int slice_type,
- unsigned int strm_size)
-{
- struct s5p_mfc_enc *enc = ctx->enc_priv;
- struct s5p_mfc_buf *dst_mb;
- unsigned int index;
-
- if (strm_size == 0) {
- mfc_debug(3, "no encoded dst (reuse)\n");
- return;
- } else if (strm_size < 0) {
- mfc_err_ctx("invalid stream size: %d\n", strm_size);
- return;
- }
-
- /* at least one more dest. buffers exist always */
- dst_mb = s5p_mfc_get_del_buf(&ctx->buf_queue_lock,
- &ctx->dst_buf_queue, MFC_BUF_NO_TOUCH_USED);
- if (!dst_mb) {
- mfc_err_ctx("no dst buffers\n");
- return;
- }
-
- mfc_debug(2, "[BUFINFO] ctx[%d] get dst addr: 0x%08llx\n",
- ctx->num, dst_mb->addr[0][0]);
-
- dst_mb->vb.flags &= ~(V4L2_BUF_FLAG_KEYFRAME |
- V4L2_BUF_FLAG_PFRAME |
- V4L2_BUF_FLAG_BFRAME);
- switch (slice_type) {
- case S5P_FIMV_E_SLICE_TYPE_I:
- dst_mb->vb.flags |= V4L2_BUF_FLAG_KEYFRAME;
- break;
- case S5P_FIMV_E_SLICE_TYPE_P:
- dst_mb->vb.flags |= V4L2_BUF_FLAG_PFRAME;
- break;
- case S5P_FIMV_E_SLICE_TYPE_B:
- dst_mb->vb.flags |= V4L2_BUF_FLAG_BFRAME;
- break;
- default:
- dst_mb->vb.flags |= V4L2_BUF_FLAG_KEYFRAME;
- break;
- }
- mfc_debug(2, "[STREAM] Slice type flag: %d\n", dst_mb->vb.flags);
-
- if (IS_BPG_ENC(ctx)) {
- strm_size += enc->header_size;
- mfc_debug(2, "bpg total stream size: %d\n", strm_size);
- }
- vb2_set_plane_payload(&dst_mb->vb.vb2_buf, 0, strm_size);
-
- index = dst_mb->vb.vb2_buf.index;
- if (call_cop(ctx, get_buf_ctrls_val, ctx, &ctx->dst_ctrls[index]) < 0)
- mfc_err_ctx("failed in get_buf_ctrls_val\n");
-
- vb2_buffer_done(&dst_mb->vb.vb2_buf, VB2_BUF_STATE_DONE);
-
- /* encoder dst buffer CFW UNPROT */
- if (ctx->is_drm)
- s5p_mfc_stream_unprotect(ctx, dst_mb, index);
-}
-
-/* Handle frame encoding interrupt */
-static int mfc_handle_stream(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_enc *enc = ctx->enc_priv;
- int slice_type;
- unsigned int strm_size;
- unsigned int pic_count;
-
- slice_type = s5p_mfc_get_enc_slice_type();
- strm_size = s5p_mfc_get_enc_strm_size();
- pic_count = s5p_mfc_get_enc_pic_count();
-
- mfc_debug(2, "[STREAM] encoded slice type: %d, size: %d, display order: %d\n",
- slice_type, strm_size, pic_count);
-
- /* buffer full handling */
- if (enc->buf_full) {
- s5p_mfc_change_state(ctx, MFCINST_ABORT_INST);
- return 0;
- }
- if (ctx->state == MFCINST_RUNNING_BUF_FULL)
- s5p_mfc_change_state(ctx, MFCINST_RUNNING);
-
- /* set encoded frame type */
- enc->frame_type = slice_type;
- ctx->sequence++;
-
- if (enc->in_slice) {
- if (s5p_mfc_is_queue_count_same(&ctx->buf_queue_lock, &ctx->dst_buf_queue, 0)) {
- s5p_mfc_clear_bit(ctx->num, &dev->work_bits);
- }
- return 0;
- }
-
- /* handle source buffer */
- mfc_handle_stream_input(ctx);
-
- /* handle destination buffer */
- mfc_handle_stream_output(ctx, slice_type, strm_size);
-
- return 0;
-}
-
-/* Error handling for interrupt */
-static inline void mfc_handle_error(struct s5p_mfc_ctx *ctx,
- unsigned int reason, unsigned int err)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_buf *src_mb;
- int index;
-
- mfc_err_ctx("Interrupt Error: display: %d, decoded: %d\n",
- s5p_mfc_get_warn(err), s5p_mfc_get_err(err));
- err = s5p_mfc_get_err(err);
-
- /* Error recovery is dependent on the state of context */
- switch (ctx->state) {
- case MFCINST_RES_CHANGE_END:
- case MFCINST_GOT_INST:
- /* This error had to happen while parsing the header */
- if (!ctx->is_drm) {
- unsigned char *stream_vir = NULL;
- unsigned int strm_size = 0;
-
- src_mb = s5p_mfc_get_del_buf(&ctx->buf_queue_lock, &ctx->src_buf_queue, MFC_BUF_NO_TOUCH_USED);
- if (src_mb) {
- stream_vir = src_mb->vir_addr;
- strm_size = src_mb->vb.vb2_buf.planes[0].bytesused;
- if (strm_size > 32)
- strm_size = 32;
-
- if (stream_vir && strm_size)
- print_hex_dump(KERN_ERR, "No header: ",
- DUMP_PREFIX_ADDRESS, strm_size, 0,
- stream_vir, strm_size, false);
-
- vb2_buffer_done(&src_mb->vb.vb2_buf, VB2_BUF_STATE_DONE);
- }
- } else {
- src_mb = s5p_mfc_get_del_buf(&ctx->buf_queue_lock, &ctx->src_buf_queue, MFC_BUF_NO_TOUCH_USED);
- if (src_mb) {
- index = src_mb->vb.vb2_buf.index;
- /* decoder src buffer CFW UNPROT */
- s5p_mfc_stream_unprotect(ctx, src_mb, index);
- vb2_buffer_done(&src_mb->vb.vb2_buf, VB2_BUF_STATE_DONE);
- }
- }
- break;
- case MFCINST_INIT:
- /* This error had to happen while acquireing instance */
- case MFCINST_RETURN_INST:
- /* This error had to happen while releasing instance */
- case MFCINST_DPB_FLUSHING:
- /* This error had to happen while flushing DPB */
- case MFCINST_SPECIAL_PARSING:
- case MFCINST_SPECIAL_PARSING_NAL:
- /* This error had to happen while special parsing */
- break;
- case MFCINST_HEAD_PARSED:
- /* This error had to happen while setting dst buffers */
- case MFCINST_RES_CHANGE_INIT:
- case MFCINST_RES_CHANGE_FLUSH:
- /* This error has to happen while resolution change */
- case MFCINST_ABORT_INST:
- /* This error has to happen while buffer full handling */
- case MFCINST_FINISHING:
- /* It is higly probable that an error occured
- * while decoding a frame */
- s5p_mfc_change_state(ctx, MFCINST_ERROR);
- /* Mark all dst buffers as having an error */
- s5p_mfc_cleanup_queue(&ctx->buf_queue_lock, &ctx->dst_buf_queue);
- /* Mark all src buffers as having an error */
- s5p_mfc_cleanup_queue(&ctx->buf_queue_lock, &ctx->src_buf_queue);
- break;
- default:
- mfc_err_ctx("Encountered an error interrupt which had not been handled\n");
- mfc_err_ctx("ctx->state = %d, ctx->inst_no = %d\n",
- ctx->state, ctx->inst_no);
- break;
- }
-
- s5p_mfc_wake_up_dev(dev, reason, err);
-
- return;
-}
-
-/* Handle header decoder interrupt */
-static int mfc_handle_seq_dec(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_dec *dec = ctx->dec_priv;
- int i, is_interlace, is_mbaff;
-
- if (ctx->src_fmt->fourcc != V4L2_PIX_FMT_FIMV1) {
- ctx->img_width = s5p_mfc_get_img_width();
- ctx->img_height = s5p_mfc_get_img_height();
- ctx->crop_width = ctx->img_width;
- ctx->crop_height = ctx->img_height;
- mfc_info_ctx("[STREAM] resolution w: %d, h: %d\n", ctx->img_width, ctx->img_height);
- }
-
- ctx->dpb_count = s5p_mfc_get_dpb_count();
- ctx->scratch_buf_size = s5p_mfc_get_scratch_size();
- for (i = 0; i < ctx->dst_fmt->num_planes; i++)
- ctx->min_dpb_size[i] = s5p_mfc_get_min_dpb_size(i);
-
- s5p_mfc_dec_store_crop_info(ctx);
- dec->mv_count = s5p_mfc_get_mv_count();
- if (CODEC_10BIT(ctx) && dev->pdata->support_10bit) {
- if (s5p_mfc_get_luma_bit_depth_minus8() ||
- s5p_mfc_get_chroma_bit_depth_minus8() ||
- s5p_mfc_get_profile() == S5P_FIMV_D_PROFILE_HEVC_MAIN_10) {
- ctx->is_10bit = 1;
- mfc_info_ctx("[STREAM][10BIT] 10bit contents, profile: %d, depth: %d/%d\n",
- s5p_mfc_get_profile(),
- s5p_mfc_get_luma_bit_depth_minus8() + 8,
- s5p_mfc_get_chroma_bit_depth_minus8() + 8);
- }
- }
- if (CODEC_422FORMAT(ctx) && dev->pdata->support_422) {
- if (s5p_mfc_get_chroma_format() == S5P_FIMV_D_CHROMA_422) {
- ctx->is_422 = 1;
- mfc_info_ctx("[STREAM] 422 chroma format\n");
- }
- }
-
- if (ctx->img_width == 0 || ctx->img_height == 0)
- s5p_mfc_change_state(ctx, MFCINST_ERROR);
- else
- s5p_mfc_change_state(ctx, MFCINST_HEAD_PARSED);
-
- if (ctx->state == MFCINST_HEAD_PARSED) {
- is_interlace = s5p_mfc_is_interlace_picture();
- is_mbaff = s5p_mfc_is_mbaff_picture();
- if (is_interlace || is_mbaff)
- dec->is_interlaced = 1;
- mfc_debug(2, "[INTERLACE] interlace: %d, mbaff: %d\n", is_interlace, is_mbaff);
- }
-
- if (IS_H264_DEC(ctx) || IS_H264_MVC_DEC(ctx) || IS_HEVC_DEC(ctx)) {
- struct s5p_mfc_buf *src_mb = s5p_mfc_get_buf(&ctx->buf_queue_lock, &ctx->src_buf_queue, MFC_BUF_NO_TOUCH_USED);
- if (src_mb) {
- dec->consumed += s5p_mfc_get_consumed_stream();
- mfc_debug(2, "[STREAM] header total size : %d, consumed : %lu\n",
- src_mb->vb.vb2_buf.planes[0].bytesused, dec->consumed);
- if ((dec->consumed > 0) &&
- (src_mb->vb.vb2_buf.planes[0].bytesused > dec->consumed)) {
- dec->remained_size = src_mb->vb.vb2_buf.planes[0].bytesused -
- dec->consumed;
- mfc_debug(2, "[STREAM] there is remained bytes(%lu) after header parsing\n",
- dec->remained_size);
- } else {
- dec->consumed = 0;
- dec->remained_size = 0;
- }
- }
- }
-
- if (IS_VP9_DEC(ctx)) {
- dec->color_range = s5p_mfc_get_color_range();
- dec->color_space = s5p_mfc_get_color_space();
- mfc_debug(2, "color range: %d, color space: %d, It's valid for VP9\n",
- dec->color_range, dec->color_space);
- }
-
- return 0;
-}
-
-/* Handle header encoder interrupt */
-static int mfc_handle_seq_enc(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_enc *enc = ctx->enc_priv;
- struct s5p_mfc_enc_params *p = &enc->params;
- struct s5p_mfc_buf *dst_mb;
- int ret;
-
- enc->header_size = s5p_mfc_get_enc_strm_size();
- mfc_debug(2, "[STREAM] encoded slice type: %d, header size: %d, display order: %d\n",
- s5p_mfc_get_enc_slice_type(), enc->header_size,
- s5p_mfc_get_enc_pic_count());
-
- if (IS_BPG_ENC(ctx)) {
- dst_mb = s5p_mfc_get_buf(&ctx->buf_queue_lock, &ctx->dst_buf_queue, MFC_BUF_NO_TOUCH_USED);
- if (!dst_mb) {
- mfc_err_dev("no dst buffers\n");
- return -EAGAIN;
- }
-
- dst_mb->vb.vb2_buf.planes[0].data_offset += (enc->header_size +
- p->codec.bpg.thumb_size + p->codec.bpg.exif_size);
- mfc_debug(2, "offset for NAL_START: %d (header: %d + thumb: %d + exif: %d)\n",
- dst_mb->vb.vb2_buf.planes[0].data_offset,
- enc->header_size,
- p->codec.bpg.thumb_size,
- p->codec.bpg.exif_size);
- } else {
- if ((p->seq_hdr_mode == V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) ||
- (p->seq_hdr_mode == V4L2_MPEG_VIDEO_HEADER_MODE_AT_THE_READY)) {
- dst_mb = s5p_mfc_get_del_buf(&ctx->buf_queue_lock,
- &ctx->dst_buf_queue, MFC_BUF_NO_TOUCH_USED);
- if (!dst_mb) {
- mfc_err_dev("no dst buffers\n");
- return -EAGAIN;
- }
-
- vb2_set_plane_payload(&dst_mb->vb.vb2_buf, 0, s5p_mfc_get_enc_strm_size());
- vb2_buffer_done(&dst_mb->vb.vb2_buf, VB2_BUF_STATE_DONE);
-
- /* encoder dst buffer CFW UNPROT */
- if (ctx->is_drm) {
- int index = dst_mb->vb.vb2_buf.index;
-
- s5p_mfc_stream_unprotect(ctx, dst_mb, index);
- }
- }
- }
-
- ctx->dpb_count = s5p_mfc_get_enc_dpb_count();
- ctx->scratch_buf_size = s5p_mfc_get_enc_scratch_size();
-
- /* If the ROI is enabled at SEQ_START, clear ROI_ENABLE bit */
- s5p_mfc_clear_roi_enable(dev);
-
- if (!ctx->codec_buffer_allocated) {
- mfc_debug(2, "[DRC] previous codec buffer is exist\n");
-
- if (dev->has_mmcache && dev->mmcache.is_on_status)
- s5p_mfc_invalidate_mmcache(dev);
-
- s5p_mfc_release_codec_buffers(ctx);
- }
- ret = s5p_mfc_alloc_codec_buffers(ctx);
- if (ret) {
- mfc_err_ctx("Failed to allocate encoding buffers\n");
- return ret;
- }
-
- s5p_mfc_change_state(ctx, MFCINST_HEAD_PARSED);
-
- return 0;
-}
-
-static inline int is_err_condition(unsigned int err)
-{
- if (err == S5P_FIMV_ERR_NO_AVAILABLE_DPB ||
- err == S5P_FIMV_ERR_INSUFFICIENT_DPB_SIZE ||
- err == S5P_FIMV_ERR_INSUFFICIENT_NUM_DPB ||
- err == S5P_FIMV_ERR_INSUFFICIENT_MV_BUF_SIZE ||
- err == S5P_FIMV_ERR_INSUFFICIENT_SCRATCH_BUF_SIZE)
- return 1;
-
- return 0;
-}
-
-irqreturn_t s5p_mfc_top_half_irq(int irq, void *priv)
-{
- struct s5p_mfc_dev *dev = priv;
- struct s5p_mfc_ctx *ctx;
- unsigned int err;
- unsigned int reason;
-
- ctx = dev->ctx[dev->curr_ctx];
- if (!ctx) {
- mfc_err_dev("no mfc context to run\n");
- return IRQ_WAKE_THREAD;
- }
-
- reason = s5p_mfc_get_int_reason();
- err = s5p_mfc_get_int_err();
- mfc_debug(2, "[c:%d] Int reason: %d (err: %d)\n",
- dev->curr_ctx, reason, err);
- MFC_TRACE_CTX("<< INT(top): %d\n", reason);
-
- s5p_mfc_perf_measure_off(dev);
-
- return IRQ_WAKE_THREAD;
-}
-
-/*
- * Return value description
- * 0: NAL-Q is handled successfully
- * 1: NAL_START command
- * -1: Error
-*/
-static inline int mfc_nal_q_irq(struct s5p_mfc_dev *dev,
- unsigned int reason, unsigned int err)
-{
- int ret = -1;
- unsigned int errcode;
-
- nal_queue_handle *nal_q_handle = dev->nal_q_handle;
- EncoderOutputStr *pOutStr;
-
- switch (reason) {
- case S5P_FIMV_R2H_CMD_QUEUE_DONE_RET:
- pOutStr = s5p_mfc_nal_q_dequeue_out_buf(dev,
- nal_q_handle->nal_q_out_handle, &errcode);
- if (pOutStr) {
- if (s5p_mfc_nal_q_handle_out_buf(dev, pOutStr))
- mfc_err_dev("[NALQ] Failed to handle out buf\n");
- } else {
- mfc_err_dev("[NALQ] pOutStr is NULL\n");
- }
-
- if (nal_q_handle->nal_q_exception)
- s5p_mfc_set_bit(nal_q_handle->nal_q_out_handle->nal_q_ctx,
- &dev->work_bits);
- s5p_mfc_clear_int_sfr();
-
- if (!nal_q_handle->nal_q_exception)
- s5p_mfc_nal_q_clock_off(dev, nal_q_handle);
-
- ret = 0;
- break;
- case S5P_FIMV_R2H_CMD_COMPLETE_QUEUE_RET:
- s5p_mfc_watchdog_stop_tick(dev);
- nal_q_handle->nal_q_state = NAL_Q_STATE_CREATED;
- MFC_TRACE_DEV("** NAL Q state : %d\n", nal_q_handle->nal_q_state);
- mfc_debug(2, "[NALQ] return to created state\n");
- s5p_mfc_nal_q_cleanup_queue(dev);
- s5p_mfc_nal_q_cleanup_clock(dev);
- s5p_mfc_clear_int_sfr();
- s5p_mfc_pm_clock_off(dev);
- s5p_mfc_wake_up_dev(dev, reason, err);
-
- ret = 0;
- break;
- default:
- if (nal_q_handle->nal_q_state == NAL_Q_STATE_STARTED ||
- nal_q_handle->nal_q_state == NAL_Q_STATE_STOPPED) {
- mfc_err_dev("[NALQ] Should not be here! state: %d, int reason : %d\n",
- nal_q_handle->nal_q_state, reason);
- s5p_mfc_clear_int_sfr();
-
- ret = -1;
- } else {
- /* NAL START */
- ret = 1;
- }
-
- break;
- }
-
- if (ret == 0)
- queue_work(dev->butler_wq, &dev->butler_work);
-
- return ret;
-}
-
-static inline int mfc_handle_done_frame(struct s5p_mfc_ctx *ctx,
- unsigned int reason, unsigned int err)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_enc *enc = NULL;
-
- if (ctx->type == MFCINST_DECODER) {
- if (ctx->state == MFCINST_SPECIAL_PARSING_NAL) {
- s5p_mfc_clear_int_sfr();
- s5p_mfc_pm_clock_off(dev);
- s5p_mfc_clear_bit(ctx->num, &dev->work_bits);
- s5p_mfc_change_state(ctx, MFCINST_RUNNING);
- s5p_mfc_wake_up_ctx(ctx, reason, err);
- return 0;
- }
- mfc_handle_frame(ctx, reason, err);
- } else if (ctx->type == MFCINST_ENCODER) {
- if (ctx->otf_handle) {
- s5p_mfc_otf_handle_stream(ctx);
- return 1;
- }
- enc = ctx->enc_priv;
- if (reason == S5P_FIMV_R2H_CMD_SLICE_DONE_RET) {
- dev->preempt_ctx = ctx->num;
- enc->buf_full = 0;
- enc->in_slice = 1;
- } else if (reason == S5P_FIMV_R2H_CMD_ENC_BUFFER_FULL_RET) {
- mfc_err_ctx("stream buffer size(%d) isn't enough\n",
- s5p_mfc_get_enc_strm_size());
- dev->preempt_ctx = ctx->num;
- enc->buf_full = 1;
- enc->in_slice = 0;
- } else {
- enc->buf_full = 0;
- enc->in_slice = 0;
- }
- mfc_handle_stream(ctx);
- }
-
- return 1;
-}
-
-static inline void mfc_handle_nal_abort(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_enc *enc = ctx->enc_priv;
-
- if (ctx->type == MFCINST_ENCODER) {
- s5p_mfc_change_state(ctx, MFCINST_RUNNING_BUF_FULL);
- enc->buf_full = 0;
- if (IS_VP8_ENC(ctx))
- mfc_err_ctx("stream buffer size isn't enough\n");
- mfc_handle_stream(ctx);
- } else {
- s5p_mfc_change_state(ctx, MFCINST_ABORT);
- }
-}
-
-static int mfc_irq_dev(struct s5p_mfc_dev *dev, unsigned int reason, unsigned int err)
-{
- /* Stop the timeout watchdog */
- if (reason != S5P_FIMV_R2H_CMD_FW_STATUS_RET)
- s5p_mfc_watchdog_stop_tick(dev);
-
- switch (reason) {
- case S5P_FIMV_R2H_CMD_CACHE_FLUSH_RET:
- case S5P_FIMV_R2H_CMD_SYS_INIT_RET:
- case S5P_FIMV_R2H_CMD_FW_STATUS_RET:
- case S5P_FIMV_R2H_CMD_SLEEP_RET:
- case S5P_FIMV_R2H_CMD_WAKEUP_RET:
- s5p_mfc_clear_int_sfr();
- s5p_mfc_wake_up_dev(dev, reason, err);
- return 0;
- }
-
- return 1;
-}
-
-static int mfc_irq_ctx(struct s5p_mfc_ctx *ctx, unsigned int reason, unsigned int err)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
-
- switch (reason) {
- case S5P_FIMV_R2H_CMD_ERR_RET:
- if (ctx->otf_handle) {
- s5p_mfc_otf_handle_error(ctx, reason, err);
- break;
- }
- /* An error has occured */
- if (ctx->state == MFCINST_RUNNING || ctx->state == MFCINST_ABORT) {
- if ((s5p_mfc_get_err(err) >= S5P_FIMV_ERR_WARNINGS_START) &&
- (s5p_mfc_get_err(err) <= S5P_FIMV_ERR_WARNINGS_END))
- mfc_handle_frame(ctx, reason, err);
- else
- mfc_handle_frame_error(ctx, reason, err);
- } else {
- mfc_handle_error(ctx, reason, err);
- }
- break;
- case S5P_FIMV_R2H_CMD_SLICE_DONE_RET:
- case S5P_FIMV_R2H_CMD_FIELD_DONE_RET:
- case S5P_FIMV_R2H_CMD_FRAME_DONE_RET:
- case S5P_FIMV_R2H_CMD_ENC_BUFFER_FULL_RET:
- return mfc_handle_done_frame(ctx, reason, err);
- case S5P_FIMV_R2H_CMD_COMPLETE_SEQ_RET:
- if (ctx->type == MFCINST_ENCODER) {
- mfc_handle_stream(ctx);
- s5p_mfc_change_state(ctx, MFCINST_RUNNING);
- } else if (ctx->type == MFCINST_DECODER) {
- return mfc_handle_done_frame(ctx, reason, err);
- }
- break;
- case S5P_FIMV_R2H_CMD_SEQ_DONE_RET:
- if (ctx->type == MFCINST_ENCODER) {
- if (ctx->otf_handle) {
- s5p_mfc_otf_handle_seq(ctx);
- break;
- }
- mfc_handle_seq_enc(ctx);
- } else if (ctx->type == MFCINST_DECODER) {
- mfc_handle_seq_dec(ctx);
- }
- break;
- case S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET:
- ctx->inst_no = s5p_mfc_get_inst_no();
- s5p_mfc_change_state(ctx, MFCINST_GOT_INST);
- break;
- case S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET:
- s5p_mfc_change_state(ctx, MFCINST_FREE);
- break;
- case S5P_FIMV_R2H_CMD_NAL_ABORT_RET:
- mfc_handle_nal_abort(ctx);
- break;
- case S5P_FIMV_R2H_CMD_DPB_FLUSH_RET:
- s5p_mfc_change_state(ctx, MFCINST_ABORT);
- break;
- case S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET:
- if (err != 0) {
- mfc_err_ctx("INIT_BUFFERS_RET error: %d\n", err);
- break;
- }
-
- s5p_mfc_change_state(ctx, MFCINST_RUNNING);
- if (ctx->type == MFCINST_DECODER) {
- if (ctx->wait_state == WAIT_DECODING) {
- ctx->wait_state = WAIT_INITBUF_DONE;
- mfc_debug(2, "INIT_BUFFER has done, but can't start decoding\n");
- }
- if (ctx->is_dpb_realloc)
- ctx->is_dpb_realloc = 0;
- }
- break;
- default:
- mfc_err_ctx("Unknown int reason: %d\n", reason);
- }
-
- return 1;
-}
-
-/* Interrupt processing */
-irqreturn_t s5p_mfc_irq(int irq, void *priv)
-{
- struct s5p_mfc_dev *dev = priv;
- struct s5p_mfc_ctx *ctx;
- unsigned int reason;
- unsigned int err;
- int ret = -1;
-
- mfc_debug_enter();
-
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- goto irq_end;
- }
-
- if (s5p_mfc_pm_get_pwr_ref_cnt(dev) == 0) {
- mfc_err_dev("no mfc power on\n");
- call_dop(dev, dump_and_stop_debug_mode, dev);
- goto irq_end;
- }
-
- /* Get the reason of interrupt and the error code */
- reason = s5p_mfc_get_int_reason();
- err = s5p_mfc_get_int_err();
- mfc_debug(1, "Int reason: %d (err: %d)\n", reason, err);
- MFC_TRACE_DEV("<< INT: %d\n", reason);
-
- dev->preempt_ctx = MFC_NO_INSTANCE_SET;
-
- if (dbg_enable && (reason != S5P_FIMV_R2H_CMD_QUEUE_DONE_RET))
- s5p_mfc_dbg_disable(dev);
-
- if ((sfr_dump & MFC_DUMP_ERR_INT) && (reason == S5P_FIMV_R2H_CMD_ERR_RET))
- call_dop(dev, dump_regs, dev);
-
- if ((sfr_dump & MFC_DUMP_WARN_INT) &&
- (err && (reason != S5P_FIMV_R2H_CMD_ERR_RET)))
- call_dop(dev, dump_regs, dev);
-
- if (is_err_condition(err))
- call_dop(dev, dump_and_stop_debug_mode, dev);
-
- if (dev->nal_q_handle) {
- ret = mfc_nal_q_irq(dev, reason, err);
- if (ret == 0) {
- mfc_debug(2, "[NALQ] command was handled\n");
- goto irq_end;
- } else if (ret == 1){
- /* Path through */
- mfc_debug(2, "NAL_START command will be handled\n");
- } else {
- mfc_debug(2, "[NALQ] command handling Error\n");
- goto irq_end;
- }
- }
-
- ret = mfc_irq_dev(dev, reason, err);
- if (!ret)
- goto irq_end;
-
- ctx = dev->ctx[dev->curr_ctx];
- if (!ctx) {
- mfc_err_dev("no mfc context to run\n");
- s5p_mfc_clear_int_sfr();
- s5p_mfc_pm_clock_off(dev);
- goto irq_end;
- }
-
- ret = mfc_irq_ctx(ctx, reason, err);
- if (!ret)
- goto irq_end;
-
- /* clean-up interrupt */
- s5p_mfc_clear_int_sfr();
-
- if ((ctx->state != MFCINST_RES_CHANGE_INIT) && (s5p_mfc_ctx_ready(ctx) == 0))
- s5p_mfc_clear_bit(ctx->num, &dev->work_bits);
-
- if (ctx->otf_handle) {
- if (s5p_mfc_otf_ctx_ready(ctx))
- s5p_mfc_set_bit(ctx->num, &dev->work_bits);
- else
- s5p_mfc_clear_bit(ctx->num, &dev->work_bits);
- }
-
- s5p_mfc_hwlock_handler_irq(dev, ctx, reason, err);
-
-irq_end:
- mfc_debug_leave();
- return IRQ_HANDLED;
-}
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_irq.h
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __S5P_MFC_IRQ_H
-#define __S5P_MFC_IRQ_H __FILE__
-
-#include <linux/interrupt.h>
-
-#include "s5p_mfc_common.h"
-
-#include "s5p_mfc_utils.h"
-
-irqreturn_t s5p_mfc_top_half_irq(int irq, void *priv);
-irqreturn_t s5p_mfc_irq(int irq, void *priv);
-
-static inline void s5p_mfc_handle_force_change_status(struct s5p_mfc_ctx *ctx)
-{
- if (ctx->state != MFCINST_ABORT && ctx->state != MFCINST_HEAD_PARSED &&
- ctx->state != MFCINST_RES_CHANGE_FLUSH)
- s5p_mfc_change_state(ctx, MFCINST_RUNNING);
-}
-
-#endif /* __S5P_MFC_IRQ_H */
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_macros.h
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __S5P_MFC_MACROS_H
-#define __S5P_MFC_MACROS_H __FILE__
-
-#define WIDTH_MB(x_size) ((x_size + 15) / 16)
-#define HEIGHT_MB(y_size) ((y_size + 15) / 16)
-
-/*
- Note that lcu_width and lcu_height are defined as follows :
- lcu_width = (frame_width + lcu_size - 1)/lcu_size
- lcu_height = (frame_height + lcu_size - 1)/lcu_size.
- (lcu_size is 32(encoder) or 64(decoder))
-*/
-#define DEC_LCU_WIDTH(x_size) ((x_size + 63) / 64)
-#define ENC_LCU_WIDTH(x_size) ((x_size + 31) / 32)
-#define DEC_LCU_HEIGHT(y_size) ((y_size + 63) / 64)
-#define ENC_LCU_HEIGHT(y_size) ((y_size + 31) / 32)
-
-#define STREAM_BUF_ALIGN 512
-#define MFC_LINEAR_BUF_SIZE 256
-#define set_strm_size_max(cpb_max) ((cpb_max) - STREAM_BUF_ALIGN)
-
-#define DEC_STATIC_BUFFER_SIZE 20480
-
-#define DEC_MV_SIZE_MB(x, y) (WIDTH_MB(x) * (((HEIGHT_MB(y)+1)/2)*2) * 64 + 1024)
-#define DEC_HEVC_MV_SIZE(x, y) (DEC_LCU_WIDTH(x) * DEC_LCU_HEIGHT(y) * 256 + 512)
-
-#define ENC_HEVC_LUMA_DPB_10B_SIZE(x, y) \
- ((x + 63) / 64) * 64 * ((y + 31) / 32 ) * 32 + \
- (((((ENC_LCU_WIDTH(x) * 32 + 3) / 4) + 15) / 16) * 16) * \
- ((y + 31) / 32 ) * 32 + 64
-#define ENC_HEVC_CHROMA_DPB_10B_SIZE(x, y) \
- ((x + 63) / 64) * 64 * ((y + 31) / 32 ) * 32 + \
- (((((ENC_LCU_WIDTH(x) * 32 + 3) / 4) + 15) / 16) * 16) * \
- ((y + 31) / 32 ) * 32 + 64
-#define ENC_VP9_LUMA_DPB_10B_SIZE(x, y) \
- (((x * 2 + 127) / 128) * 128) * \
- ((y + 31) / 32 ) * 32 + 64
-#define ENC_VP9_CHROMA_DPB_10B_SIZE(x, y) \
- (((x * 2 + 127) / 128) * 128) * \
- ((y + 31) / 32 ) * 32 + 64
-#define ENC_LUMA_DPB_SIZE(x, y) \
- ((x + 63) / 64) * 64 * ((y + 31) / 32 ) * 32 + 64
-#define ENC_CHROMA_DPB_SIZE(x, y) \
- ((x + 63) / 64) * 64 * ((((y + 31) / 32 ) * 32) / 2) + 64
-
-#define ENC_V100_H264_ME_SIZE(x, y) \
- (((x + 3) * (y + 3) * 8) + ((((x * y) + 63) / 64) * 32) + (((y * 64) + 2304) * (x + 7) / 8))
-#define ENC_V100_MPEG4_ME_SIZE(x, y) \
- (((x + 3) * (y + 3) * 8) + ((((x * y) + 127) / 128) * 16) + (((y * 64) + 2304) * (x + 7) / 8))
-#define ENC_V100_VP8_ME_SIZE(x, y) \
- (((x + 3) * (y + 3) * 8) + (((y * 64) + 2304) * (x + 7) / 8))
-#define ENC_V100_VP9_ME_SIZE(x, y) \
- ((((x * 2) + 3) * ((y * 2) + 3) * 128) + (((y * 256) + 2304) * (x + 1) / 2))
-#define ENC_V100_HEVC_ME_SIZE(x, y) \
- (((x + 3) * (y + 3) * 32) + (((y * 128) + 2304) * (x + 3) / 4))
-
-#endif /* __S5P_MFC_MACROS_H */
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_mem.c
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include "s5p_mfc_mem.h"
-
-struct vb2_mem_ops *s5p_mfc_mem_ops(void)
-{
- return (struct vb2_mem_ops *)&vb2_dma_sg_memops;
-}
-
-void s5p_mfc_mem_clean(struct s5p_mfc_dev *dev,
- struct s5p_mfc_special_buf *special_buf,
- off_t offset, size_t size)
-{
- __dma_map_area(special_buf->vaddr + offset, size, DMA_TO_DEVICE);
- return;
-}
-
-void s5p_mfc_mem_invalidate(struct s5p_mfc_dev *dev,
- struct s5p_mfc_special_buf *special_buf,
- off_t offset, size_t size)
-{
- __dma_map_area(special_buf->vaddr + offset, size, DMA_FROM_DEVICE);
- return;
-}
-
-int s5p_mfc_mem_get_user_shared_handle(struct s5p_mfc_ctx *ctx,
- struct mfc_user_shared_handle *handle)
-{
- int ret = 0;
-
- handle->dma_buf = dma_buf_get(handle->fd);
- if (IS_ERR(handle->dma_buf)) {
- mfc_err_ctx("Failed to import fd\n");
- ret = PTR_ERR(handle->dma_buf);
- goto import_dma_fail;
- }
-
- handle->vaddr = dma_buf_vmap(handle->dma_buf);
- if (handle->vaddr == NULL) {
- mfc_err_ctx("Failed to get kernel virtual address\n");
- ret = -EINVAL;
- goto map_kernel_fail;
- }
-
- return 0;
-
-map_kernel_fail:
- handle->vaddr = NULL;
- dma_buf_put(handle->dma_buf);
-
-import_dma_fail:
- handle->dma_buf = NULL;
- handle->fd = -1;
- return ret;
-}
-
-void s5p_mfc_mem_cleanup_user_shared_handle(struct s5p_mfc_ctx *ctx,
- struct mfc_user_shared_handle *handle)
-{
- if (handle->vaddr)
- dma_buf_vunmap(handle->dma_buf, handle->vaddr);
- if (handle->dma_buf)
- dma_buf_put(handle->dma_buf);
-
- handle->dma_buf = NULL;
- handle->vaddr = NULL;
- handle->fd = -1;
-}
-
-int s5p_mfc_mem_ion_alloc(struct s5p_mfc_dev *dev,
- struct s5p_mfc_special_buf *special_buf)
-{
- struct s5p_mfc_ctx *ctx = dev->ctx[dev->curr_ctx];
- int flag;
- const char *heapname;
-
- switch (special_buf->buftype) {
- case MFCBUF_NORMAL:
- heapname = "ion_system_heap";
- flag = 0;
- break;
- case MFCBUF_NORMAL_FW:
- heapname = "vnfw_heap";
- flag = 0;
- break;
- case MFCBUF_DRM:
- heapname = "vframe_heap";
- flag = ION_FLAG_PROTECTED;
- break;
- case MFCBUF_DRM_FW:
- heapname = "vfw_heap";
- flag = ION_FLAG_PROTECTED;
- break;
- default:
- mfc_err_ctx("not supported mfc mem type: %d, heapname: %s\n",
- special_buf->buftype, heapname);
- return -EINVAL;
- }
- special_buf->dma_buf =
- ion_alloc_dmabuf(heapname, special_buf->size, flag);
- if (IS_ERR(special_buf->dma_buf)) {
- mfc_err_ctx("Failed to allocate buffer (err %ld)\n",
- PTR_ERR(special_buf->dma_buf));
- call_dop(dev, dump_and_stop_debug_mode, dev);
- goto err_ion_alloc;
- }
-
- special_buf->attachment = dma_buf_attach(special_buf->dma_buf, dev->device);
- if (IS_ERR(special_buf->attachment)) {
- mfc_err_ctx("Failed to get dma_buf_attach (err %ld)\n",
- PTR_ERR(special_buf->attachment));
- call_dop(dev, dump_and_stop_debug_mode, dev);
- goto err_attach;
- }
-
- special_buf->sgt = dma_buf_map_attachment(special_buf->attachment,
- DMA_BIDIRECTIONAL);
- if (IS_ERR(special_buf->sgt)) {
- mfc_err_ctx("Failed to get sgt (err %ld)\n",
- PTR_ERR(special_buf->sgt));
- call_dop(dev, dump_and_stop_debug_mode, dev);
- goto err_map;
- }
-
- special_buf->daddr = ion_iovmm_map(special_buf->attachment, 0,
- special_buf->size, DMA_BIDIRECTIONAL, 0);
- if (IS_ERR_VALUE(special_buf->daddr)) {
- mfc_err_ctx("Failed to allocate iova (err 0x%p)\n",
- &special_buf->daddr);
- call_dop(dev, dump_and_stop_debug_mode, dev);
- goto err_iovmm;
- }
-
- special_buf->vaddr = dma_buf_vmap(special_buf->dma_buf);
- if (IS_ERR(special_buf->vaddr)) {
- mfc_err_ctx("Failed to get vaddr (err 0x%p)\n",
- &special_buf->vaddr);
- call_dop(dev, dump_and_stop_debug_mode, dev);
- goto err_vaddr;
- }
-
- return 0;
-err_vaddr:
- special_buf->vaddr = NULL;
- ion_iovmm_unmap(special_buf->attachment, special_buf->daddr);
-
-err_iovmm:
- special_buf->daddr = 0;
- dma_buf_unmap_attachment(special_buf->attachment, special_buf->sgt,
- DMA_BIDIRECTIONAL);
-err_map:
- special_buf->sgt = NULL;
- dma_buf_detach(special_buf->dma_buf, special_buf->attachment);
-err_attach:
- special_buf->attachment = NULL;
- dma_buf_put(special_buf->dma_buf);
-err_ion_alloc:
- special_buf->dma_buf = NULL;
- return -ENOMEM;
-}
-
-void s5p_mfc_mem_ion_free(struct s5p_mfc_dev *dev,
- struct s5p_mfc_special_buf *special_buf)
-{
- if (special_buf->vaddr)
- dma_buf_vunmap(special_buf->dma_buf, special_buf->vaddr);
- if (special_buf->daddr)
- ion_iovmm_unmap(special_buf->attachment, special_buf->daddr);
- if (special_buf->sgt)
- dma_buf_unmap_attachment(special_buf->attachment,
- special_buf->sgt, DMA_BIDIRECTIONAL);
- if (special_buf->attachment)
- dma_buf_detach(special_buf->dma_buf, special_buf->attachment);
- if (special_buf->dma_buf)
- dma_buf_put(special_buf->dma_buf);
-
- special_buf->dma_buf = NULL;
- special_buf->attachment = NULL;
- special_buf->sgt = NULL;
- special_buf->daddr = 0;
- special_buf->vaddr = NULL;
-}
-
-void s5p_mfc_bufcon_put_daddr(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *mfc_buf, int plane)
-{
- int i;
-
- for (i = 0; i < mfc_buf->num_valid_bufs; i++) {
- if (mfc_buf->addr[i][plane]) {
- mfc_debug(4, "[BUFCON] put batch buf addr[%d][%d]: 0x%08llx\n",
- i, plane, mfc_buf->addr[i][plane]);
- ion_iovmm_unmap(mfc_buf->attachments[i][plane], mfc_buf->addr[i][plane]);
- }
- if (mfc_buf->attachments[i][plane])
- dma_buf_detach(mfc_buf->dmabufs[i][plane], mfc_buf->attachments[i][plane]);
- if (mfc_buf->dmabufs[i][plane])
- dma_buf_put(mfc_buf->dmabufs[i][plane]);
-
- mfc_buf->addr[i][plane] = 0;
- mfc_buf->attachments[i][plane] = NULL;
- mfc_buf->dmabufs[i][plane] = NULL;
- }
-}
-
-int s5p_mfc_bufcon_get_daddr(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *mfc_buf,
- struct dma_buf *bufcon_dmabuf, int plane)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_raw_info *raw = &ctx->raw_buf;
- int i, j = 0;
- u32 mask;
-
- if (dmabuf_container_get_mask(bufcon_dmabuf, &mask)) {
- mfc_err_ctx("[BUFCON] it is not buffer container\n");
- return -1;
- } else {
- mfc_debug(3, "[BUFCON] bufcon mask info %#x\n", mask);
- }
-
- for (i = 0; i < mfc_buf->num_bufs_in_batch; i++) {
- if ((mask & (1 << i)) == 0) {
- mfc_debug(4, "[BUFCON] unmasked buf[%d]\n", i);
- continue;
- }
-
- mfc_buf->dmabufs[j][plane] = dmabuf_container_get_buffer(bufcon_dmabuf, i);
- if (IS_ERR(mfc_buf->dmabufs[i][plane])) {
- mfc_err_ctx("[BUFCON] Failed to get dma_buf (err %ld)",
- PTR_ERR(mfc_buf->dmabufs[i][plane]));
- call_dop(dev, dump_and_stop_debug_mode, dev);
- goto err_get_daddr;
- }
-
- mfc_buf->attachments[j][plane] = dma_buf_attach(mfc_buf->dmabufs[i][plane], dev->device);
- if (IS_ERR(mfc_buf->attachments[i][plane])) {
- mfc_err_ctx("[BUFCON] Failed to get dma_buf_attach (err %ld)",
- PTR_ERR(mfc_buf->attachments[i][plane]));
- call_dop(dev, dump_and_stop_debug_mode, dev);
- goto err_get_daddr;
- }
-
- mfc_buf->addr[j][plane] = ion_iovmm_map(mfc_buf->attachments[i][plane], 0,
- raw->plane_size[plane], DMA_BIDIRECTIONAL, 0);
- if (IS_ERR_VALUE(mfc_buf->addr[i][plane])) {
- mfc_err_ctx("[BUFCON] Failed to allocate iova (err %pa)",
- &mfc_buf->addr[i][plane]);
- call_dop(dev, dump_and_stop_debug_mode, dev);
- goto err_get_daddr;
- }
-
- mfc_debug(4, "[BUFCON] get batch buf addr[%d][%d]: 0x%08llx, size: %d\n",
- j, plane, mfc_buf->addr[j][plane], raw->plane_size[plane]);
- j++;
- }
-
- mfc_buf->num_valid_bufs = j;
- mfc_debug(3, "[BUFCON] batch buffer has %d buffers\n", mfc_buf->num_valid_bufs);
-
- return 0;
-
-err_get_daddr:
- s5p_mfc_bufcon_put_daddr(ctx, mfc_buf, plane);
- return -1;
-}
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_mem.h
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __S5P_MFC_MEM_H
-#define __S5P_MFC_MEM_H __FILE__
-
-#include "s5p_mfc_common.h"
-
-/* Offset base used to differentiate between CAPTURE and OUTPUT
-* while mmaping */
-#define DST_QUEUE_OFF_BASE (TASK_SIZE / 2)
-
-static inline dma_addr_t s5p_mfc_mem_get_daddr_vb(
- struct vb2_buffer *vb, unsigned int n)
-{
- dma_addr_t addr = 0;
-
- addr = vb2_dma_sg_plane_dma_addr(vb, n);
- WARN_ON((addr == 0) || IS_ERR_VALUE(addr));
-
- return addr;
-}
-
-static inline int s5p_mfc_bufcon_get_buf_count(struct dma_buf *dmabuf)
-{
- return dmabuf_container_get_count(dmabuf);
-}
-
-struct vb2_mem_ops *s5p_mfc_mem_ops(void);
-
-void s5p_mfc_mem_set_cacheable(bool cacheable);
-void s5p_mfc_mem_clean(struct s5p_mfc_dev *dev,
- struct s5p_mfc_special_buf *specail_buf,
- off_t offset, size_t size);
-void s5p_mfc_mem_invalidate(struct s5p_mfc_dev *dev,
- struct s5p_mfc_special_buf *specail_buf,
- off_t offset, size_t size);
-
-int s5p_mfc_mem_get_user_shared_handle(struct s5p_mfc_ctx *ctx,
- struct mfc_user_shared_handle *handle);
-void s5p_mfc_mem_cleanup_user_shared_handle(struct s5p_mfc_ctx *ctx,
- struct mfc_user_shared_handle *handle);
-
-int s5p_mfc_mem_ion_alloc(struct s5p_mfc_dev *dev,
- struct s5p_mfc_special_buf *special_buf);
-void s5p_mfc_mem_ion_free(struct s5p_mfc_dev *dev,
- struct s5p_mfc_special_buf *special_buf);
-
-void s5p_mfc_bufcon_put_daddr(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *mfc_buf, int plane);
-int s5p_mfc_bufcon_get_daddr(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *mfc_buf,
- struct dma_buf *bufcon_dmabuf, int plane);
-#endif /* __S5P_MFC_MEM_H */
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_mmcache.c
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include "s5p_mfc_mmcache.h"
-
-#include "s5p_mfc_reg.h"
-
-static const unsigned char mmcache_SFR_0x0010[] = {
- 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
- 0x2A, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-
-static const unsigned char mmcache_SFR_0x0040[] = {
- 0x0E, 0x00, 0x1E, 0x00, 0x0E, 0x00, 0x1E, 0x00, 0x0E, 0x00, 0x1E, 0x00, 0x0E, 0x00, 0x1E, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x10, 0x00, 0x1F, 0x00, 0x10, 0x00, 0x1F, 0x00, 0x10, 0x00, 0x1F, 0x00, 0x10, 0x00, 0x1F, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x0C, 0x00, 0x1F, 0x00, 0x0C, 0x00, 0x1F, 0x00, 0x0C, 0x00, 0x1F, 0x00, 0x0C, 0x00, 0x1F, 0x00,
- 0x12, 0x00, 0x3F, 0x00, 0x08, 0x00, 0x3F, 0x00, 0x0C, 0x00, 0x3D, 0x00, 0x0C, 0x00, 0x3D, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-
-static void mmcache_print_config(struct s5p_mfc_dev *dev)
-{
- void __iomem *addr;
- unsigned int size;
-
- mfc_debug_enter();
-
- if (!mmcache_dump)
- return;
-
- size = sizeof(mmcache_SFR_0x0010);
- addr = dev->mmcache.base + MMCACHE_WAY0_CTRL;
-
- print_hex_dump(KERN_ERR, "[MMCACHE] Config:", DUMP_PREFIX_ADDRESS, 32, 4, addr, size, false);
-
- size = sizeof(mmcache_SFR_0x0040);
- addr = dev->mmcache.base + MMCACHE_MASTER_GRP0_RPATH0;
-
- print_hex_dump(KERN_ERR, "[MMCACHE] Config:", DUMP_PREFIX_ADDRESS, 32, 4, addr, size, false);
-
- mfc_debug_leave();
-}
-
-static void mmcache_set_config(struct s5p_mfc_dev *dev)
-{
- unsigned int data, i, size;
- const unsigned int *sfr_dump;
-
- mfc_debug_enter();
-
- size = sizeof(mmcache_SFR_0x0010);
- sfr_dump = (const unsigned int *)mmcache_SFR_0x0010;
-
- for (i = 0; i < size; i += 4) {
- data = sfr_dump[i / 4];
- MMCACHE_WRITEL(data, MMCACHE_WAY0_CTRL + i);
- }
-
- size = sizeof(mmcache_SFR_0x0040);
- sfr_dump = (const unsigned int *)mmcache_SFR_0x0040;
-
- for (i = 0; i < size; i += 4) {
- data = sfr_dump[i / 4];
- MMCACHE_WRITEL(data, MMCACHE_MASTER_GRP0_RPATH0 + i);
- }
-
- mfc_debug(2, "[MMCACHE] mmcache config setting is done\n");
-
- mfc_debug_leave();
-}
-
-static void mmcache_reset_config(struct s5p_mfc_dev *dev)
-{
- void __iomem *addr;
- unsigned int data;
-
- mfc_debug_enter();
-
- addr = dev->mmcache.base + MMCACHE_MASTER_GRP_CTRL2;
- data = 0;
-
- mfc_debug(2, "[MMCACHE] before write 0x%X: (0x%08llX) 0x%X\n",
- data, (unsigned long long)(addr),
- MMCACHE_READL(MMCACHE_MASTER_GRP_CTRL2));
-
- MMCACHE_WRITEL(data, MMCACHE_MASTER_GRP_CTRL2);
-
- mfc_debug(2, "[MMCACHE] after write 0x%X: (0x%08llX) 0x%X\n",
- data, (unsigned long long)(addr),
- MMCACHE_READL(MMCACHE_MASTER_GRP_CTRL2));
-
- mfc_debug_leave();
-}
-
-static void mmcache_update_master_grp(struct s5p_mfc_dev *dev)
-{
- void __iomem *addr;
- unsigned int data;
-
- mfc_debug_enter();
-
- addr = dev->mmcache.base + MMCACHE_GLOBAL_CTRL;
- data = MMCACHE_GLOBAL_CTRL_VALUE;
-
- mfc_debug(2, "[MMCACHE] before write 0x%X: (0x%08llX) 0x%X\n",
- data, (unsigned long long)(addr),
- MMCACHE_READL(MMCACHE_GLOBAL_CTRL));
-
- MMCACHE_WRITEL(data, MMCACHE_GLOBAL_CTRL);
-
- mfc_debug(2, "[MMCACHE] after write 0x%X: (0x%08llX) 0x%X\n",
- data, (unsigned long long)(addr),
- MMCACHE_READL(MMCACHE_GLOBAL_CTRL));
-
- mfc_debug_leave();
-}
-
-static void mmcache_enable_clock_gating(struct s5p_mfc_dev *dev)
-{
- void __iomem *addr;
- unsigned int data;
-
- mfc_debug_enter();
-
- addr = dev->mmcache.base + MMCACHE_CG_CONTROL;
- data = MMCACHE_CG_CONTROL_VALUE;
-
- mfc_debug(2, "[MMCACHE] before write 0x%X: (0x%08llX) 0x%X\n",
- data, (unsigned long long)(addr),
- MMCACHE_READL(MMCACHE_CG_CONTROL));
-
- MMCACHE_WRITEL(data, MMCACHE_CG_CONTROL);
-
- mfc_debug(2, "[MMCACHE] after write 0x%X: (0x%08llX) 0x%X\n",
- data, (unsigned long long)(addr),
- MMCACHE_READL(MMCACHE_CG_CONTROL));
-
- mfc_debug_leave();
-}
-
-void s5p_mfc_mmcache_enable(struct s5p_mfc_dev *dev)
-{
- mfc_debug_enter();
-
- if (mmcache_disable)
- return;
-
- mmcache_set_config(dev);
- mmcache_print_config(dev);
- mmcache_update_master_grp(dev);
- mmcache_enable_clock_gating(dev);
-
- dev->mmcache.is_on_status = 1;
- mfc_info_dev("[MMCACHE] enabled\n");
- MFC_TRACE_DEV("[MMCACHE] enabled\n");
-
- mfc_debug_leave();
-}
-
-void s5p_mfc_mmcache_disable(struct s5p_mfc_dev *dev)
-{
- mfc_debug_enter();
-
- mmcache_reset_config(dev);
- mmcache_update_master_grp(dev);
-
- dev->mmcache.is_on_status = 0;
- mfc_info_dev("[MMCACHE] disabled\n");
- MFC_TRACE_DEV("[MMCACHE] disabled\n");
-
- mfc_debug_leave();
-}
-
-void s5p_mfc_invalidate_mmcache(struct s5p_mfc_dev *dev)
-{
- void __iomem *addr;
- unsigned int data;
- unsigned long timeout;
-
- mfc_debug_enter();
-
- addr = dev->mmcache.base + MMCACHE_INVALIDATE;
- data = MMCACHE_INVALIDATE_VALUE;
-
- mfc_debug(2, "[MMCACHE] before write 0x%X: (0x%08llX) 0x%X\n",
- data, (unsigned long long)(addr),
- MMCACHE_READL(MMCACHE_INVALIDATE));
-
- MMCACHE_WRITEL(data, MMCACHE_INVALIDATE);
-
- mfc_debug(2, "[MMCACHE] after write 0x%X: (0x%08llX) 0x%X\n",
- data, (unsigned long long)(addr),
- MMCACHE_READL(MMCACHE_INVALIDATE));
-
- addr = dev->mmcache.base + MMCACHE_INVALIDATE_STATUS;
-
- timeout = jiffies + msecs_to_jiffies(MMCACHE_INVAL_TIMEOUT);
- while (1) {
- if (MMCACHE_READL(MMCACHE_INVALIDATE_STATUS) == 0) {
- mfc_debug(2, "[MMCACHE] invalidate done: (0x%08llX) 0x%X\n",
- (unsigned long long)(addr), __raw_readl(addr));
- break;
- }
- if (time_after(jiffies, timeout)) {
- mfc_err_dev("[MMCACHE] Timeout while invalidation\n");
- call_dop(dev, dump_and_stop_debug_mode, dev);
- break;
- }
- }
-
- mfc_debug(2, "[MMCACHE] invalidated\n");
- MFC_TRACE_DEV("[MMCACHE] invalidated\n");
-
- mfc_debug_leave();
-}
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_mmcache.h
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __S5P_MFC_MMCACHE_H
-#define __S5P_MFC_MMCACHE_H __FILE__
-
-#include "s5p_mfc_common.h"
-
-#define MMCACHE_GLOBAL_CTRL 0x0000
-#define MMCACHE_INVALIDATE_STATUS 0x0008
-#define MMCACHE_WAY0_CTRL 0x0010
-#define MMCACHE_MASTER_GRP_CTRL2 0x0028
-#define MMCACHE_MASTER_GRP0_RPATH0 0x0040
-#define MMCACHE_CG_CONTROL 0x0400
-#define MMCACHE_INVALIDATE 0x0114
-
-#define MMCACHE_GLOBAL_CTRL_VALUE 0x2
-#define MMCACHE_CG_CONTROL_VALUE 0x7FF
-#define MMCACHE_INVALIDATE_VALUE 0x41
-
-/* Need HW lock to call this function */
-
-void s5p_mfc_mmcache_enable(struct s5p_mfc_dev *dev);
-void s5p_mfc_mmcache_disable(struct s5p_mfc_dev *dev);
-
-
-/* Need HW lock to call this function */
-void s5p_mfc_invalidate_mmcache(struct s5p_mfc_dev *dev);
-
-#endif /* __S5P_MFC_MMCACHE_H */
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_nal_q.c
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include "s5p_mfc_nal_q.h"
-
-#include "s5p_mfc_sync.h"
-
-#include "s5p_mfc_pm.h"
-#include "s5p_mfc_cal.h"
-#include "s5p_mfc_reg.h"
-
-#include "s5p_mfc_qos.h"
-#include "s5p_mfc_queue.h"
-#include "s5p_mfc_utils.h"
-#include "s5p_mfc_buf.h"
-#include "s5p_mfc_mem.h"
-
-#define CBR_I_LIMIT_MAX 5
-int s5p_mfc_nal_q_check_enable(struct s5p_mfc_dev *dev)
-{
- struct s5p_mfc_ctx *temp_ctx;
- struct s5p_mfc_dec *dec = NULL;
- struct s5p_mfc_enc *enc = NULL;
- struct s5p_mfc_enc_params *p = NULL;
- int i;
-
- mfc_debug_enter();
-
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
-
- if (nal_q_disable)
- return 0;
-
- for (i = 0; i < MFC_NUM_CONTEXTS; i++) {
- temp_ctx = dev->ctx[i];
- if (temp_ctx) {
- /* NAL-Q doesn't support drm */
- if (temp_ctx->is_drm) {
- mfc_debug(2, "There is a drm ctx. Can't start NAL-Q\n");
- return 0;
- }
- /* NAL-Q can be enabled when all ctx are in running state */
- if (temp_ctx->state != MFCINST_RUNNING) {
- mfc_debug(2, "There is a ctx which is not in running state. "
- "index: %d, state: %d\n", i, temp_ctx->state);
- return 0;
- }
- /* NAL-Q can't use the command about last frame */
- if (s5p_mfc_is_last_frame(temp_ctx) == 1) {
- mfc_debug(2, "There is a last frame. index: %d\n", i);
- return 0;
- }
- /* NAL-Q doesn't support OTF mode */
- if (temp_ctx->otf_handle) {
- mfc_debug(2, "There is a OTF node\n");
- return 0;
- }
- /* NAL-Q doesn't support BPG */
- if (IS_BPG_DEC(temp_ctx) || IS_BPG_ENC(temp_ctx)) {
- mfc_debug(2, "BPG codec type\n");
- return 0;
- }
- /* NAL-Q doesn't support multi-frame, interlaced, black bar */
- if (temp_ctx->type == MFCINST_DECODER) {
- dec = temp_ctx->dec_priv;
- if (!dec) {
- mfc_debug(2, "There is no dec\n");
- return 0;
- }
- if ((dec->has_multiframe && CODEC_MULTIFRAME(temp_ctx)) || dec->consumed) {
- mfc_debug(2, "[MULTIFRAME] There is a multi frame or consumed header\n");
- return 0;
- }
- if (dec->is_dpb_full) {
- mfc_debug(2, "[DPB] All buffers are referenced\n");
- return 0;
- }
- if (dec->is_interlaced) {
- mfc_debug(2, "[INTERLACE] There is a interlaced stream\n");
- return 0;
- }
- if (dec->detect_black_bar) {
- mfc_debug(2, "[BLACKBAR] black bar detection is enabled\n");
- return 0;
- }
- /* NAL-Q doesn't support fixed byte(slice mode), CBR_VT(rc mode) */
- } else if (temp_ctx->type == MFCINST_ENCODER) {
- enc = temp_ctx->enc_priv;
- if (!enc) {
- mfc_debug(2, "There is no enc\n");
- return 0;
- }
- if (enc->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_FIXED_BYTES) {
- mfc_debug(2, "There is fixed bytes option(slice mode)\n");
- return 0;
- }
- p = &enc->params;
- if (p->rc_reaction_coeff <= CBR_I_LIMIT_MAX) {
- mfc_debug(2, "There is CBR_VT option(rc mode)\n");
- return 0;
- }
- }
- mfc_debug(2, "There is a ctx in running state. index: %d\n", i);
- }
- }
-
- mfc_debug(2, "All working ctx are in running state!\n");
-
- mfc_debug_leave();
-
- return 1;
-}
-
-void s5p_mfc_nal_q_clock_on(struct s5p_mfc_dev *dev, nal_queue_handle *nal_q_handle)
-{
- unsigned long flags;
-
- mfc_debug_enter();
-
- spin_lock_irqsave(&nal_q_handle->lock, flags);
-
- mfc_debug(2, "[NALQ] continue_clock_on = %d, nal_q_clk_cnt = %d\n",
- dev->continue_clock_on, nal_q_handle->nal_q_clk_cnt);
-
- if (!dev->continue_clock_on && !nal_q_handle->nal_q_clk_cnt)
- s5p_mfc_pm_clock_on(dev);
-
- nal_q_handle->nal_q_clk_cnt++;
- dev->continue_clock_on = false;
-
- mfc_debug(2, "[NALQ] nal_q_clk_cnt = %d\n", nal_q_handle->nal_q_clk_cnt);
-
- spin_unlock_irqrestore(&nal_q_handle->lock, flags);
-
- mfc_debug_leave();
-}
-
-void s5p_mfc_nal_q_clock_off(struct s5p_mfc_dev *dev, nal_queue_handle *nal_q_handle)
-{
- unsigned long flags;
-
- mfc_debug_enter();
-
- spin_lock_irqsave(&nal_q_handle->lock, flags);
-
- mfc_debug(2, "[NALQ] nal_q_clk_cnt = %d\n", nal_q_handle->nal_q_clk_cnt);
-
- if (!nal_q_handle->nal_q_clk_cnt) {
- mfc_err_dev("[NALQ] nal_q_clk_cnt is already zero\n");
- return;
- }
-
- nal_q_handle->nal_q_clk_cnt--;
-
- if (!nal_q_handle->nal_q_clk_cnt)
- s5p_mfc_pm_clock_off(dev);
-
- mfc_debug(2, "[NALQ] nal_q_clk_cnt = %d\n", nal_q_handle->nal_q_clk_cnt);
-
- spin_unlock_irqrestore(&nal_q_handle->lock, flags);
-
- mfc_debug_leave();
-}
-
-void s5p_mfc_nal_q_cleanup_clock(struct s5p_mfc_dev *dev)
-{
- unsigned long flags;
-
- mfc_debug_enter();
-
- spin_lock_irqsave(&dev->nal_q_handle->lock, flags);
-
- dev->nal_q_handle->nal_q_clk_cnt = 0;
-
- spin_unlock_irqrestore(&dev->nal_q_handle->lock, flags);
-
- mfc_debug_leave();
-}
-
-static int mfc_nal_q_find_ctx(struct s5p_mfc_dev *dev, EncoderOutputStr *pOutputStr)
-{
- int i;
-
- if (!dev) {
- mfc_err_dev("[NALQ] no mfc device to run\n");
- return -EINVAL;
- }
-
- for(i = 0; i < MFC_NUM_CONTEXTS; i++) {
- if (dev->ctx[i] && dev->ctx[i]->inst_no == pOutputStr->InstanceId)
- return i;
- }
- return -1;
-}
-
-static nal_queue_in_handle* mfc_nal_q_create_in_q(struct s5p_mfc_dev *dev,
- nal_queue_handle *nal_q_handle)
-{
- nal_queue_in_handle *nal_q_in_handle;
-
- mfc_debug_enter();
-
- if (!dev) {
- mfc_err_dev("[NALQ] no mfc device to run\n");
- return NULL;
- }
-
- nal_q_in_handle = kzalloc(sizeof(*nal_q_in_handle), GFP_KERNEL);
- if (!nal_q_in_handle) {
- mfc_err_dev("[NALQ] Failed to get memory for nal_queue_in_handle\n");
- return NULL;
- }
-
- nal_q_in_handle->nal_q_handle = nal_q_handle;
- nal_q_in_handle->in_buf.buftype = MFCBUF_NORMAL;
- nal_q_in_handle->in_buf.size = NAL_Q_IN_ENTRY_SIZE * (NAL_Q_IN_QUEUE_SIZE + 2);
- if (s5p_mfc_mem_ion_alloc(dev, &nal_q_in_handle->in_buf)) {
- mfc_err_dev("[NALQ] failed to get memory\n");
- kfree(nal_q_in_handle);
- return NULL;
- }
- nal_q_in_handle->nal_q_in_addr = (nal_in_queue *)nal_q_in_handle->in_buf.vaddr;
-
- mfc_debug_leave();
-
- return nal_q_in_handle;
-}
-
-static nal_queue_out_handle* mfc_nal_q_create_out_q(struct s5p_mfc_dev *dev,
- nal_queue_handle *nal_q_handle)
-{
- nal_queue_out_handle *nal_q_out_handle;
-
- mfc_debug_enter();
-
- if (!dev) {
- mfc_err_dev("[NALQ] no mfc device to run\n");
- return NULL;
- }
-
- nal_q_out_handle = kzalloc(sizeof(*nal_q_out_handle), GFP_KERNEL);
- if (!nal_q_out_handle) {
- mfc_err_dev("[NALQ] failed to get memory for nal_queue_out_handle\n");
- return NULL;
- }
-
- nal_q_out_handle->nal_q_handle = nal_q_handle;
- nal_q_out_handle->out_buf.buftype = MFCBUF_NORMAL;
- nal_q_out_handle->out_buf.size = NAL_Q_OUT_ENTRY_SIZE * (NAL_Q_OUT_QUEUE_SIZE + 2);
- if (s5p_mfc_mem_ion_alloc(dev, &nal_q_out_handle->out_buf)) {
- mfc_err_dev("[NALQ] failed to get memory\n");
- kfree(nal_q_out_handle);
- return NULL;
- }
- nal_q_out_handle->nal_q_out_addr = (nal_out_queue *)nal_q_out_handle->out_buf.vaddr;
-
- mfc_debug_leave();
-
- return nal_q_out_handle;
-}
-
-static int mfc_nal_q_destroy_in_q(struct s5p_mfc_dev *dev,
- nal_queue_in_handle *nal_q_in_handle)
-{
- mfc_debug_enter();
-
- if (!nal_q_in_handle)
- return -EINVAL;
-
- s5p_mfc_mem_ion_free(dev, &nal_q_in_handle->in_buf);
- if (nal_q_in_handle)
- kfree(nal_q_in_handle);
-
- mfc_debug_leave();
-
- return 0;
-}
-
-static int mfc_nal_q_destroy_out_q(struct s5p_mfc_dev *dev,
- nal_queue_out_handle *nal_q_out_handle)
-{
- mfc_debug_enter();
-
- if (!nal_q_out_handle)
- return -EINVAL;
-
- s5p_mfc_mem_ion_free(dev, &nal_q_out_handle->out_buf);
- if (nal_q_out_handle)
- kfree(nal_q_out_handle);
-
- mfc_debug_leave();
-
- return 0;
-}
-
-/*
- * This function should be called after s5p_mfc_alloc_firmware() being called.
- */
-nal_queue_handle *s5p_mfc_nal_q_create(struct s5p_mfc_dev *dev)
-{
- nal_queue_handle *nal_q_handle;
-
- mfc_debug_enter();
-
- if (!dev) {
- mfc_err_dev("[NALQ] no mfc device to run\n");
- return NULL;
- }
-
- nal_q_handle = kzalloc(sizeof(*nal_q_handle), GFP_KERNEL);
- if (!nal_q_handle) {
- mfc_err_dev("[NALQ] no nal_q_handle\n");
- return NULL;
- }
-
- nal_q_handle->nal_q_in_handle = mfc_nal_q_create_in_q(dev, nal_q_handle);
- if (!nal_q_handle->nal_q_in_handle) {
- kfree(nal_q_handle);
- mfc_err_dev("[NALQ] no nal_q_in_handle\n");
- return NULL;
- }
-
- spin_lock_init(&nal_q_handle->lock);
-
- nal_q_handle->nal_q_out_handle = mfc_nal_q_create_out_q(dev, nal_q_handle);
- if (!nal_q_handle->nal_q_out_handle) {
- mfc_nal_q_destroy_in_q(dev, nal_q_handle->nal_q_in_handle);
- kfree(nal_q_handle);
- mfc_err_dev("[NALQ] no nal_q_out_handle\n");
- return NULL;
- }
-
- nal_q_handle->nal_q_state = NAL_Q_STATE_CREATED;
- MFC_TRACE_DEV("** NAL Q state : %d\n", nal_q_handle->nal_q_state);
- mfc_debug(2, "[NALQ] handle created, state = %d\n", nal_q_handle->nal_q_state);
-
- mfc_debug_leave();
-
- return nal_q_handle;
-}
-
-int s5p_mfc_nal_q_destroy(struct s5p_mfc_dev *dev, nal_queue_handle *nal_q_handle)
-{
- int ret = 0;
-
- mfc_debug_enter();
-
- if (!dev) {
- mfc_err_dev("[NALQ] no mfc device to run\n");
- return -EINVAL;
- }
-
- if (!nal_q_handle) {
- mfc_err_dev("[NALQ] there isn't nal_q_handle\n");
- return -EINVAL;
- }
-
- ret = mfc_nal_q_destroy_out_q(dev, nal_q_handle->nal_q_out_handle);
- if (ret) {
- mfc_err_dev("[NALQ] failed nal_q_out_handle destroy\n");
- return ret;
- }
-
- ret = mfc_nal_q_destroy_in_q(dev, nal_q_handle->nal_q_in_handle);
- if (ret) {
- mfc_err_dev("[NALQ] failed nal_q_in_handle destroy\n");
- return ret;
- }
-
- kfree(nal_q_handle);
- dev->nal_q_handle = NULL;
-
- mfc_debug_leave();
-
- return ret;
-}
-
-void s5p_mfc_nal_q_init(struct s5p_mfc_dev *dev, nal_queue_handle *nal_q_handle)
-{
- mfc_debug_enter();
-
- if (!dev) {
- mfc_err_dev("[NALQ] no mfc device to run\n");
- return;
- }
-
- if (!nal_q_handle) {
- mfc_err_dev("[NALQ] There is no nal_q_handle\n");
- return;
- }
-
- if ((nal_q_handle->nal_q_state != NAL_Q_STATE_CREATED)
- && (nal_q_handle->nal_q_state != NAL_Q_STATE_STOPPED)) {
- mfc_err_dev("[NALQ] State is wrong, state: %d\n", nal_q_handle->nal_q_state);
- return;
- }
-
- s5p_mfc_reset_nal_queue_registers(dev);
-
- nal_q_handle->nal_q_in_handle->in_exe_count = 0;
- nal_q_handle->nal_q_out_handle->out_exe_count = 0;
-
- mfc_debug(2, "[NALQ] S5P_FIMV_NAL_QUEUE_INPUT_COUNT=%d\n",
- s5p_mfc_get_nal_q_input_count());
- mfc_debug(2, "[NALQ] S5P_FIMV_NAL_QUEUE_OUTPUT_COUNT=%d\n",
- s5p_mfc_get_nal_q_output_count());
- mfc_debug(2, "[NALQ] S5P_FIMV_NAL_QUEUE_INPUT_EXE_COUNT=%d\n",
- s5p_mfc_get_nal_q_input_exe_count());
- mfc_debug(2, "[NALQ] S5P_FIMV_NAL_QUEUE_INFO=%d\n",
- s5p_mfc_get_nal_q_info());
-
- nal_q_handle->nal_q_exception = 0;
-
- mfc_debug_leave();
-
- return;
-}
-
-void s5p_mfc_nal_q_start(struct s5p_mfc_dev *dev, nal_queue_handle *nal_q_handle)
-{
- dma_addr_t addr;
-
- mfc_debug_enter();
-
- if (!dev) {
- mfc_err_dev("[NALQ] no mfc device to run\n");
- return;
- }
-
- if (!nal_q_handle) {
- mfc_err_dev("[NALQ] There is no nal_q_handle\n");
- return;
- }
-
- if (nal_q_handle->nal_q_state != NAL_Q_STATE_CREATED) {
- mfc_err_dev("[NALQ] State is wrong, state: %d\n", nal_q_handle->nal_q_state);
- return;
- }
-
- addr = nal_q_handle->nal_q_in_handle->in_buf.daddr;
-
- s5p_mfc_update_nal_queue_input(dev, addr, NAL_Q_IN_ENTRY_SIZE * NAL_Q_IN_QUEUE_SIZE);
-
- mfc_debug(2, "[NALQ] S5P_FIMV_NAL_QUEUE_INPUT_ADDR=0x%x\n",
- s5p_mfc_get_nal_q_input_addr());
- mfc_debug(2, "[NALQ] S5P_FIMV_NAL_QUEUE_INPUT_SIZE=%d\n",
- s5p_mfc_get_nal_q_input_size());
-
- addr = nal_q_handle->nal_q_out_handle->out_buf.daddr;
-
- s5p_mfc_update_nal_queue_output(dev, addr, NAL_Q_OUT_ENTRY_SIZE * NAL_Q_OUT_QUEUE_SIZE);
-
- mfc_debug(2, "[NALQ] S5P_FIMV_NAL_QUEUE_OUTPUT_ADDR=0x%x\n",
- s5p_mfc_get_nal_q_output_addr());
- mfc_debug(2, "[NALQ] S5P_FIMV_NAL_QUEUE_OUTPUT_SIZE=%d\n",
- s5p_mfc_get_nal_q_output_ize());
-
- nal_q_handle->nal_q_state = NAL_Q_STATE_STARTED;
- MFC_TRACE_DEV("** NAL Q state : %d\n", nal_q_handle->nal_q_state);
- mfc_debug(2, "[NALQ] started, state = %d\n", nal_q_handle->nal_q_state);
-
- MFC_WRITEL(MFC_TIMEOUT_VALUE, S5P_FIMV_DEC_TIMEOUT_VALUE);
- s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_NAL_QUEUE);
-
- mfc_debug_leave();
-
- return;
-}
-
-void s5p_mfc_nal_q_stop(struct s5p_mfc_dev *dev, nal_queue_handle *nal_q_handle)
-{
- mfc_debug_enter();
-
- if (!dev) {
- mfc_err_dev("[NALQ] no mfc device to run\n");
- return;
- }
-
- if (!nal_q_handle) {
- mfc_err_dev("[NALQ] There is no nal_q_handle\n");
- return;
- }
-
- if (nal_q_handle->nal_q_state != NAL_Q_STATE_STARTED) {
- mfc_err_dev("[NALQ] State is wrong, state: %d\n", nal_q_handle->nal_q_state);
- return;
- }
-
- nal_q_handle->nal_q_state = NAL_Q_STATE_STOPPED;
- MFC_TRACE_DEV("** NAL Q state : %d\n", nal_q_handle->nal_q_state);
- mfc_debug(2, "[NALQ] stopped, state = %d\n", nal_q_handle->nal_q_state);
-
- s5p_mfc_clean_dev_int_flags(dev);
-
- s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_STOP_QUEUE);
-
- mfc_debug_leave();
-
- return;
-}
-
-void s5p_mfc_nal_q_stop_if_started(struct s5p_mfc_dev *dev)
-{
- nal_queue_handle *nal_q_handle;
-
- mfc_debug_enter();
-
- if (!dev) {
- mfc_err_dev("[NALQ] no mfc device to run\n");
- return;
- }
-
- nal_q_handle = dev->nal_q_handle;
- if (!nal_q_handle) {
- mfc_err_dev("[NALQ] There is no nal_q_handle\n");
- return;
- }
-
- if (nal_q_handle->nal_q_state != NAL_Q_STATE_STARTED) {
- mfc_debug(2, "[NALQ] it is not running, state: %d\n",
- nal_q_handle->nal_q_state);
- return;
- }
-
- s5p_mfc_nal_q_clock_on(dev, nal_q_handle);
-
- s5p_mfc_nal_q_stop(dev, nal_q_handle);
- mfc_info_dev("[NALQ] stop NAL QUEUE during get hwlock\n");
- if (s5p_mfc_wait_for_done_dev(dev,
- S5P_FIMV_R2H_CMD_COMPLETE_QUEUE_RET)) {
- mfc_err_dev("[NALQ] Failed to stop qeueue during get hwlock\n");
- dev->logging_data->cause |= (1 << MFC_CAUSE_FAIL_STOP_NAL_Q_FOR_OTHER);
- call_dop(dev, dump_and_stop_always, dev);
- }
-
- mfc_debug_leave();
- return;
-}
-
-void s5p_mfc_nal_q_cleanup_queue(struct s5p_mfc_dev *dev)
-{
- struct s5p_mfc_ctx *ctx;
- int i;
-
- mfc_debug_enter();
-
- if (!dev) {
- mfc_err_dev("[NALQ] no mfc device to run\n");
- return;
- }
-
- for(i = 0; i < MFC_NUM_CONTEXTS; i++) {
- ctx = dev->ctx[i];
- if (ctx) {
- s5p_mfc_cleanup_nal_queue(ctx);
- if (s5p_mfc_ctx_ready(ctx)) {
- s5p_mfc_set_bit(ctx->num, &dev->work_bits);
- mfc_debug(2, "[NALQ] set work_bits after cleanup,"
- " ctx: %d\n", ctx->num);
- }
- }
- }
-
- mfc_debug_leave();
-
- return;
-}
-
-static void mfc_nal_q_set_slice_mode(struct s5p_mfc_ctx *ctx, EncoderInputStr *pInStr)
-{
- struct s5p_mfc_enc *enc = ctx->enc_priv;
-
- /* multi-slice control */
- if (enc->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES)
- pInStr->MsliceMode = enc->slice_mode + 0x4;
- else if (enc->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB_ROW)
- pInStr->MsliceMode = enc->slice_mode - 0x2;
- else if (enc->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_FIXED_BYTES)
- pInStr->MsliceMode = enc->slice_mode + 0x3;
- else
- pInStr->MsliceMode = enc->slice_mode;
-
- /* multi-slice MB number or bit size */
- if ((enc->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) ||
- (enc->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB_ROW)) {
- pInStr->MsliceSizeMb = enc->slice_size.mb;
- } else if ((enc->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) ||
- (enc->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_FIXED_BYTES)){
- pInStr->MsliceSizeBits = enc->slice_size.bits;
- } else {
- pInStr->MsliceSizeMb = 0;
- pInStr->MsliceSizeBits = 0;
- }
-}
-
-static int mfc_nal_q_run_in_buf_enc(struct s5p_mfc_ctx *ctx, EncoderInputStr *pInStr)
-{
- struct s5p_mfc_dev *dev;
- struct s5p_mfc_buf *src_mb, *dst_mb;
- struct s5p_mfc_raw_info *raw = NULL;
- dma_addr_t src_addr[3] = {0, 0, 0};
- dma_addr_t addr_2bit[2] = {0, 0};
- unsigned int index, i;
-
- mfc_debug_enter();
-
- if (!ctx) {
- mfc_err_dev("[NALQ] no mfc context to run\n");
- return -EINVAL;
- }
- dev = ctx->dev;
- if (!dev) {
- mfc_err_dev("[NALQ] no mfc device to run\n");
- return -EINVAL;
- }
-
- pInStr->StartCode = 0xBBBBBBBB;
- pInStr->CommandId = s5p_mfc_get_nal_q_input_count();
- pInStr->InstanceId = ctx->inst_no;
-
- raw = &ctx->raw_buf;
-
- if (IS_BUFFER_BATCH_MODE(ctx)) {
- src_mb = s5p_mfc_get_buf(&ctx->buf_queue_lock, &ctx->src_buf_queue, MFC_BUF_SET_USED);
- if (!src_mb) {
- mfc_err_dev("[NALQ][BUFCON] no src buffers\n");
- return -EAGAIN;
- }
-
- /* last image in a buffer container */
- /* move src_queue -> src_queue_nal_q */
- if (src_mb->next_index == (src_mb->num_valid_bufs - 1)) {
- src_mb = s5p_mfc_get_move_buf(&ctx->buf_queue_lock,
- &ctx->src_buf_nal_queue, &ctx->src_buf_queue,
- MFC_BUF_SET_USED, MFC_QUEUE_ADD_BOTTOM);
- if (!src_mb) {
- mfc_err_dev("[NALQ][BUFCON] no src buffers\n");
- return -EAGAIN;
- }
- }
-
- index = src_mb->vb.vb2_buf.index;
- for (i = 0; i < raw->num_planes; i++) {
- src_addr[i] = src_mb->addr[src_mb->next_index][i];
- mfc_debug(2, "[NALQ][BUFCON][BUFINFO] ctx[%d] set src index:%d, batch[%d], addr[%d]: 0x%08llx\n",
- ctx->num, index, src_mb->next_index, i, src_addr[i]);
- }
- src_mb->next_index++;
- } else {
- /* move src_queue -> src_queue_nal_q */
- src_mb = s5p_mfc_get_move_buf(&ctx->buf_queue_lock,
- &ctx->src_buf_nal_queue, &ctx->src_buf_queue,
- MFC_BUF_SET_USED, MFC_QUEUE_ADD_BOTTOM);
- if (!src_mb) {
- mfc_err_dev("[NALQ] no src buffers\n");
- return -EAGAIN;
- }
-
- index = src_mb->vb.vb2_buf.index;
- for (i = 0; i < raw->num_planes; i++) {
- src_addr[i] = src_mb->addr[0][i];
- mfc_debug(2, "[NALQ][BUFINFO] ctx[%d] set src index:%d, addr[%d]: 0x%08llx\n",
- ctx->num, index, i, src_addr[i]);
- }
- }
-
- for (i = 0; i < raw->num_planes; i++)
- pInStr->FrameAddr[i] = src_addr[i];
-
- if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M_S10B ||
- ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV21M_S10B) {
- addr_2bit[0] = src_addr[0] + NV12N_Y_SIZE(ctx->img_width, ctx->img_height);
- addr_2bit[1] = src_addr[1] + NV12N_CBCR_SIZE(ctx->img_width, ctx->img_height);
-
- for (i = 0; i < raw->num_planes; i++) {
- pInStr->Frame2bitAddr[i] = addr_2bit[i];
- mfc_debug(2, "[NALQ][BUFINFO] ctx[%d] set src 2bit addr[%d]: 0x%08llx\n",
- ctx->num, index, i, addr_2bit[i]);
- }
- } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV16M_S10B ||
- ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV61M_S10B) {
- addr_2bit[0] = src_addr[0] + NV16M_Y_SIZE(ctx->img_width, ctx->img_height);
- addr_2bit[1] = src_addr[1] + NV16M_CBCR_SIZE(ctx->img_width, ctx->img_height);
-
- for (i = 0; i < raw->num_planes; i++) {
- pInStr->Frame2bitAddr[i] = addr_2bit[i];
- mfc_debug(2, "[NALQ][BUFINFO] ctx[%d] set src 2bit addr[%d]: 0x%08llx\n",
- ctx->num, index, i, addr_2bit[i]);
- }
- }
-
- /* move dst_queue -> dst_queue_nal_q */
- dst_mb = s5p_mfc_get_move_buf(&ctx->buf_queue_lock,
- &ctx->dst_buf_nal_queue, &ctx->dst_buf_queue, MFC_BUF_SET_USED, MFC_QUEUE_ADD_BOTTOM);
- if (!dst_mb) {
- mfc_err_dev("[NALQ] no dst buffers\n");
- return -EAGAIN;
- }
-
- pInStr->StreamBufferAddr = dst_mb->addr[0][0];
- pInStr->StreamBufferSize = (unsigned int)vb2_plane_size(&dst_mb->vb.vb2_buf, 0);
- pInStr->StreamBufferSize = ALIGN(pInStr->StreamBufferSize, 512);
-
- if (call_cop(ctx, set_buf_ctrls_val_nal_q_enc, ctx, &ctx->src_ctrls[index], pInStr) < 0)
- mfc_err_ctx("[NALQ] failed in set_buf_ctrals_val in nal q\n");
-
- mfc_debug(2, "[NALQ][BUFINFO] ctx[%d] set dst index: %d, addr: 0x%08llx\n",
- ctx->num, dst_mb->vb.vb2_buf.index, pInStr->StreamBufferAddr);
- mfc_debug(2, "[NALQ] input queue, src_buf_queue -> src_buf_nal_queue, index:%d\n",
- src_mb->vb.vb2_buf.index);
- mfc_debug(2, "[NALQ] input queue, dst_buf_queue -> dst_buf_nal_queue, index:%d\n",
- dst_mb->vb.vb2_buf.index);
-
- mfc_nal_q_set_slice_mode(ctx, pInStr);
-
- mfc_debug_leave();
-
- return 0;
-}
-
-static int mfc_nal_q_run_in_buf_dec(struct s5p_mfc_ctx *ctx, DecoderInputStr *pInStr)
-{
- struct s5p_mfc_dev *dev;
- struct s5p_mfc_buf *src_mb, *dst_mb;
- struct s5p_mfc_dec *dec;
- struct s5p_mfc_raw_info *raw = &ctx->raw_buf;
- dma_addr_t buf_addr;
- unsigned int strm_size;
- unsigned int cpb_buf_size;
- int src_index, dst_index;
- int i;
-
- mfc_debug_enter();
-
- if (!ctx) {
- mfc_err_dev("[NALQ] no mfc context to run\n");
- return -EINVAL;
- }
- dev = ctx->dev;
- if (!dev) {
- mfc_err_dev("[NALQ] no mfc device to run\n");
- return -EINVAL;
- }
- dec = ctx->dec_priv;
- if (!dec) {
- mfc_err_dev("[NALQ] no mfc decoder to run\n");
- return -EINVAL;
- }
-
- if (s5p_mfc_is_queue_count_same(&ctx->buf_queue_lock, &ctx->dst_buf_queue, 0) &&
- s5p_mfc_is_queue_count_smaller(&ctx->buf_queue_lock,
- &ctx->ref_buf_queue, (ctx->dpb_count + 5))) {
- mfc_err_dev("[NALQ] no dst buffers\n");
- return -EAGAIN;
- }
-
- if (s5p_mfc_is_queue_count_same(&ctx->buf_queue_lock, &ctx->src_buf_queue, 0)) {
- mfc_err_dev("[NALQ] no src buffers\n");
- return -EAGAIN;
- }
-
- pInStr->StartCode = 0xAAAAAAAA;
- pInStr->CommandId = s5p_mfc_get_nal_q_input_count();
- pInStr->InstanceId = ctx->inst_no;
- pInStr->NalStartOptions = 0;
-
- /* Try to use the non-referenced DPB on dst-queue */
- dst_mb = s5p_mfc_search_move_dpb_nal_q(ctx, dec->dynamic_used);
- if (!dst_mb) {
- mfc_debug(2, "[NALQ][DPB] couldn't find dst buffers\n");
- return -EAGAIN;
- }
-
- /* move src_queue -> src_queue_nal_q */
- src_mb = s5p_mfc_get_move_buf(&ctx->buf_queue_lock,
- &ctx->src_buf_nal_queue, &ctx->src_buf_queue,
- MFC_BUF_SET_USED, MFC_QUEUE_ADD_BOTTOM);
- if (!src_mb) {
- mfc_err_dev("[NALQ] no src buffers\n");
- return -EAGAIN;
- }
-
- /* src buffer setting */
- src_index = src_mb->vb.vb2_buf.index;
- buf_addr = src_mb->addr[0][0];
- strm_size = src_mb->vb.vb2_buf.planes[0].bytesused;
- cpb_buf_size = ALIGN(dec->src_buf_size, STREAM_BUF_ALIGN);
-
- if (strm_size > set_strm_size_max(cpb_buf_size)) {
- mfc_info_ctx("[NALQ] Decrease strm_size : %u -> %u, gap : %d\n",
- strm_size, set_strm_size_max(cpb_buf_size), STREAM_BUF_ALIGN);
- strm_size = set_strm_size_max(cpb_buf_size);
- src_mb->vb.vb2_buf.planes[0].bytesused = strm_size;
- }
-
- mfc_debug(2, "[NALQ][BUFINFO] ctx[%d] set src index: %d, addr: 0x%08llx\n",
- ctx->num, src_index, buf_addr);
- mfc_debug(2, "[NALQ][STREAM] strm_size: %#lx(%d), buf_size: %u\n",
- strm_size, strm_size, cpb_buf_size);
-
- if (strm_size == 0)
- mfc_info_ctx("stream size is 0\n");
-
- pInStr->StreamDataSize = strm_size;
- pInStr->CpbBufferAddr = buf_addr;
- pInStr->CpbBufferSize = cpb_buf_size;
- pInStr->CpbBufferOffset = 0;
-
- MFC_TRACE_CTX("Set src[%d] fd: %d, %#llx\n",
- src_index, src_mb->vb.vb2_buf.planes[0].m.fd, buf_addr);
-
- /* dst buffer setting */
- dst_index = dst_mb->vb.vb2_buf.index;
- set_bit(dst_index, &dec->available_dpb);
- dec->dynamic_set = 1 << dst_index;
-
- for (i = 0; i < raw->num_planes; i++) {
- pInStr->FrameSize[i] = raw->plane_size[i];
- pInStr->FrameAddr[i] = dst_mb->addr[0][i];
- if (ctx->is_10bit)
- pInStr->Frame2BitSize[i] = raw->plane_size_2bits[i];
- mfc_debug(2, "[NALQ][BUFINFO][DPB] ctx[%d] set dst index: %d, addr[%d]: 0x%08llx\n",
- ctx->num, dst_index, i, dst_mb->addr[0][i]);
- }
-
- pInStr->ScratchBufAddr = ctx->codec_buf.daddr;
- pInStr->ScratchBufSize = ctx->scratch_buf_size;
-
- if (call_cop(ctx, set_buf_ctrls_val_nal_q_dec, ctx,
- &ctx->src_ctrls[src_index], pInStr) < 0)
- mfc_err_ctx("[NALQ] failed in set_buf_ctrls_val\n");
-
- pInStr->DynamicDpbFlagLower = dec->dynamic_set;
-
- /* use dynamic_set value to available dpb in NAL Q */
- // pInStr->AvailableDpbFlagLower = dec->available_dpb;
- pInStr->AvailableDpbFlagLower = dec->dynamic_set;
-
- MFC_TRACE_CTX("Set dst[%d] fd: %d, %#llx / avail %#lx used %#x\n",
- dst_index, dst_mb->vb.vb2_buf.planes[0].m.fd, dst_mb->addr[0][0],
- dec->available_dpb, dec->dynamic_used);
-
- mfc_debug_leave();
-
- return 0;
-}
-
-static void mfc_nal_q_get_enc_frame_buffer(struct s5p_mfc_ctx *ctx,
- dma_addr_t addr[], int num_planes, EncoderOutputStr *pOutStr)
-{
- unsigned long enc_recon_y_addr, enc_recon_c_addr;
- int i;
-
- for (i = 0; i < num_planes; i++)
- addr[i] = pOutStr->EncodedFrameAddr[i];
-
- enc_recon_y_addr = pOutStr->ReconLumaDpbAddr;
- enc_recon_c_addr = pOutStr->ReconChromaDpbAddr;
-
- mfc_debug(2, "[NALQ][MEMINFO] recon y: 0x%08lx c: 0x%08lx\n",
- enc_recon_y_addr, enc_recon_c_addr);
-}
-
-static void mfc_nal_q_handle_stream_copy_timestamp(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *src_mb)
-{
- struct s5p_mfc_dev *dev;
- struct s5p_mfc_enc *enc = ctx->enc_priv;
- struct s5p_mfc_enc_params *p = &enc->params;
- struct s5p_mfc_buf *dst_mb;
- u32 interval;
- u64 start_timestamp;
- u64 new_timestamp;
-
- if (!ctx) {
- mfc_err_dev("[NALQ][BUFCON][TS] no mfc context to run\n");
- return;
- }
-
- dev = ctx->dev;
- if (!dev) {
- mfc_err_dev("[NALQ][BUFCON][TS] no device to run\n");
- return;
- }
-
- start_timestamp = src_mb->vb.vb2_buf.timestamp;
- interval = NSEC_PER_SEC / p->rc_framerate;
- if (debug_ts == 1)
- mfc_info_ctx("[NALQ][BUFCON][TS] %dfps, start timestamp: %lld, base interval: %d\n",
- p->rc_framerate, start_timestamp, interval);
-
- new_timestamp = start_timestamp + (interval * src_mb->done_index);
- if (debug_ts == 1)
- mfc_info_ctx("[NALQ][BUFCON][TS] new timestamp: %lld, interval: %d\n",
- new_timestamp, interval * src_mb->done_index);
-
- /* Get the destination buffer */
- dst_mb = s5p_mfc_get_buf(&ctx->buf_queue_lock, &ctx->dst_buf_nal_queue, MFC_BUF_NO_TOUCH_USED);
- if (dst_mb)
- dst_mb->vb.vb2_buf.timestamp = new_timestamp;
-}
-
-static void mfc_nal_q_handle_stream_input(struct s5p_mfc_ctx *ctx, EncoderOutputStr *pOutStr)
-{
- struct s5p_mfc_buf *src_mb, *ref_mb;
- dma_addr_t enc_addr[3] = { 0, 0, 0 };
- struct s5p_mfc_raw_info *raw;
- int found_in_src_queue = 0;
- unsigned int i;
-
- raw = &ctx->raw_buf;
-
- mfc_nal_q_get_enc_frame_buffer(ctx, &enc_addr[0], raw->num_planes, pOutStr);
- if (enc_addr[0] == 0) {
- mfc_debug(3, "[NALQ] no encoded src\n");
- goto move_buf;
- }
-
- for (i = 0; i < raw->num_planes; i++)
- mfc_debug(2, "[NALQ][BUFINFO] ctx[%d] get src addr[%d]: 0x%08llx\n",
- ctx->num, i, enc_addr[i]);
-
- if (IS_BUFFER_BATCH_MODE(ctx)) {
- src_mb = s5p_mfc_find_first_buf(&ctx->buf_queue_lock,
- &ctx->src_buf_queue, enc_addr[0]);
- if (src_mb) {
- found_in_src_queue = 1;
-
- mfc_nal_q_handle_stream_copy_timestamp(ctx, src_mb);
- src_mb->done_index++;
- mfc_debug(4, "[NALQ][BUFCON] batch buf done_index: %d\n", src_mb->done_index);
- } else {
- src_mb = s5p_mfc_find_first_buf(&ctx->buf_queue_lock,
- &ctx->src_buf_nal_queue, enc_addr[0]);
- if (src_mb) {
- found_in_src_queue = 1;
-
- mfc_nal_q_handle_stream_copy_timestamp(ctx, src_mb);
- src_mb->done_index++;
- mfc_debug(4, "[NALQ][BUFCON] batch buf done_index: %d\n", src_mb->done_index);
-
- /* last image in a buffer container */
- if (src_mb->done_index == src_mb->num_valid_bufs) {
- src_mb = s5p_mfc_find_del_buf(&ctx->buf_queue_lock,
- &ctx->src_buf_nal_queue, enc_addr[0]);
- for (i = 0; i < raw->num_planes; i++)
- s5p_mfc_bufcon_put_daddr(ctx, src_mb, i);
- vb2_buffer_done(&src_mb->vb.vb2_buf, VB2_BUF_STATE_DONE);
- }
- }
- }
- } else {
- src_mb = s5p_mfc_find_del_buf(&ctx->buf_queue_lock,
- &ctx->src_buf_nal_queue, enc_addr[0]);
- if (src_mb) {
- mfc_debug(3, "[NALQ] find src buf in src_queue\n");
- found_in_src_queue = 1;
- vb2_buffer_done(&src_mb->vb.vb2_buf, VB2_BUF_STATE_DONE);
- } else {
- mfc_debug(3, "[NALQ] no src buf in src_queue\n");
- ref_mb = s5p_mfc_find_del_buf(&ctx->buf_queue_lock,
- &ctx->ref_buf_queue, enc_addr[0]);
- if (ref_mb) {
- mfc_debug(3, "[NALQ] find src buf in ref_queue\n");
- vb2_buffer_done(&ref_mb->vb.vb2_buf, VB2_BUF_STATE_DONE);
- } else {
- mfc_err_ctx("[NALQ] couldn't find src buffer\n");
- }
- }
- }
-
-move_buf:
- /* move enqueued src buffer: src nal queue -> ref queue */
- if (!found_in_src_queue) {
- src_mb = s5p_mfc_get_move_buf_used(&ctx->buf_queue_lock,
- &ctx->ref_buf_queue, &ctx->src_buf_nal_queue);
- if (!src_mb)
- mfc_err_dev("[NALQ] no src buffers\n");
-
- mfc_debug(2, "[NALQ] enc src_buf_nal_queue(%d) -> ref_buf_queue(%d)\n",
- s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->src_buf_nal_queue),
- s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->ref_buf_queue));
- }
-}
-
-static void mfc_nal_q_handle_stream_output(struct s5p_mfc_ctx *ctx, int slice_type,
- unsigned int strm_size, EncoderOutputStr *pOutStr)
-{
- struct s5p_mfc_buf *dst_mb;
- unsigned int index;
-
- if (strm_size == 0) {
- mfc_debug(3, "[NALQ] no encoded dst (reuse)\n");
- dst_mb = s5p_mfc_get_move_buf(&ctx->buf_queue_lock,
- &ctx->dst_buf_queue, &ctx->dst_buf_nal_queue,
- MFC_BUF_RESET_USED, MFC_QUEUE_ADD_TOP);
- if (!dst_mb) {
- mfc_err_dev("[NALQ] no dst buffers\n");
- return;
- }
-
- mfc_debug(2, "[NALQ] no output, dst_buf_nal_queue(%d) -> dst_buf_queue(%d) index:%d\n",
- s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->dst_buf_nal_queue),
- s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->dst_buf_queue),
- dst_mb->vb.vb2_buf.index);
- return;
- } else if (strm_size < 0) {
- mfc_err_ctx("[NALQ] invalid stream size: %d\n", strm_size);
- return;
- }
-
- /* at least one more dest. buffers exist always */
- dst_mb = s5p_mfc_get_del_buf(&ctx->buf_queue_lock, &ctx->dst_buf_nal_queue, MFC_BUF_NO_TOUCH_USED);
- if (!dst_mb) {
- mfc_err_dev("[NALQ] no dst buffers\n");
- return;
- }
-
- mfc_debug(2, "[NALQ][BUFINFO] ctx[%d] get dst addr: 0x%08llx\n",
- ctx->num, dst_mb->addr[0][0]);
-
- dst_mb->vb.flags &= ~(V4L2_BUF_FLAG_KEYFRAME |
- V4L2_BUF_FLAG_PFRAME |
- V4L2_BUF_FLAG_BFRAME);
-
- switch (slice_type) {
- case S5P_FIMV_E_SLICE_TYPE_I:
- dst_mb->vb.flags |= V4L2_BUF_FLAG_KEYFRAME;
- break;
- case S5P_FIMV_E_SLICE_TYPE_P:
- dst_mb->vb.flags |= V4L2_BUF_FLAG_PFRAME;
- break;
- case S5P_FIMV_E_SLICE_TYPE_B:
- dst_mb->vb.flags |= V4L2_BUF_FLAG_BFRAME;
- break;
- default:
- dst_mb->vb.flags |= V4L2_BUF_FLAG_KEYFRAME;
- break;
- }
- mfc_debug(2, "[NALQ][STREAM] Slice type flag: %d\n", dst_mb->vb.flags);
-
- vb2_set_plane_payload(&dst_mb->vb.vb2_buf, 0, strm_size);
-
- index = dst_mb->vb.vb2_buf.index;
- if (call_cop(ctx, get_buf_ctrls_val_nal_q_enc, ctx,
- &ctx->dst_ctrls[index], pOutStr) < 0)
- mfc_err_ctx("[NALQ] failed in get_buf_ctrls_val in nal q\n");
-
- vb2_buffer_done(&dst_mb->vb.vb2_buf, VB2_BUF_STATE_DONE);
-}
-
-static void mfc_nal_q_handle_stream(struct s5p_mfc_ctx *ctx, EncoderOutputStr *pOutStr)
-{
- struct s5p_mfc_enc *enc = ctx->enc_priv;
- int slice_type;
- unsigned int strm_size;
- unsigned int pic_count;
-
- mfc_debug_enter();
-
- slice_type = pOutStr->SliceType;
- strm_size = pOutStr->StreamSize;
- pic_count = pOutStr->EncCnt;
-
- mfc_debug(2, "[NALQ][STREAM] encoded slice type: %d, size: %d, display order: %d\n",
- slice_type, strm_size, pic_count);
-
- /* buffer full handling */
- if (ctx->state == MFCINST_RUNNING_BUF_FULL)
- ctx->state = MFCINST_RUNNING;
-
- /* set encoded frame type */
- enc->frame_type = slice_type;
- ctx->sequence++;
-
- /* handle input buffer */
- mfc_nal_q_handle_stream_input(ctx, pOutStr);
-
- /* handle output buffer */
- mfc_nal_q_handle_stream_output(ctx, slice_type, strm_size, pOutStr);
-
- mfc_debug_leave();
-
- return;
-}
-
-static void mfc_nal_q_handle_reuse_buffer(struct s5p_mfc_ctx *ctx, DecoderOutputStr *pOutStr)
-{
- struct s5p_mfc_dec *dec = ctx->dec_priv;
- unsigned int prev_flag, released_flag = 0;
- struct s5p_mfc_buf *dst_mb;
- dma_addr_t disp_addr;
- int i;
-
- /* reuse not used buf: dst_buf_nal_queue -> dst_queue */
- disp_addr = pOutStr->DisplayAddr[0];
- if (disp_addr) {
- mfc_debug(2, "[NALQ][DPB] decoding only but there is disp addr: 0x%llx\n", disp_addr);
- dst_mb = s5p_mfc_get_move_buf_addr(&ctx->buf_queue_lock,
- &ctx->dst_buf_queue, &ctx->dst_buf_nal_queue,
- disp_addr);
- if (dst_mb) {
- mfc_debug(2, "[NALQ][DPB] buf[%d] will reused. addr: 0x%08llx\n",
- dst_mb->vb.vb2_buf.index, disp_addr);
- dst_mb->used = 0;
- clear_bit(dst_mb->vb.vb2_buf.index, &dec->available_dpb);
- }
- }
-
- /* reuse not referenced buf anymore: ref_queue -> dst_queue */
- prev_flag = dec->dynamic_used;
- dec->dynamic_used = pOutStr->UsedDpbFlagLower;
- released_flag = prev_flag & (~dec->dynamic_used);
-
- if (!released_flag)
- return;
-
- for (i = 0; i < MFC_MAX_DPBS; i++)
- if (released_flag & (1 << i))
- if (s5p_mfc_move_reuse_buffer(ctx, i))
- released_flag &= ~(1 << i);
-
- /* Not reused buffer should be released when there is a display frame */
- dec->dec_only_release_flag |= released_flag;
- for (i = 0; i < MFC_MAX_DPBS; i++)
- if (released_flag & (1 << i))
- clear_bit(i, &dec->available_dpb);
-}
-
-static void mfc_nal_q_handle_ref_frame(struct s5p_mfc_ctx *ctx, DecoderOutputStr *pOutStr)
-{
- struct s5p_mfc_dec *dec = ctx->dec_priv;
- struct s5p_mfc_buf *dst_mb;
- dma_addr_t dec_addr;
- int index = 0;
-
- mfc_debug_enter();
-
- dec_addr = pOutStr->DecodedAddr[0];
-
- dst_mb = s5p_mfc_find_move_buf_used(&ctx->buf_queue_lock,
- &ctx->ref_buf_queue, &ctx->dst_buf_nal_queue, dec_addr);
- if (dst_mb) {
- mfc_debug(2, "[NALQ][DPB] Found in dst queue = 0x%08llx, buf = 0x%08llx\n",
- dec_addr, dst_mb->addr[0][0]);
-
- index = dst_mb->vb.vb2_buf.index;
- if (!((1 << index) & pOutStr->UsedDpbFlagLower))
- dec->dynamic_used |= 1 << index;
- } else {
- mfc_debug(2, "[NALQ][DPB] Can't find buffer for addr: 0x%08llx\n", dec_addr);
- }
-
- mfc_debug_leave();
-}
-
-static void mfc_nal_q_handle_frame_copy_timestamp(struct s5p_mfc_ctx *ctx, DecoderOutputStr *pOutStr)
-{
- struct s5p_mfc_dec *dec;
- struct s5p_mfc_dev *dev;
- struct s5p_mfc_buf *ref_mb, *src_mb;
- dma_addr_t dec_y_addr;
-
- mfc_debug_enter();
-
- if (!ctx) {
- mfc_err_dev("[TS] no mfc context to run\n");
- return;
- }
-
- dec = ctx->dec_priv;
- dev = ctx->dev;
-
- dec_y_addr = pOutStr->DecodedAddr[0];
-
- /* Get the next source buffer */
- src_mb = s5p_mfc_get_buf(&ctx->buf_queue_lock, &ctx->src_buf_nal_queue, MFC_BUF_NO_TOUCH_USED);
- if (!src_mb) {
- mfc_err_dev("[NALQ] no src buffers\n");
- return;
- }
-
- ref_mb = s5p_mfc_find_buf(&ctx->buf_queue_lock, &ctx->ref_buf_queue, dec_y_addr);
- if (ref_mb)
- ref_mb->vb.vb2_buf.timestamp = src_mb->vb.vb2_buf.timestamp;
-
- mfc_debug_leave();
-}
-
-static void mfc_nal_q_handle_frame_output_move(struct s5p_mfc_ctx *ctx,
- dma_addr_t dspl_y_addr, unsigned int released_flag)
-{
- struct s5p_mfc_dec *dec = ctx->dec_priv;
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_buf *dst_mb;
- unsigned int index;
-
- dst_mb = s5p_mfc_find_move_buf(&ctx->buf_queue_lock,
- &ctx->dst_buf_queue, &ctx->ref_buf_queue, dspl_y_addr, released_flag);
- if (dst_mb) {
- index = dst_mb->vb.vb2_buf.index;
-
- /* Check if this is the buffer we're looking for */
- mfc_debug(2, "[NALQ][DPB] Found buf[%d] 0x%08llx, looking for disp addr 0x%08llx\n",
- index, dst_mb->addr[0][0], dspl_y_addr);
-
- if (released_flag & (1 << index)) {
- dec->available_dpb &= ~(1 << index);
- released_flag &= ~(1 << index);
- mfc_debug(2, "[NALQ][DPB] Corrupted frame(%d), it will be re-used(release)\n",
- s5p_mfc_get_warn(s5p_mfc_get_int_err()));
- } else {
- dec->err_reuse_flag |= 1 << index;
- mfc_debug(2, "[NALQ][DPB] Corrupted frame(%d), it will be re-used(not released)\n",
- s5p_mfc_get_warn(s5p_mfc_get_int_err()));
- }
- dec->dynamic_used |= released_flag;
- }
-}
-
-static void mfc_nal_q_handle_frame_output_del(struct s5p_mfc_ctx *ctx,
- DecoderOutputStr *pOutStr, unsigned int err, unsigned int released_flag)
-{
- struct s5p_mfc_dec *dec = ctx->dec_priv;
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_raw_info *raw = &ctx->raw_buf;
- struct s5p_mfc_buf *ref_mb;
- dma_addr_t dspl_y_addr;
- unsigned int frame_type;
- unsigned int dst_frame_status;
- unsigned int is_video_signal_type = 0, is_colour_description = 0;
- unsigned int is_content_light = 0, is_display_colour = 0;
- unsigned int disp_err;
- int i, index;
-
- if (MFC_FEATURE_SUPPORT(dev, dev->pdata->color_aspect_dec)) {
- is_video_signal_type = ((pOutStr->VideoSignalType
- >> S5P_FIMV_D_VIDEO_SIGNAL_TYPE_FLAG_SHIFT)
- & S5P_FIMV_D_VIDEO_SIGNAL_TYPE_FLAG_MASK);
- is_colour_description = ((pOutStr->VideoSignalType
- >> S5P_FIMV_D_COLOUR_DESCRIPTION_FLAG_SHIFT)
- & S5P_FIMV_D_COLOUR_DESCRIPTION_FLAG_MASK);
- }
-
- if (MFC_FEATURE_SUPPORT(dev, dev->pdata->static_info_dec)) {
- is_content_light = ((pOutStr->SeiAvail >> S5P_FIMV_D_SEI_AVAIL_CONTENT_LIGHT_SHIFT)
- & S5P_FIMV_D_SEI_AVAIL_CONTENT_LIGHT_MASK);
- is_display_colour = ((pOutStr->SeiAvail >> S5P_FIMV_D_SEI_AVAIL_MASTERING_DISPLAY_SHIFT)
- & S5P_FIMV_D_SEI_AVAIL_MASTERING_DISPLAY_MASK);
- }
-
- if (dec->immediate_display == 1) {
- dspl_y_addr = pOutStr->DecodedAddr[0];
- frame_type = pOutStr->DecodedFrameType & S5P_FIMV_DECODED_FRAME_MASK;
- } else {
- dspl_y_addr = pOutStr->DisplayAddr[0];
- frame_type = pOutStr->DisplayFrameType & S5P_FIMV_DISPLAY_FRAME_MASK;
- }
-
- ref_mb = s5p_mfc_find_del_buf(&ctx->buf_queue_lock, &ctx->ref_buf_queue, dspl_y_addr);
- if (ref_mb) {
- index = ref_mb->vb.vb2_buf.index;
-
- /* Check if this is the buffer we're looking for */
- mfc_debug(2, "[NALQ][BUFINFO][DPB] ctx[%d] get dst index: %d, addr[0]: 0x%08llx\n",
- ctx->num, index, ref_mb->addr[0][0]);
-
- ref_mb->vb.sequence = ctx->sequence;
-
- /* Set reserved2 bits in order to inform SEI information */
- ref_mb->vb.reserved2 = 0;
-
- if (is_content_light) {
- ref_mb->vb.reserved2 |= (1 << 0);
- mfc_debug(2, "[NALQ][HDR] content light level parsed\n");
- }
- if (is_display_colour) {
- ref_mb->vb.reserved2 |= (1 << 1);
- mfc_debug(2, "[NALQ][HDR] mastering display colour parsed\n");
- }
- if (is_video_signal_type) {
- ref_mb->vb.reserved2 |= (1 << 4);
- mfc_debug(2, "[NALQ][HDR] video signal type parsed\n");
- if (is_colour_description) {
- ref_mb->vb.reserved2 |= (1 << 2);
- mfc_debug(2, "[NALQ][HDR] matrix coefficients parsed\n");
- ref_mb->vb.reserved2 |= (1 << 3);
- mfc_debug(2, "[NALQ][HDR] colour description parsed\n");
- }
- }
-
- if (IS_VP9_DEC(ctx) && MFC_FEATURE_SUPPORT(dev, dev->pdata->color_aspect_dec)) {
- if (dec->color_space != S5P_FIMV_D_COLOR_UNKNOWN) {
- ref_mb->vb.reserved2 |= (1 << 3);
- mfc_debug(2, "[NALQ][HDR] color space parsed\n");
- }
- ref_mb->vb.reserved2 |= (1 << 4);
- mfc_debug(2, "[NALQ][HDR] color range parsed\n");
- }
-
- for (i = 0; i < raw->num_planes; i++)
- vb2_set_plane_payload(&ref_mb->vb.vb2_buf, i,
- raw->plane_size[i]);
-
- clear_bit(index, &dec->available_dpb);
-
- ref_mb->vb.flags &= ~(V4L2_BUF_FLAG_KEYFRAME |
- V4L2_BUF_FLAG_PFRAME |
- V4L2_BUF_FLAG_BFRAME |
- V4L2_BUF_FLAG_ERROR);
-
- switch (frame_type) {
- case S5P_FIMV_DISPLAY_FRAME_I:
- ref_mb->vb.flags |= V4L2_BUF_FLAG_KEYFRAME;
- break;
- case S5P_FIMV_DISPLAY_FRAME_P:
- ref_mb->vb.flags |= V4L2_BUF_FLAG_PFRAME;
- break;
- case S5P_FIMV_DISPLAY_FRAME_B:
- ref_mb->vb.flags |= V4L2_BUF_FLAG_BFRAME;
- break;
- default:
- break;
- }
-
- disp_err = s5p_mfc_get_warn(pOutStr->ErrorCode);
- if (disp_err) {
- mfc_err_ctx("[NALQ] Warning for displayed frame: %d\n",
- disp_err);
- ref_mb->vb.flags |= V4L2_BUF_FLAG_ERROR;
- }
-
- if (call_cop(ctx, get_buf_ctrls_val_nal_q_dec, ctx,
- &ctx->dst_ctrls[index], pOutStr) < 0)
- mfc_err_ctx("[NALQ] failed in get_buf_ctrls_val\n");
-
- s5p_mfc_handle_released_info(ctx, released_flag, index);
-
- if (dec->immediate_display == 1) {
- dst_frame_status = pOutStr->DecodedStatus
- & S5P_FIMV_DEC_STATUS_DECODED_STATUS_MASK;
-
- call_cop(ctx, get_buf_update_val, ctx,
- &ctx->dst_ctrls[index],
- V4L2_CID_MPEG_MFC51_VIDEO_DISPLAY_STATUS,
- dst_frame_status);
-
- call_cop(ctx, get_buf_update_val, ctx,
- &ctx->dst_ctrls[index],
- V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG,
- dec->stored_tag);
-
- dec->immediate_display = 0;
- }
-
- s5p_mfc_qos_update_last_framerate(ctx, ref_mb->vb.vb2_buf.timestamp);
- vb2_buffer_done(&ref_mb->vb.vb2_buf, disp_err ?
- VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
- }
-}
-
-static void mfc_nal_q_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err,
- DecoderOutputStr *pOutStr)
-{
- struct s5p_mfc_dec *dec = ctx->dec_priv;
- dma_addr_t dspl_y_addr;
- unsigned int frame_type;
- unsigned int prev_flag, released_flag = 0;
- unsigned int disp_err;
-
- mfc_debug_enter();
-
- frame_type = pOutStr->DisplayFrameType & S5P_FIMV_DISPLAY_FRAME_MASK;
- disp_err = s5p_mfc_get_warn(pOutStr->ErrorCode);
-
- ctx->sequence++;
-
- dspl_y_addr = pOutStr->DisplayAddr[0];
-
- if (dec->immediate_display == 1) {
- dspl_y_addr = pOutStr->DecodedAddr[0];
- frame_type = pOutStr->DecodedFrameType & S5P_FIMV_DECODED_FRAME_MASK;
- }
-
- mfc_debug(2, "[NALQ][FRAME] frame type: %d\n", frame_type);
-
- /* If frame is same as previous then skip and do not dequeue */
- if (frame_type == S5P_FIMV_DISPLAY_FRAME_NOT_CODED) {
- if (!CODEC_NOT_CODED(ctx))
- return;
- }
-
- prev_flag = dec->dynamic_used;
- dec->dynamic_used = pOutStr->UsedDpbFlagLower;
- released_flag = prev_flag & (~dec->dynamic_used);
-
- mfc_debug(2, "[NALQ][DPB] Used flag: old = %08x, new = %08x, Released buffer = %08x\n",
- prev_flag, dec->dynamic_used, released_flag);
-
- if ((IS_VC1_RCV_DEC(ctx) &&
- (disp_err == S5P_FIMV_ERR_SYNC_POINT_NOT_RECEIVED)) ||
- (disp_err == S5P_FIMV_ERR_BROKEN_LINK))
- mfc_nal_q_handle_frame_output_move(ctx, dspl_y_addr, released_flag);
- else
- mfc_nal_q_handle_frame_output_del(ctx, pOutStr, err, released_flag);
-
- mfc_debug_leave();
-}
-
-static void mfc_nal_q_handle_frame_input(struct s5p_mfc_ctx *ctx, unsigned int err,
- DecoderOutputStr *pOutStr)
-{
- struct s5p_mfc_dec *dec = ctx->dec_priv;
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_buf *src_mb;
- unsigned int index;
- int deleted = 0;
- unsigned long consumed;
-
- /* If there is consumed byte, it is abnormal status,
- * We have to return remained stream buffer
- */
- if (dec->consumed) {
- mfc_err_dev("[NALQ] previous buffer was not fully consumed\n");
- src_mb = s5p_mfc_get_del_buf(&ctx->buf_queue_lock, &ctx->src_buf_nal_queue,
- MFC_BUF_NO_TOUCH_USED);
- if (src_mb)
- vb2_buffer_done(&src_mb->vb.vb2_buf, VB2_BUF_STATE_DONE);
- }
-
- /* Check multi-frame */
- consumed = pOutStr->DecodedNalSize;
- src_mb = s5p_mfc_get_del_if_consumed(ctx, &ctx->src_buf_nal_queue,
- consumed, STUFF_BYTE, err, &deleted);
- if (!src_mb) {
- mfc_err_dev("[NALQ] no src buffers\n");
- return;
- }
-
- index = src_mb->vb.vb2_buf.index;
- mfc_debug(2, "[NALQ][BUFINFO] ctx[%d] get src index: %d, addr: 0x%08llx\n",
- ctx->num, index, src_mb->addr[0][0]);
-
- if (!deleted) {
- /* Run MFC again on the same buffer */
- mfc_debug(2, "[NALQ][MULTIFRAME] Running again the same buffer\n");
-
- if (CODEC_MULTIFRAME(ctx))
- dec->y_addr_for_pb = (dma_addr_t)pOutStr->DecodedAddr[0];
-
- dec->consumed = consumed;
- dec->remained_size = src_mb->vb.vb2_buf.planes[0].bytesused
- - dec->consumed;
- dec->has_multiframe = 1;
- dev->nal_q_handle->nal_q_exception = 1;
-
- MFC_TRACE_CTX("** consumed:%ld, remained:%ld, addr:0x%08llx\n",
- dec->consumed, dec->remained_size, dec->y_addr_for_pb);
- /* Do not move src buffer to done_list */
- return;
- }
-
- if (call_cop(ctx, get_buf_ctrls_val_nal_q_dec, ctx,
- &ctx->src_ctrls[index], pOutStr) < 0)
- mfc_err_ctx("[NALQ] failed in get_buf_ctrls_val\n");
-
- dec->consumed = 0;
- dec->remained_size = 0;
-
- vb2_buffer_done(&src_mb->vb.vb2_buf, VB2_BUF_STATE_DONE);
-}
-
-void mfc_nal_q_handle_frame(struct s5p_mfc_ctx *ctx, DecoderOutputStr *pOutStr)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_dec *dec = ctx->dec_priv;
- unsigned int dst_frame_status, sei_avail_status, need_empty_dpb;
- unsigned int res_change, need_dpb_change, need_scratch_change;
- unsigned int is_interlaced, err;
-
- mfc_debug_enter();
-
- dst_frame_status = pOutStr->DisplayStatus
- & S5P_FIMV_DISP_STATUS_DISPLAY_STATUS_MASK;
- need_empty_dpb = (pOutStr->DisplayStatus
- >> S5P_FIMV_DISP_STATUS_NEED_EMPTY_DPB_SHIFT)
- & S5P_FIMV_DISP_STATUS_NEED_EMPTY_DPB_MASK;
- res_change = (pOutStr->DisplayStatus
- >> S5P_FIMV_DISP_STATUS_RES_CHANGE_SHIFT)
- & S5P_FIMV_DISP_STATUS_RES_CHANGE_MASK;
- need_dpb_change = (pOutStr->DisplayStatus
- >> S5P_FIMV_DISP_STATUS_NEED_DPB_CHANGE_SHIFT)
- & S5P_FIMV_DISP_STATUS_NEED_DPB_CHANGE_MASK;
- need_scratch_change = (pOutStr->DisplayStatus
- >> S5P_FIMV_DISP_STATUS_NEED_SCRATCH_CHANGE_SHIFT)
- & S5P_FIMV_DISP_STATUS_NEED_SCRATCH_CHANGE_MASK;
- is_interlaced = (pOutStr->DisplayStatus
- >> S5P_FIMV_DISP_STATUS_INTERLACE_SHIFT)
- & S5P_FIMV_DISP_STATUS_INTERLACE_MASK;
- sei_avail_status = pOutStr->SeiAvail;
- err = pOutStr->ErrorCode;
-
- if (dec->immediate_display == 1)
- dst_frame_status = pOutStr->DecodedStatus
- & S5P_FIMV_DEC_STATUS_DECODED_STATUS_MASK;
-
- mfc_debug(2, "[NALQ][FRAME] frame status: %d\n", dst_frame_status);
- mfc_debug(2, "[NALQ][FRAME] display status: %d, type: %d, yaddr: %#x\n",
- pOutStr->DisplayStatus & S5P_FIMV_DISP_STATUS_DISPLAY_STATUS_MASK,
- pOutStr->DisplayFrameType & S5P_FIMV_DISPLAY_FRAME_MASK,
- pOutStr->DisplayAddr[0]);
- mfc_debug(2, "[NALQ][FRAME] decoded status: %d, type: %d, yaddr: %#x\n",
- pOutStr->DecodedStatus & S5P_FIMV_DEC_STATUS_DECODED_STATUS_MASK,
- pOutStr->DecodedFrameType & S5P_FIMV_DECODED_FRAME_MASK,
- pOutStr->DecodedAddr[0]);
- mfc_debug(4, "[NALQ][HDR] SEI available status: %x\n", sei_avail_status);
- mfc_debug(2, "[NALQ][DPB] Used flag: old = %08x, new = %08x\n",
- dec->dynamic_used, pOutStr->UsedDpbFlagLower);
-
- if (ctx->state == MFCINST_RES_CHANGE_INIT) {
- mfc_debug(2, "[NALQ][DRC] return until NAL-Q stopped in try_run\n");
- goto leave_handle_frame;
- }
- if (res_change) {
- mfc_debug(2, "[NALQ][DRC] Resolution change set to %d\n", res_change);
- s5p_mfc_change_state(ctx, MFCINST_RES_CHANGE_INIT);
- ctx->wait_state = WAIT_DECODING;
- dev->nal_q_handle->nal_q_exception = 1;
- mfc_info_ctx("[NALQ][DRC] nal_q_exception is set (res change)\n");
- goto leave_handle_frame;
- }
- if (need_empty_dpb) {
- mfc_debug(2, "[NALQ][MULTIFRAME] There is multi-frame. consumed:%ld\n", dec->consumed);
- dec->has_multiframe = 1;
- dev->nal_q_handle->nal_q_exception = 1;
- mfc_info_ctx("[NALQ][MULTIFRAME] nal_q_exception is set\n");
- goto leave_handle_frame;
- }
- if (need_dpb_change || need_scratch_change) {
- mfc_debug(2, "[NALQ][DRC] Interframe resolution change is not supported\n");
- dev->nal_q_handle->nal_q_exception = 1;
- mfc_info_ctx("[NALQ][DRC] nal_q_exception is set (interframe res change)\n");
- goto leave_handle_frame;
- }
- if (is_interlaced) {
- mfc_debug(2, "[NALQ][INTERLACE] Progressive -> Interlaced\n");
- dec->is_interlaced = is_interlaced;
- dev->nal_q_handle->nal_q_exception = 1;
- mfc_info_ctx("[NALQ][INTERLACE] nal_q_exception is set\n");
- goto leave_handle_frame;
- }
-
- if (s5p_mfc_is_queue_count_same(&ctx->buf_queue_lock, &ctx->src_buf_nal_queue, 0) &&
- s5p_mfc_is_queue_count_same(&ctx->buf_queue_lock, &ctx->dst_buf_nal_queue, 0)) {
- mfc_err_dev("[NALQ] Queue count is zero for src/dst\n");
- goto leave_handle_frame;
- }
-
- switch (dst_frame_status) {
- case S5P_FIMV_DEC_STATUS_DECODING_DISPLAY:
- mfc_nal_q_handle_ref_frame(ctx, pOutStr);
- mfc_nal_q_handle_frame_copy_timestamp(ctx, pOutStr);
- break;
- case S5P_FIMV_DEC_STATUS_DECODING_ONLY:
- mfc_nal_q_handle_ref_frame(ctx, pOutStr);
- mfc_nal_q_handle_reuse_buffer(ctx, pOutStr);
- break;
- default:
- break;
- }
-
- /* A frame has been decoded and is in the buffer */
- if (s5p_mfc_dec_status_display(dst_frame_status))
- mfc_nal_q_handle_frame_new(ctx, err, pOutStr);
- else
- mfc_debug(2, "[NALQ] No display frame\n");
-
- /* Mark source buffer as complete */
- if (dst_frame_status != S5P_FIMV_DEC_STATUS_DISPLAY_ONLY)
- mfc_nal_q_handle_frame_input(ctx, err, pOutStr);
- else
- mfc_debug(2, "[NALQ][DPB] can't support display only in NAL-Q, is_dpb_full: %d\n",
- dec->is_dpb_full);
-
-leave_handle_frame:
- mfc_debug_leave();
-}
-
-int mfc_nal_q_handle_error(struct s5p_mfc_ctx *ctx, EncoderOutputStr *pOutStr, int err)
-{
- struct s5p_mfc_dev *dev;
- struct s5p_mfc_dec *dec;
- struct s5p_mfc_enc *enc;
- struct s5p_mfc_buf *src_mb;
- int stop_nal_q = 1;
-
- mfc_debug_enter();
-
- if (!ctx) {
- mfc_err_dev("[NALQ] no mfc context to run\n");
- goto end;
- }
-
- dev = ctx->dev;
- if (!dev) {
- mfc_err_dev("[NALQ] no mfc device to run\n");
- goto end;
- }
-
- mfc_err_ctx("[NALQ] Interrupt Error: %d\n", pOutStr->ErrorCode);
-
- dev->nal_q_handle->nal_q_exception = 1;
- mfc_info_ctx("[NALQ] nal_q_exception is set (error)\n");
-
- if (ctx->type == MFCINST_DECODER) {
- dec = ctx->dec_priv;
- if (!dec) {
- mfc_err_dev("[NALQ] no mfc decoder to run\n");
- goto end;
- }
- src_mb = s5p_mfc_get_del_buf(&ctx->buf_queue_lock,
- &ctx->src_buf_nal_queue, MFC_BUF_NO_TOUCH_USED);
-
- if (!src_mb) {
- mfc_err_dev("[NALQ] no src buffers\n");
- } else {
- dec->consumed = 0;
- vb2_buffer_done(&src_mb->vb.vb2_buf, VB2_BUF_STATE_ERROR);
- }
- } else if (ctx->type == MFCINST_ENCODER) {
- enc = ctx->enc_priv;
- if (!enc) {
- mfc_err_dev("[NALQ] no mfc encoder to run\n");
- goto end;
- }
-
- /*
- * If the buffer full error occurs in NAL-Q mode,
- * one input buffer is returned and the NAL-Q mode continues.
- */
- if (err == S5P_FIMV_ERR_BUFFER_FULL) {
- src_mb = s5p_mfc_get_del_buf(&ctx->buf_queue_lock,
- &ctx->src_buf_nal_queue, MFC_BUF_NO_TOUCH_USED);
-
- if (!src_mb)
- mfc_err_dev("[NALQ] no src buffers\n");
- else
- vb2_buffer_done(&src_mb->vb.vb2_buf, VB2_BUF_STATE_ERROR);
-
- dev->nal_q_handle->nal_q_exception = 0;
- stop_nal_q = 0;
- }
- }
-
-end:
- mfc_debug_leave();
-
- return stop_nal_q;
-}
-
-int s5p_mfc_nal_q_handle_out_buf(struct s5p_mfc_dev *dev, EncoderOutputStr *pOutStr)
-{
- struct s5p_mfc_ctx *ctx;
- struct s5p_mfc_enc *enc;
- struct s5p_mfc_dec *dec;
- int ctx_num;
-
- mfc_debug_enter();
-
- if (!dev) {
- mfc_err_dev("[NALQ] no mfc device to run\n");
- return -EINVAL;
- }
-
- ctx_num = dev->nal_q_handle->nal_q_out_handle->nal_q_ctx;
- if (ctx_num < 0) {
- mfc_err_dev("[NALQ] Can't find ctx in nal q\n");
- return -EINVAL;
- }
-
- ctx = dev->ctx[ctx_num];
- if (!ctx) {
- mfc_err_dev("[NALQ] no mfc context to run\n");
- return -EINVAL;
- }
-
- mfc_debug(2, "[NALQ] Int ctx is %d(%s)\n", ctx_num,
- ctx->type == MFCINST_ENCODER ? "enc" : "dec");
-
- if (s5p_mfc_get_err(pOutStr->ErrorCode) &&
- (s5p_mfc_get_err(pOutStr->ErrorCode) < S5P_FIMV_ERR_FRAME_CONCEAL)) {
- if (mfc_nal_q_handle_error(ctx, pOutStr, s5p_mfc_get_err(pOutStr->ErrorCode)))
- return 0;
- }
-
- if (ctx->type == MFCINST_ENCODER) {
- enc = ctx->enc_priv;
- if (!enc) {
- mfc_err_dev("[NALQ] no mfc encoder to run\n");
- return -EINVAL;
- }
- mfc_nal_q_handle_stream(ctx, pOutStr);
- } else if (ctx->type == MFCINST_DECODER) {
- dec = ctx->dec_priv;
- if (!dec) {
- mfc_err_dev("[NALQ] no mfc decoder to run\n");
- return -EINVAL;
- }
- mfc_nal_q_handle_frame(ctx, (DecoderOutputStr *)pOutStr);
- }
-
- mfc_debug_leave();
-
- return 0;
-}
-
-/*
- * This function should be called in NAL_Q_STATE_STARTED state.
- */
-int s5p_mfc_nal_q_enqueue_in_buf(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx,
- nal_queue_in_handle *nal_q_in_handle)
-{
- unsigned long flags;
- unsigned int input_count = 0;
- unsigned int input_exe_count = 0;
- int input_diff = 0;
- unsigned int index = 0;
- EncoderInputStr *pStr = NULL;
- int ret = 0;
-
- mfc_debug_enter();
-
- if (!nal_q_in_handle) {
- mfc_err_dev("[NALQ] There is no nal_q_handle\n");
- return -EINVAL;
- }
-
- if (nal_q_in_handle->nal_q_handle->nal_q_state != NAL_Q_STATE_STARTED) {
- mfc_err_dev("[NALQ] State is wrong, state: %d\n",
- nal_q_in_handle->nal_q_handle->nal_q_state);
- return -EINVAL;
- }
-
- spin_lock_irqsave(&nal_q_in_handle->nal_q_handle->lock, flags);
-
- input_count = s5p_mfc_get_nal_q_input_count();
- input_exe_count = s5p_mfc_get_nal_q_input_exe_count();
- input_diff = input_count - input_exe_count;
-
- /*
- * meaning of the variable input_diff
- * 0: number of available slots = NAL_Q_IN_QUEUE_SIZE
- * 1: number of available slots = NAL_Q_IN_QUEUE_SIZE - 1
- * ...
- * NAL_Q_IN_QUEUE_SIZE-1: number of available slots = 1
- * NAL_Q_IN_QUEUE_SIZE: number of available slots = 0
- */
-
- mfc_debug(2, "[NALQ] input_diff = %d(in: %d, exe: %d)\n",
- input_diff, input_count, input_exe_count);
-
- if ((input_diff < 0) || (input_diff >= NAL_Q_IN_QUEUE_SIZE)) {
- mfc_err_dev("[NALQ] No available input slot(%d)\n", input_diff);
- spin_unlock_irqrestore(&nal_q_in_handle->nal_q_handle->lock, flags);
- return -EINVAL;
- }
-
- index = input_count % NAL_Q_IN_QUEUE_SIZE;
- pStr = &(nal_q_in_handle->nal_q_in_addr->entry[index].enc);
-
- memset(pStr, 0, NAL_Q_IN_ENTRY_SIZE);
-
- if (ctx->type == MFCINST_ENCODER)
- ret = mfc_nal_q_run_in_buf_enc(ctx, pStr);
- else if (ctx->type == MFCINST_DECODER)
- ret = mfc_nal_q_run_in_buf_dec(ctx, (DecoderInputStr *)pStr);
-
- if (ret != 0) {
- mfc_debug(2, "[NALQ] Failed to set input queue\n");
- spin_unlock_irqrestore(&nal_q_in_handle->nal_q_handle->lock, flags);
- return ret;
- }
-
- if (nal_q_dump == 1) {
- mfc_err_dev("[NAL-Q][DUMP][%s INPUT][c: %d] diff: %d, count: %d, exe: %d\n",
- ctx->type == MFCINST_ENCODER ? "ENC" : "DEC", dev->curr_ctx,
- input_diff, input_count, input_exe_count);
- print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 32, 4, (int *)pStr, 256, false);
- printk("...\n");
- }
- input_count++;
-
- s5p_mfc_update_nal_queue_input_count(dev, input_count);
-
- if (input_diff == 0)
- s5p_mfc_watchdog_start_tick(dev);
-
- spin_unlock_irqrestore(&nal_q_in_handle->nal_q_handle->lock, flags);
-
- MFC_TRACE_CTX("NAL %s in: diff %d count %d exe %d\n",
- ctx->type == MFCINST_ENCODER ? "ENC" : "DEC",
- input_diff, input_count, input_exe_count);
-
- mfc_debug_leave();
-
- return ret;
-}
-
-/*
- * This function should be called in NAL_Q_STATE_STARTED state.
- */
-EncoderOutputStr *s5p_mfc_nal_q_dequeue_out_buf(struct s5p_mfc_dev *dev,
- nal_queue_out_handle *nal_q_out_handle, unsigned int *reason)
-{
- struct s5p_mfc_ctx *ctx;
- unsigned long flags;
- unsigned int output_count = 0;
- unsigned int output_exe_count = 0;
- int output_diff = 0;
- unsigned int index = 0;
- EncoderOutputStr *pStr = NULL;
-
- int input_diff = 0;
-
- mfc_debug_enter();
-
- if (!nal_q_out_handle || !nal_q_out_handle->nal_q_out_addr) {
- mfc_err_dev("[NALQ] There is no handle\n");
- return pStr;
- }
-
- spin_lock_irqsave(&nal_q_out_handle->nal_q_handle->lock, flags);
-
- output_count = s5p_mfc_get_nal_q_output_count();
- output_exe_count = nal_q_out_handle->out_exe_count;
- output_diff = output_count - output_exe_count;
-
- /*
- * meaning of the variable output_diff
- * 0: number of output slots = 0
- * 1: number of output slots = 1
- * ...
- * NAL_Q_OUT_QUEUE_SIZE-1: number of output slots = NAL_Q_OUT_QUEUE_SIZE - 1
- * NAL_Q_OUT_QUEUE_SIZE: number of output slots = NAL_Q_OUT_QUEUE_SIZE
- */
-
- mfc_debug(2, "[NALQ] output_diff = %d(out: %d, exe: %d)\n",
- output_diff, output_count, output_exe_count);
- if ((output_diff <= 0) || (output_diff > NAL_Q_OUT_QUEUE_SIZE)) {
- spin_unlock_irqrestore(&nal_q_out_handle->nal_q_handle->lock, flags);
- mfc_debug(2, "[NALQ] No available output slot(%d)\n", output_diff);
- return pStr;
- }
-
- index = output_exe_count % NAL_Q_OUT_QUEUE_SIZE;
- pStr = &(nal_q_out_handle->nal_q_out_addr->entry[index].enc);
-
- nal_q_out_handle->nal_q_ctx = mfc_nal_q_find_ctx(dev, pStr);
- if (nal_q_out_handle->nal_q_ctx < 0) {
- mfc_err_dev("[NALQ] Can't find ctx in nal q\n");
- pStr = NULL;
- return pStr;
- }
-
- ctx = dev->ctx[nal_q_out_handle->nal_q_ctx];
- if (nal_q_dump == 1) {
- mfc_err_dev("[NALQ][DUMP][%s OUTPUT][c: %d] diff: %d, count: %d, exe: %d\n",
- ctx->type == MFCINST_ENCODER ? "ENC" : "DEC",
- nal_q_out_handle->nal_q_ctx,
- output_diff, output_count, output_exe_count);
- print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 32, 4, (int *)pStr, 256, false);
- printk("...\n");
- }
- nal_q_out_handle->out_exe_count++;
-
- if (pStr->ErrorCode) {
- *reason = S5P_FIMV_R2H_CMD_ERR_RET;
- mfc_err_dev("[NALQ] Error : %d\n", pStr->ErrorCode);
- }
-
- input_diff = s5p_mfc_get_nal_q_input_count() - s5p_mfc_get_nal_q_input_exe_count();
- if (input_diff == 0) {
- s5p_mfc_watchdog_stop_tick(dev);
- } else if (input_diff > 0) {
- s5p_mfc_watchdog_reset_tick(dev);
- }
-
- spin_unlock_irqrestore(&nal_q_out_handle->nal_q_handle->lock, flags);
-
- MFC_TRACE_CTX("NAL %s out: diff %d count %d exe %d\n",
- ctx->type == MFCINST_ENCODER ? "ENC" : "DEC",
- output_diff, output_count, output_exe_count);
-
- mfc_debug_leave();
-
- return pStr;
-}
-
-#if 0
-/* not used function - only for reference sfr <-> structure */
-void s5p_mfc_nal_q_fill_DecoderInputStr(struct s5p_mfc_dev *dev, DecoderInputStr *pStr)
-{
- pStr->StartCode = 0xAAAAAAAA; // Decoder input start
-// pStr->CommandId = MFC_READL(S5P_FIMV_HOST2RISC_CMD); // 0x1100
- pStr->InstanceId = MFC_READL(S5P_FIMV_INSTANCE_ID); // 0xF008
- pStr->PictureTag = MFC_READL(S5P_FIMV_D_PICTURE_TAG); // 0xF5C8
- pStr->CpbBufferAddr = MFC_READL(S5P_FIMV_D_CPB_BUFFER_ADDR); // 0xF5B0
- pStr->CpbBufferSize = MFC_READL(S5P_FIMV_D_CPB_BUFFER_SIZE); // 0xF5B4
- pStr->CpbBufferOffset = MFC_READL(S5P_FIMV_D_CPB_BUFFER_OFFSET); // 0xF5C0
- pStr->StreamDataSize = MFC_READL(S5P_FIMV_D_STREAM_DATA_SIZE); // 0xF5D0
- pStr->AvailableDpbFlagUpper = MFC_READL(S5P_FIMV_D_AVAILABLE_DPB_FLAG_UPPER);// 0xF5B8
- pStr->AvailableDpbFlagLower = MFC_READL(S5P_FIMV_D_AVAILABLE_DPB_FLAG_LOWER);// 0xF5BC
- pStr->DynamicDpbFlagUpper = MFC_READL(S5P_FIMV_D_DYNAMIC_DPB_FLAG_UPPER); // 0xF5D4
- pStr->DynamicDpbFlagLower = MFC_READL(S5P_FIMV_D_DYNAMIC_DPB_FLAG_LOWER); // 0xF5D8
- pStr->FirstPlaneDpb = MFC_READL(S5P_FIMV_D_FIRST_PLANE_DPB0); // 0xF160+(index*4)
- pStr->SecondPlaneDpb = MFC_READL(S5P_FIMV_D_SECOND_PLANE_DPB0); // 0xF260+(index*4)
- pStr->ThirdPlaneDpb = MFC_READL(S5P_FIMV_D_THIRD_PLANE_DPB0); // 0xF360+(index*4)
- pStr->FirstPlaneDpbSize = MFC_READL(S5P_FIMV_D_FIRST_PLANE_DPB_SIZE); // 0xF144
- pStr->SecondPlaneDpbSize = MFC_READL(S5P_FIMV_D_SECOND_PLANE_DPB_SIZE); // 0xF148
- pStr->ThirdPlaneDpbSize = MFC_READL(S5P_FIMV_D_THIRD_PLANE_DPB_SIZE); // 0xF14C
- pStr->NalStartOptions = MFC_READL(0xF5AC);// S5P_FIMV_D_NAL_START_OPTIONS 0xF5AC
- pStr->FirstPlaneStrideSize = MFC_READL(S5P_FIMV_D_FIRST_PLANE_DPB_STRIDE_SIZE);// 0xF138
- pStr->SecondPlaneStrideSize = MFC_READL(S5P_FIMV_D_SECOND_PLANE_DPB_STRIDE_SIZE);// 0xF13C
- pStr->ThirdPlaneStrideSize = MFC_READL(S5P_FIMV_D_THIRD_PLANE_DPB_STRIDE_SIZE);// 0xF140
- pStr->FirstPlane2BitDpbSize = MFC_READL(S5P_FIMV_D_FIRST_PLANE_2BIT_DPB_SIZE);// 0xF578
- pStr->SecondPlane2BitDpbSize = MFC_READL(S5P_FIMV_D_SECOND_PLANE_2BIT_DPB_SIZE);// 0xF57C
- pStr->FirstPlane2BitStrideSize = MFC_READL(S5P_FIMV_D_FIRST_PLANE_2BIT_DPB_STRIDE_SIZE);// 0xF580
- pStr->SecondPlane2BitStrideSize = MFC_READL(S5P_FIMV_D_SECOND_PLANE_2BIT_DPB_STRIDE_SIZE);// 0xF584
- pStr->ScratchBufAddr = MFC_READL(S5P_FIMV_D_SCRATCH_BUFFER_ADDR); // 0xF560
- pStr->ScratchBufSize = MFC_READL(S5P_FIMV_D_SCRATCH_BUFFER_SIZE); // 0xF564
-}
-
-void s5p_mfc_nal_q_flush_DecoderOutputStr(struct s5p_mfc_dev *dev, DecoderOutputStr *pStr)
-{
- //pStr->StartCode; // 0xAAAAAAAA; // Decoder output start
-// MFC_WRITEL(pStr->CommandId, S5P_FIMV_RISC2HOST_CMD); // 0x1104
- MFC_WRITEL(pStr->InstanceId, S5P_FIMV_RET_INSTANCE_ID); // 0xF070
- MFC_WRITEL(pStr->ErrorCode, S5P_FIMV_ERROR_CODE); // 0xF074
- MFC_WRITEL(pStr->PictureTagTop, S5P_FIMV_D_RET_PICTURE_TAG_TOP); // 0xF674
- MFC_WRITEL(pStr->PictureTimeTop, S5P_FIMV_D_RET_PICTURE_TIME_TOP); // 0xF67C
- MFC_WRITEL(pStr->DisplayFrameWidth, S5P_FIMV_D_DISPLAY_FRAME_WIDTH); // 0xF600
- MFC_WRITEL(pStr->DisplayFrameHeight, S5P_FIMV_D_DISPLAY_FRAME_HEIGHT); // 0xF604
- MFC_WRITEL(pStr->DisplayStatus, S5P_FIMV_D_DISPLAY_STATUS); // 0xF608
- MFC_WRITEL(pStr->DisplayFirstPlaneAddr, S5P_FIMV_D_DISPLAY_FIRST_PLANE_ADDR); // 0xF60C
- MFC_WRITEL(pStr->DisplaySecondPlaneAddr, S5P_FIMV_D_DISPLAY_SECOND_PLANE_ADDR); // 0xF610
- MFC_WRITEL(pStr->DisplayThirdPlaneAddr,S5P_FIMV_D_DISPLAY_THIRD_PLANE_ADDR); // 0xF614
- MFC_WRITEL(pStr->DisplayFrameType, S5P_FIMV_D_DISPLAY_FRAME_TYPE); // 0xF618
- MFC_WRITEL(pStr->DisplayCropInfo1, S5P_FIMV_D_DISPLAY_CROP_INFO1); // 0xF61C
- MFC_WRITEL(pStr->DisplayCropInfo2, S5P_FIMV_D_DISPLAY_CROP_INFO2); // 0xF620
- MFC_WRITEL(pStr->DisplayPictureProfile, S5P_FIMV_D_DISPLAY_PICTURE_PROFILE); // 0xF624
- MFC_WRITEL(pStr->DisplayAspectRatio, S5P_FIMV_D_DISPLAY_ASPECT_RATIO); // 0xF634
- MFC_WRITEL(pStr->DisplayExtendedAr, S5P_FIMV_D_DISPLAY_EXTENDED_AR); // 0xF638
- MFC_WRITEL(pStr->DecodedNalSize, S5P_FIMV_D_DECODED_NAL_SIZE); // 0xF664
- MFC_WRITEL(pStr->UsedDpbFlagUpper, S5P_FIMV_D_USED_DPB_FLAG_UPPER); // 0xF720
- MFC_WRITEL(pStr->UsedDpbFlagLower, S5P_FIMV_D_USED_DPB_FLAG_LOWER); // 0xF724
- MFC_WRITEL(pStr->SeiAvail, S5P_FIMV_D_SEI_AVAIL); // 0xF6DC
- MFC_WRITEL(pStr->FramePackArrgmentId, S5P_FIMV_D_FRAME_PACK_ARRGMENT_ID); // 0xF6E0
- MFC_WRITEL(pStr->FramePackSeiInfo, S5P_FIMV_D_FRAME_PACK_SEI_INFO); // 0xF6E4
- MFC_WRITEL(pStr->FramePackGridPos, S5P_FIMV_D_FRAME_PACK_GRID_POS); // 0xF6E8
- MFC_WRITEL(pStr->DisplayRecoverySeiInfo, S5P_FIMV_D_DISPLAY_RECOVERY_SEI_INFO); // 0xF6EC
- MFC_WRITEL(pStr->H264Info, S5P_FIMV_D_H264_INFO); // 0xF690
- MFC_WRITEL(pStr->DisplayFirstCrc, S5P_FIMV_D_DISPLAY_FIRST_PLANE_CRC); // 0xF628
- MFC_WRITEL(pStr->DisplaySecondCrc, S5P_FIMV_D_DISPLAY_SECOND_PLANE_CRC); // 0xF62C
- MFC_WRITEL(pStr->DisplayThirdCrc, S5P_FIMV_D_DISPLAY_THIRD_PLANE_CRC); // 0xF630
- MFC_WRITEL(pStr->DisplayFirst2BitCrc, S5P_FIMV_D_DISPLAY_FIRST_PLANE_2BIT_CRC); // 0xF6FC
- MFC_WRITEL(pStr->DisplaySecond2BitCrc, S5P_FIMV_D_DISPLAY_SECOND_PLANE_2BIT_CRC);// 0xF700
- MFC_WRITEL(pStr->DecodedFrameWidth, S5P_FIMV_D_DECODED_FRAME_WIDTH); // 0xF63C
- MFC_WRITEL(pStr->DecodedFrameHeight, S5P_FIMV_D_DECODED_FRAME_HEIGHT); // 0xF640
- MFC_WRITEL(pStr->DecodedStatus, S5P_FIMV_D_DECODED_STATUS); // 0xF644
- MFC_WRITEL(pStr->DecodedFirstPlaneAddr, S5P_FIMV_D_DECODED_FIRST_PLANE_ADDR); // 0xF648
- MFC_WRITEL(pStr->DecodedSecondPlaneAddr, S5P_FIMV_D_DECODED_SECOND_PLANE_ADDR); // 0xF64C
- MFC_WRITEL(pStr->DecodedThirdPlaneAddr, S5P_FIMV_D_DECODED_THIRD_PLANE_ADDR); // 0xF650
- MFC_WRITEL(pStr->DecodedFrameType, S5P_FIMV_D_DECODED_FRAME_TYPE); // 0xF654
- MFC_WRITEL(pStr->DecodedCropInfo1, S5P_FIMV_D_DECODED_CROP_INFO1); // 0xF658
- MFC_WRITEL(pStr->DecodedCropInfo2, S5P_FIMV_D_DECODED_CROP_INFO2); // 0xF65C
- MFC_WRITEL(pStr->DecodedPictureProfile, S5P_FIMV_D_DECODED_PICTURE_PROFILE); // 0xF660
- MFC_WRITEL(pStr->DecodedRecoverySeiInfo, S5P_FIMV_D_DECODED_RECOVERY_SEI_INFO); // 0xF6F0
- MFC_WRITEL(pStr->DecodedFirstCrc, S5P_FIMV_D_DECODED_FIRST_PLANE_CRC); // 0xF668
- MFC_WRITEL(pStr->DecodedSecondCrc, S5P_FIMV_D_DECODED_SECOND_PLANE_CRC); // 0xF66C
- MFC_WRITEL(pStr->DecodedThirdCrc, S5P_FIMV_D_DECODED_THIRD_PLANE_CRC); // 0xF670
- MFC_WRITEL(pStr->DecodedFirst2BitCrc, S5P_FIMV_D_DECODED_FIRST_PLANE_2BIT_CRC); // 0xF704
- MFC_WRITEL(pStr->DecodedSecond2BitCrc, S5P_FIMV_D_DECODED_SECOND_PLANE_2BIT_CRC);// 0xF708
- MFC_WRITEL(pStr->PictureTagBot, S5P_FIMV_D_RET_PICTURE_TAG_BOT); // 0xF678
- MFC_WRITEL(pStr->PictureTimeBot, S5P_FIMV_D_RET_PICTURE_TIME_BOT); // 0xF680
-}
-#endif
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_nal_q.h
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __S5P_MFC_NAL_Q_H
-#define __S5P_MFC_NAL_Q_H __FILE__
-
-#include "s5p_mfc_common.h"
-
-int s5p_mfc_nal_q_check_enable(struct s5p_mfc_dev *dev);
-
-void s5p_mfc_nal_q_clock_on(struct s5p_mfc_dev *dev, nal_queue_handle *nal_q_handle);
-void s5p_mfc_nal_q_clock_off(struct s5p_mfc_dev *dev, nal_queue_handle *nal_q_handle);
-void s5p_mfc_nal_q_cleanup_clock(struct s5p_mfc_dev *dev);
-
-nal_queue_handle *s5p_mfc_nal_q_create(struct s5p_mfc_dev *dev);
-int s5p_mfc_nal_q_destroy(struct s5p_mfc_dev *dev, nal_queue_handle *nal_q_handle);
-
-void s5p_mfc_nal_q_init(struct s5p_mfc_dev *dev, nal_queue_handle *nal_q_handle);
-void s5p_mfc_nal_q_start(struct s5p_mfc_dev *dev, nal_queue_handle *nal_q_handle);
-void s5p_mfc_nal_q_stop(struct s5p_mfc_dev *dev, nal_queue_handle *nal_q_handle);
-void s5p_mfc_nal_q_stop_if_started(struct s5p_mfc_dev *dev);
-void s5p_mfc_nal_q_cleanup_queue(struct s5p_mfc_dev *dev);
-
-int s5p_mfc_nal_q_handle_out_buf(struct s5p_mfc_dev *dev, EncoderOutputStr *pOutStr);
-int s5p_mfc_nal_q_enqueue_in_buf(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx,
- nal_queue_in_handle *nal_q_in_handle);
-EncoderOutputStr *s5p_mfc_nal_q_dequeue_out_buf(struct s5p_mfc_dev *dev,
- nal_queue_out_handle *nal_q_out_handle, unsigned int *reason);
-
-#endif /* __S5P_MFC_NAL_Q_H */
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_opr.c
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include "s5p_mfc_opr.h"
-
-#include "s5p_mfc_inst.h"
-#include "s5p_mfc_reg.h"
-
-#include "s5p_mfc_queue.h"
-#include "s5p_mfc_utils.h"
-#include "s5p_mfc_mem.h"
-
-int s5p_mfc_run_dec_init(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev;
- struct s5p_mfc_buf *src_mb;
- struct s5p_mfc_dec *dec = NULL;
-
- if (!ctx) {
- mfc_err_dev("no mfc context to run\n");
- return -EINVAL;
- }
- dev = ctx->dev;
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
- dec = ctx->dec_priv;
- /* Initializing decoding - parsing header */
-
- /* Get the next source buffer */
- src_mb = s5p_mfc_get_buf(&ctx->buf_queue_lock, &ctx->src_buf_queue, MFC_BUF_NO_TOUCH_USED);
- if (!src_mb) {
- mfc_err_dev("no src buffers\n");
- return -EAGAIN;
- }
-
- mfc_debug(2, "Preparing to init decoding\n");
- mfc_debug(2, "Header size: %d, (offset: %lu)\n",
- src_mb->vb.vb2_buf.planes[0].bytesused, dec->consumed);
-
- if (dec->consumed) {
- s5p_mfc_set_dec_stream_buffer(ctx, src_mb, dec->consumed, dec->remained_size);
- } else {
- /* decoder src buffer CFW PROT */
- if (ctx->is_drm) {
- int index = src_mb->vb.vb2_buf.index;
-
- s5p_mfc_stream_protect(ctx, src_mb, index);
- }
-
- s5p_mfc_set_dec_stream_buffer(ctx, src_mb,
- 0, src_mb->vb.vb2_buf.planes[0].bytesused);
- }
-
- mfc_debug(2, "Header addr: 0x%08llx\n", src_mb->addr[0][0]);
- s5p_mfc_clean_ctx_int_flags(ctx);
- s5p_mfc_init_decode(ctx);
-
- return 0;
-}
-
-static int mfc_check_last_frame(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *mfc_buf)
-{
- if (mfc_buf->vb.reserved2 & FLAG_LAST_FRAME) {
- mfc_debug(2, "Setting ctx->state to FINISHING\n");
- s5p_mfc_change_state(ctx, MFCINST_FINISHING);
- return 1;
- }
-
- return 0;
-}
-
-int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev;
- struct s5p_mfc_buf *src_mb, *dst_mb;
- struct s5p_mfc_dec *dec;
- int last_frame = 0;
- unsigned int index;
-
- if (!ctx) {
- mfc_err_dev("no mfc context to run\n");
- return -EINVAL;
- }
- dec = ctx->dec_priv;
- dev = ctx->dev;
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
-
- if (s5p_mfc_is_queue_count_same(&ctx->buf_queue_lock, &ctx->dst_buf_queue, 0) &&
- s5p_mfc_is_queue_count_smaller(&ctx->buf_queue_lock,
- &ctx->ref_buf_queue, (ctx->dpb_count + 5))) {
- return -EAGAIN;
- }
-
- /* Get the next source buffer */
- src_mb = s5p_mfc_get_buf(&ctx->buf_queue_lock, &ctx->src_buf_queue, MFC_BUF_SET_USED);
- if (!src_mb) {
- mfc_debug(2, "no src buffers\n");
- return -EAGAIN;
- }
-
- /* decoder src buffer CFW PROT */
- if (ctx->is_drm) {
- if (!dec->consumed) {
- index = src_mb->vb.vb2_buf.index;
- s5p_mfc_stream_protect(ctx, src_mb, index);
- }
- }
-
- if (src_mb->vb.reserved2 & FLAG_EMPTY_DATA)
- src_mb->vb.vb2_buf.planes[0].bytesused = 0;
-
- if (dec->consumed)
- s5p_mfc_set_dec_stream_buffer(ctx, src_mb, dec->consumed, dec->remained_size);
- else
- s5p_mfc_set_dec_stream_buffer(ctx, src_mb, 0, src_mb->vb.vb2_buf.planes[0].bytesused);
-
- /* Try to use the non-referenced DPB on dst-queue */
- dst_mb = s5p_mfc_search_for_dpb(ctx, dec->dynamic_used);
- if (!dst_mb) {
- mfc_debug(2, "[DPB] couldn't find dst buffers\n");
- return -EAGAIN;
- }
-
- index = src_mb->vb.vb2_buf.index;
- if (call_cop(ctx, set_buf_ctrls_val, ctx, &ctx->src_ctrls[index]) < 0)
- mfc_err_ctx("failed in set_buf_ctrls_val\n");
-
- s5p_mfc_set_dynamic_dpb(ctx, dst_mb);
-
- s5p_mfc_clean_ctx_int_flags(ctx);
-
- last_frame = mfc_check_last_frame(ctx, src_mb);
- s5p_mfc_decode_one_frame(ctx, last_frame);
-
- return 0;
-}
-
-int s5p_mfc_run_dec_last_frames(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev;
- struct s5p_mfc_buf *src_mb, *dst_mb;
- struct s5p_mfc_dec *dec;
-
- if (!ctx) {
- mfc_err_dev("no mfc context to run\n");
- return -EINVAL;
- }
-
- dec = ctx->dec_priv;
- if (!dec) {
- mfc_err_dev("no decoder context to run\n");
- return -EINVAL;
- }
-
- dev = ctx->dev;
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
-
- if (s5p_mfc_is_queue_count_same(&ctx->buf_queue_lock, &ctx->dst_buf_queue, 0)) {
- mfc_debug(2, "no dst buffer\n");
- return -EAGAIN;
- }
-
- /* Get the next source buffer */
- src_mb = s5p_mfc_get_buf(&ctx->buf_queue_lock, &ctx->src_buf_queue, MFC_BUF_SET_USED);
-
- /* Frames are being decoded */
- if (!src_mb) {
- mfc_debug(2, "no src buffers\n");
- s5p_mfc_set_dec_stream_buffer(ctx, 0, 0, 0);
- } else {
- if (dec->consumed) {
- s5p_mfc_set_dec_stream_buffer(ctx, src_mb, dec->consumed, dec->remained_size);
- } else {
- /* decoder src buffer CFW PROT */
- if (ctx->is_drm) {
- int index = src_mb->vb.vb2_buf.index;
-
- s5p_mfc_stream_protect(ctx, src_mb, index);
- }
-
- s5p_mfc_set_dec_stream_buffer(ctx, src_mb, 0, 0);
- }
- }
-
- /* Try to use the non-referenced DPB on dst-queue */
- dst_mb = s5p_mfc_search_for_dpb(ctx, dec->dynamic_used);
- if (!dst_mb) {
- mfc_debug(2, "[DPB] couldn't find dst buffers\n");
- return -EAGAIN;
- }
-
- s5p_mfc_set_dynamic_dpb(ctx, dst_mb);
-
- s5p_mfc_clean_ctx_int_flags(ctx);
- s5p_mfc_decode_one_frame(ctx, 1);
-
- return 0;
-}
-
-int s5p_mfc_run_enc_init(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_buf *dst_mb;
- int ret;
-
- dst_mb = s5p_mfc_get_buf(&ctx->buf_queue_lock, &ctx->dst_buf_queue, MFC_BUF_NO_TOUCH_USED);
- if (!dst_mb) {
- mfc_debug(2, "no dst buffers\n");
- return -EAGAIN;
- }
-
- /* encoder dst buffer CFW PROT */
- if (ctx->is_drm) {
- int index = dst_mb->vb.vb2_buf.index;
-
- s5p_mfc_stream_protect(ctx, dst_mb, index);
- }
- s5p_mfc_set_enc_stream_buffer(ctx, dst_mb);
-
- s5p_mfc_set_enc_stride(ctx);
-
- mfc_debug(2, "Header addr: 0x%08llx\n", dst_mb->addr[0][0]);
- s5p_mfc_clean_ctx_int_flags(ctx);
-
- ret = s5p_mfc_init_encode(ctx);
- return ret;
-}
-
-int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_buf *dst_mb;
- struct s5p_mfc_buf *src_mb;
- struct s5p_mfc_raw_info *raw;
- unsigned int index, i;
- int last_frame = 0;
-
- raw = &ctx->raw_buf;
-
- /* Get the next source buffer */
- src_mb = s5p_mfc_get_buf(&ctx->buf_queue_lock, &ctx->src_buf_queue, MFC_BUF_SET_USED);
- if (!src_mb) {
- mfc_debug(2, "no src buffers\n");
- return -EAGAIN;
- }
-
- if (src_mb->num_valid_bufs > 0) {
- /* last image in a buffer container */
- if (src_mb->next_index == (src_mb->num_valid_bufs - 1)) {
- mfc_debug(4, "[BUFCON] last image in a container\n");
- last_frame = mfc_check_last_frame(ctx, src_mb);
- }
- } else {
- last_frame = mfc_check_last_frame(ctx, src_mb);
- }
-
- index = src_mb->vb.vb2_buf.index;
-
- /* encoder src buffer CFW PROT */
- if (ctx->is_drm)
- s5p_mfc_raw_protect(ctx, src_mb, index);
-
- s5p_mfc_set_enc_frame_buffer(ctx, src_mb, raw->num_planes);
-
- dst_mb = s5p_mfc_get_buf(&ctx->buf_queue_lock, &ctx->dst_buf_queue, MFC_BUF_SET_USED);
- if (!dst_mb) {
- mfc_debug(2, "no dst buffers\n");
- return -EAGAIN;
- }
-
- /* encoder dst buffer CFW PROT */
- if (ctx->is_drm) {
- i = dst_mb->vb.vb2_buf.index;
- s5p_mfc_stream_protect(ctx, dst_mb, i);
- }
- mfc_debug(2, "nal start : src index from src_buf_queue:%d\n",
- src_mb->vb.vb2_buf.index);
- mfc_debug(2, "nal start : dst index from dst_buf_queue:%d\n",
- dst_mb->vb.vb2_buf.index);
-
- s5p_mfc_set_enc_stream_buffer(ctx, dst_mb);
-
- if (call_cop(ctx, set_buf_ctrls_val, ctx, &ctx->src_ctrls[index]) < 0)
- mfc_err_ctx("failed in set_buf_ctrls_val\n");
-
- s5p_mfc_clean_ctx_int_flags(ctx);
- s5p_mfc_encode_one_frame(ctx, last_frame);
-
- return 0;
-}
-
-int s5p_mfc_run_enc_last_frames(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_buf *dst_mb;
- struct s5p_mfc_raw_info *raw;
-
- raw = &ctx->raw_buf;
-
- dst_mb = s5p_mfc_get_buf(&ctx->buf_queue_lock, &ctx->dst_buf_queue, MFC_BUF_SET_USED);
- if (!dst_mb) {
- mfc_debug(2, "no dst buffers\n");
- return -EAGAIN;
- }
-
- mfc_debug(2, "Set address zero for all planes\n");
- s5p_mfc_set_enc_frame_buffer(ctx, 0, raw->num_planes);
-
- /* encoder dst buffer CFW PROT */
- if (ctx->is_drm) {
- int index = dst_mb->vb.vb2_buf.index;
-
- s5p_mfc_stream_protect(ctx, dst_mb, index);
- }
-
- s5p_mfc_set_enc_stream_buffer(ctx, dst_mb);
-
- s5p_mfc_clean_ctx_int_flags(ctx);
- s5p_mfc_encode_one_frame(ctx, 1);
-
- return 0;
-}
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_opr.h
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __S5P_MFC_OPR_H
-#define __S5P_MFC_OPR_H __FILE__
-
-#include "s5p_mfc_common.h"
-
-int s5p_mfc_run_dec_init(struct s5p_mfc_ctx *ctx);
-int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx);
-int s5p_mfc_run_dec_last_frames(struct s5p_mfc_ctx *ctx);
-int s5p_mfc_run_enc_init(struct s5p_mfc_ctx *ctx);
-int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx);
-int s5p_mfc_run_enc_last_frames(struct s5p_mfc_ctx *ctx);
-
-#endif /* __S5P_MFC_OPR_H */
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_otf.c
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifdef CONFIG_VIDEO_EXYNOS_REPEATER
-#include <media/exynos_repeater.h>
-#endif
-#ifdef CONFIG_VIDEO_EXYNOS_TSMUX
-#include <media/exynos_tsmux.h>
-#endif
-#include <media/s5p_mfc_hwfc.h>
-
-#include "s5p_mfc_otf.h"
-#include "s5p_mfc_hwfc_internal.h"
-
-#include "s5p_mfc_sync.h"
-
-#include "s5p_mfc_inst.h"
-#include "s5p_mfc_pm.h"
-#include "s5p_mfc_cmd.h"
-#include "s5p_mfc_reg.h"
-
-#include "s5p_mfc_qos.h"
-#include "s5p_mfc_queue.h"
-#include "s5p_mfc_utils.h"
-#include "s5p_mfc_buf.h"
-#include "s5p_mfc_mem.h"
-
-static struct s5p_mfc_fmt *mfc_enc_hwfc_find_format(unsigned int pixelformat)
-{
- unsigned long i;
-
- mfc_debug_enter();
-
- for (i = 0; i < NUM_FORMATS; i++) {
- if (enc_hwfc_formats[i].fourcc == pixelformat)
- return (struct s5p_mfc_fmt *)&enc_hwfc_formats[i];
- }
-
- mfc_debug_leave();
-
- return NULL;
-}
-
-static int mfc_otf_set_buf_info(struct s5p_mfc_ctx *ctx)
-{
- struct _otf_handle *handle = ctx->otf_handle;
- struct _otf_buf_info *buf_info = &handle->otf_buf_info;
-
- mfc_debug_enter();
-
- ctx->src_fmt = mfc_enc_hwfc_find_format(buf_info->pixel_format);
- if (!ctx->src_fmt) {
- mfc_err_ctx("[OTF] failed to set source format\n");
- return -EINVAL;
- }
-
- mfc_debug(2, "[OTF][FRAME] resolution w: %d, h: %d, format: %s, bufcnt: %d\n",
- buf_info->width, buf_info->height,
- ctx->src_fmt->name, buf_info->buffer_count);
-
- /* set source information */
- ctx->raw_buf.num_planes = ctx->src_fmt->num_planes;
- ctx->img_width = buf_info->width;
- ctx->img_height = buf_info->height;
- ctx->crop_width = buf_info->width;
- ctx->crop_height = buf_info->height;
- ctx->buf_stride = ALIGN(ctx->img_width, 16);
-
- /* calculate source size */
- s5p_mfc_enc_calc_src_size(ctx);
-
- mfc_debug_leave();
-
- return 0;
-}
-
-static int mfc_otf_map_buf(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct _otf_handle *handle = ctx->otf_handle;
- struct _otf_buf_addr *buf_addr = &handle->otf_buf_addr;
- struct _otf_buf_info *buf_info = &handle->otf_buf_info;
- struct s5p_mfc_raw_info *raw = &ctx->raw_buf;
- int i;
-
- mfc_debug_enter();
-
- mfc_debug(2, "[OTF] buffer count: %d\n", buf_info->buffer_count);
- /* map buffers */
- for (i = 0; i < buf_info->buffer_count; i++) {
- mfc_debug(2, "[OTF] dma_buf: 0x%p\n", buf_info->bufs[i]);
- buf_addr->otf_buf_attach[i] = dma_buf_attach(buf_info->bufs[i], dev->device);
- if (IS_ERR(buf_addr->otf_buf_attach[i])) {
- mfc_err_ctx("[OTF] Failed to get attachment (err %ld)",
- PTR_ERR(buf_addr->otf_buf_attach[i]));
- buf_addr->otf_buf_attach[i] = 0;
- return -EINVAL;
- }
- buf_addr->otf_daddr[i][0] = ion_iovmm_map(buf_addr->otf_buf_attach[i], 0,
- raw->total_plane_size, DMA_BIDIRECTIONAL, 0);
- if (IS_ERR_VALUE(buf_addr->otf_daddr[i][0])) {
- mfc_err_ctx("[OTF] Failed to get daddr (0x%08llx)",
- buf_addr->otf_daddr[i][0]);
- buf_addr->otf_daddr[i][0] = 0;
- return -EINVAL;
- }
- if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12N) {
- buf_addr->otf_daddr[i][1] = NV12N_CBCR_BASE(buf_addr->otf_daddr[i][0],
- ctx->img_width, ctx->img_height);
- } else {
- mfc_err_ctx("[OTF] not supported format(0x%x)\n", ctx->src_fmt->fourcc);
- return -EINVAL;
- }
- mfc_debug(2, "[OTF] index: %d, addr[0]: 0x%08llx, addr[1]: 0x%08llx\n",
- i, buf_addr->otf_daddr[i][0], buf_addr->otf_daddr[i][1]);
- }
-
- mfc_debug_leave();
-
- return 0;
-}
-
-static void mfc_otf_unmap_buf(struct s5p_mfc_ctx *ctx)
-{
- struct _otf_handle *handle = ctx->otf_handle;
- struct _otf_buf_addr *buf_addr = &handle->otf_buf_addr;
- struct _otf_buf_info *buf_info = &handle->otf_buf_info;
- int i;
-
- mfc_debug_enter();
-
- for (i = 0; i < buf_info->buffer_count; i++) {
- if (buf_addr->otf_daddr[i][0]) {
- ion_iovmm_unmap(buf_addr->otf_buf_attach[i], buf_addr->otf_daddr[i][0]);
- buf_addr->otf_daddr[i][0] = 0;
- }
- if (buf_addr->otf_buf_attach[i]) {
- dma_buf_detach(buf_info->bufs[i], buf_addr->otf_buf_attach[i]);
- buf_addr->otf_buf_attach[i] = 0;
- }
- }
-
- mfc_debug_leave();
-}
-
-static void mfc_otf_put_buf(struct s5p_mfc_ctx *ctx)
-{
- struct _otf_handle *handle = ctx->otf_handle;
- struct _otf_buf_info *buf_info = &handle->otf_buf_info;
- int i;
-
- mfc_debug_enter();
-
- for (i = 0; i < buf_info->buffer_count; i++) {
- if (buf_info->bufs[i]) {
- dma_buf_put(buf_info->bufs[i]);
- buf_info->bufs[i] = NULL;
- }
- }
-
- mfc_debug_leave();
-
-}
-
-static int mfc_otf_init_hwfc_buf(struct s5p_mfc_ctx *ctx)
-{
-#ifdef CONFIG_VIDEO_EXYNOS_REPEATER
- struct shared_buffer_info *shared_buf_info;
-#endif
- struct _otf_handle *handle = ctx->otf_handle;
- struct _otf_buf_info *buf_info = &handle->otf_buf_info;
-
- mfc_debug_enter();
-
-#ifdef CONFIG_VIDEO_EXYNOS_REPEATER
- shared_buf_info = (struct shared_buffer_info *)buf_info;
- /* request buffers */
- if (hwfc_request_buffer(shared_buf_info, 1)) {
- mfc_err_dev("[OTF] request_buffer failed\n");
- return -EINVAL;
- }
-#endif
- mfc_debug(2, "[OTF] recieved buffer information\n");
-
- /* set buffer information to ctx, and calculate buffer size */
- if (mfc_otf_set_buf_info(ctx)) {
- mfc_err_ctx("[OTF] failed to set buffer information\n");
- mfc_otf_put_buf(ctx);
- return -EINVAL;
- }
-
- if (mfc_otf_map_buf(ctx)) {
- mfc_err_ctx("[OTF] failed to map buffers\n");
- mfc_otf_unmap_buf(ctx);
- mfc_otf_put_buf(ctx);
- return -EINVAL;
- }
- mfc_debug(2, "[OTF] HWFC buffer initialized\n");
-
- mfc_debug_leave();
-
- return 0;
-}
-
-static void mfc_otf_deinit_hwfc_buf(struct s5p_mfc_ctx *ctx)
-{
- mfc_debug_enter();
-
- mfc_otf_unmap_buf(ctx);
- mfc_otf_put_buf(ctx);
- mfc_debug(2, "[OTF] HWFC buffer de-initialized\n");
-
- mfc_debug_leave();
-}
-
-static int mfc_otf_create_handle(struct s5p_mfc_ctx *ctx)
-{
- struct _otf_handle *otf_handle;
-
- mfc_debug_enter();
-
- if (!ctx) {
- mfc_err_dev("[OTF] no mfc context to run\n");
- return -EINVAL;
- }
-
- ctx->otf_handle = kzalloc(sizeof(*otf_handle), GFP_KERNEL);
- if (!ctx->otf_handle) {
- mfc_err_dev("[OTF] no otf_handle\n");
- return -EINVAL;
- }
- mfc_debug(2, "[OTF] otf_handle created\n");
-
- mfc_debug_leave();
-
- return 0;
-}
-
-static void mfc_otf_destroy_handle(struct s5p_mfc_ctx *ctx)
-{
- mfc_debug_enter();
-
- if (!ctx) {
- mfc_err_dev("[OTF] no mfc context to run\n");
- return;
- }
-
- kfree(ctx->otf_handle);
- ctx->otf_handle = NULL;
- mfc_debug(2, "[OTF] otf_handle destroyed\n");
-
- mfc_debug_leave();
-}
-
-int s5p_mfc_otf_create(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev;
- int i;
-
- mfc_debug_enter();
-
- if (!ctx) {
- mfc_err_dev("[OTF] no mfc context to run\n");
- return -EINVAL;
- }
-
- dev = ctx->dev;
- if (!dev) {
- mfc_err_dev("[OTF] no mfc device to run\n");
- return -EINVAL;
- }
-
- for (i = 0; i < MFC_NUM_CONTEXTS; i++) {
- if (dev->ctx[i] && dev->ctx[i]->otf_handle) {
- mfc_err_dev("[OTF] otf_handle is already created, ctx: %d\n", i);
- return -EINVAL;
- }
- }
-
- if (mfc_otf_create_handle(ctx)) {
- mfc_err_dev("[OTF] otf_handle is not created\n");
- return -EINVAL;
- }
-
- if (otf_dump) {
- /* It is for debugging. Do not return error */
- if (s5p_mfc_otf_alloc_stream_buf(ctx)) {
- mfc_err_dev("[OTF] stream buffer allocation failed\n");
- s5p_mfc_otf_release_stream_buf(ctx);
- }
- }
-
- mfc_debug(2, "[OTF] otf_create is completed\n");
-
- mfc_debug_leave();
-
- return 0;
-}
-
-void s5p_mfc_otf_destroy(struct s5p_mfc_ctx *ctx)
-{
- mfc_debug_enter();
-
- if (!ctx) {
- mfc_err_dev("[OTF] no mfc context to run\n");
- return;
- }
-
- s5p_mfc_otf_release_stream_buf(ctx);
- mfc_otf_destroy_handle(ctx);
- mfc_debug(2, "[OTF] otf_destroy is completed\n");
-
- mfc_debug_leave();
-}
-
-int s5p_mfc_otf_init(struct s5p_mfc_ctx *ctx)
-{
- mfc_debug_enter();
-
- if (!ctx) {
- mfc_err_dev("[OTF] no mfc context to run\n");
- return -EINVAL;
- }
-
- if (!ctx->otf_handle) {
- mfc_err_dev("[OTF] otf_handle was not created\n");
- return -EINVAL;
- }
-
- if (mfc_otf_init_hwfc_buf(ctx)) {
- mfc_err_dev("[OTF] HWFC init failed\n");
- return -EINVAL;
- }
-
- mfc_debug(2, "[OTF] otf_init is completed\n");
-
- mfc_debug_leave();
-
- return 0;
-}
-
-void s5p_mfc_otf_deinit(struct s5p_mfc_ctx *ctx)
-{
- mfc_debug_enter();
-
- if (!ctx) {
- mfc_err_dev("[OTF] no mfc context to run\n");
- return;
- }
-
- mfc_otf_deinit_hwfc_buf(ctx);
- mfc_debug(2, "[OTF] deinit_otf is completed\n");
-
- mfc_debug_leave();
-}
-
-int s5p_mfc_otf_ctx_ready(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct _otf_handle *handle;
-
- mfc_debug_enter();
-
- if (!ctx->otf_handle)
- return 0;
-
- handle = ctx->otf_handle;
-
- mfc_debug(1, "[OTF] [c:%d] state = %d, otf_work_bit = %d\n",
- ctx->num, ctx->state, handle->otf_work_bit);
- /* If shutdown is called, do not try any cmd */
- if (dev->shutdown)
- return 0;
-
- /* Context is to parse header */
- if (ctx->state == MFCINST_GOT_INST)
- return 1;
-
- /* Context is to set buffers */
- if (ctx->state == MFCINST_HEAD_PARSED)
- return 1;
-
- if (ctx->state == MFCINST_RUNNING && handle->otf_work_bit)
- return 1;
- mfc_debug(2, "[OTF] ctx is not ready\n");
-
- mfc_debug_leave();
-
- return 0;
-}
-
-int s5p_mfc_otf_run_enc_init(struct s5p_mfc_ctx *ctx)
-{
- int ret;
-
- mfc_debug_enter();
-
- s5p_mfc_set_enc_stride(ctx);
- s5p_mfc_clean_ctx_int_flags(ctx);
- ret = s5p_mfc_init_encode(ctx);
-
- mfc_debug_leave();
-
- return ret;
-}
-
-int s5p_mfc_otf_run_enc_frame(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct _otf_handle *handle = ctx->otf_handle;
- struct s5p_mfc_raw_info *raw;
-
- mfc_debug_enter();
-
- raw = &ctx->raw_buf;
-
- if (!handle) {
- mfc_err_ctx("[OTF] There is no otf_handle, handle: 0x%p\n", handle);
- return -EINVAL;
- }
-
- if (!handle->otf_work_bit) {
- mfc_err_ctx("[OTF] Can't run OTF encoder, otf_work_bit: %d\n",
- handle->otf_work_bit);
- return -EINVAL;
- }
-
- if (!dev->has_hwfc) {
- mfc_err_ctx("[OTF] HWFC register didn't mapped\n");
- return -EINVAL;
- }
-
- s5p_mfc_otf_set_frame_addr(ctx, raw->num_planes);
- s5p_mfc_otf_set_stream_size(ctx, raw->total_plane_size);
- s5p_mfc_otf_set_hwfc_index(ctx, handle->otf_job_id);
-
- if (call_cop(ctx, init_buf_ctrls, ctx, MFC_CTRL_TYPE_SRC, handle->otf_buf_index) < 0)
- mfc_err_ctx("failed in init_buf_ctrls\n");
- if (call_cop(ctx, to_buf_ctrls, ctx, &ctx->src_ctrls[handle->otf_buf_index]) < 0)
- mfc_err_ctx("failed in to_buf_ctrls\n");
- if (call_cop(ctx, set_buf_ctrls_val, ctx, &ctx->src_ctrls[handle->otf_buf_index]) < 0)
- mfc_err_ctx("[OTF] failed in set_buf_ctrls_val\n");
-
- /* Change timestamp usec -> nsec */
- s5p_mfc_qos_update_last_framerate(ctx, handle->otf_time_stamp * 1000);
- s5p_mfc_qos_update_framerate(ctx);
-
- /* Set stream buffer size to handle buffer full */
- s5p_mfc_clean_ctx_int_flags(ctx);
- s5p_mfc_encode_one_frame(ctx, 0);
-
- mfc_debug_leave();
-
- return 0;
-}
-
-int s5p_mfc_otf_handle_seq(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_enc *enc = ctx->enc_priv;
-
- mfc_debug_enter();
-
- enc->header_size = s5p_mfc_get_enc_strm_size();
- ctx->dpb_count = s5p_mfc_get_enc_dpb_count();
- ctx->scratch_buf_size = s5p_mfc_get_enc_scratch_size();
- mfc_debug(2, "[OTF][STREAM] encoded slice type: %d, header size: %d, display order: %d\n",
- s5p_mfc_get_enc_slice_type(), enc->header_size,
- s5p_mfc_get_enc_pic_count());
- mfc_debug(2, "[OTF] cpb_count: %d, scratch size: %zu\n",
- ctx->dpb_count, ctx->scratch_buf_size);
-
- s5p_mfc_change_state(ctx, MFCINST_HEAD_PARSED);
-
- if (s5p_mfc_alloc_codec_buffers(ctx)) {
- mfc_err_ctx("[OTF] Failed to allocate encoding buffers\n");
- return -EINVAL;
- }
-
- mfc_debug_leave();
-
- return 0;
-}
-
-int s5p_mfc_otf_handle_stream(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_enc *enc = ctx->enc_priv;
- struct _otf_handle *handle = ctx->otf_handle;
- struct _otf_debug *debug = &handle->otf_debug;
- struct s5p_mfc_special_buf *buf;
- struct _otf_buf_addr *buf_addr = &handle->otf_buf_addr;
- struct s5p_mfc_raw_info *raw;
- dma_addr_t enc_addr[3] = { 0, 0, 0 };
- int slice_type, i;
- unsigned int strm_size;
- unsigned int pic_count;
- int enc_ret = HWFC_ERR_NONE;
- unsigned int print_size;
-
- mfc_debug_enter();
-
-#ifdef CONFIG_VIDEO_EXYNOS_TSMUX
- mfc_encoding_end();
-#endif
-
- slice_type = s5p_mfc_get_enc_slice_type();
- pic_count = s5p_mfc_get_enc_pic_count();
- strm_size = s5p_mfc_get_enc_strm_size();
-
- mfc_debug(2, "[OTF][STREAM] encoded slice type: %d, size: %d, display order: %d\n",
- slice_type, strm_size, pic_count);
-
- /* set encoded frame type */
- enc->frame_type = slice_type;
- raw = &ctx->raw_buf;
-
- if (strm_size > 0) {
- s5p_mfc_get_enc_frame_buffer(ctx, &enc_addr[0], raw->num_planes);
-
- for (i = 0; i < raw->num_planes; i++)
- mfc_debug(2, "[OTF][BUFINFO] ctx[%d] get src addr[%d]: 0x%08llx\n",
- ctx->num, i, enc_addr[i]);
- if (enc_addr[0] != buf_addr->otf_daddr[handle->otf_buf_index][0]) {
- mfc_err_ctx("[OTF] address is not matched. 0x%08llx != 0x%08llx\n",
- enc_addr[0], buf_addr->otf_daddr[handle->otf_buf_index][0]);
- enc_ret = -HWFC_ERR_MFC;
- }
- } else {
- mfc_err_ctx("[OTF] stream size is zero\n");
- enc_ret = -HWFC_ERR_MFC;
- }
-
- if (otf_dump && !ctx->is_drm) {
- buf = &debug->stream_buf[debug->frame_cnt];
- debug->stream_size[debug->frame_cnt] = strm_size;
- debug->frame_cnt++;
- if (debug->frame_cnt >= OTF_MAX_BUF)
- debug->frame_cnt = 0;
- /* print stream dump */
- print_size = (strm_size * 2) + 64;
-
- if (buf->vaddr)
- print_hex_dump(KERN_ERR, "OTF dump: ",
- DUMP_PREFIX_ADDRESS, print_size, 0,
- buf->vaddr, print_size, false);
- }
-
- if (call_cop(ctx, recover_buf_ctrls_val, ctx,
- &ctx->src_ctrls[handle->otf_buf_index]) < 0)
- mfc_err_ctx("[OTF] failed in recover_buf_ctrls_val\n");
- if (call_cop(ctx, cleanup_buf_ctrls, ctx,
- MFC_CTRL_TYPE_SRC, handle->otf_buf_index) < 0)
- mfc_err_ctx("[OTF] failed in cleanup_buf_ctrls\n");
-
- handle->otf_work_bit = 0;
- handle->otf_buf_index = 0;
- handle->otf_job_id = 0;
-
-#ifdef CONFIG_VIDEO_EXYNOS_REPEATER
- hwfc_encoding_done(enc_ret);
-#endif
-
- mfc_debug_leave();
-
- return 0;
-}
-
-void s5p_mfc_otf_handle_error(struct s5p_mfc_ctx *ctx,
- unsigned int reason, unsigned int err)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct _otf_handle *handle = ctx->otf_handle;
- int enc_ret = -HWFC_ERR_MFC;
-
- mfc_debug_enter();
-
- mfc_err_ctx("[OTF] Interrupt Error: display: %d, decoded: %d\n",
- s5p_mfc_get_warn(err), s5p_mfc_get_err(err));
- err = s5p_mfc_get_err(err);
-
- /* Error recovery is dependent on the state of context */
- switch (ctx->state) {
- case MFCINST_GOT_INST:
- case MFCINST_INIT:
- case MFCINST_RETURN_INST:
- case MFCINST_HEAD_PARSED:
- mfc_err_ctx("[OTF] error happened during init/de-init\n");
- break;
- case MFCINST_RUNNING:
- if (err == S5P_FIMV_ERR_MFC_TIMEOUT) {
- mfc_err_ctx("[OTF] MFC TIMEOUT. go to error state\n");
- s5p_mfc_change_state(ctx, MFCINST_ERROR);
- enc_ret = -HWFC_ERR_MFC_TIMEOUT;
- } else if (err == S5P_FIMV_ERR_TS_MUX_TIMEOUT ||
- err == S5P_FIMV_ERR_G2D_TIMEOUT) {
- mfc_err_ctx("[OTF] TS-MUX or G2D TIMEOUT. skip this frame\n");
- enc_ret = -HWFC_ERR_MFC_TIMEOUT;
- } else {
- mfc_err_ctx("[OTF] MFC ERROR. skip this frame\n");
- enc_ret = -HWFC_ERR_MFC;
- }
-
- handle->otf_work_bit = 0;
- handle->otf_buf_index = 0;
- handle->otf_job_id = 0;
-
- if (call_cop(ctx, recover_buf_ctrls_val, ctx,
- &ctx->src_ctrls[handle->otf_buf_index]) < 0)
- mfc_err_ctx("[OTF] failed in recover_buf_ctrls_val\n");
- if (call_cop(ctx, cleanup_buf_ctrls, ctx,
- MFC_CTRL_TYPE_SRC, handle->otf_buf_index) < 0)
- mfc_err_ctx("[OTF] failed in cleanup_buf_ctrls\n");
-
-#ifdef CONFIG_VIDEO_EXYNOS_REPEATER
- hwfc_encoding_done(enc_ret);
-#endif
- break;
- default:
- mfc_err_ctx("Encountered an error interrupt which had not been handled\n");
- mfc_err_ctx("ctx->state = %d, ctx->inst_no = %d\n",
- ctx->state, ctx->inst_no);
- break;
- }
-
- s5p_mfc_wake_up_dev(dev, reason, err);
-
- mfc_debug_leave();
-}
-
-int mfc_hwfc_check_run(struct s5p_mfc_ctx *ctx)
-{
- struct _otf_handle *handle = ctx->otf_handle;
-
- mfc_debug_enter();
-
- if (!handle) {
- mfc_err_ctx("[OTF] there is no handle for OTF\n");
- return -EINVAL;
- }
- if (handle->otf_work_bit) {
- mfc_err_ctx("[OTF] OTF is already working\n");
- return -EINVAL;
- }
- if (ctx->state != MFCINST_RUNNING) {
- mfc_err_ctx("[OTF] mfc is not running state\n");
- return -EINVAL;
- }
-
- mfc_debug_leave();
-
- return 0;
-}
-
-int s5p_mfc_hwfc_encode(int buf_index, int job_id, struct encoding_param *param)
-{
- struct s5p_mfc_dev *dev = g_mfc_dev;
- struct _otf_handle *handle;
- struct s5p_mfc_ctx *ctx = NULL;
-#ifdef CONFIG_VIDEO_EXYNOS_TSMUX
- struct packetizing_param packet_param;
-#endif
- int i;
-
- mfc_debug_enter();
-
-#ifdef CONFIG_VIDEO_EXYNOS_TSMUX
- mfc_encoding_start(buf_index);
-#endif
-
- for (i = 0; i < MFC_NUM_CONTEXTS; i++) {
- if (dev->ctx[i] && dev->ctx[i]->otf_handle) {
- ctx = dev->ctx[i];
- break;
- }
- }
-
- if (!ctx) {
- mfc_err_dev("[OTF] there is no context to run\n");
- return -HWFC_ERR_MFC_NOT_PREPARED;
- }
-
- if (mfc_hwfc_check_run(ctx)) {
- mfc_err_dev("[OTF] mfc is not prepared\n");
- return -HWFC_ERR_MFC_NOT_PREPARED;
- }
-
-#ifdef CONFIG_VIDEO_EXYNOS_TSMUX
- packet_param.time_stamp = param->time_stamp;
- if (debug_ts == 1)
- mfc_info_ctx("[OTF][TS] timestamp: %llu\n", param->time_stamp);
- if (packetize(&packet_param)) {
- mfc_err_dev("[OTF] packetize failed\n");
- return -HWFC_ERR_TSMUX;
- }
-#endif
-
- handle = ctx->otf_handle;
- handle->otf_work_bit = 1;
- handle->otf_buf_index = buf_index;
- handle->otf_job_id = job_id;
- handle->otf_time_stamp = param->time_stamp;
-
- if (s5p_mfc_otf_ctx_ready(ctx))
- s5p_mfc_set_bit(ctx->num, &dev->work_bits);
- if (s5p_mfc_is_work_to_do(dev))
- queue_work(dev->butler_wq, &dev->butler_work);
-
- mfc_debug_leave();
-
- return HWFC_ERR_NONE;
-}
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_otf.h
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __S5P_MFC_OTF_H
-#define __S5P_MFC_OTF_H __FILE__
-
-#include "s5p_mfc_common.h"
-
-extern struct s5p_mfc_dev *g_mfc_dev;
-
-int s5p_mfc_otf_create(struct s5p_mfc_ctx *ctx);
-void s5p_mfc_otf_destroy(struct s5p_mfc_ctx *ctx);
-int s5p_mfc_otf_init(struct s5p_mfc_ctx *ctx);
-void s5p_mfc_otf_deinit(struct s5p_mfc_ctx *ctx);
-int s5p_mfc_otf_ctx_ready(struct s5p_mfc_ctx *ctx);
-int s5p_mfc_otf_run_enc_init(struct s5p_mfc_ctx *ctx);
-int s5p_mfc_otf_run_enc_frame(struct s5p_mfc_ctx *ctx);
-int s5p_mfc_otf_handle_seq(struct s5p_mfc_ctx *ctx);
-int s5p_mfc_otf_handle_stream(struct s5p_mfc_ctx *ctx);
-void s5p_mfc_otf_handle_error(struct s5p_mfc_ctx *ctx, unsigned int reason, unsigned int err);
-
-#endif /* __S5P_MFC_OTF_H */
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_perf_measure.c
- *
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include "s5p_mfc_perf_measure.h"
-
-#ifndef PERF_MEASURE
-
-void s5p_mfc_perf_register(struct s5p_mfc_dev *dev) {}
-void mfc_measure_init(void) {}
-void mfc_measure_on(struct s5p_mfc_dev *dev) {}
-void mfc_measure_off(struct s5p_mfc_dev *dev) {}
-void mfc_measure_store(struct s5p_mfc_dev *dev, int diff) {}
-void s5p_mfc_perf_print(void) {}
-
-#else
-
-#endif
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_perf_measure.h
- *
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __S5P_MFC_PERF_MEASURE_H
-#define __S5P_MFC_PERF_MEASURE_H __FILE__
-
-#include <linux/clk.h>
-
-#include "s5p_mfc_reg.h"
-
-void s5p_mfc_perf_register(struct s5p_mfc_dev *dev);
-void mfc_measure_init(void);
-void mfc_measure_on(struct s5p_mfc_dev *dev);
-void mfc_measure_off(struct s5p_mfc_dev *dev);
-void mfc_measure_store(struct s5p_mfc_dev *dev, int diff);
-void s5p_mfc_perf_print(void);
-
-//#define PERF_MEASURE
-
-#ifndef PERF_MEASURE
-
-static inline void s5p_mfc_perf_init(struct s5p_mfc_dev *dev) {}
-static inline void s5p_mfc_perf_cancel_drv_margin(struct s5p_mfc_dev *dev) {}
-static inline void s5p_mfc_perf_measure_on(struct s5p_mfc_dev *dev) {}
-static inline void s5p_mfc_perf_measure_off(struct s5p_mfc_dev *dev) {}
-
-#else
-
-extern unsigned int perf_measure_option;
-
-static inline void s5p_mfc_perf_init(struct s5p_mfc_dev *dev)
-{
- dev->perf.new_start = 0;
- dev->perf.count = 0;
- dev->perf.drv_margin = 0;
-
- mfc_measure_init();
-
- mfc_info_dev("MFC frequency : %ld\n", clk_get_rate(dev->pm.clock));
-}
-
-static inline void s5p_mfc_perf_cancel_drv_margin(struct s5p_mfc_dev *dev)
-{
- dev->perf.drv_margin = 0;
-}
-
-static inline void s5p_mfc_perf_measure_on(struct s5p_mfc_dev *dev)
-{
- int diff;
-
- if (dev->perf.drv_margin) {
- do_gettimeofday(&dev->perf.end);
-
- diff = (dev->perf.end.tv_sec * 1000000 + dev->perf.end.tv_usec)
- - (dev->perf.begin.tv_sec * 1000000 + dev->perf.begin.tv_usec);
-
- mfc_info_dev("IRQ -> NAL_START time(ms) = %03d.%03d\n", diff / 1000, diff % 1000);
-
- dev->perf.drv_margin = 0;
- }
-
- do_gettimeofday(&dev->perf.begin);
-
- mfc_measure_on(dev);
-
- dev->perf.new_start = 1;
- dev->perf.count++;
-}
-
-static inline void s5p_mfc_perf_measure_off(struct s5p_mfc_dev *dev)
-{
- unsigned int diff;
-
- if ((dev->perf.new_start) && (dev->perf.count > 0)) {
- mfc_measure_off(dev);
-
- do_gettimeofday(&dev->perf.end);
-
- diff = (dev->perf.end.tv_sec * 1000000 + dev->perf.end.tv_usec)
- - (dev->perf.begin.tv_sec * 1000000 + dev->perf.begin.tv_usec);
-
- mfc_measure_store(dev, diff);
-
- mfc_debug(3, "uDECtype :%d, uENCtype :%d, codectype :%d\n",
- s5p_mfc_get_dec_frame_type(), s5p_mfc_get_enc_slice_type(), MFC_READL(S5P_FIMV_CODEC_TYPE));
-
- dev->perf.drv_margin = 1;
-
- do_gettimeofday(&dev->perf.begin);
- }
-
- dev->perf.new_start = 0;
-}
-
-#endif
-
-#endif /* __S5P_MFC_PERF_MEASURE_H */
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_pm.c
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/pm_runtime.h>
-#include <linux/clk.h>
-#include <linux/smc.h>
-
-#include "s5p_mfc_pm.h"
-
-#include "s5p_mfc_cal.h"
-#include "s5p_mfc_reg.h"
-
-void s5p_mfc_pm_init(struct s5p_mfc_dev *dev)
-{
- spin_lock_init(&dev->pm.clklock);
- atomic_set(&dev->pm.pwr_ref, 0);
- atomic_set(&dev->clk_ref, 0);
-
- dev->pm.device = dev->device;
- dev->pm.clock_on_steps = 0;
- dev->pm.clock_off_steps = 0;
- pm_runtime_enable(dev->pm.device);
-}
-
-void s5p_mfc_pm_final(struct s5p_mfc_dev *dev)
-{
- pm_runtime_disable(dev->pm.device);
-}
-
-int s5p_mfc_pm_clock_on(struct s5p_mfc_dev *dev)
-{
- int ret = 0;
- int state;
-
- dev->pm.clock_on_steps = 1;
- state = atomic_read(&dev->clk_ref);
-
- MFC_TRACE_DEV("** clock_on start: ref state(%d)\n", state);
- ret = clk_enable(dev->pm.clock);
- if (ret < 0) {
- mfc_err_dev("clk_enable failed (%d)\n", ret);
- call_dop(dev, dump_and_stop_debug_mode, dev);
- return ret;
- }
- dev->pm.clock_on_steps |= 0x1 << 1;
-
- if (dev->pm.base_type != MFCBUF_INVALID)
- s5p_mfc_set_risc_base_addr(dev, dev->pm.base_type);
-
- dev->pm.clock_on_steps |= 0x1 << 2;
-#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
- if (dev->curr_ctx_is_drm) {
- unsigned long flags;
-
- spin_lock_irqsave(&dev->pm.clklock, flags);
- mfc_debug(3, "Begin: enable protection\n");
- ret = exynos_smc(SMC_PROTECTION_SET, 0,
- dev->id, SMC_PROTECTION_ENABLE);
- dev->pm.clock_on_steps |= 0x1 << 3;
- if (ret != DRMDRV_OK) {
- mfc_err_dev("Protection Enable failed! ret(%u)\n", ret);
- call_dop(dev, dump_and_stop_debug_mode, dev);
- spin_unlock_irqrestore(&dev->pm.clklock, flags);
- clk_disable(dev->pm.clock);
- return -EACCES;
- }
- mfc_debug(3, "End: enable protection\n");
- spin_unlock_irqrestore(&dev->pm.clklock, flags);
- }
-#endif
- dev->pm.clock_on_steps |= 0x1 << 4;
- atomic_inc_return(&dev->clk_ref);
-
- dev->pm.clock_on_steps |= 0x1 << 6;
- state = atomic_read(&dev->clk_ref);
- mfc_debug(2, "+ %d\n", state);
- MFC_TRACE_DEV("** clock_on end: ref state(%d)\n", state);
-
- return 0;
-}
-
-/* Use only in functions that first instance is guaranteed, like mfc_init_hw() */
-int s5p_mfc_pm_clock_on_with_base(struct s5p_mfc_dev *dev,
- enum mfc_buf_usage_type buf_type)
-{
- int ret;
- dev->pm.base_type = buf_type;
- ret = s5p_mfc_pm_clock_on(dev);
- dev->pm.base_type = MFCBUF_INVALID;
-
- return ret;
-}
-
-void s5p_mfc_pm_clock_off(struct s5p_mfc_dev *dev)
-{
- int state;
-
- dev->pm.clock_off_steps = 1;
- atomic_dec_return(&dev->clk_ref);
-
- dev->pm.clock_off_steps |= 0x1 << 1;
- state = atomic_read(&dev->clk_ref);
- MFC_TRACE_DEV("** clock_off start: ref state(%d)\n", state);
- if (state < 0) {
- mfc_err_dev("Clock state is wrong(%d)\n", state);
- atomic_set(&dev->clk_ref, 0);
- dev->pm.clock_off_steps |= 0x1 << 2;
- } else {
-#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
- if (dev->curr_ctx_is_drm) {
- unsigned long flags;
- int ret = 0;
-
- mfc_debug(3, "Begin: disable protection\n");
- spin_lock_irqsave(&dev->pm.clklock, flags);
- dev->pm.clock_off_steps |= 0x1 << 3;
- ret = exynos_smc(SMC_PROTECTION_SET, 0,
- dev->id, SMC_PROTECTION_DISABLE);
- if (ret != DRMDRV_OK) {
- mfc_err_dev("Protection Disable failed! ret(%u)\n", ret);
- call_dop(dev, dump_and_stop_debug_mode, dev);
- spin_unlock_irqrestore(&dev->pm.clklock, flags);
- clk_disable(dev->pm.clock);
- return;
- }
- mfc_debug(3, "End: disable protection\n");
- dev->pm.clock_off_steps |= 0x1 << 4;
- spin_unlock_irqrestore(&dev->pm.clklock, flags);
- }
-#endif
- dev->pm.clock_off_steps |= 0x1 << 5;
- clk_disable(dev->pm.clock);
- }
-
- dev->pm.clock_off_steps |= 0x1 << 6;
- state = atomic_read(&dev->clk_ref);
- mfc_debug(2, "- %d\n", state);
- MFC_TRACE_DEV("** clock_off end: ref state(%d)\n", state);
-}
-
-int s5p_mfc_pm_power_on(struct s5p_mfc_dev *dev)
-{
- int ret;
-
- MFC_TRACE_DEV("++ Power on\n");
- ret = pm_runtime_get_sync(dev->pm.device);
- if (ret < 0) {
- mfc_err_dev("Failed to get power: ret(%d)\n", ret);
- call_dop(dev, dump_and_stop_debug_mode, dev);
- goto err_power_on;
- }
-
- dev->pm.clock = clk_get(dev->device, "aclk_mfc");
- if (IS_ERR(dev->pm.clock)) {
- mfc_err_dev("failed to get parent clock: ret(%d)\n", ret);
- ret = -ENOENT;
- goto err_clk_get;
- }
-
- ret = clk_prepare(dev->pm.clock);
- if (ret) {
- mfc_err_dev("clk_prepare() failed: ret(%d)\n", ret);
- goto err_clk_prepare;
- }
-
- atomic_inc(&dev->pm.pwr_ref);
-
- MFC_TRACE_DEV("-- Power on: ret(%d)\n", ret);
-
- return 0;
-
-err_clk_prepare:
- clk_put(dev->pm.clock);
-
-err_clk_get:
- pm_runtime_put_sync(dev->pm.device);
-
-err_power_on:
- return ret;
-}
-
-int s5p_mfc_pm_power_off(struct s5p_mfc_dev *dev)
-{
- int ret;
-
- MFC_TRACE_DEV("++ Power off\n");
-
- clk_unprepare(dev->pm.clock);
- clk_put(dev->pm.clock);
-
- ret = pm_runtime_put_sync(dev->pm.device);
- if (ret < 0) {
- mfc_err_dev("Failed to put power: ret(%d)\n", ret);
- call_dop(dev, dump_and_stop_debug_mode, dev);
- return ret;
- }
-
- atomic_dec(&dev->pm.pwr_ref);
-
- MFC_TRACE_DEV("-- Power off: ret(%d)\n", ret);
-
- return ret;
-}
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_pm.h
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __S5P_MFC_PM_H
-#define __S5P_MFC_PM_H __FILE__
-
-#include "s5p_mfc_common.h"
-
-static inline int s5p_mfc_pm_get_pwr_ref_cnt(struct s5p_mfc_dev *dev)
-{
- return atomic_read(&dev->pm.pwr_ref);
-}
-
-static inline int s5p_mfc_pm_get_clk_ref_cnt(struct s5p_mfc_dev *dev)
-{
- return atomic_read(&dev->clk_ref);
-}
-
-void s5p_mfc_pm_init(struct s5p_mfc_dev *dev);
-void s5p_mfc_pm_final(struct s5p_mfc_dev *dev);
-
-int s5p_mfc_pm_clock_on(struct s5p_mfc_dev *dev);
-int s5p_mfc_pm_clock_on_with_base(struct s5p_mfc_dev *dev,
- enum mfc_buf_usage_type buf_type);
-void s5p_mfc_pm_clock_off(struct s5p_mfc_dev *dev);
-int s5p_mfc_pm_power_on(struct s5p_mfc_dev *dev);
-int s5p_mfc_pm_power_off(struct s5p_mfc_dev *dev);
-
-#endif /* __S5P_MFC_PM_H */
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_qos.c
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/err.h>
-#ifdef CONFIG_EXYNOS_BTS
-#include <soc/samsung/bts.h>
-#endif
-
-#include "s5p_mfc_qos.h"
-
-#ifdef CONFIG_MFC_USE_BUS_DEVFREQ
-enum {
- MFC_QOS_ADD,
- MFC_QOS_UPDATE,
- MFC_QOS_REMOVE,
- MFC_QOS_BW,
-};
-
-enum {
- MFC_PERF_BOOST_DVFS = (1 << 0),
- MFC_PERF_BOOST_MO = (1 << 1),
- MFC_PERF_BOOST_CPU = (1 << 2),
-};
-
-void s5p_mfc_perf_boost_enable(struct s5p_mfc_dev *dev)
-{
- struct s5p_mfc_platdata *pdata = dev->pdata;
- struct s5p_mfc_qos_boost *qos_boost_table = pdata->qos_boost_table;
- int i;
-
- if (perf_boost_mode & MFC_PERF_BOOST_DVFS) {
- if (pdata->mfc_freq_control)
- pm_qos_add_request(&dev->qos_req_mfc, PM_QOS_MFC_THROUGHPUT,
- qos_boost_table->freq_mfc);
- pm_qos_add_request(&dev->qos_req_int, PM_QOS_DEVICE_THROUGHPUT,
- qos_boost_table->freq_int);
- pm_qos_add_request(&dev->qos_req_mif, PM_QOS_BUS_THROUGHPUT,
- qos_boost_table->freq_mif);
- mfc_debug(3, "[QoS][BOOST] DVFS mfc: %d, int:%d, mif:%d\n",
- qos_boost_table->freq_mfc, qos_boost_table->freq_int,
- qos_boost_table->freq_mif);
- }
-
-#ifdef CONFIG_EXYNOS_BTS
- if (perf_boost_mode & MFC_PERF_BOOST_MO) {
- if (pdata->mo_control) {
- bts_update_scen(BS_MFC_UHD_10BIT, 1);
- mfc_debug(3, "[QoS][BOOST] BTS(MO): UHD_10BIT\n");
- }
- }
-#endif
-
- if (perf_boost_mode & MFC_PERF_BOOST_CPU) {
- for (i = 0; i < qos_boost_table->num_cluster; i++) {
- pm_qos_add_request(&dev->qos_req_cluster[i], PM_QOS_CLUSTER0_FREQ_MIN + (i * 2),
- qos_boost_table->freq_cluster[i]);
- mfc_debug(3, "[QoS][BOOST] CPU cluster[%d]: %d\n",
- i, qos_boost_table->freq_cluster[i]);
- }
- }
-}
-
-void s5p_mfc_perf_boost_disable(struct s5p_mfc_dev *dev)
-{
- struct s5p_mfc_platdata *pdata = dev->pdata;
- int i;
-
- if (perf_boost_mode & MFC_PERF_BOOST_DVFS) {
- if (pdata->mfc_freq_control)
- pm_qos_remove_request(&dev->qos_req_mfc);
- pm_qos_remove_request(&dev->qos_req_int);
- pm_qos_remove_request(&dev->qos_req_mif);
- mfc_debug(3, "[QoS][BOOST] DVFS off\n");
- }
-
-#ifdef CONFIG_EXYNOS_BTS
- if (perf_boost_mode & MFC_PERF_BOOST_MO) {
- if (pdata->mo_control) {
- bts_update_scen(BS_MFC_UHD_10BIT, 0);
- mfc_debug(3, "[QoS][BOOST] BTS(MO) off\n");
- }
- }
-#endif
-
- if (perf_boost_mode & MFC_PERF_BOOST_CPU) {
- for (i = 0; i < pdata->qos_boost_table->num_cluster; i++) {
- pm_qos_remove_request(&dev->qos_req_cluster[i]);
- mfc_debug(3, "[QoS][BOOST] CPU cluster[%d] off\n", i);
- }
- }
-}
-
-static void mfc_qos_operate(struct s5p_mfc_ctx *ctx, int opr_type, int idx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_platdata *pdata = dev->pdata;
- struct s5p_mfc_qos *qos_table = pdata->qos_table;
-
- switch (opr_type) {
- case MFC_QOS_ADD:
- if (pdata->mfc_freq_control)
- pm_qos_add_request(&dev->qos_req_mfc,
- PM_QOS_MFC_THROUGHPUT,
- qos_table[idx].freq_mfc);
- pm_qos_add_request(&dev->qos_req_int,
- PM_QOS_DEVICE_THROUGHPUT,
- qos_table[idx].freq_int);
- pm_qos_add_request(&dev->qos_req_mif,
- PM_QOS_BUS_THROUGHPUT,
- qos_table[idx].freq_mif);
-
-#ifdef CONFIG_EXYNOS_BTS
- if (pdata->mo_control) {
- bts_update_scen(BS_MFC_UHD_ENC60, qos_table[idx].mo_uhd_enc60_value);
- bts_update_scen(BS_MFC_UHD_10BIT, qos_table[idx].mo_10bit_value);
- bts_update_scen(BS_MFC_UHD, qos_table[idx].mo_value);
- MFC_TRACE_CTX("BTS(MO) update - uhd:%d, uhd_10bit:%d, uhd_enc60:%d\n",
- qos_table[idx].mo_value, qos_table[idx].mo_10bit_value,
- qos_table[idx].mo_uhd_enc60_value);
- mfc_debug(2, "[QoS] BTS(MO) update - uhd:%d, uhd_10bit:%d, uhd_enc60:%d\n",
- qos_table[idx].mo_value, qos_table[idx].mo_10bit_value,
- qos_table[idx].mo_uhd_enc60_value);
- }
-#endif
-
- atomic_set(&dev->qos_req_cur, idx + 1);
- MFC_TRACE_CTX("QoS add[%d] - mfc:%d(%s), int:%d, mif:%d\n",
- idx, qos_table[idx].freq_mfc, pdata->mfc_freq_control ? "used" : "un-used",
- qos_table[idx].freq_int, qos_table[idx].freq_mif);
- mfc_debug(2, "[QoS] QoS add[%d] - mfc:%d(%s), int:%d, mif:%d\n",
- idx, qos_table[idx].freq_mfc, pdata->mfc_freq_control ? "used" : "un-used",
- qos_table[idx].freq_int, qos_table[idx].freq_mif);
- break;
- case MFC_QOS_UPDATE:
- if (pdata->mfc_freq_control)
- pm_qos_update_request(&dev->qos_req_mfc,
- qos_table[idx].freq_mfc);
- pm_qos_update_request(&dev->qos_req_int,
- qos_table[idx].freq_int);
- pm_qos_update_request(&dev->qos_req_mif,
- qos_table[idx].freq_mif);
-
-#ifdef CONFIG_EXYNOS_BTS
- if (pdata->mo_control) {
- bts_update_scen(BS_MFC_UHD_ENC60, qos_table[idx].mo_uhd_enc60_value);
- bts_update_scen(BS_MFC_UHD_10BIT, qos_table[idx].mo_10bit_value);
- bts_update_scen(BS_MFC_UHD, qos_table[idx].mo_value);
- MFC_TRACE_CTX("BTS(MO) update - uhd:%d, uhd_10bit:%d, uhd_enc60:%d\n",
- qos_table[idx].mo_value, qos_table[idx].mo_10bit_value,
- qos_table[idx].mo_uhd_enc60_value);
- mfc_debug(2, "[QoS] BTS(MO) update - uhd:%d, uhd_10bit:%d, uhd_enc60:%d\n",
- qos_table[idx].mo_value, qos_table[idx].mo_10bit_value,
- qos_table[idx].mo_uhd_enc60_value);
- }
-#endif
-
- atomic_set(&dev->qos_req_cur, idx + 1);
- MFC_TRACE_CTX("QoS update[%d] - mfc:%d(%s), int:%d, mif:%d\n",
- idx, qos_table[idx].freq_mfc, pdata->mfc_freq_control ? "used" : "un-used",
- qos_table[idx].freq_int, qos_table[idx].freq_mif);
- mfc_debug(2, "[QoS] QoS update[%d] - mfc:%d(%s), int:%d, mif:%d\n",
- idx, qos_table[idx].freq_mfc, pdata->mfc_freq_control ? "used" : "un-used",
- qos_table[idx].freq_int, qos_table[idx].freq_mif);
- break;
- case MFC_QOS_REMOVE:
- if (pdata->mfc_freq_control)
- pm_qos_remove_request(&dev->qos_req_mfc);
- pm_qos_remove_request(&dev->qos_req_int);
- pm_qos_remove_request(&dev->qos_req_mif);
-
-#ifdef CONFIG_EXYNOS_BTS
- if (pdata->mo_control) {
- bts_update_scen(BS_MFC_UHD_ENC60, 0);
- bts_update_scen(BS_MFC_UHD_10BIT, 0);
- bts_update_scen(BS_MFC_UHD, 0);
- }
-
- if (pdata->bw_control) {
- dev->mfc_bw.peak = 0;
- dev->mfc_bw.read = 0;
- dev->mfc_bw.write = 0;
- bts_update_bw(BTS_BW_MFC, dev->mfc_bw);
- }
-#endif
-
- atomic_set(&dev->qos_req_cur, 0);
- MFC_TRACE_CTX("QoS remove\n");
- mfc_debug(2, "[QoS] QoS remove\n");
- break;
- case MFC_QOS_BW:
-#ifdef CONFIG_EXYNOS_BTS
- if (pdata->bw_control) {
- bts_update_bw(BTS_BW_MFC, dev->mfc_bw);
- MFC_TRACE_CTX("BTS(BW) update (peak: %d, read: %d, write: %d)\n",
- dev->mfc_bw.peak, dev->mfc_bw.read, dev->mfc_bw.write);
- mfc_debug(2, "[QoS] BTS(BW) update (peak: %d, read: %d, write: %d)\n",
- dev->mfc_bw.peak, dev->mfc_bw.read, dev->mfc_bw.write);
- }
-#endif
- break;
- default:
- mfc_err_ctx("[QoS] Unknown request for opr [%d]\n", opr_type);
- break;
- }
-}
-
-#ifdef CONFIG_EXYNOS_BTS
-static void mfc_qos_set(struct s5p_mfc_ctx *ctx, struct bts_bw *mfc_bw, int i)
-#else
-static void mfc_qos_set(struct s5p_mfc_ctx *ctx, int i)
-#endif
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_platdata *pdata = dev->pdata;
- struct s5p_mfc_qos *qos_table = pdata->qos_table;
-
- mfc_debug(2, "[QoS] table[%d] covered mb %d ~ %d (mfc: %d, int:%d, mif:%d)\n",
- i, qos_table[i].threshold_mb,
- i == pdata->num_qos_steps - 1 ?
- pdata->max_mb : qos_table[i + 1].threshold_mb,
- qos_table[i].freq_mfc, qos_table[i].freq_int,
- qos_table[i].freq_mif);
-
-#ifdef CONFIG_EXYNOS_BTS
- if (mfc_bw->peak != dev->mfc_bw.peak) {
- dev->mfc_bw.peak = mfc_bw->peak;
- dev->mfc_bw.read = mfc_bw->read;
- dev->mfc_bw.write = mfc_bw->write;
- mfc_qos_operate(ctx, MFC_QOS_BW, i);
- }
-#endif
-
- if (atomic_read(&dev->qos_req_cur) == 0)
- mfc_qos_operate(ctx, MFC_QOS_ADD, i);
- else if (atomic_read(&dev->qos_req_cur) != (i + 1))
- mfc_qos_operate(ctx, MFC_QOS_UPDATE, i);
-}
-
-static inline unsigned long mfc_qos_get_weighted_mb(struct s5p_mfc_ctx *ctx,
- unsigned long mb)
-{
- struct s5p_mfc_enc *enc = ctx->enc_priv;
- struct s5p_mfc_dec *dec = ctx->dec_priv;
- struct s5p_mfc_enc_params *p;
- u32 num_planes = ctx->dst_fmt->num_planes;
- int weight = 1000;
- unsigned long weighted_mb;
-
- switch (ctx->codec_mode) {
- case S5P_FIMV_CODEC_H264_DEC:
- case S5P_FIMV_CODEC_H264_MVC_DEC:
- case S5P_FIMV_CODEC_H264_ENC:
- case S5P_FIMV_CODEC_H264_MVC_ENC:
- case S5P_FIMV_CODEC_VP8_DEC:
- case S5P_FIMV_CODEC_VP8_ENC:
- if (num_planes == 3)
- weight = (weight * 100) / MFC_QOS_WEIGHT_3PLANE;
- break;
-
- case S5P_FIMV_CODEC_HEVC_DEC:
- case S5P_FIMV_CODEC_HEVC_ENC:
- case S5P_FIMV_CODEC_VP9_DEC:
- case S5P_FIMV_CODEC_VP9_ENC:
- case S5P_FIMV_CODEC_BPG_DEC:
- case S5P_FIMV_CODEC_BPG_ENC:
- if (num_planes == 3) {
- weight = (weight * 100) / MFC_QOS_WEIGHT_3PLANE;
- } else {
- if (ctx->is_10bit)
- weight = (weight * 100) / MFC_QOS_WEIGHT_10BIT;
- else if (ctx->is_422)
- weight = (weight * 100) / MFC_QOS_WEIGHT_422_10INTRA;
- }
- break;
-
- case S5P_FIMV_CODEC_MPEG4_DEC:
- case S5P_FIMV_CODEC_FIMV1_DEC:
- case S5P_FIMV_CODEC_FIMV2_DEC:
- case S5P_FIMV_CODEC_FIMV3_DEC:
- case S5P_FIMV_CODEC_FIMV4_DEC:
- case S5P_FIMV_CODEC_H263_DEC:
- case S5P_FIMV_CODEC_VC1_RCV_DEC:
- case S5P_FIMV_CODEC_VC1_DEC:
- case S5P_FIMV_CODEC_MPEG2_DEC:
- case S5P_FIMV_CODEC_MPEG4_ENC:
- case S5P_FIMV_CODEC_H263_ENC:
- weight = (weight * 100) / MFC_QOS_WEIGHT_OTHER_CODEC;
- break;
-
- default:
- mfc_err_ctx("[QoS] wrong codec_mode (%d), no weight\n", ctx->codec_mode);
- }
-
- if (enc) {
- p = &enc->params;
- if ((IS_H264_ENC(ctx) || IS_HEVC_ENC(ctx)) && p->num_b_frame) {
- weight = (weight * 100) / MFC_QOS_WEIGHT_BFRAME;
- mfc_debug(3, "[QoS] weight: B frame encoding\n");
- }
- if ((IS_H264_ENC(ctx) || IS_HEVC_ENC(ctx) || IS_VP8_ENC(ctx) ||
- IS_VP9_ENC(ctx)) && (p->num_refs_for_p >= 2)) {
- weight = (weight * 100) / MFC_QOS_WEIGHT_NUM_OF_REF;
- mfc_debug(3, "[QoS] weight: num of ref >= 2\n");
- }
- }
- if (dec) {
- if (dec->num_of_tile_over_4) {
- weight = (weight * 100) / MFC_QOS_WEIGHT_NUM_OF_TILE;
- mfc_debug(3, "[QoS] weight: num of tile >= 4\n");
- }
- }
-
- weighted_mb = (mb * weight) / 1000;
- mfc_debug(3, "[QoS] weight: %d.%03d, codec: %d, num planes: %d, "
- "10bit: %d, 422format: %d (mb: %ld)\n",
- weight / 1000, weight % 1000, ctx->codec_mode,
- num_planes, ctx->is_10bit, ctx->is_422,
- weighted_mb);
-
-
- return weighted_mb;
-}
-
-static inline unsigned long mfc_qos_get_mb_per_second(struct s5p_mfc_ctx *ctx)
-{
- unsigned long mb_width, mb_height, fps, mb;
-
- mb_width = (ctx->crop_width + 15) / 16;
- mb_height = (ctx->crop_height + 15) / 16;
- fps = ctx->framerate / 1000;
-
- mb = mb_width * mb_height * fps;
- mfc_debug(4, "[QoS] ctx[%d:%s] %d x %d @ %ld fps (mb: %ld)\n",
- ctx->num, ctx->type == MFCINST_ENCODER ? "ENC" : "DEC",
- ctx->crop_width, ctx->crop_height, fps, mb);
-
- return mfc_qos_get_weighted_mb(ctx, mb);
-}
-
-#ifdef CONFIG_EXYNOS_BTS
-static struct s5p_mfc_qos_bw mfc_bw_info = {
- /* peak read write (KB/UHD frame) */
- .h264_dec_uhd_bw = { 38131, 40206, 24870 },
- .hevc_dec_uhd_bw = { 35055, 33741, 20511 },
- .hevc_dec_uhd_10bit_bw = { 38643, 36428, 25491 },
- .vp8_dec_uhd_bw = { 28693, 30464, 22331 },
- .vp9_dec_uhd_bw = { 21464, 22160, 19747 },
- .mpeg4_dec_uhd_bw = { 31567, 25191, 15961 },
- .h264_enc_uhd_bw = { 62543, 75230, 13080 },
- .hevc_enc_uhd_bw = { 54863, 65417, 11422 },
- .hevc_enc_uhd_10bit_bw = { 68011, 79367, 14688 },
- .vp8_enc_uhd_bw = { 63970, 67281, 22508 },
- .vp9_enc_uhd_bw = { 84443, 71588, 19337 },
- .mpeg4_enc_uhd_bw = { 44633, 55310, 9599 },
-};
-
-static void mfc_qos_get_bw_per_second(struct s5p_mfc_ctx *ctx, struct bts_bw *mfc_bw)
-{
- struct mfc_qos_bw_data bw_data;
- unsigned long mb_width, mb_height, fps, mb;
- unsigned long peak_bw_per_sec;
- unsigned long read_bw_per_sec;
- unsigned long write_bw_per_sec;
- unsigned long mb_count_per_uhd_frame = MB_COUNT_PER_UHD_FRAME;
- unsigned long max_fps_per_uhd_frame = MAX_FPS_PER_UHD_FRAME;
-
- mb_width = (ctx->crop_width + 15) / 16;
- mb_height = (ctx->crop_height + 15) / 16;
- fps = ctx->framerate / 1000;
-
- mb = mb_width * mb_height * fps;
-
- switch (ctx->codec_mode) {
- case S5P_FIMV_CODEC_H264_DEC:
- case S5P_FIMV_CODEC_H264_MVC_DEC:
- bw_data = mfc_bw_info.h264_dec_uhd_bw;
- break;
- case S5P_FIMV_CODEC_H264_ENC:
- case S5P_FIMV_CODEC_H264_MVC_ENC:
- bw_data = mfc_bw_info.h264_enc_uhd_bw;
- break;
- case S5P_FIMV_CODEC_HEVC_DEC:
- case S5P_FIMV_CODEC_BPG_DEC:
- if (ctx->is_10bit)
- bw_data = mfc_bw_info.hevc_dec_uhd_10bit_bw;
- else
- bw_data = mfc_bw_info.hevc_dec_uhd_bw;
- break;
- case S5P_FIMV_CODEC_HEVC_ENC:
- case S5P_FIMV_CODEC_BPG_ENC:
- if (ctx->is_10bit)
- bw_data = mfc_bw_info.hevc_enc_uhd_10bit_bw;
- else
- bw_data = mfc_bw_info.hevc_enc_uhd_bw;
- break;
- case S5P_FIMV_CODEC_MPEG4_DEC:
- case S5P_FIMV_CODEC_FIMV1_DEC:
- case S5P_FIMV_CODEC_FIMV2_DEC:
- case S5P_FIMV_CODEC_FIMV3_DEC:
- case S5P_FIMV_CODEC_FIMV4_DEC:
- case S5P_FIMV_CODEC_H263_DEC:
- case S5P_FIMV_CODEC_VC1_RCV_DEC:
- case S5P_FIMV_CODEC_VC1_DEC:
- case S5P_FIMV_CODEC_MPEG2_DEC:
- bw_data = mfc_bw_info.mpeg4_dec_uhd_bw;
- break;
- case S5P_FIMV_CODEC_VP8_DEC:
- bw_data = mfc_bw_info.vp8_dec_uhd_bw;
- break;
- case S5P_FIMV_CODEC_VP9_DEC:
- bw_data = mfc_bw_info.vp9_dec_uhd_bw;
- break;
- case S5P_FIMV_CODEC_MPEG4_ENC:
- case S5P_FIMV_CODEC_H263_ENC:
- bw_data = mfc_bw_info.mpeg4_enc_uhd_bw;
- break;
- case S5P_FIMV_CODEC_VP8_ENC:
- bw_data = mfc_bw_info.vp8_enc_uhd_bw;
- break;
- case S5P_FIMV_CODEC_VP9_ENC:
- bw_data = mfc_bw_info.vp9_enc_uhd_bw;
- break;
- default:
- bw_data.peak = 0;
- bw_data.read = 0;
- bw_data.write = 0;
- mfc_err_ctx("[QoS] wrong codec_mode (%d)\n", ctx->codec_mode);
- }
-
- if (mb > (mb_count_per_uhd_frame * max_fps_per_uhd_frame)) {
- mfc_debug(4, "[QoS] fix upper mb bound (mb: %ld, fps: %ld)\n", mb, fps);
- mb = mb_count_per_uhd_frame * max_fps_per_uhd_frame;
- }
-
- peak_bw_per_sec = (bw_data.peak * mb) / mb_count_per_uhd_frame;
- read_bw_per_sec = (bw_data.read * mb) / mb_count_per_uhd_frame;
- write_bw_per_sec = (bw_data.write * mb) / mb_count_per_uhd_frame;
-
- if (peak_bw_per_sec == 0) {
- mfc_debug(4, "[QoS] fix lower peak bound (mb: %ld, fps: %ld)\n", mb, fps);
- peak_bw_per_sec = MIN_BW_PER_SEC;
- }
- if (read_bw_per_sec == 0) {
- mfc_debug(4, "[QoS] fix lower read bound (mb: %ld, fps: %ld)\n", mb, fps);
- read_bw_per_sec = MIN_BW_PER_SEC;
- }
- if (write_bw_per_sec == 0) {
- mfc_debug(4, "[QoS] fix lower write bound (mb: %ld, fps: %ld)\n", mb, fps);
- write_bw_per_sec = MIN_BW_PER_SEC;
- }
-
- mfc_bw->peak = (unsigned int)peak_bw_per_sec;
- mfc_bw->read = (unsigned int)read_bw_per_sec;
- mfc_bw->write = (unsigned int)write_bw_per_sec;
-}
-#endif
-
-void s5p_mfc_qos_on(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_platdata *pdata = dev->pdata;
- struct s5p_mfc_qos *qos_table = pdata->qos_table;
- struct s5p_mfc_ctx *qos_ctx;
- unsigned long hw_mb = 0, total_mb = 0, total_fps = 0;
- unsigned int fw_time, sw_time;
- int i, found = 0, enc_found = 0;
- int start_qos_step;
-#ifdef CONFIG_EXYNOS_BTS
- struct bts_bw mfc_bw, mfc_bw_ctx;
-#endif
-
- if (perf_boost_mode) {
- mfc_info_ctx("[QoS][BOOST] skip control\n");
- return;
- }
-
- list_for_each_entry(qos_ctx, &dev->qos_queue, qos_list)
- if (qos_ctx == ctx)
- found = 1;
-
- if (!found)
- list_add_tail(&ctx->qos_list, &dev->qos_queue);
-
-#ifdef CONFIG_EXYNOS_BTS
- mfc_bw.peak = 0;
- mfc_bw.read = 0;
- mfc_bw.write = 0;
-#endif
- /* get the hw macroblock */
- list_for_each_entry(qos_ctx, &dev->qos_queue, qos_list) {
- if (OVER_UHD_ENC60(qos_ctx))
- enc_found = 1;
- hw_mb += mfc_qos_get_mb_per_second(qos_ctx);
- total_fps += (qos_ctx->framerate / 1000);
-#ifdef CONFIG_EXYNOS_BTS
- mfc_qos_get_bw_per_second(qos_ctx, &mfc_bw_ctx);
- mfc_bw.peak += mfc_bw_ctx.peak;
- mfc_bw.read += mfc_bw_ctx.read;
- mfc_bw.write += mfc_bw_ctx.write;
-#endif
- }
-
- start_qos_step = pdata->num_qos_steps;
- if (enc_found)
- start_qos_step = pdata->max_qos_steps;
-
- /* search the suitable qos table */
- for (i = start_qos_step - 1; i >= 0; i--) {
- fw_time = qos_table[i].time_fw;
- sw_time = (MFC_DRV_TIME + fw_time);
-
- if ((total_fps * sw_time) >= 1000000)
- total_mb = pdata->max_mb;
- else
- total_mb = ((1000000 * hw_mb) / (1000000 - (total_fps * sw_time)));
-
- mfc_debug(4, "[QoS] table[%d] fw_time: %dus, hw_mb: %ld, "
- "sw_time: %d, total_fps: %ld, total_mb: %ld\n",
- i, fw_time, hw_mb, sw_time, total_fps, total_mb);
-
- if ((total_mb > qos_table[i].threshold_mb) || (i == 0))
- break;
- }
-
- if (total_mb > pdata->max_mb)
- mfc_debug(4, "[QoS] overspec mb %ld > %d\n", total_mb, pdata->max_mb);
-
-#ifdef CONFIG_EXYNOS_BTS
- mfc_qos_set(ctx, &mfc_bw, i);
-#else
- mfc_qos_set(ctx, i);
-#endif
-}
-
-void s5p_mfc_qos_off(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_platdata *pdata = dev->pdata;
- struct s5p_mfc_qos *qos_table = pdata->qos_table;
- struct s5p_mfc_ctx *qos_ctx;
- unsigned long hw_mb = 0, total_mb = 0, total_fps = 0;
- unsigned int fw_time, sw_time;
- int i, found = 0, enc_found = 0;
- int start_qos_step;
-#ifdef CONFIG_EXYNOS_BTS
- struct bts_bw mfc_bw, mfc_bw_ctx;
-#endif
-
- if (perf_boost_mode) {
- mfc_info_ctx("[QoS][BOOST] skip control\n");
- return;
- }
-
- if (list_empty(&dev->qos_queue)) {
- if (atomic_read(&dev->qos_req_cur) != 0) {
- mfc_err_ctx("[QoS] MFC request count is wrong!\n");
- mfc_qos_operate(ctx, MFC_QOS_REMOVE, 0);
- }
- return;
- }
-
-#ifdef CONFIG_EXYNOS_BTS
- mfc_bw.peak = 0;
- mfc_bw.read = 0;
- mfc_bw.write = 0;
-#endif
- /* get the hw macroblock */
- list_for_each_entry(qos_ctx, &dev->qos_queue, qos_list) {
- if (qos_ctx == ctx) {
- found = 1;
- continue;
- }
-
- if (OVER_UHD_ENC60(qos_ctx))
- enc_found = 1;
- hw_mb += mfc_qos_get_mb_per_second(qos_ctx);
- total_fps += (qos_ctx->framerate / 1000);
-#ifdef CONFIG_EXYNOS_BTS
- mfc_qos_get_bw_per_second(qos_ctx, &mfc_bw_ctx);
- mfc_bw.peak += mfc_bw_ctx.peak;
- mfc_bw.read += mfc_bw_ctx.read;
- mfc_bw.write += mfc_bw_ctx.write;
-#endif
- }
-
- start_qos_step = pdata->num_qos_steps;
- if (enc_found)
- start_qos_step = pdata->max_qos_steps;
-
- /* search the suitable qos table */
- for (i = start_qos_step - 1; i >= 0; i--) {
- fw_time = qos_table[i].time_fw;
- sw_time = (MFC_DRV_TIME + fw_time);
-
- if ((total_fps * sw_time) >= 1000000)
- total_mb = pdata->max_mb;
- else
- total_mb = ((1000000 * hw_mb) / (1000000 - (total_fps * sw_time)));
-
- mfc_debug(4, "[QoS] table[%d] fw_time: %dus, hw_mb: %ld, "
- "sw_time: %d, total_fps: %ld, total_mb: %ld\n",
- i, fw_time, hw_mb, sw_time, total_fps, total_mb);
-
- if ((total_mb > qos_table[i].threshold_mb) || (total_mb == 0) || (i == 0))
- break;
- }
-
- if (total_mb > pdata->max_mb)
- mfc_debug(4, "[QoS] overspec mb %ld > %d\n", total_mb, pdata->max_mb);
-
- if (found)
- list_del(&ctx->qos_list);
-
- if (list_empty(&dev->qos_queue) || total_mb == 0)
- mfc_qos_operate(ctx, MFC_QOS_REMOVE, 0);
- else
-#ifdef CONFIG_EXYNOS_BTS
- mfc_qos_set(ctx, &mfc_bw, i);
-#else
- mfc_qos_set(ctx, i);
-#endif
-}
-#endif
-
-#define COL_FRAME_RATE 0
-#define COL_FRAME_INTERVAL 1
-
-#define MFC_MAX_INTERVAL (2 * USEC_PER_SEC)
-
-/*
- * A framerate table determines framerate by the interval(us) of each frame.
- * Framerate is not accurate, just rough value to seperate overload section.
- * Base line of each section are selected from middle value.
- * 40fps(25000us), 80fps(12500us), 144fps(6940us)
- * 205fps(4860us), 320fps(3125us)
- *
- * interval(us) | 0 3125 4860 6940 12500 25000 |
- * framerate | 480fps | 240fps | 180fps | 120fps | 60fps | 30fps |
- */
-static unsigned long framerate_table[][2] = {
- { 30000, 25000 },
- { 60000, 12500 },
- { 120000, 6940 },
- { 180000, 4860 },
- { 240000, 3125 },
- { 480000, 0 },
-};
-
-static inline unsigned long mfc_qos_timeval_diff(struct timeval *to,
- struct timeval *from)
-{
- return (to->tv_sec * USEC_PER_SEC + to->tv_usec)
- - (from->tv_sec * USEC_PER_SEC + from->tv_usec);
-}
-
-static unsigned long mfc_qos_get_framerate_by_interval(int interval)
-{
- unsigned long i;
-
- /* if the interval is too big (2sec), framerate set to 0 */
- if (interval > MFC_MAX_INTERVAL)
- return 0;
-
- for (i = 0; i < ARRAY_SIZE(framerate_table); i++) {
- if (interval > framerate_table[i][COL_FRAME_INTERVAL])
- return framerate_table[i][COL_FRAME_RATE];
- }
-
- return 0;
-}
-
-/* Return the minimum interval between previous and next entry */
-static int mfc_qos_get_interval(struct list_head *head, struct list_head *entry)
-{
- int prev_interval = MFC_MAX_INTERVAL, next_interval = MFC_MAX_INTERVAL;
- struct mfc_timestamp *prev_ts, *next_ts, *curr_ts;
-
- curr_ts = list_entry(entry, struct mfc_timestamp, list);
-
- if (entry->prev != head) {
- prev_ts = list_entry(entry->prev, struct mfc_timestamp, list);
- prev_interval = mfc_qos_timeval_diff(&curr_ts->timestamp, &prev_ts->timestamp);
- }
-
- if (entry->next != head) {
- next_ts = list_entry(entry->next, struct mfc_timestamp, list);
- next_interval = mfc_qos_timeval_diff(&next_ts->timestamp, &curr_ts->timestamp);
- }
-
- return (prev_interval < next_interval ? prev_interval : next_interval);
-}
-
-static int mfc_qos_add_timestamp(struct s5p_mfc_ctx *ctx,
- struct timeval *time, struct list_head *head)
-{
- int replace_entry = 0;
- struct mfc_timestamp *curr_ts = &ctx->ts_array[ctx->ts_count];
-
- if (ctx->ts_is_full) {
- /* Replace the entry if list of array[ts_count] is same as entry */
- if (&curr_ts->list == head)
- replace_entry = 1;
- else
- list_del(&curr_ts->list);
- }
-
- memcpy(&curr_ts->timestamp, time, sizeof(struct timeval));
- if (!replace_entry)
- list_add(&curr_ts->list, head);
- curr_ts->interval =
- mfc_qos_get_interval(&ctx->ts_list, &curr_ts->list);
- curr_ts->index = ctx->ts_count;
- ctx->ts_count++;
-
- if (ctx->ts_count == MFC_TIME_INDEX) {
- ctx->ts_is_full = 1;
- ctx->ts_count %= MFC_TIME_INDEX;
- }
-
- return 0;
-}
-
-static unsigned long mfc_qos_get_fps_by_timestamp(struct s5p_mfc_ctx *ctx, struct timeval *time)
-{
- struct mfc_timestamp *temp_ts;
- int found;
- int index = 0;
- int min_interval = MFC_MAX_INTERVAL;
- int time_diff;
- unsigned long max_framerate;
-
- if (debug_ts == 1) {
- /* Debug info */
- mfc_info_ctx("===================[TS]===================\n");
- mfc_info_ctx("[TS] New timestamp = %ld.%06ld, count = %d \n",
- time->tv_sec, time->tv_usec, ctx->ts_count);
- }
-
- if (IS_BUFFER_BATCH_MODE(ctx)) {
- if (debug_ts == 1)
- mfc_info_ctx("[BUFCON][TS] Keep framerate if buffer batch mode is used, %ldfps\n",
- ctx->framerate);
- return ctx->framerate;
- }
-
- if (list_empty(&ctx->ts_list)) {
- mfc_qos_add_timestamp(ctx, time, &ctx->ts_list);
- return mfc_qos_get_framerate_by_interval(0);
- } else {
- found = 0;
- list_for_each_entry_reverse(temp_ts, &ctx->ts_list, list) {
- time_diff = timeval_compare(time, &temp_ts->timestamp);
- if (time_diff == 0) {
- /* Do not add if same timestamp already exists */
- found = 1;
- break;
- } else if (time_diff > 0) {
- /* Add this after temp_ts */
- mfc_qos_add_timestamp(ctx, time, &temp_ts->list);
- found = 1;
- break;
- }
- }
-
- if (!found) /* Add this at first entry */
- mfc_qos_add_timestamp(ctx, time, &ctx->ts_list);
- }
-
- list_for_each_entry(temp_ts, &ctx->ts_list, list) {
- if (temp_ts->interval < min_interval)
- min_interval = temp_ts->interval;
- }
-
- max_framerate = mfc_qos_get_framerate_by_interval(min_interval);
-
- if (debug_ts == 1) {
- /* Debug info */
- index = 0;
- list_for_each_entry(temp_ts, &ctx->ts_list, list) {
- mfc_info_ctx("[TS] [%d] timestamp [i:%d]: %ld.%06ld\n",
- index, temp_ts->index,
- temp_ts->timestamp.tv_sec,
- temp_ts->timestamp.tv_usec);
- index++;
- }
- mfc_info_ctx("[TS] Min interval = %d, It is %ld fps\n",
- min_interval, max_framerate);
- } else if (debug_ts == 2) {
- mfc_info_ctx("[TS] Min interval = %d, It is %ld fps\n",
- min_interval, max_framerate);
- }
-
- if (!ctx->ts_is_full) {
- if (debug_ts == 1)
- mfc_info_ctx("[TS] ts doesn't full, keep %ld fps\n", ctx->framerate);
- return ctx->framerate;
- }
-
- return max_framerate;
-}
-
-void s5p_mfc_qos_update_framerate(struct s5p_mfc_ctx *ctx)
-{
- if (ctx->last_framerate != 0 && ctx->last_framerate != ctx->framerate) {
- mfc_debug(2, "[QoS] fps changed: %ld -> %ld, qos ratio: %d\n",
- ctx->framerate, ctx->last_framerate, ctx->qos_ratio);
- ctx->framerate = ctx->last_framerate;
- s5p_mfc_qos_on(ctx);
- }
-}
-
-void s5p_mfc_qos_update_last_framerate(struct s5p_mfc_ctx *ctx, u64 timestamp)
-{
- struct timeval time;
-
- time.tv_sec = timestamp / NSEC_PER_SEC;
- time.tv_usec = (timestamp - (time.tv_sec * NSEC_PER_SEC)) / NSEC_PER_USEC;
-
- ctx->last_framerate = mfc_qos_get_fps_by_timestamp(ctx, &time);
- if (ctx->last_framerate > MFC_MAX_FPS)
- ctx->last_framerate = MFC_MAX_FPS;
- ctx->last_framerate = (ctx->qos_ratio * ctx->last_framerate) / 100;
-}
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_qos.h
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __S5P_MFC_QOS_H
-#define __S5P_MFC_QOS_H __FILE__
-
-#include "s5p_mfc_common.h"
-
-#define MFC_MAX_FPS (480000)
-#define DEC_DEFAULT_FPS (240000)
-#define ENC_DEFAULT_FPS (240000)
-#define ENC_DEFAULT_CAM_CAPTURE_FPS (60000)
-
-#define MB_COUNT_PER_UHD_FRAME 32400
-#define MAX_FPS_PER_UHD_FRAME 120
-#define MIN_BW_PER_SEC 1
-
-#define MFC_DRV_TIME 500
-
-#define MFC_QOS_WEIGHT_3PLANE 80
-#define MFC_QOS_WEIGHT_OTHER_CODEC 25
-#define MFC_QOS_WEIGHT_10BIT 75
-#define MFC_QOS_WEIGHT_422_10INTRA 70
-#define MFC_QOS_WEIGHT_BFRAME 50
-#define MFC_QOS_WEIGHT_NUM_OF_REF 50
-#define MFC_QOS_WEIGHT_NUM_OF_TILE 75
-
-#ifdef CONFIG_MFC_USE_BUS_DEVFREQ
-void s5p_mfc_perf_boost_enable(struct s5p_mfc_dev *dev);
-void s5p_mfc_perf_boost_disable(struct s5p_mfc_dev *dev);
-void s5p_mfc_qos_on(struct s5p_mfc_ctx *ctx);
-void s5p_mfc_qos_off(struct s5p_mfc_ctx *ctx);
-#else
-#define s5p_mfc_perf_boost_enable(dev) do {} while (0)
-#define s5p_mfc_perf_boost_disable(dev) do {} while (0)
-#define s5p_mfc_qos_on(ctx) do {} while (0)
-#define s5p_mfc_qos_off(ctx) do {} while (0)
-#endif
-
-void s5p_mfc_qos_update_framerate(struct s5p_mfc_ctx *ctx);
-void s5p_mfc_qos_update_last_framerate(struct s5p_mfc_ctx *ctx, u64 timestamp);
-
-static inline void s5p_mfc_qos_reset_framerate(struct s5p_mfc_ctx *ctx)
-{
- if (ctx->type == MFCINST_DECODER)
- ctx->framerate = DEC_DEFAULT_FPS;
- else if (ctx->type == MFCINST_ENCODER)
- ctx->framerate = ENC_DEFAULT_FPS;
-}
-
-static inline void s5p_mfc_qos_reset_last_framerate(struct s5p_mfc_ctx *ctx)
-{
- ctx->last_framerate = 0;
-}
-
-static inline void s5p_mfc_qos_set_framerate(struct s5p_mfc_ctx *ctx, int rate)
-{
- ctx->framerate = rate;
-}
-
-static inline int s5p_mfc_qos_get_framerate(struct s5p_mfc_ctx *ctx)
-{
- return ctx->framerate;
-}
-
-#endif /* __S5P_MFC_QOS_H */
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_queue.c
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include "s5p_mfc_queue.h"
-
-#include "s5p_mfc_utils.h"
-#include "s5p_mfc_mem.h"
-
-void s5p_mfc_add_tail_buf(spinlock_t *plock, struct s5p_mfc_buf_queue *queue,
- struct s5p_mfc_buf *mfc_buf)
-{
- unsigned long flags;
-
- if (!mfc_buf) {
- mfc_err_dev("mfc_buf is NULL!\n");
- return;
- }
-
- spin_lock_irqsave(plock, flags);
-
- mfc_buf->used = 0;
- list_add_tail(&mfc_buf->list, &queue->head);
- queue->count++;
-
- spin_unlock_irqrestore(plock, flags);
-}
-
-int s5p_mfc_peek_buf_csd(spinlock_t *plock, struct s5p_mfc_buf_queue *queue)
-{
- unsigned long flags;
- int csd = -1;
- struct s5p_mfc_buf *mfc_buf = NULL;
-
- spin_lock_irqsave(plock, flags);
-
- if (list_empty(&queue->head)) {
- mfc_debug(2, "queue is empty\n");
- spin_unlock_irqrestore(plock, flags);
- return csd;
- }
-
- mfc_buf = list_entry(queue->head.next, struct s5p_mfc_buf, list);
-
- csd = mfc_buf->vb.reserved2 & FLAG_CSD ? 1 : 0;
-
- mfc_debug(2, "addr[0]: 0x%08llx\n", mfc_buf->addr[0][0]);
-
- spin_unlock_irqrestore(plock, flags);
- return csd;
-}
-
-struct s5p_mfc_buf *s5p_mfc_get_buf(spinlock_t *plock, struct s5p_mfc_buf_queue *queue,
- enum s5p_mfc_queue_used_type used)
-{
- unsigned long flags;
- struct s5p_mfc_buf *mfc_buf = NULL;
-
- spin_lock_irqsave(plock, flags);
-
- if (list_empty(&queue->head)) {
- mfc_debug(2, "queue is empty\n");
- spin_unlock_irqrestore(plock, flags);
- return NULL;
- }
-
- mfc_buf = list_entry(queue->head.next, struct s5p_mfc_buf, list);
-
- if ((used == MFC_BUF_RESET_USED) || (used == MFC_BUF_SET_USED))
- mfc_buf->used = used;
-
- mfc_debug(2, "addr[0]: 0x%08llx\n", mfc_buf->addr[0][0]);
-
- spin_unlock_irqrestore(plock, flags);
- return mfc_buf;
-}
-
-struct s5p_mfc_buf *s5p_mfc_get_del_buf(spinlock_t *plock, struct s5p_mfc_buf_queue *queue,
- enum s5p_mfc_queue_used_type used)
-{
- unsigned long flags;
- struct s5p_mfc_buf *mfc_buf = NULL;
-
- spin_lock_irqsave(plock, flags);
-
- if (list_empty(&queue->head)) {
- mfc_debug(2, "queue is empty\n");
- spin_unlock_irqrestore(plock, flags);
- return NULL;
- }
-
- mfc_buf = list_entry(queue->head.next, struct s5p_mfc_buf, list);
-
- if ((used == MFC_BUF_RESET_USED) || (used == MFC_BUF_SET_USED))
- mfc_buf->used = used;
-
- mfc_debug(2, "addr[0]: 0x%08llx\n", mfc_buf->addr[0][0]);
-
- list_del(&mfc_buf->list);
- queue->count--;
-
- spin_unlock_irqrestore(plock, flags);
- return mfc_buf;
-}
-
-struct s5p_mfc_buf *s5p_mfc_get_del_if_consumed(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf_queue *queue,
- unsigned long consumed, unsigned int min_bytes, int error, int *deleted)
-{
- unsigned long flags;
- struct s5p_mfc_buf *mfc_buf = NULL;
- struct s5p_mfc_dec *dec = ctx->dec_priv;
- unsigned long remained;
-
- spin_lock_irqsave(&ctx->buf_queue_lock, flags);
-
- if (list_empty(&queue->head)) {
- mfc_debug(2, "queue is empty\n");
- spin_unlock_irqrestore(&ctx->buf_queue_lock, flags);
- return NULL;
- }
-
- mfc_buf = list_entry(queue->head.next, struct s5p_mfc_buf, list);
-
- mfc_debug(2, "addr[0]: 0x%08llx\n", mfc_buf->addr[0][0]);
-
- if (dec->remained_size)
- remained = dec->remained_size - consumed;
- else
- remained = mfc_buf->vb.vb2_buf.planes[0].bytesused - consumed;
-
- mfc_debug(2, "[MULTIFRAME] Total Size: %d, consumed: %ld, remained: %ld\n",
- mfc_buf->vb.vb2_buf.planes[0].bytesused, consumed, remained);
-
- if ((consumed > 0) && (remained > min_bytes) && (error == 0) &&
- (mfc_buf->vb.vb2_buf.planes[0].bytesused > consumed)){
- /* do not delete from queue */
- *deleted = 0;
- } else {
- list_del(&mfc_buf->list);
- queue->count--;
-
- *deleted = 1;
- }
-
- spin_unlock_irqrestore(&ctx->buf_queue_lock, flags);
- return mfc_buf;
-}
-
-struct s5p_mfc_buf *s5p_mfc_get_move_buf(spinlock_t *plock,
- struct s5p_mfc_buf_queue *to_queue, struct s5p_mfc_buf_queue *from_queue,
- enum s5p_mfc_queue_used_type used, enum s5p_mfc_queue_top_type top)
-{
- unsigned long flags;
- struct s5p_mfc_buf *mfc_buf = NULL;
-
- spin_lock_irqsave(plock, flags);
-
- if (list_empty(&from_queue->head)) {
- mfc_debug(2, "from_queue is empty\n");
- spin_unlock_irqrestore(plock, flags);
- return NULL;
- }
-
- mfc_buf = list_entry(from_queue->head.next, struct s5p_mfc_buf, list);
-
- if ((used == MFC_BUF_RESET_USED) || (used == MFC_BUF_SET_USED))
- mfc_buf->used = used;
-
- mfc_debug(2, "addr[0]: 0x%08llx\n", mfc_buf->addr[0][0]);
-
- list_del(&mfc_buf->list);
- from_queue->count--;
-
- if (top == MFC_QUEUE_ADD_TOP)
- list_add(&mfc_buf->list, &to_queue->head);
- else
- list_add_tail(&mfc_buf->list, &to_queue->head);
-
- to_queue->count++;
-
- spin_unlock_irqrestore(plock, flags);
- return mfc_buf;
-}
-
-struct s5p_mfc_buf *s5p_mfc_get_move_buf_used(spinlock_t *plock,
- struct s5p_mfc_buf_queue *to_queue, struct s5p_mfc_buf_queue *from_queue)
-{
- unsigned long flags;
- struct s5p_mfc_buf *mfc_buf = NULL;
-
- spin_lock_irqsave(plock, flags);
-
- if (list_empty(&from_queue->head)) {
- mfc_debug(2, "from_queue is empty\n");
- spin_unlock_irqrestore(plock, flags);
- return NULL;
- }
-
- mfc_buf = list_entry(from_queue->head.next, struct s5p_mfc_buf, list);
-
- if (mfc_buf->used) {
- mfc_debug(2, "addr[0]: 0x%08llx\n", mfc_buf->addr[0][0]);
-
- list_del(&mfc_buf->list);
- from_queue->count--;
-
- list_add_tail(&mfc_buf->list, &to_queue->head);
- to_queue->count++;
-
- spin_unlock_irqrestore(plock, flags);
- return mfc_buf;
- } else {
- spin_unlock_irqrestore(plock, flags);
- return NULL;
- }
-}
-
-struct s5p_mfc_buf *s5p_mfc_get_move_buf_addr(spinlock_t *plock,
- struct s5p_mfc_buf_queue *to_queue, struct s5p_mfc_buf_queue *from_queue,
- dma_addr_t addr)
-{
- unsigned long flags;
- struct s5p_mfc_buf *mfc_buf = NULL;
-
- spin_lock_irqsave(plock, flags);
-
- if (list_empty(&from_queue->head)) {
- mfc_debug(2, "[DPB] from_queue is empty\n");
- spin_unlock_irqrestore(plock, flags);
- return NULL;
- }
-
- mfc_buf = list_entry(from_queue->head.next, struct s5p_mfc_buf, list);
-
- if (mfc_buf->addr[0][0] == addr) {
- mfc_debug(2, "[DPB] addr[0]: 0x%08llx\n", mfc_buf->addr[0][0]);
-
- list_del(&mfc_buf->list);
- from_queue->count--;
-
- list_add_tail(&mfc_buf->list, &to_queue->head);
- to_queue->count++;
-
- spin_unlock_irqrestore(plock, flags);
- return mfc_buf;
- } else {
- spin_unlock_irqrestore(plock, flags);
- return NULL;
- }
-}
-
-struct s5p_mfc_buf *s5p_mfc_find_first_buf(spinlock_t *plock, struct s5p_mfc_buf_queue *queue,
- dma_addr_t addr)
-{
- unsigned long flags;
- struct s5p_mfc_buf *mfc_buf = NULL;
- dma_addr_t mb_addr;
- int i;
-
- spin_lock_irqsave(plock, flags);
-
- if (list_empty(&queue->head)) {
- mfc_debug(2, "queue is empty\n");
- spin_unlock_irqrestore(plock, flags);
- return mfc_buf;
- }
-
- mfc_debug(4, "Looking for this address: 0x%08llx\n", addr);
- mfc_buf = list_entry(queue->head.next, struct s5p_mfc_buf, list);
- if (mfc_buf->num_valid_bufs > 0) {
- for (i = 0; i < mfc_buf->num_valid_bufs; i++) {
- mb_addr = mfc_buf->addr[i][0];
- mfc_debug(4, "[BUFCON] batch[%d] addr[0]: 0x%08llx\n", i, mb_addr);
- if (addr == mb_addr) {
- spin_unlock_irqrestore(plock, flags);
- return mfc_buf;
- }
- }
- } else {
- mb_addr = mfc_buf->addr[0][0];
- mfc_debug(4, "addr[0]: 0x%08llx\n", mb_addr);
-
- if (addr == mb_addr) {
- spin_unlock_irqrestore(plock, flags);
- return mfc_buf;
- }
- }
-
- spin_unlock_irqrestore(plock, flags);
- return NULL;
-}
-
-struct s5p_mfc_buf *s5p_mfc_find_buf(spinlock_t *plock, struct s5p_mfc_buf_queue *queue,
- dma_addr_t addr)
-{
- unsigned long flags;
- struct s5p_mfc_buf *mfc_buf = NULL;
- dma_addr_t mb_addr;
- int i;
-
- spin_lock_irqsave(plock, flags);
-
- mfc_debug(4, "Looking for this address: 0x%08llx\n", addr);
- list_for_each_entry(mfc_buf, &queue->head, list) {
- if (mfc_buf->num_valid_bufs > 0) {
- for (i = 0; i < mfc_buf->num_valid_bufs; i++) {
- mb_addr = mfc_buf->addr[i][0];
- mfc_debug(4, "[BUFCON] batch[%d] addr[0]: 0x%08llx\n", i, mb_addr);
- if (addr == mb_addr) {
- spin_unlock_irqrestore(plock, flags);
- return mfc_buf;
- }
- }
- } else {
- mb_addr = mfc_buf->addr[0][0];
- mfc_debug(4, "addr[0]: 0x%08llx\n", mb_addr);
-
- if (addr == mb_addr) {
- spin_unlock_irqrestore(plock, flags);
- return mfc_buf;
- }
- }
- }
-
- spin_unlock_irqrestore(plock, flags);
- return NULL;
-}
-
-struct s5p_mfc_buf *s5p_mfc_find_del_buf(spinlock_t *plock, struct s5p_mfc_buf_queue *queue,
- dma_addr_t addr)
-{
- unsigned long flags;
- struct s5p_mfc_buf *mfc_buf = NULL;
- dma_addr_t mb_addr;
- int found = 0, i;
-
- spin_lock_irqsave(plock, flags);
-
- mfc_debug(4, "Looking for this address: 0x%08llx\n", addr);
- list_for_each_entry(mfc_buf, &queue->head, list) {
- if (mfc_buf->num_valid_bufs > 0) {
- for (i = 0; i < mfc_buf->num_valid_bufs; i++) {
- mb_addr = mfc_buf->addr[i][0];
- mfc_debug(4, "batch buf[%d] plane[0] addr: 0x%08llx\n", i, mb_addr);
-
- if (addr == mb_addr) {
- found = 1;
- break;
- }
- }
-
- if (found)
- break;
- } else {
- mb_addr = mfc_buf->addr[0][0];
- mfc_debug(4, "addr[0]: 0x%08llx\n", mb_addr);
-
- if (addr == mb_addr) {
- found = 1;
- break;
- }
- }
- }
-
- if (found == 1) {
- list_del(&mfc_buf->list);
- queue->count--;
-
- spin_unlock_irqrestore(plock, flags);
- return mfc_buf;
- } else {
- spin_unlock_irqrestore(plock, flags);
- return NULL;
- }
-}
-
-struct s5p_mfc_buf *s5p_mfc_find_move_buf(spinlock_t *plock,
- struct s5p_mfc_buf_queue *to_queue, struct s5p_mfc_buf_queue *from_queue,
- dma_addr_t addr, unsigned int released_flag)
-{
- unsigned long flags;
- struct s5p_mfc_buf *mfc_buf = NULL;
- dma_addr_t mb_addr;
- int found = 0;
-
- spin_lock_irqsave(plock, flags);
-
- mfc_debug(4, "[DPB] Looking for this address: 0x%08llx\n", addr);
- list_for_each_entry(mfc_buf, &from_queue->head, list) {
- mb_addr = mfc_buf->addr[0][0];
- mfc_debug(4, "[DPB] addr[0]: 0x%08llx\n", mb_addr);
-
- if (addr == mb_addr) {
- found = 1;
- break;
- }
- }
-
- if (found == 1) {
- if (released_flag & (1 << mfc_buf->vb.vb2_buf.index)) {
- list_del(&mfc_buf->list);
- from_queue->count--;
-
- list_add_tail(&mfc_buf->list, &to_queue->head);
- to_queue->count++;
- }
-
- spin_unlock_irqrestore(plock, flags);
- return mfc_buf;
- } else {
- spin_unlock_irqrestore(plock, flags);
- return NULL;
- }
-}
-
-struct s5p_mfc_buf *s5p_mfc_find_move_buf_used(spinlock_t *plock,
- struct s5p_mfc_buf_queue *to_queue, struct s5p_mfc_buf_queue *from_queue,
- dma_addr_t addr)
-{
- unsigned long flags;
- struct s5p_mfc_buf *mfc_buf = NULL;
- dma_addr_t mb_addr;
- int found = 0;
-
- spin_lock_irqsave(plock, flags);
-
- mfc_debug(4, "[DPB] Looking for this address: 0x%08llx\n", addr);
- list_for_each_entry(mfc_buf, &from_queue->head, list) {
- mb_addr = mfc_buf->addr[0][0];
- mfc_debug(4, "[DPB] addr[0]: 0x%08llx, used: %d\n",
- mb_addr, mfc_buf->used);
-
- if ((addr == mb_addr) && (mfc_buf->used == 1)) {
- found = 1;
- break;
- }
- }
-
- if (found == 1) {
- list_del(&mfc_buf->list);
- from_queue->count--;
-
- list_add_tail(&mfc_buf->list, &to_queue->head);
- to_queue->count++;
-
- spin_unlock_irqrestore(plock, flags);
- return mfc_buf;
- } else {
- spin_unlock_irqrestore(plock, flags);
- return NULL;
- }
-}
-
-void s5p_mfc_move_first_buf_used(spinlock_t *plock, struct s5p_mfc_buf_queue *to_queue,
- struct s5p_mfc_buf_queue *from_queue, enum s5p_mfc_queue_top_type top)
-{
- unsigned long flags;
- struct s5p_mfc_buf *mfc_buf = NULL;
-
- spin_lock_irqsave(plock, flags);
-
- if (list_empty(&from_queue->head)) {
- mfc_err_dev("from_queue is empty\n");
- spin_unlock_irqrestore(plock, flags);
- return;
- }
- mfc_buf = list_entry(from_queue->head.next, struct s5p_mfc_buf, list);
-
- if (mfc_buf->used) {
- list_del(&mfc_buf->list);
- from_queue->count--;
-
- if (top == MFC_QUEUE_ADD_TOP)
- list_add(&mfc_buf->list, &to_queue->head);
- else
- list_add_tail(&mfc_buf->list, &to_queue->head);
-
- to_queue->count++;
- }
-
- spin_unlock_irqrestore(plock, flags);
-}
-
-void s5p_mfc_move_all_bufs(spinlock_t *plock, struct s5p_mfc_buf_queue *to_queue,
- struct s5p_mfc_buf_queue *from_queue, enum s5p_mfc_queue_top_type top)
-{
- unsigned long flags;
- struct s5p_mfc_buf *mfc_buf = NULL;
-
- spin_lock_irqsave(plock, flags);
-
- if (top == MFC_QUEUE_ADD_TOP) {
- while (!list_empty(&from_queue->head)) {
- mfc_buf = list_entry(from_queue->head.prev, struct s5p_mfc_buf, list);
-
- list_del(&mfc_buf->list);
- from_queue->count--;
-
- list_add(&mfc_buf->list, &to_queue->head);
- to_queue->count++;
- }
- } else {
- while (!list_empty(&from_queue->head)) {
- mfc_buf = list_entry(from_queue->head.next, struct s5p_mfc_buf, list);
-
- list_del(&mfc_buf->list);
- from_queue->count--;
-
- list_add_tail(&mfc_buf->list, &to_queue->head);
- to_queue->count++;
- }
- }
-
- INIT_LIST_HEAD(&from_queue->head);
- from_queue->count = 0;
-
- spin_unlock_irqrestore(plock, flags);
-}
-
-void s5p_mfc_cleanup_queue(spinlock_t *plock, struct s5p_mfc_buf_queue *queue)
-{
- unsigned long flags;
- struct s5p_mfc_buf *mfc_buf = NULL;
- int i;
-
- spin_lock_irqsave(plock, flags);
-
- while (!list_empty(&queue->head)) {
- mfc_buf = list_entry(queue->head.next, struct s5p_mfc_buf, list);
-
- for (i = 0; i < mfc_buf->vb.vb2_buf.num_planes; i++)
- vb2_set_plane_payload(&mfc_buf->vb.vb2_buf, i, 0);
- vb2_buffer_done(&mfc_buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
- list_del(&mfc_buf->list);
- queue->count--;
- }
-
- INIT_LIST_HEAD(&queue->head);
- queue->count = 0;
-
- spin_unlock_irqrestore(plock, flags);
-}
-
-static void mfc_cleanup_batch_queue(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf_queue *queue)
-{
- unsigned long flags;
- struct s5p_mfc_buf *mfc_buf = NULL;
- int i;
-
- spin_lock_irqsave(&ctx->buf_queue_lock, flags);
-
- while (!list_empty(&queue->head)) {
- mfc_buf = list_entry(queue->head.next, struct s5p_mfc_buf, list);
-
- for (i = 0; i < mfc_buf->vb.vb2_buf.num_planes; i++) {
- s5p_mfc_bufcon_put_daddr(ctx, mfc_buf, i);
- vb2_set_plane_payload(&mfc_buf->vb.vb2_buf, i, 0);
- }
- vb2_buffer_done(&mfc_buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
- list_del(&mfc_buf->list);
- queue->count--;
- }
-
- INIT_LIST_HEAD(&queue->head);
- queue->count = 0;
- ctx->batch_mode = 0;
-
- spin_unlock_irqrestore(&ctx->buf_queue_lock, flags);
-}
-
-struct s5p_mfc_buf *mfc_find_buf_index(spinlock_t *plock, struct s5p_mfc_buf_queue *queue,
- int index)
-{
- unsigned long flags;
- struct s5p_mfc_buf *mfc_buf = NULL;
- int buf_index;
-
- spin_lock_irqsave(plock, flags);
-
- mfc_debug(4, "[DPB] Looking for index: %d\n", index);
- list_for_each_entry(mfc_buf, &queue->head, list) {
- buf_index = mfc_buf->vb.vb2_buf.index;
-
- if (index == buf_index) {
- mfc_debug(2, "[DPB] Found index: %d\n", buf_index);
- spin_unlock_irqrestore(plock, flags);
- return mfc_buf;
- }
- }
-
- spin_unlock_irqrestore(plock, flags);
- return NULL;
-}
-
-/*
- * Check released and enqueued buffers. (dst queue)
- * Check and move reuse buffers. (ref -> dst queue)
- */
-static void mfc_check_ref_frame(spinlock_t *plock, struct s5p_mfc_buf_queue *dst_queue,
- struct s5p_mfc_buf_queue *ref_queue,
- struct s5p_mfc_ctx *ctx, int ref_index)
-{
- unsigned long flags;
- struct s5p_mfc_dec *dec = ctx->dec_priv;
- struct s5p_mfc_buf *ref_mb, *tmp_mb;
- int index;
- int found = 0;
-
- spin_lock_irqsave(plock, flags);
-
- /* reuse buffers : error frame, decoding only frame (ref -> dst queue) */
- list_for_each_entry_safe(ref_mb, tmp_mb, &ref_queue->head, list) {
- index = ref_mb->vb.vb2_buf.index;
- if (index == ref_index) {
- list_del(&ref_mb->list);
- ref_queue->count--;
-
- list_add_tail(&ref_mb->list, &dst_queue->head);
- dst_queue->count++;
-
- dec->assigned_fd[index] =
- ref_mb->vb.vb2_buf.planes[0].m.fd;
- clear_bit(index, &dec->available_dpb);
- mfc_debug(2, "[DPB] Move buffer[%d], fd[%d] to dst queue\n",
- index, dec->assigned_fd[index]);
- found = 1;
- break;
- }
- }
-
- /* released and enqueued buffers (dst queue) */
- if (!found) {
- list_for_each_entry_safe(ref_mb, tmp_mb, &dst_queue->head, list) {
- index = ref_mb->vb.vb2_buf.index;
- if (index == ref_index) {
- dec->assigned_fd[index] =
- ref_mb->vb.vb2_buf.planes[0].m.fd;
- clear_bit(index, &dec->available_dpb);
- mfc_debug(2, "[DPB] re-assigned buffer[%d], fd[%d]\n",
- index, dec->assigned_fd[index]);
- break;
- }
- }
- }
-
- spin_unlock_irqrestore(plock, flags);
-}
-
-/* Process the released reference information */
-void s5p_mfc_handle_released_info(struct s5p_mfc_ctx *ctx,
- unsigned int released_flag, int index)
-{
- struct s5p_mfc_dec *dec;
- struct dec_dpb_ref_info *refBuf;
- int t, ncount = 0;
-
- dec = ctx->dec_priv;
- if (!dec) {
- mfc_err_dev("[DPB] no decoder context to run\n");
- return;
- }
- refBuf = &dec->ref_info[index];
-
- if (dec->dec_only_release_flag) {
- for (t = 0; t < MFC_MAX_DPBS; t++) {
- if (dec->dec_only_release_flag & (1 << t)) {
- mfc_debug(2, "[DPB] Release FD[%d] = %03d (already released in dec only)\n",
- t, dec->assigned_fd[t]);
- refBuf->dpb[ncount].fd[0] = dec->assigned_fd[t];
- ncount++;
- dec->dec_only_release_flag &= ~(1 << t);
- }
- }
- }
-
- if (released_flag) {
- for (t = 0; t < MFC_MAX_DPBS; t++) {
- if (released_flag & (1 << t)) {
- if (dec->err_reuse_flag & (1 << t)) {
- /* reuse buffer with error : do not update released info */
- mfc_debug(2, "[DPB] Released, but reuse(error frame). FD[%d] = %03d\n",
- t, dec->assigned_fd[t]);
- dec->err_reuse_flag &= ~(1 << t);
- } else if ((t != index) &&
- mfc_find_buf_index(&ctx->buf_queue_lock, &ctx->ref_buf_queue, t)) {
- /* decoding only frame: do not update released info */
- mfc_debug(2, "[DPB] Released, but reuse(decoding only). FD[%d] = %03d\n",
- t, dec->assigned_fd[t]);
- } else {
- /* displayed and released frame */
- mfc_debug(2, "[DPB] Release FD[%d] = %03d\n",
- t, dec->assigned_fd[t]);
- refBuf->dpb[ncount].fd[0] = dec->assigned_fd[t];
- ncount++;
- }
- dec->assigned_fd[t] = MFC_INFO_INIT_FD;
- mfc_check_ref_frame(&ctx->buf_queue_lock, &ctx->dst_buf_queue,
- &ctx->ref_buf_queue, ctx, t);
- }
- }
- }
-
- if (ncount != MFC_MAX_DPBS)
- refBuf->dpb[ncount].fd[0] = MFC_INFO_INIT_FD;
-}
-
-struct s5p_mfc_buf *s5p_mfc_move_reuse_buffer(struct s5p_mfc_ctx *ctx, int release_index)
-{
- struct s5p_mfc_dec *dec = ctx->dec_priv;
- struct s5p_mfc_buf_queue *dst_queue = &ctx->dst_buf_queue;
- struct s5p_mfc_buf_queue *ref_queue = &ctx->ref_buf_queue;
- struct s5p_mfc_buf *ref_mb, *tmp_mb;
- spinlock_t *plock = &ctx->buf_queue_lock;
- unsigned long flags;
- int index;
-
- spin_lock_irqsave(plock, flags);
-
- list_for_each_entry_safe(ref_mb, tmp_mb, &ref_queue->head, list) {
- index = ref_mb->vb.vb2_buf.index;
- if (index == release_index) {
- s5p_mfc_raw_unprotect(ctx, ref_mb, index);
-
- ref_mb->used = 0;
-
- list_del(&ref_mb->list);
- ref_queue->count--;
-
- list_add_tail(&ref_mb->list, &dst_queue->head);
- dst_queue->count++;
-
- clear_bit(index, &dec->available_dpb);
- mfc_debug(2, "[DPB] buffer[%d] is moved to dst queue for reuse\n", index);
-
- spin_unlock_irqrestore(plock, flags);
- return ref_mb;
- }
- }
-
- spin_unlock_irqrestore(plock, flags);
- return NULL;
-}
-
-void s5p_mfc_cleanup_enc_src_queue(struct s5p_mfc_ctx *ctx)
-{
- unsigned long flags;
- struct s5p_mfc_buf *src_mb, *tmp_mb;
- int i;
-
- if (ctx->is_drm && ctx->raw_protect_flag) {
- spin_lock_irqsave(&ctx->buf_queue_lock, flags);
-
- mfc_debug(2, "raw_protect_flag(%#lx) will be released\n",
- ctx->raw_protect_flag);
-
- list_for_each_entry_safe(src_mb, tmp_mb, &ctx->src_buf_queue.head, list) {
- i = src_mb->vb.vb2_buf.index;
-
- s5p_mfc_raw_unprotect(ctx, src_mb, i);
-
- for (i = 0; i < src_mb->vb.vb2_buf.num_planes; i++) {
- s5p_mfc_bufcon_put_daddr(ctx, src_mb, i);
- vb2_set_plane_payload(&src_mb->vb.vb2_buf, i, 0);
- }
-
- vb2_buffer_done(&src_mb->vb.vb2_buf, VB2_BUF_STATE_ERROR);
- list_del(&src_mb->list);
- ctx->src_buf_queue.count--;
- }
-
- INIT_LIST_HEAD(&ctx->src_buf_queue.head);
- ctx->src_buf_queue.count = 0;
-
- spin_unlock_irqrestore(&ctx->buf_queue_lock, flags);
- } else {
- if (IS_BUFFER_BATCH_MODE(ctx))
- mfc_cleanup_batch_queue(ctx, &ctx->src_buf_queue);
- else
- s5p_mfc_cleanup_queue(&ctx->buf_queue_lock, &ctx->src_buf_queue);
- }
-}
-
-
-void s5p_mfc_cleanup_enc_dst_queue(struct s5p_mfc_ctx *ctx)
-{
- unsigned long flags;
- struct s5p_mfc_buf *dst_mb, *tmp_mb;
- int i;
-
- if (ctx->is_drm && ctx->stream_protect_flag) {
- spin_lock_irqsave(&ctx->buf_queue_lock, flags);
-
- mfc_debug(2, "stream_protect_flag(%#lx) will be released\n",
- ctx->stream_protect_flag);
-
- list_for_each_entry_safe(dst_mb, tmp_mb, &ctx->dst_buf_queue.head, list) {
- i = dst_mb->vb.vb2_buf.index;
-
- s5p_mfc_stream_unprotect(ctx, dst_mb, i);
-
- for (i = 0; i < dst_mb->vb.vb2_buf.num_planes; i++)
- vb2_set_plane_payload(&dst_mb->vb.vb2_buf, i, 0);
- vb2_buffer_done(&dst_mb->vb.vb2_buf, VB2_BUF_STATE_ERROR);
- list_del(&dst_mb->list);
- ctx->dst_buf_queue.count--;
- }
-
- INIT_LIST_HEAD(&ctx->dst_buf_queue.head);
- ctx->dst_buf_queue.count = 0;
-
- spin_unlock_irqrestore(&ctx->buf_queue_lock, flags);
- } else {
- s5p_mfc_cleanup_queue(&ctx->buf_queue_lock, &ctx->dst_buf_queue);
- }
-}
-
-/* Check all buffers are referenced or not */
-struct s5p_mfc_buf *mfc_check_full_refered_dpb(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dec *dec = NULL;
- struct s5p_mfc_buf *mfc_buf = NULL;
- int sum_dpb;
-
- dec = ctx->dec_priv;
- if (!dec) {
- mfc_err_dev("[DPB] no decoder context to run\n");
- return NULL;
- }
-
- sum_dpb = ctx->dst_buf_queue.count + ctx->ref_buf_queue.count;
-
- if ((ctx->dst_buf_queue.count > 1) && (sum_dpb >= (ctx->dpb_count + 5))) {
- if (list_empty(&ctx->dst_buf_queue.head)) {
- mfc_err_ctx("[DPB] dst_buf_queue is empty\n");
- return NULL;
- }
- mfc_debug(3, "[DPB] We should use this buffer\n");
- mfc_buf = list_entry(ctx->dst_buf_queue.head.next,
- struct s5p_mfc_buf, list);
- } else if ((ctx->dst_buf_queue.count == 0)
- && ((ctx->ref_buf_queue.count) == (ctx->dpb_count + 5))) {
- if (list_empty(&ctx->ref_buf_queue.head)) {
- mfc_err_ctx("[DPB] ref_buf_queue is empty\n");
- return NULL;
- }
- mfc_debug(3, "[DPB] All buffers are referenced\n");
- mfc_buf = list_entry(ctx->ref_buf_queue.head.next,
- struct s5p_mfc_buf, list);
- } else {
- mfc_debug(3, "[DPB] waiting for dst buffer, ref = %d, dst = %d\n",
- ctx->ref_buf_queue.count, ctx->dst_buf_queue.count);
- ctx->clear_work_bit = 1;
- }
-
- if (mfc_buf)
- mfc_buf->used = 1;
-
- return mfc_buf;
-}
-
-/* Try to search non-referenced DPB on dst-queue */
-struct s5p_mfc_buf *s5p_mfc_search_for_dpb(struct s5p_mfc_ctx *ctx, unsigned int dynamic_used)
-{
- unsigned long flags;
- struct s5p_mfc_buf *mfc_buf = NULL;
-
- spin_lock_irqsave(&ctx->buf_queue_lock, flags);
-
- mfc_debug(2, "[DPB] Try to find non-referenced DPB. dynamic_used: 0x%x\n", dynamic_used);
- list_for_each_entry(mfc_buf, &ctx->dst_buf_queue.head, list) {
- if ((dynamic_used & (1 << mfc_buf->vb.vb2_buf.index)) == 0) {
- mfc_buf->used = 1;
- spin_unlock_irqrestore(&ctx->buf_queue_lock, flags);
- return mfc_buf;
- }
- }
-
- mfc_buf = mfc_check_full_refered_dpb(ctx);
-
- spin_unlock_irqrestore(&ctx->buf_queue_lock, flags);
-
- return mfc_buf;
-}
-
-struct s5p_mfc_buf *s5p_mfc_search_move_dpb_nal_q(struct s5p_mfc_ctx *ctx, unsigned int dynamic_used)
-{
- unsigned long flags;
- struct s5p_mfc_buf *mfc_buf = NULL;
- struct s5p_mfc_dec *dec = NULL;
-
- dec = ctx->dec_priv;
- if (!dec) {
- mfc_err_dev("no mfc decoder to run\n");
- return mfc_buf;
- }
-
- spin_lock_irqsave(&ctx->buf_queue_lock, flags);
-
- mfc_debug(2, "[NALQ][DPB] Try to find non-referenced DPB. dynamic_used: 0x%x\n", dynamic_used);
- list_for_each_entry(mfc_buf, &ctx->dst_buf_queue.head, list) {
- if ((dynamic_used & (1 << mfc_buf->vb.vb2_buf.index)) == 0) {
- mfc_buf->used = 1;
-
- list_del(&mfc_buf->list);
- ctx->dst_buf_queue.count--;
-
- list_add_tail(&mfc_buf->list, &ctx->dst_buf_nal_queue.head);
- ctx->dst_buf_nal_queue.count++;
-
- spin_unlock_irqrestore(&ctx->buf_queue_lock, flags);
- return mfc_buf;
- }
- }
-
- mfc_buf = mfc_check_full_refered_dpb(ctx);
-
- if (mfc_buf) {
- mfc_debug(2, "[NALQ][DPB] DPB is full. stop NAL-Q if started\n");
- dec->is_dpb_full = 1;
- }
-
- spin_unlock_irqrestore(&ctx->buf_queue_lock, flags);
-
- return mfc_buf;
-}
-
-/* Add dst buffer in dst_buf_queue */
-void s5p_mfc_store_dpb(struct s5p_mfc_ctx *ctx, struct vb2_buffer *vb)
-{
- unsigned long flags;
- struct s5p_mfc_dec *dec;
- struct s5p_mfc_buf *mfc_buf;
- int index;
-
- if (!ctx) {
- mfc_err_dev("[DPB] no mfc context to run\n");
- return;
- }
-
- dec = ctx->dec_priv;
- if (!dec) {
- mfc_err_dev("[DPB] no mfc decoder to run\n");
- return;
- }
-
- spin_lock_irqsave(&ctx->buf_queue_lock, flags);
-
- mfc_buf = vb_to_mfc_buf(vb);
- mfc_buf->used = 0;
- index = vb->index;
-
- dec->assigned_fd[index] = vb->planes[0].m.fd;
- mfc_debug(2, "[DPB] Assigned FD[%d] = %d (%s)\n", index, dec->assigned_fd[index],
- (dec->dynamic_used & (1 << index) ? "used" : "non-used"));
-
- list_add_tail(&mfc_buf->list, &ctx->dst_buf_queue.head);
- ctx->dst_buf_queue.count++;
-
- spin_unlock_irqrestore(&ctx->buf_queue_lock, flags);
-}
-
-void s5p_mfc_cleanup_nal_queue(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dec *dec = ctx->dec_priv;
- struct s5p_mfc_buf *src_mb, *dst_mb;
- unsigned long flags;
- unsigned int index;
-
- spin_lock_irqsave(&ctx->buf_queue_lock, flags);
-
- while (!list_empty(&ctx->src_buf_nal_queue.head)) {
- src_mb = list_entry(ctx->src_buf_nal_queue.head.prev, struct s5p_mfc_buf, list);
-
- index = src_mb->vb.vb2_buf.index;
- call_cop(ctx, recover_buf_ctrls_nal_q, ctx, &ctx->src_ctrls[index]);
-
- src_mb->used = 0;
-
- /* If it is not buffer batch mode, index is always zero */
- if (src_mb->next_index > src_mb->done_index) {
- mfc_debug(2, "[NALQ][BUFCON] batch buf next index[%d] recover to [%d]\n",
- src_mb->next_index, src_mb->done_index);
- src_mb->next_index = src_mb->done_index;
- }
-
- list_del(&src_mb->list);
- ctx->src_buf_nal_queue.count--;
-
- list_add(&src_mb->list, &ctx->src_buf_queue.head);
- ctx->src_buf_queue.count++;
-
- mfc_debug(2, "[NALQ] cleanup, src_buf_nal_queue -> src_buf_queue, index:%d\n",
- src_mb->vb.vb2_buf.index);
- }
-
- while (!list_empty(&ctx->dst_buf_nal_queue.head)) {
- dst_mb = list_entry(ctx->dst_buf_nal_queue.head.prev, struct s5p_mfc_buf, list);
-
- dst_mb->used = 0;
- if (ctx->type == MFCINST_DECODER)
- clear_bit(dst_mb->vb.vb2_buf.index, &dec->available_dpb);
- list_del(&dst_mb->list);
- ctx->dst_buf_nal_queue.count--;
-
- list_add(&dst_mb->list, &ctx->dst_buf_queue.head);
- ctx->dst_buf_queue.count++;
-
- mfc_debug(2, "[NALQ] cleanup, dst_buf_nal_queue -> dst_buf_queue, index:%d\n",
- dst_mb->vb.vb2_buf.index);
- }
-
- spin_unlock_irqrestore(&ctx->buf_queue_lock, flags);
-}
-
-int s5p_mfc_is_last_frame(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_buf *src_mb;
- struct s5p_mfc_dev *dev;
- unsigned long flags;
-
- mfc_debug_enter();
-
- if (!ctx) {
- mfc_err_dev("no mfc context to run\n");
- return -EINVAL;
- }
-
- dev = ctx->dev;
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
-
- spin_lock_irqsave(&ctx->buf_queue_lock, flags);
-
- if (list_empty(&ctx->src_buf_queue.head)) {
- mfc_debug(2, "src_buf_queue is empty\n");
- spin_unlock_irqrestore(&ctx->buf_queue_lock, flags);
- return -EINVAL;
- }
-
- src_mb = list_entry(ctx->src_buf_queue.head.next, struct s5p_mfc_buf, list);
-
- mfc_debug(4, "addr[0]: 0x%08llx\n", src_mb->addr[0][0]);
-
- if (src_mb->vb.reserved2 & FLAG_LAST_FRAME) {
- mfc_debug(2, "last frame!\n");
- spin_unlock_irqrestore(&ctx->buf_queue_lock, flags);
- return 1;
- }
-
- mfc_debug(4, "not last frame!\n");
- spin_unlock_irqrestore(&ctx->buf_queue_lock, flags);
-
- mfc_debug_leave();
-
- return 0;
-}
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_queue.h
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __S5P_MFC_QUEUE_H
-#define __S5P_MFC_QUEUE_H __FILE__
-
-#include "s5p_mfc_common.h"
-
-/**
- * enum s5p_mfc_queue_used_type
- */
-enum s5p_mfc_queue_used_type {
- MFC_BUF_NO_TOUCH_USED = -1,
- MFC_BUF_RESET_USED = 0,
- MFC_BUF_SET_USED = 1,
-};
-
-/**
- * enum s5p_mfc_queue_top_type
- */
-enum s5p_mfc_queue_top_type {
- MFC_QUEUE_ADD_BOTTOM = 0,
- MFC_QUEUE_ADD_TOP = 1,
-};
-
-static inline unsigned int s5p_mfc_get_queue_count(spinlock_t *plock, struct s5p_mfc_buf_queue *queue)
-{
- unsigned long flags;
- unsigned int ret = 0;
-
- spin_lock_irqsave(plock, flags);
- ret = queue->count;
- spin_unlock_irqrestore(plock, flags);
-
- return ret;
-}
-
-static inline int s5p_mfc_is_queue_count_same(spinlock_t *plock, struct s5p_mfc_buf_queue *queue,
- unsigned int value)
-{
- unsigned long flags;
- int ret = 0;
-
- spin_lock_irqsave(plock, flags);
- if (queue->count == value)
- ret = 1;
- spin_unlock_irqrestore(plock, flags);
-
- return ret;
-}
-
-static inline int s5p_mfc_is_queue_count_greater(spinlock_t *plock, struct s5p_mfc_buf_queue *queue,
- unsigned int value)
-{
- unsigned long flags;
- int ret = 0;
-
- spin_lock_irqsave(plock, flags);
- if (queue->count > value)
- ret = 1;
- spin_unlock_irqrestore(plock, flags);
-
- return ret;
-}
-
-static inline int s5p_mfc_is_queue_count_smaller(spinlock_t *plock, struct s5p_mfc_buf_queue *queue,
- unsigned int value)
-{
- unsigned long flags;
- int ret = 0;
-
- spin_lock_irqsave(plock, flags);
- if (queue->count < value)
- ret = 1;
- spin_unlock_irqrestore(plock, flags);
-
- return ret;
-}
-
-static inline void s5p_mfc_init_queue(struct s5p_mfc_buf_queue *queue)
-{
- INIT_LIST_HEAD(&queue->head);
- queue->count = 0;
-}
-
-static inline void s5p_mfc_create_queue(struct s5p_mfc_buf_queue *queue)
-{
- s5p_mfc_init_queue(queue);
-}
-
-static inline void s5p_mfc_delete_queue(struct s5p_mfc_buf_queue *queue)
-{
- s5p_mfc_init_queue(queue);
-}
-
-void s5p_mfc_add_tail_buf(spinlock_t *plock, struct s5p_mfc_buf_queue *queue,
- struct s5p_mfc_buf *mfc_buf);
-
-int s5p_mfc_peek_buf_csd(spinlock_t *plock, struct s5p_mfc_buf_queue *queue);
-
-struct s5p_mfc_buf *s5p_mfc_get_buf(spinlock_t *plock, struct s5p_mfc_buf_queue *queue,
- enum s5p_mfc_queue_used_type used);
-struct s5p_mfc_buf *s5p_mfc_get_del_buf(spinlock_t *plock, struct s5p_mfc_buf_queue *queue,
- enum s5p_mfc_queue_used_type used);
-struct s5p_mfc_buf *s5p_mfc_get_del_if_consumed(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf_queue *queue,
- unsigned long consumed, unsigned int min_bytes, int err, int *deleted);
-struct s5p_mfc_buf *s5p_mfc_get_move_buf(spinlock_t *plock,
- struct s5p_mfc_buf_queue *to_queue, struct s5p_mfc_buf_queue *from_queue,
- enum s5p_mfc_queue_used_type used, enum s5p_mfc_queue_top_type top);
-struct s5p_mfc_buf *s5p_mfc_get_move_buf_used(spinlock_t *plock,
- struct s5p_mfc_buf_queue *to_queue, struct s5p_mfc_buf_queue *from_queue);
-struct s5p_mfc_buf *s5p_mfc_get_move_buf_addr(spinlock_t *plock,
- struct s5p_mfc_buf_queue *to_queue, struct s5p_mfc_buf_queue *from_queue,
- dma_addr_t addr);
-
-struct s5p_mfc_buf *s5p_mfc_find_first_buf(spinlock_t *plock, struct s5p_mfc_buf_queue *queue,
- dma_addr_t addr);
-struct s5p_mfc_buf *s5p_mfc_find_buf(spinlock_t *plock, struct s5p_mfc_buf_queue *queue,
- dma_addr_t addr);
-struct s5p_mfc_buf *s5p_mfc_find_del_buf(spinlock_t *plock, struct s5p_mfc_buf_queue *queue,
- dma_addr_t addr);
-struct s5p_mfc_buf *s5p_mfc_find_move_buf(spinlock_t *plock,
- struct s5p_mfc_buf_queue *to_queue, struct s5p_mfc_buf_queue *from_queue,
- dma_addr_t addr, unsigned int released_flag);
-struct s5p_mfc_buf *s5p_mfc_find_move_buf_used(spinlock_t *plock,
- struct s5p_mfc_buf_queue *to_queue, struct s5p_mfc_buf_queue *from_queue,
- dma_addr_t addr);
-
-void s5p_mfc_move_first_buf_used(spinlock_t *plock, struct s5p_mfc_buf_queue *to_queue,
- struct s5p_mfc_buf_queue *from_queue, enum s5p_mfc_queue_top_type top);
-void s5p_mfc_move_all_bufs(spinlock_t *plock, struct s5p_mfc_buf_queue *to_queue,
- struct s5p_mfc_buf_queue *from_queue, enum s5p_mfc_queue_top_type top);
-
-void s5p_mfc_cleanup_queue(spinlock_t *plock, struct s5p_mfc_buf_queue *queue);
-
-void s5p_mfc_handle_released_info(struct s5p_mfc_ctx *ctx,
- unsigned int released_flag, int index);
-
-struct s5p_mfc_buf *s5p_mfc_move_reuse_buffer(struct s5p_mfc_ctx *ctx, int release_index);
-
-void s5p_mfc_cleanup_enc_src_queue(struct s5p_mfc_ctx *ctx);
-void s5p_mfc_cleanup_enc_dst_queue(struct s5p_mfc_ctx *ctx);
-
-struct s5p_mfc_buf *s5p_mfc_search_for_dpb(struct s5p_mfc_ctx *ctx, unsigned int dynamic_used);
-struct s5p_mfc_buf *s5p_mfc_search_move_dpb_nal_q(struct s5p_mfc_ctx *ctx, unsigned int dynamic_used);
-void s5p_mfc_store_dpb(struct s5p_mfc_ctx *ctx, struct vb2_buffer *vb);
-
-void s5p_mfc_cleanup_nal_queue(struct s5p_mfc_ctx *ctx);
-int s5p_mfc_is_last_frame(struct s5p_mfc_ctx *ctx);
-
-#endif /* __S5P_MFC_QUEUE_H */
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_reg.c
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/delay.h>
-
-#include "s5p_mfc_reg.h"
-
-void s5p_mfc_dbg_enable(struct s5p_mfc_dev *dev)
-{
- mfc_debug(2, "MFC debug info enable\n");
- MFC_WRITEL(0x1, S5P_FIMV_DBG_INFO_ENABLE);
-}
-
-void s5p_mfc_dbg_disable(struct s5p_mfc_dev *dev)
-{
- mfc_debug(2, "MFC debug info disable\n");
- MFC_WRITEL(0x0, S5P_FIMV_DBG_INFO_ENABLE);
-}
-
-void s5p_mfc_dbg_set_addr(struct s5p_mfc_dev *dev)
-{
- struct s5p_mfc_ctx_buf_size *buf_size = dev->variant->buf_size->ctx_buf;
-
- memset((void *)dev->dbg_info_buf.vaddr, 0, buf_size->dbg_info_buf);
-
- MFC_WRITEL(dev->dbg_info_buf.daddr, S5P_FIMV_DBG_BUFFER_ADDR);
- MFC_WRITEL(buf_size->dbg_info_buf, S5P_FIMV_DBG_BUFFER_SIZE);
-}
-
-void s5p_mfc_otf_set_frame_addr(struct s5p_mfc_ctx *ctx, int num_planes)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct _otf_handle *handle = ctx->otf_handle;
- struct _otf_buf_addr *buf_addr = &handle->otf_buf_addr;
- int index = handle->otf_buf_index;
- int i;
-
- for (i = 0; i < num_planes; i++) {
- mfc_debug(2, "[OTF][FRAME] set frame buffer[%d], 0x%08llx)\n",
- i, buf_addr->otf_daddr[index][i]);
- MFC_WRITEL(buf_addr->otf_daddr[index][i],
- S5P_FIMV_E_SOURCE_FIRST_ADDR + (i * 4));
- }
-}
-
-void s5p_mfc_otf_set_stream_size(struct s5p_mfc_ctx *ctx, unsigned int size)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct _otf_handle *handle = ctx->otf_handle;
- struct _otf_debug *debug = &handle->otf_debug;
- struct s5p_mfc_special_buf *buf;
-
- mfc_debug(2, "[OTF] set stream buffer full size, %u\n", size);
- MFC_WRITEL(size, S5P_FIMV_E_STREAM_BUFFER_SIZE);
-
- if (otf_dump && !ctx->is_drm) {
- buf = &debug->stream_buf[debug->frame_cnt];
- mfc_debug(2, "[OTF] set stream addr for debugging\n");
- mfc_debug(2, "[OTF][STREAM] buf[%d] daddr: 0x%08llx\n",
- debug->frame_cnt, buf->daddr);
- MFC_WRITEL(buf->daddr, S5P_FIMV_E_STREAM_BUFFER_ADDR);
- }
-}
-
-void s5p_mfc_otf_set_hwfc_index(struct s5p_mfc_ctx *ctx, int job_id)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
-
- mfc_debug(2, "[OTF] set hwfc index, %d\n", job_id);
- HWFC_WRITEL(job_id, HWFC_ENCODING_IDX);
-}
-
-/* Set decoding frame buffer */
-int s5p_mfc_set_dec_codec_buffers(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev;
- struct s5p_mfc_dec *dec;
- unsigned int i;
- size_t frame_size_mv;
- dma_addr_t buf_addr;
- int buf_size;
- int align_gap;
- struct s5p_mfc_raw_info *raw;
- unsigned int reg = 0;
-
- if (!ctx) {
- mfc_err_dev("no mfc context to run\n");
- return -EINVAL;
- }
-
- dev = ctx->dev;
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
-
- dec = ctx->dec_priv;
- if (!dec) {
- mfc_err_dev("no mfc decoder to run\n");
- return -EINVAL;
- }
-
- raw = &ctx->raw_buf;
- buf_addr = ctx->codec_buf.daddr;
- buf_size = ctx->codec_buf.size;
-
- mfc_debug(2, "[MEMINFO] codec buf 0x%llx size: %d\n", buf_addr, buf_size);
- mfc_debug(2, "Total DPB COUNT: %d, display delay: %d\n",
- dec->total_dpb_count, dec->display_delay);
-
- /* set decoder DPB size, stride */
- MFC_WRITEL(dec->total_dpb_count, S5P_FIMV_D_NUM_DPB);
- for (i = 0; i < raw->num_planes; i++) {
- mfc_debug(2, "[FRAME] buf[%d] size: %d, stride: %d\n",
- i, raw->plane_size[i], raw->stride[i]);
- MFC_WRITEL(raw->plane_size[i], S5P_FIMV_D_FIRST_PLANE_DPB_SIZE + (i * 4));
- MFC_WRITEL(ctx->raw_buf.stride[i],
- S5P_FIMV_D_FIRST_PLANE_DPB_STRIDE_SIZE + (i * 4));
- if (ctx->is_10bit) {
- MFC_WRITEL(raw->stride_2bits[i], S5P_FIMV_D_FIRST_PLANE_2BIT_DPB_STRIDE_SIZE + (i * 4));
- MFC_WRITEL(raw->plane_size_2bits[i], S5P_FIMV_D_FIRST_PLANE_2BIT_DPB_SIZE + (i * 4));
- mfc_debug(2, "[FRAME][10BIT] 2bits buf[%d] size: %d, stride: %d\n",
- i, raw->plane_size_2bits[i], raw->stride_2bits[i]);
- }
- }
-
- /* set codec buffers */
- MFC_WRITEL(buf_addr, S5P_FIMV_D_SCRATCH_BUFFER_ADDR);
- MFC_WRITEL(ctx->scratch_buf_size, S5P_FIMV_D_SCRATCH_BUFFER_SIZE);
- buf_addr += ctx->scratch_buf_size;
- buf_size -= ctx->scratch_buf_size;
-
- if (IS_H264_DEC(ctx) || IS_H264_MVC_DEC(ctx) || IS_HEVC_DEC(ctx) || IS_BPG_DEC(ctx))
- MFC_WRITEL(ctx->mv_size, S5P_FIMV_D_MV_BUFFER_SIZE);
-
- if (IS_VP9_DEC(ctx)){
- MFC_WRITEL(buf_addr, S5P_FIMV_D_STATIC_BUFFER_ADDR);
- MFC_WRITEL(DEC_STATIC_BUFFER_SIZE, S5P_FIMV_D_STATIC_BUFFER_SIZE);
- buf_addr += DEC_STATIC_BUFFER_SIZE;
- buf_size -= DEC_STATIC_BUFFER_SIZE;
- }
-
- if (IS_MPEG4_DEC(ctx) && dec->loop_filter_mpeg4) {
- mfc_debug(2, "Add DPB for loop filter of MPEG4\n");
- for (i = 0; i < NUM_MPEG4_LF_BUF; i++) {
- MFC_WRITEL(buf_addr, S5P_FIMV_D_POST_FILTER_LUMA_DPB0 + (4 * i));
- buf_addr += ctx->loopfilter_luma_size;
- buf_size -= ctx->loopfilter_luma_size;
-
- MFC_WRITEL(buf_addr, S5P_FIMV_D_POST_FILTER_CHROMA_DPB0 + (4 * i));
- buf_addr += ctx->loopfilter_chroma_size;
- buf_size -= ctx->loopfilter_chroma_size;
- }
- reg |= ((dec->loop_filter_mpeg4 & S5P_FIMV_D_INIT_BUF_OPT_LF_CTRL_MASK)
- << S5P_FIMV_D_INIT_BUF_OPT_LF_CTRL_SHIFT);
- }
-
- reg |= (0x1 << S5P_FIMV_D_INIT_BUF_OPT_DYNAMIC_DPB_SET_SHIFT);
-
- if (CODEC_NOT_CODED(ctx)) {
- reg |= (0x1 << S5P_FIMV_D_INIT_BUF_OPT_COPY_NOT_CODED_SHIFT);
- mfc_debug(2, "Notcoded frame copy mode start\n");
- }
- /* Enable 10bit Dithering */
- if (ctx->is_10bit) {
- reg |= (0x1 << S5P_FIMV_D_INIT_BUF_OPT_DITHERING_EN_SHIFT);
- /* 64byte align, It is vaid only for VP9 */
- reg |= (0x1 << S5P_FIMV_D_INIT_BUF_OPT_STRIDE_SIZE_ALIGN);
- } else {
- /* 16byte align, It is vaid only for VP9 */
- reg &= ~(0x1 << S5P_FIMV_D_INIT_BUF_OPT_STRIDE_SIZE_ALIGN);
- }
-
- MFC_WRITEL(reg, S5P_FIMV_D_INIT_BUFFER_OPTIONS);
-
- frame_size_mv = ctx->mv_size;
- MFC_WRITEL(dec->mv_count, S5P_FIMV_D_NUM_MV);
- if (IS_H264_DEC(ctx) || IS_H264_MVC_DEC(ctx) || IS_HEVC_DEC(ctx) || IS_BPG_DEC(ctx)) {
- for (i = 0; i < dec->mv_count; i++) {
- /* To test alignment */
- align_gap = buf_addr;
- buf_addr = ALIGN(buf_addr, 16);
- align_gap = buf_addr - align_gap;
- buf_size -= align_gap;
-
- MFC_WRITEL(buf_addr, S5P_FIMV_D_MV_BUFFER0 + i * 4);
- buf_addr += frame_size_mv;
- buf_size -= frame_size_mv;
- }
- }
-
- mfc_debug(2, "[MEMINFO] codec buf 0x%llx, remained size: %d\n", buf_addr, buf_size);
- if (buf_size < 0) {
- mfc_debug(2, "[MEMINFO] Not enough memory has been allocated\n");
- return -ENOMEM;
- }
-
- return 0;
-}
-
-/* Set encoding ref & codec buffer */
-int s5p_mfc_set_enc_codec_buffers(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_enc *enc = ctx->enc_priv;
- dma_addr_t buf_addr;
- int buf_size;
- int i;
-
- mfc_debug_enter();
-
- buf_addr = ctx->codec_buf.daddr;
- buf_size = ctx->codec_buf.size;
-
- mfc_debug(2, "[MEMINFO] codec buf 0x%llx, size: %d\n", buf_addr, buf_size);
- mfc_debug(2, "DPB COUNT: %d\n", ctx->dpb_count);
-
- MFC_WRITEL(buf_addr, S5P_FIMV_E_SCRATCH_BUFFER_ADDR);
- MFC_WRITEL(ctx->scratch_buf_size, S5P_FIMV_E_SCRATCH_BUFFER_SIZE);
- buf_addr += ctx->scratch_buf_size;
- buf_size -= ctx->scratch_buf_size;
-
- /* start address of per buffer is aligned */
- for (i = 0; i < ctx->dpb_count; i++) {
- MFC_WRITEL(buf_addr, S5P_FIMV_E_LUMA_DPB + (4 * i));
- buf_addr += enc->luma_dpb_size;
- buf_size -= enc->luma_dpb_size;
- }
- for (i = 0; i < ctx->dpb_count; i++) {
- MFC_WRITEL(buf_addr, S5P_FIMV_E_CHROMA_DPB + (4 * i));
- buf_addr += enc->chroma_dpb_size;
- buf_size -= enc->chroma_dpb_size;
- }
- for (i = 0; i < ctx->dpb_count; i++) {
- MFC_WRITEL(buf_addr, S5P_FIMV_E_ME_BUFFER + (4 * i));
- buf_addr += enc->me_buffer_size;
- buf_size -= enc->me_buffer_size;
- }
-
- MFC_WRITEL(buf_addr, S5P_FIMV_E_TMV_BUFFER0);
- buf_addr += enc->tmv_buffer_size >> 1;
- MFC_WRITEL(buf_addr, S5P_FIMV_E_TMV_BUFFER1);
- buf_addr += enc->tmv_buffer_size >> 1;
- buf_size -= enc->tmv_buffer_size;
-
- mfc_debug(2, "[MEMINFO] codec buf 0x%llx, remained size: %d\n", buf_addr, buf_size);
- if (buf_size < 0) {
- mfc_debug(2, "[MEMINFO] Not enough memory has been allocated\n");
- return -ENOMEM;
- }
-
- mfc_debug_leave();
-
- return 0;
-}
-
-/* Set registers for decoding stream buffer */
-int s5p_mfc_set_dec_stream_buffer(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *mfc_buf,
- unsigned int start_num_byte, unsigned int strm_size)
-{
- struct s5p_mfc_dev *dev;
- struct s5p_mfc_dec *dec;
- unsigned int cpb_buf_size;
- dma_addr_t addr;
- int index = -1;
-
- mfc_debug_enter();
- if (!ctx) {
- mfc_err_dev("no mfc context to run\n");
- return -EINVAL;
- }
- dev = ctx->dev;
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
- dec = ctx->dec_priv;
- if (!dec) {
- mfc_err_dev("no mfc decoder to run\n");
- return -EINVAL;
- }
-
- cpb_buf_size = ALIGN(dec->src_buf_size, STREAM_BUF_ALIGN);
-
- if (mfc_buf) {
- index = mfc_buf->vb.vb2_buf.index;
- addr = mfc_buf->addr[0][0];
- if (strm_size > set_strm_size_max(cpb_buf_size)) {
- mfc_info_ctx("Decrease strm_size because of %d align: %u -> %u\n",
- STREAM_BUF_ALIGN, strm_size, set_strm_size_max(cpb_buf_size));
- strm_size = set_strm_size_max(cpb_buf_size);
- mfc_buf->vb.vb2_buf.planes[0].bytesused = strm_size;
- }
- } else {
- addr = 0;
- }
-
- mfc_debug(2, "[BUFINFO] ctx[%d] set src index: %d, addr: 0x%08llx\n",
- ctx->num, index, addr);
- mfc_debug(2, "[STREAM] strm_size: %#lx(%d), buf_size: %u, offset: %u\n",
- strm_size, strm_size, cpb_buf_size, start_num_byte);
-
- if (strm_size == 0)
- mfc_info_ctx("stream size is 0\n");
-
- MFC_WRITEL(strm_size, S5P_FIMV_D_STREAM_DATA_SIZE);
- MFC_WRITEL(addr, S5P_FIMV_D_CPB_BUFFER_ADDR);
- MFC_WRITEL(cpb_buf_size, S5P_FIMV_D_CPB_BUFFER_SIZE);
- MFC_WRITEL(start_num_byte, S5P_FIMV_D_CPB_BUFFER_OFFSET);
-
- if (mfc_buf)
- MFC_TRACE_CTX("Set src[%d] fd: %d, %#llx\n",
- index, mfc_buf->vb.vb2_buf.planes[0].m.fd, addr);
-
- mfc_debug_leave();
- return 0;
-}
-
-void s5p_mfc_set_enc_frame_buffer(struct s5p_mfc_ctx *ctx,
- struct s5p_mfc_buf *mfc_buf, int num_planes)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- dma_addr_t addr[3] = { 0, 0, 0 };
- dma_addr_t addr_2bit[2] = { 0, 0 };
- int index, i;
-
- if (!mfc_buf) {
- mfc_debug(3, "enc zero buffer set\n");
- goto buffer_set;
- }
-
- index = mfc_buf->vb.vb2_buf.index;
- if (mfc_buf->num_valid_bufs > 0) {
- for (i = 0; i < num_planes; i++) {
- addr[i] = mfc_buf->addr[mfc_buf->next_index][i];
- mfc_debug(2, "[BUFCON][BUFINFO] ctx[%d] set src index:%d, batch[%d], addr[%d]: 0x%08llx\n",
- ctx->num, index, mfc_buf->next_index, i, addr[i]);
- }
- mfc_buf->next_index++;
- } else {
- for (i = 0; i < num_planes; i++) {
- addr[i] = mfc_buf->addr[0][i];
- mfc_debug(2, "[BUFINFO] ctx[%d] set src index:%d, addr[%d]: 0x%08llx\n",
- ctx->num, index, i, addr[i]);
- }
- }
-
-buffer_set:
- for (i = 0; i < num_planes; i++)
- MFC_WRITEL(addr[i], S5P_FIMV_E_SOURCE_FIRST_ADDR + (i * 4));
-
- if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M_S10B ||
- ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV21M_S10B) {
- addr_2bit[0] = addr[0] + NV12N_10B_Y_8B_SIZE(ctx->img_width, ctx->img_height);
- addr_2bit[1] = addr[1] + NV12N_10B_CBCR_8B_SIZE(ctx->img_width, ctx->img_height);
-
- for (i = 0; i < num_planes; i++) {
- MFC_WRITEL(addr_2bit[i], S5P_FIMV_E_SOURCE_FIRST_2BIT_ADDR + (i * 4));
- mfc_debug(2, "[BUFINFO][10BIT] ctx[%d] set src 2bit addr[%d]: 0x%08llx\n",
- ctx->num, i, addr_2bit[i]);
- }
- } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV16M_S10B ||
- ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV61M_S10B) {
- addr_2bit[0] = addr[0] + NV16M_Y_SIZE(ctx->img_width, ctx->img_height);
- addr_2bit[1] = addr[1] + NV16M_CBCR_SIZE(ctx->img_width, ctx->img_height);
-
- for (i = 0; i < num_planes; i++) {
- MFC_WRITEL(addr_2bit[i], S5P_FIMV_E_SOURCE_FIRST_2BIT_ADDR + (i * 4));
- mfc_debug(2, "[BUFINFO][10BIT] ctx[%d] set src 2bit addr[%d]: 0x%08llx\n",
- ctx->num, i, addr_2bit[i]);
- }
- }
-}
-
-/* Set registers for encoding stream buffer */
-int s5p_mfc_set_enc_stream_buffer(struct s5p_mfc_ctx *ctx,
- struct s5p_mfc_buf *mfc_buf)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- dma_addr_t addr;
- unsigned int size, offset, index;
-
- index = mfc_buf->vb.vb2_buf.index;
- addr = mfc_buf->addr[0][0];
- offset = mfc_buf->vb.vb2_buf.planes[0].data_offset;
- size = (unsigned int)vb2_plane_size(&mfc_buf->vb.vb2_buf, 0);
- size = ALIGN(size, 512);
-
- MFC_WRITEL(addr, S5P_FIMV_E_STREAM_BUFFER_ADDR); /* 16B align */
- MFC_WRITEL(size, S5P_FIMV_E_STREAM_BUFFER_SIZE);
- MFC_WRITEL(offset, S5P_FIMV_E_STREAM_BUFFER_OFFSET);
-
- mfc_debug(2, "[BUFINFO] ctx[%d] set dst index: %d, addr: 0x%08llx\n",
- ctx->num, index, addr);
- mfc_debug(2, "[STREAM] buf_size: %u, offset: %d\n", size, offset);
-
- return 0;
-}
-
-void s5p_mfc_get_enc_frame_buffer(struct s5p_mfc_ctx *ctx,
- dma_addr_t addr[], int num_planes)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- unsigned long enc_recon_y_addr, enc_recon_c_addr;
- int i, addr_offset;
-
- addr_offset = S5P_FIMV_E_ENCODED_SOURCE_FIRST_ADDR;
-
- for (i = 0; i < num_planes; i++)
- addr[i] = MFC_READL(addr_offset + (i * 4));
-
- enc_recon_y_addr = MFC_READL(S5P_FIMV_E_RECON_LUMA_DPB_ADDR);
- enc_recon_c_addr = MFC_READL(S5P_FIMV_E_RECON_CHROMA_DPB_ADDR);
-
- mfc_debug(2, "[MEMINFO] recon y: 0x%08lx c: 0x%08lx\n",
- enc_recon_y_addr, enc_recon_c_addr);
-}
-
-void s5p_mfc_set_enc_stride(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- int i;
-
- for (i = 0; i < ctx->raw_buf.num_planes; i++) {
- MFC_WRITEL(ctx->raw_buf.stride[i],
- S5P_FIMV_E_SOURCE_FIRST_STRIDE + (i * 4));
- mfc_debug(2, "[FRAME] enc src plane[%d] stride: %d\n",
- i, ctx->raw_buf.stride[i]);
- }
-}
-
-int s5p_mfc_set_dynamic_dpb(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *dst_mb)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_dec *dec = ctx->dec_priv;
- struct s5p_mfc_raw_info *raw = &ctx->raw_buf;
- int dst_index;
- int i;
-
- dst_index = dst_mb->vb.vb2_buf.index;
- set_bit(dst_index, &dec->available_dpb);
- dec->dynamic_set = 1 << dst_index;
- mfc_debug(2, "[DPB] ADDING Flag after: 0x%lx\n", dec->available_dpb);
-
- /* for debugging about black bar detection */
- if (MFC_FEATURE_SUPPORT(dev, dev->pdata->black_bar) && dec->detect_black_bar) {
- for (i = 0; i < raw->num_planes; i++) {
- dec->frame_vaddr[i][dec->frame_cnt] = vb2_plane_vaddr(&dst_mb->vb.vb2_buf, i);
- dec->frame_daddr[i][dec->frame_cnt] = dst_mb->addr[0][i];
- dec->frame_size[i][dec->frame_cnt] = raw->plane_size[i];
- dec->index[i][dec->frame_cnt] = dst_index;
- dec->fd[i][dec->frame_cnt] = dst_mb->vb.vb2_buf.planes[0].m.fd;
- }
- dec->frame_cnt++;
- if (dec->frame_cnt >= 30)
- dec->frame_cnt = 0;
- }
-
- /* decoder dst buffer CFW PROT */
- s5p_mfc_protect_dpb(ctx, dst_mb);
-
- for (i = 0; i < raw->num_planes; i++) {
- MFC_WRITEL(raw->plane_size[i],
- S5P_FIMV_D_FIRST_PLANE_DPB_SIZE + i * 4);
- MFC_WRITEL(dst_mb->addr[0][i],
- S5P_FIMV_D_FIRST_PLANE_DPB0 + (i * 0x100 + dst_index * 4));
- if (ctx->is_10bit)
- MFC_WRITEL(raw->plane_size_2bits[i],
- S5P_FIMV_D_FIRST_PLANE_2BIT_DPB_SIZE + (i * 4));
- mfc_debug(2, "[BUFINFO][DPB] ctx[%d] set dst index: %d, addr[%d]: 0x%08llx\n",
- ctx->num, dst_index, i, dst_mb->addr[0][i]);
- }
-
- MFC_TRACE_CTX("Set dst[%d] fd: %d, %#llx / avail %#lx used %#x\n",
- dst_index, dst_mb->vb.vb2_buf.planes[0].m.fd, dst_mb->addr[0][0],
- dec->available_dpb, dec->dynamic_used);
-
- return 0;
-}
-
-void s5p_mfc_set_pixel_format(struct s5p_mfc_dev *dev, unsigned int format)
-{
- unsigned int reg = 0;
- unsigned int pix_val, mem_type_10bit = 0;
-
- if (dev->pdata->P010_decoding)
- mem_type_10bit = 1;
-
- switch (format) {
- case V4L2_PIX_FMT_NV12M:
- case V4L2_PIX_FMT_NV12N:
- case V4L2_PIX_FMT_NV12MT_16X16:
- case V4L2_PIX_FMT_NV16M:
- pix_val = 0;
- break;
- case V4L2_PIX_FMT_NV21M:
- case V4L2_PIX_FMT_NV61M:
- pix_val = 1;
- break;
- case V4L2_PIX_FMT_YVU420M:
- pix_val = 2;
- break;
- case V4L2_PIX_FMT_YUV420M:
- case V4L2_PIX_FMT_YUV420N:
- pix_val = 3;
- break;
- /* For 10bit direct set */
- case V4L2_PIX_FMT_NV12N_10B:
- case V4L2_PIX_FMT_NV12M_S10B:
- case V4L2_PIX_FMT_NV16M_S10B:
- mem_type_10bit = 0;
- pix_val = 0;
- break;
- case V4L2_PIX_FMT_NV12M_P010:
- case V4L2_PIX_FMT_NV16M_P210:
- mem_type_10bit = 1;
- pix_val = 0;
- break;
- case V4L2_PIX_FMT_NV21M_S10B:
- case V4L2_PIX_FMT_NV61M_S10B:
- mem_type_10bit = 0;
- pix_val = 1;
- break;
- case V4L2_PIX_FMT_NV21M_P010:
- case V4L2_PIX_FMT_NV61M_P210:
- mem_type_10bit = 1;
- pix_val = 1;
- break;
- default:
- pix_val = 0;
- break;
- }
- reg |= pix_val;
- reg |= (mem_type_10bit << 4);
- MFC_WRITEL(reg, S5P_FIMV_PIXEL_FORMAT);
- mfc_debug(2, "[FRAME] pixel format: %d, mem_type_10bit for 10bit: %d (reg: %#x)\n",
- pix_val, mem_type_10bit, reg);
-}
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_reg.h
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __S5P_MFC_REG_H
-#define __S5P_MFC_REG_H __FILE__
-
-#include "s5p_mfc_common.h"
-
-#include "s5p_mfc_utils.h"
-
-#define MFC_READL(offset) readl(dev->regs_base + (offset))
-#define MFC_WRITEL(data, offset) writel((data), dev->regs_base + (offset))
-
-#define MFC_MMU0_READL(offset) readl(dev->sysmmu0_base + (offset))
-#define MFC_MMU1_READL(offset) readl(dev->sysmmu1_base + (offset))
-
-#define HWFC_WRITEL(data, offset) writel((data), dev->hwfc_base + (offset))
-
-#define MMCACHE_READL(offset) readl(dev->mmcache.base + (offset))
-#define MMCACHE_WRITEL(data, offset) writel((data), dev->mmcache.base + (offset))
-
-/* version */
-#define s5p_mfc_get_fimv_info() ((MFC_READL(S5P_FIMV_FW_VERSION) \
- >> S5P_FIMV_FW_VER_INFO_SHFT) \
- & S5P_FIMV_FW_VER_INFO_MASK)
-#define s5p_mfc_get_fw_ver_year() ((MFC_READL(S5P_FIMV_FW_VERSION) \
- >> S5P_FIMV_FW_VER_YEAR_SHFT) \
- & S5P_FIMV_FW_VER_YEAR_MASK)
-#define s5p_mfc_get_fw_ver_month() ((MFC_READL(S5P_FIMV_FW_VERSION) \
- >> S5P_FIMV_FW_VER_MONTH_SHFT) \
- & S5P_FIMV_FW_VER_MONTH_MASK)
-#define s5p_mfc_get_fw_ver_date() ((MFC_READL(S5P_FIMV_FW_VERSION) \
- >> S5P_FIMV_FW_VER_DATE_SHFT) \
- & S5P_FIMV_FW_VER_DATE_MASK)
-#define s5p_mfc_get_fw_ver_all() ((MFC_READL(S5P_FIMV_FW_VERSION) \
- >> S5P_FIMV_FW_VER_ALL_SHFT) \
- & S5P_FIMV_FW_VER_ALL_MASK)
-#define s5p_mfc_get_mfc_version() ((MFC_READL(S5P_FIMV_MFC_VERSION) \
- >> S5P_FIMV_MFC_VER_SHFT) \
- & S5P_FIMV_MFC_VER_MASK)
-
-
-/* decoding & display information */
-#define s5p_mfc_get_dec_status() (MFC_READL(S5P_FIMV_D_DECODED_STATUS) \
- & S5P_FIMV_DEC_STATUS_DECODED_STATUS_MASK)
-#define s5p_mfc_get_disp_status() (MFC_READL(S5P_FIMV_D_DISPLAY_STATUS) \
- & S5P_FIMV_DISP_STATUS_DISPLAY_STATUS_MASK)
-#define s5p_mfc_get_res_change() ((MFC_READL(S5P_FIMV_D_DISPLAY_STATUS) \
- >> S5P_FIMV_DISP_STATUS_RES_CHANGE_SHIFT) \
- & S5P_FIMV_DISP_STATUS_RES_CHANGE_MASK)
-#define s5p_mfc_get_black_bar_detection() ((MFC_READL(S5P_FIMV_D_DISPLAY_STATUS) \
- >> S5P_FIMV_DISP_STATUS_BLACK_BAR_DETECT_SHIFT) \
- & S5P_FIMV_DISP_STATUS_BLACK_BAR_DETECT_MASK)
-#define s5p_mfc_get_dpb_change() ((MFC_READL(S5P_FIMV_D_DISPLAY_STATUS) \
- >> S5P_FIMV_DISP_STATUS_NEED_DPB_CHANGE_SHIFT) \
- & S5P_FIMV_DISP_STATUS_NEED_DPB_CHANGE_MASK)
-#define s5p_mfc_get_scratch_change() ((MFC_READL(S5P_FIMV_D_DISPLAY_STATUS) \
- >> S5P_FIMV_DISP_STATUS_NEED_SCRATCH_CHANGE_SHIFT) \
- & S5P_FIMV_DISP_STATUS_NEED_SCRATCH_CHANGE_MASK)
-#define s5p_mfc_get_disp_frame_type() (MFC_READL(S5P_FIMV_D_DISPLAY_FRAME_TYPE) \
- & S5P_FIMV_DISPLAY_FRAME_MASK)
-#define s5p_mfc_get_dec_frame_type() (MFC_READL(S5P_FIMV_D_DECODED_FRAME_TYPE) \
- & S5P_FIMV_DECODED_FRAME_MASK)
-#define s5p_mfc_get_interlace_type() ((MFC_READL(S5P_FIMV_D_DISPLAY_FRAME_TYPE) \
- >> S5P_FIMV_DISPLAY_TEMP_INFO_SHIFT) \
- & S5P_FIMV_DISPLAY_TEMP_INFO_MASK)
-#define s5p_mfc_is_interlace_picture() ((MFC_READL(S5P_FIMV_D_DISPLAY_STATUS) \
- >> S5P_FIMV_DISP_STATUS_INTERLACE_SHIFT)\
- & S5P_FIMV_DISP_STATUS_INTERLACE_MASK)
-#define s5p_mfc_is_mbaff_picture() ((MFC_READL(S5P_FIMV_D_H264_INFO) \
- >> S5P_FIMV_D_H264_INFO_MBAFF_FRAME_FLAG_SHIFT)\
- & S5P_FIMV_D_H264_INFO_MBAFF_FRAME_FLAG_MASK)
-#define s5p_mfc_get_img_width() MFC_READL(S5P_FIMV_D_DISPLAY_FRAME_WIDTH)
-#define s5p_mfc_get_img_height() MFC_READL(S5P_FIMV_D_DISPLAY_FRAME_HEIGHT)
-#define s5p_mfc_get_disp_y_addr() MFC_READL(S5P_FIMV_D_DISPLAY_LUMA_ADDR)
-#define s5p_mfc_get_dec_y_addr() MFC_READL(S5P_FIMV_D_DECODED_LUMA_ADDR)
-
-
-/* kind of interrupt */
-#define s5p_mfc_get_int_err() MFC_READL(S5P_FIMV_ERROR_CODE)
-#define s5p_mfc_get_err(x) (((x) >> S5P_FIMV_ERR_STATUS_SHIFT) \
- & S5P_FIMV_ERR_STATUS_MASK)
-#define s5p_mfc_get_warn(x) (((x) >> S5P_FIMV_WARN_STATUS_SHIFT) \
- & S5P_FIMV_WARN_STATUS_MASK)
-
-
-/* additional information */
-#define s5p_mfc_get_consumed_stream() MFC_READL(S5P_FIMV_D_DECODED_NAL_SIZE)
-#define s5p_mfc_get_dpb_count() MFC_READL(S5P_FIMV_D_MIN_NUM_DPB)
-#define s5p_mfc_get_min_dpb_size(x) MFC_READL(S5P_FIMV_D_MIN_FIRST_PLANE_DPB_SIZE + (x * 4))
-#define s5p_mfc_get_scratch_size() MFC_READL(S5P_FIMV_D_MIN_SCRATCH_BUFFER_SIZE)
-#define s5p_mfc_get_mv_count() MFC_READL(S5P_FIMV_D_MIN_NUM_MV)
-#define s5p_mfc_get_inst_no() MFC_READL(S5P_FIMV_RET_INSTANCE_ID)
-#define s5p_mfc_get_enc_dpb_count() MFC_READL(S5P_FIMV_E_NUM_DPB)
-#define s5p_mfc_get_enc_scratch_size() MFC_READL(S5P_FIMV_E_MIN_SCRATCH_BUFFER_SIZE)
-#define s5p_mfc_get_enc_strm_size() MFC_READL(S5P_FIMV_E_STREAM_SIZE)
-#define s5p_mfc_get_enc_slice_type() MFC_READL(S5P_FIMV_E_SLICE_TYPE)
-#define s5p_mfc_get_enc_pic_count() MFC_READL(S5P_FIMV_E_PICTURE_COUNT)
-#define s5p_mfc_get_sei_avail() MFC_READL(S5P_FIMV_D_SEI_AVAIL)
-#define s5p_mfc_get_sei_content_light() MFC_READL(S5P_FIMV_D_CONTENT_LIGHT_LEVEL_INFO_SEI)
-#define s5p_mfc_get_sei_mastering0() MFC_READL(S5P_FIMV_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_0)
-#define s5p_mfc_get_sei_mastering1() MFC_READL(S5P_FIMV_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_1)
-#define s5p_mfc_get_sei_mastering2() MFC_READL(S5P_FIMV_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_2)
-#define s5p_mfc_get_sei_mastering3() MFC_READL(S5P_FIMV_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_3)
-#define s5p_mfc_get_sei_mastering4() MFC_READL(S5P_FIMV_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_4)
-#define s5p_mfc_get_sei_mastering5() MFC_READL(S5P_FIMV_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_5)
-#define s5p_mfc_get_sei_avail_frame_pack() (MFC_READL(S5P_FIMV_D_SEI_AVAIL) \
- & S5P_FIMV_D_SEI_AVAIL_FRAME_PACK_MASK)
-#define s5p_mfc_get_sei_avail_content_light() ((MFC_READL(S5P_FIMV_D_SEI_AVAIL) \
- >> S5P_FIMV_D_SEI_AVAIL_CONTENT_LIGHT_SHIFT) \
- & S5P_FIMV_D_SEI_AVAIL_CONTENT_LIGHT_MASK)
-#define s5p_mfc_get_sei_avail_mastering_display() ((MFC_READL(S5P_FIMV_D_SEI_AVAIL) \
- >> S5P_FIMV_D_SEI_AVAIL_MASTERING_DISPLAY_SHIFT) \
- & S5P_FIMV_D_SEI_AVAIL_MASTERING_DISPLAY_MASK)
-#define s5p_mfc_get_video_signal_type() ((MFC_READL(S5P_FIMV_D_VIDEO_SIGNAL_TYPE) \
- >> S5P_FIMV_D_VIDEO_SIGNAL_TYPE_FLAG_SHIFT) \
- & S5P_FIMV_D_VIDEO_SIGNAL_TYPE_FLAG_MASK)
-#define s5p_mfc_get_colour_description() ((MFC_READL(S5P_FIMV_D_VIDEO_SIGNAL_TYPE) \
- >> S5P_FIMV_D_COLOUR_DESCRIPTION_FLAG_SHIFT) \
- & S5P_FIMV_D_COLOUR_DESCRIPTION_FLAG_MASK)
-#define s5p_mfc_get_black_bar_pos_x() ((MFC_READL(S5P_FIMV_D_BLACK_BAR_START_POS) \
- >> S5P_FIMV_D_BLACK_BAR_START_X_SHIFT) \
- & S5P_FIMV_D_BLACK_BAR_START_X_MASK)
-#define s5p_mfc_get_black_bar_pos_y() ((MFC_READL(S5P_FIMV_D_BLACK_BAR_START_POS) \
- >> S5P_FIMV_D_BLACK_BAR_START_Y_SHIFT) \
- & S5P_FIMV_D_BLACK_BAR_START_Y_MASK)
-#define s5p_mfc_get_black_bar_image_w() ((MFC_READL(S5P_FIMV_D_BLACK_BAR_IMAGE_SIZE) \
- >> S5P_FIMV_D_BLACK_BAR_IMAGE_W_SHIFT) \
- & S5P_FIMV_D_BLACK_BAR_IMAGE_W_MASK)
-#define s5p_mfc_get_black_bar_image_h() ((MFC_READL(S5P_FIMV_D_BLACK_BAR_IMAGE_SIZE) \
- >> S5P_FIMV_D_BLACK_BAR_IMAGE_H_SHIFT) \
- & S5P_FIMV_D_BLACK_BAR_IMAGE_H_MASK)
-#define s5p_mfc_get_mvc_disp_view_id() (MFC_READL(S5P_FIMV_D_MVC_VIEW_ID) \
- & S5P_FIMV_D_MVC_VIEW_ID_DISP_MASK)
-#define s5p_mfc_get_profile() (MFC_READL(S5P_FIMV_D_DECODED_PICTURE_PROFILE) \
- & S5P_FIMV_D_DECODED_PIC_PROFILE_MASK)
-#define s5p_mfc_get_luma_bit_depth_minus8() ((MFC_READL(S5P_FIMV_D_DECODED_PICTURE_PROFILE) \
- >> S5P_FIMV_D_BIT_DEPTH_LUMA_MINUS8_SHIFT) \
- & S5P_FIMV_D_BIT_DEPTH_LUMA_MINUS8_MASK)
-#define s5p_mfc_get_chroma_bit_depth_minus8() ((MFC_READL(S5P_FIMV_D_DECODED_PICTURE_PROFILE) \
- >> S5P_FIMV_D_BIT_DEPTH_CHROMA_MINUS8_SHIFT) \
- & S5P_FIMV_D_BIT_DEPTH_CHROMA_MINUS8_MASK)
-#define s5p_mfc_get_dec_used_flag() MFC_READL(S5P_FIMV_D_USED_DPB_FLAG_LOWER)
-#define s5p_mfc_get_enc_nal_done_info() ((MFC_READL(S5P_FIMV_E_NAL_DONE_INFO) & (0x3 << 4)) >> 4)
-#define s5p_mfc_get_chroma_format() (MFC_READL(S5P_FIMV_D_CHROMA_FORMAT) \
- & S5P_FIMV_D_CHROMA_FORMAT_MASK)
-#define s5p_mfc_get_color_range() ((MFC_READL(S5P_FIMV_D_CHROMA_FORMAT) \
- >> S5P_FIMV_D_COLOR_RANGE_SHIFT) \
- & S5P_FIMV_D_COLOR_RANGE_MASK)
-#define s5p_mfc_get_color_space() ((MFC_READL(S5P_FIMV_D_CHROMA_FORMAT) \
- >> S5P_FIMV_D_COLOR_SPACE_SHIFT) \
- & S5P_FIMV_D_COLOR_SPACE_MASK)
-#define s5p_mfc_get_num_of_tile() ((MFC_READL(S5P_FIMV_D_DECODED_STATUS) \
- >> S5P_FIMV_DEC_STATUS_NUM_OF_TILE_SHIFT) \
- & S5P_FIMV_DEC_STATUS_NUM_OF_TILE_MASK)
-
-
-/* nal queue information */
-#define s5p_mfc_get_nal_q_input_count() MFC_READL(S5P_FIMV_NAL_QUEUE_INPUT_COUNT)
-#define s5p_mfc_get_nal_q_output_count() MFC_READL(S5P_FIMV_NAL_QUEUE_OUTPUT_COUNT)
-#define s5p_mfc_get_nal_q_input_exe_count() MFC_READL(S5P_FIMV_NAL_QUEUE_INPUT_EXE_COUNT)
-#define s5p_mfc_get_nal_q_info() MFC_READL(S5P_FIMV_NAL_QUEUE_INFO)
-#define s5p_mfc_get_nal_q_input_addr() MFC_READL(S5P_FIMV_NAL_QUEUE_INPUT_ADDR)
-#define s5p_mfc_get_nal_q_input_size() MFC_READL(S5P_FIMV_NAL_QUEUE_INPUT_SIZE)
-#define s5p_mfc_get_nal_q_output_addr() MFC_READL(S5P_FIMV_NAL_QUEUE_OUTPUT_ADDR)
-#define s5p_mfc_get_nal_q_output_ize() MFC_READL(S5P_FIMV_NAL_QUEUE_OUTPUT_SIZE)
-
-static inline void s5p_mfc_reset_nal_queue_registers(struct s5p_mfc_dev *dev)
-{
- MFC_WRITEL(0x0, S5P_FIMV_NAL_QUEUE_INPUT_COUNT);
- MFC_WRITEL(0x0, S5P_FIMV_NAL_QUEUE_OUTPUT_COUNT);
- MFC_WRITEL(0x0, S5P_FIMV_NAL_QUEUE_INPUT_EXE_COUNT);
- MFC_WRITEL(0x0, S5P_FIMV_NAL_QUEUE_INFO);
-}
-
-static inline void s5p_mfc_update_nal_queue_input(struct s5p_mfc_dev *dev,
- dma_addr_t addr, unsigned int size)
-{
- MFC_WRITEL(addr, S5P_FIMV_NAL_QUEUE_INPUT_ADDR);
- MFC_WRITEL(size, S5P_FIMV_NAL_QUEUE_INPUT_SIZE);
-}
-
-static inline void s5p_mfc_update_nal_queue_output(struct s5p_mfc_dev *dev,
- dma_addr_t addr, unsigned int size)
-{
- MFC_WRITEL(addr, S5P_FIMV_NAL_QUEUE_OUTPUT_ADDR);
- MFC_WRITEL(size, S5P_FIMV_NAL_QUEUE_OUTPUT_SIZE);
-}
-
-static inline void s5p_mfc_update_nal_queue_input_count(struct s5p_mfc_dev *dev,
- unsigned int input_count)
-{
- MFC_WRITEL(input_count, S5P_FIMV_NAL_QUEUE_INPUT_COUNT);
-}
-
-static inline void s5p_mfc_dec_store_crop_info(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_dec *dec = ctx->dec_priv;
- u32 left, right, top, bottom;
-
- left = MFC_READL(S5P_FIMV_D_DISPLAY_CROP_INFO1);
- right = left >> S5P_FIMV_D_SHARED_CROP_RIGHT_SHIFT;
- left = left & S5P_FIMV_D_SHARED_CROP_LEFT_MASK;
- top = MFC_READL(S5P_FIMV_D_DISPLAY_CROP_INFO2);
- bottom = top >> S5P_FIMV_D_SHARED_CROP_BOTTOM_SHIFT;
- top = top & S5P_FIMV_D_SHARED_CROP_TOP_MASK;
-
- dec->cr_left = left;
- dec->cr_right = right;
- dec->cr_top = top;
- dec->cr_bot = bottom;
-}
-
-static inline void s5p_mfc_clear_enc_res_change(struct s5p_mfc_dev *dev)
-{
- unsigned int reg = 0;
-
- reg = MFC_READL(S5P_FIMV_E_PARAM_CHANGE);
- reg &= ~(0x7 << 6);
- MFC_WRITEL(reg, S5P_FIMV_E_PARAM_CHANGE);
-}
-
-static inline void s5p_mfc_clear_roi_enable(struct s5p_mfc_dev *dev)
-{
- unsigned int reg = 0;
-
- reg = MFC_READL(S5P_FIMV_E_RC_ROI_CTRL);
- reg &= ~(0x1);
- MFC_WRITEL(reg, S5P_FIMV_E_RC_ROI_CTRL);
-}
-
-void s5p_mfc_dbg_enable(struct s5p_mfc_dev *dev);
-void s5p_mfc_dbg_disable(struct s5p_mfc_dev *dev);
-void s5p_mfc_dbg_set_addr(struct s5p_mfc_dev *dev);
-
-void s5p_mfc_otf_set_frame_addr(struct s5p_mfc_ctx *ctx, int num_planes);
-void s5p_mfc_otf_set_stream_size(struct s5p_mfc_ctx *ctx, unsigned int size);
-void s5p_mfc_otf_set_hwfc_index(struct s5p_mfc_ctx *ctx, int job_id);
-
-int s5p_mfc_set_dec_codec_buffers(struct s5p_mfc_ctx *ctx);
-int s5p_mfc_set_enc_codec_buffers(struct s5p_mfc_ctx *mfc_ctx);
-
-int s5p_mfc_set_dec_stream_buffer(struct s5p_mfc_ctx *ctx,
- struct s5p_mfc_buf *mfc_buf,
- unsigned int start_num_byte,
- unsigned int buf_size);
-
-void s5p_mfc_set_enc_frame_buffer(struct s5p_mfc_ctx *ctx,
- struct s5p_mfc_buf *mfc_buf, int num_planes);
-int s5p_mfc_set_enc_stream_buffer(struct s5p_mfc_ctx *ctx,
- struct s5p_mfc_buf *mfc_buf);
-
-void s5p_mfc_get_enc_frame_buffer(struct s5p_mfc_ctx *ctx,
- dma_addr_t addr[], int num_planes);
-void s5p_mfc_set_enc_stride(struct s5p_mfc_ctx *ctx);
-
-int s5p_mfc_set_dynamic_dpb(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *dst_vb);
-
-void s5p_mfc_set_pixel_format(struct s5p_mfc_dev *dev, unsigned int format);
-
-#endif /* __S5P_MFC_REG_H */
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/regs-mfc-v10.h
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __REGS_MFC_V10_H
-#define __REGS_MFC_V10_H __FILE__
-
-#define MFC_MMU_INTERRUPT_STATUS 0x0060
-#define MFC_MMU_FAULT_TRANS_INFO 0x0078
-#define MFC_MMU_FAULT_TRANS_INFO_RW_MASK 0x100000
-#define MFC_MMU_FAULT_TRANS_INFO_AXID_MASK 0xFFFF
-
-#define HWFC_ENCODING_IDX 0x4
-
-/* Codec Common Registers */
-#define S5P_FIMV_RISC_ON 0x0000
-#define S5P_FIMV_RISC2HOST_INT 0x003C
-#define S5P_FIMV_HOST2RISC_INT 0x0044
-#define S5P_FIMV_RISC_BASE_ADDRESS 0x0054
-
-#define S5P_FIMV_MFC_FW_CLOCK 0x1060
-#define S5P_FIMV_MFC_RESET 0x1070
-
-#define S5P_FIMV_HOST2RISC_CMD 0x1100
-#define S5P_FIMV_RISC2HOST_CMD 0x1104
-
-#define S5P_FIMV_MFC_BUS_STATUS 0x7018
-#define S5P_FIMV_MFC_RPEND 0x7028
-#define S5P_FIMV_MFC_WPEND 0x702C
-#define S5P_FIMV_MFC_BUS_RESET_CTRL 0x7110
-#define S5P_FIMV_MFC_OFF 0x7120
-#define S5P_FIMV_MFC_STATE 0x7124
-
-#define S5P_FIMV_FW_VERSION 0xF000
-#define S5P_FIMV_INSTANCE_ID 0xF008
-#define S5P_FIMV_CODEC_TYPE 0xF00C
-#define S5P_FIMV_CONTEXT_MEM_ADDR 0xF014
-#define S5P_FIMV_CONTEXT_MEM_SIZE 0xF018
-#define S5P_FIMV_SHARED_MEM_ADDR 0xF01C
-#define S5P_FIMV_PIXEL_FORMAT 0xF020
-
-#define S5P_FIMV_METADATA_ENABLE 0xF024
-#define S5P_FIMV_MFC_VERSION 0xF028
-#define S5P_FIMV_DBG_INFO_ENABLE 0xF02C
-#define S5P_FIMV_DBG_BUFFER_ADDR 0xF030
-#define S5P_FIMV_DBG_BUFFER_SIZE 0xF034
-
-#define S5P_FIMV_CODEC_CONTROL 0xF038
-#define S5P_FIMV_DEC_TIMEOUT_VALUE 0xF03C
-#define S5P_FIMV_HED_SHARED_MEM_ADDR 0xF040
-
-/* NAL QUEUE */
-#define S5P_FIMV_NAL_QUEUE_INPUT_ADDR 0xF044
-#define S5P_FIMV_NAL_QUEUE_INPUT_SIZE 0xF048
-#define S5P_FIMV_NAL_QUEUE_OUTPUT_ADDR 0xF04C
-#define S5P_FIMV_NAL_QUEUE_OUTPUT_SIZE 0xF050
-#define S5P_FIMV_NAL_QUEUE_INPUT_COUNT 0xF054
-
-#define S5P_FIMV_RET_INSTANCE_ID 0xF070
-#define S5P_FIMV_ERROR_CODE 0xF074
-#define S5P_FIMV_DBG_BUFFER_OUTPUT_SIZE 0xF078
-#define S5P_FIMV_METADATA_STATUS 0xF07C
-
-#define S5P_FIMV_DBG_INFO_STAGE_COUNTER 0xF088
-
-/* NAL QUEUE */
-#define S5P_FIMV_NAL_QUEUE_OUTPUT_COUNT 0xF08C
-#define S5P_FIMV_NAL_QUEUE_INPUT_EXE_COUNT 0xF090
-#define S5P_FIMV_NAL_QUEUE_INFO 0xF094
-
-/* Decoder Registers */
-#define S5P_FIMV_D_CRC_CTRL 0xF0B0
-#define S5P_FIMV_D_DEC_OPTIONS 0xF0B4
-
-#define S5P_FIMV_D_DISPLAY_DELAY 0xF0B8
-
-#define S5P_FIMV_D_SET_FRAME_WIDTH 0xF0BC
-#define S5P_FIMV_D_SET_FRAME_HEIGHT 0xF0C0
-
-#define S5P_FIMV_D_SEI_ENABLE 0xF0C4
-
-#define S5P_FIMV_D_FORCE_PIXEL_VAL 0xF0C8
-
-/* Buffer setting registers */
-/* Session return */
-#define S5P_FIMV_D_MIN_NUM_DPB 0xF0F0
-#define S5P_FIMV_D_MIN_FIRST_PLANE_DPB_SIZE 0xF0F4
-#define S5P_FIMV_D_MIN_SECOND_PLANE_DPB_SIZE 0xF0F8
-#define S5P_FIMV_D_MIN_THIRD_PLANE_DPB_SIZE 0xF0FC
-#define S5P_FIMV_D_MIN_NUM_MV 0xF100
-#define S5P_FIMV_D_MVC_NUM_VIEWS 0xF104
-#define S5P_FIMV_D_MIN_SCRATCH_BUFFER_SIZE 0xF108
-#define S5P_FIMV_D_MIN_FIRST_PLANE_2BIT_DPB_SIZE 0xF10C
-#define S5P_FIMV_D_MIN_SECOND_PLANE_2BIT_DPB_SIZE 0xF110
-#define S5P_FIMV_D_POST_FILTER_LUMA_DPB0 0xF120
-#define S5P_FIMV_D_POST_FILTER_LUMA_DPB1 0xF124
-#define S5P_FIMV_D_POST_FILTER_CHROMA_DPB0 0xF128
-#define S5P_FIMV_D_POST_FILTER_CHROMA_DPB1 0xF12C
-
-/* Buffers */
-#define S5P_FIMV_D_NUM_DPB 0xF130
-#define S5P_FIMV_D_NUM_MV 0xF134
-#define S5P_FIMV_D_FIRST_PLANE_DPB_STRIDE_SIZE 0xF138
-#define S5P_FIMV_D_SECOND_PLANE_DPB_STRIDE_SIZE 0xF13C
-#define S5P_FIMV_D_THIRD_PLANE_DPB_STRIDE_SIZE 0xF140
-#define S5P_FIMV_D_FIRST_PLANE_DPB_SIZE 0xF144
-#define S5P_FIMV_D_SECOND_PLANE_DPB_SIZE 0xF148
-#define S5P_FIMV_D_THIRD_PLANE_DPB_SIZE 0xF14C
-#define S5P_FIMV_D_MV_BUFFER_SIZE 0xF150
-#define S5P_FIMV_D_INIT_BUFFER_OPTIONS 0xF154
-#define S5P_FIMV_D_FIRST_PLANE_DPB0 0xF160
-#define S5P_FIMV_D_SECOND_PLANE_DPB0 0xF260
-#define S5P_FIMV_D_THIRD_PLANE_DPB0 0xF360
-#define S5P_FIMV_D_MV_BUFFER0 0xF460
-#define S5P_FIMV_D_SCRATCH_BUFFER_ADDR 0xF560
-#define S5P_FIMV_D_SCRATCH_BUFFER_SIZE 0xF564
-#define S5P_FIMV_D_METADATA_BUFFER_ADDR 0xF568
-#define S5P_FIMV_D_METADATA_BUFFER_SIZE 0xF56C
-
-#define S5P_FIMV_D_STATIC_BUFFER_ADDR 0xF570
-#define S5P_FIMV_D_STATIC_BUFFER_SIZE 0xF574
-#define S5P_FIMV_D_FIRST_PLANE_2BIT_DPB_SIZE 0xF578
-#define S5P_FIMV_D_SECOND_PLANE_2BIT_DPB_SIZE 0xF57C
-#define S5P_FIMV_D_FIRST_PLANE_2BIT_DPB_STRIDE_SIZE 0xF580
-#define S5P_FIMV_D_SECOND_PLANE_2BIT_DPB_STRIDE_SIZE 0xF584
-
-#define S5P_FIMV_D_NAL_START_OPTIONS 0xF5AC
-
-/* Nal cmd */
-#define S5P_FIMV_D_CPB_BUFFER_ADDR 0xF5B0
-#define S5P_FIMV_D_CPB_BUFFER_SIZE 0xF5B4
-#define S5P_FIMV_D_AVAILABLE_DPB_FLAG_UPPER 0xF5B8
-#define S5P_FIMV_D_AVAILABLE_DPB_FLAG_LOWER 0xF5BC
-#define S5P_FIMV_D_CPB_BUFFER_OFFSET 0xF5C0
-#define S5P_FIMV_D_SLICE_IF_ENABLE 0xF5C4
-#define S5P_FIMV_D_PICTURE_TAG 0xF5C8
-#define S5P_FIMV_D_STREAM_DATA_SIZE 0xF5D0
-#define S5P_FIMV_D_DYNAMIC_DPB_FLAG_UPPER 0xF5D4
-#define S5P_FIMV_D_DYNAMIC_DPB_FLAG_LOWER 0xF5D8
-
-/* Nal return */
-#define S5P_FIMV_D_DISPLAY_FRAME_WIDTH 0xF600
-#define S5P_FIMV_D_DISPLAY_FRAME_HEIGHT 0xF604
-#define S5P_FIMV_D_DISPLAY_STATUS 0xF608
-#define S5P_FIMV_D_DISPLAY_FIRST_PLANE_ADDR 0xF60C
-#define S5P_FIMV_D_DISPLAY_SECOND_PLANE_ADDR 0xF610
-#define S5P_FIMV_D_DISPLAY_THIRD_PLANE_ADDR 0xF614
-#define S5P_FIMV_D_DISPLAY_FRAME_TYPE 0xF618
-#define S5P_FIMV_D_DISPLAY_CROP_INFO1 0xF61C
-#define S5P_FIMV_D_DISPLAY_CROP_INFO2 0xF620
-#define S5P_FIMV_D_DISPLAY_PICTURE_PROFILE 0xF624
-#define S5P_FIMV_D_DISPLAY_FIRST_PLANE_CRC 0xF628
-#define S5P_FIMV_D_DISPLAY_SECOND_PLANE_CRC 0xF62C
-#define S5P_FIMV_D_DISPLAY_THIRD_PLANE_CRC 0xF630
-#define S5P_FIMV_D_DISPLAY_ASPECT_RATIO 0xF634
-#define S5P_FIMV_D_DISPLAY_EXTENDED_AR 0xF638
-#define S5P_FIMV_D_DECODED_FRAME_WIDTH 0xF63C
-#define S5P_FIMV_D_DECODED_FRAME_HEIGHT 0xF640
-#define S5P_FIMV_D_DECODED_STATUS 0xF644
-#define S5P_FIMV_D_DECODED_FIRST_PLANE_ADDR 0xF648
-#define S5P_FIMV_D_DECODED_SECOND_PLANE_ADDR 0xF64C
-#define S5P_FIMV_D_DECODED_THIRD_PLANE_ADDR 0xF650
-#define S5P_FIMV_D_DECODED_FRAME_TYPE 0xF654
-#define S5P_FIMV_D_DECODED_CROP_INFO1 0xF658
-#define S5P_FIMV_D_DECODED_CROP_INFO2 0xF65C
-#define S5P_FIMV_D_DECODED_PICTURE_PROFILE 0xF660
-#define S5P_FIMV_D_DECODED_NAL_SIZE 0xF664
-#define S5P_FIMV_D_DECODED_FIRST_PLANE_CRC 0xF668
-#define S5P_FIMV_D_DECODED_SECOND_PLANE_CRC 0xF66C
-#define S5P_FIMV_D_DECODED_THIRD_PLANE_CRC 0xF670
-#define S5P_FIMV_D_RET_PICTURE_TAG_TOP 0xF674
-#define S5P_FIMV_D_RET_PICTURE_TAG_BOT 0xF678
-#define S5P_FIMV_D_RET_PICTURE_TIME_TOP 0xF67C
-#define S5P_FIMV_D_RET_PICTURE_TIME_BOT 0xF680
-#define S5P_FIMV_D_CHROMA_FORMAT 0xF684
-
-#define S5P_FIMV_D_VC1_INFO 0xF688
-#define S5P_FIMV_D_MPEG4_INFO 0xF68C
-#define S5P_FIMV_D_H264_INFO 0xF690
-#define S5P_FIMV_D_HEVC_INFO 0xF6A0
-#define S5P_FIMV_D_BPG_INFO 0xF6A8
-
-#define S5P_FIMV_D_METADATA_ADDR_CONCEALED_MB 0xF6B0
-#define S5P_FIMV_D_METADATA_SIZE_CONCEALED_MB 0xF6B4
-#define S5P_FIMV_D_METADATA_ADDR_VC1_PARAM 0xF6B8
-#define S5P_FIMV_D_METADATA_SIZE_VC1_PARAM 0xF6BC
-#define S5P_FIMV_D_METADATA_ADDR_SEI_NAL 0xF6C0
-#define S5P_FIMV_D_METADATA_SIZE_SEI_NAL 0xF6C4
-#define S5P_FIMV_D_METADATA_ADDR_VUI 0xF6C8
-#define S5P_FIMV_D_METADATA_SIZE_VUI 0xF6CC
-#define S5P_FIMV_D_METADATA_ADDR_MVCVUI 0xF6D0
-#define S5P_FIMV_D_METADATA_SIZE_MVCVUI 0xF6D4
-
-#define S5P_FIMV_D_MVC_VIEW_ID 0xF6D8
-
-#define S5P_FIMV_D_SEI_AVAIL 0xF6DC
-#define S5P_FIMV_D_FRAME_PACK_ARRGMENT_ID 0xF6E0
-#define S5P_FIMV_D_FRAME_PACK_SEI_INFO 0xF6E4
-#define S5P_FIMV_D_FRAME_PACK_GRID_POS 0xF6E8
-
-#define S5P_FIMV_D_DISPLAY_RECOVERY_SEI_INFO 0xF6EC
-#define S5P_FIMV_D_DECODED_RECOVERY_SEI_INFO 0xF6F0
-
-#define S5P_FIMV_D_DISPLAY_FIRST_PLANE_2BIT_CRC 0xF6FC
-#define S5P_FIMV_D_DISPLAY_SECOND_PLANE_2BIT_CRC 0xF700
-#define S5P_FIMV_D_DECODED_FIRST_PLANE_2BIT_CRC 0xF704
-#define S5P_FIMV_D_DECODED_SECOND_PLANE_2BIT_CRC 0xF708
-
-#define S5P_FIMV_D_VIDEO_SIGNAL_TYPE 0xF70C
-#define S5P_FIMV_D_CONTENT_LIGHT_LEVEL_INFO_SEI 0xF710
-#define S5P_FIMV_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_0 0xF714
-#define S5P_FIMV_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_1 0xF718
-
-#define S5P_FIMV_D_USED_DPB_FLAG_UPPER 0xF720
-#define S5P_FIMV_D_USED_DPB_FLAG_LOWER 0xF724
-
-#define S5P_FIMV_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_2 0xF728
-#define S5P_FIMV_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_3 0xF72C
-#define S5P_FIMV_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_4 0xF730
-#define S5P_FIMV_D_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_5 0xF734
-
-#define S5P_FIMV_D_BLACK_BAR_START_POS 0xF738
-#define S5P_FIMV_D_BLACK_BAR_IMAGE_SIZE 0xF73C
-
-#define S5P_FIMV_D_DISPLAY_LUMA_ADDR 0xF60C
-#define S5P_FIMV_D_DISPLAY_CHROMA_ADDR 0xF610
-
-#define S5P_FIMV_D_DECODED_LUMA_ADDR 0xF648
-#define S5P_FIMV_D_DECODED_CHROMA_ADDR 0xF64C
-
-/* Encoder Registers */
-#define S5P_FIMV_E_CROPPED_FRAME_WIDTH 0xF778
-#define S5P_FIMV_E_CROPPED_FRAME_HEIGHT 0xF77C
-#define S5P_FIMV_E_FRAME_CROP_OFFSET 0xF780
-#define S5P_FIMV_E_ENC_OPTIONS 0xF784
-#define S5P_FIMV_E_PICTURE_PROFILE 0xF788
-#define S5P_FIMV_E_VBV_BUFFER_SIZE 0xF78C
-#define S5P_FIMV_E_VBV_INIT_DELAY 0xF790
-#define S5P_FIMV_E_FIXED_PICTURE_QP 0xF794
-#define S5P_FIMV_E_RC_CONFIG 0xF798
-#define S5P_FIMV_E_RC_QP_BOUND 0xF79C
-#define S5P_FIMV_E_RC_QP_BOUND_PB 0xF7A0
-#define S5P_FIMV_E_RC_MODE 0xF7A4
-
-#define S5P_FIMV_E_MB_RC_CONFIG 0xF7A8
-#define S5P_FIMV_E_PADDING_CTRL 0xF7AC
-#define S5P_FIMV_E_AIR_THRESHOLD 0xF7B0
-
-#define S5P_FIMV_E_MV_HOR_RANGE 0xF7B4
-#define S5P_FIMV_E_MV_VER_RANGE 0xF7B8
-
-#define S5P_FIMV_E_HIGH_QUALITY_MODE 0xF7C0
-#define S5P_FIMV_E_VIDEO_SIGNAL_TYPE 0xF7C4
-
-#define S5P_FIMV_E_SAO_WEIGHT0 0xF7C8
-#define S5P_FIMV_E_SAO_WEIGHT1 0xF7CC
-
-#define S5P_FIMV_E_NUM_DPB 0xF890
-#define S5P_FIMV_E_MIN_SCRATCH_BUFFER_SIZE 0xF894
-
-#define S5P_FIMV_E_LUMA_DPB 0xF8C0
-#define S5P_FIMV_E_CHROMA_DPB 0xF904
-#define S5P_FIMV_E_ME_BUFFER 0xF948
-
-#define S5P_FIMV_E_SCRATCH_BUFFER_ADDR 0xF98C
-#define S5P_FIMV_E_SCRATCH_BUFFER_SIZE 0xF990
-#define S5P_FIMV_E_TMV_BUFFER0 0xF994
-#define S5P_FIMV_E_TMV_BUFFER1 0xF998
-#define S5P_FIMV_E_IR_BUFFER_ADDR 0xF99C
-#define S5P_FIMV_E_SOURCE_FIRST_2BIT_ADDR 0xF9D0
-#define S5P_FIMV_E_SOURCE_SECOND_2BIT_ADDR 0xF9D4
-#define S5P_FIMV_E_SOURCE_FIRST_2BIT_STRIDE 0xF9D8
-#define S5P_FIMV_E_SOURCE_SECOND_2BIT_STRIDE 0xF9DC
-#define S5P_FIMV_E_SOURCE_FIRST_ADDR 0xF9E0
-#define S5P_FIMV_E_SOURCE_SECOND_ADDR 0xF9E4
-#define S5P_FIMV_E_SOURCE_THIRD_ADDR 0xF9E8
-#define S5P_FIMV_E_SOURCE_FIRST_STRIDE 0xF9EC
-#define S5P_FIMV_E_SOURCE_SECOND_STRIDE 0xF9F0
-#define S5P_FIMV_E_SOURCE_THIRD_STRIDE 0xF9F4
-#define S5P_FIMV_E_STREAM_BUFFER_ADDR 0xF9F8
-#define S5P_FIMV_E_STREAM_BUFFER_SIZE 0xF9FC
-#define S5P_FIMV_E_ROI_BUFFER_ADDR 0xFA00
-
-#define S5P_FIMV_E_PARAM_CHANGE 0xFA04
-#define S5P_FIMV_E_IR_SIZE 0xFA08
-#define S5P_FIMV_E_GOP_CONFIG 0xFA0C
-#define S5P_FIMV_E_MSLICE_MODE 0xFA10
-#define S5P_FIMV_E_MSLICE_SIZE_MB 0xFA14
-#define S5P_FIMV_E_MSLICE_SIZE_BITS 0xFA18
-#define S5P_FIMV_E_FRAME_INSERTION 0xFA1C
-
-#define S5P_FIMV_E_RC_FRAME_RATE 0xFA20
-#define S5P_FIMV_E_RC_BIT_RATE 0xFA24
-#define S5P_FIMV_E_RC_ROI_CTRL 0xFA2C
-#define S5P_FIMV_E_PICTURE_TAG 0xFA30
-#define S5P_FIMV_E_BIT_COUNT_ENABLE 0xFA34
-#define S5P_FIMV_E_MAX_BIT_COUNT 0xFA38
-#define S5P_FIMV_E_MIN_BIT_COUNT 0xFA3C
-
-#define S5P_FIMV_E_METADATA_BUFFER_ADDR 0xFA40
-#define S5P_FIMV_E_METADATA_BUFFER_SIZE 0xFA44
-
-#define S5P_FIMV_E_ENCODING_ORDER_TIME_INFO 0xFA50
-#define S5P_FIMV_E_ENCODING_ORDER_INFO 0xFA54
-#define S5P_FIMV_E_STREAM_BUFFER_OFFSET 0xFA58
-#define S5P_FIMV_E_GOP_CONFIG2 0xFA5C
-#define S5P_FIMV_E_WEIGHT_FOR_WEIGHTED_PREDICTION 0xFA60
-
-#define S5P_FIMV_E_ENCODED_SOURCE_FIRST_ADDR 0xFA70
-#define S5P_FIMV_E_ENCODED_SOURCE_SECOND_ADDR 0xFA74
-#define S5P_FIMV_E_ENCODED_SOURCE_THIRD_ADDR 0xFA78
-
-#define S5P_FIMV_E_STREAM_SIZE 0xFA80
-#define S5P_FIMV_E_SLICE_TYPE 0xFA84
-#define S5P_FIMV_E_PICTURE_COUNT 0xFA88
-#define S5P_FIMV_E_RET_PICTURE_TAG 0xFA8C
-
-#define S5P_FIMV_E_RECON_LUMA_DPB_ADDR 0xFA9C
-#define S5P_FIMV_E_RECON_CHROMA_DPB_ADDR 0xFAA0
-#define S5P_FIMV_E_METADATA_ADDR_ENC_SLICE 0xFAA4
-#define S5P_FIMV_E_METADATA_SIZE_ENC_SLICE 0xFAA8
-
-#define S5P_FIMV_E_NAL_DONE_INFO 0xFAEC
-
-#define S5P_FIMV_E_MPEG4_OPTIONS 0xFB10
-#define S5P_FIMV_E_MPEG4_HEC_PERIOD 0xFB14
-
-#define S5P_FIMV_E_BPG_OPTIONS 0xFB1C
-#define S5P_FIMV_E_BPG_EXT_CTB_QP_CTRL 0xFB20
-#define S5P_FIMV_E_BPG_CHROMA_QP_OFFSET 0xFB24
-#define S5P_FIMV_E_BPG_EXTENSION_DATA_SIZE 0xFB28
-
-#define S5P_FIMV_E_H264_HD_SVC_EXTENSION_0 0xFB44
-#define S5P_FIMV_E_H264_HD_SVC_EXTENSION_1 0xFB48
-#define S5P_FIMV_E_ASPECT_RATIO 0xFB4C
-#define S5P_FIMV_E_EXTENDED_SAR 0xFB50
-
-#define S5P_FIMV_E_H264_OPTIONS 0xFB54
-#define S5P_FIMV_E_H264_OPTIONS_2 0xFB58
-#define S5P_FIMV_E_H264_LF_ALPHA_OFFSET 0xFB5C
-#define S5P_FIMV_E_H264_LF_BETA_OFFSET 0xFB60
-#define S5P_FIMV_E_H264_REFRESH_PERIOD 0xFB64
-
-#define S5P_FIMV_E_H264_FMO_SLICE_GRP_MAP_TYPE 0xFB68
-#define S5P_FIMV_E_H264_FMO_NUM_SLICE_GRP_MINUS1 0xFB6C
-#define S5P_FIMV_E_H264_FMO_SLICE_GRP_CHANGE_DIR 0xFB70
-#define S5P_FIMV_E_H264_FMO_SLICE_GRP_CHANGE_RATE_MINUS1 0xFB74
-#define S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_0 0xFB78
-#define S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_1 0xFB7C
-#define S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_2 0xFB80
-#define S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_3 0xFB84
-
-#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_0 0xFB88
-#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_1 0xFB8C
-#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_2 0xFB90
-#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_3 0xFB94
-#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_4 0xFB98
-#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_5 0xFB9C
-#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_6 0xFBA0
-#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_7 0xFBA4
-#define S5P_FIMV_E_H264_CHROMA_QP_OFFSET 0xFBA8
-
-#define S5P_FIMV_E_NUM_T_LAYER 0xFBAC
-#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER0 0xFBB0
-#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER1 0xFBB4
-#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER2 0xFBB8
-#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER3 0xFBBC
-#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER4 0xFBC0
-#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER5 0xFBC4
-#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER6 0xFBC8
-
-/* For backward compatibility */
-#define S5P_FIMV_E_H264_FRAME_PACKING_SEI_INFO 0xFC4C
-
-#define S5P_FIMV_E_H264_NAL_CONTROL 0xFD14
-#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER0 0xFD18
-#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER1 0xFD1C
-#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER2 0xFD20
-#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER3 0xFD24
-#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER4 0xFD28
-#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER5 0xFD2C
-#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER6 0xFD30
-
-#define S5P_FIMV_E_MVC_FRAME_QP_VIEW1 0xFD40
-#define S5P_FIMV_E_MVC_RC_FRAME_RATE_VIEW1 0xFD44
-#define S5P_FIMV_E_MVC_RC_BIT_RATE_VIEW1 0xFD48
-#define S5P_FIMV_E_MVC_RC_QBOUND_VIEW1 0xFD4C
-#define S5P_FIMV_E_MVC_RC_MODE_VIEW1 0xFD50
-#define S5P_FIMV_E_MVC_INTER_VIEW_PREDICTION_ON 0xFD80
-
-#define S5P_FIMV_E_VP9_OPTION 0xFD90
-#define S5P_FIMV_E_VP9_FILTER_OPTION 0xFD94
-#define S5P_FIMV_E_VP9_GOLDEN_FRAME_OPTION 0xFD98
-#define S5P_FIMV_E_VP8_OPTION 0xFDB0
-#define S5P_FIMV_E_VP8_FILTER_OPTION 0xFDB4
-#define S5P_FIMV_E_VP8_GOLDEN_FRAME_OPTION 0xFDB8
-
-#define S5P_FIMV_E_HEVC_OPTIONS_2 0xFDC4
-
-#define S5P_FIMV_E_HEVC_OPTIONS 0xFDD4
-#define S5P_FIMV_E_HEVC_REFRESH_PERIOD 0xFDD8
-#define S5P_FIMV_E_HEVC_CHROMA_QP_OFFSET 0xFDDC
-#define S5P_FIMV_E_HEVC_LF_BETA_OFFSET_DIV2 0xFDE0
-#define S5P_FIMV_E_HEVC_LF_TC_OFFSET_DIV2 0xFDE4
-#define S5P_FIMV_E_HEVC_NAL_CONTROL 0xFDE8
-
-#define S5P_FIMV_E_VP8_NAL_CONTROL 0xFDF0
-#define S5P_FIMV_E_VP9_NAL_CONTROL 0xFDF4
-#define S5P_FIMV_E_CONTENT_LIGHT_LEVEL_INFO_SEI 0xFDF8
-#define S5P_FIMV_E_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_0 0xFDFC
-#define S5P_FIMV_E_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_1 0xFE00
-#define S5P_FIMV_E_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_2 0xFE04
-#define S5P_FIMV_E_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_3 0xFE08
-#define S5P_FIMV_E_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_4 0xFE0C
-#define S5P_FIMV_E_MASTERING_DISPLAY_COLOUR_VOLUME_SEI_5 0xFE10
-
-
-#define S5P_FIMV_REG_CLEAR_BEGIN 0xf000
-#define S5P_FIMV_REG_CLEAR_COUNT 1024
-
-
-/* Bit Definitions */
-/* 0x1100: S5P_FIMV_HOST2RISC_CMD */
-#define S5P_FIMV_H2R_CMD_EMPTY 0
-#define S5P_FIMV_H2R_CMD_SYS_INIT 1
-#define S5P_FIMV_H2R_CMD_OPEN_INSTANCE 2
-#define S5P_FIMV_H2R_CMD_SEQ_HEADER 3
-#define S5P_FIMV_H2R_CMD_INIT_BUFFERS 4
-#define S5P_FIMV_H2R_CMD_NAL_START 5
-#define S5P_FIMV_H2R_CMD_CLOSE_INSTANCE 6
-#define S5P_FIMV_H2R_CMD_SLEEP 7
-#define S5P_FIMV_H2R_CMD_WAKEUP 8
-#define S5P_FIMV_H2R_CMD_LAST_FRAME 9
-#define S5P_FIMV_H2R_CMD_DPB_FLUSH 10
-#define S5P_FIMV_H2R_CMD_NAL_ABORT 11
-#define S5P_FIMV_H2R_CMD_CACHE_FLUSH 12
-#define S5P_FIMV_H2R_CMD_NAL_QUEUE 13
-#define S5P_FIMV_H2R_CMD_STOP_QUEUE 14
-
-
-/* 0x1104: S5P_FIMV_RISC2HOST_CMD */
-#define S5P_FIMV_RISC2HOST_CMD_MASK 0x1FFFF
-#define S5P_FIMV_R2H_CMD_EMPTY 0
-#define S5P_FIMV_R2H_CMD_SYS_INIT_RET 1
-#define S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET 2
-#define S5P_FIMV_R2H_CMD_SEQ_DONE_RET 3
-#define S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET 4
-#define S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET 6
-#define S5P_FIMV_R2H_CMD_SLEEP_RET 7
-#define S5P_FIMV_R2H_CMD_WAKEUP_RET 8
-#define S5P_FIMV_R2H_CMD_COMPLETE_SEQ_RET 9
-#define S5P_FIMV_R2H_CMD_DPB_FLUSH_RET 10
-#define S5P_FIMV_R2H_CMD_NAL_ABORT_RET 11
-#define S5P_FIMV_R2H_CMD_FW_STATUS_RET 12
-#define S5P_FIMV_R2H_CMD_FRAME_DONE_RET 13
-#define S5P_FIMV_R2H_CMD_FIELD_DONE_RET 14
-#define S5P_FIMV_R2H_CMD_SLICE_DONE_RET 15
-#define S5P_FIMV_R2H_CMD_ENC_BUFFER_FULL_RET 16
-#define S5P_FIMV_R2H_CMD_QUEUE_DONE_RET 17
-#define S5P_FIMV_R2H_CMD_COMPLETE_QUEUE_RET 18
-#define S5P_FIMV_R2H_CMD_CACHE_FLUSH_RET 20
-#define S5P_FIMV_R2H_CMD_ERR_RET 32
-
-
-/* 0xF000: S5P_FIMV_FW_VERSION */
-#define S5P_FIMV_FW_VER_INFO_MASK 0xFF
-#define S5P_FIMV_FW_VER_INFO_SHFT 24
-#define S5P_FIMV_FW_VER_YEAR_MASK 0xFF
-#define S5P_FIMV_FW_VER_YEAR_SHFT 16
-#define S5P_FIMV_FW_VER_MONTH_MASK 0xFF
-#define S5P_FIMV_FW_VER_MONTH_SHFT 8
-#define S5P_FIMV_FW_VER_DATE_MASK 0xFF
-#define S5P_FIMV_FW_VER_DATE_SHFT 0
-#define S5P_FIMV_FW_VER_ALL_MASK 0xFFFFFF
-#define S5P_FIMV_FW_VER_ALL_SHFT 0
-
-
-/* 0xF00C: S5P_FIMV_CODEC_TYPE */
-#define MFC_FORMATS_NO_CODEC -1
-/* Decoder */
-#define S5P_FIMV_CODEC_H264_DEC 0
-#define S5P_FIMV_CODEC_H264_MVC_DEC 1
-#define S5P_FIMV_CODEC_MPEG4_DEC 3
-#define S5P_FIMV_CODEC_FIMV1_DEC 4
-#define S5P_FIMV_CODEC_FIMV2_DEC 5
-#define S5P_FIMV_CODEC_FIMV3_DEC 6
-#define S5P_FIMV_CODEC_FIMV4_DEC 7
-#define S5P_FIMV_CODEC_H263_DEC 8
-#define S5P_FIMV_CODEC_VC1_RCV_DEC 9
-#define S5P_FIMV_CODEC_VC1_DEC 10
-#define S5P_FIMV_CODEC_MPEG2_DEC 13
-#define S5P_FIMV_CODEC_VP8_DEC 14
-#define S5P_FIMV_CODEC_HEVC_DEC 17
-#define S5P_FIMV_CODEC_VP9_DEC 18
-/* Encoder */
-#define S5P_FIMV_CODEC_H264_ENC 20
-#define S5P_FIMV_CODEC_H264_MVC_ENC 21
-#define S5P_FIMV_CODEC_MPEG4_ENC 23
-#define S5P_FIMV_CODEC_H263_ENC 24
-#define S5P_FIMV_CODEC_VP8_ENC 25
-#define S5P_FIMV_CODEC_HEVC_ENC 26
-#define S5P_FIMV_CODEC_VP9_ENC 27
-
-#define S5P_FIMV_CODEC_BPG_DEC 32
-#define S5P_FIMV_CODEC_BPG_ENC 33
-
-/* 0xF028: S5P_FIMV_MFC_VERSION */
-#define S5P_FIMV_MFC_VER_MASK 0xFFFFFFFF
-#define S5P_FIMV_MFC_VER_SHFT 0
-
-
-/* 0xF074: S5P_FIMV_ERROR_CODE */
-#define S5P_FIMV_ERR_STATUS_MASK 0xFFFF
-#define S5P_FIMV_ERR_STATUS_SHIFT 0
-#define S5P_FIMV_WARN_STATUS_MASK 0xFFFF
-#define S5P_FIMV_WARN_STATUS_SHIFT 16
-/* Error number */
-#define S5P_FIMV_ERR_BUFFER_FULL 18
-#define S5P_FIMV_ERR_NO_AVAILABLE_DPB 33
-#define S5P_FIMV_ERR_NO_KEY_FRAME 34
-#define S5P_FIMV_ERR_VPS_ONLY_ERROR 42
-#define S5P_FIMV_ERR_INSUFFICIENT_DPB_SIZE 57
-#define S5P_FIMV_ERR_INSUFFICIENT_NUM_DPB 58
-#define S5P_FIMV_ERR_INSUFFICIENT_MV_BUF_SIZE 60
-#define S5P_FIMV_ERR_NULL_SCRATCH 61
-#define S5P_FIMV_ERR_INSUFFICIENT_SCRATCH_BUF_SIZE 62
-
-#define S5P_FIMV_ERR_UNSUPPORTED_FEATURE 100
-#define S5P_FIMV_ERR_UNSUPPORTED_RESOLUTION 101
-#define S5P_FIMV_ERR_HEADER_NOT_FOUND 102
-#define S5P_FIMV_ERR_INVAILD_NAL_TYPE 103
-#define S5P_FIMV_ERR_SEQUENCE_HEADER 104
-#define S5P_FIMV_ERR_MFC_TIMEOUT 140
-#define S5P_FIMV_ERR_TS_MUX_TIMEOUT 141
-#define S5P_FIMV_ERR_G2D_TIMEOUT 142
-#define S5P_FIMV_ERR_FRAME_CONCEAL 150
-#define S5P_FIMV_ERR_WARNINGS_START 160
-#define S5P_FIMV_ERR_BROKEN_LINK 161
-#define S5P_FIMV_ERR_SYNC_POINT_NOT_RECEIVED 190
-#define S5P_FIMV_ERR_NON_PAIRED_FIELD 191
-#define S5P_FIMV_ERR_WARNINGS_END 222
-
-
-/* 0xF0B4: S5P_FIMV_D_DEC_OPTIONS */
-#define S5P_FIMV_D_DEC_OPT_DISPLAY_DELAY_EN_SHIFT 3
-#define S5P_FIMV_D_DEC_OPT_FMO_ASO_CTRL_MASK 0x1
-#define S5P_FIMV_D_DEC_OPT_FMO_ASO_CTRL_SHIFT 4
-#define S5P_FIMV_D_DEC_OPT_IDR_DECODING_MASK 0x1
-#define S5P_FIMV_D_DEC_OPT_IDR_DECODING_SHIFT 6
-#define S5P_FIMV_D_DEC_OPT_DISCARD_RCV_HEADER_SHIFT 7
-#define S5P_FIMV_D_DEC_OPT_CONCEAL_CONTROL_SHIFT 8
-#define S5P_FIMV_D_DEC_OPT_PARALLEL_DISABLE_SHIFT 11
-#define S5P_FIMV_D_DEC_OPT_REALLOC_CONTROL_SHIFT 13
-#define S5P_FIMV_D_DEC_OPT_SPECIAL_PARSING_SHIFT 15
-#define S5P_FIMV_D_DEC_OPT_THUMBNAIL_DECODING 16
-
-
-/* 0xF0C4: S5P_FIMV_D_SEI_ENABLE */
-#define S5P_FIMV_D_SEI_ENABLE_NEED_INIT_BUFFER_SHIFT 1
-#define S5P_FIMV_D_SEI_ENABLE_RECOVERY_PARSING_SHIFT 2
-#define S5P_FIMV_D_SEI_ENABLE_CONTENT_LIGHT_SHIFT 4
-#define S5P_FIMV_D_SEI_ENABLE_MASTERING_DISPLAY_SHIFT 5
-
-
-/* 0xF154: S5P_FIMV_D_INIT_BUFFER_OPTIONS */
-#define S5P_FIMV_D_INIT_BUF_OPT_LF_CTRL_MASK 0x3
-#define S5P_FIMV_D_INIT_BUF_OPT_LF_CTRL_SHIFT 1
-#define S5P_FIMV_D_INIT_BUF_OPT_DYNAMIC_DPB_SET_SHIFT 3
-#define S5P_FIMV_D_INIT_BUF_OPT_COPY_NOT_CODED_SHIFT 4
-#define S5P_FIMV_D_INIT_BUF_OPT_DITHERING_EN_SHIFT 6
-#define S5P_FIMV_D_INIT_BUF_OPT_STRIDE_SIZE_ALIGN 7
-
-
-/* 0xF5AC: S5P_FIMV_D_NAL_START_OPTIONS */
-#define S5P_FIMV_D_NAL_START_OPT_BLACK_BAR_SHIFT 3
-
-
-/* 0xF608: S5P_FIMV_D_DISPLAY_STATUS */
-#define S5P_FIMV_DISP_STATUS_DISPLAY_STATUS_MASK 0x7
-#define S5P_FIMV_DISP_STATUS_INTERLACE_MASK 0x1
-#define S5P_FIMV_DISP_STATUS_INTERLACE_SHIFT 3
-#define S5P_FIMV_DISP_STATUS_RES_CHANGE_MASK 0x3
-#define S5P_FIMV_DISP_STATUS_RES_CHANGE_SHIFT 4
-#define S5P_FIMV_DISP_STATUS_NEED_DPB_CHANGE_MASK 0x1
-#define S5P_FIMV_DISP_STATUS_NEED_DPB_CHANGE_SHIFT 9
-#define S5P_FIMV_DISP_STATUS_NEED_SCRATCH_CHANGE_MASK 0x1
-#define S5P_FIMV_DISP_STATUS_NEED_SCRATCH_CHANGE_SHIFT 10
-#define S5P_FIMV_DISP_STATUS_NEED_EMPTY_DPB_MASK 0x1
-#define S5P_FIMV_DISP_STATUS_NEED_EMPTY_DPB_SHIFT 12
-#define S5P_FIMV_DISP_STATUS_BLACK_BAR_DETECT_MASK 0x3
-#define S5P_FIMV_DISP_STATUS_BLACK_BAR_DETECT_SHIFT 13
-#define S5P_FIMV_DISP_STATUS_NOT_DETECTED 0x0
-#define S5P_FIMV_DISP_STATUS_BLACK_BAR 0x1
-#define S5P_FIMV_DISP_STATUS_BLACK_SCREEN 0x2
-
-
-/* 0xF618: S5P_FIMV_D_DISPLAY_FRAME_TYPE */
-#define S5P_FIMV_DISPLAY_FRAME_MASK 0x7
-#define S5P_FIMV_DISPLAY_TEMP_INFO_MASK 0x1
-#define S5P_FIMV_DISPLAY_TEMP_INFO_SHIFT 7
-#define S5P_FIMV_DISPLAY_FRAME_NOT_CODED 0
-#define S5P_FIMV_DISPLAY_FRAME_I 1
-#define S5P_FIMV_DISPLAY_FRAME_P 2
-#define S5P_FIMV_DISPLAY_FRAME_B 3
-
-
-/* 0xF61C: S5P_FIMV_D_DISPLAY_CROP_INFO1 */
-#define S5P_FIMV_D_SHARED_CROP_LEFT_MASK 0xFFFF
-#define S5P_FIMV_D_SHARED_CROP_RIGHT_SHIFT 16
-
-
-/* 0xF620: S5P_FIMV_D_DISPLAY_CROP_INFO2 */
-#define S5P_FIMV_D_SHARED_CROP_TOP_MASK 0xFFFF
-#define S5P_FIMV_D_SHARED_CROP_BOTTOM_SHIFT 16
-
-
-/* 0xF644: S5P_FIMV_D_DECODED_STATUS */
-#define S5P_FIMV_DEC_STATUS_DECODED_STATUS_MASK 0x7
-#define S5P_FIMV_DEC_STATUS_DECODING_ONLY 0
-#define S5P_FIMV_DEC_STATUS_DECODING_DISPLAY 1
-#define S5P_FIMV_DEC_STATUS_DISPLAY_ONLY 2
-#define S5P_FIMV_DEC_STATUS_DECODING_EMPTY 3
-#define S5P_FIMV_DEC_STATUS_NUM_OF_TILE_MASK 0xF
-#define S5P_FIMV_DEC_STATUS_NUM_OF_TILE_SHIFT 15
-
-
-/* 0xF654: S5P_FIMV_D_DECODED_FRAME_TYPE */
-#define S5P_FIMV_DECODED_FRAME_MASK 0x7
-#define S5P_FIMV_DECODED_FRAME_NOT_CODED 0
-#define S5P_FIMV_DECODED_FRAME_I 1
-#define S5P_FIMV_DECODED_FRAME_P 2
-#define S5P_FIMV_DECODED_FRAME_B 3
-
-
-/* 0xF660: S5P_FIMV_D_DECODED_PICTURE_PROFILE */
-#define S5P_FIMV_D_DECODED_PIC_PROFILE_MASK 0x1F
-#define S5P_FIMV_D_BIT_DEPTH_CHROMA_MINUS8_MASK 0x7
-#define S5P_FIMV_D_BIT_DEPTH_CHROMA_MINUS8_SHIFT 19
-#define S5P_FIMV_D_BIT_DEPTH_LUMA_MINUS8_MASK 0x7
-#define S5P_FIMV_D_BIT_DEPTH_LUMA_MINUS8_SHIFT 16
-#define S5P_FIMV_D_PROFILE_HEVC_MAIN 1
-#define S5P_FIMV_D_PROFILE_HEVC_MAIN_10 2
-#define S5P_FIMV_D_PROFILE_HEVC_RANGE_EXT 4
-
-
-/* 0xF684: S5P_FIMV_D_CHROMA_FORMAT */
-#define S5P_FIMV_D_CHROMA_FORMAT_MASK 0x3
-#define S5P_FIMV_D_COLOR_RANGE_MASK 0x1
-#define S5P_FIMV_D_COLOR_RANGE_SHIFT 3
-#define S5P_FIMV_D_COLOR_SPACE_MASK 0xF
-#define S5P_FIMV_D_COLOR_SPACE_SHIFT 4
-#define S5P_FIMV_D_COLOR_UNKNOWN 0
-#define S5P_FIMV_D_CHROMA_400 0
-#define S5P_FIMV_D_CHROMA_420 1
-#define S5P_FIMV_D_CHROMA_422 2
-#define S5P_FIMV_D_CHROMA_444 3
-
-
-/* 0xF690: S5P_FIMV_D_H264_INFO */
-#define S5P_FIMV_D_H264_INFO_MBAFF_FRAME_FLAG_SHIFT 9
-#define S5P_FIMV_D_H264_INFO_MBAFF_FRAME_FLAG_MASK 0x1
-
-
-/* 0xF6D8: S5P_FIMV_D_MVC_VIEW_ID */
-#define S5P_FIMV_D_MVC_VIEW_ID_DISP_MASK 0xFFFF
-
-
-/* 0xF6DC: S5P_FIMV_D_SEI_AVAIL */
-#define S5P_FIMV_D_SEI_AVAIL_FRAME_PACK_MASK 0x1
-#define S5P_FIMV_D_SEI_AVAIL_CONTENT_LIGHT_MASK 0x1
-#define S5P_FIMV_D_SEI_AVAIL_CONTENT_LIGHT_SHIFT 1
-#define S5P_FIMV_D_SEI_AVAIL_MASTERING_DISPLAY_MASK 0x1
-#define S5P_FIMV_D_SEI_AVAIL_MASTERING_DISPLAY_SHIFT 2
-
-
-/* 0xF70C: S5P_FIMV_D_VIDEO_SIGNAL_TYPE */
-#define S5P_FIMV_D_VIDEO_SIGNAL_TYPE_FLAG_MASK 0x1
-#define S5P_FIMV_D_VIDEO_SIGNAL_TYPE_FLAG_SHIFT 29
-#define S5P_FIMV_D_COLOUR_DESCRIPTION_FLAG_MASK 0x1
-#define S5P_FIMV_D_COLOUR_DESCRIPTION_FLAG_SHIFT 24
-
-
-/* 0xF738: S5P_FIMV_D_BLACK_BAR_START_POS */
-#define S5P_FIMV_D_BLACK_BAR_START_X_SHIFT 0
-#define S5P_FIMV_D_BLACK_BAR_START_X_MASK 0xFFFF
-#define S5P_FIMV_D_BLACK_BAR_START_Y_SHIFT 16
-#define S5P_FIMV_D_BLACK_BAR_START_Y_MASK 0xFFFF
-
-
-/* 0xF73C: S5P_FIMV_D_BLACK_BAR_IMAGE_SIZE */
-#define S5P_FIMV_D_BLACK_BAR_IMAGE_W_SHIFT 0
-#define S5P_FIMV_D_BLACK_BAR_IMAGE_W_MASK 0xFFFF
-#define S5P_FIMV_D_BLACK_BAR_IMAGE_H_SHIFT 16
-#define S5P_FIMV_D_BLACK_BAR_IMAGE_H_MASK 0xFFFF
-
-
-/* 0xF780: S5P_FIMV_E_FRAME_CROP_OFFSET */
-#define S5P_FIMV_E_FRAME_CROP_OFFSET_TOP 16
-#define S5P_FIMV_E_FRAME_CROP_OFFSET_LEFT 0
-#define S5P_FIMV_E_FRAME_CROP_OFFSET_MASK 0x3FFF
-
-
-/* 0xF788: S5P_FIMV_E_PICTURE_PROFILE */
-#define S5P_FIMV_E_PROFILE_H264_BASELINE 0
-#define S5P_FIMV_E_PROFILE_H264_MAIN 1
-#define S5P_FIMV_E_PROFILE_H264_HIGH 2
-#define S5P_FIMV_E_PROFILE_H264_CONSTRAINED_BASELINE 3
-#define S5P_FIMV_E_PROFILE_H264_CONSTRAINED_HIGH 5
-#define S5P_FIMV_E_PROFILE_MPEG4_SIMPLE 0
-#define S5P_FIMV_E_PROFILE_MPEG4_ADVANCED_SIMPLE 1
-#define S5P_FIMV_E_PROFILE_HEVC_MAIN_422_10_INTRA 2
-#define S5P_FIMV_E_PROFILE_HEVC_MAIN_10 3
-#define S5P_FIMV_E_PROFILE_HEVC_MAIN_422_10 4
-#define S5P_FIMV_E_PROFILE_VP9_PROFILE0 0
-#define S5P_FIMV_E_PROFILE_VP9_PROFILE1 1
-#define S5P_FIMV_E_PROFILE_VP9_PROFILE2 2
-#define S5P_FIMV_E_PROFILE_VP9_PROFILE3 3
-
-
-/* 0xF7A4: S5P_FIMV_E_RC_MODE */
-#define S5P_FIMV_E_RC_CBR_FIX 0
-#define S5P_FIMV_E_RC_CBR_VAR 1
-#define S5P_FIMV_E_RC_VBR 2
-#define S5P_FIMV_E_RC_CBR_I_LIMIT 3
-
-
-/* 0xFA84: S5P_FIMV_E_SLICE_TYPE */
-#define S5P_FIMV_E_SLICE_TYPE_NOT_CODED 0
-#define S5P_FIMV_E_SLICE_TYPE_I 1
-#define S5P_FIMV_E_SLICE_TYPE_P 2
-#define S5P_FIMV_E_SLICE_TYPE_B 3
-#define S5P_FIMV_E_SLICE_TYPE_SKIPPED 4
-
-
-#endif /* __REGS_MFC_V10_H */
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_intr.c
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include "s5p_mfc_sync.h"
-
-#include "s5p_mfc_cal.h"
-#include "s5p_mfc_perf_measure.h"
-
-#include "s5p_mfc_queue.h"
-
-#define R2H_BIT(x) (((x) > 0) ? (1 << ((x) - 1)) : 0)
-
-static inline unsigned int mfc_r2h_bit_mask(int cmd)
-{
- unsigned int mask = R2H_BIT(cmd);
-
- if (cmd == S5P_FIMV_R2H_CMD_FRAME_DONE_RET)
- mask |= (R2H_BIT(S5P_FIMV_R2H_CMD_FIELD_DONE_RET) |
- R2H_BIT(S5P_FIMV_R2H_CMD_COMPLETE_SEQ_RET) |
- R2H_BIT(S5P_FIMV_R2H_CMD_SLICE_DONE_RET) |
- R2H_BIT(S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET) |
- R2H_BIT(S5P_FIMV_R2H_CMD_ENC_BUFFER_FULL_RET));
- /* FIXME: Temporal mask for S3D SEI processing */
- else if (cmd == S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET)
- mask |= (R2H_BIT(S5P_FIMV_R2H_CMD_FIELD_DONE_RET) |
- R2H_BIT(S5P_FIMV_R2H_CMD_SLICE_DONE_RET) |
- R2H_BIT(S5P_FIMV_R2H_CMD_FRAME_DONE_RET));
-
- return (mask |= R2H_BIT(S5P_FIMV_R2H_CMD_ERR_RET));
-}
-
-#define wait_condition(x, c) (x->int_condition && \
- (R2H_BIT(x->int_reason) & mfc_r2h_bit_mask(c)))
-#define is_err_cond(x) ((x->int_condition) && (x->int_reason == S5P_FIMV_R2H_CMD_ERR_RET))
-
-/*
- * Return value description
- * 0: waked up before timeout
- * 1: failed to get the response for the command before timeout
-*/
-int s5p_mfc_wait_for_done_dev(struct s5p_mfc_dev *dev, int command)
-{
- int ret;
-
- ret = wait_event_timeout(dev->cmd_wq,
- wait_condition(dev, command),
- msecs_to_jiffies(MFC_INT_TIMEOUT));
- if (ret == 0) {
- mfc_err_dev("Interrupt (dev->int_reason:%d, command:%d) timed out\n",
- dev->int_reason, command);
- if (s5p_mfc_check_risc2host(dev)) {
- ret = wait_event_timeout(dev->cmd_wq,
- wait_condition(dev, command),
- msecs_to_jiffies(MFC_INT_TIMEOUT * MFC_INT_TIMEOUT_CNT));
- if (ret == 0) {
- mfc_err_dev("Timeout: MFC driver waited for upward of %dsec\n",
- 3 * MFC_INT_TIMEOUT);
- } else {
- goto wait_done;
- }
- }
- call_dop(dev, dump_and_stop_debug_mode, dev);
- return 1;
- }
-
-wait_done:
- mfc_debug(2, "Finished waiting (dev->int_reason:%d, command: %d)\n",
- dev->int_reason, command);
- return 0;
-}
-
-/*
- * Return value description
- * 0: waked up before timeout
- * 1: failed to get the response for the command before timeout
- * -1: got the error response for the command before timeout
-*/
-int s5p_mfc_wait_for_done_ctx(struct s5p_mfc_ctx *ctx, int command)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- int ret;
- unsigned int timeout = MFC_INT_TIMEOUT;
-
- if (command == S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET)
- timeout = MFC_INT_SHORT_TIMEOUT;
-
- ret = wait_event_timeout(ctx->cmd_wq,
- wait_condition(ctx, command),
- msecs_to_jiffies(timeout));
- if (ret == 0) {
- mfc_err_ctx("Interrupt (ctx->int_reason:%d, command:%d) timed out\n",
- ctx->int_reason, command);
- if (s5p_mfc_check_risc2host(dev)) {
- ret = wait_event_timeout(ctx->cmd_wq,
- wait_condition(ctx, command),
- msecs_to_jiffies(MFC_INT_TIMEOUT * MFC_INT_TIMEOUT_CNT));
- if (ret == 0) {
- mfc_err_dev("Timeout: MFC driver waited for upward of %dsec\n",
- 3 * MFC_INT_TIMEOUT);
- } else {
- goto wait_done;
- }
- }
- call_dop(dev, dump_and_stop_debug_mode, dev);
- return 1;
- }
-
-wait_done:
- if (is_err_cond(ctx)) {
- mfc_err_ctx("Finished (ctx->int_reason:%d, command: %d)\n",
- ctx->int_reason, command);
- mfc_err_ctx("But error (ctx->int_err:%d)\n", ctx->int_err);
- call_dop(dev, dump_and_stop_debug_mode, dev);
- return -1;
- }
-
- mfc_debug(2, "Finished waiting (ctx->int_reason:%d, command: %d)\n",
- ctx->int_reason, command);
- return 0;
-}
-
-/* Wake up device wait_queue */
-void s5p_mfc_wake_up_dev(struct s5p_mfc_dev *dev, unsigned int reason,
- unsigned int err)
-{
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return;
- }
-
- dev->int_condition = 1;
- dev->int_reason = reason;
- dev->int_err = err;
- wake_up(&dev->cmd_wq);
-}
-
-/* Wake up context wait_queue */
-void s5p_mfc_wake_up_ctx(struct s5p_mfc_ctx *ctx, unsigned int reason,
- unsigned int err)
-{
- if (!ctx) {
- mfc_err_dev("no mfc context to run\n");
- return;
- }
-
- ctx->int_condition = 1;
- ctx->int_reason = reason;
- ctx->int_err = err;
- wake_up(&ctx->cmd_wq);
-}
-
-int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev)
-{
- unsigned long wflags;
- int new_ctx_index = 0;
- int cnt = 0;
- int i;
-
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return -EINVAL;
- }
-
- spin_lock_irqsave(&dev->work_bits.lock, wflags);
-
- mfc_debug(2, "Previous context: %d (bits %08lx)\n", dev->curr_ctx,
- dev->work_bits.bits);
-
- if (dev->preempt_ctx > MFC_NO_INSTANCE_SET) {
- new_ctx_index = dev->preempt_ctx;
- mfc_debug(2, "preempt_ctx is : %d\n", new_ctx_index);
- } else {
- for (i = 0; i < MFC_NUM_CONTEXTS; i++) {
- if (dev->ctx[i] && dev->ctx[i]->otf_handle) {
- if (test_bit(i, &dev->work_bits.bits)) {
- spin_unlock_irqrestore(&dev->work_bits.lock, wflags);
- return i;
- }
- break;
- }
- }
-
- new_ctx_index = (dev->curr_ctx + 1) % MFC_NUM_CONTEXTS;
- while (!test_bit(new_ctx_index, &dev->work_bits.bits)) {
- new_ctx_index = (new_ctx_index + 1) % MFC_NUM_CONTEXTS;
- cnt++;
- if (cnt > MFC_NUM_CONTEXTS) {
- /* No contexts to run */
- spin_unlock_irqrestore(&dev->work_bits.lock, wflags);
- return -EAGAIN;
- }
- }
- }
-
- spin_unlock_irqrestore(&dev->work_bits.lock, wflags);
- return new_ctx_index;
-}
-
-/* Check whether a context should be run on hardware */
-int s5p_mfc_dec_ctx_ready(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- int src_buf_queue_greater_than_0 = 0;
- int dst_buf_queue_greater_than_0 = 0;
- int ref_buf_queue_same_dpb_count_plus_5 = 0;
-
- mfc_debug(1, "[c:%d] src = %d, dst = %d, src_nal = %d, dst_nal = %d, ref = %d, state = %d, capstat = %d\n",
- ctx->num, s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->src_buf_queue),
- s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->dst_buf_queue),
- s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->src_buf_nal_queue),
- s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->dst_buf_nal_queue),
- s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->ref_buf_queue),
- ctx->state, ctx->capture_state);
- mfc_debug(2, "wait_state = %d\n", ctx->wait_state);
-
- src_buf_queue_greater_than_0
- = s5p_mfc_is_queue_count_greater(&ctx->buf_queue_lock, &ctx->src_buf_queue, 0);
- dst_buf_queue_greater_than_0
- = s5p_mfc_is_queue_count_greater(&ctx->buf_queue_lock, &ctx->dst_buf_queue, 0);
- ref_buf_queue_same_dpb_count_plus_5
- = s5p_mfc_is_queue_count_same(&ctx->buf_queue_lock, &ctx->ref_buf_queue, (ctx->dpb_count + 5));
-
- /* If shutdown is called, do not try any cmd */
- if (dev->shutdown)
- return 0;
-
- /* Context is to parse header */
- if (ctx->state == MFCINST_GOT_INST &&
- src_buf_queue_greater_than_0)
- return 1;
-
- /* Context is to decode a frame */
- if (ctx->state == MFCINST_RUNNING &&
- ctx->wait_state == WAIT_NONE && src_buf_queue_greater_than_0 &&
- (dst_buf_queue_greater_than_0 || ref_buf_queue_same_dpb_count_plus_5))
- return 1;
-
- /* Context is to return last frame */
- if (ctx->state == MFCINST_FINISHING &&
- (dst_buf_queue_greater_than_0 || ref_buf_queue_same_dpb_count_plus_5))
- return 1;
-
- /* Context is to set buffers */
- if (ctx->state == MFCINST_HEAD_PARSED &&
- (dst_buf_queue_greater_than_0 && ctx->wait_state == WAIT_NONE))
- return 1;
-
- /* Resolution change */
- if ((ctx->state == MFCINST_RES_CHANGE_INIT || ctx->state == MFCINST_RES_CHANGE_FLUSH) &&
- dst_buf_queue_greater_than_0)
- return 1;
-
- if (ctx->state == MFCINST_RES_CHANGE_END &&
- src_buf_queue_greater_than_0)
- return 1;
-
- s5p_mfc_perf_cancel_drv_margin(dev);
- mfc_debug(2, "ctx is not ready\n");
-
- return 0;
-}
-
-int s5p_mfc_enc_ctx_ready(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_enc *enc = ctx->enc_priv;
- struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_enc_params *p = &enc->params;
- int src_buf_queue_greater_than_0 = 0;
- int dst_buf_queue_greater_than_0 = 0;
-
- mfc_debug(1, "[c:%d] src = %d, dst = %d, src_nal = %d, dst_nal = %d, ref = %d, state = %d\n",
- ctx->num, s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->src_buf_queue),
- s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->dst_buf_queue),
- s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->src_buf_nal_queue),
- s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->dst_buf_nal_queue),
- s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->ref_buf_queue),
- ctx->state);
-
- src_buf_queue_greater_than_0
- = s5p_mfc_is_queue_count_greater(&ctx->buf_queue_lock, &ctx->src_buf_queue, 0);
- dst_buf_queue_greater_than_0
- = s5p_mfc_is_queue_count_greater(&ctx->buf_queue_lock, &ctx->dst_buf_queue, 0);
-
- /* If shutdown is called, do not try any cmd */
- if (dev->shutdown)
- return 0;
-
- /* context is ready to make header */
- if (ctx->state == MFCINST_GOT_INST &&
- dst_buf_queue_greater_than_0) {
- if (p->seq_hdr_mode == V4L2_MPEG_VIDEO_HEADER_MODE_AT_THE_READY) {
- if (src_buf_queue_greater_than_0)
- return 1;
- } else {
- return 1;
- }
- }
-
- /* context is ready to allocate DPB */
- if (ctx->state == MFCINST_HEAD_PARSED &&
- dst_buf_queue_greater_than_0)
- return 1;
-
- /* context is ready to encode a frame */
- if (ctx->state == MFCINST_RUNNING &&
- src_buf_queue_greater_than_0 && dst_buf_queue_greater_than_0)
- return 1;
-
- /* context is ready to encode a frame for NAL_ABORT command */
- if (ctx->state == MFCINST_ABORT_INST &&
- src_buf_queue_greater_than_0 && dst_buf_queue_greater_than_0)
- return 1;
-
- /* context is ready to encode remain frames */
- if (ctx->state == MFCINST_FINISHING &&
- src_buf_queue_greater_than_0 && dst_buf_queue_greater_than_0)
- return 1;
-
- s5p_mfc_perf_cancel_drv_margin(dev);
- mfc_debug(2, "ctx is not ready\n");
-
- return 0;
-}
-
-int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx)
-{
- if (ctx->type == MFCINST_DECODER)
- return s5p_mfc_dec_ctx_ready(ctx);
- else if (ctx->type == MFCINST_ENCODER)
- return s5p_mfc_enc_ctx_ready(ctx);
-
- return 0;
-}
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_intr.h
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __S5P_MFC_INTR_H
-#define __S5P_MFC_INTR_H __FILE__
-
-#include "s5p_mfc_common.h"
-
-#define need_to_dpb_flush(ctx) \
- ((ctx->state == MFCINST_FINISHING) || \
- (ctx->state == MFCINST_RUNNING))
-#define need_to_wait_nal_abort(ctx) \
- (ctx->state == MFCINST_ABORT_INST)
-#define need_to_continue(ctx) \
- ((ctx->state == MFCINST_DPB_FLUSHING) ||\
- (ctx->state == MFCINST_ABORT_INST) || \
- (ctx->state == MFCINST_RETURN_INST) || \
- (ctx->state == MFCINST_SPECIAL_PARSING) || \
- (ctx->state == MFCINST_SPECIAL_PARSING_NAL))
-#define need_to_special_parsing(ctx) \
- ((ctx->state == MFCINST_GOT_INST) || \
- (ctx->state == MFCINST_HEAD_PARSED))
-#define need_to_special_parsing_nal(ctx) \
- (ctx->state == MFCINST_RUNNING)
-#define ready_to_get_crop(ctx) \
- ((ctx->state == MFCINST_HEAD_PARSED) || \
- (ctx->state == MFCINST_RUNNING) || \
- (ctx->state == MFCINST_FINISHING))
-
-int s5p_mfc_wait_for_done_dev(struct s5p_mfc_dev *dev, int command);
-int s5p_mfc_wait_for_done_ctx(struct s5p_mfc_ctx *ctx, int command);
-void s5p_mfc_wake_up_dev(struct s5p_mfc_dev *dev, unsigned int reason,
- unsigned int err);
-void s5p_mfc_wake_up_ctx(struct s5p_mfc_ctx *ctx, unsigned int reason,
- unsigned int err);
-
-int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev);
-int s5p_mfc_dec_ctx_ready(struct s5p_mfc_ctx *ctx);
-int s5p_mfc_enc_ctx_ready(struct s5p_mfc_ctx *ctx);
-int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx);
-
-
-static inline void s5p_mfc_set_bit(int num, struct s5p_mfc_bits *data)
-{
- unsigned long flags;
- spin_lock_irqsave(&data->lock, flags);
- __set_bit(num, &data->bits);
- spin_unlock_irqrestore(&data->lock, flags);
-}
-
-static inline void s5p_mfc_clear_bit(int num, struct s5p_mfc_bits *data)
-{
- unsigned long flags;
- spin_lock_irqsave(&data->lock, flags);
- __clear_bit(num, &data->bits);
- spin_unlock_irqrestore(&data->lock, flags);
-}
-
-static inline int s5p_mfc_test_bit(int num, struct s5p_mfc_bits *data)
-{
- unsigned long flags;
- int ret;
- spin_lock_irqsave(&data->lock, flags);
- ret = test_bit(num, &data->bits);
- spin_unlock_irqrestore(&data->lock, flags);
- return ret;
-}
-
-static inline int s5p_mfc_is_all_bits_cleared(struct s5p_mfc_bits *data)
-{
- unsigned long flags;
- int ret;
- spin_lock_irqsave(&data->lock, flags);
- ret = ((data->bits) == 0) ? 1 : 0;
- spin_unlock_irqrestore(&data->lock, flags);
- return ret;
-}
-
-static inline void s5p_mfc_clear_all_bits(struct s5p_mfc_bits *data)
-{
- unsigned long flags;
- spin_lock_irqsave(&data->lock, flags);
- data->bits = 0;
- spin_unlock_irqrestore(&data->lock, flags);
-}
-
-static inline unsigned long s5p_mfc_get_bits(struct s5p_mfc_bits *data)
-{
- unsigned long flags;
- unsigned long ret;
- spin_lock_irqsave(&data->lock, flags);
- ret = data->bits;
- spin_unlock_irqrestore(&data->lock, flags);
- return ret;
-}
-
-static inline void s5p_mfc_create_bits(struct s5p_mfc_bits *data)
-{
- spin_lock_init(&data->lock);
- s5p_mfc_clear_all_bits(data);
-}
-
-static inline void s5p_mfc_delete_bits(struct s5p_mfc_bits *data)
-{
- s5p_mfc_clear_all_bits(data);
-}
-
-static inline int s5p_mfc_is_work_to_do(struct s5p_mfc_dev *dev)
-{
- return (!s5p_mfc_is_all_bits_cleared(&dev->work_bits));
-}
-
-#endif /* __S5P_MFC_INTR_H */
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_utils.c
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/smc.h>
-
-#include "s5p_mfc_utils.h"
-
-int s5p_mfc_check_vb_with_fmt(struct s5p_mfc_fmt *fmt, struct vb2_buffer *vb)
-{
- if (!fmt)
- return -EINVAL;
-
- if (fmt->mem_planes != vb->num_planes) {
- mfc_err_dev("plane number is different (%d != %d)\n",
- fmt->mem_planes, vb->num_planes);
- return -EINVAL;
- }
-
- return 0;
-}
-
-int mfc_stream_buf_prot(struct s5p_mfc_ctx *ctx,
- struct s5p_mfc_buf *buf, bool en)
-{
- return 0;
-}
-
-int mfc_raw_buf_prot(struct s5p_mfc_ctx *ctx,
- struct s5p_mfc_buf *buf, bool en)
-{
- return 0;
-}
-
-void s5p_mfc_raw_protect(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *mfc_buf,
- int index)
-{
- if (!test_bit(index, &ctx->raw_protect_flag)) {
- if (mfc_raw_buf_prot(ctx, mfc_buf, true)) {
- mfc_err_ctx("failed to CFW_PROT\n");
- } else {
- set_bit(index, &ctx->raw_protect_flag);
- mfc_debug(2, "[index:%d] raw protect, flag: %#lx\n",
- index, ctx->raw_protect_flag);
- }
- }
-}
-
-void s5p_mfc_raw_unprotect(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *mfc_buf,
- int index)
-{
- if (test_bit(index, &ctx->raw_protect_flag)) {
- if (mfc_raw_buf_prot(ctx, mfc_buf, false)) {
- mfc_err_ctx("failed to CFW_UNPROT\n");
- } else {
- clear_bit(index, &ctx->raw_protect_flag);
- mfc_debug(2, "[index:%d] raw unprotect, flag: %#lx\n",
- index, ctx->raw_protect_flag);
- }
- }
-}
-
-void s5p_mfc_stream_protect(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *mfc_buf,
- int index)
-{
- if (!test_bit(index, &ctx->stream_protect_flag)) {
- if (mfc_stream_buf_prot(ctx, mfc_buf, true)) {
- mfc_err_ctx("failed to CFW_PROT\n");
- } else {
- set_bit(index, &ctx->stream_protect_flag);
- mfc_debug(2, "[index:%d] stream protect, flag: %#lx\n",
- index, ctx->stream_protect_flag);
- }
- }
-}
-
-void s5p_mfc_stream_unprotect(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *mfc_buf,
- int index)
-{
- if (test_bit(index, &ctx->stream_protect_flag)) {
- if (mfc_stream_buf_prot(ctx, mfc_buf, false)) {
- mfc_err_ctx("failed to CFW_UNPROT\n");
- } else {
- clear_bit(index, &ctx->stream_protect_flag);
- mfc_debug(2, "[index:%d] stream unprotect, flag: %#lx\n",
- index, ctx->stream_protect_flag);
- }
- }
-}
-
-static int mfc_calc_plane(int width, int height, int is_tiled)
-{
- int mbX, mbY;
-
- mbX = (width + 15)/16;
- mbY = (height + 15)/16;
-
- /* Alignment for interlaced processing */
- if (is_tiled)
- mbY = (mbY + 1) / 2 * 2;
-
- return (mbX * 16) * (mbY * 16);
-}
-
-static void mfc_set_linear_stride_size(struct s5p_mfc_ctx *ctx,
- struct s5p_mfc_fmt *fmt)
-{
- struct s5p_mfc_raw_info *raw;
- int i;
-
- raw = &ctx->raw_buf;
-
- switch (fmt->fourcc) {
- case V4L2_PIX_FMT_YUV420M:
- case V4L2_PIX_FMT_YUV420N:
- case V4L2_PIX_FMT_YVU420M:
- raw->stride[0] = ALIGN(ctx->img_width, 16);
- raw->stride[1] = ALIGN(raw->stride[0] >> 1, 16);
- raw->stride[2] = ALIGN(raw->stride[0] >> 1, 16);
- break;
- case V4L2_PIX_FMT_NV12MT_16X16:
- case V4L2_PIX_FMT_NV12MT:
- case V4L2_PIX_FMT_NV12M:
- case V4L2_PIX_FMT_NV12N:
- case V4L2_PIX_FMT_NV21M:
- case V4L2_PIX_FMT_NV16M:
- case V4L2_PIX_FMT_NV61M:
- raw->stride[0] = ALIGN(ctx->img_width, 16);
- raw->stride[1] = ALIGN(ctx->img_width, 16);
- raw->stride[2] = 0;
- break;
- case V4L2_PIX_FMT_NV12M_S10B:
- case V4L2_PIX_FMT_NV12N_10B:
- case V4L2_PIX_FMT_NV21M_S10B:
- case V4L2_PIX_FMT_NV16M_S10B:
- case V4L2_PIX_FMT_NV61M_S10B:
- raw->stride[0] = S10B_8B_STRIDE(ctx->img_width);
- raw->stride[1] = S10B_8B_STRIDE(ctx->img_width);
- raw->stride[2] = 0;
- raw->stride_2bits[0] = S10B_2B_STRIDE(ctx->img_width);
- raw->stride_2bits[1] = S10B_2B_STRIDE(ctx->img_width);
- raw->stride_2bits[2] = 0;
- break;
- case V4L2_PIX_FMT_NV12M_P010:
- case V4L2_PIX_FMT_NV21M_P010:
- case V4L2_PIX_FMT_NV61M_P210:
- case V4L2_PIX_FMT_NV16M_P210:
- raw->stride[0] = ALIGN(ctx->img_width, 16) * 2;
- raw->stride[1] = ALIGN(ctx->img_width, 16) * 2;
- raw->stride[2] = 0;
- raw->stride_2bits[0] = 0;
- raw->stride_2bits[1] = 0;
- raw->stride_2bits[2] = 0;
- break;
- case V4L2_PIX_FMT_RGB24:
- ctx->raw_buf.stride[0] = ctx->img_width * 3;
- ctx->raw_buf.stride[1] = 0;
- ctx->raw_buf.stride[2] = 0;
- break;
- case V4L2_PIX_FMT_RGB565:
- ctx->raw_buf.stride[0] = ctx->img_width * 2;
- ctx->raw_buf.stride[1] = 0;
- ctx->raw_buf.stride[2] = 0;
- break;
- case V4L2_PIX_FMT_RGB32X:
- case V4L2_PIX_FMT_BGR32:
- case V4L2_PIX_FMT_ARGB32:
- ctx->raw_buf.stride[0] = (ctx->buf_stride > ctx->img_width) ?
- (ALIGN(ctx->img_width, 16) * 4) : (ctx->img_width * 4);
- ctx->raw_buf.stride[1] = 0;
- ctx->raw_buf.stride[2] = 0;
- break;
- default:
- break;
- }
-
- /* Decoder needs multiple of 16 alignment for stride */
- if (ctx->type == MFCINST_DECODER) {
- for (i = 0; i < 3; i++)
- ctx->raw_buf.stride[i] =
- ALIGN(ctx->raw_buf.stride[i], 16);
- }
-}
-
-void s5p_mfc_dec_calc_dpb_size(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev;
- struct s5p_mfc_dec *dec;
- struct s5p_mfc_raw_info *raw;
- int i;
- int extra = MFC_LINEAR_BUF_SIZE;
-
- if (!ctx) {
- mfc_err_dev("no mfc context to run\n");
- return;
- }
-
- dev = ctx->dev;
- raw = &ctx->raw_buf;
- raw->total_plane_size = 0;
-
- dec = ctx->dec_priv;
-
- for (i = 0; i < raw->num_planes; i++) {
- raw->plane_size[i] = 0;
- raw->plane_size_2bits[i] = 0;
- }
-
- switch (ctx->dst_fmt->fourcc) {
- case V4L2_PIX_FMT_NV12M_S10B:
- case V4L2_PIX_FMT_NV21M_S10B:
- raw->plane_size[0] = NV12M_Y_SIZE(ctx->img_width, ctx->img_height);
- raw->plane_size[1] = NV12M_CBCR_SIZE(ctx->img_width, ctx->img_height);
- raw->plane_size_2bits[0] = NV12M_Y_2B_SIZE(ctx->img_width, ctx->img_height);
- raw->plane_size_2bits[1] = NV12M_CBCR_2B_SIZE(ctx->img_width, ctx->img_height);
- break;
- case V4L2_PIX_FMT_NV12M:
- case V4L2_PIX_FMT_NV21M:
- raw->plane_size[0] = mfc_calc_plane(ctx->img_width, ctx->img_height, 0) + extra;
- raw->plane_size[1] = mfc_calc_plane(ctx->img_width, ctx->img_height, 0) / 2 + extra;
- break;
- case V4L2_PIX_FMT_NV12M_P010:
- case V4L2_PIX_FMT_NV21M_P010:
- raw->plane_size[0] = mfc_calc_plane(ctx->img_width, ctx->img_height, 0) * 2 + extra;
- raw->plane_size[1] = mfc_calc_plane(ctx->img_width, ctx->img_height, 0) + extra;
- break;
- case V4L2_PIX_FMT_YUV420M:
- case V4L2_PIX_FMT_YVU420M:
- raw->plane_size[0] = mfc_calc_plane(ctx->img_width, ctx->img_height, 0) + extra;
- raw->plane_size[1] = mfc_calc_plane(ctx->img_width, ctx->img_height, 0) / 2 + extra;
- raw->plane_size[2] = mfc_calc_plane(ctx->img_width, ctx->img_height, 0) / 2 + extra;
- break;
- case V4L2_PIX_FMT_NV16M_S10B:
- case V4L2_PIX_FMT_NV61M_S10B:
- raw->plane_size[0] = NV16M_Y_SIZE(ctx->img_width, ctx->img_height);
- raw->plane_size[1] = NV16M_CBCR_SIZE(ctx->img_width, ctx->img_height);
- raw->plane_size_2bits[0] = NV16M_Y_2B_SIZE(ctx->img_width, ctx->img_height);
- raw->plane_size_2bits[1] = NV16M_CBCR_2B_SIZE(ctx->img_width, ctx->img_height);
- break;
- case V4L2_PIX_FMT_NV16M:
- case V4L2_PIX_FMT_NV61M:
- raw->plane_size[0] = mfc_calc_plane(ctx->img_width, ctx->img_height, 0) + extra;
- raw->plane_size[1] = mfc_calc_plane(ctx->img_width, ctx->img_height, 0) + extra;
- break;
- case V4L2_PIX_FMT_NV16M_P210:
- case V4L2_PIX_FMT_NV61M_P210:
- raw->plane_size[0] = mfc_calc_plane(ctx->img_width, ctx->img_height, 0) * 2 + extra;
- raw->plane_size[1] = mfc_calc_plane(ctx->img_width, ctx->img_height, 0) * 2 + extra;
- break;
- /* non-contiguous single fd format */
- case V4L2_PIX_FMT_NV12N_10B:
- raw->plane_size[0] = NV12N_10B_Y_8B_SIZE(ctx->img_width, ctx->img_height);
- raw->plane_size[1] = NV12N_10B_CBCR_8B_SIZE(ctx->img_width, ctx->img_height);
- raw->plane_size_2bits[0] = NV12N_10B_Y_2B_SIZE(ctx->img_width, ctx->img_height);
- raw->plane_size_2bits[1] = NV12N_10B_CBCR_2B_SIZE(ctx->img_width, ctx->img_height);
- break;
- case V4L2_PIX_FMT_NV12N:
- raw->plane_size[0] = NV12N_Y_SIZE(ctx->img_width, ctx->img_height);
- raw->plane_size[1] = NV12N_CBCR_SIZE(ctx->img_width, ctx->img_height);
- break;
- case V4L2_PIX_FMT_YUV420N:
- raw->plane_size[0] = YUV420N_Y_SIZE(ctx->img_width, ctx->img_height);
- raw->plane_size[1] = YUV420N_CB_SIZE(ctx->img_width, ctx->img_height);
- raw->plane_size[2] = YUV420N_CR_SIZE(ctx->img_width, ctx->img_height);
- break;
- default:
- mfc_err_ctx("Invalid pixelformat : %s\n", ctx->dst_fmt->name);
- break;
- }
-
- mfc_set_linear_stride_size(ctx, ctx->dst_fmt);
-
- for (i = 0; i < raw->num_planes; i++) {
- if (raw->plane_size[i] < ctx->min_dpb_size[i]) {
- mfc_info_dev("[FRAME] plane[%d] size is changed %d -> %d\n",
- i, raw->plane_size[i], ctx->min_dpb_size[i]);
- raw->plane_size[i] = ctx->min_dpb_size[i];
- }
- }
-
- for (i = 0; i < raw->num_planes; i++) {
- raw->total_plane_size += raw->plane_size[i];
- mfc_debug(2, "[FRAME] Plane[%d] size = %d, stride = %d\n",
- i, raw->plane_size[i], raw->stride[i]);
- }
- if (ctx->is_10bit) {
- for (i = 0; i < raw->num_planes; i++) {
- raw->total_plane_size += raw->plane_size_2bits[i];
- mfc_debug(2, "[FRAME][10BIT] Plane[%d] 2bit size = %d, stride = %d\n",
- i, raw->plane_size_2bits[i],
- raw->stride_2bits[i]);
- }
- }
- mfc_debug(2, "[FRAME] total plane size: %d\n", raw->total_plane_size);
-
- if (IS_H264_DEC(ctx) || IS_H264_MVC_DEC(ctx)) {
- ctx->mv_size = DEC_MV_SIZE_MB(ctx->img_width, ctx->img_height);
- ctx->mv_size = ALIGN(ctx->mv_size, 32);
- } else if (IS_HEVC_DEC(ctx) || IS_BPG_DEC(ctx)) {
- ctx->mv_size = DEC_HEVC_MV_SIZE(ctx->img_width, ctx->img_height);
- ctx->mv_size = ALIGN(ctx->mv_size, 32);
- } else {
- ctx->mv_size = 0;
- }
-}
-
-void s5p_mfc_enc_calc_src_size(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev;
- struct s5p_mfc_raw_info *raw;
- unsigned int mb_width, mb_height, default_size;
- int i, extra;
-
- if (!ctx) {
- mfc_err_dev("no mfc context to run\n");
- return;
- }
-
- dev = ctx->dev;
- raw = &ctx->raw_buf;
- raw->total_plane_size = 0;
- mb_width = WIDTH_MB(ctx->img_width);
- mb_height = HEIGHT_MB(ctx->img_height);
- extra = MFC_LINEAR_BUF_SIZE;
- default_size = mb_width * mb_height * 256;
-
- for (i = 0; i < raw->num_planes; i++) {
- raw->plane_size[i] = 0;
- raw->plane_size_2bits[i] = 0;
- }
-
- switch (ctx->src_fmt->fourcc) {
- case V4L2_PIX_FMT_YUV420M:
- case V4L2_PIX_FMT_YUV420N:
- case V4L2_PIX_FMT_YVU420M:
- raw->plane_size[0] = ALIGN(default_size, 256) + extra;
- raw->plane_size[1] = ALIGN(default_size >> 2, 256) + extra;
- raw->plane_size[2] = ALIGN(default_size >> 2, 256) + extra;
- break;
- case V4L2_PIX_FMT_NV12M_S10B:
- case V4L2_PIX_FMT_NV21M_S10B:
- raw->plane_size[0] = NV12M_Y_SIZE(ctx->img_width, ctx->img_height);
- raw->plane_size[1] = NV12M_CBCR_SIZE(ctx->img_width, ctx->img_height);
- raw->plane_size_2bits[0] = NV12M_Y_2B_SIZE(ctx->img_width, ctx->img_height);
- raw->plane_size_2bits[1] = NV12M_CBCR_2B_SIZE(ctx->img_width, ctx->img_height);
- break;
- case V4L2_PIX_FMT_NV12MT_16X16:
- case V4L2_PIX_FMT_NV12M:
- case V4L2_PIX_FMT_NV12N:
- case V4L2_PIX_FMT_NV21M:
- raw->plane_size[0] = ALIGN(default_size, 256) + extra;
- raw->plane_size[1] = ALIGN(default_size / 2, 256) + extra;
- break;
- case V4L2_PIX_FMT_NV12M_P010:
- case V4L2_PIX_FMT_NV21M_P010:
- raw->plane_size[0] = ALIGN(default_size, 256) * 2 + extra;
- raw->plane_size[1] = ALIGN(default_size, 256) + extra;
- break;
- case V4L2_PIX_FMT_NV16M_S10B:
- case V4L2_PIX_FMT_NV61M_S10B:
- raw->plane_size[0] = NV16M_Y_SIZE(ctx->img_width, ctx->img_height);
- raw->plane_size[1] = NV16M_CBCR_SIZE(ctx->img_width, ctx->img_height);
- raw->plane_size_2bits[0] = NV16M_Y_2B_SIZE(ctx->img_width, ctx->img_height);
- raw->plane_size_2bits[1] = NV16M_CBCR_2B_SIZE(ctx->img_width, ctx->img_height);
- break;
- case V4L2_PIX_FMT_NV16M:
- case V4L2_PIX_FMT_NV61M:
- raw->plane_size[0] = ALIGN(default_size, 256) + extra;
- raw->plane_size[1] = ALIGN(default_size, 256) + extra;
- break;
- case V4L2_PIX_FMT_NV16M_P210:
- case V4L2_PIX_FMT_NV61M_P210:
- raw->plane_size[0] = ALIGN(default_size, 256) * 2 + extra;
- raw->plane_size[1] = ALIGN(default_size, 256) * 2 + extra;
- break;
- default:
- mfc_err_ctx("Invalid pixel format(%d)\n", ctx->src_fmt->fourcc);
- break;
- }
-
- mfc_set_linear_stride_size(ctx, ctx->src_fmt);
-
- for (i = 0; i < raw->num_planes; i++) {
- raw->total_plane_size += raw->plane_size[i];
- mfc_debug(2, "[FRAME] Plane[%d] size = %d, stride = %d\n",
- i, raw->plane_size[i], raw->stride[i]);
- }
- if (ctx->is_10bit) {
- for (i = 0; i < raw->num_planes; i++) {
- raw->total_plane_size += raw->plane_size_2bits[i];
- mfc_debug(2, "[FRAME][10BIT] Plane[%d] 2bit size = %d, stride = %d\n",
- i, raw->plane_size_2bits[i],
- raw->stride_2bits[i]);
- }
- }
-
- mfc_debug(2, "[FRAME] total plane size: %d\n", raw->total_plane_size);
-}
-
-void s5p_mfc_cleanup_assigned_dpb(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dec *dec;
- struct s5p_mfc_buf *dst_mb;
- int i;
-
- if (!ctx) {
- mfc_err_dev("no mfc context to run\n");
- return;
- }
-
- dec = ctx->dec_priv;
- if (!dec) {
- mfc_err_dev("no mfc decoder to run\n");
- return;
- }
-
- if (ctx->is_drm && ctx->raw_protect_flag) {
- mfc_debug(2, "raw_protect_flag(%#lx) will be released\n",
- ctx->raw_protect_flag);
- for (i = 0; i < MFC_MAX_DPBS; i++) {
- dst_mb = dec->assigned_dpb[i];
-
- s5p_mfc_raw_unprotect(ctx, dst_mb, i);
- }
- s5p_mfc_clear_assigned_dpb(ctx);
- }
-}
-
-void s5p_mfc_unprotect_released_dpb(struct s5p_mfc_ctx *ctx, unsigned int released_flag)
-{
- struct s5p_mfc_dec *dec;
- struct s5p_mfc_buf *dst_mb;
- int i;
-
- if (!ctx) {
- mfc_err_dev("no mfc context to run\n");
- return;
- }
-
- dec = ctx->dec_priv;
- if (!dec) {
- mfc_err_dev("no mfc decoder to run\n");
- return;
- }
-
- if (ctx->is_drm) {
- for (i = 0; i < MFC_MAX_DPBS; i++) {
- if (released_flag & (1 << i)) {
- dst_mb = dec->assigned_dpb[i];
- s5p_mfc_raw_unprotect(ctx, dst_mb, i);
- }
- }
- }
-
-}
-
-void s5p_mfc_protect_dpb(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *dst_mb)
-{
- struct s5p_mfc_dec *dec;
- int dst_index;
-
- if (!ctx) {
- mfc_err_dev("no mfc context to run\n");
- return;
- }
-
- dec = ctx->dec_priv;
- if (!dec) {
- mfc_err_dev("no mfc decoder to run\n");
- return;
- }
-
- dst_index = dst_mb->vb.vb2_buf.index;
-
- if (ctx->is_drm) {
- dec->assigned_dpb[dst_index] = dst_mb;
- s5p_mfc_raw_protect(ctx, dst_mb, dst_index);
- }
-}
-
-void s5p_mfc_watchdog_tick(unsigned long arg)
-{
- struct s5p_mfc_dev *dev = (struct s5p_mfc_dev *)arg;
-
- if (!dev) {
- mfc_err_dev("no mfc device to run\n");
- return;
- }
-
- mfc_debug(5, "watchdog is ticking!\n");
-
- if (atomic_read(&dev->watchdog_tick_running))
- atomic_inc(&dev->watchdog_tick_cnt);
- else
- atomic_set(&dev->watchdog_tick_cnt, 0);
-
- if (atomic_read(&dev->watchdog_tick_cnt) >= WATCHDOG_TICK_CNT_TO_START_WATCHDOG) {
- /* This means that hw is busy and no interrupts were
- * generated by hw for the Nth time of running this
- * watchdog timer. This usually means a serious hw
- * error. Now it is time to kill all instances and
- * reset the MFC. */
- mfc_err_dev("[%d] Time out during waiting for HW\n",
- atomic_read(&dev->watchdog_tick_cnt));
- queue_work(dev->watchdog_wq, &dev->watchdog_work);
- }
-
- dev->watchdog_timer.expires = jiffies +
- msecs_to_jiffies(WATCHDOG_TICK_INTERVAL);
- add_timer(&dev->watchdog_timer);
-}
-
-void s5p_mfc_watchdog_start_tick(struct s5p_mfc_dev *dev)
-{
- if (atomic_read(&dev->watchdog_tick_running)) {
- mfc_debug(2, "watchdog timer was already started!\n");
- } else {
- mfc_debug(2, "watchdog timer is now started!\n");
- atomic_set(&dev->watchdog_tick_running, 1);
- }
-
- /* Reset the timeout watchdog */
- atomic_set(&dev->watchdog_tick_cnt, 0);
-}
-
-void s5p_mfc_watchdog_stop_tick(struct s5p_mfc_dev *dev)
-{
- if (atomic_read(&dev->watchdog_tick_running)) {
- mfc_debug(2, "watchdog timer is now stopped!\n");
- atomic_set(&dev->watchdog_tick_running, 0);
- } else {
- mfc_debug(2, "watchdog timer was already stopped!\n");
- }
-
- /* Reset the timeout watchdog */
- atomic_set(&dev->watchdog_tick_cnt, 0);
-}
-
-void s5p_mfc_watchdog_reset_tick(struct s5p_mfc_dev *dev)
-{
- mfc_debug(2, "watchdog timer reset!\n");
-
- /* Reset the timeout watchdog */
- atomic_set(&dev->watchdog_tick_cnt, 0);
-}
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_utils.h
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __S5P_MFC_UTILS_H
-#define __S5P_MFC_UTILS_H __FILE__
-
-#include "s5p_mfc_common.h"
-
-static inline void s5p_mfc_clean_dev_int_flags(struct s5p_mfc_dev *dev)
-{
- dev->int_condition = 0;
- dev->int_reason = 0;
- dev->int_err = 0;
-}
-
-static inline void s5p_mfc_clean_ctx_int_flags(struct s5p_mfc_ctx *ctx)
-{
- ctx->int_condition = 0;
- ctx->int_reason = 0;
- ctx->int_err = 0;
-}
-
-static inline void s5p_mfc_change_state(struct s5p_mfc_ctx *ctx, enum s5p_mfc_inst_state state)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
-
- MFC_TRACE_CTX("** state : %d\n", state);
- ctx->state = state;
-}
-
-static inline enum s5p_mfc_node_type s5p_mfc_get_node_type(struct file *file)
-{
- struct video_device *vdev = video_devdata(file);
- enum s5p_mfc_node_type node_type;
-
- if (!vdev) {
- mfc_err_dev("failed to get video_device\n");
- return MFCNODE_INVALID;
- }
-
- mfc_debug(2, "video_device index: %d\n", vdev->index);
-
- switch (vdev->index) {
- case 0:
- node_type = MFCNODE_DECODER;
- break;
- case 1:
- node_type = MFCNODE_ENCODER;
- break;
- case 2:
- node_type = MFCNODE_DECODER_DRM;
- break;
- case 3:
- node_type = MFCNODE_ENCODER_DRM;
- break;
- case 4:
- node_type = MFCNODE_ENCODER_OTF;
- break;
- case 5:
- node_type = MFCNODE_ENCODER_OTF_DRM;
- break;
- default:
- node_type = MFCNODE_INVALID;
- break;
- }
-
- return node_type;
-}
-
-static inline int s5p_mfc_is_decoder_node(enum s5p_mfc_node_type node)
-{
- if (node == MFCNODE_DECODER || node == MFCNODE_DECODER_DRM)
- return 1;
-
- return 0;
-}
-
-static inline int s5p_mfc_is_drm_node(enum s5p_mfc_node_type node)
-{
- if (node == MFCNODE_DECODER_DRM || node == MFCNODE_ENCODER_DRM ||
- node == MFCNODE_ENCODER_OTF_DRM)
- return 1;
-
- return 0;
-}
-
-static inline int s5p_mfc_is_encoder_otf_node(enum s5p_mfc_node_type node)
-{
- if (node == MFCNODE_ENCODER_OTF || node == MFCNODE_ENCODER_OTF_DRM)
- return 1;
-
- return 0;
-}
-
-int s5p_mfc_check_vb_with_fmt(struct s5p_mfc_fmt *fmt, struct vb2_buffer *vb);
-
-void s5p_mfc_raw_protect(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *mfc_buf,
- int index);
-void s5p_mfc_raw_unprotect(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *mfc_buf,
- int index);
-void s5p_mfc_stream_protect(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *mfc_buf,
- int index);
-void s5p_mfc_stream_unprotect(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *mfc_buf,
- int index);
-
-void s5p_mfc_dec_calc_dpb_size(struct s5p_mfc_ctx *ctx);
-void s5p_mfc_enc_calc_src_size(struct s5p_mfc_ctx *ctx);
-
-static inline void s5p_mfc_cleanup_assigned_fd(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dec *dec;
- int i;
-
- dec = ctx->dec_priv;
-
- for (i = 0; i < MFC_MAX_DPBS; i++)
- dec->assigned_fd[i] = MFC_INFO_INIT_FD;
-}
-
-static inline void s5p_mfc_clear_assigned_dpb(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dec *dec;
- int i;
-
- if (!ctx) {
- mfc_err_dev("no mfc context to run\n");
- return;
- }
-
- dec = ctx->dec_priv;
- if (!dec) {
- mfc_err_dev("no mfc decoder to run\n");
- return;
- }
-
- for (i = 0; i < MFC_MAX_DPBS; i++)
- dec->assigned_dpb[i] = NULL;
-}
-
-static inline int s5p_mfc_dec_status_decoding(unsigned int dst_frame_status)
-{
- if (dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_DISPLAY ||
- dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_ONLY)
- return 1;
- return 0;
-}
-
-static inline int s5p_mfc_dec_status_display(unsigned int dst_frame_status)
-{
- if (dst_frame_status == S5P_FIMV_DEC_STATUS_DISPLAY_ONLY ||
- dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_DISPLAY)
- return 1;
-
- return 0;
-}
-
-void s5p_mfc_cleanup_assigned_dpb(struct s5p_mfc_ctx *ctx);
-void s5p_mfc_unprotect_released_dpb(struct s5p_mfc_ctx *ctx, unsigned int released_flag);
-void s5p_mfc_protect_dpb(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *dst_mb);
-
-/* Watchdog interval */
-#define WATCHDOG_TICK_INTERVAL 1000
-/* After how many executions watchdog should assume lock up */
-#define WATCHDOG_TICK_CNT_TO_START_WATCHDOG 5
-
-void s5p_mfc_watchdog_tick(unsigned long arg);
-void s5p_mfc_watchdog_start_tick(struct s5p_mfc_dev *dev);
-void s5p_mfc_watchdog_stop_tick(struct s5p_mfc_dev *dev);
-void s5p_mfc_watchdog_reset_tick(struct s5p_mfc_dev *dev);
-
-#endif /* __S5P_MFC_UTILS_H */
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_watchdog.c
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-#ifdef BIGDATA_LOGGING_ENABLE
-#include <linux/sec_debug.h>
-#endif
-
-#include "s5p_mfc_watchdog.h"
-
-#include "s5p_mfc_sync.h"
-
-#include "s5p_mfc_pm.h"
-#include "s5p_mfc_cmd.h"
-#include "s5p_mfc_cal.h"
-#include "s5p_mfc_reg.h"
-
-#include "s5p_mfc_queue.h"
-#include "s5p_mfc_utils.h"
-
-#define MFC_SFR_AREA_COUNT 21
-static void mfc_dump_regs(struct s5p_mfc_dev *dev)
-{
- int i;
- struct s5p_mfc_ctx_buf_size *buf_size = NULL;
- int addr[MFC_SFR_AREA_COUNT][2] = {
- { 0x0, 0x80 },
- { 0x1000, 0xCD0 },
- { 0xF000, 0xFF8 },
- { 0x2000, 0xA00 },
- { 0x2f00, 0x6C },
- { 0x3000, 0x40 },
- { 0x3094, 0x4 },
- { 0x30b4, 0x8 },
- { 0x3110, 0x10 },
- { 0x5000, 0x100 },
- { 0x5200, 0x300 },
- { 0x5600, 0x100 },
- { 0x5800, 0x100 },
- { 0x5A00, 0x100 },
- { 0x6000, 0xC4 },
- { 0x7000, 0x21C },
- { 0x8000, 0x20C },
- { 0x9000, 0x10C },
- { 0xA000, 0x20C },
- { 0xB000, 0x444 },
- { 0xC000, 0x84 },
- };
-
- pr_err("-----------dumping MFC registers (SFR base = 0x%p, dev = 0x%p)\n",
- dev->regs_base, dev);
-
- s5p_mfc_enable_all_clocks(dev);
-
- for (i = 0; i < MFC_SFR_AREA_COUNT; i++) {
- printk("[%04X .. %04X]\n", addr[i][0], addr[i][0] + addr[i][1]);
- print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 32, 4, dev->regs_base + addr[i][0],
- addr[i][1], false);
- printk("...\n");
- }
-
- if (dbg_enable) {
- buf_size = dev->variant->buf_size->ctx_buf;
- printk("[DBG INFO dump]\n");
- print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 32, 4, dev->dbg_info_buf.vaddr,
- buf_size->dbg_info_buf, false);
- printk("...\n");
- }
-}
-
-const u32 s5p_mfc_logging_sfr_set1[MFC_SFR_LOGGING_COUNT_SET1] = {
- 0x1000, 0x1004, 0x100C, 0x1010
-};
-
-const u32 s5p_mfc_logging_sfr_set2[MFC_SFR_LOGGING_COUNT_SET2] = {
- 0x0070, 0x10B4, 0x2020, 0x2028,
- 0x204C, 0x20B4, 0x3000, 0x3004,
- 0x3010, 0x301C, 0x3110, 0x5A54,
- 0x5A80, 0x5A88, 0x5A94, 0x6038,
- 0x6050, 0x6168, 0x7018, 0x7110,
- 0x7114, 0xF088, 0xFFD0
-};
-
-int mfc_change_hex_to_ascii(u32 hex, u32 byte, char *ascii, int idx)
-{
- int i;
- char tmp;
-
- for (i = 0; i < byte; i++) {
- if (idx >= MFC_LOGGING_DATA_SIZE) {
- pr_err("logging data size exceed: %d\n", idx);
- return idx;
- }
-
- tmp = (hex >> ((byte - 1 - i) * 4)) & 0xF;
- if (tmp > 9)
- ascii[idx] = tmp + 'a' - 0xa;
- else if (tmp <= 9)
- ascii[idx] = tmp + '0';
- idx++;
- }
-
- /* space */
- if (idx < MFC_LOGGING_DATA_SIZE)
- ascii[idx] = ' ';
-
- return ++idx;
-}
-
-static void mfc_save_logging_sfr(struct s5p_mfc_dev *dev)
-{
- char *errorinfo;
- int i, idx = 0;
-
- pr_err("-----------logging MFC error info-----------\n");
- errorinfo = dev->logging_data->errorinfo;
- for (i = 0; i < MFC_SFR_LOGGING_COUNT_SET1; i++)
- dev->logging_data->SFRs_set1[i] = MFC_READL(s5p_mfc_logging_sfr_set1[i]);
- for (i = 0; i < MFC_SFR_LOGGING_COUNT_SET2; i++)
- dev->logging_data->SFRs_set2[i] = MFC_READL(s5p_mfc_logging_sfr_set2[i]);
-
- idx = mfc_change_hex_to_ascii(dev->logging_data->cause, 8, errorinfo, idx);
- idx = mfc_change_hex_to_ascii(dev->logging_data->fault_status, 2, errorinfo, idx);
- idx = mfc_change_hex_to_ascii(dev->logging_data->fault_trans_info, 8, errorinfo, idx);
- idx = mfc_change_hex_to_ascii(dev->logging_data->fault_addr, 8, errorinfo, idx);
- for (i = 0; i < MFC_SFR_LOGGING_COUNT_SET1; i++)
- idx = mfc_change_hex_to_ascii(dev->logging_data->SFRs_set1[i], 2, errorinfo, idx);
- for (i = 0; i < MFC_SFR_LOGGING_COUNT_SET2; i++)
- idx = mfc_change_hex_to_ascii(dev->logging_data->SFRs_set2[i], 8, errorinfo, idx);
-
- pr_err("%s\n", errorinfo);
-
-#ifdef BIGDATA_LOGGING_ENABLE
- sec_debug_set_extra_info_mfc_error(errorinfo);
-#endif
-}
-
-static void mfc_display_state(struct s5p_mfc_dev *dev)
-{
- nal_queue_handle *nal_q_handle = dev->nal_q_handle;
- int i;
-
- pr_err("-----------dumping MFC device info-----------\n");
- pr_err("power:%d, clock:%d, num_inst:%d, num_drm_inst:%d, fw_status:%d\n",
- s5p_mfc_pm_get_pwr_ref_cnt(dev), s5p_mfc_pm_get_clk_ref_cnt(dev),
- dev->num_inst, dev->num_drm_inst, dev->fw.status);
- pr_err("hwlock bits:%#lx / dev:%#lx, curr_ctx:%d (is_drm:%d),"
- " preempt_ctx:%d, work_bits:%#lx\n",
- dev->hwlock.bits, dev->hwlock.dev,
- dev->curr_ctx, dev->curr_ctx_is_drm,
- dev->preempt_ctx, s5p_mfc_get_bits(&dev->work_bits));
- pr_err("options debug_level:%d, debug_mode:%d, mmcache:%d, perf_boost:%d\n",
- debug_level, dev->pdata->debug_mode, dev->mmcache.is_on_status, perf_boost_mode);
- pr_err("NAL-Q state:%d, exception:%d, in_exe_cnt: %d, out_exe_cnt: %d\n",
- nal_q_handle->nal_q_state, nal_q_handle->nal_q_exception,
- nal_q_handle->nal_q_in_handle->in_exe_count,
- nal_q_handle->nal_q_out_handle->out_exe_count);
-
- for (i = 0; i < MFC_NUM_CONTEXTS; i++)
- if (dev->ctx[i])
- pr_err("MFC ctx[%d] %s(%d) state:%d, queue_cnt(src:%d, dst:%d, ref:%d, qsrc:%d, qdst:%d)\n"
- " interrupt(cond:%d, type:%d, err:%d)\n",
- dev->ctx[i]->num,
- dev->ctx[i]->type == MFCINST_DECODER ? "DEC" : "ENC",
- dev->ctx[i]->codec_mode, dev->ctx[i]->state,
- s5p_mfc_get_queue_count(&dev->ctx[i]->buf_queue_lock, &dev->ctx[i]->src_buf_queue),
- s5p_mfc_get_queue_count(&dev->ctx[i]->buf_queue_lock, &dev->ctx[i]->dst_buf_queue),
- s5p_mfc_get_queue_count(&dev->ctx[i]->buf_queue_lock, &dev->ctx[i]->ref_buf_queue),
- s5p_mfc_get_queue_count(&dev->ctx[i]->buf_queue_lock, &dev->ctx[i]->src_buf_nal_queue),
- s5p_mfc_get_queue_count(&dev->ctx[i]->buf_queue_lock, &dev->ctx[i]->dst_buf_nal_queue),
- dev->ctx[i]->int_condition, dev->ctx[i]->int_reason,
- dev->ctx[i]->int_err);
-}
-
-static void mfc_print_trace(struct s5p_mfc_dev *dev)
-{
- int i, cnt, trace_cnt;
-
- pr_err("-----------dumping MFC trace info-----------\n");
-
- trace_cnt = atomic_read(&dev->trace_ref);
- for (i = MFC_TRACE_COUNT_PRINT - 1; i >= 0; i--) {
- cnt = ((trace_cnt + MFC_TRACE_COUNT_MAX) - i) % MFC_TRACE_COUNT_MAX;
- pr_err("MFC trace[%d]: time=%llu, str=%s", cnt,
- dev->mfc_trace[cnt].time, dev->mfc_trace[cnt].str);
- }
-}
-
-void mfc_dump_buffer_info(struct s5p_mfc_dev *dev)
-{
- struct s5p_mfc_ctx *ctx;
-
- ctx = dev->ctx[dev->curr_ctx];
- if (ctx) {
- pr_err("-----------dumping MFC buffer info (fault at: %#x)\n",
- dev->logging_data->fault_addr);
- pr_err("common:%#llx~%#llx, instance:%#llx~%#llx, codec:%#llx~%#llx\n",
- dev->common_ctx_buf.daddr,
- dev->common_ctx_buf.daddr + PAGE_ALIGN(0x7800),
- ctx->instance_ctx_buf.daddr,
- ctx->instance_ctx_buf.daddr + ctx->instance_ctx_buf.size,
- ctx->codec_buf.daddr,
- ctx->codec_buf.daddr + ctx->codec_buf.size);
- if (ctx->type == MFCINST_DECODER) {
- pr_err("Decoder CPB:%#x++%#x, scratch:%#x++%#x, static(vp9):%#x++%#x\n",
- MFC_READL(S5P_FIMV_D_CPB_BUFFER_ADDR),
- MFC_READL(S5P_FIMV_D_CPB_BUFFER_SIZE),
- MFC_READL(S5P_FIMV_D_SCRATCH_BUFFER_ADDR),
- MFC_READL(S5P_FIMV_D_SCRATCH_BUFFER_SIZE),
- MFC_READL(S5P_FIMV_D_STATIC_BUFFER_ADDR),
- MFC_READL(S5P_FIMV_D_STATIC_BUFFER_SIZE));
- pr_err("DPB [0]plane:++%#x, [1]plane:++%#x, [2]plane:++%#x, MV buffer:++%#lx\n",
- ctx->raw_buf.plane_size[0],
- ctx->raw_buf.plane_size[1],
- ctx->raw_buf.plane_size[2],
- ctx->mv_size);
- print_hex_dump(KERN_ERR, "[0] plane ", DUMP_PREFIX_ADDRESS, 32, 4,
- dev->regs_base + S5P_FIMV_D_FIRST_PLANE_DPB0,
- 0x100, false);
- print_hex_dump(KERN_ERR, "[1] plane ", DUMP_PREFIX_ADDRESS, 32, 4,
- dev->regs_base + S5P_FIMV_D_SECOND_PLANE_DPB0,
- 0x100, false);
- if (ctx->dst_fmt->num_planes == 3)
- print_hex_dump(KERN_ERR, "[2] plane ", DUMP_PREFIX_ADDRESS, 32, 4,
- dev->regs_base + S5P_FIMV_D_THIRD_PLANE_DPB0,
- 0x100, false);
- print_hex_dump(KERN_ERR, "MV buffer ", DUMP_PREFIX_ADDRESS, 32, 4,
- dev->regs_base + S5P_FIMV_D_MV_BUFFER0,
- 0x100, false);
- } else if (ctx->type == MFCINST_ENCODER) {
- pr_err("Encoder SRC %dplane, [0]:%#x++%#x, [1]:%#x++%#x, [2]:%#x++%#x\n",
- ctx->src_fmt->num_planes,
- MFC_READL(S5P_FIMV_E_SOURCE_FIRST_ADDR),
- ctx->raw_buf.plane_size[0],
- MFC_READL(S5P_FIMV_E_SOURCE_SECOND_ADDR),
- ctx->raw_buf.plane_size[1],
- MFC_READL(S5P_FIMV_E_SOURCE_THIRD_ADDR),
- ctx->raw_buf.plane_size[2]);
- pr_err("DST:%#x++%#x, scratch:%#x++%#x\n",
- MFC_READL(S5P_FIMV_E_STREAM_BUFFER_ADDR),
- MFC_READL(S5P_FIMV_E_STREAM_BUFFER_SIZE),
- MFC_READL(S5P_FIMV_E_SCRATCH_BUFFER_ADDR),
- MFC_READL(S5P_FIMV_E_SCRATCH_BUFFER_SIZE));
- pr_err("DPB [0] plane:++%#lx, [1] plane:++%#lx, ME buffer:++%#lx\n",
- ctx->enc_priv->luma_dpb_size,
- ctx->enc_priv->chroma_dpb_size,
- ctx->enc_priv->me_buffer_size);
- print_hex_dump(KERN_ERR, "[0] plane ", DUMP_PREFIX_ADDRESS, 32, 4,
- dev->regs_base + S5P_FIMV_E_LUMA_DPB,
- 0x44, false);
- print_hex_dump(KERN_ERR, "[1] plane ", DUMP_PREFIX_ADDRESS, 32, 4,
- dev->regs_base + S5P_FIMV_E_CHROMA_DPB,
- 0x44, false);
- print_hex_dump(KERN_ERR, "ME buffer ", DUMP_PREFIX_ADDRESS, 32, 4,
- dev->regs_base + S5P_FIMV_E_ME_BUFFER,
- 0x44, false);
- } else {
- pr_err("invalid MFC instnace type(%d)\n", ctx->type);
- }
- }
-}
-
-static void mfc_dump_info_without_regs(struct s5p_mfc_dev *dev)
-{
- mfc_display_state(dev);
- mfc_print_trace(dev);
-}
-
-static void mfc_dump_info(struct s5p_mfc_dev *dev)
-{
- mfc_dump_info_without_regs(dev);
- mfc_save_logging_sfr(dev);
- mfc_dump_buffer_info(dev);
- mfc_dump_regs(dev);
- exynos_sysmmu_show_status(dev->device);
-}
-
-static void mfc_dump_info_and_stop_hw(struct s5p_mfc_dev *dev)
-{
- MFC_TRACE_DEV("** mfc will stop!!!\n");
- mfc_dump_info(dev);
- BUG();
-}
-
-static void mfc_dump_info_and_stop_hw_debug(struct s5p_mfc_dev *dev)
-{
- if (!dev->pdata->debug_mode)
- return;
-
- MFC_TRACE_DEV("** mfc will stop!!!\n");
- mfc_dump_info(dev);
- BUG();
-}
-
-void s5p_mfc_watchdog_worker(struct work_struct *work)
-{
- struct s5p_mfc_dev *dev;
- int cmd;
-
- dev = container_of(work, struct s5p_mfc_dev, watchdog_work);
-
- if (atomic_read(&dev->watchdog_run)) {
- mfc_err_dev("watchdog already running???\n");
- return;
- }
-
- if (!atomic_read(&dev->watchdog_tick_cnt)) {
- mfc_err_dev("interrupt handler is called\n");
- return;
- }
-
- cmd = s5p_mfc_check_risc2host(dev);
- if (cmd) {
- if (atomic_read(&dev->watchdog_tick_cnt) == (3 * WATCHDOG_TICK_CNT_TO_START_WATCHDOG)) {
- mfc_err_dev("MFC driver waited for upward of %dsec\n",
- 3 * WATCHDOG_TICK_CNT_TO_START_WATCHDOG);
- dev->logging_data->cause |= (1 << MFC_CAUSE_NO_SCHEDULING);
- } else {
- mfc_err_dev("interrupt(%d) is occurred, wait scheduling\n", cmd);
- return;
- }
- } else {
- dev->logging_data->cause |= (1 << MFC_CAUSE_NO_INTERRUPT);
- mfc_err_dev("Driver timeout error handling\n");
- }
-
- /* Run watchdog worker */
- atomic_set(&dev->watchdog_run, 1);
-
- /* Reset the timeout watchdog */
- atomic_set(&dev->watchdog_tick_cnt, 0);
-
- /* Stop after dumping information */
- mfc_dump_info_and_stop_hw(dev);
-}
-
-struct s5p_mfc_dump_ops mfc_dump_ops = {
- .dump_regs = mfc_dump_regs,
- .dump_info = mfc_dump_info,
- .dump_info_without_regs = mfc_dump_info_without_regs,
- .dump_and_stop_always = mfc_dump_info_and_stop_hw,
- .dump_and_stop_debug_mode = mfc_dump_info_and_stop_hw_debug,
-};
+++ /dev/null
-/*
- * drivers/media/platform/exynos/mfc/s5p_mfc_watchdog.h
- *
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __S5P_MFC_WATCHDOG_H
-#define __S5P_MFC_WATCHDOG_H __FILE__
-
-#include "s5p_mfc_common.h"
-
-void s5p_mfc_watchdog_worker(struct work_struct *work);
-
-#endif /* __S5P_MFC_WATCHDOG_H */