4.4 ipu_param_mem.h头文件分析

时间:2021-10-10 09:21:44

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

4.4 ipu_param_mem.h头文件分析

注意在数据的存储过程中涉及到大端小端的问题,对大端小端的解释: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;


如下图所示:

4.4 ipu_param_mem.h头文件分析

然后继续往下执行:

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)。

它们详细表示如下:

4.4 ipu_param_mem.h头文件分析

同样对于

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);

它们详细表示如下:

4.4 ipu_param_mem.h头文件分析

再分析一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

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

4.4 ipu_param_mem.h头文件分析

从这里可以看出来,它的存储方式是将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