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