int mfc_wakeup(struct mfc_dev *dev) { int ret; /* FIXME: add mfc_power_on()? */ //mfc_clock_on(); mfc_clock_on(dev); if (mfc_reset() == false) { //mfc_clock_off(); mfc_clock_off(dev); return MFC_FAIL; } mfc_init_memctrl(); mfc_clear_cmds(); ret = mfc_cmd_sys_wakeup(dev); //mfc_clock_off(); mfc_clock_off(dev); /* FIXME: ret = 0 */ return ret; }
int mfc_start(struct mfc_dev *dev) { int ret; /* FIXME: when MFC start, load firmware again */ /* dev->fw.state = mfc_load_firmware(dev->fw.info->data, dev->fw.info->size); */ mfc_clock_on(dev); if (mfc_reset() == false) { mfc_clock_off(dev); return MFC_FAIL; } mfc_init_memctrl(); mfc_clear_cmds(); ret = mfc_cmd_fw_start(dev); if (ret < 0) { mfc_clock_off(dev); return ret; } ret = mfc_cmd_sys_init(dev); mfc_clock_off(dev); return ret; }
static int mfc_runtime_resume(struct device *dev) { struct mfc_dev *m_dev = platform_get_drvdata(to_platform_device(dev)); int pre_power; pre_power = atomic_read(&m_dev->pm.power); atomic_set(&m_dev->pm.power, 1); #ifdef SYSMMU_MFC_ON if (pre_power == 0) { 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)); #endif mfc_clock_off(); } #endif return 0; }
/* FIXME: check mfc_remove funtionalilty */ static int __devexit mfc_remove(struct platform_device *pdev) { struct mfc_dev *dev = platform_get_drvdata(pdev); /* FIXME: close all instance? or check active instance? */ misc_deregister(&mfc_miscdev); mfc_final_buf(); #ifdef SYSMMU_MFC_ON mfc_clock_on(); #ifdef CONFIG_VIDEO_MFC_VCM_UMP vcm_deactivate(mfcdev->vcm_info.sysmmu_vcm); #endif sysmmu_off(SYSMMU_MFC_L); sysmmu_off(SYSMMU_MFC_R); mfc_clock_off(); #endif if (dev->fw.info) release_firmware(dev->fw.info); mfc_final_mem_mgr(dev); mfc_final_pm(dev); free_irq(dev->irq, dev); iounmap(dev->reg.base); release_mem_region(dev->reg.rsrc_start, dev->reg.rsrc_len); platform_set_drvdata(pdev, NULL); mutex_destroy(&dev->lock); kfree(dev); return 0; }
static int mfc_release(struct inode *inode, struct file *file) { struct mfc_inst_ctx *mfc_ctx; struct mfc_dev *dev; int ret; mfc_ctx = (struct mfc_inst_ctx *)file->private_data; if (!mfc_ctx) return -EINVAL; dev = mfc_ctx->dev; mutex_lock(&dev->lock); #ifdef CONFIG_CPU_FREQ /* Release MFC & Bus Frequency lock for High resolution */ if (mfc_ctx->busfreq_flag == true){ atomic_dec(&dev->busfreq_lock_cnt); mfc_ctx->busfreq_flag = false; if (atomic_read(&dev->busfreq_lock_cnt) == 0){ /* release Freq lock back to normal */ s5pv310_busfreq_lock_free(DVFS_LOCK_ID_MFC); mfc_dbg("[%s] Bus Freq lock Released Normal !!\n",__func__); } } #endif file->private_data = NULL; printk(KERN_INFO"[%s]Released Instance id %d \n",__func__,mfc_ctx->id); dev->inst_ctx[mfc_ctx->id] = NULL; atomic_dec(&dev->inst_cnt); mfc_destroy_inst(mfc_ctx); if (atomic_read(&dev->inst_cnt) == 0) { ret = mfc_power_off(); if (ret < 0) { mfc_err("power disable failed.\n"); goto err_pwr_disable; } } else { #if defined(SYSMMU_MFC_ON) && !defined(CONFIG_VIDEO_MFC_VCM_UMP) mfc_clock_on(); sysmmu_tlb_invalidate(SYSMMU_MFC_L); sysmmu_tlb_invalidate(SYSMMU_MFC_R); mfc_clock_off(); #endif } ret = 0; err_pwr_disable: mutex_unlock(&dev->lock); return ret; }
static void mfc_set_pagetable(enum vcm_dev_id id, unsigned long base) { if (mfc_power_chk()) { mfc_clock_on(); s5p_sysmmu_set_tablebase_pgd(NULL, base); mfc_clock_off(); } }
static void mfc_tlb_invalidate(enum vcm_dev_id id) { if (mfc_power_chk()) { mfc_clock_on(); s5p_sysmmu_tlb_invalidate(NULL); mfc_clock_off(); } }
static int mfc_resume(struct device *dev) { struct mfc_dev *m_dev = platform_get_drvdata(to_platform_device(dev)); int ret; u32 timeout; if (atomic_read(&m_dev->inst_cnt) == 0) return 0; #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)); #endif mfc_clock_off(); #endif mutex_lock(&m_dev->lock); __raw_writel(S5P_INT_LOCAL_PWR_EN, S5P_PMU_MFC_CONF); /* Wait max 1ms */ timeout = 10; while ((__raw_readl(S5P_PMU_MFC_CONF + 0x4) & S5P_INT_LOCAL_PWR_EN) != S5P_INT_LOCAL_PWR_EN) { if (timeout == 0) { printk(KERN_ERR "Power domain MFC enable failed.\n"); break; } timeout--; udelay(100); } ret = mfc_wakeup(m_dev); mutex_unlock(&m_dev->lock); if (ret != MFC_OK) return ret; return 0; }
void mfc_destroy_inst(struct mfc_inst_ctx* ctx) { struct mfc_dec_ctx *dec_ctx; struct mfc_enc_ctx *enc_ctx; struct mfc_pre_cfg *precfg; if (ctx) { if (ctx->state < INST_STATE_SETUP) { while (!list_empty(&ctx->presetcfgs)) { precfg = list_entry((&ctx->presetcfgs)->next, struct mfc_pre_cfg, list); mfc_dbg("remove unused preset config [0x%08x]\n", precfg->type); list_del(&precfg->list); kfree(precfg); } } else { /* free (decoder/encoder & context) private memory */ if (ctx->type == DECODER) { dec_ctx = ctx->c_priv; if (dec_ctx->d_priv) kfree(dec_ctx->d_priv); kfree(dec_ctx); } else if (ctx->type == ENCODER) { enc_ctx = ctx->c_priv; if (enc_ctx->e_priv) kfree(enc_ctx->e_priv); kfree(enc_ctx); } } if (ctx->state >= INST_STATE_OPEN) { mfc_clock_on(ctx->dev); mfc_cmd_inst_close(ctx); mfc_clock_off(ctx->dev); } mfc_free_buf_inst(ctx->id); /* free instance context memory */ kfree(ctx); }
int mfc_sleep(struct mfc_dev *dev) { int ret; mfc_clock_on(dev); /* FIXME: add SFR backup? */ ret = mfc_cmd_sys_sleep(dev); mfc_clock_off(dev); /* FIXME: add mfc_power_off()? */ /* FIXME: ret = 0 */ return ret; }
void mfc_destroy_inst(struct mfc_inst_ctx* ctx) { int ret = 0; if (ctx) { if (ctx->state >= INST_STATE_OPENED) { mfc_clock_on(); /* FIXME: meaningless return value */ ret = mfc_cmd_inst_close(ctx); mfc_clock_off(); } mfc_free_buf_inst(ctx->id); /* FIXME: free ctx->c_priv */ kfree(ctx); } }
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); #if defined(CONFIG_USE_MFC_CMA) && defined(CONFIG_MACH_MEHMET) if (atomic_read(&mfcdev->inst_cnt) == 0) { 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 #ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION if (mfcdev->drm_playback) { mfc_err("DRM playback was activated, cannot open no more instance\n"); ret = -EINVAL; goto err_drm_playback; } #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) { #ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION if (check_magic(mfcdev->drm_info.addr)) { mfc_dbg("DRM playback starting\n"); clear_magic(mfcdev->drm_info.addr); mfcdev->drm_playback = 1; mfc_set_buf_alloc_scheme(MBS_FIRST_FIT); } else { /* 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); } } } #else /* 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); } } #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(); 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(); #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; } } #ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION else { if (check_magic(mfcdev->drm_info.addr)) { clear_magic(mfcdev->drm_info.addr); mfc_err("MFC instances are not cleared before DRM playback!\n"); ret = -EINVAL; goto err_drm_start; } } #endif 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; mfc_ctx->id = inst_id; mfc_ctx->dev = mfcdev; #ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION if (mfcdev->drm_playback) { 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); }
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 (!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 exist, 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"); goto err_fw_state; } } 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) { 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 reloaded 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; } /* * Indicate that MFC is running */ mfc_is_running = 1; } 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) { mfc_destroy_inst(mfc_ctx); ret = -EINVAL; goto err_inst_ctx; } printk(KERN_INFO "MFC instance [%d] opened", 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; }
/* 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); #ifdef CONFIG_CPU_FREQ atomic_set(&mfcdev->busfreq_lock_cnt, 0); atomic_set(&mfcdev->cpufreq_lock_cnt, 0); #endif 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 */ mfcdev->fw.requesting = 1; ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, MFC_FW_NAME, &pdev->dev, GFP_KERNEL, pdev, mfc_firmware_request_complete_handler); if (ret) { mfcdev->fw.requesting = 0; 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; }
/* 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; }
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); #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); }