xref: /aosp_15_r20/external/edid-decode/edid-decode.h (revision 193032a37cc83cffc1526215991f3c21671f4245)
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright 2006-2012 Red Hat, Inc.
4  * Copyright 2018-2020 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
5  *
6  * Author: Adam Jackson <[email protected]>
7  * Maintainer: Hans Verkuil <[email protected]>
8  */
9 
10 #ifndef __EDID_DECODE_H_
11 #define __EDID_DECODE_H_
12 
13 #include <string>
14 #include <vector>
15 #include <set>
16 #include <string.h>
17 
18 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
19 #define min(a, b) ((a) < (b) ? (a) : (b))
20 #define max(a, b) ((a) > (b) ? (a) : (b))
21 
22 #define EDID_PAGE_SIZE 128U
23 #define EDID_MAX_BLOCKS 256U
24 
25 #define RB_ALT		(1U << 7)
26 
27 #define RB_NONE		(0U)
28 #define RB_CVT_V1	(1U)
29 #define RB_CVT_V2	(2U)
30 #define RB_CVT_V3	(3U)
31 #define RB_GTF		(4U)
32 
33 // Video Timings
34 // If interlaced is true, then the vertical blanking
35 // for each field is (vfp + vsync + vbp + 0.5), except for
36 // the VIC 39 timings that doesn't have the 0.5 constant.
37 //
38 // The sequence of the various video parameters is as follows:
39 //
40 // border - front porch - sync - back porch - border - active video
41 //
42 // Note: this is slightly different from EDID 1.4 which calls
43 // 'active video' as 'addressable video' and the EDID 1.4 term
44 // 'active video' includes the borders.
45 //
46 // But since borders are rarely used, the term 'active video' will
47 // typically be the same as 'addressable video', and that's how I
48 // use it.
49 struct timings {
50 	// Active horizontal and vertical frame height, excluding any
51 	// borders, if present.
52 	// Note: for interlaced formats the active field height is vact / 2
53 	unsigned hact, vact;
54 	unsigned hratio, vratio;
55 	unsigned pixclk_khz;
56 	// 0: no reduced blanking
57 	// 1: CVT reduced blanking version 1
58 	// 2: CVT reduced blanking version 2
59 	// 2 | RB_ALT: CVT reduced blanking version 2 video-optimized (1000/1001 fps)
60 	// 3: CVT reduced blanking version 3
61 	// 3 | RB_ALT: v3 with a horizontal blank of 160
62 	// 4: GTF Secondary Curve
63 	unsigned rb;
64 	bool interlaced;
65 	// The horizontal frontporch may be negative in GTF calculations,
66 	// so use int instead of unsigned for hfp. Example: 292x176@76.
67 	int hfp;
68 	unsigned hsync;
69 	// The backporch may be negative in buggy detailed timings.
70 	// So use int instead of unsigned for hbp and vbp.
71 	int hbp;
72 	bool pos_pol_hsync;
73 	// For interlaced formats the vertical front porch of the Even Field
74 	// is actually a half-line longer.
75 	unsigned vfp, vsync;
76 	// For interlaced formats the vertical back porch of the Odd Field
77 	// is actually a half-line longer.
78 	int vbp;
79 	bool pos_pol_vsync;
80 	unsigned hborder, vborder;
81 	bool even_vtotal; // special for VIC 39
82 	bool no_pol_vsync; // digital composite signals have no vsync polarity
83 	unsigned hsize_mm, vsize_mm;
84 	bool ycbcr420; // YCbCr 4:2:0 encoding
85 };
86 
87 struct timings_ext {
timings_exttimings_ext88 	timings_ext()
89 	{
90 		memset(&t, 0, sizeof(t));
91 	}
timings_exttimings_ext92 	timings_ext(unsigned svr, const std::string &_type)
93 	{
94 		memset(&t, 0, sizeof(t));
95 		t.hact = svr;
96 		type = _type;
97 	}
timings_exttimings_ext98 	timings_ext(const timings &_t, const std::string &_type, const std::string &_flags)
99 	{
100 		t = _t;
101 		type = _type;
102 		flags = _flags;
103 	}
104 
is_validtimings_ext105 	bool is_valid() const { return t.hact; }
has_svrtimings_ext106 	bool has_svr() const { return t.hact && !t.vact; }
svrtimings_ext107 	unsigned svr() const { return t.hact; }
108 	timings t;
109 	std::string type;
110 	std::string flags;
111 };
112 
113 enum gtf_ip_parm {
114 	gtf_ip_vert_freq = 1,
115 	gtf_ip_hor_freq,
116 	gtf_ip_clk_freq,
117 };
118 
119 typedef std::vector<timings_ext> vec_timings_ext;
120 
121 struct edid_state {
edid_stateedid_state122 	edid_state()
123 	{
124 		// Global state
125 		edid_size = num_blocks = block_nr = 0;
126 		max_hor_freq_hz = max_vert_freq_hz = max_pixclk_khz = 0;
127 		min_hor_freq_hz = 0xffffff;
128 		min_vert_freq_hz = 0xffffffff;
129 		dtd_max_vsize_mm = dtd_max_hsize_mm = 0;
130 		warnings = failures = 0;
131 		has_cta = has_dispid = false;
132 		hide_serial_numbers = false;
133 
134 		// Base block state
135 		base.edid_minor = 0;
136 		base.has_name_descriptor = base.has_display_range_descriptor =
137 			base.has_serial_number = base.has_serial_string =
138 			base.supports_continuous_freq = base.supports_gtf =
139 			base.supports_cvt = base.seen_non_detailed_descriptor =
140 			base.has_640x480p60_est_timing = base.has_spwg =
141 			base.preferred_is_also_native = false;
142 		base.supports_sec_gtf = false;
143 		base.sec_gtf_start_freq = 0;
144 		base.C = base.M = base.K = base.J = 0;
145 		base.max_pos_neg_hor_freq_khz = 0;
146 		base.detailed_block_cnt = base.dtd_cnt = 0;
147 
148 		base.min_display_hor_freq_hz = base.max_display_hor_freq_hz =
149 			base.min_display_vert_freq_hz = base.max_display_vert_freq_hz =
150 			base.max_display_pixclk_khz = base.max_display_width_mm =
151 			base.max_display_height_mm = 0;
152 
153 		// CTA-861 block state
154 		cta.has_vic_1 = cta.first_svd_might_be_preferred = cta.has_sldb =
155 			cta.has_hdmi = cta.has_vcdb = cta.has_vfpdb = false;
156 		cta.last_block_was_hdmi_vsdb = cta.have_hf_vsdb = cta.have_hf_scdb = false;
157 		cta.first_block = cta.first_svd = true;
158 		cta.supported_hdmi_vic_codes = cta.supported_hdmi_vic_vsb_codes = 0;
159 		memset(cta.vics, 0, sizeof(cta.vics));
160 		memset(cta.preparsed_has_vic, 0, sizeof(cta.preparsed_has_vic));
161 		cta.preparsed_phys_addr = 0xffff;
162 		cta.preparsed_speaker_count = 0;
163 		cta.preparsed_sld = false;
164 		cta.preparsed_sld_has_coord = false;
165 		cta.preparsed_total_dtds = 0;
166 		cta.preparsed_total_vtdbs = 0;
167 		cta.preparsed_has_t8vtdb = false;
168 
169 		// DisplayID block state
170 		dispid.version = 0;
171 		dispid.native_width = dispid.native_height = 0;
172 		dispid.preparsed_color_ids = dispid.preparsed_xfer_ids = 0;
173 		dispid.preparsed_displayid_blocks = 0;
174 		dispid.is_base_block = true;
175 		dispid.is_display = dispid.has_product_identification =
176 			dispid.has_display_parameters = dispid.has_type_1_7 =
177 			dispid.has_display_interface_features = false;
178 
179 		// Block Map block state
180 		block_map.saw_block_1 = false;
181 		block_map.saw_block_128 = false;
182 	}
183 
184 	// Global state
185 	unsigned edid_size;
186 	unsigned num_blocks;
187 	unsigned block_nr;
188 	std::string block;
189 	std::string data_block;
190 	bool has_cta;
191 	bool has_dispid;
192 	bool hide_serial_numbers;
193 
194 	unsigned min_hor_freq_hz;
195 	unsigned max_hor_freq_hz;
196 	double min_vert_freq_hz;
197 	double max_vert_freq_hz;
198 	unsigned max_pixclk_khz;
199 	unsigned dtd_max_hsize_mm;
200 	unsigned dtd_max_vsize_mm;
201 
202 	unsigned warnings;
203 	unsigned failures;
204 
205 	// Base block state
206 	struct {
207 		unsigned edid_minor;
208 		bool has_name_descriptor;
209 		bool has_display_range_descriptor;
210 		bool has_serial_number;
211 		bool has_serial_string;
212 		bool supports_continuous_freq;
213 		bool supports_gtf;
214 		bool supports_sec_gtf;
215 		unsigned sec_gtf_start_freq;
216 		double C, M, K, J;
217 		bool supports_cvt;
218 		bool has_spwg;
219 		unsigned detailed_block_cnt;
220 		unsigned dtd_cnt;
221 		bool seen_non_detailed_descriptor;
222 		bool has_640x480p60_est_timing;
223 		bool preferred_is_also_native;
224 		timings_ext preferred_timing;
225 
226 		unsigned min_display_hor_freq_hz;
227 		unsigned max_display_hor_freq_hz;
228 		unsigned min_display_vert_freq_hz;
229 		unsigned max_display_vert_freq_hz;
230 		unsigned max_display_pixclk_khz;
231 		unsigned max_display_width_mm;
232 		unsigned max_display_height_mm;
233 		unsigned max_pos_neg_hor_freq_khz;
234 	} base;
235 
236 	// CTA-861 block state
237 	struct {
238 		unsigned preparsed_total_dtds;
239 		vec_timings_ext vec_dtds;
240 		unsigned preparsed_total_vtdbs;
241 		vec_timings_ext vec_vtdbs;
242 		vec_timings_ext preferred_timings;
243 		bool preparsed_has_t8vtdb;
244 		// Keep track of the found Tag/Extended Tag pairs.
245 		// The unsigned value is equal to: (tag << 8) | ext_tag
246 		std::set<unsigned> found_tags;
247 		timings_ext t8vtdb;
248 		vec_timings_ext native_timings;
249 		bool has_vic_1;
250 		bool first_svd_might_be_preferred;
251 		unsigned char byte3;
252 		bool has_hdmi;
253 		bool has_vcdb;
254 		bool has_vfpdb;
255 		unsigned preparsed_speaker_count;
256 		bool preparsed_sld_has_coord;
257 		bool preparsed_sld;
258 		bool has_sldb;
259 		unsigned short preparsed_phys_addr;
260 		bool last_block_was_hdmi_vsdb;
261 		bool have_hf_vsdb, have_hf_scdb;
262 		bool first_block;
263 		bool first_svd;
264 		unsigned supported_hdmi_vic_codes;
265 		unsigned supported_hdmi_vic_vsb_codes;
266 		unsigned short vics[256][2];
267 		bool preparsed_has_vic[2][256];
268 		std::vector<unsigned char> preparsed_svds[2];
269 	} cta;
270 
271 	// DisplayID block state
272 	struct {
273 		unsigned char version;
274 		unsigned short preparsed_color_ids;
275 		unsigned short preparsed_xfer_ids;
276 		unsigned preparsed_displayid_blocks;
277 		bool is_base_block;
278 		bool is_display;
279 		bool has_product_identification;
280 		bool has_display_parameters;
281 		bool has_type_1_7;
282 		bool has_display_interface_features;
283 		vec_timings_ext preferred_timings;
284 		unsigned native_width, native_height;
285 		// Keep track of the found CTA-861 Tag/Extended Tag pairs.
286 		// The unsigned value is equal to: (tag << 8) | ext_tag
287 		std::set<unsigned> found_tags;
288 	} dispid;
289 
290 	// Block Map block state
291 	struct {
292 		bool saw_block_1;
293 		bool saw_block_128;
294 	} block_map;
295 
296 	std::string dtd_type(unsigned dtd);
dtd_typeedid_state297 	std::string dtd_type() { return dtd_type(base.dtd_cnt); }
298 	bool print_timings(const char *prefix, const struct timings *t,
299 			   const char *type, const char *flags = "",
300 			   bool detailed = false, bool do_checks = true);
301 	bool print_timings(const char *prefix, const struct timings_ext &t,
302 			   bool detailed = false, bool do_checks = true)
303 	{
304 		return print_timings(prefix, &t.t, t.type.c_str(), t.flags.c_str(),
305 				     detailed, do_checks);
306 	};
307 	bool match_timings(const timings &t1, const timings &t2);
308 	timings calc_gtf_mode(unsigned h_pixels, unsigned v_lines,
309 			      double ip_freq_rqd, bool int_rqd = false,
310 			      enum gtf_ip_parm ip_parm = gtf_ip_vert_freq,
311 			      bool margins_rqd = false, bool secondary = false,
312 			      double C = 40, double M = 600, double K = 128, double J = 20);
313 	void edid_gtf_mode(unsigned refresh, struct timings &t);
314 	timings calc_cvt_mode(unsigned h_pixels, unsigned v_lines,
315 			      double ip_freq_rqd, unsigned rb, bool int_rqd = false,
316 			      bool margins_rqd = false, bool alt = false,
317 			      unsigned rb_h_blank = 0);
318 	void edid_cvt_mode(unsigned refresh, struct timings &t);
319 	void detailed_cvt_descriptor(const char *prefix, const unsigned char *x, bool first);
320 	void print_standard_timing(const char *prefix, unsigned char b1, unsigned char b2,
321 				   bool gtf_only = false, bool show_both = false);
322 	void detailed_display_range_limits(const unsigned char *x);
323 	void detailed_epi(const unsigned char *x);
324 	void detailed_timings(const char *prefix, const unsigned char *x,
325 			      bool base_or_cta = true);
326 	void preparse_detailed_block(const unsigned char *x);
327 	void detailed_block(const unsigned char *x);
328 	void parse_base_block(const unsigned char *x);
329 	void check_base_block();
330 	void list_dmts();
331 	void list_established_timings();
332 
333 	void print_vic_index(const char *prefix, unsigned idx, const char *suffix, bool ycbcr420 = false);
334 	void hdmi_latency(unsigned char vid_lat, unsigned char aud_lat, bool is_ilaced);
335 	void cta_vcdb(const unsigned char *x, unsigned length);
336 	void cta_svd(const unsigned char *x, unsigned n, bool for_ycbcr420);
337 	void cta_y420cmdb(const unsigned char *x, unsigned length);
338 	void cta_vfpdb(const unsigned char *x, unsigned length);
339 	void cta_rcdb(const unsigned char *x, unsigned length);
340 	void cta_sldb(const unsigned char *x, unsigned length);
341 	void cta_preparse_sldb(const unsigned char *x, unsigned length);
342 	void cta_hdmi_block(const unsigned char *x, unsigned length);
343 	void cta_displayid_type_7(const unsigned char *x, unsigned length);
344 	void cta_displayid_type_8(const unsigned char *x, unsigned length);
345 	void cta_displayid_type_10(const unsigned char *x, unsigned length);
346 	void cta_ext_block(const unsigned char *x, unsigned length, bool duplicate);
347 	void cta_block(const unsigned char *x, bool duplicate);
348 	void preparse_cta_block(const unsigned char *x);
349 	void parse_cta_block(const unsigned char *x);
350 	void cta_resolve_svr(vec_timings_ext::iterator iter);
351 	void cta_resolve_svrs();
352 	void check_cta_blocks();
353 	void cta_list_vics();
354 	void cta_list_hdmi_vics();
355 
356 	void parse_digital_interface(const unsigned char *x);
357 	void parse_display_device(const unsigned char *x);
358 	void parse_display_caps(const unsigned char *x);
359 	void parse_display_xfer(const unsigned char *x);
360 	void parse_di_ext_block(const unsigned char *x);
361 
362 	void check_displayid_datablock_revision(unsigned char hdr,
363 						unsigned char valid_flags = 0,
364 						unsigned char rev = 0);
365 	void parse_displayid_product_id(const unsigned char *x);
366 	std::string product_type(unsigned char x, bool heading);
367 	void parse_displayid_interface_features(const unsigned char *x);
368 	void parse_displayid_parameters(const unsigned char *x);
369 	void parse_displayid_parameters_v2(const unsigned char *x, unsigned block_rev);
370 	void parse_displayid_display_intf(const unsigned char *x);
371 	void parse_displayid_color_characteristics(const unsigned char *x);
372 	void parse_displayid_transfer_characteristics(const unsigned char *x);
373 	void parse_displayid_stereo_display_intf(const unsigned char *x);
374 	void parse_displayid_type_1_7_timing(const unsigned char *x,
375 					     bool type7, unsigned block_rev, bool is_cta = false);
376 	void parse_displayid_type_2_timing(const unsigned char *x);
377 	void parse_displayid_type_3_timing(const unsigned char *x);
378 	void parse_displayid_type_4_8_timing(unsigned char type, unsigned short id, bool is_cta = false);
379 	void parse_displayid_video_timing_range_limits(const unsigned char *x);
380 	void parse_displayid_string(const unsigned char *x);
381 	void parse_displayid_display_device(const unsigned char *x);
382 	void parse_displayid_intf_power_sequencing(const unsigned char *x);
383 	void parse_displayid_type_5_timing(const unsigned char *x);
384 	void parse_displayid_tiled_display_topology(const unsigned char *x, bool is_v2);
385 	void parse_displayid_type_6_timing(const unsigned char *x);
386 	void parse_displayid_type_9_timing(const unsigned char *x);
387 	void parse_displayid_dynamic_video_timings_range_limits(const unsigned char *x);
388 	void parse_displayid_ContainerID(const unsigned char *x);
389 	void parse_displayid_type_10_timing(const unsigned char *x, bool is_cta = false);
390 	void preparse_displayid_block(const unsigned char *x);
391 	void parse_displayid_block(const unsigned char *x);
392 	void parse_displayid_vesa(const unsigned char *x);
393 	void parse_displayid_cta_data_block(const unsigned char *x);
394 	void check_displayid_blocks();
395 
396 	void parse_vtb_ext_block(const unsigned char *x);
397 
398 	void parse_string_table(const unsigned char *x);
399 	void parse_ls_ext_block(const unsigned char *x);
400 
401 	void parse_block_map(const unsigned char *x);
402 
403 	void preparse_extension(const unsigned char *x);
404 	void parse_extension(const unsigned char *x);
405 	int parse_edid();
406 };
407 
add_str(std::string & s,const std::string & add)408 static inline void add_str(std::string &s, const std::string &add)
409 {
410 	if (s.empty())
411 		s = add;
412 	else if (!add.empty())
413 		s = s + ", " + add;
414 }
415 
416 void msg(bool is_warn, const char *fmt, ...);
417 
418 #ifdef _WIN32
419 
420 #define warn(fmt, ...) msg(true, fmt, __VA_ARGS__)
421 #define warn_once(fmt, ...)				\
422 	do {						\
423 		static bool shown_warn;			\
424 		if (!shown_warn) {			\
425 			shown_warn = true;		\
426 			msg(true, fmt, __VA_ARGS__);	\
427 		}					\
428 	} while (0)
429 #define fail(fmt, ...) msg(false, fmt, __VA_ARGS__)
430 
431 #else
432 
433 #define warn(fmt, args...) msg(true, fmt, ##args)
434 #define warn_once(fmt, args...)				\
435 	do {						\
436 		static bool shown_warn;			\
437 		if (!shown_warn) {			\
438 			shown_warn = true;		\
439 			msg(true, fmt, ##args);		\
440 		}					\
441 	} while (0)
442 #define fail(fmt, args...) msg(false, fmt, ##args)
443 
444 #endif
445 
446 void do_checksum(const char *prefix, const unsigned char *x, size_t len);
447 std::string utohex(unsigned char x);
448 std::string ouitohex(unsigned oui);
449 std::string containerid2s(const unsigned char *x);
450 bool memchk(const unsigned char *x, unsigned len, unsigned char v = 0);
451 void hex_block(const char *prefix, const unsigned char *x, unsigned length,
452 	       bool show_ascii = true, unsigned step = 16);
453 std::string block_name(unsigned char block);
454 void calc_ratio(struct timings *t);
455 const char *oui_name(unsigned oui, bool reverse = false);
456 
457 bool timings_close_match(const timings &t1, const timings &t2);
458 const struct timings *find_dmt_id(unsigned char dmt_id);
459 const struct timings *close_match_to_dmt(const timings &t, unsigned &dmt);
460 const struct timings *find_vic_id(unsigned char vic);
461 const struct timings *find_hdmi_vic_id(unsigned char hdmi_vic);
462 const struct timings *cta_close_match_to_vic(const timings &t, unsigned &vic);
463 unsigned char hdmi_vic_to_vic(unsigned char hdmi_vic);
464 char *extract_string(const unsigned char *x, unsigned len);
465 
466 #endif
467