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