xref: /aosp_15_r20/external/edid-decode/parse-base-block.cpp (revision 193032a37cc83cffc1526215991f3c21671f4245)
1*193032a3SAndroid Build Coastguard Worker // SPDX-License-Identifier: MIT
2*193032a3SAndroid Build Coastguard Worker /*
3*193032a3SAndroid Build Coastguard Worker  * Copyright 2006-2012 Red Hat, Inc.
4*193032a3SAndroid Build Coastguard Worker  * Copyright 2018-2020 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
5*193032a3SAndroid Build Coastguard Worker  *
6*193032a3SAndroid Build Coastguard Worker  * Author: Adam Jackson <[email protected]>
7*193032a3SAndroid Build Coastguard Worker  * Maintainer: Hans Verkuil <[email protected]>
8*193032a3SAndroid Build Coastguard Worker  */
9*193032a3SAndroid Build Coastguard Worker 
10*193032a3SAndroid Build Coastguard Worker #include <stdio.h>
11*193032a3SAndroid Build Coastguard Worker #include <stdlib.h>
12*193032a3SAndroid Build Coastguard Worker #include <math.h>
13*193032a3SAndroid Build Coastguard Worker #include <time.h>
14*193032a3SAndroid Build Coastguard Worker 
15*193032a3SAndroid Build Coastguard Worker #include "edid-decode.h"
16*193032a3SAndroid Build Coastguard Worker 
manufacturer_name(const unsigned char * x)17*193032a3SAndroid Build Coastguard Worker static char *manufacturer_name(const unsigned char *x)
18*193032a3SAndroid Build Coastguard Worker {
19*193032a3SAndroid Build Coastguard Worker 	static char name[4];
20*193032a3SAndroid Build Coastguard Worker 
21*193032a3SAndroid Build Coastguard Worker 	name[0] = ((x[0] & 0x7c) >> 2) + '@';
22*193032a3SAndroid Build Coastguard Worker 	name[1] = ((x[0] & 0x03) << 3) + ((x[1] & 0xe0) >> 5) + '@';
23*193032a3SAndroid Build Coastguard Worker 	name[2] = (x[1] & 0x1f) + '@';
24*193032a3SAndroid Build Coastguard Worker 	name[3] = 0;
25*193032a3SAndroid Build Coastguard Worker 
26*193032a3SAndroid Build Coastguard Worker 	if (!isupper(name[0]) || !isupper(name[1]) || !isupper(name[2]))
27*193032a3SAndroid Build Coastguard Worker 		fail("Manufacturer name field contains garbage.\n");
28*193032a3SAndroid Build Coastguard Worker 
29*193032a3SAndroid Build Coastguard Worker 	return name;
30*193032a3SAndroid Build Coastguard Worker }
31*193032a3SAndroid Build Coastguard Worker 
32*193032a3SAndroid Build Coastguard Worker static const struct {
33*193032a3SAndroid Build Coastguard Worker 	unsigned dmt_id;
34*193032a3SAndroid Build Coastguard Worker 	unsigned std_id;
35*193032a3SAndroid Build Coastguard Worker 	unsigned cvt_id;
36*193032a3SAndroid Build Coastguard Worker 	struct timings t;
37*193032a3SAndroid Build Coastguard Worker } dmt_timings[] = {
38*193032a3SAndroid Build Coastguard Worker 	{ 0x01, 0x0000, 0x000000, { 640, 350, 64, 35, 31500, 0, false,
39*193032a3SAndroid Build Coastguard Worker 				    32, 64, 96, true, 32, 3, 60, false } },
40*193032a3SAndroid Build Coastguard Worker 
41*193032a3SAndroid Build Coastguard Worker 	{ 0x02, 0x3119, 0x000000, { 640, 400, 16, 10, 31500, 0, false,
42*193032a3SAndroid Build Coastguard Worker 				    32, 64, 96, false, 1, 3, 41, true } },
43*193032a3SAndroid Build Coastguard Worker 
44*193032a3SAndroid Build Coastguard Worker 	{ 0x03, 0x0000, 0x000000, { 720, 400, 9, 5, 35500, 0, false,
45*193032a3SAndroid Build Coastguard Worker 				    36, 72, 108, false, 1, 3, 42, true } },
46*193032a3SAndroid Build Coastguard Worker 
47*193032a3SAndroid Build Coastguard Worker 	{ 0x04, 0x3140, 0x000000, { 640, 480, 4, 3, 25175, 0, false,
48*193032a3SAndroid Build Coastguard Worker 				    8, 96, 40, false, 2, 2, 25, false, 8, 8 } },
49*193032a3SAndroid Build Coastguard Worker 	{ 0x05, 0x314c, 0x000000, { 640, 480, 4, 3, 31500, 0, false,
50*193032a3SAndroid Build Coastguard Worker 				    16, 40, 120, false, 1, 3, 20, false, 8, 8 } },
51*193032a3SAndroid Build Coastguard Worker 	{ 0x06, 0x314f, 0x000000, { 640, 480, 4, 3, 31500, 0, false,
52*193032a3SAndroid Build Coastguard Worker 				    16, 64, 120, false, 1, 3, 16, false } },
53*193032a3SAndroid Build Coastguard Worker 	{ 0x07, 0x3159, 0x000000, { 640, 480, 4, 3, 36000, 0, false,
54*193032a3SAndroid Build Coastguard Worker 				    56, 56, 80, false, 1, 3, 25, false } },
55*193032a3SAndroid Build Coastguard Worker 
56*193032a3SAndroid Build Coastguard Worker 	{ 0x08, 0x0000, 0x000000, { 800, 600, 4, 3, 36000, 0, false,
57*193032a3SAndroid Build Coastguard Worker 				    24, 72, 128, true, 1, 2, 22, true } },
58*193032a3SAndroid Build Coastguard Worker 	{ 0x09, 0x4540, 0x000000, { 800, 600, 4, 3, 40000, 0, false,
59*193032a3SAndroid Build Coastguard Worker 				    40, 128, 88, true, 1, 4, 23, true } },
60*193032a3SAndroid Build Coastguard Worker 	{ 0x0a, 0x454c, 0x000000, { 800, 600, 4, 3, 50000, 0, false,
61*193032a3SAndroid Build Coastguard Worker 				    56, 120, 64, true, 37, 6, 23, true } },
62*193032a3SAndroid Build Coastguard Worker 	{ 0x0b, 0x454f, 0x000000, { 800, 600, 4, 3, 49500, 0, false,
63*193032a3SAndroid Build Coastguard Worker 				    16, 80, 160, true, 1, 3, 21, true } },
64*193032a3SAndroid Build Coastguard Worker 	{ 0x0c, 0x4559, 0x000000, { 800, 600, 4, 3, 56250, 0, false,
65*193032a3SAndroid Build Coastguard Worker 				    32, 64, 152, true, 1, 3, 27, true } },
66*193032a3SAndroid Build Coastguard Worker 	{ 0x0d, 0x0000, 0x000000, { 800, 600, 4, 3, 73250, 1, false,
67*193032a3SAndroid Build Coastguard Worker 				    48, 32, 80, true, 3, 4, 29, false } },
68*193032a3SAndroid Build Coastguard Worker 
69*193032a3SAndroid Build Coastguard Worker 	{ 0x0e, 0x0000, 0x000000, { 848, 480, 16, 9, 33750, 0, false,
70*193032a3SAndroid Build Coastguard Worker 				    16, 112, 112, true, 6, 8, 23, true } },
71*193032a3SAndroid Build Coastguard Worker 
72*193032a3SAndroid Build Coastguard Worker 	{ 0x0f, 0x0000, 0x000000, { 1024, 768, 4, 3, 44900, 0, true,
73*193032a3SAndroid Build Coastguard Worker 				    8, 176, 56, true, 0, 4, 20, true } },
74*193032a3SAndroid Build Coastguard Worker 	{ 0x10, 0x6140, 0x000000, { 1024, 768, 4, 3, 65000, 0, false,
75*193032a3SAndroid Build Coastguard Worker 				    24, 136, 160, false, 3, 6, 29, false } },
76*193032a3SAndroid Build Coastguard Worker 	{ 0x11, 0x614c, 0x000000, { 1024, 768, 4, 3, 75000, 0, false,
77*193032a3SAndroid Build Coastguard Worker 				    24, 136, 144, false, 3, 6, 29, false } },
78*193032a3SAndroid Build Coastguard Worker 	{ 0x12, 0x614f, 0x000000, { 1024, 768, 4, 3, 78750, 0, false,
79*193032a3SAndroid Build Coastguard Worker 				    16, 96, 176, true, 1, 3, 28, true } },
80*193032a3SAndroid Build Coastguard Worker 	{ 0x13, 0x6159, 0x000000, { 1024, 768, 4, 3, 94500, 0, false,
81*193032a3SAndroid Build Coastguard Worker 				    48, 96, 208, true, 1, 3, 36, true } },
82*193032a3SAndroid Build Coastguard Worker 	{ 0x14, 0x0000, 0x000000, { 1024, 768, 4, 3, 115500, 1, false,
83*193032a3SAndroid Build Coastguard Worker 				    48, 32, 80, true, 3, 4, 38, false } },
84*193032a3SAndroid Build Coastguard Worker 
85*193032a3SAndroid Build Coastguard Worker 	{ 0x15, 0x714f, 0x000000, { 1152, 864, 4, 3, 108000, 0, false,
86*193032a3SAndroid Build Coastguard Worker 				    64, 128, 256, true, 1, 3, 32, true } },
87*193032a3SAndroid Build Coastguard Worker 
88*193032a3SAndroid Build Coastguard Worker 	{ 0x55, 0x81c0, 0x000000, { 1280, 720, 16, 9, 74250, 0, false,
89*193032a3SAndroid Build Coastguard Worker 				    110, 40, 220, true, 5, 5, 20, true } },
90*193032a3SAndroid Build Coastguard Worker 
91*193032a3SAndroid Build Coastguard Worker 	{ 0x16, 0x0000, 0x7f1c21, { 1280, 768, 5, 3, 68250, 1, false,
92*193032a3SAndroid Build Coastguard Worker 				    48, 32, 80, true, 3, 7, 12, false } },
93*193032a3SAndroid Build Coastguard Worker 	{ 0x17, 0x0000, 0x7f1c28, { 1280, 768, 5, 3, 79500, 0, false,
94*193032a3SAndroid Build Coastguard Worker 				    64, 128, 192, false, 3, 7, 20, true } },
95*193032a3SAndroid Build Coastguard Worker 	{ 0x18, 0x0000, 0x7f1c44, { 1280, 768, 5, 3, 102250, 0, false,
96*193032a3SAndroid Build Coastguard Worker 				    80, 128, 208, false, 3, 7, 27, true } },
97*193032a3SAndroid Build Coastguard Worker 	{ 0x19, 0x0000, 0x7f1c62, { 1280, 768, 5, 3, 117500, 0, false,
98*193032a3SAndroid Build Coastguard Worker 				    80, 136, 216, false, 3, 7, 31, true } },
99*193032a3SAndroid Build Coastguard Worker 	{ 0x1a, 0x0000, 0x000000, { 1280, 768, 5, 3, 140250, 0, false,
100*193032a3SAndroid Build Coastguard Worker 				    48, 32, 80, true, 3, 7, 35, false } },
101*193032a3SAndroid Build Coastguard Worker 
102*193032a3SAndroid Build Coastguard Worker 	{ 0x1b, 0x0000, 0x8f1821, { 1280, 800, 16, 10, 71000, 1, false,
103*193032a3SAndroid Build Coastguard Worker 				    48, 32, 80, true, 3, 6, 14, false } },
104*193032a3SAndroid Build Coastguard Worker 	{ 0x1c, 0x8100, 0x8f1828, { 1280, 800, 16, 10, 83500, 0, false,
105*193032a3SAndroid Build Coastguard Worker 				    72, 128, 200, false, 3, 6, 22, true } },
106*193032a3SAndroid Build Coastguard Worker 	{ 0x1d, 0x810f, 0x8f1844, { 1280, 800, 16, 10, 106500, 0, false,
107*193032a3SAndroid Build Coastguard Worker 				    80, 128, 208, false, 3, 6, 29, true } },
108*193032a3SAndroid Build Coastguard Worker 	{ 0x1e, 0x8119, 0x8f1862, { 1280, 800, 16, 10, 122500, 0, false,
109*193032a3SAndroid Build Coastguard Worker 				    80, 136, 216, false, 3, 6, 34, true } },
110*193032a3SAndroid Build Coastguard Worker 	{ 0x1f, 0x0000, 0x000000, { 1280, 800, 16, 10, 146250, 1, false,
111*193032a3SAndroid Build Coastguard Worker 				    48, 32, 80, true, 3, 6, 38, false } },
112*193032a3SAndroid Build Coastguard Worker 
113*193032a3SAndroid Build Coastguard Worker 	{ 0x20, 0x8140, 0x000000, { 1280, 960, 4, 3, 108000, 0, false,
114*193032a3SAndroid Build Coastguard Worker 				    96, 112, 312, true, 1, 3, 36, true } },
115*193032a3SAndroid Build Coastguard Worker 	{ 0x21, 0x8159, 0x000000, { 1280, 960, 4, 3, 148500, 0, false,
116*193032a3SAndroid Build Coastguard Worker 				    64, 160, 224, true, 1, 3, 47, true } },
117*193032a3SAndroid Build Coastguard Worker 	{ 0x22, 0x0000, 0x000000, { 1280, 960, 4, 3, 175500, 1, false,
118*193032a3SAndroid Build Coastguard Worker 				    48, 32, 80, true, 3, 4, 50, false } },
119*193032a3SAndroid Build Coastguard Worker 
120*193032a3SAndroid Build Coastguard Worker 	{ 0x23, 0x8180, 0x000000, { 1280, 1024, 5, 4, 108000, 0, false,
121*193032a3SAndroid Build Coastguard Worker 				    48, 112, 248, true, 1, 3, 38, true } },
122*193032a3SAndroid Build Coastguard Worker 	{ 0x24, 0x818f, 0x000000, { 1280, 1024, 5, 4, 135000, 0, false,
123*193032a3SAndroid Build Coastguard Worker 				    16, 144, 248, true, 1, 3, 38, true } },
124*193032a3SAndroid Build Coastguard Worker 	{ 0x25, 0x8199, 0x000000, { 1280, 1024, 5, 4, 157500, 0, false,
125*193032a3SAndroid Build Coastguard Worker 				    64, 160, 224, true, 1, 3, 44, true } },
126*193032a3SAndroid Build Coastguard Worker 	{ 0x26, 0x0000, 0x000000, { 1280, 1024, 5, 4, 187250, 1, false,
127*193032a3SAndroid Build Coastguard Worker 				    48, 32, 80, true, 3, 7, 50, false } },
128*193032a3SAndroid Build Coastguard Worker 
129*193032a3SAndroid Build Coastguard Worker 	{ 0x27, 0x0000, 0x000000, { 1360, 768, 85, 48, 85500, 0, false,
130*193032a3SAndroid Build Coastguard Worker 				    64, 112, 256, true, 3, 6, 18, true } },
131*193032a3SAndroid Build Coastguard Worker 	{ 0x28, 0x0000, 0x000000, { 1360, 768, 85, 48, 148250, 1, false,
132*193032a3SAndroid Build Coastguard Worker 				    48, 32, 80, true, 3, 5, 37, false } },
133*193032a3SAndroid Build Coastguard Worker 
134*193032a3SAndroid Build Coastguard Worker 	{ 0x51, 0x0000, 0x000000, { 1366, 768, 85, 48, 85500, 0, false,
135*193032a3SAndroid Build Coastguard Worker 				    70, 143, 213, true, 3, 3, 24, true } },
136*193032a3SAndroid Build Coastguard Worker 	{ 0x56, 0x0000, 0x000000, { 1366, 768, 85, 48, 72000, 1, false,
137*193032a3SAndroid Build Coastguard Worker 				    14, 56, 64, true, 1, 3, 28, true } },
138*193032a3SAndroid Build Coastguard Worker 
139*193032a3SAndroid Build Coastguard Worker 	{ 0x29, 0x0000, 0x0c2021, { 1400, 1050, 4, 3, 101000, 1, false,
140*193032a3SAndroid Build Coastguard Worker 				    48, 32, 80, true, 3, 4, 23, false } },
141*193032a3SAndroid Build Coastguard Worker 	{ 0x2a, 0x9040, 0x0c2028, { 1400, 1050, 4, 3, 121750, 0, false,
142*193032a3SAndroid Build Coastguard Worker 				    88, 144, 232, false, 3, 4, 32, true } },
143*193032a3SAndroid Build Coastguard Worker 	{ 0x2b, 0x904f, 0x0c2044, { 1400, 1050, 4, 3, 156000, 0, false,
144*193032a3SAndroid Build Coastguard Worker 				    104, 144, 248, false, 3, 4, 42, true } },
145*193032a3SAndroid Build Coastguard Worker 	{ 0x2c, 0x9059, 0x0c2062, { 1400, 1050, 4, 3, 179500, 0, false,
146*193032a3SAndroid Build Coastguard Worker 				    104, 152, 256, false, 3, 4, 48, true } },
147*193032a3SAndroid Build Coastguard Worker 	{ 0x2d, 0x0000, 0x000000, { 1400, 1050, 4, 3, 208000, 1, false,
148*193032a3SAndroid Build Coastguard Worker 				    48, 32, 80, true, 3, 4, 55, false } },
149*193032a3SAndroid Build Coastguard Worker 
150*193032a3SAndroid Build Coastguard Worker 	{ 0x2e, 0x0000, 0xc11821, { 1440, 900, 16, 10, 88750, 1, false,
151*193032a3SAndroid Build Coastguard Worker 				    48, 32, 80, true, 3, 6, 17, false } },
152*193032a3SAndroid Build Coastguard Worker 	{ 0x2f, 0x9500, 0xc11828, { 1440, 900, 16, 10, 106500, 0, false,
153*193032a3SAndroid Build Coastguard Worker 				    80, 152, 232, false, 3, 6, 25, true } },
154*193032a3SAndroid Build Coastguard Worker 	{ 0x30, 0x950f, 0xc11844, { 1440, 900, 16, 10, 136750, 0, false,
155*193032a3SAndroid Build Coastguard Worker 				    96, 152, 248, false, 3, 6, 33, true } },
156*193032a3SAndroid Build Coastguard Worker 	{ 0x31, 0x9519, 0xc11868, { 1440, 900, 16, 10, 157000, 0, false,
157*193032a3SAndroid Build Coastguard Worker 				    104, 152, 256, false, 3, 6, 39, true } },
158*193032a3SAndroid Build Coastguard Worker 	{ 0x32, 0x0000, 0x000000, { 1440, 900, 16, 10, 182750, 1, false,
159*193032a3SAndroid Build Coastguard Worker 				    48, 32, 80, true, 3, 6, 44, false } },
160*193032a3SAndroid Build Coastguard Worker 
161*193032a3SAndroid Build Coastguard Worker 	{ 0x53, 0xa9c0, 0x000000, { 1600, 900, 16, 9, 108000, 1, false,
162*193032a3SAndroid Build Coastguard Worker 				    24, 80, 96, true, 1, 3, 96, true } },
163*193032a3SAndroid Build Coastguard Worker 
164*193032a3SAndroid Build Coastguard Worker 	{ 0x33, 0xa940, 0x000000, { 1600, 1200, 4, 3, 162000, 0, false,
165*193032a3SAndroid Build Coastguard Worker 				    64, 192, 304, true, 1, 3, 46, true } },
166*193032a3SAndroid Build Coastguard Worker 	{ 0x34, 0xa945, 0x000000, { 1600, 1200, 4, 3, 175500, 0, false,
167*193032a3SAndroid Build Coastguard Worker 				    64, 192, 304, true, 1, 3, 46, true } },
168*193032a3SAndroid Build Coastguard Worker 	{ 0x35, 0xa94a, 0x000000, { 1600, 1200, 4, 3, 189000, 0, false,
169*193032a3SAndroid Build Coastguard Worker 				    64, 192, 304, true, 1, 3, 46, true } },
170*193032a3SAndroid Build Coastguard Worker 	{ 0x36, 0xa94f, 0x000000, { 1600, 1200, 4, 3, 202500, 0, false,
171*193032a3SAndroid Build Coastguard Worker 				    64, 192, 304, true, 1, 3, 46, true } },
172*193032a3SAndroid Build Coastguard Worker 	{ 0x37, 0xa959, 0x000000, { 1600, 1200, 4, 3, 229500, 0, false,
173*193032a3SAndroid Build Coastguard Worker 				    64, 192, 304, true, 1, 3, 46, true } },
174*193032a3SAndroid Build Coastguard Worker 	{ 0x38, 0x0000, 0x000000, { 1600, 1200, 4, 3, 268250, 1, false,
175*193032a3SAndroid Build Coastguard Worker 				    48, 32, 80, true, 3, 4, 64, false } },
176*193032a3SAndroid Build Coastguard Worker 
177*193032a3SAndroid Build Coastguard Worker 	{ 0x39, 0x0000, 0x0c2821, { 1680, 1050, 16, 10, 119000, 1, false,
178*193032a3SAndroid Build Coastguard Worker 				    48, 32, 80, true, 3, 6, 21, false } },
179*193032a3SAndroid Build Coastguard Worker 	{ 0x3a, 0xb300, 0x0c2828, { 1680, 1050, 16, 10, 146250, 0, false,
180*193032a3SAndroid Build Coastguard Worker 				    104, 176, 280, false, 3, 6, 30, true } },
181*193032a3SAndroid Build Coastguard Worker 	{ 0x3b, 0xb30f, 0x0c2844, { 1680, 1050, 16, 10, 187000, 0, false,
182*193032a3SAndroid Build Coastguard Worker 				    120, 176, 296, false, 3, 6, 40, true } },
183*193032a3SAndroid Build Coastguard Worker 	{ 0x3c, 0xb319, 0x0c2868, { 1680, 1050, 16, 10, 214750, 0, false,
184*193032a3SAndroid Build Coastguard Worker 				    128, 176, 304, false, 3, 6, 46, true } },
185*193032a3SAndroid Build Coastguard Worker 	{ 0x3d, 0x0000, 0x000000, { 1680, 1050, 16, 10, 245500, 1, false,
186*193032a3SAndroid Build Coastguard Worker 				    48, 32, 80, true, 3, 6, 53, false } },
187*193032a3SAndroid Build Coastguard Worker 
188*193032a3SAndroid Build Coastguard Worker 	{ 0x3e, 0xc140, 0x000000, { 1792, 1344, 4, 3, 204750, 0, false,
189*193032a3SAndroid Build Coastguard Worker 				    128, 200, 328, false, 1, 3, 46, true } },
190*193032a3SAndroid Build Coastguard Worker 	{ 0x3f, 0xc14f, 0x000000, { 1792, 1344, 4, 3, 261000, 0, false,
191*193032a3SAndroid Build Coastguard Worker 				    96, 216, 352, false, 1, 3, 69, true } },
192*193032a3SAndroid Build Coastguard Worker 	{ 0x40, 0x0000, 0x000000, { 1792, 1344, 4, 3, 333250, 1, false,
193*193032a3SAndroid Build Coastguard Worker 				    48, 32, 80, true, 3, 4, 72, false } },
194*193032a3SAndroid Build Coastguard Worker 
195*193032a3SAndroid Build Coastguard Worker 	{ 0x41, 0xc940, 0x000000, { 1856, 1392, 4, 3, 218250, 0, false,
196*193032a3SAndroid Build Coastguard Worker 				    96, 224, 352, false, 1, 3, 43, true } },
197*193032a3SAndroid Build Coastguard Worker 	{ 0x42, 0xc94f, 0x000000, { 1856, 1392, 4, 3, 288000, 0, false,
198*193032a3SAndroid Build Coastguard Worker 				    128, 224, 352, false, 1, 3, 104, true } },
199*193032a3SAndroid Build Coastguard Worker 	{ 0x43, 0x0000, 0x000000, { 1856, 1392, 4, 3, 356500, 1, false,
200*193032a3SAndroid Build Coastguard Worker 				    48, 32, 80, true, 3, 4, 74, false } },
201*193032a3SAndroid Build Coastguard Worker 
202*193032a3SAndroid Build Coastguard Worker 	{ 0x52, 0xd1c0, 0x000000, { 1920, 1080, 16, 9, 148500, 0, false,
203*193032a3SAndroid Build Coastguard Worker 				    88, 44, 148, true, 4, 5, 36, true } },
204*193032a3SAndroid Build Coastguard Worker 
205*193032a3SAndroid Build Coastguard Worker 	{ 0x44, 0x0000, 0x572821, { 1920, 1200, 16, 10, 154000, 1, false,
206*193032a3SAndroid Build Coastguard Worker 				    48, 32, 80, true, 3, 6, 26, false } },
207*193032a3SAndroid Build Coastguard Worker 	{ 0x45, 0xd100, 0x572828, { 1920, 1200, 16, 10, 193250, 0, false,
208*193032a3SAndroid Build Coastguard Worker 				    136, 200, 336, false, 3, 6, 36, true } },
209*193032a3SAndroid Build Coastguard Worker 	{ 0x46, 0xd10f, 0x572844, { 1920, 1200, 16, 10, 245250, 0, false,
210*193032a3SAndroid Build Coastguard Worker 				    136, 208, 344, false, 3, 6, 46, true } },
211*193032a3SAndroid Build Coastguard Worker 	{ 0x47, 0xd119, 0x572862, { 1920, 1200, 16, 10, 281250, 0, false,
212*193032a3SAndroid Build Coastguard Worker 				    144, 208, 352, false, 3, 6, 53, true } },
213*193032a3SAndroid Build Coastguard Worker 	{ 0x48, 0x0000, 0x000000, { 1920, 1200, 16, 10, 317000, 1, false,
214*193032a3SAndroid Build Coastguard Worker 				    48, 32, 80, true, 3, 6, 62, false } },
215*193032a3SAndroid Build Coastguard Worker 
216*193032a3SAndroid Build Coastguard Worker 	{ 0x49, 0xd140, 0x000000, { 1920, 1440, 4, 3, 234000, 0, false,
217*193032a3SAndroid Build Coastguard Worker 				    128, 208, 344, false, 1, 3, 56, true } },
218*193032a3SAndroid Build Coastguard Worker 	{ 0x4a, 0xd14f, 0x000000, { 1920, 1440, 4, 3, 297000, 0, false,
219*193032a3SAndroid Build Coastguard Worker 				    144, 224, 352, false, 1, 3, 56, true } },
220*193032a3SAndroid Build Coastguard Worker 	{ 0x4b, 0x0000, 0x000000, { 1920, 1440, 4, 3, 380500, 1, false,
221*193032a3SAndroid Build Coastguard Worker 				    48, 32, 80, true, 2, 3, 78, false } },
222*193032a3SAndroid Build Coastguard Worker 
223*193032a3SAndroid Build Coastguard Worker 	{ 0x54, 0xe1c0, 0x000000, { 2048, 1152, 16, 9, 162000, 1, false,
224*193032a3SAndroid Build Coastguard Worker 				    26, 80, 96, true, 1, 3, 44, true } },
225*193032a3SAndroid Build Coastguard Worker 
226*193032a3SAndroid Build Coastguard Worker 	{ 0x4c, 0x0000, 0x1f3821, { 2560, 1600, 16, 10, 268500, 1, false,
227*193032a3SAndroid Build Coastguard Worker 				    48, 32, 80, true, 3, 6, 37, false } },
228*193032a3SAndroid Build Coastguard Worker 	{ 0x4d, 0x0000, 0x1f3828, { 2560, 1600, 16, 10, 348500, 0, false,
229*193032a3SAndroid Build Coastguard Worker 				    192, 280, 472, false, 3, 6, 49, true } },
230*193032a3SAndroid Build Coastguard Worker 	{ 0x4e, 0x0000, 0x1f3844, { 2560, 1600, 16, 10, 443250, 0, false,
231*193032a3SAndroid Build Coastguard Worker 				    208, 280, 488, false, 3, 6, 63, true } },
232*193032a3SAndroid Build Coastguard Worker 	{ 0x4f, 0x0000, 0x1f3862, { 2560, 1600, 16, 10, 505250, 0, false,
233*193032a3SAndroid Build Coastguard Worker 				    208, 280, 488, false, 3, 6, 73, true } },
234*193032a3SAndroid Build Coastguard Worker 	{ 0x50, 0x0000, 0x000000, { 2560, 1600, 16, 10, 552750, 1, false,
235*193032a3SAndroid Build Coastguard Worker 				    48, 32, 80, true, 3, 6, 85, false } },
236*193032a3SAndroid Build Coastguard Worker 
237*193032a3SAndroid Build Coastguard Worker 	{ 0x57, 0x0000, 0x000000, { 4096, 2160, 256, 135, 556744, 1, false,
238*193032a3SAndroid Build Coastguard Worker 				    8, 32, 40, true, 48, 8, 6, false } },
239*193032a3SAndroid Build Coastguard Worker 	{ 0x58, 0x0000, 0x000000, { 4096, 2160, 256, 135, 556188, 1, false,
240*193032a3SAndroid Build Coastguard Worker 				    8, 32, 40, true, 48, 8, 6, false } },
241*193032a3SAndroid Build Coastguard Worker };
242*193032a3SAndroid Build Coastguard Worker 
243*193032a3SAndroid Build Coastguard Worker // The timings for the IBM/Apple modes are copied from the linux
244*193032a3SAndroid Build Coastguard Worker // kernel timings in drivers/gpu/drm/drm_edid.c, except for the
245*193032a3SAndroid Build Coastguard Worker // 1152x870 Apple format, which is copied from
246*193032a3SAndroid Build Coastguard Worker // drivers/video/fbdev/macmodes.c since the drm_edid.c version
247*193032a3SAndroid Build Coastguard Worker // describes a 1152x864 format.
248*193032a3SAndroid Build Coastguard Worker static const struct {
249*193032a3SAndroid Build Coastguard Worker 	unsigned dmt_id;
250*193032a3SAndroid Build Coastguard Worker 	struct timings t;
251*193032a3SAndroid Build Coastguard Worker 	const char *type;
252*193032a3SAndroid Build Coastguard Worker } established_timings12[] = {
253*193032a3SAndroid Build Coastguard Worker 	/* 0x23 bit 7 - 0 */
254*193032a3SAndroid Build Coastguard Worker 	{ 0x00, { 720, 400, 9, 5, 28320, 0, false,
255*193032a3SAndroid Build Coastguard Worker 	          18, 108, 54, false, 21, 2, 26, true }, "IBM" },
256*193032a3SAndroid Build Coastguard Worker 	{ 0x00, { 720, 400, 9, 5, 35500, 0, false,
257*193032a3SAndroid Build Coastguard Worker 	          18, 108, 54, false, 12, 2, 35, true }, "IBM" },
258*193032a3SAndroid Build Coastguard Worker 	{ 0x04 },
259*193032a3SAndroid Build Coastguard Worker 	{ 0x00, { 640, 480, 4, 3, 30240, 0, false,
260*193032a3SAndroid Build Coastguard Worker 	          64, 64, 96, false, 3, 3, 39, false }, "Apple" },
261*193032a3SAndroid Build Coastguard Worker 	{ 0x05 },
262*193032a3SAndroid Build Coastguard Worker 	{ 0x06 },
263*193032a3SAndroid Build Coastguard Worker 	{ 0x08 },
264*193032a3SAndroid Build Coastguard Worker 	{ 0x09 },
265*193032a3SAndroid Build Coastguard Worker 	/* 0x24 bit 7 - 0 */
266*193032a3SAndroid Build Coastguard Worker 	{ 0x0a },
267*193032a3SAndroid Build Coastguard Worker 	{ 0x0b },
268*193032a3SAndroid Build Coastguard Worker 	{ 0x00, { 832, 624, 4, 3, 57284, 0, false,
269*193032a3SAndroid Build Coastguard Worker 	          32, 64, 224, false, 1, 3, 39, false }, "Apple" },
270*193032a3SAndroid Build Coastguard Worker 	{ 0x0f },
271*193032a3SAndroid Build Coastguard Worker 	{ 0x10 },
272*193032a3SAndroid Build Coastguard Worker 	{ 0x11 },
273*193032a3SAndroid Build Coastguard Worker 	{ 0x12 },
274*193032a3SAndroid Build Coastguard Worker 	{ 0x24 },
275*193032a3SAndroid Build Coastguard Worker 	/* 0x25 bit 7 */
276*193032a3SAndroid Build Coastguard Worker 	{ 0x00, { 1152, 870, 192, 145, 100000, 0, false,
277*193032a3SAndroid Build Coastguard Worker 	          48, 128, 128, true, 3, 3, 39, true }, "Apple" },
278*193032a3SAndroid Build Coastguard Worker };
279*193032a3SAndroid Build Coastguard Worker 
280*193032a3SAndroid Build Coastguard Worker // The bits in the Established Timings III map to DMT timings,
281*193032a3SAndroid Build Coastguard Worker // this array has the DMT IDs.
282*193032a3SAndroid Build Coastguard Worker static const unsigned char established_timings3_dmt_ids[] = {
283*193032a3SAndroid Build Coastguard Worker 	/* 0x06 bit 7 - 0 */
284*193032a3SAndroid Build Coastguard Worker 	0x01, // 640x350@85
285*193032a3SAndroid Build Coastguard Worker 	0x02, // 640x400@85
286*193032a3SAndroid Build Coastguard Worker 	0x03, // 720x400@85
287*193032a3SAndroid Build Coastguard Worker 	0x07, // 640x480@85
288*193032a3SAndroid Build Coastguard Worker 	0x0e, // 848x480@60
289*193032a3SAndroid Build Coastguard Worker 	0x0c, // 800x600@85
290*193032a3SAndroid Build Coastguard Worker 	0x13, // 1024x768@85
291*193032a3SAndroid Build Coastguard Worker 	0x15, // 1152x864@75
292*193032a3SAndroid Build Coastguard Worker 	/* 0x07 bit 7 - 0 */
293*193032a3SAndroid Build Coastguard Worker 	0x16, // 1280x768@60 RB
294*193032a3SAndroid Build Coastguard Worker 	0x17, // 1280x768@60
295*193032a3SAndroid Build Coastguard Worker 	0x18, // 1280x768@75
296*193032a3SAndroid Build Coastguard Worker 	0x19, // 1280x768@85
297*193032a3SAndroid Build Coastguard Worker 	0x20, // 1280x960@60
298*193032a3SAndroid Build Coastguard Worker 	0x21, // 1280x960@85
299*193032a3SAndroid Build Coastguard Worker 	0x23, // 1280x1024@60
300*193032a3SAndroid Build Coastguard Worker 	0x25, // 1280x1024@85
301*193032a3SAndroid Build Coastguard Worker 	/* 0x08 bit 7 - 0 */
302*193032a3SAndroid Build Coastguard Worker 	0x27, // 1360x768@60
303*193032a3SAndroid Build Coastguard Worker 	0x2e, // 1440x900@60 RB
304*193032a3SAndroid Build Coastguard Worker 	0x2f, // 1440x900@60
305*193032a3SAndroid Build Coastguard Worker 	0x30, // 1440x900@75
306*193032a3SAndroid Build Coastguard Worker 	0x31, // 1440x900@85
307*193032a3SAndroid Build Coastguard Worker 	0x29, // 1400x1050@60 RB
308*193032a3SAndroid Build Coastguard Worker 	0x2a, // 1400x1050@60
309*193032a3SAndroid Build Coastguard Worker 	0x2b, // 1400x1050@75
310*193032a3SAndroid Build Coastguard Worker 	/* 0x09 bit 7 - 0 */
311*193032a3SAndroid Build Coastguard Worker 	0x2c, // 1400x1050@85
312*193032a3SAndroid Build Coastguard Worker 	0x39, // 1680x1050@60 RB
313*193032a3SAndroid Build Coastguard Worker 	0x3a, // 1680x1050@60
314*193032a3SAndroid Build Coastguard Worker 	0x3b, // 1680x1050@75
315*193032a3SAndroid Build Coastguard Worker 	0x3c, // 1680x1050@85
316*193032a3SAndroid Build Coastguard Worker 	0x33, // 1600x1200@60
317*193032a3SAndroid Build Coastguard Worker 	0x34, // 1600x1200@65
318*193032a3SAndroid Build Coastguard Worker 	0x35, // 1600x1200@70
319*193032a3SAndroid Build Coastguard Worker 	/* 0x0a bit 7 - 0 */
320*193032a3SAndroid Build Coastguard Worker 	0x36, // 1600x1200@75
321*193032a3SAndroid Build Coastguard Worker 	0x37, // 1600x1200@85
322*193032a3SAndroid Build Coastguard Worker 	0x3e, // 1792x1344@60
323*193032a3SAndroid Build Coastguard Worker 	0x3f, // 1792x1344@75
324*193032a3SAndroid Build Coastguard Worker 	0x41, // 1856x1392@60
325*193032a3SAndroid Build Coastguard Worker 	0x42, // 1856x1392@75
326*193032a3SAndroid Build Coastguard Worker 	0x44, // 1920x1200@60 RB
327*193032a3SAndroid Build Coastguard Worker 	0x45, // 1920x1200@60
328*193032a3SAndroid Build Coastguard Worker 	/* 0x0b bit 7 - 4 */
329*193032a3SAndroid Build Coastguard Worker 	0x46, // 1920x1200@75
330*193032a3SAndroid Build Coastguard Worker 	0x47, // 1920x1200@85
331*193032a3SAndroid Build Coastguard Worker 	0x49, // 1920x1440@60
332*193032a3SAndroid Build Coastguard Worker 	0x4a, // 1920x1440@75
333*193032a3SAndroid Build Coastguard Worker };
334*193032a3SAndroid Build Coastguard Worker 
find_dmt_id(unsigned char dmt_id)335*193032a3SAndroid Build Coastguard Worker const struct timings *find_dmt_id(unsigned char dmt_id)
336*193032a3SAndroid Build Coastguard Worker {
337*193032a3SAndroid Build Coastguard Worker 	unsigned i;
338*193032a3SAndroid Build Coastguard Worker 
339*193032a3SAndroid Build Coastguard Worker 	for (i = 0; i < ARRAY_SIZE(dmt_timings); i++)
340*193032a3SAndroid Build Coastguard Worker 		if (dmt_timings[i].dmt_id == dmt_id)
341*193032a3SAndroid Build Coastguard Worker 			return &dmt_timings[i].t;
342*193032a3SAndroid Build Coastguard Worker 	return NULL;
343*193032a3SAndroid Build Coastguard Worker }
344*193032a3SAndroid Build Coastguard Worker 
find_std_id(unsigned short std_id,unsigned char & dmt_id)345*193032a3SAndroid Build Coastguard Worker static const struct timings *find_std_id(unsigned short std_id, unsigned char &dmt_id)
346*193032a3SAndroid Build Coastguard Worker {
347*193032a3SAndroid Build Coastguard Worker 	unsigned i;
348*193032a3SAndroid Build Coastguard Worker 
349*193032a3SAndroid Build Coastguard Worker 	for (i = 0; i < ARRAY_SIZE(dmt_timings); i++)
350*193032a3SAndroid Build Coastguard Worker 		if (dmt_timings[i].std_id == std_id) {
351*193032a3SAndroid Build Coastguard Worker 			dmt_id = dmt_timings[i].dmt_id;
352*193032a3SAndroid Build Coastguard Worker 			return &dmt_timings[i].t;
353*193032a3SAndroid Build Coastguard Worker 		}
354*193032a3SAndroid Build Coastguard Worker 	return NULL;
355*193032a3SAndroid Build Coastguard Worker }
356*193032a3SAndroid Build Coastguard Worker 
list_established_timings()357*193032a3SAndroid Build Coastguard Worker void edid_state::list_established_timings()
358*193032a3SAndroid Build Coastguard Worker {
359*193032a3SAndroid Build Coastguard Worker 	printf("Established Timings I & II, 'Byte' is the EDID address:\n\n");
360*193032a3SAndroid Build Coastguard Worker 	for (unsigned i = 0; i < ARRAY_SIZE(established_timings12); i++) {
361*193032a3SAndroid Build Coastguard Worker 		unsigned char dmt_id = established_timings12[i].dmt_id;
362*193032a3SAndroid Build Coastguard Worker 		const struct timings *t;
363*193032a3SAndroid Build Coastguard Worker 		char type[16];
364*193032a3SAndroid Build Coastguard Worker 
365*193032a3SAndroid Build Coastguard Worker 		if (dmt_id) {
366*193032a3SAndroid Build Coastguard Worker 			sprintf(type, "DMT 0x%02x", dmt_id);
367*193032a3SAndroid Build Coastguard Worker 			t = find_dmt_id(dmt_id);
368*193032a3SAndroid Build Coastguard Worker 		} else {
369*193032a3SAndroid Build Coastguard Worker 			t = &established_timings12[i].t;
370*193032a3SAndroid Build Coastguard Worker 			sprintf(type, "%-8s", established_timings12[i].type);
371*193032a3SAndroid Build Coastguard Worker 		}
372*193032a3SAndroid Build Coastguard Worker 		printf("Byte 0x%02x, Bit %u: ", 0x23 + i / 8, 7 - i % 8);
373*193032a3SAndroid Build Coastguard Worker 		print_timings("", t, type, "", false, false);
374*193032a3SAndroid Build Coastguard Worker 	}
375*193032a3SAndroid Build Coastguard Worker 	printf("\nEstablished timings III, 'Byte' is the offset from the start of the descriptor:\n\n");
376*193032a3SAndroid Build Coastguard Worker 	for (unsigned i = 0; i < ARRAY_SIZE(established_timings3_dmt_ids); i++) {
377*193032a3SAndroid Build Coastguard Worker 		unsigned char dmt_id = established_timings3_dmt_ids[i];
378*193032a3SAndroid Build Coastguard Worker 		char type[16];
379*193032a3SAndroid Build Coastguard Worker 
380*193032a3SAndroid Build Coastguard Worker 		sprintf(type, "DMT 0x%02x", dmt_id);
381*193032a3SAndroid Build Coastguard Worker 		printf("Byte 0x%02x, Bit %u: ", 6 + i / 8, 7 - i % 8);
382*193032a3SAndroid Build Coastguard Worker 		print_timings("", find_dmt_id(dmt_id), type, "", false, false);
383*193032a3SAndroid Build Coastguard Worker 	}
384*193032a3SAndroid Build Coastguard Worker }
385*193032a3SAndroid Build Coastguard Worker 
close_match_to_dmt(const timings & t,unsigned & dmt)386*193032a3SAndroid Build Coastguard Worker const struct timings *close_match_to_dmt(const timings &t, unsigned &dmt)
387*193032a3SAndroid Build Coastguard Worker {
388*193032a3SAndroid Build Coastguard Worker 	for (unsigned i = 0; i < ARRAY_SIZE(dmt_timings); i++) {
389*193032a3SAndroid Build Coastguard Worker 		if (timings_close_match(t, dmt_timings[i].t)) {
390*193032a3SAndroid Build Coastguard Worker 			dmt = dmt_timings[i].dmt_id;
391*193032a3SAndroid Build Coastguard Worker 			return &dmt_timings[i].t;
392*193032a3SAndroid Build Coastguard Worker 		}
393*193032a3SAndroid Build Coastguard Worker 	}
394*193032a3SAndroid Build Coastguard Worker 	dmt = 0;
395*193032a3SAndroid Build Coastguard Worker 	return NULL;
396*193032a3SAndroid Build Coastguard Worker }
397*193032a3SAndroid Build Coastguard Worker 
list_dmts()398*193032a3SAndroid Build Coastguard Worker void edid_state::list_dmts()
399*193032a3SAndroid Build Coastguard Worker {
400*193032a3SAndroid Build Coastguard Worker 	char type[16];
401*193032a3SAndroid Build Coastguard Worker 
402*193032a3SAndroid Build Coastguard Worker 	for (unsigned i = 0; i < ARRAY_SIZE(dmt_timings); i++) {
403*193032a3SAndroid Build Coastguard Worker 		sprintf(type, "DMT 0x%02x", dmt_timings[i].dmt_id);
404*193032a3SAndroid Build Coastguard Worker 		std::string flags;
405*193032a3SAndroid Build Coastguard Worker 		if (dmt_timings[i].std_id)
406*193032a3SAndroid Build Coastguard Worker 			flags += std::string("STD: ") +
407*193032a3SAndroid Build Coastguard Worker 				utohex(dmt_timings[i].std_id >> 8) + " " +
408*193032a3SAndroid Build Coastguard Worker 				utohex(dmt_timings[i].std_id & 0xff);
409*193032a3SAndroid Build Coastguard Worker 		if (dmt_timings[i].cvt_id)
410*193032a3SAndroid Build Coastguard Worker 			add_str(flags, std::string("CVT: ") +
411*193032a3SAndroid Build Coastguard Worker 				utohex(dmt_timings[i].cvt_id >> 16) + " " +
412*193032a3SAndroid Build Coastguard Worker 				utohex((dmt_timings[i].cvt_id >> 8) & 0xff) + " " +
413*193032a3SAndroid Build Coastguard Worker 				utohex(dmt_timings[i].cvt_id & 0xff));
414*193032a3SAndroid Build Coastguard Worker 		print_timings("", &dmt_timings[i].t, type, flags.c_str(), false, false);
415*193032a3SAndroid Build Coastguard Worker 	}
416*193032a3SAndroid Build Coastguard Worker }
417*193032a3SAndroid Build Coastguard Worker 
detailed_cvt_descriptor(const char * prefix,const unsigned char * x,bool first)418*193032a3SAndroid Build Coastguard Worker void edid_state::detailed_cvt_descriptor(const char *prefix, const unsigned char *x, bool first)
419*193032a3SAndroid Build Coastguard Worker {
420*193032a3SAndroid Build Coastguard Worker 	static const unsigned char empty[3] = { 0, 0, 0 };
421*193032a3SAndroid Build Coastguard Worker 	struct timings cvt_t = {};
422*193032a3SAndroid Build Coastguard Worker 	unsigned char preferred;
423*193032a3SAndroid Build Coastguard Worker 
424*193032a3SAndroid Build Coastguard Worker 	if (!first && !memcmp(x, empty, 3))
425*193032a3SAndroid Build Coastguard Worker 		return;
426*193032a3SAndroid Build Coastguard Worker 
427*193032a3SAndroid Build Coastguard Worker 	cvt_t.vact = x[0];
428*193032a3SAndroid Build Coastguard Worker 	if (!cvt_t.vact)
429*193032a3SAndroid Build Coastguard Worker 		fail("CVT byte 0 is 0, which is a reserved value.\n");
430*193032a3SAndroid Build Coastguard Worker 	cvt_t.vact |= (x[1] & 0xf0) << 4;
431*193032a3SAndroid Build Coastguard Worker 	cvt_t.vact++;
432*193032a3SAndroid Build Coastguard Worker 	cvt_t.vact *= 2;
433*193032a3SAndroid Build Coastguard Worker 
434*193032a3SAndroid Build Coastguard Worker 	switch (x[1] & 0x0c) {
435*193032a3SAndroid Build Coastguard Worker 	case 0x00:
436*193032a3SAndroid Build Coastguard Worker 	default: /* avoids 'width/ratio may be used uninitialized' warnings */
437*193032a3SAndroid Build Coastguard Worker 		cvt_t.hratio = 4;
438*193032a3SAndroid Build Coastguard Worker 		cvt_t.vratio = 3;
439*193032a3SAndroid Build Coastguard Worker 		break;
440*193032a3SAndroid Build Coastguard Worker 	case 0x04:
441*193032a3SAndroid Build Coastguard Worker 		cvt_t.hratio = 16;
442*193032a3SAndroid Build Coastguard Worker 		cvt_t.vratio = 9;
443*193032a3SAndroid Build Coastguard Worker 		break;
444*193032a3SAndroid Build Coastguard Worker 	case 0x08:
445*193032a3SAndroid Build Coastguard Worker 		cvt_t.hratio = 16;
446*193032a3SAndroid Build Coastguard Worker 		cvt_t.vratio = 10;
447*193032a3SAndroid Build Coastguard Worker 		break;
448*193032a3SAndroid Build Coastguard Worker 	case 0x0c:
449*193032a3SAndroid Build Coastguard Worker 		cvt_t.hratio = 15;
450*193032a3SAndroid Build Coastguard Worker 		cvt_t.vratio = 9;
451*193032a3SAndroid Build Coastguard Worker 		break;
452*193032a3SAndroid Build Coastguard Worker 	}
453*193032a3SAndroid Build Coastguard Worker 	cvt_t.hact = 8 * (((cvt_t.vact * cvt_t.hratio) / cvt_t.vratio) / 8);
454*193032a3SAndroid Build Coastguard Worker 
455*193032a3SAndroid Build Coastguard Worker 	if (x[1] & 0x03)
456*193032a3SAndroid Build Coastguard Worker 		fail("Reserved bits of CVT byte 1 are non-zero.\n");
457*193032a3SAndroid Build Coastguard Worker 	if (x[2] & 0x80)
458*193032a3SAndroid Build Coastguard Worker 		fail("Reserved bit of CVT byte 2 is non-zero.\n");
459*193032a3SAndroid Build Coastguard Worker 	if (!(x[2] & 0x1f))
460*193032a3SAndroid Build Coastguard Worker 		fail("CVT byte 2 does not support any vertical rates.\n");
461*193032a3SAndroid Build Coastguard Worker 	preferred = (x[2] & 0x60) >> 5;
462*193032a3SAndroid Build Coastguard Worker 	if (preferred == 1 && (x[2] & 0x01))
463*193032a3SAndroid Build Coastguard Worker 		preferred = 4;
464*193032a3SAndroid Build Coastguard Worker 	if (!(x[2] & (1 << (4 - preferred))))
465*193032a3SAndroid Build Coastguard Worker 		fail("The preferred CVT Vertical Rate is not supported.\n");
466*193032a3SAndroid Build Coastguard Worker 
467*193032a3SAndroid Build Coastguard Worker 	static const char *s_pref = "preferred vertical rate";
468*193032a3SAndroid Build Coastguard Worker 
469*193032a3SAndroid Build Coastguard Worker 	if (x[2] & 0x10) {
470*193032a3SAndroid Build Coastguard Worker 		edid_cvt_mode(50, cvt_t);
471*193032a3SAndroid Build Coastguard Worker 		print_timings(prefix, &cvt_t, "CVT", preferred == 0 ? s_pref : "");
472*193032a3SAndroid Build Coastguard Worker 	}
473*193032a3SAndroid Build Coastguard Worker 	if (x[2] & 0x08) {
474*193032a3SAndroid Build Coastguard Worker 		edid_cvt_mode(60, cvt_t);
475*193032a3SAndroid Build Coastguard Worker 		print_timings(prefix, &cvt_t, "CVT", preferred == 1 ? s_pref : "");
476*193032a3SAndroid Build Coastguard Worker 	}
477*193032a3SAndroid Build Coastguard Worker 	if (x[2] & 0x04) {
478*193032a3SAndroid Build Coastguard Worker 		edid_cvt_mode(75, cvt_t);
479*193032a3SAndroid Build Coastguard Worker 		print_timings(prefix, &cvt_t, "CVT", preferred == 2 ? s_pref : "");
480*193032a3SAndroid Build Coastguard Worker 	}
481*193032a3SAndroid Build Coastguard Worker 	if (x[2] & 0x02) {
482*193032a3SAndroid Build Coastguard Worker 		edid_cvt_mode(85, cvt_t);
483*193032a3SAndroid Build Coastguard Worker 		print_timings(prefix, &cvt_t, "CVT", preferred == 3 ? s_pref : "");
484*193032a3SAndroid Build Coastguard Worker 	}
485*193032a3SAndroid Build Coastguard Worker 	if (x[2] & 0x01) {
486*193032a3SAndroid Build Coastguard Worker 		cvt_t.rb = RB_CVT_V1;
487*193032a3SAndroid Build Coastguard Worker 		edid_cvt_mode(60, cvt_t);
488*193032a3SAndroid Build Coastguard Worker 		print_timings(prefix, &cvt_t, "CVT", preferred == 4 ? s_pref : "");
489*193032a3SAndroid Build Coastguard Worker 	}
490*193032a3SAndroid Build Coastguard Worker }
491*193032a3SAndroid Build Coastguard Worker 
492*193032a3SAndroid Build Coastguard Worker /* extract a string from a detailed subblock, checking for termination */
extract_string(const unsigned char * x,unsigned len)493*193032a3SAndroid Build Coastguard Worker char *extract_string(const unsigned char *x, unsigned len)
494*193032a3SAndroid Build Coastguard Worker {
495*193032a3SAndroid Build Coastguard Worker 	static char s[EDID_PAGE_SIZE];
496*193032a3SAndroid Build Coastguard Worker 	int seen_newline = 0;
497*193032a3SAndroid Build Coastguard Worker 	unsigned i;
498*193032a3SAndroid Build Coastguard Worker 
499*193032a3SAndroid Build Coastguard Worker 	memset(s, 0, sizeof(s));
500*193032a3SAndroid Build Coastguard Worker 
501*193032a3SAndroid Build Coastguard Worker 	for (i = 0; i < len; i++) {
502*193032a3SAndroid Build Coastguard Worker 		if (isgraph(x[i])) {
503*193032a3SAndroid Build Coastguard Worker 			s[i] = x[i];
504*193032a3SAndroid Build Coastguard Worker 		} else if (!seen_newline) {
505*193032a3SAndroid Build Coastguard Worker 			if (x[i] == 0x0a) {
506*193032a3SAndroid Build Coastguard Worker 				seen_newline = 1;
507*193032a3SAndroid Build Coastguard Worker 				if (!i)
508*193032a3SAndroid Build Coastguard Worker 					fail("Empty string.\n");
509*193032a3SAndroid Build Coastguard Worker 				else if (s[i - 1] == 0x20)
510*193032a3SAndroid Build Coastguard Worker 					fail("One or more trailing spaces.\n");
511*193032a3SAndroid Build Coastguard Worker 			} else if (x[i] == 0x20) {
512*193032a3SAndroid Build Coastguard Worker 				s[i] = x[i];
513*193032a3SAndroid Build Coastguard Worker 			} else {
514*193032a3SAndroid Build Coastguard Worker 				fail("Non-printable character.\n");
515*193032a3SAndroid Build Coastguard Worker 				return s;
516*193032a3SAndroid Build Coastguard Worker 			}
517*193032a3SAndroid Build Coastguard Worker 		} else if (x[i] != 0x20) {
518*193032a3SAndroid Build Coastguard Worker 			fail("Non-space after newline.\n");
519*193032a3SAndroid Build Coastguard Worker 			return s;
520*193032a3SAndroid Build Coastguard Worker 		}
521*193032a3SAndroid Build Coastguard Worker 	}
522*193032a3SAndroid Build Coastguard Worker 	/* Does the string end with a space? */
523*193032a3SAndroid Build Coastguard Worker 	if (!seen_newline && s[len - 1] == 0x20)
524*193032a3SAndroid Build Coastguard Worker 		fail("One or more trailing spaces.\n");
525*193032a3SAndroid Build Coastguard Worker 
526*193032a3SAndroid Build Coastguard Worker 	return s;
527*193032a3SAndroid Build Coastguard Worker }
528*193032a3SAndroid Build Coastguard Worker 
print_standard_timing(const char * prefix,unsigned char b1,unsigned char b2,bool gtf_only,bool show_both)529*193032a3SAndroid Build Coastguard Worker void edid_state::print_standard_timing(const char *prefix, unsigned char b1, unsigned char b2,
530*193032a3SAndroid Build Coastguard Worker 				       bool gtf_only, bool show_both)
531*193032a3SAndroid Build Coastguard Worker {
532*193032a3SAndroid Build Coastguard Worker 	const struct timings *t;
533*193032a3SAndroid Build Coastguard Worker 	struct timings formula = {};
534*193032a3SAndroid Build Coastguard Worker 	unsigned hratio, vratio;
535*193032a3SAndroid Build Coastguard Worker 	unsigned hact, vact, refresh;
536*193032a3SAndroid Build Coastguard Worker 	unsigned char dmt_id = 0;
537*193032a3SAndroid Build Coastguard Worker 
538*193032a3SAndroid Build Coastguard Worker 	if (b1 <= 0x01) {
539*193032a3SAndroid Build Coastguard Worker 		if (b1 != 0x01 || b2 != 0x01)
540*193032a3SAndroid Build Coastguard Worker 			fail("Use 0x0101 as the invalid Standard Timings code, not 0x%02x%02x.\n", b1, b2);
541*193032a3SAndroid Build Coastguard Worker 		return;
542*193032a3SAndroid Build Coastguard Worker 	}
543*193032a3SAndroid Build Coastguard Worker 
544*193032a3SAndroid Build Coastguard Worker 	t = find_std_id((b1 << 8) | b2, dmt_id);
545*193032a3SAndroid Build Coastguard Worker 	if (t) {
546*193032a3SAndroid Build Coastguard Worker 		char type[16];
547*193032a3SAndroid Build Coastguard Worker 		sprintf(type, "DMT 0x%02x", dmt_id);
548*193032a3SAndroid Build Coastguard Worker 		print_timings(prefix, t, type);
549*193032a3SAndroid Build Coastguard Worker 		return;
550*193032a3SAndroid Build Coastguard Worker 	}
551*193032a3SAndroid Build Coastguard Worker 	hact = (b1 + 31) * 8;
552*193032a3SAndroid Build Coastguard Worker 	switch ((b2 >> 6) & 0x3) {
553*193032a3SAndroid Build Coastguard Worker 	case 0x00:
554*193032a3SAndroid Build Coastguard Worker 		if (gtf_only || show_both || base.edid_minor >= 3) {
555*193032a3SAndroid Build Coastguard Worker 			hratio = 16;
556*193032a3SAndroid Build Coastguard Worker 			vratio = 10;
557*193032a3SAndroid Build Coastguard Worker 		} else {
558*193032a3SAndroid Build Coastguard Worker 			hratio = 1;
559*193032a3SAndroid Build Coastguard Worker 			vratio = 1;
560*193032a3SAndroid Build Coastguard Worker 		}
561*193032a3SAndroid Build Coastguard Worker 		break;
562*193032a3SAndroid Build Coastguard Worker 	case 0x01:
563*193032a3SAndroid Build Coastguard Worker 		hratio = 4;
564*193032a3SAndroid Build Coastguard Worker 		vratio = 3;
565*193032a3SAndroid Build Coastguard Worker 		break;
566*193032a3SAndroid Build Coastguard Worker 	case 0x02:
567*193032a3SAndroid Build Coastguard Worker 		hratio = 5;
568*193032a3SAndroid Build Coastguard Worker 		vratio = 4;
569*193032a3SAndroid Build Coastguard Worker 		break;
570*193032a3SAndroid Build Coastguard Worker 	case 0x03:
571*193032a3SAndroid Build Coastguard Worker 		hratio = 16;
572*193032a3SAndroid Build Coastguard Worker 		vratio = 9;
573*193032a3SAndroid Build Coastguard Worker 		break;
574*193032a3SAndroid Build Coastguard Worker 	}
575*193032a3SAndroid Build Coastguard Worker 	vact = (double)hact * vratio / hratio;
576*193032a3SAndroid Build Coastguard Worker 	vact = 8 * ((vact + 7) / 8);
577*193032a3SAndroid Build Coastguard Worker 	refresh = (b2 & 0x3f) + 60;
578*193032a3SAndroid Build Coastguard Worker 
579*193032a3SAndroid Build Coastguard Worker 	formula.hact = hact;
580*193032a3SAndroid Build Coastguard Worker 	formula.vact = vact;
581*193032a3SAndroid Build Coastguard Worker 	formula.hratio = hratio;
582*193032a3SAndroid Build Coastguard Worker 	formula.vratio = vratio;
583*193032a3SAndroid Build Coastguard Worker 
584*193032a3SAndroid Build Coastguard Worker 	if (!gtf_only && (show_both || base.edid_minor >= 4)) {
585*193032a3SAndroid Build Coastguard Worker 		if (show_both || base.supports_cvt) {
586*193032a3SAndroid Build Coastguard Worker 			edid_cvt_mode(refresh, formula);
587*193032a3SAndroid Build Coastguard Worker 			print_timings(prefix, &formula, "CVT     ",
588*193032a3SAndroid Build Coastguard Worker 				      show_both ? "" : "EDID 1.4 source");
589*193032a3SAndroid Build Coastguard Worker 		}
590*193032a3SAndroid Build Coastguard Worker 		/*
591*193032a3SAndroid Build Coastguard Worker 		 * An EDID 1.3 source will assume GTF, so both GTF and CVT
592*193032a3SAndroid Build Coastguard Worker 		 * have to be supported.
593*193032a3SAndroid Build Coastguard Worker 		 */
594*193032a3SAndroid Build Coastguard Worker 		edid_gtf_mode(refresh, formula);
595*193032a3SAndroid Build Coastguard Worker 		if (base.supports_cvt)
596*193032a3SAndroid Build Coastguard Worker 			print_timings(prefix, &formula, "GTF     ", "EDID 1.3 source");
597*193032a3SAndroid Build Coastguard Worker 		else
598*193032a3SAndroid Build Coastguard Worker 			print_timings(prefix, &formula, "GTF     ");
599*193032a3SAndroid Build Coastguard Worker 	} else if (gtf_only || base.edid_minor >= 2) {
600*193032a3SAndroid Build Coastguard Worker 		edid_gtf_mode(refresh, formula);
601*193032a3SAndroid Build Coastguard Worker 		print_timings(prefix, &formula, "GTF     ");
602*193032a3SAndroid Build Coastguard Worker 	} else {
603*193032a3SAndroid Build Coastguard Worker 		printf("%sUnknown : %5ux%-5u %3u.000 Hz %3u:%u\n",
604*193032a3SAndroid Build Coastguard Worker 		       prefix, hact, vact, refresh, hratio, vratio);
605*193032a3SAndroid Build Coastguard Worker 		min_vert_freq_hz = min(min_vert_freq_hz, refresh);
606*193032a3SAndroid Build Coastguard Worker 		max_vert_freq_hz = max(max_vert_freq_hz, refresh);
607*193032a3SAndroid Build Coastguard Worker 	}
608*193032a3SAndroid Build Coastguard Worker }
609*193032a3SAndroid Build Coastguard Worker 
detailed_display_range_limits(const unsigned char * x)610*193032a3SAndroid Build Coastguard Worker void edid_state::detailed_display_range_limits(const unsigned char *x)
611*193032a3SAndroid Build Coastguard Worker {
612*193032a3SAndroid Build Coastguard Worker 	int h_max_offset = 0, h_min_offset = 0;
613*193032a3SAndroid Build Coastguard Worker 	int v_max_offset = 0, v_min_offset = 0;
614*193032a3SAndroid Build Coastguard Worker 	int is_cvt = 0;
615*193032a3SAndroid Build Coastguard Worker 	bool has_sec_gtf = false;
616*193032a3SAndroid Build Coastguard Worker 	std::string range_class;
617*193032a3SAndroid Build Coastguard Worker 
618*193032a3SAndroid Build Coastguard Worker 	data_block = "Display Range Limits";
619*193032a3SAndroid Build Coastguard Worker 	printf("  %s:\n", data_block.c_str());
620*193032a3SAndroid Build Coastguard Worker 	base.has_display_range_descriptor = 1;
621*193032a3SAndroid Build Coastguard Worker 
622*193032a3SAndroid Build Coastguard Worker 	if (base.edid_minor >= 4) {
623*193032a3SAndroid Build Coastguard Worker 		if (x[4] & 0x02) {
624*193032a3SAndroid Build Coastguard Worker 			v_max_offset = 255;
625*193032a3SAndroid Build Coastguard Worker 			if (x[4] & 0x01) {
626*193032a3SAndroid Build Coastguard Worker 				v_min_offset = 255;
627*193032a3SAndroid Build Coastguard Worker 			}
628*193032a3SAndroid Build Coastguard Worker 		}
629*193032a3SAndroid Build Coastguard Worker 		if (x[4] & 0x08) {
630*193032a3SAndroid Build Coastguard Worker 			h_max_offset = 255;
631*193032a3SAndroid Build Coastguard Worker 			if (x[4] & 0x04) {
632*193032a3SAndroid Build Coastguard Worker 				h_min_offset = 255;
633*193032a3SAndroid Build Coastguard Worker 			}
634*193032a3SAndroid Build Coastguard Worker 		}
635*193032a3SAndroid Build Coastguard Worker 	}
636*193032a3SAndroid Build Coastguard Worker 
637*193032a3SAndroid Build Coastguard Worker 	/*
638*193032a3SAndroid Build Coastguard Worker 	 * despite the values, this is not a bitfield.
639*193032a3SAndroid Build Coastguard Worker 	 */
640*193032a3SAndroid Build Coastguard Worker 	switch (x[10]) {
641*193032a3SAndroid Build Coastguard Worker 	case 0x00: /* default gtf */
642*193032a3SAndroid Build Coastguard Worker 		range_class = "GTF";
643*193032a3SAndroid Build Coastguard Worker 		if (base.edid_minor >= 4 && !base.supports_continuous_freq)
644*193032a3SAndroid Build Coastguard Worker 			fail("GTF can't be combined with non-continuous frequencies.\n");
645*193032a3SAndroid Build Coastguard Worker 		if (base.edid_minor >= 4)
646*193032a3SAndroid Build Coastguard Worker 			warn("GTF support is deprecated in EDID 1.4.\n");
647*193032a3SAndroid Build Coastguard Worker 		break;
648*193032a3SAndroid Build Coastguard Worker 	case 0x01: /* range limits only */
649*193032a3SAndroid Build Coastguard Worker 		range_class = "Bare Limits";
650*193032a3SAndroid Build Coastguard Worker 		if (base.edid_minor < 4)
651*193032a3SAndroid Build Coastguard Worker 			fail("'%s' is not allowed for EDID < 1.4.\n", range_class.c_str());
652*193032a3SAndroid Build Coastguard Worker 		break;
653*193032a3SAndroid Build Coastguard Worker 	case 0x02: /* secondary gtf curve */
654*193032a3SAndroid Build Coastguard Worker 		range_class = "Secondary GTF";
655*193032a3SAndroid Build Coastguard Worker 		if (base.edid_minor >= 4 && !base.supports_continuous_freq)
656*193032a3SAndroid Build Coastguard Worker 			fail("GTF can't be combined with non-continuous frequencies.\n");
657*193032a3SAndroid Build Coastguard Worker 		if (base.edid_minor >= 4)
658*193032a3SAndroid Build Coastguard Worker 			warn("GTF support is deprecated in EDID 1.4.\n");
659*193032a3SAndroid Build Coastguard Worker 		has_sec_gtf = true;
660*193032a3SAndroid Build Coastguard Worker 		break;
661*193032a3SAndroid Build Coastguard Worker 	case 0x04: /* cvt */
662*193032a3SAndroid Build Coastguard Worker 		range_class = "CVT";
663*193032a3SAndroid Build Coastguard Worker 		is_cvt = 1;
664*193032a3SAndroid Build Coastguard Worker 		if (base.edid_minor < 4)
665*193032a3SAndroid Build Coastguard Worker 			fail("'%s' is not allowed for EDID < 1.4.\n", range_class.c_str());
666*193032a3SAndroid Build Coastguard Worker 		else if (!base.supports_continuous_freq)
667*193032a3SAndroid Build Coastguard Worker 			fail("CVT can't be combined with non-continuous frequencies.\n");
668*193032a3SAndroid Build Coastguard Worker 		break;
669*193032a3SAndroid Build Coastguard Worker 	default: /* invalid */
670*193032a3SAndroid Build Coastguard Worker 		fail("Unknown range class (0x%02x).\n", x[10]);
671*193032a3SAndroid Build Coastguard Worker 		range_class = std::string("Unknown (") + utohex(x[10]) + ")";
672*193032a3SAndroid Build Coastguard Worker 		break;
673*193032a3SAndroid Build Coastguard Worker 	}
674*193032a3SAndroid Build Coastguard Worker 
675*193032a3SAndroid Build Coastguard Worker 	if (x[5] + v_min_offset > x[6] + v_max_offset)
676*193032a3SAndroid Build Coastguard Worker 		fail("Min vertical rate > max vertical rate.\n");
677*193032a3SAndroid Build Coastguard Worker 	base.min_display_vert_freq_hz = x[5] + v_min_offset;
678*193032a3SAndroid Build Coastguard Worker 	base.max_display_vert_freq_hz = x[6] + v_max_offset;
679*193032a3SAndroid Build Coastguard Worker 	if (x[7] + h_min_offset > x[8] + h_max_offset)
680*193032a3SAndroid Build Coastguard Worker 		fail("Min horizontal freq > max horizontal freq.\n");
681*193032a3SAndroid Build Coastguard Worker 	base.min_display_hor_freq_hz = (x[7] + h_min_offset) * 1000;
682*193032a3SAndroid Build Coastguard Worker 	base.max_display_hor_freq_hz = (x[8] + h_max_offset) * 1000;
683*193032a3SAndroid Build Coastguard Worker 	printf("    Monitor ranges (%s): %d-%d Hz V, %d-%d kHz H",
684*193032a3SAndroid Build Coastguard Worker 	       range_class.c_str(),
685*193032a3SAndroid Build Coastguard Worker 	       x[5] + v_min_offset, x[6] + v_max_offset,
686*193032a3SAndroid Build Coastguard Worker 	       x[7] + h_min_offset, x[8] + h_max_offset);
687*193032a3SAndroid Build Coastguard Worker 
688*193032a3SAndroid Build Coastguard Worker 	// For EDID 1.3 the horizontal frequency maxes out at 255 kHz.
689*193032a3SAndroid Build Coastguard Worker 	// So to avoid false range-check warnings due to this limitation,
690*193032a3SAndroid Build Coastguard Worker 	// just double the max_display_hor_freq_hz in this case.
691*193032a3SAndroid Build Coastguard Worker 	if (base.edid_minor < 4 && x[8] == 0xff)
692*193032a3SAndroid Build Coastguard Worker 		base.max_display_hor_freq_hz *= 2;
693*193032a3SAndroid Build Coastguard Worker 
694*193032a3SAndroid Build Coastguard Worker 	// For EDID 1.3 the vertical frequency maxes out at 255 Hz.
695*193032a3SAndroid Build Coastguard Worker 	// So to avoid false range-check warnings due to this limitation,
696*193032a3SAndroid Build Coastguard Worker 	// just double the max_display_vert_freq_hz in this case.
697*193032a3SAndroid Build Coastguard Worker 	if (base.edid_minor < 4 && x[6] == 0xff)
698*193032a3SAndroid Build Coastguard Worker 		base.max_display_vert_freq_hz *= 2;
699*193032a3SAndroid Build Coastguard Worker 
700*193032a3SAndroid Build Coastguard Worker 	if (x[9]) {
701*193032a3SAndroid Build Coastguard Worker 		base.max_display_pixclk_khz = x[9] * 10000;
702*193032a3SAndroid Build Coastguard Worker 		printf(", max dotclock %d MHz\n", x[9] * 10);
703*193032a3SAndroid Build Coastguard Worker 	} else {
704*193032a3SAndroid Build Coastguard Worker 		if (base.edid_minor >= 4)
705*193032a3SAndroid Build Coastguard Worker 			fail("EDID 1.4 block does not set max dotclock.\n");
706*193032a3SAndroid Build Coastguard Worker 		printf("\n");
707*193032a3SAndroid Build Coastguard Worker 	}
708*193032a3SAndroid Build Coastguard Worker 
709*193032a3SAndroid Build Coastguard Worker 	if (has_sec_gtf) {
710*193032a3SAndroid Build Coastguard Worker 		if (x[11])
711*193032a3SAndroid Build Coastguard Worker 			fail("Byte 11 is 0x%02x instead of 0x00.\n", x[11]);
712*193032a3SAndroid Build Coastguard Worker 		if (memchk(x + 12, 6)) {
713*193032a3SAndroid Build Coastguard Worker 			fail("Zeroed Secondary Curve Block.\n");
714*193032a3SAndroid Build Coastguard Worker 		} else {
715*193032a3SAndroid Build Coastguard Worker 			printf("    GTF Secondary Curve Block:\n");
716*193032a3SAndroid Build Coastguard Worker 			printf("      Start frequency: %u kHz\n", x[12] * 2);
717*193032a3SAndroid Build Coastguard Worker 			printf("      C: %.1f%%\n", x[13] / 2.0);
718*193032a3SAndroid Build Coastguard Worker 			printf("      M: %u%%/kHz\n", (x[15] << 8) | x[14]);
719*193032a3SAndroid Build Coastguard Worker 			printf("      K: %u\n", x[16]);
720*193032a3SAndroid Build Coastguard Worker 			printf("      J: %.1f%%\n", x[17] / 2.0);
721*193032a3SAndroid Build Coastguard Worker 		}
722*193032a3SAndroid Build Coastguard Worker 	} else if (is_cvt) {
723*193032a3SAndroid Build Coastguard Worker 		int max_h_pixels = 0;
724*193032a3SAndroid Build Coastguard Worker 
725*193032a3SAndroid Build Coastguard Worker 		printf("    CVT version %d.%d\n", (x[11] & 0xf0) >> 4, x[11] & 0x0f);
726*193032a3SAndroid Build Coastguard Worker 
727*193032a3SAndroid Build Coastguard Worker 		if (x[12] & 0xfc) {
728*193032a3SAndroid Build Coastguard Worker 			unsigned raw_offset = (x[12] & 0xfc) >> 2;
729*193032a3SAndroid Build Coastguard Worker 
730*193032a3SAndroid Build Coastguard Worker 			printf("    Real max dotclock: %.2f MHz\n",
731*193032a3SAndroid Build Coastguard Worker 			       (x[9] * 10) - (raw_offset * 0.25));
732*193032a3SAndroid Build Coastguard Worker 			if (raw_offset >= 40)
733*193032a3SAndroid Build Coastguard Worker 				warn("CVT block corrects dotclock by more than 9.75 MHz.\n");
734*193032a3SAndroid Build Coastguard Worker 		}
735*193032a3SAndroid Build Coastguard Worker 
736*193032a3SAndroid Build Coastguard Worker 		max_h_pixels = x[12] & 0x03;
737*193032a3SAndroid Build Coastguard Worker 		max_h_pixels <<= 8;
738*193032a3SAndroid Build Coastguard Worker 		max_h_pixels |= x[13];
739*193032a3SAndroid Build Coastguard Worker 		max_h_pixels *= 8;
740*193032a3SAndroid Build Coastguard Worker 		if (max_h_pixels)
741*193032a3SAndroid Build Coastguard Worker 			printf("    Max active pixels per line: %d\n", max_h_pixels);
742*193032a3SAndroid Build Coastguard Worker 
743*193032a3SAndroid Build Coastguard Worker 		printf("    Supported aspect ratios:%s%s%s%s%s\n",
744*193032a3SAndroid Build Coastguard Worker 		       x[14] & 0x80 ? " 4:3" : "",
745*193032a3SAndroid Build Coastguard Worker 		       x[14] & 0x40 ? " 16:9" : "",
746*193032a3SAndroid Build Coastguard Worker 		       x[14] & 0x20 ? " 16:10" : "",
747*193032a3SAndroid Build Coastguard Worker 		       x[14] & 0x10 ? " 5:4" : "",
748*193032a3SAndroid Build Coastguard Worker 		       x[14] & 0x08 ? " 15:9" : "");
749*193032a3SAndroid Build Coastguard Worker 		if (x[14] & 0x07)
750*193032a3SAndroid Build Coastguard Worker 			fail("Reserved bits of byte 14 are non-zero.\n");
751*193032a3SAndroid Build Coastguard Worker 
752*193032a3SAndroid Build Coastguard Worker 		printf("    Preferred aspect ratio: ");
753*193032a3SAndroid Build Coastguard Worker 		switch ((x[15] & 0xe0) >> 5) {
754*193032a3SAndroid Build Coastguard Worker 		case 0x00:
755*193032a3SAndroid Build Coastguard Worker 			printf("4:3");
756*193032a3SAndroid Build Coastguard Worker 			break;
757*193032a3SAndroid Build Coastguard Worker 		case 0x01:
758*193032a3SAndroid Build Coastguard Worker 			printf("16:9");
759*193032a3SAndroid Build Coastguard Worker 			break;
760*193032a3SAndroid Build Coastguard Worker 		case 0x02:
761*193032a3SAndroid Build Coastguard Worker 			printf("16:10");
762*193032a3SAndroid Build Coastguard Worker 			break;
763*193032a3SAndroid Build Coastguard Worker 		case 0x03:
764*193032a3SAndroid Build Coastguard Worker 			printf("5:4");
765*193032a3SAndroid Build Coastguard Worker 			break;
766*193032a3SAndroid Build Coastguard Worker 		case 0x04:
767*193032a3SAndroid Build Coastguard Worker 			printf("15:9");
768*193032a3SAndroid Build Coastguard Worker 			break;
769*193032a3SAndroid Build Coastguard Worker 		default:
770*193032a3SAndroid Build Coastguard Worker 			printf("Unknown (0x%02x)", (x[15] & 0xe0) >> 5);
771*193032a3SAndroid Build Coastguard Worker 			fail("Invalid preferred aspect ratio 0x%02x.\n",
772*193032a3SAndroid Build Coastguard Worker 			     (x[15] & 0xe0) >> 5);
773*193032a3SAndroid Build Coastguard Worker 			break;
774*193032a3SAndroid Build Coastguard Worker 		}
775*193032a3SAndroid Build Coastguard Worker 		printf("\n");
776*193032a3SAndroid Build Coastguard Worker 
777*193032a3SAndroid Build Coastguard Worker 		if (x[15] & 0x08)
778*193032a3SAndroid Build Coastguard Worker 			printf("    Supports CVT standard blanking\n");
779*193032a3SAndroid Build Coastguard Worker 		if (x[15] & 0x10)
780*193032a3SAndroid Build Coastguard Worker 			printf("    Supports CVT reduced blanking\n");
781*193032a3SAndroid Build Coastguard Worker 
782*193032a3SAndroid Build Coastguard Worker 		if (x[15] & 0x07)
783*193032a3SAndroid Build Coastguard Worker 			fail("Reserved bits of byte 15 are non-zero.\n");
784*193032a3SAndroid Build Coastguard Worker 
785*193032a3SAndroid Build Coastguard Worker 		if (x[16] & 0xf0) {
786*193032a3SAndroid Build Coastguard Worker 			printf("    Supported display scaling:\n");
787*193032a3SAndroid Build Coastguard Worker 			if (x[16] & 0x80)
788*193032a3SAndroid Build Coastguard Worker 				printf("      Horizontal shrink\n");
789*193032a3SAndroid Build Coastguard Worker 			if (x[16] & 0x40)
790*193032a3SAndroid Build Coastguard Worker 				printf("      Horizontal stretch\n");
791*193032a3SAndroid Build Coastguard Worker 			if (x[16] & 0x20)
792*193032a3SAndroid Build Coastguard Worker 				printf("      Vertical shrink\n");
793*193032a3SAndroid Build Coastguard Worker 			if (x[16] & 0x10)
794*193032a3SAndroid Build Coastguard Worker 				printf("      Vertical stretch\n");
795*193032a3SAndroid Build Coastguard Worker 		}
796*193032a3SAndroid Build Coastguard Worker 
797*193032a3SAndroid Build Coastguard Worker 		if (x[16] & 0x0f)
798*193032a3SAndroid Build Coastguard Worker 			fail("Reserved bits of byte 16 are non-zero.\n");
799*193032a3SAndroid Build Coastguard Worker 
800*193032a3SAndroid Build Coastguard Worker 		if (x[17])
801*193032a3SAndroid Build Coastguard Worker 			printf("    Preferred vertical refresh: %d Hz\n", x[17]);
802*193032a3SAndroid Build Coastguard Worker 		else
803*193032a3SAndroid Build Coastguard Worker 			warn("CVT block does not set preferred refresh rate.\n");
804*193032a3SAndroid Build Coastguard Worker 	} else {
805*193032a3SAndroid Build Coastguard Worker 		if (x[11] != 0x0a)
806*193032a3SAndroid Build Coastguard Worker 			fail("Byte 11 is 0x%02x instead of 0x0a.\n", x[11]);
807*193032a3SAndroid Build Coastguard Worker 		for (unsigned i = 12; i <= 17; i++) {
808*193032a3SAndroid Build Coastguard Worker 			if (x[i] != 0x20) {
809*193032a3SAndroid Build Coastguard Worker 				fail("Bytes 12-17 must be 0x20.\n");
810*193032a3SAndroid Build Coastguard Worker 				break;
811*193032a3SAndroid Build Coastguard Worker 			}
812*193032a3SAndroid Build Coastguard Worker 		}
813*193032a3SAndroid Build Coastguard Worker 	}
814*193032a3SAndroid Build Coastguard Worker }
815*193032a3SAndroid Build Coastguard Worker 
detailed_epi(const unsigned char * x)816*193032a3SAndroid Build Coastguard Worker void edid_state::detailed_epi(const unsigned char *x)
817*193032a3SAndroid Build Coastguard Worker {
818*193032a3SAndroid Build Coastguard Worker 	data_block = "EPI Descriptor";
819*193032a3SAndroid Build Coastguard Worker 	printf("    %s:\n", data_block.c_str());
820*193032a3SAndroid Build Coastguard Worker 
821*193032a3SAndroid Build Coastguard Worker 	unsigned v = x[5] & 0x07;
822*193032a3SAndroid Build Coastguard Worker 
823*193032a3SAndroid Build Coastguard Worker 	printf("      Bits per pixel: %u\n", 18 + v * 6);
824*193032a3SAndroid Build Coastguard Worker 	if (v > 2)
825*193032a3SAndroid Build Coastguard Worker 		fail("Invalid bits per pixel.\n");
826*193032a3SAndroid Build Coastguard Worker 	v = (x[5] & 0x18) >> 3;
827*193032a3SAndroid Build Coastguard Worker 	printf("      Pixels per clock: %u\n", 1 << v);
828*193032a3SAndroid Build Coastguard Worker 	if (v > 2)
829*193032a3SAndroid Build Coastguard Worker 		fail("Invalid pixels per clock.\n");
830*193032a3SAndroid Build Coastguard Worker 	v = (x[5] & 0x60) >> 5;
831*193032a3SAndroid Build Coastguard Worker 	printf("      Data color mapping: %sconventional\n", v ? "non-" : "");
832*193032a3SAndroid Build Coastguard Worker 	if (v > 1)
833*193032a3SAndroid Build Coastguard Worker 		fail("Unknown data color mapping (0x%02x).\n", v);
834*193032a3SAndroid Build Coastguard Worker 	if (x[5] & 0x80)
835*193032a3SAndroid Build Coastguard Worker 		fail("Non-zero reserved field in byte 5.\n");
836*193032a3SAndroid Build Coastguard Worker 
837*193032a3SAndroid Build Coastguard Worker 	v = x[6] & 0x0f;
838*193032a3SAndroid Build Coastguard Worker 	printf("      Interface type: ");
839*193032a3SAndroid Build Coastguard Worker 	switch (v) {
840*193032a3SAndroid Build Coastguard Worker 	case 0x00: printf("LVDS TFT\n"); break;
841*193032a3SAndroid Build Coastguard Worker 	case 0x01: printf("monoSTN 4/8 Bit\n"); break;
842*193032a3SAndroid Build Coastguard Worker 	case 0x02: printf("colorSTN 8/16 Bit\n"); break;
843*193032a3SAndroid Build Coastguard Worker 	case 0x03: printf("18 Bit TFT\n"); break;
844*193032a3SAndroid Build Coastguard Worker 	case 0x04: printf("24 Bit TFT\n"); break;
845*193032a3SAndroid Build Coastguard Worker 	case 0x05: printf("TMDS\n"); break;
846*193032a3SAndroid Build Coastguard Worker 	default:
847*193032a3SAndroid Build Coastguard Worker 		   printf("Unknown (0x%02x)\n", v);
848*193032a3SAndroid Build Coastguard Worker 		   fail("Invalid interface type 0x%02x.\n", v);
849*193032a3SAndroid Build Coastguard Worker 		   break;
850*193032a3SAndroid Build Coastguard Worker 	}
851*193032a3SAndroid Build Coastguard Worker 	printf("      DE polarity: DE %s active\n",
852*193032a3SAndroid Build Coastguard Worker 	       (x[6] & 0x10) ? "low" : "high");
853*193032a3SAndroid Build Coastguard Worker 	printf("      FPSCLK polarity: FPSCLK %sinverted\n",
854*193032a3SAndroid Build Coastguard Worker 	       (x[6] & 0x20) ? "" : "not ");
855*193032a3SAndroid Build Coastguard Worker 	if (x[6] & 0xc0)
856*193032a3SAndroid Build Coastguard Worker 		fail("Non-zero reserved field in byte 6.\n");
857*193032a3SAndroid Build Coastguard Worker 
858*193032a3SAndroid Build Coastguard Worker 	printf("      Vertical display mode: %s\n",
859*193032a3SAndroid Build Coastguard Worker 	       (x[7] & 0x01) ? "Up/Down reverse mode" : "normal");
860*193032a3SAndroid Build Coastguard Worker 	printf("      Horizontal display mode: %s\n",
861*193032a3SAndroid Build Coastguard Worker 	       (x[7] & 0x02) ? "Left/Right reverse mode" : "normal");
862*193032a3SAndroid Build Coastguard Worker 	if (x[7] & 0xfc)
863*193032a3SAndroid Build Coastguard Worker 		fail("Non-zero reserved field in byte 7.\n");
864*193032a3SAndroid Build Coastguard Worker 
865*193032a3SAndroid Build Coastguard Worker 	v = x[8] & 0x0f;
866*193032a3SAndroid Build Coastguard Worker 	printf("      Total power on sequencing delay: ");
867*193032a3SAndroid Build Coastguard Worker 	if (v)
868*193032a3SAndroid Build Coastguard Worker 		printf("%u ms\n", v * 10);
869*193032a3SAndroid Build Coastguard Worker 	else
870*193032a3SAndroid Build Coastguard Worker 		printf("VGA controller default\n");
871*193032a3SAndroid Build Coastguard Worker 	v = (x[8] & 0xf0) >> 4;
872*193032a3SAndroid Build Coastguard Worker 	printf("      Total power off sequencing delay: ");
873*193032a3SAndroid Build Coastguard Worker 	if (v)
874*193032a3SAndroid Build Coastguard Worker 		printf("%u ms\n", v * 10);
875*193032a3SAndroid Build Coastguard Worker 	else
876*193032a3SAndroid Build Coastguard Worker 		printf("VGA controller default\n");
877*193032a3SAndroid Build Coastguard Worker 
878*193032a3SAndroid Build Coastguard Worker 	v = x[9] & 0x0f;
879*193032a3SAndroid Build Coastguard Worker 	printf("      Contrast power on sequencing delay: ");
880*193032a3SAndroid Build Coastguard Worker 	if (v)
881*193032a3SAndroid Build Coastguard Worker 		printf("%u ms\n", v * 10);
882*193032a3SAndroid Build Coastguard Worker 	else
883*193032a3SAndroid Build Coastguard Worker 		printf("VGA controller default\n");
884*193032a3SAndroid Build Coastguard Worker 	v = (x[9] & 0xf0) >> 4;
885*193032a3SAndroid Build Coastguard Worker 	printf("      Contrast power off sequencing delay: ");
886*193032a3SAndroid Build Coastguard Worker 	if (v)
887*193032a3SAndroid Build Coastguard Worker 		printf("%u ms\n", v * 10);
888*193032a3SAndroid Build Coastguard Worker 	else
889*193032a3SAndroid Build Coastguard Worker 		printf("VGA controller default\n");
890*193032a3SAndroid Build Coastguard Worker 
891*193032a3SAndroid Build Coastguard Worker 	v = x[10] & 0x2f;
892*193032a3SAndroid Build Coastguard Worker 	const char *s = (x[10] & 0x80) ? "" : " (ignored)";
893*193032a3SAndroid Build Coastguard Worker 
894*193032a3SAndroid Build Coastguard Worker 	printf("      Backlight brightness control: %u steps%s\n", v, s);
895*193032a3SAndroid Build Coastguard Worker 	printf("      Backlight enable at boot: %s%s\n",
896*193032a3SAndroid Build Coastguard Worker 	       (x[10] & 0x40) ? "off" : "on", s);
897*193032a3SAndroid Build Coastguard Worker 	printf("      Backlight control enable: %s\n",
898*193032a3SAndroid Build Coastguard Worker 	       (x[10] & 0x80) ? "enabled" : "disabled");
899*193032a3SAndroid Build Coastguard Worker 
900*193032a3SAndroid Build Coastguard Worker 	v = x[11] & 0x2f;
901*193032a3SAndroid Build Coastguard Worker 	s = (x[11] & 0x80) ? "" : " (ignored)";
902*193032a3SAndroid Build Coastguard Worker 
903*193032a3SAndroid Build Coastguard Worker 	printf("      Contrast voltable control: %u steps%s\n", v, s);
904*193032a3SAndroid Build Coastguard Worker 	if (x[11] & 0x40)
905*193032a3SAndroid Build Coastguard Worker 		fail("Non-zero reserved field in byte 11.\n");
906*193032a3SAndroid Build Coastguard Worker 	printf("      Contrast control enable: %s\n",
907*193032a3SAndroid Build Coastguard Worker 	       (x[11] & 0x80) ? "enabled" : "disabled");
908*193032a3SAndroid Build Coastguard Worker 
909*193032a3SAndroid Build Coastguard Worker 	if (x[12] || x[13] || x[14] || x[15] || x[16])
910*193032a3SAndroid Build Coastguard Worker 		fail("Non-zero values in reserved bytes 12-16.\n");
911*193032a3SAndroid Build Coastguard Worker 
912*193032a3SAndroid Build Coastguard Worker 	printf("      EPI Version: %u.%u\n", (x[17] & 0xf0) >> 4, x[17] & 0x0f);
913*193032a3SAndroid Build Coastguard Worker }
914*193032a3SAndroid Build Coastguard Worker 
detailed_timings(const char * prefix,const unsigned char * x,bool base_or_cta)915*193032a3SAndroid Build Coastguard Worker void edid_state::detailed_timings(const char *prefix, const unsigned char *x,
916*193032a3SAndroid Build Coastguard Worker 				  bool base_or_cta)
917*193032a3SAndroid Build Coastguard Worker {
918*193032a3SAndroid Build Coastguard Worker 	struct timings t = {};
919*193032a3SAndroid Build Coastguard Worker 	unsigned hbl, vbl;
920*193032a3SAndroid Build Coastguard Worker 	std::string s_sync, s_flags;
921*193032a3SAndroid Build Coastguard Worker 
922*193032a3SAndroid Build Coastguard Worker 	// Only count DTDs in base block 0 or CTA-861 extension blocks
923*193032a3SAndroid Build Coastguard Worker 	if (base_or_cta)
924*193032a3SAndroid Build Coastguard Worker 		base.dtd_cnt++;
925*193032a3SAndroid Build Coastguard Worker 	data_block = "Detailed Timing Descriptor #" + std::to_string(base.dtd_cnt);
926*193032a3SAndroid Build Coastguard Worker 	t.pixclk_khz = (x[0] + (x[1] << 8)) * 10;
927*193032a3SAndroid Build Coastguard Worker 	if (t.pixclk_khz < 10000) {
928*193032a3SAndroid Build Coastguard Worker 		printf("%sDetailed mode: ", prefix);
929*193032a3SAndroid Build Coastguard Worker 		hex_block("", x, 18, true, 18);
930*193032a3SAndroid Build Coastguard Worker 		if (!t.pixclk_khz)
931*193032a3SAndroid Build Coastguard Worker 			fail("First two bytes are 0, invalid data.\n");
932*193032a3SAndroid Build Coastguard Worker 		else
933*193032a3SAndroid Build Coastguard Worker 			fail("Pixelclock < 10 MHz, assuming invalid data 0x%02x 0x%02x.\n",
934*193032a3SAndroid Build Coastguard Worker 			     x[0], x[1]);
935*193032a3SAndroid Build Coastguard Worker 		return;
936*193032a3SAndroid Build Coastguard Worker 	}
937*193032a3SAndroid Build Coastguard Worker 
938*193032a3SAndroid Build Coastguard Worker 	/*
939*193032a3SAndroid Build Coastguard Worker 	 * If the borders are non-zero, then it is unclear how to interpret
940*193032a3SAndroid Build Coastguard Worker 	 * the DTD blanking parameters.
941*193032a3SAndroid Build Coastguard Worker 	 *
942*193032a3SAndroid Build Coastguard Worker 	 * According to EDID 1.3 (3.12) the Hor/Vert Blanking includes the
943*193032a3SAndroid Build Coastguard Worker 	 * borders, and so does the Hor/Vert Sync Offset.
944*193032a3SAndroid Build Coastguard Worker 	 *
945*193032a3SAndroid Build Coastguard Worker 	 * According to EDID 1.4 (3.12) the Hor/Vert Blanking excludes the
946*193032a3SAndroid Build Coastguard Worker 	 * borders, and they are also excluded from the Hor/Vert Front Porch.
947*193032a3SAndroid Build Coastguard Worker 	 *
948*193032a3SAndroid Build Coastguard Worker 	 * But looking at what is really done in EDIDs is that the Hor/Vert
949*193032a3SAndroid Build Coastguard Worker 	 * Blanking follows EDID 1.3, but the Hor/Vert Front Porch does not
950*193032a3SAndroid Build Coastguard Worker 	 * include the border.
951*193032a3SAndroid Build Coastguard Worker 	 *
952*193032a3SAndroid Build Coastguard Worker 	 * So hbl/vbl includes the borders, so those need to be subtracted,
953*193032a3SAndroid Build Coastguard Worker 	 * but hfp/vfp is used as-is.
954*193032a3SAndroid Build Coastguard Worker 	 *
955*193032a3SAndroid Build Coastguard Worker 	 * In practice you really shouldn't use non-zero borders in DTDs
956*193032a3SAndroid Build Coastguard Worker 	 * since clearly nobody knows how to interpret the timing.
957*193032a3SAndroid Build Coastguard Worker 	 */
958*193032a3SAndroid Build Coastguard Worker 	t.hact = (x[2] + ((x[4] & 0xf0) << 4));
959*193032a3SAndroid Build Coastguard Worker 	t.hborder = x[15];
960*193032a3SAndroid Build Coastguard Worker 	hbl = (x[3] + ((x[4] & 0x0f) << 8)) - t.hborder * 2;
961*193032a3SAndroid Build Coastguard Worker 	t.hfp = (x[8] + ((x[11] & 0xc0) << 2));
962*193032a3SAndroid Build Coastguard Worker 	t.hsync = (x[9] + ((x[11] & 0x30) << 4));
963*193032a3SAndroid Build Coastguard Worker 	t.hbp = hbl - t.hsync - t.hfp;
964*193032a3SAndroid Build Coastguard Worker 	t.vact = (x[5] + ((x[7] & 0xf0) << 4));
965*193032a3SAndroid Build Coastguard Worker 	t.vborder = x[16];
966*193032a3SAndroid Build Coastguard Worker 	vbl = (x[6] + ((x[7] & 0x0f) << 8)) - t.vborder * 2;
967*193032a3SAndroid Build Coastguard Worker 	t.vfp = ((x[10] >> 4) + ((x[11] & 0x0c) << 2));
968*193032a3SAndroid Build Coastguard Worker 	t.vsync = ((x[10] & 0x0f) + ((x[11] & 0x03) << 4));
969*193032a3SAndroid Build Coastguard Worker 	t.vbp = vbl - t.vsync - t.vfp;
970*193032a3SAndroid Build Coastguard Worker 
971*193032a3SAndroid Build Coastguard Worker 	unsigned char flags = x[17];
972*193032a3SAndroid Build Coastguard Worker 
973*193032a3SAndroid Build Coastguard Worker 	if (base.has_spwg && base.detailed_block_cnt == 2)
974*193032a3SAndroid Build Coastguard Worker 		flags = *(x - 1);
975*193032a3SAndroid Build Coastguard Worker 
976*193032a3SAndroid Build Coastguard Worker 	switch ((flags & 0x18) >> 3) {
977*193032a3SAndroid Build Coastguard Worker 	case 0x00:
978*193032a3SAndroid Build Coastguard Worker 		s_flags = "analog composite";
979*193032a3SAndroid Build Coastguard Worker 		/* fall-through */
980*193032a3SAndroid Build Coastguard Worker 	case 0x01:
981*193032a3SAndroid Build Coastguard Worker 		if (s_flags.empty())
982*193032a3SAndroid Build Coastguard Worker 			s_flags = "bipolar analog composite";
983*193032a3SAndroid Build Coastguard Worker 		switch ((flags & 0x06) >> 1) {
984*193032a3SAndroid Build Coastguard Worker 		case 0x00:
985*193032a3SAndroid Build Coastguard Worker 			add_str(s_flags, "sync-on-green");
986*193032a3SAndroid Build Coastguard Worker 			break;
987*193032a3SAndroid Build Coastguard Worker 		case 0x01:
988*193032a3SAndroid Build Coastguard Worker 			break;
989*193032a3SAndroid Build Coastguard Worker 		case 0x02:
990*193032a3SAndroid Build Coastguard Worker 			add_str(s_flags, "serrate, sync-on-green");
991*193032a3SAndroid Build Coastguard Worker 			break;
992*193032a3SAndroid Build Coastguard Worker 		case 0x03:
993*193032a3SAndroid Build Coastguard Worker 			add_str(s_flags, "serrate");
994*193032a3SAndroid Build Coastguard Worker 			break;
995*193032a3SAndroid Build Coastguard Worker 		}
996*193032a3SAndroid Build Coastguard Worker 		break;
997*193032a3SAndroid Build Coastguard Worker 	case 0x02:
998*193032a3SAndroid Build Coastguard Worker 		if (flags & (1 << 1))
999*193032a3SAndroid Build Coastguard Worker 			t.pos_pol_hsync = true;
1000*193032a3SAndroid Build Coastguard Worker 		t.no_pol_vsync = true;
1001*193032a3SAndroid Build Coastguard Worker 		s_flags = "digital composite";
1002*193032a3SAndroid Build Coastguard Worker 		if (flags & (1 << 2))
1003*193032a3SAndroid Build Coastguard Worker 		    add_str(s_flags, "serrate");
1004*193032a3SAndroid Build Coastguard Worker 		break;
1005*193032a3SAndroid Build Coastguard Worker 	case 0x03:
1006*193032a3SAndroid Build Coastguard Worker 		if (flags & (1 << 1))
1007*193032a3SAndroid Build Coastguard Worker 			t.pos_pol_hsync = true;
1008*193032a3SAndroid Build Coastguard Worker 		if (flags & (1 << 2))
1009*193032a3SAndroid Build Coastguard Worker 			t.pos_pol_vsync = true;
1010*193032a3SAndroid Build Coastguard Worker 		s_sync = t.pos_pol_hsync ? "+hsync " : "-hsync ";
1011*193032a3SAndroid Build Coastguard Worker 		s_sync += t.pos_pol_vsync ? "+vsync " : "-vsync ";
1012*193032a3SAndroid Build Coastguard Worker 		if (base.has_spwg && (flags & 0x01))
1013*193032a3SAndroid Build Coastguard Worker 			s_flags = "DE timing only";
1014*193032a3SAndroid Build Coastguard Worker 		break;
1015*193032a3SAndroid Build Coastguard Worker 	}
1016*193032a3SAndroid Build Coastguard Worker 	if (flags & 0x80) {
1017*193032a3SAndroid Build Coastguard Worker 		t.interlaced = true;
1018*193032a3SAndroid Build Coastguard Worker 		t.vact *= 2;
1019*193032a3SAndroid Build Coastguard Worker 		/*
1020*193032a3SAndroid Build Coastguard Worker 		 * Check if this DTD matches VIC code 39 with special
1021*193032a3SAndroid Build Coastguard Worker 		 * interlaced timings.
1022*193032a3SAndroid Build Coastguard Worker 		 */
1023*193032a3SAndroid Build Coastguard Worker 		if (t.hact == 1920 && t.vact == 1080 && t.pixclk_khz == 72000 &&
1024*193032a3SAndroid Build Coastguard Worker 		    t.hfp == 32 && t.hsync == 168 && t.hbp == 184 && !t.hborder &&
1025*193032a3SAndroid Build Coastguard Worker 		    t.vfp == 23 && t.vsync == 5 && t.vbp == 57 && !t.vborder &&
1026*193032a3SAndroid Build Coastguard Worker 		    !base.has_spwg && cta.preparsed_has_vic[0][39] && (flags & 0x1e) == 0x1a)
1027*193032a3SAndroid Build Coastguard Worker 			t.even_vtotal = true;
1028*193032a3SAndroid Build Coastguard Worker 	}
1029*193032a3SAndroid Build Coastguard Worker 	switch (flags & 0x61) {
1030*193032a3SAndroid Build Coastguard Worker 	case 0x20:
1031*193032a3SAndroid Build Coastguard Worker 		add_str(s_flags, "field sequential L/R");
1032*193032a3SAndroid Build Coastguard Worker 		break;
1033*193032a3SAndroid Build Coastguard Worker 	case 0x40:
1034*193032a3SAndroid Build Coastguard Worker 		add_str(s_flags, "field sequential R/L");
1035*193032a3SAndroid Build Coastguard Worker 		break;
1036*193032a3SAndroid Build Coastguard Worker 	case 0x21:
1037*193032a3SAndroid Build Coastguard Worker 		add_str(s_flags, "interleaved right even");
1038*193032a3SAndroid Build Coastguard Worker 		break;
1039*193032a3SAndroid Build Coastguard Worker 	case 0x41:
1040*193032a3SAndroid Build Coastguard Worker 		add_str(s_flags, "interleaved left even");
1041*193032a3SAndroid Build Coastguard Worker 		break;
1042*193032a3SAndroid Build Coastguard Worker 	case 0x60:
1043*193032a3SAndroid Build Coastguard Worker 		add_str(s_flags, "four way interleaved");
1044*193032a3SAndroid Build Coastguard Worker 		break;
1045*193032a3SAndroid Build Coastguard Worker 	case 0x61:
1046*193032a3SAndroid Build Coastguard Worker 		add_str(s_flags, "side by side interleaved");
1047*193032a3SAndroid Build Coastguard Worker 		break;
1048*193032a3SAndroid Build Coastguard Worker 	default:
1049*193032a3SAndroid Build Coastguard Worker 		break;
1050*193032a3SAndroid Build Coastguard Worker 	}
1051*193032a3SAndroid Build Coastguard Worker 
1052*193032a3SAndroid Build Coastguard Worker 	t.hsize_mm = x[12] + ((x[14] & 0xf0) << 4);
1053*193032a3SAndroid Build Coastguard Worker 	t.vsize_mm = x[13] + ((x[14] & 0x0f) << 8);
1054*193032a3SAndroid Build Coastguard Worker 
1055*193032a3SAndroid Build Coastguard Worker 	calc_ratio(&t);
1056*193032a3SAndroid Build Coastguard Worker 
1057*193032a3SAndroid Build Coastguard Worker 	std::string s_type = base_or_cta ? dtd_type() : "DTD";
1058*193032a3SAndroid Build Coastguard Worker 	bool ok = print_timings(prefix, &t, s_type.c_str(), s_flags.c_str(), true);
1059*193032a3SAndroid Build Coastguard Worker 	timings_ext te(t, s_type, s_flags);
1060*193032a3SAndroid Build Coastguard Worker 
1061*193032a3SAndroid Build Coastguard Worker 	if (block_nr == 0 && base.dtd_cnt == 1) {
1062*193032a3SAndroid Build Coastguard Worker 		te.type = "DTD   1";
1063*193032a3SAndroid Build Coastguard Worker 		base.preferred_timing = te;
1064*193032a3SAndroid Build Coastguard Worker 		if (has_cta) {
1065*193032a3SAndroid Build Coastguard Worker 			cta.preferred_timings.push_back(te);
1066*193032a3SAndroid Build Coastguard Worker 			cta.native_timings.push_back(te);
1067*193032a3SAndroid Build Coastguard Worker 		}
1068*193032a3SAndroid Build Coastguard Worker 	}
1069*193032a3SAndroid Build Coastguard Worker 	if (base_or_cta)
1070*193032a3SAndroid Build Coastguard Worker 		cta.vec_dtds.push_back(te);
1071*193032a3SAndroid Build Coastguard Worker 
1072*193032a3SAndroid Build Coastguard Worker 	if (t.hborder || t.vborder)
1073*193032a3SAndroid Build Coastguard Worker 		warn("The use of non-zero borders in a DTD is not recommended.\n");
1074*193032a3SAndroid Build Coastguard Worker 	if ((base.max_display_width_mm && !t.hsize_mm) ||
1075*193032a3SAndroid Build Coastguard Worker 	    (base.max_display_height_mm && !t.vsize_mm)) {
1076*193032a3SAndroid Build Coastguard Worker 		fail("Mismatch of image size vs display size: image size is not set, but display size is.\n");
1077*193032a3SAndroid Build Coastguard Worker 	}
1078*193032a3SAndroid Build Coastguard Worker 	if (base.has_spwg && base.detailed_block_cnt == 2)
1079*193032a3SAndroid Build Coastguard Worker 		printf("%sSPWG Module Revision: %hhu\n", prefix, x[17]);
1080*193032a3SAndroid Build Coastguard Worker 	if (!ok) {
1081*193032a3SAndroid Build Coastguard Worker 		std::string s = prefix;
1082*193032a3SAndroid Build Coastguard Worker 
1083*193032a3SAndroid Build Coastguard Worker 		s += "               ";
1084*193032a3SAndroid Build Coastguard Worker 		hex_block(s.c_str(), x, 18, true, 18);
1085*193032a3SAndroid Build Coastguard Worker 	}
1086*193032a3SAndroid Build Coastguard Worker }
1087*193032a3SAndroid Build Coastguard Worker 
preparse_detailed_block(const unsigned char * x)1088*193032a3SAndroid Build Coastguard Worker void edid_state::preparse_detailed_block(const unsigned char *x)
1089*193032a3SAndroid Build Coastguard Worker {
1090*193032a3SAndroid Build Coastguard Worker 	if (x[0] || x[1])
1091*193032a3SAndroid Build Coastguard Worker 		return;
1092*193032a3SAndroid Build Coastguard Worker 	if (x[3] != 0xfd)
1093*193032a3SAndroid Build Coastguard Worker 		return;
1094*193032a3SAndroid Build Coastguard Worker 
1095*193032a3SAndroid Build Coastguard Worker 	switch (x[10]) {
1096*193032a3SAndroid Build Coastguard Worker 	case 0x00: /* default gtf */
1097*193032a3SAndroid Build Coastguard Worker 		base.supports_gtf = true;
1098*193032a3SAndroid Build Coastguard Worker 		break;
1099*193032a3SAndroid Build Coastguard Worker 	case 0x02: /* secondary gtf curve */
1100*193032a3SAndroid Build Coastguard Worker 		base.supports_gtf = true;
1101*193032a3SAndroid Build Coastguard Worker 		base.supports_sec_gtf = !memchk(x + 12, 6);
1102*193032a3SAndroid Build Coastguard Worker 		base.sec_gtf_start_freq = x[12] * 2;
1103*193032a3SAndroid Build Coastguard Worker 		base.C = x[13] / 2.0;
1104*193032a3SAndroid Build Coastguard Worker 		base.M = (x[15] << 8) | x[14];
1105*193032a3SAndroid Build Coastguard Worker 		base.K = x[16];
1106*193032a3SAndroid Build Coastguard Worker 		base.J = x[17] / 2.0;
1107*193032a3SAndroid Build Coastguard Worker 		break;
1108*193032a3SAndroid Build Coastguard Worker 	case 0x04: /* cvt */
1109*193032a3SAndroid Build Coastguard Worker 		if (base.edid_minor >= 4) {
1110*193032a3SAndroid Build Coastguard Worker 			/* GTF is implied if CVT is signaled */
1111*193032a3SAndroid Build Coastguard Worker 			base.supports_gtf = true;
1112*193032a3SAndroid Build Coastguard Worker 			base.supports_cvt = true;
1113*193032a3SAndroid Build Coastguard Worker 		}
1114*193032a3SAndroid Build Coastguard Worker 		break;
1115*193032a3SAndroid Build Coastguard Worker 	}
1116*193032a3SAndroid Build Coastguard Worker }
1117*193032a3SAndroid Build Coastguard Worker 
detailed_block(const unsigned char * x)1118*193032a3SAndroid Build Coastguard Worker void edid_state::detailed_block(const unsigned char *x)
1119*193032a3SAndroid Build Coastguard Worker {
1120*193032a3SAndroid Build Coastguard Worker 	static const unsigned char zero_descr[18] = { 0 };
1121*193032a3SAndroid Build Coastguard Worker 	unsigned cnt;
1122*193032a3SAndroid Build Coastguard Worker 	unsigned i;
1123*193032a3SAndroid Build Coastguard Worker 
1124*193032a3SAndroid Build Coastguard Worker 	base.detailed_block_cnt++;
1125*193032a3SAndroid Build Coastguard Worker 	if (x[0] || x[1]) {
1126*193032a3SAndroid Build Coastguard Worker 		detailed_timings("    ", x);
1127*193032a3SAndroid Build Coastguard Worker 		if (base.seen_non_detailed_descriptor)
1128*193032a3SAndroid Build Coastguard Worker 			fail("Invalid detailed timing descriptor ordering.\n");
1129*193032a3SAndroid Build Coastguard Worker 		return;
1130*193032a3SAndroid Build Coastguard Worker 	}
1131*193032a3SAndroid Build Coastguard Worker 
1132*193032a3SAndroid Build Coastguard Worker 	data_block = "Display Descriptor #" + std::to_string(base.detailed_block_cnt);
1133*193032a3SAndroid Build Coastguard Worker 	/* Monitor descriptor block, not detailed timing descriptor. */
1134*193032a3SAndroid Build Coastguard Worker 	if (x[2] != 0) {
1135*193032a3SAndroid Build Coastguard Worker 		/* 1.3, 3.10.3 */
1136*193032a3SAndroid Build Coastguard Worker 		fail("Monitor descriptor block has byte 2 nonzero (0x%02x).\n", x[2]);
1137*193032a3SAndroid Build Coastguard Worker 	}
1138*193032a3SAndroid Build Coastguard Worker 	if ((base.edid_minor < 4 || x[3] != 0xfd) && x[4] != 0x00) {
1139*193032a3SAndroid Build Coastguard Worker 		/* 1.3, 3.10.3 */
1140*193032a3SAndroid Build Coastguard Worker 		fail("Monitor descriptor block has byte 4 nonzero (0x%02x).\n", x[4]);
1141*193032a3SAndroid Build Coastguard Worker 	}
1142*193032a3SAndroid Build Coastguard Worker 
1143*193032a3SAndroid Build Coastguard Worker 	base.seen_non_detailed_descriptor = true;
1144*193032a3SAndroid Build Coastguard Worker 	if (base.edid_minor == 0)
1145*193032a3SAndroid Build Coastguard Worker 		fail("Has descriptor blocks other than detailed timings.\n");
1146*193032a3SAndroid Build Coastguard Worker 
1147*193032a3SAndroid Build Coastguard Worker 	if (!memcmp(x, zero_descr, sizeof(zero_descr))) {
1148*193032a3SAndroid Build Coastguard Worker 		data_block = "Empty Descriptor";
1149*193032a3SAndroid Build Coastguard Worker 		printf("    %s\n", data_block.c_str());
1150*193032a3SAndroid Build Coastguard Worker 		fail("Use Dummy Descriptor instead of all zeroes.\n");
1151*193032a3SAndroid Build Coastguard Worker 		return;
1152*193032a3SAndroid Build Coastguard Worker 	}
1153*193032a3SAndroid Build Coastguard Worker 
1154*193032a3SAndroid Build Coastguard Worker 	switch (x[3]) {
1155*193032a3SAndroid Build Coastguard Worker 	case 0x0e:
1156*193032a3SAndroid Build Coastguard Worker 		detailed_epi(x);
1157*193032a3SAndroid Build Coastguard Worker 		return;
1158*193032a3SAndroid Build Coastguard Worker 	case 0x10:
1159*193032a3SAndroid Build Coastguard Worker 		data_block = "Dummy Descriptor";
1160*193032a3SAndroid Build Coastguard Worker 		printf("    %s:\n", data_block.c_str());
1161*193032a3SAndroid Build Coastguard Worker 		for (i = 5; i < 18; i++) {
1162*193032a3SAndroid Build Coastguard Worker 			if (x[i]) {
1163*193032a3SAndroid Build Coastguard Worker 				fail("Dummy block filled with garbage.\n");
1164*193032a3SAndroid Build Coastguard Worker 				break;
1165*193032a3SAndroid Build Coastguard Worker 			}
1166*193032a3SAndroid Build Coastguard Worker 		}
1167*193032a3SAndroid Build Coastguard Worker 		return;
1168*193032a3SAndroid Build Coastguard Worker 	case 0xf7:
1169*193032a3SAndroid Build Coastguard Worker 		data_block = "Established timings III";
1170*193032a3SAndroid Build Coastguard Worker 		printf("    %s:\n", data_block.c_str());
1171*193032a3SAndroid Build Coastguard Worker 		for (i = 0; i < ARRAY_SIZE(established_timings3_dmt_ids); i++)
1172*193032a3SAndroid Build Coastguard Worker 			if (x[6 + i / 8] & (1 << (7 - i % 8))) {
1173*193032a3SAndroid Build Coastguard Worker 				unsigned char dmt_id = established_timings3_dmt_ids[i];
1174*193032a3SAndroid Build Coastguard Worker 				char type[16];
1175*193032a3SAndroid Build Coastguard Worker 
1176*193032a3SAndroid Build Coastguard Worker 				sprintf(type, "DMT 0x%02x", dmt_id);
1177*193032a3SAndroid Build Coastguard Worker 				print_timings("      ", find_dmt_id(dmt_id), type);
1178*193032a3SAndroid Build Coastguard Worker 			}
1179*193032a3SAndroid Build Coastguard Worker 		return;
1180*193032a3SAndroid Build Coastguard Worker 	case 0xf8:
1181*193032a3SAndroid Build Coastguard Worker 		data_block = "CVT 3 Byte Timing Codes";
1182*193032a3SAndroid Build Coastguard Worker 		printf("    %s:\n", data_block.c_str());
1183*193032a3SAndroid Build Coastguard Worker 		if (x[5] != 0x01) {
1184*193032a3SAndroid Build Coastguard Worker 			fail("Invalid version number %u.\n", x[5]);
1185*193032a3SAndroid Build Coastguard Worker 			return;
1186*193032a3SAndroid Build Coastguard Worker 		}
1187*193032a3SAndroid Build Coastguard Worker 		for (i = 0; i < 4; i++)
1188*193032a3SAndroid Build Coastguard Worker 			detailed_cvt_descriptor("      ", x + 6 + (i * 3), !i);
1189*193032a3SAndroid Build Coastguard Worker 		return;
1190*193032a3SAndroid Build Coastguard Worker 	case 0xf9:
1191*193032a3SAndroid Build Coastguard Worker 		data_block = "Display Color Management Data";
1192*193032a3SAndroid Build Coastguard Worker 		printf("    %s:\n", data_block.c_str());
1193*193032a3SAndroid Build Coastguard Worker 		printf("      Version : %d\n", x[5]);
1194*193032a3SAndroid Build Coastguard Worker 		printf("      Red a3  : %.2f\n", (short)(x[6] | (x[7] << 8)) / 100.0);
1195*193032a3SAndroid Build Coastguard Worker 		printf("      Red a2  : %.2f\n", (short)(x[8] | (x[9] << 8)) / 100.0);
1196*193032a3SAndroid Build Coastguard Worker 		printf("      Green a3: %.2f\n", (short)(x[10] | (x[11] << 8)) / 100.0);
1197*193032a3SAndroid Build Coastguard Worker 		printf("      Green a2: %.2f\n", (short)(x[12] | (x[13] << 8)) / 100.0);
1198*193032a3SAndroid Build Coastguard Worker 		printf("      Blue a3 : %.2f\n", (short)(x[14] | (x[15] << 8)) / 100.0);
1199*193032a3SAndroid Build Coastguard Worker 		printf("      Blue a2 : %.2f\n", (short)(x[16] | (x[17] << 8)) / 100.0);
1200*193032a3SAndroid Build Coastguard Worker 		return;
1201*193032a3SAndroid Build Coastguard Worker 	case 0xfa:
1202*193032a3SAndroid Build Coastguard Worker 		data_block = "Standard Timing Identifications";
1203*193032a3SAndroid Build Coastguard Worker 		printf("    %s:\n", data_block.c_str());
1204*193032a3SAndroid Build Coastguard Worker 		for (cnt = i = 0; i < 6; i++) {
1205*193032a3SAndroid Build Coastguard Worker 			if (x[5 + i * 2] != 0x01 || x[5 + i * 2 + 1] != 0x01)
1206*193032a3SAndroid Build Coastguard Worker 				cnt++;
1207*193032a3SAndroid Build Coastguard Worker 			print_standard_timing("      ", x[5 + i * 2], x[5 + i * 2 + 1]);
1208*193032a3SAndroid Build Coastguard Worker 		}
1209*193032a3SAndroid Build Coastguard Worker 		if (!cnt)
1210*193032a3SAndroid Build Coastguard Worker 			warn("%s block without any timings.\n", data_block.c_str());
1211*193032a3SAndroid Build Coastguard Worker 		return;
1212*193032a3SAndroid Build Coastguard Worker 	case 0xfb: {
1213*193032a3SAndroid Build Coastguard Worker 		unsigned w_x, w_y;
1214*193032a3SAndroid Build Coastguard Worker 		unsigned gamma;
1215*193032a3SAndroid Build Coastguard Worker 
1216*193032a3SAndroid Build Coastguard Worker 		data_block = "Color Point Data";
1217*193032a3SAndroid Build Coastguard Worker 		printf("    %s:\n", data_block.c_str());
1218*193032a3SAndroid Build Coastguard Worker 		w_x = (x[7] << 2) | ((x[6] >> 2) & 3);
1219*193032a3SAndroid Build Coastguard Worker 		w_y = (x[8] << 2) | (x[6] & 3);
1220*193032a3SAndroid Build Coastguard Worker 		gamma = x[9];
1221*193032a3SAndroid Build Coastguard Worker 		printf("      Index: %u White: 0.%04u, 0.%04u", x[5],
1222*193032a3SAndroid Build Coastguard Worker 		       (w_x * 10000) / 1024, (w_y * 10000) / 1024);
1223*193032a3SAndroid Build Coastguard Worker 		if (gamma == 0xff)
1224*193032a3SAndroid Build Coastguard Worker 			printf(" Gamma: is defined in an extension block");
1225*193032a3SAndroid Build Coastguard Worker 		else
1226*193032a3SAndroid Build Coastguard Worker 			printf(" Gamma: %.2f", ((gamma + 100.0) / 100.0));
1227*193032a3SAndroid Build Coastguard Worker 		printf("\n");
1228*193032a3SAndroid Build Coastguard Worker 		if (x[10] == 0)
1229*193032a3SAndroid Build Coastguard Worker 			return;
1230*193032a3SAndroid Build Coastguard Worker 		w_x = (x[12] << 2) | ((x[11] >> 2) & 3);
1231*193032a3SAndroid Build Coastguard Worker 		w_y = (x[13] << 2) | (x[11] & 3);
1232*193032a3SAndroid Build Coastguard Worker 		gamma = x[14];
1233*193032a3SAndroid Build Coastguard Worker 		printf("      Index: %u White: 0.%04u, 0.%04u", x[10],
1234*193032a3SAndroid Build Coastguard Worker 		       (w_x * 10000) / 1024, (w_y * 10000) / 1024);
1235*193032a3SAndroid Build Coastguard Worker 		if (gamma == 0xff)
1236*193032a3SAndroid Build Coastguard Worker 			printf(" Gamma: is defined in an extension block");
1237*193032a3SAndroid Build Coastguard Worker 		else
1238*193032a3SAndroid Build Coastguard Worker 			printf(" Gamma: %.2f", ((gamma + 100.0) / 100.0));
1239*193032a3SAndroid Build Coastguard Worker 		printf("\n");
1240*193032a3SAndroid Build Coastguard Worker 		return;
1241*193032a3SAndroid Build Coastguard Worker 	}
1242*193032a3SAndroid Build Coastguard Worker 	case 0xfc:
1243*193032a3SAndroid Build Coastguard Worker 		data_block = "Display Product Name";
1244*193032a3SAndroid Build Coastguard Worker 		base.has_name_descriptor = 1;
1245*193032a3SAndroid Build Coastguard Worker 		printf("    %s: '%s'\n", data_block.c_str(), extract_string(x + 5, 13));
1246*193032a3SAndroid Build Coastguard Worker 		return;
1247*193032a3SAndroid Build Coastguard Worker 	case 0xfd:
1248*193032a3SAndroid Build Coastguard Worker 		detailed_display_range_limits(x);
1249*193032a3SAndroid Build Coastguard Worker 		return;
1250*193032a3SAndroid Build Coastguard Worker 	case 0xfe:
1251*193032a3SAndroid Build Coastguard Worker 		if (!base.has_spwg || base.detailed_block_cnt < 3) {
1252*193032a3SAndroid Build Coastguard Worker 			data_block = "Alphanumeric Data String";
1253*193032a3SAndroid Build Coastguard Worker 			printf("    %s: '%s'\n", data_block.c_str(),
1254*193032a3SAndroid Build Coastguard Worker 			       extract_string(x + 5, 13));
1255*193032a3SAndroid Build Coastguard Worker 			return;
1256*193032a3SAndroid Build Coastguard Worker 		}
1257*193032a3SAndroid Build Coastguard Worker 		if (base.detailed_block_cnt == 3) {
1258*193032a3SAndroid Build Coastguard Worker 			char buf[6] = { 0 };
1259*193032a3SAndroid Build Coastguard Worker 
1260*193032a3SAndroid Build Coastguard Worker 			data_block = "SPWG Descriptor #3";
1261*193032a3SAndroid Build Coastguard Worker 			printf("    %s:\n", data_block.c_str());
1262*193032a3SAndroid Build Coastguard Worker 			memcpy(buf, x + 5, 5);
1263*193032a3SAndroid Build Coastguard Worker 			if (strlen(buf) != 5)
1264*193032a3SAndroid Build Coastguard Worker 				fail("Invalid PC Maker P/N length.\n");
1265*193032a3SAndroid Build Coastguard Worker 			printf("      SPWG PC Maker P/N: '%s'\n", buf);
1266*193032a3SAndroid Build Coastguard Worker 			printf("      SPWG LCD Supplier EEDID Revision: %hhu\n", x[10]);
1267*193032a3SAndroid Build Coastguard Worker 			printf("      SPWG Manufacturer P/N: '%s'\n", extract_string(x + 11, 7));
1268*193032a3SAndroid Build Coastguard Worker 		} else {
1269*193032a3SAndroid Build Coastguard Worker 			data_block = "SPWG Descriptor #4";
1270*193032a3SAndroid Build Coastguard Worker 			printf("    %s:\n", data_block.c_str());
1271*193032a3SAndroid Build Coastguard Worker 			printf("      SMBUS Values: 0x%02hhx 0x%02hhx 0x%02hhx 0x%02hhx"
1272*193032a3SAndroid Build Coastguard Worker 			       " 0x%02hhx 0x%02hhx 0x%02hhx 0x%02hhx\n",
1273*193032a3SAndroid Build Coastguard Worker 			       x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12]);
1274*193032a3SAndroid Build Coastguard Worker 			printf("      LVDS Channels: %hhu\n", x[13]);
1275*193032a3SAndroid Build Coastguard Worker 			printf("      Panel Self Test %sPresent\n", x[14] ? "" : "Not ");
1276*193032a3SAndroid Build Coastguard Worker 			if (x[15] != 0x0a || x[16] != 0x20 || x[17] != 0x20)
1277*193032a3SAndroid Build Coastguard Worker 				fail("Invalid trailing data.\n");
1278*193032a3SAndroid Build Coastguard Worker 		}
1279*193032a3SAndroid Build Coastguard Worker 		return;
1280*193032a3SAndroid Build Coastguard Worker 	case 0xff: {
1281*193032a3SAndroid Build Coastguard Worker 		data_block = "Display Product Serial Number";
1282*193032a3SAndroid Build Coastguard Worker 		char *sn = extract_string(x + 5, 13);
1283*193032a3SAndroid Build Coastguard Worker 		if (hide_serial_numbers)
1284*193032a3SAndroid Build Coastguard Worker 			printf("    %s: ...\n", data_block.c_str());
1285*193032a3SAndroid Build Coastguard Worker 		else
1286*193032a3SAndroid Build Coastguard Worker 			printf("    %s: '%s'\n", data_block.c_str(), sn);
1287*193032a3SAndroid Build Coastguard Worker 		base.has_serial_string = 1;
1288*193032a3SAndroid Build Coastguard Worker 		return;
1289*193032a3SAndroid Build Coastguard Worker 	}
1290*193032a3SAndroid Build Coastguard Worker 	default:
1291*193032a3SAndroid Build Coastguard Worker 		printf("    %s Display Descriptor (0x%02hhx):",
1292*193032a3SAndroid Build Coastguard Worker 		       x[3] <= 0x0f ? "Manufacturer-Specified" : "Unknown", x[3]);
1293*193032a3SAndroid Build Coastguard Worker 		hex_block(" ", x + 2, 16);
1294*193032a3SAndroid Build Coastguard Worker 		if (x[3] > 0x0f)
1295*193032a3SAndroid Build Coastguard Worker 			fail("Unknown Type 0x%02hhx.\n", x[3]);
1296*193032a3SAndroid Build Coastguard Worker 		return;
1297*193032a3SAndroid Build Coastguard Worker 	}
1298*193032a3SAndroid Build Coastguard Worker }
1299*193032a3SAndroid Build Coastguard Worker 
parse_base_block(const unsigned char * x)1300*193032a3SAndroid Build Coastguard Worker void edid_state::parse_base_block(const unsigned char *x)
1301*193032a3SAndroid Build Coastguard Worker {
1302*193032a3SAndroid Build Coastguard Worker 	time_t the_time;
1303*193032a3SAndroid Build Coastguard Worker 	struct tm *ptm;
1304*193032a3SAndroid Build Coastguard Worker 	int analog;
1305*193032a3SAndroid Build Coastguard Worker 	unsigned col_x, col_y;
1306*193032a3SAndroid Build Coastguard Worker 	bool has_preferred_timing = false;
1307*193032a3SAndroid Build Coastguard Worker 
1308*193032a3SAndroid Build Coastguard Worker 	data_block = "EDID Structure Version & Revision";
1309*193032a3SAndroid Build Coastguard Worker 	printf("  %s: %hhu.%hhu\n", data_block.c_str(), x[0x12], x[0x13]);
1310*193032a3SAndroid Build Coastguard Worker 	if (x[0x12] == 1) {
1311*193032a3SAndroid Build Coastguard Worker 		base.edid_minor = x[0x13];
1312*193032a3SAndroid Build Coastguard Worker 		if (base.edid_minor > 4)
1313*193032a3SAndroid Build Coastguard Worker 			warn("Unknown EDID minor version %u, assuming 1.4 conformance.\n", base.edid_minor);
1314*193032a3SAndroid Build Coastguard Worker 		if (base.edid_minor < 3)
1315*193032a3SAndroid Build Coastguard Worker 			warn("EDID 1.%u is deprecated, do not use.\n", base.edid_minor);
1316*193032a3SAndroid Build Coastguard Worker 	} else {
1317*193032a3SAndroid Build Coastguard Worker 		fail("Unknown EDID major version.\n");
1318*193032a3SAndroid Build Coastguard Worker 	}
1319*193032a3SAndroid Build Coastguard Worker 
1320*193032a3SAndroid Build Coastguard Worker 	data_block = "Vendor & Product Identification";
1321*193032a3SAndroid Build Coastguard Worker 	printf("  %s:\n", data_block.c_str());
1322*193032a3SAndroid Build Coastguard Worker 	printf("    Manufacturer: %s\n    Model: %u\n",
1323*193032a3SAndroid Build Coastguard Worker 	       manufacturer_name(x + 0x08),
1324*193032a3SAndroid Build Coastguard Worker 	       (unsigned short)(x[0x0a] + (x[0x0b] << 8)));
1325*193032a3SAndroid Build Coastguard Worker 	base.has_serial_number = x[0x0c] || x[0x0d] || x[0x0e] || x[0x0f];
1326*193032a3SAndroid Build Coastguard Worker 	if (base.has_serial_number) {
1327*193032a3SAndroid Build Coastguard Worker 		if (hide_serial_numbers)
1328*193032a3SAndroid Build Coastguard Worker 			printf("    Serial Number: ...\n");
1329*193032a3SAndroid Build Coastguard Worker 		else
1330*193032a3SAndroid Build Coastguard Worker 			printf("    Serial Number: %u\n",
1331*193032a3SAndroid Build Coastguard Worker 			       (unsigned)(x[0x0c] + (x[0x0d] << 8) +
1332*193032a3SAndroid Build Coastguard Worker 					  (x[0x0e] << 16) + (x[0x0f] << 24)));
1333*193032a3SAndroid Build Coastguard Worker 	}
1334*193032a3SAndroid Build Coastguard Worker 
1335*193032a3SAndroid Build Coastguard Worker 	time(&the_time);
1336*193032a3SAndroid Build Coastguard Worker 	ptm = localtime(&the_time);
1337*193032a3SAndroid Build Coastguard Worker 
1338*193032a3SAndroid Build Coastguard Worker 	unsigned char week = x[0x10];
1339*193032a3SAndroid Build Coastguard Worker 	int year = 1990 + x[0x11];
1340*193032a3SAndroid Build Coastguard Worker 
1341*193032a3SAndroid Build Coastguard Worker 	if (week) {
1342*193032a3SAndroid Build Coastguard Worker 		if (base.edid_minor <= 3 && week == 0xff)
1343*193032a3SAndroid Build Coastguard Worker 			fail("EDID 1.3 does not support week 0xff.\n");
1344*193032a3SAndroid Build Coastguard Worker 		// The max week is 53 in EDID 1.3 and 54 in EDID 1.4.
1345*193032a3SAndroid Build Coastguard Worker 		// No idea why there is a difference.
1346*193032a3SAndroid Build Coastguard Worker 		if (base.edid_minor <= 3 && week == 54)
1347*193032a3SAndroid Build Coastguard Worker 			fail("EDID 1.3 does not support week 54.\n");
1348*193032a3SAndroid Build Coastguard Worker 		if (week != 0xff && week > 54)
1349*193032a3SAndroid Build Coastguard Worker 			fail("Invalid week %u of manufacture.\n", week);
1350*193032a3SAndroid Build Coastguard Worker 		if (week != 0xff)
1351*193032a3SAndroid Build Coastguard Worker 			printf("    Made in: week %hhu of %d\n", week, year);
1352*193032a3SAndroid Build Coastguard Worker 	}
1353*193032a3SAndroid Build Coastguard Worker 	if (week == 0xff)
1354*193032a3SAndroid Build Coastguard Worker 		printf("    Model year: %d\n", year);
1355*193032a3SAndroid Build Coastguard Worker 	else if (!week)
1356*193032a3SAndroid Build Coastguard Worker 		printf("    Made in: %d\n", year);
1357*193032a3SAndroid Build Coastguard Worker 	if (year - 1 > ptm->tm_year + 1900)
1358*193032a3SAndroid Build Coastguard Worker 		fail("The year %d is more than one year in the future.\n", year);
1359*193032a3SAndroid Build Coastguard Worker 
1360*193032a3SAndroid Build Coastguard Worker 	/* display section */
1361*193032a3SAndroid Build Coastguard Worker 
1362*193032a3SAndroid Build Coastguard Worker 	data_block = "Basic Display Parameters & Features";
1363*193032a3SAndroid Build Coastguard Worker 	printf("  %s:\n", data_block.c_str());
1364*193032a3SAndroid Build Coastguard Worker 	if (x[0x14] & 0x80) {
1365*193032a3SAndroid Build Coastguard Worker 		analog = 0;
1366*193032a3SAndroid Build Coastguard Worker 		printf("    Digital display\n");
1367*193032a3SAndroid Build Coastguard Worker 		if (base.edid_minor >= 4) {
1368*193032a3SAndroid Build Coastguard Worker 			if ((x[0x14] & 0x70) == 0x00)
1369*193032a3SAndroid Build Coastguard Worker 				printf("    Color depth is undefined\n");
1370*193032a3SAndroid Build Coastguard Worker 			else if ((x[0x14] & 0x70) == 0x70)
1371*193032a3SAndroid Build Coastguard Worker 				fail("Color Bit Depth set to reserved value.\n");
1372*193032a3SAndroid Build Coastguard Worker 			else
1373*193032a3SAndroid Build Coastguard Worker 				printf("    Bits per primary color channel: %u\n",
1374*193032a3SAndroid Build Coastguard Worker 				       ((x[0x14] & 0x70) >> 3) + 4);
1375*193032a3SAndroid Build Coastguard Worker 
1376*193032a3SAndroid Build Coastguard Worker 			printf("    ");
1377*193032a3SAndroid Build Coastguard Worker 			switch (x[0x14] & 0x0f) {
1378*193032a3SAndroid Build Coastguard Worker 			case 0x00: printf("Digital interface is not defined\n"); break;
1379*193032a3SAndroid Build Coastguard Worker 			case 0x01: printf("DVI interface\n"); break;
1380*193032a3SAndroid Build Coastguard Worker 			case 0x02: printf("HDMI-a interface\n"); break;
1381*193032a3SAndroid Build Coastguard Worker 			case 0x03: printf("HDMI-b interface\n"); break;
1382*193032a3SAndroid Build Coastguard Worker 			case 0x04: printf("MDDI interface\n"); break;
1383*193032a3SAndroid Build Coastguard Worker 			case 0x05: printf("DisplayPort interface\n"); break;
1384*193032a3SAndroid Build Coastguard Worker 			default:
1385*193032a3SAndroid Build Coastguard Worker 				   printf("Unknown interface: 0x%02x\n", x[0x14] & 0x0f);
1386*193032a3SAndroid Build Coastguard Worker 				   fail("Digital Video Interface Standard set to reserved value 0x%02x.\n", x[0x14] & 0x0f);
1387*193032a3SAndroid Build Coastguard Worker 				   break;
1388*193032a3SAndroid Build Coastguard Worker 			}
1389*193032a3SAndroid Build Coastguard Worker 		} else if (base.edid_minor >= 2) {
1390*193032a3SAndroid Build Coastguard Worker 			if (x[0x14] & 0x01) {
1391*193032a3SAndroid Build Coastguard Worker 				printf("    DFP 1.x compatible TMDS\n");
1392*193032a3SAndroid Build Coastguard Worker 			}
1393*193032a3SAndroid Build Coastguard Worker 			if (x[0x14] & 0x7e)
1394*193032a3SAndroid Build Coastguard Worker 				fail("Digital Video Interface Standard set to reserved value 0x%02x.\n", x[0x14] & 0x7e);
1395*193032a3SAndroid Build Coastguard Worker 		} else if (x[0x14] & 0x7f) {
1396*193032a3SAndroid Build Coastguard Worker 			fail("Digital Video Interface Standard set to reserved value 0x%02x.\n", x[0x14] & 0x7f);
1397*193032a3SAndroid Build Coastguard Worker 		}
1398*193032a3SAndroid Build Coastguard Worker 	} else {
1399*193032a3SAndroid Build Coastguard Worker 		unsigned voltage = (x[0x14] & 0x60) >> 5;
1400*193032a3SAndroid Build Coastguard Worker 		unsigned sync = (x[0x14] & 0x0f);
1401*193032a3SAndroid Build Coastguard Worker 
1402*193032a3SAndroid Build Coastguard Worker 		analog = 1;
1403*193032a3SAndroid Build Coastguard Worker 		printf("    Analog display\n");
1404*193032a3SAndroid Build Coastguard Worker 		printf("    Input voltage level: %s V\n",
1405*193032a3SAndroid Build Coastguard Worker 		       voltage == 3 ? "0.7/0.7" :
1406*193032a3SAndroid Build Coastguard Worker 		       voltage == 2 ? "1.0/0.4" :
1407*193032a3SAndroid Build Coastguard Worker 		       voltage == 1 ? "0.714/0.286" :
1408*193032a3SAndroid Build Coastguard Worker 		       "0.7/0.3");
1409*193032a3SAndroid Build Coastguard Worker 
1410*193032a3SAndroid Build Coastguard Worker 		if (x[0x14] & 0x10)
1411*193032a3SAndroid Build Coastguard Worker 			printf("    Blank-to-black setup/pedestal\n");
1412*193032a3SAndroid Build Coastguard Worker 		else
1413*193032a3SAndroid Build Coastguard Worker 			printf("    Blank level equals black level\n");
1414*193032a3SAndroid Build Coastguard Worker 
1415*193032a3SAndroid Build Coastguard Worker 		if (sync)
1416*193032a3SAndroid Build Coastguard Worker 			printf("    Sync:%s%s%s%s\n",
1417*193032a3SAndroid Build Coastguard Worker 			       sync & 0x08 ? " Separate" : "",
1418*193032a3SAndroid Build Coastguard Worker 			       sync & 0x04 ? " Composite" : "",
1419*193032a3SAndroid Build Coastguard Worker 			       sync & 0x02 ? " SyncOnGreen" : "",
1420*193032a3SAndroid Build Coastguard Worker 			       sync & 0x01 ? " Serration" : "");
1421*193032a3SAndroid Build Coastguard Worker 	}
1422*193032a3SAndroid Build Coastguard Worker 
1423*193032a3SAndroid Build Coastguard Worker 	if (x[0x15] && x[0x16]) {
1424*193032a3SAndroid Build Coastguard Worker 		printf("    Maximum image size: %u cm x %u cm\n", x[0x15], x[0x16]);
1425*193032a3SAndroid Build Coastguard Worker 		base.max_display_width_mm = x[0x15] * 10;
1426*193032a3SAndroid Build Coastguard Worker 		base.max_display_height_mm = x[0x16] * 10;
1427*193032a3SAndroid Build Coastguard Worker 		if (x[0x15] < 10 || x[0x16] < 10)
1428*193032a3SAndroid Build Coastguard Worker 			warn("Dubious maximum image size (%ux%u is smaller than 10x10 cm).\n",
1429*193032a3SAndroid Build Coastguard Worker 			     x[0x15], x[0x16]);
1430*193032a3SAndroid Build Coastguard Worker 	}
1431*193032a3SAndroid Build Coastguard Worker 	else if (base.edid_minor >= 4 && (x[0x15] || x[0x16])) {
1432*193032a3SAndroid Build Coastguard Worker 		if (x[0x15])
1433*193032a3SAndroid Build Coastguard Worker 			printf("    Aspect ratio: %.2f (landscape)\n", (x[0x15] + 99) / 100.0);
1434*193032a3SAndroid Build Coastguard Worker 		else
1435*193032a3SAndroid Build Coastguard Worker 			printf("    Aspect ratio: %.2f (portrait)\n", 100.0 / (x[0x16] + 99));
1436*193032a3SAndroid Build Coastguard Worker 	} else {
1437*193032a3SAndroid Build Coastguard Worker 		/* Either or both can be zero for 1.3 and before */
1438*193032a3SAndroid Build Coastguard Worker 		printf("    Image size is variable\n");
1439*193032a3SAndroid Build Coastguard Worker 	}
1440*193032a3SAndroid Build Coastguard Worker 
1441*193032a3SAndroid Build Coastguard Worker 	if (x[0x17] == 0xff)
1442*193032a3SAndroid Build Coastguard Worker 		printf("    Gamma is defined in an extension block\n");
1443*193032a3SAndroid Build Coastguard Worker 	else
1444*193032a3SAndroid Build Coastguard Worker 		printf("    Gamma: %.2f\n", ((x[0x17] + 100.0) / 100.0));
1445*193032a3SAndroid Build Coastguard Worker 
1446*193032a3SAndroid Build Coastguard Worker 	if (x[0x18] & 0xe0) {
1447*193032a3SAndroid Build Coastguard Worker 		printf("    DPMS levels:");
1448*193032a3SAndroid Build Coastguard Worker 		if (x[0x18] & 0x80) printf(" Standby");
1449*193032a3SAndroid Build Coastguard Worker 		if (x[0x18] & 0x40) printf(" Suspend");
1450*193032a3SAndroid Build Coastguard Worker 		if (x[0x18] & 0x20) printf(" Off");
1451*193032a3SAndroid Build Coastguard Worker 		printf("\n");
1452*193032a3SAndroid Build Coastguard Worker 	}
1453*193032a3SAndroid Build Coastguard Worker 
1454*193032a3SAndroid Build Coastguard Worker 	if (analog || base.edid_minor < 4) {
1455*193032a3SAndroid Build Coastguard Worker 		printf("    ");
1456*193032a3SAndroid Build Coastguard Worker 		switch (x[0x18] & 0x18) {
1457*193032a3SAndroid Build Coastguard Worker 		case 0x00: printf("Monochrome or grayscale display\n"); break;
1458*193032a3SAndroid Build Coastguard Worker 		case 0x08: printf("RGB color display\n"); break;
1459*193032a3SAndroid Build Coastguard Worker 		case 0x10: printf("Non-RGB color display\n"); break;
1460*193032a3SAndroid Build Coastguard Worker 		case 0x18: printf("Undefined display color type\n");
1461*193032a3SAndroid Build Coastguard Worker 		}
1462*193032a3SAndroid Build Coastguard Worker 	} else {
1463*193032a3SAndroid Build Coastguard Worker 		printf("    Supported color formats: RGB 4:4:4");
1464*193032a3SAndroid Build Coastguard Worker 		if (x[0x18] & 0x08)
1465*193032a3SAndroid Build Coastguard Worker 			printf(", YCrCb 4:4:4");
1466*193032a3SAndroid Build Coastguard Worker 		if (x[0x18] & 0x10)
1467*193032a3SAndroid Build Coastguard Worker 			printf(", YCrCb 4:2:2");
1468*193032a3SAndroid Build Coastguard Worker 		printf("\n");
1469*193032a3SAndroid Build Coastguard Worker 	}
1470*193032a3SAndroid Build Coastguard Worker 
1471*193032a3SAndroid Build Coastguard Worker 	if (x[0x18] & 0x04) {
1472*193032a3SAndroid Build Coastguard Worker 		/*
1473*193032a3SAndroid Build Coastguard Worker 		 * The sRGB chromaticities are (x, y):
1474*193032a3SAndroid Build Coastguard Worker 		 * red:   0.640,  0.330
1475*193032a3SAndroid Build Coastguard Worker 		 * green: 0.300,  0.600
1476*193032a3SAndroid Build Coastguard Worker 		 * blue:  0.150,  0.060
1477*193032a3SAndroid Build Coastguard Worker 		 * white: 0.3127, 0.3290
1478*193032a3SAndroid Build Coastguard Worker 		 */
1479*193032a3SAndroid Build Coastguard Worker 		static const unsigned char srgb_chromaticity[10] = {
1480*193032a3SAndroid Build Coastguard Worker 			0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, 0x0f, 0x50, 0x54
1481*193032a3SAndroid Build Coastguard Worker 		};
1482*193032a3SAndroid Build Coastguard Worker 		printf("    Default (sRGB) color space is primary color space\n");
1483*193032a3SAndroid Build Coastguard Worker 		if (memcmp(x + 0x19, srgb_chromaticity, sizeof(srgb_chromaticity)))
1484*193032a3SAndroid Build Coastguard Worker 			fail("sRGB is signaled, but the chromaticities do not match.\n");
1485*193032a3SAndroid Build Coastguard Worker 	}
1486*193032a3SAndroid Build Coastguard Worker 	if (base.edid_minor >= 4) {
1487*193032a3SAndroid Build Coastguard Worker 		/* 1.4 always has a preferred timing and this bit means something else. */
1488*193032a3SAndroid Build Coastguard Worker 		has_preferred_timing = true;
1489*193032a3SAndroid Build Coastguard Worker 		base.preferred_is_also_native = x[0x18] & 0x02;
1490*193032a3SAndroid Build Coastguard Worker 		printf("    First detailed timing %s the native pixel format and preferred refresh rate\n",
1491*193032a3SAndroid Build Coastguard Worker 		       base.preferred_is_also_native ? "includes" : "does not include");
1492*193032a3SAndroid Build Coastguard Worker 	} else {
1493*193032a3SAndroid Build Coastguard Worker 		if (x[0x18] & 0x02) {
1494*193032a3SAndroid Build Coastguard Worker 			printf("    First detailed timing is the preferred timing\n");
1495*193032a3SAndroid Build Coastguard Worker 			has_preferred_timing = true;
1496*193032a3SAndroid Build Coastguard Worker 			// 1.3 recommends that the preferred timing corresponds to the
1497*193032a3SAndroid Build Coastguard Worker 			// native timing, but it is not a requirement.
1498*193032a3SAndroid Build Coastguard Worker 			// That said, we continue with the assumption that it actually
1499*193032a3SAndroid Build Coastguard Worker 			// is the native timing.
1500*193032a3SAndroid Build Coastguard Worker 			base.preferred_is_also_native = true;
1501*193032a3SAndroid Build Coastguard Worker 		} else if (base.edid_minor == 3) {
1502*193032a3SAndroid Build Coastguard Worker 			fail("EDID 1.3 requires that the first detailed timing is the preferred timing.\n");
1503*193032a3SAndroid Build Coastguard Worker 		}
1504*193032a3SAndroid Build Coastguard Worker 	}
1505*193032a3SAndroid Build Coastguard Worker 
1506*193032a3SAndroid Build Coastguard Worker 	if (x[0x18] & 0x01) {
1507*193032a3SAndroid Build Coastguard Worker 		if (base.edid_minor >= 4) {
1508*193032a3SAndroid Build Coastguard Worker 			base.supports_continuous_freq = true;
1509*193032a3SAndroid Build Coastguard Worker 			printf("    Display is continuous frequency\n");
1510*193032a3SAndroid Build Coastguard Worker 		} else {
1511*193032a3SAndroid Build Coastguard Worker 			printf("    Supports GTF timings within operating range\n");
1512*193032a3SAndroid Build Coastguard Worker 			base.supports_gtf = true;
1513*193032a3SAndroid Build Coastguard Worker 		}
1514*193032a3SAndroid Build Coastguard Worker 	}
1515*193032a3SAndroid Build Coastguard Worker 
1516*193032a3SAndroid Build Coastguard Worker 	data_block = "Color Characteristics";
1517*193032a3SAndroid Build Coastguard Worker 	printf("  %s:\n", data_block.c_str());
1518*193032a3SAndroid Build Coastguard Worker 	col_x = (x[0x1b] << 2) | (x[0x19] >> 6);
1519*193032a3SAndroid Build Coastguard Worker 	col_y = (x[0x1c] << 2) | ((x[0x19] >> 4) & 3);
1520*193032a3SAndroid Build Coastguard Worker 	printf("    Red  : 0.%04u, 0.%04u\n",
1521*193032a3SAndroid Build Coastguard Worker 	       (col_x * 10000) / 1024, (col_y * 10000) / 1024);
1522*193032a3SAndroid Build Coastguard Worker 	col_x = (x[0x1d] << 2) | ((x[0x19] >> 2) & 3);
1523*193032a3SAndroid Build Coastguard Worker 	col_y = (x[0x1e] << 2) | (x[0x19] & 3);
1524*193032a3SAndroid Build Coastguard Worker 	printf("    Green: 0.%04u, 0.%04u\n",
1525*193032a3SAndroid Build Coastguard Worker 	       (col_x * 10000) / 1024, (col_y * 10000) / 1024);
1526*193032a3SAndroid Build Coastguard Worker 	col_x = (x[0x1f] << 2) | (x[0x1a] >> 6);
1527*193032a3SAndroid Build Coastguard Worker 	col_y = (x[0x20] << 2) | ((x[0x1a] >> 4) & 3);
1528*193032a3SAndroid Build Coastguard Worker 	printf("    Blue : 0.%04u, 0.%04u\n",
1529*193032a3SAndroid Build Coastguard Worker 	       (col_x * 10000) / 1024, (col_y * 10000) / 1024);
1530*193032a3SAndroid Build Coastguard Worker 	col_x = (x[0x21] << 2) | ((x[0x1a] >> 2) & 3);
1531*193032a3SAndroid Build Coastguard Worker 	col_y = (x[0x22] << 2) | (x[0x1a] & 3);
1532*193032a3SAndroid Build Coastguard Worker 	printf("    White: 0.%04u, 0.%04u\n",
1533*193032a3SAndroid Build Coastguard Worker 	       (col_x * 10000) / 1024, (col_y * 10000) / 1024);
1534*193032a3SAndroid Build Coastguard Worker 
1535*193032a3SAndroid Build Coastguard Worker 	data_block = "Established Timings I & II";
1536*193032a3SAndroid Build Coastguard Worker 	if (x[0x23] || x[0x24] || x[0x25]) {
1537*193032a3SAndroid Build Coastguard Worker 		printf("  %s:\n", data_block.c_str());
1538*193032a3SAndroid Build Coastguard Worker 		for (unsigned i = 0; i < ARRAY_SIZE(established_timings12); i++) {
1539*193032a3SAndroid Build Coastguard Worker 			if (x[0x23 + i / 8] & (1 << (7 - i % 8))) {
1540*193032a3SAndroid Build Coastguard Worker 				unsigned char dmt_id = established_timings12[i].dmt_id;
1541*193032a3SAndroid Build Coastguard Worker 				const struct timings *t;
1542*193032a3SAndroid Build Coastguard Worker 				char type[16];
1543*193032a3SAndroid Build Coastguard Worker 
1544*193032a3SAndroid Build Coastguard Worker 				if (dmt_id) {
1545*193032a3SAndroid Build Coastguard Worker 					sprintf(type, "DMT 0x%02x", dmt_id);
1546*193032a3SAndroid Build Coastguard Worker 					t = find_dmt_id(dmt_id);
1547*193032a3SAndroid Build Coastguard Worker 				} else {
1548*193032a3SAndroid Build Coastguard Worker 					t = &established_timings12[i].t;
1549*193032a3SAndroid Build Coastguard Worker 					sprintf(type, "%-8s", established_timings12[i].type);
1550*193032a3SAndroid Build Coastguard Worker 				}
1551*193032a3SAndroid Build Coastguard Worker 				print_timings("    ", t, type);
1552*193032a3SAndroid Build Coastguard Worker 			}
1553*193032a3SAndroid Build Coastguard Worker 		}
1554*193032a3SAndroid Build Coastguard Worker 	} else {
1555*193032a3SAndroid Build Coastguard Worker 		printf("  %s: none\n", data_block.c_str());
1556*193032a3SAndroid Build Coastguard Worker 	}
1557*193032a3SAndroid Build Coastguard Worker 	base.has_640x480p60_est_timing = x[0x23] & 0x20;
1558*193032a3SAndroid Build Coastguard Worker 
1559*193032a3SAndroid Build Coastguard Worker 	/*
1560*193032a3SAndroid Build Coastguard Worker 	 * Need to find the Display Range Limit info before reading
1561*193032a3SAndroid Build Coastguard Worker 	 * the standard timings.
1562*193032a3SAndroid Build Coastguard Worker 	 */
1563*193032a3SAndroid Build Coastguard Worker 	preparse_detailed_block(x + 0x36);
1564*193032a3SAndroid Build Coastguard Worker 	preparse_detailed_block(x + 0x48);
1565*193032a3SAndroid Build Coastguard Worker 	preparse_detailed_block(x + 0x5a);
1566*193032a3SAndroid Build Coastguard Worker 	preparse_detailed_block(x + 0x6c);
1567*193032a3SAndroid Build Coastguard Worker 
1568*193032a3SAndroid Build Coastguard Worker 	data_block = "Standard Timings";
1569*193032a3SAndroid Build Coastguard Worker 	bool found = false;
1570*193032a3SAndroid Build Coastguard Worker 	for (unsigned i = 0; i < 8; i++) {
1571*193032a3SAndroid Build Coastguard Worker 		if (x[0x26 + i * 2] != 0x01 || x[0x26 + i * 2 + 1] != 0x01) {
1572*193032a3SAndroid Build Coastguard Worker 			found = true;
1573*193032a3SAndroid Build Coastguard Worker 			break;
1574*193032a3SAndroid Build Coastguard Worker 		}
1575*193032a3SAndroid Build Coastguard Worker 	}
1576*193032a3SAndroid Build Coastguard Worker 	if (found) {
1577*193032a3SAndroid Build Coastguard Worker 		printf("  %s:\n", data_block.c_str());
1578*193032a3SAndroid Build Coastguard Worker 		for (unsigned i = 0; i < 8; i++)
1579*193032a3SAndroid Build Coastguard Worker 			print_standard_timing("    ", x[0x26 + i * 2], x[0x26 + i * 2 + 1]);
1580*193032a3SAndroid Build Coastguard Worker 	} else {
1581*193032a3SAndroid Build Coastguard Worker 		printf("  %s: none\n", data_block.c_str());
1582*193032a3SAndroid Build Coastguard Worker 	}
1583*193032a3SAndroid Build Coastguard Worker 
1584*193032a3SAndroid Build Coastguard Worker 	/* 18 byte descriptors */
1585*193032a3SAndroid Build Coastguard Worker 	if (has_preferred_timing && !x[0x36] && !x[0x37])
1586*193032a3SAndroid Build Coastguard Worker 		fail("Missing preferred timing.\n");
1587*193032a3SAndroid Build Coastguard Worker 
1588*193032a3SAndroid Build Coastguard Worker 	/* Look for SPWG Noteboook Panel EDID data blocks */
1589*193032a3SAndroid Build Coastguard Worker 	if ((x[0x36] || x[0x37]) &&
1590*193032a3SAndroid Build Coastguard Worker 	    (x[0x48] || x[0x49]) &&
1591*193032a3SAndroid Build Coastguard Worker 	    !x[0x5a] && !x[0x5b] && x[0x5d] == 0xfe &&
1592*193032a3SAndroid Build Coastguard Worker 	    !x[0x6c] && !x[0x6d] && x[0x6f] == 0xfe &&
1593*193032a3SAndroid Build Coastguard Worker 	    (x[0x79] == 1 || x[0x79] == 2) && x[0x7a] <= 1)
1594*193032a3SAndroid Build Coastguard Worker 		base.has_spwg = true;
1595*193032a3SAndroid Build Coastguard Worker 
1596*193032a3SAndroid Build Coastguard Worker 	for (unsigned i = 0; i < (base.has_spwg ? 2 : 4); i++)
1597*193032a3SAndroid Build Coastguard Worker 		if (x[0x36 + i * 18] || x[0x37 + i * 18])
1598*193032a3SAndroid Build Coastguard Worker 			cta.preparsed_total_dtds++;
1599*193032a3SAndroid Build Coastguard Worker 
1600*193032a3SAndroid Build Coastguard Worker 	data_block = "Detailed Timing Descriptors";
1601*193032a3SAndroid Build Coastguard Worker 	printf("  %s:\n", data_block.c_str());
1602*193032a3SAndroid Build Coastguard Worker 	detailed_block(x + 0x36);
1603*193032a3SAndroid Build Coastguard Worker 	detailed_block(x + 0x48);
1604*193032a3SAndroid Build Coastguard Worker 	detailed_block(x + 0x5a);
1605*193032a3SAndroid Build Coastguard Worker 	detailed_block(x + 0x6c);
1606*193032a3SAndroid Build Coastguard Worker 	base.has_spwg = false;
1607*193032a3SAndroid Build Coastguard Worker 	if (!base.preferred_is_also_native) {
1608*193032a3SAndroid Build Coastguard Worker 		cta.native_timings.clear();
1609*193032a3SAndroid Build Coastguard Worker 		base.preferred_timing = timings_ext();
1610*193032a3SAndroid Build Coastguard Worker 	}
1611*193032a3SAndroid Build Coastguard Worker 
1612*193032a3SAndroid Build Coastguard Worker 	data_block = block;
1613*193032a3SAndroid Build Coastguard Worker 	if (x[0x7e])
1614*193032a3SAndroid Build Coastguard Worker 		printf("  Extension blocks: %u\n", x[0x7e]);
1615*193032a3SAndroid Build Coastguard Worker 	if (x[0x7e] + 1U != num_blocks)
1616*193032a3SAndroid Build Coastguard Worker 		fail("EDID specified %u extension block(s), but found %u extension block(s).\n",
1617*193032a3SAndroid Build Coastguard Worker 		     x[0x7e], num_blocks - 1);
1618*193032a3SAndroid Build Coastguard Worker 
1619*193032a3SAndroid Build Coastguard Worker 	block = block_name(0x00);
1620*193032a3SAndroid Build Coastguard Worker 	data_block.clear();
1621*193032a3SAndroid Build Coastguard Worker 	do_checksum("", x, EDID_PAGE_SIZE);
1622*193032a3SAndroid Build Coastguard Worker 	if (base.edid_minor >= 3) {
1623*193032a3SAndroid Build Coastguard Worker 		if (!base.has_name_descriptor)
1624*193032a3SAndroid Build Coastguard Worker 			fail("Missing Display Product Name.\n");
1625*193032a3SAndroid Build Coastguard Worker 		if ((base.edid_minor == 3 || base.supports_continuous_freq) &&
1626*193032a3SAndroid Build Coastguard Worker 		    !base.has_display_range_descriptor)
1627*193032a3SAndroid Build Coastguard Worker 			fail("Missing Display Range Limits Descriptor.\n");
1628*193032a3SAndroid Build Coastguard Worker 	}
1629*193032a3SAndroid Build Coastguard Worker }
1630*193032a3SAndroid Build Coastguard Worker 
check_base_block()1631*193032a3SAndroid Build Coastguard Worker void edid_state::check_base_block()
1632*193032a3SAndroid Build Coastguard Worker {
1633*193032a3SAndroid Build Coastguard Worker 	data_block = "Base EDID";
1634*193032a3SAndroid Build Coastguard Worker 
1635*193032a3SAndroid Build Coastguard Worker 	/*
1636*193032a3SAndroid Build Coastguard Worker 	 * Allow for regular rounding of vertical and horizontal frequencies.
1637*193032a3SAndroid Build Coastguard Worker 	 * The spec says that the pixelclock shall be rounded up, so there is
1638*193032a3SAndroid Build Coastguard Worker 	 * no need to take rounding into account.
1639*193032a3SAndroid Build Coastguard Worker 	 */
1640*193032a3SAndroid Build Coastguard Worker 	if (base.has_display_range_descriptor &&
1641*193032a3SAndroid Build Coastguard Worker 	    (min_vert_freq_hz + 0.5 < base.min_display_vert_freq_hz ||
1642*193032a3SAndroid Build Coastguard Worker 	     (max_vert_freq_hz >= base.max_display_vert_freq_hz + 0.5 && base.max_display_vert_freq_hz) ||
1643*193032a3SAndroid Build Coastguard Worker 	     min_hor_freq_hz + 500 < base.min_display_hor_freq_hz ||
1644*193032a3SAndroid Build Coastguard Worker 	     (max_hor_freq_hz >= base.max_display_hor_freq_hz + 500 && base.max_display_hor_freq_hz) ||
1645*193032a3SAndroid Build Coastguard Worker 	     (max_pixclk_khz > base.max_display_pixclk_khz && base.max_display_pixclk_khz))) {
1646*193032a3SAndroid Build Coastguard Worker 		/*
1647*193032a3SAndroid Build Coastguard Worker 		 * Check if it is really out of range, or if it could be a rounding error.
1648*193032a3SAndroid Build Coastguard Worker 		 * The EDID spec is not very clear about rounding.
1649*193032a3SAndroid Build Coastguard Worker 		 */
1650*193032a3SAndroid Build Coastguard Worker 		bool out_of_range =
1651*193032a3SAndroid Build Coastguard Worker 			min_vert_freq_hz + 1.0 <= base.min_display_vert_freq_hz ||
1652*193032a3SAndroid Build Coastguard Worker 			(max_vert_freq_hz >= base.max_display_vert_freq_hz + 1.0 && base.max_display_vert_freq_hz) ||
1653*193032a3SAndroid Build Coastguard Worker 			min_hor_freq_hz + 1000 <= base.min_display_hor_freq_hz ||
1654*193032a3SAndroid Build Coastguard Worker 			(max_hor_freq_hz >= base.max_display_hor_freq_hz + 1000 && base.max_display_hor_freq_hz) ||
1655*193032a3SAndroid Build Coastguard Worker 			(max_pixclk_khz >= base.max_display_pixclk_khz + 10000 && base.max_display_pixclk_khz);
1656*193032a3SAndroid Build Coastguard Worker 
1657*193032a3SAndroid Build Coastguard Worker 		std::string err("Some timings are out of range of the Monitor Ranges:\n");
1658*193032a3SAndroid Build Coastguard Worker 		char buf[512];
1659*193032a3SAndroid Build Coastguard Worker 
1660*193032a3SAndroid Build Coastguard Worker 		if (min_vert_freq_hz + 0.5 < base.min_display_vert_freq_hz ||
1661*193032a3SAndroid Build Coastguard Worker 		    (max_vert_freq_hz >= base.max_display_vert_freq_hz + 0.5 && base.max_display_vert_freq_hz)) {
1662*193032a3SAndroid Build Coastguard Worker 			sprintf(buf, "    Vertical Freq: %.3f - %.3f Hz (Monitor: %u.000 - %u.000 Hz)\n",
1663*193032a3SAndroid Build Coastguard Worker 				min_vert_freq_hz, max_vert_freq_hz,
1664*193032a3SAndroid Build Coastguard Worker 				base.min_display_vert_freq_hz, base.max_display_vert_freq_hz);
1665*193032a3SAndroid Build Coastguard Worker 			err += buf;
1666*193032a3SAndroid Build Coastguard Worker 		}
1667*193032a3SAndroid Build Coastguard Worker 
1668*193032a3SAndroid Build Coastguard Worker 		if (min_hor_freq_hz + 500 < base.min_display_hor_freq_hz ||
1669*193032a3SAndroid Build Coastguard Worker 		    (max_hor_freq_hz >= base.max_display_hor_freq_hz + 500 && base.max_display_hor_freq_hz)) {
1670*193032a3SAndroid Build Coastguard Worker 			sprintf(buf, "    Horizontal Freq: %.3f - %.3f kHz (Monitor: %.3f - %.3f kHz)\n",
1671*193032a3SAndroid Build Coastguard Worker 				min_hor_freq_hz / 1000.0, max_hor_freq_hz / 1000.0,
1672*193032a3SAndroid Build Coastguard Worker 				base.min_display_hor_freq_hz / 1000.0, base.max_display_hor_freq_hz / 1000.0);
1673*193032a3SAndroid Build Coastguard Worker 			err += buf;
1674*193032a3SAndroid Build Coastguard Worker 		}
1675*193032a3SAndroid Build Coastguard Worker 
1676*193032a3SAndroid Build Coastguard Worker 		if (max_pixclk_khz >= base.max_display_pixclk_khz && base.max_display_pixclk_khz) {
1677*193032a3SAndroid Build Coastguard Worker 			sprintf(buf, "    Maximum Clock: %.3f MHz (Monitor: %.3f MHz)\n",
1678*193032a3SAndroid Build Coastguard Worker 				max_pixclk_khz / 1000.0, base.max_display_pixclk_khz / 1000.0);
1679*193032a3SAndroid Build Coastguard Worker 			err += buf;
1680*193032a3SAndroid Build Coastguard Worker 		}
1681*193032a3SAndroid Build Coastguard Worker 
1682*193032a3SAndroid Build Coastguard Worker 		if (!out_of_range)
1683*193032a3SAndroid Build Coastguard Worker 			err += "    Could be due to a Monitor Range off-by-one rounding issue\n";
1684*193032a3SAndroid Build Coastguard Worker 
1685*193032a3SAndroid Build Coastguard Worker 		/*
1686*193032a3SAndroid Build Coastguard Worker 		 * EDID 1.4 states (in an Errata) that explicitly defined
1687*193032a3SAndroid Build Coastguard Worker 		 * timings supersede the monitor range definition.
1688*193032a3SAndroid Build Coastguard Worker 		 */
1689*193032a3SAndroid Build Coastguard Worker 		msg(!out_of_range || base.edid_minor >= 4, "%s", err.c_str());
1690*193032a3SAndroid Build Coastguard Worker 	}
1691*193032a3SAndroid Build Coastguard Worker 	// The base block will only go up to 255x255 cm for the display size,
1692*193032a3SAndroid Build Coastguard Worker 	// so don't fail if one or more image sizes exceeds that.
1693*193032a3SAndroid Build Coastguard Worker 	if (!base.max_display_width_mm && !base.max_display_height_mm &&
1694*193032a3SAndroid Build Coastguard Worker 	    dtd_max_hsize_mm && dtd_max_vsize_mm &&
1695*193032a3SAndroid Build Coastguard Worker 	    dtd_max_hsize_mm <= 2559 && dtd_max_vsize_mm <= 2559) {
1696*193032a3SAndroid Build Coastguard Worker 		fail("The DTD image sizes all fit inside 255x255cm, but no display size was set.\n");
1697*193032a3SAndroid Build Coastguard Worker 	}
1698*193032a3SAndroid Build Coastguard Worker 	// Secondary GTF curves start at a specific frequency. Any legacy timings
1699*193032a3SAndroid Build Coastguard Worker 	// that have a positive hsync and negative vsync must be less than that
1700*193032a3SAndroid Build Coastguard Worker 	// frequency to avoid confusion.
1701*193032a3SAndroid Build Coastguard Worker 	if (base.supports_sec_gtf && base.max_pos_neg_hor_freq_khz >= base.sec_gtf_start_freq)
1702*193032a3SAndroid Build Coastguard Worker 		fail("Second GTF start frequency %u is less than the highest P/N frequency %u.\n",
1703*193032a3SAndroid Build Coastguard Worker 		     base.sec_gtf_start_freq, base.max_pos_neg_hor_freq_khz);
1704*193032a3SAndroid Build Coastguard Worker 	if (base.edid_minor == 3 && num_blocks > 2 && !block_map.saw_block_1)
1705*193032a3SAndroid Build Coastguard Worker 		fail("EDID 1.3 requires a Block Map Extension in Block 1 if there are more than 2 blocks in the EDID.\n");
1706*193032a3SAndroid Build Coastguard Worker 	if (base.edid_minor == 3 && num_blocks > 128 && !block_map.saw_block_128)
1707*193032a3SAndroid Build Coastguard Worker 		fail("EDID 1.3 requires a Block Map Extension in Block 128 if there are more than 128 blocks in the EDID.\n");
1708*193032a3SAndroid Build Coastguard Worker 	if (block_map.saw_block_128 && num_blocks > 255)
1709*193032a3SAndroid Build Coastguard Worker 		fail("If there is a Block Map Extension in Block 128 then the maximum number of blocks is 255.\n");
1710*193032a3SAndroid Build Coastguard Worker }
1711