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 bool cta_matches_vic(const timings
&t
, unsigned &vic
)
324 for (vic
= 1; vic
<= ARRAY_SIZE(edid_cta_modes1
); vic
++) {
325 if (match_timings(t
, edid_cta_modes1
[vic
- 1]))
328 for (vic
= 193; vic
< ARRAY_SIZE(edid_cta_modes2
) + 193; vic
++) {
329 if (match_timings(t
, edid_cta_modes1
[vic
- 193]))
336 void edid_state::cta_list_vics()
339 for (unsigned vic
= 1; vic
<= ARRAY_SIZE(edid_cta_modes1
); vic
++) {
340 sprintf(type
, "VIC %3u", vic
);
341 print_timings("", &edid_cta_modes1
[vic
- 1], type
, "", false, false);
343 for (unsigned vic
= 193; vic
< ARRAY_SIZE(edid_cta_modes2
) + 193; vic
++) {
344 sprintf(type
, "VIC %3u", vic
);
345 print_timings("", &edid_cta_modes2
[vic
- 193], type
, "", false, false);
349 void edid_state::cta_list_hdmi_vics()
351 for (unsigned i
= 0; i
< ARRAY_SIZE(edid_hdmi_mode_map
); i
++) {
352 unsigned vic
= edid_hdmi_mode_map
[i
];
355 sprintf(type
, "HDMI VIC %u", i
+ 1);
356 print_timings("", find_vic_id(vic
), type
, "", false, false);
360 void edid_state::cta_list_rids()
362 for (unsigned i
= 1; i
< ARRAY_SIZE(rids
); i
++) {
363 printf("RID %2u: %5ux%-4u %2u:%-2u\n", i
,
364 rids
[i
].hact
, rids
[i
].vact
,
365 rids
[i
].hratio
, rids
[i
].vratio
);
369 void edid_state::cta_list_rid_timings(unsigned list_rid
)
371 for (unsigned rid
= 1; rid
< ARRAY_SIZE(rids
); rid
++) {
374 if (list_rid
&& rid
!= list_rid
)
377 sprintf(type
, "RID %u", rid
);
378 for (unsigned i
= 1; i
< ARRAY_SIZE(vf_rate_values
); i
++) {
379 unsigned fps
= vf_rate_values
[i
];
381 if (rid_to_vic(rid
, i
)) {
382 printf("%s: %5ux%-4u %7.3f Hz %3u:%-2u maps to VIC %u\n", type
,
383 rids
[rid
].hact
, rids
[rid
].vact
, (double)fps
,
384 rids
[rid
].hratio
, rids
[rid
].vratio
,
388 timings t
= calc_ovt_mode(rids
[rid
].hact
, rids
[rid
].vact
,
389 rids
[rid
].hratio
, rids
[rid
].vratio
, fps
);
390 print_timings("", &t
, type
, "", false, false);
395 static std::string
audio_ext_format(unsigned char x
)
397 if (x
>= 1 && x
<= 3)
398 fail("Obsolete Audio Ext Format 0x%02x.\n", x
);
400 case 1: return "HE AAC (Obsolete)";
401 case 2: return "HE AAC v2 (Obsolete)";
402 case 3: return "MPEG Surround (Obsolete)";
403 case 4: return "MPEG-4 HE AAC";
404 case 5: return "MPEG-4 HE AAC v2";
405 case 6: return "MPEG-4 AAC LC";
406 case 7: return "DRA";
407 case 8: return "MPEG-4 HE AAC + MPEG Surround";
408 case 10: return "MPEG-4 AAC LC + MPEG Surround";
409 case 11: return "MPEG-H 3D Audio";
410 case 12: return "AC-4";
411 case 13: return "L-PCM 3D Audio";
412 case 14: return "Auro-Cx";
413 case 15: return "MPEG-D USAC";
416 fail("Unknown Audio Ext Format 0x%02x.\n", x
);
417 return std::string("Unknown Audio Ext Format (") + utohex(x
) + ")";
420 static std::string
audio_format(unsigned char x
)
423 case 1: return "Linear PCM";
424 case 2: return "AC-3";
425 case 3: return "MPEG 1 (Layers 1 & 2)";
426 case 4: return "MPEG 1 Layer 3 (MP3)";
427 case 5: return "MPEG2 (multichannel)";
428 case 6: return "AAC LC";
429 case 7: return "DTS";
430 case 8: return "ATRAC";
431 case 9: return "One Bit Audio";
432 case 10: return "Enhanced AC-3 (DD+)";
433 case 11: return "DTS-HD";
434 case 12: return "MAT (MLP)";
435 case 13: return "DST";
436 case 14: return "WMA Pro";
439 fail("Unknown Audio Format 0x%02x.\n", x
);
440 return std::string("Unknown Audio Format (") + utohex(x
) + ")";
443 static std::string
mpeg_h_3d_audio_level(unsigned char x
)
446 case 0: return "Unspecified";
447 case 1: return "Level 1";
448 case 2: return "Level 2";
449 case 3: return "Level 3";
450 case 4: return "Level 4";
451 case 5: return "Level 5";
454 fail("Unknown MPEG-H 3D Audio Level 0x%02x.\n", x
);
455 return std::string("Unknown MPEG-H 3D Audio Level (") + utohex(x
) + ")";
458 static void cta_audio_block(const unsigned char *x
, unsigned length
)
460 unsigned i
, format
, ext_format
;
463 fail("Broken CTA-861 audio block length %d.\n", length
);
467 for (i
= 0; i
< length
; i
+= 3) {
468 format
= (x
[i
] & 0x78) >> 3;
470 printf(" Reserved (0x00)\n");
471 fail("Audio Format Code 0x00 is reserved.\n");
476 printf(" %s:\n", audio_format(format
).c_str());
478 ext_format
= (x
[i
+ 2] & 0xf8) >> 3;
479 printf(" %s:\n", audio_ext_format(ext_format
).c_str());
482 printf(" Max channels: %u\n", (x
[i
] & 0x07)+1);
483 else if (ext_format
== 11)
484 printf(" MPEG-H 3D Audio Level: %s\n",
485 mpeg_h_3d_audio_level(x
[i
] & 0x07).c_str());
486 else if (ext_format
== 13)
487 printf(" Max channels: %u\n",
488 (((x
[i
+ 1] & 0x80) >> 3) | ((x
[i
] & 0x80) >> 4) |
490 else if ((ext_format
== 12 || ext_format
== 14) && (x
[i
] & 0x07))
491 fail("Bits F10-F12 must be 0.\n");
493 printf(" Max channels: %u\n", (x
[i
] & 0x07)+1);
495 if ((format
== 1 || format
== 14) && (x
[i
+ 2] & 0xf8))
496 fail("Bits F33-F37 must be 0.\n");
497 if (ext_format
!= 13 && (x
[i
+1] & 0x80))
498 fail("Bit F27 must be 0.\n");
500 // Several sample rates are not supported in certain formats
501 if (ext_format
== 12 && (x
[i
+1] & 0x29))
502 fail("Bits F20, F23 and F25 must be 0.\n");
503 if (ext_format
>= 4 && ext_format
<= 6 && (x
[i
+1] & 0x60))
504 fail("Bits F25 and F26 must be 0.\n");
505 if ((ext_format
== 8 || ext_format
== 10 || ext_format
== 15) && (x
[i
+1] & 0x60))
506 fail("Bits F25 and F26 must be 0.\n");
508 printf(" Supported sample rates (kHz):%s%s%s%s%s%s%s\n",
509 (x
[i
+1] & 0x40) ? " 192" : "",
510 (x
[i
+1] & 0x20) ? " 176.4" : "",
511 (x
[i
+1] & 0x10) ? " 96" : "",
512 (x
[i
+1] & 0x08) ? " 88.2" : "",
513 (x
[i
+1] & 0x04) ? " 48" : "",
514 (x
[i
+1] & 0x02) ? " 44.1" : "",
515 (x
[i
+1] & 0x01) ? " 32" : "");
516 if (format
== 1 || ext_format
== 13) {
517 printf(" Supported sample sizes (bits):%s%s%s\n",
518 (x
[i
+2] & 0x04) ? " 24" : "",
519 (x
[i
+2] & 0x02) ? " 20" : "",
520 (x
[i
+2] & 0x01) ? " 16" : "");
521 } else if (format
<= 8) {
522 printf(" Maximum bit rate: %u kb/s\n", x
[i
+2] * 8);
523 } else if (format
== 10) {
524 // As specified by the "Dolby Audio and Dolby Atmos over HDMI"
525 // specification (v1.0).
527 printf(" Supports Joint Object Coding\n");
529 printf(" Supports Joint Object Coding with ACMOD28\n");
530 } else if (format
== 11) {
531 // Reverse engineering, see:
532 // https://www.avsforum.com/threads/lg-c9-earc-info-thread.3072900/post-61795538
534 printf(" Supports DTS:X\n");
535 // Note: I strongly suspect that bit 0 indicates DTS-HD MA support.
536 printf(" Audio Format Code dependent value: 0x%02x\n", x
[i
+2]);
537 } else if (format
== 12) {
539 printf(" Supports Dolby TrueHD, object audio PCM and channel-based PCM\n");
540 printf(" Hash calculation %srequired for object audio PCM or channel-based PCM\n",
541 (x
[i
+2] & 2) ? "not " : "");
543 printf(" Supports only Dolby TrueHD\n");
545 } else if (format
== 14) {
546 printf(" Profile: %u\n", x
[i
+2] & 7);
547 } else if (format
>= 9 && format
<= 13) {
548 printf(" Audio Format Code dependent value: 0x%02x\n", x
[i
+2]);
549 } else if (ext_format
== 11 && (x
[i
+2] & 1)) {
550 printf(" Supports MPEG-H 3D Audio Low Complexity Profile\n");
551 } else if ((ext_format
>= 4 && ext_format
<= 6) ||
552 ext_format
== 8 || ext_format
== 10) {
553 printf(" AAC audio frame lengths:%s%s\n",
554 (x
[i
+2] & 4) ? " 1024_TL" : "",
555 (x
[i
+2] & 2) ? " 960_TL" : "");
556 if (ext_format
>= 8 && (x
[i
+2] & 1))
557 printf(" Supports %s signaled MPEG Surround data\n",
558 (x
[i
+2] & 1) ? "implicitly and explicitly" : "only implicitly");
559 if (ext_format
== 6 && (x
[i
+2] & 1))
560 printf(" Supports 22.2ch System H\n");
561 } else if (ext_format
== 12 || ext_format
== 14) {
562 printf(" Audio Format Code dependent value: %u\n", x
[i
+2] & 7);
567 void edid_state::cta_svd(const unsigned char *x
, unsigned n
, bool for_ycbcr420
)
569 bool ascending
= !for_ycbcr420
;
570 unsigned char last_vic
= 0;
571 bool first_vic_is_1_to_4
= false;
572 bool have_vics_5_and_up
= false;
575 for (i
= 0; i
< n
; i
++) {
576 const struct timings
*t
= NULL
;
577 unsigned char svd
= x
[i
];
578 unsigned char native
;
581 if ((svd
& 0x7f) == 0)
584 if ((svd
- 1) & 0x40) {
593 first_vic_is_1_to_4
= vic
<= 4;
595 have_vics_5_and_up
= true;
600 t
= find_vic_id(vic
);
604 cta
.supported_hdmi_vic_vsb_codes
|= 1 << 0;
607 cta
.supported_hdmi_vic_vsb_codes
|= 1 << 1;
610 cta
.supported_hdmi_vic_vsb_codes
|= 1 << 2;
613 cta
.supported_hdmi_vic_vsb_codes
|= 1 << 3;
616 bool first_svd
= cta
.first_svd
&& !for_ycbcr420
;
617 bool override_pref
= first_svd
&& cta
.first_svd_might_be_preferred
;
620 sprintf(type
, "VIC %3u", vic
);
621 const char *flags
= native
? "native" : "";
624 struct timings tmp
= *t
;
626 print_timings(" ", &tmp
, type
, flags
);
628 print_timings(" ", t
, type
, flags
);
631 if (!cta
.preferred_timings
.empty()) {
632 if (match_timings(cta
.preferred_timings
[0].t
, *t
))
633 warn("For improved preferred timing interoperability, set 'Native detailed modes' to 1.\n");
635 warn("VIC %u is the preferred timing, overriding the first detailed timings. Is this intended?\n", vic
);
637 cta
.preferred_timings
.insert(cta
.preferred_timings
.begin(),
638 timings_ext(*t
, type
, flags
));
639 } else if (first_svd
) {
640 cta
.preferred_timings
.push_back(timings_ext(*t
, type
, flags
));
643 cta
.first_svd
= false;
644 cta
.first_svd_might_be_preferred
= false;
647 cta
.native_timings
.push_back(timings_ext(*t
, type
, flags
));
649 printf(" Unknown (VIC %3u)\n", vic
);
650 fail("Unknown VIC %u.\n", vic
);
653 if (vic
== 1 && !for_ycbcr420
)
655 if (++cta
.vics
[vic
][for_ycbcr420
] == 2)
656 fail("Duplicate %sVIC %u.\n", for_ycbcr420
? "YCbCr 4:2:0 " : "", vic
);
657 if (for_ycbcr420
&& cta
.preparsed_has_vic
[0][vic
])
658 fail("YCbCr 4:2:0-only VIC %u is also a regular VIC.\n", vic
);
660 if (n
> 1 && ascending
&& first_vic_is_1_to_4
&& have_vics_5_and_up
)
661 warn("All VICs are in ascending order, and the first (preferred) VIC <= 4, is that intended?\n");
664 cta_vfd
edid_state::cta_parse_vfd(const unsigned char *x
, unsigned lvfd
)
668 vfd
.rid
= x
[0] & 0x3f;
669 if (vfd
.rid
>= ARRAY_SIZE(rids
)) {
673 vfd
.bfr50
= !!(x
[0] & 0x80);
674 vfd
.fr24
= !!(x
[0] & 0x40);
675 vfd
.bfr60
= lvfd
> 1 ? !!(x
[1] & 0x80) : 1;
676 vfd
.fr144
= lvfd
> 1 ? !!(x
[1] & 0x40) : 0;
677 vfd
.fr_factor
= lvfd
> 1 ? (x
[1] & 0x3f) : 3;
678 vfd
.fr48
= lvfd
> 2 ? !!(x
[2] & 0x01) : 0;
682 static bool vfd_has_rate(cta_vfd
&vfd
, unsigned rate_index
)
684 static const unsigned factors
[6] = {
687 unsigned rate
= vf_rate_values
[rate_index
];
710 for (unsigned i
= 0; i
< ARRAY_SIZE(factors
); i
++)
711 if (factors
[i
] == factor
&& (vfd
.fr_factor
& (1 << i
)))
716 void edid_state::cta_vfdb(const unsigned char *x
, unsigned n
)
719 fail("Length is 0.\n");
722 unsigned char flags
= *x
++;
723 unsigned lvfd
= (flags
& 3) + 1;
726 fail("Length - 1 is not a multiple of Lvfd (%u).\n", lvfd
);
730 printf(" Supports YCbCr 4:2:0\n");
732 printf(" NTSC fractional frame rates are preferred\n");
733 for (unsigned i
= 0; i
< n
; i
+= lvfd
, x
+= lvfd
) {
734 unsigned char rid
= x
[0] & 0x3f;
735 cta_vfd vfd
= cta_parse_vfd(x
, lvfd
);
737 if (lvfd
> 2 && (x
[2] & 0xfe))
738 fail("Bits F31-F37 must be 0.\n");
739 if (lvfd
> 3 && x
[3])
740 fail("Bits F40-F47 must be 0.\n");
741 if (rid
== 0 || rid
>= ARRAY_SIZE(rids
)) {
742 fail("Unknown RID %u.\n", rid
);
745 for (unsigned rate_index
= 1; rate_index
< ARRAY_SIZE(vf_rate_values
); rate_index
++) {
746 if (!vfd_has_rate(vfd
, rate_index
))
748 struct timings t
= calc_ovt_mode(rids
[vfd
.rid
].hact
,
750 rids
[vfd
.rid
].hratio
,
751 rids
[vfd
.rid
].vratio
,
752 vf_rate_values
[rate_index
]);
754 sprintf(type
, "RID %u@%up", rid
, vf_rate_values
[rate_index
]);
755 print_timings(" ", &t
, type
);
756 if (rid_to_vic(vfd
.rid
, rate_index
))
757 fail("%s not allowed since it maps to VIC %u.\n",
758 type
, rid_to_vic(vfd
.rid
, rate_index
));
763 void edid_state::print_vic_index(const char *prefix
, unsigned idx
, const char *suffix
, bool ycbcr420
)
767 if (idx
< cta
.preparsed_svds
[0].size()) {
768 unsigned char vic
= cta
.preparsed_svds
[0][idx
];
769 const struct timings
*t
= find_vic_id(vic
);
772 sprintf(buf
, "VIC %3u", vic
);
775 struct timings tmp
= *t
;
776 tmp
.ycbcr420
= ycbcr420
;
777 print_timings(prefix
, &tmp
, buf
, suffix
);
779 printf("%sUnknown (%s%s%s)\n", prefix
, buf
,
780 *suffix
? ", " : "", suffix
);
783 // Should not happen!
784 printf("%sSVD Index %u is out of range", prefix
, idx
+ 1);
786 printf(" (%s)", suffix
);
791 void edid_state::cta_y420cmdb(const unsigned char *x
, unsigned length
)
793 unsigned max_idx
= 0;
797 printf(" All VDB SVDs\n");
801 if (memchk(x
, length
)) {
802 printf(" Empty Capability Map\n");
803 fail("Empty Capability Map.\n");
807 for (i
= 0; i
< length
; i
++) {
808 unsigned char v
= x
[i
];
811 for (j
= 0; j
< 8; j
++) {
815 print_vic_index(" ", i
* 8 + j
, "", true);
817 if (max_idx
< cta
.preparsed_svds
[0].size()) {
818 unsigned vic
= cta
.preparsed_svds
[0][max_idx
];
819 if (cta
.preparsed_has_vic
[1][vic
])
820 fail("VIC %u is also a YCbCr 4:2:0-only VIC.\n", vic
);
824 if (max_idx
>= cta
.preparsed_svds
[0].size())
825 fail("Max index %u > %u (#SVDs).\n",
826 max_idx
+ 1, cta
.preparsed_svds
[0].size());
829 void edid_state::cta_print_svr(unsigned char svr
, vec_timings_ext
&vec_tim
)
833 if ((svr
> 0 && svr
< 128) || (svr
> 192 && svr
< 254)) {
834 const struct timings
*t
;
835 unsigned char vic
= svr
;
837 sprintf(suffix
, "VIC %3u", vic
);
839 t
= find_vic_id(vic
);
841 print_timings(" ", t
, suffix
);
842 vec_tim
.push_back(timings_ext(*t
, suffix
, ""));
844 printf(" %s: Unknown\n", suffix
);
845 fail("Unknown VIC %u.\n", vic
);
848 } else if (svr
>= 129 && svr
<= 144) {
849 sprintf(suffix
, "DTD %3u", svr
- 128);
850 if (svr
>= cta
.preparsed_total_dtds
+ 129) {
851 printf(" %s: Invalid\n", suffix
);
852 fail("Invalid DTD %u.\n", svr
- 128);
854 printf(" %s\n", suffix
);
855 vec_tim
.push_back(timings_ext(svr
, suffix
));
858 } else if (svr
>= 145 && svr
<= 160) {
859 sprintf(suffix
, "VTDB %3u", svr
- 144);
860 if (svr
>= cta
.preparsed_total_vtdbs
+ 145) {
861 printf(" %s: Invalid\n", suffix
);
862 fail("Invalid VTDB %u.\n", svr
- 144);
864 printf(" %s\n", suffix
);
865 vec_tim
.push_back(timings_ext(svr
, suffix
));
868 } else if (svr
>= 161 && svr
<= 175) {
869 sprintf(suffix
, "RID %u@%up",
870 cta
.preparsed_first_vfd
.rid
, vf_rate_values
[svr
- 160]);
871 if (!vfd_has_rate(cta
.preparsed_first_vfd
, svr
- 160)) {
872 printf(" %s: Invalid\n", suffix
);
873 fail("Invalid %s.\n", suffix
);
875 printf(" %s\n", suffix
);
876 vec_tim
.push_back(timings_ext(svr
, suffix
));
879 } else if (svr
== 254) {
880 sprintf(suffix
, "T8VTDB");
881 if (!cta
.preparsed_has_t8vtdb
) {
882 printf(" %s: Invalid\n", suffix
);
883 fail("Invalid T8VTDB.\n");
885 sprintf(suffix
, "DMT 0x%02x", cta
.preparsed_t8vtdb_dmt
);
886 printf(" %s\n", suffix
);
887 vec_tim
.push_back(timings_ext(svr
, suffix
));
893 void edid_state::cta_vfpdb(const unsigned char *x
, unsigned length
)
898 fail("Empty Data Block with length %u.\n", length
);
901 cta
.preferred_timings_vfpdb
.clear();
902 for (i
= 0; i
< length
; i
++)
903 cta_print_svr(x
[i
], cta
.preferred_timings_vfpdb
);
906 void edid_state::cta_nvrdb(const unsigned char *x
, unsigned length
)
909 fail("Empty Data Block with length %u.\n", length
);
913 unsigned char flags
= length
== 1 ? 0 : x
[1];
915 cta
.native_timing_nvrdb
.clear();
916 cta_print_svr(x
[0], cta
.native_timing_nvrdb
);
917 if ((flags
& 1) && length
< 6) {
918 fail("Data Block too short for Image Size (length = %u).\n", length
);
922 fail("Bits F41-F46 must be 0.\n");
926 unsigned w
= (x
[3] << 8) | x
[2];
927 unsigned h
= (x
[5] << 8) | x
[4];
930 fail("Image Size has a zero width and/or height.\n");
933 printf(" Image Size: %ux%u mm\n", w
, h
);
935 printf(" Image Size: %.1fx%.1f mm\n", w
/ 10.0, h
/ 10.0);
938 static std::string
hdmi_latency2s(unsigned char l
, bool is_video
)
943 return is_video
? "Video not supported" : "Audio not supported";
944 return std::to_string(2 * (l
- 1)) + " ms";
947 void edid_state::hdmi_latency(unsigned char vid_lat
, unsigned char aud_lat
,
950 const char *vid
= is_ilaced
? "Interlaced video" : "Video";
951 const char *aud
= is_ilaced
? "Interlaced audio" : "Audio";
953 printf(" %s latency: %s\n", vid
, hdmi_latency2s(vid_lat
, true).c_str());
954 printf(" %s latency: %s\n", aud
, hdmi_latency2s(aud_lat
, false).c_str());
956 if (vid_lat
> 251 && vid_lat
!= 0xff)
957 fail("Invalid %s latency value %u.\n", vid
, vid_lat
);
958 if (aud_lat
> 251 && aud_lat
!= 0xff)
959 fail("Invalid %s latency value %u.\n", aud
, aud_lat
);
961 if (!vid_lat
|| vid_lat
> 251)
963 if (!aud_lat
|| aud_lat
> 251)
966 unsigned vid_ms
= 2 * (vid_lat
- 1);
967 unsigned aud_ms
= 2 * (aud_lat
- 1);
969 // HDMI 2.0 latency checks for devices without HDMI output
971 warn("%s latency < %s latency (%u ms < %u ms). This is discouraged for devices without HDMI output.\n",
972 aud
, vid
, aud_ms
, vid_ms
);
973 else if (vid_ms
+ 20 < aud_ms
)
974 warn("%s latency + 20 < %s latency (%u + 20 ms < %u ms). This is forbidden for devices without HDMI output.\n",
975 vid
, aud
, vid_ms
, aud_ms
);
976 else if (vid_ms
< aud_ms
)
977 warn("%s latency < %s latency (%u ms < %u ms). This is discouraged for devices without HDMI output.\n",
978 vid
, aud
, vid_ms
, aud_ms
);
981 void edid_state::cta_hdmi_block(const unsigned char *x
, unsigned length
)
983 unsigned len_vic
, len_3d
;
986 fail("Empty Data Block with length %u.\n", length
);
989 printf(" Source physical address: %x.%x.%x.%x\n", x
[0] >> 4, x
[0] & 0x0f,
990 x
[1] >> 4, x
[1] & 0x0f);
996 printf(" Supports_AI\n");
998 printf(" DC_48bit\n");
1000 printf(" DC_36bit\n");
1002 printf(" DC_30bit\n");
1004 printf(" DC_Y444\n");
1005 /* two reserved bits */
1007 printf(" DVI_Dual\n");
1012 printf(" Maximum TMDS clock: %u MHz\n", x
[3] * 5);
1014 fail("HDMI VSDB Max TMDS rate is > 340.\n");
1020 printf(" Supported Content Types:\n");
1022 printf(" Graphics\n");
1026 printf(" Cinema\n");
1033 hdmi_latency(x
[b
], x
[b
+ 1], false);
1036 if (x
[b
] == x
[b
+ 2] &&
1037 x
[b
+ 1] == x
[b
+ 3])
1038 warn("Progressive and Interlaced latency values are identical, no need for both.\n");
1040 hdmi_latency(x
[b
], x
[b
+ 1], true);
1049 bool formats
= false;
1051 printf(" Extended HDMI video details:\n");
1053 printf(" 3D present\n");
1054 if ((x
[b
] & 0x60) == 0x20) {
1055 printf(" All advertised VICs are 3D-capable\n");
1058 if ((x
[b
] & 0x60) == 0x40) {
1059 printf(" 3D-capable-VIC mask present\n");
1063 switch (x
[b
] & 0x18) {
1066 printf(" Base EDID image size is aspect ratio\n");
1069 printf(" Base EDID image size is in units of 1 cm\n");
1072 printf(" Base EDID image size is in units of 5 cm\n");
1073 base
.max_display_width_mm
*= 5;
1074 base
.max_display_height_mm
*= 5;
1075 printf(" Recalculated image size: %u cm x %u cm\n",
1076 base
.max_display_width_mm
/ 10, base
.max_display_height_mm
/ 10);
1080 len_vic
= (x
[b
] & 0xe0) >> 5;
1081 len_3d
= (x
[b
] & 0x1f) >> 0;
1087 printf(" HDMI VICs:\n");
1088 for (i
= 0; i
< len_vic
; i
++) {
1089 unsigned char vic
= x
[b
+ i
];
1090 const struct timings
*t
;
1092 if (vic
&& vic
<= ARRAY_SIZE(edid_hdmi_mode_map
)) {
1093 std::string suffix
= "HDMI VIC " + std::to_string(vic
);
1094 cta
.supported_hdmi_vic_codes
|= 1 << (vic
- 1);
1095 t
= find_vic_id(edid_hdmi_mode_map
[vic
- 1]);
1096 print_timings(" ", t
, suffix
.c_str());
1098 printf(" Unknown (HDMI VIC %u)\n", vic
);
1099 fail("Unknown HDMI VIC %u.\n", vic
);
1110 /* 3D_Structure_ALL_15..8 */
1112 printf(" 3D: Side-by-side (half, quincunx)\n");
1114 printf(" 3D: Side-by-side (half, horizontal)\n");
1115 /* 3D_Structure_ALL_7..0 */
1118 printf(" 3D: Top-and-bottom\n");
1120 printf(" 3D: L + depth + gfx + gfx-depth\n");
1122 printf(" 3D: L + depth\n");
1124 printf(" 3D: Side-by-side (full)\n");
1126 printf(" 3D: Line-alternative\n");
1128 printf(" 3D: Field-alternative\n");
1130 printf(" 3D: Frame-packing\n");
1139 printf(" 3D VIC indices that support these capabilities:\n");
1140 /* worst bit ordering ever */
1141 for (i
= 0; i
< 8; i
++)
1142 if (x
[b
+ 1] & (1 << i
)) {
1143 print_vic_index(" ", i
, "");
1146 for (i
= 0; i
< 8; i
++)
1147 if (x
[b
] & (1 << i
)) {
1148 print_vic_index(" ", i
+ 8, "");
1153 if (max_idx
>= (int)cta
.preparsed_svds
[0].size())
1154 fail("HDMI 3D VIC indices max index %d > %u (#SVDs).\n",
1155 max_idx
+ 1, cta
.preparsed_svds
[0].size());
1162 * (optionally: 3D_Detail_X and reserved)
1167 unsigned end
= b
+ len_3d
;
1170 printf(" 3D VIC indices with specific capabilities:\n");
1172 unsigned char idx
= x
[b
] >> 4;
1177 switch (x
[b
] & 0x0f) {
1178 case 0: s
= "frame packing"; break;
1179 case 1: s
= "field alternative"; break;
1180 case 2: s
= "line alternative"; break;
1181 case 3: s
= "side-by-side (full)"; break;
1182 case 4: s
= "L + depth"; break;
1183 case 5: s
= "L + depth + gfx + gfx-depth"; break;
1184 case 6: s
= "top-and-bottom"; break;
1187 switch (x
[b
+ 1] >> 4) {
1188 case 0x00: s
+= ", any subsampling"; break;
1189 case 0x01: s
+= ", horizontal"; break;
1190 case 0x02: case 0x03: case 0x04: case 0x05:
1191 s
+= ", not in use";
1192 fail("not-in-use 3D_Detail_X value 0x%02x.\n",
1195 case 0x06: s
+= ", all quincunx combinations"; break;
1196 case 0x07: s
+= ", quincunx odd/left, odd/right"; break;
1197 case 0x08: s
+= ", quincunx odd/left, even/right"; break;
1198 case 0x09: s
+= ", quincunx even/left, odd/right"; break;
1199 case 0x0a: s
+= ", quincunx even/left, even/right"; break;
1202 fail("reserved 3D_Detail_X value 0x%02x.\n",
1209 s
+= utohex(x
[b
] & 0x0f) + ")";
1210 fail("Unknown 3D_Structure_X value 0x%02x.\n", x
[b
] & 0x0f);
1213 print_vic_index(" ", idx
, s
.c_str());
1214 if ((x
[b
] & 0x0f) >= 8)
1218 if (max_idx
>= (int)cta
.preparsed_svds
[0].size())
1219 fail("HDMI 2D VIC indices max index %d > %u (#SVDs).\n",
1220 max_idx
+ 1, cta
.preparsed_svds
[0].size());
1223 static const char *max_frl_rates
[] = {
1225 "3 Gbps per lane on 3 lanes",
1226 "3 and 6 Gbps per lane on 3 lanes",
1227 "3 and 6 Gbps per lane on 3 lanes, 6 Gbps on 4 lanes",
1228 "3 and 6 Gbps per lane on 3 lanes, 6 and 8 Gbps on 4 lanes",
1229 "3 and 6 Gbps per lane on 3 lanes, 6, 8 and 10 Gbps on 4 lanes",
1230 "3 and 6 Gbps per lane on 3 lanes, 6, 8, 10 and 12 Gbps on 4 lanes",
1233 static const char *dsc_max_slices
[] = {
1235 "up to 1 slice and up to (340 MHz/Ksliceadjust) pixel clock per slice",
1236 "up to 2 slices and up to (340 MHz/Ksliceadjust) pixel clock per slice",
1237 "up to 4 slices and up to (340 MHz/Ksliceadjust) pixel clock per slice",
1238 "up to 8 slices and up to (340 MHz/Ksliceadjust) pixel clock per slice",
1239 "up to 8 slices and up to (400 MHz/Ksliceadjust) pixel clock per slice",
1240 "up to 12 slices and up to (400 MHz/Ksliceadjust) pixel clock per slice",
1241 "up to 12 slices and up to (600 MHz/Ksliceadjust) pixel clock per slice",
1244 static void cta_hf_eeodb(const unsigned char *x
, unsigned length
)
1246 printf(" EDID Extension Block Count: %u\n", x
[0]);
1248 fail("Block is too long.\n");
1250 fail("Extension Block Count == %u.\n", x
[0]);
1253 static void cta_hf_scdb(const unsigned char *x
, unsigned length
)
1255 unsigned rate
= x
[1] * 5;
1258 printf(" Version: %u\n", x
[0]);
1260 printf(" Maximum TMDS Character Rate: %u MHz\n", rate
);
1261 if (rate
<= 340 || rate
> 600)
1262 fail("Max TMDS rate is > 0 and <= 340 or > 600.\n");
1265 printf(" SCDC Present\n");
1267 printf(" SCDC Read Request Capable\n");
1269 printf(" Supports Cable Status\n");
1271 printf(" Supports Color Content Bits Per Component Indication\n");
1273 printf(" Supports scrambling for <= 340 Mcsc\n");
1275 printf(" Supports 3D Independent View signaling\n");
1277 printf(" Supports 3D Dual View signaling\n");
1279 printf(" Supports 3D OSD Disparity signaling\n");
1281 unsigned max_frl_rate
= x
[3] >> 4;
1283 printf(" Max Fixed Rate Link: ");
1284 if (max_frl_rate
< ARRAY_SIZE(max_frl_rates
)) {
1285 printf("%s\n", max_frl_rates
[max_frl_rate
]);
1287 printf("Unknown (0x%02x)\n", max_frl_rate
);
1288 fail("Unknown Max Fixed Rate Link (0x%02x).\n", max_frl_rate
);
1290 if (max_frl_rate
== 1 && rate
< 300)
1291 fail("Max Fixed Rate Link is 1, but Max TMDS rate < 300.\n");
1292 else if (max_frl_rate
>= 2 && rate
< 600)
1293 fail("Max Fixed Rate Link is >= 2, but Max TMDS rate < 600.\n");
1296 printf(" Supports UHD VIC\n");
1298 printf(" Supports 16-bits/component Deep Color 4:2:0 Pixel Encoding\n");
1300 printf(" Supports 12-bits/component Deep Color 4:2:0 Pixel Encoding\n");
1302 printf(" Supports 10-bits/component Deep Color 4:2:0 Pixel Encoding\n");
1308 printf(" Supports FAPA End Extended\n");
1310 printf(" Supports QMS\n");
1312 printf(" Supports Mdelta\n");
1314 printf(" Supports media rates below VRRmin (CinemaVRR, deprecated)\n");
1315 warn("CinemaVRR is deprecated and must be cleared.\n");
1318 printf(" Supports negative Mvrr values\n");
1320 printf(" Supports Fast Vactive\n");
1322 printf(" Supports Auto Low-Latency Mode\n");
1324 printf(" Supports a FAPA in blanking after first active video line\n");
1331 printf(" VRRmin: %u Hz\n", v
);
1333 fail("VRRmin > 48.\n");
1335 v
= (x
[5] & 0xc0) << 2 | x
[6];
1337 printf(" VRRmax: %u Hz\n", v
);
1339 fail("VRRmin == 0, but VRRmax isn't.\n");
1341 fail("VRRmax < 100.\n");
1348 printf(" Supports VESA DSC 1.2a compression\n");
1350 printf(" Supports Compressed Video Transport for 4:2:0 Pixel Encoding\n");
1352 printf(" Supports QMS TFRmax\n");
1354 printf(" Supports QMS TFRmin\n");
1356 printf(" Supports Compressed Video Transport at any valid 1/16th bit bpp\n");
1358 printf(" Supports 16 bpc Compressed Video Transport\n");
1360 printf(" Supports 12 bpc Compressed Video Transport\n");
1362 printf(" Supports 10 bpc Compressed Video Transport\n");
1364 unsigned max_slices
= x
[8] & 0xf;
1366 printf(" DSC Max Slices: ");
1367 if (max_slices
< ARRAY_SIZE(dsc_max_slices
)) {
1368 printf("%s\n", dsc_max_slices
[max_slices
]);
1370 printf("Unknown (%u), interpreted as: %s\n", max_slices
,
1372 warn("Unknown DSC Max Slices (%u).\n", max_slices
);
1376 unsigned max_frl_rate
= x
[8] >> 4;
1378 printf(" DSC Max Fixed Rate Link: ");
1379 if (max_frl_rate
< ARRAY_SIZE(max_frl_rates
)) {
1380 printf("%s\n", max_frl_rates
[max_frl_rate
]);
1382 printf("Unknown (0x%02x)\n", max_frl_rate
);
1383 fail("Unknown DSC Max Fixed Rate Link (0x%02x).\n", max_frl_rate
);
1387 printf(" Maximum number of bytes in a line of chunks: %u\n",
1388 1024 * (1 + (x
[9] & 0x3f)));
1391 // Convert a PQ value (0-1) to cd/m^2 aka nits (0-10000)
1392 static double pq2nits(double pq
)
1394 const double m1
= 2610.0 / 16384.0;
1395 const double m2
= 128.0 * (2523.0 / 4096.0);
1396 const double c1
= 3424.0 / 4096.0;
1397 const double c2
= 32.0 * (2413.0 / 4096.0);
1398 const double c3
= 32.0 * (2392.0 / 4096.0);
1399 double e
= pow(pq
, 1.0 / m2
);
1405 v
= pow(v
, 1.0 / m1
);
1409 static double chrom2d(const unsigned char *x
)
1411 unsigned v
= x
[0] + (x
[1] << 8);
1416 static double perc2d(unsigned char x
)
1421 return 100.0 * (m
/ 64.0) * pow(10, -e
);
1424 static void cta_hf_sbtmdb(const unsigned char *x
, unsigned length
)
1429 fail("Block is too short.\n");
1430 printf(" Version: %d\n", x
[0] & 0xf);
1431 switch ((x
[0] >> 5) & 3) {
1433 printf(" Does not support a General RDM format\n");
1436 printf(" Supports an SDR-range General RDM format\n");
1439 printf(" Supports an HDR-range General RDM format\n");
1442 fail("Invalid GRDM Support value.\n");
1448 bool uses_hgig_drdm
= true;
1450 printf(" Supports a D-RDM format\n");
1452 printf(" Use HGIG D-RDM\n");
1455 printf(" HGIG D-RDM is not used\n");
1456 uses_hgig_drdm
= false;
1459 printf(" PBnits[0] = 600 cd/m^2\n");
1462 printf(" PBnits[0] = 1000 cd/m^2\n");
1465 printf(" PBnits[0] = 4000 cd/m^2\n");
1468 printf(" PBnits[0] = 10000 cd/m^2\n");
1471 fail("Invalid HGIG D-DRM value.\n");
1475 bool has_chromaticities
= false;
1478 printf(" MaxRGB\n");
1479 switch (x
[1] >> 6) {
1481 printf(" Gamut is explicit\n");
1482 has_chromaticities
= true;
1485 printf(" Gamut is Rec. ITU-R BT.709\n");
1488 printf(" Gamut is SMPTE ST 2113\n");
1491 printf(" Gamut is Rec. ITU-R BT.2020\n");
1496 if (has_chromaticities
) {
1497 printf(" Red: (%.5f, %.5f)\n", chrom2d(x
), chrom2d(x
+ 2));
1498 printf(" Green: (%.5f, %.5f)\n", chrom2d(x
+ 4), chrom2d(x
+ 6));
1499 printf(" Blue: (%.5f, %.5f)\n", chrom2d(x
+ 8), chrom2d(x
+ 10));
1500 printf(" White: (%.5f, %.5f)\n", chrom2d(x
+ 12), chrom2d(x
+ 14));
1506 printf(" Min Brightness 10: %.8f cd/m^2\n", pq2nits((x
[0] << 1) / 4095.0));
1507 printf(" Peak Brightness 100: %u cd/m^2\n", (unsigned)pq2nits((x
[1] << 4) / 4095.0));
1512 printf(" Percentage of Peak Brightness P0: %.2f%%\n", perc2d(x
[0]));
1513 printf(" Peak Brightness P0: %.8f cd/m^2\n", pq2nits((x
[1] << 1) / 4095.0));
1518 printf(" Percentage of Peak Brightness P1: %.2f%%\n", perc2d(x
[0]));
1519 printf(" Peak Brightness P1: %.8f cd/m^2\n", pq2nits((x
[1] << 1) / 4095.0));
1524 printf(" Percentage of Peak Brightness P2: %.2f%%\n", perc2d(x
[0]));
1525 printf(" Peak Brightness P2: %.8f cd/m^2\n", pq2nits((x
[1] << 1) / 4095.0));
1530 printf(" Percentage of Peak Brightness P3: %.2f%%\n", perc2d(x
[0]));
1531 printf(" Peak Brightness P3: %.8f cd/m^2\n", pq2nits((x
[1] << 1) / 4095.0));
1534 static void cta_amd(const unsigned char *x
, unsigned length
)
1536 // These Freesync values are reversed engineered by looking
1537 // at existing EDIDs.
1538 printf(" Version: %u.%u\n", x
[0], x
[1]);
1539 printf(" Minimum Refresh Rate: %u Hz\n", x
[2]);
1540 printf(" Maximum Refresh Rate: %u Hz\n", x
[3]);
1541 // Freesync 1.x flags
1542 // One or more of the 0xe6 bits signal that the VESA MCCS
1543 // protocol is used to switch the Freesync range
1544 printf(" Flags 1.x: 0x%02x%s\n", x
[4],
1545 (x
[4] & 0xe6) ? " (MCCS)" : "");
1547 // Freesync 2.x flags
1548 // Bit 2 no doubt indicates if the monitor supports Local Dimming
1549 // There are probably also bits to signal support of the
1550 // FreeSync2_scRGB and FreeSync2_Gamma22 HDR display modes.
1551 // I suspect bits 0 and 1.
1552 printf(" Flags 2.x: 0x%02x\n", x
[5]);
1553 // The AMD tone mapping tutorial referred to in the URL below
1554 // mentions that the Freesync HDR info reports max/min
1555 // luminance of the monitor with and without local dimming.
1557 // https://gpuopen.com/learn/using-amd-freesync-premium-pro-hdr-code-samples/
1559 // So I assume that the first two luminance values are
1560 // the max/min luminance of the display and the next two
1561 // luminance values are the max/min luminance values when
1562 // local dimming is disabled. The values I get seem to
1564 printf(" Maximum luminance: %u (%.3f cd/m^2)\n",
1565 x
[6], 50.0 * pow(2, x
[6] / 32.0));
1566 printf(" Minimum luminance: %u (%.3f cd/m^2)\n",
1567 x
[7], (50.0 * pow(2, x
[6] / 32.0)) * pow(x
[7] / 255.0, 2) / 100.0);
1569 // One or both bytes can be 0. The meaning of that
1571 printf(" Maximum luminance (without local dimming): %u (%.3f cd/m^2)\n",
1572 x
[8], 50.0 * pow(2, x
[8] / 32.0));
1573 printf(" Minimum luminance (without local dimming): %u (%.3f cd/m^2)\n",
1574 x
[9], (50.0 * pow(2, x
[8] / 32.0)) * pow(x
[9] / 255.0, 2) / 100.0);
1576 // These bytes are always 0x08 0x2f. If these values
1577 // represent max/min luminance as well, then these
1578 // would map to 59.460 and 0.020 cd/m^2 respectively.
1579 // I wonder if this somehow relates to SDR.
1580 printf(" Unknown: 0x%02x 0x%02x\n", x
[8], x
[9]);
1585 static std::string
display_use_case(unsigned char x
)
1588 case 1: return "Test equipment";
1589 case 2: return "Generic display";
1590 case 3: return "Television display";
1591 case 4: return "Desktop productivity display";
1592 case 5: return "Desktop gaming display";
1593 case 6: return "Presentation display";
1594 case 7: return "Virtual reality headset";
1595 case 8: return "Augmented reality";
1596 case 16: return "Video wall display";
1597 case 17: return "Medical imaging display";
1598 case 18: return "Dedicated gaming display";
1599 case 19: return "Dedicated video monitor display";
1600 case 20: return "Accessory display";
1603 fail("Unknown Display product primary use case 0x%02x.\n", x
);
1604 return std::string("Unknown display use case (") + utohex(x
) + ")";
1607 static void cta_microsoft(const unsigned char *x
, unsigned length
)
1609 // This VSDB is documented at:
1610 // https://docs.microsoft.com/en-us/windows-hardware/drivers/display/specialized-monitors-edid-extension
1611 printf(" Version: %u\n", x
[0]);
1613 // In version 1 and 2 these bits should always be set to 0.
1614 printf(" Desktop Usage: %u\n", (x
[1] >> 6) & 1);
1615 printf(" Third-Party Usage: %u\n", (x
[1] >> 5) & 1);
1617 printf(" Display Product Primary Use Case: %u (%s)\n", x
[1] & 0x1f,
1618 display_use_case(x
[1] & 0x1f).c_str());
1619 printf(" Container ID: %s\n", containerid2s(x
+ 2).c_str());
1622 static void cta_hdr10plus(const unsigned char *x
, unsigned length
)
1625 fail("Empty Data Block with length %u.\n", length
);
1628 printf(" Application Version: %u\n", x
[0] & 3);
1629 printf(" Full Frame Peak Luminance Index: %u\n", (x
[0] >> 2) & 3);
1630 printf(" Peak Luminance Index: %u\n", x
[0] >> 4);
1631 hex_block(" ", x
+ 1, length
- 1);
1634 static void cta_dolby_video(const unsigned char *x
, unsigned length
)
1636 unsigned char version
= (x
[0] >> 5) & 0x07;
1638 printf(" Version: %u (%u bytes)\n", version
, length
+ 5);
1640 printf(" Supports YUV422 12 bit\n");
1644 printf(" Supports 2160p60\n");
1646 printf(" Supports global dimming\n");
1647 unsigned char dm_version
= x
[16];
1648 printf(" DM Version: %u.%u\n", dm_version
>> 4, dm_version
& 0xf);
1649 unsigned pq
= (x
[14] << 4) | (x
[13] >> 4);
1650 printf(" Target Min PQ: %u (%.8f cd/m^2)\n", pq
, pq2nits(pq
/ 4095.0));
1651 pq
= (x
[15] << 4) | (x
[13] & 0xf);
1652 printf(" Target Max PQ: %u (%u cd/m^2)\n", pq
, (unsigned)pq2nits(pq
/ 4095.0));
1653 printf(" Rx, Ry: %.8f, %.8f\n",
1654 ((x
[1] >> 4) | (x
[2] << 4)) / 4096.0,
1655 ((x
[1] & 0xf) | (x
[3] << 4)) / 4096.0);
1656 printf(" Gx, Gy: %.8f, %.8f\n",
1657 ((x
[4] >> 4) | (x
[5] << 4)) / 4096.0,
1658 ((x
[4] & 0xf) | (x
[6] << 4)) / 4096.0);
1659 printf(" Bx, By: %.8f, %.8f\n",
1660 ((x
[7] >> 4) | (x
[8] << 4)) / 4096.0,
1661 ((x
[7] & 0xf) | (x
[9] << 4)) / 4096.0);
1662 printf(" Wx, Wy: %.8f, %.8f\n",
1663 ((x
[10] >> 4) | (x
[11] << 4)) / 4096.0,
1664 ((x
[10] & 0xf) | (x
[12] << 4)) / 4096.0);
1670 printf(" Supports 2160p60\n");
1672 printf(" Supports global dimming\n");
1673 unsigned char dm_version
= (x
[0] >> 2) & 0x07;
1674 printf(" DM Version: %u.x\n", dm_version
+ 2);
1675 printf(" Colorimetry: %s\n", (x
[2] & 0x01) ? "P3-D65" : "ITU-R BT.709");
1676 printf(" Low Latency: %s\n", (x
[3] & 0x01) ? "Standard + Low Latency" : "Only Standard");
1677 double lm
= (x
[2] >> 1) / 127.0;
1678 printf(" Target Min Luminance: %.8f cd/m^2\n", lm
* lm
);
1679 printf(" Target Max Luminance: %u cd/m^2\n", 100 + (x
[1] >> 1) * 50);
1681 printf(" Rx, Ry: %.8f, %.8f\n", x
[4] / 256.0, x
[5] / 256.0);
1682 printf(" Gx, Gy: %.8f, %.8f\n", x
[6] / 256.0, x
[7] / 256.0);
1683 printf(" Bx, By: %.8f, %.8f\n", x
[8] / 256.0, x
[9] / 256.0);
1685 double xmin
= 0.625;
1686 double xstep
= (0.74609375 - xmin
) / 31.0;
1688 double ystep
= (0.37109375 - ymin
) / 31.0;
1690 printf(" Unique Rx, Ry: %.8f, %.8f\n",
1691 xmin
+ xstep
* (x
[6] >> 3),
1692 ymin
+ ystep
* (((x
[6] & 0x7) << 2) | (x
[4] & 0x01) | ((x
[5] & 0x01) << 1)));
1693 xstep
= 0.49609375 / 127.0;
1695 ystep
= (0.99609375 - ymin
) / 127.0;
1696 printf(" Unique Gx, Gy: %.8f, %.8f\n",
1697 xstep
* (x
[4] >> 1), ymin
+ ystep
* (x
[5] >> 1));
1699 xstep
= (0.15234375 - xmin
) / 7.0;
1701 ystep
= (0.05859375 - ymin
) / 7.0;
1702 printf(" Unique Bx, By: %.8f, %.8f\n",
1703 xmin
+ xstep
* (x
[3] >> 5),
1704 ymin
+ ystep
* ((x
[3] >> 2) & 0x07));
1711 printf(" Supports Backlight Control\n");
1713 printf(" Supports global dimming\n");
1714 unsigned char dm_version
= (x
[0] >> 2) & 0x07;
1715 printf(" DM Version: %u.x\n", dm_version
+ 2);
1716 printf(" Backlt Min Luma: %u cd/m^2\n", 25 + (x
[1] & 0x03) * 25);
1717 printf(" Interface: ");
1718 switch (x
[2] & 0x03) {
1719 case 0: printf("Low-Latency\n"); break;
1720 case 1: printf("Low-Latency + Low-Latency-HDMI\n"); break;
1721 case 2: printf("Standard + Low-Latency\n"); break;
1722 case 3: printf("Standard + Low-Latency + Low-Latency-HDMI\n"); break;
1724 printf(" Supports 10b 12b 444: ");
1725 switch ((x
[3] & 0x01) << 1 | (x
[4] & 0x01)) {
1726 case 0: printf("Not supported\n"); break;
1727 case 1: printf("10 bit\n"); break;
1728 case 2: printf("12 bit\n"); break;
1729 case 3: printf("Reserved\n"); break;
1732 unsigned pq
= 20 * (x
[1] >> 3);
1733 printf(" Target Min PQ v2: %u (%.8f cd/m^2)\n", pq
, pq2nits(pq
/ 4095.0));
1734 pq
= 2055 + 65 * (x
[2] >> 3);
1735 printf(" Target Max PQ v2: %u (%u cd/m^2)\n", pq
, (unsigned)pq2nits(pq
/ 4095.0));
1737 printf(" Unique Rx, Ry: %.8f, %.8f\n",
1738 0.625 + (x
[5] >> 3) / 256.0,
1739 0.25 + (x
[6] >> 3) / 256.0);
1740 printf(" Unique Gx, Gy: %.8f, %.8f\n",
1741 (x
[3] >> 1) / 256.0,
1742 0.5 + (x
[4] >> 1) / 256.0);
1743 printf(" Unique Bx, By: %.8f, %.8f\n",
1744 0.125 + (x
[5] & 0x07) / 256.0,
1745 0.03125 + (x
[6] & 0x07) / 256.0);
1749 static void cta_dolby_audio(const unsigned char *x
, unsigned length
)
1751 unsigned char version
= 1 + (x
[0] & 0x07);
1753 printf(" Version: %u (%u bytes)\n", version
, length
+ 5);
1755 printf(" Headphone playback only\n");
1757 printf(" Height speaker zone present\n");
1759 printf(" Surround speaker zone present\n");
1761 printf(" Center speaker zone present\n");
1763 printf(" Supports Dolby MAT PCM decoding at 48 kHz only, does not support TrueHD\n");
1766 static void cta_uhda_fmm(const unsigned char *x
, unsigned length
)
1768 printf(" Filmmaker Mode Content Type: %u\n", x
[0]);
1769 printf(" Filmmaker Mode Content Subtype: %u\n", x
[1]);
1772 static const char *speaker_map
[] = {
1773 "FL/FR - Front Left/Right",
1774 "LFE1 - Low Frequency Effects 1",
1775 "FC - Front Center",
1776 "BL/BR - Back Left/Right",
1778 "FLc/FRc - Front Left/Right of Center",
1779 "RLC/RRC - Rear Left/Right of Center (Deprecated)",
1780 "FLw/FRw - Front Left/Right Wide",
1781 "TpFL/TpFR - Top Front Left/Right",
1783 "TpFC - Top Front Center",
1784 "LS/RS - Left/Right Surround",
1785 "LFE2 - Low Frequency Effects 2",
1786 "TpBC - Top Back Center",
1787 "SiL/SiR - Side Left/Right",
1788 "TpSiL/TpSiR - Top Side Left/Right",
1789 "TpBL/TpBR - Top Back Left/Right",
1790 "BtFC - Bottom Front Center",
1791 "BtFL/BtFR - Bottom Front Left/Right",
1792 "TpLS/TpRS - Top Left/Right Surround (Deprecated for CTA-861)",
1793 "LSd/RSd - Left/Right Surround Direct (HDMI only)",
1796 static void cta_sadb(const unsigned char *x
, unsigned length
)
1802 fail("Empty Data Block with length %u.\n", length
);
1806 sad
= ((x
[2] << 16) | (x
[1] << 8) | x
[0]);
1808 for (i
= 0; i
< ARRAY_SIZE(speaker_map
); i
++) {
1810 printf(" %s\n", speaker_map
[i
]);
1814 static void cta_vesa_dtcdb(const unsigned char *x
, unsigned length
)
1816 if (length
!= 7 && length
!= 15 && length
!= 31) {
1817 fail("Invalid length %u.\n", length
);
1821 switch (x
[0] >> 6) {
1822 case 0: printf(" White"); break;
1823 case 1: printf(" Red"); break;
1824 case 2: printf(" Green"); break;
1825 case 3: printf(" Blue"); break;
1827 unsigned v
= x
[0] & 0x3f;
1828 printf(" transfer characteristics: %u", v
);
1829 for (unsigned i
= 1; i
< length
; i
++)
1830 printf(" %u", v
+= x
[i
]);
1834 static void cta_vesa_vdddb(const unsigned char *x
, unsigned length
)
1837 fail("Invalid length %u.\n", length
);
1841 printf(" Interface Type: ");
1842 unsigned char v
= x
[0];
1844 case 0: printf("Analog (");
1846 case 0: printf("15HD/VGA"); break;
1847 case 1: printf("VESA NAVI-V (15HD)"); break;
1848 case 2: printf("VESA NAVI-D"); break;
1849 default: printf("Reserved"); break;
1853 case 1: printf("LVDS %u lanes", v
& 0xf); break;
1854 case 2: printf("RSDS %u lanes", v
& 0xf); break;
1855 case 3: printf("DVI-D %u channels", v
& 0xf); break;
1856 case 4: printf("DVI-I analog"); break;
1857 case 5: printf("DVI-I digital %u channels", v
& 0xf); break;
1858 case 6: printf("HDMI-A"); break;
1859 case 7: printf("HDMI-B"); break;
1860 case 8: printf("MDDI %u channels", v
& 0xf); break;
1861 case 9: printf("DisplayPort %u channels", v
& 0xf); break;
1862 case 10: printf("IEEE-1394"); break;
1863 case 11: printf("M1 analog"); break;
1864 case 12: printf("M1 digital %u channels", v
& 0xf); break;
1865 default: printf("Reserved"); break;
1869 printf(" Interface Standard Version: %u.%u\n", x
[1] >> 4, x
[1] & 0xf);
1870 printf(" Content Protection Support: ");
1872 case 0: printf("None\n"); break;
1873 case 1: printf("HDCP\n"); break;
1874 case 2: printf("DTCP\n"); break;
1875 case 3: printf("DPCP\n"); break;
1876 default: printf("Reserved\n"); break;
1879 printf(" Minimum Clock Frequency: %u MHz\n", x
[3] >> 2);
1880 printf(" Maximum Clock Frequency: %u MHz\n", ((x
[3] & 0x03) << 8) | x
[4]);
1881 printf(" Device Native Pixel Format: %ux%u\n",
1882 x
[5] | (x
[6] << 8), x
[7] | (x
[8] << 8));
1883 printf(" Aspect Ratio: %.2f\n", (100 + x
[9]) / 100.0);
1885 printf(" Default Orientation: ");
1886 switch ((v
& 0xc0) >> 6) {
1887 case 0x00: printf("Landscape\n"); break;
1888 case 0x01: printf("Portrait\n"); break;
1889 case 0x02: printf("Not Fixed\n"); break;
1890 case 0x03: printf("Undefined\n"); break;
1892 printf(" Rotation Capability: ");
1893 switch ((v
& 0x30) >> 4) {
1894 case 0x00: printf("None\n"); break;
1895 case 0x01: printf("Can rotate 90 degrees clockwise\n"); break;
1896 case 0x02: printf("Can rotate 90 degrees counterclockwise\n"); break;
1897 case 0x03: printf("Can rotate 90 degrees in either direction)\n"); break;
1899 printf(" Zero Pixel Location: ");
1900 switch ((v
& 0x0c) >> 2) {
1901 case 0x00: printf("Upper Left\n"); break;
1902 case 0x01: printf("Upper Right\n"); break;
1903 case 0x02: printf("Lower Left\n"); break;
1904 case 0x03: printf("Lower Right\n"); break;
1906 printf(" Scan Direction: ");
1908 case 0x00: printf("Not defined\n"); break;
1909 case 0x01: printf("Fast Scan is on the Major (Long) Axis and Slow Scan is on the Minor Axis\n"); break;
1910 case 0x02: printf("Fast Scan is on the Minor (Short) Axis and Slow Scan is on the Major Axis\n"); break;
1911 case 0x03: printf("Reserved\n");
1912 fail("Scan Direction used the reserved value 0x03.\n");
1915 printf(" Subpixel Information: ");
1917 case 0x00: printf("Not defined\n"); break;
1918 case 0x01: printf("RGB vertical stripes\n"); break;
1919 case 0x02: printf("RGB horizontal stripes\n"); break;
1920 case 0x03: printf("Vertical stripes using primary order\n"); break;
1921 case 0x04: printf("Horizontal stripes using primary order\n"); break;
1922 case 0x05: printf("Quad sub-pixels, red at top left\n"); break;
1923 case 0x06: printf("Quad sub-pixels, red at bottom left\n"); break;
1924 case 0x07: printf("Delta (triad) RGB sub-pixels\n"); break;
1925 case 0x08: printf("Mosaic\n"); break;
1926 case 0x09: printf("Quad sub-pixels, RGB + 1 additional color\n"); break;
1927 case 0x0a: printf("Five sub-pixels, RGB + 2 additional colors\n"); break;
1928 case 0x0b: printf("Six sub-pixels, RGB + 3 additional colors\n"); break;
1929 case 0x0c: printf("Clairvoyante, Inc. PenTile Matrix (tm) layout\n"); break;
1930 default: printf("Reserved\n"); break;
1932 printf(" Horizontal and vertical dot/pixel pitch: %.2f x %.2f mm\n",
1933 (double)(x
[0x0c]) / 100.0, (double)(x
[0x0d]) / 100.0);
1935 printf(" Dithering: ");
1937 case 0: printf("None\n"); break;
1938 case 1: printf("Spatial\n"); break;
1939 case 2: printf("Temporal\n"); break;
1940 case 3: printf("Spatial and Temporal\n"); break;
1942 printf(" Direct Drive: %s\n", (v
& 0x20) ? "Yes" : "No");
1943 printf(" Overdrive %srecommended\n", (v
& 0x10) ? "not " : "");
1944 printf(" Deinterlacing: %s\n", (v
& 0x08) ? "Yes" : "No");
1947 printf(" Audio Support: %s\n", (v
& 0x80) ? "Yes" : "No");
1948 printf(" Separate Audio Inputs Provided: %s\n", (v
& 0x40) ? "Yes" : "No");
1949 printf(" Audio Input Override: %s\n", (v
& 0x20) ? "Yes" : "No");
1952 printf(" Audio Delay: %s%u ms\n", (v
& 0x80) ? "" : "-", (v
& 0x7f) * 2);
1954 printf(" Audio Delay: no information provided\n");
1956 printf(" Frame Rate/Mode Conversion: ");
1958 case 0: printf("None\n"); break;
1959 case 1: printf("Single Buffering\n"); break;
1960 case 2: printf("Double Buffering\n"); break;
1961 case 3: printf("Advanced Frame Rate Conversion\n"); break;
1964 printf(" Frame Rate Range: %u fps +/- %u fps\n",
1967 printf(" Nominal Frame Rate: %u fps\n", x
[0x12]);
1968 printf(" Color Bit Depth: %u @ interface, %u @ display\n",
1969 (x
[0x13] >> 4) + 1, (x
[0x13] & 0xf) + 1);
1972 printf(" Additional Primary Chromaticities:\n");
1973 unsigned col_x
= (x
[0x16] << 2) | (x
[0x14] >> 6);
1974 unsigned col_y
= (x
[0x17] << 2) | ((x
[0x14] >> 4) & 3);
1975 printf(" Primary 4: 0.%04u, 0.%04u\n",
1976 (col_x
* 10000) / 1024, (col_y
* 10000) / 1024);
1978 col_x
= (x
[0x18] << 2) | ((x
[0x14] >> 2) & 3);
1979 col_y
= (x
[0x19] << 2) | (x
[0x14] & 3);
1980 printf(" Primary 5: 0.%04u, 0.%04u\n",
1981 (col_x
* 10000) / 1024, (col_y
* 10000) / 1024);
1983 col_x
= (x
[0x1a] << 2) | (x
[0x15] >> 6);
1984 col_y
= (x
[0x1b] << 2) | ((x
[0x15] >> 4) & 3);
1985 printf(" Primary 6: 0.%04u, 0.%04u\n",
1986 (col_x
* 10000) / 1024, (col_y
* 10000) / 1024);
1992 printf(" Response Time %s: %u ms\n",
1993 (v
& 0x80) ? "White -> Black" : "Black -> White", v
& 0x7f);
1995 printf(" Overscan: %u%% x %u%%\n", v
>> 4, v
& 0xf);
1998 static double decode_uchar_as_double(unsigned char x
)
2000 signed char s
= (signed char)x
;
2005 void edid_state::cta_rcdb(const unsigned char *x
, unsigned length
)
2007 unsigned spm
= ((x
[3] << 16) | (x
[2] << 8) | x
[1]);
2011 fail("Empty Data Block with length %u.\n", length
);
2015 if ((x
[0] & 0x20) && !cta
.has_sldb
)
2016 fail("'SLD' flag is 1, but no Speaker Location Data Block is found.\n");
2017 else if (!(x
[0] & 0x20) && cta
.has_sldb
)
2018 fail("'SLD' flag is 0, but a Speaker Location Data Block is present.\n");
2021 printf(" Speaker count: %u\n", (x
[0] & 0x1f) + 1);
2024 fail("'Speaker' flag is 0, but 'Speaker Count' is != 0.\n");
2026 fail("'SLD' flag is 1, but 'Speaker' is 0.\n");
2029 printf(" Speaker Presence Mask:\n");
2030 for (i
= 0; i
< ARRAY_SIZE(speaker_map
); i
++) {
2032 printf(" %s\n", speaker_map
[i
]);
2035 if ((x
[0] & 0xa0) == 0x80)
2036 fail("'Display' flag set, but not the 'SLD' flag.\n");
2038 bool valid_max
= cta
.preparsed_sld_has_coord
|| (x
[0] & 0x80);
2040 if (valid_max
&& length
>= 7) {
2041 printf(" Xmax: %u dm\n", x
[4]);
2042 printf(" Ymax: %u dm\n", x
[5]);
2043 printf(" Zmax: %u dm\n", x
[6]);
2044 } else if (!valid_max
&& length
>= 7) {
2045 // The RCDB should have been truncated.
2046 warn("'Display' flag is 0 and 'Coord' is 0 for all SLDs, but the Max coordinates are still present.\n");
2048 if ((x
[0] & 0x80) && length
>= 10) {
2049 printf(" DisplayX: %.3f * Xmax\n", decode_uchar_as_double(x
[7]));
2050 printf(" DisplayY: %.3f * Ymax\n", decode_uchar_as_double(x
[8]));
2051 printf(" DisplayZ: %.3f * Zmax\n", decode_uchar_as_double(x
[9]));
2052 } else if (!(x
[0] & 0x80) && length
>= 10) {
2053 // The RCDB should have been truncated.
2054 warn("'Display' flag is 0, but the Display coordinates are still present.\n");
2058 static const struct {
2061 } speaker_location
[] = {
2062 { "FL - Front Left", -1, 1, 0 },
2063 { "FR - Front Right", 1, 1, 0 },
2064 { "FC - Front Center", 0, 1, 0 },
2065 { "LFE1 - Low Frequency Effects 1", -0.5, 1, -1 },
2066 { "BL - Back Left", -1, -1, 0 },
2067 { "BR - Back Right", 1, -1, 0 },
2068 { "FLC - Front Left of Center", -0.5, 1, 0 },
2069 { "FRC - Front Right of Center", 0.5, 1, 0 },
2070 { "BC - Back Center", 0, -1, 0 },
2071 { "LFE2 - Low Frequency Effects 2", 0.5, 1, -1 },
2072 { "SiL - Side Left", -1, 1.0/3.0, 0 },
2073 { "SiR - Side Right", 1, 1.0/3.0, 0 },
2074 { "TpFL - Top Front Left", -1, 1, 1 },
2075 { "TpFR - Top Front Right", 1, 1, 1 },
2076 { "TpFC - Top Front Center", 0, 1, 1 },
2077 { "TpC - Top Center", 0, 0, 1 },
2078 { "TpBL - Top Back Left", -1, -1, 1 },
2079 { "TpBR - Top Back Right", 1, -1, 1 },
2080 { "TpSiL - Top Side Left", -1, 0, 1 },
2081 { "TpSiR - Top Side Right", 1, 0, 1 },
2082 { "TpBC - Top Back Center", 0, -1, 1 },
2083 { "BtFC - Bottom Front Center", 0, 1, -1 },
2084 { "BtFL - Bottom Front Left", -1, 1, -1 },
2085 { "BtFR - Bottom Front Right", 1, 1, -1 },
2086 { "FLW - Front Left Wide", -1, 2.0/3.0, 0 },
2087 { "FRW - Front Right Wide", 1, 2.0/3.0, 0 },
2088 { "LS - Left Surround", -1, 0, 0 },
2089 { "RS - Right Surround", 1, 0, 0 },
2092 void edid_state::cta_sldb(const unsigned char *x
, unsigned length
)
2095 fail("Empty Data Block with length %u.\n", length
);
2099 unsigned active_cnt
= 0;
2100 unsigned channel_is_active
= 0;
2102 while (length
>= 2) {
2103 printf(" Channel: %u (%sactive)\n", x
[0] & 0x1f,
2104 (x
[0] & 0x20) ? "" : "not ");
2106 if (channel_is_active
& (1U << (x
[0] & 0x1f)))
2107 fail("Channel Index %u was already marked 'Active'.\n",
2109 channel_is_active
|= 1U << (x
[0] & 0x1f);
2113 unsigned speaker_id
= x
[1] & 0x1f;
2115 if (speaker_id
< ARRAY_SIZE(speaker_location
)) {
2116 printf(" Speaker ID: %s\n", speaker_location
[speaker_id
].name
);
2117 } else if (speaker_id
== 0x1f) {
2118 printf(" Speaker ID: None Specified\n");
2120 printf(" Speaker ID: Reserved (%u)\n", speaker_id
);
2121 fail("Reserved Speaker ID specified.\n");
2123 if (length
>= 5 && (x
[0] & 0x40)) {
2124 printf(" X: %.3f * Xmax\n", decode_uchar_as_double(x
[2]));
2125 printf(" Y: %.3f * Ymax\n", decode_uchar_as_double(x
[3]));
2126 printf(" Z: %.3f * Zmax\n", decode_uchar_as_double(x
[4]));
2129 } else if (speaker_id
< ARRAY_SIZE(speaker_location
)) {
2130 printf(" X: %.3f * Xmax (approximately)\n", speaker_location
[speaker_id
].x
);
2131 printf(" Y: %.3f * Ymax (approximately)\n", speaker_location
[speaker_id
].y
);
2132 printf(" Z: %.3f * Zmax (approximately)\n", speaker_location
[speaker_id
].z
);
2138 if (active_cnt
!= cta
.preparsed_speaker_count
)
2139 fail("There are %u active speakers, but 'Speaker Count' is %u.\n",
2140 active_cnt
, cta
.preparsed_speaker_count
);
2143 void edid_state::cta_preparse_sldb(const unsigned char *x
, unsigned length
)
2145 cta
.has_sldb
= true;
2146 while (length
>= 2) {
2147 if (length
>= 5 && (x
[0] & 0x40)) {
2148 cta
.preparsed_sld_has_coord
= true;
2156 void edid_state::cta_vcdb(const unsigned char *x
, unsigned length
)
2158 unsigned char d
= x
[0];
2160 cta
.has_vcdb
= true;
2162 fail("Empty Data Block with length %u.\n", length
);
2165 printf(" YCbCr quantization: %s\n",
2166 (d
& 0x80) ? "Selectable (via AVI YQ)" : "No Data");
2167 printf(" RGB quantization: %s\n",
2168 (d
& 0x40) ? "Selectable (via AVI Q)" : "No Data");
2170 * If this bit is not set then that will result in interoperability
2171 * problems (specifically with PCs/laptops) that quite often do not
2172 * follow the default rules with respect to RGB Quantization Range
2175 * Starting with the CTA-861-H spec this bit is now required to be
2176 * 1 for new designs.
2179 fail("Set Selectable RGB Quantization to avoid interop issues.\n");
2181 * Since most YCbCr formats use limited range, the interop issues are
2182 * less noticable than for RGB formats.
2184 * Starting with the CTA-861-H spec this bit is now required to be
2185 * 1 for new designs, but just warn about it (for now).
2187 if ((cta
.byte3
& 0x30) && !(d
& 0x80))
2188 warn("Set Selectable YCbCr Quantization to avoid interop issues.\n");
2190 unsigned char s_pt
= (d
>> 4) & 0x03;
2191 unsigned char s_it
= (d
>> 2) & 0x03;
2192 unsigned char s_ce
= d
& 0x03;
2194 printf(" PT scan behavior: ");
2196 case 0: printf("No Data\n"); break;
2197 case 1: printf("Always Overscanned\n"); break;
2198 case 2: printf("Always Underscanned\n"); break;
2199 case 3: printf("Supports both over- and underscan\n"); break;
2201 printf(" IT scan behavior: ");
2203 case 0: printf("IT video formats not supported\n"); break;
2205 printf("Always Overscanned\n");
2206 // See Table 52 of CTA-861-G for a description of Byte 3
2207 if (cta
.byte3
& 0x80)
2208 fail("IT video formats are always overscanned, but bit 7 of Byte 3 of the CTA-861 Extension header is set to underscanned.\n");
2211 printf("Always Underscanned\n");
2212 // See Table 52 of CTA-861-G for a description of Byte 3
2213 if (!(cta
.byte3
& 0x80))
2214 fail("IT video formats are always underscanned, but bit 7 of Byte 3 of the CTA-861 Extension header is set to overscanned.\n");
2216 case 3: printf("Supports both over- and underscan\n"); break;
2219 warn("IT scan behavior is expected to support underscanned.\n");
2220 printf(" CE scan behavior: ");
2222 case 0: printf("CE video formats not supported\n"); break;
2223 case 1: printf("Always Overscanned\n"); break;
2224 case 2: printf("Always Underscanned\n"); break;
2225 case 3: printf("Supports both over- and underscan\n"); break;
2228 warn("'CE video formats not supported' makes no sense.\n");
2229 else if (s_pt
== s_it
&& s_pt
== s_ce
)
2230 warn("S_PT is equal to S_IT and S_CE, so should be set to 0 instead.\n");
2233 static const char *colorimetry1_map
[] = {
2244 static const char *colorimetry2_map
[] = {
2245 "Gamut Boundary Description Metadata Profile P0",
2246 "Reserved Gamut Boundary Description Metadata Profile P1",
2247 "Reserved Gamut Boundary Description Metadata Profile P2",
2248 "Reserved Gamut Boundary Description Metadata Profile P3",
2255 void edid_state::cta_colorimetry_block(const unsigned char *x
, unsigned length
)
2260 fail("Empty Data Block with length %u.\n", length
);
2263 for (i
= 0; i
< ARRAY_SIZE(colorimetry1_map
); i
++)
2264 if (x
[0] & (1 << i
))
2265 printf(" %s\n", colorimetry1_map
[i
]);
2266 // Bits MD0-MD3 are used to indicate which HDMI Gamut Boundary Description
2267 // Metadata Profiles are supported.
2269 // HDMI 1.3a in section 5.3.12 describes 4 possible profiles, but it marks
2270 // P3 as 'defined in a future specification'.
2272 // HDMI 1.4b, however, only specifies profile P0 in section 8.3.3. And I've
2273 // only seen P0 in practice. My assumption is that profiles P1-P3 are never
2274 // used, and so these bits should be 0.
2276 fail("Reserved bits MD1-MD3 must be 0.\n");
2277 for (i
= 0; i
< ARRAY_SIZE(colorimetry2_map
); i
++)
2278 if (x
[1] & (1 << i
))
2279 printf(" %s\n", colorimetry2_map
[i
]);
2280 // The sRGB bit (added in CTA-861.6) allows sources to explicitly
2281 // signal sRGB colorimetry. Without this the default colorimetry
2282 // of an RGB video is either sRGB or defaultRGB. It depends on the
2283 // Source which is used, and the Sink has no idea what it is getting.
2285 // For proper compatibility with PCs enabling sRGB support is
2287 if (!base
.uses_srgb
&& !(x
[1] & 0x20))
2288 warn("Set the sRGB colorimetry bit to avoid interop issues.\n");
2291 static const char *eotf_map
[] = {
2292 "Traditional gamma - SDR luminance range",
2293 "Traditional gamma - HDR luminance range",
2298 static void cta_hdr_static_metadata_block(const unsigned char *x
, unsigned length
)
2303 fail("Empty Data Block with length %u.\n", length
);
2306 printf(" Electro optical transfer functions:\n");
2307 for (i
= 0; i
< 6; i
++) {
2308 if (x
[0] & (1 << i
)) {
2309 if (i
< ARRAY_SIZE(eotf_map
)) {
2310 printf(" %s\n", eotf_map
[i
]);
2312 printf(" Unknown (%u)\n", i
);
2313 fail("Unknown EOTF (%u).\n", i
);
2317 printf(" Supported static metadata descriptors:\n");
2318 for (i
= 0; i
< 8; i
++) {
2319 if (x
[1] & (1 << i
))
2320 printf(" Static metadata type %u\n", i
+ 1);
2324 printf(" Desired content max luminance: %u (%.3f cd/m^2)\n",
2325 x
[2], 50.0 * pow(2, x
[2] / 32.0));
2328 printf(" Desired content max frame-average luminance: %u (%.3f cd/m^2)\n",
2329 x
[3], 50.0 * pow(2, x
[3] / 32.0));
2332 printf(" Desired content min luminance: %u (%.3f cd/m^2)\n",
2333 x
[4], (50.0 * pow(2, x
[2] / 32.0)) * pow(x
[4] / 255.0, 2) / 100.0);
2336 static void cta_hdr_dyn_metadata_block(const unsigned char *x
, unsigned length
)
2339 fail("Empty Data Block with length %u.\n", length
);
2342 while (length
>= 3) {
2343 unsigned type_len
= x
[0];
2344 unsigned type
= x
[1] | (x
[2] << 8);
2346 if (length
< type_len
+ 1)
2348 printf(" HDR Dynamic Metadata Type %u\n", type
);
2353 printf(" Version: %u\n", x
[3] & 0xf);
2357 unsigned version
= x
[3] & 0xf;
2358 printf(" Version: %u\n", version
);
2360 if (x
[3] & 0x10) printf(" Supports SL-HDR1 (ETSI TS 103 433-1)\n");
2361 if (x
[3] & 0x20) printf(" Supports SL-HDR2 (ETSI TS 103 433-2)\n");
2362 if (x
[3] & 0x40) printf(" Supports SL-HDR3 (ETSI TS 103 433-3)\n");
2369 length
-= type_len
+ 1;
2374 static const char *infoframe_types
[] = {
2377 "Auxiliary Video Information",
2378 "Source Product Description",
2382 "Dynamic Range and Mastering",
2385 static void cta_ifdb(const unsigned char *x
, unsigned length
)
2387 unsigned len_hdr
= x
[0] >> 5;
2390 fail("Empty Data Block with length %u.\n", length
);
2393 printf(" VSIFs: %u\n", x
[1]);
2394 if (length
< len_hdr
+ 2)
2396 length
-= len_hdr
+ 2;
2398 while (length
> 0) {
2399 int payload_len
= x
[0] >> 5;
2400 unsigned char type
= x
[0] & 0x1f;
2402 const char *name
= NULL
;
2403 if (type
< ARRAY_SIZE(infoframe_types
))
2404 name
= infoframe_types
[type
];
2407 printf(" %s InfoFrame (%u)", name
, type
);
2409 if (type
== 1 && length
>= 4) {
2410 unsigned oui
= (x
[3] << 16) | (x
[2] << 8) | x
[1];
2412 printf(", OUI %s\n", ouitohex(oui
).c_str());
2421 length
-= payload_len
;
2425 void edid_state::cta_displayid_type_7(const unsigned char *x
, unsigned length
)
2427 check_displayid_datablock_revision(x
[0], 0x00, 2);
2429 if (length
< 21U + ((x
[0] & 0x70) >> 4)) {
2430 fail("Empty Data Block with length %u.\n", length
);
2433 parse_displayid_type_1_7_timing(x
+ 1, true, 2, true);
2436 void edid_state::cta_displayid_type_8(const unsigned char *x
, unsigned length
)
2438 check_displayid_datablock_revision(x
[0], 0xe8, 1);
2439 if (length
< ((x
[0] & 0x08) ? 3 : 2)) {
2440 fail("Empty Data Block with length %u.\n", length
);
2444 unsigned sz
= (x
[0] & 0x08) ? 2 : 1;
2445 unsigned type
= x
[0] >> 6;
2448 fail("Only code type 0 is supported.\n");
2453 printf(" Also supports YCbCr 4:2:0\n");
2457 for (unsigned i
= 0; i
< length
/ sz
; i
++) {
2458 unsigned id
= x
[i
* sz
];
2461 id
|= x
[i
* sz
+ 1] << 8;
2462 parse_displayid_type_4_8_timing(type
, id
, true);
2466 void edid_state::cta_displayid_type_10(const unsigned char *x
, unsigned length
)
2468 check_displayid_datablock_revision(x
[0], 0x70);
2469 if (length
< 7U + ((x
[0] & 0x70) >> 4)) {
2470 fail("Empty Data Block with length %u.\n", length
);
2474 unsigned sz
= 6U + ((x
[0] & 0x70) >> 4);
2477 for (unsigned i
= 0; i
< length
/ sz
; i
++)
2478 parse_displayid_type_10_timing(x
+ i
* sz
, sz
, true);
2481 static void cta_hdmi_audio_block(const unsigned char *x
, unsigned length
)
2486 fail("Empty Data Block with length %u.\n", length
);
2490 printf(" Max Stream Count: %u\n", (x
[0] & 3) + 1);
2492 printf(" Supports MS NonMixed\n");
2494 num_descs
= x
[1] & 7;
2499 while (length
>= 4) {
2501 unsigned format
= x
[0] & 0xf;
2503 printf(" %s, max channels %u\n", audio_format(format
).c_str(),
2505 printf(" Supported sample rates (kHz):%s%s%s%s%s%s%s\n",
2506 (x
[2] & 0x40) ? " 192" : "",
2507 (x
[2] & 0x20) ? " 176.4" : "",
2508 (x
[2] & 0x10) ? " 96" : "",
2509 (x
[2] & 0x08) ? " 88.2" : "",
2510 (x
[2] & 0x04) ? " 48" : "",
2511 (x
[2] & 0x02) ? " 44.1" : "",
2512 (x
[2] & 0x01) ? " 32" : "");
2514 printf(" Supported sample sizes (bits):%s%s%s\n",
2515 (x
[3] & 0x04) ? " 24" : "",
2516 (x
[3] & 0x02) ? " 20" : "",
2517 (x
[3] & 0x01) ? " 16" : "");
2519 unsigned sad
= ((x
[2] << 16) | (x
[1] << 8) | x
[0]);
2522 switch (x
[3] >> 4) {
2524 printf(" Speaker Allocation for 10.2 channels:\n");
2527 printf(" Speaker Allocation for 22.2 channels:\n");
2530 printf(" Speaker Allocation for 30.2 channels:\n");
2533 printf(" Unknown Speaker Allocation (0x%02x)\n", x
[3] >> 4);
2537 for (i
= 0; i
< ARRAY_SIZE(speaker_map
); i
++) {
2539 printf(" %s\n", speaker_map
[i
]);
2547 void edid_state::cta_block(const unsigned char *x
, std::vector
<unsigned> &found_tags
)
2549 unsigned length
= x
[0] & 0x1f;
2550 unsigned tag
= (x
[0] & 0xe0) >> 5;
2551 unsigned extended
= (tag
== 0x07) ? 1 : 0;
2554 if (extended
&& length
) {
2561 bool dooutputname
= true;
2562 bool audio_block
= false;
2566 case 0x01: data_block
= "Audio Data Block"; audio_block
= true; break;
2567 case 0x02: data_block
= "Video Data Block"; break;
2568 case 0x03: data_block
= "Vendor-Specific Data Block"; break;
2569 case 0x04: data_block
= "Speaker Allocation Data Block"; audio_block
= true; break;
2570 case 0x05: data_block
= "VESA Display Transfer Characteristics Data Block"; break;
2571 case 0x06: data_block
= "Video Format Data Block"; break;
2572 case 0x07: data_block
= "Unknown CTA-861 Data Block (extended tag truncated)"; break;
2574 case 0x700: data_block
= "Video Capability Data Block"; break;
2575 case 0x701: data_block
= "Vendor-Specific Video Data Block"; break;
2576 case 0x702: data_block
= "VESA Video Display Device Data Block"; break;
2577 case 0x703: data_block
= "VESA Video Timing Block Extension"; break;
2578 case 0x704: data_block
= "Reserved for HDMI Video Data Block"; break;
2579 case 0x705: data_block
= "Colorimetry Data Block"; break;
2580 case 0x706: data_block
= "HDR Static Metadata Data Block"; break;
2581 case 0x707: data_block
= "HDR Dynamic Metadata Data Block"; break;
2582 case 0x708: data_block
= "Native Video Resolution Data Block"; break;
2584 case 0x70d: data_block
= "Video Format Preference Data Block"; break;
2585 case 0x70e: data_block
= "YCbCr 4:2:0 Video Data Block"; break;
2586 case 0x70f: data_block
= "YCbCr 4:2:0 Capability Map Data Block"; break;
2587 case 0x710: data_block
= "Reserved for CTA-861 Miscellaneous Audio Fields"; break;
2588 case 0x711: data_block
= "Vendor-Specific Audio Data Block"; audio_block
= true; break;
2589 case 0x712: data_block
= "HDMI Audio Data Block"; audio_block
= true; break;
2590 case 0x713: data_block
= "Room Configuration Data Block"; audio_block
= true; break;
2591 case 0x714: data_block
= "Speaker Location Data Block"; audio_block
= true; break;
2593 case 0x720: data_block
= "InfoFrame Data Block"; break;
2595 case 0x722: data_block
= "DisplayID Type VII Video Timing Data Block"; break;
2596 case 0x723: data_block
= "DisplayID Type VIII Video Timing Data Block"; break;
2597 case 0x72a: data_block
= "DisplayID Type X Video Timing Data Block"; break;
2599 case 0x778: data_block
= "HDMI Forum EDID Extension Override Data Block"; break;
2600 case 0x779: data_block
= "HDMI Forum Sink Capability Data Block"; break;
2601 case 0x77a: data_block
= "HDMI Forum Source-Based Tone Mapping Data Block"; break;
2604 std::string unknown_name
;
2605 if (tag
< 0x700) unknown_name
= "Unknown CTA-861 Data Block";
2606 else if (tag
< 0x70d) unknown_name
= "Unknown CTA-861 Video-Related Data Block";
2607 else if (tag
< 0x720) unknown_name
= "Unknown CTA-861 Audio-Related Data Block";
2608 else if (tag
< 0x778) unknown_name
= "Unknown CTA-861 Data Block";
2609 else if (tag
< 0x780) unknown_name
= "Unknown CTA-861 HDMI-Related Data Block";
2610 else unknown_name
= "Unknown CTA-861 Data Block";
2611 unknown_name
+= std::string(" (") + (extended
? "extended " : "") + "tag " + utohex(tag
& 0xff) + ", length " + std::to_string(length
) + ")";
2612 printf(" %s:\n", unknown_name
.c_str());
2613 warn("%s.\n", unknown_name
.c_str());
2623 data_block_oui(data_block
, x
, length
, &ouinum
);
2624 x
+= (length
< 3) ? length
: 3;
2625 length
-= (length
< 3) ? length
: 3;
2626 dooutputname
= false;
2632 if (dooutputname
&& data_block
.length())
2633 printf(" %s:\n", data_block
.c_str());
2650 if (std::find(found_tags
.begin(), found_tags
.end(), tag
) != found_tags
.end())
2651 fail("Only one instance of this Data Block is allowed.\n");
2655 // See Table 52 of CTA-861-G for a description of Byte 3
2656 if (audio_block
&& !(cta
.byte3
& 0x40))
2657 fail("Audio information is present, but bit 6 of Byte 3 of the CTA-861 Extension header indicates no Basic Audio support.\n");
2660 case 0x01: cta_audio_block(x
, length
); break;
2661 case 0x02: cta_svd(x
, length
, false); break;
2662 case 0x03|kOUI_HDMI
:
2663 cta_hdmi_block(x
, length
);
2664 // The HDMI OUI is present, so this EDID represents an HDMI
2665 // interface. And HDMI interfaces must use EDID version 1.3
2666 // according to the HDMI Specification, so check for this.
2667 if (base
.edid_minor
!= 3)
2668 fail("The HDMI Specification requires EDID 1.3 instead of 1.%u.\n",
2671 case 0x03|kOUI_HDMIForum
:
2672 if (cta
.previous_cta_tag
!= (0x03|kOUI_HDMI
))
2673 fail("HDMI Forum VSDB did not immediately follow the HDMI VSDB.\n");
2674 if (cta
.have_hf_scdb
|| cta
.have_hf_vsdb
)
2675 fail("Duplicate HDMI Forum VSDB/SCDB.\n");
2676 cta_hf_scdb(x
, length
);
2677 cta
.have_hf_vsdb
= true;
2679 case 0x03|kOUI_AMD
: cta_amd(x
, length
); break;
2680 case 0x03|kOUI_Microsoft
: if (length
!= 0x12) goto dodefault
; cta_microsoft(x
, length
); break;
2681 case 0x03|kOUI_UHDA
: cta_uhda_fmm(x
, length
); break;
2682 case 0x04: cta_sadb(x
, length
); break;
2683 case 0x05: cta_vesa_dtcdb(x
, length
); break;
2684 case 0x06: cta_vfdb(x
, length
); break;
2685 case 0x07: fail("Extended tag cannot have zero length.\n"); break;
2686 case 0x700: cta_vcdb(x
, length
); break;
2687 case 0x701|kOUI_HDR10
: cta_hdr10plus(x
, length
); break;
2688 case 0x701|kOUI_Dolby
: cta_dolby_video(x
, length
); break;
2689 // 0x701|kOUI_Apple: this almost certainly contains 'BLC Info/Corrections',
2690 // since the data (spread out over two VSDBs) is very similar to what is seen
2691 // in DisplayID blocks. Since I don't know how to parse this data, we still
2692 // default to a hex dump, but I mention this here in case data on how to
2693 // parse this becomes available.
2694 case 0x702: cta_vesa_vdddb(x
, length
); break;
2695 case 0x705: cta_colorimetry_block(x
, length
); break;
2696 case 0x706: cta_hdr_static_metadata_block(x
, length
); break;
2697 case 0x707: cta_hdr_dyn_metadata_block(x
, length
); break;
2698 case 0x708: cta_nvrdb(x
, length
); return;
2699 case 0x70d: cta_vfpdb(x
, length
); break;
2700 case 0x70e: cta_svd(x
, length
, true); break;
2701 case 0x70f: cta_y420cmdb(x
, length
); break;
2702 case 0x711|kOUI_Dolby
: cta_dolby_audio(x
, length
); break;
2703 case 0x712: cta_hdmi_audio_block(x
, length
); break;
2704 case 0x713: cta_rcdb(x
, length
); break;
2705 case 0x714: cta_sldb(x
, length
); break;
2706 case 0x720: cta_ifdb(x
, length
); break;
2707 case 0x722: cta_displayid_type_7(x
, length
); break;
2708 case 0x723: cta_displayid_type_8(x
, length
); break;
2709 case 0x72a: cta_displayid_type_10(x
, length
); break;
2711 cta_hf_eeodb(x
, length
);
2713 fail("Data Block can only be present in Block 1.\n");
2714 // This must be the first CTA-861 block
2715 if (cta
.block_number
> 0)
2716 fail("Data Block starts at a wrong offset.\n");
2719 if (cta
.previous_cta_tag
!= (0x03|kOUI_HDMI
))
2720 fail("HDMI Forum SCDB did not immediately follow the HDMI VSDB.\n");
2721 if (cta
.have_hf_scdb
|| cta
.have_hf_vsdb
)
2722 fail("Duplicate HDMI Forum VSDB/SCDB.\n");
2724 fail("Data Block can only be present in Block 1.\n");
2726 data_block
= std::string("HDMI Forum SCDB");
2727 fail("Invalid length %u < 2.\n", length
);
2731 printf(" Non-zero SCDB reserved fields!\n");
2732 cta_hf_scdb(x
+ 2, length
- 2);
2733 cta
.have_hf_scdb
= true;
2736 cta_hf_sbtmdb(x
, length
);
2740 hex_block(" ", x
, length
);
2745 cta
.previous_cta_tag
= tag
;
2746 found_tags
.push_back(tag
);
2749 void edid_state::preparse_cta_block(unsigned char *x
)
2751 unsigned version
= x
[1];
2752 unsigned offset
= x
[2];
2755 const unsigned char *detailed
;
2757 for (detailed
= x
+ offset
; detailed
+ 17 < x
+ 127; detailed
+= 18) {
2758 if (memchk(detailed
, 18))
2760 if (detailed
[0] || detailed
[1])
2761 cta
.preparsed_total_dtds
++;
2768 for (unsigned i
= 4; i
< offset
; i
+= (x
[i
] & 0x1f) + 1) {
2769 bool for_ycbcr420
= false;
2772 switch ((x
[i
] & 0xe0) >> 5) {
2774 oui
= (x
[i
+ 3] << 16) + (x
[i
+ 2] << 8) + x
[i
+ 1];
2775 if (oui
== 0x000c03) {
2776 cta
.has_hdmi
= true;
2777 cta
.preparsed_phys_addr
= (x
[i
+ 4] << 8) | x
[i
+ 5];
2778 } else if ((oui
== 0xca125c || oui
== 0x5c12ca) &&
2779 (x
[i
] & 0x1f) == 0x15 && replace_unique_ids
) {
2780 memset(x
+ i
+ 6, 0, 16);
2781 replace_checksum(x
, EDID_PAGE_SIZE
);
2785 if (!(x
[i
] & 0x1f) || cta
.preparsed_first_vfd
.rid
)
2787 cta
.preparsed_first_vfd
= cta_parse_vfd(x
+ i
+ 2, (x
[i
+ 1] & 3) + 1);
2790 if (x
[i
+ 1] == 0x0d)
2791 cta
.has_vfpdb
= true;
2792 else if (x
[i
+ 1] == 0x05)
2794 else if (x
[i
+ 1] == 0x08)
2795 cta
.has_nvrdb
= true;
2796 else if (x
[i
+ 1] == 0x13 && (x
[i
+ 2] & 0x40)) {
2797 cta
.preparsed_speaker_count
= 1 + (x
[i
+ 2] & 0x1f);
2798 cta
.preparsed_sld
= x
[i
+ 2] & 0x20;
2799 } else if (x
[i
+ 1] == 0x14)
2800 cta_preparse_sldb(x
+ i
+ 2, (x
[i
] & 0x1f) - 1);
2801 else if (x
[i
+ 1] == 0x22)
2802 cta
.preparsed_total_vtdbs
++;
2803 else if (x
[i
+ 1] == 0x23) {
2804 cta
.preparsed_has_t8vtdb
= true;
2805 cta
.preparsed_t8vtdb_dmt
= x
[i
+ 3];
2806 if (x
[i
+ 2] & 0x08)
2807 cta
.preparsed_t8vtdb_dmt
|= x
[i
+ 4] << 8;
2808 } else if (x
[i
+ 1] == 0x2a)
2809 cta
.preparsed_total_vtdbs
+=
2810 ((x
[i
] & 0x1f) - 2) / (6 + ((x
[i
+ 2] & 0x70) >> 4));
2811 else if (x
[i
+ 1] == 0x78)
2812 cta
.hf_eeodb_blocks
= x
[i
+ 2];
2813 if (x
[i
+ 1] != 0x0e)
2815 for_ycbcr420
= true;
2816 #ifdef __EMSCRIPTEN__
2817 [[clang::fallthrough
]];
2821 for (unsigned j
= 1 + for_ycbcr420
; j
<= (x
[i
] & 0x1f); j
++) {
2822 unsigned char vic
= x
[i
+ j
];
2824 if ((vic
& 0x7f) <= 64)
2826 cta
.preparsed_svds
[for_ycbcr420
].push_back(vic
);
2827 cta
.preparsed_has_vic
[for_ycbcr420
][vic
] = true;
2829 const struct timings
*t
= find_vic_id(vic
);
2831 if (!for_ycbcr420
&& t
&&
2832 t
->pixclk_khz
> cta
.preparsed_max_vic_pixclk_khz
)
2833 cta
.preparsed_max_vic_pixclk_khz
= t
->pixclk_khz
;
2840 void edid_state::parse_cta_block(const unsigned char *x
)
2842 unsigned version
= x
[1];
2843 unsigned offset
= x
[2];
2844 const unsigned char *detailed
;
2846 // See Table 52 of CTA-861-G for a description of Byte 3
2848 printf(" Revision: %u\n", version
);
2850 fail("Invalid CTA-861 Extension revision 0.\n");
2852 fail("Deprecated CTA-861 Extension revision 2.\n");
2853 if (cta
.has_hdmi
&& version
!= 3)
2854 fail("The HDMI Specification requires CTA Extension revision 3.\n");
2856 warn("Unknown CTA-861 Extension revision %u.\n", version
);
2857 if (offset
> 0 && offset
< 4)
2858 fail("Invalid CTA-861 Extension offset value (byte 2).\n");
2860 if (version
>= 1) do {
2861 if (version
== 1 && x
[3] != 0)
2862 fail("Non-zero byte 3.\n");
2864 if (version
< 3 && offset
>= 4 && ((offset
- 4) / 8)) {
2865 printf(" 8-byte timing descriptors: %u\n", (offset
- 4) / 8);
2866 fail("8-byte descriptors were never used.\n");
2871 printf(" Underscans IT Video Formats by default\n");
2873 warn("IT Video Formats are overscanned by default, but normally this should be underscanned.\n");
2875 printf(" Basic audio support\n");
2877 printf(" Supports YCbCr 4:4:4\n");
2879 printf(" Supports YCbCr 4:2:2\n");
2880 // Disable this test: this fails a lot of EDIDs, and there are
2881 // also some corner cases where you only want to receive 4:4:4
2882 // and refuse a fallback to 4:2:2.
2883 // if ((x[3] & 0x30) && (x[3] & 0x30) != 0x30)
2884 // msg(!cta.has_hdmi, "If YCbCr support is indicated, then both 4:2:2 and 4:4:4 %s be supported.\n",
2885 // cta.has_hdmi ? "shall" : "should");
2886 printf(" Native detailed modes: %u\n", x
[3] & 0x0f);
2887 if (cta
.block_number
== 0)
2889 else if (x
[3] != cta
.byte3
)
2890 fail("Byte 3 must be the same for all CTA-861 Extension Blocks.\n");
2891 if (cta
.block_number
== 0) {
2892 unsigned native_dtds
= x
[3] & 0x0f;
2894 cta
.native_timings
.clear();
2895 if (!native_dtds
&& !cta
.has_vfpdb
) {
2896 cta
.first_svd_might_be_preferred
= true;
2897 } else if (native_dtds
> cta
.preparsed_total_dtds
) {
2898 fail("There are more Native DTDs (%u) than DTDs (%u).\n",
2899 native_dtds
, cta
.preparsed_total_dtds
);
2901 if (native_dtds
> cta
.preparsed_total_dtds
)
2902 native_dtds
= cta
.preparsed_total_dtds
;
2903 for (unsigned i
= 0; i
< native_dtds
; i
++) {
2906 sprintf(type
, "DTD %3u", i
+ 1);
2907 cta
.native_timings
.push_back(timings_ext(i
+ 129, type
));
2909 if (cta
.has_hdmi
&& block_nr
!= (block_map
.saw_block_1
? 2 : 1))
2910 fail("The HDMI Specification requires that the first Extension Block (that is not a Block Map) is an CTA-861 Extension Block.\n");
2915 // Offset 0 means that there are no data blocks or DTDs,
2916 // so the remainder must be padding.
2917 if (!memchk(x
+ 4, 127 - 4)) {
2918 data_block
= "Padding";
2919 fail("Contains non-zero bytes.\n");
2927 for (i
= 4; i
< offset
; i
+= (x
[i
] & 0x1f) + 1) {
2928 cta_block(x
+ i
, cta
.found_tags
);
2933 fail("Offset is %u, but should be %u.\n", offset
, i
);
2936 data_block
= "Detailed Timing Descriptors";
2937 base
.seen_non_detailed_descriptor
= false;
2939 for (detailed
= x
+ offset
; detailed
+ 17 < x
+ 127; detailed
+= 18) {
2940 if (memchk(detailed
, 18))
2944 printf(" %s:\n", data_block
.c_str());
2946 detailed_block(detailed
);
2948 unused_bytes
= x
+ 127 - detailed
;
2949 if (!memchk(detailed
, unused_bytes
)) {
2950 data_block
= "Padding";
2951 fail("Contains non-zero bytes.\n");
2956 if (base
.serial_number
&& base
.has_serial_string
)
2957 warn("Display Product Serial Number is set, so the Serial Number in the Base EDID should be 0.\n");
2958 if (!cta
.has_vic_1
&& !base
.has_640x480p60_est_timing
)
2959 fail("Required 640x480p60 timings are missing in the established timings"
2960 " and the SVD list (VIC 1).\n");
2961 if ((cta
.supported_hdmi_vic_vsb_codes
& cta
.supported_hdmi_vic_codes
) !=
2962 cta
.supported_hdmi_vic_codes
)
2963 fail("HDMI VIC Codes must have their CTA-861 VIC equivalents in the VSB.\n");
2965 fail("Missing VCDB, needed for Set Selectable RGB Quantization to avoid interop issues.\n");
2966 if (!base
.uses_srgb
&& !cta
.has_cdb
)
2967 warn("Add a Colorimetry Data Block with the sRGB colorimetry bit set to avoid interop issues.\n");
2970 void edid_state::cta_resolve_svr(timings_ext
&t_ext
)
2972 if (t_ext
.svr() == 254) {
2973 t_ext
.flags
= cta
.t8vtdb
.flags
;
2974 add_str(t_ext
.flags
, ">=CTA-861-H");
2975 t_ext
.t
= cta
.t8vtdb
.t
;
2976 } else if (t_ext
.svr() <= 144) {
2977 if (t_ext
.svr() < 129 || t_ext
.svr() - 129 >= cta
.vec_dtds
.size())
2979 t_ext
.flags
= cta
.vec_dtds
[t_ext
.svr() - 129].flags
;
2980 t_ext
.t
= cta
.vec_dtds
[t_ext
.svr() - 129].t
;
2981 } else if (t_ext
.svr() <= 160) {
2982 if (t_ext
.svr() - 145 >= cta
.vec_vtdbs
.size())
2984 t_ext
.flags
= cta
.vec_vtdbs
[t_ext
.svr() - 145].flags
;
2985 add_str(t_ext
.flags
, ">=CTA-861-H");
2986 t_ext
.t
= cta
.vec_vtdbs
[t_ext
.svr() - 145].t
;
2987 } else if (t_ext
.svr() <= 175) {
2988 t_ext
.flags
.clear();
2989 unsigned char rid
= cta
.preparsed_first_vfd
.rid
;
2990 t_ext
.t
= calc_ovt_mode(rids
[rid
].hact
, rids
[rid
].vact
,
2991 rids
[rid
].hratio
, rids
[rid
].vratio
,
2992 vf_rate_values
[t_ext
.svr() - 160]);
2993 t_ext
.flags
= ">=CTA-861.6";
2997 void edid_state::cta_resolve_svrs()
2999 for (vec_timings_ext::iterator iter
= cta
.preferred_timings_vfpdb
.begin();
3000 iter
!= cta
.preferred_timings_vfpdb
.end(); ++iter
) {
3001 if (iter
->has_svr())
3002 cta_resolve_svr(*iter
);
3005 for (vec_timings_ext::iterator iter
= cta
.native_timings
.begin();
3006 iter
!= cta
.native_timings
.end(); ++iter
) {
3007 if (iter
->has_svr())
3008 cta_resolve_svr(*iter
);
3011 for (vec_timings_ext::iterator iter
= cta
.native_timing_nvrdb
.begin();
3012 iter
!= cta
.native_timing_nvrdb
.end(); ++iter
) {
3013 if (iter
->has_svr())
3014 cta_resolve_svr(*iter
);
3018 void edid_state::check_cta_blocks()
3020 unsigned max_pref_prog_hact
= 0;
3021 unsigned max_pref_prog_vact
= 0;
3022 unsigned max_pref_ilace_hact
= 0;
3023 unsigned max_pref_ilace_vact
= 0;
3025 data_block
= "CTA-861";
3027 // HDMI 1.4 goes up to 340 MHz. Dubious to have a DTD above that,
3028 // but no VICs. Displays often have a setting to turn off HDMI 2.x
3029 // support, dropping any HDMI 2.x VICs, but they sometimes forget
3030 // to replace the DTD in the base block as well.
3031 if (cta
.warn_about_hdmi_2x_dtd
)
3032 warn("DTD pixelclock indicates HDMI 2.x support, VICs indicate HDMI 1.x.\n");
3034 for (vec_timings_ext::iterator iter
= cta
.preferred_timings
.begin();
3035 iter
!= cta
.preferred_timings
.end(); ++iter
) {
3036 if (iter
->t
.interlaced
&&
3037 (iter
->t
.vact
> max_pref_ilace_vact
||
3038 (iter
->t
.vact
== max_pref_ilace_vact
&& iter
->t
.hact
>= max_pref_ilace_hact
))) {
3039 max_pref_ilace_hact
= iter
->t
.hact
;
3040 max_pref_ilace_vact
= iter
->t
.vact
;
3042 if (!iter
->t
.interlaced
&&
3043 (iter
->t
.vact
> max_pref_prog_vact
||
3044 (iter
->t
.vact
== max_pref_prog_vact
&& iter
->t
.hact
>= max_pref_prog_hact
))) {
3045 max_pref_prog_hact
= iter
->t
.hact
;
3046 max_pref_prog_vact
= iter
->t
.vact
;
3049 for (vec_timings_ext::iterator iter
= cta
.preferred_timings_vfpdb
.begin();
3050 iter
!= cta
.preferred_timings_vfpdb
.end(); ++iter
) {
3051 if (iter
->t
.interlaced
&&
3052 (iter
->t
.vact
> max_pref_ilace_vact
||
3053 (iter
->t
.vact
== max_pref_ilace_vact
&& iter
->t
.hact
>= max_pref_ilace_hact
))) {
3054 max_pref_ilace_hact
= iter
->t
.hact
;
3055 max_pref_ilace_vact
= iter
->t
.vact
;
3057 if (!iter
->t
.interlaced
&&
3058 (iter
->t
.vact
> max_pref_prog_vact
||
3059 (iter
->t
.vact
== max_pref_prog_vact
&& iter
->t
.hact
>= max_pref_prog_hact
))) {
3060 max_pref_prog_hact
= iter
->t
.hact
;
3061 max_pref_prog_vact
= iter
->t
.vact
;
3065 unsigned native_prog
= 0;
3066 unsigned native_prog_hact
= 0;
3067 unsigned native_prog_vact
= 0;
3068 bool native_prog_mixed_resolutions
= false;
3069 unsigned native_ilace
= 0;
3070 unsigned native_ilace_hact
= 0;
3071 unsigned native_ilace_vact
= 0;
3072 bool native_ilace_mixed_resolutions
= false;
3073 unsigned native_nvrdb_hact
= 0;
3074 unsigned native_nvrdb_vact
= 0;
3076 for (vec_timings_ext::iterator iter
= cta
.native_timings
.begin();
3077 iter
!= cta
.native_timings
.end(); ++iter
) {
3078 if (iter
->t
.interlaced
) {
3080 if (!native_ilace_hact
) {
3081 native_ilace_hact
= iter
->t
.hact
;
3082 native_ilace_vact
= iter
->t
.vact
;
3083 } else if (native_ilace_hact
!= iter
->t
.hact
||
3084 native_ilace_vact
!= iter
->t
.vact
) {
3085 native_ilace_mixed_resolutions
= true;
3089 if (!native_prog_hact
) {
3090 native_prog_hact
= iter
->t
.hact
;
3091 native_prog_vact
= iter
->t
.vact
;
3092 } else if (native_prog_hact
!= iter
->t
.hact
||
3093 native_prog_vact
!= iter
->t
.vact
) {
3094 native_prog_mixed_resolutions
= true;
3099 for (vec_timings_ext::iterator iter
= cta
.native_timing_nvrdb
.begin();
3100 iter
!= cta
.native_timing_nvrdb
.end(); ++iter
) {
3101 native_nvrdb_hact
= iter
->t
.hact
;
3102 native_nvrdb_vact
= iter
->t
.vact
;
3105 if (native_prog_mixed_resolutions
)
3106 fail("Native progressive timings are a mix of several resolutions.\n");
3107 if (native_ilace_mixed_resolutions
)
3108 fail("Native interlaced timings are a mix of several resolutions.\n");
3109 if (native_ilace
&& !native_prog
)
3110 fail("A native interlaced timing is present, but not a native progressive timing.\n");
3111 if (!native_prog_mixed_resolutions
&& native_prog
> 1)
3112 warn("Multiple native progressive timings are defined.\n");
3113 if (!native_ilace_mixed_resolutions
&& native_ilace
> 1)
3114 warn("Multiple native interlaced timings are defined.\n");
3116 if (native_nvrdb_vact
&&
3117 (max_pref_prog_vact
> native_nvrdb_vact
||
3118 (max_pref_prog_vact
== native_nvrdb_vact
&& max_pref_prog_hact
> native_nvrdb_hact
)))
3119 warn("Native video resolution of %ux%u is smaller than the max preferred progressive resolution %ux%u.\n",
3120 native_nvrdb_hact
, native_nvrdb_vact
,
3121 max_pref_prog_hact
, max_pref_prog_vact
);
3122 else if (!native_nvrdb_vact
&& !native_prog_mixed_resolutions
&& native_prog_vact
&&
3123 (max_pref_prog_vact
> native_prog_vact
||
3124 (max_pref_prog_vact
== native_prog_vact
&& max_pref_prog_hact
> native_prog_hact
)))
3125 warn("Native progressive resolution of %ux%u is smaller than the max preferred progressive resolution %ux%u.\n",
3126 native_prog_hact
, native_prog_vact
,
3127 max_pref_prog_hact
, max_pref_prog_vact
);
3128 if (!native_ilace_mixed_resolutions
&& native_ilace_vact
&&
3129 (max_pref_ilace_vact
> native_ilace_vact
||
3130 (max_pref_ilace_vact
== native_ilace_vact
&& max_pref_ilace_hact
> native_ilace_hact
)))
3131 warn("Native interlaced resolution of %ux%u is smaller than the max preferred interlaced resolution %ux%u.\n",
3132 native_ilace_hact
, native_ilace_vact
,
3133 max_pref_ilace_hact
, max_pref_ilace_vact
);
3135 if (dispid
.native_width
&& native_prog_hact
&&
3136 !native_prog_mixed_resolutions
) {
3137 if (dispid
.native_width
!= native_prog_hact
||
3138 dispid
.native_height
!= native_prog_vact
)
3139 fail("Mismatch between CTA-861 and DisplayID native progressive resolution.\n");