aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/samsung
diff options
context:
space:
mode:
authorBrian Swetland <swetland@google.com>2010-11-14 20:20:42 -0800
committerArve Hjønnevåg <arve@android.com>2011-11-16 21:48:38 -0800
commit8c7e8d2cae5cca8c2fc7a7dd983b27be648d57c0 (patch)
treee61488cfc283bf09d5ca12d7d3e896f3e05f979a /drivers/media/video/samsung
parent641e3602113012003ec9d49bde7f8d8c5e292b87 (diff)
downloadkernel_samsung_crespo-8c7e8d2cae5cca8c2fc7a7dd983b27be648d57c0.zip
kernel_samsung_crespo-8c7e8d2cae5cca8c2fc7a7dd983b27be648d57c0.tar.gz
kernel_samsung_crespo-8c7e8d2cae5cca8c2fc7a7dd983b27be648d57c0.tar.bz2
ARM: S5PC110: MFC: MFC (Multi Format Codec) 5.0 video encoder/decoder
Signed-off-by: Sungjun Bae <june.bae@samsung.com> Signed-off-by: Choi jonghwan <jhbird.choi@samsung.com> Signed-off-by: huisung.kang <hs1218.kang@samsung.com>
Diffstat (limited to 'drivers/media/video/samsung')
-rw-r--r--drivers/media/video/samsung/Kconfig2
-rw-r--r--drivers/media/video/samsung/Makefile2
-rw-r--r--drivers/media/video/samsung/mfc50/Kconfig23
-rw-r--r--drivers/media/video/samsung/mfc50/Makefile7
-rw-r--r--drivers/media/video/samsung/mfc50/mfc.c803
-rw-r--r--drivers/media/video/samsung/mfc50/mfc_buffer_manager.c350
-rw-r--r--drivers/media/video/samsung/mfc50/mfc_buffer_manager.h56
-rw-r--r--drivers/media/video/samsung/mfc50/mfc_errorno.h83
-rw-r--r--drivers/media/video/samsung/mfc50/mfc_interface.h327
-rw-r--r--drivers/media/video/samsung/mfc50/mfc_intr.c202
-rw-r--r--drivers/media/video/samsung/mfc50/mfc_intr.h25
-rw-r--r--drivers/media/video/samsung/mfc50/mfc_logmsg.h72
-rw-r--r--drivers/media/video/samsung/mfc50/mfc_memory.c65
-rw-r--r--drivers/media/video/samsung/mfc50/mfc_memory.h110
-rw-r--r--drivers/media/video/samsung/mfc50/mfc_opr.c2516
-rw-r--r--drivers/media/video/samsung/mfc50/mfc_opr.h202
-rw-r--r--drivers/media/video/samsung/mfc50/mfc_shared_mem.c123
-rw-r--r--drivers/media/video/samsung/mfc50/mfc_shared_mem.h97
18 files changed, 5063 insertions, 2 deletions
diff --git a/drivers/media/video/samsung/Kconfig b/drivers/media/video/samsung/Kconfig
index 3060019..ad38288 100644
--- a/drivers/media/video/samsung/Kconfig
+++ b/drivers/media/video/samsung/Kconfig
@@ -15,7 +15,7 @@ config VIDEO_SAMSUNG_V4L2
if CPU_S5PV210
source "drivers/media/video/samsung/fimc/Kconfig"
-#source "drivers/media/video/samsung/mfc50/Kconfig"
+source "drivers/media/video/samsung/mfc50/Kconfig"
#source "drivers/media/video/samsung/jpeg_v2/Kconfig"
#source "drivers/media/video/samsung/tv20/Kconfig"
#source "drivers/media/video/samsung/tsi/Kconfig"
diff --git a/drivers/media/video/samsung/Makefile b/drivers/media/video/samsung/Makefile
index ff6d1fa..1ac2a12 100644
--- a/drivers/media/video/samsung/Makefile
+++ b/drivers/media/video/samsung/Makefile
@@ -1,5 +1,5 @@
obj-$(CONFIG_VIDEO_FIMC) += fimc/
-#obj-$(CONFIG_VIDEO_MFC50) += mfc50/
+obj-$(CONFIG_VIDEO_MFC50) += mfc50/
#obj-$(CONFIG_VIDEO_JPEG_V2) += jpeg_v2/
#obj-$(CONFIG_VIDEO_ROTATOR) += rotator/
#obj-$(CONFIG_VIDEO_TV20) += tv20/
diff --git a/drivers/media/video/samsung/mfc50/Kconfig b/drivers/media/video/samsung/mfc50/Kconfig
new file mode 100644
index 0000000..11d17c2
--- /dev/null
+++ b/drivers/media/video/samsung/mfc50/Kconfig
@@ -0,0 +1,23 @@
+#
+# Configuration for Multi Format Codecs (MFC)
+#
+#
+config VIDEO_MFC50
+ bool "Samsung MFC (Multi Format Codec - FIMV 5.0) Driver"
+ depends on VIDEO_SAMSUNG && CPU_S5PV210
+ default n
+ select S5P_SETUP_MFC
+ select S5P_DEV_MFC
+ ---help---
+ This is a Samsung Multi Format Codecs (MFC) FIMV V5.0 - driver for Samsung S5PC110
+
+config VIDEO_MFC_MAX_INSTANCE
+ int "Maximum size of MFC instance (1-4)"
+ range 1 4
+ depends on VIDEO_MFC50
+ default 4
+
+config VIDEO_MFC50_DEBUG
+ bool "print MFC debug message"
+ depends on VIDEO_MFC50
+ default n
diff --git a/drivers/media/video/samsung/mfc50/Makefile b/drivers/media/video/samsung/mfc50/Makefile
new file mode 100644
index 0000000..31f0499
--- /dev/null
+++ b/drivers/media/video/samsung/mfc50/Makefile
@@ -0,0 +1,7 @@
+obj-$(CONFIG_VIDEO_MFC50) += mfc.o mfc_buffer_manager.o mfc_intr.o mfc_memory.o mfc_opr.o mfc_shared_mem.o
+
+ifeq ($(CONFIG_VIDEO_MFC50_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
+
+#EXTRA_CFLAGS += -DMFC_REQUEST_TIME
diff --git a/drivers/media/video/samsung/mfc50/mfc.c b/drivers/media/video/samsung/mfc50/mfc.c
new file mode 100644
index 0000000..e1fc927
--- /dev/null
+++ b/drivers/media/video/samsung/mfc50/mfc.c
@@ -0,0 +1,803 @@
+/*
+ * drivers/media/video/samsung/mfc50/mfc.c
+ *
+ * C file for Samsung MFC (Multi Function Codec - FIMV) driver
+ *
+ * Jaeryul Oh, Copyright (c) 2009 Samsung Electronics
+ * http://www.samsungsemi.com/
+ *
+ * Change Logs
+ * 2009.09.14 - Beautify source code (Key Young, Park)
+ * 2009.09.21 - Implement clock & power gating.
+ * including suspend & resume fuction. (Key Young, Park)
+ * 2009.10.08 - Apply 9/30 firmware (Key Young, Park)
+ * 2009.10.09 - Add error handling rountine (Key Young, Park)
+ * 2009.10.13 - move mfc interrupt routine into mfc_irq.c (Key Young, Park)
+ * 2009.10.27 - Update firmware (2009.10.15) (Key Young, Park)
+ * 2009.11.04 - get physical address via mfc_allocate_buffer (Key Young, Park)
+ * 2009.11.04 - remove mfc_common.[ch]
+ * seperate buffer alloc & set (Key Young, Park)
+ * 2009.11.24 - add state check when decoding & encoding (Key Young, Park)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/wait.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/sched.h>
+#include <linux/firmware.h>
+
+#include <linux/io.h>
+#include <linux/uaccess.h>
+
+#include <plat/media.h>
+#include <mach/media.h>
+#include <plat/mfc.h>
+
+#include "mfc_interface.h"
+#include "mfc_logmsg.h"
+#include "mfc_opr.h"
+#include "mfc_memory.h"
+#include "mfc_buffer_manager.h"
+#include "mfc_intr.h"
+
+#define MFC_FW_NAME "samsung_mfc_fw.bin"
+
+static struct resource *mfc_mem;
+static struct mutex mfc_mutex;
+static struct clk *mfc_sclk;
+static struct regulator *mfc_pd_regulator;
+const struct firmware *mfc_fw_info;
+
+static int mfc_open(struct inode *inode, struct file *file)
+{
+ struct mfc_inst_ctx *mfc_ctx;
+ int ret;
+
+ mutex_lock(&mfc_mutex);
+
+ if (!mfc_is_running()) {
+ /* Turn on mfc power domain regulator */
+ ret = regulator_enable(mfc_pd_regulator);
+ if (ret < 0) {
+ mfc_err("MFC_RET_POWER_ENABLE_FAIL\n");
+ ret = -EINVAL;
+ goto err_open;
+ }
+
+ clk_enable(mfc_sclk);
+
+ mfc_load_firmware(mfc_fw_info->data, mfc_fw_info->size);
+
+ if (mfc_init_hw() != true) {
+ clk_disable(mfc_sclk);
+ ret = -ENODEV;
+ goto err_regulator;
+ }
+ clk_disable(mfc_sclk);
+ }
+
+ mfc_ctx = (struct mfc_inst_ctx *)kmalloc(sizeof(struct mfc_inst_ctx), GFP_KERNEL);
+ if (mfc_ctx == NULL) {
+ mfc_err("MFCINST_MEMORY_ALLOC_FAIL\n");
+ ret = -ENOMEM;
+ goto err_regulator;
+ }
+
+ memset(mfc_ctx, 0, sizeof(struct mfc_inst_ctx));
+
+ /* get the inst no allocating some part of memory among reserved memory */
+ mfc_ctx->mem_inst_no = mfc_get_mem_inst_no();
+ mfc_ctx->InstNo = -1;
+ if (mfc_ctx->mem_inst_no < 0) {
+ mfc_err("MFCINST_INST_NUM_EXCEEDED\n");
+ ret = -EPERM;
+ goto err_mem_inst;
+ }
+
+ if (mfc_set_state(mfc_ctx, MFCINST_STATE_OPENED) < 0) {
+ mfc_err("MFCINST_ERR_STATE_INVALID\n");
+ ret = -ENODEV;
+ goto err_set_state;
+ }
+
+ /* Decoder only */
+ mfc_ctx->extraDPB = MFC_MAX_EXTRA_DPB;
+ mfc_ctx->FrameType = MFC_RET_FRAME_NOT_SET;
+
+ file->private_data = mfc_ctx;
+
+ mutex_unlock(&mfc_mutex);
+
+ return 0;
+
+err_set_state:
+ mfc_return_mem_inst_no(mfc_ctx->mem_inst_no);
+err_mem_inst:
+ kfree(mfc_ctx);
+err_regulator:
+ if (!mfc_is_running()) {
+ /* Turn off mfc power domain regulator */
+ ret = regulator_disable(mfc_pd_regulator);
+ if (ret < 0)
+ mfc_err("MFC_RET_POWER_DISABLE_FAIL\n");
+ }
+err_open:
+ mutex_unlock(&mfc_mutex);
+
+ return ret;
+}
+
+static int mfc_release(struct inode *inode, struct file *file)
+{
+ struct mfc_inst_ctx *mfc_ctx;
+ int ret;
+
+ mutex_lock(&mfc_mutex);
+
+ mfc_ctx = (struct mfc_inst_ctx *)file->private_data;
+ if (mfc_ctx == NULL) {
+ mfc_err("MFCINST_ERR_INVALID_PARAM\n");
+ ret = -EIO;
+ goto out_release;
+ }
+
+ mfc_release_all_buffer(mfc_ctx->mem_inst_no);
+ mfc_merge_fragment(mfc_ctx->mem_inst_no);
+
+ mfc_return_mem_inst_no(mfc_ctx->mem_inst_no);
+
+ /* In case of no instance, we should not release codec instance */
+ if (mfc_ctx->InstNo >= 0) {
+ clk_enable(mfc_sclk);
+ mfc_return_inst_no(mfc_ctx->InstNo, mfc_ctx->MfcCodecType);
+ clk_disable(mfc_sclk);
+ }
+
+ kfree(mfc_ctx);
+
+ ret = 0;
+
+ if (!mfc_is_running()) {
+ /* Turn off mfc power domain regulator */
+ ret = regulator_disable(mfc_pd_regulator);
+ if (ret < 0) {
+ mfc_err("MFC_RET_POWER_DISABLE_FAIL\n");
+ goto out_release;
+ }
+ }
+
+out_release:
+
+ mutex_unlock(&mfc_mutex);
+ return ret;
+}
+
+static long mfc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ int ret, ex_ret;
+ struct mfc_inst_ctx *mfc_ctx = NULL;
+ struct mfc_common_args in_param;
+
+ mutex_lock(&mfc_mutex);
+ clk_enable(mfc_sclk);
+
+ ret = copy_from_user(&in_param, (struct mfc_common_args *)arg, sizeof(struct mfc_common_args));
+ if (ret < 0) {
+ mfc_err("Inparm copy error\n");
+ ret = -EIO;
+ in_param.ret_code = MFCINST_ERR_INVALID_PARAM;
+ goto out_ioctl;
+ }
+
+ mfc_ctx = (struct mfc_inst_ctx *)file->private_data;
+ mutex_unlock(&mfc_mutex);
+
+ switch (cmd) {
+ case IOCTL_MFC_ENC_INIT:
+ mutex_lock(&mfc_mutex);
+
+ if (mfc_set_state(mfc_ctx, MFCINST_STATE_ENC_INITIALIZE) < 0) {
+ mfc_err("MFCINST_ERR_STATE_INVALID\n");
+ in_param.ret_code = MFCINST_ERR_STATE_INVALID;
+ ret = -EINVAL;
+ mutex_unlock(&mfc_mutex);
+ break;
+ }
+
+ /* MFC encode init */
+ in_param.ret_code = mfc_init_encode(mfc_ctx, &(in_param.args));
+ ret = in_param.ret_code;
+ mutex_unlock(&mfc_mutex);
+ break;
+
+ case IOCTL_MFC_ENC_EXE:
+ mutex_lock(&mfc_mutex);
+ if (mfc_ctx->MfcState < MFCINST_STATE_ENC_INITIALIZE) {
+ mfc_err("MFCINST_ERR_STATE_INVALID\n");
+ in_param.ret_code = MFCINST_ERR_STATE_INVALID;
+ ret = -EINVAL;
+ mutex_unlock(&mfc_mutex);
+ break;
+ }
+
+ if (mfc_set_state(mfc_ctx, MFCINST_STATE_ENC_EXE) < 0) {
+ mfc_err("MFCINST_ERR_STATE_INVALID\n");
+ in_param.ret_code = MFCINST_ERR_STATE_INVALID;
+ ret = -EINVAL;
+ mutex_unlock(&mfc_mutex);
+ break;
+ }
+
+ in_param.ret_code = mfc_exe_encode(mfc_ctx, &(in_param.args));
+ ret = in_param.ret_code;
+ mutex_unlock(&mfc_mutex);
+ break;
+
+ case IOCTL_MFC_DEC_INIT:
+ mutex_lock(&mfc_mutex);
+ if (mfc_set_state(mfc_ctx, MFCINST_STATE_DEC_INITIALIZE) < 0) {
+ mfc_err("MFCINST_ERR_STATE_INVALID\n");
+ in_param.ret_code = MFCINST_ERR_STATE_INVALID;
+ ret = -EINVAL;
+ mutex_unlock(&mfc_mutex);
+ break;
+ }
+
+ /* MFC decode init */
+ in_param.ret_code = mfc_init_decode(mfc_ctx, &(in_param.args));
+ if (in_param.ret_code < 0) {
+ ret = in_param.ret_code;
+ mutex_unlock(&mfc_mutex);
+ break;
+ }
+
+ if (in_param.args.dec_init.out_dpb_cnt <= 0) {
+ mfc_err("MFC out_dpb_cnt error\n");
+ mutex_unlock(&mfc_mutex);
+ break;
+ }
+
+ mutex_unlock(&mfc_mutex);
+ break;
+
+ case IOCTL_MFC_DEC_EXE:
+ mutex_lock(&mfc_mutex);
+ if (mfc_ctx->MfcState < MFCINST_STATE_DEC_INITIALIZE) {
+ mfc_err("MFCINST_ERR_STATE_INVALID\n");
+ in_param.ret_code = MFCINST_ERR_STATE_INVALID;
+ ret = -EINVAL;
+ mutex_unlock(&mfc_mutex);
+ break;
+ }
+
+ if (mfc_set_state(mfc_ctx, MFCINST_STATE_DEC_EXE) < 0) {
+ mfc_err("MFCINST_ERR_STATE_INVALID\n");
+ in_param.ret_code = MFCINST_ERR_STATE_INVALID;
+ ret = -EINVAL;
+ mutex_unlock(&mfc_mutex);
+ break;
+ }
+
+ in_param.ret_code = mfc_exe_decode(mfc_ctx, &(in_param.args));
+ ret = in_param.ret_code;
+ mutex_unlock(&mfc_mutex);
+ break;
+
+ case IOCTL_MFC_GET_CONFIG:
+ mutex_lock(&mfc_mutex);
+ if (mfc_ctx->MfcState < MFCINST_STATE_DEC_INITIALIZE) {
+ mfc_err("MFCINST_ERR_STATE_INVALID\n");
+ in_param.ret_code = MFCINST_ERR_STATE_INVALID;
+ ret = -EINVAL;
+ mutex_unlock(&mfc_mutex);
+ break;
+ }
+
+ in_param.ret_code = mfc_get_config(mfc_ctx, &(in_param.args));
+ ret = in_param.ret_code;
+ mutex_unlock(&mfc_mutex);
+ break;
+
+ case IOCTL_MFC_SET_CONFIG:
+ mutex_lock(&mfc_mutex);
+ in_param.ret_code = mfc_set_config(mfc_ctx, &(in_param.args));
+ ret = in_param.ret_code;
+ mutex_unlock(&mfc_mutex);
+ break;
+
+ case IOCTL_MFC_GET_IN_BUF:
+ mutex_lock(&mfc_mutex);
+ if (mfc_ctx->MfcState < MFCINST_STATE_OPENED) {
+ mfc_err("MFCINST_ERR_STATE_INVALID\n");
+ in_param.ret_code = MFCINST_ERR_STATE_INVALID;
+ ret = -EINVAL;
+ mutex_unlock(&mfc_mutex);
+ break;
+ }
+
+ if (in_param.args.mem_alloc.buff_size <= 0) {
+ mfc_err("MFCINST_ERR_INVALID_PARAM\n");
+ in_param.ret_code = MFCINST_ERR_INVALID_PARAM;
+ ret = -EINVAL;
+ mutex_unlock(&mfc_mutex);
+ break;
+ }
+
+ if ((is_dec_codec(in_param.args.mem_alloc.codec_type)) &&
+ (in_param.args.mem_alloc.buff_size < (CPB_BUF_SIZE + DESC_BUF_SIZE))) {
+ in_param.args.mem_alloc.buff_size = CPB_BUF_SIZE + DESC_BUF_SIZE;
+ }
+
+ /* Buffer manager should have 64KB alignment for MFC base addresses */
+ in_param.args.mem_alloc.buff_size = ALIGN_TO_8KB(in_param.args.mem_alloc.buff_size);
+
+ /* allocate stream buf for decoder & current YC buf for encoder */
+ if (is_dec_codec(in_param.args.mem_alloc.codec_type))
+ in_param.ret_code = mfc_allocate_buffer(mfc_ctx, &in_param.args, 0);
+ else
+ in_param.ret_code = mfc_allocate_buffer(mfc_ctx, &in_param.args, 1);
+
+ ret = in_param.ret_code;
+ mutex_unlock(&mfc_mutex);
+ break;
+
+ case IOCTL_MFC_FREE_BUF:
+ mutex_lock(&mfc_mutex);
+ if (mfc_ctx->MfcState < MFCINST_STATE_OPENED) {
+ mfc_err("MFCINST_ERR_STATE_INVALID\n");
+ in_param.ret_code = MFCINST_ERR_STATE_INVALID;
+ ret = -EINVAL;
+ mutex_unlock(&mfc_mutex);
+ break;
+ }
+
+ in_param.ret_code = mfc_release_buffer((unsigned char *)in_param.args.mem_free.u_addr);
+ ret = in_param.ret_code;
+ mutex_unlock(&mfc_mutex);
+ break;
+
+ case IOCTL_MFC_GET_PHYS_ADDR:
+ mutex_lock(&mfc_mutex);
+ mfc_debug("IOCTL_MFC_GET_PHYS_ADDR\n");
+
+ if (mfc_ctx->MfcState < MFCINST_STATE_OPENED) {
+ mfc_err("MFCINST_ERR_STATE_INVALID\n");
+ in_param.ret_code = MFCINST_ERR_STATE_INVALID;
+ ret = -EINVAL;
+ mutex_unlock(&mfc_mutex);
+ break;
+ }
+
+ in_param.ret_code = mfc_get_phys_addr(mfc_ctx, &(in_param.args));
+ ret = in_param.ret_code;
+ mutex_unlock(&mfc_mutex);
+ break;
+
+ case IOCTL_MFC_GET_MMAP_SIZE:
+
+ if (mfc_ctx->MfcState < MFCINST_STATE_OPENED) {
+ mfc_err("MFC_RET_STATE_INVALID\n");
+ in_param.ret_code = MFCINST_ERR_STATE_INVALID;
+ ret = -EINVAL;
+
+ break;
+ }
+
+ in_param.ret_code = MFCINST_RET_OK;
+ ret = mfc_ctx->port0_mmap_size;
+
+ break;
+
+ default:
+ mfc_err("Requested ioctl command is not defined. (ioctl cmd=0x%08x)\n", cmd);
+ in_param.ret_code = MFCINST_ERR_INVALID_PARAM;
+ ret = -EINVAL;
+ }
+
+out_ioctl:
+ clk_disable(mfc_sclk);
+
+ ex_ret = copy_to_user((struct mfc_common_args *)arg, &in_param, sizeof(struct mfc_common_args));
+ if (ex_ret < 0) {
+ mfc_err("Outparm copy to user error\n");
+ ret = -EIO;
+ }
+
+ mfc_debug_L0("---------------IOCTL return = %d ---------------\n", ret);
+
+ return ret;
+}
+
+static int mfc_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ unsigned long vir_size = vma->vm_end - vma->vm_start;
+ unsigned long phy_size, firmware_size;
+ unsigned long page_frame_no = 0;
+ struct mfc_inst_ctx *mfc_ctx;
+
+ mfc_debug("vma->vm_start = 0x%08x, vma->vm_end = 0x%08x\n",
+ (unsigned int)vma->vm_start,
+ (unsigned int)vma->vm_end);
+ mfc_debug("vma->vm_end - vma->vm_start = %ld\n", vir_size);
+
+ mfc_ctx = (struct mfc_inst_ctx *)filp->private_data;
+
+ firmware_size = mfc_get_port0_buff_paddr() - mfc_get_fw_buff_paddr();
+ phy_size = (unsigned long)(mfc_port0_memsize - firmware_size + mfc_port1_memsize);
+
+ /* if memory size required from appl. mmap() is bigger than max data memory
+ * size allocated in the driver */
+ if (vir_size > phy_size) {
+ mfc_err("virtual requested mem(%ld) is bigger than physical mem(%ld)\n",
+ vir_size, phy_size);
+ return -EINVAL;
+ }
+
+ mfc_ctx->port0_mmap_size = (vir_size / 2);
+
+ vma->vm_flags |= VM_RESERVED | VM_IO;
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ /*
+ * port0 mapping for stream buf & frame buf (chroma + MV)
+ */
+ page_frame_no = __phys_to_pfn(mfc_get_port0_buff_paddr());
+ if (remap_pfn_range(vma, vma->vm_start, page_frame_no,
+ mfc_ctx->port0_mmap_size, vma->vm_page_prot)) {
+ mfc_err("mfc remap port0 error\n");
+ return -EAGAIN;
+ }
+
+ vma->vm_flags |= VM_RESERVED | VM_IO;
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ /*
+ * port1 mapping for frame buf (luma)
+ */
+ page_frame_no = __phys_to_pfn(mfc_get_port1_buff_paddr());
+ if (remap_pfn_range(vma, vma->vm_start + mfc_ctx->port0_mmap_size,
+ page_frame_no, vir_size - mfc_ctx->port0_mmap_size, vma->vm_page_prot)) {
+ mfc_err("mfc remap port1 error\n");
+ return -EAGAIN;
+ }
+
+ mfc_debug("virtual requested mem = %ld, physical reserved data mem = %ld\n", vir_size, phy_size);
+
+ return 0;
+}
+
+static const struct file_operations mfc_fops = {
+ .owner = THIS_MODULE,
+ .open = mfc_open,
+ .release = mfc_release,
+ .unlocked_ioctl = mfc_ioctl,
+ .mmap = mfc_mmap
+};
+
+
+static struct miscdevice mfc_miscdev = {
+ .minor = 252,
+ .name = "s3c-mfc",
+ .fops = &mfc_fops,
+};
+
+static void mfc_firmware_request_complete_handler(const struct firmware *fw,
+ void *context)
+{
+ if (fw != NULL) {
+ mfc_load_firmware(fw->data, fw->size);
+ mfc_fw_info = fw;
+ } else {
+ mfc_err("failed to load MFC F/W, MFC will not working\n");
+ }
+}
+
+static int mfc_probe(struct platform_device *pdev)
+{
+ struct s3c_platform_mfc *pdata;
+ struct resource *res;
+ size_t size;
+ int ret;
+
+ if (!pdev || !pdev->dev.platform_data) {
+ dev_err(&pdev->dev, "Unable to probe mfc!\n");
+ return -1;
+ }
+
+ pdata = pdev->dev.platform_data;
+
+ /* mfc clock enable should be here */
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "failed to get memory region resource\n");
+ ret = -ENOENT;
+ goto probe_out;
+ }
+
+ /* 60K is required for mfc register (0x0 ~ 0xe008) */
+ size = (res->end - res->start) + 1;
+ mfc_mem = request_mem_region(res->start, size, pdev->name);
+ if (mfc_mem == NULL) {
+ dev_err(&pdev->dev, "failed to get memory region\n");
+ ret = -ENOENT;
+ goto err_mem_req;
+ }
+
+ mfc_sfr_base_vaddr = ioremap(mfc_mem->start, mfc_mem->end - mfc_mem->start + 1);
+ if (mfc_sfr_base_vaddr == NULL) {
+ dev_err(&pdev->dev, "failed to ioremap address region\n");
+ ret = -ENOENT;
+ goto err_mem_map;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "failed to get irq resource\n");
+ ret = -ENOENT;
+ goto err_irq_res;
+ }
+
+#if !defined(MFC_POLLING)
+ ret = request_irq(res->start, mfc_irq, IRQF_DISABLED, pdev->name, pdev);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "failed to install irq (%d)\n", ret);
+ goto err_irq_req;
+ }
+#endif
+
+ mutex_init(&mfc_mutex);
+
+ /*
+ * buffer memory secure
+ */
+ mfc_port0_base_paddr =(unsigned int)pdata->buf_phy_base[0];
+ mfc_port0_memsize = (unsigned int)pdata->buf_phy_size[0];
+
+ mfc_debug(" mfc_port0_base_paddr= 0x%x \n", mfc_port0_base_paddr);
+ mfc_debug(" mfc_port0_memsize = 0x%x \n", mfc_port0_memsize);
+
+ mfc_port0_base_paddr = ALIGN_TO_128KB(mfc_port0_base_paddr);
+ mfc_port0_base_vaddr = phys_to_virt(mfc_port0_base_paddr);
+
+ if (mfc_port0_base_vaddr == NULL) {
+ mfc_err("fail to mapping port0 buffer\n");
+ ret = -EPERM;
+ goto err_vaddr_map;
+ }
+
+ mfc_port1_base_paddr = (unsigned int)pdata->buf_phy_base[1];
+ mfc_port1_memsize = (unsigned int)pdata->buf_phy_size[1];
+
+ mfc_debug(" mfc_port1_base_paddr= 0x%x \n", mfc_port1_base_paddr);
+ mfc_debug(" mfc_port1_memsize = 0x%x \n", mfc_port1_memsize);
+
+ mfc_port1_base_paddr = ALIGN_TO_128KB(mfc_port1_base_paddr);
+ mfc_port1_base_vaddr = phys_to_virt(mfc_port1_base_paddr);
+
+ if (mfc_port1_base_vaddr == NULL) {
+ mfc_err("fail to mapping port1 buffer\n");
+ ret = -EPERM;
+ goto err_vaddr_map;
+ }
+
+ mfc_debug("mfc_port0_base_paddr = 0x%08x, mfc_port1_base_paddr = 0x%08x <<\n",
+ (unsigned int)mfc_port0_base_paddr, (unsigned int)mfc_port1_base_paddr);
+ mfc_debug("mfc_port0_base_vaddr = 0x%08x, mfc_port1_base_vaddr = 0x%08x <<\n",
+ (unsigned int)mfc_port0_base_vaddr, (unsigned int)mfc_port1_base_vaddr);
+
+ /* Get mfc power domain regulator */
+ mfc_pd_regulator = regulator_get(&pdev->dev, "pd");
+ if (IS_ERR(mfc_pd_regulator)) {
+ mfc_err("failed to find mfc power domain\n");
+ ret = PTR_ERR(mfc_pd_regulator);
+ goto err_regulator_get;
+ }
+
+ mfc_sclk = clk_get(&pdev->dev, "sclk_mfc");
+ if (IS_ERR(mfc_sclk)) {
+ mfc_err("failed to find mfc clock source\n");
+ ret = PTR_ERR(mfc_sclk);
+ goto err_clk_get;
+ }
+
+ mfc_init_mem_inst_no();
+ mfc_init_buffer();
+
+ ret = misc_register(&mfc_miscdev);
+ if (ret) {
+ mfc_err("MFC can't misc register on minor\n");
+ goto err_misc_reg;
+ }
+
+ /*
+ * MFC FW downloading
+ */
+ ret = request_firmware_nowait(THIS_MODULE,
+ FW_ACTION_HOTPLUG,
+ MFC_FW_NAME,
+ &pdev->dev,
+ GFP_KERNEL,
+ pdev,
+ mfc_firmware_request_complete_handler);
+ if (ret) {
+ mfc_err("MFCINST_ERR_FW_INIT_FAIL\n");
+ ret = -EPERM;
+ goto err_req_fw;
+ }
+
+ return 0;
+
+err_req_fw:
+ misc_deregister(&mfc_miscdev);
+err_misc_reg:
+ clk_put(mfc_sclk);
+err_clk_get:
+ regulator_put(mfc_pd_regulator);
+err_regulator_get:
+err_vaddr_map:
+ free_irq(res->start, pdev);
+ mutex_destroy(&mfc_mutex);
+err_irq_req:
+err_irq_res:
+ iounmap(mfc_sfr_base_vaddr);
+err_mem_map:
+ release_mem_region(mfc_mem, size);
+err_mem_req:
+probe_out:
+ dev_err(&pdev->dev, "not found (%d).\n", ret);
+ return ret;
+}
+
+static int mfc_remove(struct platform_device *pdev)
+{
+ iounmap(mfc_sfr_base_vaddr);
+ iounmap(mfc_port0_base_vaddr);
+
+ /* remove memory region */
+ if (mfc_mem != NULL) {
+ release_resource(mfc_mem);
+ kfree(mfc_mem);
+ mfc_mem = NULL;
+ }
+
+ free_irq(IRQ_MFC, pdev);
+
+ mutex_destroy(&mfc_mutex);
+
+ clk_put(mfc_sclk);
+
+ misc_deregister(&mfc_miscdev);
+
+ if (mfc_fw_info)
+ release_firmware(mfc_fw_info);
+
+ return 0;
+}
+
+static int mfc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ int ret = 0;
+
+ mutex_lock(&mfc_mutex);
+
+ if (!mfc_is_running()) {
+ mutex_unlock(&mfc_mutex);
+ return 0;
+ }
+ clk_enable(mfc_sclk);
+
+ ret = mfc_set_sleep();
+ if (ret != MFCINST_RET_OK) {
+ clk_disable(mfc_sclk);
+ mutex_unlock(&mfc_mutex);
+ return ret;
+ }
+
+ clk_disable(mfc_sclk);
+
+ mutex_unlock(&mfc_mutex);
+
+ return 0;
+}
+
+static int mfc_resume(struct platform_device *pdev)
+{
+ int ret = 0;
+ unsigned int mc_status;
+
+ mutex_lock(&mfc_mutex);
+
+ if (!mfc_is_running()) {
+ mutex_unlock(&mfc_mutex);
+ return 0;
+ }
+
+ clk_enable(mfc_sclk);
+
+ /*
+ * 1. MFC reset
+ */
+ do {
+ mc_status = READL(MFC_MC_STATUS);
+ } while (mc_status != 0);
+
+ if (mfc_cmd_reset() == false) {
+ clk_disable(mfc_sclk);
+ mutex_unlock(&mfc_mutex);
+ mfc_err("MFCINST_ERR_INIT_FAIL\n");
+ return MFCINST_ERR_INIT_FAIL;
+ }
+
+ WRITEL(mfc_port0_base_paddr, MFC_MC_DRAMBASE_ADDR_A);
+ WRITEL(mfc_port1_base_paddr, MFC_MC_DRAMBASE_ADDR_B);
+ WRITEL(1, MFC_NUM_MASTER);
+
+ ret = mfc_set_wakeup();
+ if (ret != MFCINST_RET_OK) {
+ clk_disable(mfc_sclk);
+ mutex_unlock(&mfc_mutex);
+ return ret;
+ }
+
+ clk_disable(mfc_sclk);
+
+ mutex_unlock(&mfc_mutex);
+
+ return 0;
+}
+
+static struct platform_driver mfc_driver = {
+ .probe = mfc_probe,
+ .remove = mfc_remove,
+ .shutdown = NULL,
+ .suspend = mfc_suspend,
+ .resume = mfc_resume,
+
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "s3c-mfc",
+ },
+};
+
+static char banner[] __initdata = KERN_INFO "S5PC110 MFC Driver, (c) 2009 Samsung Electronics\n";
+
+static int __init mfc_init(void)
+{
+ mfc_info("%s\n", banner);
+
+ if (platform_driver_register(&mfc_driver) != 0) {
+ mfc_err(KERN_ERR "platform device registration failed..\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void __exit mfc_exit(void)
+{
+ platform_driver_unregister(&mfc_driver);
+ mfc_info("S5PC110 MFC Driver exit.\n");
+}
+
+module_init(mfc_init);
+module_exit(mfc_exit);
+
+MODULE_AUTHOR("Jaeryul, Oh");
+MODULE_DESCRIPTION("S3C MFC (Multi Function Codec - FIMV5.0) Device Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/samsung/mfc50/mfc_buffer_manager.c b/drivers/media/video/samsung/mfc50/mfc_buffer_manager.c
new file mode 100644
index 0000000..327637a
--- /dev/null
+++ b/drivers/media/video/samsung/mfc50/mfc_buffer_manager.c
@@ -0,0 +1,350 @@
+/*
+ * drivers/media/video/samsung/mfc50/mfc_buffer_manager.c
+ *
+ * C file for Samsung MFC (Multi Function Codec - FIMV) driver
+ *
+ * Key-Young Park, Copyright (c) 2009 Samsung Electronics
+ * http://www.samsungsemi.com/
+ *
+ * Change Logs
+ * 2009.09.14 - use struct list_head for duble linked list
+ * 2009.11.04 - get physical address via mfc_allocate_buffer (Key Young, Park)
+ * 2009.11.13 - fix free buffer fragmentation (Key Young, Park)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/miscdevice.h>
+#include <linux/platform_device.h>
+#include <linux/wait.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <linux/io.h>
+#include <linux/uaccess.h>
+
+#include <plat/media.h>
+#include <mach/media.h>
+
+#include "mfc_buffer_manager.h"
+#include "mfc_errorno.h"
+#include "mfc_logmsg.h"
+#include "mfc_memory.h"
+
+static struct list_head mfc_alloc_mem_head[MFC_MAX_PORT_NUM];
+static struct list_head mfc_free_mem_head[MFC_MAX_PORT_NUM];
+
+void mfc_print_mem_list(void)
+{
+ struct list_head *pos;
+ struct mfc_alloc_mem *alloc_node;
+ struct mfc_free_mem *free_node;
+ int port_no;
+
+ for (port_no = 0; port_no < MFC_MAX_PORT_NUM; port_no++) {
+ mfc_info("===== %s port%d list =====\n", __func__, port_no);
+ list_for_each(pos, &mfc_alloc_mem_head[port_no])
+ {
+ alloc_node = list_entry(pos, struct mfc_alloc_mem, list);
+ mfc_info("[alloc_list] inst_no: %d, p_addr: 0x%08x, "
+ "u_addr: 0x%p, size: %d\n",
+ alloc_node->inst_no,
+ alloc_node->p_addr,
+ alloc_node->u_addr,
+ alloc_node->size);
+ }
+
+ list_for_each(pos, &mfc_free_mem_head[port_no])
+ {
+ free_node = list_entry(pos, struct mfc_free_mem, list);
+ mfc_info("[free_list] start_addr: 0x%08x size:%d\n",
+ free_node->start_addr , free_node->size);
+ }
+ }
+}
+
+void mfc_merge_fragment(int inst_no)
+{
+ struct list_head *pos, *n;
+ struct mfc_free_mem *node1, *node2;
+ int port_no;
+
+ for (port_no = 0; port_no < MFC_MAX_PORT_NUM; port_no++) {
+ list_for_each_safe(pos, n, &mfc_free_mem_head[port_no])
+ {
+ node1 = list_entry(pos, struct mfc_free_mem, list);
+ node2 = list_entry(n, struct mfc_free_mem, list);
+ if ((node1->start_addr + node1->size) == node2->start_addr) {
+ node2->start_addr = node1->start_addr;
+ node2->size += node1->size;
+ list_del(&(node1->list));
+ kfree(node1);
+ }
+ }
+ }
+
+#if defined(DEBUG)
+ mfc_print_mem_list();
+#endif
+}
+
+
+
+static unsigned int mfc_get_free_mem(int alloc_size, int inst_no, int port_no)
+{
+ struct list_head *pos;
+ struct mfc_free_mem *free_node, *match_node = NULL;
+ unsigned int alloc_addr = 0;
+
+ mfc_debug("request Size : %d\n", alloc_size);
+
+ if (list_empty(&mfc_free_mem_head[port_no])) {
+ mfc_err("all memory is gone\n");
+ return alloc_addr;
+ }
+ /* find best chunk of memory */
+ list_for_each(pos, &mfc_free_mem_head[port_no])
+ {
+ free_node = list_entry(pos, struct mfc_free_mem, list);
+
+ if (match_node != NULL) {
+ if ((free_node->size >= alloc_size) &&
+ (free_node->size < match_node->size))
+ match_node = free_node;
+ } else {
+ if (free_node->size >= alloc_size)
+ match_node = free_node;
+ }
+ }
+
+
+ if (match_node != NULL) {
+ mfc_debug("match : startAddr(0x%08x) size(%d)\n", match_node->start_addr, match_node->size);
+
+ alloc_addr = match_node->start_addr;
+ match_node->start_addr += alloc_size;
+ match_node->size -= alloc_size;
+
+ if (match_node->size < 0x1) /* delete match_node. */
+ mfc_err("there is no suitable chunk...[case 0]\n");
+ } else {
+ mfc_err("there is no suitable chunk....[case 1]\n");
+ return 0;
+ }
+
+ return alloc_addr;
+}
+
+
+int mfc_init_buffer(void)
+{
+ struct mfc_free_mem *free_node;
+ int port_no;
+
+ for (port_no = 0; port_no < MFC_MAX_PORT_NUM; port_no++) {
+ INIT_LIST_HEAD(&mfc_alloc_mem_head[port_no]);
+ INIT_LIST_HEAD(&mfc_free_mem_head[port_no]);
+ /* init free head node */
+ free_node =
+ (struct mfc_free_mem *)kmalloc(sizeof(struct mfc_free_mem), GFP_KERNEL);
+ memset(free_node, 0x00, sizeof(struct mfc_free_mem));
+
+ if (port_no) {
+ free_node->start_addr = mfc_get_port1_buff_paddr();
+ free_node->size = mfc_port1_memsize;
+ } else {
+ free_node->start_addr = mfc_get_port0_buff_paddr();
+ free_node->size = mfc_port1_memsize -
+ (mfc_get_port0_buff_paddr() - mfc_get_fw_buff_paddr());
+ }
+
+ list_add_tail(&(free_node->list), &mfc_free_mem_head[port_no]);
+ }
+
+#if defined(DEBUG)
+ mfc_print_mem_list();
+#endif
+ return 0;
+}
+
+enum mfc_error_code mfc_release_buffer(unsigned char *u_addr)
+{
+ struct list_head *pos;
+ int port_no;
+ struct mfc_alloc_mem *alloc_node;
+ bool found = false;
+
+ for (port_no = 0; port_no < MFC_MAX_PORT_NUM; port_no++) {
+ list_for_each(pos, &mfc_alloc_mem_head[port_no])
+ {
+ alloc_node = list_entry(pos, struct mfc_alloc_mem, list);
+ if (alloc_node->u_addr == u_addr) {
+ mfc_free_alloc_mem(alloc_node, port_no);
+ found = true;
+ break;
+ }
+ }
+ }
+
+#if defined(DEBUG)
+ mfc_print_mem_list();
+#endif
+
+ if (found)
+ return MFCINST_RET_OK;
+ else
+ return MFCINST_MEMORY_INVALID_ADDR;
+}
+
+void mfc_release_all_buffer(int inst_no)
+{
+ struct list_head *pos, *n;
+ int port_no;
+ struct mfc_alloc_mem *alloc_node;
+
+ for (port_no = 0; port_no < MFC_MAX_PORT_NUM; port_no++) {
+ list_for_each_safe(pos, n, &mfc_alloc_mem_head[port_no]) {
+ alloc_node = list_entry(pos, struct mfc_alloc_mem, list);
+ if (alloc_node->inst_no == inst_no) {
+ mfc_free_alloc_mem(alloc_node, port_no);
+ }
+ }
+ }
+
+#if defined(DEBUG)
+ mfc_print_mem_list();
+#endif
+}
+
+void mfc_free_alloc_mem(struct mfc_alloc_mem *alloc_node, int port_no)
+{
+ struct list_head *pos;
+ struct mfc_free_mem *free_node;
+ struct mfc_free_mem *target_node;
+
+ free_node = (struct mfc_free_mem *)kmalloc(sizeof(struct mfc_free_mem), GFP_KERNEL);
+ free_node->start_addr = alloc_node->p_addr;
+ free_node->size = alloc_node->size;
+
+ list_for_each(pos, &mfc_free_mem_head[port_no])
+ {
+ target_node = list_entry(pos, struct mfc_free_mem, list);
+ if (alloc_node->p_addr < target_node->start_addr)
+ break;
+ }
+
+ if (pos == &mfc_free_mem_head[port_no])
+ list_add_tail(&(free_node->list), &(mfc_free_mem_head[port_no]));
+ else
+ list_add_tail(&(free_node->list), pos);
+
+ list_del(&(alloc_node->list));
+ kfree(alloc_node);
+}
+
+enum mfc_error_code mfc_get_phys_addr(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args)
+{
+ int ret, port_no;
+ struct list_head *pos;
+ struct mfc_alloc_mem *alloc_node;
+ struct mfc_get_phys_addr_arg *phys_addr_arg;
+
+ phys_addr_arg = (struct mfc_get_phys_addr_arg *)args;
+ for (port_no = 0; port_no < MFC_MAX_PORT_NUM; port_no++) {
+ list_for_each(pos, &mfc_alloc_mem_head[port_no])
+ {
+ alloc_node = list_entry(pos, struct mfc_alloc_mem, list);
+ if (alloc_node->u_addr == (unsigned char *)phys_addr_arg->u_addr) {
+ mfc_debug("u_addr(0x%08x), p_addr(0x%08x) is found\n",
+ alloc_node->u_addr, alloc_node->p_addr);
+ goto found;
+ }
+ }
+ }
+
+ mfc_err("invalid virtual address(0x%08x)\r\n", phys_addr_arg->u_addr);
+ ret = MFCINST_MEMORY_INVALID_ADDR;
+ goto out_getphysaddr;
+
+found:
+ phys_addr_arg->p_addr = alloc_node->p_addr;
+ ret = MFCINST_RET_OK;
+
+out_getphysaddr:
+ return ret;
+}
+
+enum mfc_error_code mfc_allocate_buffer(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args, int port_no)
+{
+ int ret;
+ int inst_no = mfc_ctx->mem_inst_no;
+ unsigned int start_paddr;
+ struct mfc_mem_alloc_arg *in_param;
+ struct mfc_alloc_mem *alloc_node;
+
+ in_param = (struct mfc_mem_alloc_arg *)args;
+
+ alloc_node = (struct mfc_alloc_mem *)kmalloc(sizeof(struct mfc_alloc_mem), GFP_KERNEL);
+ if (!alloc_node) {
+ mfc_err("There is no more kernel memory");
+ ret = MFCINST_MEMORY_ALLOC_FAIL;
+ goto out_getcodecviraddr;
+ }
+ memset(alloc_node, 0x00, sizeof(struct mfc_alloc_mem));
+
+ /* if user request area, allocate from reserved area */
+ start_paddr = mfc_get_free_mem((int)in_param->buff_size, inst_no, port_no);
+ mfc_debug("start_paddr = 0x%X\n\r", start_paddr);
+
+ if (!start_paddr) {
+ mfc_err("There is no more memory\n\r");
+ in_param->out_uaddr = -1;
+ ret = MFCINST_MEMORY_ALLOC_FAIL;
+ kfree(alloc_node);
+ goto out_getcodecviraddr;
+ }
+
+ alloc_node->p_addr = start_paddr;
+ if (port_no) {
+ alloc_node->v_addr = (unsigned char *)(mfc_get_port1_buff_vaddr() +
+ (alloc_node->p_addr - mfc_get_port1_buff_paddr()));
+ alloc_node->u_addr = (unsigned char *)(in_param->mapped_addr +
+ mfc_ctx->port0_mmap_size +
+ (alloc_node->p_addr - mfc_get_port1_buff_paddr()));
+ } else {
+ alloc_node->v_addr = (unsigned char *)(mfc_get_port0_buff_vaddr() +
+ (alloc_node->p_addr - mfc_get_port0_buff_paddr()));
+ alloc_node->u_addr = (unsigned char *)(in_param->mapped_addr +
+ (alloc_node->p_addr - mfc_get_port0_buff_paddr()));
+ }
+
+ in_param->out_uaddr = (unsigned int)alloc_node->u_addr;
+ in_param->out_paddr = (unsigned int)alloc_node->p_addr;
+ mfc_debug("u_addr : 0x%08x v_addr : 0x%08x p_addr : 0x%08x\n",
+ (unsigned int)alloc_node->u_addr,
+ (unsigned int)alloc_node->v_addr,
+ alloc_node->p_addr);
+
+ alloc_node->size = (int)in_param->buff_size;
+ alloc_node->inst_no = inst_no;
+
+ list_add(&(alloc_node->list), &mfc_alloc_mem_head[port_no]);
+ ret = MFCINST_RET_OK;
+
+#if defined(DEBUG)
+ mfc_print_mem_list();
+#endif
+
+out_getcodecviraddr:
+ return ret;
+}
diff --git a/drivers/media/video/samsung/mfc50/mfc_buffer_manager.h b/drivers/media/video/samsung/mfc50/mfc_buffer_manager.h
new file mode 100644
index 0000000..d40bc04
--- /dev/null
+++ b/drivers/media/video/samsung/mfc50/mfc_buffer_manager.h
@@ -0,0 +1,56 @@
+/*
+ * drivers/media/video/samsung/mfc50/mfc_buffer_manager.h
+ *
+ * Header file for Samsung MFC (Multi Function Codec - FIMV) driver
+ *
+ * Key-Young Park, Copyright (c) 2009 Samsung Electronics
+ * http://www.samsungsemi.com/
+ *
+ * Change Logs
+ * 2009.11.04 - remove mfc_common.[ch]
+ * seperate buffer alloc & set (Key Young, Park)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef _MFC_BUFFER_MANAGER_H_
+#define _MFC_BUFFER_MANAGER_H_
+
+#include <linux/list.h>
+#include "mfc_interface.h"
+#include "mfc_opr.h"
+
+#define MFC_MAX_PORT_NUM 2
+
+/* Struct Definition */
+struct mfc_alloc_mem {
+ struct list_head list; /* strcut list_head for alloc mem */
+ unsigned int p_addr; /* physical address */
+ unsigned char *v_addr; /* virtual address */
+ unsigned char *u_addr; /* virtual address for user mode process */
+ int size; /* memory size */
+ int inst_no; /* instance no */
+};
+
+
+struct mfc_free_mem {
+ struct list_head list; /* struct list_head for free mem */
+ unsigned int start_addr; /* start address of free mem */
+ unsigned int size; /* size of free mem */
+};
+
+
+/* Function Prototype */
+void mfc_print_mem_list(void);
+int mfc_init_buffer(void);
+void mfc_merge_fragment(int inst_no);
+void mfc_release_all_buffer(int inst_no);
+void mfc_free_alloc_mem(struct mfc_alloc_mem *alloc_node, int port_no);
+enum mfc_error_code mfc_release_buffer(unsigned char *u_addr);
+enum mfc_error_code mfc_get_phys_addr(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args);
+enum mfc_error_code mfc_allocate_buffer(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args, int port_no);
+
+#endif /* _MFC_BUFFER_MANAGER_H_ */
diff --git a/drivers/media/video/samsung/mfc50/mfc_errorno.h b/drivers/media/video/samsung/mfc50/mfc_errorno.h
new file mode 100644
index 0000000..7f27115
--- /dev/null
+++ b/drivers/media/video/samsung/mfc50/mfc_errorno.h
@@ -0,0 +1,83 @@
+/*
+ * drivers/media/video/samsung/mfc50/mfc_errorno.h
+ *
+ * Header file for Samsung MFC (Multi Function Codec - FIMV) driver
+ *
+ * Jaeryul Oh, Copyright (c) 2009 Samsung Electronics
+ * http://www.samsungsemi.com/
+ *
+ * Change Logs
+ * 2009.09.14 - Beautify source code (Key Young, Park)
+ * 2009.09.21 - Implement clock & power gating.
+ * including suspend & resume fuction. (Key Young, Park)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MFC_ERRORNO_H_
+#define _MFC_ERRORNO_H_
+
+enum mfc_error_code {
+ MFCINST_RET_OK = 1,
+ MFCINST_ERR_INVALID_PARAM = -1001,
+ MFCINST_ERR_STATE_INVALID = -1002,
+ MFCINST_ERR_POWER_OFF = -1003,
+ MFCINST_ERR_WRONG_CODEC_MODE = -1004,
+ MFCINST_ERR_INIT_FAIL = -1005,
+ MFCINST_ERR_FILE_OPEN_FAIL = -1006,
+ MFCINST_ERR_INTR_TIME_OUT = -1007,
+ MFCINST_ERR_INTR_INIT_FAIL = -1008,
+ MFCINST_ERR_OPEN_FAIL = -1009,
+ MFCINST_ERR_CLOSE_FAIL = -1010,
+
+
+ MFCINST_ERR_DEC_INIT_CMD_FAIL = -2001,
+ MFCINST_ERR_DEC_HEADER_DECODE_FAIL = -2002,
+ MFCINST_ERR_DEC_INIT_BUFFER_FAIL = -2003,
+ MFCINST_ERR_DEC_DECODE_CMD_FAIL = -2004,
+ MFCINST_ERR_DEC_DECODE_DONE_FAIL = -2005,
+ MFCINST_ERR_DEC_INVALID_STRM = -2006,
+ MFCINST_ERR_DEC_STRM_SIZE_INVALID = -2007,
+ MFCINST_ERR_DEC_SEQ_DONE_FAIL = -2008,
+ MFCINST_ERR_DEC_NON_I_FRAME_START = -2009,
+
+ MFCINST_ERR_ENC_INIT_CMD_FAIL = -3001,
+ MFCINST_ERR_ENC_HEADER_DECODE_FAIL = -3002,
+ MFCINST_ERR_ENC_ENCODE_CMD_FAIL = -3003,
+ MFCINST_ERR_ENC_ENCODE_DONE_FAIL = -3004,
+ MFCINST_ERR_ENC_PARAM_INVALID_VALUE = -3005,
+
+ MFCINST_ERR_STRM_BUF_INVALID = -4001,
+ MFCINST_ERR_FRM_BUF_INVALID = -4002,
+ MFCINST_ERR_FRM_BUF_SIZE = -4003,
+
+ MFCINST_ERR_FW_LOAD_FAIL = -5001,
+ MFCINST_ERR_FW_MEMORY_INVALID = -5002,
+ MFCINST_ERR_FW_DMA_SET_FAIL = -5003,
+ MFCINST_ERR_FW_INIT_FAIL = -5004,
+ MFCINST_ERR_SEQ_START_FAIL = -5005,
+
+ MFCINST_INST_NUM_INVALID = -6001,
+ MFCINST_INST_NUM_EXCEEDED = -6002,
+ MFCINST_ERR_SET_CONF = -6003,
+ MFCINST_ERR_GET_CONF = -6004,
+
+ MFCINST_MEMORY_ALLOC_FAIL = -8001,
+ MFCINST_MUTEX_CREATE_FAIL = -8002,
+ MFCINST_POWER_INIT_FAIL = -8003,
+ MFCINST_POWER_ON_OFF_FAIL = -8004,
+ MFCINST_POWER_STATE_INVALID = -8005,
+ MFCINST_POWER_MANAGER_ERR = -8006,
+ MFCINST_SLEEP_FAIL = -8007,
+ MFCINST_WAKEUP_FAIL = -8008,
+
+ MFCINST_MEMORY_INVALID_ADDR = -8101,
+ MFCINST_MEMORY_MAPPING_FAIL = -8102,
+
+ MFCAPI_RET_FAIL = -9001,
+};
+
+#endif /* _MFC_ERRORNO_H_ */
+
diff --git a/drivers/media/video/samsung/mfc50/mfc_interface.h b/drivers/media/video/samsung/mfc50/mfc_interface.h
new file mode 100644
index 0000000..469620a
--- /dev/null
+++ b/drivers/media/video/samsung/mfc50/mfc_interface.h
@@ -0,0 +1,327 @@
+/*
+ * drivers/media/video/samsung/mfc50/mfc_interface.h
+ *
+ * Header file for Samsung MFC (Multi Function Codec - FIMV) driver
+ *
+ * Jaeryul Oh, Copyright (c) 2009 Samsung Electronics
+ * http://www.samsungsemi.com/
+ *
+ * Change Logs
+ * 2009.09.14 - Beautify source code (Key Young, Park)
+ * 2009.10.22 - Change codec name VC1AP_DEC -> VC1_DEC (Key Young, Park)
+ * 2009.11.04 - get physical address via mfc_allocate_buffer (Key Young, Park)
+ * 2009.11.06 - Apply common MFC API (Key Young, Park)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MFC_INTERFACE_H_
+#define _MFC_INTERFACE_H_
+
+#include "mfc_errorno.h"
+
+#define IOCTL_MFC_DEC_INIT 0x00800001
+#define IOCTL_MFC_ENC_INIT 0x00800002
+#define IOCTL_MFC_DEC_EXE 0x00800003
+#define IOCTL_MFC_ENC_EXE 0x00800004
+
+#define IOCTL_MFC_GET_IN_BUF 0x00800010
+#define IOCTL_MFC_FREE_BUF 0x00800011
+#define IOCTL_MFC_GET_PHYS_ADDR 0x00800012
+#define IOCTL_MFC_GET_MMAP_SIZE 0x00800014
+
+#define IOCTL_MFC_SET_CONFIG 0x00800101
+#define IOCTL_MFC_GET_CONFIG 0x00800102
+
+/* MFC H/W support maximum 32 extra DPB */
+#define MFC_MAX_EXTRA_DPB 5
+
+#define ENC_PROFILE_LEVEL(profile, level) ((profile) | ((level) << 8))
+
+#define ENC_PROFILE_MPEG4_SP 0
+#define ENC_PROFILE_MPEG4_ASP 1
+#define ENC_PROFILE_H264_BP 0
+#define ENC_PROFILE_H264_MAIN 1
+#define ENC_PROFILE_H264_HIGH 2
+
+#define ENC_RC_DISABLE 0
+#define ENC_RC_ENABLE_MACROBLOCK 1
+#define ENC_RC_ENABLE_FRAME 2
+
+#define ENC_RC_QBOUND(min_qp, max_qp) ((min_qp) | ((max_qp) << 8))
+#define ENC_RC_MB_CTRL_DARK_DISABLE (1 << 3)
+#define ENC_RC_MB_CTRL_SMOOTH_DISABLE (1 << 2)
+#define ENC_RC_MB_CTRL_STATIC_DISABLE (1 << 1)
+#define ENC_RC_MB_CTRL_ACTIVITY_DISABLE (1 << 0)
+
+
+enum ssbsip_mfc_codec_type {
+ H264_DEC,
+ VC1_DEC, /* VC1 advaced Profile decoding */
+ MPEG4_DEC,
+ XVID_DEC,
+ MPEG1_DEC,
+ MPEG2_DEC,
+ H263_DEC,
+ VC1RCV_DEC, /* VC1 simple/main profile decoding */
+ FIMV1_DEC,
+ FIMV2_DEC,
+ FIMV3_DEC,
+ FIMV4_DEC,
+ H264_ENC,
+ MPEG4_ENC,
+ H263_ENC,
+ UNKNOWN_TYPE
+};
+
+enum ssbsip_mfc_force_set_frame_type {
+ DONT_CARE = 0,
+ I_FRAME = 1,
+ NOT_CODED = 2
+};
+
+enum ssbsip_mfc_dec_conf {
+ MFC_DEC_SETCONF_POST_ENABLE = 1,
+ MFC_DEC_SETCONF_EXTRA_BUFFER_NUM,
+ MFC_DEC_SETCONF_DISPLAY_DELAY,
+ MFC_DEC_SETCONF_IS_LAST_FRAME,
+ MFC_DEC_SETCONF_SLICE_ENABLE,
+ MFC_DEC_SETCONF_CRC_ENABLE,
+ MFC_DEC_SETCONF_FIMV1_WIDTH_HEIGHT,
+ MFC_DEC_SETCONF_FRAME_TAG,
+ MFC_DEC_GETCONF_CRC_DATA,
+ MFC_DEC_GETCONF_BUF_WIDTH_HEIGHT,
+ FC_DEC_GETCONF_CROP_INFO,
+ MFC_DEC_GETCONF_FRAME_TAG
+};
+
+enum ssbsip_mfc_enc_conf {
+ MFC_ENC_SETCONF_FRAME_TYPE = 100,
+ MFC_ENC_SETCONF_CHANGE_FRAME_RATE,
+ MFC_ENC_SETCONF_CHANGE_BIT_RATE,
+ MFC_ENC_SETCONF_FRAME_TAG,
+ MFC_ENC_SETCONF_ALLOW_FRAME_SKIP,
+ MFC_ENC_GETCONF_FRAME_TAG
+};
+
+struct mfc_strm_ref_buf_arg {
+ unsigned int strm_ref_y;
+ unsigned int mv_ref_yc;
+};
+
+struct mfc_frame_buf_arg {
+ unsigned int luma;
+ unsigned int chroma;
+};
+
+struct mfc_enc_init_mpeg4_arg {
+ enum ssbsip_mfc_codec_type in_codec_type; /* [IN] codec type */
+ int in_width; /* [IN] width of YUV420 frame to be encoded */
+ int in_height; /* [IN] height of YUV420 frame to be encoded */
+ int in_profile_level; /* [IN] profile & level */
+ int in_gop_num; /* [IN] GOP Number (interval of I-frame) */
+ int in_frame_qp; /* [IN] the quantization parameter of the frame */
+ int in_frame_P_qp; /* [IN] the quantization parameter of the P frame */
+ int in_frame_B_qp; /* [IN] the quantization parameter of the B frame */
+
+ int in_RC_frm_enable; /* [IN] RC enable (0:disable, 1:frame level RC) */
+ int in_RC_framerate; /* [IN] RC parameter (framerate) */
+ int in_RC_bitrate; /* [IN] RC parameter (bitrate in kbps) */
+ int in_RC_qbound; /* [IN] RC parameter (Q bound) */
+ int in_RC_rpara; /* [IN] RC parameter (Reaction Coefficient) */
+
+ int in_MS_mode; /* [IN] Multi-slice mode (0:single, 1:multiple) */
+ int in_MS_size; /* [IN] Multi-slice size (in num. of mb or byte) */
+ int in_mb_refresh; /* [IN] Macroblock refresh */
+ int in_interlace_mode; /* [IN] interlace mode(0:progressive, 1:interlace) */
+ int in_BframeNum; /* [IN] B frame number */
+
+ int in_pad_ctrl_on; /* [IN] Enable (1) / Disable (0) padding */
+ int in_luma_pad_val; /* [IN] pad value if pad_ctrl_on is Enable */
+ int in_cb_pad_val;
+ int in_cr_pad_val;
+
+ unsigned int in_mapped_addr;
+ struct mfc_strm_ref_buf_arg out_u_addr;
+ struct mfc_strm_ref_buf_arg out_p_addr;
+ struct mfc_strm_ref_buf_arg out_buf_size;
+ unsigned int out_header_size;
+
+ /* MPEG4 Only */
+ int in_qpelME_enable; /* [IN] Quarter-pel MC enable(1:enable, 0:disable) */
+ int in_time_increament_res; /* [IN] time increment resolution */
+ int in_time_vop_time_increament; /* [IN] time increment */
+};
+
+//struct mfc_enc_init_mpeg4_arg mfc_enc_init_h263_arg;
+
+struct mfc_enc_init_h264_arg {
+ enum ssbsip_mfc_codec_type in_codec_type; /* [IN] codec type */
+ int in_width; /* [IN] width of YUV420 frame to be encoded */
+ int in_height; /* [IN] height of YUV420 frame to be encoded */
+ int in_profile_level; /* [IN] profile & level */
+ int in_gop_num; /* [IN] GOP Number (interval of I-frame) */
+ int in_frame_qp; /* [IN] the quantization parameter of the frame */
+ int in_frame_P_qp; /* [IN] the quantization parameter of the P frame */
+ int in_frame_B_qp; /* [IN] the quantization parameter of the B frame */
+
+ int in_RC_frm_enable; /* [IN] RC enable (0:disable, 1:frame level RC) */
+ int in_RC_framerate; /* [IN] RC parameter (framerate) */
+ int in_RC_bitrate; /* [IN] RC parameter (bitrate in kbps) */
+ int in_RC_qbound; /* [IN] RC parameter (Q bound) */
+ int in_RC_rpara; /* [IN] RC parameter (Reaction Coefficient) */
+
+ int in_MS_mode; /* [IN] Multi-slice mode (0:single, 1:multiple) */
+ int in_MS_size; /* [IN] Multi-slice size (in num. of mb or byte) */
+ int in_mb_refresh; /* [IN] Macroblock refresh */
+ int in_interlace_mode; /* [IN] interlace mode(0:progressive, 1:interlace) */
+ int in_BframeNum;
+
+ int in_pad_ctrl_on; /* [IN] Enable padding control */
+ int in_luma_pad_val; /* [IN] Luma pel value used to fill padding area */
+ int in_cb_pad_val; /* [IN] CB pel value used to fill padding area */
+ int in_cr_pad_val; /* [IN] CR pel value used to fill padding area */
+
+ unsigned int in_mapped_addr;
+ struct mfc_strm_ref_buf_arg out_u_addr;
+ struct mfc_strm_ref_buf_arg out_p_addr;
+ struct mfc_strm_ref_buf_arg out_buf_size;
+ unsigned int out_header_size;
+
+ /* H264 Only */
+ int in_RC_mb_enable; /* [IN] RC enable (0:disable, 1:MB level RC) */
+ int in_reference_num; /* [IN] The number of reference pictures used */
+ int in_ref_num_p; /* [IN] The number of reference pictures used for P pictures */
+ int in_RC_mb_dark_disable; /* [IN] Disable adaptive rate control on dark region */
+ int in_RC_mb_smooth_disable; /* [IN] Disable adaptive rate control on smooth region */
+ int in_RC_mb_static_disable; /* [IN] Disable adaptive rate control on static region */
+ int in_RC_mb_activity_disable; /* [IN] Disable adaptive rate control on static region */
+ int in_deblock_filt; /* [IN] disable the loop filter */
+ int in_deblock_alpha_C0; /* [IN] Alpha & C0 offset for H.264 loop filter */
+ int in_deblock_beta; /* [IN] Beta offset for H.264 loop filter */
+ int in_symbolmode; /* [IN] The mode of entropy coding(CABAC, CAVLC) */
+ int in_transform8x8_mode; /* [IN] Allow 8x8 transform(only for high profile) */
+ int in_md_interweight_pps; /* [IN] Inter weighted parameter for mode decision */
+ int in_md_intraweight_pps; /* [IN] Intra weighted parameter for mode decision */
+};
+
+struct mfc_enc_exe_arg {
+ enum ssbsip_mfc_codec_type in_codec_type; /* [IN] codec type */
+ unsigned int in_Y_addr; /* [IN] In-buffer addr of Y component */
+ unsigned int in_CbCr_addr; /* [IN] In-buffer addr of CbCr component */
+ unsigned int in_Y_addr_vir; /* [IN] In-buffer addr of Y component */
+ unsigned int in_CbCr_addr_vir; /* [IN] In-buffer addr of CbCr component */
+ unsigned int in_strm_st; /* [IN] Out-buffer start addr of encoded strm */
+ unsigned int in_strm_end; /* [IN] Out-buffer end addr of encoded strm */
+ int in_frametag; /* [IN] unique frame ID */
+
+ unsigned int out_frame_type; /* [OUT] frame type */
+ int out_encoded_size; /* [OUT] Length of Encoded video stream */
+ unsigned int out_encoded_Y_paddr; /* [OUT] physical Y address which is flushed */
+ unsigned int out_encoded_C_paddr; /* [OUT] physical C address which is flushed */
+ int out_frametag_top; /* [OUT] unique frame ID of an output frame or top field */
+ int out_frametag_bottom; /* [OUT] unique frame ID of bottom field */
+};
+
+struct mfc_dec_init_arg {
+ enum ssbsip_mfc_codec_type in_codec_type; /* [IN] codec type */
+ unsigned int in_strm_buf; /* [IN] the physical address of STRM_BUF */
+ int in_strm_size; /* [IN] size of video stream filled in STRM_BUF */
+ int in_packed_PB; /* [IN] Is packed PB frame or not, 1: packedPB 0: unpacked */
+
+ int out_img_width; /* [OUT] width of YUV420 frame */
+ int out_img_height; /* [OUT] height of YUV420 frame */
+ int out_buf_width; /* [OUT] width of YUV420 frame */
+ int out_buf_height; /* [OUT] height of YUV420 frame */
+ int out_dpb_cnt; /* [OUT] the number of buffers which is nessary during decoding */
+
+ int out_crop_top_offset; /* [OUT] crop information, top offset */
+ int out_crop_bottom_offset; /* [OUT] crop information, bottom offset */
+ int out_crop_left_offset; /* [OUT] crop information, left offset */
+ int out_crop_right_offset; /* [OUT] crop information, right offset */
+
+ struct mfc_frame_buf_arg in_frm_buf; /* [IN] the address of dpb FRAME_BUF */
+ struct mfc_frame_buf_arg in_frm_size; /* [IN] size of dpb FRAME_BUF */
+ unsigned int in_mapped_addr;
+
+ struct mfc_frame_buf_arg out_u_addr;
+ struct mfc_frame_buf_arg out_p_addr;
+ struct mfc_frame_buf_arg out_frame_buf_size;
+};
+
+struct mfc_dec_exe_arg {
+ enum ssbsip_mfc_codec_type in_codec_type; /* [IN] codec type */
+ unsigned int in_strm_buf; /* [IN] the physical address of STRM_BUF */
+ int in_strm_size; /* [IN] Size of video stream filled in STRM_BUF */
+ struct mfc_frame_buf_arg in_frm_buf; /* [IN] the address of dpb FRAME_BUF */
+ struct mfc_frame_buf_arg in_frm_size; /* [IN] size of dpb FRAME_BUF */
+ int in_frametag; /* [IN] unique frame ID */
+
+ unsigned int out_display_Y_addr; /* [OUT] the physical address of display buf */
+ unsigned int out_display_C_addr; /* [OUT] the physical address of display buf */
+ int out_display_status; /* [OUT] whether display frame exist or not. */
+ int out_timestamp_top; /* [OUT] presentation time of an output frame or top field */
+ int out_timestamp_bottom; /* [OUT] presentation time of bottom field */
+ int out_consume_bytes; /* [OUT] consumed bytes when decoding finished */
+ int out_frametag_top; /* [OUT] unique frame ID of an output frame or top field */
+ int out_frametag_bottom; /* [OUT] unique frame ID of bottom field */
+ int out_res_change; /* [OUT] whether resolution is changed or not (0, 1, 2) */
+ int out_crop_top_offset; /* [OUT] crop information, top offset */
+ int out_crop_bottom_offset; /* [OUT] crop information, bottom offset */
+ int out_crop_left_offset; /* [OUT] crop information, left offset */
+ int out_crop_right_offset; /* [OUT] crop information, right offset */
+};
+
+struct mfc_get_config_arg {
+ int in_config_param; /* [IN] Configurable parameter type */
+ int out_config_value[4]; /* [IN] Values to get for the configurable parameter. */
+};
+
+struct mfc_set_config_arg {
+ int in_config_param; /* [IN] Configurable parameter type */
+ int in_config_value[2]; /* [IN] Values to be set for the configurable parameter. */
+ int out_config_value_old[2]; /* [OUT] Old values of the configurable parameters */
+};
+
+struct mfc_get_phys_addr_arg {
+ unsigned int u_addr;
+ unsigned int p_addr;
+};
+
+struct mfc_mem_alloc_arg {
+ enum ssbsip_mfc_codec_type codec_type;
+ int buff_size;
+ unsigned int mapped_addr;
+ unsigned int out_uaddr;
+ unsigned int out_paddr;
+};
+
+struct mfc_mem_free_arg {
+ unsigned int u_addr;
+};
+
+union mfc_args {
+ struct mfc_enc_init_mpeg4_arg enc_init_mpeg4;
+ struct mfc_enc_init_mpeg4_arg enc_init_h263;
+ struct mfc_enc_init_h264_arg enc_init_h264;
+ struct mfc_enc_exe_arg enc_exe;
+
+ struct mfc_dec_init_arg dec_init;
+ struct mfc_dec_exe_arg dec_exe;
+
+ struct mfc_get_config_arg get_config;
+ struct mfc_set_config_arg set_config;
+
+ struct mfc_mem_alloc_arg mem_alloc;
+ struct mfc_mem_free_arg mem_free;
+ struct mfc_get_phys_addr_arg get_phys_addr;
+};
+
+struct mfc_common_args {
+ enum mfc_error_code ret_code; /* [OUT] error code */
+ union mfc_args args;
+};
+
+#endif /* _MFC_INTERFACE_H_ */
diff --git a/drivers/media/video/samsung/mfc50/mfc_intr.c b/drivers/media/video/samsung/mfc50/mfc_intr.c
new file mode 100644
index 0000000..035d460
--- /dev/null
+++ b/drivers/media/video/samsung/mfc50/mfc_intr.c
@@ -0,0 +1,202 @@
+/*
+ * drivers/media/video/samsung/mfc50/mfc_intr.c
+ *
+ * C file for Samsung MFC (Multi Function Codec - FIMV) driver
+ *
+ * Jaeryul Oh, Copyright (c) 2009 Samsung Electronics
+ * http://www.samsungsemi.com/
+ *
+ * Change Logs
+ * 2009.09.14 - Beautify source code (Key Young, Park)
+ * 2009.09.21 - Implement clock & power gating.
+ * including suspend & resume fuction. (Key Young, Park)
+ * 2009.10.09 - Add error handling rountine (Key Young, Park)
+ * 2009.10.13 - Change wait_for_done (Key Young, Park)
+ * 2009.11.04 - remove mfc_common.[ch]
+ * seperate buffer alloc & set (Key Young, Park)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/io.h>
+
+#include <plat/regs-mfc.h>
+
+#include "mfc_logmsg.h"
+#include "mfc_opr.h"
+#include "mfc_memory.h"
+#include "mfc_intr.h"
+
+
+#define MFC_WAIT_1_TIME 100
+#define MFC_WAIT_2_TIME 200
+#define MFC_WAIT_3_TIME 400
+#define MFC_WAIT_4_TIME 600
+#define MFC_WAIT_5_TIME 800
+#define MFC_WAIT_6_TIME 1000
+
+#define ENABLE_MFC_INTERRUPT_DEBUG 0 /* 0: Disable 1: Enable */
+
+#if defined(MFC_REQUEST_TIME)
+struct timeval mfc_wakeup_before;
+struct timeval mfc_wakeup_after;
+#endif
+
+static unsigned int mfc_int_type;
+static unsigned int mfc_disp_err_status;
+static unsigned int mfc_dec_err_status;
+static bool irq_sync;
+static DECLARE_WAIT_QUEUE_HEAD(mfc_wait_queue);
+static DEFINE_SPINLOCK(mfc_irq_lock);
+
+#if !defined(MFC_POLLING)
+irqreturn_t mfc_irq(int irq, void *dev_id)
+{
+ unsigned int int_reason;
+ unsigned int err_status;
+
+ int_reason = READL(MFC_RISC2HOST_COMMAND) & 0x1FFFF;
+ err_status = READL(MFC_RISC2HOST_ARG2);
+
+ mfc_disp_err_status = err_status >> 16;
+ mfc_dec_err_status = err_status & 0xFFFF;
+
+ mfc_debug_L0("mfc_irq() : Interrupt !! : %d\n", int_reason);
+
+ if (((int_reason & R2H_CMD_FRAME_DONE_RET) == R2H_CMD_FRAME_DONE_RET) ||
+ ((int_reason & R2H_CMD_SEQ_DONE_RET) == R2H_CMD_SEQ_DONE_RET) ||
+ ((int_reason & R2H_CMD_SYS_INIT_RET) == R2H_CMD_SYS_INIT_RET) ||
+ ((int_reason & R2H_CMD_OPEN_INSTANCE_RET) == R2H_CMD_OPEN_INSTANCE_RET) ||
+ ((int_reason & R2H_CMD_CLOSE_INSTANCE_RET) == R2H_CMD_CLOSE_INSTANCE_RET) ||
+ ((int_reason & R2H_CMD_INIT_BUFFERS_RET) == R2H_CMD_INIT_BUFFERS_RET) ||
+ ((int_reason & R2H_CMD_DECODE_ERR_RET) == R2H_CMD_DECODE_ERR_RET) ||
+ ((int_reason & R2H_CMD_SLICE_DONE_RET) == R2H_CMD_SLICE_DONE_RET) ||
+ ((int_reason & R2H_CMD_ERROR_RET) == R2H_CMD_ERROR_RET)) {
+ mfc_int_type = int_reason;
+ irq_sync = true;
+ wake_up(&mfc_wait_queue);
+ } else {
+ irq_sync = false;
+ mfc_info("Strange Interrupt !! : %d\n", int_reason);
+ }
+
+
+ WRITEL(0, MFC_RISC_HOST_INT);
+ WRITEL(0, MFC_RISC2HOST_COMMAND);
+ WRITEL(0xffff, MFC_SI_RTN_CHID);
+
+ return IRQ_HANDLED;
+}
+#endif
+
+void mfc_interrupt_debug(int nCnt)
+{
+ int nn = 0;
+ for (nn = 0; nn < nCnt; nn++) {
+ mdelay(100);
+ mfc_err("[%d] Timeout (0x64: 0x%08x) (0xF4: 0x%08x)\n", nn, READL(0x64), READL(0xF4));
+ }
+}
+
+int mfc_wait_for_done(enum mfc_wait_done_type command)
+{
+ unsigned int nwait_time = 100;
+ unsigned int ret_val = 1;
+ unsigned long flags;
+
+ if ((command == R2H_CMD_CLOSE_INSTANCE_RET) ||
+ (command == R2H_CMD_OPEN_INSTANCE_RET) ||
+ (command == R2H_CMD_SYS_INIT_RET) ||
+ (command == R2H_CMD_FW_STATUS_RET))
+ nwait_time = MFC_WAIT_6_TIME;
+ else
+ nwait_time = MFC_WAIT_2_TIME;
+
+
+#if defined(MFC_REQUEST_TIME)
+ long sec, msec;
+#endif
+
+#if defined(MFC_POLLING)
+ unsigned long timeo = jiffies;
+ timeo += 20; /* waiting for 100ms */
+#endif
+
+#if defined(MFC_REQUEST_TIME)
+ do_gettimeofday(&mfc_wakeup_before);
+ if (mfc_wakeup_before.tv_usec - mfc_wakeup_after.tv_usec < 0) {
+ msec = 1000000 + mfc_wakeup_before.tv_usec - mfc_wakeup_after.tv_usec;
+ sec = mfc_wakeup_before.tv_sec - mfc_wakeup_after.tv_sec - 1;
+ } else {
+ msec = mfc_wakeup_before.tv_usec - mfc_wakeup_after.tv_usec;
+ sec = mfc_wakeup_before.tv_sec - mfc_wakeup_after.tv_sec;
+ }
+#endif
+
+#if defined(MFC_POLLING)
+ while (time_before(jiffies, timeo))
+ ret_val = READL(MFC_RISC2HOST_COMMAND) & 0x1ffff;
+ if (ret_val != 0) {
+ WRITEL(0, MFC_RISC_HOST_INT);
+ WRITEL(0, MFC_RISC2HOST_COMMAND);
+ WRITEL(0xffff, MFC_SI_RTN_CHID);
+ mfc_int_type = ret_val;
+ break;
+ }
+ msleep_interruptible(2);
+ }
+
+ if (ret_val == 0)
+ printk(KERN_INFO "MFC timeouted!\n");
+#else
+ if (wait_event_timeout(mfc_wait_queue, irq_sync, nwait_time) == 0) {
+ ret_val = 0;
+ mfc_err("Interrupt Time Out(Cmd: %d) (Ver: 0x%08x) (0x64: 0x%08x) (0xF4: 0x%08x) (0x80: 0x%08x)\n", command, READL(0x58), READL(0x64), READL(0xF4), READL(0x80));
+
+#if ENABLE_MFC_INTERRUPT_DEBUG /* For MFC Interrupt Debugging. */
+ mfc_interrupt_debug(10);
+#endif
+
+ mfc_int_type = 0;
+ return ret_val;
+ } else if (mfc_int_type == R2H_CMD_DECODE_ERR_RET) {
+ mfc_err("Decode Error Returned Disp Error Status(%d), Dec Error Status(%d)\n", mfc_disp_err_status, mfc_dec_err_status);
+ } else if (command != mfc_int_type) {
+ mfc_err("Interrupt Error Returned (%d) waiting for (%d)\n", mfc_int_type, command);
+ }
+#endif
+ spin_lock_irqsave(&mfc_irq_lock, flags);
+ irq_sync = false;
+ spin_unlock_irqrestore(&mfc_irq_lock, flags);
+
+#if defined(MFC_REQUEST_TIME)
+ do_gettimeofday(&mfc_wakeup_after);
+ if (mfc_wakeup_after.tv_usec - mfc_wakeup_before.tv_usec < 0) {
+ msec = 1000000 + mfc_wakeup_after.tv_usec - mfc_wakeup_before.tv_usec;
+ sec = mfc_wakeup_after.tv_sec - mfc_wakeup_before.tv_sec - 1;
+ } else {
+ msec = mfc_wakeup_after.tv_usec - mfc_wakeup_before.tv_usec;
+ sec = mfc_wakeup_after.tv_sec - mfc_wakeup_before.tv_sec;
+ }
+
+ mfc_info("mfc_wait_for_done: mfc request interval time is %ld(sec), %ld(msec)\n", sec, msec);
+#endif
+
+ ret_val = mfc_int_type;
+ mfc_int_type = 0;
+
+ return ret_val;
+}
+
+
+int mfc_return_code(void)
+{
+ return mfc_dec_err_status;
+}
diff --git a/drivers/media/video/samsung/mfc50/mfc_intr.h b/drivers/media/video/samsung/mfc50/mfc_intr.h
new file mode 100644
index 0000000..ed156b9
--- /dev/null
+++ b/drivers/media/video/samsung/mfc50/mfc_intr.h
@@ -0,0 +1,25 @@
+/*
+ * drivers/media/video/samsung/mfc50/mfc_intr.h
+ *
+ * Header file for Samsung MFC (Multi Function Codec - FIMV) driver
+ *
+ * Key-Young Park, Copyright (c) 2009 Samsung Electronics
+ * http://www.samsungsemi.com/
+ *
+ * Change Logs
+ * 2009.10.13 - Separate from mfc_common.h(Key Young, Park)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MFC_INTR_H_
+#define _MFC_INTR_H_
+
+#include <linux/interrupt.h>
+
+irqreturn_t mfc_irq(int irq, void *dev_id);
+int mfc_wait_for_done(enum mfc_wait_done_type command);
+int mfc_return_code(void);
+#endif
diff --git a/drivers/media/video/samsung/mfc50/mfc_logmsg.h b/drivers/media/video/samsung/mfc50/mfc_logmsg.h
new file mode 100644
index 0000000..881d733
--- /dev/null
+++ b/drivers/media/video/samsung/mfc50/mfc_logmsg.h
@@ -0,0 +1,72 @@
+/*
+ * drivers/media/video/samsung/mfc50/mfc_logmsg.h
+ *
+ * Header file for Samsung MFC (Multi Function Codec - FIMV) driver
+ *
+ * Jaeryul Oh, Copyright (c) 2009 Samsung Electronics
+ * http://www.samsungsemi.com/
+ *
+ * Change Logs
+ * 2009.09.14 - Beautify source code (Key Young, Park)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MFC_LOGMSG_H_
+#define _MFC_LOGMSG_H_
+
+/* debug macros */
+#define MFC_DEBUG(fmt, ...) \
+ do { \
+ printk(KERN_DEBUG \
+ "%s: " fmt, __func__, ##__VA_ARGS__); \
+ } while (0)
+
+#define MFC_ERROR(fmt, ...) \
+ do { \
+ printk(KERN_ERR \
+ "%s: " fmt, __func__, ##__VA_ARGS__); \
+ } while (0)
+
+#define MFC_NOTICE(fmt, ...) \
+ do { \
+ printk(KERN_NOTICE \
+ "%s: " fmt, __func__, ##__VA_ARGS__); \
+ } while (0)
+
+#define MFC_INFO(fmt, ...) \
+ do { \
+ printk(KERN_INFO \
+ "%s: " fmt, __func__, ##__VA_ARGS__); \
+ } while (0)
+
+#define MFC_WARN(fmt, ...) \
+ do { \
+ printk(KERN_WARNING \
+ "%s: " fmt, __func__, ##__VA_ARGS__); \
+ } while (0)
+
+
+#ifdef CONFIG_VIDEO_MFC50_DEBUG
+#define mfc_debug(fmt, ...) MFC_INFO(fmt, ##__VA_ARGS__)
+#define mfc_debug_L0(fmt, ...) MFC_INFO(fmt, ##__VA_ARGS__)
+#else
+#define mfc_debug(fmt, ...)
+#define mfc_debug_L0(fmt, ...)
+#endif
+
+#if defined(DEBUG_LEVEL_0)
+#define mfc_debug_L0(fmt, ...) MFC_INFO(fmt, ##__VA_ARGS__)
+#define mfc_debug(fmt, ...) MFC_INFO(fmt, ##__VA_ARGS__)
+#elseif define(DEBUG_LEVEL_1)
+#define mfc_debug(fmt, ...) MFC_INFO(fmt, ##__VA_ARGS__)
+#endif
+
+#define mfc_err(fmt, ...) MFC_ERROR(fmt, ##__VA_ARGS__)
+#define mfc_notice(fmt, ...) MFC_NOTICE(fmt, ##__VA_ARGS__)
+#define mfc_info(fmt, ...) MFC_INFO(fmt, ##__VA_ARGS__)
+#define mfc_warn(fmt, ...) MFC_WARN(fmt, ##__VA_ARGS__)
+
+#endif /* _MFC_LOGMSG_H_ */
diff --git a/drivers/media/video/samsung/mfc50/mfc_memory.c b/drivers/media/video/samsung/mfc50/mfc_memory.c
new file mode 100644
index 0000000..8668b52
--- /dev/null
+++ b/drivers/media/video/samsung/mfc50/mfc_memory.c
@@ -0,0 +1,65 @@
+/*
+ * drivers/media/video/samsung/mfc50/mfc_memory.c
+ *
+ * C file for Samsung MFC (Multi Function Codec - FIMV) driver
+ *
+ * Jaeryul Oh, Copyright (c) 2009 Samsung Electronics
+ * http://www.samsungsemi.com/
+ *
+ * Change Logs
+ * 2009.09.14 - Beautify source code (Key Young, Park)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <mach/map.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <asm/sizes.h>
+#include <linux/memory.h>
+#include <plat/media.h>
+
+#include "mfc_memory.h"
+#include "mfc_logmsg.h"
+#include "mfc_interface.h"
+
+void __iomem *mfc_sfr_base_vaddr;
+unsigned int mfc_port0_base_paddr, mfc_port1_base_paddr;
+unsigned char *mfc_port0_base_vaddr, *mfc_port1_base_vaddr;
+unsigned int mfc_port0_memsize, mfc_port1_memsize;
+
+unsigned int mfc_get_fw_buff_paddr(void)
+{
+ return mfc_port0_base_paddr;
+}
+
+unsigned char *mfc_get_fw_buff_vaddr(void)
+{
+ return mfc_port0_base_vaddr;
+}
+
+unsigned int mfc_get_port0_buff_paddr(void)
+{
+ return mfc_port0_base_paddr + MFC_FW_MAX_SIZE;
+}
+
+unsigned char *mfc_get_port0_buff_vaddr(void)
+{
+ return mfc_port0_base_vaddr + MFC_FW_MAX_SIZE;
+}
+
+unsigned char *mfc_get_port1_buff_vaddr(void)
+{
+ return mfc_port1_base_vaddr;
+}
+
+unsigned int mfc_get_port1_buff_paddr(void)
+{
+ return mfc_port1_base_paddr;
+}
+
diff --git a/drivers/media/video/samsung/mfc50/mfc_memory.h b/drivers/media/video/samsung/mfc50/mfc_memory.h
new file mode 100644
index 0000000..2ad0987
--- /dev/null
+++ b/drivers/media/video/samsung/mfc50/mfc_memory.h
@@ -0,0 +1,110 @@
+/*
+ * drivers/media/video/samsung/mfc50/mfc_memory.h
+ *
+ * Header file for Samsung MFC (Multi Function Codec - FIMV) driver
+ *
+ * Jaeryul Oh, Copyright (c) 2009 Samsung Electronics
+ * http://www.samsungsemi.com/
+ *
+ * Change Logs
+ * 2009.09.14 - Beautify source code (Key Young, Park)
+ * 2009.10.08 - Apply 9/30 firmware(Key Young, Park)
+ * 2009.11.04 - remove mfc_common.[ch]
+ * seperate buffer alloc & set (Key Young, Park)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef _MFC_MEMORY_H_
+#define _MFC_MEMORY_H_
+
+#include "mfc_opr.h"
+
+#ifdef CONFIG_VIDEO_MFC_MAX_INSTANCE
+#define MFC_MAX_INSTANCE_NUM (CONFIG_VIDEO_MFC_MAX_INSTANCE)
+#endif
+
+#define SET_MEM_1080P 1
+#define SET_MEM_720P 0
+
+#if SET_MEM_1080P
+/*
+ * Memory Configuration for 1080P
+ * MFC_FW_TOTAL_BUF_SIZE should be aligned to 4KB (page size)
+ */
+#define MFC_FW_TOTAL_BUF_SIZE (ALIGN_TO_4KB(MFC_FW_MAX_SIZE + MFC_MAX_INSTANCE_NUM * MFC_FW_BUF_SIZE))
+#define MFC_FW_MAX_SIZE (2 * 1024 * 1024) /* 2MB : 2x1024x1024 */
+#define MFC_FW_BUF_SIZE (512 * 1024) /* 512KB : 512x1024 size per instance */
+
+#define RISC_BUF_SIZE (0x80000) /* 512KB : 512x1024 size per instance */
+#define CPB_BUF_SIZE (0x300000) /* 3MB : 3x1024x1024 for decoder */
+#define DESC_BUF_SIZE (0x20000) /* 128KB : 128x1024 */
+#define SHARED_BUF_SIZE (0x10000) /* 64KB : 64x1024 */
+#define PRED_BUF_SIZE (0x10000) /* 64KB : 64x1024 */
+#define DEC_CODEC_BUF_SIZE (0x80000) /* 512KB : 512x1024 size per instance */
+#define ENC_CODEC_BUF_SIZE (0x50000) /* 320KB : 512x1024 size per instance */
+
+#define STREAM_BUF_SIZE (0x300000) /* 3MB : 3x1024x1024 for encoder */
+#define MV_BUF_SIZE (0x10000) /* 64KB : 64x1024 for encoder */
+
+#define H264DEC_CONTEXT_SIZE (640 * 1024) /* 600KB -> 640KB for alignment */
+#define VC1DEC_CONTEXT_SIZE (64 * 1024) /* 10KB -> 64KB for alignment */
+#define MPEG2DEC_CONTEXT_SIZE (64 * 1024) /* 10KB -> 64KB for alignment */
+#define H263DEC_CONTEXT_SIZE (64 * 1024) /* 10KB -> 64KB for alignment */
+#define MPEG4DEC_CONTEXT_SIZE (64 * 1024) /* 10KB -> 64KB for alignment */
+#define H264ENC_CONTEXT_SIZE (640 * 1024) /* 64KB -> 640KB for alignment */
+#define MPEG4ENC_CONTEXT_SIZE (64 * 1024) /* 10KB -> 64KB for alignment */
+#define H263ENC_CONTEXT_SIZE (64 * 1024) /* 10KB -> 64KB for alignment */
+
+#else
+/* Memory Configuration for 720P */
+#define MFC_FW_TOTAL_BUF_SIZE (ALIGN_TO_4KB(MFC_FW_MAX_SIZE + MFC_MAX_INSTANCE_NUM * MFC_FW_BUF_SIZE))
+#define MFC_FW_MAX_SIZE (2 * 1024 * 1024) /* 2MB : 2x1024x1024 */
+#define MFC_FW_BUF_SIZE (512 * 1024) /* 512KB : 512x1024 size per instance */
+
+#define RISC_BUF_SIZE (0x80000) /* 512KB : 512x1024 size per instance */
+#define CPB_BUF_SIZE (0x300000) /* 3MB : 3x1024x1024 for decoder */
+#define DESC_BUF_SIZE (0x20000) /* 128KB : 128x1024 */
+#define SHARED_BUF_SIZE (0x10000) /* 64KB : 64x1024 */
+#define PRED_BUF_SIZE (0x10000) /* 64KB : 64x1024 */
+#define DEC_CODEC_BUF_SIZE (0x80000) /* 512KB : 512x1024 size per instance */
+#define ENC_CODEC_BUF_SIZE (0x50000) /* 320KB : 512x1024 size per instance */
+
+#define STREAM_BUF_SIZE (0x200000) /* 2MB : 2x1024x1024 for encoder */
+#define MV_BUF_SIZE (0x10000) /* 64KB : 64x1024 for encoder */
+
+#define H264DEC_CONTEXT_SIZE (640 * 1024) /* 600KB -> 640KB for alignment */
+#define VC1DEC_CONTEXT_SIZE (64 * 1024) /* 10KB -> 64KB for alignment */
+#define MPEG2DEC_CONTEXT_SIZE (64 * 1024) /* 10KB -> 64KB for alignment */
+#define H263DEC_CONTEXT_SIZE (64 * 1024) /* 10KB -> 64KB for alignment */
+#define MPEG4DEC_CONTEXT_SIZE (64 * 1024) /* 10KB -> 64KB for alignment */
+#define H264ENC_CONTEXT_SIZE (64 * 1024) /* 10KB -> 64KB for alignment */
+#define MPEG4ENC_CONTEXT_SIZE (64 * 1024) /* 10KB -> 64KB for alignment */
+#define H263ENC_CONTEXT_SIZE (64 * 1024) /* 10KB -> 64KB for alignment */
+
+#endif
+
+unsigned int mfc_get_fw_buf_phys_addr(void);
+unsigned int mfc_get_risc_buf_phys_addr(int instNo);
+
+extern unsigned char *mfc_port0_base_vaddr; /* port1 */
+extern unsigned char *mfc_port1_base_vaddr; /* port0 */
+extern unsigned int mfc_port0_base_paddr, mfc_port1_base_paddr;
+extern unsigned int mfc_port0_memsize, mfc_port1_memsize;
+
+unsigned int mfc_get_fw_buff_paddr(void);
+unsigned char *mfc_get_fw_buff_vaddr(void);
+unsigned int mfc_get_port0_buff_paddr(void);
+unsigned char *mfc_get_port0_buff_vaddr(void);
+unsigned int mfc_get_port1_buff_paddr(void);
+unsigned char *mfc_get_port1_buff_vaddr(void);
+
+extern void __iomem *mfc_sfr_base_vaddr;
+
+#define READL(offset) readl(mfc_sfr_base_vaddr + (offset))
+#define WRITEL(data, offset) writel((data), mfc_sfr_base_vaddr + (offset))
+
+#endif /* _MFC_MEMORY_H_ */
diff --git a/drivers/media/video/samsung/mfc50/mfc_opr.c b/drivers/media/video/samsung/mfc50/mfc_opr.c
new file mode 100644
index 0000000..a2c2464
--- /dev/null
+++ b/drivers/media/video/samsung/mfc50/mfc_opr.c
@@ -0,0 +1,2516 @@
+/*
+ * drivers/media/video/samsung/mfc50/mfc_opr.c
+ *
+ * C file for Samsung MFC (Multi Function Codec - FIMV) driver
+ *
+ * Jaeryul Oh, Copyright (c) 2009 Samsung Electronics
+ * http://www.samsungsemi.com/
+ *
+ * Change Logs
+ * 2009.09.14 - Beautify source code. (Key Young, Park)
+ * 2009.09.21 - Implement clock & power gating.
+ * including suspend & resume fuction. (Key Young, Park)
+ * 2009.09.23 - Use TILE mode encoding / Move MFC reserved memory
+ * before FIMC reserved memory. (Key Young, Park)
+ * 2009.09.24 - Minor patch. (Key Young, Park)
+ * 2009.10.08 - Apply 9/30 firmware(Key Young, Park)
+ * 2009.10.13 - Change wait_for_done (Key Young, Park)
+ * 2009.10.17 - Add error handling routine for buffer allocation (Key Young, Park)
+ * 2009.10.22 - Change codec name VC1AP_DEC -> VC1_DEC (Key Young, Park)
+ * 2009.10.27 - Update firmware (2009.10.15) (Key Young, Park)
+ * 2009.11.04 - get physical address via mfc_allocate_buffer (Key Young, Park)
+ * 2009.11.04 - remove mfc_common.[ch]
+ * seperate buffer alloc & set (Key Young, Park)
+ * 2009.11.06 - Apply common MFC API (Key Young, Park)
+ * 2009.11.06 - memset shared_memory (Key Young, Park)
+ * 2009.11.09 - implement packed PB (Key Young, Park)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <plat/regs-mfc.h>
+#include <asm/cacheflush.h>
+#include <mach/map.h>
+#include <plat/map-s5p.h>
+
+#include "mfc_opr.h"
+#include "mfc_logmsg.h"
+#include "mfc_memory.h"
+#include "mfc_buffer_manager.h"
+#include "mfc_interface.h"
+#include "mfc_shared_mem.h"
+#include "mfc_intr.h"
+
+
+/* DEBUG_MAKE_RAW is option to dump input stream data of MFC.*/
+#define DEBUG_MAKE_RAW 0 /* Making Dec/Enc Debugging Files */
+#define ENABLE_DEBUG_MFC_INIT 0
+#define ENABLE_MFC_REGISTER_DEBUG 0 /* 0: Disable 1: Enable */
+#define ENABLE_ENC_MB 1
+
+#define ENABLE_CHECK_START_CODE 1
+#define ENABLE_CHECK_NULL_STREAM 1
+#define ENABLE_CHECK_STREAM_SIZE 1
+#define ENABLE_CHECK_SEQ_HEADER 0
+
+#if DEBUG_MAKE_RAW
+#define ENABLE_DEBUG_DEC_EXE_INTR_ERR 1 /* You must make the "dec_in" folder in data folder.*/
+#define ENABLE_DEBUG_DEC_EXE_INTR_OK 1 /* Make log about Normal Interrupts.*/
+#define ENABLE_DEBUG_ENC_EXE_INTR_ERR 1 /* You must make the "enc_in" folder in data folder.*/
+#endif
+
+#ifdef ENABLE_DEBUG_DEC_EXE_INTR_ERR
+#if ENABLE_DEBUG_DEC_EXE_INTR_ERR
+#define ENABLE_DEBUG_DEC_EXE_PARSER_ERR 1 /* Firstly, Set ENABLE_DEBUG_DEC_EXE_INTR_ERR is "1". */
+#endif
+#endif
+
+#if DEBUG_MAKE_RAW
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/syscalls.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/fcntl.h>
+#include <linux/uaccess.h>
+#endif
+
+
+static void mfc_backup_context(struct mfc_inst_ctx *mfc_ctx);
+static void mfc_restore_context(struct mfc_inst_ctx *mfc_ctx);
+static void mfc_set_encode_init_param(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args);
+static int mfc_get_inst_no(struct mfc_inst_ctx *mfc_ctx, unsigned int context_addr, int context_size);
+static enum mfc_error_code mfc_encode_header(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args);
+static enum mfc_error_code mfc_decode_one_frame(struct mfc_inst_ctx *mfc_ctx, struct mfc_dec_exe_arg *dec_arg, unsigned int *consumed_strm_size);
+
+static void mfc_set_codec_buffer(struct mfc_inst_ctx *mfc_ctx);
+static void mfc_set_dec_frame_buffer(struct mfc_inst_ctx *mfc_ctx);
+static void mfc_set_dec_stream_buffer(struct mfc_inst_ctx *mfc_ctx, int buf_addr, unsigned int buf_size);
+static void mfc_set_enc_ref_buffer(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args);
+
+static enum mfc_error_code mfc_alloc_codec_buffer(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args);
+static enum mfc_error_code mfc_alloc_dec_frame_buffer(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args);
+static enum mfc_error_code mfc_alloc_context_buffer(struct mfc_inst_ctx *mfc_ctx, unsigned int mapped_addr, unsigned int *context_addr, int *size);
+static enum mfc_error_code mfc_alloc_stream_ref_buffer(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args);
+
+static int CheckMPEG4StartCode(unsigned char *src_mem, unsigned int remainSize);
+static int CheckDecStartCode(unsigned char *src_mem, unsigned int nstreamSize, enum ssbsip_mfc_codec_type nCodecType);
+static int CheckNullStream(unsigned char *src_mem, unsigned int streamSize);
+
+static int mfc_mem_inst_no[MFC_MAX_INSTANCE_NUM];
+static bool mCheckType;
+
+
+/*
+ * Debugging Functions Definition
+ * tile_to_linear_4x2(..)
+ * calculate_seq_size(..)
+ * printk_mfc_init_info(..)
+ */
+#if DEBUG_MAKE_RAW
+static int mframe_cnt;
+static int mImgWidth;
+static int mImgHight;
+
+static void copy16(unsigned char *p_linear_addr, unsigned char *p_tiled_addr, int mm, int nn);
+static void write_file(char *filename, unsigned char *data, unsigned int nSize);
+static int tile_4x2_read(int x_size, int y_size, int x_pos, int y_pos);
+static void tile_to_linear_4x2(unsigned char *p_linear_addr, unsigned char *p_tiled_addr, unsigned int x_size, unsigned int y_size);
+#endif
+
+#if ENABLE_CHECK_SEQ_HEADER
+static int calculate_seq_size(mfc_args *args);
+#endif
+
+#if ENABLE_DEBUG_MFC_INIT
+void printk_mfc_init_info(struct mfc_inst_ctx *mfc_ctx, struct mfc_args *args);
+#endif
+
+#ifdef ENABLE_DEBUG_DEC_EXE_INTR_ERR
+#if ENABLE_DEBUG_DEC_EXE_INTR_ERR
+void printk_mfc_dec_exe_info(struct mfc_inst_ctx *mfc_ctx, struct mfc_dec_exe_arg *dec_arg);
+void makefile_mfc_dec_err_info(struct mfc_inst_ctx *mfc_ctx, struct mfc_dec_exe_arg *dec_arg, int nReturnErrCode);
+void makefile_mfc_decinit_err_info(struct mfc_inst_ctx *mfc_ctx, struct mfc_dec_init_arg *decinit_arg, int nReturnErrCode);
+
+static unsigned int mcontext_addr;
+static int mcontext_size;
+static int mIsDangerError;
+#endif
+#endif
+
+#ifdef ENABLE_DEBUG_DEC_EXE_INTR_ERR
+#if ENABLE_DEBUG_ENC_EXE_INTR_ERR
+void makefile_mfc_enc_err_info(struct mfc_enc_exe_arg *enc_arg);
+#endif
+#endif
+
+#if ENABLE_MFC_REGISTER_DEBUG
+void mfc_fw_debug(mfc_wait_done_type command);
+#endif
+
+#ifdef ENABLE_DEBUG_DEC_EXE_INTR_ERR
+#if ENABLE_DEBUG_ENC_EXE_INTR_ERR
+static unsigned char pResLinearbuf[1280*720*3/2];
+#endif
+#endif
+
+#define MC_STATUS_TIMEOUT 1000 /* ms */
+
+bool mfc_cmd_reset(void)
+{
+ unsigned int mc_status;
+ unsigned long timeo = jiffies;
+
+ timeo += msecs_to_jiffies(MC_STATUS_TIMEOUT);
+
+ /* Stop procedure */
+ WRITEL(0x3f6, MFC_SW_RESET); /* reset RISC */
+ WRITEL(0x3e2, MFC_SW_RESET); /* All reset except for MC */
+ mdelay(10);
+
+ /* Check MC status */
+ do {
+ mc_status = (READL(MFC_MC_STATUS) & 0x3);
+
+ if (mc_status == 0)
+ break;
+
+ schedule_timeout_uninterruptible(1);
+ } while (time_before(jiffies, timeo));
+
+ if (mc_status != 0)
+ return false;
+
+ WRITEL(0x0, MFC_SW_RESET);
+ WRITEL(0x3fe, MFC_SW_RESET);
+
+ return true;
+}
+
+static bool mfc_cmd_host2risc(enum mfc_facade_cmd cmd, int arg1, int arg2, int arg3, int arg4)
+{
+ enum mfc_facade_cmd cur_cmd = 0;
+ unsigned long timeo = jiffies;
+ timeo += 20; /* waiting for 100ms */
+
+ /* wait until host to risc command register becomes 'H2R_CMD_EMPTY' */
+ while (time_before(jiffies, timeo)) {
+ cur_cmd = READL(MFC_HOST2RISC_COMMAND);
+ if (cur_cmd == H2R_CMD_EMPTY)
+ break;
+ msleep_interruptible(2);
+ }
+
+ if (cur_cmd != H2R_CMD_EMPTY)
+ return false;
+
+ WRITEL(arg1, MFC_HOST2RISC_ARG1);
+ WRITEL(arg2, MFC_HOST2RISC_ARG2);
+ WRITEL(arg3, MFC_HOST2RISC_ARG3);
+ WRITEL(arg4, MFC_HOST2RISC_ARG4);
+ WRITEL(cmd, MFC_HOST2RISC_COMMAND);
+
+ return true;
+}
+
+static void mfc_backup_context(struct mfc_inst_ctx *mfc_ctx)
+{
+}
+
+static void mfc_restore_context(struct mfc_inst_ctx *mfc_ctx)
+{
+}
+
+static void mfc_set_dec_stream_buffer(struct mfc_inst_ctx *mfc_ctx, int buf_addr, unsigned int buf_size)
+{
+ unsigned int port0_base_paddr;
+
+ mfc_debug_L0("inst_no : %d, buf_addr : 0x%08x, buf_size : 0x%08x\n", mfc_ctx->InstNo, buf_addr, buf_size);
+
+ port0_base_paddr = mfc_port0_base_paddr;
+
+ /* release buffer */
+ WRITEL(0xffffffff, MFC_SI_CH0_RELEASE_BUFFER);
+
+ /* Set stream & desc buffer */
+ WRITEL((buf_addr - port0_base_paddr) >> 11, MFC_SI_CH0_ES_ADDR);
+ WRITEL(buf_size, MFC_SI_CH0_ES_DEC_UNIT_SIZE);
+ WRITEL(CPB_BUF_SIZE, MFC_SI_CH0_CPB_SIZE);
+ WRITEL((buf_addr + CPB_BUF_SIZE - port0_base_paddr) >> 11, MFC_SI_CH0_DESC_ADDR);
+ WRITEL(DESC_BUF_SIZE, MFC_SI_CH0_DESC_SIZE);
+
+ mfc_debug_L0("stream_paddr: 0x%08x, desc_paddr: 0x%08x\n", buf_addr, buf_addr + CPB_BUF_SIZE);
+}
+
+static enum mfc_error_code mfc_alloc_dec_frame_buffer(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args)
+{
+ struct mfc_dec_init_arg *init_arg;
+ enum mfc_error_code ret_code;
+ union mfc_args local_param;
+ struct mfc_frame_buf_arg buf_size;
+ unsigned int luma_size, chroma_size;
+ unsigned int luma_plane_sz, chroma_plane_sz, mv_plane_sz;
+
+ init_arg = (struct mfc_dec_init_arg *)args;
+
+ /* width : 128B align, height : 32B align, size: 8KB align */
+ luma_plane_sz = ALIGN_TO_128B(init_arg->out_img_width) * ALIGN_TO_32B(init_arg->out_img_height);
+ luma_plane_sz = ALIGN_TO_8KB(luma_plane_sz);
+ chroma_plane_sz = ALIGN_TO_128B(init_arg->out_img_width) * ALIGN_TO_32B(init_arg->out_img_height / 2);
+ chroma_plane_sz = ALIGN_TO_8KB(chroma_plane_sz);
+ mv_plane_sz = 0;
+
+ buf_size.luma = luma_plane_sz;
+ buf_size.chroma = chroma_plane_sz;
+
+ if (mfc_ctx->MfcCodecType == H264_DEC) {
+ /* width : 128B align, height : 32B align, size: 8KB align */
+ mv_plane_sz = ALIGN_TO_128B(init_arg->out_img_width) * ALIGN_TO_32B(init_arg->out_img_height / 4);
+ mv_plane_sz = ALIGN_TO_8KB(mv_plane_sz);
+ buf_size.luma += mv_plane_sz;
+ }
+
+ mfc_ctx->shared_mem.allocated_luma_dpb_size = luma_plane_sz;
+ mfc_ctx->shared_mem.allocated_chroma_dpb_size = chroma_plane_sz;
+ mfc_ctx->shared_mem.allocated_mv_size = mv_plane_sz;
+
+ luma_size = buf_size.luma * mfc_ctx->totalDPBCnt;
+ chroma_size = buf_size.chroma * mfc_ctx->totalDPBCnt;
+
+ /*
+ * Allocate chroma & (Mv in case of H264) buf
+ */
+ init_arg->out_frame_buf_size.chroma = chroma_size;
+
+ memset(&local_param, 0, sizeof(local_param));
+ local_param.mem_alloc.buff_size = chroma_size;
+ local_param.mem_alloc.mapped_addr = init_arg->in_mapped_addr;
+
+ ret_code = mfc_allocate_buffer(mfc_ctx, &(local_param), 0);
+ if (ret_code < 0)
+ return ret_code;
+
+ init_arg->out_u_addr.chroma = local_param.mem_alloc.out_uaddr;
+ init_arg->out_p_addr.chroma = local_param.mem_alloc.out_paddr;
+
+ /*
+ * Allocate luma buf
+ */
+ init_arg->out_frame_buf_size.luma = luma_size;
+
+ memset(&local_param, 0, sizeof(local_param));
+ local_param.mem_alloc.buff_size = luma_size;
+ local_param.mem_alloc.mapped_addr = init_arg->in_mapped_addr;
+
+ ret_code = mfc_allocate_buffer(mfc_ctx, &(local_param), 1);
+ if (ret_code < 0)
+ return ret_code;
+
+ init_arg->out_u_addr.luma = local_param.mem_alloc.out_uaddr;
+ init_arg->out_p_addr.luma = local_param.mem_alloc.out_paddr;
+
+ mfc_ctx->dec_dpb_buff_paddr = init_arg->out_p_addr;
+
+ return MFCINST_RET_OK;
+}
+
+
+
+static void mfc_set_dec_frame_buffer(struct mfc_inst_ctx *mfc_ctx)
+{
+ unsigned int port0_base_paddr, port1_base_paddr, i;
+ struct mfc_frame_buf_arg dpb_buff_addr;
+ unsigned int luma_plane_sz, chroma_plane_sz, mv_plane_sz;
+
+ dpb_buff_addr = mfc_ctx->dec_dpb_buff_paddr;
+ port0_base_paddr = mfc_port0_base_paddr;
+ port1_base_paddr = mfc_port1_base_paddr;
+
+ luma_plane_sz = mfc_ctx->shared_mem.allocated_luma_dpb_size;
+ chroma_plane_sz = mfc_ctx->shared_mem.allocated_chroma_dpb_size;
+ mv_plane_sz = mfc_ctx->shared_mem.allocated_mv_size;
+
+ mfc_debug("luma_buf_addr start : 0x%08x luma_buf_size : %d\n", dpb_buff_addr.luma, (luma_plane_sz + mv_plane_sz));
+ mfc_debug("chroma_buf_addr start : 0x%08x chroma_buf_size : %d\n", dpb_buff_addr.chroma, chroma_plane_sz);
+
+ if (mfc_ctx->MfcCodecType == H264_DEC) {
+ for (i = 0; i < mfc_ctx->totalDPBCnt; i++) {
+ mfc_debug("DPB[%d] luma_buf_addr : 0x%08x luma_buf_size : %d\n", i, dpb_buff_addr.luma, luma_plane_sz);
+ mfc_debug("DPB[%d] chroma_buf_addr : 0x%08x chroma_buf_size : %d\n", i, dpb_buff_addr.chroma, chroma_plane_sz);
+ mfc_debug("DPB[%d] mv_buf_addr : 0x%08x mv_plane_sz : %d\n", i, dpb_buff_addr.luma + luma_plane_sz, mv_plane_sz);
+
+ /* set Luma address */
+ WRITEL((dpb_buff_addr.luma - port1_base_paddr) >> 11, MFC_H264DEC_LUMA + (4 * i));
+ WRITEL((dpb_buff_addr.luma + luma_plane_sz - port1_base_paddr) >> 11, MFC_H264DEC_MV + (4 * i));
+ dpb_buff_addr.luma += (luma_plane_sz + mv_plane_sz);
+
+ /* set Chroma address & set MV address */
+ WRITEL((dpb_buff_addr.chroma - port0_base_paddr) >> 11, MFC_H264DEC_CHROMA + (4 * i));
+ dpb_buff_addr.chroma += chroma_plane_sz;
+ }
+ } else {
+ for (i = 0; i < mfc_ctx->totalDPBCnt; i++) {
+ mfc_debug("DPB[%d] luma_buf_addr : 0x%08x luma_buf_size : %d\n", i, dpb_buff_addr.luma, luma_plane_sz);
+ mfc_debug("DPB[%d] chroma_buf_addr : 0x%08x chroma_buf_size : %d\n", i, dpb_buff_addr.chroma, chroma_plane_sz);
+
+ /* set Luma address */
+ WRITEL((dpb_buff_addr.luma - port1_base_paddr) >> 11, MFC_DEC_LUMA + (4 * i));
+ dpb_buff_addr.luma += luma_plane_sz;
+
+ /* set Chroma address */
+ WRITEL((dpb_buff_addr.chroma - port0_base_paddr) >> 11, MFC_DEC_CHROMA + (4 * i));
+ dpb_buff_addr.chroma += chroma_plane_sz;
+ }
+ }
+
+ mfc_debug("luma_buf_addr end : 0x%08x\n", dpb_buff_addr.luma);
+ mfc_debug("chroma_buf_addr end : 0x%08x\n", dpb_buff_addr.chroma);
+}
+
+/* Allocate buffers for encoder */
+static enum mfc_error_code mfc_alloc_stream_ref_buffer(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args)
+{
+ struct mfc_enc_init_mpeg4_arg *init_arg;
+ union mfc_args local_param;
+ unsigned int luma_plane_sz, chroma_plane_sz;
+ enum mfc_error_code ret_code = MFCINST_RET_OK;
+ struct mfc_frame_buf_arg buf_size;
+
+ init_arg = (struct mfc_enc_init_mpeg4_arg *)args;
+
+ /* width : 128B align, height : 32B align, size: 8KB align */
+ luma_plane_sz = ALIGN_TO_128B(init_arg->in_width) * ALIGN_TO_32B(init_arg->in_height);
+ luma_plane_sz = ALIGN_TO_8KB(luma_plane_sz);
+ chroma_plane_sz = ALIGN_TO_128B(init_arg->in_width) * ALIGN_TO_32B(init_arg->in_height / 2);
+ chroma_plane_sz = ALIGN_TO_8KB(chroma_plane_sz);
+
+ buf_size.luma = luma_plane_sz;
+ buf_size.chroma = chroma_plane_sz;
+
+ /*
+ * Allocate stream ref Y0, Y1 buf
+ */
+ init_arg->out_buf_size.strm_ref_y = STREAM_BUF_SIZE + (buf_size.luma * 2);
+
+ memset(&local_param, 0, sizeof(local_param));
+ local_param.mem_alloc.buff_size = init_arg->out_buf_size.strm_ref_y;
+ local_param.mem_alloc.mapped_addr = init_arg->in_mapped_addr;
+
+ ret_code = mfc_allocate_buffer(mfc_ctx, &(local_param), 0);
+ if (ret_code < 0)
+ return ret_code;
+
+ init_arg->out_u_addr.strm_ref_y = local_param.mem_alloc.out_uaddr;
+ init_arg->out_p_addr.strm_ref_y = local_param.mem_alloc.out_paddr;
+
+ /*
+ * Allocate ref C0, C1, Y2, C2, Y3, C3 buf XXX : remove MV buffer
+ */
+ init_arg->out_buf_size.mv_ref_yc = (buf_size.luma * 2) + (buf_size.chroma * 4);
+
+ memset(&local_param, 0, sizeof(local_param));
+ local_param.mem_alloc.buff_size = init_arg->out_buf_size.mv_ref_yc;
+ local_param.mem_alloc.mapped_addr = init_arg->in_mapped_addr;
+
+ ret_code = mfc_allocate_buffer(mfc_ctx, &(local_param), 1);
+ if (ret_code < 0)
+ return ret_code;
+
+ init_arg->out_u_addr.mv_ref_yc = local_param.mem_alloc.out_uaddr;
+ init_arg->out_p_addr.mv_ref_yc = local_param.mem_alloc.out_paddr;
+
+ return ret_code;
+}
+
+static void mfc_set_enc_ref_buffer(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args)
+{
+ unsigned int port0_base_paddr, port1_base_paddr, i;
+ struct mfc_strm_ref_buf_arg ref_buf_addr;
+ unsigned int luma_plane_sz, chroma_plane_sz;
+ struct mfc_enc_init_mpeg4_arg *init_arg;
+
+ init_arg = (struct mfc_enc_init_mpeg4_arg *)args;
+
+ /* width : 128B align, height : 32B align, size: 8KB align */
+ luma_plane_sz = ALIGN_TO_128B(init_arg->in_width) * ALIGN_TO_32B(init_arg->in_height);
+ luma_plane_sz = ALIGN_TO_8KB(luma_plane_sz);
+ chroma_plane_sz = ALIGN_TO_128B(init_arg->in_width) * ALIGN_TO_32B(init_arg->in_height / 2);
+ chroma_plane_sz = ALIGN_TO_8KB(chroma_plane_sz);
+
+ ref_buf_addr = init_arg->out_p_addr;
+ mfc_debug("strm_ref_y_buf_addr : 0x%08x, strm_ref_y_buf_size : %d\n",
+ ref_buf_addr.strm_ref_y, init_arg->out_buf_size.strm_ref_y);
+ mfc_debug("mv_ref_yc_buf_addr : 0x%08x, mv_ref_yc_buf_size : %d\n",
+ ref_buf_addr.mv_ref_yc, init_arg->out_buf_size.mv_ref_yc);
+
+ port0_base_paddr = mfc_port0_base_paddr;
+ port1_base_paddr = mfc_port1_base_paddr;
+
+ mfc_debug("stream_buf_addr : 0x%08x\n", ref_buf_addr.strm_ref_y);
+ ref_buf_addr.strm_ref_y += STREAM_BUF_SIZE;
+
+ /* Set Y0, Y1 ref buffer address */
+ mfc_debug("REF[0] luma_buf_addr : 0x%08x luma_buf_size : %d\n", ref_buf_addr.strm_ref_y, luma_plane_sz);
+ WRITEL((ref_buf_addr.strm_ref_y - port0_base_paddr) >> 11, MFC_ENC_DPB_Y0_ADDR);
+ ref_buf_addr.strm_ref_y += luma_plane_sz;
+ mfc_debug("REF[1] luma_buf_addr : 0x%08x luma_buf_size : %d\n", ref_buf_addr.strm_ref_y, luma_plane_sz);
+ WRITEL((ref_buf_addr.strm_ref_y - port0_base_paddr) >> 11, MFC_ENC_DPB_Y1_ADDR);
+
+ /* Set Y2, Y3 ref buffer address */
+ mfc_debug("REF[2] luma_buf_addr : 0x%08x luma_buf_size : %d\n", ref_buf_addr.mv_ref_yc, luma_plane_sz);
+ WRITEL((ref_buf_addr.mv_ref_yc - port1_base_paddr) >> 11, MFC_ENC_DPB_Y2_ADDR);
+ ref_buf_addr.mv_ref_yc += luma_plane_sz;
+ mfc_debug("REF[3] luma_buf_addr : 0x%08x luma_buf_size : %d\n", ref_buf_addr.mv_ref_yc, luma_plane_sz);
+ WRITEL((ref_buf_addr.mv_ref_yc - port1_base_paddr) >> 11, MFC_ENC_DPB_Y3_ADDR);
+ ref_buf_addr.mv_ref_yc += luma_plane_sz;
+
+ /* Set C0, C1, C2, C3 ref buffer address */
+ for (i = 0; i < 4; i++) {
+ mfc_debug("REF[%d] chroma_buf_addr : 0x%08x chroma_buf_size : %d\n", i, ref_buf_addr.mv_ref_yc, chroma_plane_sz);
+ WRITEL((ref_buf_addr.mv_ref_yc - port1_base_paddr) >> 11, MFC_ENC_DPB_C0_ADDR + (4 * i));
+ ref_buf_addr.mv_ref_yc += chroma_plane_sz;
+ }
+}
+
+static enum mfc_error_code mfc_alloc_codec_buffer(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args)
+{
+ struct mfc_dec_init_arg *init_arg;
+ enum mfc_error_code ret_code;
+ union mfc_args local_param;
+
+ init_arg = (struct mfc_dec_init_arg *)args;
+
+ memset(&local_param, 0, sizeof(local_param));
+ if (is_dec_codec(mfc_ctx->MfcCodecType))
+ local_param.mem_alloc.buff_size = DEC_CODEC_BUF_SIZE + SHARED_BUF_SIZE;
+ else
+ local_param.mem_alloc.buff_size = ENC_CODEC_BUF_SIZE + SHARED_BUF_SIZE;
+
+ local_param.mem_alloc.mapped_addr = init_arg->in_mapped_addr;
+ ret_code = mfc_allocate_buffer(mfc_ctx, &(local_param), 0);
+ if (ret_code < 0)
+ return ret_code;
+
+ mfc_ctx->codec_buff_paddr = local_param.mem_alloc.out_paddr;
+ if (is_dec_codec(mfc_ctx->MfcCodecType))
+ mfc_ctx->shared_mem_paddr = mfc_ctx->codec_buff_paddr + DEC_CODEC_BUF_SIZE;
+ else
+ mfc_ctx->shared_mem_paddr = mfc_ctx->codec_buff_paddr + ENC_CODEC_BUF_SIZE;
+
+ mfc_ctx->shared_mem_vaddr = (unsigned int)mfc_get_fw_buff_vaddr() + (mfc_ctx->shared_mem_paddr - mfc_port0_base_paddr);
+ memset((void *)mfc_ctx->shared_mem_vaddr, 0x0, SHARED_MEM_MAX);
+
+ if (mfc_ctx->MfcCodecType == H264_ENC) {
+ memset(&local_param, 0, sizeof(local_param));
+ local_param.mem_alloc.buff_size = PRED_BUF_SIZE;
+ local_param.mem_alloc.mapped_addr = init_arg->in_mapped_addr;
+ ret_code = mfc_allocate_buffer(mfc_ctx, &(local_param), 1);
+ if (ret_code < 0)
+ return ret_code;
+
+ mfc_ctx->pred_buff_paddr = local_param.mem_alloc.out_paddr;
+ }
+
+ return MFCINST_RET_OK;
+}
+
+
+
+static void mfc_set_codec_buffer(struct mfc_inst_ctx *mfc_ctx)
+{
+ unsigned int codec_buff_paddr;
+ unsigned int pred_buff_paddr;
+ unsigned int port0_base_paddr;
+ unsigned int port1_base_paddr;
+
+ port0_base_paddr = mfc_port0_base_paddr;
+ port1_base_paddr = mfc_port1_base_paddr;
+ codec_buff_paddr = mfc_ctx->codec_buff_paddr;
+ pred_buff_paddr = mfc_ctx->pred_buff_paddr;
+
+ mfc_debug("inst_no : %d, codec_buf_start: 0x%08x\n", mfc_ctx->InstNo, codec_buff_paddr);
+
+ switch (mfc_ctx->MfcCodecType) {
+ case H264_DEC:
+ WRITEL((codec_buff_paddr - port0_base_paddr) >> 11, MFC_H264DEC_VERT_NB_MV);
+ codec_buff_paddr += (16 << 10);
+ WRITEL((codec_buff_paddr - port0_base_paddr) >> 11, MFC_H264DEC_NB_IP);
+ codec_buff_paddr += (32 << 10);
+ break;
+
+ case MPEG4_DEC:
+ case H263_DEC:
+ case XVID_DEC:
+ case FIMV1_DEC:
+ case FIMV2_DEC:
+ case FIMV3_DEC:
+ case FIMV4_DEC:
+ WRITEL((codec_buff_paddr - port0_base_paddr) >> 11, MFC_NB_DCAC);
+ codec_buff_paddr += (16 << 10);
+ WRITEL((codec_buff_paddr - port0_base_paddr) >> 11, MFC_UPNB_MV);
+ codec_buff_paddr += (68 << 10);
+ WRITEL((codec_buff_paddr - port0_base_paddr) >> 11, MFC_SUB_ANCHOR_MV);
+ codec_buff_paddr += (136 << 10);
+ WRITEL((codec_buff_paddr - port0_base_paddr) >> 11, MFC_OVERLAP_TRANSFORM);
+ codec_buff_paddr += (32 << 10);
+ WRITEL((codec_buff_paddr - port0_base_paddr) >> 11, MFC_STX_PARSER);
+ codec_buff_paddr += (68 << 10);
+ break;
+
+ case VC1_DEC:
+ case VC1RCV_DEC:
+ WRITEL((codec_buff_paddr - port0_base_paddr) >> 11, MFC_NB_DCAC);
+ codec_buff_paddr += (16 << 10);
+ WRITEL((codec_buff_paddr - port0_base_paddr) >> 11, MFC_UPNB_MV);
+ codec_buff_paddr += (68 << 10);
+ WRITEL((codec_buff_paddr - port0_base_paddr) >> 11, MFC_SUB_ANCHOR_MV);
+ codec_buff_paddr += (136 << 10);
+ WRITEL((codec_buff_paddr - port0_base_paddr) >> 11, MFC_OVERLAP_TRANSFORM);
+ codec_buff_paddr += (32 << 10);
+ WRITEL((codec_buff_paddr - port0_base_paddr) >> 11, MFC_BITPLANE3);
+ codec_buff_paddr += (8 << 10);
+ WRITEL((codec_buff_paddr - port0_base_paddr) >> 11, MFC_BITPLANE2);
+ codec_buff_paddr += (8 << 10);
+ WRITEL((codec_buff_paddr - port0_base_paddr) >> 11, MFC_BITPLANE1);
+ codec_buff_paddr += (8 << 10);
+ break;
+
+ case MPEG1_DEC:
+ case MPEG2_DEC:
+ break;
+
+ case H264_ENC:
+ case MPEG4_ENC:
+ case H263_ENC:
+ WRITEL((codec_buff_paddr - port0_base_paddr) >> 11, MFC_UPPER_MV_ADDR);
+ codec_buff_paddr += (64 << 10);
+ WRITEL((codec_buff_paddr - port0_base_paddr) >> 11, MFC_DIRECT_COLZERO_FLAG_ADDR);
+ codec_buff_paddr += (64 << 10);
+ WRITEL((codec_buff_paddr - port0_base_paddr) >> 11, MFC_UPPER_INTRA_MD_ADDR);
+ codec_buff_paddr += (64 << 10);
+ if (mfc_ctx->MfcCodecType == H264_ENC) {
+ WRITEL((codec_buff_paddr - port0_base_paddr) >> 11, MFC_NBOR_INFO_MPENC_ADDR);
+ WRITEL((pred_buff_paddr - port1_base_paddr) >> 11, MFC_UPPER_INTRA_PRED_ADDR);
+ } else {
+ WRITEL((codec_buff_paddr - port0_base_paddr) >> 11, MFC_ACDC_COEF_BASE_ADDR);
+ }
+ codec_buff_paddr += (64 << 10);
+ break;
+
+ default:
+ break;
+ }
+
+ mfc_debug("inst_no : %d, codec_buf_end : 0x%08x\n", mfc_ctx->InstNo, codec_buff_paddr);
+}
+
+/* This function sets the MFC SFR values according to the input arguments. */
+static void mfc_set_encode_init_param(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args)
+{
+ unsigned int ms_size;
+ struct mfc_enc_init_mpeg4_arg *enc_init_mpeg4_arg;
+ struct mfc_enc_init_h264_arg *enc_init_h264_arg;
+
+ enc_init_mpeg4_arg = (struct mfc_enc_init_mpeg4_arg *)args;
+ enc_init_h264_arg = (struct mfc_enc_init_h264_arg *)args;
+
+#if DEBUG_MAKE_RAW
+ mImgHight = enc_init_mpeg4_arg->in_height;
+ mImgWidth = enc_init_mpeg4_arg->in_width;
+#endif
+
+ mfc_debug("mfc_codec_type : %d\n", mfc_ctx->MfcCodecType);
+
+ WRITEL(enc_init_mpeg4_arg->in_width, MFC_HSIZE_PX);
+ if (enc_init_mpeg4_arg->in_interlace_mode)
+ WRITEL(enc_init_mpeg4_arg->in_height >> 1, MFC_VSIZE_PX);
+ else
+ WRITEL(enc_init_mpeg4_arg->in_height, MFC_VSIZE_PX);
+
+ /* H.263 does not support field picture */
+ WRITEL(enc_init_mpeg4_arg->in_interlace_mode, MFC_PICTURE_STRUCT);
+ WRITEL(0, MFC_ENC_INT_MASK); /* mask interrupt */
+ WRITEL(1, MFC_STR_BF_MODE_CTRL); /* stream buf frame mode */
+ WRITEL((1 << 18) | (enc_init_mpeg4_arg->in_BframeNum << 16) |
+ enc_init_mpeg4_arg->in_gop_num, MFC_ENC_PIC_TYPE_CTRL);
+
+ /* Multi-slice options */
+ if (enc_init_mpeg4_arg->in_MS_mode) {
+ ms_size = (mfc_ctx->MfcCodecType == H263_ENC) ? 0 : enc_init_mpeg4_arg->in_MS_size;
+ switch (enc_init_mpeg4_arg->in_MS_mode) {
+ case 1:
+ WRITEL(0x1, MFC_ENC_MSLICE_CTRL);
+ WRITEL(ms_size, MFC_ENC_MSLICE_MB);
+ break;
+
+ case 2:
+ WRITEL(0x3, MFC_ENC_MSLICE_CTRL);
+ WRITEL(ms_size, MFC_ENC_MSLICE_BYTE);
+ break;
+
+ default:
+ mfc_err("Invalid Multi-slice mode type\n");
+ break;
+ }
+ } else {
+ WRITEL(0, MFC_ENC_MSLICE_CTRL);
+ }
+
+ /* Set circular intra refresh MB count */
+ WRITEL(enc_init_mpeg4_arg->in_mb_refresh, MFC_ENC_CIR_CTRL);
+ WRITEL(MEM_STRUCT_TILE_ENC, MFC_ENC_MAP_FOR_CUR);
+
+ /* Set padding control */
+ WRITEL((enc_init_mpeg4_arg->in_pad_ctrl_on << 31) |
+ (enc_init_mpeg4_arg->in_cr_pad_val << 16) |
+ (enc_init_mpeg4_arg->in_cb_pad_val << 8) |
+ (enc_init_mpeg4_arg->in_luma_pad_val << 0), MFC_ENC_PADDING_CTRL);
+
+ /* Set Rate Control */
+ if (enc_init_mpeg4_arg->in_RC_frm_enable) {
+ WRITEL(enc_init_mpeg4_arg->in_RC_framerate, MFC_RC_FRAME_RATE);
+ WRITEL(enc_init_mpeg4_arg->in_RC_bitrate, MFC_RC_BIT_RATE);
+ WRITEL(enc_init_mpeg4_arg->in_RC_rpara, MFC_RC_RPARA);
+ }
+
+ WRITEL(enc_init_mpeg4_arg->in_RC_qbound, MFC_RC_QBOUND);
+
+ switch (mfc_ctx->MfcCodecType) {
+ case H264_ENC:
+ WRITEL(enc_init_h264_arg->in_profile_level, MFC_PROFILE);
+ WRITEL(enc_init_h264_arg->in_transform8x8_mode, MFC_H264_ENC_TRANS_8X8_FLAG);
+ WRITEL(enc_init_h264_arg->in_deblock_filt, MFC_LF_CONTROL);
+ WRITEL(((enc_init_h264_arg->in_deblock_alpha_C0 * 2) & 0x1f), MFC_LF_ALPHA_OFF);
+ WRITEL(((enc_init_h264_arg->in_deblock_beta * 2) & 0x1f), MFC_LF_BETA_OFF);
+ WRITEL(1, MFC_EDFU_SF_EPB_ON_CTRL); /* Auto EPB insertion on, only for h264 */
+
+ /* if in_RC_mb_enable is '1' */
+#if ENABLE_ENC_MB
+ if (enc_init_h264_arg->in_RC_frm_enable != 1)
+ enc_init_h264_arg->in_RC_frm_enable = 1;
+ if (enc_init_h264_arg->in_RC_mb_enable != 1)
+ enc_init_h264_arg->in_RC_mb_enable = 1;
+#endif
+
+ WRITEL((enc_init_h264_arg->in_RC_frm_enable << 9) |
+ (enc_init_h264_arg->in_RC_mb_enable << 8) |
+ (enc_init_h264_arg->in_frame_qp & 0x3f),
+ MFC_RC_CONFIG);
+
+ if (enc_init_h264_arg->in_RC_mb_enable) {
+ WRITEL((enc_init_h264_arg->in_RC_mb_dark_disable << 3)|
+ (enc_init_h264_arg->in_RC_mb_smooth_disable << 2)|
+ (enc_init_h264_arg->in_RC_mb_static_disable << 1)|
+ (enc_init_h264_arg->in_RC_mb_activity_disable << 0),
+ MFC_RC_MB_CTRL);
+ }
+
+ WRITEL((enc_init_h264_arg->in_symbolmode & 0x1), MFC_H264_ENC_ENTRP_MODE);
+
+ if (enc_init_h264_arg->in_reference_num > 2)
+ enc_init_h264_arg->in_reference_num = 2;
+ if (enc_init_h264_arg->in_ref_num_p > enc_init_h264_arg->in_reference_num)
+ enc_init_h264_arg->in_ref_num_p = enc_init_h264_arg->in_reference_num;
+ WRITEL((enc_init_h264_arg->in_ref_num_p << 5) |
+ (enc_init_h264_arg->in_reference_num),
+ MFC_H264_ENC_NUM_OF_REF);
+
+ WRITEL(enc_init_h264_arg->in_md_interweight_pps, MFC_H264_ENC_MDINTER_WEIGHT);
+ WRITEL(enc_init_h264_arg->in_md_intraweight_pps, MFC_H264_ENC_MDINTRA_WEIGHT);
+ break;
+
+ case MPEG4_ENC:
+ WRITEL(enc_init_mpeg4_arg->in_profile_level, MFC_PROFILE);
+ WRITEL((enc_init_mpeg4_arg->in_RC_frm_enable << 9) |
+ (enc_init_mpeg4_arg->in_frame_qp & 0x3f),
+ MFC_RC_CONFIG);
+ WRITEL(enc_init_mpeg4_arg->in_qpelME_enable, MFC_MPEG4_ENC_QUART_PXL);
+ if (enc_init_mpeg4_arg->in_time_increament_res) {
+ mfc_ctx->shared_mem.vop_timing = (1 << 31) |
+ (enc_init_mpeg4_arg->in_time_increament_res << 16) |
+ (enc_init_mpeg4_arg->in_time_vop_time_increament);
+ }
+ break;
+
+ case H263_ENC:
+ WRITEL(0x20, MFC_PROFILE);
+ WRITEL((enc_init_mpeg4_arg->in_RC_frm_enable << 9) |
+ (enc_init_mpeg4_arg->in_frame_qp & 0x3f),
+ MFC_RC_CONFIG);
+ break;
+
+ default:
+ mfc_err("Invalid MFC codec type\n");
+ }
+}
+
+int mfc_load_firmware(const unsigned char *data, size_t size)
+{
+ volatile unsigned char *fw_virbuf;
+
+ mfc_debug("mfc_load_firmware : MFC F/W Loading Start.................\n");
+
+ fw_virbuf = mfc_get_fw_buff_vaddr();
+ memset((void *)fw_virbuf, 0, MFC_FW_MAX_SIZE);
+
+ invalidate_kernel_vmap_range((void *)data, size);
+ memcpy((void *)fw_virbuf, data, size);
+ flush_kernel_vmap_range((void *)fw_virbuf, size);
+
+ mfc_debug("mfc_load_firmware : MFC F/W Loading Stop.................(fw_virbuf: 0x%08x)\n", fw_virbuf);
+
+ return 0;
+}
+
+enum mfc_error_code mfc_init_hw()
+{
+ int fw_buf_size;
+ unsigned int fw_version;
+ unsigned int mc_status;
+ unsigned long idcode;
+ int nIntrRet = 0;
+
+ mfc_debug("mfc_init_hw++\n");
+
+ /*
+ * 0-1. Check Type
+ */
+ idcode = readl(S5P_VA_CHIPID);
+ if ((idcode & 0x0F) == 0x02)
+ mCheckType = false;
+ else
+ mCheckType = true;
+
+ /*
+ * 1. MFC reset
+ */
+ do {
+ mc_status = READL(MFC_MC_STATUS);
+ } while (mc_status != 0);
+
+ if (mfc_cmd_reset() == false) {
+ mfc_err("MFCINST_ERR_INIT_FAIL\n");
+ return MFCINST_ERR_INIT_FAIL;
+ }
+
+ /*
+ * 2. Set DRAM base Addr
+ */
+ WRITEL(mfc_port0_base_paddr, MFC_MC_DRAMBASE_ADDR_A);
+ WRITEL(mfc_port1_base_paddr, MFC_MC_DRAMBASE_ADDR_B);
+ WRITEL(1, MFC_NUM_MASTER);
+
+ /*
+ * 3. Initialize registers of stream I/F for decoder
+ */
+ WRITEL(0xffff, MFC_SI_CH0_INST_ID);
+ WRITEL(0xffff, MFC_SI_CH1_INST_ID);
+
+ WRITEL(0, MFC_RISC2HOST_COMMAND);
+ WRITEL(0, MFC_HOST2RISC_COMMAND);
+
+ /*
+ * 4. Release reset signal to the RISC.
+ */
+ WRITEL(0x3ff, MFC_SW_RESET);
+ nIntrRet = mfc_wait_for_done(R2H_CMD_FW_STATUS_RET);
+ if (nIntrRet != R2H_CMD_FW_STATUS_RET) {
+ /*
+ * 4-1. MFC FW downloading
+ */
+
+ mfc_err("MFCINST_ERR_FW_LOAD_MFC_SW_RESET_FAIL............(Ret = %d)", nIntrRet);
+
+
+ mfc_err("MFCINST_ERR_FW_LOAD_FAIL\n");
+ return MFCINST_ERR_FW_LOAD_FAIL;
+ }
+
+ /*
+ * 5. Initialize firmware
+ */
+ fw_buf_size = MFC_FW_MAX_SIZE;
+ if (mfc_cmd_host2risc(H2R_CMD_SYS_INIT, fw_buf_size, 0, 0, 0) == false) {
+ mfc_err("R2H_CMD_SYS_INIT FAIL\n");
+ return MFCINST_ERR_FW_INIT_FAIL;
+ }
+
+ if (mfc_wait_for_done(R2H_CMD_SYS_INIT_RET) != R2H_CMD_SYS_INIT_RET) {
+ mfc_err("R2H_CMD_SYS_INIT_RET FAIL\n");
+ return MFCINST_ERR_FW_INIT_FAIL;
+ }
+
+ fw_version = READL(MFC_FW_VERSION);
+
+
+ mfc_debug("MFC FW version : %02xyy, %02xmm, %02xdd\n",
+ (fw_version >> 16) & 0xff, (fw_version >> 8) & 0xff, fw_version & 0xff);
+
+ mfc_debug("DRAM PORT0 BASE ADDRESS: 0x%08x\n", READL(MFC_MC_DRAMBASE_ADDR_A));
+ mfc_debug("DRAM PORT1 BASE ADDRESS: 0x%08x\n", READL(MFC_MC_DRAMBASE_ADDR_B));
+ mfc_debug("mfc_init_hw-\n");
+
+ return MFCINST_RET_OK;
+}
+
+static unsigned int mfc_get_codec_arg(enum ssbsip_mfc_codec_type codec_type)
+{
+ unsigned int codec_no = 99;
+
+ switch (codec_type) {
+ case H264_DEC:
+ codec_no = 0;
+ break;
+
+ case VC1_DEC:
+ codec_no = 1;
+ break;
+
+ case MPEG4_DEC:
+ case XVID_DEC:
+ codec_no = 2;
+ break;
+
+ case MPEG1_DEC:
+ case MPEG2_DEC:
+ codec_no = 3;
+ break;
+
+ case H263_DEC:
+ codec_no = 4;
+ break;
+
+ case VC1RCV_DEC:
+ codec_no = 5;
+ break;
+
+ case FIMV1_DEC:
+ codec_no = 6;
+ break;
+
+ case FIMV2_DEC:
+ codec_no = 7;
+ break;
+
+ case FIMV3_DEC:
+ codec_no = 8;
+ break;
+
+ case FIMV4_DEC:
+ codec_no = 9;
+ break;
+
+ case H264_ENC:
+ codec_no = 16;
+ break;
+
+ case MPEG4_ENC:
+ codec_no = 17;
+ break;
+
+ case H263_ENC:
+ codec_no = 18;
+ break;
+
+ default:
+ break;
+ }
+
+ return codec_no;
+}
+
+static int mfc_get_inst_no(struct mfc_inst_ctx *mfc_ctx, unsigned int context_addr, int context_size)
+{
+ unsigned int codec_no;
+ int inst_no;
+ unsigned int port0_base_paddr;
+ int mfc_wait_ret = 0;
+ port0_base_paddr = mfc_port0_base_paddr;
+
+ codec_no = (unsigned int)mfc_get_codec_arg(mfc_ctx->MfcCodecType);
+
+ if (mfc_cmd_host2risc(H2R_CMD_OPEN_INSTANCE,
+ codec_no,
+ (mfc_ctx->crcEnable << 31) | PIXEL_CACHE_ON_ONLY_P_PICTURE,
+ (context_addr - port0_base_paddr) >> 11,
+ context_size) == false) {
+ mfc_err("R2H_CMD_OPEN_INSTANCE FAIL\n");
+ return MFCINST_ERR_OPEN_FAIL;
+ }
+
+ mfc_wait_ret = mfc_wait_for_done(R2H_CMD_OPEN_INSTANCE_RET);
+ if (mfc_wait_ret != R2H_CMD_OPEN_INSTANCE_RET) {
+ mfc_err("R2H_CMD_OPEN_INSTANCE_RET FAIL..........(ret:%d)\n", mfc_wait_ret);
+ return MFCINST_ERR_OPEN_FAIL;
+ }
+
+ inst_no = READL(MFC_RISC2HOST_ARG1);
+ if (inst_no >= MFC_MAX_INSTANCE_NUM) {
+ mfc_err("mfc_get_inst_no() - INSTANCE NO : %d, CODEC_TYPE : %d --\n", inst_no, codec_no);
+ return -1;
+ } else {
+ mfc_debug("mfc_get_inst_no() - INSTANCE NO : %d, CODEC_TYPE : %d --\n", inst_no, codec_no);
+ return inst_no;
+ }
+}
+
+int mfc_return_inst_no(int inst_no, enum ssbsip_mfc_codec_type codec_type)
+{
+ unsigned int codec_no;
+ int mfc_wait_ret = 0;
+
+ codec_no = (unsigned int)mfc_get_codec_arg(codec_type);
+
+ if (mfc_cmd_host2risc(H2R_CMD_CLOSE_INSTANCE, inst_no, 0, 0, 0) == false) {
+ mfc_err("R2H_CMD_CLOSE_INSTANCE FAIL\n");
+ return MFCINST_ERR_CLOSE_FAIL;
+ }
+
+ mfc_wait_ret = mfc_wait_for_done(R2H_CMD_CLOSE_INSTANCE_RET);
+ if (mfc_wait_ret != R2H_CMD_CLOSE_INSTANCE_RET) {
+ mfc_err("R2H_CMD_CLOSE_INSTANCE_RET FAIL\n");
+ return MFCINST_ERR_CLOSE_FAIL;
+ }
+
+ mfc_debug("mfc_return_inst_no() - INSTANCE NO : %d, CODEC_TYPE : %d --\n", READL(MFC_RISC2HOST_ARG1), codec_no);
+ return MFCINST_RET_OK;
+}
+
+enum mfc_error_code mfc_init_encode(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args)
+{
+ struct mfc_enc_init_mpeg4_arg *enc_init_mpeg4_arg;
+ enum mfc_error_code ret_code;
+ unsigned int context_addr;
+ int context_size;
+ int frame_P_qp, frame_B_qp;
+ int nSize = 0;
+
+ enc_init_mpeg4_arg = (struct mfc_enc_init_mpeg4_arg *)args;
+
+ mfc_debug("++\n");
+ mfc_ctx->MfcCodecType = enc_init_mpeg4_arg->in_codec_type;
+ mfc_ctx->img_width = (unsigned int)enc_init_mpeg4_arg->in_width;
+ mfc_ctx->img_height = (unsigned int)enc_init_mpeg4_arg->in_height;
+ mfc_ctx->interlace_mode = enc_init_mpeg4_arg->in_interlace_mode;
+
+
+ /*
+ * Set Available Type
+ */
+ if (mCheckType == false) {
+ nSize = mfc_ctx->img_width * mfc_ctx->img_height;
+ mfc_ctx->shared_mem.p720_limit_enable = 49425;
+ if (nSize > BOUND_MEMORY_SIZE)
+ return MFCINST_ERR_FRM_BUF_SIZE;
+ } else {
+ mfc_ctx->shared_mem.p720_limit_enable = 49424;
+ }
+
+
+
+
+ /* OPEN CHANNEL
+ * - set open instance using codec_type
+ * - get the instance no
+ */
+ ret_code = mfc_alloc_context_buffer(mfc_ctx, enc_init_mpeg4_arg->in_mapped_addr, &context_addr, &context_size);
+ if (ret_code != MFCINST_RET_OK)
+ return ret_code;
+
+ mfc_ctx->InstNo = mfc_get_inst_no(mfc_ctx, context_addr, context_size);
+ if (mfc_ctx->InstNo < 0) {
+ mfc_err("MFCINST_INST_NUM_EXCEEDED\n");
+ return MFCINST_INST_NUM_EXCEEDED;
+ }
+
+ /* INIT CODEC
+ * - set init parameter
+ * - set init sequence done command
+ * - set codec buffer
+ * - set input risc buffer
+ */
+
+ mfc_set_encode_init_param(mfc_ctx, args);
+
+ ret_code = mfc_alloc_codec_buffer(mfc_ctx, args);
+ if (ret_code != MFCINST_RET_OK) {
+ /* In case of no instance, we should not release codec instance */
+ if (mfc_ctx->InstNo >= 0)
+ mfc_return_inst_no(mfc_ctx->InstNo, mfc_ctx->MfcCodecType);
+
+ return ret_code;
+ }
+
+ mfc_set_codec_buffer(mfc_ctx);
+
+ /* Set Ref YC0~3 & MV */
+ ret_code = mfc_alloc_stream_ref_buffer(mfc_ctx, args);
+ if (ret_code != MFCINST_RET_OK) {
+ /* In case of no instance, we should not release codec instance */
+ if (mfc_ctx->InstNo >= 0)
+ mfc_return_inst_no(mfc_ctx->InstNo, mfc_ctx->MfcCodecType);
+
+ return ret_code;
+ }
+
+ mfc_set_enc_ref_buffer(mfc_ctx, args);
+
+ if (enc_init_mpeg4_arg->in_frame_P_qp)
+ frame_P_qp = enc_init_mpeg4_arg->in_frame_P_qp;
+ else
+ frame_P_qp = enc_init_mpeg4_arg->in_frame_qp;
+
+ if (enc_init_mpeg4_arg->in_frame_B_qp)
+ frame_B_qp = enc_init_mpeg4_arg->in_frame_B_qp;
+ else
+ frame_B_qp = enc_init_mpeg4_arg->in_frame_qp;
+ mfc_ctx->shared_mem.P_B_frame_qp = (frame_B_qp << 6 | frame_P_qp);
+
+ if (enc_init_mpeg4_arg->in_RC_frm_enable)
+ mfc_ctx->shared_mem.vop_timing = ((1 << 31) | (enc_init_mpeg4_arg->in_RC_framerate << 16) | 1);
+
+
+ mfc_write_shared_mem(mfc_ctx->shared_mem_vaddr, &(mfc_ctx->shared_mem));
+
+ ret_code = mfc_encode_header(mfc_ctx, args);
+
+ mfc_read_shared_mem(mfc_ctx->shared_mem_vaddr, &(mfc_ctx->shared_mem));
+
+ mfc_backup_context(mfc_ctx);
+
+ mfc_debug_L0("--\n");
+
+ return ret_code;
+}
+
+static enum mfc_error_code mfc_encode_header(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args)
+{
+ struct mfc_enc_init_mpeg4_arg *init_arg;
+ unsigned int port0_base_paddr;
+ int nIntrRet = 0;
+ int nReturnErrCode = 0;
+
+ init_arg = (struct mfc_enc_init_mpeg4_arg *)args;
+
+ mfc_debug("++ enc_arg->in_strm_st : 0x%08x\n", init_arg->out_p_addr.strm_ref_y);
+
+ port0_base_paddr = mfc_port0_base_paddr;
+
+ /* Set share memory */
+ WRITEL((mfc_ctx->shared_mem_paddr - port0_base_paddr), MFC_SI_CH0_HOST_WR_ADR);
+
+ /* Set stream buffer addr */
+ WRITEL((init_arg->out_p_addr.strm_ref_y - port0_base_paddr) >> 11, MFC_SI_CH0_SB_U_ADDR);
+ WRITEL((init_arg->out_p_addr.strm_ref_y - port0_base_paddr) >> 11, MFC_SI_CH0_SB_L_ADDR);
+ WRITEL(STREAM_BUF_SIZE, MFC_SI_CH0_BUFFER_SIZE);
+
+ WRITEL(1, MFC_STR_BF_U_EMPTY);
+ WRITEL(1, MFC_STR_BF_L_EMPTY);
+
+ /* buf reset command if stream buffer is frame mode */
+ WRITEL(0x1 << 1, MFC_EDFU_SF_BUF_CTRL);
+
+ WRITEL((SEQ_HEADER << 16) | (mfc_ctx->InstNo), MFC_SI_CH0_INST_ID);
+ nIntrRet = mfc_wait_for_done(R2H_CMD_SEQ_DONE_RET);
+ nReturnErrCode = mfc_return_code();
+ if (nIntrRet == 0) {
+ mfc_err("MFCINST_ERR_ENC_EXE_TIME_OUT\n");
+ return MFCINST_ERR_INTR_TIME_OUT;
+ } else if ((nIntrRet != R2H_CMD_SEQ_DONE_RET) && (nReturnErrCode < MFC_WARN_START_NO)) {
+ mfc_err("MFCINST_ERR_ENC_SEQ_HEADER_FAIL ....Intr Code (%d)\n", nIntrRet);
+ return MFCINST_ERR_ENC_HEADER_DECODE_FAIL;
+ } else if (nIntrRet != R2H_CMD_SEQ_DONE_RET) {
+ mfc_warn("MFCINST_WARN_ENC_SEQ_HEADER.........(code: %d)\n", nIntrRet);
+ }
+
+
+ init_arg->out_header_size = READL(MFC_SI_ENC_STREAM_SIZE);
+
+ mfc_debug("encoded header size (%d)\n", init_arg->out_header_size);
+
+ return MFCINST_RET_OK;
+}
+
+static enum mfc_error_code mfc_encode_one_frame(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args)
+{
+ struct mfc_enc_exe_arg *enc_arg;
+ unsigned int port0_base_paddr, port1_base_paddr;
+ int interrupt_flag;
+ int nReturnErrCode;
+
+
+ enc_arg = (struct mfc_enc_exe_arg *)args;
+
+ mfc_debug("++ enc_arg->in_strm_st : 0x%08x enc_arg->in_strm_end :0x%08x \r\n",
+ enc_arg->in_strm_st, enc_arg->in_strm_end);
+ mfc_debug("enc_arg->in_Y_addr : 0x%08x enc_arg->in_CbCr_addr :0x%08x \r\n",
+ enc_arg->in_Y_addr, enc_arg->in_CbCr_addr);
+
+ mfc_restore_context(mfc_ctx);
+
+ port0_base_paddr = mfc_port0_base_paddr;
+ port1_base_paddr = mfc_port1_base_paddr;
+
+#ifdef ENABLE_DEBUG_ENC_EXE_INTR_ERR
+#if ENABLE_DEBUG_ENC_EXE_INTR_ERR
+ makefile_mfc_enc_err_info(enc_arg);
+#endif
+#endif
+
+ /* Set share memory */
+ WRITEL((mfc_ctx->shared_mem_paddr - port0_base_paddr), MFC_SI_CH0_HOST_WR_ADR);
+
+ /* Set stream buffer addr */
+ WRITEL((enc_arg->in_strm_st - port0_base_paddr) >> 11, MFC_SI_CH0_SB_U_ADDR);
+ WRITEL((enc_arg->in_strm_st - port0_base_paddr) >> 11, MFC_SI_CH0_SB_L_ADDR);
+ WRITEL(STREAM_BUF_SIZE, MFC_SI_CH0_BUFFER_SIZE);
+
+ /* Set current frame buffer addr */
+ WRITEL((enc_arg->in_Y_addr - port1_base_paddr) >> 11, MFC_SI_CH0_CURRENT_Y_ADDR);
+ WRITEL((enc_arg->in_CbCr_addr - port1_base_paddr) >> 11, MFC_SI_CH0_CURRENT_C_ADDR);
+
+ WRITEL(1, MFC_STR_BF_U_EMPTY);
+ WRITEL(1, MFC_STR_BF_L_EMPTY);
+
+ /* buf reset command if stream buffer is frame mode */
+ WRITEL(0x1 << 1, MFC_EDFU_SF_BUF_CTRL);
+
+ if (mfc_ctx->forceSetFrameType == NOT_CODED)
+ WRITEL((0x1 << 1), MFC_SI_CH0_ENC_PARA);
+ else if (mfc_ctx->forceSetFrameType == I_FRAME)
+ WRITEL(0x1, MFC_SI_CH0_ENC_PARA);
+
+ mfc_ctx->forceSetFrameType = DONT_CARE;
+
+ /* Try frame encoding */
+ WRITEL((FRAME << 16) | (mfc_ctx->InstNo), MFC_SI_CH0_INST_ID);
+ interrupt_flag = mfc_wait_for_done(R2H_CMD_FRAME_DONE_RET);
+ nReturnErrCode = mfc_return_code();
+ if (interrupt_flag == 0) {
+ mfc_err("MFCINST_ERR_ENC_EXE_TIME_OUT\n");
+ return MFCINST_ERR_INTR_TIME_OUT;
+ } else if ((interrupt_flag != R2H_CMD_FRAME_DONE_RET) && (nReturnErrCode < MFC_WARN_START_NO)) {
+ mfc_err("MFCINST_ERR_ENC_DONE_FAIL\n");
+ return MFCINST_ERR_ENC_ENCODE_DONE_FAIL;
+ } else if (interrupt_flag != R2H_CMD_FRAME_DONE_RET) {
+ mfc_warn("MFCINST_WARN_ENC_EXE.........(code: %d)\n", interrupt_flag);
+ }
+
+ /* Get encoded infromation */
+ enc_arg->out_frame_type = READL(MFC_SI_ENC_SLICE_TYPE);
+ enc_arg->out_encoded_size = READL(MFC_SI_ENC_STREAM_SIZE);
+ enc_arg->out_encoded_Y_paddr = READL(MFC_SI_ENCODED_Y_ADDR);
+ enc_arg->out_encoded_C_paddr = READL(MFC_SI_ENCODED_C_ADDR);
+
+ mfc_debug("-- frame type(%d) encodedSize(%d)\r\n",
+ enc_arg->out_frame_type, enc_arg->out_encoded_size);
+
+ return MFCINST_RET_OK;
+}
+
+enum mfc_error_code mfc_exe_encode(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args)
+{
+ enum mfc_error_code ret_code;
+ struct mfc_enc_exe_arg *enc_arg;
+
+ enc_arg = (struct mfc_enc_exe_arg *)args;
+
+ mfc_ctx->shared_mem.set_frame_tag = enc_arg->in_frametag;
+ mfc_write_shared_mem(mfc_ctx->shared_mem_vaddr, &(mfc_ctx->shared_mem));
+
+ /* 5. Encode Frame */
+ ret_code = mfc_encode_one_frame(mfc_ctx, args);
+
+ if (ret_code != MFCINST_RET_OK) {
+ mfc_debug("mfc_exe_encode() : Encode Fail..(%d)\n", ret_code);
+ return ret_code;
+ }
+
+ mfc_read_shared_mem(mfc_ctx->shared_mem_vaddr, &(mfc_ctx->shared_mem));
+ enc_arg->out_frametag_top = mfc_ctx->shared_mem.get_frame_tag_top;
+ enc_arg->out_frametag_bottom = mfc_ctx->shared_mem.get_frame_tag_bot;
+
+ mfc_debug_L0("--\n");
+
+ return ret_code;
+}
+
+enum mfc_error_code mfc_init_decode(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args)
+{
+ enum mfc_error_code ret_code;
+ struct mfc_dec_init_arg *init_arg;
+ unsigned int context_addr;
+ int context_size;
+ int nSize;
+ int nIntrRet = 0;
+ int nReturnErrCode = 0;
+
+
+ mfc_debug("[%d] mfc_init_decode() start\n", current->pid);
+ init_arg = (struct mfc_dec_init_arg *)args;
+
+ /* Calculate stream header size */
+#if ENABLE_CHECK_SEQ_HEADER
+ init_arg->in_strm_size = calculate_seq_size(init_arg);
+#endif
+
+ /* Context setting from input param */
+ mfc_ctx->MfcCodecType = init_arg->in_codec_type;
+ mfc_ctx->IsPackedPB = init_arg->in_packed_PB;
+
+ /* OPEN CHANNEL
+ * - set open instance using codec_type
+ * - get the instance no
+ */
+ ret_code = mfc_alloc_context_buffer(mfc_ctx, init_arg->in_mapped_addr, &context_addr, &context_size);
+ if (ret_code != MFCINST_RET_OK)
+ return ret_code;
+
+ mfc_ctx->InstNo = mfc_get_inst_no(mfc_ctx, context_addr, context_size);
+ if (mfc_ctx->InstNo < 0) {
+ mfc_err("MFCINST_INST_NUM_EXCEEDED\n");
+ return MFCINST_INST_NUM_EXCEEDED;
+ }
+
+#ifdef ENABLE_DEBUG_DEC_EXE_INTR_ERR
+#if ENABLE_DEBUG_DEC_EXE_INTR_ERR
+ mcontext_addr = context_addr;
+ mcontext_size = context_size;
+#endif
+#endif
+
+ /*
+ * MFC_LF_CONTROL used both encoding and decoding
+ * H.264 encoding, MPEG4 decoding(post filter)
+ * should disable : need more DPB for loop filter
+ */
+
+ /* INIT CODEC
+ * set input stream buffer
+ * set sequence done command
+ * set NUM_EXTRA_DPB
+ */
+ if (mfc_ctx->MfcCodecType == FIMV1_DEC) {
+ WRITEL(mfc_ctx->widthFIMV1, MFC_SI_CH0_FIMV1_HRESOL);
+ WRITEL(mfc_ctx->heightFIMV1, MFC_SI_CH0_FIMV1_VRESOL);
+ }
+
+ ret_code = mfc_alloc_codec_buffer(mfc_ctx, args);
+ if (ret_code != MFCINST_RET_OK) {
+ /* In case of no instance, we should not release codec instance */
+ if (mfc_ctx->InstNo >= 0)
+ mfc_return_inst_no(mfc_ctx->InstNo, mfc_ctx->MfcCodecType);
+
+ return ret_code;
+ }
+
+ if (nReturnErrCode < 0)
+ return MFCINST_ERR_DEC_INVALID_STRM;
+
+ mfc_set_dec_stream_buffer(mfc_ctx, init_arg->in_strm_buf, init_arg->in_strm_size);
+
+ /* Set Display Delay and SliceEnable */
+ mfc_ctx->sliceEnable = 0;
+ WRITEL(((mfc_ctx->sliceEnable << 31) |
+ (mfc_ctx->displayDelay ? ((1 << 30) |
+ (mfc_ctx->displayDelay << 16)) : 0)),
+ MFC_SI_CH0_DPB_CONFIG_CTRL);
+
+ /* Codec Command : Decode a sequence header */
+ WRITEL((SEQ_HEADER << 16) | (mfc_ctx->InstNo), MFC_SI_CH0_INST_ID);
+
+ nIntrRet = mfc_wait_for_done(R2H_CMD_SEQ_DONE_RET);
+ nReturnErrCode = mfc_return_code();
+ if (nIntrRet == 0) {
+
+#ifdef ENABLE_DEBUG_DEC_EXE_INTR_ERR
+#if ENABLE_DEBUG_DEC_EXE_INTR_ERR
+ makefile_mfc_decinit_err_info(mfc_ctx, init_arg, 300);
+#endif
+#endif
+
+ mfc_err("MFCINST_ERR_DEC_INIT_TIME_OUT..........[#1]\n");
+ /* In case of no instance, we should not release codec instance */
+ if (mfc_ctx->InstNo >= 0)
+ mfc_return_inst_no(mfc_ctx->InstNo, mfc_ctx->MfcCodecType);
+
+ return MFCINST_ERR_INTR_TIME_OUT;
+ } else if ((nIntrRet != R2H_CMD_SEQ_DONE_RET) && (nReturnErrCode < MFC_WARN_START_NO)) {
+ mfc_err("MFCINST_ERR_DEC_SEQ_HEADER_FAIL ....Intr Code (%d)\n", nIntrRet);
+ /* In case of no instance, we should not release codec instance */
+ if (mfc_ctx->InstNo >= 0)
+ mfc_return_inst_no(mfc_ctx->InstNo, mfc_ctx->MfcCodecType);
+
+ return MFCINST_ERR_DEC_SEQ_DONE_FAIL;
+ } else if (nIntrRet != R2H_CMD_SEQ_DONE_RET) {
+ mfc_warn("MFCINST_WARN_DEC_INIT.........(code: %d)\n", nIntrRet);
+ }
+
+#ifdef ENABLE_DEBUG_DEC_EXE_INTR_OK
+ #if ENABLE_DEBUG_DEC_EXE_INTR_OK
+ makefile_mfc_decinit_err_info(mfc_ctx, init_arg, 1000);
+#endif
+#endif
+
+ /* out param & context setting from header decoding result */
+ mfc_ctx->img_width = READL(MFC_SI_HOR_RESOL);
+ mfc_ctx->img_height = READL(MFC_SI_VER_RESOL);
+
+ init_arg->out_img_width = READL(MFC_SI_HOR_RESOL);
+ init_arg->out_img_height = READL(MFC_SI_VER_RESOL);
+
+ /* in the case of VC1 interlace, height will be the multiple of 32
+ * otherwise, height and width is the mupltiple of 16
+ */
+ init_arg->out_buf_width = ALIGN_TO_128B(READL(MFC_SI_HOR_RESOL));
+ init_arg->out_buf_height = ALIGN_TO_32B(READL(MFC_SI_VER_RESOL));
+
+ if (mfc_ctx->MfcCodecType == FIMV1_DEC) {
+ mfc_ctx->img_width = mfc_ctx->widthFIMV1;
+ mfc_ctx->img_height = mfc_ctx->heightFIMV1;
+
+ init_arg->out_img_width = mfc_ctx->widthFIMV1;
+ init_arg->out_img_height = mfc_ctx->heightFIMV1;
+ init_arg->out_buf_width = ALIGN_TO_128B(mfc_ctx->widthFIMV1);
+ init_arg->out_buf_height = ALIGN_TO_32B(mfc_ctx->heightFIMV1);
+ }
+
+
+ /* Set totalDPB */
+ init_arg->out_dpb_cnt = READL(MFC_SI_MIN_NUM_DPB);
+ mfc_ctx->DPBCnt = READL(MFC_SI_MIN_NUM_DPB);
+
+ mfc_ctx->totalDPBCnt = init_arg->out_dpb_cnt;
+ mfc_ctx->totalDPBCnt = init_arg->out_dpb_cnt + mfc_ctx->extraDPB;
+ if (mfc_ctx->totalDPBCnt < mfc_ctx->displayDelay)
+ mfc_ctx->totalDPBCnt = mfc_ctx->displayDelay;
+
+ WRITEL(((mfc_ctx->sliceEnable << 31) |
+ (mfc_ctx->displayDelay ? ((1 << 30) |
+ (mfc_ctx->displayDelay << 16)) : 0) |
+ mfc_ctx->totalDPBCnt), MFC_SI_CH0_DPB_CONFIG_CTRL);
+
+ mfc_debug("buf_width : %d buf_height : %d out_dpb_cnt : %d mfc_ctx->DPBCnt : %d\n",
+ init_arg->out_img_width, init_arg->out_img_height, init_arg->out_dpb_cnt, mfc_ctx->DPBCnt);
+ mfc_debug("img_width : %d img_height : %d\n",
+ init_arg->out_img_width, init_arg->out_img_height);
+
+ mfc_set_codec_buffer(mfc_ctx);
+
+ ret_code = mfc_alloc_dec_frame_buffer(mfc_ctx, args);
+ if (ret_code != MFCINST_RET_OK) {
+ /* In case of no instance, we should not release codec instance */
+ if (mfc_ctx->InstNo >= 0)
+ mfc_return_inst_no(mfc_ctx->InstNo, mfc_ctx->MfcCodecType);
+
+ return ret_code;
+ }
+
+ mfc_set_dec_frame_buffer(mfc_ctx);
+
+ /*
+ * Set Available Type
+ */
+ if (mCheckType == false) {
+ nSize = mfc_ctx->img_width * mfc_ctx->img_height;
+ mfc_ctx->shared_mem.p720_limit_enable = 49425;
+ if (nSize > BOUND_MEMORY_SIZE) {
+ /* In case of no instance, we should not release codec instance */
+ if (mfc_ctx->InstNo >= 0)
+ mfc_return_inst_no(mfc_ctx->InstNo, mfc_ctx->MfcCodecType);
+
+ return MFCINST_ERR_FRM_BUF_SIZE;
+ }
+ } else {
+ mfc_ctx->shared_mem.p720_limit_enable = 49424;
+ }
+
+#ifdef ENABLE_DEBUG_MFC_INIT
+#if ENABLE_DEBUG_MFC_INIT
+ printk_mfc_init_info(mfc_ctx, init_arg);
+#endif
+#endif
+
+ mfc_write_shared_mem(mfc_ctx->shared_mem_vaddr, &(mfc_ctx->shared_mem));
+ WRITEL((mfc_ctx->shared_mem_paddr - mfc_port0_base_paddr), MFC_SI_CH0_HOST_WR_ADR);
+ WRITEL((INIT_BUFFER << 16) | (mfc_ctx->InstNo), MFC_SI_CH0_INST_ID);
+
+ nIntrRet = mfc_wait_for_done(R2H_CMD_INIT_BUFFERS_RET);
+ nReturnErrCode = mfc_return_code();
+ if (nIntrRet == 0) {
+#ifdef ENABLE_DEBUG_DEC_EXE_INTR_ERR
+#if ENABLE_DEBUG_DEC_EXE_INTR_ERR
+ makefile_mfc_decinit_err_info(mfc_ctx, init_arg, 300);
+#endif
+#endif
+
+ mfc_err("MFCINST_ERR_DEC_INIT_TIME_OUT..............[#2]\n");
+ /* In case of no instance, we should not release codec instance */
+ if (mfc_ctx->InstNo >= 0)
+ mfc_return_inst_no(mfc_ctx->InstNo, mfc_ctx->MfcCodecType);
+
+ return MFCINST_ERR_INTR_TIME_OUT;
+ } else if ((nIntrRet != R2H_CMD_INIT_BUFFERS_RET) && (nReturnErrCode < MFC_WARN_START_NO)) {
+ mfc_err("MFCINST_ERR_DEC_INIT_BUFFER_FAIL ........(Intr Code : %d)\n", nIntrRet);
+ /* In case of no instance, we should not release codec instance */
+ if (mfc_ctx->InstNo >= 0)
+ mfc_return_inst_no(mfc_ctx->InstNo, mfc_ctx->MfcCodecType);
+
+ return MFCINST_ERR_DEC_INIT_BUFFER_FAIL;
+ } else if (nIntrRet != R2H_CMD_INIT_BUFFERS_RET) {
+ mfc_warn("MFCINST_WARN_DEC_INIT_BUFFER.........(Intr code: %d)\n", nIntrRet);
+ }
+
+ mfc_ctx->IsStartedIFrame = 0;
+
+ mfc_backup_context(mfc_ctx);
+
+ mfc_debug("[%d] mfc_init_decode() end\n", current->pid);
+
+ mfc_read_shared_mem(mfc_ctx->shared_mem_vaddr, &(mfc_ctx->shared_mem));
+ init_arg->out_crop_top_offset = (mfc_ctx->shared_mem.crop_info2 & 0xffff);
+ init_arg->out_crop_bottom_offset = (mfc_ctx->shared_mem.crop_info2 >> 16);
+ init_arg->out_crop_left_offset = (mfc_ctx->shared_mem.crop_info1 & 0xffff);
+ init_arg->out_crop_right_offset = (mfc_ctx->shared_mem.crop_info1 >> 16);
+ mfc_debug("out_crop_top_offset : %d out_crop_bottom_offset : %d\n", init_arg->out_crop_top_offset, init_arg->out_crop_bottom_offset);
+
+ return MFCINST_RET_OK;
+}
+
+static enum mfc_error_code mfc_decode_one_frame(struct mfc_inst_ctx *mfc_ctx, struct mfc_dec_exe_arg *dec_arg, unsigned int *consumed_strm_size)
+{
+ unsigned int frame_type;
+ static int count;
+ int interrupt_flag;
+ int nReturnErrCode = 0;
+ int nMaxFrameSize = 0;
+ int nOffSet = 0;
+ int nSum = 0;
+ unsigned char *stream_vir;
+
+ /* Check Invalid Stream Size */
+#if ENABLE_CHECK_STREAM_SIZE
+ nMaxFrameSize = mfc_ctx->img_height * mfc_ctx->img_width;
+ if ((dec_arg->in_strm_size < 1) || (dec_arg->in_strm_size > nMaxFrameSize) || (dec_arg->in_strm_size > STREAM_BUF_SIZE)) {
+ mfc_err("MFCINST_ERR_DEC_STRM_SIZE_INVALID : (stream size : %d), (resolution : %d)\n", dec_arg->in_strm_size, nMaxFrameSize);
+ return MFCINST_ERR_DEC_STRM_SIZE_INVALID;
+ }
+#endif
+
+ /* Check Invalid Null Stream */
+#if ENABLE_CHECK_NULL_STREAM
+ if ((dec_arg->in_strm_size > 10) && (!(mfc_ctx->IsPackedPB))) {
+ stream_vir = phys_to_virt(dec_arg->in_strm_buf);
+ nSum = CheckNullStream(stream_vir, dec_arg->in_strm_size);
+
+ if (nSum != 0) {
+#ifdef ENABLE_DEBUG_DEC_EXE_INTR_ERR
+ #if ENABLE_DEBUG_DEC_EXE_INTR_ERR
+ makefile_mfc_dec_err_info(mfc_ctx, dec_arg, 500);
+#endif
+#endif
+ return MFCINST_ERR_STRM_BUF_INVALID;
+ }
+ }
+#endif
+
+ /* Check H.263 Strat Code */
+#if ENABLE_CHECK_START_CODE
+ stream_vir = phys_to_virt(dec_arg->in_strm_buf);
+ nOffSet = CheckDecStartCode(stream_vir, dec_arg->in_strm_size, dec_arg->in_codec_type);
+
+ if (nOffSet < 0) {
+#ifdef ENABLE_DEBUG_DEC_EXE_INTR_ERR
+ #if ENABLE_DEBUG_DEC_EXE_INTR_ERR
+ makefile_mfc_dec_err_info(mfc_ctx, dec_arg, 400);
+#endif
+#endif
+ return MFCINST_ERR_STRM_BUF_INVALID;
+ }
+#endif
+
+ count++;
+ mfc_debug_L0("++ IntNo%d(%d)\r\n", mfc_ctx->InstNo, count);
+
+ WRITEL((mfc_ctx->shared_mem_paddr - mfc_port0_base_paddr), MFC_SI_CH0_HOST_WR_ADR);
+ mfc_set_dec_stream_buffer(mfc_ctx, dec_arg->in_strm_buf, dec_arg->in_strm_size);
+
+ if (mfc_ctx->endOfFrame) {
+ WRITEL((LAST_FRAME<<16) | (mfc_ctx->InstNo), MFC_SI_CH0_INST_ID);
+ mfc_ctx->endOfFrame = 0;
+ } else {
+ WRITEL((FRAME<<16) | (mfc_ctx->InstNo), MFC_SI_CH0_INST_ID);
+ }
+
+ interrupt_flag = mfc_wait_for_done(R2H_CMD_FRAME_DONE_RET);
+ nReturnErrCode = mfc_return_code();
+ if (interrupt_flag == 0) {
+#ifdef ENABLE_DEBUG_DEC_EXE_INTR_ERR
+ #if ENABLE_DEBUG_DEC_EXE_INTR_ERR
+ makefile_mfc_dec_err_info(mfc_ctx, dec_arg, 300);
+#endif
+#endif
+
+
+#if ENABLE_MFC_REGISTER_DEBUG
+ mfc_fw_debug(R2H_CMD_FRAME_DONE_RET);
+#endif
+
+ mfc_err("MFCINST_ERR_DEC_EXE_TIME_OUT\n");
+ return MFCINST_ERR_INTR_TIME_OUT;
+ } else if ((interrupt_flag != R2H_CMD_FRAME_DONE_RET) && (nReturnErrCode < MFC_WARN_START_NO)) {
+
+#ifdef ENABLE_DEBUG_DEC_EXE_PARSER_ERR
+ #if ENABLE_DEBUG_DEC_EXE_PARSER_ERR
+ makefile_mfc_dec_err_info(mfc_ctx, dec_arg, nReturnErrCode);
+#endif
+#endif
+ /* Clear start_byte_num in case of error */
+ mfc_ctx->shared_mem.start_byte_num = 0x0;
+ mfc_write_shared_mem(mfc_ctx->shared_mem_vaddr, &(mfc_ctx->shared_mem));
+
+#if ENABLE_MFC_REGISTER_DEBUG
+ mfc_fw_debug(R2H_CMD_FRAME_DONE_RET);
+#endif
+
+ mfc_err("MFCINST_ERR_DEC_DONE_FAIL.......(interrupt_flag: %d), (ERR Code: %d)\n", interrupt_flag, nReturnErrCode);
+ return MFCINST_ERR_DEC_DECODE_DONE_FAIL;
+
+ } else if (interrupt_flag != R2H_CMD_FRAME_DONE_RET) {
+ mfc_warn("MFCINST_WARN_DEC_EXE.........(interrupt_flag: %d), (WARN Code: %d)\n", interrupt_flag, nReturnErrCode);
+ }
+
+ mfc_read_shared_mem(mfc_ctx->shared_mem_vaddr, &(mfc_ctx->shared_mem));
+
+ dec_arg->out_res_change = (READL(MFC_SI_DISPLAY_STATUS) >> 4) & 0x3;
+
+ if (((READL(MFC_SI_DISPLAY_STATUS) & 0x3) != DECODING_DISPLAY) &&
+ ((READL(MFC_SI_DISPLAY_STATUS) & 0x3) != DISPLAY_ONLY)) {
+ dec_arg->out_display_Y_addr = 0;
+ dec_arg->out_display_C_addr = 0;
+ mfc_debug("DECODING_ONLY frame decoded\n");
+ } else {
+ /* address shift */
+ dec_arg->out_display_Y_addr = READL(MFC_SI_DISPLAY_Y_ADR) << 11;
+ dec_arg->out_display_C_addr = READL(MFC_SI_DISPLAY_C_ADR) << 11;
+ mfc_debug("DISPLAY Able frame decoded\n");
+ }
+
+ if ((READL(MFC_SI_DISPLAY_STATUS) & 0x3) == DECODING_EMPTY)
+ dec_arg->out_display_status = 0;
+ else if ((READL(MFC_SI_DISPLAY_STATUS) & 0x3) == DECODING_DISPLAY)
+ dec_arg->out_display_status = 1;
+ else if ((READL(MFC_SI_DISPLAY_STATUS) & 0x3) == DISPLAY_ONLY)
+ dec_arg->out_display_status = 2;
+ else
+ dec_arg->out_display_status = 3;
+
+ frame_type = READL(MFC_SI_FRAME_TYPE);
+ mfc_ctx->FrameType = (enum mfc_frame_type)(frame_type & 0x3);
+
+ mfc_debug_L0("(Y_ADDR : 0x%08x C_ADDR : 0x%08x)\r\n",
+ dec_arg->out_display_Y_addr, dec_arg->out_display_C_addr);
+
+ *consumed_strm_size = READL(MFC_SI_DEC_FRM_SIZE);
+
+ return MFCINST_RET_OK;
+}
+
+enum mfc_error_code mfc_exe_decode(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args)
+{
+ enum mfc_error_code ret_code;
+ struct mfc_dec_exe_arg *dec_arg;
+ int consumed_strm_size;
+
+ /* 6. Decode Frame */
+ mfc_debug_L0("[%d] mfc_exe_decode() start\n", current->pid);
+
+ dec_arg = (struct mfc_dec_exe_arg *)args;
+
+ mfc_ctx->shared_mem.set_frame_tag = dec_arg->in_frametag;
+
+ mfc_write_shared_mem(mfc_ctx->shared_mem_vaddr, &(mfc_ctx->shared_mem));
+
+ ret_code = mfc_decode_one_frame(mfc_ctx, dec_arg, &consumed_strm_size);
+
+ if (ret_code != MFCINST_RET_OK) {
+ mfc_debug("mfc_exe_decode() : Decode Fail..(%d)\n", ret_code);
+ return ret_code;
+ }
+
+ mfc_read_shared_mem(mfc_ctx->shared_mem_vaddr, &(mfc_ctx->shared_mem));
+ dec_arg->out_frametag_top = mfc_ctx->shared_mem.get_frame_tag_top;
+ dec_arg->out_frametag_bottom = mfc_ctx->shared_mem.get_frame_tag_bot;
+ dec_arg->out_timestamp_top = mfc_ctx->shared_mem.pic_time_top;
+ dec_arg->out_timestamp_bottom = mfc_ctx->shared_mem.pic_time_bot;
+ dec_arg->out_consume_bytes = consumed_strm_size;
+ dec_arg->out_crop_top_offset = (mfc_ctx->shared_mem.crop_info2 & 0xffff);
+ dec_arg->out_crop_bottom_offset = (mfc_ctx->shared_mem.crop_info2 >> 16);
+ dec_arg->out_crop_left_offset = (mfc_ctx->shared_mem.crop_info1 & 0xffff);
+ dec_arg->out_crop_right_offset = (mfc_ctx->shared_mem.crop_info1 >> 16);
+
+
+ /* PackedPB Stream Processing */
+ if ((mfc_ctx->IsPackedPB) &&
+ (mfc_ctx->FrameType == MFC_RET_FRAME_P_FRAME) &&
+ (dec_arg->in_strm_size - consumed_strm_size > 4)) {
+
+ unsigned char *stream_vir;
+ int offset = 0;
+
+ stream_vir = phys_to_virt(dec_arg->in_strm_buf);
+
+ invalidate_kernel_vmap_range((void *)stream_vir, dec_arg->in_strm_size);
+
+ offset = CheckMPEG4StartCode(stream_vir+consumed_strm_size , dec_arg->in_strm_size - consumed_strm_size);
+ if (offset > 4)
+ consumed_strm_size += offset;
+ dec_arg->in_strm_size -= consumed_strm_size;
+
+ mfc_ctx->shared_mem.set_frame_tag = dec_arg->in_frametag;
+ mfc_ctx->shared_mem.start_byte_num = consumed_strm_size;
+ mfc_write_shared_mem(mfc_ctx->shared_mem_vaddr, &(mfc_ctx->shared_mem));
+ ret_code = mfc_decode_one_frame(mfc_ctx, dec_arg, &consumed_strm_size);
+ if (ret_code != MFCINST_RET_OK)
+ return ret_code;
+
+ mfc_read_shared_mem(mfc_ctx->shared_mem_vaddr, &(mfc_ctx->shared_mem));
+ dec_arg->out_frametag_top = mfc_ctx->shared_mem.get_frame_tag_top;
+ dec_arg->out_frametag_bottom = mfc_ctx->shared_mem.get_frame_tag_bot;
+ dec_arg->out_timestamp_top = mfc_ctx->shared_mem.pic_time_top;
+ dec_arg->out_timestamp_bottom = mfc_ctx->shared_mem.pic_time_bot;
+ dec_arg->out_consume_bytes += consumed_strm_size;
+ dec_arg->out_crop_top_offset = (mfc_ctx->shared_mem.crop_info2 & 0xffff);
+ dec_arg->out_crop_bottom_offset = (mfc_ctx->shared_mem.crop_info2 >> 16);
+ dec_arg->out_crop_left_offset = (mfc_ctx->shared_mem.crop_info1 & 0xffff);
+ dec_arg->out_crop_right_offset = (mfc_ctx->shared_mem.crop_info1 >> 16);
+
+ mfc_ctx->shared_mem.start_byte_num = 0;
+
+ }
+
+ mfc_debug_L0("--\n");
+
+ return ret_code;
+}
+
+enum mfc_error_code mfc_deinit_hw(struct mfc_inst_ctx *mfc_ctx)
+{
+ mfc_restore_context(mfc_ctx);
+
+ return MFCINST_RET_OK;
+}
+
+enum mfc_error_code mfc_get_config(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args)
+{
+ struct mfc_get_config_arg *get_cnf_arg;
+ get_cnf_arg = (struct mfc_get_config_arg *)args;
+
+ switch (get_cnf_arg->in_config_param) {
+ case MFC_DEC_GETCONF_CRC_DATA:
+ if (mfc_ctx->MfcState != MFCINST_STATE_DEC_EXE) {
+ mfc_err("MFC_DEC_GETCONF_CRC_DATA : state is invalid\n");
+ return MFC_DEC_GETCONF_CRC_DATA;
+ }
+ get_cnf_arg->out_config_value[0] = READL(MFC_CRC_LUMA0);
+ get_cnf_arg->out_config_value[1] = READL(MFC_CRC_CHROMA0);
+ break;
+
+ default:
+ mfc_err("invalid config param\n");
+ return MFCINST_ERR_GET_CONF; /* peter, it should be mod. */
+ }
+
+ return MFCINST_RET_OK;
+}
+
+enum mfc_error_code mfc_set_config(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args)
+{
+ struct mfc_set_config_arg *set_cnf_arg;
+ set_cnf_arg = (struct mfc_set_config_arg *)args;
+
+ switch (set_cnf_arg->in_config_param) {
+ case MFC_DEC_SETCONF_POST_ENABLE:
+ if (mfc_ctx->MfcState >= MFCINST_STATE_DEC_INITIALIZE) {
+ mfc_err("MFC_DEC_SETCONF_POST_ENABLE : state is invalid\n");
+ return MFCINST_ERR_STATE_INVALID;
+ }
+
+ if ((set_cnf_arg->in_config_value[0] == 0) || (set_cnf_arg->in_config_value[0] == 1)) {
+ mfc_ctx->postEnable = set_cnf_arg->in_config_value[0];
+ } else {
+ mfc_warn("POST_ENABLE should be 0 or 1\n");
+ mfc_ctx->postEnable = 0;
+ }
+ break;
+
+ case MFC_DEC_SETCONF_EXTRA_BUFFER_NUM:
+ if (mfc_ctx->MfcState >= MFCINST_STATE_DEC_INITIALIZE) {
+ mfc_err("MFC_DEC_SETCONF_EXTRA_BUFFER_NUM : state is invalid\n");
+ return MFCINST_ERR_STATE_INVALID;
+ }
+ if ((set_cnf_arg->in_config_value[0] >= 0) || (set_cnf_arg->in_config_value[0] <= MFC_MAX_EXTRA_DPB)) {
+ mfc_ctx->extraDPB = set_cnf_arg->in_config_value[0];
+ } else {
+ mfc_warn("EXTRA_BUFFER_NUM should be between 0 and 5...It will be set 5 by default\n");
+ mfc_ctx->extraDPB = MFC_MAX_EXTRA_DPB;
+ }
+ break;
+
+ case MFC_DEC_SETCONF_DISPLAY_DELAY:
+ if (mfc_ctx->MfcState >= MFCINST_STATE_DEC_INITIALIZE) {
+ mfc_err("MFC_DEC_SETCONF_DISPLAY_DELAY : state is invalid\n");
+ return MFCINST_ERR_STATE_INVALID;
+ }
+
+ if ((set_cnf_arg->in_config_value[0] >= 0) || (set_cnf_arg->in_config_value[0] < 16)) {
+ mfc_ctx->displayDelay = set_cnf_arg->in_config_value[0];
+ mfc_debug("DISPLAY_DELAY Number = %d\n", mfc_ctx->displayDelay);
+ } else {
+ mfc_warn("DISPLAY_DELAY should be between 0 and 16\n");
+ mfc_ctx->displayDelay = 0;
+ }
+ break;
+
+ case MFC_DEC_SETCONF_IS_LAST_FRAME:
+ if (mfc_ctx->MfcState != MFCINST_STATE_DEC_EXE) {
+ mfc_err("MFC_DEC_SETCONF_IS_LAST_FRAME : state is invalid\n");
+ return MFCINST_ERR_STATE_INVALID;
+ }
+
+ if ((set_cnf_arg->in_config_value[0] == 0) || (set_cnf_arg->in_config_value[0] == 1)) {
+ mfc_ctx->endOfFrame = set_cnf_arg->in_config_value[0];
+ } else {
+ mfc_warn("IS_LAST_FRAME should be 0 or 1\n");
+ mfc_ctx->endOfFrame = 0;
+ }
+ break;
+
+ case MFC_DEC_SETCONF_SLICE_ENABLE:
+ if (mfc_ctx->MfcState >= MFCINST_STATE_DEC_INITIALIZE) {
+ mfc_err("MFC_DEC_SETCONF_SLICE_ENABLE : state is invalid\n");
+ return MFCINST_ERR_STATE_INVALID;
+ }
+
+ if ((set_cnf_arg->in_config_value[0] == 0) || (set_cnf_arg->in_config_value[0] == 1)) {
+ mfc_ctx->sliceEnable = set_cnf_arg->in_config_value[0];
+ } else {
+ mfc_warn("SLICE_ENABLE should be 0 or 1\n");
+ mfc_ctx->sliceEnable = 0;
+ }
+ break;
+
+ case MFC_DEC_SETCONF_CRC_ENABLE:
+ if (mfc_ctx->MfcState >= MFCINST_STATE_DEC_INITIALIZE) {
+ mfc_err("MFC_DEC_SETCONF_CRC_ENABLE : state is invalid\n");
+ return MFCINST_ERR_STATE_INVALID;
+ }
+
+ if ((set_cnf_arg->in_config_value[0] == 0) || (set_cnf_arg->in_config_value[0] == 1)) {
+ mfc_ctx->crcEnable = set_cnf_arg->in_config_value[0];
+ } else {
+ mfc_warn("CRC_ENABLE should be 0 or 1\n");
+ mfc_ctx->crcEnable = 0;
+ }
+ break;
+
+ case MFC_DEC_SETCONF_FIMV1_WIDTH_HEIGHT:
+ if (mfc_ctx->MfcState >= MFCINST_STATE_DEC_INITIALIZE) {
+ mfc_err("MFC_DEC_SETCONF_FIMV1_WIDTH_HEIGHT : state is invalid\n");
+ return MFCINST_ERR_STATE_INVALID;
+ }
+
+ mfc_ctx->widthFIMV1 = set_cnf_arg->in_config_value[0];
+ mfc_ctx->heightFIMV1 = set_cnf_arg->in_config_value[1];
+ break;
+
+ case MFC_ENC_SETCONF_FRAME_TYPE:
+ if (mfc_ctx->MfcState != MFCINST_STATE_ENC_EXE) {
+ mfc_err("MFC_ENC_SETCONF_FRAME_TYPE : state is invalid\n");
+ return MFCINST_ERR_STATE_INVALID;
+ }
+
+ if ((set_cnf_arg->in_config_value[0] >= DONT_CARE) && (set_cnf_arg->in_config_value[0] <= NOT_CODED)) {
+ mfc_ctx->forceSetFrameType = set_cnf_arg->in_config_value[0];
+ } else {
+ mfc_warn("FRAME_TYPE should be between 0 and 2\n");
+ mfc_ctx->forceSetFrameType = DONT_CARE;
+ }
+ break;
+
+ case MFC_ENC_SETCONF_ALLOW_FRAME_SKIP:
+ if (mfc_ctx->MfcState >= MFCINST_STATE_ENC_INITIALIZE) {
+ mfc_err("MFC_ENC_SETCONF_ALLOW_FRAME_SKIP : state is invalid\n");
+ return MFCINST_ERR_STATE_INVALID;
+ }
+
+ if (set_cnf_arg->in_config_value[0])
+ mfc_ctx->shared_mem.ext_enc_control = (mfc_ctx->shared_mem.ext_enc_control | (0x1 << 1));
+ break;
+
+ /* XXX: need to implement */
+ case MFC_ENC_SETCONF_CHANGE_FRAME_RATE:
+ if (mfc_ctx->MfcState != MFCINST_STATE_ENC_EXE) {
+ mfc_err("MFC_ENC_SETCONF_FRAME_TYPE : state is invalid\n");
+ return MFCINST_ERR_STATE_INVALID;
+ }
+ break;
+
+ /* XXX: need to implement */
+ case MFC_ENC_SETCONF_CHANGE_BIT_RATE:
+ if (mfc_ctx->MfcState != MFCINST_STATE_ENC_EXE) {
+ mfc_err("MFC_ENC_SETCONF_FRAME_TYPE : state is invalid\n");
+ return MFCINST_ERR_STATE_INVALID;
+ }
+ break;
+
+ default:
+ mfc_err("invalid config param\n");
+ return MFCINST_ERR_SET_CONF;
+ }
+
+ return MFCINST_RET_OK;
+}
+
+enum mfc_error_code mfc_set_sleep()
+{
+ if (mfc_cmd_host2risc(H2R_CMD_SLEEP, 0, 0, 0, 0) == false) {
+ mfc_err("R2H_CMD_SLEEP FAIL\n");
+ return MFCINST_SLEEP_FAIL;
+ }
+
+ if (mfc_wait_for_done(R2H_CMD_SLEEP_RET) != R2H_CMD_SLEEP_RET) {
+ mfc_err("R2H_CMD_SLEEP_RET FAIL\n");
+ return MFCINST_SLEEP_FAIL;
+ }
+
+ return MFCINST_RET_OK;
+}
+
+enum mfc_error_code mfc_set_wakeup()
+{
+ int ret;
+
+ if (mfc_cmd_host2risc(H2R_CMD_WAKEUP, 0, 0, 0, 0) == false) {
+ mfc_err("R2H_CMD_WAKEUP FAIL\n");
+ return MFCINST_WAKEUP_FAIL;
+ }
+
+ WRITEL(0x3ff, MFC_SW_RESET);
+
+ ret = mfc_wait_for_done(R2H_CMD_WAKEUP_RET);
+ if ((ret != R2H_CMD_WAKEUP_RET) && (ret != R2H_CMD_FW_STATUS_RET)) {
+ mfc_err("R2H_CMD_WAKEUP_RET FAIL\n");
+ return MFCINST_WAKEUP_FAIL;
+ }
+
+ return MFCINST_RET_OK;
+}
+
+static enum
+mfc_error_code mfc_alloc_context_buffer(struct mfc_inst_ctx *mfc_ctx, unsigned int mapped_addr,
+ unsigned int *context_addr, int *size)
+{
+ union mfc_args local_param;
+ enum mfc_error_code ret_code;
+ unsigned char *context_vir;
+
+ switch (mfc_ctx->MfcCodecType) {
+ case H264_ENC:
+ *size = H264ENC_CONTEXT_SIZE;
+ break;
+
+ case MPEG4_ENC:
+ *size = MPEG4ENC_CONTEXT_SIZE;
+ break;
+
+ case H263_ENC:
+ *size = H263ENC_CONTEXT_SIZE;
+ break;
+
+ case H264_DEC:
+ *size = H264DEC_CONTEXT_SIZE;
+ break;
+
+ case H263_DEC:
+ *size = H263DEC_CONTEXT_SIZE;
+ break;
+
+ case MPEG2_DEC:
+ *size = MPEG2DEC_CONTEXT_SIZE;
+ break;
+
+ case MPEG4_DEC:
+ case FIMV1_DEC:
+ case FIMV2_DEC:
+ case FIMV3_DEC:
+ case FIMV4_DEC:
+ *size = MPEG4DEC_CONTEXT_SIZE;
+ break;
+
+ case VC1_DEC:
+ case VC1RCV_DEC:
+ *size = VC1DEC_CONTEXT_SIZE;
+ break;
+
+ default:
+ return MFCINST_ERR_WRONG_CODEC_MODE;
+ }
+
+ memset(&local_param, 0, sizeof(local_param));
+ local_param.mem_alloc.buff_size = *size;
+ local_param.mem_alloc.mapped_addr = mapped_addr;
+
+ ret_code = mfc_allocate_buffer(mfc_ctx, &(local_param), 0);
+ if (ret_code < 0)
+ return ret_code;
+
+ /* Set mfc context to "0". */
+ context_vir = phys_to_virt(local_param.mem_alloc.out_paddr);
+ memset(context_vir, 0x0, local_param.mem_alloc.buff_size);
+
+ dmac_flush_range(context_vir, context_vir + local_param.mem_alloc.buff_size);
+
+ *context_addr = local_param.mem_alloc.out_paddr;
+
+ return ret_code;
+}
+
+void mfc_init_mem_inst_no(void)
+{
+ memset(&mfc_mem_inst_no, 0x00, sizeof(mfc_mem_inst_no));
+}
+
+int mfc_get_mem_inst_no(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < MFC_MAX_INSTANCE_NUM; i++) {
+ if (mfc_mem_inst_no[i] == 0) {
+ mfc_mem_inst_no[i] = 1;
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+void mfc_return_mem_inst_no(int inst_no)
+{
+ if ((inst_no >= 0) && (inst_no < MFC_MAX_INSTANCE_NUM))
+ mfc_mem_inst_no[inst_no] = 0;
+}
+
+bool mfc_is_running(void)
+{
+ unsigned int i;
+ bool ret = false;
+
+ for (i = 0; i < MFC_MAX_INSTANCE_NUM; i++) {
+ mfc_debug("mfc_mem_inst_no[%d] = %d\n", i, mfc_mem_inst_no[i]);
+ if (mfc_mem_inst_no[i] == 1)
+ ret = true;
+ }
+
+ return ret;
+}
+
+int mfc_set_state(struct mfc_inst_ctx *ctx, enum mfc_inst_state state)
+{
+ if (ctx->MfcState > state)
+ return -1;
+
+ ctx->MfcState = state;
+ return 0;
+}
+
+bool is_dec_codec(enum ssbsip_mfc_codec_type codec_type)
+{
+ switch (codec_type) {
+ case H264_DEC:
+ case VC1_DEC:
+ case MPEG4_DEC:
+ case XVID_DEC:
+ case MPEG1_DEC:
+ case MPEG2_DEC:
+ case H263_DEC:
+ case VC1RCV_DEC:
+ case FIMV1_DEC:
+ case FIMV2_DEC:
+ case FIMV3_DEC:
+ case FIMV4_DEC:
+ return true;
+
+ case H264_ENC:
+ case MPEG4_ENC:
+ case H263_ENC:
+ return false;
+
+ default:
+ return false;
+ }
+}
+
+
+
+
+
+/*
+ * Debugging Functions Definition
+ * tile_to_linear_4x2(..)
+ * calculate_seq_size(..)
+ * printk_mfc_init_info(..)
+ */
+
+
+#if DEBUG_MAKE_RAW
+static void write_file(char *filename, unsigned char *data, unsigned int nSize)
+{
+ struct file *file;
+ loff_t pos = 0;
+ int fd;
+ mm_segment_t old_fs;
+
+ invalidate_kernel_vmap_range(data, nSize);
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ fd = sys_open(filename, O_WRONLY|O_CREAT, 0644);
+ if (fd >= 0) {
+ sys_write(fd, data, nSize);
+ file = fget(fd);
+ if (file) {
+ vfs_write(file, data, nSize, &pos);
+ fput(file);
+ }
+ sys_close(fd);
+ } else {
+ mfc_err("........Open fail : %d\n", fd);
+ }
+ set_fs(old_fs);
+
+ dmac_flush_range(data, data + nSize);
+
+}
+
+static int tile_4x2_read(int x_size, int y_size, int x_pos, int y_pos)
+{
+ int pixel_x_m1, pixel_y_m1;
+ int roundup_x, roundup_y;
+ int linear_addr0, linear_addr1, bank_addr ;
+ int x_addr;
+ int trans_addr;
+
+ pixel_x_m1 = x_size - 1;
+ pixel_y_m1 = y_size - 1;
+
+ roundup_x = ((pixel_x_m1 >> 7) + 1);
+ roundup_y = ((pixel_x_m1 >> 6) + 1);
+
+ x_addr = (x_pos >> 2);
+
+ if ((y_size <= y_pos+32) && (y_pos < y_size) &&
+ (((pixel_y_m1 >> 5) & 0x1) == 0) && (((y_pos >> 5) & 0x1) == 0)) {
+ linear_addr0 = (((y_pos & 0x1f) << 4) | (x_addr & 0xf));
+ linear_addr1 = (((y_pos >> 6) & 0xff) * roundup_x + ((x_addr >> 6) & 0x3f));
+
+ if (((x_addr >> 5) & 0x1) == ((y_pos >> 5) & 0x1))
+ bank_addr = ((x_addr >> 4) & 0x1);
+ else
+ bank_addr = 0x2 | ((x_addr >> 4) & 0x1);
+ } else {
+ linear_addr0 = (((y_pos & 0x1f) << 4) | (x_addr & 0xf));
+ linear_addr1 = (((y_pos >> 6) & 0xff) * roundup_x + ((x_addr >> 5) & 0x7f));
+
+ if (((x_addr >> 5) & 0x1) == ((y_pos >> 5) & 0x1))
+ bank_addr = ((x_addr >> 4) & 0x1);
+ else
+ bank_addr = 0x2 | ((x_addr >> 4) & 0x1);
+ }
+
+ linear_addr0 = linear_addr0 << 2;
+ trans_addr = (linear_addr1 << 13) | (bank_addr << 11) | linear_addr0;
+
+ return trans_addr;
+}
+
+
+static void copy16(unsigned char *p_linear_addr, unsigned char *p_tiled_addr, int mm, int nn)
+{
+ p_linear_addr[mm] = p_tiled_addr[nn];
+ p_linear_addr[mm + 1] = p_tiled_addr[nn + 1];
+ p_linear_addr[mm + 2] = p_tiled_addr[nn + 2];
+ p_linear_addr[mm + 3] = p_tiled_addr[nn + 3];
+
+ p_linear_addr[mm + 4] = p_tiled_addr[nn + 4];
+ p_linear_addr[mm + 5] = p_tiled_addr[nn + 5];
+ p_linear_addr[mm + 6] = p_tiled_addr[nn + 6];
+ p_linear_addr[mm + 7] = p_tiled_addr[nn + 7];
+
+ p_linear_addr[mm + 8] = p_tiled_addr[nn + 8];
+ p_linear_addr[mm + 9] = p_tiled_addr[nn + 9];
+ p_linear_addr[mm + 10] = p_tiled_addr[nn + 10];
+ p_linear_addr[mm + 11] = p_tiled_addr[nn + 11];
+
+ p_linear_addr[mm + 12] = p_tiled_addr[nn + 12];
+ p_linear_addr[mm + 13] = p_tiled_addr[nn + 13];
+ p_linear_addr[mm + 14] = p_tiled_addr[nn + 14];
+ p_linear_addr[mm + 15] = p_tiled_addr[nn + 15];
+}
+
+
+static void
+tile_to_linear_4x2(unsigned char *p_linear_addr, unsigned char *p_tiled_addr,
+ unsigned int x_size, unsigned int y_size)
+{
+ int trans_addr;
+ unsigned int i, j, k, nn, mm, index;
+
+ /*. TILE 4x2 test */
+ for (i = 0; i < y_size; i = i + 16) {
+ for (j = 0; j < x_size; j = j + 16) {
+ trans_addr = tile_4x2_read(x_size, y_size, j, i);
+ index = i*x_size + j;
+
+ k = 0; nn = trans_addr + (k << 6); mm = index;
+ copy16(p_linear_addr, p_tiled_addr, mm, nn);
+
+ k = 1; nn = trans_addr + (k << 6); mm += x_size;
+ copy16(p_linear_addr, p_tiled_addr, mm, nn);
+
+ k = 2; nn = trans_addr + (k << 6); mm += x_size;
+ copy16(p_linear_addr, p_tiled_addr, mm, nn);
+
+ k = 3; nn = trans_addr + (k << 6); mm += x_size;
+ copy16(p_linear_addr, p_tiled_addr, mm, nn);
+
+ k = 4; nn = trans_addr + (k << 6); mm += x_size;
+ copy16(p_linear_addr, p_tiled_addr, mm, nn);
+
+ k = 5; nn = trans_addr + (k << 6); mm += x_size;
+ copy16(p_linear_addr, p_tiled_addr, mm, nn);
+
+ k = 6; nn = trans_addr + (k << 6); mm += x_size;
+ copy16(p_linear_addr, p_tiled_addr, mm, nn);
+
+ k = 7; nn = trans_addr + (k << 6); mm += x_size;
+ copy16(p_linear_addr, p_tiled_addr, mm, nn);
+
+ k = 8; nn = trans_addr + (k << 6); mm += x_size;
+ copy16(p_linear_addr, p_tiled_addr, mm, nn);
+
+ k = 9; nn = trans_addr + (k << 6); mm += x_size;
+ copy16(p_linear_addr, p_tiled_addr, mm, nn);
+
+ k = 10; nn = trans_addr + (k << 6); mm += x_size;
+ copy16(p_linear_addr, p_tiled_addr, mm, nn);
+
+ k = 11; nn = trans_addr + (k << 6); mm += x_size;
+ copy16(p_linear_addr, p_tiled_addr, mm, nn);
+
+ k = 12; nn = trans_addr + (k << 6); mm += x_size;
+ copy16(p_linear_addr, p_tiled_addr, mm, nn);
+
+ k = 13; nn = trans_addr + (k << 6); mm += x_size;
+ copy16(p_linear_addr, p_tiled_addr, mm, nn);
+
+ k = 14; nn = trans_addr + (k << 6); mm += x_size;
+ copy16(p_linear_addr, p_tiled_addr, mm, nn);
+
+ k = 15; nn = trans_addr + (k << 6); mm += x_size;
+ copy16(p_linear_addr, p_tiled_addr, mm, nn);
+
+ }
+ }
+}
+#endif
+
+
+
+#if ENABLE_CHECK_SEQ_HEADER
+static int calculate_seq_size(mfc_args *args)
+{
+ int nn = 0;
+ int nCnt = 0;
+ unsigned char nSum = 0;
+ unsigned char *stream_vir;
+
+ stream_vir = phys_to_virt(args->dec_init.in_strm_buf);
+ if (args->dec_init.in_strm_size > 31) {
+ for (nn = 0; nn < args->dec_init.in_strm_size - 4; nn++) {
+ nSum = (unsigned char)(((*(stream_vir + nn)) << 1) + ((*(stream_vir + nn + 1)) << 1)
+ + ((*(stream_vir + nn + 2)) << 1) + (*(stream_vir+nn+3)));
+ if (nSum == 0x1) {
+ nCnt++;
+ }
+
+ if (nCnt == 3) {
+ mfc_info("After Stream Size : %d , nCnt = %d\n", args->dec_init.in_strm_size, nCnt);
+ return nn;
+ }
+ }
+ }
+
+ return args->dec_init.in_strm_size;
+}
+#endif
+
+
+#if ENABLE_DEBUG_MFC_INIT
+void printk_mfc_init_info(mfc_inst_ctx *mfc_ctx, mfc_args *args)
+{
+ int nn = 0;
+ unsigned char *stream_vir;
+
+ mfc_info("MFC Decoder/Encoder Init Information\n");
+ mfc_info("[InstNo : %d], [DPBCnt : %d], [totalDPBCnt : %d], [extraDPB : %d], [displayDelay : %d],\n",
+ mfc_ctx->InstNo, mfc_ctx->DPBCnt, mfc_ctx->totalDPBCnt, mfc_ctx->extraDPB, mfc_ctx->displayDelay);
+ mfc_info("[img_width : %d], [img_height : %d], [MfcCodecType : %d], [MfcState : %d]\n",
+ mfc_ctx->img_width, mfc_ctx->img_height, mfc_ctx->MfcCodecType, mfc_ctx->MfcState);
+
+ mfc_info("Input Stream Buffer Information\n");
+ mfc_info("[in_strm_size : %d], [in_strm_buf : %d]\n",
+ args->dec_init.in_strm_size, args->dec_init.in_strm_buf);
+
+ stream_vir = phys_to_virt(args->dec_init.in_strm_buf);
+ if (args->dec_init.in_strm_size > 0) {
+ mfc_info("Input Stream Buffer\n");
+ for (nn = 0; nn < 40; nn++)
+ printk("%02x ", *(stream_vir+nn));
+ printk("\n");
+ }
+
+}
+#endif
+
+
+#ifdef ENABLE_DEBUG_DEC_EXE_INTR_ERR
+#if ENABLE_DEBUG_DEC_EXE_INTR_ERR
+void printk_mfc_dec_exe_info(struct mfc_inst_ctx *mfc_ctx, struct mfc_dec_exe_arg *dec_arg)
+{
+ int nn = 0;
+ unsigned char *stream_vir;
+
+ mfc_info("MFC Decoder/Encoder Exe Information\n");
+ mfc_info("[InstNo : %d], [DPBCnt : %d], [totalDPBCnt : %d], [extraDPB : %d], [displayDelay : %d],\n",
+ mfc_ctx->InstNo, mfc_ctx->DPBCnt, mfc_ctx->totalDPBCnt, mfc_ctx->extraDPB, mfc_ctx->displayDelay);
+ mfc_info("[img_width : %d], [img_height : %d], [MfcCodecType : %d], [MfcState : %d], [FrameType: %d]\n",
+ mfc_ctx->img_width, mfc_ctx->img_height, mfc_ctx->MfcCodecType, mfc_ctx->MfcState, mfc_ctx->FrameType);
+
+ mfc_info("Input Stream Buffer Information\n");
+ mfc_info("[in_strm_size : %d], [in_strm_buf : %d]\n",
+ dec_arg->in_strm_size, dec_arg->in_strm_buf);
+
+ stream_vir = phys_to_virt(dec_arg->in_strm_buf);
+ if (dec_arg->in_strm_size > 0) {
+ mfc_info("Input Stream Buffer\n");
+ for (nn = 0; nn < 50; nn++)
+ printk("%02x ", *(stream_vir+nn));
+ printk("\n");
+ }
+}
+
+void
+makefile_mfc_dec_err_info(struct mfc_inst_ctx *mfc_ctx,
+ struct mfc_dec_exe_arg *dec_arg, int nReturnErrCode)
+{
+ char fileName0[50];
+ char fileName1[50];
+ unsigned char *ctx_virbuf;
+ unsigned char *mfc_dec_in_base_vaddr;
+
+ mframe_cnt++;
+
+ if ((nReturnErrCode < 145) || (nReturnErrCode == 300)) {
+ mIsDangerError = 1;
+ printk_mfc_dec_exe_info(mfc_ctx, dec_arg);
+ }
+
+ memset(fileName0, 0, 50);
+ memset(fileName1, 0, 50);
+
+ sprintf(fileName0, "/data/dec_in/mfc_decexe_instream_%d_%d.raw", nReturnErrCode, mframe_cnt);
+ sprintf(fileName1, "/data/dec_in/mfc_decexe_mfcctx_%d_%d.bin", nReturnErrCode, mframe_cnt);
+
+ mfc_dec_in_base_vaddr = phys_to_virt(dec_arg->in_strm_buf);
+ ctx_virbuf = phys_to_virt(mcontext_addr);
+
+ write_file(fileName0, mfc_dec_in_base_vaddr, dec_arg->in_strm_size);
+ write_file(fileName1, ctx_virbuf, mcontext_size);
+
+}
+
+
+void makefile_mfc_decinit_err_info(struct mfc_inst_ctx *mfc_ctx, struct mfc_dec_init_arg *decinit_arg, int nReturnErrCode)
+{
+ char fileName0[50];
+ char fileName1[50];
+ unsigned char *ctx_virbuf;
+ unsigned char *mfc_dec_in_base_vaddr;
+
+ mframe_cnt++;
+
+ pr_info("makefile_mfc_decinit_err_info : in_strm_size(%d)\n", decinit_arg->in_strm_size);
+
+ memset(fileName0, 0, 50);
+ memset(fileName1, 0, 50);
+
+ sprintf(fileName0, "/data/dec_in/mfc_decinit_instream_%d_%d.raw", nReturnErrCode, mframe_cnt);
+ sprintf(fileName1, "/data/dec_in/mfc_decinit_mfcctx_%d_%d.bin", nReturnErrCode, mframe_cnt);
+
+ mfc_dec_in_base_vaddr = phys_to_virt(decinit_arg->in_strm_buf);
+ ctx_virbuf = phys_to_virt(mcontext_addr);
+
+ write_file(fileName0, mfc_dec_in_base_vaddr, decinit_arg->in_strm_size);
+ write_file(fileName1, ctx_virbuf, mcontext_size);
+}
+#endif
+#endif
+
+#ifdef ENABLE_DEBUG_ENC_EXE_INTR_ERR
+#if ENABLE_DEBUG_ENC_EXE_INTR_ERR
+void makefile_mfc_enc_err_info(struct mfc_enc_exe_arg *enc_arg)
+{
+ int nFrameSize = 0;
+ char fileName[50];
+ unsigned char *mfc_enc_in_base_Y_vaddr;
+ unsigned char *mfc_enc_in_base_CbCr_vaddr;
+
+ mframe_cnt++;
+
+ memset(fileName, 0, 50);
+ sprintf(fileName, "/data/enc_in/mfc_in_%04d.yuv", mframe_cnt);
+ nFrameSize = mImgHight * mImgWidth * 3/2;
+
+ mfc_enc_in_base_Y_vaddr = phys_to_virt(enc_arg->in_Y_addr);
+ mfc_enc_in_base_CbCr_vaddr = phys_to_virt(enc_arg->in_CbCr_addr);
+
+ mfc_debug("enc_arg->in_Y_addr : 0x%08x enc_arg->in_Y_addr_vir :0x%08x\r\n",
+ enc_arg->in_Y_addr, mfc_enc_in_base_Y_vaddr);
+
+ tile_to_linear_4x2(pResLinearbuf, mfc_enc_in_base_Y_vaddr,
+ mImgWidth, mImgHight);
+ tile_to_linear_4x2(pResLinearbuf + (mImgHight * mImgWidth),
+ mfc_enc_in_base_CbCr_vaddr, mImgWidth, mImgHight/2);
+ write_file(fileName, pResLinearbuf, nFrameSize);
+
+}
+#endif
+#endif
+
+
+static int CheckMPEG4StartCode(unsigned char *src_mem, unsigned int remainSize)
+{
+ unsigned int index = 0;
+
+ for (index = 0; index < remainSize-3; index++) {
+ if ((src_mem[index] == 0x00)
+ && (src_mem[index+1] == 0x00)
+ && (src_mem[index+2] == 0x01))
+ return index;
+ }
+
+ return -1;
+}
+
+#if ENABLE_CHECK_START_CODE
+static int CheckDecStartCode(unsigned char *src_mem, unsigned int nstreamSize, enum ssbsip_mfc_codec_type nCodecType)
+{
+ unsigned int index = 0;
+ /* Check Start Code within "isearchSize" bytes. */
+ unsigned int isearchSize = 20;
+ unsigned int nShift = 0;
+ unsigned char nFlag = 0xFF;
+
+ if (nCodecType == H263_DEC) {
+ nFlag = 0x08;
+ nShift = 4;
+ } else if (nCodecType == MPEG4_DEC) {
+ nFlag = 0x01;
+ nShift = 0;
+ } else if (nCodecType == H264_DEC) {
+ nFlag = 0x01;
+ nShift = 0;
+ } else {
+ nFlag = 0xFF;
+ }
+
+ if (nFlag != 0xFF) {
+ if (nstreamSize > 3) {
+ if (nstreamSize > isearchSize) {
+ for (index = 0; index < isearchSize-3; index++) {
+ if ((src_mem[index] == 0x00)
+ && (src_mem[index+1] == 0x00)
+ && ((src_mem[index+2] >> nShift) == nFlag))
+ return index;
+ }
+ } else {
+ for (index = 0; index < nstreamSize - 3; index++) {
+ if ((src_mem[index] == 0x00)
+ && (src_mem[index+1] == 0x00)
+ && ((src_mem[index+2] >> nShift) == nFlag))
+ return index;
+ }
+ }
+ } else {
+ return -1;
+ }
+ } else {
+ return 0;
+ }
+
+ return -1;
+}
+#endif
+
+#if ENABLE_CHECK_NULL_STREAM
+static int CheckNullStream(unsigned char *src_mem, unsigned int streamSize)
+{
+ unsigned int temp = 0;
+ unsigned int nn;
+
+ if (streamSize < 30) {
+ for (nn = 0; nn < streamSize; nn++)
+ temp += src_mem[nn];
+ } else {
+ for (nn = 0; nn < 10; nn++)
+ temp += src_mem[nn];
+
+ if (temp == 0) {
+ for (nn = streamSize-10; nn < streamSize; nn++)
+ temp += src_mem[nn];
+ }
+ }
+
+ if (temp == 0) {
+ mfc_debug("Null Stream......Error\n");
+ return -1;
+ }
+
+ return 0;
+
+}
+#endif
+
+#if ENABLE_MFC_REGISTER_DEBUG
+void mfc_fw_debug(mfc_wait_done_type command)
+{
+ mfc_err("=== MFC FW Debug (Cmd: %d)"
+ "(Ver: 0x%08x) ===\n", command, READL(0x58));
+ mfc_err("=== (0x64: 0x%08x) (0x68: 0x%08x)"
+ "(0xE4: 0x%08x) (0xE8: 0x%08x)\n",
+ READL(0x64), READL(0x68), READL(0xe4), READL(0xe8));
+ mfc_err("=== (0xF0: 0x%08x) (0xF4: 0x%08x)"
+ "(0xF8: 0x%08x) (0xFC: 0x%08x)\n",
+ READL(0xf0), READL(0xf4), READL(0xf8), READL(0xfc));
+}
+#endif
diff --git a/drivers/media/video/samsung/mfc50/mfc_opr.h b/drivers/media/video/samsung/mfc50/mfc_opr.h
new file mode 100644
index 0000000..2c2a570
--- /dev/null
+++ b/drivers/media/video/samsung/mfc50/mfc_opr.h
@@ -0,0 +1,202 @@
+/*
+ * drivers/media/video/samsung/mfc50/mfc_opr.h
+ *
+ * Header file for Samsung MFC (Multi Function Codec - FIMV) driver
+ *
+ * Jaeryul Oh, Copyright (c) 2009 Samsung Electronics
+ * http://www.samsungsemi.com/
+ *
+ * Change Logs
+ * 2009.09.14 - Beautify source code (Key Young, Park)
+ * 2009.09.21 - Implement clock & power gating.
+ * including suspend & resume fuction. (Key Young, Park)
+ * 2009.11.04 - remove mfc_common.[ch]
+ * seperate buffer alloc & set (Key Young, Park)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MFC_OPR_H_
+#define _MFC_OPR_H_
+
+#include <plat/regs-mfc.h>
+#include "mfc_errorno.h"
+#include "mfc_interface.h"
+#include "mfc_shared_mem.h"
+
+#define MFC_WARN_START_NO 145
+#define MFC_ERR_START_NO 1
+
+
+#define INT_MFC_FW_DONE (0x1 << 5)
+#define INT_MFC_DMA_DONE (0x1 << 7)
+#define INT_MFC_FRAME_DONE (0x1 << 8)
+/* Interrupt on/off (0x500) */
+#define INT_ENABLE_BIT (0 << 0)
+#define INT_DISABLE_BIT (1 << 0)
+/* Interrupt mode (0x504) */
+#define INT_LEVEL_BIT (0 << 0)
+#define INT_PULSE_BIT (1 << 0)
+
+/* Command Types */
+#define MFC_CHANNEL_SET 0
+#define MFC_CHANNEL_READ 1
+#define MFC_CHANNEL_END 2
+#define MFC_INIT_CODEC 3
+#define MFC_FRAME_RUN 4
+#define MFC_SLEEP 6
+#define MFC_WAKEUP 7
+
+/* DPB Count */
+#define NUM_MPEG4_DPB 2
+#define NUM_POST_DPB 3
+#define NUM_VC1_DPB 4
+
+#define ALIGN_TO_16B(x) ((((x) + (1 << 4) - 1) >> 4) << 4)
+#define ALIGN_TO_32B(x) ((((x) + (1 << 5) - 1) >> 5) << 5)
+#define ALIGN_TO_64B(x) ((((x) + (1 << 6) - 1) >> 6) << 6)
+#define ALIGN_TO_128B(x) ((((x) + (1 << 7) - 1) >> 7) << 7)
+#define ALIGN_TO_2KB(x) ((((x) + (1 << 11) - 1) >> 11) << 11)
+#define ALIGN_TO_4KB(x) ((((x) + (1 << 12) - 1) >> 12) << 12)
+#define ALIGN_TO_8KB(x) ((((x) + (1 << 13) - 1) >> 13) << 13)
+#define ALIGN_TO_64KB(x) ((((x) + (1 << 16) - 1) >> 16) << 16)
+#define ALIGN_TO_128KB(x) ((((x) + (1 << 17) - 1) >> 17) << 17)
+
+#define PIXEL_CACHE_ON_ONLY_P_PICTURE 0
+#define PIXEL_CACHE_ON_ONLY_B_PICTURE 1
+#define PIXEL_CACHE_ON_BOTH_P_B_PICTURE 2
+#define PIXEL_CACHE_DISABLE 3
+
+#define BOUND_MEMORY_SIZE 921600
+
+enum mfc_inst_state {
+ MFCINST_STATE_NULL = 0,
+
+ /* Instance is created */
+ MFCINST_STATE_OPENED = 10,
+
+ /* channel_set and init_codec is completed */
+ MFCINST_STATE_DEC_INITIALIZE = 20,
+
+ MFCINST_STATE_DEC_EXE = 30,
+ MFCINST_STATE_DEC_EXE_DONE,
+
+ /* Instance is initialized for encoding */
+ MFCINST_STATE_ENC_INITIALIZE = 40,
+ MFCINST_STATE_ENC_EXE,
+ MFCINST_STATE_ENC_EXE_DONE
+};
+
+enum mfc_mem_type {
+ MEM_STRUCT_LINEAR = 0,
+ MEM_STRUCT_TILE_ENC = 3 /* 64x32 */
+};
+
+enum mfc_dec_type {
+ SEQ_HEADER = 1,
+ FRAME = 2,
+ LAST_FRAME = 3,
+ INIT_BUFFER = 4,
+ FRAME_RUN_REALLOC = 5,
+};
+
+enum mfc_facade_cmd {
+ H2R_CMD_EMPTY = 0,
+ H2R_CMD_OPEN_INSTANCE = 1,
+ H2R_CMD_CLOSE_INSTANCE = 2,
+ H2R_CMD_SYS_INIT = 3,
+ H2R_CMD_SLEEP = 5,
+ H2R_CMD_WAKEUP = 6,
+};
+
+enum mfc_wait_done_type {
+ R2H_CMD_EMPTY = 0,
+ R2H_CMD_OPEN_INSTANCE_RET = 1,
+ R2H_CMD_CLOSE_INSTANCE_RET = 2,
+ R2H_CMD_ERROR_RET = 3,
+ R2H_CMD_SEQ_DONE_RET = 4,
+ R2H_CMD_FRAME_DONE_RET = 5,
+ R2H_CMD_SLICE_DONE_RET = 6,
+ R2H_CMD_ENC_COMPLETE_RET = 6,
+ R2H_CMD_SYS_INIT_RET = 8,
+ R2H_CMD_FW_STATUS_RET = 9,
+ R2H_CMD_SLEEP_RET = 10,
+ R2H_CMD_WAKEUP_RET = 11,
+ R2H_CMD_INIT_BUFFERS_RET = 15,
+ R2H_CMD_EDFU_INT_RET = 16,
+ R2H_CMD_DECODE_ERR_RET = 32
+};
+
+enum mfc_display_status {
+ DECODING_ONLY = 0,
+ DECODING_DISPLAY = 1,
+ DISPLAY_ONLY = 2,
+ DECODING_EMPTY = 3
+};
+
+/* In case of decoder */
+enum mfc_frame_type {
+ MFC_RET_FRAME_NOT_SET = 0,
+ MFC_RET_FRAME_I_FRAME = 1,
+ MFC_RET_FRAME_P_FRAME = 2,
+ MFC_RET_FRAME_B_FRAME = 3
+};
+
+struct mfc_inst_ctx {
+ int InstNo;
+ unsigned int DPBCnt;
+ unsigned int totalDPBCnt;
+ unsigned int extraDPB;
+ unsigned int displayDelay;
+ unsigned int postEnable;
+ unsigned int endOfFrame;
+ unsigned int forceSetFrameType;
+ unsigned int img_width;
+ unsigned int img_height;
+ unsigned int dwAccess; /* for Power Management. */
+ unsigned int IsPackedPB;
+ unsigned int interlace_mode;
+ unsigned int sliceEnable;
+ unsigned int crcEnable;
+ unsigned int widthFIMV1;
+ unsigned int heightFIMV1;
+ int mem_inst_no;
+ enum mfc_frame_type FrameType;
+ enum ssbsip_mfc_codec_type MfcCodecType;
+ enum mfc_inst_state MfcState;
+ unsigned int port0_mmap_size;
+ unsigned int codec_buff_paddr;
+ unsigned int pred_buff_paddr;
+ struct mfc_frame_buf_arg dec_dpb_buff_paddr;
+ unsigned int shared_mem_paddr;
+ unsigned int shared_mem_vaddr;
+ unsigned int IsStartedIFrame;
+ struct mfc_shared_mem shared_mem;
+};
+
+int mfc_load_firmware(const unsigned char *data, size_t size);
+bool mfc_cmd_reset(void);
+
+enum mfc_error_code mfc_init_hw(void);
+enum mfc_error_code mfc_init_encode(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args);
+enum mfc_error_code mfc_exe_encode(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args);
+enum mfc_error_code mfc_init_decode(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args);
+enum mfc_error_code mfc_exe_decode(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args);
+enum mfc_error_code mfc_get_config(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args);
+enum mfc_error_code mfc_set_config(struct mfc_inst_ctx *mfc_ctx, union mfc_args *args);
+enum mfc_error_code mfc_deinit_hw(struct mfc_inst_ctx *mfc_ctx);
+enum mfc_error_code mfc_set_sleep(void);
+enum mfc_error_code mfc_set_wakeup(void);
+
+int mfc_return_inst_no(int inst_no, enum ssbsip_mfc_codec_type codec_type);
+int mfc_set_state(struct mfc_inst_ctx *ctx, enum mfc_inst_state state);
+void mfc_init_mem_inst_no(void);
+int mfc_get_mem_inst_no(void);
+void mfc_return_mem_inst_no(int inst_no);
+bool mfc_is_running(void);
+bool is_dec_codec(enum ssbsip_mfc_codec_type codec_type);
+
+
+#endif /* _MFC_OPR_H_ */
diff --git a/drivers/media/video/samsung/mfc50/mfc_shared_mem.c b/drivers/media/video/samsung/mfc50/mfc_shared_mem.c
new file mode 100644
index 0000000..813c2db
--- /dev/null
+++ b/drivers/media/video/samsung/mfc50/mfc_shared_mem.c
@@ -0,0 +1,123 @@
+/*
+ * drivers/media/video/samsung/mfc50/mfc_shared_mem.c
+ *
+ * Header file for Samsung MFC (Multi Function Codec - FIMV) driver
+ *
+ * Key-Young Park, Copyright (c) 2009 Samsung Electronics
+ * http://www.samsungsemi.com/
+ *
+ * Change Logs
+ * 2009.10.08 - Apply 9/30 firmware(Key Young, Park)
+ * 2009.11.06 - clean & invalidate shared mem area (Key Young, Park)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/io.h>
+#include <asm/cacheflush.h>
+
+#include "mfc_shared_mem.h"
+#include "mfc_logmsg.h"
+
+#define DEBUG_ENABLE 0
+
+static inline void mfc_write_shared_mem_item(unsigned int host_wr_addr, unsigned int addr, unsigned int value)
+{
+ MEM_WRITE(host_wr_addr + addr, value);
+}
+
+static inline unsigned int mfc_read_shared_mem_item(unsigned int host_wr_addr, unsigned int addr)
+{
+ return MEM_READ(host_wr_addr + addr);
+}
+
+void mfc_write_shared_mem(unsigned int host_wr_addr, struct mfc_shared_mem *shared_mem)
+{
+ mfc_write_shared_mem_item(host_wr_addr, RC_CONTROL_ENABLE, 1);/* RC_CONTROL_CONFIG : enable (1), disable(0) */
+
+ mfc_write_shared_mem_item(host_wr_addr, SET_FRAME_TAG, shared_mem->set_frame_tag);
+ mfc_write_shared_mem_item(host_wr_addr, START_BYTE_NUM, shared_mem->start_byte_num);
+ mfc_write_shared_mem_item(host_wr_addr, EXT_ENC_CONTROL, shared_mem->ext_enc_control);
+ mfc_write_shared_mem_item(host_wr_addr, ENC_PARAM_CHANGE, shared_mem->enc_param_change);
+ mfc_write_shared_mem_item(host_wr_addr, VOP_TIMING, shared_mem->vop_timing);
+ mfc_write_shared_mem_item(host_wr_addr, HEC_PERIOD, shared_mem->hec_period);
+ mfc_write_shared_mem_item(host_wr_addr, P_B_FRAME_QP, shared_mem->P_B_frame_qp);
+ mfc_write_shared_mem_item(host_wr_addr, METADATA_ENABLE, shared_mem->metadata_enable);
+ mfc_write_shared_mem_item(host_wr_addr, EXT_METADATA_START_ADDR, shared_mem->ext_metadata_start_addr);
+ mfc_write_shared_mem_item(host_wr_addr, PUT_EXTRADATA, shared_mem->put_extradata);
+ mfc_write_shared_mem_item(host_wr_addr, DBG_INFO_INPUT0, shared_mem->dbg_info_input0);
+ mfc_write_shared_mem_item(host_wr_addr, DBG_INFO_INPUT1, shared_mem->dbg_info_input1);
+ mfc_write_shared_mem_item(host_wr_addr, ALLOCATED_LUMA_DPB_SIZE, shared_mem->allocated_luma_dpb_size);
+ mfc_write_shared_mem_item(host_wr_addr, ALLOCATED_CHROMA_DPB_SIZE, shared_mem->allocated_chroma_dpb_size);
+ mfc_write_shared_mem_item(host_wr_addr, ALLOCATED_MV_SIZE, shared_mem->allocated_mv_size);
+ mfc_write_shared_mem_item(host_wr_addr, P720_LIMIT_ENABLE, shared_mem->p720_limit_enable);
+
+ dmac_flush_range((void *)host_wr_addr, (void *)host_wr_addr + SHARED_MEM_MAX);
+
+#if DEBUG_ENABLE
+ mfc_print_shared_mem(host_wr_addr);
+#endif
+}
+
+void mfc_read_shared_mem(unsigned int host_wr_addr, struct mfc_shared_mem *shared_mem)
+{
+ invalidate_kernel_vmap_range((void *)host_wr_addr, SHARED_MEM_MAX);
+
+ shared_mem->extended_decode_status = mfc_read_shared_mem_item(host_wr_addr, EXTENEDED_DECODE_STATUS);
+ shared_mem->get_frame_tag_top = mfc_read_shared_mem_item(host_wr_addr, GET_FRAME_TAG_TOP);
+ shared_mem->get_frame_tag_bot = mfc_read_shared_mem_item(host_wr_addr, GET_FRAME_TAG_BOT);
+ shared_mem->pic_time_top = mfc_read_shared_mem_item(host_wr_addr, PIC_TIME_TOP);
+ shared_mem->pic_time_bot = mfc_read_shared_mem_item(host_wr_addr, PIC_TIME_BOT);
+ shared_mem->start_byte_num = mfc_read_shared_mem_item(host_wr_addr, START_BYTE_NUM);
+ shared_mem->dec_frm_size = mfc_read_shared_mem_item(host_wr_addr, DEC_FRM_SIZE);
+ shared_mem->crop_info1 = mfc_read_shared_mem_item(host_wr_addr, CROP_INFO1);
+ shared_mem->crop_info2 = mfc_read_shared_mem_item(host_wr_addr, CROP_INFO2);
+ shared_mem->metadata_status = mfc_read_shared_mem_item(host_wr_addr, METADATA_STATUS);
+ shared_mem->metadata_display_index = mfc_read_shared_mem_item(host_wr_addr, METADATA_DISPLAY_INDEX);
+ shared_mem->dbg_info_output0 = mfc_read_shared_mem_item(host_wr_addr, DBG_INFO_OUTPUT0);
+ shared_mem->dbg_info_output1 = mfc_read_shared_mem_item(host_wr_addr, DBG_INFO_OUTPUT1);
+
+#if DEBUG_ENABLE
+ mfc_print_shared_mem(host_wr_addr);
+#endif
+}
+
+void mfc_print_shared_mem(unsigned int host_wr_addr)
+{
+ mfc_info("set_frame_tag = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, SET_FRAME_TAG));
+ mfc_info("start_byte_num = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, START_BYTE_NUM));
+ mfc_info("ext_enc_control = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, EXT_ENC_CONTROL));
+ mfc_info("enc_param_change = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, ENC_PARAM_CHANGE));
+ mfc_info("vop_timing = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, VOP_TIMING));
+ mfc_info("hec_period = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, HEC_PERIOD));
+ mfc_info("p_b_frame_qp = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, P_B_FRAME_QP));
+ mfc_info("metadata_enable = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, METADATA_ENABLE));
+ mfc_info("ext_metadata_start_addr= 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, EXT_METADATA_START_ADDR));
+ mfc_info("put_extradata = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, PUT_EXTRADATA));
+ mfc_info("dbg_info_input0 = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, DBG_INFO_INPUT0));
+ mfc_info("dbg_info_input1 = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, DBG_INFO_INPUT1));
+ mfc_info("luma_dpb_size = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, ALLOCATED_LUMA_DPB_SIZE));
+ mfc_info("chroma_dpb_size = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, ALLOCATED_CHROMA_DPB_SIZE));
+ mfc_info("mv_size = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, ALLOCATED_MV_SIZE));
+ mfc_info("extended_decode_status = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, EXTENEDED_DECODE_STATUS));
+ mfc_info("get_frame_tag_top = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, GET_FRAME_TAG_TOP));
+ mfc_info("get_frame_tag_bot = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, GET_FRAME_TAG_BOT));
+ mfc_info("pic_time_top = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, PIC_TIME_TOP));
+ mfc_info("pic_time_bot = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, PIC_TIME_BOT));
+ mfc_info("start_byte_num = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, START_BYTE_NUM));
+ mfc_info("dec_frm_size = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, DEC_FRM_SIZE));
+ mfc_info("crop_info1 = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, CROP_INFO1));
+ mfc_info("crop_info2 = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, CROP_INFO2));
+ mfc_info("metadata_status = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, METADATA_STATUS));
+ mfc_info("metadata_display_index = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, METADATA_DISPLAY_INDEX));
+ mfc_info("dbg_info_output0 = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, DBG_INFO_OUTPUT0));
+ mfc_info("dbg_info_output1 = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, DBG_INFO_OUTPUT1));
+ mfc_info("720p_limit_enable = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, P720_LIMIT_ENABLE));
+ mfc_info("RC_CONTROL_ENABLE = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, RC_CONTROL_ENABLE));
+}
diff --git a/drivers/media/video/samsung/mfc50/mfc_shared_mem.h b/drivers/media/video/samsung/mfc50/mfc_shared_mem.h
new file mode 100644
index 0000000..ca86876
--- /dev/null
+++ b/drivers/media/video/samsung/mfc50/mfc_shared_mem.h
@@ -0,0 +1,97 @@
+/*
+ * drivers/media/video/samsung/mfc50/mfc_shared_mem.h
+ *
+ * Header file for Samsung MFC (Multi Function Codec - FIMV) driver
+ *
+ * Key-Young Park, Copyright (c) 2009 Samsung Electronics
+ * http://www.samsungsemi.com/
+ *
+ * Change Logs
+ * 2009.10.08 - Apply 9/30 firmware(Key Young, Park)
+ * 2009.11.06 - clean & invalidate shared mem area (Key Young, Park)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MFC_SHARED_MEM_H_
+#define _MFC_SHARED_MEM_H_
+
+#define MEM_WRITE(ADDR, VALUE) (*(volatile unsigned int *)(ADDR) = (VALUE))
+#define MEM_READ(ADDR) (*(volatile unsigned int *)(ADDR))
+
+enum mfc_shared {
+ EXTENEDED_DECODE_STATUS = 0x0,
+ SET_FRAME_TAG = 0x4,
+ GET_FRAME_TAG_TOP = 0x8,
+ GET_FRAME_TAG_BOT = 0xC,
+ PIC_TIME_TOP = 0x10,
+ PIC_TIME_BOT = 0x14,
+ START_BYTE_NUM = 0x18,
+ DEC_FRM_SIZE = 0x1C,
+ CROP_INFO1 = 0x20,
+ CROP_INFO2 = 0x24,
+ EXT_ENC_CONTROL = 0x28,
+ ENC_PARAM_CHANGE = 0x2C,
+ VOP_TIMING = 0x30,
+ HEC_PERIOD = 0x34,
+ METADATA_ENABLE = 0x38,
+ METADATA_STATUS = 0x3C,
+ METADATA_DISPLAY_INDEX = 0x40,
+ EXT_METADATA_START_ADDR = 0x44,
+ PUT_EXTRADATA = 0x48,
+ DBG_INFO_OUTPUT0 = 0x4C,
+ DBG_INFO_OUTPUT1 = 0x50,
+ DBG_INFO_INPUT0 = 0x54,
+ DBG_INFO_INPUT1 = 0x58,
+ REF_L0_PHY_IDX = 0x5C,
+ REF_L1_PHY_IDX = 0x60,
+ ALLOCATED_LUMA_DPB_SIZE = 0x64,
+ ALLOCATED_CHROMA_DPB_SIZE = 0x68,
+ ALLOCATED_MV_SIZE = 0x6C,
+ P_B_FRAME_QP = 0x70,
+ RC_CONTROL_ENABLE = 0xA0,
+ P720_LIMIT_ENABLE = 0xB4,
+ SHARED_MEM_MAX = 0x1000,
+};
+
+struct mfc_shared_mem {
+ unsigned int num_dpb;
+ unsigned int allocated_dpb_size;
+ unsigned int extended_decode_status;
+ unsigned int set_frame_tag;
+ unsigned int get_frame_tag_top;
+ unsigned int get_frame_tag_bot;
+ unsigned int pic_time_top;
+ unsigned int pic_time_bot;
+ unsigned int start_byte_num;
+ unsigned int dec_frm_size;
+ unsigned int crop_info1;
+ unsigned int crop_info2;
+ unsigned int ext_enc_control;
+ unsigned int enc_param_change;
+ unsigned int vop_timing;
+ unsigned int hec_period;
+ unsigned int P_B_frame_qp;
+ unsigned int metadata_enable;
+ unsigned int metadata_status;
+ unsigned int metadata_display_index;
+ unsigned int ext_metadata_start_addr;
+ unsigned int put_extradata;
+ unsigned int dbg_info_output0;
+ unsigned int dbg_info_output1;
+ unsigned int dbg_info_input0;
+ unsigned int dbg_info_input1;
+ unsigned int ref_l0_phy_idx;
+ unsigned int ref_l1_phy_idx;
+ unsigned int allocated_luma_dpb_size;
+ unsigned int allocated_chroma_dpb_size;
+ unsigned int allocated_mv_size;
+ unsigned int p720_limit_enable;
+};
+
+void mfc_write_shared_mem(unsigned int host_wr_addr, struct mfc_shared_mem *shared_mem);
+void mfc_read_shared_mem(unsigned int host_wr_addr, struct mfc_shared_mem *shared_mem);
+void mfc_print_shared_mem(unsigned int host_wr_addr);
+#endif