xref: /aosp_15_r20/external/edid-decode/parse-displayid-block.cpp (revision 193032a37cc83cffc1526215991f3c21671f4245)
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright 2006-2012 Red Hat, Inc.
4  * Copyright 2018-2020 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
5  *
6  * Author: Adam Jackson <[email protected]>
7  * Maintainer: Hans Verkuil <[email protected]>
8  */
9 
10 #include <math.h>
11 
12 #include "edid-decode.h"
13 
14 static const char *bpc444[] = {"6", "8", "10", "12", "14", "16", NULL, NULL};
15 static const char *bpc4xx[] = {"8", "10", "12", "14", "16", NULL, NULL, NULL};
16 static const char *audiorates[] = {"32", "44.1", "48", NULL, NULL, NULL, NULL, NULL};
17 
18 // misc functions
19 
print_flags(const char * label,unsigned char flag_byte,const char ** flags,bool reverse=false)20 static void print_flags(const char *label, unsigned char flag_byte,
21 			const char **flags, bool reverse = false)
22 {
23 	if (!flag_byte)
24 		return;
25 
26 	unsigned countflags = 0;
27 
28 	printf("%s: ", label);
29 	for (unsigned i = 0; i < 8; i++) {
30 		if (flag_byte & (1 << (reverse ? 7 - i : i))) {
31 			if (countflags)
32 				printf(", ");
33 			if (flags[i])
34 				printf("%s", flags[i]);
35 			else
36 				printf("Undefined (%u)", i);
37 			countflags++;
38 		}
39 	}
40 	printf("\n");
41 }
42 
check_displayid_datablock_revision(unsigned char hdr,unsigned char valid_flags,unsigned char rev)43 void edid_state::check_displayid_datablock_revision(unsigned char hdr,
44 						    unsigned char valid_flags,
45 						    unsigned char rev)
46 {
47 	unsigned char revision = hdr & 7;
48 	unsigned char flags = hdr & ~7 & ~valid_flags;
49 
50 	if (revision != rev)
51 		warn("Unexpected revision (%u != %u).\n", revision, rev);
52 	if (flags)
53 		warn("Unexpected flags (0x%02x).\n", flags);
54 }
55 
check_displayid_datablock_length(const unsigned char * x,unsigned expectedlenmin=0,unsigned expectedlenmax=128-2-5-3,unsigned payloaddumpstart=0)56 static bool check_displayid_datablock_length(const unsigned char *x,
57 					     unsigned expectedlenmin = 0,
58 					     unsigned expectedlenmax = 128 - 2 - 5 - 3,
59 					     unsigned payloaddumpstart = 0)
60 {
61 	unsigned char len = x[2];
62 
63 	if (expectedlenmin == expectedlenmax && len != expectedlenmax)
64 		fail("DisplayID payload length is different than expected (%d != %d).\n", len, expectedlenmax);
65 	else if (len > expectedlenmax)
66 		fail("DisplayID payload length is greater than expected (%d > %d).\n", len, expectedlenmax);
67 	else if (len < expectedlenmin)
68 		fail("DisplayID payload length is less than expected (%d < %d).\n", len, expectedlenmin);
69 	else
70 		return true;
71 
72 	if (len > payloaddumpstart)
73 		hex_block("    ", x + 3 + payloaddumpstart, len - payloaddumpstart);
74 	return false;
75 }
76 
77 // tag 0x00 and 0x20
78 
parse_displayid_product_id(const unsigned char * x)79 void edid_state::parse_displayid_product_id(const unsigned char *x)
80 {
81 	check_displayid_datablock_revision(x[1]);
82 
83 	dispid.has_product_identification = true;
84 	if (dispid.version >= 0x20) {
85 		unsigned oui = (x[3] << 16) | (x[4] << 8) | x[5];
86 		printf("    Vendor OUI %s\n", ouitohex(oui).c_str());
87 	} else {
88 		printf("    Vendor ID: %c%c%c\n", x[3], x[4], x[5]);
89 	}
90 	printf("    Product Code: %u\n", x[6] | (x[7] << 8));
91 	unsigned sn = x[8] | (x[9] << 8) | (x[10] << 16) | (x[11] << 24);
92 	if (sn) {
93 		if (hide_serial_numbers)
94 			printf("    Serial Number: ...\n");
95 		else
96 			printf("    Serial Number: %u\n", sn);
97 	}
98 	unsigned week = x[12];
99 	unsigned year = 2000 + x[13];
100 	printf("    %s: %u",
101 	       week == 0xff ? "Model Year" : "Year of Manufacture", year);
102 	if (week && week <= 0x36)
103 		printf(", Week %u", week);
104 	printf("\n");
105 	if (x[14]) {
106 		char buf[256];
107 
108 		memcpy(buf, x + 15, x[14]);
109 		buf[x[14]] = 0;
110 		printf("    Product ID: %s\n", buf);
111 	}
112 }
113 
114 // tag 0x01
115 
116 static const char *feature_support_flags[] = {
117 	"De-interlacing",
118 	"Support ACP, ISRC1, or ISRC2packets",
119 	"Fixed pixel format",
120 	"Fixed timing",
121 	"Power management (DPM)",
122 	"Audio input override",
123 	"Separate audio inputs provided",
124 	"Audio support on video interface"
125 };
126 
print_flag_lines(const char * indent,const char * label,unsigned char flag_byte,const char ** flags)127 static void print_flag_lines(const char *indent, const char *label,
128 			     unsigned char flag_byte, const char **flags)
129 {
130 	if (flag_byte) {
131 		printf("%s\n", label);
132 
133 		for (int i = 0; i < 8; i++)
134 			if (flag_byte & (1 << i))
135 				printf("%s%s\n", indent, flags[i]);
136 	}
137 }
138 
parse_displayid_parameters(const unsigned char * x)139 void edid_state::parse_displayid_parameters(const unsigned char *x)
140 {
141 	check_displayid_datablock_revision(x[1]);
142 
143 	if (!check_displayid_datablock_length(x, 12, 12))
144 		return;
145 
146 	dispid.has_display_parameters = true;
147 	printf("    Image size: %.1f mm x %.1f mm\n",
148 	       ((x[4] << 8) + x[3]) / 10.0,
149 	       ((x[6] << 8) + x[5]) / 10.0);
150 	printf("    Pixels: %d x %d\n",
151 	       (x[8] << 8) + x[7], (x[10] << 8) + x[9]);
152 	print_flag_lines("      ", "    Feature support flags:",
153 			 x[11], feature_support_flags);
154 
155 	if (x[12] != 0xff)
156 		printf("    Gamma: %.2f\n", ((x[12] + 100.0) / 100.0));
157 	printf("    Aspect ratio: %.2f\n", ((x[13] + 100.0) / 100.0));
158 	printf("    Dynamic bpc native: %d\n", (x[14] & 0xf) + 1);
159 	printf("    Dynamic bpc overall: %d\n", ((x[14] >> 4) & 0xf) + 1);
160 }
161 
162 // tag 0x02
163 
164 static const char *std_colorspace_ids[] = {
165 	"sRGB",
166 	"BT.601",
167 	"BT.709",
168 	"Adobe RGB",
169 	"DCI-P3",
170 	"NTSC",
171 	"EBU",
172 	"Adobe Wide Gamut RGB",
173 	"DICOM"
174 };
175 
fp2d(unsigned short fp)176 static double fp2d(unsigned short fp)
177 {
178 	return fp / 4096.0;
179 }
180 
parse_displayid_color_characteristics(const unsigned char * x)181 void edid_state::parse_displayid_color_characteristics(const unsigned char *x)
182 {
183 	check_displayid_datablock_revision(x[1], 0xf8, 1);
184 
185 	unsigned cie_year = (x[1] & 0x80) ? 1976 : 1931;
186 	unsigned xfer_id = (x[1] >> 3) & 0x0f;
187 	unsigned num_whitepoints = x[3] & 0x0f;
188 	unsigned num_primaries = (x[3] >> 4) & 0x07;
189 	bool temporal_color = x[3] & 0x80;
190 	unsigned offset = 4;
191 
192 	printf("    Uses %s color\n", temporal_color ? "temporal" : "spatial");
193 	printf("    Uses %u CIE (x, y) coordinates\n", cie_year);
194 	if (xfer_id) {
195 		printf("    Associated with Transfer Characteristics Data Block with Identifier %u\n", xfer_id);
196 		if (!(dispid.preparsed_xfer_ids & (1 << xfer_id)))
197 			fail("Missing Transfer Characteristics Data Block with Identifier %u.\n", xfer_id);
198 	}
199 	if (!num_primaries) {
200 		printf("    Uses color space %s\n",
201 		       x[4] >= ARRAY_SIZE(std_colorspace_ids) ? "Reserved" :
202 								std_colorspace_ids[x[4]]);
203 		offset++;
204 	}
205 	for (unsigned i = 0; i < num_primaries; i++) {
206 		unsigned idx = offset + 3 * i;
207 
208 		printf("    Primary #%u: (%.4f, %.4f)\n", i,
209 		       fp2d(x[idx] | ((x[idx + 1] & 0x0f) << 8)),
210 		       fp2d(((x[idx + 1] & 0xf0) >> 4) | (x[idx + 2] << 4)));
211 	}
212 	offset += 3 * num_primaries;
213 	for (unsigned i = 0; i < num_whitepoints; i++) {
214 		unsigned idx = offset + 3 * i;
215 
216 		printf("    White point #%u: (%.4f, %.4f)\n", i,
217 		       fp2d(x[idx] | ((x[idx + 1] & 0x0f) << 8)),
218 		       fp2d(((x[idx + 1] & 0xf0) >> 4) | (x[idx + 2] << 4)));
219 	}
220 }
221 
222 // tag 0x03 and 0x22
223 
parse_displayid_type_1_7_timing(const unsigned char * x,bool type7,unsigned block_rev,bool is_cta)224 void edid_state::parse_displayid_type_1_7_timing(const unsigned char *x,
225 						 bool type7, unsigned block_rev, bool is_cta)
226 {
227 	struct timings t = {};
228 	unsigned hbl, vbl;
229 	std::string s("aspect ");
230 
231 	dispid.has_type_1_7 = true;
232 	t.pixclk_khz = (type7 ? 1 : 10) * (1 + (x[0] + (x[1] << 8) + (x[2] << 16)));
233 	switch (x[3] & 0xf) {
234 	case 0:
235 		s += "1:1";
236 		t.hratio = t.vratio = 1;
237 		break;
238 	case 1:
239 		s += "5:4";
240 		t.hratio = 5;
241 		t.vratio = 4;
242 		break;
243 	case 2:
244 		s += "4:3";
245 		t.hratio = 4;
246 		t.vratio = 3;
247 		break;
248 	case 3:
249 		s += "15:9";
250 		t.hratio = 15;
251 		t.vratio = 9;
252 		break;
253 	case 4:
254 		s += "16:9";
255 		t.hratio = 16;
256 		t.vratio = 9;
257 		break;
258 	case 5:
259 		s += "16:10";
260 		t.hratio = 16;
261 		t.vratio = 10;
262 		break;
263 	case 6:
264 		s += "64:27";
265 		t.hratio = 64;
266 		t.vratio = 27;
267 		break;
268 	case 7:
269 		s += "256:135";
270 		t.hratio = 256;
271 		t.vratio = 135;
272 		break;
273 	default:
274 		s += "undefined";
275 		if ((x[3] & 0xf) > (dispid.version <= 0x12 ? 7 : 8))
276 			fail("Unknown aspect 0x%02x.\n", x[3] & 0xf);
277 		break;
278 	}
279 	switch ((x[3] >> 5) & 0x3) {
280 	case 0:
281 		s += ", no 3D stereo";
282 		break;
283 	case 1:
284 		s += ", 3D stereo";
285 		break;
286 	case 2:
287 		s += ", 3D stereo depends on user action";
288 		break;
289 	case 3:
290 		s += ", reserved";
291 		fail("Reserved stereo 0x03.\n");
292 		break;
293 	}
294 	if (block_rev >= 2 && (x[3] & 0x80))
295 		s += ", YCbCr 4:2:0";
296 
297 	t.hact = 1 + (x[4] | (x[5] << 8));
298 	hbl = 1 + (x[6] | (x[7] << 8));
299 	t.hfp = 1 + (x[8] | ((x[9] & 0x7f) << 8));
300 	t.hsync = 1 + (x[10] | (x[11] << 8));
301 	t.hbp = hbl - t.hfp - t.hsync;
302 	if ((x[9] >> 7) & 0x1)
303 		t.pos_pol_hsync = true;
304 	t.vact = 1 + (x[12] | (x[13] << 8));
305 	vbl = 1 + (x[14] | (x[15] << 8));
306 	t.vfp = 1 + (x[16] | ((x[17] & 0x7f) << 8));
307 	t.vsync = 1 + (x[18] | (x[19] << 8));
308 	t.vbp = vbl - t.vfp - t.vsync;
309 	if ((x[17] >> 7) & 0x1)
310 		t.pos_pol_vsync = true;
311 
312 	if (x[3] & 0x10) {
313 		t.interlaced = true;
314 		t.vfp /= 2;
315 		t.vsync /= 2;
316 		t.vbp /= 2;
317 	}
318 	if (block_rev < 2 && (x[3] & 0x80)) {
319 		s += ", preferred";
320 		dispid.preferred_timings.push_back(timings_ext(t, "DTD", s));
321 	}
322 
323 	print_timings("    ", &t, "DTD", s.c_str(), true);
324 	if (is_cta) {
325 		timings_ext te(t, "DTD", s);
326 		cta.vec_vtdbs.push_back(te);
327 
328 		// Only use a T7VTDB if is cannot be expressed by a
329 		// DTD or a T10VTDB.
330 		if (t.hact <= 4095 && t.vact <= 4095 &&
331 		    t.pixclk_khz <= 655360 && !(x[3] & 0xe0)) {
332 			fail("This T7VTDB can be represented as an 18-byte DTD.\n");
333 			return;
334 		}
335 		unsigned htot = t.hact + t.hfp + t.hsync + t.hbp;
336 		unsigned vtot = t.vact + t.vfp + t.vsync + t.vbp;
337 		unsigned refresh = (t.pixclk_khz * 1000ULL) / (htot * vtot);
338 
339 		for (unsigned rb = RB_NONE; rb <= RB_CVT_V3; rb++) {
340 			timings cvt_t = calc_cvt_mode(t.hact, t.vact, refresh, rb);
341 			if (match_timings(t, cvt_t)) {
342 				fail("This T7VTDB can be represented as a T10VTDB.\n");
343 				return;
344 			}
345 		}
346 		timings cvt_t = calc_cvt_mode(t.hact, t.vact, refresh, RB_CVT_V3,
347 					      false, false, true);
348 		if (match_timings(t, cvt_t))
349 			fail("This T7VTDB can be represented as a T10VTDB.\n");
350 	}
351 }
352 
353 // tag 0x04
354 
parse_displayid_type_2_timing(const unsigned char * x)355 void edid_state::parse_displayid_type_2_timing(const unsigned char *x)
356 {
357 	struct timings t = {};
358 	unsigned hbl, vbl;
359 	std::string s("aspect ");
360 
361 	t.pixclk_khz = 10 * (1 + (x[0] + (x[1] << 8) + (x[2] << 16)));
362 	t.hact = 8 + 8 * (x[4] | ((x[5] & 0x01) << 8));
363 	hbl = 8 + 8 * ((x[5] & 0xfe) >> 1);
364 	t.hfp = 8 + 8 * ((x[6] & 0xf0) >> 4);
365 	t.hsync = 8 + 8 * (x[6] & 0xf);
366 	t.hbp = hbl - t.hfp - t.hsync;
367 	if ((x[3] >> 3) & 0x1)
368 		t.pos_pol_hsync = true;
369 	t.vact = 1 + (x[7] | ((x[8] & 0xf) << 8));
370 	vbl = 1 + x[9];
371 	t.vfp = 1 + (x[10] >> 4);
372 	t.vsync = 1 + (x[10] & 0xf);
373 	t.vbp = vbl - t.vfp - t.vsync;
374 	if ((x[17] >> 2) & 0x1)
375 		t.pos_pol_vsync = true;
376 
377 	if (x[3] & 0x10) {
378 		t.interlaced = true;
379 		t.vfp /= 2;
380 		t.vsync /= 2;
381 		t.vbp /= 2;
382 	}
383 
384 	calc_ratio(&t);
385 
386 	s += std::to_string(t.hratio) + ":" + std::to_string(t.vratio);
387 
388 	switch ((x[3] >> 5) & 0x3) {
389 	case 0:
390 		s += ", no 3D stereo";
391 		break;
392 	case 1:
393 		s += ", 3D stereo";
394 		break;
395 	case 2:
396 		s += ", 3D stereo depends on user action";
397 		break;
398 	case 3:
399 		s += ", reserved";
400 		fail("Reserved stereo 0x03.\n");
401 		break;
402 	}
403 	if (x[3] & 0x80) {
404 		s += ", preferred";
405 		dispid.preferred_timings.push_back(timings_ext(t, "DTD", s));
406 	}
407 
408 	print_timings("    ", &t, "DTD", s.c_str(), true);
409 }
410 
411 // tag 0x05
412 
parse_displayid_type_3_timing(const unsigned char * x)413 void edid_state::parse_displayid_type_3_timing(const unsigned char *x)
414 {
415 	struct timings t = {};
416 	std::string s("aspect ");
417 
418 	switch (x[0] & 0xf) {
419 	case 0:
420 		s += "1:1";
421 		t.hratio = t.vratio = 1;
422 		break;
423 	case 1:
424 		s += "5:4";
425 		t.hratio = 5;
426 		t.vratio = 4;
427 		break;
428 	case 2:
429 		s += "4:3";
430 		t.hratio = 4;
431 		t.vratio = 3;
432 		break;
433 	case 3:
434 		s += "15:9";
435 		t.hratio = 15;
436 		t.vratio = 9;
437 		break;
438 	case 4:
439 		s += "16:9";
440 		t.hratio = 16;
441 		t.vratio = 9;
442 		break;
443 	case 5:
444 		s += "16:10";
445 		t.hratio = 16;
446 		t.vratio = 10;
447 		break;
448 	case 6:
449 		s += "64:27";
450 		t.hratio = 64;
451 		t.vratio = 27;
452 		break;
453 	case 7:
454 		s += "256:135";
455 		t.hratio = 256;
456 		t.vratio = 135;
457 		break;
458 	default:
459 		s += "undefined";
460 		if ((x[3] & 0xf) > (dispid.version <= 0x12 ? 7 : 8))
461 			fail("Unknown aspect 0x%02x.\n", x[3] & 0xf);
462 		break;
463 	}
464 
465 	t.rb = ((x[0] & 0x70) >> 4) == 1 ? RB_CVT_V1 : RB_NONE;
466 	t.hact = 8 + 8 * x[1];
467 	t.vact = t.hact * t.vratio / t.hratio;
468 
469 	edid_cvt_mode(1 + (x[2] & 0x7f), t);
470 
471 	if (x[0] & 0x80) {
472 		s += ", preferred";
473 		dispid.preferred_timings.push_back(timings_ext(t, "CVT", s));
474 	}
475 
476 	print_timings("    ", &t, "CVT", s.c_str());
477 }
478 
479 // tag 0x06 and 0x23
480 
parse_displayid_type_4_8_timing(unsigned char type,unsigned short id,bool is_cta)481 void edid_state::parse_displayid_type_4_8_timing(unsigned char type, unsigned short id, bool is_cta)
482 {
483 	const struct timings *t = NULL;
484 	char type_name[16];
485 
486 	switch (type) {
487 	case 0: t = find_dmt_id(id); sprintf(type_name, "DMT 0x%02x", id); break;
488 	case 1: t = find_vic_id(id); sprintf(type_name, "VIC %3u", id); break;
489 	case 2: t = find_hdmi_vic_id(id); sprintf(type_name, "HDMI VIC %u", id); break;
490 	default: break;
491 	}
492 	if (t)
493 		print_timings("    ", t, type_name);
494 	if (t && is_cta && !cta.t8vtdb.is_valid()) {
495 		timings_ext te(*t, type_name, "");
496 		cta.t8vtdb = te;
497 	}
498 }
499 
500 // tag 0x09
501 
parse_displayid_video_timing_range_limits(const unsigned char * x)502 void edid_state::parse_displayid_video_timing_range_limits(const unsigned char *x)
503 {
504 	check_displayid_datablock_revision(x[1]);
505 
506 	if (!check_displayid_datablock_length(x, 15, 15))
507 		return;
508 	printf("    Pixel Clock: %.3f-%.3f MHz\n",
509 	       (double)((x[3] | (x[4] << 8) | (x[5] << 16)) + 1) / 100.0,
510 	       (double)((x[6] | (x[7] << 8) | (x[8] << 16)) + 1) / 100.0);
511 	printf("    Horizontal Frequency: %u-%u kHz\n", x[9], x[10]);
512 	printf("    Minimum Horizontal Blanking: %u pixels\n", x[11] | (x[12] << 8));
513 	printf("    Vertical Refresh: %u-%u Hz\n", x[13], x[14]);
514 	printf("    Minimum Vertical Blanking: %u lines\n", x[15] | (x[16] << 8));
515 	if (x[17] & 0x80)
516 		printf("    Supports Interlaced\n");
517 	if (x[17] & 0x40)
518 		printf("    Supports CVT\n");
519 	if (x[17] & 0x20)
520 		printf("    Supports CVT Reduced Blanking\n");
521 	if (x[17] & 0x10)
522 		printf("    Discrete frequency display device\n");
523 }
524 
525 // tag 0x0a and 0x0b
526 
parse_displayid_string(const unsigned char * x)527 void edid_state::parse_displayid_string(const unsigned char *x)
528 {
529 	check_displayid_datablock_revision(x[1]);
530 	if (check_displayid_datablock_length(x))
531 		printf("    Text: '%s'\n", extract_string(x + 3, x[2]));
532 }
533 
534 // tag 0x0c
535 
parse_displayid_display_device(const unsigned char * x)536 void edid_state::parse_displayid_display_device(const unsigned char *x)
537 {
538 	check_displayid_datablock_revision(x[1]);
539 
540 	if (!check_displayid_datablock_length(x, 13, 13))
541 		return;
542 
543 	printf("    Display Device Technology: ");
544 	switch (x[3]) {
545 	case 0x00: printf("Monochrome CRT\n"); break;
546 	case 0x01: printf("Standard tricolor CRT\n"); break;
547 	case 0x02: printf("Other/undefined CRT\n"); break;
548 	case 0x10: printf("Passive matrix TN\n"); break;
549 	case 0x11: printf("Passive matrix cholesteric LC\n"); break;
550 	case 0x12: printf("Passive matrix ferroelectric LC\n"); break;
551 	case 0x13: printf("Other passive matrix LC type\n"); break;
552 	case 0x14: printf("Active-matrix TN\n"); break;
553 	case 0x15: printf("Active-matrix IPS (all types)\n"); break;
554 	case 0x16: printf("Active-matrix VA (all types)\n"); break;
555 	case 0x17: printf("Active-matrix OCB\n"); break;
556 	case 0x18: printf("Active-matrix ferroelectric\n"); break;
557 	case 0x1f: printf("Other LC type\n"); break;
558 	case 0x20: printf("DC plasma\n"); break;
559 	case 0x21: printf("AC plasma\n"); break;
560 	}
561 	switch (x[3] & 0xf0) {
562 	case 0x30: printf("Electroluminescent, except OEL/OLED\n"); break;
563 	case 0x40: printf("Inorganic LED\n"); break;
564 	case 0x50: printf("Organic LED/OEL\n"); break;
565 	case 0x60: printf("FED or sim. \"cold-cathode,\" phosphor-based types\n"); break;
566 	case 0x70: printf("Electrophoretic\n"); break;
567 	case 0x80: printf("Electrochromic\n"); break;
568 	case 0x90: printf("Electromechanical\n"); break;
569 	case 0xa0: printf("Electrowetting\n"); break;
570 	case 0xf0: printf("Other type not defined here\n"); break;
571 	}
572 	printf("    Display operating mode: ");
573 	switch (x[4] >> 4) {
574 	case 0x00: printf("Direct-view reflective, ambient light\n"); break;
575 	case 0x01: printf("Direct-view reflective, ambient light, also has light source\n"); break;
576 	case 0x02: printf("Direct-view reflective, uses light source\n"); break;
577 	case 0x03: printf("Direct-view transmissive, ambient light\n"); break;
578 	case 0x04: printf("Direct-view transmissive, ambient light, also has light source\n"); break;
579 	case 0x05: printf("Direct-view transmissive, uses light source\n"); break;
580 	case 0x06: printf("Direct-view emissive\n"); break;
581 	case 0x07: printf("Direct-view transflective, backlight off by default\n"); break;
582 	case 0x08: printf("Direct-view transflective, backlight on by default\n"); break;
583 	case 0x09: printf("Transparent display, ambient light\n"); break;
584 	case 0x0a: printf("Transparent emissive display\n"); break;
585 	case 0x0b: printf("Projection device using reflective light modulator\n"); break;
586 	case 0x0c: printf("Projection device using transmissive light modulator\n"); break;
587 	case 0x0d: printf("Projection device using emissive image transducer\n"); break;
588 	default: printf("Reserved\n"); break;
589 	}
590 	if (x[4] & 0x08)
591 		printf("    The backlight may be switched on and off\n");
592 	if (x[4] & 0x04)
593 		printf("    The backlight's intensity can be controlled\n");
594 	unsigned w = x[5] | (x[6] << 8);
595 	unsigned h = x[7] | (x[8] << 8);
596 	if (w && h) {
597 		printf("    Display native pixel format: %ux%u\n", w + 1, h + 1);
598 		dispid.native_width = w + 1;
599 		dispid.native_height = h + 1;
600 	} else if (w || h) {
601 		fail("Invalid Native Pixel Format %ux%u.\n", w, h);
602 	}
603 	printf("    Aspect ratio and orientation:\n");
604 	printf("      Aspect Ratio: %.2f\n", (100 + x[9]) / 100.0);
605 	unsigned char v = x[0x0a];
606 	printf("      Default Orientation: ");
607 	switch ((v & 0xc0) >> 6) {
608 	case 0x00: printf("Landscape\n"); break;
609 	case 0x01: printf("Portrait\n"); break;
610 	case 0x02: printf("Not Fixed\n"); break;
611 	case 0x03: printf("Undefined\n"); break;
612 	}
613 	printf("      Rotation Capability: ");
614 	switch ((v & 0x30) >> 4) {
615 	case 0x00: printf("None\n"); break;
616 	case 0x01: printf("Can rotate 90 degrees clockwise\n"); break;
617 	case 0x02: printf("Can rotate 90 degrees counterclockwise\n"); break;
618 	case 0x03: printf("Can rotate 90 degrees in either direction)\n"); break;
619 	}
620 	printf("      Zero Pixel Location: ");
621 	switch ((v & 0x0c) >> 2) {
622 	case 0x00: printf("Upper Left\n"); break;
623 	case 0x01: printf("Upper Right\n"); break;
624 	case 0x02: printf("Lower Left\n"); break;
625 	case 0x03: printf("Lower Right\n"); break;
626 	}
627 	printf("      Scan Direction: ");
628 	switch (v & 0x03) {
629 	case 0x00: printf("Not defined\n"); break;
630 	case 0x01: printf("Fast Scan is on the Major (Long) Axis and Slow Scan is on the Minor Axis\n"); break;
631 	case 0x02: printf("Fast Scan is on the Minor (Short) Axis and Slow Scan is on the Major Axis\n"); break;
632 	case 0x03: printf("Reserved\n");
633 		   fail("Scan Direction used the reserved value 0x03.\n");
634 		   break;
635 	}
636 	printf("    Sub-pixel layout/configuration/shape: ");
637 	switch (x[0x0b]) {
638 	case 0x00: printf("Not defined\n"); break;
639 	case 0x01: printf("RGB vertical stripes\n"); break;
640 	case 0x02: printf("RGB horizontal stripes\n"); break;
641 	case 0x03: printf("Vertical stripes using primary order\n"); break;
642 	case 0x04: printf("Horizontal stripes using primary order\n"); break;
643 	case 0x05: printf("Quad sub-pixels, red at top left\n"); break;
644 	case 0x06: printf("Quad sub-pixels, red at bottom left\n"); break;
645 	case 0x07: printf("Delta (triad) RGB sub-pixels\n"); break;
646 	case 0x08: printf("Mosaic\n"); break;
647 	case 0x09: printf("Quad sub-pixels, RGB + 1 additional color\n"); break;
648 	case 0x0a: printf("Five sub-pixels, RGB + 2 additional colors\n"); break;
649 	case 0x0b: printf("Six sub-pixels, RGB + 3 additional colors\n"); break;
650 	case 0x0c: printf("Clairvoyante, Inc. PenTile Matrix (tm) layout\n"); break;
651 	default: printf("Reserved\n"); break;
652 	}
653 	printf("    Horizontal and vertical dot/pixel pitch: %.2fx%.2f mm\n",
654 	       (double)(x[0x0c]) / 100.0, (double)(x[0x0d]) / 100.0);
655 	printf("    Color bit depth: %u\n", x[0x0e] & 0x0f);
656 	v = x[0x0f];
657 	printf("    Response time for %s transition: %u ms\n",
658 	       (v & 0x80) ? "white-to-black" : "black-to-white", v & 0x7f);
659 }
660 
661 // tag 0x0d
662 
parse_displayid_intf_power_sequencing(const unsigned char * x)663 void edid_state::parse_displayid_intf_power_sequencing(const unsigned char *x)
664 {
665 	check_displayid_datablock_revision(x[1]);
666 
667 	if (!check_displayid_datablock_length(x, 6, 6))
668 		return;
669 
670 	printf("    Power Sequence T1 Range: %.1f-%u.0 ms\n", (x[3] >> 4) / 10.0, (x[3] & 0xf) * 2);
671 	printf("    Power Sequence T2 Range: 0.0-%u.0 ms\n", (x[4] & 0x3f) * 2);
672 	printf("    Power Sequence T3 Range: 0.0-%u.0 ms\n", (x[5] & 0x3f) * 2);
673 	printf("    Power Sequence T4 Min: %u.0 ms\n", (x[6] & 0x7f) * 10);
674 	printf("    Power Sequence T5 Min: %u.0 ms\n", (x[7] & 0x3f) * 10);
675 	printf("    Power Sequence T6 Min: %u.0 ms\n", (x[8] & 0x3f) * 10);
676 }
677 
678 // tag 0x0e
679 
parse_displayid_transfer_characteristics(const unsigned char * x)680 void edid_state::parse_displayid_transfer_characteristics(const unsigned char *x)
681 {
682 	check_displayid_datablock_revision(x[1], 0xf0, 1);
683 
684 	unsigned xfer_id = x[1] >> 4;
685 	bool first_is_white = x[3] & 0x80;
686 	bool four_param = x[3] & 0x20;
687 
688 	if (xfer_id) {
689 		printf("    Transfer Characteristics Data Block Identifier: %u\n", xfer_id);
690 		if (!(dispid.preparsed_color_ids & (1 << xfer_id)))
691 			fail("Missing Color Characteristics Data Block using Identifier %u.\n", xfer_id);
692 	}
693 	if (first_is_white)
694 		printf("    The first curve is the 'white' transfer characteristic\n");
695 	if (x[3] & 0x40)
696 		printf("    Individual response curves\n");
697 
698 	unsigned offset = 4;
699 	unsigned len = x[2] - 1;
700 
701 	for (unsigned i = 0; len; i++) {
702 		if ((x[3] & 0x80) && !i)
703 			printf("    White curve:      ");
704 		else
705 			printf("    Response curve #%u:",
706 			       i - first_is_white);
707 		unsigned samples = x[offset];
708 		if (four_param) {
709 			if (samples != 5)
710 				fail("Expected 5 samples.\n");
711 			printf(" A0=%u A1=%u A2=%u A3=%u Gamma=%.2f\n",
712 			       x[offset + 1], x[offset + 2], x[offset + 3], x[offset + 4],
713 			       (double)(x[offset + 5] + 100.0) / 100.0);
714 			samples++;
715 		} else {
716 			double sum = 0;
717 
718 			// The spec is not very clear about the number of samples:
719 			// should this be interpreted as the actual number of
720 			// samples stored in this Data Block, or as the number of
721 			// samples in the curve, but where the last sample is not
722 			// actually stored since it is always 0x3ff.
723 			//
724 			// The ATP Manager interprets this as the latter, so that's
725 			// what we implement here.
726 			for (unsigned j = offset + 1; j < offset + samples; j++) {
727 				sum += x[j];
728 				printf(" %.2f", sum * 100.0 / 1023.0);
729 			}
730 			printf(" 100.00\n");
731 		}
732 		offset += samples;
733 		len -= samples;
734 	}
735 }
736 
737 // tag 0x0f
738 
parse_displayid_display_intf(const unsigned char * x)739 void edid_state::parse_displayid_display_intf(const unsigned char *x)
740 {
741 	check_displayid_datablock_revision(x[1]);
742 
743 	if (!check_displayid_datablock_length(x, 10, 10))
744 		return;
745 
746 	dispid.has_display_interface_features = true;
747 	printf("    Interface Type: ");
748 	switch (x[3] >> 4) {
749 	case 0x00:
750 		switch (x[3] & 0xf) {
751 		case 0x00: printf("Analog 15HD/VGA\n"); break;
752 		case 0x01: printf("Analog VESA NAVI-V (15HD)\n"); break;
753 		case 0x02: printf("Analog VESA NAVI-D\n"); break;
754 		default: printf("Reserved\n"); break;
755 		}
756 		break;
757 	case 0x01: printf("LVDS\n"); break;
758 	case 0x02: printf("TMDS\n"); break;
759 	case 0x03: printf("RSDS\n"); break;
760 	case 0x04: printf("DVI-D\n"); break;
761 	case 0x05: printf("DVI-I, analog\n"); break;
762 	case 0x06: printf("DVI-I, digital\n"); break;
763 	case 0x07: printf("HDMI-A\n"); break;
764 	case 0x08: printf("HDMI-B\n"); break;
765 	case 0x09: printf("MDDI\n"); break;
766 	case 0x0a: printf("DisplayPort\n"); break;
767 	case 0x0b: printf("Proprietary Digital Interface\n"); break;
768 	default: printf("Reserved\n"); break;
769 	}
770 	if (x[3] >> 4)
771 		printf("    Number of Links: %u\n", x[3] & 0xf);
772 	printf("    Interface Standard Version: %u.%u\n",
773 	       x[4] >> 4, x[4] & 0xf);
774 	print_flags("    Supported bpc for RGB encoding", x[5], bpc444);
775 	print_flags("    Supported bpc for YCbCr 4:4:4 encoding", x[6], bpc444);
776 	print_flags("    Supported bpc for YCbCr 4:2:2 encoding", x[7], bpc4xx);
777 	printf("    Supported Content Protection: ");
778 	switch (x[8] & 0xf) {
779 	case 0x00: printf("None\n"); break;
780 	case 0x01: printf("HDCP "); break;
781 	case 0x02: printf("DTCP "); break;
782 	case 0x03: printf("DPCP "); break;
783 	default: printf("Reserved "); break;
784 	}
785 	if (x[8] & 0xf)
786 		printf("%u.%u\n", x[9] >> 4, x[9] & 0xf);
787 	unsigned char v = x[0x0a] & 0xf;
788 	printf("    Spread Spectrum: ");
789 	switch (x[0x0a] >> 6) {
790 	case 0x00: printf("None\n"); break;
791 	case 0x01: printf("Down Spread %.1f%%\n", v / 10.0); break;
792 	case 0x02: printf("Center Spread %.1f%%\n", v / 10.0); break;
793 	case 0x03: printf("Reserved\n"); break;
794 	}
795 	switch (x[3] >> 4) {
796 	case 0x01:
797 		printf("    LVDS Color Mapping: %s mode\n",
798 		       (x[0x0b] & 0x10) ? "6 bit compatible" : "normal");
799 		if (x[0x0b] & 0x08) printf("    LVDS supports 2.8V\n");
800 		if (x[0x0b] & 0x04) printf("    LVDS supports 12V\n");
801 		if (x[0x0b] & 0x02) printf("    LVDS supports 5V\n");
802 		if (x[0x0b] & 0x01) printf("    LVDS supports 3.3V\n");
803 		printf("    LVDS %s Mode\n", (x[0x0c] & 0x04) ? "Fixed" : "DE");
804 		if (x[0x0c] & 0x04)
805 			printf("    LVDS %s Signal Level\n", (x[0x0c] & 0x02) ? "Low" : "High");
806 		else
807 			printf("    LVDS DE Polarity Active %s\n", (x[0x0c] & 0x02) ? "Low" : "High");
808 		printf("    LVDS Shift Clock Data Strobe at %s Edge\n", (x[0x0c] & 0x01) ? "Rising" : "Falling");
809 		break;
810 	case 0x0b:
811 		printf("    PDI %s Mode\n", (x[0x0b] & 0x04) ? "Fixed" : "DE");
812 		if (x[0x0b] & 0x04)
813 			printf("    PDI %s Signal Level\n", (x[0x0b] & 0x02) ? "Low" : "High");
814 		else
815 			printf("    PDI DE Polarity Active %s\n", (x[0x0b] & 0x02) ? "Low" : "High");
816 		printf("    PDI Shift Clock Data Strobe at %s Edge\n", (x[0x0b] & 0x01) ? "Rising" : "Falling");
817 		break;
818 	}
819 }
820 
821 // tag 0x10 and 0x27
822 
parse_displayid_stereo_display_intf(const unsigned char * x)823 void edid_state::parse_displayid_stereo_display_intf(const unsigned char *x)
824 {
825 	check_displayid_datablock_revision(x[1], 0xc0, 1);
826 
827 	switch (x[1] >> 6) {
828 	case 0x00: printf("    Timings that explicitly report 3D capability\n"); break;
829 	case 0x01: printf("    Timings that explicitly report 3D capability & Timing Codes listed here\n"); break;
830 	case 0x02: printf("    All listed timings\n"); break;
831 	case 0x03: printf("    Only Timings Codes listed here\n"); break;
832 	}
833 
834 	unsigned len = x[2];
835 
836 	switch (x[4]) {
837 	case 0x00:
838 		printf("    Field Sequential Stereo (L/R Polarity: %s)\n",
839 		       (x[5] & 1) ? "0/1" : "1/0");
840 		break;
841 	case 0x01:
842 		printf("    Side-by-side Stereo (Left Half = %s Eye View)\n",
843 		       (x[5] & 1) ? "Right" : "Left");
844 		break;
845 	case 0x02:
846 		printf("    Pixel Interleaved Stereo:\n");
847 		for (unsigned y = 0; y < 8; y++) {
848 			unsigned char v = x[5 + y];
849 
850 			printf("      ");
851 			for (int x = 7; x >= 0; x--)
852 				printf("%c", (v & (1 << x)) ? 'L' : 'R');
853 			printf("\n");
854 		}
855 		break;
856 	case 0x03:
857 		printf("    Dual Interface, Left and Right Separate\n");
858 		printf("      Carries the %s-eye view\n",
859 		       (x[5] & 1) ? "Right" : "Left");
860 		printf("      ");
861 		switch ((x[5] >> 1) & 3) {
862 		case 0x00: printf("No mirroring\n"); break;
863 		case 0x01: printf("Left/Right mirroring\n"); break;
864 		case 0x02: printf("Top/Bottom mirroring\n"); break;
865 		case 0x03: printf("Reserved\n"); break;
866 		}
867 		break;
868 	case 0x04:
869 		printf("    Multi-View: %u views, Interleaving Method Code: %u\n",
870 		       x[5], x[6]);
871 		break;
872 	case 0x05:
873 		printf("    Stacked Frame Stereo (Top Half = %s Eye View)\n",
874 		       (x[5] & 1) ? "Right" : "Left");
875 		break;
876 	case 0xff:
877 		printf("    Proprietary\n");
878 		break;
879 	default:
880 		printf("    Reserved\n");
881 		break;
882 	}
883 	if (!(x[1] & 0x40)) // Has No Timing Codes
884 		return;
885 	len -= 1 + x[3];
886 	x += 4 + x[3];
887 	while (1U + (x[0] & 0x1f) <= len) {
888 		unsigned num_codes = x[0] & 0x1f;
889 		unsigned type = x[0] >> 6;
890 		char type_name[16];
891 
892 		for (unsigned i = 1; i <= num_codes; i++) {
893 			switch (type) {
894 			case 0x00:
895 				sprintf(type_name, "DMT 0x%02x", x[i]);
896 				print_timings("    ", find_dmt_id(x[i]), type_name);
897 				break;
898 			case 0x01:
899 				sprintf(type_name, "VIC %3u", x[i]);
900 				print_timings("    ", find_vic_id(x[i]), type_name);
901 				break;
902 			case 0x02:
903 				sprintf(type_name, "HDMI VIC %u", x[i]);
904 				print_timings("    ", find_hdmi_vic_id(x[i]), type_name);
905 				break;
906 			}
907 		}
908 
909 		len -= 1 + num_codes;
910 		x += 1 + num_codes;
911 	}
912 }
913 
914 // tag 0x11
915 
parse_displayid_type_5_timing(const unsigned char * x)916 void edid_state::parse_displayid_type_5_timing(const unsigned char *x)
917 {
918 	struct timings t = {};
919 	std::string s("aspect ");
920 
921 	t.hact = 1 + (x[2] | (x[3] << 8));
922 	t.vact = 1 + (x[4] | (x[5] << 8));
923 	calc_ratio(&t);
924 	s += std::to_string(t.hratio) + ":" + std::to_string(t.vratio);
925 	switch ((x[0] >> 5) & 0x3) {
926 	case 0:
927 		s += ", no 3D stereo";
928 		break;
929 	case 1:
930 		s += ", 3D stereo";
931 		break;
932 	case 2:
933 		s += ", 3D stereo depends on user action";
934 		break;
935 	case 3:
936 		s += ", reserved";
937 		fail("Reserved stereo 0x03.\n");
938 		break;
939 	}
940 	if (x[0] & 0x10)
941 		s += ", refresh rate * (1000/1001) supported";
942 
943 	t.rb = RB_CVT_V2;
944 	if ((x[0] & 0x03) == 1)
945 		warn("Unexpected use of 'custom reduced blanking'.\n");
946 	else if ((x[0] & 0x03) > 1)
947 		fail("Invalid Timing Formula.\n");
948 
949 	edid_cvt_mode(1 + x[6], t);
950 
951 	if (x[0] & 0x80) {
952 		s += ", preferred";
953 		dispid.preferred_timings.push_back(timings_ext(t, "CVT", s));
954 	}
955 
956 	print_timings("    ", &t, "CVT", s.c_str());
957 }
958 
959 // tag 0x12 and 0x28
960 
parse_displayid_tiled_display_topology(const unsigned char * x,bool is_v2)961 void edid_state::parse_displayid_tiled_display_topology(const unsigned char *x, bool is_v2)
962 {
963 	check_displayid_datablock_revision(x[1]);
964 
965 	if (!check_displayid_datablock_length(x, 22, 22))
966 		return;
967 
968 	unsigned caps = x[3];
969 	unsigned num_v_tile = (x[4] & 0xf) | (x[6] & 0x30);
970 	unsigned num_h_tile = (x[4] >> 4) | ((x[6] >> 2) & 0x30);
971 	unsigned tile_v_location = (x[5] & 0xf) | ((x[6] & 0x3) << 4);
972 	unsigned tile_h_location = (x[5] >> 4) | (((x[6] >> 2) & 0x3) << 4);
973 	unsigned tile_width = x[7] | (x[8] << 8);
974 	unsigned tile_height = x[9] | (x[10] << 8);
975 	unsigned pix_mult = x[11];
976 
977 	printf("    Capabilities:\n");
978 	printf("      Behavior if it is the only tile: ");
979 	switch (caps & 0x07) {
980 	case 0x00: printf("Undefined\n"); break;
981 	case 0x01: printf("Image is displayed at the Tile Location\n"); break;
982 	case 0x02: printf("Image is scaled to fit the entire tiled display\n"); break;
983 	case 0x03: printf("Image is cloned to all other tiles\n"); break;
984 	default: printf("Reserved\n"); break;
985 	}
986 	printf("      Behavior if more than one tile and fewer than total number of tiles: ");
987 	switch ((caps >> 3) & 0x03) {
988 	case 0x00: printf("Undefined\n"); break;
989 	case 0x01: printf("Image is displayed at the Tile Location\n"); break;
990 	default: printf("Reserved\n"); break;
991 	}
992 	if (caps & 0x80)
993 		printf("    Tiled display consists of a single physical display enclosure\n");
994 	else
995 		printf("    Tiled display consists of multiple physical display enclosures\n");
996 	printf("    Num horizontal tiles: %u Num vertical tiles: %u\n",
997 	       num_h_tile + 1, num_v_tile + 1);
998 	printf("    Tile location: %u, %u\n", tile_h_location, tile_v_location);
999 	printf("    Tile resolution: %ux%u\n", tile_width + 1, tile_height + 1);
1000 	if (caps & 0x40) {
1001 		if (pix_mult) {
1002 			printf("    Top bevel size: %.1f pixels\n",
1003 			       pix_mult * x[12] / 10.0);
1004 			printf("    Bottom bevel size: %.1f pixels\n",
1005 			       pix_mult * x[13] / 10.0);
1006 			printf("    Right bevel size: %.1f pixels\n",
1007 			       pix_mult * x[14] / 10.0);
1008 			printf("    Left bevel size: %.1f pixels\n",
1009 			       pix_mult * x[15] / 10.0);
1010 		} else {
1011 			fail("No bevel information, but the pixel multiplier is non-zero.\n");
1012 		}
1013 		printf("    Tile resolution: %ux%u\n", tile_width + 1, tile_height + 1);
1014 	} else if (pix_mult) {
1015 		fail("No bevel information, but the pixel multiplier is non-zero.\n");
1016 	}
1017 	if (is_v2)
1018 		printf("    Tiled Display Manufacturer/Vendor ID: %02X-%02X-%02X\n",
1019 		       x[0x10], x[0x11], x[0x12]);
1020 	else
1021 		printf("    Tiled Display Manufacturer/Vendor ID: %c%c%c\n",
1022 		       x[0x10], x[0x11], x[0x12]);
1023 	printf("    Tiled Display Product ID Code: %u\n",
1024 	       x[0x13] | (x[0x14] << 8));
1025 	if (hide_serial_numbers)
1026 		printf("    Tiled Display Serial Number: ...\n");
1027 	else
1028 		printf("    Tiled Display Serial Number: %u\n",
1029 		       x[0x15] | (x[0x16] << 8) | (x[0x17] << 16)| (x[0x18] << 24));
1030 }
1031 
1032 // tag 0x13
1033 
parse_displayid_type_6_timing(const unsigned char * x)1034 void edid_state::parse_displayid_type_6_timing(const unsigned char *x)
1035 {
1036 	struct timings t = {};
1037 	std::string s("aspect ");
1038 
1039 	t.pixclk_khz = 1 + (x[0] + (x[1] << 8) + ((x[2] & 0x3f) << 16));
1040 	t.hact = 1 + (x[3] | ((x[4] & 0x3f) << 8));
1041 	if ((x[4] >> 7) & 0x1)
1042 		t.pos_pol_hsync = true;
1043 	unsigned hbl = 1 + (x[7] | ((x[9] & 0xf) << 8));
1044 	t.hfp = 1 + (x[8] | ((x[9] & 0xf0) << 4));
1045 	t.hsync = 1 + x[10];
1046 	t.hbp = hbl - t.hfp - t.hsync;
1047 	t.vact = 1 + (x[5] | ((x[6] & 0x3f) << 8));
1048 	if ((x[6] >> 7) & 0x1)
1049 		t.pos_pol_vsync = true;
1050 	unsigned vbl = 1 + x[11];
1051 	t.vfp = 1 + x[12];
1052 	t.vsync = 1 + (x[13] & 0x0f);
1053 	t.vbp = vbl - t.vfp - t.vsync;
1054 
1055 	if (x[13] & 0x80) {
1056 		t.interlaced = true;
1057 		t.vfp /= 2;
1058 		t.vsync /= 2;
1059 		t.vbp /= 2;
1060 	}
1061 	calc_ratio(&t);
1062 	s += std::to_string(t.hratio) + ":" + std::to_string(t.vratio);
1063 	if (x[2] & 0x40) {
1064 		double aspect_mult = x[14] * 3.0 / 256.0;
1065 		unsigned size_mult = 1 + (x[16] >> 4);
1066 
1067 		t.vsize_mm = size_mult * (1 + (x[15] | ((x[16] & 0xf) << 8)));
1068 		t.hsize_mm = t.vsize_mm * aspect_mult;
1069 	}
1070 
1071 	switch ((x[13] >> 5) & 0x3) {
1072 	case 0:
1073 		s += ", no 3D stereo";
1074 		break;
1075 	case 1:
1076 		s += ", 3D stereo";
1077 		break;
1078 	case 2:
1079 		s += ", 3D stereo depends on user action";
1080 		break;
1081 	case 3:
1082 		s += ", reserved";
1083 		fail("Reserved stereo 0x03.\n");
1084 		break;
1085 	}
1086 
1087 	if (x[2] & 0x80) {
1088 		s += ", preferred";
1089 		dispid.preferred_timings.push_back(timings_ext(t, "DTD", s));
1090 	}
1091 
1092 	print_timings("    ", &t, "DTD", s.c_str(), true);
1093 }
1094 
ieee7542d(unsigned short fp)1095 static std::string ieee7542d(unsigned short fp)
1096 {
1097 	int exp = ((fp & 0x7c00) >> 10) - 15;
1098 	unsigned fract = (fp & 0x3ff) | 0x400;
1099 
1100 	if (fp == 0x8000)
1101 		return "do not use";
1102 	if (fp & 0x8000)
1103 		return "reserved";
1104 	return std::to_string(pow(2, exp) * fract / 1024.0) + " cd/m^2";
1105 }
1106 
1107 // tag 0x21
1108 
parse_displayid_parameters_v2(const unsigned char * x,unsigned block_rev)1109 void edid_state::parse_displayid_parameters_v2(const unsigned char *x,
1110 					       unsigned block_rev)
1111 {
1112 	if (!check_displayid_datablock_length(x, 29, 29))
1113 		return;
1114 
1115 	unsigned hor_size = (x[4] << 8) + x[3];
1116 	unsigned vert_size = (x[6] << 8) + x[5];
1117 
1118 	dispid.has_display_parameters = true;
1119 	if (x[1] & 0x80)
1120 		printf("    Image size: %u mm x %u mm\n",
1121 		       hor_size, vert_size);
1122 	else
1123 		printf("    Image size: %.1f mm x %.1f mm\n",
1124 		       hor_size / 10.0, vert_size / 10.0);
1125 	unsigned w = (x[8] << 8) + x[7];
1126 	unsigned h = (x[10] << 8) + x[9];
1127 	if (w && h) {
1128 		printf("    Native Format: %ux%u\n", w, h);
1129 		dispid.native_width = w;
1130 		dispid.native_height = h;
1131 	} else if (w || h) {
1132 		fail("Invalid Native Format %ux%u.\n", w, h);
1133 	}
1134 	unsigned char v = x[11];
1135 	printf("    Scan Orientation: ");
1136 	switch (v & 0x07) {
1137 	case 0x00: printf("Left to Right, Top to Bottom\n"); break;
1138 	case 0x01: printf("Right to Left, Top to Bottom\n"); break;
1139 	case 0x02: printf("Top to Bottom, Right to Left\n"); break;
1140 	case 0x03: printf("Bottom to Top, Right to Left\n"); break;
1141 	case 0x04: printf("Right to Left, Bottom to Top\n"); break;
1142 	case 0x05: printf("Left to Right, Bottom to Top\n"); break;
1143 	case 0x06: printf("Bottom to Top, Left to Right\n"); break;
1144 	case 0x07: printf("Top to Bottom, Left to Right\n"); break;
1145 	}
1146 	printf("    Luminance Information: ");
1147 	switch ((v >> 3) & 0x03) {
1148 	case 0x00: printf("Minimum guaranteed value\n"); break;
1149 	case 0x01: printf("Guidance for the Source device\n"); break;
1150 	default: printf("Reserved\n"); break;
1151 	}
1152 	printf("    Color Information: CIE %u\n",
1153 	       (v & 0x40) ? 1976 : 1931);
1154 	printf("    Audio Speaker Information: %sintegrated\n",
1155 	       (v & 0x80) ? "not " : "");
1156 	printf("    Native Color Chromaticity:\n");
1157 	printf("      Primary #1:  (%.6f, %.6f)\n",
1158 	       fp2d(x[0x0c] | ((x[0x0d] & 0x0f) << 8)),
1159 	       fp2d(((x[0x0d] & 0xf0) >> 4) | (x[0x0e] << 4)));
1160 	printf("      Primary #2:  (%.6f, %.6f)\n",
1161 	       fp2d(x[0x0f] | ((x[0x10] & 0x0f) << 8)),
1162 	       fp2d(((x[0x10] & 0xf0) >> 4) | (x[0x11] << 4)));
1163 	printf("      Primary #3:  (%.6f, %.6f)\n",
1164 	       fp2d(x[0x12] | ((x[0x13] & 0x0f) << 8)),
1165 	       fp2d(((x[0x13] & 0xf0) >> 4) | (x[0x14] << 4)));
1166 	printf("      White Point: (%.6f, %.6f)\n",
1167 	       fp2d(x[0x15] | ((x[0x16] & 0x0f) << 8)),
1168 	       fp2d(((x[0x16] & 0xf0) >> 4) | (x[0x17] << 4)));
1169 	printf("    Native Maximum Luminance (Full Coverage): %s\n",
1170 	       ieee7542d(x[0x18] | (x[0x19] << 8)).c_str());
1171 	printf("    Native Maximum Luminance (10%% Rectangular Coverage): %s\n",
1172 	       ieee7542d(x[0x1a] | (x[0x1b] << 8)).c_str());
1173 	printf("    Native Minimum Luminance: %s\n",
1174 	       ieee7542d(x[0x1c] | (x[0x1d] << 8)).c_str());
1175 	printf("    Native Color Depth: ");
1176 	if (!(x[0x1e] & 0x07))
1177 		printf("Not defined\n");
1178 	else if (bpc444[x[0x1e] & 0x07])
1179 		printf("%s bpc\n", bpc444[x[0x1e] & 0x07]);
1180 	else
1181 		printf("Reserved\n");
1182 	printf("    Display Device Technology: ");
1183 	switch ((x[0x1e] >> 4) & 0x07) {
1184 	case 0x00: printf("Not Specified\n"); break;
1185 	case 0x01: printf("Active Matrix LCD\n"); break;
1186 	case 0x02: printf("Organic LED\n"); break;
1187 	default: printf("Reserved\n"); break;
1188 	}
1189 	if (block_rev)
1190 		printf("    Display Device Theme Preference: %s\n",
1191 		       (x[0x1e] & 0x80) ? "Dark Theme Preferred" : "No Preference");
1192 	if (x[0x1f] != 0xff)
1193 		printf("    Native Gamma EOTF: %.2f\n",
1194 		       (100 + x[0x1f]) / 100.0);
1195 }
1196 
1197 // tag 0x24
1198 
parse_displayid_type_9_timing(const unsigned char * x)1199 void edid_state::parse_displayid_type_9_timing(const unsigned char *x)
1200 {
1201 	struct timings t = {};
1202 	std::string s("aspect ");
1203 
1204 	t.hact = 1 + (x[1] | (x[2] << 8));
1205 	t.vact = 1 + (x[3] | (x[4] << 8));
1206 	calc_ratio(&t);
1207 	s += std::to_string(t.hratio) + ":" + std::to_string(t.vratio);
1208 	switch ((x[0] >> 5) & 0x3) {
1209 	case 0:
1210 		s += ", no 3D stereo";
1211 		break;
1212 	case 1:
1213 		s += ", 3D stereo";
1214 		break;
1215 	case 2:
1216 		s += ", 3D stereo depends on user action";
1217 		break;
1218 	case 3:
1219 		s += ", reserved";
1220 		fail("Reserved stereo 0x03.\n");
1221 		break;
1222 	}
1223 	if (x[0] & 0x10)
1224 		s += ", refresh rate * (1000/1001) supported";
1225 
1226 	switch (x[0] & 0x07) {
1227 	case 1: t.rb = RB_CVT_V1; break;
1228 	case 2: t.rb = RB_CVT_V2; break;
1229 	default: break;
1230 	}
1231 
1232 	edid_cvt_mode(1 + x[5], t);
1233 
1234 	print_timings("    ", &t, "CVT", s.c_str());
1235 }
1236 
1237 // tag 0x25
1238 
parse_displayid_dynamic_video_timings_range_limits(const unsigned char * x)1239 void edid_state::parse_displayid_dynamic_video_timings_range_limits(const unsigned char *x)
1240 {
1241 	check_displayid_datablock_revision(x[1], 0, (x[1] & 7) == 1);
1242 
1243 	if (!check_displayid_datablock_length(x, 9, 9))
1244 		return;
1245 
1246 	printf("    Minimum Pixel Clock: %u kHz\n",
1247 	       1 + (x[3] | (x[4] << 8) | (x[5] << 16)));
1248 	printf("    Maximum Pixel Clock: %u kHz\n",
1249 	       1 + (x[6] | (x[7] << 8) | (x[8] << 16)));
1250 	printf("    Minimum Vertical Refresh Rate: %u Hz\n", x[9]);
1251 	if (x[1] & 7)
1252 		printf("    Maximum Vertical Refresh Rate: %u Hz\n", x[10] + ((x[11] & 3) << 8));
1253 	else
1254 		printf("    Maximum Vertical Refresh Rate: %u Hz\n", x[10]);
1255 	printf("    Seamless Dynamic Video Timing Support: %s\n",
1256 	       (x[11] & 0x80) ? "Yes" : "No");
1257 }
1258 
1259 // tag 0x26
1260 
1261 static const char *colorspace_eotf_combinations[] = {
1262 	"sRGB",
1263 	"BT.601",
1264 	"BT.709/BT.1886",
1265 	"Adobe RGB",
1266 	"DCI-P3",
1267 	"BT.2020",
1268 	"BT.2020/SMPTE ST 2084"
1269 };
1270 
1271 static const char *colorspace_eotf_reserved[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
1272 
1273 static const char *colorspaces[] = {
1274 	"Undefined",
1275 	"sRGB",
1276 	"BT.601",
1277 	"BT.709",
1278 	"Adobe RGB",
1279 	"DCI-P3",
1280 	"BT.2020",
1281 	"Custom"
1282 };
1283 
1284 static const char *eotfs[] = {
1285 	"Undefined",
1286 	"sRGB",
1287 	"BT.601",
1288 	"BT.1886",
1289 	"Adobe RGB",
1290 	"DCI-P3",
1291 	"BT.2020",
1292 	"Gamma function",
1293 	"SMPTE ST 2084",
1294 	"Hybrid Log",
1295 	"Custom"
1296 };
1297 
parse_displayid_interface_features(const unsigned char * x)1298 void edid_state::parse_displayid_interface_features(const unsigned char *x)
1299 {
1300 	check_displayid_datablock_revision(x[1]);
1301 
1302 	if (!check_displayid_datablock_length(x, 9))
1303 		return;
1304 
1305 	dispid.has_display_interface_features = true;
1306 	unsigned len = x[2];
1307 	if (len > 0) print_flags("    Supported bpc for RGB encoding", x[3], bpc444);
1308 	if (len > 1) print_flags("    Supported bpc for YCbCr 4:4:4 encoding", x[4], bpc444);
1309 	if (len > 2) print_flags("    Supported bpc for YCbCr 4:2:2 encoding", x[5], bpc4xx);
1310 	if (len > 3) print_flags("    Supported bpc for YCbCr 4:2:0 encoding", x[6], bpc4xx);
1311 	if (len > 4 && x[7])
1312 		printf("    Minimum pixel rate at which YCbCr 4:2:0 encoding is supported: %.3f MHz\n",
1313 		       74.25 * x[7]);
1314 	if (len > 5) print_flags("    Supported audio capability and features (kHz)",
1315 				 x[8], audiorates, true);
1316 	if (len > 6) print_flags("    Supported color space and EOTF standard combination 1",
1317 				 x[9], colorspace_eotf_combinations);
1318 	if (len > 7) print_flags("    Supported color space and EOTF standard combination 2",x[10], colorspace_eotf_reserved);
1319 
1320 	unsigned i = 0;
1321 
1322 	if (len > 8 && x[11]) {
1323 		printf("    Supported color space and EOTF additional combinations:");
1324 		for (i = 0; i < x[11]; i++) {
1325 			if (i > 6) {
1326 				printf("\n    Number of additional color space and EOTF combinations (%d) is greater than allowed (7).", x[11]);
1327 				break;
1328 			} else if (i + 10 > len) {
1329 				printf("\n    Number of additional color space and EOTF combinations (%d) is too many to fit in block (%d).", x[11], len - 9);
1330 				break;
1331 			}
1332 
1333 			const char *colorspace = "Out of range";
1334 			const char *eotf = "Out of range";
1335 			unsigned colorspace_index = (x[12 + i] >> 4) & 0xf;
1336 			unsigned eotf_index = x[12 + i] & 0xf;
1337 
1338 			if (colorspace_index < sizeof(colorspaces) / sizeof(colorspaces[0]))
1339 				colorspace = colorspaces[colorspace_index];
1340 			if (eotf_index < sizeof(eotfs) / sizeof(eotfs[0]))
1341 				eotf = eotfs[eotf_index];
1342 
1343 			if (i > 0)
1344 				printf(", ");
1345 			if (!strcmp(colorspace, eotf))
1346 				printf("%s", colorspace);
1347 			else
1348 				printf("%s/%s", colorspace, eotf);
1349 		}
1350 		printf("\n");
1351 	}
1352 	check_displayid_datablock_length(x, 9 + i, 9 + i, 9 + i);
1353 }
1354 
1355 // tag 0x29
1356 
parse_displayid_ContainerID(const unsigned char * x)1357 void edid_state::parse_displayid_ContainerID(const unsigned char *x)
1358 {
1359 	check_displayid_datablock_revision(x[1]);
1360 
1361 	if (check_displayid_datablock_length(x, 16, 16)) {
1362 		x += 3;
1363 		printf("    Container ID: %s\n", containerid2s(x).c_str());
1364 	}
1365 }
1366 
1367 // tag 0x32
1368 
parse_displayid_type_10_timing(const unsigned char * x,bool is_cta)1369 void edid_state::parse_displayid_type_10_timing(const unsigned char *x, bool is_cta)
1370 {
1371 	struct timings t = {};
1372 	std::string s("aspect ");
1373 
1374 	t.hact = 1 + (x[1] | (x[2] << 8));
1375 	t.vact = 1 + (x[3] | (x[4] << 8));
1376 	calc_ratio(&t);
1377 	s += std::to_string(t.hratio) + ":" + std::to_string(t.vratio);
1378 
1379 	switch ((x[0] >> 5) & 0x3) {
1380 	case 0:
1381 		s += ", no 3D stereo";
1382 		break;
1383 	case 1:
1384 		s += ", 3D stereo";
1385 		break;
1386 	case 2:
1387 		s += ", 3D stereo depends on user action";
1388 		break;
1389 	case 3:
1390 		s += ", reserved";
1391 		fail("Reserved stereo 0x03.\n");
1392 		break;
1393 	}
1394 
1395 	switch (x[0] & 0x07) {
1396 	case 1: t.rb = RB_CVT_V1; break;
1397 	case 2: t.rb = RB_CVT_V2; break;
1398 	case 3: t.rb = RB_CVT_V3; break;
1399 	default: break;
1400 	}
1401 
1402 	if (x[0] & 0x10) {
1403 		if (t.rb == RB_CVT_V2) {
1404 			s += ", refresh rate * (1000/1001) supported";
1405 			t.rb |= RB_ALT;
1406 		} else if (t.rb == RB_CVT_V3) {
1407 			s += ", hblank is 160 pixels";
1408 			t.rb |= RB_ALT;
1409 		} else {
1410 			fail("VR_HB must be 0.\n");
1411 		}
1412 	}
1413 	if (x[0] & 0x80)
1414 		s += ", YCbCr 4:2:0";
1415 
1416 	edid_cvt_mode(1 + x[5], t);
1417 
1418 	print_timings("    ", &t, "CVT", s.c_str());
1419 	if (is_cta) {
1420 		timings_ext te(t, "CVT", s);
1421 		cta.vec_vtdbs.push_back(te);
1422 	}
1423 }
1424 
1425 // tag 0x7e, OUI 3A-02-92 (VESA)
1426 
parse_displayid_vesa(const unsigned char * x)1427 void edid_state::parse_displayid_vesa(const unsigned char *x)
1428 {
1429 	check_displayid_datablock_revision(x[1]);
1430 
1431 	if (!check_displayid_datablock_length(x, 5, 7))
1432 		return;
1433 
1434 	unsigned len = x[2];
1435 	x += 6;
1436 	printf("    Data Structure Type: ");
1437 	switch (x[0] & 0x07) {
1438 	case 0x00: printf("eDP\n"); break;
1439 	case 0x01: printf("DP\n"); break;
1440 	default: printf("Reserved\n"); break;
1441 	}
1442 	printf("    Default Colorspace and EOTF Handling: %s\n",
1443 	       (x[0] & 0x80) ? "Native as specified in the Display Parameters DB" : "sRGB");
1444 	printf("    Number of Pixels in Hor Pix Cnt Overlapping an Adjacent Panel: %u\n",
1445 	       x[1] & 0xf);
1446 	printf("    Multi-SST Operation: ");
1447 	switch ((x[1] >> 5) & 0x03) {
1448 	case 0x00: printf("Not Supported\n"); break;
1449 	case 0x01: printf("Two Streams (number of links shall be 2 or 4)\n"); break;
1450 	case 0x02: printf("Four Streams (number of links shall be 4)\n"); break;
1451 	case 0x03: printf("Reserved\n"); break;
1452 	}
1453 	if (len >= 7) {
1454 		double bpp = (x[2] & 0x3f) + (x[3] & 0x0f) / 16.0;
1455 		printf("    Pass through timing's target DSC bits per pixel: %.4f\n", bpp);
1456 	}
1457 }
1458 
1459 // tag 0x81
1460 
parse_displayid_cta_data_block(const unsigned char * x)1461 void edid_state::parse_displayid_cta_data_block(const unsigned char *x)
1462 {
1463 	check_displayid_datablock_revision(x[1]);
1464 
1465 	unsigned len = x[2];
1466 	unsigned i;
1467 
1468 	if (len > 248) {
1469 		fail("Length is > 248.\n");
1470 		len = 248;
1471 	}
1472 	x += 3;
1473 
1474 	for (i = 0; i < len; i += (x[i] & 0x1f) + 1) {
1475 		unsigned tag = (x[i] & 0xe0) << 3;
1476 
1477 		if (tag == 0x700)
1478 			tag |= x[i + 1];
1479 		bool duplicate = dispid.found_tags.find(tag) != dispid.found_tags.end();
1480 
1481 		cta_block(x + i, duplicate);
1482 		if (!duplicate)
1483 			dispid.found_tags.insert(tag);
1484 	}
1485 
1486 	if (i != len)
1487 		fail("Length is %u instead of %u.\n", len, i);
1488 }
1489 
1490 // DisplayID main
1491 
product_type(unsigned char x,bool heading)1492 std::string edid_state::product_type(unsigned char x, bool heading)
1493 {
1494 	std::string headingstr;
1495 
1496 	if (dispid.version < 0x20) {
1497 		headingstr = "Display Product Type";
1498 		if (heading) return headingstr;
1499 		dispid.is_display = x == 2 || x == 3 || x == 4 || x == 6;
1500 		switch (x) {
1501 		case 0: return "Extension Section";
1502 		case 1: return "Test Structure; test equipment only";
1503 		case 2: return "Display panel or other transducer, LCD or PDP module, etc.";
1504 		case 3: return "Standalone display device";
1505 		case 4: return "Television receiver";
1506 		case 5: return "Repeater/translator";
1507 		case 6: return "DIRECT DRIVE monitor";
1508 		default: break;
1509 		}
1510 	} else {
1511 		headingstr = "Display Product Primary Use Case";
1512 		if (heading) return headingstr;
1513 		dispid.is_display = x >= 2 && x <= 8;
1514 		switch (x) {
1515 		case 0: return "Same primary use case as the base section";
1516 		case 1: return "Test Structure; test equipment only";
1517 		case 2: return "None of the listed primary use cases; generic display";
1518 		case 3: return "Television (TV) display";
1519 		case 4: return "Desktop productivity display";
1520 		case 5: return "Desktop gaming display";
1521 		case 6: return "Presentation display";
1522 		case 7: return "Head-mounted Virtual Reality (VR) display";
1523 		case 8: return "Head-mounted Augmented Reality (AR) display";
1524 		default: break;
1525 		}
1526 	}
1527 	fail("Unknown %s 0x%02x.\n", headingstr.c_str(), x);
1528 	return std::string("Unknown " + headingstr + " (") + utohex(x) + ")";
1529 }
1530 
preparse_displayid_block(const unsigned char * x)1531 void edid_state::preparse_displayid_block(const unsigned char *x)
1532 {
1533 	unsigned length = x[2];
1534 
1535 	if (length > 121)
1536 		length = 121;
1537 
1538 	unsigned offset = 5;
1539 
1540 	dispid.preparsed_displayid_blocks++;
1541 	while (length > 0) {
1542 		unsigned tag = x[offset];
1543 		unsigned len = x[offset + 2];
1544 
1545 		switch (tag) {
1546 		case 0x02:
1547 			dispid.preparsed_color_ids |= 1 << ((x[offset + 1] >> 3) & 0x0f);
1548 			break;
1549 		case 0x0e:
1550 			dispid.preparsed_xfer_ids |= 1 << ((x[offset + 1] >> 4) & 0x0f);
1551 			break;
1552 		default:
1553 			break;
1554 		}
1555 
1556 		if (length < 3)
1557 			break;
1558 
1559 		if (length < len + 3)
1560 			break;
1561 
1562 		if (!tag && !len)
1563 			break;
1564 
1565 		length -= len + 3;
1566 		offset += len + 3;
1567 	}
1568 }
1569 
parse_displayid_block(const unsigned char * x)1570 void edid_state::parse_displayid_block(const unsigned char *x)
1571 {
1572 	unsigned version = x[1];
1573 	unsigned length = x[2];
1574 	unsigned prod_type = x[3]; // future check: based on type, check for required data blocks
1575 	unsigned ext_count = x[4];
1576 	unsigned i;
1577 
1578 	printf("  Version: %u.%u\n  Extension Count: %u\n",
1579 	       version >> 4, version & 0xf, ext_count);
1580 
1581 	if (dispid.is_base_block) {
1582 		dispid.version = version;
1583 		printf("  %s: %s\n", product_type(prod_type, true).c_str(),
1584 		       product_type(prod_type, false).c_str());
1585 		if (!prod_type)
1586 			fail("DisplayID Base Block has no product type.\n");
1587 		if (ext_count != dispid.preparsed_displayid_blocks - 1)
1588 			fail("Expected %u DisplayID Extension Block%s, but got %u.\n",
1589 			     ext_count,
1590 			     ext_count > 1 ? "s" : "",
1591 			     dispid.preparsed_displayid_blocks - 1);
1592 	} else {
1593 		if (prod_type)
1594 			fail("Product Type should be 0 in extension block.\n");
1595 		if (ext_count)
1596 			fail("Extension Count should be 0 in extension block.\n");
1597 		if (version != dispid.version)
1598 			fail("Got version %u.%u, expected %u.%u.\n",
1599 			     version >> 4, version & 0xf,
1600 			     dispid.version >> 4, dispid.version & 0xf);
1601 	}
1602 
1603 	if (length > 121) {
1604 		fail("DisplayID length %d is greater than 121.\n", length);
1605 		length = 121;
1606 	}
1607 
1608 	unsigned offset = 5;
1609 	bool first_data_block = true;
1610 	while (length > 0) {
1611 		unsigned tag = x[offset];
1612 		unsigned oui = 0;
1613 
1614 		switch (tag) {
1615 		// DisplayID 1.3:
1616 		case 0x00: data_block = "Product Identification Data Block (" + utohex(tag) + ")"; break;
1617 		case 0x01: data_block = "Display Parameters Data Block (" + utohex(tag) + ")"; break;
1618 		case 0x02: data_block = "Color Characteristics Data Block"; break;
1619 		case 0x03: data_block = "Video Timing Modes Type 1 - Detailed Timings Data Block"; break;
1620 		case 0x04: data_block = "Video Timing Modes Type 2 - Detailed Timings Data Block"; break;
1621 		case 0x05: data_block = "Video Timing Modes Type 3 - Short Timings Data Block"; break;
1622 		case 0x06: data_block = "Video Timing Modes Type 4 - DMT Timings Data Block"; break;
1623 		case 0x07: data_block = "Supported Timing Modes Type 1 - VESA DMT Timings Data Block"; break;
1624 		case 0x08: data_block = "Supported Timing Modes Type 2 - CTA-861 Timings Data Block"; break;
1625 		case 0x09: data_block = "Video Timing Range Data Block"; break;
1626 		case 0x0a: data_block = "Product Serial Number Data Block"; break;
1627 		case 0x0b: data_block = "GP ASCII String Data Block"; break;
1628 		case 0x0c: data_block = "Display Device Data Data Block"; break;
1629 		case 0x0d: data_block = "Interface Power Sequencing Data Block"; break;
1630 		case 0x0e: data_block = "Transfer Characteristics Data Block"; break;
1631 		case 0x0f: data_block = "Display Interface Data Block"; break;
1632 		case 0x10: data_block = "Stereo Display Interface Data Block (" + utohex(tag) + ")"; break;
1633 		case 0x11: data_block = "Video Timing Modes Type 5 - Short Timings Data Block"; break;
1634 		case 0x12: data_block = "Tiled Display Topology Data Block (" + utohex(tag) + ")"; break;
1635 		case 0x13: data_block = "Video Timing Modes Type 6 - Detailed Timings Data Block"; break;
1636 		// 0x14 .. 0x7e RESERVED for Additional VESA-defined Data Blocks
1637 		// DisplayID 2.0
1638 		case 0x20: data_block = "Product Identification Data Block (" + utohex(tag) + ")"; break;
1639 		case 0x21: data_block = "Display Parameters Data Block (" + utohex(tag) + ")"; break;
1640 		case 0x22: data_block = "Video Timing Modes Type 7 - Detailed Timings Data Block"; break;
1641 		case 0x23: data_block = "Video Timing Modes Type 8 - Enumerated Timing Codes Data Block"; break;
1642 		case 0x24: data_block = "Video Timing Modes Type 9 - Formula-based Timings Data Block"; break;
1643 		case 0x25: data_block = "Dynamic Video Timing Range Limits Data Block"; break;
1644 		case 0x26: data_block = "Display Interface Features Data Block"; break;
1645 		case 0x27: data_block = "Stereo Display Interface Data Block (" + utohex(tag) + ")"; break;
1646 		case 0x28: data_block = "Tiled Display Topology Data Block (" + utohex(tag) + ")"; break;
1647 		case 0x29: data_block = "ContainerID Data Block"; break;
1648 		case 0x32: data_block = "Video Timing Modes Type 10 - Formula-based Timings Data Block"; break;
1649 		// 0x2a .. 0x7d RESERVED for Additional VESA-defined Data Blocks
1650 		case 0x7e: // DisplayID 2.0
1651 		case 0x7f: // DisplayID 1.3
1652 			if ((tag == 0x7e && version >= 0x20) ||
1653 			    (tag == 0x7f && version < 0x20)) {
1654 				oui = (x[offset + 3] << 16) + (x[offset + 4] << 8) + x[offset + 5];
1655 				const char *name = oui_name(oui);
1656 				bool reversed = false;
1657 
1658 				if (!name) {
1659 					name = oui_name(oui, true);
1660 					if (name)
1661 						reversed = true;
1662 				}
1663 				if (name)
1664 					data_block = std::string("Vendor-Specific Data Block (") + name + ")";
1665 				else
1666 					data_block = "Vendor-Specific Data Block, OUI " + ouitohex(oui);
1667 				if (reversed)
1668 					fail((std::string("OUI ") + ouitohex(oui) + " is in the wrong byte order.\n").c_str());
1669 			} else {
1670 				data_block = "Unknown DisplayID Data Block (" + utohex(tag) + ")";
1671 			}
1672 			break;
1673 		// 0x80 RESERVED
1674 		case 0x81: data_block = "CTA-861 DisplayID Data Block (" + utohex(tag) + ")"; break;
1675 		// 0x82 .. 0xff RESERVED
1676 		default:   data_block = "Unknown DisplayID Data Block (" + utohex(tag) + ")"; break;
1677 		}
1678 
1679 		if (version >= 0x20 && (tag < 0x20 || tag == 0x7f))
1680 			fail("Use of DisplayID v1.x tag for DisplayID v%u.%u.\n",
1681 			     version >> 4, version & 0xf);
1682 		if (version < 0x20 && tag >= 0x20 && tag <= 0x7e)
1683 			fail("Use of DisplayID v2.0 tag for DisplayID v%u.%u.\n",
1684 			     version >> 4, version & 0xf);
1685 
1686 		if (length < 3) {
1687 			// report a problem when the remaining bytes are not 0.
1688 			if (tag || x[offset + 1]) {
1689 				fail("Not enough bytes remain (%d) for a DisplayID data block or the DisplayID filler is non-0.\n", length);
1690 			}
1691 			break;
1692 		}
1693 
1694 		unsigned block_rev = x[offset + 1] & 0x07;
1695 		unsigned len = x[offset + 2];
1696 
1697 		if (length < len + 3) {
1698 			fail("The length of this DisplayID data block (%d) exceeds the number of bytes remaining (%d).\n", len + 3, length);
1699 			break;
1700 		}
1701 
1702 		if (!tag && !len) {
1703 			// A Product Identification Data Block with no payload bytes is not valid - assume this is the end.
1704 			if (!memchk(x + offset, length)) {
1705 				fail("Non-0 filler bytes in the DisplayID block.\n");
1706 			}
1707 			break;
1708 		}
1709 
1710 		printf("  %s:\n", data_block.c_str());
1711 
1712 		switch (tag) {
1713 		case 0x00: parse_displayid_product_id(x + offset); break;
1714 		case 0x01: parse_displayid_parameters(x + offset); break;
1715 		case 0x02: parse_displayid_color_characteristics(x + offset); break;
1716 		case 0x03:
1717 			   check_displayid_datablock_revision(x[offset + 1], 0, block_rev & 1);
1718 			   for (i = 0; i < len / 20; i++)
1719 				   parse_displayid_type_1_7_timing(&x[offset + 3 + (i * 20)], false, block_rev);
1720 			   break;
1721 		case 0x04:
1722 			   check_displayid_datablock_revision(x[offset + 1]);
1723 			   for (i = 0; i < len / 11; i++)
1724 				   parse_displayid_type_2_timing(&x[offset + 3 + (i * 11)]);
1725 			   break;
1726 		case 0x05:
1727 			   check_displayid_datablock_revision(x[offset + 1], 0, block_rev & 1);
1728 			   for (i = 0; i < len / 3; i++)
1729 				   parse_displayid_type_3_timing(&x[offset + 3 + (i * 3)]);
1730 			   break;
1731 		case 0x06:
1732 			   check_displayid_datablock_revision(x[offset + 1], 0xc0, 1);
1733 			   for (i = 0; i < len; i++)
1734 				   parse_displayid_type_4_8_timing((x[offset + 1] & 0xc0) >> 6, x[offset + 3 + i]);
1735 			   break;
1736 		case 0x07:
1737 			   check_displayid_datablock_revision(x[offset + 1]);
1738 			   for (i = 0; i < min(len, 10) * 8; i++)
1739 				   if (x[offset + 3 + i / 8] & (1 << (i % 8))) {
1740 					   char type[16];
1741 					   sprintf(type, "DMT 0x%02x", i + 1);
1742 					   print_timings("    ", find_dmt_id(i + 1), type);
1743 				   }
1744 			   break;
1745 		case 0x08:
1746 			   check_displayid_datablock_revision(x[offset + 1]);
1747 			   for (i = 0; i < min(len, 8) * 8; i++)
1748 				   if (x[offset + 3 + i / 8] & (1 << (i % 8))) {
1749 					   char type[16];
1750 					   sprintf(type, "VIC %3u", i + 1);
1751 					   print_timings("    ", find_vic_id(i + 1), type);
1752 				   }
1753 			   break;
1754 		case 0x09: parse_displayid_video_timing_range_limits(x + offset); break;
1755 		case 0x0a:
1756 		case 0x0b: parse_displayid_string(x + offset); break;
1757 		case 0x0c: parse_displayid_display_device(x + offset); break;
1758 		case 0x0d: parse_displayid_intf_power_sequencing(x + offset); break;
1759 		case 0x0e: parse_displayid_transfer_characteristics(x + offset); break;
1760 		case 0x0f: parse_displayid_display_intf(x + offset); break;
1761 		case 0x10: parse_displayid_stereo_display_intf(x + offset); break;
1762 		case 0x11:
1763 			   check_displayid_datablock_revision(x[offset + 1]);
1764 			   for (i = 0; i < len / 7; i++)
1765 				   parse_displayid_type_5_timing(&x[offset + 3 + (i * 7)]);
1766 			   break;
1767 		case 0x12: parse_displayid_tiled_display_topology(x + offset, false); break;
1768 		case 0x13:
1769 			   check_displayid_datablock_revision(x[offset + 1]);
1770 			   for (i = 0; i < len; i += (x[offset + 3 + i + 2] & 0x40) ? 17 : 14)
1771 				   parse_displayid_type_6_timing(&x[offset + 3 + i]);
1772 			   break;
1773 		case 0x20: parse_displayid_product_id(x + offset); break;
1774 		case 0x21:
1775 			   if (block_rev >= 1)
1776 				   check_displayid_datablock_revision(x[offset + 1], 0x80, 1);
1777 			   else
1778 				   check_displayid_datablock_revision(x[offset + 1], 0x80, 0);
1779 			   parse_displayid_parameters_v2(x + offset, block_rev);
1780 			   break;
1781 		case 0x22: {
1782 			   unsigned sz = 20;
1783 
1784 			   if (block_rev >= 2)
1785 				   check_displayid_datablock_revision(x[offset + 1], 0x08, 2);
1786 			   else if (block_rev == 1)
1787 				   check_displayid_datablock_revision(x[offset + 1], 0x08, 1);
1788 			   else
1789 				   check_displayid_datablock_revision(x[offset + 1]);
1790 			   sz += (x[offset + 1] & 0x70) >> 4;
1791 			   if (block_rev >= 1 && (x[offset + 1] & 0x08))
1792 				   printf("    These timings support DSC pass-through\n");
1793 			   for (i = 0; i < len / sz; i++)
1794 				   parse_displayid_type_1_7_timing(&x[offset + 3 + i * sz], true, block_rev);
1795 			   break;
1796 		}
1797 		case 0x23:
1798 			   if (block_rev)
1799 				   check_displayid_datablock_revision(x[offset + 1], 0xe8, 1);
1800 			   else
1801 				   check_displayid_datablock_revision(x[offset + 1], 0xc8);
1802 			   if (x[offset + 1] & 0x08) {
1803 				   for (i = 0; i < len / 2; i++)
1804 					   parse_displayid_type_4_8_timing((x[offset + 1] & 0xc0) >> 6,
1805 									   x[offset + 3 + i * 2] |
1806 									   (x[offset + 4 + i * 2] << 8));
1807 			   } else {
1808 				   for (i = 0; i < len; i++)
1809 					   parse_displayid_type_4_8_timing((x[offset + 1] & 0xc0) >> 6,
1810 									   x[offset + 3 + i]);
1811 			   }
1812 			   break;
1813 		case 0x24:
1814 			   check_displayid_datablock_revision(x[offset + 1]);
1815 			   for (i = 0; i < len / 6; i++)
1816 				   parse_displayid_type_9_timing(&x[offset + 3 + i * 6]);
1817 			   break;
1818 		case 0x25: parse_displayid_dynamic_video_timings_range_limits(x + offset); break;
1819 		case 0x26: parse_displayid_interface_features(x + offset); break;
1820 		case 0x27: parse_displayid_stereo_display_intf(x + offset); break;
1821 		case 0x28: parse_displayid_tiled_display_topology(x + offset, true); break;
1822 		case 0x29: parse_displayid_ContainerID(x + offset); break;
1823 		case 0x32: {
1824 			   unsigned sz = 6 + ((x[offset + 1] & 0x70) >> 4);
1825 
1826 			   check_displayid_datablock_revision(x[offset + 1], 0x10);
1827 			   for (i = 0; i < len / sz; i++)
1828 				   parse_displayid_type_10_timing(&x[offset + 3 + i * sz]);
1829 			   break;
1830 		}
1831 		case 0x81: parse_displayid_cta_data_block(x + offset); break;
1832 		case 0x7e:
1833 			if (oui == 0x3a0292) {
1834 				parse_displayid_vesa(x + offset);
1835 				break;
1836 			}
1837 			// fall-through
1838 		default: hex_block("    ", x + offset + 3, len); break;
1839 		}
1840 
1841 		if ((tag == 0x00 || tag == 0x20) &&
1842 		    (!dispid.is_base_block || !first_data_block))
1843 			fail("%s is required to be the first DisplayID Data Block.\n",
1844 			     data_block.c_str());
1845 		length -= len + 3;
1846 		offset += len + 3;
1847 		first_data_block = false;
1848 	}
1849 
1850 	/*
1851 	 * DisplayID length field is number of following bytes
1852 	 * but checksum is calculated over the entire structure
1853 	 * (excluding DisplayID-in-EDID magic byte)
1854 	 */
1855 	data_block.clear();
1856 	do_checksum("  ", x + 1, x[2] + 5);
1857 
1858 	if (!memchk(x + 1 + x[2] + 5, 0x7f - (1 + x[2] + 5))) {
1859 		data_block = "Padding";
1860 		fail("DisplayID padding contains non-zero bytes.\n");
1861 	}
1862 	dispid.is_base_block = false;
1863 }
1864 
check_displayid_blocks()1865 void edid_state::check_displayid_blocks()
1866 {
1867 	data_block = "DisplayID";
1868 	if (!dispid.has_product_identification)
1869 		fail("Missing DisplayID Product Identification Data Block.\n");
1870 	if (dispid.is_display && !dispid.has_display_parameters)
1871 		fail("Missing DisplayID Display Parameters Data Block.\n");
1872 	if (dispid.is_display && !dispid.has_display_interface_features)
1873 		fail("Missing DisplayID Display Interface Features Data Block.\n");
1874 	if (dispid.is_display && !dispid.has_type_1_7)
1875 		fail("Missing DisplayID Type %s Detailed Timing Data Block.\n",
1876 		     dispid.version >= 0x20 ? "VII" : "I");
1877 	if (dispid.preferred_timings.empty())
1878 		fail("DisplayID expects at least one preferred timing.\n");
1879 }
1880