6.2 ipu_csi_enc.c详细分析

这个文件和ipu_prp_enc.c以及ipu_fg_overlay_sdc.cipu_bg_overlay_sdc.c几个文件的操作都是相似的,这几个文件可以一起查看。找到他们之间的区别,

1cam_data中使用的函数指针的不同;

2ipu_init_channel_buffer中地址的不同和width等不同。


mxc_v4l2_capture.c中的mxc_v4l_open函数,里面有这样一个选择语句:

if (strcmp(mxc_capture_inputs[cam->current_input].name, 
			   "CSI MEM") == 0) { 
#if defined(CONFIG_MXC_IPU_CSI_ENC) || defined(CONFIG_MXC_IPU_CSI_ENC_MODULE) 
			err = csi_enc_select(cam); 
#endif 
		} else if (strcmp(mxc_capture_inputs[cam->current_input].name, 
				  "CSI IC MEM") == 0) { 
#if defined(CONFIG_MXC_IPU_PRP_ENC) || defined(CONFIG_MXC_IPU_PRP_ENC_MODULE) 
			err = prp_enc_select(cam); 
#endif 
		}

如果匹配的mxc_capture_inputs[cam->current_input].name"CSIMEM"的话,就会执行csi_enc_select函数,这个“CSIMEM”一般是用作overlay或者viewfinder,从CSI中获取到的数据,不经过IC,直接到达内存中。这个csi_enc_select函数就在ipu_csi_enc.c文件中,这个函数就是设置cam_data结构体中的几个函数指针所指向的函数。


1.csi_enc_select函数

int csi_enc_select(void *private) 
{ 
	cam_data *cam = (cam_data *) private; 
	int err = 0; 

	if (cam) { 
		cam->enc_update_eba = csi_enc_eba_update; 
		cam->enc_enable = csi_enc_enabling_tasks; 
		cam->enc_disable = csi_enc_disabling_tasks; 
		cam->enc_enable_csi = csi_enc_enable_csi; 
		cam->enc_disable_csi = csi_enc_disable_csi; 
	} else { 
		err = -EIO; 
	} 

	return err; 
} 
EXPORT_SYMBOL(csi_enc_select);

2.csi_enc_enabling_tasks函数

当在mxc_v4l2_capture.c中的mxc_streamon函数中调用cam->enc_enable的话,就会调用到csi_enc_enabling_tasks函数。

static int csi_enc_enabling_tasks(void *private) 
{ 
	cam_data *cam = (cam_data *) private; 
	int err = 0; 
	uint32_t irq = (cam->csi == 0) ? 
		IPU_IRQ_CSI0_OUT_EOF : IPU_IRQ_CSI1_OUT_EOF; 

	CAMERA_TRACE("IPU:In csi_enc_enabling_tasks\n"); 

	cam->dummy_frame.vaddress = dma_alloc_coherent(0, 
			       PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage), 
			       &cam->dummy_frame.paddress, 
			       GFP_DMA | GFP_KERNEL); 
	if (cam->dummy_frame.vaddress == 0) { 
		pr_err("ERROR: v4l2 capture: Allocate dummy frame " 
		       "failed.\n"); 
		return -ENOBUFS; 
	} 
	cam->dummy_frame.buffer.type = V4L2_BUF_TYPE_PRIVATE; 
	cam->dummy_frame.buffer.length = 
	    PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage); 
	cam->dummy_frame.buffer.m.offset = cam->dummy_frame.paddress; 

	ipu_clear_irq(cam->ipu, irq); 
	err = ipu_request_irq( 
		cam->ipu, irq, csi_enc_callback, 0, "Mxc Camera", cam); 
	if (err != 0) { 
		printk(KERN_ERR "Error registering rot irq\n"); 
		return err; 
	} 

	err = csi_enc_setup(cam); 
	if (err != 0) { 
		printk(KERN_ERR "csi_enc_setup %d\n", err); 
		return err; 
	} 

	return err; 
}

这个函数与ipu_prp_enc.c中的不同就是首先会根据cam->csi号来选择一个对应的中断号,其他的步骤都是相似的,通过dma_alloc_coherent函数来为cam->dummy_frame.vaddress生成虚拟地址,然后填充这个cam->dummy_frame结构体。之后通过ipu_request_irq函数来为对应的中断号申请中断,同时中断处理函数为csi_enc_callback。之后调用csi_enc_setup函数。

static int csi_enc_setup(cam_data *cam) 
{ 
	ipu_channel_params_t params; 
	u32 pixel_fmt; 
	int err = 0, sensor_protocol = 0; 
	dma_addr_t dummy = cam->dummy_frame.buffer.m.offset; 
	ipu_channel_t chan = (cam->csi == 0) ? CSI_MEM0 : CSI_MEM1; 
#ifdef CONFIG_MXC_MIPI_CSI2 
	void *mipi_csi2_info; 
	int ipu_id; 
	int csi_id; 
#endif 

	CAMERA_TRACE("In csi_enc_setup\n"); 
	if (!cam) { 
		printk(KERN_ERR "cam private is NULL\n"); 
		return -ENXIO; 
	} 

	memset(¶ms, 0, sizeof(ipu_channel_params_t)); 
	params.csi_mem.csi = cam->csi; 

	sensor_protocol = ipu_csi_get_sensor_protocol(cam->ipu, cam->csi); 
	switch (sensor_protocol) { 
	case IPU_CSI_CLK_MODE_GATED_CLK: 
	case IPU_CSI_CLK_MODE_NONGATED_CLK: 
	case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE: 
	case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR: 
	case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR: 
		params.csi_mem.interlaced = false; 
		break; 
	case IPU_CSI_CLK_MODE_CCIR656_INTERLACED: 
	case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR: 
	case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR: 
		params.csi_mem.interlaced = true; 
		break; 
	default: 
		printk(KERN_ERR "sensor protocol unsupported\n"); 
		return -EINVAL; 
	} 

	if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) 
		pixel_fmt = IPU_PIX_FMT_YUV420P; 
	else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YVU420) 
		pixel_fmt = IPU_PIX_FMT_YVU420P; 
	else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV422P) 
		pixel_fmt = IPU_PIX_FMT_YUV422P; 
	else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY) 
		pixel_fmt = IPU_PIX_FMT_UYVY; 
	else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) 
		pixel_fmt = IPU_PIX_FMT_YUYV; 
	else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_NV12) 
		pixel_fmt = IPU_PIX_FMT_NV12; 
	else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR24) 
		pixel_fmt = IPU_PIX_FMT_BGR24; 
	else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24) 
		pixel_fmt = IPU_PIX_FMT_RGB24; 
	else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565) 
		pixel_fmt = IPU_PIX_FMT_RGB565; 
	else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR32) 
		pixel_fmt = IPU_PIX_FMT_BGR32; 
	else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB32) 
		pixel_fmt = IPU_PIX_FMT_RGB32; 
	else { 
		printk(KERN_ERR "format not supported\n"); 
		return -EINVAL; 
	} 

#ifdef CONFIG_MXC_MIPI_CSI2 
	mipi_csi2_info = mipi_csi2_get_info(); 

	if (mipi_csi2_info) { 
		if (mipi_csi2_get_status(mipi_csi2_info)) { 
			ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info); 
			csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info); 

			if (cam->ipu == ipu_get_soc(ipu_id) 
				&& cam->csi == csi_id) { 
				params.csi_mem.mipi_en = true; 
				params.csi_mem.mipi_vc = 
				mipi_csi2_get_virtual_channel(mipi_csi2_info); 
				params.csi_mem.mipi_id = 
				mipi_csi2_get_datatype(mipi_csi2_info); 

				mipi_csi2_pixelclk_enable(mipi_csi2_info); 
			} else { 
				params.csi_mem.mipi_en = false; 
				params.csi_mem.mipi_vc = 0; 
				params.csi_mem.mipi_id = 0; 
			} 
		} else { 
			params.csi_mem.mipi_en = false; 
			params.csi_mem.mipi_vc = 0; 
			params.csi_mem.mipi_id = 0; 
		} 
	} 
#endif 

	err = ipu_init_channel(cam->ipu, chan, ¶ms); 
	if (err != 0) { 
		printk(KERN_ERR "ipu_init_channel %d\n", err); 
		return err; 
	} 

	err = ipu_init_channel_buffer(cam->ipu, 
				      chan, 
				      IPU_OUTPUT_BUFFER, 
				      pixel_fmt, cam->v2f.fmt.pix.width, 
				      cam->v2f.fmt.pix.height, 
				      cam->v2f.fmt.pix.bytesperline, 
				      IPU_ROTATE_NONE, 
				      dummy, dummy, 0, 
				      cam->offset.u_offset, 
				      cam->offset.v_offset); 
	if (err != 0) { 
		printk(KERN_ERR "CSI_MEM output buffer\n"); 
		return err; 
	} 
	err = ipu_enable_channel(cam->ipu, chan); 
	if (err < 0) { 
		printk(KERN_ERR "ipu_enable_channel CSI_MEM\n"); 
		return err; 
	} 

	return err; 
}

在这个函数中,我们可以发现,设置的是ipu_channel_params_t联合中的csi_mem结构体。所以,这个文件所对应的channel就是CSI_MEMx。所以重点就是设置ipu_channel_params_t联合中的csi_mem结构体。

之后就是根据这个params参数通过ipu_init_channel函数来初始化channel,之后继续调用ipu_init_channel_buffer来初始化buffer参数。最后调用ipu_enable_channel函数来使能即可。


其他的步骤与ipu_prp_enc.c中基本相似,就不分析了。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值