Android s5pv210 fimc driver analysis-fimc_dev.c

Source: Internet
Author: User

The fimc-dev.c is the v4l2 driver of the Samsung fimc device. Upper-layer applications directly operate on this device for capture, image processing, and overlay output.

 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 }

This function is very simple. The reason is that I got stuck for more than a week on the DMA alignment problem.

Fimc uses pre-allocated physical memory to apply for DMA buffer. Align in the parameter specifies the align method for applying for buffer. For fimc capture, it seems that output DMA requires 4 K alignment (although I did not find it in Datasheet). If the given DMA address does not have 4 K alignment, the fimc DMA controller intelligently transmits data from 4 K aligned addresses, which causes frame data offset.

@ I parameter specifies the plane number. fimc output supports many formats, including single-layer VV, two-layer v4l2_pix_fmt_nv12, and three-layer v4l2_pix_fmt_nv12t

One buffer is applied for single-layer format output, two buffer is applied for two-layer format output, and three buffer is required for three layers.

  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 }

This function has a problem, 93 ~ 95 is true if the address occupied by BS-> base [I] Must be Ctrl-> mem. base, which requires that the release sequence must be released from the last node of 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 }

The mmap implementation of the fimc capture device. CTRL-> cap-> bufs [idx] is the buffer applied by the fimc capture device. MMAP maps the buffer to the application space.

661 VMA-> vm_pgoff indicates the offset in the vm_file in the unit of page_size, but here the application layer and the kernel use another agreed meaning, buffer ID, the Application Layer calls the MMAP interface to map the buffer of the fimc capture device.

 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 provides a Wait Mechanism for the upstream application. The poll fimc device of the application is blocked until the CAP or output interrupt handler wake up.

 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 affects the result of flip. This function maps (merges) rot and flip operations.

 776 int fimc_get_scaler_factor(u32 src, u32 tar, u32 *ratio, u32 *shift) 777 { 778     if (src >= tar * 64) { 779         return -EINVAL; 780     } else if (src >= tar * 32) { 781         *ratio = 32; 782         *shift = 5; 783     } else if (src >= tar * 16) { 784         *ratio = 16; 785         *shift = 4; 786     } else if (src >= tar * 8) { 787         *ratio = 8; 788         *shift = 3; 789     } else if (src >= tar * 4) { 790         *ratio = 4; 791         *shift = 2; 792     } else if (src >= tar * 2) { 793         *ratio = 2; 794         *shift = 1; 795     } else { 796         *ratio = 1; 797         *shift = 0; 798     } 799  800     return 0; 801 }

Even if the scaler factor is used, SRC is the original resolution, and tar is the target resolution,

@ Ratio: returns the scaling ratio. The maximum scaler value cannot exceed 64.

 803 void fimc_get_nv12t_size(int img_hres, int img_vres, 804                 int *y_size, int *cb_size, int rotate)... 

Fimc_get_nv12t_size: Based on the horizontal resolution of the original image, the size of the Y component and the size of the CB component are calculated for the vertical resolution. If the image needs to be rotate, the rotate affects the alignment.

893 static int fimc_open (struct file * filp) 894 {...
 932     if (in_use == 1) { 933         fimc_clk_en(ctrl, true); 934  935         if (pdata->hw_ver == 0x40) 936             fimc_hw_reset_camera(ctrl); 937  938         /* Apply things to interface register */ 939         fimc_hwset_reset(ctrl); 940  941         if (num_registered_fb > 0) { 942             struct fb_info *fbinfo = registered_fb[0]; 943             ctrl->fb.lcd_hres = (int)fbinfo->var.xres; 944             ctrl->fb.lcd_vres = (int)fbinfo->var.yres; 945             fimc_info1("%s: fd.lcd_hres=%d fd.lcd_vres=%d\n", 946                     __func__, ctrl->fb.lcd_hres, 947                     ctrl->fb.lcd_vres); 948         } 949  950         ctrl->mem.curr = ctrl->mem.base; 951         ctrl->status = FIMC_STREAMOFF; 952  953         if (0 != ctrl->id) 954             fimc_clk_en(ctrl, false); 955     }

...

932 if it is enabled for the first time, you need to enable the mclk

939 call fimc_hwset_reset to reset the fimc Controller

951 fimc will pre-allocate a block of physical memory for each controller, mem. base points to the starting address of the physical memory. Before fimc executes the DMA, it needs to allocate the physical memory for the DMA. fimc allocates the pre-reserved space directly.

Mem. curr records the starting position of the current available space.

In ARCH/ARM/mach-s5pv210/mach-smdkc110.c:

#define  S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMC0 (24576 * SZ_1K)#define  S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMC1 (9900 * 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)

Defines the size of the reserved physical memory required by the media device. The actual usage of the physical memory cannot meet the defined size,

The size of the physical memory is proportional to the image size and the number of queue buffers. That is to say, the higher the width x height of the image resolution, the larger the number of queue buffers.

Therefore, the physical memory size should be adjusted according to the project situation. Of course, you can skip the adjustment, which is a waste of memory.

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 has three fimc0, fimc1, and fimc2 devices,

FoPs defines the file operation function of the device node; ioctl_ops defines all IOCTL operation sets provided by fimc to v4l2

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;13161317     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     }13251326     ctrl = fimc_register_controller(pdev);1327     if (!ctrl) {1328         printk(KERN_ERR "%s: cannot register fimc\n", __func__);1329         goto err_alloc;1330     }13311332     pdata = to_fimc_plat(&pdev->dev);1333     if (pdata->cfg_gpio)1334         pdata->cfg_gpio(pdev);13351336     /* 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     }13431344     /* 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 call the gpio setting function of the platform. Generally, this function is used to set the input and output of external cameraa/camerab.

1344 ~ 1364 set mclk. The frequency of mclk is determined by the size of the sensor output image. If the Peripheral sensor has a crystal oscillator, the CPU does not need to provide mclk for external use.

1381 ~ 1385 registering a video device will generate a device node/dev/videox

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.