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使用5个uint32_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结构体,它的取值为0和1。

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

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]的,所以这个值的范围为0~160。size表示数据所占的位数。v表示传入的数据字面值。

这个宏的意思是首先通过(bit)/32来计算出这个数据的起始bit在data数组成员中的哪一个(因为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); \ } \
}

这个宏根据base,w,bit的值计算出寄存器的位置,然后将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))

这个宏根据ipu和ch两个参数来找到对应寄存器的基址,具体来说就是根据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宏根据传入的ipu和ch参数来找到某个寄存器的基址,然后修改这个寄存器中的某些位。

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

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) << off将v的值写到这几位中。修改某些位值的时候,一定要先清零了再写。

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_width,red_offset,green_width,green_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函数根据ipu和ch参数取得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) */

如果channel是8/9/10的话,从注释上来看是vdoa+vdichannel,用的是bandmode,会将params那几位设置成height/2和stride*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。原因是EBA是8字节对齐的,后面需要分析这里。*/

 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/pixel,word[1]里面从85位开始的几位决定pixformat,word[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_offset和v_offset的值。他俩分别位于params->word[0]里面的46~68和68~90位。*/

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

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

 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的初始值,在这里可以继续通过ipu和ch的值来修改他们的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;
};

通过ipu和ch参数找到对应的寄存器然后读取它的值。这个函数被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);
};

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

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

首先根据ipu和ch来获取基址,然后根据传入的bufNum参数来决定修改基址中的哪些位。这个函数被ipu_common.c中的ipu_update_channel_buffer函数调用。根据手册上面可以看出来,关于buffer的设置是在word[1]中从0~28,59~57,而且根据后面的分析,对于双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]的119~121位。这个函数被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]里面的117~119位。这个函数被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]的93~94位,这一位是关于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]的93~94位。这个函数被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_offset和v_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 update:ipuchannel偏移更新,这个函数首先通过上一个__ipu_ch_offset_calc函数来计算出&u_offset和&v_offset,然后根据传入的ipu和ch参数来读取ch对应基址word[0]的46~68位中的老&u_offset偏移值和ch对应基址word[0]的68~90位中的老&v_offset偏移值,然后修改它们。重点还是u_offset和v_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]的125~128位,将它设置为(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]的114~117位,将它设置为(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_fmt为32位的时候,就返回true,否则返回false。

4.4 ipu_param_mem.h头文件分析相关推荐

  1. linux内核中链表代码分析---list.h头文件分析(二)【转】

    转自:http://blog.chinaunix.net/uid-30254565-id-5637598.html linux内核中链表代码分析---list.h头文件分析(二) 16年2月28日16 ...

  2. linux内核中链表代码分析---list.h头文件分析(一)

    linux内核中链表代码分析---list.h头文件分析(一) 16年2月27日17:13:14 在学习数据结构时,有一个重要的知识点就是链表.对于链表的一些基本操作,它的最好学习资料就是内核中的li ...

  3. a.out.h 头文件分析 \linux-1.0\linux\include\linux\a.out.h

    #ifndef __A_OUT_GNU_H__ #define __A_OUT_GNU_H__#define __GNU_EXEC_MACROS__#ifndef __STRUCT_EXEC_OVER ...

  4. HAL层,.sensors.h 头文件分析

    Google为Sensor提供了统一的HAL接口,不同的硬件厂商需要根据该接口来实现并完成具体的硬件抽象层, Android中Sensor的HAL接口定义在:hardware/libhardware/ ...

  5. c语言中的stdbool.h头文件,【C语言】中的stdbool.h头文件

    C语言中的stdbool.h头文件 一.相关基础知识 二.具体内容 Win7下安装的VS2015中的stdbool.h的位置为: F:\Program Files (x86)\Microsoft Vi ...

  6. C语言不要重复包含.h头文件和.c文件

    1.不要重复包含头文件 --以上出自<C语言程序设计:现代方法(第2版)> f3.h //#ifndef AE_OK #define AE_OK 0 typedef int ngx_int ...

  7. Android JNI入门第四篇——jni头文件分析

    转载请标明出处: http://blog.csdn.net/michael1112/article/details/56666407 江东橘子的博客 一. 首先写了java文件: public cla ...

  8. c语言 自动包含头文件,C语言不要重复包含.h头文件和.c文件

    http://blog.csdn.net/unix21/article/details/8450235 2012 1.不要重复包含头文件 --以上出自<C语言程序设计:现代方法(第2版)> ...

  9. 每日一题(12)—— .h头文件中ifndef/define/endif的作用

     .h头文件中ifndef/define/endif的作用? 分析: 防止头文件被重复包含. #ifndef _TEST_H_ #define _TEST_H_/* test.h */#endif / ...

最新文章

  1. 吴 恩 达 教 你 做 机 器 学 习 职 业 规 划
  2. jmeter测试java接口测试_简单易学的测试攻略:JMeter测试Java请求示例
  3. .NET 并行(多核)编程系列之七 共享数据问题和解决概述
  4. php编写一个学生类_Python零基础入门之编写测试实例
  5. Spring Boot 2.3.x 分层构建 Docker 镜像实战
  6. 程序员面试金典 - 面试题 04.01. 节点间通路(图的遍历)
  7. 三星Galaxy A80首款保护壳曝光:配件厂商这样解难题
  8. 生成介于0.95-1的随机数MATLAB,matlab生成随机数函数
  9. 基于JAVA+SpringBoot+Mybatis+MYSQL的飞机订票系统
  10. 深航 App 劫持微信;董明珠:给员工分房加薪是应得的回报;ofo 复活 | 极客头条...
  11. vite 打包页面空白
  12. 【爬虫】利用Python爬虫爬取小麦苗itpub博客的所有文章的连接地址(1)
  13. Arduino IDE下载安装ESP8266/32慢的解决办法
  14. 计算机组成原理——总线
  15. linux fcntl函数,Linux C 学习之 - fcntl 函数
  16. stm32单片机驱动L298N模块
  17. 安卓手机怎么投屏台式计算机,怎么将手机投屏到台式电脑上
  18. 南通全国计算机等级考试,南通大学2017年3月全国计算机等级考试报名通知
  19. 没有这个传奇工程师,就没有今天的Windows
  20. 360 html快捷,360极速浏览器如何设置键盘快捷键?

热门文章

  1. 关于股息、增发、回购的个人看法
  2. DHU 第一题 重排链表
  3. 【沃顿商学院学习笔记】管理学——09行业对腐败的控制 Corruption Control By Industries
  4. 【科技与狠货】云盘变硬盘
  5. CSS3绘制的军曹giroro卡通图像
  6. 第二章 C语言基础程序设计
  7. QQ怎么让好友在列表里隐藏
  8. 应试技巧丨英语写作忘词了?我有办法
  9. 自动化配置管理工具 SaltStack-03
  10. stm32f103VET6-FreerRTOS移植LWIP (enc28j60)