8.3 子模块分析之SMFC

来源:互联网 发布:java读取property文件 编辑:程序博客网 时间:2024/05/22 06:40

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”Channel02FIFO扇区大小是固定的,并且等于一个扇区的大小。Channel13FIFO扇区大小会根据其他FIFO扇区的大小来决定。如下图所示:


从这个图中可以看出来,Channel02FIFO扇区大小只能是0或者1,Channel13FIFO扇区大小就是可以调整的。


下图是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 0
原创粉丝点击