Esempio n. 1
0
static MFC_ERROR_CODE s3c_mfc_set_dec_frame_buffer(s3c_mfc_inst_ctx  *MfcCtx, int buf_addr, unsigned int buf_size)
{
	unsigned int    Width, Height, FrameSize, dec_dpb_addr;


	mfc_debug("buf_addr : 0x%08x  buf_size : %d\n", buf_addr, buf_size);

	Width = (MfcCtx->img_width + 15)/16*16;
	Height = (MfcCtx->img_height + 31)/32*32;
	FrameSize = (Width*Height*3)>>1;

	mfc_debug("width : %d height : %d framesize : %d buf_size : %d MfcCtx->DPBCnt :%d\n", \
								Width, Height, FrameSize, buf_size, MfcCtx->DPBCnt);
	if(buf_size < FrameSize*MfcCtx->totalDPBCnt){
		mfc_err("MFCINST_ERR_FRM_BUF_SIZE\n");
		return MFCINST_ERR_FRM_BUF_SIZE;
	}

	WRITEL(Align(buf_addr, BUF_ALIGN_UNIT), S3C_FIMV_DEC_DPB_ADR);
	dec_dpb_addr = READL(S3C_FIMV_DEC_DPB_ADR);
	WRITEL(Align(dec_dpb_addr + FrameSize*MfcCtx->DPBCnt, BUF_ALIGN_UNIT), S3C_FIMV_DPB_COMV_ADR);

	if((MfcCtx->MfcCodecType == MPEG4_DEC) 
			||(MfcCtx->MfcCodecType == MPEG2_DEC) 
			||(MfcCtx->MfcCodecType == XVID_DEC) 
			||(MfcCtx->MfcCodecType == DIVX_DEC) ) {
		dec_dpb_addr = READL(S3C_FIMV_DEC_DPB_ADR);
		WRITEL(Align(dec_dpb_addr + ((3*FrameSize*MfcCtx->DPBCnt)>>1), BUF_ALIGN_UNIT), S3C_FIMV_POST_ADR);
	}
Esempio n. 2
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;
	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;
	}
#ifdef CONFIG_MACH_ARIES
	mfc_ctx->port0_mmap_size = mfc_port0_memsize - firmware_size;
#else // CONFIG_MACH_P1
	mfc_ctx->port0_mmap_size = (vir_size / 2);
#endif

	vma->vm_flags |= VM_RESERVED | VM_IO;
	if (mfc_ctx->buf_type != MFC_BUFFER_CACHE)
		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;
	if (mfc_ctx->buf_type != MFC_BUFFER_CACHE)
		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;
}
/* Remove Fragmentation in FreeMemList */
void s3c_mfc_merge_frag(int inst_no)
{
	s3c_mfc_free_mem_t *node1, *node2;

	node1 = s3c_mfc_free_mem_head;

	while (node1 != s3c_mfc_free_mem_tail) {
		node2 = s3c_mfc_free_mem_head;
		while (node2 != s3c_mfc_free_mem_tail) {
			if ((node1->start_addr + node1->size == node2->start_addr) && (node1->cache_flag == node2->cache_flag)) {
				node1->size += node2->size;
				mfc_debug("find merge area !! ( node1->start_addr + node1->size == node2->start_addr)\n");
				s3c_mfc_del_node_from_free_list(node2, inst_no);
				break;
			} else if((node1->start_addr == node2->start_addr + node2->size) && 
						(node1->cache_flag == node2->cache_flag) ) {
				mfc_debug("find merge area !! ( node1->start_addr == node2->start_addr + node2->size)\n");
				node1->start_addr = node2->start_addr;
				node1->size += node2->size;
				s3c_mfc_del_node_from_free_list(node2, inst_no);
				break;
			}
			node2 = node2->next;
		}
		node1 = node1->next;
	}
}
int s5p_mfc_clock_on(struct s5p_mfc_dev *dev)
{
	int ret = 0;
	int state, val;
	unsigned long flags;

	dev->pm.clock_on_steps = 1;
	MFC_TRACE_DEV("++ clock_on: Set clock rate(%d)\n", dev->curr_rate);
	ret = clk_enable(dev->pm.clock);
	if (ret < 0)
		return ret;

	if (dev->pm.base_type != MFCBUF_INVALID)
		s5p_mfc_init_memctrl(dev, dev->pm.base_type);

	dev->pm.clock_on_steps |= 0x1 << 1;
	if (dev->curr_ctx_drm && dev->is_support_smc) {
		spin_lock_irqsave(&dev->pm.clklock, flags);
		mfc_debug(3, "Begin: enable protection\n");
		ret = exynos_smc(SMC_PROTECTION_SET, 0,
					dev->id, SMC_PROTECTION_ENABLE);
		dev->pm.clock_on_steps |= 0x1 << 2;
		if (!ret) {
			printk("Protection Enable failed! ret(%u)\n", ret);
			spin_unlock_irqrestore(&dev->pm.clklock, flags);
			clk_disable(dev->pm.clock);
			return -EACCES;
		}
		mfc_debug(3, "End: enable protection\n");
		spin_unlock_irqrestore(&dev->pm.clklock, flags);
	} else {
		ret = s5p_mfc_mem_resume(dev->alloc_ctx[0]);
		if (ret < 0) {
			dev->pm.clock_on_steps |= 0x1 << 3;
			clk_disable(dev->pm.clock);
			return ret;
		}
	}

	dev->pm.clock_on_steps |= 0x1 << 4;
	if (IS_MFCV6(dev)) {
		spin_lock_irqsave(&dev->pm.clklock, flags);
		if ((atomic_inc_return(&dev->clk_ref) == 1) &&
				FW_HAS_BUS_RESET(dev)) {
			val = s5p_mfc_read_reg(dev, S5P_FIMV_MFC_BUS_RESET_CTRL);
			val &= ~(0x1);
			s5p_mfc_write_reg(dev, val, S5P_FIMV_MFC_BUS_RESET_CTRL);
		}
		spin_unlock_irqrestore(&dev->pm.clklock, flags);
	} else {
		atomic_inc_return(&dev->clk_ref);
	}

	dev->pm.clock_on_steps |= 0x1 << 5;
	state = atomic_read(&dev->clk_ref);
	mfc_debug(2, "+ %d\n", state);
	MFC_TRACE_DEV("-- clock_on : ref state(%d)\n", state);

	return 0;
}
void s5p_mfc_init_memctrl(struct s5p_mfc_dev *dev,
					enum mfc_buf_usage_type buf_type)
{
	struct s5p_mfc_extra_buf *fw_info;

	fw_info = &dev->fw_info;

	if (IS_MFCV6(dev)) {
#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
		if (buf_type == MFCBUF_DRM)
			fw_info = &dev->drm_fw_info;

		s5p_mfc_write_reg(dev, fw_info->ofs, S5P_FIMV_RISC_BASE_ADDRESS);
		mfc_info_dev("[%d] Base Address : %08lx\n", buf_type, fw_info->ofs);
#else
		s5p_mfc_write_reg(dev, dev->port_a, S5P_FIMV_RISC_BASE_ADDRESS);
		mfc_debug(2, "Base Address : %08zu\n", dev->port_a);
#endif
	} else {
		/* channelA, port0 */
		s5p_mfc_write_reg(dev, dev->port_a, S5P_FIMV_MC_DRAMBASE_ADR_A);
		/* channelB, port1 */
		s5p_mfc_write_reg(dev, dev->port_b, S5P_FIMV_MC_DRAMBASE_ADR_B);

		mfc_debug(2, "Port A: %08zu, Port B: %08zu\n", dev->port_a, dev->port_b);
	}
}
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");
		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);

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

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

	s5p_mfc_clock_off();

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

	mfc_debug_leave();

	return 0;
}
static unsigned int s3c_mfc_get_mem_area(int allocSize, int inst_no, char cache_flag)
{
	s3c_mfc_free_mem_t	*node, *match_node = NULL;
	unsigned int	allocAddr = 0;


	mfc_debug("request Size : %ld\n", allocSize);

	if (s3c_mfc_free_mem_head == s3c_mfc_free_mem_tail) {
		mfc_err("all memory is gone\n");
		return(allocAddr);
	}

	/* find best chunk of memory */
	for (node = s3c_mfc_free_mem_head; node != s3c_mfc_free_mem_tail; node = node->next) {
		if (match_node != NULL) {
			if (cache_flag) {
				if ((node->size >= allocSize) && (node->size < match_node->size) && (node->cache_flag))
					match_node = node;
			} else {
				if ((node->size >= allocSize) && (node->size < match_node->size) && (!node->cache_flag))
					match_node = node;
			}
		} else {
			if (cache_flag) {
				if ((node->size >= allocSize) && (node->cache_flag))
					match_node = node;
			} else {
				if ((node->size >= allocSize) && (!node->cache_flag))
					match_node = node;
			}
		}
	}

	if (match_node != NULL) {
		mfc_debug("match : startAddr(0x%08x) size(%ld) cache flag(%d)\n", 
			match_node->start_addr, match_node->size, match_node->cache_flag);
	}

	/* rearange FreeMemArea */
	if (match_node != NULL) {
		allocAddr = match_node->start_addr;
		match_node->start_addr += allocSize;
		match_node->size -= allocSize;

		if(match_node->size == 0)          /* delete match_node. */
			s3c_mfc_del_node_from_free_list(match_node, inst_no);

		return(allocAddr);
	} else {
		printk("there is no suitable chunk\n");
		return 0;
	}

	return(allocAddr);
}
int s5p_mfc_clock_on(struct s5p_mfc_dev *dev)
{
	int ret = 0;
	int state, val;
	unsigned long flags;

#ifdef CONFIG_MFC_USE_BUS_DEVFREQ
	MFC_TRACE_DEV("++ clock_on: Set clock rate(%d)\n", dev->curr_rate);
	mutex_lock(&dev->curr_rate_lock);
	s5p_mfc_clock_set_rate(dev, dev->curr_rate);
	mutex_unlock(&dev->curr_rate_lock);
#endif
	ret = clk_enable(dev->pm.clock);
	if (ret < 0)
		return ret;

	if (dev->curr_ctx_drm && dev->is_support_smc) {
		spin_lock_irqsave(&dev->pm.clklock, flags);
		mfc_debug(3, "Begin: enable protection\n");
		ret = exynos_smc(SMC_PROTECTION_SET, 0,
					dev->id, SMC_PROTECTION_ENABLE);
		if (!ret) {
			printk("Protection Enable failed! ret(%u)\n", ret);
			spin_unlock_irqrestore(&dev->pm.clklock, flags);
			clk_disable(dev->pm.clock);
			return ret;
		}
		mfc_debug(3, "End: enable protection\n");
		spin_unlock_irqrestore(&dev->pm.clklock, flags);
	} else {
		ret = s5p_mfc_mem_resume(dev->alloc_ctx[0]);
		if (ret < 0) {
			clk_disable(dev->pm.clock);
			return ret;
		}
	}

	if (IS_MFCV6(dev)) {
		spin_lock_irqsave(&dev->pm.clklock, flags);
		if ((atomic_inc_return(&dev->clk_ref) == 1) &&
				FW_HAS_BUS_RESET(dev)) {
			val = s5p_mfc_read_reg(dev, S5P_FIMV_MFC_BUS_RESET_CTRL);
			val &= ~(0x1);
			s5p_mfc_write_reg(dev, val, S5P_FIMV_MFC_BUS_RESET_CTRL);
		}
		spin_unlock_irqrestore(&dev->pm.clklock, flags);
	} else {
		atomic_inc_return(&dev->clk_ref);
	}

	state = atomic_read(&dev->clk_ref);
	mfc_debug(2, "+ %d\n", state);
	MFC_TRACE_DEV("-- clock_on : ref state(%d)\n", state);

	return 0;
}
void s5p_mfc_clock_off(struct s5p_mfc_dev *dev)
{
	int state, val;
	unsigned long timeout, flags;
	int ret = 0;

	if (IS_MFCV6(dev)) {
		spin_lock_irqsave(&dev->pm.clklock, flags);
		if ((atomic_dec_return(&dev->clk_ref) == 0) &&
				FW_HAS_BUS_RESET(dev)) {
			s5p_mfc_write_reg(dev, 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_dev("Timeout while resetting MFC.\n");
					break;
				}
				val = s5p_mfc_read_reg(dev,
						S5P_FIMV_MFC_BUS_RESET_CTRL);
			} while ((val & 0x2) == 0);
		}
		spin_unlock_irqrestore(&dev->pm.clklock, flags);
	} else {
		atomic_dec_return(&dev->clk_ref);
	}

	state = atomic_read(&dev->clk_ref);
	if (state < 0) {
		mfc_err_dev("Clock state is wrong(%d)\n", state);
		atomic_set(&dev->clk_ref, 0);
	} else {
		if (dev->curr_ctx_drm && dev->is_support_smc) {
			mfc_debug(3, "Begin: disable protection\n");
			spin_lock_irqsave(&dev->pm.clklock, flags);
			ret = exynos_smc(SMC_PROTECTION_SET, 0,
					dev->id, SMC_PROTECTION_DISABLE);
			if (!ret) {
				printk("Protection Disable failed! ret(%u)\n", ret);
				spin_unlock_irqrestore(&dev->pm.clklock, flags);
				clk_disable(dev->pm.clock);
				return;
			}
			mfc_debug(3, "End: disable protection\n");
			spin_unlock_irqrestore(&dev->pm.clklock, flags);
		} else {
			s5p_mfc_mem_suspend(dev->alloc_ctx[0]);
		}
		clk_disable(dev->pm.clock);
	}
	mfc_debug(2, "- %d\n", state);
}
Esempio n. 10
0
static int reqbufs_capture(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx,
				struct v4l2_requestbuffers *reqbufs)
{
	int ret = 0;

	s5p_mfc_clock_on();

	if (reqbufs->count == 0) {
		mfc_debug(2, "Freeing buffers\n");
		ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
		if (ret)
			goto out;
		s5p_mfc_hw_call_void(dev->mfc_ops, release_codec_buffers, ctx);
		ctx->dst_bufs_cnt = 0;
	} else if (ctx->capture_state == QUEUE_FREE) {
		WARN_ON(ctx->dst_bufs_cnt != 0);
		mfc_debug(2, "Allocating %d buffers for CAPTURE queue\n",
				reqbufs->count);
		ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
		if (ret)
			goto out;

		ctx->capture_state = QUEUE_BUFS_REQUESTED;
		ctx->total_dpb_count = reqbufs->count;

		ret = s5p_mfc_hw_call(dev->mfc_ops, alloc_codec_buffers, ctx);
		if (ret) {
			mfc_err("Failed to allocate decoding buffers\n");
			reqbufs->count = 0;
			vb2_reqbufs(&ctx->vq_dst, reqbufs);
			ret = -ENOMEM;
			ctx->capture_state = QUEUE_FREE;
			goto out;
		}

		WARN_ON(ctx->dst_bufs_cnt != ctx->total_dpb_count);
		ctx->capture_state = QUEUE_BUFS_MMAPED;

		if (s5p_mfc_ctx_ready(ctx))
			set_work_bit_irqsave(ctx);
		s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
		s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_INIT_BUFFERS_RET,
					  0);
	} else {
		mfc_err("Buffers have already been requested\n");
		ret = -EINVAL;
	}
out:
	s5p_mfc_clock_off();
	if (ret)
		mfc_err("Failed allocating buffers for CAPTURE queue\n");
	return ret;
}
Esempio n. 11
0
static inline void s5p_mfc_init_memctrl(struct s5p_mfc_dev *dev)
{
    if (IS_MFCV6_PLUS(dev)) {
        mfc_write(dev, dev->bank1, S5P_FIMV_RISC_BASE_ADDRESS_V6);
        mfc_debug(2, "Base Address : %pad\n", &dev->bank1);
    } else {
        mfc_write(dev, dev->bank1, S5P_FIMV_MC_DRAMBASE_ADR_A);
        mfc_write(dev, dev->bank2, S5P_FIMV_MC_DRAMBASE_ADR_B);
        mfc_debug(2, "Bank1: %pad, Bank2: %pad\n",
                  &dev->bank1, &dev->bank2);
    }
}
Esempio n. 12
0
static void s5p_mfc_handle_frame_all_extracted(struct s5p_mfc_ctx *ctx)
{
	struct s5p_mfc_dec *dec = ctx->dec_priv;
	struct s5p_mfc_buf *dst_buf;
	int index, is_first = 1;

	mfc_debug(2, "Decided to finish\n");
	ctx->sequence++;
	while (!list_empty(&ctx->dst_queue)) {
		dst_buf = list_entry(ctx->dst_queue.next,
				     struct s5p_mfc_buf, list);
		mfc_debug(2, "Cleaning up buffer: %d\n",
					  dst_buf->vb.v4l2_buf.index);
		vb2_set_plane_payload(&dst_buf->vb, 0, 0);
		vb2_set_plane_payload(&dst_buf->vb, 1, 0);
		list_del(&dst_buf->list);
		ctx->dst_queue_cnt--;
		dst_buf->vb.v4l2_buf.sequence = (ctx->sequence++);

		if (s5p_mfc_read_info(ctx, PIC_TIME_TOP) ==
			s5p_mfc_read_info(ctx, PIC_TIME_BOT))
			dst_buf->vb.v4l2_buf.field = V4L2_FIELD_NONE;
		else
			dst_buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED;

		clear_bit(dst_buf->vb.v4l2_buf.index, &dec->dpb_status);

		index = dst_buf->vb.v4l2_buf.index;
		if (call_cop(ctx, get_buf_ctrls_val, ctx, &ctx->dst_ctrls[index]) < 0)
			mfc_err("failed in get_buf_ctrls_val\n");

		if (is_first) {
			call_cop(ctx, get_buf_update_val, ctx,
				&ctx->dst_ctrls[index],
				V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG,
				dec->eos_tag);
			is_first = 0;
		} else {
			call_cop(ctx, get_buf_update_val, ctx,
				&ctx->dst_ctrls[index],
				V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG,
				DEFAULT_TAG);
		}

		vb2_buffer_done(&dst_buf->vb, VB2_BUF_STATE_DONE);
		mfc_debug(2, "Cleaned up buffer: %d\n",
			  dst_buf->vb.v4l2_buf.index);
	}
	if (ctx->state != MFCINST_ABORT && ctx->state != MFCINST_RES_CHANGE_FLUSH)
		ctx->state = MFCINST_RUNNING;
	mfc_debug(2, "After cleanup\n");
}
Esempio n. 13
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_debug(2, "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);
	release_firmware(fw_blob);
	mfc_debug_leave();
	return 0;
}
Esempio n. 14
0
static inline void s5p_mfc_init_memctrl(struct s5p_mfc_dev *dev)
{
	if (IS_MFCV6(dev)) {
		s5p_mfc_write_reg(dev->port_a, S5P_FIMV_RISC_BASE_ADDRESS);
		mfc_debug(2, "Base Address : %08x\n", dev->port_a);
	} else {
		/* channelA, port0 */
		s5p_mfc_write_reg(dev->port_a, S5P_FIMV_MC_DRAMBASE_ADR_A);
		/* channelB, port1 */
		s5p_mfc_write_reg(dev->port_b, S5P_FIMV_MC_DRAMBASE_ADR_B);

		mfc_debug(2, "Port A: %08x, Port B: %08x\n", dev->port_a, dev->port_b);
	}
}
Esempio n. 15
0
static int reqbufs_output(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx,
				struct v4l2_requestbuffers *reqbufs)
{
	int ret = 0;

	s5p_mfc_clock_on();

	if (reqbufs->count == 0) {
		mfc_debug(2, "Freeing buffers\n");
		ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
		if (ret)
			goto out;
		s5p_mfc_close_mfc_inst(dev, ctx);
		ctx->src_bufs_cnt = 0;
		ctx->output_state = QUEUE_FREE;
	} else if (ctx->output_state == QUEUE_FREE) {
		/* Can only request buffers when we have a valid format set. */
		WARN_ON(ctx->src_bufs_cnt != 0);
		if (ctx->state != MFCINST_INIT) {
			mfc_err("Reqbufs called in an invalid state\n");
			ret = -EINVAL;
			goto out;
		}

		mfc_debug(2, "Allocating %d buffers for OUTPUT queue\n",
				reqbufs->count);
		ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
		if (ret)
			goto out;

		ret = s5p_mfc_open_mfc_inst(dev, ctx);
		if (ret) {
			reqbufs->count = 0;
			vb2_reqbufs(&ctx->vq_src, reqbufs);
			goto out;
		}

		ctx->output_state = QUEUE_BUFS_REQUESTED;
	} else {
		mfc_err("Buffers have already been requested\n");
		ret = -EINVAL;
	}
out:
	s5p_mfc_clock_off();
	if (ret)
		mfc_err("Failed allocating buffers for OUTPUT queue\n");
	return ret;
}
/* Open a new instance and get its number */
int s5p_mfc_open_inst_cmd(struct s5p_mfc_ctx *ctx)
{
	struct s5p_mfc_cmd_args h2r_args;
	unsigned int crc = 0;
	struct s5p_mfc_dec *dec = ctx->dec_priv;
	int ret;

	mfc_debug_enter();

	mfc_debug(2, "Requested codec mode: %d\n", ctx->codec_mode);

	if (ctx->type == MFCINST_DECODER)
		crc = dec->crc_enable;

	memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
	h2r_args.arg[0] = ctx->codec_mode;
	h2r_args.arg[1] = crc << 31; /* no pixelcache */
	h2r_args.arg[2] = ctx->ctx.ofs;
	h2r_args.arg[3] = ctx->ctx_buf_size;

	ret = s5p_mfc_cmd_host2risc(S5P_FIMV_H2R_CMD_OPEN_INSTANCE, &h2r_args);

	mfc_debug_leave();

	return ret;
}
Esempio n. 17
0
/* Try format */
static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
{
	struct s5p_mfc_dev *dev = video_drvdata(file);
	struct s5p_mfc_fmt *fmt;

	mfc_debug(2, "Type is %d\n", f->type);
	if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
		fmt = find_format(f, MFC_FMT_DEC);
		if (!fmt) {
			mfc_err("Unsupported format for source.\n");
			return -EINVAL;
		}
		if (fmt->codec_mode == S5P_FIMV_CODEC_NONE) {
			mfc_err("Unknown codec\n");
			return -EINVAL;
		}
		if ((dev->variant->version_bit & fmt->versions) == 0) {
			mfc_err("Unsupported format by this MFC version.\n");
			return -EINVAL;
		}
	} else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
		fmt = find_format(f, MFC_FMT_RAW);
		if (!fmt) {
			mfc_err("Unsupported format for destination.\n");
			return -EINVAL;
		}
		if ((dev->variant->version_bit & fmt->versions) == 0) {
			mfc_err("Unsupported format by this MFC version.\n");
			return -EINVAL;
		}
	}

	return 0;
}
Esempio n. 18
0
static int s5p_mfc_close_inst_cmd_v5(struct s5p_mfc_ctx *ctx)
{
	struct s5p_mfc_dev *dev = ctx->dev;
	struct s5p_mfc_cmd_args h2r_args;
	int ret;

	if (ctx->state == MFCINST_FREE) {
		mfc_err("Instance already returned\n");
		ctx->state = MFCINST_ERROR;
		return -EINVAL;
	}
	/* Closing decoding instance  */
	mfc_debug(2, "Returning instance number %d\n", ctx->inst_no);
	dev->curr_ctx = ctx->num;
	memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
	h2r_args.arg[0] = ctx->inst_no;
	ret = s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_CLOSE_INSTANCE,
								&h2r_args);
	if (ret) {
		mfc_err("Failed to return an instance\n");
		ctx->state = MFCINST_ERROR;
		return -EINVAL;
	}
	return 0;
}
int s5p_mfc_init_shm(struct s5p_mfc_ctx *ctx)
{
	struct s5p_mfc_dev *dev = ctx->dev;
	struct s5p_mfc_buf_size_v5 *buf_size = dev->variant->buf_size->buf;
	void *shm_alloc_ctx = dev->alloc_ctx[MFC_CMA_BANK1_ALLOC_CTX];

	ctx->shm.alloc = s5p_mfc_mem_alloc(shm_alloc_ctx, buf_size->shared_buf);
	if (IS_ERR(ctx->shm.alloc)) {
		mfc_err("failed to allocate shared memory\n");
		return PTR_ERR(ctx->shm.alloc);
	}

	/* shm_ofs only keeps the offset from base (port a) */
	ctx->shm.ofs = s5p_mfc_mem_daddr(ctx->shm.alloc) - dev->port_a;
	ctx->shm.virt = s5p_mfc_mem_vaddr(ctx->shm.alloc);
	if (!ctx->shm.virt) {
		s5p_mfc_mem_free(ctx->shm.alloc);
		ctx->shm.ofs = 0;
		ctx->shm.alloc = NULL;

		mfc_err("failed to virt addr of shared memory\n");
		return -ENOMEM;
	}

	memset((void *)ctx->shm.virt, 0, buf_size->shared_buf);
	s5p_mfc_cache_clean_priv(ctx->shm.alloc);

	mfc_debug(2, "shm info addr: 0x%08x, phys: 0x%08lx\n",
		 (unsigned int)ctx->shm.virt, ctx->shm.ofs);

	return 0;
}
Esempio n. 20
0
int s5p_mfc_alloc_priv_buf(struct device *dev,
					struct s5p_mfc_priv_buf *b)
{

	mfc_debug(3, "Allocating priv: %d\n", b->size);

	b->virt = dma_alloc_coherent(dev, b->size, &b->dma, GFP_KERNEL);

	if (!b->virt) {
		mfc_err("Allocating private buffer failed\n");
		return -ENOMEM;
	}

	mfc_debug(3, "Allocated addr %p %08x\n", b->virt, b->dma);
	return 0;
}
/* Open a new instance and get its number */
int s5p_mfc_open_inst_cmd(struct s5p_mfc_ctx *ctx)
{
	struct s5p_mfc_dev *dev;
	int ret;

	mfc_debug_enter();

	if (!ctx) {
		mfc_err("no mfc context to run\n");
		return -EINVAL;
	}
	dev = ctx->dev;
	mfc_debug(2, "Requested codec mode: %d\n", ctx->codec_mode);

	s5p_mfc_write_reg(dev, ctx->codec_mode, S5P_FIMV_CODEC_TYPE);
	s5p_mfc_write_reg(dev, ctx->ctx.ofs, S5P_FIMV_CONTEXT_MEM_ADDR);
	s5p_mfc_write_reg(dev, ctx->ctx_buf_size, S5P_FIMV_CONTEXT_MEM_SIZE);
	if (ctx->type == MFCINST_DECODER)
		s5p_mfc_write_reg(dev, ctx->dec_priv->crc_enable,
							S5P_FIMV_D_CRC_CTRL);

	ret = s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_OPEN_INSTANCE, NULL);

	mfc_debug_leave();

	return ret;
}
Esempio n. 22
0
static int s5p_mfc_v8_wait_wakeup(struct s5p_mfc_dev *dev)
{
	int ret;

	/* Release reset signal to the RISC */
	dev->risc_on = 1;
	mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6);

	if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_FW_STATUS_RET)) {
		mfc_err("Failed to reset MFCV8\n");
		return -EIO;
	}
	mfc_debug(2, "Write command to wakeup MFCV8\n");
	ret = s5p_mfc_hw_call(dev->mfc_cmds, wakeup_cmd, dev);
	if (ret) {
		mfc_err("Failed to send command to MFCV8 - timeout\n");
		return ret;
	}

	if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_WAKEUP_RET)) {
		mfc_err("Failed to wakeup MFC\n");
		return -EIO;
	}
	return ret;
}
Esempio n. 23
0
/* Try format */
static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
{
	struct s5p_mfc_dev *dev = video_drvdata(file);
	struct s5p_mfc_fmt *fmt;

	mfc_debug(2, "Type is %d\n", f->type);
	if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
		fmt = find_format(f, MFC_FMT_DEC);
		if (!fmt) {
			mfc_err("Unsupported format for source.\n");
			return -EINVAL;
		}
		if (!IS_MFCV6(dev) && (fmt->fourcc == V4L2_PIX_FMT_VP8)) {
			mfc_err("Not supported format.\n");
			return -EINVAL;
		}
	} else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
		fmt = find_format(f, MFC_FMT_RAW);
		if (!fmt) {
			mfc_err("Unsupported format for destination.\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;
		}
	}

	return 0;
}
Esempio n. 24
0
/* Get cropping information */
static int vidioc_g_crop(struct file *file, void *priv,
		struct v4l2_crop *cr)
{
	struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
	struct s5p_mfc_dev *dev = ctx->dev;
	u32 left, right, top, bottom;

	if (ctx->state != MFCINST_HEAD_PARSED &&
	ctx->state != MFCINST_RUNNING && ctx->state != MFCINST_FINISHING
					&& ctx->state != MFCINST_FINISHED) {
			mfc_err("Cannont set crop\n");
			return -EINVAL;
		}
	if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_H264) {
		left = s5p_mfc_hw_call(dev->mfc_ops, get_crop_info_h, ctx);
		right = left >> S5P_FIMV_SHARED_CROP_RIGHT_SHIFT;
		left = left & S5P_FIMV_SHARED_CROP_LEFT_MASK;
		top = s5p_mfc_hw_call(dev->mfc_ops, get_crop_info_v, ctx);
		bottom = top >> S5P_FIMV_SHARED_CROP_BOTTOM_SHIFT;
		top = top & S5P_FIMV_SHARED_CROP_TOP_MASK;
		cr->c.left = left;
		cr->c.top = top;
		cr->c.width = ctx->img_width - left - right;
		cr->c.height = ctx->img_height - top - bottom;
		mfc_debug(2, "Cropping info [h264]: l=%d t=%d "
			"w=%d h=%d (r=%d b=%d fw=%d fh=%d\n", left, top,
			cr->c.width, cr->c.height, right, bottom,
			ctx->buf_width, ctx->buf_height);
	} else {
Esempio n. 25
0
int s5p_mfc_wait_for_done_ctx(struct s5p_mfc_ctx *ctx,
				    int command, int interrupt)
{
	int ret;

	if (interrupt) {
		ret = wait_event_interruptible_timeout(ctx->queue,
				(ctx->int_cond && (ctx->int_type == command
			|| ctx->int_type == S5P_MFC_R2H_CMD_ERR_RET)),
					msecs_to_jiffies(MFC_INT_TIMEOUT));
	} else {
		ret = wait_event_timeout(ctx->queue,
				(ctx->int_cond && (ctx->int_type == command
			|| ctx->int_type == S5P_MFC_R2H_CMD_ERR_RET)),
					msecs_to_jiffies(MFC_INT_TIMEOUT));
	}
	if (ret == 0) {
		mfc_err("Interrupt (ctx->int_type:%d, command:%d) timed out\n",
							ctx->int_type, command);
		return 1;
	} else if (ret == -ERESTARTSYS) {
		mfc_err("Interrupted by a signal\n");
		return 1;
	}
	mfc_debug(1, "Finished waiting (ctx->int_type:%d, command: %d)\n",
							ctx->int_type, command);
	if (ctx->int_type == S5P_MFC_R2H_CMD_ERR_RET)
		return 1;
	return 0;
}
Esempio n. 26
0
/* Query buffer */
static int vidioc_querybuf(struct file *file, void *priv,
						   struct v4l2_buffer *buf)
{
	struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
	int ret;
	int i;

	if (buf->memory != V4L2_MEMORY_MMAP) {
		mfc_err("Only mmaped buffers can be used\n");
		return -EINVAL;
	}
	mfc_debug(2, "State: %d, buf->type: %d\n", ctx->state, buf->type);
	if (ctx->state == MFCINST_INIT &&
			buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
		ret = vb2_querybuf(&ctx->vq_src, buf);
	} else if (ctx->state == MFCINST_RUNNING &&
			buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
		ret = vb2_querybuf(&ctx->vq_dst, buf);
		for (i = 0; i < buf->length; i++)
			buf->m.planes[i].m.mem_offset += DST_QUEUE_OFF_BASE;
	} else {
		mfc_err("vidioc_querybuf called in an inappropriate state\n");
		ret = -EINVAL;
	}
	mfc_debug_leave();
	return ret;
}
Esempio n. 27
0
/* Check whether a context should be run on hardware */
static int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx)
{
	/* Context is to parse header */
	if (ctx->src_queue_cnt >= 1 && ctx->state == MFCINST_GOT_INST)
		return 1;
	/* Context is to decode a frame */
	if (ctx->src_queue_cnt >= 1 &&
	    ctx->state == MFCINST_RUNNING &&
	    ctx->dst_queue_cnt >= ctx->dpb_count)
		return 1;
	/* Context is to return last frame */
	if (ctx->state == MFCINST_FINISHING &&
	    ctx->dst_queue_cnt >= ctx->dpb_count)
		return 1;
	/* Context is to set buffers */
	if (ctx->src_queue_cnt >= 1 &&
	    ctx->state == MFCINST_HEAD_PARSED &&
	    ctx->capture_state == QUEUE_BUFS_MMAPED)
		return 1;
	/* Resolution change */
	if ((ctx->state == MFCINST_RES_CHANGE_INIT ||
		ctx->state == MFCINST_RES_CHANGE_FLUSH) &&
		ctx->dst_queue_cnt >= ctx->dpb_count)
		return 1;
	if (ctx->state == MFCINST_RES_CHANGE_END &&
		ctx->src_queue_cnt >= 1)
		return 1;
	mfc_debug(2, "ctx is not ready\n");
	return 0;
}
Esempio n. 28
0
/* Open a new instance and get its number */
static int s5p_mfc_open_inst_cmd_v6(struct s5p_mfc_ctx *ctx)
{
	struct s5p_mfc_dev *dev = ctx->dev;
	struct s5p_mfc_cmd_args h2r_args;
	int codec_type;

	mfc_debug(2, "Requested codec mode: %d\n", ctx->codec_mode);
	dev->curr_ctx = ctx->num;
	switch (ctx->codec_mode) {
	case S5P_MFC_CODEC_H264_DEC:
		codec_type = S5P_FIMV_CODEC_H264_DEC_V6;
		break;
	case S5P_MFC_CODEC_H264_MVC_DEC:
		codec_type = S5P_FIMV_CODEC_H264_MVC_DEC_V6;
		break;
	case S5P_MFC_CODEC_VC1_DEC:
		codec_type = S5P_FIMV_CODEC_VC1_DEC_V6;
		break;
	case S5P_MFC_CODEC_MPEG4_DEC:
		codec_type = S5P_FIMV_CODEC_MPEG4_DEC_V6;
		break;
	case S5P_MFC_CODEC_MPEG2_DEC:
		codec_type = S5P_FIMV_CODEC_MPEG2_DEC_V6;
		break;
	case S5P_MFC_CODEC_H263_DEC:
		codec_type = S5P_FIMV_CODEC_H263_DEC_V6;
		break;
	case S5P_MFC_CODEC_VC1RCV_DEC:
		codec_type = S5P_FIMV_CODEC_VC1RCV_DEC_V6;
		break;
	case S5P_MFC_CODEC_VP8_DEC:
		codec_type = S5P_FIMV_CODEC_VP8_DEC_V6;
		break;
	case S5P_MFC_CODEC_H264_ENC:
		codec_type = S5P_FIMV_CODEC_H264_ENC_V6;
		break;
	case S5P_MFC_CODEC_H264_MVC_ENC:
		codec_type = S5P_FIMV_CODEC_H264_MVC_ENC_V6;
		break;
	case S5P_MFC_CODEC_MPEG4_ENC:
		codec_type = S5P_FIMV_CODEC_MPEG4_ENC_V6;
		break;
	case S5P_MFC_CODEC_H263_ENC:
		codec_type = S5P_FIMV_CODEC_H263_ENC_V6;
		break;
	case S5P_MFC_CODEC_VP8_ENC:
		codec_type = S5P_FIMV_CODEC_VP8_ENC_V7;
		break;
	default:
		codec_type = S5P_FIMV_CODEC_NONE_V6;
	};
	mfc_write(dev, codec_type, S5P_FIMV_CODEC_TYPE_V6);
	mfc_write(dev, ctx->ctx.dma, S5P_FIMV_CONTEXT_MEM_ADDR_V6);
	mfc_write(dev, ctx->ctx.size, S5P_FIMV_CONTEXT_MEM_SIZE_V6);
	mfc_write(dev, 0, S5P_FIMV_D_CRC_CTRL_V6); /* no crc */

	return s5p_mfc_cmd_host2risc_v6(dev, S5P_FIMV_H2R_CMD_OPEN_INSTANCE_V6,
					&h2r_args);
}
Esempio n. 29
0
/* Deinitialize hardware */
void s5p_mfc_deinit_hw(struct s5p_mfc_dev *dev)
{
	mfc_debug(2, "mfc deinit start\n");

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

	if (!IS_MFCv7X(dev)) {
		s5p_mfc_clock_on();
		s5p_mfc_reset(dev);
		s5p_mfc_clock_off();
	}

	mfc_debug(2, "mfc deinit completed\n");
}
Esempio n. 30
0
/* Load firmware to MFC */
int s5p_mfc_load_firmware(struct s5p_mfc_dev *dev)
{
	struct firmware *fw_blob;
	size_t 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_debug(2, "Requesting fw\n");
	err = request_firmware((const struct firmware **)&fw_blob,
					MFC_FW_NAME, dev->v4l2_dev.dev);

	if (err != 0) {
		mfc_err_dev("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: %zu\n", err, fw_blob->size);

	if (fw_blob->size > firmware_size) {
		mfc_err_dev("MFC firmware is too big to be loaded.\n");
		release_firmware(fw_blob);
		return -ENOMEM;
	}

	if (dev->fw_info.alloc == 0 || dev->fw_info.ofs == 0) {
		mfc_err_dev("MFC firmware is not allocated or was not mapped correctly.\n");
		release_firmware(fw_blob);
		return -EINVAL;
	}
	dev->fw_size = fw_blob->size;
	memcpy(dev->fw_info.virt, fw_blob->data, fw_blob->size);
	s5p_mfc_mem_clean_priv(dev->fw_info.alloc, dev->fw_info.virt, 0,
			fw_blob->size);
	release_firmware(fw_blob);
	mfc_debug_leave();
	return 0;
}