如之前所说,一直想知道显示数据都在哪个地方,通常的数据,比如 framebuffer 中的显示数据,和OpenGL 处理的数据有啥关系。 目前为止我还没有弄明白 OpenGL 这块,但是 framebuffer 这部分差不多了。这篇文章记录了 framebuffer 的显示数据相关内容。 1. 关于FIMD Tiny210v2 开发板属于 s5pv210 的一种,在这块开发板上,显示部分又被叫做 FIMD,我不知道FIMD是什么的缩写,但D应该和Display Controller有关系吧。 FIMD 的主要功能就是获取显示数据,并将数据输出到显示屏。当然期间会对显示数据进行处理: FIMD一共支持5个layer,在SoC用户手册中,将layer成为window,源代码中也叫做window。 FIMD可以通过AXI总线从内存或者Camera哪里获取到显示数据,并进行合成。 2. 内核配置 framebuffer 通过 make menuconfig 可以配置 framebuffer 相关的内容。 保存以后,在 .config 文件中可以找到相关配置内容。 .config --------------------------------------------------
同样也会在头文件中生成宏定义: include/generated/autoconf.h --------------------------------------------------
CONFIG_FB_S3C_DEFAULT_WINDOW 是指 默认的 window, 0-4。 CONFIG_FB_S3C_NR_BUFFERS 是指 window 的buffer数,3个就是 trebble-buffer,2个就是double-buffer。 其中第一个是正在显示的数据,又叫onscreen,其他几个是后台描画的数据,又叫offscreen,通过 flip 操作可以将 onscreen 数据和offscreen 数据交换。 CONFIG_FB_S3C_NUM_OVLY_WIN 是 OVERLAY window, 0-4。 CONFIG_FB_S3C_NUM_BUF_OVLY_WIN 是指 OVERLAY window 的buffer数,和 CONFIG_FB_S3C_NR_BUFFERS 一个意思。 3. 显示数据buffer 内核初始话过程中,为这些window 的 buffer 预留了一部分内存。 具体看下面的代码: 初始化函数会首先映射内存空间:
在映射内存空间中,保留了一部分内存,保留的大小就和window 以及 buffer数有关系: 大小是 800 x 480 x 2个window x 3个buffer x RGBA的4字节,这是给通常显示数据的, 除此之外,还预留了 YUV 的数据区域,1280 x 720 x 3个buffer x Y的一个字节数据 + 1280 x 720 x 3个buffer x UV的一个字节数据。 另外还有一个 4096 字节大小的 数据。 这些数据我只理解了 RGBA 数据, YUV 的数据不知道是干啥的? 难道是给 HDMI 输出用的? arch/arm/mach-sp5v210/Mach-mini210.c --------------------------------------------------
这些内存是PAGE对齐的,对齐的部分参考下面的算法。 PAGE_SIZE 大小是 4096。 include/linux/Const.h --------------------------------------------------
arch/arm/include/asm/Page.h --------------------------------------------------
include/linux/Kernel.h --------------------------------------------------
4. 内核关于FIMD内存预留的相关debug log 在内核的 boot log 中,我们可以找到关于内存预留的log: dmesg log : -------------------------------------------------- [ 0.000000] s5p: 13060 kbytes system memory reserved for fimd at 0x3c330000, 1-bank base(0x3c330000) [ 0.648804] fimd at 0x3c330000 5. 物理内存视图 画了一个简单的物理内存布局图,可以看到 RGBA 部分的数据,其实一共给 2 个 window 预留了。 | | |--------------| | |0x3CFF0000 -- 0x3CFF0FFF || ???? |--------------| | |0x3CF7F000 -- 0x3CFEFFFF || |--------------| || | |0x3CF0E000 -- 0x3CF7EFFF || treble-buffer YUV( UV ) framebuffer : 1280 x 360 x 1 byte |--------------| || | |0x3CE9D000 -- 0x3CF0DFFF || |--------------| | |0x3CDBC000 -- 0x3CE9EFFF || |--------------| || | |0x3CCDB000 -- 0x3CDBBFFF || treble-buffer YUV( Y ) framebuffer : 1280 x 720 x 1 byte |--------------| || | |0x3CBFA000 -- 0x3CCDAFFF || |--------------| | |0x3CA83000 -- 0x3CBF9FFF || |--------------| || | |0x3C90C000 -- 0x3CA82FFF || treble-buffer RGBA framebuffer : 800 x 480 x 4 bytes |--------------| || | |0x3C795000 -- 0x3C90BFFF || |--------------| | |0x3C61E000 -- 0x3C794FFF || |--------------| || | |0x3C4A7000 -- 0x3C61DFFF || treble-buffer RGBA framebuffer : 800 x 480 x 4 byte |--------------| || | |0x3C330000 -- 0x3C4A6FFF || |--------------| | | 6. 将预留的物理内存记录到platform信息中 这些预留的物理内存,在 platform 初始化过程中,会映射到内存空间。 在开发板初始化过程中,会进行 machine init, 而 machine init 过程中会调用 s3c_fb_set_platdata 初始化 platform 信息。 arch/arm/mach-sp5v210/Mach-mini210.c --------------------------------------------------
在platform初始化过程中,就会通过 pmem_start 和 pmem_size 分别记录这5个window 的物理内存地址和大小。 注意的是 platform 初始化,相当于是记录系统都有哪些资源。而设备驱动初始化过程中,比如s3cfb这个fb驱动,则会来使用这些资源。 arch/arm/plat-s5p/include/plat/Fb.h --------------------------------------------------
arch/arm/plat-samsung/Dev-fb.c --------------------------------------------------
我们需要留意一下上面这段代码, 因为 num_overlay_win 是 CONFIG_FB_S3C_NUM_OVLY_WIN=1,所以 for 循环只执行了一次,那么 window 0 的物理内存地址初始化了。 然后又手工为 default_win 也就是 CONFIG_FB_S3C_DEFAULT_WINDOW=2 进行了初始化。 也就是说: window 0 和 window 2 在platform初始化中记录了数据buffer的物理内存地址。 虽然是 for 循环做的,我认为这个for循环写得不好。 7. 在s3cfb初始化过程中,为window 关联这些内存 在初始化过程中,会分配fb设备相关数据结构,并注册fb设备。 drivers/video/samsung/s3cfb.c --------------------------------------------------
但是我们发现,只有当 fb 设备对应的 window 是 default window ,也就是 window 2 的时候, 才会将 window 2 对应的内存映射到内存空间。 虽然预留的物理内存是 window 0 和 window 2 的,但这个时候 window 0 的物理内存是没有被映射的。 drivers/video/samsung/s3cfb.c --------------------------------------------------
这是注册 fb 设备的地方,只要注册成功,/dev 目录下就会有一个 fb 文件。 虽然只给 window 2 映射了显示数据的内存,但是 for 循环还是将所有的 window 都注册设备文件了。 这就是为什么 /dev 目录下有 fb0 - fb4 5个fb设备。其实每一个 fb 设备对应一个 window。 另外需要注意的是,第一个注册的 fb 是 fb0,然后依次 ++。 下面的代码在注册的时候, 首先注册的是 default window 2,然后是 3, 4, 0, 1。 也就是说 : fb0 -> window 2 fb1 -> window 3 fb2 -> window 4 fb3 -> window 0 fb4 -> window 1 另外还需要注意的是,如果你直接去 cat /dev/fbX ,只有 fb0 是成功的,其他全部失败, 因为到目前位置,只有 fb0 也就是 default window 2,映射了显示数据的内存。 drivers/video/samsung/s3cfb.c --------------------------------------------------
8. 内核关于显示内存映射的相关debug log 需要注意一下,部分log中写的是fb2,但这个log是boot阶段的,真正有效的是fb0, 代码中log写错了,fb 很多应该是 window。fb0 -> window 2 dmesg log : -------------------------------------------------- [ 507.316250] [s3cfb]win 2: pmem_start=0x3c795000 [ 507.316292] [s3cfb][fb2] dma: 0x3c795000, cpu: 0xe1000000, size: 0x0085c000 [ 507.333888] PA FB = 0x3C795000, bits per pixel = 32 [ 507.333933] screen width=800 height=480 va=0xdc795000 pa=0x3c795000 [ 507.333987] xres_virtual = 800, yres_virtual = 1440, xoffset = 0, yoffset = 0 [ 507.336543] fb_size=8765440 [ 507.339351] Back frameBuffer[0].VAddr=dc90c000 PAddr=3c90c000 size=1536000 [ 507.346146] Back frameBuffer[1].VAddr=dca83000 PAddr=3ca83000 size=1536000 [ 507.353014] Video Y Buffer[0].VAddr=dcbfa000 PAddr=3cbfa000 size=921600 [ 507.359576] Video Y Buffer[1].VAddr=dccdb000 PAddr=3ccdb000 size=921600 [ 507.366161] Video Y Buffer[2].VAddr=dcdbc000 PAddr=3cdbc000 size=921600 [ 507.372750] Video UV Buffer[0].VAddr=dce9d000 PAddr=3ce9d000 size=462848 [ 507.379418] Video UV Buffer[1].VAddr=dcf0e000 PAddr=3cf0e000 size=462848 [ 507.386093] Video UV Buffer[2].VAddr=dcf7f000 PAddr=3cf7f000 size=462848 9. 显示数据使用内存映射的一些细节 s3cfb_map_video_memory 这个函数用于映射显示数据的内存地址, 如果是 platform 初始化过程中预留过物理内存,则会使用这个物理内存。 否则就会临时申请一块内存。 也就是说 window 0 和 window 2 会使用预留的物理内存。 window 1 / window 3 / window 4 会使用新申请的内存。 drivers/video/samsung/s3cfb.c --------------------------------------------------
除了在初始化的时候会映射以外, 还可一通过 ioctl 来调用 s3cfb_map_video_memory。 传递的参数是 FBIOPUT_VSCREENINFO。 drivers/video/samsung/s3cfb.c --------------------------------------------------
10. 在s3cfb初始化过程中映射FIMD的控制寄存器,用于控制硬件 FIMD的控制寄存器和内存是统一编址的,因此可以像使用内存一样访问他们,但前提是需要将他们映射到内存空间。 内核代码中的寄存器地址定义都能和 SoC 用户手册对应上,我们看看下面的截图,很一致吧。 但是在看代码的过程中,我发现代码使用的寄存器的一些信息,Soc 用户手册没有,是不是用户手册比较老了? 在 s3cfb 模块初始化的过程中,就会将控制寄存器映射到内存中。 arch/arm/mach-sp5v210/include/mach/map.h --------------------------------------------------
arch/arm/plat-samsung/dev-fb.c --------------------------------------------------
s3cfb_fimd6x.c这个文件将读写 FIMD 的控制寄存器相关功能都集中在这里了。 我理解 6x 可能是对应硬件版本号,因为印象中看到硬件版本号好象是 0x62。 通过设定这些控制寄存器,就能控制比如 window 是否显示啊,显示数据格式是啥啊,显示数据地址在哪里啊,等等。 drivers/video/samsung/s3cfb_fimd6x.c --------------------------------------------------
11. 用户空间的测试用例 这个用例其实是用来确认 /dev 目录下的 fb0 - fb4 是否好用的,以及 window 之间的alpha透过是否正确。 关于 window 之间的层次关系可以参考: 下面的代码,大概意思是: * 打开 window 0 - window 4 对应的 fb 设备文件。 * 设置这些 window 都是 800 x 480 x RGBA * 设置这些 window 内部的显示数据,是从 window 0 - window 4 开始的,分别画 500x480, 400x480, 300x480, 200x480, 100x480 这么大块数据。 * 让window 的显示数据显示出来。 s3cfb_test.c --------------------------------------------------
下面是屏幕截图,其实我对 RGB 不太了解,不知到什么值应该是什么颜色,但 只描画了红/绿/蓝 三种颜色,而屏幕上不是这三种颜色。 说明 alpha blending 应该是正常工作了的。 END
[ 此帖被happyzlz在2012-12-12 21:30重新编辑 ]
|
|||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
顶端
更多
|
benjaminwan
级别: 骑士
精华: 9 发帖: 167 金钱: 1285 两 威望: 257 点 贡献值: 9 点 综合积分: 514 分 注册时间: 2010-10-01 最后登录: 2013-04-14 |
1楼
发表于: 2012-12-12 22:23
只看该作者 | 小 中 大
技术贴,要顶。
|
---|---|
顶端
更多
|
kasim
*無鈳取玳
级别: 论坛版主
精华: 12 发帖: 4922 金钱: 37525 两 威望: 17410 点 贡献值: 71 点 综合积分: 10084 分 注册时间: 2008-01-16 最后登录: 2013-04-15 |
2楼
发表于: 2012-12-12 22:55
只看该作者 | 小 中 大
|
---|---|
顶端
更多
|
windsun
级别: 新手上路
精华: 0 发帖: 29 金钱: 145 两 威望: 29 点 贡献值: 0 点 综合积分: 58 分 注册时间: 2012-11-11 最后登录: 2013-03-04 |
3楼
发表于: 2012-12-13 00:36
只看该作者 | 小 中 大
太强大了 收了
|
---|---|
顶端
更多
|
mindee
自由,自强,共享,共创。
级别: 论坛版主
精华: 24 发帖: 7930 金钱: 41425 两 威望: 8285 点 贡献值: 24 点 综合积分: 16340 分 注册时间: 2010-01-09 最后登录: 2013-04-15 |
4楼
发表于: 2012-12-13 07:44
只看该作者 | 小 中 大
牛人!强贴!!!
多谢分享 |
---|---|
顶端
更多
|
mizu123
级别: 新手上路
精华: 0 发帖: 7 金钱: 35 两 威望: 7 点 贡献值: 0 点 综合积分: 14 分 注册时间: 2012-12-07 最后登录: 2013-01-10 |
5楼
发表于: 2013-01-06 02:05
只看该作者 | 小 中 大
一个字,强!
分析很到位,多谢分享 |
---|---|
顶端
更多
|
lugang_29202
级别: 新手上路
精华: 0 发帖: 47 金钱: 235 两 威望: 47 点 贡献值: 0 点 综合积分: 94 分 注册时间: 2010-05-16 最后登录: 2013-04-13 |
6楼
发表于: 2013-01-11 15:23
只看该作者 | 小 中 大
mark
|
---|---|
顶端
更多
|
syhee
级别: 新手上路
精华: 0 发帖: 39 金钱: 195 两 威望: 39 点 贡献值: 0 点 综合积分: 78 分 注册时间: 2012-07-05 最后登录: 2013-03-11 |
7楼
发表于: 56天前
只看该作者 | 小 中 大
在映射内存空间中,保留了一部分内存,保留的大小就和window 以及 buffer数有关系:
大小是 800 x 480 x 2个window x 3个buffer x RGBA的4字节,这是给通常显示数据的, 除此之外,还预留了 YUV 的数据区域,1280 x 720 x 3个buffer x Y的一个字节数据 + 1280 x 720 x 3个buffer x UV的一个字节数据。 另外还有一个 4096 字节大小的 数据。 static void __init mini210_map_io(void) { ...... frame_size = lcd->width * lcd->height * BYTES_PER_PIXEL; fimd_size = ALIGN(frame_size, PAGE_SIZE) * NUM_BUFFER; if (frame_size > 0x200000) { fimd_size += ALIGN(frame_size, PAGE_SIZE) * 2; // Not used } /* Reserve 0x003f6000 bytes for PVR YUV video, and 1 page */ fimd_size += ALIGN(1280*720, PAGE_SIZE) * 3; fimd_size += ALIGN(1280*360, PAGE_SIZE) * 3 + PAGE_SIZE; if (fimd_size != S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMD) { mini210_fixup_bootmem(S5P_MDEV_FIMD, fimd_size); } 楼主的代码,跟我的kernel不一样啊,我用的是友善之臂linux-2.6.35.7-20121027,在这里预留ram的时候没有加YUV部分。 请问楼主的代码是什么版本的? static void __init mini210_map_io(void) { struct s3cfb_lcd *lcd = mini210_get_lcd(); int frame_size, fimd_size; s5p_init_io(NULL, 0, S5P_VA_CHIPID); s3c24xx_init_clocks(24000000); s5pv210_gpiolib_init(); s3c24xx_init_uarts(mini210_uartcfgs, ARRAY_SIZE(mini210_uartcfgs)); frame_size = lcd->width * lcd->height * BYTES_PER_PIXEL; fimd_size = ALIGN(frame_size, PAGE_SIZE) * CONFIG_FB_S3C_NR_BUFFERS; if (fimd_size != S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMD) { mini210_fixup_bootmem(S5P_MDEV_FIMD, fimd_size); } |
---|---|
顶端
更多
|
happyzlz
级别: 侠客
精华: 9 发帖: 50 金钱: 700 两 威望: 140 点 贡献值: 9 点 综合积分: 280 分 注册时间: 2009-05-11 最后登录: 2013-04-15 |
8楼
发表于: 54天前
只看该作者 | 小 中 大
回 7楼(syhee) 的帖子
我的开发板是 tiny210 v2 ,有 HDMI 输出的, 内核版本是 3.0.8
|
---|---|
顶端
更多
|
syhee
级别: 新手上路
精华: 0 发帖: 39 金钱: 195 两 威望: 39 点 贡献值: 0 点 综合积分: 78 分 注册时间: 2012-07-05 最后登录: 2013-03-11 |
9楼
发表于: 39天前
只看该作者 | 小 中 大
麻烦LZ帮忙解答下:
1. 为什么显示时用FBIOBLANK,不是使用FBIOPAN_DISPLAY。 再手册上 看到 FBIOBLANK的作用是清屏的,但是这里设置成blank = FB_BLANK_UNBLANK; 看内核 应该是 开启DMA,使能显示。这一块默认都是打开的么? 2. 在draw framebuffer时 如果 初始不画*( p + j * xres + i ) = 0x00FFFFFF; 这部分图片显示出来 就不同,请问LZ 这个是什么原因呢? |
---|---|
|