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 36static 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 292const 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 349const 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}; 499EXPORT_SYMBOL(vesa_modes); 500 501const 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}; 583EXPORT_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 599static 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][m] or 648 * <name>[-<bpp>][@<refresh>] 649 * 650 * with <xres>, <yres>, <bpp> and <refresh> decimal numbers and 651 * <name> a string. 652 * 653 * If 'M' is present after yres (and before refresh/bpp if present), 654 * the function will compute the timings using VESA(tm) Coordinated 655 * Video Timings (CVT). If 'R' is present after 'M', will compute with 656 * reduced blanking (for flatpanels). If 'i' is present, compute 657 * interlaced mode. If 'm' is present, add margins equal to 1.8% 658 * of xres rounded down to 8 pixels, and 1.8% of yres. The char 659 * 'i' and 'm' must be after 'M' and 'R'. Example: 660 * 661 * 1024x768MR-8@60m - Reduced blank with margins at 60Hz. 662 * 663 * NOTE: The passed struct @var is _not_ cleared! This allows you 664 * to supply values for e.g. the grayscale and accel_flags fields. 665 * 666 * Returns zero for failure, 1 if using specified @mode_option, 667 * 2 if using specified @mode_option with an ignored refresh rate, 668 * 3 if default mode is used, 4 if fall back to any valid mode. 669 * 670 */ 671 672int fb_find_mode(struct fb_var_screeninfo *var, 673 struct fb_info *info, const char *mode_option, 674 const struct fb_videomode *db, unsigned int dbsize, 675 const struct fb_videomode *default_mode, 676 unsigned int default_bpp) 677{ 678 int i; 679 680 /* Set up defaults */ 681 if (!db) { 682 db = modedb; 683 dbsize = ARRAY_SIZE(modedb); 684 } 685 686 if (!default_mode) 687 default_mode = &db[0]; 688 689 if (!default_bpp) 690 default_bpp = 8; 691 692 /* Did the user specify a video mode? */ 693 if (!mode_option) 694 mode_option = fb_mode_option; 695 if (mode_option) { 696 const char *name = mode_option; 697 unsigned int namelen = strlen(name); 698 int res_specified = 0, bpp_specified = 0, refresh_specified = 0; 699 unsigned int xres = 0, yres = 0, bpp = default_bpp, refresh = 0; 700 int yres_specified = 0, cvt = 0, rb = 0, interlace = 0; 701 int margins = 0; 702 u32 best, diff, tdiff; 703 704 for (i = namelen-1; i >= 0; i--) { 705 switch (name[i]) { 706 case '@': 707 namelen = i; 708 if (!refresh_specified && !bpp_specified && 709 !yres_specified) { 710 refresh = simple_strtol(&name[i+1], NULL, 711 10); 712 refresh_specified = 1; 713 if (cvt || rb) 714 cvt = 0; 715 } else 716 goto done; 717 break; 718 case '-': 719 namelen = i; 720 if (!bpp_specified && !yres_specified) { 721 bpp = simple_strtol(&name[i+1], NULL, 722 10); 723 bpp_specified = 1; 724 if (cvt || rb) 725 cvt = 0; 726 } else 727 goto done; 728 break; 729 case 'x': 730 if (!yres_specified) { 731 yres = simple_strtol(&name[i+1], NULL, 732 10); 733 yres_specified = 1; 734 } else 735 goto done; 736 break; 737 case '0' ... '9': 738 break; 739 case 'M': 740 if (!yres_specified) 741 cvt = 1; 742 break; 743 case 'R': 744 if (!cvt) 745 rb = 1; 746 break; 747 case 'm': 748 if (!cvt) 749 margins = 1; 750 break; 751 case 'i': 752 if (!cvt) 753 interlace = 1; 754 break; 755 default: 756 goto done; 757 } 758 } 759 if (i < 0 && yres_specified) { 760 xres = simple_strtol(name, NULL, 10); 761 res_specified = 1; 762 } 763done: 764 if (cvt) { 765 struct fb_videomode cvt_mode; 766 int ret; 767 768 DPRINTK("CVT mode %dx%d@%dHz%s%s%s\n", xres, yres, 769 (refresh) ? refresh : 60, 770 (rb) ? " reduced blanking" : "", 771 (margins) ? " with margins" : "", 772 (interlace) ? " interlaced" : ""); 773 774 memset(&cvt_mode, 0, sizeof(cvt_mode)); 775 cvt_mode.xres = xres; 776 cvt_mode.yres = yres; 777 cvt_mode.refresh = (refresh) ? refresh : 60; 778 779 if (interlace) 780 cvt_mode.vmode |= FB_VMODE_INTERLACED; 781 else 782 cvt_mode.vmode &= ~FB_VMODE_INTERLACED; 783 784 ret = fb_find_mode_cvt(&cvt_mode, margins, rb); 785 786 if (!ret && !fb_try_mode(var, info, &cvt_mode, bpp)) { 787 DPRINTK("modedb CVT: CVT mode ok\n"); 788 return 1; 789 } 790 791 DPRINTK("CVT mode invalid, getting mode from database\n"); 792 } 793 794 DPRINTK("Trying specified video mode%s %ix%i\n", 795 refresh_specified ? "" : " (ignoring refresh rate)", 796 xres, yres); 797 798 if (!refresh_specified) { 799 /* 800 * If the caller has provided a custom mode database and 801 * a valid monspecs structure, we look for the mode with 802 * the highest refresh rate. Otherwise we play it safe 803 * it and try to find a mode with a refresh rate closest 804 * to the standard 60 Hz. 805 */ 806 if (db != modedb && 807 info->monspecs.vfmin && info->monspecs.vfmax && 808 info->monspecs.hfmin && info->monspecs.hfmax && 809 info->monspecs.dclkmax) { 810 refresh = 1000; 811 } else { 812 refresh = 60; 813 } 814 } 815 816 diff = -1; 817 best = -1; 818 for (i = 0; i < dbsize; i++) { 819 if ((name_matches(db[i], name, namelen) || 820 (res_specified && res_matches(db[i], xres, yres))) && 821 !fb_try_mode(var, info, &db[i], bpp)) { 822 if (refresh_specified && db[i].refresh == refresh) 823 return 1; 824 825 if (abs(db[i].refresh - refresh) < diff) { 826 diff = abs(db[i].refresh - refresh); 827 best = i; 828 } 829 } 830 } 831 if (best != -1) { 832 fb_try_mode(var, info, &db[best], bpp); 833 return (refresh_specified) ? 2 : 1; 834 } 835 836 diff = 2 * (xres + yres); 837 best = -1; 838 DPRINTK("Trying best-fit modes\n"); 839 for (i = 0; i < dbsize; i++) { 840 DPRINTK("Trying %ix%i\n", db[i].xres, db[i].yres); 841 if (!fb_try_mode(var, info, &db[i], bpp)) { 842 tdiff = abs(db[i].xres - xres) + 843 abs(db[i].yres - yres); 844 845 /* 846 * Penalize modes with resolutions smaller 847 * than requested. 848 */ 849 if (xres > db[i].xres || yres > db[i].yres) 850 tdiff += xres + yres; 851 852 if (diff > tdiff) { 853 diff = tdiff; 854 best = i; 855 } 856 } 857 } 858 if (best != -1) { 859 fb_try_mode(var, info, &db[best], bpp); 860 return 5; 861 } 862 } 863 864 DPRINTK("Trying default video mode\n"); 865 if (!fb_try_mode(var, info, default_mode, default_bpp)) 866 return 3; 867 868 DPRINTK("Trying all modes\n"); 869 for (i = 0; i < dbsize; i++) 870 if (!fb_try_mode(var, info, &db[i], default_bpp)) 871 return 4; 872 873 DPRINTK("No valid mode found\n"); 874 return 0; 875} 876 877/** 878 * fb_var_to_videomode - convert fb_var_screeninfo to fb_videomode 879 * @mode: pointer to struct fb_videomode 880 * @var: pointer to struct fb_var_screeninfo 881 */ 882void fb_var_to_videomode(struct fb_videomode *mode, 883 const struct fb_var_screeninfo *var) 884{ 885 u32 pixclock, hfreq, htotal, vtotal; 886 887 mode->name = NULL; 888 mode->xres = var->xres; 889 mode->yres = var->yres; 890 mode->pixclock = var->pixclock; 891 mode->hsync_len = var->hsync_len; 892 mode->vsync_len = var->vsync_len; 893 mode->left_margin = var->left_margin; 894 mode->right_margin = var->right_margin; 895 mode->upper_margin = var->upper_margin; 896 mode->lower_margin = var->lower_margin; 897 mode->sync = var->sync; 898 mode->vmode = var->vmode & FB_VMODE_MASK; 899 mode->flag = FB_MODE_IS_FROM_VAR; 900 mode->refresh = 0; 901 902 if (!var->pixclock) 903 return; 904 905 pixclock = PICOS2KHZ(var->pixclock) * 1000; 906 907 htotal = var->xres + var->right_margin + var->hsync_len + 908 var->left_margin; 909 vtotal = var->yres + var->lower_margin + var->vsync_len + 910 var->upper_margin; 911 912 if (var->vmode & FB_VMODE_INTERLACED) 913 vtotal /= 2; 914 if (var->vmode & FB_VMODE_DOUBLE) 915 vtotal *= 2; 916 917 hfreq = pixclock/htotal; 918 mode->refresh = hfreq/vtotal; 919} 920 921/** 922 * fb_videomode_to_var - convert fb_videomode to fb_var_screeninfo 923 * @var: pointer to struct fb_var_screeninfo 924 * @mode: pointer to struct fb_videomode 925 */ 926void fb_videomode_to_var(struct fb_var_screeninfo *var, 927 const struct fb_videomode *mode) 928{ 929 var->xres = mode->xres; 930 var->yres = mode->yres; 931 var->xres_virtual = mode->xres; 932 var->yres_virtual = mode->yres; 933 var->xoffset = 0; 934 var->yoffset = 0; 935 var->pixclock = mode->pixclock; 936 var->left_margin = mode->left_margin; 937 var->right_margin = mode->right_margin; 938 var->upper_margin = mode->upper_margin; 939 var->lower_margin = mode->lower_margin; 940 var->hsync_len = mode->hsync_len; 941 var->vsync_len = mode->vsync_len; 942 var->sync = mode->sync; 943 var->vmode = mode->vmode & FB_VMODE_MASK; 944} 945 946/** 947 * fb_mode_is_equal - compare 2 videomodes 948 * @mode1: first videomode 949 * @mode2: second videomode 950 * 951 * RETURNS: 952 * 1 if equal, 0 if not 953 */ 954int fb_mode_is_equal(const struct fb_videomode *mode1, 955 const struct fb_videomode *mode2) 956{ 957 return (mode1->xres == mode2->xres && 958 mode1->yres == mode2->yres && 959 mode1->pixclock == mode2->pixclock && 960 mode1->hsync_len == mode2->hsync_len && 961 mode1->vsync_len == mode2->vsync_len && 962 mode1->left_margin == mode2->left_margin && 963 mode1->right_margin == mode2->right_margin && 964 mode1->upper_margin == mode2->upper_margin && 965 mode1->lower_margin == mode2->lower_margin && 966 mode1->sync == mode2->sync && 967 mode1->vmode == mode2->vmode); 968} 969 970/** 971 * fb_find_best_mode - find best matching videomode 972 * @var: pointer to struct fb_var_screeninfo 973 * @head: pointer to struct list_head of modelist 974 * 975 * RETURNS: 976 * struct fb_videomode, NULL if none found 977 * 978 * IMPORTANT: 979 * This function assumes that all modelist entries in 980 * info->modelist are valid. 981 * 982 * NOTES: 983 * Finds best matching videomode which has an equal or greater dimension than 984 * var->xres and var->yres. If more than 1 videomode is found, will return 985 * the videomode with the highest refresh rate 986 */ 987const struct fb_videomode *fb_find_best_mode(const struct fb_var_screeninfo *var, 988 struct list_head *head) 989{ 990 struct list_head *pos; 991 struct fb_modelist *modelist; 992 struct fb_videomode *mode, *best = NULL; 993 u32 diff = -1; 994 995 list_for_each(pos, head) { 996 u32 d; 997 998 modelist = list_entry(pos, struct fb_modelist, list); 999 mode = &modelist->mode; 1000 1001 if (mode->xres >= var->xres && mode->yres >= var->yres) { 1002 d = (mode->xres - var->xres) + 1003 (mode->yres - var->yres); 1004 if (diff > d) { 1005 diff = d; 1006 best = mode; 1007 } else if (diff == d && best && 1008 mode->refresh > best->refresh) 1009 best = mode; 1010 } 1011 } 1012 return best; 1013} 1014 1015/** 1016 * fb_find_nearest_mode - find closest videomode 1017 * 1018 * @mode: pointer to struct fb_videomode 1019 * @head: pointer to modelist 1020 * 1021 * Finds best matching videomode, smaller or greater in dimension. 1022 * If more than 1 videomode is found, will return the videomode with 1023 * the closest refresh rate. 1024 */ 1025const struct fb_videomode *fb_find_nearest_mode(const struct fb_videomode *mode, 1026 struct list_head *head) 1027{ 1028 struct list_head *pos; 1029 struct fb_modelist *modelist; 1030 struct fb_videomode *cmode, *best = NULL; 1031 u32 diff = -1, diff_refresh = -1; 1032 1033 list_for_each(pos, head) { 1034 u32 d; 1035 1036 modelist = list_entry(pos, struct fb_modelist, list); 1037 cmode = &modelist->mode; 1038 1039 d = abs(cmode->xres - mode->xres) + 1040 abs(cmode->yres - mode->yres); 1041 if (diff > d) { 1042 diff = d; 1043 diff_refresh = abs(cmode->refresh - mode->refresh); 1044 best = cmode; 1045 } else if (diff == d) { 1046 d = abs(cmode->refresh - mode->refresh); 1047 if (diff_refresh > d) { 1048 diff_refresh = d; 1049 best = cmode; 1050 } 1051 } 1052 } 1053 1054 return best; 1055} 1056 1057/** 1058 * fb_match_mode - find a videomode which exactly matches the timings in var 1059 * @var: pointer to struct fb_var_screeninfo 1060 * @head: pointer to struct list_head of modelist 1061 * 1062 * RETURNS: 1063 * struct fb_videomode, NULL if none found 1064 */ 1065const struct fb_videomode *fb_match_mode(const struct fb_var_screeninfo *var, 1066 struct list_head *head) 1067{ 1068 struct list_head *pos; 1069 struct fb_modelist *modelist; 1070 struct fb_videomode *m, mode; 1071 1072 fb_var_to_videomode(&mode, var); 1073 list_for_each(pos, head) { 1074 modelist = list_entry(pos, struct fb_modelist, list); 1075 m = &modelist->mode; 1076 if (fb_mode_is_equal(m, &mode)) 1077 return m; 1078 } 1079 return NULL; 1080} 1081 1082/** 1083 * fb_add_videomode - adds videomode entry to modelist 1084 * @mode: videomode to add 1085 * @head: struct list_head of modelist 1086 * 1087 * NOTES: 1088 * Will only add unmatched mode entries 1089 */ 1090int fb_add_videomode(const struct fb_videomode *mode, struct list_head *head) 1091{ 1092 struct list_head *pos; 1093 struct fb_modelist *modelist; 1094 struct fb_videomode *m; 1095 int found = 0; 1096 1097 list_for_each(pos, head) { 1098 modelist = list_entry(pos, struct fb_modelist, list); 1099 m = &modelist->mode; 1100 if (fb_mode_is_equal(m, mode)) { 1101 found = 1; 1102 break; 1103 } 1104 } 1105 if (!found) { 1106 modelist = kmalloc(sizeof(struct fb_modelist), 1107 GFP_KERNEL); 1108 1109 if (!modelist) 1110 return -ENOMEM; 1111 modelist->mode = *mode; 1112 list_add(&modelist->list, head); 1113 } 1114 return 0; 1115} 1116 1117/** 1118 * fb_delete_videomode - removed videomode entry from modelist 1119 * @mode: videomode to remove 1120 * @head: struct list_head of modelist 1121 * 1122 * NOTES: 1123 * Will remove all matching mode entries 1124 */ 1125void fb_delete_videomode(const struct fb_videomode *mode, 1126 struct list_head *head) 1127{ 1128 struct list_head *pos, *n; 1129 struct fb_modelist *modelist; 1130 struct fb_videomode *m; 1131 1132 list_for_each_safe(pos, n, head) { 1133 modelist = list_entry(pos, struct fb_modelist, list); 1134 m = &modelist->mode; 1135 if (fb_mode_is_equal(m, mode)) { 1136 list_del(pos); 1137 kfree(pos); 1138 } 1139 } 1140} 1141 1142/** 1143 * fb_destroy_modelist - destroy modelist 1144 * @head: struct list_head of modelist 1145 */ 1146void fb_destroy_modelist(struct list_head *head) 1147{ 1148 struct list_head *pos, *n; 1149 1150 list_for_each_safe(pos, n, head) { 1151 list_del(pos); 1152 kfree(pos); 1153 } 1154} 1155EXPORT_SYMBOL_GPL(fb_destroy_modelist); 1156 1157/** 1158 * fb_videomode_to_modelist - convert mode array to mode list 1159 * @modedb: array of struct fb_videomode 1160 * @num: number of entries in array 1161 * @head: struct list_head of modelist 1162 */ 1163void fb_videomode_to_modelist(const struct fb_videomode *modedb, int num, 1164 struct list_head *head) 1165{ 1166 int i; 1167 1168 INIT_LIST_HEAD(head); 1169 1170 for (i = 0; i < num; i++) { 1171 if (fb_add_videomode(&modedb[i], head)) 1172 return; 1173 } 1174} 1175 1176const struct fb_videomode *fb_find_best_display(const struct fb_monspecs *specs, 1177 struct list_head *head) 1178{ 1179 struct list_head *pos; 1180 struct fb_modelist *modelist; 1181 const struct fb_videomode *m, *m1 = NULL, *md = NULL, *best = NULL; 1182 int first = 0; 1183 1184 if (!head->prev || !head->next || list_empty(head)) 1185 goto finished; 1186 1187 /* get the first detailed mode and the very first mode */ 1188 list_for_each(pos, head) { 1189 modelist = list_entry(pos, struct fb_modelist, list); 1190 m = &modelist->mode; 1191 1192 if (!first) { 1193 m1 = m; 1194 first = 1; 1195 } 1196 1197 if (m->flag & FB_MODE_IS_FIRST) { 1198 md = m; 1199 break; 1200 } 1201 } 1202 1203 /* first detailed timing is preferred */ 1204 if (specs->misc & FB_MISC_1ST_DETAIL) { 1205 best = md; 1206 goto finished; 1207 } 1208 1209 /* find best mode based on display width and height */ 1210 if (specs->max_x && specs->max_y) { 1211 struct fb_var_screeninfo var; 1212 1213 memset(&var, 0, sizeof(struct fb_var_screeninfo)); 1214 var.xres = (specs->max_x * 7200)/254; 1215 var.yres = (specs->max_y * 7200)/254; 1216 m = fb_find_best_mode(&var, head); 1217 if (m) { 1218 best = m; 1219 goto finished; 1220 } 1221 } 1222 1223 /* use first detailed mode */ 1224 if (md) { 1225 best = md; 1226 goto finished; 1227 } 1228 1229 /* last resort, use the very first mode */ 1230 best = m1; 1231finished: 1232 return best; 1233} 1234EXPORT_SYMBOL(fb_find_best_display); 1235 1236EXPORT_SYMBOL(fb_videomode_to_var); 1237EXPORT_SYMBOL(fb_var_to_videomode); 1238EXPORT_SYMBOL(fb_mode_is_equal); 1239EXPORT_SYMBOL(fb_add_videomode); 1240EXPORT_SYMBOL(fb_match_mode); 1241EXPORT_SYMBOL(fb_find_best_mode); 1242EXPORT_SYMBOL(fb_find_nearest_mode); 1243EXPORT_SYMBOL(fb_videomode_to_modelist); 1244EXPORT_SYMBOL(fb_find_mode); 1245EXPORT_SYMBOL(fb_find_mode_cvt); 1246