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使用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(¶ms,5, 0, 6, 5, 5, 11, 8, 16);
通过这样调用,就分别设置了params中的RGB的信息,从上面可以看出来是RGB565格式的。
_ipu_ch_params_set_packing(¶ms,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(¶ms<style type="text/css">p { margin-bottom: 0.25cm; line-height: 120%; }a:link { }¶ms</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>¶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>, 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>¶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><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>¶<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>¶<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>¶<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>¶<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;">¶ms</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;">¶ms</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;">¶ms</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;">¶ms</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 { }¶ms</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;">¶ms</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;">¶ms</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;">¶ms</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头文件分析相关推荐
- linux内核中链表代码分析---list.h头文件分析(二)【转】
转自:http://blog.chinaunix.net/uid-30254565-id-5637598.html linux内核中链表代码分析---list.h头文件分析(二) 16年2月28日16 ...
- linux内核中链表代码分析---list.h头文件分析(一)
linux内核中链表代码分析---list.h头文件分析(一) 16年2月27日17:13:14 在学习数据结构时,有一个重要的知识点就是链表.对于链表的一些基本操作,它的最好学习资料就是内核中的li ...
- 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 ...
- HAL层,.sensors.h 头文件分析
Google为Sensor提供了统一的HAL接口,不同的硬件厂商需要根据该接口来实现并完成具体的硬件抽象层, Android中Sensor的HAL接口定义在:hardware/libhardware/ ...
- c语言中的stdbool.h头文件,【C语言】中的stdbool.h头文件
C语言中的stdbool.h头文件 一.相关基础知识 二.具体内容 Win7下安装的VS2015中的stdbool.h的位置为: F:\Program Files (x86)\Microsoft Vi ...
- C语言不要重复包含.h头文件和.c文件
1.不要重复包含头文件 --以上出自<C语言程序设计:现代方法(第2版)> f3.h //#ifndef AE_OK #define AE_OK 0 typedef int ngx_int ...
- Android JNI入门第四篇——jni头文件分析
转载请标明出处: http://blog.csdn.net/michael1112/article/details/56666407 江东橘子的博客 一. 首先写了java文件: public cla ...
- c语言 自动包含头文件,C语言不要重复包含.h头文件和.c文件
http://blog.csdn.net/unix21/article/details/8450235 2012 1.不要重复包含头文件 --以上出自<C语言程序设计:现代方法(第2版)> ...
- 每日一题(12)—— .h头文件中ifndef/define/endif的作用
.h头文件中ifndef/define/endif的作用? 分析: 防止头文件被重复包含. #ifndef _TEST_H_ #define _TEST_H_/* test.h */#endif / ...
最新文章
- 吴 恩 达 教 你 做 机 器 学 习 职 业 规 划
- jmeter测试java接口测试_简单易学的测试攻略:JMeter测试Java请求示例
- .NET 并行(多核)编程系列之七 共享数据问题和解决概述
- php编写一个学生类_Python零基础入门之编写测试实例
- Spring Boot 2.3.x 分层构建 Docker 镜像实战
- 程序员面试金典 - 面试题 04.01. 节点间通路(图的遍历)
- 三星Galaxy A80首款保护壳曝光:配件厂商这样解难题
- 生成介于0.95-1的随机数MATLAB,matlab生成随机数函数
- 基于JAVA+SpringBoot+Mybatis+MYSQL的飞机订票系统
- 深航 App 劫持微信;董明珠:给员工分房加薪是应得的回报;ofo 复活 | 极客头条...
- vite 打包页面空白
- 【爬虫】利用Python爬虫爬取小麦苗itpub博客的所有文章的连接地址(1)
- Arduino IDE下载安装ESP8266/32慢的解决办法
- 计算机组成原理——总线
- linux fcntl函数,Linux C 学习之 - fcntl 函数
- stm32单片机驱动L298N模块
- 安卓手机怎么投屏台式计算机,怎么将手机投屏到台式电脑上
- 南通全国计算机等级考试,南通大学2017年3月全国计算机等级考试报名通知
- 没有这个传奇工程师,就没有今天的Windows
- 360 html快捷,360极速浏览器如何设置键盘快捷键?