我是靠谱客的博主 落后眼睛,最近开发中收集的这篇文章主要介绍IMX6 LCD 参数匹配过程分析[IMX6Q]LCD参数匹配过程分析 ,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

[IMX6Q]LCD参数匹配过程分析

2072人阅读 评论(0) 收藏 举报
本文章已收录于:
分类:
作者同类文章 X

    Platform: IMX6Q

    OS: Android 4.4


    本文只讨论lvds接口的是lcd参数匹配的过程,mipi dsi以及其他接口部分会有一点差异。


    核心函数fb_find_mode(),在分析之前先了解下几个参数。


    重要参数说明:


    1. ldb.c中的 ldb_modedb

    [cpp] view plain copy
    print ?
    1. static struct fb_videomode ldb_modedb[] = {  
    2.     {  
    3.      "LDB-WXGA", 60, 1280, 800, 14065,  
    4.      40, 40,  
    5.      10, 3,  
    6.      80, 10,  
    7.      0,  
    8.      FB_VMODE_NONINTERLACED,  
    9.      FB_MODE_IS_DETAILED,},  
    10.     {  
    11.      "LDB-XGA", 60, 1024, 768, 15385,  
    12.      220, 40,  
    13.      21, 7,  
    14.      60, 10,  
    15.      0,  
    16.      FB_VMODE_NONINTERLACED,  
    17.      FB_MODE_IS_DETAILED,},  
    18.     {  
    19.      "LDB-1080P60", 60, 1920, 1080, 7692,  
    20.      100, 40,  
    21.      30, 3,  
    22.      10, 2,  
    23.      0,  
    24.      FB_VMODE_NONINTERLACED,  
    25.      FB_MODE_IS_DETAILED,},  
    26.      {  
    27.      "LDB-WSVGA"//Name  
    28.      60, //refresh  
    29.      1024, //xres  
    30.      600, //yres  
    31.      19531,//pixclock  
    32.      220, 40,//left/right margin  
    33.      21, 7,//upper/lower margin  
    34.      60, 7,//hsync_len,vsync_len  
    35.      0,//sync  
    36.      FB_VMODE_NONINTERLACED,//vmode  
    37.      FB_MODE_IS_DETAILED,},  
    38. };  
    39. static int ldb_modedb_sz = ARRAY_SIZE(ldb_modedb);  
    static struct fb_videomode ldb_modedb[] = {
    {
    "LDB-WXGA", 60, 1280, 800, 14065,
    40, 40,
    10, 3,
    80, 10,
    0,
    FB_VMODE_NONINTERLACED,
    FB_MODE_IS_DETAILED,},
    {
    "LDB-XGA", 60, 1024, 768, 15385,
    220, 40,
    21, 7,
    60, 10,
    0,
    FB_VMODE_NONINTERLACED,
    FB_MODE_IS_DETAILED,},
    {
    "LDB-1080P60", 60, 1920, 1080, 7692,
    100, 40,
    30, 3,
    10, 2,
    0,
    FB_VMODE_NONINTERLACED,
    FB_MODE_IS_DETAILED,},
    {
    "LDB-WSVGA", //Name
    60, //refresh
    1024, //xres
    600, //yres
    19531,//pixclock
    220, 40,//left/right margin
    21, 7,//upper/lower margin
    60, 7,//hsync_len,vsync_len
    0,//sync
    FB_VMODE_NONINTERLACED,//vmode
    FB_MODE_IS_DETAILED,},
    };
    static int ldb_modedb_sz = ARRAY_SIZE(ldb_modedb);

    系统lvds接口支持的lcd时序参数都在此了。

    2. board-mx6-xxx.c中的ipuv3_fb_platform_data结构

    本例是:

    [cpp] view plain copy
    print ?
    1. static struct ipuv3_fb_platform_data tek_fb_data[] = {  
    2.     { /*fb0*/  
    3.     .disp_dev = "ldb",  
    4.     .interface_pix_fmt = IPU_PIX_FMT_RGB24,  
    5.     .mode_str = "LDB-WSVGA",  
    6.     .default_bpp = 32,  
    7.     .int_clk = false,  
    8.     .late_init = false,  
    9.     }, {  
    10.     .disp_dev = "hdmi",  
    11.     .interface_pix_fmt = IPU_PIX_FMT_RGB24,  
    12.     .mode_str = "1920x1080M@60",  
    13.     .default_bpp = 32,  
    14.     .int_clk = false,  
    15.     .late_init = false,  
    16.     },  
    17.     {  
    18.     .disp_dev = "lcd",  
    19.     .interface_pix_fmt = IPU_PIX_FMT_RGB565,  
    20.     .mode_str = "CLAA-WVGA",  
    21.     .default_bpp = 16,  
    22.     .int_clk = false,  
    23.     .late_init = false,  
    24.     }, {  
    25.     .disp_dev = "ldb",  
    26.     .interface_pix_fmt = IPU_PIX_FMT_RGB666,  
    27.     .mode_str = "LDB-VGA",  
    28.     .default_bpp = 16,  
    29.     .int_clk = false,  
    30.     .late_init = false,  
    31.     },  
    32. };  
    static struct ipuv3_fb_platform_data tek_fb_data[] = {
    { /*fb0*/
    .disp_dev = "ldb",
    .interface_pix_fmt = IPU_PIX_FMT_RGB24,
    .mode_str = "LDB-WSVGA",
    .default_bpp = 32,
    .int_clk = false,
    .late_init = false,
    }, {
    .disp_dev = "hdmi",
    .interface_pix_fmt = IPU_PIX_FMT_RGB24,
    .mode_str = "1920x1080M@60",
    .default_bpp = 32,
    .int_clk = false,
    .late_init = false,
    },
    {
    .disp_dev = "lcd",
    .interface_pix_fmt = IPU_PIX_FMT_RGB565,
    .mode_str = "CLAA-WVGA",
    .default_bpp = 16,
    .int_clk = false,
    .late_init = false,
    }, {
    .disp_dev = "ldb",
    .interface_pix_fmt = IPU_PIX_FMT_RGB666,
    .mode_str = "LDB-VGA",
    .default_bpp = 16,
    .int_clk = false,
    .late_init = false,
    },
    };

    fb_find_mode()用到其mode_str里的值去ldb_modedb查找有没有对应lcd时序参数。

    此mode_str其实就是后面会提到的mode_options, 格式如下:

      <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m] or
        <name>[-<bpp>][@<refresh>]

    所以有两种类型:

    1. 字符规则形, 如 “LDB-WXVGA”

    2. 数字规则形,如"1920*1080"

    具体各个参数意义可参照fb_find_mode()函数注释。


    3.  kernel cmdline里设置的

    本例是:

    video=mxcfb0:dev=ldb,LDB-WSVGA,if=RGB24,bpp=32

    它会覆盖 tek_fb_data中的值,覆盖规则根据mxcfb后面的值。

    比如mxcfb0覆盖tek_fb_data[0], 以此类推。

    了解了参数意义之后下面就方便理解了.


    系统有如下调用:

    [cpp] view plain copy
    print ?
    1. static int ldb_disp_init(struct mxc_dispdrv_handle *disp,  
    2.     struct mxc_dispdrv_setting *setting) {  
    3. ......  
    4.     ret = fb_find_mode(&setting->fbi->var, setting->fbi, setting->dft_mode_str,  
    5.                 ldb_modedb, ldb_modedb_sz, NULL, setting->default_bpp);  
    6. ......  
    7. }  
    static int ldb_disp_init(struct mxc_dispdrv_handle *disp,
        struct mxc_dispdrv_setting *setting) {
    ......
    ret = fb_find_mode(&setting->fbi->var, setting->fbi, setting->dft_mode_str,
    ldb_modedb, ldb_modedb_sz, NULL, setting->default_bpp);
    ......
    }
    

    本例:

    setting->dft_mode_str为: "LDB-WSVGA"

    setting->default_bpp为: 32


    下面看代码执行流程:


    [cpp] view plain copy
    print ?
    1. /** 
    2.  *    fb_find_mode - finds a valid video mode 
    3.  *    @var: frame buffer user defined part of display 
    4.  *    @info: frame buffer info structure 
    5.  *    @mode_option: string video mode to find 
    6.  *    @db: video mode database 
    7.  *    @dbsize: size of @db 
    8.  *    @default_mode: default video mode to fall back to 
    9.  *    @default_bpp: default color depth in bits per pixel 
    10.  * 
    11.  *    Finds a suitable video mode, starting with the specified mode 
    12.  *    in @mode_option with fallback to @default_mode.  If 
    13.  *    @default_mode fails, all modes in the video mode database will 
    14.  *    be tried. 
    15.  * 
    16.  *    Valid mode specifiers for @mode_option: 
    17.  * 
    18.  *    <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m] or 
    19.  *    <name>[-<bpp>][@<refresh>] 
    20.  * 
    21.  *    with <xres>, <yres>, <bpp> and <refresh> decimal numbers and 
    22.  *    <name> a string. 
    23.  * 
    24.  *      If 'M' is present after yres (and before refresh/bpp if present), 
    25.  *      the function will compute the timings using VESA(tm) Coordinated 
    26.  *      Video Timings (CVT).  If 'R' is present after 'M', will compute with 
    27.  *      reduced blanking (for flatpanels).  If 'i' is present, compute 
    28.  *      interlaced mode.  If 'm' is present, add margins equal to 1.8% 
    29.  *      of xres rounded down to 8 pixels, and 1.8% of yres. The char 
    30.  *      'i' and 'm' must be after 'M' and 'R'. Example: 
    31.  * 
    32.  *      1024x768MR-8@60m - Reduced blank with margins at 60Hz. 
    33.  * 
    34.  *    NOTE: The passed struct @var is _not_ cleared!  This allows you 
    35.  *    to supply values for e.g. the grayscale and accel_flags fields. 
    36.  * 
    37.  *    Returns zero for failure, 1 if using specified @mode_option, 
    38.  *    2 if using specified @mode_option with an ignored refresh rate, 
    39.  *    3 if default mode is used, 4 if fall back to any valid mode. 
    40.  * 
    41.  */  
    42. int fb_find_mode(struct fb_var_screeninfo *var,  
    43.          struct fb_info *info, const char *mode_option,  
    44.          const struct fb_videomode *db, unsigned int dbsize,  
    45.          const struct fb_videomode *default_mode,  
    46.          unsigned int default_bpp)  
    47. {  
    48.     int i;  
    49.   
    50.     /* Set up defaults */  
    51.     /*参数未给则使用modedb。*/  
    52.     if (!db) {  
    53.     db = modedb;  
    54.     dbsize = ARRAY_SIZE(modedb);  
    55.     }  
    56.   
    57.     /*如果没设置则使用db[0]的值,此例传进来的本身就是db[0]*/  
    58.     if (!default_mode)  
    59.     default_mode = &db[0];  
    60.     /*没有设置bpp则默认使用8bpp,本例是32*/  
    61.     if (!default_bpp)  
    62.     default_bpp = 8;  
    63.   
    64.     /* Did the user specify a video mode? */  
    65.     if (!mode_option)  
    66.     mode_option = fb_mode_option;  
    67.     /*本例是“LDB-WSVGA”*/  
    68.     if (mode_option) {  
    69.     const char *name = mode_option;  
    70.     unsigned int namelen = strlen(name);  
    71.     int res_specified = 0, bpp_specified = 0, refresh_specified = 0;  
    72.     unsigned int xres = 0, yres = 0, bpp = default_bpp, refresh = 0;  
    73.     int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0;  
    74.     u32 best, diff, tdiff;  
    75.        /*数字格式规则形才会跑下面的循环*/  
    76.     for (i = namelen-1; i >= 0; i--) {  
    77.         switch (name[i]) {  
    78.                 /*@后面的是刷新频率*/  
    79.                 case '@':  
    80.             namelen = i;  
    81.             if (!refresh_specified && !bpp_specified &&  
    82.             !yres_specified) {  
    83.             refresh = simple_strtol(&name[i+1], NULL, 10);  
    84.             refresh_specified = 1;  
    85.             if (cvt || rb)  
    86.                 cvt = 0;  
    87.             } else  
    88.             goto done;  
    89.             break;  
    90.                 /*后面是bpp*/  
    91.                 case '-':  
    92.             namelen = i;  
    93.             printk("line:%dn", __LINE__);  
    94.             if (!bpp_specified && !yres_specified) {  
    95.             bpp = simple_strtol(&name[i+1], NULL, 10);  
    96.             bpp_specified = 1;  
    97.             if (cvt || rb)  
    98.                 cvt = 0;  
    99.             } else  
    100.             goto done;  
    101.             break;  
    102.                 /*获取yres*/  
    103.         case 'x':  
    104.             if (!yres_specified) {  
    105.             yres = simple_strtol(&name[i+1], NULL, 10);  
    106.             yres_specified = 1;  
    107.             } else  
    108.             goto done;  
    109.             break;  
    110.         case '0' ... '9':  
    111.             break;  
    112.         case 'M':  
    113.             if (!yres_specified)  
    114.             cvt = 1;  
    115.             break;  
    116.         case 'R':  
    117.             if (!cvt)  
    118.             rb = 1;  
    119.             break;  
    120.         case 'm':  
    121.             if (!cvt)  
    122.             margins = 1;  
    123.             break;  
    124.         case 'i':  
    125.             if (!cvt)  
    126.             interlace = 1;  
    127.             break;  
    128.         default:  
    129.             goto done;  
    130.         }  
    131.     }  
    132.         /*如果yres有值,那么也获取xres.*/  
    133.         if (i < 0 && yres_specified) {  
    134.         xres = simple_strtol(name, NULL, 10);  
    135.         res_specified = 1;  
    136.     }  
    137. done:  
    138.         /*不会跑这里*/  
    139.         if (cvt) {  
    140.         struct fb_videomode cvt_mode;  
    141.         int ret;  
    142.   
    143.         DPRINTK("CVT mode %dx%d@%dHz%s%s%sn", xres, yres,  
    144.             (refresh) ? refresh : 60, (rb) ? " reduced blanking" :  
    145.             "", (margins) ? " with margins" : "", (interlace) ?  
    146.             " interlaced" : "");  
    147.   
    148.         memset(&cvt_mode, 0, sizeof(cvt_mode));  
    149.         cvt_mode.xres = xres;  
    150.         cvt_mode.yres = yres;  
    151.         cvt_mode.refresh = (refresh) ? refresh : 60;  
    152.   
    153.         if (interlace)  
    154.         cvt_mode.vmode |= FB_VMODE_INTERLACED;  
    155.         else  
    156.         cvt_mode.vmode &= ~FB_VMODE_INTERLACED;  
    157.   
    158.         ret = fb_find_mode_cvt(&cvt_mode, margins, rb);  
    159.   
    160.         if (!ret && !fb_try_mode(var, info, &cvt_mode, bpp)) {  
    161.         DPRINTK("modedb CVT: CVT mode okn");  
    162.         return 1;  
    163.         }  
    164.   
    165.         DPRINTK("CVT mode invalid, getting mode from databasen");  
    166.     }  
    167.   
    168.     DPRINTK("Trying specified video mode%s %ix%in",  
    169.         refresh_specified ? "" : " (ignoring refresh rate)", xres, yres);  
    170.   
    171.        /*刷新率没指定*/  
    172.        if (!refresh_specified) {  
    173.         /* 
    174.          * If the caller has provided a custom mode database and a 
    175.          * valid monspecs structure, we look for the mode with the 
    176.          * highest refresh rate.  Otherwise we play it safe it and 
    177.          * try to find a mode with a refresh rate closest to the 
    178.          * standard 60 Hz. 
    179.          */  
    180.         if (db != modedb &&  
    181.             info->monspecs.vfmin && info->monspecs.vfmax &&  
    182.             info->monspecs.hfmin && info->monspecs.hfmax &&  
    183.             info->monspecs.dclkmax) {  
    184.               refresh = 1000;  
    185.         } else {  
    186.                     /*默认使用60HZ*/  
    187.                     refresh = 60;  
    188.         }  
    189.     }  
    190.   
    191.     diff = -1;  
    192.     best = -1;  
    193.         /*根据名字以及或者分辨率来匹配。*/  
    194.         for (i = 0; i < dbsize; i++) {  
    195.         if ((name_matches(db[i], name, namelen) ||  
    196.             (res_specified && res_matches(db[i], xres, yres))) &&  
    197.             !fb_try_mode(var, info, &db[i], bpp)) {  
    198.                        /*刷新率也匹配的时候就认准你了!*/  
    199.                        if (refresh_specified && db[i].refresh == refresh) {  
    200.                 return 1;  
    201.             } else {  
    202.                               /*刷新率不一样就找差得最少的*/    
    203.                               if (abs(db[i].refresh - refresh) < diff) {  
    204.                     diff = abs(db[i].refresh - refresh);  
    205.                     best = i;  
    206.                 }  
    207.             }  
    208.         }  
    209.     }  
    210.     /*得到刷新率差得最少的db,然后返回*/  
    211.        if (best != -1) {  
    212.         fb_try_mode(var, info, &db[best], bpp);  
    213.         return (refresh_specified) ? 2 : 1;  
    214.     }  
    215.   
    216.     /*跑到这里说明名字和分辨率都不匹配。*/  
    217.     diff = 2 * (xres + yres);  
    218.     best = -1;  
    219.     DPRINTK("Trying best-fit modesn");  
    220.         /*找到分辨率最小的那组数据。*/  
    221.         for (i = 0; i < dbsize; i++) {  
    222.                 DPRINTK("Trying %ix%in", db[i].xres, db[i].yres);  
    223.         if (!fb_try_mode(var, info, &db[i], bpp)) {  
    224.              tdiff = abs(db[i].xres - xres) +  
    225.                 abs(db[i].yres - yres);  
    226.   
    227.              /* 
    228.              * Penalize modes with resolutions smaller 
    229.              * than requested. 
    230.              */  
    231.             if (xres > db[i].xres || yres > db[i].yres)  
    232.                 tdiff += xres + yres;  
    233.                        /*差值大的会被保留,说白了,最终就是找到分辨率最小的那组参数。*/  
    234.             if (diff > tdiff) {  
    235.                 diff = tdiff;  
    236.                 best = i;  
    237.             }  
    238.         }  
    239.     }  
    240.        /*获取best对应的var参数。*/  
    241.        if (best != -1) {  
    242.         fb_try_mode(var, info, &db[best], bpp);  
    243.         return 5;  
    244.     }  
    245.     }  
    246.   
    247.     /*运行到这里有两种情况, 
    248.      1. 字母规则型(如LDB-WXVGA),那就是名字不匹配,并且参数检查失败,。 
    249.      2. 数字规则性(如1920x1080), 那就是名字不匹配 && 分辨率比ldb_modedb中的小上两倍以上(比如1920x1080 和 320x240)。 */  
    250.     DPRINTK("Trying default video moden");  
    251.     if (!fb_try_mode(var, info, default_mode, default_bpp))  
    252.     return 3;  
    253.   
    254.     DPRINTK("Trying all modesn");  
    255.     /*默认的还失败那我只能随便找一个了。*/  
    256.     for (i = 0; i < dbsize; i++)  
    257.     if (!fb_try_mode(var, info, &db[i], default_bpp))  
    258.         return 4;  
    259.   
    260.     /*随便都不行,那我只能失败了...*/  
    261.     DPRINTK("No valid mode foundn");  
    262.     return 0;  
    263. }   
    /**
     *    fb_find_mode - finds a valid video mode
     *    @var: frame buffer user defined part of display
     *    @info: frame buffer info structure
     *    @mode_option: string video mode to find
     *    @db: video mode database
     *    @dbsize: size of @db
     *    @default_mode: default video mode to fall back to
     *    @default_bpp: default color depth in bits per pixel
     *
     *    Finds a suitable video mode, starting with the specified mode
     *    in @mode_option with fallback to @default_mode.  If
     *    @default_mode fails, all modes in the video mode database will
     *    be tried.
     *
     *    Valid mode specifiers for @mode_option:
     *
     *    <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m] or
     *    <name>[-<bpp>][@<refresh>]
     *
     *    with <xres>, <yres>, <bpp> and <refresh> decimal numbers and
     *    <name> a string.
     *
     *      If 'M' is present after yres (and before refresh/bpp if present),
     *      the function will compute the timings using VESA(tm) Coordinated
     *      Video Timings (CVT).  If 'R' is present after 'M', will compute with
     *      reduced blanking (for flatpanels).  If 'i' is present, compute
     *      interlaced mode.  If 'm' is present, add margins equal to 1.8%
     *      of xres rounded down to 8 pixels, and 1.8% of yres. The char
     *      'i' and 'm' must be after 'M' and 'R'. Example:
     *
     *      1024x768MR-8@60m - Reduced blank with margins at 60Hz.
     *
     *    NOTE: The passed struct @var is _not_ cleared!  This allows you
     *    to supply values for e.g. the grayscale and accel_flags fields.
     *
     *    Returns zero for failure, 1 if using specified @mode_option,
     *    2 if using specified @mode_option with an ignored refresh rate,
     *    3 if default mode is used, 4 if fall back to any valid mode.
     *
     */
    int fb_find_mode(struct fb_var_screeninfo *var,
    struct fb_info *info, const char *mode_option,
    const struct fb_videomode *db, unsigned int dbsize,
    const struct fb_videomode *default_mode,
    unsigned int default_bpp)
    {
    int i;
    /* Set up defaults */
    /*参数未给则使用modedb。*/
    if (!db) {
    db = modedb;
    dbsize = ARRAY_SIZE(modedb);
    }
    /*如果没设置则使用db[0]的值,此例传进来的本身就是db[0]*/
    if (!default_mode)
    default_mode = &db[0];
    /*没有设置bpp则默认使用8bpp,本例是32*/
    if (!default_bpp)
    default_bpp = 8;
    /* Did the user specify a video mode? */
    if (!mode_option)
    mode_option = fb_mode_option;
    /*本例是“LDB-WSVGA”*/
     if (mode_option) {
    const char *name = mode_option;
    unsigned int namelen = strlen(name);
    int res_specified = 0, bpp_specified = 0, refresh_specified = 0;
    unsigned int xres = 0, yres = 0, bpp = default_bpp, refresh = 0;
    int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0;
    u32 best, diff, tdiff;
    /*数字格式规则形才会跑下面的循环*/
    for (i = namelen-1; i >= 0; i--) {
    switch (name[i]) {
    /*@后面的是刷新频率*/
    case '@':
    namelen = i;
    if (!refresh_specified && !bpp_specified &&
    !yres_specified) {
    refresh = simple_strtol(&name[i+1], NULL, 10);
    refresh_specified = 1;
    if (cvt || rb)
    cvt = 0;
    } else
    goto done;
    break;
    /*后面是bpp*/
    case '-':
    namelen = i;
    printk("line:%dn", __LINE__);
    if (!bpp_specified && !yres_specified) {
    bpp = simple_strtol(&name[i+1], NULL, 10);
    bpp_specified = 1;
    if (cvt || rb)
    cvt = 0;
    } else
    goto done;
    break;
    /*获取yres*/
    case 'x':
    if (!yres_specified) {
    yres = simple_strtol(&name[i+1], NULL, 10);
    yres_specified = 1;
    } else
    goto done;
    break;
    case '0' ... '9':
    break;
    case 'M':
    if (!yres_specified)
    cvt = 1;
    break;
    case 'R':
    if (!cvt)
    rb = 1;
    break;
    case 'm':
    if (!cvt)
    margins = 1;
    break;
    case 'i':
    if (!cvt)
    interlace = 1;
    break;
    default:
    goto done;
    }
    }
    /*如果yres有值,那么也获取xres.*/
     if (i < 0 && yres_specified) {
    xres = simple_strtol(name, NULL, 10);
    res_specified = 1;
    }
    done:
    /*不会跑这里*/
    if (cvt) {
    struct fb_videomode cvt_mode;
    int ret;
    DPRINTK("CVT mode %dx%d@%dHz%s%s%sn", xres, yres,
    (refresh) ? refresh : 60, (rb) ? " reduced blanking" :
    "", (margins) ? " with margins" : "", (interlace) ?
    " interlaced" : "");
    memset(&cvt_mode, 0, sizeof(cvt_mode));
    cvt_mode.xres = xres;
    cvt_mode.yres = yres;
    cvt_mode.refresh = (refresh) ? refresh : 60;
    if (interlace)
    cvt_mode.vmode |= FB_VMODE_INTERLACED;
    else
    cvt_mode.vmode &= ~FB_VMODE_INTERLACED;
    ret = fb_find_mode_cvt(&cvt_mode, margins, rb);
    if (!ret && !fb_try_mode(var, info, &cvt_mode, bpp)) {
    DPRINTK("modedb CVT: CVT mode okn");
    return 1;
    }
    DPRINTK("CVT mode invalid, getting mode from databasen");
    }
    DPRINTK("Trying specified video mode%s %ix%in",
    refresh_specified ? "" : " (ignoring refresh rate)", xres, yres);
    /*刷新率没指定*/
    if (!refresh_specified) {
    /*
    * If the caller has provided a custom mode database and a
    * valid monspecs structure, we look for the mode with the
    * highest refresh rate.
    Otherwise we play it safe it and
    * try to find a mode with a refresh rate closest to the
    * standard 60 Hz.
    */
    if (db != modedb &&
    info->monspecs.vfmin && info->monspecs.vfmax &&
    info->monspecs.hfmin && info->monspecs.hfmax &&
    info->monspecs.dclkmax) {
    refresh = 1000;
    } else {
    /*默认使用60HZ*/
     refresh = 60;
    }
    }
    diff = -1;
    best = -1;
    /*根据名字以及或者分辨率来匹配。*/
     for (i = 0; i < dbsize; i++) {
    if ((name_matches(db[i], name, namelen) ||
    (res_specified && res_matches(db[i], xres, yres))) &&
    !fb_try_mode(var, info, &db[i], bpp)) {
    /*刷新率也匹配的时候就认准你了!*/
    if (refresh_specified && db[i].refresh == refresh) {
    return 1;
    } else {
    /*刷新率不一样就找差得最少的*/
    if (abs(db[i].refresh - refresh) < diff) {
    diff = abs(db[i].refresh - refresh);
    best = i;
    }
    }
    }
    }
    /*得到刷新率差得最少的db,然后返回*/
    if (best != -1) {
    fb_try_mode(var, info, &db[best], bpp);
    return (refresh_specified) ? 2 : 1;
    }
    /*跑到这里说明名字和分辨率都不匹配。*/
    diff = 2 * (xres + yres);
    best = -1;
    DPRINTK("Trying best-fit modesn");
    /*找到分辨率最小的那组数据。*/
     for (i = 0; i < dbsize; i++) {
    DPRINTK("Trying %ix%in", db[i].xres, db[i].yres);
    if (!fb_try_mode(var, info, &db[i], bpp)) {
    tdiff = abs(db[i].xres - xres) +
    abs(db[i].yres - yres);
    /*
    * Penalize modes with resolutions smaller
    * than requested.
    */
    if (xres > db[i].xres || yres > db[i].yres)
    tdiff += xres + yres;
    /*差值大的会被保留,说白了,最终就是找到分辨率最小的那组参数。*/
    if (diff > tdiff) {
    diff = tdiff;
    best = i;
    }
    }
    }
    /*获取best对应的var参数。*/
    if (best != -1) {
    fb_try_mode(var, info, &db[best], bpp);
    return 5;
    }
    }
    /*运行到这里有两种情况,
    1. 字母规则型(如LDB-WXVGA),那就是名字不匹配,并且参数检查失败,。
    2. 数字规则性(如1920x1080), 那就是名字不匹配 && 分辨率比ldb_modedb中的小上两倍以上(比如1920x1080 和 320x240)。 */
    DPRINTK("Trying default video moden");
    if (!fb_try_mode(var, info, default_mode, default_bpp))
    return 3;
    DPRINTK("Trying all modesn");
    /*默认的还失败那我只能随便找一个了。*/
    for (i = 0; i < dbsize; i++)
    if (!fb_try_mode(var, info, &db[i], default_bpp))
    return 4;
    /*随便都不行,那我只能失败了...*/
    DPRINTK("No valid mode foundn");
    return 0;
    }
    

      其实本例中fb_try_mode返回的都是0,看代码,这里的作用基本上看成是得到当前对应的db值然后放再var中

    供后面的framebuffer driver使用。

    kernel_imxdriversvideomodedb.c

    [cpp] view plain copy
    print ?
    1. static int fb_try_mode(struct fb_var_screeninfo *var, struct fb_info *info,  
    2.                const struct fb_videomode *mode, unsigned int bpp)  
    3. {  
    4.     int err = 0;  
    5.   
    6.     DPRINTK("Trying mode %s %dx%d-%d@%dn", mode->name ? mode->name : "noname",  
    7.         mode->xres, mode->yres, bpp, mode->refresh);  
    8.     var->xres = mode->xres;  
    9.     var->yres = mode->yres;  
    10.     var->xres_virtual = mode->xres;  
    11.     var->yres_virtual = mode->yres;  
    12.     var->xoffset = 0;  
    13.     var->yoffset = 0;  
    14.     var->bits_per_pixel = bpp;  
    15.     var->activate |= FB_ACTIVATE_TEST;  
    16.     var->pixclock = mode->pixclock;  
    17.     var->left_margin = mode->left_margin;  
    18.     var->right_margin = mode->right_margin;  
    19.     var->upper_margin = mode->upper_margin;  
    20.     var->lower_margin = mode->lower_margin;  
    21.     var->hsync_len = mode->hsync_len;  
    22.     var->vsync_len = mode->vsync_len;  
    23.     var->sync = mode->sync;  
    24.     var->vmode = mode->vmode;  
    25.     if (info->fbops->fb_check_var)  
    26.         err = info->fbops->fb_check_var(var, info);  
    27.     var->activate &= ~FB_ACTIVATE_TEST;  
    28.     return err;  
    29. }  
    static int fb_try_mode(struct fb_var_screeninfo *var, struct fb_info *info,
    const struct fb_videomode *mode, unsigned int bpp)
    {
    int err = 0;
    DPRINTK("Trying mode %s %dx%d-%d@%dn", mode->name ? mode->name : "noname",
    mode->xres, mode->yres, bpp, mode->refresh);
    var->xres = mode->xres;
    var->yres = mode->yres;
    var->xres_virtual = mode->xres;
    var->yres_virtual = mode->yres;
    var->xoffset = 0;
    var->yoffset = 0;
    var->bits_per_pixel = bpp;
    var->activate |= FB_ACTIVATE_TEST;
    var->pixclock = mode->pixclock;
    var->left_margin = mode->left_margin;
    var->right_margin = mode->right_margin;
    var->upper_margin = mode->upper_margin;
    var->lower_margin = mode->lower_margin;
    var->hsync_len = mode->hsync_len;
    var->vsync_len = mode->vsync_len;
    var->sync = mode->sync;
    var->vmode = mode->vmode;
    if (info->fbops->fb_check_var)
    err = info->fbops->fb_check_var(var, info);
    var->activate &= ~FB_ACTIVATE_TEST;
    return err;
    }
    

    kernel_imxdriversvideomxcmxc_ipuv3_fb.c

    [cpp] view plain copy
    print ?
    1. static int mxcfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)  
    2. {  
    3.     u32 vtotal;  
    4.     u32 htotal;  
    5.     struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)info->par;  
    6.   
    7.   
    8.     if (var->xres == 0 || var->yres == 0) {  
    9.         return 0;  
    10.         }  
    11.     /* fg should not bigger than bg */  
    12.     if (mxc_fbi->ipu_ch == MEM_FG_SYNC) {  
    13.         struct fb_info *fbi_tmp;  
    14.         int bg_xres = 0, bg_yres = 0;  
    15.         int16_t pos_x, pos_y;  
    16.   
    17.         bg_xres = var->xres;  
    18.         bg_yres = var->yres;  
    19.   
    20.         fbi_tmp = found_registered_fb(MEM_BG_SYNC, mxc_fbi->ipu_id);  
    21.         if (fbi_tmp) {  
    22.             bg_xres = fbi_tmp->var.xres;  
    23.             bg_yres = fbi_tmp->var.yres;  
    24.         }  
    25.   
    26.         ipu_disp_get_window_pos(mxc_fbi->ipu, mxc_fbi->ipu_ch, &pos_x, &pos_y);  
    27.   
    28.         if ((var->xres + pos_x) > bg_xres)  
    29.             var->xres = bg_xres - pos_x;  
    30.         if ((var->yres + pos_y) > bg_yres)  
    31.             var->yres = bg_yres - pos_y;  
    32.     }  
    33.   
    34.     if (var->rotate > IPU_ROTATE_VERT_FLIP)  
    35.         var->rotate = IPU_ROTATE_NONE;  
    36.   
    37.     if (var->xres_virtual < var->xres)  
    38.         var->xres_virtual = var->xres;  
    39.   
    40.     if (var->yres_virtual < var->yres)  
    41.         var->yres_virtual = var->yres * 3;  
    42.   
    43.     if ((var->bits_per_pixel != 32) && (var->bits_per_pixel != 24) &&  
    44.         (var->bits_per_pixel != 16) && (var->bits_per_pixel != 12) &&  
    45.         (var->bits_per_pixel != 8))  
    46.         var->bits_per_pixel = 16;  
    47.   
    48.     if (check_var_pixfmt(var))  
    49.         /* Fall back to default */  
    50.         bpp_to_var(var->bits_per_pixel, var);  
    51.   
    52.     if (var->pixclock < 1000) {  
    53.         htotal = var->xres + var->right_margin + var->hsync_len +  
    54.             var->left_margin;  
    55.         vtotal = var->yres + var->lower_margin + var->vsync_len +  
    56.             var->upper_margin;  
    57.         var->pixclock = (vtotal * htotal * 6UL) / 100UL;  
    58.         var->pixclock = KHZ2PICOS(var->pixclock);  
    59.         dev_dbg(info->device,  
    60.             "pixclock set for 60Hz refresh = %u psn",  
    61.             var->pixclock);  
    62.     }  
    63.   
    64.     if (var->height == 0 && mxc_fbi->panel_height_mm)  
    65.         var->height = mxc_fbi->panel_height_mm;  
    66.     else if (var->height == 0)  
    67.         var->height = -1;  
    68.   
    69.     if (var->width == 0 && mxc_fbi->panel_width_mm)  
    70.         var->width = mxc_fbi->panel_width_mm;  
    71.     else if (var->width == 0)  
    72.         var->width = -1;  
    73.   
    74.     var->grayscale = 0;  
    75.   
    76.     return 0;  
    77. }  
    static int mxcfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
    {
    u32 vtotal;
    u32 htotal;
    struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)info->par;
    if (var->xres == 0 || var->yres == 0) {
    return 0;
    }
    /* fg should not bigger than bg */
    if (mxc_fbi->ipu_ch == MEM_FG_SYNC) {
    struct fb_info *fbi_tmp;
    int bg_xres = 0, bg_yres = 0;
    int16_t pos_x, pos_y;
    bg_xres = var->xres;
    bg_yres = var->yres;
    fbi_tmp = found_registered_fb(MEM_BG_SYNC, mxc_fbi->ipu_id);
    if (fbi_tmp) {
    bg_xres = fbi_tmp->var.xres;
    bg_yres = fbi_tmp->var.yres;
    }
    ipu_disp_get_window_pos(mxc_fbi->ipu, mxc_fbi->ipu_ch, &pos_x, &pos_y);
    if ((var->xres + pos_x) > bg_xres)
    var->xres = bg_xres - pos_x;
    if ((var->yres + pos_y) > bg_yres)
    var->yres = bg_yres - pos_y;
    }
    if (var->rotate > IPU_ROTATE_VERT_FLIP)
    var->rotate = IPU_ROTATE_NONE;
    if (var->xres_virtual < var->xres)
    var->xres_virtual = var->xres;
    if (var->yres_virtual < var->yres)
    var->yres_virtual = var->yres * 3;
    if ((var->bits_per_pixel != 32) && (var->bits_per_pixel != 24) &&
    (var->bits_per_pixel != 16) && (var->bits_per_pixel != 12) &&
    (var->bits_per_pixel != 8))
    var->bits_per_pixel = 16;
    if (check_var_pixfmt(var))
    /* Fall back to default */
    bpp_to_var(var->bits_per_pixel, var);
    if (var->pixclock < 1000) {
    htotal = var->xres + var->right_margin + var->hsync_len +
    var->left_margin;
    vtotal = var->yres + var->lower_margin + var->vsync_len +
    var->upper_margin;
    var->pixclock = (vtotal * htotal * 6UL) / 100UL;
    var->pixclock = KHZ2PICOS(var->pixclock);
    dev_dbg(info->device,
    "pixclock set for 60Hz refresh = %u psn",
    var->pixclock);
    }
    if (var->height == 0 && mxc_fbi->panel_height_mm)
    var->height = mxc_fbi->panel_height_mm;
    else if (var->height == 0)
    var->height = -1;
    if (var->width == 0 && mxc_fbi->panel_width_mm)
    var->width = mxc_fbi->panel_width_mm;
    else if (var->width == 0)
    var->width = -1;
    var->grayscale = 0;
    return 0;
    }
    



    1
    0
     
     

    我的同类文章

    http://blog.csdn.net
    • [IMX6DL]dd命令刷u-boot.bin到sd卡失败解决方法2016-07-21
    • Linux死锁调试之hardlockup2016-05-05
    • [IMX6DL]Linux dmaengine 使用方法2016-05-03
    • [IMX6DL]超声波模块HC-SR04 Linux驱动源代码2016-04-15
    • [IMX6DL]Linux内核 --- 中断流程小结2016-04-01
    • [IMX6Q][Android5.1]移植笔记 --- kernel移植2016-03-14
    • [IMX6DL]CPU频率调节模式以及降频方法2016-07-04
    • Linux死锁调试之softlockup2016-05-04
    • [IMX6DL]超声波模块KS103 Linux驱动源代码2016-04-25
    • [IMX6DL]do_gettimeofday()的精度分析2016-04-14
    • 如何将dtb反编译成dts2016-03-14
    更多文章

    最后

    以上就是落后眼睛为你收集整理的IMX6 LCD 参数匹配过程分析[IMX6Q]LCD参数匹配过程分析 的全部内容,希望文章能够帮你解决IMX6 LCD 参数匹配过程分析[IMX6Q]LCD参数匹配过程分析 所遇到的程序开发问题。

    如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

    本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
    点赞(59)

    评论列表共有 0 条评论

    立即
    投稿
    返回
    顶部