Android S5PV210 fimc驱动分析 - fimc_regs.c

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。

再看代码就简单了






  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值