fimc_regs.c是fimc框架操作camera 硬件的接口,fimc框架把所有硬件相关的操作都放在这个文件中
100 int fimc_hwset_camera_source(struct fimc_control *ctrl)
101 {
102 struct s3c_platform_camera *cam = ctrl->cam;
103 u32 cfg = 0;
104
105 /* for now, we support only ITU601 8 bit mode */
106 cfg |= S3C_CISRCFMT_ITU601_8BIT;
107 cfg |= cam->order422;
108
109 if (cam->type == CAM_TYPE_ITU)
110 cfg |= cam->fmt;
111
112 cfg |= S3C_CISRCFMT_SOURCEHSIZE(cam->width);
113 cfg |= S3C_CISRCFMT_SOURCEVSIZE(cam->height);
114
115 writel(cfg, ctrl->regs + S3C_CISRCFMT);
116
117 return 0;
118 }
S3C_CISRCFMT: Camera Source Format,FIMC1 FIMC2 FIMC3各对应一个
106 设置external 摄像头支持的模式,一般来讲 AD转换芯片都是支持BT656
107 cam->order422,这里的cam代表的就是一个外部摄像头,cam->order422是在arch/arm/mach-s5pv210/mach-xxx.c中定义的,标识了external camera 像素的Y C R分量的排列方式,对于BT656来是,选择CAM_ORDER422_8BIT_YCBYCR,CAM_ORDER422_8BIT_YCRYCB, CAM_ORDER422_8BIT_CBYCRY, CAM_ORDER422_8BIT_CRYCBY之一,具体选择哪一个,要根据sensor datasheet中BT656输出 Y U V分量的顺序决定。
109 因为cam->fmt也是设置 ITU模式的,所以和106行代码是冗余的,不知作者为什么这样写
112 ~ 113 设置source水平和垂直像素数目,source可以是 camera或者FIFO input
159 int fimc_hwset_output_area_size(struct fimc_control *ctrl, u32 size)
160 {
161 u32 cfg = 0;
162
163 cfg = S3C_CITAREA_TARGET_AREA(size);
164
165 writel(cfg, ctrl->regs + S3C_CITAREA);
166
167 return 0;
168 }
CITAREA: output DMA target area register
设置output DMA的target大小,这个值并不是buffer空间的大小,而是输出图像的H_size * V_size
170 void fimc_wait_disable_capture(struct fimc_control *ctrl)
171 {
172 unsigned long timeo = jiffies + 20; /* timeout of 100 ms */
173 u32 cfg;
174
175 if (!ctrl || !ctrl->cap ||
176 ctrl->cap->fmt.colorspace == V4L2_COLORSPACE_JPEG)
177 return;
178
179 while (time_before(jiffies, timeo)) {
180 cfg = readl(ctrl->regs + S3C_CISTATUS);
181
182 if (0 == (cfg & S3C_CISTATUS_IMGCPTEN))
183 break;
184
185 msleep(10);
186 }
187
188 dev_dbg(ctrl->dev, "IMGCPTEN: Wait time = %d ms\n",
189 jiffies_to_msecs(jiffies - timeo + 20));
190
191 return;
192 }
在disable capture后,可以调用这个函数,来保证disable capture操作完成
S3C_CISTATUS_IMGCPTEN 标识是否image capture enable的状态
194 int fimc_hwset_image_effect(struct fimc_control *ctrl)
195 {
196 u32 cfg = 0;
197
198 if (ctrl->fe.ie_on) {
199 if (ctrl->fe.ie_after_sc)
200 cfg |= S3C_CIIMGEFF_IE_SC_AFTER;
201
202 cfg |= S3C_CIIMGEFF_FIN(ctrl->fe.fin);
203
204 if (ctrl->fe.fin == FIMC_EFFECT_FIN_ARBITRARY_CBCR)
205 cfg |= S3C_CIIMGEFF_PAT_CB(ctrl->fe.pat_cb) |
206 S3C_CIIMGEFF_PAT_CR(ctrl->fe.pat_cr);
207
208 cfg |= S3C_CIIMGEFF_IE_ENABLE;
209 }
210
211 writel(cfg, ctrl->regs + S3C_CIIMGEFF);
212
213 return 0;
214 }
FIMC控制器支持图片特效处理,因此fimc的V4L2 s_ctl接口提供了特效控制
CIIMGEFF寄存器控制图片的特效,具体的特效说明,参看s5pv210 datasheet
267 int fimc_hwset_reset(struct fimc_control *ctrl)
268 {
269 u32 cfg = 0;
270
271 cfg = readl(ctrl->regs + S3C_CISRCFMT);
272 cfg |= S3C_CISRCFMT_ITU601_8BIT;
273 writel(cfg, ctrl->regs + S3C_CISRCFMT);
274
275 /* s/w reset */
276 cfg = readl(ctrl->regs + S3C_CIGCTRL);
277 cfg |= (S3C_CIGCTRL_SWRST);
278 writel(cfg, ctrl->regs + S3C_CIGCTRL);
279 mdelay(1);
280
281 cfg = readl(ctrl->regs + S3C_CIGCTRL);
282 cfg &= ~S3C_CIGCTRL_SWRST;
283 writel(cfg, ctrl->regs + S3C_CIGCTRL);
284
285 /* in case of ITU656, CISRCFMT[31] should be 0 */
286 if ((ctrl->cap != NULL) && (ctrl->cam->fmt == ITU_656_YCBCR422_8BIT)) {
287 cfg = readl(ctrl->regs + S3C_CISRCFMT);
288 cfg &= ~S3C_CISRCFMT_ITU601_8BIT;
289 writel(cfg, ctrl->regs + S3C_CISRCFMT);
290 }
291
292 fimc_reset_cfg(ctrl);
293
294 return 0;
295 }
FIMC软件复位过程:
S5PV210 datasheet推荐使用如下初始化序列
对于ITU601: ITU601_656n置1 -> SwRst置1 -> SwRst置0
对于ITU656: ITU601_656n置1 -> SwRst置1 -> SwRst置0 -> ITU601_656置0
335 int fimc_hwset_camera_offset(struct fimc_control *ctrl)
336 {
337 struct s3c_platform_camera *cam = ctrl->cam;
338 struct v4l2_rect *rect = &cam->window;
339 u32 cfg, h1, h2, v1, v2;
340
341 if (!cam) {
342 fimc_err("%s: no active camera\n", __func__);
343 return -ENODEV;
344 }
345
346 h1 = rect->left;
347 h2 = cam->width - rect->width - rect->left;
348 v1 = rect->top;
349 v2 = cam->height - rect->height - rect->top;
350
351 cfg = readl(ctrl->regs + S3C_CIWDOFST);
352 cfg &= ~(S3C_CIWDOFST_WINHOROFST_MASK | S3C_CIWDOFST_WINVEROFST_MASK);
353 cfg |= S3C_CIWDOFST_WINHOROFST(h1);
354 cfg |= S3C_CIWDOFST_WINVEROFST(v1);
355 cfg |= S3C_CIWDOFST_WINOFSEN;
356 writel(cfg, ctrl->regs + S3C_CIWDOFST);
357
358 cfg = 0;
359 cfg |= S3C_CIWDOFST2_WINHOROFST2(h2);
360 cfg |= S3C_CIWDOFST2_WINVEROFST2(v2);
361 writel(cfg, ctrl->regs + S3C_CIWDOFST2);
362
363 return 0;
364 }
h1: Window Horizon Offset, v1: Window Vertical Offset
h2: Window Horizon Offset2, v2: Window Vertical Offset2
下面这个图很明了的解释了这几个坐标概念
h1, h2, v1, v2这四个坐标就定义了crop的范围,上图右边部分就是crop结果
366 int fimc_hwset_camera_polarity(struct fimc_control *ctrl)
367 {
368 struct s3c_platform_camera *cam = ctrl->cam;
369 u32 cfg;
370
371 if (!cam) {
372 fimc_err("%s: no active camera\n", __func__);
373 return -ENODEV;
374 }
375
376 cfg = readl(ctrl->regs + S3C_CIGCTRL);
377
378 cfg &= ~(S3C_CIGCTRL_INVPOLPCLK | S3C_CIGCTRL_INVPOLVSYNC |
379 S3C_CIGCTRL_INVPOLHREF | S3C_CIGCTRL_INVPOLHSYNC);
380
381 if (cam->inv_pclk)
382 cfg |= S3C_CIGCTRL_INVPOLPCLK;
383
384 if (cam->inv_vsync)
385 cfg |= S3C_CIGCTRL_INVPOLVSYNC;
386
387 if (cam->inv_href)
388 cfg |= S3C_CIGCTRL_INVPOLHREF;
389
390 if (cam->inv_hsync)
391 cfg |= S3C_CIGCTRL_INVPOLHSYNC;
392
393 writel(cfg, ctrl->regs + S3C_CIGCTRL);
394
395 return 0;
396 }
camera sensor输出到fimc控制器的几个信号: pixclk, href(hsync), vsync。 sensor可能会设置这几个信号的极性,因此FIMC控制器端也需要和这个信号的极性匹配
具体配置需要参考sensor的输出,一般情况下无极性翻转。
对于BT656信号来说,只需要考虑pixclk的极性。
434 int fimc43_hwset_camera_type(struct fimc_control *ctrl)
435 {
436 struct s3c_platform_camera *cam = ctrl->cam;
437 u32 cfg;
438
439 if (!cam) {
440 fimc_err("%s: no active camera\n", __func__);
441 return -ENODEV;
442 }
443
444 cfg = readl(ctrl->regs + S3C_CIGCTRL);
445 cfg &= ~(S3C_CIGCTRL_TESTPATTERN_MASK | S3C_CIGCTRL_SELCAM_ITU_MASK |
446 S3C_CIGCTRL_SELCAM_MIPI_MASK | S3C_CIGCTRL_SELCAM_FIMC_MASK |
447 S3C_CIGCTRL_SELWB_CAMIF_MASK);
448
449 /* Interface selection */
450 if (cam->id == CAMERA_WB) {
451 cfg |= S3C_CIGCTRL_SELWB_CAMIF_WRITEBACK;
452 } else if (cam->type == CAM_TYPE_MIPI) {
453 cfg |= S3C_CIGCTRL_SELCAM_FIMC_MIPI;
454
455 /* C110/V210 Support only MIPI A support */
456 cfg |= S3C_CIGCTRL_SELCAM_MIPI_A;
457
458 /* FIXME: Temporary MIPI CSIS Data 32 bit aligned */
459 if (ctrl->cap->fmt.pixelformat == V4L2_PIX_FMT_JPEG)
460 writel((MIPI_USER_DEF_PACKET_1 | (0x1 << 8)),
461 ctrl->regs + S3C_CSIIMGFMT);
462 else
463 writel(cam->fmt | (0x1 << 8),
464 ctrl->regs + S3C_CSIIMGFMT);
465 } else if (cam->type == CAM_TYPE_ITU) {
466 if (cam->id == CAMERA_PAR_A)
467 cfg |= S3C_CIGCTRL_SELCAM_ITU_A;
468 else
469 cfg |= S3C_CIGCTRL_SELCAM_ITU_B;
470 /* switch to ITU interface */
471 cfg |= S3C_CIGCTRL_SELCAM_FIMC_ITU;
472 } else {
473 fimc_err("%s: invalid camera bus type selected\n", __func__);
474 return -EINVAL;
475 }
476
477 writel(cfg, ctrl->regs + S3C_CIGCTRL);
478
479 return 0;
480 }
FIMC提供了三个物理camera接口:
两个ITU类型的:Camera A(GPE0_0 --- GPE1_4)和Camera B(GPJ0_0 --- GPJ1_4),
一个MIPI类型的: Camera C
465 ~ 469 选择使用哪个物理camera接口,这个需要查看原理图来预设cam->id。
522 int fimc_hwset_jpeg_mode(struct fimc_control *ctrl, bool enable)
523 {
524 u32 cfg;
525 cfg = readl(ctrl->regs + S3C_CIGCTRL);
526
527 if (enable)
528 cfg |= S3C_CIGCTRL_CAM_JPEG;
529 else
530 cfg &= ~S3C_CIGCTRL_CAM_JPEG;
531
532 writel(cfg, ctrl->regs + S3C_CIGCTRL);
533
534 return 0;
535 }
对于ITU601输入如果输入数据是8bit jpeg格式(压缩格式),那么就要设置JPEG标志位,这时FIMC会忽略scaler和转换。
对于BT656来说只能是YUYV格式
537 int fimc_hwset_output_size(struct fimc_control *ctrl, int width, int height)
538 {
539 u32 cfg = readl(ctrl->regs + S3C_CITRGFMT);
540
541 printk(KERN_ERR "%s: width(%d), height(%d)\n", __func__, width, height);
542
543 cfg &= ~(S3C_CITRGFMT_TARGETH_MASK | S3C_CITRGFMT_TARGETV_MASK);
544
545 cfg |= S3C_CITRGFMT_TARGETHSIZE(width);
546 cfg |= S3C_CITRGFMT_TARGETVSIZE(height);
547
548 writel(cfg, ctrl->regs + S3C_CITRGFMT);
549
550 return 0;
551 }
545 ~ 546 是FIMC输出图像的width和height size, 他们不应该大于camera source height size和 source width size,当然这并不意味着FIMC的scaler没有放大功能,FIMC的scaler有放大功能
,但是放大后的尺寸不能超过source Hsize和souce Vsize
553 int fimc_hwset_output_colorspace(struct fimc_control *ctrl, u32 pixelformat)
554 {
555 struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev);
556 u32 cfg;
557
558 if (pdata->hw_ver != 0x40) {
559 if (pixelformat == V4L2_PIX_FMT_YUV444) {
560 cfg = readl(ctrl->regs + S3C_CIEXTEN);
561 cfg |= S3C_CIEXTEN_YUV444_OUT;
562 writel(cfg, ctrl->regs + S3C_CIEXTEN);
563
564 return 0;
565 } else {
566 cfg = readl(ctrl->regs + S3C_CIEXTEN);
567 cfg &= ~S3C_CIEXTEN_YUV444_OUT;
568 writel(cfg, ctrl->regs + S3C_CIEXTEN);
569 }
570 }
571
572 cfg = readl(ctrl->regs + S3C_CITRGFMT);
573 cfg &= ~S3C_CITRGFMT_OUTFORMAT_MASK;
574
575 switch (pixelformat) {
576 case V4L2_PIX_FMT_JPEG:
577 break;
578 case V4L2_PIX_FMT_RGB565: /* fall through */
579 case V4L2_PIX_FMT_RGB32:
580 cfg |= S3C_CITRGFMT_OUTFORMAT_RGB;
581 break;
582
583 case V4L2_PIX_FMT_YUYV: /* fall through */
584 case V4L2_PIX_FMT_UYVY: /* fall through */
585 case V4L2_PIX_FMT_VYUY: /* fall through */
586 case V4L2_PIX_FMT_YVYU:
587 cfg |= S3C_CITRGFMT_OUTFORMAT_YCBCR422_1PLANE;
588 break;
589
590 case V4L2_PIX_FMT_NV16: /* fall through */
591 case V4L2_PIX_FMT_NV61: /* fall through */
592 case V4L2_PIX_FMT_YUV422P:
593 cfg |= S3C_CITRGFMT_OUTFORMAT_YCBCR422;
594 break;
595
596 case V4L2_PIX_FMT_YUV420: /* fall through */
597 case V4L2_PIX_FMT_NV12: /* fall through */
598 case V4L2_PIX_FMT_NV12T: /* fall through */
599 case V4L2_PIX_FMT_NV21:
600 cfg |= S3C_CITRGFMT_OUTFORMAT_YCBCR420;
601 break;
602
603 default:
604 fimc_err("%s: invalid pixel format\n", __func__);
605 break;
606 }
607
608 writel(cfg, ctrl->regs + S3C_CITRGFMT);
609
610 return 0;
611 }
设置FIMC的输出颜色格式,FIMC支持颜色空间转换,应用程序或测试程序可以通过S_FMT ioctl指定希望的输出颜色格式
615 int fimc_hwset_output_rot_flip(struct fimc_control *ctrl, u32 rot, u32 flip)
616 {
617 u32 cfg, val;
618
619 cfg = readl(ctrl->regs + S3C_CITRGFMT);
620 cfg &= ~S3C_CITRGFMT_FLIP_MASK;
621 cfg &= ~S3C_CITRGFMT_OUTROT90_CLOCKWISE;
622
623 val = fimc_mapping_rot_flip(rot, flip);
624
625 if (val & FIMC_ROT)
626 cfg |= S3C_CITRGFMT_OUTROT90_CLOCKWISE;
627
628 if (val & FIMC_XFLIP)
629 cfg |= S3C_CITRGFMT_FLIP_X_MIRROR;
630
631 if (val & FIMC_YFLIP)
632 cfg |= S3C_CITRGFMT_FLIP_Y_MIRROR;
633
634 writel(cfg, ctrl->regs + S3C_CITRGFMT);
635
636 return 0;
637 }
FIMC控制器支持图片的翻转,应用层可以通过s_ctrl ioctl来设置翻转
690 int fimc_hwset_output_address(struct fimc_control *ctrl,
691 struct fimc_buf_set *bs, int id)
692 {
693 printk(KERN_ERR "%s: FIMC_ADDR_Y=0x%x, FIMC_ADDR_CB=0x%x, FIMC_ADDR_CR=0x%x\n",
694 __func__, bs->base[FIMC_ADDR_Y], bs->base[FIMC_ADDR_CB],
695 bs->base[FIMC_ADDR_CR]);
696 writel(bs->base[FIMC_ADDR_Y], ctrl->regs + S3C_CIOYSA(id));
697 writel(bs->base[FIMC_ADDR_CB], ctrl->regs + S3C_CIOCBSA(id));
698 writel(bs->base[FIMC_ADDR_CR], ctrl->regs + S3C_CIOCRSA(id));
699
700 return 0;
701 }
设置输出DMA地址,这里需要注意某些情况下,DMA物理地址需要一定的对齐方式,如果赋给FIMC的DMA地址没有满足需要的对齐方式,FIMC驱动并不会报错,而是把输出数据写入到指定地址后符合对齐方式的地址,这样就导致DMA地址前面一部分没有有效数据写入,而后面地址写入的数据又发生了错位。
举个例子,比如DMA要求4K对齐,你赋值的地址为0x40000800,那么FIMC会越过2K字节从0x40001000开始写数据,而且会越过你假定的那个DMA buffer边界,写入不可知的区域(这个我纯属猜测)
FIMC既支持packed格式的输出,此时仅需要设置FIMC_ADDR_Y;也支持planer格式的输出,此时还需要设置FIMC_ADDR_CB和FIMC_ADDR_CR
703 int fimc_hwset_output_yuv(struct fimc_control *ctrl, u32 pixelformat)
704 {
705 u32 cfg;
706
707 cfg = readl(ctrl->regs + S3C_CIOCTRL);
708 cfg &= ~(S3C_CIOCTRL_ORDER2P_MASK | S3C_CIOCTRL_ORDER422_MASK |
709 S3C_CIOCTRL_YCBCR_PLANE_MASK);
710
711 switch (pixelformat) {
712 /* 1 plane formats */
713 case V4L2_PIX_FMT_YUYV:
714 cfg |= S3C_CIOCTRL_ORDER422_YCBYCR;
715 break;
716
717 case V4L2_PIX_FMT_UYVY:
718 cfg |= S3C_CIOCTRL_ORDER422_CBYCRY;
719 break;
720
721 case V4L2_PIX_FMT_VYUY:
722 cfg |= S3C_CIOCTRL_ORDER422_CRYCBY;
723 break;
724
725 case V4L2_PIX_FMT_YVYU:
726 cfg |= S3C_CIOCTRL_ORDER422_YCRYCB;
727 break;
728
729 /* 2 plane formats */
730 case V4L2_PIX_FMT_NV12: /* fall through */
731 case V4L2_PIX_FMT_NV12T: /* fall through */
732 case V4L2_PIX_FMT_NV16:
733 cfg |= S3C_CIOCTRL_ORDER2P_LSB_CBCR;
734 cfg |= S3C_CIOCTRL_YCBCR_2PLANE;
735 break;
736
737 case V4L2_PIX_FMT_NV21: /* fall through */
738 case V4L2_PIX_FMT_NV61:
739 cfg |= S3C_CIOCTRL_ORDER2P_LSB_CRCB;
740 cfg |= S3C_CIOCTRL_YCBCR_2PLANE;
741 break;
742
743 /* 3 plane formats */
744 case V4L2_PIX_FMT_YUV422P: /* fall through */
745 case V4L2_PIX_FMT_YUV420:
746 cfg |= S3C_CIOCTRL_YCBCR_3PLANE;
747 break;
748 }
749
750 writel(cfg, ctrl->regs + S3C_CIOCTRL);
751
752 return 0;
753 }
YUV有很多种格式,可以分为两大类: 打包格式(packed)和平面格式(planer),打包格式是YUV分量放在一个数组中,相邻的几个分量组成一个像素的。而后者使用两个或者三个分量数组,两个分量数组是将Y和UV分量分开,三个分量数组则是将YUV分量放在不同的数组中
755 int fimc_hwset_output_scan(struct fimc_control *ctrl,
756 struct v4l2_pix_format *fmt)
757 {
758 struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev);
759 u32 cfg;
760
761 /* nothing to do: FIMC40 not supported interlaced and weave output */
762 if (pdata->hw_ver == 0x40)
763 return 0;
764
765 cfg = readl(ctrl->regs + S3C_CISCCTRL);
766 cfg &= ~S3C_CISCCTRL_SCAN_MASK;
767
768 if (fmt->field == V4L2_FIELD_INTERLACED ||
769 fmt->field == V4L2_FIELD_INTERLACED_TB) {
770 cfg |= S3C_CISCCTRL_INTERLACE;
771 printk(KERN_ERR "%s: set S3C_CISCCTRL_INTERLACE\n", __func__);
772 }
773 else
774 cfg |= S3C_CISCCTRL_PROGRESSIVE;
775
776 writel(cfg, ctrl->regs + S3C_CISCCTRL);
777
778 cfg = readl(ctrl->regs + S3C_CIOCTRL);
779 cfg &= ~S3C_CIOCTRL_WEAVE_MASK;
780
781 if ((ctrl->cap) && (fmt->field == V4L2_FIELD_INTERLACED_TB))
782 cfg |= S3C_CIOCTRL_WEAVE_OUT;
783
784 writel(cfg, ctrl->regs + S3C_CIOCTRL);
785
786 return 0;
787 }
776 根据输出field格式来设定FIMC的扫描方式,
设置为S3C_CISCCTRL_INTERLACE, 如果输入为progressive,则输出半帧数据;如果输入为interlace,输出仅为1/4帧,在s5pv210的datasheet中也注明了这种情况下输入不能为interlace
设置为S3C_CISCCTRL_PROGRESSIVE,如果输入为interlace,则输出半帧数据; 如果输入是progressive,则输出是整帧数据。
781 ~ 782 先了解下V4L2_FIELD_INTERLACED_TB和 V4L2_FIELD_INTERLACED的区别, 设置这个标志后,even field(top field) 被输出而odd field被忽略掉
具体原因我开始猜测了:把even field和odd field交织在一起是会产生毛刺的,所以有时会仅取一场 even field和 odd field之一来代表一帧数据。
这里我比较奇怪的是为什么没有处理V4L2_FIELD_INTERLACED_BT
789 int fimc_hwset_input_rot(struct fimc_control *ctrl, u32 rot, u32 flip)
790 {
791 u32 cfg, val;
792
793 cfg = readl(ctrl->regs + S3C_CITRGFMT);
794 cfg &= ~S3C_CITRGFMT_INROT90_CLOCKWISE;
795
796 val = fimc_mapping_rot_flip(rot, flip);
797
798 if (val & FIMC_ROT)
799 cfg |= S3C_CITRGFMT_INROT90_CLOCKWISE;
800
801 writel(cfg, ctrl->regs + S3C_CITRGFMT);
802
803 return 0;
804 }
796 调用fimc_mapping_rot_flip把 for flip映射为寄存器参数值,但是由于FIMC的input仅仅支持90 degree clockwise rotate,所以算出来的 flip值实际上没有用的,而且FIMC子系统并没有真正调用这个函数,就是一摆设
838 int fimc43_hwset_scaler(struct fimc_control *ctrl, struct fimc_scaler *sc)
839 {
840 u32 cfg = readl(ctrl->regs + S3C_CISCCTRL);
841 u32 cfg_ext = readl(ctrl->regs + S3C_CIEXTEN);
842
843 cfg &= ~(S3C_CISCCTRL_SCALERBYPASS |
844 S3C_CISCCTRL_SCALEUP_H | S3C_CISCCTRL_SCALEUP_V |
845 S3C_CISCCTRL_MAIN_V_RATIO_MASK |
846 S3C_CISCCTRL_MAIN_H_RATIO_MASK |
847 S3C_CISCCTRL_CSCR2Y_WIDE |
848 S3C_CISCCTRL_CSCY2R_WIDE);
849
850 #ifdef CONFIG_VIDEO_FIMC_RANGE_WIDE
851 cfg |= (S3C_CISCCTRL_CSCR2Y_WIDE | S3C_CISCCTRL_CSCY2R_WIDE);
852 #endif
853
854 if (sc->bypass)
855 cfg |= S3C_CISCCTRL_SCALERBYPASS;
856
857 if (sc->scaleup_h)
858 cfg |= S3C_CISCCTRL_SCALEUP_H;
859
860 if (sc->scaleup_v)
861 cfg |= S3C_CISCCTRL_SCALEUP_V;
862
863 cfg |= S3C_CISCCTRL_MAINHORRATIO(sc->main_hratio);
864 cfg |= S3C_CISCCTRL_MAINVERRATIO(sc->main_vratio);
865
866 writel(cfg, ctrl->regs + S3C_CISCCTRL);
867
868 cfg_ext &= ~S3C_CIEXTEN_MAINHORRATIO_EXT_MASK;
869 cfg_ext &= ~S3C_CIEXTEN_MAINVERRATIO_EXT_MASK;
870
871 cfg_ext |= S3C_CIEXTEN_MAINHORRATIO_EXT(sc->main_hratio);
872 cfg_ext |= S3C_CIEXTEN_MAINVERRATIO_EXT(sc->main_vratio);
873
874 writel(cfg_ext, ctrl->regs + S3C_CIEXTEN);
875
876 return 0;
877 }
854 FIMC仅仅在camera input 格式为JPEG时 设置sc->bypass为1, 这是因为在这种情况下图片的尺寸可能大于scaler能处理的最大尺寸
scaler是我认为比较难理解的地方,有很多莫名秒的变量,无用的变量,按我现在得出的结论,scaler部分三星开发人员写了很多垃圾代码,在作者还没撸清的前提下,我就不分析了。
1085 int fimc_hwset_output_rgb(struct fimc_control *ctrl, u32 pixelformat)
1086 {
1087 u32 cfg = readl(ctrl->regs + S3C_CISCCTRL);
1088 cfg &= ~S3C_CISCCTRL_OUTRGB_FMT_RGB_MASK;
1089
1090 if (pixelformat == V4L2_PIX_FMT_RGB32)
1091 cfg |= S3C_CISCCTRL_OUTRGB_FMT_RGB888;
1092 else if (pixelformat == V4L2_PIX_FMT_RGB565)
1093 cfg |= S3C_CISCCTRL_OUTRGB_FMT_RGB565;
1094
1095 writel(cfg, ctrl->regs + S3C_CISCCTRL);
1096
1097 return 0;
1098 }
设置output DMA RGB格式,FIMC硬件支持RGB565, RGB888和RGB666,因为V4L2没有RGB666的说法, 所以代码并不支持RGB666。
火大,看什么代码都不顺眼,为什么三桑要把output DMA RGB格式的设置放到Main-scaler control寄存器,就不能和ouput DMA YUV设置寄存器放一块
1100 int fimc_hwset_ext_rgb(struct fimc_control *ctrl, int enable)
1101 {
1102 u32 cfg = readl(ctrl->regs + S3C_CISCCTRL);
1103 cfg &= ~S3C_CISCCTRL_EXTRGB_EXTENSION;
1104
1105 if (enable)
1106 cfg |= S3C_CISCCTRL_EXTRGB_EXTENSION;
1107
1108 writel(cfg, ctrl->regs + S3C_CISCCTRL);
1109
1110 return 0;
1111 }
RGB565/RGB666 转换为 RGB888的方式,FIMC控制器支持两种转换
1. normal模式,简单的末位填充00, 000
2. extension模式,量化补偿方式,S5PV210 FIMC控制器的做法是用原始数据高位补充新数据的低位
1731 int fimc_hwset_output_addr_style(struct fimc_control *ctrl, u32 pixelformat)
1732 {
1733 u32 cfg = readl(ctrl->regs + S3C_CIDMAPARAM);
1734 cfg &= ~S3C_CIDMAPARAM_W_MODE_MASK;
1735
1736 if (pixelformat == V4L2_PIX_FMT_NV12T)
1737 cfg |= S3C_CIDMAPARAM_W_MODE_64X32;
1738 else
1739 cfg |= S3C_CIDMAPARAM_W_MODE_LINEAR;
1740
1741 writel(cfg, ctrl->regs + S3C_CIDMAPARAM);
1742
1743 return 0;
1744 }
先唠叨一下V4L2_PIX_FMT_NV12T格式,NV12T后面这个T就是Tile的缩写,NV12T就是tile版本的NV12格式,NV12T的图块包含 64 × 32 pixels.
和tile对应的就是linear,所以我们可以称V4L2_PIX_FMT_NV12为linear的NV12。
再看代码就简单了