• mx51的三个framebuffer,mxc_ipuv3_fb.c分析


    转载:http://blog.csdn.net/jack_a8/article/details/43309169

    mx51支持三个framebuffer:fb0, fb1, fb2

    /dev/graphics/fb0,/dev/graphics/fb1:

    一个作为系统的主framebuffer,另外一个作为TVOUT输出的framebuffer,缺省情况下,fb0做primary(也就是用来在primary LCD显示UI),fb1做secondary(也就是用来在TVOUT输出上显示数据)。

    根据项目中的实际物理连接情况,如果primary LCD连接到disp0,那么使用缺省设置,如果primary LCD连接到disp1,那么就要在kernel启动参数中加入di1_primary。

    /dev/graphics/fb2 :

    用来实现overlay叠加,显示video数据的framebuffer,仅支持bpp16,数据格式是yuv422,可以在DP(Display Process)和来自MEM_BG_SYNC的数据进行合成,再传送到DC/DI。

    在mxc framebuffer probe 时,第一个注册的mxc framebuffer (fb0 或者fb1,这个framebuffer作为主LCD的framebuffer)使用MEM_BG_SYNC,第二个注册的mxc framebuffer(fb0或者fb1,这个framebuffer作为TVOUT使用的framebuffer)使用MEM_DC_SYNC,最后一个注册的framebuffer(fb2)使用MEM_FG_SYNC。

    MEM_BG_SYNC 和MEM_FG_SYNC都是mx5x ipu中独一无二的资源,这意味着每个通道只能被其中一个framebuffer占用。事实上MEM_DC_SYNC这个通道并不存在,只是用来表示直接连接到DC

    注意这几个framebuffer中的数据并不是直连显示设备,中间可能还有MX51 IPU的DP处理单元,DP Unit负责对fb0 fb1 fb2过来的数据进行处理,包括颜色转换,图层合并,gamma处理以及光标处理后发送给DC->DI->显示设备

    fsl 在/sys/class/graphics/fbx/ 下创建了一个fsl特定的属性文件fsl_disp_property,在我的机器上显示如下

    [cpp] view plaincopy
     
     
    1. # cat /sys/class/graphics/fb0/fsl_disp_property  
    2. 2-layer-fb-bg  
    3. # cat /sys/class/graphics/fb1/fsl_disp_property  
    4. 1-layer-fb  
    5. # cat /sys/class/graphics/fb2/fsl_disp_property  
    6. 2-layer-fb-fg  

    2-layer-fb-bg,表示fb0使用MEM_BG_SYNC通道,在IPU 的Display Process模块和MEM_FG_SYNC通道来的数据合并,再送入DC

    1-layer-fb,表示fb1使用MEM_DC_SYNC通道,不经过Display Process模块,DC(Display Control)直接连接到DI(Display Interface)

    2-layber-fb-fg,表示fb2使用MEM_FG_SYNC通道,在IPU的Display Process模块和MEM_BG_SYNC通道来的数据合并,再送入DC

    应用层还可以修改/sys/class/graphics/fb0/fsl_disp_property和/sys/class/graphics/fb1/fsl_disp_property,使用如下命令:

    [cpp] view plaincopy
     
     
    1. echo 1-layer-fb > /sys/class/graphics/fb0/fsl_disp_property  
    2. 或者  
    3.   
    4. echo 2-layer-fb-bg > /sys/class/graphics/fb1/fsl_disp_property  

    注意,二者的作用是一样的,都会导致fb0和fb1交换显示通道,fsl引入这个属性的目的,就是给上层应用提供一个接口,使得应用层可以控制fb0 fb1使用MEM_BG_SYNC还是MEM_DC_SYNC通道,说到这里可能还是让人糊涂,为什么应用层要选择fb0 fb1的通道,这要先搞清楚MEM_BG_SYNC和MEM_DC_SYNC的区别。

    imx51/imx53 IPU支持三种类型的显示通道:MEM_BG_SYNC, MEM_FG_SYNC和MEM_DC_SYNC,framebuffer只能通过三者之一传送数据,这些通道在物理上是唯一的,同一时间只能被一个framebuffer使用。

    [cpp] view plaincopy
     
     
    1. MEM_BG_SYNC:fb0 -> DP (full plane) -> DC -> DI0  
    2. MEM_FG_SYNC:fb2 -> DP (partial plane) -> DC -> DI0  
    3. MEM_DC_SYNC:fb1 -> DC -> DI1  

    MEM_BG_SYNC和MEM_FG_SYNC会在DP进行合并处理,这个功能就是所谓的overlay。

    正常情况下来自fb0的UI和来自fb2的video数据在DP合并后,送到DI0,我们就可以看到UI 浮在video上面的效果。但是当激活双屏的时候,一般希望video数据和UI 都送到后屏(也就是DI1),前屏只显示UI。这就需要fb1拥有MEM_BG_SYNC,此时需要交换fb1和fb0的显示通道如下:

    [cpp] view plaincopy
     
     
    1. MEM_BG_SYNC: fb1 -> DP (full plane) -> DC -> DI0  
    2. MEM_FG_SYNC: fb2 -> DP (partial plane) -> DC -> DI1  
    3. MEM_DC_SYNC: fb0 -> DC -> DI0  

    通道交换代码

    [cpp] view plaincopy
     
     
    1. swap_disp_chan  
    2.   
    3. 1673 static ssize_t swap_disp_chan(struct device *dev,  
    4. 1674                   struct device_attribute *attr,  
    5. 1675                   const char *buf, size_t count)  
    6. 1676 {  
    7. 1677     struct fb_info *info = dev_get_drvdata(dev);  
    8. 1678     struct mxcfb_info *mxcfbi = (struct mxcfb_info *)info->par;  
    9. 1679     struct mxcfb_info *fg_mxcfbi = NULL;  
    10. 1680   
    11. 1681     acquire_console_sem();  
    12. 1682     /* swap only happen between DP-BG and DC, while DP-FG disable */  
    13. 1683     if (((mxcfbi->ipu_ch == MEM_BG_SYNC) &&  
    14. 1684          (strstr(buf, "1-layer-fb") != NULL)) ||  
    15. 1685         ((mxcfbi->ipu_ch == MEM_DC_SYNC) &&  
    16. 1686          (strstr(buf, "2-layer-fb-bg") != NULL))) {  
    17. 1687         int i;  
    18. 1688   
    19. 1689         for (i = 0; i < num_registered_fb; i++) {  
    20. 1690             fg_mxcfbi =  
    21. 1691                 (struct mxcfb_info *)mxcfb_info[i]->par;  
    22. 1692             if (fg_mxcfbi->ipu_ch == MEM_FG_SYNC)  
    23. 1693                 break;  
    24. 1694             else  
    25. 1695                 fg_mxcfbi = NULL;  
    26. 1696         }  
    27. 1697         if (!fg_mxcfbi ||  
    28. 1698             fg_mxcfbi->cur_blank == FB_BLANK_UNBLANK) {  
    29. 1699             dev_err(dev,  
    30. 1700                 "Can not switch while fb2(fb-fg) is on. ");  
    31. 1701             release_console_sem();  
    32. 1702             return count;  
    33. 1703         }  
    34. 1704   
    35. 1705         if (swap_channels(info) < 0)  
    36. 1706             dev_err(dev, "Swap display channel failed. ");  
    37. 1707     }  
    38. 1708   
    39. 1709     release_console_sem();  
    40. 1710     return count;  
    41. 1711 }  
    42. 1712 DEVICE_ATTR(fsl_disp_property, 644, show_disp_chan, swap_disp_chan);  

    1682~1686 只有fb0和fb1才会参与显示通道的交换,fb2只使用MEM_FG_SYNC
    1705 调用swap_channels实现通道的切换
    [cpp] view plaincopy
     
     
    1. swap_channels  
    2.   
    3.  545 static int swap_channels(struct fb_info *fbi)  
    4.  546 {  
    5.  547     int i;  
    6.  548     int swap_mode;  
    7.  549     ipu_channel_t ch_to;  
    8.  550     struct mxcfb_info *mxc_fbi_from = (struct mxcfb_info *)fbi->par;  
    9.  551     struct fb_info *fbi_to = NULL;  
    10.  552     struct mxcfb_info *mxc_fbi_to;  
    11.  553   
    12.  554     /* what's the target channel? */  
    13.  555     if (mxc_fbi_from->ipu_ch == MEM_BG_SYNC)  
    14.  556         ch_to = MEM_DC_SYNC;  
    15.  557     else  
    16.  558         ch_to = MEM_BG_SYNC;  
    17.  559   
    18.  560     for (i = 0; i < num_registered_fb; i++) {  
    19.  561         mxc_fbi_to =  
    20.  562             (struct mxcfb_info *)mxcfb_info[i]->par;  
    21.  563         if (mxc_fbi_to->ipu_ch == ch_to) {  
    22.  564             fbi_to = mxcfb_info[i];  
    23.  565             break;  
    24.  566         }  
    25.  567     }  
    26.  568     if (fbi_to == NULL)  
    27.  569         return -1;  
    28.  570   
    29.  571     ipu_clear_irq(mxc_fbi_from->ipu_ch_irq);  
    30.  572     ipu_clear_irq(mxc_fbi_to->ipu_ch_irq);  
    31.  573     ipu_free_irq(mxc_fbi_from->ipu_ch_irq, fbi);  
    32.  574     ipu_free_irq(mxc_fbi_to->ipu_ch_irq, fbi_to);  
    33.  575   
    34.  576     if (mxc_fbi_from->cur_blank == FB_BLANK_UNBLANK) {  
    35.  577         if (mxc_fbi_to->cur_blank == FB_BLANK_UNBLANK)  
    36.  578             swap_mode = BOTH_ON;  
    37.  579         else  
    38.  580             swap_mode = SRC_ON;  
    39.  581     } else {  
    40.  582         if (mxc_fbi_to->cur_blank == FB_BLANK_UNBLANK)  
    41.  583             swap_mode = TGT_ON;  
    42.  584         else  
    43.  585             swap_mode = BOTH_OFF;  
    44.  586     }  
    45.  587   
    46.  588     /* tvout di-1: for DC use UYVY, for DP use RGB */  
    47.  589     if (mxc_fbi_from->ipu_di == 1 && ch_to == MEM_DC_SYNC) {  
    48.  590         fbi->var.bits_per_pixel = 16;  
    49.  591         fbi->var.nonstd = IPU_PIX_FMT_UYVY;  
    50.  592     } else if (mxc_fbi_from->ipu_di == 1 && ch_to == MEM_BG_SYNC) {  
    51.  593         fbi->var.nonstd = 0;  
    52.  594     } else if (mxc_fbi_from->ipu_di == 0 && ch_to == MEM_DC_SYNC) {  
    53.  595         fbi_to->var.nonstd = 0;  
    54.  596     } else if (mxc_fbi_from->ipu_di == 0 && ch_to == MEM_BG_SYNC) {  
    55.  597         fbi->var.bits_per_pixel = 16;  
    56.  598         fbi->var.nonstd = IPU_PIX_FMT_UYVY;  
    57.  599     }  
    58.  600   
    59.  601     switch (swap_mode) {  
    60.  602     case BOTH_ON:  
    61.  603         /* disable target->switch src->enable target */  
    62.  604         _swap_channels(fbi, fbi_to, true);  
    63.  605         break;  
    64.  606     case SRC_ON:  
    65.  607         /* just switch src */  
    66.  608         _swap_channels(fbi, fbi_to, false);  
    67.  609         break;  
    68.  610     case TGT_ON:  
    69.  611         /* just switch target */  
    70.  612         _swap_channels(fbi_to, fbi, false);  
    71.  613         break;  
    72.  614     case BOTH_OFF:  
    73.  615         /* switch directly, no more need to do */  
    74.  616         mxc_fbi_to->ipu_ch = mxc_fbi_from->ipu_ch;  
    75.  617         mxc_fbi_from->ipu_ch = ch_to;  
    76.  618         i = mxc_fbi_from->ipu_ch_irq;  
    77.  619         mxc_fbi_from->ipu_ch_irq = mxc_fbi_to->ipu_ch_irq;  
    78.  620         mxc_fbi_to->ipu_ch_irq = i;  
    79.  621         break;  
    80.  622     default:  
    81.  623         break;  
    82.  624     }  
    83.  625   
    84.  626     if (ipu_request_irq(mxc_fbi_from->ipu_ch_irq, mxcfb_irq_handler, 0,  
    85.  627         MXCFB_NAME, fbi) != 0) {  
    86.  628         dev_err(fbi->device, "Error registering irq %d ",  
    87.  629             mxc_fbi_from->ipu_ch_irq);  
    88.  630         return -EBUSY;  
    89.  631     }  
    90.  632     ipu_disable_irq(mxc_fbi_from->ipu_ch_irq);  
    91.  633     if (ipu_request_irq(mxc_fbi_to->ipu_ch_irq, mxcfb_irq_handler, 0,  
    92.  634         MXCFB_NAME, fbi_to) != 0) {  
    93.  635         dev_err(fbi_to->device, "Error registering irq %d ",  
    94.  636             mxc_fbi_to->ipu_ch_irq);  
    95.  637         return -EBUSY;  
    96.  638     }  
    97.  639     ipu_disable_irq(mxc_fbi_to->ipu_ch_irq);  
    98.  640   
    99.  641     return 0;  
    100.  642 }   

    550 mxc_fbi_from 和字面意思一样,我们想要交换哪一个fb_info,也就是交换源

    555~558 交换只发生在MEM_DC_SYNC和MEM_BG_SYNC之间,如果源fb的通道是MEM_BG_SYNC,那么我们希望交换为MEM_DC_SYNC,反之亦然。

    560~567 找到目标通道坐在的framebuffer

    576~586 swap_mode记录下source和dest framebuffer的blank状态

    571~574 先释放from和to的ipu 通道中断号,因为IPU通道中断号也会随着通道一起交换

    589~599 I have no idea

    601~613 _swap_channels进行交换

    614~620 如果fbi_from和fbi_to都处于BLANK状态,那么直接交换通道即可,注意通道中断号也需要交换,因为通道和通道中断号是一一对应的。

    626~642 重新为fbi_from和fbi_to申请ipu irq,这里disable了irq,不过不要紧,当pan_display操作时,会使能ipu irq

    [cpp] view plaincopy
     
     
    1. swap_channels  
    2.   
    3.  504 static int _swap_channels(struct fb_info *fbi,  
    4.  505               struct fb_info *fbi_to, bool both_on)  
    5.  506 {  
    6.  507     int retval, tmp;  
    7.  508     ipu_channel_t old_ch;  
    8.  509     struct mxcfb_info *mxc_fbi_from = (struct mxcfb_info *)fbi->par;  
    9.  510     struct mxcfb_info *mxc_fbi_to = (struct mxcfb_info *)fbi_to->par;  
    10.  511   
    11.  512     if (both_on) {  
    12.  513         ipu_disable_channel(mxc_fbi_to->ipu_ch, true);  
    13.  514         ipu_uninit_channel(mxc_fbi_to->ipu_ch);  
    14.  515     }  
    15.  516   
    16.  517     /* switch the mxc fbi parameters */  
    17.  518     old_ch = mxc_fbi_from->ipu_ch;  
    18.  519     mxc_fbi_from->ipu_ch = mxc_fbi_to->ipu_ch;  
    19.  520     mxc_fbi_to->ipu_ch = old_ch;  
    20.  521     tmp = mxc_fbi_from->ipu_ch_irq;  
    21.  522     mxc_fbi_from->ipu_ch_irq = mxc_fbi_to->ipu_ch_irq;  
    22.  523     mxc_fbi_to->ipu_ch_irq = tmp;  
    23.  524   
    24.  525     _setup_disp_channel1(fbi);  
    25.  526     retval = _setup_disp_channel2(fbi);  
    26.  527     if (retval)  
    27.  528         return retval;  
    28.  529   
    29.  530     /* switch between dp and dc, disable old idmac, enable new idmac */  
    30.  531     retval = ipu_swap_channel(old_ch, mxc_fbi_from->ipu_ch);  
    31.  532     ipu_uninit_channel(old_ch);  
    32.  533   
    33.  534     if (both_on) {  
    34.  535         _setup_disp_channel1(fbi_to);  
    35.  536         retval = _setup_disp_channel2(fbi_to);  
    36.  537         if (retval)  
    37.  538             return retval;  
    38.  539         ipu_enable_channel(mxc_fbi_to->ipu_ch);  
    39.  540     }  
    40.  541   
    41.  542     return retval;  
    42.  543 }  

    504~505 函数有三个参数,@fbi是source,@fbi_to是dest,@both_on 布尔量为true 则@fbi_to为UNBLANK状态;false,则@fbi_to为BLANK状态。这里@fbi一定为UNBLANK状态,否则不会调用这个函数。

    512~515 在交换之前,先销毁掉@fbi_to的channel

    518~523 交换二者的通道和通道irq

    525~528 交换完成后,设置disp通道的参数。

    531~532 现在,通道号已经交换完成,但是还有一件事没有完成,我们知道DC通道1,5的控制寄存器DC_WR_CH_CONF_x中,配置着这个DC通道连接到哪一个DI,我们希望交换通道,但是不希望更改到DI的配置。ipu_swap_channel交换两个DC通道的DI配置。

    [cpp] view plaincopy
     
     
    1. <pre></pre>  
    2. <pre></pre>  
    3. <pre></pre>  
    4. <pre></pre>  
    5. <pre></pre>  
    6. <pre></pre>  
     
     
  • 相关阅读:
    动态链接库DLL
    异常处理
    内存
    线程同步
    线程基础、线程调度
    笔记摘录:进程、作业
    工具DebugView、PCHunter、Procexp、Procmon
    使用Windbg和VMware来搭建调试内核的环境
    C++智能指针
    AndroidEventBus
  • 原文地址:https://www.cnblogs.com/senior-engineer/p/6232433.html
Copyright © 2020-2023  润新知