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
982
983
984
985
986
987 for (i = 0; i < specs->modedb_len; i++) {
988 if (specs->modedb[i].flag & FB_MODE_IS_DETAILED) {
989 found = 1;
990 break;
991 }
992 }
993
994 if (!found)
995 specs->misc &= ~FB_MISC_1ST_DETAIL;
996
997 DPRINTK("========================================\n");
998}
999
1000
1001
1002
1003
1004
1005void fb_edid_add_monspecs(unsigned char *edid, struct fb_monspecs *specs)
1006{
1007 unsigned char *block;
1008 struct fb_videomode *m;
1009 int num = 0, i;
1010 u8 svd[64], edt[(128 - 4) / DETAILED_TIMING_DESCRIPTION_SIZE];
1011 u8 pos = 4, svd_n = 0;
1012
1013 if (!edid)
1014 return;
1015
1016 if (!edid_checksum(edid))
1017 return;
1018
1019 if (edid[0] != 0x2 ||
1020 edid[2] < 4 || edid[2] > 128 - DETAILED_TIMING_DESCRIPTION_SIZE)
1021 return;
1022
1023 DPRINTK(" Short Video Descriptors\n");
1024
1025 while (pos < edid[2]) {
1026 u8 len = edid[pos] & 0x1f, type = (edid[pos] >> 5) & 7;
1027 pr_debug("Data block %u of %u bytes\n", type, len);
1028 if (type == 2) {
1029 for (i = pos; i < pos + len; i++) {
1030 u8 idx = edid[pos + i] & 0x7f;
1031 svd[svd_n++] = idx;
1032 pr_debug("N%sative mode #%d\n",
1033 edid[pos + i] & 0x80 ? "" : "on-n", idx);
1034 }
1035 } else if (type == 3 && len >= 3) {
1036
1037
1038 if (edid[pos + 1] == 3 && edid[pos + 2] == 0xc &&
1039 edid[pos + 3] == 0)
1040 specs->misc |= FB_MISC_HDMI;
1041 }
1042 pos += len + 1;
1043 }
1044
1045 block = edid + edid[2];
1046
1047 DPRINTK(" Extended Detailed Timings\n");
1048
1049 for (i = 0; i < (128 - edid[2]) / DETAILED_TIMING_DESCRIPTION_SIZE;
1050 i++, block += DETAILED_TIMING_DESCRIPTION_SIZE)
1051 if (PIXEL_CLOCK != 0)
1052 edt[num++] = block - edid;
1053
1054
1055 if (!(num + svd_n))
1056 return;
1057
1058 m = kcalloc(specs->modedb_len + num + svd_n,
1059 sizeof(struct fb_videomode),
1060 GFP_KERNEL);
1061
1062 if (!m)
1063 return;
1064
1065 memcpy(m, specs->modedb, specs->modedb_len * sizeof(struct fb_videomode));
1066
1067 for (i = specs->modedb_len; i < specs->modedb_len + num; i++) {
1068 get_detailed_timing(edid + edt[i - specs->modedb_len], &m[i]);
1069 if (i == specs->modedb_len)
1070 m[i].flag |= FB_MODE_IS_FIRST;
1071 pr_debug("Adding %ux%u@%u\n", m[i].xres, m[i].yres, m[i].refresh);
1072 }
1073
1074 for (i = specs->modedb_len + num; i < specs->modedb_len + num + svd_n; i++) {
1075 int idx = svd[i - specs->modedb_len - num];
1076 if (!idx || idx >= ARRAY_SIZE(cea_modes)) {
1077 pr_warn("Reserved SVD code %d\n", idx);
1078 } else if (!cea_modes[idx].xres) {
1079 pr_warn("Unimplemented SVD code %d\n", idx);
1080 } else {
1081 memcpy(&m[i], cea_modes + idx, sizeof(m[i]));
1082 pr_debug("Adding SVD #%d: %ux%u@%u\n", idx,
1083 m[i].xres, m[i].yres, m[i].refresh);
1084 }
1085 }
1086
1087 kfree(specs->modedb);
1088 specs->modedb = m;
1089 specs->modedb_len = specs->modedb_len + num + svd_n;
1090}
1091
1092
1093
1094
1095
1096#define FLYBACK 550
1097#define V_FRONTPORCH 1
1098#define H_OFFSET 40
1099#define H_SCALEFACTOR 20
1100#define H_BLANKSCALE 128
1101#define H_GRADIENT 600
1102#define C_VAL 30
1103#define M_VAL 300
1104
1105struct __fb_timings {
1106 u32 dclk;
1107 u32 hfreq;
1108 u32 vfreq;
1109 u32 hactive;
1110 u32 vactive;
1111 u32 hblank;
1112 u32 vblank;
1113 u32 htotal;
1114 u32 vtotal;
1115};
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132static u32 fb_get_vblank(u32 hfreq)
1133{
1134 u32 vblank;
1135
1136 vblank = (hfreq * FLYBACK)/1000;
1137 vblank = (vblank + 500)/1000;
1138 return (vblank + V_FRONTPORCH);
1139}
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161static u32 fb_get_hblank_by_hfreq(u32 hfreq, u32 xres)
1162{
1163 u32 c_val, m_val, duty_cycle, hblank;
1164
1165 c_val = (((H_OFFSET - H_SCALEFACTOR) * H_BLANKSCALE)/256 +
1166 H_SCALEFACTOR) * 1000;
1167 m_val = (H_BLANKSCALE * H_GRADIENT)/256;
1168 m_val = (m_val * 1000000)/hfreq;
1169 duty_cycle = c_val - m_val;
1170 hblank = (xres * duty_cycle)/(100000 - duty_cycle);
1171 return (hblank);
1172}
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195static u32 fb_get_hblank_by_dclk(u32 dclk, u32 xres)
1196{
1197 u32 duty_cycle, h_period, hblank;
1198
1199 dclk /= 1000;
1200 h_period = 100 - C_VAL;
1201 h_period *= h_period;
1202 h_period += (M_VAL * xres * 2 * 1000)/(5 * dclk);
1203 h_period *= 10000;
1204
1205 h_period = int_sqrt(h_period);
1206 h_period -= (100 - C_VAL) * 100;
1207 h_period *= 1000;
1208 h_period /= 2 * M_VAL;
1209
1210 duty_cycle = C_VAL * 1000 - (M_VAL * h_period)/100;
1211 hblank = (xres * duty_cycle)/(100000 - duty_cycle) + 8;
1212 hblank &= ~15;
1213 return (hblank);
1214}
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229static u32 fb_get_hfreq(u32 vfreq, u32 yres)
1230{
1231 u32 divisor, hfreq;
1232
1233 divisor = (1000000 - (vfreq * FLYBACK))/1000;
1234 hfreq = (yres + V_FRONTPORCH) * vfreq * 1000;
1235 return (hfreq/divisor);
1236}
1237
1238static void fb_timings_vfreq(struct __fb_timings *timings)
1239{
1240 timings->hfreq = fb_get_hfreq(timings->vfreq, timings->vactive);
1241 timings->vblank = fb_get_vblank(timings->hfreq);
1242 timings->vtotal = timings->vactive + timings->vblank;
1243 timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq,
1244 timings->hactive);
1245 timings->htotal = timings->hactive + timings->hblank;
1246 timings->dclk = timings->htotal * timings->hfreq;
1247}
1248
1249static void fb_timings_hfreq(struct __fb_timings *timings)
1250{
1251 timings->vblank = fb_get_vblank(timings->hfreq);
1252 timings->vtotal = timings->vactive + timings->vblank;
1253 timings->vfreq = timings->hfreq/timings->vtotal;
1254 timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq,
1255 timings->hactive);
1256 timings->htotal = timings->hactive + timings->hblank;
1257 timings->dclk = timings->htotal * timings->hfreq;
1258}
1259
1260static void fb_timings_dclk(struct __fb_timings *timings)
1261{
1262 timings->hblank = fb_get_hblank_by_dclk(timings->dclk,
1263 timings->hactive);
1264 timings->htotal = timings->hactive + timings->hblank;
1265 timings->hfreq = timings->dclk/timings->htotal;
1266 timings->vblank = fb_get_vblank(timings->hfreq);
1267 timings->vtotal = timings->vactive + timings->vblank;
1268 timings->vfreq = timings->hfreq/timings->vtotal;
1269}
1270
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
1305int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_info *info)
1306{
1307 struct __fb_timings *timings;
1308 u32 interlace = 1, dscan = 1;
1309 u32 hfmin, hfmax, vfmin, vfmax, dclkmin, dclkmax, err = 0;
1310
1311
1312 timings = kzalloc(sizeof(struct __fb_timings), GFP_KERNEL);
1313
1314 if (!timings)
1315 return -ENOMEM;
1316
1317
1318
1319
1320
1321 if (!info || !info->monspecs.hfmax || !info->monspecs.vfmax ||
1322 !info->monspecs.dclkmax ||
1323 info->monspecs.hfmax < info->monspecs.hfmin ||
1324 info->monspecs.vfmax < info->monspecs.vfmin ||
1325 info->monspecs.dclkmax < info->monspecs.dclkmin) {
1326 hfmin = 29000; hfmax = 30000;
1327 vfmin = 60; vfmax = 60;
1328 dclkmin = 0; dclkmax = 25000000;
1329 } else {
1330 hfmin = info->monspecs.hfmin;
1331 hfmax = info->monspecs.hfmax;
1332 vfmin = info->monspecs.vfmin;
1333 vfmax = info->monspecs.vfmax;
1334 dclkmin = info->monspecs.dclkmin;
1335 dclkmax = info->monspecs.dclkmax;
1336 }
1337
1338 timings->hactive = var->xres;
1339 timings->vactive = var->yres;
1340 if (var->vmode & FB_VMODE_INTERLACED) {
1341 timings->vactive /= 2;
1342 interlace = 2;
1343 }
1344 if (var->vmode & FB_VMODE_DOUBLE) {
1345 timings->vactive *= 2;
1346 dscan = 2;
1347 }
1348
1349 switch (flags & ~FB_IGNOREMON) {
1350 case FB_MAXTIMINGS:
1351 timings->hfreq = hfmax;
1352 fb_timings_hfreq(timings);
1353 if (timings->vfreq > vfmax) {
1354 timings->vfreq = vfmax;
1355 fb_timings_vfreq(timings);
1356 }
1357 if (timings->dclk > dclkmax) {
1358 timings->dclk = dclkmax;
1359 fb_timings_dclk(timings);
1360 }
1361 break;
1362 case FB_VSYNCTIMINGS:
1363 timings->vfreq = val;
1364 fb_timings_vfreq(timings);
1365 break;
1366 case FB_HSYNCTIMINGS:
1367 timings->hfreq = val;
1368 fb_timings_hfreq(timings);
1369 break;
1370 case FB_DCLKTIMINGS:
1371 timings->dclk = PICOS2KHZ(val) * 1000;
1372 fb_timings_dclk(timings);
1373 break;
1374 default:
1375 err = -EINVAL;
1376
1377 }
1378
1379 if (err || (!(flags & FB_IGNOREMON) &&
1380 (timings->vfreq < vfmin || timings->vfreq > vfmax ||
1381 timings->hfreq < hfmin || timings->hfreq > hfmax ||
1382 timings->dclk < dclkmin || timings->dclk > dclkmax))) {
1383 err = -EINVAL;
1384 } else {
1385 var->pixclock = KHZ2PICOS(timings->dclk/1000);
1386 var->hsync_len = (timings->htotal * 8)/100;
1387 var->right_margin = (timings->hblank/2) - var->hsync_len;
1388 var->left_margin = timings->hblank - var->right_margin -
1389 var->hsync_len;
1390 var->vsync_len = (3 * interlace)/dscan;
1391 var->lower_margin = (1 * interlace)/dscan;
1392 var->upper_margin = (timings->vblank * interlace)/dscan -
1393 (var->vsync_len + var->lower_margin);
1394 }
1395
1396 kfree(timings);
1397 return err;
1398}
1399
1400#ifdef CONFIG_VIDEOMODE_HELPERS
1401int fb_videomode_from_videomode(const struct videomode *vm,
1402 struct fb_videomode *fbmode)
1403{
1404 unsigned int htotal, vtotal;
1405
1406 fbmode->xres = vm->hactive;
1407 fbmode->left_margin = vm->hback_porch;
1408 fbmode->right_margin = vm->hfront_porch;
1409 fbmode->hsync_len = vm->hsync_len;
1410
1411 fbmode->yres = vm->vactive;
1412 fbmode->upper_margin = vm->vback_porch;
1413 fbmode->lower_margin = vm->vfront_porch;
1414 fbmode->vsync_len = vm->vsync_len;
1415
1416
1417 fbmode->pixclock = vm->pixelclock ?
1418 KHZ2PICOS(vm->pixelclock / 1000) : 0;
1419
1420 fbmode->sync = 0;
1421 fbmode->vmode = 0;
1422 if (vm->flags & DISPLAY_FLAGS_HSYNC_HIGH)
1423 fbmode->sync |= FB_SYNC_HOR_HIGH_ACT;
1424 if (vm->flags & DISPLAY_FLAGS_VSYNC_HIGH)
1425 fbmode->sync |= FB_SYNC_VERT_HIGH_ACT;
1426 if (vm->flags & DISPLAY_FLAGS_INTERLACED)
1427 fbmode->vmode |= FB_VMODE_INTERLACED;
1428 if (vm->flags & DISPLAY_FLAGS_DOUBLESCAN)
1429 fbmode->vmode |= FB_VMODE_DOUBLE;
1430 fbmode->flag = 0;
1431
1432 htotal = vm->hactive + vm->hfront_porch + vm->hback_porch +
1433 vm->hsync_len;
1434 vtotal = vm->vactive + vm->vfront_porch + vm->vback_porch +
1435 vm->vsync_len;
1436
1437 if (htotal && vtotal) {
1438 fbmode->refresh = vm->pixelclock / (htotal * vtotal);
1439
1440 } else {
1441 fbmode->refresh = 0;
1442 return -EINVAL;
1443 }
1444
1445 return 0;
1446}
1447EXPORT_SYMBOL_GPL(fb_videomode_from_videomode);
1448
1449#ifdef CONFIG_OF
1450static inline void dump_fb_videomode(const struct fb_videomode *m)
1451{
1452 pr_debug("fb_videomode = %ux%u@%uHz (%ukHz) %u %u %u %u %u %u %u %u %u\n",
1453 m->xres, m->yres, m->refresh, m->pixclock, m->left_margin,
1454 m->right_margin, m->upper_margin, m->lower_margin,
1455 m->hsync_len, m->vsync_len, m->sync, m->vmode, m->flag);
1456}
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469int of_get_fb_videomode(struct device_node *np, struct fb_videomode *fb,
1470 int index)
1471{
1472 struct videomode vm;
1473 int ret;
1474
1475 ret = of_get_videomode(np, &vm, index);
1476 if (ret)
1477 return ret;
1478
1479 ret = fb_videomode_from_videomode(&vm, fb);
1480 if (ret)
1481 return ret;
1482
1483 pr_debug("%pOF: got %dx%d display mode from %s\n",
1484 np, vm.hactive, vm.vactive, np->name);
1485 dump_fb_videomode(fb);
1486
1487 return 0;
1488}
1489EXPORT_SYMBOL_GPL(of_get_fb_videomode);
1490#endif
1491#endif
1492
1493#else
1494int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var)
1495{
1496 return 1;
1497}
1498void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs)
1499{
1500}
1501void fb_edid_add_monspecs(unsigned char *edid, struct fb_monspecs *specs)
1502{
1503}
1504void fb_destroy_modedb(struct fb_videomode *modedb)
1505{
1506}
1507int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var,
1508 struct fb_info *info)
1509{
1510 return -EINVAL;
1511}
1512#endif
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526int fb_validate_mode(const struct fb_var_screeninfo *var, struct fb_info *info)
1527{
1528 u32 hfreq, vfreq, htotal, vtotal, pixclock;
1529 u32 hfmin, hfmax, vfmin, vfmax, dclkmin, dclkmax;
1530
1531
1532
1533
1534
1535 if (!info->monspecs.hfmax || !info->monspecs.vfmax ||
1536 !info->monspecs.dclkmax ||
1537 info->monspecs.hfmax < info->monspecs.hfmin ||
1538 info->monspecs.vfmax < info->monspecs.vfmin ||
1539 info->monspecs.dclkmax < info->monspecs.dclkmin) {
1540 hfmin = 29000; hfmax = 30000;
1541 vfmin = 60; vfmax = 60;
1542 dclkmin = 0; dclkmax = 25000000;
1543 } else {
1544 hfmin = info->monspecs.hfmin;
1545 hfmax = info->monspecs.hfmax;
1546 vfmin = info->monspecs.vfmin;
1547 vfmax = info->monspecs.vfmax;
1548 dclkmin = info->monspecs.dclkmin;
1549 dclkmax = info->monspecs.dclkmax;
1550 }
1551
1552 if (!var->pixclock)
1553 return -EINVAL;
1554 pixclock = PICOS2KHZ(var->pixclock) * 1000;
1555
1556 htotal = var->xres + var->right_margin + var->hsync_len +
1557 var->left_margin;
1558 vtotal = var->yres + var->lower_margin + var->vsync_len +
1559 var->upper_margin;
1560
1561 if (var->vmode & FB_VMODE_INTERLACED)
1562 vtotal /= 2;
1563 if (var->vmode & FB_VMODE_DOUBLE)
1564 vtotal *= 2;
1565
1566 hfreq = pixclock/htotal;
1567 hfreq = (hfreq + 500) / 1000 * 1000;
1568
1569 vfreq = hfreq/vtotal;
1570
1571 return (vfreq < vfmin || vfreq > vfmax ||
1572 hfreq < hfmin || hfreq > hfmax ||
1573 pixclock < dclkmin || pixclock > dclkmax) ?
1574 -EINVAL : 0;
1575}
1576
1577#if defined(CONFIG_FIRMWARE_EDID) && defined(CONFIG_X86)
1578
1579
1580
1581
1582
1583
1584const unsigned char *fb_firmware_edid(struct device *device)
1585{
1586 struct pci_dev *dev = NULL;
1587 struct resource *res = NULL;
1588 unsigned char *edid = NULL;
1589
1590 if (device)
1591 dev = to_pci_dev(device);
1592
1593 if (dev)
1594 res = &dev->resource[PCI_ROM_RESOURCE];
1595
1596 if (res && res->flags & IORESOURCE_ROM_SHADOW)
1597 edid = edid_info.dummy;
1598
1599 return edid;
1600}
1601#else
1602const unsigned char *fb_firmware_edid(struct device *device)
1603{
1604 return NULL;
1605}
1606#endif
1607EXPORT_SYMBOL(fb_firmware_edid);
1608
1609EXPORT_SYMBOL(fb_parse_edid);
1610EXPORT_SYMBOL(fb_edid_to_monspecs);
1611EXPORT_SYMBOL(fb_edid_add_monspecs);
1612EXPORT_SYMBOL(fb_get_mode);
1613EXPORT_SYMBOL(fb_validate_mode);
1614EXPORT_SYMBOL(fb_destroy_modedb);
1615