4.4 ipu_param_mem.h头文件分析

1.下面这两个结构体是本文件的核心结构体。

struct ipu_ch_param_word { 
	uint32_t data[5]; 
	uint32_t res[3]; 
}; 

struct ipu_ch_param { 
	struct ipu_ch_param_word word[2]; 
};

因为CPMEM是两个160位的word,所以每个word使用5uint32_t类型来表示,同时有两个word


2.这个宏暂时不分析,在后面用到的时候再分析。

#define ipu_ch_param_addr(ipu, ch) (((struct ipu_ch_param *)ipu->cpmem_base) + (ch))

3._param_word

#define _param_word(base, w) \ 
	(((struct ipu_ch_param *)(base))->word[(w)].data)

这个宏有两个参数,第一个参数是一个起始地址值,它一般是一个指针,在宏中会进行强制类型转化;第二个参数是第几个word,看ipu_ch_param结构体,它的取值为01

这个宏的意思是根据base这个起始地址值取到里面的第wworddata数据段。


4.ipu_ch_param_set_field

#define ipu_ch_param_set_field(base, w, bit, size, v) { \ 
	int i = (bit) / 32; \ 
	int off = (bit) % 32; \ 
	_param_word(base, w)[i] |= (v) << off; \ 
	if (((bit)+(size)-1)/32 > i) { \ 
		_param_word(base, w)[i + 1] |= (v) >> (off ? (32 - off) : 0); \ 
	} \ 
}

这个宏有5个参数,前两个参数与_param_word宏中的参数相同,它们也确实是给_param_word宏使用的。第三个参数bit表示某一个数据在通过_param_word宏所找到的data数据段中的准确起始bit位,因为data数据段是uint32_tdata[5]的,所以这个值的范围为0160size表示数据所占的位数。v表示传入的数据字面值。

这个宏的意思是首先通过(bit)/32来计算出这个数据的起始bitdata数组成员中的哪一个(因为data数组有5个成员)。然后off表示这个数据在data数组成员中的偏移值。然后通过_param_word(base,w)[i]来找到对应的data数组成员。同时这个宏中也给出了这个数据所占的位数:size,如果bit所在的data数组成员放不下这么多size数的话,就需要在data数组中的下一个数组成员中存储剩下的bit

注意在数据的存储过程中涉及到大端小端的问题,对大端小端的解释:http://www.cnblogs.com/wuyuegb2312/archive/2013/06/08/3126510.html#轻松记住大端小端的含义(附对大端和小端的解释)


以下面这个函数中的各个数据为例来解释一下:

static inline void _ipu_ch_params_set_packing(struct ipu_ch_param *p, 
					      int red_width, int red_offset, 
					      int green_width, int green_offset, 
					      int blue_width, int blue_offset, 
					      int alpha_width, int alpha_offset) 
{ 
	/* Setup red width and offset */ 
	ipu_ch_param_set_field(p, 1, 116, 3, red_width - 1); 
	ipu_ch_param_set_field(p, 1, 128, 5, red_offset); 
	/* Setup green width and offset */ 
	ipu_ch_param_set_field(p, 1, 119, 3, green_width - 1); 
	ipu_ch_param_set_field(p, 1, 133, 5, green_offset); 
	/* Setup blue width and offset */ 
	ipu_ch_param_set_field(p, 1, 122, 3, blue_width - 1); 
	ipu_ch_param_set_field(p, 1, 138, 5, blue_offset); 
	/* Setup alpha width and offset */ 
	ipu_ch_param_set_field(p, 1, 125, 3, alpha_width - 1); 
	ipu_ch_param_set_field(p, 1, 143, 5, alpha_offset); 
}

首先ipu_ch_param_set_field( p, 1, 116, 3, red_width – 1)为例:

#define ipu_ch_param_set_field( base,  w,   bit,  size,        v) { \ 
	int i = (bit) / 32; \ 
	int off = (bit) % 32; \ 
	_param_word(base, w)[i] |= (v) << off; \ 
	if (((bit)+(size)-1)/32 > i) { \ 
		_param_word(base, w)[i + 1] |= (v) >> (off ? (32 - off) : 0); \ 
	} \ 
}

解释:

i= 116/32= 3

off= 116%32 = 20

#define _param_word(base, w) \ 
	(((struct ipu_ch_param *)(base))->word[(w)].data)

_param_word(base,w)[i] |= (v) << off

     ==>p->word[w].data[i]|= (v) << off

         ==>p->word[1].data[3] |= (red_width – 1)<<20;


如下图所示:


然后继续往下执行:

ipu_ch_param_set_field(p, 1, 119, 3, green_width – 1);
ipu_ch_param_set_field(p, 1, 122, 3, blue_width – 1); 
ipu_ch_param_set_field(p, 1, 125, 3, alpha_width - 1); 

同样,它最终就会在119的位置存储(green_width– 1),在122的位置存储(blue_width– 1),在125的位置存储(alpha_width– 1)。

它们详细表示如下:


同样对于

ipu_ch_param_set_field(p, 1, 128, 5, red_offset);
ipu_ch_param_set_field(p, 1, 133, 5, green_offset);
ipu_ch_param_set_field(p, 1, 138, 5, blue_offset);
ipu_ch_param_set_field(p, 1, 143, 5, alpha_offset); 

它们详细表示如下:


再分析一ipu_ch_param_set_field函数中w=1, bit = 125, size = 13 的情况,对大端小端理解的更清楚。

i= 125/32 = 3

off= 125%32 = 29

_param_word(base,w)[i] |= (v) << off

     ==>p->word[w].data[i] |= (v) << off

         ==>p->word[1].data[3] |= (v)<<29;

if(((bit)+(size)-1)/32 > i) 125+12/32= 4 > 3成立,所以会执行if下面的语句:

_param_word(base,w)[i + 1] |= (v) >> (off ? (32 - off) : 0);

     ==>_param_word(base,w)[4] |= (v) >> 3

         ==>p->word[1].data[4]|=(v) >> 3

重要的部分我用红色标出了,


从这里可以看出来,它的存储方式是将v的前10位存在了data[4]中,而v的后3位存在了data[3]中,从这里可以看出来,数据的存储方式是小端模式。


5.ipu_ch_param_set_field_io

#define ipu_ch_param_set_field_io(base, w, bit, size, v) { \ 
	int i = (bit) / 32; \ 
	int off = (bit) % 32; \ 
	unsigned reg_offset; \ 
	u32 temp; \ 
	reg_offset = sizeof(struct ipu_ch_param_word) * w / 4; \ 
	reg_offset += i; \ 
	temp = readl((u32 *)base + reg_offset); \ 
	temp |= (v) << off; \ 
	writel(temp, (u32 *)base + reg_offset); \ 
	if (((bit)+(size)-1)/32 > i) { \ 
		reg_offset++; \ 
		temp = readl((u32 *)base + reg_offset); \ 
		temp |= (v) >> (off ? (32 - off) : 0); \ 
		writel(temp, (u32 *)base + reg_offset); \ 
	} \ 
}

这个宏根据basewbit的值计算出寄存器的位置,然后将v的值写进去。


但是这个ipu_ch_param_set_field_io宏与上面那个ipu_ch_param_set_field宏有什么不同呢?

往下搜索源码可以发现,虽然这两个宏的第一个参数都是base,但是他们两个不相同:

ipu_ch_param_set_field(¶ms, 0, 125, 13, width – 1);
ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, ch), 0, 113, 1, 1);

而这个ipu_ch_param_addr宏就是本文件开始的那个宏

#defineipu_ch_param_addr(ipu, ch) (((struct ipu_ch_param *)ipu->cpmem_base)+ (ch))

这个宏根据ipuch两个参数来找到对应寄存器的基址,具体来说就是根据ipu_soc结构体里面存放的cpmem_base寄存器的地址,ch是一般是uint32_t类型的dmachannel,通过这两个参数来找到对应寄存器的基地址。所以这个cpmem_base寄存器是设置dmachannel的关键寄存器。

对比上面两条语句,可以发现ipu_ch_param_set_field宏用于设置structipu_ch_param结构体参数params中某些位的值。而ipu_ch_param_set_field_io宏根据传入的ipuch参数来找到某个寄存器的基址,然后修改这个寄存器中的某些位。

以下的几个宏都与这两种情况类似。


6.ipu_ch_param_mod_field

#define ipu_ch_param_mod_field(base, w, bit, size, v) { \ 
	int i = (bit) / 32; \ 
	int off = (bit) % 32; \ 
	u32 mask = (1UL << size) - 1; \ 
	u32 temp = _param_word(base, w)[i]; \ 
	temp &= ~(mask << off); \ 
	_param_word(base, w)[i] = temp | (v) << off; \ 
	if (((bit)+(size)-1)/32 > i) { \ 
		temp = _param_word(base, w)[i + 1]; \ 
		temp &= ~(mask >> (32 - off)); \ 
		_param_word(base, w)[i + 1] = \ 
			temp | ((v) >> (off ? (32 - off) : 0)); \ 
	} \ 
}

这个函数首先为size大小设置掩码,比如size=7,这个mask就等于111111(二进制),然后通过temp&= ~(mask << off)将这几位都清零,最后再通过temp| (v) << offv的值写到这几位中。修改某些位值的时候,一定要先清零了再写。

7.ipu_ch_param_mod_field_io

#define ipu_ch_param_mod_field_io(base, w, bit, size, v) { \ 
	int i = (bit) / 32; \ 
	int off = (bit) % 32; \ 
	u32 mask = (1UL << size) - 1; \ 
	unsigned reg_offset; \ 
	u32 temp; \ 
	reg_offset = sizeof(struct ipu_ch_param_word) * w / 4; \ 
	reg_offset += i; \ 
	temp = readl((u32 *)base + reg_offset); \ 
	temp &= ~(mask << off); \ 
	temp |= (v) << off; \ 
	writel(temp, (u32 *)base + reg_offset); \ 
	if (((bit)+(size)-1)/32 > i) { \ 
		reg_offset++; \ 
		temp = readl((u32 *)base + reg_offset); \ 
		temp &= ~(mask >> (32 - off)); \ 
		temp |= ((v) >> (off ? (32 - off) : 0)); \ 
		writel(temp, (u32 *)base + reg_offset); \ 
	} \ 
}

这个宏与上一个宏类似,修改寄存器中某些位的值。


8.ipu_ch_param_read_field

#define ipu_ch_param_read_field(base, w, bit, size) ({ \ 
	u32 temp2; \ 
	int i = (bit) / 32; \ 
	int off = (bit) % 32; \ 
	u32 mask = (1UL << size) - 1; \ 
	u32 temp1 = _param_word(base, w)[i]; \ 
	temp1 = mask & (temp1 >> off); \ 
	if (((bit)+(size)-1)/32 > i) { \ 
		temp2 = _param_word(base, w)[i + 1]; \ 
		temp2 &= mask >> (off ? (32 - off) : 0); \ 
		temp1 |= temp2 << (off ? (32 - off) : 0); \ 
	} \ 
	temp1; \ 
})

这个宏的意思是读取某些位的值,这个宏最后的结果是temp1的值。


9.ipu_ch_param_read_field_io

#define ipu_ch_param_read_field_io(base, w, bit, size) ({ \ 
	u32 temp1, temp2; \ 
	int i = (bit) / 32; \ 
	int off = (bit) % 32; \ 
	u32 mask = (1UL << size) - 1; \ 
	unsigned reg_offset; \ 
	reg_offset = sizeof(struct ipu_ch_param_word) * w / 4; \ 
	reg_offset += i; \ 
	temp1 = readl((u32 *)base + reg_offset); \ 
	temp1 = mask & (temp1 >> off); \ 
	if (((bit)+(size)-1)/32 > i) { \ 
		reg_offset++; \ 
		temp2 = readl((u32 *)base + reg_offset); \ 
		temp2 &= mask >> (off ? (32 - off) : 0); \ 
		temp1 |= temp2 << (off ? (32 - off) : 0); \ 
	} \ 
	temp1; \ 
})

这个宏的意思是读取某个寄存器中某些位的值,最后的结果是temp1


10.__ipu_ch_get_third_buf_cpmem_num函数

static inline int __ipu_ch_get_third_buf_cpmem_num(int ch) 
{ 
	switch (ch) { 
	case 8: 
		return 64; 
	case 9: 
		return 65; 
	case 10: 
		return 66; 
	case 13: 
		return 67; 
	case 21: 
		return 68; 
	case 23: 
		return 69; 
	case 27: 
		return 70; 
	case 28: 
		return 71; 
	default: 
		return -EINVAL; 
	} 
	return 0; 
}

这个函数的大致意思是从函数传入的参数ch中获取到第三个buffer的起始地址。


11._ipu_ch_params_set_packing函数

static inline void _ipu_ch_params_set_packing(struct ipu_ch_param *p, 
					      int red_width, int red_offset, 
					      int green_width, int green_offset, 
					      int blue_width, int blue_offset, 
					      int alpha_width, int alpha_offset) 
{ 
	/* Setup red width and offset */ 
	ipu_ch_param_set_field(p, 1, 116, 3, red_width - 1); 
	ipu_ch_param_set_field(p, 1, 128, 5, red_offset); 
	/* Setup green width and offset */ 
	ipu_ch_param_set_field(p, 1, 119, 3, green_width - 1); 
	ipu_ch_param_set_field(p, 1, 133, 5, green_offset); 
	/* Setup blue width and offset */ 
	ipu_ch_param_set_field(p, 1, 122, 3, blue_width - 1); 
	ipu_ch_param_set_field(p, 1, 138, 5, blue_offset); 
	/* Setup alpha width and offset */ 
	ipu_ch_param_set_field(p, 1, 125, 3, alpha_width - 1); 
	ipu_ch_param_set_field(p, 1, 143, 5, alpha_offset); 
}

这个函数在前面分析了,它主要目的是设置第一个参数p里面的red_widthred_offsetgreen_widthgreen_offset等信息。这个函数在_ipu_ch_param_init函数中调用,比如下面这样:

_ipu_ch_params_set_packing(&params,5, 0, 6, 5, 5, 11, 8, 16);

通过这样调用,就分别设置了params中的RGB的信息,从上面可以看出来是RGB565格式的。

_ipu_ch_params_set_packing(&params,4, 4, 4, 8, 4, 12, 4, 0);

这样调用设置的是RGBA4444的格式。


12._ipu_ch_param_dump函数

这个函数是输出ipu_ch_param中的一些信息,就不分析了。


13.fill_cpmem函数

static inline void fill_cpmem(struct ipu_soc *ipu, int ch, struct ipu_ch_param *params) 
{ 
	int i, w; 
	void *addr = ipu_ch_param_addr(ipu, ch); 

	/* 2 words, 5 valid data */ 
	for (w = 0; w < 2; w++) { 
		for (i = 0; i < 5; i++) { 
			writel(params->word[w].data[i], addr); 
			addr += 4; 
		} 
		addr += 12; 
	} 
}

这个函数首先通过ipu_ch_param_addr函数根据ipuch参数取得dmachannel的基址,然后将params参数里面两个word里面的data数据填充到获得的这个基址中。这个函数被_ipu_ch_param_init函数中调用。


14._ipu_ch_param_init函数

static inline void _ipu_ch_param_init(struct ipu_soc *ipu, int ch, 
				      uint32_t pixel_fmt, uint32_t width, 
				      uint32_t height, uint32_t stride, 
				      uint32_t u, uint32_t v, 
				      uint32_t uv_stride, dma_addr_t addr0, 
				      dma_addr_t addr1, dma_addr_t addr2) 
{ 
	uint32_t u_offset = 0; 
	uint32_t v_offset = 0; 
	uint32_t bs = 0; 
	int32_t sub_ch = 0; 
	struct ipu_ch_param params; 

	memset(&params<style type="text/css">p { margin-bottom: 0.25cm; line-height: 120%; }a:link {  }&params</style>, 0, sizeof(params)); 

	ipu_ch_param_set_field(<span style="background: transparent"><span style="font-family:Courier 10 Pitch;"><span style="font-size:12px;"><span style="background: transparent"></span></span></span></span>&params<span style="background: transparent"><span style="font-family:Courier 10 Pitch;"><span style="font-size:12px;"><span style="background: transparent"></span></span></span></span>, 0, 125, 13, width - 1); 

/*params参数里面的word[0]里面的125位到138位设置为(width- 1) */

	if (((ch == 8) || (ch == 9) || (ch == 10)) && !ipu->vdoa_en) { 
		ipu_ch_param_set_field(<span style="background: transparent"><span style="font-family:Courier 10 Pitch;"><span style="font-size:12px;"><span style="background: transparent"></span></span></span></span>&params<span style="background: transparent"><span style="font-family:Courier 10 Pitch;"><span style="font-size:12px;"><span style="background: transparent"></span></span></span></span><span style="background: transparent"><span style="font-family:Courier 10 Pitch;"><span style="font-size:12px;"><span style="background: transparent"></span></span></span></span>, 0, 138, 12, (height / 2) - 1); 
		ipu_ch_param_set_field(<span style="background: transparent"><span style="font-family:Courier 10 Pitch;"><span style="font-size:12px;"><span style="background: transparent"></span></span></span></span>&para<span style="background: transparent"><span style="font-family:Courier 10 Pitch;"><span style="font-size:12px;"><span style="background: transparent"></span></span></span></span>ms, 1, 102, 14, (stride * 2) – 1); 

/*params参数里面的word[0]里面的138位到150位设置为((height/ 2) - 1) */

/*params参数里面的word[1]里面的102位到116位设置为((stride* 2) - 1) */

	} else { 
		/* note: for vdoa+vdi- ch8/9/10, always use band mode */ 
		ipu_ch_param_set_field(<span style="background: transparent"></span>&para<span style="background: transparent"><span style="font-family:Courier 10 Pitch;"><span style="font-size:12px;"><span style="background: transparent"></span></span></span></span>ms, 0, 138, 12, height - 1); 
<span style="background: transparent"><span style="font-family:Courier 10 Pitch;"><span style="font-size:12px;"><span style="background: transparent"></span></span></span></span>		ipu_ch_param_set_field(<span style="background: transparent"><span style="font-family:Courier 10 Pitch;"><span style="font-size:12px;"><span style="background: transparent"></span></span></span></span>&para<span style="background: transparent"><span style="font-family:Courier 10 Pitch;"><span style="font-size:12px;"><span style="background: transparent"></span></span></span></span>ms<span style="background: transparent"><span style="font-family:Courier 10 Pitch;"><span style="font-size:12px;"><span style="background: transparent"></span></span></span></span>, 1, 102, 14, stride - 1); 
	} 

/*params参数里面的word[0]里面的138位到150位设置为(height- 1) */

/*params参数里面的word[1]里面的102位到116位设置为(stride- 1) */

如果channel8/9/10的话,从注释上来看是vdoa+vdichannel,用的是bandmode,会将params那几位设置成height/2stride*2

	/* EBA is 8-byte aligned */ 
	ipu_ch_param_set_field(<span style="background: transparent"><span style="font-family:Courier 10 Pitch;"><span style="font-size:12px;"><span style="background: transparent"></span></span></span></span>&para<span style="background: transparent"><span style="font-family:Courier 10 Pitch;"><span style="font-size:12px;"><span style="background: transparent"></span></span></span></span>ms<span style="background: transparent"><span style="font-family:Courier 10 Pitch;"><span style="font-size:12px;"><span style="background: transparent"></span></span></span></span>, 1, 0, 29, addr0 >> 3); 
	ipu_ch_param_set_field(<span style="font-family:Courier 10 Pitch;">&params</span>, 1, 29, 29, addr1 >> 3); 
	if (addr0%8) 
		dev_warn(ipu->dev, 
			 "IDMAC%d's EBA0 is not 8-byte aligned\n", ch); 
	if (addr1%8) 
		dev_warn(ipu->dev, 
			 "IDMAC%d's EBA1 is not 8-byte aligned\n", ch); 

/*params参数里面的word[1]里面的0位到29位设置为(addr0>> 3)29位到58位设置成addr1>> 3原因是EBA8字节对齐的,后面需要分析这里*/

	switch (pixel_fmt) { 
	case IPU_PIX_FMT_GENERIC: 
		/*Represents 8-bit Generic data */ 
		ipu_ch_param_set_field(<span style="background: transparent"><span style="font-family:Courier 10 Pitch;"><span style="font-size:12px;"><span style="background: transparent"></span></span></span></span><span style="font-family:Courier 10 Pitch;">&params</span><span style="background: transparent"><span style="font-family:Courier 10 Pitch;"><span style="font-size:12px;"><span style="background: transparent"></span></span></span></span>, 0, 107, 3, 5);	/* bits/pixel */ 
		ipu_ch_param_set_field(<span style="background: transparent"><span style="font-family:Courier 10 Pitch;"><span style="font-size:12px;"><span style="background: transparent"></span></span></span></span><span style="font-family:Courier 10 Pitch;">&params</span><span style="background: transparent"><span style="font-family:Courier 10 Pitch;"><span style="font-size:12px;"><span style="background: transparent"></span></span></span></span>, 1, 85, 4, 6);	/* pix format */ 
		ipu_ch_param_set_field(<span style="background: transparent"><span style="font-family:Courier 10 Pitch;"><span style="font-size:12px;"><span style="background: transparent"></span></span></span></span><span style="font-family:Courier 10 Pitch;">&params</span><span style="background: transparent"><span style="font-family:Courier 10 Pitch;"><span style="font-size:12px;"><span style="background: transparent"></span></span></span></span>, 1, 78, 7, 63);	/* burst size */ 

		break; 
	case IPU_PIX_FMT_GENERIC_16: 
		/* Represents 16-bit generic data */ 
		ipu_ch_param_set_field(<style type="text/css">p { margin-bottom: 0.25cm; line-height: 120%; }a:link {  }&params</style><span style="background: transparent"><span style="font-family:Courier 10 Pitch;"><span style="font-size:12px;"><span style="background: transparent"></span></span></span></span><span style="font-family:Courier 10 Pitch;">&params</span><span style="background: transparent"><span style="font-family:Courier 10 Pitch;"><span style="font-size:12px;"><span style="background: transparent"></span></span></span></span>, 0, 107, 3, 3);	/* bits/pixel */ 
		ipu_ch_param_set_field(<span style="background: transparent"><span style="font-family:Courier 10 Pitch;"><span style="font-size:12px;"><span style="background: transparent"></span></span></span></span><span style="font-family:Courier 10 Pitch;">&params</span><span style="background: transparent"><span style="font-family:Courier 10 Pitch;"><span style="font-size:12px;"><span style="background: transparent"></span></span></span></span>, 1, 85, 4, 6);	/* pix format */ 
		ipu_ch_param_set_field(<span style="background: transparent"><span style="font-family:Courier 10 Pitch;"><span style="font-size:12px;"><span style="background: transparent"></span></span></span></span><span style="font-family:Courier 10 Pitch;">&params</span><span style="background: transparent"><span style="font-family:Courier 10 Pitch;"><span style="font-size:12px;"><span style="background: transparent"></span></span></span></span>, 1, 78, 7, 31);	/* burst size */ 

		break; 
	case IPU_PIX_FMT_GENERIC_32: 
		/*Represents 32-bit Generic data */ 
		break; 
	case IPU_PIX_FMT_RGB565: 
		ipu_ch_param_set_field(¶ms, 0, 107, 3, 3);	/* bits/pixel */ 
		ipu_ch_param_set_field(¶ms, 1, 85, 4, 7);	/* pix format */ 
		ipu_ch_param_set_field(¶ms, 1, 78, 7, 31);	/* burst size */ 
 
		_ipu_ch_params_set_packing(¶ms, 5, 0, 6, 5, 5, 11, 8, 16); 
		break; 
	case IPU_PIX_FMT_BGRA4444: 
		ipu_ch_param_set_field(¶ms, 0, 107, 3, 3);	/* bits/pixel */ 
		ipu_ch_param_set_field(¶ms, 1, 85, 4, 7);	/* pix format */ 
		ipu_ch_param_set_field(¶ms, 1, 78, 7, 31);	/* burst size */ 

		_ipu_ch_params_set_packing(¶ms, 4, 4, 4, 8, 4, 12, 4, 0); 
		break; 
	case IPU_PIX_FMT_BGRA5551: 
		ipu_ch_param_set_field(¶ms, 0, 107, 3, 3);	/* bits/pixel */ 
		ipu_ch_param_set_field(¶ms, 1, 85, 4, 7);	/* pix format */ 
		ipu_ch_param_set_field(¶ms, 1, 78, 7, 31);	/* burst size */ 

		_ipu_ch_params_set_packing(¶ms, 5, 1, 5, 6, 5, 11, 1, 0); 
		break; 
	case IPU_PIX_FMT_BGR24: 
		ipu_ch_param_set_field(¶ms, 0, 107, 3, 1);	/* bits/pixel */ 
		ipu_ch_param_set_field(¶ms, 1, 85, 4, 7);	/* pix format */ 
		ipu_ch_param_set_field(¶ms, 1, 78, 7, 19);	/* burst size */ 

		_ipu_ch_params_set_packing(¶ms, 8, 0, 8, 8, 8, 16, 8, 24); 
		break; 
	case IPU_PIX_FMT_RGB24: 
	case IPU_PIX_FMT_YUV444: 
		ipu_ch_param_set_field(¶ms, 0, 107, 3, 1);	/* bits/pixel */ 
		ipu_ch_param_set_field(¶ms, 1, 85, 4, 7);	/* pix format */ 
		ipu_ch_param_set_field(¶ms, 1, 78, 7, 19);	/* burst size */ 

		_ipu_ch_params_set_packing(¶ms, 8, 16, 8, 8, 8, 0, 8, 24); 
		break; 
	case IPU_PIX_FMT_VYU444: 
		ipu_ch_param_set_field(¶ms, 0, 107, 3, 1);	/* bits/pixel */ 
		ipu_ch_param_set_field(¶ms, 1, 85, 4, 7);	/* pix format */ 
		ipu_ch_param_set_field(¶ms, 1, 78, 7, 19);	/* burst size */ 

		_ipu_ch_params_set_packing(¶ms, 8, 8, 8, 0, 8, 16, 8, 24); 
		break; 
	case IPU_PIX_FMT_AYUV: 
		ipu_ch_param_set_field(¶ms, 0, 107, 3, 0);	/* bits/pixel */ 
		ipu_ch_param_set_field(¶ms, 1, 85, 4, 7);	/* pix format */ 
		ipu_ch_param_set_field(¶ms, 1, 78, 7, 15);	/* burst size */ 

		_ipu_ch_params_set_packing(¶ms, 8, 8, 8, 16, 8, 24, 8, 0); 
		break; 
	case IPU_PIX_FMT_BGRA32: 
	case IPU_PIX_FMT_BGR32: 
		ipu_ch_param_set_field(¶ms, 0, 107, 3, 0);	/* bits/pixel */ 
		ipu_ch_param_set_field(¶ms, 1, 85, 4, 7);	/* pix format */ 
		ipu_ch_param_set_field(¶ms, 1, 78, 7, 15);	/* burst size */ 

		_ipu_ch_params_set_packing(¶ms, 8, 8, 8, 16, 8, 24, 8, 0); 
		break; 
	case IPU_PIX_FMT_RGBA32: 
	case IPU_PIX_FMT_RGB32: 
		ipu_ch_param_set_field(¶ms, 0, 107, 3, 0);	/* bits/pixel */ 
		ipu_ch_param_set_field(¶ms, 1, 85, 4, 7);	/* pix format */ 
		ipu_ch_param_set_field(¶ms, 1, 78, 7, 15);	/* burst size */ 

		_ipu_ch_params_set_packing(¶ms, 8, 24, 8, 16, 8, 8, 8, 0); 
		break; 
	case IPU_PIX_FMT_ABGR32: 
		ipu_ch_param_set_field(¶ms, 0, 107, 3, 0);	/* bits/pixel */ 
		ipu_ch_param_set_field(¶ms, 1, 85, 4, 7);	/* pix format */ 
		ipu_ch_param_set_field(¶ms, 1, 78, 7, 15);	/* burst size */ 

		_ipu_ch_params_set_packing(¶ms, 8, 0, 8, 8, 8, 16, 8, 24); 
		break; 
	case IPU_PIX_FMT_UYVY: 
		ipu_ch_param_set_field(¶ms, 0, 107, 3, 3);	/* bits/pixel */ 
		ipu_ch_param_set_field(¶ms, 1, 85, 4, 0xA);	/* pix format */ 
		if ((ch == 8) || (ch == 9) || (ch == 10)) { 
			ipu_ch_param_set_field(¶ms, 1, 78, 7, 15);  /* burst size */ 
		} else { 
			ipu_ch_param_set_field(¶ms, 1, 78, 7, 31);	/* burst size */ 
		} 
		break; 
	case IPU_PIX_FMT_YUYV: 
		ipu_ch_param_set_field(¶ms, 0, 107, 3, 3);	/* bits/pixel */ 
		ipu_ch_param_set_field(¶ms, 1, 85, 4, 0x8);	/* pix format */ 
		if ((ch == 8) || (ch == 9) || (ch == 10)) { 
			if (ipu->vdoa_en) { 
				ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); 
			} else { 
				ipu_ch_param_set_field(¶ms, 1, 78, 7, 15); 
			} 
		} else { 
			ipu_ch_param_set_field(¶ms, 1, 78, 7, 31);	/* burst size */ 
		} 
		break; 
	case IPU_PIX_FMT_YUV420P2: 
	case IPU_PIX_FMT_YUV420P: 
		ipu_ch_param_set_field(¶ms, 1, 85, 4, 2);	/* pix format */ 

		if (uv_stride < stride / 2) 
			uv_stride = stride / 2; 

		u_offset = stride * height; 
		v_offset = u_offset + (uv_stride * height / 2); 
		if ((ch == 8) || (ch == 9) || (ch == 10)) { 
			ipu_ch_param_set_field(¶ms, 1, 78, 7, 15);  /* burst size */ 
			uv_stride = uv_stride*2; 
		} else { 
			if (_ipu_is_smfc_chan(ch) && 
				ipu->smfc_idmac_12bit_3planar_bs_fixup) 
				bs = 15; 
			else 
				bs = 31; 
			ipu_ch_param_set_field(¶ms, 1, 78, 7, bs);  /* burst size */ 
		} 
		break; 
	case IPU_PIX_FMT_YVU420P: 
		ipu_ch_param_set_field(¶ms, 1, 85, 4, 2);	/* pix format */ 

		if (uv_stride < stride / 2) 
			uv_stride = stride / 2; 

		v_offset = stride * height; 
		u_offset = v_offset + (uv_stride * height / 2); 
		if ((ch == 8) || (ch == 9) || (ch == 10)) { 
			ipu_ch_param_set_field(¶ms, 1, 78, 7, 15);  /* burst size */ 
			uv_stride = uv_stride*2; 
		} else { 
			if (_ipu_is_smfc_chan(ch) && 
				ipu->smfc_idmac_12bit_3planar_bs_fixup) 
				bs = 15; 
			else 
				bs = 31; 
			ipu_ch_param_set_field(¶ms, 1, 78, 7, bs);  /* burst size */ 
		} 
		break; 
	case IPU_PIX_FMT_YVU422P: 
		/* BPP & pixel format */ 
		ipu_ch_param_set_field(¶ms, 1, 85, 4, 1);	/* pix format */ 
		ipu_ch_param_set_field(¶ms, 1, 78, 7, 31);	/* burst size */ 

		if (uv_stride < stride / 2) 
			uv_stride = stride / 2; 

		v_offset = (v == 0) ? stride * height : v; 
		u_offset = (u == 0) ? v_offset + v_offset / 2 : u; 
		break; 
	case IPU_PIX_FMT_YUV422P: 
		/* BPP & pixel format */ 
		ipu_ch_param_set_field(¶ms, 1, 85, 4, 1);	/* pix format */ 
		ipu_ch_param_set_field(¶ms, 1, 78, 7, 31);	/* burst size */ 

		if (uv_stride < stride / 2) 
			uv_stride = stride / 2; 

		u_offset = (u == 0) ? stride * height : u; 
		v_offset = (v == 0) ? u_offset + u_offset / 2 : v; 
		break; 
	case IPU_PIX_FMT_YUV444P: 
		/* BPP & pixel format */ 
		ipu_ch_param_set_field(¶ms, 1, 85, 4, 0);	/* pix format */ 
		ipu_ch_param_set_field(¶ms, 1, 78, 7, 31);	/* burst size */ 
		uv_stride = stride; 
		u_offset = (u == 0) ? stride * height : u; 
		v_offset = (v == 0) ? u_offset * 2 : v; 
		break; 
	case IPU_PIX_FMT_NV16: 
		ipu_ch_param_set_field(¶ms, 1, 85, 4, 1);	/* pix format */ 
		ipu_ch_param_set_field(¶ms, 1, 78, 7, 31);	/* burst size */ 
		uv_stride = stride; 
		u_offset = (u == 0) ? stride * height : u; 
		break; 
	case IPU_PIX_FMT_NV12: 
		/* BPP & pixel format */ 
		ipu_ch_param_set_field(¶ms, 1, 85, 4, 4);	/* pix format */ 
		uv_stride = stride; 
		u_offset = (u == 0) ? stride * height : u; 
		if ((ch == 8) || (ch == 9) || (ch == 10)) { 
			if (ipu->vdoa_en) { 
				 /* one field buffer, memory width 64bits */ 
				ipu_ch_param_set_field(¶ms, 1, 78, 7, 63); 
			} else { 
				ipu_ch_param_set_field(¶ms, 1, 78, 7, 15); 
				 /* top/bottom field in one buffer*/ 
				uv_stride = uv_stride*2; 
			} 
		} else { 
			ipu_ch_param_set_field(¶ms, 1, 78, 7, 31);	/* burst size */ 
		} 
		break; 
	default: 
		dev_err(ipu->dev, "mxc ipu: unimplemented pixel format\n"); 
		break; 
	} 
	/*set burst size to 16*/ 

/*根据函数传入的pixel_fmt参数的至来决定设置params里面的哪些位。从这个switch语句中可以看出来params参数里面word[0]里面从107位开始的几位决定bits/pixelword[1]里面从85位开始的几位决定pixformatword[1]里面从78位开始的几位决定burstsize*/

	if (uv_stride) 
		ipu_ch_param_set_field(¶ms, 1, 128, 14, uv_stride - 1); 

/*如果uv_stride存在的话,就设置params参数里面的word[1]128位到142位的值为(uv_stride- 1) */

	/* Get the uv offset from user when need cropping */ 
	if (u || v) { 
		u_offset = u; 
		v_offset = v; 
	} 

	/* UBO and VBO are 22-bit and 8-byte aligned */ 
	if (u_offset/8 > 0x3fffff) 
		dev_warn(ipu->dev, 
			 "IDMAC%d's U offset exceeds IPU limitation\n", ch); 
	if (v_offset/8 > 0x3fffff) 
		dev_warn(ipu->dev, 
			 "IDMAC%d's V offset exceeds IPU limitation\n", ch); 
	if (u_offset%8) 
		dev_warn(ipu->dev, 
			 "IDMAC%d's U offset is not 8-byte aligned\n", ch); 
	if (v_offset%8) 
		dev_warn(ipu->dev, 
			 "IDMAC%d's V offset is not 8-byte aligned\n", ch); 

	ipu_ch_param_set_field(¶ms, 0, 46, 22, u_offset / 8); 
	ipu_ch_param_set_field(¶ms, 0, 68, 22, v_offset / 8); 

/*上面这一段代码是设置u_offsetv_offset的值。他俩分别位于params->word[0]里面的46686890位。*/

	dev_dbg(ipu->dev, "initializing idma ch %d @ %p\n", ch, ipu_ch_param_addr(ipu, ch)); 
	fill_cpmem(ipu, ch, ¶ms); 

/*辛辛苦苦设置好了params的值,肯定需要将它使用起来,就是通过这个函数来将params填充到根据ipuch参数找到的基址中。*/

	if (addr2) { //在ipu_common.c中调用的_ipu_ch_param_init函数中有addr2这个值。
		sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch); 
		if (sub_ch <= 0) 
			return; 

/*通过__ipu_ch_get_third_buf_cpmem_num函数来找到第三个buffer的基址。*/

		ipu_ch_param_set_field(¶ms, 1, 0, 29, addr2 >> 3); 
		ipu_ch_param_set_field(¶ms, 1, 29, 29, 0); 
		if (addr2%8) 
			dev_warn(ipu->dev, 
				 "IDMAC%d's sub-CPMEM entry%d EBA0 is not " 
				 "8-byte aligned\n", ch, sub_ch); 

		dev_dbg(ipu->dev, "initializing idma ch %d @ %p sub cpmem\n", ch, 
					ipu_ch_param_addr(ipu, sub_ch)); 
		fill_cpmem(ipu, sub_ch, ¶ms); 
	} 
};

最后这些设置是在某些情况下,比如之前分析过,可能会将几个channel一起启用。这个函数被ipu_common.c中的ipu_init_channel_buffer函数所调用。


15._ipu_ch_param_set_burst_size函数

static inline void _ipu_ch_param_set_burst_size(struct ipu_soc *ipu, 
						uint32_t ch, 
						uint16_t burst_pixels) 
{ 
	int32_t sub_ch = 0; 

	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 78, 7, 
			       burst_pixels - 1); 

	sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch); 
	if (sub_ch <= 0) 
		return; 
	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 78, 7, 
			       burst_pixels - 1); 
};

这个函数用来设置或修改burst_size的值。因为在_ipu_ch_param_init初始化函数中,已经根据pixel_fmt的值设置了burst_size的初始值,在这里可以继续通过ipuch的值来修改他们的burst_size。这个函数被ipu_common.c中的ipu_init_channel_buffer函数所调用。


16._ipu_ch_param_get_burst_size函数

static inline int _ipu_ch_param_get_burst_size(struct ipu_soc *ipu, uint32_t ch) 
{ 
	return ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 78, 7) + 1; 
};

通过ipuch参数找到对应的寄存器然后读取它的值。这个函数被ipu_common.c中的ipu_init_channel_buffer函数所调用。


17._ipu_ch_param_get_bpp函数

static inline int _ipu_ch_param_get_bpp(struct ipu_soc *ipu, uint32_t ch) 
{ 
	return ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 107, 3); 
};

通过ipuch参数找到对应的寄存器然后读取它的值。


18._ipu_ch_param_set_buffer函数

static inline void _ipu_ch_param_set_buffer(struct ipu_soc *ipu, uint32_t ch, 
					int bufNum, dma_addr_t phyaddr) 
{ 
	if (bufNum == 2) { 
		ch = __ipu_ch_get_third_buf_cpmem_num(ch); 
		if (ch <= 0) 
			return; 
		bufNum = 0; 
	} 

	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 29 * bufNum, 29, 
			       phyaddr / 8); 
};

首先根据ipuch来获取基址,然后根据传入的bufNum参数来决定修改基址中的哪些位。这个函数被ipu_common.c中的ipu_update_channel_buffer函数调用。根据手册上面可以看出来,关于buffer的设置是在word[1]中从028,5957,而且根据后面的分析,对于双buffer模式,这个bufNum的取值是0或者1.


19._ipu_ch_param_set_rotation函数

static inline void _ipu_ch_param_set_rotation(struct ipu_soc *ipu, uint32_t ch, 
					      ipu_rotate_mode_t rot) 
{ 
	u32 temp_rot = bitrev8(rot) >> 5; 
	int32_t sub_ch = 0; 

	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 0, 119, 3, temp_rot); 

	sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch); 
	if (sub_ch <= 0) 
		return; 
	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 119, 3, temp_rot); 
};

设置rotation参数,这个函数首先根据rot的值通过bitrev8函数从byte_rev_table数组中取出对应的值,然后将那个值设置到word[0]119121位。这个函数被ipu_common.c中的ipu_init_channel_buffer函数调用


20._ipu_ch_param_set_block_mode函数

static inline void _ipu_ch_param_set_block_mode(struct ipu_soc *ipu, uint32_t ch) 
{ 
	int32_t sub_ch = 0; 

	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 0, 117, 2, 1); 

	sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch); 
	if (sub_ch <= 0) 
		return; 
	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 117, 2, 1); 
};

设置block_mode参数,这个block_mode参数应该是位于word[0]里面的117119位。这个函数被ipu_common.c中的ipu_init_channel_buffer函数调用


21._ipu_ch_param_set_alpha_use_separate_channel函数

static inline void _ipu_ch_param_set_alpha_use_separate_channel(struct ipu_soc *ipu, 
								uint32_t ch, 
								bool option) 
{ 
	int32_t sub_ch = 0; 

	if (option) { 
		ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 89, 1, 1); 
	} else { 
		ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 89, 1, 0); 
	} 

/*根据option这个bool类型的值来设置ch对应的基址中word[1]89位。*/

	sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch); 
	if (sub_ch <= 0) 
		return; 

	if (option) { 
		ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 89, 1, 1); 
	} else { 
		ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 89, 1, 0); 
	} 
}; 

如果有第三个buffer的话,就设置sub_ch对应的基址中word[1]89位。这个函数被ipu_common.c中的ipu_init_channel_buffer函数调用


22._ipu_ch_param_set_alpha_condition_read函数

static inline void _ipu_ch_param_set_alpha_condition_read(struct ipu_soc *ipu, uint32_t ch) 
{ 
	int32_t sub_ch = 0; 

	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 149, 1, 1); 

	sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch); 
	if (sub_ch <= 0) 
		return; 
	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 149, 1, 1); 
}; 

这个函数的名字里面有read,但是里面调用的是ipu_ch_param_mod_field_io函数,他用来将ch对应的基址里面的word[1]149位修改为1。如果有sub_ch的话,就同时修改sub_ch所对应的基址。这个函数被ipu_common.c中的ipu_init_channel_buffer函数调用


23._ipu_ch_param_set_alpha_buffer_memory函数

static inline void _ipu_ch_param_set_alpha_buffer_memory(struct ipu_soc *ipu, uint32_t ch) 
{ 
	int alp_mem_idx; 
	int32_t sub_ch = 0; 

	switch (ch) { 
	case 14: /* PRP graphic */ 
		alp_mem_idx = 0; 
		break; 
	case 15: /* PP graphic */ 
		alp_mem_idx = 1; 
		break; 
	case 23: /* DP BG SYNC graphic */ 
		alp_mem_idx = 4; 
		break; 
	case 27: /* DP FG SYNC graphic */ 
		alp_mem_idx = 2; 
		break; 
	default: 
		dev_err(ipu->dev, "unsupported correlative channel of local " 
			"alpha channel\n"); 
		return; 
	} 

/*根据ch的值设置alp_mem_idx的值。*/

	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 90, 3, alp_mem_idx); 

	sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch); 
	if (sub_ch <= 0) 
		return; 
	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 90, 3, alp_mem_idx); 
}; 

这个函数首先根据ch的值来确定alp_mem_idx。然后调用ipu_ch_param_mod_field_io将ch对应基址里面的word[1]里面的90~93位修改成alp_mem_idx的值。这个函数被ipu_common.c中的ipu_init_channel_buffer函数调用。


24._ipu_ch_param_set_interlaced_scan函数

static inline void _ipu_ch_param_set_interlaced_scan(struct ipu_soc *ipu, uint32_t ch) 
{ 
	u32 stride; 
	int32_t sub_ch = 0; 

	sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch); 

	ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, ch), 0, 113, 1, 1); 
	if (sub_ch > 0) 
		ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 113, 1, 1); 
	stride = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 102, 14) + 1; 
	/* ILO is 20-bit and 8-byte aligned */ 
	if (stride/8 > 0xfffff) 
		dev_warn(ipu->dev, 
			 "IDMAC%d's ILO exceeds IPU limitation\n", ch); 
	if (stride%8) 
		dev_warn(ipu->dev, 
			 "IDMAC%d's ILO is not 8-byte aligned\n", ch); 
	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 58, 20, stride / 8); 
	if (sub_ch > 0) 
		ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 58, 20, 
				       stride / 8); 
	stride *= 2; 
	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 102, 14, stride - 1); 
	if (sub_ch > 0) 
		ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 102, 14, 
				       stride - 1); 
}; 

首先通过ipu_ch_param_set_field_io函数将ch对应基址里面word[0]的113位设为1。如果存在sub_ch的话,将sub_ch对应的基址里面word[0]的113位设为1。之后通过ipu_ch_param_read_field_io函数读取ch对应基址里面word[1]的102~116位的值来求出stride的值。之后通过ipu_ch_param_mod_field_io函数将ch对应基址里面的word[1]的58~78位设置为(stride/ 8),将ch对应基址里面的word[1]的102~116位设置为(stride-1),如果存在sub_ch的话需要做同样的操作。这个函数被ipu_common.c中的ipu_init_channel_buffer函数调用。


25._ipu_ch_param_set_axi_id函数

static inline void _ipu_ch_param_set_axi_id(struct ipu_soc *ipu, uint32_t ch, uint32_t id) 
{ 
	int32_t sub_ch = 0; 

	id %= 4; 

	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 93, 2, id); 

	sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch); 
	if (sub_ch <= 0) 
		return; 
	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 93, 2, id); 
}; 

根据传入的id参数来设置ch对应的基址里面word[1]9394位,这一位是关于axi_id的。


26._ipu_ch_param_get_axi_id函数

static inline int _ipu_ch_param_get_axi_id(struct ipu_soc *ipu, uint32_t ch) 
{ 
	return ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 93, 2); 
} 

这个函数就是读取ch对应的基址里面word[1]9394位。这个函数被ipu_common.c中的ipu_ch_param_get_axi_id函数调用。


27.__ipu_ch_offset_calc函数

static inline int __ipu_ch_offset_calc(uint32_t pixel_fmt, 
				       uint32_t width, 
				       uint32_t height, 
				       uint32_t stride, 
				       uint32_t u, 
				       uint32_t v, 
				       uint32_t uv_stride, 
				       uint32_t vertical_offset, 
				       uint32_t horizontal_offset, 
				       uint32_t *u_offset, 
				       uint32_t *v_offset) 
{ 
	uint32_t u_fix = 0; 
	uint32_t v_fix = 0; 

	switch (pixel_fmt) { 
	case IPU_PIX_FMT_GENERIC: 
	case IPU_PIX_FMT_GENERIC_16: 
	case IPU_PIX_FMT_GENERIC_32: 
	case IPU_PIX_FMT_RGB565: 
	case IPU_PIX_FMT_BGR24: 
	case IPU_PIX_FMT_RGB24: 
	case IPU_PIX_FMT_YUV444: 
	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: 
	case IPU_PIX_FMT_UYVY: 
	case IPU_PIX_FMT_YUYV: 
	case IPU_PIX_FMT_GPU32_SB_ST: 
	case IPU_PIX_FMT_GPU32_SB_SRT: 
	case IPU_PIX_FMT_GPU32_ST: 
	case IPU_PIX_FMT_GPU32_SRT: 
	case IPU_PIX_FMT_GPU16_SB_ST: 
	case IPU_PIX_FMT_GPU16_SB_SRT: 
	case IPU_PIX_FMT_GPU16_ST: 
	case IPU_PIX_FMT_GPU16_SRT: 
		*u_offset = 0; 
		*v_offset = 0; 
		break; 
	case IPU_PIX_FMT_YUV420P2: 
	case IPU_PIX_FMT_YUV420P: 
		if (uv_stride < stride / 2) 
			uv_stride = stride / 2; 

		*u_offset = stride * (height - vertical_offset - 1) + 
					(stride - horizontal_offset) + 
					(uv_stride * vertical_offset / 2) + 
					horizontal_offset / 2; 
		*v_offset = *u_offset + (uv_stride * height / 2); 
		u_fix = u ? (u + (uv_stride * vertical_offset / 2) + 
					(horizontal_offset / 2) - 
					(stride * vertical_offset) - (horizontal_offset)) : 
					*u_offset; 
		v_fix = v ? (v + (uv_stride * vertical_offset / 2) + 
					(horizontal_offset / 2) - 
					(stride * vertical_offset) - (horizontal_offset)) : 
					*v_offset; 
		break; 
	case IPU_PIX_FMT_YVU420P: 
		if (uv_stride < stride / 2) 
			uv_stride = stride / 2; 

		*v_offset = stride * (height - vertical_offset - 1) + 
					(stride - horizontal_offset) + 
					(uv_stride * vertical_offset / 2) + 
					horizontal_offset / 2; 
		*u_offset = *v_offset + (uv_stride * height / 2); 
		u_fix = u ? (u + (uv_stride * vertical_offset / 2) + 
					(horizontal_offset / 2) - 
					(stride * vertical_offset) - (horizontal_offset)) : 
					*u_offset; 
		v_fix = v ? (v + (uv_stride * vertical_offset / 2) + 
					(horizontal_offset / 2) - 
					(stride * vertical_offset) - (horizontal_offset)) : 
					*v_offset; 
		break; 
	case IPU_PIX_FMT_YVU422P: 
		if (uv_stride < stride / 2) 
			uv_stride = stride / 2; 

		*v_offset = stride * (height - vertical_offset - 1) + 
					(stride - horizontal_offset) + 
					(uv_stride * vertical_offset) + 
					horizontal_offset / 2; 
		*u_offset = *v_offset + uv_stride * height; 
		u_fix = u ? (u + (uv_stride * vertical_offset) + 
					horizontal_offset / 2 - 
					(stride * vertical_offset) - (horizontal_offset)) : 
					*u_offset; 
		v_fix = v ? (v + (uv_stride * vertical_offset) + 
					horizontal_offset / 2 - 
					(stride * vertical_offset) - (horizontal_offset)) : 
					*v_offset; 
		break; 
	case IPU_PIX_FMT_YUV422P: 
		if (uv_stride < stride / 2) 
			uv_stride = stride / 2; 

		*u_offset = stride * (height - vertical_offset - 1) + 
					(stride - horizontal_offset) + 
					(uv_stride * vertical_offset) + 
					horizontal_offset / 2; 
		*v_offset = *u_offset + uv_stride * height; 
		u_fix = u ? (u + (uv_stride * vertical_offset) + 
					horizontal_offset / 2 - 
					(stride * vertical_offset) - (horizontal_offset)) : 
					*u_offset; 
		v_fix = v ? (v + (uv_stride * vertical_offset) + 
					horizontal_offset / 2 - 
					(stride * vertical_offset) - (horizontal_offset)) : 
					*v_offset; 
		break; 
	case IPU_PIX_FMT_YUV444P: 
		uv_stride = stride; 
		*u_offset = stride * (height - vertical_offset - 1) + 
					(stride - horizontal_offset) + 
					(uv_stride * vertical_offset) + 
					horizontal_offset; 
		*v_offset = *u_offset + uv_stride * height; 
		u_fix = u ? (u + (uv_stride * vertical_offset) + 
					horizontal_offset - 
					(stride * vertical_offset) - 
					(horizontal_offset)) : 
					*u_offset; 
		v_fix = v ? (v + (uv_stride * vertical_offset) + 
					horizontal_offset - 
					(stride * vertical_offset) - 
					(horizontal_offset)) : 
					*v_offset; 
		break; 
	case IPU_PIX_FMT_NV12: 
	case IPU_PIX_FMT_NV16: 
	case PRE_PIX_FMT_NV21: 
	case PRE_PIX_FMT_NV61: 
		uv_stride = stride; 
		*u_offset = stride * (height - vertical_offset - 1) + 
					(stride - horizontal_offset) + 
					(uv_stride * vertical_offset / 2) + 
					horizontal_offset; 
		*v_offset = 0; 
		u_fix = u ? (u + (uv_stride * vertical_offset / 2) + 
					horizontal_offset - 
					(stride * vertical_offset) - (horizontal_offset)) : 
					*u_offset; 
		break; 
	default: 
		return -EINVAL; 
	} 

	if (u_fix > *u_offset) 
		*u_offset = u_fix; 

	if (v_fix > *v_offset) 
		*v_offset = v_fix; 

	return 0; 
} 

这个函数一共有11个参数,它的最终目的是根据前9个参数设置最后2个参数的值。这个函数被本文件中_ipu_ch_offset_update函数和ipu_common.c文件中ipu_get_channel_offset函数调用。

这个函数就是根据数据格式来算出u_offsetv_offset的值,以后根据各种格式来仔细算算。


28._ipu_ch_offset_update函数

/* IDMAC U/V offset changing support */ 
/* U and V input is not affected, */ 
/* the update is done by new calculation according to */ 
/* vertical_offset and horizontal_offset */ 
static inline void _ipu_ch_offset_update(struct ipu_soc *ipu, 
					 int ch, 
					 uint32_t pixel_fmt, 
					 uint32_t width, 
					 uint32_t height, 
					 uint32_t stride, 
					 uint32_t u, 
					 uint32_t v, 
					 uint32_t uv_stride, 
					 uint32_t vertical_offset, 
					 uint32_t horizontal_offset) 
{ 
	uint32_t u_offset = 0; 
	uint32_t v_offset = 0; 
	uint32_t old_offset = 0; 
	int32_t sub_ch = 0; 
	int ret; 

	ret = __ipu_ch_offset_calc(pixel_fmt, width, height, stride, 
				   u, v, uv_stride, 
				   vertical_offset, horizontal_offset, 
				   &u_offset, &v_offset); 
	if (ret) { 
		dev_err(ipu->dev, "mxc ipu: unimplemented pixel format\n"); 
		return; 
	} 

	/* UBO and VBO are 22-bit and 8-byte aligned */ 
	if (u_offset/8 > 0x3fffff) 
		dev_warn(ipu->dev, 
			"IDMAC%d's U offset exceeds IPU limitation\n", ch); 
	if (v_offset/8 > 0x3fffff) 
		dev_warn(ipu->dev, 
			"IDMAC%d's V offset exceeds IPU limitation\n", ch); 
	if (u_offset%8) 
		dev_warn(ipu->dev, 
			"IDMAC%d's U offset is not 8-byte aligned\n", ch); 
	if (v_offset%8) 
		dev_warn(ipu->dev, 
			"IDMAC%d's V offset is not 8-byte aligned\n", ch); 

	old_offset = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 46, 22); 
	if (old_offset != u_offset / 8) 
		ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 0, 46, 22, u_offset / 8); 
	old_offset = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 68, 22); 
	if (old_offset != v_offset / 8) 
		ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 0, 68, 22, v_offset / 8); 

	sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch); 
	if (sub_ch <= 0) 
		return; 
	old_offset = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 46, 22); 
	if (old_offset != u_offset / 8) 
		ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 46, 22, u_offset / 8); 
	old_offset = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 68, 22); 
	if (old_offset != v_offset / 8) 
		ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 68, 22, v_offset / 8); 
}; 

从这个函数的名字可以看出来,ipuchannel offset updateipuchannel偏移更新,这个函数首先通过上一个__ipu_ch_offset_calc函数来计算出&u_offset&v_offset,然后根据传入的ipuch参数来读取ch对应基址word[0]4668位中的老&u_offset偏移值和ch对应基址word[0]6890位中的老&v_offset偏移值,然后修改它们。重点还是u_offsetv_offset这两个值。


29._ipu_ch_params_set_alpha_width函数

static inline void _ipu_ch_params_set_alpha_width(struct ipu_soc *ipu, uint32_t ch, int alpha_width) 
{ 
	int32_t sub_ch = 0; 

	ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, ch), 1, 125, 3, alpha_width - 1); 

	sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch); 
	if (sub_ch <= 0) 
		return; 
	ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 125, 3, alpha_width - 1); 
}; 

这个函数同样就是设置ch对应基址里面word[1]125128位,将它设置为(alpha_width– 1),这一位应该就是关于alpha_width的。


30._ipu_ch_param_set_bandmode函数

static inline void _ipu_ch_param_set_bandmode(struct ipu_soc *ipu, 
			uint32_t ch, uint32_t band_height) 
{ 
	int32_t sub_ch = 0; 

	ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, ch), 
					0, 114, 3, band_height - 1); 
	sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch); 
	if (sub_ch <= 0) 
		return; 
	ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, sub_ch), 
					0, 114, 3, band_height - 1); 

	dev_dbg(ipu->dev, "BNDM 0x%x, ", 
		 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 114, 3)); 
} 

这个函数同样就是设置ch对应基址里面word[0]114117位,将它设置为(band_height– 1),这一位应该就是关于band_height的。


31._ipu_ch_param_bad_alpha_pos函数

/* 
 * The IPUv3 IDMAC has a bug to read 32bpp pixels from a graphics plane 
 * whose alpha component is at the most significant 8 bits. The bug only 
 * impacts on cases in which the relevant separate alpha channel is enabled. 
 * 
 * Return true on bad alpha component position, otherwise, return false. 
 */ 
static inline bool _ipu_ch_param_bad_alpha_pos(uint32_t pixel_fmt) 
{ 
	switch (pixel_fmt) { 
	case IPU_PIX_FMT_BGRA32: 
	case IPU_PIX_FMT_BGR32: 
	case IPU_PIX_FMT_RGBA32: 
	case IPU_PIX_FMT_RGB32: 
		return true; 
	} 

	return false; 
} 

这个注释里面写的很清楚了,当IPUv3IDMAC 在从一个alpha组件位于最重要8位的图像位面读取32bpp像素的时候有一个bug,所以当pixel_fmt32位的时候,就返回true,否则返回false


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值