2 * linux/drivers/video/fbmon.c
4 * Copyright (C) 2002 James Simmons <jsimmons@users.sf.net>
8 * The EDID Parser is a conglomeration from the following sources:
10 * 1. SciTech SNAP Graphics Architecture
11 * Copyright (C) 1991-2002 SciTech Software, Inc. All rights reserved.
13 * 2. XFree86 4.3.0, interpret_edid.c
14 * Copyright 1998 by Egbert Eich <Egbert.Eich@Physik.TU-Darmstadt.DE>
16 * 3. John Fremlin <vii@users.sourceforge.net> and
17 * Ani Joshi <ajoshi@unixbox.com>
19 * Generalized Timing Formula is derived from:
21 * GTF Spreadsheet by Andy Morrish (1/5/97)
22 * available at http://www.vesa.org
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
30 #include <linux/module.h>
31 #include <linux/pci.h>
32 #include <linux/slab.h>
33 #include <video/edid.h>
34 #include <video/of_videomode.h>
35 #include <video/videomode.h>
38 #include <asm/pci-bridge.h>
46 #undef DEBUG /* define this for verbose EDID parsing output */
49 #define DPRINTK(fmt, args...) printk(fmt,## args)
51 #define DPRINTK(fmt, args...)
54 #define FBMON_FIX_HEADER 1
55 #define FBMON_FIX_INPUT 2
56 #define FBMON_FIX_TIMINGS 3
58 #ifdef CONFIG_FB_MODE_HELPERS
65 static const struct broken_edid brokendb
[] = {
68 .manufacturer
= "DEC",
70 .fix
= FBMON_FIX_HEADER
,
72 /* ViewSonic PF775a */
74 .manufacturer
= "VSC",
76 .fix
= FBMON_FIX_INPUT
,
80 .manufacturer
= "SHP",
82 .fix
= FBMON_FIX_TIMINGS
,
86 static const unsigned char edid_v1_header
[] = { 0x00, 0xff, 0xff, 0xff,
87 0xff, 0xff, 0xff, 0x00
90 static void copy_string(unsigned char *c
, unsigned char *s
)
94 for (i
= 0; (i
< 13 && *c
!= 0x0A); i
++)
97 while (i
-- && (*--s
== 0x20)) *s
= 0;
100 static int edid_is_serial_block(unsigned char *block
)
102 if ((block
[0] == 0x00) && (block
[1] == 0x00) &&
103 (block
[2] == 0x00) && (block
[3] == 0xff) &&
110 static int edid_is_ascii_block(unsigned char *block
)
112 if ((block
[0] == 0x00) && (block
[1] == 0x00) &&
113 (block
[2] == 0x00) && (block
[3] == 0xfe) &&
120 static int edid_is_limits_block(unsigned char *block
)
122 if ((block
[0] == 0x00) && (block
[1] == 0x00) &&
123 (block
[2] == 0x00) && (block
[3] == 0xfd) &&
130 static int edid_is_monitor_block(unsigned char *block
)
132 if ((block
[0] == 0x00) && (block
[1] == 0x00) &&
133 (block
[2] == 0x00) && (block
[3] == 0xfc) &&
140 static int edid_is_timing_block(unsigned char *block
)
142 if ((block
[0] != 0x00) || (block
[1] != 0x00) ||
143 (block
[2] != 0x00) || (block
[4] != 0x00))
149 static int check_edid(unsigned char *edid
)
151 unsigned char *block
= edid
+ ID_MANUFACTURER_NAME
, manufacturer
[4];
154 int i
, fix
= 0, ret
= 0;
156 manufacturer
[0] = ((block
[0] & 0x7c) >> 2) + '@';
157 manufacturer
[1] = ((block
[0] & 0x03) << 3) +
158 ((block
[1] & 0xe0) >> 5) + '@';
159 manufacturer
[2] = (block
[1] & 0x1f) + '@';
161 model
= block
[2] + (block
[3] << 8);
163 for (i
= 0; i
< ARRAY_SIZE(brokendb
); i
++) {
164 if (!strncmp(manufacturer
, brokendb
[i
].manufacturer
, 4) &&
165 brokendb
[i
].model
== model
) {
166 fix
= brokendb
[i
].fix
;
172 case FBMON_FIX_HEADER
:
173 for (i
= 0; i
< 8; i
++) {
174 if (edid
[i
] != edid_v1_header
[i
]) {
180 case FBMON_FIX_INPUT
:
181 b
= edid
+ EDID_STRUCT_DISPLAY
;
182 /* Only if display is GTF capable will
183 the input type be reset to analog */
184 if (b
[4] & 0x01 && b
[0] & 0x80)
187 case FBMON_FIX_TIMINGS
:
188 b
= edid
+ DETAILED_TIMING_DESCRIPTIONS_START
;
191 for (i
= 0; i
< 4; i
++) {
192 if (edid_is_limits_block(b
)) {
197 b
+= DETAILED_TIMING_DESCRIPTION_SIZE
;
204 printk("fbmon: The EDID Block of "
205 "Manufacturer: %s Model: 0x%x is known to "
206 "be broken,\n", manufacturer
, model
);
211 static void fix_edid(unsigned char *edid
, int fix
)
214 unsigned char *b
, csum
= 0;
217 case FBMON_FIX_HEADER
:
218 printk("fbmon: trying a header reconstruct\n");
219 memcpy(edid
, edid_v1_header
, 8);
221 case FBMON_FIX_INPUT
:
222 printk("fbmon: trying to fix input type\n");
223 b
= edid
+ EDID_STRUCT_DISPLAY
;
227 case FBMON_FIX_TIMINGS
:
228 printk("fbmon: trying to fix monitor timings\n");
229 b
= edid
+ DETAILED_TIMING_DESCRIPTIONS_START
;
230 for (i
= 0; i
< 4; i
++) {
231 if (!(edid_is_serial_block(b
) ||
232 edid_is_ascii_block(b
) ||
233 edid_is_monitor_block(b
) ||
234 edid_is_timing_block(b
))) {
240 b
[5] = 60; /* vfmin */
241 b
[6] = 60; /* vfmax */
242 b
[7] = 30; /* hfmin */
243 b
[8] = 75; /* hfmax */
244 b
[9] = 17; /* pixclock - 170 MHz*/
249 b
+= DETAILED_TIMING_DESCRIPTION_SIZE
;
252 for (i
= 0; i
< EDID_LENGTH
- 1; i
++)
255 edid
[127] = 256 - csum
;
260 static int edid_checksum(unsigned char *edid
)
262 unsigned char csum
= 0, all_null
= 0;
263 int i
, err
= 0, fix
= check_edid(edid
);
268 for (i
= 0; i
< EDID_LENGTH
; i
++) {
273 if (csum
== 0x00 && all_null
) {
274 /* checksum passed, everything's good */
281 static int edid_check_header(unsigned char *edid
)
283 int i
, err
= 1, fix
= check_edid(edid
);
288 for (i
= 0; i
< 8; i
++) {
289 if (edid
[i
] != edid_v1_header
[i
])
296 static void parse_vendor_block(unsigned char *block
, struct fb_monspecs
*specs
)
298 specs
->manufacturer
[0] = ((block
[0] & 0x7c) >> 2) + '@';
299 specs
->manufacturer
[1] = ((block
[0] & 0x03) << 3) +
300 ((block
[1] & 0xe0) >> 5) + '@';
301 specs
->manufacturer
[2] = (block
[1] & 0x1f) + '@';
302 specs
->manufacturer
[3] = 0;
303 specs
->model
= block
[2] + (block
[3] << 8);
304 specs
->serial
= block
[4] + (block
[5] << 8) +
305 (block
[6] << 16) + (block
[7] << 24);
306 specs
->year
= block
[9] + 1990;
307 specs
->week
= block
[8];
308 DPRINTK(" Manufacturer: %s\n", specs
->manufacturer
);
309 DPRINTK(" Model: %x\n", specs
->model
);
310 DPRINTK(" Serial#: %u\n", specs
->serial
);
311 DPRINTK(" Year: %u Week %u\n", specs
->year
, specs
->week
);
314 static void get_dpms_capabilities(unsigned char flags
,
315 struct fb_monspecs
*specs
)
318 if (flags
& DPMS_ACTIVE_OFF
)
319 specs
->dpms
|= FB_DPMS_ACTIVE_OFF
;
320 if (flags
& DPMS_SUSPEND
)
321 specs
->dpms
|= FB_DPMS_SUSPEND
;
322 if (flags
& DPMS_STANDBY
)
323 specs
->dpms
|= FB_DPMS_STANDBY
;
324 DPRINTK(" DPMS: Active %s, Suspend %s, Standby %s\n",
325 (flags
& DPMS_ACTIVE_OFF
) ? "yes" : "no",
326 (flags
& DPMS_SUSPEND
) ? "yes" : "no",
327 (flags
& DPMS_STANDBY
) ? "yes" : "no");
330 static void get_chroma(unsigned char *block
, struct fb_monspecs
*specs
)
334 DPRINTK(" Chroma\n");
335 /* Chromaticity data */
336 tmp
= ((block
[5] & (3 << 6)) >> 6) | (block
[0x7] << 2);
339 specs
->chroma
.redx
= tmp
/1024;
340 DPRINTK(" RedX: 0.%03d ", specs
->chroma
.redx
);
342 tmp
= ((block
[5] & (3 << 4)) >> 4) | (block
[0x8] << 2);
345 specs
->chroma
.redy
= tmp
/1024;
346 DPRINTK("RedY: 0.%03d\n", specs
->chroma
.redy
);
348 tmp
= ((block
[5] & (3 << 2)) >> 2) | (block
[0x9] << 2);
351 specs
->chroma
.greenx
= tmp
/1024;
352 DPRINTK(" GreenX: 0.%03d ", specs
->chroma
.greenx
);
354 tmp
= (block
[5] & 3) | (block
[0xa] << 2);
357 specs
->chroma
.greeny
= tmp
/1024;
358 DPRINTK("GreenY: 0.%03d\n", specs
->chroma
.greeny
);
360 tmp
= ((block
[6] & (3 << 6)) >> 6) | (block
[0xb] << 2);
363 specs
->chroma
.bluex
= tmp
/1024;
364 DPRINTK(" BlueX: 0.%03d ", specs
->chroma
.bluex
);
366 tmp
= ((block
[6] & (3 << 4)) >> 4) | (block
[0xc] << 2);
369 specs
->chroma
.bluey
= tmp
/1024;
370 DPRINTK("BlueY: 0.%03d\n", specs
->chroma
.bluey
);
372 tmp
= ((block
[6] & (3 << 2)) >> 2) | (block
[0xd] << 2);
375 specs
->chroma
.whitex
= tmp
/1024;
376 DPRINTK(" WhiteX: 0.%03d ", specs
->chroma
.whitex
);
378 tmp
= (block
[6] & 3) | (block
[0xe] << 2);
381 specs
->chroma
.whitey
= tmp
/1024;
382 DPRINTK("WhiteY: 0.%03d\n", specs
->chroma
.whitey
);
385 static void calc_mode_timings(int xres
, int yres
, int refresh
,
386 struct fb_videomode
*mode
)
388 struct fb_var_screeninfo
*var
;
390 var
= kzalloc(sizeof(struct fb_var_screeninfo
), GFP_KERNEL
);
395 fb_get_mode(FB_VSYNCTIMINGS
| FB_IGNOREMON
,
399 mode
->pixclock
= var
->pixclock
;
400 mode
->refresh
= refresh
;
401 mode
->left_margin
= var
->left_margin
;
402 mode
->right_margin
= var
->right_margin
;
403 mode
->upper_margin
= var
->upper_margin
;
404 mode
->lower_margin
= var
->lower_margin
;
405 mode
->hsync_len
= var
->hsync_len
;
406 mode
->vsync_len
= var
->vsync_len
;
413 static int get_est_timing(unsigned char *block
, struct fb_videomode
*mode
)
420 calc_mode_timings(720, 400, 70, &mode
[num
]);
421 mode
[num
++].flag
= FB_MODE_IS_CALCULATED
;
422 DPRINTK(" 720x400@70Hz\n");
425 calc_mode_timings(720, 400, 88, &mode
[num
]);
426 mode
[num
++].flag
= FB_MODE_IS_CALCULATED
;
427 DPRINTK(" 720x400@88Hz\n");
430 mode
[num
++] = vesa_modes
[3];
431 DPRINTK(" 640x480@60Hz\n");
434 calc_mode_timings(640, 480, 67, &mode
[num
]);
435 mode
[num
++].flag
= FB_MODE_IS_CALCULATED
;
436 DPRINTK(" 640x480@67Hz\n");
439 mode
[num
++] = vesa_modes
[4];
440 DPRINTK(" 640x480@72Hz\n");
443 mode
[num
++] = vesa_modes
[5];
444 DPRINTK(" 640x480@75Hz\n");
447 mode
[num
++] = vesa_modes
[7];
448 DPRINTK(" 800x600@56Hz\n");
451 mode
[num
++] = vesa_modes
[8];
452 DPRINTK(" 800x600@60Hz\n");
457 mode
[num
++] = vesa_modes
[9];
458 DPRINTK(" 800x600@72Hz\n");
461 mode
[num
++] = vesa_modes
[10];
462 DPRINTK(" 800x600@75Hz\n");
465 calc_mode_timings(832, 624, 75, &mode
[num
]);
466 mode
[num
++].flag
= FB_MODE_IS_CALCULATED
;
467 DPRINTK(" 832x624@75Hz\n");
470 mode
[num
++] = vesa_modes
[12];
471 DPRINTK(" 1024x768@87Hz Interlaced\n");
474 mode
[num
++] = vesa_modes
[13];
475 DPRINTK(" 1024x768@60Hz\n");
478 mode
[num
++] = vesa_modes
[14];
479 DPRINTK(" 1024x768@70Hz\n");
482 mode
[num
++] = vesa_modes
[15];
483 DPRINTK(" 1024x768@75Hz\n");
486 mode
[num
++] = vesa_modes
[21];
487 DPRINTK(" 1280x1024@75Hz\n");
491 mode
[num
++] = vesa_modes
[17];
492 DPRINTK(" 1152x870@75Hz\n");
494 DPRINTK(" Manufacturer's mask: %x\n",c
&0x7F);
498 static int get_std_timing(unsigned char *block
, struct fb_videomode
*mode
,
501 int xres
, yres
= 0, refresh
, ratio
, i
;
503 xres
= (block
[0] + 31) * 8;
507 ratio
= (block
[1] & 0xc0) >> 6;
510 /* in EDID 1.3 the meaning of 0 changed to 16:10 (prior 1:1) */
511 if (ver
< 1 || (ver
== 1 && rev
< 3))
514 yres
= (xres
* 10)/16;
523 yres
= (xres
* 9)/16;
526 refresh
= (block
[1] & 0x3f) + 60;
528 DPRINTK(" %dx%d@%dHz\n", xres
, yres
, refresh
);
529 for (i
= 0; i
< VESA_MODEDB_SIZE
; i
++) {
530 if (vesa_modes
[i
].xres
== xres
&&
531 vesa_modes
[i
].yres
== yres
&&
532 vesa_modes
[i
].refresh
== refresh
) {
533 *mode
= vesa_modes
[i
];
534 mode
->flag
|= FB_MODE_IS_STANDARD
;
538 calc_mode_timings(xres
, yres
, refresh
, mode
);
542 static int get_dst_timing(unsigned char *block
,
543 struct fb_videomode
*mode
, int ver
, int rev
)
547 for (j
= 0; j
< 6; j
++, block
+= STD_TIMING_DESCRIPTION_SIZE
)
548 num
+= get_std_timing(block
, &mode
[num
], ver
, rev
);
553 static void get_detailed_timing(unsigned char *block
,
554 struct fb_videomode
*mode
)
556 mode
->xres
= H_ACTIVE
;
557 mode
->yres
= V_ACTIVE
;
558 mode
->pixclock
= PIXEL_CLOCK
;
559 mode
->pixclock
/= 1000;
560 mode
->pixclock
= KHZ2PICOS(mode
->pixclock
);
561 mode
->right_margin
= H_SYNC_OFFSET
;
562 mode
->left_margin
= (H_ACTIVE
+ H_BLANKING
) -
563 (H_ACTIVE
+ H_SYNC_OFFSET
+ H_SYNC_WIDTH
);
564 mode
->upper_margin
= V_BLANKING
- V_SYNC_OFFSET
-
566 mode
->lower_margin
= V_SYNC_OFFSET
;
567 mode
->hsync_len
= H_SYNC_WIDTH
;
568 mode
->vsync_len
= V_SYNC_WIDTH
;
570 mode
->sync
|= FB_SYNC_HOR_HIGH_ACT
;
572 mode
->sync
|= FB_SYNC_VERT_HIGH_ACT
;
573 mode
->refresh
= PIXEL_CLOCK
/((H_ACTIVE
+ H_BLANKING
) *
574 (V_ACTIVE
+ V_BLANKING
));
577 mode
->upper_margin
*= 2;
578 mode
->lower_margin
*= 2;
579 mode
->vsync_len
*= 2;
580 mode
->vmode
|= FB_VMODE_INTERLACED
;
582 mode
->flag
= FB_MODE_IS_DETAILED
;
584 DPRINTK(" %d MHz ", PIXEL_CLOCK
/1000000);
585 DPRINTK("%d %d %d %d ", H_ACTIVE
, H_ACTIVE
+ H_SYNC_OFFSET
,
586 H_ACTIVE
+ H_SYNC_OFFSET
+ H_SYNC_WIDTH
, H_ACTIVE
+ H_BLANKING
);
587 DPRINTK("%d %d %d %d ", V_ACTIVE
, V_ACTIVE
+ V_SYNC_OFFSET
,
588 V_ACTIVE
+ V_SYNC_OFFSET
+ V_SYNC_WIDTH
, V_ACTIVE
+ V_BLANKING
);
589 DPRINTK("%sHSync %sVSync\n\n", (HSYNC_POSITIVE
) ? "+" : "-",
590 (VSYNC_POSITIVE
) ? "+" : "-");
594 * fb_create_modedb - create video mode database
596 * @dbsize: database size
598 * RETURNS: struct fb_videomode, @dbsize contains length of database
601 * This function builds a mode database using the contents of the EDID
604 static struct fb_videomode
*fb_create_modedb(unsigned char *edid
, int *dbsize
)
606 struct fb_videomode
*mode
, *m
;
607 unsigned char *block
;
608 int num
= 0, i
, first
= 1;
611 ver
= edid
[EDID_STRUCT_VERSION
];
612 rev
= edid
[EDID_STRUCT_REVISION
];
614 mode
= kzalloc(50 * sizeof(struct fb_videomode
), GFP_KERNEL
);
618 if (edid
== NULL
|| !edid_checksum(edid
) ||
619 !edid_check_header(edid
)) {
626 DPRINTK(" Detailed Timings\n");
627 block
= edid
+ DETAILED_TIMING_DESCRIPTIONS_START
;
628 for (i
= 0; i
< 4; i
++, block
+= DETAILED_TIMING_DESCRIPTION_SIZE
) {
629 if (!(block
[0] == 0x00 && block
[1] == 0x00)) {
630 get_detailed_timing(block
, &mode
[num
]);
632 mode
[num
].flag
|= FB_MODE_IS_FIRST
;
639 DPRINTK(" Supported VESA Modes\n");
640 block
= edid
+ ESTABLISHED_TIMING_1
;
641 num
+= get_est_timing(block
, &mode
[num
]);
643 DPRINTK(" Standard Timings\n");
644 block
= edid
+ STD_TIMING_DESCRIPTIONS_START
;
645 for (i
= 0; i
< STD_TIMING
; i
++, block
+= STD_TIMING_DESCRIPTION_SIZE
)
646 num
+= get_std_timing(block
, &mode
[num
], ver
, rev
);
648 block
= edid
+ DETAILED_TIMING_DESCRIPTIONS_START
;
649 for (i
= 0; i
< 4; i
++, block
+= DETAILED_TIMING_DESCRIPTION_SIZE
) {
650 if (block
[0] == 0x00 && block
[1] == 0x00 && block
[3] == 0xfa)
651 num
+= get_dst_timing(block
+ 5, &mode
[num
], ver
, rev
);
654 /* Yikes, EDID data is totally useless */
661 m
= kmalloc(num
* sizeof(struct fb_videomode
), GFP_KERNEL
);
664 memmove(m
, mode
, num
* sizeof(struct fb_videomode
));
670 * fb_destroy_modedb - destroys mode database
671 * @modedb: mode database to destroy
674 * Destroy mode database created by fb_create_modedb
676 void fb_destroy_modedb(struct fb_videomode
*modedb
)
681 static int fb_get_monitor_limits(unsigned char *edid
, struct fb_monspecs
*specs
)
684 unsigned char *block
;
686 block
= edid
+ DETAILED_TIMING_DESCRIPTIONS_START
;
688 DPRINTK(" Monitor Operating Limits: ");
690 for (i
= 0; i
< 4; i
++, block
+= DETAILED_TIMING_DESCRIPTION_SIZE
) {
691 if (edid_is_limits_block(block
)) {
692 specs
->hfmin
= H_MIN_RATE
* 1000;
693 specs
->hfmax
= H_MAX_RATE
* 1000;
694 specs
->vfmin
= V_MIN_RATE
;
695 specs
->vfmax
= V_MAX_RATE
;
696 specs
->dclkmax
= MAX_PIXEL_CLOCK
* 1000000;
697 specs
->gtf
= (GTF_SUPPORT
) ? 1 : 0;
699 DPRINTK("From EDID\n");
704 /* estimate monitor limits based on modes supported */
706 struct fb_videomode
*modes
, *mode
;
707 int num_modes
, hz
, hscan
, pixclock
;
710 modes
= fb_create_modedb(edid
, &num_modes
);
712 DPRINTK("None Available\n");
717 for (i
= 0; i
< num_modes
; i
++) {
719 pixclock
= PICOS2KHZ(modes
[i
].pixclock
) * 1000;
720 htotal
= mode
->xres
+ mode
->right_margin
+ mode
->hsync_len
722 vtotal
= mode
->yres
+ mode
->lower_margin
+ mode
->vsync_len
723 + mode
->upper_margin
;
725 if (mode
->vmode
& FB_VMODE_INTERLACED
)
728 if (mode
->vmode
& FB_VMODE_DOUBLE
)
731 hscan
= (pixclock
+ htotal
/ 2) / htotal
;
732 hscan
= (hscan
+ 500) / 1000 * 1000;
733 hz
= (hscan
+ vtotal
/ 2) / vtotal
;
735 if (specs
->dclkmax
== 0 || specs
->dclkmax
< pixclock
)
736 specs
->dclkmax
= pixclock
;
738 if (specs
->dclkmin
== 0 || specs
->dclkmin
> pixclock
)
739 specs
->dclkmin
= pixclock
;
741 if (specs
->hfmax
== 0 || specs
->hfmax
< hscan
)
742 specs
->hfmax
= hscan
;
744 if (specs
->hfmin
== 0 || specs
->hfmin
> hscan
)
745 specs
->hfmin
= hscan
;
747 if (specs
->vfmax
== 0 || specs
->vfmax
< hz
)
750 if (specs
->vfmin
== 0 || specs
->vfmin
> hz
)
753 DPRINTK("Extrapolated\n");
754 fb_destroy_modedb(modes
);
756 DPRINTK(" H: %d-%dKHz V: %d-%dHz DCLK: %dMHz\n",
757 specs
->hfmin
/1000, specs
->hfmax
/1000, specs
->vfmin
,
758 specs
->vfmax
, specs
->dclkmax
/1000000);
762 static void get_monspecs(unsigned char *edid
, struct fb_monspecs
*specs
)
764 unsigned char c
, *block
;
766 block
= edid
+ EDID_STRUCT_DISPLAY
;
768 fb_get_monitor_limits(edid
, specs
);
773 specs
->input
|= FB_DISP_DDI
;
774 DPRINTK(" Digital Display Input");
776 DPRINTK(" Analog Display Input: Input Voltage - ");
777 switch ((block
[0] & 0x60) >> 5) {
779 DPRINTK("0.700V/0.300V");
780 specs
->input
|= FB_DISP_ANA_700_300
;
783 DPRINTK("0.714V/0.286V");
784 specs
->input
|= FB_DISP_ANA_714_286
;
787 DPRINTK("1.000V/0.400V");
788 specs
->input
|= FB_DISP_ANA_1000_400
;
791 DPRINTK("0.700V/0.000V");
792 specs
->input
|= FB_DISP_ANA_700_000
;
796 DPRINTK("\n Sync: ");
799 DPRINTK(" Configurable signal level\n");
803 DPRINTK("Blank to Blank ");
804 specs
->signal
|= FB_SIGNAL_BLANK_BLANK
;
807 DPRINTK("Separate ");
808 specs
->signal
|= FB_SIGNAL_SEPARATE
;
811 DPRINTK("Composite ");
812 specs
->signal
|= FB_SIGNAL_COMPOSITE
;
815 DPRINTK("Sync on Green ");
816 specs
->signal
|= FB_SIGNAL_SYNC_ON_GREEN
;
819 DPRINTK("Serration on ");
820 specs
->signal
|= FB_SIGNAL_SERRATION_ON
;
823 specs
->max_x
= block
[1];
824 specs
->max_y
= block
[2];
825 DPRINTK(" Max H-size in cm: ");
827 DPRINTK("%d\n", specs
->max_x
);
829 DPRINTK("variable\n");
830 DPRINTK(" Max V-size in cm: ");
832 DPRINTK("%d\n", specs
->max_y
);
834 DPRINTK("variable\n");
837 specs
->gamma
= c
+100;
839 DPRINTK("%d.%d\n", specs
->gamma
/100, specs
->gamma
% 100);
841 get_dpms_capabilities(block
[4], specs
);
843 switch ((block
[4] & 0x18) >> 3) {
845 DPRINTK(" Monochrome/Grayscale\n");
846 specs
->input
|= FB_DISP_MONO
;
849 DPRINTK(" RGB Color Display\n");
850 specs
->input
|= FB_DISP_RGB
;
853 DPRINTK(" Non-RGB Multicolor Display\n");
854 specs
->input
|= FB_DISP_MULTI
;
857 DPRINTK(" Unknown\n");
858 specs
->input
|= FB_DISP_UNKNOWN
;
862 get_chroma(block
, specs
);
867 DPRINTK(" Default color format is primary\n");
868 specs
->misc
|= FB_MISC_PRIM_COLOR
;
871 DPRINTK(" First DETAILED Timing is preferred\n");
872 specs
->misc
|= FB_MISC_1ST_DETAIL
;
875 printk(" Display is GTF capable\n");
880 int fb_parse_edid(unsigned char *edid
, struct fb_var_screeninfo
*var
)
883 unsigned char *block
;
885 if (edid
== NULL
|| var
== NULL
)
888 if (!(edid_checksum(edid
)))
891 if (!(edid_check_header(edid
)))
894 block
= edid
+ DETAILED_TIMING_DESCRIPTIONS_START
;
896 for (i
= 0; i
< 4; i
++, block
+= DETAILED_TIMING_DESCRIPTION_SIZE
) {
897 if (edid_is_timing_block(block
)) {
898 var
->xres
= var
->xres_virtual
= H_ACTIVE
;
899 var
->yres
= var
->yres_virtual
= V_ACTIVE
;
900 var
->height
= var
->width
= 0;
901 var
->right_margin
= H_SYNC_OFFSET
;
902 var
->left_margin
= (H_ACTIVE
+ H_BLANKING
) -
903 (H_ACTIVE
+ H_SYNC_OFFSET
+ H_SYNC_WIDTH
);
904 var
->upper_margin
= V_BLANKING
- V_SYNC_OFFSET
-
906 var
->lower_margin
= V_SYNC_OFFSET
;
907 var
->hsync_len
= H_SYNC_WIDTH
;
908 var
->vsync_len
= V_SYNC_WIDTH
;
909 var
->pixclock
= PIXEL_CLOCK
;
910 var
->pixclock
/= 1000;
911 var
->pixclock
= KHZ2PICOS(var
->pixclock
);
914 var
->sync
|= FB_SYNC_HOR_HIGH_ACT
;
916 var
->sync
|= FB_SYNC_VERT_HIGH_ACT
;
923 void fb_edid_to_monspecs(unsigned char *edid
, struct fb_monspecs
*specs
)
925 unsigned char *block
;
931 if (!(edid_checksum(edid
)))
934 if (!(edid_check_header(edid
)))
937 memset(specs
, 0, sizeof(struct fb_monspecs
));
939 specs
->version
= edid
[EDID_STRUCT_VERSION
];
940 specs
->revision
= edid
[EDID_STRUCT_REVISION
];
942 DPRINTK("========================================\n");
943 DPRINTK("Display Information (EDID)\n");
944 DPRINTK("========================================\n");
945 DPRINTK(" EDID Version %d.%d\n", (int) specs
->version
,
946 (int) specs
->revision
);
948 parse_vendor_block(edid
+ ID_MANUFACTURER_NAME
, specs
);
950 block
= edid
+ DETAILED_TIMING_DESCRIPTIONS_START
;
951 for (i
= 0; i
< 4; i
++, block
+= DETAILED_TIMING_DESCRIPTION_SIZE
) {
952 if (edid_is_serial_block(block
)) {
953 copy_string(block
, specs
->serial_no
);
954 DPRINTK(" Serial Number: %s\n", specs
->serial_no
);
955 } else if (edid_is_ascii_block(block
)) {
956 copy_string(block
, specs
->ascii
);
957 DPRINTK(" ASCII Block: %s\n", specs
->ascii
);
958 } else if (edid_is_monitor_block(block
)) {
959 copy_string(block
, specs
->monitor
);
960 DPRINTK(" Monitor Name: %s\n", specs
->monitor
);
964 DPRINTK(" Display Characteristics:\n");
965 get_monspecs(edid
, specs
);
967 specs
->modedb
= fb_create_modedb(edid
, &specs
->modedb_len
);
970 * Workaround for buggy EDIDs that sets that the first
971 * detailed timing is preferred but has not detailed
974 for (i
= 0; i
< specs
->modedb_len
; i
++) {
975 if (specs
->modedb
[i
].flag
& FB_MODE_IS_DETAILED
) {
982 specs
->misc
&= ~FB_MISC_1ST_DETAIL
;
984 DPRINTK("========================================\n");
988 * fb_edid_add_monspecs() - add monitor video modes from E-EDID data
989 * @edid: 128 byte array with an E-EDID block
990 * @spacs: monitor specs to be extended
992 void fb_edid_add_monspecs(unsigned char *edid
, struct fb_monspecs
*specs
)
994 unsigned char *block
;
995 struct fb_videomode
*m
;
997 u8 svd
[64], edt
[(128 - 4) / DETAILED_TIMING_DESCRIPTION_SIZE
];
998 u8 pos
= 4, svd_n
= 0;
1003 if (!edid_checksum(edid
))
1006 if (edid
[0] != 0x2 ||
1007 edid
[2] < 4 || edid
[2] > 128 - DETAILED_TIMING_DESCRIPTION_SIZE
)
1010 DPRINTK(" Short Video Descriptors\n");
1012 while (pos
< edid
[2]) {
1013 u8 len
= edid
[pos
] & 0x1f, type
= (edid
[pos
] >> 5) & 7;
1014 pr_debug("Data block %u of %u bytes\n", type
, len
);
1016 for (i
= pos
; i
< pos
+ len
; i
++) {
1017 u8 idx
= edid
[pos
+ i
] & 0x7f;
1019 pr_debug("N%sative mode #%d\n",
1020 edid
[pos
+ i
] & 0x80 ? "" : "on-n", idx
);
1025 block
= edid
+ edid
[2];
1027 DPRINTK(" Extended Detailed Timings\n");
1029 for (i
= 0; i
< (128 - edid
[2]) / DETAILED_TIMING_DESCRIPTION_SIZE
;
1030 i
++, block
+= DETAILED_TIMING_DESCRIPTION_SIZE
)
1032 edt
[num
++] = block
- edid
;
1034 /* Yikes, EDID data is totally useless */
1038 m
= kzalloc((specs
->modedb_len
+ num
+ svd_n
) *
1039 sizeof(struct fb_videomode
), GFP_KERNEL
);
1044 memcpy(m
, specs
->modedb
, specs
->modedb_len
* sizeof(struct fb_videomode
));
1046 for (i
= specs
->modedb_len
; i
< specs
->modedb_len
+ num
; i
++) {
1047 get_detailed_timing(edid
+ edt
[i
- specs
->modedb_len
], &m
[i
]);
1048 if (i
== specs
->modedb_len
)
1049 m
[i
].flag
|= FB_MODE_IS_FIRST
;
1050 pr_debug("Adding %ux%u@%u\n", m
[i
].xres
, m
[i
].yres
, m
[i
].refresh
);
1053 for (i
= specs
->modedb_len
+ num
; i
< specs
->modedb_len
+ num
+ svd_n
; i
++) {
1054 int idx
= svd
[i
- specs
->modedb_len
- num
];
1055 if (!idx
|| idx
> 63) {
1056 pr_warning("Reserved SVD code %d\n", idx
);
1057 } else if (idx
> ARRAY_SIZE(cea_modes
) || !cea_modes
[idx
].xres
) {
1058 pr_warning("Unimplemented SVD code %d\n", idx
);
1060 memcpy(&m
[i
], cea_modes
+ idx
, sizeof(m
[i
]));
1061 pr_debug("Adding SVD #%d: %ux%u@%u\n", idx
,
1062 m
[i
].xres
, m
[i
].yres
, m
[i
].refresh
);
1066 kfree(specs
->modedb
);
1068 specs
->modedb_len
= specs
->modedb_len
+ num
+ svd_n
;
1072 * VESA Generalized Timing Formula (GTF)
1076 #define V_FRONTPORCH 1
1078 #define H_SCALEFACTOR 20
1079 #define H_BLANKSCALE 128
1080 #define H_GRADIENT 600
1084 struct __fb_timings
{
1097 * fb_get_vblank - get vertical blank time
1098 * @hfreq: horizontal freq
1101 * vblank = right_margin + vsync_len + left_margin
1103 * given: right_margin = 1 (V_FRONTPORCH)
1108 * left_margin = --------------- - vsync_len
1111 static u32
fb_get_vblank(u32 hfreq
)
1115 vblank
= (hfreq
* FLYBACK
)/1000;
1116 vblank
= (vblank
+ 500)/1000;
1117 return (vblank
+ V_FRONTPORCH
);
1121 * fb_get_hblank_by_freq - get horizontal blank time given hfreq
1122 * @hfreq: horizontal freq
1123 * @xres: horizontal resolution in pixels
1128 * hblank = ------------------
1131 * duty cycle = percent of htotal assigned to inactive display
1132 * duty cycle = C - (M/Hfreq)
1134 * where: C = ((offset - scale factor) * blank_scale)
1135 * -------------------------------------- + scale factor
1137 * M = blank_scale * gradient
1140 static u32
fb_get_hblank_by_hfreq(u32 hfreq
, u32 xres
)
1142 u32 c_val
, m_val
, duty_cycle
, hblank
;
1144 c_val
= (((H_OFFSET
- H_SCALEFACTOR
) * H_BLANKSCALE
)/256 +
1145 H_SCALEFACTOR
) * 1000;
1146 m_val
= (H_BLANKSCALE
* H_GRADIENT
)/256;
1147 m_val
= (m_val
* 1000000)/hfreq
;
1148 duty_cycle
= c_val
- m_val
;
1149 hblank
= (xres
* duty_cycle
)/(100000 - duty_cycle
);
1154 * fb_get_hblank_by_dclk - get horizontal blank time given pixelclock
1155 * @dclk: pixelclock in Hz
1156 * @xres: horizontal resolution in pixels
1161 * hblank = ------------------
1164 * duty cycle = percent of htotal assigned to inactive display
1165 * duty cycle = C - (M * h_period)
1167 * where: h_period = SQRT(100 - C + (0.4 * xres * M)/dclk) + C - 100
1168 * -----------------------------------------------
1174 static u32
fb_get_hblank_by_dclk(u32 dclk
, u32 xres
)
1176 u32 duty_cycle
, h_period
, hblank
;
1179 h_period
= 100 - C_VAL
;
1180 h_period
*= h_period
;
1181 h_period
+= (M_VAL
* xres
* 2 * 1000)/(5 * dclk
);
1184 h_period
= int_sqrt(h_period
);
1185 h_period
-= (100 - C_VAL
) * 100;
1187 h_period
/= 2 * M_VAL
;
1189 duty_cycle
= C_VAL
* 1000 - (M_VAL
* h_period
)/100;
1190 hblank
= (xres
* duty_cycle
)/(100000 - duty_cycle
) + 8;
1196 * fb_get_hfreq - estimate hsync
1197 * @vfreq: vertical refresh rate
1198 * @yres: vertical resolution
1202 * (yres + front_port) * vfreq * 1000000
1203 * hfreq = -------------------------------------
1204 * (1000000 - (vfreq * FLYBACK)
1208 static u32
fb_get_hfreq(u32 vfreq
, u32 yres
)
1212 divisor
= (1000000 - (vfreq
* FLYBACK
))/1000;
1213 hfreq
= (yres
+ V_FRONTPORCH
) * vfreq
* 1000;
1214 return (hfreq
/divisor
);
1217 static void fb_timings_vfreq(struct __fb_timings
*timings
)
1219 timings
->hfreq
= fb_get_hfreq(timings
->vfreq
, timings
->vactive
);
1220 timings
->vblank
= fb_get_vblank(timings
->hfreq
);
1221 timings
->vtotal
= timings
->vactive
+ timings
->vblank
;
1222 timings
->hblank
= fb_get_hblank_by_hfreq(timings
->hfreq
,
1224 timings
->htotal
= timings
->hactive
+ timings
->hblank
;
1225 timings
->dclk
= timings
->htotal
* timings
->hfreq
;
1228 static void fb_timings_hfreq(struct __fb_timings
*timings
)
1230 timings
->vblank
= fb_get_vblank(timings
->hfreq
);
1231 timings
->vtotal
= timings
->vactive
+ timings
->vblank
;
1232 timings
->vfreq
= timings
->hfreq
/timings
->vtotal
;
1233 timings
->hblank
= fb_get_hblank_by_hfreq(timings
->hfreq
,
1235 timings
->htotal
= timings
->hactive
+ timings
->hblank
;
1236 timings
->dclk
= timings
->htotal
* timings
->hfreq
;
1239 static void fb_timings_dclk(struct __fb_timings
*timings
)
1241 timings
->hblank
= fb_get_hblank_by_dclk(timings
->dclk
,
1243 timings
->htotal
= timings
->hactive
+ timings
->hblank
;
1244 timings
->hfreq
= timings
->dclk
/timings
->htotal
;
1245 timings
->vblank
= fb_get_vblank(timings
->hfreq
);
1246 timings
->vtotal
= timings
->vactive
+ timings
->vblank
;
1247 timings
->vfreq
= timings
->hfreq
/timings
->vtotal
;
1251 * fb_get_mode - calculates video mode using VESA GTF
1252 * @flags: if: 0 - maximize vertical refresh rate
1253 * 1 - vrefresh-driven calculation;
1254 * 2 - hscan-driven calculation;
1255 * 3 - pixelclock-driven calculation;
1256 * @val: depending on @flags, ignored, vrefresh, hsync or pixelclock
1257 * @var: pointer to fb_var_screeninfo
1258 * @info: pointer to fb_info
1261 * Calculates video mode based on monitor specs using VESA GTF.
1262 * The GTF is best for VESA GTF compliant monitors but is
1263 * specifically formulated to work for older monitors as well.
1265 * If @flag==0, the function will attempt to maximize the
1266 * refresh rate. Otherwise, it will calculate timings based on
1267 * the flag and accompanying value.
1269 * If FB_IGNOREMON bit is set in @flags, monitor specs will be
1270 * ignored and @var will be filled with the calculated timings.
1272 * All calculations are based on the VESA GTF Spreadsheet
1273 * available at VESA's public ftp (http://www.vesa.org).
1276 * The timings generated by the GTF will be different from VESA
1277 * DMT. It might be a good idea to keep a table of standard
1278 * VESA modes as well. The GTF may also not work for some displays,
1279 * such as, and especially, analog TV.
1282 * A valid info->monspecs, otherwise 'safe numbers' will be used.
1284 int fb_get_mode(int flags
, u32 val
, struct fb_var_screeninfo
*var
, struct fb_info
*info
)
1286 struct __fb_timings
*timings
;
1287 u32 interlace
= 1, dscan
= 1;
1288 u32 hfmin
, hfmax
, vfmin
, vfmax
, dclkmin
, dclkmax
, err
= 0;
1291 timings
= kzalloc(sizeof(struct __fb_timings
), GFP_KERNEL
);
1297 * If monspecs are invalid, use values that are enough
1300 if (!info
|| !info
->monspecs
.hfmax
|| !info
->monspecs
.vfmax
||
1301 !info
->monspecs
.dclkmax
||
1302 info
->monspecs
.hfmax
< info
->monspecs
.hfmin
||
1303 info
->monspecs
.vfmax
< info
->monspecs
.vfmin
||
1304 info
->monspecs
.dclkmax
< info
->monspecs
.dclkmin
) {
1305 hfmin
= 29000; hfmax
= 30000;
1306 vfmin
= 60; vfmax
= 60;
1307 dclkmin
= 0; dclkmax
= 25000000;
1309 hfmin
= info
->monspecs
.hfmin
;
1310 hfmax
= info
->monspecs
.hfmax
;
1311 vfmin
= info
->monspecs
.vfmin
;
1312 vfmax
= info
->monspecs
.vfmax
;
1313 dclkmin
= info
->monspecs
.dclkmin
;
1314 dclkmax
= info
->monspecs
.dclkmax
;
1317 timings
->hactive
= var
->xres
;
1318 timings
->vactive
= var
->yres
;
1319 if (var
->vmode
& FB_VMODE_INTERLACED
) {
1320 timings
->vactive
/= 2;
1323 if (var
->vmode
& FB_VMODE_DOUBLE
) {
1324 timings
->vactive
*= 2;
1328 switch (flags
& ~FB_IGNOREMON
) {
1329 case FB_MAXTIMINGS
: /* maximize refresh rate */
1330 timings
->hfreq
= hfmax
;
1331 fb_timings_hfreq(timings
);
1332 if (timings
->vfreq
> vfmax
) {
1333 timings
->vfreq
= vfmax
;
1334 fb_timings_vfreq(timings
);
1336 if (timings
->dclk
> dclkmax
) {
1337 timings
->dclk
= dclkmax
;
1338 fb_timings_dclk(timings
);
1341 case FB_VSYNCTIMINGS
: /* vrefresh driven */
1342 timings
->vfreq
= val
;
1343 fb_timings_vfreq(timings
);
1345 case FB_HSYNCTIMINGS
: /* hsync driven */
1346 timings
->hfreq
= val
;
1347 fb_timings_hfreq(timings
);
1349 case FB_DCLKTIMINGS
: /* pixelclock driven */
1350 timings
->dclk
= PICOS2KHZ(val
) * 1000;
1351 fb_timings_dclk(timings
);
1358 if (err
|| (!(flags
& FB_IGNOREMON
) &&
1359 (timings
->vfreq
< vfmin
|| timings
->vfreq
> vfmax
||
1360 timings
->hfreq
< hfmin
|| timings
->hfreq
> hfmax
||
1361 timings
->dclk
< dclkmin
|| timings
->dclk
> dclkmax
))) {
1364 var
->pixclock
= KHZ2PICOS(timings
->dclk
/1000);
1365 var
->hsync_len
= (timings
->htotal
* 8)/100;
1366 var
->right_margin
= (timings
->hblank
/2) - var
->hsync_len
;
1367 var
->left_margin
= timings
->hblank
- var
->right_margin
-
1369 var
->vsync_len
= (3 * interlace
)/dscan
;
1370 var
->lower_margin
= (1 * interlace
)/dscan
;
1371 var
->upper_margin
= (timings
->vblank
* interlace
)/dscan
-
1372 (var
->vsync_len
+ var
->lower_margin
);
1379 #if IS_ENABLED(CONFIG_VIDEOMODE)
1380 int fb_videomode_from_videomode(const struct videomode
*vm
,
1381 struct fb_videomode
*fbmode
)
1383 unsigned int htotal
, vtotal
;
1385 fbmode
->xres
= vm
->hactive
;
1386 fbmode
->left_margin
= vm
->hback_porch
;
1387 fbmode
->right_margin
= vm
->hfront_porch
;
1388 fbmode
->hsync_len
= vm
->hsync_len
;
1390 fbmode
->yres
= vm
->vactive
;
1391 fbmode
->upper_margin
= vm
->vback_porch
;
1392 fbmode
->lower_margin
= vm
->vfront_porch
;
1393 fbmode
->vsync_len
= vm
->vsync_len
;
1395 /* prevent division by zero in KHZ2PICOS macro */
1396 fbmode
->pixclock
= vm
->pixelclock
?
1397 KHZ2PICOS(vm
->pixelclock
/ 1000) : 0;
1401 if (vm
->dmt_flags
& VESA_DMT_HSYNC_HIGH
)
1402 fbmode
->sync
|= FB_SYNC_HOR_HIGH_ACT
;
1403 if (vm
->dmt_flags
& VESA_DMT_HSYNC_HIGH
)
1404 fbmode
->sync
|= FB_SYNC_VERT_HIGH_ACT
;
1405 if (vm
->data_flags
& DISPLAY_FLAGS_INTERLACED
)
1406 fbmode
->vmode
|= FB_VMODE_INTERLACED
;
1407 if (vm
->data_flags
& DISPLAY_FLAGS_DOUBLESCAN
)
1408 fbmode
->vmode
|= FB_VMODE_DOUBLE
;
1411 htotal
= vm
->hactive
+ vm
->hfront_porch
+ vm
->hback_porch
+
1413 vtotal
= vm
->vactive
+ vm
->vfront_porch
+ vm
->vback_porch
+
1415 /* prevent division by zero */
1416 if (htotal
&& vtotal
) {
1417 fbmode
->refresh
= vm
->pixelclock
/ (htotal
* vtotal
);
1418 /* a mode must have htotal and vtotal != 0 or it is invalid */
1420 fbmode
->refresh
= 0;
1426 EXPORT_SYMBOL_GPL(fb_videomode_from_videomode
);
1429 #if IS_ENABLED(CONFIG_OF_VIDEOMODE)
1430 static inline void dump_fb_videomode(const struct fb_videomode
*m
)
1432 pr_debug("fb_videomode = %ux%u@%uHz (%ukHz) %u %u %u %u %u %u %u %u %u\n",
1433 m
->xres
, m
->yres
, m
->refresh
, m
->pixclock
, m
->left_margin
,
1434 m
->right_margin
, m
->upper_margin
, m
->lower_margin
,
1435 m
->hsync_len
, m
->vsync_len
, m
->sync
, m
->vmode
, m
->flag
);
1439 * of_get_fb_videomode - get a fb_videomode from devicetree
1440 * @np: device_node with the timing specification
1441 * @fb: will be set to the return value
1442 * @index: index into the list of display timings in devicetree
1445 * This function is expensive and should only be used, if only one mode is to be
1446 * read from DT. To get multiple modes start with of_get_display_timings ond
1447 * work with that instead.
1449 int of_get_fb_videomode(struct device_node
*np
, struct fb_videomode
*fb
,
1452 struct videomode vm
;
1455 ret
= of_get_videomode(np
, &vm
, index
);
1459 fb_videomode_from_videomode(&vm
, fb
);
1461 pr_debug("%s: got %dx%d display mode from %s\n",
1462 of_node_full_name(np
), vm
.hactive
, vm
.vactive
, np
->name
);
1463 dump_fb_videomode(fb
);
1467 EXPORT_SYMBOL_GPL(of_get_fb_videomode
);
1471 int fb_parse_edid(unsigned char *edid
, struct fb_var_screeninfo
*var
)
1475 void fb_edid_to_monspecs(unsigned char *edid
, struct fb_monspecs
*specs
)
1479 void fb_edid_add_monspecs(unsigned char *edid
, struct fb_monspecs
*specs
)
1482 void fb_destroy_modedb(struct fb_videomode
*modedb
)
1485 int fb_get_mode(int flags
, u32 val
, struct fb_var_screeninfo
*var
,
1486 struct fb_info
*info
)
1490 #endif /* CONFIG_FB_MODE_HELPERS */
1493 * fb_validate_mode - validates var against monitor capabilities
1494 * @var: pointer to fb_var_screeninfo
1495 * @info: pointer to fb_info
1498 * Validates video mode against monitor capabilities specified in
1502 * A valid info->monspecs.
1504 int fb_validate_mode(const struct fb_var_screeninfo
*var
, struct fb_info
*info
)
1506 u32 hfreq
, vfreq
, htotal
, vtotal
, pixclock
;
1507 u32 hfmin
, hfmax
, vfmin
, vfmax
, dclkmin
, dclkmax
;
1510 * If monspecs are invalid, use values that are enough
1513 if (!info
->monspecs
.hfmax
|| !info
->monspecs
.vfmax
||
1514 !info
->monspecs
.dclkmax
||
1515 info
->monspecs
.hfmax
< info
->monspecs
.hfmin
||
1516 info
->monspecs
.vfmax
< info
->monspecs
.vfmin
||
1517 info
->monspecs
.dclkmax
< info
->monspecs
.dclkmin
) {
1518 hfmin
= 29000; hfmax
= 30000;
1519 vfmin
= 60; vfmax
= 60;
1520 dclkmin
= 0; dclkmax
= 25000000;
1522 hfmin
= info
->monspecs
.hfmin
;
1523 hfmax
= info
->monspecs
.hfmax
;
1524 vfmin
= info
->monspecs
.vfmin
;
1525 vfmax
= info
->monspecs
.vfmax
;
1526 dclkmin
= info
->monspecs
.dclkmin
;
1527 dclkmax
= info
->monspecs
.dclkmax
;
1532 pixclock
= PICOS2KHZ(var
->pixclock
) * 1000;
1534 htotal
= var
->xres
+ var
->right_margin
+ var
->hsync_len
+
1536 vtotal
= var
->yres
+ var
->lower_margin
+ var
->vsync_len
+
1539 if (var
->vmode
& FB_VMODE_INTERLACED
)
1541 if (var
->vmode
& FB_VMODE_DOUBLE
)
1544 hfreq
= pixclock
/htotal
;
1545 hfreq
= (hfreq
+ 500) / 1000 * 1000;
1547 vfreq
= hfreq
/vtotal
;
1549 return (vfreq
< vfmin
|| vfreq
> vfmax
||
1550 hfreq
< hfmin
|| hfreq
> hfmax
||
1551 pixclock
< dclkmin
|| pixclock
> dclkmax
) ?
1555 #if defined(CONFIG_FIRMWARE_EDID) && defined(CONFIG_X86)
1558 * We need to ensure that the EDID block is only returned for
1559 * the primary graphics adapter.
1562 const unsigned char *fb_firmware_edid(struct device
*device
)
1564 struct pci_dev
*dev
= NULL
;
1565 struct resource
*res
= NULL
;
1566 unsigned char *edid
= NULL
;
1569 dev
= to_pci_dev(device
);
1572 res
= &dev
->resource
[PCI_ROM_RESOURCE
];
1574 if (res
&& res
->flags
& IORESOURCE_ROM_SHADOW
)
1575 edid
= edid_info
.dummy
;
1580 const unsigned char *fb_firmware_edid(struct device
*device
)
1585 EXPORT_SYMBOL(fb_firmware_edid
);
1587 EXPORT_SYMBOL(fb_parse_edid
);
1588 EXPORT_SYMBOL(fb_edid_to_monspecs
);
1589 EXPORT_SYMBOL(fb_edid_add_monspecs
);
1590 EXPORT_SYMBOL(fb_get_mode
);
1591 EXPORT_SYMBOL(fb_validate_mode
);
1592 EXPORT_SYMBOL(fb_destroy_modedb
);