我是靠谱客的博主 落后眼睛,这篇文章主要介绍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);  
    复制代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    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. };  
    复制代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    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. }  
    复制代码
    1
    2
    3
    4
    5
    6
    7
    8
    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. }   
    复制代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    /**  *    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. }  
    复制代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    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. }  
    复制代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    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内容请搜索靠谱客的其他文章。

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

    评论列表共有 0 条评论

    立即
    投稿
    返回
    顶部