1 // SPDX-License-Identifier: MIT
3 * Copyright 2006-2012 Red Hat, Inc.
4 * Copyright 2018-2020 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
6 * Author: Adam Jackson <ajax@nwnk.net>
7 * Maintainer: Hans Verkuil <hverkuil-cisco@xs4all.nl>
14 #include "edid-decode.h"
16 static const struct timings edid_cta_modes1
[] = {
18 { 640, 480, 4, 3, 25175, 0, false, 16, 96, 48, false, 10, 2, 33, false },
19 { 720, 480, 4, 3, 27000, 0, false, 16, 62, 60, false, 9, 6, 30, false },
20 { 720, 480, 16, 9, 27000, 0, false, 16, 62, 60, false, 9, 6, 30, false },
21 { 1280, 720, 16, 9, 74250, 0, false, 110, 40, 220, true, 5, 5, 20, true },
22 { 1920, 1080, 16, 9, 74250, 0, true, 88, 44, 148, true, 2, 5, 15, true },
23 { 1440, 480, 4, 3, 27000, 0, true, 38, 124, 114, false, 4, 3, 15, false },
24 { 1440, 480, 16, 9, 27000, 0, true, 38, 124, 114, false, 4, 3, 15, false },
25 { 1440, 240, 4, 3, 27000, 0, false, 38, 124, 114, false, 4, 3, 15, false },
26 { 1440, 240, 16, 9, 27000, 0, false, 38, 124, 114, false, 4, 3, 15, false },
27 { 2880, 480, 4, 3, 54000, 0, true, 76, 248, 228, false, 4, 3, 15, false },
29 { 2880, 480, 16, 9, 54000, 0, true, 76, 248, 228, false, 4, 3, 15, false },
30 { 2880, 240, 4, 3, 54000, 0, false, 76, 248, 228, false, 4, 3, 15, false },
31 { 2880, 240, 16, 9, 54000, 0, false, 76, 248, 228, false, 4, 3, 15, false },
32 { 1440, 480, 4, 3, 54000, 0, false, 32, 124, 120, false, 9, 6, 30, false },
33 { 1440, 480, 16, 9, 54000, 0, false, 32, 124, 120, false, 9, 6, 30, false },
34 { 1920, 1080, 16, 9, 148500, 0, false, 88, 44, 148, true, 4, 5, 36, true },
35 { 720, 576, 4, 3, 27000, 0, false, 12, 64, 68, false, 5, 5, 39, false },
36 { 720, 576, 16, 9, 27000, 0, false, 12, 64, 68, false, 5, 5, 39, false },
37 { 1280, 720, 16, 9, 74250, 0, false, 440, 40, 220, true, 5, 5, 20, true },
38 { 1920, 1080, 16, 9, 74250, 0, true, 528, 44, 148, true, 2, 5, 15, true },
40 { 1440, 576, 4, 3, 27000, 0, true, 24, 126, 138, false, 2, 3, 19, false },
41 { 1440, 576, 16, 9, 27000, 0, true, 24, 126, 138, false, 2, 3, 19, false },
42 { 1440, 288, 4, 3, 27000, 0, false, 24, 126, 138, false, 2, 3, 19, false },
43 { 1440, 288, 16, 9, 27000, 0, false, 24, 126, 138, false, 2, 3, 19, false },
44 { 2880, 576, 4, 3, 54000, 0, true, 48, 252, 276, false, 2, 3, 19, false },
45 { 2880, 576, 16, 9, 54000, 0, true, 48, 252, 276, false, 2, 3, 19, false },
46 { 2880, 288, 4, 3, 54000, 0, false, 48, 252, 276, false, 2, 3, 19, false },
47 { 2880, 288, 16, 9, 54000, 0, false, 48, 252, 276, false, 2, 3, 19, false },
48 { 1440, 576, 4, 3, 54000, 0, false, 24, 128, 136, false, 5, 5, 39, false },
49 { 1440, 576, 16, 9, 54000, 0, false, 24, 128, 136, false, 5, 5, 39, false },
51 { 1920, 1080, 16, 9, 148500, 0, false, 528, 44, 148, true, 4, 5, 36, true },
52 { 1920, 1080, 16, 9, 74250, 0, false, 638, 44, 148, true, 4, 5, 36, true },
53 { 1920, 1080, 16, 9, 74250, 0, false, 528, 44, 148, true, 4, 5, 36, true },
54 { 1920, 1080, 16, 9, 74250, 0, false, 88, 44, 148, true, 4, 5, 36, true },
55 { 2880, 480, 4, 3, 108000, 0, false, 64, 248, 240, false, 9, 6, 30, false },
56 { 2880, 480, 16, 9, 108000, 0, false, 64, 248, 240, false, 9, 6, 30, false },
57 { 2880, 576, 4, 3, 108000, 0, false, 48, 256, 272, false, 5, 5, 39, false },
58 { 2880, 576, 16, 9, 108000, 0, false, 48, 256, 272, false, 5, 5, 39, false },
59 { 1920, 1080, 16, 9, 72000, 0, true, 32, 168, 184, true, 23, 5, 57, false, 0, 0, true },
60 { 1920, 1080, 16, 9, 148500, 0, true, 528, 44, 148, true, 2, 5, 15, true },
62 { 1280, 720, 16, 9, 148500, 0, false, 440, 40, 220, true, 5, 5, 20, true },
63 { 720, 576, 4, 3, 54000, 0, false, 12, 64, 68, false, 5, 5, 39, false },
64 { 720, 576, 16, 9, 54000, 0, false, 12, 64, 68, false, 5, 5, 39, false },
65 { 1440, 576, 4, 3, 54000, 0, true, 24, 126, 138, false, 2, 3, 19, false },
66 { 1440, 576, 16, 9, 54000, 0, true, 24, 126, 138, false, 2, 3, 19, false },
67 { 1920, 1080, 16, 9, 148500, 0, true, 88, 44, 148, true, 2, 5, 15, true },
68 { 1280, 720, 16, 9, 148500, 0, false, 110, 40, 220, true, 5, 5, 20, true },
69 { 720, 480, 4, 3, 54000, 0, false, 16, 62, 60, false, 9, 6, 30, false },
70 { 720, 480, 16, 9, 54000, 0, false, 16, 62, 60, false, 9, 6, 30, false },
71 { 1440, 480, 4, 3, 54000, 0, true, 38, 124, 114, false, 4, 3, 15, false },
73 { 1440, 480, 16, 9, 54000, 0, true, 38, 124, 114, false, 4, 3, 15, false },
74 { 720, 576, 4, 3, 108000, 0, false, 12, 64, 68, false, 5, 5, 39, false },
75 { 720, 576, 16, 9, 108000, 0, false, 12, 64, 68, false, 5, 5, 39, false },
76 { 1440, 576, 4, 3, 108000, 0, true, 24, 126, 138, false, 2, 3, 19, false },
77 { 1440, 576, 16, 9, 108000, 0, true, 24, 126, 138, false, 2, 3, 19, false },
78 { 720, 480, 4, 3, 108000, 0, false, 16, 62, 60, false, 9, 6, 30, false },
79 { 720, 480, 16, 9, 108000, 0, false, 16, 62, 60, false, 9, 6, 30, false },
80 { 1440, 480, 4, 3, 108000, 0, true, 38, 124, 114, false, 4, 3, 15, false },
81 { 1440, 480, 16, 9, 108000, 0, true, 38, 124, 114, false, 4, 3, 15, false },
82 { 1280, 720, 16, 9, 59400, 0, false, 1760, 40, 220, true, 5, 5, 20, true },
84 { 1280, 720, 16, 9, 74250, 0, false, 2420, 40, 220, true, 5, 5, 20, true },
85 { 1280, 720, 16, 9, 74250, 0, false, 1760, 40, 220, true, 5, 5, 20, true },
86 { 1920, 1080, 16, 9, 297000, 0, false, 88, 44, 148, true, 4, 5, 36, true },
87 { 1920, 1080, 16, 9, 297000, 0, false, 528, 44, 148, true, 4, 5, 36, true },
88 { 1280, 720, 64, 27, 59400, 0, false, 1760, 40, 220, true, 5, 5, 20, true },
89 { 1280, 720, 64, 27, 74250, 0, false, 2420, 40, 220, true, 5, 5, 20, true },
90 { 1280, 720, 64, 27, 74250, 0, false, 1760, 40, 220, true, 5, 5, 20, true },
91 { 1280, 720, 64, 27, 74250, 0, false, 440, 40, 220, true, 5, 5, 20, true },
92 { 1280, 720, 64, 27, 74250, 0, false, 110, 40, 220, true, 5, 5, 20, true },
93 { 1280, 720, 64, 27, 148500, 0, false, 440, 40, 220, true, 5, 5, 20, true },
95 { 1280, 720, 64, 27, 148500, 0, false, 110, 40, 220, true, 5, 5, 20, true },
96 { 1920, 1080, 64, 27, 74250, 0, false, 638, 44, 148, true, 4, 5, 36, true },
97 { 1920, 1080, 64, 27, 74250, 0, false, 528, 44, 148, true, 4, 5, 36, true },
98 { 1920, 1080, 64, 27, 74250, 0, false, 88, 44, 148, true, 4, 5, 36, true },
99 { 1920, 1080, 64, 27, 148500, 0, false, 528, 44, 148, true, 4, 5, 36, true },
100 { 1920, 1080, 64, 27, 148500, 0, false, 88, 44, 148, true, 4, 5, 36, true },
101 { 1920, 1080, 64, 27, 297000, 0, false, 528, 44, 148, true, 4, 5, 36, true },
102 { 1920, 1080, 64, 27, 297000, 0, false, 88, 44, 148, true, 4, 5, 36, true },
103 { 1680, 720, 64, 27, 59400, 0, false, 1360, 40, 220, true, 5, 5, 20, true },
104 { 1680, 720, 64, 27, 59400, 0, false, 1228, 40, 220, true, 5, 5, 20, true },
106 { 1680, 720, 64, 27, 59400, 0, false, 700, 40, 220, true, 5, 5, 20, true },
107 { 1680, 720, 64, 27, 82500, 0, false, 260, 40, 220, true, 5, 5, 20, true },
108 { 1680, 720, 64, 27, 99000, 0, false, 260, 40, 220, true, 5, 5, 20, true },
109 { 1680, 720, 64, 27, 165000, 0, false, 60, 40, 220, true, 5, 5, 95, true },
110 { 1680, 720, 64, 27, 198000, 0, false, 60, 40, 220, true, 5, 5, 95, true },
111 { 2560, 1080, 64, 27, 99000, 0, false, 998, 44, 148, true, 4, 5, 11, true },
112 { 2560, 1080, 64, 27, 90000, 0, false, 448, 44, 148, true, 4, 5, 36, true },
113 { 2560, 1080, 64, 27, 118800, 0, false, 768, 44, 148, true, 4, 5, 36, true },
114 { 2560, 1080, 64, 27, 185625, 0, false, 548, 44, 148, true, 4, 5, 36, true },
115 { 2560, 1080, 64, 27, 198000, 0, false, 248, 44, 148, true, 4, 5, 11, true },
117 { 2560, 1080, 64, 27, 371250, 0, false, 218, 44, 148, true, 4, 5, 161, true },
118 { 2560, 1080, 64, 27, 495000, 0, false, 548, 44, 148, true, 4, 5, 161, true },
119 { 3840, 2160, 16, 9, 297000, 0, false, 1276, 88, 296, true, 8, 10, 72, true },
120 { 3840, 2160, 16, 9, 297000, 0, false, 1056, 88, 296, true, 8, 10, 72, true },
121 { 3840, 2160, 16, 9, 297000, 0, false, 176, 88, 296, true, 8, 10, 72, true },
122 { 3840, 2160, 16, 9, 594000, 0, false, 1056, 88, 296, true, 8, 10, 72, true },
123 { 3840, 2160, 16, 9, 594000, 0, false, 176, 88, 296, true, 8, 10, 72, true },
124 { 4096, 2160, 256, 135, 297000, 0, false, 1020, 88, 296, true, 8, 10, 72, true },
125 { 4096, 2160, 256, 135, 297000, 0, false, 968, 88, 128, true, 8, 10, 72, true },
126 { 4096, 2160, 256, 135, 297000, 0, false, 88, 88, 128, true, 8, 10, 72, true },
128 { 4096, 2160, 256, 135, 594000, 0, false, 968, 88, 128, true, 8, 10, 72, true },
129 { 4096, 2160, 256, 135, 594000, 0, false, 88, 88, 128, true, 8, 10, 72, true },
130 { 3840, 2160, 64, 27, 297000, 0, false, 1276, 88, 296, true, 8, 10, 72, true },
131 { 3840, 2160, 64, 27, 297000, 0, false, 1056, 88, 296, true, 8, 10, 72, true },
132 { 3840, 2160, 64, 27, 297000, 0, false, 176, 88, 296, true, 8, 10, 72, true },
133 { 3840, 2160, 64, 27, 594000, 0, false, 1056, 88, 296, true, 8, 10, 72, true },
134 { 3840, 2160, 64, 27, 594000, 0, false, 176, 88, 296, true, 8, 10, 72, true },
135 { 1280, 720, 16, 9, 90000, 0, false, 960, 40, 220, true, 5, 5, 20, true },
136 { 1280, 720, 64, 27, 90000, 0, false, 960, 40, 220, true, 5, 5, 20, true },
137 { 1680, 720, 64, 27, 99000, 0, false, 810, 40, 220, true, 5, 5, 20, true },
139 { 1920, 1080, 16, 9, 148500, 0, false, 638, 44, 148, true, 4, 5, 36, true },
140 { 1920, 1080, 64, 27, 148500, 0, false, 638, 44, 148, true, 4, 5, 36, true },
141 { 2560, 1080, 64, 27, 198000, 0, false, 998, 44, 148, true, 4, 5, 11, true },
142 { 3840, 2160, 16, 9, 594000, 0, false, 1276, 88, 296, true, 8, 10, 72, true },
143 { 4096, 2160, 256, 135, 594000, 0, false, 1020, 88, 296, true, 8, 10, 72, true },
144 { 3840, 2160, 64, 27, 594000, 0, false, 1276, 88, 296, true, 8, 10, 72, true },
145 { 3840, 2160, 16, 9, 1188000, 0, false, 1056, 88, 296, true, 8, 10, 72, true },
146 { 3840, 2160, 16, 9, 1188000, 0, false, 176, 88, 296, true, 8, 10, 72, true },
147 { 3840, 2160, 64, 27, 1188000, 0, false, 1056, 88, 296, true, 8, 10, 72, true },
148 { 3840, 2160, 64, 27, 1188000, 0, false, 176, 88, 296, true, 8, 10, 72, true },
150 { 5120, 2160, 64, 27, 396000, 0, false, 1996, 88, 296, true, 8, 10, 22, true },
151 { 5120, 2160, 64, 27, 396000, 0, false, 1696, 88, 296, true, 8, 10, 22, true },
152 { 5120, 2160, 64, 27, 396000, 0, false, 664, 88, 128, true, 8, 10, 22, true },
153 { 5120, 2160, 64, 27, 742500, 0, false, 746, 88, 296, true, 8, 10, 297, true },
154 { 5120, 2160, 64, 27, 742500, 0, false, 1096, 88, 296, true, 8, 10, 72, true },
155 { 5120, 2160, 64, 27, 742500, 0, false, 164, 88, 128, true, 8, 10, 72, true },
156 { 5120, 2160, 64, 27, 1485000, 0, false, 1096, 88, 296, true, 8, 10, 72, true },
159 static const struct timings edid_cta_modes2
[] = {
161 { 5120, 2160, 64, 27, 1485000, 0, false, 164, 88, 128, true, 8, 10, 72, true },
162 { 7680, 4320, 16, 9, 1188000, 0, false, 2552, 176, 592, true, 16, 20, 144, true },
163 { 7680, 4320, 16, 9, 1188000, 0, false, 2352, 176, 592, true, 16, 20, 44, true },
164 { 7680, 4320, 16, 9, 1188000, 0, false, 552, 176, 592, true, 16, 20, 44, true },
165 { 7680, 4320, 16, 9, 2376000, 0, false, 2552, 176, 592, true, 16, 20, 144, true },
166 { 7680, 4320, 16, 9, 2376000, 0, false, 2352, 176, 592, true, 16, 20, 44, true },
167 { 7680, 4320, 16, 9, 2376000, 0, false, 552, 176, 592, true, 16, 20, 44, true },
168 { 7680, 4320, 16, 9, 4752000, 0, false, 2112, 176, 592, true, 16, 20, 144, true },
170 { 7680, 4320, 16, 9, 4752000, 0, false, 352, 176, 592, true, 16, 20, 144, true },
171 { 7680, 4320, 64, 27, 1188000, 0, false, 2552, 176, 592, true, 16, 20, 144, true },
172 { 7680, 4320, 64, 27, 1188000, 0, false, 2352, 176, 592, true, 16, 20, 44, true },
173 { 7680, 4320, 64, 27, 1188000, 0, false, 552, 176, 592, true, 16, 20, 44, true },
174 { 7680, 4320, 64, 27, 2376000, 0, false, 2552, 176, 592, true, 16, 20, 144, true },
175 { 7680, 4320, 64, 27, 2376000, 0, false, 2352, 176, 592, true, 16, 20, 44, true },
176 { 7680, 4320, 64, 27, 2376000, 0, false, 552, 176, 592, true, 16, 20, 44, true },
177 { 7680, 4320, 64, 27, 4752000, 0, false, 2112, 176, 592, true, 16, 20, 144, true },
178 { 7680, 4320, 64, 27, 4752000, 0, false, 352, 176, 592, true, 16, 20, 144, true },
179 { 10240, 4320, 64, 27, 1485000, 0, false, 1492, 176, 592, true, 16, 20, 594, true },
181 { 10240, 4320, 64, 27, 1485000, 0, false, 2492, 176, 592, true, 16, 20, 44, true },
182 { 10240, 4320, 64, 27, 1485000, 0, false, 288, 176, 296, true, 16, 20, 144, true },
183 { 10240, 4320, 64, 27, 2970000, 0, false, 1492, 176, 592, true, 16, 20, 594, true },
184 { 10240, 4320, 64, 27, 2970000, 0, false, 2492, 176, 592, true, 16, 20, 44, true },
185 { 10240, 4320, 64, 27, 2970000, 0, false, 288, 176, 296, true, 16, 20, 144, true },
186 { 10240, 4320, 64, 27, 5940000, 0, false, 2192, 176, 592, true, 16, 20, 144, true },
187 { 10240, 4320, 64, 27, 5940000, 0, false, 288, 176, 296, true, 16, 20, 144, true },
188 { 4096, 2160, 256, 135, 1188000, 0, false, 800, 88, 296, true, 8, 10, 72, true },
189 { 4096, 2160, 256, 135, 1188000, 0, false, 88, 88, 128, true, 8, 10, 72, true },
192 static const cta_rid rids
[] = {
195 { 1280, 720, 16, 9 },
196 { 1280, 720, 64, 27 },
197 { 1680, 720, 64, 27 },
198 { 1920, 1080, 16, 9 },
199 { 1920, 1080, 64, 27 },
200 { 2560, 1080, 64, 27 },
201 { 3840, 1080, 32, 9 },
202 { 2560, 1440, 16, 9 },
203 { 3440, 1440, 64, 27 },
205 { 5120, 1440, 32, 9 },
206 { 3840, 2160, 16, 9 },
207 { 3840, 2160, 64, 27 },
208 { 5120, 2160, 64, 27 },
209 { 7680, 2160, 32, 9 },
210 { 5120, 2880, 16, 9 },
211 { 5120, 2880, 64, 27 },
212 { 6880, 2880, 64, 27 },
213 { 10240, 2880, 32, 9 },
214 { 7680, 4320, 16, 9 },
216 { 7680, 4320, 64, 27 },
217 { 10240, 4320, 64, 27 },
218 { 15360, 4320, 32, 9 },
219 { 11520, 6480, 16, 9 },
220 { 11520, 6480, 64, 27 },
221 { 15360, 6480, 64, 27 },
222 { 15360, 8640, 16, 9 },
223 { 15360, 8640, 64, 27 },
224 { 20480, 8640, 64, 27 },
227 static const unsigned char rid2vic
[ARRAY_SIZE(rids
)][8] = {
230 { 60, 61, 62, 108, 19, 4, 41, 47 },
231 { 65, 66, 67, 109, 68, 69, 70, 71 },
232 { 79, 80, 81, 110, 82, 83, 84, 85 },
233 { 32, 33, 34, 111, 31, 16, 64, 63 },
234 { 72, 73, 74, 112, 75, 76, 77, 78 },
235 { 86, 87, 88, 113, 89, 90, 91, 92 },
241 { 93, 94, 95, 114, 96, 97, 117, 118 },
242 { 103, 104, 105, 116, 106, 107, 119, 120 },
243 { 121, 122, 123, 124, 125, 126, 127, 193 },
249 { 194, 195, 196, 197, 198, 199, 200, 201 },
251 { 202, 203, 204, 205, 206, 207, 208, 209 },
252 { 210, 211, 212, 213, 214, 215, 216, 217 },
262 static const unsigned vf_rate_values
[] = {
264 0, 24, 25, 30, 48, 50, 60, 100,
265 /* Rate Index 8-15 */
266 120, 144, 200, 240, 300, 360, 400, 480,
269 static const unsigned char edid_hdmi_mode_map
[] = { 95, 94, 93, 98 };
271 unsigned char hdmi_vic_to_vic(unsigned char hdmi_vic
)
273 if (hdmi_vic
> 0 && hdmi_vic
<= ARRAY_SIZE(edid_hdmi_mode_map
))
274 return edid_hdmi_mode_map
[hdmi_vic
- 1];
278 const struct timings
*find_vic_id(unsigned char vic
)
280 if (vic
> 0 && vic
<= ARRAY_SIZE(edid_cta_modes1
))
281 return edid_cta_modes1
+ vic
- 1;
282 if (vic
>= 193 && vic
< ARRAY_SIZE(edid_cta_modes2
) + 193)
283 return edid_cta_modes2
+ vic
- 193;
287 const struct timings
*find_hdmi_vic_id(unsigned char hdmi_vic
)
289 if (hdmi_vic
> 0 && hdmi_vic
<= ARRAY_SIZE(edid_hdmi_mode_map
))
290 return find_vic_id(edid_hdmi_mode_map
[hdmi_vic
- 1]);
294 const struct cta_rid
*find_rid(unsigned char rid
)
296 if (rid
> 0 && rid
< ARRAY_SIZE(rids
))
301 static unsigned char rid_to_vic(unsigned char rid
, unsigned char rate_index
)
303 if (vf_rate_values
[rate_index
] > 120)
305 return rid2vic
[rid
][rate_index
- 1];
308 const struct timings
*cta_close_match_to_vic(const timings
&t
, unsigned &vic
)
310 for (vic
= 1; vic
<= ARRAY_SIZE(edid_cta_modes1
); vic
++) {
311 if (timings_close_match(t
, edid_cta_modes1
[vic
- 1]))
312 return &edid_cta_modes1
[vic
- 1];
314 for (vic
= 193; vic
< ARRAY_SIZE(edid_cta_modes2
) + 193; vic
++) {
315 if (timings_close_match(t
, edid_cta_modes1
[vic
- 193]))
316 return &edid_cta_modes1
[vic
- 193];
322 void edid_state::cta_list_vics()
325 for (unsigned vic
= 1; vic
<= ARRAY_SIZE(edid_cta_modes1
); vic
++) {
326 sprintf(type
, "VIC %3u", vic
);
327 print_timings("", &edid_cta_modes1
[vic
- 1], type
, "", false, false);
329 for (unsigned vic
= 193; vic
< ARRAY_SIZE(edid_cta_modes2
) + 193; vic
++) {
330 sprintf(type
, "VIC %3u", vic
);
331 print_timings("", &edid_cta_modes2
[vic
- 193], type
, "", false, false);
335 void edid_state::cta_list_hdmi_vics()
337 for (unsigned i
= 0; i
< ARRAY_SIZE(edid_hdmi_mode_map
); i
++) {
338 unsigned vic
= edid_hdmi_mode_map
[i
];
341 sprintf(type
, "HDMI VIC %u", i
+ 1);
342 print_timings("", find_vic_id(vic
), type
, "", false, false);
346 void edid_state::cta_list_rids()
348 for (unsigned i
= 1; i
< ARRAY_SIZE(rids
); i
++) {
349 printf("RID %2u: %5ux%-4u %2u:%-2u\n", i
,
350 rids
[i
].hact
, rids
[i
].vact
,
351 rids
[i
].hratio
, rids
[i
].vratio
);
355 void edid_state::cta_list_rid_timings(unsigned list_rid
)
357 for (unsigned rid
= 1; rid
< ARRAY_SIZE(rids
); rid
++) {
360 if (list_rid
&& rid
!= list_rid
)
363 sprintf(type
, "RID %u", rid
);
364 for (unsigned i
= 1; i
< ARRAY_SIZE(vf_rate_values
); i
++) {
365 unsigned fps
= vf_rate_values
[i
];
367 if (rid_to_vic(rid
, i
)) {
368 printf("%s: %5ux%-4u %7.3f Hz %3u:%-2u maps to VIC %u\n", type
,
369 rids
[rid
].hact
, rids
[rid
].vact
, (double)fps
,
370 rids
[rid
].hratio
, rids
[rid
].vratio
,
374 timings t
= calc_ovt_mode(rids
[rid
].hact
, rids
[rid
].vact
,
375 rids
[rid
].hratio
, rids
[rid
].vratio
, fps
);
376 print_timings("", &t
, type
, "", false, false);
381 static std::string
audio_ext_format(unsigned char x
)
383 if (x
>= 1 && x
<= 3)
384 fail("Obsolete Audio Ext Format 0x%02x.\n", x
);
386 case 1: return "HE AAC (Obsolete)";
387 case 2: return "HE AAC v2 (Obsolete)";
388 case 3: return "MPEG Surround (Obsolete)";
389 case 4: return "MPEG-4 HE AAC";
390 case 5: return "MPEG-4 HE AAC v2";
391 case 6: return "MPEG-4 AAC LC";
392 case 7: return "DRA";
393 case 8: return "MPEG-4 HE AAC + MPEG Surround";
394 case 10: return "MPEG-4 AAC LC + MPEG Surround";
395 case 11: return "MPEG-H 3D Audio";
396 case 12: return "AC-4";
397 case 13: return "L-PCM 3D Audio";
398 case 14: return "Auro-Cx";
399 case 15: return "MPEG-D USAC";
402 fail("Unknown Audio Ext Format 0x%02x.\n", x
);
403 return std::string("Unknown Audio Ext Format (") + utohex(x
) + ")";
406 static std::string
audio_format(unsigned char x
)
409 case 1: return "Linear PCM";
410 case 2: return "AC-3";
411 case 3: return "MPEG 1 (Layers 1 & 2)";
412 case 4: return "MPEG 1 Layer 3 (MP3)";
413 case 5: return "MPEG2 (multichannel)";
414 case 6: return "AAC LC";
415 case 7: return "DTS";
416 case 8: return "ATRAC";
417 case 9: return "One Bit Audio";
418 case 10: return "Enhanced AC-3 (DD+)";
419 case 11: return "DTS-HD";
420 case 12: return "MAT (MLP)";
421 case 13: return "DST";
422 case 14: return "WMA Pro";
425 fail("Unknown Audio Format 0x%02x.\n", x
);
426 return std::string("Unknown Audio Format (") + utohex(x
) + ")";
429 static std::string
mpeg_h_3d_audio_level(unsigned char x
)
432 case 0: return "Unspecified";
433 case 1: return "Level 1";
434 case 2: return "Level 2";
435 case 3: return "Level 3";
436 case 4: return "Level 4";
437 case 5: return "Level 5";
440 fail("Unknown MPEG-H 3D Audio Level 0x%02x.\n", x
);
441 return std::string("Unknown MPEG-H 3D Audio Level (") + utohex(x
) + ")";
444 static void cta_audio_block(const unsigned char *x
, unsigned length
)
446 unsigned i
, format
, ext_format
;
449 fail("Broken CTA-861 audio block length %d.\n", length
);
453 for (i
= 0; i
< length
; i
+= 3) {
454 format
= (x
[i
] & 0x78) >> 3;
456 printf(" Reserved (0x00)\n");
457 fail("Audio Format Code 0x00 is reserved.\n");
462 printf(" %s:\n", audio_format(format
).c_str());
464 ext_format
= (x
[i
+ 2] & 0xf8) >> 3;
465 printf(" %s:\n", audio_ext_format(ext_format
).c_str());
468 printf(" Max channels: %u\n", (x
[i
] & 0x07)+1);
469 else if (ext_format
== 11)
470 printf(" MPEG-H 3D Audio Level: %s\n",
471 mpeg_h_3d_audio_level(x
[i
] & 0x07).c_str());
472 else if (ext_format
== 13)
473 printf(" Max channels: %u\n",
474 (((x
[i
+ 1] & 0x80) >> 3) | ((x
[i
] & 0x80) >> 4) |
476 else if ((ext_format
== 12 || ext_format
== 14) && (x
[i
] & 0x07))
477 fail("Bits F10-F12 must be 0.\n");
479 printf(" Max channels: %u\n", (x
[i
] & 0x07)+1);
481 if ((format
== 1 || format
== 14) && (x
[i
+ 2] & 0xf8))
482 fail("Bits F33-F37 must be 0.\n");
483 if (ext_format
!= 13 && (x
[i
+1] & 0x80))
484 fail("Bit F27 must be 0.\n");
486 // Several sample rates are not supported in certain formats
487 if (ext_format
== 12 && (x
[i
+1] & 0x29))
488 fail("Bits F20, F23 and F25 must be 0.\n");
489 if (ext_format
>= 4 && ext_format
<= 6 && (x
[i
+1] & 0x60))
490 fail("Bits F25 and F26 must be 0.\n");
491 if ((ext_format
== 8 || ext_format
== 10 || ext_format
== 15) && (x
[i
+1] & 0x60))
492 fail("Bits F25 and F26 must be 0.\n");
494 printf(" Supported sample rates (kHz):%s%s%s%s%s%s%s\n",
495 (x
[i
+1] & 0x40) ? " 192" : "",
496 (x
[i
+1] & 0x20) ? " 176.4" : "",
497 (x
[i
+1] & 0x10) ? " 96" : "",
498 (x
[i
+1] & 0x08) ? " 88.2" : "",
499 (x
[i
+1] & 0x04) ? " 48" : "",
500 (x
[i
+1] & 0x02) ? " 44.1" : "",
501 (x
[i
+1] & 0x01) ? " 32" : "");
502 if (format
== 1 || ext_format
== 13) {
503 printf(" Supported sample sizes (bits):%s%s%s\n",
504 (x
[i
+2] & 0x04) ? " 24" : "",
505 (x
[i
+2] & 0x02) ? " 20" : "",
506 (x
[i
+2] & 0x01) ? " 16" : "");
507 } else if (format
<= 8) {
508 printf(" Maximum bit rate: %u kb/s\n", x
[i
+2] * 8);
509 } else if (format
== 10) {
510 // As specified by the "Dolby Audio and Dolby Atmos over HDMI"
511 // specification (v1.0).
513 printf(" Supports Joint Object Coding\n");
515 printf(" Supports Joint Object Coding with ACMOD28\n");
516 } else if (format
== 11) {
517 // Reverse engineering, see:
518 // https://www.avsforum.com/threads/lg-c9-earc-info-thread.3072900/post-61795538
520 printf(" Supports DTS:X\n");
521 // Note: I strongly suspect that bit 0 indicates DTS-HD MA support.
522 printf(" Audio Format Code dependent value: 0x%02x\n", x
[i
+2]);
523 } else if (format
== 12) {
525 printf(" Supports Dolby TrueHD, object audio PCM and channel-based PCM\n");
526 printf(" Hash calculation %srequired for object audio PCM or channel-based PCM\n",
527 (x
[i
+2] & 2) ? "not " : "");
529 printf(" Supports only Dolby TrueHD\n");
531 } else if (format
== 14) {
532 printf(" Profile: %u\n", x
[i
+2] & 7);
533 } else if (format
>= 9 && format
<= 13) {
534 printf(" Audio Format Code dependent value: 0x%02x\n", x
[i
+2]);
535 } else if (ext_format
== 11 && (x
[i
+2] & 1)) {
536 printf(" Supports MPEG-H 3D Audio Low Complexity Profile\n");
537 } else if ((ext_format
>= 4 && ext_format
<= 6) ||
538 ext_format
== 8 || ext_format
== 10) {
539 printf(" AAC audio frame lengths:%s%s\n",
540 (x
[i
+2] & 4) ? " 1024_TL" : "",
541 (x
[i
+2] & 2) ? " 960_TL" : "");
542 if (ext_format
>= 8 && (x
[i
+2] & 1))
543 printf(" Supports %s signaled MPEG Surround data\n",
544 (x
[i
+2] & 1) ? "implicitly and explicitly" : "only implicitly");
545 if (ext_format
== 6 && (x
[i
+2] & 1))
546 printf(" Supports 22.2ch System H\n");
547 } else if (ext_format
== 12 || ext_format
== 14) {
548 printf(" Audio Format Code dependent value: %u\n", x
[i
+2] & 7);
553 void edid_state::cta_svd(const unsigned char *x
, unsigned n
, bool for_ycbcr420
)
557 for (i
= 0; i
< n
; i
++) {
558 const struct timings
*t
= NULL
;
559 unsigned char svd
= x
[i
];
560 unsigned char native
;
563 if ((svd
& 0x7f) == 0)
566 if ((svd
- 1) & 0x40) {
574 t
= find_vic_id(vic
);
578 cta
.supported_hdmi_vic_vsb_codes
|= 1 << 0;
581 cta
.supported_hdmi_vic_vsb_codes
|= 1 << 1;
584 cta
.supported_hdmi_vic_vsb_codes
|= 1 << 2;
587 cta
.supported_hdmi_vic_vsb_codes
|= 1 << 3;
590 bool first_svd
= cta
.first_svd
&& !for_ycbcr420
;
591 bool override_pref
= first_svd
&& cta
.first_svd_might_be_preferred
;
594 sprintf(type
, "VIC %3u", vic
);
595 const char *flags
= native
? "native" : "";
598 struct timings tmp
= *t
;
600 print_timings(" ", &tmp
, type
, flags
);
602 print_timings(" ", t
, type
, flags
);
605 if (!cta
.preferred_timings
.empty()) {
606 if (match_timings(cta
.preferred_timings
[0].t
, *t
))
607 warn("For improved preferred timing interoperability, set 'Native detailed modes' to 1.\n");
609 warn("VIC %u is the preferred timing, overriding the first detailed timings. Is this intended?\n", vic
);
611 cta
.preferred_timings
.insert(cta
.preferred_timings
.begin(),
612 timings_ext(*t
, type
, flags
));
613 } else if (first_svd
) {
614 cta
.preferred_timings
.push_back(timings_ext(*t
, type
, flags
));
617 cta
.first_svd
= false;
618 cta
.first_svd_might_be_preferred
= false;
621 cta
.native_timings
.push_back(timings_ext(*t
, type
, flags
));
623 printf(" Unknown (VIC %3u)\n", vic
);
624 fail("Unknown VIC %u.\n", vic
);
627 if (vic
== 1 && !for_ycbcr420
)
629 if (++cta
.vics
[vic
][for_ycbcr420
] == 2)
630 fail("Duplicate %sVIC %u.\n", for_ycbcr420
? "YCbCr 4:2:0 " : "", vic
);
631 if (for_ycbcr420
&& cta
.preparsed_has_vic
[0][vic
])
632 fail("YCbCr 4:2:0-only VIC %u is also a regular VIC.\n", vic
);
636 cta_vfd
edid_state::cta_parse_vfd(const unsigned char *x
, unsigned lvfd
)
640 vfd
.rid
= x
[0] & 0x3f;
641 if (vfd
.rid
>= ARRAY_SIZE(rids
)) {
645 vfd
.bfr50
= !!(x
[0] & 0x80);
646 vfd
.fr24
= !!(x
[0] & 0x40);
647 vfd
.bfr60
= lvfd
> 1 ? !!(x
[1] & 0x80) : 1;
648 vfd
.fr144
= lvfd
> 1 ? !!(x
[1] & 0x40) : 0;
649 vfd
.fr_factor
= lvfd
> 1 ? (x
[1] & 0x3f) : 3;
650 vfd
.fr48
= lvfd
> 2 ? !!(x
[2] & 0x01) : 0;
654 static bool vfd_has_rate(cta_vfd
&vfd
, unsigned rate_index
)
656 static const unsigned factors
[6] = {
659 unsigned rate
= vf_rate_values
[rate_index
];
682 for (unsigned i
= 0; i
< ARRAY_SIZE(factors
); i
++)
683 if (factors
[i
] == factor
&& (vfd
.fr_factor
& (1 << i
)))
688 void edid_state::cta_vfdb(const unsigned char *x
, unsigned n
)
691 fail("Length is 0.\n");
694 unsigned char flags
= *x
++;
695 unsigned lvfd
= (flags
& 3) + 1;
698 fail("Length - 1 is not a multiple of Lvfd (%u).\n", lvfd
);
702 printf(" Supports YCbCr 4:2:0\n");
704 printf(" NTSC fractional frame rates are preferred\n");
705 for (unsigned i
= 0; i
< n
; i
+= lvfd
, x
+= lvfd
) {
706 unsigned char rid
= x
[0] & 0x3f;
707 cta_vfd vfd
= cta_parse_vfd(x
, lvfd
);
709 if (lvfd
> 2 && (x
[2] & 0xfe))
710 fail("Bits F31-F37 must be 0.\n");
711 if (lvfd
> 3 && x
[3])
712 fail("Bits F40-F47 must be 0.\n");
713 if (rid
== 0 || rid
>= ARRAY_SIZE(rids
)) {
714 fail("Unknown RID %u.\n", rid
);
717 for (unsigned rate_index
= 1; rate_index
< ARRAY_SIZE(vf_rate_values
); rate_index
++) {
718 if (!vfd_has_rate(vfd
, rate_index
))
720 struct timings t
= calc_ovt_mode(rids
[vfd
.rid
].hact
,
722 rids
[vfd
.rid
].hratio
,
723 rids
[vfd
.rid
].vratio
,
724 vf_rate_values
[rate_index
]);
726 sprintf(type
, "RID %u@%up", rid
, vf_rate_values
[rate_index
]);
727 print_timings(" ", &t
, type
);
728 if (rid_to_vic(vfd
.rid
, rate_index
))
729 fail("%s not allowed since it maps to VIC %u.\n",
730 type
, rid_to_vic(vfd
.rid
, rate_index
));
735 void edid_state::print_vic_index(const char *prefix
, unsigned idx
, const char *suffix
, bool ycbcr420
)
739 if (idx
< cta
.preparsed_svds
[0].size()) {
740 unsigned char vic
= cta
.preparsed_svds
[0][idx
];
741 const struct timings
*t
= find_vic_id(vic
);
744 sprintf(buf
, "VIC %3u", vic
);
747 struct timings tmp
= *t
;
748 tmp
.ycbcr420
= ycbcr420
;
749 print_timings(prefix
, &tmp
, buf
, suffix
);
751 printf("%sUnknown (%s%s%s)\n", prefix
, buf
,
752 *suffix
? ", " : "", suffix
);
755 // Should not happen!
756 printf("%sSVD Index %u is out of range", prefix
, idx
+ 1);
758 printf(" (%s)", suffix
);
763 void edid_state::cta_y420cmdb(const unsigned char *x
, unsigned length
)
765 unsigned max_idx
= 0;
769 printf(" All VDB SVDs\n");
773 if (memchk(x
, length
)) {
774 printf(" Empty Capability Map\n");
775 fail("Empty Capability Map.\n");
779 for (i
= 0; i
< length
; i
++) {
780 unsigned char v
= x
[i
];
783 for (j
= 0; j
< 8; j
++) {
787 print_vic_index(" ", i
* 8 + j
, "", true);
789 if (max_idx
< cta
.preparsed_svds
[0].size()) {
790 unsigned vic
= cta
.preparsed_svds
[0][max_idx
];
791 if (cta
.preparsed_has_vic
[1][vic
])
792 fail("VIC %u is also a YCbCr 4:2:0-only VIC.\n", vic
);
796 if (max_idx
>= cta
.preparsed_svds
[0].size())
797 fail("Max index %u > %u (#SVDs).\n",
798 max_idx
+ 1, cta
.preparsed_svds
[0].size());
801 void edid_state::cta_print_svr(unsigned char svr
, vec_timings_ext
&vec_tim
)
805 if ((svr
> 0 && svr
< 128) || (svr
> 192 && svr
< 254)) {
806 const struct timings
*t
;
807 unsigned char vic
= svr
;
809 sprintf(suffix
, "VIC %3u", vic
);
811 t
= find_vic_id(vic
);
813 print_timings(" ", t
, suffix
);
814 vec_tim
.push_back(timings_ext(*t
, suffix
, ""));
816 printf(" %s: Unknown\n", suffix
);
817 fail("Unknown VIC %u.\n", vic
);
820 } else if (svr
>= 129 && svr
<= 144) {
821 sprintf(suffix
, "DTD %3u", svr
- 128);
822 if (svr
>= cta
.preparsed_total_dtds
+ 129) {
823 printf(" %s: Invalid\n", suffix
);
824 fail("Invalid DTD %u.\n", svr
- 128);
826 printf(" %s\n", suffix
);
827 vec_tim
.push_back(timings_ext(svr
, suffix
));
829 } else if (svr
>= 145 && svr
<= 160) {
830 sprintf(suffix
, "VTDB %3u", svr
- 144);
831 if (svr
>= cta
.preparsed_total_vtdbs
+ 145) {
832 printf(" %s: Invalid\n", suffix
);
833 fail("Invalid VTDB %u.\n", svr
- 144);
835 printf(" %s\n", suffix
);
836 vec_tim
.push_back(timings_ext(svr
, suffix
));
838 } else if (svr
>= 161 && svr
<= 175) {
839 sprintf(suffix
, "RID %u@%up",
840 cta
.preparsed_first_vfd
.rid
, vf_rate_values
[svr
- 160]);
841 if (!vfd_has_rate(cta
.preparsed_first_vfd
, svr
- 160)) {
842 printf(" %s: Invalid\n", suffix
);
843 fail("Invalid %s.\n", suffix
);
845 printf(" %s\n", suffix
);
846 vec_tim
.push_back(timings_ext(svr
, suffix
));
848 } else if (svr
== 254) {
849 sprintf(suffix
, "T8VTDB");
850 if (!cta
.preparsed_has_t8vtdb
) {
851 printf(" %s: Invalid\n", suffix
);
852 fail("Invalid T8VTDB.\n");
854 sprintf(suffix
, "DMT 0x%02x", cta
.preparsed_t8vtdb_dmt
);
855 printf(" %s\n", suffix
);
856 vec_tim
.push_back(timings_ext(svr
, suffix
));
861 void edid_state::cta_vfpdb(const unsigned char *x
, unsigned length
)
866 fail("Empty Data Block with length %u.\n", length
);
869 cta
.preferred_timings_vfpdb
.clear();
870 for (i
= 0; i
< length
; i
++)
871 cta_print_svr(x
[i
], cta
.preferred_timings_vfpdb
);
874 void edid_state::cta_nvrdb(const unsigned char *x
, unsigned length
)
877 fail("Empty Data Block with length %u.\n", length
);
881 unsigned char flags
= length
== 1 ? 0 : x
[1];
883 cta
.native_timing_nvrdb
.clear();
884 cta_print_svr(x
[0], cta
.native_timing_nvrdb
);
885 if ((flags
& 1) && length
< 6) {
886 fail("Data Block too short for Image Size (length = %u).\n", length
);
890 fail("Bits F41-F46 must be 0.\n");
894 unsigned w
= (x
[3] << 8) | x
[2];
895 unsigned h
= (x
[5] << 8) | x
[4];
898 fail("Image Size has a zero width and/or height.\n");
901 printf(" Image Size: %ux%u mm\n", w
, h
);
903 printf(" Image Size: %.1fx%.1f mm\n", w
/ 10.0, h
/ 10.0);
906 static std::string
hdmi_latency2s(unsigned char l
, bool is_video
)
911 return is_video
? "Video not supported" : "Audio not supported";
912 return std::to_string(2 * (l
- 1)) + " ms";
915 void edid_state::hdmi_latency(unsigned char vid_lat
, unsigned char aud_lat
,
918 const char *vid
= is_ilaced
? "Interlaced video" : "Video";
919 const char *aud
= is_ilaced
? "Interlaced audio" : "Audio";
921 printf(" %s latency: %s\n", vid
, hdmi_latency2s(vid_lat
, true).c_str());
922 printf(" %s latency: %s\n", aud
, hdmi_latency2s(aud_lat
, false).c_str());
924 if (vid_lat
> 251 && vid_lat
!= 0xff)
925 fail("Invalid %s latency value %u.\n", vid
, vid_lat
);
926 if (aud_lat
> 251 && aud_lat
!= 0xff)
927 fail("Invalid %s latency value %u.\n", aud
, aud_lat
);
929 if (!vid_lat
|| vid_lat
> 251)
931 if (!aud_lat
|| aud_lat
> 251)
934 unsigned vid_ms
= 2 * (vid_lat
- 1);
935 unsigned aud_ms
= 2 * (aud_lat
- 1);
937 // HDMI 2.0 latency checks for devices without HDMI output
939 warn("%s latency < %s latency (%u ms < %u ms). This is discouraged for devices without HDMI output.\n",
940 aud
, vid
, aud_ms
, vid_ms
);
941 else if (vid_ms
+ 20 < aud_ms
)
942 warn("%s latency + 20 < %s latency (%u + 20 ms < %u ms). This is forbidden for devices without HDMI output.\n",
943 vid
, aud
, vid_ms
, aud_ms
);
944 else if (vid_ms
< aud_ms
)
945 warn("%s latency < %s latency (%u ms < %u ms). This is discouraged for devices without HDMI output.\n",
946 vid
, aud
, vid_ms
, aud_ms
);
949 void edid_state::cta_hdmi_block(const unsigned char *x
, unsigned length
)
951 unsigned len_vic
, len_3d
;
954 fail("Empty Data Block with length %u.\n", length
);
957 printf(" Source physical address: %x.%x.%x.%x\n", x
[0] >> 4, x
[0] & 0x0f,
958 x
[1] >> 4, x
[1] & 0x0f);
964 printf(" Supports_AI\n");
966 printf(" DC_48bit\n");
968 printf(" DC_36bit\n");
970 printf(" DC_30bit\n");
972 printf(" DC_Y444\n");
973 /* two reserved bits */
975 printf(" DVI_Dual\n");
980 printf(" Maximum TMDS clock: %u MHz\n", x
[3] * 5);
982 fail("HDMI VSDB Max TMDS rate is > 340.\n");
988 printf(" Supported Content Types:\n");
990 printf(" Graphics\n");
1001 hdmi_latency(x
[b
], x
[b
+ 1], false);
1004 if (x
[b
] == x
[b
+ 2] &&
1005 x
[b
+ 1] == x
[b
+ 3])
1006 warn("Progressive and Interlaced latency values are identical, no need for both.\n");
1008 hdmi_latency(x
[b
], x
[b
+ 1], true);
1017 bool formats
= false;
1019 printf(" Extended HDMI video details:\n");
1021 printf(" 3D present\n");
1022 if ((x
[b
] & 0x60) == 0x20) {
1023 printf(" All advertised VICs are 3D-capable\n");
1026 if ((x
[b
] & 0x60) == 0x40) {
1027 printf(" 3D-capable-VIC mask present\n");
1031 switch (x
[b
] & 0x18) {
1034 printf(" Base EDID image size is aspect ratio\n");
1037 printf(" Base EDID image size is in units of 1 cm\n");
1040 printf(" Base EDID image size is in units of 5 cm\n");
1041 base
.max_display_width_mm
*= 5;
1042 base
.max_display_height_mm
*= 5;
1043 printf(" Recalculated image size: %u cm x %u cm\n",
1044 base
.max_display_width_mm
/ 10, base
.max_display_height_mm
/ 10);
1048 len_vic
= (x
[b
] & 0xe0) >> 5;
1049 len_3d
= (x
[b
] & 0x1f) >> 0;
1055 printf(" HDMI VICs:\n");
1056 for (i
= 0; i
< len_vic
; i
++) {
1057 unsigned char vic
= x
[b
+ i
];
1058 const struct timings
*t
;
1060 if (vic
&& vic
<= ARRAY_SIZE(edid_hdmi_mode_map
)) {
1061 std::string suffix
= "HDMI VIC " + std::to_string(vic
);
1062 cta
.supported_hdmi_vic_codes
|= 1 << (vic
- 1);
1063 t
= find_vic_id(edid_hdmi_mode_map
[vic
- 1]);
1064 print_timings(" ", t
, suffix
.c_str());
1066 printf(" Unknown (HDMI VIC %u)\n", vic
);
1067 fail("Unknown HDMI VIC %u.\n", vic
);
1078 /* 3D_Structure_ALL_15..8 */
1080 printf(" 3D: Side-by-side (half, quincunx)\n");
1082 printf(" 3D: Side-by-side (half, horizontal)\n");
1083 /* 3D_Structure_ALL_7..0 */
1086 printf(" 3D: Top-and-bottom\n");
1088 printf(" 3D: L + depth + gfx + gfx-depth\n");
1090 printf(" 3D: L + depth\n");
1092 printf(" 3D: Side-by-side (full)\n");
1094 printf(" 3D: Line-alternative\n");
1096 printf(" 3D: Field-alternative\n");
1098 printf(" 3D: Frame-packing\n");
1107 printf(" 3D VIC indices that support these capabilities:\n");
1108 /* worst bit ordering ever */
1109 for (i
= 0; i
< 8; i
++)
1110 if (x
[b
+ 1] & (1 << i
)) {
1111 print_vic_index(" ", i
, "");
1114 for (i
= 0; i
< 8; i
++)
1115 if (x
[b
] & (1 << i
)) {
1116 print_vic_index(" ", i
+ 8, "");
1121 if (max_idx
>= (int)cta
.preparsed_svds
[0].size())
1122 fail("HDMI 3D VIC indices max index %d > %u (#SVDs).\n",
1123 max_idx
+ 1, cta
.preparsed_svds
[0].size());
1130 * (optionally: 3D_Detail_X and reserved)
1135 unsigned end
= b
+ len_3d
;
1138 printf(" 3D VIC indices with specific capabilities:\n");
1140 unsigned char idx
= x
[b
] >> 4;
1145 switch (x
[b
] & 0x0f) {
1146 case 0: s
= "frame packing"; break;
1147 case 1: s
= "field alternative"; break;
1148 case 2: s
= "line alternative"; break;
1149 case 3: s
= "side-by-side (full)"; break;
1150 case 4: s
= "L + depth"; break;
1151 case 5: s
= "L + depth + gfx + gfx-depth"; break;
1152 case 6: s
= "top-and-bottom"; break;
1155 switch (x
[b
+ 1] >> 4) {
1156 case 0x00: s
+= ", any subsampling"; break;
1157 case 0x01: s
+= ", horizontal"; break;
1158 case 0x02: case 0x03: case 0x04: case 0x05:
1159 s
+= ", not in use";
1160 fail("not-in-use 3D_Detail_X value 0x%02x.\n",
1163 case 0x06: s
+= ", all quincunx combinations"; break;
1164 case 0x07: s
+= ", quincunx odd/left, odd/right"; break;
1165 case 0x08: s
+= ", quincunx odd/left, even/right"; break;
1166 case 0x09: s
+= ", quincunx even/left, odd/right"; break;
1167 case 0x0a: s
+= ", quincunx even/left, even/right"; break;
1170 fail("reserved 3D_Detail_X value 0x%02x.\n",
1177 s
+= utohex(x
[b
] & 0x0f) + ")";
1178 fail("Unknown 3D_Structure_X value 0x%02x.\n", x
[b
] & 0x0f);
1181 print_vic_index(" ", idx
, s
.c_str());
1182 if ((x
[b
] & 0x0f) >= 8)
1186 if (max_idx
>= (int)cta
.preparsed_svds
[0].size())
1187 fail("HDMI 2D VIC indices max index %d > %u (#SVDs).\n",
1188 max_idx
+ 1, cta
.preparsed_svds
[0].size());
1191 static const char *max_frl_rates
[] = {
1193 "3 Gbps per lane on 3 lanes",
1194 "3 and 6 Gbps per lane on 3 lanes",
1195 "3 and 6 Gbps per lane on 3 lanes, 6 Gbps on 4 lanes",
1196 "3 and 6 Gbps per lane on 3 lanes, 6 and 8 Gbps on 4 lanes",
1197 "3 and 6 Gbps per lane on 3 lanes, 6, 8 and 10 Gbps on 4 lanes",
1198 "3 and 6 Gbps per lane on 3 lanes, 6, 8, 10 and 12 Gbps on 4 lanes",
1201 static const char *dsc_max_slices
[] = {
1203 "up to 1 slice and up to (340 MHz/Ksliceadjust) pixel clock per slice",
1204 "up to 2 slices and up to (340 MHz/Ksliceadjust) pixel clock per slice",
1205 "up to 4 slices and up to (340 MHz/Ksliceadjust) pixel clock per slice",
1206 "up to 8 slices and up to (340 MHz/Ksliceadjust) pixel clock per slice",
1207 "up to 8 slices and up to (400 MHz/Ksliceadjust) pixel clock per slice",
1208 "up to 12 slices and up to (400 MHz/Ksliceadjust) pixel clock per slice",
1209 "up to 16 slices and up to (400 MHz/Ksliceadjust) pixel clock per slice",
1212 static void cta_hf_eeodb(const unsigned char *x
, unsigned length
)
1214 printf(" EDID Extension Block Count: %u\n", x
[0]);
1216 fail("Block is too long.\n");
1218 fail("Extension Block Count == %u.\n", x
[0]);
1221 static void cta_hf_scdb(const unsigned char *x
, unsigned length
)
1223 unsigned rate
= x
[1] * 5;
1226 printf(" Version: %u\n", x
[0]);
1228 printf(" Maximum TMDS Character Rate: %u MHz\n", rate
);
1229 if (rate
<= 340 || rate
> 600)
1230 fail("Max TMDS rate is > 0 and <= 340 or > 600.\n");
1233 printf(" SCDC Present\n");
1235 printf(" SCDC Read Request Capable\n");
1237 printf(" Supports Cable Status\n");
1239 printf(" Supports Color Content Bits Per Component Indication\n");
1241 printf(" Supports scrambling for <= 340 Mcsc\n");
1243 printf(" Supports 3D Independent View signaling\n");
1245 printf(" Supports 3D Dual View signaling\n");
1247 printf(" Supports 3D OSD Disparity signaling\n");
1249 unsigned max_frl_rate
= x
[3] >> 4;
1251 printf(" Max Fixed Rate Link: ");
1252 if (max_frl_rate
< ARRAY_SIZE(max_frl_rates
)) {
1253 printf("%s\n", max_frl_rates
[max_frl_rate
]);
1255 printf("Unknown (0x%02x)\n", max_frl_rate
);
1256 fail("Unknown Max Fixed Rate Link (0x%02x).\n", max_frl_rate
);
1258 if (max_frl_rate
== 1 && rate
< 300)
1259 fail("Max Fixed Rate Link is 1, but Max TMDS rate < 300.\n");
1260 else if (max_frl_rate
>= 2 && rate
< 600)
1261 fail("Max Fixed Rate Link is >= 2, but Max TMDS rate < 600.\n");
1264 printf(" Supports UHD VIC\n");
1266 printf(" Supports 16-bits/component Deep Color 4:2:0 Pixel Encoding\n");
1268 printf(" Supports 12-bits/component Deep Color 4:2:0 Pixel Encoding\n");
1270 printf(" Supports 10-bits/component Deep Color 4:2:0 Pixel Encoding\n");
1276 printf(" Supports Mdelta\n");
1278 printf(" Supports media rates below VRRmin (CinemaVRR)\n");
1280 printf(" Supports negative Mvrr values\n");
1282 printf(" Supports Fast Vactive\n");
1284 printf(" Supports Auto Low-Latency Mode\n");
1286 printf(" Supports a FAPA in blanking after first active video line\n");
1293 printf(" VRRmin: %u Hz\n", v
);
1295 fail("VRRmin > 48.\n");
1297 v
= (x
[5] & 0xc0) << 2 | x
[6];
1299 printf(" VRRmax: %u Hz\n", v
);
1301 fail("VRRmin == 0, but VRRmax isn't.\n");
1303 fail("VRRmax < 100.\n");
1310 printf(" Supports VESA DSC 1.2a compression\n");
1312 printf(" Supports Compressed Video Transport for 4:2:0 Pixel Encoding\n");
1314 printf(" Supports Compressed Video Transport at any valid 1/16th bit bpp\n");
1316 printf(" Supports 16 bpc Compressed Video Transport\n");
1318 printf(" Supports 12 bpc Compressed Video Transport\n");
1320 printf(" Supports 10 bpc Compressed Video Transport\n");
1322 unsigned max_slices
= x
[8] & 0xf;
1324 printf(" DSC Max Slices: ");
1325 if (max_slices
< ARRAY_SIZE(dsc_max_slices
)) {
1326 printf("%s\n", dsc_max_slices
[max_slices
]);
1328 printf("Unknown (0x%02x)\n", max_slices
);
1329 fail("Unknown DSC Max Slices (0x%02x).\n", max_slices
);
1333 unsigned max_frl_rate
= x
[8] >> 4;
1335 printf(" DSC Max Fixed Rate Link: ");
1336 if (max_frl_rate
< ARRAY_SIZE(max_frl_rates
)) {
1337 printf("%s\n", max_frl_rates
[max_frl_rate
]);
1339 printf("Unknown (0x%02x)\n", max_frl_rate
);
1340 fail("Unknown DSC Max Fixed Rate Link (0x%02x).\n", max_frl_rate
);
1344 printf(" Maximum number of bytes in a line of chunks: %u\n",
1345 1024 * (1 + (x
[9] & 0x3f)));
1348 static void cta_amd(const unsigned char *x
, unsigned length
)
1350 // These Freesync values are reversed engineered by looking
1351 // at existing EDIDs.
1352 printf(" Version: %u.%u\n", x
[0], x
[1]);
1353 printf(" Minimum Refresh Rate: %u Hz\n", x
[2]);
1354 printf(" Maximum Refresh Rate: %u Hz\n", x
[3]);
1355 // Freesync 1.x flags
1356 // One or more of the 0xe6 bits signal that the VESA MCCS
1357 // protocol is used to switch the Freesync range
1358 printf(" Flags 1.x: 0x%02x%s\n", x
[4],
1359 (x
[4] & 0xe6) ? " (MCCS)" : "");
1361 // Freesync 2.x flags
1362 // Bit 2 no doubt indicates if the monitor supports Local Dimming
1363 // There are probably also bits to signal support of the
1364 // FreeSync2_scRGB and FreeSync2_Gamma22 HDR display modes.
1365 // I suspect bits 0 and 1.
1366 printf(" Flags 2.x: 0x%02x\n", x
[5]);
1367 // The AMD tone mapping tutorial referred to in the URL below
1368 // mentions that the Freesync HDR info reports max/min
1369 // luminance of the monitor with and without local dimming.
1371 // https://gpuopen.com/learn/using-amd-freesync-premium-pro-hdr-code-samples/
1373 // So I assume that the first two luminance values are
1374 // the max/min luminance of the display and the next two
1375 // luminance values are the max/min luminance values when
1376 // local dimming is disabled. The values I get seem to
1378 printf(" Maximum luminance: %u (%.3f cd/m^2)\n",
1379 x
[6], 50.0 * pow(2, x
[6] / 32.0));
1380 printf(" Minimum luminance: %u (%.3f cd/m^2)\n",
1381 x
[7], (50.0 * pow(2, x
[6] / 32.0)) * pow(x
[7] / 255.0, 2) / 100.0);
1383 // One or both bytes can be 0. The meaning of that
1385 printf(" Maximum luminance (without local dimming): %u (%.3f cd/m^2)\n",
1386 x
[8], 50.0 * pow(2, x
[8] / 32.0));
1387 printf(" Minimum luminance (without local dimming): %u (%.3f cd/m^2)\n",
1388 x
[9], (50.0 * pow(2, x
[8] / 32.0)) * pow(x
[9] / 255.0, 2) / 100.0);
1390 // These bytes are always 0x08 0x2f. If these values
1391 // represent max/min luminance as well, then these
1392 // would map to 59.460 and 0.020 cd/m^2 respectively.
1393 // I wonder if this somehow relates to SDR.
1394 printf(" Unknown: 0x%02x 0x%02x\n", x
[8], x
[9]);
1399 static std::string
display_use_case(unsigned char x
)
1402 case 1: return "Test equipment";
1403 case 2: return "Generic display";
1404 case 3: return "Television display";
1405 case 4: return "Desktop productivity display";
1406 case 5: return "Desktop gaming display";
1407 case 6: return "Presentation display";
1408 case 7: return "Virtual reality headset";
1409 case 8: return "Augmented reality";
1410 case 16: return "Video wall display";
1411 case 17: return "Medical imaging display";
1412 case 18: return "Dedicated gaming display";
1413 case 19: return "Dedicated video monitor display";
1414 case 20: return "Accessory display";
1417 fail("Unknown Display product primary use case 0x%02x.\n", x
);
1418 return std::string("Unknown display use case (") + utohex(x
) + ")";
1421 static void cta_microsoft(const unsigned char *x
, unsigned length
)
1423 // This VSDB is documented at:
1424 // https://docs.microsoft.com/en-us/windows-hardware/drivers/display/specialized-monitors-edid-extension
1425 printf(" Version: %u\n", x
[0]);
1427 // In version 1 and 2 these bits should always be set to 0.
1428 printf(" Desktop Usage: %u\n", (x
[1] >> 6) & 1);
1429 printf(" Third-Party Usage: %u\n", (x
[1] >> 5) & 1);
1431 printf(" Display Product Primary Use Case: %u (%s)\n", x
[1] & 0x1f,
1432 display_use_case(x
[1] & 0x1f).c_str());
1433 printf(" Container ID: %s\n", containerid2s(x
+ 2).c_str());
1436 static void cta_hdr10plus(const unsigned char *x
, unsigned length
)
1439 fail("Empty Data Block with length %u.\n", length
);
1442 printf(" Application Version: %u\n", x
[0]);
1443 hex_block(" ", x
+ 1, length
- 1);
1446 // Convert a PQ value (0-1) to cd/m^2 aka nits (0-10000)
1447 static double pq2nits(double pq
)
1449 const double m1
= 2610.0 / 16384.0;
1450 const double m2
= 128.0 * (2523.0 / 4096.0);
1451 const double c1
= 3424.0 / 4096.0;
1452 const double c2
= 32.0 * (2413.0 / 4096.0);
1453 const double c3
= 32.0 * (2392.0 / 4096.0);
1454 double e
= pow(pq
, 1.0 / m2
);
1460 v
= pow(v
, 1.0 / m1
);
1464 static void cta_dolby_video(const unsigned char *x
, unsigned length
)
1466 unsigned char version
= (x
[0] >> 5) & 0x07;
1468 printf(" Version: %u (%u bytes)\n", version
, length
+ 5);
1470 printf(" Supports YUV422 12 bit\n");
1474 printf(" Supports 2160p60\n");
1476 printf(" Supports global dimming\n");
1477 unsigned char dm_version
= x
[16];
1478 printf(" DM Version: %u.%u\n", dm_version
>> 4, dm_version
& 0xf);
1479 unsigned pq
= (x
[14] << 4) | (x
[13] >> 4);
1480 printf(" Target Min PQ: %u (%.8f cd/m^2)\n", pq
, pq2nits(pq
/ 4095.0));
1481 pq
= (x
[15] << 4) | (x
[13] & 0xf);
1482 printf(" Target Max PQ: %u (%u cd/m^2)\n", pq
, (unsigned)pq2nits(pq
/ 4095.0));
1483 printf(" Rx, Ry: %.8f, %.8f\n",
1484 ((x
[1] >> 4) | (x
[2] << 4)) / 4096.0,
1485 ((x
[1] & 0xf) | (x
[3] << 4)) / 4096.0);
1486 printf(" Gx, Gy: %.8f, %.8f\n",
1487 ((x
[4] >> 4) | (x
[5] << 4)) / 4096.0,
1488 ((x
[4] & 0xf) | (x
[6] << 4)) / 4096.0);
1489 printf(" Bx, By: %.8f, %.8f\n",
1490 ((x
[7] >> 4) | (x
[8] << 4)) / 4096.0,
1491 ((x
[7] & 0xf) | (x
[9] << 4)) / 4096.0);
1492 printf(" Wx, Wy: %.8f, %.8f\n",
1493 ((x
[10] >> 4) | (x
[11] << 4)) / 4096.0,
1494 ((x
[10] & 0xf) | (x
[12] << 4)) / 4096.0);
1500 printf(" Supports 2160p60\n");
1502 printf(" Supports global dimming\n");
1503 unsigned char dm_version
= (x
[0] >> 2) & 0x07;
1504 printf(" DM Version: %u.x\n", dm_version
+ 2);
1505 printf(" Colorimetry: %s\n", (x
[2] & 0x01) ? "P3-D65" : "ITU-R BT.709");
1506 printf(" Low Latency: %s\n", (x
[3] & 0x01) ? "Standard + Low Latency" : "Only Standard");
1507 double lm
= (x
[2] >> 1) / 127.0;
1508 printf(" Target Min Luminance: %.8f cd/m^2\n", lm
* lm
);
1509 printf(" Target Max Luminance: %u cd/m^2\n", 100 + (x
[1] >> 1) * 50);
1511 printf(" Rx, Ry: %.8f, %.8f\n", x
[4] / 256.0, x
[5] / 256.0);
1512 printf(" Gx, Gy: %.8f, %.8f\n", x
[6] / 256.0, x
[7] / 256.0);
1513 printf(" Bx, By: %.8f, %.8f\n", x
[8] / 256.0, x
[9] / 256.0);
1515 double xmin
= 0.625;
1516 double xstep
= (0.74609375 - xmin
) / 31.0;
1518 double ystep
= (0.37109375 - ymin
) / 31.0;
1520 printf(" Unique Rx, Ry: %.8f, %.8f\n",
1521 xmin
+ xstep
* (x
[6] >> 3),
1522 ymin
+ ystep
* (((x
[6] & 0x7) << 2) | (x
[4] & 0x01) | ((x
[5] & 0x01) << 1)));
1523 xstep
= 0.49609375 / 127.0;
1525 ystep
= (0.99609375 - ymin
) / 127.0;
1526 printf(" Unique Gx, Gy: %.8f, %.8f\n",
1527 xstep
* (x
[4] >> 1), ymin
+ ystep
* (x
[5] >> 1));
1529 xstep
= (0.15234375 - xmin
) / 7.0;
1531 ystep
= (0.05859375 - ymin
) / 7.0;
1532 printf(" Unique Bx, By: %.8f, %.8f\n",
1533 xmin
+ xstep
* (x
[3] >> 5),
1534 ymin
+ ystep
* ((x
[3] >> 2) & 0x07));
1541 printf(" Supports Backlight Control\n");
1543 printf(" Supports global dimming\n");
1544 unsigned char dm_version
= (x
[0] >> 2) & 0x07;
1545 printf(" DM Version: %u.x\n", dm_version
+ 2);
1546 printf(" Backlt Min Luma: %u cd/m^2\n", 25 + (x
[1] & 0x03) * 25);
1547 printf(" Interface: ");
1548 switch (x
[2] & 0x03) {
1549 case 0: printf("Low-Latency\n"); break;
1550 case 1: printf("Low-Latency + Low-Latency-HDMI\n"); break;
1551 case 2: printf("Standard + Low-Latency\n"); break;
1552 case 3: printf("Standard + Low-Latency + Low-Latency-HDMI\n"); break;
1554 printf(" Supports 10b 12b 444: ");
1555 switch ((x
[3] & 0x01) << 1 | (x
[4] & 0x01)) {
1556 case 0: printf("Not supported\n"); break;
1557 case 1: printf("10 bit\n"); break;
1558 case 2: printf("12 bit\n"); break;
1559 case 3: printf("Reserved\n"); break;
1562 // This divider constant is a guess. According to what I read
1563 // when googling for how to interpret these values, the Min PQ
1564 // maps to a range of 0-1 cd/m^2, and the Max PQ maps to a
1565 // range of 100-10000 cd/m^2. Since the maximum value for the Max PQ
1566 // is 2055 + 65 * 31 = 4070, I am guessing that that is the correct
1567 // divider, but it might well be 4095 or 4096 instead.
1569 // I'm also not sure if the divider for Min PQ is the same as for
1570 // Max PQ. To map the max value of 20 * 31 to 1 cd/m^2 you would
1571 // need a divider of 4134 or 4135, but I suspect the same divider
1573 const double dv_pq_div
= 2055 + 31 * 65;
1575 unsigned pq
= 20 * (x
[1] >> 3);
1576 printf(" Target Min PQ v2: %u (%.8f cd/m^2)\n", pq
, pq2nits(pq
/ dv_pq_div
));
1577 pq
= 2055 + 65 * (x
[2] >> 3);
1578 printf(" Target Max PQ v2: %u (%u cd/m^2)\n", pq
, (unsigned)pq2nits(pq
/ dv_pq_div
));
1580 double xmin
= 0.625;
1581 double xstep
= (0.74609375 - xmin
) / 31.0;
1583 double ystep
= (0.37109375 - ymin
) / 31.0;
1585 printf(" Unique Rx, Ry: %.8f, %.8f\n",
1586 xmin
+ xstep
* (x
[5] >> 3),
1587 ymin
+ ystep
* (x
[6] >> 3));
1588 xstep
= 0.49609375 / 127.0;
1590 ystep
= (0.99609375 - ymin
) / 127.0;
1591 printf(" Unique Gx, Gy: %.8f, %.8f\n",
1592 xstep
* (x
[3] >> 1), ymin
+ ystep
* (x
[4] >> 1));
1594 xstep
= (0.15234375 - xmin
) / 7.0;
1596 ystep
= (0.05859375 - ymin
) / 7.0;
1597 printf(" Unique Bx, By: %.8f, %.8f\n",
1598 xmin
+ xstep
* (x
[5] & 0x07),
1599 ymin
+ ystep
* (x
[6] & 0x07));
1603 static void cta_dolby_audio(const unsigned char *x
, unsigned length
)
1605 unsigned char version
= 1 + (x
[0] & 0x07);
1607 printf(" Version: %u (%u bytes)\n", version
, length
+ 5);
1609 printf(" Headphone playback only\n");
1611 printf(" Height speaker zone present\n");
1613 printf(" Surround speaker zone present\n");
1615 printf(" Center speaker zone present\n");
1617 printf(" Supports Dolby MAT PCM decoding at 48 kHz only, does not support TrueHD\n");
1620 static const char *speaker_map
[] = {
1621 "FL/FR - Front Left/Right",
1622 "LFE1 - Low Frequency Effects 1",
1623 "FC - Front Center",
1624 "BL/BR - Back Left/Right",
1626 "FLc/FRc - Front Left/Right of Center",
1627 "RLC/RRC - Rear Left/Right of Center (Deprecated)",
1628 "FLw/FRw - Front Left/Right Wide",
1629 "TpFL/TpFR - Top Front Left/Right",
1631 "TpFC - Top Front Center",
1632 "LS/RS - Left/Right Surround",
1633 "LFE2 - Low Frequency Effects 2",
1634 "TpBC - Top Back Center",
1635 "SiL/SiR - Side Left/Right",
1636 "TpSiL/TpSiR - Top Side Left/Right",
1637 "TpBL/TpBR - Top Back Left/Right",
1638 "BtFC - Bottom Front Center",
1639 "BtFL/BtFR - Bottom Front Left/Right",
1640 "TpLS/TpRS - Top Left/Right Surround (Deprecated for CTA-861)",
1641 "LSd/RSd - Left/Right Surround Direct (HDMI only)",
1644 static void cta_sadb(const unsigned char *x
, unsigned length
)
1650 fail("Empty Data Block with length %u.\n", length
);
1654 sad
= ((x
[2] << 16) | (x
[1] << 8) | x
[0]);
1656 for (i
= 0; i
< ARRAY_SIZE(speaker_map
); i
++) {
1658 printf(" %s\n", speaker_map
[i
]);
1662 static void cta_vesa_dtcdb(const unsigned char *x
, unsigned length
)
1664 if (length
!= 7 && length
!= 15 && length
!= 31) {
1665 fail("Invalid length %u.\n", length
);
1669 switch (x
[0] >> 6) {
1670 case 0: printf(" White"); break;
1671 case 1: printf(" Red"); break;
1672 case 2: printf(" Green"); break;
1673 case 3: printf(" Blue"); break;
1675 unsigned v
= x
[0] & 0x3f;
1676 printf(" transfer characteristics: %u", v
);
1677 for (unsigned i
= 1; i
< length
; i
++)
1678 printf(" %u", v
+= x
[i
]);
1682 static void cta_vesa_vdddb(const unsigned char *x
, unsigned length
)
1685 fail("Invalid length %u.\n", length
);
1689 printf(" Interface Type: ");
1690 unsigned char v
= x
[0];
1692 case 0: printf("Analog (");
1694 case 0: printf("15HD/VGA"); break;
1695 case 1: printf("VESA NAVI-V (15HD)"); break;
1696 case 2: printf("VESA NAVI-D"); break;
1697 default: printf("Reserved"); break;
1701 case 1: printf("LVDS %u lanes", v
& 0xf); break;
1702 case 2: printf("RSDS %u lanes", v
& 0xf); break;
1703 case 3: printf("DVI-D %u channels", v
& 0xf); break;
1704 case 4: printf("DVI-I analog"); break;
1705 case 5: printf("DVI-I digital %u channels", v
& 0xf); break;
1706 case 6: printf("HDMI-A"); break;
1707 case 7: printf("HDMI-B"); break;
1708 case 8: printf("MDDI %u channels", v
& 0xf); break;
1709 case 9: printf("DisplayPort %u channels", v
& 0xf); break;
1710 case 10: printf("IEEE-1394"); break;
1711 case 11: printf("M1 analog"); break;
1712 case 12: printf("M1 digital %u channels", v
& 0xf); break;
1713 default: printf("Reserved"); break;
1717 printf(" Interface Standard Version: %u.%u\n", x
[1] >> 4, x
[1] & 0xf);
1718 printf(" Content Protection Support: ");
1720 case 0: printf("None\n"); break;
1721 case 1: printf("HDCP\n"); break;
1722 case 2: printf("DTCP\n"); break;
1723 case 3: printf("DPCP\n"); break;
1724 default: printf("Reserved\n"); break;
1727 printf(" Minimum Clock Frequency: %u MHz\n", x
[3] >> 2);
1728 printf(" Maximum Clock Frequency: %u MHz\n", ((x
[3] & 0x03) << 8) | x
[4]);
1729 printf(" Device Native Pixel Format: %ux%u\n",
1730 x
[5] | (x
[6] << 8), x
[7] | (x
[8] << 8));
1731 printf(" Aspect Ratio: %.2f\n", (100 + x
[9]) / 100.0);
1733 printf(" Default Orientation: ");
1734 switch ((v
& 0xc0) >> 6) {
1735 case 0x00: printf("Landscape\n"); break;
1736 case 0x01: printf("Portrait\n"); break;
1737 case 0x02: printf("Not Fixed\n"); break;
1738 case 0x03: printf("Undefined\n"); break;
1740 printf(" Rotation Capability: ");
1741 switch ((v
& 0x30) >> 4) {
1742 case 0x00: printf("None\n"); break;
1743 case 0x01: printf("Can rotate 90 degrees clockwise\n"); break;
1744 case 0x02: printf("Can rotate 90 degrees counterclockwise\n"); break;
1745 case 0x03: printf("Can rotate 90 degrees in either direction)\n"); break;
1747 printf(" Zero Pixel Location: ");
1748 switch ((v
& 0x0c) >> 2) {
1749 case 0x00: printf("Upper Left\n"); break;
1750 case 0x01: printf("Upper Right\n"); break;
1751 case 0x02: printf("Lower Left\n"); break;
1752 case 0x03: printf("Lower Right\n"); break;
1754 printf(" Scan Direction: ");
1756 case 0x00: printf("Not defined\n"); break;
1757 case 0x01: printf("Fast Scan is on the Major (Long) Axis and Slow Scan is on the Minor Axis\n"); break;
1758 case 0x02: printf("Fast Scan is on the Minor (Short) Axis and Slow Scan is on the Major Axis\n"); break;
1759 case 0x03: printf("Reserved\n");
1760 fail("Scan Direction used the reserved value 0x03.\n");
1763 printf(" Subpixel Information: ");
1765 case 0x00: printf("Not defined\n"); break;
1766 case 0x01: printf("RGB vertical stripes\n"); break;
1767 case 0x02: printf("RGB horizontal stripes\n"); break;
1768 case 0x03: printf("Vertical stripes using primary order\n"); break;
1769 case 0x04: printf("Horizontal stripes using primary order\n"); break;
1770 case 0x05: printf("Quad sub-pixels, red at top left\n"); break;
1771 case 0x06: printf("Quad sub-pixels, red at bottom left\n"); break;
1772 case 0x07: printf("Delta (triad) RGB sub-pixels\n"); break;
1773 case 0x08: printf("Mosaic\n"); break;
1774 case 0x09: printf("Quad sub-pixels, RGB + 1 additional color\n"); break;
1775 case 0x0a: printf("Five sub-pixels, RGB + 2 additional colors\n"); break;
1776 case 0x0b: printf("Six sub-pixels, RGB + 3 additional colors\n"); break;
1777 case 0x0c: printf("Clairvoyante, Inc. PenTile Matrix (tm) layout\n"); break;
1778 default: printf("Reserved\n"); break;
1780 printf(" Horizontal and vertical dot/pixel pitch: %.2f x %.2f mm\n",
1781 (double)(x
[0x0c]) / 100.0, (double)(x
[0x0d]) / 100.0);
1783 printf(" Dithering: ");
1785 case 0: printf("None\n"); break;
1786 case 1: printf("Spatial\n"); break;
1787 case 2: printf("Temporal\n"); break;
1788 case 3: printf("Spatial and Temporal\n"); break;
1790 printf(" Direct Drive: %s\n", (v
& 0x20) ? "Yes" : "No");
1791 printf(" Overdrive %srecommended\n", (v
& 0x10) ? "not " : "");
1792 printf(" Deinterlacing: %s\n", (v
& 0x08) ? "Yes" : "No");
1795 printf(" Audio Support: %s\n", (v
& 0x80) ? "Yes" : "No");
1796 printf(" Separate Audio Inputs Provided: %s\n", (v
& 0x40) ? "Yes" : "No");
1797 printf(" Audio Input Override: %s\n", (v
& 0x20) ? "Yes" : "No");
1800 printf(" Audio Delay: %s%u ms\n", (v
& 0x80) ? "" : "-", (v
& 0x7f) * 2);
1802 printf(" Audio Delay: no information provided\n");
1804 printf(" Frame Rate/Mode Conversion: ");
1806 case 0: printf("None\n"); break;
1807 case 1: printf("Single Buffering\n"); break;
1808 case 2: printf("Double Buffering\n"); break;
1809 case 3: printf("Advanced Frame Rate Conversion\n"); break;
1812 printf(" Frame Rate Range: %u fps +/- %u fps\n",
1815 printf(" Nominal Frame Rate: %u fps\n", x
[0x12]);
1816 printf(" Color Bit Depth: %u @ interface, %u @ display\n",
1817 (x
[0x13] >> 4) + 1, (x
[0x13] & 0xf) + 1);
1820 printf(" Additional Primary Chromaticities:\n");
1821 unsigned col_x
= (x
[0x16] << 2) | (x
[0x14] >> 6);
1822 unsigned col_y
= (x
[0x17] << 2) | ((x
[0x14] >> 4) & 3);
1823 printf(" Primary 4: 0.%04u, 0.%04u\n",
1824 (col_x
* 10000) / 1024, (col_y
* 10000) / 1024);
1826 col_x
= (x
[0x18] << 2) | ((x
[0x14] >> 2) & 3);
1827 col_y
= (x
[0x19] << 2) | (x
[0x14] & 3);
1828 printf(" Primary 5: 0.%04u, 0.%04u\n",
1829 (col_x
* 10000) / 1024, (col_y
* 10000) / 1024);
1831 col_x
= (x
[0x1a] << 2) | (x
[0x15] >> 6);
1832 col_y
= (x
[0x1b] << 2) | ((x
[0x15] >> 4) & 3);
1833 printf(" Primary 6: 0.%04u, 0.%04u\n",
1834 (col_x
* 10000) / 1024, (col_y
* 10000) / 1024);
1840 printf(" Response Time %s: %u ms\n",
1841 (v
& 0x80) ? "White -> Black" : "Black -> White", v
& 0x7f);
1843 printf(" Overscan: %u%% x %u%%\n", v
>> 4, v
& 0xf);
1846 static double decode_uchar_as_double(unsigned char x
)
1848 signed char s
= (signed char)x
;
1853 void edid_state::cta_rcdb(const unsigned char *x
, unsigned length
)
1855 unsigned spm
= ((x
[3] << 16) | (x
[2] << 8) | x
[1]);
1859 fail("Empty Data Block with length %u.\n", length
);
1863 if ((x
[0] & 0x20) && !cta
.has_sldb
)
1864 fail("'SLD' flag is 1, but no Speaker Location Data Block is found.\n");
1865 else if (!(x
[0] & 0x20) && cta
.has_sldb
)
1866 fail("'SLD' flag is 0, but a Speaker Location Data Block is present.\n");
1869 printf(" Speaker count: %u\n", (x
[0] & 0x1f) + 1);
1872 fail("'Speaker' flag is 0, but 'Speaker Count' is != 0.\n");
1874 fail("'SLD' flag is 1, but 'Speaker' is 0.\n");
1877 printf(" Speaker Presence Mask:\n");
1878 for (i
= 0; i
< ARRAY_SIZE(speaker_map
); i
++) {
1880 printf(" %s\n", speaker_map
[i
]);
1883 if ((x
[0] & 0xa0) == 0x80)
1884 fail("'Display' flag set, but not the 'SLD' flag.\n");
1886 bool valid_max
= cta
.preparsed_sld_has_coord
|| (x
[0] & 0x80);
1888 if (valid_max
&& length
>= 7) {
1889 printf(" Xmax: %u dm\n", x
[4]);
1890 printf(" Ymax: %u dm\n", x
[5]);
1891 printf(" Zmax: %u dm\n", x
[6]);
1892 } else if (!valid_max
&& length
>= 7) {
1893 // The RCDB should have been truncated.
1894 warn("'Display' flag is 0 and 'Coord' is 0 for all SLDs, but the Max coordinates are still present.\n");
1896 if ((x
[0] & 0x80) && length
>= 10) {
1897 printf(" DisplayX: %.3f * Xmax\n", decode_uchar_as_double(x
[7]));
1898 printf(" DisplayY: %.3f * Ymax\n", decode_uchar_as_double(x
[8]));
1899 printf(" DisplayZ: %.3f * Zmax\n", decode_uchar_as_double(x
[9]));
1900 } else if (!(x
[0] & 0x80) && length
>= 10) {
1901 // The RCDB should have been truncated.
1902 warn("'Display' flag is 0, but the Display coordinates are still present.\n");
1906 static const struct {
1909 } speaker_location
[] = {
1910 { "FL - Front Left", -1, 1, 0 },
1911 { "FR - Front Right", 1, 1, 0 },
1912 { "FC - Front Center", 0, 1, 0 },
1913 { "LFE1 - Low Frequency Effects 1", -0.5, 1, -1 },
1914 { "BL - Back Left", -1, -1, 0 },
1915 { "BR - Back Right", 1, -1, 0 },
1916 { "FLC - Front Left of Center", -0.5, 1, 0 },
1917 { "FRC - Front Right of Center", 0.5, 1, 0 },
1918 { "BC - Back Center", 0, -1, 0 },
1919 { "LFE2 - Low Frequency Effects 2", 0.5, 1, -1 },
1920 { "SiL - Side Left", -1, 1.0/3.0, 0 },
1921 { "SiR - Side Right", 1, 1.0/3.0, 0 },
1922 { "TpFL - Top Front Left", -1, 1, 1 },
1923 { "TpFR - Top Front Right", 1, 1, 1 },
1924 { "TpFC - Top Front Center", 0, 1, 1 },
1925 { "TpC - Top Center", 0, 0, 1 },
1926 { "TpBL - Top Back Left", -1, -1, 1 },
1927 { "TpBR - Top Back Right", 1, -1, 1 },
1928 { "TpSiL - Top Side Left", -1, 0, 1 },
1929 { "TpSiR - Top Side Right", 1, 0, 1 },
1930 { "TpBC - Top Back Center", 0, -1, 1 },
1931 { "BtFC - Bottom Front Center", 0, 1, -1 },
1932 { "BtFL - Bottom Front Left", -1, 1, -1 },
1933 { "BtFR - Bottom Front Right", 1, 1, -1 },
1934 { "FLW - Front Left Wide", -1, 2.0/3.0, 0 },
1935 { "FRW - Front Right Wide", 1, 2.0/3.0, 0 },
1936 { "LS - Left Surround", -1, 0, 0 },
1937 { "RS - Right Surround", 1, 0, 0 },
1940 void edid_state::cta_sldb(const unsigned char *x
, unsigned length
)
1943 fail("Empty Data Block with length %u.\n", length
);
1947 unsigned active_cnt
= 0;
1948 unsigned channel_is_active
= 0;
1950 while (length
>= 2) {
1951 printf(" Channel: %u (%sactive)\n", x
[0] & 0x1f,
1952 (x
[0] & 0x20) ? "" : "not ");
1954 if (channel_is_active
& (1U << (x
[0] & 0x1f)))
1955 fail("Channel Index %u was already marked 'Active'.\n",
1957 channel_is_active
|= 1U << (x
[0] & 0x1f);
1960 if ((x
[1] & 0x1f) < ARRAY_SIZE(speaker_location
))
1961 printf(" Speaker: %s\n", speaker_location
[x
[1] & 0x1f].name
);
1962 if (length
>= 5 && (x
[0] & 0x40)) {
1963 printf(" X: %.3f * Xmax\n", decode_uchar_as_double(x
[2]));
1964 printf(" Y: %.3f * Ymax\n", decode_uchar_as_double(x
[3]));
1965 printf(" Z: %.3f * Zmax\n", decode_uchar_as_double(x
[4]));
1969 printf(" X: %.3f * Xmax (approximately)\n", speaker_location
[x
[1] & 0x1f].x
);
1970 printf(" Y: %.3f * Ymax (approximately)\n", speaker_location
[x
[1] & 0x1f].y
);
1971 printf(" Z: %.3f * Zmax (approximately)\n", speaker_location
[x
[1] & 0x1f].z
);
1977 if (active_cnt
!= cta
.preparsed_speaker_count
)
1978 fail("There are %u active speakers, but 'Speaker Count' is %u.\n",
1979 active_cnt
, cta
.preparsed_speaker_count
);
1982 void edid_state::cta_preparse_sldb(const unsigned char *x
, unsigned length
)
1984 cta
.has_sldb
= true;
1985 while (length
>= 2) {
1986 if (length
>= 5 && (x
[0] & 0x40)) {
1987 cta
.preparsed_sld_has_coord
= true;
1995 void edid_state::cta_vcdb(const unsigned char *x
, unsigned length
)
1997 unsigned char d
= x
[0];
1999 cta
.has_vcdb
= true;
2001 fail("Empty Data Block with length %u.\n", length
);
2004 printf(" YCbCr quantization: %s\n",
2005 (d
& 0x80) ? "Selectable (via AVI YQ)" : "No Data");
2006 printf(" RGB quantization: %s\n",
2007 (d
& 0x40) ? "Selectable (via AVI Q)" : "No Data");
2009 * If this bit is not set then that will result in interoperability
2010 * problems (specifically with PCs/laptops) that quite often do not
2011 * follow the default rules with respect to RGB Quantization Range
2014 * Starting with the CTA-861-H spec this bit is now required to be
2015 * 1 for new designs.
2018 fail("Set Selectable RGB Quantization to avoid interop issues.\n");
2020 * Since most YCbCr formats use limited range, the interop issues are
2021 * less noticable than for RGB formats.
2023 * Starting with the CTA-861-H spec this bit is now required to be
2024 * 1 for new designs, but just warn about it (for now).
2026 if ((cta
.byte3
& 0x30) && !(d
& 0x80))
2027 warn("Set Selectable YCbCr Quantization to avoid interop issues.\n");
2029 unsigned char s_pt
= (d
>> 4) & 0x03;
2030 unsigned char s_it
= (d
>> 2) & 0x03;
2031 unsigned char s_ce
= d
& 0x03;
2033 printf(" PT scan behavior: ");
2035 case 0: printf("No Data\n"); break;
2036 case 1: printf("Always Overscanned\n"); break;
2037 case 2: printf("Always Underscanned\n"); break;
2038 case 3: printf("Supports both over- and underscan\n"); break;
2040 printf(" IT scan behavior: ");
2042 case 0: printf("IT video formats not supported\n"); break;
2044 printf("Always Overscanned\n");
2045 // See Table 52 of CTA-861-G for a description of Byte 3
2046 if (cta
.byte3
& 0x80)
2047 fail("IT video formats are always overscanned, but bit 7 of Byte 3 of the CTA-861 Extension header is set to underscanned.\n");
2050 printf("Always Underscanned\n");
2051 // See Table 52 of CTA-861-G for a description of Byte 3
2052 if (!(cta
.byte3
& 0x80))
2053 fail("IT video formats are always underscanned, but bit 7 of Byte 3 of the CTA-861 Extension header is set to overscanned.\n");
2055 case 3: printf("Supports both over- and underscan\n"); break;
2058 warn("IT scan behavior is expected to support underscanned.\n");
2059 printf(" CE scan behavior: ");
2061 case 0: printf("CE video formats not supported\n"); break;
2062 case 1: printf("Always Overscanned\n"); break;
2063 case 2: printf("Always Underscanned\n"); break;
2064 case 3: printf("Supports both over- and underscan\n"); break;
2067 warn("'CE video formats not supported' makes no sense.\n");
2068 else if (s_pt
== s_it
&& s_pt
== s_ce
)
2069 warn("S_PT is equal to S_IT and S_CE, so should be set to 0 instead.\n");
2072 static const char *colorimetry1_map
[] = {
2083 static const char *colorimetry2_map
[] = {
2084 "Gamut Boundary Description Metadata Profile P0",
2085 "Reserved Gamut Boundary Description Metadata Profile P1",
2086 "Reserved Gamut Boundary Description Metadata Profile P2",
2087 "Reserved Gamut Boundary Description Metadata Profile P3",
2094 void edid_state::cta_colorimetry_block(const unsigned char *x
, unsigned length
)
2099 fail("Empty Data Block with length %u.\n", length
);
2102 for (i
= 0; i
< ARRAY_SIZE(colorimetry1_map
); i
++)
2103 if (x
[0] & (1 << i
))
2104 printf(" %s\n", colorimetry1_map
[i
]);
2105 // Bits MD0-MD3 are used to indicate which HDMI Gamut Boundary Description
2106 // Metadata Profiles are supported.
2108 // HDMI 1.3a in section 5.3.12 describes 4 possible profiles, but it marks
2109 // P3 as 'defined in a future specification'.
2111 // HDMI 1.4b, however, only specifies profile P0 in section 8.3.3. And I've
2112 // only seen P0 in practice. My assumption is that profiles P1-P3 are never
2113 // used, and so these bits should be 0.
2115 fail("Reserved bits MD1-MD3 must be 0.\n");
2116 for (i
= 0; i
< ARRAY_SIZE(colorimetry2_map
); i
++)
2117 if (x
[1] & (1 << i
))
2118 printf(" %s\n", colorimetry2_map
[i
]);
2119 // The sRGB bit (added in CTA-861.6) allows sources to explicitly
2120 // signal sRGB colorimetry. Without this the default colorimetry
2121 // of an RGB video is either sRGB or defaultRGB. It depends on the
2122 // Source which is used, and the Sink has no idea what it is getting.
2124 // For proper compatibility with PCs enabling sRGB support is
2126 if (!base
.uses_srgb
&& !(x
[1] & 0x20))
2127 warn("Set the sRGB colorimetry bit to avoid interop issues.\n");
2130 static const char *eotf_map
[] = {
2131 "Traditional gamma - SDR luminance range",
2132 "Traditional gamma - HDR luminance range",
2137 static void cta_hdr_static_metadata_block(const unsigned char *x
, unsigned length
)
2142 fail("Empty Data Block with length %u.\n", length
);
2145 printf(" Electro optical transfer functions:\n");
2146 for (i
= 0; i
< 6; i
++) {
2147 if (x
[0] & (1 << i
)) {
2148 if (i
< ARRAY_SIZE(eotf_map
)) {
2149 printf(" %s\n", eotf_map
[i
]);
2151 printf(" Unknown (%u)\n", i
);
2152 fail("Unknown EOTF (%u).\n", i
);
2156 printf(" Supported static metadata descriptors:\n");
2157 for (i
= 0; i
< 8; i
++) {
2158 if (x
[1] & (1 << i
))
2159 printf(" Static metadata type %u\n", i
+ 1);
2163 printf(" Desired content max luminance: %u (%.3f cd/m^2)\n",
2164 x
[2], 50.0 * pow(2, x
[2] / 32.0));
2167 printf(" Desired content max frame-average luminance: %u (%.3f cd/m^2)\n",
2168 x
[3], 50.0 * pow(2, x
[3] / 32.0));
2171 printf(" Desired content min luminance: %u (%.3f cd/m^2)\n",
2172 x
[4], (50.0 * pow(2, x
[2] / 32.0)) * pow(x
[4] / 255.0, 2) / 100.0);
2175 static void cta_hdr_dyn_metadata_block(const unsigned char *x
, unsigned length
)
2178 fail("Empty Data Block with length %u.\n", length
);
2181 while (length
>= 3) {
2182 unsigned type_len
= x
[0];
2183 unsigned type
= x
[1] | (x
[2] << 8);
2185 if (length
< type_len
+ 1)
2187 printf(" HDR Dynamic Metadata Type %u\n", type
);
2192 printf(" Version: %u\n", x
[3] & 0xf);
2196 unsigned version
= x
[3] & 0xf;
2197 printf(" Version: %u\n", version
);
2199 if (x
[3] & 0x10) printf(" Supports SL-HDR1 (ETSI TS 103 433-1)\n");
2200 if (x
[3] & 0x20) printf(" Supports SL-HDR2 (ETSI TS 103 433-2)\n");
2201 if (x
[3] & 0x40) printf(" Supports SL-HDR3 (ETSI TS 103 433-3)\n");
2208 length
-= type_len
+ 1;
2213 static const char *infoframe_types
[] = {
2216 "Auxiliary Video Information",
2217 "Source Product Description",
2221 "Dynamic Range and Mastering",
2224 static void cta_ifdb(const unsigned char *x
, unsigned length
)
2226 unsigned len_hdr
= x
[0] >> 5;
2229 fail("Empty Data Block with length %u.\n", length
);
2232 printf(" VSIFs: %u\n", x
[1]);
2233 if (length
< len_hdr
+ 2)
2235 length
-= len_hdr
+ 2;
2237 while (length
> 0) {
2238 int payload_len
= x
[0] >> 5;
2239 unsigned char type
= x
[0] & 0x1f;
2241 const char *name
= NULL
;
2242 if (type
< ARRAY_SIZE(infoframe_types
))
2243 name
= infoframe_types
[type
];
2246 printf(" %s InfoFrame (%u)", name
, type
);
2248 if (type
== 1 && length
>= 4) {
2249 unsigned oui
= (x
[3] << 16) | (x
[2] << 8) | x
[1];
2251 printf(", OUI %s\n", ouitohex(oui
).c_str());
2260 length
-= payload_len
;
2264 void edid_state::cta_displayid_type_7(const unsigned char *x
, unsigned length
)
2266 check_displayid_datablock_revision(x
[0], 0x00, 2);
2268 if (length
< 21U + ((x
[0] & 0x70) >> 4)) {
2269 fail("Empty Data Block with length %u.\n", length
);
2272 parse_displayid_type_1_7_timing(x
+ 1, true, 2, true);
2275 void edid_state::cta_displayid_type_8(const unsigned char *x
, unsigned length
)
2277 check_displayid_datablock_revision(x
[0], 0xe8, 1);
2278 if (length
< ((x
[0] & 0x08) ? 3 : 2)) {
2279 fail("Empty Data Block with length %u.\n", length
);
2283 unsigned sz
= (x
[0] & 0x08) ? 2 : 1;
2284 unsigned type
= x
[0] >> 6;
2287 fail("Only code type 0 is supported.\n");
2292 printf(" Also supports YCbCr 4:2:0\n");
2296 for (unsigned i
= 0; i
< length
/ sz
; i
++) {
2297 unsigned id
= x
[i
* sz
];
2300 id
|= x
[i
* sz
+ 1] << 8;
2301 parse_displayid_type_4_8_timing(type
, id
, true);
2305 void edid_state::cta_displayid_type_10(const unsigned char *x
, unsigned length
)
2307 check_displayid_datablock_revision(x
[0], 0x70);
2308 if (length
< 7U + ((x
[0] & 0x70) >> 4)) {
2309 fail("Empty Data Block with length %u.\n", length
);
2313 unsigned sz
= 6U + ((x
[0] & 0x70) >> 4);
2316 for (unsigned i
= 0; i
< length
/ sz
; i
++)
2317 parse_displayid_type_10_timing(x
+ i
* sz
, sz
, true);
2320 static void cta_hdmi_audio_block(const unsigned char *x
, unsigned length
)
2325 fail("Empty Data Block with length %u.\n", length
);
2329 printf(" Max Stream Count: %u\n", (x
[0] & 3) + 1);
2331 printf(" Supports MS NonMixed\n");
2333 num_descs
= x
[1] & 7;
2338 while (length
>= 4) {
2340 unsigned format
= x
[0] & 0xf;
2342 printf(" %s, max channels %u\n", audio_format(format
).c_str(),
2344 printf(" Supported sample rates (kHz):%s%s%s%s%s%s%s\n",
2345 (x
[2] & 0x40) ? " 192" : "",
2346 (x
[2] & 0x20) ? " 176.4" : "",
2347 (x
[2] & 0x10) ? " 96" : "",
2348 (x
[2] & 0x08) ? " 88.2" : "",
2349 (x
[2] & 0x04) ? " 48" : "",
2350 (x
[2] & 0x02) ? " 44.1" : "",
2351 (x
[2] & 0x01) ? " 32" : "");
2353 printf(" Supported sample sizes (bits):%s%s%s\n",
2354 (x
[3] & 0x04) ? " 24" : "",
2355 (x
[3] & 0x02) ? " 20" : "",
2356 (x
[3] & 0x01) ? " 16" : "");
2358 unsigned sad
= ((x
[2] << 16) | (x
[1] << 8) | x
[0]);
2361 switch (x
[3] >> 4) {
2363 printf(" Speaker Allocation for 10.2 channels:\n");
2366 printf(" Speaker Allocation for 22.2 channels:\n");
2369 printf(" Speaker Allocation for 30.2 channels:\n");
2372 printf(" Unknown Speaker Allocation (0x%02x)\n", x
[3] >> 4);
2376 for (i
= 0; i
< ARRAY_SIZE(speaker_map
); i
++) {
2378 printf(" %s\n", speaker_map
[i
]);
2386 void edid_state::cta_block(const unsigned char *x
, std::vector
<unsigned> &found_tags
)
2388 unsigned length
= x
[0] & 0x1f;
2389 unsigned tag
= (x
[0] & 0xe0) >> 5;
2390 unsigned extended
= (tag
== 0x07) ? 1 : 0;
2393 if (extended
&& length
) {
2400 bool dooutputname
= true;
2401 bool audio_block
= false;
2405 case 0x01: data_block
= "Audio Data Block"; audio_block
= true; break;
2406 case 0x02: data_block
= "Video Data Block"; break;
2407 case 0x03: data_block
= "Vendor-Specific Data Block"; break;
2408 case 0x04: data_block
= "Speaker Allocation Data Block"; audio_block
= true; break;
2409 case 0x05: data_block
= "VESA Display Transfer Characteristics Data Block"; break;
2410 case 0x06: data_block
= "Video Format Data Block"; break;
2411 case 0x07: data_block
= "Unknown CTA-861 Data Block (extended tag truncated)"; break;
2413 case 0x700: data_block
= "Video Capability Data Block"; break;
2414 case 0x701: data_block
= "Vendor-Specific Video Data Block"; break;
2415 case 0x702: data_block
= "VESA Video Display Device Data Block"; break;
2416 case 0x703: data_block
= "VESA Video Timing Block Extension"; break;
2417 case 0x704: data_block
= "Reserved for HDMI Video Data Block"; break;
2418 case 0x705: data_block
= "Colorimetry Data Block"; break;
2419 case 0x706: data_block
= "HDR Static Metadata Data Block"; break;
2420 case 0x707: data_block
= "HDR Dynamic Metadata Data Block"; break;
2421 case 0x708: data_block
= "Native Video Resolution Data Block"; break;
2423 case 0x70d: data_block
= "Video Format Preference Data Block"; break;
2424 case 0x70e: data_block
= "YCbCr 4:2:0 Video Data Block"; break;
2425 case 0x70f: data_block
= "YCbCr 4:2:0 Capability Map Data Block"; break;
2426 case 0x710: data_block
= "Reserved for CTA-861 Miscellaneous Audio Fields"; break;
2427 case 0x711: data_block
= "Vendor-Specific Audio Data Block"; audio_block
= true; break;
2428 case 0x712: data_block
= "HDMI Audio Data Block"; audio_block
= true; break;
2429 case 0x713: data_block
= "Room Configuration Data Block"; audio_block
= true; break;
2430 case 0x714: data_block
= "Speaker Location Data Block"; audio_block
= true; break;
2432 case 0x720: data_block
= "InfoFrame Data Block"; break;
2434 case 0x722: data_block
= "DisplayID Type VII Video Timing Data Block"; break;
2435 case 0x723: data_block
= "DisplayID Type VIII Video Timing Data Block"; break;
2436 case 0x72a: data_block
= "DisplayID Type X Video Timing Data Block"; break;
2438 case 0x778: data_block
= "HDMI Forum EDID Extension Override Data Block"; break;
2439 case 0x779: data_block
= "HDMI Forum Sink Capability Data Block"; break;
2442 std::string unknown_name
;
2443 if (tag
< 0x700) unknown_name
= "Unknown CTA-861 Data Block";
2444 else if (tag
< 0x70d) unknown_name
= "Unknown CTA-861 Video-Related Data Block";
2445 else if (tag
< 0x720) unknown_name
= "Unknown CTA-861 Audio-Related Data Block";
2446 else if (tag
< 0x778) unknown_name
= "Unknown CTA-861 Data Block";
2447 else if (tag
< 0x780) unknown_name
= "Unknown CTA-861 HDMI-Related Data Block";
2448 else unknown_name
= "Unknown CTA-861 Data Block";
2449 unknown_name
+= std::string(" (") + (extended
? "extended " : "") + "tag " + utohex(tag
& 0xff) + ", length " + std::to_string(length
) + ")";
2450 printf(" %s:\n", unknown_name
.c_str());
2451 warn("%s.\n", unknown_name
.c_str());
2461 data_block_oui(data_block
, x
, length
, &ouinum
);
2462 x
+= (length
< 3) ? length
: 3;
2463 length
-= (length
< 3) ? length
: 3;
2464 dooutputname
= false;
2470 if (dooutputname
&& data_block
.length())
2471 printf(" %s:\n", data_block
.c_str());
2487 if (std::find(found_tags
.begin(), found_tags
.end(), tag
) != found_tags
.end())
2488 fail("Only one instance of this Data Block is allowed.\n");
2492 // See Table 52 of CTA-861-G for a description of Byte 3
2493 if (audio_block
&& !(cta
.byte3
& 0x40))
2494 fail("Audio information is present, but bit 6 of Byte 3 of the CTA-861 Extension header indicates no Basic Audio support.\n");
2497 case 0x01: cta_audio_block(x
, length
); break;
2498 case 0x02: cta_svd(x
, length
, false); break;
2499 case 0x03|kOUI_HDMI
:
2500 cta_hdmi_block(x
, length
);
2501 // The HDMI OUI is present, so this EDID represents an HDMI
2502 // interface. And HDMI interfaces must use EDID version 1.3
2503 // according to the HDMI Specification, so check for this.
2504 if (base
.edid_minor
!= 3)
2505 fail("The HDMI Specification requires EDID 1.3 instead of 1.%u.\n",
2508 case 0x03|kOUI_HDMIForum
:
2509 if (cta
.previous_cta_tag
!= (0x03|kOUI_HDMI
))
2510 fail("HDMI Forum VSDB did not immediately follow the HDMI VSDB.\n");
2511 if (cta
.have_hf_scdb
|| cta
.have_hf_vsdb
)
2512 fail("Duplicate HDMI Forum VSDB/SCDB.\n");
2513 cta_hf_scdb(x
, length
);
2514 cta
.have_hf_vsdb
= true;
2516 case 0x03|kOUI_AMD
: cta_amd(x
, length
); break;
2517 case 0x03|kOUI_Microsoft
: if (length
!= 0x12) goto dodefault
; cta_microsoft(x
, length
); break;
2518 case 0x04: cta_sadb(x
, length
); break;
2519 case 0x05: cta_vesa_dtcdb(x
, length
); break;
2520 case 0x06: cta_vfdb(x
, length
); break;
2521 case 0x07: fail("Extended tag cannot have zero length.\n"); break;
2522 case 0x700: cta_vcdb(x
, length
); break;
2523 case 0x701|kOUI_HDR10
: cta_hdr10plus(x
, length
); break;
2524 case 0x701|kOUI_Dolby
: cta_dolby_video(x
, length
); break;
2525 // 0x701|kOUI_Apple: this almost certainly contains 'BLC Info/Corrections',
2526 // since the data (spread out over two VSDBs) is very similar to what is seen
2527 // in DisplayID blocks. Since I don't know how to parse this data, we still
2528 // default to a hex dump, but I mention this here in case data on how to
2529 // parse this becomes available.
2530 case 0x702: cta_vesa_vdddb(x
, length
); break;
2531 case 0x705: cta_colorimetry_block(x
, length
); break;
2532 case 0x706: cta_hdr_static_metadata_block(x
, length
); break;
2533 case 0x707: cta_hdr_dyn_metadata_block(x
, length
); break;
2534 case 0x708: cta_nvrdb(x
, length
); return;
2535 case 0x70d: cta_vfpdb(x
, length
); break;
2536 case 0x70e: cta_svd(x
, length
, true); break;
2537 case 0x70f: cta_y420cmdb(x
, length
); break;
2538 case 0x711|kOUI_Dolby
: cta_dolby_audio(x
, length
); break;
2539 case 0x712: cta_hdmi_audio_block(x
, length
); break;
2540 case 0x713: cta_rcdb(x
, length
); break;
2541 case 0x714: cta_sldb(x
, length
); break;
2542 case 0x720: cta_ifdb(x
, length
); break;
2543 case 0x722: cta_displayid_type_7(x
, length
); break;
2544 case 0x723: cta_displayid_type_8(x
, length
); break;
2545 case 0x72a: cta_displayid_type_10(x
, length
); break;
2547 cta_hf_eeodb(x
, length
);
2549 fail("Data Block can only be present in Block 1.\n");
2550 // This must be the first CTA-861 block
2551 if (cta
.block_number
> 0)
2552 fail("Data Block starts at a wrong offset.\n");
2555 if (cta
.previous_cta_tag
!= (0x03|kOUI_HDMI
))
2556 fail("HDMI Forum SCDB did not immediately follow the HDMI VSDB.\n");
2557 if (cta
.have_hf_scdb
|| cta
.have_hf_vsdb
)
2558 fail("Duplicate HDMI Forum VSDB/SCDB.\n");
2560 data_block
= std::string("HDMI Forum SCDB");
2561 fail("Invalid length %u < 2.\n", length
);
2565 printf(" Non-zero SCDB reserved fields!\n");
2566 cta_hf_scdb(x
+ 2, length
- 2);
2567 cta
.have_hf_scdb
= true;
2571 hex_block(" ", x
, length
);
2576 cta
.previous_cta_tag
= tag
;
2577 found_tags
.push_back(tag
);
2580 void edid_state::preparse_cta_block(unsigned char *x
)
2582 unsigned version
= x
[1];
2583 unsigned offset
= x
[2];
2586 const unsigned char *detailed
;
2588 for (detailed
= x
+ offset
; detailed
+ 17 < x
+ 127; detailed
+= 18) {
2589 if (memchk(detailed
, 18))
2591 if (detailed
[0] || detailed
[1])
2592 cta
.preparsed_total_dtds
++;
2599 for (unsigned i
= 4; i
< offset
; i
+= (x
[i
] & 0x1f) + 1) {
2600 bool for_ycbcr420
= false;
2603 switch ((x
[i
] & 0xe0) >> 5) {
2605 oui
= (x
[i
+ 3] << 16) + (x
[i
+ 2] << 8) + x
[i
+ 1];
2606 if (oui
== 0x000c03) {
2607 cta
.has_hdmi
= true;
2608 cta
.preparsed_phys_addr
= (x
[i
+ 4] << 8) | x
[i
+ 5];
2609 } else if ((oui
== 0xca125c || oui
== 0x5c12ca) &&
2610 (x
[i
] & 0x1f) == 0x15 && replace_unique_ids
) {
2611 memset(x
+ i
+ 6, 0, 16);
2612 replace_checksum(x
, EDID_PAGE_SIZE
);
2616 if (!(x
[i
] & 0x1f) || cta
.preparsed_first_vfd
.rid
)
2618 cta
.preparsed_first_vfd
= cta_parse_vfd(x
+ i
+ 2, (x
[i
+ 1] & 3) + 1);
2621 if (x
[i
+ 1] == 0x0d)
2622 cta
.has_vfpdb
= true;
2623 else if (x
[i
+ 1] == 0x05)
2625 else if (x
[i
+ 1] == 0x08)
2626 cta
.has_nvrdb
= true;
2627 else if (x
[i
+ 1] == 0x13 && (x
[i
+ 2] & 0x40)) {
2628 cta
.preparsed_speaker_count
= 1 + (x
[i
+ 2] & 0x1f);
2629 cta
.preparsed_sld
= x
[i
+ 2] & 0x20;
2630 } else if (x
[i
+ 1] == 0x14)
2631 cta_preparse_sldb(x
+ i
+ 2, (x
[i
] & 0x1f) - 1);
2632 else if (x
[i
+ 1] == 0x22)
2633 cta
.preparsed_total_vtdbs
++;
2634 else if (x
[i
+ 1] == 0x23) {
2635 cta
.preparsed_has_t8vtdb
= true;
2636 cta
.preparsed_t8vtdb_dmt
= x
[i
+ 3];
2637 if (x
[i
+ 2] & 0x08)
2638 cta
.preparsed_t8vtdb_dmt
|= x
[i
+ 4] << 8;
2639 } else if (x
[i
+ 1] == 0x2a)
2640 cta
.preparsed_total_vtdbs
+=
2641 ((x
[i
] & 0x1f) - 2) / (6 + ((x
[i
+ 2] & 0x70) >> 4));
2642 else if (x
[i
+ 1] == 0x78)
2643 cta
.hf_eeodb_blocks
= x
[i
+ 2];
2644 if (x
[i
+ 1] != 0x0e)
2646 for_ycbcr420
= true;
2647 #ifdef __EMSCRIPTEN__
2648 [[clang::fallthrough
]];
2652 for (unsigned j
= 1 + for_ycbcr420
; j
<= (x
[i
] & 0x1f); j
++) {
2653 unsigned char vic
= x
[i
+ j
];
2655 if ((vic
& 0x7f) <= 64)
2657 cta
.preparsed_svds
[for_ycbcr420
].push_back(vic
);
2658 cta
.preparsed_has_vic
[for_ycbcr420
][vic
] = true;
2665 void edid_state::parse_cta_block(const unsigned char *x
)
2667 unsigned version
= x
[1];
2668 unsigned offset
= x
[2];
2669 const unsigned char *detailed
;
2671 // See Table 52 of CTA-861-G for a description of Byte 3
2673 printf(" Revision: %u\n", version
);
2675 fail("Invalid CTA-861 Extension revision 0.\n");
2677 fail("Deprecated CTA-861 Extension revision 2.\n");
2678 if (cta
.has_hdmi
&& version
!= 3)
2679 fail("The HDMI Specification requires CTA Extension revision 3.\n");
2681 warn("Unknown CTA-861 Extension revision %u.\n", version
);
2683 if (version
>= 1) do {
2684 if (version
== 1 && x
[3] != 0)
2685 fail("Non-zero byte 3.\n");
2690 if (version
< 3 && ((offset
- 4) / 8)) {
2691 printf(" 8-byte timing descriptors: %u\n", (offset
- 4) / 8);
2692 fail("8-byte descriptors were never used.\n");
2697 printf(" Underscans IT Video Formats by default\n");
2699 warn("IT Video Formats are overscanned by default, but normally this should be underscanned.\n");
2701 printf(" Basic audio support\n");
2703 printf(" Supports YCbCr 4:4:4\n");
2705 printf(" Supports YCbCr 4:2:2\n");
2706 // Disable this test: this fails a lot of EDIDs, and there are
2707 // also some corner cases where you only want to receive 4:4:4
2708 // and refuse a fallback to 4:2:2.
2709 // if ((x[3] & 0x30) && (x[3] & 0x30) != 0x30)
2710 // msg(!cta.has_hdmi, "If YCbCr support is indicated, then both 4:2:2 and 4:4:4 %s be supported.\n",
2711 // cta.has_hdmi ? "shall" : "should");
2712 printf(" Native detailed modes: %u\n", x
[3] & 0x0f);
2713 if (cta
.block_number
== 0)
2715 else if (x
[3] != cta
.byte3
)
2716 fail("Byte 3 must be the same for all CTA-861 Extension Blocks.\n");
2717 if (cta
.block_number
== 0) {
2718 unsigned native_dtds
= x
[3] & 0x0f;
2720 cta
.native_timings
.clear();
2721 if (!native_dtds
&& !cta
.has_vfpdb
) {
2722 cta
.first_svd_might_be_preferred
= true;
2723 } else if (native_dtds
> cta
.preparsed_total_dtds
) {
2724 fail("There are more Native DTDs (%u) than DTDs (%u).\n",
2725 native_dtds
, cta
.preparsed_total_dtds
);
2727 if (native_dtds
> cta
.preparsed_total_dtds
)
2728 native_dtds
= cta
.preparsed_total_dtds
;
2729 for (unsigned i
= 0; i
< native_dtds
; i
++) {
2732 sprintf(type
, "DTD %3u", i
+ 1);
2733 cta
.native_timings
.push_back(timings_ext(i
+ 129, type
));
2735 if (cta
.has_hdmi
&& block_nr
!= (block_map
.saw_block_1
? 2 : 1))
2736 fail("The HDMI Specification requires that the first Extension Block (that is not a Block Map) is an CTA-861 Extension Block.\n");
2742 for (i
= 4; i
< offset
; i
+= (x
[i
] & 0x1f) + 1) {
2743 cta_block(x
+ i
, cta
.found_tags
);
2748 fail("Offset is %u, but should be %u.\n", offset
, i
);
2751 data_block
= "Detailed Timing Descriptors";
2752 base
.seen_non_detailed_descriptor
= false;
2754 for (detailed
= x
+ offset
; detailed
+ 17 < x
+ 127; detailed
+= 18) {
2755 if (memchk(detailed
, 18))
2759 printf(" %s:\n", data_block
.c_str());
2761 detailed_block(detailed
);
2763 unused_bytes
= x
+ 127 - detailed
;
2764 if (!memchk(detailed
, unused_bytes
)) {
2765 data_block
= "Padding";
2766 fail("Contains non-zero bytes.\n");
2771 if (base
.has_serial_number
&& base
.has_serial_string
)
2772 warn("Display Product Serial Number is set, so the Serial Number in the Base EDID should be 0.\n");
2773 if (!cta
.has_vic_1
&& !base
.has_640x480p60_est_timing
)
2774 fail("Required 640x480p60 timings are missing in the established timings"
2775 " and the SVD list (VIC 1).\n");
2776 if ((cta
.supported_hdmi_vic_vsb_codes
& cta
.supported_hdmi_vic_codes
) !=
2777 cta
.supported_hdmi_vic_codes
)
2778 fail("HDMI VIC Codes must have their CTA-861 VIC equivalents in the VSB.\n");
2780 fail("Missing VCDB, needed for Set Selectable RGB Quantization to avoid interop issues.\n");
2781 if (!base
.uses_srgb
&& !cta
.has_cdb
)
2782 warn("Add a Colorimetry Data Block with the sRGB colorimetry bit set to avoid interop issues.\n");
2785 void edid_state::cta_resolve_svr(timings_ext
&t_ext
)
2787 if (t_ext
.svr() == 254) {
2788 t_ext
.flags
= cta
.t8vtdb
.flags
;
2789 add_str(t_ext
.flags
, ">=CTA-861-H");
2790 t_ext
.t
= cta
.t8vtdb
.t
;
2791 } else if (t_ext
.svr() <= 144) {
2792 t_ext
.flags
= cta
.vec_dtds
[t_ext
.svr() - 129].flags
;
2793 t_ext
.t
= cta
.vec_dtds
[t_ext
.svr() - 129].t
;
2794 } else if (t_ext
.svr() <= 160) {
2795 t_ext
.flags
= cta
.vec_vtdbs
[t_ext
.svr() - 145].flags
;
2796 add_str(t_ext
.flags
, ">=CTA-861-H");
2797 t_ext
.t
= cta
.vec_vtdbs
[t_ext
.svr() - 145].t
;
2798 } else if (t_ext
.svr() <= 175) {
2799 t_ext
.flags
.clear();
2800 unsigned char rid
= cta
.preparsed_first_vfd
.rid
;
2801 t_ext
.t
= calc_ovt_mode(rids
[rid
].hact
, rids
[rid
].vact
,
2802 rids
[rid
].hratio
, rids
[rid
].vratio
,
2803 vf_rate_values
[t_ext
.svr() - 160]);
2804 t_ext
.flags
= ">=CTA-861.6";
2808 void edid_state::cta_resolve_svrs()
2810 for (vec_timings_ext::iterator iter
= cta
.preferred_timings_vfpdb
.begin();
2811 iter
!= cta
.preferred_timings_vfpdb
.end(); ++iter
) {
2812 if (iter
->has_svr())
2813 cta_resolve_svr(*iter
);
2816 for (vec_timings_ext::iterator iter
= cta
.native_timings
.begin();
2817 iter
!= cta
.native_timings
.end(); ++iter
) {
2818 if (iter
->has_svr())
2819 cta_resolve_svr(*iter
);
2822 for (vec_timings_ext::iterator iter
= cta
.native_timing_nvrdb
.begin();
2823 iter
!= cta
.native_timing_nvrdb
.end(); ++iter
) {
2824 if (iter
->has_svr())
2825 cta_resolve_svr(*iter
);
2829 void edid_state::check_cta_blocks()
2831 unsigned max_pref_prog_hact
= 0;
2832 unsigned max_pref_prog_vact
= 0;
2833 unsigned max_pref_ilace_hact
= 0;
2834 unsigned max_pref_ilace_vact
= 0;
2836 data_block
= "CTA-861";
2837 for (vec_timings_ext::iterator iter
= cta
.preferred_timings
.begin();
2838 iter
!= cta
.preferred_timings
.end(); ++iter
) {
2839 if (iter
->t
.interlaced
&&
2840 (iter
->t
.vact
> max_pref_ilace_vact
||
2841 (iter
->t
.vact
== max_pref_ilace_vact
&& iter
->t
.hact
>= max_pref_ilace_hact
))) {
2842 max_pref_ilace_hact
= iter
->t
.hact
;
2843 max_pref_ilace_vact
= iter
->t
.vact
;
2845 if (!iter
->t
.interlaced
&&
2846 (iter
->t
.vact
> max_pref_prog_vact
||
2847 (iter
->t
.vact
== max_pref_prog_vact
&& iter
->t
.hact
>= max_pref_prog_hact
))) {
2848 max_pref_prog_hact
= iter
->t
.hact
;
2849 max_pref_prog_vact
= iter
->t
.vact
;
2852 for (vec_timings_ext::iterator iter
= cta
.preferred_timings_vfpdb
.begin();
2853 iter
!= cta
.preferred_timings_vfpdb
.end(); ++iter
) {
2854 if (iter
->t
.interlaced
&&
2855 (iter
->t
.vact
> max_pref_ilace_vact
||
2856 (iter
->t
.vact
== max_pref_ilace_vact
&& iter
->t
.hact
>= max_pref_ilace_hact
))) {
2857 max_pref_ilace_hact
= iter
->t
.hact
;
2858 max_pref_ilace_vact
= iter
->t
.vact
;
2860 if (!iter
->t
.interlaced
&&
2861 (iter
->t
.vact
> max_pref_prog_vact
||
2862 (iter
->t
.vact
== max_pref_prog_vact
&& iter
->t
.hact
>= max_pref_prog_hact
))) {
2863 max_pref_prog_hact
= iter
->t
.hact
;
2864 max_pref_prog_vact
= iter
->t
.vact
;
2868 unsigned native_prog
= 0;
2869 unsigned native_prog_hact
= 0;
2870 unsigned native_prog_vact
= 0;
2871 bool native_prog_mixed_resolutions
= false;
2872 unsigned native_ilace
= 0;
2873 unsigned native_ilace_hact
= 0;
2874 unsigned native_ilace_vact
= 0;
2875 bool native_ilace_mixed_resolutions
= false;
2876 unsigned native_nvrdb_hact
= 0;
2877 unsigned native_nvrdb_vact
= 0;
2879 for (vec_timings_ext::iterator iter
= cta
.native_timings
.begin();
2880 iter
!= cta
.native_timings
.end(); ++iter
) {
2881 if (iter
->t
.interlaced
) {
2883 if (!native_ilace_hact
) {
2884 native_ilace_hact
= iter
->t
.hact
;
2885 native_ilace_vact
= iter
->t
.vact
;
2886 } else if (native_ilace_hact
!= iter
->t
.hact
||
2887 native_ilace_vact
!= iter
->t
.vact
) {
2888 native_ilace_mixed_resolutions
= true;
2892 if (!native_prog_hact
) {
2893 native_prog_hact
= iter
->t
.hact
;
2894 native_prog_vact
= iter
->t
.vact
;
2895 } else if (native_prog_hact
!= iter
->t
.hact
||
2896 native_prog_vact
!= iter
->t
.vact
) {
2897 native_prog_mixed_resolutions
= true;
2902 for (vec_timings_ext::iterator iter
= cta
.native_timing_nvrdb
.begin();
2903 iter
!= cta
.native_timing_nvrdb
.end(); ++iter
) {
2904 native_nvrdb_hact
= iter
->t
.hact
;
2905 native_nvrdb_vact
= iter
->t
.vact
;
2908 if (native_prog_mixed_resolutions
)
2909 fail("Native progressive timings are a mix of several resolutions.\n");
2910 if (native_ilace_mixed_resolutions
)
2911 fail("Native interlaced timings are a mix of several resolutions.\n");
2912 if (native_ilace
&& !native_prog
)
2913 fail("A native interlaced timing is present, but not a native progressive timing.\n");
2914 if (!native_prog_mixed_resolutions
&& native_prog
> 1)
2915 warn("Multiple native progressive timings are defined.\n");
2916 if (!native_ilace_mixed_resolutions
&& native_ilace
> 1)
2917 warn("Multiple native interlaced timings are defined.\n");
2919 if (native_nvrdb_vact
&&
2920 (max_pref_prog_vact
> native_nvrdb_vact
||
2921 (max_pref_prog_vact
== native_nvrdb_vact
&& max_pref_prog_hact
> native_nvrdb_hact
)))
2922 warn("Native video resolution of %ux%u is smaller than the max preferred progressive resolution %ux%u.\n",
2923 native_nvrdb_hact
, native_nvrdb_vact
,
2924 max_pref_prog_hact
, max_pref_prog_vact
);
2925 else if (!native_nvrdb_vact
&& !native_prog_mixed_resolutions
&& native_prog_vact
&&
2926 (max_pref_prog_vact
> native_prog_vact
||
2927 (max_pref_prog_vact
== native_prog_vact
&& max_pref_prog_hact
> native_prog_hact
)))
2928 warn("Native progressive resolution of %ux%u is smaller than the max preferred progressive resolution %ux%u.\n",
2929 native_prog_hact
, native_prog_vact
,
2930 max_pref_prog_hact
, max_pref_prog_vact
);
2931 if (!native_ilace_mixed_resolutions
&& native_ilace_vact
&&
2932 (max_pref_ilace_vact
> native_ilace_vact
||
2933 (max_pref_ilace_vact
== native_ilace_vact
&& max_pref_ilace_hact
> native_ilace_hact
)))
2934 warn("Native interlaced resolution of %ux%u is smaller than the max preferred interlaced resolution %ux%u.\n",
2935 native_ilace_hact
, native_ilace_vact
,
2936 max_pref_ilace_hact
, max_pref_ilace_vact
);
2938 if (dispid
.native_width
&& native_prog_hact
&&
2939 !native_prog_mixed_resolutions
) {
2940 if (dispid
.native_width
!= native_prog_hact
||
2941 dispid
.native_height
!= native_prog_vact
)
2942 fail("Mismatch between CTA-861 and DisplayID native progressive resolution.\n");