4.6 ipu_enable_channel函数详细分析

int32_t ipu_enable_channel(struct ipu_soc *ipu, ipu_channel_t channel) 
{ 
	uint32_t reg; 
	uint32_t ipu_conf; 
	uint32_t in_dma; 
	uint32_t out_dma; 
	uint32_t sec_dma; 
	uint32_t thrd_dma; 

	mutex_lock(&ipu->mutex_lock); 

	if (ipu->channel_enable_mask & (1L << IPU_CHAN_ID(channel))) { 
		dev_err(ipu->dev, "Warning: channel already enabled %d\n", 
			IPU_CHAN_ID(channel)); 
		mutex_unlock(&ipu->mutex_lock); 
		return -EACCES; 
	} 

/*ipu->channel_enable_mask中每一位对应一个channel是否使能了。首先检查要使能的这个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); 

/*通过这两步将channel转化成dma_ch,在之前分析过这个函数,会根据type类型从channel中选取出输入或者输出的dmachannel. */

	ipu_conf = ipu_cm_read(ipu, IPU_CONF); 
	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; 
	} 
	if (ipu->dp_use_count > 0) 
		ipu_conf |= IPU_CONF_DP_EN; 
	if (ipu->dc_use_count > 0) 
		ipu_conf |= IPU_CONF_DC_EN; 
	if (ipu->dmfc_use_count > 0) 
		ipu_conf |= IPU_CONF_DMFC_EN; 
	if (ipu->ic_use_count > 0) 
		ipu_conf |= IPU_CONF_IC_EN; 
	if (ipu->vdi_use_count > 0) { 
		ipu_conf |= IPU_CONF_ISP_EN; 
		ipu_conf |= IPU_CONF_VDI_EN; 
		ipu_conf |= IPU_CONF_IC_INPUT; 
	} 
	if (ipu->rot_use_count > 0) 
		ipu_conf |= IPU_CONF_ROT_EN; 
	if (ipu->smfc_use_count > 0) 
		ipu_conf |= IPU_CONF_SMFC_EN; 
	ipu_cm_write(ipu, ipu_conf, IPU_CONF); 

/*根据ipu参数里面的引用计数来决定将ipu_conf寄存器中的对应位置位。最终将这些值都写到这个ipu_conf寄存器中。*/

	if (idma_is_valid(in_dma)) { 
		reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(in_dma)); 
		ipu_idmac_write(ipu, reg | idma_mask(in_dma), IDMAC_CHA_EN(in_dma)); 
	} 
	if (idma_is_valid(out_dma)) { 
		reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(out_dma)); 
		ipu_idmac_write(ipu, reg | idma_mask(out_dma), IDMAC_CHA_EN(out_dma)); 
	} 

/*通过这几个函数来将in_dmaout_dma的值写到ipu里面的idmac寄存器中。*/

	if ((ipu->sec_chan_en[IPU_CHAN_ID(channel)]) && 
		((channel == MEM_PP_MEM) || (channel == MEM_PRP_VF_MEM) || 
		 (channel == MEM_VDI_PRP_VF_MEM))) { 
		sec_dma = channel_2_dma(channel, IPU_GRAPH_IN_BUFFER); 
		reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(sec_dma)); 
		ipu_idmac_write(ipu, reg | idma_mask(sec_dma),												IDMAC_CHA_EN(sec_dma)); 
	} 

/*ipu_soc结构体中sec_chan_en是一个bool类型的数组,它会根据channel通过IPU_CHAN_ID转化成的数字来从这个数组中找到对应的一项,如果使能了secondchannel的话,就是true,否则就是false。同时channel的需要是PPPRP_VF,VDI_PRP_VF的情况,如果条件都成立的话,同样会设置idmac寄存器里面的某些位。*/

	if ((ipu->thrd_chan_en[IPU_CHAN_ID(channel)]) && 
		((channel == MEM_PP_MEM) || (channel == MEM_PRP_VF_MEM))) { 
		thrd_dma = channel_2_dma(channel, IPU_ALPHA_IN_BUFFER); 
		reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(thrd_dma)); 
		ipu_idmac_write(ipu, reg | idma_mask(thrd_dma), IDMAC_CHA_EN(thrd_dma)); 

		sec_dma = channel_2_dma(channel, IPU_GRAPH_IN_BUFFER); 
		reg = ipu_idmac_read(ipu, IDMAC_SEP_ALPHA); 
		ipu_idmac_write(ipu, reg | idma_mask(sec_dma), IDMAC_SEP_ALPHA); 
	} 

/*这一段代码判断的是thirdchannel是否使能同时此时对应的channelPPPRP_VF。如果是使能了thirdchannel的话,肯定已经使能了secondchannel,所以需要同时在idmac中设置thrd_dmasec_dma的值。*/

else if ((ipu->thrd_chan_en[IPU_CHAN_ID(channel)]) && 
		   ((channel == MEM_BG_SYNC) || (channel == MEM_FG_SYNC))) { 
		thrd_dma = channel_2_dma(channel, IPU_ALPHA_IN_BUFFER); 
		reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(thrd_dma)); 
		ipu_idmac_write(ipu, reg | idma_mask(thrd_dma), IDMAC_CHA_EN(thrd_dma)); 
		reg = ipu_idmac_read(ipu, IDMAC_SEP_ALPHA); 
		ipu_idmac_write(ipu, reg | idma_mask(in_dma), IDMAC_SEP_ALPHA); 
	} 

/*这一段代码判断的是thirdchannel是否使能同时此时对应的channelBGFG。如果是使能了thirdchannel的话,肯定已经使能了secondchannel,所以需要同时在idmac中设置thrd_dmasec_dma的值。*/

	if ((channel == MEM_DC_SYNC) || (channel == MEM_BG_SYNC) || 
	    (channel == MEM_FG_SYNC)) { 
		reg = ipu_idmac_read(ipu, IDMAC_WM_EN(in_dma)); 
		ipu_idmac_write(ipu, reg | idma_mask(in_dma), IDMAC_WM_EN(in_dma)); 

		_ipu_dp_dc_enable(ipu, channel); 
	} 

/*这几个通道是关于输出显示的通道,个人理解是displaycontroll sync, background syncforegroundsyncchannel,这时肯定不能仅仅设置idmac寄存器,同时需要调用_ipu_dp_dc_enable函数来使能显示设备,这个函数在ipu_disp.c中定义。*/

	if (_ipu_is_ic_chan(in_dma) || _ipu_is_ic_chan(out_dma) || 
		_ipu_is_irt_chan(in_dma) || _ipu_is_irt_chan(out_dma) || 
		_ipu_is_vdi_out_chan(out_dma)) 
		_ipu_ic_enable_task(ipu, channel); 

/*如果是in_dmaout_dma使用到了ic,irt,vdi_out的话,都需要通过_ipu_ic_enable_task函数来使能ic,这个函数在ipu_ic.c中定义。*/

	ipu->channel_enable_mask |= 1L << IPU_CHAN_ID(channel); 

/*这个channel_enable_mask是一个uint32_t类型的掩码,如果使能了哪个channel的话,就将这个channel对应的位置1。同时也会在这个函数开始的地方通过它来判断一个channel是否已经使能过了。*/

	if (ipu->prg_clk) 
		clk_prepare_enable(ipu->prg_clk); 

	mutex_unlock(&ipu->mutex_lock); 

	return 0; 
} 
EXPORT_SYMBOL(ipu_enable_channel);

总结一下,这个函数都做了哪些事情:

1)既然是使能channel函数,设置的首要寄存器就是ipu_conf,会根据ipu_soc结构体里面的各个子模块的引用计数来将ipu_conf中对应的位使能。


2)每一个channel都会使用到一个或者多个dmachannel,那么同样的,需要将这几个dmachannel所对应的寄存器的位使能,对应的寄存器是IPUx_IDMAC_CH_EN_1或者IPUx_IDMAC_CH_EN_2.

至此,ipu_common.c文件中的重要函数都分析完毕。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值