/* FIXME: add request firmware ioctl */ static long mfc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct mfc_inst_ctx *mfc_ctx; int ret, ex_ret; struct mfc_common_args in_param; struct mfc_buf_alloc_arg buf_arg; int port; struct mfc_dev *dev; int i; struct mfc_set_config_arg *set_cnf_arg; mfc_ctx = (struct mfc_inst_ctx *)file->private_data; if (!mfc_ctx) return -EINVAL; dev = mfc_ctx->dev; mutex_lock(&dev->lock); ret = copy_from_user(&in_param, (struct mfc_common_args *)arg, sizeof(struct mfc_common_args)); if (ret < 0) { mfc_err("failed to copy parameters\n"); ret = -EIO; in_param.ret_code = MFC_INVALID_PARAM_FAIL; goto out_ioctl; } mutex_unlock(&dev->lock); /* FIXME: add locking */ mfc_dbg("cmd: 0x%08x\n", cmd); switch (cmd) { case IOCTL_MFC_DEC_INIT: mutex_lock(&dev->lock); if (mfc_chk_inst_state(mfc_ctx, INST_STATE_CREATE) < 0) { mfc_err("IOCTL_MFC_DEC_INIT invalid state: 0x%08x\n", mfc_ctx->state); in_param.ret_code = MFC_STATE_INVALID; ret = -EINVAL; break; } mfc_clock_on(); in_param.ret_code = mfc_init_decoding(mfc_ctx, &(in_param.args)); ret = in_param.ret_code; mfc_clock_off(); mutex_unlock(&dev->lock); break; case IOCTL_MFC_ENC_INIT: mutex_lock(&dev->lock); if (mfc_chk_inst_state(mfc_ctx, INST_STATE_CREATE) < 0) { mfc_err("IOCTL_MFC_ENC_INIT invalid state: 0x%08x\n", mfc_ctx->state); in_param.ret_code = MFC_STATE_INVALID; ret = -EINVAL; break; } mfc_clock_on(); in_param.ret_code = mfc_init_encoding(mfc_ctx, &(in_param.args)); ret = in_param.ret_code; mfc_clock_off(); mutex_unlock(&dev->lock); break; case IOCTL_MFC_DEC_EXE: mutex_lock(&dev->lock); mfc_clock_on(); in_param.ret_code = mfc_exec_decoding(mfc_ctx, &(in_param.args)); ret = in_param.ret_code; mfc_clock_off(); mutex_unlock(&dev->lock); break; case IOCTL_MFC_ENC_EXE: mutex_lock(&dev->lock); mfc_clock_on(); in_param.ret_code = mfc_exec_encoding(mfc_ctx, &(in_param.args)); ret = in_param.ret_code; mfc_clock_off(); mutex_unlock(&dev->lock); break; case IOCTL_MFC_GET_IN_BUF: if (in_param.args.mem_alloc.type == ENCODER) { buf_arg.type = ENCODER; port = 1; } else { buf_arg.type = DECODER; port = 0; } /* FIXME: consider the size */ buf_arg.size = in_param.args.mem_alloc.buff_size; /* buf_arg.mapped = in_param.args.mem_alloc.mapped_addr; */ /* FIXME: encodeing linear: 2KB, tile: 8KB */ buf_arg.align = ALIGN_2KB; if (buf_arg.type == ENCODER) in_param.ret_code = mfc_alloc_buf(mfc_ctx, &buf_arg, MBT_DPB | port); else in_param.ret_code = mfc_alloc_buf(mfc_ctx, &buf_arg, MBT_CPB | port); #if defined(CONFIG_VIDEO_MFC_VCM_UMP) in_param.args.mem_alloc.secure_id = buf_arg.secure_id; #elif defined(CONFIG_S5P_VMEM) in_param.args.mem_alloc.cookie = buf_arg.cookie; #else in_param.args.mem_alloc.offset = buf_arg.offset; #endif ret = in_param.ret_code; break; case IOCTL_MFC_FREE_BUF: in_param.ret_code = mfc_free_buf(mfc_ctx, in_param.args.mem_free.key); ret = in_param.ret_code; break; case IOCTL_MFC_GET_REAL_ADDR: in_param.args.real_addr.addr = mfc_get_buf_real(mfc_ctx->id, in_param.args.real_addr.key); mfc_dbg("real addr: 0x%08x", in_param.args.real_addr.addr); if (in_param.args.real_addr.addr) in_param.ret_code = MFC_OK; else in_param.ret_code = MFC_MEM_INVALID_ADDR_FAIL; ret = in_param.ret_code; break; case IOCTL_MFC_GET_MMAP_SIZE: if (mfc_chk_inst_state(mfc_ctx, INST_STATE_CREATE) < 0) { mfc_err("IOCTL_MFC_GET_MMAP_SIZE invalid state: \ 0x%08x\n", mfc_ctx->state); in_param.ret_code = MFC_STATE_INVALID; ret = -EINVAL; break; } in_param.ret_code = MFC_OK; ret = 0; for (i = 0; i < dev->mem_ports; i++) ret += mfc_mem_data_size(i); break; #if defined(CONFIG_VIDEO_MFC_VCM_UMP) case IOCTL_MFC_SET_IN_BUF: if (in_param.args.mem_alloc.type == ENCODER) { buf_arg.secure_id = in_param.args.mem_alloc.secure_id; buf_arg.align = ALIGN_2KB; port = 1; ret = mfc_vcm_bind_from_others(mfc_ctx, &buf_arg, MBT_OTHER | port); } else { in_param.args.real_addr.addr = mfc_ump_get_virt(in_param.args.real_addr.key); mfc_dbg("real addr: 0x%08x", in_param.args.real_addr.addr); if (in_param.args.real_addr.addr) in_param.ret_code = MFC_OK; else in_param.ret_code = MFC_MEM_INVALID_ADDR_FAIL; ret = in_param.ret_code; } break; #endif case IOCTL_MFC_SET_CONFIG: /* FIXME: mfc_chk_inst_state*/ /* RMVME: need locking ? */ mutex_lock(&dev->lock); /* in_param.ret_code = mfc_set_config(mfc_ctx, &(in_param.args)); */ set_cnf_arg = (struct mfc_set_config_arg *)&in_param.args; in_param.ret_code = mfc_set_inst_cfg(mfc_ctx, set_cnf_arg->in_config_param, set_cnf_arg->in_config_value); ret = in_param.ret_code; mutex_unlock(&dev->lock); break; case IOCTL_MFC_GET_CONFIG: /* FIXME: */ /* FIXME: mfc_chk_inst_state */ /* RMVME: need locking ? */ in_param.ret_code = MFC_OK; ret = MFC_OK; break; case IOCTL_MFC_SET_BUF_CACHE: mfc_ctx->buf_cache_type = in_param.args.mem_alloc.buf_cache_type; in_param.ret_code = MFC_OK; break; default: mfc_err("failed to execute ioctl cmd: 0x%08x\n", cmd); in_param.ret_code = MFC_INVALID_PARAM_FAIL; ret = -EINVAL; }
/* Allocate firmware */ int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev) { #if defined(CONFIG_S5P_MFC_VB2_CMA) int err; struct cma_info mem_info_f, mem_info_a, mem_info_b; #endif unsigned int base_align = dev->variant->buf_align->mfc_base_align; unsigned int firmware_size = dev->variant->buf_size->firmware_code; mfc_debug_enter(); #if !defined(CONFIG_S5P_MFC_VB2_ION) if (s5p_mfc_bitproc_buf) { mfc_err("Attempting to allocate firmware when it seems that it is already loaded.\n"); return -ENOMEM; } #else if (s5p_mfc_bitproc_buf) return 0; #endif /* Get memory region information and check if it is correct */ #if defined(CONFIG_S5P_MFC_VB2_CMA) err = cma_info(&mem_info_f, dev->v4l2_dev.dev, MFC_CMA_FW); mfc_debug(3, "Area \"%s\" is from %08x to %08x and has size %08x", "f", mem_info_f.lower_bound, mem_info_f.upper_bound, mem_info_f.total_size); if (err) { mfc_err("Couldn't get memory information from CMA.\n"); return -EINVAL; } err = cma_info(&mem_info_a, dev->v4l2_dev.dev, MFC_CMA_BANK1); mfc_debug(3, "Area \"%s\" is from %08x to %08x and has size %08x", "a", mem_info_a.lower_bound, mem_info_a.upper_bound, mem_info_a.total_size); if (err) { mfc_err("Couldn't get memory information from CMA.\n"); return -EINVAL; } if (mem_info_f.upper_bound > mem_info_a.lower_bound) { mfc_err("Firmware has to be " "allocated before memory for buffers (bank A).\n"); return -EINVAL; } mfc_debug(2, "Allocating memory for firmware.\n"); s5p_mfc_bitproc_buf = s5p_mfc_mem_allocate( dev->alloc_ctx[MFC_CMA_FW_ALLOC_CTX], firmware_size); if (IS_ERR(s5p_mfc_bitproc_buf)) { s5p_mfc_bitproc_buf = 0; printk(KERN_ERR "Allocating bitprocessor buffer failed\n"); return -ENOMEM; } s5p_mfc_bitproc_phys = s5p_mfc_mem_dma_addr(s5p_mfc_bitproc_buf); if (s5p_mfc_bitproc_phys & ((1 << base_align) - 1)) { mfc_err("The base memory is not aligned to %dBytes.\n", (1 << base_align)); s5p_mfc_mem_free(s5p_mfc_bitproc_buf); s5p_mfc_bitproc_phys = 0; s5p_mfc_bitproc_buf = 0; return -EIO; } dev->port_a = s5p_mfc_bitproc_phys; s5p_mfc_bitproc_virt = s5p_mfc_mem_vaddr(s5p_mfc_bitproc_buf); mfc_debug(2, "Virtual address for FW: %08lx\n", (long unsigned int)s5p_mfc_bitproc_virt); if (!s5p_mfc_bitproc_virt) { mfc_err("Bitprocessor memory remap failed\n"); s5p_mfc_mem_free(s5p_mfc_bitproc_buf); s5p_mfc_bitproc_phys = 0; s5p_mfc_bitproc_buf = 0; return -EIO; } if (HAS_PORTNUM(dev) && IS_TWOPORT(dev)) { err = cma_info(&mem_info_b, dev->v4l2_dev.dev, MFC_CMA_BANK2); mfc_debug(3, "Area \"%s\" is from %08x to %08x and has size %08x", "b", mem_info_b.lower_bound, mem_info_b.upper_bound, mem_info_b.total_size); if (err) { mfc_err("Couldn't get memory information from CMA.\n"); return -EINVAL; } dev->port_b = mem_info_b.lower_bound; mfc_debug(2, "Port A: %08x Port B: %08x (FW: %08x size: %08x)\n", dev->port_a, dev->port_b, s5p_mfc_bitproc_phys, firmware_size); } else { mfc_debug(2, "Port : %08x (FW: %08x size: %08x)\n", dev->port_a, s5p_mfc_bitproc_phys, firmware_size); } #elif defined(CONFIG_S5P_MFC_VB2_SDVMM) mfc_debug(2, "Allocating memory for firmware.\n"); s5p_mfc_bitproc_buf = s5p_mfc_mem_alloc( dev->alloc_ctx[MFC_CMA_FW_ALLOC_CTX], firmware_size); if (IS_ERR(s5p_mfc_bitproc_buf)) { s5p_mfc_bitproc_buf = 0; printk(KERN_ERR "Allocating bitprocessor buffer failed\n"); return -ENOMEM; } s5p_mfc_bitproc_phys = s5p_mfc_mem_cookie( dev->alloc_ctx[MFC_CMA_FW_ALLOC_CTX], s5p_mfc_bitproc_buf); if (s5p_mfc_bitproc_phys & ((1 << base_align) - 1)) { mfc_err("The base memory is not aligned to %dBytes.\n", (1 << base_align)); s5p_mfc_mem_put(dev->alloc_ctx[MFC_CMA_FW_ALLOC_CTX], s5p_mfc_bitproc_buf); s5p_mfc_bitproc_phys = 0; s5p_mfc_bitproc_buf = 0; return -EIO; } s5p_mfc_bitproc_virt = s5p_mfc_mem_vaddr( dev->alloc_ctx[MFC_CMA_FW_ALLOC_CTX], s5p_mfc_bitproc_buf); mfc_debug(2, "Virtual address for FW: %08lx\n", (long unsigned int)s5p_mfc_bitproc_virt); if (!s5p_mfc_bitproc_virt) { mfc_err("Bitprocessor memory remap failed\n"); s5p_mfc_mem_put(dev->alloc_ctx[MFC_CMA_FW_ALLOC_CTX], s5p_mfc_bitproc_buf); s5p_mfc_bitproc_phys = 0; s5p_mfc_bitproc_buf = 0; return -EIO; } dev->port_a = s5p_mfc_bitproc_phys; dev->port_b = s5p_mfc_bitproc_phys; mfc_debug(2, "Port A: %08x Port B: %08x (FW: %08x size: %08x)\n", dev->port_a, dev->port_b, s5p_mfc_bitproc_phys, firmware_size); #elif defined(CONFIG_S5P_MFC_VB2_ION) mfc_debug(2, "Allocating memory for firmware.\n"); s5p_mfc_bitproc_buf = s5p_mfc_mem_allocate( dev->alloc_ctx[MFC_CMA_FW_ALLOC_CTX], firmware_size); if (IS_ERR(s5p_mfc_bitproc_buf)) { s5p_mfc_bitproc_buf = 0; printk(KERN_ERR "Allocating bitprocessor buffer failed\n"); return -ENOMEM; } s5p_mfc_bitproc_phys = s5p_mfc_mem_dma_addr(s5p_mfc_bitproc_buf); if (s5p_mfc_bitproc_phys & ((1 << base_align) - 1)) { mfc_err("The base memory is not aligned to %dBytes.\n", (1 << base_align)); s5p_mfc_mem_free(s5p_mfc_bitproc_buf); s5p_mfc_bitproc_phys = 0; s5p_mfc_bitproc_buf = 0; return -EIO; } s5p_mfc_bitproc_virt = s5p_mfc_mem_vaddr(s5p_mfc_bitproc_buf); mfc_debug(2, "Virtual address for FW: %08lx\n", (long unsigned int)s5p_mfc_bitproc_virt); if (!s5p_mfc_bitproc_virt) { mfc_err("Bitprocessor memory remap failed\n"); s5p_mfc_mem_free(s5p_mfc_bitproc_buf); s5p_mfc_bitproc_phys = 0; s5p_mfc_bitproc_buf = 0; return -EIO; } dev->port_a = s5p_mfc_bitproc_phys; dev->port_b = s5p_mfc_bitproc_phys; mfc_debug(2, "Port A: %08x Port B: %08x (FW: %08x size: %08x)\n", dev->port_a, dev->port_b, s5p_mfc_bitproc_phys, firmware_size); #endif mfc_debug_leave(); return 0; }
int s5p_mfc_wakeup(struct s5p_mfc_dev *dev) { int ret; mfc_debug_enter(); /* 0. MFC reset */ mfc_debug(2, "MFC reset...\n"); s5p_mfc_clock_on(); ret = s5p_mfc_reset(dev); if (ret) { mfc_err("Failed to reset MFC - timeout.\n"); goto err_mfc_wakeup; } mfc_debug(2, "Done MFC reset...\n"); /* 1. Set DRAM base Addr */ s5p_mfc_init_memctrl(dev); /* 2. Initialize registers of channel I/F */ s5p_mfc_clear_cmds(dev); s5p_mfc_clean_dev_int_flags(dev); /* 3. Initialize firmware */ ret = s5p_mfc_wakeup_cmd(dev); if (ret) { mfc_err("Failed to send command to MFC - timeout.\n"); goto err_mfc_wakeup; } /* 4. Release reset signal to the RISC */ if (IS_MFCV6(dev)) s5p_mfc_write_reg(0x1, S5P_FIMV_RISC_ON); else s5p_mfc_write_reg(0x3ff, S5P_FIMV_SW_RESET); mfc_debug(2, "Ok, now will write a command to wakeup the system\n"); if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_WAKEUP_RET)) { mfc_err("Failed to load firmware\n"); ret = -EIO; goto err_mfc_wakeup; } dev->int_cond = 0; if (dev->int_err != 0 || dev->int_type != S5P_FIMV_R2H_CMD_WAKEUP_RET) { /* Failure. */ mfc_err("Failed to wakeup - error: %d" " int: %d.\n",dev->int_err, dev->int_type); ret = -EIO; goto err_mfc_wakeup; } err_mfc_wakeup: s5p_mfc_clock_off(); mfc_debug_leave(); return 0; }
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((unsigned int)mfc_mem, size); err_mem_req: probe_out: dev_err(&pdev->dev, "not found (%d).\n", ret); return ret; }
static int mfc_open(struct inode *inode, struct file *file) { struct mfc_inst_ctx *mfc_ctx; int ret; enum mfc_ret_code retcode; int inst_id; #ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION struct mfc_alloc_buffer *alloc; #endif /* prevent invalid reference */ file->private_data = NULL; mutex_lock(&mfcdev->lock); #ifdef CONFIG_USE_MFC_CMA if (atomic_read(&mfcdev->inst_cnt) == 0) { #if defined(CONFIG_MACH_M0) || defined(CONFIG_MACH_GC1) size_t size = 0x02800000; mfcdev->cma_vaddr = dma_alloc_coherent(mfcdev->device, size, &mfcdev->cma_dma_addr, 0); if (!mfcdev->cma_vaddr) { printk(KERN_ERR "%s: dma_alloc_coherent returns " "-ENOMEM\n", __func__); mutex_unlock(&mfcdev->lock); return -ENOMEM; } printk(KERN_INFO "%s[%d] size 0x%x, vaddr 0x%x, base 0x%x\n", __func__, __LINE__, (int)size, (int)mfcdev->cma_vaddr, (int)mfcdev->cma_dma_addr); #endif } #endif #if SUPPORT_SLICE_ENCODING mfcdev->frame_working_flag = 1; mfcdev->frame_sys = 0; #endif if (!mfcdev->fw.state) { if (mfcdev->fw.requesting) { printk(KERN_INFO "MFC F/W request is on-going, try again\n"); ret = -ENODEV; goto err_fw_state; } printk(KERN_INFO "MFC F/W is not existing, requesting...\n"); ret = request_firmware(&mfcdev->fw.info, MFC_FW_NAME, mfcdev->device); if (ret < 0) { printk(KERN_INFO "failed to copy MFC F/W during open\n"); ret = -ENODEV; goto err_fw_state; } if (soc_is_exynos4212() || soc_is_exynos4412()) { mfcdev->fw.state = mfc_load_firmware(mfcdev->fw.info->data, mfcdev->fw.info->size); if (!mfcdev->fw.state) { printk(KERN_ERR "failed to load MFC F/W, MFC will not working\n"); ret = -ENODEV; goto err_fw_state; } else { printk(KERN_INFO "MFC F/W loaded successfully (size: %d)\n", mfcdev->fw.info->size); } } } if (atomic_read(&mfcdev->inst_cnt) == 0) { /* reload F/W for first instance again */ if (soc_is_exynos4210()) { mfcdev->fw.state = mfc_load_firmware(mfcdev->fw.info->data, mfcdev->fw.info->size); if (!mfcdev->fw.state) { printk(KERN_ERR "failed to reload MFC F/W, MFC will not working\n"); ret = -ENODEV; goto err_fw_state; } else { printk(KERN_INFO "MFC F/W reloaded successfully (size: %d)\n", mfcdev->fw.info->size); } } #if defined(CONFIG_BUSFREQ_OPP) || defined(CONFIG_BUSFREQ_LOCK_WRAPPER) dev_lock(mfcdev->bus_dev, mfcdev->device, 133133); #endif #ifdef CONFIG_BUSFREQ pm_qos_add_request(&bus_qos_pm_qos_req, PM_QOS_BUS_QOS, 1); #endif ret = mfc_power_on(); if (ret < 0) { mfc_err("power enable failed\n"); goto err_pwr_enable; } #ifndef CONFIG_PM_RUNTIME #ifdef SYSMMU_MFC_ON mfc_clock_on(mfcdev); s5p_sysmmu_enable(mfcdev->device); #ifdef CONFIG_VIDEO_MFC_VCM_UMP vcm_set_pgtable_base(VCM_DEV_MFC); #else /* CONFIG_S5P_VMEM or kernel virtual memory allocator */ s5p_sysmmu_set_tablebase_pgd(mfcdev->device, __pa(swapper_pg_dir)); /* * RMVME: the power-gating work really (on <-> off), * all TBL entry was invalidated already when the power off */ s5p_sysmmu_tlb_invalidate(mfcdev->device, SYSMMU_MFC_R); #endif mfc_clock_off(mfcdev); #endif #endif /* MFC hardware initialization */ retcode = mfc_start(mfcdev); if (retcode != MFC_OK) { mfc_err("MFC H/W init failed: %d\n", retcode); ret = -ENODEV; goto err_start_hw; } } if (atomic_read(&mfcdev->inst_cnt) >= MFC_MAX_INSTANCE_NUM) { mfc_err("exceed max instance number, too many instance opened already\n"); ret = -EINVAL; goto err_inst_cnt; } inst_id = get_free_inst_id(mfcdev); if (inst_id < 0) { mfc_err("failed to get instance ID\n"); ret = -EINVAL; goto err_inst_id; } mfc_ctx = mfc_create_inst(); if (!mfc_ctx) { mfc_err("failed to create instance context\n"); ret = -ENOMEM; goto err_inst_ctx; } atomic_inc(&mfcdev->inst_cnt); mfcdev->inst_ctx[inst_id] = mfc_ctx; #ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION if (check_magic(mfcdev->drm_info.addr) >= 0) { mfc_info("DRM instance starting\n"); clear_magic(mfcdev->drm_info.addr + check_magic(mfcdev->drm_info.addr)); mfc_ctx->drm_flag = 1; mfc_set_buf_alloc_scheme(MBS_FIRST_FIT); } else { mfc_ctx->drm_flag = 0; } #endif mfc_ctx->id = inst_id; mfc_ctx->dev = mfcdev; #ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION if (mfc_ctx->drm_flag) { alloc = _mfc_alloc_buf(mfc_ctx, MFC_CTX_SIZE_L, ALIGN_2KB, MBT_CTX | PORT_A); if (alloc == NULL) { mfc_err("failed to alloc context buffer\n"); ret = -ENOMEM; goto err_drm_ctx; } mfc_ctx->ctxbufofs = mfc_mem_base_ofs(alloc->real) >> 11; mfc_ctx->ctxbufsize = alloc->size; memset((void *)alloc->addr, 0, alloc->size); mfc_mem_cache_clean((void *)alloc->addr, alloc->size); }
/* Initialize hardware */ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) { unsigned int ver; int ret; mfc_debug_enter(); if (!dev->fw_virt_addr) { mfc_err("Firmware memory is not allocated.\n"); return -EINVAL; } /* 0. MFC reset */ mfc_debug(2, "MFC reset..\n"); s5p_mfc_clock_on(); ret = s5p_mfc_reset(dev); if (ret) { mfc_err("Failed to reset MFC - timeout\n"); return ret; } mfc_debug(2, "Done MFC reset..\n"); /* 1. Set DRAM base Addr */ s5p_mfc_init_memctrl(dev); /* 2. Initialize registers of channel I/F */ s5p_mfc_clear_cmds(dev); /* 3. Release reset signal to the RISC */ s5p_mfc_clean_dev_int_flags(dev); if (IS_MFCV6_PLUS(dev)) mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6); else mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET); mfc_debug(2, "Will now wait for completion of firmware transfer\n"); if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_FW_STATUS_RET)) { mfc_err("Failed to load firmware\n"); s5p_mfc_reset(dev); s5p_mfc_clock_off(); return -EIO; } s5p_mfc_clean_dev_int_flags(dev); /* 4. Initialize firmware */ ret = s5p_mfc_hw_call(dev->mfc_cmds, sys_init_cmd, dev); if (ret) { mfc_err("Failed to send command to MFC - timeout\n"); s5p_mfc_reset(dev); s5p_mfc_clock_off(); return ret; } mfc_debug(2, "Ok, now will wait for completion of hardware init\n"); if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_SYS_INIT_RET)) { mfc_err("Failed to init hardware\n"); s5p_mfc_reset(dev); s5p_mfc_clock_off(); return -EIO; } dev->int_cond = 0; if (dev->int_err != 0 || dev->int_type != S5P_MFC_R2H_CMD_SYS_INIT_RET) { /* Failure. */ mfc_err("Failed to init firmware - error: %d int: %d\n", dev->int_err, dev->int_type); s5p_mfc_reset(dev); s5p_mfc_clock_off(); return -EIO; } if (IS_MFCV6_PLUS(dev)) ver = mfc_read(dev, S5P_FIMV_FW_VERSION_V6); else ver = mfc_read(dev, S5P_FIMV_FW_VERSION); mfc_debug(2, "MFC F/W version : %02xyy, %02xmm, %02xdd\n", (ver >> 16) & 0xFF, (ver >> 8) & 0xFF, ver & 0xFF); s5p_mfc_clock_off(); mfc_debug_leave(); return 0; }
/* Reqeust buffers */ static int vidioc_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *reqbufs) { struct s5p_mfc_dev *dev = video_drvdata(file); struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); int ret = 0; unsigned long flags; if (reqbufs->memory != V4L2_MEMORY_MMAP) { mfc_err("Only V4L2_MEMORY_MAP is supported\n"); return -EINVAL; } if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { /* Can only request buffers after an instance has been opened.*/ if (ctx->state == MFCINST_INIT) { ctx->src_bufs_cnt = 0; if (reqbufs->count == 0) { mfc_debug(2, "Freeing buffers\n"); s5p_mfc_clock_on(); ret = vb2_reqbufs(&ctx->vq_src, reqbufs); s5p_mfc_clock_off(); return ret; } /* Decoding */ if (ctx->output_state != QUEUE_FREE) { mfc_err("Bufs have already been requested\n"); return -EINVAL; } s5p_mfc_clock_on(); ret = vb2_reqbufs(&ctx->vq_src, reqbufs); s5p_mfc_clock_off(); if (ret) { mfc_err("vb2_reqbufs on output failed\n"); return ret; } mfc_debug(2, "vb2_reqbufs: %d\n", ret); ctx->output_state = QUEUE_BUFS_REQUESTED; } } else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { ctx->dst_bufs_cnt = 0; if (reqbufs->count == 0) { mfc_debug(2, "Freeing buffers\n"); s5p_mfc_clock_on(); ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); s5p_mfc_clock_off(); return ret; } if (ctx->capture_state != QUEUE_FREE) { mfc_err("Bufs have already been requested\n"); return -EINVAL; } ctx->capture_state = QUEUE_BUFS_REQUESTED; s5p_mfc_clock_on(); ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); s5p_mfc_clock_off(); if (ret) { mfc_err("vb2_reqbufs on capture failed\n"); return ret; } if (reqbufs->count < ctx->dpb_count) { mfc_err("Not enough buffers allocated\n"); reqbufs->count = 0; s5p_mfc_clock_on(); ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); s5p_mfc_clock_off(); return -ENOMEM; } ctx->total_dpb_count = reqbufs->count; ret = s5p_mfc_alloc_codec_buffers(ctx); if (ret) { mfc_err("Failed to allocate decoding buffers\n"); reqbufs->count = 0; s5p_mfc_clock_on(); ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); s5p_mfc_clock_off(); return -ENOMEM; } if (ctx->dst_bufs_cnt == ctx->total_dpb_count) { ctx->capture_state = QUEUE_BUFS_MMAPED; } else { mfc_err("Not all buffers passed to buf_init\n"); reqbufs->count = 0; s5p_mfc_clock_on(); ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); s5p_mfc_release_codec_buffers(ctx); s5p_mfc_clock_off(); return -ENOMEM; } if (s5p_mfc_ctx_ready(ctx)) { spin_lock_irqsave(&dev->condlock, flags); set_bit(ctx->num, &dev->ctx_work_bits); spin_unlock_irqrestore(&dev->condlock, flags); } s5p_mfc_try_run(dev); s5p_mfc_wait_for_done_ctx(ctx, S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET, 0); } 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; mfc_inst_ctx *mfc_ctx; #if ENABLE_MONITORING_MFC_DD mfc_info("MFC mfc_mmap..dev_id(%d)\n",S5P_MDEV_MFC); #endif 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 = (mfc_inst_ctx *)filp->private_data; firmware_size = mfc_get_port0_buff_paddr() - mfc_get_fw_buff_paddr(); phy_size = (unsigned long)(s5p_get_media_memory_bank(S5P_MDEV_MFC, 0) - firmware_size + s5p_get_media_memory_bank(S5P_MDEV_MFC, 1)); /* 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 int mfc_probe(struct platform_device *pdev) { struct resource *res; size_t size; int ret; #if ENABLE_MONITORING_MFC_DD mfc_info("MFC mfc_probe..dev_id(%d)\n",S5P_MDEV_MFC); #endif /* 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 probe_out; } 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 probe_out; } res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (res == NULL) { dev_err(&pdev->dev, "failed to get irq resource\n"); ret = -ENOENT; goto probe_out; } #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 probe_out; } #endif mutex_init(&mfc_mutex); /* * buffer memory secure */ mfc_port0_base_paddr = s5p_get_media_memory_bank(S5P_MDEV_MFC, 0); 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 probe_out; } mfc_port1_base_paddr = s5p_get_media_memory_bank(S5P_MDEV_MFC, 1); 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 probe_out; } // 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); /* * MFC FW downloading */ if (mfc_load_firmware() < 0) { mfc_err("MFCINST_ERR_FW_INIT_FAIL\n"); ret = -EPERM; goto probe_out; } mfc_init_mem_inst_no(); mfc_init_buffer(); mfc_clk = clk_get(&pdev->dev, "mfc"); if (mfc_clk == NULL) { printk(KERN_ERR "failed to find mfc clock source\n"); return -ENOENT; } ret = misc_register(&mfc_miscdev); return 0; probe_out: dev_err(&pdev->dev, "not found (%d). \n", ret); return ret; }
static int mfc_release(struct inode *inode, struct file *file) { mfc_inst_ctx *mfc_ctx; int ret; #if ENABLE_MONITORING_MFC_DD mfc_info("MFC Release..\n"); #endif mutex_lock(&mfc_mutex); #if Frame_Base_Power_CTR_ON /*if (s5pv210_pd_enable("mfc_pd") < 0) { printk(KERN_ERR "[Error]The power is not on for mfc\n"); return -1; }*/ clk_enable(mfc_clk); #endif mfc_ctx = (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) mfc_return_inst_no(mfc_ctx->InstNo, mfc_ctx->MfcCodecType); kfree(mfc_ctx); ret = 0; out_release: if (!mfc_is_running()) { #ifdef CONFIG_CPU_FREQ_S5PV210 s5pv210_set_cpufreq_level(NORMAL_TABLE); #endif /* CONFIG_CPU_FREQ_S5PV210 */ #ifdef CONFIG_PM_PWR_GATING s5pc110_unlock_power_domain(MFC_DOMAIN_LOCK_TOKEN); #endif #ifdef CONFIG_S5P_LPAUDIO s5p_set_lpaudio_lock(0); #endif /* CONFIG_S5P_LPAUDIO */ } clk_disable(mfc_clk); if (s5pv210_pd_disable("mfc_pd") < 0) { printk(KERN_ERR "[Error]The power is not off for mfc\n"); return -1; } mutex_unlock(&mfc_mutex); return ret; }
static int mfc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int ret, ex_ret; mfc_inst_ctx *mfc_ctx = NULL; mfc_common_args in_param; mutex_lock(&mfc_mutex); #if Frame_Base_Power_CTR_ON if (s5pv210_pd_enable("mfc_pd") < 0) { printk(KERN_ERR "[Error]The power is not on for mfc\n"); return -1; } clk_enable(mfc_clk); #endif ret = copy_from_user(&in_param, (mfc_common_args *)arg, sizeof(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 = (mfc_inst_ctx *)file->private_data; mutex_unlock(&mfc_mutex); switch (cmd) { case IOCTL_MFC_ENC_INIT: mutex_lock(&mfc_mutex); #if ENABLE_MONITORING_MFC_DD mfc_info("IOCTL_MFC_ENC_INIT\n"); #endif 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 ENABLE_MONITORING_MFC_DD mfc_info("IOCTL_MFC_ENC_EXE\n"); #endif 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 ENABLE_MONITORING_MFC_DD mfc_info("IOCTL_MFC_DEC_INIT\n"); #endif 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) { mfc_err("MFC_DEC_INIT ERROR ............. ret(%d)\n",in_param.ret_code); 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 ENABLE_MONITORING_MFC_DD mfc_debug_L0("IOCTL_MFC_DEC_EXE\n"); #endif 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 ENABLE_MONITORING_MFC_DD mfc_info("IOCTL_MFC_GET_CONFIG\n"); #endif 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); #if ENABLE_MONITORING_MFC_DD mfc_info("IOCTL_MFC_SET_CONFIG\n"); #endif 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 ENABLE_MONITORING_MFC_DD mfc_info("IOCTL_MFC_GET_IN_BUF\n"); #endif 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 ENABLE_MONITORING_MFC_DD mfc_info("IOCTL_MFC_FREE_BUF\n"); #endif 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; 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: #if Frame_Base_Power_CTR_ON clk_disable(mfc_clk); if (s5pv210_pd_disable("mfc_pd") < 0) { printk(KERN_ERR "[Error]The power is not off for mfc\n"); return -1; } #endif ex_ret = copy_to_user((mfc_common_args *)arg, &in_param, sizeof(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; }
/* FIXME: check every exception case (goto) */ static int __devinit mfc_probe(struct platform_device *pdev) { struct resource *res; int ret; mfcdev = kzalloc(sizeof(struct mfc_dev), GFP_KERNEL); if (unlikely(mfcdev == NULL)) { dev_err(&pdev->dev, "failed to allocate control memory\n"); return -ENOMEM; } /* init. control structure */ sprintf(mfcdev->name, "%s", MFC_DEV_NAME); mutex_init(&mfcdev->lock); init_waitqueue_head(&mfcdev->wait_sys); init_waitqueue_head(&mfcdev->wait_codec[0]); init_waitqueue_head(&mfcdev->wait_codec[1]); atomic_set(&mfcdev->inst_cnt, 0); atomic_set(&mfcdev->busfreq_lock_cnt, 0); mfcdev->device = &pdev->dev; platform_set_drvdata(pdev, mfcdev); /* get the memory region */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (unlikely(res == NULL)) { dev_err(&pdev->dev, "no memory resource specified\n"); ret = -ENOENT; goto err_mem_res; } mfcdev->reg.rsrc_start = res->start; mfcdev->reg.rsrc_len = resource_size(res); /* request mem region for MFC register (0x0000 ~ 0xE008) */ res = request_mem_region(mfcdev->reg.rsrc_start, mfcdev->reg.rsrc_len, pdev->name); if (unlikely(res == NULL)) { dev_err(&pdev->dev, "failed to get memory region\n"); ret = -ENOENT; goto err_mem_req; } /* ioremap for MFC register */ mfcdev->reg.base = ioremap(mfcdev->reg.rsrc_start, mfcdev->reg.rsrc_len); if (unlikely(!mfcdev->reg.base)) { dev_err(&pdev->dev, "failed to ioremap memory region\n"); ret = -EINVAL; goto err_mem_map; } init_reg(mfcdev->reg.base); mfcdev->irq = platform_get_irq(pdev, 0); if (unlikely(mfcdev->irq < 0)) { dev_err(&pdev->dev, "no irq resource specified\n"); ret = -ENOENT; goto err_irq_res; } ret = request_irq(mfcdev->irq, mfc_irq, IRQF_DISABLED, mfcdev->name, mfcdev); if (ret) { dev_err(&pdev->dev, "failed to allocate irq (%d)\n", ret); goto err_irq_req; } /* * initialize PM(power, clock) interface */ ret = mfc_init_pm(mfcdev); if (ret < 0) { printk(KERN_ERR "failed to init. MFC PM interface\n"); goto err_pm_if; } /* * initialize memory manager */ ret = mfc_init_mem_mgr(mfcdev); if (ret < 0) { printk(KERN_ERR "failed to init. MFC memory manager\n"); goto err_mem_mgr; } /* * loading firmware */ ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, MFC_FW_NAME, &pdev->dev, GFP_KERNEL, pdev, mfc_firmware_request_complete_handler); if (ret) { dev_err(&pdev->dev, "could not load firmware (err=%d)\n", ret); goto err_fw_req; } #if defined(SYSMMU_MFC_ON) && defined(CONFIG_VIDEO_MFC_VCM_UMP) ret = vcm_activate(mfcdev->vcm_info.sysmmu_vcm); if (ret < 0) { mfc_err("failed to activate VCM: %d", ret); goto err_act_vcm; } #endif /* * initialize buffer manager */ mfc_init_buf(); /* FIXME: final dec & enc */ mfc_init_decoders(); mfc_init_encoders(); ret = misc_register(&mfc_miscdev); if (ret) { mfc_err("MFC can't misc register on minor=%d\n", MFC_MINOR); goto err_misc_reg; } mfc_info("MFC(Multi Function Codec - FIMV v5.x) registered successfully\n"); return 0; err_misc_reg: mfc_final_buf(); #ifdef SYSMMU_MFC_ON #ifdef CONFIG_VIDEO_MFC_VCM_UMP mfc_clock_on(); vcm_deactivate(mfcdev->vcm_info.sysmmu_vcm); mfc_clock_off(); err_act_vcm: #endif mfc_clock_on(); sysmmu_off(SYSMMU_MFC_L); sysmmu_off(SYSMMU_MFC_R); mfc_clock_off(); #endif if (mfcdev->fw.info) release_firmware(mfcdev->fw.info); err_fw_req: /* FIXME: make kenel dump when probe fail */ mfc_clock_on(); mfc_final_mem_mgr(mfcdev); mfc_clock_off(); err_mem_mgr: mfc_final_pm(mfcdev); err_pm_if: free_irq(mfcdev->irq, mfcdev); err_irq_req: err_irq_res: iounmap(mfcdev->reg.base); err_mem_map: release_mem_region(mfcdev->reg.rsrc_start, mfcdev->reg.rsrc_len); err_mem_req: err_mem_res: platform_set_drvdata(pdev, NULL); mutex_destroy(&mfcdev->lock); kfree(mfcdev); return ret; }
static int mfc_open(struct inode *inode, struct file *file) { struct mfc_inst_ctx *mfc_ctx; int ret; enum mfc_ret_code retcode; /* prevent invalid reference */ file->private_data = NULL; mutex_lock(&mfcdev->lock); if (atomic_read(&mfcdev->inst_cnt) == 0) { /* reload F/W for first instance again */ mfcdev->fw.state = mfc_load_firmware(mfcdev->fw.info->data, mfcdev->fw.info->size); if (!mfcdev->fw.state) { mfc_err("MFC F/W not load yet\n"); ret = -ENODEV; goto err_fw_state; } printk(KERN_INFO "MFC F/W reloaded for first Instance successfully (size: %d)\n", mfcdev->fw.info->size); ret = mfc_power_on(); if (ret < 0) { mfc_err("power enable failed\n"); goto err_pwr_enable; } #ifndef CONFIG_PM_RUNTIME #ifdef SYSMMU_MFC_ON mfc_clock_on(); sysmmu_on(SYSMMU_MFC_L); sysmmu_on(SYSMMU_MFC_R); #ifdef CONFIG_VIDEO_MFC_VCM_UMP vcm_set_pgtable_base(VCM_DEV_MFC); #else /* CONFIG_S5P_VMEM or kernel virtual memory allocator */ sysmmu_set_tablebase_pgd(SYSMMU_MFC_L, __pa(swapper_pg_dir)); sysmmu_set_tablebase_pgd(SYSMMU_MFC_R, __pa(swapper_pg_dir)); /* * RMVME: the power-gating work really (on <-> off), * all TBL entry was invalidated already when the power off */ sysmmu_tlb_invalidate(SYSMMU_MFC_L); sysmmu_tlb_invalidate(SYSMMU_MFC_R); #endif mfc_clock_off(); #endif #endif /* MFC hardware initialization */ retcode = mfc_start(mfcdev); if (retcode != MFC_OK) { mfc_err("MFC H/W init failed: %d\n", retcode); ret = -ENODEV; goto err_start_hw; } } mfc_ctx = mfc_create_inst(); if (!mfc_ctx) { mfc_err("failed to create instance context\n"); ret = -ENOMEM; goto err_inst_ctx; } mfc_ctx->id = get_free_inst_id(mfcdev); if (mfc_ctx->id < 0) { ret = -EINVAL; goto err_inst_ctx; } printk(KERN_INFO"[%s]Opened Instance id %d \n",__func__,mfc_ctx->id); mfc_ctx->dev = mfcdev; atomic_inc(&mfcdev->inst_cnt); mfcdev->inst_ctx[mfc_ctx->id] = mfc_ctx; file->private_data = (struct mfc_inst_ctx *)mfc_ctx; mutex_unlock(&mfcdev->lock); return 0; err_inst_ctx: err_start_hw: if (atomic_read(&mfcdev->inst_cnt) == 0) { if (mfc_power_off() < 0) mfc_err("power disable failed\n"); } err_pwr_enable: err_fw_state: mutex_unlock(&mfcdev->lock); return ret; }
static int mfc_mmap(struct file *file, struct vm_area_struct *vma) { unsigned long user_size = vma->vm_end - vma->vm_start; unsigned long real_size; struct mfc_inst_ctx *mfc_ctx; #if !(defined(CONFIG_VIDEO_MFC_VCM_UMP) || defined(CONFIG_S5P_VMEM)) /* mmap support */ unsigned long pfn; unsigned long remap_offset, remap_size; struct mfc_dev *dev; #ifdef SYSMMU_MFC_ON /* kernel virtual memory allocator */ char *ptr; unsigned long start, size; #endif #endif mfc_ctx = (struct mfc_inst_ctx *)file->private_data; if (!mfc_ctx) return -EINVAL; #if !(defined(CONFIG_VIDEO_MFC_VCM_UMP) || defined(CONFIG_S5P_VMEM)) dev = mfc_ctx->dev; #endif mfc_dbg("vm_start: 0x%08lx, vm_end: 0x%08lx, size: %ld(%ldMB)\n", vma->vm_start, vma->vm_end, user_size, (user_size >> 20)); real_size = (unsigned long)(mfc_mem_data_size(0) + mfc_mem_data_size(1)); mfc_dbg("port 0 size: %d, port 1 size: %d, total: %ld\n", mfc_mem_data_size(0), mfc_mem_data_size(1), real_size); /* * if memory size required from appl. mmap() is bigger than max data memory * size allocated in the driver. */ if (user_size > real_size) { mfc_err("user requeste mem(%ld) is bigger than available mem(%ld)\n", user_size, real_size); return -EINVAL; } #ifdef SYSMMU_MFC_ON #if (defined(CONFIG_VIDEO_MFC_VCM_UMP) || defined(CONFIG_S5P_VMEM)) vma->vm_flags |= VM_RESERVED | VM_IO; vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); vma->vm_ops = &mfc_vm_ops; vma->vm_private_data = mfc_ctx; mfc_ctx->userbase = vma->vm_start; #else /* not CONFIG_VIDEO_MFC_VCM_UMP && not CONFIG_S5P_VMEM */ /* kernel virtual memory allocator */ if (dev->mem_ports == 1) { remap_offset = 0; remap_size = user_size; vma->vm_flags |= VM_RESERVED | VM_IO; vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); /* * Port 0 mapping for stream buf & frame buf (chroma + MV + luma) */ ptr = (char *)mfc_mem_data_base(0); start = remap_offset; size = remap_size; while (size > 0) { pfn = vmalloc_to_pfn(ptr); if (remap_pfn_range(vma, vma->vm_start + start, pfn, PAGE_SIZE, vma->vm_page_prot)) { mfc_err("failed to remap port 0\n"); return -EAGAIN; } start += PAGE_SIZE; ptr += PAGE_SIZE; size -= PAGE_SIZE; } } else { remap_offset = 0; remap_size = min((unsigned long)mfc_mem_data_size(0), user_size); vma->vm_flags |= VM_RESERVED | VM_IO; vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); /* * Port 0 mapping for stream buf & frame buf (chroma + MV) */ ptr = (char *)mfc_mem_data_base(0); start = remap_offset; size = remap_size; while (size > 0) { pfn = vmalloc_to_pfn(ptr); if (remap_pfn_range(vma, vma->vm_start + start, pfn, PAGE_SIZE, vma->vm_page_prot)) { mfc_err("failed to remap port 0\n"); return -EAGAIN; } start += PAGE_SIZE; ptr += PAGE_SIZE; size -= PAGE_SIZE; } remap_offset = remap_size; remap_size = min((unsigned long)mfc_mem_data_size(1), user_size - remap_offset); vma->vm_flags |= VM_RESERVED | VM_IO; vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); /* * Port 1 mapping for frame buf (luma) */ ptr = (void *)mfc_mem_data_base(1); start = remap_offset; size = remap_size; while (size > 0) { pfn = vmalloc_to_pfn(ptr); if (remap_pfn_range(vma, vma->vm_start + start, pfn, PAGE_SIZE, vma->vm_page_prot)) { mfc_err("failed to remap port 1\n"); return -EAGAIN; } start += PAGE_SIZE; ptr += PAGE_SIZE; size -= PAGE_SIZE; } } mfc_ctx->userbase = vma->vm_start; mfc_dbg("user request mem = %ld, available data mem = %ld\n", user_size, real_size); if ((remap_offset + remap_size) < real_size) mfc_warn("The MFC reserved memory dose not mmap fully [%ld: %ld]\n", real_size, (remap_offset + remap_size)); #endif /* end of CONFIG_VIDEO_MFC_VCM_UMP */ #else /* not SYSMMU_MFC_ON */ /* early allocator */ /* CMA or bootmem(memblock) */ if (dev->mem_ports == 1) { remap_offset = 0; remap_size = user_size; vma->vm_flags |= VM_RESERVED | VM_IO; if(mfc_ctx->buf_cache_type == NO_CACHE){ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); mfc_info("CONFIG_VIDEO_MFC_CACHE is not enabled\n"); }else mfc_info("CONFIG_VIDEO_MFC_CACHE is enabled\n"); /* * Port 0 mapping for stream buf & frame buf (chroma + MV + luma) */ pfn = __phys_to_pfn(mfc_mem_data_base(0)); if (remap_pfn_range(vma, vma->vm_start + remap_offset, pfn, remap_size, vma->vm_page_prot)) { mfc_err("failed to remap port 0\n"); return -EINVAL; } } else { remap_offset = 0; remap_size = min((unsigned long)mfc_mem_data_size(0), user_size); vma->vm_flags |= VM_RESERVED | VM_IO; if(mfc_ctx->buf_cache_type == NO_CACHE){ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); mfc_info("CONFIG_VIDEO_MFC_CACHE is not enabled\n"); }else mfc_info("CONFIG_VIDEO_MFC_CACHE is enabled\n"); /* * Port 0 mapping for stream buf & frame buf (chroma + MV) */ pfn = __phys_to_pfn(mfc_mem_data_base(0)); if (remap_pfn_range(vma, vma->vm_start + remap_offset, pfn, remap_size, vma->vm_page_prot)) { mfc_err("failed to remap port 0\n"); return -EINVAL; } remap_offset = remap_size; remap_size = min((unsigned long)mfc_mem_data_size(1), user_size - remap_offset); vma->vm_flags |= VM_RESERVED | VM_IO; if(mfc_ctx->buf_cache_type == NO_CACHE) vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); /* * Port 1 mapping for frame buf (luma) */ pfn = __phys_to_pfn(mfc_mem_data_base(1)); if (remap_pfn_range(vma, vma->vm_start + remap_offset, pfn, remap_size, vma->vm_page_prot)) { mfc_err("failed to remap port 1\n"); return -EINVAL; } } mfc_ctx->userbase = vma->vm_start; mfc_dbg("user request mem = %ld, available data mem = %ld\n", user_size, real_size); if ((remap_offset + remap_size) < real_size) mfc_warn("The MFC reserved memory dose not mmap fully [%ld: %ld]\n", real_size, (remap_offset + remap_size)); #endif /* end of SYSMMU_MFC_ON */ return 0; }
int s5p_mfc_sleep(struct s5p_mfc_dev *dev) { struct s5p_mfc_ctx *ctx; int ret; int old_state; mfc_debug_enter(); if (!dev) { mfc_err("no mfc device to run\n"); return -EINVAL; } ctx = dev->ctx[dev->curr_ctx]; if (!ctx) { mfc_err("no mfc context to run\n"); return -EINVAL; } old_state = ctx->state; ctx->state = MFCINST_ABORT; ret = wait_event_interruptible_timeout(ctx->queue, (test_bit(ctx->num, &dev->hw_lock) == 0), msecs_to_jiffies(MFC_INT_TIMEOUT)); if (ret == 0) { mfc_err_dev("Waiting for hardware to finish timed out\n"); ret = -EIO; return ret; } spin_lock_irq(&dev->condlock); mfc_info_dev("curr_ctx_drm:%d, hw_lock:%lu\n", dev->curr_ctx_drm, dev->hw_lock); set_bit(ctx->num, &dev->hw_lock); spin_unlock_irq(&dev->condlock); ctx->state = old_state; s5p_mfc_clock_on(dev); s5p_mfc_clean_dev_int_flags(dev); ret = s5p_mfc_sleep_cmd(dev); if (ret) { mfc_err_dev("Failed to send command to MFC - timeout.\n"); goto err_mfc_sleep; } if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_SLEEP_RET)) { mfc_err_dev("Failed to sleep\n"); ret = -EIO; goto err_mfc_sleep; } dev->int_cond = 0; if (dev->int_err != 0 || dev->int_type != S5P_FIMV_R2H_CMD_SLEEP_RET) { /* Failure. */ mfc_err_dev("Failed to sleep - error: %d" " int: %d.\n", dev->int_err, dev->int_type); ret = -EIO; goto err_mfc_sleep; } err_mfc_sleep: s5p_mfc_clock_off(dev); /* release system pgtable */ if (dev->curr_ctx_drm) { ret = s5p_mfc_release_sec_pgtable(dev); if (ret < 0) { mfc_err("Fail to release MFC secure sysmmu page tables. ret = %d\n", ret); } } mfc_debug_leave(); return ret; }
static int mfc_open(struct inode *inode, struct file *file) { mfc_inst_ctx *mfc_ctx; int ret; //struct sched_param param = { .sched_priority = 1 }; #if ENABLE_MONITORING_MFC_DD mfc_info("MFC mfc_open..\n"); #endif mutex_lock(&mfc_mutex); if (!mfc_is_running()) { #ifdef CONFIG_CPU_FREQ_S5PV210 s5pv210_set_cpufreq_level(RESTRICT_TABLE); #endif /* CONFIG_CPU_FREQ_S5PV210 */ #ifdef CONFIG_S5P_LPAUDIO s5p_set_lpaudio_lock(1); #endif /* CONFIG_S5P_LPAUDIO */ if (s5pv210_pd_enable("mfc_pd") < 0){ printk(KERN_ERR "[Error]The power is not on for mfc\n"); return -1; } clk_enable(mfc_clk); #ifdef CONFIG_PM_PWR_GATING s5pc110_lock_power_domain(MFC_DOMAIN_LOCK_TOKEN); #endif if (mfc_init_hw() != TRUE) { #if Frame_Base_Power_CTR_ON clk_disable(mfc_clk); if (s5pv210_pd_disable("mfc_pd") < 0) { printk(KERN_ERR "[Error]The power is not off for mfc\n"); return -1; } #endif ret = -ENODEV; goto out_open; } #if Frame_Base_Power_CTR_ON clk_disable(mfc_clk); /*if (s5pv210_pd_disable("mfc_pd") < 0) { printk(KERN_ERR "[Error]The power is not off for mfc\n"); return -1; }*/ #endif } mfc_ctx = (mfc_inst_ctx *)kmalloc(sizeof(mfc_inst_ctx), GFP_KERNEL); if (mfc_ctx == NULL) { mfc_err("MFCINST_MEMORY_ALLOC_FAIL\n"); ret = -ENOMEM; goto out_open; } memset(mfc_ctx, 0, sizeof(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"); kfree(mfc_ctx); ret = -EPERM; goto out_open; } if (mfc_set_state(mfc_ctx, MFCINST_STATE_OPENED) < 0) { mfc_err("MFCINST_ERR_STATE_INVALID\n"); kfree(mfc_ctx); ret = -ENODEV; goto out_open; } /* Decoder only */ mfc_ctx->extraDPB = MFC_MAX_EXTRA_DPB; mfc_ctx->FrameType = MFC_RET_FRAME_NOT_SET; file->private_data = (mfc_inst_ctx *)mfc_ctx; //sched_setscheduler(current, SCHED_FIFO, ¶m); ret = 0; out_open: mutex_unlock(&mfc_mutex); if(ret != 0) { mfc_err("MFC_OEPN_FAIL..... ret(%d) \n", ret); return ret; } #if ENABLE_MONITORING_MFC_DD mfc_info("MFC_OEPN_OK..... ret(%d) \n", ret); #endif return ret; }
int s5p_mfc_wakeup(struct s5p_mfc_dev *dev) { enum mfc_buf_usage_type buf_type; int ret; mfc_debug_enter(); if (!dev) { mfc_err("no mfc device to run\n"); return -EINVAL; } mfc_info_dev("curr_ctx_drm:%d\n", dev->curr_ctx_drm); /* Set clock source again after wake up */ s5p_mfc_set_clock_parent(dev); /* setup system pgtable */ if (dev->curr_ctx_drm) { ret = s5p_mfc_request_sec_pgtable(dev); if (ret < 0) { mfc_err("Fail to make MFC secure sysmmu page tables. ret = %d\n", ret); } } /* 0. MFC reset */ mfc_debug(2, "MFC reset...\n"); s5p_mfc_clock_on(dev); ret = s5p_mfc_reset(dev); if (ret) { mfc_err_dev("Failed to reset MFC - timeout.\n"); goto err_mfc_wakeup; } mfc_debug(2, "Done MFC reset...\n"); if (dev->curr_ctx_drm) buf_type = MFCBUF_DRM; else buf_type = MFCBUF_NORMAL; /* 1. Set DRAM base Addr */ s5p_mfc_init_memctrl(dev, buf_type); /* 2. Initialize registers of channel I/F */ s5p_mfc_clear_cmds(dev); s5p_mfc_clean_dev_int_flags(dev); /* 3. Initialize firmware */ if (!FW_WAKEUP_AFTER_RISC_ON(dev)) ret = s5p_mfc_wakeup_cmd(dev); if (ret) { mfc_err_dev("Failed to send command to MFC - timeout.\n"); goto err_mfc_wakeup; } /* 4. Release reset signal to the RISC */ if (IS_MFCV6(dev)) s5p_mfc_write_reg(dev, 0x1, S5P_FIMV_RISC_ON); else s5p_mfc_write_reg(dev, 0x3ff, S5P_FIMV_SW_RESET); mfc_debug(2, "Will now wait for completion of firmware transfer.\n"); if (FW_WAKEUP_AFTER_RISC_ON(dev)) { if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_FW_STATUS_RET)) { mfc_err_dev("Failed to load firmware.\n"); s5p_mfc_clean_dev_int_flags(dev); ret = -EIO; goto err_mfc_wakeup; } } if (FW_WAKEUP_AFTER_RISC_ON(dev)) ret = s5p_mfc_wakeup_cmd(dev); mfc_debug(2, "Ok, now will write a command to wakeup the system\n"); if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_WAKEUP_RET)) { mfc_err_dev("Failed to load firmware\n"); ret = -EIO; goto err_mfc_wakeup; } dev->int_cond = 0; if (dev->int_err != 0 || dev->int_type != S5P_FIMV_R2H_CMD_WAKEUP_RET) { /* Failure. */ mfc_err_dev("Failed to wakeup - error: %d" " int: %d.\n", dev->int_err, dev->int_type); ret = -EIO; goto err_mfc_wakeup; } err_mfc_wakeup: s5p_mfc_clock_off(dev); mfc_debug_leave(); return 0; }
/* Input arguments for S3C_MFC_IOCTL_MFC_SET_CONFIG */ int s3c_mfc_set_config_params(s3c_mfc_inst_context_t *mfc_inst, s3c_mfc_args_t *args) { __D("\n"); int ret, size; unsigned int param_change_enable = 0, param_change_val; unsigned char *start; unsigned int offset; switch (args->set_config.in_config_param) { case S3C_MFC_SET_CONFIG_DEC_ROTATE: #if (S3C_MFC_ROTATE_ENABLE == 1) args->set_config.out_config_value_old[0] = s3c_mfc_inst_set_post_rotate(mfc_inst, args->set_config.in_config_value[0]); #else mfc_err("S3C_MFC_IOCTL_MFC_SET_CONFIG with S3C_MFC_SET_CONFIG_DEC_ROTATE is not supported\n"); mfc_err("please check if S3C_MFC_ROTATE_ENABLE is defined as 1 in MfcConfig.h file\n"); #endif ret = S3C_MFC_INST_RET_OK; break; case S3C_MFC_SET_CONFIG_ENC_H263_PARAM: args->set_config.out_config_value_old[0] = mfc_inst->h263_annex; mfc_inst->h263_annex = args->set_config.in_config_value[0]; mfc_debug("parameter = 0x%x\n", mfc_inst->h263_annex); ret = S3C_MFC_INST_RET_OK; break; case S3C_MFC_SET_CONFIG_ENC_SLICE_MODE: if (mfc_inst->enc_num_slices) { args->set_config.out_config_value_old[0] = 1; args->set_config.out_config_value_old[1] = mfc_inst->enc_num_slices; } else { args->set_config.out_config_value_old[0] = 0; args->set_config.out_config_value_old[1] = 0; } if (args->set_config.in_config_value[0]) mfc_inst->enc_num_slices = args->set_config.in_config_value[1]; else mfc_inst->enc_num_slices = 0; ret = S3C_MFC_INST_RET_OK; break; case S3C_MFC_SET_CONFIG_ENC_PARAM_CHANGE: switch (args->set_config.in_config_value[0]) { case S3C_ENC_PARAM_GOP_NUM: param_change_enable = (1 << 0); break; case S3C_ENC_PARAM_INTRA_QP: param_change_enable = (1 << 1); break; case S3C_ENC_PARAM_BITRATE: param_change_enable = (1 << 2); break; case S3C_ENC_PARAM_F_RATE: param_change_enable = (1 << 3); break; case S3C_ENC_PARAM_INTRA_REF: param_change_enable = (1 << 4); break; case S3C_ENC_PARAM_SLICE_MODE: param_change_enable = (1 << 5); break; default: break; } param_change_val = args->set_config.in_config_value[1]; ret = s3c_mfc_inst_enc_param_change(mfc_inst, param_change_enable, param_change_val); break; case S3C_MFC_SET_CONFIG_ENC_CUR_PIC_OPT: switch (args->set_config.in_config_value[0]) { case S3C_ENC_PIC_OPT_IDR: mfc_inst->enc_pic_option ^= (args->set_config.in_config_value[1] << 1); break; case S3C_ENC_PIC_OPT_SKIP: mfc_inst->enc_pic_option ^= (args->set_config.in_config_value[1] << 0); break; case S3C_ENC_PIC_OPT_RECOVERY: mfc_inst->enc_pic_option ^= (args->set_config.in_config_value[1] << 24); break; default: break; } ret = S3C_MFC_INST_RET_OK; break; case S3C_MFC_SET_CACHE_CLEAN: /* * in_config_value[0] : start address in user layer * in_config_value[1] : offset * in_config_value[2] : start address of stream buffer in user layer */ offset = args->set_config.in_config_value[0] - args->set_config.in_config_value[2]; start = mfc_inst->stream_buffer + offset; size = args->set_config.in_config_value[1]; dma_cache_maint(start, size, DMA_TO_DEVICE); /* offset = args->set_config.in_config_value[0] - args->set_config.in_config_value[2]; start = (unsigned int)mfc_inst->stream_buffer + offset; end = start + args->set_config.in_config_value[1]; dmac_clean_range((void *)start, (void *)end); start = (unsigned int)mfc_inst->phys_addr_stream_buffer + offset; end = start + args->set_config.in_config_value[1]; outer_clean_range((unsigned long)start, (unsigned long)end); */ ret = S3C_MFC_INST_RET_OK; break; case S3C_MFC_SET_CACHE_INVALIDATE: /* * in_config_value[0] : start address in user layer * in_config_value[1] : offset * in_config_value[2] : start address of stream buffer in user layer */ offset = args->set_config.in_config_value[0] - args->set_config.in_config_value[2]; start = mfc_inst->stream_buffer + offset; size = args->set_config.in_config_value[1]; dma_cache_maint(start, size, DMA_FROM_DEVICE); /* offset = args->set_config.in_config_value[0] - args->set_config.in_config_value[2]; start = (unsigned int)mfc_inst->stream_buffer + offset; end = start + args->set_config.in_config_value[1]; dmac_inv_range((void *)start, (void *)end); start = (unsigned int)mfc_inst->phys_addr_stream_buffer + offset; end = start + args->set_config.in_config_value[1]; outer_inv_range((unsigned long)start, (unsigned long)end); */ ret = S3C_MFC_INST_RET_OK; break; case S3C_MFC_SET_CACHE_CLEAN_INVALIDATE: /* * in_config_value[0] : start address in user layer * in_config_value[1] : offset * in_config_value[2] : start address of stream buffer in user layer */ offset = args->set_config.in_config_value[0] - args->set_config.in_config_value[2]; start = mfc_inst->stream_buffer + offset; size = args->set_config.in_config_value[1]; dma_cache_maint(start, size, DMA_BIDIRECTIONAL); /* offset = args->set_config.in_config_value[0] - args->set_config.in_config_value[2]; start = (unsigned int)mfc_inst->stream_buffer + offset; end = start + args->set_config.in_config_value[1]; dmac_flush_range((void *)start, (void *)end); start = (unsigned int)mfc_inst->phys_addr_stream_buffer + offset; end = start + args->set_config.in_config_value[1]; outer_flush_range((unsigned long)start, (unsigned long)end); */ ret = S3C_MFC_INST_RET_OK; break; #if (defined(DIVX_ENABLE) && (DIVX_ENABLE == 1)) case S3C_MFC_SET_PADDING_SIZE: mfc_debug("padding size = %d\n", \ args->set_config.in_config_value[0]); mfc_inst->padding_size = args->set_config.in_config_value[0]; ret = S3C_MFC_INST_RET_OK; break; #endif default: ret = -1; } /* Output arguments for S3C_MFC_IOCTL_MFC_SET_CONFIG */ args->set_config.ret_code = ret; return S3C_MFC_INST_RET_OK; }
int mfc_wait_for_done(mfc_wait_done_type command) { unsigned int nwait_time = 100; unsigned int ret_val = 1; if((command == R2H_CMD_CLOSE_INSTANCE_RET) || (command == R2H_CMD_OPEN_INSTANCE_RET) || (command == R2H_CMD_FW_STATUS_RET)) nwait_time = MFC_WAIT_4_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 //set_user_nice(current, -20); #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("MFC timeouted!\n"); #else if (interruptible_sleep_on_timeout(&mfc_wait_queue, nwait_time) == 0) { ret_val = R2H_CMD_TIMEOUT; 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 = ret_val; return ret_val; } else if (mfc_int_type == R2H_CMD_DECODE_ERR_RET) { mfc_err("MFC 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 #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; }
/* Set format */ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct s5p_mfc_dev *dev = video_drvdata(file); struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); int ret = 0; struct s5p_mfc_fmt *fmt; struct v4l2_pix_format_mplane *pix_mp; mfc_debug_enter(); ret = vidioc_try_fmt(file, priv, f); pix_mp = &f->fmt.pix_mp; if (ret) return ret; if (ctx->vq_src.streaming || ctx->vq_dst.streaming) { v4l2_err(&dev->v4l2_dev, "%s queue busy\n", __func__); ret = -EBUSY; goto out; } if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { fmt = find_format(f, MFC_FMT_RAW); if (!fmt) { mfc_err("Unsupported format for source.\n"); return -EINVAL; } if (!IS_MFCV6(dev) && (fmt->fourcc != V4L2_PIX_FMT_NV12MT)) { mfc_err("Not supported format.\n"); return -EINVAL; } else if (IS_MFCV6(dev) && (fmt->fourcc == V4L2_PIX_FMT_NV12MT)) { mfc_err("Not supported format.\n"); return -EINVAL; } ctx->dst_fmt = fmt; mfc_debug_leave(); return ret; } else if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { mfc_err("Wrong type error for S_FMT : %d", f->type); return -EINVAL; } fmt = find_format(f, MFC_FMT_DEC); if (!fmt || fmt->codec_mode == S5P_MFC_CODEC_NONE) { mfc_err("Unknown codec\n"); ret = -EINVAL; goto out; } if (fmt->type != MFC_FMT_DEC) { mfc_err("Wrong format selected, you should choose " "format for decoding\n"); ret = -EINVAL; goto out; } if (!IS_MFCV6(dev) && (fmt->fourcc == V4L2_PIX_FMT_VP8)) { mfc_err("Not supported format.\n"); return -EINVAL; } ctx->src_fmt = fmt; ctx->codec_mode = fmt->codec_mode; mfc_debug(2, "The codec number is: %d\n", ctx->codec_mode); pix_mp->height = 0; pix_mp->width = 0; if (pix_mp->plane_fmt[0].sizeimage) ctx->dec_src_buf_size = pix_mp->plane_fmt[0].sizeimage; else pix_mp->plane_fmt[0].sizeimage = ctx->dec_src_buf_size = DEF_CPB_SIZE; pix_mp->plane_fmt[0].bytesperline = 0; ctx->state = MFCINST_INIT; out: mfc_debug_leave(); 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); if (mfc_ctx->buf_type == MFC_BUFFER_CACHE) { vma->vm_flags |= VM_RESERVED | VM_IO; /* * 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; /* * 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; } } else { 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; }
/* Allocate and load firmware */ int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev) { struct firmware *fw_blob; size_t bank2_base_phys; void *b_base; int err; /* Firmare has to be present as a separate file or compiled * into kernel. */ mfc_debug_enter(); err = request_firmware((const struct firmware **)&fw_blob, "s5p-mfc.fw", dev->v4l2_dev.dev); if (err != 0) { mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n"); return -EINVAL; } dev->fw_size = ALIGN(fw_blob->size, FIRMWARE_ALIGN); if (s5p_mfc_bitproc_buf) { mfc_err("Attempting to allocate firmware when it seems that it is already loaded\n"); release_firmware(fw_blob); return -ENOMEM; } s5p_mfc_bitproc_buf = vb2_dma_contig_memops.alloc( dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], dev->fw_size); if (IS_ERR(s5p_mfc_bitproc_buf)) { s5p_mfc_bitproc_buf = NULL; mfc_err("Allocating bitprocessor buffer failed\n"); release_firmware(fw_blob); return -ENOMEM; } s5p_mfc_bitproc_phys = s5p_mfc_mem_cookie( dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], s5p_mfc_bitproc_buf); if (s5p_mfc_bitproc_phys & ((1 << MFC_BASE_ALIGN_ORDER) - 1)) { mfc_err("The base memory for bank 1 is not aligned to 128KB\n"); vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf); s5p_mfc_bitproc_phys = 0; s5p_mfc_bitproc_buf = NULL; release_firmware(fw_blob); return -EIO; } s5p_mfc_bitproc_virt = vb2_dma_contig_memops.vaddr(s5p_mfc_bitproc_buf); if (!s5p_mfc_bitproc_virt) { mfc_err("Bitprocessor memory remap failed\n"); vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf); s5p_mfc_bitproc_phys = 0; s5p_mfc_bitproc_buf = NULL; release_firmware(fw_blob); return -EIO; } dev->bank1 = s5p_mfc_bitproc_phys; b_base = vb2_dma_contig_memops.alloc( dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], 1 << MFC_BANK2_ALIGN_ORDER); if (IS_ERR(b_base)) { vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf); s5p_mfc_bitproc_phys = 0; s5p_mfc_bitproc_buf = NULL; mfc_err("Allocating bank2 base failed\n"); release_firmware(fw_blob); return -ENOMEM; } bank2_base_phys = s5p_mfc_mem_cookie( dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], b_base); vb2_dma_contig_memops.put(b_base); if (bank2_base_phys & ((1 << MFC_BASE_ALIGN_ORDER) - 1)) { mfc_err("The base memory for bank 2 is not aligned to 128KB\n"); vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf); s5p_mfc_bitproc_phys = 0; s5p_mfc_bitproc_buf = NULL; release_firmware(fw_blob); return -EIO; } dev->bank2 = bank2_base_phys; memcpy(s5p_mfc_bitproc_virt, fw_blob->data, fw_blob->size); wmb(); release_firmware(fw_blob); mfc_debug_leave(); return 0; }
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; } #ifdef CONFIG_DVFS_LIMIT s5pv210_lock_dvfs_high_level(DVFS_LOCK_TOKEN_1, L4); #endif 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()) { #ifdef CONFIG_DVFS_LIMIT s5pv210_unlock_dvfs_high_level(DVFS_LOCK_TOKEN_1); #endif /* 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; }
/* Reset the device */ static int s5p_mfc_reset(struct s5p_mfc_dev *dev) { int i; unsigned int status; unsigned long timeout; mfc_debug_enter(); if (!dev) { mfc_err("no mfc device to run\n"); return -EINVAL; } /* Stop procedure */ /* Reset VI */ /* s5p_mfc_write_reg(dev, 0x3f7, S5P_FIMV_SW_RESET); */ if (IS_MFCV6(dev)) { /* Zero Initialization of MFC registers */ s5p_mfc_write_reg(dev, 0, S5P_FIMV_RISC2HOST_CMD); s5p_mfc_write_reg(dev, 0, S5P_FIMV_HOST2RISC_CMD); s5p_mfc_write_reg(dev, 0, S5P_FIMV_FW_VERSION); for (i = 0; i < S5P_FIMV_REG_CLEAR_COUNT; i++) s5p_mfc_write_reg(dev, 0, S5P_FIMV_REG_CLEAR_BEGIN + (i*4)); if (IS_MFCv6X(dev)) if (s5p_mfc_bus_reset(dev)) return -EIO; s5p_mfc_write_reg(dev, 0, S5P_FIMV_RISC_ON); s5p_mfc_write_reg(dev, 0x1FFF, S5P_FIMV_MFC_RESET); s5p_mfc_write_reg(dev, 0, S5P_FIMV_MFC_RESET); } else { s5p_mfc_write_reg(dev, 0x3f6, S5P_FIMV_SW_RESET); /* reset RISC */ s5p_mfc_write_reg(dev, 0x3e2, S5P_FIMV_SW_RESET); /* All reset except for MC */ mdelay(10); timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT); /* Check MC status */ do { if (time_after(jiffies, timeout)) { mfc_err_dev("Timeout while resetting MFC.\n"); return -EIO; } status = s5p_mfc_read_reg(dev, S5P_FIMV_MC_STATUS); } while (status & 0x3); s5p_mfc_write_reg(dev, 0x0, S5P_FIMV_SW_RESET); s5p_mfc_write_reg(dev, 0x3fe, S5P_FIMV_SW_RESET); } mfc_debug_leave(); return 0; }
/* Reset the device */ static int s5p_mfc_reset(struct s5p_mfc_dev *dev) { int i; unsigned int status; unsigned long timeout; mfc_debug_enter(); /* Stop procedure */ /* FIXME: F/W can be access invalid address */ /* Reset VI */ /* s5p_mfc_write_reg(0x3f7, S5P_FIMV_SW_RESET); */ if (IS_MFCV6(dev)) { /* Reset IP */ s5p_mfc_write_reg(0xFEE, S5P_FIMV_MFC_RESET); /* except RISC, reset */ s5p_mfc_write_reg(0x0, S5P_FIMV_MFC_RESET); /* reset release */ /* Zero Initialization of MFC registers */ s5p_mfc_write_reg(0, S5P_FIMV_RISC2HOST_CMD); s5p_mfc_write_reg(0, S5P_FIMV_HOST2RISC_CMD); s5p_mfc_write_reg(0, S5P_FIMV_FW_VERSION); for (i = 0; i < S5P_FIMV_REG_CLEAR_COUNT; i++) s5p_mfc_write_reg(0, S5P_FIMV_REG_CLEAR_BEGIN + (i*4)); /* Reset */ s5p_mfc_write_reg(0x1, S5P_FIMV_MFC_BUS_RESET_CTRL); timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT); /* Check bus status */ do { if (time_after(jiffies, timeout)) { mfc_err("Timeout while resetting MFC.\n"); return -EIO; } status = s5p_mfc_read_reg(S5P_FIMV_MFC_BUS_RESET_CTRL); } while ((status & 0x2) == 0); s5p_mfc_write_reg(0, S5P_FIMV_RISC_ON); s5p_mfc_write_reg(0x1FFF, S5P_FIMV_MFC_RESET); s5p_mfc_write_reg(0, S5P_FIMV_MFC_RESET); } else { s5p_mfc_write_reg(0x3f6, S5P_FIMV_SW_RESET); /* reset RISC */ s5p_mfc_write_reg(0x3e2, S5P_FIMV_SW_RESET); /* All reset except for MC */ mdelay(10); timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT); /* Check MC status */ do { if (time_after(jiffies, timeout)) { mfc_err("Timeout while resetting MFC.\n"); return -EIO; } status = s5p_mfc_read_reg(S5P_FIMV_MC_STATUS); } while (status & 0x3); s5p_mfc_write_reg(0x0, S5P_FIMV_SW_RESET); s5p_mfc_write_reg(0x3fe, S5P_FIMV_SW_RESET); } mfc_debug_leave(); return 0; }
/* Initialize hardware */ int mfc_init_hw(struct s5p_mfc_dev *dev, enum mfc_buf_usage_type buf_type) { char fimv_info; int fw_ver; int ret = 0; int curr_ctx_backup; mfc_debug_enter(); if (!dev) { mfc_err("no mfc device to run\n"); return -EINVAL; } curr_ctx_backup = dev->curr_ctx_drm; /* RMVME: */ if (!dev->fw_info.alloc) return -EINVAL; /* 0. MFC reset */ mfc_debug(2, "MFC reset...\n"); /* At init time, do not call secure API */ if (buf_type == MFCBUF_NORMAL) dev->curr_ctx_drm = 0; else if (buf_type == MFCBUF_DRM) dev->curr_ctx_drm = 1; ret = s5p_mfc_clock_on(dev); if (ret) { mfc_err_dev("Failed to enable clock before reset(%d)\n", ret); dev->curr_ctx_drm = curr_ctx_backup; return ret; } ret = s5p_mfc_reset(dev); if (ret) { mfc_err_dev("Failed to reset MFC - timeout.\n"); goto err_init_hw; } mfc_debug(2, "Done MFC reset...\n"); /* 1. Set DRAM base Addr */ s5p_mfc_init_memctrl(dev, buf_type); /* 2. Initialize registers of channel I/F */ s5p_mfc_clear_cmds(dev); s5p_mfc_clean_dev_int_flags(dev); /* 3. Release reset signal to the RISC */ if (IS_MFCV6(dev)) s5p_mfc_write_reg(dev, 0x1, S5P_FIMV_RISC_ON); else s5p_mfc_write_reg(dev, 0x3ff, S5P_FIMV_SW_RESET); mfc_debug(2, "Will now wait for completion of firmware transfer.\n"); if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_FW_STATUS_RET)) { mfc_err_dev("Failed to load firmware.\n"); s5p_mfc_clean_dev_int_flags(dev); ret = -EIO; goto err_init_hw; } s5p_mfc_clean_dev_int_flags(dev); /* 4. Initialize firmware */ ret = s5p_mfc_sys_init_cmd(dev, buf_type); if (ret) { mfc_err_dev("Failed to send command to MFC - timeout.\n"); goto err_init_hw; } mfc_debug(2, "Ok, now will write a command to init the system\n"); if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_SYS_INIT_RET)) { mfc_err_dev("Failed to load firmware\n"); ret = -EIO; goto err_init_hw; } dev->int_cond = 0; if (dev->int_err != 0 || dev->int_type != S5P_FIMV_R2H_CMD_SYS_INIT_RET) { /* Failure. */ mfc_err_dev("Failed to init firmware - error: %d" " int: %d.\n", dev->int_err, dev->int_type); ret = -EIO; goto err_init_hw; } fimv_info = MFC_GET_REG(SYS_FW_FIMV_INFO); if (fimv_info != 'D' && fimv_info != 'E') fimv_info = 'N'; mfc_info_dev("MFC v%x.%x, F/W: %02xyy, %02xmm, %02xdd (%c)\n", MFC_VER_MAJOR(dev), MFC_VER_MINOR(dev), MFC_GET_REG(SYS_FW_VER_YEAR), MFC_GET_REG(SYS_FW_VER_MONTH), MFC_GET_REG(SYS_FW_VER_DATE), fimv_info); dev->fw.date = MFC_GET_REG(SYS_FW_VER_ALL); /* Check MFC version and F/W version */ if (IS_MFCV6(dev) && FW_HAS_VER_INFO(dev)) { fw_ver = MFC_GET_REG(SYS_MFC_VER); if (fw_ver != mfc_version(dev)) { mfc_err_dev("Invalid F/W version(0x%x) for MFC H/W(0x%x)\n", fw_ver, mfc_version(dev)); ret = -EIO; goto err_init_hw; } } #ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION /* Cache flush for base address change */ if (FW_HAS_BASE_CHANGE(dev)) { s5p_mfc_clean_dev_int_flags(dev); s5p_mfc_cmd_host2risc(dev, S5P_FIMV_CH_CACHE_FLUSH, NULL); if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_CACHE_FLUSH_RET)) { mfc_err_dev("Failed to flush cache\n"); ret = -EIO; goto err_init_hw; } if (buf_type == MFCBUF_DRM && !curr_ctx_backup) { s5p_mfc_clock_off(dev); dev->curr_ctx_drm = curr_ctx_backup; s5p_mfc_clock_on_with_base(dev, MFCBUF_NORMAL); } else if (buf_type == MFCBUF_NORMAL && curr_ctx_backup) { s5p_mfc_init_memctrl(dev, MFCBUF_DRM); } } #endif err_init_hw: s5p_mfc_clock_off(dev); dev->curr_ctx_drm = curr_ctx_backup; mfc_debug_leave(); return ret; }
/* Initialize hardware */ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) { char dvx_info; int mfc_info; int ret = 0; mfc_debug_enter(); /* RMVME: */ if (!s5p_mfc_bitproc_buf) return -EINVAL; /* 0. MFC reset */ mfc_debug(2, "MFC reset...\n"); s5p_mfc_clock_on(); ret = s5p_mfc_reset(dev); if (ret) { mfc_err("Failed to reset MFC - timeout.\n"); goto err_init_hw; } mfc_debug(2, "Done MFC reset...\n"); /* 1. Set DRAM base Addr */ s5p_mfc_init_memctrl(dev); /* 2. Initialize registers of channel I/F */ s5p_mfc_clear_cmds(dev); /* 3. Release reset signal to the RISC */ if (IS_MFCV6(dev)) s5p_mfc_write_reg(0x1, S5P_FIMV_RISC_ON); else s5p_mfc_write_reg(0x3ff, S5P_FIMV_SW_RESET); mfc_debug(2, "Will now wait for completion of firmware transfer.\n"); if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_FW_STATUS_RET)) { mfc_err("Failed to load firmware.\n"); s5p_mfc_clean_dev_int_flags(dev); ret = -EIO; goto err_init_hw; } s5p_mfc_clean_dev_int_flags(dev); /* 4. Initialize firmware */ ret = s5p_mfc_sys_init_cmd(dev); if (ret) { mfc_err("Failed to send command to MFC - timeout.\n"); goto err_init_hw; } mfc_debug(2, "Ok, now will write a command to init the system\n"); if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_SYS_INIT_RET)) { mfc_err("Failed to load firmware\n"); ret = -EIO; /* Disable the clock that enabled in s5p_mfc_sys_init_cmd() */ s5p_mfc_clock_off(); goto err_init_hw; } dev->int_cond = 0; if (dev->int_err != 0 || dev->int_type != S5P_FIMV_R2H_CMD_SYS_INIT_RET) { /* Failure. */ mfc_err("Failed to init firmware - error: %d" " int: %d.\n",dev->int_err, dev->int_type); ret = -EIO; goto err_init_hw; } dvx_info = MFC_GET_REG(SYS_FW_DVX_INFO); if (dvx_info != 'D' && dvx_info != 'E') dvx_info = 'N'; mfc_info("MFC v%x.%x, F/W : (%c) %02xyy, %02xmm, %02xdd\n", MFC_VER_MAJOR(dev->fw.ver), MFC_VER_MINOR(dev->fw.ver), dvx_info, MFC_GET_REG(SYS_FW_VER_YEAR), MFC_GET_REG(SYS_FW_VER_MONTH), MFC_GET_REG(SYS_FW_VER_DATE)); dev->fw.date = MFC_GET_REG(SYS_FW_VER_ALL); /* Check MFC version and F/W version */ if (dev->fw.date >= 0x120328) { mfc_info = MFC_GET_REG(SYS_MFC_VER); if (mfc_info != dev->fw.ver) { mfc_err("Invalid F/W version(0x%x) for MFC H/W(0x%x)\n", mfc_info, dev->fw.ver); ret = -EIO; goto err_init_hw; } } err_init_hw: s5p_mfc_clock_off(); mfc_debug_leave(); return ret; }
/* Allocate firmware */ int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev) { unsigned int base_align; unsigned int firmware_size; void *alloc_ctx; mfc_debug_enter(); if (!dev) { mfc_err("no mfc device to run\n"); return -EINVAL; } base_align = dev->variant->buf_align->mfc_base_align; firmware_size = dev->variant->buf_size->firmware_code; alloc_ctx = dev->alloc_ctx[MFC_FW_ALLOC_CTX]; if (dev->fw_info.alloc) return 0; mfc_debug(2, "Allocating memory for firmware.\n"); alloc_ctx = dev->alloc_ctx_fw; dev->fw_info.alloc = s5p_mfc_mem_alloc_priv(alloc_ctx, firmware_size); if (IS_ERR(dev->fw_info.alloc)) { dev->fw_info.alloc = 0; printk(KERN_ERR "Allocating bitprocessor buffer failed\n"); return -ENOMEM; } dev->fw_info.ofs = s5p_mfc_mem_daddr_priv(dev->fw_info.alloc); if (dev->fw_info.ofs & ((1 << base_align) - 1)) { mfc_err_dev("The base memory is not aligned to %dBytes.\n", (1 << base_align)); s5p_mfc_mem_free_priv(dev->fw_info.alloc); dev->fw_info.ofs = 0; dev->fw_info.alloc = 0; return -EIO; } dev->fw_info.virt = s5p_mfc_mem_vaddr_priv(dev->fw_info.alloc); mfc_debug(2, "Virtual address for FW: %08lx\n", (long unsigned int)dev->fw_info.virt); if (!dev->fw_info.virt) { mfc_err_dev("Bitprocessor memory remap failed\n"); s5p_mfc_mem_free_priv(dev->fw_info.alloc); dev->fw_info.ofs = 0; dev->fw_info.alloc = 0; return -EIO; } dev->port_a = dev->fw_info.ofs; dev->port_b = dev->fw_info.ofs; mfc_debug(2, "Port A: %08x Port B: %08x (FW: %08lx size: %08x)\n", dev->port_a, dev->port_b, dev->fw_info.ofs, firmware_size); #ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION alloc_ctx = dev->alloc_ctx_drm_fw; dev->drm_fw_info.alloc = s5p_mfc_mem_alloc_priv(alloc_ctx, firmware_size); if (IS_ERR(dev->drm_fw_info.alloc)) { /* Release normal F/W buffer */ s5p_mfc_mem_free_priv(dev->fw_info.alloc); dev->fw_info.ofs = 0; dev->fw_info.alloc = 0; printk(KERN_ERR "Allocating bitprocessor buffer failed\n"); return -ENOMEM; } dev->drm_fw_info.ofs = s5p_mfc_mem_daddr_priv(dev->drm_fw_info.alloc); if (dev->drm_fw_info.ofs & ((1 << base_align) - 1)) { mfc_err_dev("The base memory is not aligned to %dBytes.\n", (1 << base_align)); s5p_mfc_mem_free_priv(dev->drm_fw_info.alloc); /* Release normal F/W buffer */ s5p_mfc_mem_free_priv(dev->fw_info.alloc); dev->fw_info.ofs = 0; dev->fw_info.alloc = 0; return -EIO; } mfc_info_dev("Port for DRM F/W : 0x%lx\n", dev->drm_fw_info.ofs); #endif mfc_debug_leave(); return 0; }
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); mfc_ctx->desc_buff_paddr = in_param.args.mem_alloc.out_paddr + CPB_BUF_SIZE; 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; case IOCTL_MFC_BUF_CACHE: mutex_lock(&mfc_mutex); in_param.ret_code = MFCINST_RET_OK; mfc_ctx->buf_type = in_param.args.buf_type; mutex_unlock(&mfc_mutex); 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 s3c_mfc_probe(struct platform_device *pdev) { int size; int ret; struct resource *res; unsigned int mfc_clk; /* mfc clock enable */ s3c_mfc_hclk = clk_get(&pdev->dev, "hclk_mfc"); if (!s3c_mfc_hclk || IS_ERR(s3c_mfc_hclk)) { mfc_err("failed to get mfc hclk source\n"); return -ENOENT; } clk_enable(s3c_mfc_hclk); s3c_mfc_sclk = clk_get(&pdev->dev, "sclk_mfc"); if (!s3c_mfc_sclk || IS_ERR(s3c_mfc_sclk)) { mfc_err("failed to get mfc sclk source\n"); return -ENOENT; } clk_enable(s3c_mfc_sclk); s3c_mfc_pclk = clk_get(&pdev->dev, "pclk_mfc"); if (!s3c_mfc_pclk || IS_ERR(s3c_mfc_pclk)) { mfc_err("failed to get mfc pclk source\n"); return -ENOENT; } clk_enable(s3c_mfc_pclk); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { mfc_err("failed to get memory region resouce\n"); return -ENOENT; } size = (res->end-res->start)+1; s3c_mfc_mem = request_mem_region(res->start, size, pdev->name); if (s3c_mfc_mem == NULL) { mfc_err("failed to get memory region\n"); return -ENOENT; } s3c_mfc_sfr_base_virt_addr = ioremap_nocache(res->start, size); if (s3c_mfc_sfr_base_virt_addr == 0) { mfc_err("failed to ioremap() region\n"); return -EINVAL; } res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (res == NULL) { mfc_err("failed to get irq resource\n"); return -ENOENT; } ret = request_irq(res->start, s3c_mfc_irq, IRQF_DISABLED, pdev->name, pdev); if (ret != 0) { mfc_err("failed to install irq (%d)\n", ret); return ret; } s3c_mfc_phys_buffer = s3c_get_media_memory(S3C_MDEV_MFC); /* mutex creation and initialization */ s3c_mfc_mutex = (struct mutex *)kmalloc(sizeof(struct mutex), GFP_KERNEL); if (s3c_mfc_mutex == NULL) return -ENOMEM; mutex_init(s3c_mfc_mutex); /* mfc clock set 133 Mhz */ if (s3c_mfc_setup_clock() == FALSE) return -ENODEV; /* * 2. MFC Memory Setup */ if (s3c_mfc_setup_memory() == FALSE) return -ENOMEM; /* * 3. MFC Hardware Initialization */ if (s3c_mfc_init_hw() == FALSE) return -ENODEV; ret = misc_register(&s3c_mfc_miscdev); clk_disable(s3c_mfc_hclk); clk_disable(s3c_mfc_sclk); clk_disable(s3c_mfc_pclk); return 0; }