Example #1
0
/*
 * This function enables a logical channel.
 *
 * @param       channel         Input parameter for the logical channel ID.
 *
 * @return      This function returns 0 on success or negative error code on
 *              fail.
 */
int32_t ipu_enable_channel(ipu_channel_t channel)
{
	uint32_t reg;
	uint32_t in_dma;
	uint32_t out_dma;

	if (g_channel_enable_mask & (1L << IPU_CHAN_ID(channel))) {
		printf("Warning: channel already enabled %d\n",
			IPU_CHAN_ID(channel));
	}

	/* Get input and output dma channels */
	out_dma = channel_2_dma(channel, IPU_OUTPUT_BUFFER);
	in_dma = channel_2_dma(channel, IPU_VIDEO_IN_BUFFER);

	if (idma_is_valid(in_dma)) {
		reg = __raw_readl(IDMAC_CHA_EN(in_dma));
		__raw_writel(reg | idma_mask(in_dma), IDMAC_CHA_EN(in_dma));
	}
	if (idma_is_valid(out_dma)) {
		reg = __raw_readl(IDMAC_CHA_EN(out_dma));
		__raw_writel(reg | idma_mask(out_dma), IDMAC_CHA_EN(out_dma));
	}

	if ((channel == MEM_DC_SYNC) || (channel == MEM_BG_SYNC) ||
	    (channel == MEM_FG_SYNC))
		ipu_dp_dc_enable(channel);

	g_channel_enable_mask |= 1L << IPU_CHAN_ID(channel);

	return 0;
}
Example #2
0
/*
 * This function disables a logical channel.
 *
 * @param       channel         Input parameter for the logical channel ID.
 *
 * @param       wait_for_stop   Flag to set whether to wait for channel end
 *                              of frame or return immediately.
 *
 * @return      This function returns 0 on success or negative error code on
 *              fail.
 */
int32_t ipu_disable_channel(ipu_channel_t channel)
{
	uint32_t reg;
	uint32_t in_dma;
	uint32_t out_dma;

	if ((g_channel_enable_mask & (1L << IPU_CHAN_ID(channel))) == 0) {
		debug("Channel already disabled %d\n",
			IPU_CHAN_ID(channel));
		return 0;
	}

	/* Get input and output dma channels */
	out_dma = channel_2_dma(channel, IPU_OUTPUT_BUFFER);
	in_dma = channel_2_dma(channel, IPU_VIDEO_IN_BUFFER);

	if ((idma_is_valid(in_dma) &&
		!idma_is_set(IDMAC_CHA_EN, in_dma))
		&& (idma_is_valid(out_dma) &&
		!idma_is_set(IDMAC_CHA_EN, out_dma)))
		return -EINVAL;

	if ((channel == MEM_BG_SYNC) || (channel == MEM_FG_SYNC) ||
	    (channel == MEM_DC_SYNC)) {
		ipu_dp_dc_disable(channel, 0);
	}

	/* Disable DMA channel(s) */
	if (idma_is_valid(in_dma)) {
		reg = __raw_readl(IDMAC_CHA_EN(in_dma));
		__raw_writel(reg & ~idma_mask(in_dma), IDMAC_CHA_EN(in_dma));
		__raw_writel(idma_mask(in_dma), IPU_CHA_CUR_BUF(in_dma));
	}
	if (idma_is_valid(out_dma)) {
		reg = __raw_readl(IDMAC_CHA_EN(out_dma));
		__raw_writel(reg & ~idma_mask(out_dma), IDMAC_CHA_EN(out_dma));
		__raw_writel(idma_mask(out_dma), IPU_CHA_CUR_BUF(out_dma));
	}

	g_channel_enable_mask &= ~(1L << IPU_CHAN_ID(channel));

	/* Set channel buffers NOT to be ready */
	if (idma_is_valid(in_dma)) {
		ipu_clear_buffer_ready(channel, IPU_VIDEO_IN_BUFFER, 0);
		ipu_clear_buffer_ready(channel, IPU_VIDEO_IN_BUFFER, 1);
	}
	if (idma_is_valid(out_dma)) {
		ipu_clear_buffer_ready(channel, IPU_OUTPUT_BUFFER, 0);
		ipu_clear_buffer_ready(channel, IPU_OUTPUT_BUFFER, 1);
	}

	return 0;
}
Example #3
0
/*
 * This function is called to initialize a buffer for logical IPU channel.
 *
 * @param       channel         Input parameter for the logical channel ID.
 *
 * @param       type            Input parameter which buffer to initialize.
 *
 * @param       pixel_fmt       Input parameter for pixel format of buffer.
 *                              Pixel format is a FOURCC ASCII code.
 *
 * @param       width           Input parameter for width of buffer in pixels.
 *
 * @param       height          Input parameter for height of buffer in pixels.
 *
 * @param       stride          Input parameter for stride length of buffer
 *                              in pixels.
 *
 * @param       phyaddr_0       Input parameter buffer 0 physical address.
 *
 * @param       phyaddr_1       Input parameter buffer 1 physical address.
 *                              Setting this to a value other than NULL enables
 *                              double buffering mode.
 *
 * @param       u		private u offset for additional cropping,
 *				zero if not used.
 *
 * @param       v		private v offset for additional cropping,
 *				zero if not used.
 *
 * @return      Returns 0 on success or negative error code on fail
 */
int32_t ipu_init_channel_buffer(ipu_channel_t channel, ipu_buffer_t type,
				uint32_t pixel_fmt,
				uint16_t width, uint16_t height,
				uint32_t stride,
				dma_addr_t phyaddr_0, dma_addr_t phyaddr_1,
				uint32_t u, uint32_t v)
{
	uint32_t reg;
	uint32_t dma_chan;

	dma_chan = channel_2_dma(channel, type);
	if (!idma_is_valid(dma_chan))
		return -EINVAL;

	if (stride < width * bytes_per_pixel(pixel_fmt))
		stride = width * bytes_per_pixel(pixel_fmt);

	if (stride % 4) {
		printf(
			"Stride not 32-bit aligned, stride = %d\n", stride);
		return -EINVAL;
	}
	/* Build parameter memory data for DMA channel */
	ipu_ch_param_init(dma_chan, pixel_fmt, width, height, stride, u, v, 0,
			   phyaddr_0, phyaddr_1);

	if (ipu_is_dmfc_chan(dma_chan)) {
		ipu_dmfc_set_wait4eot(dma_chan, width);
	}

	if (idma_is_set(IDMAC_CHA_PRI, dma_chan))
		ipu_ch_param_set_high_priority(dma_chan);

	ipu_ch_param_dump(dma_chan);

	reg = __raw_readl(IPU_CHA_DB_MODE_SEL(dma_chan));
	if (phyaddr_1)
		reg |= idma_mask(dma_chan);
	else
		reg &= ~idma_mask(dma_chan);
	__raw_writel(reg, IPU_CHA_DB_MODE_SEL(dma_chan));

	/* Reset to buffer 0 */
	__raw_writel(idma_mask(dma_chan), IPU_CHA_CUR_BUF(dma_chan));

	return 0;
}
Example #4
0
/*
 * This function clear buffer ready for a logical channel.
 *
 * @param       channel         Input parameter for the logical channel ID.
 *
 * @param       type            Input parameter which buffer to clear.
 *
 * @param       bufNum          Input parameter for which buffer number clear
 *				ready state.
 *
 */
void ipu_clear_buffer_ready(ipu_channel_t channel, ipu_buffer_t type,
		uint32_t bufNum)
{
	uint32_t dma_ch = channel_2_dma(channel, type);

	if (!idma_is_valid(dma_ch))
		return;

	__raw_writel(0xF0000000, IPU_GPR); /* write one to clear */
	if (bufNum == 0) {
		if (idma_is_set(IPU_CHA_BUF0_RDY, dma_ch)) {
			__raw_writel(idma_mask(dma_ch),
					IPU_CHA_BUF0_RDY(dma_ch));
		}
	} else {
		if (idma_is_set(IPU_CHA_BUF1_RDY, dma_ch)) {
			__raw_writel(idma_mask(dma_ch),
					IPU_CHA_BUF1_RDY(dma_ch));
		}
	}
	__raw_writel(0x0, IPU_GPR); /* write one to set */
}
Example #5
0
/*
 * This function is called to uninitialize a logical IPU channel.
 *
 * @param       channel Input parameter for the logical channel ID to uninit.
 */
void ipu_uninit_channel(ipu_channel_t channel)
{
	uint32_t reg;
	uint32_t in_dma, out_dma = 0;
	uint32_t ipu_conf;

	if ((g_channel_init_mask & (1L << IPU_CHAN_ID(channel))) == 0) {
		debug("Channel already uninitialized %d\n",
			IPU_CHAN_ID(channel));
		return;
	}

	/*
	 * Make sure channel is disabled
	 * Get input and output dma channels
	 */
	in_dma = channel_2_dma(channel, IPU_OUTPUT_BUFFER);
	out_dma = channel_2_dma(channel, IPU_VIDEO_IN_BUFFER);

	if (idma_is_set(IDMAC_CHA_EN, in_dma) ||
	    idma_is_set(IDMAC_CHA_EN, out_dma)) {
		printf(
			"Channel %d is not disabled, disable first\n",
			IPU_CHAN_ID(channel));
		return;
	}

	ipu_conf = __raw_readl(IPU_CONF);

	/* Reset the double buffer */
	reg = __raw_readl(IPU_CHA_DB_MODE_SEL(in_dma));
	__raw_writel(reg & ~idma_mask(in_dma), IPU_CHA_DB_MODE_SEL(in_dma));
	reg = __raw_readl(IPU_CHA_DB_MODE_SEL(out_dma));
	__raw_writel(reg & ~idma_mask(out_dma), IPU_CHA_DB_MODE_SEL(out_dma));

	switch (channel) {
	case MEM_DC_SYNC:
		ipu_dc_uninit(1);
		ipu_di_use_count[g_dc_di_assignment[1]]--;
		ipu_dc_use_count--;
		ipu_dmfc_use_count--;
		break;
	case MEM_BG_SYNC:
		ipu_dp_uninit(channel);
		ipu_dc_uninit(5);
		ipu_di_use_count[g_dc_di_assignment[5]]--;
		ipu_dc_use_count--;
		ipu_dp_use_count--;
		ipu_dmfc_use_count--;
		break;
	case MEM_FG_SYNC:
		ipu_dp_uninit(channel);
		ipu_dc_use_count--;
		ipu_dp_use_count--;
		ipu_dmfc_use_count--;
		break;
	default:
		break;
	}

	g_channel_init_mask &= ~(1L << IPU_CHAN_ID(channel));

	if (ipu_dc_use_count == 0)
		ipu_conf &= ~IPU_CONF_DC_EN;
	if (ipu_dp_use_count == 0)
		ipu_conf &= ~IPU_CONF_DP_EN;
	if (ipu_dmfc_use_count == 0)
		ipu_conf &= ~IPU_CONF_DMFC_EN;
	if (ipu_di_use_count[0] == 0) {
		ipu_conf &= ~IPU_CONF_DI0_EN;
	}
	if (ipu_di_use_count[1] == 0) {
		ipu_conf &= ~IPU_CONF_DI1_EN;
	}

	__raw_writel(ipu_conf, IPU_CONF);

	if (ipu_conf == 0) {
		clk_disable(g_ipu_clk);
		g_ipu_clk_enabled = 0;
	}

}
Example #6
0
/*
 * This function is called to initialize a logical IPU channel.
 *
 * @param       channel Input parameter for the logical channel ID to init.
 *
 * @param       params  Input parameter containing union of channel
 *                      initialization parameters.
 *
 * @return      Returns 0 on success or negative error code on fail
 */
int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params)
{
	int ret = 0;
	uint32_t ipu_conf;
	u32 reg;

	debug("init channel = %d\n", IPU_CHAN_ID(channel));

	if (g_ipu_clk_enabled == 0) {
		g_ipu_clk_enabled = 1;
		clk_enable(g_ipu_clk);
	}


	if (g_channel_init_mask & (1L << IPU_CHAN_ID(channel))) {
		printf("Warning--0: channel already initialized %d\n",
			IPU_CHAN_ID(channel));
	}

	ipu_conf = __raw_readl(IPU_CONF);

	switch (channel) {
	case CSI_MEM:
		if (params->csi_mem.csi > 1) {
			ret = -EINVAL;
			goto err;
		}
		//printf("csi_mem interlaced= %d, csi_mem mipi_en: %d\n", params->csi_mem.interlaced, params->csi_mem.mipi_en);
		if (params->csi_mem.interlaced)
			g_chan_is_interlaced[channel_2_dma(channel,
				IPU_OUTPUT_BUFFER)] = 0x1;
		else
			g_chan_is_interlaced[channel_2_dma(channel,
				IPU_OUTPUT_BUFFER)] = 0x0;

		ipu_smfc_use_count++;
		g_ipu_csi_channel[params->csi_mem.csi] = channel;

		/*SMFC setting*/
		if (params->csi_mem.mipi_en) {
			ipu_conf |= (1 << (IPU_CONF_CSI0_DATA_SOURCE_OFFSET +
				params->csi_mem.csi));
			_ipu_smfc_init(channel, params->csi_mem.mipi_id,
				params->csi_mem.csi);
		} else {
			ipu_conf &= ~(1 << (IPU_CONF_CSI0_DATA_SOURCE_OFFSET +
				params->csi_mem.csi));
			_ipu_smfc_init(channel, 0, params->csi_mem.csi);
		}

		/*CSI data (include compander) dest*/
		_ipu_csi_init(channel, params->csi_mem.csi);
		break;
	case CSI_PRP_ENC_MEM:
		if (g_channel_init_mask & (1L << IPU_CHAN_ID(channel))) {
			printf("Warning--1: channel already initialized %d\n", IPU_CHAN_ID(channel));
			/*CSI data (include compander) dest*/
			_ipu_csi_init(channel, params->csi_prp_enc_mem.csi);
		}else{
			if (params->csi_prp_enc_mem.csi > 1) {
					ret = -EINVAL;
					goto err;
			}
			using_ic_dirct_ch = CSI_PRP_ENC_MEM;

			ipu_ic_use_count++;
			g_ipu_csi_channel[params->csi_prp_enc_mem.csi] = channel;

			/*Without SMFC, CSI only support parallel data source*/
			ipu_conf &= ~(1 << (IPU_CONF_CSI0_DATA_SOURCE_OFFSET +
				params->csi_prp_enc_mem.csi));

			/*CSI0/1 feed into IC*/
			ipu_conf &= ~IPU_CONF_IC_INPUT;
			if (params->csi_prp_enc_mem.csi)
				ipu_conf |= IPU_CONF_CSI_SEL;
			else
				ipu_conf &= ~IPU_CONF_CSI_SEL;

			/*PRP skip buffer in memory, only valid when RWS_EN is true*/
			reg = __raw_readl(IPU_FS_PROC_FLOW1);
			__raw_writel(reg & ~FS_ENC_IN_VALID, IPU_FS_PROC_FLOW1);
			/*CSI data (include compander) dest*/
			_ipu_csi_init(channel, params->csi_prp_enc_mem.csi);
			_ipu_ic_init_prpenc(params, 1);
		}
		break;
	case CSI_PRP_VF_MEM:
		if (params->csi_prp_vf_mem.csi > 1) {
			ret = -EINVAL;
			goto err;
		}
		using_ic_dirct_ch = CSI_PRP_VF_MEM;

		ipu_ic_use_count++;
		g_ipu_csi_channel[params->csi_prp_vf_mem.csi] = channel;

		/*Without SMFC, CSI only support parallel data source*/
		ipu_conf &= ~(1 << (IPU_CONF_CSI0_DATA_SOURCE_OFFSET +
			params->csi_prp_vf_mem.csi));

		/*CSI0/1 feed into IC*/
		ipu_conf &= ~IPU_CONF_IC_INPUT;
		if (params->csi_prp_vf_mem.csi)
			ipu_conf |= IPU_CONF_CSI_SEL;
		else
			ipu_conf &= ~IPU_CONF_CSI_SEL;

		/*PRP skip buffer in memory, only valid when RWS_EN is true*/
		reg = __raw_readl(IPU_FS_PROC_FLOW1);
		__raw_writel(reg & ~FS_VF_IN_VALID, IPU_FS_PROC_FLOW1);

		/*CSI data (include compander) dest*/
		_ipu_csi_init(channel, params->csi_prp_vf_mem.csi);
		_ipu_ic_init_prpvf(params, 1);
		break;

	case MEM_DC_SYNC:
		if (params->mem_dc_sync.di > 1) {
			ret = -EINVAL;
			goto err;
		}

		g_dc_di_assignment[1] = params->mem_dc_sync.di;
		ipu_dc_init(1, params->mem_dc_sync.di,
			     params->mem_dc_sync.interlaced);
		ipu_di_use_count[params->mem_dc_sync.di]++;
		ipu_dc_use_count++;
		ipu_dmfc_use_count++;
		break;
	case MEM_BG_SYNC:
		if (params->mem_dp_bg_sync.di > 1) {
			ret = -EINVAL;
			goto err;
		}
		//printf("in_pixel_fmt: 0x%x, out_pixel_fmt: 0x%x\n", params->mem_dp_bg_sync.in_pixel_fmt, params->mem_dp_bg_sync.out_pixel_fmt);
		g_dc_di_assignment[5] = params->mem_dp_bg_sync.di;
		ipu_dp_init(channel, params->mem_dp_bg_sync.in_pixel_fmt,
			     params->mem_dp_bg_sync.out_pixel_fmt);
		ipu_dc_init(5, params->mem_dp_bg_sync.di,
			     params->mem_dp_bg_sync.interlaced);
		ipu_di_use_count[params->mem_dp_bg_sync.di]++;
		ipu_dc_use_count++;
		ipu_dp_use_count++;
		ipu_dmfc_use_count++;
		break;
	case MEM_FG_SYNC:
		ipu_dp_init(channel, params->mem_dp_fg_sync.in_pixel_fmt,
			     params->mem_dp_fg_sync.out_pixel_fmt);

		ipu_dc_use_count++;
		ipu_dp_use_count++;
		ipu_dmfc_use_count++;
		break;
	default:
		printf("Missing channel initialization\n");
		break;
	}

	if (g_channel_init_mask & (1L << IPU_CHAN_ID(channel))) {
		printf("Warning--2: channel already initialized %d\n", IPU_CHAN_ID(channel));

	}else{
		/* Enable IPU sub module */
		g_channel_init_mask |= 1L << IPU_CHAN_ID(channel);
		if (ipu_dc_use_count == 1)
			ipu_conf |= IPU_CONF_DC_EN;
		if (ipu_dp_use_count == 1)
			ipu_conf |= IPU_CONF_DP_EN;
		if (ipu_dmfc_use_count == 1)
			ipu_conf |= IPU_CONF_DMFC_EN;
		if (ipu_di_use_count[0] == 1) {
			ipu_conf |= IPU_CONF_DI0_EN;
		}
		if (ipu_di_use_count[1] == 1) {
			ipu_conf |= IPU_CONF_DI1_EN;
		}
		if (ipu_ic_use_count > 0)
			ipu_conf |= IPU_CONF_IC_EN;
		
		__raw_writel(ipu_conf, IPU_CONF);
	}

err:
	return ret;
}
Example #7
0
/*
 * This function is called to initialize a buffer for logical IPU channel.
 *
 * @param       channel         Input parameter for the logical channel ID.
 *
 * @param       type            Input parameter which buffer to initialize.
 *
 * @param       pixel_fmt       Input parameter for pixel format of buffer.
 *                              Pixel format is a FOURCC ASCII code.
 *
 * @param       width           Input parameter for width of buffer in pixels.
 *
 * @param       height          Input parameter for height of buffer in pixels.
 *
 * @param       stride          Input parameter for stride length of buffer
 *                              in pixels.
 *
 * @param       phyaddr_0       Input parameter buffer 0 physical address.
 *
 * @param       phyaddr_1       Input parameter buffer 1 physical address.
 *                              Setting this to a value other than NULL enables
 *                              double buffering mode.
 *
 * @param       u		private u offset for additional cropping,
 *				zero if not used.
 *
 * @param       v		private v offset for additional cropping,
 *				zero if not used.
 *
 * @return      Returns 0 on success or negative error code on fail
 */
int32_t ipu_init_channel_buffer(ipu_channel_t channel, ipu_buffer_t type,
				uint32_t pixel_fmt,
				uint16_t width, uint16_t height,
				uint32_t stride,
				dma_addr_t phyaddr_0, dma_addr_t phyaddr_1,
				uint32_t u, uint32_t v)
{
	uint32_t reg;
	uint32_t dma_chan;
	uint32_t burst_size;

	static int once = 0;
	if(IPU_CHAN_ID(channel) == 19){
		if (once == 0){
			once++;
		}else{
			printf("ipu_init_channel_buffer fake reinit\n");
			return 0;
		}
	}

	//printf("ipu_init_channel_buffer: channel: %d, type: %d, pixel_fmt: 0x%x, width: %d, height: %d, stride: %d, phyaddr_0: 0x%x, phyaddr_1: 0x%x, u: 0x%x, v: 0x%x\r\n",
	//	IPU_CHAN_ID(channel), type, pixel_fmt, width, height,stride, phyaddr_0, phyaddr_1, u,v);
	
	dma_chan = channel_2_dma(channel, type);
	if (!idma_is_valid(dma_chan))
		return -EINVAL;

	if (stride < width * bytes_per_pixel(pixel_fmt)){
		stride = width * bytes_per_pixel(pixel_fmt);
//		printf("stride is update with bpp: 0x%x\n", bytes_per_pixel(pixel_fmt));
	}

	if (stride % 4) {
		printf(
			"Stride not 32-bit aligned, stride = %d\n", stride);
		return -EINVAL;
	}
	/* Build parameter memory data for DMA channel */
	ipu_ch_param_init(dma_chan, pixel_fmt, width, height, stride, u, v, 0,
			   phyaddr_0, phyaddr_1);

	if (ipu_is_dmfc_chan(dma_chan)) {
		burst_size = _ipu_ch_param_get_burst_size(dma_chan);
		//printf("burst_size: 0x%x\n", burst_size);
		ipu_dmfc_set_wait4eot(dma_chan, width);
		ipu_dmfc_set_burst_size(dma_chan, burst_size);
	}

	/* IC and ROT channels have restriction of 8 or 16 pix burst length */
	if (_ipu_is_ic_chan(dma_chan)) {
		if ((width % 16) == 0)
			_ipu_ch_param_set_burst_size(dma_chan, 16);
		else
			_ipu_ch_param_set_burst_size(dma_chan, 8);
	} 

	if (_ipu_is_ic_chan(dma_chan) ) {
		burst_size = _ipu_ch_param_get_burst_size(dma_chan);
		_ipu_ic_idma_init(dma_chan, width, height, burst_size);
	} else if (_ipu_is_smfc_chan(dma_chan)) {
		burst_size = _ipu_ch_param_get_burst_size(dma_chan);
		if ((pixel_fmt == IPU_PIX_FMT_GENERIC) &&
			((_ipu_ch_param_get_bpp(dma_chan) == 5) ||
			(_ipu_ch_param_get_bpp(dma_chan) == 3)))
			burst_size = burst_size >> 4;
		else
			burst_size = burst_size >> 2;
		_ipu_smfc_set_burst_size(channel, burst_size-1);
	}