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 if (INTERLACED) {
568 mode->yres *= 2;
569 mode->upper_margin *= 2;
570 mode->lower_margin *= 2;
571 mode->vsync_len *= 2;
572 mode->vmode |= FB_VMODE_INTERLACED;
573 }
574 mode->flag = FB_MODE_IS_DETAILED;
575
576 DPRINTK(" %d MHz ", PIXEL_CLOCK/1000000);
577 DPRINTK("%d %d %d %d ", H_ACTIVE, H_ACTIVE + H_SYNC_OFFSET,
578 H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH, H_ACTIVE + H_BLANKING);
579 DPRINTK("%d %d %d %d ", V_ACTIVE, V_ACTIVE + V_SYNC_OFFSET,
580 V_ACTIVE + V_SYNC_OFFSET + V_SYNC_WIDTH, V_ACTIVE + V_BLANKING);
581 DPRINTK("%sHSync %sVSync\n\n", (HSYNC_POSITIVE) ? "+" : "-",
582 (VSYNC_POSITIVE) ? "+" : "-");
583}
584
585
586
587
588
589
590
591
592
593
594
595
596static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize)
597{
598 struct fb_videomode *mode, *m;
599 unsigned char *block;
600 int num = 0, i, first = 1;
601
602 mode = kzalloc(50 * sizeof(struct fb_videomode), GFP_KERNEL);
603 if (mode == NULL)
604 return NULL;
605
606 if (edid == NULL || !edid_checksum(edid) ||
607 !edid_check_header(edid)) {
608 kfree(mode);
609 return NULL;
610 }
611
612 *dbsize = 0;
613
614 DPRINTK(" Detailed Timings\n");
615 block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
616 for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) {
617 if (!(block[0] == 0x00 && block[1] == 0x00)) {
618 get_detailed_timing(block, &mode[num]);
619 if (first) {
620 mode[num].flag |= FB_MODE_IS_FIRST;
621 first = 0;
622 }
623 num++;
624 }
625 }
626
627 DPRINTK(" Supported VESA Modes\n");
628 block = edid + ESTABLISHED_TIMING_1;
629 num += get_est_timing(block, &mode[num]);
630
631 DPRINTK(" Standard Timings\n");
632 block = edid + STD_TIMING_DESCRIPTIONS_START;
633 for (i = 0; i < STD_TIMING; i++, block += STD_TIMING_DESCRIPTION_SIZE)
634 num += get_std_timing(block, &mode[num]);
635
636 block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
637 for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) {
638 if (block[0] == 0x00 && block[1] == 0x00 && block[3] == 0xfa)
639 num += get_dst_timing(block + 5, &mode[num]);
640 }
641
642
643 if (!num) {
644 kfree(mode);
645 return NULL;
646 }
647
648 *dbsize = num;
649 m = kmalloc(num * sizeof(struct fb_videomode), GFP_KERNEL);
650 if (!m)
651 return mode;
652 memmove(m, mode, num * sizeof(struct fb_videomode));
653 kfree(mode);
654 return m;
655}
656
657
658
659
660
661
662
663
664void fb_destroy_modedb(struct fb_videomode *modedb)
665{
666 kfree(modedb);
667}
668
669static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs)
670{
671 int i, retval = 1;
672 unsigned char *block;
673
674 block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
675
676 DPRINTK(" Monitor Operating Limits: ");
677
678 for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {
679 if (edid_is_limits_block(block)) {
680 specs->hfmin = H_MIN_RATE * 1000;
681 specs->hfmax = H_MAX_RATE * 1000;
682 specs->vfmin = V_MIN_RATE;
683 specs->vfmax = V_MAX_RATE;
684 specs->dclkmax = MAX_PIXEL_CLOCK * 1000000;
685 specs->gtf = (GTF_SUPPORT) ? 1 : 0;
686 retval = 0;
687 DPRINTK("From EDID\n");
688 break;
689 }
690 }
691
692
693 if (retval) {
694 struct fb_videomode *modes, *mode;
695 int num_modes, hz, hscan, pixclock;
696 int vtotal, htotal;
697
698 modes = fb_create_modedb(edid, &num_modes);
699 if (!modes) {
700 DPRINTK("None Available\n");
701 return 1;
702 }
703
704 retval = 0;
705 for (i = 0; i < num_modes; i++) {
706 mode = &modes[i];
707 pixclock = PICOS2KHZ(modes[i].pixclock) * 1000;
708 htotal = mode->xres + mode->right_margin + mode->hsync_len
709 + mode->left_margin;
710 vtotal = mode->yres + mode->lower_margin + mode->vsync_len
711 + mode->upper_margin;
712
713 if (mode->vmode & FB_VMODE_INTERLACED)
714 vtotal /= 2;
715
716 if (mode->vmode & FB_VMODE_DOUBLE)
717 vtotal *= 2;
718
719 hscan = (pixclock + htotal / 2) / htotal;
720 hscan = (hscan + 500) / 1000 * 1000;
721 hz = (hscan + vtotal / 2) / vtotal;
722
723 if (specs->dclkmax == 0 || specs->dclkmax < pixclock)
724 specs->dclkmax = pixclock;
725
726 if (specs->dclkmin == 0 || specs->dclkmin > pixclock)
727 specs->dclkmin = pixclock;
728
729 if (specs->hfmax == 0 || specs->hfmax < hscan)
730 specs->hfmax = hscan;
731
732 if (specs->hfmin == 0 || specs->hfmin > hscan)
733 specs->hfmin = hscan;
734
735 if (specs->vfmax == 0 || specs->vfmax < hz)
736 specs->vfmax = hz;
737
738 if (specs->vfmin == 0 || specs->vfmin > hz)
739 specs->vfmin = hz;
740 }
741 DPRINTK("Extrapolated\n");
742 fb_destroy_modedb(modes);
743 }
744 DPRINTK(" H: %d-%dKHz V: %d-%dHz DCLK: %dMHz\n",
745 specs->hfmin/1000, specs->hfmax/1000, specs->vfmin,
746 specs->vfmax, specs->dclkmax/1000000);
747 return retval;
748}
749
750static void get_monspecs(unsigned char *edid, struct fb_monspecs *specs)
751{
752 unsigned char c, *block;
753
754 block = edid + EDID_STRUCT_DISPLAY;
755
756 fb_get_monitor_limits(edid, specs);
757
758 c = block[0] & 0x80;
759 specs->input = 0;
760 if (c) {
761 specs->input |= FB_DISP_DDI;
762 DPRINTK(" Digital Display Input");
763 } else {
764 DPRINTK(" Analog Display Input: Input Voltage - ");
765 switch ((block[0] & 0x60) >> 5) {
766 case 0:
767 DPRINTK("0.700V/0.300V");
768 specs->input |= FB_DISP_ANA_700_300;
769 break;
770 case 1:
771 DPRINTK("0.714V/0.286V");
772 specs->input |= FB_DISP_ANA_714_286;
773 break;
774 case 2:
775 DPRINTK("1.000V/0.400V");
776 specs->input |= FB_DISP_ANA_1000_400;
777 break;
778 case 3:
779 DPRINTK("0.700V/0.000V");
780 specs->input |= FB_DISP_ANA_700_000;
781 break;
782 }
783 }
784 DPRINTK("\n Sync: ");
785 c = block[0] & 0x10;
786 if (c)
787 DPRINTK(" Configurable signal level\n");
788 c = block[0] & 0x0f;
789 specs->signal = 0;
790 if (c & 0x10) {
791 DPRINTK("Blank to Blank ");
792 specs->signal |= FB_SIGNAL_BLANK_BLANK;
793 }
794 if (c & 0x08) {
795 DPRINTK("Separate ");
796 specs->signal |= FB_SIGNAL_SEPARATE;
797 }
798 if (c & 0x04) {
799 DPRINTK("Composite ");
800 specs->signal |= FB_SIGNAL_COMPOSITE;
801 }
802 if (c & 0x02) {
803 DPRINTK("Sync on Green ");
804 specs->signal |= FB_SIGNAL_SYNC_ON_GREEN;
805 }
806 if (c & 0x01) {
807 DPRINTK("Serration on ");
808 specs->signal |= FB_SIGNAL_SERRATION_ON;
809 }
810 DPRINTK("\n");
811 specs->max_x = block[1];
812 specs->max_y = block[2];
813 DPRINTK(" Max H-size in cm: ");
814 if (specs->max_x)
815 DPRINTK("%d\n", specs->max_x);
816 else
817 DPRINTK("variable\n");
818 DPRINTK(" Max V-size in cm: ");
819 if (specs->max_y)
820 DPRINTK("%d\n", specs->max_y);
821 else
822 DPRINTK("variable\n");
823
824 c = block[3];
825 specs->gamma = c+100;
826 DPRINTK(" Gamma: ");
827 DPRINTK("%d.%d\n", specs->gamma/100, specs->gamma % 100);
828
829 get_dpms_capabilities(block[4], specs);
830
831 switch ((block[4] & 0x18) >> 3) {
832 case 0:
833 DPRINTK(" Monochrome/Grayscale\n");
834 specs->input |= FB_DISP_MONO;
835 break;
836 case 1:
837 DPRINTK(" RGB Color Display\n");
838 specs->input |= FB_DISP_RGB;
839 break;
840 case 2:
841 DPRINTK(" Non-RGB Multicolor Display\n");
842 specs->input |= FB_DISP_MULTI;
843 break;
844 default:
845 DPRINTK(" Unknown\n");
846 specs->input |= FB_DISP_UNKNOWN;
847 break;
848 }
849
850 get_chroma(block, specs);
851
852 specs->misc = 0;
853 c = block[4] & 0x7;
854 if (c & 0x04) {
855 DPRINTK(" Default color format is primary\n");
856 specs->misc |= FB_MISC_PRIM_COLOR;
857 }
858 if (c & 0x02) {
859 DPRINTK(" First DETAILED Timing is preferred\n");
860 specs->misc |= FB_MISC_1ST_DETAIL;
861 }
862 if (c & 0x01) {
863 printk(" Display is GTF capable\n");
864 specs->gtf = 1;
865 }
866}
867
868int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var)
869{
870 int i;
871 unsigned char *block;
872
873 if (edid == NULL || var == NULL)
874 return 1;
875
876 if (!(edid_checksum(edid)))
877 return 1;
878
879 if (!(edid_check_header(edid)))
880 return 1;
881
882 block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
883
884 for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {
885 if (edid_is_timing_block(block)) {
886 var->xres = var->xres_virtual = H_ACTIVE;
887 var->yres = var->yres_virtual = V_ACTIVE;
888 var->height = var->width = 0;
889 var->right_margin = H_SYNC_OFFSET;
890 var->left_margin = (H_ACTIVE + H_BLANKING) -
891 (H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH);
892 var->upper_margin = V_BLANKING - V_SYNC_OFFSET -
893 V_SYNC_WIDTH;
894 var->lower_margin = V_SYNC_OFFSET;
895 var->hsync_len = H_SYNC_WIDTH;
896 var->vsync_len = V_SYNC_WIDTH;
897 var->pixclock = PIXEL_CLOCK;
898 var->pixclock /= 1000;
899 var->pixclock = KHZ2PICOS(var->pixclock);
900
901 if (HSYNC_POSITIVE)
902 var->sync |= FB_SYNC_HOR_HIGH_ACT;
903 if (VSYNC_POSITIVE)
904 var->sync |= FB_SYNC_VERT_HIGH_ACT;
905 return 0;
906 }
907 }
908 return 1;
909}
910
911void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs)
912{
913 unsigned char *block;
914 int i, found = 0;
915
916 if (edid == NULL)
917 return;
918
919 if (!(edid_checksum(edid)))
920 return;
921
922 if (!(edid_check_header(edid)))
923 return;
924
925 memset(specs, 0, sizeof(struct fb_monspecs));
926
927 specs->version = edid[EDID_STRUCT_VERSION];
928 specs->revision = edid[EDID_STRUCT_REVISION];
929
930 DPRINTK("========================================\n");
931 DPRINTK("Display Information (EDID)\n");
932 DPRINTK("========================================\n");
933 DPRINTK(" EDID Version %d.%d\n", (int) specs->version,
934 (int) specs->revision);
935
936 parse_vendor_block(edid + ID_MANUFACTURER_NAME, specs);
937
938 block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
939 for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {
940 if (edid_is_serial_block(block)) {
941 copy_string(block, specs->serial_no);
942 DPRINTK(" Serial Number: %s\n", specs->serial_no);
943 } else if (edid_is_ascii_block(block)) {
944 copy_string(block, specs->ascii);
945 DPRINTK(" ASCII Block: %s\n", specs->ascii);
946 } else if (edid_is_monitor_block(block)) {
947 copy_string(block, specs->monitor);
948 DPRINTK(" Monitor Name: %s\n", specs->monitor);
949 }
950 }
951
952 DPRINTK(" Display Characteristics:\n");
953 get_monspecs(edid, specs);
954
955 specs->modedb = fb_create_modedb(edid, &specs->modedb_len);
956
957
958
959
960
961
962 for (i = 0; i < specs->modedb_len; i++) {
963 if (specs->modedb[i].flag & FB_MODE_IS_DETAILED) {
964 found = 1;
965 break;
966 }
967 }
968
969 if (!found)
970 specs->misc &= ~FB_MISC_1ST_DETAIL;
971
972 DPRINTK("========================================\n");
973}
974
975
976
977
978
979#define FLYBACK 550
980#define V_FRONTPORCH 1
981#define H_OFFSET 40
982#define H_SCALEFACTOR 20
983#define H_BLANKSCALE 128
984#define H_GRADIENT 600
985#define C_VAL 30
986#define M_VAL 300
987
988struct __fb_timings {
989 u32 dclk;
990 u32 hfreq;
991 u32 vfreq;
992 u32 hactive;
993 u32 vactive;
994 u32 hblank;
995 u32 vblank;
996 u32 htotal;
997 u32 vtotal;
998};
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015static u32 fb_get_vblank(u32 hfreq)
1016{
1017 u32 vblank;
1018
1019 vblank = (hfreq * FLYBACK)/1000;
1020 vblank = (vblank + 500)/1000;
1021 return (vblank + V_FRONTPORCH);
1022}
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044static u32 fb_get_hblank_by_hfreq(u32 hfreq, u32 xres)
1045{
1046 u32 c_val, m_val, duty_cycle, hblank;
1047
1048 c_val = (((H_OFFSET - H_SCALEFACTOR) * H_BLANKSCALE)/256 +
1049 H_SCALEFACTOR) * 1000;
1050 m_val = (H_BLANKSCALE * H_GRADIENT)/256;
1051 m_val = (m_val * 1000000)/hfreq;
1052 duty_cycle = c_val - m_val;
1053 hblank = (xres * duty_cycle)/(100000 - duty_cycle);
1054 return (hblank);
1055}
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078static u32 fb_get_hblank_by_dclk(u32 dclk, u32 xres)
1079{
1080 u32 duty_cycle, h_period, hblank;
1081
1082 dclk /= 1000;
1083 h_period = 100 - C_VAL;
1084 h_period *= h_period;
1085 h_period += (M_VAL * xres * 2 * 1000)/(5 * dclk);
1086 h_period *= 10000;
1087
1088 h_period = int_sqrt(h_period);
1089 h_period -= (100 - C_VAL) * 100;
1090 h_period *= 1000;
1091 h_period /= 2 * M_VAL;
1092
1093 duty_cycle = C_VAL * 1000 - (M_VAL * h_period)/100;
1094 hblank = (xres * duty_cycle)/(100000 - duty_cycle) + 8;
1095 hblank &= ~15;
1096 return (hblank);
1097}
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112static u32 fb_get_hfreq(u32 vfreq, u32 yres)
1113{
1114 u32 divisor, hfreq;
1115
1116 divisor = (1000000 - (vfreq * FLYBACK))/1000;
1117 hfreq = (yres + V_FRONTPORCH) * vfreq * 1000;
1118 return (hfreq/divisor);
1119}
1120
1121static void fb_timings_vfreq(struct __fb_timings *timings)
1122{
1123 timings->hfreq = fb_get_hfreq(timings->vfreq, timings->vactive);
1124 timings->vblank = fb_get_vblank(timings->hfreq);
1125 timings->vtotal = timings->vactive + timings->vblank;
1126 timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq,
1127 timings->hactive);
1128 timings->htotal = timings->hactive + timings->hblank;
1129 timings->dclk = timings->htotal * timings->hfreq;
1130}
1131
1132static void fb_timings_hfreq(struct __fb_timings *timings)
1133{
1134 timings->vblank = fb_get_vblank(timings->hfreq);
1135 timings->vtotal = timings->vactive + timings->vblank;
1136 timings->vfreq = timings->hfreq/timings->vtotal;
1137 timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq,
1138 timings->hactive);
1139 timings->htotal = timings->hactive + timings->hblank;
1140 timings->dclk = timings->htotal * timings->hfreq;
1141}
1142
1143static void fb_timings_dclk(struct __fb_timings *timings)
1144{
1145 timings->hblank = fb_get_hblank_by_dclk(timings->dclk,
1146 timings->hactive);
1147 timings->htotal = timings->hactive + timings->hblank;
1148 timings->hfreq = timings->dclk/timings->htotal;
1149 timings->vblank = fb_get_vblank(timings->hfreq);
1150 timings->vtotal = timings->vactive + timings->vblank;
1151 timings->vfreq = timings->hfreq/timings->vtotal;
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
1182
1183
1184
1185
1186
1187
1188int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_info *info)
1189{
1190 struct __fb_timings *timings;
1191 u32 interlace = 1, dscan = 1;
1192 u32 hfmin, hfmax, vfmin, vfmax, dclkmin, dclkmax, err = 0;
1193
1194
1195 timings = kzalloc(sizeof(struct __fb_timings), GFP_KERNEL);
1196
1197 if (!timings)
1198 return -ENOMEM;
1199
1200
1201
1202
1203
1204 if (!info || !info->monspecs.hfmax || !info->monspecs.vfmax ||
1205 !info->monspecs.dclkmax ||
1206 info->monspecs.hfmax < info->monspecs.hfmin ||
1207 info->monspecs.vfmax < info->monspecs.vfmin ||
1208 info->monspecs.dclkmax < info->monspecs.dclkmin) {
1209 hfmin = 29000; hfmax = 30000;
1210 vfmin = 60; vfmax = 60;
1211 dclkmin = 0; dclkmax = 25000000;
1212 } else {
1213 hfmin = info->monspecs.hfmin;
1214 hfmax = info->monspecs.hfmax;
1215 vfmin = info->monspecs.vfmin;
1216 vfmax = info->monspecs.vfmax;
1217 dclkmin = info->monspecs.dclkmin;
1218 dclkmax = info->monspecs.dclkmax;
1219 }
1220
1221 timings->hactive = var->xres;
1222 timings->vactive = var->yres;
1223 if (var->vmode & FB_VMODE_INTERLACED) {
1224 timings->vactive /= 2;
1225 interlace = 2;
1226 }
1227 if (var->vmode & FB_VMODE_DOUBLE) {
1228 timings->vactive *= 2;
1229 dscan = 2;
1230 }
1231
1232 switch (flags & ~FB_IGNOREMON) {
1233 case FB_MAXTIMINGS:
1234 timings->hfreq = hfmax;
1235 fb_timings_hfreq(timings);
1236 if (timings->vfreq > vfmax) {
1237 timings->vfreq = vfmax;
1238 fb_timings_vfreq(timings);
1239 }
1240 if (timings->dclk > dclkmax) {
1241 timings->dclk = dclkmax;
1242 fb_timings_dclk(timings);
1243 }
1244 break;
1245 case FB_VSYNCTIMINGS:
1246 timings->vfreq = val;
1247 fb_timings_vfreq(timings);
1248 break;
1249 case FB_HSYNCTIMINGS:
1250 timings->hfreq = val;
1251 fb_timings_hfreq(timings);
1252 break;
1253 case FB_DCLKTIMINGS:
1254 timings->dclk = PICOS2KHZ(val) * 1000;
1255 fb_timings_dclk(timings);
1256 break;
1257 default:
1258 err = -EINVAL;
1259
1260 }
1261
1262 if (err || (!(flags & FB_IGNOREMON) &&
1263 (timings->vfreq < vfmin || timings->vfreq > vfmax ||
1264 timings->hfreq < hfmin || timings->hfreq > hfmax ||
1265 timings->dclk < dclkmin || timings->dclk > dclkmax))) {
1266 err = -EINVAL;
1267 } else {
1268 var->pixclock = KHZ2PICOS(timings->dclk/1000);
1269 var->hsync_len = (timings->htotal * 8)/100;
1270 var->right_margin = (timings->hblank/2) - var->hsync_len;
1271 var->left_margin = timings->hblank - var->right_margin -
1272 var->hsync_len;
1273 var->vsync_len = (3 * interlace)/dscan;
1274 var->lower_margin = (1 * interlace)/dscan;
1275 var->upper_margin = (timings->vblank * interlace)/dscan -
1276 (var->vsync_len + var->lower_margin);
1277 }
1278
1279 kfree(timings);
1280 return err;
1281}
1282#else
1283int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var)
1284{
1285 return 1;
1286}
1287void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs)
1288{
1289 specs = NULL;
1290}
1291void fb_destroy_modedb(struct fb_videomode *modedb)
1292{
1293}
1294int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var,
1295 struct fb_info *info)
1296{
1297 return -EINVAL;
1298}
1299#endif
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313int fb_validate_mode(const struct fb_var_screeninfo *var, struct fb_info *info)
1314{
1315 u32 hfreq, vfreq, htotal, vtotal, pixclock;
1316 u32 hfmin, hfmax, vfmin, vfmax, dclkmin, dclkmax;
1317
1318
1319
1320
1321
1322 if (!info->monspecs.hfmax || !info->monspecs.vfmax ||
1323 !info->monspecs.dclkmax ||
1324 info->monspecs.hfmax < info->monspecs.hfmin ||
1325 info->monspecs.vfmax < info->monspecs.vfmin ||
1326 info->monspecs.dclkmax < info->monspecs.dclkmin) {
1327 hfmin = 29000; hfmax = 30000;
1328 vfmin = 60; vfmax = 60;
1329 dclkmin = 0; dclkmax = 25000000;
1330 } else {
1331 hfmin = info->monspecs.hfmin;
1332 hfmax = info->monspecs.hfmax;
1333 vfmin = info->monspecs.vfmin;
1334 vfmax = info->monspecs.vfmax;
1335 dclkmin = info->monspecs.dclkmin;
1336 dclkmax = info->monspecs.dclkmax;
1337 }
1338
1339 if (!var->pixclock)
1340 return -EINVAL;
1341 pixclock = PICOS2KHZ(var->pixclock) * 1000;
1342
1343 htotal = var->xres + var->right_margin + var->hsync_len +
1344 var->left_margin;
1345 vtotal = var->yres + var->lower_margin + var->vsync_len +
1346 var->upper_margin;
1347
1348 if (var->vmode & FB_VMODE_INTERLACED)
1349 vtotal /= 2;
1350 if (var->vmode & FB_VMODE_DOUBLE)
1351 vtotal *= 2;
1352
1353 hfreq = pixclock/htotal;
1354 hfreq = (hfreq + 500) / 1000 * 1000;
1355
1356 vfreq = hfreq/vtotal;
1357
1358 return (vfreq < vfmin || vfreq > vfmax ||
1359 hfreq < hfmin || hfreq > hfmax ||
1360 pixclock < dclkmin || pixclock > dclkmax) ?
1361 -EINVAL : 0;
1362}
1363
1364#if defined(CONFIG_FIRMWARE_EDID) && defined(CONFIG_X86)
1365
1366
1367
1368
1369
1370
1371const unsigned char *fb_firmware_edid(struct device *device)
1372{
1373 struct pci_dev *dev = NULL;
1374 struct resource *res = NULL;
1375 unsigned char *edid = NULL;
1376
1377 if (device)
1378 dev = to_pci_dev(device);
1379
1380 if (dev)
1381 res = &dev->resource[PCI_ROM_RESOURCE];
1382
1383 if (res && res->flags & IORESOURCE_ROM_SHADOW)
1384 edid = edid_info.dummy;
1385
1386 return edid;
1387}
1388#else
1389const unsigned char *fb_firmware_edid(struct device *device)
1390{
1391 return NULL;
1392}
1393#endif
1394EXPORT_SYMBOL(fb_firmware_edid);
1395
1396EXPORT_SYMBOL(fb_parse_edid);
1397EXPORT_SYMBOL(fb_edid_to_monspecs);
1398EXPORT_SYMBOL(fb_get_mode);
1399EXPORT_SYMBOL(fb_validate_mode);
1400EXPORT_SYMBOL(fb_destroy_modedb);