freescale R10 ipu lib 分析 - ipu_capture.c

来源:互联网 发布:淘宝店铺背景图 编辑:程序博客网 时间:2024/05/01 17:17

转:http://blog.csdn.net/kickxxx/article/details/6560455

ipu_capture.c

 

47 int32_t
 48 ipu_csi_init_interface(uint16_t width, uint16_t height, uint32_t pixel_fmt,
 49     ipu_csi_signal_cfg_t cfg_param)
 50 {
 51     uint32_t data = 0;
 52     uint32_t csi = cfg_param.csi;
 53     unsigned long lock_flags;
 54 
 55     /* Set SENS_DATA_FORMAT bits (8, 9 and 10)
 56        RGB or YUV444 is 0 which is current value in data so not set
 57        explicitly
 58        This is also the default value if attempts are made to set it to
 59        something invalid. */
 60     switch (pixel_fmt) {
 61     case IPU_PIX_FMT_YUYV:
 62         cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_YUYV;
 63         break;
 64     case IPU_PIX_FMT_UYVY:
 65         cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY;
 66         break;
 67     case IPU_PIX_FMT_RGB24:
 68     case IPU_PIX_FMT_BGR24:
 69         cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_RGB_YUV444;
 70         break;
 71     case IPU_PIX_FMT_GENERIC:
 72         cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
 73         break;
 74     case IPU_PIX_FMT_RGB565:
 75         cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_RGB565;
 76         break;
 77     case IPU_PIX_FMT_RGB555:
 78         cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_RGB555;
 79         break;
 80     default:
 81         return -EINVAL;
 82     }
 83 
 84     /* Set the CSI_SENS_CONF register remaining fields */
 85     data |= cfg_param.data_width << CSI_SENS_CONF_DATA_WIDTH_SHIFT |
 86         cfg_param.data_fmt << CSI_SENS_CONF_DATA_FMT_SHIFT |
 87         cfg_param.data_pol << CSI_SENS_CONF_DATA_POL_SHIFT |
 88         cfg_param.Vsync_pol << CSI_SENS_CONF_VSYNC_POL_SHIFT |
 89         cfg_param.Hsync_pol << CSI_SENS_CONF_HSYNC_POL_SHIFT |
 90         cfg_param.pixclk_pol << CSI_SENS_CONF_PIX_CLK_POL_SHIFT |
 91         cfg_param.ext_vsync << CSI_SENS_CONF_EXT_VSYNC_SHIFT |
 92         cfg_param.clk_mode << CSI_SENS_CONF_SENS_PRTCL_SHIFT |
 93         cfg_param.pack_tight << CSI_SENS_CONF_PACK_TIGHT_SHIFT |
 94         cfg_param.force_eof << CSI_SENS_CONF_FORCE_EOF_SHIFT |
 95         cfg_param.data_en_pol << CSI_SENS_CONF_DATA_EN_POL_SHIFT;
 96 
 97     if (g_ipu_clk_enabled == false) {
 98         stop_dvfs_per();
 99         g_ipu_clk_enabled = true;
100         clk_enable(g_ipu_clk);
101     }
102 
103     spin_lock_irqsave(&ipu_lock, lock_flags);
104 
105     __raw_writel(data, CSI_SENS_CONF(csi));
106 
107     /* Setup sensor frame size */
108     __raw_writel((width - 1) | (height - 1) << 16, CSI_SENS_FRM_SIZE(csi));
109 
110     /* Set CCIR registers */
111     if (cfg_param.clk_mode == IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE) {
112         __raw_writel(0x40030, CSI_CCIR_CODE_1(csi));
113         __raw_writel(0xFF0000, CSI_CCIR_CODE_3(csi));
114     } else if (cfg_param.clk_mode == IPU_CSI_CLK_MODE_CCIR656_INTERLACED) {
115         if (width == 720 && height == 625) {
116             /* PAL case */
117             /*
118              * Field0BlankEnd = 0x6, Field0BlankStart = 0x2,
119              * Field0ActiveEnd = 0x4, Field0ActiveStart = 0
120              */
121             __raw_writel(0x40596, CSI_CCIR_CODE_1(csi));
122             /*
123              * Field1BlankEnd = 0x7, Field1BlankStart = 0x3,
124              * Field1ActiveEnd = 0x5, Field1ActiveStart = 0x1
125              */
126             __raw_writel(0xD07DF, CSI_CCIR_CODE_2(csi));
127             __raw_writel(0xFF0000, CSI_CCIR_CODE_3(csi));
128         } else if (width == 720 && height == 525) {
129             /* NTSC case */
130             /*
131              * Field0BlankEnd = 0x7, Field0BlankStart = 0x3,
132              * Field0ActiveEnd = 0x5, Field0ActiveStart = 0x1
133              */
134             __raw_writel(0xD07DF, CSI_CCIR_CODE_1(csi));
135             /*
136              * Field1BlankEnd = 0x6, Field1BlankStart = 0x2,
137              * Field1ActiveEnd = 0x4, Field1ActiveStart = 0
138              */
139             __raw_writel(0x40596, CSI_CCIR_CODE_2(csi));
140             __raw_writel(0xFF0000, CSI_CCIR_CODE_3(csi));
141         } else {
142             spin_unlock_irqrestore(&ipu_lock, lock_flags);
143             dev_err(g_ipu_dev, "Unsupported CCIR656 interlaced "
144                     "video mode/n");
145             return -EINVAL;
146         }
147         _ipu_csi_ccir_err_detection_enable(csi);
148     } else if ((cfg_param.clk_mode ==
149             IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR) ||
150         (cfg_param.clk_mode ==
151             IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR) ||
152         (cfg_param.clk_mode ==
153             IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR) ||
154         (cfg_param.clk_mode ==
155             IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR)) {
156         __raw_writel(0x40030, CSI_CCIR_CODE_1(csi));
157         __raw_writel(0xFF0000, CSI_CCIR_CODE_3(csi));
158         _ipu_csi_ccir_err_detection_enable(csi);
159     } else if ((cfg_param.clk_mode == IPU_CSI_CLK_MODE_GATED_CLK) ||
160            (cfg_param.clk_mode == IPU_CSI_CLK_MODE_NONGATED_CLK)) {
161         _ipu_csi_ccir_err_detection_disable(csi);
162     }
163 
164     dev_dbg(g_ipu_dev, "CSI_SENS_CONF = 0x%08X/n",
165         __raw_readl(CSI_SENS_CONF(csi)));
166     dev_dbg(g_ipu_dev, "CSI_ACT_FRM_SIZE = 0x%08X/n",
167         __raw_readl(CSI_ACT_FRM_SIZE(csi)));
168 
169     spin_unlock_irqrestore(&ipu_lock, lock_flags);
170 
171     return 0;
172 }
173 EXPORT_SYMBOL(ipu_csi_init_interface);
 
这个函数初始化CSI 寄存器,open设备或者VIDIOC_S_PARM时调用

参数@height @width是sensor的frame RAW尺寸, raw size与之对应的是active size,比如PAL制式的摄像头raw size是720x625, 而active size是720x576

参数@pixel_fmt: csi input pixel format

参数@cfg_param: 定义了csi接口相关的参数, 这些参数应该是具体camera chip和外围电路决定的

data_fmt: csi input pixel format

ext_vsync: 是否存在外部vsync信号

clock_mode: 如果是BT656输入,那么应该是IPU_CSI_CLK_MODE_CCIR656_INTERLACED

 

55~82 转换pixel format为CSI 寄存器的内部表示

84~96 把外部参数转换为CSI_SENS_CONF寄存器的值

108 这里写入的是raw size, 可以参考MX51 中CSI_SENS_FRM_SIZE的定义

110~162 设置CCIR寄存器,设置BT656的time reference signals(frame start, frame end etc.), 前三个字节是固定的,这个寄存器定义第四个字节的模式。time reference signals是由V H F来决定的,具体怎么映射的,我没分析出来.

V H F的定义可以查看BT656的定义F=0表示偶数场,F=1表示奇数场;v=0表示该行为active video,v=1表示该行不是active video; H=0表示为SAV信号,H=1为EAV信号

至于为什么PAL NTSC设置是反的,我最后想到一种可能,那就是因为PAL与NTSC的field顺序是不一样的,所以这里给颠倒了一下,因此你获得的capture或者preview要根据输入制式做相应处理。

 

(先保存一下,接着来)

 

276 void ipu_csi_set_window_size(uint32_t width, uint32_t height, uint32_t csi)
277 {
278     unsigned long lock_flags;
279 
280     if (g_ipu_clk_enabled == false) {
281         stop_dvfs_per();
282         g_ipu_clk_enabled = true;
283         clk_enable(g_ipu_clk);
284     }
285 
286     spin_lock_irqsave(&ipu_lock, lock_flags);
287 
288     __raw_writel((width - 1) | (height - 1) << 16, CSI_ACT_FRM_SIZE(csi));
289 
290     spin_unlock_irqrestore(&ipu_lock, lock_flags);
291 }
292 EXPORT_SYMBOL(ipu_csi_set_window_size);

 

301 void ipu_csi_set_window_pos(uint32_t left, uint32_t top, uint32_t csi)
302 {
303     uint32_t temp;
304     unsigned long lock_flags;
305 
306     if (g_ipu_clk_enabled == false) {
307         stop_dvfs_per();
308         g_ipu_clk_enabled = true;
309         clk_enable(g_ipu_clk);
310     }
311 
312     spin_lock_irqsave(&ipu_lock, lock_flags);
313 
314     temp = __raw_readl(CSI_OUT_FRM_CTRL(csi));
315     temp &= ~(CSI_HSC_MASK | CSI_VSC_MASK);
316     temp |= ((top << CSI_VSC_SHIFT) | (left << CSI_HSC_SHIFT));
317     __raw_writel(temp, CSI_OUT_FRM_CTRL(csi));
318 
319     spin_unlock_irqrestore(&ipu_lock, lock_flags);
320 }
321 EXPORT_SYMBOL(ipu_csi_set_window_pos);

这两个函数没什么可讲的,但是CSI_ACT_FRM_SIZE,CSI_OUT_FRM_CTRL是做什么的很重要,这里我只能猜了,因为没有试出这个功能。

CSI_ACT_FRM_SIZE和CSI_OUT_FRM_CTRL定义了crop rectangle, 还记得VIDIOC_S_CROP吗,这个ioctl最终会调用ipu_csi_set_window_size和ipu_csi_set_window_pos。相当于在CSI 最大active窗口开了一个取景框,capture和overlay只使用这个取景框内的像素,如果以后有时间再回来验证这个问题。

 

329 void _ipu_csi_horizontal_downsize_enable(uint32_t csi)
330 {
331     uint32_t temp;
332     unsigned long lock_flags; 
333 
334     if (g_ipu_clk_enabled == false) {
335         stop_dvfs_per();
336         g_ipu_clk_enabled = true; 
337         clk_enable(g_ipu_clk);
338     }
339 
340     spin_lock_irqsave(&ipu_lock, lock_flags);
341 
342     temp = __raw_readl(CSI_OUT_FRM_CTRL(csi));
343     temp |= CSI_HORI_DOWNSIZE_EN;
344     __raw_writel(temp, CSI_OUT_FRM_CTRL(csi));
345 
346     spin_unlock_irqrestore(&ipu_lock, lock_flags);
347 }

 

381 void _ipu_csi_vertical_downsize_enable(uint32_t csi)
382 {
383     uint32_t temp;
384     unsigned long lock_flags;
385 
386     if (g_ipu_clk_enabled == false) {
387         stop_dvfs_per();
388         g_ipu_clk_enabled = true;
389         clk_enable(g_ipu_clk);
390     }
391 
392     spin_lock_irqsave(&ipu_lock, lock_flags);
393 
394     temp = __raw_readl(CSI_OUT_FRM_CTRL(csi));
395     temp |= CSI_VERT_DOWNSIZE_EN;
396     __raw_writel(temp, CSI_OUT_FRM_CTRL(csi));
397 
398     spin_unlock_irqrestore(&ipu_lock, lock_flags);
399 }

CSI_VERT_DOWNSIZE_EN CSI_HORI_DOWNSIZE_EN的作用,还要日后试一下再说

 

 

824 int _ipu_csi_init(ipu_channel_t channel, uint32_t csi)
825 {
826     uint32_t csi_sens_conf, csi_dest;
827     int retval = 0;
828 
829     switch (channel) {
830     case CSI_MEM0:
831     case CSI_MEM1:
832     case CSI_MEM2:
833     case CSI_MEM3:
834         csi_dest = CSI_DATA_DEST_IDMAC;
835         break;
836     case CSI_PRP_ENC_MEM:
837     case CSI_PRP_VF_MEM:
838         csi_dest = CSI_DATA_DEST_IC;
839         break;
840     default:
841         retval = -EINVAL;
842         goto err;
843     }
844 
845     csi_sens_conf = __raw_readl(CSI_SENS_CONF(csi));
846     csi_sens_conf &= ~CSI_SENS_CONF_DATA_DEST_MASK;
847     __raw_writel(csi_sens_conf | (csi_dest <<
848         CSI_SENS_CONF_DATA_DEST_SHIFT), CSI_SENS_CONF(csi));
849 err:
850     return retval;
851 }

 

根据channel不同,设置CSI 数据的destination,  通过设置DATA_DEST就可以决定CSI sensor数据的流向。IC, SMFC, ISP