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 mode->vmode = 0; 568 mode->flag = FB_MODE_IS_DETAILED; 569 570 DPRINTK(" %d MHz ", PIXEL_CLOCK/1000000); 571 DPRINTK("%d %d %d %d ", H_ACTIVE, H_ACTIVE + H_SYNC_OFFSET, 572 H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH, H_ACTIVE + H_BLANKING); 573 DPRINTK("%d %d %d %d ", V_ACTIVE, V_ACTIVE + V_SYNC_OFFSET, 574 V_ACTIVE + V_SYNC_OFFSET + V_SYNC_WIDTH, V_ACTIVE + V_BLANKING); 575 DPRINTK("%sHSync %sVSync\n\n", (HSYNC_POSITIVE) ? "+" : "-", 576 (VSYNC_POSITIVE) ? "+" : "-"); 577} 578 579/** 580 * fb_create_modedb - create video mode database 581 * @edid: EDID data 582 * @dbsize: database size 583 * 584 * RETURNS: struct fb_videomode, @dbsize contains length of database 585 * 586 * DESCRIPTION: 587 * This function builds a mode database using the contents of the EDID 588 * data 589 */ 590static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize) 591{ 592 struct fb_videomode *mode, *m; 593 unsigned char *block; 594 int num = 0, i; 595 596 mode = kzalloc(50 * sizeof(struct fb_videomode), GFP_KERNEL); 597 if (mode == NULL) 598 return NULL; 599 600 if (edid == NULL || !edid_checksum(edid) || 601 !edid_check_header(edid)) { 602 kfree(mode); 603 return NULL; 604 } 605 606 *dbsize = 0; 607 608 DPRINTK(" Detailed Timings\n"); 609 block = edid + DETAILED_TIMING_DESCRIPTIONS_START; 610 for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) { 611 int first = 1; 612 613 if (!(block[0] == 0x00 && block[1] == 0x00)) { 614 get_detailed_timing(block, &mode[num]); 615 if (first) { 616 mode[num].flag |= FB_MODE_IS_FIRST; 617 first = 0; 618 } 619 num++; 620 } 621 } 622 623 DPRINTK(" Supported VESA Modes\n"); 624 block = edid + ESTABLISHED_TIMING_1; 625 num += get_est_timing(block, &mode[num]); 626 627 DPRINTK(" Standard Timings\n"); 628 block = edid + STD_TIMING_DESCRIPTIONS_START; 629 for (i = 0; i < STD_TIMING; i++, block += STD_TIMING_DESCRIPTION_SIZE) 630 num += get_std_timing(block, &mode[num]); 631 632 block = edid + DETAILED_TIMING_DESCRIPTIONS_START; 633 for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) { 634 if (block[0] == 0x00 && block[1] == 0x00 && block[3] == 0xfa) 635 num += get_dst_timing(block + 5, &mode[num]); 636 } 637 638 /* Yikes, EDID data is totally useless */ 639 if (!num) { 640 kfree(mode); 641 return NULL; 642 } 643 644 *dbsize = num; 645 m = kmalloc(num * sizeof(struct fb_videomode), GFP_KERNEL); 646 if (!m) 647 return mode; 648 memmove(m, mode, num * sizeof(struct fb_videomode)); 649 kfree(mode); 650 return m; 651} 652 653/** 654 * fb_destroy_modedb - destroys mode database 655 * @modedb: mode database to destroy 656 * 657 * DESCRIPTION: 658 * Destroy mode database created by fb_create_modedb 659 */ 660void fb_destroy_modedb(struct fb_videomode *modedb) 661{ 662 kfree(modedb); 663} 664 665static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs) 666{ 667 int i, retval = 1; 668 unsigned char *block; 669 670 block = edid + DETAILED_TIMING_DESCRIPTIONS_START; 671 672 DPRINTK(" Monitor Operating Limits: "); 673 674 for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) { 675 if (edid_is_limits_block(block)) { 676 specs->hfmin = H_MIN_RATE * 1000; 677 specs->hfmax = H_MAX_RATE * 1000; 678 specs->vfmin = V_MIN_RATE; 679 specs->vfmax = V_MAX_RATE; 680 specs->dclkmax = MAX_PIXEL_CLOCK * 1000000; 681 specs->gtf = (GTF_SUPPORT) ? 1 : 0; 682 retval = 0; 683 DPRINTK("From EDID\n"); 684 break; 685 } 686 } 687 688 /* estimate monitor limits based on modes supported */ 689 if (retval) { 690 struct fb_videomode *modes, *mode; 691 int num_modes, i, hz, hscan, pixclock; 692 int vtotal, htotal; 693 694 modes = fb_create_modedb(edid, &num_modes); 695 if (!modes) { 696 DPRINTK("None Available\n"); 697 return 1; 698 } 699 700 retval = 0; 701 for (i = 0; i < num_modes; i++) { 702 mode = &modes[i]; 703 pixclock = PICOS2KHZ(modes[i].pixclock) * 1000; 704 htotal = mode->xres + mode->right_margin + mode->hsync_len 705 + mode->left_margin; 706 vtotal = mode->yres + mode->lower_margin + mode->vsync_len 707 + mode->upper_margin; 708 709 if (mode->vmode & FB_VMODE_INTERLACED) 710 vtotal /= 2; 711 712 if (mode->vmode & FB_VMODE_DOUBLE) 713 vtotal *= 2; 714 715 hscan = (pixclock + htotal / 2) / htotal; 716 hscan = (hscan + 500) / 1000 * 1000; 717 hz = (hscan + vtotal / 2) / vtotal; 718 719 if (specs->dclkmax == 0 || specs->dclkmax < pixclock) 720 specs->dclkmax = pixclock; 721 722 if (specs->dclkmin == 0 || specs->dclkmin > pixclock) 723 specs->dclkmin = pixclock; 724 725 if (specs->hfmax == 0 || specs->hfmax < hscan) 726 specs->hfmax = hscan; 727 728 if (specs->hfmin == 0 || specs->hfmin > hscan) 729 specs->hfmin = hscan; 730 731 if (specs->vfmax == 0 || specs->vfmax < hz) 732 specs->vfmax = hz; 733 734 if (specs->vfmin == 0 || specs->vfmin > hz) 735 specs->vfmin = hz; 736 } 737 DPRINTK("Extrapolated\n"); 738 fb_destroy_modedb(modes); 739 } 740 DPRINTK(" H: %d-%dKHz V: %d-%dHz DCLK: %dMHz\n", 741 specs->hfmin/1000, specs->hfmax/1000, specs->vfmin, 742 specs->vfmax, specs->dclkmax/1000000); 743 return retval; 744} 745 746static void get_monspecs(unsigned char *edid, struct fb_monspecs *specs) 747{ 748 unsigned char c, *block; 749 750 block = edid + EDID_STRUCT_DISPLAY; 751 752 fb_get_monitor_limits(edid, specs); 753 754 c = block[0] & 0x80; 755 specs->input = 0; 756 if (c) { 757 specs->input |= FB_DISP_DDI; 758 DPRINTK(" Digital Display Input"); 759 } else { 760 DPRINTK(" Analog Display Input: Input Voltage - "); 761 switch ((block[0] & 0x60) >> 5) { 762 case 0: 763 DPRINTK("0.700V/0.300V"); 764 specs->input |= FB_DISP_ANA_700_300; 765 break; 766 case 1: 767 DPRINTK("0.714V/0.286V"); 768 specs->input |= FB_DISP_ANA_714_286; 769 break; 770 case 2: 771 DPRINTK("1.000V/0.400V"); 772 specs->input |= FB_DISP_ANA_1000_400; 773 break; 774 case 3: 775 DPRINTK("0.700V/0.000V"); 776 specs->input |= FB_DISP_ANA_700_000; 777 break; 778 } 779 } 780 DPRINTK("\n Sync: "); 781 c = block[0] & 0x10; 782 if (c) 783 DPRINTK(" Configurable signal level\n"); 784 c = block[0] & 0x0f; 785 specs->signal = 0; 786 if (c & 0x10) { 787 DPRINTK("Blank to Blank "); 788 specs->signal |= FB_SIGNAL_BLANK_BLANK; 789 } 790 if (c & 0x08) { 791 DPRINTK("Separate "); 792 specs->signal |= FB_SIGNAL_SEPARATE; 793 } 794 if (c & 0x04) { 795 DPRINTK("Composite "); 796 specs->signal |= FB_SIGNAL_COMPOSITE; 797 } 798 if (c & 0x02) { 799 DPRINTK("Sync on Green "); 800 specs->signal |= FB_SIGNAL_SYNC_ON_GREEN; 801 } 802 if (c & 0x01) { 803 DPRINTK("Serration on "); 804 specs->signal |= FB_SIGNAL_SERRATION_ON; 805 } 806 DPRINTK("\n"); 807 specs->max_x = block[1]; 808 specs->max_y = block[2]; 809 DPRINTK(" Max H-size in cm: "); 810 if (specs->max_x) 811 DPRINTK("%d\n", specs->max_x); 812 else 813 DPRINTK("variable\n"); 814 DPRINTK(" Max V-size in cm: "); 815 if (specs->max_y) 816 DPRINTK("%d\n", specs->max_y); 817 else 818 DPRINTK("variable\n"); 819 820 c = block[3]; 821 specs->gamma = c+100; 822 DPRINTK(" Gamma: "); 823 DPRINTK("%d.%d\n", specs->gamma/100, specs->gamma % 100); 824 825 get_dpms_capabilities(block[4], specs); 826 827 switch ((block[4] & 0x18) >> 3) { 828 case 0: 829 DPRINTK(" Monochrome/Grayscale\n"); 830 specs->input |= FB_DISP_MONO; 831 break; 832 case 1: 833 DPRINTK(" RGB Color Display\n"); 834 specs->input |= FB_DISP_RGB; 835 break; 836 case 2: 837 DPRINTK(" Non-RGB Multicolor Display\n"); 838 specs->input |= FB_DISP_MULTI; 839 break; 840 default: 841 DPRINTK(" Unknown\n"); 842 specs->input |= FB_DISP_UNKNOWN; 843 break; 844 } 845 846 get_chroma(block, specs); 847 848 specs->misc = 0; 849 c = block[4] & 0x7; 850 if (c & 0x04) { 851 DPRINTK(" Default color format is primary\n"); 852 specs->misc |= FB_MISC_PRIM_COLOR; 853 } 854 if (c & 0x02) { 855 DPRINTK(" First DETAILED Timing is preferred\n"); 856 specs->misc |= FB_MISC_1ST_DETAIL; 857 } 858 if (c & 0x01) { 859 printk(" Display is GTF capable\n"); 860 specs->gtf = 1; 861 } 862} 863 864int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var) 865{ 866 int i; 867 unsigned char *block; 868 869 if (edid == NULL || var == NULL) 870 return 1; 871 872 if (!(edid_checksum(edid))) 873 return 1; 874 875 if (!(edid_check_header(edid))) 876 return 1; 877 878 block = edid + DETAILED_TIMING_DESCRIPTIONS_START; 879 880 for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) { 881 if (edid_is_timing_block(block)) { 882 var->xres = var->xres_virtual = H_ACTIVE; 883 var->yres = var->yres_virtual = V_ACTIVE; 884 var->height = var->width = -1; 885 var->right_margin = H_SYNC_OFFSET; 886 var->left_margin = (H_ACTIVE + H_BLANKING) - 887 (H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH); 888 var->upper_margin = V_BLANKING - V_SYNC_OFFSET - 889 V_SYNC_WIDTH; 890 var->lower_margin = V_SYNC_OFFSET; 891 var->hsync_len = H_SYNC_WIDTH; 892 var->vsync_len = V_SYNC_WIDTH; 893 var->pixclock = PIXEL_CLOCK; 894 var->pixclock /= 1000; 895 var->pixclock = KHZ2PICOS(var->pixclock); 896 897 if (HSYNC_POSITIVE) 898 var->sync |= FB_SYNC_HOR_HIGH_ACT; 899 if (VSYNC_POSITIVE) 900 var->sync |= FB_SYNC_VERT_HIGH_ACT; 901 return 0; 902 } 903 } 904 return 1; 905} 906 907void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs) 908{ 909 unsigned char *block; 910 int i, found = 0; 911 912 if (edid == NULL) 913 return; 914 915 if (!(edid_checksum(edid))) 916 return; 917 918 if (!(edid_check_header(edid))) 919 return; 920 921 memset(specs, 0, sizeof(struct fb_monspecs)); 922 923 specs->version = edid[EDID_STRUCT_VERSION]; 924 specs->revision = edid[EDID_STRUCT_REVISION]; 925 926 DPRINTK("========================================\n"); 927 DPRINTK("Display Information (EDID)\n"); 928 DPRINTK("========================================\n"); 929 DPRINTK(" EDID Version %d.%d\n", (int) specs->version, 930 (int) specs->revision); 931 932 parse_vendor_block(edid + ID_MANUFACTURER_NAME, specs); 933 934 block = edid + DETAILED_TIMING_DESCRIPTIONS_START; 935 for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) { 936 if (edid_is_serial_block(block)) { 937 copy_string(block, specs->serial_no); 938 DPRINTK(" Serial Number: %s\n", specs->serial_no); 939 } else if (edid_is_ascii_block(block)) { 940 copy_string(block, specs->ascii); 941 DPRINTK(" ASCII Block: %s\n", specs->ascii); 942 } else if (edid_is_monitor_block(block)) { 943 copy_string(block, specs->monitor); 944 DPRINTK(" Monitor Name: %s\n", specs->monitor); 945 } 946 } 947 948 DPRINTK(" Display Characteristics:\n"); 949 get_monspecs(edid, specs); 950 951 specs->modedb = fb_create_modedb(edid, &specs->modedb_len); 952 953 for (i = 0; i < specs->modedb_len; i++) { 954 if (specs->modedb[i].flag & FB_MODE_IS_DETAILED) { 955 found = 1; 956 break; 957 } 958 } 959 960 if (!found) 961 specs->misc &= ~FB_MISC_1ST_DETAIL; 962 963 DPRINTK("========================================\n"); 964} 965 966/* 967 * VESA Generalized Timing Formula (GTF) 968 */ 969 970#define FLYBACK 550 971#define V_FRONTPORCH 1 972#define H_OFFSET 40 973#define H_SCALEFACTOR 20 974#define H_BLANKSCALE 128 975#define H_GRADIENT 600 976#define C_VAL 30 977#define M_VAL 300 978 979struct __fb_timings { 980 u32 dclk; 981 u32 hfreq; 982 u32 vfreq; 983 u32 hactive; 984 u32 vactive; 985 u32 hblank; 986 u32 vblank; 987 u32 htotal; 988 u32 vtotal; 989}; 990 991/** 992 * fb_get_vblank - get vertical blank time 993 * @hfreq: horizontal freq 994 * 995 * DESCRIPTION: 996 * vblank = right_margin + vsync_len + left_margin 997 * 998 * given: right_margin = 1 (V_FRONTPORCH) 999 * vsync_len = 3 1000 * flyback = 550 1001 * 1002 * flyback * hfreq 1003 * left_margin = --------------- - vsync_len 1004 * 1000000 1005 */ 1006static u32 fb_get_vblank(u32 hfreq) 1007{ 1008 u32 vblank; 1009 1010 vblank = (hfreq * FLYBACK)/1000; 1011 vblank = (vblank + 500)/1000; 1012 return (vblank + V_FRONTPORCH); 1013} 1014 1015/** 1016 * fb_get_hblank_by_freq - get horizontal blank time given hfreq 1017 * @hfreq: horizontal freq 1018 * @xres: horizontal resolution in pixels 1019 * 1020 * DESCRIPTION: 1021 * 1022 * xres * duty_cycle 1023 * hblank = ------------------ 1024 * 100 - duty_cycle 1025 * 1026 * duty cycle = percent of htotal assigned to inactive display 1027 * duty cycle = C - (M/Hfreq) 1028 * 1029 * where: C = ((offset - scale factor) * blank_scale) 1030 * -------------------------------------- + scale factor 1031 * 256 1032 * M = blank_scale * gradient 1033 * 1034 */ 1035static u32 fb_get_hblank_by_hfreq(u32 hfreq, u32 xres) 1036{ 1037 u32 c_val, m_val, duty_cycle, hblank; 1038 1039 c_val = (((H_OFFSET - H_SCALEFACTOR) * H_BLANKSCALE)/256 + 1040 H_SCALEFACTOR) * 1000; 1041 m_val = (H_BLANKSCALE * H_GRADIENT)/256; 1042 m_val = (m_val * 1000000)/hfreq; 1043 duty_cycle = c_val - m_val; 1044 hblank = (xres * duty_cycle)/(100000 - duty_cycle); 1045 return (hblank); 1046} 1047 1048/** 1049 * fb_get_hblank_by_dclk - get horizontal blank time given pixelclock 1050 * @dclk: pixelclock in Hz 1051 * @xres: horizontal resolution in pixels 1052 * 1053 * DESCRIPTION: 1054 * 1055 * xres * duty_cycle 1056 * hblank = ------------------ 1057 * 100 - duty_cycle 1058 * 1059 * duty cycle = percent of htotal assigned to inactive display 1060 * duty cycle = C - (M * h_period) 1061 * 1062 * where: h_period = SQRT(100 - C + (0.4 * xres * M)/dclk) + C - 100 1063 * ----------------------------------------------- 1064 * 2 * M 1065 * M = 300; 1066 * C = 30; 1067 1068 */ 1069static u32 fb_get_hblank_by_dclk(u32 dclk, u32 xres) 1070{ 1071 u32 duty_cycle, h_period, hblank; 1072 1073 dclk /= 1000; 1074 h_period = 100 - C_VAL; 1075 h_period *= h_period; 1076 h_period += (M_VAL * xres * 2 * 1000)/(5 * dclk); 1077 h_period *=10000; 1078 1079 h_period = int_sqrt(h_period); 1080 h_period -= (100 - C_VAL) * 100; 1081 h_period *= 1000; 1082 h_period /= 2 * M_VAL; 1083 1084 duty_cycle = C_VAL * 1000 - (M_VAL * h_period)/100; 1085 hblank = (xres * duty_cycle)/(100000 - duty_cycle) + 8; 1086 hblank &= ~15; 1087 return (hblank); 1088} 1089 1090/** 1091 * fb_get_hfreq - estimate hsync 1092 * @vfreq: vertical refresh rate 1093 * @yres: vertical resolution 1094 * 1095 * DESCRIPTION: 1096 * 1097 * (yres + front_port) * vfreq * 1000000 1098 * hfreq = ------------------------------------- 1099 * (1000000 - (vfreq * FLYBACK) 1100 * 1101 */ 1102 1103static u32 fb_get_hfreq(u32 vfreq, u32 yres) 1104{ 1105 u32 divisor, hfreq; 1106 1107 divisor = (1000000 - (vfreq * FLYBACK))/1000; 1108 hfreq = (yres + V_FRONTPORCH) * vfreq * 1000; 1109 return (hfreq/divisor); 1110} 1111 1112static void fb_timings_vfreq(struct __fb_timings *timings) 1113{ 1114 timings->hfreq = fb_get_hfreq(timings->vfreq, timings->vactive); 1115 timings->vblank = fb_get_vblank(timings->hfreq); 1116 timings->vtotal = timings->vactive + timings->vblank; 1117 timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq, 1118 timings->hactive); 1119 timings->htotal = timings->hactive + timings->hblank; 1120 timings->dclk = timings->htotal * timings->hfreq; 1121} 1122 1123static void fb_timings_hfreq(struct __fb_timings *timings) 1124{ 1125 timings->vblank = fb_get_vblank(timings->hfreq); 1126 timings->vtotal = timings->vactive + timings->vblank; 1127 timings->vfreq = timings->hfreq/timings->vtotal; 1128 timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq, 1129 timings->hactive); 1130 timings->htotal = timings->hactive + timings->hblank; 1131 timings->dclk = timings->htotal * timings->hfreq; 1132} 1133 1134static void fb_timings_dclk(struct __fb_timings *timings) 1135{ 1136 timings->hblank = fb_get_hblank_by_dclk(timings->dclk, 1137 timings->hactive); 1138 timings->htotal = timings->hactive + timings->hblank; 1139 timings->hfreq = timings->dclk/timings->htotal; 1140 timings->vblank = fb_get_vblank(timings->hfreq); 1141 timings->vtotal = timings->vactive + timings->vblank; 1142 timings->vfreq = timings->hfreq/timings->vtotal; 1143} 1144 1145/* 1146 * fb_get_mode - calculates video mode using VESA GTF 1147 * @flags: if: 0 - maximize vertical refresh rate 1148 * 1 - vrefresh-driven calculation; 1149 * 2 - hscan-driven calculation; 1150 * 3 - pixelclock-driven calculation; 1151 * @val: depending on @flags, ignored, vrefresh, hsync or pixelclock 1152 * @var: pointer to fb_var_screeninfo 1153 * @info: pointer to fb_info 1154 * 1155 * DESCRIPTION: 1156 * Calculates video mode based on monitor specs using VESA GTF. 1157 * The GTF is best for VESA GTF compliant monitors but is 1158 * specifically formulated to work for older monitors as well. 1159 * 1160 * If @flag==0, the function will attempt to maximize the 1161 * refresh rate. Otherwise, it will calculate timings based on 1162 * the flag and accompanying value. 1163 * 1164 * If FB_IGNOREMON bit is set in @flags, monitor specs will be 1165 * ignored and @var will be filled with the calculated timings. 1166 * 1167 * All calculations are based on the VESA GTF Spreadsheet 1168 * available at VESA's public ftp (http://www.vesa.org). 1169 * 1170 * NOTES: 1171 * The timings generated by the GTF will be different from VESA 1172 * DMT. It might be a good idea to keep a table of standard 1173 * VESA modes as well. The GTF may also not work for some displays, 1174 * such as, and especially, analog TV. 1175 * 1176 * REQUIRES: 1177 * A valid info->monspecs, otherwise 'safe numbers' will be used. 1178 */ 1179int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_info *info) 1180{ 1181 struct __fb_timings *timings; 1182 u32 interlace = 1, dscan = 1; 1183 u32 hfmin, hfmax, vfmin, vfmax, dclkmin, dclkmax, err = 0; 1184 1185 1186 timings = kzalloc(sizeof(struct __fb_timings), GFP_KERNEL); 1187 1188 if (!timings) 1189 return -ENOMEM; 1190 1191 /* 1192 * If monspecs are invalid, use values that are enough 1193 * for 640x480@60 1194 */ 1195 if (!info || !info->monspecs.hfmax || !info->monspecs.vfmax || 1196 !info->monspecs.dclkmax || 1197 info->monspecs.hfmax < info->monspecs.hfmin || 1198 info->monspecs.vfmax < info->monspecs.vfmin || 1199 info->monspecs.dclkmax < info->monspecs.dclkmin) { 1200 hfmin = 29000; hfmax = 30000; 1201 vfmin = 60; vfmax = 60; 1202 dclkmin = 0; dclkmax = 25000000; 1203 } else { 1204 hfmin = info->monspecs.hfmin; 1205 hfmax = info->monspecs.hfmax; 1206 vfmin = info->monspecs.vfmin; 1207 vfmax = info->monspecs.vfmax; 1208 dclkmin = info->monspecs.dclkmin; 1209 dclkmax = info->monspecs.dclkmax; 1210 } 1211 1212 timings->hactive = var->xres; 1213 timings->vactive = var->yres; 1214 if (var->vmode & FB_VMODE_INTERLACED) { 1215 timings->vactive /= 2; 1216 interlace = 2; 1217 } 1218 if (var->vmode & FB_VMODE_DOUBLE) { 1219 timings->vactive *= 2; 1220 dscan = 2; 1221 } 1222 1223 switch (flags & ~FB_IGNOREMON) { 1224 case FB_MAXTIMINGS: /* maximize refresh rate */ 1225 timings->hfreq = hfmax; 1226 fb_timings_hfreq(timings); 1227 if (timings->vfreq > vfmax) { 1228 timings->vfreq = vfmax; 1229 fb_timings_vfreq(timings); 1230 } 1231 if (timings->dclk > dclkmax) { 1232 timings->dclk = dclkmax; 1233 fb_timings_dclk(timings); 1234 } 1235 break; 1236 case FB_VSYNCTIMINGS: /* vrefresh driven */ 1237 timings->vfreq = val; 1238 fb_timings_vfreq(timings); 1239 break; 1240 case FB_HSYNCTIMINGS: /* hsync driven */ 1241 timings->hfreq = val; 1242 fb_timings_hfreq(timings); 1243 break; 1244 case FB_DCLKTIMINGS: /* pixelclock driven */ 1245 timings->dclk = PICOS2KHZ(val) * 1000; 1246 fb_timings_dclk(timings); 1247 break; 1248 default: 1249 err = -EINVAL; 1250 1251 } 1252 1253 if (err || (!(flags & FB_IGNOREMON) && 1254 (timings->vfreq < vfmin || timings->vfreq > vfmax || 1255 timings->hfreq < hfmin || timings->hfreq > hfmax || 1256 timings->dclk < dclkmin || timings->dclk > dclkmax))) { 1257 err = -EINVAL; 1258 } else { 1259 var->pixclock = KHZ2PICOS(timings->dclk/1000); 1260 var->hsync_len = (timings->htotal * 8)/100; 1261 var->right_margin = (timings->hblank/2) - var->hsync_len; 1262 var->left_margin = timings->hblank - var->right_margin - 1263 var->hsync_len; 1264 var->vsync_len = (3 * interlace)/dscan; 1265 var->lower_margin = (1 * interlace)/dscan; 1266 var->upper_margin = (timings->vblank * interlace)/dscan - 1267 (var->vsync_len + var->lower_margin); 1268 } 1269 1270 kfree(timings); 1271 return err; 1272} 1273#else 1274int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var) 1275{ 1276 return 1; 1277} 1278void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs) 1279{ 1280 specs = NULL; 1281} 1282void fb_destroy_modedb(struct fb_videomode *modedb) 1283{ 1284} 1285int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, 1286 struct fb_info *info) 1287{ 1288 return -EINVAL; 1289} 1290#endif /* CONFIG_FB_MODE_HELPERS */ 1291 1292/* 1293 * fb_validate_mode - validates var against monitor capabilities 1294 * @var: pointer to fb_var_screeninfo 1295 * @info: pointer to fb_info 1296 * 1297 * DESCRIPTION: 1298 * Validates video mode against monitor capabilities specified in 1299 * info->monspecs. 1300 * 1301 * REQUIRES: 1302 * A valid info->monspecs. 1303 */ 1304int fb_validate_mode(const struct fb_var_screeninfo *var, struct fb_info *info) 1305{ 1306 u32 hfreq, vfreq, htotal, vtotal, pixclock; 1307 u32 hfmin, hfmax, vfmin, vfmax, dclkmin, dclkmax; 1308 1309 /* 1310 * If monspecs are invalid, use values that are enough 1311 * for 640x480@60 1312 */ 1313 if (!info->monspecs.hfmax || !info->monspecs.vfmax || 1314 !info->monspecs.dclkmax || 1315 info->monspecs.hfmax < info->monspecs.hfmin || 1316 info->monspecs.vfmax < info->monspecs.vfmin || 1317 info->monspecs.dclkmax < info->monspecs.dclkmin) { 1318 hfmin = 29000; hfmax = 30000; 1319 vfmin = 60; vfmax = 60; 1320 dclkmin = 0; dclkmax = 25000000; 1321 } else { 1322 hfmin = info->monspecs.hfmin; 1323 hfmax = info->monspecs.hfmax; 1324 vfmin = info->monspecs.vfmin; 1325 vfmax = info->monspecs.vfmax; 1326 dclkmin = info->monspecs.dclkmin; 1327 dclkmax = info->monspecs.dclkmax; 1328 } 1329 1330 if (!var->pixclock) 1331 return -EINVAL; 1332 pixclock = PICOS2KHZ(var->pixclock) * 1000; 1333 1334 htotal = var->xres + var->right_margin + var->hsync_len + 1335 var->left_margin; 1336 vtotal = var->yres + var->lower_margin + var->vsync_len + 1337 var->upper_margin; 1338 1339 if (var->vmode & FB_VMODE_INTERLACED) 1340 vtotal /= 2; 1341 if (var->vmode & FB_VMODE_DOUBLE) 1342 vtotal *= 2; 1343 1344 hfreq = pixclock/htotal; 1345 hfreq = (hfreq + 500) / 1000 * 1000; 1346 1347 vfreq = hfreq/vtotal; 1348 1349 return (vfreq < vfmin || vfreq > vfmax || 1350 hfreq < hfmin || hfreq > hfmax || 1351 pixclock < dclkmin || pixclock > dclkmax) ? 1352 -EINVAL : 0; 1353} 1354 1355#if defined(CONFIG_FIRMWARE_EDID) && defined(CONFIG_X86) 1356 1357/* 1358 * We need to ensure that the EDID block is only returned for 1359 * the primary graphics adapter. 1360 */ 1361 1362const unsigned char *fb_firmware_edid(struct device *device) 1363{ 1364 struct pci_dev *dev = NULL; 1365 struct resource *res = NULL; 1366 unsigned char *edid = NULL; 1367 1368 if (device) 1369 dev = to_pci_dev(device); 1370 1371 if (dev) 1372 res = &dev->resource[PCI_ROM_RESOURCE]; 1373 1374 if (res && res->flags & IORESOURCE_ROM_SHADOW) 1375 edid = edid_info.dummy; 1376 1377 return edid; 1378} 1379#else 1380const unsigned char *fb_firmware_edid(struct device *device) 1381{ 1382 return NULL; 1383} 1384#endif 1385EXPORT_SYMBOL(fb_firmware_edid); 1386 1387EXPORT_SYMBOL(fb_parse_edid); 1388EXPORT_SYMBOL(fb_edid_to_monspecs); 1389EXPORT_SYMBOL(fb_get_mode); 1390EXPORT_SYMBOL(fb_validate_mode); 1391EXPORT_SYMBOL(fb_destroy_modedb); 1392