s5pv210 fimc 之 fimc-dev.c
fimc-dev.c 是Samsung FIMC 设备的V4L2 驱动。上层应用直接操作这个设备,进行capture,图片处理,以及overlay输出
http://blog.csdn.net/cxw3506/article/details/8476263
- 43 int fimc_dma_alloc(struct fimc_control *ctrl, struct fimc_buf_set *bs,
- 44 int i, int align)
- 45 {
- 46 dma_addr_t end, *curr;
- 47
- 48 mutex_lock(&ctrl->alloc_lock);
- 49
- 50 end = ctrl->mem.base + ctrl->mem.size;
- 51 curr = &ctrl->mem.curr;
- 52
- 53 if (!bs->length[i])
- 54 return -EINVAL;
- 55
- 56 if (!align) {
- 57 if (*curr + bs->length[i] > end) {
- 58 goto overflow;
- 59 } else {
- 60 bs->base[i] = *curr;
- 61 bs->garbage[i] = 0;
- 62 *curr += bs->length[i];
- 63 }
- 64 } else {
- 65 if (ALIGN(*curr, align) + bs->length[i] > end)
- 66 goto overflow;
- 67 else {
- 68 bs->base[i] = ALIGN(*curr, align);
- 69 bs->garbage[i] = ALIGN(*curr, align) - *curr;
- 70 *curr += (bs->length[i] + bs->garbage[i]);
- 71 }
- 72 }
- 73
- 74 mutex_unlock(&ctrl->alloc_lock);
- 75
- 76 return 0;
- 77
- 78 overflow:
- 79 bs->base[i] = 0;
- 80 bs->length[i] = 0;
- 81 bs->garbage[i] = 0;
- 82
- 83 mutex_unlock(&ctrl->alloc_lock);
- 84
- 85 return -ENOMEM;
- 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。
- 88 void fimc_dma_free(struct fimc_control *ctrl, struct fimc_buf_set *bs, int i)
- 89 {
- 90 int total = bs->length[i] + bs->garbage[i];
- 91 mutex_lock(&ctrl->alloc_lock);
- 92
- 93 if (bs->base[i]) {
- 94 if (ctrl->mem.curr - total >= ctrl->mem.base)
- 95 ctrl->mem.curr -= total;
- 96
- 97 bs->base[i] = 0;
- 98 bs->length[i] = 0;
- 99 bs->garbage[i] = 0;
- 100 }
- 101
- 102 mutex_unlock(&ctrl->alloc_lock);
- 103 }
这个函数有问题,93 ~ 95 成立的条件是bs->base[i]所占的地址必须在ctrl->mem.base最后面,这就要求释放顺序必须从bs的最后一个节点向前释放。
- 655 static inline int fimc_mmap_cap(struct file *filp, struct vm_area_struct *vma)
- 656 {
- 657 struct fimc_prv_data *prv_data =
- 658 (struct fimc_prv_data *)filp->private_data;
- 659 struct fimc_control *ctrl = prv_data->ctrl;
- 660 u32 size = vma->vm_end - vma->vm_start;
- 661 u32 pfn, idx = vma->vm_pgoff;
- 662
- 663 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- 664 vma->vm_flags |= VM_RESERVED;
- 665
- 666 /*
- 667 * page frame number of the address for a source frame
- 668 * to be stored at.
- 669 */
- 670 pfn = __phys_to_pfn(ctrl->cap->bufs[idx].base[0]);
- 671
- 672 if ((vma->vm_flags & VM_WRITE) && !(vma->vm_flags & VM_SHARED)) {
- 673 fimc_err("%s: writable mapping must be shared\n", __func__);
- 674 return -EINVAL;
- 675 }
- 676
- 677 if (remap_pfn_range(vma, vma->vm_start, pfn, size, vma->vm_page_prot)) {
- 678 fimc_err("%s: mmap fail\n", __func__);
- 679 return -EINVAL;
- 680 }
- 681
- 682 return 0;
- 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进行映射
- 700 static u32 fimc_poll(struct file *filp, poll_table *wait)
- 701 {
- 702 struct fimc_prv_data *prv_data =
- 703 (struct fimc_prv_data *)filp->private_data;
- 704 struct fimc_control *ctrl = prv_data->ctrl;
- 705 struct fimc_capinfo *cap = ctrl->cap;
- 706 u32 mask = 0;
- 707
- 708 if (cap) {
- 709 if (cap->irq || (ctrl->status != FIMC_STREAMON)) {
- 710 mask = POLLIN | POLLRDNORM;
- 711 cap->irq = 0;
- 712 } else {
- 713 poll_wait(filp, &ctrl->wq, wait);
- 714 }
- 715 }
- 716
- 717 return mask;
- 718 }
fimc_poll向上层应用提供了等待机制,应用程序poll fimc设备并阻塞,直到cap或者output中断处理函数唤醒
- 732 u32 fimc_mapping_rot_flip(u32 rot, u32 flip)
- 733 {
- 734 u32 ret = 0;
- 735
- 736 switch (rot) {
- 737 case 0:
- 738 if (flip & FIMC_XFLIP)
- 739 ret |= FIMC_XFLIP;
- 740
- 741 if (flip & FIMC_YFLIP)
- 742 ret |= FIMC_YFLIP;
- 743 break;
- 744
- 745 case 90:
- 746 ret = FIMC_ROT;
- 747 if (flip & FIMC_XFLIP)
- 748 ret |= FIMC_XFLIP;
- 749
- 750 if (flip & FIMC_YFLIP)
- 751 ret |= FIMC_YFLIP;
- 752 break;
- 753
- 754 case 180:
- 755 ret = (FIMC_XFLIP | FIMC_YFLIP);
- 756 if (flip & FIMC_XFLIP)
- 757 ret &= ~FIMC_XFLIP;
- 758
- 759 if (flip & FIMC_YFLIP)
- 760 ret &= ~FIMC_YFLIP;
- 761 break;
- 762
- 763 case 270:
- 764 ret = (FIMC_XFLIP | FIMC_YFLIP | FIMC_ROT);
- 765 if (flip & FIMC_XFLIP)
- 766 ret &= ~FIMC_XFLIP;
- 767
- 768 if (flip & FIMC_YFLIP)
- 769 ret &= ~FIMC_YFLIP;
- 770 break;
- 771 }
- 772
- 773 return ret;
- 774 }
rot会影响flip的结果,该函数映射(合并)rot和 flip操作
- static int fimc_open(struct file *filp)
- {
- struct fimc_control *ctrl;
- struct s3c_platform_fimc *pdata;
- struct fimc_prv_data *prv_data;
- int in_use;
- int ret;
- ctrl = video_get_drvdata(video_devdata(filp));
- pdata = to_fimc_plat(ctrl->dev);
- mutex_lock(&ctrl->lock);
- in_use = atomic_read(&ctrl->in_use);
- if (in_use >= FIMC_MAX_CTXS || (in_use && 1 != ctrl->id)) {
- fimc_err("%s: Device busy.\n", __func__);
- ret = -EBUSY;
- goto resource_busy;
- } else {
- atomic_inc(&ctrl->in_use);
- }
- in_use = atomic_read(&ctrl->in_use);
- prv_data = kzalloc(sizeof(struct fimc_prv_data), GFP_KERNEL);
- if (!prv_data) {
- fimc_err("%s: not enough memory\n", __func__);
- ret = -ENOMEM;
- goto kzalloc_err;
- }
- prv_data->ctx_id = fimc_get_free_ctx(ctrl);
- if (prv_data->ctx_id < 0) {
- fimc_err("%s: Context busy flag not reset.\n", __func__);
- ret = -EBUSY;
- goto ctx_err;
- }
- prv_data->ctrl = ctrl;
- filp->private_data = prv_data;
- if (in_use == 1) {
- fimc_clk_en(ctrl, true);
- if (pdata->hw_ver == 0x40)
- fimc_hw_reset_camera(ctrl);
- /* Apply things to interface register */
- fimc_hwset_reset(ctrl);
- if (num_registered_fb > 0) {
- struct fb_info *fbinfo = registered_fb[0];
- ctrl->fb.lcd_hres = (int)fbinfo->var.xres;
- ctrl->fb.lcd_vres = (int)fbinfo->var.yres;
- fimc_info1("%s: fd.lcd_hres=%d fd.lcd_vres=%d\n",
- __func__, ctrl->fb.lcd_hres,
- ctrl->fb.lcd_vres);
- }
- ctrl->mem.curr = ctrl->mem.base;
- ctrl->status = FIMC_STREAMOFF;
- if (0 != ctrl->id)
- fimc_clk_en(ctrl, false);
- }
- mutex_unlock(&ctrl->lock);
- fimc_info1("%s opened.\n", ctrl->name);
- return 0;
- ctx_err:
- kfree(prv_data);
- kzalloc_err:
- atomic_dec(&ctrl->in_use);
- resource_busy:
- mutex_unlock(&ctrl->lock);
- return ret;
- }
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中
- //#define S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMC0 (6144 * SZ_1K)
- #define S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMC0 (24576 * SZ_1K)
- #define S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMC1 (9900 * SZ_1K)
- //#define S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMC2 (6144 * SZ_1K)
- #define S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMC2 (24576 * SZ_1K)
- #define S5PV210_VIDEO_SAMSUNG_MEMSIZE_MFC0 (36864 * SZ_1K)
- #define S5PV210_VIDEO_SAMSUNG_MEMSIZE_MFC1 (36864 * SZ_1K)
- #define S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMD (S5PV210_LCD_WIDTH * \
- S5PV210_LCD_HEIGHT * 4 * \
- CONFIG_FB_S3C_NR_BUFFERS)
- #define S5PV210_VIDEO_SAMSUNG_MEMSIZE_JPEG (8192 * SZ_1K)<span>
- <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>
- 物理内存的使用大小 和图片大小以及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>
- 所以这个物理内存大小要根据项目情况具体调整,当然你也可以不调,就是浪费点内存。
- </span></span></span>
- <pre name="code" class="cpp">1133 struct video_device fimc_video_device[FIMC_DEVICES] = {
- 1134 [0] = {
- 1135 .fops = &fimc_fops,
- 1136 .ioctl_ops = &fimc_v4l2_ops,
- 1137 .release = fimc_vdev_release,
- 1138 },
- 1139 [1] = {
- 1140 .fops = &fimc_fops,
- 1141 .ioctl_ops = &fimc_v4l2_ops,
- 1142 .release = fimc_vdev_release,
- 1143 },
- 1144 [2] = {
- 1145 .fops = &fimc_fops,
- 1146 .ioctl_ops = &fimc_v4l2_ops,
- 1147 .release = fimc_vdev_release,
- 1148 },
- 1149 };
- FIMC_DEVICES 一共有三个fimc0, fimc1, fimc2设备,
- fops定义了设备节点的文件操作函数; ioctl_ops定义了fimc向V4L2提供的所有ioctl操作集合</pre><pre name="code" class="cpp">1310 static int __devinit fimc_probe(struct platform_device *pdev)
- 1311 {
- 1312 struct s3c_platform_fimc *pdata;
- 1313 struct fimc_control *ctrl;
- 1314 struct clk *srclk;
- 1315 int ret;
- 1316
- 1317 if (!fimc_dev) {
- 1318 fimc_dev = kzalloc(sizeof(*fimc_dev), GFP_KERNEL);
- 1319 if (!fimc_dev) {
- 1320 dev_err(&pdev->dev, "%s: not enough memory\n",
- 1321 __func__);
- 1322 return -ENOMEM;
- 1323 }
- 1324 }
- 1325
- 1326 ctrl = fimc_register_controller(pdev);
- 1327 if (!ctrl) {
- 1328 printk(KERN_ERR "%s: cannot register fimc\n", __func__);
- 1329 goto err_alloc;
- 1330 }
- 1331
- 1332 pdata = to_fimc_plat(&pdev->dev);
- 1333 if (pdata->cfg_gpio)
- 1334 pdata->cfg_gpio(pdev);
- 1335
- 1336 /* Get fimc power domain regulator */
- 1337 ctrl->regulator = regulator_get(&pdev->dev, "pd");
- 1338 if (IS_ERR(ctrl->regulator)) {
- 1339 fimc_err("%s: failed to get resource %s\n",
- 1340 __func__, "s3c-fimc");
- 1341 return PTR_ERR(ctrl->regulator);
- 1342 }
- 1343
- 1344 /* fimc source clock */
- 1345 srclk = clk_get(&pdev->dev, pdata->srclk_name);
- 1346 if (IS_ERR(srclk)) {
- 1347 fimc_err("%s: failed to get source clock of fimc\n",
- 1348 __func__);
- 1349 goto err_v4l2;
- 1350 }
- 1351
- 1352 /* fimc clock */
- 1353 ctrl->clk = clk_get(&pdev->dev, pdata->clk_name);
- 1354 if (IS_ERR(ctrl->clk)) {
- 1355 fimc_err("%s: failed to get fimc clock source\n",
- 1356 __func__);
- 1357 goto err_v4l2;
- 1358 }
- 1359
- 1360 /* set parent for mclk */
- 1361 clk_set_parent(ctrl->clk, srclk);
- 1362
- 1363 /* set rate for mclk */
- 1364 clk_set_rate(ctrl->clk, pdata->clk_rate);
- 1365
- 1366 /* V4L2 device-subdev registration */
- 1367 ret = v4l2_device_register(&pdev->dev, &ctrl->v4l2_dev);
- 1368 if (ret) {
- 1369 fimc_err("%s: v4l2 device register failed\n", __func__);
- 1370 goto err_fimc;
- 1371 }
- 1372
- 1373 /* things to initialize once */
- 1374 if (!fimc_dev->initialized) {
- 1375 ret = fimc_init_global(pdev);
- 1376 if (ret)
- 1377 goto err_v4l2;
- 1378 }
- 1379
- 1380 /* video device register */
- 1381 ret = video_register_device(ctrl->vd, VFL_TYPE_GRABBER, ctrl->id);
- 1382 if (ret) {
- 1383 fimc_err("%s: cannot register video driver\n", __func__);
- 1384 goto err_v4l2;
- 1385 }
- 1386
- 1387 video_set_drvdata(ctrl->vd, ctrl);
- 1388
- 1389 ret = device_create_file(&(pdev->dev), &dev_attr_log_level);
- 1390 if (ret < 0) {
- 1391 fimc_err("failed to add sysfs entries\n");
- 1392 goto err_global;
- 1393 }
- 1394 printk(KERN_INFO "FIMC%d registered successfully\n", ctrl->id);
- 1395
- 1396 return 0;
- 1397
- 1398 err_global:
- 1399 video_unregister_device(ctrl->vd);
- 1400
- 1401 err_v4l2:
- 1402 v4l2_device_unregister(&ctrl->v4l2_dev);
- 1403
- 1404 err_fimc:
- 1405 fimc_unregister_controller(pdev);
- 1406
- 1407 err_alloc:
- 1408 kfree(fimc_dev);
- 1409 return -EINVAL;
- 1410
- 1411 }
- 1333 ~ 1334 调用平台的gpio设置函数,一般来说,这个用来设置external CameraA/CameraB的输入输出
- 1344 ~ 1364 设置mclk,mclk的频率由sensor的输出图像尺寸, 如果外围sensor自身有晶振,那么CPU不需要对外提供mclk
- 1381 ~ 1385 注册一个video device,会生成设备节点/dev/videoX
- </pre><br>
- <br>
- <p></p>
- <pre></pre>
- <p></p>
- <p><br>
- </p>
s5pv210 fimc 之 fimc-dev.c的更多相关文章
- android camera(三):camera V4L2 FIMC
1. V4L2 1)简介 在Linux中,摄像头方面的标准化程度比较高,这个标准就是V4L2驱动程序,这也是业界比较公认的方式. V4L全称是Video for Linux,是Linux内核中标准的关 ...
- 【转】android camera(三):camera V4L2 FIMC
关键词:android camera CMM 模组 camera参数 CAMIF V4L2 平台信息:内核:linux系统:android 平台:S5PV310(samsung exynos ...
- Tiny210v2( S5PV210 )平台下创建基本根文件系统
转自Tiny210v2( S5PV210 )平台下创建基本根文件系统 0. 概要介绍 ========================================================= ...
- 基于Linux 3.0.8 Samsung FIMC(S5PV210) 的摄像头驱动框架解读(一)
作者:咕唧咕唧liukun321 来自:http://blog.csdn.net/liukun321 FIMC这个名字应该是从S5PC1x0開始出现的.在s5pv210里面的定义是摄像头接口.可是它相 ...
- (转)S5PV210 三个Camera Interface/CAMIF/FIMC的区别
原文出处:http://blog.csdn.net/kickxxx/article/details/7728947 S5PV210有三个CAMIF单元,分别为CAMIF0 CAMIF1和CAMIF2. ...
- S5PV210 三个Camera Interface/CAMIF/FIMC的区别
S5PV210有三个CAMIF单元,分别为CAMIF0 CAMIF1和CAMIF2.对应着驱动中的fimc0, fimc1, fimc2.在三星datasheet和驱动代码中CAMIF和FIMC(Fu ...
- Android S5PV210 fimc驱动分析 - fimc_capture.c
fimc_capture.c在FIMC系统中的位置,网上偷来的一幅图片 http://blog.csdn.net/kickxxx/article/details/7733482 43 static c ...
- 基于S5PC100的FIMC控制器解析
作者:邹南,华清远见嵌入式学院讲师. http://www.cnblogs.com/gooogleman/archive/2012/07/26/2610449.html CAMERA SENSOR O ...
- S5PV210 时钟体系分析
S5PV210 时钟体系 如下面时钟结构图所示,S5PV210 中包含 3 大类时钟域, 分别是主系统时钟域(简称 MSYS).显示相关的时钟域(简称 DSYS). 外围设备的时钟域(简称 PSYS) ...
随机推荐
- 定时器SDK
定时器是一切SDK的根本,欲写SDK必先确定定时器,定时器效率的高低决定着SDK函数的效率,下面是我个人写的Linux C++服务器端进程SDK中的定时器,部分参照了ACE和RocketMQ定时器的思 ...
- [SharePoint][SharePoint Designer 入门经典]Chapter7 数据源和外部内容类型
本章概要: 1.SharePoint能够使用的数据类型 2.如何从SharePoint列表和库中取得数据并展现出来 3.SharePoint访问远程数据 4.如何把外部数据源作为列表展现在你的SPS站 ...
- ios基础-分辨率适配
(一)分辨率定义 分辨率,是指单位长度内包括的像素点的数量,它的单位通常为像素/英寸(ppi).描写叙述分辨率的单位有:(dpi点每英寸).lpi(线每英寸)和ppi(像素每英寸). (二)ios分辨 ...
- Oracle 用户管理(一)
1 创建用户 create user @username identified by @password 比如:create user aobama identified by ...
- Linux环境thinkphp配置以及数据源驱动改动
项目中须要用到thinkphp,以下简称tp. linux版本号:64位CentOS 6.4 Nginx版本号:nginx1.8.0 php版本号:php5.5.28 thinkphp版:3.2.3 ...
- 每天一个JavaScript实例-tab标签切换
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...
- FFMpeg在Windows下搭建开发环境【转】
本文转载自:http://blog.csdn.net/wootengxjj/article/details/51758621 版权声明:本文为博主原创文章,未经博主允许不得转载. FFmpeg 是一个 ...
- 30.QT IDE编写
mainwindow.h #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QTe ...
- kubernetes系列:(二)、kubernetes部署mysql(单节点)
使用kubeadm搭建好kubernetes集群后就可以动手部署自己的应用了. 本文用例来自官网,如有需要请参看 kubernetes官网 一.环境说明 kubernetes 1.13.1 docke ...
- Kylin基础教程(一)
一.Kylin介绍 1.1 现状 Hadoop于2006年初步实现,改变了企业级的大数据存储(基于HDFS)和批处理(主要基于MR)问题,10几年过去了,数据量随着互联网的发展井喷式增长,如何高速.低 ...