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