Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.30-rc7 1400 lines 35 kB view raw
1/* 2 * linux/drivers/video/fbmon.c 3 * 4 * Copyright (C) 2002 James Simmons <jsimmons@users.sf.net> 5 * 6 * Credits: 7 * 8 * The EDID Parser is a conglomeration from the following sources: 9 * 10 * 1. SciTech SNAP Graphics Architecture 11 * Copyright (C) 1991-2002 SciTech Software, Inc. All rights reserved. 12 * 13 * 2. XFree86 4.3.0, interpret_edid.c 14 * Copyright 1998 by Egbert Eich <Egbert.Eich@Physik.TU-Darmstadt.DE> 15 * 16 * 3. John Fremlin <vii@users.sourceforge.net> and 17 * Ani Joshi <ajoshi@unixbox.com> 18 * 19 * Generalized Timing Formula is derived from: 20 * 21 * GTF Spreadsheet by Andy Morrish (1/5/97) 22 * available at http://www.vesa.org 23 * 24 * This file is subject to the terms and conditions of the GNU General Public 25 * License. See the file COPYING in the main directory of this archive 26 * for more details. 27 * 28 */ 29#include <linux/fb.h> 30#include <linux/module.h> 31#include <linux/pci.h> 32#include <video/edid.h> 33#ifdef CONFIG_PPC_OF 34#include <asm/prom.h> 35#include <asm/pci-bridge.h> 36#endif 37#include "edid.h" 38 39/* 40 * EDID parser 41 */ 42 43#undef DEBUG /* define this for verbose EDID parsing output */ 44 45#ifdef DEBUG 46#define DPRINTK(fmt, args...) printk(fmt,## args) 47#else 48#define DPRINTK(fmt, args...) 49#endif 50 51#define FBMON_FIX_HEADER 1 52#define FBMON_FIX_INPUT 2 53#define FBMON_FIX_TIMINGS 3 54 55#ifdef CONFIG_FB_MODE_HELPERS 56struct broken_edid { 57 u8 manufacturer[4]; 58 u32 model; 59 u32 fix; 60}; 61 62static const struct broken_edid brokendb[] = { 63 /* DEC FR-PCXAV-YZ */ 64 { 65 .manufacturer = "DEC", 66 .model = 0x073a, 67 .fix = FBMON_FIX_HEADER, 68 }, 69 /* ViewSonic PF775a */ 70 { 71 .manufacturer = "VSC", 72 .model = 0x5a44, 73 .fix = FBMON_FIX_INPUT, 74 }, 75 /* Sharp UXGA? */ 76 { 77 .manufacturer = "SHP", 78 .model = 0x138e, 79 .fix = FBMON_FIX_TIMINGS, 80 }, 81}; 82 83static const unsigned char edid_v1_header[] = { 0x00, 0xff, 0xff, 0xff, 84 0xff, 0xff, 0xff, 0x00 85}; 86 87static void copy_string(unsigned char *c, unsigned char *s) 88{ 89 int i; 90 c = c + 5; 91 for (i = 0; (i < 13 && *c != 0x0A); i++) 92 *(s++) = *(c++); 93 *s = 0; 94 while (i-- && (*--s == 0x20)) *s = 0; 95} 96 97static int edid_is_serial_block(unsigned char *block) 98{ 99 if ((block[0] == 0x00) && (block[1] == 0x00) && 100 (block[2] == 0x00) && (block[3] == 0xff) && 101 (block[4] == 0x00)) 102 return 1; 103 else 104 return 0; 105} 106 107static int edid_is_ascii_block(unsigned char *block) 108{ 109 if ((block[0] == 0x00) && (block[1] == 0x00) && 110 (block[2] == 0x00) && (block[3] == 0xfe) && 111 (block[4] == 0x00)) 112 return 1; 113 else 114 return 0; 115} 116 117static int edid_is_limits_block(unsigned char *block) 118{ 119 if ((block[0] == 0x00) && (block[1] == 0x00) && 120 (block[2] == 0x00) && (block[3] == 0xfd) && 121 (block[4] == 0x00)) 122 return 1; 123 else 124 return 0; 125} 126 127static int edid_is_monitor_block(unsigned char *block) 128{ 129 if ((block[0] == 0x00) && (block[1] == 0x00) && 130 (block[2] == 0x00) && (block[3] == 0xfc) && 131 (block[4] == 0x00)) 132 return 1; 133 else 134 return 0; 135} 136 137static int edid_is_timing_block(unsigned char *block) 138{ 139 if ((block[0] != 0x00) || (block[1] != 0x00) || 140 (block[2] != 0x00) || (block[4] != 0x00)) 141 return 1; 142 else 143 return 0; 144} 145 146static int check_edid(unsigned char *edid) 147{ 148 unsigned char *block = edid + ID_MANUFACTURER_NAME, manufacturer[4]; 149 unsigned char *b; 150 u32 model; 151 int i, fix = 0, ret = 0; 152 153 manufacturer[0] = ((block[0] & 0x7c) >> 2) + '@'; 154 manufacturer[1] = ((block[0] & 0x03) << 3) + 155 ((block[1] & 0xe0) >> 5) + '@'; 156 manufacturer[2] = (block[1] & 0x1f) + '@'; 157 manufacturer[3] = 0; 158 model = block[2] + (block[3] << 8); 159 160 for (i = 0; i < ARRAY_SIZE(brokendb); i++) { 161 if (!strncmp(manufacturer, brokendb[i].manufacturer, 4) && 162 brokendb[i].model == model) { 163 fix = brokendb[i].fix; 164 break; 165 } 166 } 167 168 switch (fix) { 169 case FBMON_FIX_HEADER: 170 for (i = 0; i < 8; i++) { 171 if (edid[i] != edid_v1_header[i]) { 172 ret = fix; 173 break; 174 } 175 } 176 break; 177 case FBMON_FIX_INPUT: 178 b = edid + EDID_STRUCT_DISPLAY; 179 /* Only if display is GTF capable will 180 the input type be reset to analog */ 181 if (b[4] & 0x01 && b[0] & 0x80) 182 ret = fix; 183 break; 184 case FBMON_FIX_TIMINGS: 185 b = edid + DETAILED_TIMING_DESCRIPTIONS_START; 186 ret = fix; 187 188 for (i = 0; i < 4; i++) { 189 if (edid_is_limits_block(b)) { 190 ret = 0; 191 break; 192 } 193 194 b += DETAILED_TIMING_DESCRIPTION_SIZE; 195 } 196 197 break; 198 } 199 200 if (ret) 201 printk("fbmon: The EDID Block of " 202 "Manufacturer: %s Model: 0x%x is known to " 203 "be broken,\n", manufacturer, model); 204 205 return ret; 206} 207 208static void fix_edid(unsigned char *edid, int fix) 209{ 210 int i; 211 unsigned char *b, csum = 0; 212 213 switch (fix) { 214 case FBMON_FIX_HEADER: 215 printk("fbmon: trying a header reconstruct\n"); 216 memcpy(edid, edid_v1_header, 8); 217 break; 218 case FBMON_FIX_INPUT: 219 printk("fbmon: trying to fix input type\n"); 220 b = edid + EDID_STRUCT_DISPLAY; 221 b[0] &= ~0x80; 222 edid[127] += 0x80; 223 break; 224 case FBMON_FIX_TIMINGS: 225 printk("fbmon: trying to fix monitor timings\n"); 226 b = edid + DETAILED_TIMING_DESCRIPTIONS_START; 227 for (i = 0; i < 4; i++) { 228 if (!(edid_is_serial_block(b) || 229 edid_is_ascii_block(b) || 230 edid_is_monitor_block(b) || 231 edid_is_timing_block(b))) { 232 b[0] = 0x00; 233 b[1] = 0x00; 234 b[2] = 0x00; 235 b[3] = 0xfd; 236 b[4] = 0x00; 237 b[5] = 60; /* vfmin */ 238 b[6] = 60; /* vfmax */ 239 b[7] = 30; /* hfmin */ 240 b[8] = 75; /* hfmax */ 241 b[9] = 17; /* pixclock - 170 MHz*/ 242 b[10] = 0; /* GTF */ 243 break; 244 } 245 246 b += DETAILED_TIMING_DESCRIPTION_SIZE; 247 } 248 249 for (i = 0; i < EDID_LENGTH - 1; i++) 250 csum += edid[i]; 251 252 edid[127] = 256 - csum; 253 break; 254 } 255} 256 257static int edid_checksum(unsigned char *edid) 258{ 259 unsigned char i, csum = 0, all_null = 0; 260 int err = 0, fix = check_edid(edid); 261 262 if (fix) 263 fix_edid(edid, fix); 264 265 for (i = 0; i < EDID_LENGTH; i++) { 266 csum += edid[i]; 267 all_null |= edid[i]; 268 } 269 270 if (csum == 0x00 && all_null) { 271 /* checksum passed, everything's good */ 272 err = 1; 273 } 274 275 return err; 276} 277 278static int edid_check_header(unsigned char *edid) 279{ 280 int i, err = 1, fix = check_edid(edid); 281 282 if (fix) 283 fix_edid(edid, fix); 284 285 for (i = 0; i < 8; i++) { 286 if (edid[i] != edid_v1_header[i]) 287 err = 0; 288 } 289 290 return err; 291} 292 293static void parse_vendor_block(unsigned char *block, struct fb_monspecs *specs) 294{ 295 specs->manufacturer[0] = ((block[0] & 0x7c) >> 2) + '@'; 296 specs->manufacturer[1] = ((block[0] & 0x03) << 3) + 297 ((block[1] & 0xe0) >> 5) + '@'; 298 specs->manufacturer[2] = (block[1] & 0x1f) + '@'; 299 specs->manufacturer[3] = 0; 300 specs->model = block[2] + (block[3] << 8); 301 specs->serial = block[4] + (block[5] << 8) + 302 (block[6] << 16) + (block[7] << 24); 303 specs->year = block[9] + 1990; 304 specs->week = block[8]; 305 DPRINTK(" Manufacturer: %s\n", specs->manufacturer); 306 DPRINTK(" Model: %x\n", specs->model); 307 DPRINTK(" Serial#: %u\n", specs->serial); 308 DPRINTK(" Year: %u Week %u\n", specs->year, specs->week); 309} 310 311static void get_dpms_capabilities(unsigned char flags, 312 struct fb_monspecs *specs) 313{ 314 specs->dpms = 0; 315 if (flags & DPMS_ACTIVE_OFF) 316 specs->dpms |= FB_DPMS_ACTIVE_OFF; 317 if (flags & DPMS_SUSPEND) 318 specs->dpms |= FB_DPMS_SUSPEND; 319 if (flags & DPMS_STANDBY) 320 specs->dpms |= FB_DPMS_STANDBY; 321 DPRINTK(" DPMS: Active %s, Suspend %s, Standby %s\n", 322 (flags & DPMS_ACTIVE_OFF) ? "yes" : "no", 323 (flags & DPMS_SUSPEND) ? "yes" : "no", 324 (flags & DPMS_STANDBY) ? "yes" : "no"); 325} 326 327static void get_chroma(unsigned char *block, struct fb_monspecs *specs) 328{ 329 int tmp; 330 331 DPRINTK(" Chroma\n"); 332 /* Chromaticity data */ 333 tmp = ((block[5] & (3 << 6)) >> 6) | (block[0x7] << 2); 334 tmp *= 1000; 335 tmp += 512; 336 specs->chroma.redx = tmp/1024; 337 DPRINTK(" RedX: 0.%03d ", specs->chroma.redx); 338 339 tmp = ((block[5] & (3 << 4)) >> 4) | (block[0x8] << 2); 340 tmp *= 1000; 341 tmp += 512; 342 specs->chroma.redy = tmp/1024; 343 DPRINTK("RedY: 0.%03d\n", specs->chroma.redy); 344 345 tmp = ((block[5] & (3 << 2)) >> 2) | (block[0x9] << 2); 346 tmp *= 1000; 347 tmp += 512; 348 specs->chroma.greenx = tmp/1024; 349 DPRINTK(" GreenX: 0.%03d ", specs->chroma.greenx); 350 351 tmp = (block[5] & 3) | (block[0xa] << 2); 352 tmp *= 1000; 353 tmp += 512; 354 specs->chroma.greeny = tmp/1024; 355 DPRINTK("GreenY: 0.%03d\n", specs->chroma.greeny); 356 357 tmp = ((block[6] & (3 << 6)) >> 6) | (block[0xb] << 2); 358 tmp *= 1000; 359 tmp += 512; 360 specs->chroma.bluex = tmp/1024; 361 DPRINTK(" BlueX: 0.%03d ", specs->chroma.bluex); 362 363 tmp = ((block[6] & (3 << 4)) >> 4) | (block[0xc] << 2); 364 tmp *= 1000; 365 tmp += 512; 366 specs->chroma.bluey = tmp/1024; 367 DPRINTK("BlueY: 0.%03d\n", specs->chroma.bluey); 368 369 tmp = ((block[6] & (3 << 2)) >> 2) | (block[0xd] << 2); 370 tmp *= 1000; 371 tmp += 512; 372 specs->chroma.whitex = tmp/1024; 373 DPRINTK(" WhiteX: 0.%03d ", specs->chroma.whitex); 374 375 tmp = (block[6] & 3) | (block[0xe] << 2); 376 tmp *= 1000; 377 tmp += 512; 378 specs->chroma.whitey = tmp/1024; 379 DPRINTK("WhiteY: 0.%03d\n", specs->chroma.whitey); 380} 381 382static void calc_mode_timings(int xres, int yres, int refresh, 383 struct fb_videomode *mode) 384{ 385 struct fb_var_screeninfo *var; 386 387 var = kzalloc(sizeof(struct fb_var_screeninfo), GFP_KERNEL); 388 389 if (var) { 390 var->xres = xres; 391 var->yres = yres; 392 fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 393 refresh, var, NULL); 394 mode->xres = xres; 395 mode->yres = yres; 396 mode->pixclock = var->pixclock; 397 mode->refresh = refresh; 398 mode->left_margin = var->left_margin; 399 mode->right_margin = var->right_margin; 400 mode->upper_margin = var->upper_margin; 401 mode->lower_margin = var->lower_margin; 402 mode->hsync_len = var->hsync_len; 403 mode->vsync_len = var->vsync_len; 404 mode->vmode = 0; 405 mode->sync = 0; 406 kfree(var); 407 } 408} 409 410static int get_est_timing(unsigned char *block, struct fb_videomode *mode) 411{ 412 int num = 0; 413 unsigned char c; 414 415 c = block[0]; 416 if (c&0x80) { 417 calc_mode_timings(720, 400, 70, &mode[num]); 418 mode[num++].flag = FB_MODE_IS_CALCULATED; 419 DPRINTK(" 720x400@70Hz\n"); 420 } 421 if (c&0x40) { 422 calc_mode_timings(720, 400, 88, &mode[num]); 423 mode[num++].flag = FB_MODE_IS_CALCULATED; 424 DPRINTK(" 720x400@88Hz\n"); 425 } 426 if (c&0x20) { 427 mode[num++] = vesa_modes[3]; 428 DPRINTK(" 640x480@60Hz\n"); 429 } 430 if (c&0x10) { 431 calc_mode_timings(640, 480, 67, &mode[num]); 432 mode[num++].flag = FB_MODE_IS_CALCULATED; 433 DPRINTK(" 640x480@67Hz\n"); 434 } 435 if (c&0x08) { 436 mode[num++] = vesa_modes[4]; 437 DPRINTK(" 640x480@72Hz\n"); 438 } 439 if (c&0x04) { 440 mode[num++] = vesa_modes[5]; 441 DPRINTK(" 640x480@75Hz\n"); 442 } 443 if (c&0x02) { 444 mode[num++] = vesa_modes[7]; 445 DPRINTK(" 800x600@56Hz\n"); 446 } 447 if (c&0x01) { 448 mode[num++] = vesa_modes[8]; 449 DPRINTK(" 800x600@60Hz\n"); 450 } 451 452 c = block[1]; 453 if (c&0x80) { 454 mode[num++] = vesa_modes[9]; 455 DPRINTK(" 800x600@72Hz\n"); 456 } 457 if (c&0x40) { 458 mode[num++] = vesa_modes[10]; 459 DPRINTK(" 800x600@75Hz\n"); 460 } 461 if (c&0x20) { 462 calc_mode_timings(832, 624, 75, &mode[num]); 463 mode[num++].flag = FB_MODE_IS_CALCULATED; 464 DPRINTK(" 832x624@75Hz\n"); 465 } 466 if (c&0x10) { 467 mode[num++] = vesa_modes[12]; 468 DPRINTK(" 1024x768@87Hz Interlaced\n"); 469 } 470 if (c&0x08) { 471 mode[num++] = vesa_modes[13]; 472 DPRINTK(" 1024x768@60Hz\n"); 473 } 474 if (c&0x04) { 475 mode[num++] = vesa_modes[14]; 476 DPRINTK(" 1024x768@70Hz\n"); 477 } 478 if (c&0x02) { 479 mode[num++] = vesa_modes[15]; 480 DPRINTK(" 1024x768@75Hz\n"); 481 } 482 if (c&0x01) { 483 mode[num++] = vesa_modes[21]; 484 DPRINTK(" 1280x1024@75Hz\n"); 485 } 486 c = block[2]; 487 if (c&0x80) { 488 mode[num++] = vesa_modes[17]; 489 DPRINTK(" 1152x870@75Hz\n"); 490 } 491 DPRINTK(" Manufacturer's mask: %x\n",c&0x7F); 492 return num; 493} 494 495static int get_std_timing(unsigned char *block, struct fb_videomode *mode) 496{ 497 int xres, yres = 0, refresh, ratio, i; 498 499 xres = (block[0] + 31) * 8; 500 if (xres <= 256) 501 return 0; 502 503 ratio = (block[1] & 0xc0) >> 6; 504 switch (ratio) { 505 case 0: 506 yres = xres; 507 break; 508 case 1: 509 yres = (xres * 3)/4; 510 break; 511 case 2: 512 yres = (xres * 4)/5; 513 break; 514 case 3: 515 yres = (xres * 9)/16; 516 break; 517 } 518 refresh = (block[1] & 0x3f) + 60; 519 520 DPRINTK(" %dx%d@%dHz\n", xres, yres, refresh); 521 for (i = 0; i < VESA_MODEDB_SIZE; i++) { 522 if (vesa_modes[i].xres == xres && 523 vesa_modes[i].yres == yres && 524 vesa_modes[i].refresh == refresh) { 525 *mode = vesa_modes[i]; 526 mode->flag |= FB_MODE_IS_STANDARD; 527 return 1; 528 } 529 } 530 calc_mode_timings(xres, yres, refresh, mode); 531 return 1; 532} 533 534static int get_dst_timing(unsigned char *block, 535 struct fb_videomode *mode) 536{ 537 int j, num = 0; 538 539 for (j = 0; j < 6; j++, block += STD_TIMING_DESCRIPTION_SIZE) 540 num += get_std_timing(block, &mode[num]); 541 542 return num; 543} 544 545static void get_detailed_timing(unsigned char *block, 546 struct fb_videomode *mode) 547{ 548 mode->xres = H_ACTIVE; 549 mode->yres = V_ACTIVE; 550 mode->pixclock = PIXEL_CLOCK; 551 mode->pixclock /= 1000; 552 mode->pixclock = KHZ2PICOS(mode->pixclock); 553 mode->right_margin = H_SYNC_OFFSET; 554 mode->left_margin = (H_ACTIVE + H_BLANKING) - 555 (H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH); 556 mode->upper_margin = V_BLANKING - V_SYNC_OFFSET - 557 V_SYNC_WIDTH; 558 mode->lower_margin = V_SYNC_OFFSET; 559 mode->hsync_len = H_SYNC_WIDTH; 560 mode->vsync_len = V_SYNC_WIDTH; 561 if (HSYNC_POSITIVE) 562 mode->sync |= FB_SYNC_HOR_HIGH_ACT; 563 if (VSYNC_POSITIVE) 564 mode->sync |= FB_SYNC_VERT_HIGH_ACT; 565 mode->refresh = PIXEL_CLOCK/((H_ACTIVE + H_BLANKING) * 566 (V_ACTIVE + V_BLANKING)); 567 if (INTERLACED) { 568 mode->yres *= 2; 569 mode->upper_margin *= 2; 570 mode->lower_margin *= 2; 571 mode->vsync_len *= 2; 572 mode->vmode |= FB_VMODE_INTERLACED; 573 } 574 mode->flag = FB_MODE_IS_DETAILED; 575 576 DPRINTK(" %d MHz ", PIXEL_CLOCK/1000000); 577 DPRINTK("%d %d %d %d ", H_ACTIVE, H_ACTIVE + H_SYNC_OFFSET, 578 H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH, H_ACTIVE + H_BLANKING); 579 DPRINTK("%d %d %d %d ", V_ACTIVE, V_ACTIVE + V_SYNC_OFFSET, 580 V_ACTIVE + V_SYNC_OFFSET + V_SYNC_WIDTH, V_ACTIVE + V_BLANKING); 581 DPRINTK("%sHSync %sVSync\n\n", (HSYNC_POSITIVE) ? "+" : "-", 582 (VSYNC_POSITIVE) ? "+" : "-"); 583} 584 585/** 586 * fb_create_modedb - create video mode database 587 * @edid: EDID data 588 * @dbsize: database size 589 * 590 * RETURNS: struct fb_videomode, @dbsize contains length of database 591 * 592 * DESCRIPTION: 593 * This function builds a mode database using the contents of the EDID 594 * data 595 */ 596static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize) 597{ 598 struct fb_videomode *mode, *m; 599 unsigned char *block; 600 int num = 0, i, first = 1; 601 602 mode = kzalloc(50 * sizeof(struct fb_videomode), GFP_KERNEL); 603 if (mode == NULL) 604 return NULL; 605 606 if (edid == NULL || !edid_checksum(edid) || 607 !edid_check_header(edid)) { 608 kfree(mode); 609 return NULL; 610 } 611 612 *dbsize = 0; 613 614 DPRINTK(" Detailed Timings\n"); 615 block = edid + DETAILED_TIMING_DESCRIPTIONS_START; 616 for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) { 617 if (!(block[0] == 0x00 && block[1] == 0x00)) { 618 get_detailed_timing(block, &mode[num]); 619 if (first) { 620 mode[num].flag |= FB_MODE_IS_FIRST; 621 first = 0; 622 } 623 num++; 624 } 625 } 626 627 DPRINTK(" Supported VESA Modes\n"); 628 block = edid + ESTABLISHED_TIMING_1; 629 num += get_est_timing(block, &mode[num]); 630 631 DPRINTK(" Standard Timings\n"); 632 block = edid + STD_TIMING_DESCRIPTIONS_START; 633 for (i = 0; i < STD_TIMING; i++, block += STD_TIMING_DESCRIPTION_SIZE) 634 num += get_std_timing(block, &mode[num]); 635 636 block = edid + DETAILED_TIMING_DESCRIPTIONS_START; 637 for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) { 638 if (block[0] == 0x00 && block[1] == 0x00 && block[3] == 0xfa) 639 num += get_dst_timing(block + 5, &mode[num]); 640 } 641 642 /* Yikes, EDID data is totally useless */ 643 if (!num) { 644 kfree(mode); 645 return NULL; 646 } 647 648 *dbsize = num; 649 m = kmalloc(num * sizeof(struct fb_videomode), GFP_KERNEL); 650 if (!m) 651 return mode; 652 memmove(m, mode, num * sizeof(struct fb_videomode)); 653 kfree(mode); 654 return m; 655} 656 657/** 658 * fb_destroy_modedb - destroys mode database 659 * @modedb: mode database to destroy 660 * 661 * DESCRIPTION: 662 * Destroy mode database created by fb_create_modedb 663 */ 664void fb_destroy_modedb(struct fb_videomode *modedb) 665{ 666 kfree(modedb); 667} 668 669static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs) 670{ 671 int i, retval = 1; 672 unsigned char *block; 673 674 block = edid + DETAILED_TIMING_DESCRIPTIONS_START; 675 676 DPRINTK(" Monitor Operating Limits: "); 677 678 for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) { 679 if (edid_is_limits_block(block)) { 680 specs->hfmin = H_MIN_RATE * 1000; 681 specs->hfmax = H_MAX_RATE * 1000; 682 specs->vfmin = V_MIN_RATE; 683 specs->vfmax = V_MAX_RATE; 684 specs->dclkmax = MAX_PIXEL_CLOCK * 1000000; 685 specs->gtf = (GTF_SUPPORT) ? 1 : 0; 686 retval = 0; 687 DPRINTK("From EDID\n"); 688 break; 689 } 690 } 691 692 /* estimate monitor limits based on modes supported */ 693 if (retval) { 694 struct fb_videomode *modes, *mode; 695 int num_modes, hz, hscan, pixclock; 696 int vtotal, htotal; 697 698 modes = fb_create_modedb(edid, &num_modes); 699 if (!modes) { 700 DPRINTK("None Available\n"); 701 return 1; 702 } 703 704 retval = 0; 705 for (i = 0; i < num_modes; i++) { 706 mode = &modes[i]; 707 pixclock = PICOS2KHZ(modes[i].pixclock) * 1000; 708 htotal = mode->xres + mode->right_margin + mode->hsync_len 709 + mode->left_margin; 710 vtotal = mode->yres + mode->lower_margin + mode->vsync_len 711 + mode->upper_margin; 712 713 if (mode->vmode & FB_VMODE_INTERLACED) 714 vtotal /= 2; 715 716 if (mode->vmode & FB_VMODE_DOUBLE) 717 vtotal *= 2; 718 719 hscan = (pixclock + htotal / 2) / htotal; 720 hscan = (hscan + 500) / 1000 * 1000; 721 hz = (hscan + vtotal / 2) / vtotal; 722 723 if (specs->dclkmax == 0 || specs->dclkmax < pixclock) 724 specs->dclkmax = pixclock; 725 726 if (specs->dclkmin == 0 || specs->dclkmin > pixclock) 727 specs->dclkmin = pixclock; 728 729 if (specs->hfmax == 0 || specs->hfmax < hscan) 730 specs->hfmax = hscan; 731 732 if (specs->hfmin == 0 || specs->hfmin > hscan) 733 specs->hfmin = hscan; 734 735 if (specs->vfmax == 0 || specs->vfmax < hz) 736 specs->vfmax = hz; 737 738 if (specs->vfmin == 0 || specs->vfmin > hz) 739 specs->vfmin = hz; 740 } 741 DPRINTK("Extrapolated\n"); 742 fb_destroy_modedb(modes); 743 } 744 DPRINTK(" H: %d-%dKHz V: %d-%dHz DCLK: %dMHz\n", 745 specs->hfmin/1000, specs->hfmax/1000, specs->vfmin, 746 specs->vfmax, specs->dclkmax/1000000); 747 return retval; 748} 749 750static void get_monspecs(unsigned char *edid, struct fb_monspecs *specs) 751{ 752 unsigned char c, *block; 753 754 block = edid + EDID_STRUCT_DISPLAY; 755 756 fb_get_monitor_limits(edid, specs); 757 758 c = block[0] & 0x80; 759 specs->input = 0; 760 if (c) { 761 specs->input |= FB_DISP_DDI; 762 DPRINTK(" Digital Display Input"); 763 } else { 764 DPRINTK(" Analog Display Input: Input Voltage - "); 765 switch ((block[0] & 0x60) >> 5) { 766 case 0: 767 DPRINTK("0.700V/0.300V"); 768 specs->input |= FB_DISP_ANA_700_300; 769 break; 770 case 1: 771 DPRINTK("0.714V/0.286V"); 772 specs->input |= FB_DISP_ANA_714_286; 773 break; 774 case 2: 775 DPRINTK("1.000V/0.400V"); 776 specs->input |= FB_DISP_ANA_1000_400; 777 break; 778 case 3: 779 DPRINTK("0.700V/0.000V"); 780 specs->input |= FB_DISP_ANA_700_000; 781 break; 782 } 783 } 784 DPRINTK("\n Sync: "); 785 c = block[0] & 0x10; 786 if (c) 787 DPRINTK(" Configurable signal level\n"); 788 c = block[0] & 0x0f; 789 specs->signal = 0; 790 if (c & 0x10) { 791 DPRINTK("Blank to Blank "); 792 specs->signal |= FB_SIGNAL_BLANK_BLANK; 793 } 794 if (c & 0x08) { 795 DPRINTK("Separate "); 796 specs->signal |= FB_SIGNAL_SEPARATE; 797 } 798 if (c & 0x04) { 799 DPRINTK("Composite "); 800 specs->signal |= FB_SIGNAL_COMPOSITE; 801 } 802 if (c & 0x02) { 803 DPRINTK("Sync on Green "); 804 specs->signal |= FB_SIGNAL_SYNC_ON_GREEN; 805 } 806 if (c & 0x01) { 807 DPRINTK("Serration on "); 808 specs->signal |= FB_SIGNAL_SERRATION_ON; 809 } 810 DPRINTK("\n"); 811 specs->max_x = block[1]; 812 specs->max_y = block[2]; 813 DPRINTK(" Max H-size in cm: "); 814 if (specs->max_x) 815 DPRINTK("%d\n", specs->max_x); 816 else 817 DPRINTK("variable\n"); 818 DPRINTK(" Max V-size in cm: "); 819 if (specs->max_y) 820 DPRINTK("%d\n", specs->max_y); 821 else 822 DPRINTK("variable\n"); 823 824 c = block[3]; 825 specs->gamma = c+100; 826 DPRINTK(" Gamma: "); 827 DPRINTK("%d.%d\n", specs->gamma/100, specs->gamma % 100); 828 829 get_dpms_capabilities(block[4], specs); 830 831 switch ((block[4] & 0x18) >> 3) { 832 case 0: 833 DPRINTK(" Monochrome/Grayscale\n"); 834 specs->input |= FB_DISP_MONO; 835 break; 836 case 1: 837 DPRINTK(" RGB Color Display\n"); 838 specs->input |= FB_DISP_RGB; 839 break; 840 case 2: 841 DPRINTK(" Non-RGB Multicolor Display\n"); 842 specs->input |= FB_DISP_MULTI; 843 break; 844 default: 845 DPRINTK(" Unknown\n"); 846 specs->input |= FB_DISP_UNKNOWN; 847 break; 848 } 849 850 get_chroma(block, specs); 851 852 specs->misc = 0; 853 c = block[4] & 0x7; 854 if (c & 0x04) { 855 DPRINTK(" Default color format is primary\n"); 856 specs->misc |= FB_MISC_PRIM_COLOR; 857 } 858 if (c & 0x02) { 859 DPRINTK(" First DETAILED Timing is preferred\n"); 860 specs->misc |= FB_MISC_1ST_DETAIL; 861 } 862 if (c & 0x01) { 863 printk(" Display is GTF capable\n"); 864 specs->gtf = 1; 865 } 866} 867 868int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var) 869{ 870 int i; 871 unsigned char *block; 872 873 if (edid == NULL || var == NULL) 874 return 1; 875 876 if (!(edid_checksum(edid))) 877 return 1; 878 879 if (!(edid_check_header(edid))) 880 return 1; 881 882 block = edid + DETAILED_TIMING_DESCRIPTIONS_START; 883 884 for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) { 885 if (edid_is_timing_block(block)) { 886 var->xres = var->xres_virtual = H_ACTIVE; 887 var->yres = var->yres_virtual = V_ACTIVE; 888 var->height = var->width = 0; 889 var->right_margin = H_SYNC_OFFSET; 890 var->left_margin = (H_ACTIVE + H_BLANKING) - 891 (H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH); 892 var->upper_margin = V_BLANKING - V_SYNC_OFFSET - 893 V_SYNC_WIDTH; 894 var->lower_margin = V_SYNC_OFFSET; 895 var->hsync_len = H_SYNC_WIDTH; 896 var->vsync_len = V_SYNC_WIDTH; 897 var->pixclock = PIXEL_CLOCK; 898 var->pixclock /= 1000; 899 var->pixclock = KHZ2PICOS(var->pixclock); 900 901 if (HSYNC_POSITIVE) 902 var->sync |= FB_SYNC_HOR_HIGH_ACT; 903 if (VSYNC_POSITIVE) 904 var->sync |= FB_SYNC_VERT_HIGH_ACT; 905 return 0; 906 } 907 } 908 return 1; 909} 910 911void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs) 912{ 913 unsigned char *block; 914 int i, found = 0; 915 916 if (edid == NULL) 917 return; 918 919 if (!(edid_checksum(edid))) 920 return; 921 922 if (!(edid_check_header(edid))) 923 return; 924 925 memset(specs, 0, sizeof(struct fb_monspecs)); 926 927 specs->version = edid[EDID_STRUCT_VERSION]; 928 specs->revision = edid[EDID_STRUCT_REVISION]; 929 930 DPRINTK("========================================\n"); 931 DPRINTK("Display Information (EDID)\n"); 932 DPRINTK("========================================\n"); 933 DPRINTK(" EDID Version %d.%d\n", (int) specs->version, 934 (int) specs->revision); 935 936 parse_vendor_block(edid + ID_MANUFACTURER_NAME, specs); 937 938 block = edid + DETAILED_TIMING_DESCRIPTIONS_START; 939 for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) { 940 if (edid_is_serial_block(block)) { 941 copy_string(block, specs->serial_no); 942 DPRINTK(" Serial Number: %s\n", specs->serial_no); 943 } else if (edid_is_ascii_block(block)) { 944 copy_string(block, specs->ascii); 945 DPRINTK(" ASCII Block: %s\n", specs->ascii); 946 } else if (edid_is_monitor_block(block)) { 947 copy_string(block, specs->monitor); 948 DPRINTK(" Monitor Name: %s\n", specs->monitor); 949 } 950 } 951 952 DPRINTK(" Display Characteristics:\n"); 953 get_monspecs(edid, specs); 954 955 specs->modedb = fb_create_modedb(edid, &specs->modedb_len); 956 957 /* 958 * Workaround for buggy EDIDs that sets that the first 959 * detailed timing is preferred but has not detailed 960 * timing specified 961 */ 962 for (i = 0; i < specs->modedb_len; i++) { 963 if (specs->modedb[i].flag & FB_MODE_IS_DETAILED) { 964 found = 1; 965 break; 966 } 967 } 968 969 if (!found) 970 specs->misc &= ~FB_MISC_1ST_DETAIL; 971 972 DPRINTK("========================================\n"); 973} 974 975/* 976 * VESA Generalized Timing Formula (GTF) 977 */ 978 979#define FLYBACK 550 980#define V_FRONTPORCH 1 981#define H_OFFSET 40 982#define H_SCALEFACTOR 20 983#define H_BLANKSCALE 128 984#define H_GRADIENT 600 985#define C_VAL 30 986#define M_VAL 300 987 988struct __fb_timings { 989 u32 dclk; 990 u32 hfreq; 991 u32 vfreq; 992 u32 hactive; 993 u32 vactive; 994 u32 hblank; 995 u32 vblank; 996 u32 htotal; 997 u32 vtotal; 998}; 999 1000/** 1001 * fb_get_vblank - get vertical blank time 1002 * @hfreq: horizontal freq 1003 * 1004 * DESCRIPTION: 1005 * vblank = right_margin + vsync_len + left_margin 1006 * 1007 * given: right_margin = 1 (V_FRONTPORCH) 1008 * vsync_len = 3 1009 * flyback = 550 1010 * 1011 * flyback * hfreq 1012 * left_margin = --------------- - vsync_len 1013 * 1000000 1014 */ 1015static u32 fb_get_vblank(u32 hfreq) 1016{ 1017 u32 vblank; 1018 1019 vblank = (hfreq * FLYBACK)/1000; 1020 vblank = (vblank + 500)/1000; 1021 return (vblank + V_FRONTPORCH); 1022} 1023 1024/** 1025 * fb_get_hblank_by_freq - get horizontal blank time given hfreq 1026 * @hfreq: horizontal freq 1027 * @xres: horizontal resolution in pixels 1028 * 1029 * DESCRIPTION: 1030 * 1031 * xres * duty_cycle 1032 * hblank = ------------------ 1033 * 100 - duty_cycle 1034 * 1035 * duty cycle = percent of htotal assigned to inactive display 1036 * duty cycle = C - (M/Hfreq) 1037 * 1038 * where: C = ((offset - scale factor) * blank_scale) 1039 * -------------------------------------- + scale factor 1040 * 256 1041 * M = blank_scale * gradient 1042 * 1043 */ 1044static u32 fb_get_hblank_by_hfreq(u32 hfreq, u32 xres) 1045{ 1046 u32 c_val, m_val, duty_cycle, hblank; 1047 1048 c_val = (((H_OFFSET - H_SCALEFACTOR) * H_BLANKSCALE)/256 + 1049 H_SCALEFACTOR) * 1000; 1050 m_val = (H_BLANKSCALE * H_GRADIENT)/256; 1051 m_val = (m_val * 1000000)/hfreq; 1052 duty_cycle = c_val - m_val; 1053 hblank = (xres * duty_cycle)/(100000 - duty_cycle); 1054 return (hblank); 1055} 1056 1057/** 1058 * fb_get_hblank_by_dclk - get horizontal blank time given pixelclock 1059 * @dclk: pixelclock in Hz 1060 * @xres: horizontal resolution in pixels 1061 * 1062 * DESCRIPTION: 1063 * 1064 * xres * duty_cycle 1065 * hblank = ------------------ 1066 * 100 - duty_cycle 1067 * 1068 * duty cycle = percent of htotal assigned to inactive display 1069 * duty cycle = C - (M * h_period) 1070 * 1071 * where: h_period = SQRT(100 - C + (0.4 * xres * M)/dclk) + C - 100 1072 * ----------------------------------------------- 1073 * 2 * M 1074 * M = 300; 1075 * C = 30; 1076 1077 */ 1078static u32 fb_get_hblank_by_dclk(u32 dclk, u32 xres) 1079{ 1080 u32 duty_cycle, h_period, hblank; 1081 1082 dclk /= 1000; 1083 h_period = 100 - C_VAL; 1084 h_period *= h_period; 1085 h_period += (M_VAL * xres * 2 * 1000)/(5 * dclk); 1086 h_period *= 10000; 1087 1088 h_period = int_sqrt(h_period); 1089 h_period -= (100 - C_VAL) * 100; 1090 h_period *= 1000; 1091 h_period /= 2 * M_VAL; 1092 1093 duty_cycle = C_VAL * 1000 - (M_VAL * h_period)/100; 1094 hblank = (xres * duty_cycle)/(100000 - duty_cycle) + 8; 1095 hblank &= ~15; 1096 return (hblank); 1097} 1098 1099/** 1100 * fb_get_hfreq - estimate hsync 1101 * @vfreq: vertical refresh rate 1102 * @yres: vertical resolution 1103 * 1104 * DESCRIPTION: 1105 * 1106 * (yres + front_port) * vfreq * 1000000 1107 * hfreq = ------------------------------------- 1108 * (1000000 - (vfreq * FLYBACK) 1109 * 1110 */ 1111 1112static u32 fb_get_hfreq(u32 vfreq, u32 yres) 1113{ 1114 u32 divisor, hfreq; 1115 1116 divisor = (1000000 - (vfreq * FLYBACK))/1000; 1117 hfreq = (yres + V_FRONTPORCH) * vfreq * 1000; 1118 return (hfreq/divisor); 1119} 1120 1121static void fb_timings_vfreq(struct __fb_timings *timings) 1122{ 1123 timings->hfreq = fb_get_hfreq(timings->vfreq, timings->vactive); 1124 timings->vblank = fb_get_vblank(timings->hfreq); 1125 timings->vtotal = timings->vactive + timings->vblank; 1126 timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq, 1127 timings->hactive); 1128 timings->htotal = timings->hactive + timings->hblank; 1129 timings->dclk = timings->htotal * timings->hfreq; 1130} 1131 1132static void fb_timings_hfreq(struct __fb_timings *timings) 1133{ 1134 timings->vblank = fb_get_vblank(timings->hfreq); 1135 timings->vtotal = timings->vactive + timings->vblank; 1136 timings->vfreq = timings->hfreq/timings->vtotal; 1137 timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq, 1138 timings->hactive); 1139 timings->htotal = timings->hactive + timings->hblank; 1140 timings->dclk = timings->htotal * timings->hfreq; 1141} 1142 1143static void fb_timings_dclk(struct __fb_timings *timings) 1144{ 1145 timings->hblank = fb_get_hblank_by_dclk(timings->dclk, 1146 timings->hactive); 1147 timings->htotal = timings->hactive + timings->hblank; 1148 timings->hfreq = timings->dclk/timings->htotal; 1149 timings->vblank = fb_get_vblank(timings->hfreq); 1150 timings->vtotal = timings->vactive + timings->vblank; 1151 timings->vfreq = timings->hfreq/timings->vtotal; 1152} 1153 1154/* 1155 * fb_get_mode - calculates video mode using VESA GTF 1156 * @flags: if: 0 - maximize vertical refresh rate 1157 * 1 - vrefresh-driven calculation; 1158 * 2 - hscan-driven calculation; 1159 * 3 - pixelclock-driven calculation; 1160 * @val: depending on @flags, ignored, vrefresh, hsync or pixelclock 1161 * @var: pointer to fb_var_screeninfo 1162 * @info: pointer to fb_info 1163 * 1164 * DESCRIPTION: 1165 * Calculates video mode based on monitor specs using VESA GTF. 1166 * The GTF is best for VESA GTF compliant monitors but is 1167 * specifically formulated to work for older monitors as well. 1168 * 1169 * If @flag==0, the function will attempt to maximize the 1170 * refresh rate. Otherwise, it will calculate timings based on 1171 * the flag and accompanying value. 1172 * 1173 * If FB_IGNOREMON bit is set in @flags, monitor specs will be 1174 * ignored and @var will be filled with the calculated timings. 1175 * 1176 * All calculations are based on the VESA GTF Spreadsheet 1177 * available at VESA's public ftp (http://www.vesa.org). 1178 * 1179 * NOTES: 1180 * The timings generated by the GTF will be different from VESA 1181 * DMT. It might be a good idea to keep a table of standard 1182 * VESA modes as well. The GTF may also not work for some displays, 1183 * such as, and especially, analog TV. 1184 * 1185 * REQUIRES: 1186 * A valid info->monspecs, otherwise 'safe numbers' will be used. 1187 */ 1188int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_info *info) 1189{ 1190 struct __fb_timings *timings; 1191 u32 interlace = 1, dscan = 1; 1192 u32 hfmin, hfmax, vfmin, vfmax, dclkmin, dclkmax, err = 0; 1193 1194 1195 timings = kzalloc(sizeof(struct __fb_timings), GFP_KERNEL); 1196 1197 if (!timings) 1198 return -ENOMEM; 1199 1200 /* 1201 * If monspecs are invalid, use values that are enough 1202 * for 640x480@60 1203 */ 1204 if (!info || !info->monspecs.hfmax || !info->monspecs.vfmax || 1205 !info->monspecs.dclkmax || 1206 info->monspecs.hfmax < info->monspecs.hfmin || 1207 info->monspecs.vfmax < info->monspecs.vfmin || 1208 info->monspecs.dclkmax < info->monspecs.dclkmin) { 1209 hfmin = 29000; hfmax = 30000; 1210 vfmin = 60; vfmax = 60; 1211 dclkmin = 0; dclkmax = 25000000; 1212 } else { 1213 hfmin = info->monspecs.hfmin; 1214 hfmax = info->monspecs.hfmax; 1215 vfmin = info->monspecs.vfmin; 1216 vfmax = info->monspecs.vfmax; 1217 dclkmin = info->monspecs.dclkmin; 1218 dclkmax = info->monspecs.dclkmax; 1219 } 1220 1221 timings->hactive = var->xres; 1222 timings->vactive = var->yres; 1223 if (var->vmode & FB_VMODE_INTERLACED) { 1224 timings->vactive /= 2; 1225 interlace = 2; 1226 } 1227 if (var->vmode & FB_VMODE_DOUBLE) { 1228 timings->vactive *= 2; 1229 dscan = 2; 1230 } 1231 1232 switch (flags & ~FB_IGNOREMON) { 1233 case FB_MAXTIMINGS: /* maximize refresh rate */ 1234 timings->hfreq = hfmax; 1235 fb_timings_hfreq(timings); 1236 if (timings->vfreq > vfmax) { 1237 timings->vfreq = vfmax; 1238 fb_timings_vfreq(timings); 1239 } 1240 if (timings->dclk > dclkmax) { 1241 timings->dclk = dclkmax; 1242 fb_timings_dclk(timings); 1243 } 1244 break; 1245 case FB_VSYNCTIMINGS: /* vrefresh driven */ 1246 timings->vfreq = val; 1247 fb_timings_vfreq(timings); 1248 break; 1249 case FB_HSYNCTIMINGS: /* hsync driven */ 1250 timings->hfreq = val; 1251 fb_timings_hfreq(timings); 1252 break; 1253 case FB_DCLKTIMINGS: /* pixelclock driven */ 1254 timings->dclk = PICOS2KHZ(val) * 1000; 1255 fb_timings_dclk(timings); 1256 break; 1257 default: 1258 err = -EINVAL; 1259 1260 } 1261 1262 if (err || (!(flags & FB_IGNOREMON) && 1263 (timings->vfreq < vfmin || timings->vfreq > vfmax || 1264 timings->hfreq < hfmin || timings->hfreq > hfmax || 1265 timings->dclk < dclkmin || timings->dclk > dclkmax))) { 1266 err = -EINVAL; 1267 } else { 1268 var->pixclock = KHZ2PICOS(timings->dclk/1000); 1269 var->hsync_len = (timings->htotal * 8)/100; 1270 var->right_margin = (timings->hblank/2) - var->hsync_len; 1271 var->left_margin = timings->hblank - var->right_margin - 1272 var->hsync_len; 1273 var->vsync_len = (3 * interlace)/dscan; 1274 var->lower_margin = (1 * interlace)/dscan; 1275 var->upper_margin = (timings->vblank * interlace)/dscan - 1276 (var->vsync_len + var->lower_margin); 1277 } 1278 1279 kfree(timings); 1280 return err; 1281} 1282#else 1283int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var) 1284{ 1285 return 1; 1286} 1287void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs) 1288{ 1289 specs = NULL; 1290} 1291void fb_destroy_modedb(struct fb_videomode *modedb) 1292{ 1293} 1294int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, 1295 struct fb_info *info) 1296{ 1297 return -EINVAL; 1298} 1299#endif /* CONFIG_FB_MODE_HELPERS */ 1300 1301/* 1302 * fb_validate_mode - validates var against monitor capabilities 1303 * @var: pointer to fb_var_screeninfo 1304 * @info: pointer to fb_info 1305 * 1306 * DESCRIPTION: 1307 * Validates video mode against monitor capabilities specified in 1308 * info->monspecs. 1309 * 1310 * REQUIRES: 1311 * A valid info->monspecs. 1312 */ 1313int fb_validate_mode(const struct fb_var_screeninfo *var, struct fb_info *info) 1314{ 1315 u32 hfreq, vfreq, htotal, vtotal, pixclock; 1316 u32 hfmin, hfmax, vfmin, vfmax, dclkmin, dclkmax; 1317 1318 /* 1319 * If monspecs are invalid, use values that are enough 1320 * for 640x480@60 1321 */ 1322 if (!info->monspecs.hfmax || !info->monspecs.vfmax || 1323 !info->monspecs.dclkmax || 1324 info->monspecs.hfmax < info->monspecs.hfmin || 1325 info->monspecs.vfmax < info->monspecs.vfmin || 1326 info->monspecs.dclkmax < info->monspecs.dclkmin) { 1327 hfmin = 29000; hfmax = 30000; 1328 vfmin = 60; vfmax = 60; 1329 dclkmin = 0; dclkmax = 25000000; 1330 } else { 1331 hfmin = info->monspecs.hfmin; 1332 hfmax = info->monspecs.hfmax; 1333 vfmin = info->monspecs.vfmin; 1334 vfmax = info->monspecs.vfmax; 1335 dclkmin = info->monspecs.dclkmin; 1336 dclkmax = info->monspecs.dclkmax; 1337 } 1338 1339 if (!var->pixclock) 1340 return -EINVAL; 1341 pixclock = PICOS2KHZ(var->pixclock) * 1000; 1342 1343 htotal = var->xres + var->right_margin + var->hsync_len + 1344 var->left_margin; 1345 vtotal = var->yres + var->lower_margin + var->vsync_len + 1346 var->upper_margin; 1347 1348 if (var->vmode & FB_VMODE_INTERLACED) 1349 vtotal /= 2; 1350 if (var->vmode & FB_VMODE_DOUBLE) 1351 vtotal *= 2; 1352 1353 hfreq = pixclock/htotal; 1354 hfreq = (hfreq + 500) / 1000 * 1000; 1355 1356 vfreq = hfreq/vtotal; 1357 1358 return (vfreq < vfmin || vfreq > vfmax || 1359 hfreq < hfmin || hfreq > hfmax || 1360 pixclock < dclkmin || pixclock > dclkmax) ? 1361 -EINVAL : 0; 1362} 1363 1364#if defined(CONFIG_FIRMWARE_EDID) && defined(CONFIG_X86) 1365 1366/* 1367 * We need to ensure that the EDID block is only returned for 1368 * the primary graphics adapter. 1369 */ 1370 1371const unsigned char *fb_firmware_edid(struct device *device) 1372{ 1373 struct pci_dev *dev = NULL; 1374 struct resource *res = NULL; 1375 unsigned char *edid = NULL; 1376 1377 if (device) 1378 dev = to_pci_dev(device); 1379 1380 if (dev) 1381 res = &dev->resource[PCI_ROM_RESOURCE]; 1382 1383 if (res && res->flags & IORESOURCE_ROM_SHADOW) 1384 edid = edid_info.dummy; 1385 1386 return edid; 1387} 1388#else 1389const unsigned char *fb_firmware_edid(struct device *device) 1390{ 1391 return NULL; 1392} 1393#endif 1394EXPORT_SYMBOL(fb_firmware_edid); 1395 1396EXPORT_SYMBOL(fb_parse_edid); 1397EXPORT_SYMBOL(fb_edid_to_monspecs); 1398EXPORT_SYMBOL(fb_get_mode); 1399EXPORT_SYMBOL(fb_validate_mode); 1400EXPORT_SYMBOL(fb_destroy_modedb);