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

版权声明:本文为博主原创文章,未经博主允许不得转载。
Platform: IMX6Q
OS: Android 4.4
本文只讨论lvds接口的是lcd参数匹配的过程,mipi dsi以及其他接口部分会有一点差异。
核心函数fb_find_mode(),在分析之前先了解下几个参数。
重要参数说明:
1. ldb.c中的 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);

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
39static 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结构
本例是:
- 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,
- },
- };

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
32static 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], 以此类推。
了解了参数意义之后下面就方便理解了.
系统有如下调用:
- 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);
- ......
- }

1
2
3
4
5
6
7
8static 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
下面看代码执行流程:
- /**
- * 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;
- }

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
- 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;
- }

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
29static 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
- 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
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
62static 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
- 上一篇Ubuntu通过串口发送文件给u-boot
- 下一篇Android Kitkat 如何让系统永久不休眠
我的同类文章
- •[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内容请搜索靠谱客的其他文章。
发表评论 取消回复