OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [video/] [fbmon.c] - Blame information for rev 62

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.