1. 程式人生 > >7.2 ipu_device.c分析(二)---具體函式分析

7.2 ipu_device.c分析(二)---具體函式分析

1. deinterlace_3_field函式

static bool deinterlace_3_field(struct ipu_task_entry *t) 
{ 
	return ((t->set.mode & VDI_MODE) && 
		(t->input.deinterlace.motion != HIGH_MOTION)); 
} 

2. tiled_filed_size函式

	u32 field_size; 
static u32 tiled_filed_size(struct ipu_task_entry *t) 
{ 

	/* note: page_align is required by VPU hw ouput buffer */ 
	field_size = TILED_NV12_FRAME_SIZE(t->input.width, t->input.height/2); 
	return field_size; 
}

3. MODE模式

關於這個VDOA模式,在下面這個task_set結構體裡面的註釋有說明:VDOA_MODE意味著這個task任務使用vdoa,並且VDOA有兩種模式:BANDMODEnon-bandMODE模式。non-bandMODE模式將要轉化資料到記憶體中。而BANDMODE模式需要IPU硬體的同步訊號,這種模式是連上VDIC的預設模式。

先來看這個task_set結構體:

struct task_set { 
#define	<span style="color:#FF0000;">NULL_MODE</span>	0x0 
#define	<span style="color:#FF0000;">IC_MODE</span>		0x1 
#define	<span style="color:#FF0000;">ROT_MODE</span>	0x2 
#define	<span style="color:#FF0000;">VDI_MODE</span>	0x4 
#define <span style="color:#FF0000;">IPU_PREPROCESS_MODE_MASK</span>	(IC_MODE | ROT_MODE | VDI_MODE) 
/* VDOA_MODE means this task use vdoa, and VDOA has two modes: 
 * BAND MODE and non-BAND MODE. Non-band mode will do transfer data 
 * to memory. BAND mode needs hareware sync with IPU, it is used default 
 * if connected to VDIC. 
 */ 
#define	<span style="color:#FF0000;">VDOA_MODE</span>	0x8 
#define	<span style="color:#FF0000;">VDOA_BAND_MODE</span>	0x10 
	u8	mode; 
。。。。。。。。。
	struct stripe_setting sp_setting; 
};

上面紅色字型是有關MODE模式的變數,可以看到IC_MODE,ROT_MODE,VDA_MODE分別佔用u8的一位:

下面就來看下面三個函式:

3.1 only_ic函式

static bool only_ic(u8 mode) 
{ 
	mode = mode & IPU_PREPROCESS_MODE_MASK; 
	return ((mode == IC_MODE) || (mode == VDI_MODE)); 
} 

可以看出來,如果mode佔用的如下紅色字型所示的任意一位的話,都可以認為是only_ic模式。

3.2 only_rot函式

static bool only_rot(u8 mode) 
{ 
	mode = mode & IPU_PREPROCESS_MODE_MASK; 
	return (mode == ROT_MODE); 
} 

這個only_rot模式,則只有mode佔用ROT位的話,才能夠認為是only_rot

3.3ic_and_rot函式

static bool ic_and_rot(u8 mode) 
{ 
	mode = mode & IPU_PREPROCESS_MODE_MASK; 
	return ((mode == (IC_MODE | ROT_MODE)) || 
		 (mode == (VDI_MODE | ROT_MODE))); 
}

這種模式如下所示:

4.need_split函式

static bool need_split(struct ipu_task_entry *t) 
{ 
	return ((t->set.split_mode != NO_SPLIT) || (t->task_no & SPLIT_MASK)); 
} 
struct task_set { 
。。。。。。。。。。
#define NO_SPLIT	0x0 
#define RL_SPLIT	0x1 
#define UD_SPLIT	0x2 
#define LEFT_STRIPE	0x1 
#define RIGHT_STRIPE	0x2 
#define UP_STRIPE	0x4 
#define DOWN_STRIPE	0x8 
#define SPLIT_MASK	0xF 
	u8	split_mode;
。。。。。。。。。
	struct stripe_setting sp_setting; 
};

這個函式判斷的同樣是ipu_task_entry結構體中的task_set裡面的split_mode,如果這一位不等於0的話,就返回true。這個函式的意思應該是判斷一個結構體是否需要拆分,do_taskget_res_do_taskipu_task_threadipu_queue_task函式中都呼叫了這個函式。

5.fmt_to_bpp函式

unsigned int fmt_to_bpp(unsigned int pixelformat) 
{ 
	u32 bpp; 

	switch (pixelformat) { 
	case IPU_PIX_FMT_RGB565: 
	/*interleaved 422*/ 
	case IPU_PIX_FMT_YUYV: 
	case IPU_PIX_FMT_UYVY: 
	/*non-interleaved 422*/ 
	case IPU_PIX_FMT_YUV422P: 
	case IPU_PIX_FMT_YVU422P: 
		bpp = 16; 
		break; 
	case IPU_PIX_FMT_BGR24: 
	case IPU_PIX_FMT_RGB24: 
	case IPU_PIX_FMT_YUV444: 
	case IPU_PIX_FMT_YUV444P: 
		bpp = 24; 
		break; 
	case IPU_PIX_FMT_BGR32: 
	case IPU_PIX_FMT_BGRA32: 
	case IPU_PIX_FMT_RGB32: 
	case IPU_PIX_FMT_RGBA32: 
	case IPU_PIX_FMT_ABGR32: 
		bpp = 32; 
		break; 
	/*non-interleaved 420*/ 
	case IPU_PIX_FMT_YUV420P: 
	case IPU_PIX_FMT_YVU420P: 
	case IPU_PIX_FMT_YUV420P2: 
	case IPU_PIX_FMT_NV12: 
		bpp = 12; 
		break; 
	default: 
		bpp = 8; 
		break; 
	} 
	return bpp; 
} 
EXPORT_SYMBOL_GPL(fmt_to_bpp);

這個函式就很簡單了,它根據pixelformat格式返回它所佔用的bit數,bitsper pixel

6.colorspaceofpixel函式

cs_t colorspaceofpixel(int fmt) 
{ 
	switch (fmt) { 
	case IPU_PIX_FMT_RGB565: 
	case IPU_PIX_FMT_RGB666: 
	case IPU_PIX_FMT_BGR24: 
	case IPU_PIX_FMT_RGB24: 
	case IPU_PIX_FMT_BGRA32: 
	case IPU_PIX_FMT_BGR32: 
	case IPU_PIX_FMT_RGBA32: 
	case IPU_PIX_FMT_RGB32: 
	case IPU_PIX_FMT_ABGR32: 
		return RGB_CS; 
		break; 
	case IPU_PIX_FMT_UYVY: 
	case IPU_PIX_FMT_YUYV: 
	case IPU_PIX_FMT_YUV420P2: 
	case IPU_PIX_FMT_YUV420P: 
	case IPU_PIX_FMT_YVU420P: 
	case IPU_PIX_FMT_YVU422P: 
	case IPU_PIX_FMT_YUV422P: 
	case IPU_PIX_FMT_YUV444: 
	case IPU_PIX_FMT_YUV444P: 
	case IPU_PIX_FMT_NV12: 
	case IPU_PIX_FMT_TILED_NV12: 
	case IPU_PIX_FMT_TILED_NV12F: 
		return YUV_CS; 
		break; 
	default: 
		return NULL_CS; 
	} 
} 
EXPORT_SYMBOL_GPL(colorspaceofpixel);

這個函式根據format的值返回這個format的顏色空間colorspace。顏色空間在ipu.h中定義:

typedef enum { 
	RGB_CS, 
	YUV_CS, 
	NULL_CS 
} cs_t;

這個函式主要用在下面要介紹的need_csc函式。

7.need_csc函式

int need_csc(int ifmt, int ofmt) 
{ 
	cs_t ics, ocs; 

	ics = colorspaceofpixel(ifmt); 
	ocs = colorspaceofpixel(ofmt); 

	if ((ics == NULL_CS) || (ocs == NULL_CS)) 
		return -1; 
	else if (ics != ocs) 
		return 1; 

	return 0; 
} 
EXPORT_SYMBOL_GPL(need_csc);

這個函式通過colorspaceofpixel函式分別獲取輸入format和輸出format的顏色空間,如果兩者相同的話,就不需要csc轉化了,如果不同的話就需要csc轉化。這個函式在check_task中呼叫。

8.soc_max_in_width函式

static int soc_max_in_width(u32 is_vdoa) 
{ 
	return is_vdoa ? 8192 : 4096; 
}

這個函式返回soc最大的寬度,如果傳入的引數為1的話,就返回8192,否則返回4096。這個函式在check_task函式中就是直接這樣用的。引數為1的話代表是vdoa

9.soc_max_vdi_in_width函式

static int soc_max_vdi_in_width(struct ipu_soc *ipu) 
{ 
	int i; 

	if (!ipu) { 
		for (i = 0; i < max_ipu_no; i++) { 
			ipu = ipu_get_soc(i); 
			if (!IS_ERR_OR_NULL(ipu)) 
				break; 
		} 

		if (i == max_ipu_no) 
			return 720; 
	} 
	return IPU_MAX_VDI_IN_WIDTH(ipu->devtype); 
}

#define IPU_MAX_VDI_IN_WIDTH(type)	({ (type) >= IPUv3M ? 968 : 720; })

這個函式根據傳入的ipu_soc結構體裡面的devtype來返回vdi的最大寬度。

ipu_common.c中的ipu_probe函式裡面,以下程式碼是摘取出來的:(在ipu_common.c中詳細分析)

const struct of_device_id *of_id = 
			of_match_device(imx_ipuv3_dt_ids, &pdev->dev);
const struct ipu_platform_type *iputype = of_id->data; 
	const struct ipu_devtype *devtype = &iputype->devtype;
ipu = &ipu_array[id];
ipu->devtype = devtype->type;

最終ipu->devtype就呼叫到imx_ipuv3_dt_ids[x]裡面的data資料段:

static const struct of_device_id imx_ipuv3_dt_ids[] = { 
	{ .compatible = "fsl,imx51-ipu", .data = &ipu_type_imx51, }, 
	{ .compatible = "fsl,imx53-ipu", .data = &ipu_type_imx53, }, 
	{ .compatible = "fsl,imx6q-ipu", .data = &ipu_type_imx6q, }, 
	{ .compatible = "fsl,imx6qp-ipu", .data = &ipu_type_imx6qp, }, 
	{ /* sentinel */ } 
}; 
MODULE_DEVICE_TABLE(of, imx_ipuv3_dt_ids);

ipu_type_imx6qp為例,如下所示:

static struct ipu_platform_type ipu_type_imx6qp = { 
	<span style="color:#FF0000;">.devtype = { 
		.name = "IPUv3H", 
		.cm_ofs =	0x00200000, 
		.idmac_ofs =	0x00208000, 
		.ic_ofs =	0x00220000, 
		.csi0_ofs =	0x00230000, 
		.csi1_ofs =	0x00238000, 
		.di0_ofs =	0x00240000, 
		.di1_ofs =	0x00248000, 
		.smfc_ofs =	0x00250000, 
		.dc_ofs =	0x00258000, 
		.dmfc_ofs =	0x00260000, 
		.vdi_ofs =	0x00268000, 
		.cpmem_ofs =	0x00300000, 
		.srm_ofs =	0x00340000, 
		.tpm_ofs =	0x00360000, 
		.dc_tmpl_ofs =	0x00380000, 
		.type =		IPUv3H, 
		.idmac_used_bufs_present = true, 
	},</span> 
	.ch0123_axi = 0, 
	.ch23_axi = 0, 
	.ch27_axi = 2, 
	.ch28_axi = 3, 
	.normal_axi = 1, 
	.idmac_used_bufs_en_r = true, 
	.idmac_used_bufs_en_w = true, 
	.idmac_used_bufs_max_r = 0x3, 
	.idmac_used_bufs_max_w = 0x3, 
	.smfc_idmac_12bit_3planar_bs_fixup = true, 
 };

這個soc_max_vdi_in_width函式就會比對ipu->devtype即上面標紅的部分,將它於IPUv3M比較,大於就返回968,否則返回720。可以檢視ipu_common.c中可以看出來ipu_type_imx51"IPUv3EX"ipu_type_imx53"IPUv3M"ipu_type_imx6q"IPUv3H"ipu_type_imx6qp"IPUv3H",所以對於imx51imx53返回720imx6qimx6qp返回968

這個函式在本檔案中的update_split_settingcheck_taskget_res_do_task函式中呼叫。

10.soc_max_in_height函式

static int soc_max_in_height(void) 
{ 
	return 4096; 
}

11.soc_max_out_width函式

static int soc_max_out_width(void) 
{ 
	/* mx51/mx53/mx6q is 1024*/ 
	return 1024; 
}

12.soc_max_out_height函式

static int soc_max_out_height(void) 
{ 
	/* mx51/mx53/mx6q is 1024*/ 
	return 1024; 
}

13.dump_task_info函式

static void dump_task_info(struct ipu_task_entry *t) 
{ 
	if (!debug) 
		return; 
	dev_dbg(t->dev, "[0x%p]input:\n", (void *)t); 
	dev_dbg(t->dev, "[0x%p]\tformat = 0x%x\n", (void *)t, t->input.format); 
	dev_dbg(t->dev, "[0x%p]\twidth = %d\n", (void *)t, t->input.width); 
	dev_dbg(t->dev, "[0x%p]\theight = %d\n", (void *)t, t->input.height); 
	dev_dbg(t->dev, "[0x%p]\tcrop.w = %d\n", (void *)t, t->input.crop.w); 
	dev_dbg(t->dev, "[0x%p]\tcrop.h = %d\n", (void *)t, t->input.crop.h); 
	dev_dbg(t->dev, "[0x%p]\tcrop.pos.x = %d\n", 
			(void *)t, t->input.crop.pos.x); 
	dev_dbg(t->dev, "[0x%p]\tcrop.pos.y = %d\n", 
			(void *)t, t->input.crop.pos.y); 

/*列印ipu_task_entry->input的資訊。*/

	dev_dbg(t->dev, "[0x%p]input buffer:\n", (void *)t); 
	dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n", (void *)t, t->input.paddr); 
	dev_dbg(t->dev, "[0x%p]\ti_off = 0x%x\n", (void *)t, t->set.i_off); 
	dev_dbg(t->dev, "[0x%p]\ti_uoff = 0x%x\n", (void *)t, t->set.i_uoff); 
	dev_dbg(t->dev, "[0x%p]\ti_voff = 0x%x\n", (void *)t, t->set.i_voff); 
	dev_dbg(t->dev, "[0x%p]\tistride = %d\n", (void *)t, t->set.istride); 
	if (t->input.deinterlace.enable) { 
		dev_dbg(t->dev, "[0x%p]deinterlace enabled with:\n", (void *)t); 
		if (t->input.deinterlace.motion != HIGH_MOTION) { 
			dev_dbg(t->dev, "[0x%p]\tlow/medium motion\n", (void *)t); 
			dev_dbg(t->dev, "[0x%p]\tpaddr_n = 0x%x\n", 
				(void *)t, t->input.paddr_n); 
		} else 
			dev_dbg(t->dev, "[0x%p]\thigh motion\n", (void *)t); 
	} 

/*列印ipu_task_entry->inputbuffer的一些資訊。*/

	dev_dbg(t->dev, "[0x%p]output:\n", (void *)t); 
	dev_dbg(t->dev, "[0x%p]\tformat = 0x%x\n", (void *)t, t->output.format); 
	dev_dbg(t->dev, "[0x%p]\twidth = %d\n", (void *)t, t->output.width); 
	dev_dbg(t->dev, "[0x%p]\theight = %d\n", (void *)t, t->output.height); 
	dev_dbg(t->dev, "[0x%p]\tcrop.w = %d\n", (void *)t, t->output.crop.w); 
	dev_dbg(t->dev, "[0x%p]\tcrop.h = %d\n", (void *)t, t->output.crop.h); 
	dev_dbg(t->dev, "[0x%p]\tcrop.pos.x = %d\n", 
			(void *)t, t->output.crop.pos.x); 
	dev_dbg(t->dev, "[0x%p]\tcrop.pos.y = %d\n", 
			(void *)t, t->output.crop.pos.y); 
	dev_dbg(t->dev, "[0x%p]\trotate = %d\n", (void *)t, t->output.rotate); 

/*列印ipu_task_entry->output的資訊。*/

	dev_dbg(t->dev, "[0x%p]output buffer:\n", (void *)t); 
	dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n", (void *)t, t->output.paddr); 
	dev_dbg(t->dev, "[0x%p]\to_off = 0x%x\n", (void *)t, t->set.o_off); 
	dev_dbg(t->dev, "[0x%p]\to_uoff = 0x%x\n", (void *)t, t->set.o_uoff); 
	dev_dbg(t->dev, "[0x%p]\to_voff = 0x%x\n", (void *)t, t->set.o_voff); 
	dev_dbg(t->dev, "[0x%p]\tostride = %d\n", (void *)t, t->set.ostride); 

/*列印ipu_task_entry->outputbuffer的一些資訊。*/

	if (t->overlay_en) { 
		dev_dbg(t->dev, "[0x%p]overlay:\n", (void *)t); 
		dev_dbg(t->dev, "[0x%p]\tformat = 0x%x\n", 
				(void *)t, t->overlay.format); 
		dev_dbg(t->dev, "[0x%p]\twidth = %d\n", 
				(void *)t, t->overlay.width); 
		dev_dbg(t->dev, "[0x%p]\theight = %d\n", 
				(void *)t, t->overlay.height); 
		dev_dbg(t->dev, "[0x%p]\tcrop.w = %d\n", 
				(void *)t, t->overlay.crop.w); 
		dev_dbg(t->dev, "[0x%p]\tcrop.h = %d\n", 
				(void *)t, t->overlay.crop.h); 
		dev_dbg(t->dev, "[0x%p]\tcrop.pos.x = %d\n", 
				(void *)t, t->overlay.crop.pos.x); 
		dev_dbg(t->dev, "[0x%p]\tcrop.pos.y = %d\n", 
				(void *)t, t->overlay.crop.pos.y); 

/*如果使能了overlay_en的話,列印overlay的一些資訊。*/

		dev_dbg(t->dev, "[0x%p]overlay buffer:\n", (void *)t); 
		dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n", 
				(void *)t, t->overlay.paddr); 
		dev_dbg(t->dev, "[0x%p]\tov_off = 0x%x\n", 
				(void *)t, t->set.ov_off); 
		dev_dbg(t->dev, "[0x%p]\tov_uoff = 0x%x\n", 
				(void *)t, t->set.ov_uoff); 
		dev_dbg(t->dev, "[0x%p]\tov_voff = 0x%x\n", 
				(void *)t, t->set.ov_voff); 
		dev_dbg(t->dev, "[0x%p]\tovstride = %d\n", 
				(void *)t, t->set.ovstride); 

/*列印overlaybuffer的一些資訊。*/

		if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) { 
			dev_dbg(t->dev, "[0x%p]local alpha enabled with:\n", 
					(void *)t); 
			dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n", 
					(void *)t, t->overlay.alpha.loc_alp_paddr); 
			dev_dbg(t->dev, "[0x%p]\tov_alpha_off = 0x%x\n", 
					(void *)t, t->set.ov_alpha_off); 
			dev_dbg(t->dev, "[0x%p]\tov_alpha_stride = %d\n", 
					(void *)t, t->set.ov_alpha_stride); 
		} else 
			dev_dbg(t->dev, "[0x%p]globle alpha enabled with value 0x%x\n", 
					(void *)t, t->overlay.alpha.gvalue); 
		if (t->overlay.colorkey.enable) 
			dev_dbg(t->dev, "[0x%p]colorkey enabled with value 0x%x\n", 
					(void *)t, t->overlay.colorkey.value); 
	} 

/*列印alpha通道的一些資訊。*/

	dev_dbg(t->dev, "[0x%p]want task_id = %d\n", (void *)t, t->task_id); 
	dev_dbg(t->dev, "[0x%p]want task mode is 0x%x\n", 
				(void *)t, t->set.mode); 
	dev_dbg(t->dev, "[0x%p]\tIC_MODE = 0x%x\n", (void *)t, IC_MODE); 
	dev_dbg(t->dev, "[0x%p]\tROT_MODE = 0x%x\n", (void *)t, ROT_MODE); 
	dev_dbg(t->dev, "[0x%p]\tVDI_MODE = 0x%x\n", (void *)t, VDI_MODE); 
	dev_dbg(t->dev, "[0x%p]\tTask_no = 0x%x\n\n\n", (void *)t, t->task_no); 
}

/*列印這個task的一些資訊。*/

這個函式裡面就是一些列印資訊,可以在合適的地方新增這些列印資訊來輔助除錯。

14.dump_check_err函式

static void dump_check_err(struct device *dev, int err) 
{ 
	switch (err) { 
	case IPU_CHECK_ERR_INPUT_CROP: 
		dev_err(dev, "input crop setting error\n"); 
		break; 
	case IPU_CHECK_ERR_OUTPUT_CROP: 
		dev_err(dev, "output crop setting error\n"); 
		break; 
	case IPU_CHECK_ERR_OVERLAY_CROP: 
		dev_err(dev, "overlay crop setting error\n"); 
		break; 
	case IPU_CHECK_ERR_INPUT_OVER_LIMIT: 
		dev_err(dev, "input over limitation\n"); 
		break; 
	case IPU_CHECK_ERR_OVERLAY_WITH_VDI: 
		dev_err(dev, "do not support overlay with deinterlace\n"); 
		break; 
	case IPU_CHECK_ERR_OV_OUT_NO_FIT: 
		dev_err(dev, 
			"width/height of overlay and ic output should be same\n"); 
		break; 
	case IPU_CHECK_ERR_PROC_NO_NEED: 
		dev_err(dev, "no ipu processing need\n"); 
		break; 
	case IPU_CHECK_ERR_SPLIT_INPUTW_OVER: 
		dev_err(dev, "split mode input width overflow\n"); 
		break; 
	case IPU_CHECK_ERR_SPLIT_INPUTH_OVER: 
		dev_err(dev, "split mode input height overflow\n"); 
		break; 
	case IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER: 
		dev_err(dev, "split mode output width overflow\n"); 
		break; 
	case IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER: 
		dev_err(dev, "split mode output height overflow\n"); 
		break; 
	case IPU_CHECK_ERR_SPLIT_WITH_ROT: 
		dev_err(dev, "not support split mode with rotation\n"); 
		break; 
	case IPU_CHECK_ERR_W_DOWNSIZE_OVER: 
		dev_err(dev, "horizontal downsizing ratio overflow\n"); 
		break; 
	case IPU_CHECK_ERR_H_DOWNSIZE_OVER: 
		dev_err(dev, "vertical downsizing ratio overflow\n"); 
		break; 
	default: 
		break; 
	} 
}

這個函式在check_task裡面呼叫。在上一個ipu_device.c分析(一)中分析的框架中,

staticstruct file_operations mxc_ipu_fops = { 。。。

.unlocked_ioctl= mxc_ipu_ioctl,

};

在這個mxc_ipu_ioctl函式中,它為應用程式提供了這個IPU_CHECK_TASKioctl巨集,這個巨集的核心是ipu_check_task函式,在這個ipu_check_task函式中呼叫了check_task函式來檢查task是否出錯,這個函式會生成各個錯誤資訊,然後就會呼叫這個dump_check_err函式將錯誤資訊打印出來。同時也會呼叫dump_check_warn函式來列印警告資訊,這個dump_check_warn函式在下面貼出來。

15.dump_check_warn函式

static void dump_check_warn(struct device *dev, int warn) 
{ 
	if (warn & IPU_CHECK_WARN_INPUT_OFFS_NOT8ALIGN) 
		dev_warn(dev, "input u/v offset not 8 align\n"); 
	if (warn & IPU_CHECK_WARN_OUTPUT_OFFS_NOT8ALIGN) 
		dev_warn(dev, "output u/v offset not 8 align\n"); 
	if (warn & IPU_CHECK_WARN_OVERLAY_OFFS_NOT8ALIGN) 
		dev_warn(dev, "overlay u/v offset not 8 align\n"); 
}

16.set_crop函式

static int set_crop(struct ipu_crop *crop, int width, int height, int fmt) 
{ 
	if ((width == 0) || (height == 0)) { 
		pr_err("Invalid param: width=%d, height=%d\n", width, height); 
		return -EINVAL; 
	} 

	if ((IPU_PIX_FMT_TILED_NV12 == fmt) || 
		(IPU_PIX_FMT_TILED_NV12F == fmt)) { 
		if (crop->w || crop->h) { 
			if (((crop->w + crop->pos.x) > width) 
			|| ((crop->h + crop->pos.y) > height) 
			|| (0 != (crop->w % IPU_PIX_FMT_TILED_NV12_MBALIGN)) 
			|| (0 != (crop->h % IPU_PIX_FMT_TILED_NV12_MBALIGN)) 
			|| (0 != (crop->pos.x % IPU_PIX_FMT_TILED_NV12_MBALIGN)) 
			|| (0 != (crop->pos.y % IPU_PIX_FMT_TILED_NV12_MBALIGN)) 
			) { 
				pr_err("set_crop error MB align.\n"); 
				return -EINVAL; 
			} 
		} else { 
			crop->pos.x = 0; 
			crop->pos.y = 0; 
			crop->w = width; 
			crop->h = height; 
			if ((0 != (crop->w % IPU_PIX_FMT_TILED_NV12_MBALIGN)) 
			|| (0 != (crop->h % IPU_PIX_FMT_TILED_NV12_MBALIGN))) { 
				pr_err("set_crop error w/h MB align.\n"); 
				return -EINVAL; 
			} 
		} 
	} else { 
		if (crop->w || crop->h) { 
			if (((crop->w + crop->pos.x) > (width + 16)) 
			|| ((crop->h + crop->pos.y) > height + 16)) { 
				pr_err("set_crop error exceeds width/height.\n"); 
				return -EINVAL; 
			} 
		} else { 
			crop->pos.x = 0; 
			crop->pos.y = 0; 
			crop->w = width; 
			crop->h = height; 
		} 
		crop->w -= crop->w%8; 
		crop->h -= crop->h%8; 
	} 

	if ((crop->w == 0) || (crop->h == 0)) { 
		pr_err("Invalid crop param: crop.w=%d, crop.h=%d\n", 
			crop->w, crop->h); 
		return -EINVAL; 
	} 

	return 0; 
}

這個函式根據傳入的widthheightfmt引數設定傳入的structipu_crop*crop引數。它在檔案中主要是用來設定ipu_task_entry結構體中的ipu_output結構體裡面的structipu_crop crop。它在check_taskdo_task_vdoa_vdi函式中都有呼叫。

17.update_offset函式

static void update_offset(unsigned int fmt, 
				unsigned int width, unsigned int height, 
				unsigned int pos_x, unsigned int pos_y, 
				int *off, int *uoff, int *voff, int *stride) 
{ 
	/* NOTE: u v offset should based on start point of off*/ 
	switch (fmt) { 
	case IPU_PIX_FMT_YUV420P2: 
	case IPU_PIX_FMT_YUV420P: 
		*off = pos_y * width + pos_x; 
		*uoff = (width * (height - pos_y) - pos_x) 
			+ (width/2) * (pos_y/2) + pos_x/2; 
		/* In case height is odd, round up to even */ 
		*voff = *uoff + (width/2) * ((height+1)/2); 
		break; 
	case IPU_PIX_FMT_YVU420P: 
		*off = pos_y * width + pos_x; 
		*voff = (width * (height - pos_y) - pos_x) 
			+ (width/2) * (pos_y/2) + pos_x/2; 
		/* In case height is odd, round up to even */ 
		*uoff = *voff + (width/2) * ((height+1)/2); 
		break; 
	case IPU_PIX_FMT_YVU422P: 
		*off = pos_y * width + po