fimc-dev.c 是Samsung FIMC 设备的V4L2 驱动。上层应用直接操作这个设备,进行capture,图片处理,以及overlay输出

http://blog.csdn.net/cxw3506/article/details/8476263

  1. 43 int fimc_dma_alloc(struct fimc_control *ctrl, struct fimc_buf_set *bs,
  2. 44                             int i, int align)
  3. 45 {
  4. 46     dma_addr_t end, *curr;
  5. 47
  6. 48     mutex_lock(&ctrl->alloc_lock);
  7. 49
  8. 50     end = ctrl->mem.base + ctrl->mem.size;
  9. 51     curr = &ctrl->mem.curr;
  10. 52
  11. 53     if (!bs->length[i])
  12. 54         return -EINVAL;
  13. 55
  14. 56     if (!align) {
  15. 57         if (*curr + bs->length[i] > end) {
  16. 58             goto overflow;
  17. 59         } else {
  18. 60             bs->base[i] = *curr;
  19. 61             bs->garbage[i] = 0;
  20. 62             *curr += bs->length[i];
  21. 63         }
  22. 64     } else {
  23. 65         if (ALIGN(*curr, align) + bs->length[i] > end)
  24. 66             goto overflow;
  25. 67         else {
  26. 68             bs->base[i] = ALIGN(*curr, align);
  27. 69             bs->garbage[i] = ALIGN(*curr, align) - *curr;
  28. 70             *curr += (bs->length[i] + bs->garbage[i]);
  29. 71         }
  30. 72     }
  31. 73
  32. 74     mutex_unlock(&ctrl->alloc_lock);
  33. 75
  34. 76     return 0;
  35. 77
  36. 78 overflow:
  37. 79     bs->base[i] = 0;
  38. 80     bs->length[i] = 0;
  39. 81     bs->garbage[i] = 0;
  40. 82
  41. 83     mutex_unlock(&ctrl->alloc_lock);
  42. 84
  43. 85     return -ENOMEM;
  44. 86 }

这个函数很简单,之所以提出来说下,是因为我在DMA对齐问题上卡了一个多星期

FIMC使用预分配的物理内存来申请DMA buffer,参数中的align指明申请buffer的对齐方式,对于FIMC capture来说,似乎output DMA要求4k对齐(尽管我没有在datasheet中找到),如果给定的DMA地址没有4K对齐,FIMC DMA控制器会很聪明的从4K对齐的地址开始传送数据,这会导致了帧数据偏移。

@i 参数指定了plane数,FIMC 输出支持很多种格式,有单层的比如YUYV,两层的V4L2_PIX_FMT_NV12,还有三层的V4L2_PIX_FMT_NV12T

单层格式输出申请一个buffer,两层格式输出申请两个buffer,三层则需申请三个buffer。

  1. 88 void fimc_dma_free(struct fimc_control *ctrl, struct fimc_buf_set *bs, int i)
  2. 89 {
  3. 90     int total = bs->length[i] + bs->garbage[i];
  4. 91     mutex_lock(&ctrl->alloc_lock);
  5. 92
  6. 93     if (bs->base[i]) {
  7. 94         if (ctrl->mem.curr - total >= ctrl->mem.base)
  8. 95             ctrl->mem.curr -= total;
  9. 96
  10. 97         bs->base[i] = 0;
  11. 98         bs->length[i] = 0;
  12. 99         bs->garbage[i] = 0;
  13. 100     }
  14. 101
  15. 102     mutex_unlock(&ctrl->alloc_lock);
  16. 103 }

这个函数有问题,93 ~ 95 成立的条件是bs->base[i]所占的地址必须在ctrl->mem.base最后面,这就要求释放顺序必须从bs的最后一个节点向前释放。

  1. 655 static inline int fimc_mmap_cap(struct file *filp, struct vm_area_struct *vma)
  2. 656 {
  3. 657     struct fimc_prv_data *prv_data =
  4. 658                 (struct fimc_prv_data *)filp->private_data;
  5. 659     struct fimc_control *ctrl = prv_data->ctrl;
  6. 660     u32 size = vma->vm_end - vma->vm_start;
  7. 661     u32 pfn, idx = vma->vm_pgoff;
  8. 662
  9. 663     vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
  10. 664     vma->vm_flags |= VM_RESERVED;
  11. 665
  12. 666     /*
  13. 667      * page frame number of the address for a source frame
  14. 668      * to be stored at.
  15. 669      */
  16. 670     pfn = __phys_to_pfn(ctrl->cap->bufs[idx].base[0]);
  17. 671
  18. 672     if ((vma->vm_flags & VM_WRITE) && !(vma->vm_flags & VM_SHARED)) {
  19. 673         fimc_err("%s: writable mapping must be shared\n", __func__);
  20. 674         return -EINVAL;
  21. 675     }
  22. 676
  23. 677     if (remap_pfn_range(vma, vma->vm_start, pfn, size, vma->vm_page_prot)) {
  24. 678         fimc_err("%s: mmap fail\n", __func__);
  25. 679         return -EINVAL;
  26. 680     }
  27. 681
  28. 682     return 0;
  29. 683 }

fimc capture 设备的mmap实现,ctrl->cap->bufs[idx]是fimc capture设备申请的buffer,mmap就是把这个buffer映射到应用程序空间

661 vma->vm_pgoff 表示vm_file内以PAGE_SIZE为单位的偏移,但是在这里应用层和内核使用另外一种约定的含义,buffer ID, 应用层调用mmap接口对fimc capture设备的buffer进行映射

  1. 700 static u32 fimc_poll(struct file *filp, poll_table *wait)
  2. 701 {
  3. 702     struct fimc_prv_data *prv_data =
  4. 703                 (struct fimc_prv_data *)filp->private_data;
  5. 704     struct fimc_control *ctrl = prv_data->ctrl;
  6. 705     struct fimc_capinfo *cap = ctrl->cap;
  7. 706     u32 mask = 0;
  8. 707
  9. 708     if (cap) {
  10. 709         if (cap->irq || (ctrl->status != FIMC_STREAMON)) {
  11. 710             mask = POLLIN | POLLRDNORM;
  12. 711             cap->irq = 0;
  13. 712         } else {
  14. 713             poll_wait(filp, &ctrl->wq, wait);
  15. 714         }
  16. 715     }
  17. 716
  18. 717     return mask;
  19. 718 }

fimc_poll向上层应用提供了等待机制,应用程序poll fimc设备并阻塞,直到cap或者output中断处理函数唤醒

  1. 732 u32 fimc_mapping_rot_flip(u32 rot, u32 flip)
  2. 733 {
  3. 734     u32 ret = 0;
  4. 735
  5. 736     switch (rot) {
  6. 737     case 0:
  7. 738         if (flip & FIMC_XFLIP)
  8. 739             ret |= FIMC_XFLIP;
  9. 740
  10. 741         if (flip & FIMC_YFLIP)
  11. 742             ret |= FIMC_YFLIP;
  12. 743         break;
  13. 744
  14. 745     case 90:
  15. 746         ret = FIMC_ROT;
  16. 747         if (flip & FIMC_XFLIP)
  17. 748             ret |= FIMC_XFLIP;
  18. 749
  19. 750         if (flip & FIMC_YFLIP)
  20. 751             ret |= FIMC_YFLIP;
  21. 752         break;
  22. 753
  23. 754     case 180:
  24. 755         ret = (FIMC_XFLIP | FIMC_YFLIP);
  25. 756         if (flip & FIMC_XFLIP)
  26. 757             ret &= ~FIMC_XFLIP;
  27. 758
  28. 759         if (flip & FIMC_YFLIP)
  29. 760             ret &= ~FIMC_YFLIP;
  30. 761         break;
  31. 762
  32. 763     case 270:
  33. 764         ret = (FIMC_XFLIP | FIMC_YFLIP | FIMC_ROT);
  34. 765         if (flip & FIMC_XFLIP)
  35. 766             ret &= ~FIMC_XFLIP;
  36. 767
  37. 768         if (flip & FIMC_YFLIP)
  38. 769             ret &= ~FIMC_YFLIP;
  39. 770         break;
  40. 771     }
  41. 772
  42. 773     return ret;
  43. 774 }

rot会影响flip的结果,该函数映射(合并)rot和 flip操作

  1. static int fimc_open(struct file *filp)
  2. {
  3. struct fimc_control *ctrl;
  4. struct s3c_platform_fimc *pdata;
  5. struct fimc_prv_data *prv_data;
  6. int in_use;
  7. int ret;
  8. ctrl = video_get_drvdata(video_devdata(filp));
  9. pdata = to_fimc_plat(ctrl->dev);
  10. mutex_lock(&ctrl->lock);
  11. in_use = atomic_read(&ctrl->in_use);
  12. if (in_use >= FIMC_MAX_CTXS || (in_use && 1 != ctrl->id)) {
  13. fimc_err("%s: Device busy.\n", __func__);
  14. ret = -EBUSY;
  15. goto resource_busy;
  16. } else {
  17. atomic_inc(&ctrl->in_use);
  18. }
  19. in_use = atomic_read(&ctrl->in_use);
  20. prv_data = kzalloc(sizeof(struct fimc_prv_data), GFP_KERNEL);
  21. if (!prv_data) {
  22. fimc_err("%s: not enough memory\n", __func__);
  23. ret = -ENOMEM;
  24. goto kzalloc_err;
  25. }
  26. prv_data->ctx_id = fimc_get_free_ctx(ctrl);
  27. if (prv_data->ctx_id < 0) {
  28. fimc_err("%s: Context busy flag not reset.\n", __func__);
  29. ret = -EBUSY;
  30. goto ctx_err;
  31. }
  32. prv_data->ctrl = ctrl;
  33. filp->private_data = prv_data;
  34. if (in_use == 1) {
  35. fimc_clk_en(ctrl, true);
  36. if (pdata->hw_ver == 0x40)
  37. fimc_hw_reset_camera(ctrl);
  38. /* Apply things to interface register */
  39. fimc_hwset_reset(ctrl);
  40. if (num_registered_fb > 0) {
  41. struct fb_info *fbinfo = registered_fb[0];
  42. ctrl->fb.lcd_hres = (int)fbinfo->var.xres;
  43. ctrl->fb.lcd_vres = (int)fbinfo->var.yres;
  44. fimc_info1("%s: fd.lcd_hres=%d fd.lcd_vres=%d\n",
  45. __func__, ctrl->fb.lcd_hres,
  46. ctrl->fb.lcd_vres);
  47. }
  48. ctrl->mem.curr = ctrl->mem.base;
  49. ctrl->status = FIMC_STREAMOFF;
  50. if (0 != ctrl->id)
  51. fimc_clk_en(ctrl, false);
  52. }
  53. mutex_unlock(&ctrl->lock);
  54. fimc_info1("%s opened.\n", ctrl->name);
  55. return 0;
  56. ctx_err:
  57. kfree(prv_data);
  58. kzalloc_err:
  59. atomic_dec(&ctrl->in_use);
  60. resource_busy:
  61. mutex_unlock(&ctrl->lock);
  62. return ret;
  63. }

932 如果是第一次打开,那么需要使能mclk

939 调用fimc_hwset_reset 进行fimc控制器的reset过程951 FIMC会为每一个控制器预分配一段物理内存, mem.base 指向物理内存的起始地址,FIMC在执行DMA之前,需要为DMA分配物理内存,FIMC直接从这个预保留的空间进行分配

mem.curr记录着当前可用空间的起始位置在arch/arm/mach-s5pv210/mach-smdkc110.c中

    1. //#define  S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMC0 (6144 * SZ_1K)
    2. #define  S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMC0 (24576 * SZ_1K)
    3. #define  S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMC1 (9900 * SZ_1K)
    4. //#define  S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMC2 (6144 * SZ_1K)
    5. #define  S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMC2 (24576 * SZ_1K)
    6. #define  S5PV210_VIDEO_SAMSUNG_MEMSIZE_MFC0 (36864 * SZ_1K)
    7. #define  S5PV210_VIDEO_SAMSUNG_MEMSIZE_MFC1 (36864 * SZ_1K)
    8. #define  S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMD (S5PV210_LCD_WIDTH * \
    9. S5PV210_LCD_HEIGHT * 4 * \
    10. CONFIG_FB_S3C_NR_BUFFERS)
    11. #define  S5PV210_VIDEO_SAMSUNG_MEMSIZE_JPEG (8192 * SZ_1K)<span>
    12. <span style="color:#FF0000;">定义了media device需要的reserved 物理内存大小,物理内存的实际使用可能达不到定义的大小, </span></span><span style="color:#FF0000;"><span><span class="tag"></span><span class="tag-name"></span><span class="tag"></span><span class="tag"></span><span class="tag-name"></span><span class="tag"></span><span></span></span><span><span class="tag"></span><span>
    13. 物理内存的使用大小 和图片大小以及queue buffer数量成正比的,也就是说图片分辨率Width x Height越高,queue buffer数量越多,实际使用的物理内存越大</span><span class="tag"></span><span class="tag-name"></span><span class="tag"></span><span></span></span><span><span>
    14. 所以这个物理内存大小要根据项目情况具体调整,当然你也可以不调,就是浪费点内存。
    15. </span></span></span>
    16. <pre name="code" class="cpp">1133 struct video_device fimc_video_device[FIMC_DEVICES] = {
    17. 1134     [0] = {
    18. 1135         .fops = &fimc_fops,
    19. 1136         .ioctl_ops = &fimc_v4l2_ops,
    20. 1137         .release = fimc_vdev_release,
    21. 1138     },
    22. 1139     [1] = {
    23. 1140         .fops = &fimc_fops,
    24. 1141         .ioctl_ops = &fimc_v4l2_ops,
    25. 1142         .release = fimc_vdev_release,
    26. 1143     },
    27. 1144     [2] = {
    28. 1145         .fops = &fimc_fops,
    29. 1146         .ioctl_ops = &fimc_v4l2_ops,
    30. 1147         .release = fimc_vdev_release,
    31. 1148     },
    32. 1149 };
    33. FIMC_DEVICES 一共有三个fimc0, fimc1, fimc2设备,
    34. fops定义了设备节点的文件操作函数; ioctl_ops定义了fimc向V4L2提供的所有ioctl操作集合</pre><pre name="code" class="cpp">1310 static int __devinit fimc_probe(struct platform_device *pdev)
    35. 1311 {
    36. 1312     struct s3c_platform_fimc *pdata;
    37. 1313     struct fimc_control *ctrl;
    38. 1314     struct clk *srclk;
    39. 1315     int ret;
    40. 1316
    41. 1317     if (!fimc_dev) {
    42. 1318         fimc_dev = kzalloc(sizeof(*fimc_dev), GFP_KERNEL);
    43. 1319         if (!fimc_dev) {
    44. 1320             dev_err(&pdev->dev, "%s: not enough memory\n",
    45. 1321                 __func__);
    46. 1322             return -ENOMEM;
    47. 1323         }
    48. 1324     }
    49. 1325
    50. 1326     ctrl = fimc_register_controller(pdev);
    51. 1327     if (!ctrl) {
    52. 1328         printk(KERN_ERR "%s: cannot register fimc\n", __func__);
    53. 1329         goto err_alloc;
    54. 1330     }
    55. 1331
    56. 1332     pdata = to_fimc_plat(&pdev->dev);
    57. 1333     if (pdata->cfg_gpio)
    58. 1334         pdata->cfg_gpio(pdev);
    59. 1335
    60. 1336     /* Get fimc power domain regulator */
    61. 1337     ctrl->regulator = regulator_get(&pdev->dev, "pd");
    62. 1338     if (IS_ERR(ctrl->regulator)) {
    63. 1339         fimc_err("%s: failed to get resource %s\n",
    64. 1340                 __func__, "s3c-fimc");
    65. 1341         return PTR_ERR(ctrl->regulator);
    66. 1342     }
    67. 1343
    68. 1344     /* fimc source clock */
    69. 1345     srclk = clk_get(&pdev->dev, pdata->srclk_name);
    70. 1346     if (IS_ERR(srclk)) {
    71. 1347         fimc_err("%s: failed to get source clock of fimc\n",
    72. 1348                 __func__);
    73. 1349         goto err_v4l2;
    74. 1350     }
    75. 1351
    76. 1352     /* fimc clock */
    77. 1353     ctrl->clk = clk_get(&pdev->dev, pdata->clk_name);
    78. 1354     if (IS_ERR(ctrl->clk)) {
    79. 1355         fimc_err("%s: failed to get fimc clock source\n",
    80. 1356             __func__);
    81. 1357         goto err_v4l2;
    82. 1358     }
    83. 1359
    84. 1360     /* set parent for mclk */
    85. 1361     clk_set_parent(ctrl->clk, srclk);
    86. 1362
    87. 1363     /* set rate for mclk */
    88. 1364     clk_set_rate(ctrl->clk, pdata->clk_rate);
    89. 1365
    90. 1366     /* V4L2 device-subdev registration */
    91. 1367     ret = v4l2_device_register(&pdev->dev, &ctrl->v4l2_dev);
    92. 1368     if (ret) {
    93. 1369         fimc_err("%s: v4l2 device register failed\n", __func__);
    94. 1370         goto err_fimc;
    95. 1371     }
    96. 1372
    97. 1373     /* things to initialize once */
    98. 1374     if (!fimc_dev->initialized) {
    99. 1375         ret = fimc_init_global(pdev);
    100. 1376         if (ret)
    101. 1377             goto err_v4l2;
    102. 1378     }
    103. 1379
    104. 1380     /* video device register */
    105. 1381     ret = video_register_device(ctrl->vd, VFL_TYPE_GRABBER, ctrl->id);
    106. 1382     if (ret) {
    107. 1383         fimc_err("%s: cannot register video driver\n", __func__);
    108. 1384         goto err_v4l2;
    109. 1385     }
    110. 1386
    111. 1387     video_set_drvdata(ctrl->vd, ctrl);
    112. 1388
    113. 1389     ret = device_create_file(&(pdev->dev), &dev_attr_log_level);
    114. 1390     if (ret < 0) {
    115. 1391         fimc_err("failed to add sysfs entries\n");
    116. 1392         goto err_global;
    117. 1393     }
    118. 1394     printk(KERN_INFO "FIMC%d registered successfully\n", ctrl->id);
    119. 1395
    120. 1396     return 0;
    121. 1397
    122. 1398 err_global:
    123. 1399     video_unregister_device(ctrl->vd);
    124. 1400
    125. 1401 err_v4l2:
    126. 1402     v4l2_device_unregister(&ctrl->v4l2_dev);
    127. 1403
    128. 1404 err_fimc:
    129. 1405     fimc_unregister_controller(pdev);
    130. 1406
    131. 1407 err_alloc:
    132. 1408     kfree(fimc_dev);
    133. 1409     return -EINVAL;
    134. 1410
    135. 1411 }
    136. 1333 ~ 1334 调用平台的gpio设置函数,一般来说,这个用来设置external CameraA/CameraB的输入输出
    137. 1344 ~ 1364 设置mclk,mclk的频率由sensor的输出图像尺寸, 如果外围sensor自身有晶振,那么CPU不需要对外提供mclk
    138. 1381 ~ 1385 注册一个video device,会生成设备节点/dev/videoX
    139. </pre><br>
    140. <br>
    141. <p></p>
    142. <pre></pre>
    143. <p></p>
    144. <p><br>
    145. </p>

s5pv210 fimc 之 fimc-dev.c的更多相关文章

  1. android camera(三):camera V4L2 FIMC

    1. V4L2 1)简介 在Linux中,摄像头方面的标准化程度比较高,这个标准就是V4L2驱动程序,这也是业界比较公认的方式. V4L全称是Video for Linux,是Linux内核中标准的关 ...

  2. 【转】android camera(三):camera V4L2 FIMC

    关键词:android  camera CMM 模组 camera参数  CAMIF   V4L2  平台信息:内核:linux系统:android 平台:S5PV310(samsung exynos ...

  3. Tiny210v2( S5PV210 )平台下创建基本根文件系统

    转自Tiny210v2( S5PV210 )平台下创建基本根文件系统 0. 概要介绍 ========================================================= ...

  4. 基于Linux 3.0.8 Samsung FIMC(S5PV210) 的摄像头驱动框架解读(一)

    作者:咕唧咕唧liukun321 来自:http://blog.csdn.net/liukun321 FIMC这个名字应该是从S5PC1x0開始出现的.在s5pv210里面的定义是摄像头接口.可是它相 ...

  5. (转)S5PV210 三个Camera Interface/CAMIF/FIMC的区别

    原文出处:http://blog.csdn.net/kickxxx/article/details/7728947 S5PV210有三个CAMIF单元,分别为CAMIF0 CAMIF1和CAMIF2. ...

  6. S5PV210 三个Camera Interface/CAMIF/FIMC的区别

    S5PV210有三个CAMIF单元,分别为CAMIF0 CAMIF1和CAMIF2.对应着驱动中的fimc0, fimc1, fimc2.在三星datasheet和驱动代码中CAMIF和FIMC(Fu ...

  7. Android S5PV210 fimc驱动分析 - fimc_capture.c

    fimc_capture.c在FIMC系统中的位置,网上偷来的一幅图片 http://blog.csdn.net/kickxxx/article/details/7733482 43 static c ...

  8. 基于S5PC100的FIMC控制器解析

    作者:邹南,华清远见嵌入式学院讲师. http://www.cnblogs.com/gooogleman/archive/2012/07/26/2610449.html CAMERA SENSOR O ...

  9. S5PV210 时钟体系分析

    S5PV210 时钟体系 如下面时钟结构图所示,S5PV210 中包含 3 大类时钟域, 分别是主系统时钟域(简称 MSYS).显示相关的时钟域(简称 DSYS). 外围设备的时钟域(简称 PSYS) ...

随机推荐

  1. 定时器SDK

    定时器是一切SDK的根本,欲写SDK必先确定定时器,定时器效率的高低决定着SDK函数的效率,下面是我个人写的Linux C++服务器端进程SDK中的定时器,部分参照了ACE和RocketMQ定时器的思 ...

  2. [SharePoint][SharePoint Designer 入门经典]Chapter7 数据源和外部内容类型

    本章概要: 1.SharePoint能够使用的数据类型 2.如何从SharePoint列表和库中取得数据并展现出来 3.SharePoint访问远程数据 4.如何把外部数据源作为列表展现在你的SPS站 ...

  3. ios基础-分辨率适配

    (一)分辨率定义 分辨率,是指单位长度内包括的像素点的数量,它的单位通常为像素/英寸(ppi).描写叙述分辨率的单位有:(dpi点每英寸).lpi(线每英寸)和ppi(像素每英寸). (二)ios分辨 ...

  4. Oracle 用户管理(一)

    1     创建用户     create user @username identified by @password     比如:create user aobama identified by ...

  5. Linux环境thinkphp配置以及数据源驱动改动

    项目中须要用到thinkphp,以下简称tp. linux版本号:64位CentOS 6.4 Nginx版本号:nginx1.8.0 php版本号:php5.5.28 thinkphp版:3.2.3 ...

  6. 每天一个JavaScript实例-tab标签切换

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

  7. FFMpeg在Windows下搭建开发环境【转】

    本文转载自:http://blog.csdn.net/wootengxjj/article/details/51758621 版权声明:本文为博主原创文章,未经博主允许不得转载. FFmpeg 是一个 ...

  8. 30.QT IDE编写

    mainwindow.h #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QTe ...

  9. kubernetes系列:(二)、kubernetes部署mysql(单节点)

    使用kubeadm搭建好kubernetes集群后就可以动手部署自己的应用了. 本文用例来自官网,如有需要请参看 kubernetes官网 一.环境说明 kubernetes 1.13.1 docke ...

  10. Kylin基础教程(一)

    一.Kylin介绍 1.1 现状 Hadoop于2006年初步实现,改变了企业级的大数据存储(基于HDFS)和批处理(主要基于MR)问题,10几年过去了,数据量随着互联网的发展井喷式增长,如何高速.低 ...