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