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