1 /* 2 * linux/drivers/video/modedb.c -- Standard video mode database management 3 * 4 * Copyright (C) 1999 Geert Uytterhoeven 5 * 6 * 2001 - Documented with DocBook 7 * - Brad Douglas <brad@neruo.com> 8 * 9 * This file is subject to the terms and conditions of the GNU General Public 10 * License. See the file COPYING in the main directory of this archive for 11 * more details. 12 */ 13 14 #include <linux/module.h> 15 #include <linux/slab.h> 16 #include <linux/fb.h> 17 #include <linux/kernel.h> 18 19 #undef DEBUG 20 21 #define name_matches(v, s, l) \ 22 ((v).name && !strncmp((s), (v).name, (l)) && strlen((v).name) == (l)) 23 #define res_matches(v, x, y) \ 24 ((v).xres == (x) && (v).yres == (y)) 25 26 #ifdef DEBUG 27 #define DPRINTK(fmt, args...) printk("modedb %s: " fmt, __func__ , ## args) 28 #else 29 #define DPRINTK(fmt, args...) 30 #endif 31 32 /* 33 * Standard video mode definitions (taken from XFree86) 34 */ 35 36 static const struct fb_videomode modedb[] = { 37 38 /* 640x400 @ 70 Hz, 31.5 kHz hsync */ 39 { NULL, 70, 640, 400, 39721, 40, 24, 39, 9, 96, 2, 0, 40 FB_VMODE_NONINTERLACED }, 41 42 /* 640x480 @ 60 Hz, 31.5 kHz hsync */ 43 { NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2, 0, 44 FB_VMODE_NONINTERLACED }, 45 46 /* 800x600 @ 56 Hz, 35.15 kHz hsync */ 47 { NULL, 56, 800, 600, 27777, 128, 24, 22, 1, 72, 2, 0, 48 FB_VMODE_NONINTERLACED }, 49 50 /* 1024x768 @ 87 Hz interlaced, 35.5 kHz hsync */ 51 { NULL, 87, 1024, 768, 22271, 56, 24, 33, 8, 160, 8, 0, 52 FB_VMODE_INTERLACED }, 53 54 /* 640x400 @ 85 Hz, 37.86 kHz hsync */ 55 { NULL, 85, 640, 400, 31746, 96, 32, 41, 1, 64, 3, 56 FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, 57 58 /* 640x480 @ 72 Hz, 36.5 kHz hsync */ 59 { NULL, 72, 640, 480, 31746, 144, 40, 30, 8, 40, 3, 0, 60 FB_VMODE_NONINTERLACED }, 61 62 /* 640x480 @ 75 Hz, 37.50 kHz hsync */ 63 { NULL, 75, 640, 480, 31746, 120, 16, 16, 1, 64, 3, 0, 64 FB_VMODE_NONINTERLACED }, 65 66 /* 800x600 @ 60 Hz, 37.8 kHz hsync */ 67 { NULL, 60, 800, 600, 25000, 88, 40, 23, 1, 128, 4, 68 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 69 FB_VMODE_NONINTERLACED }, 70 71 /* 640x480 @ 85 Hz, 43.27 kHz hsync */ 72 { NULL, 85, 640, 480, 27777, 80, 56, 25, 1, 56, 3, 0, 73 FB_VMODE_NONINTERLACED }, 74 75 /* 1152x864 @ 89 Hz interlaced, 44 kHz hsync */ 76 { NULL, 89, 1152, 864, 15384, 96, 16, 110, 1, 216, 10, 0, 77 FB_VMODE_INTERLACED }, 78 /* 800x600 @ 72 Hz, 48.0 kHz hsync */ 79 { NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6, 80 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 81 FB_VMODE_NONINTERLACED }, 82 83 /* 1024x768 @ 60 Hz, 48.4 kHz hsync */ 84 { NULL, 60, 1024, 768, 15384, 168, 8, 29, 3, 144, 6, 0, 85 FB_VMODE_NONINTERLACED }, 86 87 /* 640x480 @ 100 Hz, 53.01 kHz hsync */ 88 { NULL, 100, 640, 480, 21834, 96, 32, 36, 8, 96, 6, 0, 89 FB_VMODE_NONINTERLACED }, 90 91 /* 1152x864 @ 60 Hz, 53.5 kHz hsync */ 92 { NULL, 60, 1152, 864, 11123, 208, 64, 16, 4, 256, 8, 0, 93 FB_VMODE_NONINTERLACED }, 94 95 /* 800x600 @ 85 Hz, 55.84 kHz hsync */ 96 { NULL, 85, 800, 600, 16460, 160, 64, 36, 16, 64, 5, 0, 97 FB_VMODE_NONINTERLACED }, 98 99 /* 1024x768 @ 70 Hz, 56.5 kHz hsync */ 100 { NULL, 70, 1024, 768, 13333, 144, 24, 29, 3, 136, 6, 0, 101 FB_VMODE_NONINTERLACED }, 102 103 /* 1280x1024 @ 87 Hz interlaced, 51 kHz hsync */ 104 { NULL, 87, 1280, 1024, 12500, 56, 16, 128, 1, 216, 12, 0, 105 FB_VMODE_INTERLACED }, 106 107 /* 800x600 @ 100 Hz, 64.02 kHz hsync */ 108 { NULL, 100, 800, 600, 14357, 160, 64, 30, 4, 64, 6, 0, 109 FB_VMODE_NONINTERLACED }, 110 111 /* 1024x768 @ 76 Hz, 62.5 kHz hsync */ 112 { NULL, 76, 1024, 768, 11764, 208, 8, 36, 16, 120, 3, 0, 113 FB_VMODE_NONINTERLACED }, 114 115 /* 1152x864 @ 70 Hz, 62.4 kHz hsync */ 116 { NULL, 70, 1152, 864, 10869, 106, 56, 20, 1, 160, 10, 0, 117 FB_VMODE_NONINTERLACED }, 118 119 /* 1280x1024 @ 61 Hz, 64.2 kHz hsync */ 120 { NULL, 61, 1280, 1024, 9090, 200, 48, 26, 1, 184, 3, 0, 121 FB_VMODE_NONINTERLACED }, 122 123 /* 1400x1050 @ 60Hz, 63.9 kHz hsync */ 124 { NULL, 60, 1400, 1050, 9259, 136, 40, 13, 1, 112, 3, 0, 125 FB_VMODE_NONINTERLACED }, 126 127 /* 1400x1050 @ 75,107 Hz, 82,392 kHz +hsync +vsync*/ 128 { NULL, 75, 1400, 1050, 7190, 120, 56, 23, 10, 112, 13, 129 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 130 FB_VMODE_NONINTERLACED }, 131 132 /* 1400x1050 @ 60 Hz, ? kHz +hsync +vsync*/ 133 { NULL, 60, 1400, 1050, 9259, 128, 40, 12, 0, 112, 3, 134 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 135 FB_VMODE_NONINTERLACED }, 136 137 /* 1024x768 @ 85 Hz, 70.24 kHz hsync */ 138 { NULL, 85, 1024, 768, 10111, 192, 32, 34, 14, 160, 6, 0, 139 FB_VMODE_NONINTERLACED }, 140 141 /* 1152x864 @ 78 Hz, 70.8 kHz hsync */ 142 { NULL, 78, 1152, 864, 9090, 228, 88, 32, 0, 84, 12, 0, 143 FB_VMODE_NONINTERLACED }, 144 145 /* 1280x1024 @ 70 Hz, 74.59 kHz hsync */ 146 { NULL, 70, 1280, 1024, 7905, 224, 32, 28, 8, 160, 8, 0, 147 FB_VMODE_NONINTERLACED }, 148 149 /* 1600x1200 @ 60Hz, 75.00 kHz hsync */ 150 { NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3, 151 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 152 FB_VMODE_NONINTERLACED }, 153 154 /* 1152x864 @ 84 Hz, 76.0 kHz hsync */ 155 { NULL, 84, 1152, 864, 7407, 184, 312, 32, 0, 128, 12, 0, 156 FB_VMODE_NONINTERLACED }, 157 158 /* 1280x1024 @ 74 Hz, 78.85 kHz hsync */ 159 { NULL, 74, 1280, 1024, 7407, 256, 32, 34, 3, 144, 3, 0, 160 FB_VMODE_NONINTERLACED }, 161 162 /* 1024x768 @ 100Hz, 80.21 kHz hsync */ 163 { NULL, 100, 1024, 768, 8658, 192, 32, 21, 3, 192, 10, 0, 164 FB_VMODE_NONINTERLACED }, 165 166 /* 1280x1024 @ 76 Hz, 81.13 kHz hsync */ 167 { NULL, 76, 1280, 1024, 7407, 248, 32, 34, 3, 104, 3, 0, 168 FB_VMODE_NONINTERLACED }, 169 170 /* 1600x1200 @ 70 Hz, 87.50 kHz hsync */ 171 { NULL, 70, 1600, 1200, 5291, 304, 64, 46, 1, 192, 3, 0, 172 FB_VMODE_NONINTERLACED }, 173 174 /* 1152x864 @ 100 Hz, 89.62 kHz hsync */ 175 { NULL, 100, 1152, 864, 7264, 224, 32, 17, 2, 128, 19, 0, 176 FB_VMODE_NONINTERLACED }, 177 178 /* 1280x1024 @ 85 Hz, 91.15 kHz hsync */ 179 { NULL, 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3, 180 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 181 FB_VMODE_NONINTERLACED }, 182 183 /* 1600x1200 @ 75 Hz, 93.75 kHz hsync */ 184 { NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3, 185 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 186 FB_VMODE_NONINTERLACED }, 187 188 /* 1680x1050 @ 60 Hz, 65.191 kHz hsync */ 189 { NULL, 60, 1680, 1050, 6848, 280, 104, 30, 3, 176, 6, 190 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 191 FB_VMODE_NONINTERLACED }, 192 193 /* 1600x1200 @ 85 Hz, 105.77 kHz hsync */ 194 { NULL, 85, 1600, 1200, 4545, 272, 16, 37, 4, 192, 3, 195 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 196 FB_VMODE_NONINTERLACED }, 197 198 /* 1280x1024 @ 100 Hz, 107.16 kHz hsync */ 199 { NULL, 100, 1280, 1024, 5502, 256, 32, 26, 7, 128, 15, 0, 200 FB_VMODE_NONINTERLACED }, 201 202 /* 1800x1440 @ 64Hz, 96.15 kHz hsync */ 203 { NULL, 64, 1800, 1440, 4347, 304, 96, 46, 1, 192, 3, 204 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 205 FB_VMODE_NONINTERLACED }, 206 207 /* 1800x1440 @ 70Hz, 104.52 kHz hsync */ 208 { NULL, 70, 1800, 1440, 4000, 304, 96, 46, 1, 192, 3, 209 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 210 FB_VMODE_NONINTERLACED }, 211 212 /* 512x384 @ 78 Hz, 31.50 kHz hsync */ 213 { NULL, 78, 512, 384, 49603, 48, 16, 16, 1, 64, 3, 0, 214 FB_VMODE_NONINTERLACED }, 215 216 /* 512x384 @ 85 Hz, 34.38 kHz hsync */ 217 { NULL, 85, 512, 384, 45454, 48, 16, 16, 1, 64, 3, 0, 218 FB_VMODE_NONINTERLACED }, 219 220 /* 320x200 @ 70 Hz, 31.5 kHz hsync, 8:5 aspect ratio */ 221 { NULL, 70, 320, 200, 79440, 16, 16, 20, 4, 48, 1, 0, 222 FB_VMODE_DOUBLE }, 223 224 /* 320x240 @ 60 Hz, 31.5 kHz hsync, 4:3 aspect ratio */ 225 { NULL, 60, 320, 240, 79440, 16, 16, 16, 5, 48, 1, 0, 226 FB_VMODE_DOUBLE }, 227 228 /* 320x240 @ 72 Hz, 36.5 kHz hsync */ 229 { NULL, 72, 320, 240, 63492, 16, 16, 16, 4, 48, 2, 0, 230 FB_VMODE_DOUBLE }, 231 232 /* 400x300 @ 56 Hz, 35.2 kHz hsync, 4:3 aspect ratio */ 233 { NULL, 56, 400, 300, 55555, 64, 16, 10, 1, 32, 1, 0, 234 FB_VMODE_DOUBLE }, 235 236 /* 400x300 @ 60 Hz, 37.8 kHz hsync */ 237 { NULL, 60, 400, 300, 50000, 48, 16, 11, 1, 64, 2, 0, 238 FB_VMODE_DOUBLE }, 239 240 /* 400x300 @ 72 Hz, 48.0 kHz hsync */ 241 { NULL, 72, 400, 300, 40000, 32, 24, 11, 19, 64, 3, 0, 242 FB_VMODE_DOUBLE }, 243 244 /* 480x300 @ 56 Hz, 35.2 kHz hsync, 8:5 aspect ratio */ 245 { NULL, 56, 480, 300, 46176, 80, 16, 10, 1, 40, 1, 0, 246 FB_VMODE_DOUBLE }, 247 248 /* 480x300 @ 60 Hz, 37.8 kHz hsync */ 249 { NULL, 60, 480, 300, 41858, 56, 16, 11, 1, 80, 2, 0, 250 FB_VMODE_DOUBLE }, 251 252 /* 480x300 @ 63 Hz, 39.6 kHz hsync */ 253 { NULL, 63, 480, 300, 40000, 56, 16, 11, 1, 80, 2, 0, 254 FB_VMODE_DOUBLE }, 255 256 /* 480x300 @ 72 Hz, 48.0 kHz hsync */ 257 { NULL, 72, 480, 300, 33386, 40, 24, 11, 19, 80, 3, 0, 258 FB_VMODE_DOUBLE }, 259 260 /* 1920x1200 @ 60 Hz, 74.5 Khz hsync */ 261 { NULL, 60, 1920, 1200, 5177, 128, 336, 1, 38, 208, 3, 262 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 263 FB_VMODE_NONINTERLACED }, 264 265 /* 1152x768, 60 Hz, PowerBook G4 Titanium I and II */ 266 { NULL, 60, 1152, 768, 14047, 158, 26, 29, 3, 136, 6, 267 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 268 FB_VMODE_NONINTERLACED }, 269 270 /* 1366x768, 60 Hz, 47.403 kHz hsync, WXGA 16:9 aspect ratio */ 271 { NULL, 60, 1366, 768, 13806, 120, 10, 14, 3, 32, 5, 0, 272 FB_VMODE_NONINTERLACED }, 273 274 /* 1280x800, 60 Hz, 47.403 kHz hsync, WXGA 16:10 aspect ratio */ 275 { NULL, 60, 1280, 800, 12048, 200, 64, 24, 1, 136, 3, 0, 276 FB_VMODE_NONINTERLACED }, 277 278 /* 720x576i @ 50 Hz, 15.625 kHz hsync (PAL RGB) */ 279 { NULL, 50, 720, 576, 74074, 64, 16, 39, 5, 64, 5, 0, 280 FB_VMODE_INTERLACED }, 281 282 /* 800x520i @ 50 Hz, 15.625 kHz hsync (PAL RGB) */ 283 { NULL, 50, 800, 520, 58823, 144, 64, 72, 28, 80, 5, 0, 284 FB_VMODE_INTERLACED }, 285 286 /* 864x480 @ 60 Hz, 35.15 kHz hsync */ 287 { NULL, 60, 864, 480, 27777, 1, 1, 1, 1, 0, 0, 288 0, FB_VMODE_NONINTERLACED }, 289 }; 290 291 #ifdef CONFIG_FB_MODE_HELPERS 292 const struct fb_videomode cea_modes[65] = { 293 /* #1: 640x480p@59.94/60Hz */ 294 [1] = { 295 NULL, 60, 640, 480, 39722, 48, 16, 33, 10, 96, 2, 0, 296 FB_VMODE_NONINTERLACED, 0, 297 }, 298 /* #3: 720x480p@59.94/60Hz */ 299 [3] = { 300 NULL, 60, 720, 480, 37037, 60, 16, 30, 9, 62, 6, 0, 301 FB_VMODE_NONINTERLACED, 0, 302 }, 303 /* #5: 1920x1080i@59.94/60Hz */ 304 [5] = { 305 NULL, 60, 1920, 1080, 13763, 148, 88, 15, 2, 44, 5, 306 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 307 FB_VMODE_INTERLACED, 0, 308 }, 309 /* #7: 720(1440)x480iH@59.94/60Hz */ 310 [7] = { 311 NULL, 60, 1440, 480, 18554/*37108*/, 114, 38, 15, 4, 124, 3, 0, 312 FB_VMODE_INTERLACED, 0, 313 }, 314 /* #9: 720(1440)x240pH@59.94/60Hz */ 315 [9] = { 316 NULL, 60, 1440, 240, 18554, 114, 38, 16, 4, 124, 3, 0, 317 FB_VMODE_NONINTERLACED, 0, 318 }, 319 /* #18: 720x576pH@50Hz */ 320 [18] = { 321 NULL, 50, 720, 576, 37037, 68, 12, 39, 5, 64, 5, 0, 322 FB_VMODE_NONINTERLACED, 0, 323 }, 324 /* #19: 1280x720p@50Hz */ 325 [19] = { 326 NULL, 50, 1280, 720, 13468, 220, 440, 20, 5, 40, 5, 327 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 328 FB_VMODE_NONINTERLACED, 0, 329 }, 330 /* #20: 1920x1080i@50Hz */ 331 [20] = { 332 NULL, 50, 1920, 1080, 13480, 148, 528, 15, 5, 528, 5, 333 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 334 FB_VMODE_INTERLACED, 0, 335 }, 336 /* #32: 1920x1080p@23.98/24Hz */ 337 [32] = { 338 NULL, 24, 1920, 1080, 13468, 148, 638, 36, 4, 44, 5, 339 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 340 FB_VMODE_NONINTERLACED, 0, 341 }, 342 /* #35: (2880)x480p4x@59.94/60Hz */ 343 [35] = { 344 NULL, 60, 2880, 480, 9250, 240, 64, 30, 9, 248, 6, 0, 345 FB_VMODE_NONINTERLACED, 0, 346 }, 347 }; 348 349 const struct fb_videomode vesa_modes[] = { 350 /* 0 640x350-85 VESA */ 351 { NULL, 85, 640, 350, 31746, 96, 32, 60, 32, 64, 3, 352 FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA}, 353 /* 1 640x400-85 VESA */ 354 { NULL, 85, 640, 400, 31746, 96, 32, 41, 01, 64, 3, 355 FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 356 /* 2 720x400-85 VESA */ 357 { NULL, 85, 721, 400, 28169, 108, 36, 42, 01, 72, 3, 358 FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 359 /* 3 640x480-60 VESA */ 360 { NULL, 60, 640, 480, 39682, 48, 16, 33, 10, 96, 2, 361 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 362 /* 4 640x480-72 VESA */ 363 { NULL, 72, 640, 480, 31746, 128, 24, 29, 9, 40, 2, 364 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 365 /* 5 640x480-75 VESA */ 366 { NULL, 75, 640, 480, 31746, 120, 16, 16, 01, 64, 3, 367 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 368 /* 6 640x480-85 VESA */ 369 { NULL, 85, 640, 480, 27777, 80, 56, 25, 01, 56, 3, 370 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 371 /* 7 800x600-56 VESA */ 372 { NULL, 56, 800, 600, 27777, 128, 24, 22, 01, 72, 2, 373 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 374 FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 375 /* 8 800x600-60 VESA */ 376 { NULL, 60, 800, 600, 25000, 88, 40, 23, 01, 128, 4, 377 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 378 FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 379 /* 9 800x600-72 VESA */ 380 { NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6, 381 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 382 FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 383 /* 10 800x600-75 VESA */ 384 { NULL, 75, 800, 600, 20202, 160, 16, 21, 01, 80, 3, 385 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 386 FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 387 /* 11 800x600-85 VESA */ 388 { NULL, 85, 800, 600, 17761, 152, 32, 27, 01, 64, 3, 389 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 390 FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 391 /* 12 1024x768i-43 VESA */ 392 { NULL, 43, 1024, 768, 22271, 56, 8, 41, 0, 176, 8, 393 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 394 FB_VMODE_INTERLACED, FB_MODE_IS_VESA }, 395 /* 13 1024x768-60 VESA */ 396 { NULL, 60, 1024, 768, 15384, 160, 24, 29, 3, 136, 6, 397 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 398 /* 14 1024x768-70 VESA */ 399 { NULL, 70, 1024, 768, 13333, 144, 24, 29, 3, 136, 6, 400 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 401 /* 15 1024x768-75 VESA */ 402 { NULL, 75, 1024, 768, 12690, 176, 16, 28, 1, 96, 3, 403 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 404 FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 405 /* 16 1024x768-85 VESA */ 406 { NULL, 85, 1024, 768, 10582, 208, 48, 36, 1, 96, 3, 407 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 408 FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 409 /* 17 1152x864-75 VESA */ 410 { NULL, 75, 1152, 864, 9259, 256, 64, 32, 1, 128, 3, 411 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 412 FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 413 /* 18 1280x960-60 VESA */ 414 { NULL, 60, 1280, 960, 9259, 312, 96, 36, 1, 112, 3, 415 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 416 FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 417 /* 19 1280x960-85 VESA */ 418 { NULL, 85, 1280, 960, 6734, 224, 64, 47, 1, 160, 3, 419 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 420 FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 421 /* 20 1280x1024-60 VESA */ 422 { NULL, 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3, 423 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 424 FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 425 /* 21 1280x1024-75 VESA */ 426 { NULL, 75, 1280, 1024, 7407, 248, 16, 38, 1, 144, 3, 427 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 428 FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 429 /* 22 1280x1024-85 VESA */ 430 { NULL, 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3, 431 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 432 FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 433 /* 23 1600x1200-60 VESA */ 434 { NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3, 435 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 436 FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 437 /* 24 1600x1200-65 VESA */ 438 { NULL, 65, 1600, 1200, 5698, 304, 64, 46, 1, 192, 3, 439 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 440 FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 441 /* 25 1600x1200-70 VESA */ 442 { NULL, 70, 1600, 1200, 5291, 304, 64, 46, 1, 192, 3, 443 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 444 FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 445 /* 26 1600x1200-75 VESA */ 446 { NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3, 447 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 448 FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 449 /* 27 1600x1200-85 VESA */ 450 { NULL, 85, 1600, 1200, 4357, 304, 64, 46, 1, 192, 3, 451 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 452 FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 453 /* 28 1792x1344-60 VESA */ 454 { NULL, 60, 1792, 1344, 4882, 328, 128, 46, 1, 200, 3, 455 FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 456 /* 29 1792x1344-75 VESA */ 457 { NULL, 75, 1792, 1344, 3831, 352, 96, 69, 1, 216, 3, 458 FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 459 /* 30 1856x1392-60 VESA */ 460 { NULL, 60, 1856, 1392, 4580, 352, 96, 43, 1, 224, 3, 461 FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 462 /* 31 1856x1392-75 VESA */ 463 { NULL, 75, 1856, 1392, 3472, 352, 128, 104, 1, 224, 3, 464 FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 465 /* 32 1920x1440-60 VESA */ 466 { NULL, 60, 1920, 1440, 4273, 344, 128, 56, 1, 200, 3, 467 FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 468 /* 33 1920x1440-75 VESA */ 469 { NULL, 75, 1920, 1440, 3367, 352, 144, 56, 1, 224, 3, 470 FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 471 /* 34 1920x1200-60 RB VESA */ 472 { NULL, 60, 1920, 1200, 6493, 80, 48, 26, 3, 32, 6, 473 FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 474 /* 35 1920x1200-60 VESA */ 475 { NULL, 60, 1920, 1200, 5174, 336, 136, 36, 3, 200, 6, 476 FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 477 /* 36 1920x1200-75 VESA */ 478 { NULL, 75, 1920, 1200, 4077, 344, 136, 46, 3, 208, 6, 479 FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 480 /* 37 1920x1200-85 VESA */ 481 { NULL, 85, 1920, 1200, 3555, 352, 144, 53, 3, 208, 6, 482 FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 483 /* 38 2560x1600-60 RB VESA */ 484 { NULL, 60, 2560, 1600, 3724, 80, 48, 37, 3, 32, 6, 485 FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 486 /* 39 2560x1600-60 VESA */ 487 { NULL, 60, 2560, 1600, 2869, 472, 192, 49, 3, 280, 6, 488 FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 489 /* 40 2560x1600-75 VESA */ 490 { NULL, 75, 2560, 1600, 2256, 488, 208, 63, 3, 280, 6, 491 FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 492 /* 41 2560x1600-85 VESA */ 493 { NULL, 85, 2560, 1600, 1979, 488, 208, 73, 3, 280, 6, 494 FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 495 /* 42 2560x1600-120 RB VESA */ 496 { NULL, 120, 2560, 1600, 1809, 80, 48, 85, 3, 32, 6, 497 FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 498 }; 499 EXPORT_SYMBOL(vesa_modes); 500 501 const struct dmt_videomode dmt_modes[DMT_SIZE] = { 502 { 0x01, 0x0000, 0x000000, &vesa_modes[0] }, 503 { 0x02, 0x3119, 0x000000, &vesa_modes[1] }, 504 { 0x03, 0x0000, 0x000000, &vesa_modes[2] }, 505 { 0x04, 0x3140, 0x000000, &vesa_modes[3] }, 506 { 0x05, 0x314c, 0x000000, &vesa_modes[4] }, 507 { 0x06, 0x314f, 0x000000, &vesa_modes[5] }, 508 { 0x07, 0x3159, 0x000000, &vesa_modes[6] }, 509 { 0x08, 0x0000, 0x000000, &vesa_modes[7] }, 510 { 0x09, 0x4540, 0x000000, &vesa_modes[8] }, 511 { 0x0a, 0x454c, 0x000000, &vesa_modes[9] }, 512 { 0x0b, 0x454f, 0x000000, &vesa_modes[10] }, 513 { 0x0c, 0x4559, 0x000000, &vesa_modes[11] }, 514 { 0x0d, 0x0000, 0x000000, NULL }, 515 { 0x0e, 0x0000, 0x000000, NULL }, 516 { 0x0f, 0x0000, 0x000000, &vesa_modes[12] }, 517 { 0x10, 0x6140, 0x000000, &vesa_modes[13] }, 518 { 0x11, 0x614a, 0x000000, &vesa_modes[14] }, 519 { 0x12, 0x614f, 0x000000, &vesa_modes[15] }, 520 { 0x13, 0x6159, 0x000000, &vesa_modes[16] }, 521 { 0x14, 0x0000, 0x000000, NULL }, 522 { 0x15, 0x714f, 0x000000, &vesa_modes[17] }, 523 { 0x16, 0x0000, 0x7f1c21, NULL }, 524 { 0x17, 0x0000, 0x7f1c28, NULL }, 525 { 0x18, 0x0000, 0x7f1c44, NULL }, 526 { 0x19, 0x0000, 0x7f1c62, NULL }, 527 { 0x1a, 0x0000, 0x000000, NULL }, 528 { 0x1b, 0x0000, 0x8f1821, NULL }, 529 { 0x1c, 0x8100, 0x8f1828, NULL }, 530 { 0x1d, 0x810f, 0x8f1844, NULL }, 531 { 0x1e, 0x8119, 0x8f1862, NULL }, 532 { 0x1f, 0x0000, 0x000000, NULL }, 533 { 0x20, 0x8140, 0x000000, &vesa_modes[18] }, 534 { 0x21, 0x8159, 0x000000, &vesa_modes[19] }, 535 { 0x22, 0x0000, 0x000000, NULL }, 536 { 0x23, 0x8180, 0x000000, &vesa_modes[20] }, 537 { 0x24, 0x818f, 0x000000, &vesa_modes[21] }, 538 { 0x25, 0x8199, 0x000000, &vesa_modes[22] }, 539 { 0x26, 0x0000, 0x000000, NULL }, 540 { 0x27, 0x0000, 0x000000, NULL }, 541 { 0x28, 0x0000, 0x000000, NULL }, 542 { 0x29, 0x0000, 0x0c2021, NULL }, 543 { 0x2a, 0x9040, 0x0c2028, NULL }, 544 { 0x2b, 0x904f, 0x0c2044, NULL }, 545 { 0x2c, 0x9059, 0x0c2062, NULL }, 546 { 0x2d, 0x0000, 0x000000, NULL }, 547 { 0x2e, 0x9500, 0xc11821, NULL }, 548 { 0x2f, 0x9500, 0xc11828, NULL }, 549 { 0x30, 0x950f, 0xc11844, NULL }, 550 { 0x31, 0x9519, 0xc11868, NULL }, 551 { 0x32, 0x0000, 0x000000, NULL }, 552 { 0x33, 0xa940, 0x000000, &vesa_modes[23] }, 553 { 0x34, 0xa945, 0x000000, &vesa_modes[24] }, 554 { 0x35, 0xa94a, 0x000000, &vesa_modes[25] }, 555 { 0x36, 0xa94f, 0x000000, &vesa_modes[26] }, 556 { 0x37, 0xa959, 0x000000, &vesa_modes[27] }, 557 { 0x38, 0x0000, 0x000000, NULL }, 558 { 0x39, 0x0000, 0x0c2821, NULL }, 559 { 0x3a, 0xb300, 0x0c2828, NULL }, 560 { 0x3b, 0xb30f, 0x0c2844, NULL }, 561 { 0x3c, 0xb319, 0x0c2868, NULL }, 562 { 0x3d, 0x0000, 0x000000, NULL }, 563 { 0x3e, 0xc140, 0x000000, &vesa_modes[28] }, 564 { 0x3f, 0xc14f, 0x000000, &vesa_modes[29] }, 565 { 0x40, 0x0000, 0x000000, NULL}, 566 { 0x41, 0xc940, 0x000000, &vesa_modes[30] }, 567 { 0x42, 0xc94f, 0x000000, &vesa_modes[31] }, 568 { 0x43, 0x0000, 0x000000, NULL }, 569 { 0x44, 0x0000, 0x572821, &vesa_modes[34] }, 570 { 0x45, 0xd100, 0x572828, &vesa_modes[35] }, 571 { 0x46, 0xd10f, 0x572844, &vesa_modes[36] }, 572 { 0x47, 0xd119, 0x572862, &vesa_modes[37] }, 573 { 0x48, 0x0000, 0x000000, NULL }, 574 { 0x49, 0xd140, 0x000000, &vesa_modes[32] }, 575 { 0x4a, 0xd14f, 0x000000, &vesa_modes[33] }, 576 { 0x4b, 0x0000, 0x000000, NULL }, 577 { 0x4c, 0x0000, 0x1f3821, &vesa_modes[38] }, 578 { 0x4d, 0x0000, 0x1f3828, &vesa_modes[39] }, 579 { 0x4e, 0x0000, 0x1f3844, &vesa_modes[40] }, 580 { 0x4f, 0x0000, 0x1f3862, &vesa_modes[41] }, 581 { 0x50, 0x0000, 0x000000, &vesa_modes[42] }, 582 }; 583 EXPORT_SYMBOL(dmt_modes); 584 #endif /* CONFIG_FB_MODE_HELPERS */ 585 586 /** 587 * fb_try_mode - test a video mode 588 * @var: frame buffer user defined part of display 589 * @info: frame buffer info structure 590 * @mode: frame buffer video mode structure 591 * @bpp: color depth in bits per pixel 592 * 593 * Tries a video mode to test it's validity for device @info. 594 * 595 * Returns 1 on success. 596 * 597 */ 598 599 static int fb_try_mode(struct fb_var_screeninfo *var, struct fb_info *info, 600 const struct fb_videomode *mode, unsigned int bpp) 601 { 602 int err = 0; 603 604 DPRINTK("Trying mode %s %dx%d-%d@%d\n", 605 mode->name ? mode->name : "noname", 606 mode->xres, mode->yres, bpp, mode->refresh); 607 var->xres = mode->xres; 608 var->yres = mode->yres; 609 var->xres_virtual = mode->xres; 610 var->yres_virtual = mode->yres; 611 var->xoffset = 0; 612 var->yoffset = 0; 613 var->bits_per_pixel = bpp; 614 var->activate |= FB_ACTIVATE_TEST; 615 var->pixclock = mode->pixclock; 616 var->left_margin = mode->left_margin; 617 var->right_margin = mode->right_margin; 618 var->upper_margin = mode->upper_margin; 619 var->lower_margin = mode->lower_margin; 620 var->hsync_len = mode->hsync_len; 621 var->vsync_len = mode->vsync_len; 622 var->sync = mode->sync; 623 var->vmode = mode->vmode; 624 if (info->fbops->fb_check_var) 625 err = info->fbops->fb_check_var(var, info); 626 var->activate &= ~FB_ACTIVATE_TEST; 627 return err; 628 } 629 630 /** 631 * fb_find_mode - finds a valid video mode 632 * @var: frame buffer user defined part of display 633 * @info: frame buffer info structure 634 * @mode_option: string video mode to find 635 * @db: video mode database 636 * @dbsize: size of @db 637 * @default_mode: default video mode to fall back to 638 * @default_bpp: default color depth in bits per pixel 639 * 640 * Finds a suitable video mode, starting with the specified mode 641 * in @mode_option with fallback to @default_mode. If 642 * @default_mode fails, all modes in the video mode database will 643 * be tried. 644 * 645 * Valid mode specifiers for @mode_option:: 646 * 647 * <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][p][m] 648 * 649 * or :: 650 * 651 * <name>[-<bpp>][@<refresh>] 652 * 653 * with <xres>, <yres>, <bpp> and <refresh> decimal numbers and 654 * <name> a string. 655 * 656 * If 'M' is present after yres (and before refresh/bpp if present), 657 * the function will compute the timings using VESA(tm) Coordinated 658 * Video Timings (CVT). If 'R' is present after 'M', will compute with 659 * reduced blanking (for flatpanels). If 'i' or 'p' are present, compute 660 * interlaced or progressive mode. If 'm' is present, add margins equal 661 * to 1.8% of xres rounded down to 8 pixels, and 1.8% of yres. The char 662 * 'i', 'p' and 'm' must be after 'M' and 'R'. Example:: 663 * 664 * 1024x768MR-8@60m - Reduced blank with margins at 60Hz. 665 * 666 * NOTE: The passed struct @var is _not_ cleared! This allows you 667 * to supply values for e.g. the grayscale and accel_flags fields. 668 * 669 * Returns zero for failure, 1 if using specified @mode_option, 670 * 2 if using specified @mode_option with an ignored refresh rate, 671 * 3 if default mode is used, 4 if fall back to any valid mode. 672 */ 673 674 int fb_find_mode(struct fb_var_screeninfo *var, 675 struct fb_info *info, const char *mode_option, 676 const struct fb_videomode *db, unsigned int dbsize, 677 const struct fb_videomode *default_mode, 678 unsigned int default_bpp) 679 { 680 int i; 681 682 /* Set up defaults */ 683 if (!db) { 684 db = modedb; 685 dbsize = ARRAY_SIZE(modedb); 686 } 687 688 if (!default_mode) 689 default_mode = &db[0]; 690 691 if (!default_bpp) 692 default_bpp = 8; 693 694 /* Did the user specify a video mode? */ 695 if (!mode_option) 696 mode_option = fb_mode_option; 697 if (mode_option) { 698 const char *name = mode_option; 699 unsigned int namelen = strlen(name); 700 int res_specified = 0, bpp_specified = 0, refresh_specified = 0; 701 unsigned int xres = 0, yres = 0, bpp = default_bpp, refresh = 0; 702 int yres_specified = 0, cvt = 0, rb = 0; 703 int interlace_specified = 0, interlace = 0; 704 int margins = 0; 705 u32 best, diff, tdiff; 706 707 for (i = namelen-1; i >= 0; i--) { 708 switch (name[i]) { 709 case '@': 710 namelen = i; 711 if (!refresh_specified && !bpp_specified && 712 !yres_specified) { 713 refresh = simple_strtol(&name[i+1], NULL, 714 10); 715 refresh_specified = 1; 716 if (cvt || rb) 717 cvt = 0; 718 } else 719 goto done; 720 break; 721 case '-': 722 namelen = i; 723 if (!bpp_specified && !yres_specified) { 724 bpp = simple_strtol(&name[i+1], NULL, 725 10); 726 bpp_specified = 1; 727 if (cvt || rb) 728 cvt = 0; 729 } else 730 goto done; 731 break; 732 case 'x': 733 if (!yres_specified) { 734 yres = simple_strtol(&name[i+1], NULL, 735 10); 736 yres_specified = 1; 737 } else 738 goto done; 739 break; 740 case '0' ... '9': 741 break; 742 case 'M': 743 if (!yres_specified) 744 cvt = 1; 745 break; 746 case 'R': 747 if (!cvt) 748 rb = 1; 749 break; 750 case 'm': 751 if (!cvt) 752 margins = 1; 753 break; 754 case 'p': 755 if (!cvt) { 756 interlace = 0; 757 interlace_specified = 1; 758 } 759 break; 760 case 'i': 761 if (!cvt) { 762 interlace = 1; 763 interlace_specified = 1; 764 } 765 break; 766 default: 767 goto done; 768 } 769 } 770 if (i < 0 && yres_specified) { 771 xres = simple_strtol(name, NULL, 10); 772 res_specified = 1; 773 } 774 done: 775 if (cvt) { 776 struct fb_videomode cvt_mode; 777 int ret; 778 779 DPRINTK("CVT mode %dx%d@%dHz%s%s%s\n", xres, yres, 780 (refresh) ? refresh : 60, 781 (rb) ? " reduced blanking" : "", 782 (margins) ? " with margins" : "", 783 (interlace) ? " interlaced" : ""); 784 785 memset(&cvt_mode, 0, sizeof(cvt_mode)); 786 cvt_mode.xres = xres; 787 cvt_mode.yres = yres; 788 cvt_mode.refresh = (refresh) ? refresh : 60; 789 790 if (interlace) 791 cvt_mode.vmode |= FB_VMODE_INTERLACED; 792 else 793 cvt_mode.vmode &= ~FB_VMODE_INTERLACED; 794 795 ret = fb_find_mode_cvt(&cvt_mode, margins, rb); 796 797 if (!ret && !fb_try_mode(var, info, &cvt_mode, bpp)) { 798 DPRINTK("modedb CVT: CVT mode ok\n"); 799 return 1; 800 } 801 802 DPRINTK("CVT mode invalid, getting mode from database\n"); 803 } 804 805 DPRINTK("Trying specified video mode%s %ix%i\n", 806 refresh_specified ? "" : " (ignoring refresh rate)", 807 xres, yres); 808 809 if (!refresh_specified) { 810 /* 811 * If the caller has provided a custom mode database and 812 * a valid monspecs structure, we look for the mode with 813 * the highest refresh rate. Otherwise we play it safe 814 * it and try to find a mode with a refresh rate closest 815 * to the standard 60 Hz. 816 */ 817 if (db != modedb && 818 info->monspecs.vfmin && info->monspecs.vfmax && 819 info->monspecs.hfmin && info->monspecs.hfmax && 820 info->monspecs.dclkmax) { 821 refresh = 1000; 822 } else { 823 refresh = 60; 824 } 825 } 826 827 diff = -1; 828 best = -1; 829 for (i = 0; i < dbsize; i++) { 830 if ((name_matches(db[i], name, namelen) || 831 (res_specified && res_matches(db[i], xres, yres))) && 832 !fb_try_mode(var, info, &db[i], bpp)) { 833 const int db_interlace = (db[i].vmode & 834 FB_VMODE_INTERLACED ? 1 : 0); 835 int score = abs(db[i].refresh - refresh); 836 837 if (interlace_specified) 838 score += abs(db_interlace - interlace); 839 840 if (!interlace_specified || 841 db_interlace == interlace) 842 if (refresh_specified && 843 db[i].refresh == refresh) 844 return 1; 845 846 if (score < diff) { 847 diff = score; 848 best = i; 849 } 850 } 851 } 852 if (best != -1) { 853 fb_try_mode(var, info, &db[best], bpp); 854 return (refresh_specified) ? 2 : 1; 855 } 856 857 diff = 2 * (xres + yres); 858 best = -1; 859 DPRINTK("Trying best-fit modes\n"); 860 for (i = 0; i < dbsize; i++) { 861 DPRINTK("Trying %ix%i\n", db[i].xres, db[i].yres); 862 if (!fb_try_mode(var, info, &db[i], bpp)) { 863 tdiff = abs(db[i].xres - xres) + 864 abs(db[i].yres - yres); 865 866 /* 867 * Penalize modes with resolutions smaller 868 * than requested. 869 */ 870 if (xres > db[i].xres || yres > db[i].yres) 871 tdiff += xres + yres; 872 873 if (diff > tdiff) { 874 diff = tdiff; 875 best = i; 876 } 877 } 878 } 879 if (best != -1) { 880 fb_try_mode(var, info, &db[best], bpp); 881 return 5; 882 } 883 } 884 885 DPRINTK("Trying default video mode\n"); 886 if (!fb_try_mode(var, info, default_mode, default_bpp)) 887 return 3; 888 889 DPRINTK("Trying all modes\n"); 890 for (i = 0; i < dbsize; i++) 891 if (!fb_try_mode(var, info, &db[i], default_bpp)) 892 return 4; 893 894 DPRINTK("No valid mode found\n"); 895 return 0; 896 } 897 898 /** 899 * fb_var_to_videomode - convert fb_var_screeninfo to fb_videomode 900 * @mode: pointer to struct fb_videomode 901 * @var: pointer to struct fb_var_screeninfo 902 */ 903 void fb_var_to_videomode(struct fb_videomode *mode, 904 const struct fb_var_screeninfo *var) 905 { 906 u32 pixclock, hfreq, htotal, vtotal; 907 908 mode->name = NULL; 909 mode->xres = var->xres; 910 mode->yres = var->yres; 911 mode->pixclock = var->pixclock; 912 mode->hsync_len = var->hsync_len; 913 mode->vsync_len = var->vsync_len; 914 mode->left_margin = var->left_margin; 915 mode->right_margin = var->right_margin; 916 mode->upper_margin = var->upper_margin; 917 mode->lower_margin = var->lower_margin; 918 mode->sync = var->sync; 919 mode->vmode = var->vmode & FB_VMODE_MASK; 920 mode->flag = FB_MODE_IS_FROM_VAR; 921 mode->refresh = 0; 922 923 if (!var->pixclock) 924 return; 925 926 pixclock = PICOS2KHZ(var->pixclock) * 1000; 927 928 htotal = var->xres + var->right_margin + var->hsync_len + 929 var->left_margin; 930 vtotal = var->yres + var->lower_margin + var->vsync_len + 931 var->upper_margin; 932 933 if (var->vmode & FB_VMODE_INTERLACED) 934 vtotal /= 2; 935 if (var->vmode & FB_VMODE_DOUBLE) 936 vtotal *= 2; 937 938 hfreq = pixclock/htotal; 939 mode->refresh = hfreq/vtotal; 940 } 941 942 /** 943 * fb_videomode_to_var - convert fb_videomode to fb_var_screeninfo 944 * @var: pointer to struct fb_var_screeninfo 945 * @mode: pointer to struct fb_videomode 946 */ 947 void fb_videomode_to_var(struct fb_var_screeninfo *var, 948 const struct fb_videomode *mode) 949 { 950 var->xres = mode->xres; 951 var->yres = mode->yres; 952 var->xres_virtual = mode->xres; 953 var->yres_virtual = mode->yres; 954 var->xoffset = 0; 955 var->yoffset = 0; 956 var->pixclock = mode->pixclock; 957 var->left_margin = mode->left_margin; 958 var->right_margin = mode->right_margin; 959 var->upper_margin = mode->upper_margin; 960 var->lower_margin = mode->lower_margin; 961 var->hsync_len = mode->hsync_len; 962 var->vsync_len = mode->vsync_len; 963 var->sync = mode->sync; 964 var->vmode = mode->vmode & FB_VMODE_MASK; 965 } 966 967 /** 968 * fb_mode_is_equal - compare 2 videomodes 969 * @mode1: first videomode 970 * @mode2: second videomode 971 * 972 * RETURNS: 973 * 1 if equal, 0 if not 974 */ 975 int fb_mode_is_equal(const struct fb_videomode *mode1, 976 const struct fb_videomode *mode2) 977 { 978 return (mode1->xres == mode2->xres && 979 mode1->yres == mode2->yres && 980 mode1->pixclock == mode2->pixclock && 981 mode1->hsync_len == mode2->hsync_len && 982 mode1->vsync_len == mode2->vsync_len && 983 mode1->left_margin == mode2->left_margin && 984 mode1->right_margin == mode2->right_margin && 985 mode1->upper_margin == mode2->upper_margin && 986 mode1->lower_margin == mode2->lower_margin && 987 mode1->sync == mode2->sync && 988 mode1->vmode == mode2->vmode); 989 } 990 991 /** 992 * fb_find_best_mode - find best matching videomode 993 * @var: pointer to struct fb_var_screeninfo 994 * @head: pointer to struct list_head of modelist 995 * 996 * RETURNS: 997 * struct fb_videomode, NULL if none found 998 * 999 * IMPORTANT: 1000 * This function assumes that all modelist entries in 1001 * info->modelist are valid. 1002 * 1003 * NOTES: 1004 * Finds best matching videomode which has an equal or greater dimension than 1005 * var->xres and var->yres. If more than 1 videomode is found, will return 1006 * the videomode with the highest refresh rate 1007 */ 1008 const struct fb_videomode *fb_find_best_mode(const struct fb_var_screeninfo *var, 1009 struct list_head *head) 1010 { 1011 struct list_head *pos; 1012 struct fb_modelist *modelist; 1013 struct fb_videomode *mode, *best = NULL; 1014 u32 diff = -1; 1015 1016 list_for_each(pos, head) { 1017 u32 d; 1018 1019 modelist = list_entry(pos, struct fb_modelist, list); 1020 mode = &modelist->mode; 1021 1022 if (mode->xres >= var->xres && mode->yres >= var->yres) { 1023 d = (mode->xres - var->xres) + 1024 (mode->yres - var->yres); 1025 if (diff > d) { 1026 diff = d; 1027 best = mode; 1028 } else if (diff == d && best && 1029 mode->refresh > best->refresh) 1030 best = mode; 1031 } 1032 } 1033 return best; 1034 } 1035 1036 /** 1037 * fb_find_nearest_mode - find closest videomode 1038 * 1039 * @mode: pointer to struct fb_videomode 1040 * @head: pointer to modelist 1041 * 1042 * Finds best matching videomode, smaller or greater in dimension. 1043 * If more than 1 videomode is found, will return the videomode with 1044 * the closest refresh rate. 1045 */ 1046 const struct fb_videomode *fb_find_nearest_mode(const struct fb_videomode *mode, 1047 struct list_head *head) 1048 { 1049 struct list_head *pos; 1050 struct fb_modelist *modelist; 1051 struct fb_videomode *cmode, *best = NULL; 1052 u32 diff = -1, diff_refresh = -1; 1053 1054 list_for_each(pos, head) { 1055 u32 d; 1056 1057 modelist = list_entry(pos, struct fb_modelist, list); 1058 cmode = &modelist->mode; 1059 1060 d = abs(cmode->xres - mode->xres) + 1061 abs(cmode->yres - mode->yres); 1062 if (diff > d) { 1063 diff = d; 1064 diff_refresh = abs(cmode->refresh - mode->refresh); 1065 best = cmode; 1066 } else if (diff == d) { 1067 d = abs(cmode->refresh - mode->refresh); 1068 if (diff_refresh > d) { 1069 diff_refresh = d; 1070 best = cmode; 1071 } 1072 } 1073 } 1074 1075 return best; 1076 } 1077 1078 /** 1079 * fb_match_mode - find a videomode which exactly matches the timings in var 1080 * @var: pointer to struct fb_var_screeninfo 1081 * @head: pointer to struct list_head of modelist 1082 * 1083 * RETURNS: 1084 * struct fb_videomode, NULL if none found 1085 */ 1086 const struct fb_videomode *fb_match_mode(const struct fb_var_screeninfo *var, 1087 struct list_head *head) 1088 { 1089 struct list_head *pos; 1090 struct fb_modelist *modelist; 1091 struct fb_videomode *m, mode; 1092 1093 fb_var_to_videomode(&mode, var); 1094 list_for_each(pos, head) { 1095 modelist = list_entry(pos, struct fb_modelist, list); 1096 m = &modelist->mode; 1097 if (fb_mode_is_equal(m, &mode)) 1098 return m; 1099 } 1100 return NULL; 1101 } 1102 1103 /** 1104 * fb_add_videomode - adds videomode entry to modelist 1105 * @mode: videomode to add 1106 * @head: struct list_head of modelist 1107 * 1108 * NOTES: 1109 * Will only add unmatched mode entries 1110 */ 1111 int fb_add_videomode(const struct fb_videomode *mode, struct list_head *head) 1112 { 1113 struct list_head *pos; 1114 struct fb_modelist *modelist; 1115 struct fb_videomode *m; 1116 int found = 0; 1117 1118 list_for_each(pos, head) { 1119 modelist = list_entry(pos, struct fb_modelist, list); 1120 m = &modelist->mode; 1121 if (fb_mode_is_equal(m, mode)) { 1122 found = 1; 1123 break; 1124 } 1125 } 1126 if (!found) { 1127 modelist = kmalloc(sizeof(struct fb_modelist), 1128 GFP_KERNEL); 1129 1130 if (!modelist) 1131 return -ENOMEM; 1132 modelist->mode = *mode; 1133 list_add(&modelist->list, head); 1134 } 1135 return 0; 1136 } 1137 1138 /** 1139 * fb_delete_videomode - removed videomode entry from modelist 1140 * @mode: videomode to remove 1141 * @head: struct list_head of modelist 1142 * 1143 * NOTES: 1144 * Will remove all matching mode entries 1145 */ 1146 void fb_delete_videomode(const struct fb_videomode *mode, 1147 struct list_head *head) 1148 { 1149 struct list_head *pos, *n; 1150 struct fb_modelist *modelist; 1151 struct fb_videomode *m; 1152 1153 list_for_each_safe(pos, n, head) { 1154 modelist = list_entry(pos, struct fb_modelist, list); 1155 m = &modelist->mode; 1156 if (fb_mode_is_equal(m, mode)) { 1157 list_del(pos); 1158 kfree(pos); 1159 } 1160 } 1161 } 1162 1163 /** 1164 * fb_destroy_modelist - destroy modelist 1165 * @head: struct list_head of modelist 1166 */ 1167 void fb_destroy_modelist(struct list_head *head) 1168 { 1169 struct list_head *pos, *n; 1170 1171 list_for_each_safe(pos, n, head) { 1172 list_del(pos); 1173 kfree(pos); 1174 } 1175 } 1176 EXPORT_SYMBOL_GPL(fb_destroy_modelist); 1177 1178 /** 1179 * fb_videomode_to_modelist - convert mode array to mode list 1180 * @modedb: array of struct fb_videomode 1181 * @num: number of entries in array 1182 * @head: struct list_head of modelist 1183 */ 1184 void fb_videomode_to_modelist(const struct fb_videomode *modedb, int num, 1185 struct list_head *head) 1186 { 1187 int i; 1188 1189 INIT_LIST_HEAD(head); 1190 1191 for (i = 0; i < num; i++) { 1192 if (fb_add_videomode(&modedb[i], head)) 1193 return; 1194 } 1195 } 1196 1197 const struct fb_videomode *fb_find_best_display(const struct fb_monspecs *specs, 1198 struct list_head *head) 1199 { 1200 struct list_head *pos; 1201 struct fb_modelist *modelist; 1202 const struct fb_videomode *m, *m1 = NULL, *md = NULL, *best = NULL; 1203 int first = 0; 1204 1205 if (!head->prev || !head->next || list_empty(head)) 1206 goto finished; 1207 1208 /* get the first detailed mode and the very first mode */ 1209 list_for_each(pos, head) { 1210 modelist = list_entry(pos, struct fb_modelist, list); 1211 m = &modelist->mode; 1212 1213 if (!first) { 1214 m1 = m; 1215 first = 1; 1216 } 1217 1218 if (m->flag & FB_MODE_IS_FIRST) { 1219 md = m; 1220 break; 1221 } 1222 } 1223 1224 /* first detailed timing is preferred */ 1225 if (specs->misc & FB_MISC_1ST_DETAIL) { 1226 best = md; 1227 goto finished; 1228 } 1229 1230 /* find best mode based on display width and height */ 1231 if (specs->max_x && specs->max_y) { 1232 struct fb_var_screeninfo var; 1233 1234 memset(&var, 0, sizeof(struct fb_var_screeninfo)); 1235 var.xres = (specs->max_x * 7200)/254; 1236 var.yres = (specs->max_y * 7200)/254; 1237 m = fb_find_best_mode(&var, head); 1238 if (m) { 1239 best = m; 1240 goto finished; 1241 } 1242 } 1243 1244 /* use first detailed mode */ 1245 if (md) { 1246 best = md; 1247 goto finished; 1248 } 1249 1250 /* last resort, use the very first mode */ 1251 best = m1; 1252 finished: 1253 return best; 1254 } 1255 EXPORT_SYMBOL(fb_find_best_display); 1256 1257 EXPORT_SYMBOL(fb_videomode_to_var); 1258 EXPORT_SYMBOL(fb_var_to_videomode); 1259 EXPORT_SYMBOL(fb_mode_is_equal); 1260 EXPORT_SYMBOL(fb_add_videomode); 1261 EXPORT_SYMBOL(fb_match_mode); 1262 EXPORT_SYMBOL(fb_find_best_mode); 1263 EXPORT_SYMBOL(fb_find_nearest_mode); 1264 EXPORT_SYMBOL(fb_videomode_to_modelist); 1265 EXPORT_SYMBOL(fb_find_mode); 1266 EXPORT_SYMBOL(fb_find_mode_cvt); 1267