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