5069|2

468

帖子

0

TA的资源

纯净的硅(高级)

楼主
 

S5PV210 多媒体预留内存空间 1 - FIMC控制器 [复制链接]

由于GPU 多媒体解码 camera输入以及overlay显示等操作需要大块的连续物理内存,S5PV210开发板在初始化的过程中,会为这些多媒体相关驱动预留内存,这些预留的物理内存不能再被系统的其他部件使用,因此调整这些预留空间使之既能满足项目的需求,同时把浪费部分最小化,有必要分析每一部分内存需求的计算公式。


FIMC0, FMIC1, FIMC2预留空间计算


在arch/arm/plat-s5p/bootmem.c中,s5p_reserve_bootmem为media设备预留内存


[cpp] view plaincopy


  • 80 void s5p_reserve_bootmem(struct s5p_media_device *mdevs, int nr_mdevs)  
  • 81 {  
  • 82     struct s5p_media_device *mdev;  
  • 83     void *virt_mem;  
  • 84     int i;  
  • 85  
  • 86     media_devs = mdevs;  
  • 87     nr_media_devs = nr_mdevs;  
  • 88  
  • 89     for (i = 0; i < nr_media_devs; i++) {  
  • 90         mdev = &media_devs;  
  • 91         if (mdev->memsize <= 0)  
  • 92             continue;  
  • 93  
  • 94         if (mdev->paddr)  
  • 95             virt_mem = __alloc_bootmem(mdev->memsize, PAGE_SIZE,  
  • 96                     mdev->paddr);  
  • 97         else {  
  • 98             printk(KERN_INFO "s5pv210: meminfo.back[mdev->bank].start=0x%08lx\n",  
  • 99                     meminfo.bank[mdev->bank].start);  
  • 100             virt_mem = __alloc_bootmem(mdev->memsize, PAGE_SIZE,  
  • 101                     meminfo.bank[mdev->bank].start);  
  • 102         }  
  • 103  
  • 104         if (virt_mem != NULL) {  
  • 105             mdev->paddr = virt_to_phys(virt_mem);  
  • 106         } else {  
  • 107             mdev->paddr = (dma_addr_t)NULL;  
  • 108             printk(KERN_INFO "s5p: Failed to reserve system memory\n");  
  • 109         }  
  • 110  
  • 111         printk(KERN_INFO "s5pv210: %lu bytes system memory reserved "  
  • 112             "for %s at 0x%08x\n", (unsigned long) mdev->memsize,  
  • 113             mdev->name, mdev->paddr);  
  • 114     }  
  • 115 }  



@mdevs 是在mach-s5pv210.c中定义的

[cpp] view plaincopy


  • 174 #define  S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMC0 (24576 * SZ_1K)  
  • 175 #define  S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMC1 (9900 * SZ_1K)  
  •   
  • 177 #define  S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMC2 (24576 * SZ_1K)  
  • 178 #define  S5PV210_VIDEO_SAMSUNG_MEMSIZE_MFC0 (36864 * SZ_1K)  
  • 179 #define  S5PV210_VIDEO_SAMSUNG_MEMSIZE_MFC1 (36864 * SZ_1K)  
  • 180 #define  S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMD (S5PV210_LCD_WIDTH * \  
  • 181                          S5PV210_LCD_HEIGHT * 4 * \  
  • 182                          CONFIG_FB_S3C_NR_BUFFERS)  
  • 183 #define  S5PV210_VIDEO_SAMSUNG_MEMSIZE_JPEG (8192 * SZ_1K)  
  • 184  
  • 185 /* 1920 * 1080 * 4 (RGBA)
  • 186  * - framesize == 1080p : 1920 * 1080 * 2(16bpp) * 2(double buffer) = 8MB
  • 187  * - framesize <  1080p : 1080 *  720 * 4(32bpp) * 2(double buffer) = under 8MB
  • 188  **/  
  • 189 #define  S5PV210_VIDEO_SAMSUNG_MEMSIZE_G2D (8192 * SZ_1K)  
  • 190 #define  S5PV210_VIDEO_SAMSUNG_MEMSIZE_TEXSTREAM (3000 * SZ_1K)  
  • 191 #define  S5PV210_ANDROID_PMEM_MEMSIZE_PMEM_GPU1 (3300 * SZ_1K)  
  • 192  
  • 193 static struct s5p_media_device smdkc110_media_devs[] = {  
  • 194     [0] = {  
  • 195         .id = S5P_MDEV_MFC,  
  • 196         .name = "mfc",  
  • 197         .bank = 0,  
  • 198         .memsize = S5PV210_VIDEO_SAMSUNG_MEMSIZE_MFC0,  
  • 199         .paddr = 0,  
  • 200     },  
  • 201     [1] = {  
  • 202         .id = S5P_MDEV_MFC,  
  • 203         .name = "mfc",  
  • 204         .bank = 1,  
  • 205         .memsize = S5PV210_VIDEO_SAMSUNG_MEMSIZE_MFC1,  
  • 206         .paddr = 0,  
  • 207     },  
  • 208     [2] = {  
  • 209         .id = S5P_MDEV_FIMC0,  
  • 210         .name = "fimc0",  
  • 211         .bank = 1,  
  • 212         .memsize = S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMC0,  
  • 213         .paddr = 0,  
  • 214     },  
  • 215     [3] = {  
  • 216         .id = S5P_MDEV_FIMC1,  
  • 217         .name = "fimc1",  
  • 218         .bank = 1,  
  • 219         .memsize = S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMC1,  
  • 220         .paddr = 0,  
  • 221     },  
  • 222     [4] = {  
  • 223         .id = S5P_MDEV_FIMC2,  
  • 224         .name = "fimc2",  
  • 225         .bank = 1,  
  • 226         .memsize = S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMC2,  
  • 227         .paddr = 0,  
  • 228     },  
  • 229     [5] = {  
  • 230         .id = S5P_MDEV_JPEG,  
  • 231         .name = "jpeg",  
  • 232         .bank = 0,  
  • 233         .memsize = S5PV210_VIDEO_SAMSUNG_MEMSIZE_JPEG,  
  • 234         .paddr = 0,  
  • 235     },  
  • 236     [6] = {  
  • 237         .id = S5P_MDEV_FIMD,  
  • 238         .name = "fimd",  
  • 239         .bank = 1,  
  • 240         .memsize = S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMD,  
  • 241         .paddr = 0,  
  • 242     },  
  • 243     [7] = {  
  • 244         .id = S5P_MDEV_TEXSTREAM,  
  • 245         .name = "texstream",  
  • 246         .bank = 1,  
  • 247         .memsize = S5PV210_VIDEO_SAMSUNG_MEMSIZE_TEXSTREAM,  
  • 248         .paddr = 0,  
  • 249     },  
  • 250     [8] = {  
  • 251         .id = S5P_MDEV_PMEM_GPU1,  
  • 252         .name = "pmem_gpu1",  
  • 253         .bank = 0, /* OneDRAM */  
  • 254         .memsize = S5PV210_ANDROID_PMEM_MEMSIZE_PMEM_GPU1,  
  • 255         .paddr = 0,  
  • 256     },  
  • 257     [9] = {  
  • 258         .id = S5P_MDEV_G2D,  
  • 259         .name = "g2d",  
  • 260         .bank = 0,  
  • 261         .memsize = S5PV210_VIDEO_SAMSUNG_MEMSIZE_G2D,  
  • 262         .paddr = 0,  
  • 263     },  
  • 264 };   


结构smdkc110_media_devs定义了每个驱动的名字,物理内存的bank位置,需要的物理内存大小,以及希望的物理内存位置

下面我们一一分析如何计算每个驱动实际需要的物理内存大小


FIMC0,原生代码预留了32MB的物理内存空间

关于fimc0, fimc1, fimc2控制器的作用,参看http://blog.csdn.net/kickxxx/article/details/7728947

FIMC0在拍照以及preview时,系统从camera sensor获取数据时使用。拍照或者preview的数据需要放在request buffer中,应用通过VIDIOC_REQBUFS从内核申请request buffer,kernel从这块预留的物理内存分配buffer:


[cpp] view plaincopy


  • 897 static int fimc_alloc_buffers(struct fimc_control *ctrl, int size[], int align)  
  • 898 {  
  • 899     struct fimc_capinfo *cap = ctrl->cap;  
  • 900     int i, plane;  
  • 901   
  • 902     for (i = 0; i < cap->nr_bufs; i++) {  
  • 903         for (plane = 0; plane < 4; plane++) {  
  • 904             cap->bufs.length[plane] = size[plane];  
  • 905             if (!cap->bufs.length[plane])  
  • 906                 continue;  
  • 907   
  • 908             fimc_dma_alloc(ctrl, &cap->bufs, plane, align);  
  • 909   
  • 910             if (!cap->bufs.base[plane])  
  • 911                 goto err_alloc;  
  • 912         }  
  • 913   
  • 914         cap->bufs.state = VIDEOBUF_PREPARED;  
  • 915         cap->bufs.id = i;  
  • 916     }  
  • 917   
  • 918     return 0;  
  • 919   
  • 920 err_alloc:  
  • 921     for (i = 0; i < cap->nr_bufs; i++) {  
  • 922         if (cap->bufs.base[plane])  
  • 923             fimc_dma_free(ctrl, &cap->bufs, plane);  
  • 924   
  • 925         memset(&cap->bufs, 0, sizeof(cap->bufs));  
  • 926     }  
  • 927   
  • 928     return -ENOMEM;  
  • 929 }  


预留空间计算公式 = cam->nr_bufs * SUM(size),因此CameraHal的申请的buffer队列越大,需要预留的空间越多,CameraHal中定义buffer count 为 8,此外kenerl本身也有一个最大限制FIMC_CAPBUFS(16)



@size之所以是个数组,是因为不同的pixelformat对应的层数不一样,size的大小和preview,capture的图片大小是成正比的,因此系统支持的camera sensor分辨率越高,@size越大

我们看下@size的计算方法


[cpp] view plaincopy


  • 950 int fimc_reqbufs_capture(void *fh, struct v4l2_requestbuffers *b)  
  •   
  • ..............  
  •   
  • 996     switch (cap->fmt.pixelformat) {  
  • 997     case V4L2_PIX_FMT_RGB32:    /* fall through */  
  • 998     case V4L2_PIX_FMT_RGB565:   /* fall through */  
  • 999     case V4L2_PIX_FMT_YUYV:     /* fall through */  
  • 1000     case V4L2_PIX_FMT_UYVY:     /* fall through */  
  • 1001     case V4L2_PIX_FMT_VYUY:     /* fall through */  
  • 1002     case V4L2_PIX_FMT_YVYU:     /* fall through */  
  • 1003     case V4L2_PIX_FMT_YUV422P:  /* fall through */  
  • 1004         size[0] = cap->fmt.sizeimage;  
  • 1005         break;  
  • 1006   
  • 1007     case V4L2_PIX_FMT_NV16:     /* fall through */  
  • 1008     case V4L2_PIX_FMT_NV61:  
  • 1009         size[0] = cap->fmt.width * cap->fmt.height;  
  • 1010         size[1] = cap->fmt.width * cap->fmt.height;  
  • 1011         size[3] = 16; /* Padding buffer */  
  • 1012         break;  
  • 1013     case V4L2_PIX_FMT_NV12:  
  • 1014         size[0] = cap->fmt.width * cap->fmt.height;  
  • 1015         size[1] = cap->fmt.width * cap->fmt.height/2;  
  • 1016         break;  
  • 1017     case V4L2_PIX_FMT_NV21:  
  • 1018         size[0] = cap->fmt.width * cap->fmt.height;  
  • 1019         size[1] = cap->fmt.width * cap->fmt.height/2;  
  • 1020         size[3] = 16; /* Padding buffer */  
  • 1021         break;  
  • 1022     case V4L2_PIX_FMT_NV12T:  
  • 1023         /* Tiled frame size calculations as per 4x2 tiles
  • 1024          *  - Width: Has to be aligned to 2 times the tile width
  • 1025          *  - Height: Has to be aligned to the tile height
  • 1026          *  - Alignment: Has to be aligned to the size of the
  • 1027          *  macrotile (size of 4 tiles)
  • 1028          *
  • 1029          * NOTE: In case of rotation, we need modified calculation as
  • 1030          * width and height are aligned to different values.
  • 1031          */  
  • 1032         if (cap->rotate == 90 || cap->rotate == 270) {  
  • 1033             size[0] = ALIGN(ALIGN(cap->fmt.height, 128) *  
  • 1034                     ALIGN(cap->fmt.width, 32),  
  • 1035                     SZ_8K);  
  • 1036             size[1] = ALIGN(ALIGN(cap->fmt.height, 128) *  
  • 1037                     ALIGN(cap->fmt.width/2, 32),  
  • 1038                     SZ_8K);  
  • 1039         } else {  
  • 1040             size[0] = ALIGN(ALIGN(cap->fmt.width, 128) *  
  • 1041                     ALIGN(cap->fmt.height, 32),  
  • 1042                     SZ_8K);  
  • 1043             size[1] = ALIGN(ALIGN(cap->fmt.width, 128) *  
  • 1044                     ALIGN(cap->fmt.height/2, 32),  
  • 1045                     SZ_8K);  
  • 1046         }  
  • 1047         align = SZ_8K;  
  • 1048         break;  
  • 1049   
  • 1050     case V4L2_PIX_FMT_YUV420:  
  • 1051         size[0] = cap->fmt.width * cap->fmt.height;  
  • 1052         size[1] = cap->fmt.width * cap->fmt.height >> 2;  
  • 1053         size[2] = cap->fmt.width * cap->fmt.height >> 2;  
  • 1054         size[3] = 16; /* Padding buffer */  
  • 1055         break;  
  • 1056   
  • 1057     case V4L2_PIX_FMT_JPEG:  
  • 1058         size[0] = fimc_camera_get_jpeg_memsize(ctrl);  
  • 1059     default:  
  • 1060         break;  
  • 1061     }  
  •   
  • ...............   


fmt.width和fmt.height 和capture需要的图片尺寸大小或者preview的大小相关,因此需要根据项目预估这个值,我们的项目使用的是video  AD转换芯片,sensor raw size最大为720*576,preview最大为WVGA 800*480,取二者的最大值720*576

一般来说上层应用使用YUYV或者NV12T作为image格式,考虑对齐方式和安全边界,那么每个buffer最大不会超过1024KB


因此我们可以大致估算FIMC0预留空间大小:

cam->nr_bufs * SUM(size) = 16 * 720 * 576 * 2 = 13MB


FIMC2

Recording过程中,中间件使用fimc0获取preview数据,使用fimc2获取recording的数据

预留空间计算公式 = buffer_count * (record_width * record_height * pixel_size)

CameraHal层在调用REQBUFS时指定buffer count大小为8,kernel对申请request buffer的数目限制为16

一般来说录像的宽高等于LCD的尺寸(当然这是项目相关的)

所以对于WVGA计算得到

cam->nr_bufs * (record_width * record_height * pixel_size) = 16 * (800 * 480 * 2) =13MB


FIMC1
FIMC1用来实现overlay功能,不论是camera preview还是视频播放,都会通过FIMC1进行数据转换,预留的内存空间用来保存转换后的数据,转换的image大小是和LCD屏尺寸相关

FIMC1预留空间计算公式=buffer_count * (lcd_width * lcd_height * pixel_size) + buffer_count *(video_width * video_height * pixel_size)

对于WVGA lcd, lcd_width=800, lcd_height=480, pixel_size根据pixelformat不同,分别为4, 2, 1.5,这里取最大值4

Video_width和video_height是解码后的视频宽高,有些解码器需要从overlay设备分配这个解码后端buffer,但有些解码器不需要从FIMC1申请内存。samsung平台的有些解码器在从FIMC1申请buffer失败后,会转到软件显示(surfaceflinger),申请后端解码buffer失败则转到软件解码。用例比较多,我自己也没搞太清楚。

buffer count虽然是CameraHAL申请request buffer 时设定的,但是kernel对最大buffer count做了限制 为FIMC_OUTBUFS=3

buffer_count * (lcd_width * lcd_height * pixel_size) = 3 * (800 * 480 * 4) = 4608000

buffer_count * (1080p * 3) = 3 * 1980 * 1300 * 4 = 29.45MB,注意这里的1300,我们一般认为1080P的高度为1080,实际上仍然有些不规范的视频高度超过了1300,三星在fimc_output.c对最大输入高度做了限制FIMC_SRC_MAX_H = 1300,所以在这里我们以1300为准

考虑对齐等因素,需要为FIMC1预留35MB



转载文章原文地址 http://blog.csdn.net/kickxxx/article/details/8064585  这位老兄对摄像头多媒体颇有研究啊。现在来学习学习。

最新回复

感谢楼主分享   详情 回复 发表于 2021-4-26 14:53
点赞 关注
个人签名

回复
举报

468

帖子

0

TA的资源

纯净的硅(高级)

沙发
 

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

S5PV210有三个CAMIF单元,分别为CAMIF0 CAMIF1和CAMIF2。对应着驱动中的fimc0, fimc1, fimc2。在三星datasheet和驱动代码中CAMIF和FIMC(Fully Interactive Mobile Camera)这两个术语基本上可以互换的,后面我们都用FIMC代替CAMIF。这两个术语的称呼有很强的模糊性,尤其刚刚接触三星平台,会觉得这三个接口设备都是用来控制camera,实际上三个接口并不局限于只控制camera。

我们先看下datasheet中定义的CAMIF feature - 输入支持

    1. ITU-R BT601/656/709 mode

    2. DMA模式

    3. MIPI(CSI)模式

    4. Direct FIFO 模式

1 和3是典型的camera输入接口,用来处理输入的camere sensor的信号

而2则是DMA内存输入模式,FIMC的输入是DMA内存中的图像数据,FIMC负责进行图像color space 的转换,图像的scaler处理。


因此,每个FIMC既可以做为camera 输入ITU或MIPI的处理单元,此时就为capture设备,也可以作为内存图像的处理单元,此时做为output 设备或者overlay设备。


Camera A, Camera B,Camera C这三个物理接口和FIMC们也不是一回事,下图说明了前者和后者的关系,当FIMC工作在1,3模式(做为capture设备)时,Camera A/B/C是FIMC的输入。

Camera A/B是ITU类型;Camera C是MIPI类型的接口,配置FIMC寄存器决定FIMC从Camera A/B/C中的哪一个获取camera数据。

注意一个物理接口可以同时作为多个FIMC的输入源。


在android平台上:

FIMC0 用于拍照 以及preview时,从camera sensor获取数据

FIMC1 用于camera 的preview环节或者视频播放器的视频输出,S5PV210 overlay功能的驱动部分就是通过FIMC1来实现的

FIMC2 用于录像时,从camera sensor获取数据,提供给上层应用使用。

注意,在驱动层并没有对这三个控制器进行上述功能的划分,三个控制器是通用的。上诉功能的划分完全是CameraHAL和OverlayHAL实现的。

 
个人签名
 

回复

661

帖子

0

TA的资源

纯净的硅(初级)

板凳
 

感谢楼主分享

 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/7 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表