0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029 #include <linux/fb.h>
0030 #include <linux/module.h>
0031 #include <linux/pci.h>
0032 #include <linux/slab.h>
0033 #include <video/edid.h>
0034 #include <video/of_videomode.h>
0035 #include <video/videomode.h>
0036 #include "../edid.h"
0037
0038
0039
0040
0041
0042 #undef DEBUG
0043
0044 #ifdef DEBUG
0045 #define DPRINTK(fmt, args...) printk(fmt,## args)
0046 #else
0047 #define DPRINTK(fmt, args...) no_printk(fmt, ##args)
0048 #endif
0049
0050 #define FBMON_FIX_HEADER 1
0051 #define FBMON_FIX_INPUT 2
0052 #define FBMON_FIX_TIMINGS 3
0053
0054 #ifdef CONFIG_FB_MODE_HELPERS
0055 struct broken_edid {
0056 u8 manufacturer[4];
0057 u32 model;
0058 u32 fix;
0059 };
0060
0061 static const struct broken_edid brokendb[] = {
0062
0063 {
0064 .manufacturer = "DEC",
0065 .model = 0x073a,
0066 .fix = FBMON_FIX_HEADER,
0067 },
0068
0069 {
0070 .manufacturer = "VSC",
0071 .model = 0x5a44,
0072 .fix = FBMON_FIX_INPUT,
0073 },
0074
0075 {
0076 .manufacturer = "SHP",
0077 .model = 0x138e,
0078 .fix = FBMON_FIX_TIMINGS,
0079 },
0080 };
0081
0082 static const unsigned char edid_v1_header[] = { 0x00, 0xff, 0xff, 0xff,
0083 0xff, 0xff, 0xff, 0x00
0084 };
0085
0086 static void copy_string(unsigned char *c, unsigned char *s)
0087 {
0088 int i;
0089 c = c + 5;
0090 for (i = 0; (i < 13 && *c != 0x0A); i++)
0091 *(s++) = *(c++);
0092 *s = 0;
0093 while (i-- && (*--s == 0x20)) *s = 0;
0094 }
0095
0096 static int edid_is_serial_block(unsigned char *block)
0097 {
0098 if ((block[0] == 0x00) && (block[1] == 0x00) &&
0099 (block[2] == 0x00) && (block[3] == 0xff) &&
0100 (block[4] == 0x00))
0101 return 1;
0102 else
0103 return 0;
0104 }
0105
0106 static int edid_is_ascii_block(unsigned char *block)
0107 {
0108 if ((block[0] == 0x00) && (block[1] == 0x00) &&
0109 (block[2] == 0x00) && (block[3] == 0xfe) &&
0110 (block[4] == 0x00))
0111 return 1;
0112 else
0113 return 0;
0114 }
0115
0116 static int edid_is_limits_block(unsigned char *block)
0117 {
0118 if ((block[0] == 0x00) && (block[1] == 0x00) &&
0119 (block[2] == 0x00) && (block[3] == 0xfd) &&
0120 (block[4] == 0x00))
0121 return 1;
0122 else
0123 return 0;
0124 }
0125
0126 static int edid_is_monitor_block(unsigned char *block)
0127 {
0128 if ((block[0] == 0x00) && (block[1] == 0x00) &&
0129 (block[2] == 0x00) && (block[3] == 0xfc) &&
0130 (block[4] == 0x00))
0131 return 1;
0132 else
0133 return 0;
0134 }
0135
0136 static int edid_is_timing_block(unsigned char *block)
0137 {
0138 if ((block[0] != 0x00) || (block[1] != 0x00) ||
0139 (block[2] != 0x00) || (block[4] != 0x00))
0140 return 1;
0141 else
0142 return 0;
0143 }
0144
0145 static int check_edid(unsigned char *edid)
0146 {
0147 unsigned char *block = edid + ID_MANUFACTURER_NAME, manufacturer[4];
0148 unsigned char *b;
0149 u32 model;
0150 int i, fix = 0, ret = 0;
0151
0152 manufacturer[0] = ((block[0] & 0x7c) >> 2) + '@';
0153 manufacturer[1] = ((block[0] & 0x03) << 3) +
0154 ((block[1] & 0xe0) >> 5) + '@';
0155 manufacturer[2] = (block[1] & 0x1f) + '@';
0156 manufacturer[3] = 0;
0157 model = block[2] + (block[3] << 8);
0158
0159 for (i = 0; i < ARRAY_SIZE(brokendb); i++) {
0160 if (!strncmp(manufacturer, brokendb[i].manufacturer, 4) &&
0161 brokendb[i].model == model) {
0162 fix = brokendb[i].fix;
0163 break;
0164 }
0165 }
0166
0167 switch (fix) {
0168 case FBMON_FIX_HEADER:
0169 for (i = 0; i < 8; i++) {
0170 if (edid[i] != edid_v1_header[i]) {
0171 ret = fix;
0172 break;
0173 }
0174 }
0175 break;
0176 case FBMON_FIX_INPUT:
0177 b = edid + EDID_STRUCT_DISPLAY;
0178
0179
0180 if (b[4] & 0x01 && b[0] & 0x80)
0181 ret = fix;
0182 break;
0183 case FBMON_FIX_TIMINGS:
0184 b = edid + DETAILED_TIMING_DESCRIPTIONS_START;
0185 ret = fix;
0186
0187 for (i = 0; i < 4; i++) {
0188 if (edid_is_limits_block(b)) {
0189 ret = 0;
0190 break;
0191 }
0192
0193 b += DETAILED_TIMING_DESCRIPTION_SIZE;
0194 }
0195
0196 break;
0197 }
0198
0199 if (ret)
0200 printk("fbmon: The EDID Block of "
0201 "Manufacturer: %s Model: 0x%x is known to "
0202 "be broken,\n", manufacturer, model);
0203
0204 return ret;
0205 }
0206
0207 static void fix_edid(unsigned char *edid, int fix)
0208 {
0209 int i;
0210 unsigned char *b, csum = 0;
0211
0212 switch (fix) {
0213 case FBMON_FIX_HEADER:
0214 printk("fbmon: trying a header reconstruct\n");
0215 memcpy(edid, edid_v1_header, 8);
0216 break;
0217 case FBMON_FIX_INPUT:
0218 printk("fbmon: trying to fix input type\n");
0219 b = edid + EDID_STRUCT_DISPLAY;
0220 b[0] &= ~0x80;
0221 edid[127] += 0x80;
0222 break;
0223 case FBMON_FIX_TIMINGS:
0224 printk("fbmon: trying to fix monitor timings\n");
0225 b = edid + DETAILED_TIMING_DESCRIPTIONS_START;
0226 for (i = 0; i < 4; i++) {
0227 if (!(edid_is_serial_block(b) ||
0228 edid_is_ascii_block(b) ||
0229 edid_is_monitor_block(b) ||
0230 edid_is_timing_block(b))) {
0231 b[0] = 0x00;
0232 b[1] = 0x00;
0233 b[2] = 0x00;
0234 b[3] = 0xfd;
0235 b[4] = 0x00;
0236 b[5] = 60;
0237 b[6] = 60;
0238 b[7] = 30;
0239 b[8] = 75;
0240 b[9] = 17;
0241 b[10] = 0;
0242 break;
0243 }
0244
0245 b += DETAILED_TIMING_DESCRIPTION_SIZE;
0246 }
0247
0248 for (i = 0; i < EDID_LENGTH - 1; i++)
0249 csum += edid[i];
0250
0251 edid[127] = 256 - csum;
0252 break;
0253 }
0254 }
0255
0256 static int edid_checksum(unsigned char *edid)
0257 {
0258 unsigned char csum = 0, all_null = 0;
0259 int i, err = 0, fix = check_edid(edid);
0260
0261 if (fix)
0262 fix_edid(edid, fix);
0263
0264 for (i = 0; i < EDID_LENGTH; i++) {
0265 csum += edid[i];
0266 all_null |= edid[i];
0267 }
0268
0269 if (csum == 0x00 && all_null) {
0270
0271 err = 1;
0272 }
0273
0274 return err;
0275 }
0276
0277 static int edid_check_header(unsigned char *edid)
0278 {
0279 int i, err = 1, fix = check_edid(edid);
0280
0281 if (fix)
0282 fix_edid(edid, fix);
0283
0284 for (i = 0; i < 8; i++) {
0285 if (edid[i] != edid_v1_header[i])
0286 err = 0;
0287 }
0288
0289 return err;
0290 }
0291
0292 static void parse_vendor_block(unsigned char *block, struct fb_monspecs *specs)
0293 {
0294 specs->manufacturer[0] = ((block[0] & 0x7c) >> 2) + '@';
0295 specs->manufacturer[1] = ((block[0] & 0x03) << 3) +
0296 ((block[1] & 0xe0) >> 5) + '@';
0297 specs->manufacturer[2] = (block[1] & 0x1f) + '@';
0298 specs->manufacturer[3] = 0;
0299 specs->model = block[2] + (block[3] << 8);
0300 specs->serial = block[4] + (block[5] << 8) +
0301 (block[6] << 16) + (block[7] << 24);
0302 specs->year = block[9] + 1990;
0303 specs->week = block[8];
0304 DPRINTK(" Manufacturer: %s\n", specs->manufacturer);
0305 DPRINTK(" Model: %x\n", specs->model);
0306 DPRINTK(" Serial#: %u\n", specs->serial);
0307 DPRINTK(" Year: %u Week %u\n", specs->year, specs->week);
0308 }
0309
0310 static void get_dpms_capabilities(unsigned char flags,
0311 struct fb_monspecs *specs)
0312 {
0313 specs->dpms = 0;
0314 if (flags & DPMS_ACTIVE_OFF)
0315 specs->dpms |= FB_DPMS_ACTIVE_OFF;
0316 if (flags & DPMS_SUSPEND)
0317 specs->dpms |= FB_DPMS_SUSPEND;
0318 if (flags & DPMS_STANDBY)
0319 specs->dpms |= FB_DPMS_STANDBY;
0320 DPRINTK(" DPMS: Active %s, Suspend %s, Standby %s\n",
0321 (flags & DPMS_ACTIVE_OFF) ? "yes" : "no",
0322 (flags & DPMS_SUSPEND) ? "yes" : "no",
0323 (flags & DPMS_STANDBY) ? "yes" : "no");
0324 }
0325
0326 static void get_chroma(unsigned char *block, struct fb_monspecs *specs)
0327 {
0328 int tmp;
0329
0330 DPRINTK(" Chroma\n");
0331
0332 tmp = ((block[5] & (3 << 6)) >> 6) | (block[0x7] << 2);
0333 tmp *= 1000;
0334 tmp += 512;
0335 specs->chroma.redx = tmp/1024;
0336 DPRINTK(" RedX: 0.%03d ", specs->chroma.redx);
0337
0338 tmp = ((block[5] & (3 << 4)) >> 4) | (block[0x8] << 2);
0339 tmp *= 1000;
0340 tmp += 512;
0341 specs->chroma.redy = tmp/1024;
0342 DPRINTK("RedY: 0.%03d\n", specs->chroma.redy);
0343
0344 tmp = ((block[5] & (3 << 2)) >> 2) | (block[0x9] << 2);
0345 tmp *= 1000;
0346 tmp += 512;
0347 specs->chroma.greenx = tmp/1024;
0348 DPRINTK(" GreenX: 0.%03d ", specs->chroma.greenx);
0349
0350 tmp = (block[5] & 3) | (block[0xa] << 2);
0351 tmp *= 1000;
0352 tmp += 512;
0353 specs->chroma.greeny = tmp/1024;
0354 DPRINTK("GreenY: 0.%03d\n", specs->chroma.greeny);
0355
0356 tmp = ((block[6] & (3 << 6)) >> 6) | (block[0xb] << 2);
0357 tmp *= 1000;
0358 tmp += 512;
0359 specs->chroma.bluex = tmp/1024;
0360 DPRINTK(" BlueX: 0.%03d ", specs->chroma.bluex);
0361
0362 tmp = ((block[6] & (3 << 4)) >> 4) | (block[0xc] << 2);
0363 tmp *= 1000;
0364 tmp += 512;
0365 specs->chroma.bluey = tmp/1024;
0366 DPRINTK("BlueY: 0.%03d\n", specs->chroma.bluey);
0367
0368 tmp = ((block[6] & (3 << 2)) >> 2) | (block[0xd] << 2);
0369 tmp *= 1000;
0370 tmp += 512;
0371 specs->chroma.whitex = tmp/1024;
0372 DPRINTK(" WhiteX: 0.%03d ", specs->chroma.whitex);
0373
0374 tmp = (block[6] & 3) | (block[0xe] << 2);
0375 tmp *= 1000;
0376 tmp += 512;
0377 specs->chroma.whitey = tmp/1024;
0378 DPRINTK("WhiteY: 0.%03d\n", specs->chroma.whitey);
0379 }
0380
0381 static void calc_mode_timings(int xres, int yres, int refresh,
0382 struct fb_videomode *mode)
0383 {
0384 struct fb_var_screeninfo *var;
0385
0386 var = kzalloc(sizeof(struct fb_var_screeninfo), GFP_KERNEL);
0387
0388 if (var) {
0389 var->xres = xres;
0390 var->yres = yres;
0391 fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON,
0392 refresh, var, NULL);
0393 mode->xres = xres;
0394 mode->yres = yres;
0395 mode->pixclock = var->pixclock;
0396 mode->refresh = refresh;
0397 mode->left_margin = var->left_margin;
0398 mode->right_margin = var->right_margin;
0399 mode->upper_margin = var->upper_margin;
0400 mode->lower_margin = var->lower_margin;
0401 mode->hsync_len = var->hsync_len;
0402 mode->vsync_len = var->vsync_len;
0403 mode->vmode = 0;
0404 mode->sync = 0;
0405 kfree(var);
0406 }
0407 }
0408
0409 static int get_est_timing(unsigned char *block, struct fb_videomode *mode)
0410 {
0411 int num = 0;
0412 unsigned char c;
0413
0414 c = block[0];
0415 if (c&0x80) {
0416 calc_mode_timings(720, 400, 70, &mode[num]);
0417 mode[num++].flag = FB_MODE_IS_CALCULATED;
0418 DPRINTK(" 720x400@70Hz\n");
0419 }
0420 if (c&0x40) {
0421 calc_mode_timings(720, 400, 88, &mode[num]);
0422 mode[num++].flag = FB_MODE_IS_CALCULATED;
0423 DPRINTK(" 720x400@88Hz\n");
0424 }
0425 if (c&0x20) {
0426 mode[num++] = vesa_modes[3];
0427 DPRINTK(" 640x480@60Hz\n");
0428 }
0429 if (c&0x10) {
0430 calc_mode_timings(640, 480, 67, &mode[num]);
0431 mode[num++].flag = FB_MODE_IS_CALCULATED;
0432 DPRINTK(" 640x480@67Hz\n");
0433 }
0434 if (c&0x08) {
0435 mode[num++] = vesa_modes[4];
0436 DPRINTK(" 640x480@72Hz\n");
0437 }
0438 if (c&0x04) {
0439 mode[num++] = vesa_modes[5];
0440 DPRINTK(" 640x480@75Hz\n");
0441 }
0442 if (c&0x02) {
0443 mode[num++] = vesa_modes[7];
0444 DPRINTK(" 800x600@56Hz\n");
0445 }
0446 if (c&0x01) {
0447 mode[num++] = vesa_modes[8];
0448 DPRINTK(" 800x600@60Hz\n");
0449 }
0450
0451 c = block[1];
0452 if (c&0x80) {
0453 mode[num++] = vesa_modes[9];
0454 DPRINTK(" 800x600@72Hz\n");
0455 }
0456 if (c&0x40) {
0457 mode[num++] = vesa_modes[10];
0458 DPRINTK(" 800x600@75Hz\n");
0459 }
0460 if (c&0x20) {
0461 calc_mode_timings(832, 624, 75, &mode[num]);
0462 mode[num++].flag = FB_MODE_IS_CALCULATED;
0463 DPRINTK(" 832x624@75Hz\n");
0464 }
0465 if (c&0x10) {
0466 mode[num++] = vesa_modes[12];
0467 DPRINTK(" 1024x768@87Hz Interlaced\n");
0468 }
0469 if (c&0x08) {
0470 mode[num++] = vesa_modes[13];
0471 DPRINTK(" 1024x768@60Hz\n");
0472 }
0473 if (c&0x04) {
0474 mode[num++] = vesa_modes[14];
0475 DPRINTK(" 1024x768@70Hz\n");
0476 }
0477 if (c&0x02) {
0478 mode[num++] = vesa_modes[15];
0479 DPRINTK(" 1024x768@75Hz\n");
0480 }
0481 if (c&0x01) {
0482 mode[num++] = vesa_modes[21];
0483 DPRINTK(" 1280x1024@75Hz\n");
0484 }
0485 c = block[2];
0486 if (c&0x80) {
0487 mode[num++] = vesa_modes[17];
0488 DPRINTK(" 1152x870@75Hz\n");
0489 }
0490 DPRINTK(" Manufacturer's mask: %x\n",c&0x7F);
0491 return num;
0492 }
0493
0494 static int get_std_timing(unsigned char *block, struct fb_videomode *mode,
0495 int ver, int rev, const struct fb_monspecs *specs)
0496 {
0497 int i;
0498
0499 for (i = 0; i < DMT_SIZE; i++) {
0500 u32 std_2byte_code = block[0] << 8 | block[1];
0501 if (std_2byte_code == dmt_modes[i].std_2byte_code)
0502 break;
0503 }
0504
0505 if (i < DMT_SIZE && dmt_modes[i].mode) {
0506
0507 *mode = *dmt_modes[i].mode;
0508 mode->flag |= FB_MODE_IS_STANDARD;
0509 DPRINTK(" DMT id=%d\n", dmt_modes[i].dmt_id);
0510
0511 } else {
0512 int xres, yres = 0, refresh, ratio;
0513
0514 xres = (block[0] + 31) * 8;
0515 if (xres <= 256)
0516 return 0;
0517
0518 ratio = (block[1] & 0xc0) >> 6;
0519 switch (ratio) {
0520 case 0:
0521
0522 if (ver < 1 || (ver == 1 && rev < 3))
0523 yres = xres;
0524 else
0525 yres = (xres * 10)/16;
0526 break;
0527 case 1:
0528 yres = (xres * 3)/4;
0529 break;
0530 case 2:
0531 yres = (xres * 4)/5;
0532 break;
0533 case 3:
0534 yres = (xres * 9)/16;
0535 break;
0536 }
0537 refresh = (block[1] & 0x3f) + 60;
0538 DPRINTK(" %dx%d@%dHz\n", xres, yres, refresh);
0539
0540 calc_mode_timings(xres, yres, refresh, mode);
0541 }
0542
0543
0544 if (specs && specs->dclkmax
0545 && PICOS2KHZ(mode->pixclock) * 1000 > specs->dclkmax) {
0546 DPRINTK(" mode exceed max DCLK\n");
0547 return 0;
0548 }
0549
0550 return 1;
0551 }
0552
0553 static int get_dst_timing(unsigned char *block, struct fb_videomode *mode,
0554 int ver, int rev, const struct fb_monspecs *specs)
0555 {
0556 int j, num = 0;
0557
0558 for (j = 0; j < 6; j++, block += STD_TIMING_DESCRIPTION_SIZE)
0559 num += get_std_timing(block, &mode[num], ver, rev, specs);
0560
0561 return num;
0562 }
0563
0564 static void get_detailed_timing(unsigned char *block,
0565 struct fb_videomode *mode)
0566 {
0567 mode->xres = H_ACTIVE;
0568 mode->yres = V_ACTIVE;
0569 mode->pixclock = PIXEL_CLOCK;
0570 mode->pixclock /= 1000;
0571 mode->pixclock = KHZ2PICOS(mode->pixclock);
0572 mode->right_margin = H_SYNC_OFFSET;
0573 mode->left_margin = (H_ACTIVE + H_BLANKING) -
0574 (H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH);
0575 mode->upper_margin = V_BLANKING - V_SYNC_OFFSET -
0576 V_SYNC_WIDTH;
0577 mode->lower_margin = V_SYNC_OFFSET;
0578 mode->hsync_len = H_SYNC_WIDTH;
0579 mode->vsync_len = V_SYNC_WIDTH;
0580 if (HSYNC_POSITIVE)
0581 mode->sync |= FB_SYNC_HOR_HIGH_ACT;
0582 if (VSYNC_POSITIVE)
0583 mode->sync |= FB_SYNC_VERT_HIGH_ACT;
0584 mode->refresh = PIXEL_CLOCK/((H_ACTIVE + H_BLANKING) *
0585 (V_ACTIVE + V_BLANKING));
0586 if (INTERLACED) {
0587 mode->yres *= 2;
0588 mode->upper_margin *= 2;
0589 mode->lower_margin *= 2;
0590 mode->vsync_len *= 2;
0591 mode->vmode |= FB_VMODE_INTERLACED;
0592 }
0593 mode->flag = FB_MODE_IS_DETAILED;
0594
0595 DPRINTK(" %d MHz ", PIXEL_CLOCK/1000000);
0596 DPRINTK("%d %d %d %d ", H_ACTIVE, H_ACTIVE + H_SYNC_OFFSET,
0597 H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH, H_ACTIVE + H_BLANKING);
0598 DPRINTK("%d %d %d %d ", V_ACTIVE, V_ACTIVE + V_SYNC_OFFSET,
0599 V_ACTIVE + V_SYNC_OFFSET + V_SYNC_WIDTH, V_ACTIVE + V_BLANKING);
0600 DPRINTK("%sHSync %sVSync\n\n", (HSYNC_POSITIVE) ? "+" : "-",
0601 (VSYNC_POSITIVE) ? "+" : "-");
0602 }
0603
0604
0605
0606
0607
0608
0609
0610
0611
0612
0613
0614
0615
0616 static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize,
0617 const struct fb_monspecs *specs)
0618 {
0619 struct fb_videomode *mode, *m;
0620 unsigned char *block;
0621 int num = 0, i, first = 1;
0622 int ver, rev;
0623
0624 mode = kcalloc(50, sizeof(struct fb_videomode), GFP_KERNEL);
0625 if (mode == NULL)
0626 return NULL;
0627
0628 if (edid == NULL || !edid_checksum(edid) ||
0629 !edid_check_header(edid)) {
0630 kfree(mode);
0631 return NULL;
0632 }
0633
0634 ver = edid[EDID_STRUCT_VERSION];
0635 rev = edid[EDID_STRUCT_REVISION];
0636
0637 *dbsize = 0;
0638
0639 DPRINTK(" Detailed Timings\n");
0640 block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
0641 for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) {
0642 if (!(block[0] == 0x00 && block[1] == 0x00)) {
0643 get_detailed_timing(block, &mode[num]);
0644 if (first) {
0645 mode[num].flag |= FB_MODE_IS_FIRST;
0646 first = 0;
0647 }
0648 num++;
0649 }
0650 }
0651
0652 DPRINTK(" Supported VESA Modes\n");
0653 block = edid + ESTABLISHED_TIMING_1;
0654 num += get_est_timing(block, &mode[num]);
0655
0656 DPRINTK(" Standard Timings\n");
0657 block = edid + STD_TIMING_DESCRIPTIONS_START;
0658 for (i = 0; i < STD_TIMING; i++, block += STD_TIMING_DESCRIPTION_SIZE)
0659 num += get_std_timing(block, &mode[num], ver, rev, specs);
0660
0661 block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
0662 for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) {
0663 if (block[0] == 0x00 && block[1] == 0x00 && block[3] == 0xfa)
0664 num += get_dst_timing(block + 5, &mode[num],
0665 ver, rev, specs);
0666 }
0667
0668
0669 if (!num) {
0670 kfree(mode);
0671 return NULL;
0672 }
0673
0674 *dbsize = num;
0675 m = kmalloc_array(num, sizeof(struct fb_videomode), GFP_KERNEL);
0676 if (!m)
0677 return mode;
0678 memmove(m, mode, num * sizeof(struct fb_videomode));
0679 kfree(mode);
0680 return m;
0681 }
0682
0683
0684
0685
0686
0687
0688
0689
0690 void fb_destroy_modedb(struct fb_videomode *modedb)
0691 {
0692 kfree(modedb);
0693 }
0694
0695 static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs)
0696 {
0697 int i, retval = 1;
0698 unsigned char *block;
0699
0700 block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
0701
0702 DPRINTK(" Monitor Operating Limits: ");
0703
0704 for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {
0705 if (edid_is_limits_block(block)) {
0706 specs->hfmin = H_MIN_RATE * 1000;
0707 specs->hfmax = H_MAX_RATE * 1000;
0708 specs->vfmin = V_MIN_RATE;
0709 specs->vfmax = V_MAX_RATE;
0710 specs->dclkmax = MAX_PIXEL_CLOCK * 1000000;
0711 specs->gtf = (GTF_SUPPORT) ? 1 : 0;
0712 retval = 0;
0713 DPRINTK("From EDID\n");
0714 break;
0715 }
0716 }
0717
0718
0719 if (retval) {
0720 struct fb_videomode *modes, *mode;
0721 int num_modes, hz, hscan, pixclock;
0722 int vtotal, htotal;
0723
0724 modes = fb_create_modedb(edid, &num_modes, specs);
0725 if (!modes) {
0726 DPRINTK("None Available\n");
0727 return 1;
0728 }
0729
0730 retval = 0;
0731 for (i = 0; i < num_modes; i++) {
0732 mode = &modes[i];
0733 pixclock = PICOS2KHZ(modes[i].pixclock) * 1000;
0734 htotal = mode->xres + mode->right_margin + mode->hsync_len
0735 + mode->left_margin;
0736 vtotal = mode->yres + mode->lower_margin + mode->vsync_len
0737 + mode->upper_margin;
0738
0739 if (mode->vmode & FB_VMODE_INTERLACED)
0740 vtotal /= 2;
0741
0742 if (mode->vmode & FB_VMODE_DOUBLE)
0743 vtotal *= 2;
0744
0745 hscan = (pixclock + htotal / 2) / htotal;
0746 hscan = (hscan + 500) / 1000 * 1000;
0747 hz = (hscan + vtotal / 2) / vtotal;
0748
0749 if (specs->dclkmax == 0 || specs->dclkmax < pixclock)
0750 specs->dclkmax = pixclock;
0751
0752 if (specs->dclkmin == 0 || specs->dclkmin > pixclock)
0753 specs->dclkmin = pixclock;
0754
0755 if (specs->hfmax == 0 || specs->hfmax < hscan)
0756 specs->hfmax = hscan;
0757
0758 if (specs->hfmin == 0 || specs->hfmin > hscan)
0759 specs->hfmin = hscan;
0760
0761 if (specs->vfmax == 0 || specs->vfmax < hz)
0762 specs->vfmax = hz;
0763
0764 if (specs->vfmin == 0 || specs->vfmin > hz)
0765 specs->vfmin = hz;
0766 }
0767 DPRINTK("Extrapolated\n");
0768 fb_destroy_modedb(modes);
0769 }
0770 DPRINTK(" H: %d-%dKHz V: %d-%dHz DCLK: %dMHz\n",
0771 specs->hfmin/1000, specs->hfmax/1000, specs->vfmin,
0772 specs->vfmax, specs->dclkmax/1000000);
0773 return retval;
0774 }
0775
0776 static void get_monspecs(unsigned char *edid, struct fb_monspecs *specs)
0777 {
0778 unsigned char c, *block;
0779
0780 block = edid + EDID_STRUCT_DISPLAY;
0781
0782 fb_get_monitor_limits(edid, specs);
0783
0784 c = block[0] & 0x80;
0785 specs->input = 0;
0786 if (c) {
0787 specs->input |= FB_DISP_DDI;
0788 DPRINTK(" Digital Display Input");
0789 } else {
0790 DPRINTK(" Analog Display Input: Input Voltage - ");
0791 switch ((block[0] & 0x60) >> 5) {
0792 case 0:
0793 DPRINTK("0.700V/0.300V");
0794 specs->input |= FB_DISP_ANA_700_300;
0795 break;
0796 case 1:
0797 DPRINTK("0.714V/0.286V");
0798 specs->input |= FB_DISP_ANA_714_286;
0799 break;
0800 case 2:
0801 DPRINTK("1.000V/0.400V");
0802 specs->input |= FB_DISP_ANA_1000_400;
0803 break;
0804 case 3:
0805 DPRINTK("0.700V/0.000V");
0806 specs->input |= FB_DISP_ANA_700_000;
0807 break;
0808 }
0809 }
0810 DPRINTK("\n Sync: ");
0811 c = block[0] & 0x10;
0812 if (c)
0813 DPRINTK(" Configurable signal level\n");
0814 c = block[0] & 0x0f;
0815 specs->signal = 0;
0816 if (c & 0x10) {
0817 DPRINTK("Blank to Blank ");
0818 specs->signal |= FB_SIGNAL_BLANK_BLANK;
0819 }
0820 if (c & 0x08) {
0821 DPRINTK("Separate ");
0822 specs->signal |= FB_SIGNAL_SEPARATE;
0823 }
0824 if (c & 0x04) {
0825 DPRINTK("Composite ");
0826 specs->signal |= FB_SIGNAL_COMPOSITE;
0827 }
0828 if (c & 0x02) {
0829 DPRINTK("Sync on Green ");
0830 specs->signal |= FB_SIGNAL_SYNC_ON_GREEN;
0831 }
0832 if (c & 0x01) {
0833 DPRINTK("Serration on ");
0834 specs->signal |= FB_SIGNAL_SERRATION_ON;
0835 }
0836 DPRINTK("\n");
0837 specs->max_x = block[1];
0838 specs->max_y = block[2];
0839 DPRINTK(" Max H-size in cm: ");
0840 if (specs->max_x)
0841 DPRINTK("%d\n", specs->max_x);
0842 else
0843 DPRINTK("variable\n");
0844 DPRINTK(" Max V-size in cm: ");
0845 if (specs->max_y)
0846 DPRINTK("%d\n", specs->max_y);
0847 else
0848 DPRINTK("variable\n");
0849
0850 c = block[3];
0851 specs->gamma = c+100;
0852 DPRINTK(" Gamma: ");
0853 DPRINTK("%d.%d\n", specs->gamma/100, specs->gamma % 100);
0854
0855 get_dpms_capabilities(block[4], specs);
0856
0857 switch ((block[4] & 0x18) >> 3) {
0858 case 0:
0859 DPRINTK(" Monochrome/Grayscale\n");
0860 specs->input |= FB_DISP_MONO;
0861 break;
0862 case 1:
0863 DPRINTK(" RGB Color Display\n");
0864 specs->input |= FB_DISP_RGB;
0865 break;
0866 case 2:
0867 DPRINTK(" Non-RGB Multicolor Display\n");
0868 specs->input |= FB_DISP_MULTI;
0869 break;
0870 default:
0871 DPRINTK(" Unknown\n");
0872 specs->input |= FB_DISP_UNKNOWN;
0873 break;
0874 }
0875
0876 get_chroma(block, specs);
0877
0878 specs->misc = 0;
0879 c = block[4] & 0x7;
0880 if (c & 0x04) {
0881 DPRINTK(" Default color format is primary\n");
0882 specs->misc |= FB_MISC_PRIM_COLOR;
0883 }
0884 if (c & 0x02) {
0885 DPRINTK(" First DETAILED Timing is preferred\n");
0886 specs->misc |= FB_MISC_1ST_DETAIL;
0887 }
0888 if (c & 0x01) {
0889 printk(" Display is GTF capable\n");
0890 specs->gtf = 1;
0891 }
0892 }
0893
0894 int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var)
0895 {
0896 int i;
0897 unsigned char *block;
0898
0899 if (edid == NULL || var == NULL)
0900 return 1;
0901
0902 if (!(edid_checksum(edid)))
0903 return 1;
0904
0905 if (!(edid_check_header(edid)))
0906 return 1;
0907
0908 block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
0909
0910 for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {
0911 if (edid_is_timing_block(block)) {
0912 var->xres = var->xres_virtual = H_ACTIVE;
0913 var->yres = var->yres_virtual = V_ACTIVE;
0914 var->height = var->width = 0;
0915 var->right_margin = H_SYNC_OFFSET;
0916 var->left_margin = (H_ACTIVE + H_BLANKING) -
0917 (H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH);
0918 var->upper_margin = V_BLANKING - V_SYNC_OFFSET -
0919 V_SYNC_WIDTH;
0920 var->lower_margin = V_SYNC_OFFSET;
0921 var->hsync_len = H_SYNC_WIDTH;
0922 var->vsync_len = V_SYNC_WIDTH;
0923 var->pixclock = PIXEL_CLOCK;
0924 var->pixclock /= 1000;
0925 var->pixclock = KHZ2PICOS(var->pixclock);
0926
0927 if (HSYNC_POSITIVE)
0928 var->sync |= FB_SYNC_HOR_HIGH_ACT;
0929 if (VSYNC_POSITIVE)
0930 var->sync |= FB_SYNC_VERT_HIGH_ACT;
0931 return 0;
0932 }
0933 }
0934 return 1;
0935 }
0936
0937 void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs)
0938 {
0939 unsigned char *block;
0940 int i, found = 0;
0941
0942 if (edid == NULL)
0943 return;
0944
0945 if (!(edid_checksum(edid)))
0946 return;
0947
0948 if (!(edid_check_header(edid)))
0949 return;
0950
0951 memset(specs, 0, sizeof(struct fb_monspecs));
0952
0953 specs->version = edid[EDID_STRUCT_VERSION];
0954 specs->revision = edid[EDID_STRUCT_REVISION];
0955
0956 DPRINTK("========================================\n");
0957 DPRINTK("Display Information (EDID)\n");
0958 DPRINTK("========================================\n");
0959 DPRINTK(" EDID Version %d.%d\n", (int) specs->version,
0960 (int) specs->revision);
0961
0962 parse_vendor_block(edid + ID_MANUFACTURER_NAME, specs);
0963
0964 block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
0965 for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {
0966 if (edid_is_serial_block(block)) {
0967 copy_string(block, specs->serial_no);
0968 DPRINTK(" Serial Number: %s\n", specs->serial_no);
0969 } else if (edid_is_ascii_block(block)) {
0970 copy_string(block, specs->ascii);
0971 DPRINTK(" ASCII Block: %s\n", specs->ascii);
0972 } else if (edid_is_monitor_block(block)) {
0973 copy_string(block, specs->monitor);
0974 DPRINTK(" Monitor Name: %s\n", specs->monitor);
0975 }
0976 }
0977
0978 DPRINTK(" Display Characteristics:\n");
0979 get_monspecs(edid, specs);
0980
0981 specs->modedb = fb_create_modedb(edid, &specs->modedb_len, specs);
0982 if (!specs->modedb)
0983 return;
0984
0985
0986
0987
0988
0989
0990 for (i = 0; i < specs->modedb_len; i++) {
0991 if (specs->modedb[i].flag & FB_MODE_IS_DETAILED) {
0992 found = 1;
0993 break;
0994 }
0995 }
0996
0997 if (!found)
0998 specs->misc &= ~FB_MISC_1ST_DETAIL;
0999
1000 DPRINTK("========================================\n");
1001 }
1002
1003
1004
1005
1006
1007 #define FLYBACK 550
1008 #define V_FRONTPORCH 1
1009 #define H_OFFSET 40
1010 #define H_SCALEFACTOR 20
1011 #define H_BLANKSCALE 128
1012 #define H_GRADIENT 600
1013 #define C_VAL 30
1014 #define M_VAL 300
1015
1016 struct __fb_timings {
1017 u32 dclk;
1018 u32 hfreq;
1019 u32 vfreq;
1020 u32 hactive;
1021 u32 vactive;
1022 u32 hblank;
1023 u32 vblank;
1024 u32 htotal;
1025 u32 vtotal;
1026 };
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043 static u32 fb_get_vblank(u32 hfreq)
1044 {
1045 u32 vblank;
1046
1047 vblank = (hfreq * FLYBACK)/1000;
1048 vblank = (vblank + 500)/1000;
1049 return (vblank + V_FRONTPORCH);
1050 }
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072 static u32 fb_get_hblank_by_hfreq(u32 hfreq, u32 xres)
1073 {
1074 u32 c_val, m_val, duty_cycle, hblank;
1075
1076 c_val = (((H_OFFSET - H_SCALEFACTOR) * H_BLANKSCALE)/256 +
1077 H_SCALEFACTOR) * 1000;
1078 m_val = (H_BLANKSCALE * H_GRADIENT)/256;
1079 m_val = (m_val * 1000000)/hfreq;
1080 duty_cycle = c_val - m_val;
1081 hblank = (xres * duty_cycle)/(100000 - duty_cycle);
1082 return (hblank);
1083 }
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
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
1128
1129
1130
1131
1132
1133
1134
1135
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
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
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
1229
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:
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:
1273 timings->vfreq = val;
1274 fb_timings_vfreq(timings);
1275 break;
1276 case FB_HSYNCTIMINGS:
1277 timings->hfreq = val;
1278 fb_timings_hfreq(timings);
1279 break;
1280 case FB_DCLKTIMINGS:
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
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
1347 if (htotal && vtotal) {
1348 fbmode->refresh = vm->pixelclock / (htotal * vtotal);
1349
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
1370
1371
1372
1373
1374
1375
1376
1377
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
1401 #endif
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
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
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
1440
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
1488
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);