S5PV210 多媒体预留内存空间 1 - FIMC控制器

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


FIMC0, FMIC1, FIMC2预留空间计算


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

 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[i];
 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中定义的

 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:

 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[i].length[plane] = size[plane];
 905             if (!cap->bufs[i].length[plane])
 906                 continue;
 907 
 908             fimc_dma_alloc(ctrl, &cap->bufs[i], plane, align);
 909 
 910             if (!cap->bufs[i].base[plane])
 911                 goto err_alloc;
 912         }
 913 
 914         cap->bufs[i].state = VIDEOBUF_PREPARED;
 915         cap->bufs[i].id = i;
 916     }
 917 
 918     return 0;
 919 
 920 err_alloc:
 921     for (i = 0; i < cap->nr_bufs; i++) {
 922         if (cap->bufs[i].base[plane])
 923             fimc_dma_free(ctrl, &cap->bufs[i], plane);
 924 
 925         memset(&cap->bufs[i], 0, sizeof(cap->bufs[i]));
 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的计算方法

 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




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值