Android S5PV210 fimc驱动分析

fimc_capture.c在FIMC系统中的位置,网上偷来的一幅图片

http://blog.csdn.net/kickxxx/article/details/7733482

[cpp] view plaincopy
 
  1. 43 static const struct v4l2_fmtdesc capture_fmts[] = {  
  2.  44     {  
  3.  45         .index      = 0,  
  4.  46         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,  
  5.  47         .flags      = FORMAT_FLAGS_PACKED,  
  6.  48         .description    = "RGB-5-6-5",  
  7.  49         .pixelformat    = V4L2_PIX_FMT_RGB565,  
  8.  50     }, {  
  9.  51         .index      = 1,  
  10.  52         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,  
  11.  53         .flags      = FORMAT_FLAGS_PACKED,  
  12.  54         .description    = "RGB-8-8-8, unpacked 24 bpp",  
  13.  55         .pixelformat    = V4L2_PIX_FMT_RGB32,  
  14.  56     }, {  
  15.  57         .index      = 2,  
  16.  58         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,  
  17.  59         .flags      = FORMAT_FLAGS_PACKED,  
  18.  60         .description    = "YUV 4:2:2 packed, YCbYCr",  
  19.  61         .pixelformat    = V4L2_PIX_FMT_YUYV,  
  20.  62     }, {  
  21.  63         .index      = 3,  
  22.  64         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,  
  23.  65         .flags      = FORMAT_FLAGS_PACKED,  
  24.  66         .description    = "YUV 4:2:2 packed, CbYCrY",  
  25.  67         .pixelformat    = V4L2_PIX_FMT_UYVY,  
  26.  68     }, {  
  27.  69         .index      = 4,  
  28.  70         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,  
  29.  71         .flags      = FORMAT_FLAGS_PACKED,  
  30.  72         .description    = "YUV 4:2:2 packed, CrYCbY",  
  31.  73         .pixelformat    = V4L2_PIX_FMT_VYUY,  
  32.  74     }, {  
  33.  75         .index      = 5,  
  34.  76         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,  
  35.  77         .flags      = FORMAT_FLAGS_PACKED,  
  36.  78         .description    = "YUV 4:2:2 packed, YCrYCb",  
  37.  79         .pixelformat    = V4L2_PIX_FMT_YVYU,  
  38.  80     }, {  
  39.  81         .index      = 6,  
  40.  82         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,  
  41.  83         .flags      = FORMAT_FLAGS_PLANAR,  
  42.  84         .description    = "YUV 4:2:2 planar, Y/Cb/Cr",  
  43. 85         .pixelformat    = V4L2_PIX_FMT_YUV422P,  
  44.  86     }, {  
  45.  87         .index      = 7,  
  46.  88         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,  
  47.  89         .flags      = FORMAT_FLAGS_PLANAR,  
  48.  90         .description    = "YUV 4:2:0 planar, Y/CbCr",  
  49.  91         .pixelformat    = V4L2_PIX_FMT_NV12,  
  50.  92     }, {  
  51.  93         .index      = 8,  
  52.  94         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,  
  53.  95         .flags      = FORMAT_FLAGS_PLANAR,  
  54.  96         .description    = "YUV 4:2:0 planar, Y/CbCr, Tiled",  
  55.  97         .pixelformat    = V4L2_PIX_FMT_NV12T,  
  56.  98     }, {  
  57.  99         .index      = 9,  
  58. 100         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,  
  59. 101         .flags      = FORMAT_FLAGS_PLANAR,  
  60. 102         .description    = "YUV 4:2:0 planar, Y/CrCb",  
  61. 103         .pixelformat    = V4L2_PIX_FMT_NV21,  
  62. 104     }, {  
  63. 105         .index      = 10,  
  64. 106         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,  
  65. 107         .flags      = FORMAT_FLAGS_PLANAR,  
  66. 108         .description    = "YUV 4:2:2 planar, Y/CbCr",  
  67. 109         .pixelformat    = V4L2_PIX_FMT_NV16,  
  68. 110     }, {  
  69. 111         .index      = 11,  
  70. 112         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,  
  71. 113         .flags      = FORMAT_FLAGS_PLANAR,  
  72. 114         .description    = "YUV 4:2:2 planar, Y/CrCb",  
  73. 115         .pixelformat    = V4L2_PIX_FMT_NV61,  
  74. 116     }, {  
  75. 117         .index      = 12,  
  76. 118         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,  
  77. 119         .flags      = FORMAT_FLAGS_PLANAR,  
  78. 120         .description    = "YUV 4:2:0 planar, Y/Cb/Cr",  
  79. 121         .pixelformat    = V4L2_PIX_FMT_YUV420,  
  80. 122     }, {  
  81. 123         .index      = 13,  
  82. 124         .type       = V4L2_BUF_TYPE_VIDEO_CAPTURE,  
  83. 125         .flags      = FORMAT_FLAGS_ENCODED,  
  84. 126         .description    = "Encoded JPEG bitstream",  
  85. 127         .pixelformat    = V4L2_PIX_FMT_JPEG,  
  86. 128     },  
  87. 129 };  

这个列表列出了FIMC支持的capture格式,app可以通过vidioc_s_fmt设置capture的输出格式,capture的输出格式必须在上面的列表中

这里的flags标志位并不符合V4L2标准,V4L2只支持一种标志:V4L2_FMT_FLAG_COMPRESSED。

samsung扩展了flags标志:

FORMAT_FLAGS_PACKED: 图片的像素点分量放在一同一个buffer中

FORMAT_FLAGS_PLANAR:图片像素的分量放在不同的buffer中

FORMAT_FLAGS_ENCODED:图片数据编码存储,如jpeg格式

[cpp] view plaincopy
 
  1. 131 static const struct v4l2_queryctrl fimc_controls[] = {  
  2. 132     {  
  3. 133         .id = V4L2_CID_ROTATION,  
  4. 134         .type = V4L2_CTRL_TYPE_BOOLEAN,  
  5. 135         .name = "Roataion",  
  6. 136         .minimum = 0,  
  7. 137         .maximum = 270,  
  8. 138         .step = 90,  
  9. 139         .default_value = 0,  
  10. 140     }, {  
  11. 141         .id = V4L2_CID_HFLIP,  
  12. 142         .type = V4L2_CTRL_TYPE_BOOLEAN,  
  13. 143         .name = "Horizontal Flip",  
  14. 144         .minimum = 0,  
  15. 145         .maximum = 1,  
  16. 146         .step = 1,  
  17. 147         .default_value = 0,  
  18. 148     }, {  
  19. 149         .id = V4L2_CID_VFLIP,  
  20. 150         .type = V4L2_CTRL_TYPE_BOOLEAN,  
  21. 151         .name = "Vertical Flip",  
  22. 152         .minimum = 0,  
  23. 153         .maximum = 1,  
  24. 154         .step = 1,  
  25. 155         .default_value = 0,  
  26. 156     }, {  
  27. 157         .id = V4L2_CID_PADDR_Y,  
  28. 158         .type = V4L2_CTRL_TYPE_BOOLEAN,  
  29. 159         .name = "Physical address Y",  
  30. 160         .minimum = 0,  
  31. 161         .maximum = 1,  
  32. 162         .step = 1,  
  33. 163         .default_value = 0,  
  34. 164         .flags = V4L2_CTRL_FLAG_READ_ONLY,  
  35. 165     }, {  
  36. 166         .id = V4L2_CID_PADDR_CB,  
  37. 167         .type = V4L2_CTRL_TYPE_BOOLEAN,  
  38. 168         .name = "Physical address Cb",  
  39. 169         .minimum = 0,  
  40. 170         .maximum = 1,  
  41. 171         .step = 1,  
  42. 172         .default_value = 0,  
  43. 173         .flags = V4L2_CTRL_FLAG_READ_ONLY,  
  44. 174     }, {  
  45. 175         .id = V4L2_CID_PADDR_CR,  
  46. 176         .type = V4L2_CTRL_TYPE_BOOLEAN,  
  47. 177         .name = "Physical address Cr",  
  48. 178         .minimum = 0,  
  49. 179         .maximum = 1,  
  50. 180         .step = 1,  
  51. 181         .default_value = 0,  
  52. 182         .flags = V4L2_CTRL_FLAG_READ_ONLY,  
  53. 183     }, {  
  54. 184         .id = V4L2_CID_PADDR_CBCR,  
  55. 185         .type = V4L2_CTRL_TYPE_BOOLEAN,  
  56. 186         .name = "Physical address CbCr",  
  57. 187         .minimum = 0,  
  58. 188         .maximum = 1,  
  59. 189         .step = 1,  
  60. 190         .default_value = 0,  
  61. 191         .flags = V4L2_CTRL_FLAG_READ_ONLY,  
  62. 192     },  
  63. 193 };  

定义了FIMC支持的ctrl,后面四个ctrl: V4L2_CID_PADDR_Y, V4L2_CID_PADDR_CB, V4L2_CID_PADDR_CR, V4L2_CID_PADDR_CBCR 是samsung fimc私有的ctrl id, 用来获取分量的物理起始地址。

[cpp] view plaincopy
 
  1. 201 static int fimc_camera_init(struct fimc_control *ctrl)  
  2. 202 {  
  3. 203     int ret;  
  4. 204   
  5. 205     fimc_dbg("%s ", __func__);  
  6. 206   
  7. 207     /* do nothing if already initialized */  
  8. 208     if (ctrl->cam->initialized)  
  9. 209         return 0;  
  10. 210   
  11. 211     /* enable camera power if needed */  
  12. 212     if (ctrl->cam->cam_power)  
  13. 213         ctrl->cam->cam_power(1);  
  14. 214   
  15. 215     /* subdev call for init */  
  16. 216     ret = subdev_call(ctrl, core, init, 0);  
  17. 217     if (ret == -ENOIOCTLCMD) {  
  18. 218         fimc_err("%s: init subdev api not supported ",  
  19. 219             __func__);  
  20. 220         return ret;  
  21. 221     }  
  22. 222   
  23. 223     if (ctrl->cam->type == CAM_TYPE_MIPI) {  
  24. 224         /* subdev call for sleep/wakeup: 
  25. 225          * no error although no s_stream api support 
  26. 226          */  
  27. 227         u32 pixelformat;  
  28. 228         if (ctrl->cap->fmt.pixelformat == V4L2_PIX_FMT_JPEG)  
  29. 229             pixelformat = V4L2_PIX_FMT_JPEG;  
  30. 230         else  
  31. 231             pixelformat = ctrl->cam->pixelformat;  
  32. 232   
  33. 233         subdev_call(ctrl, video, s_stream, 0);  
  34. 234         s3c_csis_start(ctrl->cam->mipi_lanes, ctrl->cam->mipi_settle,   
  35. 235                 ctrl->cam->mipi_align, ctrl->cam->width,   
  36. 236                 ctrl->cam->height, pixelformat);  
  37. 237         subdev_call(ctrl, video, s_stream, 1);  
  38. 238     }  
  39. 239   
  40. 240     ctrl->cam->initialized = 1;  
  41. 241   
  42. 242     return 0;  
  43. 243 }  

这个函数主要对camera的sensor进行上电,初始化,这个函数最早的调用位置是streamon。

但是有一个问题,假定外围电路是一个video AD转换芯片托多个cvbs s-video或者YPbPr输入,那么在执行streamon之前,要首先执行s_input操作选择哪个video AD芯片的输入。选择video AD 的input输入是要操作AD芯片I2C寄存器的,因此这个上电位置是有问题的。

[cpp] view plaincopy
 
  1. 368 static int fimc_add_inqueue(struct fimc_control *ctrl, int i)  
  2. 369 {  
  3. 370     struct fimc_capinfo *cap = ctrl->cap;  
  4. 371  
  5. 372     struct fimc_buf_set *buf;  
  6. 373  
  7. 374     if (i >= cap->nr_bufs)  
  8. 375         return -EINVAL;  
  9. 376  
  10. 377     list_for_each_entry(buf, &cap->inq, list) {  
  11. 378         if (buf->id == i) {  
  12. 379             fimc_dbg("%s: buffer %d already in inqueue. ",   
  13. 380                     __func__, i);  
  14. 381             return -EINVAL;  
  15. 382         }  
  16. 383     }  
  17. 384  
  18. 385     list_add_tail(&cap->bufs[i].list, &cap->inq);  
  19. 386  
  20. 387     return 0;  
  21. 388 }  

这个函数被qbuf调用,把@i指定的buffer加到cap->inq链表中

cap->inq是可用buffer链表,当FIMC更新out DMA address时,就设置为cap->inq中的一个buffer

[cpp] view plaincopy
 
  1. 390 static int fimc_add_outqueue(struct fimc_control *ctrl, int i)  
  2. 391 {  
  3. 392     struct fimc_capinfo *cap = ctrl->cap;  
  4. 393     struct fimc_buf_set *buf;  
  5. 394  
  6. 395     unsigned int mask = 0x2;  
  7. 396  
  8. 397     /* PINGPONG_2ADDR_MODE Only */  
  9. 398     /* pair_buf_index stands for pair index of i. (0<->2) (1<->3) */  
  10. 399  
  11. 400     int pair_buf_index = (i^mask);  
  12. 401  
  13. 402     /* FIMC have 4 h/w registers */  
  14. 403     if (i < 0 || i >= FIMC_PHYBUFS) {  
  15. 404         fimc_err("%s: invalid queue index : %d ", __func__, i);  
  16. 405         return -ENOENT;  
  17. 406     }  
  18. 407  
  19. 408     if (list_empty(&cap->inq))  
  20. 409         return -ENOENT;  
  21. 410  
  22. 411     buf = list_first_entry(&cap->inq, struct fimc_buf_set, list);  
  23. 412  
  24. 413     /* pair index buffer should be allocated first */  
  25. 414     cap->outq[pair_buf_index] = buf->id;  
  26. 415     fimc_hwset_output_address(ctrl, buf, pair_buf_index);  
  27. 416  
  28. 417     cap->outq[i] = buf->id;  
  29. 418     fimc_hwset_output_address(ctrl, buf, i);  
  30. 419  
  31. 420     if (cap->nr_bufs != 1)  
  32. 421         list_del(&buf->list);  
  33. 422  
  34. 423     return 0;  
  35. 424 }  

411 在cap->inq buffer链表中取得第一个可用buffer

413 ~ 418 一直没明白为什么这里把buf设置到两个输出out DMA address寄存器中,华清远见有篇文档http://www.embedu.org/Column/Column457.htm对这个代码的解释是说最多可以把四个out DMA address都配置上,可以增加画面的流畅度。

我原来也是同意华清讲师的说法的,四个output DMA address把帧数分成四个部分,第一个DMA address存储 1, 5, 9, 13... 帧, 第二个DMA address存储2, 6, 10, 14...帧, 第三个存储3, 7, 11, 15...帧, 第四个存储4, 8, 12, 16...帧,如果仅使用一个output DMA address,那么仅能得到1/4的帧率。

但是测试后发现,删除414~415后重新编译的内核没发现有帧率的变化,对帧率没有任何影响。

420 ~ 421 从cap->inq 链表中删除这个buf

[cpp] view plaincopy
 
  1. 516 int fimc_enum_input(struct file *file, void *fh, struct v4l2_input *inp)  
  2. 517 {  
  3. 518     struct fimc_global *fimc = get_fimc_dev();  
  4. 519     struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;  
  5. 520  
  6. 521     fimc_dbg("%s: index %d ", __func__, inp->index);  
  7. 522  
  8. 523     if (inp->index < 0 || inp->index >= FIMC_MAXCAMS) {  
  9. 524         fimc_err("%s: invalid input index, received = %d ",   
  10. 525                 __func__, inp->index);  
  11. 526         return -EINVAL;  
  12. 527     }  
  13. 528  
  14. 529     if (!fimc->camera_isvalid[inp->index])  
  15. 530         return -EINVAL;  
  16. 531  
  17. 532     strcpy(inp->name, fimc->camera[inp->index].info->type);  
  18. 533     inp->type = V4L2_INPUT_TYPE_CAMERA;  
  19. 534  
  20. 535     return 0;  
  21. 536 }  


我觉得fimc应该把ENUMINPUT ioctl调用传递给sensor驱动实现,毕竟std, status甚至name,是隶属于sensor的特性,fimc不该管理这些信息,管理就破坏了fimc驱动的通用性。

[cpp] view plaincopy
 
  1. 538 int fimc_g_input(struct file *file, void *fh, unsigned int *i)  
  2. 539 {  
  3. 540     struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;  
  4. 541     struct fimc_global *fimc = get_fimc_dev();  
  5. 542   
  6. 543     /* In case of isueing g_input before s_input */  
  7. 544     if (!ctrl->cam) {  
  8. 545         fimc_err("no camera device selected yet!"   
  9. 546                 "do VIDIOC_S_INPUT first ");  
  10. 547         return -ENODEV;  
  11. 548     }  
  12. 549   
  13. 550     *i = (unsigned int) fimc->active_camera;  
  14. 551   
  15. 552     fimc_dbg("%s: index %d ", __func__, *i);  
  16. 553   
  17. 554     return 0;  
  18. 555 }  

与fimc_enum_input不同,fimc_g_input可以完全由fimc驱动实现,毕竟这个函数仅仅返回current input的编号,这个编号应该算是隶属于video设备@file的一个特性。

[cpp] view plaincopy
 
  1. 637 int fimc_s_input(struct file *file, void *fh, unsigned int i)  
  2.  638 {  
  3.  639     struct fimc_global *fimc = get_fimc_dev();  
  4.  640     struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;  
  5.  641     int ret = 0;  
  6.  642   
  7.  643     fimc_dbg("%s: index %d ", __func__, i);  
  8.  644   
  9.  645     if (i < 0 || i >= FIMC_MAXCAMS) {  
  10.  646         fimc_err("%s: invalid input index ", __func__);  
  11.  647         return -EINVAL;  
  12.  648     }  
  13.  649   
  14.  650     if (!fimc->camera_isvalid[i])  
  15.  651         return -EINVAL;  
  16.  652   
  17.  653     if (fimc->camera[i].sd && ctrl->id != 2) {  
  18.  654         fimc_err("%s: Camera already in use. ", __func__);  
  19.  655         return -EBUSY;  
  20.  656     }  
  21.  657   
  22.  658     mutex_lock(&ctrl->v4l2_lock);  
  23.  659     /* If ctrl->cam is not NULL, there is one subdev already registered. 
  24.  660      * We need to unregister that subdev first. 
  25.  661      */  
  26.  662     if (i != fimc->active_camera) {  
  27.  663         fimc_release_subdev(ctrl);  
  28.  664         ctrl->cam = &fimc->camera[i];  
  29.  665         ret = fimc_configure_subdev(ctrl);  
  30.  666         if (ret < 0) {  
  31.  667             mutex_unlock(&ctrl->v4l2_lock);  
  32.  668             fimc_err("%s: Could not register camera sensor "  
  33.  669                     "with V4L2. ", __func__);  
  34.  670             return -ENODEV;  
  35.  671         }  
  36.  672         fimc->active_camera = i;  
  37.  673     }  
  38.  674   
  39.  675     if (ctrl->id == 2) {  
  40.  676         if (i == fimc->active_camera) {  
  41.  677             ctrl->cam = &fimc->camera[i];  
  42.  678         } else {  
  43.  679             mutex_unlock(&ctrl->v4l2_lock);  
  44.  680             return -EINVAL;  
  45.  681         }  
  46.  682     }  
  47.  683   
  48.  684     mutex_unlock(&ctrl->v4l2_lock);  
  49.  685   
  50.  686     return 0;  
  51.  687 }  


这个函数选择@file指定的video设备的input路径,我的理解是s_input必须要有sensor驱动参与,这里的实现并没有调用sensor的接口

[cpp] view plaincopy
 
  1. 897 static int fimc_alloc_buffers(struct fimc_control *ctrl, int size[], int align)  
  2. 898 {  
  3. 899     struct fimc_capinfo *cap = ctrl->cap;  
  4. 900     int i, plane;  
  5. 901  
  6. 902     for (i = 0; i < cap->nr_bufs; i++) {  
  7. 903         for (plane = 0; plane < 4; plane++) {  
  8. 904             cap->bufs[i].length[plane] = size[plane];  
  9. 905             if (!cap->bufs[i].length[plane])  
  10. 906                 continue;  
  11. 907  
  12. 908             fimc_dma_alloc(ctrl, &cap->bufs[i], plane, align);  
  13. 909  
  14. 910             if (!cap->bufs[i].base[plane])  
  15. 911                 goto err_alloc;  
  16. 912         }  
  17. 913  
  18. 914         cap->bufs[i].state = VIDEOBUF_PREPARED;  
  19. 915         cap->bufs[i].id = i;  
  20. 916     }  
  21. 917  
  22. 918     return 0;  
  23. 919  
  24. 920 err_alloc:  
  25. 921     for (i = 0; i < cap->nr_bufs; i++) {  
  26. 922         if (cap->bufs[i].base[plane])  
  27. 923             fimc_dma_free(ctrl, &cap->bufs[i], plane);  
  28. 924  
  29. 925         memset(&cap->bufs[i], 0, sizeof(cap->bufs[i]));  
  30. 926     }  
  31. 927  
  32. 928     return -ENOMEM;  
  33. 929 }  

分配queue buffer

@align:queue buffer是DMA buffer,所以会有alignment要求

@size:不同的format,每帧需要的子buffers数目不同,这个函数的plane就代表需要的子buffers数目,size[]是一个数组,表示queue buffers的每个子buffer需求的尺寸

902 cap->nr_bufs,是capture总的queue buffers数量。

[cpp] view plaincopy
 
  1.  950 int fimc_reqbufs_capture(void *fh, struct v4l2_requestbuffers *b)  
  2.  951 {  
  3.  952     struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;  
  4.  953     struct fimc_capinfo *cap = ctrl->cap;  
  5.  954     int ret = 0, i;  
  6.  955     int size[4] = { 0, 0, 0, 0};  
  7.  956     int align = SZ_4K;  
  8.  957   
  9.  958     if (b->memory != V4L2_MEMORY_MMAP) {  
  10.  959         fimc_err("%s: invalid memory type ", __func__);  
  11.  960         return -EINVAL;  
  12.  961     }  
  13.  962   
  14.  963     if (!cap) {  
  15.  964         fimc_err("%s: no capture device info ", __func__);  
  16.  965         return -ENODEV;  
  17.  966     }  
  18.  967   
  19.  968     if (!ctrl->cam || !ctrl->cam->sd) {  
  20.  969         fimc_err("%s: No capture device. ", __func__);  
  21.  970         return -ENODEV;  
  22.  971     }  
  23.  972   
  24.  973     mutex_lock(&ctrl->v4l2_lock);  
  25.  974   
  26.  975     if (b->count < 1 || b->count > FIMC_CAPBUFS)  
  27.  976         return -EINVAL;  
  28.  977   
  29.  978     /* It causes flickering as buf_0 and buf_3 refer to same hardware 
  30.  979      * address. 
  31.  980      */  
  32.  981     if (b->count == 3)  
  33.  982         b->count = 4;  
  34.  983   
  35.  984     cap->nr_bufs = b->count;  
  36.  985   
  37.  986     fimc_dbg("%s: requested %d buffers ", __func__, b->count);  
  38.  987   
  39.  988     INIT_LIST_HEAD(&cap->inq);  
  40.  989   
  41.  990     fimc_free_buffers(ctrl);  
  42.  991   
  43.  992     switch (cap->fmt.pixelformat) {  
  44.  993     case V4L2_PIX_FMT_RGB32:    /* fall through */  
  45.  994     case V4L2_PIX_FMT_RGB565:   /* fall through */  
  46.  995     case V4L2_PIX_FMT_YUYV:     /* fall through */  
  47.  996     case V4L2_PIX_FMT_UYVY:     /* fall through */  
  48.  997     case V4L2_PIX_FMT_VYUY:     /* fall through */  
  49.  998     case V4L2_PIX_FMT_YVYU:     /* fall through */  
  50.  999     case V4L2_PIX_FMT_YUV422P:  /* fall through */  
  51. 1000         size[0] = cap->fmt.sizeimage;  
  52. 1001         break;  
  53. 1002   
  54. 1003     case V4L2_PIX_FMT_NV16:     /* fall through */  
  55. 1004     case V4L2_PIX_FMT_NV61:  
  56. 1005         size[0] = cap->fmt.width * cap->fmt.height;  
  57. 1006         size[1] = cap->fmt.width * cap->fmt.height;  
  58. 1007         size[3] = 16; /* Padding buffer */  
  59. 1008         break;  
  60. 1009     case V4L2_PIX_FMT_NV12:  
  61. 1010         size[0] = cap->fmt.width * cap->fmt.height;  
  62. 1011         size[1] = cap->fmt.width * cap->fmt.height/2;  
  63. 1012         break;  
  64. 1013     case V4L2_PIX_FMT_NV21:  
  65. 1014         size[0] = cap->fmt.width * cap->fmt.height;  
  66. 1015         size[1] = cap->fmt.width * cap->fmt.height/2;  
  67. 1016         size[3] = 16; /* Padding buffer */  
  68. 1017         break;  
  69. 1018     case V4L2_PIX_FMT_NV12T:  
  70. 1019         /* Tiled frame size calculations as per 4x2 tiles 
  71. 1020          *  - Width: Has to be aligned to 2 times the tile width 
  72. 1021          *  - Height: Has to be aligned to the tile height 
  73. 1022          *  - Alignment: Has to be aligned to the size of the 
  74. 1023          *  macrotile (size of 4 tiles) 
  75. 1024          * 
  76. 1025          * NOTE: In case of rotation, we need modified calculation as 
  77. 1026          * width and height are aligned to different values. 
  78. 1027          */  
  79. 1028         if (cap->rotate == 90 || cap->rotate == 270) {  
  80. 1029             size[0] = ALIGN(ALIGN(cap->fmt.height, 128) *  
  81. 1030                     ALIGN(cap->fmt.width, 32),  
  82. 1031                     SZ_8K);  
  83. 1032             size[1] = ALIGN(ALIGN(cap->fmt.height, 128) *  
  84. 1033                     ALIGN(cap->fmt.width/2, 32),  
  85. 1034                     SZ_8K);  
  86. 1035         } else {  
  87. 1036             size[0] = ALIGN(ALIGN(cap->fmt.width, 128) *  
  88. 1037                     ALIGN(cap->fmt.height, 32),  
  89. 1038                     SZ_8K);  
  90. 1039             size[1] = ALIGN(ALIGN(cap->fmt.width, 128) *  
  91. 1040                     ALIGN(cap->fmt.height/2, 32),  
  92. 1041                     SZ_8K);  
  93. 1042         }  
  94. 1043         align = SZ_8K;  
  95. 1044         break;  
  96. 1045   
  97. 1046     case V4L2_PIX_FMT_YUV420:  
  98. 1047         size[0] = cap->fmt.width * cap->fmt.height;  
  99. 1048         size[1] = cap->fmt.width * cap->fmt.height >> 2;  
  100. 1049         size[2] = cap->fmt.width * cap->fmt.height >> 2;  
  101. 1050         size[3] = 16; /* Padding buffer */  
  102. 1051         break;  
  103. 1052   
  104. 1053     case V4L2_PIX_FMT_JPEG:  
  105. 1054         size[0] = fimc_camera_get_jpeg_memsize(ctrl);  
  106. 1055     default:  
  107. 1056         break;  
  108. 1057     }  
  109. 1058   
  110. 1059     ret = fimc_alloc_buffers(ctrl, size, align);  
  111. 1060     if (ret) {  
  112. 1061         fimc_err("%s: no memory for "  
  113. 1062                 "capture buffer ", __func__);  
  114. 1063         mutex_unlock(&ctrl->v4l2_lock);  
  115. 1064         return -ENOMEM;  
  116. 1065     }  
  117. 1066   
  118. 1067     for (i = cap->nr_bufs; i < FIMC_PHYBUFS; i++) {  
  119. 1068         memcpy(&cap->bufs[i],   
  120. 1069             &cap->bufs[i - cap->nr_bufs], sizeof(cap->bufs[i]));  
  121. 1070     }  
  122. 1071   
  123. 1072     mutex_unlock(&ctrl->v4l2_lock);  
  124. 1073   
  125. 1074     return 0;  
  126. 1075 }  

975 ~978 FIMC_CAPBUFS是fimc支持的最大queue buffers数量,可以根据最大capture buffers数目,以及帧buffer所需空间大小(所有子buffers空间总和),加上alignment所带来的空间损失,大致算出fimc capture设备需要预留的物理空间
992 ~ 1057 根据pixelformat和width/height计算每个帧子buffers的尺寸。

[cpp] view plaincopy
 
  1. 1077 int fimc_querybuf_capture(void *fh, struct v4l2_buffer *b)  
  2. 1078 {     
  3. 1079     struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;  
  4. 1080       
  5. 1081     if (!ctrl->cap || !ctrl->cap->bufs) {  
  6. 1082         fimc_err("%s: no capture device info ", __func__);  
  7. 1083         return -ENODEV;   
  8. 1084     }  
  9. 1085       
  10. 1086     if (ctrl->status != FIMC_STREAMOFF) {  
  11. 1087         fimc_err("fimc is running ");  
  12. 1088         return -EBUSY;        
  13. 1089     }  
  14. 1090           
  15. 1091     mutex_lock(&ctrl->v4l2_lock);  
  16. 1092       
  17. 1093     b->length = ctrl->cap->bufs[b->index].length[FIMC_ADDR_Y]  
  18. 1094             + ctrl->cap->bufs[b->index].length[FIMC_ADDR_CB]  
  19. 1095             + ctrl->cap->bufs[b->index].length[FIMC_ADDR_CR];  
  20. 1096   
  21. 1097     b->m.offset = b->index * PAGE_SIZE;  
  22. 1098   
  23. 1099     ctrl->cap->bufs[b->index].state = VIDEOBUF_IDLE;  
  24. 1100   
  25. 1101     mutex_unlock(&ctrl->v4l2_lock);  
  26. 1102   
  27. 1103     fimc_dbg("%s: %d bytes at index: %d ", __func__, b->length, b->index);  
  28. 1104   
  29. 1105     return 0;  
  30. 1106 }  


1093 ~ 1095 buffer的length由三个分量buffer总长度决定
1097 这个需要结合fimc_mmap_cap来看,b->m.offset可以用来表示buffer的索引值

[cpp] view plaincopy
 
  1. 1255 int fimc_cropcap_capture(void *fh, struct v4l2_cropcap *a)  
  2. 1256 {  
  3. 1257     struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;  
  4. 1258     struct fimc_capinfo *cap = ctrl->cap;  
  5. 1259   
  6. 1260     fimc_dbg("%s ", __func__);  
  7. 1261   
  8. 1262     if (!ctrl->cam || !ctrl->cam->sd || !ctrl->cap) {  
  9. 1263         fimc_err("%s: No capture device. ", __func__);  
  10. 1264         return -ENODEV;  
  11. 1265     }  
  12. 1266   
  13. 1267     mutex_lock(&ctrl->v4l2_lock);  
  14. 1268   
  15. 1269     /* crop limitations */  
  16. 1270     cap->cropcap.bounds.left = 0;  
  17. 1271     cap->cropcap.bounds.top = 0;  
  18. 1272     cap->cropcap.bounds.width = ctrl->cam->width;  
  19. 1273     cap->cropcap.bounds.height = ctrl->cam->height;  
  20. 1274   
  21. 1275     /* crop default values */  
  22. 1276     cap->cropcap.defrect.left = 0;  
  23. 1277     cap->cropcap.defrect.top = 0;  
  24. 1278     cap->cropcap.defrect.width = ctrl->cam->width;  
  25. 1279     cap->cropcap.defrect.height = ctrl->cam->height;  
  26. 1280   
  27. 1281     a->bounds = cap->cropcap.bounds;  
  28. 1282     a->defrect = cap->cropcap.defrect;  
  29. 1283   
  30. 1284     mutex_unlock(&ctrl->v4l2_lock);  
  31. 1285   
  32. 1286     return 0;  
  33. 1287 }  

fimc_cropcap_capture:fimc的VIDIOC_CROPCAP的实现

cropcap.bounds 是capture window 最大边界,capture.defrect是capture window的默认方框

cropcap.defrect一定不会超出cropcap.bounds的范围,他们的关系如下图

cropcap.pixelaspect =垂直像素数 / 水平像素数

[cpp] view plaincopy
 
  1. 1289 int fimc_g_crop_capture(void *fh, struct v4l2_crop *a)  
  2. 1290 {  
  3. 1291     struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;  
  4. 1292   
  5. 1293     fimc_dbg("%s ", __func__);  
  6. 1294   
  7. 1295     if (!ctrl->cap) {  
  8. 1296         fimc_err("%s: No capture device. ", __func__);  
  9. 1297         return -ENODEV;  
  10. 1298     }  
  11. 1299   
  12. 1300     mutex_lock(&ctrl->v4l2_lock);  
  13. 1301     a->c = ctrl->cap->crop;  
  14. 1302     mutex_unlock(&ctrl->v4l2_lock);  
  15. 1303   
  16. 1304     return 0;  
  17. 1305 }  
  18. 1306   


fimc_g_crop_capture 是capture设备的VIDIOC_G_CROP实现,返回当前的crop

[cpp] view plaincopy
 
    1. <pre name="code" class="cpp">1307 static int fimc_capture_crop_size_check(struct fimc_control *ctrl)  
    2. 1308 {  
    3. 1309     struct fimc_capinfo *cap = ctrl->cap;  
    4. 1310     int win_hor_offset = 0, win_hor_offset2 = 0;  
    5. 1311     int win_ver_offset = 0, win_ver_offset2 = 0;  
    6. 1312     int crop_width = 0, crop_height = 0;  
    7. 1313   
    8. 1314     /* check win_hor_offset, win_hor_offset2 */  
    9. 1315     win_hor_offset = ctrl->cam->window.left;  
    10. 1316     win_hor_offset2 = ctrl->cam->width - ctrl->cam->window.left -  
    11. 1317                         ctrl->cam->window.width;  
    12. 1318   
    13. 1319     win_ver_offset = ctrl->cam->window.top;  
    14. 1320     win_ver_offset2 = ctrl->cam->height - ctrl->cam->window.top -  
    15. 1321                         ctrl->cam->window.height;  
    16. 1322   
    17. 1323     if (win_hor_offset < 0 || win_hor_offset2 < 0) {  
    18. 1324         fimc_err("%s: Offset (left-side(%d) or right-side(%d) "  
    19. 1325                 "is negative. ", __func__,   
    20. 1326                 win_hor_offset, win_hor_offset2);  
    21. 1327         return -1;  
    22. 1328     }  
    23. 1329   
    24. 1330     if (win_ver_offset < 0 || win_ver_offset2 < 0) {  
    25. 1331         fimc_err("%s: Offset (top-side(%d) or bottom-side(%d)) "  
    26. 1332                 "is negative. ", __func__,   
    27. 1333                 win_ver_offset, win_ver_offset2);  
    28. 1334         return -1;  
    29. 1335     }  
    30. 1336   
    31. 1337     if ((win_hor_offset % 2) || (win_hor_offset2 % 2)) {  
    32. 1338         fimc_err("%s: win_hor_offset must be multiple of 2 ",   
    33. 1339                 __func__);  
    34. 1340         return -1;  
    35. 1341     }  
    36. 1342   
    37. 1343     /* check crop_width, crop_height */  
    38. 1344     crop_width = ctrl->cam->window.width;  
    39. 1345     crop_height = ctrl->cam->window.height;  
    40. 1346   
    41. 1347     if (crop_width % 16) {  
    42. 1348         fimc_err("%s: crop_width must be multiple of 16 ", __func__);  
    43. 1349         return -1;  
    44. 1350     }  
    45. 1351   
    46. 1352     switch (cap->fmt.pixelformat) {  
    47. 1353     case V4L2_PIX_FMT_YUV420:       /* fall through */  
    48. 1354     case V4L2_PIX_FMT_NV12:         /* fall through */  
    49. 1355     case V4L2_PIX_FMT_NV21:         /* fall through */  
    50. 1356     case V4L2_PIX_FMT_NV12T:         /* fall through */  
    51. 1357         if ((crop_height % 2) || (crop_height < 8)) {  
    52. 1358             fimc_err("%s: crop_height error! ", __func__);  
    53. 1359             return -1;  
    54. 1360         }  
    55. 1361         break;  
    56. 1362     default:  
    57. 1363         break;  
    58. 1364     }  
    59. 1365   
    60. 1366     return 0;  
    61. 1367 }  
    62. </pre><p></p>  
    63. <pre></pre>  
    64. <br>  
    65. cam->cam->window是crop设置后的取景框,这个函数就是检测这个取景框是否符合规范  
    66. <p></p>  
    67. <p><br>  
    68. </p>  
    69. <p></p><pre name="code" class="cpp">1377 static void fimc_capture_update_crop_window(struct fimc_control *ctrl)  
    70. 1378 {  
    71. 1379     unsigned int zoom_hor = 0;  
    72. 1380     unsigned int zoom_ver = 0;  
    73. 1381     unsigned int multiplier = 1024;  
    74. 1382   
    75. 1383     if (!ctrl->cam->width || !ctrl->cam->height)  
    76. 1384         return;  
    77. 1385   
    78. 1386     zoom_hor = ctrl->cap->fmt.width * multiplier / ctrl->cam->width;  
    79. 1387     zoom_ver = ctrl->cap->fmt.height * multiplier / ctrl->cam->height;  
    80. 1388   
    81. 1389     if (!zoom_hor || !zoom_ver)  
    82. 1390         return;  
    83. 1391   
    84. 1392     /* Width */  
    85. 1393     ctrl->cam->window.width = ctrl->cap->crop.width * multiplier / zoom_hor;  
    86. 1394     if (ctrl->cam->window.width > ctrl->cam->width)  
    87. 1395         ctrl->cam->window.width = ctrl->cam->width;  
    88. 1396     if (ctrl->cam->window.width % 16)  
    89. 1397         ctrl->cam->window.width =  
    90. 1398             (ctrl->cam->window.width + 0xF) & ~0xF;  
    91. 1399   
    92. 1400     /* Left offset */  
    93. 1401     ctrl->cam->window.left = ctrl->cap->crop.left * multiplier / zoom_hor;  
    94. 1402     if (ctrl->cam->window.width + ctrl->cam->window.left > ctrl->cam->width)  
    95. 1403         ctrl->cam->window.left =  
    96. 1404             (ctrl->cam->width - ctrl->cam->window.width)/2;  
    97. 1405     if (ctrl->cam->window.left % 2)  
    98. 1406         ctrl->cam->window.left--;  
    99. 1407   
    100. 1408     /* Height */  
    101. 1409     ctrl->cam->window.height =  
    102. 1410         (ctrl->cap->crop.height * multiplier) / zoom_ver;  
    103. 1411     if (ctrl->cam->window.top > ctrl->cam->height)  
    104. 1412         ctrl->cam->window.height = ctrl->cam->height;  
    105. 1413     if (ctrl->cam->window.height % 2)  
    106. 1414         ctrl->cam->window.height--;  
    107. 1415   
    108. 1416     /* Top offset */  
    109. 1417     ctrl->cam->window.top = ctrl->cap->crop.top * multiplier / zoom_ver;  
    110. 1418     if (ctrl->cam->window.height + ctrl->cam->window.top >  
    111. 1419             ctrl->cam->height)  
    112. 1420         ctrl->cam->window.top =  
    113. 1421             (ctrl->cam->height - ctrl->cam->window.height)/2;  
    114. 1422     if (ctrl->cam->window.top % 2)  
    115. 1423         ctrl->cam->window.top--;  
    116. 1424   
    117. 1425     fimc_dbg("Cam (%dx%d) Crop: (%d %d %d %d) Win: (%d %d %d %d) ",   
    118. 1426             ctrl->cam->width, ctrl->cam->height,   
    119. 1427             ctrl->cap->crop.left, ctrl->cap->crop.top,   
    120. 1428             ctrl->cap->crop.width, ctrl->cap->crop.height,   
    121. 1429             ctrl->cam->window.left, ctrl->cam->window.top,   
    122. 1430             ctrl->cam->window.width, ctrl->cam->window.height);  
    123. 1431   
    124. 1432 }  
    125. </pre><br>  
    126. 根据s_crop设置的curr_crop设置capture 的取景框<br>  
    127. <p></p>  
    128. <p><br>  
    129. </p>  
    130. <p></p><pre name="code" class="cpp">1434 int fimc_s_crop_capture(void *fh, struct v4l2_crop *a)  
    131. 1435 {  
    132. 1436     struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl;  
    133. 1437     int ret = 0;  
    134. 1438   
    135. 1439     fimc_dbg("%s ", __func__);  
    136. 1440   
    137. 1441     if (!ctrl->cap) {  
    138. 1442         fimc_err("%s: No capture device. ", __func__);  
    139. 1443         return -ENODEV;  
    140. 1444     }  
    141. 1445   
    142. 1446     mutex_lock(&ctrl->v4l2_lock);  
    143. 1447     ctrl->cap->crop = a->c;  
    144. 1448   
    145. 1449     fimc_capture_update_crop_window(ctrl);  
    146. 1450   
    147. 1451     ret = fimc_capture_crop_size_check(ctrl);  
    148. 1452     if (ret < 0) {  
    149. 1453         mutex_unlock(&ctrl->v4l2_lock);  
    150. 1454         fimc_err("%s: Invalid crop parameters. ", __func__);  
    151. 1455         return -EINVAL;  
    152. 1456     }  
    153. 1457   
    154. 1458     if (ctrl->status == FIMC_STREAMON &&  
    155. 1459             ctrl->cap->fmt.pixelformat != V4L2_PIX_FMT_JPEG) {  
    156. 1460         fimc_hwset_shadow_disable(ctrl);  
    157. 1461         fimc_hwset_camera_offset(ctrl);  
    158. 1462         fimc_capture_scaler_info(ctrl);  
    159. 1463         fimc_hwset_prescaler(ctrl, &ctrl->sc);  
    160. 1464         fimc_hwset_scaler(ctrl, &ctrl->sc);  
    161. 1465         fimc_hwset_shadow_enable(ctrl);  
    162. 1466     }  
    163. 1467   
    164. 1468     mutex_unlock(&ctrl->v4l2_lock);  
    165. 1469   
    166. 1470     return 0;  
    167. 1471 }  
    168. </pre>fimc_s_crop_capture是capture设备的VIDIOC_S_CROP ioctl实现<p></p>  
    169. <p>1449 用@a更新capture window</p>  
    170. <p>1451 检测新生成的capture window参数合法性</p>  
    171. <p>1458 ~ 1466 FIMC支持streamon正在进行时,修改capture取景框<br>  
    172. </p>  
    173. <p><br>  
    174. </p>  
    175. <p><br>  
    176. </p>  
    177. <p><br>  
    178. <br>  
    179. </p>  
原文地址:https://www.cnblogs.com/cainiaoaixuexi/p/3357279.html