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