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 unsigned rate
= x
[3] * 5;
1013 printf(" Maximum TMDS clock: %u MHz\n", rate
);
1014 cta
.hdmi_max_rate
= rate
;
1016 fail("HDMI VSDB Max TMDS rate is > 340.\n");
1022 printf(" Supported Content Types:\n");
1024 printf(" Graphics\n");
1028 printf(" Cinema\n");
1035 hdmi_latency(x
[b
], x
[b
+ 1], false);
1038 if (x
[b
] == x
[b
+ 2] &&
1039 x
[b
+ 1] == x
[b
+ 3])
1040 warn("Progressive and Interlaced latency values are identical, no need for both.\n");
1042 hdmi_latency(x
[b
], x
[b
+ 1], true);
1051 bool formats
= false;
1053 printf(" Extended HDMI video details:\n");
1055 printf(" 3D present\n");
1056 if ((x
[b
] & 0x60) == 0x20) {
1057 printf(" All advertised VICs are 3D-capable\n");
1060 if ((x
[b
] & 0x60) == 0x40) {
1061 printf(" 3D-capable-VIC mask present\n");
1065 switch (x
[b
] & 0x18) {
1068 printf(" Base EDID image size is aspect ratio\n");
1071 printf(" Base EDID image size is in units of 1 cm\n");
1074 printf(" Base EDID image size is in units of 5 cm\n");
1075 base
.max_display_width_mm
*= 5;
1076 base
.max_display_height_mm
*= 5;
1077 printf(" Recalculated image size: %u cm x %u cm\n",
1078 base
.max_display_width_mm
/ 10, base
.max_display_height_mm
/ 10);
1082 len_vic
= (x
[b
] & 0xe0) >> 5;
1083 len_3d
= (x
[b
] & 0x1f) >> 0;
1089 printf(" HDMI VICs:\n");
1090 for (i
= 0; i
< len_vic
; i
++) {
1091 unsigned char vic
= x
[b
+ i
];
1092 const struct timings
*t
;
1094 if (vic
&& vic
<= ARRAY_SIZE(edid_hdmi_mode_map
)) {
1095 std::string suffix
= "HDMI VIC " + std::to_string(vic
);
1096 cta
.supported_hdmi_vic_codes
|= 1 << (vic
- 1);
1097 t
= find_vic_id(edid_hdmi_mode_map
[vic
- 1]);
1098 print_timings(" ", t
, suffix
.c_str());
1100 printf(" Unknown (HDMI VIC %u)\n", vic
);
1101 fail("Unknown HDMI VIC %u.\n", vic
);
1112 /* 3D_Structure_ALL_15..8 */
1114 printf(" 3D: Side-by-side (half, quincunx)\n");
1116 printf(" 3D: Side-by-side (half, horizontal)\n");
1117 /* 3D_Structure_ALL_7..0 */
1120 printf(" 3D: Top-and-bottom\n");
1122 printf(" 3D: L + depth + gfx + gfx-depth\n");
1124 printf(" 3D: L + depth\n");
1126 printf(" 3D: Side-by-side (full)\n");
1128 printf(" 3D: Line-alternative\n");
1130 printf(" 3D: Field-alternative\n");
1132 printf(" 3D: Frame-packing\n");
1141 printf(" 3D VIC indices that support these capabilities:\n");
1142 /* worst bit ordering ever */
1143 for (i
= 0; i
< 8; i
++)
1144 if (x
[b
+ 1] & (1 << i
)) {
1145 print_vic_index(" ", i
, "");
1148 for (i
= 0; i
< 8; i
++)
1149 if (x
[b
] & (1 << i
)) {
1150 print_vic_index(" ", i
+ 8, "");
1155 if (max_idx
>= (int)cta
.preparsed_svds
[0].size())
1156 fail("HDMI 3D VIC indices max index %d > %u (#SVDs).\n",
1157 max_idx
+ 1, cta
.preparsed_svds
[0].size());
1164 * (optionally: 3D_Detail_X and reserved)
1169 unsigned end
= b
+ len_3d
;
1172 printf(" 3D VIC indices with specific capabilities:\n");
1174 unsigned char idx
= x
[b
] >> 4;
1179 switch (x
[b
] & 0x0f) {
1180 case 0: s
= "frame packing"; break;
1181 case 1: s
= "field alternative"; break;
1182 case 2: s
= "line alternative"; break;
1183 case 3: s
= "side-by-side (full)"; break;
1184 case 4: s
= "L + depth"; break;
1185 case 5: s
= "L + depth + gfx + gfx-depth"; break;
1186 case 6: s
= "top-and-bottom"; break;
1189 switch (x
[b
+ 1] >> 4) {
1190 case 0x00: s
+= ", any subsampling"; break;
1191 case 0x01: s
+= ", horizontal"; break;
1192 case 0x02: case 0x03: case 0x04: case 0x05:
1193 s
+= ", not in use";
1194 fail("not-in-use 3D_Detail_X value 0x%02x.\n",
1197 case 0x06: s
+= ", all quincunx combinations"; break;
1198 case 0x07: s
+= ", quincunx odd/left, odd/right"; break;
1199 case 0x08: s
+= ", quincunx odd/left, even/right"; break;
1200 case 0x09: s
+= ", quincunx even/left, odd/right"; break;
1201 case 0x0a: s
+= ", quincunx even/left, even/right"; break;
1204 fail("reserved 3D_Detail_X value 0x%02x.\n",
1211 s
+= utohex(x
[b
] & 0x0f) + ")";
1212 fail("Unknown 3D_Structure_X value 0x%02x.\n", x
[b
] & 0x0f);
1215 print_vic_index(" ", idx
, s
.c_str());
1216 if ((x
[b
] & 0x0f) >= 8)
1220 if (max_idx
>= (int)cta
.preparsed_svds
[0].size())
1221 fail("HDMI 2D VIC indices max index %d > %u (#SVDs).\n",
1222 max_idx
+ 1, cta
.preparsed_svds
[0].size());
1225 static const char *max_frl_rates
[] = {
1227 "3 Gbps per lane on 3 lanes",
1228 "3 and 6 Gbps per lane on 3 lanes",
1229 "3 and 6 Gbps per lane on 3 lanes, 6 Gbps on 4 lanes",
1230 "3 and 6 Gbps per lane on 3 lanes, 6 and 8 Gbps on 4 lanes",
1231 "3 and 6 Gbps per lane on 3 lanes, 6, 8 and 10 Gbps on 4 lanes",
1232 "3 and 6 Gbps per lane on 3 lanes, 6, 8, 10 and 12 Gbps on 4 lanes",
1235 static const char *dsc_max_slices
[] = {
1237 "up to 1 slice and up to (340 MHz/Ksliceadjust) pixel clock per slice",
1238 "up to 2 slices and up to (340 MHz/Ksliceadjust) pixel clock per slice",
1239 "up to 4 slices and up to (340 MHz/Ksliceadjust) pixel clock per slice",
1240 "up to 8 slices and up to (340 MHz/Ksliceadjust) pixel clock per slice",
1241 "up to 8 slices and up to (400 MHz/Ksliceadjust) pixel clock per slice",
1242 "up to 12 slices and up to (400 MHz/Ksliceadjust) pixel clock per slice",
1243 "up to 12 slices and up to (600 MHz/Ksliceadjust) pixel clock per slice",
1246 static void cta_hf_eeodb(const unsigned char *x
, unsigned length
)
1248 printf(" EDID Extension Block Count: %u\n", x
[0]);
1250 fail("Block is too long.\n");
1252 fail("Extension Block Count == %u.\n", x
[0]);
1255 void edid_state::cta_hf_scdb(const unsigned char *x
, unsigned length
)
1257 unsigned rate
= x
[1] * 5;
1260 printf(" Version: %u\n", x
[0]);
1262 printf(" Maximum TMDS Character Rate: %u MHz\n", rate
);
1263 if (rate
<= 340 || rate
> 600)
1264 fail("Max TMDS rate is > 0 and <= 340 or > 600.\n");
1265 if (rate
< cta
.hdmi_max_rate
)
1266 fail("HDMI Forum VSDB rate < HDMI VSDB rate.\n");
1268 cta
.hdmi_max_rate
= rate
;
1271 printf(" SCDC Present\n");
1273 printf(" SCDC Read Request Capable\n");
1275 printf(" Supports Cable Status\n");
1277 printf(" Supports Color Content Bits Per Component Indication\n");
1279 printf(" Supports scrambling for <= 340 Mcsc\n");
1281 printf(" Supports 3D Independent View signaling\n");
1283 printf(" Supports 3D Dual View signaling\n");
1285 printf(" Supports 3D OSD Disparity signaling\n");
1287 unsigned max_frl_rate
= x
[3] >> 4;
1289 printf(" Max Fixed Rate Link: ");
1290 if (max_frl_rate
< ARRAY_SIZE(max_frl_rates
)) {
1291 printf("%s\n", max_frl_rates
[max_frl_rate
]);
1293 printf("Unknown (0x%02x)\n", max_frl_rate
);
1294 fail("Unknown Max Fixed Rate Link (0x%02x).\n", max_frl_rate
);
1296 if (max_frl_rate
== 1 && rate
< 300)
1297 fail("Max Fixed Rate Link is 1, but Max TMDS rate < 300.\n");
1298 else if (max_frl_rate
>= 2 && rate
< 600)
1299 fail("Max Fixed Rate Link is >= 2, but Max TMDS rate < 600.\n");
1302 // Currently I do not really know how to translate the
1303 // Max FRL value to an equivalent max clock frequency.
1304 // So reset this field to 0 to skip any clock rate checks.
1305 cta
.hdmi_max_rate
= 0;
1308 printf(" Supports UHD VIC\n");
1310 printf(" Supports 16-bits/component Deep Color 4:2:0 Pixel Encoding\n");
1312 printf(" Supports 12-bits/component Deep Color 4:2:0 Pixel Encoding\n");
1314 printf(" Supports 10-bits/component Deep Color 4:2:0 Pixel Encoding\n");
1320 printf(" Supports FAPA End Extended\n");
1322 printf(" Supports QMS\n");
1324 printf(" Supports Mdelta\n");
1326 printf(" Supports media rates below VRRmin (CinemaVRR, deprecated)\n");
1327 warn("CinemaVRR is deprecated and must be cleared.\n");
1330 printf(" Supports negative Mvrr values\n");
1332 printf(" Supports Fast Vactive\n");
1334 printf(" Supports Auto Low-Latency Mode\n");
1336 printf(" Supports a FAPA in blanking after first active video line\n");
1343 printf(" VRRmin: %u Hz\n", v
);
1345 fail("VRRmin > 48.\n");
1347 v
= (x
[5] & 0xc0) << 2 | x
[6];
1349 printf(" VRRmax: %u Hz\n", v
);
1351 fail("VRRmin == 0, but VRRmax isn't.\n");
1353 fail("VRRmax < 100.\n");
1360 printf(" Supports VESA DSC 1.2a compression\n");
1362 printf(" Supports Compressed Video Transport for 4:2:0 Pixel Encoding\n");
1364 printf(" Supports QMS TFRmax\n");
1366 printf(" Supports QMS TFRmin\n");
1368 printf(" Supports Compressed Video Transport at any valid 1/16th bit bpp\n");
1370 printf(" Supports 16 bpc Compressed Video Transport\n");
1372 printf(" Supports 12 bpc Compressed Video Transport\n");
1374 printf(" Supports 10 bpc Compressed Video Transport\n");
1376 unsigned max_slices
= x
[8] & 0xf;
1378 printf(" DSC Max Slices: ");
1379 if (max_slices
< ARRAY_SIZE(dsc_max_slices
)) {
1380 printf("%s\n", dsc_max_slices
[max_slices
]);
1382 printf("Unknown (%u), interpreted as: %s\n", max_slices
,
1384 warn("Unknown DSC Max Slices (%u).\n", max_slices
);
1388 unsigned max_frl_rate
= x
[8] >> 4;
1390 printf(" DSC Max Fixed Rate Link: ");
1391 if (max_frl_rate
< ARRAY_SIZE(max_frl_rates
)) {
1392 printf("%s\n", max_frl_rates
[max_frl_rate
]);
1394 printf("Unknown (0x%02x)\n", max_frl_rate
);
1395 fail("Unknown DSC Max Fixed Rate Link (0x%02x).\n", max_frl_rate
);
1399 printf(" Maximum number of bytes in a line of chunks: %u\n",
1400 1024 * (1 + (x
[9] & 0x3f)));
1403 // Convert a PQ value (0-1) to cd/m^2 aka nits (0-10000)
1404 static double pq2nits(double pq
)
1406 const double m1
= 2610.0 / 16384.0;
1407 const double m2
= 128.0 * (2523.0 / 4096.0);
1408 const double c1
= 3424.0 / 4096.0;
1409 const double c2
= 32.0 * (2413.0 / 4096.0);
1410 const double c3
= 32.0 * (2392.0 / 4096.0);
1411 double e
= pow(pq
, 1.0 / m2
);
1417 v
= pow(v
, 1.0 / m1
);
1421 static double chrom2d(const unsigned char *x
)
1423 unsigned v
= x
[0] + (x
[1] << 8);
1428 static double perc2d(unsigned char x
)
1433 return 100.0 * (m
/ 64.0) * pow(10, -e
);
1436 static void cta_hf_sbtmdb(const unsigned char *x
, unsigned length
)
1441 fail("Block is too short.\n");
1442 printf(" Version: %d\n", x
[0] & 0xf);
1443 switch ((x
[0] >> 5) & 3) {
1445 printf(" Does not support a General RDM format\n");
1448 printf(" Supports an SDR-range General RDM format\n");
1451 printf(" Supports an HDR-range General RDM format\n");
1454 fail("Invalid GRDM Support value.\n");
1460 bool uses_hgig_drdm
= true;
1462 printf(" Supports a D-RDM format\n");
1464 printf(" Use HGIG D-RDM\n");
1467 printf(" HGIG D-RDM is not used\n");
1468 uses_hgig_drdm
= false;
1471 printf(" PBnits[0] = 600 cd/m^2\n");
1474 printf(" PBnits[0] = 1000 cd/m^2\n");
1477 printf(" PBnits[0] = 4000 cd/m^2\n");
1480 printf(" PBnits[0] = 10000 cd/m^2\n");
1483 fail("Invalid HGIG D-DRM value.\n");
1487 bool has_chromaticities
= false;
1490 printf(" MaxRGB\n");
1491 switch (x
[1] >> 6) {
1493 printf(" Gamut is explicit\n");
1494 has_chromaticities
= true;
1497 printf(" Gamut is Rec. ITU-R BT.709\n");
1500 printf(" Gamut is SMPTE ST 2113\n");
1503 printf(" Gamut is Rec. ITU-R BT.2020\n");
1508 if (has_chromaticities
) {
1509 printf(" Red: (%.5f, %.5f)\n", chrom2d(x
), chrom2d(x
+ 2));
1510 printf(" Green: (%.5f, %.5f)\n", chrom2d(x
+ 4), chrom2d(x
+ 6));
1511 printf(" Blue: (%.5f, %.5f)\n", chrom2d(x
+ 8), chrom2d(x
+ 10));
1512 printf(" White: (%.5f, %.5f)\n", chrom2d(x
+ 12), chrom2d(x
+ 14));
1518 printf(" Min Brightness 10: %.8f cd/m^2\n", pq2nits((x
[0] << 1) / 4095.0));
1519 printf(" Peak Brightness 100: %u cd/m^2\n", (unsigned)pq2nits((x
[1] << 4) / 4095.0));
1524 printf(" Percentage of Peak Brightness P0: %.2f%%\n", perc2d(x
[0]));
1525 printf(" Peak Brightness P0: %.8f cd/m^2\n", pq2nits((x
[1] << 1) / 4095.0));
1530 printf(" Percentage of Peak Brightness P1: %.2f%%\n", perc2d(x
[0]));
1531 printf(" Peak Brightness P1: %.8f cd/m^2\n", pq2nits((x
[1] << 1) / 4095.0));
1536 printf(" Percentage of Peak Brightness P2: %.2f%%\n", perc2d(x
[0]));
1537 printf(" Peak Brightness P2: %.8f cd/m^2\n", pq2nits((x
[1] << 1) / 4095.0));
1542 printf(" Percentage of Peak Brightness P3: %.2f%%\n", perc2d(x
[0]));
1543 printf(" Peak Brightness P3: %.8f cd/m^2\n", pq2nits((x
[1] << 1) / 4095.0));
1546 static void cta_amd(const unsigned char *x
, unsigned length
)
1548 // These Freesync values are reversed engineered by looking
1549 // at existing EDIDs.
1550 printf(" Version: %u.%u\n", x
[0], x
[1]);
1551 printf(" Minimum Refresh Rate: %u Hz\n", x
[2]);
1552 printf(" Maximum Refresh Rate: %u Hz\n", x
[3]);
1553 // Freesync 1.x flags
1554 // One or more of the 0xe6 bits signal that the VESA MCCS
1555 // protocol is used to switch the Freesync range
1556 printf(" Flags 1.x: 0x%02x%s\n", x
[4],
1557 (x
[4] & 0xe6) ? " (MCCS)" : "");
1559 // Freesync 2.x flags
1560 // Bit 2 no doubt indicates if the monitor supports Local Dimming
1561 // There are probably also bits to signal support of the
1562 // FreeSync2_scRGB and FreeSync2_Gamma22 HDR display modes.
1563 // I suspect bits 0 and 1.
1564 printf(" Flags 2.x: 0x%02x\n", x
[5]);
1565 // The AMD tone mapping tutorial referred to in the URL below
1566 // mentions that the Freesync HDR info reports max/min
1567 // luminance of the monitor with and without local dimming.
1569 // https://gpuopen.com/learn/using-amd-freesync-premium-pro-hdr-code-samples/
1571 // So I assume that the first two luminance values are
1572 // the max/min luminance of the display and the next two
1573 // luminance values are the max/min luminance values when
1574 // local dimming is disabled. The values I get seem to
1576 printf(" Maximum luminance: %u (%.3f cd/m^2)\n",
1577 x
[6], 50.0 * pow(2, x
[6] / 32.0));
1578 printf(" Minimum luminance: %u (%.3f cd/m^2)\n",
1579 x
[7], (50.0 * pow(2, x
[6] / 32.0)) * pow(x
[7] / 255.0, 2) / 100.0);
1581 // One or both bytes can be 0. The meaning of that
1583 printf(" Maximum luminance (without local dimming): %u (%.3f cd/m^2)\n",
1584 x
[8], 50.0 * pow(2, x
[8] / 32.0));
1585 printf(" Minimum luminance (without local dimming): %u (%.3f cd/m^2)\n",
1586 x
[9], (50.0 * pow(2, x
[8] / 32.0)) * pow(x
[9] / 255.0, 2) / 100.0);
1588 // These bytes are always 0x08 0x2f. If these values
1589 // represent max/min luminance as well, then these
1590 // would map to 59.460 and 0.020 cd/m^2 respectively.
1591 // I wonder if this somehow relates to SDR.
1592 printf(" Unknown: 0x%02x 0x%02x\n", x
[8], x
[9]);
1597 static std::string
display_use_case(unsigned char x
)
1600 case 1: return "Test equipment";
1601 case 2: return "Generic display";
1602 case 3: return "Television display";
1603 case 4: return "Desktop productivity display";
1604 case 5: return "Desktop gaming display";
1605 case 6: return "Presentation display";
1606 case 7: return "Virtual reality headset";
1607 case 8: return "Augmented reality";
1608 case 16: return "Video wall display";
1609 case 17: return "Medical imaging display";
1610 case 18: return "Dedicated gaming display";
1611 case 19: return "Dedicated video monitor display";
1612 case 20: return "Accessory display";
1615 fail("Unknown Display product primary use case 0x%02x.\n", x
);
1616 return std::string("Unknown display use case (") + utohex(x
) + ")";
1619 static void cta_microsoft(const unsigned char *x
, unsigned length
)
1621 // This VSDB is documented at:
1622 // https://docs.microsoft.com/en-us/windows-hardware/drivers/display/specialized-monitors-edid-extension
1623 printf(" Version: %u\n", x
[0]);
1625 // In version 1 and 2 these bits should always be set to 0.
1626 printf(" Desktop Usage: %u\n", (x
[1] >> 6) & 1);
1627 printf(" Third-Party Usage: %u\n", (x
[1] >> 5) & 1);
1629 printf(" Display Product Primary Use Case: %u (%s)\n", x
[1] & 0x1f,
1630 display_use_case(x
[1] & 0x1f).c_str());
1631 printf(" Container ID: %s\n", containerid2s(x
+ 2).c_str());
1634 static void cta_hdr10plus(const unsigned char *x
, unsigned length
)
1637 fail("Empty Data Block with length %u.\n", length
);
1640 printf(" Application Version: %u\n", x
[0] & 3);
1641 printf(" Full Frame Peak Luminance Index: %u\n", (x
[0] >> 2) & 3);
1642 printf(" Peak Luminance Index: %u\n", x
[0] >> 4);
1643 hex_block(" ", x
+ 1, length
- 1);
1646 static void cta_dolby_video(const unsigned char *x
, unsigned length
)
1648 unsigned char version
= (x
[0] >> 5) & 0x07;
1650 printf(" Version: %u (%u bytes)\n", version
, length
+ 5);
1652 printf(" Supports YUV422 12 bit\n");
1656 printf(" Supports 2160p60\n");
1658 printf(" Supports global dimming\n");
1659 unsigned char dm_version
= x
[16];
1660 printf(" DM Version: %u.%u\n", dm_version
>> 4, dm_version
& 0xf);
1661 unsigned pq
= (x
[14] << 4) | (x
[13] >> 4);
1662 printf(" Target Min PQ: %u (%.8f cd/m^2)\n", pq
, pq2nits(pq
/ 4095.0));
1663 pq
= (x
[15] << 4) | (x
[13] & 0xf);
1664 printf(" Target Max PQ: %u (%u cd/m^2)\n", pq
, (unsigned)pq2nits(pq
/ 4095.0));
1665 printf(" Rx, Ry: %.8f, %.8f\n",
1666 ((x
[1] >> 4) | (x
[2] << 4)) / 4096.0,
1667 ((x
[1] & 0xf) | (x
[3] << 4)) / 4096.0);
1668 printf(" Gx, Gy: %.8f, %.8f\n",
1669 ((x
[4] >> 4) | (x
[5] << 4)) / 4096.0,
1670 ((x
[4] & 0xf) | (x
[6] << 4)) / 4096.0);
1671 printf(" Bx, By: %.8f, %.8f\n",
1672 ((x
[7] >> 4) | (x
[8] << 4)) / 4096.0,
1673 ((x
[7] & 0xf) | (x
[9] << 4)) / 4096.0);
1674 printf(" Wx, Wy: %.8f, %.8f\n",
1675 ((x
[10] >> 4) | (x
[11] << 4)) / 4096.0,
1676 ((x
[10] & 0xf) | (x
[12] << 4)) / 4096.0);
1682 printf(" Supports 2160p60\n");
1684 printf(" Supports global dimming\n");
1685 unsigned char dm_version
= (x
[0] >> 2) & 0x07;
1686 printf(" DM Version: %u.x\n", dm_version
+ 2);
1687 printf(" Colorimetry: %s\n", (x
[2] & 0x01) ? "P3-D65" : "ITU-R BT.709");
1688 printf(" Low Latency: %s\n", (x
[3] & 0x01) ? "Standard + Low Latency" : "Only Standard");
1689 double lm
= (x
[2] >> 1) / 127.0;
1690 printf(" Target Min Luminance: %.8f cd/m^2\n", lm
* lm
);
1691 printf(" Target Max Luminance: %u cd/m^2\n", 100 + (x
[1] >> 1) * 50);
1693 printf(" Rx, Ry: %.8f, %.8f\n", x
[4] / 256.0, x
[5] / 256.0);
1694 printf(" Gx, Gy: %.8f, %.8f\n", x
[6] / 256.0, x
[7] / 256.0);
1695 printf(" Bx, By: %.8f, %.8f\n", x
[8] / 256.0, x
[9] / 256.0);
1697 double xmin
= 0.625;
1698 double xstep
= (0.74609375 - xmin
) / 31.0;
1700 double ystep
= (0.37109375 - ymin
) / 31.0;
1702 printf(" Unique Rx, Ry: %.8f, %.8f\n",
1703 xmin
+ xstep
* (x
[6] >> 3),
1704 ymin
+ ystep
* (((x
[6] & 0x7) << 2) | (x
[4] & 0x01) | ((x
[5] & 0x01) << 1)));
1705 xstep
= 0.49609375 / 127.0;
1707 ystep
= (0.99609375 - ymin
) / 127.0;
1708 printf(" Unique Gx, Gy: %.8f, %.8f\n",
1709 xstep
* (x
[4] >> 1), ymin
+ ystep
* (x
[5] >> 1));
1711 xstep
= (0.15234375 - xmin
) / 7.0;
1713 ystep
= (0.05859375 - ymin
) / 7.0;
1714 printf(" Unique Bx, By: %.8f, %.8f\n",
1715 xmin
+ xstep
* (x
[3] >> 5),
1716 ymin
+ ystep
* ((x
[3] >> 2) & 0x07));
1723 printf(" Supports Backlight Control\n");
1725 printf(" Supports global dimming\n");
1726 unsigned char dm_version
= (x
[0] >> 2) & 0x07;
1727 printf(" DM Version: %u.x\n", dm_version
+ 2);
1728 printf(" Backlt Min Luma: %u cd/m^2\n", 25 + (x
[1] & 0x03) * 25);
1729 printf(" Interface: ");
1730 switch (x
[2] & 0x03) {
1731 case 0: printf("Low-Latency\n"); break;
1732 case 1: printf("Low-Latency + Low-Latency-HDMI\n"); break;
1733 case 2: printf("Standard + Low-Latency\n"); break;
1734 case 3: printf("Standard + Low-Latency + Low-Latency-HDMI\n"); break;
1736 printf(" Supports 10b 12b 444: ");
1737 switch ((x
[3] & 0x01) << 1 | (x
[4] & 0x01)) {
1738 case 0: printf("Not supported\n"); break;
1739 case 1: printf("10 bit\n"); break;
1740 case 2: printf("12 bit\n"); break;
1741 case 3: printf("Reserved\n"); break;
1744 unsigned pq
= 20 * (x
[1] >> 3);
1745 printf(" Target Min PQ v2: %u (%.8f cd/m^2)\n", pq
, pq2nits(pq
/ 4095.0));
1746 pq
= 2055 + 65 * (x
[2] >> 3);
1747 printf(" Target Max PQ v2: %u (%u cd/m^2)\n", pq
, (unsigned)pq2nits(pq
/ 4095.0));
1749 printf(" Unique Rx, Ry: %.8f, %.8f\n",
1750 0.625 + (x
[5] >> 3) / 256.0,
1751 0.25 + (x
[6] >> 3) / 256.0);
1752 printf(" Unique Gx, Gy: %.8f, %.8f\n",
1753 (x
[3] >> 1) / 256.0,
1754 0.5 + (x
[4] >> 1) / 256.0);
1755 printf(" Unique Bx, By: %.8f, %.8f\n",
1756 0.125 + (x
[5] & 0x07) / 256.0,
1757 0.03125 + (x
[6] & 0x07) / 256.0);
1761 static void cta_dolby_audio(const unsigned char *x
, unsigned length
)
1763 unsigned char version
= 1 + (x
[0] & 0x07);
1765 printf(" Version: %u (%u bytes)\n", version
, length
+ 5);
1767 printf(" Headphone playback only\n");
1769 printf(" Height speaker zone present\n");
1771 printf(" Surround speaker zone present\n");
1773 printf(" Center speaker zone present\n");
1775 printf(" Supports Dolby MAT PCM decoding at 48 kHz only, does not support TrueHD\n");
1778 static void cta_uhda_fmm(const unsigned char *x
, unsigned length
)
1780 printf(" Filmmaker Mode Content Type: %u\n", x
[0]);
1781 printf(" Filmmaker Mode Content Subtype: %u\n", x
[1]);
1784 static const char *speaker_map
[] = {
1785 "FL/FR - Front Left/Right",
1786 "LFE1 - Low Frequency Effects 1",
1787 "FC - Front Center",
1788 "BL/BR - Back Left/Right",
1790 "FLc/FRc - Front Left/Right of Center",
1791 "RLC/RRC - Rear Left/Right of Center (Deprecated)",
1792 "FLw/FRw - Front Left/Right Wide",
1793 "TpFL/TpFR - Top Front Left/Right",
1795 "TpFC - Top Front Center",
1796 "LS/RS - Left/Right Surround",
1797 "LFE2 - Low Frequency Effects 2",
1798 "TpBC - Top Back Center",
1799 "SiL/SiR - Side Left/Right",
1800 "TpSiL/TpSiR - Top Side Left/Right",
1801 "TpBL/TpBR - Top Back Left/Right",
1802 "BtFC - Bottom Front Center",
1803 "BtFL/BtFR - Bottom Front Left/Right",
1804 "TpLS/TpRS - Top Left/Right Surround (Deprecated for CTA-861)",
1805 "LSd/RSd - Left/Right Surround Direct (HDMI only)",
1808 static void cta_sadb(const unsigned char *x
, unsigned length
)
1814 fail("Empty Data Block with length %u.\n", length
);
1818 sad
= ((x
[2] << 16) | (x
[1] << 8) | x
[0]);
1820 for (i
= 0; i
< ARRAY_SIZE(speaker_map
); i
++) {
1822 printf(" %s\n", speaker_map
[i
]);
1826 static void cta_vesa_dtcdb(const unsigned char *x
, unsigned length
)
1828 if (length
!= 7 && length
!= 15 && length
!= 31) {
1829 fail("Invalid length %u.\n", length
);
1833 switch (x
[0] >> 6) {
1834 case 0: printf(" White"); break;
1835 case 1: printf(" Red"); break;
1836 case 2: printf(" Green"); break;
1837 case 3: printf(" Blue"); break;
1839 unsigned v
= x
[0] & 0x3f;
1840 printf(" transfer characteristics: %u", v
);
1841 for (unsigned i
= 1; i
< length
; i
++)
1842 printf(" %u", v
+= x
[i
]);
1846 static void cta_vesa_vdddb(const unsigned char *x
, unsigned length
)
1849 fail("Invalid length %u.\n", length
);
1853 printf(" Interface Type: ");
1854 unsigned char v
= x
[0];
1856 case 0: printf("Analog (");
1858 case 0: printf("15HD/VGA"); break;
1859 case 1: printf("VESA NAVI-V (15HD)"); break;
1860 case 2: printf("VESA NAVI-D"); break;
1861 default: printf("Reserved"); break;
1865 case 1: printf("LVDS %u lanes", v
& 0xf); break;
1866 case 2: printf("RSDS %u lanes", v
& 0xf); break;
1867 case 3: printf("DVI-D %u channels", v
& 0xf); break;
1868 case 4: printf("DVI-I analog"); break;
1869 case 5: printf("DVI-I digital %u channels", v
& 0xf); break;
1870 case 6: printf("HDMI-A"); break;
1871 case 7: printf("HDMI-B"); break;
1872 case 8: printf("MDDI %u channels", v
& 0xf); break;
1873 case 9: printf("DisplayPort %u channels", v
& 0xf); break;
1874 case 10: printf("IEEE-1394"); break;
1875 case 11: printf("M1 analog"); break;
1876 case 12: printf("M1 digital %u channels", v
& 0xf); break;
1877 default: printf("Reserved"); break;
1881 printf(" Interface Standard Version: %u.%u\n", x
[1] >> 4, x
[1] & 0xf);
1882 printf(" Content Protection Support: ");
1884 case 0: printf("None\n"); break;
1885 case 1: printf("HDCP\n"); break;
1886 case 2: printf("DTCP\n"); break;
1887 case 3: printf("DPCP\n"); break;
1888 default: printf("Reserved\n"); break;
1891 printf(" Minimum Clock Frequency: %u MHz\n", x
[3] >> 2);
1892 printf(" Maximum Clock Frequency: %u MHz\n", ((x
[3] & 0x03) << 8) | x
[4]);
1893 printf(" Device Native Pixel Format: %ux%u\n",
1894 x
[5] | (x
[6] << 8), x
[7] | (x
[8] << 8));
1895 printf(" Aspect Ratio: %.2f\n", (100 + x
[9]) / 100.0);
1897 printf(" Default Orientation: ");
1898 switch ((v
& 0xc0) >> 6) {
1899 case 0x00: printf("Landscape\n"); break;
1900 case 0x01: printf("Portrait\n"); break;
1901 case 0x02: printf("Not Fixed\n"); break;
1902 case 0x03: printf("Undefined\n"); break;
1904 printf(" Rotation Capability: ");
1905 switch ((v
& 0x30) >> 4) {
1906 case 0x00: printf("None\n"); break;
1907 case 0x01: printf("Can rotate 90 degrees clockwise\n"); break;
1908 case 0x02: printf("Can rotate 90 degrees counterclockwise\n"); break;
1909 case 0x03: printf("Can rotate 90 degrees in either direction)\n"); break;
1911 printf(" Zero Pixel Location: ");
1912 switch ((v
& 0x0c) >> 2) {
1913 case 0x00: printf("Upper Left\n"); break;
1914 case 0x01: printf("Upper Right\n"); break;
1915 case 0x02: printf("Lower Left\n"); break;
1916 case 0x03: printf("Lower Right\n"); break;
1918 printf(" Scan Direction: ");
1920 case 0x00: printf("Not defined\n"); break;
1921 case 0x01: printf("Fast Scan is on the Major (Long) Axis and Slow Scan is on the Minor Axis\n"); break;
1922 case 0x02: printf("Fast Scan is on the Minor (Short) Axis and Slow Scan is on the Major Axis\n"); break;
1923 case 0x03: printf("Reserved\n");
1924 fail("Scan Direction used the reserved value 0x03.\n");
1927 printf(" Subpixel Information: ");
1929 case 0x00: printf("Not defined\n"); break;
1930 case 0x01: printf("RGB vertical stripes\n"); break;
1931 case 0x02: printf("RGB horizontal stripes\n"); break;
1932 case 0x03: printf("Vertical stripes using primary order\n"); break;
1933 case 0x04: printf("Horizontal stripes using primary order\n"); break;
1934 case 0x05: printf("Quad sub-pixels, red at top left\n"); break;
1935 case 0x06: printf("Quad sub-pixels, red at bottom left\n"); break;
1936 case 0x07: printf("Delta (triad) RGB sub-pixels\n"); break;
1937 case 0x08: printf("Mosaic\n"); break;
1938 case 0x09: printf("Quad sub-pixels, RGB + 1 additional color\n"); break;
1939 case 0x0a: printf("Five sub-pixels, RGB + 2 additional colors\n"); break;
1940 case 0x0b: printf("Six sub-pixels, RGB + 3 additional colors\n"); break;
1941 case 0x0c: printf("Clairvoyante, Inc. PenTile Matrix (tm) layout\n"); break;
1942 default: printf("Reserved\n"); break;
1944 printf(" Horizontal and vertical dot/pixel pitch: %.2f x %.2f mm\n",
1945 (double)(x
[0x0c]) / 100.0, (double)(x
[0x0d]) / 100.0);
1947 printf(" Dithering: ");
1949 case 0: printf("None\n"); break;
1950 case 1: printf("Spatial\n"); break;
1951 case 2: printf("Temporal\n"); break;
1952 case 3: printf("Spatial and Temporal\n"); break;
1954 printf(" Direct Drive: %s\n", (v
& 0x20) ? "Yes" : "No");
1955 printf(" Overdrive %srecommended\n", (v
& 0x10) ? "not " : "");
1956 printf(" Deinterlacing: %s\n", (v
& 0x08) ? "Yes" : "No");
1959 printf(" Audio Support: %s\n", (v
& 0x80) ? "Yes" : "No");
1960 printf(" Separate Audio Inputs Provided: %s\n", (v
& 0x40) ? "Yes" : "No");
1961 printf(" Audio Input Override: %s\n", (v
& 0x20) ? "Yes" : "No");
1964 printf(" Audio Delay: %s%u ms\n", (v
& 0x80) ? "" : "-", (v
& 0x7f) * 2);
1966 printf(" Audio Delay: no information provided\n");
1968 printf(" Frame Rate/Mode Conversion: ");
1970 case 0: printf("None\n"); break;
1971 case 1: printf("Single Buffering\n"); break;
1972 case 2: printf("Double Buffering\n"); break;
1973 case 3: printf("Advanced Frame Rate Conversion\n"); break;
1976 printf(" Frame Rate Range: %u fps +/- %u fps\n",
1979 printf(" Nominal Frame Rate: %u fps\n", x
[0x12]);
1980 printf(" Color Bit Depth: %u @ interface, %u @ display\n",
1981 (x
[0x13] >> 4) + 1, (x
[0x13] & 0xf) + 1);
1984 printf(" Additional Primary Chromaticities:\n");
1985 unsigned col_x
= (x
[0x16] << 2) | (x
[0x14] >> 6);
1986 unsigned col_y
= (x
[0x17] << 2) | ((x
[0x14] >> 4) & 3);
1987 printf(" Primary 4: 0.%04u, 0.%04u\n",
1988 (col_x
* 10000) / 1024, (col_y
* 10000) / 1024);
1990 col_x
= (x
[0x18] << 2) | ((x
[0x14] >> 2) & 3);
1991 col_y
= (x
[0x19] << 2) | (x
[0x14] & 3);
1992 printf(" Primary 5: 0.%04u, 0.%04u\n",
1993 (col_x
* 10000) / 1024, (col_y
* 10000) / 1024);
1995 col_x
= (x
[0x1a] << 2) | (x
[0x15] >> 6);
1996 col_y
= (x
[0x1b] << 2) | ((x
[0x15] >> 4) & 3);
1997 printf(" Primary 6: 0.%04u, 0.%04u\n",
1998 (col_x
* 10000) / 1024, (col_y
* 10000) / 1024);
2004 printf(" Response Time %s: %u ms\n",
2005 (v
& 0x80) ? "White -> Black" : "Black -> White", v
& 0x7f);
2007 printf(" Overscan: %u%% x %u%%\n", v
>> 4, v
& 0xf);
2010 static double decode_uchar_as_double(unsigned char x
)
2012 signed char s
= (signed char)x
;
2017 void edid_state::cta_rcdb(const unsigned char *x
, unsigned length
)
2019 unsigned spm
= ((x
[3] << 16) | (x
[2] << 8) | x
[1]);
2023 fail("Empty Data Block with length %u.\n", length
);
2027 if ((x
[0] & 0x20) && !cta
.has_sldb
)
2028 fail("'SLD' flag is 1, but no Speaker Location Data Block is found.\n");
2029 else if (!(x
[0] & 0x20) && cta
.has_sldb
)
2030 fail("'SLD' flag is 0, but a Speaker Location Data Block is present.\n");
2033 printf(" Speaker count: %u\n", (x
[0] & 0x1f) + 1);
2036 fail("'Speaker' flag is 0, but 'Speaker Count' is != 0.\n");
2038 fail("'SLD' flag is 1, but 'Speaker' is 0.\n");
2041 printf(" Speaker Presence Mask:\n");
2042 for (i
= 0; i
< ARRAY_SIZE(speaker_map
); i
++) {
2044 printf(" %s\n", speaker_map
[i
]);
2047 if ((x
[0] & 0xa0) == 0x80)
2048 fail("'Display' flag set, but not the 'SLD' flag.\n");
2050 bool valid_max
= cta
.preparsed_sld_has_coord
|| (x
[0] & 0x80);
2052 if (valid_max
&& length
>= 7) {
2053 printf(" Xmax: %u dm\n", x
[4]);
2054 printf(" Ymax: %u dm\n", x
[5]);
2055 printf(" Zmax: %u dm\n", x
[6]);
2056 } else if (!valid_max
&& length
>= 7) {
2057 // The RCDB should have been truncated.
2058 warn("'Display' flag is 0 and 'Coord' is 0 for all SLDs, but the Max coordinates are still present.\n");
2060 if ((x
[0] & 0x80) && length
>= 10) {
2061 printf(" DisplayX: %.3f * Xmax\n", decode_uchar_as_double(x
[7]));
2062 printf(" DisplayY: %.3f * Ymax\n", decode_uchar_as_double(x
[8]));
2063 printf(" DisplayZ: %.3f * Zmax\n", decode_uchar_as_double(x
[9]));
2064 } else if (!(x
[0] & 0x80) && length
>= 10) {
2065 // The RCDB should have been truncated.
2066 warn("'Display' flag is 0, but the Display coordinates are still present.\n");
2070 static const struct {
2073 } speaker_location
[] = {
2074 { "FL - Front Left", -1, 1, 0 },
2075 { "FR - Front Right", 1, 1, 0 },
2076 { "FC - Front Center", 0, 1, 0 },
2077 { "LFE1 - Low Frequency Effects 1", -0.5, 1, -1 },
2078 { "BL - Back Left", -1, -1, 0 },
2079 { "BR - Back Right", 1, -1, 0 },
2080 { "FLC - Front Left of Center", -0.5, 1, 0 },
2081 { "FRC - Front Right of Center", 0.5, 1, 0 },
2082 { "BC - Back Center", 0, -1, 0 },
2083 { "LFE2 - Low Frequency Effects 2", 0.5, 1, -1 },
2084 { "SiL - Side Left", -1, 1.0/3.0, 0 },
2085 { "SiR - Side Right", 1, 1.0/3.0, 0 },
2086 { "TpFL - Top Front Left", -1, 1, 1 },
2087 { "TpFR - Top Front Right", 1, 1, 1 },
2088 { "TpFC - Top Front Center", 0, 1, 1 },
2089 { "TpC - Top Center", 0, 0, 1 },
2090 { "TpBL - Top Back Left", -1, -1, 1 },
2091 { "TpBR - Top Back Right", 1, -1, 1 },
2092 { "TpSiL - Top Side Left", -1, 0, 1 },
2093 { "TpSiR - Top Side Right", 1, 0, 1 },
2094 { "TpBC - Top Back Center", 0, -1, 1 },
2095 { "BtFC - Bottom Front Center", 0, 1, -1 },
2096 { "BtFL - Bottom Front Left", -1, 1, -1 },
2097 { "BtFR - Bottom Front Right", 1, 1, -1 },
2098 { "FLW - Front Left Wide", -1, 2.0/3.0, 0 },
2099 { "FRW - Front Right Wide", 1, 2.0/3.0, 0 },
2100 { "LS - Left Surround", -1, 0, 0 },
2101 { "RS - Right Surround", 1, 0, 0 },
2104 void edid_state::cta_sldb(const unsigned char *x
, unsigned length
)
2107 fail("Empty Data Block with length %u.\n", length
);
2111 unsigned active_cnt
= 0;
2112 unsigned channel_is_active
= 0;
2114 while (length
>= 2) {
2115 printf(" Channel: %u (%sactive)\n", x
[0] & 0x1f,
2116 (x
[0] & 0x20) ? "" : "not ");
2118 if (channel_is_active
& (1U << (x
[0] & 0x1f)))
2119 fail("Channel Index %u was already marked 'Active'.\n",
2121 channel_is_active
|= 1U << (x
[0] & 0x1f);
2125 unsigned speaker_id
= x
[1] & 0x1f;
2127 if (speaker_id
< ARRAY_SIZE(speaker_location
)) {
2128 printf(" Speaker ID: %s\n", speaker_location
[speaker_id
].name
);
2129 } else if (speaker_id
== 0x1f) {
2130 printf(" Speaker ID: None Specified\n");
2132 printf(" Speaker ID: Reserved (%u)\n", speaker_id
);
2133 fail("Reserved Speaker ID specified.\n");
2135 if (length
>= 5 && (x
[0] & 0x40)) {
2136 printf(" X: %.3f * Xmax\n", decode_uchar_as_double(x
[2]));
2137 printf(" Y: %.3f * Ymax\n", decode_uchar_as_double(x
[3]));
2138 printf(" Z: %.3f * Zmax\n", decode_uchar_as_double(x
[4]));
2141 } else if (speaker_id
< ARRAY_SIZE(speaker_location
)) {
2142 printf(" X: %.3f * Xmax (approximately)\n", speaker_location
[speaker_id
].x
);
2143 printf(" Y: %.3f * Ymax (approximately)\n", speaker_location
[speaker_id
].y
);
2144 printf(" Z: %.3f * Zmax (approximately)\n", speaker_location
[speaker_id
].z
);
2150 if (active_cnt
!= cta
.preparsed_speaker_count
)
2151 fail("There are %u active speakers, but 'Speaker Count' is %u.\n",
2152 active_cnt
, cta
.preparsed_speaker_count
);
2155 void edid_state::cta_preparse_sldb(const unsigned char *x
, unsigned length
)
2157 cta
.has_sldb
= true;
2158 while (length
>= 2) {
2159 if (length
>= 5 && (x
[0] & 0x40)) {
2160 cta
.preparsed_sld_has_coord
= true;
2168 void edid_state::cta_vcdb(const unsigned char *x
, unsigned length
)
2170 unsigned char d
= x
[0];
2172 cta
.has_vcdb
= true;
2174 fail("Empty Data Block with length %u.\n", length
);
2177 printf(" YCbCr quantization: %s\n",
2178 (d
& 0x80) ? "Selectable (via AVI YQ)" : "No Data");
2179 printf(" RGB quantization: %s\n",
2180 (d
& 0x40) ? "Selectable (via AVI Q)" : "No Data");
2182 * If this bit is not set then that will result in interoperability
2183 * problems (specifically with PCs/laptops) that quite often do not
2184 * follow the default rules with respect to RGB Quantization Range
2187 * Starting with the CTA-861-H spec this bit is now required to be
2188 * 1 for new designs.
2191 fail("Set Selectable RGB Quantization to avoid interop issues.\n");
2193 * Since most YCbCr formats use limited range, the interop issues are
2194 * less noticable than for RGB formats.
2196 * Starting with the CTA-861-H spec this bit is now required to be
2197 * 1 for new designs, but just warn about it (for now).
2199 if ((cta
.byte3
& 0x30) && !(d
& 0x80))
2200 warn("Set Selectable YCbCr Quantization to avoid interop issues.\n");
2202 unsigned char s_pt
= (d
>> 4) & 0x03;
2203 unsigned char s_it
= (d
>> 2) & 0x03;
2204 unsigned char s_ce
= d
& 0x03;
2206 printf(" PT scan behavior: ");
2208 case 0: printf("No Data\n"); break;
2209 case 1: printf("Always Overscanned\n"); break;
2210 case 2: printf("Always Underscanned\n"); break;
2211 case 3: printf("Supports both over- and underscan\n"); break;
2213 printf(" IT scan behavior: ");
2215 case 0: printf("IT video formats not supported\n"); break;
2217 printf("Always Overscanned\n");
2218 // See Table 52 of CTA-861-G for a description of Byte 3
2219 if (cta
.byte3
& 0x80)
2220 fail("IT video formats are always overscanned, but bit 7 of Byte 3 of the CTA-861 Extension header is set to underscanned.\n");
2223 printf("Always Underscanned\n");
2224 // See Table 52 of CTA-861-G for a description of Byte 3
2225 if (!(cta
.byte3
& 0x80))
2226 fail("IT video formats are always underscanned, but bit 7 of Byte 3 of the CTA-861 Extension header is set to overscanned.\n");
2228 case 3: printf("Supports both over- and underscan\n"); break;
2231 warn("IT scan behavior is expected to support underscanned.\n");
2232 printf(" CE scan behavior: ");
2234 case 0: printf("CE video formats not supported\n"); break;
2235 case 1: printf("Always Overscanned\n"); break;
2236 case 2: printf("Always Underscanned\n"); break;
2237 case 3: printf("Supports both over- and underscan\n"); break;
2240 warn("'CE video formats not supported' makes no sense.\n");
2241 else if (s_pt
== s_it
&& s_pt
== s_ce
)
2242 warn("S_PT is equal to S_IT and S_CE, so should be set to 0 instead.\n");
2245 static const char *colorimetry1_map
[] = {
2256 static const char *colorimetry2_map
[] = {
2257 "Gamut Boundary Description Metadata Profile P0",
2258 "Reserved Gamut Boundary Description Metadata Profile P1",
2259 "Reserved Gamut Boundary Description Metadata Profile P2",
2260 "Reserved Gamut Boundary Description Metadata Profile P3",
2267 void edid_state::cta_colorimetry_block(const unsigned char *x
, unsigned length
)
2272 fail("Empty Data Block with length %u.\n", length
);
2275 for (i
= 0; i
< ARRAY_SIZE(colorimetry1_map
); i
++)
2276 if (x
[0] & (1 << i
))
2277 printf(" %s\n", colorimetry1_map
[i
]);
2278 // Bits MD0-MD3 are used to indicate which HDMI Gamut Boundary Description
2279 // Metadata Profiles are supported.
2281 // HDMI 1.3a in section 5.3.12 describes 4 possible profiles, but it marks
2282 // P3 as 'defined in a future specification'.
2284 // HDMI 1.4b, however, only specifies profile P0 in section 8.3.3. And I've
2285 // only seen P0 in practice. My assumption is that profiles P1-P3 are never
2286 // used, and so these bits should be 0.
2288 fail("Reserved bits MD1-MD3 must be 0.\n");
2289 for (i
= 0; i
< ARRAY_SIZE(colorimetry2_map
); i
++)
2290 if (x
[1] & (1 << i
))
2291 printf(" %s\n", colorimetry2_map
[i
]);
2292 // The sRGB bit (added in CTA-861.6) allows sources to explicitly
2293 // signal sRGB colorimetry. Without this the default colorimetry
2294 // of an RGB video is either sRGB or defaultRGB. It depends on the
2295 // Source which is used, and the Sink has no idea what it is getting.
2297 // For proper compatibility with PCs enabling sRGB support is
2299 if (!base
.uses_srgb
&& !(x
[1] & 0x20))
2300 warn("Set the sRGB colorimetry bit to avoid interop issues.\n");
2303 static const char *eotf_map
[] = {
2304 "Traditional gamma - SDR luminance range",
2305 "Traditional gamma - HDR luminance range",
2310 static void cta_hdr_static_metadata_block(const unsigned char *x
, unsigned length
)
2315 fail("Empty Data Block with length %u.\n", length
);
2318 printf(" Electro optical transfer functions:\n");
2319 for (i
= 0; i
< 6; i
++) {
2320 if (x
[0] & (1 << i
)) {
2321 if (i
< ARRAY_SIZE(eotf_map
)) {
2322 printf(" %s\n", eotf_map
[i
]);
2324 printf(" Unknown (%u)\n", i
);
2325 fail("Unknown EOTF (%u).\n", i
);
2329 printf(" Supported static metadata descriptors:\n");
2330 for (i
= 0; i
< 8; i
++) {
2331 if (x
[1] & (1 << i
))
2332 printf(" Static metadata type %u\n", i
+ 1);
2336 printf(" Desired content max luminance: %u (%.3f cd/m^2)\n",
2337 x
[2], 50.0 * pow(2, x
[2] / 32.0));
2340 printf(" Desired content max frame-average luminance: %u (%.3f cd/m^2)\n",
2341 x
[3], 50.0 * pow(2, x
[3] / 32.0));
2344 printf(" Desired content min luminance: %u (%.3f cd/m^2)\n",
2345 x
[4], (50.0 * pow(2, x
[2] / 32.0)) * pow(x
[4] / 255.0, 2) / 100.0);
2348 static void cta_hdr_dyn_metadata_block(const unsigned char *x
, unsigned length
)
2351 fail("Empty Data Block with length %u.\n", length
);
2354 while (length
>= 3) {
2355 unsigned type_len
= x
[0];
2356 unsigned type
= x
[1] | (x
[2] << 8);
2358 if (length
< type_len
+ 1)
2360 printf(" HDR Dynamic Metadata Type %u\n", type
);
2365 printf(" Version: %u\n", x
[3] & 0xf);
2369 unsigned version
= x
[3] & 0xf;
2370 printf(" Version: %u\n", version
);
2372 if (x
[3] & 0x10) printf(" Supports SL-HDR1 (ETSI TS 103 433-1)\n");
2373 if (x
[3] & 0x20) printf(" Supports SL-HDR2 (ETSI TS 103 433-2)\n");
2374 if (x
[3] & 0x40) printf(" Supports SL-HDR3 (ETSI TS 103 433-3)\n");
2381 length
-= type_len
+ 1;
2386 static const char *infoframe_types
[] = {
2389 "Auxiliary Video Information",
2390 "Source Product Description",
2394 "Dynamic Range and Mastering",
2397 static void cta_ifdb(const unsigned char *x
, unsigned length
)
2399 unsigned len_hdr
= x
[0] >> 5;
2402 fail("Empty Data Block with length %u.\n", length
);
2405 printf(" VSIFs: %u\n", x
[1]);
2406 if (length
< len_hdr
+ 2)
2408 length
-= len_hdr
+ 2;
2410 while (length
> 0) {
2411 int payload_len
= x
[0] >> 5;
2412 unsigned char type
= x
[0] & 0x1f;
2414 const char *name
= NULL
;
2415 if (type
< ARRAY_SIZE(infoframe_types
))
2416 name
= infoframe_types
[type
];
2419 printf(" %s InfoFrame (%u)", name
, type
);
2421 if (type
== 1 && length
>= 4) {
2422 unsigned oui
= (x
[3] << 16) | (x
[2] << 8) | x
[1];
2424 printf(", OUI %s\n", ouitohex(oui
).c_str());
2433 length
-= payload_len
;
2437 void edid_state::cta_displayid_type_7(const unsigned char *x
, unsigned length
)
2439 check_displayid_datablock_revision(x
[0], 0x00, 2);
2441 if (length
< 21U + ((x
[0] & 0x70) >> 4)) {
2442 fail("Empty Data Block with length %u.\n", length
);
2445 parse_displayid_type_1_7_timing(x
+ 1, true, 2, true);
2448 void edid_state::cta_displayid_type_8(const unsigned char *x
, unsigned length
)
2450 check_displayid_datablock_revision(x
[0], 0xe8, 1);
2451 if (length
< ((x
[0] & 0x08) ? 3 : 2)) {
2452 fail("Empty Data Block with length %u.\n", length
);
2456 unsigned sz
= (x
[0] & 0x08) ? 2 : 1;
2457 unsigned type
= x
[0] >> 6;
2460 fail("Only code type 0 is supported.\n");
2465 printf(" Also supports YCbCr 4:2:0\n");
2469 for (unsigned i
= 0; i
< length
/ sz
; i
++) {
2470 unsigned id
= x
[i
* sz
];
2473 id
|= x
[i
* sz
+ 1] << 8;
2474 parse_displayid_type_4_8_timing(type
, id
, true);
2478 void edid_state::cta_displayid_type_10(const unsigned char *x
, unsigned length
)
2480 check_displayid_datablock_revision(x
[0], 0x70);
2481 if (length
< 7U + ((x
[0] & 0x70) >> 4)) {
2482 fail("Empty Data Block with length %u.\n", length
);
2486 unsigned sz
= 6U + ((x
[0] & 0x70) >> 4);
2489 for (unsigned i
= 0; i
< length
/ sz
; i
++)
2490 parse_displayid_type_10_timing(x
+ i
* sz
, sz
, true);
2493 static void cta_hdmi_audio_block(const unsigned char *x
, unsigned length
)
2498 fail("Empty Data Block with length %u.\n", length
);
2502 printf(" Max Stream Count: %u\n", (x
[0] & 3) + 1);
2504 printf(" Supports MS NonMixed\n");
2505 } else if (x
[0] & 4) {
2506 fail("MS NonMixed support indicated but Max Stream Count == 0.\n");
2509 num_descs
= x
[1] & 7;
2514 while (length
>= 4) {
2516 unsigned format
= x
[0] & 0xf;
2518 printf(" %s:\n", audio_format(format
).c_str());
2519 printf(" Max channels: %u\n", (x
[1] & 0x1f)+1);
2520 printf(" Supported sample rates (kHz):%s%s%s%s%s%s%s\n",
2521 (x
[2] & 0x40) ? " 192" : "",
2522 (x
[2] & 0x20) ? " 176.4" : "",
2523 (x
[2] & 0x10) ? " 96" : "",
2524 (x
[2] & 0x08) ? " 88.2" : "",
2525 (x
[2] & 0x04) ? " 48" : "",
2526 (x
[2] & 0x02) ? " 44.1" : "",
2527 (x
[2] & 0x01) ? " 32" : "");
2529 printf(" Supported sample sizes (bits):%s%s%s\n",
2530 (x
[3] & 0x04) ? " 24" : "",
2531 (x
[3] & 0x02) ? " 20" : "",
2532 (x
[3] & 0x01) ? " 16" : "");
2534 unsigned sad
= ((x
[2] << 16) | (x
[1] << 8) | x
[0]);
2537 switch (x
[3] >> 4) {
2539 printf(" Speaker Allocation for 10.2 channels:\n");
2542 printf(" Speaker Allocation for 22.2 channels:\n");
2545 printf(" Speaker Allocation for 30.2 channels:\n");
2548 printf(" Unknown Speaker Allocation (0x%02x)\n", x
[3] >> 4);
2552 for (i
= 0; i
< ARRAY_SIZE(speaker_map
); i
++) {
2554 printf(" %s\n", speaker_map
[i
]);
2562 void edid_state::cta_block(const unsigned char *x
, std::vector
<unsigned> &found_tags
)
2564 unsigned length
= x
[0] & 0x1f;
2565 unsigned tag
= (x
[0] & 0xe0) >> 5;
2566 unsigned extended
= (tag
== 0x07) ? 1 : 0;
2569 if (extended
&& length
) {
2576 bool dooutputname
= true;
2577 bool audio_block
= false;
2581 case 0x01: data_block
= "Audio Data Block"; audio_block
= true; break;
2582 case 0x02: data_block
= "Video Data Block"; break;
2583 case 0x03: data_block
= "Vendor-Specific Data Block"; break;
2584 case 0x04: data_block
= "Speaker Allocation Data Block"; audio_block
= true; break;
2585 case 0x05: data_block
= "VESA Display Transfer Characteristics Data Block"; break;
2586 case 0x06: data_block
= "Video Format Data Block"; break;
2587 case 0x07: data_block
= "Unknown CTA-861 Data Block (extended tag truncated)"; break;
2589 case 0x700: data_block
= "Video Capability Data Block"; break;
2590 case 0x701: data_block
= "Vendor-Specific Video Data Block"; break;
2591 case 0x702: data_block
= "VESA Video Display Device Data Block"; break;
2592 case 0x703: data_block
= "VESA Video Timing Block Extension"; break;
2593 case 0x704: data_block
= "Reserved for HDMI Video Data Block"; break;
2594 case 0x705: data_block
= "Colorimetry Data Block"; break;
2595 case 0x706: data_block
= "HDR Static Metadata Data Block"; break;
2596 case 0x707: data_block
= "HDR Dynamic Metadata Data Block"; break;
2597 case 0x708: data_block
= "Native Video Resolution Data Block"; break;
2599 case 0x70d: data_block
= "Video Format Preference Data Block"; break;
2600 case 0x70e: data_block
= "YCbCr 4:2:0 Video Data Block"; break;
2601 case 0x70f: data_block
= "YCbCr 4:2:0 Capability Map Data Block"; break;
2602 case 0x710: data_block
= "Reserved for CTA-861 Miscellaneous Audio Fields"; break;
2603 case 0x711: data_block
= "Vendor-Specific Audio Data Block"; audio_block
= true; break;
2604 case 0x712: data_block
= "HDMI Audio Data Block"; audio_block
= true; break;
2605 case 0x713: data_block
= "Room Configuration Data Block"; audio_block
= true; break;
2606 case 0x714: data_block
= "Speaker Location Data Block"; audio_block
= true; break;
2608 case 0x720: data_block
= "InfoFrame Data Block"; break;
2610 case 0x722: data_block
= "DisplayID Type VII Video Timing Data Block"; break;
2611 case 0x723: data_block
= "DisplayID Type VIII Video Timing Data Block"; break;
2612 case 0x72a: data_block
= "DisplayID Type X Video Timing Data Block"; break;
2614 case 0x778: data_block
= "HDMI Forum EDID Extension Override Data Block"; break;
2615 case 0x779: data_block
= "HDMI Forum Sink Capability Data Block"; break;
2616 case 0x77a: data_block
= "HDMI Forum Source-Based Tone Mapping Data Block"; break;
2619 std::string unknown_name
;
2620 if (tag
< 0x700) unknown_name
= "Unknown CTA-861 Data Block";
2621 else if (tag
< 0x70d) unknown_name
= "Unknown CTA-861 Video-Related Data Block";
2622 else if (tag
< 0x720) unknown_name
= "Unknown CTA-861 Audio-Related Data Block";
2623 else if (tag
< 0x778) unknown_name
= "Unknown CTA-861 Data Block";
2624 else if (tag
< 0x780) unknown_name
= "Unknown CTA-861 HDMI-Related Data Block";
2625 else unknown_name
= "Unknown CTA-861 Data Block";
2626 unknown_name
+= std::string(" (") + (extended
? "extended " : "") + "tag " + utohex(tag
& 0xff) + ", length " + std::to_string(length
) + ")";
2627 printf(" %s:\n", unknown_name
.c_str());
2628 warn("%s.\n", unknown_name
.c_str());
2638 data_block_oui(data_block
, x
, length
, &ouinum
);
2639 x
+= (length
< 3) ? length
: 3;
2640 length
-= (length
< 3) ? length
: 3;
2641 dooutputname
= false;
2647 if (dooutputname
&& data_block
.length())
2648 printf(" %s:\n", data_block
.c_str());
2665 if (std::find(found_tags
.begin(), found_tags
.end(), tag
) != found_tags
.end())
2666 fail("Only one instance of this Data Block is allowed.\n");
2670 // See Table 52 of CTA-861-G for a description of Byte 3
2671 if (audio_block
&& !(cta
.byte3
& 0x40))
2672 fail("Audio information is present, but bit 6 of Byte 3 of the CTA-861 Extension header indicates no Basic Audio support.\n");
2675 case 0x01: cta_audio_block(x
, length
); break;
2676 case 0x02: cta_svd(x
, length
, false); break;
2677 case 0x03|kOUI_HDMI
:
2678 cta_hdmi_block(x
, length
);
2679 // The HDMI OUI is present, so this EDID represents an HDMI
2680 // interface. And HDMI interfaces must use EDID version 1.3
2681 // according to the HDMI Specification, so check for this.
2682 if (base
.edid_minor
!= 3)
2683 fail("The HDMI Specification requires EDID 1.3 instead of 1.%u.\n",
2686 case 0x03|kOUI_HDMIForum
:
2687 if (cta
.previous_cta_tag
!= (0x03|kOUI_HDMI
))
2688 fail("HDMI Forum VSDB did not immediately follow the HDMI VSDB.\n");
2689 if (cta
.have_hf_scdb
|| cta
.have_hf_vsdb
)
2690 fail("Duplicate HDMI Forum VSDB/SCDB.\n");
2691 cta_hf_scdb(x
, length
);
2692 cta
.have_hf_vsdb
= true;
2694 case 0x03|kOUI_AMD
: cta_amd(x
, length
); break;
2695 case 0x03|kOUI_Microsoft
: if (length
!= 0x12) goto dodefault
; cta_microsoft(x
, length
); break;
2696 case 0x03|kOUI_UHDA
: cta_uhda_fmm(x
, length
); break;
2697 case 0x04: cta_sadb(x
, length
); break;
2698 case 0x05: cta_vesa_dtcdb(x
, length
); break;
2699 case 0x06: cta_vfdb(x
, length
); break;
2700 case 0x07: fail("Extended tag cannot have zero length.\n"); break;
2701 case 0x700: cta_vcdb(x
, length
); break;
2702 case 0x701|kOUI_HDR10
: cta_hdr10plus(x
, length
); break;
2703 case 0x701|kOUI_Dolby
: cta_dolby_video(x
, length
); break;
2704 // 0x701|kOUI_Apple: this almost certainly contains 'BLC Info/Corrections',
2705 // since the data (spread out over two VSDBs) is very similar to what is seen
2706 // in DisplayID blocks. Since I don't know how to parse this data, we still
2707 // default to a hex dump, but I mention this here in case data on how to
2708 // parse this becomes available.
2709 case 0x702: cta_vesa_vdddb(x
, length
); break;
2710 case 0x705: cta_colorimetry_block(x
, length
); break;
2711 case 0x706: cta_hdr_static_metadata_block(x
, length
); break;
2712 case 0x707: cta_hdr_dyn_metadata_block(x
, length
); break;
2713 case 0x708: cta_nvrdb(x
, length
); return;
2714 case 0x70d: cta_vfpdb(x
, length
); break;
2715 case 0x70e: cta_svd(x
, length
, true); break;
2716 case 0x70f: cta_y420cmdb(x
, length
); break;
2717 case 0x711|kOUI_Dolby
: cta_dolby_audio(x
, length
); break;
2718 case 0x712: cta_hdmi_audio_block(x
, length
); break;
2719 case 0x713: cta_rcdb(x
, length
); break;
2720 case 0x714: cta_sldb(x
, length
); break;
2721 case 0x720: cta_ifdb(x
, length
); break;
2722 case 0x722: cta_displayid_type_7(x
, length
); break;
2723 case 0x723: cta_displayid_type_8(x
, length
); break;
2724 case 0x72a: cta_displayid_type_10(x
, length
); break;
2726 cta_hf_eeodb(x
, length
);
2728 fail("Data Block can only be present in Block 1.\n");
2729 // This must be the first CTA-861 block
2730 if (cta
.block_number
> 0)
2731 fail("Data Block starts at a wrong offset.\n");
2734 if (cta
.previous_cta_tag
!= (0x03|kOUI_HDMI
))
2735 fail("HDMI Forum SCDB did not immediately follow the HDMI VSDB.\n");
2736 if (cta
.have_hf_scdb
|| cta
.have_hf_vsdb
)
2737 fail("Duplicate HDMI Forum VSDB/SCDB.\n");
2739 fail("Data Block can only be present in Block 1.\n");
2741 data_block
= std::string("HDMI Forum SCDB");
2742 fail("Invalid length %u < 2.\n", length
);
2746 printf(" Non-zero SCDB reserved fields!\n");
2747 cta_hf_scdb(x
+ 2, length
- 2);
2748 cta
.have_hf_scdb
= true;
2751 cta_hf_sbtmdb(x
, length
);
2755 hex_block(" ", x
, length
);
2760 cta
.previous_cta_tag
= tag
;
2761 found_tags
.push_back(tag
);
2764 void edid_state::preparse_cta_block(unsigned char *x
)
2766 unsigned version
= x
[1];
2767 unsigned offset
= x
[2];
2770 unsigned char *detailed
;
2771 bool update_checksum
= false;
2773 for (detailed
= x
+ offset
; detailed
+ 17 < x
+ 127; detailed
+= 18) {
2774 if (memchk(detailed
, 18))
2776 update_checksum
|= preparse_detailed_block(detailed
);
2777 if (detailed
[0] || detailed
[1])
2778 cta
.preparsed_total_dtds
++;
2780 if (update_checksum
)
2781 replace_checksum(x
, EDID_PAGE_SIZE
);
2787 for (unsigned i
= 4; i
< offset
; i
+= (x
[i
] & 0x1f) + 1) {
2788 bool for_ycbcr420
= false;
2791 switch ((x
[i
] & 0xe0) >> 5) {
2793 oui
= (x
[i
+ 3] << 16) + (x
[i
+ 2] << 8) + x
[i
+ 1];
2794 if (oui
== 0x000c03) {
2795 cta
.has_hdmi
= true;
2796 cta
.preparsed_phys_addr
= (x
[i
+ 4] << 8) | x
[i
+ 5];
2797 } else if ((oui
== 0xca125c || oui
== 0x5c12ca) &&
2798 (x
[i
] & 0x1f) == 0x15 && replace_unique_ids
) {
2799 memset(x
+ i
+ 6, 0, 16);
2800 replace_checksum(x
, EDID_PAGE_SIZE
);
2804 if (!(x
[i
] & 0x1f) || cta
.preparsed_first_vfd
.rid
)
2806 cta
.preparsed_first_vfd
= cta_parse_vfd(x
+ i
+ 2, (x
[i
+ 1] & 3) + 1);
2809 if (x
[i
+ 1] == 0x0d)
2810 cta
.has_vfpdb
= true;
2811 else if (x
[i
+ 1] == 0x05)
2813 else if (x
[i
+ 1] == 0x08)
2814 cta
.has_nvrdb
= true;
2815 else if (x
[i
+ 1] == 0x13 && (x
[i
+ 2] & 0x40)) {
2816 cta
.preparsed_speaker_count
= 1 + (x
[i
+ 2] & 0x1f);
2817 cta
.preparsed_sld
= x
[i
+ 2] & 0x20;
2818 } else if (x
[i
+ 1] == 0x14)
2819 cta_preparse_sldb(x
+ i
+ 2, (x
[i
] & 0x1f) - 1);
2820 else if (x
[i
+ 1] == 0x22)
2821 cta
.preparsed_total_vtdbs
++;
2822 else if (x
[i
+ 1] == 0x23) {
2823 cta
.preparsed_has_t8vtdb
= true;
2824 cta
.preparsed_t8vtdb_dmt
= x
[i
+ 3];
2825 if (x
[i
+ 2] & 0x08)
2826 cta
.preparsed_t8vtdb_dmt
|= x
[i
+ 4] << 8;
2827 } else if (x
[i
+ 1] == 0x2a)
2828 cta
.preparsed_total_vtdbs
+=
2829 ((x
[i
] & 0x1f) - 2) / (6 + ((x
[i
+ 2] & 0x70) >> 4));
2830 else if (x
[i
+ 1] == 0x78)
2831 cta
.hf_eeodb_blocks
= x
[i
+ 2];
2832 if (x
[i
+ 1] != 0x0e)
2834 for_ycbcr420
= true;
2835 #ifdef __EMSCRIPTEN__
2836 [[clang::fallthrough
]];
2840 for (unsigned j
= 1 + for_ycbcr420
; j
<= (x
[i
] & 0x1f); j
++) {
2841 unsigned char vic
= x
[i
+ j
];
2843 if ((vic
& 0x7f) <= 64)
2845 cta
.preparsed_svds
[for_ycbcr420
].push_back(vic
);
2846 cta
.preparsed_has_vic
[for_ycbcr420
][vic
] = true;
2848 const struct timings
*t
= find_vic_id(vic
);
2850 if (!for_ycbcr420
&& t
&&
2851 t
->pixclk_khz
> cta
.preparsed_max_vic_pixclk_khz
)
2852 cta
.preparsed_max_vic_pixclk_khz
= t
->pixclk_khz
;
2859 void edid_state::parse_cta_block(const unsigned char *x
)
2861 unsigned version
= x
[1];
2862 unsigned offset
= x
[2];
2863 const unsigned char *detailed
;
2865 // See Table 52 of CTA-861-G for a description of Byte 3
2867 printf(" Revision: %u\n", version
);
2869 fail("Invalid CTA-861 Extension revision 0.\n");
2871 fail("Deprecated CTA-861 Extension revision 2.\n");
2872 if (cta
.has_hdmi
&& version
!= 3)
2873 fail("The HDMI Specification requires CTA Extension revision 3.\n");
2875 warn("Unknown CTA-861 Extension revision %u.\n", version
);
2876 if (offset
> 0 && offset
< 4)
2877 fail("Invalid CTA-861 Extension offset value (byte 2).\n");
2879 if (version
>= 1) do {
2880 if (version
== 1 && x
[3] != 0)
2881 fail("Non-zero byte 3.\n");
2883 if (version
< 3 && offset
>= 4 && ((offset
- 4) / 8)) {
2884 printf(" 8-byte timing descriptors: %u\n", (offset
- 4) / 8);
2885 fail("8-byte descriptors were never used.\n");
2890 printf(" Underscans IT Video Formats by default\n");
2892 warn("IT Video Formats are overscanned by default, but normally this should be underscanned.\n");
2894 printf(" Basic audio support\n");
2896 printf(" Supports YCbCr 4:4:4\n");
2898 printf(" Supports YCbCr 4:2:2\n");
2899 // Disable this test: this fails a lot of EDIDs, and there are
2900 // also some corner cases where you only want to receive 4:4:4
2901 // and refuse a fallback to 4:2:2.
2902 // if ((x[3] & 0x30) && (x[3] & 0x30) != 0x30)
2903 // msg(!cta.has_hdmi, "If YCbCr support is indicated, then both 4:2:2 and 4:4:4 %s be supported.\n",
2904 // cta.has_hdmi ? "shall" : "should");
2905 printf(" Native detailed modes: %u\n", x
[3] & 0x0f);
2906 if (cta
.block_number
== 0)
2908 else if (x
[3] != cta
.byte3
)
2909 fail("Byte 3 must be the same for all CTA-861 Extension Blocks.\n");
2910 if (cta
.block_number
== 0) {
2911 unsigned native_dtds
= x
[3] & 0x0f;
2913 cta
.native_timings
.clear();
2914 if (!native_dtds
&& !cta
.has_vfpdb
) {
2915 cta
.first_svd_might_be_preferred
= true;
2916 } else if (native_dtds
> cta
.preparsed_total_dtds
) {
2917 fail("There are more Native DTDs (%u) than DTDs (%u).\n",
2918 native_dtds
, cta
.preparsed_total_dtds
);
2920 if (native_dtds
> cta
.preparsed_total_dtds
)
2921 native_dtds
= cta
.preparsed_total_dtds
;
2922 for (unsigned i
= 0; i
< native_dtds
; i
++) {
2925 sprintf(type
, "DTD %3u", i
+ 1);
2926 cta
.native_timings
.push_back(timings_ext(i
+ 129, type
));
2927 cta
.has_svrs
= true;
2929 if (cta
.has_hdmi
&& block_nr
!= (block_map
.saw_block_1
? 2 : 1))
2930 fail("The HDMI Specification requires that the first Extension Block (that is not a Block Map) is an CTA-861 Extension Block.\n");
2935 // Offset 0 means that there are no data blocks or DTDs,
2936 // so the remainder must be padding.
2937 if (!memchk(x
+ 4, 127 - 4)) {
2938 data_block
= "Padding";
2939 fail("Contains non-zero bytes.\n");
2947 for (i
= 4; i
< offset
; i
+= (x
[i
] & 0x1f) + 1) {
2948 cta_block(x
+ i
, cta
.found_tags
);
2953 fail("Offset is %u, but should be %u.\n", offset
, i
);
2956 data_block
= "Detailed Timing Descriptors";
2957 base
.seen_non_detailed_descriptor
= false;
2959 for (detailed
= x
+ offset
; detailed
+ 17 < x
+ 127; detailed
+= 18) {
2960 if (memchk(detailed
, 18))
2964 printf(" %s:\n", data_block
.c_str());
2966 detailed_block(detailed
);
2968 unused_bytes
= x
+ 127 - detailed
;
2969 if (!memchk(detailed
, unused_bytes
)) {
2970 data_block
= "Padding";
2971 fail("Contains non-zero bytes.\n");
2976 if (base
.serial_number
&& serial_strings
.size())
2977 warn("Display Product Serial Number is set, so the Serial Number in the Base EDID should be 0.\n");
2978 if (!cta
.has_vic_1
&& !base
.has_640x480p60_est_timing
)
2979 fail("Required 640x480p60 timings are missing in the established timings"
2980 " and the SVD list (VIC 1).\n");
2981 if ((cta
.supported_hdmi_vic_vsb_codes
& cta
.supported_hdmi_vic_codes
) !=
2982 cta
.supported_hdmi_vic_codes
)
2983 fail("HDMI VIC Codes must have their CTA-861 VIC equivalents in the VSB.\n");
2985 fail("Missing VCDB, needed for Set Selectable RGB Quantization to avoid interop issues.\n");
2986 if (!base
.uses_srgb
&& !cta
.has_cdb
)
2987 warn("Add a Colorimetry Data Block with the sRGB colorimetry bit set to avoid interop issues.\n");
2990 void edid_state::cta_resolve_svr(timings_ext
&t_ext
)
2992 if (t_ext
.svr() == 254) {
2993 t_ext
.flags
= cta
.t8vtdb
.flags
;
2994 add_str(t_ext
.flags
, ">=CTA-861-H");
2995 t_ext
.t
= cta
.t8vtdb
.t
;
2996 } else if (t_ext
.svr() <= 144) {
2997 if (t_ext
.svr() < 129 || t_ext
.svr() - 129 >= cta
.vec_dtds
.size())
2999 t_ext
.flags
= cta
.vec_dtds
[t_ext
.svr() - 129].flags
;
3000 t_ext
.t
= cta
.vec_dtds
[t_ext
.svr() - 129].t
;
3001 } else if (t_ext
.svr() <= 160) {
3002 if (t_ext
.svr() - 145 >= cta
.vec_vtdbs
.size())
3004 t_ext
.flags
= cta
.vec_vtdbs
[t_ext
.svr() - 145].flags
;
3005 add_str(t_ext
.flags
, ">=CTA-861-H");
3006 t_ext
.t
= cta
.vec_vtdbs
[t_ext
.svr() - 145].t
;
3007 } else if (t_ext
.svr() <= 175) {
3008 t_ext
.flags
.clear();
3009 unsigned char rid
= cta
.preparsed_first_vfd
.rid
;
3010 t_ext
.t
= calc_ovt_mode(rids
[rid
].hact
, rids
[rid
].vact
,
3011 rids
[rid
].hratio
, rids
[rid
].vratio
,
3012 vf_rate_values
[t_ext
.svr() - 160]);
3013 t_ext
.flags
= ">=CTA-861.6";
3017 void edid_state::cta_resolve_svrs()
3019 for (vec_timings_ext::iterator iter
= cta
.preferred_timings_vfpdb
.begin();
3020 iter
!= cta
.preferred_timings_vfpdb
.end(); ++iter
) {
3021 if (iter
->has_svr())
3022 cta_resolve_svr(*iter
);
3025 for (vec_timings_ext::iterator iter
= cta
.native_timings
.begin();
3026 iter
!= cta
.native_timings
.end(); ++iter
) {
3027 if (iter
->has_svr())
3028 cta_resolve_svr(*iter
);
3031 for (vec_timings_ext::iterator iter
= cta
.native_timing_nvrdb
.begin();
3032 iter
!= cta
.native_timing_nvrdb
.end(); ++iter
) {
3033 if (iter
->has_svr())
3034 cta_resolve_svr(*iter
);
3038 void edid_state::check_cta_blocks()
3040 unsigned max_pref_prog_hact
= 0;
3041 unsigned max_pref_prog_vact
= 0;
3042 unsigned max_pref_ilace_hact
= 0;
3043 unsigned max_pref_ilace_vact
= 0;
3045 data_block
= "CTA-861";
3047 // HDMI 1.4 goes up to 340 MHz. Dubious to have a DTD above that,
3048 // but no VICs. Displays often have a setting to turn off HDMI 2.x
3049 // support, dropping any HDMI 2.x VICs, but they sometimes forget
3050 // to replace the DTD in the base block as well.
3051 if (cta
.warn_about_hdmi_2x_dtd
)
3052 warn("DTD pixelclock indicates HDMI 2.x support, VICs indicate HDMI 1.x.\n");
3054 if (cta
.hdmi_max_rate
&& max_pixclk_khz
> cta
.hdmi_max_rate
* 1000)
3055 fail("The maximum HDMI TMDS clock is %u kHz, but one or more video timings go up to %u kHz.\n",
3056 cta
.hdmi_max_rate
* 1000, max_pixclk_khz
);
3058 for (vec_timings_ext::iterator iter
= cta
.preferred_timings
.begin();
3059 iter
!= cta
.preferred_timings
.end(); ++iter
) {
3060 if (iter
->t
.interlaced
&&
3061 (iter
->t
.vact
> max_pref_ilace_vact
||
3062 (iter
->t
.vact
== max_pref_ilace_vact
&& iter
->t
.hact
>= max_pref_ilace_hact
))) {
3063 max_pref_ilace_hact
= iter
->t
.hact
;
3064 max_pref_ilace_vact
= iter
->t
.vact
;
3066 if (!iter
->t
.interlaced
&&
3067 (iter
->t
.vact
> max_pref_prog_vact
||
3068 (iter
->t
.vact
== max_pref_prog_vact
&& iter
->t
.hact
>= max_pref_prog_hact
))) {
3069 max_pref_prog_hact
= iter
->t
.hact
;
3070 max_pref_prog_vact
= iter
->t
.vact
;
3073 for (vec_timings_ext::iterator iter
= cta
.preferred_timings_vfpdb
.begin();
3074 iter
!= cta
.preferred_timings_vfpdb
.end(); ++iter
) {
3075 if (iter
->t
.interlaced
&&
3076 (iter
->t
.vact
> max_pref_ilace_vact
||
3077 (iter
->t
.vact
== max_pref_ilace_vact
&& iter
->t
.hact
>= max_pref_ilace_hact
))) {
3078 max_pref_ilace_hact
= iter
->t
.hact
;
3079 max_pref_ilace_vact
= iter
->t
.vact
;
3081 if (!iter
->t
.interlaced
&&
3082 (iter
->t
.vact
> max_pref_prog_vact
||
3083 (iter
->t
.vact
== max_pref_prog_vact
&& iter
->t
.hact
>= max_pref_prog_hact
))) {
3084 max_pref_prog_hact
= iter
->t
.hact
;
3085 max_pref_prog_vact
= iter
->t
.vact
;
3089 unsigned native_prog
= 0;
3090 unsigned native_prog_hact
= 0;
3091 unsigned native_prog_vact
= 0;
3092 bool native_prog_mixed_resolutions
= false;
3093 unsigned native_ilace
= 0;
3094 unsigned native_ilace_hact
= 0;
3095 unsigned native_ilace_vact
= 0;
3096 bool native_ilace_mixed_resolutions
= false;
3097 unsigned native_nvrdb_hact
= 0;
3098 unsigned native_nvrdb_vact
= 0;
3100 for (vec_timings_ext::iterator iter
= cta
.native_timings
.begin();
3101 iter
!= cta
.native_timings
.end(); ++iter
) {
3102 if (iter
->t
.interlaced
) {
3104 if (!native_ilace_hact
) {
3105 native_ilace_hact
= iter
->t
.hact
;
3106 native_ilace_vact
= iter
->t
.vact
;
3107 } else if (native_ilace_hact
!= iter
->t
.hact
||
3108 native_ilace_vact
!= iter
->t
.vact
) {
3109 native_ilace_mixed_resolutions
= true;
3113 if (!native_prog_hact
) {
3114 native_prog_hact
= iter
->t
.hact
;
3115 native_prog_vact
= iter
->t
.vact
;
3116 } else if (native_prog_hact
!= iter
->t
.hact
||
3117 native_prog_vact
!= iter
->t
.vact
) {
3118 native_prog_mixed_resolutions
= true;
3123 for (vec_timings_ext::iterator iter
= cta
.native_timing_nvrdb
.begin();
3124 iter
!= cta
.native_timing_nvrdb
.end(); ++iter
) {
3125 native_nvrdb_hact
= iter
->t
.hact
;
3126 native_nvrdb_vact
= iter
->t
.vact
;
3129 if (native_prog_mixed_resolutions
)
3130 fail("Native progressive timings are a mix of several resolutions.\n");
3131 if (native_ilace_mixed_resolutions
)
3132 fail("Native interlaced timings are a mix of several resolutions.\n");
3133 if (native_ilace
&& !native_prog
)
3134 fail("A native interlaced timing is present, but not a native progressive timing.\n");
3135 if (!native_prog_mixed_resolutions
&& native_prog
> 1)
3136 warn("Multiple native progressive timings are defined.\n");
3137 if (!native_ilace_mixed_resolutions
&& native_ilace
> 1)
3138 warn("Multiple native interlaced timings are defined.\n");
3140 if (native_nvrdb_vact
&&
3141 (max_pref_prog_vact
> native_nvrdb_vact
||
3142 (max_pref_prog_vact
== native_nvrdb_vact
&& max_pref_prog_hact
> native_nvrdb_hact
)))
3143 warn("Native video resolution of %ux%u is smaller than the max preferred progressive resolution %ux%u.\n",
3144 native_nvrdb_hact
, native_nvrdb_vact
,
3145 max_pref_prog_hact
, max_pref_prog_vact
);
3146 else if (!native_nvrdb_vact
&& !native_prog_mixed_resolutions
&& native_prog_vact
&&
3147 (max_pref_prog_vact
> native_prog_vact
||
3148 (max_pref_prog_vact
== native_prog_vact
&& max_pref_prog_hact
> native_prog_hact
)))
3149 warn("Native progressive resolution of %ux%u is smaller than the max preferred progressive resolution %ux%u.\n",
3150 native_prog_hact
, native_prog_vact
,
3151 max_pref_prog_hact
, max_pref_prog_vact
);
3152 if (!native_ilace_mixed_resolutions
&& native_ilace_vact
&&
3153 (max_pref_ilace_vact
> native_ilace_vact
||
3154 (max_pref_ilace_vact
== native_ilace_vact
&& max_pref_ilace_hact
> native_ilace_hact
)))
3155 warn("Native interlaced resolution of %ux%u is smaller than the max preferred interlaced resolution %ux%u.\n",
3156 native_ilace_hact
, native_ilace_vact
,
3157 max_pref_ilace_hact
, max_pref_ilace_vact
);
3159 if (dispid
.native_width
&& native_prog_hact
&&
3160 !native_prog_mixed_resolutions
) {
3161 if (dispid
.native_width
!= native_prog_hact
||
3162 dispid
.native_height
!= native_prog_vact
)
3163 fail("Mismatch between CTA-861 and DisplayID native progressive resolution.\n");