NXP

4.6 ipu_enable_channel函数详细分析

2019-07-12 13:51发布

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 ", 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文件中的重要函数都分析完毕。