原文:http://blog.csdn.net/kickxxx/archive/2011/06/22/6560455.aspx
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