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