1.ipu_soc结构体:
struct ipu_soc {
unsigned int id; //ipu的ID号
unsigned int devtype; //ipu的一些信息,包含cm,ic等模块的地址偏移值
bool online; //表示这个ipu是否正在使用中
/*clk*/
struct clk *ipu_clk;
struct clk *di_clk[2];
struct clk *di_clk_sel[2];
struct clk *pixel_clk[2];
bool pixel_clk_en[2];
struct clk *pixel_clk_sel[2];
struct clk *csi_clk[2];
struct clk *prg_clk;
/*irq*/
int irq_sync;
int irq_err;
struct ipu_irq_node irq_list[IPU_IRQ_COUNT]; //在request_irq函数中会根据传入的irq号在这个数组中选择对应的下标,来存取有关这个irq的
//信息如irq服务函数,名字,flags等参数。
/*reg*/ /* ipu内部模块经过ioremap后的地址 */
void __iomem *cm_reg;
void __iomem *idmac_reg;
void __iomem *dp_reg;
void __iomem *ic_reg;
void __iomem *dc_reg;
void __iomem *dc_tmpl_reg;
void __iomem *dmfc_reg;
void __iomem *di_reg[2];
void __iomem *smfc_reg;
void __iomem *csi_reg[2];
void __iomem *cpmem_base;
void __iomem *tpmem_base;
void __iomem *vdi_reg;
struct device *dev;
ipu_channel_t csi_channel[2]; //每个ipu有两个csi设备,将此时csi设备对应的channel根据csi号保存在这个csi_channel[]数组中
ipu_channel_t using_ic_dirct_ch; //表示那个channel直接使用IC设备
unsigned char dc_di_assignment[10];
bool sec_chan_en[24]; //对应的channel是否使能了second channel
bool thrd_chan_en[24]; //对应的channel是否使能了third channel
bool chan_is_interlaced[52]; //对应的channel中的数据是否是隔行的,每个channel对应其中的一位,每一位是一个bool类型的值
uint32_t channel_init_mask; //这是一个32位的数,其中每一位代表一个channel号,如果初始化一个channel的话,就将这个channel对应的位置1
uint32_t channel_enable_mask; //每一位对应一个channel号,如果使能了一个channel 的话,就将这个channel对应的位置1,与上面那个channel_init_mask类似。
/*use count*/ /* 下面几个是IPU内部模块的引用计数 */
int dc_use_count; //dc引用计数
int dp_use_count; //dp引用计数
int dmfc_use_count; //dmfc引用计数
int smfc_use_count; //smfc引用计数
int ic_use_count; //ic引用计数
int rot_use_count; //rot引用计数
int vdi_use_count; //vdi引用计数
int di_use_count[2]; //di引用计数,每个ipu只有两个di
int csi_use_count[2]; //csi引用计数,每个ipu只有两个csi
struct mutex mutex_lock;
spinlock_t int_reg_spin_lock;
spinlock_t rdy_reg_spin_lock;
int dmfc_size_28;
int dmfc_size_29;
int dmfc_size_24;
int dmfc_size_27;
int dmfc_size_23;
enum csc_type_t fg_csc_type;
enum csc_type_t bg_csc_type;
bool color_key_4rgb;
bool dc_swap;
struct completion dc_comp;
struct completion csi_comp;
struct rot_mem {
void *vaddr;
dma_addr_t paddr;
int size;
} rot_dma[2];
int vdoa_en; //是否使能VDOA
struct task_struct *thread[2]; //两个内核线程
/*
* Bypass reset to avoid display channel being
* stopped by probe since it may starts to work
* in bootloader.
*/
bool bypass_reset; /* 这个值是从dts文件中获得的bypass_reset,因为在开发板启动过程中,需要使能屏幕来显示,所以显示通道可能已经在bootloader中开启了,
* 在这里设置这个值,使得显示通道在probe函数中不会关闭,也就是这个参数的含义(旁路)。*/
/* AXI protocol id */
unsigned int ch0123_axi;
unsigned int ch23_axi;
unsigned int ch27_axi;
unsigned int ch28_axi;
unsigned int normal_axi;
/* 不同的channel可能会对应不同的 AXI protocol,在ipu_probe函数中对这些值进行了赋值,在ipu_platform_type结构体中指定的。 */
bool smfc_idmac_12bit_3planar_bs_fixup; /* workaround little stripes */
};
2.ipu_channel_t枚举:
typedef enum {
CHAN_NONE = -1,
MEM_ROT_ENC_MEM = _MAKE_CHAN(1, 45, NO_DMA, NO_DMA, 48),
MEM_ROT_VF_MEM = _MAKE_CHAN(2, 46, NO_DMA, NO_DMA, 49),
MEM_ROT_PP_MEM = _MAKE_CHAN(3, 47, NO_DMA, NO_DMA, 50),
MEM_PRP_ENC_MEM = _MAKE_CHAN(4, 12, 14, 17, 20),
MEM_PRP_VF_MEM = _MAKE_CHAN(5, 12, 14, 17, 21),
MEM_PP_MEM = _MAKE_CHAN(6, 11, 15, 18, 22),
MEM_DC_SYNC = _MAKE_CHAN(7, 28, NO_DMA, NO_DMA, NO_DMA),
MEM_DC_ASYNC = _MAKE_CHAN(8, 41, NO_DMA, NO_DMA, NO_DMA),
MEM_BG_SYNC = _MAKE_CHAN(9, 23, NO_DMA, 51, NO_DMA),
MEM_FG_SYNC = _MAKE_CHAN(10, 27, NO_DMA, 31, NO_DMA),
MEM_BG_ASYNC0 = _MAKE_CHAN(11, 24, NO_DMA, 52, NO_DMA),
MEM_FG_ASYNC0 = _MAKE_CHAN(12, 29, NO_DMA, 33, NO_DMA),
MEM_BG_ASYNC1 = _MAKE_ALT_CHAN(MEM_BG_ASYNC0),
MEM_FG_ASYNC1 = _MAKE_ALT_CHAN(MEM_FG_ASYNC0),
DIRECT_ASYNC0 = _MAKE_CHAN(13, NO_DMA, NO_DMA, NO_DMA, NO_DMA),
DIRECT_ASYNC1 = _MAKE_CHAN(14, NO_DMA, NO_DMA, NO_DMA, NO_DMA),
CSI_MEM0 = _MAKE_CHAN(15, NO_DMA, NO_DMA, NO_DMA, 0),
CSI_MEM1 = _MAKE_CHAN(16, NO_DMA, NO_DMA, NO_DMA, 1),
CSI_MEM2 = _MAKE_CHAN(17, NO_DMA, NO_DMA, NO_DMA, 2),
CSI_MEM3 = _MAKE_CHAN(18, NO_DMA, NO_DMA, NO_DMA, 3),
CSI_MEM = CSI_MEM0,
CSI_PRP_ENC_MEM = _MAKE_CHAN(19, NO_DMA, NO_DMA, NO_DMA, 20),
CSI_PRP_VF_MEM = _MAKE_CHAN(20, NO_DMA, NO_DMA, NO_DMA, 21),
/* for vdi mem->vdi->ic->mem , add graphics plane and alpha*/
MEM_VDI_PRP_VF_MEM_P = _MAKE_CHAN(21, 8, 14, 17, 21),
MEM_VDI_PRP_VF_MEM = _MAKE_CHAN(22, 9, 14, 17, 21),
MEM_VDI_PRP_VF_MEM_N = _MAKE_CHAN(23, 10, 14, 17, 21),
/* for vdi mem->vdi->mem */
MEM_VDI_MEM_P = _MAKE_CHAN(24, 8, NO_DMA, NO_DMA, 5),
MEM_VDI_MEM = _MAKE_CHAN(25, 9, NO_DMA, NO_DMA, 5),
MEM_VDI_MEM_N = _MAKE_CHAN(26, 10, NO_DMA, NO_DMA, 5),
/* fake channel for vdoa to link with IPU */
MEM_VDOA_MEM = _MAKE_CHAN(27, NO_DMA, NO_DMA, NO_DMA, NO_DMA),
MEM_PP_ADC = CHAN_NONE,
ADC_SYS2 = CHAN_NONE,
} ipu_channel_t;
再来看看这个_MAKE_CHAN宏:
#define _MAKE_CHAN(num, v_in, g_in, a_in, out)
((num << 24) | (v_in << 18) | (g_in << 12) | (a_in << 6) | out)
#define NO_DMA 0x3F
从这里就可以看出来,ipu_channel_t只是根据5个值左移形成的一个数字。
那么想要从channel中获取它的ID号怎么办?只需要将它右移24位即可,就能得到,就是下面一个宏:
#define IPU_CHAN_ID(ch) (ch >> 24)
再来看看channel_2_dma函数:
static inline uint32_t channel_2_dma(ipu_channel_t ch, ipu_buffer_t type)
{
return ((uint32_t) ch >> (6 * type)) & 0x3F;
};
这个函数能够根据不同的type类型从channel里面提取出所使用的dmachannel。
typedef enum {
IPU_OUTPUT_BUFFER = 0, /*!< Buffer for output from IPU */
IPU_ALPHA_IN_BUFFER = 1, /*!< Buffer for input to IPU */
IPU_GRAPH_IN_BUFFER = 2, /*!< Buffer for input to IPU */
IPU_VIDEO_IN_BUFFER = 3, /*!< Buffer for input to IPU */
IPU_INPUT_BUFFER = IPU_VIDEO_IN_BUFFER,
IPU_SEC_INPUT_BUFFER = IPU_GRAPH_IN_BUFFER,
} ipu_buffer_t;
同时根据_MAKE_CHAN宏中几个变量的名字,就能够理解ipu_channel_t中各个位的含义:
0~5位:输出dmachannel号
6~11位:alpha通道号
12~17位:graph通道号
18~23位:video输入dmachannel号
24~ :channel的序列号
3. ipu_channel_params_t联合:
typedef union {
struct {
uint32_t csi; //csi设备号,0或1
uint32_t mipi_id; //mipi ID号
uint32_t mipi_vc; //mipi虚拟通道号
bool mipi_en; //是否使能mipi接口
bool interlaced; //数据是否是隔行的
} csi_mem;
struct {
uint32_t in_width; //输入数据的宽度
uint32_t in_height; //输入数据的高度
uint32_t in_pixel_fmt; //输入数据的像素格式
uint32_t out_width; //输出数据的宽度
uint32_t out_height; //输出数据的高度
uint32_t out_pixel_fmt; //输出数据的像素格式
uint32_t outh_resize_ratio; //输出水平方向上重定义大小系数
uint32_t outv_resize_ratio; //输出垂直方向上重定义大小系数
uint32_t csi; //csi 设备号
uint32_t mipi_id; //mipi ID号
uint32_t mipi_vc; //mipi 虚拟通道号
bool mipi_en; //是否是能mipi接口
} csi_prp_enc_mem;
struct {
uint32_t in_width;
uint32_t in_height;
uint32_t in_pixel_fmt;
uint32_t out_width;
uint32_t out_height;
uint32_t out_pixel_fmt;
uint32_t outh_resize_ratio;
uint32_t outv_resize_ratio;
} mem_prp_enc_mem;
struct {
uint32_t in_width;
uint32_t in_height;
uint32_t in_pixel_fmt;
uint32_t out_width;
uint32_t out_height;
uint32_t out_pixel_fmt;
} mem_rot_enc_mem;
struct {
uint32_t in_width;
uint32_t in_height;
uint32_t in_pixel_fmt;
uint32_t out_width;
uint32_t out_height;
uint32_t out_pixel_fmt;
uint32_t outh_resize_ratio;
uint32_t outv_resize_ratio;
bool graphics_combine_en;
bool global_alpha_en;
bool key_color_en;
uint32_t in_g_pixel_fmt;
uint8_t alpha;
uint32_t key_color;
bool alpha_chan_en;
ipu_motion_sel motion_sel;
enum v4l2_field field_fmt;
uint32_t csi;
uint32_t mipi_id;
uint32_t mipi_vc;
bool mipi_en;
} csi_prp_vf_mem;
struct {
uint32_t in_width;
uint32_t in_height;
uint32_t in_pixel_fmt;
uint32_t out_width;
uint32_t out_height;
uint32_t out_pixel_fmt;
bool graphics_combine_en;
bool global_alpha_en;
bool key_color_en;
display_port_t disp;
uint32_t out_left;
uint32_t out_top;
} csi_prp_vf_adc;
struct {
uint32_t in_width; //输入宽度
uint32_t in_height; //输入高度
uint32_t in_pixel_fmt; //输入像素格式
uint32_t out_width; //输出宽度
uint32_t out_height; //输出高度
uint32_t out_pixel_fmt; //输出像素格式
uint32_t outh_resize_ratio; //输出水平方向上重定义大小的比例
uint32_t outv_resize_ratio; //输出垂直方向上重定义大小的比例
bool graphics_combine_en; //是否使能second channel的标志位
bool global_alpha_en; //是否使能third channel的标志位
bool key_color_en;
uint32_t in_g_pixel_fmt;
uint8_t alpha;
uint32_t key_color;
bool alpha_chan_en;
ipu_motion_sel motion_sel;
enum v4l2_field field_fmt;
} mem_prp_vf_mem;
struct {
uint32_t temp;
} mem_prp_vf_adc;
struct {
uint32_t temp;
} mem_rot_vf_mem;
struct {
uint32_t in_width;
uint32_t in_height;
uint32_t in_pixel_fmt;
uint32_t out_width;
uint32_t out_height;
uint32_t out_pixel_fmt;
uint32_t outh_resize_ratio;
uint32_t outv_resize_ratio;
bool graphics_combine_en;
bool global_alpha_en;
bool key_color_en;
uint32_t in_g_pixel_fmt;
uint8_t alpha;
uint32_t key_color;
bool alpha_chan_en;
} mem_pp_mem;
struct {
uint32_t temp;
} mem_rot_mem;
struct {
uint32_t in_width;
uint32_t in_height;
uint32_t in_pixel_fmt;
uint32_t out_width;
uint32_t out_height;
uint32_t out_pixel_fmt;
bool graphics_combine_en;
bool global_alpha_en;
bool key_color_en;
display_port_t disp;
uint32_t out_left;
uint32_t out_top;
} mem_pp_adc;
struct {
uint32_t di;
bool interlaced; //数据是否是隔行的
uint32_t in_pixel_fmt;
uint32_t out_pixel_fmt;
} mem_dc_sync;
struct {
uint32_t temp;
} mem_sdc_fg;
struct {
uint32_t di;
bool interlaced; //数据是否是隔行的
uint32_t in_pixel_fmt;
uint32_t out_pixel_fmt;
bool alpha_chan_en;
} mem_dp_bg_sync;
struct {
uint32_t temp;
} mem_sdc_bg;
struct {
uint32_t di;
bool interlaced; //数据是否是隔行的
uint32_t in_pixel_fmt;
uint32_t out_pixel_fmt;
bool alpha_chan_en;
} mem_dp_fg_sync;
struct {
uint32_t di;
} direct_async;
struct {
display_port_t disp;
mcu_mode_t ch_mode;
uint32_t out_left;
uint32_t out_top;
} adc_sys1;
struct {
display_port_t disp;
mcu_mode_t ch_mode;
uint32_t out_left;
uint32_t out_top;
} adc_sys2;
} ipu_channel_params_t;
这个ipu_channel_params_t这个联合,在这个联合中对于每一种channel都有一个对应的结构体类型来保存channel的参数。如果想要获取哪一个channel的信息,就从这个联合中的对应channel里面找即可。同时,在initchannel的时候,也是通过对这个联合里面对应的channel参数赋值。