Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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