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