日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

(转)Tiny210v2( S5PV210 ) 平台下 FIMD 对应 的 framebuffer 驱动中,关于 video buffer 的理解...

發(fā)布時(shí)間:2023/11/29 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 (转)Tiny210v2( S5PV210 ) 平台下 FIMD 对应 的 framebuffer 驱动中,关于 video buffer 的理解... 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

原文:http://www.arm9home.net/read.php?tid-25938.html

管理提醒:?本帖被 xoom 執(zhí)行加亮操作(2012-12-13)
如之前所說,一直想知道顯示數(shù)據(jù)都在哪個(gè)地方,通常的數(shù)據(jù),比如 framebuffer 中的顯示數(shù)據(jù),和OpenGL 處理的數(shù)據(jù)有啥關(guān)系。
目前為止我還沒有弄明白 OpenGL 這塊,但是 framebuffer 這部分差不多了。這篇文章記錄了 framebuffer 的顯示數(shù)據(jù)相關(guān)內(nèi)容。

1. 關(guān)于FIMD

????Tiny210v2 開發(fā)板屬于 s5pv210 的一種,在這塊開發(fā)板上,顯示部分又被叫做 FIMD,我不知道FIMD是什么的縮寫,但D應(yīng)該和Display Controller有關(guān)系吧。
????FIMD 的主要功能就是獲取顯示數(shù)據(jù),并將數(shù)據(jù)輸出到顯示屏。當(dāng)然期間會(huì)對(duì)顯示數(shù)據(jù)進(jìn)行處理:

?????????
?

????FIMD一共支持5個(gè)layer,在SoC用戶手冊(cè)中,將layer成為window,源代碼中也叫做window。

?????????
?

????FIMD可以通過AXI總線從內(nèi)存或者Camera哪里獲取到顯示數(shù)據(jù),并進(jìn)行合成。

?????????
?
????
2. 內(nèi)核配置 framebuffer

????通過 make menuconfig 可以配置 framebuffer 相關(guān)的內(nèi)容。
????
?????????
?

????保存以后,在 .config 文件中可以找到相關(guān)配置內(nèi)容。
????
????????.config
????????--------------------------------------------------
復(fù)制代碼
  • ????????CONFIG_FB_S3C_DEFAULT_WINDOW=2
  • ????????CONFIG_FB_S3C_NR_BUFFERS=3
  • ????????CONFIG_FB_S3C_NUM_OVLY_WIN=1
  • ????????CONFIG_FB_S3C_NUM_BUF_OVLY_WIN=3


  • ????同樣也會(huì)在頭文件中生成宏定義:

    ????????include/generated/autoconf.h
    ????????--------------------------------------------------
    復(fù)制代碼
  • ????????#define CONFIG_FB_S3C_DEFAULT_WINDOW 2
  • ????????#define CONFIG_FB_S3C_NR_BUFFERS 3
  • ????????#define CONFIG_FB_S3C_NUM_OVLY_WIN 1
  • ????????#define CONFIG_FB_S3C_NUM_BUF_OVLY_WIN 3

  • ????
    ????CONFIG_FB_S3C_DEFAULT_WINDOW 是指 默認(rèn)的 window, 0-4。
    ????CONFIG_FB_S3C_NR_BUFFERS 是指 window 的buffer數(shù),3個(gè)就是 trebble-buffer,2個(gè)就是double-buffer。
    ????其中第一個(gè)是正在顯示的數(shù)據(jù),又叫onscreen,其他幾個(gè)是后臺(tái)描畫的數(shù)據(jù),又叫offscreen,通過 flip 操作可以將 onscreen 數(shù)據(jù)和offscreen 數(shù)據(jù)交換。
    ????CONFIG_FB_S3C_NUM_OVLY_WIN 是 OVERLAY window, 0-4。
    ????CONFIG_FB_S3C_NUM_BUF_OVLY_WIN 是指 OVERLAY window 的buffer數(shù),和 CONFIG_FB_S3C_NR_BUFFERS 一個(gè)意思。
    ????????
    3. 顯示數(shù)據(jù)buffer

    ????內(nèi)核初始話過程中,為這些window 的 buffer 預(yù)留了一部分內(nèi)存。
    ????具體看下面的代碼:

    ????初始化函數(shù)會(huì)首先映射內(nèi)存空間:
    ????????
    復(fù)制代碼
  • ????????MACHINE_START(MINI210, "MINI210")
  • ????????????/* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */
  • ????????????.boot_params????= S5P_PA_SDRAM + 0x100,
  • ????????????.fixup????????????= mini210_fixup,
  • ????????????.init_irq????????= s5pv210_init_irq,
  • ????????????.map_io????????????= mini210_map_io,
  • ????????????.init_machine????= mini210_machine_init,
  • ????????#ifdef CONFIG_S5P_HIGH_RES_TIMERS
  • ????????????.timer????????????= &s5p_systimer,
  • ????????#else
  • ????????????.timer????????????= &s5p_timer,
  • ????????#endif
  • ????????MACHINE_END

  • ????
    ????在映射內(nèi)存空間中,保留了一部分內(nèi)存,保留的大小就和window 以及 buffer數(shù)有關(guān)系:
    ????大小是 800 x 480 x 2個(gè)window x 3個(gè)buffer x RGBA的4字節(jié),這是給通常顯示數(shù)據(jù)的,
    ????除此之外,還預(yù)留了 YUV 的數(shù)據(jù)區(qū)域,1280 x 720 x 3個(gè)buffer x Y的一個(gè)字節(jié)數(shù)據(jù) + 1280 x 720 x 3個(gè)buffer x UV的一個(gè)字節(jié)數(shù)據(jù)。
    ????另外還有一個(gè) 4096 字節(jié)大小的 數(shù)據(jù)。

    ????這些數(shù)據(jù)我只理解了 RGBA 數(shù)據(jù), YUV 的數(shù)據(jù)不知道是干啥的? 難道是給 HDMI 輸出用的?
    ????????
    ????????arch/arm/mach-sp5v210/Mach-mini210.c
    ????????--------------------------------------------------
    復(fù)制代碼
  • ????????/* Multimedia support */
  • ????????#define LCD_WIDTH????????????????800
  • ????????#define LCD_HEIGHT????????????????480
  • ????????#define BYTES_PER_PIXEL????????????4
  • ????????#define NUM_BUFFER_OVLY????????????(CONFIG_FB_S3C_NUM_OVLY_WIN * CONFIG_FB_S3C_NUM_BUF_OVLY_WIN)
  • ????????#define NUM_BUFFER????????????????(CONFIG_FB_S3C_NR_BUFFERS + NUM_BUFFER_OVLY)
  • ????????#define PXL2FIMD(pixels)????????((pixels) * BYTES_PER_PIXEL * NUM_BUFFER)
  • ????????#define S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMD????????PXL2FIMD(LCD_WIDTH * LCD_HEIGHT)
  • ????????
  • ????????static struct s5p_media_device mini210_media_devs[] = {
  • ????????????......,
  • ????????????{
  • ????????????????.id????????????= S5P_MDEV_FIMD,
  • ????????????????.name????????= "fimd",
  • ????????????????.bank????????= 1,
  • ????????????????.memsize????= S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMD,
  • ????????????????.paddr????????= 0,
  • ????????????},
  • ????????????......,
  • ????????}
  • ????????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);
  • ????????????}
  • ????????????......
  • ????????????s5p_reserve_bootmem(mini210_media_devs, ARRAY_SIZE(mini210_media_devs), S5P_RANGE_MFC);
  • ????????????......
  • ????????}


  • ????這些內(nèi)存是PAGE對(duì)齊的,對(duì)齊的部分參考下面的算法。
    ????PAGE_SIZE 大小是 4096。

    ????????include/linux/Const.h
    ????????--------------------------------------------------
    復(fù)制代碼
  • ????????#ifdef __ASSEMBLY__
  • ????????#define _AC(X,Y)????X
  • ????????#define _AT(T,X)????X
  • ????????#else
  • ????????#define __AC(X,Y)????(X##Y)
  • ????????#define _AC(X,Y)????__AC(X,Y)
  • ????????#define _AT(T,X)????((T)(X))
  • ????????#endif

  • ????????
    ????????arch/arm/include/asm/Page.h
    ????????--------------------------------------------------
    復(fù)制代碼
  • ????????#define PAGE_SHIFT????????12
  • ????????#define PAGE_SIZE????????(_AC(1,UL) << PAGE_SHIFT)

  • ????????
    ????????include/linux/Kernel.h
    ????????--------------------------------------------------
    復(fù)制代碼
  • ????????#define __ALIGN_KERNEL_MASK(x, mask)????(((x) + (mask)) & ~(mask))
  • ????????#define __ALIGN_KERNEL(x, a)????????__ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1)
  • ????????#define ALIGN(x, a)????????__ALIGN_KERNEL((x), (a))

  • ????????

    4. 內(nèi)核關(guān)于FIMD內(nèi)存預(yù)留的相關(guān)debug log

    ????在內(nèi)核的 boot log 中,我們可以找到關(guān)于內(nèi)存預(yù)留的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. 物理內(nèi)存視圖

    ????畫了一個(gè)簡(jiǎn)單的物理內(nèi)存布局圖,可以看到 RGBA 部分的數(shù)據(jù),其實(shí)一共給 2 個(gè) window 預(yù)留了。

    ????????|??????????????|
    ????????|--------------|
    ????????|??????????????|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. 將預(yù)留的物理內(nèi)存記錄到platform信息中

    ????這些預(yù)留的物理內(nèi)存,在 platform 初始化過程中,會(huì)映射到內(nèi)存空間。
    ????在開發(fā)板初始化過程中,會(huì)進(jìn)行 machine init, 而 machine init 過程中會(huì)調(diào)用 s3c_fb_set_platdata 初始化 platform 信息。
    ????????
    ????????arch/arm/mach-sp5v210/Mach-mini210.c
    ????????--------------------------------------------------
    復(fù)制代碼
  • ????????static struct s3c_platform_fb mini210_fb_data __initdata = {
  • ????????????.hw_ver????????????= 0x62,
  • ????????????.clk_name?????? = "sclk_fimd",
  • ????????????.nr_wins????????= 5,
  • ????????????.default_win????= CONFIG_FB_S3C_DEFAULT_WINDOW,
  • ????????????.swap????????????= FB_SWAP_WORD | FB_SWAP_HWORD,
  • ????????
  • ????????????.cfg_gpio????????= lcd_cfg_gpio,
  • ????????????.backlight_on????= lcd_backlight_on,
  • ????????????.backlight_onoff= lcd_backlight_off,
  • ????????????.reset_lcd????????= lcd_reset_lcd,
  • ????????};
  • ????????static void __init mini210_machine_init(void)
  • ????????{
  • ????????????......
  • ????????#ifdef CONFIG_FB_S3C_MINI210
  • ????????????{
  • ????????????????struct s3cfb_lcd *mlcd = mini210_get_lcd();
  • ????????????????if (!(mlcd->args & 0x0f)) {
  • ????????????????????if (readl(S5PV210_GPF0_BASE + 0x184) & 0x10)
  • ????????????????????????mlcd->args |= (1 << 7);
  • ????????????????}
  • ????????????????mini210_fb_data.lcd = mlcd;
  • ????????????????s3c_fb_set_platdata(&mini210_fb_data);
  • ????????????}
  • ????????#endif
  • ????????????......
  • ????????}
  • ????????
  • ????????MACHINE_START(MINI210, "MINI210")
  • ????????????/* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */
  • ????????????.boot_params????= S5P_PA_SDRAM + 0x100,
  • ????????????.fixup????????????= mini210_fixup,
  • ????????????.init_irq????????= s5pv210_init_irq,
  • ????????????.map_io????????????= mini210_map_io,
  • ????????????.init_machine????= mini210_machine_init,
  • ????????#ifdef CONFIG_S5P_HIGH_RES_TIMERS
  • ????????????.timer????????????= &s5p_systimer,
  • ????????#else
  • ????????????.timer????????????= &s5p_timer,
  • ????????#endif
  • ????????MACHINE_END

  • ????
    ????在platform初始化過程中,就會(huì)通過 pmem_start 和 pmem_size 分別記錄這5個(gè)window 的物理內(nèi)存地址和大小。????
    ????注意的是 platform 初始化,相當(dāng)于是記錄系統(tǒng)都有哪些資源。而設(shè)備驅(qū)動(dòng)初始化過程中,比如s3cfb這個(gè)fb驅(qū)動(dòng),則會(huì)來使用這些資源。

    ????????arch/arm/plat-s5p/include/plat/Fb.h
    ????????--------------------------------------------------
    復(fù)制代碼
  • ????????struct s3c_platform_fb {
  • ????????????int????????????hw_ver;
  • ????????????char????????clk_name[16];
  • ????????????int????????????nr_wins;
  • ????????????int????????????nr_buffers[5];
  • ????????????int????????????default_win;
  • ????????????int????????????swap;
  • ????????????phys_addr_t????pmem_start[5]; /* starting physical address of memory region */
  • ????????????size_t????????pmem_size[5]; /* size of memory region */
  • ????????????void????????*lcd;
  • ????????????void????????(*cfg_gpio)(struct platform_device *dev);
  • ????????????int????????????(*backlight_on)(struct platform_device *dev);
  • ????????????int????????????(*backlight_onoff)(struct platform_device *dev, int onoff);
  • ????????????int????????????(*reset_lcd)(struct platform_device *dev);
  • ????????????int????????????(*clk_on)(struct platform_device *pdev, struct clk **s3cfb_clk);
  • ????????????int????????????(*clk_off)(struct platform_device *pdev, struct clk **clk);
  • ????????};

  • ????????
    ????????arch/arm/plat-samsung/Dev-fb.c
    ????????--------------------------------------------------
    復(fù)制代碼
  • ?????? void __init s3c_fb_set_platdata(struct s3c_platform_fb *pd)
  • ????????{
  • ????????????struct s3c_platform_fb *npd;
  • ????????????struct s3cfb_lcd *lcd;
  • ????????????phys_addr_t pmem_start;
  • ????????????int i, default_win, num_overlay_win;
  • ????????????int frame_size;
  • ????????
  • ????????????if (!pd)
  • ????????????????pd = &default_fb_data;
  • ????????
  • ????????????npd = kmemdup(pd, sizeof(struct s3c_platform_fb), GFP_KERNEL);
  • ????????????if (!npd) {
  • ????????????????printk(KERN_ERR "%s: no memory for platform data\n", __func__);
  • ????????
  • ????????????} else {
  • ????????????????for (i = 0; i < npd->nr_wins && i < NR_BUFFERS; i++) {
  • ????????????????????npd->nr_buffers?? = 1;
  • ????????????????}
  • ????????
  • ????????????????default_win = npd->default_win;
  • ????????????????num_overlay_win = CONFIG_FB_S3C_NUM_OVLY_WIN;
  • ????????????????if (num_overlay_win >= default_win) {
  • ????????????????????printk(KERN_WARNING "%s: NUM_OVLY_WIN should be less than default \
  • ????????????????????????????window number. set to 0.\n", __func__);
  • ????????????????????num_overlay_win = 0;
  • ????????????????}
  • ????????????????......
  • ????????????????
  • ????????????????/* set starting physical address & size of memory region for
  • ???????????????? * overlay window and default window */
  • ????????????????pmem_start = s5p_get_media_memory_bank(S5P_MDEV_FIMD, 1);
  • ????????????????printk("fimd at 0x%08x\n", pmem_start);
  • ????????
  • ????????????????for (i = 0; i < num_overlay_win; i++) {
  • ????????????????????*(npd->nr_buffers+i) = CONFIG_FB_S3C_NUM_BUF_OVLY_WIN;
  • ????????????????????*(npd->pmem_start+i) = pmem_start;
  • ????????????????????*(npd->pmem_size+i) = frame_size *?? *(npd->nr_buffers+i);
  • ????????????????????pmem_start += *(npd->pmem_size+i);
  • ????????????????}
  • ????????
  • ????????????????npd->nr_buffers[default_win] = CONFIG_FB_S3C_NR_BUFFERS;
  • ????????????????npd->pmem_start[default_win] = pmem_start;
  • ????????????????npd->pmem_size[default_win] = frame_size * npd->nr_buffers[default_win];
  • ????????
  • ????????#if defined(CONFIG_MACH_MINI210)
  • ????????????????npd->pmem_size[default_win] += ALIGN(1280*720, PAGE_SIZE) * 3;
  • ????????????????npd->pmem_size[default_win] += ALIGN(1280*360, PAGE_SIZE) * 3 + PAGE_SIZE;
  • ????????
  • ????????????????if (frame_size > 0x200000) {????????????????????????????????????????// Not Used : frame_size < 0x200000
  • ????????????????????pmem_start += npd->pmem_size[default_win];
  • ????????????????????for (; i < npd->nr_wins; i++) {
  • ????????????????????????if (i != default_win) {
  • ????????????????????????????npd->nr_buffers[i] = 2;
  • ????????????????????????????npd->pmem_start[i] = pmem_start;
  • ????????????????????????????npd->pmem_size[i] = frame_size * npd->nr_buffers[i];
  • ????????????????????????????break;
  • ????????????????????????}
  • ????????????????????}
  • ????????????????}
  • ????????#endif
  • ????????
  • ????????????????s3c_device_fb.dev.platform_data = npd;
  • ????????????}
  • ????????}

  • ????
    ????我們需要留意一下上面這段代碼,????
    ????因?yàn)?num_overlay_win 是 CONFIG_FB_S3C_NUM_OVLY_WIN=1,所以 for 循環(huán)只執(zhí)行了一次,那么 window 0 的物理內(nèi)存地址初始化了。
    ????然后又手工為 default_win 也就是 CONFIG_FB_S3C_DEFAULT_WINDOW=2 進(jìn)行了初始化。
    ????也就是說: window 0 和 window 2 在platform初始化中記錄了數(shù)據(jù)buffer的物理內(nèi)存地址。
    ????雖然是 for 循環(huán)做的,我認(rèn)為這個(gè)for循環(huán)寫得不好。


    7. 在s3cfb初始化過程中,為window 關(guān)聯(lián)這些內(nèi)存

    ????在初始化過程中,會(huì)分配fb設(shè)備相關(guān)數(shù)據(jù)結(jié)構(gòu),并注冊(cè)fb設(shè)備。

    ????????drivers/video/samsung/s3cfb.c
    ????????--------------------------------------------------
    復(fù)制代碼
  • ????????static int __devinit s3cfb_probe(struct platform_device *pdev)
  • ????????{
  • ????????????......
  • ????????????if (s3cfb_alloc_framebuffer(fbdev)) {
  • ????????????????ret = -ENOMEM;
  • ????????????????goto err_alloc;
  • ????????????}
  • ????????
  • ????????????if (s3cfb_register_framebuffer(fbdev)) {
  • ????????????????ret = -EINVAL;
  • ????????????????goto err_register;
  • ????????????}
  • ????????????......
  • ????????}


  • ????但是我們發(fā)現(xiàn),只有當(dāng) fb 設(shè)備對(duì)應(yīng)的 window 是 default window ,也就是 window 2 的時(shí)候,
    ????才會(huì)將 window 2 對(duì)應(yīng)的內(nèi)存映射到內(nèi)存空間。
    ????雖然預(yù)留的物理內(nèi)存是 window 0 和 window 2 的,但這個(gè)時(shí)候 window 0 的物理內(nèi)存是沒有被映射的。

    ????????drivers/video/samsung/s3cfb.c
    ????????--------------------------------------------------
    復(fù)制代碼
  • ????????static int s3cfb_alloc_framebuffer(struct s3cfb_global *ctrl)
  • ????????{
  • ????????????......
  • ????????????for (i = 0; i < pdata->nr_wins; i++) {
  • ????????????????ctrl->fb[i] = framebuffer_alloc(sizeof(*ctrl->fb), ctrl->dev);
  • ????????????????if (!ctrl->fb[i]) {
  • ????????????????????dev_err(ctrl->dev, "not enough memory\n");
  • ????????????????????ret = -ENOMEM;
  • ????????????????????goto err_alloc_fb;
  • ????????????????}
  • ????????????????......
  • ????????????????if (i == pdata->default_win) {
  • ????????????????????if (s3cfb_map_video_memory(ctrl->fb[i])) {
  • ????????????????????????dev_err(ctrl->dev,
  • ????????????????????????????"failed to map video memory "
  • ????????????????????????????"for default window (%d)\n", i);
  • ????????????????????????ret = -ENOMEM;
  • ????????????????????????goto err_map_video_mem;
  • ????????????????????}
  • ????????????????}
  • ????????????}
  • ????????????......
  • ????????}

  • ????
    ????這是注冊(cè) fb 設(shè)備的地方,只要注冊(cè)成功,/dev 目錄下就會(huì)有一個(gè) fb 文件。
    ????雖然只給 window 2 映射了顯示數(shù)據(jù)的內(nèi)存,但是 for 循環(huán)還是將所有的 window 都注冊(cè)設(shè)備文件了。
    ????這就是為什么 /dev 目錄下有 fb0 - fb4 5個(gè)fb設(shè)備。其實(shí)每一個(gè) fb 設(shè)備對(duì)應(yīng)一個(gè) window。
    ????
    ????另外需要注意的是,第一個(gè)注冊(cè)的 fb 是 fb0,然后依次 ++。
    ????下面的代碼在注冊(cè)的時(shí)候, 首先注冊(cè)的是 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 是成功的,其他全部失敗,
    ????因?yàn)榈侥壳拔恢?#xff0c;只有 fb0 也就是 default window 2,映射了顯示數(shù)據(jù)的內(nèi)存。
    ????????
    ????????drivers/video/samsung/s3cfb.c
    ????????--------------------------------------------------
    復(fù)制代碼
  • ????????static int s3cfb_register_framebuffer(struct s3cfb_global *ctrl)
  • ????????{
  • ????????????......
  • ????????????k = 0;
  • ????????????for (i = pdata->default_win;
  • ????????????????i < pdata->nr_wins + pdata->default_win; i++) {
  • ????????????????????j = i % pdata->nr_wins;
  • ????????????????????ret = register_framebuffer(ctrl->fb[j]);
  • ????????????????????if (ret) {
  • ????????????????????????dev_err(ctrl->dev, "failed to register "
  • ????????????????????????????????"framebuffer device\n");
  • ????????????????????????ret = -EINVAL;
  • ????????????????????????goto err_register_fb;
  • ????????????????????}
  • ????????????????????pdata->fb_file_minor[ j ] = k;
  • ????????????????????k++;
  • ????????????????????
  • ????????????????????#ifndef CONFIG_FRAMEBUFFER_CONSOLE
  • ????????????????????if (j == pdata->default_win) {
  • ????????????????????????s3cfb_check_var(&ctrl->fb[j]->var, ctrl->fb[j]);
  • ????????????????????????s3cfb_set_par(ctrl->fb[j]);
  • ????????????????????????s3cfb_draw_logo(ctrl->fb[j]);
  • ????????????????????}
  • ????????????????????#endif
  • ????????????}
  • ????????????......
  • ????????}


  • 8. 內(nèi)核關(guān)于顯示內(nèi)存映射的相關(guān)debug log

    ????需要注意一下,部分log中寫的是fb2,但這個(gè)log是boot階段的,真正有效的是fb0,
    ????代碼中l(wèi)og寫錯(cuò)了,fb 很多應(yīng)該是 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. 顯示數(shù)據(jù)使用內(nèi)存映射的一些細(xì)節(jié)

    ????s3cfb_map_video_memory 這個(gè)函數(shù)用于映射顯示數(shù)據(jù)的內(nèi)存地址,
    ????如果是 platform 初始化過程中預(yù)留過物理內(nèi)存,則會(huì)使用這個(gè)物理內(nèi)存。
    ????否則就會(huì)臨時(shí)申請(qǐng)一塊內(nèi)存。

    ????也就是說 window 0 和 window 2 會(huì)使用預(yù)留的物理內(nèi)存。
    ????window 1 / window 3 / window 4 會(huì)使用新申請(qǐng)的內(nèi)存。

    ????????drivers/video/samsung/s3cfb.c
    ????????--------------------------------------------------
    復(fù)制代碼
  • ????????static int s3cfb_map_video_memory(struct fb_info *fb)
  • ????????{
  • ????????????......
  • ????????????if (win->owner == DMA_MEM_OTHER) {
  • ????????????????fix->smem_start = win->other_mem_addr;
  • ????????????????fix->smem_len = win->other_mem_size;
  • ????????????????return 0;
  • ????????????}
  • ????????
  • ????????????if (fb->screen_base)
  • ????????????????return 0;
  • ????????
  • ????????????if (pdata && pdata->pmem_start[win->id] && (pdata->pmem_size[win->id] >= fix->smem_len)) {
  • ????????????????fix->smem_start = pdata->pmem_start[win->id];
  • ????????????????fix->smem_len = pdata->pmem_size[win->id];
  • ????????????????fb->screen_base = ioremap_wc(fix->smem_start, pdata->pmem_size[win->id]);
  • ????????
  • ????????????????dev_err(fbdev->dev, "[fb%d][win%d]: pmem_start=0x%x\n",
  • ????????????????????????pdata->fb_file_minor[win->id],win->id, pdata->pmem_start[win->id]);
  • ????????????} else {
  • ????????????????fb->screen_base = dma_alloc_writecombine(fbdev->dev,
  • ????????????????????????PAGE_ALIGN(fix->smem_len),
  • ????????????????????????(unsigned int *)&fix->smem_start, GFP_KERNEL);
  • ????????????}
  • ????????????......
  • ????????}


  • ????除了在初始化的時(shí)候會(huì)映射以外,
    ????還可一通過 ioctl 來調(diào)用 s3cfb_map_video_memory。
    ????傳遞的參數(shù)是 FBIOPUT_VSCREENINFO。

    ????????drivers/video/samsung/s3cfb.c
    ????????--------------------------------------------------
    復(fù)制代碼
  • ????????static int s3cfb_set_par(struct fb_info *fb)
  • ????????{
  • ????????????......
  • ????????????if (win->id != pdata->default_win) {
  • ????????????????fb->fix.line_length = fb->var.xres_virtual *
  • ????????????????????????????????fb->var.bits_per_pixel / 8;
  • ????????????????fb->fix.smem_len = fb->fix.line_length * fb->var.yres_virtual;
  • ????????
  • ????????????????s3cfb_map_video_memory(fb);
  • ????????????}
  • ????????????......
  • ????????}
  • ????????struct fb_ops s3cfb_ops = {
  • ????????????.fb_set_par = s3cfb_set_par,
  • ????????};
  • ????????drivers/video/fbmem.c
  • ????????--------------------------------------------------
  • ????????int fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
  • ????????{
  • ????????????......
  • ????????????if (info->fbops->fb_set_par) {
  • ????????????????ret = info->fbops->fb_set_par(info);
  • ????????????????......
  • ????????????}
  • ????????????......
  • ????????}
  • ????????static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,unsigned long arg)
  • ????????{
  • ????????????case FBIOPUT_VSCREENINFO:
  • ????????????????......
  • ????????????????ret = fb_set_var(info, &var);
  • ????????????????.....
  • ????????????????break;
  • ????????}
  • ????????static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  • ????????{
  • ????????????......
  • ????????????return do_fb_ioctl(info, cmd, arg);
  • ????????????......
  • ????????}
  • ????????static const struct file_operations fb_fops = {
  • ????????????......
  • ????????????.unlocked_ioctl = fb_ioctl,
  • ????????????......
  • ????????};



  • 10. 在s3cfb初始化過程中映射FIMD的控制寄存器,用于控制硬件

    ????FIMD的控制寄存器和內(nèi)存是統(tǒng)一編址的,因此可以像使用內(nèi)存一樣訪問他們,但前提是需要將他們映射到內(nèi)存空間。
    ????內(nèi)核代碼中的寄存器地址定義都能和 SoC 用戶手冊(cè)對(duì)應(yīng)上,我們看看下面的截圖,很一致吧。
    ????但是在看代碼的過程中,我發(fā)現(xiàn)代碼使用的寄存器的一些信息,Soc 用戶手冊(cè)沒有,是不是用戶手冊(cè)比較老了?
    ????
    ?????????
    ?

    ?????????
    ?

    ????在 s3cfb 模塊初始化的過程中,就會(huì)將控制寄存器映射到內(nèi)存中。

    ????????arch/arm/mach-sp5v210/include/mach/map.h
    ????????--------------------------------------------------
    復(fù)制代碼
  • ????????#define S5PV210_PA_LCD??????????(0xF8000000)
  • ????????#define S5P_PA_LCD??????????????S5PV210_PA_LCD
  • ????????#define S5PV210_SZ_LCD??????????SZ_1M
  • ????????#define S5P_SZ_LCD??????????????S5PV210_SZ_LCD

  • ????????
    ????????
    ????????arch/arm/plat-samsung/dev-fb.c
    ????????--------------------------------------------------
    復(fù)制代碼
  • ????????static struct resource s3cfb_resource[] = {
  • ????????????[0] = {
  • ????????????????.start????????= S5P_PA_LCD,
  • ????????????????.end????????= S5P_PA_LCD + S5P_SZ_LCD - 1,
  • ????????????????.flags????????= IORESOURCE_MEM,
  • ????????????},
  • ????????????[1] = {
  • ????????????????.start????????= IRQ_LCD1,
  • ????????????????.end????????= IRQ_LCD1,
  • ????????????????.flags????????= IORESOURCE_IRQ,
  • ????????????},
  • ????????????[2] = {
  • ????????????????.start????????= IRQ_LCD0,
  • ????????????????.end????????= IRQ_LCD0,
  • ????????????????.flags????????= IORESOURCE_IRQ,
  • ????????????},
  • ????????};
  • ????????
  • ????????static u64 fb_dma_mask = 0xffffffffUL;
  • ????????
  • ????????struct platform_device s3c_device_fb = {
  • ????????????.name????????????= "s3cfb",
  • ????????????.id????????????????= -1,
  • ????????????.num_resources????= ARRAY_SIZE(s3cfb_resource),
  • ????????????.resource????????= s3cfb_resource,
  • ????????????.dev????????????= {
  • ????????????????.dma_mask????????????= &fb_dma_mask,
  • ????????????????.coherent_dma_mask????= 0xffffffffUL
  • ????????????}
  • ????????};
  • ????????
  • ????????drivers/video/samsung/s3cfb.c
  • ????????--------------------------------------------------
  • ????????static int __devinit s3cfb_probe(struct platform_device *pdev)
  • ????????{
  • ????????????......
  • ????????????res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  • ????????????if (!res) {
  • ????????????????dev_err(fbdev->dev, "failed to get io memory region\n");
  • ????????????????ret = -EINVAL;
  • ????????????????goto err_io;
  • ????????????}
  • ????????
  • ????????????res = request_mem_region(res->start, res->end - res->start + 1, pdev->name);
  • ????????????if (!res) {
  • ????????????????dev_err(fbdev->dev, "failed to request io memory region\n");
  • ????????????????ret = -EINVAL;
  • ????????????????goto err_io;
  • ????????????}
  • ????????
  • ????????????fbdev->regs = ioremap(res->start, res->end - res->start + 1);
  • ????????????if (!fbdev->regs) {
  • ????????????????dev_err(fbdev->dev, "failed to remap io region\n");
  • ????????????????ret = -EINVAL;
  • ????????????????goto err_mem;
  • ????????????}
  • ????????????......
  • ????????}

  • ????????
    ????s3cfb_fimd6x.c這個(gè)文件將讀寫 FIMD 的控制寄存器相關(guān)功能都集中在這里了。
    ????我理解 6x 可能是對(duì)應(yīng)硬件版本號(hào),因?yàn)橛∠笾锌吹接布姹咎?hào)好象是 0x62。

    ????通過設(shè)定這些控制寄存器,就能控制比如 window 是否顯示啊,顯示數(shù)據(jù)格式是啥啊,顯示數(shù)據(jù)地址在哪里啊,等等。

    ????????drivers/video/samsung/s3cfb_fimd6x.c
    ????????--------------------------------------------------
    復(fù)制代碼
  • ????????int s3cfb_display_on(struct s3cfb_global *ctrl)
  • ????????{
  • ????????????u32 cfg;
  • ????????
  • ????????????cfg = readl(ctrl->regs + S3C_VIDCON0);
  • ????????????cfg |= (S3C_VIDCON0_ENVID_ENABLE | S3C_VIDCON0_ENVID_F_ENABLE);
  • ????????????writel(cfg, ctrl->regs + S3C_VIDCON0);
  • ????????
  • ????????????dev_dbg(ctrl->dev, "global display is on\n");
  • ????????
  • ????????????return 0;
  • ????????}



  • 11. 用戶空間的測(cè)試用例

    ????這個(gè)用例其實(shí)是用來確認(rèn) /dev 目錄下的 fb0 - fb4 是否好用的,以及 window 之間的alpha透過是否正確。

    ????關(guān)于 window 之間的層次關(guān)系可以參考:
    ?????????
    ?

    ????下面的代碼,大概意思是:
    ????* 打開 window 0 - window 4 對(duì)應(yīng)的 fb 設(shè)備文件。
    ????* 設(shè)置這些 window 都是 800 x 480 x RGBA
    ????* 設(shè)置這些 window 內(nèi)部的顯示數(shù)據(jù),是從 window 0 - window 4 開始的,分別畫 500x480, 400x480, 300x480, 200x480, 100x480 這么大塊數(shù)據(jù)。
    ????* 讓window 的顯示數(shù)據(jù)顯示出來。

    ????????s3cfb_test.c
    ????????--------------------------------------------------
    復(fù)制代碼
  • ????????#include <sys/types.h>
  • ????????#include <sys/stat.h>
  • ????????#include <sys/ioctl.h>
  • ????????#include <sys/mman.h>
  • ????????#include <fcntl.h>
  • ????????#include <stdio.h>
  • ????????#include <string.h>
  • ????????#include <linux/fb.h>
  • ????????
  • ????????
  • ????????#define????WIN0????0
  • ????????#define????WIN1????1
  • ????????#define????WIN2????2
  • ????????#define????WIN3????3
  • ????????#define????WIN4????4
  • ????????#define????WIN_MAX????5
  • ????????
  • ????????const char * fb_file_path[ WIN_MAX ] = {
  • ????????/* WIN0 */"/dev/fb3",
  • ????????/* WIN1 */"/dev/fb4",
  • ????????/* WIN2 */"/dev/fb0",
  • ????????/* WIN3 */"/dev/fb1",
  • ????????/* WIN4 */"/dev/fb2"
  • ????????};
  • ????????const int fb_x[ WIN_MAX ] = {
  • ????????/* WIN0 */500,
  • ????????/* WIN1 */400,
  • ????????/* WIN2 */300,
  • ????????/* WIN3 */200,
  • ????????/* WIN4 */100
  • ????????};
  • ????????const int fb_color[ WIN_MAX ] = {
  • ????????/* WIN0 */0x10FFFFFF,
  • ????????/* WIN1 */0x10FF0000,
  • ????????/* WIN2 */0x1000FF00,
  • ????????/* WIN3 */0x100000FF,
  • ????????/* WIN4 */0x10000000,
  • ????????};
  • ????????
  • ????????void draw_framebuffer( int win, int fd, int xres, int yres )
  • ????????{
  • ????????????int i, j;
  • ????????????int *p;
  • ????????????int color;
  • ????????????
  • ????????????p = mmap( NULL, xres*yres*4, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0 );
  • ????????????if( !p ){
  • ????????????????printf( "mmap failed\n" );
  • ????????????????return;
  • ????????????}
  • ????????
  • ????????????/* draw default color with alpha : all pass through*/
  • ????????????for( j = 0; j < yres; j++ ){
  • ????????????????for( i = 0; i < xres ; i++ ){
  • ????????????????????*( p + j * xres + i ) = 0x00FFFFFF;
  • ????????????????}
  • ????????????}
  • ????????
  • ????????????/* draw color */
  • ????????????for( j = 0; j < yres; j++ ){
  • ????????????????for( i = 0; i < fb_x[win] ; i++ ){
  • ????????????????????*( p + j * xres + i ) = fb_color[win];
  • ????????????????}
  • ????????????}
  • ????????
  • ????????????munmap( p, xres*yres*4 );
  • ????????}
  • ????????
  • ????????int main( int argc, char *argv[] )
  • ????????{
  • ????????????int i;
  • ????????????int ret;
  • ????????????struct fb_var_screeninfo var;
  • ????????????int????blank;
  • ????????????int fd[ WIN_MAX ];
  • ????????
  • ????????????/* initial */
  • ????????????memset( fd, -1, sizeof( fd ) );
  • ????????
  • ????????????/* open framebuffer */
  • ????????????for( i=0; i<WIN_MAX; i++ ){
  • ????????????????fd[i] = open( fb_file_path[i], O_RDWR );
  • ????????????????if( fd[i] < 0 ){
  • ????????????????????printf( "open %s failed\n", fb_file_path[i] );
  • ????????????????????goto end;
  • ????????????????}
  • ????????????}
  • ????????????printf( "open framebuffer ok\n" );
  • ????????
  • ????????????/* set screen info */
  • ????????????ret = ioctl( fd[WIN2], FBIOGET_VSCREENINFO, &var );
  • ????????????if( ret < 0 ){
  • ????????????????printf( "ioctl %s FBIOGET_VSCREENINFO failed\n", fb_file_path[WIN2] );
  • ????????????????goto end;
  • ????????????}
  • ????????
  • ????????????var.activate = FB_ACTIVATE_FORCE;
  • ????????????var.yres_virtual = var.yres;
  • ????????????
  • ????????????for( i=0; i<WIN_MAX; i++ ){
  • ????????????????ret = ioctl( fd[i], FBIOPUT_VSCREENINFO, &var );
  • ????????????????if( ret < 0 ){
  • ????????????????????printf( "ioctl %s FBIOPUT_VSCREENINFO failed\n", fb_file_path[i] );
  • ????????????????????goto end;
  • ????????????????}
  • ????????????}
  • ????????????printf( "set screeninfo ok\n" );
  • ????????
  • ????????????/* draw some color */
  • ????????????for( i=0; i<WIN_MAX; i++ ){
  • ????????????????draw_framebuffer( i, fd[i], var.xres, var.yres );
  • ????????????}
  • ????????????printf( "draw color ok\n" );
  • ????????
  • ????????????/* show window */
  • ????????????blank = FB_BLANK_UNBLANK;
  • ????????
  • ????????????for( i=0; i<WIN_MAX; i++ ){
  • ????????????????ret = ioctl( fd[i], FBIOBLANK, blank );
  • ????????????????if( ret < 0 ){
  • ????????????????????printf( "ioctl %s FBIOBLANK failed\n", fb_file_path[i] );
  • ????????????????????goto end;
  • ????????????????}
  • ????????????}
  • ????????????printf( "show window ok\n" );
  • ????????
  • ????????????/* wait input */????
  • ????????????getchar();
  • ????????end:
  • ????????????return 0;
  • ????????}

  • ????????
    ????下面是屏幕截圖,其實(shí)我對(duì) RGB 不太了解,不知到什么值應(yīng)該是什么顏色,但 只描畫了紅/綠/藍(lán) 三種顏色,而屏幕上不是這三種顏色。
    ????說明 alpha blending 應(yīng)該是正常工作了的。

    ?????????
    ?

    END

    總結(jié)

    以上是生活随笔為你收集整理的(转)Tiny210v2( S5PV210 ) 平台下 FIMD 对应 的 framebuffer 驱动中,关于 video buffer 的理解...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。