【轉載】Android S5PV210 fimc驅動分析 - fimc_regs.c

本文系轉載,供本身查閱。非本人做品。
轉載自:http://blog.csdn.net/dahailinan/article/details/7780154

fimc_regs.c是fimc框架操做camera 硬件的接口,fimc框架把全部硬件相關的操做都放在這個文件中 html

  1. 100 int fimc_hwset_camera_source(struct fimc_control *ctrl)  
  2. 101 {  
  3. 102     struct s3c_platform_camera *cam = ctrl->cam;  
  4. 103     u32 cfg = 0;  
  5. 104   
  6. 105     /* for now, we support only ITU601 8 bit mode */  
  7. 106     cfg |= S3C_CISRCFMT_ITU601_8BIT;  
  8. 107     cfg |= cam->order422;  
  9. 108   
  10. 109     if (cam->type == CAM_TYPE_ITU)  
  11. 110         cfg |= cam->fmt;  
  12. 111   
  13. 112     cfg |= S3C_CISRCFMT_SOURCEHSIZE(cam->width);  
  14. 113     cfg |= S3C_CISRCFMT_SOURCEVSIZE(cam->height);  
  15. 114   
  16. 115     writel(cfg, ctrl->regs + S3C_CISRCFMT);  
  17. 116   
  18. 117     return 0;  
  19. 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 app

109 由於cam->fmt也是設置 ITU模式的,因此和106行代碼是冗餘的,不知做者爲何這樣寫 框架

112 ~ 113 設置source水平和垂直像素數目,source能夠是 camera或者FIFO input 函數


  1. 159 int fimc_hwset_output_area_size(struct fimc_control *ctrl, u32 size)  
  2. 160 {  
  3. 161     u32 cfg = 0;  
  4. 162   
  5. 163     cfg = S3C_CITAREA_TARGET_AREA(size);  
  6. 164   
  7. 165     writel(cfg, ctrl->regs + S3C_CITAREA);  
  8. 166   
  9. 167     return 0;  
  10. 168 }  
CITAREA: output DMA target area register

設置output DMA的target大小,這個值並非buffer空間的大小,而是輸出圖像的H_size * V_size 測試


  1. 170 void fimc_wait_disable_capture(struct fimc_control *ctrl)  
  2. 171 {  
  3. 172     unsigned long timeo = jiffies + 20; /* timeout of 100 ms */  
  4. 173     u32 cfg;  
  5. 174   
  6. 175     if (!ctrl || !ctrl->cap ||  
  7. 176             ctrl->cap->fmt.colorspace == V4L2_COLORSPACE_JPEG)  
  8. 177         return;  
  9. 178   
  10. 179     while (time_before(jiffies, timeo)) {  
  11. 180         cfg = readl(ctrl->regs + S3C_CISTATUS);  
  12. 181   
  13. 182         if (0 == (cfg & S3C_CISTATUS_IMGCPTEN))  
  14. 183             break;  
  15. 184   
  16. 185         msleep(10);  
  17. 186     }  
  18. 187   
  19. 188     dev_dbg(ctrl->dev, "IMGCPTEN: Wait time = %d ms\n",  
  20. 189             jiffies_to_msecs(jiffies - timeo + 20));  
  21. 190   
  22. 191     return;  
  23. 192 }  

在disable capture後,能夠調用這個函數,來保證disable capture操做完成 spa

S3C_CISTATUS_IMGCPTEN 標識是否image capture enable的狀態 .net


  1. 194 int fimc_hwset_image_effect(struct fimc_control *ctrl)  
  2. 195 {  
  3. 196     u32 cfg = 0;  
  4. 197   
  5. 198     if (ctrl->fe.ie_on) {  
  6. 199         if (ctrl->fe.ie_after_sc)  
  7. 200             cfg |= S3C_CIIMGEFF_IE_SC_AFTER;  
  8. 201   
  9. 202         cfg |= S3C_CIIMGEFF_FIN(ctrl->fe.fin);  
  10. 203   
  11. 204         if (ctrl->fe.fin == FIMC_EFFECT_FIN_ARBITRARY_CBCR)  
  12. 205             cfg |= S3C_CIIMGEFF_PAT_CB(ctrl->fe.pat_cb) |  
  13. 206                 S3C_CIIMGEFF_PAT_CR(ctrl->fe.pat_cr);  
  14. 207   
  15. 208         cfg |= S3C_CIIMGEFF_IE_ENABLE;  
  16. 209     }  
  17. 210   
  18. 211     writel(cfg, ctrl->regs + S3C_CIIMGEFF);  
  19. 212   
  20. 213     return 0;  
  21. 214 }  

FIMC控制器支持圖片特效處理,所以fimc的V4L2 s_ctl接口提供了特效控制

CIIMGEFF寄存器控制圖片的特效,具體的特效說明,參看s5pv210 datasheet orm


  1.  267 int fimc_hwset_reset(struct fimc_control *ctrl)  
  2.  268 {  
  3.  269     u32 cfg = 0;  
  4.  270   
  5.  271     cfg = readl(ctrl->regs + S3C_CISRCFMT);  
  6.  272     cfg |= S3C_CISRCFMT_ITU601_8BIT;  
  7.  273     writel(cfg, ctrl->regs + S3C_CISRCFMT);  
  8.  274   
  9.  275     /* s/w reset */  
  10.  276     cfg = readl(ctrl->regs + S3C_CIGCTRL);  
  11.  277     cfg |= (S3C_CIGCTRL_SWRST);  
  12.  278     writel(cfg, ctrl->regs + S3C_CIGCTRL);  
  13.  279     mdelay(1);  
  14.  280   
  15.  281     cfg = readl(ctrl->regs + S3C_CIGCTRL);  
  16.  282     cfg &= ~S3C_CIGCTRL_SWRST;  
  17.  283     writel(cfg, ctrl->regs + S3C_CIGCTRL);  
  18.  284   
  19.  285     /* in case of ITU656, CISRCFMT[31] should be 0 */  
  20.  286     if ((ctrl->cap != NULL) && (ctrl->cam->fmt == ITU_656_YCBCR422_8BIT)) {  
  21.  287         cfg = readl(ctrl->regs + S3C_CISRCFMT);  
  22.  288         cfg &= ~S3C_CISRCFMT_ITU601_8BIT;  
  23.  289         writel(cfg, ctrl->regs + S3C_CISRCFMT);  
  24.  290     }  
  25.  291   
  26.  292     fimc_reset_cfg(ctrl);  
  27.  293   
  28.  294     return 0;  
  29.  295 }  

FIMC軟件復位過程:

S5PV210 datasheet推薦使用以下初始化序列 htm

對於ITU601: ITU601_656n置1 -> SwRst置1 -> SwRst置0

對於ITU656: ITU601_656n置1 -> SwRst置1 -> SwRst置0 -> ITU601_656置0


  1.  335 int fimc_hwset_camera_offset(struct fimc_control *ctrl)  
  2.  336 {  
  3.  337     struct s3c_platform_camera *cam = ctrl->cam;  
  4.  338     struct v4l2_rect *rect = &cam->window;  
  5.  339     u32 cfg, h1, h2, v1, v2;  
  6.  340   
  7.  341     if (!cam) {  
  8.  342         fimc_err("%s: no active camera\n", __func__);  
  9.  343         return -ENODEV;  
  10.  344     }  
  11.  345   
  12.  346     h1 = rect->left;  
  13.  347     h2 = cam->width - rect->width - rect->left;  
  14.  348     v1 = rect->top;  
  15.  349     v2 = cam->height - rect->height - rect->top;  
  16.  350   
  17.  351     cfg = readl(ctrl->regs + S3C_CIWDOFST);  
  18.  352     cfg &= ~(S3C_CIWDOFST_WINHOROFST_MASK | S3C_CIWDOFST_WINVEROFST_MASK);  
  19.  353     cfg |= S3C_CIWDOFST_WINHOROFST(h1);  
  20.  354     cfg |= S3C_CIWDOFST_WINVEROFST(v1);  
  21.  355     cfg |= S3C_CIWDOFST_WINOFSEN;  
  22.  356     writel(cfg, ctrl->regs + S3C_CIWDOFST);  
  23.  357   
  24.  358     cfg = 0;  
  25.  359     cfg |= S3C_CIWDOFST2_WINHOROFST2(h2);  
  26.  360     cfg |= S3C_CIWDOFST2_WINVEROFST2(v2);  
  27.  361     writel(cfg, ctrl->regs + S3C_CIWDOFST2);  
  28.  362   
  29.  363     return 0;  
  30.  364 }  

h1: Window Horizon Offset, v1: Window Vertical Offset

h2: Window Horizon Offset2, v2: Window Vertical Offset2

下面這個圖很明瞭的解釋了這幾個座標概念

h1, h2, v1, v2這四個座標就定義了crop的範圍,上圖右邊部分就是crop結果


 

  1. 366 int fimc_hwset_camera_polarity(struct fimc_control *ctrl)  
  2. 367 {  
  3. 368     struct s3c_platform_camera *cam = ctrl->cam;  
  4. 369     u32 cfg;  
  5. 370   
  6. 371     if (!cam) {  
  7. 372         fimc_err("%s: no active camera\n", __func__);  
  8. 373         return -ENODEV;  
  9. 374     }  
  10. 375   
  11. 376     cfg = readl(ctrl->regs + S3C_CIGCTRL);  
  12. 377   
  13. 378     cfg &= ~(S3C_CIGCTRL_INVPOLPCLK | S3C_CIGCTRL_INVPOLVSYNC |  
  14. 379          S3C_CIGCTRL_INVPOLHREF | S3C_CIGCTRL_INVPOLHSYNC);  
  15. 380   
  16. 381     if (cam->inv_pclk)  
  17. 382         cfg |= S3C_CIGCTRL_INVPOLPCLK;  
  18. 383   
  19. 384     if (cam->inv_vsync)  
  20. 385         cfg |= S3C_CIGCTRL_INVPOLVSYNC;  
  21. 386   
  22. 387     if (cam->inv_href)  
  23. 388         cfg |= S3C_CIGCTRL_INVPOLHREF;  
  24. 389   
  25. 390     if (cam->inv_hsync)  
  26. 391         cfg |= S3C_CIGCTRL_INVPOLHSYNC;  
  27. 392   
  28. 393     writel(cfg, ctrl->regs + S3C_CIGCTRL);  
  29. 394   
  30. 395     return 0;  
  31. 396 }  

camera sensor輸出到fimc控制器的幾個信號: pixclk, href(hsync), vsync。 sensor可能會設置這幾個信號的極性,所以FIMC控制器端也須要和這個信號的極性匹配

具體配置須要參考sensor的輸出,通常狀況下無極性翻轉。

對於BT656信號來講,只須要考慮pixclk的極性。


  1. 434 int fimc43_hwset_camera_type(struct fimc_control *ctrl)  
  2.  435 {  
  3.  436     struct s3c_platform_camera *cam = ctrl->cam;  
  4.  437     u32 cfg;  
  5.  438      
  6.  439     if (!cam) {  
  7.  440         fimc_err("%s: no active camera\n", __func__);  
  8.  441         return -ENODEV;  
  9.  442     }  
  10.  443   
  11.  444     cfg = readl(ctrl->regs + S3C_CIGCTRL);  
  12.  445     cfg &= ~(S3C_CIGCTRL_TESTPATTERN_MASK | S3C_CIGCTRL_SELCAM_ITU_MASK |  
  13.  446         S3C_CIGCTRL_SELCAM_MIPI_MASK | S3C_CIGCTRL_SELCAM_FIMC_MASK |  
  14.  447         S3C_CIGCTRL_SELWB_CAMIF_MASK);  
  15.  448   
  16.  449     /* Interface selection */  
  17.  450     if (cam->id == CAMERA_WB) {  
  18.  451         cfg |= S3C_CIGCTRL_SELWB_CAMIF_WRITEBACK;  
  19.  452     } else if (cam->type == CAM_TYPE_MIPI) {  
  20.  453         cfg |= S3C_CIGCTRL_SELCAM_FIMC_MIPI;  
  21.  454   
  22.  455         /* C110/V210 Support only MIPI A support */  
  23.  456         cfg |= S3C_CIGCTRL_SELCAM_MIPI_A;  
  24.  457   
  25.  458         /* FIXME: Temporary MIPI CSIS Data 32 bit aligned */  
  26.  459         if (ctrl->cap->fmt.pixelformat == V4L2_PIX_FMT_JPEG)  
  27.  460             writel((MIPI_USER_DEF_PACKET_1 | (0x1 << 8)),  
  28.  461                     ctrl->regs + S3C_CSIIMGFMT);  
  29.  462         else  
  30.  463             writel(cam->fmt | (0x1 << 8),  
  31.  464                     ctrl->regs + S3C_CSIIMGFMT);  
  32.  465     } else if (cam->type == CAM_TYPE_ITU) {  
  33.  466         if (cam->id == CAMERA_PAR_A)  
  34.  467             cfg |= S3C_CIGCTRL_SELCAM_ITU_A;  
  35.  468         else  
  36.  469             cfg |= S3C_CIGCTRL_SELCAM_ITU_B;  
  37.  470         /* switch to ITU interface */  
  38.  471         cfg |= S3C_CIGCTRL_SELCAM_FIMC_ITU;  
  39.  472     } else {  
  40.  473         fimc_err("%s: invalid camera bus type selected\n", __func__);  
  41.  474         return -EINVAL;  
  42.  475     }  
  43.  476   
  44.  477     writel(cfg, ctrl->regs + S3C_CIGCTRL);  
  45.  478   
  46.  479     return 0;  
  47.  480 }  


FIMC提供了三個物理camera接口:

兩個ITU類型的:Camera A(GPE0_0 --- GPE1_4)和Camera B(GPJ0_0 --- GPJ1_4),

一個MIPI類型的: Camera C

465 ~ 469 選擇使用哪一個物理camera接口,這個須要查看原理圖來預設cam->id。


  1. 522 int fimc_hwset_jpeg_mode(struct fimc_control *ctrl, bool enable)  
  2. 523 {  
  3. 524     u32 cfg;  
  4. 525     cfg = readl(ctrl->regs + S3C_CIGCTRL);  
  5. 526   
  6. 527     if (enable)  
  7. 528         cfg |= S3C_CIGCTRL_CAM_JPEG;  
  8. 529     else  
  9. 530         cfg &= ~S3C_CIGCTRL_CAM_JPEG;  
  10. 531   
  11. 532     writel(cfg, ctrl->regs + S3C_CIGCTRL);  
  12. 533   
  13. 534     return 0;  
  14. 535 }  
對於ITU601輸入若是輸入數據是8bit jpeg格式(壓縮格式),那麼就要設置JPEG標誌位,這時FIMC會忽略scaler和轉換。

對於BT656來講只能是YUYV格式


  1. 537 int fimc_hwset_output_size(struct fimc_control *ctrl, int width, int height)  
  2. 538 {  
  3. 539     u32 cfg = readl(ctrl->regs + S3C_CITRGFMT);  
  4. 540  
  5. 541     printk(KERN_ERR "%s: width(%d), height(%d)\n", __func__, width, height);  
  6. 542  
  7. 543     cfg &= ~(S3C_CITRGFMT_TARGETH_MASK | S3C_CITRGFMT_TARGETV_MASK);  
  8. 544  
  9. 545     cfg |= S3C_CITRGFMT_TARGETHSIZE(width);  
  10. 546     cfg |= S3C_CITRGFMT_TARGETVSIZE(height);  
  11. 547  
  12. 548     writel(cfg, ctrl->regs + S3C_CITRGFMT);  
  13. 549  
  14. 550     return 0;  
  15. 551 }  

545 ~ 546 是FIMC輸出圖像的width和height size, 他們不該該大於camera source height size和 source width size,固然這並不意味着FIMC的scaler沒有放大功能,FIMC的scaler有放大功能

,可是放大後的尺寸不能超過source Hsize和souce Vsize


  1. 553 int fimc_hwset_output_colorspace(struct fimc_control *ctrl, u32 pixelformat)  
  2. 554 {  
  3. 555     struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev);  
  4. 556     u32 cfg;  
  5. 557   
  6. 558     if (pdata->hw_ver != 0x40) {  
  7. 559         if (pixelformat == V4L2_PIX_FMT_YUV444) {  
  8. 560             cfg = readl(ctrl->regs + S3C_CIEXTEN);  
  9. 561             cfg |= S3C_CIEXTEN_YUV444_OUT;  
  10. 562             writel(cfg, ctrl->regs + S3C_CIEXTEN);  
  11. 563   
  12. 564             return 0;  
  13. 565         } else {  
  14. 566             cfg = readl(ctrl->regs + S3C_CIEXTEN);  
  15. 567             cfg &= ~S3C_CIEXTEN_YUV444_OUT;  
  16. 568             writel(cfg, ctrl->regs + S3C_CIEXTEN);  
  17. 569         }  
  18. 570     }  
  19. 571   
  20. 572     cfg = readl(ctrl->regs + S3C_CITRGFMT);  
  21. 573     cfg &= ~S3C_CITRGFMT_OUTFORMAT_MASK;  
  22. 574   
  23. 575     switch (pixelformat) {  
  24. 576     case V4L2_PIX_FMT_JPEG:  
  25. 577         break;  
  26. 578     case V4L2_PIX_FMT_RGB565: /* fall through */  
  27. 579     case V4L2_PIX_FMT_RGB32:  
  28. 580         cfg |= S3C_CITRGFMT_OUTFORMAT_RGB;  
  29. 581         break;  
  30. 582   
  31. 583     case V4L2_PIX_FMT_YUYV:     /* fall through */  
  32. 584     case V4L2_PIX_FMT_UYVY:     /* fall through */  
  33. 585     case V4L2_PIX_FMT_VYUY:     /* fall through */  
  34. 586     case V4L2_PIX_FMT_YVYU:  
  35. 587         cfg |= S3C_CITRGFMT_OUTFORMAT_YCBCR422_1PLANE;  
  36. 588         break;  
  37. 589   
  38. 590     case V4L2_PIX_FMT_NV16:     /* fall through */  
  39. 591     case V4L2_PIX_FMT_NV61:     /* fall through */  
  40. 592     case V4L2_PIX_FMT_YUV422P:  
  41. 593         cfg |= S3C_CITRGFMT_OUTFORMAT_YCBCR422;  
  42. 594         break;  
  43. 595   
  44. 596     case V4L2_PIX_FMT_YUV420:   /* fall through */  
  45. 597     case V4L2_PIX_FMT_NV12:     /* fall through */  
  46. 598     case V4L2_PIX_FMT_NV12T:    /* fall through */  
  47. 599     case V4L2_PIX_FMT_NV21:  
  48. 600         cfg |= S3C_CITRGFMT_OUTFORMAT_YCBCR420;  
  49. 601         break;  
  50. 602   
  51. 603     default:  
  52. 604         fimc_err("%s: invalid pixel format\n", __func__);  
  53. 605         break;  
  54. 606     }  
  55. 607   
  56. 608     writel(cfg, ctrl->regs + S3C_CITRGFMT);  
  57. 609   
  58. 610     return 0;  
  59. 611 }  

設置FIMC的輸出顏色格式,FIMC支持顏色空間轉換,應用程序或測試程序能夠經過S_FMT ioctl指定但願的輸出顏色格式


  1. 615 int fimc_hwset_output_rot_flip(struct fimc_control *ctrl, u32 rot, u32 flip)  
  2. 616 {             
  3. 617     u32 cfg, val;  
  4. 618           
  5. 619     cfg = readl(ctrl->regs + S3C_CITRGFMT);  
  6. 620     cfg &= ~S3C_CITRGFMT_FLIP_MASK;  
  7. 621     cfg &= ~S3C_CITRGFMT_OUTROT90_CLOCKWISE;  
  8. 622       
  9. 623     val = fimc_mapping_rot_flip(rot, flip);  
  10. 624           
  11. 625     if (val & FIMC_ROT)  
  12. 626         cfg |= S3C_CITRGFMT_OUTROT90_CLOCKWISE;  
  13. 627           
  14. 628     if (val & FIMC_XFLIP)  
  15. 629         cfg |= S3C_CITRGFMT_FLIP_X_MIRROR;  
  16. 630   
  17. 631     if (val & FIMC_YFLIP)  
  18. 632         cfg |= S3C_CITRGFMT_FLIP_Y_MIRROR;  
  19. 633           
  20. 634     writel(cfg, ctrl->regs + S3C_CITRGFMT);  
  21. 635   
  22. 636     return 0;  
  23. 637 }      


FIMC控制器支持圖片的翻轉,應用層能夠經過s_ctrl ioctl來設置翻轉


  1.  690 int fimc_hwset_output_address(struct fimc_control *ctrl,  
  2.  691                   struct fimc_buf_set *bs, int id)  
  3.  692 {  
  4.  693     printk(KERN_ERR "%s: FIMC_ADDR_Y=0x%x, FIMC_ADDR_CB=0x%x, FIMC_ADDR_CR=0x%x\n",  
  5.  694             __func__, bs->base[FIMC_ADDR_Y], bs->base[FIMC_ADDR_CB],  
  6.  695             bs->base[FIMC_ADDR_CR]);  
  7.  696     writel(bs->base[FIMC_ADDR_Y], ctrl->regs + S3C_CIOYSA(id));  
  8.  697     writel(bs->base[FIMC_ADDR_CB], ctrl->regs + S3C_CIOCBSA(id));  
  9.  698     writel(bs->base[FIMC_ADDR_CR], ctrl->regs + S3C_CIOCRSA(id));  
  10.  699   
  11.  700     return 0;  
  12.  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


  1. 703 int fimc_hwset_output_yuv(struct fimc_control *ctrl, u32 pixelformat)  
  2.  704 {  
  3.  705     u32 cfg;  
  4.  706   
  5.  707     cfg = readl(ctrl->regs + S3C_CIOCTRL);  
  6.  708     cfg &= ~(S3C_CIOCTRL_ORDER2P_MASK | S3C_CIOCTRL_ORDER422_MASK |  
  7.  709         S3C_CIOCTRL_YCBCR_PLANE_MASK);  
  8.  710   
  9.  711     switch (pixelformat) {  
  10.  712     /* 1 plane formats */  
  11.  713     case V4L2_PIX_FMT_YUYV:  
  12.  714         cfg |= S3C_CIOCTRL_ORDER422_YCBYCR;  
  13.  715         break;  
  14.  716   
  15.  717     case V4L2_PIX_FMT_UYVY:  
  16.  718         cfg |= S3C_CIOCTRL_ORDER422_CBYCRY;  
  17.  719         break;  
  18.  720   
  19.  721     case V4L2_PIX_FMT_VYUY:  
  20.  722         cfg |= S3C_CIOCTRL_ORDER422_CRYCBY;  
  21.  723         break;  
  22.  724   
  23.  725     case V4L2_PIX_FMT_YVYU:  
  24.  726         cfg |= S3C_CIOCTRL_ORDER422_YCRYCB;  
  25.  727         break;  
  26.  728   
  27.  729     /* 2 plane formats */  
  28.  730     case V4L2_PIX_FMT_NV12:     /* fall through */  
  29.  731     case V4L2_PIX_FMT_NV12T:    /* fall through */  
  30.  732     case V4L2_PIX_FMT_NV16:  
  31.  733         cfg |= S3C_CIOCTRL_ORDER2P_LSB_CBCR;  
  32.  734         cfg |= S3C_CIOCTRL_YCBCR_2PLANE;  
  33.  735         break;  
  34.  736   
  35.  737     case V4L2_PIX_FMT_NV21:     /* fall through */  
  36.  738     case V4L2_PIX_FMT_NV61:  
  37.  739         cfg |= S3C_CIOCTRL_ORDER2P_LSB_CRCB;  
  38.  740         cfg |= S3C_CIOCTRL_YCBCR_2PLANE;  
  39.  741         break;  
  40.  742   
  41.  743     /* 3 plane formats */  
  42.  744     case V4L2_PIX_FMT_YUV422P:  /* fall through */  
  43.  745     case V4L2_PIX_FMT_YUV420:  
  44.  746         cfg |= S3C_CIOCTRL_YCBCR_3PLANE;  
  45.  747         break;  
  46.  748     }  
  47.  749   
  48.  750     writel(cfg, ctrl->regs + S3C_CIOCTRL);  
  49.  751   
  50.  752     return 0;  
  51.  753 }  

YUV有不少種格式,能夠分爲兩大類: 打包格式(packed)和平面格式(planer),打包格式是YUV份量放在一個數組中,相鄰的幾個份量組成一個像素的。然後者使用兩個或者三個份量 數組,兩個份量數組是將Y和UV份量分開,三個份量數組則是將YUV份量放在不一樣的數組中


  1. 755 int fimc_hwset_output_scan(struct fimc_control *ctrl,  
  2. 756                struct v4l2_pix_format *fmt)  
  3. 757 {  
  4. 758     struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev);  
  5. 759     u32 cfg;  
  6. 760   
  7. 761     /* nothing to do: FIMC40 not supported interlaced and weave output */  
  8. 762     if (pdata->hw_ver == 0x40)  
  9. 763         return 0;  
  10. 764   
  11. 765     cfg = readl(ctrl->regs + S3C_CISCCTRL);  
  12. 766     cfg &= ~S3C_CISCCTRL_SCAN_MASK;  
  13. 767   
  14. 768     if (fmt->field == V4L2_FIELD_INTERLACED ||  
  15. 769         fmt->field == V4L2_FIELD_INTERLACED_TB) {  
  16. 770         cfg |= S3C_CISCCTRL_INTERLACE;  
  17. 771         printk(KERN_ERR "%s: set S3C_CISCCTRL_INTERLACE\n", __func__);  
  18. 772     }  
  19. 773     else  
  20. 774         cfg |= S3C_CISCCTRL_PROGRESSIVE;  
  21. 775   
  22. 776     writel(cfg, ctrl->regs + S3C_CISCCTRL);  
  23. 777   
  24. 778     cfg = readl(ctrl->regs + S3C_CIOCTRL);  
  25. 779     cfg &= ~S3C_CIOCTRL_WEAVE_MASK;  
  26. 780   
  27. 781     if ((ctrl->cap) && (fmt->field == V4L2_FIELD_INTERLACED_TB))  
  28. 782         cfg |= S3C_CIOCTRL_WEAVE_OUT;  
  29. 783   
  30. 784     writel(cfg, ctrl->regs + S3C_CIOCTRL);  
  31. 785   
  32. 786     return 0;  
  33. 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


  1. 789 int fimc_hwset_input_rot(struct fimc_control *ctrl, u32 rot, u32 flip)  
  2. 790 {         
  3. 791     u32 cfg, val;  
  4. 792           
  5. 793     cfg = readl(ctrl->regs + S3C_CITRGFMT);  
  6. 794     cfg &= ~S3C_CITRGFMT_INROT90_CLOCKWISE;  
  7. 795           
  8. 796     val = fimc_mapping_rot_flip(rot, flip);  
  9. 797               
  10. 798     if (val & FIMC_ROT)  
  11. 799         cfg |= S3C_CITRGFMT_INROT90_CLOCKWISE;  
  12. 800               
  13. 801     writel(cfg, ctrl->regs + S3C_CITRGFMT);  
  14. 802   
  15. 803     return 0;  
  16. 804 }  

796 調用fimc_mapping_rot_flip把 for flip映射爲寄存器參數值,可是因爲FIMC的input僅僅支持90 degree clockwise rotate,因此算出來的 flip值實際上沒有用的,並且FIMC子系統並無真正調用這個函數,就是一擺設


  1. 838 int fimc43_hwset_scaler(struct fimc_control *ctrl, struct fimc_scaler *sc)  
  2.  839 {  
  3.  840     u32 cfg = readl(ctrl->regs + S3C_CISCCTRL);  
  4.  841     u32 cfg_ext = readl(ctrl->regs + S3C_CIEXTEN);  
  5.  842   
  6.  843     cfg &= ~(S3C_CISCCTRL_SCALERBYPASS |  
  7.  844         S3C_CISCCTRL_SCALEUP_H | S3C_CISCCTRL_SCALEUP_V |  
  8.  845         S3C_CISCCTRL_MAIN_V_RATIO_MASK |  
  9.  846         S3C_CISCCTRL_MAIN_H_RATIO_MASK |  
  10.  847         S3C_CISCCTRL_CSCR2Y_WIDE |  
  11.  848         S3C_CISCCTRL_CSCY2R_WIDE);  
  12.  849           
  13.  850 #ifdef CONFIG_VIDEO_FIMC_RANGE_WIDE  
  14.  851     cfg |= (S3C_CISCCTRL_CSCR2Y_WIDE | S3C_CISCCTRL_CSCY2R_WIDE);  
  15.  852 #endif  
  16.  853   
  17.  854     if (sc->bypass)  
  18.  855         cfg |= S3C_CISCCTRL_SCALERBYPASS;  
  19.  856           
  20.  857     if (sc->scaleup_h)  
  21.  858         cfg |= S3C_CISCCTRL_SCALEUP_H;  
  22.  859           
  23.  860     if (sc->scaleup_v)  
  24.  861         cfg |= S3C_CISCCTRL_SCALEUP_V;  
  25.  862           
  26.  863     cfg |= S3C_CISCCTRL_MAINHORRATIO(sc->main_hratio);  
  27.  864     cfg |= S3C_CISCCTRL_MAINVERRATIO(sc->main_vratio);  
  28.  865       
  29.  866     writel(cfg, ctrl->regs + S3C_CISCCTRL);  
  30.  867       
  31.  868     cfg_ext &= ~S3C_CIEXTEN_MAINHORRATIO_EXT_MASK;  
  32.  869     cfg_ext &= ~S3C_CIEXTEN_MAINVERRATIO_EXT_MASK;  
  33.  870       
  34.  871     cfg_ext |= S3C_CIEXTEN_MAINHORRATIO_EXT(sc->main_hratio);  
  35.  872     cfg_ext |= S3C_CIEXTEN_MAINVERRATIO_EXT(sc->main_vratio);  
  36.  873       
  37.  874     writel(cfg_ext, ctrl->regs + S3C_CIEXTEN);  
  38.  875       
  39.  876     return 0;  
  40.  877 }     

854 FIMC僅僅在camera input 格式爲JPEG時 設置sc->bypass爲1, 這是由於在這種狀況下圖片的尺寸可能大於scaler能處理的最大尺寸

scaler是我認爲比較難理解的地方,有不少莫名秒的變量,無用的變量,按我如今得出的結論,scaler部分三星開發人員寫了不少垃圾代碼,在做者還沒擼清的前提下,我就不分析了。


  1. 1085 int fimc_hwset_output_rgb(struct fimc_control *ctrl, u32 pixelformat)  
  2. 1086 {  
  3. 1087     u32 cfg = readl(ctrl->regs + S3C_CISCCTRL);  
  4. 1088     cfg &= ~S3C_CISCCTRL_OUTRGB_FMT_RGB_MASK;  
  5. 1089  
  6. 1090     if (pixelformat == V4L2_PIX_FMT_RGB32)  
  7. 1091         cfg |= S3C_CISCCTRL_OUTRGB_FMT_RGB888;  
  8. 1092     else if (pixelformat == V4L2_PIX_FMT_RGB565)  
  9. 1093         cfg |= S3C_CISCCTRL_OUTRGB_FMT_RGB565;  
  10. 1094  
  11. 1095     writel(cfg, ctrl->regs + S3C_CISCCTRL);  
  12. 1096  
  13. 1097     return 0;  
  14. 1098 }  

設置output DMA RGB格式,FIMC硬件支持RGB565, RGB888和RGB666,由於V4L2沒有RGB666的說法, 因此代碼並不支持RGB666。

火大,看什麼代碼都不順眼,爲何三桑要把output DMA RGB格式的設置放到Main-scaler control寄存器,就不能和ouput DMA YUV設置寄存器放一塊

  1. 1100 int fimc_hwset_ext_rgb(struct fimc_control *ctrl, int enable)  
  2. 1101 {  
  3. 1102     u32 cfg = readl(ctrl->regs + S3C_CISCCTRL);  
  4. 1103     cfg &= ~S3C_CISCCTRL_EXTRGB_EXTENSION;  
  5. 1104   
  6. 1105     if (enable)  
  7. 1106         cfg |= S3C_CISCCTRL_EXTRGB_EXTENSION;  
  8. 1107   
  9. 1108     writel(cfg, ctrl->regs + S3C_CISCCTRL);  
  10. 1109       
  11. 1110     return 0;  
  12. 1111 }  

RGB565/RGB666 轉換爲 RGB888的方式,FIMC控制器支持兩種轉換

1. normal模式,簡單的末位填充00, 000

2. extension模式,量化補償方式,S5PV210 FIMC控制器的作法是用原始數據高位補充新數據的低位


  1. 1731 int fimc_hwset_output_addr_style(struct fimc_control *ctrl, u32 pixelformat)  
  2. 1732 {  
  3. 1733     u32 cfg = readl(ctrl->regs + S3C_CIDMAPARAM);  
  4. 1734     cfg &= ~S3C_CIDMAPARAM_W_MODE_MASK;  
  5. 1735  
  6. 1736     if (pixelformat == V4L2_PIX_FMT_NV12T)  
  7. 1737         cfg |= S3C_CIDMAPARAM_W_MODE_64X32;  
  8. 1738     else  
  9. 1739         cfg |= S3C_CIDMAPARAM_W_MODE_LINEAR;  
  10. 1740  
  11. 1741     writel(cfg, ctrl->regs + S3C_CIDMAPARAM);  
  12. 1742  
  13. 1743     return 0;  
  14. 1744 }    


先嘮叨一下V4L2_PIX_FMT_NV12T格式,NV12T後面這個T就是Tile的縮寫,NV12T就是tile版本的NV12格式,NV12T的圖塊包含 64 × 32 pixels.

和tile對應的就是linear,因此咱們能夠稱V4L2_PIX_FMT_NV12爲linear的NV12。

再看代碼就簡單了

相關文章
相關標籤/搜索