예제 #1
0
static int mfc_resume(struct platform_device *pdev)
{
	int ret = 0;
	unsigned int mc_status;

#if	ENABLE_MONITORING_MFC_DD
	mfc_info("mfc_resume......#1\n");
#endif

	mutex_lock(&mfc_mutex);

	if (!mfc_is_running())
	{
#if	ENABLE_MONITORING_MFC_DD
	mfc_info("mfc_resume......#2-0\n");
#endif	
		mutex_unlock(&mfc_mutex);
		return 0;
	}

#if	ENABLE_MONITORING_MFC_DD
	mfc_info("mfc_resume......#2-1\n");
#endif	
	
#if	Frame_Base_Power_CTR_ON			
	clk_enable(mfc_clk);
#endif
	/*
	 * 1. MFC reset
	 */
	do {
		mc_status = READL(MFC_MC_STATUS);
	} while(mc_status != 0);	
	
	mfc_cmd_reset();

	WRITEL(mfc_port0_base_paddr, MFC_MC_DRAMBASE_ADDR_A);
	WRITEL(mfc_port1_base_paddr, MFC_MC_DRAMBASE_ADDR_B);
	WRITEL(1, MFC_NUM_MASTER);

	ret = mfc_set_wakeup();
	if(ret != MFCINST_RET_OK){
		mutex_unlock(&mfc_mutex);
		return ret;
	}

#if	Frame_Base_Power_CTR_ON			
	clk_disable(mfc_clk);
#endif

	mutex_unlock(&mfc_mutex);

	return 0;
}
/* Deinitialize hardware */
void s5p_mfc_deinit_hw(struct s5p_mfc_dev *dev)
{
	mfc_info("mfc deinit start\n");

	if (!dev) {
		mfc_err("no mfc device to run\n");
		return;
	}

	s5p_mfc_clock_on();
	s5p_mfc_reset(dev);
	s5p_mfc_clock_off();

	mfc_info("mfc deinit completed\n");
}
예제 #3
0
static int mfc_remove(struct platform_device *pdev)
{
#if	ENABLE_MONITORING_MFC_DD
	mfc_info("remove mfc memory region, register\n");
#endif
	iounmap(mfc_sfr_base_vaddr);
	iounmap(mfc_port0_base_vaddr);

	/* remove memory region */
	if (mfc_mem != NULL)
	{
		release_resource(mfc_mem);
		kfree(mfc_mem);
		mfc_mem = NULL;
	}

	free_irq(IRQ_MFC, pdev);

	mutex_destroy(&mfc_mutex);

	clk_put(mfc_clk);

	misc_deregister(&mfc_miscdev);

	return 0;
}
예제 #4
0
static int mfc_suspend(struct platform_device *pdev, pm_message_t state)
{
	int ret = 0;

#if	ENABLE_MONITORING_MFC_DD
	mfc_info("mfc_suspend......#1\n");
#endif

	mutex_lock(&mfc_mutex);

	if (!mfc_is_running())
	{
#if	ENABLE_MONITORING_MFC_DD
		mfc_info("mfc_suspend......#2-0\n");
#endif
		mutex_unlock(&mfc_mutex);
		return 0;
	}

#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

#if	ENABLE_MONITORING_MFC_DD
	mfc_info("mfc_suspend......#2-1\n");
#endif

	ret = mfc_set_sleep();
	if(ret != MFCINST_RET_OK){
		mutex_unlock(&mfc_mutex);
		return ret;
	}

#if	Frame_Base_Power_CTR_ON
	clk_disable(mfc_clk);
#endif

	mutex_unlock(&mfc_mutex);

	return 0;
}
예제 #5
0
static int __init s3c_mfc_init(void)
{
	printk(banner);

#ifdef CONFIG_S3C6400_PDFW
	pd_register_dev(&s3c_mfc_pmdev, "domain_v");
	mfc_info("mfc devid = %d\n", s3c_mfc_pmdev.devid);
#endif

	if (platform_driver_register(&s3c_mfc_driver) != 0) {
		mfc_err("fail to register platform device\n");
		return -EPERM;
	}

	mfc_info("%s", banner);

	return 0;
}
예제 #6
0
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			
	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
		s5pc110_unlock_dvfs_high_level(DVFS_LOCK_TOKEN_1);
#endif
#ifdef CONFIG_PM_PWR_GATING
		s5pc110_unlock_power_domain(MFC_DOMAIN_LOCK_TOKEN);
#endif
#ifdef CONFIG_S5PC11X_LPAUDIO
		s5pc110_set_lpaudio_lock(0);
#endif /* CONFIG_S5PC11X_LPAUDIO */
	}
	
	clk_disable(mfc_clk);

	mutex_unlock(&mfc_mutex);
	return ret;
}
예제 #7
0
/* Load firmware to MFC */
int s5p_mfc_load_firmware(struct s5p_mfc_dev *dev)
{
	struct firmware *fw_blob;
	unsigned int firmware_size;
	int err;

	if (!dev) {
		mfc_err("no mfc device to run\n");
		return -EINVAL;
	}

	firmware_size = dev->variant->buf_size->firmware_code;

	/* Firmare has to be present as a separate file or compiled
	 * into kernel. */
	mfc_debug_enter();
	mfc_info("Requesting fw\n");
	err = request_firmware((const struct firmware **)&fw_blob,
					MFC_FW_NAME, 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;
	}

	mfc_debug(2, "Ret of request_firmware: %d Size: %d\n", err, fw_blob->size);

	if (fw_blob->size > firmware_size) {
		mfc_err("MFC firmware is too big to be loaded.\n");
		release_firmware(fw_blob);
		return -ENOMEM;
	}
	if (s5p_mfc_bitproc_buf == 0 || s5p_mfc_bitproc_phys == 0) {
		mfc_err("MFC firmware is not allocated or was not mapped correctly.\n");
		release_firmware(fw_blob);
		return -EINVAL;
	}
	memcpy(s5p_mfc_bitproc_virt, fw_blob->data, fw_blob->size);
	/*
	s5p_mfc_bitproc_dma = dma_map_single(dev->v4l2_dev.dev,
					     s5p_mfc_bitproc_virt,
					     FIRMWARE_CODE_SIZE,
					     DMA_TO_DEVICE);
	*/
	s5p_mfc_mem_clean_priv(s5p_mfc_bitproc_buf, s5p_mfc_bitproc_virt, 0,
			fw_blob->size);

	dev->fw.dva = s5p_mfc_bitproc_phys;
	dev->fw.kva = s5p_mfc_bitproc_virt;
	dev->fw.ctx = s5p_mfc_bitproc_buf;
	dev->fw.size = fw_blob->size;

	release_firmware(fw_blob);
	mfc_debug_leave();
	return 0;
}
예제 #8
0
static int __init mfc_init(void)
{
	mfc_info("%s\n", banner);

	if (platform_driver_register(&mfc_driver) != 0) {
		mfc_err(KERN_ERR "platform device registration failed..\n");
		return -1;
	}

	return 0;
}
예제 #9
0
파일: s5p_mfc_pm.c 프로젝트: AK101111/linux
int s5p_mfc_init_pm(struct s5p_mfc_dev *dev)
{
	int ret = 0;

	pm = &dev->pm;
	p_dev = dev;
	pm->clock_gate = clk_get(&dev->plat_dev->dev, MFC_GATE_CLK_NAME);
	if (IS_ERR(pm->clock_gate)) {
		mfc_err("Failed to get clock-gating control\n");
		ret = PTR_ERR(pm->clock_gate);
		goto err_g_ip_clk;
	}

	ret = clk_prepare(pm->clock_gate);
	if (ret) {
		mfc_err("Failed to prepare clock-gating control\n");
		goto err_p_ip_clk;
	}

	if (dev->variant->version != MFC_VERSION_V6) {
		pm->clock = clk_get(&dev->plat_dev->dev, MFC_SCLK_NAME);
		if (IS_ERR(pm->clock)) {
			mfc_info("Failed to get MFC special clock control\n");
			pm->clock = NULL;
		} else {
			clk_set_rate(pm->clock, MFC_SCLK_RATE);
			ret = clk_prepare_enable(pm->clock);
			if (ret) {
				mfc_err("Failed to enable MFC special clock\n");
				goto err_s_clk;
			}
		}
	}

	atomic_set(&pm->power, 0);
#ifdef CONFIG_PM
	pm->device = &dev->plat_dev->dev;
	pm_runtime_enable(pm->device);
#endif
#ifdef CLK_DEBUG
	atomic_set(&clk_ref, 0);
#endif
	return 0;

err_s_clk:
	clk_put(pm->clock);
	pm->clock = NULL;
err_p_ip_clk:
	clk_put(pm->clock_gate);
	pm->clock_gate = NULL;
err_g_ip_clk:
	return ret;
}
예제 #10
0
irqreturn_t mfc_irq(int irq, void *dev_id)
{
	struct mfc_dev *dev = (struct mfc_dev *)dev_id;

	r2h_cmd = read_reg(MFC_RISC2HOST_CMD);
	mfc_dbg("MFC IRQ: 0x%02x\n", r2h_cmd);

	if (((r2h_cmd >= OPEN_CH_RET) && (r2h_cmd <= CLOSE_CH_RET)) ||
	    ((r2h_cmd >= SEQ_DONE_RET) && (r2h_cmd <= EDFU_INIT_RET)) ||
	    ( r2h_cmd == ERR_RET)) {
		memset(&r2h_args, 0, sizeof(struct mfc_cmd_args));

		r2h_args.arg[0] = read_reg(MFC_RISC2HOST_ARG1);
		r2h_args.arg[1] = read_reg(MFC_RISC2HOST_ARG2);
		r2h_args.arg[2] = read_reg(MFC_RISC2HOST_ARG3);
		r2h_args.arg[3] = read_reg(MFC_RISC2HOST_ARG4);

		if (r2h_cmd == ERR_RET)
			//mfc_dbg("F/W error code: %d", r2h_args.arg[1] & 0xFFFF);
			mfc_dbg("F/W error code: 0x%08x", r2h_args.arg[1]);
	} else {
		mfc_err("Unknown R2H return value: 0x%02x\n", r2h_cmd);
	}

#ifdef MFC_PERF
	if (framecnt > 0) {
		do_gettimeofday(&tv2);

		mfc_info("%d, %ld", framecnt,
			(long)(((tv2.tv_sec * 1000000) + tv2.tv_usec) - ((tv1.tv_sec * 1000000) + tv1.tv_usec)));

		framecnt++;
	}
#endif

	/* FIXME: codec wait_queue processing */
	dev->irq_sys = 1;
	wake_up(&dev->wait_sys);

	/*
	 * FIXME: check is codec command return or error
	 * move to mfc_wait_codec() ?
	 */
	write_reg(0xFFFF, MFC_SI_RTN_CHID);

	write_reg(0, MFC_RISC2HOST_CMD);
	write_reg(0, MFC_RISC_HOST_INT);

	return IRQ_HANDLED;
}
예제 #11
0
irqreturn_t mfc_irq(int irq, void *dev_id)
{
	unsigned int int_reason;
	unsigned int err_status;

	int_reason = READL(MFC_RISC2HOST_COMMAND) & 0x1FFFF;
	err_status = READL(MFC_RISC2HOST_ARG2);

	mfc_disp_err_status = err_status >> 16;
	mfc_dec_err_status = err_status & 0xFFFF;

	mfc_debug_L0("mfc_irq() : Interrupt !! : %d\n", int_reason);

	
	if(	((int_reason & R2H_CMD_EMPTY)     						== R2H_CMD_EMPTY)      					||
		((int_reason & R2H_CMD_OPEN_INSTANCE_RET)     	== R2H_CMD_OPEN_INSTANCE_RET)      	||
		((int_reason & R2H_CMD_CLOSE_INSTANCE_RET)     	== R2H_CMD_CLOSE_INSTANCE_RET)		||
		((int_reason & R2H_CMD_ERROR_RET)     				== R2H_CMD_ERROR_RET)      				||
		((int_reason & R2H_CMD_SEQ_DONE_RET)     			== R2H_CMD_SEQ_DONE_RET)      		||
		((int_reason & R2H_CMD_FRAME_DONE_RET)     		== R2H_CMD_FRAME_DONE_RET)     		||
		((int_reason & R2H_CMD_SLICE_DONE_RET)     		== R2H_CMD_SLICE_DONE_RET)      		||
		((int_reason & R2H_CMD_ENC_COMPLETE_RET)     	== R2H_CMD_ENC_COMPLETE_RET)  		||
		((int_reason & R2H_CMD_SYS_INIT_RET)     				== R2H_CMD_SYS_INIT_RET)      			||
		((int_reason & R2H_CMD_FW_STATUS_RET)     			== R2H_CMD_FW_STATUS_RET)      		||
		((int_reason & R2H_CMD_SLEEP_RET)     				== R2H_CMD_SLEEP_RET)      				||
		((int_reason & R2H_CMD_WAKEUP_RET)     				== R2H_CMD_WAKEUP_RET)      			||
		((int_reason & R2H_CMD_FLUSH_COMMAND_RET)    	== R2H_CMD_FLUSH_COMMAND_RET) 	||
		((int_reason & R2H_CMD_CMD_ABORT_RET)     		== R2H_CMD_CMD_ABORT_RET)      		||
		((int_reason & R2H_CMD_CMD_BATCH_ENC_RET)     	== R2H_CMD_CMD_BATCH_ENC_RET) 	||
		((int_reason & R2H_CMD_INIT_BUFFERS_RET)     		== R2H_CMD_INIT_BUFFERS_RET) 			||
		((int_reason & R2H_CMD_EDFU_INT_RET)     			== R2H_CMD_EDFU_INT_RET) 				||
		((int_reason & R2H_CMD_DECODE_ERR_RET)     		== R2H_CMD_DECODE_ERR_RET))
	{
		mfc_int_type = int_reason;
		wake_up_interruptible(&mfc_wait_queue);
	}
	else
		mfc_info("Strange Interrupt !! : %d\n", int_reason);


	WRITEL(0, MFC_RISC_HOST_INT);
	WRITEL(0, MFC_RISC2HOST_COMMAND);
	WRITEL(0xffff, MFC_SI_RTN_CHID);

	return IRQ_HANDLED;
}
예제 #12
0
static void s3c_mfc_del_node_from_alloc_list(s3c_mfc_alloc_mem_t *node, int inst_no)
{
	mfc_debug("[%d]instance (uncached_p_addr : 0x%08x cached_p_addr : 0x%08x size:%d cacheflag : %d)\n",
			inst_no, node->uncached_p_addr, node->cached_p_addr, node->size, node->cache_flag);

	if(node == s3c_mfc_alloc_mem_tail){
		mfc_info("InValid node\n");
		return;
	}

	if(node == s3c_mfc_alloc_mem_head)
		s3c_mfc_alloc_mem_head = node->next;

	node->prev->next = node->next;
	node->next->prev = node->prev;

	kfree(node);
}
예제 #13
0
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;
}
예제 #14
0
static void __exit mfc_exit(void)
{
	platform_driver_unregister(&mfc_driver);
	mfc_info("FIMV MFC(Multi Function Codec) V5.x exit\n");
}
int s5p_mfc_sleep(struct s5p_mfc_dev *dev)
{
	struct s5p_mfc_ctx *ctx;
	int new_ctx;
	int ret;

	mfc_debug_enter();

	if (!dev) {
		mfc_info("No mfc device to run\n");
		ret = 0;
		return ret;
	}

	spin_lock_irq(&dev->condlock);
	new_ctx = s5p_mfc_get_new_ctx(dev);
	spin_unlock_irq(&dev->condlock);

	if (new_ctx < 0) {
		mfc_info("No ctx is scheduled to be run\n");
		ret = 0;
		return ret;
	}

	ctx = dev->ctx[new_ctx];
	if (!ctx) {
		mfc_info("No ctx: not need to enter suspend\n");
		ret = 0;
		return ret;
	}

	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("Waiting for hardware to finish timed out\n");
		ret = -EIO;
		return ret;
	}

	spin_lock(&dev->condlock);
	set_bit(ctx->num, &dev->hw_lock);
	spin_unlock(&dev->condlock);

	s5p_mfc_clock_on();
	s5p_mfc_clean_dev_int_flags(dev);
	ret = s5p_mfc_sleep_cmd(dev);
	if (ret) {
		mfc_err("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("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("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();
	mfc_debug_leave();

	return ret;
}
예제 #16
0
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;
}
/* Allocate firmware */
int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev)
{
#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
	int err;
	struct cma_info mem_info_f, mem_info_a, mem_info_b;
#endif
	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_CMA_FW_ALLOC_CTX];

#if !defined(CONFIG_VIDEOBUF2_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_VIDEOBUF2_CMA_PHYS)
	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;
	}
#endif
	mfc_info("Allocating memory for firmware.\n");

#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
	if (dev->num_drm_inst)
		alloc_ctx = dev->alloc_ctx_fw;
#endif

	s5p_mfc_bitproc_buf = s5p_mfc_mem_alloc_priv(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_daddr_priv(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_priv(s5p_mfc_bitproc_buf);
		s5p_mfc_bitproc_phys = 0;
		s5p_mfc_bitproc_buf = 0;
		return -EIO;
	}

	if (!dev->num_drm_inst) {
		s5p_mfc_bitproc_virt =
				s5p_mfc_mem_vaddr_priv(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_priv(s5p_mfc_bitproc_buf);
			s5p_mfc_bitproc_phys = 0;
			s5p_mfc_bitproc_buf = 0;
			return -EIO;
		}
	}

	dev->port_a = s5p_mfc_bitproc_phys;

#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
	if (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_VIDEOBUF2_ION)
	dev->port_b = s5p_mfc_bitproc_phys;

	mfc_info("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;
}
예제 #18
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;
}
예제 #19
0
static void __exit mfc_exit(void)
{
	platform_driver_unregister(&mfc_driver);
	mfc_info("S5PC110 MFC Driver exit.\n");
}
예제 #20
0
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;
}
예제 #21
0
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);
	}
예제 #22
0
static int mfc_open(struct inode *inode, struct file *file)
{
	mfc_inst_ctx *mfc_ctx;
	int ret;
	//struct sched_param param = { .sched_priority = 1 };

	printk("%s(%d)\n", __func__, __LINE__);
	
	mutex_lock(&mfc_mutex);

	
	if (!mfc_is_running())
	{
#ifdef CONFIG_CPU_FREQ
#if defined(CONFIG_MACH_S5PC110_P1)
		s5pc110_lock_dvfs_high_level(DVFS_LOCK_TOKEN_1, 2); // DVFS Limit 200Mhz when mfc is running
#endif
#if defined(CONFIG_MACH_S5PC110_ARIES)
		#if MAXIMUM_FREQ == 1200000
		s5pc110_lock_dvfs_high_level(DVFS_LOCK_TOKEN_1, LEV_400MHZ);
		#else
		s5pc110_lock_dvfs_high_level(DVFS_LOCK_TOKEN_1, LEV_416MHZ);
		#endif
#endif // CONFIG_MACH_S5PC110_P1
#endif
#ifdef CONFIG_S5PC11X_LPAUDIO
		s5pc110_set_lpaudio_lock(1);
#endif /* CONFIG_S5PC11X_LPAUDIO */

		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);
#endif
			ret =  -ENODEV;
			goto out_open;
		}
#if	Frame_Base_Power_CTR_ON			
			clk_disable(mfc_clk);
#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, &param);

	ret = 0;
	
out_open:
	mutex_unlock(&mfc_mutex);

	if(ret != 0)
	{
		mfc_err("MFC_OEPN_FAIL..... ret(%d) \n", ret);	
		return ret;
	}

#if	ENABLE_MFC_DD_MONITOR
		mfc_info("MFC_OEPN_OK..... ret(%d) \n", ret);
#endif		


	return ret;
}
예제 #23
0
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;
}
예제 #24
0
int mfc_init_mem_mgr(struct mfc_dev *dev)
{
	int i;
#if !defined(CONFIG_VIDEO_MFC_VCM_UMP)
	dma_addr_t base[MAX_ALLOCATION];
#else
	/* FIXME: for support user-side allocation. it's temporary solution */
	struct vcm_res	*hole;
#endif
#ifndef SYSMMU_MFC_ON
	size_t size;
#endif
#ifdef CONFIG_S5P_MEM_CMA
	struct cma_info cma_infos[2];
#ifdef CONFIG_EXYNOS4_CONTENT_PATH_PROTECTION
	size_t bound_size;
	size_t available_size;
	size_t hole_size;
#else
	int cma_index = 0;
#endif
#else
	unsigned int align_margin;
#endif

	dev->mem_ports = MFC_MAX_MEM_PORT_NUM;
	memset(dev->mem_infos, 0, sizeof(dev->mem_infos));

#ifdef SYSMMU_MFC_ON
#if defined(CONFIG_VIDEO_MFC_VCM_UMP)
	dev->vcm_info.sysmmu_vcm = vcm_create_unified(
		SZ_256M * dev->mem_ports,
			VCM_DEV_MFC,
			&mfc_vcm_driver);

	memcpy(&vcm_info, &dev->vcm_info, sizeof(struct mfc_vcm));

	dev->mem_infos[0].vcm_s = vcm_reserve(dev->vcm_info.sysmmu_vcm,
		MFC_MEMSIZE_PORT_A, 0);

	if (IS_ERR(dev->mem_infos[0].vcm_s))
		return PTR_ERR(dev->mem_infos[0].vcm_s);

	dev->mem_infos[0].base = ALIGN(dev->mem_infos[0].vcm_s->start,
		ALIGN_128KB);
	align_margin = dev->mem_infos[0].base - dev->mem_infos[0].vcm_s->start;
	/* FIXME: for offset operation. it's temporary solution */
	/*
	dev->mem_infos[0].size = MFC_MEMSIZE_PORT_A - align_margin;
	*/
	dev->mem_infos[0].size = SZ_256M - align_margin;
	dev->mem_infos[0].addr = NULL;

	/* FIXME: for support user-side allocation. it's temporary solution */
	if (MFC_MEMSIZE_PORT_A < SZ_256M)
		hole = vcm_reserve(dev->vcm_info.sysmmu_vcm,
			SZ_256M - MFC_MEMSIZE_PORT_A, 0);

	if (dev->mem_ports == 2) {
		dev->mem_infos[1].vcm_s = vcm_reserve(dev->vcm_info.sysmmu_vcm,
			MFC_MEMSIZE_PORT_B, 0);

		if (IS_ERR(dev->mem_infos[1].vcm_s)) {
			vcm_unreserve(dev->mem_infos[0].vcm_s);
			return PTR_ERR(dev->mem_infos[1].vcm_s);
		}

		dev->mem_infos[1].base = ALIGN(dev->mem_infos[1].vcm_s->start,
			ALIGN_128KB);
		align_margin = dev->mem_infos[1].base - dev->mem_infos[1].vcm_s->start;
		dev->mem_infos[1].size = MFC_MEMSIZE_PORT_B - align_margin;
		dev->mem_infos[1].addr = NULL;
	}

	/* FIXME: for support user-side allocation. it's temporary solution */
	vcm_unreserve(hole);

	dev->fw.vcm_s = mfc_vcm_bind(dev->mem_infos[0].base, MFC_FW_SYSTEM_SIZE);
	if (IS_ERR(dev->fw.vcm_s))
		return PTR_ERR(dev->fw.vcm_s);

	dev->fw.vcm_k = mfc_vcm_map(dev->fw.vcm_s->res.phys);
	if (IS_ERR(dev->fw.vcm_k)) {
		mfc_vcm_unbind(dev->fw.vcm_s, 0);
		return PTR_ERR(dev->fw.vcm_k);
	}

	/* FIXME: it's very tricky! MUST BE FIX */
	dev->mem_infos[0].addr = (unsigned char *)dev->fw.vcm_k->start;
#elif defined(CONFIG_S5P_VMEM)
	base[0] = MFC_FREEBASE;

	dev->mem_infos[0].base = ALIGN(base[0], ALIGN_128KB);
	align_margin = dev->mem_infos[0].base - base[0];
	dev->mem_infos[0].size = MFC_MEMSIZE_PORT_A - align_margin;
	dev->mem_infos[0].addr = (unsigned char *)dev->mem_infos[0].base;

	if (dev->mem_ports == 2) {
		base[1] = dev->mem_infos[0].base + dev->mem_infos[0].size;
		dev->mem_infos[1].base = ALIGN(base[1], ALIGN_128KB);
		align_margin = dev->mem_infos[1].base - base[1];
		dev->mem_infos[1].size = MFC_MEMSIZE_PORT_B - align_margin;
		dev->mem_infos[1].addr = (unsigned char *)dev->mem_infos[1].base;
	}

	dev->fw.vmem_cookie = s5p_vmem_vmemmap(MFC_FW_SYSTEM_SIZE,
		dev->mem_infos[0].base,
		dev->mem_infos[0].base + MFC_FW_SYSTEM_SIZE);

	if (!dev->fw.vmem_cookie)
		return -ENOMEM;
#else	/* not CONFIG_VIDEO_MFC_VCM_UMP && not CONFIG_S5P_VMEM */
	/* kernel virtual memory allocator */

	dev->mem_infos[0].vmalloc_addr = vmalloc(MFC_MEMSIZE_PORT_A);
	if (dev->mem_infos[0].vmalloc_addr == NULL)
		return -ENOMEM;

	base[0] = (unsigned long)dev->mem_infos[0].vmalloc_addr;
	dev->mem_infos[0].base = ALIGN(base[0], ALIGN_128KB);
	align_margin = dev->mem_infos[0].base - base[0];
	dev->mem_infos[0].size = MFC_MEMSIZE_PORT_A - align_margin;
	dev->mem_infos[0].addr = (unsigned char *)dev->mem_infos[0].base;

	if (dev->mem_ports == 2) {
		dev->mem_infos[1].vmalloc_addr = vmalloc(MFC_MEMSIZE_PORT_B);
		if (dev->mem_infos[1].vmalloc_addr == NULL) {
			vfree(dev->mem_infos[0].vmalloc_addr);
			return -ENOMEM;
		}

		base[1] = (unsigned long)dev->mem_infos[1].vmalloc_addr;
		dev->mem_infos[1].base = ALIGN(base[1], ALIGN_128KB);
		align_margin = dev->mem_infos[1].base - base[1];
		dev->mem_infos[1].size = MFC_MEMSIZE_PORT_B - align_margin;
		dev->mem_infos[1].addr = (unsigned char *)dev->mem_infos[1].base;
	}
#endif	/* end of CONFIG_VIDEO_MFC_VCM_UMP */
#else	/* not SYSMMU_MFC_ON */
	/* early allocator */
#if defined(CONFIG_S5P_MEM_CMA)
#ifdef  CONFIG_EXYNOS4_CONTENT_PATH_PROTECTION
	if (cma_info(&cma_infos[0], dev->device, "A")) {
		mfc_info("failed to get CMA info of 'mfc-secure'\n");
		return -ENOMEM;
	}

	if (cma_info(&cma_infos[1], dev->device, "B")) {
		mfc_info("failed to get CMA info of 'mfc-normal'\n");
		return -ENOMEM;
	}

	if (cma_infos[0].lower_bound > cma_infos[1].lower_bound) {
		mfc_info("'mfc-secure' region must be lower than 'mfc-normal' region\n");
		return -ENOMEM;
	}

	/*
	 * available = secure + normal
	 * bound = secure + hole + normal
	 * hole = bound - available
	 */
	available_size = cma_infos[0].free_size + cma_infos[1].free_size;
	bound_size = cma_infos[1].upper_bound - cma_infos[0].lower_bound;
	hole_size = bound_size - available_size;
	mfc_dbg("avail: 0x%08x, bound: 0x%08x offset: 0x%08x, hole: 0x%08x\n",
		available_size, bound_size, MAX_MEM_OFFSET, hole_size);

	/* re-assign actually available size */
	if (bound_size > MAX_MEM_OFFSET) {
		if (cma_infos[0].free_size > MAX_MEM_OFFSET)
			/* it will be return error */
			available_size = MAX_MEM_OFFSET;
		else if ((cma_infos[0].free_size + hole_size) >= MAX_MEM_OFFSET)
			/* it will be return error */
			available_size = cma_infos[0].free_size;
		else
			available_size -= (bound_size - MAX_MEM_OFFSET);
	}
	mfc_dbg("avail: 0x%08x\n", available_size);

	size = cma_infos[0].free_size;
	if (size > available_size) {
		mfc_info("'mfc-secure' region is too large (%d:%d)",
			size >> 10,
			MAX_MEM_OFFSET >> 10);
		return -ENOMEM;
	}
예제 #25
0
/* 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;
}
예제 #26
0
/* Initialize hardware */
int s5p_mfc_init_hw(struct s5p_mfc_dev *dev)
{
	int ret;

	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");
		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 */
	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);
		return -EIO;
	}

	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");
		return ret;
	}
	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");
		return -EIO;
	}

	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);
		return -EIO;
	}

	mfc_info("MFC F/W version : %02xyy, %02xmm, %02xdd\n",
		 MFC_GET_REG(SYS_FW_VER_YEAR),
		 MFC_GET_REG(SYS_FW_VER_MONTH),
		 MFC_GET_REG(SYS_FW_VER_DATE));

	s5p_mfc_clock_off();

	mfc_debug_leave();

	return 0;
}
예제 #27
0
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;
}
void mfc_print_shared_mem(unsigned int host_wr_addr)
{
	mfc_info("set_frame_tag          = 0x%08x\n" ,mfc_read_shared_mem_item(host_wr_addr, SET_FRAME_TAG));
	mfc_info("start_byte_num         = 0x%08x\n" ,mfc_read_shared_mem_item(host_wr_addr, START_BYTE_NUM));
	mfc_info("ext_enc_control        = 0x%08x\n" ,mfc_read_shared_mem_item(host_wr_addr, EXT_ENC_CONTROL));
	mfc_info("enc_param_change       = 0x%08x\n" ,mfc_read_shared_mem_item(host_wr_addr, ENC_PARAM_CHANGE));
	mfc_info("vop_timing             = 0x%08x\n" ,mfc_read_shared_mem_item(host_wr_addr, VOP_TIMING));
	mfc_info("hec_period             = 0x%08x\n" ,mfc_read_shared_mem_item(host_wr_addr, HEC_PERIOD));
	mfc_info("p_b_frame_qp           = 0x%08x\n" ,mfc_read_shared_mem_item(host_wr_addr, P_B_FRAME_QP));
	mfc_info("metadata_enable        = 0x%08x\n" ,mfc_read_shared_mem_item(host_wr_addr, METADATA_ENABLE));
	mfc_info("ext_metadata_start_addr= 0x%08x\n" ,mfc_read_shared_mem_item(host_wr_addr, EXT_METADATA_START_ADDR));
	mfc_info("put_extradata          = 0x%08x\n" ,mfc_read_shared_mem_item(host_wr_addr, PUT_EXTRADATA));
	mfc_info("dbg_info_input0        = 0x%08x\n" ,mfc_read_shared_mem_item(host_wr_addr, DBG_INFO_INPUT0));
	mfc_info("dbg_info_input1        = 0x%08x\n" ,mfc_read_shared_mem_item(host_wr_addr, DBG_INFO_INPUT1));
	mfc_info("luma_dpb_size          = 0x%08x\n" ,mfc_read_shared_mem_item(host_wr_addr, ALLOCATED_LUMA_DPB_SIZE));
	mfc_info("chroma_dpb_size        = 0x%08x\n" ,mfc_read_shared_mem_item(host_wr_addr, ALLOCATED_CHROMA_DPB_SIZE));
	mfc_info("mv_size                = 0x%08x\n" ,mfc_read_shared_mem_item(host_wr_addr, ALLOCATED_MV_SIZE));
	mfc_info("extended_decode_status = 0x%08x\n" ,mfc_read_shared_mem_item(host_wr_addr, EXTENEDED_DECODE_STATUS));
	mfc_info("get_frame_tag_top      = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, GET_FRAME_TAG_TOP));
	mfc_info("get_frame_tag_bot      = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, GET_FRAME_TAG_BOT));
	mfc_info("pic_time_top           = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, PIC_TIME_TOP));
	mfc_info("pic_time_bot           = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, PIC_TIME_BOT));
	mfc_info("start_byte_num         = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, START_BYTE_NUM));
	mfc_info("dec_frm_size           = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, DEC_FRM_SIZE));
	mfc_info("crop_info1             = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, CROP_INFO1));
	mfc_info("crop_info2             = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, CROP_INFO2));
	mfc_info("metadata_status        = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, METADATA_STATUS));
	mfc_info("metadata_display_index = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, METADATA_DISPLAY_INDEX));
	mfc_info("dbg_info_output0       = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, DBG_INFO_OUTPUT0));
	mfc_info("dbg_info_output1       = 0x%08x\n", mfc_read_shared_mem_item(host_wr_addr, DBG_INFO_OUTPUT1));
	mfc_info("720p_limit_enable        = 0x%08x\n" ,mfc_read_shared_mem_item(host_wr_addr, P720_LIMIT_ENABLE));	
	mfc_info("RC_CONTROL_ENABLE      = 0x%08x\n" ,mfc_read_shared_mem_item(host_wr_addr, RC_CONTROL_ENABLE));	
}
예제 #29
0
/* Initialize hardware */
int s5p_mfc_init_hw(struct s5p_mfc_dev *dev)
{
	char fimv_info;
	int fw_ver;
	int ret = 0;

	mfc_debug_enter();

	if (!dev) {
		mfc_err("no mfc device to run\n");
		return -EINVAL;
	}

	/* 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);
	s5p_mfc_clean_dev_int_flags(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;
		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;
	}

	fimv_info = MFC_GET_REG(SYS_FW_FIMV_INFO);
	if (fimv_info != 'D' && fimv_info != 'E')
		fimv_info = 'N';

	mfc_info("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("Invalid F/W version(0x%x) for MFC H/W(0x%x)\n",
					fw_ver, mfc_version(dev));
			ret = -EIO;
			goto err_init_hw;
		}
	}

err_init_hw:
	s5p_mfc_clock_off();
	mfc_debug_leave();

	return ret;
}
예제 #30
0
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, &param);

	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;
}