root/drivers/video/fbdev/core/fbmon.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. copy_string
  2. edid_is_serial_block
  3. edid_is_ascii_block
  4. edid_is_limits_block
  5. edid_is_monitor_block
  6. edid_is_timing_block
  7. check_edid
  8. fix_edid
  9. edid_checksum
  10. edid_check_header
  11. parse_vendor_block
  12. get_dpms_capabilities
  13. get_chroma
  14. calc_mode_timings
  15. get_est_timing
  16. get_std_timing
  17. get_dst_timing
  18. get_detailed_timing
  19. fb_create_modedb
  20. fb_destroy_modedb
  21. fb_get_monitor_limits
  22. get_monspecs
  23. fb_parse_edid
  24. fb_edid_to_monspecs
  25. fb_get_vblank
  26. fb_get_hblank_by_hfreq
  27. fb_get_hblank_by_dclk
  28. fb_get_hfreq
  29. fb_timings_vfreq
  30. fb_timings_hfreq
  31. fb_timings_dclk
  32. fb_get_mode
  33. fb_videomode_from_videomode
  34. dump_fb_videomode
  35. of_get_fb_videomode
  36. fb_parse_edid
  37. fb_edid_to_monspecs
  38. fb_destroy_modedb
  39. fb_get_mode
  40. fb_validate_mode
  41. fb_firmware_edid
  42. fb_firmware_edid

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

/* [<][>][^][v][top][bottom][index][help] */