diff options
author | Brian Swetland <swetland@google.com> | 2010-11-14 20:20:42 -0800 |
---|---|---|
committer | Arve Hjønnevåg <arve@android.com> | 2011-11-16 21:48:38 -0800 |
commit | 8c7e8d2cae5cca8c2fc7a7dd983b27be648d57c0 (patch) | |
tree | e61488cfc283bf09d5ca12d7d3e896f3e05f979a /drivers/media/video/samsung | |
parent | 641e3602113012003ec9d49bde7f8d8c5e292b87 (diff) | |
download | kernel_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')
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 |