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