8.3 子模块分析之SMFC

1)概述

Sensor Multifile Controller作为CSI模块和IDMAC之间的一个缓冲设备,每个SMFC可以支持两个CSI设备。

每个CSI设备可以最多发送4帧图像到SMFC中,SMFC通过csi_id号来区分是哪个CSI发送的。每一帧图像通过SMFC映射到4dmachannel其中的一个。每个dmachannel都是一个FIFO


2SMFC功能介绍

SMFC最多支持4dmachannel,每一个dmachannel都有一个专用的FIFO控制器(FIFOcontroller)。每个buffer中都含有真正的数据和帧ID。当RR优先级机制选中其中的某一个buffer后,会将对应buffer里面保存的ID号与CH#_MAP位进行比较,然后对应的FIFO控制器将会被使能,之后这个buffer里面的真正数据就会被拷贝到RAM中。wptrbase用来计算在RAM中的位置,rptr是在dma_active信号发生后跟随wptr发出。

这个过程如下图所示:

由于这四个channels不能够同时启用,所以四个FIFO需要使用同一个RAMSMFC所使用的内存空间分为4个相同的扇区,每一个FIFO拥有一个固定的基地址————“base”Channel0 2FIFO扇区大小是固定的,并且等于一个扇区的大小。Channel1 3FIFO扇区大小会根据其他FIFO扇区的大小来决定。如下图所示:


从这个图中可以看出来,Channel0 2FIFO扇区大小只能是0或者1,Channel1 3FIFO扇区大小就是可以调整的。


下图是SMFC的时序图:

(三)代码实现

3.1需要使用到SMFCchannel就是CSI-->SMFC-->MEM这个channel,在ipu_init_channel函数中对应于CSI_MEM0,CSI_MEM1, CSI_MEM2, CSI_MEM3这几个channel。所以,以ipu_init_channel这个函数为核心来分析SMFC的设置。有关CSI_MEM0,CSI_MEM1, CSI_MEM2, CSI_MEM3这几个channel的文件是ipu_csi_enc.c

3.2ipu_init_channel函数中,设置SMFC的就是_ipu_smfc_init函数:

	if (params->csi_mem.mipi_en) { 
			ipu_conf |= (1 << (IPU_CONF_CSI0_DATA_SOURCE_OFFSET + 
				params->csi_mem.csi)); 
			_ipu_smfc_init(ipu, channel, params->csi_mem.mipi_vc, 
				params->csi_mem.csi); 
			_ipu_csi_set_mipi_di(ipu, params->csi_mem.mipi_vc, 
				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(ipu, channel, 0, params->csi_mem.csi); 
		}

再来看看这个_ipu_smfc_init函数的实现:

void _ipu_smfc_init(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t mipi_id, uint32_t csi) 
{ 
	uint32_t temp; 

	temp = ipu_smfc_read(ipu, SMFC_MAP); 

	switch (channel) { 
	case CSI_MEM0: 
		temp &= ~SMFC_MAP_CH0_MASK; 
		temp |= ((csi << 2) | mipi_id) << SMFC_MAP_CH0_SHIFT; 
		break; 
	case CSI_MEM1: 
		temp &= ~SMFC_MAP_CH1_MASK; 
		temp |= ((csi << 2) | mipi_id) << SMFC_MAP_CH1_SHIFT; 
		break; 
	case CSI_MEM2: 
		temp &= ~SMFC_MAP_CH2_MASK; 
		temp |= ((csi << 2) | mipi_id) << SMFC_MAP_CH2_SHIFT; 
		break; 
	case CSI_MEM3: 
		temp &= ~SMFC_MAP_CH3_MASK; 
		temp |= ((csi << 2) | mipi_id) << SMFC_MAP_CH3_SHIFT; 
		break; 
	default: 
		return; 
	} 

	ipu_smfc_write(ipu, temp, SMFC_MAP); 
}

这个函数对比IPUx_SMFC_MAP寄存器来看:

...........................

..............................

从寄存器的介绍来看的话,其实_ipu_smfc_init函数中传入的mipi_idcsi参数都是没有作用的,因为这个函数根据传入的channel参数来决定执行哪一个switch分支,然后决定数据在SMFC中被映射到哪一路。

所以真正起作用的就是这个channel参数了。而这个channel参数是通过ipu_init_channel函数传进来的。所以下面简单追踪一下应用程序与驱动程序中的设置。


3.3

mxc_v4l2_capture.c中,维护着一个全局数组,如下所示:

static struct v4l2_input mxc_capture_inputs[MXC_V4L2_CAPTURE_NUM_INPUTS] = { 
	{ 
	 .index = 0, 
	 .name = "CSI IC MEM", 
	 .type = V4L2_INPUT_TYPE_CAMERA, 
	 .audioset = 0, 
	 .tuner = 0, 
	 .std = V4L2_STD_UNKNOWN, 
	 .status = 0, 
	 }, 
	{ 
	 .index = 1, 
	 .name = "CSI MEM", 
	 .type = V4L2_INPUT_TYPE_CAMERA, 
	 .audioset = 0, 
	 .tuner = 0, 
	 .std = V4L2_STD_UNKNOWN, 
	 .status = V4L2_IN_ST_NO_POWER, 
	 }, 
};

这个数组代表输入有几种形式,从这个数组可以看出来,对于摄像头采集设备来说,它有的两条通道就是:CSI-->SMFC-->MEMCSI-->IC-->MEM。看这个数组成员中,重要的参数有两个:indexname,应用程序中可以通过-i选项来选择对应的index参数的值。在应用程序开始执行的时候,会首先执行open函数,对应到驱动中就是mxc_v4l_open函数,以及在后面,应用程序通过-i选项来指定的输入,是通过VIDIOC_S_INPUT这个ioctl调用来设置到驱动中的。先来看看mxc_v4l_open函数:

if (strcmp(mxc_capture_inputs[cam->current_input].name, "CSI MEM") == 0) { 
			err = csi_enc_select(cam); 
		} else if (strcmp(mxc_capture_inputs[cam->current_input].name, 
				  "CSI IC MEM") == 0) { 
			err = prp_enc_select(cam); 
}

这个cam->current_input在初始化的时候初始化为0了,mxc_capture_inputs[0].name== "CSI ICMEM",所以,默认选择的是CSI-->IC-->MEM这条通道。如果想要选择CSI-->SMFC-->MEM通路的话,就需要在应用程序中指定:-i1。而这个设置是在VIDIOC_S_INPUT中,同样会调用到上面那段代码,然后就会选择csi_enc_select函数来执行。然后在mxc_streamon函数中,就会执行cam->enc_enable函数,对应执行到ipu_csi_enc.c文件中的csi_enc_enabling_tasks函数,继续执行到csi_enc_setup函数,在csi_enc_setup函数中:

ipu_channel_t chan = (cam->csi == 0) ? CSI_MEM0 : CSI_MEM1;
	err = ipu_init_channel(cam->ipu, chan, ¶ms);
		_ipu_smfc_init(ipu, channel, 0, params->csi_mem.csi);

然后就在ipu_init_channel函数中,根据chan参数来选择执行哪一个case,因为会根据cam->csi号来选择chan=CSI_MEM0还是CSI_MEM1,而_ipu_smfc_init函数咱们在上面分析过了,它会根据传入的channel号来选择映射到哪一条dma_smfc_ch。而在csi_enc_setup函数中,设置了channel号的值,所以,对应的cam->csi== 0的,就会在SMFC中映射到dma_smfc_ch0;对应的cam->csi==1的,就会在SMFC中映射到dma_smfc_ch1在驱动中没有指定CSI_MEM2CSI_MEM3,所以dma_smfc_ch2dma_smfc_ch3不会被使用到。


如果想使用dma_smfc_ch2dma_smfc_ch3的话,就需要在驱动程序中的ipu_init_channel函数之前,将channel号设置为CSI_MEM2CSI_MEM3。但是目前的代码中没有这么做


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值